27#include <DGtal/base/Common.h>
28#include <DGtal/helpers/StdDefs.h>
29#include <DGtal/helpers/Shortcuts.h>
30#include <DGtal/helpers/ShortcutsGeometry.h>
31#include <DGtal/shapes/SurfaceMesh.h>
32#include <DGtal/geometry/volumes/TangencyComputer.h>
33#include <DGtal/geometry/volumes/ConvexityHelper.h>
34#include <DGtal/geometry/tools/QuickHull.h>
35#include <DGtal/geometry/surfaces/estimation/PlaneProbingTetrahedronEstimator.h>
37#include <polyscope/pick.h>
38#include <polyscope/polyscope.h>
39#include <polyscope/surface_mesh.h>
40#include <polyscope/point_cloud.h>
56typedef std::size_t
Size;
59polyscope::SurfaceMesh *
psMesh;
60polyscope::SurfaceMesh *psDualMesh;
61polyscope::SurfaceMesh *psOuterDualMesh;
62polyscope::SurfaceMesh *psTriangle;
63polyscope::SurfaceMesh *psDelaunay;
64polyscope::PointCloud* psCloud;
65polyscope::PointCloud* psCloudRemaining;
66polyscope::PointCloud* psCloudCvx;
67polyscope::PointCloud* psCloudProc;
68polyscope::PointCloud* psOuterCloudProc;
69polyscope::PointCloud* psCloudInnerDelaunay;
78bool remove_empty_cells =
false;
79bool local_tangency =
false;
82Size outer_current = 0;
83std::vector< Size > order;
84std::vector< Size > outer_order;
85std::vector< Point > digital_points;
86std::vector< Point > outer_digital_points;
87std::set< Point > useless_points;
88std::vector< double > intercepts;
89std::vector< double > outer_intercepts;
90std::vector<std::vector<SH3::SurfaceMesh::Vertex>> dual_faces;
91std::vector<RealPoint> dual_positions;
92std::vector<std::vector<SH3::SurfaceMesh::Vertex>> outer_dual_faces;
93std::vector<RealPoint> outer_dual_positions;
94std::vector<SCell> surfels;
95std::map<Point,Size> surfel2idx;
105typedef std::vector< Index > Indices;
106typedef double Scalar;
107typedef std::vector< Scalar > Scalars;
111 if ( order.size() != digital_points.size() )
113 auto rng = std::default_random_engine {};
114 order.resize( digital_points.size() );
115 for (
Size i = 0; i < order.size(); i++ ) order[ i ] = i;
116 std::shuffle( order.begin(), order.end(), rng);
119 if ( current == order.size() ) current = 0;
120 return static_cast<int>(order[ current++ ]);
124 if ( outer_order.size() != outer_digital_points.size() )
126 auto rng = std::default_random_engine {};
127 outer_order.resize( outer_digital_points.size() );
128 for (
Size i = 0; i < outer_order.size(); i++ ) outer_order[ i ] = i;
129 std::shuffle( outer_order.begin(), outer_order.end(), rng);
132 if ( outer_current == outer_order.size() ) outer_current = 0;
133 return static_cast<int>(outer_order[ outer_current++ ]);
141 round( p[ 1 ] / gridstep + 0.5 ),
142 round( p[ 2 ] / gridstep + 0.5 ) );
143 return Point( sp[ 0 ], sp[ 1 ], sp[ 2 ] );
147 return RealPoint( gridstep * ( q[ 0 ] - 0.5 ),
148 gridstep * ( q[ 1 ] - 0.5 ),
149 gridstep * ( q[ 2 ] - 0.5 ) );
151void embedPointels(
const std::vector< Point >& vq, std::vector< RealPoint >& vp )
153 vp.resize( vq.size() );
154 for (
auto i = 0; i < vp.size(); ++i )
155 vp[ i ] = pointelPoint2RealPoint( vq[ i ] );
157void digitizePointels(
const std::vector< RealPoint >& vp, std::vector< Point >& vq )
159 vq.resize( vp.size() );
160 for (
auto i = 0; i < vq.size(); ++i )
161 vq[ i ] = pointelRealPoint2Point( vp[ i ] );
169 round( p[ 1 ] / gridstep ),
170 round( p[ 2 ] / gridstep ) );
171 return Point( sp[ 0 ], sp[ 1 ], sp[ 2 ] );
176 gridstep * ( q[ 1 ] ),
177 gridstep * ( q[ 2 ] ) );
179void embedVoxels(
const std::vector< Point >& vq, std::vector< RealPoint >& vp )
181 vp.resize( vq.size() );
182 for (
auto i = 0; i < vp.size(); ++i )
183 vp[ i ] = voxelPoint2RealPoint( vq[ i ] );
185void digitizeVoxels(
const std::vector< RealPoint >& vp, std::vector< Point >& vq )
187 vq.resize( vp.size() );
188 for (
auto i = 0; i < vq.size(); ++i )
189 vq[ i ] = voxelRealPoint2Point( vp[ i ] );
193Indices tangentCone(
const Point& p )
195 return TC.getCotangentPoints( p );
198Scalars distances(
const Point& p,
const Indices& idx )
200 Scalars D( idx.size() );
201 for (
Index i = 0; i < idx.size(); i++ )
202 D[ i ] = ( TC.point( i ) - p ).norm();
208findCorners(
const std::unordered_set< Point >& S,
209 const std::vector< Vector >& In,
210 const std::vector< Vector >& Out )
212 std::vector< Point > C;
216 for (
auto&& n : In )
217 if ( ! S.count( p+n ) ) { corner =
false;
break; }
218 if ( ! corner )
continue;
219 for (
auto&& n : Out )
220 if ( S.count( p+n ) ) { corner =
false;
break; }
221 if ( corner ) C.push_back( p );
226void computeQuadrant(
int q,
227 std::vector< Vector >& In,
228 std::vector< Vector >& Out )
232 In.push_back(
Vector( q & 0x1 ? 1 : -1, 0, 0 ) );
233 In.push_back(
Vector( 0, q & 0x2 ? 1 : -1, 0 ) );
234 In.push_back(
Vector( 0, 0, q & 0x4 ? 1 : -1 ) );
235 Out.push_back(
Vector( q & 0x1 ? 1 : -1, q & 0x2 ? 1 : -1, q & 0x4 ? 1 : -1 ) );
237 if ( D.
dot( Out[ 0 ] ) < 0.0 ) std::swap( In[ 1 ], In[ 2 ] );
238 In.push_back( In[ 0 ]+In[ 1 ] );
239 In.push_back( In[ 0 ]+In[ 2 ] );
240 In.push_back( In[ 1 ]+In[ 2 ] );
243struct UnorderedPointSetPredicate
246 const std::unordered_set< Point >* myS;
247 explicit UnorderedPointSetPredicate(
const std::unordered_set< Point >& S )
249 bool operator()(
const Point& p )
const
250 {
return myS->count( p ) != 0; }
260 std::vector< RealPoint > positions;
262 std::vector< std::vector<SH3::SurfaceMesh::Vertex> > faces;
263 std::vector< Vector > In;
264 std::vector< Vector > Out;
265 std::unordered_set< Point > S( digital_points.cbegin(), digital_points.cend() );
266 UnorderedPointSetPredicate predS( S );
268 for (
int q = 0; q < 8; q++ )
270 computeQuadrant( q, In, Out );
271 std::vector< Point > corners = findCorners( S, In, Out );
272 std::cout <<
"Found " << corners.size() <<
" in Q" << q << std::endl;
273 std::array<Point, 3> m = { In[ 0 ], In[ 1 ], In[ 2 ] };
274 for (
auto&& p : corners )
280 std::vector<SH3::SurfaceMesh::Vertex> triangle { i, i+1, i+2 };
281 auto v = estimator.vertices();
282 faces.push_back( triangle );
286 while (estimator.advance().first) {
287 auto state = estimator.hexagonState();
288 if (state == Estimator::Neighborhood::HexagonState::Planar) {
289 auto v = estimator.vertices();
290 if ( S.count( v[ 0 ] ) && S.count( v[ 1 ] ) && S.count( v[ 2 ] ) )
292 std::vector< Point > X { v[ 0 ], v[ 1 ], v[ 2 ] };
309 embedPointels( vertices, positions );
310 psTriangle = polyscope::registerSurfaceMesh(
"Triangle", positions, faces);
313void displayMidReconstruction()
315 std::vector< RealPoint > mid_dual_positions( dual_positions.size() );
316 for (
auto i = 0; i < surfels.size(); i++ )
320 auto int_p = voxelPoint2RealPoint( int_vox );
321 auto ext_p = voxelPoint2RealPoint( ext_vox );
322 const double s = intercepts[ i ] + 0.001;
323 const RealPoint q = ( 1.0 - s ) * int_p + s * ext_p;
324 const double ds = outer_intercepts[ i ] + 0.001;
325 const RealPoint dq = ( 1.0 - ds ) * ext_p + ds * int_p;
326 mid_dual_positions[ i ] = 0.5*(q+dq);
328 psDualMesh = polyscope::registerSurfaceMesh(
"Mid surface", mid_dual_positions, dual_faces);
331void displayReconstruction()
333 for (
auto i = 0; i < surfels.size(); i++ )
337 auto int_p = voxelPoint2RealPoint( int_vox );
338 auto ext_p = voxelPoint2RealPoint( ext_vox );
339 const double s = intercepts[ i ] + 0.001;
340 const RealPoint q = ( 1.0 - s ) * int_p + s * ext_p;
341 dual_positions[ i ] = q;
343 psDualMesh = polyscope::registerSurfaceMesh(
"Reconstruction surface", dual_positions, dual_faces);
344 std::vector< Point > X;
345 for (
Size i = 0; i < current; i++ )
346 X.push_back( digital_points[ order[ i ] ] );
347 std::vector< RealPoint > emb_X;
348 embedVoxels( X, emb_X );
349 psCloudProc = polyscope::registerPointCloud(
"Processed points", emb_X );
350 psCloudProc->setPointRadius( gridstep / 300.0 );
354void displayRemainingPoints()
356 std::vector< Point > X;
357 std::vector< RealPoint > emb_X;
358 for (
auto i = current; i < digital_points.size(); i++ )
360 Point p = digital_points[ order[ i ] ];
361 if ( ! useless_points.count( p ) )
364 embedVoxels( X, emb_X );
365 psCloudProc = polyscope::registerPointCloud(
"Remaining points", emb_X );
366 psCloudProc->setPointRadius( gridstep / 200.0 );
369void displayOuterReconstruction()
371 for (
auto i = 0; i < surfels.size(); i++ )
375 auto int_p = voxelPoint2RealPoint( int_vox );
376 auto ext_p = voxelPoint2RealPoint( ext_vox );
377 const double s = outer_intercepts[ i ] + 0.001;
378 const RealPoint q = ( 1.0 - s ) * ext_p + s * int_p;
379 outer_dual_positions[ i ] = q;
381 psOuterDualMesh = polyscope::registerSurfaceMesh(
"Reconstruction outer surface", outer_dual_positions, outer_dual_faces);
382 std::vector< Point > X;
383 for (
Size i = 0; i < outer_current; i++ )
384 X.push_back( outer_digital_points[ outer_order[ i ] ] );
385 std::vector< RealPoint > emb_X;
386 embedVoxels( X, emb_X );
387 psOuterCloudProc = polyscope::registerPointCloud(
"Processed outer points", emb_X );
388 psOuterCloudProc->setPointRadius( gridstep / 300.0 );
392void updateReconstructionFromCells(
const std::vector< Point >& X,
393 const std::vector< Point >& cells )
397 const auto a = N.
dot( X[ 0 ] );
399 for (
auto&& kp : cells )
403 if (
K.
uDim( c ) != 1 )
continue;
409 const auto it = surfel2idx.find( dual_kp );
410 if ( it == surfel2idx.cend() )
continue;
412 const Size idx = it->second;
413 const SCell surfel = surfels[ idx ];
416 const auto int_val = N.
dot( int_vox );
417 const auto ext_val = N.
dot( ext_vox );
419 if ( ( int_val <= a && ext_val <= a ) || ( int_val >= a && ext_val >= a ) )
421 if ( ( int_val < a && ext_val < a ) || ( int_val > a && ext_val > a ) )
425 const double s = (double)( a - int_val ) / (double) (ext_val - int_val );
426 const double old_s = intercepts[ idx ];
428 intercepts[ idx ] = std::max( old_s, s );
432void updateOuterReconstructionFromCells(
const std::vector< Point >& X,
433 const std::vector< Point >& cells )
437 const auto a = N.
dot( X[ 0 ] );
439 for (
auto&& kp : cells )
443 if (
K.
uDim( c ) != 1 )
continue;
449 const auto it = surfel2idx.find( dual_kp );
450 if ( it == surfel2idx.cend() )
continue;
452 const Size idx = it->second;
453 const SCell surfel = surfels[ idx ];
456 const auto int_val = N.
dot( int_vox );
457 const auto ext_val = N.
dot( ext_vox );
458 if ( ( int_val <= a && ext_val <= a ) || ( int_val >= a && ext_val >= a ) )
460 if ( ( int_val < a && ext_val < a ) || ( int_val > a && ext_val > a ) )
464 const double s = (double)( a - ext_val ) / (double) (int_val - ext_val );
465 outer_intercepts[ idx ] = std::max( outer_intercepts[ idx ], s );
469void updateReconstructionFromCells(
Point x,
Point y,
470 const std::vector< Point >& cells )
475 const double l = U.
norm();
477 const RealPoint p( x[ 0 ], x[ 1 ], x[ 2 ] );
479 for (
auto&& kp : cells )
483 if (
K.
uDim( c ) != 1 )
continue;
489 const auto it = surfel2idx.find( dual_kp );
490 if ( it == surfel2idx.cend() )
continue;
492 const Size idx = it->second;
493 const SCell surfel = surfels[ idx ];
496 const Vector V = ext_vox - int_vox;
498 const RealPoint q( int_vox[ 0 ], int_vox[ 1 ], int_vox[ 2 ] );
499 const auto uv = u.
dot( v );
500 if ( uv == 0 )
continue;
502 const auto c1 = ( q - p ).dot( u );
503 const auto c2 = ( p - q ).dot( v );
504 const double d = 1.0-uv*uv;
505 const double s = ( c1 + uv * c2 ) / d;
506 const double t = ( c2 + uv * c1 ) / d;
507 if ( ( s < 0.0 ) || ( s > l ) )
continue;
509 intercepts[ idx ] = std::max( intercepts[ idx ], std::min( t, 1.0 ) );
513void updateReconstructionFromTangentConeLines(
int vertex_idx )
515 if ( digital_points.empty() )
return;
516 if ( vertex_idx < 0 || vertex_idx >= digital_points.size() )
return;
519 auto local_X_idx = TC.getCotangentPoints( p );
520 std::vector< Point > local_X;
521 for (
auto idx : local_X_idx )
522 local_X.push_back( TC.point( idx ) );
523 for (
auto&& q : local_X )
525 std::vector< Point > X { p, q };
527 updateReconstructionFromCells( p, q, line_cells.toPointRange() );
531void updateReconstructionFromTangentConeTriangles(
int vertex_idx )
534 if ( digital_points.empty() )
return;
535 if ( vertex_idx < 0 || vertex_idx >= digital_points.size() )
return;
538 auto local_X_idx = TC.getCotangentPoints( p );
539 local_X_idx.push_back( vertex_idx );
540 std::vector< Point > local_X;
541 for (
auto idx : local_X_idx )
542 local_X.push_back( TC.point( idx ) );
546 std::vector< Point > positions;
549 std::vector< IndexRange > facet_vertices;
551 if ( ! ok )
trace.
error() <<
"Bad facet computation" << std::endl;
553 std::set< std::pair< Point, Point > >
edges;
554 for (
auto&& facet : facet_vertices )
556 const auto nb = facet.size();
557 for (
auto i = 0; i < nb; i++ )
558 edges.insert( std::make_pair( positions[ facet[ i ] ],
559 positions[ facet[ (i+1)%nb ] ] ) );
561 for (
auto&& e :
edges )
563 if ( e.second < e.first )
continue;
564 std::vector< Point > X { p, e.first, e.second };
565 const auto triangle_cells = dconv.
StarCvxH( X, LS.
axis() );
566 if ( LS.
includes( triangle_cells ) )
567 updateReconstructionFromCells( X, triangle_cells.toPointRange() );
606void computeTangentCone(
int vertex_idx)
608 if ( digital_points.empty() )
return;
612 auto local_X_idx = TC.getCotangentPoints( p );
613 std::cout <<
"#cone=" << local_X_idx.size() << std::endl;
614 local_X_idx.push_back( vertex_idx );
615 std::vector< Point > local_X;
616 std::vector< RealPoint > emb_local_X;
617 for (
auto idx : local_X_idx )
618 local_X.push_back( TC.point( idx ) );
619 std::vector< double > values( local_X.size(), 0.0 );
621 embedVoxels( local_X, emb_local_X );
622 psCloud = polyscope::registerPointCloud(
"Tangent cone", emb_local_X );
623 psCloud->setPointRadius( gridstep / 300.0 );
624 psCloud->addScalarQuantity(
"Classification", values );
628 std::vector< Point > positions;
629 std::vector< RealPoint > emb_positions;
632 embedVoxels( positions, emb_positions );
633 psCloudCvx = polyscope::registerPointCloud(
"Tangent cone vertices", emb_positions );
634 psCloudCvx->setPointRadius( gridstep / 200.0 );
636 updateReconstructionFromTangentConeTriangles( vertex_idx );
637 displayReconstruction();
641void updateReconstructionFromLocalTangentDelaunayComplex(
int vertex_idx)
643 if ( digital_points.empty() )
return;
646 auto local_X_idx = TC.getCotangentPoints( p );
647 local_X_idx.push_back( vertex_idx );
648 std::vector< Point > local_X;
649 for (
auto idx : local_X_idx )
650 local_X.push_back( TC.point( idx ) );
652 if ( local_tangency )
659 trace.
error() <<
"Input set of points is not full dimensional." << std::endl;
663 std::vector< bool > is_cell_tangent( dcomplex.
nbCells(),
false );
664 if ( remove_empty_cells )
669 if ( P.countUpTo( (
Integer)Y.size()+1 ) >= (
Integer)Y.size()+1 )
continue;
670 is_cell_tangent[ c ] =
679 is_cell_tangent[ c ] =
685 std::vector< std::vector<SH3::SurfaceMesh::Vertex> > del_faces;
686 std::vector< RealPoint > del_positions;
687 std::set<Index> boundary_or_ext_points;
690 auto f0 = std::make_pair( f,
false );
699 if ( ! is_cell_tangent[ c0 ] )
702 boundary_or_ext_points.insert( V.cbegin(), V.cend() );
704 if ( ! dcomplex.
isInfinite( c1 ) && ! is_cell_tangent[ c1 ] )
707 boundary_or_ext_points.insert( V.cbegin(), V.cend() );
710 ( is_cell_tangent[ c0 ] && ( dcomplex.
isInfinite( c1 )
711 || ( ! is_cell_tangent[ c1 ] ) ) )
713 ( ! is_cell_tangent[ c0 ] && ( ! dcomplex.
isInfinite( c1 )
714 && ( is_cell_tangent[ c1 ] ) ) );
715 if ( ! bdry )
continue;
717 const auto triangle_cells = dconv.
StarCvxH( X, LS.
axis() );
719 updateReconstructionFromCells( X, triangle_cells.toPointRange() );
721 useless_points.insert( p );
725 if ( ! boundary_or_ext_points.count( v ) )
726 useless_points.insert( q );
732void updateOuterReconstructionFromLocalTangentDelaunayComplex(
int vertex_idx)
734 if ( outer_digital_points.empty() )
return;
736 const auto p = outer_digital_points[
vertex_idx ];
737 auto local_X_idx = outer_TC.getCotangentPoints( p );
738 local_X_idx.push_back( vertex_idx );
739 std::vector< Point > local_X;
740 for (
auto idx : local_X_idx )
741 local_X.push_back( outer_TC.point( idx ) );
747 trace.
error() <<
"Input set of points is not full dimensional." << std::endl;
751 std::vector< bool > is_cell_tangent( dcomplex.
nbCells(),
false );
752 if ( remove_empty_cells )
757 if ( P.countUpTo( (
Integer)Y.size()+1 ) >= (
Integer)Y.size()+1 )
continue;
767 std::vector< std::vector<SH3::SurfaceMesh::Vertex> > del_faces;
770 auto f0 = std::make_pair( f,
false );
780 ( is_cell_tangent[ c0 ] && ( dcomplex.
isInfinite( c1 )
781 || ( ! is_cell_tangent[ c1 ] ) ) )
783 ( ! is_cell_tangent[ c0 ] && ( ! dcomplex.
isInfinite( c1 )
784 && ( is_cell_tangent[ c1 ] ) ) );
785 if ( ! bdry )
continue;
787 const auto triangle_cells = dconv.
StarCvxH( X, outer_LS.
axis() );
789 updateOuterReconstructionFromCells( X, triangle_cells.toPointRange() );
794void computeLocalTangentDelaunayComplex(
int vertex_idx)
796 if ( digital_points.empty() )
return;
800 auto local_X_idx = TC.getCotangentPoints( p );
801 std::cout <<
"#cone=" << local_X_idx.size() << std::endl;
802 local_X_idx.push_back( vertex_idx );
803 std::vector< Point > local_X;
804 for (
auto idx : local_X_idx )
805 local_X.push_back( TC.point( idx ) );
807 if ( local_tangency )
814 trace.
error() <<
"Input set of points is not full dimensional." << std::endl;
818 std::vector< bool > is_cell_tangent( dcomplex.
nbCells(),
false );
819 if ( remove_empty_cells )
824 if ( P.countUpTo( (
Integer)Y.size()+1 ) >= (
Integer)Y.size()+1 )
continue;
825 is_cell_tangent[ c ] =
834 is_cell_tangent[ c ] =
840 std::vector< std::vector<SH3::SurfaceMesh::Vertex> > del_faces;
841 std::vector< RealPoint > del_positions;
842 std::vector< RealPoint > del_inner_points;
843 std::set<Index> boundary_or_ext_points;
846 auto f0 = std::make_pair( f,
false );
855 if ( ! is_cell_tangent[ c0 ] )
858 boundary_or_ext_points.insert( V.cbegin(), V.cend() );
860 if ( ! dcomplex.
isInfinite( c1 ) && ! is_cell_tangent[ c1 ] )
863 boundary_or_ext_points.insert( V.cbegin(), V.cend() );
866 ( is_cell_tangent[ c0 ] && ( dcomplex.
isInfinite( c1 )
867 || ( ! is_cell_tangent[ c1 ] ) ) )
869 ( ! is_cell_tangent[ c0 ] && ( ! dcomplex.
isInfinite( c1 )
870 && ( is_cell_tangent[ c1 ] ) ) );
871 if ( bdry ) del_faces.push_back( dcomplex.
faceVertices( f0 ) );
876 del_positions.push_back( voxelPoint2RealPoint( p ) );
877 if ( ! boundary_or_ext_points.count( v ) )
878 del_inner_points.push_back( voxelPoint2RealPoint( p ) );
882 psCloudInnerDelaunay = polyscope::registerPointCloud(
"Inner Delaunay points",
884 psCloudInnerDelaunay->setPointRadius( gridstep / 200.0 );
886 psDelaunay = polyscope::registerSurfaceMesh(
"Delaunay surface",
887 del_positions, del_faces);
888 updateReconstructionFromLocalTangentDelaunayComplex( vertex_idx );
889 displayReconstruction();
893void computeGlobalTangentDelaunayComplex()
895 if ( digital_points.empty() )
return;
904 trace.
error() <<
"Input set of points is not full dimensional." << std::endl;
910 std::vector< bool > is_cell_tangent( dcomplex.
nbCells(),
false );
915 if ( P.countUpTo( (
Integer)Y.size()+1 ) >= (
Integer)Y.size()+1 )
continue;
920 std::vector< std::vector<SH3::SurfaceMesh::Vertex> > del_faces;
921 std::vector< RealPoint > del_positions;
922 std::vector< RealPoint > del_inner_points;
923 std::set<Index> useful_points;
924 std::vector< std::pair< Index, bool > > all_bdry_faces;
927 auto f0 = std::make_pair( f,
false );
933 std::swap( c0, c1 ); std::swap( f0, f1 );
935 const bool inf_c1 = dcomplex.
isInfinite( c1 );
936 const bool bdry_f0 = is_cell_tangent[ c0 ] &&
937 ( inf_c1 || ! is_cell_tangent[ c1 ] );
938 const bool bdry_f1 = ( ! is_cell_tangent[ c0 ] )
939 && ( ( ! inf_c1 ) && is_cell_tangent[ c1 ] );
944 del_faces.push_back( V );
945 useful_points.insert( V.cbegin(), V.cend() );
946 all_bdry_faces.push_back( f0 );
951 del_faces.push_back( V );
952 useful_points.insert( V.cbegin(), V.cend() );
953 all_bdry_faces.push_back( f1 );
955 else if ( ( ! ( is_cell_tangent[ c0 ] || inf_c1 || is_cell_tangent[ c0 ] )
956 || ( ! is_cell_tangent[ c0 ] && inf_c1 ) )
960 del_faces.push_back( V );
961 useful_points.insert( V.cbegin(), V.cend() );
963 all_bdry_faces.push_back( f0 );
969 del_positions.push_back( voxelPoint2RealPoint( p ) );
970 if ( ! useful_points.count( v ) )
972 del_inner_points.push_back( voxelPoint2RealPoint( p ) );
973 useless_points.insert( p );
979 const auto axis = LS.
axis();
980 for (
auto f : all_bdry_faces )
983 const auto cells = dconv.
StarCvxH( X, axis );
986 updateReconstructionFromCells( X, cells.toPointRange() );
990 psCloudInnerDelaunay = polyscope::registerPointCloud(
"Inner Delaunay points",
992 psCloudInnerDelaunay->setPointRadius( gridstep / 200.0 );
994 psDelaunay = polyscope::registerSurfaceMesh(
"Delaunay surface",
995 del_positions, del_faces);
996 displayReconstruction();
1002 if (polyscope::pick::haveSelection()) {
1003 bool goodSelection =
false;
1004 auto selection = polyscope::pick::getSelection();
1005 auto selectedSurface =
static_cast<polyscope::SurfaceMesh*
>(selection.first);
1006 const auto idx = selection.second;
1009 auto surf = polyscope::getSurfaceMesh(
"Input surface");
1010 goodSelection = goodSelection || (selectedSurface == surf);
1011 const auto nv = selectedSurface->nVertices();
1013 if ( goodSelection )
1017 std::ostringstream otext;
1018 otext <<
"Selected vertex = " << idx;
1019 ImGui::Text(
"%s", otext.str().c_str() );
1025 if (ImGui::Button(
"Compute global tangent Delaunay complex"))
1027 computeGlobalTangentDelaunayComplex();
1029 if (ImGui::Button(
"Compute tangent cone"))
1031 computeTangentCone( pickPoint() );
1034 if (ImGui::Button(
"Compute local Delaunay complex"))
1036 computeLocalTangentDelaunayComplex( pickPoint() );
1039 ImGui::Checkbox(
"Remove empty cells", &remove_empty_cells );
1040 ImGui::Checkbox(
"Check local tangency", &local_tangency );
1041 if (ImGui::Button(
"Compute planes"))
1043 if (ImGui::Button(
"Compute reconstructions from triangles"))
1046 for (
int i = 0; i < nb_cones; ++i )
1049 updateReconstructionFromTangentConeTriangles( pickPoint() );
1051 displayReconstruction();
1054 if (ImGui::Button(
"Compute reconstruction from local Delaunay cplx"))
1057 for (
int i = 0; i < nb_cones; ++i )
1060 auto j = pickPoint();
1061 if ( ! useless_points.count( digital_points[ j ] ) )
1062 updateReconstructionFromLocalTangentDelaunayComplex( j );
1063 if ( current == 0 )
break;
1065 displayReconstruction();
1068 if (ImGui::Button(
"Compute outer reconstruction from local Delaunay cplx"))
1071 for (
int i = 0; i < nb_cones; ++i )
1074 updateOuterReconstructionFromLocalTangentDelaunayComplex( pickOuterPoint() );
1076 displayOuterReconstruction();
1079 if (ImGui::Button(
"Compute reconstructions from lines"))
1082 for (
int i = 0; i < nb_cones; ++i )
1085 updateReconstructionFromTangentConeLines( pickPoint() );
1087 displayReconstruction();
1090 ImGui::SliderInt(
"Nb cones for reconstruction", &nb_cones, 1, 100);
1091 ImGui::Text(
"Computation time = %f ms", Time );
1092 ImGui::Text(
"#X = %ld, #P = %ld, #U = %ld",
1093 digital_points.size(), current, useless_points.size() );
1094 if (ImGui::Button(
"Mid reconstructions"))
1095 displayMidReconstruction();
1096 if (ImGui::Button(
"Remaining points"))
1097 displayRemainingPoints();
1101int main(
int argc,
char* argv[] )
1104 params(
"surfaceComponents",
"All");
1105 if ( argc <= 1 )
return 0;
1106 bool input_polynomial = argc > 2;
1107 std::string filename = std::string( argv[ 1 ] );
1108 std::string polynomial = std::string( argv[ 1 ] );
1109 const double h = argc >= 3 ? atof( argv[ 2 ] ) : 1.0;
1110 const double bounds = argc >= 4 ? atof( argv[ 3 ] ) : 10.0;
1113 if ( input_polynomial )
1115 params(
"polynomial", polynomial );
1116 params(
"gridstep", h );
1117 params(
"minAABB", -bounds );
1118 params(
"maxAABB", bounds );
1119 params(
"offset", 1.0 );
1120 params(
"closed", 1 );
1141 for (
Size i = 0; i < surfels.size(); i++ )
1142 surfel2idx[
K.
sKCoords( surfels[ i ] ) ] = i;
1144 std::set< Point > I;
1145 for (
auto s : surfels ) I.
insert(
K.interiorVoxel( s ) );
1146 digital_points = std::vector<Point>( I.cbegin(), I.cend() );
1148 std::set< Point > O;
1149 for (
auto s : surfels ) O.
insert(
K.exteriorVoxel( s ) );
1150 outer_digital_points = std::vector<Point>( O.cbegin(), O.cend() );
1152 intercepts = std::vector< double >( surfels.size(), 0.0 );
1153 outer_intercepts = std::vector< double >( surfels.size(), 0.0 );
1158 std::vector<std::vector<SH3::SurfaceMesh::Vertex>> faces;
1159 std::vector<RealPoint> positions;
1160 for(
auto face= 0 ; face < primalSurface->nbFaces(); ++face)
1161 faces.push_back(primalSurface->incidentVertices( face ));
1164 positions = primalSurface->positions();
1170 for(
auto face= 0 ; face < dualSurface->nbFaces(); ++face)
1171 dual_faces.push_back( dualSurface->verticesAroundFace( face ));
1174 for (
auto vtx = 0; vtx < dualSurface->nbVertices(); ++vtx )
1175 dual_positions.push_back( dualSurface->position( vtx ) );
1177 dual_surfmesh =
SurfMesh(dual_positions.begin(),
1178 dual_positions.end(),
1181 outer_dual_faces = dual_faces;
1182 outer_dual_positions = dual_positions;
1183 outer_dual_surfmesh =
SurfMesh(outer_dual_positions.begin(),
1184 outer_dual_positions.end(),
1185 outer_dual_faces.begin(),
1186 outer_dual_faces.end());
1187 std::cout <<
surfmesh << std::endl;
1190 trace.
info() <<
"Inner points has " << digital_points.size() <<
" points." << std::endl;
1191 trace.
info() <<
"Outer points has " << outer_digital_points.size() <<
" points." << std::endl;
1194 TC.init( digital_points.cbegin(), digital_points.cend() );
1196 outer_TC.init( outer_digital_points.cbegin(), outer_digital_points.cend() );
1197 trace.
info() <<
"#cell_cover = " << TC.cellCover().nbCells() << std::endl;
1198 trace.
info() <<
"#outer_cell_cover = " << outer_TC.cellCover().nbCells() << std::endl;
1200 ( digital_points.cbegin(), digital_points.cend(), 0 ).
starOfPoints();
1201 trace.
info() <<
"#lattice_cover = " << LS.
size() << std::endl;
1203 ( outer_digital_points.cbegin(), outer_digital_points.cend(), 0 ).
starOfPoints();
1204 trace.
info() <<
"#outer_lattice_cover = " << outer_LS.
size() << std::endl;
1209 psMesh = polyscope::registerSurfaceMesh(
"Input surface", positions, faces);
1210 displayReconstruction();
1211 displayOuterReconstruction();
1218 return EXIT_SUCCESS;
Aim: Smart pointer based on reference counts.
bool isFullySubconvex(const PointRange &Y, const LatticeSet &StarX) const
LatticeSet StarCvxH(const PointRange &X, Dimension axis=dimension) const
LatticePolytope makePolytope(const PointRange &X, bool make_minkowski_summable=false) const
Aim: This class is a model of CCellularGridSpaceND. It represents the cubical grid as a cell complex,...
Point interiorVoxel(const SCell &c) const
For a given surfel ((n-1)-signed cell), returns its interior voxel (point in Z^d given by the direct ...
Cell uIncident(const Cell &c, Dimension k, bool up) const
Return the forward or backward unsigned cell incident to [c] along axis [k], depending on [up].
const Point & lowerBound() const
Return the lower bound for digital points in this space.
DirIterator uDirs(const Cell &p) const
Given an unsigned cell [p], returns an iterator to iterate over each coordinate the cell spans.
Cell uCell(const PreCell &c) const
From an unsigned cell, returns an unsigned cell lying into this Khalismky space.
const Point & sKCoords(const SCell &c) const
Return its Khalimsky coordinates.
const Point & upperBound() const
Return the upper bound for digital points in this space.
Dimension uDim(const Cell &p) const
Return the dimension of the cell [p].
Point uCoords(const Cell &c) const
Return its digital coordinates.
Point exteriorVoxel(const SCell &c) const
For a given surfel ((n-1)-signed cell), returns its exterior voxel (point in Z^d given by the indirec...
Self starOfPoints() const
bool includes(const Self &other) const
Aim: A class that locally estimates a normal on a digital set using only a predicate "does a point x ...
PointVector< dim, double, std::array< double, dim > > getNormalized() const
auto dot(const PointVector< dim, OtherComponent, OtherStorage > &v) const -> decltype(DGtal::dotProduct(*this, v))
Dot product with a PointVector.
double norm(const NormType type=L_2) const
static Self diagonal(Component val=1)
Aim: This class is used to simplify shape and surface creation. With it, you can create new shapes an...
static Parameters parametersGeometryEstimation()
static Parameters defaultParameters()
Aim: This class is used to simplify shape and surface creation. With it, you can create new shapes an...
static KSpace getKSpace(const Point &low, const Point &up, Parameters params=parametersKSpace())
static CountedPtr< DigitizedImplicitShape3D > makeDigitizedImplicitShape3D(CountedPtr< ImplicitShape3D > shape, Parameters params=parametersDigitizedImplicitShape3D())
std::map< Surfel, IdxSurfel > Surfel2Index
static SurfelRange getSurfelRange(CountedPtr< ::DGtal::DigitalSurface< TDigitalSurfaceContainer > > surface, const Parameters ¶ms=parametersDigitalSurface())
static CountedPtr< DigitalSurface > makeDigitalSurface(CountedPtr< TPointPredicate > bimage, const KSpace &K, const Parameters ¶ms=parametersDigitalSurface())
static CountedPtr< PolygonalSurface > makeDualPolygonalSurface(Surfel2Index &s2i, CountedPtr< ::DGtal::DigitalSurface< TContainer > > aSurface)
static Parameters defaultParameters()
static CountedPtr< SurfaceMesh > makePrimalSurfaceMesh(Cell2Index &c2i, CountedPtr< ::DGtal::DigitalSurface< TContainer > > aSurface)
static CountedPtr< BinaryImage > makeBinaryImage(Domain shapeDomain)
static CountedPtr< ImplicitShape3D > makeImplicitShape3D(const Parameters ¶ms=parametersImplicitShape3D())
Aim: A class that computes tangency to a given digital set. It provides services to compute all the c...
void beginBlock(const std::string &keyword="")
void progressBar(const double currentValue, const double maximalValue)
polyscope::SurfaceMesh * psMesh
CountedPtr< SH3::DigitalSurface > surface
CountedPtr< SH3::BinaryImage > binary_image
Space::RealPoint RealPoint
DGtal is the top-level namespace which contains all DGtal functions and types.
auto crossProduct(PointVector< 3, LeftEuclideanRing, LeftContainer > const &lhs, PointVector< 3, RightEuclideanRing, RightContainer > const &rhs) -> decltype(DGtal::constructFromArithmeticConversion(lhs, rhs))
Cross product of two 3D Points/Vectors.
DGtal::uint32_t Dimension
std::pair< typename graph_traits< DGtal::DigitalSurface< TDigitalSurfaceContainer > >::edge_iterator, typename graph_traits< DGtal::DigitalSurface< TDigitalSurfaceContainer > >::edge_iterator > edges(const DGtal::DigitalSurface< TDigitalSurfaceContainer > &digSurf)
std::pair< typename graph_traits< DGtal::DigitalSurface< TDigitalSurfaceContainer > >::vertex_iterator, typename graph_traits< DGtal::DigitalSurface< TDigitalSurfaceContainer > >::vertex_iterator > vertices(const DGtal::DigitalSurface< TDigitalSurfaceContainer > &digSurf)
Aim: represents a d-dimensional complex in a d-dimensional space with the following properties and re...
std::vector< Point > cellVertexPositions(const Cell c) const
Cell faceCell(const Face f) const
const VertexRange & cellVertices(const Cell c) const
Face opposite(const Face f) const
Point position(const Vertex v) const
VertexRange faceVertices(const Face f) const
std::vector< Point > faceVertexPositions(const Face f) const
void requireFaceGeometry()
Forces the computation of face geometry.
bool isInfinite(const Cell c) const
Aim: a geometric kernel to compute the convex hull of digital points with integer-only arithmetic.
Aim: Provides a set of functions to facilitate the computation of convex hulls and polytopes,...
static bool computeDelaunayCellComplex(ConvexCellComplex< Point > &cell_complex, const PointRange &input_points, bool remove_duplicates=true)
Aim: Implements the quickhull algorithm by Barber et al. barber1996, a famous arbitrary dimensional c...
bool setInput(const std::vector< InputPoint > &input_points, bool remove_duplicates=true)
std::vector< Index > IndexRange
bool getFacetVertices(std::vector< IndexRange > &facet_vertices) const
bool getVertexPositions(std::vector< OutputPoint > &vertex_positions)
bool computeConvexHull(Status target=Status::VerticesCompleted)
Represents a signed cell in a cellular grid space by its Khalimsky coordinates and a boolean value.
Aim: Represents an embedded mesh as faces and a list of vertices. Vertices may be shared among faces ...
HalfEdgeDataStructure::Size Size
void insert(VContainer1 &c1, LContainer2 &c2, unsigned int idx, double v)