泊松表面重建中PoissonRecon.cpp源码分析

独学而无友,则孤陋而寡闻。深知独学的无奈,深知无友的感慨,所以个人将学习研究过程当中遇到的、学习到的东西分享出来,只为有志同道合的朋友互相交流,共同进步。
有一QQ群:285214996,希望汇聚所有这个领域的朋友,我们一起分享学习的快乐。

泊松表面重建中会PoissonRecon.cpp文件,下面是我个人在研究过程当中的分析过程,定有不当之处,还请指出。

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <math.h>
  4 #include <float.h>
  5 #ifdef _WIN32
  6 #include <Windows.h>
  7 #include <Psapi.h>
  8 #endif // _WIN32
  9 #include "Time.h"
 10 #include "MarchingCubes.h"
 11 #include "Octree.h"
 12 #include "SparseMatrix.h"
 13 #include "CmdLineParser.h"
 14 #include "PPolynomial.h"
 15 #include "Ply.h"
 16 #include "MemoryUsage.h"
 17 #include "omp.h"
 18 #include <stdarg.h>
 19
 20 char* outputFile=NULL;//将注释写入的文件路径
 21 int echoStdout=0;//控制是否在控制台显示,1显示,0不显示
 22
 23 /*
 24 将注释按照format的格式输出到文件中,并且根据echoStdout的值来选择是否将值输出到控制台
 25 */
 26 void DumpOutput( const char* format , ... )
 27 {
 28     if( outputFile )
 29     {
 30         FILE* fp = fopen( outputFile , "a" );
 31         va_list args;
 32         va_start( args , format );
 33         vfprintf( fp , format , args );
 34         fclose( fp );
 35         va_end( args );
 36     }
 37     if( echoStdout )
 38     {
 39         va_list args;
 40         va_start( args , format );
 41         vprintf( format , args );
 42         va_end( args );
 43     }
 44 }
 45
 46 /*
 47 将注释按照format的格式输出到文件中,且将注释写入到str中,并且根据echoStdout的值来选择是否将值输出到控制台
 48 */
 49 void DumpOutput2( char* str , const char* format , ... )
 50 {
 51     if( outputFile )
 52     {
 53         FILE* fp = fopen( outputFile , "a" );
 54         va_list args;
 55         va_start( args , format );
 56         vfprintf( fp , format , args );
 57         fclose( fp );
 58         va_end( args );
 59     }
 60     if( echoStdout )//输出到STDOUT(标准输出)
 61     {
 62         va_list args;
 63         va_start( args , format );
 64         vprintf( format , args );
 65         va_end( args );
 66     }
 67     va_list args;
 68     va_start( args , format );
 69     vsprintf( str , format , args );
 70     va_end( args );
 71     if( str[strlen(str)-1]==‘\n‘ ) str[strlen(str)-1] = 0;
 72 }
 73
 74 #include "MultiGridOctreeData.h"
 75 #ifdef MAX_MEMORY_GB
 76 #undef MAX_MEMORY_GB
 77 #endif // MAX_MEMORY_GB
 78 //#define MAX_MEMORY_GB 8
 79
 80 /*
 81 后面必须跟字符串,比如 --in bunny.points.ply
 82 */
 83 cmdLineString
 84     In( "in" ) ,
 85     Out( "out" ) ,
 86     VoxelGrid( "voxel" ) ,/*体素网格*/
 87     XForm( "xForm" );
 88
 89 /*
 90 直接使用,比如:--performance
 91 */
 92 cmdLineReadable
 93 #ifdef _WIN32
 94     Performance( "performance" ) ,//性能
 95 #endif // _WIN32
 96     ShowResidual( "showResidual" ) ,//显示剩余误差
 97     NoComments( "noComments" ) ,//无注释
 98     PolygonMesh( "polygonMesh" ) ,//多边形
 99     Confidence( "confidence" ) ,//置信度
