DGtal  1.5.beta
tangency-explorer.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/tools/QuickHull.h"
34 #include "DGtal/geometry/surfaces/estimation/PlaneProbingTetrahedronEstimator.h"
35 #include "SymmetricConvexExpander.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 #include "ConfigExamples.h"
43 
44 #include <Eigen/Dense>
45 #include <Eigen/Sparse>
46 
47 using namespace DGtal;
48 using namespace Z3i;
49 
50 // Using standard 3D digital space.
53 // The following typedefs are useful
55 typedef SurfMesh::Face Face;
56 typedef SurfMesh::Vertex Vertex;
59 
60 //Polyscope global
61 polyscope::SurfaceMesh *psMesh;
62 polyscope::SurfaceMesh *psDualMesh;
63 polyscope::SurfaceMesh *psTriangle;
64 polyscope::PointCloud* psCloud;
65 polyscope::PointCloud* psCloudCvx;
67 SurfMesh dual_surfmesh;
68 float gridstep = 1.0;
69 int vertex_idx = -1;
70 int face_idx = -1;
71 int edge_idx = -1;
72 float Time = 0.0;
73 bool is_selected = false;
74 Point selected_kpoint; // valid if selection == true
75 bool PSym = false;
76 bool enforceFC = true;
77 std::vector< Point > digital_points;
78 KSpace K;
83 typedef std::vector< Index > Indices;
84 typedef double Scalar;
85 typedef std::vector< Scalar > Scalars;
86 
87 struct UnorderedPointSetPredicate
88 {
89  typedef DGtal::Z3i::Point Point;
90  const std::unordered_set< Point >* myS;
91  explicit UnorderedPointSetPredicate( const std::unordered_set< Point >& S )
92  : myS( &S ) {}
93  bool operator()( const Point& p ) const
94  { return myS->count( p ) != 0; }
95 };
96 
97 std::unordered_set< Point > unorderedSet;
98 
99 // ----------------------------------------------------------------------
100 // utilities pointel
101 Point pointelRealPoint2Point( RealPoint p )
102 {
103  RealPoint sp = RealPoint( round( p[ 0 ] / gridstep + 0.5 ),
104  round( p[ 1 ] / gridstep + 0.5 ),
105  round( p[ 2 ] / gridstep + 0.5 ) );
106  return Point( sp[ 0 ], sp[ 1 ], sp[ 2 ] );
107 }
108 RealPoint pointelPoint2RealPoint( Point q )
109 {
110  return RealPoint( gridstep * ( q[ 0 ] - 0.5 ),
111  gridstep * ( q[ 1 ] - 0.5 ),
112  gridstep * ( q[ 2 ] - 0.5 ) );
113 }
114 void embedPointels( const std::vector< Point >& vq, std::vector< RealPoint >& vp )
115 {
116  vp.resize( vq.size() );
117  for ( auto i = 0; i < vp.size(); ++i )
118  vp[ i ] = pointelPoint2RealPoint( vq[ i ] );
119 }
120 void digitizePointels( const std::vector< RealPoint >& vp, std::vector< Point >& vq )
121 {
122  vq.resize( vp.size() );
123  for ( auto i = 0; i < vq.size(); ++i )
124  vq[ i ] = pointelRealPoint2Point( vp[ i ] );
125 }
126 
127 // ----------------------------------------------------------------------
128 // utilities voxel
129 Point voxelRealPoint2Point( RealPoint p )
130 {
131  RealPoint sp = RealPoint( round( p[ 0 ] / gridstep ),
132  round( p[ 1 ] / gridstep ),
133  round( p[ 2 ] / gridstep ) );
134  return Point( sp[ 0 ], sp[ 1 ], sp[ 2 ] );
135 }
136 RealPoint voxelPoint2RealPoint( Point q )
137 {
138  return RealPoint( gridstep * ( q[ 0 ] ),
139  gridstep * ( q[ 1 ] ),
140  gridstep * ( q[ 2 ] ) );
141 }
142 void embedVoxels( const std::vector< Point >& vq, std::vector< RealPoint >& vp )
143 {
144  vp.resize( vq.size() );
145  for ( auto i = 0; i < vp.size(); ++i )
146  vp[ i ] = voxelPoint2RealPoint( vq[ i ] );
147 }
148 void digitizeVoxels( const std::vector< RealPoint >& vp, std::vector< Point >& vq )
149 {
150  vq.resize( vp.size() );
151  for ( auto i = 0; i < vq.size(); ++i )
152  vq[ i ] = voxelRealPoint2Point( vp[ i ] );
153 }
154 
155 // @return the indices of all the points of X different from p that are cotangent to p.
156 Indices tangentCone( const Point& p )
157 {
158  return TC.getCotangentPoints( p );
159 }
160 
161 Scalars distances( const Point& p, const Indices& idx )
162 {
163  Scalars D( idx.size() );
164  for ( Index i = 0; i < idx.size(); i++ )
165  D[ i ] = ( TC.point( i ) - p ).norm();
166  return D;
167 }
168 
170 std::vector< Point >
171 findCorners( const std::unordered_set< Point >& S,
172  const std::vector< Vector >& In,
173  const std::vector< Vector >& Out )
174 {
175  std::vector< Point > C;
176  for ( auto&& p : S )
177  {
178  bool corner = true;
179  for ( auto&& n : In )
180  if ( ! S.count( p+n ) ) { corner = false; break; }
181  if ( ! corner ) continue;
182  for ( auto&& n : Out )
183  if ( S.count( p+n ) ) { corner = false; break; }
184  if ( corner ) C.push_back( p );
185  }
186  return C;
187 }
188 
189 void computeQuadrant( int q,
190  std::vector< Vector >& In,
191  std::vector< Vector >& Out )
192 {
193  In.clear();
194  Out.clear();
195  In.push_back( Vector( q & 0x1 ? 1 : -1, 0, 0 ) );
196  In.push_back( Vector( 0, q & 0x2 ? 1 : -1, 0 ) );
197  In.push_back( Vector( 0, 0, q & 0x4 ? 1 : -1 ) );
198  Out.push_back( Vector( q & 0x1 ? 1 : -1, q & 0x2 ? 1 : -1, q & 0x4 ? 1 : -1 ) );
199  Vector D = ( In[ 1 ] - In[ 0 ] ).crossProduct( In[ 2 ] - In[ 0 ] );
200  if ( D.dot( Out[ 0 ] ) < 0.0 ) std::swap( In[ 1 ], In[ 2 ] );
201  In.push_back( In[ 0 ]+In[ 1 ] );
202  In.push_back( In[ 0 ]+In[ 2 ] );
203  In.push_back( In[ 1 ]+In[ 2 ] );
204 }
205 
206 
207 void computePlanes()
208 {
209  // - mode specifies the candidate set, it is one of { ProbingMode::H, ProbingMode::R, ProbingMode::R1 }.
210  using Estimator
211  = DGtal::PlaneProbingTetrahedronEstimator< UnorderedPointSetPredicate,
212  ProbingMode::R >;
213  trace.beginBlock( "Compute planes" );
214  std::vector< RealPoint > positions;
215  std::vector< Point > vertices;
216  std::vector< std::vector<SH3::SurfaceMesh::Vertex> > faces;
217  std::vector< Vector > In;
218  std::vector< Vector > Out;
219  std::unordered_set< Point > S( digital_points.cbegin(), digital_points.cend() );
220  UnorderedPointSetPredicate predS( S );
221  Index i = 0;
222  for ( int q = 0; q < 8; q++ ) // for each quadrant
223  {
224  computeQuadrant( q, In, Out );
225  std::vector< Point > corners = findCorners( S, In, Out );
226  std::cout << "Found " << corners.size() << " in Q" << q << std::endl;
227  std::array<Point, 3> m = { In[ 0 ], In[ 1 ], In[ 2 ] };
228  for ( auto&& p : corners )
229  {
230  Estimator estimator( p, m, predS );
231  // if ( estimator.hexagonState()
232  // != Estimator::Neighborhood::HexagonState::Planar)
233  // continue;
234  std::vector<SH3::SurfaceMesh::Vertex> triangle { i, i+1, i+2 };
235  auto v = estimator.vertices();
236  faces.push_back( triangle );
237  vertices.push_back( v[ 0 ] );
238  vertices.push_back( v[ 1 ] );
239  vertices.push_back( v[ 2 ] );
240  while (estimator.advance().first) {
241  auto state = estimator.hexagonState();
242  if (state == Estimator::Neighborhood::HexagonState::Planar) {
243  auto v = estimator.vertices();
244  if ( S.count( v[ 0 ] ) && S.count( v[ 1 ] ) && S.count( v[ 2 ] ) )
245  {
246  std::vector< Point > X { v[ 0 ], v[ 1 ], v[ 2 ] };
247  auto P = dconv.makePolytope( X );
248  if ( dconv.isFullySubconvex( P, LS ) )
249  // // && TC.arePointsCotangent( v[ 0 ], v[ 1 ], v[ 2 ] ) )
250  {
251  vertices[ i ] = v[ 0 ];
252  vertices[ i+1 ] = v[ 1 ];
253  vertices[ i+2 ] = v[ 2 ];
254  }
255  }
256  }
257  }
258  i += 3;
259  // }
260  }
261  }
262  Time = trace.endBlock();
263  embedPointels( vertices, positions );
264  psTriangle = polyscope::registerSurfaceMesh("Triangle", positions, faces);
265 }
266 
268 void computeTangentCone()
269 {
270  if ( digital_points.empty() ) return;
271  if ( vertex_idx < 0 || vertex_idx >= digital_points.size() ) return;
272  const auto p = digital_points[ vertex_idx ];
273  trace.beginBlock( "Compute tangent cone" );
274  auto local_X_idx = TC.getCotangentPoints( p );
275  std::cout << "#cone=" << local_X_idx.size() << std::endl;
276  local_X_idx.push_back( vertex_idx );
277  std::vector< Point > local_X;
278  std::vector< RealPoint > emb_local_X;
279  for ( auto idx : local_X_idx )
280  local_X.push_back( TC.point( idx ) );
281  std::vector< double > values( local_X.size(), 0.0 );
282  values.back() = 1.0;
283  embedPointels( local_X, emb_local_X );
284  psCloud = polyscope::registerPointCloud( "Tangent cone", emb_local_X );
285  psCloud->setPointRadius( gridstep / 100.0 );
286  psCloud->addScalarQuantity( "Classification", values );
287  QuickHull3D hull;
288  hull.setInput( local_X, false );
289  hull.computeConvexHull();
290  std::vector< Point > positions;
291  std::vector< RealPoint > emb_positions;
292  hull.getVertexPositions( positions );
293  Time = trace.endBlock();
294  embedPointels( positions, emb_positions );
295  psCloudCvx = polyscope::registerPointCloud( "Tangent cone vertices", emb_positions );
296  psCloudCvx->setPointRadius( gridstep / 50.0 );
297 }
298 
300 void computeSymmetricConvexSet()
301 {
302  if ( digital_points.empty() ) return;
303  if ( ! is_selected ) return;
304  trace.beginBlock( "Compute symmetric convex set" );
305  Point lo = Point::diagonal(-10000);
306  Point up = Point::diagonal( 10000);
307  UnorderedPointSetPredicate predS( unorderedSet );
309  ( predS, selected_kpoint, lo, up );
310  while ( SCE.advance( enforceFC ) )
311  if ( PSym && ! SCE.myPerfectSymmetry
312  && SCE.current().second >= SCE.myPerfectSymmetryRadius )
313  break;
314  std::cout << "#symcvx=" << SCE.myPoints.size() << std::endl;
315  Time = trace.endBlock();
316  std::vector< Point > positions( SCE.myPoints.cbegin(), SCE.myPoints.cend() );
317  std::vector< RealPoint > emb_positions;
318  embedPointels( positions, emb_positions );
319  psCloud = polyscope::registerPointCloud( "Symmetric convex set", emb_positions );
320  psCloud->setPointRadius( gridstep / 100.0 );
321 }
322 
323 struct TriangleContext
324 {
325  Point p;
326  Indices cone_P; // the vector of indices of points in the tangent cone to p.
327  Scalars d_P; // the associated vector of distance to point p.
328  Scalar max_d; // the maximum of d_P
329  Scalar min_d; // the minimum distance between all pair of points in {P,A,B,C}
330  Scalar best; // the current best D=d_P(A)+d_P(B)+d_P(C)+d_A(B)+d_A(C)+d_B(C)
331  Scalar cur_qA;
332  Scalar cur_qAB;
333 };
334 
335 Scalar bestTriangleAB( TriangleContext& ctx,
336  const Index A, const Index B, Index& C )
337 {
338  if ( ( ctx.best - ctx.cur_qAB ) > 4.0 * ctx.max_d ) return 0.0;
339  Index cur_C;
340  Scalar q = 0.0;
341  const Point a = TC.point( ctx.cone_P[ A ] );
342  const Point b = TC.point( ctx.cone_P[ B ] );
343  for ( cur_C = B + 1; cur_C < ctx.cone_P.size(); cur_C++ )
344  {
345  const Scalar d_PC = ctx.d_P[ cur_C ];
346  if ( d_PC < ctx.min_d ) continue;
347  const Point c = TC.point( ctx.cone_P[ cur_C ] );
348  const Scalar d_AC = ( c - a ).norm();
349  if ( d_AC < ctx.min_d ) continue;
350  const Scalar d_BC = ( c - b ).norm();
351  if ( d_BC < ctx.min_d ) continue;
352  const Scalar cur_q = ctx.cur_qAB + d_PC + d_AC + d_BC
353  + sqrt( ( ( b - a ).crossProduct( c - a ) ).norm() );
354  if ( cur_q > q )
355  {
356  if ( ! TC.arePointsCotangent( a, c ) ) continue;
357  if ( ! TC.arePointsCotangent( b, c ) ) continue;
358  C = cur_C; q = cur_q;
359  }
360  }
361  return q;
362 }
363 
364 Scalar bestTriangleA( TriangleContext& ctx,
365  const Index A,
366  Index& B, Index& C )
367 {
368  Index cur_B, cur_C;
369  Scalar q = 0.0;
370  const Point a = TC.point( ctx.cone_P[ A ] );
371  for ( cur_B = A + 1; cur_B < ctx.cone_P.size(); cur_B++ )
372  {
373  const Scalar d_PB = ctx.d_P[ cur_B ];
374  if ( d_PB < ctx.min_d ) continue;
375  const Point b = TC.point( ctx.cone_P[ cur_B ] );
376  const Scalar d_AB = ( b - a ).norm();
377  if ( d_AB < ctx.min_d ) continue;
378  if ( ! TC.arePointsCotangent( a, b ) ) continue;
379  ctx.cur_qAB = ctx.cur_qA + d_PB + d_AB;
380  const Scalar result = bestTriangleAB( ctx, A, cur_B, cur_C );
381  if ( result > q )
382  {
383  B = cur_B; C = cur_C; q = result;
384  }
385  }
386  return q;
387 }
388 
389 Scalar bestTriangle( TriangleContext& ctx,
390  Index& A, Index& B, Index& C )
391 {
392  Index cur_A, cur_B, cur_C;
393  for ( cur_A = 0; cur_A < ctx.cone_P.size(); cur_A++ )
394  {
395  std::cout << " " << cur_A;
396  std::cout.flush();
397  const Scalar d_PA = ctx.d_P[ cur_A ];
398  if ( d_PA < ctx.min_d ) continue;
399  ctx.cur_qA = d_PA;
400  const Scalar result = bestTriangleA( ctx, cur_A, cur_B, cur_C );
401  if ( result > ctx.best )
402  {
403  A = cur_A; B = cur_B; C = cur_C;
404  ctx.best = result;
405  }
406  }
407  return ctx.best;
408 }
409 
410 void computeGreatTriangle()
411 {
412  if ( digital_points.empty() ) return;
413  if ( vertex_idx < 0 || vertex_idx >= digital_points.size() ) return;
414  trace.beginBlock( "Compute best triangle" );
415  TriangleContext ctx;
416  ctx.p = digital_points[ vertex_idx ];
417  ctx.cone_P = tangentCone( ctx.p );
418  std::cout << "#cone=" << ctx.cone_P.size() << std::endl;
419  ctx.cone_P.push_back( vertex_idx );
420  ctx.d_P = distances( ctx.p, ctx.cone_P );
421  ctx.max_d = *( std::max_element( ctx.d_P.cbegin(), ctx.d_P.cend() ) );
422  ctx.min_d = ctx.max_d / 3.0;
423  ctx.best = 0.0;
424  Index A, B, C;
425  Scalar d = bestTriangle( ctx, A, B, C );
426  Time = trace.endBlock();
427  std::cout << "Best triangle " << A << " " << B << " " << C
428  << " d=" << ctx.best << std::endl;
429  if ( d == 0 ) return;
430  std::vector< std::vector<SH3::SurfaceMesh::Vertex> > faces;
431  std::vector<SH3::SurfaceMesh::Vertex> triangle { 0, 1, 2 };
432  faces.push_back( triangle );
433  std::vector<RealPoint> positions;
434  std::vector< Point > vertices
435  { TC.point( ctx.cone_P[ A ] ),
436  TC.point( ctx.cone_P[ B ] ),
437  TC.point( ctx.cone_P[ C ] ) };
438  embedPointels( vertices, positions );
439  psTriangle = polyscope::registerSurfaceMesh("Triangle", positions, faces);
440 }
441 
442 void myCallback()
443 {
444  // Select a vertex with the mouse
445  if (polyscope::pick::haveSelection()) {
446  bool goodSelection = false;
447  auto selection = polyscope::pick::getSelection();
448  auto selectedSurface = static_cast<polyscope::SurfaceMesh*>(selection.first);
449  int idx = selection.second;
450 
451  // Only authorize selection on the input surface and the reconstruction
452  auto surf = polyscope::getSurfaceMesh("Input surface");
453  goodSelection = goodSelection || (selectedSurface == surf);
454  const auto nv = surfmesh.nbVertices();
455  const auto nf = surfmesh.nbFaces();
456  const auto ne = surfmesh.nbEdges();
457  // Validate that it its a face index
458  if ( goodSelection )
459  {
460  if ( idx < nv )
461  {
462  vertex_idx = idx;
463  is_selected = true;
464  selected_kpoint = digital_points[ vertex_idx ] * 2;
465  std::ostringstream otext;
466  otext << "Selected vertex = " << vertex_idx
467  << " pos=" << selected_kpoint;
468  ImGui::Text( "%s", otext.str().c_str() );
469  }
470  else if ( idx - nv < nf )
471  {
472  face_idx = idx - nv;
473  is_selected = true;
474  selected_kpoint = Point::zero;
475  for ( auto i : surfmesh.incidentVertices( face_idx ) )
476  selected_kpoint += digital_points[ i ];
477  selected_kpoint /= 2;
478  std::ostringstream otext;
479  otext << "Selected face = " << face_idx
480  << " pos=" << selected_kpoint;
481  ImGui::Text( "%s", otext.str().c_str() );
482  }
483  else
484  {
485  vertex_idx = -1;
486  face_idx = -1;
487  edge_idx = -1;
488  is_selected= false;
489  }
490  }
491  }
492  if (ImGui::Button("Compute tangent cone"))
493  computeTangentCone();
494  if (ImGui::Button("Compute symmetric convex set"))
495  computeSymmetricConvexSet();
496  ImGui::Checkbox("Perfect symmetry", &PSym );
497  ImGui::Checkbox("Full convexity", &enforceFC );
498  if (ImGui::Button("Compute great triangle"))
499  computeGreatTriangle();
500  if (ImGui::Button("Compute planes"))
501  computePlanes();
502  ImGui::Text( "Computation time = %f ms", Time );
503 }
504 
505 int main( int argc, char* argv[] )
506 {
507  auto params = SH3::defaultParameters() | SHG3::defaultParameters() | SHG3::parametersGeometryEstimation();
508  params("surfaceComponents", "All");
509  std::string filename = examplesPath + std::string("/samples/bunny-32.vol");
510  if ( argc > 1 ) filename = std::string( argv[ 1 ] );
511  auto binary_image = SH3::makeBinaryImage(filename, params );
512  K = SH3::getKSpace( binary_image, params );
513  auto surface = SH3::makeDigitalSurface( binary_image, K, params );
514  auto primalSurface = SH3::makePrimalSurfaceMesh(surface);
515  SH3::Surfel2Index s2i;
516  auto dualSurface = SH3::makeDualPolygonalSurface( s2i, surface );
517  //Need to convert the faces
518  std::vector<std::vector<SH3::SurfaceMesh::Vertex>> faces;
519  std::vector<RealPoint> positions;
520  for(auto face= 0 ; face < primalSurface->nbFaces(); ++face)
521  faces.push_back(primalSurface->incidentVertices( face ));
522 
523  //Recasting to vector of vertices
524  positions = primalSurface->positions();
525 
526  surfmesh = SurfMesh(positions.begin(),
527  positions.end(),
528  faces.begin(),
529  faces.end());
530  std::vector<std::vector<SH3::SurfaceMesh::Vertex>> dual_faces;
531  std::vector<RealPoint> dual_positions;
532  for(auto face= 0 ; face < dualSurface->nbFaces(); ++face)
533  dual_faces.push_back( dualSurface->verticesAroundFace( face ));
534 
535  //Recasting to vector of vertices
536  for ( auto vtx = 0; vtx < dualSurface->nbVertices(); ++vtx )
537  dual_positions.push_back( dualSurface->position( vtx ) );
538 
539  dual_surfmesh = SurfMesh(dual_positions.begin(),
540  dual_positions.end(),
541  dual_faces.begin(),
542  dual_faces.end());
543  std::cout << surfmesh << std::endl;
544  std::cout << "number of non-manifold Edges = "
545  << surfmesh.computeNonManifoldEdges().size() << std::endl;
546  std::cout << dual_surfmesh << std::endl;
547  std::cout << "number of non-manifold Edges = "
548  << dual_surfmesh.computeNonManifoldEdges().size() << std::endl;
549  // Make digital surface
550  digitizePointels( positions, digital_points );
551  trace.info() << "Surface has " << digital_points.size() << " pointels." << std::endl;
554  TC.init( digital_points.cbegin(), digital_points.cend() );
556  ( digital_points.cbegin(), digital_points.cend(), 0 ).starOfPoints();
557  trace.info() << "#cell_cover = " << TC.cellCover().nbCells() << std::endl;
558  trace.info() << "#lattice_cover = " << LS.size() << std::endl;
559 
560  // Make predicate for pointel-based digital surface
561  unorderedSet = std::unordered_set< Point >( digital_points.cbegin(),
562  digital_points.cend() );
563 
564  // Initialize polyscope
565  polyscope::init();
566 
567  psMesh = polyscope::registerSurfaceMesh("Input surface", positions, faces);
568  psDualMesh = polyscope::registerSurfaceMesh("Input dual surface", dual_positions, dual_faces);
569 
570  // Set the callback function
571  polyscope::state::userCallback = myCallback;
572  polyscope::show();
573  return EXIT_SUCCESS;
574 }
bool isFullySubconvex(const PointRange &Y, const LatticeSet &StarX) 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,...
Aim: A class that locally estimates a normal on a digital set using only a predicate "does a point x ...
auto dot(const PointVector< dim, OtherComponent, OtherStorage > &v) const -> decltype(DGtal::dotProduct(*this, v))
Dot product with a PointVector.
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...
Aim: This class is used to simplify shape and surface creation. With it, you can create new shapes an...
Definition: Shortcuts.h:105
std::map< Surfel, IdxSurfel > Surfel2Index
Definition: Shortcuts.h:188
Aim: SymmetricConvexExpander computes symmetric fully convex subsets of a given digital set.
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 & info()
double endBlock()
SurfaceMesh< RealPoint, RealVector > SurfMesh
void myCallback()
polyscope::SurfaceMesh * psMesh
SurfMesh surfmesh
CountedPtr< SH3::DigitalSurface > surface
CountedPtr< SH3::BinaryImage > binary_image
SMesh::Index Index
Space::RealPoint RealPoint
Definition: StdDefs.h:170
Space::Point Point
Definition: StdDefs.h:168
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.
Trace trace
Definition: Common.h:153
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: a geometric kernel to compute the convex hull of digital points with integer-only arithmetic.
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
bool getVertexPositions(std::vector< OutputPoint > &vertex_positions)
Definition: QuickHull.h:612
bool computeConvexHull(Status target=Status::VerticesCompleted)
Definition: QuickHull.h:460
Aim: Represents an embedded mesh as faces and a list of vertices. Vertices may be shared among faces ...
Definition: SurfaceMesh.h:92
const Vertices & incidentVertices(Face f) const
Definition: SurfaceMesh.h:315
Size nbFaces() const
Definition: SurfaceMesh.h:296
Size nbEdges() const
Definition: SurfaceMesh.h:292
Size nbVertices() const
Definition: SurfaceMesh.h:288
Edges computeNonManifoldEdges() const
int main(int argc, char **argv)
Shortcuts< KSpace > SH3
K init(Point(0, 0, 0), Point(512, 512, 512), true)
KSpace K
ShortcutsGeometry< Z3i::KSpace > SHG3
TriMesh::Face Face
TriMesh::Vertex Vertex