1 /*
2 Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
7
8 Redistributions of source code must retain the above copyright notice, this list of
9 conditions and the following disclaimer. Redistributions in binary form must reproduce
10 the above copyright notice, this list of conditions and the following disclaimer
11 in the documentation and/or other materials provided with the distribution.
12
13 Neither the name of the Johns Hopkins University nor the names of its contributors
14 may be used to endorse or promote products derived from this software without specific
15 prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
18 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES
19 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
20 SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
22 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26 DAMAGE.
27 */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <math.h>
32 #include <float.h>
33 #include <cmath>
34 #ifdef _WIN32
35 #include <Windows.h>
36 #include <Psapi.h>
37 #endif // _WIN32
38 #include "MyTime.h"
39 #include "MarchingCubes.h"
40 #include "Octree.h"
41 #include "SparseMatrix.h"
42 #include "CmdLineParser.h"
43 #include "PPolynomial.h"
44 #include "Ply.h"
45 #include "MemoryUsage.h"
46 #ifdef _OPENMP
47 #include "omp.h"
48 #endif // _OPENMP
49
50 namespace {
51
52 void DumpOutput( const char* format , ... );
53 void DumpOutput2( std::vector< char* >& comments , const char* format , ... );
54 #include "MultiGridOctreeData.h"
55
56 #define DEFAULT_FULL_DEPTH 5
57
58 #define XSTR(x) STR(x)
59 #define STR(x) #x
60 #if DEFAULT_FULL_DEPTH
61 // #pragma message ( "[WARNING] Setting default full depth to " XSTR(DEFAULT_FULL_DEPTH) )
62 #endif // DEFAULT_FULL_DEPTH
63
64 #include <stdarg.h>
65 char* outputFile=NULL;
66 int echoStdout=0;
DumpOutput(const char * format,...)67 void DumpOutput( const char* format , ... )
68 {
69 if( outputFile )
70 {
71 FILE* fp = fopen( outputFile , "a" );
72 va_list args;
73 va_start( args , format );
74 vfprintf( fp , format , args );
75 fclose( fp );
76 va_end( args );
77 }
78 if( echoStdout )
79 {
80 va_list args;
81 va_start( args , format );
82 vprintf( format , args );
83 va_end( args );
84 }
85 }
DumpOutput2(std::vector<char * > & comments,const char * format,...)86 void DumpOutput2( std::vector< char* >& comments , const char* format , ... )
87 {
88 if( outputFile )
89 {
90 FILE* fp = fopen( outputFile , "a" );
91 va_list args;
92 va_start( args , format );
93 vfprintf( fp , format , args );
94 fclose( fp );
95 va_end( args );
96 }
97 if( echoStdout )
98 {
99 va_list args;
100 va_start( args , format );
101 vprintf( format , args );
102 va_end( args );
103 }
104 comments.push_back( new char[1024] );
105 char* str = comments.back();
106 va_list args;
107 va_start( args , format );
108 vsprintf( str , format , args );
109 va_end( args );
110 if( str[strlen(str)-1]=='\n' ) str[strlen(str)-1] = 0;
111 }
112
113
114 cmdLineString
115 In( "in" ) ,
116 Out( "out" ) ,
117 VoxelGrid( "voxel" ) ,
118 XForm( "xForm" );
119
120 cmdLineReadable
121 #ifdef _WIN32
122 Performance( "performance" ) ,
123 #endif // _WIN32
124 Complete( "complete" ) ,
125 ShowResidual( "showResidual" ) ,
126 NoComments( "noComments" ) ,
127 PolygonMesh( "polygonMesh" ) ,
128 Confidence( "confidence" ) ,
129 NormalWeights( "nWeights" ) ,
130 NonManifold( "nonManifold" ) ,
131 Dirichlet( "dirichlet" ) ,
132 ASCII( "ascii" ) ,
133 Density( "density" ) ,
134 LinearFit( "linearFit" ) ,
135 PrimalVoxel( "primalVoxel" ) ,
136 Verbose( "verbose" ) ,
137 Double( "double" );
138
139 cmdLineInt
140 Degree( "degree" , 2 ) ,
141 Depth( "depth" , 8 ) ,
142 CGDepth( "cgDepth" , 0 ) ,
143 KernelDepth( "kernelDepth" ) ,
144 AdaptiveExponent( "adaptiveExp" , 1 ) ,
145 Iters( "iters" , 8 ) ,
146 VoxelDepth( "voxelDepth" , -1 ) ,
147 FullDepth( "fullDepth" , DEFAULT_FULL_DEPTH ) ,
148 MinDepth( "minDepth" , 0 ) ,
149 MaxSolveDepth( "maxSolveDepth" ) ,
150 Threads( "threads" , omp_get_num_procs() );
151
152 cmdLineFloat
153 Color( "color" , 16.f ) ,
154 SamplesPerNode( "samplesPerNode" , 1.5f ) ,
155 Scale( "scale" , 1.1f ) ,
156 CSSolverAccuracy( "cgAccuracy" , float(1e-3) ) ,
157 PointWeight( "pointWeight" , 4.f );
158
159
160 cmdLineReadable* params[] =
161 {
162 &In , &Degree , &Depth , &Out , &XForm ,
163 &Scale , &Verbose , &CSSolverAccuracy , &NoComments , &Double ,
164 &KernelDepth , &SamplesPerNode , &Confidence , &NormalWeights , &NonManifold , &PolygonMesh , &ASCII , &ShowResidual , &VoxelDepth ,
165 &PointWeight , &VoxelGrid , &Threads , &MaxSolveDepth ,
166 &AdaptiveExponent , &Dirichlet ,
167 &Density ,
168 &FullDepth ,
169 &MinDepth ,
170 &CGDepth , &Iters ,
171 &Complete ,
172 &Color ,
173 &LinearFit ,
174 &PrimalVoxel ,
175 #ifdef _WIN32
176 &Performance ,
177 #endif // _WIN32
178 };
179
180
ShowUsage(char * ex)181 void ShowUsage(char* ex)
182 {
183 printf( "Usage: %s\n" , ex );
184 printf( "\t --%s <input points>\n" , In.name );
185
186 printf( "\t[--%s <ouput triangle mesh>]\n" , Out.name );
187 printf( "\t[--%s <ouput voxel grid>]\n" , VoxelGrid.name );
188
189 printf( "\t[--%s <b-spline degree>=%d]\n" , Degree.name , Degree.value );
190
191 printf( "\t[--%s <maximum reconstruction depth>=%d]\n" , Depth.name , Depth.value );
192 printf( "\t\t Running at depth d corresponds to solving on a 2^d x 2^d x 2^d\n" );
193 printf( "\t\t voxel grid.\n" );
194
195 printf( "\t[--%s <full depth>=%d]\n" , FullDepth.name , FullDepth.value );
196 printf( "\t\t This flag specifies the depth up to which the octree should be complete.\n" );
197
198 printf( "\t[--%s <depth at which to extract the voxel grid>=<%s>]\n" , VoxelDepth.name , Depth.name );
199
200 printf( "\t[--%s <conjugate-gradients depth>=%d]\n" , CGDepth.name , CGDepth.value );
201 printf( "\t\t The depth up to which a conjugate-gradients solver should be used.\n");
202
203 printf( "\t[--%s <scale factor>=%f]\n" , Scale.name , Scale.value );
204 printf( "\t\t Specifies the factor of the bounding cube that the input\n" );
205 printf( "\t\t samples should fit into.\n" );
206
207 printf( "\t[--%s <minimum number of samples per node>=%f]\n" , SamplesPerNode.name, SamplesPerNode.value );
208 printf( "\t\t This parameter specifies the minimum number of points that\n" );
209 printf( "\t\t should fall within an octree node.\n" );
210
211 printf( "\t[--%s <interpolation weight>=%f]\n" , PointWeight.name , PointWeight.value );
212 printf( "\t\t This value specifies the weight that point interpolation constraints are\n" );
213 printf( "\t\t given when defining the (screened) Poisson system.\n" );
214
215 printf( "\t[--%s <iterations>=%d]\n" , Iters.name , Iters.value );
216 printf( "\t\t This flag specifies the (maximum if CG) number of solver iterations.\n" );
217
218 printf( "\t[--%s <pull factor>]\n" , Color.name );
219 printf( "\t\t This flag specifies the pull factor for color interpolation\n" );
220
221 #ifdef _OPENMP
222 printf( "\t[--%s <num threads>=%d]\n" , Threads.name , Threads.value );
223 printf( "\t\t This parameter specifies the number of threads across which\n" );
224 printf( "\t\t the solver should be parallelized.\n" );
225 #endif // _OPENMP
226
227 printf( "\t[--%s]\n" , Confidence.name );
228 printf( "\t\t If this flag is enabled, the size of a sample's normals is\n" );
229 printf( "\t\t used as a confidence value, affecting the sample's\n" );
230 printf( "\t\t constribution to the reconstruction process.\n" );
231
232 printf( "\t[--%s]\n" , NormalWeights.name );
233 printf( "\t\t If this flag is enabled, the size of a sample's normals is\n" );
234 printf( "\t\t used as to modulate the interpolation weight.\n" );
235
236 #if 0
237 printf( "\t[--%s]\n" , NonManifold.name );
238 printf( "\t\t If this flag is enabled, the isosurface extraction does not add\n" );
239 printf( "\t\t a planar polygon's barycenter in order to ensure that the output\n" );
240 printf( "\t\t mesh is manifold.\n" );
241 #endif
242
243 printf( "\t[--%s]\n" , PolygonMesh.name);
244 printf( "\t\t If this flag is enabled, the isosurface extraction returns polygons\n" );
245 printf( "\t\t rather than triangles.\n" );
246
247 #if 0
248 printf( "\t[--%s <minimum depth>=%d]\n" , MinDepth.name , MinDepth.value );
249 printf( "\t\t This flag specifies the coarsest depth at which the system is to be solved.\n" );
250
251 printf( "\t[--%s <cg solver accuracy>=%g]\n" , CSSolverAccuracy.name , CSSolverAccuracy.value );
252 printf( "\t\t This flag specifies the accuracy cut-off to be used for CG.\n" );
253
254 printf( "\t[--%s <adaptive weighting exponent>=%d]\n", AdaptiveExponent.name , AdaptiveExponent.value );
255 printf( "\t\t This flag specifies the exponent scale for the adaptive weighting.\n" );
256
257 #ifdef _WIN32
258 printf( "\t[--%s]\n" , Performance.name );
259 printf( "\t\t If this flag is enabled, the running time and peak memory usage\n" );
260 printf( "\t\t is output after the reconstruction.\n" );
261 #endif // _WIN32
262 #endif
263 printf( "\t[--%s]\n" , Dirichlet.name);
264 printf( "\t\t If this flag is enabled, Dirichlet boundary constraints are used for reconstruction.\n" );
265
266 printf( "\t[--%s]\n" , Density.name );
267 printf( "\t\t If this flag is enabled, the sampling density is written out with the vertices.\n" );
268
269 printf( "\t[--%s]\n" , LinearFit.name );
270 printf( "\t\t If this flag is enabled, the iso-surfacing will be performed using linear fitting.\n" );
271
272 printf( "\t[--%s]\n" , PrimalVoxel.name );
273 printf( "\t\t If this flag is enabled, voxel sampling is performed at corners rather than centers.\n" );
274
275 #if 0
276 printf( "\t[--%s]\n" , ASCII.name );
277 printf( "\t\t If this flag is enabled, the output file is written out in ASCII format.\n" );
278
279 printf( "\t[--%s]\n" , NoComments.name );
280 printf( "\t\t If this flag is enabled, the output file will not include comments.\n" );
281 #endif
282
283 printf( "\t[--%s]\n" , Double.name );
284 printf( "\t\t If this flag is enabled, the reconstruction will be performed with double-precision floats.\n" );
285
286 printf( "\t[--%s]\n" , Verbose.name );
287 printf( "\t\t If this flag is enabled, the progress of the reconstructor will be output to STDOUT.\n" );
288 }
289
ReadASCIIColor(FILE * fp)290 Point3D< unsigned char > ReadASCIIColor( FILE* fp )
291 {
292 Point3D< unsigned char > c;
293 if( fscanf( fp , " %c %c %c " , &c[0] , &c[1] , &c[2] )!=3 ) fprintf( stderr , "[ERROR] Failed to read color\n" ) , exit( 0 );
294 return c;
295 }
296
297 PlyProperty PlyColorProperties[]=
298 {
299 { "r" , PLY_UCHAR , PLY_UCHAR , int( offsetof( Point3D< unsigned char > , coords[0] ) ) , 0 , 0 , 0 , 0 } ,
300 { "g" , PLY_UCHAR , PLY_UCHAR , int( offsetof( Point3D< unsigned char > , coords[1] ) ) , 0 , 0 , 0 , 0 } ,
301 { "b" , PLY_UCHAR , PLY_UCHAR , int( offsetof( Point3D< unsigned char > , coords[2] ) ) , 0 , 0 , 0 , 0 } ,
302 { "red" , PLY_UCHAR , PLY_UCHAR , int( offsetof( Point3D< unsigned char > , coords[0] ) ) , 0 , 0 , 0 , 0 } ,
303 { "green" , PLY_UCHAR , PLY_UCHAR , int( offsetof( Point3D< unsigned char > , coords[1] ) ) , 0 , 0 , 0 , 0 } ,
304 { "blue" , PLY_UCHAR , PLY_UCHAR , int( offsetof( Point3D< unsigned char > , coords[2] ) ) , 0 , 0 , 0 , 0 }
305 };
306
ValidPlyColorProperties(const bool * props)307 bool ValidPlyColorProperties( const bool* props ){ return ( props[0] || props[3] ) && ( props[1] || props[4] ) && ( props[2] || props[5] ); }
308
309 template< class Real , int Degree , class Vertex >
_Execute(int argc,char * argv[])310 int _Execute( int argc , char* argv[] )
311 {
312 Reset< Real >();
313 int paramNum = sizeof(params)/sizeof(cmdLineReadable*);
314 std::vector< char* > comments;
315
316 if( Verbose.set ) echoStdout=1;
317
318 XForm4x4< Real > xForm , iXForm;
319 if( XForm.set )
320 {
321 FILE* fp = fopen( XForm.value , "r" );
322 if( !fp )
323 {
324 fprintf( stderr , "[WARNING] Could not read x-form from: %s\n" , XForm.value );
325 xForm = XForm4x4< Real >::Identity();
326 }
327 else
328 {
329 for( int i=0 ; i<4 ; i++ ) for( int j=0 ; j<4 ; j++ )
330 {
331 float f;
332 if( fscanf( fp , " %f " , &f )!=1 ) fprintf( stderr , "[ERROR] Execute: Failed to read xform\n" ) , exit( 0 );
333 xForm(i,j) = (Real)f;
334 }
335 fclose( fp );
336 }
337 }
338 else xForm = XForm4x4< Real >::Identity();
339 iXForm = xForm.inverse();
340
341 DumpOutput2( comments , "Running Screened Poisson Reconstruction (Version 8.0)\n" );
342 char str[1024];
343 for( int i=0 ; i<paramNum ; i++ )
344 if( params[i]->set )
345 {
346 params[i]->writeValue( str );
347 if( strlen( str ) ) DumpOutput2( comments , "\t--%s %s\n" , params[i]->name , str );
348 else DumpOutput2( comments , "\t--%s\n" , params[i]->name );
349 }
350
351 double t;
352 double tt=Time();
353 Real isoValue = 0;
354
355 Octree< Real > tree;
356 tree.threads = Threads.value;
357 if( !In.set )
358 {
359 ShowUsage( argv[0] );
360 return 0;
361 }
362 if( !MaxSolveDepth.set ) MaxSolveDepth.value = Depth.value;
363
364 OctNode< TreeNodeData >::SetAllocator( MEMORY_ALLOCATOR_BLOCK_SIZE );
365
366 t=Time();
367 int kernelDepth = KernelDepth.set ? KernelDepth.value : Depth.value-2;
368 if( kernelDepth>Depth.value )
369 {
370 fprintf( stderr,"[WARNING] %s can't be greater than %s: %d <= %d\n" , KernelDepth.name , Depth.name , KernelDepth.value , Depth.value );
371 kernelDepth = Depth.value;
372 }
373
374 double maxMemoryUsage;
375 t=Time() , tree.maxMemoryUsage=0;
376 SparseNodeData< PointData< Real > , 0 >* pointInfo = new SparseNodeData< PointData< Real > , 0 >();
377 SparseNodeData< Point3D< Real > , NORMAL_DEGREE >* normalInfo = new SparseNodeData< Point3D< Real > , NORMAL_DEGREE >();
378 SparseNodeData< Real , WEIGHT_DEGREE >* densityWeights = new SparseNodeData< Real , WEIGHT_DEGREE >();
379 SparseNodeData< Real , NORMAL_DEGREE >* nodeWeights = new SparseNodeData< Real , NORMAL_DEGREE >();
380 int pointCount;
381 typedef typename Octree< Real >::template ProjectiveData< Point3D< Real > > ProjectiveColor;
382 SparseNodeData< ProjectiveColor , DATA_DEGREE >* colorData = NULL;
383
384 char* ext = GetFileExtension( In.value );
385 if( Color.set && Color.value>0 )
386 {
387 colorData = new SparseNodeData< ProjectiveColor , DATA_DEGREE >();
388 OrientedPointStreamWithData< float , Point3D< unsigned char > >* pointStream;
389 if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryOrientedPointStreamWithData< float , Point3D< unsigned char > >( In.value );
390 else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYOrientedPointStreamWithData< float , Point3D< unsigned char > >( In.value , PlyColorProperties , 6 , ValidPlyColorProperties );
391 else pointStream = new ASCIIOrientedPointStreamWithData< float , Point3D< unsigned char > >( In.value , ReadASCIIColor );
392 pointCount = tree.template SetTree< float , NORMAL_DEGREE , WEIGHT_DEGREE , DATA_DEGREE , Point3D< unsigned char > >( pointStream , MinDepth.value , Depth.value , FullDepth.value , kernelDepth , Real(SamplesPerNode.value) , Scale.value , Confidence.set , NormalWeights.set , PointWeight.value , AdaptiveExponent.value , *densityWeights , *pointInfo , *normalInfo , *nodeWeights , colorData , xForm , Dirichlet.set , Complete.set );
393 delete pointStream;
394
395 for( const OctNode< TreeNodeData >* n = tree.tree().nextNode() ; n!=NULL ; n=tree.tree().nextNode( n ) )
396 {
397 int idx = colorData->index( n );
398 if( idx>=0 ) colorData->data[idx] *= (Real)pow( Color.value , n->depth() );
399 }
400 }
401 else
402 {
403 OrientedPointStream< float >* pointStream;
404 if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryOrientedPointStream< float >( In.value );
405 else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYOrientedPointStream< float >( In.value );
406 else pointStream = new ASCIIOrientedPointStream< float >( In.value );
407 pointCount = tree.template SetTree< float , NORMAL_DEGREE , WEIGHT_DEGREE , DATA_DEGREE , Point3D< unsigned char > >( pointStream , MinDepth.value , Depth.value , FullDepth.value , kernelDepth , Real(SamplesPerNode.value) , Scale.value , Confidence.set , NormalWeights.set , PointWeight.value , AdaptiveExponent.value , *densityWeights , *pointInfo , *normalInfo , *nodeWeights , colorData , xForm , Dirichlet.set , Complete.set );
408 delete pointStream;
409 }
410 delete[] ext;
411 if( !Density.set ) delete densityWeights , densityWeights = NULL;
412 {
413 std::vector< int > indexMap;
414 if( NORMAL_DEGREE>Degree ) tree.template EnableMultigrid< NORMAL_DEGREE >( &indexMap );
415 else tree.template EnableMultigrid< Degree >( &indexMap );
416 if( pointInfo ) pointInfo->remapIndices( indexMap );
417 if( normalInfo ) normalInfo->remapIndices( indexMap );
418 if( densityWeights ) densityWeights->remapIndices( indexMap );
419 if( nodeWeights ) nodeWeights->remapIndices( indexMap );
420 if( colorData ) colorData->remapIndices( indexMap );
421 }
422
423 DumpOutput2( comments , "# Tree set in: %9.1f (s), %9.1f (MB)\n" , Time()-t , tree.maxMemoryUsage );
424 DumpOutput( "Input Points: %d\n" , pointCount );
425 DumpOutput( "Leaves/Nodes: %d/%d\n" , tree.leaves() , tree.nodes() );
426 DumpOutput( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage() )/(1<<20) );
427
428 maxMemoryUsage = tree.maxMemoryUsage;
429 t=Time() , tree.maxMemoryUsage=0;
430 DenseNodeData< Real , Degree > constraints = tree.template SetLaplacianConstraints< Degree >( *normalInfo );
431 delete normalInfo;
432 DumpOutput2( comments , "# Constraints set in: %9.1f (s), %9.1f (MB)\n" , Time()-t , tree.maxMemoryUsage );
433 DumpOutput( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage())/(1<<20) );
434 maxMemoryUsage = std::max< double >( maxMemoryUsage , tree.maxMemoryUsage );
435
436 t=Time() , tree.maxMemoryUsage=0;
437 DenseNodeData< Real , Degree > solution = tree.SolveSystem( *pointInfo , constraints , ShowResidual.set , Iters.value , MaxSolveDepth.value , CGDepth.value , CSSolverAccuracy.value );
438 delete pointInfo;
439 constraints.resize( 0 );
440
441 DumpOutput2( comments , "# Linear system solved in: %9.1f (s), %9.1f (MB)\n" , Time()-t , tree.maxMemoryUsage );
442 DumpOutput( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage() )/(1<<20) );
443 maxMemoryUsage = std::max< double >( maxMemoryUsage , tree.maxMemoryUsage );
444
445 CoredFileMeshData< Vertex > mesh;
446
447 if( Verbose.set ) tree.maxMemoryUsage=0;
448 t=Time();
449 isoValue = tree.GetIsoValue( solution , *nodeWeights );
450 delete nodeWeights;
451 DumpOutput( "Got average in: %f\n" , Time()-t );
452 DumpOutput( "Iso-Value: %e\n" , isoValue );
453
454 if( VoxelGrid.set )
455 {
456 double t = Time();
457 FILE* fp = fopen( VoxelGrid.value , "wb" );
458 if( !fp ) fprintf( stderr , "Failed to open voxel file for writing: %s\n" , VoxelGrid.value );
459 else
460 {
461 int res = 0;
462 Pointer( Real ) values = tree.Evaluate( solution , res , isoValue , VoxelDepth.value , PrimalVoxel.set );
463 fwrite( &res , sizeof(int) , 1 , fp );
464 if( sizeof(Real)==sizeof(float) ) fwrite( values , sizeof(float) , res*res*res , fp );
465 else
466 {
467 float *fValues = new float[res*res*res];
468 for( int i=0 ; i<res*res*res ; i++ ) fValues[i] = float( values[i] );
469 fwrite( fValues , sizeof(float) , res*res*res , fp );
470 delete[] fValues;
471 }
472 fclose( fp );
473 DeletePointer( values );
474 }
475 DumpOutput( "Got voxel grid in: %f\n" , Time()-t );
476 }
477
478 if( Out.set )
479 {
480 t = Time() , tree.maxMemoryUsage = 0;
481 tree.template GetMCIsoSurface< Degree , WEIGHT_DEGREE , DATA_DEGREE >( densityWeights , colorData , solution , isoValue , mesh , !LinearFit.set , !NonManifold.set , PolygonMesh.set );
482 if( PolygonMesh.set ) DumpOutput2( comments , "# Got polygons in: %9.1f (s), %9.1f (MB)\n" , Time()-t , tree.maxMemoryUsage );
483 else DumpOutput2( comments , "# Got triangles in: %9.1f (s), %9.1f (MB)\n" , Time()-t , tree.maxMemoryUsage );
484 maxMemoryUsage = std::max< double >( maxMemoryUsage , tree.maxMemoryUsage );
485 DumpOutput2( comments , "# Total Solve: %9.1f (s), %9.1f (MB)\n" , Time()-tt , maxMemoryUsage );
486
487 if( NoComments.set )
488 {
489 if( ASCII.set ) PlyWritePolygons( Out.value , &mesh , PLY_ASCII , NULL , 0 , iXForm );
490 else PlyWritePolygons( Out.value , &mesh , PLY_BINARY_NATIVE , NULL , 0 , iXForm );
491 }
492 else
493 {
494 if( ASCII.set ) PlyWritePolygons( Out.value , &mesh , PLY_ASCII , &comments[0] , (int)comments.size() , iXForm );
495 else PlyWritePolygons( Out.value , &mesh , PLY_BINARY_NATIVE , &comments[0] , (int)comments.size() , iXForm );
496 }
497 DumpOutput( "Vertices / Polygons: %d / %d\n" , mesh.outOfCorePointCount()+mesh.inCorePoints.size() , mesh.polygonCount() );
498 }
499 solution.resize( 0 );
500 if( colorData ){ delete colorData ; colorData = NULL; }
501 return 1;
502 }
503
504 #ifdef _WIN32
to_seconds(const FILETIME & ft)505 inline double to_seconds( const FILETIME& ft )
506 {
507 const double low_to_sec=100e-9; // 100 nanoseconds
508 const double high_to_sec=low_to_sec*4294967296.0;
509 return ft.dwLowDateTime*low_to_sec+ft.dwHighDateTime*high_to_sec;
510 }
511 #endif // _WIN32
512
513 template< class Real , class Vertex >
Execute(int argc,char * argv[])514 int Execute( int argc , char* argv[] )
515 {
516 switch( Degree.value )
517 {
518 case 1: return _Execute< Real , 1 , Vertex >( argc , argv );
519 case 2: return _Execute< Real , 2 , Vertex >( argc , argv );
520 case 3: return _Execute< Real , 3 , Vertex >( argc , argv );
521 case 4: return _Execute< Real , 4 , Vertex >( argc , argv );
522 default:
523 fprintf( stderr , "[ERROR] Only B-Splines of degree 1 - 4 are supported" );
524 return EXIT_FAILURE;
525 }
526 }
527
528 } // namespace
529
PoissonRecon(int argc,char * argv[])530 int PoissonRecon( int argc , char* argv[] )
531 {
532 #if defined(WIN32) && defined(MAX_MEMORY_GB)
533 if( MAX_MEMORY_GB>0 )
534 {
535 SIZE_T peakMemory = 1;
536 peakMemory <<= 30;
537 peakMemory *= MAX_MEMORY_GB;
538 printf( "Limiting memory usage to %.2f GB\n" , float( peakMemory>>30 ) );
539 HANDLE h = CreateJobObject( NULL , NULL );
540 AssignProcessToJobObject( h , GetCurrentProcess() );
541
542 JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
543 jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_JOB_MEMORY;
544 jeli.JobMemoryLimit = peakMemory;
545 if( !SetInformationJobObject( h , JobObjectExtendedLimitInformation , &jeli , sizeof( jeli ) ) )
546 fprintf( stderr , "Failed to set memory limit\n" );
547 }
548 #endif // defined(WIN32) && defined(MAX_MEMORY_GB)
549 double t = Time();
550
551 cmdLineParse( argc-1 , &argv[1] , sizeof(params)/sizeof(cmdLineReadable*) , params , 1 );
552 if( Density.set )
553 if( Color.set )
554 if( Double.set ) Execute< double , PlyColorAndValueVertex< float > >( argc , argv );
555 else Execute< float , PlyColorAndValueVertex< float > >( argc , argv );
556 else
557 if( Double.set ) Execute< double , PlyValueVertex< float > >( argc , argv );
558 else Execute< float , PlyValueVertex< float > >( argc , argv );
559 else
560 if( Color.set )
561 if( Double.set ) Execute< double , PlyColorVertex< float > >( argc , argv );
562 else Execute< float , PlyColorVertex< float > >( argc , argv );
563 else
564 if( Double.set ) Execute< double , PlyVertex< float > >( argc , argv );
565 else Execute< float , PlyVertex< float > >( argc , argv );
566 #ifdef _WIN32
567 if( Performance.set )
568 {
569 HANDLE cur_thread=GetCurrentThread();
570 FILETIME tcreat, texit, tkernel, tuser;
571 if( GetThreadTimes( cur_thread , &tcreat , &texit , &tkernel , &tuser ) )
572 printf( "Time (Wall/User/Kernel): %.2f / %.2f / %.2f\n" , Time()-t , to_seconds( tuser ) , to_seconds( tkernel ) );
573 else printf( "Time: %.2f\n" , Time()-t );
574 HANDLE h = GetCurrentProcess();
575 PROCESS_MEMORY_COUNTERS pmc;
576 if( GetProcessMemoryInfo( h , &pmc , sizeof(pmc) ) ) printf( "Peak Memory (MB): %d\n" , pmc.PeakWorkingSetSize>>20 );
577 }
578 #endif // _WIN32
579 return EXIT_SUCCESS;
580 }
581