DGtal  0.6.devel
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
viewDualSurface.cpp
1 
28 
29 #include <iostream>
30 #include <algorithm>
31 #include <QtGui/qapplication.h>
32 #include "DGtal/base/Common.h"
33 #include "DGtal/io/viewers/Viewer3D.h"
34 #include "DGtal/helpers/StdDefs.h"
35 #include "DGtal/topology/helpers/Surfaces.h"
36 #include "ConfigExamples.h"
37 
38 
39 using namespace std;
40 using namespace DGtal;
41 using namespace Z3i;
42 
43 
44 
45 template <typename Vector>
46 Vector wedge( const Vector & v1, const Vector & v2 )
47 {
48  return Vector( v1[ 1 ] * v2[ 2 ] - v1[ 2 ] * v2[ 1 ],
49  v1[ 2 ] * v2[ 0 ] - v1[ 0 ] * v2[ 2 ],
50  v1[ 0 ] * v2[ 1 ] - v1[ 1 ] * v2[ 0 ] );
51 }
52 
53 template <typename Vector>
55 {
56  Vector N; // expected normal
57  Vector P; // origin or first point
58  const std::vector< Vector > & pts;
59  inline LessThanOnFace( const Vector & aN, const Vector & aP,
60  const std::vector< Vector > & aPts )
61  : N( aN ), P( aP ), pts( aPts )
62  {}
63  inline bool operator()( unsigned int i1, unsigned int i2 ) const
64  {
65  return N.dot( wedge( pts[ i1 ] - P, pts[ i2 ] - P ) ) > 0;
66  }
67 };
68 
69 // Very naive convex hull algorithm. O(n^4) complexity ! But very
70 // short. Takes care also of polygonal faces.
71 template <typename Vector>
72 void naiveConvexHull
73 ( std::vector< std::vector< unsigned int > > & indices,
74  const std::vector<Vector> & points, bool left_handed )
75 {
76  typedef typename Vector::Component Scalar;
77  // Checks all triplets of points.
78  unsigned int faces = 0;
79  std::vector< unsigned int > aFace;
80  for ( unsigned int i1 = 0; i1 < points.size(); ++i1 )
81  for ( unsigned int i2 = 0; i2 < points.size(); ++i2 )
82  if ( i1 != i2 )
83  for ( unsigned int i3 = i1 > i2 ? i1+1 : i2+1; i3 < points.size(); ++i3 )
84  {
85  Vector P12 = points[ i2 ] - points[ i1 ];
86  Vector P13 = points[ i3 ] - points[ i1 ];
87  Vector N = wedge( P12, P13 );
88  if ( N == Vector::zero ) continue;
89 
90  unsigned int nbBadPos = 0;
91  for ( unsigned int i4 = 0; i4 < points.size(); ++i4 )
92  {
93  Vector P14 = points[ i4 ] - points[ i1 ];
94  Scalar c = N.dot( P14 );
95  if ( c == 0 ) aFace.push_back( i4 );
96  else if ( ( left_handed && ( c > 0 ) )
97  || ( ! left_handed && ( c < 0 ) ) )
98  ++nbBadPos;
99  }
100  if ( nbBadPos == 0 )
101  {
102  LessThanOnFace<Vector> LTOF( N, points[ aFace[ 0 ] ], points );
103  std::sort( ++aFace.begin(), aFace.end(), LTOF );
104  indices.push_back( aFace );
105  }
106  aFace.clear();
107  }
108  // purge faces.
109  for ( unsigned int i = 0; i < indices.size(); ++i )
110  {
111  unsigned int s = indices[ i ].size();
112  for ( unsigned int j = i+1; j < indices.size(); )
113  {
114  if ( indices[ j ].size() == s )
115  {
116  bool equal = true;
117  for ( unsigned int k = 0; equal && ( k < s ); ++k )
118  if ( indices[ i ][ k ] != indices[ j ][ k ] )
119  equal = false;
120  if ( equal )
121  {
122  std::swap( indices[ j ], indices.back() );
123  indices.pop_back();
124  }
125  else
126  ++j;
127  }
128  else ++j;
129  }
130  }
131  // std::cerr << "----------- " << std::endl;
132  // for ( unsigned int i = 0; i < indices.size(); ++i )
133  // {
134  // std::cerr << "( ";
135  // for ( unsigned int j = 0; j < indices[ i ].size(); ++j )
136  // std::cerr << indices[ i ][ j ] << " ";
137  // std::cerr << ")" << std::endl;
138  // }
139 }
140 
141 double rescale( double x )
142 {
143  return ( x - 1.0 ) * 0.5 + 0.5;
144 }
145 
146 template <typename Viewer,
147  typename Vector>
148 void viewPolygons
149 ( Viewer & viewer,
150  const DGtal::Color & color,
151  const std::vector< std::vector< unsigned int > > & indices,
152  const std::vector<Vector> & points )
153 {
154  typedef typename Viewer::pointD3D pointD3D;
155  //DGtal::Color color( 200, 200, 220, 255 );
156  std::vector<pointD3D> pts3d;
157  for ( unsigned int f = 0; f < indices.size(); ++f )
158  {
159  pts3d.clear();
160  pointD3D P;
161  P.R = color.red();
162  P.G = color.green();
163  P.B = color.blue();
164  P.T = color.alpha();
165  P.isSigned = false;
166  P.signPos = false;
167  P.size = 0.1;
168  for ( unsigned int v = 0; v < indices[ f ].size(); ++v )
169  {
170  unsigned int i = indices[ f ][ v ];
171  P.x = rescale( points[ i ][ 0 ] );
172  P.y = rescale( points[ i ][ 1 ] );
173  P.z = rescale( points[ i ][ 2 ] );
174  pts3d.push_back( P );
175  }
176  viewer.addPolygon( pts3d, color );
177  }
178 }
179 
180 template <typename Vector>
181 unsigned int dim( const Vector & z )
182 {
183  unsigned int d = 0;
184  for ( unsigned int i = 0; i < Vector::dimension; ++i )
185  if ( ( z[ i ] % 2 ) == 1 ) ++d;
186  return d;
187 }
188 
189 template <typename Vector>
190 unsigned int openDim( const Vector & z )
191 {
192  for ( unsigned int i = 0; i < Vector::dimension; ++i )
193  if ( ( z[ i ] % 2 ) == 1 ) return i;
194  return Vector::dimension;
195 }
196 template <typename Vector>
197 Vector lower( const Vector & z, unsigned int k )
198 {
199  Vector z2( z );
200  --z2[ k ];
201  return z2;
202 }
203 template <typename Vector>
204 Vector upper( const Vector & z, unsigned int k )
205 {
206  Vector z2( z );
207  ++z2[ k ];
208  return z2;
209 }
210 
211 template <typename Vector>
212 unsigned int nbLighted( std::map< Vector, bool > & f,
213  const Vector & z )
214 { // z of dim >=2
215  unsigned int d = dim( z );
216  if ( d == 0 ) return f[ z ] ? 1 : 0;
217  unsigned int i = openDim( z );
218  return nbLighted( f, lower( z, i ) )
219  + nbLighted( f, upper( z, i ) );
220 }
221 
222 
223 // Most similar to convex hull... but not exactly, e.g. cfg 31.
224 template <typename Vector>
225 bool lightBetween( std::map< Vector, bool > & f,
226  const Vector & z )
227 {
228  unsigned int d = dim( z );
229  if ( d == 0 ) return f[ z ];
230  else if ( d == 1 )
231  {
232  unsigned int i = openDim( z );
233  return f[ lower( z, i ) ] || f[ upper( z, i ) ];
234  }
235  else
236  {
237  Vector v1, v2;
238  for ( unsigned int i = 0; i < Vector::dimension; ++i )
239  {
240  v1[ i ] = ( ( z[ i ] % 2 ) == 1 ) ? z[ i ] - 1 : z[ i ];
241  v2[ i ] = ( ( z[ i ] % 2 ) == 1 ) ? z[ i ] + 1 : z[ i ];
242  }
243  Domain domain( v1, v2 );
244  for ( Domain::ConstIterator it = domain.begin(), itE = domain.end();
245  it != itE; ++it )
246  {
247  if ( *it == z ) break;
248  Point zp = z*2 - *it;
249  // std::cerr << *it << " <--> " << zp << std::endl;
250  if ( lightBetween( f, *it ) && lightBetween( f, zp ) )
251  return true;
252  }
253  return false;
254  }
255 
256 }
257 
258 
259 template <typename Vector>
260 bool lightMax( std::map< Vector, bool > & f,
261  const Vector & z )
262 {
263  unsigned int d = dim( z );
264  if ( d == 0 ) return f[ z ];
265  else if ( d == 1 )
266  {
267  unsigned int i = openDim( z );
268  return f[ lower( z, i ) ] || f[ upper( z, i ) ];
269  }
270  else // if ( d > 1 )
271  {
272  unsigned int n = nbLighted( f, z );
273  return n >= 2;
274  }
275 }
276 template <typename Vector>
277 bool lightMinMax( std::map< Vector, bool > & f,
278  const Vector & z )
279 {
280  unsigned int d = dim( z );
281  if ( d == 0 ) return f[ z ];
282  else
283  {
284  Vector tmp( z );
285  bool val = true;
286  for ( unsigned i = 0; i < d; ++i )
287  {
288  unsigned int k = openDim( tmp );
289  tmp = lower( tmp, k );
290  val = val && ( lightMinMax( f, lower( z, k ) ) || lightMinMax( f, upper( z, k ) ) );
291  }
292  return val;
293  }
294 }
295 template <typename Vector>
296 bool lightMaxMin( std::map< Vector, bool > & f,
297  const Vector & z )
298 {
299  unsigned int d = dim( z );
300  if ( d == 0 ) return f[ z ];
301  else
302  {
303  Vector tmp( z );
304  bool val = false;
305  for ( unsigned i = 0; i < d; ++i )
306  {
307  unsigned int k = openDim( tmp );
308  tmp = lower( tmp, k );
309  val = val || ( lightMaxMin( f, lower( z, k ) ) && lightMaxMin( f, upper( z, k ) ) );
310  }
311  return val;
312  }
313 }
314 
315 template <typename Vector>
316 bool lightEpsilon( std::map< Vector, bool > & f,
317  const Vector & z,
318  unsigned int epsilon )
319 {
320  unsigned int d = dim( z );
321  if ( d == 0 ) return f[ z ];
322  else
323  {
324  Vector tmp( z );
325  bool eps_d = ( ( epsilon >> (d-1)) & 1 ) != 0;
326  bool val = eps_d ? true : false;
327  for ( unsigned i = 0; i < d; ++i )
328  {
329  unsigned int k = openDim( tmp );
330  tmp = lower( tmp, k );
331  if ( eps_d )
332  val = val && ( lightEpsilon( f, lower( z, k ), epsilon )
333  || lightEpsilon( f, upper( z, k ), epsilon ) );
334  else
335  val = val || ( lightEpsilon( f, lower( z, k ), epsilon )
336  && lightEpsilon( f, upper( z, k ), epsilon ) );
337  }
338  return val;
339  }
340 }
341 
342 
343 template <typename Vector>
344 void fillCfg( std::map< Vector, bool > & f,
345  const Vector & z,
346  unsigned int cfg )
347 {
348  unsigned int d = dim( z );
349  if ( d == 0 )
350  {
351  f[ z ] = (cfg == 1);
352  //std::cerr << "f[" << z << "] = " << f[ z ] << std::endl;
353  }
354  else
355  {
356  unsigned n = 1 << ( d - 1 );
357  unsigned int cfgLow = 0;
358  unsigned int cfgUp = 0;
359  for ( unsigned int j = 0; j < n; ++j )
360  {
361  cfgLow += ( cfg & 1 ) << j;
362  cfg >>= 1;
363  cfgUp += ( cfg & 1 ) << j;
364  cfg >>= 1;
365  }
366  unsigned int i = openDim( z );
367  fillCfg( f, lower( z, i ), cfgLow );
368  fillCfg( f, upper( z, i ), cfgUp );
369  }
370 }
371 
372 template <typename Vector>
373 void localDualVolume( std::vector<Vector> & points,
374  std::map< Vector, bool > & f,
375  const Vector & z )
376 {
377  points.clear();
378  Z3i::Domain domain( z, z + Vector::diagonal(1) );
379  for ( Z3i::Domain::ConstIterator it = domain.begin(), itE = domain.end();
380  it != itE; ++it )
381  {
382  if ( f[ *it ] ) points.push_back( *it );
383  }
384 }
385 
386 template <typename Vector>
388 {
389  std::map< Vector, bool > & fct;
391  ConfigPointPredicate( std::map< Vector, bool > & aFct, Vector aBase )
392  : fct( aFct ), base( aBase ) {}
393  bool operator()( const Vector & p ) const
394  {
395  return fct[ p * 2 + base];
396  }
397 };
398 
399 int main( int argc, char** argv )
400 {
401  typedef KSpace::CellSet CellSet;
402  QApplication application(argc,argv);
404  Viewer3D viewer;
405  viewer.show();
406  DGtal::Color fillColor( 200, 200, 220, 255 );
407  DGtal::Color surfelColor( 255, 0, 0, 150 );
408  DGtal::Color voxelColor( 150, 150, 0, 150 );
409 
410  std::vector<Vector> pts;
411  // pts.push_back( Vector( 0, 0, 0 ) );
412  // pts.push_back( Vector( 1, 0, 0 ) );
413  // pts.push_back( Vector( 0, 1, 0 ) );
414  // pts.push_back( Vector( 0, 0, 1 ) );
415  // pts.push_back( Vector( 0, 1, 1 ) );
416  // pts.push_back( Vector( 1, 0, 1 ) );
417  // pts.push_back( Vector( 1, 1, 0 ) );
418  // std::vector< std::vector< unsigned int > > indices;
419  // naiveConvexHull( indices, pts, false ); // right_handed
420 
421  // viewPolygons( viewer, fillColor, indices, pts );
422  // viewer << Viewer3D::updateDisplay;
423 
424  unsigned int cfg = argc > 1 ? atoi( argv[1] ) : 0;
425  unsigned int cfg2 = argc > 2 ? atoi( argv[2] ) : 255;
426  std::map< Vector, bool > f;
427  for ( unsigned int y = 0; (y < 16) && (cfg <= cfg2); ++y )
428  for ( unsigned int x = 0; (x < 16) && (cfg <= cfg2); ++x, ++cfg )
429  {
430  Vector offset( x*6, y*6, 0 );
431  fillCfg( f, offset + Vector( 1, 1, 1 ), cfg );
432  Domain domain( offset + Vector( 0, 0, 0), offset + Vector( 2, 2, 2 ) );
433  KSpace K;
434  K.init( offset + Vector( 0, 0, 0), offset + Vector( 2, 2, 2 ), true );
435  ConfigPointPredicate<Vector> cpp( f, offset );
436  CellSet aBoundary;
437  Surfaces<KSpace>::uMakeBoundary( aBoundary, K, cpp, Vector( 0, 0, 0), Vector( 1, 1, 1 ) );
438  for ( CellSet::const_iterator it = aBoundary.begin(), itE = aBoundary.end();
439  it != itE; ++it )
440  {
441  viewer << CustomColors3D( surfelColor, surfelColor );
442  viewer << K.uTranslation( *it, offset/2 );
443  }
444  for ( Domain::ConstIterator it = domain.begin(), itE = domain.end();
445  it != itE; ++it )
446  {
447  // lightEpsilon( f, *it, 5 ); // {1,-1,1}=5 // interesting
448  f[ *it ] = lightBetween( f, *it );
449  }
450  viewer << CustomColors3D( DGtal::Color( 255, 0, 0, 255 ), fillColor );
451  std::vector< std::vector< unsigned int > > indices;
452  Domain domain2( offset + Vector( 0, 0, 0), offset + Vector( 1, 1, 1 ) );
453  for ( Domain::ConstIterator it = domain.begin(), itE = domain.end();
454  it != itE; ++it )
455  {
456  localDualVolume( pts, f, *it );
457  indices.clear();
458  naiveConvexHull( indices, pts, false ); // right_handed
459  viewPolygons( viewer, fillColor, indices, pts );
460  }
461  }
462  viewer << Viewer3D::updateDisplay;
464  return application.exec();
465 }