| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #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; |
| | } |
| |
|