| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <math.h> |
| #include <float.h> |
| #include <cmath> |
| #ifdef _WIN32 |
| #include <Windows.h> |
| #include <Psapi.h> |
| #endif |
| #include "MyTime.h" |
| #include "MarchingCubes.h" |
| #include "Octree.h" |
| #include "SparseMatrix.h" |
| #include "CmdLineParser.h" |
| #include "PPolynomial.h" |
| #include "Ply.h" |
| #include "MemoryUsage.h" |
| #ifdef _OPENMP |
| #include "omp.h" |
| #endif |
|
|
| namespace { |
|
|
| void DumpOutput( const char* format , ... ); |
| void DumpOutput2( std::vector< char* >& comments , const char* format , ... ); |
| #include "MultiGridOctreeData.h" |
|
|
| #define DEFAULT_FULL_DEPTH 5 |
|
|
| #define XSTR(x) STR(x) |
| #define STR(x) #x |
| #if DEFAULT_FULL_DEPTH |
| |
| #endif |
|
|
| #include <stdarg.h> |
| char* outputFile=NULL; |
| int echoStdout=0; |
| void DumpOutput( const char* format , ... ) |
| { |
| if( outputFile ) |
| { |
| FILE* fp = fopen( outputFile , "a" ); |
| va_list args; |
| va_start( args , format ); |
| vfprintf( fp , format , args ); |
| fclose( fp ); |
| va_end( args ); |
| } |
| if( echoStdout ) |
| { |
| va_list args; |
| va_start( args , format ); |
| vprintf( format , args ); |
| va_end( args ); |
| } |
| } |
| void DumpOutput2( std::vector< char* >& comments , const char* format , ... ) |
| { |
| if( outputFile ) |
| { |
| FILE* fp = fopen( outputFile , "a" ); |
| va_list args; |
| va_start( args , format ); |
| vfprintf( fp , format , args ); |
| fclose( fp ); |
| va_end( args ); |
| } |
| if( echoStdout ) |
| { |
| va_list args; |
| va_start( args , format ); |
| vprintf( format , args ); |
| va_end( args ); |
| } |
| comments.push_back( new char[1024] ); |
| char* str = comments.back(); |
| va_list args; |
| va_start( args , format ); |
| vsprintf( str , format , args ); |
| va_end( args ); |
| if( str[strlen(str)-1]=='\n' ) str[strlen(str)-1] = 0; |
| } |
|
|
|
|
| cmdLineString |
| In( "in" ) , |
| Out( "out" ) , |
| VoxelGrid( "voxel" ) , |
| XForm( "xForm" ); |
|
|
| cmdLineReadable |
| #ifdef _WIN32 |
| Performance( "performance" ) , |
| #endif |
| Complete( "complete" ) , |
| ShowResidual( "showResidual" ) , |
| NoComments( "noComments" ) , |
| PolygonMesh( "polygonMesh" ) , |
| Confidence( "confidence" ) , |
| NormalWeights( "nWeights" ) , |
| NonManifold( "nonManifold" ) , |
| Dirichlet( "dirichlet" ) , |
| ASCII( "ascii" ) , |
| Density( "density" ) , |
| LinearFit( "linearFit" ) , |
| PrimalVoxel( "primalVoxel" ) , |
| Verbose( "verbose" ) , |
| Double( "double" ); |
|
|
| cmdLineInt |
| Degree( "degree" , 2 ) , |
| Depth( "depth" , 8 ) , |
| CGDepth( "cgDepth" , 0 ) , |
| KernelDepth( "kernelDepth" ) , |
| AdaptiveExponent( "adaptiveExp" , 1 ) , |
| Iters( "iters" , 8 ) , |
| VoxelDepth( "voxelDepth" , -1 ) , |
| FullDepth( "fullDepth" , DEFAULT_FULL_DEPTH ) , |
| MinDepth( "minDepth" , 0 ) , |
| MaxSolveDepth( "maxSolveDepth" ) , |
| Threads( "threads" , omp_get_num_procs() ); |
|
|
| cmdLineFloat |
| Color( "color" , 16.f ) , |
| SamplesPerNode( "samplesPerNode" , 1.5f ) , |
| Scale( "scale" , 1.1f ) , |
| CSSolverAccuracy( "cgAccuracy" , float(1e-3) ) , |
| PointWeight( "pointWeight" , 4.f ); |
|
|
|
|
| cmdLineReadable* params[] = |
| { |
| &In , &Degree , &Depth , &Out , &XForm , |
| &Scale , &Verbose , &CSSolverAccuracy , &NoComments , &Double , |
| &KernelDepth , &SamplesPerNode , &Confidence , &NormalWeights , &NonManifold , &PolygonMesh , &ASCII , &ShowResidual , &VoxelDepth , |
| &PointWeight , &VoxelGrid , &Threads , &MaxSolveDepth , |
| &AdaptiveExponent , &Dirichlet , |
| &Density , |
| &FullDepth , |
| &MinDepth , |
| &CGDepth , &Iters , |
| &Complete , |
| &Color , |
| &LinearFit , |
| &PrimalVoxel , |
| #ifdef _WIN32 |
| &Performance , |
| #endif |
| }; |
|
|
|
|
| void ShowUsage(char* ex) |
| { |
| printf( "Usage: %s\n" , ex ); |
| printf( "\t --%s <input points>\n" , In.name ); |
|
|
| printf( "\t[--%s <ouput triangle mesh>]\n" , Out.name ); |
| printf( "\t[--%s <ouput voxel grid>]\n" , VoxelGrid.name ); |
|
|
| printf( "\t[--%s <b-spline degree>=%d]\n" , Degree.name , Degree.value ); |
|
|
| printf( "\t[--%s <maximum reconstruction depth>=%d]\n" , Depth.name , Depth.value ); |
| printf( "\t\t Running at depth d corresponds to solving on a 2^d x 2^d x 2^d\n" ); |
| printf( "\t\t voxel grid.\n" ); |
|
|
| printf( "\t[--%s <full depth>=%d]\n" , FullDepth.name , FullDepth.value ); |
| printf( "\t\t This flag specifies the depth up to which the octree should be complete.\n" ); |
|
|
| printf( "\t[--%s <depth at which to extract the voxel grid>=<%s>]\n" , VoxelDepth.name , Depth.name ); |
|
|
| printf( "\t[--%s <conjugate-gradients depth>=%d]\n" , CGDepth.name , CGDepth.value ); |
| printf( "\t\t The depth up to which a conjugate-gradients solver should be used.\n"); |
|
|
| printf( "\t[--%s <scale factor>=%f]\n" , Scale.name , Scale.value ); |
| printf( "\t\t Specifies the factor of the bounding cube that the input\n" ); |
| printf( "\t\t samples should fit into.\n" ); |
|
|
| printf( "\t[--%s <minimum number of samples per node>=%f]\n" , SamplesPerNode.name, SamplesPerNode.value ); |
| printf( "\t\t This parameter specifies the minimum number of points that\n" ); |
| printf( "\t\t should fall within an octree node.\n" ); |
|
|
| printf( "\t[--%s <interpolation weight>=%f]\n" , PointWeight.name , PointWeight.value ); |
| printf( "\t\t This value specifies the weight that point interpolation constraints are\n" ); |
| printf( "\t\t given when defining the (screened) Poisson system.\n" ); |
|
|
| printf( "\t[--%s <iterations>=%d]\n" , Iters.name , Iters.value ); |
| printf( "\t\t This flag specifies the (maximum if CG) number of solver iterations.\n" ); |
|
|
| printf( "\t[--%s <pull factor>]\n" , Color.name ); |
| printf( "\t\t This flag specifies the pull factor for color interpolation\n" ); |
|
|
| #ifdef _OPENMP |
| printf( "\t[--%s <num threads>=%d]\n" , Threads.name , Threads.value ); |
| printf( "\t\t This parameter specifies the number of threads across which\n" ); |
| printf( "\t\t the solver should be parallelized.\n" ); |
| #endif |
|
|
| printf( "\t[--%s]\n" , Confidence.name ); |
| printf( "\t\t If this flag is enabled, the size of a sample's normals is\n" ); |
| printf( "\t\t used as a confidence value, affecting the sample's\n" ); |
| printf( "\t\t constribution to the reconstruction process.\n" ); |
|
|
| printf( "\t[--%s]\n" , NormalWeights.name ); |
| printf( "\t\t If this flag is enabled, the size of a sample's normals is\n" ); |
| printf( "\t\t used as to modulate the interpolation weight.\n" ); |
|
|
| #if 0 |
| printf( "\t[--%s]\n" , NonManifold.name ); |
| printf( "\t\t If this flag is enabled, the isosurface extraction does not add\n" ); |
| printf( "\t\t a planar polygon's barycenter in order to ensure that the output\n" ); |
| printf( "\t\t mesh is manifold.\n" ); |
| #endif |
|
|
| printf( "\t[--%s]\n" , PolygonMesh.name); |
| printf( "\t\t If this flag is enabled, the isosurface extraction returns polygons\n" ); |
| printf( "\t\t rather than triangles.\n" ); |
|
|
| #if 0 |
| printf( "\t[--%s <minimum depth>=%d]\n" , MinDepth.name , MinDepth.value ); |
| printf( "\t\t This flag specifies the coarsest depth at which the system is to be solved.\n" ); |
|
|
| printf( "\t[--%s <cg solver accuracy>=%g]\n" , CSSolverAccuracy.name , CSSolverAccuracy.value ); |
| printf( "\t\t This flag specifies the accuracy cut-off to be used for CG.\n" ); |
|
|
| printf( "\t[--%s <adaptive weighting exponent>=%d]\n", AdaptiveExponent.name , AdaptiveExponent.value ); |
| printf( "\t\t This flag specifies the exponent scale for the adaptive weighting.\n" ); |
|
|
| #ifdef _WIN32 |
| printf( "\t[--%s]\n" , Performance.name ); |
| printf( "\t\t If this flag is enabled, the running time and peak memory usage\n" ); |
| printf( "\t\t is output after the reconstruction.\n" ); |
| #endif |
| #endif |
| printf( "\t[--%s]\n" , Dirichlet.name); |
| printf( "\t\t If this flag is enabled, Dirichlet boundary constraints are used for reconstruction.\n" ); |
|
|
| printf( "\t[--%s]\n" , Density.name ); |
| printf( "\t\t If this flag is enabled, the sampling density is written out with the vertices.\n" ); |
|
|
| printf( "\t[--%s]\n" , LinearFit.name ); |
| printf( "\t\t If this flag is enabled, the iso-surfacing will be performed using linear fitting.\n" ); |
|
|
| printf( "\t[--%s]\n" , PrimalVoxel.name ); |
| printf( "\t\t If this flag is enabled, voxel sampling is performed at corners rather than centers.\n" ); |
|
|
| #if 0 |
| printf( "\t[--%s]\n" , ASCII.name ); |
| printf( "\t\t If this flag is enabled, the output file is written out in ASCII format.\n" ); |
|
|
| printf( "\t[--%s]\n" , NoComments.name ); |
| printf( "\t\t If this flag is enabled, the output file will not include comments.\n" ); |
| #endif |
|
|
| printf( "\t[--%s]\n" , Double.name ); |
| printf( "\t\t If this flag is enabled, the reconstruction will be performed with double-precision floats.\n" ); |
|
|
| printf( "\t[--%s]\n" , Verbose.name ); |
| printf( "\t\t If this flag is enabled, the progress of the reconstructor will be output to STDOUT.\n" ); |
| } |
|
|
| Point3D< unsigned char > ReadASCIIColor( FILE* fp ) |
| { |
| Point3D< unsigned char > c; |
| if( fscanf( fp , " %c %c %c " , &c[0] , &c[1] , &c[2] )!=3 ) fprintf( stderr , "[ERROR] Failed to read color\n" ) , exit( 0 ); |
| return c; |
| } |
|
|
| PlyProperty PlyColorProperties[]= |
| { |
| { "r" , PLY_UCHAR , PLY_UCHAR , int( offsetof( Point3D< unsigned char > , coords[0] ) ) , 0 , 0 , 0 , 0 } , |
| { "g" , PLY_UCHAR , PLY_UCHAR , int( offsetof( Point3D< unsigned char > , coords[1] ) ) , 0 , 0 , 0 , 0 } , |
| { "b" , PLY_UCHAR , PLY_UCHAR , int( offsetof( Point3D< unsigned char > , coords[2] ) ) , 0 , 0 , 0 , 0 } , |
| { "red" , PLY_UCHAR , PLY_UCHAR , int( offsetof( Point3D< unsigned char > , coords[0] ) ) , 0 , 0 , 0 , 0 } , |
| { "green" , PLY_UCHAR , PLY_UCHAR , int( offsetof( Point3D< unsigned char > , coords[1] ) ) , 0 , 0 , 0 , 0 } , |
| { "blue" , PLY_UCHAR , PLY_UCHAR , int( offsetof( Point3D< unsigned char > , coords[2] ) ) , 0 , 0 , 0 , 0 } |
| }; |
|
|
| bool ValidPlyColorProperties( const bool* props ){ return ( props[0] || props[3] ) && ( props[1] || props[4] ) && ( props[2] || props[5] ); } |
|
|
| template< class Real , int Degree , class Vertex > |
| int _Execute( int argc , char* argv[] ) |
| { |
| Reset< Real >(); |
| int paramNum = sizeof(params)/sizeof(cmdLineReadable*); |
| std::vector< char* > comments; |
|
|
| if( Verbose.set ) echoStdout=1; |
|
|
| XForm4x4< Real > xForm , iXForm; |
| if( XForm.set ) |
| { |
| FILE* fp = fopen( XForm.value , "r" ); |
| if( !fp ) |
| { |
| fprintf( stderr , "[WARNING] Could not read x-form from: %s\n" , XForm.value ); |
| xForm = XForm4x4< Real >::Identity(); |
| } |
| else |
| { |
| for( int i=0 ; i<4 ; i++ ) for( int j=0 ; j<4 ; j++ ) |
| { |
| float f; |
| if( fscanf( fp , " %f " , &f )!=1 ) fprintf( stderr , "[ERROR] Execute: Failed to read xform\n" ) , exit( 0 ); |
| xForm(i,j) = (Real)f; |
| } |
| fclose( fp ); |
| } |
| } |
| else xForm = XForm4x4< Real >::Identity(); |
| iXForm = xForm.inverse(); |
|
|
| DumpOutput2( comments , "Running Screened Poisson Reconstruction (Version 8.0)\n" ); |
| char str[1024]; |
| for( int i=0 ; i<paramNum ; i++ ) |
| if( params[i]->set ) |
| { |
| params[i]->writeValue( str ); |
| if( strlen( str ) ) DumpOutput2( comments , "\t--%s %s\n" , params[i]->name , str ); |
| else DumpOutput2( comments , "\t--%s\n" , params[i]->name ); |
| } |
|
|
| double t; |
| double tt=Time(); |
| Real isoValue = 0; |
|
|
| Octree< Real > tree; |
| tree.threads = Threads.value; |
| if( !In.set ) |
| { |
| ShowUsage( argv[0] ); |
| return 0; |
| } |
| if( !MaxSolveDepth.set ) MaxSolveDepth.value = Depth.value; |
|
|
| OctNode< TreeNodeData >::SetAllocator( MEMORY_ALLOCATOR_BLOCK_SIZE ); |
|
|
| t=Time(); |
| int kernelDepth = KernelDepth.set ? KernelDepth.value : Depth.value-2; |
| if( kernelDepth>Depth.value ) |
| { |
| fprintf( stderr,"[WARNING] %s can't be greater than %s: %d <= %d\n" , KernelDepth.name , Depth.name , KernelDepth.value , Depth.value ); |
| kernelDepth = Depth.value; |
| } |
|
|
| double maxMemoryUsage; |
| t=Time() , tree.maxMemoryUsage=0; |
| SparseNodeData< PointData< Real > , 0 >* pointInfo = new SparseNodeData< PointData< Real > , 0 >(); |
| SparseNodeData< Point3D< Real > , NORMAL_DEGREE >* normalInfo = new SparseNodeData< Point3D< Real > , NORMAL_DEGREE >(); |
| SparseNodeData< Real , WEIGHT_DEGREE >* densityWeights = new SparseNodeData< Real , WEIGHT_DEGREE >(); |
| SparseNodeData< Real , NORMAL_DEGREE >* nodeWeights = new SparseNodeData< Real , NORMAL_DEGREE >(); |
| int pointCount; |
| typedef typename Octree< Real >::template ProjectiveData< Point3D< Real > > ProjectiveColor; |
| SparseNodeData< ProjectiveColor , DATA_DEGREE >* colorData = NULL; |
|
|
| char* ext = GetFileExtension( In.value ); |
| if( Color.set && Color.value>0 ) |
| { |
| colorData = new SparseNodeData< ProjectiveColor , DATA_DEGREE >(); |
| OrientedPointStreamWithData< float , Point3D< unsigned char > >* pointStream; |
| if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryOrientedPointStreamWithData< float , Point3D< unsigned char > >( In.value ); |
| else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYOrientedPointStreamWithData< float , Point3D< unsigned char > >( In.value , PlyColorProperties , 6 , ValidPlyColorProperties ); |
| else pointStream = new ASCIIOrientedPointStreamWithData< float , Point3D< unsigned char > >( In.value , ReadASCIIColor ); |
| 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 ); |
| delete pointStream; |
|
|
| for( const OctNode< TreeNodeData >* n = tree.tree().nextNode() ; n!=NULL ; n=tree.tree().nextNode( n ) ) |
| { |
| int idx = colorData->index( n ); |
| if( idx>=0 ) colorData->data[idx] *= (Real)pow( Color.value , n->depth() ); |
| } |
| } |
| else |
| { |
| OrientedPointStream< float >* pointStream; |
| if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryOrientedPointStream< float >( In.value ); |
| else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYOrientedPointStream< float >( In.value ); |
| else pointStream = new ASCIIOrientedPointStream< float >( In.value ); |
| 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 ); |
| delete pointStream; |
| } |
| delete[] ext; |
| if( !Density.set ) delete densityWeights , densityWeights = NULL; |
| { |
| std::vector< int > indexMap; |
| if( NORMAL_DEGREE>Degree ) tree.template EnableMultigrid< NORMAL_DEGREE >( &indexMap ); |
| else tree.template EnableMultigrid< Degree >( &indexMap ); |
| if( pointInfo ) pointInfo->remapIndices( indexMap ); |
| if( normalInfo ) normalInfo->remapIndices( indexMap ); |
| if( densityWeights ) densityWeights->remapIndices( indexMap ); |
| if( nodeWeights ) nodeWeights->remapIndices( indexMap ); |
| if( colorData ) colorData->remapIndices( indexMap ); |
| } |
|
|
| DumpOutput2( comments , "# Tree set in: %9.1f (s), %9.1f (MB)\n" , Time()-t , tree.maxMemoryUsage ); |
| DumpOutput( "Input Points: %d\n" , pointCount ); |
| DumpOutput( "Leaves/Nodes: %d/%d\n" , tree.leaves() , tree.nodes() ); |
| DumpOutput( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage() )/(1<<20) ); |
|
|
| maxMemoryUsage = tree.maxMemoryUsage; |
| t=Time() , tree.maxMemoryUsage=0; |
| DenseNodeData< Real , Degree > constraints = tree.template SetLaplacianConstraints< Degree >( *normalInfo ); |
| delete normalInfo; |
| DumpOutput2( comments , "# Constraints set in: %9.1f (s), %9.1f (MB)\n" , Time()-t , tree.maxMemoryUsage ); |
| DumpOutput( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage())/(1<<20) ); |
| maxMemoryUsage = std::max< double >( maxMemoryUsage , tree.maxMemoryUsage ); |
|
|
| t=Time() , tree.maxMemoryUsage=0; |
| DenseNodeData< Real , Degree > solution = tree.SolveSystem( *pointInfo , constraints , ShowResidual.set , Iters.value , MaxSolveDepth.value , CGDepth.value , CSSolverAccuracy.value ); |
| delete pointInfo; |
| constraints.resize( 0 ); |
|
|
| DumpOutput2( comments , "# Linear system solved in: %9.1f (s), %9.1f (MB)\n" , Time()-t , tree.maxMemoryUsage ); |
| DumpOutput( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage() )/(1<<20) ); |
| maxMemoryUsage = std::max< double >( maxMemoryUsage , tree.maxMemoryUsage ); |
|
|
| CoredFileMeshData< Vertex > mesh; |
|
|
| if( Verbose.set ) tree.maxMemoryUsage=0; |
| t=Time(); |
| isoValue = tree.GetIsoValue( solution , *nodeWeights ); |
| delete nodeWeights; |
| DumpOutput( "Got average in: %f\n" , Time()-t ); |
| DumpOutput( "Iso-Value: %e\n" , isoValue ); |
|
|
| if( VoxelGrid.set ) |
| { |
| double t = Time(); |
| FILE* fp = fopen( VoxelGrid.value , "wb" ); |
| if( !fp ) fprintf( stderr , "Failed to open voxel file for writing: %s\n" , VoxelGrid.value ); |
| else |
| { |
| int res = 0; |
| Pointer( Real ) values = tree.Evaluate( solution , res , isoValue , VoxelDepth.value , PrimalVoxel.set ); |
| fwrite( &res , sizeof(int) , 1 , fp ); |
| if( sizeof(Real)==sizeof(float) ) fwrite( values , sizeof(float) , res*res*res , fp ); |
| else |
| { |
| float *fValues = new float[res*res*res]; |
| for( int i=0 ; i<res*res*res ; i++ ) fValues[i] = float( values[i] ); |
| fwrite( fValues , sizeof(float) , res*res*res , fp ); |
| delete[] fValues; |
| } |
| fclose( fp ); |
| DeletePointer( values ); |
| } |
| DumpOutput( "Got voxel grid in: %f\n" , Time()-t ); |
| } |
|
|
| if( Out.set ) |
| { |
| t = Time() , tree.maxMemoryUsage = 0; |
| tree.template GetMCIsoSurface< Degree , WEIGHT_DEGREE , DATA_DEGREE >( densityWeights , colorData , solution , isoValue , mesh , !LinearFit.set , !NonManifold.set , PolygonMesh.set ); |
| if( PolygonMesh.set ) DumpOutput2( comments , "# Got polygons in: %9.1f (s), %9.1f (MB)\n" , Time()-t , tree.maxMemoryUsage ); |
| else DumpOutput2( comments , "# Got triangles in: %9.1f (s), %9.1f (MB)\n" , Time()-t , tree.maxMemoryUsage ); |
| maxMemoryUsage = std::max< double >( maxMemoryUsage , tree.maxMemoryUsage ); |
| DumpOutput2( comments , "# Total Solve: %9.1f (s), %9.1f (MB)\n" , Time()-tt , maxMemoryUsage ); |
|
|
| if( NoComments.set ) |
| { |
| if( ASCII.set ) PlyWritePolygons( Out.value , &mesh , PLY_ASCII , NULL , 0 , iXForm ); |
| else PlyWritePolygons( Out.value , &mesh , PLY_BINARY_NATIVE , NULL , 0 , iXForm ); |
| } |
| else |
| { |
| if( ASCII.set ) PlyWritePolygons( Out.value , &mesh , PLY_ASCII , &comments[0] , (int)comments.size() , iXForm ); |
| else PlyWritePolygons( Out.value , &mesh , PLY_BINARY_NATIVE , &comments[0] , (int)comments.size() , iXForm ); |
| } |
| DumpOutput( "Vertices / Polygons: %d / %d\n" , mesh.outOfCorePointCount()+mesh.inCorePoints.size() , mesh.polygonCount() ); |
| } |
| solution.resize( 0 ); |
| if( colorData ){ delete colorData ; colorData = NULL; } |
| return 1; |
| } |
|
|
| #ifdef _WIN32 |
| inline double to_seconds( const FILETIME& ft ) |
| { |
| const double low_to_sec=100e-9; |
| const double high_to_sec=low_to_sec*4294967296.0; |
| return ft.dwLowDateTime*low_to_sec+ft.dwHighDateTime*high_to_sec; |
| } |
| #endif |
|
|
| template< class Real , class Vertex > |
| int Execute( int argc , char* argv[] ) |
| { |
| switch( Degree.value ) |
| { |
| case 1: return _Execute< Real , 1 , Vertex >( argc , argv ); |
| case 2: return _Execute< Real , 2 , Vertex >( argc , argv ); |
| case 3: return _Execute< Real , 3 , Vertex >( argc , argv ); |
| case 4: return _Execute< Real , 4 , Vertex >( argc , argv ); |
| default: |
| fprintf( stderr , "[ERROR] Only B-Splines of degree 1 - 4 are supported" ); |
| return EXIT_FAILURE; |
| } |
| } |
|
|
| } |
|
|
| int PoissonRecon( int argc , char* argv[] ) |
| { |
| #if defined(WIN32) && defined(MAX_MEMORY_GB) |
| if( MAX_MEMORY_GB>0 ) |
| { |
| SIZE_T peakMemory = 1; |
| peakMemory <<= 30; |
| peakMemory *= MAX_MEMORY_GB; |
| printf( "Limiting memory usage to %.2f GB\n" , float( peakMemory>>30 ) ); |
| HANDLE h = CreateJobObject( NULL , NULL ); |
| AssignProcessToJobObject( h , GetCurrentProcess() ); |
|
|
| JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 }; |
| jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_JOB_MEMORY; |
| jeli.JobMemoryLimit = peakMemory; |
| if( !SetInformationJobObject( h , JobObjectExtendedLimitInformation , &jeli , sizeof( jeli ) ) ) |
| fprintf( stderr , "Failed to set memory limit\n" ); |
| } |
| #endif |
| double t = Time(); |
|
|
| cmdLineParse( argc-1 , &argv[1] , sizeof(params)/sizeof(cmdLineReadable*) , params , 1 ); |
| if( Density.set ) |
| if( Color.set ) |
| if( Double.set ) Execute< double , PlyColorAndValueVertex< float > >( argc , argv ); |
| else Execute< float , PlyColorAndValueVertex< float > >( argc , argv ); |
| else |
| if( Double.set ) Execute< double , PlyValueVertex< float > >( argc , argv ); |
| else Execute< float , PlyValueVertex< float > >( argc , argv ); |
| else |
| if( Color.set ) |
| if( Double.set ) Execute< double , PlyColorVertex< float > >( argc , argv ); |
| else Execute< float , PlyColorVertex< float > >( argc , argv ); |
| else |
| if( Double.set ) Execute< double , PlyVertex< float > >( argc , argv ); |
| else Execute< float , PlyVertex< float > >( argc , argv ); |
| #ifdef _WIN32 |
| if( Performance.set ) |
| { |
| HANDLE cur_thread=GetCurrentThread(); |
| FILETIME tcreat, texit, tkernel, tuser; |
| if( GetThreadTimes( cur_thread , &tcreat , &texit , &tkernel , &tuser ) ) |
| printf( "Time (Wall/User/Kernel): %.2f / %.2f / %.2f\n" , Time()-t , to_seconds( tuser ) , to_seconds( tkernel ) ); |
| else printf( "Time: %.2f\n" , Time()-t ); |
| HANDLE h = GetCurrentProcess(); |
| PROCESS_MEMORY_COUNTERS pmc; |
| if( GetProcessMemoryInfo( h , &pmc , sizeof(pmc) ) ) printf( "Peak Memory (MB): %d\n" , pmc.PeakWorkingSetSize>>20 ); |
| } |
| #endif |
| return EXIT_SUCCESS; |
| } |
|
|