DGtalTools 2.1.0
Loading...
Searching...
No Matches
3dImplicitSurfaceExtractorByThickening.cpp
1
32#include <iostream>
33#include <sstream>
34#include <map>
35#include "CLI11.hpp"
36
37#include "DGtal/base/Common.h"
38#include "DGtal/base/CountedPtr.h"
39#include "DGtal/helpers/StdDefs.h"
40#include "DGtal/math/MPolynomial.h"
41#include "DGtal/io/readers/MPolynomialReader.h"
42#include "DGtal/io/viewers/PolyscopeViewer.h"
43#include "DGtal/topology/KhalimskySpaceND.h"
44#include "DGtal/topology/CubicalComplex.h"
45#include "DGtal/topology/CubicalComplexFunctions.h"
46#include "DGtal/topology/SetOfSurfels.h"
47#include "DGtal/topology/DigitalSurface.h"
48#include "DGtal/topology/helpers/Surfaces.h"
49#include "DGtal/shapes/GaussDigitizer.h"
50#include "DGtal/shapes/Mesh.h"
51#include "DGtal/shapes/implicit/ImplicitPolynomial3Shape.h"
53
54using namespace std;
55using namespace DGtal;
56
57
58
119template <typename CellOutputIterator, typename DigitalSurface>
120void
121analyzeSurface( CellOutputIterator itSure, CellOutputIterator itUnsure, DigitalSurface surface )
122{
123 typedef typename DigitalSurface::KSpace KSpace;
124 typedef typename DigitalSurface::Surfel Surfel;
125 typedef typename DigitalSurface::ConstIterator ConstIterator;
126 typedef typename DigitalSurface::DigitalSurfaceContainer Container;
127 typedef typename DigitalSurface::DigitalSurfaceTracker Tracker;
128 typedef typename KSpace::Integer Integer;
129 typedef typename KSpace::Cell Cell;
130 const Dimension t = KSpace::dimension - 1;
131 const Container& C = surface.container();
132 const KSpace& K = surface.container().space();
133 Surfel s2;
134 for ( ConstIterator it = surface.begin(), itE = surface.end(); it != itE; ++it )
135 {
136 Surfel s = *it;
137 Cell is = K.unsigns( s );
138 Integer s_xt = K.sKCoord( s, t );
139 if ( s_xt == 0 ) *itUnsure++ = is;
140 else if ( s_xt == -1 )
141 {
142 CountedPtr<Tracker> tracker( C.newTracker( s ) );
143 if ( tracker->adjacent( s2, t, true ) != 0 )
144 {
145 Integer s2_xt = K.sKCoord( s2, t );
146 Cell ic = K.uIncident( is, t, true );
147 if ( s2_xt > 0 ) *itSure++ = ic;
148 else *itUnsure++ = ic;
149 }
150 }
151 else if ( s_xt == 1 )
152 {
153 CountedPtr<Tracker> tracker( C.newTracker( s ) );
154 if ( tracker->adjacent( s2, t, false ) != 0 )
155 {
156 Integer s2_xt = K.sKCoord( s2, t );
157 Cell ic = K.uIncident( is, t, false );
158 if ( s2_xt < 0 ) *itSure++ = ic;
159 else *itUnsure++ = ic;
160 }
161 }
162 else cout << " " << s_xt;
163 }
164}
165
174template <typename ImplicitSurface, typename RealPoint>
175RealPoint projectNewton( const ImplicitSurface & is,
176 RealPoint x,
177 typename RealPoint::Coordinate epsilon,
178 unsigned int max_iter )
179{
180 typedef typename RealPoint::Coordinate Scalar;
181 RealPoint gx;
182 Scalar f, g2;
183 Scalar eps2 = epsilon * epsilon;
184 while ( max_iter-- != 0 )
185 {
186 f = is( x );
187 if ( abs( f ) < epsilon ) return x;
188 gx = is.gradient( x );
189 g2 = gx.dot( gx );
190 if ( g2 < eps2 ) return x;
191 x -= (f/g2) * gx;
192 }
193 return x;
194}
195
196
197template <typename CubicalComplex3, typename ImplicitShape3,
198 typename ImplicitDigitalShape3>
199void projectComplex( std::vector< typename ImplicitShape3::RealPoint >& points,
200 const CubicalComplex3& complex3,
201 const ImplicitShape3& shape,
202 const ImplicitDigitalShape3& dshape,
203 double epsilon,
204 unsigned int max_iter,
205 double max_distance )
206{
207 typedef typename CubicalComplex3::Cell Cell3;
208 typedef typename CubicalComplex3::Point Point3;
209 typedef typename CubicalComplex3::CellMapConstIterator CellMapConstIterator;
210 typedef typename ImplicitShape3::RealPoint RealPoint3;
211 typedef typename ImplicitShape3::Ring Ring;
212 points.clear();
213 for ( CellMapConstIterator it = complex3.begin( 0 ), itE = complex3.end( 0 ); it != itE; ++it )
214 {
215 Cell3 cell = it->first;
216 Point3 dp = complex3.space().uKCoords( cell ) - Point3::diagonal( 1 );
217 RealPoint3 p = dshape->embed( dp ) / 2.0;
218 RealPoint3 q = projectNewton( shape, p, epsilon, max_iter );
219 double d = (p-q).norm();
220 if ( d > max_distance ) q = p + (q-p)*( max_distance / d );
221 points.push_back( q );
222 }
223}
224
225template <typename CubicalComplex3, typename ImplicitShape3,
226 typename ImplicitDigitalShape3>
227typename ImplicitShape3::Ring
228getValue( const CubicalComplex3& complex3,
229 const typename CubicalComplex3::Cell& cell,
230 const ImplicitShape3& shape,
231 const ImplicitDigitalShape3& dshape )
232{
233 typedef typename CubicalComplex3::Cell Cell3;
234 typedef typename CubicalComplex3::Cells Cells3;
235 typedef typename CubicalComplex3::Point Point3;
236 typedef typename ImplicitShape3::RealPoint RealPoint3;
237 typedef typename ImplicitShape3::Ring Ring;
238
239 Point3 dp = complex3.space().uKCoords( cell ) - Point3::diagonal( 1 );
240 RealPoint3 p = dshape->embed( dp ) / 2.0;
241 Ring v = shape( p );
242 return v;
243}
244
245
246template <typename CubicalComplex3, typename ImplicitShape3,
247 typename ImplicitDigitalShape3>
248void doNotProjectComplex( std::vector< typename ImplicitShape3::RealPoint >& points,
249 const CubicalComplex3& complex3,
250 const ImplicitShape3& shape,
251 const ImplicitDigitalShape3& dshape )
252{
253 typedef typename CubicalComplex3::Cell Cell3;
254 typedef typename CubicalComplex3::Point Point3;
255 typedef typename CubicalComplex3::CellMapConstIterator CellMapConstIterator;
256 typedef typename ImplicitShape3::RealPoint RealPoint3;
257 typedef typename ImplicitShape3::Ring Ring;
258 points.clear();
259 for ( CellMapConstIterator it = complex3.begin( 0 ), itE = complex3.end( 0 ); it != itE; ++it )
260 {
261 Cell3 cell = it->first;
262 Point3 dp = complex3.space().uKCoords( cell );
263 RealPoint3 p = dshape->embed( dp ) / 2.0;
264 points.push_back( p );
265 }
266}
267
268
269
270int main( int argc, char** argv )
271{
272 typedef int Integer;
273 typedef SpaceND<3,Integer> Space3;
274 typedef KhalimskySpaceND<3,Integer> KSpace3;
275 typedef KSpace3::Cell Cell3;
276 typedef std::map<Cell3, CubicalCellData> Map3;
277 // typedef boost::unordered_map<Cell3, CubicalCellData> Map3;
278 typedef CubicalComplex< KSpace3, Map3 > CC3;
279 typedef Space3::Point Point3;
280 typedef Space3::RealPoint RealPoint3;
281 typedef Space3::RealVector RealVector3;
282 typedef RealPoint3::Coordinate Ring;
283 typedef Ring Scalar;
284 typedef MPolynomial<3, Ring> Polynomial3;
285 typedef MPolynomialReader<3, Ring> Polynomial3Reader;
286 typedef ImplicitPolynomial3Shape<Space3> ImplicitShape3;
287 typedef GaussDigitizer< Space3, ImplicitShape3 >
288 ImplicitDigitalShape3;
289 typedef ImplicitDigitalShape3::Domain Domain3;
290 typedef CC3::CellMapIterator CellMapIterator;
291 typedef CC3::CellMapConstIterator CellMapConstIterator;
292 typedef CC3::Cells Cells3;
293
294 // parse command line using CLI ----------------------------------------------
295 CLI::App app;
296 string poly_str;
297 std::string outputFileName {"result.raw"};
298 DGtal::int64_t rescaleInputMin {0};
299 DGtal::int64_t rescaleInputMax {255};
300 Ring min_x {-10.0};
301 Ring max_x {10.0};
302 Ring h {1.0};
303 Ring t {1e-2};
304 std::string project {"Newton"};
305 double epsilon {1e-6};
306 unsigned int max_iter {500};
307 std::string view {"Normal"};
308
309 app.description( "Computes the zero level set of the given polynomial. Usage: 3dImplicitSurfaceExtractorByThickening -p <polynomial> [options]\n Example:\n 3dImplicitSurfaceExtractorByThickening -p \"x^2-y*z^2\" -g 0.1 -a -2 -A 2 -v Singular\n - whitney : x^2-y*z^2 \n - 4lines : x*y*(y-x)*(y-z*x) \n - cone : z^2-x^2-y^2 \n - simonU : x^2-z*y^2+x^4+y^4 \n - cayley3 : 4*(x^2 + y^2 + z^2) + 16*x*y*z - 1 \n - crixxi : -0.9*(y^2+z^2-1)^2-(x^2+y^2-1)^3 \n Some other examples (more difficult): \n 3dImplicitSurfaceExtractorByThickening -a -2 -A 2 -p \"((y^2+z^2-1)^2-(x^2+y^2-1)^3)*(y*(x-1)^2-z*(x+1))^2\" -g 0.025 -e 1e-6 -n 50000 -v Singular -t 0.5 -P Newton \n 3dImplicitSurfaceExtractorByThickening -a -2 -A 2 -p \"(x^5-4*z^3*y^2)*((x+y)^2-(z-x)^3)\" -g 0.025 -e 1e-6 -n 50000 -v Singular -t 0.05 -P Newton ");
310 app.add_option("-p,--polynomial,1", poly_str, "the implicit polynomial whose zero-level defines the shape of interest." )
311 ->required();
312 app.add_option("--minAABB,-a",min_x, "the min value of the AABB bounding box (domain)");
313 app.add_option("--maxAABB,-A",max_x, "the max value of the AABB bounding box (domain)" );
314 app.add_option("--gridstep,-g", h, "the gridstep that defines the digitization (often called h).");
315 app.add_option("--thickness,-t",t, "the thickening parameter for the implicit surface." );
316 app.add_option("--project,-P", project, "defines the projection: either No or Newton.")
317 -> check(CLI::IsMember({"No", "Newton"}));
318 app.add_option("--epsilon,-e", epsilon, "the maximum precision relative to the implicit surface in the Newton approximation of F=0.");
319 app.add_option("--max_iter,-n", max_iter, "the maximum number of iteration in the Newton approximation of F=0." );
320 app.add_option("--view,-v", view, "specifies if the surface is viewed as is (Normal) or if places close to singularities are highlighted (Singular), or if unsure places should not be displayed (Hide).")
321 -> check(CLI::IsMember({"Singular", "Normal", "Hide"}));
322
323 app.get_formatter()->column_width(40);
324 CLI11_PARSE(app, argc, argv);
325 // END parse command line using CLI ----------------------------------------------
326
327
328 //-------------- read polynomial and creating 3d implicit fct -----------------
329 trace.beginBlock( "Reading polynomial and creating 3D implicit function" );
330 Polynomial3 poly;
331 Polynomial3Reader reader;
332 string::const_iterator iter = reader.read( poly, poly_str.begin(), poly_str.end() );
333 if ( iter != poly_str.end() )
334 {
335 trace.error() << "ERROR reading polynomial: I read only <" << poly_str.substr( 0, iter - poly_str.begin() )
336 << ">, and I built P=" << poly << std::endl;
337 return 2;
338 }
339 // Creating implicit shape and storing it with smart pointer for automatic deallocation.
340 CountedPtr<ImplicitShape3> shape( new ImplicitShape3( poly ) );
341
342 RealPoint3 p1( min_x, min_x, min_x );
343 RealPoint3 p2( max_x, max_x, max_x );
344 // Creating digitized shape and storing it with smart pointer for automatic deallocation.
345 CountedPtr<ImplicitDigitalShape3> dshape( new ImplicitDigitalShape3() );
346 dshape->attach( *shape );
347 dshape->init( p1, p2, RealVector3( h, h, h ) );
348 Domain3 domain3 = dshape->getDomain();
349 KSpace3 K3;
350 K3.init( domain3.lowerBound(), domain3.upperBound(), true );
351 trace.info() << "- domain is " << domain3 << std::endl;
352 trace.endBlock();
353
354 //-------------- read polynomial and creating 3d implicit fct -----------------
355 trace.beginBlock( "Extracting thickened isosurface [-t,+t] of 3D polynomial. " );
356 CubicalCellData unsure_data( 0 );
357 CubicalCellData sure_data( CC3::FIXED );
358 CC3 complex3( K3 );
359 for ( Domain3::ConstIterator it = domain3.begin(), itE = domain3.end(); it != itE; ++it )
360 {
361 Cell3 spel = K3.uSpel( *it );
362 // RealPoint3 px = dshape->embed( *it );
363 RealPoint3 px = dshape->embed( K3.uKCoords( spel ) - Point3::diagonal( 1 ) ) / 2.0;
364 Ring s = (*shape)( px );
365 if ( (-t <= s ) && ( s <= t ) ) complex3.insertCell( spel, unsure_data );
366 }
367 trace.info() << "- K[-t,+t] = " << complex3 << endl;
368 complex3.close();
369 trace.info() << "- Cl K[-t,+t] = " << complex3 << endl;
370 std::vector<Cell3> separating_cells;
371 std::back_insert_iterator< std::vector<Cell3> > outItSurface( separating_cells );
372 Surfaces<KSpace3>::uWriteBoundary( outItSurface,
373 K3, *dshape, domain3.lowerBound(), domain3.upperBound() );
374 trace.info() << "- separating S = " << separating_cells.size() << " 2-cells." << endl;
375 complex3.insertCells( separating_cells.begin(), separating_cells.end(), sure_data );
376 for ( std::vector<Cell3>::const_iterator it = separating_cells.begin(), itE = separating_cells.end(); it != itE; ++it )
377 {
378 Cells3 bdry = K3.uFaces( *it );
379 for ( Cells3::const_iterator itBdry = bdry.begin(), itBdryE = bdry.end(); itBdry != itBdryE; ++itBdry )
380 complex3.insertCell( *itBdry, sure_data );
381 }
382 separating_cells.clear();
383 trace.info() << "- Cl K[-t,+t] + Cl S = " << complex3 << endl;
384 trace.endBlock();
385
386 //-------------- Get boundary and inner cells --------------------------------
387 trace.beginBlock( "Get boundary and inner cells. " );
388 std::vector<Cell3> inner;
389 std::vector<Cell3> bdry;
390 functions::filterCellsWithinBounds
391 ( complex3, K3.uKCoords( K3.lowerCell() ), K3.uKCoords( K3.upperCell() ),
392 std::back_inserter( bdry ), std::back_inserter( inner ) );
393 trace.info() << "- there are " << inner.size() << " inner cells." << endl;
394 trace.info() << "- there are " << bdry.size() << " boundary cells." << endl;
395 trace.endBlock();
396
397 //-------------- Compute priority function -----------------------------------
398 trace.beginBlock( "Compute priority function. " );
399 Dimension d = complex3.dim();
400 for ( Dimension i = 0; i <= d; ++i )
401 {
402 for ( CellMapIterator it = complex3.begin( i ), itE = complex3.end( i ); it != itE; ++it )
403 {
404 Cell3 cell = it->first;
405 Ring v = getValue( complex3, cell, *shape, dshape );
406 v = abs( 10000.0*v );
407 if ( v > 10000000.0 ) v = 10000000.0;
408 it->second.data &= ~CC3::VALUE;
409 it->second.data |= (DGtal::uint32_t) floor( v );
410 // std::cout << " " << it->second.data;
411 }
412 }
413 trace.endBlock();
414
415 //-------------- Collapse boundary -------------------------------------------
416 trace.beginBlock( "Collapse boundary. " );
417 typename CC3::DefaultCellMapIteratorPriority priority;
418 CC3 bdry_complex3( K3 );
419 for ( std::vector<Cell3>::const_iterator it = bdry.begin(), itE = bdry.end(); it != itE; ++it )
420 {
421 Cell3 cell = *it;
422 Dimension d = K3.uDim( cell );
423 CellMapConstIterator cmIt = complex3.findCell( d, cell );
424 bdry_complex3.insertCell( d, cell, cmIt->second );
425 }
426 trace.info() << "- [before collapse] K_bdry =" << bdry_complex3 << endl;
427 functions::collapse( bdry_complex3, bdry.begin(), bdry.end(), priority, true, true, false );
428 trace.info() << "- [after collapse] K_bdry =" << bdry_complex3 << endl;
429 for ( std::vector<Cell3>::const_iterator it = bdry.begin(), itE = bdry.end(); it != itE; ++it )
430 {
431 Cell3 cell = *it;
432 Dimension d = K3.uDim( cell );
433 CellMapConstIterator cmIt = bdry_complex3.findCell( d, cell );
434 if ( cmIt != bdry_complex3.end( d ) ) {
435 CellMapIterator cmIt2 = complex3.findCell( d, cell );
436 cmIt2->second = sure_data;
437 }
438 }
439 trace.endBlock();
440
441 //-------------- Collapse all -------------------------------------------
442 trace.beginBlock( "Collapse all. " );
443 std::copy( bdry.begin(), bdry.end(), std::back_inserter( inner ) );
444 functions::collapse( complex3, inner.begin(), inner.end(), priority, true, true, true );
445 trace.info() << "- K = " << complex3 << endl;
446 trace.endBlock();
447
448 //-------------- Project complex onto surface --------------------------------
449 trace.beginBlock( "Project complex onto surface. " );
450 std::vector<RealPoint3> points;
451 if ( project == "Newton" )
452 projectComplex( points, complex3, *shape, dshape, epsilon, max_iter, h * sqrt(3.0));
453 else
454 doNotProjectComplex( points, complex3, *shape, dshape );
455 trace.endBlock();
456
457 //-------------- Create Mesh -------------------------------------------
458 trace.beginBlock( "Create Mesh. " );
459 bool highlight = ( view == "Singular" );
460 bool hide = ( view == "Hide" );
461 Mesh<RealPoint3> mesh( true );
462 std::map<Cell3,unsigned int> indices;
463 int idx = 0;
464 for ( CellMapConstIterator it = complex3.begin( 0 ), itE = complex3.end( 0 ); it != itE; ++it, ++idx )
465 {
466 Cell3 cell = it->first;
467 indices[ cell ] = idx;
468 mesh.addVertex( points[ idx ] );
469 }
470 for ( CellMapConstIterator it = complex3.begin( 2 ), itE = complex3.end( 2 ); it != itE; ++it )
471 {
472 Cell3 cell = it->first;
473 bool fixed = it->second.data & CC3::FIXED;
474 Cells3 bdry = complex3.cellBoundary( cell, true );
475 std::vector<unsigned int> face_idx;
476 for ( Cells3::const_iterator itC = bdry.begin(), itCE = bdry.end(); itC != itCE; ++itC )
477 {
478 if ( complex3.dim( *itC ) == 0 )
479 face_idx.push_back( indices[ *itC ] );
480 }
481 if ( ( ! fixed ) && hide ) continue;
482 Color color = highlight
483 ? ( fixed ? Color::White : Color(128,255,128) )
484 : Color::White;
485 RealVector3 diag03 = points[ face_idx[ 0 ] ] - points[ face_idx[ 3 ] ];
486 RealVector3 diag12 = points[ face_idx[ 1 ] ] - points[ face_idx[ 2 ] ];
487 if ( diag03.dot( diag03 ) <= diag12.dot( diag12 ) )
488 {
489 mesh.addTriangularFace( face_idx[ 0 ], face_idx[ 1 ], face_idx[ 3 ], color );
490 mesh.addTriangularFace( face_idx[ 0 ], face_idx[ 3 ], face_idx[ 2 ], color );
491 }
492 else
493 {
494 mesh.addTriangularFace( face_idx[ 0 ], face_idx[ 1 ], face_idx[ 2 ], color );
495 mesh.addTriangularFace( face_idx[ 1 ], face_idx[ 3 ], face_idx[ 2 ], color );
496 }
497 //mesh.addQuadFace( face_idx[ 0 ], face_idx[ 1 ], face_idx[ 3 ], face_idx[ 2 ], color );
498 }
499 trace.endBlock();
500
501 //-------------- View surface -------------------------------------------
502 stringstream s;
503 s << "3dImplicitSurfaceExtractorByThickening - DGtalTools";
504
505 polyscope::options::programName = s.str();
506 polyscope::view::setNavigateStyle(polyscope::NavigateStyle::Free);
507
508 PolyscopeViewer<Space3,KSpace3> viewer( K3 );
509 viewer << mesh;
510
511 // Display lines that are not in the mesh.
512 for ( CellMapConstIterator it = complex3.begin( 1 ), itE = complex3.end( 1 ); it != itE; ++it )
513 {
514 Cell3 cell = it->first;
515 bool fixed = it->second.data & CC3::FIXED;
516 std::vector<Cell3> dummy;
517 std::back_insert_iterator< std::vector<Cell3> > outIt( dummy );
518 complex3.directCoFaces( outIt, cell );
519 if ( ! dummy.empty() ) continue;
520
521 Cells3 bdry = complex3.cellBoundary( cell, true );
522 Cell3 v0 = *(bdry.begin() );
523 Cell3 v1 = *(bdry.begin() + 1);
524 if ( ( ! fixed ) && hide ) continue;
525 Color color = highlight
526 ? ( fixed ? Color::White : Color(128,255,128) )
527 : Color::White;
528 viewer.drawColor( color );
529 viewer.drawLine( points[ indices[ v0 ] ], points[ indices[ v1 ] ]);
530 }
531 viewer.show();
532 return 0;
533}
Definition ATu0v1.h:57