100     NormalWeights( "normalWeight" ) ,//法向权重
101     NonManifold( "nonManifold" ) ,//非流形?
102     ASCII( "ascii" ) ,
103     Density( "density" ) ,//密度
104     Verbose( "verbose" );//冗余信息显示
105
106 /*
107 后面必须跟整型数字,比如:--depth 8
108 */
109 cmdLineInt
110     Depth( "depth" , 8 ) ,//深度
111     SolverDivide( "solverDivide" , 8 ) ,//解算深度
112     IsoDivide( "isoDivide" , 8 ) ,//等值面提取
113     KernelDepth( "kernelDepth" ) ,//核心深度
114     AdaptiveExponent( "adaptiveExp" , 1 ) ,//适应指数
115     MinIters( "minIters" , 24 ) ,//最小迭代
116     FixedIters( "iters" , -1 ) ,//修改的迭代?
117     VoxelDepth( "voxelDepth" , -1 ) ,//体素深度
118 #if 1
119 #ifdef _WIN32
120 #pragma message( "[WARNING] Setting default min-depth to 5" )
121 #endif // _WIN32
122     MinDepth( "minDepth" , 5 ) ,//最小深度
123 #else
124     MinDepth( "minDepth" , 0 ) ,
125 #endif
126     MaxSolveDepth( "maxSolveDepth" ) ,//最大解算深度
127     BoundaryType( "boundary" , 1 ) ,//边界
128     Threads( "threads" , omp_get_num_procs() );//线程数
129 /*
130 后面必须跟浮点型数字,比如:--samplesPerNode 1.f
131 */
132 cmdLineFloat
133     SamplesPerNode( "samplesPerNode" , 1.f ) ,//每个节点中的样本点个数
134     Scale( "scale" , 1.1f ) ,//尺度|规模
135     SolverAccuracy( "accuracy" , float(1e-3) ) ,//解算精度
136     PointWeight( "pointWeight" , 4.f );//点的权重
137
138 //预设参考命令
139 cmdLineReadable* params[] =
140 {
141     &In , &Depth , &Out , &XForm ,
142     &SolverDivide , &IsoDivide , &Scale , &Verbose , &SolverAccuracy , &NoComments ,
143     &KernelDepth , &SamplesPerNode , &Confidence , &NormalWeights , &NonManifold , &PolygonMesh , &ASCII , &ShowResidual , &MinIters , &FixedIters , &VoxelDepth ,
144     &PointWeight , &VoxelGrid , &Threads , &MinDepth , &MaxSolveDepth ,
145     &AdaptiveExponent , &BoundaryType ,
146     &Density ,
147 #ifdef _WIN32//windows特有的
148     &Performance ,
149 #endif // _WIN32
150 };
151
152
153 void ShowUsage(char* ex)
154 {
155     //printf( "Usage: %s\n" , ex );
156     printf( "用法: %s\n" , ex );//ex是可执行文件的绝对路径
157
158     //printf( "\t --%s  <input points>\n" , In.name );
159     printf( "\t --%s  <输入点集>\n" , In.name );
160
161     //printf( "\t[--%s <ouput triangle mesh>]\n" , Out.name );
162     printf( "\t[--%s <输出的三角形网格>]\n" , Out.name );
163
164     //printf( "\t[--%s <ouput voxel grid>]\n" , VoxelGrid.name );
165     printf( "\t[--%s <输出立体像素网格>]\n" , VoxelGrid.name );
166
167     //printf( "\t[--%s <maximum reconstruction depth>=%d]\n" , Depth.name , Depth.value );
168     printf( "\t[--%s <最大重建深度>=%d]\n" , Depth.name , Depth.value );
169
170     //printf( "\t\t Running at depth d corresponds to solving on a 2^d x 2^d x 2^d\n" );
171     //printf( "\t\t voxel grid.\n" );
172     printf( "\t\t 在深度d运行对应的解为2^d x 2^d x 2^d个体素网格\n" );
173
174     //printf( "\t[--%s <depth at which to extract the voxel grid>=<%s>]\n" , VoxelDepth.name , Depth.name );
175     printf( "\t[--%s <提取体素网格的深度>=<%s>]\n" , VoxelDepth.name , Depth.name );
176
177     //printf( "\t[--%s <scale factor>=%f]\n" , Scale.name , Scale.value );
178     printf( "\t[--%s <比例因子>=%f]\n" , Scale.name , Scale.value );
179
180     //printf( "\t\t Specifies the factor of the bounding cube that the input\n" );
181     //printf( "\t\t samples should fit into.\n" );
182     printf( "\t\t 指定应该拟合的输入样本点的边界立方体的系数\n" );
183
184     //printf( "\t[--%s <subdivision depth>=%d]\n" , SolverDivide.name , SolverDivide.value );
185     printf( "\t[--%s <解算器细分深度>=%d]\n" , SolverDivide.name , SolverDivide.value );
186
187     //printf( "\t\t The depth at which a block Gauss-Seidel solver is used\n");
188     //printf( "\t\t to solve the Laplacian.\n");
189     printf( "\t\t 用于求解拉普拉斯的阻塞高斯-塞德尔求解器深度\n");
190
191     //printf( "\t[--%s <minimum number of samples per node>=%f]\n" , SamplesPerNode.name, SamplesPerNode.value );
192     //printf( "\t\t This parameter specifies the minimum number of points that\n" );
193     //printf( "\t\t should fall within an octree node.\n" );
194     printf( "\t[--%s <每个节点样本点的最小数目>=%f]\n" , SamplesPerNode.name, SamplesPerNode.value );
195     printf( "\t\t 此参数指定了应该落在一个八叉树节点内点的最小数目\n" );
196
197     //printf( "\t[--%s <num threads>=%d]\n" , Threads.name , Threads.value );
198     //printf( "\t\t This parameter specifies the number of threads across which\n" );
199     //printf( "\t\t the solver should be parallelized.\n" );
200     printf( "\t[--%s <线程数>=%d]\n" , Threads.name , Threads.value );
201     printf( "\t\t 此参数指定横过其求解器应并行的线程数\n" );
202
203     //printf( "\t[--%s]\n" , Confidence.name );
204     //printf( "\t\t If this flag is enabled, the size of a sample‘s normals is\n" );
205     //printf( "\t\t used as a confidence value, affecting the sample‘s\n" );
206     //printf( "\t\t constribution to the reconstruction process.\n" );
207     printf( "\t[--%s]\n" , Confidence.name );
208     printf( "\t\t 如果这个标志被启用,样品法线的大小用作一个置信度值,影响到重建\n" );
209     printf( "\t\t 过程中样品的贡献\n" );
210
211     //printf( "\t[--%s]\n" , NormalWeights.name );
212     //printf( "\t\t If this flag is enabled, the size of a sample‘s normals is\n" );
213     //printf( "\t\t used as to modulate the interpolation weight.\n" );
214     printf( "\t[--%s]\n" , NormalWeights.name );
215     printf( "\t\t 如果这个标志被启用,样品的法线的大小用来调节内插权重\n" );
216
217     //printf( "\t[--%s]\n" , NonManifold.name );
218     //printf( "\t\t If this flag is enabled, the isosurface extraction does not add\n" );
219     //printf( "\t\t a planar polygon‘s barycenter in order to ensure that the output\n" );
220     //printf( "\t\t mesh is manifold.\n" );
221     printf( "\t[--%s]\n" , NonManifold.name );
222     printf( "\t\t 如果这个标志被启用,提取等值面不会添加一个平面多边形的重心,以\n" );
223     printf( "\t\t 确保输出网格是多方面的\n" );
224
225     //printf( "\t[--%s]\n" , PolygonMesh.name);
226     //printf( "\t\t If this flag is enabled, the isosurface extraction returns polygons\n" );
227     //printf( "\t\t rather than triangles.\n" );
228     printf( "\t[--%s]\n" , PolygonMesh.name);
229     printf( "\t\t 等值面提取返回的是多边形,而不是三角形\n" );
230
231     //printf( "\t[--%s <interpolation weight>=%f]\n" , PointWeight.name , PointWeight.value );
232     //printf( "\t\t This value specifies the weight that point interpolation constraints are\n" );
233     //printf( "\t\t given when defining the (screened) Poisson system.\n" );
234     printf( "\t[--%s <插值权重>=%f]\n" , PointWeight.name , PointWeight.value );
235     printf( "\t\t 此值指定当定义(屏蔽)泊松系统时,给定点插值约束的权重\n" );
236
237     //printf( "\t[--%s <minimum depth>=%d]\n" , MinDepth.name , MinDepth.value );
238     //printf( "\t\t This flag specifies the minimum depth at which the octree is to be adaptive.\n" );
239     printf( "\t[--%s <最小深度>=%d]\n" , MinDepth.name , MinDepth.value );
240     printf( "\t\t 此标志指定的是八叉树要适应的最小深度\n" );
241
242     //printf( "\t[--%s <solver accuracy>=%g]\n" , SolverAccuracy.name , SolverAccuracy.value );
243     //printf( "\t[--%s <minimum number of solver iterations>=%d]\n" , MinIters.name , MinIters.value );
244     printf( "\t[--%s <解算精度>=%g]\n" , SolverAccuracy.name , SolverAccuracy.value );
245     printf( "\t[--%s <迭代求解器的最小数目>=%d]\n" , MinIters.name , MinIters.value );
246
247     //printf( "\t[--%s <adaptive weighting exponent>=%d]\n", AdaptiveExponent.name , AdaptiveExponent.value );
248     //printf( "\t\t This flag specifies the exponent scale for the adaptive weighting.\n" );
249     printf( "\t[--%s <自适应加权指数>=%d]\n", AdaptiveExponent.name , AdaptiveExponent.value );
250     printf( "\t\t 此标志指定自适应加权的指数规模\n" );
251
252 #ifdef _WIN32
253     //printf( "\t[--%s]\n" , Performance.name );
254     //printf( "\t\t If this flag is enabled, the running time and peak memory usage\n" );
255     //printf( "\t\t is output after the reconstruction.\n" );
256     printf( "\t[--%s]\n" , Performance.name );
257     printf( "\t\t 如果这个标志启用后,运行时间和峰值内存使用量在重建后输出\n" );
258 #endif // _WIN32
259     printf( "\t[--%s]\n" , Density.name );
260     printf( "\t[--%s]\n" , ASCII.name );
261     //printf( "\t\t If this flag is enabled, the output file is written out in ASCII format.\n" );
262     printf( "\t\t 如果这个标志启用,输出文件会以ASCII的格式写入\n" );
263
264     printf( "\t[--%s]\n" , NoComments.name );
265     //printf( "\t\t If this flag is enabled, the output file will not include comments.\n" );
266     printf( "\t\t 如果这个标志启用,输出文件将不包括注释\n" );
267
268     printf( "\t[--%s]\n" , Verbose.name );
269     //printf( "\t\t If this flag is enabled, the progress of the reconstructor will be output to STDOUT.\n" );
270     printf( "\t\t 如果这个标志启用,重构的进度将被输出到STDOUT\n" );
271 }
272
273 /*
274 Degree:维度
275 Vertex:顶点
276 OutputDensity:输出密度
277 */
278 template< int Degree , class Vertex , bool OutputDensity >
279 int Execute( int argc , char* argv[] )
280 {
281     int i;
282     int paramNum = sizeof(params)/sizeof(cmdLineReadable*);//预设命令数组params中命令参数的个数
283     int commentNum=0;//注释个数
284     char **comments;//“注释”变量,comments是一个指针1,指针指向了指针2,指针2指向了char,指针类型是4个字节
285
286     //“注释”初始化,有参数可以控制是否输出注释
287     comments = new char*[paramNum+7];//为什么加7?_201405042113
288     for( i=0 ; i<paramNum+7 ; i++ ) comments[i] = new char[1024];
289
290     if( Verbose.set ) echoStdout=1;//判断是否输出到控制台,Verbose.set为TRUE时输出到控制台
291
292     /**
293       *读取定义的XForm4x4矩阵,如果读取失败直接定义4x4单位矩阵否则直接读取定义的值,如果没有设置直接定义4x4单位矩阵,最后求逆矩阵
294       */
295     XForm4x4< Real > xForm , iXForm;
296     if( XForm.set )
297     {
298         FILE* fp = fopen( XForm.value , "r" );//只读
299         if( !fp )
300         {
301             fprintf( stderr , "[WARNING] Could not read x-form from: %s\n" , XForm.value );
302             xForm = XForm4x4< Real >::Identity();//4x4单位矩阵
303         }
304         else
305         {
306             for( int i=0 ; i<4 ; i++ ) for( int j=0 ; j<4 ; j++ ) fscanf( fp , " %f " , &xForm( i , j ) );
307             fclose( fp );
308         }
309     }
310     else xForm = XForm4x4< Real >::Identity();//4x4单位矩阵
311     iXForm = xForm.inverse();//4x4单位矩阵的逆矩阵
312
313     /*
314     写入文件是肯定的,是否输出到控制台根据echoStdout是否为1判断,同时写入到comments[commentNum++]中
315     */
316     DumpOutput2( comments[commentNum++] , "屏蔽泊松表面重建(版本 5.71)\n" );
317     char str[1024];
318     /*
319     将成功设定过的命令输出到控制台,如果有参数同时输出
320     */
321     for( int i=0 ; i<paramNum ; i++ )
322         if( params[i]->set )//如果参数被设定过则执行这一步
323         {
324             params[i]->writeValue( str );//将值写入到str中
325             if( strlen( str ) ) DumpOutput2( comments[commentNum++] , "\t--%s %s\n" , params[i]->name , str );//判断str中值得长度,如果有值即strlen(str)!=0则将参数名称连同值一起输出
326             else                DumpOutput2( comments[commentNum++] , "\t--%s\n" , params[i]->name );//否则只输出参数名称
327         }
328
329     double t;
330     double tt=Time();
331     Real isoValue = 0;
332
333     /*
334     八叉树结构Octree
335     此处是为了获取可用线程数
336     */
337     Octree< Degree , OutputDensity > tree;
338     tree.threads = Threads.value;//使用OpenMP来获取线程数
339     //判断in是否设定过,没有设定过则输出可执行文件的绝对路径及文件名.扩展名
340     if( !In.set )
341     {
342         ShowUsage(argv[0]);
343         return 0;
344     }
345     /*
346     最大解算深度MaxSolveDepth初始化时没有设置,如果在输入的命令行参数中也没有指定则将Depth.value的默认值8赋给MaxSolveDepth.value
347     */
348     if( !MaxSolveDepth.set ) MaxSolveDepth.value = Depth.value;
349     /*
350     解算深度SolverDivide.value默认8
351     最小深度MinDepth.value默认5
352     如果解算深度小于最小深度则给出提示,将最小深度的值赋给解算深度
353     */
354     if( SolverDivide.value<MinDepth.value )//解算器的深度应>=最小深度
355     {
356         fprintf( stderr , "[WARNING] %s must be at least as large as %s: %d>=%d\n" , SolverDivide.name , MinDepth.name , SolverDivide.value , MinDepth.value );
357         SolverDivide.value = MinDepth.value;
358     }
359     /*
360     等值面提取深度默认为8
361     等值面提取深度应大于等于最小深度
362     如果小于最小深度则将最小深度的值赋给等值面提取深度
363     */
364     if( IsoDivide.value<MinDepth.value )//等值提取的深度应>=最小深度
365     {
366         fprintf( stderr , "[WARNING] %s must be at least as large as %s: %d>=%d\n" , IsoDivide.name , MinDepth.name , IsoDivide.value , IsoDivide.value );
367         IsoDivide.value = MinDepth.value;
368     }
369
370     /**201406231802
371       *八叉树节点OctNode
372       *给八叉树节点分配空间大小为MEMORY_ALLOCATOR_BLOCK_SIZE
373       *此处只是告知大小,但是没有具体分配空间,只是一个参数的设定而已,没有具体什么动作或操作
374       */
375     OctNode< TreeNodeData< OutputDensity > , Real >::SetAllocator( MEMORY_ALLOCATOR_BLOCK_SIZE );
376
377     t=Time();
378     /**201406252155
379       *设定kernerDepth,如果设定过,就取设定的值,否则取Depth.value得默认值然后减去2
380       */
381     int kernelDepth = KernelDepth.set ?  KernelDepth.value : Depth.value-2;//为什么是减去2?201405042147
382
383     /*201406252156
384     设置B样条数据
385     输入:
386     Depth.value:最大深度
387     BoundaryType.value:边界类型
388     理解不透彻
389     */
390     tree.setBSplineData( Depth.value , BoundaryType.value );//201405052103
391     /**201406252157
392       *检测刚才设定的kernelDepth是否合理,理论上应该小于Depth.value默认值8
393       *否则报错
394       */
395     if( kernelDepth>Depth.value )
396     {
397         fprintf( stderr,"[ERROR] %s can‘t be greater than %s: %d <= %d\n" , KernelDepth.name , Depth.name , KernelDepth.value , Depth.value );
398         return EXIT_FAILURE;
399     }
400
401     double maxMemoryUsage;
402     t=Time() , tree.maxMemoryUsage=0;
403     /**201406261717
404       *输入
405       *输出
406       */
407     int pointCount = tree.setTree( In.value , Depth.value , MinDepth.value , kernelDepth , Real(SamplesPerNode.value) , Scale.value , Confidence.set , NormalWeights.set , PointWeight.value , AdaptiveExponent.value , xForm );
408     tree.ClipTree();//201405042200
409     tree.finalize( IsoDivide.value );
410
411     DumpOutput2( comments[commentNum++] , "#             Tree set in: %9.1f (s), %9.1f (MB)\n" , Time()-t , tree.maxMemoryUsage );
412     DumpOutput( "Input Points: %d\n" , pointCount );
413     DumpOutput( "Leaves/Nodes: %lld/%lld\n" , tree.tree.leaves() , tree.tree.nodes() );
414     DumpOutput( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage() )/(1<<20) );
415
416     maxMemoryUsage = tree.maxMemoryUsage;
417     t=Time() , tree.maxMemoryUsage=0;
418     /*
419     201406281151
420     设置拉普拉斯约束
421     这里有OpenMP的并行
422     */
423     tree.SetLaplacianConstraints();//201406071814
424     DumpOutput2( comments[commentNum++] , "#      Constraints set in: %9.1f (s), %9.1f (MB)\n" , Time()-t , tree.maxMemoryUsage );
425     DumpOutput( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage())/(1<<20) );
426     maxMemoryUsage = std::max< double >( maxMemoryUsage , tree.maxMemoryUsage );
427
428     t=Time() , tree.maxMemoryUsage=0;
429     /*
430     201406281154
431     设置拉普拉斯矩阵迭代
432     输入:
433     SolverDivide:解算深度
434     ShowResidual:显示剩余误差
435     MinTters:最小迭代
436     SolverAccuracy:解算精度
437     MaxSolveDepth:最大解算深度
438     FixedIters:修改的迭代,此处值为-1
439     */
440     tree.LaplacianMatrixIteration( SolverDivide.value, ShowResidual.set , MinIters.value , SolverAccuracy.value , MaxSolveDepth.value , FixedIters.value );
441     DumpOutput2( comments[commentNum++] , "# 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) );//单位为MB,2的10次方是1k,2的20次方是1M
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     /*
450     201406281158
451     这里有OpenMP并行
452     */
453     isoValue = tree.GetIsoValue();
454     DumpOutput( "Got average in: %f\n" , Time()-t );
455     DumpOutput( "Iso-Value: %e\n" , isoValue );
456
457     if( VoxelGrid.set )
458     {
459         double t = Time();
460         FILE* fp = fopen( VoxelGrid.value , "wb" );
461         if( !fp ) fprintf( stderr , "Failed to open voxel file for writing: %s\n" , VoxelGrid.value );
462         else
463         {
464             int res;
465             /*
466             201406281201
467             GetSolutionGrid获取网格
468             */
469             Pointer( Real ) values = tree.GetSolutionGrid( res , isoValue , VoxelDepth.value );
470             fwrite( &res , sizeof(int) , 1 , fp );
471             if( sizeof(Real)==sizeof(float) ) fwrite( values , sizeof(float) , res*res*res , fp );
472             else
473             {
474                 float *fValues = new float[res*res*res];
475                 for( int i=0 ; i<res*res*res ; i++ ) fValues[i] = float( values[i] );
476                 fwrite( fValues , sizeof(float) , res*res*res , fp );
477                 delete[] fValues;
478             }
479             fclose( fp );
480             DeletePointer( values );
481         }
482         DumpOutput( "Got voxel grid in: %f\n" , Time()-t );
483     }
484
485     if( Out.set )
486     {
487         t = Time() , tree.maxMemoryUsage = 0;
488         /*
489         201406281203
490         GetMCIsoTriangles此处有OpenMP并行
491         */
492         tree.GetMCIsoTriangles( isoValue , IsoDivide.value , &mesh , 0 , 1 , !NonManifold.set , PolygonMesh.set );
493         if( PolygonMesh.set ) DumpOutput2( comments[commentNum++] , "#         Got polygons in: %9.1f (s), %9.1f (MB)\n" , Time()-t , tree.maxMemoryUsage );
494         else                  DumpOutput2( comments[commentNum++] , "#        Got triangles in: %9.1f (s), %9.1f (MB)\n" , Time()-t , tree.maxMemoryUsage );
495         maxMemoryUsage = std::max< double >( maxMemoryUsage , tree.maxMemoryUsage );
496         DumpOutput2( comments[commentNum++],"#             Total Solve: %9.1f (s), %9.1f (MB)\n" , Time()-tt , maxMemoryUsage );
497
498         if( NoComments.set )
499         {
500             if( ASCII.set ) PlyWritePolygons( Out.value , &mesh , PLY_ASCII         , NULL , 0 , iXForm );
501             else            PlyWritePolygons( Out.value , &mesh , PLY_BINARY_NATIVE , NULL , 0 , iXForm );
502         }
503         else
504         {
505             if( ASCII.set ) PlyWritePolygons( Out.value , &mesh , PLY_ASCII         , comments , commentNum , iXForm );
506             else            PlyWritePolygons( Out.value , &mesh , PLY_BINARY_NATIVE , comments , commentNum , iXForm );
507         }
508     }
509
510     return 1;
511 }
512
513 #ifdef _WIN32
514 inline double to_seconds( const FILETIME& ft )
515 {
516     const double low_to_sec=100e-9; // 100 nanoseconds
517     const double high_to_sec=low_to_sec*4294967296.0;// 2^32 = 4294967296
518     return ft.dwLowDateTime*low_to_sec+ft.dwHighDateTime*high_to_sec;
519 }
520 #endif // _WIN32
521
522 /*
523 201406231200
524 *搞清楚每个函数的输入输出都是什么,还有完成了什么功能
525 *执行思路:
526 *获取命令行参数=cmdLineParse
527 *根据设置的参数执行=Execute
528 **/
529 int main( int argc , char* argv[] )
530 {
531 #if defined(WIN32) && defined(MAX_MEMORY_GB)
532     if( MAX_MEMORY_GB>0 )
533     {
534         SIZE_T peakMemory = 1;
535         peakMemory <<= 30;
536         peakMemory *= MAX_MEMORY_GB;
537         printf( "Limiting memory usage to %.2f GB\n" , float( peakMemory>>30 ) );
538         HANDLE h = CreateJobObject( NULL , NULL );
539         AssignProcessToJobObject( h , GetCurrentProcess() );
540
541         JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
542         jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_JOB_MEMORY;
543         jeli.JobMemoryLimit = peakMemory;
544         if( !SetInformationJobObject( h , JobObjectExtendedLimitInformation , &jeli , sizeof( jeli ) ) )
545             fprintf( stderr , "Failed to set memory limit\n" );
546     }
547 #endif // defined(WIN32) && defined(MAX_MEMORY_GB)
548     double t = Time();
549
550     /*
551     201406231200
552     argc-1是除掉函数自身的名\***\***\bmcj.exe之外的参数总个数,位置从其后开始,
553     params中的内容为预定义的可选参数,1是指定是否在有错的情况下输出错误提示,有1时输出
554     输出:无输出
555     如果参数后面有值则设置set为TRUE并将值存放在对应的value中,这个是由重写的cmdLineReadable::read函数完成的
556     */
557     cmdLineParse( argc-1 , &argv[1] , sizeof(params)/sizeof(cmdLineReadable*) , params , 1 );//命令后面的值都存放在value中
558     /*
559     201406231200
560     函数Execute的输入和输出都是什么
561     */
562     if( Density.set ) Execute< 2 , PlyValueVertex< Real > , true  >( argc , argv );//启用Density.set以告诉重构器输出等值面的顶点的深度估计信息
563     else              Execute< 2 ,      PlyVertex< Real > , false >( argc , argv );
564 #ifdef _WIN32
565     if( Performance.set )
566     {
567         HANDLE cur_thread=GetCurrentThread();//获取当前线程的一个伪句柄
568         FILETIME tcreat, texit, tkernel, tuser;
569         if( GetThreadTimes( cur_thread , &tcreat , &texit , &tkernel , &tuser ) )//获取与一个线程的经过时间有关的信息,返回值非零表示成功
570             printf( "Time (墙钟时间(Wall)/用户模式消耗总时间(User)/内核模式消耗的总时间(Kernel)): %.2f / %.2f / %.2f\n" , Time()-t , to_seconds( tuser ) , to_seconds( tkernel ) );
571         else printf( "Time: %.2f\n" , Time()-t );
572         HANDLE h = GetCurrentProcess();//获取当前进程的一个伪句柄
573         PROCESS_MEMORY_COUNTERS pmc;
574         if( GetProcessMemoryInfo( h , &pmc , sizeof(pmc) ) ) printf( "内存峰值-Peak Memory (MB): %d\n" , pmc.PeakWorkingSetSize>>20 );
575     }
576 #endif // _WIN32
577     return EXIT_SUCCESS;
578 }

