From a2d7666b3e4d5b181c6e45ed901af345984c1bbc Mon Sep 17 00:00:00 2001 From: "DESKTOP-P4IRLQG\\mkazh" Date: Sun, 13 May 2018 21:39:47 -0400 Subject: [PATCH] no message --- AdaptiveSolvers.sln | 1 + README.md | 8 +- Src/AdaptiveTreeVisualization.cpp | 10 +- Src/EDTInHeat.cpp | 2 +- Src/FEMTree.IsoSurface.specialized.inl | 56 +-- Src/FEMTree.h | 5 +- Src/FEMTree.inl | 2 +- Src/Ply.h | 515 +++++++------------- Src/PlyFile.cpp | 10 +- Src/PlyFile.h | 220 +++++++++ Src/PointStream.h | 34 +- Src/PointStream.inl | 47 +- Src/PointStreamData.h | 636 ++++++++++++++++--------- Src/PoissonRecon.cpp | 237 +++++---- Src/SSDRecon.cpp | 226 +++++---- Src/SurfaceTrimmer.cpp | 59 ++- 16 files changed, 1218 insertions(+), 850 deletions(-) create mode 100644 Src/PlyFile.h diff --git a/AdaptiveSolvers.sln b/AdaptiveSolvers.sln index e7fe8ca..6b4486e 100644 --- a/AdaptiveSolvers.sln +++ b/AdaptiveSolvers.sln @@ -41,6 +41,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Header Files", "Header File Src\MAT.h = Src\MAT.h Src\MyMiscellany.h = Src\MyMiscellany.h Src\Ply.h = Src\Ply.h + Src\PlyFile.h = Src\PlyFile.h Src\PointStream.h = Src\PointStream.h Src\PointStreamData.h = Src\PointStreamData.h Src\Polynomial.h = Src\Polynomial.h diff --git a/README.md b/README.md index 6578cc8..51082de 100644 --- a/README.md +++ b/README.md @@ -738,12 +738,18 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • Added a parameter for specifying the temporary directory.
  • -Version 10.00: +Version 10.00:
    1. The code has been reworked to support arbitrary dimensions, finite elements of arbitrary degree, generally SPD systems in the evaluated/integrated values and derivatives of the functions, etc.
    2. For the reconstruction code, added the --width flag which allows the system to compute the depth of the octree given a target depth for the finest resolution nodes.
    3. For the reconstruction code, fixed a bug in the handling of the confidence encoded in the lengths of the normals. In addition, added the flags --confidence and --confidenceBias which allow the user more control of how confidence is used to affect the contribution of a sample.
    + +Version 10.01: +
      +
    1. Modified the reconstruction code to facilitate interpolation of other input-sample quantities, in addition to color.
    2. +
    + diff --git a/Src/AdaptiveTreeVisualization.cpp b/Src/AdaptiveTreeVisualization.cpp index 99cf509..895af5f 100644 --- a/Src/AdaptiveTreeVisualization.cpp +++ b/Src/AdaptiveTreeVisualization.cpp @@ -37,6 +37,7 @@ DAMAGE. #include "PPolynomial.h" #include "FEMTree.h" #include "Ply.h" +#include "PointStreamData.h" cmdLineParameter< char* > In( "in" ) , @@ -137,15 +138,16 @@ void _Execute( const FEMTree< Dim , Real >* tree , FILE* fp ) // Output the mesh if( OutMesh.set ) { - CoredFileMeshData< PlyVertex< float , Dim > > mesh; double t = Time(); - IsoSurfaceExtractor< Dim , Real , PlyVertex< float , Dim > >::template Extract< Point< Real , 3 > >( IsotropicUIntPack< Dim , FEMSig >() , UIntPack< 0 >() , UIntPack< FEMTrivialSignature >() , *tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , NULL , coefficients , IsoValue.value , mesh , []( PlyVertex< float , Dim >& , Real ){;} , []( PlyVertex< float , Dim >& , Point< Real , 3 > ){;} , NonLinearFit.set , !NonManifold.set , PolygonMesh.set , FlipOrientation.set ); + typedef PlyVertex< Real , Dim > Vertex; + CoredFileMeshData< Vertex > mesh; + std::function< void ( Vertex& , Point< Real , Dim > , Real , Real ) > SetVertex = []( Vertex& v , Point< Real , Dim > p , Real , Real ){ v.point = p; }; + IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< Real >( IsotropicUIntPack< Dim , FEMSig >() , UIntPack< 0 >() , UIntPack< FEMTrivialSignature >() , *tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , NULL , coefficients , IsoValue.value , mesh , SetVertex , NonLinearFit.set , !NonManifold.set , PolygonMesh.set , FlipOrientation.set ); if( Verbose.set ) printf( "Got iso-surface: %.2f(s)\n" , Time()-t ); if( Verbose.set ) printf( "Vertices / Polygons: %d / %d\n" , (int)( mesh.outOfCorePointCount()+mesh.inCorePoints.size() ) , (int)mesh.polygonCount() ); - if( ASCII.set ) PlyWritePolygons< PlyVertex< float , Dim > , Real , Dim >( OutMesh.value , &mesh , PLY_ASCII , NULL , 0 , XForm< Real , Dim+1 >::Identity() ); - else PlyWritePolygons< PlyVertex< float , Dim > , Real , Dim >( OutMesh.value , &mesh , PLY_BINARY_NATIVE , NULL , 0 , XForm< Real , Dim+1 >::Identity() ); + PlyWritePolygons< Vertex , Real , Dim >( OutMesh.value , &mesh , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , NULL , 0 , XForm< Real , Dim+1 >::Identity() ); } } diff --git a/Src/EDTInHeat.cpp b/Src/EDTInHeat.cpp index 5509fa3..42f5b0f 100644 --- a/Src/EDTInHeat.cpp +++ b/Src/EDTInHeat.cpp @@ -271,7 +271,7 @@ int _Execute( int argc , char* argv[] ) int file_type; std::vector< PlyVertex< float , Dim > > _vertices; std::vector< std::vector< int > > _polygons; - PlyReadPolygons( In.value , _vertices , _polygons , PlyVertex< float , Dim >::Properties() , PlyVertex< float , Dim >::ReadComponents , file_type ); + PlyReadPolygons( In.value , _vertices , _polygons , PlyVertex< float , Dim >::PlyReadProperties() , PlyVertex< float , Dim >::PlyReadNum , file_type ); vertices.resize( _vertices.size() ); for( int i=0 ; i - static void _SetSliceIsoVertices( const FEMTree< Dim , Real >& tree , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , int slice , int& vOffset , CoredMeshData< Vertex >& mesh , std::vector< _SlabValues >& slabValues , std::function< void ( Vertex& , Real ) > SetVertexDepth , std::function< void ( Vertex& , Data ) > SetVertexData ) + static void _SetSliceIsoVertices( const FEMTree< Dim , Real >& tree , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , int slice , int& vOffset , CoredMeshData< Vertex >& mesh , std::vector< _SlabValues >& slabValues , std::function< void ( Vertex& , Point< Real , Dim > , Real , Data ) > SetVertex ) { - if( slice>0 ) _SetSliceIsoVertices< WeightDegree , Data , DataSig >( tree , pointEvaluator , densityWeights , data , isoValue , depth , slice , HyperCube::FRONT , vOffset , mesh , slabValues , SetVertexDepth , SetVertexData ); - if( slice<(1<( tree , pointEvaluator , densityWeights , data , isoValue , depth , slice , HyperCube::BACK , vOffset , mesh , slabValues , SetVertexDepth , SetVertexData ); + if( slice>0 ) _SetSliceIsoVertices< WeightDegree , Data , DataSig >( tree , pointEvaluator , densityWeights , data , isoValue , depth , slice , HyperCube::FRONT , vOffset , mesh , slabValues , SetVertex ); + if( slice<(1<( tree , pointEvaluator , densityWeights , data , isoValue , depth , slice , HyperCube::BACK , vOffset , mesh , slabValues , SetVertex ); } template< unsigned int WeightDegree , typename Data , unsigned int DataSig > - static void _SetSliceIsoVertices( const FEMTree< Dim , Real >& tree , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , int slice , HyperCube::Direction zDir , int& vOffset , CoredMeshData< Vertex >& mesh , std::vector< _SlabValues >& slabValues , std::function< void ( Vertex& , Real ) > SetVertexDepth , std::function< void ( Vertex& , Data ) > SetVertexData ) + static void _SetSliceIsoVertices( const FEMTree< Dim , Real >& tree , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , int slice , HyperCube::Direction zDir , int& vOffset , CoredMeshData< Vertex >& mesh , std::vector< _SlabValues >& slabValues , std::function< void ( Vertex& , Point< Real , Dim > , Real , Data ) > SetVertex ) { static const unsigned int DataDegree = FEMSignature< DataSig >::Degree; _SliceValues& sValues = slabValues[depth].sliceValues( slice ); @@ -895,7 +895,7 @@ protected: { Vertex vertex; long long key = _VertexData::EdgeIndex( leaf , e , tree._localToGlobal( tree._maxDepth ) ); - _GetIsoVertex< WeightDegree , Data , DataSig >( tree , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , _e , zDir , sValues , vertex , SetVertexDepth , SetVertexData ); + _GetIsoVertex< WeightDegree , Data , DataSig >( tree , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , _e , zDir , sValues , vertex , SetVertex ); bool stillOwner = false; std::pair< int , Vertex > hashed_vertex; #pragma omp critical (add_point_access) @@ -952,7 +952,7 @@ protected: // Iso-Extraction // //////////////////// template< unsigned int WeightDegree , typename Data , unsigned int DataSig > - static void _SetXSliceIsoVertices( const FEMTree< Dim , Real >& tree , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , int slab , int& vOffset , CoredMeshData< Vertex >& mesh , std::vector< _SlabValues >& slabValues , std::function< void ( Vertex& , Real ) > SetVertexDepth , std::function< void ( Vertex& , Data ) > SetVertexData ) + static void _SetXSliceIsoVertices( const FEMTree< Dim , Real >& tree , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , int slab , int& vOffset , CoredMeshData< Vertex >& mesh , std::vector< _SlabValues >& slabValues , std::function< void ( Vertex& , Point< Real , Dim > , Real , Data ) > SetVertex ) { static const unsigned int DataDegree = FEMSignature< DataSig >::Degree; _SliceValues& bValues = slabValues[depth].sliceValues ( slab ); @@ -991,7 +991,7 @@ protected: { Vertex vertex; long long key = _VertexData::EdgeIndex( leaf , e.index , tree._localToGlobal( tree._maxDepth ) ); - _GetIsoVertex< WeightDegree , Data , DataSig >( tree , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , _c , bValues , fValues , vertex , SetVertexDepth , SetVertexData ); + _GetIsoVertex< WeightDegree , Data , DataSig >( tree , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , _c , bValues , fValues , vertex , SetVertex ); bool stillOwner = false; std::pair< int , Vertex > hashed_vertex; #pragma omp critical (add_point_access) @@ -1413,7 +1413,7 @@ protected: } template< unsigned int WeightDegree , typename Data , unsigned int DataSig > - static bool _GetIsoVertex( const FEMTree< Dim , Real >& tree , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , ConstPointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , ConstPointSupportKey< IsotropicUIntPack< Dim , FEMSignature< DataSig >::Degree > >& dataKey , const TreeNode* node , typename HyperCube::template Cube< Dim-1 >::template Element< 1 > _e , HyperCube::Direction zDir , const _SliceValues& sValues , Vertex& vertex , std::function< void ( Vertex& , Real ) > SetVertexDepth , std::function< void ( Vertex& , Data ) > SetVertexData ) + static bool _GetIsoVertex( const FEMTree< Dim , Real >& tree , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , ConstPointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , ConstPointSupportKey< IsotropicUIntPack< Dim , FEMSignature< DataSig >::Degree > >& dataKey , const TreeNode* node , typename HyperCube::template Cube< Dim-1 >::template Element< 1 > _e , HyperCube::Direction zDir , const _SliceValues& sValues , Vertex& vertex , std::function< void ( Vertex& , Point< Real , Dim > , Real , Data ) > SetVertex ) { static const unsigned int DataDegree = FEMSignature< DataSig >::Degree; Point< Real , Dim > position; @@ -1478,26 +1478,27 @@ protected: if( averageRoot>1 ) averageRoot = 1; } position[o] = Real( start + width*averageRoot ); - vertex.point = position; + Real depth = (Real)1.; + Data dataValue; if( densityWeights ) { - Real depth , weight; + Real weight; tree._getSampleDepthAndWeight( *densityWeights , node , position , weightKey , depth , weight ); - SetVertexDepth( vertex , depth ); } if( data ) { if( DataDegree==0 ) { Point< Real , 3 > center( s[0] + width/2 , s[1] + width/2 , s[2] + width/2 ); - SetVertexData( vertex , tree.template _evaluate< ProjectiveData< Data , Real > , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > , 0 >( *data , center , *pointEvaluator , dataKey ).value() ); + dataValue = tree.template _evaluate< ProjectiveData< Data , Real > , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > , 0 >( *data , center , *pointEvaluator , dataKey ).value(); } - else SetVertexData( vertex , tree.template _evaluate< ProjectiveData< Data , Real > , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > , 0 >( *data , position , *pointEvaluator , dataKey ).value() ); + else dataValue = tree.template _evaluate< ProjectiveData< Data , Real > , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > , 0 >( *data , position , *pointEvaluator , dataKey ).value(); } + SetVertex( vertex , position , depth , dataValue ); return true; } template< unsigned int WeightDegree , typename Data , unsigned int DataSig > - static bool _GetIsoVertex( const FEMTree< Dim , Real >& tree , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , ConstPointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , ConstPointSupportKey< IsotropicUIntPack< Dim , FEMSignature< DataSig >::Degree > >& dataKey , const TreeNode* node , typename HyperCube::template Cube< Dim-1 >::template Element< 0 > _c , const _SliceValues& bValues , const _SliceValues& fValues , Vertex& vertex , std::function< void ( Vertex& , Real ) > SetVertexDepth , std::function< void ( Vertex& , Data ) > SetVertexData ) + static bool _GetIsoVertex( const FEMTree< Dim , Real >& tree , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , ConstPointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , ConstPointSupportKey< IsotropicUIntPack< Dim , FEMSignature< DataSig >::Degree > >& dataKey , const TreeNode* node , typename HyperCube::template Cube< Dim-1 >::template Element< 0 > _c , const _SliceValues& bValues , const _SliceValues& fValues , Vertex& vertex , std::function< void ( Vertex& , Point< Real , Dim > , Real , Data ) > SetVertex ) { static const unsigned int DataDegree = FEMSignature< DataSig >::Degree; Point< Real , Dim > position; @@ -1558,22 +1559,23 @@ protected: if( averageRoot>1 ) averageRoot = 1; } position[2] = Real( start + width*averageRoot ); - vertex.point = position; + Real depth = (Real)1.; + Data dataValue; if( densityWeights ) { - Real depth , weight; + Real weight; tree._getSampleDepthAndWeight( *densityWeights , node , position , weightKey , depth , weight ); - SetVertexDepth( vertex , depth ); } if( data ) { if( DataDegree==0 ) { Point< Real , 3 > center( s[0] + width/2 , s[1] + width/2 , s[2] + width/2 ); - SetVertexData( vertex , tree.template _evaluate< ProjectiveData< Data , Real > , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > , 0 >( *data , center , *pointEvaluator , dataKey ).value() ); + dataValue = tree.template _evaluate< ProjectiveData< Data , Real > , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > , 0 >( *data , center , *pointEvaluator , dataKey ).value(); } - else SetVertexData( vertex , tree.template _evaluate< ProjectiveData< Data , Real > , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > , 0 >( *data , position , *pointEvaluator , dataKey ).value() ); + else dataValue = tree.template _evaluate< ProjectiveData< Data , Real > , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > , 0 >( *data , position , *pointEvaluator , dataKey ).value(); } + SetVertex( vertex , position , depth , dataValue ); return true; } @@ -1602,11 +1604,9 @@ protected: if( isCoplanar ) { Vertex c; - typename Vertex::Wrapper _c; - _c *= 0; - for( int i=0 ; i<(int)polygon.size() ; i++ ) _c += typename Vertex::Wrapper( polygon[i].second ); - _c /= ( typename Vertex::Real )polygon.size(); - c = _c; + c *= 0; + for( int i=0 ; i<(int)polygon.size() ; i++ ) c += polygon[i].second; + c /= ( typename Vertex::Real )polygon.size(); int cIdx; #pragma omp critical (add_barycenter_point_access) { @@ -1651,7 +1651,7 @@ public: IsoStats( void ) : cornersTime(0) , verticesTime(0) , edgesTime(0) , surfaceTime(0) , copyFinerTime(0) , setTableTime(0) {;} }; template< typename Data , unsigned int ... FEMSigs , unsigned int WeightDegree , unsigned int DataSig > - static IsoStats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , CoredMeshData< Vertex >& mesh , std::function< void ( Vertex& , Real ) > SetVertexDepth , std::function< void ( Vertex& , Data ) > SetVertexData , bool nonLinearFit , bool addBarycenter , bool polygonMesh , bool flipOrientation ) + static IsoStats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , CoredMeshData< Vertex >& mesh , std::function< void ( Vertex& , Point< Real , Dim > , Real , Data ) > SetVertex , bool nonLinearFit , bool addBarycenter , bool polygonMesh , bool flipOrientation ) { IsoStats isoStats; static_assert( sizeof...(FEMSigs)==Dim , "[ERROR] Number of signatures should match dimension" ); @@ -1697,7 +1697,7 @@ public: isoStats.copyFinerTime += Time()-t , t = Time(); _SetSliceIsoCorners< FEMSigs ... >( tree , coefficients() , coarseCoefficients() , isoValue , d , 0 , slabValues , evaluators[d] ); isoStats.cornersTime += Time()-t , t = Time(); - _SetSliceIsoVertices< WeightDegree , Data , DataSig >( tree , pointEvaluator , densityWeights , data , isoValue , d , 0 , vertexOffset , mesh , slabValues , SetVertexDepth , SetVertexData ); + _SetSliceIsoVertices< WeightDegree , Data , DataSig >( tree , pointEvaluator , densityWeights , data , isoValue , d , 0 , vertexOffset , mesh , slabValues , SetVertex ); isoStats.verticesTime += Time()-t , t = Time(); _SetSliceIsoEdges( tree , d , 0 , slabValues ); isoStats.edgesTime += Time()-t , t = Time(); @@ -1721,13 +1721,13 @@ public: // Set the slice values/vertices _SetSliceIsoCorners< FEMSigs ... >( tree , coefficients() , coarseCoefficients() , isoValue , d , o , slabValues , evaluators[d] ); isoStats.cornersTime += Time()-t , t = Time(); - _SetSliceIsoVertices< WeightDegree , Data , DataSig >( tree , pointEvaluator , densityWeights , data , isoValue , d , o , vertexOffset , mesh , slabValues , SetVertexDepth , SetVertexData ); + _SetSliceIsoVertices< WeightDegree , Data , DataSig >( tree , pointEvaluator , densityWeights , data , isoValue , d , o , vertexOffset , mesh , slabValues , SetVertex ); isoStats.verticesTime += Time()-t , t = Time(); _SetSliceIsoEdges( tree , d , o , slabValues ); isoStats.edgesTime += Time()-t , t = Time(); // Set the cross-slice edges - _SetXSliceIsoVertices< WeightDegree , Data , DataSig >( tree , pointEvaluator , densityWeights , data , isoValue , d , o-1 , vertexOffset , mesh , slabValues , SetVertexDepth , SetVertexData ); + _SetXSliceIsoVertices< WeightDegree , Data , DataSig >( tree , pointEvaluator , densityWeights , data , isoValue , d , o-1 , vertexOffset , mesh , slabValues , SetVertex ); isoStats.verticesTime += Time()-t , t = Time(); _SetXSliceIsoEdges( tree , d , o-1 , slabValues ); isoStats.edgesTime += Time()-t , t = Time(); diff --git a/Src/FEMTree.h b/Src/FEMTree.h index ae4ca7c..754219a 100644 --- a/Src/FEMTree.h +++ b/Src/FEMTree.h @@ -42,7 +42,7 @@ DAMAGE. #ifndef FEM_TREE_INCLUDED #define FEM_TREE_INCLUDED -#define VERSION "10.00" +#define VERSION "10.01" #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 #define NEW_CODE @@ -2549,8 +2549,7 @@ struct IsoSurfaceExtractor const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , // The coefficients of the function Real isoValue , // The value at which to extract the level-set CoredMeshData< Vertex >& mesh , // The mesh in which to store the output - std::function< void ( Vertex& , Real ) > SetVertexDepth , // A function for setting the depth of a vertex - std::function< void ( Vertex& , Data ) > SetVertexData , // A function for setting the auxiliary data of a vertex + std::function< void ( Vertex& , Point< Real , Dim > , Real , Data ) > SetVertex , // A function for setting the depth and data of a vertex bool nonLinearFit , // Should a linear interpolant be used bool addBarycenter , // Should we triangulate polygons by adding a mid-point bool polygonMesh , // Should we output triangles or polygons diff --git a/Src/FEMTree.inl b/Src/FEMTree.inl index ff2b194..cdc0faf 100644 --- a/Src/FEMTree.inl +++ b/Src/FEMTree.inl @@ -338,7 +338,7 @@ SparseNodeData< Point< Real , Dim > , UIntPack< NormalSigs ... > > FEMTree< Dim const ProjectiveData< Point< Real , Dim > , Real >& sample = samples[i].sample; if( sample.weight>0 ) { - Point< Real , Dim > p = sample.data / sample.weight , n = normalData[i].normal; + Point< Real , Dim > p = sample.data / sample.weight , n = std::get< 0 >( normalData[i].data ).data; Real l = (Real)Length( n ); Real confidence = l / sample.weight; n *= sample.weight / l; diff --git a/Src/Ply.h b/Src/Ply.h index 9e0fd51..cf3c8da 100644 --- a/Src/Ply.h +++ b/Src/Ply.h @@ -35,192 +35,9 @@ #define __PLY_H__ #define NEW_PLY_CODE - -#ifndef WIN32 -#define _strdup strdup -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include -#include - -#define PLY_ASCII 1 /* ascii PLY file */ -#define PLY_BINARY_BE 2 /* binary PLY file, big endian */ -#define PLY_BINARY_LE 3 /* binary PLY file, little endian */ -#define PLY_BINARY_NATIVE 4 /* binary PLY file, same endianness as current architecture */ - -#define PLY_OKAY 0 /* ply routine worked okay */ -#define PLY_ERROR -1 /* error in ply routine */ - - /* scalar data types supported by PLY format */ - -#define PLY_START_TYPE 0 -#define PLY_CHAR 1 -#define PLY_SHORT 2 -#define PLY_INT 3 -#define PLY_UCHAR 4 -#define PLY_USHORT 5 -#define PLY_UINT 6 -#define PLY_FLOAT 7 -#define PLY_DOUBLE 8 -#define PLY_INT_8 9 -#define PLY_UINT_8 10 -#define PLY_INT_16 11 -#define PLY_UINT_16 12 -#define PLY_INT_32 13 -#define PLY_UINT_32 14 -#define PLY_FLOAT_32 15 -#define PLY_FLOAT_64 16 - -#define PLY_END_TYPE 17 - -#define PLY_SCALAR 0 -#define PLY_LIST 1 - -#define PLY_STRIP_COMMENT_HEADER 0 - -typedef struct PlyProperty { /* description of a property */ - char *name; /* property name */ - int external_type; /* file's data type */ - int internal_type; /* program's data type */ - int offset; /* offset bytes of prop in a struct */ - - int is_list; /* 1 = list, 0 = scalar */ - int count_external; /* file's count type */ - int count_internal; /* program's count type */ - int count_offset; /* offset byte for list count */ -} -PlyProperty; - -typedef struct PlyElement { /* description of an element */ - char *name; /* element name */ - int num; /* number of elements in this object */ - int size; /* size of element (bytes) or -1 if variable */ - int nprops; /* number of properties for this element */ - PlyProperty **props; /* list of properties in the file */ - char *store_prop; /* flags: property wanted by user? */ - int other_offset; /* offset to un-asked-for props, or -1 if none*/ - int other_size; /* size of other_props structure */ -} PlyElement; - -typedef struct PlyOtherProp { /* describes other properties in an element */ - char *name; /* element name */ - int size; /* size of other_props */ - int nprops; /* number of properties in other_props */ - PlyProperty **props; /* list of properties in other_props */ -} PlyOtherProp; - -typedef struct OtherData { /* for storing other_props for an other element */ - void *other_props; -} OtherData; - -typedef struct OtherElem { /* data for one "other" element */ - char *elem_name; /* names of other elements */ - int elem_count; /* count of instances of each element */ - OtherData **other_data; /* actual property data for the elements */ - PlyOtherProp *other_props; /* description of the property data */ -} OtherElem; - -typedef struct PlyOtherElems { /* "other" elements, not interpreted by user */ - int num_elems; /* number of other elements */ - OtherElem *other_list; /* list of data for other elements */ -} PlyOtherElems; - -typedef struct PlyFile { /* description of PLY file */ - FILE *fp; /* file pointer */ - int file_type; /* ascii or binary */ - float version; /* version number of file */ - int nelems; /* number of elements of object */ - PlyElement **elems; /* list of elements */ - int num_comments; /* number of comments */ - char **comments; /* list of comments */ - int num_obj_info; /* number of items of object information */ - char **obj_info; /* list of object info items */ - PlyElement *which_elem; /* which element we're currently writing */ - PlyOtherElems *other_elems; /* "other" elements from a PLY file */ -} PlyFile; - - /* memory allocation */ -extern char *my_alloc(); -#define myalloc(mem_size) my_alloc((mem_size), __LINE__, __FILE__) - -#ifndef ALLOCN -#define REALLOCN(PTR,TYPE,OLD_N,NEW_N) \ -{ \ - if ((OLD_N) == 0) \ -{ ALLOCN((PTR),TYPE,(NEW_N));} \ - else \ -{ \ - (PTR) = (TYPE *)realloc((PTR),(NEW_N)*sizeof(TYPE)); \ - if (((PTR) == NULL) && ((NEW_N) != 0)) \ -{ \ - fprintf(stderr, "Memory reallocation failed on line %d in %s\n", \ - __LINE__, __FILE__); \ - fprintf(stderr, " tried to reallocate %d->%d\n", \ - (OLD_N), (NEW_N)); \ - exit(-1); \ -} \ - if ((NEW_N)>(OLD_N)) \ - memset((char *)(PTR)+(OLD_N)*sizeof(TYPE), 0, \ - ((NEW_N)-(OLD_N))*sizeof(TYPE)); \ -} \ -} - -#define ALLOCN(PTR,TYPE,N) \ -{ (PTR) = (TYPE *) calloc(((unsigned)(N)),sizeof(TYPE));\ - if ((PTR) == NULL) { \ - fprintf(stderr, "Memory allocation failed on line %d in %s\n", \ - __LINE__, __FILE__); \ - exit(-1); \ - } \ -} - - -#define FREE(PTR) { free((PTR)); (PTR) = NULL; } -#endif - - -/*** delcaration of routines ***/ - -extern PlyFile *ply_write(FILE *, int, const char **, int); -extern PlyFile *ply_open_for_writing( const char *, int, const char **, int, float *); -extern void ply_describe_element(PlyFile *, char *, int, int, PlyProperty *); -extern void ply_describe_property(PlyFile *, const char *, PlyProperty *); -extern void ply_element_count(PlyFile *, const char *, int); -extern void ply_header_complete(PlyFile *); -extern void ply_put_element_setup(PlyFile *, const char *); -extern void ply_put_element(PlyFile *, void *); -extern void ply_put_comment(PlyFile *, char *); -extern void ply_put_obj_info(PlyFile *, char *); -extern PlyFile *ply_read(FILE *, int *, char ***); -extern PlyFile *ply_open_for_reading( const char *, int *, char ***, int *, float *); -extern PlyProperty **ply_get_element_description(PlyFile *, char *, int*, int*); -extern void ply_get_element_setup( PlyFile *, char *, int, PlyProperty *); -extern int ply_get_property(PlyFile *, char *, PlyProperty *); -extern PlyOtherProp *ply_get_other_properties(PlyFile *, char *, int); -extern void ply_get_element(PlyFile *, void *); -extern char **ply_get_comments(PlyFile *, int *); -extern char **ply_get_obj_info(PlyFile *, int *); -extern void ply_close(PlyFile *); -extern void ply_get_info(PlyFile *, float *, int *); -extern PlyOtherElems *ply_get_other_element (PlyFile *, char *, int); -extern void ply_describe_other_elements ( PlyFile *, PlyOtherElems *); -extern void ply_put_other_elements (PlyFile *); -extern void ply_free_other_elements (PlyOtherElems *); -extern void ply_describe_other_properties(PlyFile *, PlyOtherProp *, int); - -extern int equal_strings(const char *, const char *); - -#ifdef __cplusplus -} -#endif -#include "Geometry.h" #include +#include "PlyFile.h" +#include "Geometry.h" template< class Real > int PLYType( void ); template<> inline int PLYType< int >( void ){ return PLY_INT ; } @@ -242,35 +59,6 @@ static PlyProperty face_props[] = }; -/////////////// -// PlyVertex // -/////////////// -#ifdef NEW_PLY_CODE -static char* PlyPositionNames[] = { "x" , "y" , "z" , "w" }; -static char* PlyNormalNames[] = { "nx" , "ny" , "nz" , "nw" }; -static char* PlyValueNames[] = { "value" }; -static char* PlyColorNames[] = { "red" , "green" , "blue" , "alpha" }; -static char* PlyAlternateColorNames[] = { "r" , "g" , "b" , "a" }; -#else // !NEW_PLY_CODE -static char* PlyPositionNames[] = { _strdup( "x" ) , _strdup( "y" ) , _strdup( "z" ) , _strdup( "w" ) }; -static char* PlyNormalNames[] = { _strdup( "nx" ) , _strdup( "ny" ) , _strdup( "nz" ) , _strdup( "nw" ) }; -static char* PlyValueNames[] = { _strdup( "value" ) }; -static char* PlyColorNames[] = { _strdup( "red" ), _strdup( "green" ) , _strdup( "blue" ) , _strdup( "alpha" ) }; -static char* PlyAlternateColorNames[] = { _strdup( "r" ) , _strdup( "g" ) , _strdup( "b" ) , _strdup( "a" ) }; -#endif // NEW_PLY_CODE -inline PlyProperty MakePlyProperty( char* name , int internalType , int externalType , int offset ) -{ - PlyProperty p; - p.name = name; - p.external_type = externalType; - p.internal_type = internalType; - p.offset = offset; - p.is_list = p.count_external = p.count_internal = p.count_offset = 0; - return p; -} - -// The "Wrapper" class indicates the class to cast to/from in order to support linear operations. - struct RGBColor { unsigned char c[3]; @@ -280,127 +68,192 @@ struct RGBColor RGBColor( const RGBColor& rgb ){ memcpy( c , rgb.c , sizeof(unsigned char) * 3 ); } RGBColor& operator = ( const RGBColor& rgb ){ memcpy( c , rgb.c , sizeof(unsigned char) * 3 ) ; return *this; } }; -/////////////////// -// FullPlyVertex // -/////////////////// -template< class _Real , int Dim , bool HasNormal , bool HasValue , bool HasColor > -class FullPlyVertex +/////////////// +// PlyVertex // +/////////////// +template< typename _Real , int Dim , typename _RealOnDisk=float > +class PlyVertex { public: typedef _Real Real; -protected: - static PlyProperty _Properties[]; - static const int _NormalSize = HasNormal ? sizeof( Point< Real , Dim > ) : 0; - static const int _ValueSize = HasValue ? sizeof( Real ) : 0; - static const int _ColorSize = HasColor ? sizeof( RGBColor ) : 0; - static const int _Size = _NormalSize + _ValueSize + _ColorSize; - static const int _NormalOffset = 0; - static const int _ValueOffset = _NormalOffset + _NormalSize; - static const int _ColorOffset = _ValueOffset + _ValueSize; + PlyVertex& operator += ( const PlyVertex& p ){ point += p.point ; return *this; } + PlyVertex& operator -= ( const PlyVertex& p ){ point -= p.point ; return *this; } + PlyVertex& operator *= ( Real s ) { point *= s ; return *this; } + PlyVertex& operator /= ( Real s ) { point /= s ; return *this; } + PlyVertex operator + ( const PlyVertex& p ) const { return PlyVertex( point + p.point ); } + PlyVertex operator - ( const PlyVertex& p ) const { return PlyVertex( point - p.point ); } + PlyVertex operator * ( Real s ) const { return PlyVertex( point * s ); } + PlyVertex operator / ( Real s ) const { return PlyVertex( point / s ); } - char _vertexData[ _Size==0 ? 1 :_Size ]; -public: - struct _FullPlyVertex - { - static const int PointCount = Dim ; - static const int NormalCount = ( HasNormal ? Dim : 0 ); - static const int ValueCount = ( HasValue ? 1 : 0 ); - static const int ColorCount = ( HasColor ? 3 : 0 ); - static const int Count = NormalCount + ValueCount + ColorCount; + const static int PlyReadNum = Dim; + const static int PlyWriteNum = Dim; - static const int NormalOffset = 0; - static const int ValueOffset = NormalOffset + NormalCount; - static const int ColorOffset = ValueOffset + ValueCount; - - Point< Real , Count==0 ? 1 : Count > vertexData; - Point< Real , Dim > point; - Point< Real , Dim >& normal( void ){ return *( ( Point< Real , Dim >*)(&vertexData[0] + NormalOffset) ); } - Real & value ( void ){ return *( ( Real *)(&vertexData[0] + ValueOffset) ); } - Point< Real , 3 >& color ( void ){ return *( ( Point< Real , 3 >*)(&vertexData[0] + ColorOffset) ); } - const Point< Real , Dim >& normal( void ) const { return *( ( Point< Real , Dim >*)(&vertexData[0] + NormalOffset) ); } - const Real & value ( void ) const { return *( ( Real *)(&vertexData[0] + ValueOffset) ); } - const Point< Real , 3 >& color ( void ) const { return *( ( Point< Real , 3 >*)(&vertexData[0] + ColorOffset) ); } - - _FullPlyVertex( void ) {;} - _FullPlyVertex( Point< Real , Dim > p , Point< Real , Count > vData ){ point = p , vertexData = vData; } - _FullPlyVertex( FullPlyVertex p ) - { - point = p.point; - if( HasNormal ) for( int i=0 ; i( 0 , std::min< int >( 255 , (int)( vertexData[ColorOffset+i]+0.5 ) ) ); - return p; - } - _FullPlyVertex& operator += ( const _FullPlyVertex& p ){ point += p.point , vertexData += p.vertexData ; return *this; } - _FullPlyVertex& operator -= ( const _FullPlyVertex& p ){ point -= p.point , vertexData -= p.vertexData ; return *this; } - _FullPlyVertex& operator *= ( Real s ) { point *= s , vertexData *= s ; return *this; } - _FullPlyVertex& operator /= ( Real s ) { point /= s , vertexData /= s ; return *this; } - _FullPlyVertex operator + ( const _FullPlyVertex& p ) const { return _FullPlyVertex( point + p.point , vertexData + p.vertexData ); } - _FullPlyVertex operator - ( const _FullPlyVertex& p ) const { return _FullPlyVertex( point - p.point , vertexData - p.vertexData ); } - _FullPlyVertex operator * ( Real s ) const { return _FullPlyVertex( point * s , vertexData * s ); } - _FullPlyVertex operator / ( Real s ) const { return _FullPlyVertex( point / s , vertexData / s ); } - }; - - typedef _FullPlyVertex Wrapper; - - const static int ReadComponents = Dim + ( HasNormal ? Dim : 0 ) + ( HasValue ? 1 : 0 ) + ( HasColor ? 6 : 0 ); - const static int WriteComponents = Dim + ( HasNormal ? Dim : 0 ) + ( HasValue ? 1 : 0 ) + ( HasColor ? 3 : 0 ); - - static PlyProperty* Properties( void ); + static const PlyProperty* PlyReadProperties( void ){ return _PlyProperties; } + static const PlyProperty* PlyWriteProperties( void ){ return _PlyProperties; } Point< Real , Dim > point; - Point< Real , Dim >& normal( void ){ return *( ( Point< Real , Dim >* )( _vertexData + _NormalOffset ) ); } - Real& value( void ){ return *( ( Real* ) ( _vertexData + _ValueOffset ) ); } - RGBColor& color( void ){ return *( ( RGBColor* ) ( _vertexData + _ColorOffset ) ); } - FullPlyVertex( void ){ memset( _vertexData , 0 , _Size ); } - FullPlyVertex( Point< Real , Dim > p ) : FullPlyVertex() { point = p; } - FullPlyVertex( const FullPlyVertex& v ) : FullPlyVertex() { point = v.point , memcpy( _vertexData , v._vertexData , _Size ); } - FullPlyVertex& operator = ( const FullPlyVertex& v ) { point = v.point , memcpy( _vertexData , v._vertexData , _Size ) ; return *this; } + PlyVertex( void ) {} + PlyVertex( Point< Real , Dim > p ) : point(p) { } + + struct Transform + { + Transform( void ){} + Transform( const XForm< Real , Dim+1 >& xForm ) : _pointXForm(xForm) { } + PlyVertex operator() ( const PlyVertex& p ) const + { + PlyVertex _p; + _p.point = _pointXForm * p.point; + return _p; + } + protected: + XForm< Real , Dim+1 > _pointXForm; + }; + +protected: + static const PlyProperty _PlyProperties[]; }; -template< class Real , int Dim , bool HasNormal , bool HasValue , bool HasColor , class _Real > -FullPlyVertex< Real , Dim , HasNormal , HasValue , HasColor > operator * ( XForm< _Real , Dim+1 > xForm , FullPlyVertex< Real , Dim , HasNormal , HasValue , HasColor > p ) + +template<> +const PlyProperty PlyVertex< float , 2 , float >::_PlyProperties[] = { - FullPlyVertex< Real , Dim , HasNormal , HasValue , HasColor > _p = p; - _p.point = xForm * p.point; - if( HasNormal ) _p.normal() = xForm.inverse().transpose() * p.normal(); - return _p; -} - -template< class Real , int Dim , bool HasNormal , bool HasValue , bool HasColor > PlyProperty FullPlyVertex< Real , Dim , HasNormal , HasValue , HasColor >::_Properties[ FullPlyVertex::ReadComponents ]; -template< class Real , int Dim , bool HasNormal , bool HasValue , bool HasColor > -PlyProperty* FullPlyVertex< Real , Dim , HasNormal , HasValue , HasColor >::Properties( void ) + { "x" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 } , + { "y" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 } , +}; +template<> +const PlyProperty PlyVertex< double , 2 , float >::_PlyProperties[] = { - int idx = 0; + { "x" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 } , + { "y" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 } , +}; +template<> +const PlyProperty PlyVertex< float , 2 , double >::_PlyProperties[] = +{ + { "x" , PLY_DOUBLE , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 } , + { "y" , PLY_DOUBLE , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 } , +}; +template<> +const PlyProperty PlyVertex< double , 2 , double >::_PlyProperties[] = +{ + { "x" , PLY_DOUBLE , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 } , + { "y" , PLY_DOUBLE , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 } , +}; - // Primary values (for writing) - int vertexDataOffset = (size_t)(&( ( (FullPlyVertex*)0 )->_vertexData )); - int pointOffset = (size_t)(&( ( (FullPlyVertex*)0 )->point )); - for( int d=0 ; d() , PLYType< Real >() , pointOffset + sizeof( Real )*d ); - if( HasNormal ) for( int d=0 ; d() , PLYType< Real >() , vertexDataOffset + _NormalOffset + sizeof( Real )*d ); - if( HasValue ) _Properties[idx++] = MakePlyProperty( PlyValueNames[0] , PLYType< Real >() , PLYType< Real >() , vertexDataOffset + _ValueOffset ); - if( HasColor ) for( int c=0 ; c<3 ; c++ ) _Properties[idx++] = MakePlyProperty( PlyColorNames[c] , PLYType< unsigned char >() , PLYType< unsigned char >() , vertexDataOffset + _ColorOffset + sizeof( unsigned char )*c ); +template<> +const PlyProperty PlyVertex< float , 3 , float >::_PlyProperties[] = +{ + { "x" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 } , + { "y" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 } , + { "z" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 } , +}; +template<> +const PlyProperty PlyVertex< double , 3 , float >::_PlyProperties[] = +{ + { "x" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 } , + { "y" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 } , + { "z" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 } , +}; +template<> +const PlyProperty PlyVertex< float , 3 , double >::_PlyProperties[] = +{ + { "x" , PLY_DOUBLE , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 } , + { "y" , PLY_DOUBLE , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 } , + { "z" , PLY_DOUBLE , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 } , +}; +template<> +const PlyProperty PlyVertex< double , 3 , double >::_PlyProperties[] = +{ + { "x" , PLY_DOUBLE , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 } , + { "y" , PLY_DOUBLE , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 } , + { "z" , PLY_DOUBLE , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 } , +}; - // Alternative values (for reading or writing) - if( HasColor ) for( int c=0 ; c<3 ; c++ ) _Properties[idx++] = MakePlyProperty( PlyAlternateColorNames[c] , PLYType< unsigned char >() , PLYType< unsigned char >() , vertexDataOffset + _ColorOffset + sizeof( unsigned char )*c ); +/////////////////////// +// PlyVertexWithData // +/////////////////////// +template< typename _Real , int Dim , typename Data , typename _RealOnDisk=float > +class PlyVertexWithData +{ +public: + typedef _Real Real; - return _Properties; + PlyVertexWithData& operator += ( const PlyVertexWithData& p ){ point += p.point , data += p.data ; return *this; } + PlyVertexWithData& operator -= ( const PlyVertexWithData& p ){ point -= p.point , data -= p.data ; return *this; } + PlyVertexWithData& operator *= ( Real s ) { point *= s , data *= s ; return *this; } + PlyVertexWithData& operator /= ( Real s ) { point /= s , data /= s ; return *this; } + PlyVertexWithData operator + ( const PlyVertexWithData& p ) const { return PlyVertexWithData( point + p.point , data + p.data ); } + PlyVertexWithData operator - ( const PlyVertexWithData& p ) const { return PlyVertexWithData( point - p.point , data - p.data ); } + PlyVertexWithData operator * ( Real s ) const { return PlyVertexWithData( point * s , data * s ); } + PlyVertexWithData operator / ( Real s ) const { return PlyVertexWithData( point / s , data / s ); } + + const static int PlyReadNum = Data::PlyReadNum + Dim; + const static int PlyWriteNum = Data::PlyWriteNum + Dim; + + static const PlyProperty* PlyReadProperties( void ){ _SetReadProperties() ; return _PlyReadProperties; } + static const PlyProperty* PlyWriteProperties( void ){ _SetWriteProperties() ; return _PlyWriteProperties; } + + + Point< Real , Dim > point; + Data data; + PlyVertexWithData( void ) {} + PlyVertexWithData( Point< Real , Dim > p , Data d ) : point(p) , data(d) { } + + struct Transform + { + Transform( void ){} + Transform( const XForm< Real , Dim+1 >& xForm ) : _pointXForm(xForm) , _dataXForm(xForm) { } + PlyVertexWithData operator() ( const PlyVertexWithData& p ) const + { + PlyVertexWithData _p; + _p.point = _pointXForm * p.point; + _p.data = _dataXForm( p.data ); + return _p; + } + protected: + XForm< Real , Dim+1 > _pointXForm; + typename Data::Transform _dataXForm; + }; + +protected: + static void _SetReadProperties( void ); + static void _SetWriteProperties( void ); + static PlyProperty _PlyReadProperties[]; + static PlyProperty _PlyWriteProperties[]; +}; +template< typename Real , int Dim , typename Data , typename RealOnDisk > PlyProperty PlyVertexWithData< Real , Dim , Data , RealOnDisk >::_PlyReadProperties[ PlyReadNum ]; +template< typename Real , int Dim , typename Data , typename RealOnDisk > PlyProperty PlyVertexWithData< Real , Dim , Data , RealOnDisk >::_PlyWriteProperties[ PlyWriteNum ]; +template< typename Real , int Dim , typename Data , typename RealOnDisk > +void PlyVertexWithData< Real , Dim , Data , RealOnDisk >::_SetReadProperties( void ) +{ + { + const PlyProperty * ReadProps = PlyVertex< Real , Dim , RealOnDisk >::PlyReadProperties(); + for( int d=0 ; d::PlyReadNum ; d++ ) _PlyReadProperties[d] = ReadProps[d]; + } + { + const PlyProperty * ReadProps = Data::PlyReadProperties(); + for( int d=0 ; d::PlyReadNum ] = ReadProps[d]; + _PlyReadProperties[d+PlyVertex< Real , Dim , RealOnDisk >::PlyReadNum ].offset += (int)offsetof( PlyVertexWithData , data ); + } + } +} +template< typename Real , int Dim , typename Data , typename RealOnDisk > +void PlyVertexWithData< Real , Dim , Data , RealOnDisk >::_SetWriteProperties( void ) +{ + { + const PlyProperty * WriteProps = PlyVertex< Real , Dim , RealOnDisk >::PlyWriteProperties(); + for( int d=0 ; d::PlyWriteNum ; d++ ) _PlyWriteProperties[d] = WriteProps[d]; + } + { + const PlyProperty * WriteProps = Data::PlyWriteProperties(); + for( int d=0 ; d::PlyWriteNum ] = WriteProps[d]; + _PlyWriteProperties[d+PlyVertex< Real , Dim , RealOnDisk >::PlyWriteNum ].offset += (int)offsetof( PlyVertexWithData , data ); + } + } } - -template< class Real , int Dim > using PlyVertex = FullPlyVertex< Real , Dim , false , false , false >; -template< class Real , int Dim > using PlyOrientedVertex = FullPlyVertex< Real , Dim , true , false , false >; -template< class Real , int Dim > using PlyValueVertex = FullPlyVertex< Real , Dim , false , true , false >; -template< class Real , int Dim > using PlyColorVertex = FullPlyVertex< Real , Dim , false , false , true >; -template< class Real , int Dim > using PlyOrientedColorVertex = FullPlyVertex< Real , Dim , true , false , true >; -template< class Real , int Dim > using PlyColorAndValueVertex = FullPlyVertex< Real , Dim , false , true , true >; template< class Vertex , class Real , int Dim > int PlyWritePolygons( const char* fileName , CoredMeshData< Vertex >* mesh , int file_type , const Point< float , Dim >& translate , float scale , char** comments=NULL , int commentNum=0 , XForm< Real , Dim+1 > xForm=XForm< Real , Dim+1 >::Identity() ); @@ -408,7 +261,7 @@ int PlyWritePolygons( const char* fileName , CoredMeshData< Vertex >* mesh , in template< class Vertex , class Real , int Dim > int PlyWritePolygons( const char* fileName , CoredMeshData< Vertex >* mesh , int file_type , char** comments=NULL , int commentNum=0 , XForm< Real , Dim+1 > xForm=XForm< Real , Dim+1 >::Identity() ); -inline bool PlyReadHeader( const char* fileName , PlyProperty* properties , int propertyNum , bool* readFlags , int& file_type ) +inline bool PlyReadHeader( char* fileName , const PlyProperty* properties , int propertyNum , bool* readFlags , int& file_type ) { int nr_elems; char **elist; @@ -489,7 +342,7 @@ inline bool PlyReadHeader( const char* fileName , PlyProperty* properties , int ply_close( ply ); return true; } -inline bool PlyReadHeader( const char* fileName , PlyProperty* properties , int propertyNum , bool* readFlags ) +inline bool PlyReadHeader( char* fileName , const PlyProperty* properties , int propertyNum , bool* readFlags ) { int file_type; return PlyReadHeader( fileName , properties , propertyNum , readFlags , file_type ); @@ -499,21 +352,21 @@ inline bool PlyReadHeader( const char* fileName , PlyProperty* properties , int template int PlyReadPolygons( const char* fileName, std::vector& vertices,std::vector >& polygons, - PlyProperty* properties,int propertyNum, + const PlyProperty* properties,int propertyNum, int& file_type, char*** comments=NULL,int* commentNum=NULL , bool* readFlags=NULL ); template int PlyWritePolygons( const char* fileName, const std::vector& vertices,const std::vector >& polygons , - PlyProperty* properties,int propertyNum, + const PlyProperty* properties,int propertyNum, int file_type, char** comments=NULL,const int& commentNum=0); template int PlyWritePolygons( const char* fileName, const std::vector& vertices , const std::vector< std::vector< int > >& polygons, - PlyProperty* properties,int propertyNum, + const PlyProperty* properties,int propertyNum, int file_type, char** comments,const int& commentNum) { @@ -574,7 +427,7 @@ int PlyWritePolygons( const char* fileName, template int PlyReadPolygons( const char* fileName, std::vector& vertices , std::vector >& polygons , - PlyProperty* properties , int propertyNum , + const PlyProperty* properties , int propertyNum , int& file_type , char*** comments , int* commentNum , bool* readFlags ) { @@ -762,8 +615,10 @@ int PlyWritePolygons( const char* fileName , CoredMeshData< Vertex >* mesh , int // describe vertex and face properties // ply_element_count( ply , "vertex" , nr_vertices ); - for( int i=0 ; i* mesh , int ply_put_element_setup( ply , "vertex" ); for( i=0 ; iinCorePoints.size() ) ; i++ ) { - Vertex vertex = xForm * mesh->inCorePoints[i]; + Vertex vertex = _xForm( mesh->inCorePoints[i] ); ply_put_element(ply, (void *) &vertex); } for( i=0; ioutOfCorePointCount() ; i++ ) { Vertex vertex; mesh->nextOutOfCorePoint( vertex ); - vertex = xForm * ( vertex ); + vertex = _xForm( vertex ); ply_put_element(ply, (void *) &vertex); } // for, write vertices diff --git a/Src/PlyFile.cpp b/Src/PlyFile.cpp index 857b56d..e2a457a 100644 --- a/Src/PlyFile.cpp +++ b/Src/PlyFile.cpp @@ -36,7 +36,7 @@ WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. #include #include #include -#include "Ply.h" +#include "PlyFile.h" const char *type_names[] = { "invalid", @@ -127,7 +127,7 @@ void add_comment(PlyFile *, char *); void add_obj_info(PlyFile *, char *); /* copy a property */ -void copy_property(PlyProperty *, PlyProperty *); +void copy_property(PlyProperty *, const PlyProperty *); /* store a value into where a pointer and a type specify */ void store_item(char *, int, int, unsigned int, double); @@ -339,7 +339,7 @@ prop - the new property void ply_describe_property( PlyFile *plyfile, const char *elem_name, - PlyProperty *prop + const PlyProperty *prop ) { PlyElement *elem; @@ -1010,7 +1010,7 @@ prop - property to add to those that will be returned int ply_get_property( PlyFile *plyfile, char *elem_name, - PlyProperty *prop + const PlyProperty *prop ) { PlyElement *elem; @@ -2690,7 +2690,7 @@ void add_obj_info (PlyFile *plyfile, char *line) Copy a property. ******************************************************************************/ -void copy_property(PlyProperty *dest, PlyProperty *src) +void copy_property(PlyProperty *dest, const PlyProperty *src) { dest->name = _strdup (src->name); dest->external_type = src->external_type; diff --git a/Src/PlyFile.h b/Src/PlyFile.h new file mode 100644 index 0000000..5d40dfa --- /dev/null +++ b/Src/PlyFile.h @@ -0,0 +1,220 @@ +/* + + Header for PLY polygon files. + + - Greg Turk, March 1994 + + A PLY file contains a single polygonal _object_. + + An object is composed of lists of _elements_. Typical elements are + vertices, faces, edges and materials. + + Each type of element for a given object has one or more _properties_ + associated with the element type. For instance, a vertex element may + have as properties three floating-point values x,y,z and three unsigned + chars for red, green and blue. + + --------------------------------------------------------------- + + Copyright (c) 1994 The Board of Trustees of The Leland Stanford + Junior University. All rights reserved. + + Permission to use, copy, modify and distribute this software and its + documentation for any purpose is hereby granted without fee, provided + that the above copyright notice and this permission notice appear in + all copies of this software and that you do not sell the software. + + THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, + EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +*/ + + +#ifndef __PLY_FILE_H__ +#define __PLY_FILE_H__ + +#ifndef WIN32 +#define _strdup strdup +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +#define PLY_ASCII 1 /* ascii PLY file */ +#define PLY_BINARY_BE 2 /* binary PLY file, big endian */ +#define PLY_BINARY_LE 3 /* binary PLY file, little endian */ +#define PLY_BINARY_NATIVE 4 /* binary PLY file, same endianness as current architecture */ + +#define PLY_OKAY 0 /* ply routine worked okay */ +#define PLY_ERROR -1 /* error in ply routine */ + + /* scalar data types supported by PLY format */ + +#define PLY_START_TYPE 0 +#define PLY_CHAR 1 +#define PLY_SHORT 2 +#define PLY_INT 3 +#define PLY_UCHAR 4 +#define PLY_USHORT 5 +#define PLY_UINT 6 +#define PLY_FLOAT 7 +#define PLY_DOUBLE 8 +#define PLY_INT_8 9 +#define PLY_UINT_8 10 +#define PLY_INT_16 11 +#define PLY_UINT_16 12 +#define PLY_INT_32 13 +#define PLY_UINT_32 14 +#define PLY_FLOAT_32 15 +#define PLY_FLOAT_64 16 + +#define PLY_END_TYPE 17 + +#define PLY_SCALAR 0 +#define PLY_LIST 1 + +#define PLY_STRIP_COMMENT_HEADER 0 + +typedef struct PlyProperty { /* description of a property */ + char *name; /* property name */ + int external_type; /* file's data type */ + int internal_type; /* program's data type */ + int offset; /* offset bytes of prop in a struct */ + + int is_list; /* 1 = list, 0 = scalar */ + int count_external; /* file's count type */ + int count_internal; /* program's count type */ + int count_offset; /* offset byte for list count */ +} +PlyProperty; + +typedef struct PlyElement { /* description of an element */ + char *name; /* element name */ + int num; /* number of elements in this object */ + int size; /* size of element (bytes) or -1 if variable */ + int nprops; /* number of properties for this element */ + PlyProperty **props; /* list of properties in the file */ + char *store_prop; /* flags: property wanted by user? */ + int other_offset; /* offset to un-asked-for props, or -1 if none*/ + int other_size; /* size of other_props structure */ +} PlyElement; + +typedef struct PlyOtherProp { /* describes other properties in an element */ + char *name; /* element name */ + int size; /* size of other_props */ + int nprops; /* number of properties in other_props */ + PlyProperty **props; /* list of properties in other_props */ +} PlyOtherProp; + +typedef struct OtherData { /* for storing other_props for an other element */ + void *other_props; +} OtherData; + +typedef struct OtherElem { /* data for one "other" element */ + char *elem_name; /* names of other elements */ + int elem_count; /* count of instances of each element */ + OtherData **other_data; /* actual property data for the elements */ + PlyOtherProp *other_props; /* description of the property data */ +} OtherElem; + +typedef struct PlyOtherElems { /* "other" elements, not interpreted by user */ + int num_elems; /* number of other elements */ + OtherElem *other_list; /* list of data for other elements */ +} PlyOtherElems; + +typedef struct PlyFile { /* description of PLY file */ + FILE *fp; /* file pointer */ + int file_type; /* ascii or binary */ + float version; /* version number of file */ + int nelems; /* number of elements of object */ + PlyElement **elems; /* list of elements */ + int num_comments; /* number of comments */ + char **comments; /* list of comments */ + int num_obj_info; /* number of items of object information */ + char **obj_info; /* list of object info items */ + PlyElement *which_elem; /* which element we're currently writing */ + PlyOtherElems *other_elems; /* "other" elements from a PLY file */ +} PlyFile; + + /* memory allocation */ +extern char *my_alloc(); +#define myalloc(mem_size) my_alloc((mem_size), __LINE__, __FILE__) + +#ifndef ALLOCN +#define REALLOCN(PTR,TYPE,OLD_N,NEW_N) \ +{ \ + if ((OLD_N) == 0) \ +{ ALLOCN((PTR),TYPE,(NEW_N));} \ + else \ +{ \ + (PTR) = (TYPE *)realloc((PTR),(NEW_N)*sizeof(TYPE)); \ + if (((PTR) == NULL) && ((NEW_N) != 0)) \ +{ \ + fprintf(stderr, "Memory reallocation failed on line %d in %s\n", \ + __LINE__, __FILE__); \ + fprintf(stderr, " tried to reallocate %d->%d\n", \ + (OLD_N), (NEW_N)); \ + exit(-1); \ +} \ + if ((NEW_N)>(OLD_N)) \ + memset((char *)(PTR)+(OLD_N)*sizeof(TYPE), 0, \ + ((NEW_N)-(OLD_N))*sizeof(TYPE)); \ +} \ +} + +#define ALLOCN(PTR,TYPE,N) \ +{ (PTR) = (TYPE *) calloc(((unsigned)(N)),sizeof(TYPE));\ + if ((PTR) == NULL) { \ + fprintf(stderr, "Memory allocation failed on line %d in %s\n", \ + __LINE__, __FILE__); \ + exit(-1); \ + } \ +} + + +#define FREE(PTR) { free((PTR)); (PTR) = NULL; } +#endif + + +/*** delcaration of routines ***/ + +extern PlyFile *ply_write(FILE *, int, const char **, int); +extern PlyFile *ply_open_for_writing( const char *, int, const char **, int, float *); +extern void ply_describe_element(PlyFile *, char *, int, int, PlyProperty *); +extern void ply_describe_property(PlyFile *, const char *, const PlyProperty *); +extern void ply_element_count(PlyFile *, const char *, int); +extern void ply_header_complete(PlyFile *); +extern void ply_put_element_setup(PlyFile *, const char *); +extern void ply_put_element(PlyFile *, void *); +extern void ply_put_comment(PlyFile *, char *); +extern void ply_put_obj_info(PlyFile *, char *); +extern PlyFile *ply_read(FILE *, int *, char ***); +extern PlyFile *ply_open_for_reading( const char *, int *, char ***, int *, float *); +extern PlyProperty **ply_get_element_description(PlyFile *, char *, int*, int*); +extern void ply_get_element_setup( PlyFile *, char *, int, PlyProperty *); +extern int ply_get_property(PlyFile *, char *, const PlyProperty *); +extern PlyOtherProp *ply_get_other_properties(PlyFile *, char *, int); +extern void ply_get_element(PlyFile *, void *); +extern char **ply_get_comments(PlyFile *, int *); +extern char **ply_get_obj_info(PlyFile *, int *); +extern void ply_close(PlyFile *); +extern void ply_get_info(PlyFile *, float *, int *); +extern PlyOtherElems *ply_get_other_element (PlyFile *, char *, int); +extern void ply_describe_other_elements ( PlyFile *, PlyOtherElems *); +extern void ply_put_other_elements (PlyFile *); +extern void ply_free_other_elements (PlyOtherElems *); +extern void ply_describe_other_properties(PlyFile *, PlyOtherProp *, int); + +extern int equal_strings(const char *, const char *); + +#ifdef __cplusplus +} +#endif +#endif /* !__PLY_FILE_H__ */ diff --git a/Src/PointStream.h b/Src/PointStream.h index 902e60f..44d1d02 100644 --- a/Src/PointStream.h +++ b/Src/PointStream.h @@ -218,9 +218,9 @@ template< class Real , int Dim , class Data > class ASCIIInputPointStreamWithData : public InputPointStreamWithData< Real , Dim , Data > { FILE* _fp; - Data (*_readData)( FILE* ); + void (*_ReadData)( FILE* , Data& ); public: - ASCIIInputPointStreamWithData( const char* fileName , Data (*readData)( FILE* ) ); + ASCIIInputPointStreamWithData( const char* fileName , void (*ReadData)( FILE* , Data& ) ); ~ASCIIInputPointStreamWithData( void ); void reset( void ); bool nextPoint( Point< Real , Dim >& p , Data& d ); @@ -230,9 +230,9 @@ template< class Real , int Dim , class Data > class ASCIIOutputPointStreamWithData : public OutputPointStreamWithData< Real , Dim , Data > { FILE* _fp; - void (*_writeData)( FILE* , const Data& ); + void (*_WriteData)( FILE* , const Data& ); public: - ASCIIOutputPointStreamWithData( const char* fileName , void (*writeData)( FILE* , const Data& ) ); + ASCIIOutputPointStreamWithData( const char* fileName , void (*WriteData)( FILE* , const Data& ) ); ~ASCIIOutputPointStreamWithData( void ); void nextPoint( const Point< Real , Dim >& p , const Data& d ); }; @@ -241,50 +241,44 @@ template< class Real , int Dim > class BinaryInputPointStream : public InputPointStream< Real , Dim > { FILE* _fp; - bool (*_readPoint)( FILE* , Point< Real , Dim >& ); - static bool _DefaultReadPoint( FILE* fp , Point< Real , Dim >& d ){ return fread( &d , sizeof(Point< Real , Dim >) , 1 , fp )==1; } public: - BinaryInputPointStream( const char* filename , bool (*readPoint)( FILE* , Point< Real , Dim >& )=NULL ); + BinaryInputPointStream( const char* filename ); ~BinaryInputPointStream( void ){ fclose( _fp ) , _fp=NULL; } void reset( void ){ fseek( _fp , SEEK_SET , 0 ); } - bool nextPoint( Point< Real , Dim >& p ){ return _readPoint( _fp , p ); } + bool nextPoint( Point< Real , Dim >& p ); }; template< class Real , int Dim > class BinaryOutputPointStream : public OutputPointStream< Real , Dim > { FILE* _fp; - void (*_writePoint)( FILE* , const Point< Real , Dim >& ); - static void _DefaultWritePoint( FILE* fp , const Point< Real , Dim >& d ){ fwrite( &d , sizeof(Point< Real , Dim >) , 1 , fp ); } public: - BinaryOutputPointStream( const char* filename , void (*writePoint)( FILE* , const Point< Real , Dim >& )=NULL ); + BinaryOutputPointStream( const char* filename ); ~BinaryOutputPointStream( void ){ fclose( _fp ) , _fp=NULL; } void reset( void ){ fseek( _fp , SEEK_SET , 0 ); } - void nextPoint( const Point< Real , Dim >& p ){ return _writePoint( _fp , p ); } + void nextPoint( const Point< Real , Dim >& p ); }; template< class Real , int Dim , class Data > class BinaryInputPointStreamWithData : public InputPointStreamWithData< Real , Dim , Data > { FILE* _fp; - bool (*_readPointAndData)( FILE* , Point< Real , Dim >& , Data& ); - static bool _DefaultReadPointAndData( FILE* fp , Point< Real , Dim >& p , Data& d ){ return fread( &p , sizeof( Point< Real , Dim > ) , 1 , fp )==1 && fread( &d , sizeof( Data ) , 1 , fp )==1; } + void (*_ReadData)( FILE* , Data& ); public: - BinaryInputPointStreamWithData( const char* filename , bool (*readPointAndData)( FILE* , Point< Real , Dim >& , Data& ) = NULL ); + BinaryInputPointStreamWithData( const char* filename , void (*ReadData)( FILE* , Data& ) ); ~BinaryInputPointStreamWithData( void ){ fclose( _fp ) , _fp=NULL; } void reset( void ){ fseek( _fp , SEEK_SET , 0 ); } - bool nextPoint( Point< Real , Dim >& p , Data& d ){ return _readPointAndData( _fp , p , d ); } + bool nextPoint( Point< Real , Dim >& p , Data& d ); }; template< class Real , int Dim , class Data > class BinaryOutputPointStreamWithData : public OutputPointStreamWithData< Real , Dim , Data > { FILE* _fp; - void (*_writePointAndData)( FILE* , const Point< Real , Dim >& , const Data& ); - static void _DefaultWritePointAndData( FILE* fp , const Point< Real , Dim >& p , const Data& d ){ fwrite( &p , sizeof( Point< Real , Dim > ) , 1 , fp ) ; fwrite( &d , sizeof( Data ) , 1 , fp ); } + void (*_WriteData)( FILE* , const Data& ); public: - BinaryOutputPointStreamWithData( const char* filename , void (*writePointAndData)( FILE* , const Point< Real , Dim >& , const Data& ) = NULL ); + BinaryOutputPointStreamWithData( const char* filename , void (*WriteData)( FILE* , const Data& ) ); ~BinaryOutputPointStreamWithData( void ){ fclose( _fp ) , _fp=NULL; } void reset( void ){ fseek( _fp , SEEK_SET , 0 ); } - void nextPoint( const Point< Real , Dim >& p , const Data& d ){ return _writePointAndData( _fp , p , d ); } + void nextPoint( const Point< Real , Dim >& p , const Data& d ); }; template< class Real , int Dim > diff --git a/Src/PointStream.inl b/Src/PointStream.inl index ad92c2f..8bc144a 100644 --- a/Src/PointStream.inl +++ b/Src/PointStream.inl @@ -97,23 +97,25 @@ void ASCIIOutputPointStream< Real , Dim >::nextPoint( const Point< Real , Dim >& // BinaryInputPointStream // //////////////////////////// template< class Real , int Dim > -BinaryInputPointStream< Real , Dim >::BinaryInputPointStream( const char* fileName , bool (*readPoint)( FILE* , Point< Real , Dim >& ) ) +BinaryInputPointStream< Real , Dim >::BinaryInputPointStream( const char* fileName ) { - _readPoint = readPoint!=NULL ? readPoint : _DefaultReadPoint; _fp = fopen( fileName , "rb" ); if( !_fp ) fprintf( stderr , "Failed to open file for reading: %s\n" , fileName ) , exit( 0 ); } +template< class Real , int Dim > +bool BinaryInputPointStream< Real , Dim >::nextPoint( Point< Real , Dim >& p ){ return fread( &p , sizeof(Point< Real , Dim >) , 1 , _fp )==1; } ///////////////////////////// // BinaryOutputPointStream // ///////////////////////////// template< class Real , int Dim > -BinaryOutputPointStream< Real , Dim >::BinaryOutputPointStream( const char* fileName , void (*writePoint)( FILE* , const Point< Real , Dim >& ) ) +BinaryOutputPointStream< Real , Dim >::BinaryOutputPointStream( const char* fileName ) { - _writePoint = writePoint!=NULL ? writePoint : _DefaultWritePoint; _fp = fopen( fileName , "wb" ); if( !_fp ) fprintf( stderr , "Failed to open file for writing: %s\n" , fileName ) , exit( 0 ); } +template< class Real , int Dim > +void BinaryOutputPointStream< Real , Dim >::nextPoint( const Point< Real , Dim >& p ){ fwrite( &p , sizeof(Point< Real , Dim >) , 1 , _fp )==1; } ///////////////////////// // PLYInputPointStream // @@ -230,7 +232,7 @@ bool MemoryInputPointStreamWithData< Real , Dim , Data >::nextPoint( Point< Real // ASCIIInputPointStreamWithData // /////////////////////////////////// template< class Real , int Dim , class Data > -ASCIIInputPointStreamWithData< Real , Dim , Data >::ASCIIInputPointStreamWithData( const char* fileName , Data (*readData)( FILE* ) ) : _readData( readData ) +ASCIIInputPointStreamWithData< Real , Dim , Data >::ASCIIInputPointStreamWithData( const char* fileName , void (*ReadData)( FILE* , Data& ) ) : _ReadData( ReadData ) { _fp = fopen( fileName , "r" ); if( !_fp ) fprintf( stderr , "Failed to open file for reading: %s\n" , fileName ) , exit( 0 ); @@ -250,7 +252,7 @@ bool ASCIIInputPointStreamWithData< Real , Dim , Data >::nextPoint( Point< Real for( int dd=0 ; dd::nextPoint( Point< Real // ASCIIOutputPointStreamWithData // //////////////////////////////////// template< class Real , int Dim , class Data > -ASCIIOutputPointStreamWithData< Real , Dim , Data >::ASCIIOutputPointStreamWithData( const char* fileName , void (*writeData)( FILE* , const Data& ) ) : _writeData( writeData ) +ASCIIOutputPointStreamWithData< Real , Dim , Data >::ASCIIOutputPointStreamWithData( const char* fileName , void (*WriteData)( FILE* , const Data& ) ) : _WriteData( WriteData ) { _fp = fopen( fileName , "w" ); if( !_fp ) fprintf( stderr , "Failed to open file for writing: %s\n" , fileName ) , exit( 0 ); @@ -274,7 +276,7 @@ void ASCIIOutputPointStreamWithData< Real , Dim , Data >::nextPoint( const Point { for( int d=0 ; d::nextPoint( const Point // BinaryInputPointStreamWithData // //////////////////////////////////// template< class Real , int Dim , class Data > -BinaryInputPointStreamWithData< Real , Dim , Data >::BinaryInputPointStreamWithData( const char* fileName , bool (*readPointAndData)( FILE* , Point< Real , Dim >& , Data& ) ) +BinaryInputPointStreamWithData< Real , Dim , Data >::BinaryInputPointStreamWithData( const char* fileName , void (*ReadData)( FILE* , Data& ) ) : _ReadData(ReadData) { - _readPointAndData = readPointAndData!=NULL ? readPointAndData : _DefaultReadPointAndData; _fp = fopen( fileName , "rb" ); if( !_fp ) fprintf( stderr , "Failed to open file for reading: %s\n" , fileName ) , exit( 0 ); } +template< class Real , int Dim , class Data > +bool BinaryInputPointStreamWithData< Real , Dim , Data >::nextPoint( Point< Real , Dim >& p , Data& d ) +{ + if( fread( &p , sizeof(Point< Real , Dim >) , 1 , _fp )==1 ) + { + _ReadData( _fp , d ); + return true; + } + else return false; +} ///////////////////////////////////// // BinaryOutputPointStreamWithData // ///////////////////////////////////// template< class Real , int Dim , class Data > -BinaryOutputPointStreamWithData< Real , Dim , Data >::BinaryOutputPointStreamWithData( const char* fileName , void (*writePointAndData)( FILE* , const Point< Real , Dim >& , const Data& ) ) +BinaryOutputPointStreamWithData< Real , Dim , Data >::BinaryOutputPointStreamWithData( const char* fileName , void (*WriteData)( FILE* , const Data& ) ) : _WriteData(WriteData) { - _writePointAndData = writePointAndData!=NULL ? writePointAndData : _DefaultWritePointAndData; _fp = fopen( fileName , "wb" ); if( !_fp ) fprintf( stderr , "Failed to open file for writing: %s\n" , fileName ) , exit( 0 ); } +template< class Real , int Dim , class Data > +void BinaryOutputPointStreamWithData< Real , Dim , Data >::nextPoint( const Point< Real , Dim >& p , const Data& d ) +{ + fwrite( &p , sizeof(Point< Real , Dim >) , 1 , _fp ); + _WriteData( _fp , d ); +} ///////////////////////////////// // PLYInputPointStreamWithData // @@ -337,9 +353,10 @@ void PLYInputPointStreamWithData< Real , Dim , Data >::reset( void ) { foundVertices = true; _pCount = num_elems , _pIdx = 0; - for( int i=0 ; i::ReadComponents ; i++ ) - if( !ply_get_property( _ply , elem_name , &(PlyVertex< Real , Dim >::Properties()[i]) ) ) - fprintf( stderr , "[ERROR] Failed to find property in ply file: %s\n" , PlyVertex< Real , Dim >::Properties()[i].name ) , exit( 0 ); + const PlyProperty* PlyReadProperties = PlyVertex< Real , Dim >::PlyReadProperties(); + for( int i=0 ; i::PlyReadNum ; i++ ) + if( !ply_get_property( _ply , elem_name , &(PlyReadProperties[i]) ) ) + fprintf( stderr , "[ERROR] Failed to find property in ply file: %s\n" , PlyReadProperties[i].name ) , exit( 0 ); if( _validationFunction ) { bool* properties = new bool[_dataPropertiesCount]; diff --git a/Src/PointStreamData.h b/Src/PointStreamData.h index e0dcca4..b6bbc72 100644 --- a/Src/PointStreamData.h +++ b/Src/PointStreamData.h @@ -29,266 +29,470 @@ DAMAGE. #define POINT_STREAM_DATA_INCLUDED #include +#include #include "Ply.h" template< class Real > using Color = Point< Real , 3 >; template< class Real > void SetColorValues( const Color< Real >& color , unsigned char c[3] ){ for( int i=0 ; i<3 ; i++ ) c[i] = (unsigned char)std::max< int >( 0 , std::min< int >( 255 , (int)( color[i]+0.5 ) ) ); } template< class Real > void SetColorValues( const Color< Real >& color , RGBColor& c ){ for( int i=0 ; i<3 ; i++ ) c[i] = (unsigned char)std::max< int >( 0 , std::min< int >( 255 , (int)( color[i]+0.5 ) ) ); } -template< class Real , int Dim > -struct Normal +// Should have: +// -- binary operators for vectors +// -- static ReadASCII +// -- static WriteASCII +// -- static ReadBinary +// -- static WriteBinary +// -- static ValidPlyReadProperties( const bool* ) method +// -- static int PlyReadNum +// -- static int PlyWriteNum +// -- static const PlyProperty* PlyReadProperties() +// -- static const PlyProperty* PlyWriteProperties() +// -- a nested class Transform which gets initialized by something and acts on the data +template< typename Real , typename Data > +struct PointStreamData { - Point< Real , Dim > normal; - Normal( void ){;} - Normal( Point< Real , Dim > n ) : normal( n ) {;} - Normal( const Normal& n ) : normal( n.normal ) {;} + Data data; - Normal& operator += ( const Normal& p ){ normal += p.normal ; return *this; } - Normal& operator -= ( const Normal& p ){ normal -= p.normal ; return *this; } - Normal& operator *= ( Real s ){ normal *= s ; return *this; } - Normal& operator /= ( Real s ){ normal /= s ; return *this; } - Normal operator + ( const Normal& p ) const { return Normal( normal+p.normal ); } - Normal operator - ( const Normal& p ) const { return Normal( normal-p.normal ); } - Normal operator * ( Real s ) const { return Normal( normal*s ); } - Normal operator / ( Real s ) const { return Normal( normal/s ); } + PointStreamData& operator += ( const PointStreamData& p ){ data += p.data ; return *this; } + PointStreamData& operator -= ( const PointStreamData& p ){ data -= p.data ; return *this; } + PointStreamData& operator *= ( Real s ) { data *= s ; return *this; } + PointStreamData& operator /= ( Real s ) { data /= s ; return *this; } + PointStreamData operator + ( const PointStreamData& p ) const { PointStreamData _p = *this ; _p += p ; return _p; } + PointStreamData operator - ( const PointStreamData& p ) const { PointStreamData _p = *this ; _p -= p ; return _p; } + PointStreamData operator * ( Real s ) const { PointStreamData _p = *this ; _p *= s ; return _p; } + PointStreamData operator / ( Real s ) const { PointStreamData _p = *this ; _p /= s ; return _p; } + + static const int PlyReadNum; + static const int PlyWriteNum; + static const PlyProperty* PlyReadProperties( void ); + static const PlyProperty* PlyWriteProperties( void ); + static bool ValidPlyReadProperties( const bool* flags ); }; -template< class Real , int Dim > -struct NormalAndColor +template< class Real , unsigned int Dim > +struct PointStreamPosition : public PointStreamData< Real , Point< Real , Dim > > { - Point< Real , Dim > normal; - Color< Real > color; - NormalAndColor( void ){;} - NormalAndColor( Point< Real , Dim > n , Color< Real > c ) : normal(n) , color(c) {;} + struct Transform + { + Transform( void ){} + Transform( const XForm< Real , Dim+1 >& xForm ) : _xForm(xForm) { } + PointStreamPosition operator() ( const PointStreamPosition& p ) const + { + PointStreamPosition _p; + _p.data = _xForm * p.data; + return _p; + } + protected: + XForm< Real , Dim+1 > _xForm; + }; + static void readASCII( FILE* fp , PointStreamPosition& p ) + { + float f; + for( int i=0 ; i +const PlyProperty PointStreamPosition< float , 2 >::_PlyProperties[] = +{ + { "x" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamPosition , data.coords[0] ) ) , 0 , 0 , 0 , 0 } , +{ "y" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamPosition , data.coords[1] ) ) , 0 , 0 , 0 , 0 } , +}; +template<> +const PlyProperty PointStreamPosition< double , 2 >::_PlyProperties[] = +{ + { "x" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamPosition , data.coords[0] ) ) , 0 , 0 , 0 , 0 } , +{ "y" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamPosition , data.coords[1] ) ) , 0 , 0 , 0 , 0 } , +}; +template<> +const PlyProperty PointStreamPosition< float , 3 >::_PlyProperties[] = +{ + { "x" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamPosition , data.coords[0] ) ) , 0 , 0 , 0 , 0 } , +{ "y" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamPosition , data.coords[1] ) ) , 0 , 0 , 0 , 0 } , +{ "z" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamPosition , data.coords[2] ) ) , 0 , 0 , 0 , 0 } , +}; +template<> +const PlyProperty PointStreamPosition< double , 3 >::_PlyProperties[] = +{ + { "x" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamPosition , data.coords[0] ) ) , 0 , 0 , 0 , 0 } , +{ "y" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamPosition , data.coords[1] ) ) , 0 , 0 , 0 , 0 } , +{ "z" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamPosition , data.coords[2] ) ) , 0 , 0 , 0 , 0 } , +}; +template<> +const PlyProperty PointStreamPosition< float , 4 >::_PlyProperties[] = +{ + { "x" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamPosition , data.coords[0] ) ) , 0 , 0 , 0 , 0 } , +{ "y" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamPosition , data.coords[1] ) ) , 0 , 0 , 0 , 0 } , +{ "z" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamPosition , data.coords[2] ) ) , 0 , 0 , 0 , 0 } , +{ "w" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamPosition , data.coords[3] ) ) , 0 , 0 , 0 , 0 } , +}; +template<> +const PlyProperty PointStreamPosition< double , 4 >::_PlyProperties[] = +{ + { "x" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamPosition , data.coords[0] ) ) , 0 , 0 , 0 , 0 } , +{ "y" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamPosition , data.coords[1] ) ) , 0 , 0 , 0 , 0 } , +{ "z" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamPosition , data.coords[2] ) ) , 0 , 0 , 0 , 0 } , +{ "w" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamPosition , data.coords[3] ) ) , 0 , 0 , 0 , 0 } , }; -template< class Real , int Dim > -struct NormalInfo +template< class Real , unsigned int Dim > +struct PointStreamNormal : public PointStreamData< Real , Point< Real , Dim > > { - typedef Normal< Real , Dim > Type; - static Type ReadASCII( FILE* fp ) + struct Transform { - float n[3]; - if( fscanf( fp , " %f %f %f " , &n[0] , &n[1] , &n[2] )!=3 ) fprintf( stderr , "[ERROR] Failed to read normal\n" ) , exit( 0 ); - return Type( Point< Real , Dim >( n[0] , n[1] , n[2] ) ); + Transform( void ){} + Transform( const XForm< Real , Dim+1 >& xForm ) + { + for( int i=0 ; i _xForm; }; - static bool ReadBinary( FILE* fp , Point< Real , Dim >& p , Type& d ) + static void ReadASCII( FILE* fp , PointStreamNormal& p ) { - struct TypeOnDisk { Point< float , Dim > point , normal; }; - TypeOnDisk t; - if( fread( &t , sizeof(TypeOnDisk) , 1 , fp )!=1 ) return false; - p = Point< Real , Dim >(t.point); - d.normal = Point< Real , Dim >(t.normal); - return true; - } - static void WriteASCII( FILE* fp , const Type& d ) - { - fprintf( fp , " %f %f %f " , d.normal[0] , d.normal[1] , d.normal[2] ); + float f; + for( int i=0 ; i& p , const Type& d ) + static void ReadBinary( FILE* fp , PointStreamNormal& p ) { - struct TypeOnDisk { Point< float , Dim > point , normal; }; - TypeOnDisk t; - t.point = Point< float , Dim >( p ) , t.normal = Point< float , Dim >( d.normal ); - fwrite( &t , sizeof(TypeOnDisk) , 1 , fp ); + float f; + for( int i=0 ; i +const PlyProperty PointStreamNormal< float , 2 >::_PlyProperties[] = +{ + { "nx" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamNormal , data.coords[0] ) ) , 0 , 0 , 0 , 0 } , +{ "ny" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamNormal , data.coords[1] ) ) , 0 , 0 , 0 , 0 } , +}; +template<> +const PlyProperty PointStreamNormal< double , 2 >::_PlyProperties[] = +{ + { "nx" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamNormal , data.coords[0] ) ) , 0 , 0 , 0 , 0 } , +{ "ny" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamNormal , data.coords[1] ) ) , 0 , 0 , 0 , 0 } , +}; +template<> +const PlyProperty PointStreamNormal< float , 3 >::_PlyProperties[] = +{ + { "nx" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamNormal , data.coords[0] ) ) , 0 , 0 , 0 , 0 } , +{ "ny" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamNormal , data.coords[1] ) ) , 0 , 0 , 0 , 0 } , +{ "nz" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamNormal , data.coords[2] ) ) , 0 , 0 , 0 , 0 } , +}; +template<> +const PlyProperty PointStreamNormal< double , 3 >::_PlyProperties[] = +{ + { "nx" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamNormal , data.coords[0] ) ) , 0 , 0 , 0 , 0 } , +{ "ny" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamNormal , data.coords[1] ) ) , 0 , 0 , 0 , 0 } , +{ "nz" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamNormal , data.coords[2] ) ) , 0 , 0 , 0 , 0 } , +}; +template<> +const PlyProperty PointStreamNormal< float , 4 >::_PlyProperties[] = +{ + { "nx" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamNormal , data.coords[0] ) ) , 0 , 0 , 0 , 0 } , +{ "ny" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamNormal , data.coords[1] ) ) , 0 , 0 , 0 , 0 } , +{ "nz" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamNormal , data.coords[2] ) ) , 0 , 0 , 0 , 0 } , +{ "nw" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamNormal , data.coords[3] ) ) , 0 , 0 , 0 , 0 } , +}; +template<> +const PlyProperty PointStreamNormal< double , 4 >::_PlyProperties[] = +{ + { "nx" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamNormal , data.coords[0] ) ) , 0 , 0 , 0 , 0 } , +{ "ny" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamNormal , data.coords[1] ) ) , 0 , 0 , 0 , 0 } , +{ "nz" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamNormal , data.coords[2] ) ) , 0 , 0 , 0 , 0 } , +{ "nw" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamNormal , data.coords[3] ) ) , 0 , 0 , 0 , 0 } , +}; - template< class Vertex > - struct VertexSetter +template< class Real > +struct PointStreamColor : public PointStreamData< Real , Color< Real > > +{ + struct Transform { - static void SetValue( Vertex& v , Real w ){ ; } - static void SetData ( Vertex& v , const Type& nc ){ ; } + Transform( void ){} + template< typename X > Transform( const X& ){} + PointStreamColor operator() ( const PointStreamColor& c ) const { return c; } }; - template< bool HasNormal , bool HasValue , bool HasColor > - struct VertexSetter< FullPlyVertex< float , Dim , HasNormal , HasValue , HasColor > > + static void ReadASCII( FILE* fp , PointStreamColor& p ) { - typedef FullPlyVertex< float , Dim , HasNormal , HasValue , HasColor > Vertex; - static void SetValue( Vertex& v , Real w ){ if( HasValue ) v.value() = (float)w; } - static void SetData ( Vertex& v , const Type& nc ){ if( HasNormal ) v.normal() = Point< Real , Dim >( nc.normal ); } + unsigned char c[3]; + if( fscanf( fp , " %c %c %c " , &c[0] , &c[1] , &c[2] )!=3 ) fprintf( stderr , "[ERROR] PointStreamColor::readASCII: Failed to read color\n" ) , exit( 0 ); + p.data[0] = (Real)c[0] , p.data[1] = (Real)c[1] , p.data[2] = (Real)c[2]; }; + static void ReadBinary( FILE* fp , PointStreamColor& p ) + { + unsigned char c[3]; + if( fread( c , sizeof(unsigned char) , 3 , fp )!=3 ) fprintf( stderr , "[ERROR] PointStreamColor::readBinary: Failed to read color\n" ) , exit( 0 ); + p.data[0] = (Real)c[0] , p.data[1] = (Real)c[1] , p.data[2] = (Real)c[2]; + } + static void WriteASCII( FILE* fp , const PointStreamColor& p ) + { + unsigned char c[3]; + SetColorValues( p.data , c ); + fprintf( fp , " %d %d %d " , c[0] , c[1] , c[2] ); + }; + static void WriteBinary( FILE* fp , const PointStreamColor& p ) + { + unsigned char c[3]; + SetColorValues( p.data , c ); + fwrite( c , sizeof(unsigned char) , 3 , fp ); + } + static const int PlyReadNum = 6; + static const int PlyWriteNum = 3; + static const PlyProperty* PlyReadProperties( void ){ return _PlyProperties; } + static const PlyProperty* PlyWriteProperties( void ){ return _PlyProperties; } + static bool ValidPlyReadProperties( const bool* flags ){ for( int d=0 ; d<3 ; d++ ) if( !flags[d] && !flags[d+3] ) return false ; return true ; } +protected: + static const PlyProperty _PlyProperties[]; +}; +template<> +const PlyProperty PointStreamColor< float >::_PlyProperties[] = +{ + { "red" , PLY_UCHAR , PLY_FLOAT , int( offsetof( PointStreamColor , data.coords[0] ) ) , 0 , 0 , 0 , 0 } , +{ "green" , PLY_UCHAR , PLY_FLOAT , int( offsetof( PointStreamColor , data.coords[1] ) ) , 0 , 0 , 0 , 0 } , +{ "blue" , PLY_UCHAR , PLY_FLOAT , int( offsetof( PointStreamColor , data.coords[2] ) ) , 0 , 0 , 0 , 0 } , +{ "r" , PLY_UCHAR , PLY_FLOAT , int( offsetof( PointStreamColor , data.coords[0] ) ) , 0 , 0 , 0 , 0 } , +{ "g" , PLY_UCHAR , PLY_FLOAT , int( offsetof( PointStreamColor , data.coords[1] ) ) , 0 , 0 , 0 , 0 } , +{ "b" , PLY_UCHAR , PLY_FLOAT , int( offsetof( PointStreamColor , data.coords[2] ) ) , 0 , 0 , 0 , 0 } , +}; +template<> +const PlyProperty PointStreamColor< double >::_PlyProperties[] = +{ + { "red" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( PointStreamColor , data.coords[0] ) ) , 0 , 0 , 0 , 0 } , +{ "green" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( PointStreamColor , data.coords[1] ) ) , 0 , 0 , 0 , 0 } , +{ "blue" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( PointStreamColor , data.coords[2] ) ) , 0 , 0 , 0 , 0 } , +{ "r" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( PointStreamColor , data.coords[0] ) ) , 0 , 0 , 0 , 0 } , +{ "g" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( PointStreamColor , data.coords[1] ) ) , 0 , 0 , 0 , 0 } , +{ "b" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( PointStreamColor , data.coords[2] ) ) , 0 , 0 , 0 , 0 } , +}; - static Real ProcessDataWithConfidence( const Point< Real , Dim >& p , Type& data ) +template< class Real > +struct PointStreamValue : public PointStreamData< Real , Real > +{ + struct Transform { - Real l = (Real)Length( data.normal ); - if( !l || l!=l ) return (Real)-1.; - return l; - } - static Real ProcessData( const Point< Real , Dim >& p , Type& data ) + Transform( void ){} + template< typename X > Transform( const X& ){} + PointStreamValue operator() ( const PointStreamValue& r ) const { return r; } + }; + static void ReadASCII ( FILE* fp , PointStreamValue& p ){ float f ; if( fscanf( fp , " %f " , &f )!=1 ) fprintf( stderr , "[ERROR] PointStreamValue::readASCII: Failed to read color\n" ) , exit( 0 ) ; p.data = (Real)f; } + static void ReadBinary( FILE* fp , PointStreamValue& p ){ float f ; if( fread( &f , sizeof(float) , 1 , fp )!=1 ) fprintf( stderr , "[ERROR] PointStreamValue::readBinary: Failed to read color\n" ) , exit( 0 ) ; p.data = (Real)f; } + static void WriteASCII ( FILE* fp , const PointStreamValue& p ){ float f = (float)p.data ; fprintf( fp , " %f " , f ); } + static void WriteBinary( FILE* fp , const PointStreamValue& p ){ float f = (float)p.data ; fwrite( &f , sizeof(Real) , 1 , fp ); } + static const int PlyReadNum = 1; + static const int PlyWriteNum = 1; + static const PlyProperty* PlyReadProperties( void ){ return _PlyProperties; } + static const PlyProperty* PlyWriteProperties( void ){ return _PlyProperties; } + static bool ValidPlyReadProperties( const bool* flags ){ if( !flags[0] ) return false ; return true ; } +public: + static const PlyProperty _PlyProperties[]; +}; +template<> +const PlyProperty PointStreamValue< float >::_PlyProperties[] = +{ + { "value" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamValue , data ) ) , 0 , 0 , 0 , 0 } , +}; +template<> +const PlyProperty PointStreamValue< double >::_PlyProperties[] = +{ + { "value" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamValue , data ) ) , 0 , 0 , 0 , 0 } , +}; +template< class Real > +struct PointStreamRoughness : public PointStreamData< Real , Real > +{ + struct Transform { - Real l = (Real)Length( data.normal ); - if( !l || l!=l ) return (Real)-1.; - data.normal /= l; - return (Real)1.; - } + Transform( void ){} + template< typename X > Transform( const X& ){} + PointStreamRoughness operator() ( const PointStreamRoughness& r ) const { return r; } + }; + static void ReadASCII ( FILE* fp , PointStreamRoughness& p ){ float f ; if( fscanf( fp , " %f " , &f )!=1 ) fprintf( stderr , "[ERROR] PointStreamRoughness::readASCII: Failed to read color\n" ) , exit( 0 ) ; p.data = (Real)f; } + static void ReadBinary( FILE* fp , PointStreamRoughness& p ){ float f ; if( fread( &f , sizeof(float) , 1 , fp )!=1 ) fprintf( stderr , "[ERROR] PointStreamRoughness::readBinary: Failed to read color\n" ) , exit( 0 ) ; p.data = (Real)f; } + static void WriteASCII ( FILE* fp , const PointStreamRoughness& p ){ float f = (float)p.data ; fprintf( fp , " %f " , f ); } + static void WriteBinary( FILE* fp , const PointStreamRoughness& p ){ float f = (float)p.data ; fwrite( &f , sizeof(Real) , 1 , fp ); } + static const int PlyReadNum = 1; + static const int PlyWriteNum = 1; + static const PlyProperty* PlyReadProperties( void ){ return _PlyProperties; } + static const PlyProperty* PlyWriteProperties( void ){ return _PlyProperties; } + static bool ValidPlyReadProperties( const bool* flags ){ if( !flags[0] ) return false ; return true ; } +public: + static const PlyProperty _PlyProperties[]; +}; +template<> +const PlyProperty PointStreamRoughness< float >::_PlyProperties[] = +{ + { "rg" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamRoughness , data ) ) , 0 , 0 , 0 , 0 } , +}; +template<> +const PlyProperty PointStreamRoughness< double >::_PlyProperties[] = +{ + { "rg" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamRoughness , data ) ) , 0 , 0 , 0 , 0 } , +}; + +template< typename Real , typename ... Data > +struct MultiPointStreamData : public PointStreamData< Real , std::tuple< Data ... > > +{ + typedef std::tuple< Data ... > MultiData; + using PointStreamData< Real , MultiData >::data; + template< unsigned int I > using DataType = typename std::tuple_element< I , MultiData >::type; struct Transform { - Transform( const XForm< Real , Dim+1 >& xForm ) : _pointXForm( xForm ) + Transform( void ){} + template< typename X > + Transform( const X& x ){ _initTransforms<0>( x ); } + MultiPointStreamData operator() ( const MultiPointStreamData& d ) const { - for( int i=0 ; i( d , _d ); + return _d; } - void operator()( Point< Real , Dim >& p , Type& n ) const { p = _pointXForm * p , n.normal = _normalXForm * n.normal; } protected: - XForm< Real , Dim+1 > _pointXForm; - XForm< Real , Dim > _normalXForm; - }; -}; -template<> -const PlyProperty NormalInfo< float , 3 >::PlyProperties[] = -{ - { "nx" , PLY_FLOAT , PLY_FLOAT , int( offsetof( Type , normal.coords[0] ) ) , 0 , 0 , 0 , 0 } , - { "ny" , PLY_FLOAT , PLY_FLOAT , int( offsetof( Type , normal.coords[1] ) ) , 0 , 0 , 0 , 0 } , - { "nz" , PLY_FLOAT , PLY_FLOAT , int( offsetof( Type , normal.coords[2] ) ) , 0 , 0 , 0 , 0 } , -}; -template<> -const PlyProperty NormalInfo< double , 3 >::PlyProperties[] = -{ - { "nx" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( Type , normal.coords[0] ) ) , 0 , 0 , 0 , 0 } , - { "ny" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( Type , normal.coords[1] ) ) , 0 , 0 , 0 , 0 } , - { "nz" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( Type , normal.coords[2] ) ) , 0 , 0 , 0 , 0 } , -}; - -template< class Real , int Dim > -struct NormalAndColorInfo -{ - typedef NormalAndColor< Real , Dim > Type; - - static Type ReadASCII( FILE* fp ) - { - float n[3]; - unsigned char c[3]; - if( fscanf( fp , " %f %f %f %c %c %c " , &n[0] , &n[1] , &n[2] , &c[0] , &c[1] , &c[2] )!=6 ) fprintf( stderr , "[ERROR] Failed to read normal and color\n" ) , exit( 0 ); - return Type( Point< Real , Dim >( n[0] , n[1] , n[2] ) , Color< Real >( (Real)c[0] , (Real)c[1] , (Real)c[2] ) ); + typedef std::tuple< typename Data::Transform ... > Transforms; + template< unsigned int I > using TransformType = typename std::tuple_element< I , Transforms >::type; + Transforms _xForms; + private: + template< unsigned int I , typename X > + typename std::enable_if< I!=sizeof...(Data) >::type _initTransforms( const X& x ){ std::get< I >( _xForms ) = TransformType< I >( x ) ; _initTransforms< I+1 >( x ); } + template< unsigned int I , typename X > + typename std::enable_if< I==sizeof...(Data) >::type _initTransforms( const X& x ){ } + template< unsigned int I > + typename std::enable_if< I!=sizeof...(Data) >::type _transform( const MultiPointStreamData& in , MultiPointStreamData& out ) const { std::get< I >( out.data ) = std::get< I >( _xForms )( std::get< I >( in.data ) ) ; _transform< I+1 >( in , out ); } + template< unsigned int I > + typename std::enable_if< I==sizeof...(Data) >::type _transform( const MultiPointStreamData& in , MultiPointStreamData& out ) const { } }; - static bool ReadBinary( FILE* fp , Point< Real , Dim >& p , Type& d ) + static void ReadASCII ( FILE* fp , MultiPointStreamData& p ){ p._readASCII <0>( fp ); } + static void ReadBinary( FILE* fp , MultiPointStreamData& p ){ p._readBinary<0>( fp ); } + static void WriteASCII ( FILE* fp , const MultiPointStreamData& p ){ p._writeASCII <0>( fp ); } + static void WriteBinary( FILE* fp , const MultiPointStreamData& p ){ p._writeBinary<0>( fp ); } + + MultiPointStreamData& operator += ( const MultiPointStreamData& p ){ _add<0>( p ) ; return *this; } + MultiPointStreamData& operator -= ( const MultiPointStreamData& p ){ _sub<0>( p ) ; return *this; } + MultiPointStreamData& operator *= ( Real s ) { _mul<0>( s ) ; return *this; } + MultiPointStreamData& operator /= ( Real s ) { _div<0>( s ) ; return *this; } + MultiPointStreamData operator + ( const MultiPointStreamData& p ) const { MultiPointStreamData _p = *this ; _p += p ; return _p; } + MultiPointStreamData operator - ( const MultiPointStreamData& p ) const { MultiPointStreamData _p = *this ; _p -= p ; return _p; } + MultiPointStreamData operator * ( Real s ) const { MultiPointStreamData _p = *this ; _p *= s ; return _p; } + MultiPointStreamData operator / ( Real s ) const { MultiPointStreamData _p = *this ; _p /= s ; return _p; } + +private: + template< unsigned int I > static constexpr typename std::enable_if< I!=sizeof...(Data) , int >::type _PlyTotalReadNum( void ){ return DataType< I >::PlyReadNum + _PlyTotalReadNum< I+1 >(); } + template< unsigned int I > static constexpr typename std::enable_if< I==sizeof...(Data) , int >::type _PlyTotalReadNum( void ){ return 0; } + template< unsigned int I > static constexpr typename std::enable_if< I!=sizeof...(Data) , int >::type _PlyTotalWriteNum( void ){ return DataType< I >::PlyWriteNum + _PlyTotalWriteNum< I+1 >(); } + template< unsigned int I > static constexpr typename std::enable_if< I==sizeof...(Data) , int >::type _PlyTotalWriteNum( void ){ return 0; } +public: + static const int PlyReadNum = _PlyTotalReadNum<0>(); + static const int PlyWriteNum = _PlyTotalWriteNum<0>(); + static PlyProperty* PlyReadProperties( void ){ _SetPlyReadProperties<0>( _PlyReadProperties ) ; return _PlyReadProperties; } + static PlyProperty* PlyWriteProperties( void ){ _SetPlyWriteProperties<0>( _PlyWriteProperties ) ; return _PlyWriteProperties; } + + static bool ValidPlyReadProperties( const bool* flags ){ return _ValidPlyReadProperties<0>( flags ) ; } + template< unsigned int I > static bool ValidPlyReadProperties( const bool* flags ){ return DataType< I >::ValidPlyReadProperties( flags + _PlyReadNum< I >() ); } +protected: + static PlyProperty _PlyReadProperties[]; + static PlyProperty _PlyWriteProperties[]; +private: + template< unsigned int I , unsigned int _I=0 > static typename std::enable_if< I==_I , unsigned int >::type _PlyReadNum( void ){ return 0; } + template< unsigned int I , unsigned int _I=0 > static typename std::enable_if< I!=_I , unsigned int >::type _PlyReadNum( void ){ return DataType< I >::PlyReadNum + _PlyReadNum< I , _I+1 >(); } + + template< unsigned int I > typename std::enable_if< I!=sizeof...(Data) >::type _readASCII ( FILE* fp ) { DataType< I >:: ReadASCII ( fp , std::get< I >( data ) ) ; _readASCII < I+1 >( fp ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Data) >::type _readASCII ( FILE* fp ) { } + template< unsigned int I > typename std::enable_if< I!=sizeof...(Data) >::type _readBinary( FILE* fp ) { DataType< I >:: ReadBinary( fp , std::get< I >( data ) ) ; _readBinary< I+1 >( fp ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Data) >::type _readBinary( FILE* fp ) { } + template< unsigned int I > typename std::enable_if< I!=sizeof...(Data) >::type _writeASCII ( FILE* fp ) const { DataType< I >::WriteASCII ( fp , std::get< I >( data ) ) ; _writeASCII < I+1 >( fp ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Data) >::type _writeASCII ( FILE* fp ) const { } + template< unsigned int I > typename std::enable_if< I!=sizeof...(Data) >::type _writeBinary( FILE* fp ) const { DataType< I >::WriteBinary( fp , std::get< I >( data ) ) ; _writeBinary< I+1 >( fp ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Data) >::type _writeBinary( FILE* fp ) const { } + + template< unsigned int I > typename std::enable_if< I!=sizeof...(Data) >::type _add( const MultiPointStreamData& p ){ std::get< I >( data ) += std::get< I >( p.data ) ; _add< I+1 >( p ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Data) >::type _add( const MultiPointStreamData& p ){ } + template< unsigned int I > typename std::enable_if< I!=sizeof...(Data) >::type _sub( const MultiPointStreamData& p ){ std::get< I >( data ) -= std::get< I >( p.data ) ; _sub< I+1 >( p ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Data) >::type _sub( const MultiPointStreamData& p ){ } + template< unsigned int I > typename std::enable_if< I!=sizeof...(Data) >::type _mul( Real s ){ std::get< I >( data ) *= s ; _mul< I+1 >( s ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Data) >::type _mul( Real s ){ } + template< unsigned int I > typename std::enable_if< I!=sizeof...(Data) >::type _div( Real s ){ std::get< I >( data ) /= s ; _div< I+1 >( s ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Data) >::type _div( Real s ){ } + + template< unsigned int I > static typename std::enable_if< I!=sizeof...(Data) >::type _SetPlyReadProperties( PlyProperty* PlyReadProperties ) { - struct TypeOnDisk + for( int d=0 ; d::PlyReadNum ; d++ ) { - Point< float , Dim > point; - Point< float , Dim > normal; - unsigned char color[3]; - }; - TypeOnDisk t; - if( fread( &t , sizeof( TypeOnDisk ) , 1 , fp )!=1 ) return false; - p = Point< Real , Dim >(t.point); - d.normal = Point< Real , Dim >(t.normal); - for( int c=0 ; c<3 ; c++ ) d.color[c] = (Real)t.color[c]; - return true; - } - static void WriteASCII( FILE* fp , const Type& d ) - { - unsigned char c[3]; - SetColorValues( d.color , c ); - fprintf( fp , " %f %f %f %d %d %d " , d.normal[0] , d.normal[1] , d.normal[2] , c[0] , c[1] , c[2] ); - }; - static void WriteBinary( FILE* fp , const Point< Real , Dim >& p , const Type& d ) - { - struct TypeOnDisk - { - Point< float , Dim > point; - Point< float , Dim > normal; - unsigned char color[3]; - }; - TypeOnDisk t; - t.point = Point< float , Dim >( p ) , t.normal = Point< float , Dim >( d.normal ); - SetColorValues( d.color , t.color ); - fwrite( &t , sizeof(TypeOnDisk) , 1 , fp ); - } - - static bool ValidPlyProperties( const bool* props ){ return ( props[0] && props[1] && props[2] ) && ( ( props[3] || props[6] ) && ( props[4] || props[7] ) && ( props[5] || props[8] ) ); } - const static PlyProperty PlyProperties[]; - const static int PlyPropertyNum = 9; - - template< class Vertex > - struct VertexSetter - { - static void SetValue( Vertex& v , Real w ){} - static void SetData ( Vertex& v , const Type& nc ){} - }; - template< bool HasNormal , bool HasValue , bool HasColor > - struct VertexSetter< FullPlyVertex< float , Dim , HasNormal , HasValue , HasColor > > - { - typedef FullPlyVertex< float , Dim , HasNormal , HasValue , HasColor > Vertex; - static void SetValue( Vertex& v , Real w ){ if( HasValue ) v.value() = (float)w; } - static void SetData ( Vertex& v , const Type& nc ) - { - if( HasNormal ) v.normal() = Point< Real , Dim >( nc.normal ); - if( HasColor ) SetColorValues( nc.color , v.color() ); + PlyReadProperties[d] = DataType< I >::PlyReadProperties()[d]; + MultiPointStreamData temp; + const typename std::tuple_element< I , MultiData >::type& temp_data = std::get< I >( temp.data ); + PlyReadProperties[d].offset += (int)( (size_t)&temp_data - (size_t)&temp ); } - }; - - static Real ProcessDataWithConfidence( const Point< Real , Dim >& p , Type& data ) - { - Real l = (Real)Length( data.normal ); - if( !l || l!=l ) return (Real)-1.; - return l; + _SetPlyReadProperties< I+1 >( PlyReadProperties + DataType< I >::PlyReadNum ); } - static Real ProcessData( const Point< Real , Dim >& p , Type& data ) + template< unsigned int I > static typename std::enable_if< I==sizeof...(Data) >::type _SetPlyReadProperties( PlyProperty* PlyReadProperties ){ } + template< unsigned int I > static typename std::enable_if< I!=sizeof...(Data) >::type _SetPlyWriteProperties( PlyProperty* PlyWriteProperties ) { - Real l = (Real)Length( data.normal ); - if( !l || l!=l ) return (Real)-1.; - data.normal /= l; - return (Real)1.; - } - - struct Transform - { - Transform( const XForm< Real , Dim+1 >& xForm ) : _pointXForm( xForm ) + for( int d=0 ; d::PlyWriteNum ; d++ ) { - for( int i=0 ; i::PlyWriteProperties()[d]; + MultiPointStreamData temp; + const typename std::tuple_element< I , MultiData >::type& temp_data = std::get< I >( temp.data ); + PlyWriteProperties[d].offset += (int)( (size_t)&temp_data - (size_t)&temp ); } - void operator()( Point< Real , Dim >& p , Type& nc ) const { p = _pointXForm * p , nc.normal = _normalXForm * nc.normal; } - protected: - XForm< Real , Dim+1 > _pointXForm; - XForm< Real , Dim > _normalXForm; - }; -}; -template<> -const PlyProperty NormalAndColorInfo< float , 3 >::PlyProperties[] = -{ - { "nx" , PLY_FLOAT , PLY_FLOAT , int( offsetof( Type , normal.coords[0] ) ) , 0 , 0 , 0 , 0 } , - { "ny" , PLY_FLOAT , PLY_FLOAT , int( offsetof( Type , normal.coords[1] ) ) , 0 , 0 , 0 , 0 } , - { "nz" , PLY_FLOAT , PLY_FLOAT , int( offsetof( Type , normal.coords[2] ) ) , 0 , 0 , 0 , 0 } , - { "r" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Type , color .coords[0] ) ) , 0 , 0 , 0 , 0 } , - { "g" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Type , color .coords[1] ) ) , 0 , 0 , 0 , 0 } , - { "b" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Type , color .coords[2] ) ) , 0 , 0 , 0 , 0 } , - { "red" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Type , color .coords[0] ) ) , 0 , 0 , 0 , 0 } , - { "green" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Type , color .coords[1] ) ) , 0 , 0 , 0 , 0 } , - { "blue" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Type , color .coords[2] ) ) , 0 , 0 , 0 , 0 } -}; -template<> -const PlyProperty NormalAndColorInfo< double , 3 >::PlyProperties[] = -{ - { "nx" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( Type , normal.coords[0] ) ) , 0 , 0 , 0 , 0 } , - { "ny" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( Type , normal.coords[1] ) ) , 0 , 0 , 0 , 0 } , - { "nz" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( Type , normal.coords[2] ) ) , 0 , 0 , 0 , 0 } , - { "r" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Type , color .coords[0] ) ) , 0 , 0 , 0 , 0 } , - { "g" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Type , color .coords[1] ) ) , 0 , 0 , 0 , 0 } , - { "b" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Type , color .coords[2] ) ) , 0 , 0 , 0 , 0 } , - { "red" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Type , color .coords[0] ) ) , 0 , 0 , 0 , 0 } , - { "green" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Type , color .coords[1] ) ) , 0 , 0 , 0 , 0 } , - { "blue" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Type , color .coords[2] ) ) , 0 , 0 , 0 , 0 } + _SetPlyWriteProperties< I+1 >( PlyWriteProperties + DataType< I >::PlyWriteNum ); + } + template< unsigned int I > static typename std::enable_if< I==sizeof...(Data) >::type _SetPlyWriteProperties( PlyProperty* PlyWriteProperties ){ } + + template< unsigned int I > static typename std::enable_if< I!=sizeof...(Data) , bool >::type _ValidPlyReadProperties( const bool* flags ){ return DataType< I >::ValidPlyReadProperties( flags ) && _ValidPlyReadProperties< I+1 >( flags + std::tuple_element< I , MultiData >::type::PlyReadNum ); } + template< unsigned int I > static typename std::enable_if< I==sizeof...(Data) , bool >::type _ValidPlyReadProperties( const bool* flags ){ return true; } }; +template< typename Real , typename ... Data > PlyProperty MultiPointStreamData< Real , Data ... >::_PlyReadProperties[ MultiPointStreamData< Real , Data ... >::PlyReadNum==0 ? 1 : MultiPointStreamData< Real , Data ... >::PlyReadNum ]; +template< typename Real , typename ... Data > PlyProperty MultiPointStreamData< Real , Data ... >::_PlyWriteProperties[ MultiPointStreamData< Real , Data ... >::PlyWriteNum==0 ? 1 : MultiPointStreamData< Real , Data ... >::PlyWriteNum ]; + #endif // POINT_STREAM_DATA_INCLUDED \ No newline at end of file diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index 2c5a4f0..958b19f 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -290,7 +290,54 @@ struct SystemDual< Dim , double > CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim >& p , const CumulativeDerivativeValues< Real , Dim , 0 >& dValues ) const { return dValues * weight; }; }; -template< class Real , class StreamDataInfo , class Vertex , unsigned int ... FEMSigs > +template< typename Vertex , typename Real , unsigned int ... FEMSigs , typename ... SampleData > +void ExtractMesh( UIntPack< FEMSigs ... > , std::tuple< SampleData ... > , FEMTree< sizeof ... ( FEMSigs ) , Real >& tree , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& solution , Real isoValue , const std::vector< typename FEMTree< sizeof ... ( FEMSigs ) , Real >::PointSample >* samples , std::vector< MultiPointStreamData< Real , PointStreamNormal< Real , DIMENSION > , MultiPointStreamData< Real , SampleData ... > > >* sampleData , const typename FEMTree< sizeof ... ( FEMSigs ) , Real >::template DensityEstimator< WEIGHT_DEGREE >* density , std::function< void ( Vertex& , Point< Real , DIMENSION > , Real , MultiPointStreamData< Real , PointStreamNormal< Real , DIMENSION > , MultiPointStreamData< Real , SampleData ... > > ) > SetVertex , std::vector< char* > comments , XForm< Real , sizeof...(FEMSigs)+1 > iXForm ) +{ + static const int Dim = sizeof ... ( FEMSigs ); + typedef UIntPack< FEMSigs ... > Sigs; + typedef PointStreamNormal< Real , Dim > NormalPointSampleData; + typedef MultiPointStreamData< Real , SampleData ... > AdditionalPointSampleData; + typedef MultiPointStreamData< Real , NormalPointSampleData , AdditionalPointSampleData > TotalPointSampleData; + static const unsigned int DataSig = FEMDegreeAndBType< DATA_DEGREE , BOUNDARY_FREE >::Signature; + typedef typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; + + FEMTreeProfiler< Dim , Real > profiler( tree ); + + char tempHeader[1024]; + { + char tempPath[1024]; + tempPath[0] = 0; + if( TempDir.set ) strcpy( tempPath , TempDir.value ); + else SetTempDirectory( tempPath , sizeof(tempPath) ); + if( strlen(tempPath)==0 ) sprintf( tempPath , ".%c" , FileSeparator ); + if( tempPath[ strlen( tempPath )-1 ]==FileSeparator ) sprintf( tempHeader , "%sPR_" , tempPath ); + else sprintf( tempHeader , "%s%cPR_" , tempPath , FileSeparator ); + } + CoredFileMeshData< Vertex > mesh( tempHeader ); + + profiler.start(); + typename IsoSurfaceExtractor< Dim , Real , Vertex >::IsoStats isoStats; + if( sampleData ) + { + SparseNodeData< ProjectiveData< TotalPointSampleData , Real > , IsotropicUIntPack< Dim , DataSig > > _sampleData = tree.template setDataField< DataSig , false >( *samples , *sampleData , (DensityEstimator*)NULL ); + for( const RegularTreeNode< Dim , FEMTreeNodeData >* n = tree.tree().nextNode() ; n ; n=tree.tree().nextNode( n ) ) + { + ProjectiveData< TotalPointSampleData , Real >* clr = _sampleData( n ); + if( clr ) (*clr) *= (Real)pow( DataX.value , tree.depth( n ) ); + } + isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< TotalPointSampleData >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , &_sampleData , solution , isoValue , mesh , SetVertex , !LinearFit.set , !NonManifold.set , PolygonMesh.set , false ); + } + else isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< TotalPointSampleData >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , NULL , solution , isoValue , mesh , SetVertex , !LinearFit.set , !NonManifold.set , PolygonMesh.set , false ); + messageWriter( "Vertices / Polygons: %d / %d\n" , mesh.outOfCorePointCount()+mesh.inCorePoints.size() , mesh.polygonCount() ); + messageWriter( "Corners / Vertices / Edges / Surface / Set Table / Copy Finer: %.1f / %.1f / %.1f / %.1f / %.1f / %.1f (s)\n" , isoStats.cornersTime , isoStats.verticesTime , isoStats.edgesTime , isoStats.surfaceTime , isoStats.setTableTime , isoStats.copyFinerTime ); + if( PolygonMesh.set ) profiler.dumpOutput2( comments , "# Got polygons:" ); + else profiler.dumpOutput2( comments , "# Got triangles:" ); + + if( NoComments.set ) PlyWritePolygons< Vertex , Real , Dim >( Out.value , &mesh , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , NULL , 0 , iXForm ); + else PlyWritePolygons< Vertex , Real , Dim >( Out.value , &mesh , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , &comments[0] , (int)comments.size() , iXForm ); +} + +template< class Real , typename ... SampleData , unsigned int ... FEMSigs > int Execute( int argc , char* argv[] , UIntPack< FEMSigs ... > ) { static const int Dim = sizeof ... ( FEMSigs ); @@ -298,11 +345,13 @@ int Execute( int argc , char* argv[] , UIntPack< FEMSigs ... > ) typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > Degrees; typedef UIntPack< FEMDegreeAndBType< NORMAL_DEGREE , DerivativeBoundary< FEMSignature< FEMSigs >::BType , 1 >::BType >::Signature ... > NormalSigs; static const unsigned int DataSig = FEMDegreeAndBType< DATA_DEGREE , BOUNDARY_FREE >::Signature; - typedef Point< Real , 3 > Color; typedef typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; typedef typename FEMTree< Dim , Real >::template InterpolationInfo< Real , 0 > InterpolationInfo; - typedef InputPointStreamWithData< Real , Dim , typename StreamDataInfo::Type > InputPointStream; - typedef TransformedInputPointStreamWithData< Real , Dim , typename StreamDataInfo::Type > XInputPointStream; + typedef PointStreamNormal< Real , Dim > NormalPointSampleData; + typedef MultiPointStreamData< Real , SampleData ... > AdditionalPointSampleData; + typedef MultiPointStreamData< Real , NormalPointSampleData , AdditionalPointSampleData > TotalPointSampleData; + typedef InputPointStreamWithData< Real , Dim , TotalPointSampleData > InputPointStream; + typedef TransformedInputPointStreamWithData< Real , Dim , TotalPointSampleData > XInputPointStream; std::vector< char* > comments; messageWriter( comments , "*************************************************************\n" ); messageWriter( comments , "*************************************************************\n" ); @@ -357,7 +406,7 @@ int Execute( int argc , char* argv[] , UIntPack< FEMSigs ... > ) Real pointWeightSum; std::vector< typename FEMTree< Dim , Real >::PointSample >* samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); - std::vector< typename StreamDataInfo::Type >* sampleData = NULL; + std::vector< TotalPointSampleData >* sampleData = NULL; DensityEstimator* density = NULL; SparseNodeData< Point< Real , Dim > , NormalSigs >* normalInfo = NULL; Real targetValue = (Real)0.5; @@ -367,18 +416,33 @@ int Execute( int argc , char* argv[] , UIntPack< FEMSigs ... > ) profiler.start(); InputPointStream* pointStream; char* ext = GetFileExtension( In.value ); - sampleData = new std::vector< typename StreamDataInfo::Type >(); - if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryInputPointStreamWithData< Real , Dim , typename StreamDataInfo::Type >( In.value , StreamDataInfo::ReadBinary ); - else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYInputPointStreamWithData< Real , Dim , typename StreamDataInfo::Type >( In.value , StreamDataInfo::PlyProperties , StreamDataInfo::PlyPropertyNum , StreamDataInfo::ValidPlyProperties ); - else pointStream = new ASCIIInputPointStreamWithData< Real , Dim , typename StreamDataInfo::Type >( In.value , StreamDataInfo::ReadASCII ); + sampleData = new std::vector< TotalPointSampleData >(); + if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::ReadBinary ); + else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::PlyReadProperties() , TotalPointSampleData::PlyReadNum , TotalPointSampleData::ValidPlyReadProperties ); + else pointStream = new ASCIIInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::ReadASCII ); delete[] ext; - XInputPointStream _pointStream( typename StreamDataInfo::Transform( xForm ) , *pointStream ); + typename TotalPointSampleData::Transform _xForm( xForm ); + XInputPointStream _pointStream( [&]( Point< Real , Dim >& p , TotalPointSampleData& d ){ p = xForm*p , d = _xForm(d); } , *pointStream ); if( Width.value>0 ) xForm = GetPointXForm< Real , Dim >( _pointStream , Width.value , (Real)( Scale.value>0 ? Scale.value : 1. ) , Depth.value ) * xForm; else xForm = Scale.value>0 ? GetPointXForm< Real , Dim >( _pointStream , (Real)Scale.value ) * xForm : xForm; { - XInputPointStream _pointStream( typename StreamDataInfo::Transform( xForm ) , *pointStream ); - if( Confidence.value>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< typename StreamDataInfo::Type >( tree.spaceRoot() , _pointStream , Depth.value , *samples , *sampleData , true , tree.nodeAllocator , tree.initializer() , [&]( const Point< Real , Dim >&p , typename StreamDataInfo::Type& d ){ return (Real)pow( StreamDataInfo::ProcessDataWithConfidence( p , d ) , Confidence.value ); } ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< typename StreamDataInfo::Type >( tree.spaceRoot() , _pointStream , Depth.value , *samples , *sampleData , true , tree.nodeAllocator , tree.initializer() , StreamDataInfo::ProcessData ); + typename TotalPointSampleData::Transform _xForm( xForm ); + XInputPointStream _pointStream( [&]( Point< Real , Dim >& p , TotalPointSampleData& d ){ p = xForm*p , d = _xForm(d); } , *pointStream ); + auto ProcessDataWithConfidence = [&]( const Point< Real , Dim >& p , TotalPointSampleData& d ) + { + Real l = (Real)Length( std::get< 0 >( d.data ).data ); + if( !l || l!=l ) return (Real)-1.; + return (Real)pow( l , Confidence.value ); + }; + auto ProcessData = []( const Point< Real , Dim >& p , TotalPointSampleData& d ) + { + Real l = (Real)Length( std::get< 0 >( d.data ).data ); + if( !l || l!=l ) return (Real)-1.; + std::get< 0 >( d.data ).data /= l; + return (Real)1.; + }; + if( Confidence.value>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< TotalPointSampleData >( tree.spaceRoot() , _pointStream , Depth.value , *samples , *sampleData , true , tree.nodeAllocator , tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< TotalPointSampleData >( tree.spaceRoot() , _pointStream , Depth.value , *samples , *sampleData , true , tree.nodeAllocator , tree.initializer() , ProcessData ); } iXForm = xForm.inverse(); delete pointStream; @@ -533,48 +597,37 @@ int Execute( int argc , char* argv[] , UIntPack< FEMSigs ... > ) if( Out.set ) { - char tempHeader[1024]; + if( Normals.set ) { - char tempPath[1024]; - tempPath[0] = 0; - if( TempDir.set ) strcpy( tempPath , TempDir.value ); - else SetTempDirectory( tempPath , sizeof(tempPath) ); - if( strlen(tempPath)==0 ) sprintf( tempPath , ".%c" , FileSeparator ); - if( tempPath[ strlen( tempPath )-1 ]==FileSeparator ) sprintf( tempHeader , "%sPR_" , tempPath ); - else sprintf( tempHeader , "%s%cPR_" , tempPath , FileSeparator ); - } - CoredFileMeshData< Vertex > mesh( tempHeader ); - - profiler.start(); - typename IsoSurfaceExtractor< Dim , Real , Vertex >::IsoStats isoStats; - if( sampleData ) - { - SparseNodeData< ProjectiveData< typename StreamDataInfo::Type , Real > , IsotropicUIntPack< Dim , DataSig > > _sampleData = tree.template setDataField< DataSig , false >( *samples , *sampleData , (DensityEstimator*)NULL ); - for( const RegularTreeNode< Dim , FEMTreeNodeData >* n = tree.tree().nextNode() ; n ; n=tree.tree().nextNode( n ) ) + if( Density.set ) { - ProjectiveData< typename StreamDataInfo::Type , Real >* clr = _sampleData( n ); - if( clr ) (*clr) *= (Real)pow( DataX.value , tree.depth( n ) ); + typedef PlyVertexWithData< Real , Dim , MultiPointStreamData< Real , PointStreamNormal< Real , Dim > , PointStreamValue< Real > , AdditionalPointSampleData > > Vertex; + std::function< void ( Vertex& , Point< Real , Dim > , Real , TotalPointSampleData ) > SetVertex = []( Vertex& v , Point< Real , Dim > p , Real w , TotalPointSampleData d ){ v.point = p , std::get< 0 >( v.data.data ) = std::get< 0 >( d.data ) , std::get< 1 >( v.data.data ).data = w , std::get< 2 >( v.data.data ) = std::get< 1 >( d.data ); }; + ExtractMesh< Vertex >( UIntPack< FEMSigs ... >() , std::tuple< SampleData ... >() , tree , solution , isoValue , samples , sampleData , density , SetVertex , comments , iXForm ); + } + else + { + typedef PlyVertexWithData< Real , Dim , MultiPointStreamData< Real , PointStreamNormal< Real , Dim > , AdditionalPointSampleData > > Vertex; + std::function< void ( Vertex& , Point< Real , Dim > , Real , TotalPointSampleData ) > SetVertex = []( Vertex& v , Point< Real , Dim > p , Real w , TotalPointSampleData d ){ v.point = p , std::get< 0 >( v.data.data ) = std::get< 0 >( d.data ) , std::get< 1 >( v.data.data ) = std::get< 1 >( d.data ); }; + ExtractMesh< Vertex >( UIntPack< FEMSigs ... >() , std::tuple< SampleData ... >() , tree , solution , isoValue , samples , sampleData , density , SetVertex , comments , iXForm ); } - delete sampleData , sampleData = NULL; - - isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< typename StreamDataInfo::Type >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , &_sampleData , solution , isoValue , mesh , StreamDataInfo::template VertexSetter< Vertex >::SetValue , StreamDataInfo::template VertexSetter< Vertex >::SetData , !LinearFit.set , !NonManifold.set , PolygonMesh.set , false ); - } - else isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< typename StreamDataInfo::Type >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , NULL , solution , isoValue , mesh , StreamDataInfo::template VertexSetter< Vertex >::SetValue , StreamDataInfo::template VertexSetter< Vertex >::SetData , !LinearFit.set , !NonManifold.set , PolygonMesh.set , false ); - messageWriter( "Vertices / Polygons: %d / %d\n" , mesh.outOfCorePointCount()+mesh.inCorePoints.size() , mesh.polygonCount() ); - messageWriter( "Corners / Vertices / Edges / Surface / Set Table / Copy Finer: %.1f / %.1f / %.1f / %.1f / %.1f / %.1f (s)\n" , isoStats.cornersTime , isoStats.verticesTime , isoStats.edgesTime , isoStats.surfaceTime , isoStats.setTableTime , isoStats.copyFinerTime ); - if( PolygonMesh.set ) profiler.dumpOutput2( comments , "# Got polygons:" ); - else profiler.dumpOutput2( comments , "# Got triangles:" ); - - if( NoComments.set ) - { - if( ASCII.set ) PlyWritePolygons< Vertex , Real , Dim >( Out.value , &mesh , PLY_ASCII , NULL , 0 , iXForm ); - else PlyWritePolygons< Vertex , Real , Dim >( Out.value , &mesh , PLY_BINARY_NATIVE , NULL , 0 , iXForm ); } else { - if( ASCII.set ) PlyWritePolygons< Vertex , Real , Dim >( Out.value , &mesh , PLY_ASCII , &comments[0] , (int)comments.size() , iXForm ); - else PlyWritePolygons< Vertex , Real , Dim >( Out.value , &mesh , PLY_BINARY_NATIVE , &comments[0] , (int)comments.size() , iXForm ); + if( Density.set ) + { + typedef PlyVertexWithData< Real , Dim , MultiPointStreamData< Real , PointStreamValue< Real > , AdditionalPointSampleData > > Vertex; + std::function< void ( Vertex& , Point< Real , Dim > , Real , TotalPointSampleData ) > SetVertex = []( Vertex& v , Point< Real , Dim > p , Real w , TotalPointSampleData d ){ v.point = p , std::get< 0 >( v.data.data ).data = w , std::get< 1 >( v.data.data ) = std::get< 1 >( d.data ); }; + ExtractMesh< Vertex >( UIntPack< FEMSigs ... >() , std::tuple< SampleData ... >() , tree , solution , isoValue , samples , sampleData , density , SetVertex , comments , iXForm ); + } + else + { + typedef PlyVertexWithData< Real , Dim , MultiPointStreamData< Real , AdditionalPointSampleData > > Vertex; + std::function< void ( Vertex& , Point< Real , Dim > , Real , TotalPointSampleData ) > SetVertex = []( Vertex& v , Point< Real , Dim > p , Real w , TotalPointSampleData d ){ v.point = p , std::get< 0 >( v.data.data ) = std::get< 1 >( d.data ); }; + ExtractMesh< Vertex >( UIntPack< FEMSigs ... >() , std::tuple< SampleData ... >() , tree , solution , isoValue , samples , sampleData , density , SetVertex , comments , iXForm ); + } } + if( sampleData ){ delete sampleData ; sampleData = NULL; } } if( density ) delete density , density = NULL; messageWriter( comments , "# Total Solve: %9.1f (s), %9.1f (MB)\n" , Time()-startTime , FEMTree< Dim , Real >::MaxMemoryUsage() ); @@ -583,45 +636,45 @@ int Execute( int argc , char* argv[] , UIntPack< FEMSigs ... > ) } #ifndef FAST_COMPILE -template< unsigned int Dim , class Real , class InfoType , class Vertex > +template< unsigned int Dim , class Real , typename ... SampleData > int Execute( int argc , char* argv[] ) { switch( BType.value ) { - case BOUNDARY_FREE+1: - { - switch( Degree.value ) + case BOUNDARY_FREE+1: { - case 1: return Execute< Real , InfoType , Vertex >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 1 , BOUNDARY_FREE >::Signature >() ); - case 2: return Execute< Real , InfoType , Vertex >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BOUNDARY_FREE >::Signature >() ); -// case 3: return Execute< Real , InfoType , Vertex >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BOUNDARY_FREE >::Signature >() ); -// case 4: return Execute< Real , InfoType , Vertex >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BOUNDARY_FREE >::Signature >() ); - default: fprintf( stderr , "[ERROR] Only B-Splines of degree 1 - 2 are supported" ) ; return EXIT_FAILURE; + switch( Degree.value ) + { + case 1: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 1 , BOUNDARY_FREE >::Signature >() ); + case 2: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BOUNDARY_FREE >::Signature >() ); +// case 3: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BOUNDARY_FREE >::Signature >() ); +// case 4: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BOUNDARY_FREE >::Signature >() ); + default: fprintf( stderr , "[ERROR] Only B-Splines of degree 1 - 2 are supported" ) ; return EXIT_FAILURE; + } } - } - case BOUNDARY_NEUMANN+1: - { - switch( Degree.value ) + case BOUNDARY_NEUMANN+1: { - case 1: return Execute< Real , InfoType , Vertex >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 1 , BOUNDARY_NEUMANN >::Signature >() ); - case 2: return Execute< Real , InfoType , Vertex >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BOUNDARY_NEUMANN >::Signature >() ); -// case 3: return Execute< Real , InfoType , Vertex >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BOUNDARY_NEUMANN >::Signature >() ); -// case 4: return Execute< Real , InfoType , Vertex >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BOUNDARY_NEUMANN >::Signature >() ); - default: fprintf( stderr , "[ERROR] Only B-Splines of degree 1 - 2 are supported" ) ; return EXIT_FAILURE; + switch( Degree.value ) + { + case 1: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 1 , BOUNDARY_NEUMANN >::Signature >() ); + case 2: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BOUNDARY_NEUMANN >::Signature >() ); +// case 3: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BOUNDARY_NEUMANN >::Signature >() ); +// case 4: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BOUNDARY_NEUMANN >::Signature >() ); + default: fprintf( stderr , "[ERROR] Only B-Splines of degree 1 - 2 are supported" ) ; return EXIT_FAILURE; + } } - } - case BOUNDARY_DIRICHLET+1: - { - switch( Degree.value ) + case BOUNDARY_DIRICHLET+1: { - case 1: return Execute< Real , InfoType , Vertex >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 1 , BOUNDARY_DIRICHLET >::Signature >() ); - case 2: return Execute< Real , InfoType , Vertex >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BOUNDARY_DIRICHLET >::Signature >() ); -// case 3: return Execute< Real , InfoType , Vertex >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BOUNDARY_DIRICHLET >::Signature >() ); -// case 4: return Execute< Real , InfoType , Vertex >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BOUNDARY_DIRICHLET >::Signature >() ); + switch( Degree.value ) + { + case 1: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 1 , BOUNDARY_DIRICHLET >::Signature >() ); + case 2: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BOUNDARY_DIRICHLET >::Signature >() ); +// case 3: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BOUNDARY_DIRICHLET >::Signature >() ); +// case 4: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BOUNDARY_DIRICHLET >::Signature >() ); default: fprintf( stderr , "[ERROR] Only B-Splines of degree 1 - 2 are supported" ) ; return EXIT_FAILURE; + } } - } - default: fprintf( stderr , "[ERROR] Not a valid boundary type: %d\n" , BType.value ) ; return EXIT_FAILURE; + default: fprintf( stderr , "[ERROR] Not a valid boundary type: %d\n" , BType.value ) ; return EXIT_FAILURE; } } #endif // !FAST_COMPILE @@ -662,36 +715,12 @@ int main( int argc , char* argv[] ) typedef IsotropicUIntPack< DIMENSION , FEMDegreeAndBType< Degree , BType >::Signature > FEMSigs; fprintf( stderr , "[WARNING] Compiled for degree-%d, boundary-%s, %s-precision _only_\n" , Degree , BoundaryNames[ BType ] , sizeof(Real)==4 ? "single" : "double" ); if( !PointWeight.set ) PointWeight.value = DefaultPointWeightMultiplier*Degree; - if( Normals.set ) - if( Colors.set ) - if( Density.set ) Execute< Real , NormalAndColorInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , true , true , true > >( argc , argv , FEMSigs() ); - else Execute< Real , NormalAndColorInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , true , false , true > >( argc , argv , FEMSigs() ); - else - if( Density.set ) Execute< Real , NormalInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , true , true , false > >( argc , argv , FEMSigs() ); - else Execute< Real , NormalInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , true , false , false > >( argc , argv , FEMSigs() ); - else - if( Colors.set ) - if( Density.set ) Execute< Real , NormalAndColorInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , false , true , true > >( argc , argv , FEMSigs() ); - else Execute< Real , NormalAndColorInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , false , false , true > >( argc , argv , FEMSigs() ); - else - if( Density.set ) Execute< Real , NormalInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , false , true , false > >( argc , argv , FEMSigs() ); - else Execute< Real , NormalInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , false , false , false > >( argc , argv , FEMSigs() ); + if( Colors.set ) Execute< DefaultFloatType , PointStreamColor< DefaultFloatType > >( argc , argv , FEMSigs() ); + else Execute< DefaultFloatType >( argc , argv , FEMSigs() ); #else // !FAST_COMPILE if( !PointWeight.set ) PointWeight.value = DefaultPointWeightMultiplier*Degree.value; - if( Normals.set ) - if( Density.set ) - if( Colors.set ) Execute< DIMENSION , Real , NormalAndColorInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , true , true , true > >( argc , argv ); - else Execute< DIMENSION , Real , NormalInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , true , true , false > >( argc , argv ); - else - if( Colors.set ) Execute< DIMENSION , Real , NormalAndColorInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , true , false , true > >( argc , argv ); - else Execute< DIMENSION , Real , NormalInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , true , false , false > >( argc , argv ); - else - if( Density.set ) - if( Colors.set ) Execute< DIMENSION , Real , NormalAndColorInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , false , true , true > >( argc , argv ); - else Execute< DIMENSION , Real , NormalInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , false , true , false > >( argc , argv ); - else - if( Colors.set ) Execute< DIMENSION , Real , NormalAndColorInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , false , false , true > >( argc , argv ); - else Execute< DIMENSION , Real , NormalInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , false , false , false > >( argc , argv ); + if( Colors.set ) Execute< DIMENSION , float , PointStreamColor< float > >( argc , argv ); + else Execute< DIMENSION , float >( argc , argv ); #endif // FAST_COMPILE if( Performance.set ) { diff --git a/Src/SSDRecon.cpp b/Src/SSDRecon.cpp index 738bddc..b5838be 100644 --- a/Src/SSDRecon.cpp +++ b/Src/SSDRecon.cpp @@ -271,43 +271,93 @@ XForm< Real , Dim+1 > GetPointXForm( InputPointStream< Real , Dim >& stream , Re return GetBoundingBoxXForm( min , max , scaleFactor ); } -template< unsigned int Dim , typename Real , class StreamDataInfo > +template< unsigned int Dim , typename Real , typename TotalPointSampleData > struct ConstraintDual { Real target , vWeight , gWeight; ConstraintDual( Real t , Real v , Real g ) : target(t) , vWeight(v) , gWeight(g) { } - CumulativeDerivativeValues< Real , Dim , 1 > operator()( const Point< Real , Dim >& p , const typename StreamDataInfo::Type& data ) const + CumulativeDerivativeValues< Real , Dim , 1 > operator()( const Point< Real , Dim >& p , const TotalPointSampleData& data ) const { - return CumulativeDerivativeValues< Real , Dim , 1 >( target*vWeight , -data.normal[0]*gWeight , -data.normal[1]*gWeight , -data.normal[2]*gWeight ); + Point< Real , Dim > n = std::get<0>( data.data ).data; + CumulativeDerivativeValues< Real , Dim , 1 > cdv; + cdv[0] = target*vWeight; + for( int d=0 ; d +template< unsigned int Dim , typename Real , typename TotalPointSampleData > struct SystemDual { CumulativeDerivativeValues< Real , Dim , 1 > weight; SystemDual( Real v , Real g ) : weight( v , g , g , g ) { } - CumulativeDerivativeValues< Real , Dim , 1 > operator()( Point< Real , Dim > p , const typename StreamDataInfo::Type& data , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const + CumulativeDerivativeValues< Real , Dim , 1 > operator()( Point< Real , Dim > p , const TotalPointSampleData& data , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const { return dValues * weight; } - CumulativeDerivativeValues< double , Dim , 1 > operator()( Point< Real , Dim > p , const typename StreamDataInfo::Type& data , const CumulativeDerivativeValues< double , Dim , 1 >& dValues ) const + CumulativeDerivativeValues< double , Dim , 1 > operator()( Point< Real , Dim > p , const TotalPointSampleData& data , const CumulativeDerivativeValues< double , Dim , 1 >& dValues ) const { return dValues * weight; }; }; -template< unsigned int Dim , class StreamDataInfo > -struct SystemDual< Dim , double , StreamDataInfo > +template< unsigned int Dim , class TotalPointSampleData > +struct SystemDual< Dim , double , TotalPointSampleData > { typedef double Real; CumulativeDerivativeValues< Real , Dim , 1 > weight; SystemDual( Real v , Real g ) : weight( v , g , g , g ) { } - CumulativeDerivativeValues< Real , Dim , 1 > operator()( Point< Real , Dim > p , const typename StreamDataInfo::Type& data , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const + CumulativeDerivativeValues< Real , Dim , 1 > operator()( Point< Real , Dim > p , const TotalPointSampleData& data , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const { return dValues * weight; } }; -template< class Real , class StreamDataInfo , class Vertex , unsigned int ... FEMSigs > +template< typename Vertex , typename Real , unsigned int ... FEMSigs , typename ... SampleData > +void ExtractMesh( UIntPack< FEMSigs ... > , std::tuple< SampleData ... > , FEMTree< sizeof ... ( FEMSigs ) , Real >& tree , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& solution , Real isoValue , const std::vector< typename FEMTree< sizeof ... ( FEMSigs ) , Real >::PointSample >* samples , std::vector< MultiPointStreamData< Real , PointStreamNormal< Real , DIMENSION > , MultiPointStreamData< Real , SampleData ... > > >* sampleData , const typename FEMTree< sizeof ... ( FEMSigs ) , Real >::template DensityEstimator< WEIGHT_DEGREE >* density , std::function< void ( Vertex& , Point< Real , DIMENSION > , Real , MultiPointStreamData< Real , PointStreamNormal< Real , DIMENSION > , MultiPointStreamData< Real , SampleData ... > > ) > SetVertex , std::vector< char* > comments , XForm< Real , sizeof...(FEMSigs)+1 > iXForm ) +{ + static const int Dim = sizeof ... ( FEMSigs ); + typedef UIntPack< FEMSigs ... > Sigs; + typedef PointStreamNormal< Real , Dim > NormalPointSampleData; + typedef MultiPointStreamData< Real , SampleData ... > AdditionalPointSampleData; + typedef MultiPointStreamData< Real , NormalPointSampleData , AdditionalPointSampleData > TotalPointSampleData; + static const unsigned int DataSig = FEMDegreeAndBType< DATA_DEGREE , BOUNDARY_FREE >::Signature; + typedef typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; + + FEMTreeProfiler< Dim , Real > profiler( tree ); + + char tempHeader[1024]; + { + char tempPath[1024]; + tempPath[0] = 0; + if( TempDir.set ) strcpy( tempPath , TempDir.value ); + else SetTempDirectory( tempPath , sizeof(tempPath) ); + if( strlen(tempPath)==0 ) sprintf( tempPath , ".%c" , FileSeparator ); + if( tempPath[ strlen( tempPath )-1 ]==FileSeparator ) sprintf( tempHeader , "%sPR_" , tempPath ); + else sprintf( tempHeader , "%s%cPR_" , tempPath , FileSeparator ); + } + CoredFileMeshData< Vertex > mesh( tempHeader ); + profiler.start(); + typename IsoSurfaceExtractor< Dim , Real , Vertex >::IsoStats isoStats; + if( sampleData ) + { + SparseNodeData< ProjectiveData< TotalPointSampleData , Real > , IsotropicUIntPack< Dim , DataSig > > _sampleData = tree.template setDataField< DataSig , false >( *samples , *sampleData , (DensityEstimator*)NULL ); + for( const RegularTreeNode< Dim , FEMTreeNodeData >* n = tree.tree().nextNode() ; n ; n=tree.tree().nextNode( n ) ) + { + ProjectiveData< TotalPointSampleData , Real >* clr = _sampleData( n ); + if( clr ) (*clr) *= (Real)pow( DataX.value , tree.depth( n ) ); + } + isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< TotalPointSampleData >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , &_sampleData , solution , isoValue , mesh , SetVertex , NonLinearFit.set , !NonManifold.set , PolygonMesh.set , false ); + } + else isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< TotalPointSampleData >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , NULL , solution , isoValue , mesh , SetVertex , NonLinearFit.set , !NonManifold.set , PolygonMesh.set , false ); + messageWriter( "Vertices / Polygons: %d / %d\n" , mesh.outOfCorePointCount()+mesh.inCorePoints.size() , mesh.polygonCount() ); + messageWriter( "Corners / Vertices / Edges / Surface / Set Table / Copy Finer: %.1f / %.1f / %.1f / %.1f / %.1f / %.1f (s)\n" , isoStats.cornersTime , isoStats.verticesTime , isoStats.edgesTime , isoStats.surfaceTime , isoStats.setTableTime , isoStats.copyFinerTime ); + if( PolygonMesh.set ) profiler.dumpOutput2( comments , "# Got polygons:" ); + else profiler.dumpOutput2( comments , "# Got triangles:" ); + + if( NoComments.set ) PlyWritePolygons< Vertex , Real , Dim >( Out.value , &mesh , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , NULL , 0 , iXForm ); + else PlyWritePolygons< Vertex , Real , Dim >( Out.value , &mesh , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , &comments[0] , (int)comments.size() , iXForm ); +} + +template< class Real , typename ... SampleData , unsigned int ... FEMSigs > int Execute( int argc , char* argv[] , UIntPack< FEMSigs ... > ) { static const int Dim = sizeof ... ( FEMSigs ); @@ -315,11 +365,13 @@ int Execute( int argc , char* argv[] , UIntPack< FEMSigs ... > ) typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > Degrees; typedef UIntPack< FEMDegreeAndBType< NORMAL_DEGREE , DerivativeBoundary< FEMSignature< FEMSigs >::BType , 1 >::BType >::Signature ... > NormalSigs; static const unsigned int DataSig = FEMDegreeAndBType< DATA_DEGREE , BOUNDARY_FREE >::Signature; - typedef Point< Real , 3 > Color; typedef typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; typedef typename FEMTree< Dim , Real >::template InterpolationInfo< Real , 1 > InterpolationInfo; - typedef InputPointStreamWithData< Real , Dim , typename StreamDataInfo::Type > InputPointStream; - typedef TransformedInputPointStreamWithData< Real , Dim , typename StreamDataInfo::Type > XInputPointStream; + typedef PointStreamNormal< Real , Dim > NormalPointSampleData; + typedef MultiPointStreamData< Real , SampleData ... > AdditionalPointSampleData; + typedef MultiPointStreamData< Real , NormalPointSampleData , AdditionalPointSampleData > TotalPointSampleData; + typedef InputPointStreamWithData< Real , Dim , TotalPointSampleData > InputPointStream; + typedef TransformedInputPointStreamWithData< Real , Dim , TotalPointSampleData > XInputPointStream; std::vector< char* > comments; messageWriter( comments , "************************************************\n" ); messageWriter( comments , "************************************************\n" ); @@ -374,7 +426,7 @@ int Execute( int argc , char* argv[] , UIntPack< FEMSigs ... > ) Real pointWeightSum; std::vector< typename FEMTree< Dim , Real >::PointSample >* samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); - std::vector< typename StreamDataInfo::Type >* sampleData = NULL; + std::vector< TotalPointSampleData >* sampleData = NULL; DensityEstimator* density = NULL; SparseNodeData< Point< Real , Dim > , NormalSigs >* normalInfo = NULL; Real targetValue = (Real)0.; @@ -384,18 +436,33 @@ int Execute( int argc , char* argv[] , UIntPack< FEMSigs ... > ) profiler.start(); InputPointStream* pointStream; char* ext = GetFileExtension( In.value ); - sampleData = new std::vector< typename StreamDataInfo::Type >(); - if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryInputPointStreamWithData< Real , Dim , typename StreamDataInfo::Type >( In.value , StreamDataInfo::ReadBinary ); - else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYInputPointStreamWithData< Real , Dim , typename StreamDataInfo::Type >( In.value , StreamDataInfo::PlyProperties , StreamDataInfo::PlyPropertyNum , StreamDataInfo::ValidPlyProperties ); - else pointStream = new ASCIIInputPointStreamWithData< Real , Dim , typename StreamDataInfo::Type >( In.value , StreamDataInfo::ReadASCII ); + sampleData = new std::vector< TotalPointSampleData >(); + if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::ReadBinary ); + else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::PlyReadProperties() , TotalPointSampleData::PlyReadNum , TotalPointSampleData::ValidPlyReadProperties ); + else pointStream = new ASCIIInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::ReadASCII ); delete[] ext; - XInputPointStream _pointStream( typename StreamDataInfo::Transform( xForm ) , *pointStream ); + typename TotalPointSampleData::Transform _xForm( xForm ); + XInputPointStream _pointStream( [&]( Point< Real , Dim >& p , TotalPointSampleData& d ){ p = xForm*p , d = _xForm(d); } , *pointStream ); if( Width.value>0 ) xForm = GetPointXForm< Real , Dim >( _pointStream , Width.value , (Real)( Scale.value>0 ? Scale.value : 1. ) , Depth.value ) * xForm; else xForm = Scale.value>0 ? GetPointXForm< Real , Dim >( _pointStream , (Real)Scale.value ) * xForm : xForm; { - XInputPointStream _pointStream( typename StreamDataInfo::Transform( xForm ) , *pointStream ); - if( Confidence.value>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< typename StreamDataInfo::Type >( tree.spaceRoot() , _pointStream , Depth.value , *samples , *sampleData , true , tree.nodeAllocator , tree.initializer() , [&]( const Point< Real , Dim >&p , typename StreamDataInfo::Type& d ){ return (Real)pow( StreamDataInfo::ProcessDataWithConfidence( p , d ) , Confidence.value ); } ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< typename StreamDataInfo::Type >( tree.spaceRoot() , _pointStream , Depth.value , *samples , *sampleData , true , tree.nodeAllocator , tree.initializer() , StreamDataInfo::ProcessData ); + typename TotalPointSampleData::Transform _xForm( xForm ); + XInputPointStream _pointStream( [&]( Point< Real , Dim >& p , TotalPointSampleData& d ){ p = xForm*p , d = _xForm(d); } , *pointStream ); + auto ProcessDataWithConfidence = [&]( const Point< Real , Dim >& p , TotalPointSampleData& d ) + { + Real l = (Real)Length( std::get< 0 >( d.data ).data ); + if( !l || l!=l ) return (Real)-1.; + return (Real)pow( l , Confidence.value ); + }; + auto ProcessData = []( const Point< Real , Dim >& p , TotalPointSampleData& d ) + { + Real l = (Real)Length( std::get< 0 >( d.data ).data ); + if( !l || l!=l ) return (Real)-1.; + std::get< 0 >( d.data ).data /= l; + return (Real)1.; + }; + if( Confidence.value>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< TotalPointSampleData >( tree.spaceRoot() , _pointStream , Depth.value , *samples , *sampleData , true , tree.nodeAllocator , tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< TotalPointSampleData >( tree.spaceRoot() , _pointStream , Depth.value , *samples , *sampleData , true , tree.nodeAllocator , tree.initializer() , ProcessData ); } iXForm = xForm.inverse(); delete pointStream; @@ -452,8 +519,8 @@ int Execute( int argc , char* argv[] , UIntPack< FEMSigs ... > ) if( ValueWeight.value>0 || GradientWeight.value>0 ) { profiler.start(); - if( ExactInterpolation.set ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , typename StreamDataInfo::Type , 1 >( tree , *samples , GetPointer( *sampleData ) , ConstraintDual< Dim , Real , StreamDataInfo >( targetValue , (Real)ValueWeight.value * pointWeightSum , (Real)GradientWeight.value * pointWeightSum ) , SystemDual< Dim , Real , StreamDataInfo >( (Real)ValueWeight.value * pointWeightSum , (Real)GradientWeight.value * pointWeightSum ) , true , false ); - else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , typename StreamDataInfo::Type , 1 >( tree , *samples , GetPointer( *sampleData ) , ConstraintDual< Dim , Real , StreamDataInfo >( targetValue , (Real)ValueWeight.value * pointWeightSum , (Real)GradientWeight.value * pointWeightSum ) , SystemDual< Dim , Real , StreamDataInfo >( (Real)ValueWeight.value * pointWeightSum , (Real)GradientWeight.value * pointWeightSum ) , true , 1 ); + if( ExactInterpolation.set ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , TotalPointSampleData , 1 >( tree , *samples , GetPointer( *sampleData ) , ConstraintDual< Dim , Real , TotalPointSampleData >( targetValue , (Real)ValueWeight.value * pointWeightSum , (Real)GradientWeight.value * pointWeightSum ) , SystemDual< Dim , Real , TotalPointSampleData >( (Real)ValueWeight.value * pointWeightSum , (Real)GradientWeight.value * pointWeightSum ) , true , false ); + else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , TotalPointSampleData , 1 >( tree , *samples , GetPointer( *sampleData ) , ConstraintDual< Dim , Real , TotalPointSampleData >( targetValue , (Real)ValueWeight.value * pointWeightSum , (Real)GradientWeight.value * pointWeightSum ) , SystemDual< Dim , Real , TotalPointSampleData >( (Real)ValueWeight.value * pointWeightSum , (Real)GradientWeight.value * pointWeightSum ) , true , 1 ); constraints = tree.initDenseNodeData( Sigs() ); tree.addInterpolationConstraints( constraints , solveDepth , *iInfo ); profiler.dumpOutput2( comments , "#Set point constraints:" ); @@ -531,48 +598,37 @@ int Execute( int argc , char* argv[] , UIntPack< FEMSigs ... > ) if( Out.set ) { - char tempHeader[1024]; + if( Normals.set ) { - char tempPath[1024]; - tempPath[0] = 0; - if( TempDir.set ) strcpy( tempPath , TempDir.value ); - else SetTempDirectory( tempPath , sizeof(tempPath) ); - if( strlen(tempPath)==0 ) sprintf( tempPath , ".%c" , FileSeparator ); - if( tempPath[ strlen( tempPath )-1 ]==FileSeparator ) sprintf( tempHeader , "%sPR_" , tempPath ); - else sprintf( tempHeader , "%s%cPR_" , tempPath , FileSeparator ); - } - CoredFileMeshData< Vertex > mesh( tempHeader ); - - profiler.start(); - typename IsoSurfaceExtractor< Dim , Real , Vertex >::IsoStats isoStats; - if( sampleData ) - { - SparseNodeData< ProjectiveData< typename StreamDataInfo::Type , Real > , IsotropicUIntPack< Dim , DataSig > > _sampleData = tree.template setDataField< DataSig , false >( *samples , *sampleData , (DensityEstimator*)NULL ); - for( const RegularTreeNode< Dim , FEMTreeNodeData >* n = tree.tree().nextNode() ; n ; n=tree.tree().nextNode( n ) ) + if( Density.set ) { - ProjectiveData< typename StreamDataInfo::Type , Real >* clr = _sampleData( n ); - if( clr ) (*clr) *= (Real)pow( DataX.value , tree.depth( n ) ); + typedef PlyVertexWithData< Real , Dim , MultiPointStreamData< Real , PointStreamNormal< Real , Dim > , PointStreamValue< Real > , AdditionalPointSampleData > > Vertex; + std::function< void ( Vertex& , Point< Real , Dim > , Real , TotalPointSampleData ) > SetVertex = []( Vertex& v , Point< Real , Dim > p , Real w , TotalPointSampleData d ){ v.point = p , std::get< 0 >( v.data.data ) = std::get< 0 >( d.data ) , std::get< 1 >( v.data.data ).data = w , std::get< 2 >( v.data.data ) = std::get< 1 >( d.data ); }; + ExtractMesh< Vertex >( UIntPack< FEMSigs ... >() , std::tuple< SampleData ... >() , tree , solution , isoValue , samples , sampleData , density , SetVertex , comments , iXForm ); + } + else + { + typedef PlyVertexWithData< Real , Dim , MultiPointStreamData< Real , PointStreamNormal< Real , Dim > , AdditionalPointSampleData > > Vertex; + std::function< void ( Vertex& , Point< Real , Dim > , Real , TotalPointSampleData ) > SetVertex = []( Vertex& v , Point< Real , Dim > p , Real w , TotalPointSampleData d ){ v.point = p , std::get< 0 >( v.data.data ) = std::get< 0 >( d.data ) , std::get< 1 >( v.data.data ) = std::get< 1 >( d.data ); }; + ExtractMesh< Vertex >( UIntPack< FEMSigs ... >() , std::tuple< SampleData ... >() , tree , solution , isoValue , samples , sampleData , density , SetVertex , comments , iXForm ); } - delete sampleData , sampleData = NULL; - - isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< typename StreamDataInfo::Type >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , &_sampleData , solution , isoValue , mesh , StreamDataInfo::template VertexSetter< Vertex >::SetValue , StreamDataInfo::template VertexSetter< Vertex >::SetData , NonLinearFit.set , !NonManifold.set , PolygonMesh.set , false ); - } - else isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< typename StreamDataInfo::Type >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , NULL , solution , isoValue , mesh , StreamDataInfo::template VertexSetter< Vertex >::SetValue , StreamDataInfo::template VertexSetter< Vertex >::SetData , NonLinearFit.set , !NonManifold.set , PolygonMesh.set , false ); - messageWriter( "Vertices / Polygons: %d / %d\n" , mesh.outOfCorePointCount()+mesh.inCorePoints.size() , mesh.polygonCount() ); - messageWriter( "Corners / Vertices / Edges / Surface / Set Table / Copy Finer: %.1f / %.1f / %.1f / %.1f / %.1f / %.1f (s)\n" , isoStats.cornersTime , isoStats.verticesTime , isoStats.edgesTime , isoStats.surfaceTime , isoStats.setTableTime , isoStats.copyFinerTime ); - if( PolygonMesh.set ) profiler.dumpOutput2( comments , "# Got polygons:" ); - else profiler.dumpOutput2( comments , "# Got triangles:" ); - - if( NoComments.set ) - { - if( ASCII.set ) PlyWritePolygons< Vertex , Real , Dim >( Out.value , &mesh , PLY_ASCII , NULL , 0 , iXForm ); - else PlyWritePolygons< Vertex , Real , Dim >( Out.value , &mesh , PLY_BINARY_NATIVE , NULL , 0 , iXForm ); } else { - if( ASCII.set ) PlyWritePolygons< Vertex , Real , Dim >( Out.value , &mesh , PLY_ASCII , &comments[0] , (int)comments.size() , iXForm ); - else PlyWritePolygons< Vertex , Real , Dim >( Out.value , &mesh , PLY_BINARY_NATIVE , &comments[0] , (int)comments.size() , iXForm ); + if( Density.set ) + { + typedef PlyVertexWithData< Real , Dim , MultiPointStreamData< Real , PointStreamValue< Real > , AdditionalPointSampleData > > Vertex; + std::function< void ( Vertex& , Point< Real , Dim > , Real , TotalPointSampleData ) > SetVertex = []( Vertex& v , Point< Real , Dim > p , Real w , TotalPointSampleData d ){ v.point = p , std::get< 0 >( v.data.data ).data = w , std::get< 1 >( v.data.data ) = std::get< 1 >( d.data ); }; + ExtractMesh< Vertex >( UIntPack< FEMSigs ... >() , std::tuple< SampleData ... >() , tree , solution , isoValue , samples , sampleData , density , SetVertex , comments , iXForm ); + } + else + { + typedef PlyVertexWithData< Real , Dim , MultiPointStreamData< Real , AdditionalPointSampleData > > Vertex; + std::function< void ( Vertex& , Point< Real , Dim > , Real , TotalPointSampleData ) > SetVertex = []( Vertex& v , Point< Real , Dim > p , Real w , TotalPointSampleData d ){ v.point = p , std::get< 0 >( v.data.data ) = std::get< 1 >( d.data ); }; + ExtractMesh< Vertex >( UIntPack< FEMSigs ... >() , std::tuple< SampleData ... >() , tree , solution , isoValue , samples , sampleData , density , SetVertex , comments , iXForm ); + } } + if( sampleData ){ delete sampleData ; sampleData = NULL; } } if( density ) delete density , density = NULL; messageWriter( comments , "# Total Solve: %9.1f (s), %9.1f (MB)\n" , Time()-startTime , FEMTree< Dim , Real >::MaxMemoryUsage() ); @@ -581,7 +637,7 @@ int Execute( int argc , char* argv[] , UIntPack< FEMSigs ... > ) } #ifndef FAST_COMPILE -template< unsigned int Dim , class Real , class InfoType , class Vertex > +template< unsigned int Dim , class Real , typename ... SampleData > int Execute( int argc , char* argv[] ) { switch( BType.value ) @@ -590,9 +646,9 @@ int Execute( int argc , char* argv[] ) { switch( Degree.value ) { - case 2: return Execute< Real , InfoType , Vertex >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BOUNDARY_FREE >::Signature >() ); - case 3: return Execute< Real , InfoType , Vertex >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BOUNDARY_FREE >::Signature >() ); -// case 4: return Execute< Real , InfoType , Vertex >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BOUNDARY_FREE >::Signature >() ); + case 2: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BOUNDARY_FREE >::Signature >() ); + case 3: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BOUNDARY_FREE >::Signature >() ); +// case 4: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BOUNDARY_FREE >::Signature >() ); default: fprintf( stderr , "[ERROR] Only B-Splines of degree 2 - 3 are supported" ) ; return EXIT_FAILURE; } } @@ -600,9 +656,9 @@ int Execute( int argc , char* argv[] ) { switch( Degree.value ) { - case 2: return Execute< Real , InfoType , Vertex >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BOUNDARY_NEUMANN >::Signature >() ); - case 3: return Execute< Real , InfoType , Vertex >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BOUNDARY_NEUMANN >::Signature >() ); -// case 4: return Execute< Real , InfoType , Vertex >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BOUNDARY_NEUMANN >::Signature >() ); + case 2: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BOUNDARY_NEUMANN >::Signature >() ); + case 3: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BOUNDARY_NEUMANN >::Signature >() ); +// case 4: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BOUNDARY_NEUMANN >::Signature >() ); default: fprintf( stderr , "[ERROR] Only B-Splines of degree 2 - 3 are supported" ) ; return EXIT_FAILURE; } } @@ -610,9 +666,9 @@ int Execute( int argc , char* argv[] ) { switch( Degree.value ) { - case 2: return Execute< Real , InfoType , Vertex >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BOUNDARY_DIRICHLET >::Signature >() ); - case 3: return Execute< Real , InfoType , Vertex >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BOUNDARY_DIRICHLET >::Signature >() ); -// case 4: return Execute< Real , InfoType , Vertex >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BOUNDARY_DIRICHLET >::Signature >() ); + case 2: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BOUNDARY_DIRICHLET >::Signature >() ); + case 3: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BOUNDARY_DIRICHLET >::Signature >() ); +// case 4: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BOUNDARY_DIRICHLET >::Signature >() ); default: fprintf( stderr , "[ERROR] Only B-Splines of degree 2- 3 are supported" ) ; return EXIT_FAILURE; } } @@ -661,35 +717,11 @@ int main( int argc , char* argv[] ) static const BoundaryType BType = DEFAULT_FEM_BOUNDARY; typedef IsotropicUIntPack< DIMENSION , FEMDegreeAndBType< Degree , BType >::Signature > FEMSigs; fprintf( stderr , "[WARNING] Compiled for degree-%d, boundary-%s, %s-precision _only_\n" , Degree , BoundaryNames[ BType ] , sizeof(Real)==4 ? "single" : "double" ); - if( Normals.set ) - if( Colors.set ) - if( Density.set ) Execute< Real , NormalAndColorInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , true , true , true > >( argc , argv , FEMSigs() ); - else Execute< Real , NormalAndColorInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , true , false , true > >( argc , argv , FEMSigs() ); - else - if( Density.set ) Execute< Real , NormalInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , true , true , false > >( argc , argv , FEMSigs() ); - else Execute< Real , NormalInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , true , false , false > >( argc , argv , FEMSigs() ); - else - if( Colors.set ) - if( Density.set ) Execute< Real , NormalAndColorInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , false , true , true > >( argc , argv , FEMSigs() ); - else Execute< Real , NormalAndColorInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , false , false , true > >( argc , argv , FEMSigs() ); - else - if( Density.set ) Execute< Real , NormalInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , false , true , false > >( argc , argv , FEMSigs() ); - else Execute< Real , NormalInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , false , false , false > >( argc , argv , FEMSigs() ); + if( Colors.set ) Execute< DefaultFloatType , PointStreamColor< DefaultFloatType > >( argc , argv , FEMSigs() ); + else Execute< DefaultFloatType >( argc , argv , FEMSigs() ); #else // !FAST_COMPILE - if( Normals.set ) - if( Density.set ) - if( Colors.set ) Execute< DIMENSION , Real , NormalAndColorInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , true , true , true > >( argc , argv ); - else Execute< DIMENSION , Real , NormalInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , true , true , false > >( argc , argv ); - else - if( Colors.set ) Execute< DIMENSION , Real , NormalAndColorInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , true , false , true > >( argc , argv ); - else Execute< DIMENSION , Real , NormalInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , true , false , false > >( argc , argv ); - else - if( Density.set ) - if( Colors.set ) Execute< DIMENSION , Real , NormalAndColorInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , false , true , true > >( argc , argv ); - else Execute< DIMENSION , Real , NormalInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , false , true , false > >( argc , argv ); - else - if( Colors.set ) Execute< DIMENSION , Real , NormalAndColorInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , false , false , true > >( argc , argv ); - else Execute< DIMENSION , Real , NormalInfo< Real , DIMENSION > , FullPlyVertex< float , DIMENSION , false , false , false > >( argc , argv ); + if( Colors.set ) Execute< DIMENSION , float , PointStreamColor< float > >( argc , argv ); + else Execute< DIMENSION , float >( argc , argv ); #endif // FAST_COMPILE if( Performance.set ) { diff --git a/Src/SurfaceTrimmer.cpp b/Src/SurfaceTrimmer.cpp index b4f86f3..1fcaf65 100644 --- a/Src/SurfaceTrimmer.cpp +++ b/Src/SurfaceTrimmer.cpp @@ -39,6 +39,7 @@ DAMAGE. #include "MAT.h" #include "Geometry.h" #include "Ply.h" +#include "PointStreamData.h" MessageWriter messageWriter; @@ -80,16 +81,15 @@ long long EdgeKey( int key1 , int key2 ) else return ( ( (long long)key2 )<<32 ) | ( (long long)key1 ); } -template< class Real , class Vertex > -Vertex InterpolateVertices( const Vertex& v1 , const Vertex& v2 , Real value ) +template< typename Real , typename ... VertexData > +PlyVertexWithData< float , DIMENSION , MultiPointStreamData< float , PointStreamValue< float > , VertexData ... > > InterpolateVertices( const PlyVertexWithData< float , DIMENSION , MultiPointStreamData< float , PointStreamValue< float > , VertexData ... > >& v1 , const PlyVertexWithData< float , DIMENSION , MultiPointStreamData< float , PointStreamValue< float > , VertexData ... > >& v2 , Real value ) { - typename Vertex::Wrapper _v1(v1) , _v2(v2); - if( _v1.value()==_v2.value() ) return (_v1+_v2)/Real(2.); - Real dx = ( _v1.value()-value ) / ( _v1.value()-_v2.value() ); - return _v1*(1.f-dx) + _v2*dx; + if( std::get<0>( v1.data.data ).data==std::get<0>( v2.data.data ).data ) return (v1+v2)/Real(2.); + Real dx = ( std::get<0>( v1.data.data ).data-value ) / ( std::get<0>( v1.data.data ).data-std::get<0>( v2.data.data ).data ); + return v1*(1.f-dx) + v2*dx; } -template< class Real , class Vertex > -void SmoothValues( std::vector< Vertex >& vertices , const std::vector< std::vector< int > >& polygons ) +template< typename Real , typename ... VertexData > +void SmoothValues( std::vector< PlyVertexWithData< float , DIMENSION , MultiPointStreamData< float , PointStreamValue< float > , VertexData ... > > >& vertices , const std::vector< std::vector< int > >& polygons ) { std::vector< int > count( vertices.size() ); std::vector< Real > sums( vertices.size() , 0 ); @@ -101,16 +101,16 @@ void SmoothValues( std::vector< Vertex >& vertices , const std::vector< std::vec int j1 = j , j2 = (j+1)%sz; int v1 = polygons[i][j1] , v2 = polygons[i][j2]; count[v1]++ , count[v2]++; - sums[v1] += vertices[v2].value() , sums[v2] += vertices[v1].value(); + sums[v1] += std::get< 0 >( vertices[v2].data.data ).data , sums[v2] += std::get< 0 >( vertices[v1].data.data ).data; } } - for( size_t i=0 ; i( vertices[i].data.data ).data = ( sums[i] + std::get< 0 >( vertices[i].data.data ).data ) / ( count[i] + 1 ); } -template< class Real , class Vertex > +template< class Real , typename ... VertexData > void SplitPolygon ( const std::vector< int >& polygon , - std::vector< Vertex >& vertices , + std::vector< PlyVertexWithData< float , DIMENSION , MultiPointStreamData< float , PointStreamValue< float > , VertexData ... > > >& vertices , std::vector< std::vector< int > >* ltPolygons , std::vector< std::vector< int > >* gtPolygons , std::vector< bool >* ltFlags , std::vector< bool >* gtFlags , std::unordered_map< long long, int >& vertexTable, @@ -122,7 +122,7 @@ void SplitPolygon int gtCount = 0; for( int j=0 ; jtrimValue ); + gt[j] = ( std::get<0>( vertices[ polygon[j] ].data.data ).data>trimValue ); if( gt[j] ) gtCount++; } if ( gtCount==sz ){ if( gtPolygons ) gtPolygons->push_back( polygon ) ; if( gtFlags ) gtFlags->push_back( false ); } @@ -273,9 +273,10 @@ void SetConnectedComponents( const std::vector< std::vector< int > >& polygons , components.resize( cCount ); for( int i=0 ; i +template< typename ... VertexData > int Execute( void ) { + typedef PlyVertexWithData< float , DIMENSION , MultiPointStreamData< float , PointStreamValue< float > , VertexData ... > > Vertex; float min , max; std::vector< Vertex > vertices; std::vector< std::vector< int > > polygons; @@ -283,11 +284,11 @@ int Execute( void ) int ft , commentNum = 0; std::vector< char* > comments; char** _comments; - PlyReadPolygons< Vertex >( In.value , vertices , polygons , Vertex::Properties() , Vertex::ReadComponents , ft , &_comments , &commentNum ); + PlyReadPolygons< Vertex >( In.value , vertices , polygons , Vertex::PlyReadProperties() , Vertex::PlyReadNum , ft , &_comments , &commentNum ); for( int i=0 ; i( vertices , polygons ); - min = max = vertices[0].value(); - for( size_t i=0 ; i( min , vertices[i].value() ) , max = std::max< float >( max , vertices[i].value() ); + for( int i=0 ; i( vertices , polygons ); + min = max = std::get< 0 >( vertices[0].data.data ).data; + for( size_t i=0 ; i( min , std::get< 0 >( vertices[0].data.data ).data ) , max = std::max< float >( max , std::get< 0 >( vertices[0].data.data ).data ); if( Verbose.set ) printf( "Value Range: [%f,%f]\n" , min , max ); std::unordered_map< long long, int > vertexTable; @@ -363,7 +364,7 @@ int Execute( void ) RemoveHangingVertices( vertices , gtPolygons ); sprintf( comments[commentNum++] , "#Trimmed In: %9.1f (s)" , Time()-t ); - if( Out.set ) PlyWritePolygons< Vertex >( Out.value , vertices , gtPolygons , Vertex::Properties() , Vertex::WriteComponents , ft , &comments[0] , (int)comments.size() ); + if( Out.set ) PlyWritePolygons< Vertex >( Out.value , vertices , gtPolygons , Vertex::PlyWriteProperties() , Vertex::PlyWriteNum , ft , &comments[0] , (int)comments.size() ); return EXIT_SUCCESS; } @@ -377,13 +378,21 @@ int main( int argc , char* argv[] ) ShowUsage( argv[0] ); return EXIT_FAILURE; } - bool readFlags[ PlyColorAndValueVertex< float , DIMENSION >::ReadComponents ]; - if( !PlyReadHeader( In.value , PlyColorAndValueVertex< float , DIMENSION >::Properties() , PlyColorAndValueVertex< float , DIMENSION >::ReadComponents , readFlags ) ) fprintf( stderr , "[ERROR] Failed to read ply header: %s\n" , In.value ) , exit( 0 ); + typedef MultiPointStreamData< float , PointStreamValue< float > , PointStreamNormal< float , DIMENSION > , PointStreamColor< float > > VertexData; + typedef PlyVertexWithData< float , DIMENSION , VertexData > Vertex; + bool readFlags[ Vertex::PlyReadNum ]; + if( !PlyReadHeader( In.value , Vertex::PlyReadProperties() , Vertex::PlyReadNum , readFlags ) ) fprintf( stderr , "[ERROR] Failed to read ply header: %s\n" , In.value ) , exit( 0 ); - bool hasValue = readFlags[DIMENSION]; - bool hasColor = ( readFlags[DIMENSION+1] || readFlags[DIMENSION+4] ) && ( readFlags[DIMENSION+2] || readFlags[DIMENSION+5] ) && ( readFlags[DIMENSION+3] || readFlags[DIMENSION+6] ); + bool hasValue = VertexData::ValidPlyReadProperties< 0 >( readFlags + DIMENSION ); + bool hasNormal = VertexData::ValidPlyReadProperties< 1 >( readFlags + DIMENSION ); + bool hasColor = VertexData::ValidPlyReadProperties< 2 >( readFlags + DIMENSION ); if( !hasValue ) fprintf( stderr , "[ERROR] Ply file does not contain values\n" ) , exit( 0 ); - if( hasColor ) return Execute< PlyColorAndValueVertex< float , DIMENSION > >(); - else return Execute< PlyValueVertex< float , DIMENSION > >(); + + if( hasColor ) + if( hasNormal ) return Execute< PointStreamNormal< float , DIMENSION > , PointStreamColor< float > >(); + else return Execute< PointStreamColor< float > >(); + else + if( hasNormal ) return Execute< PointStreamNormal< float , DIMENSION > >(); + else return Execute< >(); }