DGtal 1.3.0
Loading...
Searching...
No Matches
tangency-reconstruction.cpp
1
25#include <iostream>
26#include <string>
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>
36
37#include <polyscope/pick.h>
38#include <polyscope/polyscope.h>
39#include <polyscope/surface_mesh.h>
40#include <polyscope/point_cloud.h>
41
42
43using namespace DGtal;
44using namespace Z3i;
45
46// Using standard 3D digital space.
49// The following typedefs are useful
52typedef SurfMesh::Face Face;
56typedef std::size_t Size;
57//typedef Z3i::KSpace::SCell SCell;
58//Polyscope global
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;
70
71SurfMesh surfmesh;
72SurfMesh dual_surfmesh;
73SurfMesh outer_dual_surfmesh;
74float gridstep = 1.0;
75int vertex_idx = -1;
76float Time = 0.0;
77int nb_cones = 10;
78bool remove_empty_cells = false;
79bool local_tangency = false;
80
81Size current = 0;
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;
96
97KSpace K;
103
105typedef std::vector< Index > Indices;
106typedef double Scalar;
107typedef std::vector< Scalar > Scalars;
108
109Size pickPoint()
110{
111 if ( order.size() != digital_points.size() )
112 {
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);
117 current = 0;
118 }
119 if ( current == order.size() ) current = 0;
120 return order[ current++ ];
121}
122Size pickOuterPoint()
123{
124 if ( outer_order.size() != outer_digital_points.size() )
125 {
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);
130 outer_current = 0;
131 }
132 if ( outer_current == outer_order.size() ) outer_current = 0;
133 return outer_order[ outer_current++ ];
134}
135
136// ----------------------------------------------------------------------
137// utilities pointel
138Point pointelRealPoint2Point( RealPoint p )
139{
140 RealPoint sp = RealPoint( round( p[ 0 ] / gridstep + 0.5 ),
141 round( p[ 1 ] / gridstep + 0.5 ),
142 round( p[ 2 ] / gridstep + 0.5 ) );
143 return Point( sp[ 0 ], sp[ 1 ], sp[ 2 ] );
144}
145RealPoint pointelPoint2RealPoint( Point q )
146{
147 return RealPoint( gridstep * ( q[ 0 ] - 0.5 ),
148 gridstep * ( q[ 1 ] - 0.5 ),
149 gridstep * ( q[ 2 ] - 0.5 ) );
150}
151void embedPointels( const std::vector< Point >& vq, std::vector< RealPoint >& vp )
152{
153 vp.resize( vq.size() );
154 for ( auto i = 0; i < vp.size(); ++i )
155 vp[ i ] = pointelPoint2RealPoint( vq[ i ] );
156}
157void digitizePointels( const std::vector< RealPoint >& vp, std::vector< Point >& vq )
158{
159 vq.resize( vp.size() );
160 for ( auto i = 0; i < vq.size(); ++i )
161 vq[ i ] = pointelRealPoint2Point( vp[ i ] );
162}
163
164// ----------------------------------------------------------------------
165// utilities voxel
166Point voxelRealPoint2Point( RealPoint p )
167{
168 RealPoint sp = RealPoint( round( p[ 0 ] / gridstep ),
169 round( p[ 1 ] / gridstep ),
170 round( p[ 2 ] / gridstep ) );
171 return Point( sp[ 0 ], sp[ 1 ], sp[ 2 ] );
172}
173RealPoint voxelPoint2RealPoint( Point q )
174{
175 return RealPoint( gridstep * ( q[ 0 ] ),
176 gridstep * ( q[ 1 ] ),
177 gridstep * ( q[ 2 ] ) );
178}
179void embedVoxels( const std::vector< Point >& vq, std::vector< RealPoint >& vp )
180{
181 vp.resize( vq.size() );
182 for ( auto i = 0; i < vp.size(); ++i )
183 vp[ i ] = voxelPoint2RealPoint( vq[ i ] );
184}
185void digitizeVoxels( const std::vector< RealPoint >& vp, std::vector< Point >& vq )
186{
187 vq.resize( vp.size() );
188 for ( auto i = 0; i < vq.size(); ++i )
189 vq[ i ] = voxelRealPoint2Point( vp[ i ] );
190}
191
192// @return the indices of all the points of X different from p that are cotangent to p.
193Indices tangentCone( const Point& p )
194{
195 return TC.getCotangentPoints( p );
196}
197
198Scalars distances( const Point& p, const Indices& idx )
199{
200 Scalars D( idx.size() );
201 for ( Index i = 0; i < idx.size(); i++ )
202 D[ i ] = ( TC.point( i ) - p ).norm();
203 return D;
204}
205
207std::vector< Point >
208findCorners( const std::unordered_set< Point >& S,
209 const std::vector< Vector >& In,
210 const std::vector< Vector >& Out )
211{
212 std::vector< Point > C;
213 for ( auto&& p : S )
214 {
215 bool corner = true;
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 );
222 }
223 return C;
224}
225
226void computeQuadrant( int q,
227 std::vector< Vector >& In,
228 std::vector< Vector >& Out )
229{
230 In.clear();
231 Out.clear();
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 ) );
236 Vector D = ( In[ 1 ] - In[ 0 ] ).crossProduct( In[ 2 ] - In[ 0 ] );
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 ] );
241}
242
243struct UnorderedPointSetPredicate
244{
245 typedef DGtal::Z3i::Point Point;
246 const std::unordered_set< Point >* myS;
247 explicit UnorderedPointSetPredicate( const std::unordered_set< Point >& S )
248 : myS( &S ) {}
249 bool operator()( const Point& p ) const
250 { return myS->count( p ) != 0; }
251};
252
253void computePlanes()
254{
255 // - mode specifies the candidate set, it is one of { ProbingMode::H, ProbingMode::R, ProbingMode::R1 }.
256 using Estimator
257 = DGtal::PlaneProbingTetrahedronEstimator< UnorderedPointSetPredicate,
258 ProbingMode::R >;
259 trace.beginBlock( "Compute planes" );
260 std::vector< RealPoint > positions;
261 std::vector< Point > vertices;
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 );
267 Index i = 0;
268 for ( int q = 0; q < 8; q++ ) // for each quadrant
269 {
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 )
275 {
276 Estimator estimator( p, m, predS );
277 // if ( estimator.hexagonState()
278 // != Estimator::Neighborhood::HexagonState::Planar)
279 // continue;
280 std::vector<SH3::SurfaceMesh::Vertex> triangle { i, i+1, i+2 };
281 auto v = estimator.vertices();
282 faces.push_back( triangle );
283 vertices.push_back( v[ 0 ] );
284 vertices.push_back( v[ 1 ] );
285 vertices.push_back( v[ 2 ] );
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 ] ) )
291 {
292 std::vector< Point > X { v[ 0 ], v[ 1 ], v[ 2 ] };
293 auto P = dconv.makePolytope( X );
294 if ( dconv.isFullySubconvex( P, TC.cellCover() ) )
295 // // && TC.arePointsCotangent( v[ 0 ], v[ 1 ], v[ 2 ] ) )
296 {
297 vertices[ i ] = v[ 0 ];
298 vertices[ i+1 ] = v[ 1 ];
299 vertices[ i+2 ] = v[ 2 ];
300 }
301 }
302 }
303 }
304 i += 3;
305 // }
306 }
307 }
308 Time = trace.endBlock();
309 embedPointels( vertices, positions );
310 psTriangle = polyscope::registerSurfaceMesh("Triangle", positions, faces);
311}
312
313void displayMidReconstruction()
314{
315 std::vector< RealPoint > mid_dual_positions( dual_positions.size() );
316 for ( auto i = 0; i < surfels.size(); i++ )
317 {
318 auto int_vox = K.interiorVoxel( surfels[ i ] );
319 auto ext_vox = K.exteriorVoxel( surfels[ i ] );
320 auto int_p = voxelPoint2RealPoint( int_vox ); //K.uCoords( int_vox ) );
321 auto ext_p = voxelPoint2RealPoint( ext_vox ); //K.uCoords( 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);
327 }
328 psDualMesh = polyscope::registerSurfaceMesh("Mid surface", mid_dual_positions, dual_faces);
329}
330
331void displayReconstruction()
332{
333 for ( auto i = 0; i < surfels.size(); i++ )
334 {
335 auto int_vox = K.interiorVoxel( surfels[ i ] );
336 auto ext_vox = K.exteriorVoxel( surfels[ i ] );
337 auto int_p = voxelPoint2RealPoint( int_vox ); //K.uCoords( int_vox ) );
338 auto ext_p = voxelPoint2RealPoint( ext_vox ); //K.uCoords( 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;
342 }
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 );
351
352}
353
354void displayRemainingPoints()
355{
356 std::vector< Point > X;
357 std::vector< RealPoint > emb_X;
358 for ( auto i = current; i < digital_points.size(); i++ )
359 {
360 Point p = digital_points[ order[ i ] ];
361 if ( ! useless_points.count( p ) )
362 X.push_back( p );
363 }
364 embedVoxels( X, emb_X );
365 psCloudProc = polyscope::registerPointCloud( "Remaining points", emb_X );
366 psCloudProc->setPointRadius( gridstep / 200.0 );
367}
368
369void displayOuterReconstruction()
370{
371 for ( auto i = 0; i < surfels.size(); i++ )
372 {
373 auto int_vox = K.interiorVoxel( surfels[ i ] );
374 auto ext_vox = K.exteriorVoxel( surfels[ i ] );
375 auto int_p = voxelPoint2RealPoint( int_vox ); //K.uCoords( int_vox ) );
376 auto ext_p = voxelPoint2RealPoint( ext_vox ); //K.uCoords( 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;
380 }
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 );
389
390}
391
392void updateReconstructionFromCells( const std::vector< Point >& X,
393 const std::vector< Point >& cells )
394{
395 // Compute plane
396 const Vector N = ( X[ 1 ] - X[ 0 ] ).crossProduct( X[ 2 ] - X[ 0 ] );
397 const auto a = N.dot( X[ 0 ] );
398 // Extract 1-cells which are dual to surfels
399 for ( auto&& kp : cells )
400 {
401 // Look for dimension 1 cells.
402 const Cell c = K.uCell( kp );
403 if ( K.uDim( c ) != 1 ) continue;
404 // Compute dual surfel
405 const Dimension t = *K.uDirs( c );
406 const Cell p0 = K.uIncident( c, t, false );
407 const Cell p1 = K.uIncident( c, t, true );
408 const Point dual_kp = K.uCoords( p0 ) + K.uCoords( p1 ) + Point::diagonal(1);
409 const auto it = surfel2idx.find( dual_kp );
410 if ( it == surfel2idx.cend() ) continue;
411 // Compute and update intercept
412 const Size idx = it->second;
413 const SCell surfel = surfels[ idx ];
414 const Point int_vox = K.interiorVoxel( surfel );
415 const Point ext_vox = K.exteriorVoxel( surfel );
416 const auto int_val = N.dot( int_vox );
417 const auto ext_val = N.dot( ext_vox );
418 // std::cout << " int_val=" << int_val << " a=" << a << " ext_val=" << ext_val;
419 if ( ( int_val <= a && ext_val <= a ) || ( int_val >= a && ext_val >= a ) )
420 {
421 if ( ( int_val < a && ext_val < a ) || ( int_val > a && ext_val > a ) )
422 trace.warning() << "Bad intersection" << std::endl;
423 continue;
424 }
425 const double s = (double)( a - int_val ) / (double) (ext_val - int_val );
426 const double old_s = intercepts[ idx ];
427 // if ( old_s < s ) std::cout << " s=" << old_s << " -> " << s << std::endl;
428 intercepts[ idx ] = std::max( old_s, s );
429 }
430}
431
432void updateOuterReconstructionFromCells( const std::vector< Point >& X,
433 const std::vector< Point >& cells )
434{
435 // Compute plane
436 const Vector N = ( X[ 1 ] - X[ 0 ] ).crossProduct( X[ 2 ] - X[ 0 ] );
437 const auto a = N.dot( X[ 0 ] );
438 // Extract 1-cells which are dual to surfels
439 for ( auto&& kp : cells )
440 {
441 // Look for dimension 1 cells.
442 const Cell c = K.uCell( kp );
443 if ( K.uDim( c ) != 1 ) continue;
444 // Compute dual surfel
445 const Dimension t = *K.uDirs( c );
446 const Cell p0 = K.uIncident( c, t, false );
447 const Cell p1 = K.uIncident( c, t, true );
448 const Point dual_kp = K.uCoords( p0 ) + K.uCoords( p1 ) + Point::diagonal(1);
449 const auto it = surfel2idx.find( dual_kp );
450 if ( it == surfel2idx.cend() ) continue;
451 // Compute and update intercept
452 const Size idx = it->second;
453 const SCell surfel = surfels[ idx ];
454 const Point int_vox = K.interiorVoxel( surfel );
455 const Point ext_vox = K.exteriorVoxel( surfel );
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 ) )
459 {
460 if ( ( int_val < a && ext_val < a ) || ( int_val > a && ext_val > a ) )
461 trace.warning() << "Bad intersection" << std::endl;
462 continue;
463 }
464 const double s = (double)( a - ext_val ) / (double) (int_val - ext_val );
465 outer_intercepts[ idx ] = std::max( outer_intercepts[ idx ], s );
466 }
467}
468
469void updateReconstructionFromCells( Point x, Point y,
470 const std::vector< Point >& cells )
471{
472 // Compute plane
473 const Vector U = y - x;
474 if ( U == Vector::zero ) return;
475 const double l = U.norm();
476 const RealVector u = U.getNormalized();
477 const RealPoint p( x[ 0 ], x[ 1 ], x[ 2 ] );
478 // Extract 1-cells which are dual to surfels
479 for ( auto&& kp : cells )
480 {
481 // Look for dimension 1 cells.
482 const Cell c = K.uCell( kp );
483 if ( K.uDim( c ) != 1 ) continue;
484 // Compute dual surfel
485 const Dimension r = *K.uDirs( c );
486 const Cell p0 = K.uIncident( c, r, false );
487 const Cell p1 = K.uIncident( c, r, true );
488 const Point dual_kp = K.uCoords( p0 ) + K.uCoords( p1 ) + Point::diagonal(1);
489 const auto it = surfel2idx.find( dual_kp );
490 if ( it == surfel2idx.cend() ) continue;
491 // Compute and update intercept
492 const Size idx = it->second;
493 const SCell surfel = surfels[ idx ];
494 const Point int_vox = K.interiorVoxel( surfel );
495 const Point ext_vox = K.exteriorVoxel( surfel );
496 const Vector V = ext_vox - int_vox;
497 const RealVector v = V.getNormalized();
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;
501 // Solving system to get closest points.
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; // on [xy]
506 const double t = ( c2 + uv * c1 ) / d; // on linel
507 if ( ( s < 0.0 ) || ( s > l ) ) continue;
508 // if ( ( t < 0.0 ) || ( t > 1.0 ) ) continue;
509 intercepts[ idx ] = std::max( intercepts[ idx ], std::min( t, 1.0 ) );
510 }
511}
512
513void updateReconstructionFromTangentConeLines( int vertex_idx )
514{
515 typedef QuickHull3D::IndexRange IndexRange;
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 ];
520 // trace.beginBlock( "Compute tangent cone" );
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 )
526 {
527 std::vector< Point > X { p, q };
528 const auto line_cells = dconv.StarCvxH( X, LS.axis() );
529 updateReconstructionFromCells( p, q, line_cells.toPointRange() );
530 }
531}
532
533void updateReconstructionFromTangentConeTriangles( int vertex_idx )
534{
535 typedef QuickHull3D::IndexRange IndexRange;
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 ];
540 // trace.beginBlock( "Compute tangent cone" );
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 ) );
546 QuickHull3D hull;
547 hull.setInput( local_X, false );
548 hull.computeConvexHull();
549 std::vector< Point > positions;
550 hull.getVertexPositions( positions );
551
552 std::vector< IndexRange > facet_vertices;
553 bool ok = hull.getFacetVertices( facet_vertices );
554 if ( ! ok ) trace.error() << "Bad facet computation" << std::endl;
555 // Update from all cones
556 std::set< std::pair< Point, Point > > edges;
557 for ( auto&& facet : facet_vertices )
558 {
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 ] ] ) );
563 }
564 for ( auto&& e : edges )
565 {
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 ) ) // tangent to shape
570 updateReconstructionFromCells( X, triangle_cells.toPointRange() );
571 }
572
573 // Miss features
574 // // Update from all facets
575 // for ( auto&& facet : facet_vertices )
576 // {
577 // const auto nb = facet.size();
578 // for ( auto i = 0; i < nb; i++ )
579 // for ( auto j = i+1; j < nb; j++ )
580 // for ( auto k = j+1; k < nb; k++ )
581 // {
582 // std::vector< Point > X
583 // { positions[ facet[ i ] ],
584 // positions[ facet[ j ] ],
585 // positions[ facet[ k ] ] };
586 // const auto triangle_cells = dconv.StarCvxH( X, LS.axis() );
587 // if ( LS.includes( triangle_cells ) ) // tangent to shape
588 // updateReconstructionFromCells( X, triangle_cells.toPointRange() );
589 // }
590 // }
591
592 // Too costly
593 // // Update from all possible triplets
594 // const auto nb = positions.size();
595 // for ( auto i = 0; i < nb; i++ )
596 // for ( auto j = i+1; j < nb; j++ )
597 // for ( auto k = j+1; k < nb; k++ )
598 // {
599 // std::vector< Point > X { positions[ i ], positions[ j ], positions[ k ] };
600 // const auto triangle_cells = dconv.StarCvxH( X, LS.axis() );
601 // if ( LS.includes( triangle_cells ) ) // tangent to shape
602 // updateReconstructionFromCells( X, triangle_cells.toPointRange() );
603 // }
604 // Time = trace.endBlock();
605}
606
607
609void computeTangentCone( int vertex_idx)
610{
611 if ( digital_points.empty() ) return;
612 // if ( vertex_idx < 0 || vertex_idx >= digital_points.size() ) return;
613 const auto p = digital_points[ vertex_idx ];
614 // trace.beginBlock( "Compute tangent cone" );
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 );
623 values.back() = 1.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 );
628 QuickHull3D hull;
629 hull.setInput( local_X, false );
630 hull.computeConvexHull();
631 std::vector< Point > positions;
632 std::vector< RealPoint > emb_positions;
633 hull.getVertexPositions( positions );
634 // Time = trace.endBlock();
635 embedVoxels( positions, emb_positions );
636 psCloudCvx = polyscope::registerPointCloud( "Tangent cone vertices", emb_positions );
637 psCloudCvx->setPointRadius( gridstep / 200.0 );
638
639 updateReconstructionFromTangentConeTriangles( vertex_idx );
640 displayReconstruction();
641}
642
644void updateReconstructionFromLocalTangentDelaunayComplex( int vertex_idx)
645{
646 if ( digital_points.empty() ) return;
647 // if ( vertex_idx < 0 || vertex_idx >= digital_points.size() ) 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 )
656 local_LS = DGtal::LatticeSetByIntervals< Space >( local_X.cbegin(), local_X.cend(), 0 ).starOfPoints();
657
662 bool ok = CvxHelper::computeDelaunayCellComplex( dcomplex, local_X, false );
663 if ( ! ok )
664 trace.error() << "Input set of points is not full dimensional." << std::endl;
665
666 dcomplex.requireFaceGeometry();
667 // Filter cells
668 std::vector< bool > is_cell_tangent( dcomplex.nbCells(), false );
669 if ( remove_empty_cells )
670 for ( Index c = 0; c < dcomplex.nbCells(); ++c )
671 {
672 auto Y = dcomplex.cellVertexPositions( c );
673 auto P = dconv.makePolytope( Y );
674 if ( P.countUpTo( Y.size()+1 ) >= Y.size()+1 ) continue;
675 is_cell_tangent[ c ] =
676 local_tangency
677 ? dconv.isFullySubconvex( P, local_LS )
678 : dconv.isFullySubconvex( P, LS );
679 }
680 else
681 for ( Index c = 0; c < dcomplex.nbCells(); ++c )
682 {
683 auto Y = dcomplex.cellVertexPositions( c );
684 is_cell_tangent[ c ] =
685 local_tangency
686 ? dconv.isFullySubconvex( Y, local_LS )
687 : dconv.isFullySubconvex( Y, LS );
688 }
689 // Get faces
690 std::vector< std::vector<SH3::SurfaceMesh::Vertex> > del_faces;
691 std::vector< RealPoint > del_positions;
692 std::set<Index> boundary_or_ext_points;
693 for ( Index f = 0; f < dcomplex.nbFaces(); ++f )
694 {
695 auto f0 = std::make_pair( f, false );
696 auto c0 = dcomplex.faceCell( f0 );
697 auto f1 = dcomplex.opposite( f0 );
698 auto c1 = dcomplex.faceCell( f1 );
699 if ( dcomplex.isInfinite( c0 ) )
700 {
701 std::swap( f0, f1 );
702 std::swap( c0, c1 );
703 }
704 if ( ! is_cell_tangent[ c0 ] )
705 {
706 auto V = dcomplex.cellVertices( c0 );
707 boundary_or_ext_points.insert( V.cbegin(), V.cend() );
708 }
709 if ( ! dcomplex.isInfinite( c1 ) && ! is_cell_tangent[ c1 ] )
710 {
711 auto V = dcomplex.cellVertices( c1 );
712 boundary_or_ext_points.insert( V.cbegin(), V.cend() );
713 }
714 bool bdry =
715 ( is_cell_tangent[ c0 ] && ( dcomplex.isInfinite( c1 )
716 || ( ! is_cell_tangent[ c1 ] ) ) )
717 ||
718 ( ! is_cell_tangent[ c0 ] && ( ! dcomplex.isInfinite( c1 )
719 && ( is_cell_tangent[ c1 ] ) ) );
720 if ( ! bdry ) continue;
721 std::vector< Point > X = dcomplex.faceVertexPositions( f0 );
722 const auto triangle_cells = dconv.StarCvxH( X, LS.axis() );
723 //if ( LS.includes( triangle_cells ) ) // tangent to shape
724 updateReconstructionFromCells( X, triangle_cells.toPointRange() );
725 }
726 useless_points.insert( p );
727 for ( Index v = 0; v < dcomplex.nbVertices(); v++ )
728 {
729 auto q = dcomplex.position( v );
730 if ( ! boundary_or_ext_points.count( v ) )
731 useless_points.insert( q );
732 }
733}
734
735
737void updateOuterReconstructionFromLocalTangentDelaunayComplex( int vertex_idx)
738{
739 if ( outer_digital_points.empty() ) return;
740 // if ( vertex_idx < 0 || vertex_idx >= digital_points.size() ) 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 ) );
747
752 bool ok = CvxHelper::computeDelaunayCellComplex( dcomplex, local_X, false );
753 if ( ! ok )
754 trace.error() << "Input set of points is not full dimensional." << std::endl;
755
756 dcomplex.requireFaceGeometry();
757 // Filter cells
758 std::vector< bool > is_cell_tangent( dcomplex.nbCells(), false );
759 if ( remove_empty_cells )
760 for ( Index c = 0; c < dcomplex.nbCells(); ++c )
761 {
762 auto Y = dcomplex.cellVertexPositions( c );
763 auto P = dconv.makePolytope( Y );
764 if ( P.countUpTo( Y.size()+1 ) >= Y.size()+1 ) continue;
765 is_cell_tangent[ c ] = dconv.isFullySubconvex( P, outer_LS );
766 }
767 else
768 for ( Index c = 0; c < dcomplex.nbCells(); ++c )
769 {
770 auto Y = dcomplex.cellVertexPositions( c );
771 is_cell_tangent[ c ] = dconv.isFullySubconvex( Y, outer_LS );
772 }
773 // Get faces
774 std::vector< std::vector<SH3::SurfaceMesh::Vertex> > del_faces;
775 for ( Index f = 0; f < dcomplex.nbFaces(); ++f )
776 {
777 auto f0 = std::make_pair( f, false );
778 auto c0 = dcomplex.faceCell( f0 );
779 auto f1 = dcomplex.opposite( f0 );
780 auto c1 = dcomplex.faceCell( f1 );
781 if ( dcomplex.isInfinite( c0 ) )
782 {
783 std::swap( f0, f1 );
784 std::swap( c0, c1 );
785 }
786 bool bdry =
787 ( is_cell_tangent[ c0 ] && ( dcomplex.isInfinite( c1 )
788 || ( ! is_cell_tangent[ c1 ] ) ) )
789 ||
790 ( ! is_cell_tangent[ c0 ] && ( ! dcomplex.isInfinite( c1 )
791 && ( is_cell_tangent[ c1 ] ) ) );
792 if ( ! bdry ) continue;
793 std::vector< Point > X = dcomplex.faceVertexPositions( f0 );
794 const auto triangle_cells = dconv.StarCvxH( X, outer_LS.axis() );
795 //if ( LS.includes( triangle_cells ) ) // tangent to shape
796 updateOuterReconstructionFromCells( X, triangle_cells.toPointRange() );
797 }
798}
799
801void computeLocalTangentDelaunayComplex( int vertex_idx)
802{
803 if ( digital_points.empty() ) return;
804 // if ( vertex_idx < 0 || vertex_idx >= digital_points.size() ) return;
805 const auto p = digital_points[ vertex_idx ];
806 trace.beginBlock( "Compute tangent cone" );
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 )
815 local_LS = DGtal::LatticeSetByIntervals< Space >( local_X.cbegin(), local_X.cend(), 0 ).starOfPoints();
816
821 bool ok = CvxHelper::computeDelaunayCellComplex( dcomplex, local_X, false );
822 if ( ! ok )
823 trace.error() << "Input set of points is not full dimensional." << std::endl;
824 dcomplex.requireFaceGeometry();
825
826 // Filter cells
827 std::vector< bool > is_cell_tangent( dcomplex.nbCells(), false );
828 if ( remove_empty_cells )
829 for ( Index c = 0; c < dcomplex.nbCells(); ++c )
830 {
831 auto Y = dcomplex.cellVertexPositions( c );
832 auto P = dconv.makePolytope( Y );
833 if ( P.countUpTo( Y.size()+1 ) >= Y.size()+1 ) continue;
834 is_cell_tangent[ c ] =
835 local_tangency
836 ? dconv.isFullySubconvex( P, local_LS )
837 : dconv.isFullySubconvex( P, LS );
838 }
839 else
840 for ( Index c = 0; c < dcomplex.nbCells(); ++c )
841 {
842 auto Y = dcomplex.cellVertexPositions( c );
843 is_cell_tangent[ c ] =
844 local_tangency
845 ? dconv.isFullySubconvex( Y, local_LS )
846 : dconv.isFullySubconvex( Y, LS );
847 }
848 // Get faces
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;
853 for ( Index f = 0; f < dcomplex.nbFaces(); ++f )
854 {
855 auto f0 = std::make_pair( f, false );
856 auto c0 = dcomplex.faceCell( f0 );
857 auto f1 = dcomplex.opposite( f0 );
858 auto c1 = dcomplex.faceCell( f1 );
859 if ( dcomplex.isInfinite( c0 ) )
860 {
861 std::swap( f0, f1 );
862 std::swap( c0, c1 );
863 }
864 if ( ! is_cell_tangent[ c0 ] )
865 {
866 auto V = dcomplex.cellVertices( c0 );
867 boundary_or_ext_points.insert( V.cbegin(), V.cend() );
868 }
869 if ( ! dcomplex.isInfinite( c1 ) && ! is_cell_tangent[ c1 ] )
870 {
871 auto V = dcomplex.cellVertices( c1 );
872 boundary_or_ext_points.insert( V.cbegin(), V.cend() );
873 }
874 bool bdry =
875 ( is_cell_tangent[ c0 ] && ( dcomplex.isInfinite( c1 )
876 || ( ! is_cell_tangent[ c1 ] ) ) )
877 ||
878 ( ! is_cell_tangent[ c0 ] && ( ! dcomplex.isInfinite( c1 )
879 && ( is_cell_tangent[ c1 ] ) ) );
880 if ( bdry ) del_faces.push_back( dcomplex.faceVertices( f0 ) );
881 }
882 for ( Index v = 0; v < dcomplex.nbVertices(); v++ )
883 {
884 auto p = dcomplex.position( v );
885 del_positions.push_back( voxelPoint2RealPoint( p ) );
886 if ( ! boundary_or_ext_points.count( v ) )
887 del_inner_points.push_back( voxelPoint2RealPoint( p ) );
888 }
889 Time = trace.endBlock();
890
891 psCloudInnerDelaunay = polyscope::registerPointCloud( "Inner Delaunay points",
892 del_inner_points );
893 psCloudInnerDelaunay->setPointRadius( gridstep / 200.0 );
894
895 psDelaunay = polyscope::registerSurfaceMesh("Delaunay surface",
896 del_positions, del_faces);
897 updateReconstructionFromLocalTangentDelaunayComplex( vertex_idx );
898 displayReconstruction();
899}
900
902void computeGlobalTangentDelaunayComplex()
903{
904 if ( digital_points.empty() ) return;
905 // if ( vertex_idx < 0 || vertex_idx >= digital_points.size() ) return;
906 const auto p = digital_points[ vertex_idx ];
907 trace.beginBlock( "Compute global tangent Delaunay complex" );
908
913 bool ok = CvxHelper::computeDelaunayCellComplex( dcomplex, digital_points, false );
914 if ( ! ok )
915 trace.error() << "Input set of points is not full dimensional." << std::endl;
916
917 // Reorder vertices of faces
918 dcomplex.requireFaceGeometry();
919
920 // Filter cells
921 std::vector< bool > is_cell_tangent( dcomplex.nbCells(), false );
922 for ( Index c = 0; c < dcomplex.nbCells(); ++c )
923 {
924 auto Y = dcomplex.cellVertexPositions( c );
925 auto P = dconv.makePolytope( Y );
926 if ( P.countUpTo( Y.size()+1 ) >= Y.size()+1 ) continue;
927 is_cell_tangent[ c ] = dconv.isFullySubconvex( P, LS );
928 }
929
930 // Get faces
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;
936 for ( Index f = 0; f < dcomplex.nbFaces(); ++f )
937 {
938 auto f0 = std::make_pair( f, false );
939 auto c0 = dcomplex.faceCell( f0 );
940 auto f1 = dcomplex.opposite( f0 );
941 auto c1 = dcomplex.faceCell( f1 );
942 if ( dcomplex.isInfinite( c0 ) )
943 {
944 std::swap( c0, c1 ); std::swap( f0, f1 );
945 }
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 ] );
951
952 if ( bdry_f0 )
953 {
954 const auto V = dcomplex.faceVertices( f0 );
955 del_faces.push_back( V );
956 useful_points.insert( V.cbegin(), V.cend() );
957 all_bdry_faces.push_back( f0 );
958 }
959 else if ( bdry_f1 )
960 {
961 const auto V = dcomplex.faceVertices( f1 );
962 del_faces.push_back( V );
963 useful_points.insert( V.cbegin(), V.cend() );
964 all_bdry_faces.push_back( f1 );
965 }
966 else if ( ( ! ( is_cell_tangent[ c0 ] || inf_c1 || is_cell_tangent[ c0 ] )
967 || ( ! is_cell_tangent[ c0 ] && inf_c1 ) )
968 && dconv.isFullySubconvex( dcomplex.faceVertexPositions( f0 ), LS ) )
969 {
970 const auto V = dcomplex.faceVertices( f0 );
971 del_faces.push_back( V );
972 useful_points.insert( V.cbegin(), V.cend() );
973 //del_faces.push_back( dcomplex.faceVertices( f1 ) );
974 all_bdry_faces.push_back( f0 );
975 }
976 }
977 for ( Index v = 0; v < dcomplex.nbVertices(); v++ )
978 {
979 auto p = dcomplex.position( v );
980 del_positions.push_back( voxelPoint2RealPoint( p ) );
981 if ( ! useful_points.count( v ) )
982 {
983 del_inner_points.push_back( voxelPoint2RealPoint( p ) );
984 useless_points.insert( p );
985 }
986 }
987 Time = trace.endBlock();
988
989 trace.beginBlock( "Update reconstruction" );
990 const auto axis = LS.axis();
991 for ( auto f : all_bdry_faces )
992 {
993 std::vector< Point > X = dcomplex.faceVertexPositions( f );
994 const auto cells = dconv.StarCvxH( X, axis );
995 // std::cout << "(" << f.first << "," << f.second << ") "
996 // << " #X=" << X.size() << " #cells=" << cells.size() << std::endl;
997 updateReconstructionFromCells( X, cells.toPointRange() );
998 }
999 trace.endBlock();
1000
1001 psCloudInnerDelaunay = polyscope::registerPointCloud( "Inner Delaunay points",
1002 del_inner_points );
1003 psCloudInnerDelaunay->setPointRadius( gridstep / 200.0 );
1004
1005 psDelaunay = polyscope::registerSurfaceMesh("Delaunay surface",
1006 del_positions, del_faces);
1007 displayReconstruction();
1008}
1009
1010void myCallback()
1011{
1012 // Select a vertex with the mouse
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;
1018
1019 // Only authorize selection on the input surface and the reconstruction
1020 auto surf = polyscope::getSurfaceMesh("Input surface");
1021 goodSelection = goodSelection || (selectedSurface == surf);
1022 const auto nv = selectedSurface->nVertices();
1023 // Validate that it its a face index
1024 if ( goodSelection )
1025 {
1026 if ( idx < nv )
1027 {
1028 std::ostringstream otext;
1029 otext << "Selected vertex = " << idx;
1030 ImGui::Text( "%s", otext.str().c_str() );
1031 vertex_idx = idx;
1032 }
1033 else vertex_idx = -1;
1034 }
1035 }
1036 if (ImGui::Button("Compute global tangent Delaunay complex"))
1037 {
1038 computeGlobalTangentDelaunayComplex();
1039 }
1040 if (ImGui::Button("Compute tangent cone"))
1041 {
1042 computeTangentCone( pickPoint() );
1043 current--;
1044 }
1045 if (ImGui::Button("Compute local Delaunay complex"))
1046 {
1047 computeLocalTangentDelaunayComplex( pickPoint() );
1048 current--;
1049 }
1050 ImGui::Checkbox( "Remove empty cells", &remove_empty_cells );
1051 ImGui::Checkbox( "Check local tangency", &local_tangency );
1052 if (ImGui::Button("Compute planes"))
1053 computePlanes();
1054 if (ImGui::Button("Compute reconstructions from triangles"))
1055 { // todo
1056 trace.beginBlock( "Compute reconstruction" );
1057 for ( int i = 0; i < nb_cones; ++i )
1058 {
1059 trace.progressBar( (double) i, (double) nb_cones );
1060 updateReconstructionFromTangentConeTriangles( pickPoint() );
1061 }
1062 displayReconstruction();
1063 Time = trace.endBlock();
1064 }
1065 if (ImGui::Button("Compute reconstruction from local Delaunay cplx"))
1066 { // todo
1067 trace.beginBlock( "Compute reconstruction" );
1068 for ( int i = 0; i < nb_cones; ++i )
1069 {
1070 trace.progressBar( (double) i, (double) nb_cones );
1071 auto j = pickPoint();
1072 if ( ! useless_points.count( digital_points[ j ] ) )
1073 updateReconstructionFromLocalTangentDelaunayComplex( j );
1074 if ( current == 0 ) break;
1075 }
1076 displayReconstruction();
1077 Time = trace.endBlock();
1078 }
1079 if (ImGui::Button("Compute outer reconstruction from local Delaunay cplx"))
1080 { // todo
1081 trace.beginBlock( "Compute outer reconstruction" );
1082 for ( int i = 0; i < nb_cones; ++i )
1083 {
1084 trace.progressBar( (double) i, (double) nb_cones );
1085 updateOuterReconstructionFromLocalTangentDelaunayComplex( pickOuterPoint() );
1086 }
1087 displayOuterReconstruction();
1088 Time = trace.endBlock();
1089 }
1090 if (ImGui::Button("Compute reconstructions from lines"))
1091 { // todo
1092 trace.beginBlock( "Compute reconstruction" );
1093 for ( int i = 0; i < nb_cones; ++i )
1094 {
1095 trace.progressBar( (double) i, (double) nb_cones );
1096 updateReconstructionFromTangentConeLines( pickPoint() );
1097 }
1098 displayReconstruction();
1099 Time = trace.endBlock();
1100 }
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();
1109}
1110
1111
1112int main( int argc, char* argv[] )
1113{
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;
1122
1123 CountedPtr<SH3::BinaryImage> binary_image ( nullptr );
1124 if ( input_polynomial )
1125 {
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 );
1132 auto implicit_shape = SH3::makeImplicitShape3D ( params );
1133 auto digitized_shape = SH3::makeDigitizedImplicitShape3D( implicit_shape, params );
1134 K = SH3::getKSpace( params );
1135 binary_image = SH3::makeBinaryImage(digitized_shape,
1137 params );
1138 }
1139 else
1140 {
1141 //params( "thresholdMin", vm[ "min" ].as<int>() );
1142 // params( "thresholdMax", vm[ "max" ].as<int>() );
1143 binary_image = SH3::makeBinaryImage( filename, params );
1144 K = SH3::getKSpace( binary_image );
1145 }
1146
1147 // auto binary_image = SH3::makeBinaryImage(filename, params );
1148 // K = SH3::getKSpace( binary_image, params );
1149 auto surface = SH3::makeDigitalSurface( binary_image, K, params );
1150 surfels = SH3::getSurfelRange( surface, params );
1151 // compute map surfel -> idx
1152 for ( Size i = 0; i < surfels.size(); i++ )
1153 surfel2idx[ K.sKCoords( surfels[ i ] ) ] = i;
1154 // compute inner points
1155 std::set< Point > I;
1156 for ( auto s : surfels ) I.insert( K.interiorVoxel( s ) );
1157 digital_points = std::vector<Point>( I.cbegin(), I.cend() );
1158 // compute outer points
1159 std::set< Point > O;
1160 for ( auto s : surfels ) O.insert( K.exteriorVoxel( s ) );
1161 outer_digital_points = std::vector<Point>( O.cbegin(), O.cend() );
1162 // initializa intercepts
1163 intercepts = std::vector< double >( surfels.size(), 0.0 );
1164 outer_intercepts = std::vector< double >( surfels.size(), 0.0 );
1165 auto primalSurface = SH3::makePrimalSurfaceMesh(surface);
1167 auto dualSurface = SH3::makeDualPolygonalSurface( s2i, surface );
1168 //Need to convert the faces
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 ));
1173
1174 //Recasting to vector of vertices
1175 positions = primalSurface->positions();
1176
1177 surfmesh = SurfMesh(positions.begin(),
1178 positions.end(),
1179 faces.begin(),
1180 faces.end());
1181 for(auto face= 0 ; face < dualSurface->nbFaces(); ++face)
1182 dual_faces.push_back( dualSurface->verticesAroundFace( face ));
1183
1184 //Recasting to vector of vertices
1185 for ( auto vtx = 0; vtx < dualSurface->nbVertices(); ++vtx )
1186 dual_positions.push_back( dualSurface->position( vtx ) );
1187
1188 dual_surfmesh = SurfMesh(dual_positions.begin(),
1189 dual_positions.end(),
1190 dual_faces.begin(),
1191 dual_faces.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;
1199 // Make digital surface
1200 // digitizePointels( positions, digital_points );
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() );
1206 outer_TC = DGtal::TangencyComputer< KSpace >( K );
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;
1216
1217 // Initialize polyscope
1218 polyscope::init();
1219
1220 psMesh = polyscope::registerSurfaceMesh("Input surface", positions, faces);
1221 displayReconstruction();
1222 displayOuterReconstruction();
1223 // psDualMesh = polyscope::registerSurfaceMesh("Input dual surface", dual_positions, dual_faces);
1224
1225
1226 // Set the callback function
1227 polyscope::state::userCallback = myCallback;
1228 polyscope::show();
1229 return EXIT_SUCCESS;
1230}
Aim: Smart pointer based on reference counts.
Definition: CountedPtr.h:80
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...
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.
Definition: PointVector.h:1595
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...
Definition: Shortcuts.h:105
static KSpace getKSpace(const Point &low, const Point &up, Parameters params=parametersKSpace())
Definition: Shortcuts.h:332
static CountedPtr< DigitizedImplicitShape3D > makeDigitizedImplicitShape3D(CountedPtr< ImplicitShape3D > shape, Parameters params=parametersDigitizedImplicitShape3D())
Definition: Shortcuts.h:523
std::map< Surfel, IdxSurfel > Surfel2Index
Definition: Shortcuts.h:188
static SurfelRange getSurfelRange(CountedPtr< ::DGtal::DigitalSurface< TDigitalSurfaceContainer > > surface, const Parameters &params=parametersDigitalSurface())
Definition: Shortcuts.h:1547
static CountedPtr< DigitalSurface > makeDigitalSurface(CountedPtr< TPointPredicate > bimage, const KSpace &K, const Parameters &params=parametersDigitalSurface())
Definition: Shortcuts.h:1209
static CountedPtr< PolygonalSurface > makeDualPolygonalSurface(Surfel2Index &s2i, CountedPtr< ::DGtal::DigitalSurface< TContainer > > aSurface)
Definition: Shortcuts.h:2268
static Parameters defaultParameters()
Definition: Shortcuts.h:203
static CountedPtr< SurfaceMesh > makePrimalSurfaceMesh(Cell2Index &c2i, CountedPtr< ::DGtal::DigitalSurface< TContainer > > aSurface)
Definition: Shortcuts.h:2372
static CountedPtr< BinaryImage > makeBinaryImage(Domain shapeDomain)
Definition: Shortcuts.h:561
static CountedPtr< ImplicitShape3D > makeImplicitShape3D(const Parameters &params=parametersImplicitShape3D())
Definition: Shortcuts.h:282
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="")
std::ostream & warning()
std::ostream & error()
std::ostream & info()
void progressBar(const double currentValue, const double maximalValue)
double endBlock()
SMesh::Index Index
Space::RealPoint RealPoint
Definition: StdDefs.h:170
Space::Point Point
Definition: StdDefs.h:168
KSpace::Cell Cell
Definition: StdDefs.h:148
Space::Vector Vector
Definition: StdDefs.h:169
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
Definition: Common.h:137
Trace trace
Definition: Common.h:154
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...
Definition: QuickHull.h:140
bool setInput(const std::vector< InputPoint > &input_points, bool remove_duplicates=true)
Definition: QuickHull.h:382
std::vector< Index > IndexRange
Definition: QuickHull.h:149
bool getFacetVertices(std::vector< IndexRange > &facet_vertices) const
Definition: QuickHull.h:666
bool getVertexPositions(std::vector< OutputPoint > &vertex_positions)
Definition: QuickHull.h:612
bool computeConvexHull(Status target=Status::VerticesCompleted)
Definition: QuickHull.h:460
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 ...
Definition: SurfaceMesh.h:92
int main()
Definition: testBits.cpp:56
KSpace K
HalfEdgeDataStructure::Size Size
TriMesh::VertexRange VertexRange
TriMesh::Face Face
TriMesh::Vertex Vertex