也可通过下方的邮件联系我,相互交流。

时间: 2024-07-30 19:45:05

泊松表面重建中PoissonRecon.cpp源码分析的相关文章

Django中CBV和Restful API中的APIView源码分析

Django中CBV和Restful API中的APIView源码分析 python的Django框架的视图处理可以用FBV, 也可以采用CBV.首先定义一个CBV视图: from django.views import Viewfrom django.http import JsonResponseclass Book(View):    def get(self, request):        ll = [{'key':value}]        return JsonResponse

Spring中Bean命名源码分析

Spring中Bean命名源码分析 一.案例代码 首先是demo的整体结构 其次是各个部分的代码,代码本身比较简单,不是我们关注的重点 配置类 /** * @Author Helius * @Create 2019-10-25-20:16 */ @Configuration @ComponentScan(basePackages = {"service"}) public class SpringConfiguration { } 接口的实现类 public interface Use

Netty中的ChannelPipeline源码分析

ChannelPipeline在Netty中是用来处理请求的责任链,默认实现是DefaultChannelPipeline,其构造方法如下: 1 private final Channel channel; 2 private final ChannelFuture succeededFuture; 3 private final VoidChannelPromise voidPromise; 4 final AbstractChannelHandlerContext head; 5 final

【朝花夕拾】Android自定义View篇之(六)Android事件分发机制(中)从源码分析事件分发逻辑及经常遇到的一些“诡异”现象

