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 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 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 )
516 if ( digital_points.empty() )
return;
517 if ( vertex_idx < 0 || vertex_idx >= digital_points.size() )
return;
518 typedef std::size_t
Size;
519 const auto p = digital_points[ vertex_idx ];
521 auto local_X_idx = TC.getCotangentPoints( p );
522 std::vector< Point > local_X;
523 for (
auto idx : local_X_idx )
524 local_X.push_back( TC.point( idx ) );
525 for (
auto&& q : local_X )
527 std::vector< Point > X { p, q };
529 updateReconstructionFromCells( p, q, line_cells.toPointRange() );
533void updateReconstructionFromTangentConeTriangles(
int vertex_idx )
536 if ( digital_points.empty() )
return;
537 if ( vertex_idx < 0 || vertex_idx >= digital_points.size() )
return;
538 typedef std::size_t
Size;
539 const auto p = digital_points[ vertex_idx ];
541 auto local_X_idx = TC.getCotangentPoints( p );
542 local_X_idx.push_back( vertex_idx );
543 std::vector< Point > local_X;
544 for (
auto idx : local_X_idx )
545 local_X.push_back( TC.point( idx ) );
549 std::vector< Point > positions;
552 std::vector< IndexRange > facet_vertices;
554 if ( ! ok )
trace.
error() <<
"Bad facet computation" << std::endl;
556 std::set< std::pair< Point, Point > >
edges;
557 for (
auto&& facet : facet_vertices )
559 const auto nb = facet.size();
560 for (
auto i = 0; i < nb; i++ )
561 edges.insert( std::make_pair( positions[ facet[ i ] ],
562 positions[ facet[ (i+1)%nb ] ] ) );
564 for (
auto&& e : edges )
566 if ( e.second < e.first )
continue;
567 std::vector< Point > X { p, e.first, e.second };
568 const auto triangle_cells = dconv.
StarCvxH( X, LS.
axis() );
569 if ( LS.
includes( triangle_cells ) )
570 updateReconstructionFromCells( X, triangle_cells.toPointRange() );
609void computeTangentCone(
int vertex_idx)
611 if ( digital_points.empty() )
return;
613 const auto p = digital_points[ vertex_idx ];
615 auto local_X_idx = TC.getCotangentPoints( p );
616 std::cout <<
"#cone=" << local_X_idx.size() << std::endl;
617 local_X_idx.push_back( vertex_idx );
618 std::vector< Point > local_X;
619 std::vector< RealPoint > emb_local_X;
620 for (
auto idx : local_X_idx )
621 local_X.push_back( TC.point( idx ) );
622 std::vector< double > values( local_X.size(), 0.0 );
624 embedVoxels( local_X, emb_local_X );
625 psCloud = polyscope::registerPointCloud(
"Tangent cone", emb_local_X );
626 psCloud->setPointRadius( gridstep / 300.0 );
627 psCloud->addScalarQuantity(
"Classification", values );
631 std::vector< Point > positions;
632 std::vector< RealPoint > emb_positions;
635 embedVoxels( positions, emb_positions );
636 psCloudCvx = polyscope::registerPointCloud(
"Tangent cone vertices", emb_positions );
637 psCloudCvx->setPointRadius( gridstep / 200.0 );
639 updateReconstructionFromTangentConeTriangles( vertex_idx );
640 displayReconstruction();
644void updateReconstructionFromLocalTangentDelaunayComplex(
int vertex_idx)
646 if ( digital_points.empty() )
return;
648 const auto p = digital_points[ vertex_idx ];
649 auto local_X_idx = TC.getCotangentPoints( p );
650 local_X_idx.push_back( vertex_idx );
651 std::vector< Point > local_X;
652 for (
auto idx : local_X_idx )
653 local_X.push_back( TC.point( idx ) );
655 if ( local_tangency )
664 trace.
error() <<
"Input set of points is not full dimensional." << std::endl;
668 std::vector< bool > is_cell_tangent( dcomplex.
nbCells(),
false );
669 if ( remove_empty_cells )
674 if ( P.countUpTo( Y.size()+1 ) >= Y.size()+1 )
continue;
675 is_cell_tangent[ c ] =
684 is_cell_tangent[ c ] =
690 std::vector< std::vector<SH3::SurfaceMesh::Vertex> > del_faces;
691 std::vector< RealPoint > del_positions;
692 std::set<Index> boundary_or_ext_points;
695 auto f0 = std::make_pair( f,
false );
704 if ( ! is_cell_tangent[ c0 ] )
707 boundary_or_ext_points.insert( V.cbegin(), V.cend() );
709 if ( ! dcomplex.
isInfinite( c1 ) && ! is_cell_tangent[ c1 ] )
712 boundary_or_ext_points.insert( V.cbegin(), V.cend() );
715 ( is_cell_tangent[ c0 ] && ( dcomplex.
isInfinite( c1 )
716 || ( ! is_cell_tangent[ c1 ] ) ) )
718 ( ! is_cell_tangent[ c0 ] && ( ! dcomplex.
isInfinite( c1 )
719 && ( is_cell_tangent[ c1 ] ) ) );
720 if ( ! bdry )
continue;
722 const auto triangle_cells = dconv.
StarCvxH( X, LS.
axis() );
724 updateReconstructionFromCells( X, triangle_cells.toPointRange() );
726 useless_points.insert( p );
730 if ( ! boundary_or_ext_points.count( v ) )
731 useless_points.insert( q );
737void updateOuterReconstructionFromLocalTangentDelaunayComplex(
int vertex_idx)
739 if ( outer_digital_points.empty() )
return;
741 const auto p = outer_digital_points[ vertex_idx ];
742 auto local_X_idx = outer_TC.getCotangentPoints( p );
743 local_X_idx.push_back( vertex_idx );
744 std::vector< Point > local_X;
745 for (
auto idx : local_X_idx )
746 local_X.push_back( outer_TC.point( idx ) );
754 trace.
error() <<
"Input set of points is not full dimensional." << std::endl;
758 std::vector< bool > is_cell_tangent( dcomplex.
nbCells(),
false );
759 if ( remove_empty_cells )
764 if ( P.countUpTo( Y.size()+1 ) >= Y.size()+1 )
continue;
774 std::vector< std::vector<SH3::SurfaceMesh::Vertex> > del_faces;
777 auto f0 = std::make_pair( f,
false );
787 ( is_cell_tangent[ c0 ] && ( dcomplex.
isInfinite( c1 )
788 || ( ! is_cell_tangent[ c1 ] ) ) )
790 ( ! is_cell_tangent[ c0 ] && ( ! dcomplex.
isInfinite( c1 )
791 && ( is_cell_tangent[ c1 ] ) ) );
792 if ( ! bdry )
continue;
794 const auto triangle_cells = dconv.
StarCvxH( X, outer_LS.
axis() );
796 updateOuterReconstructionFromCells( X, triangle_cells.toPointRange() );
801void computeLocalTangentDelaunayComplex(
int vertex_idx)
803 if ( digital_points.empty() )
return;
805 const auto p = digital_points[ vertex_idx ];
807 auto local_X_idx = TC.getCotangentPoints( p );
808 std::cout <<
"#cone=" << local_X_idx.size() << std::endl;
809 local_X_idx.push_back( vertex_idx );
810 std::vector< Point > local_X;
811 for (
auto idx : local_X_idx )
812 local_X.push_back( TC.point( idx ) );
814 if ( local_tangency )
823 trace.
error() <<
"Input set of points is not full dimensional." << std::endl;
827 std::vector< bool > is_cell_tangent( dcomplex.
nbCells(),
false );
828 if ( remove_empty_cells )
833 if ( P.countUpTo( Y.size()+1 ) >= Y.size()+1 )
continue;
834 is_cell_tangent[ c ] =
843 is_cell_tangent[ c ] =
849 std::vector< std::vector<SH3::SurfaceMesh::Vertex> > del_faces;
850 std::vector< RealPoint > del_positions;
851 std::vector< RealPoint > del_inner_points;
852 std::set<Index> boundary_or_ext_points;
855 auto f0 = std::make_pair( f,
false );
864 if ( ! is_cell_tangent[ c0 ] )
867 boundary_or_ext_points.insert( V.cbegin(), V.cend() );
869 if ( ! dcomplex.
isInfinite( c1 ) && ! is_cell_tangent[ c1 ] )
872 boundary_or_ext_points.insert( V.cbegin(), V.cend() );
875 ( is_cell_tangent[ c0 ] && ( dcomplex.
isInfinite( c1 )
876 || ( ! is_cell_tangent[ c1 ] ) ) )
878 ( ! is_cell_tangent[ c0 ] && ( ! dcomplex.
isInfinite( c1 )
879 && ( is_cell_tangent[ c1 ] ) ) );
880 if ( bdry ) del_faces.push_back( dcomplex.
faceVertices( f0 ) );
885 del_positions.push_back( voxelPoint2RealPoint( p ) );
886 if ( ! boundary_or_ext_points.count( v ) )
887 del_inner_points.push_back( voxelPoint2RealPoint( p ) );
891 psCloudInnerDelaunay = polyscope::registerPointCloud(
"Inner Delaunay points",
893 psCloudInnerDelaunay->setPointRadius( gridstep / 200.0 );
895 psDelaunay = polyscope::registerSurfaceMesh(
"Delaunay surface",
896 del_positions, del_faces);
897 updateReconstructionFromLocalTangentDelaunayComplex( vertex_idx );
898 displayReconstruction();
902void computeGlobalTangentDelaunayComplex()
904 if ( digital_points.empty() )
return;
906 const auto p = digital_points[ vertex_idx ];
915 trace.
error() <<
"Input set of points is not full dimensional." << std::endl;
921 std::vector< bool > is_cell_tangent( dcomplex.
nbCells(),
false );
926 if ( P.countUpTo( Y.size()+1 ) >= Y.size()+1 )
continue;
931 std::vector< std::vector<SH3::SurfaceMesh::Vertex> > del_faces;
932 std::vector< RealPoint > del_positions;
933 std::vector< RealPoint > del_inner_points;
934 std::set<Index> useful_points;
935 std::vector< std::pair< Index, bool > > all_bdry_faces;
938 auto f0 = std::make_pair( f,
false );
944 std::swap( c0, c1 ); std::swap( f0, f1 );
946 const bool inf_c1 = dcomplex.
isInfinite( c1 );
947 const bool bdry_f0 = is_cell_tangent[ c0 ] &&
948 ( inf_c1 || ! is_cell_tangent[ c1 ] );
949 const bool bdry_f1 = ( ! is_cell_tangent[ c0 ] )
950 && ( ( ! inf_c1 ) && is_cell_tangent[ c1 ] );
955 del_faces.push_back( V );
956 useful_points.insert( V.cbegin(), V.cend() );
957 all_bdry_faces.push_back( f0 );
962 del_faces.push_back( V );
963 useful_points.insert( V.cbegin(), V.cend() );
964 all_bdry_faces.push_back( f1 );
966 else if ( ( ! ( is_cell_tangent[ c0 ] || inf_c1 || is_cell_tangent[ c0 ] )
967 || ( ! is_cell_tangent[ c0 ] && inf_c1 ) )
971 del_faces.push_back( V );
972 useful_points.insert( V.cbegin(), V.cend() );
974 all_bdry_faces.push_back( f0 );
980 del_positions.push_back( voxelPoint2RealPoint( p ) );
981 if ( ! useful_points.count( v ) )
983 del_inner_points.push_back( voxelPoint2RealPoint( p ) );
984 useless_points.insert( p );
990 const auto axis = LS.
axis();
991 for (
auto f : all_bdry_faces )
994 const auto cells = dconv.
StarCvxH( X, axis );
997 updateReconstructionFromCells( X, cells.toPointRange() );
1001 psCloudInnerDelaunay = polyscope::registerPointCloud(
"Inner Delaunay points",
1003 psCloudInnerDelaunay->setPointRadius( gridstep / 200.0 );
1005 psDelaunay = polyscope::registerSurfaceMesh(
"Delaunay surface",
1006 del_positions, del_faces);
1007 displayReconstruction();
1013 if (polyscope::pick::haveSelection()) {
1014 bool goodSelection =
false;
1015 auto selection = polyscope::pick::getSelection();
1016 auto selectedSurface =
static_cast<polyscope::SurfaceMesh*
>(selection.first);
1017 int idx = selection.second;
1020 auto surf = polyscope::getSurfaceMesh(
"Input surface");
1021 goodSelection = goodSelection || (selectedSurface == surf);
1022 const auto nv = selectedSurface->nVertices();
1024 if ( goodSelection )
1028 std::ostringstream otext;
1029 otext <<
"Selected vertex = " << idx;
1030 ImGui::Text(
"%s", otext.str().c_str() );
1033 else vertex_idx = -1;
1036 if (ImGui::Button(
"Compute global tangent Delaunay complex"))
1038 computeGlobalTangentDelaunayComplex();
1040 if (ImGui::Button(
"Compute tangent cone"))
1042 computeTangentCone( pickPoint() );
1045 if (ImGui::Button(
"Compute local Delaunay complex"))
1047 computeLocalTangentDelaunayComplex( pickPoint() );
1050 ImGui::Checkbox(
"Remove empty cells", &remove_empty_cells );
1051 ImGui::Checkbox(
"Check local tangency", &local_tangency );
1052 if (ImGui::Button(
"Compute planes"))
1054 if (ImGui::Button(
"Compute reconstructions from triangles"))
1057 for (
int i = 0; i < nb_cones; ++i )
1060 updateReconstructionFromTangentConeTriangles( pickPoint() );
1062 displayReconstruction();
1065 if (ImGui::Button(
"Compute reconstruction from local Delaunay cplx"))
1068 for (
int i = 0; i < nb_cones; ++i )
1071 auto j = pickPoint();
1072 if ( ! useless_points.count( digital_points[ j ] ) )
1073 updateReconstructionFromLocalTangentDelaunayComplex( j );
1074 if ( current == 0 )
break;
1076 displayReconstruction();
1079 if (ImGui::Button(
"Compute outer reconstruction from local Delaunay cplx"))
1082 for (
int i = 0; i < nb_cones; ++i )
1085 updateOuterReconstructionFromLocalTangentDelaunayComplex( pickOuterPoint() );
1087 displayOuterReconstruction();
1090 if (ImGui::Button(
"Compute reconstructions from lines"))
1093 for (
int i = 0; i < nb_cones; ++i )
1096 updateReconstructionFromTangentConeLines( pickPoint() );
1098 displayReconstruction();
1101 ImGui::SliderInt(
"Nb cones for reconstruction", &nb_cones, 1, 100);
1102 ImGui::Text(
"Computation time = %f ms", Time );
1103 ImGui::Text(
"#X = %ld, #P = %ld, #U = %ld",
1104 digital_points.size(), current, useless_points.size() );
1105 if (ImGui::Button(
"Mid reconstructions"))
1106 displayMidReconstruction();
1107 if (ImGui::Button(
"Remaining points"))
1108 displayRemainingPoints();
1112int main(
int argc,
char* argv[] )
1115 params(
"surfaceComponents",
"All");
1116 if ( argc <= 1 )
return 0;
1117 bool input_polynomial = argc > 2;
1118 std::string filename = std::string( argv[ 1 ] );
1119 std::string polynomial = std::string( argv[ 1 ] );
1120 const double h = argc >= 3 ? atof( argv[ 2 ] ) : 1.0;
1121 const double bounds = argc >= 4 ? atof( argv[ 3 ] ) : 10.0;
1124 if ( input_polynomial )
1126 params(
"polynomial", polynomial );
1127 params(
"gridstep", h );
1128 params(
"minAABB", -bounds );
1129 params(
"maxAABB", bounds );
1130 params(
"offset", 1.0 );
1131 params(
"closed", 1 );
1152 for (
Size i = 0; i < surfels.size(); i++ )
1153 surfel2idx[
K.
sKCoords( surfels[ i ] ) ] = i;
1155 std::set< Point > I;
1157 digital_points = std::vector<Point>( I.cbegin(), I.cend() );
1159 std::set< Point > O;
1161 outer_digital_points = std::vector<Point>( O.cbegin(), O.cend() );
1163 intercepts = std::vector< double >( surfels.size(), 0.0 );
1164 outer_intercepts = std::vector< double >( surfels.size(), 0.0 );
1169 std::vector<std::vector<SH3::SurfaceMesh::Vertex>> faces;
1170 std::vector<RealPoint> positions;
1171 for(
auto face= 0 ; face < primalSurface->nbFaces(); ++face)
1172 faces.push_back(primalSurface->incidentVertices( face ));
1175 positions = primalSurface->positions();
1177 surfmesh =
SurfMesh(positions.begin(),
1181 for(
auto face= 0 ; face < dualSurface->nbFaces(); ++face)
1182 dual_faces.push_back( dualSurface->verticesAroundFace( face ));
1185 for (
auto vtx = 0; vtx < dualSurface->nbVertices(); ++vtx )
1186 dual_positions.push_back( dualSurface->position( vtx ) );
1188 dual_surfmesh =
SurfMesh(dual_positions.begin(),
1189 dual_positions.end(),
1192 outer_dual_faces = dual_faces;
1193 outer_dual_positions = dual_positions;
1194 outer_dual_surfmesh =
SurfMesh(outer_dual_positions.begin(),
1195 outer_dual_positions.end(),
1196 outer_dual_faces.begin(),
1197 outer_dual_faces.end());
1198 std::cout << surfmesh << std::endl;
1201 trace.
info() <<
"Inner points has " << digital_points.size() <<
" points." << std::endl;
1202 trace.
info() <<
"Outer points has " << outer_digital_points.size() <<
" points." << std::endl;
1205 TC.init( digital_points.cbegin(), digital_points.cend() );
1207 outer_TC.init( outer_digital_points.cbegin(), outer_digital_points.cend() );
1208 trace.
info() <<
"#cell_cover = " << TC.cellCover().nbCells() << std::endl;
1209 trace.
info() <<
"#outer_cell_cover = " << outer_TC.cellCover().nbCells() << std::endl;
1211 ( digital_points.cbegin(), digital_points.cend(), 0 ).
starOfPoints();
1212 trace.
info() <<
"#lattice_cover = " << LS.
size() << std::endl;
1214 ( outer_digital_points.cbegin(), outer_digital_points.cend(), 0 ).
starOfPoints();
1215 trace.
info() <<
"#outer_lattice_cover = " << outer_LS.
size() << std::endl;
1220 psMesh = polyscope::registerSurfaceMesh(
"Input surface", positions, faces);
1221 displayReconstruction();
1222 displayOuterReconstruction();
1227 polyscope::state::userCallback = myCallback;
1229 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)
static Self zero
Static const for zero PointVector.
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)
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
std::vector< Vertex > VertexRange
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. , a famous arbitrary dimensional convex hull...
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
TriMesh::VertexRange VertexRange