前言 转载请注明,转自[https://www.cnblogs.com/andy-songwei/p/11039252.html]谢谢! 在上一篇文章[[朝花夕拾]Android自定义View篇之(五)Android事件分发机制(上)Touch三个重要方法的处理逻辑][下文简称(五),请先阅读完(五)再阅读本文],我们通过示例和log来分析了Android的事件分发机制.这些,我们只是看到了现象,如果要进一步了解事件分发机制,这是不够的,我们还需要透过现象看本质,去研究研究源码.本文将从源码(基

JDK1.7 中的HashMap源码分析

一.源码地址: 源码地址:http://docs.oracle.com/javase/7/docs/api/ 二.数据结构 JDK1.7中采用数组+链表的形式,HashMap是一个Entry<K,V>[] table数组,JDK1.8采用数组+链表/红黑树实现,当链表长度超过阈值,将链表转为红黑树. Entry代码如下: /** Entry是单向链表. * 它是 “HashMap链式存储法”对应的链表. *它实现了Map.Entry 接口,即实现getKey(), getValue(), se

avalon 中require.config源码分析

/********************************************************************* * 配置系统 在系统运行的开始就需要读取系统中require.config()这个方法中所配置的项目 * **********************************************************************/ //这里写在前面是为了更加方便阅读代码,在实际运行中,这几段代码必须放在下面 kernel.debug =

Java并发编程中线程池源码分析及使用

当Java处理高并发的时候,线程数量特别的多的时候,而且每个线程都是执行很短的时间就结束了,频繁创建线程和销毁线程需要占用很多系统的资源和时间,会降低系统的工作效率. 参考http://www.cnblogs.com/dolphin0520/p/3932921.html 由于原文作者使用的API 是1.6 版本的,参考他的文章,做了一些修改成 jdk 1.8版本的方法,涉及到的内容比较多,可能有少许错误. API : jdk1.8.0_144 ThreadPoolExecutor类 Java中线

泊松表面重建中主函数中部分代码分析-关于内存设置

1 //总体来看是和内存设置有关的 2 #if defined(WIN32) && defined(MAX_MEMORY_GB) 3 if( MAX_MEMORY_GB>0 ) 4 { 5 //SIZE_T是ULONG_PTR类型又是unsigned __int64类型取值范围为2到2的64次方,貌似和64为操作系统支持的理论内存值有关系 6 SIZE_T peakMemory = 1; 7 peakMemory <<= 30;//peakMemory等于peakMemo

jquery中的globalEval()源码分析

//20170724 huanhua 定义成全局的变量 // 在谷歌浏览器下运行的: // function fun(){ eval('var a=1'); } 此时 定义的 a 就是局部的变量 // function fun(){ var val=eval; val('var a=1'); } 此时定义的 a 就是全局变量 globalEval: function( data ) { if ( data && jQuery.trim( data ) ) { // We use execS