From 1790081f9de195470021600c1645590319cc1d92 Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Fri, 24 Apr 2020 12:16:23 +0200 Subject: [PATCH 1/8] non xml screened poisson --- .../filter_screened_poisson/CMakeLists.txt | 5 +- .../filter_screened_poisson.cpp | 761 ++---- .../filter_screened_poisson.h | 31 +- .../filter_screened_poisson.pro | 5 +- .../filter_screened_poisson/poisson_utils.h | 567 ++++ .../CMakeLists.txt | 62 + .../Src/Allocator.h | 165 ++ .../filter_screened_poisson_xml/Src/Array.h | 126 + .../filter_screened_poisson_xml/Src/Array.inl | 662 +++++ .../Src/BSplineData.h | 471 ++++ .../Src/BSplineData.inl | 546 ++++ .../Src/BinaryNode.h | 70 + .../Src/CmdLineParser.cpp | 279 ++ .../Src/CmdLineParser.h | 120 + .../Src/CmdLineParser.inl | 141 + .../Src/Factor.cpp | 264 ++ .../filter_screened_poisson_xml/Src/Factor.h | 50 + .../Src/FunctionData.h | 109 + .../Src/FunctionData.inl | 415 +++ .../Src/Geometry.cpp | 122 + .../Src/Geometry.h | 414 +++ .../Src/Geometry.inl | 591 +++++ .../filter_screened_poisson_xml/Src/Hash.h | 29 + .../filter_screened_poisson_xml/Src/MAT.h | 48 + .../filter_screened_poisson_xml/Src/MAT.inl | 217 ++ .../Src/MarchingCubes.cpp | 1025 ++++++++ .../Src/MarchingCubes.h | 147 ++ .../Src/MemoryUsage.h | 165 ++ .../Src/MultiGridOctreeData.Evaluation.inl | 1151 +++++++++ .../Src/MultiGridOctreeData.IsoSurface.inl | 1106 ++++++++ .../MultiGridOctreeData.SortedTreeNodes.inl | 357 +++ .../Src/MultiGridOctreeData.System.inl | 2274 +++++++++++++++++ .../MultiGridOctreeData.WeightedSamples.inl | 443 ++++ .../Src/MultiGridOctreeData.h | 990 +++++++ .../Src/MultiGridOctreeData.inl | 654 +++++ .../filter_screened_poisson_xml/Src/MyTime.h | 51 + .../filter_screened_poisson_xml/Src/Octree.h | 184 ++ .../Src/Octree.inl | 1135 ++++++++ .../Src/PPolynomial.h | 113 + .../Src/PPolynomial.inl | 470 ++++ .../Src/PlyVertexMini.h | 172 ++ .../Src/PointStream.h | 207 ++ .../Src/PointStream.inl | 201 ++ .../Src/PoissonRecon.cpp | 780 ++++++ .../Src/Polynomial.h | 100 + .../Src/Polynomial.inl | 369 +++ .../Src/SSDRecon.cpp | 760 ++++++ .../Src/SparseMatrix.h | 194 ++ .../Src/SparseMatrix.inl | 504 ++++ .../Src/SurfaceTrimmer.cpp | 382 +++ .../filter_screened_poisson_xml/Src/Time.cpp | 46 + .../filter_screened_poisson_xml/Src/Time.h | 32 + .../filter_screened_poisson_xml/Src/Vector.h | 111 + .../Src/Vector.inl | 304 +++ .../filter_screened_poisson.cpp | 676 +++++ .../filter_screened_poisson.h | 43 + .../filter_screened_poisson.pro | 21 + .../filter_screened_poisson.xml | 76 + 58 files changed, 20886 insertions(+), 627 deletions(-) create mode 100644 src/meshlabplugins/filter_screened_poisson/poisson_utils.h create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/CMakeLists.txt create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/Allocator.h create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/Array.h create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/Array.inl create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/BSplineData.h create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/BSplineData.inl create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/BinaryNode.h create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/CmdLineParser.cpp create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/CmdLineParser.h create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/CmdLineParser.inl create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/Factor.cpp create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/Factor.h create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/FunctionData.h create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/FunctionData.inl create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/Geometry.cpp create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/Geometry.h create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/Geometry.inl create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/Hash.h create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/MAT.h create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/MAT.inl create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/MarchingCubes.cpp create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/MarchingCubes.h create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/MemoryUsage.h create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.Evaluation.inl create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.IsoSurface.inl create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.SortedTreeNodes.inl create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.System.inl create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.WeightedSamples.inl create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.h create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.inl create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/MyTime.h create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/Octree.h create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/Octree.inl create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/PPolynomial.h create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/PPolynomial.inl create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/PlyVertexMini.h create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/PointStream.h create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/PointStream.inl create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/PoissonRecon.cpp create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/Polynomial.h create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/Polynomial.inl create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/SSDRecon.cpp create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/SparseMatrix.h create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/SparseMatrix.inl create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/SurfaceTrimmer.cpp create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/Time.cpp create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/Time.h create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/Vector.h create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/Src/Vector.inl create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/filter_screened_poisson.cpp create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/filter_screened_poisson.h create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/filter_screened_poisson.pro create mode 100644 src/plugins_unsupported/filter_screened_poisson_xml/filter_screened_poisson.xml diff --git a/src/meshlabplugins/filter_screened_poisson/CMakeLists.txt b/src/meshlabplugins/filter_screened_poisson/CMakeLists.txt index 2f02f6dd7..3cfef1a52 100644 --- a/src/meshlabplugins/filter_screened_poisson/CMakeLists.txt +++ b/src/meshlabplugins/filter_screened_poisson/CMakeLists.txt @@ -31,12 +31,9 @@ set(HEADERS Src/SparseMatrix.h Src/Time.h Src/Vector.h + poisson_utils.h filter_screened_poisson.h) -set(XML filter_screened_poisson.xml) -meshlab_install_plugin_xml(${CMAKE_CURRENT_SOURCE_DIR}/${XML} XML_OUT) -list(APPEND SOURCES ${XML_OUT}) - add_library(filter_screened_poisson MODULE ${SOURCES} ${HEADERS}) target_compile_definitions(filter_screened_poisson PRIVATE BRUNO_LEVY_FIX diff --git a/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.cpp b/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.cpp index e5450be5b..9a372c863 100644 --- a/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.cpp +++ b/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.cpp @@ -25,652 +25,183 @@ #include #include #endif -#include -#include "Src/MyTime.h" -#include "Src/MemoryUsage.h" -#include "Src/MarchingCubes.h" -#include "Src/Octree.h" -#include "Src/SparseMatrix.h" -#include "Src/CmdLineParser.h" -#include "Src/PPolynomial.h" -void DumpOutput( const char* format , ... ); -void DumpOutput2( char* str , const char* format , ... ); -#include "Src/PointStream.h" - -#include "Src/MultiGridOctreeData.h" #include "filter_screened_poisson.h" -#include - - - -void DumpOutput( const char* format , ... ) -{ - char buf[4096]; - va_list marker; - va_start( marker, format ); - - vsprintf(buf,format,marker); - va_end( marker ); - - qDebug(buf); - } -void DumpOutput2(std::vector< char* >& comments , const char* format , ... ) -{ - char buf[4096]; - va_list marker; - va_start( marker, format ); - - vsprintf(buf,format,marker); - va_end( marker ); - qDebug(buf); -} - - -#if defined( _WIN32 ) || defined( _WIN64 ) -double PeakMemoryUsageMB( void ) -{ - HANDLE h = GetCurrentProcess(); - PROCESS_MEMORY_COUNTERS pmc; - return GetProcessMemoryInfo( h , &pmc , sizeof(pmc) ) ? ( (double)pmc.PeakWorkingSetSize )/(1<<20) : 0; -} -#endif // _WIN32 || _WIN64 - -#if defined( _WIN32 ) || defined( _WIN64 ) -inline double to_seconds( const FILETIME& ft ) -{ - const double low_to_sec=100e-9; // 100 nanoseconds - const double high_to_sec=low_to_sec*4294967296.0; - return ft.dwLowDateTime*low_to_sec+ft.dwHighDateTime*high_to_sec; -} -#endif // _WIN32 || _WIN64 - - -template< class Real > -struct OctreeProfiler -{ - Octree< Real >& tree; - double t; - - OctreeProfiler( Octree< Real >& t ) : tree(t) { ; } - void start( void ){ t = Time() , tree.resetLocalMemoryUsage(); } - void print( const char* header ) const - { - tree.memoryUsage(); -#if defined( _WIN32 ) || defined( _WIN64 ) - if( header ) printf( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); - else printf( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); -#else // !_WIN32 && !_WIN64 - if( header ) printf( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); - else printf( "%9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); -#endif // _WIN32 || _WIN64 - } - void dumpOutput( const char* header ) const - { - tree.memoryUsage(); -#if defined( _WIN32 ) || defined( _WIN64 ) - if( header ) DumpOutput( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); - else DumpOutput( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); -#else // !_WIN32 && !_WIN64 - if( header ) DumpOutput( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); - else DumpOutput( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); -#endif // _WIN32 || _WIN64 - } - void dumpOutput2( std::vector< char* >& comments , const char* header ) const - { - tree.memoryUsage(); -#if defined( _WIN32 ) || defined( _WIN64 ) - if( header ) DumpOutput2( comments , "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); - else DumpOutput2( comments , "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); -#else // !_WIN32 && !_WIN64 - if( header ) DumpOutput2( comments , "%s %9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); - else DumpOutput2( comments , "%9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); -#endif // _WIN32 || _WIN64 - } -}; - - - -// Constructor usually performs only two simple tasks of filling the two lists -// - typeList: with all the possible id of the filtering actions -// - actionList with the corresponding actions. If you want to add icons to your filtering actions you can do here by construction the QActions accordingly +#include "poisson_utils.h" FilterScreenedPoissonPlugin::FilterScreenedPoissonPlugin() { -} -template -class PoissonParam -{ -public: - int MaxDepthVal; - int MaxSolveDepthVal; - int KernelDepthVal; - int MinDepthVal; - int FullDepthVal; - Real SamplesPerNodeVal; - Real ScaleVal; - bool ConfidenceFlag; - bool CleanFlag; - bool DensityFlag; - Real PointWeightVal; - int AdaptiveExponentVal; - int BoundaryTypeVal; - bool CompleteFlag; - bool NonManifoldFlag; - bool ShowResidualFlag; - int CGDepthVal; - int ItersVal; - Real CSSolverAccuracyVal; - - bool VerboseFlag; - int ThreadsVal; - bool LinearFitFlag; - float LowResIterMultiplierVal; - float ColorVal; - - PoissonParam() - { - MaxDepthVal=8; - MaxSolveDepthVal=-1; - KernelDepthVal=-1; - MinDepthVal=0; - FullDepthVal=5; - SamplesPerNodeVal =1.5f; - ScaleVal=1.1f; - ConfidenceFlag=false; - CleanFlag=false; - DensityFlag=false; - PointWeightVal = 4.0f; - AdaptiveExponentVal=1; - BoundaryTypeVal=1; - CompleteFlag=false; - NonManifoldFlag=false; - ShowResidualFlag=false; - CGDepthVal=0; - ItersVal=8; - CSSolverAccuracyVal=1e-3f; - - VerboseFlag=true; - ThreadsVal=omp_get_num_procs(); - LinearFitFlag = false; - LowResIterMultiplierVal=1.f; - ColorVal=16.0f; - } -}; + typeList << FP_SCREENED_POISSON; - -template< class Real> -XForm4x4 GetPointStreamScale(vcg::Box3 &bb, float expFact) -{ - qDebug("bbox %f %f %f - %f %f %f ",bb.min[0],bb.min[1],bb.min[2],bb.max[0],bb.max[1],bb.max[2]); - Real scale = bb.Dim()[bb.MaxDim()] * expFact; - Point3m center = bb.Center(); - for( int i=0 ; i<3 ; i++ ) center[i] -= scale/2; - XForm4x4< Real > tXForm = XForm4x4< Real >::Identity() , sXForm = XForm4x4< Real >::Identity(); - for( int i=0 ; i<3 ; i++ ) sXForm(i,i) = (Real)(1./scale ) , tXForm(3,i) = -center[i]; - return sXForm * tXForm; + for (FilterIDType tt : types()){ + actionList << new QAction(filterName(tt), this); + } } - -template< class Real > -class MeshModelPointStream : public OrientedPointStreamWithData< Real, Point3m > -{ - CMeshO &_m; - size_t _curPos; -public: - MeshModelPointStream( CMeshO &m):_m(m),_curPos(0) - { - vcg::tri::RequireCompactness(m); - } - ~MeshModelPointStream( void ){} - void reset( void ) { _curPos =0;} - bool nextPoint( OrientedPoint3D< Real >& pt, Point3m &d) - { - if(_curPos>=_m.vn) - return false; - Point3m &nn = _m.vert[_curPos].N(); - Point3m tp = _m.Tr * _m.vert[_curPos].P(); - Point4m np = _m.Tr * Point4m(nn[0],nn[1],nn[2],0); - - pt.p[0] = tp[0]; - pt.p[1] = tp[1]; - pt.p[2] = tp[2]; - pt.n[0] = np[0]; - pt.n[1] = np[1]; - pt.n[2] = np[2]; - - d[0]=Real(_m.vert[_curPos].C()[0]); - d[1]=Real(_m.vert[_curPos].C()[1]); - d[2]=Real(_m.vert[_curPos].C()[2]); - - ++_curPos; - return true; - } - -}; - -template< class Real > -class MeshDocumentPointStream : public OrientedPointStreamWithData< Real, Point3m > +FilterScreenedPoissonPlugin::~FilterScreenedPoissonPlugin() { - MeshDocument &_md; - MeshModel *_curMesh; - size_t _curPos; - size_t _totalSize; -public: - MeshDocumentPointStream( MeshDocument &md):_md(md),_curMesh(0),_curPos(0) - { - _totalSize=0; - MeshModel *m=0; - do - { - m=_md.nextVisibleMesh(m); - if(m!=0) - { - vcg::tri::RequireCompactness(m->cm); - _totalSize+=m->cm.vn; - } - } while(m); - qDebug("TotalSize %i",_totalSize); - } - ~MeshDocumentPointStream( void ){} - void reset( void ) { _curPos =0; _curMesh=0;} - bool nextPoint( OrientedPoint3D< Real >& pt, Point3m &d ) - { - Point3m nn(0,0,0); -// do - { - if((_curMesh==0) || (_curPos >= _curMesh->cm.vn) ) - { - _curMesh = _md.nextVisibleMesh(_curMesh); - _curPos = 0; - } + for (QAction* a : actionList){ + delete a; + } +} - if(_curMesh==0) - return false; - if(_curPos < _curMesh->cm.vn) - { - nn = _curMesh->cm.vert[_curPos].N(); - Point3m tp = _curMesh->cm.Tr * _curMesh->cm.vert[_curPos].P(); - Point4m np = _curMesh->cm.Tr * Point4m(nn[0],nn[1],nn[2],0); -// Point3m tp = _curMesh->cm.vert[_curPos].P(); -// Point3m np = nn; - pt.p[0] = tp[0]; - pt.p[1] = tp[1]; - pt.p[2] = tp[2]; - pt.n[0] = np[0]; - pt.n[1] = np[1]; - pt.n[2] = np[2]; - d[0]=Real(_curMesh->cm.vert[_curPos].C()[0]); - d[1]=Real(_curMesh->cm.vert[_curPos].C()[1]); - d[2]=Real(_curMesh->cm.vert[_curPos].C()[2]); - - ++_curPos; - } - } - assert(nn!=Point3m(0,0,0)); - return true; - } - -}; - - - - -template< class Real , int Degree , BoundaryType BType , class Vertex > -int _Execute(OrientedPointStream< Real > *pointStream, Box3m bb, CMeshO &pm, PoissonParam &pp, vcg::CallBackPos* cb) +QString FilterScreenedPoissonPlugin::filterName(FilterIDType filter) const { - typedef typename Octree< Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; - typedef typename Octree< Real >::template InterpolationInfo< false > InterpolationInfo; - typedef OrientedPointStreamWithData< Real , Point3D< Real > > PointStreamWithData; - typedef TransformedOrientedPointStreamWithData< Real , Point3D< Real > > XPointStreamWithData; - Reset< Real >(); - std::vector< char* > comments; - - XForm4x4< Real > xForm = GetPointStreamScale(bb,pp.ScaleVal); - XForm4x4< Real > iXForm = xForm.inverse(); - DumpOutput2( comments , "Running Screened Poisson Reconstruction (Version 9.0)\n" ); - double startTime = Time(); - - OctNode< TreeNodeData >::SetAllocator(MEMORY_ALLOCATOR_BLOCK_SIZE); - Octree< Real > tree; - OctreeProfiler< Real > profiler( tree ); - tree.threads = pp.ThreadsVal; - if( pp.MaxSolveDepthVal<0 ) pp.MaxSolveDepthVal = pp.MaxDepthVal; - - - - qDebug("Using %i threads\n",pp.ThreadsVal); -// int kernelDepth = KernelDepth.set ? KernelDepth.value : Depth.value-2; - if(pp.KernelDepthVal<0) pp.KernelDepthVal =pp.MaxDepthVal-2; - if( pp.KernelDepthVal>pp.MaxDepthVal ) - { - printf("kernelDepth cannot be greateer Depth.value\n"); - return false; - } - - int pointCount; - - Real pointWeightSum; - std::vector< typename Octree< Real >::PointSample >* samples = new std::vector< typename Octree< Real >::PointSample >(); - std::vector< ProjectiveData< Point3D< Real > , Real > >* sampleData = NULL; - DensityEstimator* density = NULL; - SparseNodeData< Point3D< Real > , NORMAL_DEGREE >* normalInfo = NULL; - Real targetValue = (Real)0.5; - - // Read in the samples (and color data) - { - profiler.start(); -// PointStream* pointStream; - -// char* ext = GetFileExtension( In.value ); -// if( Color.set && Color.value>0 ) -// { -// sampleData = new std::vector< ProjectiveData< Point3D< Real > , Real > >(); -// if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryOrientedPointStreamWithData< Real , Point3D< Real > , float , Point3D< unsigned char > >( In.value ); -// else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYOrientedPointStreamWithData< Real , Point3D< Real > >( In.value , ColorInfo< Real >::PlyProperties , 6 , ColorInfo< Real >::ValidPlyProperties ); -// else pointStream = new ASCIIOrientedPointStreamWithData< Real , Point3D< Real > >( In.value , ColorInfo< Real >::ReadASCII ); -// } -// else -// { -// if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryOrientedPointStream< Real , float >( In.value ); -// else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYOrientedPointStream< Real >( In.value ); -// else pointStream = new ASCIIOrientedPointStream< Real >( In.value ); -// } -// delete[] ext; - sampleData = new std::vector< ProjectiveData< Point3D< Real > , Real > >(); - XPointStreamWithData _pointStream( xForm , ( PointStreamWithData& )*pointStream ); - pointCount = tree.template init< Point3D< Real > >( _pointStream , pp.MaxDepthVal , pp.ConfidenceFlag , *samples , sampleData ); - -#pragma omp parallel for num_threads( pp.ThreadsVal ) - for( int i=0 ; i<(int)samples->size() ; i++ ) (*samples)[i].sample.data.n *= (Real)-1; - - DumpOutput( "Input Points / Samples: %d / %d\n" , pointCount , samples->size() ); - profiler.dumpOutput2( comments , "# Read input into tree:" ); + if (filter == FP_SCREENED_POISSON) + return "Surface Reconstruction: Screened Poisson"; + else { + return "Error!"; } - - DenseNodeData< Real , Degree > solution; +} - { - DenseNodeData< Real , Degree > constraints; - InterpolationInfo* iInfo = NULL; - int solveDepth = pp.MaxSolveDepthVal; - - tree.resetNodeIndices(); - - // Get the kernel density estimator [If discarding, compute anew. Otherwise, compute once.] - { - profiler.start(); - density = tree.template setDensityEstimator< WEIGHT_DEGREE >( *samples , pp.KernelDepthVal , pp.SamplesPerNodeVal ); - profiler.dumpOutput2( comments , "# Got kernel density:" ); - } - - // Transform the Hermite samples into a vector field [If discarding, compute anew. Otherwise, compute once.] - { - profiler.start(); - normalInfo = new SparseNodeData< Point3D< Real > , NORMAL_DEGREE >(); - *normalInfo = tree.template setNormalField< NORMAL_DEGREE >( *samples , *density , pointWeightSum , BType==BOUNDARY_NEUMANN ); - profiler.dumpOutput2( comments , "# Got normal field:" ); - } - - if( !pp.DensityFlag ) delete density , density = NULL; - - // Trim the tree and prepare for multigrid - { - profiler.start(); - std::vector< int > indexMap; - - constexpr int MAX_DEGREE = NORMAL_DEGREE > Degree ? NORMAL_DEGREE : Degree; - tree.template inalizeForBroodedMultigrid< MAX_DEGREE , Degree , BType >( pp.FullDepthVal , typename Octree< Real >::template HasNormalDataFunctor< NORMAL_DEGREE >( *normalInfo ) , &indexMap ); - - if( normalInfo ) normalInfo->remapIndices( indexMap ); - if( density ) density->remapIndices( indexMap ); - profiler.dumpOutput2( comments , "# Finalized tree:" ); - } - - // Add the FEM constraints - { - profiler.start(); - constraints = tree.template initDenseNodeData< Degree >( ); - tree.template addFEMConstraints< Degree , BType , NORMAL_DEGREE , BType >( FEMVFConstraintFunctor< NORMAL_DEGREE , BType , Degree , BType >( 1. , 0. ) , *normalInfo , constraints , solveDepth ); - profiler.dumpOutput2( comments , "# Set FEM constraints:" ); - } - - // Free up the normal info [If we don't need it for subseequent iterations.] - delete normalInfo , normalInfo = NULL; - - // Add the interpolation constraints - if( pp.PointWeightVal>0 ) - { - profiler.start(); - iInfo = new InterpolationInfo( tree , *samples , targetValue , pp.AdaptiveExponentVal , (Real)pp.PointWeightVal * pointWeightSum , (Real)0 ); - tree.template addInterpolationConstraints< Degree , BType >( *iInfo , constraints , solveDepth ); - profiler.dumpOutput2( comments , "#Set point constraints:" ); - } - - DumpOutput( "Leaf Nodes / Active Nodes / Ghost Nodes: %d / %d / %d\n" , (int)tree.leaves() , (int)tree.nodes() , (int)tree.ghostNodes() ); - DumpOutput( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage())/(1<<20) ); - - // Solve the linear system - { - profiler.start(); - typename Octree< Real >::SolverInfo solverInfo; - solverInfo.cgDepth = pp.CGDepthVal , solverInfo.iters = pp.ItersVal , solverInfo.cgAccuracy = pp.CSSolverAccuracyVal , solverInfo.verbose = pp.VerboseFlag , solverInfo.showResidual = pp.ShowResidualFlag , solverInfo.lowResIterMultiplier = std::max< double >( 1. , pp.LowResIterMultiplierVal ); - solution = tree.template solveSystem< Degree , BType >( FEMSystemFunctor< Degree , BType >( 0 , 1. , 0 ) , iInfo , constraints , solveDepth , solverInfo ); - profiler.dumpOutput2( comments , "# Linear system solved:" ); - if( iInfo ) delete iInfo , iInfo = NULL; - } +QString FilterScreenedPoissonPlugin::filterInfo(FilterIDType filter) const +{ + if (filter == FP_SCREENED_POISSON) + return "This surface reconstruction algorithm creates watertight surfaces from oriented point sets.\n" + "The filter uses the original code of Michael Kazhdan and Matthew Bolitho implementing the algorithm described in the following paper:\n" + "Michael Kazhdan, Hugues Hoppe,\n" + "\"Screened Poisson surface reconstruction\"\n" + "ACM Trans. Graphics, 32(3), 2013\n" + "WARNING: this filter saves intermediate cache files in the \"working\" folder (last folder used when loading/saving). Be sure you are not working in a READ-ONLY location.\n"; + else { + return "Error!"; } +} - CoredFileMeshData< Vertex > mesh; +MeshFilterInterface::FilterClass FilterScreenedPoissonPlugin::getClass(QAction* a) +{ + if (ID(a) == FP_SCREENED_POISSON){ + return FilterScreenedPoissonPlugin::FilterClass(MeshFilterInterface::Remeshing); + } + else { + assert(0); + return MeshFilterInterface::Generic; + } +} +int FilterScreenedPoissonPlugin::getRequirements(QAction* a) +{ + if (ID(a) == FP_SCREENED_POISSON){ + + } + else { + assert(0); + return 0; + } +} + +bool FilterScreenedPoissonPlugin::applyFilter(QAction* filter, MeshDocument& md, RichParameterSet& params, vcg::CallBackPos* cb) +{ + /*bool currDirChanged=false; + QDir currDir = QDir::current(); + + if (filter == "Surface Reconstruction: Screened Poisson") { - profiler.start(); - double valueSum = 0 , weightSum = 0; - typename Octree< Real >::template MultiThreadedEvaluator< Degree , BType > evaluator( &tree , solution , pp.ThreadsVal ); -#pragma omp parallel for num_threads( pp.ThreadsVal ) reduction( + : valueSum , weightSum ) - for( int j=0 ; jsize() ; j++ ) + //check if folder is writable + QTemporaryFile file("./_tmp_XXXXXX.tmp"); + if (!file.open()) { - ProjectiveData< OrientedPoint3D< Real > , Real >& sample = (*samples)[j].sample; - Real w = sample.weight; - if( w>0 ) weightSum += w , valueSum += evaluator.value( sample.data.p / sample.weight , omp_get_thread_num() , (*samples)[j].node ) * w; + currDirChanged=true; + QTemporaryDir tmpdir; + QDir::setCurrent(tmpdir.path()); + Log("Warning - current folder is not writable. Screened Poisson Merging needs to save intermediate files in the current working folder. Project and meshes must be in a write-enabled folder. Please save your data in a suitable folder before applying."); + //errorMessage = "current folder is not writable.
Screened Poisson Merging needs to save intermediate files in the current working folder.
Project and meshes must be in a write-enabled folder.
Please save your data in a suitable folder before applying."; + //return false; } - Real isoValue = (Real)( valueSum / weightSum ); -// if( samples ) delete samples , samples = NULL; - profiler.dumpOutput( "Got average:" ); - DumpOutput( "Iso-Value: %e\n" , isoValue ); - profiler.start(); - SparseNodeData< ProjectiveData< Point3D< Real > , Real > , DATA_DEGREE >* colorData = NULL; - if( sampleData ) + PoissonParam pp; + pp.MaxDepthVal = params.evalInt("depth"); + pp.FullDepthVal = params.evalInt("fullDepth"); + pp.CGDepthVal= params.evalInt("cgDepth"); + pp.ScaleVal = params.evalFloat("scale"); + pp.SamplesPerNodeVal = params.evalFloat("samplesPerNode"); + pp.PointWeightVal = params.evalFloat("pointWeight"); + pp.ItersVal = params.evalInt("iters"); + pp.ConfidenceFlag = params.evalBool("confidence"); + pp.DensityFlag = true; + pp.CleanFlag = params.evalBool("preClean"); + + bool goodNormal=true, goodColor=true; + if(params.evalBool("visibleLayer") == false) { - colorData = new SparseNodeData< ProjectiveData< Point3D< Real > , Real > , DATA_DEGREE >(); - *colorData = tree.template setDataField< DATA_DEGREE , false >( *samples , *sampleData , (DensityEstimator*)NULL ); - delete sampleData , sampleData = NULL; - for( const OctNode< TreeNodeData >* n = tree.tree().nextNode() ; n ; n=tree.tree().nextNode( n ) ) - { - ProjectiveData< Point3D< Real > , Real >* clr = (*colorData)( n ); - if( clr ) - (*clr) *= (Real)pow( pp.ColorVal , tree.depth( n ) ); + PoissonClean(md.mm()->cm, pp.ConfidenceFlag, pp.CleanFlag); + goodNormal=HasGoodNormal(md.mm()->cm); + goodColor = md.mm()->hasDataMask(MeshModel::MM_VERTCOLOR); + } + else + { + MeshModel *_mm=0; + while(_mm=md.nextVisibleMesh(_mm)) { + PoissonClean(_mm->cm, pp.ConfidenceFlag, pp.CleanFlag); + goodNormal &= HasGoodNormal(_mm->cm); + goodColor &= _mm->hasDataMask(MeshModel::MM_VERTCOLOR); } } - tree.template getMCIsoSurface< Degree , BType , WEIGHT_DEGREE , DATA_DEGREE >( density , colorData , solution , isoValue , mesh , !pp.LinearFitFlag , !pp.NonManifoldFlag , false /*PolygonMesh.set*/ ); - DumpOutput( "Vertices / Polygons: %d / %d\n" , mesh.outOfCorePointCount()+mesh.inCorePoints.size() , mesh.polygonCount() ); - profiler.dumpOutput2( comments , "# Got triangles:" ); - } -// FreePointer( solution ); - - cb(90,"Creating Mesh"); - mesh.resetIterator(); - int vm = mesh.outOfCorePointCount()+mesh.inCorePoints.size(); - for(auto pt=mesh.inCorePoints.begin();pt!=mesh.inCorePoints.end();++pt) - { - Point3D pp = iXForm*pt->point; - vcg::tri::Allocator::AddVertex(pm,Point3m(pp[0],pp[1],pp[2])); - pm.vert.back().Q() = pt->value; - pm.vert.back().C()[0] = pt->color[0]; - pm.vert.back().C()[1] = pt->color[1]; - pm.vert.back().C()[2] = pt->color[2]; - } - for (int ii=0; ii < mesh.outOfCorePointCount(); ii++){ - Vertex pt; - mesh.nextOutOfCorePoint(pt); - Point3D pp = iXForm*pt.point; - vcg::tri::Allocator::AddVertex(pm,Point3m(pp[0],pp[1],pp[2])); - pm.vert.back().Q() = pt.value; - pm.vert.back().C()[0] = pt.color[0]; - pm.vert.back().C()[1] = pt.color[1]; - pm.vert.back().C()[2] = pt.color[2]; - } - - std::vector< CoredVertexIndex > polygon; - while(mesh.nextPolygon( polygon )) - { - assert(polygon.size()==3); - int indV[3]; - for( int i=0 ; i::AddFace(pm, &pm.vert[indV[0]], &pm.vert[indV[1]], &pm.vert[indV[2]]); - } - cb(100,"Done"); - -// if( colorData ) delete colorData , colorData = NULL; + if(!goodNormal) + { + this->errorMessage = "Filter requires correct per vertex normals.
" + "E.g. it is necessary that your ALL the input vertices have a proper, not-null normal.
" + "Try enabling the pre-clean option and retry.

" + "To permanently remove this problem:
" + "If you encounter this error on a triangulated mesh try to use the Remove Unreferenced Vertices filter" + "If you encounter this error on a pointcloud try to use the Conditional Vertex Selection filter" + "with function '(nx==0.0) && (ny==0.0) && (nz==0.0)', and then delete selected vertices.
"; + return false; + } + MeshModel *pm =md.addNewMesh("","Poisson mesh",false); + md.setVisible(pm->id(),false); + pm->updateDataMask(MeshModel::MM_VERTQUALITY); + if(goodColor) pm->updateDataMask(MeshModel::MM_VERTCOLOR); - if( density ) delete density , density = NULL; - DumpOutput2( comments , "# Total Solve: %9.1f (s), %9.1f (MB)\n" , Time()-startTime , tree.maxMemoryUsage() ); + if(params.evalBool("visibleLayer")) + { + Box3m bb; + MeshModel *_mm=0; + while(_mm=md.nextVisibleMesh(_mm)) + bb.Add(_mm->cm.Tr,_mm->cm.bbox); - return 1; -} - - - -template -void PoissonClean(MeshType &m, bool scaleNormal, bool cleanFlag) -{ - vcg::tri::UpdateNormal::NormalizePerVertex(m); - - if(cleanFlag) { - for (auto vi = m.vert.begin(); vi != m.vert.end(); ++vi) - if (vcg::SquaredNorm(vi->N()) < std::numeric_limits::min()*10.0) - vcg::tri::Allocator::DeleteVertex(m,*vi); - - for (auto fi = m.face.begin(); fi != m.face.end(); ++fi) - if( fi->V(0)->IsD() || fi->V(1)->IsD() || fi->V(2)->IsD() ) - vcg::tri::Allocator::DeleteFace(m,*fi); - } - - vcg::tri::Allocator::CompactEveryVector(m); - if(scaleNormal) - { - for(auto vi=m.vert.begin();vi!=m.vert.end();++vi) - vi->N() *= vi->Q(); - } -} - -bool HasGoodNormal(CMeshO &m) -{ - for(auto vi=m.vert.begin();vi!=m.vert.end();++vi) - if(vcg::SquaredNorm(vi->N()) < std::numeric_limits::min()*10.0) - return false; - - return true; -} - -bool FilterScreenedPoissonPlugin::applyFilter( const QString& filterName,MeshDocument& md,EnvWrap& env, vcg::CallBackPos* cb) -{ - bool currDirChanged=false; - QDir currDir = QDir::current(); - - if (filterName == "Surface Reconstruction: Screened Poisson") - { - //check if folder is writable - QTemporaryFile file("./_tmp_XXXXXX.tmp"); - if (!file.open()) - { - currDirChanged=true; - QTemporaryDir tmpdir; - QDir::setCurrent(tmpdir.path()); - Log("Warning - current folder is not writable. Screened Poisson Merging needs to save intermediate files in the current working folder. Project and meshes must be in a write-enabled folder. Please save your data in a suitable folder before applying."); - //errorMessage = "current folder is not writable.
Screened Poisson Merging needs to save intermediate files in the current working folder.
Project and meshes must be in a write-enabled folder.
Please save your data in a suitable folder before applying."; - //return false; + MeshDocumentPointStream documentStream(md); + _Execute >(&documentStream,bb,pm->cm,pp,cb); + } + else + { + MeshModelPointStream meshStream(md.mm()->cm); + _Execute >(&meshStream,md.mm()->cm.bbox,pm->cm,pp,cb); + } + pm->UpdateBoxAndNormals(); + md.setVisible(pm->id(),true); + md.setCurrentMesh(pm->id()); + if(currDirChanged) QDir::setCurrent(currDir.path()); + return true; } + return false;*/ +} - PoissonParam pp; - pp.MaxDepthVal = env.evalInt("depth"); - pp.FullDepthVal = env.evalInt("fullDepth"); - pp.CGDepthVal= env.evalInt("cgDepth"); - pp.ScaleVal = env.evalFloat("scale"); - pp.SamplesPerNodeVal = env.evalFloat("samplesPerNode"); - pp.PointWeightVal = env.evalFloat("pointWeight"); - pp.ItersVal = env.evalInt("iters"); - pp.ConfidenceFlag = env.evalBool("confidence"); - pp.DensityFlag = true; - pp.CleanFlag = env.evalBool("preClean"); - - bool goodNormal=true, goodColor=true; - if(env.evalBool("visibleLayer") == false) - { - PoissonClean(md.mm()->cm, pp.ConfidenceFlag, pp.CleanFlag); - goodNormal=HasGoodNormal(md.mm()->cm); - goodColor = md.mm()->hasDataMask(MeshModel::MM_VERTCOLOR); - } - else - { - MeshModel *_mm=0; - while(_mm=md.nextVisibleMesh(_mm)) { - PoissonClean(_mm->cm, pp.ConfidenceFlag, pp.CleanFlag); - goodNormal &= HasGoodNormal(_mm->cm); - goodColor &= _mm->hasDataMask(MeshModel::MM_VERTCOLOR); - } - } - - if(!goodNormal) - { - this->errorMessage = "Filter requires correct per vertex normals.
" - "E.g. it is necessary that your ALL the input vertices have a proper, not-null normal.
" - "Try enabling the pre-clean option and retry.

" - "To permanently remove this problem:
" - "If you encounter this error on a triangulated mesh try to use the Remove Unreferenced Vertices filter" - "If you encounter this error on a pointcloud try to use the Conditional Vertex Selection filter" - "with function '(nx==0.0) && (ny==0.0) && (nz==0.0)', and then delete selected vertices.
"; - return false; - } - - MeshModel *pm =md.addNewMesh("","Poisson mesh",false); - md.setVisible(pm->id(),false); - pm->updateDataMask(MeshModel::MM_VERTQUALITY); - if(goodColor) pm->updateDataMask(MeshModel::MM_VERTCOLOR); - - if(env.evalBool("visibleLayer")) - { - Box3m bb; - MeshModel *_mm=0; - while(_mm=md.nextVisibleMesh(_mm)) - bb.Add(_mm->cm.Tr,_mm->cm.bbox); +void FilterScreenedPoissonPlugin::initParameterSet( + QAction* filter, + MeshModel& m, + RichParameterSet& parent) +{ + if (ID(filter) == FP_SCREENED_POISSON) { - MeshDocumentPointStream documentStream(md); - _Execute >(&documentStream,bb,pm->cm,pp,cb); - } - else - { - MeshModelPointStream meshStream(md.mm()->cm); - _Execute >(&meshStream,md.mm()->cm.bbox,pm->cm,pp,cb); - } - pm->UpdateBoxAndNormals(); - md.setVisible(pm->id(),true); - md.setCurrentMesh(pm->id()); - if(currDirChanged) QDir::setCurrent(currDir.path()); - return true; - } - return false; + } +} + +int FilterScreenedPoissonPlugin::postCondition(QAction* filter) const +{ + if (ID(filter) == FP_SCREENED_POISSON){ + return MeshModel::MM_VERTNUMBER + MeshModel::MM_FACENUMBER; + } + else { + return MeshModel::MM_ALL; + } } +MeshFilterInterface::FILTER_ARITY FilterScreenedPoissonPlugin::filterArity(QAction*) const +{ + return VARIABLE; +} - - -MESHLAB_PLUGIN_NAME_EXPORTER(FilterScreenedPoissonPlugin) diff --git a/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.h b/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.h index 475a4400c..eb7f858d0 100644 --- a/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.h +++ b/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.h @@ -27,16 +27,35 @@ #include //class QScriptEngine; -class FilterScreenedPoissonPlugin : public MeshLabFilterInterface +class FilterScreenedPoissonPlugin : public QObject, public MeshFilterInterface { - Q_OBJECT - MESHLAB_PLUGIN_IID_EXPORTER(MESHLAB_FILTER_INTERFACE_IID) - Q_INTERFACES(MeshLabFilterInterface) + Q_OBJECT + MESHLAB_PLUGIN_IID_EXPORTER(MESH_FILTER_INTERFACE_IID) + Q_INTERFACES(MeshFilterInterface) public: - FilterScreenedPoissonPlugin(); + enum { + FP_SCREENED_POISSON + }; - bool applyFilter(const QString& filterName,MeshDocument& md,EnvWrap& env, vcg::CallBackPos* cb) ; + FilterScreenedPoissonPlugin(); + ~FilterScreenedPoissonPlugin(); + + QString filterName(FilterIDType filter) const; + QString filterInfo(FilterIDType filter) const; + + FilterClass getClass(QAction* a); + int getRequirements(QAction* a); + + bool applyFilter( + QAction* filter, + MeshDocument& md, + RichParameterSet& params, + vcg::CallBackPos* cb) ; + + void initParameterSet(QAction* a,MeshModel& m, RichParameterSet& parent); + int postCondition(QAction* filter) const; + FILTER_ARITY filterArity(QAction*) const; }; diff --git a/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.pro b/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.pro index a9a5f4702..b9959898d 100644 --- a/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.pro +++ b/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.pro @@ -5,7 +5,8 @@ macx:QMAKE_CXXFLAGS_RELEASE+= -O3 -DRELEASE -funroll-loops -ffast-math -Wno-sig linux:QMAKE_LFLAGS += -fopenmp -lgomp HEADERS += \ - filter_screened_poisson.h + filter_screened_poisson.h \ + poisson_utils.h SOURCES += \ filter_screened_poisson.cpp \ @@ -14,8 +15,8 @@ SOURCES += \ Src/Factor.cpp \ Src/Geometry.cpp + TARGET = filter_screened_poisson DEFINES += BRUNO_LEVY_FIX DEFINES += FOR_RELEASE -include (../../shared_post.pri) diff --git a/src/meshlabplugins/filter_screened_poisson/poisson_utils.h b/src/meshlabplugins/filter_screened_poisson/poisson_utils.h new file mode 100644 index 000000000..bcf5b49be --- /dev/null +++ b/src/meshlabplugins/filter_screened_poisson/poisson_utils.h @@ -0,0 +1,567 @@ +/**************************************************************************** +* MeshLab o o * +* A versatile mesh processing toolbox o o * +* _ O _ * +* Copyright(C) 2005 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ +#ifndef POISSON_UTILS_H +#define POISSON_UTILS_H + +#ifdef WIN32 +#include +#include +#endif +#include +#include "Src/MyTime.h" +#include "Src/MemoryUsage.h" +#include "Src/MarchingCubes.h" +#include "Src/Octree.h" +#include "Src/SparseMatrix.h" +#include "Src/CmdLineParser.h" +#include "Src/PPolynomial.h" +#include + +#include "Src/MultiGridOctreeData.h" + +#include +#include +#include + +inline void DumpOutput( const char* format , ... ) +{ + char buf[4096]; + va_list marker; + va_start( marker, format ); + + vsprintf(buf,format,marker); + va_end( marker ); + + qDebug() << buf; +} + +inline void DumpOutput2(std::vector< char* >& , const char* format , ... ) +{ + char buf[4096]; + va_list marker; + va_start( marker, format ); + + vsprintf(buf,format,marker); + va_end( marker ); + qDebug() << buf; +} + +#if defined( _WIN32 ) || defined( _WIN64 ) +inline double PeakMemoryUsageMB( void ) +{ + HANDLE h = GetCurrentProcess(); + PROCESS_MEMORY_COUNTERS pmc; + return GetProcessMemoryInfo( h , &pmc , sizeof(pmc) ) ? ( (double)pmc.PeakWorkingSetSize )/(1<<20) : 0; +} + +inline double to_seconds( const FILETIME& ft ) +{ + const double low_to_sec=100e-9; // 100 nanoseconds + const double high_to_sec=low_to_sec*4294967296.0; + return ft.dwLowDateTime*low_to_sec+ft.dwHighDateTime*high_to_sec; +} +#endif // _WIN32 || _WIN64 + +template< class Real > +struct OctreeProfiler +{ + Octree< Real >& tree; + double t; + + OctreeProfiler( Octree< Real >& t ) : tree(t) { ; } + void start( void ){ t = Time() , tree.resetLocalMemoryUsage(); } + void print( const char* header ) const + { + tree.memoryUsage(); +#if defined( _WIN32 ) || defined( _WIN64 ) + if( header ) printf( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); + else printf( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); +#else // !_WIN32 && !_WIN64 + if( header ) printf( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); + else printf( "%9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); +#endif // _WIN32 || _WIN64 + } + void dumpOutput( const char* header ) const + { + tree.memoryUsage(); +#if defined( _WIN32 ) || defined( _WIN64 ) + if( header ) DumpOutput( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); + else DumpOutput( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); +#else // !_WIN32 && !_WIN64 + if( header ) DumpOutput( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); + else DumpOutput( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); +#endif // _WIN32 || _WIN64 + } + void dumpOutput2( std::vector< char* >& comments , const char* header ) const + { + tree.memoryUsage(); +#if defined( _WIN32 ) || defined( _WIN64 ) + if( header ) DumpOutput2( comments , "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); + else DumpOutput2( comments , "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); +#else // !_WIN32 && !_WIN64 + if( header ) DumpOutput2( comments , "%s %9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); + else DumpOutput2( comments , "%9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); +#endif // _WIN32 || _WIN64 + } +}; + +template +class PoissonParam +{ +public: + int MaxDepthVal; + int MaxSolveDepthVal; + int KernelDepthVal; + int MinDepthVal; + int FullDepthVal; + Real SamplesPerNodeVal; + Real ScaleVal; + bool ConfidenceFlag; + bool CleanFlag; + bool DensityFlag; + Real PointWeightVal; + int AdaptiveExponentVal; + int BoundaryTypeVal; + bool CompleteFlag; + bool NonManifoldFlag; + bool ShowResidualFlag; + int CGDepthVal; + int ItersVal; + Real CSSolverAccuracyVal; + + bool VerboseFlag; + int ThreadsVal; + bool LinearFitFlag; + float LowResIterMultiplierVal; + float ColorVal; + + PoissonParam() { + MaxDepthVal=8; + MaxSolveDepthVal=-1; + KernelDepthVal=-1; + MinDepthVal=0; + FullDepthVal=5; + SamplesPerNodeVal =1.5f; + ScaleVal=1.1f; + ConfidenceFlag=false; + CleanFlag=false; + DensityFlag=false; + PointWeightVal = 4.0f; + AdaptiveExponentVal=1; + BoundaryTypeVal=1; + CompleteFlag=false; + NonManifoldFlag=false; + ShowResidualFlag=false; + CGDepthVal=0; + ItersVal=8; + CSSolverAccuracyVal=1e-3f; + + VerboseFlag=true; + ThreadsVal=omp_get_num_procs(); + LinearFitFlag = false; + LowResIterMultiplierVal=1.f; + ColorVal=16.0f; + } +}; + +template< class Real > +class MeshModelPointStream : public OrientedPointStreamWithData< Real, Point3m > +{ + CMeshO &_m; + size_t _curPos; +public: + MeshModelPointStream( CMeshO &m):_m(m),_curPos(0) + { + vcg::tri::RequireCompactness(m); + } + + ~MeshModelPointStream( void ){} + + void reset( void ) { _curPos =0;} + + bool nextPoint( OrientedPoint3D< Real >& pt, Point3m &d) + { + if(_curPos>=_m.vn) + return false; + Point3m &nn = _m.vert[_curPos].N(); + Point3m tp = _m.Tr * _m.vert[_curPos].P(); + Point4m np = _m.Tr * Point4m(nn[0],nn[1],nn[2],0); + + pt.p[0] = tp[0]; + pt.p[1] = tp[1]; + pt.p[2] = tp[2]; + pt.n[0] = np[0]; + pt.n[1] = np[1]; + pt.n[2] = np[2]; + + d[0]=Real(_m.vert[_curPos].C()[0]); + d[1]=Real(_m.vert[_curPos].C()[1]); + d[2]=Real(_m.vert[_curPos].C()[2]); + + ++_curPos; + return true; + } +}; + +template< class Real > +class MeshDocumentPointStream : public OrientedPointStreamWithData< Real, Point3m > +{ + MeshDocument &_md; + MeshModel *_curMesh; + size_t _curPos; + size_t _totalSize; +public: + MeshDocumentPointStream( MeshDocument &md):_md(md),_curMesh(0),_curPos(0) + { + _totalSize=0; + MeshModel *m=0; + do { + m=_md.nextVisibleMesh(m); + if(m!=0) { + vcg::tri::RequireCompactness(m->cm); + _totalSize+=m->cm.vn; + } + } while(m); + qDebug("TotalSize %i",_totalSize); + } + + ~MeshDocumentPointStream( void ){} + + void reset( void ) { _curPos =0; _curMesh=0;} + + bool nextPoint( OrientedPoint3D< Real >& pt, Point3m &d ) + { + Point3m nn(0,0,0); + // do + { + if((_curMesh==0) || (_curPos >= _curMesh->cm.vn) ) { + _curMesh = _md.nextVisibleMesh(_curMesh); + _curPos = 0; + } + + if(_curMesh==0) + return false; + if(_curPos < _curMesh->cm.vn) { + nn = _curMesh->cm.vert[_curPos].N(); + Point3m tp = _curMesh->cm.Tr * _curMesh->cm.vert[_curPos].P(); + Point4m np = _curMesh->cm.Tr * Point4m(nn[0],nn[1],nn[2],0); + // Point3m tp = _curMesh->cm.vert[_curPos].P(); + // Point3m np = nn; + pt.p[0] = tp[0]; + pt.p[1] = tp[1]; + pt.p[2] = tp[2]; + pt.n[0] = np[0]; + pt.n[1] = np[1]; + pt.n[2] = np[2]; + d[0]=Real(_curMesh->cm.vert[_curPos].C()[0]); + d[1]=Real(_curMesh->cm.vert[_curPos].C()[1]); + d[2]=Real(_curMesh->cm.vert[_curPos].C()[2]); + + ++_curPos; + } + } + assert(nn!=Point3m(0,0,0)); + return true; + } + +}; + +template< class Real> +XForm4x4 GetPointStreamScale(vcg::Box3 &bb, float expFact) +{ + qDebug("bbox %f %f %f - %f %f %f ",bb.min[0],bb.min[1],bb.min[2],bb.max[0],bb.max[1],bb.max[2]); + Real scale = bb.Dim()[bb.MaxDim()] * expFact; + Point3m center = bb.Center(); + for( int i=0 ; i<3 ; i++ ) + center[i] -= scale/2; + XForm4x4< Real > tXForm = XForm4x4< Real >::Identity() , sXForm = XForm4x4< Real >::Identity(); + for( int i=0 ; i<3 ; i++ ) { + sXForm(i,i) = (Real)(1./scale ); + tXForm(3,i) = -center[i]; + } + return sXForm * tXForm; +} + +template< class Real , int Degree , BoundaryType BType , class Vertex > +int _Execute( + OrientedPointStream< Real > *pointStream, + Box3m bb, CMeshO &pm, + PoissonParam &pp, + vcg::CallBackPos* cb) +{ + typedef typename Octree< Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; + typedef typename Octree< Real >::template InterpolationInfo< false > InterpolationInfo; + typedef OrientedPointStreamWithData< Real , Point3D< Real > > PointStreamWithData; + typedef TransformedOrientedPointStreamWithData< Real , Point3D< Real > > XPointStreamWithData; + Reset< Real >(); + std::vector< char* > comments; + + XForm4x4< Real > xForm = GetPointStreamScale(bb,pp.ScaleVal); + XForm4x4< Real > iXForm = xForm.inverse(); + DumpOutput2( comments , "Running Screened Poisson Reconstruction (Version 9.0)\n" ); + double startTime = Time(); + + OctNode< TreeNodeData >::SetAllocator(MEMORY_ALLOCATOR_BLOCK_SIZE); + Octree< Real > tree; + OctreeProfiler< Real > profiler( tree ); + tree.threads = pp.ThreadsVal; + if( pp.MaxSolveDepthVal<0 ) pp.MaxSolveDepthVal = pp.MaxDepthVal; + + qDebug("Using %i threads\n",pp.ThreadsVal); + // int kernelDepth = KernelDepth.set ? KernelDepth.value : Depth.value-2; + if(pp.KernelDepthVal<0) pp.KernelDepthVal =pp.MaxDepthVal-2; + if( pp.KernelDepthVal>pp.MaxDepthVal ) { + printf("kernelDepth cannot be greateer Depth.value\n"); + return false; + } + + int pointCount; + + Real pointWeightSum; + std::vector< typename Octree< Real >::PointSample >* samples = new std::vector< typename Octree< Real >::PointSample >(); + std::vector< ProjectiveData< Point3D< Real > , Real > >* sampleData = NULL; + DensityEstimator* density = NULL; + SparseNodeData< Point3D< Real > , NORMAL_DEGREE >* normalInfo = NULL; + Real targetValue = (Real)0.5; + + // Read in the samples (and color data) + { + profiler.start(); + // PointStream* pointStream; + + // char* ext = GetFileExtension( In.value ); + // if( Color.set && Color.value>0 ) + // { + // sampleData = new std::vector< ProjectiveData< Point3D< Real > , Real > >(); + // if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryOrientedPointStreamWithData< Real , Point3D< Real > , float , Point3D< unsigned char > >( In.value ); + // else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYOrientedPointStreamWithData< Real , Point3D< Real > >( In.value , ColorInfo< Real >::PlyProperties , 6 , ColorInfo< Real >::ValidPlyProperties ); + // else pointStream = new ASCIIOrientedPointStreamWithData< Real , Point3D< Real > >( In.value , ColorInfo< Real >::ReadASCII ); + // } + // else + // { + // if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryOrientedPointStream< Real , float >( In.value ); + // else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYOrientedPointStream< Real >( In.value ); + // else pointStream = new ASCIIOrientedPointStream< Real >( In.value ); + // } + // delete[] ext; + sampleData = new std::vector< ProjectiveData< Point3D< Real > , Real > >(); + XPointStreamWithData _pointStream( xForm , ( PointStreamWithData& )*pointStream ); + pointCount = tree.template init< Point3D< Real > >( _pointStream , pp.MaxDepthVal , pp.ConfidenceFlag , *samples , sampleData ); + + #pragma omp parallel for num_threads( pp.ThreadsVal ) + for( int i=0 ; i<(int)samples->size() ; i++ ) + (*samples)[i].sample.data.n *= (Real)-1; + + DumpOutput( "Input Points / Samples: %d / %d\n" , pointCount , samples->size() ); + profiler.dumpOutput2( comments , "# Read input into tree:" ); + } + + DenseNodeData< Real , Degree > solution; + + { + DenseNodeData< Real , Degree > constraints; + InterpolationInfo* iInfo = NULL; + int solveDepth = pp.MaxSolveDepthVal; + + tree.resetNodeIndices(); + + // Get the kernel density estimator [If discarding, compute anew. Otherwise, compute once.] + { + profiler.start(); + density = tree.template setDensityEstimator< WEIGHT_DEGREE >( *samples , pp.KernelDepthVal , pp.SamplesPerNodeVal ); + profiler.dumpOutput2( comments , "# Got kernel density:" ); + } + + // Transform the Hermite samples into a vector field [If discarding, compute anew. Otherwise, compute once.] + { + profiler.start(); + normalInfo = new SparseNodeData< Point3D< Real > , NORMAL_DEGREE >(); + *normalInfo = tree.template setNormalField< NORMAL_DEGREE >( *samples , *density , pointWeightSum , BType==BOUNDARY_NEUMANN ); + profiler.dumpOutput2( comments , "# Got normal field:" ); + } + + if( !pp.DensityFlag ) { + delete density; + density = NULL; + } + + // Trim the tree and prepare for multigrid + { + profiler.start(); + std::vector< int > indexMap; + + constexpr int MAX_DEGREE = NORMAL_DEGREE > Degree ? NORMAL_DEGREE : Degree; + tree.template inalizeForBroodedMultigrid< MAX_DEGREE , Degree , BType >( pp.FullDepthVal , typename Octree< Real >::template HasNormalDataFunctor< NORMAL_DEGREE >( *normalInfo ) , &indexMap ); + + if( normalInfo ) normalInfo->remapIndices( indexMap ); + if( density ) density->remapIndices( indexMap ); + profiler.dumpOutput2( comments , "# Finalized tree:" ); + } + + // Add the FEM constraints + { + profiler.start(); + constraints = tree.template initDenseNodeData< Degree >( ); + tree.template addFEMConstraints< Degree , BType , NORMAL_DEGREE , BType >( FEMVFConstraintFunctor< NORMAL_DEGREE , BType , Degree , BType >( 1. , 0. ) , *normalInfo , constraints , solveDepth ); + profiler.dumpOutput2( comments , "# Set FEM constraints:" ); + } + + // Free up the normal info [If we don't need it for subseequent iterations.] + delete normalInfo; + normalInfo = NULL; + + // Add the interpolation constraints + if( pp.PointWeightVal>0 ) { + profiler.start(); + iInfo = new InterpolationInfo( tree , *samples , targetValue , pp.AdaptiveExponentVal , (Real)pp.PointWeightVal * pointWeightSum , (Real)0 ); + tree.template addInterpolationConstraints< Degree , BType >( *iInfo , constraints , solveDepth ); + profiler.dumpOutput2( comments , "#Set point constraints:" ); + } + + DumpOutput( "Leaf Nodes / Active Nodes / Ghost Nodes: %d / %d / %d\n" , (int)tree.leaves() , (int)tree.nodes() , (int)tree.ghostNodes() ); + DumpOutput( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage())/(1<<20) ); + + // Solve the linear system + { + profiler.start(); + typename Octree< Real >::SolverInfo solverInfo; + solverInfo.cgDepth = pp.CGDepthVal , solverInfo.iters = pp.ItersVal , solverInfo.cgAccuracy = pp.CSSolverAccuracyVal , solverInfo.verbose = pp.VerboseFlag , solverInfo.showResidual = pp.ShowResidualFlag , solverInfo.lowResIterMultiplier = std::max< double >( 1. , pp.LowResIterMultiplierVal ); + solution = tree.template solveSystem< Degree , BType >( FEMSystemFunctor< Degree , BType >( 0 , 1. , 0 ) , iInfo , constraints , solveDepth , solverInfo ); + profiler.dumpOutput2( comments , "# Linear system solved:" ); + if( iInfo ) delete iInfo , iInfo = NULL; + } + } + + CoredFileMeshData< Vertex > mesh; + + { + profiler.start(); + double valueSum = 0 , weightSum = 0; + typename Octree< Real >::template MultiThreadedEvaluator< Degree , BType > evaluator( &tree , solution , pp.ThreadsVal ); + #pragma omp parallel for num_threads( pp.ThreadsVal ) reduction( + : valueSum , weightSum ) + for( int j=0 ; jsize() ; j++ ) { + ProjectiveData< OrientedPoint3D< Real > , Real >& sample = (*samples)[j].sample; + Real w = sample.weight; + if( w>0 ) weightSum += w , valueSum += evaluator.value( sample.data.p / sample.weight , omp_get_thread_num() , (*samples)[j].node ) * w; + } + Real isoValue = (Real)( valueSum / weightSum ); + // if( samples ) delete samples , samples = NULL; + profiler.dumpOutput( "Got average:" ); + DumpOutput( "Iso-Value: %e\n" , isoValue ); + + profiler.start(); + SparseNodeData< ProjectiveData< Point3D< Real > , Real > , DATA_DEGREE >* colorData = NULL; + if( sampleData ) { + colorData = new SparseNodeData< ProjectiveData< Point3D< Real > , Real > , DATA_DEGREE >(); + *colorData = tree.template setDataField< DATA_DEGREE , false >( *samples , *sampleData , (DensityEstimator*)NULL ); + delete sampleData , sampleData = NULL; + for( const OctNode< TreeNodeData >* n = tree.tree().nextNode() ; n ; n=tree.tree().nextNode( n ) ) { + ProjectiveData< Point3D< Real > , Real >* clr = (*colorData)( n ); + if( clr ) + (*clr) *= (Real)pow( pp.ColorVal , tree.depth( n ) ); + } + } + tree.template getMCIsoSurface< Degree , BType , WEIGHT_DEGREE , DATA_DEGREE >( density , colorData , solution , isoValue , mesh , !pp.LinearFitFlag , !pp.NonManifoldFlag , false /*PolygonMesh.set*/ ); + DumpOutput( "Vertices / Polygons: %d / %d\n" , mesh.outOfCorePointCount()+mesh.inCorePoints.size() , mesh.polygonCount() ); + profiler.dumpOutput2( comments , "# Got triangles:" ); + } + + // FreePointer( solution ); + + cb(90,"Creating Mesh"); + mesh.resetIterator(); + int vm = mesh.outOfCorePointCount()+mesh.inCorePoints.size(); + for(auto pt=mesh.inCorePoints.begin();pt!=mesh.inCorePoints.end();++pt) { + Point3D pp = iXForm*pt->point; + vcg::tri::Allocator::AddVertex(pm,Point3m(pp[0],pp[1],pp[2])); + pm.vert.back().Q() = pt->value; + pm.vert.back().C()[0] = pt->color[0]; + pm.vert.back().C()[1] = pt->color[1]; + pm.vert.back().C()[2] = pt->color[2]; + } + for (int ii=0; ii < mesh.outOfCorePointCount(); ii++) { + Vertex pt; + mesh.nextOutOfCorePoint(pt); + Point3D pp = iXForm*pt.point; + vcg::tri::Allocator::AddVertex(pm,Point3m(pp[0],pp[1],pp[2])); + pm.vert.back().Q() = pt.value; + pm.vert.back().C()[0] = pt.color[0]; + pm.vert.back().C()[1] = pt.color[1]; + pm.vert.back().C()[2] = pt.color[2]; + } + + std::vector< CoredVertexIndex > polygon; + while(mesh.nextPolygon( polygon )) { + assert(polygon.size()==3); + int indV[3]; + for( int i=0 ; i::AddFace(pm, &pm.vert[indV[0]], &pm.vert[indV[1]], &pm.vert[indV[2]]); + } + cb(100,"Done"); + + //if( colorData ) delete colorData , colorData = NULL; + + + if( density ) delete density , density = NULL; + DumpOutput2( comments , "# Total Solve: %9.1f (s), %9.1f (MB)\n" , Time()-startTime , tree.maxMemoryUsage() ); + + return 1; +} + +template +void PoissonClean(MeshType &m, bool scaleNormal, bool cleanFlag) +{ + vcg::tri::UpdateNormal::NormalizePerVertex(m); + + if(cleanFlag) { + for (auto vi = m.vert.begin(); vi != m.vert.end(); ++vi) + if (vcg::SquaredNorm(vi->N()) < std::numeric_limits::min()*10.0) + vcg::tri::Allocator::DeleteVertex(m,*vi); + + for (auto fi = m.face.begin(); fi != m.face.end(); ++fi) + if( fi->V(0)->IsD() || fi->V(1)->IsD() || fi->V(2)->IsD() ) + vcg::tri::Allocator::DeleteFace(m,*fi); + } + + vcg::tri::Allocator::CompactEveryVector(m); + if(scaleNormal) { + for(auto vi=m.vert.begin();vi!=m.vert.end();++vi) + vi->N() *= vi->Q(); + } +} + +bool HasGoodNormal(CMeshO &m) +{ + for(auto vi=m.vert.begin();vi!=m.vert.end();++vi) + if(vcg::SquaredNorm(vi->N()) < std::numeric_limits::min()*10.0) + return false; + + return true; +} + +#endif // POISSON_UTILS_H diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/CMakeLists.txt b/src/plugins_unsupported/filter_screened_poisson_xml/CMakeLists.txt new file mode 100644 index 000000000..2f02f6dd7 --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/CMakeLists.txt @@ -0,0 +1,62 @@ +# Copyright 2019 Collabora, Ltd. +# SPDX-License-Identifier: BSL-1.0 + +### Generated file! Edit the templates in src/templates then re-run ./make-cmake.py + +set(SOURCES + filter_screened_poisson.cpp Src/MarchingCubes.cpp + # Src/CmdLineParser.cpp + Src/Factor.cpp Src/Geometry.cpp) + +set(HEADERS + Src/Allocator.h + Src/Array.h + Src/BSplineData.h + Src/BinaryNode.h + Src/CmdLineParser.h + Src/Factor.h + Src/FunctionData.h + Src/Geometry.h + Src/Hash.h + Src/MAT.h + Src/MarchingCubes.h + Src/MemoryUsage.h + Src/MultiGridOctreeData.h + Src/MyTime.h + Src/Octree.h + Src/PPolynomial.h + Src/PlyVertexMini.h + Src/PointStream.h + Src/Polynomial.h + Src/SparseMatrix.h + Src/Time.h + Src/Vector.h + filter_screened_poisson.h) + +set(XML filter_screened_poisson.xml) +meshlab_install_plugin_xml(${CMAKE_CURRENT_SOURCE_DIR}/${XML} XML_OUT) +list(APPEND SOURCES ${XML_OUT}) + +add_library(filter_screened_poisson MODULE ${SOURCES} ${HEADERS}) + +target_compile_definitions(filter_screened_poisson PRIVATE BRUNO_LEVY_FIX + FOR_RELEASE) + +if(OpenMP_CXX_FOUND) + target_link_libraries(filter_screened_poisson PRIVATE OpenMP::OpenMP_CXX) +endif() + +target_include_directories(filter_screened_poisson + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(filter_screened_poisson PUBLIC common) + +set_property(TARGET filter_screened_poisson PROPERTY FOLDER Plugins) + +set_property(TARGET filter_screened_poisson + PROPERTY RUNTIME_OUTPUT_DIRECTORY ${MESHLAB_PLUGIN_OUTPUT_DIR}) + +set_property(TARGET filter_screened_poisson + PROPERTY LIBRARY_OUTPUT_DIRECTORY ${MESHLAB_PLUGIN_OUTPUT_DIR}) + +install(TARGETS filter_screened_poisson DESTINATION + ${MESHLAB_PLUGIN_INSTALL_DIR} COMPONENT Plugins) diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/Allocator.h b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Allocator.h new file mode 100644 index 000000000..3ba23d9d6 --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Allocator.h @@ -0,0 +1,165 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +#ifndef ALLOCATOR_INCLUDED +#define ALLOCATOR_INCLUDED + +#include + +class AllocatorState +{ +public: + int index , remains; +}; +/** This templated class assists in memory allocation and is well suited for instances + * when it is known that the sequence of memory allocations is performed in a stack-based + * manner, so that memory allocated last is released first. It also preallocates memory + * in chunks so that multiple requests for small chunks of memory do not require separate + * system calls to the memory manager. + * The allocator is templated off of the class of objects that we would like it to allocate, + * ensuring that appropriate constructors and destructors are called as necessary. + */ +template +class Allocator +{ + int blockSize; + int index , remains; + std::vector< T* > memory; +public: + Allocator( void ){ blockSize = index = remains = 0; } + ~Allocator( void ){ reset(); } + + /** This method is the allocators destructor. It frees up any of the memory that + * it has allocated. */ + void reset( void ) + { + for( size_t i=0 ; iblockSize = blockSize; + index=-1; + remains=0; + } + + /** This method returns a pointer to an array of elements objects. If there is left over pre-allocated + * memory, this method simply returns a pointer to the next free piece of memory, otherwise it pre-allocates + * more memory. Note that if the number of objects requested is larger than the value blockSize with which + * the allocator was initialized, the request for memory will fail. + */ + T* newElements( int elements=1 ) + { + T* mem; + if( !elements ) return NULL; + if( elements>blockSize ) fprintf( stderr , "[ERROR] Allocator: elements bigger than block-size: %d>%d\n" , elements , blockSize ) , exit( 0 ); + if( remains + +#ifdef _WIN64 +#define ASSERT( x ) { if( !( x ) ) __debugbreak(); } +#else // !_WIN64 +#ifdef _WIN32 +#define ASSERT( x ) { if( !( x ) ) _asm{ int 0x03 } } +#else // !_WIN32 +#define ASSERT( x ) { if( !( x ) ) exit(0); } +#endif // _WIN32 +#endif // _WIN64 + +// Code from http://stackoverflow.com +void* aligned_malloc( size_t size , size_t align ) +{ + // Align enough for the data, the alignment padding, and room to store a pointer to the actual start of the memory + void* mem = malloc( size + align + sizeof( void* ) ); + // The position at which we could potentially start addressing + char* amem = ( (char*)mem ) + sizeof( void* ); + // Add align-1 to the start of the address and then zero out at most of the first align-1 bits. + amem = ( char* )( ( (size_t)( ( (char*)amem ) + (align-1) ) ) & ~( align-1 ) ); + // Pre-write the actual address + ( ( void** ) amem )[-1] = mem; + return amem; +} +void aligned_free( void* mem ) { free( ( ( void** )mem )[-1] ); } + +#ifdef ARRAY_DEBUG +#pragma message ( "[WARNING] Array debugging is enabled" ) +#include "Array.inl" +#define Pointer( ... ) Array< __VA_ARGS__ > +#define ConstPointer( ... ) ConstArray< __VA_ARGS__ > +#define NullPointer( ... ) Array< __VA_ARGS__ >() +template< class C > void FreePointer( Array< C >& a ){ a.Free( ); } +template< class C > void AlignedFreePointer( Array< C >& a ){ a.Free( ); } +template< class C > void VFreePointer( Array< C >& a ){ a.Free( ); } +template< class C > void DeletePointer( Array< C >& a ){ a.Delete( ); } + +template< class C > Array< C > NewPointer( size_t size , const char* name=NULL ){ return Array< C >::New ( size , name ); } +template< class C > Array< C > AllocPointer( size_t size , const char* name=NULL ){ return Array< C >::Alloc ( size , false , name ); } +template< class C > Array< C > AlignedAllocPointer( size_t size , size_t alignment , const char* name=NULL ){ return Array< C >::AlignedAlloc( size , alignment , false , name ); } +template< class C > Array< C > ReAllocPointer( Array< C >& a , size_t size , const char* name=NULL ){ return Array< C >::ReAlloc ( a , size , false , name ); } + +template< class C > C* PointerAddress( Array< C >& a ) { return a.pointer(); } +template< class C > const C* PointerAddress( ConstArray< C >& a ) { return a.pointer(); } +template< class C > Array< C > GetPointer( C& c ) { return Array< C >::FromPointer( &c , 1 ); } +template< class C > ConstArray< C > GetPointer( const C& c ) { return ConstArray< C >::FromPointer( &c , 1 ); } +template< class C > Array< C > GetPointer( std::vector< C >& v ){ return Array< C >::FromPointer( &v[0] , v.size() ); } +template< class C > ConstArray< C > GetPointer( const std::vector< C >& v ){ return ConstArray< C >::FromPointer( &v[0] , v.size() ); } + +template< class C > Array< C > GetPointer( C* c , int sz ) { return Array< C >::FromPointer( c , sz ); } +template< class C > ConstArray< C > GetPointer( const C* c , int sz ) { return ConstArray< C >::FromPointer( c , sz ); } + +#else // !ARRAY_DEBUG +#define Pointer( ... ) __VA_ARGS__* +#define ConstPointer( ... ) const __VA_ARGS__* +#define NullPointer( ... ) NULL + +#define FreePointer( ... ) { if( __VA_ARGS__ ) free( __VA_ARGS__ ) , __VA_ARGS__ = NULL; } +#define AlignedFreePointer( ... ) { if( __VA_ARGS__ ) aligned_free( __VA_ARGS__ ) , __VA_ARGS__ = NULL; } +#define DeletePointer( ... ) { if( __VA_ARGS__ ) delete[] __VA_ARGS__ , __VA_ARGS__ = NULL; } + +// [BL] Added memory clear here to avoid uninitialized memory read in SparseMatrix. +template< class C > C* NewPointer( size_t size , const char* name=NULL ){ return new C[size]; } + +template< class C > C* AllocPointer( size_t size , const char* name=NULL ){ + return (C*) calloc(size, sizeof(C)); +} + +template< class C > C* AlignedAllocPointer( size_t size , size_t alignment , const char* name=NULL ){ + C* result = (C*)aligned_malloc( sizeof(C) * size , alignment ); + memset(result, 0, sizeof(C)*size); + return result; +} + +template< class C > C* ReAllocPointer( C* c , size_t size , const char* name=NULL ){ + C* result = (C*)realloc( c , sizeof(C) * size ); + // [BL] cannot clear memory here, because I do not know what the previous size was... + return result; +} + +//template< class C > C* NullPointer( void ){ return NULL; } + +template< class C > C* PointerAddress( C* c ){ return c; } +template< class C > const C* PointerAddress( const C* c ){ return c; } +template< class C > C* GetPointer( C& c ){ return &c; } +template< class C > const C* GetPointer( const C& c ){ return &c; } +template< class C > C* GetPointer( std::vector< C >& v ){ return &v[0]; } +template< class C > const C* GetPointer( const std::vector< C >& v ){ return &v[0]; } + +template< class C > C* GetPointer( C* c , int sz ) { return c; } +template< class C > const C* GetPointer( const C* c , int sz ) { return c; } + +#endif // ARRAY_DEBUG +#endif // ARRAY_INCLUDED diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/Array.inl b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Array.inl new file mode 100644 index 000000000..6247f5282 --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Array.inl @@ -0,0 +1,662 @@ +/* +Copyright (c) 2011, Michael Kazhdan and Ming Chuang +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ +#define FULL_ARRAY_DEBUG 0 // Note that this is not thread-safe + +#include +#include +#include +#ifdef _WIN32 +#include +#endif // _WIN32 +#include + +inline bool isfinitef( float fp ){ float f=fp; return ((*(unsigned *)&f)&0x7f800000)!=0x7f800000; } + + +template< class C > bool IsValid( const C& c ); +#if _DEBUG +template< > inline bool IsValid< float >( const float& f ) { return isfinitef( f ) && ( f==0.f || abs(f)>1e-31f ); } +#else // !_DEBUG +template< > inline bool IsValid< float >( const float& f ) { return isfinitef( f ); } +#endif // _DEBUG +template< > inline bool IsValid< __m128 >( const __m128& m ) +{ + const __m128* addr = &m; + if( size_t(addr) & 15 ) return false; + else return true; +} +template< class C > inline bool IsValid( const C& c ){ return true; } + + +#if FULL_ARRAY_DEBUG +class DebugMemoryInfo +{ +public: + const void* address; + char name[512]; +}; +static std::vector< DebugMemoryInfo > memoryInfo; +#endif // FULL_ARRAY_DEBUG + +template< class C > +class Array +{ + void _assertBounds( long long idx ) const + { + if( idx=max ) + { + fprintf( stderr , "Array index out-of-bounds: %lld <= %lld < %lld\n" , min , idx , max ); + ASSERT( 0 ); + exit( 0 ); + } + } +protected: + C *data , *_data; + long long min , max; +#if FULL_ARRAY_DEBUG + static void _AddMemoryInfo( const void* ptr , const char* name ) + { + size_t sz = memoryInfo.size(); + memoryInfo.resize( sz + 1 ); + memoryInfo[sz].address = ptr; + if( name ) strcpy( memoryInfo[sz].name , name ); + else memoryInfo[sz].name[0] = 0; + } + static void _RemoveMemoryInfo( const void* ptr ) + { + { + size_t idx; + for( idx=0 ; idx + Array( Array< D >& a ) + { + _data = NULL; + if( !a ) + { + data = NULL; + min = max = 0; + } + else + { + // [WARNING] Chaning szC and szD to size_t causes some really strange behavior. + long long szC = sizeof( C ); + long long szD = sizeof( D ); + data = (C*)a.data; + min = ( a.minimum() * szD ) / szC; + max = ( a.maximum() * szD ) / szC; + if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD ) + { + fprintf( stderr , "Could not convert array [ %lld , %lld ] * %lld => [ %lld , %lld ] * %lld\n" , a.minimum() , a.maximum() , szD , min , max , szC ); + ASSERT( 0 ); + exit( 0 ); + } + } + } + static Array FromPointer( C* data , long long max ) + { + Array a; + a._data = NULL; + a.data = data; + a.min = 0; + a.max = max; + return a; + } + static Array FromPointer( C* data , long long min , long long max ) + { + Array a; + a._data = NULL; + a.data = data; + a.min = min; + a.max = max; + return a; + } + inline bool operator == ( const Array< C >& a ) const { return data==a.data; } + inline bool operator != ( const Array< C >& a ) const { return data!=a.data; } + inline bool operator == ( const C* c ) const { return data==c; } + inline bool operator != ( const C* c ) const { return data!=c; } + inline C* operator -> ( void ) + { + _assertBounds( 0 ); + return data; + } + inline const C* operator -> ( ) const + { + _assertBounds( 0 ); + return data; + } + inline C& operator[]( long long idx ) + { + _assertBounds( idx ); + return data[idx]; + } + inline const C& operator[]( long long idx ) const + { + _assertBounds( idx ); + return data[idx]; + } + inline Array operator + ( int idx ) const + { + Array a; + a._data = _data; + a.data = data+idx; + a.min = min-idx; + a.max = max-idx; + return a; + } + inline Array operator + ( long long idx ) const + { + Array a; + a._data = _data; + a.data = data+idx; + a.min = min-idx; + a.max = max-idx; + return a; + } + inline Array operator + ( unsigned int idx ) const + { + Array a; + a._data = _data; + a.data = data+idx; + a.min = min-idx; + a.max = max-idx; + return a; + } + inline Array operator + ( unsigned long long idx ) const + { + Array a; + a._data = _data; + a.data = data+idx; + a.min = min-idx; + a.max = max-idx; + return a; + } + inline Array& operator += ( int idx ) + { + min -= idx; + max -= idx; + data += idx; + return (*this); + } + inline Array& operator += ( long long idx ) + { + min -= idx; + max -= idx; + data += idx; + return (*this); + } + inline Array& operator += ( unsigned int idx ) + { + min -= idx; + max -= idx; + data += idx; + return (*this); + } + inline Array& operator += ( unsigned long long idx ) + { + min -= idx; + max -= idx; + data += idx; + return (*this); + } + inline Array& operator ++ ( void ) { return (*this) += 1; } + inline Array operator++( int ){ Array< C > temp = (*this) ; (*this) +=1 ; return temp; } + Array operator - ( int idx ) const { return (*this) + (-idx); } + Array operator - ( long long idx ) const { return (*this) + (-idx); } + Array operator - ( unsigned int idx ) const { return (*this) + (-idx); } + Array operator - ( unsigned long long idx ) const { return (*this) + (-idx); } + Array& operator -= ( int idx ) { return (*this) += (-idx); } + Array& operator -= ( long long idx ) { return (*this) += (-idx); } + Array& operator -= ( unsigned int idx ) { return (*this) += (-idx); } + Array& operator -= ( unsigned long long idx ) { return (*this) += (-idx); } + Array& operator -- ( void ) { return (*this) -= 1; } + inline Array operator--( int ){ Array< C > temp = (*this) ; (*this) -=1 ; return temp; } + long long operator - ( const Array& a ) const { return ( long long )( data - a.data ); } + + void Free( void ) + { + if( _data ) + { + free( _data ); +#if FULL_ARRAY_DEBUG + _RemoveMemoryInfo( _data ); +#endif // FULL_ARRAY_DEBUG + } + (*this) = Array( ); + } + void Delete( void ) + { + if( _data ) + { + delete[] _data; +#if FULL_ARRAY_DEBUG + _RemoveMemoryInfo( _data ); +#endif // FULL_ARRAY_DEBUG + } + (*this) = Array( ); + } + C* pointer( void ){ return data; } + const C* pointer( void ) const { return data; } + bool operator !( void ) const { return data==NULL; } + operator bool( ) const { return data!=NULL; } +}; + +template< class C > +class ConstArray +{ + void _assertBounds( long long idx ) const + { + if( idx=max ) + { + fprintf( stderr , "ConstArray index out-of-bounds: %lld <= %lld < %lld\n" , min , idx , max ); + ASSERT( 0 ); + exit( 0 ); + } + } +protected: + const C *data; + long long min , max; +public: + long long minimum( void ) const { return min; } + long long maximum( void ) const { return max; } + + inline ConstArray( void ) + { + data = NULL; + min = max = 0; + } + inline ConstArray( const Array< C >& a ) + { + // [WARNING] Changing szC and szD to size_t causes some really strange behavior. + data = ( const C* )a.pointer( ); + min = a.minimum(); + max = a.maximum(); + } + template< class D > + inline ConstArray( const Array< D >& a ) + { + // [WARNING] Changing szC and szD to size_t causes some really strange behavior. + long long szC = ( long long ) sizeof( C ); + long long szD = ( long long ) sizeof( D ); + data = ( const C* )a.pointer( ); + min = ( a.minimum() * szD ) / szC; + max = ( a.maximum() * szD ) / szC; + if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD ) + { +// fprintf( stderr , "Could not convert const array [ %lld , %lld ] * %lld => [ %lld , %lld ] * %lld\n" , a.minimum() , a.maximum() , szD , min , max , szC ); + fprintf( stderr , "Could not convert const array [ %lld , %lld ] * %lld => [ %lld , %lld ] * %lld\n %lld %lld %lld\n" , a.minimum() , a.maximum() , szD , min , max , szC , a.minimum() , a.minimum()*szD , (a.minimum()*szD)/szC ); + ASSERT( 0 ); + exit( 0 ); + } + } + template< class D > + inline ConstArray( const ConstArray< D >& a ) + { + // [WARNING] Chaning szC and szD to size_t causes some really strange behavior. + long long szC = sizeof( C ); + long long szD = sizeof( D ); + data = ( const C*)a.pointer( ); + min = ( a.minimum() * szD ) / szC; + max = ( a.maximum() * szD ) / szC; + if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD ) + { + fprintf( stderr , "Could not convert array [ %lld , %lld ] * %lld => [ %lld , %lld ] * %lld\n" , a.minimum() , a.maximum() , szD , min , max , szC ); + ASSERT( 0 ); + exit( 0 ); + } + } + static ConstArray FromPointer( const C* data , long long max ) + { + ConstArray a; + a.data = data; + a.min = 0; + a.max = max; + return a; + } + static ConstArray FromPointer( const C* data , long long min , long long max ) + { + ConstArray a; + a.data = data; + a.min = min; + a.max = max; + return a; + } + + inline bool operator == ( const ConstArray< C >& a ) const { return data==a.data; } + inline bool operator != ( const ConstArray< C >& a ) const { return data!=a.data; } + inline bool operator == ( const C* c ) const { return data==c; } + inline bool operator != ( const C* c ) const { return data!=c; } + inline const C* operator -> ( void ) + { + _assertBounds( 0 ); + return data; + } + inline const C& operator[]( long long idx ) const + { + _assertBounds( idx ); + return data[idx]; + } + inline ConstArray operator + ( int idx ) const + { + ConstArray a; + a.data = data+idx; + a.min = min-idx; + a.max = max-idx; + return a; + } + inline ConstArray operator + ( long long idx ) const + { + ConstArray a; + a.data = data+idx; + a.min = min-idx; + a.max = max-idx; + return a; + } + inline ConstArray operator + ( unsigned int idx ) const + { + ConstArray a; + a.data = data+idx; + a.min = min-idx; + a.max = max-idx; + return a; + } + inline ConstArray operator + ( unsigned long long idx ) const + { + ConstArray a; + a.data = data+idx; + a.min = min-idx; + a.max = max-idx; + return a; + } + inline ConstArray& operator += ( int idx ) + { + min -= idx; + max -= idx; + data += idx; + return (*this); + } + inline ConstArray& operator += ( long long idx ) + { + min -= idx; + max -= idx; + data += idx; + return (*this); + } + inline ConstArray& operator += ( unsigned int idx ) + { + min -= idx; + max -= idx; + data += idx; + return (*this); + } + inline ConstArray& operator += ( unsigned long long idx ) + { + min -= idx; + max -= idx; + data += idx; + return (*this); + } + inline ConstArray& operator ++ ( void ) { return (*this) += 1; } + inline ConstArray operator++( int ){ ConstArray< C > temp = (*this) ; (*this) +=1 ; return temp; } + ConstArray operator - ( int idx ) const { return (*this) + (-idx); } + ConstArray operator - ( long long idx ) const { return (*this) + (-idx); } + ConstArray operator - ( unsigned int idx ) const { return (*this) + (-idx); } + ConstArray operator - ( unsigned long long idx ) const { return (*this) + (-idx); } + ConstArray& operator -= ( int idx ) { return (*this) += (-idx); } + ConstArray& operator -= ( long long idx ) { return (*this) += (-idx); } + ConstArray& operator -= ( unsigned int idx ) { return (*this) += (-idx); } + ConstArray& operator -= ( unsigned long long idx ) { return (*this) += (-idx); } + ConstArray& operator -- ( void ) { return (*this) -= 1; } + inline ConstArray operator--( int ){ ConstArray< C > temp = (*this) ; (*this) -=1 ; return temp; } + long long operator - ( const ConstArray& a ) const { return ( long long )( data - a.data ); } + long long operator - ( const Array< C >& a ) const { return ( long long )( data - a.pointer() ); } + + const C* pointer( void ) const { return data; } + bool operator !( void ) { return data==NULL; } + operator bool( ) { return data!=NULL; } +}; + +#if FULL_ARRAY_DEBUG +inline void PrintMemoryInfo( void ){ for( size_t i=0 ; i +Array< C > memcpy( Array< C > destination , const void* source , size_t size ) +{ + if( size>destination.maximum()*sizeof(C) ) + { + fprintf( stderr , "Size of copy exceeds destination maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( destination.maximum()*sizeof( C ) ) ); + ASSERT( 0 ); + exit( 0 ); + } + if( size ) memcpy( &destination[0] , source , size ); + return destination; +} +template< class C , class D > +Array< C > memcpy( Array< C > destination , Array< D > source , size_t size ) +{ + if( size>destination.maximum()*sizeof( C ) ) + { + fprintf( stderr , "Size of copy exceeds destination maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( destination.maximum()*sizeof( C ) ) ); + ASSERT( 0 ); + exit( 0 ); + } + if( size>source.maximum()*sizeof( D ) ) + { + fprintf( stderr , "Size of copy exceeds source maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( source.maximum()*sizeof( D ) ) ); + ASSERT( 0 ); + exit( 0 ); + } + if( size ) memcpy( &destination[0] , &source[0] , size ); + return destination; +} +template< class C , class D > +Array< C > memcpy( Array< C > destination , ConstArray< D > source , size_t size ) +{ + if( size>destination.maximum()*sizeof( C ) ) + { + fprintf( stderr , "Size of copy exceeds destination maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( destination.maximum()*sizeof( C ) ) ); + ASSERT( 0 ); + exit( 0 ); + } + if( size>source.maximum()*sizeof( D ) ) + { + fprintf( stderr , "Size of copy exceeds source maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( source.maximum()*sizeof( D ) ) ); + ASSERT( 0 ); + exit( 0 ); + } + if( size ) memcpy( &destination[0] , &source[0] , size ); + return destination; +} +template< class D > +void* memcpy( void* destination , Array< D > source , size_t size ) +{ + if( size>source.maximum()*sizeof( D ) ) + { + fprintf( stderr , "Size of copy exceeds source maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( source.maximum()*sizeof( D ) ) ); + ASSERT( 0 ); + exit( 0 ); + } + if( size ) memcpy( destination , &source[0] , size ); + return destination; +} +template< class D > +void* memcpy( void* destination , ConstArray< D > source , size_t size ) +{ + if( size>source.maximum()*sizeof( D ) ) + { + fprintf( stderr , "Size of copy exceeds source maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( source.maximum()*sizeof( D ) ) ); + ASSERT( 0 ); + exit( 0 ); + } + if( size ) memcpy( destination , &source[0] , size ); + return destination; +} +template< class C > +Array< C > memset( Array< C > destination , int value , size_t size ) +{ + if( size>destination.maximum()*sizeof( C ) ) + { + fprintf( stderr , "Size of set exceeds destination maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( destination.maximum()*sizeof( C ) ) ); + ASSERT( 0 ); + exit( 0 ); + } + if( size ) memset( &destination[0] , value , size ); + return destination; +} + +template< class C > +size_t fread( Array< C > destination , size_t eSize , size_t count , FILE* fp ) +{ + if( count*eSize>destination.maximum()*sizeof( C ) ) + { + fprintf( stderr , "Size of read exceeds source maximum: %lld > %lld\n" , ( long long )( count*eSize ) , ( long long )( destination.maximum()*sizeof( C ) ) ); + ASSERT( 0 ); + exit( 0 ); + } + return fread( &destination[0] , eSize , count , fp ); +} +template< class C > +size_t fwrite( Array< C > source , size_t eSize , size_t count , FILE* fp ) +{ + if( count*eSize>source.maximum()*sizeof( C ) ) + { + fprintf( stderr , "Size of write exceeds source maximum: %lld > %lld\n" , ( long long )( count*eSize ) , ( long long )( source.maximum()*sizeof( C ) ) ); + ASSERT( 0 ); + exit( 0 ); + } + return fwrite( &source[0] , eSize , count , fp ); +} +template< class C > +size_t fwrite( ConstArray< C > source , size_t eSize , size_t count , FILE* fp ) +{ + if( count*eSize>source.maximum()*sizeof( C ) ) + { + fprintf( stderr , "Size of write exceeds source maximum: %lld > %lld\n" , ( long long )( count*eSize ) , ( long long )( source.maximum()*sizeof( C ) ) ); + ASSERT( 0 ); + exit( 0 ); + } + return fwrite( &source[0] , eSize , count , fp ); +} +template< class C > +void qsort( Array< C > base , size_t numElements , size_t elementSize , int (*compareFunction)( const void* , const void* ) ) +{ + if( sizeof(C)!=elementSize ) + { + fprintf( stderr , "Element sizes differ: %lld != %lld\n" , ( long long )( sizeof(C) ) , ( long long )( elementSize ) ); + ASSERT( 0 ); + exit( 0 ); + } + if( base.minimum()>0 || base.maximum() inline bool HasPartitionOfUnity( void ){ return BType!=BOUNDARY_DIRICHLET; } + +// This class represents a function that is a linear combination of B-spline elements. +// The coeff member indicating how much of each element is present. +// [WARNING] The ordering of B-spline elements is in the opposite order from that returned by Polynomial::BSplineComponent +template< int Degree > +struct BSplineElementCoefficients +{ + int coeffs[Degree+1]; + BSplineElementCoefficients( void ){ memset( coeffs , 0 , sizeof( coeffs ) ); } + int& operator[]( int idx ){ return coeffs[idx]; } + const int& operator[]( int idx ) const { return coeffs[idx]; } +}; + +// This class represents a function on the the interval, partitioned into "res" blocks. +// On each block, the function is a degree-Degree polynomial, represented by the coefficients +// in the associated BSplineElementCoefficients. +// [NOTE] This representation of a function is agnostic to the type of boundary conditions (though the constructor is not). +template< int Degree > +struct BSplineElements : public std::vector< BSplineElementCoefficients< Degree > > +{ + static const bool _Primal = (Degree&1)==1; + static const int _Off = (Degree+1)/2; + static int _ReflectLeft ( int offset , int res ); + static int _ReflectRight( int offset , int res ); + static int _RotateLeft ( int offset , int res ); + static int _RotateRight ( int offset , int res ); + template< bool Left > void _addPeriodic( int offset , bool negate ); +public: + // Coefficients are ordered as "/" "-" "\" + // [WARNING] This is the opposite of the order in Polynomial::BSplineComponent + int denominator; + + BSplineElements( void ) { denominator = 1; } + BSplineElements( int res , int offset , BoundaryType bType ); + + void upSample( BSplineElements& high ) const; + template< unsigned int D > + void differentiate( BSplineElements< Degree-D >& d ) const; + + void print( FILE* fp=stdout ) const + { + for( int i=0 ; i >::size() ; i++ ) + { + printf( "%d]" , i ); + for( int j=0 ; j<=Degree ; j++ ) printf( " %d" , (*this)[i][j] ); + printf( " (%d)\n" , denominator ); + } + } + Polynomial< Degree > polynomial( int idx ) const + { + int res = (int)std::vector< BSplineElementCoefficients< Degree > >::size(); + Polynomial< Degree > P; + if( idx>=0 && idx::BSplineComponent( Degree-d ).scale( 1./res ).shift( (idx+0.)/res ) * ( (*this)[idx][d] ); + return P / denominator; + } + PPolynomial< Degree > pPolynomial( void ) const + { + int res = (int)std::vector< BSplineElementCoefficients< Degree > >::size(); + PPolynomial< Degree > P; + P.polyCount = res + 1; + P.polys = AllocPointer< StartingPolynomial< Degree > >( P.polyCount ); + for( int i=0 ; i=1 ; i-- ) P.polys[i].p -= P.polys[i-1].p; + return P.compress(0); + } +}; +template< int Degree , int DDegree > struct Differentiator { static void Differentiate( const BSplineElements< Degree >& bse , BSplineElements< DDegree >& dbse ); }; +template< int Degree > struct Differentiator< Degree , Degree >{ static void Differentiate( const BSplineElements< Degree >& bse , BSplineElements< Degree >& dbse ); }; +#define BSPLINE_SET_BOUNDS( name , s , e ) \ + static const int name ## Start = (s); \ + static const int name ## End = (e); \ + static const int name ## Size = (e)-(s)+1 + +// Assumes that x is non-negative +#define _FLOOR_OF_HALF( x ) ( (x) >>1 ) +#define _CEIL_OF_HALF( x ) ( ( (x)+1 )>>1 ) +// Done with the assumption +#define FLOOR_OF_HALF( x ) ( (x)<0 ? - _CEIL_OF_HALF( -(x) ) : _FLOOR_OF_HALF( x ) ) +#define CEIL_OF_HALF( x ) ( (x)<0 ? - _FLOOR_OF_HALF( -(x) ) : _CEIL_OF_HALF( x ) ) +#define SMALLEST_INTEGER_LARGER_THAN_HALF( x ) ( CEIL_OF_HALF( (x)+1 ) ) +#define LARGEST_INTEGER_SMALLER_THAN_HALF( x ) ( FLOOR_OF_HALF( (x)-1 ) ) +#define SMALLEST_INTEGER_LARGER_THAN_OR_EQUAL_TO_HALF( x ) ( CEIL_OF_HALF( x ) ) +#define LARGEST_INTEGER_SMALLER_THAN_OR_EQUAL_TO_HALF( x ) ( FLOOR_OF_HALF( x ) ) + +template< int Degree > +struct BSplineSupportSizes +{ + inline static int Nodes( int depth ){ return ( 1<=0 || offset [-(Degree+1-Inset) , (Degree+1+Inset) ] CONTAINS [ J-(Degree+1-Inset)/2 , J+(Degree+1+Inset)/2 ] + // Which is the same as the smallest/largest integers J such that: + // J - (Degree+1-Inset)/2 >= -(Degree+1-Inset) | J + (Degree+1+Inset)/2 <= (Degree+1+Inset) + // <=> J >= -(Degree+1-Inset)/2 | J <= (Degree+1+Inset)/2 + BSPLINE_SET_BOUNDS( UpSample , - ( Degree + 1 - Inset ) / 2 , ( Degree + 1 + Inset ) /2 ); + + // Setting I=0/1, we are looking for the smallest/largest integers J such that: + // Support( J ) CONTAINS Support( 0/1 ) + // <=> [ 2*J - (Degree+1-Inset) , 2*J + (Degree+1+Inset) ] CONTAINS [ 0/1 - (Degree+1-Inset)/2 , 0/1 + (Degree+1+Inset)/2 ] + // Which is the same as the smallest/largest integers J such that: + // 2*J + (Degree+1+Inset) >= 0/1 + (Degree+1+Inset)/2 | 2*J - (Degree+1-Inset) <= 0/1 - (Degree+1-Inset)/2 + // <=> 2*J >= 0/1 - (Degree+1+Inset)/2 | 2*J <= 0/1 + (Degree+1-Inset)/2 + BSPLINE_SET_BOUNDS( DownSample0 , SMALLEST_INTEGER_LARGER_THAN_OR_EQUAL_TO_HALF( 0 - ( Degree + 1 + Inset ) / 2 ) , LARGEST_INTEGER_SMALLER_THAN_OR_EQUAL_TO_HALF( 0 + ( Degree + 1 - Inset ) / 2 ) ); + BSPLINE_SET_BOUNDS( DownSample1 , SMALLEST_INTEGER_LARGER_THAN_OR_EQUAL_TO_HALF( 1 - ( Degree + 1 + Inset ) / 2 ) , LARGEST_INTEGER_SMALLER_THAN_OR_EQUAL_TO_HALF( 1 + ( Degree + 1 - Inset ) / 2 ) ); + static const int DownSampleStart[] , DownSampleEnd[] , DownSampleSize[]; +}; +template< int Degree > const int BSplineSupportSizes< Degree >::DownSampleStart[] = { DownSample0Start , DownSample1Start }; +template< int Degree > const int BSplineSupportSizes< Degree >::DownSampleEnd [] = { DownSample0End , DownSample1End }; +template< int Degree > const int BSplineSupportSizes< Degree >::DownSampleSize [] = { DownSample0Size , DownSample1Size }; + + +// Given a B-Spline of degree Degree1 at position i, this gives the offsets of the B-splines of degree Degree2 that just overlap with it. +template< int Degree1 , int Degree2 > +struct BSplineOverlapSizes +{ + typedef BSplineSupportSizes< Degree1 > EData1; + typedef BSplineSupportSizes< Degree2 > EData2; + BSPLINE_SET_BOUNDS( Overlap , EData1:: SupportStart - EData2::SupportEnd , EData1:: SupportEnd - EData2::SupportStart ); + BSPLINE_SET_BOUNDS( ChildOverlap , EData1::ChildSupportStart - EData2::SupportEnd , EData1::ChildSupportEnd - EData2::SupportStart ); + BSPLINE_SET_BOUNDS( OverlapSupport , OverlapStart + EData2::SupportStart , OverlapEnd + EData2::SupportEnd ); + BSPLINE_SET_BOUNDS( ChildOverlapSupport , ChildOverlapStart + EData2::SupportStart , ChildOverlapEnd + EData2::SupportEnd ); + + // Setting I=0/1, we are looking for the smallest/largest integers J such that: + // Support( 2*J ) * 2 INTERSECTION Support( 0/1 ) NON-EMPTY + // <=> [ 2*J - (Degree2+1-Inset2) , 2*J + (Degree2+1+Inset2) ] INTERSECTION [ 0/1 - (Degree1+1-Inset1)/2 , 0/1 + (Degree1+1+Inset1)/2 ] NON-EMPTY + // Which is the same as the smallest/largest integers J such that: + // 0/1 - (Degree1+1-Inset1)/2 < 2*J + (Degree2+1+Inset2) | 0/1 + (Degree1+1+Inset1)/2 > 2*J - (Degree2+1-Inset2) + // <=> 2*J > 0/1 - ( 2*Degree2 + Degree1 + 3 + 2*Inset2 - Inset1 ) / 2 | 2*J < 0/1 + ( 2*Degree2 + Degree1 + 3 - 2*Inset2 + Inset1 ) / 2 + BSPLINE_SET_BOUNDS( ParentOverlap0 , SMALLEST_INTEGER_LARGER_THAN_HALF( 0 - ( 2*Degree2 + Degree1 + 3 + 2*EData2::Inset - EData1::Inset ) / 2 ) , LARGEST_INTEGER_SMALLER_THAN_HALF( 0 + ( 2*Degree2 + Degree1 + 3 - 2*EData2::Inset + EData1::Inset ) / 2 ) ); + BSPLINE_SET_BOUNDS( ParentOverlap1 , SMALLEST_INTEGER_LARGER_THAN_HALF( 1 - ( 2*Degree2 + Degree1 + 3 + 2*EData2::Inset - EData1::Inset ) / 2 ) , LARGEST_INTEGER_SMALLER_THAN_HALF( 1 + ( 2*Degree2 + Degree1 + 3 - 2*EData2::Inset + EData1::Inset ) / 2 ) ); + static const int ParentOverlapStart[] , ParentOverlapEnd[] , ParentOverlapSize[]; +}; +template< int Degree1 , int Degree2 > const int BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapStart[] = { ParentOverlap0Start , ParentOverlap1Start }; +template< int Degree1 , int Degree2 > const int BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapEnd [] = { ParentOverlap0End , ParentOverlap1End }; +template< int Degree1 , int Degree2 > const int BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapSize [] = { ParentOverlap0Size , ParentOverlap1Size }; + +template< int Degree , BoundaryType BType > +class BSplineEvaluationData +{ +public: + static const int Pad = (BType==BOUNDARY_FREE ) ? BSplineSupportSizes< Degree >::SupportEnd : ( (Degree&1) && BType==BOUNDARY_DIRICHLET ) ? -1 : 0; + inline static int Begin( int depth ){ return -Pad; } + inline static int End ( int depth ){ return (1<=End(depth); } + + static const int OffsetStart = -BSplineSupportSizes< Degree >::SupportStart , OffsetStop = BSplineSupportSizes< Degree >::SupportEnd + ( Degree&1 ) , IndexSize = OffsetStart + OffsetStop + 1 + 2 * Pad; + static int OffsetToIndex( int depth , int offset ) + { + int dim = BSplineSupportSizes< Degree >::Nodes( depth ); + if ( offset=dim-OffsetStop ) return Pad + OffsetStart + 1 + offset - ( dim-OffsetStop ); + else return Pad + OffsetStart; + } + static inline int IndexToOffset( int depth , int idx ){ return ( idx-Pad<=OffsetStart ? idx - Pad : ( BSplineSupportSizes< Degree >::Nodes(depth) + Pad - IndexSize + idx ) ); } + + BSplineEvaluationData( void ); + + // [NOTE] The offset represents the node position, not the index of the function + static double Value( int depth , int off , double s , bool derivative ); + + // Note that this struct stores the components in left-to-right order + struct BSplineComponents + { + protected: + Polynomial< Degree > _polys[Degree+1]; + public: + BSplineComponents( void ){ ; } + BSplineComponents( int depth , int offset ); + const Polynomial< Degree >& operator[] ( int idx ) const { return _polys[idx]; } + BSplineComponents derivative( void ) const; + void printnl( void ) const { for( int d=0 ; d<=Degree ; d++ ) printf( "[%d] " , d ) , _polys[d].printnl(); } + }; + struct BSplineUpSamplingCoefficients + { + protected: + int _coefficients[ BSplineSupportSizes< Degree >::UpSampleSize ]; + public: + BSplineUpSamplingCoefficients( void ){ ; } + BSplineUpSamplingCoefficients( int depth , int offset ); + double operator[] ( int idx ){ return (double)_coefficients[idx] / (1<::SupportSize]; + public: +#ifdef BRUNO_LEVY_FIX + Evaluator( void ){ _depth = 0 ; memset( _ccValues , 0 , sizeof(_ccValues) ); } +#endif // BRUNO_LEVY_FIX + double value( int fIdx , int cIdx , bool d ) const; + int depth( void ) const { return _depth; } + }; + struct ChildEvaluator + { + protected: + friend BSplineEvaluationData; + int _parentDepth; + double _pcValues[2][IndexSize][BSplineSupportSizes< Degree >::ChildSupportSize]; + public: +#ifdef BRUNO_LEVY_FIX + ChildEvaluator( void ){ _parentDepth = 0 ; memset( _pcValues , 0 , sizeof(_pcValues) ); } +#endif // BRUNO_LEVY_FIX + double value( int fIdx , int cIdx , bool d ) const; + int parentDepth( void ) const { return _parentDepth; } + int childDepth( void ) const { return _parentDepth+1; } + }; + }; + static void SetCenterEvaluator( typename CenterEvaluator::Evaluator& evaluator , int depth ); + static void SetChildCenterEvaluator( typename CenterEvaluator::ChildEvaluator& evaluator , int parentDepth ); + + struct CornerEvaluator + { + struct Evaluator + { + protected: + friend BSplineEvaluationData; + int _depth; + double _ccValues[2][IndexSize][BSplineSupportSizes< Degree >::CornerSize]; + public: +#ifdef BRUNO_LEVY_FIX + Evaluator( void ){ _depth = 0 ; memset( _ccValues , 0 , sizeof( _ccValues ) ); } +#endif // BRUNO_LEVY_FIX + double value( int fIdx , int cIdx , bool d ) const; + int depth( void ) const { return _depth; } + }; + struct ChildEvaluator + { + protected: + friend BSplineEvaluationData; + int _parentDepth; + double _pcValues[2][IndexSize][BSplineSupportSizes< Degree >::ChildCornerSize]; + public: +#ifdef BRUNO_LEVY_FIX + ChildEvaluator( void ){ _parentDepth = 0 ; memset( _pcValues , 0 , sizeof( _pcValues ) ); } +#endif // BRUNO_LEVY_FIX + double value( int fIdx , int cIdx , bool d ) const; + int parentDepth( void ) const { return _parentDepth; } + int childDepth( void ) const { return _parentDepth+1; } + }; + }; + static void SetCornerEvaluator( typename CornerEvaluator::Evaluator& evaluator , int depth ); + static void SetChildCornerEvaluator( typename CornerEvaluator::ChildEvaluator& evaluator , int parentDepth ); + + struct Evaluator + { + typename CenterEvaluator::Evaluator centerEvaluator; + typename CornerEvaluator::Evaluator cornerEvaluator; + double centerValue( int fIdx , int cIdx , bool d ) const { return centerEvaluator.value( fIdx , cIdx , d ); } + double cornerValue( int fIdx , int cIdx , bool d ) const { return cornerEvaluator.value( fIdx , cIdx , d ); } + }; + static void SetEvaluator( Evaluator& evaluator , int depth ){ SetCenterEvaluator( evaluator.centerEvaluator , depth ) , SetCornerEvaluator( evaluator.cornerEvaluator , depth ); } + + struct ChildEvaluator + { + typename CenterEvaluator::ChildEvaluator centerEvaluator; + typename CornerEvaluator::ChildEvaluator cornerEvaluator; + double centerValue( int fIdx , int cIdx , bool d ) const { return centerEvaluator.value( fIdx , cIdx , d ); } + double cornerValue( int fIdx , int cIdx , bool d ) const { return cornerEvaluator.value( fIdx , cIdx , d ); } + }; + static void SetChildEvaluator( ChildEvaluator& evaluator , int depth ){ SetChildCenterEvaluator( evaluator.centerEvaluator , depth ) , SetChildCornerEvaluator( evaluator.cornerEvaluator , depth ); } + + struct UpSampleEvaluator + { + protected: + friend BSplineEvaluationData; + int _lowDepth; + double _pcValues[IndexSize][BSplineSupportSizes< Degree >::UpSampleSize]; + public: +#ifdef BRUNO_LEVY_FIX + UpSampleEvaluator( void ){ _lowDepth = 0 ; memset( _pcValues , 0 , sizeof( _pcValues ) ); } +#endif // BRUNO_LEVY_FIX + double value( int pIdx , int cIdx ) const; + int lowDepth( void ) const { return _lowDepth; } + }; + static void SetUpSampleEvaluator( UpSampleEvaluator& evaluator , int lowDepth ); +}; + +template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +class BSplineIntegrationData +{ +public: + static const int OffsetStart = - BSplineOverlapSizes< Degree1 , Degree2 >::OverlapSupportStart , OffsetStop = BSplineOverlapSizes< Degree1 , Degree2 >::OverlapSupportEnd + ( Degree1&1 ) , IndexSize = OffsetStart + OffsetStop + 1 + 2 * BSplineEvaluationData< Degree1 , BType1 >::Pad; + static int OffsetToIndex( int depth , int offset ) + { + int dim = BSplineSupportSizes< Degree1 >::Nodes( depth ); + if ( offset::Pad + offset; + else if( offset>=dim-OffsetStop ) return BSplineEvaluationData< Degree1 , BType1 >::Pad + OffsetStart + 1 + offset - ( dim-OffsetStop ); + else return BSplineEvaluationData< Degree1 , BType1 >::Pad + OffsetStart; + } + static inline int IndexToOffset( int depth , int idx ){ return ( idx-BSplineEvaluationData< Degree1 , BType1 >::Pad<=OffsetStart ? idx-BSplineEvaluationData< Degree1 , BType1 >::Pad : ( BSplineSupportSizes< Degree1 >::Nodes(depth) + BSplineEvaluationData< Degree1 , BType1 >::Pad - IndexSize + idx ) ); } + + template< unsigned int D1 , unsigned int D2 > static double Dot( int depth1 , int off1 , int depth2 , int off2 ); + // An index is interiorly overlapped if the support of its overlapping neighbors is in the range [0,1<::OverlapStart-BSplineSupportSizes< Degree2 >::SupportStart , end = (1<::OverlapEnd-BSplineSupportSizes< Degree2 >::SupportEnd; } + + struct FunctionIntegrator + { + template< unsigned int D1 , unsigned int D2 > + struct Integrator + { + protected: + friend BSplineIntegrationData; + int _depth; + double _ccIntegrals[D1+1][D2+1][IndexSize][BSplineOverlapSizes< Degree1 , Degree2 >::OverlapSize]; + public: +#ifdef BRUNO_LEVY_FIX + Integrator( void ){ _depth = 0 ; memset(_ccIntegrals, 0, sizeof(_ccIntegrals)); } +#endif // BRUNO_LEVY_FIX + double dot( int fIdx1 , int fidx2 , int d1 , int d2 ) const; + int depth( void ) const { return _depth; } + }; + template< unsigned int D1 , unsigned int D2 > + struct ChildIntegrator + { + protected: + friend BSplineIntegrationData; + int _parentDepth; + double _pcIntegrals[D1+1][D2+1][IndexSize][BSplineOverlapSizes< Degree1 , Degree2 >::ChildOverlapSize]; + public: +#ifdef BRUNO_LEVY_FIX + ChildIntegrator( void ){ _parentDepth = 0 ; memset( _pcIntegrals , 0 , sizeof( _pcIntegrals ) ); } +#endif // BRUNO_LEVY_FIX + double dot( int fIdx1 , int fidx2 , int d1 , int d2 ) const; + int parentDepth( void ) const { return _parentDepth; } + int childDepth( void ) const { return _parentDepth+1; } + }; + }; + // D1 and D2 indicate the number of derivatives that should be taken + template< unsigned int D1 , unsigned int D2 > + static void SetIntegrator( typename FunctionIntegrator::template Integrator< D1 , D2 >& integrator , int depth ); + template< unsigned int D1 , unsigned int D2 > + static void SetChildIntegrator( typename FunctionIntegrator::template ChildIntegrator< D1 , D2 >& integrator , int parentDepth ); + +protected: + // _D1 and _D2 indicate the total number of derivatives the integrator will be storing + template< unsigned int D1 , unsigned int D2 , unsigned int _D1 , unsigned int _D2 > + struct _IntegratorSetter + { + static void Set( typename FunctionIntegrator::template Integrator< _D1 , _D2 >& integrator , int depth ); + static void Set( typename FunctionIntegrator::template ChildIntegrator< _D1 , _D2 >& integrator , int depth ); + }; + + template< unsigned int D1 , unsigned int D2 , unsigned int _D1 , unsigned int _D2 , class Integrator > + struct IntegratorSetter + { + static void Set2D( Integrator& integrator , int depth ); + static void Set1D( Integrator& integrator , int depth ); + }; + template< unsigned int D1 , unsigned int _D1 , unsigned int _D2 , class Integrator > + struct IntegratorSetter< D1 , 0 , _D1 , _D2 , Integrator > + { + static void Set2D( Integrator& integrator , int depth ); + static void Set1D( Integrator& integrator , int depth ); + }; + template< unsigned int D2 , unsigned int _D1 , unsigned int _D2 , class Integrator > + struct IntegratorSetter< 0 , D2 , _D1 , _D2 , Integrator > + { + static void Set2D( Integrator& integrator , int depth ); + static void Set1D( Integrator& integrator , int depth ); + }; + template< unsigned int _D1 , unsigned int _D2 , class Integrator > + struct IntegratorSetter< 0 , 0 , _D1 , _D2 , Integrator > + { + static void Set2D( Integrator& integrator , int depth ); + static void Set1D( Integrator& integrator , int depth ); + }; +}; +#undef BSPLINE_SET_BOUNDS +#undef _FLOOR_OF_HALF +#undef _CEIL_OF_HALF +#undef FLOOR_OF_HALF +#undef CEIL_OF_HALF +#undef SMALLEST_INTEGER_LARGER_THAN_HALF +#undef LARGEST_INTEGER_SMALLER_THAN_HALF +#undef SMALLEST_INTEGER_LARGER_THAN_OR_EQUAL_TO_HALF +#undef LARGEST_INTEGER_SMALLER_THAN_OR_EQUAL_TO_HALF + +template< int Degree , BoundaryType BType > +struct BSplineData +{ + inline static int TotalFunctionCount( int depth ){ return depth<0 ? 0 : (1<<(depth+1)) - 1 + (depth+1) * ( (Degree&1) + 2 * BSplineEvaluationData< Degree , BType >::Pad ); } + inline static int FunctionIndex( int depth , int offset ){ return TotalFunctionCount( depth-1 ) + offset + BSplineEvaluationData< Degree , BType >::Pad; } + inline static void FactorFunctionIndex( int idx , int& depth , int& offset ) + { + int dim; + depth = 0; + while( idx>=( dim = BSplineEvaluationData< Degree , BType >::End( depth ) - BSplineEvaluationData< Degree , BType >::Begin( depth ) ) ) idx -= dim , depth++; + offset = idx - BSplineEvaluationData< Degree , BType >::Pad; + } + inline static void FunctionSpan( int depth , int& fStart , int& fEnd ){ fStart = TotalFunctionCount( depth-1 ) , fEnd = TotalFunctionCount( depth ); } + inline static int RemapOffset( int depth , int idx , bool& reflect ); + + size_t functionCount; + Pointer( typename BSplineEvaluationData< Degree , BType >::BSplineComponents ) baseBSplines; + Pointer( typename BSplineEvaluationData< Degree , BType >::BSplineComponents ) dBaseBSplines; + + BSplineData( int maxDepth ); + ~BSplineData( void ); +}; + +template< int Degree1 , int Degree2 > void SetBSplineElementIntegrals( double integrals[Degree1+1][Degree2+1] ); + + +#include "BSplineData.inl" +#endif // BSPLINE_DATA_INCLUDED \ No newline at end of file diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/BSplineData.inl b/src/plugins_unsupported/filter_screened_poisson_xml/Src/BSplineData.inl new file mode 100644 index 000000000..225fed8f4 --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/BSplineData.inl @@ -0,0 +1,546 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +/////////////////////////// +// BSplineEvaluationData // +/////////////////////////// +template< int Degree , BoundaryType BType > +double BSplineEvaluationData< Degree , BType >::Value( int depth , int off , double s , bool derivative ) +{ + if( s<0 || s>1 ) return 0.; + + int res = 1<( 0 , std::min< int >( res-1 , (int)floor( s * res ) ) ) - off; + + if( ii::SupportStart || ii>BSplineSupportSizes< Degree >::SupportEnd ) return 0; + if( derivative ) return components[ ii-BSplineSupportSizes< Degree >::SupportStart ].derivative()(s); + else return components[ ii-BSplineSupportSizes< Degree >::SupportStart ](s); +} +template< int Degree , BoundaryType BType > +void BSplineEvaluationData< Degree , BType >::SetCenterEvaluator( typename CenterEvaluator::Evaluator& evaluator , int depth ) +{ + evaluator._depth = depth; + int res = 1<::SupportStart ; j<=BSplineSupportSizes< Degree >::SupportEnd ; j++ ) + { + int ii = IndexToOffset( depth , i ); + double s = 0.5 + ii + j; + for( int d1=0 ; d1<2 ; d1++ ) evaluator._ccValues[d1][i][j-BSplineSupportSizes< Degree >::SupportStart] = Value( depth , ii , s/res , d1!=0 ); + } +} +template< int Degree , BoundaryType BType > +void BSplineEvaluationData< Degree , BType >::SetChildCenterEvaluator( typename CenterEvaluator::ChildEvaluator& evaluator , int parentDepth ) +{ + evaluator._parentDepth = parentDepth; + int res = 1<<(parentDepth+1); + for( int i=0 ; i::ChildSupportStart ; j<=BSplineSupportSizes< Degree >::ChildSupportEnd ; j++ ) + { + int ii = IndexToOffset( parentDepth , i ); + double s = 0.5 + 2*ii + j; + for( int d1=0 ; d1<2 ; d1++ ) evaluator._pcValues[d1][i][j-BSplineSupportSizes< Degree >::ChildSupportStart] = Value( parentDepth , ii , s/res , d1!=0 ); + } +} +template< int Degree , BoundaryType BType > +double BSplineEvaluationData< Degree , BType >::CenterEvaluator::Evaluator::value( int fIdx , int cIdx , bool d ) const +{ + int dd = cIdx-fIdx , res = 1<<(_depth); + if( cIdx<0 || cIdx>=res || OutOfBounds( _depth , fIdx ) || dd::SupportStart || dd>BSplineSupportSizes< Degree >::SupportEnd ) return 0; + return _ccValues[d?1:0][ OffsetToIndex( _depth , fIdx ) ][dd-BSplineSupportSizes< Degree >::SupportStart]; +} +template< int Degree , BoundaryType BType > +double BSplineEvaluationData< Degree , BType >::CenterEvaluator::ChildEvaluator::value( int fIdx , int cIdx , bool d ) const +{ + int dd = cIdx-2*fIdx , res = 1<<(_parentDepth+1); + if( cIdx<0 || cIdx>=res || OutOfBounds( _parentDepth , fIdx ) || dd::ChildSupportStart || dd>BSplineSupportSizes< Degree >::ChildSupportEnd ) return 0; + return _pcValues[d?1:0][ OffsetToIndex( _parentDepth , fIdx ) ][dd-BSplineSupportSizes< Degree >::ChildSupportStart]; +} +template< int Degree , BoundaryType BType > +void BSplineEvaluationData< Degree , BType >::SetCornerEvaluator( typename CornerEvaluator::Evaluator& evaluator , int depth ) +{ + evaluator._depth = depth; + int res = 1<::CornerStart ; j<=BSplineSupportSizes< Degree >::CornerEnd ; j++ ) + { + int ii = IndexToOffset( depth , i ); + double s = ii + j; + for( int d1=0 ; d1<2 ; d1++ ) evaluator._ccValues[d1][i][j-BSplineSupportSizes< Degree >::CornerStart] = Value( depth , ii , s/res , d1!=0 ); + } +} +template< int Degree , BoundaryType BType > +void BSplineEvaluationData< Degree , BType >::SetChildCornerEvaluator( typename CornerEvaluator::ChildEvaluator& evaluator , int parentDepth ) +{ + evaluator._parentDepth = parentDepth; + int res = 1<<(parentDepth+1); + for( int i=0 ; i::ChildCornerStart ; j<=BSplineSupportSizes< Degree >::ChildCornerEnd ; j++ ) + { + int ii = IndexToOffset( parentDepth , i ); + double s = 2*ii + j; + for( int d1=0 ; d1<2 ; d1++ ) evaluator._pcValues[d1][i][j-BSplineSupportSizes< Degree >::ChildCornerStart] = Value( parentDepth , ii , s/res , d1!=0 ); + } +} +template< int Degree , BoundaryType BType > +void BSplineEvaluationData< Degree , BType >::SetUpSampleEvaluator( UpSampleEvaluator& evaluator , int lowDepth ) +{ + evaluator._lowDepth = lowDepth; + for( int i=0 ; i::UpSampleSize ; j++ ) evaluator._pcValues[i][j] = b[j]; + } +} +template< int Degree , BoundaryType BType > +double BSplineEvaluationData< Degree , BType >::CornerEvaluator::Evaluator::value( int fIdx , int cIdx , bool d ) const +{ + int dd = cIdx-fIdx , res = ( 1<<_depth ) + 1; + if( cIdx<0 || cIdx>=res || OutOfBounds( _depth , fIdx ) || dd::CornerStart || dd>BSplineSupportSizes< Degree >::CornerEnd ) return 0; + return _ccValues[d?1:0][ OffsetToIndex( _depth , fIdx ) ][dd-BSplineSupportSizes< Degree >::CornerStart]; +} +template< int Degree , BoundaryType BType > +double BSplineEvaluationData< Degree , BType >::CornerEvaluator::ChildEvaluator::value( int fIdx , int cIdx , bool d ) const +{ + int dd = cIdx-2*fIdx , res = ( 1<<(_parentDepth+1) ) + 1; + if( cIdx<0 || cIdx>=res || OutOfBounds( _parentDepth , fIdx ) || dd::ChildCornerStart || dd>BSplineSupportSizes< Degree >::ChildCornerEnd ) return 0; + return _pcValues[d?1:0][ OffsetToIndex( _parentDepth , fIdx ) ][dd-BSplineSupportSizes< Degree >::ChildCornerStart]; +} +template< int Degree , BoundaryType BType > +double BSplineEvaluationData< Degree , BType >::UpSampleEvaluator::value( int pIdx , int cIdx ) const +{ + int dd = cIdx-2*pIdx; + if( OutOfBounds( _lowDepth+1 , cIdx ) || OutOfBounds( _lowDepth , pIdx ) || dd::UpSampleStart || dd>BSplineSupportSizes< Degree >::UpSampleEnd ) return 0; + return _pcValues[ OffsetToIndex( _lowDepth , pIdx ) ][dd-BSplineSupportSizes< Degree >::UpSampleStart]; +} + +////////////////////////////////////////////// +// BSplineEvaluationData::BSplineComponents // +////////////////////////////////////////////// +template< int Degree , BoundaryType BType > +BSplineEvaluationData< Degree , BType >::BSplineComponents::BSplineComponents( int depth , int offset ) +{ + int res = 1< elements( res , offset , BType ); + + // The first index is the position, the second is the element type + Polynomial< Degree > components[Degree+1][Degree+1]; + // Generate the elements that can appear in the base function corresponding to the base function at (depth,offset) = (0,0) + for( int d=0 ; d<=Degree ; d++ ) for( int dd=0 ; dd<=Degree ; dd++ ) components[d][dd] = Polynomial< Degree >::BSplineComponent( Degree-dd ).shift( -( (Degree+1)/2 ) + d ); + + // Now adjust to the desired depth and offset + double width = 1. / res; + for( int d=0 ; d<=Degree ; d++ ) for( int dd=0 ; dd<=Degree ; dd++ ) components[d][dd] = components[d][dd].scale( width ).shift( width*offset ); + + // Now write in the polynomials + for( int d=0 ; d<=Degree ; d++ ) + { + int idx = offset + BSplineSupportSizes< Degree >::SupportStart + d; + _polys[d] = Polynomial< Degree >(); + + if( idx>=0 && idx +typename BSplineEvaluationData< Degree , BType >::BSplineComponents BSplineEvaluationData< Degree , BType >::BSplineComponents::derivative( void ) const +{ + BSplineComponents b = (*this); + for( int d=0 ; d<=Degree ; d++ ) b._polys[d] = b._polys[d].derivative(); + return b; +} + +////////////////////////////////////////////////////////// +// BSplineEvaluationData::BSplineUpSamplingCoefficients // +////////////////////////////////////////////////////////// +template< int Degree , BoundaryType BType > +BSplineEvaluationData< Degree , BType >::BSplineUpSamplingCoefficients::BSplineUpSamplingCoefficients( int depth , int offset ) +{ + // [ 1/8 1/2 3/4 1/2 1/8] + // [ 1 , 1 ] -> [ 3/4 , 1/2 , 1/8 ] + [ 1/8 , 1/2 , 3/4 ] = [ 7/8 , 1 , 7/8 ] + int dim = BSplineSupportSizes< Degree >::Nodes(depth) , _dim = BSplineSupportSizes< Degree >::Nodes(depth+1); + bool reflect; + offset = BSplineData< Degree , BType >::RemapOffset( depth , offset , reflect ); + int multiplier = ( BType==BOUNDARY_DIRICHLET && reflect ) ? -1 : 1; + bool useReflected = ( BType!=BOUNDARY_FREE ) && ( BSplineSupportSizes< Degree >::Inset || ( offset % ( dim-1 ) ) ); + int b[ BSplineSupportSizes< Degree >::UpSampleSize ]; + Polynomial< Degree+1 >::BinomialCoefficients( b ); + + // Clear the values + memset( _coefficients , 0 , sizeof(int) * BSplineSupportSizes< Degree >::UpSampleSize ); + + // Get the array of coefficients, relative to the origin + int* coefficients = _coefficients - ( 2*offset + BSplineSupportSizes< Degree >::UpSampleStart ); + for( int i=BSplineSupportSizes< Degree >::UpSampleStart ; i<=BSplineSupportSizes< Degree >::UpSampleEnd ; i++ ) + { + int _offset = 2*offset+i; + _offset = BSplineData< Degree , BType >::RemapOffset( depth+1 , _offset , reflect ); + if( useReflected || !reflect ) + { + int _multiplier = multiplier * ( ( BType==BOUNDARY_DIRICHLET && reflect ) ? -1 : 1 ); + coefficients[ _offset ] += b[ i-BSplineSupportSizes< Degree >::UpSampleStart ] * _multiplier; + } + // If we are not inset and we are at the boundary, use the reflection as well + if( BType!=BOUNDARY_FREE && !BSplineSupportSizes< Degree >::Inset && ( offset % (dim-1) ) && !( _offset % (_dim-1) ) ) + { + _offset = BSplineData< Degree , BType >::RemapOffset( depth+1 , _offset , reflect ); + int _multiplier = multiplier * ( ( BType==BOUNDARY_DIRICHLET && reflect ) ? -1 : 1 ); + if( BType==BOUNDARY_DIRICHLET ) _multiplier *= -1; + coefficients[ _offset ] += b[ i-BSplineSupportSizes< Degree >::UpSampleStart ] * _multiplier; + } + } +} + +//////////////////////////// +// BSplineIntegrationData // +//////////////////////////// +template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int D1 , unsigned int D2 > +double BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::Dot( int depth1 , int off1 , int depth2 , int off2 ) +{ + if( D1>Degree1 ) fprintf( stderr , "[ERROR] BSplineIntegrationData::Dot: taking more derivatives than the degree: %d > %d\n" , D1 , Degree1 ) , exit( 0 ); + if( D2>Degree2 ) fprintf( stderr , "[ERROR] BSplineIntegrationData::Dot: taking more derivatives than the degree: %d > %d\n" , D2 , Degree2 ) , exit( 0 ); + const int _Degree1 = ( Degree1>=D1 ) ? Degree1 - D1 : 0 , _Degree2 = ( Degree2>=D2 ) ? Degree2 - D2 : 0; + int sums[ Degree1+1 ][ Degree2+1 ]; + + int depth = std::max< int >( depth1 , depth2 ); + + BSplineElements< Degree1 > b1( 1< b2( 1< b; + while( depth1 b; + while( depth2 db1; + BSplineElements< Degree2-D2 > db2; + b1.template differentiate< D1 >( db1 ) , b2.template differentiate< D2 >( db2 ); + + int start1=-1 , end1=-1 , start2=-1 , end2=-1; + for( int i=0 ; i=end2 || start2>=end1 ) return 0.; + int start = std::max< int >( start1 , start2 ) , end = std::min< int >( end1 , end2 ); + memset( sums , 0 , sizeof( sums ) ); + + // Iterate over the support + for( int i=start ; i( integrals ); + for( int j=0 ; j<=_Degree1 ; j++ ) for( int k=0 ; k<=_Degree2 ; k++ ) _dot += integrals[j][k] * sums[j][k]; + } + + _dot /= b1.denominator; + _dot /= b2.denominator; + return ( !D1 && !D2 ) ? _dot / (1< +template< unsigned int D1 , unsigned int D2 , unsigned int _D1 , unsigned int _D2 , class Integrator > +void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::IntegratorSetter< D1 , D2 , _D1 , _D2 , Integrator >::Set2D( Integrator& integrator , int depth ) +{ + IntegratorSetter< D1-1 , D2 , _D1 , _D2 , Integrator >::Set2D( integrator , depth ); + IntegratorSetter< D1 , D2 , _D1 , _D2 , Integrator >::Set1D( integrator , depth ); +} +template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int D1 , unsigned int D2 , unsigned int _D1 , unsigned int _D2 , class Integrator > +void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::IntegratorSetter< D1 , D2 , _D1 , _D2 , Integrator >::Set1D( Integrator& integrator , int depth ) +{ + IntegratorSetter< D1 , D2-1 , _D1 , _D2 , Integrator >::Set1D( integrator , depth ); + _IntegratorSetter< D1 , D2 , _D1 , _D2 >::Set( integrator , depth ); +} +template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int D2 , unsigned int _D1 , unsigned int _D2 , class Integrator > +void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::IntegratorSetter< 0 , D2 , _D1 , _D2 , Integrator >::Set2D( Integrator& integrator , int depth ) +{ + IntegratorSetter< 0 , D2 , _D1 , _D2 , Integrator >::Set1D( integrator , depth ); +} +template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int D2 , unsigned int _D1 , unsigned int _D2 , class Integrator > +void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::IntegratorSetter< 0 , D2 , _D1 , _D2 , Integrator >::Set1D( Integrator& integrator , int depth ) +{ + IntegratorSetter< 0 , D2-1 , _D1 , _D2 , Integrator >::Set1D( integrator , depth ); + _IntegratorSetter< 0 , D2 , _D1 , _D2 >::Set( integrator , depth ); +} +template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int D1 , unsigned int _D1 , unsigned int _D2 , class Integrator > +void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::IntegratorSetter< D1 , 0 , _D1 , _D2 , Integrator >::Set2D( Integrator& integrator , int depth ) +{ + IntegratorSetter< D1-1 , 0 , _D1 , _D2 , Integrator >::Set2D( integrator , depth ); + IntegratorSetter< D1 , 0 , _D1 , _D2 , Integrator >::Set1D( integrator , depth ); +} +template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int D1 , unsigned int _D1 , unsigned int _D2 , class Integrator > +void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::IntegratorSetter< D1 , 0 , _D1 , _D2 , Integrator >::Set1D( Integrator& integrator , int depth ) +{ + _IntegratorSetter< D1 , 0 , _D1 , _D2 >::Set( integrator , depth ); +} +template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int _D1 , unsigned int _D2 , class Integrator > +void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::IntegratorSetter< 0 , 0 , _D1 , _D2 , Integrator >::Set2D( Integrator& integrator , int depth ) +{ + IntegratorSetter< 0 , 0 , _D1 , _D2 , Integrator >::Set1D( integrator , depth ); +} +template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int _D1 , unsigned int _D2 , class Integrator > +void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::IntegratorSetter< 0 , 0 , _D1 , _D2 , Integrator >::Set1D( Integrator& integrator , int depth ) +{ + _IntegratorSetter< 0 , 0 , _D1 , _D2 >::Set( integrator , depth ); +} + +template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int D1 , unsigned int D2 , unsigned int _D1 , unsigned int _D2 > +void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::_IntegratorSetter< D1 , D2 , _D1 , _D2 >::Set( typename FunctionIntegrator::template Integrator< _D1 , _D2 >& integrator , int depth ) +{ + for( int i=0 ; i::OverlapStart ; j<=BSplineOverlapSizes< Degree1 , Degree2 >::OverlapEnd ; j++ ) + { + int ii = IndexToOffset( depth , i ); + integrator._ccIntegrals[D1][D2][i][j-BSplineOverlapSizes< Degree1 , Degree2 >::OverlapStart] = Dot< D1 , D2 >( depth , ii , depth , ii+j ); + } +} +template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int D1 , unsigned int D2 , unsigned int _D1 , unsigned int _D2 > +void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::_IntegratorSetter< D1 , D2 , _D1 , _D2 >::Set( typename FunctionIntegrator::template ChildIntegrator< _D1 , _D2 >& integrator , int pDepth ) +{ + for( int i=0 ; i::ChildOverlapStart ; j<=BSplineOverlapSizes< Degree1 , Degree2 >::ChildOverlapEnd ; j++ ) + { + int ii = IndexToOffset( pDepth , i ); + integrator._pcIntegrals[D1][D2][i][j-BSplineOverlapSizes< Degree1 , Degree2 >::ChildOverlapStart] = Dot< D1 , D2 >( pDepth , ii , pDepth+1 , 2*ii+j ); + } +} + +template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int D1 , unsigned int D2 > +void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::SetIntegrator( typename FunctionIntegrator::template Integrator< D1 , D2 >& integrator , int depth ) +{ + integrator._depth = depth; + IntegratorSetter< D1 , D2 , D1 , D2 , typename FunctionIntegrator::template Integrator< D1 , D2 > >::Set2D( integrator , depth ); +} +template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int D1 , unsigned int D2 > +void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::SetChildIntegrator( typename FunctionIntegrator::template ChildIntegrator< D1 , D2 >& integrator , int parentDepth ) +{ + integrator._parentDepth = parentDepth; + IntegratorSetter< D1 , D2 , D1 , D2 , typename FunctionIntegrator::template ChildIntegrator< D1 , D2 > >::Set2D( integrator , parentDepth ); +} +template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int D1 , unsigned int D2 > +double BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::FunctionIntegrator::Integrator< D1 , D2 >::dot( int off1 , int off2 , int d1 , int d2 ) const +{ + int d = off2-off1; + if( BSplineEvaluationData< Degree1 , BType1 >::OutOfBounds( _depth , off1 ) || BSplineEvaluationData< Degree2 , BType2 >::OutOfBounds( _depth , off2 ) || d::OverlapStart || d>BSplineOverlapSizes< Degree1 , Degree2 >::OverlapEnd ) return 0; + return _ccIntegrals[d1][d2][ OffsetToIndex( _depth , off1 ) ][d-BSplineOverlapSizes< Degree1 , Degree2 >::OverlapStart]; +} +template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int D1 , unsigned int D2 > +double BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::FunctionIntegrator::ChildIntegrator< D1 , D2 >::dot( int off1 , int off2 , int d1 , int d2 ) const +{ + int d = off2-2*off1; + if( BSplineEvaluationData< Degree1 , BType1 >::OutOfBounds( _parentDepth , off1 ) || BSplineEvaluationData< Degree2 , BType2 >::OutOfBounds( _parentDepth+1 , off2 ) || d::ChildOverlapStart || d>BSplineOverlapSizes< Degree1 , Degree2 >::ChildOverlapEnd ) return 0; + return _pcIntegrals[d1][d2][ OffsetToIndex( _parentDepth , off1 ) ][d-BSplineOverlapSizes< Degree1 , Degree2 >::ChildOverlapStart]; +} + +///////////////// +// BSplineData // +///////////////// +#define MODULO( A , B ) ( (A)<0 ? ( (B)-((-(A))%(B)) ) % (B) : (A) % (B) ) +template< int Degree , BoundaryType BType > +int BSplineData< Degree , BType >::RemapOffset( int depth , int offset , bool& reflect ) +{ + const int I = ( Degree&1 ) ? 0 : 1; + if( BType==BOUNDARY_FREE ){ reflect = false ; return offset; } + int dim = BSplineEvaluationData< Degree , BOUNDARY_NEUMANN >::End( depth ) - BSplineEvaluationData< Degree , BOUNDARY_NEUMANN >::Begin( depth ); + offset = MODULO( offset , 2*(dim-1+I) ); + reflect = offset>=dim; + if( reflect ) return 2*(dim-1+I) - (offset+I); + else return offset; +} +#undef MODULO + +template< int Degree , BoundaryType BType > +BSplineData< Degree , BType >::BSplineData( int maxDepth ) +{ + functionCount = TotalFunctionCount( maxDepth ); + baseBSplines = NewPointer< typename BSplineEvaluationData< Degree , BType >::BSplineComponents >( functionCount ); + dBaseBSplines = NewPointer< typename BSplineEvaluationData< Degree , BType >::BSplineComponents >( functionCount ); + + for( size_t i=0 ; i::BSplineComponents( d , off ); + dBaseBSplines[i] = baseBSplines[i].derivative(); + } +} +template< int Degree , BoundaryType BType > +BSplineData< Degree , BType >::~BSplineData( void ) +{ + FreePointer( baseBSplines ); + FreePointer( dBaseBSplines ); +} + +///////////////////// +// BSplineElements // +///////////////////// +template< int Degree > +BSplineElements< Degree >::BSplineElements( int res , int offset , BoundaryType bType ) +{ + denominator = 1; + std::vector< BSplineElementCoefficients< Degree > >::resize( res , BSplineElementCoefficients< Degree >() ); + + // If we have primal dirichlet constraints, the boundary functions are necessarily zero + if( _Primal && bType==BOUNDARY_DIRICHLET && !(offset%res) ) return; + + // Construct the B-Spline + for( int i=0 ; i<=Degree ; i++ ) + { + int idx = -_Off + offset + i; + if( idx>=0 && idx( _RotateLeft ( offset , res ) , false ) , _addPeriodic< false >( _RotateRight( offset , res ) , false ); + + // Recursively fold in the boundaries + if( _Primal && !(offset%res) ) return; + + // Fold in the reflected instance (which may require negation) + _addPeriodic< true >( _ReflectLeft( offset , res ) , bType==BOUNDARY_DIRICHLET ) , _addPeriodic< false >( _ReflectRight( offset , res ) , bType==BOUNDARY_DIRICHLET ); + } +} +template< int Degree > int BSplineElements< Degree >::_ReflectLeft ( int offset , int res ){ return (Degree&1) ? -offset : -1-offset; } +template< int Degree > int BSplineElements< Degree >::_ReflectRight( int offset , int res ){ return (Degree&1) ? 2*res-offset : 2*res-1-offset; } +template< int Degree > int BSplineElements< Degree >::_RotateLeft ( int offset , int res ){ return offset-2*res; } +template< int Degree > int BSplineElements< Degree >::_RotateRight ( int offset , int res ){ return offset+2*res; } + +template< int Degree > +template< bool Left > +void BSplineElements< Degree >::_addPeriodic( int offset , bool negate ) +{ + int res = int( std::vector< BSplineElementCoefficients< Degree > >::size() ); + bool set = false; + // Add in the corresponding B-spline elements (possibly negated) + for( int i=0 ; i<=Degree ; i++ ) + { + int idx = -_Off + offset + i; + if( idx>=0 && idx( Left ? _RotateLeft( offset , res ) : _RotateRight( offset , res ) , negate ); +} +template< int Degree > +void BSplineElements< Degree >::upSample( BSplineElements< Degree >& high ) const +{ + int bCoefficients[ BSplineSupportSizes< Degree >::UpSampleSize ]; + Polynomial< Degree+1 >::BinomialCoefficients( bCoefficients ); + + high.resize( std::vector< BSplineElementCoefficients< Degree > >::size()*2 ); + high.assign( high.size() , BSplineElementCoefficients< Degree >() ); + // [NOTE] We have flipped the order of the B-spline elements + for( int i=0 ; i >::size()) ; i++ ) for( int j=0 ; j<=Degree ; j++ ) + { + // At index I , B-spline element J corresponds to a B-spline centered at: + // I - SupportStart - J + int idx = i - BSplineSupportSizes< Degree >::SupportStart - j; + for( int k=BSplineSupportSizes< Degree >::UpSampleStart ; k<=BSplineSupportSizes< Degree >::UpSampleEnd ; k++ ) + { + // Index idx at the coarser resolution gets up-sampled into indices: + // 2*idx + [UpSampleStart,UpSampleEnd] + // at the finer resolution + int _idx = 2*idx + k; + // Compute the index of the B-spline element relative to 2*i and 2*i+1 + int _j1 = -_idx + 2*i - BSplineSupportSizes< Degree >::SupportStart , _j2 = -_idx + 2*i + 1 - BSplineSupportSizes< Degree >::SupportStart; + if( _j1>=0 && _j1<=Degree ) high[2*i+0][_j1] += (*this)[i][j] * bCoefficients[k-BSplineSupportSizes< Degree >::UpSampleStart]; + if( _j2>=0 && _j2<=Degree ) high[2*i+1][_j2] += (*this)[i][j] * bCoefficients[k-BSplineSupportSizes< Degree >::UpSampleStart]; + } + } + high.denominator = denominator< +template< unsigned int D > +void BSplineElements< Degree >::differentiate( BSplineElements< Degree-D >& d ) const{ Differentiator< Degree , Degree-D >::Differentiate( *this , d ); } + +template< int Degree , int DDegree > +void Differentiator< Degree , DDegree >::Differentiate( const BSplineElements< Degree >& bse , BSplineElements< DDegree >& dbse ) +{ + BSplineElements< Degree-1 > _dbse; + _dbse.resize( bse.size() ); + _dbse.assign( _dbse.size() , BSplineElementCoefficients< Degree-1 >() ); + for( int i=0 ; i<(int)bse.size() ; i++ ) for( int j=0 ; j<=Degree ; j++ ) + { + if( j-1>=0 ) _dbse[i][j-1] -= bse[i][j]; + if( j::Differentiate( _dbse , dbse ); +} + +template< int Degree > +void Differentiator< Degree , Degree >::Differentiate( const BSplineElements< Degree >& bse , BSplineElements< Degree >& dbse ){ dbse = bse; } + +// If we were really good, we would implement this integral table to store +// rational values to improve precision... +template< int Degree1 , int Degree2 > +void SetBSplineElementIntegrals( double integrals[Degree1+1][Degree2+1] ) +{ + for( int i=0 ; i<=Degree1 ; i++ ) + { + Polynomial< Degree1 > p1 = Polynomial< Degree1 >::BSplineComponent( Degree1-i ); + for( int j=0 ; j<=Degree2 ; j++ ) + { + Polynomial< Degree2 > p2 = Polynomial< Degree2 >::BSplineComponent( Degree2-j ); + integrals[i][j] = ( p1 * p2 ).integral( 0 , 1 ); + } + } +} diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/BinaryNode.h b/src/plugins_unsupported/filter_screened_poisson_xml/Src/BinaryNode.h new file mode 100644 index 000000000..7c5a17153 --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/BinaryNode.h @@ -0,0 +1,70 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +#ifndef BINARY_NODE_INCLUDED +#define BINARY_NODE_INCLUDED + +class BinaryNode +{ +public: + static inline int CenterCount( int depth ) { return 1< static inline Real Width( int depth ){ return Real(1.0/(1< static inline void CenterAndWidth( int depth , int offset , Real& center , Real& width ){ width = Real (1.0/(1< static inline void CornerAndWidth( int depth , int offset , Real& corner , Real& width ){ width = Real(1.0/(1< static inline void CenterAndWidth( int idx , Real& center , Real& width ) + { + int depth , offset; + CenterDepthAndOffset( idx , depth , offset ); + CenterAndWidth( depth , offset , center , width ); + } + template< class Real > static inline void CornerAndWidth( int idx , Real& corner , Real& width ) + { + int depth , offset; + CornerDepthAndOffset( idx , depth , offset ); + CornerAndWidth( depth , offset , corner , width ); + } + static inline void CenterDepthAndOffset( int idx , int& depth , int& offset ) + { + offset = idx , depth = 0; + while( offset>=(1<=( (1< +#include +#include +#include +#include "CmdLineParser.h" + + +#ifdef WIN32 +int strcasecmp(char* c1,char* c2){return _stricmp(c1,c2);} +#endif + +cmdLineReadable::cmdLineReadable(const char* name) +{ + set=false; + this->name=new char[strlen(name)+1]; + strcpy(this->name,name); +} +cmdLineReadable::~cmdLineReadable(void) +{ + if(name) delete[] name; + name=NULL; +} +int cmdLineReadable::read(char**,int){ + set=true; + return 0; +} +void cmdLineReadable::writeValue(char* str) +{ + str[0] = 0; +} + +//////////////// +// cmdLineInt // +//////////////// +cmdLineInt::cmdLineInt(const char* name) : cmdLineReadable(name) {value=0;} +cmdLineInt::cmdLineInt(const char* name,const int& v) : cmdLineReadable(name) {value=v;} +int cmdLineInt::read(char** argv,int argc){ + if(argc>0){ + value=atoi(argv[0]); + set=true; + return 1; + } + else{return 0;} +} +void cmdLineInt::writeValue(char* str) +{ + sprintf(str,"%d",value); +} + +////////////////// +// cmdLineFloat // +////////////////// +cmdLineFloat::cmdLineFloat(const char* name) : cmdLineReadable(name) {value=0;} +cmdLineFloat::cmdLineFloat(const char* name, const float& v) : cmdLineReadable(name) {value=v;} +int cmdLineFloat::read(char** argv,int argc){ + if(argc>0){ + value=(float)atof(argv[0]); + set=true; + return 1; + } + else{return 0;} +} +void cmdLineFloat::writeValue(char* str) +{ + sprintf(str,"%f",value); +} + +/////////////////// +// cmdLineString // +/////////////////// +cmdLineString::cmdLineString(const char* name) : cmdLineReadable(name) {value=NULL;} +cmdLineString::~cmdLineString(void) +{ + if(value) delete[] value; + value=NULL; +} +int cmdLineString::read(char** argv,int argc){ + if(argc>0) + { + value=new char[strlen(argv[0])+1]; + strcpy(value,argv[0]); + set=true; + return 1; + } + else{return 0;} +} +void cmdLineString::writeValue(char* str) +{ + sprintf(str,"%s",value); +} + +//////////////////// +// cmdLineStrings // +//////////////////// +cmdLineStrings::cmdLineStrings(const char* name,int Dim) : cmdLineReadable(name) +{ + this->Dim=Dim; + values=new char*[Dim]; + for(int i=0;i=Dim) + { + for(int i=0;i 0) + { + if (argv[0][0] == '-' && argv[0][1]=='-') + { + for(i=0;iname)) + { + argv++, argc--; + j=readable[i]->read(argv,argc); + argv+=j,argc-=j; + break; + } + } + if(i==num){ + if(dumpError) + { + fprintf(stderr, "invalid option: %s\n",*argv); + fprintf(stderr, "possible options are:\n"); + for(i=0;iname); + } + argv++, argc--; + } + } + else + { + if(dumpError) + { + fprintf(stderr, "invalid option: %s\n", *argv); + fprintf(stderr, " options must start with a \'--\'\n"); + } + argv++, argc--; + } + } +} +char** ReadWords(const char* fileName,int& cnt) +{ + char** names; + char temp[500]; + FILE* fp; + + fp=fopen(fileName,"r"); + if(!fp){return NULL;} + cnt=0; + while(fscanf(fp," %s ",temp)==1){cnt++;} + fclose(fp); + + names=new char*[cnt]; + if(!names){return NULL;} + + fp=fopen(fileName,"r"); + if(!fp){ + delete[] names; + cnt=0; + return NULL; + } + cnt=0; + while(fscanf(fp," %s ",temp)==1){ + names[cnt]=new char[strlen(temp)+1]; + if(!names){ + for(int j=0;j +#include + + +#ifdef WIN32 +int strcasecmp(char* c1,char* c2); +#endif + +class cmdLineReadable{ +public: + bool set; + char* name; + cmdLineReadable(const char* name); + virtual ~cmdLineReadable(void); + virtual int read(char** argv,int argc); + virtual void writeValue(char* str); +}; + +class cmdLineInt : public cmdLineReadable { +public: + int value; + cmdLineInt(const char* name); + cmdLineInt(const char* name,const int& v); + int read(char** argv,int argc); + void writeValue(char* str); +}; +template +class cmdLineIntArray : public cmdLineReadable { +public: + int values[Dim]; + cmdLineIntArray(const char* name); + cmdLineIntArray(const char* name,const int v[Dim]); + int read(char** argv,int argc); + void writeValue(char* str); +}; + +class cmdLineFloat : public cmdLineReadable { +public: + float value; + cmdLineFloat(const char* name); + cmdLineFloat(const char* name,const float& f); + int read(char** argv,int argc); + void writeValue(char* str); +}; +template +class cmdLineFloatArray : public cmdLineReadable { +public: + float values[Dim]; + cmdLineFloatArray(const char* name); + cmdLineFloatArray(const char* name,const float f[Dim]); + int read(char** argv,int argc); + void writeValue(char* str); +}; +class cmdLineString : public cmdLineReadable { +public: + char* value; + cmdLineString(const char* name); + ~cmdLineString(); + int read(char** argv,int argc); + void writeValue(char* str); +}; +class cmdLineStrings : public cmdLineReadable { + int Dim; +public: + char** values; + cmdLineStrings(const char* name,int Dim); + ~cmdLineStrings(void); + int read(char** argv,int argc); + void writeValue(char* str); +}; +template +class cmdLineStringArray : public cmdLineReadable { +public: + char* values[Dim]; + cmdLineStringArray(const char* name); + ~cmdLineStringArray(); + int read(char** argv,int argc); + void writeValue(char* str); +}; + +// This reads the arguments in argc, matches them against "names" and sets +// the values of "r" appropriately. Parameters start with "--" +void cmdLineParse(int argc, char **argv,int num,cmdLineReadable** r,int dumpError=1); + +char* GetFileExtension(char* fileName); +char* GetLocalFileName(char* fileName); +char** ReadWords(const char* fileName,int& cnt); + +#include "CmdLineParser.inl" +#endif // CMD_LINE_PARSER_INCLUDED diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/CmdLineParser.inl b/src/plugins_unsupported/filter_screened_poisson_xml/Src/CmdLineParser.inl new file mode 100644 index 000000000..eeded6805 --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/CmdLineParser.inl @@ -0,0 +1,141 @@ +/* -*- C++ -*- +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +///////////////////// +// cmdLineIntArray // +///////////////////// +template +cmdLineIntArray::cmdLineIntArray(const char* name) : cmdLineReadable(name) +{ + for(int i=0;i +cmdLineIntArray::cmdLineIntArray(const char* name,const int v[Dim]) : cmdLineReadable(name) +{ + for(int i=0;i +int cmdLineIntArray::read(char** argv,int argc) +{ + if(argc>=Dim) + { + for(int i=0;i +void cmdLineIntArray::writeValue(char* str) +{ + char* temp=str; + for(int i=0;i +cmdLineFloatArray::cmdLineFloatArray(const char* name) : cmdLineReadable(name) +{ + for(int i=0;i +cmdLineFloatArray::cmdLineFloatArray(const char* name,const float f[Dim]) : cmdLineReadable(name) +{ + for(int i=0;i +int cmdLineFloatArray::read(char** argv,int argc) +{ + if(argc>=Dim) + { + for(int i=0;i +void cmdLineFloatArray::writeValue(char* str) +{ + char* temp=str; + for(int i=0;i +cmdLineStringArray::cmdLineStringArray(const char* name) : cmdLineReadable(name) +{ + for(int i=0;i +cmdLineStringArray::~cmdLineStringArray(void) +{ + for(int i=0;i +int cmdLineStringArray::read(char** argv,int argc) +{ + if(argc>=Dim) + { + for(int i=0;i +void cmdLineStringArray::writeValue(char* str) +{ + char* temp=str; + for(int i=0;i +#include "Factor.h" +int Factor(double a1,double a0,double roots[1][2],double EPS){ + if(fabs(a1)<=EPS){return 0;} + roots[0][0]=-a0/a1; + roots[0][1]=0; + return 1; +} +int Factor(double a2,double a1,double a0,double roots[2][2],double EPS){ + double d; + if(fabs(a2)<=EPS){return Factor(a1,a0,roots,EPS);} + + d=a1*a1-4*a0*a2; + a1/=(2*a2); + if(d<0){ + d=sqrt(-d)/(2*a2); + roots[0][0]=roots[1][0]=-a1; + roots[0][1]=-d; + roots[1][1]= d; + } + else{ + d=sqrt(d)/(2*a2); + roots[0][1]=roots[1][1]=0; + roots[0][0]=-a1-d; + roots[1][0]=-a1+d; + } + return 2; +} +// Solution taken from: http://mathworld.wolfram.com/CubicFormula.html +// and http://www.csit.fsu.edu/~burkardt/f_src/subpak/subpak.f90 +int Factor(double a3,double a2,double a1,double a0,double roots[3][2],double EPS){ + double q,r,r2,q3; + + if(fabs(a3)<=EPS){return Factor(a2,a1,a0,roots,EPS);} + a2/=a3; + a1/=a3; + a0/=a3; + + q=-(3*a1-a2*a2)/9; + r=-(9*a2*a1-27*a0-2*a2*a2*a2)/54; + r2=r*r; + q3=q*q*q; + + if(r20){return PI/2.0;} + else{return -PI/2.0;} + } + if(x>=0){return atan(y/x);} + else{ + if(y>=0){return atan(y/x)+PI;} + else{return atan(y/x)-PI;} + } +} +double Angle(const double in[2]){ + if((in[0]*in[0]+in[1]*in[1])==0.0){return 0;} + else{return ArcTan2(in[1],in[0]);} +} +void Sqrt(const double in[2],double out[2]){ + double r=sqrt(sqrt(in[0]*in[0]+in[1]*in[1])); + double a=Angle(in)*0.5; + out[0]=r*cos(a); + out[1]=r*sin(a); +} +void Add(const double in1[2],const double in2[2],double out[2]){ + out[0]=in1[0]+in2[0]; + out[1]=in1[1]+in2[1]; +} +void Subtract(const double in1[2],const double in2[2],double out[2]){ + out[0]=in1[0]-in2[0]; + out[1]=in1[1]-in2[1]; +} +void Multiply(const double in1[2],const double in2[2],double out[2]){ + out[0]=in1[0]*in2[0]-in1[1]*in2[1]; + out[1]=in1[0]*in2[1]+in1[1]*in2[0]; +} +void Divide(const double in1[2],const double in2[2],double out[2]){ + double temp[2]; + double l=in2[0]*in2[0]+in2[1]*in2[1]; + temp[0]= in2[0]/l; + temp[1]=-in2[1]/l; + Multiply(in1,temp,out); +} +// Solution taken from: http://mathworld.wolfram.com/QuarticEquation.html +// and http://www.csit.fsu.edu/~burkardt/f_src/subpak/subpak.f90 +int Factor(double a4,double a3,double a2,double a1,double a0,double roots[4][2],double EPS){ + double R[2],D[2],E[2],R2[2]; + + if(fabs(a4)10e-8){ + double temp1[2],temp2[2]; + double p1[2],p2[2]; + + p1[0]=a3*a3*0.75-2.0*a2-R2[0]; + p1[1]=0; + + temp2[0]=((4.0*a3*a2-8.0*a1-a3*a3*a3)/4.0); + temp2[1]=0; + Divide(temp2,R,p2); + + Add (p1,p2,temp1); + Subtract(p1,p2,temp2); + + Sqrt(temp1,D); + Sqrt(temp2,E); + } + else{ + R[0]=R[1]=0; + double temp1[2],temp2[2]; + temp1[0]=roots[0][0]*roots[0][0]-4.0*a0; + temp1[1]=0; + Sqrt(temp1,temp2); + temp1[0]=a3*a3*0.75-2.0*a2+2.0*temp2[0]; + temp1[1]= 2.0*temp2[1]; + Sqrt(temp1,D); + temp1[0]=a3*a3*0.75-2.0*a2-2.0*temp2[0]; + temp1[1]= -2.0*temp2[1]; + Sqrt(temp1,E); + } + + roots[0][0]=-a3/4.0+R[0]/2.0+D[0]/2.0; + roots[0][1]= R[1]/2.0+D[1]/2.0; + + roots[1][0]=-a3/4.0+R[0]/2.0-D[0]/2.0; + roots[1][1]= R[1]/2.0-D[1]/2.0; + + roots[2][0]=-a3/4.0-R[0]/2.0+E[0]/2.0; + roots[2][1]= -R[1]/2.0+E[1]/2.0; + + roots[3][0]=-a3/4.0-R[0]/2.0-E[0]/2.0; + roots[3][1]= -R[1]/2.0-E[1]/2.0; + return 4; +} + +int Solve(const double* eqns,const double* values,double* solutions,int dim){ + int i,j,eIndex; + double v,m; + int *index=new int[dim]; + int *set=new int[dim]; + double* myEqns=new double[dim*dim]; + double* myValues=new double[dim]; + + for(i=0;im){ + m=fabs(myEqns[j*dim+i]); + eIndex=j; + } + } + if(eIndex==-1){ + delete[] index; + delete[] myValues; + delete[] myEqns; + delete[] set; + return 0; + } + // The position in which the solution for the i-th variable can be found + index[i]=eIndex; + set[eIndex]=1; + + // Normalize the equation + v=myEqns[eIndex*dim+i]; + for(j=0;j +class FunctionData{ + bool useDotRatios; + int normalize; +#if BOUNDARY_CONDITIONS + bool reflectBoundary; +#endif // BOUNDARY_CONDITIONS +public: + const static int DOT_FLAG = 1; + const static int D_DOT_FLAG = 2; + const static int D2_DOT_FLAG = 4; + const static int VALUE_FLAG = 1; + const static int D_VALUE_FLAG = 2; + + int depth , res , res2; + Real *dotTable , *dDotTable , *d2DotTable; + Real *valueTables , *dValueTables; +#if BOUNDARY_CONDITIONS + PPolynomial baseFunction , leftBaseFunction , rightBaseFunction; + PPolynomial dBaseFunction , dLeftBaseFunction , dRightBaseFunction; +#else // !BOUNDARY_CONDITIONS + PPolynomial baseFunction; + PPolynomial dBaseFunction; +#endif // BOUNDARY_CONDITIONS + PPolynomial* baseFunctions; + + FunctionData(void); + ~FunctionData(void); + + virtual void setDotTables(const int& flags); + virtual void clearDotTables(const int& flags); + + virtual void setValueTables(const int& flags,const double& smooth=0); + virtual void setValueTables(const int& flags,const double& valueSmooth,const double& normalSmooth); + virtual void clearValueTables(void); + + /******************************************************** + * Sets the translates and scales of the basis function + * up to the prescribed depth + * the maximum depth + * the basis function + * how the functions should be scaled + * 0] Value at zero equals 1 + * 1] Integral equals 1 + * 2] L2-norm equals 1 + * specifies if dot-products of derivatives + * should be pre-divided by function integrals + * specifies if function space should be + * forced to be reflectively symmetric across the boundary + ********************************************************/ +#if BOUNDARY_CONDITIONS + void set( const int& maxDepth , const PPolynomial& F , const int& normalize , bool useDotRatios=true , bool reflectBoundary=false ); +#else // !BOUNDARY_CONDITIONS + void set(const int& maxDepth,const PPolynomial& F,const int& normalize , bool useDotRatios=true ); +#endif // BOUNDARY_CONDITIONS + +#if BOUNDARY_CONDITIONS + Real dotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 , int boundary1 , int boundary2 ) const; + Real dDotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 , int boundary1 , int boundary2 ) const; + Real d2DotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 , int boundary1 , int boundary2 ) const; +#else // !BOUNDARY_CONDITIONS + Real dotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 ) const; + Real dDotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 ) const; + Real d2DotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 ) const; +#endif // BOUNDARY_CONDITIONS + + static inline int SymmetricIndex( const int& i1 , const int& i2 ); + static inline int SymmetricIndex( const int& i1 , const int& i2 , int& index ); +}; + + +#include "FunctionData.inl" +#endif // FUNCTION_DATA_INCLUDED \ No newline at end of file diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/FunctionData.inl b/src/plugins_unsupported/filter_screened_poisson_xml/Src/FunctionData.inl new file mode 100644 index 000000000..4e61b961e --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/FunctionData.inl @@ -0,0 +1,415 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +////////////////// +// FunctionData // +////////////////// +template +FunctionData::FunctionData(void) +{ + dotTable=dDotTable=d2DotTable=NULL; + valueTables=dValueTables=NULL; + res=0; +} + +template +FunctionData::~FunctionData(void) +{ + if(res) + { + if( dotTable) delete[] dotTable; + if( dDotTable) delete[] dDotTable; + if(d2DotTable) delete[] d2DotTable; + if( valueTables) delete[] valueTables; + if(dValueTables) delete[] dValueTables; + } + dotTable=dDotTable=d2DotTable=NULL; + valueTables=dValueTables=NULL; + res=0; +} + +template +#if BOUNDARY_CONDITIONS +void FunctionData::set( const int& maxDepth , const PPolynomial& F , const int& normalize , bool useDotRatios , bool reflectBoundary ) +#else // !BOUNDARY_CONDITIONS +void FunctionData::set(const int& maxDepth,const PPolynomial& F,const int& normalize , bool useDotRatios ) +#endif // BOUNDARY_CONDITIONS +{ + this->normalize = normalize; + this->useDotRatios = useDotRatios; +#if BOUNDARY_CONDITIONS + this->reflectBoundary = reflectBoundary; +#endif // BOUNDARY_CONDITIONS + + depth = maxDepth; + res = BinaryNode::CumulativeCenterCount( depth ); + res2 = (1<<(depth+1))+1; + baseFunctions = new PPolynomial[res]; + // Scale the function so that it has: + // 0] Value 1 at 0 + // 1] Integral equal to 1 + // 2] Square integral equal to 1 + switch( normalize ) + { + case 2: + baseFunction=F/sqrt((F*F).integral(F.polys[0].start,F.polys[F.polyCount-1].start)); + break; + case 1: + baseFunction=F/F.integral(F.polys[0].start,F.polys[F.polyCount-1].start); + break; + default: + baseFunction=F/F(0); + } + dBaseFunction = baseFunction.derivative(); +#if BOUNDARY_CONDITIONS + leftBaseFunction = baseFunction + baseFunction.shift( -1 ); + rightBaseFunction = baseFunction + baseFunction.shift( 1 ); + dLeftBaseFunction = leftBaseFunction.derivative(); + dRightBaseFunction = rightBaseFunction.derivative(); +#endif // BOUNDARY_CONDITIONS + double c1,w1; + for( int i=0 ; i::CenterAndWidth( i , c1 , w1 ); +#if BOUNDARY_CONDITIONS + if( reflectBoundary ) + { + int d , off; + BinaryNode< double >::DepthAndOffset( i , d , off ); + if ( off==0 ) baseFunctions[i] = leftBaseFunction.scale( w1 ).shift( c1 ); + else if( off==((1< +void FunctionData::setDotTables( const int& flags ) +{ + clearDotTables( flags ); + int size; + size = ( res*res + res )>>1; + if( flags & DOT_FLAG ) + { + dotTable = new Real[size]; + memset( dotTable , 0 , sizeof(Real)*size ); + } + if( flags & D_DOT_FLAG ) + { + dDotTable = new Real[size]; + memset( dDotTable , 0 , sizeof(Real)*size ); + } + if( flags & D2_DOT_FLAG ) + { + d2DotTable = new Real[size]; + memset( d2DotTable , 0 , sizeof(Real)*size ); + } + double t1 , t2; + t1 = baseFunction.polys[0].start; + t2 = baseFunction.polys[baseFunction.polyCount-1].start; + for( int i=0 ; i::CenterAndWidth( i , c1 , w1 ); +#if BOUNDARY_CONDITIONS + int d1 , d2 , off1 , off2; + BinaryNode< double >::DepthAndOffset( i , d1 , off1 ); + int boundary1 = 0; + if ( reflectBoundary && off1==0 ) boundary1 = -1; + else if( reflectBoundary && off1==( (1<::CenterAndWidth( j , c2 , w2 ); +#if BOUNDARY_CONDITIONS + BinaryNode< double >::DepthAndOffset( j , d2 , off2 ); + int boundary2 = 0; + if ( reflectBoundary && off2==0 ) boundary2 = -1; + else if( reflectBoundary && off2==( (1<1 ) start = 1; + if( end <0 ) end = 0; + if( end >1 ) end = 1; + } +#endif // BOUNDARY_CONDITIONS + + if( start< start1 ) start = start1; + if( end > end1 ) end = end1; + if( start>= end ) continue; + +#if BOUNDARY_CONDITIONS + Real dot = dotProduct( c1 , w1 , c2 , w2 , boundary1 , boundary2 ); +#else // !BOUNDARY_CONDITIONS + Real dot = dotProduct( c1 , w1 , c2 , w2 ); +#endif // BOUNDARY_CONDITIONS + if( fabs(dot)<1e-15 ) continue; + if( flags & DOT_FLAG ) dotTable[idx]=dot; + if( useDotRatios ) + { +#if BOUNDARY_CONDITIONS + if( flags & D_DOT_FLAG ) dDotTable[idx] = -dDotProduct( c1 , w1 , c2 , w2 , boundary1 , boundary2 ) / dot; + if( flags & D2_DOT_FLAG ) d2DotTable[idx] = d2DotProduct( c1 , w1 , c2 , w2 , boundary1 , boundary2 ) / dot; +#else // !BOUNDARY_CONDITIONS + if( flags & D_DOT_FLAG ) dDotTable[idx] = -dDotProduct(c1,w1,c2,w2)/dot; + if( flags & D2_DOT_FLAG ) d2DotTable[idx] = d2DotProduct(c1,w1,c2,w2)/dot; +#endif // BOUNDARY_CONDITIONS + } + else + { +#if BOUNDARY_CONDITIONS + if( flags & D_DOT_FLAG ) dDotTable[idx] = dDotProduct( c1 , w1 , c2 , w2 , boundary1 , boundary2 ); + if( flags & D2_DOT_FLAG ) d2DotTable[idx] = d2DotProduct( c1 , w1 , c2 , w2 , boundary1 , boundary2 ); +#else // !BOUNDARY_CONDTIONS + if( flags & D_DOT_FLAG ) dDotTable[idx] = dDotProduct(c1,w1,c2,w2); + if( flags & D2_DOT_FLAG ) d2DotTable[idx] = d2DotProduct(c1,w1,c2,w2); +#endif // BOUNDARY_CONDITIONS + } + } + } +} +template +void FunctionData::clearDotTables( const int& flags ) +{ + if((flags & DOT_FLAG) && dotTable) + { + delete[] dotTable; + dotTable=NULL; + } + if((flags & D_DOT_FLAG) && dDotTable) + { + delete[] dDotTable; + dDotTable=NULL; + } + if((flags & D2_DOT_FLAG) && d2DotTable) + { + delete[] d2DotTable; + d2DotTable=NULL; + } +} +template +void FunctionData::setValueTables( const int& flags , const double& smooth ) +{ + clearValueTables(); + if( flags & VALUE_FLAG ) valueTables = new Real[res*res2]; + if( flags & D_VALUE_FLAG ) dValueTables = new Real[res*res2]; + PPolynomial function; + PPolynomial dFunction; + for( int i=0 ; i0) + { + function=baseFunctions[i].MovingAverage(smooth); + dFunction=baseFunctions[i].derivative().MovingAverage(smooth); + } + else + { + function=baseFunctions[i]; + dFunction=baseFunctions[i].derivative(); + } + for( int j=0 ; j +void FunctionData::setValueTables(const int& flags,const double& valueSmooth,const double& normalSmooth){ + clearValueTables(); + if(flags & VALUE_FLAG){ valueTables=new Real[res*res2];} + if(flags & D_VALUE_FLAG){dValueTables=new Real[res*res2];} + PPolynomial function; + PPolynomial dFunction; + for(int i=0;i0) { function=baseFunctions[i].MovingAverage(valueSmooth);} + else { function=baseFunctions[i];} + if(normalSmooth>0) {dFunction=baseFunctions[i].derivative().MovingAverage(normalSmooth);} + else {dFunction=baseFunctions[i].derivative();} + + for(int j=0;j +void FunctionData::clearValueTables(void){ + if( valueTables){delete[] valueTables;} + if(dValueTables){delete[] dValueTables;} + valueTables=dValueTables=NULL; +} + +#if BOUNDARY_CONDITIONS +template +Real FunctionData::dotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 , int boundary1 , int boundary2 ) const +{ + const PPolynomial< Degree > *b1 , *b2; + if ( boundary1==-1 ) b1 = & leftBaseFunction; + else if( boundary1== 0 ) b1 = & baseFunction; + else if( boundary1== 1 ) b1 = &rightBaseFunction; + if ( boundary2==-1 ) b2 = & leftBaseFunction; + else if( boundary2== 0 ) b2 = & baseFunction; + else if( boundary2== 1 ) b2 = &rightBaseFunction; + double r=fabs( baseFunction.polys[0].start ); + switch( normalize ) + { + case 2: + return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)*width1/sqrt(width1*width2)); + case 1: + return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)*width1/(width1*width2)); + default: + return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)*width1); + } +} +template +Real FunctionData::dDotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 , int boundary1 , int boundary2 ) const +{ + const PPolynomial< Degree-1 > *b1; + const PPolynomial< Degree > *b2; + if ( boundary1==-1 ) b1 = & dLeftBaseFunction; + else if( boundary1== 0 ) b1 = & dBaseFunction; + else if( boundary1== 1 ) b1 = &dRightBaseFunction; + if ( boundary2==-1 ) b2 = & leftBaseFunction; + else if( boundary2== 0 ) b2 = & baseFunction; + else if( boundary2== 1 ) b2 = & rightBaseFunction; + double r=fabs(baseFunction.polys[0].start); + switch(normalize){ + case 2: + return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/sqrt(width1*width2)); + case 1: + return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/(width1*width2)); + default: + return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)); + } +} +template +Real FunctionData::d2DotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 , int boundary1 , int boundary2 ) const +{ + const PPolynomial< Degree-1 > *b1 , *b2; + if ( boundary1==-1 ) b1 = & dLeftBaseFunction; + else if( boundary1== 0 ) b1 = & dBaseFunction; + else if( boundary1== 1 ) b1 = &dRightBaseFunction; + if ( boundary2==-1 ) b2 = & dLeftBaseFunction; + else if( boundary2== 0 ) b2 = & dBaseFunction; + else if( boundary2== 1 ) b2 = &dRightBaseFunction; + double r=fabs(baseFunction.polys[0].start); + switch( normalize ) + { + case 2: + return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/width2/sqrt(width1*width2)); + case 1: + return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/width2/(width1*width2)); + default: + return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/width2); + } +} +#else // !BOUNDARY_CONDITIONS +template +Real FunctionData::dotProduct(const double& center1,const double& width1,const double& center2,const double& width2) const{ + double r=fabs(baseFunction.polys[0].start); + switch( normalize ) + { + case 2: + return Real((baseFunction*baseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)*width1/sqrt(width1*width2)); + case 1: + return Real((baseFunction*baseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)*width1/(width1*width2)); + default: + return Real((baseFunction*baseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)*width1); + } +} +template +Real FunctionData::dDotProduct(const double& center1,const double& width1,const double& center2,const double& width2) const{ + double r=fabs(baseFunction.polys[0].start); + switch(normalize){ + case 2: + return Real((dBaseFunction*baseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/sqrt(width1*width2)); + case 1: + return Real((dBaseFunction*baseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/(width1*width2)); + default: + return Real((dBaseFunction*baseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)); + } +} +template +Real FunctionData::d2DotProduct(const double& center1,const double& width1,const double& center2,const double& width2) const{ + double r=fabs(baseFunction.polys[0].start); + switch(normalize){ + case 2: + return Real((dBaseFunction*dBaseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/width2/sqrt(width1*width2)); + case 1: + return Real((dBaseFunction*dBaseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/width2/(width1*width2)); + default: + return Real((dBaseFunction*dBaseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/width2); + } +} +#endif // BOUNDARY_CONDITIONS +template +inline int FunctionData::SymmetricIndex( const int& i1 , const int& i2 ) +{ + if( i1>i2 ) return ((i1*i1+i1)>>1)+i2; + else return ((i2*i2+i2)>>1)+i1; +} +template +inline int FunctionData::SymmetricIndex( const int& i1 , const int& i2 , int& index ) +{ + if( i1>1)+i1; + return 1; + } + else{ + index = ((i1*i1+i1)>>1)+i2; + return 0; + } +} diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/Geometry.cpp b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Geometry.cpp new file mode 100644 index 000000000..d6fa72832 --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Geometry.cpp @@ -0,0 +1,122 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ +#include "Geometry.h" +#include +#include +#ifdef _WIN32 +#include +#endif // _WIN32 + +/////////////////// +// CoredMeshData // +/////////////////// + +TriangulationEdge::TriangulationEdge(void){pIndex[0]=pIndex[1]=tIndex[0]=tIndex[1]=-1;} +TriangulationTriangle::TriangulationTriangle(void){eIndex[0]=eIndex[1]=eIndex[2]=-1;} + +/////////////////////////// +// BufferedReadWriteFile // +/////////////////////////// +BufferedReadWriteFile::BufferedReadWriteFile( char* fileName , int bufferSize ) +{ + _bufferIndex = 0; + _bufferSize = bufferSize; + if( fileName ) strcpy( _fileName , fileName ) , tempFile = false , _fp = fopen( _fileName , "w+b" ); + else + { + strcpy( _fileName , "PR_XXXXXX" ); +#ifdef _WIN32 + _mktemp( _fileName ); + _fp = fopen( _fileName , "w+b" ); +#else // !_WIN32 + _fp = fdopen( mkstemp( _fileName ) , "w+b" ); +#endif // _WIN32 + tempFile = true; + } + if( !_fp ) fprintf( stderr , "[ERROR] Failed to open file: %s\n" , _fileName ) , exit( 0 ); + _buffer = (char*) malloc( _bufferSize ); +} +BufferedReadWriteFile::~BufferedReadWriteFile( void ) +{ + free( _buffer ); + fclose( _fp ); + if( tempFile ) remove( _fileName ); +} +void BufferedReadWriteFile::reset( void ) +{ + if( _bufferIndex ) fwrite( _buffer , 1 , _bufferIndex , _fp ); + _bufferIndex = 0; + fseek( _fp , 0 , SEEK_SET ); + _bufferIndex = 0; + _bufferSize = fread( _buffer , 1 , _bufferSize , _fp ); +} +bool BufferedReadWriteFile::write( const void* data , size_t size ) +{ + if( !size ) return true; + char* _data = (char*) data; + size_t sz = _bufferSize - _bufferIndex; + while( sz<=size ) + { + memcpy( _buffer+_bufferIndex , _data , sz ); + fwrite( _buffer , 1 , _bufferSize , _fp ); + _data += sz; + size -= sz; + _bufferIndex = 0; + sz = _bufferSize; + } + if( size ) + { + memcpy( _buffer+_bufferIndex , _data , size ); + _bufferIndex += size; + } + return true; +} +bool BufferedReadWriteFile::read( void* data , size_t size ) +{ + if( !size ) return true; + char *_data = (char*) data; + size_t sz = _bufferSize - _bufferIndex; + while( sz<=size ) + { + if( size && !_bufferSize ) return false; + memcpy( _data , _buffer+_bufferIndex , sz ); + _bufferSize = fread( _buffer , 1 , _bufferSize , _fp ); + _data += sz; + size -= sz; + _bufferIndex = 0; + if( !size ) return true; + sz = _bufferSize; + } + if( size ) + { + if( !_bufferSize ) return false; + memcpy( _data , _buffer+_bufferIndex , size ); + _bufferIndex += size; + } + return true; +} \ No newline at end of file diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/Geometry.h b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Geometry.h new file mode 100644 index 000000000..9c2018d2d --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Geometry.h @@ -0,0 +1,414 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +#ifndef GEOMETRY_INCLUDED +#define GEOMETRY_INCLUDED + +#include +#include +#include +#include +#include + +template +Real Random(void); + +template< class Real > +struct Point3D +{ + Real coords[3]; + Point3D( void ) { coords[0] = coords[1] = coords[2] = Real(0); } + Point3D( Real v ) { coords[0] = coords[1] = coords[2] = v; } + template< class _Real > Point3D( _Real v0 , _Real v1 , _Real v2 ){ coords[0] = Real(v0) , coords[1] = Real(v1) , coords[2] = Real(v2); } + template< class _Real > Point3D( const Point3D< _Real >& p ){ coords[0] = Real( p[0] ) , coords[1] = Real( p[1] ) , coords[2] = Real( p[2] ); } + inline Real& operator[] ( int i ) { return coords[i]; } + inline const Real& operator[] ( int i ) const { return coords[i]; } + inline Point3D operator - ( void ) const { Point3D q ; q.coords[0] = -coords[0] , q.coords[1] = -coords[1] , q.coords[2] = -coords[2] ; return q; } + + template< class _Real > inline Point3D& operator += ( Point3D< _Real > p ){ coords[0] += Real(p.coords[0]) , coords[1] += Real(p.coords[1]) , coords[2] += Real(p.coords[2]) ; return *this; } + template< class _Real > inline Point3D operator + ( Point3D< _Real > p ) const { Point3D q ; q.coords[0] = coords[0] + Real(p.coords[0]) , q.coords[1] = coords[1] + Real(p.coords[1]) , q.coords[2] = coords[2] + Real(p.coords[2]) ; return q; } + template< class _Real > inline Point3D& operator *= ( _Real r ) { coords[0] *= Real(r) , coords[1] *= Real(r) , coords[2] *= Real(r) ; return *this; } + template< class _Real > inline Point3D operator * ( _Real r ) const { Point3D q ; q.coords[0] = coords[0] * Real(r) , q.coords[1] = coords[1] * Real(r) , q.coords[2] = coords[2] * Real(r) ; return q; } + + template< class _Real > inline Point3D& operator -= ( Point3D< _Real > p ){ return ( (*this)+=(-p) ); } + template< class _Real > inline Point3D operator - ( Point3D< _Real > p ) const { return (*this)+(-p); } + template< class _Real > inline Point3D& operator /= ( _Real r ){ return ( (*this)*=Real(1./r) ); } + template< class _Real > inline Point3D operator / ( _Real r ) const { return (*this) * ( Real(1.)/r ); } + + static Real Dot( const Point3D< Real >& p1 , const Point3D< Real >& p2 ){ return p1.coords[0]*p2.coords[0] + p1.coords[1]*p2.coords[1] + p1.coords[2]*p2.coords[2]; } + template< class Real1 , class Real2 > + static Real Dot( const Point3D< Real1 >& p1 , const Point3D< Real2 >& p2 ){ return Real( p1.coords[0]*p2.coords[0] + p1.coords[1]*p2.coords[1] + p1.coords[2]*p2.coords[2] ); } +}; + +template< class Real > +struct XForm3x3 +{ + Real coords[3][3]; + XForm3x3( void ) { for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) coords[i][j] = Real(0.); } + static XForm3x3 Identity( void ) + { + XForm3x3 xForm; + xForm(0,0) = xForm(1,1) = xForm(2,2) = Real(1.); + return xForm; + } + Real& operator() ( int i , int j ){ return coords[i][j]; } + const Real& operator() ( int i , int j ) const { return coords[i][j]; } + template< class _Real > Point3D< _Real > operator * ( const Point3D< _Real >& p ) const + { + Point3D< _Real > q; + for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) q[i] += _Real( coords[j][i] * p[j] ); + return q; + } + XForm3x3 operator * ( const XForm3x3& m ) const + { + XForm3x3 n; + for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) n.coords[i][j] += m.coords[i][k]*coords[k][j]; + return n; + } + XForm3x3 transpose( void ) const + { + XForm3x3 xForm; + for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) xForm( i , j ) = coords[j][i]; + return xForm; + } + Real subDeterminant( int i , int j ) const + { + int i1 = (i+1)%3 , i2 = (i+2)%3; + int j1 = (j+1)%3 , j2 = (j+2)%3; + return coords[i1][j1] * coords[i2][j2] - coords[i1][j2] * coords[i2][j1]; + } + Real determinant( void ) const { return coords[0][0] * subDeterminant( 0 , 0 ) + coords[1][0] * subDeterminant( 1 , 0 ) + coords[2][0] * subDeterminant( 2 , 0 ); } + XForm3x3 inverse( void ) const + { + XForm3x3 xForm; + Real d = determinant(); + for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ;j++ ) xForm.coords[j][i] = subDeterminant( i , j ) / d; + return xForm; + } +}; + +template< class Real > +struct XForm4x4 +{ + Real coords[4][4]; + XForm4x4( void ) { for( int i=0 ; i<4 ; i++ ) for( int j=0 ; j<4 ; j++ ) coords[i][j] = Real(0.); } + static XForm4x4 Identity( void ) + { + XForm4x4 xForm; + xForm(0,0) = xForm(1,1) = xForm(2,2) = xForm(3,3) = Real(1.); + return xForm; + } + Real& operator() ( int i , int j ){ return coords[i][j]; } + const Real& operator() ( int i , int j ) const { return coords[i][j]; } + template< class _Real > Point3D< _Real > operator * ( const Point3D< _Real >& p ) const + { + Point3D< _Real > q; + for( int i=0 ; i<3 ; i++ ) + { + for( int j=0 ; j<3 ; j++ ) q[i] += (_Real)( coords[j][i] * p[j] ); + q[i] += (_Real)coords[3][i]; + } + return q; + } + XForm4x4 operator * ( const XForm4x4& m ) const + { + XForm4x4 n; + for( int i=0 ; i<4 ; i++ ) for( int j=0 ; j<4 ; j++ ) for( int k=0 ; k<4 ; k++ ) n.coords[i][j] += m.coords[i][k]*coords[k][j]; + return n; + } + XForm4x4 transpose( void ) const + { + XForm4x4 xForm; + for( int i=0 ; i<4 ; i++ ) for( int j=0 ; j<4 ; j++ ) xForm( i , j ) = coords[j][i]; + return xForm; + } + Real subDeterminant( int i , int j ) const + { + XForm3x3< Real > xForm; + int ii[] = { (i+1)%4 , (i+2)%4 , (i+3)%4 } , jj[] = { (j+1)%4 , (j+2)%4 , (j+3)%4 }; + for( int _i=0 ; _i<3 ; _i++ ) for( int _j=0 ; _j<3 ; _j++ ) xForm( _i , _j ) = coords[ ii[_i] ][ jj[_j] ]; + return xForm.determinant(); + } + Real determinant( void ) const { return coords[0][0] * subDeterminant( 0 , 0 ) - coords[1][0] * subDeterminant( 1 , 0 ) + coords[2][0] * subDeterminant( 2 , 0 ) - coords[3][0] * subDeterminant( 3 , 0 ); } + XForm4x4 inverse( void ) const + { + XForm4x4 xForm; + Real d = determinant(); + for( int i=0 ; i<4 ; i++ ) for( int j=0 ; j<4 ;j++ ) + if( (i+j)%2==0 ) xForm.coords[j][i] = subDeterminant( i , j ) / d; + else xForm.coords[j][i] = -subDeterminant( i , j ) / d; + return xForm; + } +}; + +template< class Real > +struct OrientedPoint3D +{ + Point3D< Real > p , n; + OrientedPoint3D( Point3D< Real > pp=Point3D< Real >() , Point3D< Real > nn=Point3D< Real >() ) : p(pp) , n(nn) { ; } + template< class _Real > OrientedPoint3D( const OrientedPoint3D< _Real >& p ) : OrientedPoint3D( Point3D< Real >( p.p ) , Point3D< Real >( p.n ) ){ ; } + + template< class _Real > inline OrientedPoint3D& operator += ( OrientedPoint3D< _Real > _p ){ p += _p.p , n += _p.n ; return *this; } + template< class _Real > inline OrientedPoint3D operator + ( OrientedPoint3D< _Real > _p ) const { return OrientedPoint3D< Real >( p+_p.p , n+_p.n ); } + template< class _Real > inline OrientedPoint3D& operator *= ( _Real r ) { p *= r , n *= r ; return *this; } + template< class _Real > inline OrientedPoint3D operator * ( _Real r ) const { return OrientedPoint3D< Real >( p*r , n*r ); } + + template< class _Real > inline OrientedPoint3D& operator -= ( OrientedPoint3D< _Real > p ){ return ( (*this)+=(-p) ); } + template< class _Real > inline OrientedPoint3D operator - ( OrientedPoint3D< _Real > p ) const { return (*this)+(-p); } + template< class _Real > inline OrientedPoint3D& operator /= ( _Real r ){ return ( (*this)*=Real(1./r) ); } + template< class _Real > inline OrientedPoint3D operator / ( _Real r ) const { return (*this) * ( Real(1.)/r ); } +}; + +template< class Data , class Real > +struct ProjectiveData +{ + Data data; + Real weight; + ProjectiveData( Data d=Data(0) , Real w=Real(0) ) : data(d) , weight(w) { ; } + operator Data (){ return weight!=0 ? data/weight : data*weight; } + ProjectiveData& operator += ( const ProjectiveData& p ){ data += p.data , weight += p.weight ; return *this; } + ProjectiveData& operator -= ( const ProjectiveData& p ){ data -= p.data , weight -= p.weight ; return *this; } + ProjectiveData& operator *= ( Real s ){ data *= s , weight *= s ; return *this; } + ProjectiveData& operator /= ( Real s ){ data /= s , weight /= s ; return *this; } + ProjectiveData operator + ( const ProjectiveData& p ) const { return ProjectiveData( data+p.data , weight+p.weight ); } + ProjectiveData operator - ( const ProjectiveData& p ) const { return ProjectiveData( data-p.data , weight-p.weight ); } + ProjectiveData operator * ( Real s ) const { return ProjectiveData( data*s , weight*s ); } + ProjectiveData operator / ( Real s ) const { return ProjectiveData( data/s , weight/s ); } +}; + +template +Point3D RandomBallPoint(void); + +template +Point3D RandomSpherePoint(void); + +template +double Length(const Point3D& p); + +template +double SquareLength(const Point3D& p); + +template +double Distance(const Point3D& p1,const Point3D& p2); + +template +double SquareDistance(const Point3D& p1,const Point3D& p2); + +template +void CrossProduct(const Point3D& p1,const Point3D& p2,Point3D& p); + + +class Edge{ +public: + double p[2][2]; + double Length(void) const{ + double d[2]; + d[0]=p[0][0]-p[1][0]; + d[1]=p[0][1]-p[1][1]; + + return sqrt(d[0]*d[0]+d[1]*d[1]); + } +}; +class Triangle{ +public: + double p[3][3]; + double Area(void) const{ + double v1[3] , v2[3] , v[3]; + for( int d=0 ; d<3 ; d++ ) + { + v1[d] = p[1][d] - p[0][d]; + v2[d] = p[2][d] - p[0][d]; + } + v[0] = v1[1]*v2[2] - v1[2]*v2[1]; + v[1] = -v1[0]*v2[2] + v1[2]*v2[0]; + v[2] = v1[0]*v2[1] - v1[1]*v2[0]; + return sqrt( v[0]*v[0] + v[1]*v[1] + v[2]*v[2] ) / 2; + } + double AspectRatio(void) const{ + double d=0; + int i,j; + for(i=0;i<3;i++){ + for(i=0;i<3;i++) + for(j=0;j<3;j++){d+=(p[(i+1)%3][j]-p[i][j])*(p[(i+1)%3][j]-p[i][j]);} + } + return Area()/d; + } + +}; +class CoredPointIndex +{ +public: + int index; + char inCore; + + int operator == (const CoredPointIndex& cpi) const {return (index==cpi.index) && (inCore==cpi.inCore);}; + int operator != (const CoredPointIndex& cpi) const {return (index!=cpi.index) || (inCore!=cpi.inCore);}; +}; +class EdgeIndex{ +public: + int idx[2]; +}; +class CoredEdgeIndex +{ +public: + CoredPointIndex idx[2]; +}; +class TriangleIndex{ +public: + int idx[3]; +}; + +class TriangulationEdge +{ +public: + TriangulationEdge(void); + int pIndex[2]; + int tIndex[2]; +}; + +class TriangulationTriangle +{ +public: + TriangulationTriangle(void); + int eIndex[3]; +}; + +template +class Triangulation +{ +public: + + std::vector > points; + std::vector edges; + std::vector triangles; + + int factor( int tIndex,int& p1,int& p2,int& p3); + double area(void); + double area( int tIndex ); + double area( int p1 , int p2 , int p3 ); + int flipMinimize( int eIndex); + int addTriangle( int p1 , int p2 , int p3 ); + +protected: + std::unordered_map edgeMap; + static long long EdgeIndex( int p1 , int p2 ); + double area(const Triangle& t); +}; + + +template +void EdgeCollapse(const Real& edgeRatio,std::vector& triangles,std::vector< Point3D >& positions,std::vector >* normals); +template +void TriangleCollapse(const Real& edgeRatio,std::vector& triangles,std::vector >& positions,std::vector >* normals); + +struct CoredVertexIndex +{ + int idx; + bool inCore; +}; +template< class Vertex > +class CoredMeshData +{ +public: + std::vector< Vertex > inCorePoints; + virtual void resetIterator( void ) = 0; + + virtual int addOutOfCorePoint( const Vertex& p ) = 0; + virtual int addOutOfCorePoint_s( const Vertex& p ) = 0; + virtual int addPolygon_s( const std::vector< CoredVertexIndex >& vertices ) = 0; + virtual int addPolygon_s( const std::vector< int >& vertices ) = 0; + + virtual int nextOutOfCorePoint( Vertex& p )=0; + virtual int nextPolygon( std::vector< CoredVertexIndex >& vertices ) = 0; + + virtual int outOfCorePointCount(void)=0; + virtual int polygonCount( void ) = 0; +}; + +template< class Vertex > +class CoredVectorMeshData : public CoredMeshData< Vertex > +{ + std::vector< Vertex > oocPoints; + std::vector< std::vector< int > > polygons; + int polygonIndex; + int oocPointIndex; +public: + CoredVectorMeshData(void); + + void resetIterator(void); + + int addOutOfCorePoint( const Vertex& p ); + int addOutOfCorePoint_s( const Vertex& p ); + int addPolygon_s( const std::vector< CoredVertexIndex >& vertices ); + int addPolygon_s( const std::vector< int >& vertices ); + + int nextOutOfCorePoint( Vertex& p ); + int nextPolygon( std::vector< CoredVertexIndex >& vertices ); + + int outOfCorePointCount(void); + int polygonCount( void ); +}; +class BufferedReadWriteFile +{ + bool tempFile; + FILE* _fp; + char *_buffer , _fileName[1024]; + size_t _bufferIndex , _bufferSize; +public: + BufferedReadWriteFile( char* fileName=NULL , int bufferSize=(1<<20) ); + ~BufferedReadWriteFile( void ); + bool write( const void* data , size_t size ); + bool read ( void* data , size_t size ); + void reset( void ); +}; +template< class Vertex > +class CoredFileMeshData : public CoredMeshData< Vertex > +{ + char pointFileName[1024] , polygonFileName[1024]; + BufferedReadWriteFile *oocPointFile , *polygonFile; + int oocPoints , polygons; +public: + CoredFileMeshData( void ); + ~CoredFileMeshData( void ); + + void resetIterator( void ); + + int addOutOfCorePoint( const Vertex& p ); + int addOutOfCorePoint_s( const Vertex& p ); + int addPolygon_s( const std::vector< CoredVertexIndex >& vertices ); + int addPolygon_s( const std::vector< int >& vertices ); + + int nextOutOfCorePoint( Vertex& p ); + int nextPolygon( std::vector< CoredVertexIndex >& vertices ); + + int outOfCorePointCount( void ); + int polygonCount( void ); +}; +#include "Geometry.inl" + +#endif // GEOMETRY_INCLUDED diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/Geometry.inl b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Geometry.inl new file mode 100644 index 000000000..b38f0e6b1 --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Geometry.inl @@ -0,0 +1,591 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +#include + +template +Real Random(void){return Real(rand())/RAND_MAX;} + +template +Point3D RandomBallPoint(void){ + Point3D p; + while(1){ + p.coords[0]=Real(1.0-2.0*Random()); + p.coords[1]=Real(1.0-2.0*Random()); + p.coords[2]=Real(1.0-2.0*Random()); + double l=SquareLength(p); + if(l<=1){return p;} + } +} +template +Point3D RandomSpherePoint(void){ + Point3D p=RandomBallPoint(); + Real l=Real(Length(p)); + p.coords[0]/=l; + p.coords[1]/=l; + p.coords[2]/=l; + return p; +} + +template +double SquareLength(const Point3D& p){return p.coords[0]*p.coords[0]+p.coords[1]*p.coords[1]+p.coords[2]*p.coords[2];} + +template +double Length(const Point3D& p){return sqrt(SquareLength(p));} + +template +double SquareDistance(const Point3D& p1,const Point3D& p2){ + return (p1.coords[0]-p2.coords[0])*(p1.coords[0]-p2.coords[0])+(p1.coords[1]-p2.coords[1])*(p1.coords[1]-p2.coords[1])+(p1.coords[2]-p2.coords[2])*(p1.coords[2]-p2.coords[2]); +} + +template +double Distance(const Point3D& p1,const Point3D& p2){return sqrt(SquareDistance(p1,p2));} + +template +void CrossProduct(const Point3D& p1,const Point3D& p2,Point3D& p){ + p.coords[0]= p1.coords[1]*p2.coords[2]-p1.coords[2]*p2.coords[1]; + p.coords[1]=-p1.coords[0]*p2.coords[2]+p1.coords[2]*p2.coords[0]; + p.coords[2]= p1.coords[0]*p2.coords[1]-p1.coords[1]*p2.coords[0]; +} +template +void EdgeCollapse(const Real& edgeRatio,std::vector& triangles,std::vector< Point3D >& positions,std::vector< Point3D >* normals){ + int i,j,*remapTable,*pointCount,idx[3]; + Point3D p[3],q[2],c; + double d[3],a; + double Ratio=12.0/sqrt(3.0); // (Sum of Squares Length / Area) for and equilateral triangle + + remapTable=new int[positions.size()]; + pointCount=new int[positions.size()]; + for(i=0;i=0;i--){ + for(j=0;j<3;j++){ + idx[j]=triangles[i].idx[j]; + while(remapTable[idx[j]] a*Ratio){ + // Find the smallest edge + j=0; + if(d[1]=0;i--){ + for(j=0;j<3;j++){ + idx[j]=triangles[i].idx[j]; + while(remapTable[idx[j]] +void TriangleCollapse(const Real& edgeRatio,std::vector& triangles,std::vector< Point3D >& positions,std::vector< Point3D >* normals){ + int i,j,*remapTable,*pointCount,idx[3]; + Point3D p[3],q[2],c; + double d[3],a; + double Ratio=12.0/sqrt(3.0); // (Sum of Squares Length / Area) for and equilateral triangle + + remapTable=new int[positions.size()]; + pointCount=new int[positions.size()]; + for(i=0;i=0;i--){ + for(j=0;j<3;j++){ + idx[j]=triangles[i].idx[j]; + while(remapTable[idx[j]] a*Ratio){ + // Find the smallest edge + j=0; + if(d[1]=0;i--){ + for(j=0;j<3;j++){ + idx[j]=triangles[i].idx[j]; + while(remapTable[idx[j]] +long long Triangulation::EdgeIndex( int p1 , int p2 ) +{ + if(p1>p2) {return ((long long)(p1)<<32) | ((long long)(p2));} + else {return ((long long)(p2)<<32) | ((long long)(p1));} +} + +template +int Triangulation::factor(int tIndex,int& p1,int& p2,int & p3){ + if(triangles[tIndex].eIndex[0]<0 || triangles[tIndex].eIndex[1]<0 || triangles[tIndex].eIndex[2]<0){return 0;} + if(edges[triangles[tIndex].eIndex[0]].tIndex[0]==tIndex){p1=edges[triangles[tIndex].eIndex[0]].pIndex[0];} + else {p1=edges[triangles[tIndex].eIndex[0]].pIndex[1];} + if(edges[triangles[tIndex].eIndex[1]].tIndex[0]==tIndex){p2=edges[triangles[tIndex].eIndex[1]].pIndex[0];} + else {p2=edges[triangles[tIndex].eIndex[1]].pIndex[1];} + if(edges[triangles[tIndex].eIndex[2]].tIndex[0]==tIndex){p3=edges[triangles[tIndex].eIndex[2]].pIndex[0];} + else {p3=edges[triangles[tIndex].eIndex[2]].pIndex[1];} + return 1; +} +template +double Triangulation::area(int p1,int p2,int p3){ + Point3D q1,q2,q; + for(int i=0;i<3;i++){ + q1.coords[i]=points[p2].coords[i]-points[p1].coords[i]; + q2.coords[i]=points[p3].coords[i]-points[p1].coords[i]; + } + CrossProduct(q1,q2,q); + return Length(q); +} +template +double Triangulation::area(int tIndex){ + int p1,p2,p3; + factor(tIndex,p1,p2,p3); + return area(p1,p2,p3); +} +template +double Triangulation::area(void){ + double a=0; + for(int i=0;i +int Triangulation::addTriangle(int p1,int p2,int p3) +{ + std::unordered_map::iterator iter; + int tIdx,eIdx,p[3]; + p[0]=p1; + p[1]=p2; + p[2]=p3; + triangles.push_back(TriangulationTriangle()); + tIdx=int(triangles.size())-1; + + for(int i=0;i<3;i++) + { + long long e = EdgeIndex(p[i],p[(i+1)%3]); + iter=edgeMap.find(e); + if(iter==edgeMap.end()) + { + TriangulationEdge edge; + edge.pIndex[0]=p[i]; + edge.pIndex[1]=p[(i+1)%3]; + edges.push_back(edge); + eIdx=int(edges.size())-1; + edgeMap[e]=eIdx; + edges[eIdx].tIndex[0]=tIdx; + } + else{ + eIdx=edgeMap[e]; + if(edges[eIdx].pIndex[0]==p[i]){ + if(edges[eIdx].tIndex[0]<0){edges[eIdx].tIndex[0]=tIdx;} + else{printf("Edge Triangle in use 1\n");return 0;} + } + else{ + if(edges[eIdx].tIndex[1]<0){edges[eIdx].tIndex[1]=tIdx;} + else{printf("Edge Triangle in use 2\n");return 0;} + } + + } + triangles[tIdx].eIndex[i]=eIdx; + } + return tIdx; +} +template +int Triangulation::flipMinimize(int eIndex){ + double oldArea,newArea; + int oldP[3],oldQ[3],newP[3],newQ[3]; + TriangulationEdge newEdge; + + if(edges[eIndex].tIndex[0]<0 || edges[eIndex].tIndex[1]<0){return 0;} + + if(!factor(edges[eIndex].tIndex[0],oldP[0],oldP[1],oldP[2])){return 0;} + if(!factor(edges[eIndex].tIndex[1],oldQ[0],oldQ[1],oldQ[2])){return 0;} + + oldArea=area(oldP[0],oldP[1],oldP[2])+area(oldQ[0],oldQ[1],oldQ[2]); + int idxP,idxQ; + for(idxP=0;idxP<3;idxP++){ + int i; + for(i=0;i<3;i++){if(oldP[idxP]==oldQ[i]){break;}} + if(i==3){break;} + } + for(idxQ=0;idxQ<3;idxQ++){ + int i; + for(i=0;i<3;i++){if(oldP[i]==oldQ[idxQ]){break;}} + if(i==3){break;} + } + if(idxP==3 || idxQ==3){return 0;} + newP[0]=oldP[idxP]; + newP[1]=oldP[(idxP+1)%3]; + newP[2]=oldQ[idxQ]; + newQ[0]=oldQ[idxQ]; + newQ[1]=oldP[(idxP+2)%3]; + newQ[2]=oldP[idxP]; + + newArea=area(newP[0],newP[1],newP[2])+area(newQ[0],newQ[1],newQ[2]); + if(oldArea<=newArea){return 0;} + + // Remove the entry in the hash_table for the old edge + edgeMap.erase(EdgeIndex(edges[eIndex].pIndex[0],edges[eIndex].pIndex[1])); + // Set the new edge so that the zero-side is newQ + edges[eIndex].pIndex[0]=newP[0]; + edges[eIndex].pIndex[1]=newQ[0]; + // Insert the entry into the hash_table for the new edge + edgeMap[EdgeIndex(newP[0],newQ[0])]=eIndex; + // Update the triangle information + for(int i=0;i<3;i++){ + int idx; + idx=edgeMap[EdgeIndex(newQ[i],newQ[(i+1)%3])]; + triangles[edges[eIndex].tIndex[0]].eIndex[i]=idx; + if(idx!=eIndex){ + if(edges[idx].tIndex[0]==edges[eIndex].tIndex[1]){edges[idx].tIndex[0]=edges[eIndex].tIndex[0];} + if(edges[idx].tIndex[1]==edges[eIndex].tIndex[1]){edges[idx].tIndex[1]=edges[eIndex].tIndex[0];} + } + + idx=edgeMap[EdgeIndex(newP[i],newP[(i+1)%3])]; + triangles[edges[eIndex].tIndex[1]].eIndex[i]=idx; + if(idx!=eIndex){ + if(edges[idx].tIndex[0]==edges[eIndex].tIndex[0]){edges[idx].tIndex[0]=edges[eIndex].tIndex[1];} + if(edges[idx].tIndex[1]==edges[eIndex].tIndex[0]){edges[idx].tIndex[1]=edges[eIndex].tIndex[1];} + } + } + return 1; +} +///////////////////////// +// CoredVectorMeshData // +///////////////////////// +template< class Vertex > +CoredVectorMeshData< Vertex >::CoredVectorMeshData( void ) { oocPointIndex = polygonIndex = 0; } +template< class Vertex > +void CoredVectorMeshData< Vertex >::resetIterator ( void ) { oocPointIndex = polygonIndex = 0; } +template< class Vertex > +int CoredVectorMeshData< Vertex >::addOutOfCorePoint( const Vertex& p ) +{ + oocPoints.push_back(p); + return int(oocPoints.size())-1; +} +template< class Vertex > +int CoredVectorMeshData< Vertex >::addOutOfCorePoint_s( const Vertex& p ) +{ + size_t sz; +#pragma omp critical (CoredVectorMeshData_addOutOfCorePoint_s ) + { + sz = oocPoints.size(); + oocPoints.push_back(p); + } + return (int)sz; +} +template< class Vertex > +int CoredVectorMeshData< Vertex >::addPolygon_s( const std::vector< int >& polygon ) +{ + size_t sz; +#pragma omp critical (CoredVectorMeshData_addPolygon_s) + { + sz = polygon.size(); + polygons.push_back( polygon ); + } + return (int)sz; +} +template< class Vertex > +int CoredVectorMeshData< Vertex >::addPolygon_s( const std::vector< CoredVertexIndex >& vertices ) +{ + std::vector< int > polygon( vertices.size() ); + for( int i=0 ; i<(int)vertices.size() ; i++ ) + if( vertices[i].inCore ) polygon[i] = vertices[i].idx; + else polygon[i] = -vertices[i].idx-1; + return addPolygon_s( polygon ); +} +template< class Vertex > +int CoredVectorMeshData< Vertex >::nextOutOfCorePoint( Vertex& p ) +{ + if( oocPointIndex +int CoredVectorMeshData< Vertex >::nextPolygon( std::vector< CoredVertexIndex >& vertices ) +{ + if( polygonIndex& polygon = polygons[ polygonIndex++ ]; + vertices.resize( polygon.size() ); + for( int i=0 ; i +int CoredVectorMeshData< Vertex >::outOfCorePointCount(void){return int(oocPoints.size());} +template< class Vertex > +int CoredVectorMeshData< Vertex >::polygonCount( void ) { return int( polygons.size() ); } + +/////////////////////// +// CoredFileMeshData // +/////////////////////// +template< class Vertex > +CoredFileMeshData< Vertex >::CoredFileMeshData( void ) +{ + oocPoints = polygons = 0; + + oocPointFile = new BufferedReadWriteFile(); + polygonFile = new BufferedReadWriteFile(); +} +template< class Vertex > +CoredFileMeshData< Vertex >::~CoredFileMeshData( void ) +{ + delete oocPointFile; + delete polygonFile; +} +template< class Vertex > +void CoredFileMeshData< Vertex >::resetIterator ( void ) +{ + oocPointFile->reset(); + polygonFile->reset(); +} +template< class Vertex > +int CoredFileMeshData< Vertex >::addOutOfCorePoint( const Vertex& p ) +{ + oocPointFile->write( &p , sizeof( Vertex ) ); + oocPoints++; + return oocPoints-1; +} +template< class Vertex > +int CoredFileMeshData< Vertex >::addOutOfCorePoint_s( const Vertex& p ) +{ + int sz; +#pragma omp critical (CoredFileMeshData_addOutOfCorePoint_s) + { + sz = oocPoints; + oocPointFile->write( &p , sizeof( Vertex ) ); + oocPoints++; + } + return sz; +} +template< class Vertex > +int CoredFileMeshData< Vertex >::addPolygon_s( const std::vector< int >& vertices ) +{ + int sz , vSize = (int)vertices.size(); +#pragma omp critical (CoredFileMeshData_addPolygon_s ) + { + sz = polygons; + polygonFile->write( &vSize , sizeof(int) ); + polygonFile->write( &vertices[0] , sizeof(int) * vSize ); + polygons++; + } + return sz; +} +template< class Vertex > +int CoredFileMeshData< Vertex >::addPolygon_s( const std::vector< CoredVertexIndex >& vertices ) +{ + std::vector< int > polygon( vertices.size() ); + for( int i=0 ; i<(int)vertices.size() ; i++ ) + if( vertices[i].inCore ) polygon[i] = vertices[i].idx; + else polygon[i] = -vertices[i].idx-1; + return addPolygon_s( polygon ); +} +template< class Vertex > +int CoredFileMeshData< Vertex >::nextOutOfCorePoint( Vertex& p ) +{ + if( oocPointFile->read( &p , sizeof( Vertex ) ) ) return 1; + else return 0; +} +template< class Vertex > +int CoredFileMeshData< Vertex >::nextPolygon( std::vector< CoredVertexIndex >& vertices ) +{ + int pSize; + if( polygonFile->read( &pSize , sizeof(int) ) ) + { + std::vector< int > polygon( pSize ); + if( polygonFile->read( &polygon[0] , sizeof(int)*pSize ) ) + { + vertices.resize( pSize ); + for( int i=0 ; i +int CoredFileMeshData< Vertex >::outOfCorePointCount( void ){ return oocPoints; } +template< class Vertex > +int CoredFileMeshData< Vertex >::polygonCount( void ) { return polygons; } diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/Hash.h b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Hash.h new file mode 100644 index 000000000..b66c07362 --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Hash.h @@ -0,0 +1,29 @@ +#ifndef HASH_INCLUDED +#define HASH_INCLUDED +#ifdef WIN32 +#include +using stdext::hash_map; +#else // !WIN32 +#include +using namespace __gnu_cxx; + +namespace __gnu_cxx +{ + template<> struct hash { + size_t operator()(long long __x) const { return __x; } + }; + template<> struct hash { + size_t operator()(const long long __x) const { return __x; } + }; + + + template<> struct hash { + size_t operator()(unsigned long long __x) const { return __x; } + }; + template<> struct hash { + size_t operator()(const unsigned long long __x) const { return __x; } + }; +} +#endif // WIN32 +#endif // HASH_INCLUDED + diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/MAT.h b/src/plugins_unsupported/filter_screened_poisson_xml/Src/MAT.h new file mode 100644 index 000000000..c090450d6 --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/MAT.h @@ -0,0 +1,48 @@ +/* +Copyright (c) 2007, Michael Kazhdan +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ +#ifndef MAT_INCLUDED +#define MAT_INCLUDED +#include "Geometry.h" + +template +class MinimalAreaTriangulation +{ + Real* bestTriangulation; + int* midPoint; + Real GetArea(const size_t& i,const size_t& j,const std::vector >& vertices); + void GetTriangulation(const size_t& i,const size_t& j,const std::vector >& vertices,std::vector& triangles); +public: + MinimalAreaTriangulation(void); + ~MinimalAreaTriangulation(void); + Real GetArea(const std::vector >& vertices); + void GetTriangulation(const std::vector >& vertices,std::vector& triangles); +}; + +#include "MAT.inl" + +#endif // MAT_INCLUDED diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/MAT.inl b/src/plugins_unsupported/filter_screened_poisson_xml/Src/MAT.inl new file mode 100644 index 000000000..5106659fd --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/MAT.inl @@ -0,0 +1,217 @@ +/* +Copyright (c) 2007, Michael Kazhdan +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ +////////////////////////////// +// MinimalAreaTriangulation // +////////////////////////////// +template +MinimalAreaTriangulation::MinimalAreaTriangulation(void) +{ + bestTriangulation=NULL; + midPoint=NULL; +} +template +MinimalAreaTriangulation::~MinimalAreaTriangulation(void) +{ + if(bestTriangulation) + delete[] bestTriangulation; + bestTriangulation=NULL; + if(midPoint) + delete[] midPoint; + midPoint=NULL; +} +template +void MinimalAreaTriangulation::GetTriangulation(const std::vector >& vertices,std::vector& triangles) +{ + if(vertices.size()==3) + { + triangles.resize(1); + triangles[0].idx[0]=0; + triangles[0].idx[1]=1; + triangles[0].idx[2]=2; + return; + } + else if(vertices.size()==4) + { + TriangleIndex tIndex[2][2]; + Real area[2]; + + area[0]=area[1]=0; + triangles.resize(2); + + tIndex[0][0].idx[0]=0; + tIndex[0][0].idx[1]=1; + tIndex[0][0].idx[2]=2; + tIndex[0][1].idx[0]=2; + tIndex[0][1].idx[1]=3; + tIndex[0][1].idx[2]=0; + + tIndex[1][0].idx[0]=0; + tIndex[1][0].idx[1]=1; + tIndex[1][0].idx[2]=3; + tIndex[1][1].idx[0]=3; + tIndex[1][1].idx[1]=1; + tIndex[1][1].idx[2]=2; + + Point3D n,p1,p2; + for(int i=0;i<2;i++) + for(int j=0;j<2;j++) + { + p1=vertices[tIndex[i][j].idx[1]]-vertices[tIndex[i][j].idx[0]]; + p2=vertices[tIndex[i][j].idx[2]]-vertices[tIndex[i][j].idx[0]]; + CrossProduct(p1,p2,n); + area[i] += Real( Length(n) ); + } + if(area[0]>area[1]) + { + triangles[0]=tIndex[1][0]; + triangles[1]=tIndex[1][1]; + } + else + { + triangles[0]=tIndex[0][0]; + triangles[1]=tIndex[0][1]; + } + return; + } + if(bestTriangulation) + delete[] bestTriangulation; + if(midPoint) + delete[] midPoint; + bestTriangulation=NULL; + midPoint=NULL; + size_t eCount=vertices.size(); + bestTriangulation=new Real[eCount*eCount]; + midPoint=new int[eCount*eCount]; + for(size_t i=0;i +Real MinimalAreaTriangulation::GetArea(const std::vector >& vertices) +{ + if(bestTriangulation) + delete[] bestTriangulation; + if(midPoint) + delete[] midPoint; + bestTriangulation=NULL; + midPoint=NULL; + int eCount=vertices.size(); + bestTriangulation=new double[eCount*eCount]; + midPoint=new int[eCount*eCount]; + for(int i=0;i +void MinimalAreaTriangulation::GetTriangulation(const size_t& i,const size_t& j,const std::vector >& vertices,std::vector& triangles) +{ + TriangleIndex tIndex; + size_t eCount=vertices.size(); +#ifdef BRUNO_LEVY_FIX + int ii=(int)i; + if( i=ii ) + return; + ii=midPoint[i*eCount+j]; + if( ii>=0 ) + { + tIndex.idx[0] = int( i ); + tIndex.idx[1] = int( j ); + tIndex.idx[2] = int( ii ); + triangles.push_back(tIndex); + GetTriangulation(i,ii,vertices,triangles); + GetTriangulation(ii,j,vertices,triangles); + } +} + +template +Real MinimalAreaTriangulation::GetArea(const size_t& i,const size_t& j,const std::vector >& vertices) +{ + Real a=FLT_MAX,temp; + size_t eCount=vertices.size(); + size_t idx=i*eCount+j; + size_t ii=i; + if(i=ii) + { + bestTriangulation[idx]=0; + return 0; + } + if(midPoint[idx]!=-1) + return bestTriangulation[idx]; + int mid=-1; + for(size_t r=j+1;r p,p1,p2; + p1=vertices[i]-vertices[rr]; + p2=vertices[j]-vertices[rr]; + CrossProduct(p1,p2,p); + temp = Real( Length(p) ); + if(bestTriangulation[idx1]>=0) + { + temp+=bestTriangulation[idx1]; + if(temp>a) + continue; + if(bestTriangulation[idx2]>0) + temp+=bestTriangulation[idx2]; + else + temp+=GetArea(rr,j,vertices); + } + else + { + if(bestTriangulation[idx2]>=0) + temp+=bestTriangulation[idx2]; + else + temp+=GetArea(rr,j,vertices); + if(temp>a) + continue; + temp+=GetArea(i,rr,vertices); + } + + if(temp +#include "MarchingCubes.h" + +//////////// +// Square // +//////////// +int Square::AntipodalCornerIndex(int idx){ + int x,y; + FactorCornerIndex(idx,x,y); + return CornerIndex( (x+1)%2 , (y+1)%2 ); +} +int Square::CornerIndex( int x , int y ){ return (y<<1)|x; } +void Square::FactorCornerIndex( int idx , int& x , int& y ){ x=(idx>>0)&1 , y=(idx>>1)&1; } +int Square::EdgeIndex( int orientation , int i ) +{ + switch( orientation ) + { + case 0: // x + if( !i ) return 0; // (0,0) -> (1,0) + else return 2; // (0,1) -> (1,1) + case 1: // y + if( !i ) return 3; // (0,0) -> (0,1) + else return 1; // (1,0) -> (1,1) + }; + return -1; +} +void Square::FactorEdgeIndex(int idx,int& orientation,int& i){ + switch(idx){ + case 0: case 2: + orientation=0; + i=idx/2; + return; + case 1: case 3: + orientation=1; + i=((idx/2)+1)%2; + return; + }; +} +void Square::EdgeCorners(int idx,int& c1,int& c2){ + int orientation,i; + FactorEdgeIndex(idx,orientation,i); + switch(orientation){ + case 0: + c1 = CornerIndex(0,i); + c2 = CornerIndex(1,i); + break; + case 1: + c1 = CornerIndex(i,0); + c2 = CornerIndex(i,1); + break; + }; +} +int Square::ReflectEdgeIndex(int idx,int edgeIndex){ + int orientation=edgeIndex%2; + int o,i; + FactorEdgeIndex(idx,o,i); + if(o!=orientation){return idx;} + else{return EdgeIndex(o,(i+1)%2);} +} +int Square::ReflectCornerIndex(int idx,int edgeIndex){ + int orientation=edgeIndex%2; + int x,y; + FactorCornerIndex(idx,x,y); + switch(orientation){ + case 0: return CornerIndex((x+1)%2,y); + case 1: return CornerIndex(x,(y+1)%2); + }; + return -1; +} + + + +////////// +// Cube // +////////// +int Cube::CornerIndex( int x , int y , int z ){ return (z<<2)|(y<<1)|x; } +void Cube::FactorCornerIndex( int idx , int& x , int& y , int& z ){ x = (idx>>0)&1 , y = (idx>>1)&1 , z = (idx>>2)&1; } +int Cube::EdgeIndex(int orientation,int i,int j){return (i | (j<<1))|(orientation<<2);} +void Cube::FactorEdgeIndex( int idx , int& orientation , int& i , int &j ) +{ + orientation=idx>>2; + i = (idx&1); + j = (idx&2)>>1; +} +int Cube::FaceIndex( int x , int y , int z ) +{ + if ( x<0 ) return 0; + else if( x>0 ) return 1; + else if( y<0 ) return 2; + else if( y>0 ) return 3; + else if( z<0 ) return 4; + else if( z>0 ) return 5; + else return -1; +} +int Cube::FaceIndex( int dir , int offSet ){ return (dir<<1)|offSet; } + +void Cube::FactorFaceIndex( int idx , int& x , int& y , int& z ) +{ + x=y=z=0; + switch( idx ) + { + case 0: x=-1; break; + case 1: x= 1; break; + case 2: y=-1; break; + case 3: y= 1; break; + case 4: z=-1; break; + case 5: z= 1; break; + }; +} +void Cube::FactorFaceIndex( int idx , int& dir , int& offSet ) +{ + dir = idx>>1; + offSet=idx &1; +} +bool Cube::IsEdgeCorner( int cIndex , int e ) +{ + int o , i , j; + FactorEdgeIndex( e , o , i , j ); + switch( o ) + { + case 0: return (cIndex & 2)==(i<<1) && (cIndex & 4)==(j<<2); + case 1: return (cIndex & 1)==(i<<0) && (cIndex & 4)==(j<<2); + case 2: return (cIndex & 4)==(i<<2) && (cIndex & 2)==(j<<1); + default: return false; + } +} +bool Cube::IsFaceCorner( int cIndex , int f ) +{ + int dir , off; + FactorFaceIndex( f , dir , off ); + return ( cIndex & (1< (1,0) +1} // (1,0) -> (1,1) +2} // (0,1) -> (1,1) +3} // (0,0) -> (0,1) +*/ +const int MarchingSquares::edgeMask[1< -> -> + 9, // 1 -> 0 -> (0,0) -> 0,3 -> 9 + 3, // 2 -> 1 -> (1,0) -> 0,1 -> 3 + 10, // 3 -> 0,1 -> (0,0) (1,0) -> 1,3 -> 10 + 12, // 4 -> 2 -> (0,1) -> 2,3 -> 12 + 5, // 5 -> 0,2 -> (0,0) (0,1) -> 0,2 -> 5 + 15, // 6 -> 1,2 -> (1,0) (0,1) -> 0,1,2,3 -> 15 + 6, // 7 -> 0,1,2 -> (0,0) (1,0) (0,1) -> 1,2 -> 6 + 6, // 8 -> 3 -> (1,1) -> 1,2 -> 6 + 15, // 9 -> 0,3 -> (0,0) (1,1) -> 0,1,2,3 -> 15 + 5, // 10 -> 1,3 -> (1,0) (1,1) -> 0,2 -> 5 + 12, // 11 -> 0,1,3 -> (0,0) (1,0) (1,1) -> 2,3 -> 12 + 10, // 12 -> 2,3 -> (0,1) (1,1) -> 1,3 -> 10 + 3, // 13 -> 0,2,3 -> (0,0) (0,1) (1,1) -> 0,1 -> 3 + 9, // 14 -> 1,2,3 -> (1,0) (0,1) (1,1) -> 0,3 -> 9 + 0, // 15 -> 0,1,2,3 -> (0,0) (1,0) (0,1) (1,1) -> +}; +#if NEW_ORDERING +/* +0} // (0,0) -> (1,0) +1} // (1,0) -> (1,1) +2} // (0,1) -> (1,1) +3} // (0,0) -> (0,1) +*/ +const int MarchingSquares::edges[1<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(1,i,j)];}}} + else if (y<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,0,j)];}}} + else if (y>0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,1,j)];}}} + else if (z<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,j,0)];}}} + else if (z>0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,j,1)];}}} + if (v[0][0] < iso) idx |= 1; + if (v[1][0] < iso) idx |= 2; + if (v[1][1] < iso) idx |= 4; + if (v[0][1] < iso) idx |= 8; + return idx; +} +bool MarchingCubes::IsAmbiguous( const double v[Cube::CORNERS] , double isoValue , int faceIndex ){ return MarchingSquares::IsAmbiguous( GetFaceIndex( v , isoValue , faceIndex ) ); } +bool MarchingCubes::HasRoots( const double v[Cube::CORNERS] , double isoValue , int faceIndex ){ return MarchingSquares::HasRoots( GetFaceIndex( v , isoValue , faceIndex ) ); } +bool MarchingCubes::HasRoots( const double v[Cube::CORNERS] , double isoValue ){ return HasRoots( GetIndex( v , isoValue ) ); } +bool MarchingCubes::HasRoots( unsigned char mcIndex ){ return !(mcIndex==0 || mcIndex==255); } +int MarchingCubes::AddTriangles( const double v[Cube::CORNERS] , double iso , Triangle* isoTriangles ) +{ + unsigned char idx; + int ntriang=0; + Triangle tri; + + idx=GetIndex(v,iso); + + /* Cube is entirely in/out of the surface */ + if (!edgeMask[idx]) return 0; + + /* Find the vertices where the surface intersects the cube */ + int i,j,ii=1; + for(i=0;i<12;i++){ + if(edgeMask[idx] & ii){SetVertex(i,v,iso);} + ii<<=1; + } + /* Create the triangle */ + for( i=0 ; triangles[idx][i]!=-1 ; i+=3 ) + { + for(j=0;j<3;j++){ + tri.p[0][j]=vertexList[triangles[idx][i+0]][j]; + tri.p[1][j]=vertexList[triangles[idx][i+1]][j]; + tri.p[2][j]=vertexList[triangles[idx][i+2]][j]; + } + isoTriangles[ntriang++]=tri; + } + return ntriang; +} + +int MarchingCubes::AddTriangleIndices(const double v[Cube::CORNERS],double iso,int* isoIndices){ + unsigned char idx; + int ntriang=0; + + idx=GetIndex(v,iso); + + /* Cube is entirely in/out of the surface */ + if (!edgeMask[idx]) return 0; + + /* Create the triangle */ + for(int i=0;triangles[idx][i]!=-1;i+=3){ + for(int j=0;j<3;j++){isoIndices[i+j]=triangles[idx][i+j];} + ntriang++; + } + return ntriang; +} + +void MarchingCubes::SetVertex( int e , const double values[Cube::CORNERS] , double iso ) +{ + double t; + int o , i1 , i2; + Cube::FactorEdgeIndex( e , o , i1 , i2 ); + switch( o ) + { + case 0: + t = Interpolate( values[ Cube::CornerIndex( 0 , i1 , i2 ) ] - iso , values[ Cube::CornerIndex( 1 , i1 , i2 ) ] - iso ); + vertexList[e][0] = t , vertexList[e][1] = i1 , vertexList[e][2] = i2; + break; + case 1: + t = Interpolate( values[ Cube::CornerIndex( i1 , 0 , i2 ) ] - iso , values[ Cube::CornerIndex( i1 , 1 , i2 ) ] - iso ); + vertexList[e][0] = i1 , vertexList[e][1] = t , vertexList[e][2] = i2; + break; + case 2: + t = Interpolate( values[ Cube::CornerIndex( i1 , i2 , 0 ) ] - iso , values[ Cube::CornerIndex( i1 , i2 , 1 ) ] - iso ); + vertexList[e][0] = i1 , vertexList[e][1] = i2 , vertexList[e][2] = t; + break; + } +} +double MarchingCubes::Interpolate( double v1 , double v2 ) { return v1/(v1-v2); } + + +/////////////////////////////////// +unsigned char MarchingCubes::GetIndex(const float v[Cube::CORNERS],float iso){ + unsigned char idx=0; + if (v[Cube::CornerIndex(0,0,0)] < iso) idx |= 1; + if (v[Cube::CornerIndex(1,0,0)] < iso) idx |= 2; + if (v[Cube::CornerIndex(1,1,0)] < iso) idx |= 4; + if (v[Cube::CornerIndex(0,1,0)] < iso) idx |= 8; + if (v[Cube::CornerIndex(0,0,1)] < iso) idx |= 16; + if (v[Cube::CornerIndex(1,0,1)] < iso) idx |= 32; + if (v[Cube::CornerIndex(1,1,1)] < iso) idx |= 64; + if (v[Cube::CornerIndex(0,1,1)] < iso) idx |= 128; + return idx; +} +unsigned char MarchingCubes::GetFaceIndex( const float values[Cube::CORNERS] , float iso , int faceIndex ) +{ + int i,j,x,y,z; + unsigned char idx=0; + double v[2][2]; + Cube::FactorFaceIndex(faceIndex,x,y,z); + if (x<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(0,i,j)];}}} + else if (x>0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(1,i,j)];}}} + else if (y<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,0,j)];}}} + else if (y>0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,1,j)];}}} + else if (z<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,j,0)];}}} + else if (z>0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,j,1)];}}} + if (v[0][0] < iso) idx |= 1; + if (v[1][0] < iso) idx |= 2; + if (v[1][1] < iso) idx |= 4; + if (v[0][1] < iso) idx |= 8; + return idx; +} +unsigned char MarchingCubes::GetFaceIndex( unsigned char mcIndex , int faceIndex ) +{ + int i,j,x,y,z; + unsigned char idx=0; + int v[2][2]; + Cube::FactorFaceIndex(faceIndex,x,y,z); + if (x<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=mcIndex&(1<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=mcIndex&(1<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=mcIndex&(1<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=mcIndex&(1< +#include "Geometry.h" + +#define NEW_ORDERING 1 + +class Square +{ +public: + const static unsigned int CORNERS=4 , EDGES=4 , FACES=1; + static int CornerIndex (int x,int y); + static int AntipodalCornerIndex(int idx); + static void FactorCornerIndex (int idx,int& x,int& y); + static int EdgeIndex (int orientation,int i); + static void FactorEdgeIndex (int idx,int& orientation,int& i); + + static int ReflectCornerIndex (int idx,int edgeIndex); + static int ReflectEdgeIndex (int idx,int edgeIndex); + + static void EdgeCorners(int idx,int& c1,int &c2); +}; + +class Cube{ +public: + const static unsigned int CORNERS=8 , EDGES=12 , FACES=6; + + static int CornerIndex ( int x , int y , int z ); + static void FactorCornerIndex ( int idx , int& x , int& y , int& z ); + static int EdgeIndex ( int orientation , int i , int j ); + static void FactorEdgeIndex ( int idx , int& orientation , int& i , int &j); + static int FaceIndex ( int dir , int offSet ); + static int FaceIndex ( int x , int y , int z ); + static void FactorFaceIndex ( int idx , int& x , int &y , int& z ); + static void FactorFaceIndex ( int idx , int& dir , int& offSet ); + + static int AntipodalCornerIndex ( int idx ); + static int FaceReflectCornerIndex ( int idx , int faceIndex ); + static int FaceReflectEdgeIndex ( int idx , int faceIndex ); + static int FaceReflectFaceIndex ( int idx , int faceIndex ); + static int EdgeReflectCornerIndex ( int idx , int edgeIndex ); + static int EdgeReflectEdgeIndex ( int edgeIndex ); + + static int FaceAdjacentToEdges ( int eIndex1 , int eIndex2 ); + static void FacesAdjacentToEdge ( int eIndex , int& f1Index , int& f2Index ); + + static void EdgeCorners( int idx , int& c1 , int &c2 ); + static void FaceCorners( int idx , int& c1 , int &c2 , int& c3 , int& c4 ); + + static bool IsEdgeCorner( int cIndex , int e ); + static bool IsFaceCorner( int cIndex , int f ); +}; + +class MarchingSquares +{ + static double Interpolate(double v1,double v2); + static void SetVertex(int e,const double values[Square::CORNERS],double iso); +public: + const static unsigned int MAX_EDGES=2; + static const int edgeMask[1< +struct MemoryInfo +{ + static size_t Usage( void ) + { + HANDLE h = GetCurrentProcess(); + PROCESS_MEMORY_COUNTERS pmc; + return GetProcessMemoryInfo( h , &pmc , sizeof(pmc) ) ? pmc.WorkingSetSize : 0; + } +}; + +#else // !_WIN32 && !_WIN64 + +#ifndef __APPLE__ // Linux variants + +#include +#include + +class MemoryInfo +{ + public: + static size_t Usage(void) + { + FILE* f = fopen("/proc/self/stat","rb"); + + int d; + long ld; + unsigned long lu; + unsigned long long llu; + char s[1024]; + char c; + + int pid; + unsigned long vm; + + int n = fscanf(f, "%d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %d %ld %llu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu" + ,&pid ,s ,&c ,&d ,&d ,&d ,&d ,&d ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&ld ,&ld ,&ld ,&ld ,&d ,&ld ,&llu ,&vm ,&ld ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&d ,&d ,&lu ,&lu ); + + fclose(f); +/* +pid %d +comm %s +state %c +ppid %d +pgrp %d +session %d +tty_nr %d +tpgid %d +flags %lu +minflt %lu +cminflt %lu +majflt %lu +cmajflt %lu +utime %lu +stime %lu +cutime %ld +cstime %ld +priority %ld +nice %ld +0 %ld +itrealvalue %ld +starttime %lu +vsize %lu +rss %ld +rlim %lu +startcode %lu +endcode %lu +startstack %lu +kstkesp %lu +kstkeip %lu +signal %lu +blocked %lu +sigignore %lu +sigcatch %lu +wchan %lu +nswap %lu +cnswap %lu +exit_signal %d +processor %d +rt_priority %lu (since kernel 2.5.19) +policy %lu (since kernel 2.5.19) +*/ + return vm; + } + +}; +#else // __APPLE__: has no "/proc" pseudo-file system + +// Thanks to David O'Gwynn for providing this fix. +// This comes from a post by Michael Knight: +// +// http://miknight.blogspot.com/2005/11/resident-set-size-in-mac-os-x.html + +#include +#include +#include +#include +#include +#include +#include + +void getres(task_t task, unsigned long *rss, unsigned long *vs) +{ + struct task_basic_info t_info; + mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; + + task_info(task, TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count); + *rss = t_info.resident_size; + *vs = t_info.virtual_size; +} + +class MemoryInfo +{ + public: + static size_t Usage(void) + { + unsigned long rss, vs, psize; + task_t task = MACH_PORT_NULL; + + if (task_for_pid(current_task(), getpid(), &task) != KERN_SUCCESS) + abort(); + getres(task, &rss, &vs); + return rss; + } + +}; + +#endif // !__APPLE__ + +#endif // _WIN32 || _WIN64 + +#endif // MEMORY_USAGE_INCLUDE diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.Evaluation.inl b/src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.Evaluation.inl new file mode 100644 index 000000000..c965effbe --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.Evaluation.inl @@ -0,0 +1,1151 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +template< class Real > +template< int FEMDegree , BoundaryType BType> +void Octree< Real >::_Evaluator< FEMDegree , BType >::set( LocalDepth depth ) +{ + static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + static const int RightPointSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; + + BSplineEvaluationData< FEMDegree , BType >::SetEvaluator( evaluator , depth ); + if( depth>0 ) BSplineEvaluationData< FEMDegree , BType >::SetChildEvaluator( childEvaluator , depth-1 ); + int center = ( 1<>1; + + // First set the stencils for the current depth + for( int x=-LeftPointSupportRadius ; x<=RightPointSupportRadius ; x++ ) for( int y=-LeftPointSupportRadius ; y<=RightPointSupportRadius ; y++ ) for( int z=-LeftPointSupportRadius ; z<=RightPointSupportRadius ; z++ ) + { + int fIdx[] = { center+x , center+y , center+z }; + + // The cell stencil + { + double vv[3] , dv[3]; + for( int dd=0 ; dd( dv[0] * vv[1] * vv[2] , vv[0] * dv[1] * vv[2] , vv[0] * vv[1] * dv[2] ); + } + + //// The face stencil + for( int f=0 ; f( dv[0] * vv[1] * vv[2] , vv[0] * dv[1] * vv[2] , vv[0] * vv[1] * dv[2] ); + } + + //// The edge stencil + for( int e=0 ; e( dv[0] * vv[1] * vv[2] , vv[0] * dv[1] * vv[2] , vv[0] * vv[1] * dv[2] ); + } + + //// The corner stencil + for( int c=0 ; c( dv[0] * vv[1] * vv[2] , vv[0] * dv[1] * vv[2] , vv[0] * vv[1] * dv[2] ); + } + } + + // Now set the stencils for the parents + for( int child=0 ; child( dv[0] * vv[1] * vv[2] , vv[0] * dv[1] * vv[2] , vv[0] * vv[1] * dv[2] ); + } + + //// The face stencil + for( int f=0 ; f( dv[0] * vv[1] * vv[2] , vv[0] * dv[1] * vv[2] , vv[0] * vv[1] * dv[2] ); + } + + //// The edge stencil + for( int e=0 ; e( dv[0] * vv[1] * vv[2] , vv[0] * dv[1] * vv[2] , vv[0] * vv[1] * dv[2] ); + } + + //// The corner stencil + for( int c=0 ; c( dv[0] * vv[1] * vv[2] , vv[0] * dv[1] * vv[2] , vv[0] * vv[1] * dv[2] ); + } + } + } + if( _bsData ) delete _bsData; + _bsData = new BSplineData< FEMDegree , BType >( depth ); +} +template< class Real > +template< class V , int FEMDegree , BoundaryType BType > +V Octree< Real >::_getValue( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , Point3D< Real > p , const DenseNodeData< V , FEMDegree >& solution , const DenseNodeData< V , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator ) const +{ + static const int SupportSize = BSplineSupportSizes< FEMDegree >::SupportSize; + static const int LeftSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; + static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + static const int RightPointSupportRadius = - BSplineSupportSizes< FEMDegree >::SupportStart; + + if( IsActiveNode( node->children ) ) fprintf( stderr , "[WARNING] getValue assumes leaf node\n" ); + V value(0); + + while( GetGhostFlag( node ) ) + { + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); + + for( int i=0 ; i _s ; Real _w; + _startAndWidth( _n , _s , _w ); + int _fIdx[3]; + functionIndex< FEMDegree , BType >( _n , _fIdx ); + for( int dd=0 ; dd<3 ; dd++ ) _pIdx[dd] = std::max< int >( 0 , std::min< int >( SupportSize-1 , LeftSupportRadius + (int)floor( ( p[dd]-_s[dd] ) / _w ) ) ); + value += + solution[ _n->nodeData.nodeIndex ] * + (Real) + ( + evaluator._bsData->baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * + evaluator._bsData->baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * + evaluator._bsData->baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) + ); + } + } + node = node->parent; + } + + LocalDepth d = _localDepth( node ); + + for( int dd=0 ; dd<3 ; dd++ ) + if ( p[dd]==0 ) p[dd] = (Real)(0.+1e-6); + else if( p[dd]==1 ) p[dd] = (Real)(1.-1e-6); + + { + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); + + for( int i=0 ; i _s ; Real _w; + _startAndWidth( _n , _s , _w ); + int _fIdx[3]; + functionIndex< FEMDegree , BType >( _n , _fIdx ); + for( int dd=0 ; dd<3 ; dd++ ) _pIdx[dd] = std::max< int >( 0 , std::min< int >( SupportSize-1 , LeftSupportRadius + (int)floor( ( p[dd]-_s[dd] ) / _w ) ) ); + value += + solution[ _n->nodeData.nodeIndex ] * + (Real) + ( + evaluator._bsData->baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * + evaluator._bsData->baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * + evaluator._bsData->baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) + ); + } + } + if( d>0 ) + { + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node->parent ); + for( int i=0 ; i _s ; Real _w; + _startAndWidth( _n , _s , _w ); + int _fIdx[3]; + functionIndex< FEMDegree , BType >( _n , _fIdx ); + for( int dd=0 ; dd<3 ; dd++ ) _pIdx[dd] = std::max< int >( 0 , std::min< int >( SupportSize-1 , LeftSupportRadius + (int)floor( ( p[dd]-_s[dd] ) / _w ) ) ); + value += + coarseSolution[ _n->nodeData.nodeIndex ] * + (Real) + ( + evaluator._bsData->baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * + evaluator._bsData->baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * + evaluator._bsData->baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) + ); + } + } + } + } + return value; +} +template< class Real > +template< int FEMDegree , BoundaryType BType > +std::pair< Real , Point3D< Real > > Octree< Real >::_getValueAndGradient( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , Point3D< Real > p , const DenseNodeData< Real , FEMDegree >& solution , const DenseNodeData< Real , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator ) const +{ + static const int SupportSize = BSplineSupportSizes< FEMDegree >::SupportSize; + static const int LeftSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; + static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + static const int RightPointSupportRadius = - BSplineSupportSizes< FEMDegree >::SupportStart; + + if( IsActiveNode( node->children ) ) fprintf( stderr , "[WARNING] _getValueAndGradient assumes leaf node\n" ); + Real value(0); + Point3D< Real > gradient; + + while( GetGhostFlag( node ) ) + { + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); + + for( int i=0 ; i _s; Real _w; + _startAndWidth( _n , _s , _w ); + int _fIdx[3]; + functionIndex< FEMDegree , BType >( _n , _fIdx ); + for( int dd=0 ; dd<3 ; dd++ ) _pIdx[dd] = std::max< int >( 0 , std::min< int >( SupportSize-1 , LeftSupportRadius + (int)floor( ( p[dd]-_s[dd] ) / _w ) ) ); + value += + solution[ _n->nodeData.nodeIndex ] * + (Real) + ( + evaluator._bsData->baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData->baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData->baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) + ); + gradient += + Point3D< Real > + ( + evaluator._bsData->dBaseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData-> baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData-> baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) , + evaluator._bsData-> baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData->dBaseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData-> baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) , + evaluator._bsData-> baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData-> baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData->dBaseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) + ) * solution[ _n->nodeData.nodeIndex ]; + } + } + node = node->parent; + } + + + LocalDepth d = _localDepth( node ); + + for( int dd=0 ; dd<3 ; dd++ ) + if ( p[dd]==0 ) p[dd] = (Real)(0.+1e-6); + else if( p[dd]==1 ) p[dd] = (Real)(1.-1e-6); + + { + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); + + for( int i=0 ; i _s ; Real _w; + _startAndWidth( _n , _s , _w ); + int _fIdx[3]; + functionIndex< FEMDegree , BType >( _n , _fIdx ); + for( int dd=0 ; dd<3 ; dd++ ) _pIdx[dd] = std::max< int >( 0 , std::min< int >( SupportSize-1 , LeftSupportRadius + (int)floor( ( p[dd]-_s[dd] ) / _w ) ) ); + value += + solution[ _n->nodeData.nodeIndex ] * + (Real) + ( + evaluator._bsData->baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData->baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData->baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) + ); + gradient += + Point3D< Real > + ( + evaluator._bsData->dBaseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData-> baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData-> baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) , + evaluator._bsData-> baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData->dBaseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData-> baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) , + evaluator._bsData-> baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData-> baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData->dBaseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) + ) * solution[ _n->nodeData.nodeIndex ]; + } + } + if( d>0 ) + { + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node->parent ); + for( int i=0 ; i _s ; Real _w; + _startAndWidth( _n , _s , _w ); + int _fIdx[3]; + functionIndex< FEMDegree , BType >( _n , _fIdx ); + for( int dd=0 ; dd<3 ; dd++ ) _pIdx[dd] = std::max< int >( 0 , std::min< int >( SupportSize-1 , LeftSupportRadius + (int)floor( ( p[dd]-_s[dd] ) / _w ) ) ); + value += + coarseSolution[ _n->nodeData.nodeIndex ] * + (Real) + ( + evaluator._bsData->baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData->baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData->baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) + ); + gradient += + Point3D< Real > + ( + evaluator._bsData->dBaseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData-> baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData-> baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) , + evaluator._bsData-> baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData->dBaseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData-> baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) , + evaluator._bsData-> baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData-> baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData->dBaseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) + ) * coarseSolution[ _n->nodeData.nodeIndex ]; + } + } + } + } + return std::pair< Real , Point3D< Real > >( value , gradient ); +} +template< class Real > +template< class V , int FEMDegree , BoundaryType BType > +V Octree< Real >::_getCenterValue( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , const DenseNodeData< V , FEMDegree >& solution , const DenseNodeData< V , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator , bool isInterior ) const +{ + static const int SupportSize = BSplineEvaluationData< FEMDegree , BType >::SupportSize; + static const int LeftPointSupportRadius = BSplineEvaluationData< FEMDegree , BType >::SupportEnd; + static const int RightPointSupportRadius = - BSplineEvaluationData< FEMDegree , BType >::SupportStart; + + if( IsActiveNode( node->children ) ) fprintf( stderr , "[WARNING] getCenterValue assumes leaf node\n" ); + V value(0); + LocalDepth d = _localDepth( node ); + + if( isInterior ) + { + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); + for( int i=0 ; inodeData.nodeIndex ] * Real( evaluator.cellStencil( i , j , k ) ); + } + if( d>0 ) + { + int _corner = int( node - node->parent->children ); + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node->parent ); + for( int i=0 ; inodeData.nodeIndex] * Real( evaluator.cellStencils[_corner]( i , j , k ) ); + } + } + } + else + { + LocalOffset cIdx; + _localDepthAndOffset( node , d , cIdx ); + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); + + for( int i=0 ; inodeData.nodeIndex ] * + Real( + evaluator.evaluator.centerValue( fIdx[0] , cIdx[0] , false ) * + evaluator.evaluator.centerValue( fIdx[1] , cIdx[1] , false ) * + evaluator.evaluator.centerValue( fIdx[2] , cIdx[2] , false ) + ); + } + } + if( d>0 ) + { + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node->parent ); + for( int i=0 ; inodeData.nodeIndex ] * + Real( + evaluator.childEvaluator.centerValue( fIdx[0] , cIdx[0] , false ) * + evaluator.childEvaluator.centerValue( fIdx[1] , cIdx[1] , false ) * + evaluator.childEvaluator.centerValue( fIdx[2] , cIdx[2] , false ) + ); + } + } + } + } + return value; +} +template< class Real > +template< int FEMDegree , BoundaryType BType > +std::pair< Real , Point3D< Real > > Octree< Real >::_getCenterValueAndGradient( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , const DenseNodeData< Real , FEMDegree >& solution , const DenseNodeData< Real , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator , bool isInterior ) const +{ + static const int SupportSize = BSplineEvaluationData< FEMDegree , BType >::SupportSize; + static const int LeftPointSupportRadius = BSplineEvaluationData< FEMDegree , BType >::SupportEnd; + static const int RightPointSupportRadius = - BSplineEvaluationData< FEMDegree , BType >::SupportStart; + + if( IsActiveNode( node->children ) ) fprintf( stderr , "[WARNING] getCenterValueAndGradient assumes leaf node\n" ); + Real value(0); + Point3D< Real > gradient; + LocalDepth d = _localDepth( node ); + + if( isInterior ) + { + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); + for( int i=0 ; inodeData.nodeIndex ]; + gradient += Point3D< Real >( evaluator.dCellStencil( i , j , k ) ) * solution[ n->nodeData.nodeIndex ]; + } + } + if( d>0 ) + { + int _corner = int( node - node->parent->children ); + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node->parent ); + for( int i=0 ; inodeData.nodeIndex]; + gradient += Point3D< Real >( evaluator.dCellStencils[_corner]( i , j , k ) ) * coarseSolution[n->nodeData.nodeIndex]; + } + } + } + } + else + { + LocalOffset cIdx; + _localDepthAndOffset( node , d , cIdx ); + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); + + for( int i=0 ; inodeData.nodeIndex ]; + gradient += + Point3D< Real > + ( + evaluator.evaluator.centerValue( fIdx[0] , cIdx[0] , true ) * evaluator.evaluator.centerValue( fIdx[1] , cIdx[1] , false ) * evaluator.evaluator.centerValue( fIdx[2] , cIdx[2] , false ) , + evaluator.evaluator.centerValue( fIdx[0] , cIdx[0] , false ) * evaluator.evaluator.centerValue( fIdx[1] , cIdx[1] , true ) * evaluator.evaluator.centerValue( fIdx[2] , cIdx[2] , false ) , + evaluator.evaluator.centerValue( fIdx[0] , cIdx[0] , false ) * evaluator.evaluator.centerValue( fIdx[1] , cIdx[1] , false ) * evaluator.evaluator.centerValue( fIdx[2] , cIdx[2] , true ) + ) * solution[ n->nodeData.nodeIndex ]; + } + } + if( d>0 ) + { + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node->parent ); + for( int i=0 ; inodeData.nodeIndex ]; + gradient += + Point3D< Real > + ( + evaluator.childEvaluator.centerValue( fIdx[0] , cIdx[0] , true ) * evaluator.childEvaluator.centerValue( fIdx[1] , cIdx[1] , false ) * evaluator.childEvaluator.centerValue( fIdx[2] , cIdx[2] , false ) , + evaluator.childEvaluator.centerValue( fIdx[0] , cIdx[0] , false ) * evaluator.childEvaluator.centerValue( fIdx[1] , cIdx[1] , true ) * evaluator.childEvaluator.centerValue( fIdx[2] , cIdx[2] , false ) , + evaluator.childEvaluator.centerValue( fIdx[0] , cIdx[0] , false ) * evaluator.childEvaluator.centerValue( fIdx[1] , cIdx[1] , false ) * evaluator.childEvaluator.centerValue( fIdx[2] , cIdx[2] , true ) + ) * coarseSolution[ n->nodeData.nodeIndex ]; + } + } + } + } + return std::pair< Real , Point3D< Real > >( value , gradient ); +} +template< class Real > +template< class V , int FEMDegree , BoundaryType BType > +V Octree< Real >::_getEdgeValue( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , int edge , const DenseNodeData< V , FEMDegree >& solution , const DenseNodeData< V , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator , bool isInterior ) const +{ + static const int SupportSize = BSplineEvaluationData< FEMDegree , BType >::SupportSize; + static const int LeftPointSupportRadius = BSplineEvaluationData< FEMDegree , BType >::SupportEnd; + static const int RightPointSupportRadius = -BSplineEvaluationData< FEMDegree , BType >::SupportStart; + V value(0); + LocalDepth d ; LocalOffset cIdx; + _localDepthAndOffset( node , d , cIdx ); + int startX = 0 , endX = SupportSize , startY = 0 , endY = SupportSize , startZ = 0 , endZ = SupportSize; + int orientation , i1 , i2; + Cube::FactorEdgeIndex( edge , orientation , i1 , i2 ); + switch( orientation ) + { + case 0: + cIdx[1] += i1 , cIdx[2] += i2; + if( i1 ) startY++ ; else endY--; + if( i2 ) startZ++ ; else endZ--; + break; + case 1: + cIdx[0] += i1 , cIdx[2] += i2; + if( i1 ) startX++ ; else endX--; + if( i2 ) startZ++ ; else endZ--; + break; + case 2: + cIdx[0] += i1 , cIdx[1] += i2; + if( i1 ) startX++ ; else endX--; + if( i2 ) startY++ ; else endY--; + break; + } + + { + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , d ); + for( int x=startX ; xnodeData.nodeIndex ] * evaluator.edgeStencil[edge]( x , y , z ); + else + { + LocalDepth _d ; LocalOffset fIdx; + _localDepthAndOffset( _node , _d , fIdx ); + switch( orientation ) + { + case 0: + value += + solution[ _node->nodeData.nodeIndex ] * + Real( + evaluator.evaluator.centerValue( fIdx[0] , cIdx[0] , false ) * + evaluator.evaluator.cornerValue( fIdx[1] , cIdx[1] , false ) * + evaluator.evaluator.cornerValue( fIdx[2] , cIdx[2] , false ) + ); + break; + case 1: + value += + solution[ _node->nodeData.nodeIndex ] * + Real( + evaluator.evaluator.cornerValue( fIdx[0] , cIdx[0] , false ) * + evaluator.evaluator.centerValue( fIdx[1] , cIdx[1] , false ) * + evaluator.evaluator.cornerValue( fIdx[2] , cIdx[2] , false ) + ); + break; + case 2: + value += + solution[ _node->nodeData.nodeIndex ] * + Real( + evaluator.evaluator.cornerValue( fIdx[0] , cIdx[0] , false ) * + evaluator.evaluator.cornerValue( fIdx[1] , cIdx[1] , false ) * + evaluator.evaluator.centerValue( fIdx[2] , cIdx[2] , false ) + ); + break; + } + } + } + } + } + if( d>0 ) + { + int _corner = int( node - node->parent->children ); + int _cx , _cy , _cz; + Cube::FactorCornerIndex( _corner , _cx , _cy , _cz ); + // If the corner/child indices don't match, then the sample position is in the interior of the + // coarser cell and so the full support resolution should be used. + switch( orientation ) + { + case 0: + if( _cy!=i1 ) startY = 0 , endY = SupportSize; + if( _cz!=i2 ) startZ = 0 , endZ = SupportSize; + break; + case 1: + if( _cx!=i1 ) startX = 0 , endX = SupportSize; + if( _cz!=i2 ) startZ = 0 , endZ = SupportSize; + break; + case 2: + if( _cx!=i1 ) startX = 0 , endX = SupportSize; + if( _cy!=i2 ) startY = 0 , endY = SupportSize; + break; + } + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node->parent ); + for( int x=startX ; xnodeData.nodeIndex ] * evaluator.edgeStencils[_corner][edge]( x , y , z ); + else + { + LocalDepth _d ; LocalOffset fIdx; + _localDepthAndOffset( _node , _d , fIdx ); + switch( orientation ) + { + case 0: + value += + coarseSolution[ _node->nodeData.nodeIndex ] * + Real( + evaluator.childEvaluator.centerValue( fIdx[0] , cIdx[0] , false ) * + evaluator.childEvaluator.cornerValue( fIdx[1] , cIdx[1] , false ) * + evaluator.childEvaluator.cornerValue( fIdx[2] , cIdx[2] , false ) + ); + break; + case 1: + value += + coarseSolution[ _node->nodeData.nodeIndex ] * + Real( + evaluator.childEvaluator.cornerValue( fIdx[0] , cIdx[0] , false ) * + evaluator.childEvaluator.centerValue( fIdx[1] , cIdx[1] , false ) * + evaluator.childEvaluator.cornerValue( fIdx[2] , cIdx[2] , false ) + ); + break; + case 2: + value += + coarseSolution[ _node->nodeData.nodeIndex ] * + Real( + evaluator.childEvaluator.cornerValue( fIdx[0] , cIdx[0] , false ) * + evaluator.childEvaluator.cornerValue( fIdx[1] , cIdx[1] , false ) * + evaluator.childEvaluator.centerValue( fIdx[2] , cIdx[2] , false ) + ); + break; + } + } + } + } + } + return Real( value ); +} +template< class Real > +template< int FEMDegree , BoundaryType BType > +std::pair< Real , Point3D< Real > > Octree< Real >::_getEdgeValueAndGradient( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , int edge , const DenseNodeData< Real , FEMDegree >& solution , const DenseNodeData< Real , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator , bool isInterior ) const +{ + static const int SupportSize = BSplineEvaluationData< FEMDegree , BType >::SupportSize; + static const int LeftPointSupportRadius = BSplineEvaluationData< FEMDegree , BType >::SupportEnd; + static const int RightPointSupportRadius = -BSplineEvaluationData< FEMDegree , BType >::SupportStart; + double value = 0; + Point3D< double > gradient; + LocalDepth d ; LocalOffset cIdx; + _localDepthAndOffset( node , d , cIdx ); + + int startX = 0 , endX = SupportSize , startY = 0 , endY = SupportSize , startZ = 0 , endZ = SupportSize; + int orientation , i1 , i2; + Cube::FactorEdgeIndex( edge , orientation , i1 , i2 ); + switch( orientation ) + { + case 0: + cIdx[1] += i1 , cIdx[2] += i2; + if( i1 ) startY++ ; else endY--; + if( i2 ) startZ++ ; else endZ--; + break; + case 1: + cIdx[0] += i1 , cIdx[2] += i2; + if( i1 ) startX++ ; else endX--; + if( i2 ) startZ++ ; else endZ--; + break; + case 2: + cIdx[0] += i1 , cIdx[1] += i2; + if( i1 ) startX++ ; else endX--; + if( i2 ) startY++ ; else endY--; + break; + } + { + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); + for( int x=startX ; xnodeData.nodeIndex ]; + gradient += evaluator.dEdgeStencil[edge]( x , y , z ) * solution[ _node->nodeData.nodeIndex ]; + } + else + { + LocalDepth _d ; LocalOffset fIdx; + _localDepthAndOffset( _node , _d , fIdx ); + + double vv[3] , dv[3]; + switch( orientation ) + { + case 0: + vv[0] = evaluator.evaluator.centerValue( fIdx[0] , cIdx[0] , false ); + vv[1] = evaluator.evaluator.cornerValue( fIdx[1] , cIdx[1] , false ); + vv[2] = evaluator.evaluator.cornerValue( fIdx[2] , cIdx[2] , false ); + dv[0] = evaluator.evaluator.centerValue( fIdx[0] , cIdx[0] , true ); + dv[1] = evaluator.evaluator.cornerValue( fIdx[1] , cIdx[1] , true ); + dv[2] = evaluator.evaluator.cornerValue( fIdx[2] , cIdx[2] , true ); + break; + case 1: + vv[0] = evaluator.evaluator.cornerValue( fIdx[0] , cIdx[0] , false ); + vv[1] = evaluator.evaluator.centerValue( fIdx[1] , cIdx[1] , false ); + vv[2] = evaluator.evaluator.cornerValue( fIdx[2] , cIdx[2] , false ); + dv[0] = evaluator.evaluator.cornerValue( fIdx[0] , cIdx[0] , true ); + dv[1] = evaluator.evaluator.centerValue( fIdx[1] , cIdx[1] , true ); + dv[2] = evaluator.evaluator.cornerValue( fIdx[2] , cIdx[2] , true ); + break; + case 2: + vv[0] = evaluator.evaluator.cornerValue( fIdx[0] , cIdx[0] , false ); + vv[1] = evaluator.evaluator.cornerValue( fIdx[1] , cIdx[1] , false ); + vv[2] = evaluator.evaluator.centerValue( fIdx[2] , cIdx[2] , false ); + dv[0] = evaluator.evaluator.cornerValue( fIdx[0] , cIdx[0] , true ); + dv[1] = evaluator.evaluator.cornerValue( fIdx[1] , cIdx[1] , true ); + dv[2] = evaluator.evaluator.centerValue( fIdx[2] , cIdx[2] , true ); + break; + } + value += solution[ _node->nodeData.nodeIndex ] * vv[0] * vv[1] * vv[2]; + gradient += Point3D< double >( dv[0]*vv[1]*vv[2] , vv[0]*dv[1]*vv[2] , vv[0]*vv[1]*dv[2] ) * solution[ _node->nodeData.nodeIndex ]; + } + } + } + } + if( d>0 ) + { + int _corner = int( node - node->parent->children ); + int _cx , _cy , _cz; + Cube::FactorCornerIndex( _corner , _cx , _cy , _cz ); + // If the corner/child indices don't match, then the sample position is in the interior of the + // coarser cell and so the full support resolution should be used. + switch( orientation ) + { + case 0: + if( _cy!=i1 ) startY = 0 , endY = SupportSize; + if( _cz!=i2 ) startZ = 0 , endZ = SupportSize; + break; + case 1: + if( _cx!=i1 ) startX = 0 , endX = SupportSize; + if( _cz!=i2 ) startZ = 0 , endZ = SupportSize; + break; + case 2: + if( _cx!=i1 ) startX = 0 , endX = SupportSize; + if( _cy!=i2 ) startY = 0 , endY = SupportSize; + break; + } + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node->parent ); + for( int x=startX ; xnodeData.nodeIndex ]; + gradient += evaluator.dEdgeStencils[_corner][edge]( x , y , z ) * coarseSolution[ _node->nodeData.nodeIndex ]; + } + else + { + LocalDepth _d ; LocalOffset fIdx; + _localDepthAndOffset( _node , _d , fIdx ); + double vv[3] , dv[3]; + switch( orientation ) + { + case 0: + vv[0] = evaluator.childEvaluator.centerValue( fIdx[0] , cIdx[0] , false ); + vv[1] = evaluator.childEvaluator.cornerValue( fIdx[1] , cIdx[1] , false ); + vv[2] = evaluator.childEvaluator.cornerValue( fIdx[2] , cIdx[2] , false ); + dv[0] = evaluator.childEvaluator.centerValue( fIdx[0] , cIdx[0] , true ); + dv[1] = evaluator.childEvaluator.cornerValue( fIdx[1] , cIdx[1] , true ); + dv[2] = evaluator.childEvaluator.cornerValue( fIdx[2] , cIdx[2] , true ); + break; + case 1: + vv[0] = evaluator.childEvaluator.cornerValue( fIdx[0] , cIdx[0] , false ); + vv[1] = evaluator.childEvaluator.centerValue( fIdx[1] , cIdx[1] , false ); + vv[2] = evaluator.childEvaluator.cornerValue( fIdx[2] , cIdx[2] , false ); + dv[0] = evaluator.childEvaluator.cornerValue( fIdx[0] , cIdx[0] , true ); + dv[1] = evaluator.childEvaluator.centerValue( fIdx[1] , cIdx[1] , true ); + dv[2] = evaluator.childEvaluator.cornerValue( fIdx[2] , cIdx[2] , true ); + break; + case 2: + vv[0] = evaluator.childEvaluator.cornerValue( fIdx[0] , cIdx[0] , false ); + vv[1] = evaluator.childEvaluator.cornerValue( fIdx[1] , cIdx[1] , false ); + vv[2] = evaluator.childEvaluator.centerValue( fIdx[2] , cIdx[2] , false ); + dv[0] = evaluator.childEvaluator.cornerValue( fIdx[0] , cIdx[0] , true ); + dv[1] = evaluator.childEvaluator.cornerValue( fIdx[1] , cIdx[1] , true ); + dv[2] = evaluator.childEvaluator.centerValue( fIdx[2] , cIdx[2] , true ); + break; + } + value += coarseSolution[ _node->nodeData.nodeIndex ] * vv[0] * vv[1] * vv[2]; + gradient += Point3D< double >( dv[0]*vv[1]*vv[2] , vv[0]*dv[1]*vv[2] , vv[0]*vv[1]*dv[2] ) * coarseSolution[ _node->nodeData.nodeIndex ]; + } + } + } + } + return std::pair< Real , Point3D< Real > >( Real( value ) , Point3D< Real >( gradient ) ); +} + +template< class Real > +template< class V , int FEMDegree , BoundaryType BType > +V Octree< Real >::_getCornerValue( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , int corner , const DenseNodeData< V , FEMDegree >& solution , const DenseNodeData< V , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator , bool isInterior ) const +{ + static const int SupportSize = BSplineSupportSizes< FEMDegree >::SupportSize; + static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + static const int RightPointSupportRadius = - BSplineSupportSizes< FEMDegree >::SupportStart; + + V value(0); + LocalDepth d ; LocalOffset cIdx; + _localDepthAndOffset( node , d , cIdx ); + + int cx , cy , cz; + int startX = 0 , endX = SupportSize , startY = 0 , endY = SupportSize , startZ = 0 , endZ = SupportSize; + Cube::FactorCornerIndex( corner , cx , cy , cz ); + cIdx[0] += cx , cIdx[1] += cy , cIdx[2] += cz; + { + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); + if( cx==0 ) endX--; + else startX++; + if( cy==0 ) endY--; + else startY++; + if( cz==0 ) endZ--; + else startZ++; + if( isInterior ) + for( int x=startX ; xnodeData.nodeIndex ] * Real( evaluator.cornerStencil[corner]( x , y , z ) ); + } + else + for( int x=startX ; xnodeData.nodeIndex ] * + Real( + evaluator.evaluator.cornerValue( fIdx[0] , cIdx[0] , false ) * + evaluator.evaluator.cornerValue( fIdx[1] , cIdx[1] , false ) * + evaluator.evaluator.cornerValue( fIdx[2] , cIdx[2] , false ) + ); + } + } + } + if( d>0 ) + { + int _corner = int( node - node->parent->children ); + int _cx , _cy , _cz; + Cube::FactorCornerIndex( _corner , _cx , _cy , _cz ); + // If the corner/child indices don't match, then the sample position is in the interior of the + // coarser cell and so the full support resolution should be used. + if( cx!=_cx ) startX = 0 , endX = SupportSize; + if( cy!=_cy ) startY = 0 , endY = SupportSize; + if( cz!=_cz ) startZ = 0 , endZ = SupportSize; + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node->parent ); + if( isInterior ) + for( int x=startX ; xnodeData.nodeIndex ] * Real( evaluator.cornerStencils[_corner][corner]( x , y , z ) ); + } + else + for( int x=startX ; xnodeData.nodeIndex ] * + Real( + evaluator.childEvaluator.cornerValue( fIdx[0] , cIdx[0] , false ) * + evaluator.childEvaluator.cornerValue( fIdx[1] , cIdx[1] , false ) * + evaluator.childEvaluator.cornerValue( fIdx[2] , cIdx[2] , false ) + ); + } + } + } + return Real( value ); +} +template< class Real > +template< int FEMDegree , BoundaryType BType > +std::pair< Real , Point3D< Real > > Octree< Real >::_getCornerValueAndGradient( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , int corner , const DenseNodeData< Real , FEMDegree >& solution , const DenseNodeData< Real , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator , bool isInterior ) const +{ + static const int SupportSize = BSplineSupportSizes< FEMDegree >::SupportSize; + static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + static const int RightPointSupportRadius = - BSplineSupportSizes< FEMDegree >::SupportStart; + + double value = 0; + Point3D< double > gradient; + LocalDepth d ; LocalOffset cIdx; + _localDepthAndOffset( node , d , cIdx ); + + int cx , cy , cz; + int startX = 0 , endX = SupportSize , startY = 0 , endY = SupportSize , startZ = 0 , endZ = SupportSize; + Cube::FactorCornerIndex( corner , cx , cy , cz ); + cIdx[0] += cx , cIdx[1] += cy , cIdx[2] += cz; + { + if( cx==0 ) endX--; + else startX++; + if( cy==0 ) endY--; + else startY++; + if( cz==0 ) endZ--; + else startZ++; + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); + if( isInterior ) + for( int x=startX ; xnodeData.nodeIndex ] * evaluator.cornerStencil[corner]( x , y , z ) , gradient += evaluator.dCornerStencil[corner]( x , y , z ) * solution[ _node->nodeData.nodeIndex ]; + } + else + for( int x=startX ; xnodeData.nodeIndex ] * v[0] * v[1] * v[2]; + gradient += Point3D< double >( dv[0]*v[1]*v[2] , v[0]*dv[1]*v[2] , v[0]*v[1]*dv[2] ) * solution[ _node->nodeData.nodeIndex ]; + } + } + } + if( d>0 ) + { + int _corner = int( node - node->parent->children ); + int _cx , _cy , _cz; + Cube::FactorCornerIndex( _corner , _cx , _cy , _cz ); + if( cx!=_cx ) startX = 0 , endX = SupportSize; + if( cy!=_cy ) startY = 0 , endY = SupportSize; + if( cz!=_cz ) startZ = 0 , endZ = SupportSize; + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node->parent ); + if( isInterior ) + for( int x=startX ; xnodeData.nodeIndex ] * evaluator.cornerStencils[_corner][corner]( x , y , z ) , gradient += evaluator.dCornerStencils[_corner][corner]( x , y , z ) * coarseSolution[ _node->nodeData.nodeIndex ]; + } + else + for( int x=startX ; xnodeData.nodeIndex ] * v[0] * v[1] * v[2]; + gradient += Point3D< double >( dv[0]*v[1]*v[2] , v[0]*dv[1]*v[2] , v[0]*v[1]*dv[2] ) * coarseSolution[ _node->nodeData.nodeIndex ]; + } + } + } + return std::pair< Real , Point3D< Real > >( Real( value ) , Point3D< Real >( gradient ) ); +} +template< class Real > +template< int Degree , BoundaryType BType > +Octree< Real >::MultiThreadedEvaluator< Degree , BType >::MultiThreadedEvaluator( const Octree< Real >* tree , const DenseNodeData< Real , Degree >& coefficients , int threads ) : _coefficients( coefficients ) , _tree( tree ) +{ + _threads = std::max< int >( 1 , threads ); + _neighborKeys.resize( _threads ); + _coarseCoefficients = _tree->template coarseCoefficients< Real , Degree , BType >( _coefficients ); + _evaluator.set( _tree->_maxDepth ); + for( int t=0 ; t<_threads ; t++ ) _neighborKeys[t].set( tree->_localToGlobal( _tree->_maxDepth ) ); +} +template< class Real > +template< int Degree , BoundaryType BType > +Real Octree< Real >::MultiThreadedEvaluator< Degree , BType >::value( Point3D< Real > p , int thread , const TreeOctNode* node ) +{ + if( !node ) node = _tree->leaf( p ); + ConstPointSupportKey< Degree >& nKey = _neighborKeys[thread]; + nKey.getNeighbors( node ); + return _tree->template _getValue< Real , Degree >( nKey , node , p , _coefficients , _coarseCoefficients , _evaluator ); +} +template< class Real > +template< int Degree , BoundaryType BType > +std::pair< Real , Point3D< Real > > Octree< Real >::MultiThreadedEvaluator< Degree , BType >::valueAndGradient( Point3D< Real > p , int thread , const TreeOctNode* node ) +{ + if( !node ) node = _tree->leaf( p ); + ConstPointSupportKey< Degree >& nKey = _neighborKeys[thread]; + nKey.getNeighbors( node ); + return _tree->template _getValueAndGradient< Degree >( nKey , node , p , _coefficients , _coarseCoefficients , _evaluator ); +} diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.IsoSurface.inl b/src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.IsoSurface.inl new file mode 100644 index 000000000..2be26dc51 --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.IsoSurface.inl @@ -0,0 +1,1106 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +#include "Octree.h" +#include "MyTime.h" +#include "MemoryUsage.h" +#include "MAT.h" + +template< class Real > +template< class Vertex > +Octree< Real >::_SliceValues< Vertex >::_SliceValues( void ) +{ + _oldCCount = _oldECount = _oldFCount = _oldNCount = 0; + cornerValues = NullPointer( Real ) ; cornerGradients = NullPointer( Point3D< Real > ) ; cornerSet = NullPointer( char ); + edgeKeys = NullPointer( long long ) ; edgeSet = NullPointer( char ); + faceEdges = NullPointer( _FaceEdges ) ; faceSet = NullPointer( char ); + mcIndices = NullPointer( char ); +} +template< class Real > +template< class Vertex > +Octree< Real >::_SliceValues< Vertex >::~_SliceValues( void ) +{ + _oldCCount = _oldECount = _oldFCount = _oldNCount = 0; + FreePointer( cornerValues ) ; FreePointer( cornerGradients ) ; FreePointer( cornerSet ); + FreePointer( edgeKeys ) ; FreePointer( edgeSet ); + FreePointer( faceEdges ) ; FreePointer( faceSet ); + FreePointer( mcIndices ); +} +template< class Real > +template< class Vertex > +void Octree< Real >::_SliceValues< Vertex >::reset( bool nonLinearFit ) +{ + faceEdgeMap.clear() , edgeVertexMap.clear() , vertexPairMap.clear(); + + if( _oldNCount0 ) mcIndices = AllocPointer< char >( _oldNCount ); + } + if( _oldCCount0 ) + { + cornerValues = AllocPointer< Real >( _oldCCount ); + if( nonLinearFit ) cornerGradients = AllocPointer< Point3D< Real > >( _oldCCount ); + cornerSet = AllocPointer< char >( _oldCCount ); + } + } + if( _oldECount( _oldECount ); + edgeSet = AllocPointer< char >( _oldECount ); + } + if( _oldFCount( _oldFCount ); + faceSet = AllocPointer< char >( _oldFCount ); + } + + if( sliceData.cCount>0 ) memset( cornerSet , 0 , sizeof( char ) * sliceData.cCount ); + if( sliceData.eCount>0 ) memset( edgeSet , 0 , sizeof( char ) * sliceData.eCount ); + if( sliceData.fCount>0 ) memset( faceSet , 0 , sizeof( char ) * sliceData.fCount ); +} +template< class Real > +template< class Vertex > +Octree< Real >::_XSliceValues< Vertex >::_XSliceValues( void ) +{ + _oldECount = _oldFCount = 0; + edgeKeys = NullPointer( long long ) ; edgeSet = NullPointer( char ); + faceEdges = NullPointer( _FaceEdges ) ; faceSet = NullPointer( char ); +} +template< class Real > +template< class Vertex > +Octree< Real >::_XSliceValues< Vertex >::~_XSliceValues( void ) +{ + _oldECount = _oldFCount = 0; + FreePointer( edgeKeys ) ; FreePointer( edgeSet ); + FreePointer( faceEdges ) ; FreePointer( faceSet ); +} +template< class Real > +template< class Vertex > +void Octree< Real >::_XSliceValues< Vertex >::reset( void ) +{ + faceEdgeMap.clear() , edgeVertexMap.clear() , vertexPairMap.clear(); + + if( _oldECount( _oldECount ); + edgeSet = AllocPointer< char >( _oldECount ); + } + if( _oldFCount( _oldFCount ); + faceSet = AllocPointer< char >( _oldFCount ); + } + if( xSliceData.eCount>0 ) memset( edgeSet , 0 , sizeof( char ) * xSliceData.eCount ); + if( xSliceData.fCount>0 ) memset( faceSet , 0 , sizeof( char ) * xSliceData.fCount ); +} + +template< class Real > +template< int FEMDegree , BoundaryType BType , int WeightDegree , int ColorDegree , class Vertex > +void Octree< Real >::getMCIsoSurface( const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Point3D< Real > , Real > , ColorDegree >* colorData , const DenseNodeData< Real , FEMDegree >& solution , Real isoValue , CoredMeshData< Vertex >& mesh , bool nonLinearFit , bool addBarycenter , bool polygonMesh ) +{ + if( FEMDegree==1 && nonLinearFit ) fprintf( stderr , "[WARNING] First order B-Splines do not support non-linear interpolation\n" ) , nonLinearFit = false; + + BSplineData< ColorDegree , BOUNDARY_NEUMANN >* colorBSData = NULL; + if( colorData ) colorBSData = new BSplineData< ColorDegree , BOUNDARY_NEUMANN >( _maxDepth ); + DenseNodeData< Real , FEMDegree > coarseSolution( _sNodesEnd(_maxDepth-1) ); + memset( &coarseSolution[0] , 0 , sizeof(Real)*_sNodesEnd( _maxDepth-1) ); +#pragma omp parallel for num_threads( threads ) + for( int i=_sNodesBegin(0) ; i<_sNodesEnd(_maxDepth-1) ; i++ ) coarseSolution[i] = solution[i]; + for( LocalDepth d=1 ; d<_maxDepth ; d++ ) _upSample< Real , FEMDegree , BType >( d , coarseSolution ); + memoryUsage(); + + std::vector< _Evaluator< FEMDegree , BType > > evaluators( _maxDepth+1 ); + for( LocalDepth d=0 ; d<=_maxDepth ; d++ ) evaluators[d].set( d ); + + int vertexOffset = 0; + + std::vector< _SlabValues< Vertex > > slabValues( _maxDepth+1 ); + + // Initialize the back slice + for( LocalDepth d=_maxDepth ; d>=0 ; d-- ) + { + _sNodes.setSliceTableData ( slabValues[d]. sliceValues(0). sliceData , _localToGlobal( d ) , 0 + _localInset( d ) , threads ); + _sNodes.setSliceTableData ( slabValues[d]. sliceValues(1). sliceData , _localToGlobal( d ) , 1 + _localInset( d ) , threads ); + _sNodes.setXSliceTableData( slabValues[d].xSliceValues(0).xSliceData , _localToGlobal( d ) , 0 + _localInset( d ) , threads ); + slabValues[d].sliceValues (0).reset( nonLinearFit ); + slabValues[d].sliceValues (1).reset( nonLinearFit ); + slabValues[d].xSliceValues(0).reset( ); + } + for( LocalDepth d=_maxDepth ; d>=0 ; d-- ) + { + // Copy edges from finer + if( d<_maxDepth ) _copyFinerSliceIsoEdgeKeys( d , 0 , slabValues , threads ); + _setSliceIsoCorners( solution , coarseSolution , isoValue , d , 0 , slabValues , evaluators[d] , threads ); + _setSliceIsoVertices< WeightDegree , ColorDegree >( colorBSData , densityWeights , colorData , isoValue , d , 0 , vertexOffset , mesh , slabValues , threads ); + _setSliceIsoEdges( d , 0 , slabValues , threads ); + } + + // Iterate over the slices at the finest level + for( int slice=0 ; slice<( 1<<_maxDepth ) ; slice++ ) + { + // Process at all depths that contain this slice + LocalDepth d ; int o; + for( d=_maxDepth , o=slice+1 ; d>=0 ; d-- , o>>=1 ) + { + // Copy edges from finer (required to ensure we correctly track edge cancellations) + if( d<_maxDepth ) + { + _copyFinerSliceIsoEdgeKeys( d , o , slabValues , threads ); + _copyFinerXSliceIsoEdgeKeys( d , o-1 , slabValues , threads ); + } + + // Set the slice values/vertices + _setSliceIsoCorners( solution , coarseSolution , isoValue , d , o , slabValues , evaluators[d] , threads ); + _setSliceIsoVertices< WeightDegree , ColorDegree >( colorBSData , densityWeights , colorData , isoValue , d , o , vertexOffset , mesh , slabValues , threads ); + _setSliceIsoEdges( d , o , slabValues , threads ); + + // Set the cross-slice edges + _setXSliceIsoVertices< WeightDegree , ColorDegree >( colorBSData , densityWeights , colorData , isoValue , d , o-1 , vertexOffset , mesh , slabValues , threads ); + _setXSliceIsoEdges( d , o-1 , slabValues , threads ); + + // Add the triangles + _setIsoSurface( d , o-1 , slabValues[d].sliceValues(o-1) , slabValues[d].sliceValues(o) , slabValues[d].xSliceValues(o-1) , mesh , polygonMesh , addBarycenter , vertexOffset , threads ); + + if( o&1 ) break; + } + + for( d=_maxDepth , o=slice+1 ; d>=0 ; d-- , o>>=1 ) + { + // Initialize for the next pass + if( o<(1<<(d+1)) ) + { + _sNodes.setSliceTableData( slabValues[d].sliceValues(o+1).sliceData , _localToGlobal( d ) , o+1 + _localInset( d ) , threads ); + _sNodes.setXSliceTableData( slabValues[d].xSliceValues(o).xSliceData , _localToGlobal( d ) , o + _localInset( d ) , threads ); + slabValues[d].sliceValues(o+1).reset( nonLinearFit ); + slabValues[d].xSliceValues(o).reset(); + } + if( o&1 ) break; + } + } + memoryUsage(); + if( colorBSData ) delete colorBSData; +} + + +template< class Real > +template< class Vertex , int FEMDegree , BoundaryType BType > +void Octree< Real >::_setSliceIsoCorners( const DenseNodeData< Real , FEMDegree >& solution , const DenseNodeData< Real , FEMDegree >& coarseSolution , Real isoValue , LocalDepth depth , int slice , std::vector< _SlabValues< Vertex > >& slabValues , const _Evaluator< FEMDegree , BType >& evaluator , int threads ) +{ + if( slice>0 ) _setSliceIsoCorners( solution , coarseSolution , isoValue , depth , slice , 1 , slabValues , evaluator , threads ); + if( slice<(1< +template< class Vertex , int FEMDegree , BoundaryType BType > +void Octree< Real >::_setSliceIsoCorners( const DenseNodeData< Real , FEMDegree >& solution , const DenseNodeData< Real , FEMDegree >& coarseSolution , Real isoValue , LocalDepth depth , int slice , int z , std::vector< _SlabValues< Vertex > >& slabValues , const struct _Evaluator< FEMDegree , BType >& evaluator , int threads ) +{ + typename Octree::template _SliceValues< Vertex >& sValues = slabValues[depth].sliceValues( slice ); + std::vector< ConstPointSupportKey< FEMDegree > > neighborKeys( std::max< int >( 1 , threads ) ); + for( size_t i=0 ; i& neighborKey = neighborKeys[ omp_get_thread_num() ]; + TreeOctNode* leaf = _sNodes.treeNodes[i]; + if( !IsActiveNode( leaf->children ) ) + { + const typename SortedTreeNodes::SquareCornerIndices& cIndices = sValues.sliceData.cornerIndices( leaf ); + + bool isInterior = _isInteriorlySupported< FEMDegree >( leaf->parent ); + neighborKey.getNeighbors( leaf ); + + for( int x=0 ; x<2 ; x++ ) for( int y=0 ; y<2 ; y++ ) + { + int cc = Cube::CornerIndex( x , y , z ); + int fc = Square::CornerIndex( x , y ); + int vIndex = cIndices[fc]; + if( !sValues.cornerSet[vIndex] ) + { + if( sValues.cornerGradients ) + { + std::pair< Real , Point3D< Real > > p = _getCornerValueAndGradient( neighborKey , leaf , cc , solution , coarseSolution , evaluator , isInterior ); + sValues.cornerValues[vIndex] = p.first , sValues.cornerGradients[vIndex] = p.second; + } + else sValues.cornerValues[vIndex] = _getCornerValue( neighborKey , leaf , cc , solution , coarseSolution , evaluator , isInterior ); + sValues.cornerSet[vIndex] = 1; + } + squareValues[fc] = sValues.cornerValues[ vIndex ]; + TreeOctNode* node = leaf; + LocalDepth _depth = depth; + int _slice = slice; + while( _isValidSpaceNode( node->parent ) && (node-node->parent->children)==cc ) + { + node = node->parent , _depth-- , _slice >>= 1; + typename Octree::template _SliceValues< Vertex >& _sValues = slabValues[_depth].sliceValues( _slice ); + const typename SortedTreeNodes::SquareCornerIndices& _cIndices = _sValues.sliceData.cornerIndices( node ); + int _vIndex = _cIndices[fc]; + _sValues.cornerValues[_vIndex] = sValues.cornerValues[vIndex]; + if( _sValues.cornerGradients ) _sValues.cornerGradients[_vIndex] = sValues.cornerGradients[vIndex]; + _sValues.cornerSet[_vIndex] = 1; + } + } + sValues.mcIndices[ i - sValues.sliceData.nodeOffset ] = MarchingSquares::GetIndex( squareValues , isoValue ); + } + } +} + +template< class Real > +template< int WeightDegree , int ColorDegree , BoundaryType BType , class Vertex > +void Octree< Real >::_setSliceIsoVertices( const BSplineData< ColorDegree , BType >* colorBSData , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Point3D< Real > , Real > , ColorDegree >* colorData , Real isoValue , LocalDepth depth , int slice , int& vOffset , CoredMeshData< Vertex >& mesh , std::vector< _SlabValues< Vertex > >& slabValues , int threads ) +{ + if( slice>0 ) _setSliceIsoVertices< WeightDegree , ColorDegree >( colorBSData , densityWeights , colorData , isoValue , depth , slice , 1 , vOffset , mesh , slabValues , threads ); + if( slice<(1<( colorBSData , densityWeights , colorData , isoValue , depth , slice , 0 , vOffset , mesh , slabValues , threads ); +} +template< class Real > +template< int WeightDegree , int ColorDegree , BoundaryType BType , class Vertex > +void Octree< Real >::_setSliceIsoVertices( const BSplineData< ColorDegree , BType >* colorBSData , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Point3D< Real > , Real > , ColorDegree >* colorData , Real isoValue , LocalDepth depth , int slice , int z , int& vOffset , CoredMeshData< Vertex >& mesh , std::vector< _SlabValues< Vertex > >& slabValues , int threads ) +{ + typename Octree::template _SliceValues< Vertex >& sValues = slabValues[depth].sliceValues( slice ); + // [WARNING] In the case Degree=2, these two keys are the same, so we don't have to maintain them separately. + std::vector< ConstAdjacenctNodeKey > neighborKeys( std::max< int >( 1 , threads ) ); + std::vector< ConstPointSupportKey< WeightDegree > > weightKeys( std::max< int >( 1 , threads ) ); + std::vector< ConstPointSupportKey< ColorDegree > > colorKeys( std::max< int >( 1 , threads ) ); + for( size_t i=0 ; i& weightKey = weightKeys[ omp_get_thread_num() ]; + ConstPointSupportKey< ColorDegree >& colorKey = colorKeys[ omp_get_thread_num() ]; + TreeOctNode* leaf = _sNodes.treeNodes[i]; + if( !IsActiveNode( leaf->children ) ) + { + int idx = i - sValues.sliceData.nodeOffset; + const typename SortedTreeNodes::SquareEdgeIndices& eIndices = sValues.sliceData.edgeIndices( leaf ); + if( MarchingSquares::HasRoots( sValues.mcIndices[idx] ) ) + { + neighborKey.getNeighbors( leaf ); + if( densityWeights ) weightKey.getNeighbors( leaf ); + if( colorData ) colorKey.getNeighbors( leaf ); + for( int e=0 ; e hashed_vertex; +#pragma omp critical (add_point_access) + { + if( !sValues.edgeSet[vIndex] ) + { + mesh.addOutOfCorePoint( vertex ); + sValues.edgeSet[ vIndex ] = 1; + sValues.edgeKeys[ vIndex ] = key; + sValues.edgeVertexMap[key] = hashed_vertex = std::pair< int , Vertex >( vOffset , vertex ); + vOffset++; + stillOwner = true; + } + } + if( stillOwner ) + { + // We only need to pass the iso-vertex down if the edge it lies on is adjacent to a coarser leaf + bool isNeeded; + switch( o ) + { + case 0: isNeeded = ( !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[1][2*y][1] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[1][2*y][2*z] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[1][1][2*z] ) ) ; break; + case 1: isNeeded = ( !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[2*y][1][1] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[2*y][1][2*z] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[1][1][2*z] ) ) ; break; + } + if( isNeeded ) + { + int f[2]; + Cube::FacesAdjacentToEdge( Cube::EdgeIndex( o , y , z ) , f[0] , f[1] ); + for( int k=0 ; k<2 ; k++ ) + { + TreeOctNode* node = leaf; + LocalDepth _depth = depth; + int _slice = slice; + bool _isNeeded = isNeeded; + while( _isNeeded && _isValidSpaceNode( node->parent ) && Cube::IsFaceCorner( (int)(node-node->parent->children) , f[k] ) ) + { + node = node->parent , _depth-- , _slice >>= 1; + typename Octree::template _SliceValues< Vertex >& _sValues = slabValues[_depth].sliceValues( _slice ); +#pragma omp critical (add_coarser_point_access) + _sValues.edgeVertexMap[key] = hashed_vertex; + switch( o ) + { + case 0: _isNeeded = ( !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[1][2*y][1] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[1][2*y][2*z] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[1][1][2*z] ) ) ; break; + case 1: _isNeeded = ( !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[2*y][1][1] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[2*y][1][2*z] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[1][1][2*z] ) ) ; break; + } + } + } + } + } + } + } + } + } + } +} +template< class Real > +template< int WeightDegree , int ColorDegree , BoundaryType BType , class Vertex > +void Octree< Real >::_setXSliceIsoVertices( const BSplineData< ColorDegree , BType >* colorBSData , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Point3D< Real > , Real > , ColorDegree >* colorData , Real isoValue , LocalDepth depth , int slab , int& vOffset , CoredMeshData< Vertex >& mesh , std::vector< _SlabValues< Vertex > >& slabValues , int threads ) +{ + typename Octree::template _SliceValues< Vertex >& bValues = slabValues[depth].sliceValues ( slab ); + typename Octree::template _SliceValues< Vertex >& fValues = slabValues[depth].sliceValues ( slab+1 ); + typename Octree::template _XSliceValues< Vertex >& xValues = slabValues[depth].xSliceValues( slab ); + + // [WARNING] In the case Degree=2, these two keys are the same, so we don't have to maintain them separately. + std::vector< ConstAdjacenctNodeKey > neighborKeys( std::max< int >( 1 , threads ) ); + std::vector< ConstPointSupportKey< WeightDegree > > weightKeys( std::max< int >( 1 , threads ) ); + std::vector< ConstPointSupportKey< ColorDegree > > colorKeys( std::max< int >( 1 , threads ) ); + for( size_t i=0 ; i& weightKey = weightKeys[ omp_get_thread_num() ]; + ConstPointSupportKey< ColorDegree >& colorKey = colorKeys[ omp_get_thread_num() ]; + TreeOctNode* leaf = _sNodes.treeNodes[i]; + if( !IsActiveNode( leaf->children ) ) + { + unsigned char mcIndex = ( bValues.mcIndices[ i - bValues.sliceData.nodeOffset ] ) | ( fValues.mcIndices[ i - fValues.sliceData.nodeOffset ] )<<4; + const typename SortedTreeNodes::SquareCornerIndices& eIndices = xValues.xSliceData.edgeIndices( leaf ); + if( MarchingCubes::HasRoots( mcIndex ) ) + { + neighborKey.getNeighbors( leaf ); + if( densityWeights ) weightKey.getNeighbors( leaf ); + if( colorData ) colorKey.getNeighbors( leaf ); + for( int x=0 ; x<2 ; x++ ) for( int y=0 ; y<2 ; y++ ) + { + int c = Square::CornerIndex( x , y ); + int e = Cube::EdgeIndex( 2 , x , y ); + if( MarchingCubes::HasEdgeRoots( mcIndex , e ) ) + { + int vIndex = eIndices[c]; + if( !xValues.edgeSet[vIndex] ) + { + Vertex vertex; + long long key = VertexData::EdgeIndex( leaf , e , _localToGlobal(_maxDepth) ); + _getIsoVertex( colorBSData , densityWeights , colorData , isoValue , weightKey , colorKey , leaf , c , bValues , fValues , vertex ); + bool stillOwner = false; + std::pair< int , Vertex > hashed_vertex; +#pragma omp critical (add_x_point_access) + { + if( !xValues.edgeSet[vIndex] ) + { + mesh.addOutOfCorePoint( vertex ); + xValues.edgeSet[ vIndex ] = 1; + xValues.edgeKeys[ vIndex ] = key; + xValues.edgeVertexMap[key] = hashed_vertex = std::pair< int , Vertex >( vOffset , vertex ); + stillOwner = true; + vOffset++; + } + } + if( stillOwner ) + { + // We only need to pass the iso-vertex down if the edge it lies on is adjacent to a coarser leaf + bool isNeeded = ( !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[2*x][1][1] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[2*x][2*y][1] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[1][2*y][1] ) ); + if( isNeeded ) + { + int f[2]; + Cube::FacesAdjacentToEdge( e , f[0] , f[1] ); + for( int k=0 ; k<2 ; k++ ) + { + TreeOctNode* node = leaf; + LocalDepth _depth = depth; + int _slab = slab; + bool _isNeeded = isNeeded; + while( _isNeeded && _isValidSpaceNode( node->parent ) && Cube::IsFaceCorner( (int)(node-node->parent->children) , f[k] ) ) + { + node = node->parent , _depth-- , _slab >>= 1; + typename Octree::template _XSliceValues< Vertex >& _xValues = slabValues[_depth].xSliceValues( _slab ); +#pragma omp critical (add_x_coarser_point_access) + _xValues.edgeVertexMap[key] = hashed_vertex; + _isNeeded = ( !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[2*x][1][1] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[2*x][2*y][1] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[1][2*y][1] ) ); + } + } + } + } + } + } + } + } + } + } +} +template< class Real > +template< class Vertex > +void Octree< Real >::_copyFinerSliceIsoEdgeKeys( LocalDepth depth , int slice , std::vector< _SlabValues< Vertex > >& slabValues , int threads ) +{ + if( slice>0 ) _copyFinerSliceIsoEdgeKeys( depth , slice , 1 , slabValues , threads ); + if( slice<(1< +template< class Vertex > +void Octree< Real >::_copyFinerSliceIsoEdgeKeys( LocalDepth depth , int slice , int z , std::vector< _SlabValues< Vertex > >& slabValues , int threads ) +{ + _SliceValues< Vertex >& pSliceValues = slabValues[depth ].sliceValues(slice ); + _SliceValues< Vertex >& cSliceValues = slabValues[depth+1].sliceValues(slice<<1); + typename SortedTreeNodes::SliceTableData& pSliceData = pSliceValues.sliceData; + typename SortedTreeNodes::SliceTableData& cSliceData = cSliceValues.sliceData; +#pragma omp parallel for num_threads( threads ) + for( int i=_sNodesBegin(depth,slice-z) ; i<_sNodesEnd(depth,slice-z) ; i++ ) if( _isValidSpaceNode( _sNodes.treeNodes[i] ) ) + if( IsActiveNode( _sNodes.treeNodes[i]->children ) ) + { + typename SortedTreeNodes::SquareEdgeIndices& pIndices = pSliceData.edgeIndices( i ); + // Copy the edges that overlap the coarser edges + for( int orientation=0 ; orientation<2 ; orientation++ ) for( int y=0 ; y<2 ; y++ ) + { + int fe = Square::EdgeIndex( orientation , y ); + int pIndex = pIndices[fe]; + if( !pSliceValues.edgeSet[ pIndex ] ) + { + int ce = Cube::EdgeIndex( orientation , y , z ); + int c1 , c2; + switch( orientation ) + { + case 0: c1 = Cube::CornerIndex( 0 , y , z ) , c2 = Cube::CornerIndex( 1 , y , z ) ; break; + case 1: c1 = Cube::CornerIndex( y , 0 , z ) , c2 = Cube::CornerIndex( y , 1 , z ) ; break; + } + // [SANITY CHECK] +// if( _isValidSpaceNode( _sNodes.treeNodes[i]->children + c1 )!=_isValidSpaceNode( _sNodes.treeNodes[i]->children + c2 ) ) fprintf( stderr , "[WARNING] Finer edges should both be valid or invalid\n" ) , exit( 0 ); + if( !_isValidSpaceNode( _sNodes.treeNodes[i]->children + c1 ) || !_isValidSpaceNode( _sNodes.treeNodes[i]->children + c2 ) ) continue; + + int cIndex1 = cSliceData.edgeIndices( _sNodes.treeNodes[i]->children + c1 )[fe]; + int cIndex2 = cSliceData.edgeIndices( _sNodes.treeNodes[i]->children + c2 )[fe]; + if( cSliceValues.edgeSet[cIndex1] != cSliceValues.edgeSet[cIndex2] ) + { + long long key; + if( cSliceValues.edgeSet[cIndex1] ) key = cSliceValues.edgeKeys[cIndex1]; + else key = cSliceValues.edgeKeys[cIndex2]; + std::pair< int , Vertex > vPair = cSliceValues.edgeVertexMap.find( key )->second; +#pragma omp critical ( copy_finer_edge_keys ) + pSliceValues.edgeVertexMap[key] = vPair; + pSliceValues.edgeKeys[pIndex] = key; + pSliceValues.edgeSet[pIndex] = 1; + } + else if( cSliceValues.edgeSet[cIndex1] && cSliceValues.edgeSet[cIndex2] ) + { + long long key1 = cSliceValues.edgeKeys[cIndex1] , key2 = cSliceValues.edgeKeys[cIndex2]; +#pragma omp critical ( set_edge_pairs ) + pSliceValues.vertexPairMap[ key1 ] = key2 , pSliceValues.vertexPairMap[ key2 ] = key1; + + const TreeOctNode* node = _sNodes.treeNodes[i]; + LocalDepth _depth = depth; + int _slice = slice; + while( _isValidSpaceNode( node->parent ) && Cube::IsEdgeCorner( (int)( node - node->parent->children ) , ce ) ) + { + node = node->parent , _depth-- , _slice >>= 1; + _SliceValues< Vertex >& _pSliceValues = slabValues[_depth].sliceValues(_slice); +#pragma omp critical ( set_edge_pairs ) + _pSliceValues.vertexPairMap[ key1 ] = key2 , _pSliceValues.vertexPairMap[ key2 ] = key1; + } + } + } + } + } +} +template< class Real > +template< class Vertex > +void Octree< Real >::_copyFinerXSliceIsoEdgeKeys( LocalDepth depth , int slab , std::vector< _SlabValues< Vertex > >& slabValues , int threads ) +{ + _XSliceValues< Vertex >& pSliceValues = slabValues[depth ].xSliceValues(slab); + _XSliceValues< Vertex >& cSliceValues0 = slabValues[depth+1].xSliceValues( (slab<<1)|0 ); + _XSliceValues< Vertex >& cSliceValues1 = slabValues[depth+1].xSliceValues( (slab<<1)|1 ); + typename SortedTreeNodes::XSliceTableData& pSliceData = pSliceValues.xSliceData; + typename SortedTreeNodes::XSliceTableData& cSliceData0 = cSliceValues0.xSliceData; + typename SortedTreeNodes::XSliceTableData& cSliceData1 = cSliceValues1.xSliceData; +#pragma omp parallel for num_threads( threads ) + for( int i=_sNodesBegin(depth,slab) ; i<_sNodesEnd(depth,slab) ; i++ ) if( _isValidSpaceNode( _sNodes.treeNodes[i] ) ) + if( IsActiveNode( _sNodes.treeNodes[i]->children ) ) + { + typename SortedTreeNodes::SquareCornerIndices& pIndices = pSliceData.edgeIndices( i ); + for( int x=0 ; x<2 ; x++ ) for( int y=0 ; y<2 ; y++ ) + { + int fc = Square::CornerIndex( x , y ); + int pIndex = pIndices[fc]; + if( !pSliceValues.edgeSet[pIndex] ) + { + int c0 = Cube::CornerIndex( x , y , 0 ) , c1 = Cube::CornerIndex( x , y , 1 ); + + // [SANITY CHECK] +// if( _isValidSpaceNode( _sNodes.treeNodes[i]->children + c0 )!=_isValidSpaceNode( _sNodes.treeNodes[i]->children + c1 ) ) fprintf( stderr , "[ERROR] Finer edges should both be valid or invalid\n" ) , exit( 0 ); + if( !_isValidSpaceNode( _sNodes.treeNodes[i]->children + c0 ) || !_isValidSpaceNode( _sNodes.treeNodes[i]->children + c1 ) ) continue; + + int cIndex0 = cSliceData0.edgeIndices( _sNodes.treeNodes[i]->children + c0 )[fc]; + int cIndex1 = cSliceData1.edgeIndices( _sNodes.treeNodes[i]->children + c1 )[fc]; + if( cSliceValues0.edgeSet[cIndex0] != cSliceValues1.edgeSet[cIndex1] ) + { + long long key; + std::pair< int , Vertex > vPair; + if( cSliceValues0.edgeSet[cIndex0] ) key = cSliceValues0.edgeKeys[cIndex0] , vPair = cSliceValues0.edgeVertexMap.find( key )->second; + else key = cSliceValues1.edgeKeys[cIndex1] , vPair = cSliceValues1.edgeVertexMap.find( key )->second; +#pragma omp critical ( copy_finer_x_edge_keys ) + pSliceValues.edgeVertexMap[key] = vPair; + pSliceValues.edgeKeys[ pIndex ] = key; + pSliceValues.edgeSet[ pIndex ] = 1; + } + else if( cSliceValues0.edgeSet[cIndex0] && cSliceValues1.edgeSet[cIndex1] ) + { + long long key0 = cSliceValues0.edgeKeys[cIndex0] , key1 = cSliceValues1.edgeKeys[cIndex1]; +#pragma omp critical ( set_x_edge_pairs ) + pSliceValues.vertexPairMap[ key0 ] = key1 , pSliceValues.vertexPairMap[ key1 ] = key0; + const TreeOctNode* node = _sNodes.treeNodes[i]; + LocalDepth _depth = depth; + int _slab = slab , ce = Cube::CornerIndex( 2 , x , y ); + while( _isValidSpaceNode( node->parent ) && Cube::IsEdgeCorner( (int)( node - node->parent->children ) , ce ) ) + { + node = node->parent , _depth-- , _slab>>= 1; + _SliceValues< Vertex >& _pSliceValues = slabValues[_depth].sliceValues(_slab); +#pragma omp critical ( set_x_edge_pairs ) + _pSliceValues.vertexPairMap[ key0 ] = key1 , _pSliceValues.vertexPairMap[ key1 ] = key0; + } + } + } + } + } +} +template< class Real > +template< class Vertex > +void Octree< Real >::_setSliceIsoEdges( LocalDepth depth , int slice , std::vector< _SlabValues< Vertex > >& slabValues , int threads ) +{ + if( slice>0 ) _setSliceIsoEdges( depth , slice , 1 , slabValues , threads ); + if( slice<(1< +template< class Vertex > +void Octree< Real >::_setSliceIsoEdges( LocalDepth depth , int slice , int z , std::vector< _SlabValues< Vertex > >& slabValues , int threads ) +{ + typename Octree::template _SliceValues< Vertex >& sValues = slabValues[depth].sliceValues( slice ); + std::vector< ConstAdjacenctNodeKey > neighborKeys( std::max< int >( 1 , threads ) ); + for( size_t i=0 ; ichildren ) ) + { + int idx = i - sValues.sliceData.nodeOffset; + const typename SortedTreeNodes::SquareEdgeIndices& eIndices = sValues.sliceData.edgeIndices( leaf ); + const typename SortedTreeNodes::SquareFaceIndices& fIndices = sValues.sliceData.faceIndices( leaf ); + unsigned char mcIndex = sValues.mcIndices[idx]; + if( !sValues.faceSet[ fIndices[0] ] ) + { + neighborKey.getNeighbors( leaf ); + if( !IsActiveNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[1][1][2*z] ) || !IsActiveNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[1][1][2*z]->children ) ) + { + _FaceEdges fe; + fe.count = MarchingSquares::AddEdgeIndices( mcIndex , isoEdges ); + for( int j=0 ; j edges; + edges.resize( fe.count ); + for( int j=0 ; jparent ) && Cube::IsFaceCorner( (int)(node-node->parent->children) , f ) ) + { + node = node->parent , _depth-- , _slice >>= 1; + if( IsActiveNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[1][1][2*z] ) && IsActiveNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[1][1][2*z]->children ) ) break; + long long key = VertexData::FaceIndex( node , f , _localToGlobal(_maxDepth) ); +#pragma omp critical( add_iso_edge_access ) + { + typename Octree::template _SliceValues< Vertex >& _sValues = slabValues[_depth].sliceValues( _slice ); + typename std::unordered_map< long long, std::vector< _IsoEdge > >::iterator iter = _sValues.faceEdgeMap.find(key); + if( iter==_sValues.faceEdgeMap.end() ) _sValues.faceEdgeMap[key] = edges; + else for( int j=0 ; jsecond.push_back( fe.edges[j] ); + } + } + } + } + } + } +} +template< class Real > +template< class Vertex > +void Octree< Real >::_setXSliceIsoEdges( LocalDepth depth , int slab , std::vector< _SlabValues< Vertex > >& slabValues , int threads ) +{ + typename Octree::template _SliceValues< Vertex >& bValues = slabValues[depth].sliceValues ( slab ); + typename Octree::template _SliceValues< Vertex >& fValues = slabValues[depth].sliceValues ( slab+1 ); + typename Octree::template _XSliceValues< Vertex >& xValues = slabValues[depth].xSliceValues( slab ); + + std::vector< ConstAdjacenctNodeKey > neighborKeys( std::max< int >( 1 , threads ) ); + for( size_t i=0 ; ichildren ) ) + { + const typename SortedTreeNodes::SquareCornerIndices& cIndices = xValues.xSliceData.edgeIndices( leaf ); + const typename SortedTreeNodes::SquareEdgeIndices& eIndices = xValues.xSliceData.faceIndices( leaf ); + unsigned char mcIndex = ( bValues.mcIndices[ i - bValues.sliceData.nodeOffset ] ) | ( fValues.mcIndices[ i - fValues.sliceData.nodeOffset ]<<4 ); + { + neighborKey.getNeighbors( leaf ); + for( int o=0 ; o<2 ; o++ ) for( int x=0 ; x<2 ; x++ ) + { + int e = Square::EdgeIndex( o , x ); + int f = Cube::FaceIndex( 1-o , x ); + unsigned char _mcIndex = MarchingCubes::GetFaceIndex( mcIndex , f ); + int xx = o==1 ? 2*x : 1 , yy = o==0 ? 2*x : 1 , zz = 1; + if( !xValues.faceSet[ eIndices[e] ] && ( !IsActiveNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[xx][yy][zz] ) || !IsActiveNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[xx][yy][zz]->children ) ) ) + { + _FaceEdges fe; + fe.count = MarchingSquares::AddEdgeIndices( _mcIndex , isoEdges ); + for( int j=0 ; j& sValues = (_x==0) ? bValues : fValues; + int idx = sValues.sliceData.edgeIndices(i)[ Square::EdgeIndex(o,x) ]; + if( !sValues.edgeSet[ idx ] ) fprintf( stderr , "[ERROR] Edge not set 5: %d / %d\n" , slab , 1< edges; + edges.resize( fe.count ); + for( int j=0 ; jparent ) && Cube::IsFaceCorner( (int)(node-node->parent->children) , f ) ) + { + node = node->parent , _depth-- , _slab >>= 1; + if( IsActiveNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[xx][yy][zz] ) && IsActiveNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[xx][yy][zz]->children ) ) break; + long long key = VertexData::FaceIndex( node , f , _localToGlobal(_maxDepth) ); +#pragma omp critical( add_x_iso_edge_access ) + { + typename Octree::template _XSliceValues< Vertex >& _xValues = slabValues[_depth].xSliceValues( _slab ); + typename std::unordered_map< long long, std::vector< _IsoEdge > >::iterator iter = _xValues.faceEdgeMap.find(key); + if( iter==_xValues.faceEdgeMap.end() ) _xValues.faceEdgeMap[key] = edges; + else for( int j=0 ; jsecond.push_back( fe.edges[j] ); + } + } + } + } + } + } + } +} +template< class Real > +template< class Vertex > +void Octree< Real >::_setIsoSurface( LocalDepth depth , int offset , const _SliceValues< Vertex >& bValues , const _SliceValues< Vertex >& fValues , const _XSliceValues< Vertex >& xValues , CoredMeshData< Vertex >& mesh , bool polygonMesh , bool addBarycenter , int& vOffset , int threads ) +{ + std::vector< std::pair< int , Vertex > > polygon; + std::vector< std::vector< _IsoEdge > > edgess( std::max< int >( 1 , threads ) ); +#pragma omp parallel for num_threads( threads ) + for( int i=_sNodesBegin(depth,offset) ; i<_sNodesEnd(depth,offset) ; i++ ) if( _isValidSpaceNode( _sNodes.treeNodes[i] ) ) + { + std::vector< _IsoEdge >& edges = edgess[ omp_get_thread_num() ]; + TreeOctNode* leaf = _sNodes.treeNodes[i]; + int res = 1<=0 && off[0]=0 && off[1]=0 && off[2]children ) ) + { + edges.clear(); + unsigned char mcIndex = ( bValues.mcIndices[ i - bValues.sliceData.nodeOffset ] ) | ( fValues.mcIndices[ i - fValues.sliceData.nodeOffset ]<<4 ); + // [WARNING] Just because the node looks empty doesn't mean it doesn't get eges from finer neighbors + { + // Gather the edges from the faces (with the correct orientation) + for( int f=0 ; f& sValues = (o==0) ? bValues : fValues; + int fIdx = sValues.sliceData.faceIndices(i)[0]; + if( sValues.faceSet[fIdx] ) + { + const _FaceEdges& fe = sValues.faceEdges[ fIdx ]; + for( int j=0 ; j >::const_iterator iter = sValues.faceEdgeMap.find(key); + if( iter!=sValues.faceEdgeMap.end() ) + { + const std::vector< _IsoEdge >& _edges = iter->second; + for( size_t j=0 ; j<_edges.size() ; j++ ) edges.push_back( _IsoEdge( _edges[j][flip] , _edges[j][1-flip] ) ); + } + else fprintf( stderr , "[ERROR] Invalid faces: %d %d %d\n" , i , d , o ) , exit( 0 ); + } + } + else + { + int fIdx = xValues.xSliceData.faceIndices(i)[ Square::EdgeIndex( 1-d , o ) ]; + if( xValues.faceSet[fIdx] ) + { + const _FaceEdges& fe = xValues.faceEdges[ fIdx ]; + for( int j=0 ; j >::const_iterator iter = xValues.faceEdgeMap.find(key); + if( iter!=xValues.faceEdgeMap.end() ) + { + const std::vector< _IsoEdge >& _edges = iter->second; + for( size_t j=0 ; j<_edges.size() ; j++ ) edges.push_back( _IsoEdge( _edges[j][flip] , _edges[j][1-flip] ) ); + } + else fprintf( stderr , "[ERROR] Invalid faces: %d %d %d\n" , i , d , o ) , exit( 0 ); + } + } + } + // Get the edge loops + std::vector< std::vector< long long > > loops; + while( edges.size() ) + { + loops.resize( loops.size()+1 ); + _IsoEdge edge = edges.back(); + edges.pop_back(); + long long start = edge[0] , current = edge[1]; + while( current!=start ) + { + int idx; + for( idx=0 ; idx<(int)edges.size() ; idx++ ) if( edges[idx][0]==current ) break; + if( idx==edges.size() ) + { + typename std::unordered_map< long long, long long >::const_iterator iter; + if ( (iter=bValues.vertexPairMap.find(current))!=bValues.vertexPairMap.end() ) loops.back().push_back( current ) , current = iter->second; + else if( (iter=fValues.vertexPairMap.find(current))!=fValues.vertexPairMap.end() ) loops.back().push_back( current ) , current = iter->second; + else if( (iter=xValues.vertexPairMap.find(current))!=xValues.vertexPairMap.end() ) loops.back().push_back( current ) , current = iter->second; + else + { + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( leaf , d , off ); + fprintf( stderr , "[ERROR] Failed to close loop [%d: %d %d %d] | (%d): %lld\n" , d-1 , off[0] , off[1] , off[2] , i , current ); + exit( 0 ); + } + } + else + { + loops.back().push_back( current ); + current = edges[idx][1]; + edges[idx] = edges.back() , edges.pop_back(); + } + } + loops.back().push_back( start ); + } + // Add the loops to the mesh + for( size_t j=0 ; j > polygon( loops[j].size() ); + for( size_t k=0 ; k >::const_iterator iter; + if ( ( iter=bValues.edgeVertexMap.find( key ) )!=bValues.edgeVertexMap.end() ) polygon[k] = iter->second; + else if( ( iter=fValues.edgeVertexMap.find( key ) )!=fValues.edgeVertexMap.end() ) polygon[k] = iter->second; + else if( ( iter=xValues.edgeVertexMap.find( key ) )!=xValues.edgeVertexMap.end() ) polygon[k] = iter->second; + else fprintf( stderr , "[ERROR] Couldn't find vertex in edge map\n" ) , exit( 0 ); + } + _addIsoPolygons( mesh , polygon , polygonMesh , addBarycenter , vOffset ); + } + } + } + } +} +template< class Real > void SetColor( Point3D< 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 SetIsoVertex( PlyVertex< float >& vertex , Point3D< Real > color , Real value ){ ; } +template< class Real > void SetIsoVertex( PlyColorVertex< float >& vertex , Point3D< Real > color , Real value ){ SetColor( color , vertex.color ); } +template< class Real > void SetIsoVertex( PlyValueVertex< float >& vertex , Point3D< Real > color , Real value ){ vertex.value = float(value); } +template< class Real > void SetIsoVertex( PlyColorAndValueVertex< float >& vertex , Point3D< Real > color , Real value ){ SetColor( color , vertex.color ) , vertex.value = float(value); } +template< class Real > void SetIsoVertex( PlyVertex< double >& vertex , Point3D< Real > color , Real value ){ ; } +template< class Real > void SetIsoVertex( PlyColorVertex< double >& vertex , Point3D< Real > color , Real value ){ SetColor( color , vertex.color ); } +template< class Real > void SetIsoVertex( PlyValueVertex< double >& vertex , Point3D< Real > color , Real value ){ vertex.value = double(value); } +template< class Real > void SetIsoVertex( PlyColorAndValueVertex< double >& vertex , Point3D< Real > color , Real value ){ SetColor( color , vertex.color ) , vertex.value = double(value); } + +template< class Real > +template< int WeightDegree , int ColorDegree , BoundaryType BType , class Vertex > +bool Octree< Real >::_getIsoVertex( const BSplineData< ColorDegree , BType >* colorBSData , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Point3D< Real > , Real > , ColorDegree >* colorData , Real isoValue , ConstPointSupportKey< WeightDegree >& weightKey , ConstPointSupportKey< ColorDegree >& colorKey , const TreeOctNode* node , int edgeIndex , int z , const _SliceValues< Vertex >& sValues , Vertex& vertex ) +{ + Point3D< Real > position; + int c0 , c1; + Square::EdgeCorners( edgeIndex , c0 , c1 ); + + bool nonLinearFit = sValues.cornerGradients!=NullPointer( Point3D< Real > ); + const typename SortedTreeNodes::SquareCornerIndices& idx = sValues.sliceData.cornerIndices( node ); + Real x0 = sValues.cornerValues[idx[c0]] , x1 = sValues.cornerValues[idx[c1]]; + Point3D< Real > s; + Real start , width; + _startAndWidth( node , s , width ); + int o , y; + Square::FactorEdgeIndex( edgeIndex , o , y ); + start = s[o]; + switch( o ) + { + case 0: + position[1] = s[1] + width*y; + position[2] = s[2] + width*z; + break; + case 1: + position[0] = s[0] + width*y; + position[2] = s[2] + width*z; + break; + } + + double averageRoot; + bool rootFound = false; + if( nonLinearFit ) + { + double dx0 = sValues.cornerGradients[idx[c0]][o] * width , dx1 = sValues.cornerGradients[idx[c1]][o] * width; + + // The scaling will turn the Hermite Spline into a quadratic + double scl = (x1-x0) / ( (dx1+dx0 ) / 2 ); + dx0 *= scl , dx1 *= scl; + + // Hermite Spline + Polynomial< 2 > P; + P.coefficients[0] = x0; + P.coefficients[1] = dx0; + P.coefficients[2] = 3*(x1-x0)-dx1-2*dx0; + + double roots[2]; + int rCount = 0 , rootCount = P.getSolutions( isoValue , roots , 0 ); + averageRoot = 0; + for( int i=0 ; i=0 && roots[i]<=1 ) averageRoot += roots[i] , rCount++; + if( rCount ) rootFound = true; + averageRoot /= rCount; + } + if( !rootFound ) + { + // We have a linear function L, with L(0) = x0 and L(1) = x1 + // => L(t) = x0 + t * (x1-x0) + // => L(t) = isoValue <=> t = ( isoValue - x0 ) / ( x1 - x0 ) + if( x0==x1 ) fprintf( stderr , "[ERROR] Not a zero-crossing root: %g %g\n" , x0 , x1 ) , exit( 0 ); + averageRoot = ( isoValue - x0 ) / ( x1 - x0 ); + } + if( averageRoot<0 || averageRoot>1 ) + { + fprintf( stderr , "[WARNING] Bad average root: %f\n" , averageRoot ); + fprintf( stderr , "\t(%f %f) (%f)\n" , x0 , x1 , isoValue ); + if( averageRoot<0 ) averageRoot = 0; + if( averageRoot>1 ) averageRoot = 1; + } + position[o] = Real( start + width*averageRoot ); + vertex.point = position; + Point3D< Real > color; + Real depth(0); + if( densityWeights ) + { + Real weight; + _getSampleDepthAndWeight( *densityWeights , node , position , weightKey , depth , weight ); + } + if( colorData ) color = Point3D< Real >( _evaluate< ProjectiveData< Point3D< Real > , Real > >( *colorData , position , *colorBSData , colorKey ) ); + SetIsoVertex( vertex , color , depth ); + return true; +} +template< class Real > +template< int WeightDegree , int ColorDegree , BoundaryType BType , class Vertex > +bool Octree< Real >::_getIsoVertex( const BSplineData< ColorDegree , BType >* colorBSData , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Point3D< Real > , Real > , ColorDegree >* colorData , Real isoValue , ConstPointSupportKey< WeightDegree >& weightKey , ConstPointSupportKey< ColorDegree >& colorKey , const TreeOctNode* node , int cornerIndex , const _SliceValues< Vertex >& bValues , const _SliceValues< Vertex >& fValues , Vertex& vertex ) +{ + Point3D< Real > position; + + bool nonLinearFit = bValues.cornerGradients!=NullPointer( Point3D< Real > ) && fValues.cornerGradients!=NullPointer( Point3D< Real > ); + const typename SortedTreeNodes::SquareCornerIndices& idx0 = bValues.sliceData.cornerIndices( node ); + const typename SortedTreeNodes::SquareCornerIndices& idx1 = fValues.sliceData.cornerIndices( node ); + Real x0 = bValues.cornerValues[ idx0[cornerIndex] ] , x1 = fValues.cornerValues[ idx1[cornerIndex] ]; + Point3D< Real > s; + Real start , width; + _startAndWidth( node , s , width ); + start = s[2]; + int x , y; + Square::FactorCornerIndex( cornerIndex , x , y ); + + + position[0] = s[0] + width*x; + position[1] = s[1] + width*y; + + double averageRoot; + + bool rootFound = false; + if( nonLinearFit ) + { + double dx0 = bValues.cornerGradients[ idx0[cornerIndex] ][2] * width , dx1 = fValues.cornerGradients[ idx1[cornerIndex] ][2] * width; + // The scaling will turn the Hermite Spline into a quadratic + double scl = (x1-x0) / ( (dx1+dx0 ) / 2 ); + dx0 *= scl , dx1 *= scl; + + // Hermite Spline + Polynomial< 2 > P; + P.coefficients[0] = x0; + P.coefficients[1] = dx0; + P.coefficients[2] = 3*(x1-x0)-dx1-2*dx0; + + double roots[2]; + int rCount = 0 , rootCount = P.getSolutions( isoValue , roots , 0 ); + averageRoot = 0; + for( int i=0 ; i=0 && roots[i]<=1 ) averageRoot += roots[i] , rCount++; + if( rCount ) rootFound = true; + averageRoot /= rCount; + } + if( !rootFound ) + { + // We have a linear function L, with L(0) = x0 and L(1) = x1 + // => L(t) = x0 + t * (x1-x0) + // => L(t) = isoValue <=> t = ( isoValue - x0 ) / ( x1 - x0 ) + if( x0==x1 ) fprintf( stderr , "[ERROR] Not a zero-crossing root: %g %g\n" , x0 , x1 ) , exit( 0 ); + averageRoot = ( isoValue - x0 ) / ( x1 - x0 ); + } + if( averageRoot<0 || averageRoot>1 ) + { + fprintf( stderr , "[WARNING] Bad average root: %f\n" , averageRoot ); + fprintf( stderr , "\t(%f %f) (%f)\n" , x0 , x1 , isoValue ); + if( averageRoot<0 ) averageRoot = 0; + if( averageRoot>1 ) averageRoot = 1; + } + position[2] = Real( start + width*averageRoot ); + vertex.point = position; + Point3D< Real > color; + Real depth(0); + if( densityWeights ) + { + Real weight; + _getSampleDepthAndWeight( *densityWeights , node , position , weightKey , depth , weight ); + } + if( colorData ) color = Point3D< Real >( _evaluate< ProjectiveData< Point3D< Real > , Real > >( *colorData , position , *colorBSData , colorKey ) ); + SetIsoVertex( vertex , color , depth ); + return true; +} + +template< class Real > +template< class Vertex > +int Octree< Real >::_addIsoPolygons( CoredMeshData< Vertex >& mesh , std::vector< std::pair< int , Vertex > >& polygon , bool polygonMesh , bool addBarycenter , int& vOffset ) +{ + if( polygonMesh ) + { + std::vector< int > vertices( polygon.size() ); + for( int i=0 ; i<(int)polygon.size() ; i++ ) vertices[i] = polygon[polygon.size()-1-i].first; + mesh.addPolygon_s( vertices ); + return 1; + } + if( polygon.size()>3 ) + { + bool isCoplanar = false; + std::vector< int > triangle( 3 ); + + if( addBarycenter ) + for( int i=0 ; i<(int)polygon.size() ; i++ ) + for( int j=0 ; j MAT; + std::vector< Point3D< Real > > vertices; + std::vector< TriangleIndex > triangles; + vertices.resize( polygon.size() ); + // Add the points + for( int i=0 ; i<(int)polygon.size() ; i++ ) vertices[i] = polygon[i].second.point; + MAT.GetTriangulation( vertices , triangles ); + for( int i=0 ; i<(int)triangles.size() ; i++ ) + { + for( int j=0 ; j<3 ; j++ ) triangle[2-j] = polygon[ triangles[i].idx[j] ].first; + mesh.addPolygon_s( triangle ); + } + } + } + else if( polygon.size()==3 ) + { + std::vector< int > vertices( 3 ); + for( int i=0 ; i<3 ; i++ ) vertices[2-i] = polygon[i].first; + mesh.addPolygon_s( vertices ); + } + return (int)polygon.size()-2; +} diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.SortedTreeNodes.inl b/src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.SortedTreeNodes.inl new file mode 100644 index 000000000..7efc9f879 --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.SortedTreeNodes.inl @@ -0,0 +1,357 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +///////////////////// +// SortedTreeNodes // +///////////////////// +SortedTreeNodes::SortedTreeNodes( void ) +{ + _sliceStart = NullPointer( Pointer( int ) ); + treeNodes = NullPointer( TreeOctNode* ); + _levels = 0; +} +SortedTreeNodes::~SortedTreeNodes( void ) +{ + if( _sliceStart ) for( int d=0 ; d<_levels ; d++ ) FreePointer( _sliceStart[d] ); + FreePointer( _sliceStart ); + DeletePointer( treeNodes ); +} +void SortedTreeNodes::set( TreeOctNode& root , std::vector< int >* map ) +{ + set( root ); + + if( map ) + { + map->resize( _sliceStart[_levels-1][(size_t)1<<(_levels-1)] ); + for( int i=0 ; i<_sliceStart[_levels-1][(size_t)1<<(_levels-1)] ; i++ ) (*map)[i] = treeNodes[i]->nodeData.nodeIndex; + } + for( int i=0 ; i<_sliceStart[_levels-1][(size_t)1<<(_levels-1)] ; i++ ) treeNodes[i]->nodeData.nodeIndex = i; +} +void SortedTreeNodes::set( TreeOctNode& root ) +{ + _levels = root.maxDepth()+1; + + if( _sliceStart ) for( int d=0 ; d<_levels ; d++ ) FreePointer( _sliceStart[d] ); + FreePointer( _sliceStart ); + DeletePointer( treeNodes ); + + _sliceStart = AllocPointer< Pointer( int ) >( _levels ); + for( int l=0 ; l<_levels ; l++ ) + { + _sliceStart[l] = AllocPointer< int >( ((size_t)1<depthAndOffset( d , off ); + _sliceStart[d][ off[2]+1 ]++; + } + + // Get the start index for each slice + { + int levelOffset = 0; + for( int l=0 ; l<_levels ; l++ ) + { + _sliceStart[l][0] = levelOffset; + for( int s=0 ; s<((size_t)1<( _sliceStart[_levels-1][(size_t)1<<(_levels-1)] ); + + // Add the tree nodes + for( TreeOctNode* node=root.nextNode() ; node ; node=root.nextNode( node ) ) if( !GetGhostFlag( node ) ) + { + int d , off[3]; + node->depthAndOffset( d , off ); + treeNodes[ _sliceStart[d][ off[2] ]++ ] = node; + } + + // Shift the slice offsets up since we incremented as we added + for( int l=0 ; l<_levels ; l++ ) + { + for( int s=(1<0 ; s-- ) _sliceStart[l][s] = _sliceStart[l][s-1]; + _sliceStart[l][0] = l>0 ? _sliceStart[l-1][(size_t)1<<(l-1)] : 0; + } +} +SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::SliceTableData::cornerIndices( const TreeOctNode* node ) { return cTable[ node->nodeData.nodeIndex - nodeOffset ]; } +SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::SliceTableData::cornerIndices( int idx ) { return cTable[ idx - nodeOffset ]; } +const SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::SliceTableData::cornerIndices( const TreeOctNode* node ) const { return cTable[ node->nodeData.nodeIndex - nodeOffset ]; } +const SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::SliceTableData::cornerIndices( int idx ) const { return cTable[ idx - nodeOffset ]; } +SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::SliceTableData::edgeIndices( const TreeOctNode* node ) { return eTable[ node->nodeData.nodeIndex - nodeOffset ]; } +SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::SliceTableData::edgeIndices( int idx ) { return eTable[ idx - nodeOffset ]; } +const SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::SliceTableData::edgeIndices( const TreeOctNode* node ) const { return eTable[ node->nodeData.nodeIndex - nodeOffset ]; } +const SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::SliceTableData::edgeIndices( int idx ) const { return eTable[ idx - nodeOffset ]; } +SortedTreeNodes::SquareFaceIndices& SortedTreeNodes::SliceTableData::faceIndices( const TreeOctNode* node ) { return fTable[ node->nodeData.nodeIndex - nodeOffset ]; } +SortedTreeNodes::SquareFaceIndices& SortedTreeNodes::SliceTableData::faceIndices( int idx ) { return fTable[ idx - nodeOffset ]; } +const SortedTreeNodes::SquareFaceIndices& SortedTreeNodes::SliceTableData::faceIndices( const TreeOctNode* node ) const { return fTable[ node->nodeData.nodeIndex - nodeOffset ]; } +const SortedTreeNodes::SquareFaceIndices& SortedTreeNodes::SliceTableData::faceIndices( int idx ) const { return fTable[ idx - nodeOffset ]; } +SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::XSliceTableData::edgeIndices( const TreeOctNode* node ) { return eTable[ node->nodeData.nodeIndex - nodeOffset ]; } +SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::XSliceTableData::edgeIndices( int idx ) { return eTable[ idx - nodeOffset ]; } +const SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::XSliceTableData::edgeIndices( const TreeOctNode* node ) const { return eTable[ node->nodeData.nodeIndex - nodeOffset ]; } +const SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::XSliceTableData::edgeIndices( int idx ) const { return eTable[ idx - nodeOffset ]; } +SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::XSliceTableData::faceIndices( const TreeOctNode* node ) { return fTable[ node->nodeData.nodeIndex - nodeOffset ]; } +SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::XSliceTableData::faceIndices( int idx ) { return fTable[ idx - nodeOffset ]; } +const SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::XSliceTableData::faceIndices( const TreeOctNode* node ) const { return fTable[ node->nodeData.nodeIndex - nodeOffset ]; } +const SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::XSliceTableData::faceIndices( int idx ) const { return fTable[ idx - nodeOffset ]; } + +void SortedTreeNodes::setSliceTableData( SliceTableData& sData , int depth , int offset , int threads ) const +{ + // [NOTE] This is structure is purely for determining adjacency and is independent of the FEM degree + typedef OctNode< TreeNodeData >::template ConstNeighborKey< 1 , 1 > ConstAdjacenctNodeKey; + if( offset<0 || offset>((size_t)1< span( _sliceStart[depth][ std::max< int >( 0 , offset-1 ) ] , _sliceStart[depth][ std::min< int >( (size_t)1<( sData.nodeCount * Square::CORNERS ); + sData._eMap = NewPointer< int >( sData.nodeCount * Square::EDGES ); + sData._fMap = NewPointer< int >( sData.nodeCount * Square::FACES ); + sData.cTable = NewPointer< typename SortedTreeNodes::SquareCornerIndices >( sData.nodeCount ); + sData.eTable = NewPointer< typename SortedTreeNodes::SquareCornerIndices >( sData.nodeCount ); + sData.fTable = NewPointer< typename SortedTreeNodes::SquareFaceIndices >( sData.nodeCount ); + memset( sData._cMap , 0 , sizeof(int) * sData.nodeCount * Square::CORNERS ); + memset( sData._eMap , 0 , sizeof(int) * sData.nodeCount * Square::EDGES ); + memset( sData._fMap , 0 , sizeof(int) * sData.nodeCount * Square::FACES ); + } + std::vector< ConstAdjacenctNodeKey > neighborKeys( std::max< int >( 1 , threads ) ); + for( size_t i=0 ; i& neighbors = neighborKey.getNeighbors( node ); + int d , off[3]; + node->depthAndOffset( d , off ); + int z; + if ( off[2]==offset-1 ) z = 1; + else if( off[2]==offset ) z = 0; + else fprintf( stderr , "[ERROR] Node out of bounds: %d %d\n" , offset , off[2] ) , exit( 0 ); + // Process the corners + for( int x=0 ; x<2 ; x++ ) for( int y=0 ; y<2 ; y++ ) + { + int c = Cube::CornerIndex( x , y , z ); + int fc = Square::CornerIndex( x , y ); + bool cornerOwner = true; + int ac = Cube::AntipodalCornerIndex(c); // The index of the node relative to the corner + for( int cc=0 ; cc::template ConstNeighborKey< 1 , 1 > ConstAdjacenctNodeKey; + if( offset<0 || offset>=((size_t)1< span( _sliceStart[depth][offset] , _sliceStart[depth][offset+1] ); + sData.nodeOffset = span.first; + sData.nodeCount = span.second - span.first; + + DeletePointer( sData._eMap ) ; DeletePointer( sData._fMap ); + DeletePointer( sData.eTable ) ; DeletePointer( sData.fTable ); + if( sData.nodeCount ) + { + sData._eMap = NewPointer< int >( sData.nodeCount * Square::CORNERS ); + sData._fMap = NewPointer< int >( sData.nodeCount * Square::EDGES ); + sData.eTable = NewPointer< typename SortedTreeNodes::SquareCornerIndices >( sData.nodeCount ); + sData.fTable = NewPointer< typename SortedTreeNodes::SquareEdgeIndices >( sData.nodeCount ); + memset( sData._eMap , 0 , sizeof(int) * sData.nodeCount * Square::CORNERS ); + memset( sData._fMap , 0 , sizeof(int) * sData.nodeCount * Square::EDGES ); + } + + std::vector< ConstAdjacenctNodeKey > neighborKeys( std::max< int >( 1 , threads ) ); + for( size_t i=0 ; i& neighbors = neighborKey.getNeighbors( node ); + int d , off[3]; + node->depthAndOffset( d , off ); + // Process the edges + int o=2; + for( int x=0 ; x<2 ; x++ ) for( int y=0 ; y<2 ; y++ ) + { + int fc = Square::CornerIndex( x , y ); + bool edgeOwner = true; + + int ac = Square::AntipodalCornerIndex( Square::CornerIndex( x , y ) ); + for( int cc=0 ; cc +struct _ConstraintCalculator_ +{ + static inline Real _CalculateConstraint_( const PointData< Real , HasGradients >& p , const Polynomial< Degree >& px , const Polynomial< Degree >& py , const Polynomial< Degree >& pz , const Polynomial< Degree >& dpx , const Polynomial< Degree >& dpy , const Polynomial< Degree >& dpz , Real valueWeight , Real gradientWeight ); + static inline Real _CalculateConstraint_( const PointData< Real , HasGradients >& p , const Polynomial< Degree >& px , const Polynomial< Degree >& py , const Polynomial< Degree >& pz , const Polynomial< Degree >& dpx , const Polynomial< Degree >& dpy , const Polynomial< Degree >& dpz ); +#if POINT_DATA_RES + static inline void _CalculateCoarser_( int c , PointData< Real , HasGradients >& p , Real value , Point3D< Real > gradient , Real valueWeight , Real gradientWeight ); +#else // !POINT_DATA_RES + static inline void _CalculateCoarser_( PointData< Real , HasGradients >& p , Real value , Point3D< Real > gradient , Real valueWeight , Real gradientWeight ); +#endif // POINT_DATA_RES + +}; +template< class Real , int Degree > +struct _ConstraintCalculator_< Real , Degree , false > +{ + static inline Real _CalculateConstraint_( const PointData< Real , false >& p , const Polynomial< Degree >& px , const Polynomial< Degree >& py , const Polynomial< Degree >& pz , const Polynomial< Degree >& dpx , const Polynomial< Degree >& dpy , const Polynomial< Degree >& dpz , Real valueWeight , Real gradientWeight ) + { +#if POINT_DATA_RES + Real constraint = 0; + for( int c=0 ; c::SAMPLES ; c++ ) if( p[c].weight ) + { + const Point3D< Real > q = p[c].position; + constraint += (Real)( px( q[0] ) * py( q[1] ) * pz( q[2] ) * p[c].weight * p[c].value ); + } + return constraint * valueWeight; +#else // !POINT_DATA_RES + const Point3D< Real > q = p.position; + return (Real)( px( q[0] ) * py( q[1] ) * pz( q[2] ) * p.weight * p.value ) * valueWeight; +#endif // POINT_DATA_RES + } + static inline Real _CalculateConstraint_( const PointData< Real , false >& p , const Polynomial< Degree >& px , const Polynomial< Degree >& py , const Polynomial< Degree >& pz , const Polynomial< Degree >& dpx , const Polynomial< Degree >& dpy , const Polynomial< Degree >& dpz ) + { +#if POINT_DATA_RES + Real constraint = 0; + for( int c=0 ; c::SAMPLES ; c++ ) if( p[c].weight ) + { + const Point3D< Real > q = p[c].position; + constraint += (Real)( px( q[0] ) * py( q[1] ) * pz( q[2] ) * p[c]._value ); + } + return constraint; +#else // !POINT_DATA_RES + const Point3D< Real > q = p.position; + return (Real)( px( q[0] ) * py( q[1] ) * pz( q[2] ) * p._value ); +#endif // POINT_DATA_RES + } +#if POINT_DATA_RES + static inline void _CalculateCoarser_( int c , PointData< Real , false >& p , Real value , Point3D< Real > gradient , Real valueWeight , Real gradientWeight ){ p[c]._value = value * valueWeight * p[c].weight; } +#else // !POINT_DATA_RES + static inline void _CalculateCoarser_( PointData< Real , false >& p , Real value , Point3D< Real > gradient , Real valueWeight , Real gradientWeight ){ p._value = value * valueWeight * p.weight; } +#endif // POINT_DATA_RES +}; +template< class Real , int Degree > +struct _ConstraintCalculator_< Real , Degree , true > +{ + static inline Real _CalculateConstraint_( const PointData< Real , true >& p , const Polynomial< Degree >& px , const Polynomial< Degree >& py , const Polynomial< Degree >& pz , const Polynomial< Degree >& dpx , const Polynomial< Degree >& dpy , const Polynomial< Degree >& dpz , Real valueWeight , Real gradientWeight ) + { +#if POINT_DATA_RES + Real constraint = 0; + for( int c=0 ; c::SAMPLES ; c++ ) if( p[c].weight ) + { + const Point3D< Real > q = p[c].position; + double _px = px( q[0] ) , _py = py( q[1] ) , _pz = pz( q[2] ); + constraint += + ( + (Real)( _px * _py * _pz * p[c].value ) * valueWeight + + Point3D< Real >::Dot( Point3D< Real >( dpx( q[0] ) * _py * _pz , _px * dpy( q[1] ) * _pz , _px * _py * dpz( q[2] ) ) , p[c].gradient ) * gradientWeight + ) * p[c].weight; + } + return constraint; +#else // !POINT_DATA_RES + const Point3D< Real > q = p.position; + double _px = px( q[0] ) , _py = py( q[1] ) , _pz = pz( q[2] ); + return + ( + (Real)( _px * _py * _pz * p.value ) * valueWeight + + Point3D< Real >::Dot( Point3D< Real >( dpx( q[0] ) * _py * _pz , _px * dpy( q[1] ) * _pz , _px * _py * dpz( q[2] ) ) , p.gradient ) * gradientWeight + ) * p.weight; +#endif // POINT_DATA_RES + } + static inline Real _CalculateConstraint_( const PointData< Real , true >& p , const Polynomial< Degree >& px , const Polynomial< Degree >& py , const Polynomial< Degree >& pz , const Polynomial< Degree >& dpx , const Polynomial< Degree >& dpy , const Polynomial< Degree >& dpz ) + { +#if POINT_DATA_RES + Real constraint = 0; + for( int c=0 ; c::SAMPLES ; c++ ) if( p[c].weight ) + { + const Point3D< Real > q = p[c].position; + double _px = px( q[0] ) , _py = py( q[1] ) , _pz = pz( q[2] ); + constraint += + (Real)( _px * _py * _pz * p[c]._value ) + + Point3D< Real >::Dot( Point3D< Real >( dpx( q[0] ) * _py * _pz , _px * dpy( q[1] ) * _pz , _px * _py * dpz( q[2] ) ) , p[c]._gradient ); + } + return constraint; +#else // !POINT_DATA_RES + const Point3D< Real > q = p.position; + double _px = px( q[0] ) , _py = py( q[1] ) , _pz = pz( q[2] ); + return + (Real)( _px * _py * _pz * p._value ) + + Point3D< Real >::Dot( Point3D< Real >( dpx( q[0] ) * _py * _pz , _px * dpy( q[1] ) * _pz , _px * _py * dpz( q[2] ) ) , p._gradient ); +#endif // POINT_DATA_RES + } +#if POINT_DATA_RES + static inline void _CalculateCoarser_( int c , PointData< Real , true >& p , Real value , Point3D< Real > gradient , Real valueWeight , Real gradientWeight ){ p[c]._value = value * valueWeight * p[c].weight ; p[c]._gradient = gradient * gradientWeight * p[c].weight; } +#else // !POINT_DATA_RES + static inline void _CalculateCoarser_( PointData< Real , true >& p , Real value , Point3D< Real > gradient , Real valueWeight , Real gradientWeight ){ p._value = value * valueWeight * p.weight ; p._gradient = gradient * gradientWeight * p.weight; } +#endif // POINT_DATA_RES +}; + +template< > +template< class I > +double FEMSystemFunctor< 0 , BOUNDARY_FREE >::_integrate( const I& integrator , const int off1[] , const int off2[] ) const +{ +#define D_DOT( D1 , D2 ) { integrator.dot( off1[0] , off2[0] , D1 , D2 ) , integrator.dot( off1[1] , off2[1] , D1 , D2 ) , integrator.dot( off1[2] , off2[2] , D1 , D2 ) } + double d00[] = D_DOT( 0 , 0 ); + return + ( + d00[0] * d00[1] * d00[2] + ) * massWeight; +#undef D_DOT +} +template< > +template< class I > +double FEMSystemFunctor< 0 , BOUNDARY_NEUMANN >::_integrate( const I& integrator , const int off1[] , const int off2[] ) const +{ +#define D_DOT( D1 , D2 ) { integrator.dot( off1[0] , off2[0] , D1 , D2 ) , integrator.dot( off1[1] , off2[1] , D1 , D2 ) , integrator.dot( off1[2] , off2[2] , D1 , D2 ) } + double d00[] = D_DOT( 0 , 0 ); + return + ( + d00[0] * d00[1] * d00[2] + ) * massWeight; +#undef D_DOT +} +template< > +template< class I > +double FEMSystemFunctor< 0 , BOUNDARY_DIRICHLET >::_integrate( const I& integrator , const int off1[] , const int off2[] ) const +{ +#define D_DOT( D1 , D2 ) { integrator.dot( off1[0] , off2[0] , D1 , D2 ) , integrator.dot( off1[1] , off2[1] , D1 , D2 ) , integrator.dot( off1[2] , off2[2] , D1 , D2 ) } + double d00[] = D_DOT( 0 , 0 ); + return + ( + d00[0] * d00[1] * d00[2] + ) * massWeight; +#undef D_DOT +} +template< > +template< class I > +double FEMSystemFunctor< 1 , BOUNDARY_FREE >::_integrate( const I& integrator , const int off1[] , const int off2[] ) const +{ +#define D_DOT( D1 , D2 ) { integrator.dot( off1[0] , off2[0] , D1 , D2 ) , integrator.dot( off1[1] , off2[1] , D1 , D2 ) , integrator.dot( off1[2] , off2[2] , D1 , D2 ) } + double d00[] = D_DOT( 0 , 0 ) , d11[] = D_DOT( 1 , 1 ); + return + ( + d00[0] * d00[1] * d00[2] + ) * massWeight + + + ( + d11[0] * d00[1] * d00[2] + + d11[1] * d00[2] * d00[0] + + d11[2] * d00[0] * d00[1] + ) * lapWeight; +#undef D_DOT +} +template< > +template< class I > +double FEMSystemFunctor< 1 , BOUNDARY_NEUMANN >::_integrate( const I& integrator , const int off1[] , const int off2[] ) const +{ +#define D_DOT( D1 , D2 ) { integrator.dot( off1[0] , off2[0] , D1 , D2 ) , integrator.dot( off1[1] , off2[1] , D1 , D2 ) , integrator.dot( off1[2] , off2[2] , D1 , D2 ) } + double d00[] = D_DOT( 0 , 0 ) , d11[] = D_DOT( 1 , 1 ); + return + ( + d00[0] * d00[1] * d00[2] + ) * massWeight + + + ( + d11[0] * d00[1] * d00[2] + + d11[1] * d00[2] * d00[0] + + d11[2] * d00[0] * d00[1] + ) * lapWeight; +#undef D_DOT +} +template< > +template< class I > +double FEMSystemFunctor< 1 , BOUNDARY_DIRICHLET >::_integrate( const I& integrator , const int off1[] , const int off2[] ) const +{ +#define D_DOT( D1 , D2 ) { integrator.dot( off1[0] , off2[0] , D1 , D2 ) , integrator.dot( off1[1] , off2[1] , D1 , D2 ) , integrator.dot( off1[2] , off2[2] , D1 , D2 ) } + double d00[] = D_DOT( 0 , 0 ) , d11[] = D_DOT( 1 , 1 ); + return + ( + d00[0] * d00[1] * d00[2] + ) * massWeight + + + ( + d11[0] * d00[1] * d00[2] + + d11[1] * d00[2] * d00[0] + + d11[2] * d00[0] * d00[1] + ) * lapWeight; +#undef D_DOT +} + +template< int FEMDegree , BoundaryType BType > +template< class I > +double FEMSystemFunctor< FEMDegree , BType >::_integrate( const I& integrator , const int off1[] , const int off2[] ) const +{ +#define D_DOT( D1 , D2 ) { integrator.dot( off1[0] , off2[0] , D1 , D2 ) , integrator.dot( off1[1] , off2[1] , D1 , D2 ) , integrator.dot( off1[2] , off2[2] , D1 , D2 ) } + double d00[] = D_DOT( 0 , 0 ) , d02[] = D_DOT( 0 , 2 ) , d20[] = D_DOT( 2 , 0 ) , d22[] = D_DOT( 2 , 2 ) , d11[] = D_DOT( 1 , 1 ); + return + ( + d00[0] * d00[1] * d00[2] + ) * massWeight + + + ( + d11[0] * d00[1] * d00[2] + + d11[1] * d00[2] * d00[0] + + d11[2] * d00[0] * d00[1] + ) * lapWeight + + + ( + d22[0] * d00[1] * d00[2] + // Unmixed + d22[1] * d00[2] * d00[0] + // Unmixed + d22[2] * d00[0] * d00[1] + // Unmixed + d00[0] * ( d02[1] * d20[2] + d20[1] * d02[2] ) + // Mixed + d00[1] * ( d02[2] * d20[0] + d20[2] * d02[0] ) + // Mixed + d00[2] * ( d02[0] * d20[1] + d20[0] * d02[1] ) // Mixed + ) * biLapWeight; +#undef D_DOT +} +template< int SFDegree , BoundaryType SFBType , int FEMDegree , BoundaryType FEMBType > +template< bool Reverse , class I > +double FEMSFConstraintFunctor< SFDegree , SFBType , FEMDegree , FEMBType >::_integrate( const I& integrator , const int off1[] , const int off2[] ) const +{ +#define D_DOT( D1 , D2 ) { integrator.dot( off1[0] , off2[0] , Reverse ? D2 : D1 , Reverse ? D1 : D2 ) , integrator.dot( off1[1] , off2[1] , Reverse ? D2 : D1 , Reverse ? D1 : D2 ) , integrator.dot( off1[2] , off2[2] , Reverse ? D2 : D1 , Reverse ? D1 : D2 ) } + double d00[] = D_DOT( 0 , 0 ) , d02[] = D_DOT( 0 , 2 ) , d20[] = D_DOT( 2 , 0 ) , d22[] = D_DOT( 2 , 2 ) , d11[] = D_DOT( 1 , 1 ); + if( SFDegree==0 || FEMDegree==0 ) + return d00[0] * d00[1] * d00[2] * massWeight; + else if( SFDegree<=1 || FEMDegree<=1 ) + return + ( + d00[0] * d00[1] * d00[2] + ) * massWeight + + + ( + d11[0] * d00[1] * d00[2] + + d11[1] * d00[2] * d00[0] + + d11[2] * d00[0] * d00[1] + ) * lapWeight; + else + return + ( + d00[0] * d00[1] * d00[2] + ) * massWeight + + + ( + d11[0] * d00[1] * d00[2] + + d11[1] * d00[2] * d00[0] + + d11[2] * d00[0] * d00[1] + ) * lapWeight + + + ( + d22[0] * d00[1] * d00[2] + // Unmixed + d22[1] * d00[2] * d00[0] + // Unmixed + d22[2] * d00[0] * d00[1] + // Unmixed + d00[0] * ( d02[1] * d20[2] + d20[1] * d02[2] ) + // Mixed + d00[1] * ( d02[2] * d20[0] + d20[2] * d02[0] ) + // Mixed + d00[2] * ( d02[0] * d20[1] + d20[0] * d02[1] ) // Mixed + ) * biLapWeight; +#undef D_DOT +} +template< int VFDegree , BoundaryType VFBType , int FEMDegree , BoundaryType FEMBType > +template< bool Reverse , class I > +Point3D< double > FEMVFConstraintFunctor< VFDegree , VFBType , FEMDegree , FEMBType >::_integrate( const I& integrator , const int off1[] , const int off2[] ) const +{ +#define D_DOT( D1 , D2 ) { integrator.dot( off1[0] , off2[0] , Reverse ? D2 : D1 , Reverse ? D1 : D2 ) , integrator.dot( off1[1] , off2[1] , Reverse ? D2 : D1 , Reverse ? D1 : D2 ) , integrator.dot( off1[2] , off2[2] , Reverse ? D2 : D1 , Reverse ? D1 : D2 ) } + if( FEMDegree==0 ) fprintf( stderr , "[ERROR] FEMDegree does not support differentiation: %d\n" , FEMDegree ) , exit( 0 ); + if( VFDegree==0 || FEMDegree==1 ) + { + double d00[] = D_DOT( 0 , 0 ) , d01[] = D_DOT( 0 , 1 ); + return + Point3D< double > + ( + d01[0] * d00[1] * d00[2] , + d01[1] * d00[2] * d00[0] , + d01[2] * d00[0] * d00[1] + ) * lapWeight; + } + else + { + double d00[] = D_DOT( 0 , 0 ) , d10[] = D_DOT( 1 , 0 ) , d01[] = D_DOT( 0 , 1 ) , d02[] = D_DOT( 0 , 2 ) , d12[] = D_DOT( 1 , 2 ); + return + Point3D< double > + ( + d01[0] * d00[1] * d00[2] , + d01[1] * d00[2] * d00[0] , + d01[2] * d00[0] * d00[1] + ) * lapWeight + + + Point3D< double > + ( + d12[0] * d00[1] * d00[2] + d10[0] * ( d00[1] * d02[2] + d02[1] * d00[2] ) , + d12[1] * d00[2] * d00[0] + d10[1] * ( d00[2] * d02[0] + d02[2] * d00[0] ) , + d12[2] * d00[0] * d00[1] + d10[2] * ( d00[0] * d02[1] + d02[0] * d00[1] ) + ) * biLapWeight; + } +#undef D_DOT +} + +template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< bool Reverse , class _FEMSystemFunctor > +void SystemCoefficients< Degree1 , BType1 , Degree2 , BType2 >::SetCentralConstraintStencil( const _FEMSystemFunctor& F , const Integrator& integrator , Stencil< double , OverlapSize >& stencil ) +{ + int center = ( 1<>1; + int offset[] = { center , center , center }; + for( int x=0 ; x( integrator , _offset , offset ); + } +} +template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< bool Reverse , class _FEMSystemFunctor > +void SystemCoefficients< Degree1 , BType1 , Degree2 , BType2 >::SetCentralConstraintStencils( const _FEMSystemFunctor& F , const ChildIntegrator& integrator , Stencil< double , OverlapSize > stencils[2][2][2] ) +{ + int center = ( 1<>1; + // [NOTE] We want the center to be at the first node of the brood + // Which is not the case when childDepth is 1. + center = ( center>>1 )<<1; + for( int i=0 ; i<2 ; i++ ) for( int j=0 ; j<2 ; j++ ) for( int k=0 ; k<2 ; k++ ) + { + int offset[] = { center+i , center+j , center+k }; + for( int x=0 ; x( integrator , _offset , offset ); + } + } +} +template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< bool Reverse , class _FEMSystemFunctor > +void SystemCoefficients< Degree1 , BType1 , Degree2 , BType2 >::SetCentralConstraintStencil( const _FEMSystemFunctor& F , const Integrator& integrator , Stencil< Point3D< double > , OverlapSize >& stencil ) +{ + int center = ( 1<>1; + int offset[] = { center , center , center }; + for( int x=0 ; x( integrator , _offset , offset ); + } +} +template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< bool Reverse , class _FEMSystemFunctor > +void SystemCoefficients< Degree1 , BType1 , Degree2 , BType2 >::SetCentralConstraintStencils( const _FEMSystemFunctor& F , const ChildIntegrator& integrator , Stencil< Point3D< double > , OverlapSize > stencils[2][2][2] ) +{ + int center = ( 1<>1; + // [NOTE] We want the center to be at the first node of the brood + // Which is not the case when childDepth is 1. + center = ( center>>1 )<<1; + for( int i=0 ; i<2 ; i++ ) for( int j=0 ; j<2 ; j++ ) for( int k=0 ; k<2 ; k++ ) + { + int offset[] = { center+i , center+j , center+k }; + for( int x=0 ; x( integrator , _offset , offset ); + } + } +} +template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< class _FEMSystemFunctor > +void SystemCoefficients< Degree1 , BType1 , Degree2 , BType2 >::SetCentralSystemStencil( const _FEMSystemFunctor& F , const Integrator& integrator , Stencil< double , OverlapSize >& stencil ) +{ + int center = ( 1<>1; + int offset[] = { center , center , center }; + for( int x=0 ; x +template< class _FEMSystemFunctor > +void SystemCoefficients< Degree1 , BType1 , Degree2 , BType2 >::SetCentralSystemStencils( const _FEMSystemFunctor& F , const ChildIntegrator& integrator , Stencil< double , OverlapSize > stencils[2][2][2] ) +{ + int center = ( 1<>1; + // [NOTE] We want the center to be at the first node of the brood + // Which is not the case when childDepth is 1. + center = ( center>>1 )<<1; + for( int i=0 ; i<2 ; i++ ) for( int j=0 ; j<2 ; j++ ) for( int k=0 ; k<2 ; k++ ) + { + int offset[] = { center+i , center+j , center+k }; + for( int x=0 ; x +template< int FEMDegree > +void Octree< Real >::_setMultiColorIndices( int start , int end , std::vector< std::vector< int > >& indices ) const +{ + static const int OverlapRadius = - BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapStart; + + const int modulus = OverlapRadius+1; + indices.resize( modulus*modulus*modulus ); + int count[modulus*modulus*modulus]; + memset( count , 0 , sizeof(int)*modulus*modulus*modulus ); +#pragma omp parallel for num_threads( threads ) + for( int i=start ; idepthAndOffset( d , off ); + int idx = (modulus*modulus) * ( off[2]%modulus ) + modulus * ( off[1]%modulus ) + ( off[0]%modulus ); +#pragma omp atomic + count[idx]++; + } + + for( int i=0 ; idepthAndOffset( d , off ); + int idx = (modulus*modulus) * ( off[2]%modulus ) + modulus * ( off[1]%modulus ) + ( off[0]%modulus ); + indices[idx].push_back( i - start ); + } +} + +template< class Real > +template< class C , int FEMDegree , BoundaryType BType > +void Octree< Real >::_downSample( LocalDepth highDepth , DenseNodeData< C , FEMDegree >& constraints ) const +{ + typedef typename TreeOctNode::NeighborKey< -BSplineSupportSizes< FEMDegree >::UpSampleStart , BSplineSupportSizes< FEMDegree >::UpSampleEnd > UpSampleKey; + + LocalDepth lowDepth = highDepth-1; + if( lowDepth<0 ) return; + + typename BSplineEvaluationData< FEMDegree , BType >::UpSampleEvaluator upSampleEvaluator; + BSplineEvaluationData< FEMDegree , BType >::SetUpSampleEvaluator( upSampleEvaluator , lowDepth ); + std::vector< UpSampleKey > neighborKeys( std::max< int >( 1 , threads ) ); + for( size_t i=0 ; i::UpSampleSize > upSampleStencil; + int lowCenter = ( 1<>1; + for( int i=0 ; i::UpSampleSize ; i++ ) for( int j=0 ; j::UpSampleSize ; j++ ) for( int k=0 ; k::UpSampleSize ; k++ ) + upSampleStencil( i , j , k ) = + upSampleEvaluator.value( lowCenter , 2*lowCenter + i + BSplineSupportSizes< FEMDegree >::UpSampleStart ) * + upSampleEvaluator.value( lowCenter , 2*lowCenter + j + BSplineSupportSizes< FEMDegree >::UpSampleStart ) * + upSampleEvaluator.value( lowCenter , 2*lowCenter + k + BSplineSupportSizes< FEMDegree >::UpSampleStart ); + + // Iterate over all (valid) parent nodes +#pragma omp parallel for num_threads( threads ) + for( int i=_sNodesBegin(lowDepth) ; i<_sNodesEnd(lowDepth) ; i++ ) if( _isValidFEMNode( _sNodes.treeNodes[i] ) ) + { + TreeOctNode* pNode = _sNodes.treeNodes[i]; + + UpSampleKey& neighborKey = neighborKeys[ omp_get_thread_num() ]; + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( pNode , d , off ); + + neighborKey.template getNeighbors< false >( pNode ); + + // Get the child neighbors + typename TreeOctNode::Neighbors< BSplineSupportSizes< FEMDegree >::UpSampleSize > neighbors; + neighborKey.template getChildNeighbors< false >( 0 , _localToGlobal( d ) , neighbors ); + + C& coarseConstraint = constraints[i]; + + // Want to make sure test if contained children are interior. + // This is more conservative because we are test that overlapping children are interior + bool isInterior = _isInteriorlyOverlapped< FEMDegree , FEMDegree >( pNode ); + if( isInterior ) + { + for( int ii=0 ; ii::UpSampleSize ; ii++ ) for( int jj=0 ; jj::UpSampleSize ; jj++ ) for( int kk=0 ; kk::UpSampleSize ; kk++ ) + { + const TreeOctNode* cNode = neighbors.neighbors[ii][jj][kk]; + if( IsActiveNode( cNode ) ) coarseConstraint += (C)( constraints[ cNode->nodeData.nodeIndex ] * upSampleStencil( ii , jj , kk ) ); + } + } + else + { + double upSampleValues[3][ BSplineSupportSizes< FEMDegree >::UpSampleSize ]; + for( int ii=0 ; ii::UpSampleSize ; ii++ ) + { + upSampleValues[0][ii] = upSampleEvaluator.value( off[0] , 2*off[0] + ii + BSplineSupportSizes< FEMDegree >::UpSampleStart ); + upSampleValues[1][ii] = upSampleEvaluator.value( off[1] , 2*off[1] + ii + BSplineSupportSizes< FEMDegree >::UpSampleStart ); + upSampleValues[2][ii] = upSampleEvaluator.value( off[2] , 2*off[2] + ii + BSplineSupportSizes< FEMDegree >::UpSampleStart ); + } + for( int ii=0 ; ii::UpSampleSize ; ii++ ) for( int jj=0 ; jj::UpSampleSize ; jj++ ) + { + double dxy = upSampleValues[0][ii] * upSampleValues[1][jj]; + for( int kk=0 ; kk::UpSampleSize ; kk++ ) + { + const TreeOctNode* cNode = neighbors.neighbors[ii][jj][kk]; + if( _isValidFEMNode( cNode ) ) coarseConstraint += (C)( constraints[ cNode->nodeData.nodeIndex ] * dxy * upSampleValues[2][kk] ); + } + } + } + } +} +template< class Real > +template< class C , int FEMDegree , BoundaryType BType > +void Octree< Real >::_upSample( LocalDepth highDepth , DenseNodeData< C , FEMDegree >& coefficients ) const +{ + static const int LeftDownSampleRadius = -( ( BSplineSupportSizes< FEMDegree >::DownSample0Start < BSplineSupportSizes< FEMDegree >::DownSample1Start ) ? BSplineSupportSizes< FEMDegree >::DownSample0Start : BSplineSupportSizes< FEMDegree >::DownSample1Start ); + static const int RightDownSampleRadius = ( ( BSplineSupportSizes< FEMDegree >::DownSample0End > BSplineSupportSizes< FEMDegree >::DownSample1End ) ? BSplineSupportSizes< FEMDegree >::DownSample0End : BSplineSupportSizes< FEMDegree >::DownSample1End ); + typedef TreeOctNode::NeighborKey< LeftDownSampleRadius , RightDownSampleRadius > DownSampleKey; + + LocalDepth lowDepth = highDepth-1; + if( lowDepth<0 ) return; + + typename BSplineEvaluationData< FEMDegree , BType >::UpSampleEvaluator upSampleEvaluator; + BSplineEvaluationData< FEMDegree , BType >::SetUpSampleEvaluator( upSampleEvaluator , lowDepth ); + std::vector< DownSampleKey > neighborKeys( std::max< int >( 1 , threads ) ); + for( size_t i=0 ; i::DownSample0Size > BSplineSupportSizes< FEMDegree >::DownSample1Size ? BSplineSupportSizes< FEMDegree >::DownSample0Size : BSplineSupportSizes< FEMDegree >::DownSample1Size; + Stencil< double , DownSampleSize > downSampleStencils[ Cube::CORNERS ]; + int lowCenter = ( 1<>1; + for( int c=0 ; c::DownSampleSize[cx] ; ii++ ) + for( int jj=0 ; jj::DownSampleSize[cy] ; jj++ ) + for( int kk=0 ; kk::DownSampleSize[cz] ; kk++ ) + downSampleStencils[c]( ii , jj , kk ) = + upSampleEvaluator.value( lowCenter + ii + BSplineSupportSizes< FEMDegree >::DownSampleStart[cx] , 2*lowCenter + cx ) * + upSampleEvaluator.value( lowCenter + jj + BSplineSupportSizes< FEMDegree >::DownSampleStart[cy] , 2*lowCenter + cy ) * + upSampleEvaluator.value( lowCenter + kk + BSplineSupportSizes< FEMDegree >::DownSampleStart[cz] , 2*lowCenter + cz ) ; + } + + // For Dirichlet constraints, can't get to all children from parents because boundary nodes are invalid +#pragma omp parallel for num_threads( threads ) + for( int i=_sNodesBegin(highDepth) ; i<_sNodesEnd(highDepth) ; i++ ) if( _isValidFEMNode( _sNodes.treeNodes[i] ) ) + { + TreeOctNode *cNode = _sNodes.treeNodes[i] , *pNode = cNode->parent; + int c = (int)( cNode-pNode->children ); + + DownSampleKey& neighborKey = neighborKeys[ omp_get_thread_num() ]; + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( pNode , d , off ); + typename TreeOctNode::Neighbors< LeftDownSampleRadius + RightDownSampleRadius + 1 >& neighbors = neighborKey.template getNeighbors< false >( pNode ); + + // Want to make sure test if contained children are interior. + // This is more conservative because we are test that overlapping children are interior + bool isInterior = _isInteriorlyOverlapped< FEMDegree , FEMDegree >( pNode ); + + C& fineCoefficient = coefficients[ cNode->nodeData.nodeIndex ]; + + int cx , cy , cz; + Cube::FactorCornerIndex( c , cx , cy , cz ); + + if( isInterior ) + { + for( int ii=0 ; ii::DownSampleSize[cx] ; ii++ ) for( int jj=0 ; jj::DownSampleSize[cy] ; jj++ ) + { + int _ii = ii + BSplineSupportSizes< FEMDegree >::DownSampleStart[cx] + LeftDownSampleRadius; + int _jj = jj + BSplineSupportSizes< FEMDegree >::DownSampleStart[cy] + LeftDownSampleRadius; + for( int kk=0 ; kk::DownSampleSize[cz] ; kk++ ) + { + int _kk = kk + BSplineSupportSizes< FEMDegree >::DownSampleStart[cz] + LeftDownSampleRadius; + const TreeOctNode* _pNode = neighbors.neighbors[_ii][_jj][_kk]; + if( _pNode ) fineCoefficient += (C)( coefficients[ _pNode->nodeData.nodeIndex ] * downSampleStencils[c]( ii , jj , kk ) ); + } + } + } + else + { + double downSampleValues[3][ BSplineSupportSizes< FEMDegree >::DownSample0Size > BSplineSupportSizes< FEMDegree >::DownSample1Size ? BSplineSupportSizes< FEMDegree >::DownSample0Size : BSplineSupportSizes< FEMDegree >::DownSample1Size ]; + for( int ii=0 ; ii::DownSampleSize[cx] ; ii++ ) downSampleValues[0][ii] = upSampleEvaluator.value( off[0] + ii + BSplineSupportSizes< FEMDegree >::DownSampleStart[cx] , 2*off[0] + cx ); + for( int ii=0 ; ii::DownSampleSize[cy] ; ii++ ) downSampleValues[1][ii] = upSampleEvaluator.value( off[1] + ii + BSplineSupportSizes< FEMDegree >::DownSampleStart[cy] , 2*off[1] + cy ); + for( int ii=0 ; ii::DownSampleSize[cz] ; ii++ ) downSampleValues[2][ii] = upSampleEvaluator.value( off[2] + ii + BSplineSupportSizes< FEMDegree >::DownSampleStart[cz] , 2*off[2] + cz ); + + for( int ii=0 ; ii::DownSampleSize[cx] ; ii++ ) for( int jj=0 ; jj::DownSampleSize[cy] ; jj++ ) + { + double dxy = downSampleValues[0][ii] * downSampleValues[1][jj]; + int _ii = ii + BSplineSupportSizes< FEMDegree >::DownSampleStart[cx] + LeftDownSampleRadius; + int _jj = jj + BSplineSupportSizes< FEMDegree >::DownSampleStart[cy] + LeftDownSampleRadius; + for( int kk=0 ; kk::DownSampleSize[cz] ; kk++ ) + { + int _kk = kk + BSplineSupportSizes< FEMDegree >::DownSampleStart[cz] + LeftDownSampleRadius; + const TreeOctNode* _pNode = neighbors.neighbors[_ii][_jj][_kk]; + if( _isValidFEMNode( _pNode ) ) fineCoefficient += (C)( coefficients[ _pNode->nodeData.nodeIndex ] * dxy * downSampleValues[2][kk] ); + } + } + } + } +} + +template< class Real > +template< class C , int FEMDegree , BoundaryType BType > +void Octree< Real >::_UpSample( LocalDepth highDepth , ConstPointer( C ) lowCoefficients , Pointer( C ) highCoefficients , int threads ) +{ + static const int LeftDownSampleRadius = -( ( BSplineSupportSizes< FEMDegree >::DownSample0Start < BSplineSupportSizes< FEMDegree >::DownSample1Start ) ? BSplineSupportSizes< FEMDegree >::DownSample0Start : BSplineSupportSizes< FEMDegree >::DownSample1Start ); + static const int RightDownSampleRadius = ( ( BSplineSupportSizes< FEMDegree >::DownSample0End > BSplineSupportSizes< FEMDegree >::DownSample1End ) ? BSplineSupportSizes< FEMDegree >::DownSample0End : BSplineSupportSizes< FEMDegree >::DownSample1End ); + typedef TreeOctNode::NeighborKey< LeftDownSampleRadius , RightDownSampleRadius > DownSampleKey; + + LocalDepth lowDepth = highDepth - 1; + if( lowDepth<0 ) return; + + typename BSplineEvaluationData< FEMDegree , BType >::UpSampleEvaluator upSampleEvaluator; + BSplineEvaluationData< FEMDegree , BType >::SetUpSampleEvaluator( upSampleEvaluator , lowDepth ); + std::vector< DownSampleKey > neighborKeys( std::max< int >( 1 , threads ) ); + + static const int DownSampleSize = BSplineSupportSizes< FEMDegree >::DownSample0Size > BSplineSupportSizes< FEMDegree >::DownSample1Size ? BSplineSupportSizes< FEMDegree >::DownSample0Size : BSplineSupportSizes< FEMDegree >::DownSample1Size; + Stencil< double , DownSampleSize > downSampleStencils[ Cube::CORNERS ]; + int lowCenter = ( 1<>1; + for( int c=0 ; c::DownSample0Size > BSplineSupportSizes< FEMDegree >::DownSample1Size ? BSplineSupportSizes< FEMDegree >::DownSample0Size : BSplineSupportSizes< FEMDegree >::DownSample1Size; + for( int ii=0 ; ii::DownSampleSize[cx] ; ii++ ) + for( int jj=0 ; jj::DownSampleSize[cy] ; jj++ ) + for( int kk=0 ; kk::DownSampleSize[cz] ; kk++ ) + downSampleStencils[c]( ii , jj , kk ) = + upSampleEvaluator.value( lowCenter + ii + BSplineSupportSizes< FEMDegree >::DownSampleStart[cx] , 2*lowCenter + cx ) * + upSampleEvaluator.value( lowCenter + jj + BSplineSupportSizes< FEMDegree >::DownSampleStart[cy] , 2*lowCenter + cy ) * + upSampleEvaluator.value( lowCenter + kk + BSplineSupportSizes< FEMDegree >::DownSampleStart[cz] , 2*lowCenter + cz ) ; + } + int lowBegin = _BSplineBegin< FEMDegree , BType >( lowDepth ) , lowEnd = _BSplineEnd< FEMDegree , BType >( lowDepth ); + int highBegin = _BSplineBegin< FEMDegree , BType >( highDepth ) , highEnd = _BSplineEnd< FEMDegree , BType >( highDepth ); + int lowDim = lowEnd - lowBegin , highDim = highEnd - highBegin; + // Iterate over all child nodes. (This is required since there can be child nodes whose parent is inactive.) +#pragma omp parallel for num_threads( threads ) + for( int k=0 ; k>1 , _off[1] = off[1]>>1 , _off[2] = off[2]>>1; + + // Want to make sure test if contained children are interior. + // This is more conservative because we are test that overlapping children are interior + bool isInterior = _IsInteriorlyOverlapped< FEMDegree , FEMDegree >( lowDepth , _off ); + int cx = off[0]&1 , cy = off[1]&1 , cz = off[2]&1; + int c = Cube::CornerIndex( cx , cy , cz ); + + C& highCoefficient = highCoefficients[ highIdx ]; + + if( isInterior ) + { + for( int ii=0 ; ii::DownSampleSize[cx] ; ii++ ) for( int jj=0 ; jj::DownSampleSize[cy] ; jj++ ) + { + int _i = _off[0] + ii + BSplineSupportSizes< FEMDegree >::DownSampleStart[cx] - lowBegin; + int _j = _off[1] + jj + BSplineSupportSizes< FEMDegree >::DownSampleStart[cy] - lowBegin; + for( int kk=0 ; kk::DownSampleSize[cz] ; kk++ ) + { + int _k = _off[2] + kk + BSplineSupportSizes< FEMDegree >::DownSampleStart[cz] - lowBegin; + highCoefficient += (C)( lowCoefficients[ _i + _j*lowDim + _k*lowDim*lowDim ] * downSampleStencils[c]( ii , jj , kk ) ); + } + } + } + else + { + double downSampleValues[3][ BSplineSupportSizes< FEMDegree >::DownSample0Size > BSplineSupportSizes< FEMDegree >::DownSample1Size ? BSplineSupportSizes< FEMDegree >::DownSample0Size : BSplineSupportSizes< FEMDegree >::DownSample1Size ]; + + for( int ii=0 ; ii::DownSampleSize[cx] ; ii++ ) downSampleValues[0][ii] = upSampleEvaluator.value( _off[0] + ii + BSplineSupportSizes< FEMDegree >::DownSampleStart[cx] , off[0] ); + for( int ii=0 ; ii::DownSampleSize[cy] ; ii++ ) downSampleValues[1][ii] = upSampleEvaluator.value( _off[1] + ii + BSplineSupportSizes< FEMDegree >::DownSampleStart[cy] , off[1] ); + for( int ii=0 ; ii::DownSampleSize[cz] ; ii++ ) downSampleValues[2][ii] = upSampleEvaluator.value( _off[2] + ii + BSplineSupportSizes< FEMDegree >::DownSampleStart[cz] , off[2] ); + + for( int ii=0 ; ii::DownSampleSize[cx] ; ii++ ) for( int jj=0 ; jj::DownSampleSize[cy] ; jj++ ) + { + double dxy = downSampleValues[0][ii] * downSampleValues[1][jj]; + int _i = _off[0] + ii + BSplineSupportSizes< FEMDegree >::DownSampleStart[cx] - lowBegin; + int _j = _off[1] + jj + BSplineSupportSizes< FEMDegree >::DownSampleStart[cy] - lowBegin; + if( _i>=0 && _i=0 && _j::DownSampleSize[cz] ; kk++ ) + { + int _k = _off[2] + kk + BSplineSupportSizes< FEMDegree >::DownSampleStart[cz] - lowBegin; + if( _k>=0 && _k +template< class C , int FEMDegree , BoundaryType BType > +DenseNodeData< C , FEMDegree > Octree< Real >::coarseCoefficients( const DenseNodeData< C , FEMDegree >& coefficients ) const +{ + DenseNodeData< Real , FEMDegree > coarseCoefficients( _sNodesEnd(_maxDepth-1) ); + memset( &coarseCoefficients[0] , 0 , sizeof(Real)*_sNodesEnd(_maxDepth-1) ); +#pragma omp parallel for num_threads( threads ) + for( int i=_sNodesBegin(0) ; i<_sNodesEnd(_maxDepth-1) ; i++ ) coarseCoefficients[i] = coefficients[i]; + for( LocalDepth d=1 ; d<_maxDepth ; d++ ) _upSample< C , FEMDegree , BType >( d , coarseCoefficients ); + return coarseCoefficients; +} +template< class Real > +template< class C , int FEMDegree , BoundaryType BType > +DenseNodeData< C , FEMDegree > Octree< Real >::coarseCoefficients( const SparseNodeData< C , FEMDegree >& coefficients ) const +{ + DenseNodeData< Real , FEMDegree > coarseCoefficients( _sNodesEnd(_maxDepth-1) ); + memset( &coarseCoefficients[0] , 0 , sizeof(Real)*_sNodesEnd(_maxDepth-1) ); +#pragma omp parallel for num_threads( threads ) + for( int i=_sNodesBegin(0) ; i<_sNodesEnd(_maxDepth-1) ; i++ ) + { + const C* c = coefficients( _sNodes.treeNodes[i] ); + if( c ) coarseCoefficients[i] = *c; + } + for( LocalDepth d=1 ; d<_maxDepth ; d++ ) _upSample< C , FEMDegree , BType >( d , coarseCoefficients ); + return coarseCoefficients; +} + +template< class Real > +template< int FEMDegree , BoundaryType BType > +Real Octree< Real >::_coarserFunctionValue( Point3D< Real > p , const PointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* pointNode , const BSplineData< FEMDegree , BType >& bsData , const DenseNodeData< Real , FEMDegree >& upSampledCoefficients ) const +{ + static const int SupportSize = BSplineSupportSizes< FEMDegree >::SupportSize; + static const int LeftSupportRadius = - BSplineSupportSizes< FEMDegree >::SupportStart; + static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + static const int RightPointSupportRadius = - BSplineSupportSizes< FEMDegree >::SupportStart; + + double pointValue = 0; + LocalDepth depth = _localDepth( pointNode ); + if( depth<0 ) return (Real)0.; + + // Iterate over all basis functions that overlap the point at the coarser resolution + { + const typename TreeOctNode::Neighbors< SupportSize >& neighbors = neighborKey.neighbors[ _localToGlobal( depth-1 ) ]; + LocalDepth _d ; LocalOffset _off; + _localDepthAndOffset( pointNode->parent , _d , _off ); + int fStart , fEnd; + BSplineData< FEMDegree , BType >::FunctionSpan( _d , fStart , fEnd ); + + double pointValues[ DIMENSION ][SupportSize]; + memset( pointValues , 0 , sizeof(double) * DIMENSION * SupportSize ); + + for( int dd=0 ; dd::FunctionIndex( _d , _off[dd]+i ); + if( fIdx>=fStart && fIdxnodeData.nodeIndex] ); + } + pointValue += _pointValue * xyValue; + } + } + return Real( pointValue ); +} +template< class Real > +template< int FEMDegree , BoundaryType BType > +Point3D< Real > Octree< Real >::_coarserFunctionGradient( Point3D< Real > p , const PointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* pointNode , const BSplineData< FEMDegree , BType >& bsData , const DenseNodeData< Real , FEMDegree >& upSampledCoefficients ) const +{ + static const int SupportSize = BSplineSupportSizes< FEMDegree >::SupportSize; + static const int LeftSupportRadius = - BSplineSupportSizes< FEMDegree >::SupportStart; + static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + static const int RightPointSupportRadius = - BSplineSupportSizes< FEMDegree >::SupportStart; + + Point3D< double > pointGradient; + LocalDepth depth = _localDepth( pointNode ); + if( depth<=0 ) return Real(0.); + + // Iterate over all basis functions that overlap the point at the coarser resolution + { + const typename TreeOctNode::Neighbors< SupportSize >& neighbors = neighborKey.neighbors[ _localToGlobal( depth-1 ) ]; + LocalDepth _d ; LocalOffset _off; + _localDepthAndOffset( pointNode->parent , _d , _off ); + int fStart , fEnd; + BSplineData< FEMDegree , BType >::FunctionSpan( _d , fStart , fEnd ); + + double _pointValues[ DIMENSION ][SupportSize] , dPointValues[ DIMENSION ][SupportSize]; + memset( _pointValues , 0 , sizeof(double) * DIMENSION * SupportSize ); + memset( dPointValues , 0 , sizeof(double) * DIMENSION * SupportSize ); + + for( int dd=0 ; dd::FunctionIndex( _d , _off[dd]+i ); + if( fIdx>=fStart && fIdxnodeData.nodeIndex] ); + _dPointValue += dPointValues[2][l] * double( upSampledCoefficients[_node->nodeData.nodeIndex] ); + } + } + + pointGradient += Point3D< double >( __pointValue * dx_yValue , __pointValue * _xdyValue , _dPointValue * _x_yValue ); + } + } + return Point3D< Real >( pointGradient ); +} + +template< class Real > +template< int FEMDegree , BoundaryType BType > +Real Octree< Real >::_finerFunctionValue( Point3D< Real > p , const PointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* pointNode , const BSplineData< FEMDegree , BType >& bsData , const DenseNodeData< Real , FEMDegree >& finerCoefficients ) const +{ + typename TreeOctNode::Neighbors< BSplineSupportSizes< FEMDegree >::SupportSize > childNeighbors; + static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + static const int RightPointSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; + static const int LeftSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; + static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + + double pointValue = 0; + LocalDepth depth = _localDepth( pointNode ); + neighborKey.template getChildNeighbors< false >( _childIndex( pointNode , p ) , _localToGlobal( depth ) , childNeighbors ); + for( int j=-LeftPointSupportRadius ; j<=RightPointSupportRadius ; j++ ) + for( int k=-LeftPointSupportRadius ; k<=RightPointSupportRadius ; k++ ) + for( int l=-LeftPointSupportRadius ; l<=RightPointSupportRadius ; l++ ) + { + const TreeOctNode* _node = childNeighbors.neighbors[j+LeftPointSupportRadius][k+LeftPointSupportRadius][l+LeftPointSupportRadius]; + if( _isValidFEMNode( _node ) ) + { + int fIdx[3]; + functionIndex< FEMDegree , BType >( _node , fIdx ); + pointValue += + bsData.baseBSplines[ fIdx[0] ][LeftSupportRadius-j]( p[0] ) * + bsData.baseBSplines[ fIdx[1] ][LeftSupportRadius-k]( p[1] ) * + bsData.baseBSplines[ fIdx[2] ][LeftSupportRadius-l]( p[2] ) * + double( finerCoefficients[ _node->nodeData.nodeIndex ] ); + } + } + return Real( pointValue ); +} +template< class Real > +template< int FEMDegree , BoundaryType BType > +Point3D< Real > Octree< Real >::_finerFunctionGradient( Point3D< Real > p , const PointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* pointNode , const BSplineData< FEMDegree , BType >& bsData , const DenseNodeData< Real , FEMDegree >& finerCoefficients ) const +{ + typename TreeOctNode::Neighbors< BSplineSupportSizes< FEMDegree >::SupportSize > childNeighbors; + static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + static const int RightPointSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; + static const int LeftSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; + static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + + Point3D< double > pointGradient = 0; + LocalDepth depth = _localDepth( pointNode ); + neighborKey.template getChildNeighbors< false >( _childIndex( pointNode , p ) , _localToGlobal( depth ) , childNeighbors ); + for( int j=-LeftPointSupportRadius ; j<=RightPointSupportRadius ; j++ ) + for( int k=-LeftPointSupportRadius ; k<=RightPointSupportRadius ; k++ ) + for( int l=-LeftPointSupportRadius ; l<=RightPointSupportRadius ; l++ ) + { + const TreeOctNode* _node = childNeighbors.neighbors[j+LeftPointSupportRadius][k+LeftPointSupportRadius][l+LeftPointSupportRadius]; + if( _isValidFEMNode( _node ) ) + { + int fIdx[3]; + functionIndex< FEMDegree , BType >( _node , fIdx ); + double x = bsData. baseBSplines[ fIdx[0] ][LeftSupportRadius-j]( p[0] ) , y = bsData. baseBSplines[ fIdx[1] ][LeftSupportRadius-k]( p[1] ) , z = bsData. baseBSplines[ fIdx[2] ][LeftSupportRadius-l]( p[2] ); + double dx = bsData.dBaseBSplines[ fIdx[0] ][LeftSupportRadius-j]( p[0] ) , dy = bsData.dBaseBSplines[ fIdx[1] ][LeftSupportRadius-k]( p[1] ) , dz = bsData.dBaseBSplines[ fIdx[2] ][LeftSupportRadius-l]( p[2] ); + pointGradient += Point3D< double >( dx * y * z , x * dy * z , x * y * dz ) * (double)( finerCoefficients[ _node->nodeData.nodeIndex ] ); + } + } + return Point3D< Real >( pointGradient ); +} + +template< class Real > +template< int FEMDegree , BoundaryType BType , bool HasGradients > +void Octree< Real >::_setPointValuesFromCoarser( InterpolationInfo< HasGradients >& interpolationInfo , LocalDepth highDepth , const BSplineData< FEMDegree , BType >& bsData , const DenseNodeData< Real , FEMDegree >& upSampledCoefficients ) +{ + LocalDepth lowDepth = highDepth-1; + if( lowDepth<0 ) return; + std::vector< PointSupportKey< FEMDegree > > neighborKeys( std::max< int >( 1 , threads ) ); + for( size_t i=0 ; i& neighborKey = neighborKeys[ omp_get_thread_num() ]; + PointData< Real , HasGradients >* pData = interpolationInfo( _sNodes.treeNodes[i] ); + if( pData ) + { + neighborKey.template getNeighbors< false >( _sNodes.treeNodes[i]->parent ); +#if POINT_DATA_RES + for( int c=0 ; c::SAMPLES ; c++ ) if( (*pData)[c].weight ) + _ConstraintCalculator_< Real , FEMDegree , HasGradients >::_CalculateCoarser_ + ( + c , *pData , + _coarserFunctionValue( (*pData)[c].position , neighborKey , _sNodes.treeNodes[i] , bsData , upSampledCoefficients ) , + HasGradients ? _coarserFunctionGradient( (*pData)[c].position , neighborKey , _sNodes.treeNodes[i] , bsData , upSampledCoefficients ) : Point3D< Real >() , + interpolationInfo.valueWeight , interpolationInfo.gradientWeight + ); +#else // !POINT_DATA_RES + _ConstraintCalculator_< Real , FEMDegree , HasGradients >::_CalculateCoarser_ + ( + *pData , + _coarserFunctionValue( pData->position , neighborKey , _sNodes.treeNodes[i] , bsData , upSampledCoefficients ) , + HasGradients ? _coarserFunctionGradient( pData->position , neighborKey , _sNodes.treeNodes[i] , bsData , upSampledCoefficients ) : Point3D< Real >() , + interpolationInfo.valueWeight , interpolationInfo.gradientWeight + ); +#endif // POINT_DATA_RES + } + } +} + +template< class Real > +template< int FEMDegree , BoundaryType BType , bool HasGradients > +void Octree< Real >::_updateCumulativeInterpolationConstraintsFromFiner( const InterpolationInfo< HasGradients >& interpolationInfo , const BSplineData< FEMDegree , BType >& bsData , LocalDepth highDepth , const DenseNodeData< Real , FEMDegree >& finerCoefficients , DenseNodeData< Real , FEMDegree >& coarserConstraints ) const +{ + static const int SupportSize = BSplineSupportSizes< FEMDegree >::SupportSize; + static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + static const int RightPointSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; + static const int LeftSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; + static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + + // Note: We can't iterate over the finer point nodes as the point weights might be + // scaled incorrectly, due to the adaptive exponent. So instead, we will iterate + // over the coarser nodes and evaluate the finer solution at the associated points. + LocalDepth lowDepth = highDepth-1; + if( lowDepth<0 ) return; + size_t start = _sNodesBegin(lowDepth) , end = _sNodesEnd(lowDepth); + std::vector< PointSupportKey< FEMDegree > > neighborKeys( std::max< int >( 1 , threads ) ); + for( size_t i=0 ; i& neighborKey = neighborKeys[ omp_get_thread_num() ]; + const PointData< Real , HasGradients >* pData = interpolationInfo( _sNodes.treeNodes[i] ); + if( pData ) + { + typename TreeOctNode::Neighbors< SupportSize >& neighbors = neighborKey.template getNeighbors< false >( _sNodes.treeNodes[i] ); + // evaluate the solution @( depth ) at the current point @( depth-1 ) +#if POINT_DATA_RES + for( int c=0 ; c::SAMPLES ; c++ ) if( (*pData)[c].weight ) +#endif // POINT_DATA_RES + { +#if POINT_DATA_RES + Real finerPointDValue = _finerFunctionValue( (*pData)[c].position , neighborKey , _sNodes.treeNodes[i] , bsData , finerCoefficients ) * interpolationInfo.valueWeight * (*pData)[c].weight; + Point3D< Real > finerPointDGradient = HasGradients ? _finerFunctionGradient( (*pData)[c].position , neighborKey , _sNodes.treeNodes[i] , bsData , finerCoefficients ) * interpolationInfo.gradientWeight * (*pData)[c].weight : Point3D< Real >(); + Point3D< Real > p = (*pData)[c].position; +#else // !POINT_DATA_RES + Real finerPointDValue = _finerFunctionValue( pData->position , neighborKey , _sNodes.treeNodes[i] , bsData , finerCoefficients ) * interpolationInfo.valueWeight * pData->weight; + Point3D< Real > finerPointDGradient = HasGradients ? _finerFunctionGradient( pData->position , neighborKey , _sNodes.treeNodes[i] , bsData , finerCoefficients ) * interpolationInfo.gradientWeight * pData->weight : Point3D< Real >(); + Point3D< Real > p = pData->position; +#endif // POINT_DATA_RES + // Update constraints for all nodes @( depth-1 ) that overlap the point + int idx[3]; + functionIndex< FEMDegree , BType >( _sNodes.treeNodes[i] , idx ); + for( int x=-LeftPointSupportRadius ; x<=RightPointSupportRadius ; x++ ) for( int y=-LeftPointSupportRadius ; y<=RightPointSupportRadius ; y++ ) for( int z=-LeftPointSupportRadius ; z<=RightPointSupportRadius ; z++ ) + { + const TreeOctNode* _node = neighbors.neighbors[x+LeftPointSupportRadius][y+LeftPointSupportRadius][z+LeftPointSupportRadius]; + if( _isValidFEMNode( _node ) ) + { + double px = bsData.baseBSplines[idx[0]+x][LeftSupportRadius-x]( p[0] ) , py = bsData.baseBSplines[idx[1]+y][LeftSupportRadius-y]( p[1] ) , pz = bsData.baseBSplines[idx[2]+z][LeftSupportRadius-z]( p[2] ); +#pragma omp atomic + coarserConstraints[ _node->nodeData.nodeIndex ] += (Real)( px * py * pz * finerPointDValue ); + if( HasGradients ) + { + double dpx = bsData.dBaseBSplines[idx[0]+x][LeftSupportRadius-x]( p[0] ) , dpy = bsData.dBaseBSplines[idx[1]+y][LeftSupportRadius-y]( p[1] ) , dpz = bsData.dBaseBSplines[idx[2]+z][LeftSupportRadius-z]( p[2] ); +#pragma omp atomic + coarserConstraints[ _node->nodeData.nodeIndex ] += Point3D< Real >::Dot( finerPointDGradient , Point3D< Real >( dpx * py * pz , px * dpy * pz , px * py * dpz ) ); + } + } + } + } + } + } +} + +template< class Real > +template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > +int Octree< Real >::_setMatrixRow( const FEMSystemFunctor& F , const InterpolationInfo< HasGradients >* interpolationInfo , const typename TreeOctNode::Neighbors< BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& neighbors , Pointer( MatrixEntry< Real > ) row , int offset , const typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template Integrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) >& integrator , const Stencil< double , BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& stencil , const BSplineData< FEMDegree , BType >& bsData ) const +{ + static const int SupportSize = BSplineSupportSizes< FEMDegree >::SupportSize; + static const int OverlapRadius = - BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapStart; + static const int OverlapSize = BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize; + static const int LeftSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; + static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + static const int RightPointSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; + + bool hasYZPoints[SupportSize] , hasZPoints[SupportSize][SupportSize]; + Real diagonal = 0; + // Given a node: + // -- for each node in its support: + // ---- if the supporting node contains a point: + // ------ evaluate the x, y, and z B-splines of the nodes supporting the point + // splineValues \in [-LeftSupportRadius,RightSupportRadius] x [-LeftSupportRadius,RightSupportRadius] x [-LeftSupportRadius,RightSupportRadius] x [0,Dimension) x [-LeftPointSupportRadius,RightPointSupportRadius] +#if POINT_DATA_RES + Real _splineValues[PointData< Real , HasGradients >::SAMPLES][SupportSize][SupportSize][SupportSize][DIMENSION][SupportSize]; + Real wSplineValues[PointData< Real , HasGradients >::SAMPLES][SupportSize][SupportSize][SupportSize][DIMENSION][SupportSize]; + Real dSplineValues[PointData< Real , HasGradients >::SAMPLES][SupportSize][SupportSize][SupportSize][DIMENSION][SupportSize]; + memset( _splineValues , 0 , sizeof( Real ) * PointData< Real , HasGradients >::SAMPLES * SupportSize * SupportSize * SupportSize * DIMENSION *SupportSize ); + memset( wSplineValues , 0 , sizeof( Real ) * PointData< Real , HasGradients >::SAMPLES * SupportSize * SupportSize * SupportSize * DIMENSION *SupportSize ); + memset( dSplineValues , 0 , sizeof( Real ) * PointData< Real , HasGradients >::SAMPLES * SupportSize * SupportSize * SupportSize * DIMENSION *SupportSize ); +#else // !POINT_DATA_RES + Real _splineValues[SupportSize][SupportSize][SupportSize][DIMENSION][SupportSize]; + Real wSplineValues[SupportSize][SupportSize][SupportSize][DIMENSION][SupportSize]; + Real dSplineValues[SupportSize][SupportSize][SupportSize][DIMENSION][SupportSize]; + memset( _splineValues , 0 , sizeof( Real ) * SupportSize * SupportSize * SupportSize * DIMENSION *SupportSize ); + memset( wSplineValues , 0 , sizeof( Real ) * SupportSize * SupportSize * SupportSize * DIMENSION *SupportSize ); + memset( dSplineValues , 0 , sizeof( Real ) * SupportSize * SupportSize * SupportSize * DIMENSION *SupportSize ); +#endif // NEW_POINT_DATA + + int count = 0; + const TreeOctNode* node = neighbors.neighbors[OverlapRadius][OverlapRadius][OverlapRadius]; + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + int fStart , fEnd; + BSplineData< FEMDegree , BType >::FunctionSpan( d , fStart , fEnd ); + bool isInterior = _isInteriorlyOverlapped< FEMDegree , FEMDegree >( node ); + + if( interpolationInfo ) + { + // Iterate over all neighboring nodes that may have a constraining point + // -- For each one, compute the values of the spline functions supported on the point + for( int j=0 ; j& pData = *( (*interpolationInfo)( _node ) ); + +#if POINT_DATA_RES + for( int c=0 ; c::SAMPLES ; c++ ) if( pData[c].weight ) +#endif // POINT_DATA_RES + { +#if POINT_DATA_RES + Real (*__splineValues)[SupportSize] = _splineValues[c][jj][kk][ll]; + Real (*_wSplineValues)[SupportSize] = wSplineValues[c][jj][kk][ll]; + Real (*_dSplineValues)[SupportSize] = dSplineValues[c][jj][kk][ll]; + Real weight = pData[c].weight; + Point3D< Real > p = pData[c].position; +#else // !POINT_DATA_RES + Real (*__splineValues)[SupportSize] = _splineValues[jj][kk][ll]; + Real (*_wSplineValues)[SupportSize] = wSplineValues[jj][kk][ll]; + Real (*_dSplineValues)[SupportSize] = dSplineValues[jj][kk][ll]; + Real weight = pData.weight; + Point3D< Real > p = pData.position; +#endif // POINT_DATA_RES + + // evaluate the point p at all the nodes whose functions have it in their support + for( int s=-LeftPointSupportRadius ; s<=RightPointSupportRadius ; s++ ) for( int dd=0 ; dd::FunctionIndex( d , pOff[dd]+s ); + if( fIdx>=fStart && fIdxvalueWeight * weight; + Point3D< Real > weightedGradient; + if( HasGradients ) + { + Point3D< Real > gradient + ( + _dSplineValues[0][-j+LeftPointSupportRadius] * __splineValues[1][-k+LeftPointSupportRadius] * __splineValues[2][-l+LeftPointSupportRadius] , + __splineValues[0][-j+LeftPointSupportRadius] * _dSplineValues[1][-k+LeftPointSupportRadius] * __splineValues[2][-l+LeftPointSupportRadius] , + __splineValues[0][-j+LeftPointSupportRadius] * __splineValues[1][-k+LeftPointSupportRadius] * _dSplineValues[2][-l+LeftPointSupportRadius] + ); + weightedGradient = gradient * interpolationInfo->gradientWeight * weight; + diagonal += value * weightedValue + Point3D< Real >::Dot( gradient , weightedGradient ); + } + else diagonal += value * weightedValue; + + // Pre-multiply the x-coordinate values so that when we evaluate at one of the neighboring basis functions + // we get the product of the values of the center base function and the base function of the neighboring node + if( HasGradients ) for( int s=0 ; s& pData = *( (*interpolationInfo)( _node ) ); +#if POINT_DATA_RES + for( int c=0 ; c::SAMPLES ; c++ ) if( pData[c].weight ) +#endif // POINT_DATA_RES + { +#if POINT_DATA_RES + Real (*__splineValues)[SupportSize] = _splineValues[c][i+LeftSupportRadius][j+LeftSupportRadius][k+LeftSupportRadius]; + Real (*_wSplineValues)[SupportSize] = wSplineValues[c][i+LeftSupportRadius][j+LeftSupportRadius][k+LeftSupportRadius]; + Real (*_dSplineValues)[SupportSize] = dSplineValues[c][i+LeftSupportRadius][j+LeftSupportRadius][k+LeftSupportRadius]; +#else // !POINT_DATA_RES + Real (*__splineValues)[SupportSize] = _splineValues[i+LeftSupportRadius][j+LeftSupportRadius][k+LeftSupportRadius]; + Real (*_wSplineValues)[SupportSize] = wSplineValues[i+LeftSupportRadius][j+LeftSupportRadius][k+LeftSupportRadius]; + Real (*_dSplineValues)[SupportSize] = dSplineValues[i+LeftSupportRadius][j+LeftSupportRadius][k+LeftSupportRadius]; +#endif // POINT_DATA_RES + // Iterate over all neighbors whose support contains the point and accumulate the mutual integral + for( int ii=-LeftPointSupportRadius ; ii<=RightPointSupportRadius ; ii++ ) + for( int jj=-LeftPointSupportRadius ; jj<=RightPointSupportRadius ; jj++ ) + if( HasGradients ) + { + Real partialW_SplineValue = _wSplineValues[0][ii+LeftPointSupportRadius ] * __splineValues[1][jj+LeftPointSupportRadius ]; + Real partial__SplineValue = __splineValues[0][ii+LeftPointSupportRadius ] * __splineValues[1][jj+LeftPointSupportRadius ]; + Real partialD0SplineValue = _dSplineValues[0][ii+LeftPointSupportRadius ] * __splineValues[1][jj+LeftPointSupportRadius ]; + Real partialD1SplineValue = __splineValues[0][ii+LeftPointSupportRadius ] * _dSplineValues[1][jj+LeftPointSupportRadius ]; + Real* _pointValues = pointValues[i+ii+OverlapRadius][j+jj+OverlapRadius] + k + OverlapRadius; + Real* ___splineValues = __splineValues[2] + LeftPointSupportRadius; + Real* __dSplineValues = _dSplineValues[2] + LeftPointSupportRadius; + TreeOctNode* const * _neighbors = neighbors.neighbors[i+ii+OverlapRadius][j+jj+OverlapRadius] + k + OverlapRadius; + for( int kk=-LeftPointSupportRadius ; kk<=RightPointSupportRadius ; kk++ ) if( _isValidFEMNode( _neighbors[kk] ) ) + _pointValues[kk] += + partialW_SplineValue * ___splineValues[kk] + partialD0SplineValue * ___splineValues[kk] + partialD1SplineValue * ___splineValues[kk] + partial__SplineValue * __dSplineValues[kk]; + } + else + { + Real partialWSplineValue = _wSplineValues[0][ii+LeftPointSupportRadius ] * __splineValues[1][jj+LeftPointSupportRadius ]; + Real* _pointValues = pointValues[i+ii+OverlapRadius][j+jj+OverlapRadius] + k + OverlapRadius; + Real* ___splineValues = __splineValues[2] + LeftPointSupportRadius; + TreeOctNode* const * _neighbors = neighbors.neighbors[i+ii+OverlapRadius][j+jj+OverlapRadius] + k + OverlapRadius; + for( int kk=-LeftPointSupportRadius ; kk<=RightPointSupportRadius ; kk++ ) if( _isValidFEMNode( _neighbors[kk] ) ) + _pointValues[kk] += partialWSplineValue * ___splineValues[kk]; + } + } + } + } + } + pointValues[OverlapRadius][OverlapRadius][OverlapRadius] = diagonal; + int nodeIndex = neighbors.neighbors[OverlapRadius][OverlapRadius][OverlapRadius]->nodeData.nodeIndex; + if( isInterior ) // General case, so try to make fast + { + const TreeOctNode* const * _nodes = &neighbors.neighbors[0][0][0]; + const double* _stencil = &stencil( 0 , 0 , 0 ); + Real* _values = &pointValues[0][0][0]; + const static int CenterIndex = OverlapSize*OverlapSize*OverlapRadius + OverlapSize*OverlapRadius + OverlapRadius; + if( interpolationInfo ) for( int i=0 ; i( nodeIndex-offset , _values[CenterIndex] ); + for( int i=0 ; i( _nodes[i]->nodeData.nodeIndex-offset , _values[i] ); + } + else + { + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + Real temp = (Real)F.integrate( integrator , off , off ); + if( interpolationInfo ) temp += pointValues[OverlapRadius][OverlapRadius][OverlapRadius]; + row[count++] = MatrixEntry< Real >( nodeIndex-offset , temp ); + for( int x=0 ; x( _node->nodeData.nodeIndex-offset , temp ); + } + } + return count; +} + +template< class Real > +template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > +int Octree< Real >::_getMatrixAndUpdateConstraints( const FEMSystemFunctor& F , const InterpolationInfo< HasGradients >* interpolationInfo , SparseMatrix< Real >& matrix , DenseNodeData< Real , FEMDegree >& constraints , typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template Integrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) >& integrator , typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template ChildIntegrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) >& childIntegrator , const BSplineData< FEMDegree , BType >& bsData , LocalDepth depth , const DenseNodeData< Real , FEMDegree >& metSolution , bool coarseToFine ) +{ + static const int OverlapRadius = - BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapStart; + static const int OverlapSize = BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize; + + size_t start = _sNodesBegin(depth) , end = _sNodesEnd(depth) , range = end-start; + Stencil< double , OverlapSize > stencil , stencils[2][2][2]; + SystemCoefficients< FEMDegree , BType , FEMDegree , BType >::SetCentralSystemStencil ( F , integrator , stencil ); + SystemCoefficients< FEMDegree , BType , FEMDegree , BType >::SetCentralSystemStencils( F , childIntegrator , stencils ); + matrix.Resize( (int)range ); + std::vector< AdjacenctNodeKey > neighborKeys( std::max< int >( 1 , threads ) ); + for( size_t i=0 ; i neighbors; + neighborKey.template getNeighbors< false , OverlapRadius , OverlapRadius >( node , neighbors ); + int count = _getMatrixRowSize< FEMDegree , BType >( neighbors ); + // Allocate memory for the row + matrix.SetRowSize( i , count ); + + // Set the row entries + matrix.rowSizes[i] = _setMatrixRow( F , interpolationInfo , neighbors , matrix[i] , (int)start , integrator , stencil , bsData ); + if( coarseToFine && depth>0 ) + { + // Offset the constraints using the solution from lower resolutions. + int x , y , z; + Cube::FactorCornerIndex( (int)( node - node->parent->children ) , x , y , z ); + typename TreeOctNode::Neighbors< OverlapSize > pNeighbors; + neighborKey.template getNeighbors< false , OverlapRadius , OverlapRadius >( node->parent , pNeighbors ); + _updateConstraintsFromCoarser( F , interpolationInfo , neighbors , pNeighbors , node , constraints , metSolution , childIntegrator , stencils[x][y][z] , bsData ); + } + } + memoryUsage(); + return 1; +} + +template< class Real > +template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > +int Octree< Real >::_getSliceMatrixAndUpdateConstraints( const FEMSystemFunctor& F , const InterpolationInfo< HasGradients >* interpolationInfo , SparseMatrix< Real >& matrix , DenseNodeData< Real , FEMDegree >& constraints , typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template Integrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) >& integrator , typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template ChildIntegrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) >& childIntegrator , const BSplineData< FEMDegree , BType >& bsData , LocalDepth depth , int slice , const DenseNodeData< Real , FEMDegree >& metSolution , bool coarseToFine ) +{ + static const int OverlapSize = BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize; + static const int OverlapRadius = -BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapStart; + + int nStart = _sNodesBegin( depth , slice ) , nEnd = _sNodesEnd( depth , slice ); + size_t range = nEnd - nStart; + Stencil< double , OverlapSize > stencil , stencils[2][2][2]; + SystemCoefficients< FEMDegree , BType , FEMDegree , BType >::SetCentralSystemStencil ( F , integrator , stencil ); + SystemCoefficients< FEMDegree , BType , FEMDegree , BType >::SetCentralSystemStencils( F , childIntegrator , stencils ); + + matrix.Resize( (int)range ); + std::vector< AdjacenctNodeKey > neighborKeys( std::max< int >( 1 , threads ) ); + for( size_t i=0 ; i neighbors; + neighborKey.template getNeighbors< false , OverlapRadius , OverlapRadius >( node , neighbors ); + int count = _getMatrixRowSize< FEMDegree , BType >( neighbors ); + + // Allocate memory for the row + matrix.SetRowSize( i , count ); + + // Set the row entries + matrix.rowSizes[i] = _setMatrixRow( F , interpolationInfo , neighbors , matrix[i] , _sNodesBegin( depth , slice ) , integrator , stencil , bsData ); + + if( coarseToFine && depth>0 ) + { + // Offset the constraints using the solution from lower resolutions. + int x , y , z; + Cube::FactorCornerIndex( (int)( node - node->parent->children ) , x , y , z ); + typename TreeOctNode::Neighbors< OverlapSize > pNeighbors; + neighborKey.template getNeighbors< false, OverlapRadius , OverlapRadius >( node->parent , pNeighbors ); + _updateConstraintsFromCoarser( F , interpolationInfo , neighbors , pNeighbors , node , constraints , metSolution , childIntegrator , stencils[x][y][z] , bsData ); + } + } +#if !defined( _WIN32 ) && !defined( _WIN64 ) +#pragma message( "[WARNING] I'm not sure how expensive this system call is on non-Windows system. (You may want to comment this out.)" ) +#endif // !_WIN32 && !_WIN64 + memoryUsage(); + return 1; +} + +#ifndef MOD +#define MOD( a , b ) ( (a)>0 ? (a) % (b) : ( (b) - ( -(a) % (b) ) ) % (b) ) +#endif // MOD +template< class Real > +template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > +int Octree< Real >::_solveSystemGS( const FEMSystemFunctor& F , const BSplineData< FEMDegree , BType >& bsData , InterpolationInfo< HasGradients >* interpolationInfo , LocalDepth depth , DenseNodeData< Real , FEMDegree >& solution , DenseNodeData< Real , FEMDegree >& constraints , DenseNodeData< Real , FEMDegree >& metSolutionConstraints , int iters , bool coarseToFine , _SolverStats& stats , bool computeNorms ) +{ + const int OverlapRadius = -BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapStart; + typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template Integrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) > integrator; + typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template ChildIntegrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) > childIntegrator; + BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::SetIntegrator( integrator , depth ); + if( depth>0 ) BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::SetChildIntegrator( childIntegrator , depth-1 ); + + DenseNodeData< Real , FEMDegree >& metSolution = metSolutionConstraints; // This stores the up-sampled solution up to depth-2 + DenseNodeData< Real , FEMDegree >& metConstraints = metSolutionConstraints; // This stores the down-sampled constraints up to depth + + int sliceBegin = _BSplineBegin< FEMDegree , BType >( depth ) , sliceEnd = _BSplineEnd< FEMDegree , BType >( depth ); + double& systemTime = stats. systemTime; + double& solveTime = stats. solveTime; + double& evaluateTime = stats.evaluateTime; + systemTime = solveTime = evaluateTime = 0.; + + if( coarseToFine ) + { + if( depth>0 ) + { + // Up-sample the cumulative change in solution @(depth-2) into the cumulative change in solution @(depth-1) + if( depth-2>=0 ) _upSample< Real , FEMDegree , BType >( depth-1 , metSolution ); + // Add in the change in solution @(depth-1) +#pragma omp parallel for num_threads( threads ) + for( int i=_sNodesBegin(depth-1) ; i<_sNodesEnd(depth-1) ; i++ ) metSolution[i] += solution[i]; + // evaluate the points @(depth) using the cumulative change in solution @(depth-1) + if( interpolationInfo ) + { + evaluateTime = Time(); + _setPointValuesFromCoarser( *interpolationInfo , depth , bsData , metSolution ); + evaluateTime = Time() - evaluateTime; + } + } + } + else if( depth<_maxDepth ) for( int i=_sNodesBegin(depth) ; i<_sNodesEnd(depth) ; i++ ) constraints[i] -= metConstraints[i]; + double bNorm = 0 , inRNorm = 0 , outRNorm = 0; + if( depth>=0 ) + { + // Add padding space if we are computing residuals + int frontOffset = computeNorms ? OverlapRadius : 0 , backOffset = computeNorms ? OverlapRadius : 0; + // Set the number of in-memory slices required for a temporally blocked solver + int solveSlices = std::max< int >( 0 , std::min< int >( OverlapRadius*iters - (OverlapRadius-1) , sliceEnd-sliceBegin ) ) , matrixSlices = std::max< int >( 1 , std::min< int >( solveSlices+frontOffset+backOffset , sliceEnd-sliceBegin ) ); + // The list of matrices for each in-memory slices + std::vector< SparseMatrix< Real > > _M( matrixSlices ); + // The list of multi-colored indices for each in-memory slice + std::vector< std::vector< std::vector< int > > > __mcIndices( solveSlices ); + + int dir = coarseToFine ? -1 : 1 , start = coarseToFine ? sliceEnd-1 : sliceBegin , end = coarseToFine ? sliceBegin-1 : sliceEnd; + for( int frontSlice=start-frontOffset*dir , backSlice = frontSlice-OverlapRadius*(iters-1)*dir ; backSlice!=end+backOffset*dir ; frontSlice+=dir , backSlice+=dir ) + { + double t; + if( frontSlice+frontOffset*dir>=sliceBegin && frontSlice+frontOffset*dir ) start = _M[_s][j]; + ConstPointer( MatrixEntry< Real > ) end = start + _M[_s].rowSizes[j]; + ConstPointer( MatrixEntry< Real > ) e; + for( e=start ; e!=end ; e++ ) temp += X[ e->N ] * e->Value; + bNorm += B[j]*B[j]; + inRNorm += (temp-B[j]) * (temp-B[j]); + } + } + } + t = Time(); + // Compute the multicolor indices + if( iters && frontSlice>=sliceBegin && frontSlice( _sNodesBegin( depth , s ) , _sNodesEnd( depth , s ) , __mcIndices[__s] ); + } + // Advance through the in-memory slices, taking an appropriately sized stride + for( int slice=frontSlice ; slice*dir>=backSlice*dir ; slice-=OverlapRadius*dir ) + if( slice>=sliceBegin && slice::SolveGS( __mcIndices[__s] , _M[_s] , B , X , !coarseToFine , threads ); + } + solveTime += Time() - t; + // Compute residuals + if( computeNorms && backSlice-backOffset*dir>=sliceBegin && backSlice-backOffset*dir ) start = _M[_s][j]; + ConstPointer( MatrixEntry< Real > ) end = start + _M[_s].rowSizes[j]; + ConstPointer( MatrixEntry< Real > ) e; + for( e=start ; e!=end ; e++ ) temp += X[ e->N ] * e->Value; + outRNorm += (temp-B[j]) * (temp-B[j]); + } + } + } + } + if( computeNorms ) stats.bNorm2 = bNorm , stats.inRNorm2 = inRNorm , stats.outRNorm2 = outRNorm; + + if( !coarseToFine && depth>0 ) + { + // Explicitly compute the restriction of the met solution onto the coarser nodes + // and down-sample the previous accumulation + { + _updateCumulativeIntegralConstraintsFromFiner( F , bsData , depth , solution , metConstraints ); + if( interpolationInfo ) _updateCumulativeInterpolationConstraintsFromFiner( *interpolationInfo , bsData , depth , solution , metConstraints ); + if( depth<_maxDepth ) _downSample< Real , FEMDegree , BType >( depth , metConstraints ); + } + } + memoryUsage(); + + return iters; +} +#undef MOD + +template< class Real > +template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > +int Octree< Real >::_solveSystemCG( const FEMSystemFunctor& F , const BSplineData< FEMDegree , BType >& bsData , InterpolationInfo< HasGradients >* interpolationInfo , LocalDepth depth , DenseNodeData< Real , FEMDegree >& solution , DenseNodeData< Real , FEMDegree >& constraints , DenseNodeData< Real , FEMDegree >& metSolutionConstraints , int iters , bool coarseToFine , _SolverStats& stats , bool computeNorms , double accuracy ) +{ + typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template Integrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) > integrator; + typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template ChildIntegrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) > childIntegrator; + BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::SetIntegrator( integrator , depth ); + if( depth>0 ) BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::SetChildIntegrator( childIntegrator , depth-1 ); + + DenseNodeData< Real , FEMDegree >& metSolution = metSolutionConstraints; // This stores the up-sampled solution up to depth-2 + DenseNodeData< Real , FEMDegree >& metConstraints = metSolutionConstraints; // This stores the down-sampled constraints up to depth + + int iter = 0; + Pointer( Real ) X = GetPointer( & solution[0] + _sNodesBegin(depth) , _sNodesSize(depth) ); + Pointer( Real ) B = GetPointer( &constraints[0] + _sNodesBegin(depth) , _sNodesSize(depth) ); + SparseMatrix< Real > M; + double& systemTime = stats. systemTime; + double& solveTime = stats. solveTime; + double& evaluateTime = stats.evaluateTime; + systemTime = solveTime = evaluateTime = 0.; + + if( coarseToFine ) + { + if( depth>0 ) + { + // Up-sample the cumulative change in solution @(depth-2) into the cumulative change in solution @(depth-1) + if( depth-2>=0 ) _upSample< Real , FEMDegree , BType >( depth-1 , metSolution ); + // Add in the change in solution @(depth-1) +#pragma omp parallel for num_threads( threads ) + for( int i=_sNodesBegin(depth-1) ; i<_sNodesEnd(depth-1) ; i++ ) metSolution[i] += solution[i]; + // evaluate the points @(depth) using the cumulative change in solution @(depth-1) + if( interpolationInfo ) + { + evaluateTime = Time(); + _setPointValuesFromCoarser( *interpolationInfo , depth , bsData , metSolution ); + evaluateTime = Time() - evaluateTime; + } + } + } + else if( depth<_maxDepth ) for( int i=_sNodesBegin(depth) ; i<_sNodesEnd(depth) ; i++ ) constraints[i] -= metConstraints[i]; + + // Get the system matrix (and adjust the right-hand-side based on the coarser solution if prolonging) + systemTime = Time(); + _getMatrixAndUpdateConstraints( F , interpolationInfo , M , constraints , integrator , childIntegrator , bsData , depth , metSolution , coarseToFine ); + systemTime = Time()-systemTime; + + solveTime = Time(); + // Solve the linear system + accuracy = Real( accuracy / 100000 ) * M.rows; + int dim = _BSplineEnd< FEMDegree , BType >( depth ) - _BSplineBegin< FEMDegree , BType >( depth ); + int nonZeroRows = 0; + for( int i=0 ; ivalueWeight ) && HasPartitionOfUnity< BType >() && F.vanishesOnConstants() ); + double bNorm = 0 , inRNorm = 0 , outRNorm = 0; + if( computeNorms ) + { +#pragma omp parallel for num_threads( threads ) reduction( + : bNorm , inRNorm ) + for( int j=0 ; j ) start = M[j]; + ConstPointer( MatrixEntry< Real > ) end = start + M.rowSizes[j]; + ConstPointer( MatrixEntry< Real > ) e; + for( e=start ; e!=end ; e++ ) temp += X[ e->N ] * e->Value; + bNorm += B[j] * B[j]; + inRNorm += ( temp-B[j] ) * ( temp-B[j] ); + } + } + + iters = std::min< int >( nonZeroRows , iters ); + if( iters ) iter += SparseMatrix< Real >::SolveCG( M , ( ConstPointer( Real ) )B , iters , X , Real( accuracy ) , 0 , addDCTerm , false , threads ); + + solveTime = Time()-solveTime; + if( computeNorms ) + { +#pragma omp parallel for num_threads( threads ) reduction( + : outRNorm ) + for( int j=0 ; j ) start = M[j]; + ConstPointer( MatrixEntry< Real > ) end = start + M.rowSizes[j]; + ConstPointer( MatrixEntry< Real > ) e; + for( e=start ; e!=end ; e++ ) temp += X[ e->N ] * e->Value; + outRNorm += ( temp-B[j] ) * ( temp-B[j] ); + } + stats.bNorm2 = bNorm , stats.inRNorm2 = inRNorm , stats.outRNorm2 = outRNorm; + } + + // Copy the old solution into the buffer, write in the new solution, compute the change, and update the met solution + if( !coarseToFine && depth>0 ) + { + // Explicitly compute the restriction of the met solution onto the coarser nodes + // and down-sample the previous accumulation + { + _updateCumulativeIntegralConstraintsFromFiner( F , bsData , depth , solution , metConstraints ); + if( interpolationInfo ) _updateCumulativeInterpolationConstraintsFromFiner( *interpolationInfo , bsData , depth , solution , metConstraints ); + if( depth>_maxDepth ) _downSample< Real , FEMDegree , BType >( depth , metConstraints ); + } + } + memoryUsage(); + return iter; +} + +template< class Real > +template< int FEMDegree , BoundaryType BType > +int Octree< Real >::_getMatrixRowSize( const typename TreeOctNode::Neighbors< BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& neighbors ) const +{ + static const int OverlapSize = BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize; + static const int OverlapRadius = - BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapStart; + + int count = 0; + int nodeIndex = neighbors.neighbors[OverlapRadius][OverlapRadius][OverlapRadius]->nodeData.nodeIndex; + const TreeOctNode* const * _nodes = &neighbors.neighbors[0][0][0]; + for( int i=0 ; i +template< int FEMDegree1 , int FEMDegree2 > +void Octree< Real >::_SetParentOverlapBounds( const TreeOctNode* node , int& startX , int& endX , int& startY , int& endY , int& startZ , int& endZ ) +{ + const int OverlapStart = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::OverlapStart; + + if( node->parent ) + { + int x , y , z , c = (int)( node - node->parent->children ); + Cube::FactorCornerIndex( c , x , y , z ); + startX = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::ParentOverlapStart[x]-OverlapStart , endX = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::ParentOverlapEnd[x]-OverlapStart+1; + startY = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::ParentOverlapStart[y]-OverlapStart , endY = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::ParentOverlapEnd[y]-OverlapStart+1; + startZ = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::ParentOverlapStart[z]-OverlapStart , endZ = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::ParentOverlapEnd[z]-OverlapStart+1; + } +} + +// It is assumed that at this point, the evaluationg of the current depth's points, using the coarser resolution solution +// has already happened +template< class Real > +template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > +void Octree< Real >::_updateConstraintsFromCoarser( const FEMSystemFunctor& F , const InterpolationInfo< HasGradients >* interpolationInfo , const typename TreeOctNode::Neighbors< BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& neighbors , const typename TreeOctNode::Neighbors< BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& pNeighbors , TreeOctNode* node , DenseNodeData< Real , FEMDegree >& constraints , const DenseNodeData< Real , FEMDegree >& metSolution , const typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template ChildIntegrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) >& childIntegrator , const Stencil< double , BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& lapStencil , const BSplineData< FEMDegree , BType >& bsData ) const +{ + static const int LeftSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; + static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + static const int OverlapRadius = - BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapStart; + + if( _localDepth( node )<=0 ) return; + // This is a conservative estimate as we only need to make sure that the parent nodes don't overlap the child (not the parent itself) + bool isInterior = _isInteriorlyOverlapped< FEMDegree , FEMDegree >( node->parent ); + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + + // Offset the constraints using the solution from lower resolutions. + int startX , endX , startY , endY , startZ , endZ; + _SetParentOverlapBounds< FEMDegree , FEMDegree >( node , startX , endX , startY , endY , startZ , endZ ); + + for( int x=startX ; xnodeData.nodeIndex ]; + { + if( isInterior ) constraints[ node->nodeData.nodeIndex ] -= Real( lapStencil( x , y , z ) * _solution ); + else + { + LocalDepth _d ; LocalOffset _off; + _localDepthAndOffset( _node , _d , _off ); + constraints[ node->nodeData.nodeIndex ] -= (Real)F.integrate( childIntegrator , _off , off ) * _solution; + } + } + } + + if( interpolationInfo ) + { + double constraint = 0; + int fIdx[3]; + functionIndex< FEMDegree , BType >( node , fIdx ); + // evaluate the current node's basis function at adjacent points + for( int x=-LeftSupportRadius ; x<=RightSupportRadius ; x++ ) for( int y=-LeftSupportRadius ; y<=RightSupportRadius ; y++ ) for( int z=-LeftSupportRadius ; z<=RightSupportRadius ; z++ ) + { + const TreeOctNode* _node = neighbors.neighbors[x+OverlapRadius][y+OverlapRadius][z+OverlapRadius]; + if( _isValidSpaceNode( _node ) && (*interpolationInfo)( _node ) ) + { + const PointData< Real , HasGradients >& pData = *( (*interpolationInfo)( _node ) ); + constraint += _ConstraintCalculator_< Real , FEMDegree , HasGradients >::_CalculateConstraint_ + ( + pData , + bsData. baseBSplines[ fIdx[0] ][x+LeftSupportRadius] , + bsData. baseBSplines[ fIdx[1] ][y+LeftSupportRadius] , + bsData. baseBSplines[ fIdx[2] ][z+LeftSupportRadius] , + bsData.dBaseBSplines[ fIdx[0] ][x+LeftSupportRadius] , + bsData.dBaseBSplines[ fIdx[1] ][y+LeftSupportRadius] , + bsData.dBaseBSplines[ fIdx[2] ][z+LeftSupportRadius] + ); + } + } + constraints[ node->nodeData.nodeIndex ] -= Real( constraint ); + } +} + +// Given the solution @( depth ) add to the met constraints @( depth-1 ) +template< class Real > +template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor > +void Octree< Real >::_updateCumulativeIntegralConstraintsFromFiner( const FEMSystemFunctor& F , const BSplineData< FEMDegree , BType >& bsData , LocalDepth highDepth , const DenseNodeData< Real , FEMDegree >& fineSolution , DenseNodeData< Real , FEMDegree >& coarseConstraints ) const +{ + typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template ChildIntegrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) > childIntegrator; + BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::SetChildIntegrator( childIntegrator , highDepth-1 ); + + static const int OverlapSize = BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize; + static const int OverlapRadius = - BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapStart; + typedef typename TreeOctNode::NeighborKey< -BSplineSupportSizes< FEMDegree >::SupportStart , BSplineSupportSizes< FEMDegree >::SupportEnd >SupportKey; + + if( highDepth<=0 ) return; + // Get the stencil describing the Laplacian relating coefficients @(depth) with coefficients @(depth-1) + Stencil< double , OverlapSize > stencils[2][2][2]; + SystemCoefficients< FEMDegree , BType , FEMDegree , BType >::SetCentralSystemStencils( F , childIntegrator , stencils ); + size_t start = _sNodesBegin( highDepth) , end = _sNodesEnd(highDepth) , range = end-start; + int lStart = _sNodesBegin(highDepth-1); + + // Iterate over the nodes @( depth ) + std::vector< SupportKey > neighborKeys( std::max< int >( 1 , threads ) ); + for( size_t i=0 ; iparent->children ); + Cube::FactorCornerIndex( c , x , y , z ); + { + typename TreeOctNode::Neighbors< OverlapSize > pNeighbors; + neighborKey.template getNeighbors< false , OverlapRadius , OverlapRadius >( node->parent , pNeighbors ); + const Stencil< double , OverlapSize >& stencil = stencils[x][y][z]; + + bool isInterior = _isInteriorlyOverlapped< FEMDegree , FEMDegree >( node->parent ); + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + + // Offset the constraints using the solution from finer resolutions. + int startX , endX , startY , endY , startZ , endZ; + _SetParentOverlapBounds< FEMDegree , FEMDegree >( node , startX , endX , startY , endY , startZ , endZ ); + + Real solution = fineSolution[ node->nodeData.nodeIndex ]; + for( int x=startX ; xnodeData.nodeIndex ] += Real( stencil( x , y , z ) * solution ); + else + { + LocalDepth _d ; LocalOffset _off; + _localDepthAndOffset( _node , _d , _off ); +#pragma omp atomic + coarseConstraints[ _node->nodeData.nodeIndex ] += Real( F.integrate( childIntegrator , _off , off ) * solution ); + } + } + } + } +} + +template< class Real > +template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > +void Octree< Real >::setSystemMatrix( const FEMSystemFunctor& F , const InterpolationInfo< HasGradients >* interpolationInfo , LocalDepth depth , SparseMatrix< Real >& matrix ) const +{ + if( depth<0 || depth>_maxDepth ) fprintf( stderr , "[ERROR] System depth out of bounds: %d <= %d <= %d\n" , 0 , depth , _maxDepth ) , exit( 0 ); + typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template Integrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) > integrator; + BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::SetIntegrator( integrator , depth ); + BSplineData< FEMDegree , BType > bsData( depth ); + + static const int OverlapRadius = - BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapStart; + static const int OverlapSize = BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize; + + Stencil< double , OverlapSize > stencil; + SystemCoefficients< FEMDegree , BType , FEMDegree , BType >::SetCentralSystemStencil ( F , integrator , stencil ); + + matrix.Resize( _sNodesSize(depth) ); + std::vector< AdjacenctNodeKey > neighborKeys( std::max< int >( 1 , threads ) ); + for( size_t i=0 ; i neighbors; + neighborKey.template getNeighbors< false , OverlapRadius , OverlapRadius >( _sNodes.treeNodes[i] , neighbors ); + + matrix.SetRowSize( ii , _getMatrixRowSize< FEMDegree , BType >( neighbors ) ); + matrix.rowSizes[ii] = _setMatrixRow( F , interpolationInfo , neighbors , matrix[ii] , _sNodesBegin(depth) , integrator , stencil , bsData ); + } +} + +template< class Real > +template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > +DenseNodeData< Real , FEMDegree > Octree< Real >::solveSystem( const FEMSystemFunctor& F , InterpolationInfo< HasGradients >* interpolationInfo , DenseNodeData< Real , FEMDegree >& constraints , LocalDepth maxSolveDepth , const typename Octree< Real >::SolverInfo& solverInfo ) +{ + BSplineData< FEMDegree , BType > bsData( maxSolveDepth ); + + maxSolveDepth = std::min< LocalDepth >( maxSolveDepth , _maxDepth ); + int iter = 0; + const int _iters = std::max< int >( 0 , solverInfo.iters ); + + DenseNodeData< Real , FEMDegree > solution( _sNodesEnd( _maxDepth ) ); + memset( &solution[0] , 0 , sizeof(Real) * _sNodesEnd( _maxDepth ) ); + + DenseNodeData< Real , FEMDegree > metSolution( _sNodesEnd( _maxDepth-1 ) ); + memset( &metSolution[0] , 0 , sizeof(Real)*_sNodesEnd( _maxDepth-1 ) ); + for( LocalDepth d=0 ; d<=maxSolveDepth ; d++ ) + { + int iters = (int)ceil( _iters * pow( solverInfo.lowResIterMultiplier , maxSolveDepth-d ) ); + _SolverStats sStats; + if( !d ) iter = _solveSystemCG( F , bsData , interpolationInfo , d , solution , constraints , metSolution , _sNodesSize(d) , true , sStats , solverInfo.showResidual , 0 ); + else + { + if( d>solverInfo.cgDepth ) iter = _solveSystemGS( F , bsData , interpolationInfo , d , solution , constraints , metSolution , iters , true , sStats , solverInfo.showResidual ); + else iter = _solveSystemCG( F , bsData , interpolationInfo , d , solution , constraints , metSolution , iters , true , sStats , solverInfo.showResidual , solverInfo.cgAccuracy ); + } + int femNodes = 0; +#pragma omp parallel for reduction( + : femNodes ) + for( int i=_sNodesBegin(d) ; i<_sNodesEnd(d) ; i++ ) if( _isValidFEMNode( _sNodes.treeNodes[i] ) ) femNodes++; + if( solverInfo.verbose ) + { + if( maxSolveDepth<10 ) printf( "Depth[%d/%d]:\t" , d , maxSolveDepth ); + else printf( "Depth[%2d/%d]:\t" , d , maxSolveDepth ); + printf( "Evaluated / Got / Solved in: %6.3f / %6.3f / %6.3f\t(%.3f MB)\tNodes: %d\n" , sStats.evaluateTime , sStats.systemTime , sStats.solveTime , _localMemoryUsage , femNodes ); + } + if( solverInfo.showResidual && iters ) + { + for( LocalDepth dd=0 ; dd %.4e -> %.4e (%.2e) [%d]\n" , d<=solverInfo.cgDepth ? "CG" : "GS" , sqrt( sStats.bNorm2 ) , sqrt( sStats.inRNorm2 ) , sqrt( sStats.outRNorm2 ) , sqrt( sStats.outRNorm2 / sStats.bNorm2 ) , iters ); + } + } + memoryUsage(); + return solution; +} + +template< class Real > +template< int FEMDegree > +DenseNodeData< Real , FEMDegree > Octree< Real >::initDenseNodeData( void ) +{ + DenseNodeData< Real , FEMDegree > constraints( _sNodes.size() ); + memset( &constraints[0] , 0 , sizeof(Real)*_sNodes.size() ); + return constraints; +} +template< > template< > float Octree< float >::_Dot( const float & r1 , const float & r2 ){ return r1*r2; } +template< > template< > double Octree< double >::_Dot( const double& r1 , const double& r2 ){ return r1*r2; } +template< > template< > float Octree< float >::_Dot( const Point3D< float >& p1 , const Point3D< float >& p2 ){ return Point3D< float >::Dot( p1 , p2 ); } +template< > template< > double Octree< double >::_Dot( const Point3D< double >& p1 , const Point3D< double >& p2 ){ return Point3D< double >::Dot( p1 , p2 ); } +template< > template< > bool Octree< float >::_IsZero( const float & r ){ return r==0; } +template< > template< > bool Octree< double >::_IsZero( const double& r ){ return r==0; } +template< > template< > bool Octree< float >::_IsZero( const Point3D< float >& p ){ return p[0]==0 && p[1]==0 && p[2]==0; } +template< > template< > bool Octree< double >::_IsZero( const Point3D< double >& p ){ return p[0]==0 && p[1]==0 && p[2]==0; } +template< class Real > +template< int FEMDegree , BoundaryType FEMBType , int CDegree , BoundaryType CBType , class FEMConstraintFunctor , class Coefficients , class D , class _D > +void Octree< Real >::_addFEMConstraints( const FEMConstraintFunctor& F , const Coefficients& coefficients , DenseNodeData< Real , FEMDegree >& constraints , LocalDepth maxDepth ) +{ + typedef typename TreeOctNode::NeighborKey< -BSplineSupportSizes< FEMDegree >::SupportStart , BSplineSupportSizes< FEMDegree >::SupportEnd > SupportKey; + const int CFEMOverlapSize = BSplineOverlapSizes< CDegree , FEMDegree >::OverlapSize; + const int LeftCFEMOverlapRadius = -BSplineOverlapSizes< CDegree , FEMDegree >::OverlapStart; + const int RightCFEMOverlapRadius = BSplineOverlapSizes< CDegree , FEMDegree >::OverlapEnd; + const int LeftFEMCOverlapRadius = -BSplineOverlapSizes< FEMDegree , CDegree >::OverlapStart; + const int RightFEMCOverlapRadius = BSplineOverlapSizes< FEMDegree , CDegree >::OverlapEnd; + + // To set the constraints, we iterate over the + // splatted normals and compute the dot-product of the + // divergence of the normal field with all the basis functions. + // Within the same depth: set directly as a gather + // Coarser depths + maxDepth = std::min< LocalDepth >( maxDepth , _maxDepth ); + DenseNodeData< Real , FEMDegree >* __constraints = new DenseNodeData< Real , FEMDegree >( _sNodesEnd(maxDepth-1) ); + DenseNodeData< Real , FEMDegree >& _constraints = *__constraints; + memset( &_constraints[0] , 0 , sizeof(Real)*( _sNodesEnd(maxDepth-1) ) ); + memoryUsage(); + + for( LocalDepth d=maxDepth ; d>=0 ; d-- ) + { + Stencil< _D , CFEMOverlapSize > stencil , stencils[2][2][2]; + typename SystemCoefficients< CDegree , CBType , FEMDegree , FEMBType >:: Integrator integrator; + typename SystemCoefficients< FEMDegree , FEMBType , CDegree , CBType >::ChildIntegrator childIntegrator; + BSplineIntegrationData< CDegree , CBType , FEMDegree , FEMBType >::SetIntegrator( integrator , d ); + if( d>0 ) BSplineIntegrationData< FEMDegree , FEMBType , CDegree , CBType >::SetChildIntegrator( childIntegrator , d-1 ); + SystemCoefficients< CDegree , CBType , FEMDegree , FEMBType >::template SetCentralConstraintStencil < false >( F, integrator , stencil ); + SystemCoefficients< FEMDegree , FEMBType , CDegree , CBType >::template SetCentralConstraintStencils< true >( F, childIntegrator , stencils ); + + std::vector< SupportKey > neighborKeys( std::max< int >( 1 , threads ) ); + for( size_t i=0 ; i neighbors; + neighborKey.template getNeighbors< false , LeftFEMCOverlapRadius , RightFEMCOverlapRadius >( node , neighbors ); + bool isInterior = _isInteriorlyOverlapped< FEMDegree , CDegree >( node ) , isInterior2 = _isInteriorlyOverlapped< CDegree , FEMDegree >( node->parent ); + + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + // Set constraints from current depth + // Gather the constraints from the vector-field at _node into the constraint stored with node + if( _isValidFEMNode( node ) ) + { + for( int x=startX ; x( _node ) ) + { + const D* d = coefficients( _node ); + if( d ) + if( isInterior ) { constraints[i] += _Dot( (D)stencil( x , y , z ) , *d ); } + else + { + LocalDepth _d ; LocalOffset _off; + _localDepthAndOffset( _node , _d , _off ); + constraints[i] += _Dot( *d , (D)F.template integrate< false >( integrator , _off , off ) ); + } + } + } + _SetParentOverlapBounds< CDegree , FEMDegree >( node , startX , endX , startY , endY , startZ , endZ ); + } + if( !isValidFEMNode< CDegree , CBType >( node ) ) continue; + const D* _data = coefficients( node ); + if( !_data ) continue; + const D& data = *_data; + if( _IsZero( data ) ) continue; + + // Set the _constraints for the parents + if( d>0 ) + { + int cx , cy , cz; + Cube::FactorCornerIndex( (int)( node - node->parent->children ) , cx , cy ,cz ); + const Stencil< _D , CFEMOverlapSize >& _stencil = stencils[cx][cy][cz]; + + neighborKey.template getNeighbors< false , LeftCFEMOverlapRadius , RightCFEMOverlapRadius >( node->parent , neighbors ); + + for( int x=startX ; x( childIntegrator , _off , off ) ); + } +#pragma omp atomic + _constraints[ _node->nodeData.nodeIndex ] += c; + } + } + } + } + memoryUsage(); + } + + // Fine-to-coarse down-sampling of constraints + for( LocalDepth d=maxDepth-1 ; d>0 ; d-- ) _downSample< Real , FEMDegree , FEMBType >( d , _constraints ); + + // Add the accumulated constraints from all finer depths +#pragma omp parallel for num_threads( threads ) + for( int i=0 ; i<_sNodesEnd(maxDepth-1) ; i++ ) constraints[i] += _constraints[i]; + + delete __constraints; + + DenseNodeData< D , CDegree > _coefficients( _sNodesEnd(maxDepth-1) ); + memset( &_coefficients[0] , 0 , sizeof(D) * _sNodesEnd(maxDepth-1) ); + for( LocalDepth d=maxDepth-1 ; d>=0 ; d-- ) + { +#pragma omp parallel for num_threads( threads ) + for( int i=_sNodesBegin(d) ; i<_sNodesEnd(d) ; i++ ) if( isValidFEMNode< CDegree , CBType >( _sNodes.treeNodes[i] ) ) + { + const D* d = coefficients( _sNodes.treeNodes[i] ); + if( d ) _coefficients[i] += *d; + } + } + + // Coarse-to-fine up-sampling of coefficients + for( LocalDepth d=1 ; d( d , _coefficients ); + + // Compute the contribution from all coarser depths + for( LocalDepth d=1 ; d<=maxDepth ; d++ ) + { + size_t start = _sNodesBegin( d ) , end = _sNodesEnd( d ) , range = end - start; + Stencil< _D , CFEMOverlapSize > stencils[2][2][2]; + typename SystemCoefficients< CDegree , CBType , FEMDegree , FEMBType >::ChildIntegrator childIntegrator; + BSplineIntegrationData< CDegree , CBType , FEMDegree , FEMBType >::SetChildIntegrator( childIntegrator , d-1 ); + SystemCoefficients< CDegree , CBType , FEMDegree , FEMBType >::template SetCentralConstraintStencils< false >( F , childIntegrator , stencils ); + std::vector< SupportKey > neighborKeys( std::max< int >( 1 , threads ) ); + for( size_t i=0 ; i( node , startX , endX , startY , endY , startZ , endZ ); + typename TreeOctNode::Neighbors< CFEMOverlapSize > pNeighbors; + neighborKey.template getNeighbors< false , LeftFEMCOverlapRadius , RightFEMCOverlapRadius >( node->parent , pNeighbors ); + + bool isInterior = _isInteriorlyOverlapped< FEMDegree , CDegree >( node->parent ); + int cx , cy , cz; + if( d>0 ) + { + int c = int( node - node->parent->children ); + Cube::FactorCornerIndex( c , cx , cy , cz ); + } + else cx = cy = cz = 0; + Stencil< _D , CFEMOverlapSize >& _stencil = stencils[cx][cy][cz]; + + Real constraint = Real(0); + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + for( int x=startX ; x( _node ) ) + { + if( isInterior ) constraint += _Dot( _coefficients[ _node->nodeData.nodeIndex ] , (D)_stencil( x , y , z ) ); + else + { + LocalDepth _d ; LocalOffset _off; + _localDepthAndOffset ( _node , _d , _off ); + constraint += _Dot( _coefficients[ _node->nodeData.nodeIndex ] , (D)F.template integrate< false >( childIntegrator , _off , off ) ); + } + } + } + constraints[i] += constraint; + } + } + memoryUsage(); +} + +template< class Real > +template< int FEMDegree , BoundaryType BType , bool HasGradients > +void Octree< Real >::addInterpolationConstraints( const InterpolationInfo< HasGradients >& interpolationInfo , DenseNodeData< Real , FEMDegree >& constraints , LocalDepth maxDepth ) +{ + typedef typename TreeOctNode::NeighborKey< -BSplineSupportSizes< FEMDegree >::SupportStart , BSplineSupportSizes< FEMDegree >::SupportEnd > SupportKey; + maxDepth = std::min< LocalDepth >( maxDepth , _maxDepth ); + { + static const int OverlapSize = BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize; + static const int LeftSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; + static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + static const int OverlapRadius = - BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapStart; + BSplineData< FEMDegree , BType > bsData( _maxDepth ); + for( int d=0 ; d<=maxDepth ; d++ ) + { + std::vector< SupportKey > neighborKeys( std::max< int >( 1 , threads ) ); + for( size_t i=0 ; i neighbors; + neighborKey.template getNeighbors< false , OverlapRadius , OverlapRadius >( node , neighbors ); + + double constraint = 0; + int fIdx[3]; + functionIndex< FEMDegree , BType >( node , fIdx ); + // evaluate the current node's basis function at adjacent points + for( int x=-LeftSupportRadius ; x<=RightSupportRadius ; x++ ) for( int y=-LeftSupportRadius ; y<=RightSupportRadius ; y++ ) for( int z=-LeftSupportRadius ; z<=RightSupportRadius ; z++ ) + { + const TreeOctNode* _node = neighbors.neighbors[x+OverlapRadius][y+OverlapRadius][z+OverlapRadius]; + if( _isValidSpaceNode( _node ) && interpolationInfo( _node ) ) + { + const PointData< Real , HasGradients >& pData = *( interpolationInfo( _node ) ); + constraint += _ConstraintCalculator_< Real , FEMDegree , HasGradients >::_CalculateConstraint_ + ( + pData , + bsData. baseBSplines[ fIdx[0] ][x+LeftSupportRadius] , + bsData. baseBSplines[ fIdx[1] ][y+LeftSupportRadius] , + bsData. baseBSplines[ fIdx[2] ][z+LeftSupportRadius] , + bsData.dBaseBSplines[ fIdx[0] ][x+LeftSupportRadius] , + bsData.dBaseBSplines[ fIdx[1] ][y+LeftSupportRadius] , + bsData.dBaseBSplines[ fIdx[2] ][z+LeftSupportRadius] , + interpolationInfo.valueWeight , interpolationInfo.gradientWeight + ); + } + } + constraints[ node->nodeData.nodeIndex ] += (Real)constraint; + } + } + memoryUsage(); + } +} +template< class Real > +template< int FEMDegree1 , BoundaryType FEMBType1 , int FEMDegree2 , BoundaryType FEMBType2 , class DotFunctor , bool HasGradients , class Coefficients1 , class Coefficients2 > +double Octree< Real >::_dot( const DotFunctor& F , const InterpolationInfo< HasGradients >* iInfo , const Coefficients1& coefficients1 , const Coefficients2& coefficients2 ) const +{ + double dot = 0; + + // Calculate the contribution from @(depth,depth) + { + typedef typename TreeOctNode::ConstNeighborKey< -BSplineSupportSizes< FEMDegree1 >::SupportStart , BSplineSupportSizes< FEMDegree1 >::SupportEnd > SupportKey; + const int OverlapSize = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::OverlapSize; + const int LeftOverlapRadius = -BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::OverlapStart; + const int RightOverlapRadius = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::OverlapEnd; + + for( LocalDepth d=0 ; d<=_maxDepth ; d++ ) + { + Stencil< double , OverlapSize > stencil; + typename SystemCoefficients< FEMDegree1 , FEMBType1 , FEMDegree2 , FEMBType2 >::Integrator integrator; + BSplineIntegrationData< FEMDegree1 , FEMBType1 , FEMDegree2 , FEMBType2 >::SetIntegrator( integrator , d ); + SystemCoefficients< FEMDegree1 , FEMBType1 , FEMDegree2 , FEMBType2 >::template SetCentralConstraintStencil< false , DotFunctor >( F , integrator , stencil ); + + std::vector< SupportKey > neighborKeys( std::max< int >( 1 , threads ) ); + for( size_t i=0 ; i( node ) && ( _data1=coefficients1(node) ) ) + { + SupportKey& neighborKey = neighborKeys[ omp_get_thread_num() ]; + typename TreeOctNode::ConstNeighbors< OverlapSize > neighbors; + neighborKey.template getNeighbors< LeftOverlapRadius , RightOverlapRadius >( node , neighbors ); + bool isInterior = _isInteriorlyOverlapped< FEMDegree1 , FEMDegree2 >( node ); + + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + + for( int x=0 ; x( _node ) && ( _data2=coefficients2( _node ) ) ) + if( isInterior ) { dot += (*_data1) * (*_data2 ) * stencil( x , y , z ); } + else + { + LocalDepth _d ; LocalOffset _off; + _localDepthAndOffset( _node , _d , _off ); + dot += (*_data1) * (*_data2) * F.template integrate< false >( integrator , off , _off ); + } + } + } + } + } + } + // Calculate the contribution from @(::SupportStart , BSplineSupportSizes< FEMDegree1 >::SupportEnd > SupportKey; + const int OverlapSize = BSplineOverlapSizes< FEMDegree2 , FEMDegree1 >::OverlapSize; + const int LeftOverlapRadius = -BSplineOverlapSizes< FEMDegree2 , FEMDegree1 >::OverlapStart; + const int RightOverlapRadius = BSplineOverlapSizes< FEMDegree2 , FEMDegree1 >::OverlapEnd; + + DenseNodeData< Real , FEMDegree1 > cumulative1( _sNodesEnd( _maxDepth-1 ) ); + if( _maxDepth>0 ) memset( &cumulative1[0] , 0 , sizeof(Real) * _sNodesEnd( _maxDepth-1 ) ); + + for( LocalDepth d=1 ; d<=_maxDepth ; d++ ) + { + // Update the cumulative coefficients with the coefficients @(depth-1) +#pragma omp parallel for + for( int i=_sNodesBegin(d-1) ; i<_sNodesEnd(d-1) ; i++ ) + { + const Real* _data1 = coefficients1( _sNodes.treeNodes[i] ); + if( _data1 ) cumulative1[i] += *_data1; + } + + Stencil< double , OverlapSize > stencils[2][2][2]; + typename SystemCoefficients< FEMDegree1 , FEMBType1 , FEMDegree2 , FEMBType2 >::ChildIntegrator childIntegrator; + BSplineIntegrationData< FEMDegree1 , FEMBType1 , FEMDegree2 , FEMBType2 >::SetChildIntegrator( childIntegrator , d-1 ); + SystemCoefficients< FEMDegree1 , FEMBType1 , FEMDegree2 , FEMBType2 >::template SetCentralConstraintStencils< false >( F, childIntegrator , stencils ); + + std::vector< SupportKey > neighborKeys( std::max< int >( 1 , threads ) ); + for( size_t i=0 ; i( node ) && ( _data2=coefficients2( node ) ) ) + { + SupportKey& neighborKey = neighborKeys[ omp_get_thread_num() ]; + bool isInterior = _isInteriorlyOverlapped< FEMDegree1 , FEMDegree2 >( node->parent ); + + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + + int cx , cy , cz; + Cube::FactorCornerIndex( (int)( node - node->parent->children ) , cx , cy ,cz ); + const Stencil< double , OverlapSize >& _stencil = stencils[cx][cy][cz]; + typename TreeOctNode::ConstNeighbors< OverlapSize > neighbors; + neighborKey.template getNeighbors< LeftOverlapRadius , RightOverlapRadius >( node->parent , neighbors ); + + int startX , endX , startY , endY , startZ , endZ; + _SetParentOverlapBounds< FEMDegree2 , FEMDegree1 >( node , startX , endX , startY , endY , startZ , endZ ); + for( int x=startX ; x( _node ) && ( _data1=cumulative1(_node) ) ) + { + if( isInterior ) dot += (*_data1) * (*_data2) * _stencil( x , y , z ); + else + { + LocalDepth _d ; LocalOffset _off; + _localDepthAndOffset( _node , _d , _off ); + dot += (*_data1) * (*_data2) * F.template integrate< false >( childIntegrator , _off , off ); + } + } + } + } + } + // Up sample the cumulative coefficients for the next level + if( d<_maxDepth ) _upSample< Real , FEMDegree1 , FEMBType1 >( d , cumulative1 ); + } + } + + // Calculate the contribution from @(>depth,depth) + { + typedef typename TreeOctNode::ConstNeighborKey< -BSplineSupportSizes< FEMDegree2 >::SupportStart , BSplineSupportSizes< FEMDegree2 >::SupportEnd > SupportKey; + const int OverlapSize = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::OverlapSize; + const int LeftOverlapRadius = -BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::OverlapStart; + const int RightOverlapRadius = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::OverlapEnd; + + DenseNodeData< Real , FEMDegree2 > cumulative2( _sNodesEnd( _maxDepth-1 ) ); + if( _maxDepth>0 ) memset( &cumulative2[0] , 0 , sizeof(Real) * _sNodesEnd( _maxDepth-1 ) ); + + for( LocalDepth d=_maxDepth ; d>0 ; d-- ) + { + Stencil< double , OverlapSize > stencils[2][2][2]; + typename SystemCoefficients< FEMDegree2 , FEMBType2 , FEMDegree1 , FEMBType1 >::ChildIntegrator childIntegrator; + BSplineIntegrationData< FEMDegree2 , FEMBType2 , FEMDegree1 , FEMBType1 >::SetChildIntegrator( childIntegrator , d-1 ); + SystemCoefficients< FEMDegree2 , FEMBType2 , FEMDegree1 , FEMBType1 >::template SetCentralConstraintStencils< true >( F , childIntegrator , stencils ); + + std::vector< SupportKey > neighborKeys( std::max< int >( 1 , threads ) ); + for( size_t i=0 ; i( node ) && ( _data1=coefficients1( node ) ) ) + { + SupportKey& neighborKey = neighborKeys[ omp_get_thread_num() ]; + bool isInterior = _isInteriorlyOverlapped< FEMDegree2 , FEMDegree1 >( node->parent ); + + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + + int cx , cy , cz; + Cube::FactorCornerIndex( (int)( node - node->parent->children ) , cx , cy ,cz ); + const Stencil< double , OverlapSize >& _stencil = stencils[cx][cy][cz]; + typename TreeOctNode::ConstNeighbors< OverlapSize > neighbors; + neighborKey.template getNeighbors< LeftOverlapRadius , RightOverlapRadius >( node->parent , neighbors ); + + int startX , endX , startY , endY , startZ , endZ; + _SetParentOverlapBounds< FEMDegree1 , FEMDegree2 >( node , startX , endX , startY , endY , startZ , endZ ); + + for( int x=startX ; x( _node ) ) + { + Real _dot; + if( isInterior ) _dot = (*_data1) * _stencil( x , y , z ); + else + { + LocalDepth _d ; LocalOffset _off; + _localDepthAndOffset( _node , _d , _off ); + _dot = (*_data1) * F.template integrate< true >( childIntegrator , _off , off ); + } +#pragma omp atomic + cumulative2[ _node->nodeData.nodeIndex ] += _dot; + } + } + } + } + // Update the dot-product using the cumulative constraints @(depth-1) +#pragma omp parallel for num_threads( threads ) reduction( + : dot ) + for( int i=_sNodesBegin(d-1) ; i<_sNodesEnd(d-1) ; i++ ) + { + const TreeOctNode* node = _sNodes.treeNodes[i]; + const Real* _data2; + if( isValidFEMNode< FEMDegree2 , FEMBType2 >( node ) && ( _data2=coefficients2( node ) ) ) dot += cumulative2[ node->nodeData.nodeIndex ] * (*_data2); + } + + // Down-sample the cumulative constraints from @(depth-1) to @(depth-2) for the next pass + if( d-1>0 ) _downSample< Real , FEMDegree2 , FEMBType2 >( d-1 , cumulative2 ); + } + } + + if( iInfo ) + { + MultiThreadedEvaluator< FEMDegree1 , FEMBType1 > mt1( this , coefficients1 , threads ); + MultiThreadedEvaluator< FEMDegree2 , FEMBType2 > mt2( this , coefficients2 , threads ); + +#pragma omp parallel for num_threads( threads ) reduction( + : dot ) + for( int i=_sNodesBegin(0) ; i<_sNodesEnd(_maxDepth) ; i++ ) + { + if( _isValidSpaceNode( _sNodes.treeNodes[i] ) && !_isValidSpaceNode( _sNodes.treeNodes[i]->children ) && (*iInfo)( _sNodes.treeNodes[i] ) ) + { + + const PointData< Real , HasGradients >& pData = *( (*iInfo)( _sNodes.treeNodes[i] ) ); +#if POINT_DATA_RES + for( int c=0 ; c::SAMPLES ; c++ ) if( pData[c].weight ) + { + Point3D< Real > p = pData[c].position; + Real w = pData[c].weight; + if( HasGradients ) + { + std::pair< Real , Point3D< Real > > v1 = mt1.valueAndGradient( p , omp_get_thread_num() ); + std::pair< Real , Point3D< Real > > v2 = mt2.valueAndGradient( p , omp_get_thread_num() ); + dot += v1.first * v2.first * w * iInfo->valueWeight + Point3D< Real >::Dot( v1.second , v2.second ) * w * iInfo->gradientWeight; + } + else dot += mt1.value( p , omp_get_thread_num() ) * mt2.value( p , omp_get_thread_num() ) * w * iInfo->valueWeight; + } +#else // !POINT_DATA_RES + Point3D< Real > p = pData.position; + Real w = pData.weight; + if( HasGradients ) + { + std::pair< Real , Point3D< Real > > v1 = mt1.valueAndGradient( p , omp_get_thread_num() ); + std::pair< Real , Point3D< Real > > v2 = mt2.valueAndGradient( p , omp_get_thread_num() ); + dot += v1.first * v2.first * w * iInfo->valueWeight + Point3D< Real >::Dot( v1.second , v2.second ) * w * iInfo->gradientWeight; + } + else dot += mt1.value( p , omp_get_thread_num() ) * mt2.value( p , omp_get_thread_num() ) * w * iInfo->valueWeight; +#endif // POINT_DATA_RES + } + } + } + + return dot; +} diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.WeightedSamples.inl b/src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.WeightedSamples.inl new file mode 100644 index 000000000..279d91b91 --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.WeightedSamples.inl @@ -0,0 +1,443 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +// evaluate the result of splatting along a plane and then evaluating at a point on the plane. +template< int Degree > double GetScaleValue( void ) +{ + double centerValues[Degree+1]; + Polynomial< Degree >::BSplineComponentValues( 0.5 , centerValues ); + double scaleValue = 0; + for( int i=0 ; i<=Degree ; i++ ) scaleValue += centerValues[i] * centerValues[i]; + return 1./ scaleValue; +} +template< class Real > +template< int WeightDegree > +void Octree< Real >::_addWeightContribution( DensityEstimator< WeightDegree >& densityWeights , TreeOctNode* node , Point3D< Real > position , PointSupportKey< WeightDegree >& weightKey , Real weight ) +{ + static const double ScaleValue = GetScaleValue< WeightDegree >(); + double dx[ DIMENSION ][ PointSupportKey< WeightDegree >::Size ]; + typename TreeOctNode::Neighbors< PointSupportKey< WeightDegree >::Size >& neighbors = weightKey.template getNeighbors< true >( node , _NodeInitializer ); + densityWeights.reserve( NodeCount() ); + Point3D< Real > start; + Real w; + _startAndWidth( node , start , w ); + for( int dim=0 ; dim::BSplineComponentValues( ( position[dim]-start[dim] ) / w , dx[dim] ); + + weight *= (Real)ScaleValue; + + for( int i=0 ; i::Size ; i++ ) for( int j=0 ; j::Size ; j++ ) + { + double dxdy = dx[0][i] * dx[1][j] * weight; + TreeOctNode** _neighbors = neighbors.neighbors[i][j]; + for( int k=0 ; k::Size ; k++ ) if( _neighbors[k] ) densityWeights[ _neighbors[k] ] += Real( dxdy * dx[2][k] ); + } +} + +template< class Real > +template< int WeightDegree , class PointSupportKey > +Real Octree< Real >::_getSamplesPerNode( const DensityEstimator< WeightDegree >& densityWeights , const TreeOctNode* node , Point3D< Real > position , PointSupportKey& weightKey ) const +{ + Real weight = 0; + double dx[ DIMENSION ][ PointSupportKey::Size ]; + const typename PointSupportKey::template Neighbors< PointSupportKey::Size >& neighbors = weightKey.getNeighbors( node ); + + Point3D< Real > start; + Real w; + _startAndWidth( node , start , w ); + + for( int dim=0 ; dim::BSplineComponentValues( ( position[dim]-start[dim] ) / w , dx[dim] ); + + for( int i=0 ; i +template< int WeightDegree , class PointSupportKey > +void Octree< Real >::_getSampleDepthAndWeight( const DensityEstimator< WeightDegree >& densityWeights , const TreeOctNode* node , Point3D< Real > position , PointSupportKey& weightKey , Real& depth , Real& weight ) const +{ + const TreeOctNode* temp = node; + while( _localDepth( temp )>densityWeights.kernelDepth() ) temp = temp->parent; + weight = _getSamplesPerNode( densityWeights , temp , position , weightKey ); + if( weight>=(Real)1. ) depth = Real( _localDepth( temp ) + log( weight ) / log(double(1<<(DIMENSION-1))) ); + else + { + Real oldWeight , newWeight; + oldWeight = newWeight = weight; + while( newWeight<(Real)1. && temp->parent ) + { + temp=temp->parent; + oldWeight = newWeight; + newWeight = _getSamplesPerNode( densityWeights , temp , position , weightKey ); + } + depth = Real( _localDepth( temp ) + log( newWeight ) / log( newWeight / oldWeight ) ); + } + weight = Real( pow( double(1<<(DIMENSION-1)) , -double(depth) ) ); +} +template< class Real > +template< int WeightDegree , class PointSupportKey > +void Octree< Real >::_getSampleDepthAndWeight( const DensityEstimator< WeightDegree >& densityWeights , Point3D< Real > position , PointSupportKey& weightKey , Real& depth , Real& weight ) const +{ + TreeOctNode* temp; + Point3D< Real > myCenter( (Real)0.5 , (Real)0.5 , (Real)0.5 ); + Real myWidth = Real( 1. ); + + // Get the finest node with depth less than or equal to the splat depth that contains the point + temp = _spaceRoot; + while( _localDepth( temp )children ) ) break;// fprintf( stderr , "[ERROR] Octree::GetSampleDepthAndWeight\n" ) , exit( 0 ); + int cIndex = TreeOctNode::CornerIndex( myCenter , position ); + temp = temp->children + cIndex; + myWidth /= 2; + if( cIndex&1 ) myCenter[0] += myWidth/2; + else myCenter[0] -= myWidth/2; + if( cIndex&2 ) myCenter[1] += myWidth/2; + else myCenter[1] -= myWidth/2; + if( cIndex&4 ) myCenter[2] += myWidth/2; + else myCenter[2] -= myWidth/2; + } + return _getSampleDepthAndWeight( densityWeights , temp , position , weightKey , depth , weight ); +} + +template< class Real > +template< bool CreateNodes , int DataDegree , class V > +void Octree< Real >::_splatPointData( TreeOctNode* node , Point3D< Real > position , V v , SparseNodeData< V , DataDegree >& dataInfo , PointSupportKey< DataDegree >& dataKey ) +{ + double dx[ DIMENSION ][ PointSupportKey< DataDegree >::Size ]; + typename TreeOctNode::Neighbors< PointSupportKey< DataDegree >::Size >& neighbors = dataKey.template getNeighbors< CreateNodes >( node , _NodeInitializer ); + Point3D< Real > start; + Real w; + _startAndWidth( node , start , w ); + + for( int dd=0 ; dd::BSplineComponentValues( ( position[dd]-start[dd] ) / w , dx[dd] ); + + for( int i=0 ; i::Size ; i++ ) for( int j=0 ; j::Size ; j++ ) + { + double dxdy = dx[0][i] * dx[1][j]; + for( int k=0 ; k::Size ; k++ ) + if( IsActiveNode( neighbors.neighbors[i][j][k] ) ) + { + TreeOctNode* _node = neighbors.neighbors[i][j][k]; + + double dxdydz = dxdy * dx[2][k]; + dataInfo[ _node ] += v * (Real)dxdydz; + } + } +} +template< class Real > +template< bool CreateNodes , int WeightDegree , int DataDegree , class V > +Real Octree< Real >::_splatPointData( const DensityEstimator< WeightDegree >& densityWeights , Point3D< Real > position , V v , SparseNodeData< V , DataDegree >& dataInfo , PointSupportKey< WeightDegree >& weightKey , PointSupportKey< DataDegree >& dataKey , LocalDepth minDepth , LocalDepth maxDepth , int dim ) +{ + double dx; + V _v; + TreeOctNode* temp; + int cnt=0; + double width; + Point3D< Real > myCenter( (Real)0.5 , (Real)0.5 , (Real)0.5 ); + Real myWidth = (Real)1.; + + temp = _spaceRoot; + while( _localDepth( temp )children ) ) break; + int cIndex = TreeOctNode::CornerIndex( myCenter , position ); + temp = temp->children + cIndex; + myWidth /= 2; + if( cIndex&1 ) myCenter[0] += myWidth/2; + else myCenter[0] -= myWidth/2; + if( cIndex&2 ) myCenter[1] += myWidth/2; + else myCenter[1] -= myWidth/2; + if( cIndex&4 ) myCenter[2] += myWidth/2; + else myCenter[2] -= myWidth/2; + } + Real weight , depth; + _getSampleDepthAndWeight( densityWeights , temp , position , weightKey , depth , weight ); + + if( depthmaxDepth ) depth = Real(maxDepth); + int topDepth = int(ceil(depth)); + + dx = 1.0-(topDepth-depth); + if ( topDepth<=minDepth ) topDepth = minDepth , dx = 1; + else if( topDepth> maxDepth ) topDepth = maxDepth , dx = 1; + + while( _localDepth( temp )>topDepth ) temp=temp->parent; + while( _localDepth( temp )children ) temp->initChildren( _NodeInitializer ); + int cIndex = TreeOctNode::CornerIndex( myCenter , position ); + temp = &temp->children[cIndex]; + myWidth/=2; + if( cIndex&1 ) myCenter[0] += myWidth/2; + else myCenter[0] -= myWidth/2; + if( cIndex&2 ) myCenter[1] += myWidth/2; + else myCenter[1] -= myWidth/2; + if( cIndex&4 ) myCenter[2] += myWidth/2; + else myCenter[2] -= myWidth/2; + } + width = 1.0 / ( 1<<_localDepth( temp ) ); + _v = v * weight / Real( pow( width , dim ) ) * Real( dx ); + _splatPointData< CreateNodes >( temp , position , _v , dataInfo , dataKey ); + if( fabs(1.0-dx) > EPSILON ) + { + dx = Real(1.0-dx); + temp = temp->parent; + width = 1.0 / ( 1<<_localDepth( temp ) ); + + _v = v * weight / Real( pow( width , dim ) ) * Real( dx ); + _splatPointData< CreateNodes >( temp , position , _v , dataInfo , dataKey ); + } + return weight; +} +template< class Real > +template< bool CreateNodes , int WeightDegree , int DataDegree , class V > +Real Octree< Real >::_multiSplatPointData( const DensityEstimator< WeightDegree >* densityWeights , TreeOctNode* node , Point3D< Real > position , V v , SparseNodeData< V , DataDegree >& dataInfo , PointSupportKey< WeightDegree >& weightKey , PointSupportKey< DataDegree >& dataKey , int dim ) +{ + Real _depth , weight; + if( densityWeights ) _getSampleDepthAndWeight( *densityWeights , position , weightKey , _depth , weight ); + else weight = (Real)1.; + V _v = v * weight; + + double dx[ DIMENSION ][ PointSupportKey< DataDegree >::Size ]; + dataKey.template getNeighbors< CreateNodes >( node , _NodeInitializer ); + + for( TreeOctNode* _node=node ; _localDepth( _node )>=0 ; _node=_node->parent ) + { + V __v = _v * (Real)pow( 1<<_localDepth( _node ) , dim ); + Point3D< Real > start; + Real w; + _startAndWidth( _node , start , w ); + for( int dd=0 ; dd::BSplineComponentValues( ( position[dd]-start[dd] ) / w , dx[dd] ); + typename TreeOctNode::Neighbors< PointSupportKey< DataDegree >::Size >& neighbors = dataKey.neighbors[ _localToGlobal( _localDepth( _node ) ) ]; + for( int i=0 ; i::Size ; i++ ) for( int j=0 ; j::Size ; j++ ) + { + double dxdy = dx[0][i] * dx[1][j]; + for( int k=0 ; k::Size ; k++ ) + if( IsActiveNode( neighbors.neighbors[i][j][k] ) ) + { + TreeOctNode* _node = neighbors.neighbors[i][j][k]; + double dxdydz = dxdy * dx[2][k]; + dataInfo[ _node ] += __v * (Real)dxdydz; + } + } + } + return weight; +} + +template< class Real > +template< class V , int DataDegree , BoundaryType BType , class Coefficients > +V Octree< Real >::_evaluate( const Coefficients& coefficients , Point3D< Real > p , const BSplineData< DataDegree , BType >& bsData , const ConstPointSupportKey< DataDegree >& dataKey ) const +{ + V value = V(0); + + for( int d=_localToGlobal( 0 ) ; d<=dataKey.depth() ; d++ ) + { + double dx[ DIMENSION ][ PointSupportKey< DataDegree >::Size ]; + memset( dx , 0 , sizeof( double ) * DIMENSION * PointSupportKey< DataDegree >::Size ); + { + const TreeOctNode* n = dataKey.neighbors[d].neighbors[ PointSupportKey< DataDegree >::LeftRadius ][ PointSupportKey< DataDegree >::LeftRadius ][ PointSupportKey< DataDegree >::LeftRadius ]; + if( !n ) fprintf( stderr , "[ERROR] Point is not centered on a node\n" ) , exit( 0 ); + int fIdx[3]; + functionIndex< DataDegree , BType >( n , fIdx ); + int fStart , fEnd; + BSplineData< DataDegree , BType >::FunctionSpan( _localDepth( n ) , fStart , fEnd ); + for( int dd=0 ; dd::LeftRadius ; i<=PointSupportKey< DataDegree >::RightRadius ; i++ ) + if( fIdx[dd]+i>=fStart && fIdx[dd]+i::RightRadius ]( p[dd] ); + } + for( int i=0 ; i::Size ; i++ ) for( int j=0 ; j::Size ; j++ ) for( int k=0 ; k::Size ; k++ ) + { + const TreeOctNode* n = dataKey.neighbors[d].neighbors[i][j][k]; + if( isValidFEMNode< DataDegree , BType >( n ) ) + { + const V* v = coefficients( n ); + if( v ) value += (*v) * (Real) ( dx[0][i] * dx[1][j] * dx[2][k] ); + } + } + } + + return value; +} + +template< class Real > +template< class V , int DataDegree , BoundaryType BType > +Pointer( V ) Octree< Real >::voxelEvaluate( const DenseNodeData< V , DataDegree >& coefficients , int& res , Real isoValue , LocalDepth depth , bool primal ) +{ + int begin , end , dim; + if( depth<=0 || depth>_maxDepth ) depth = _maxDepth; + + // Initialize the coefficients at the coarsest level + Pointer( V ) _coefficients = NullPointer( V ); + { + LocalDepth d = 0; + begin = _BSplineBegin< DataDegree , BType >( d ) , end = _BSplineEnd< DataDegree , BType >( d ) , dim = end - begin; + _coefficients = NewPointer< V >( dim * dim * dim ); + memset( _coefficients , 0 , sizeof( V ) * dim * dim * dim ); +#pragma omp parallel for num_threads( threads ) + for( int i=_sNodesBegin(d) ; i<_sNodesEnd(d) ; i++ ) if( !_outOfBounds< DataDegree , BType >( _sNodes.treeNodes[i] ) ) + { + LocalDepth _d ; LocalOffset _off; + _localDepthAndOffset( _sNodes.treeNodes[i] , _d , _off ); + _off[0] -= begin , _off[1] -= begin , _off[2] -= begin; + _coefficients[ _off[0] + _off[1]*dim + _off[2]*dim*dim ] = coefficients[i]; + } + } + + // Up-sample and add in the existing coefficients + for( LocalDepth d=1 ; d<=depth ; d++ ) + { + begin = _BSplineBegin< DataDegree , BType >( d ) , end = _BSplineEnd< DataDegree , BType >( d ) , dim = end - begin; + Pointer( V ) __coefficients = NewPointer< V >( dim * dim *dim ); + memset( __coefficients , 0 , sizeof( V ) * dim * dim * dim ); +#pragma omp parallel for num_threads( threads ) + for( int i=_sNodesBegin(d) ; i<_sNodesEnd(d) ; i++ ) if( !_outOfBounds< DataDegree , BType >( _sNodes.treeNodes[i] ) ) + { + LocalDepth _d ; LocalOffset _off; + _localDepthAndOffset( _sNodes.treeNodes[i] , _d , _off ); + _off[0] -= begin , _off[1] -= begin , _off[2] -= begin; + __coefficients[ _off[0] + _off[1]*dim + _off[2]*dim*dim ] = coefficients[i]; + } + _UpSample< V , DataDegree , BType >( d , ( ConstPointer(V) )_coefficients , __coefficients , threads ); + DeletePointer( _coefficients ); + _coefficients = __coefficients; + } + + res = 1<( res*res*res ); + memset( values , 0 , sizeof(V)*res*res*res ); + + if( primal ) + { + // evaluate at the cell corners + typename BSplineEvaluationData< DataDegree , BType >::CornerEvaluator::Evaluator evaluator; + BSplineEvaluationData< DataDegree , BType >::SetCornerEvaluator( evaluator , depth ); +#pragma omp parallel for num_threads( threads ) + for( int k=0 ; k::CornerEnd ; kk<=-BSplineSupportSizes< DataDegree >::CornerStart ; kk++ ) if( k+kk>=begin && k+kk::CornerEnd ; jj<=-BSplineSupportSizes< DataDegree >::CornerStart ; jj++ ) if( j+jj>=begin && j+jj::CornerEnd ; ii<=-BSplineSupportSizes< DataDegree >::CornerStart ; ii++ ) if( i+ii>=begin && i+ii::CenterEvaluator::Evaluator evaluator; + BSplineEvaluationData< DataDegree , BType >::SetCenterEvaluator( evaluator , depth ); +#pragma omp parallel for num_threads( threads ) + for( int k=0 ; k::SupportEnd ; kk<=-BSplineSupportSizes< DataDegree >::SupportStart ; kk++ ) if( k+kk>=begin && k+kk::SupportEnd ; jj<=-BSplineSupportSizes< DataDegree >::SupportStart ; jj++ ) if( j+jj>=begin && j+jj::SupportEnd ; ii<=-BSplineSupportSizes< DataDegree >::SupportStart ; ii++ ) if( i+ii>=begin && i+ii +template< int FEMDegree , BoundaryType BType > +SparseNodeData< Real , 0 > Octree< Real >::leafValues( const DenseNodeData< Real , FEMDegree >& coefficients ) const +{ + SparseNodeData< Real , 0 > values; + DenseNodeData< Real , FEMDegree > _coefficients( _sNodesEnd(_maxDepth-1) ); + memset( &_coefficients[0] , 0 , sizeof(Real)*_sNodesEnd(_maxDepth-1) ); + for( int i=_sNodes.begin( _localToGlobal( 0 ) ) ; i<_sNodesEnd(_maxDepth-1) ; i++ ) _coefficients[i] = coefficients[i]; + for( LocalDepth d=1 ; d<_maxDepth ; d++ ) _upSample( d , _coefficients ); + for( LocalDepth d=_maxDepth ; d>=0 ; d-- ) + { + _Evaluator< FEMDegree , BType > evaluator; + evaluator.set( d ); + std::vector< ConstPointSupportKey< FEMDegree > > neighborKeys( std::max< int >( 1 , threads ) ); + for( size_t i=0 ; i& neighborKey = neighborKeys[ omp_get_thread_num() ]; + TreeOctNode* node = _sNodes.treeNodes[i]; + if( !IsActiveNode( node->children ) ) + { + neighborKey.getNeighbors( node ); + bool isInterior = _IsInteriorlySupported< FEMDegree >( node->parent ); + values[ node ] = _getCenterValue( neighborKey , node , coefficients , _coefficients , evaluator , isInterior ); + } + } + } + return values; +} +template< class Real > +template< int FEMDegree , BoundaryType BType > +SparseNodeData< Point3D< Real > , 0 > Octree< Real >::leafGradients( const DenseNodeData< Real , FEMDegree >& coefficients ) const +{ + SparseNodeData< Point3D< Real > , 0 > gradients; + DenseNodeData< Real , FEMDegree > _coefficients( _sNodesEnd(_maxDepth-1 ) ); + memset( &_coefficients[0] , 0 , sizeof(Real)*_sNodesEnd(_maxDepth-1) ); + for( int i=_sNodesBegin(0) ; i<_sNodesEnd(_maxDepth-1) ; i++ ) _coefficients[i] = coefficients[i]; + for( LocalDepth d=1 ; d<_maxDepth ; d++ ) _upSample( d , _coefficients ); + for( LocalDepth d=_maxDepth ; d>=0 ; d-- ) + { + _Evaluator< FEMDegree , BType > evaluator; + evaluator.set( d ); + std::vector< ConstPointSupportKey< FEMDegree > > neighborKeys( std::max< int >( 1 , threads ) ); + for( size_t i=0 ; i& neighborKey = neighborKeys[ omp_get_thread_num() ]; + TreeOctNode* node = _sNodes.treeNodes[i]; + if( !IsActiveNode( node->children ) ) + { + neighborKey.getNeighbors( node ); + bool isInterior = _IsInteriorlySupported< FEMDegree >( node->parent ); + gradients[ node ] = _getCenterValueAndGradient( neighborKey , node , coefficients , _coefficients , evaluator , isInterior ).second; + } + } + } + return gradients; +} diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.h b/src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.h new file mode 100644 index 000000000..b5aa80825 --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.h @@ -0,0 +1,990 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ +// [COMMENTS] +// -- Throughout the code, should make a distinction between indices and offsets +// -- Make an instance of _evaluate that samples the finite-elements correctly (specifically, to handle the boundaries) +// -- Make functions like depthAndOffset parity dependent (ideally all "depth"s should be relative to the B-Slpline resolution +// -- Make all points relative to the unit-cube, regardless of degree parity +// -- It's possible that for odd degrees, the iso-surfacing will fail because the leaves in the SortedTreeNodes do not form a partition of space +// -- [MAYBE] Treat normal field as a sum of delta functions, rather than a smoothed signal (again, so that high degrees aren't forced to generate smooth reconstructions) +// -- [MAYBE] Make the degree of the B-Spline with which the normals are splatted independent of the degree of the FEM system. (This way, higher degree systems aren't forced to generate smoother normal fields.) +// -- [MAYBE] Remove the isValidFEM/isValidSpace functions since the octree supports all degrees/boundary types (up to the max degree for which finalizedBrooded... was called) + +// [TODO] +// -- Currently, the implementation assumes that the boundary constraints are the same for vector fields and scalar fields +// -- Modify the setting of the flags so that only the subset of the broods that are needed + +#ifndef MULTI_GRID_OCTREE_DATA_INCLUDED +#define MULTI_GRID_OCTREE_DATA_INCLUDED + +#define NEW_CODE +#define FAST_SET_UP // If enabled, kernel density estimation is done aglomeratively + +#define POINT_DATA_RES 0 // Specifies the resolution of the subgrid storing points with each voxel (0==1 but is faster) + +#define DATA_DEGREE 1 // The order of the B-Spline used to splat in data for color interpolation +#define WEIGHT_DEGREE 2 // The order of the B-Spline used to splat in the weights for density estimation +#define NORMAL_DEGREE 2 // The order of the B-Spline used to splat int the normals for constructing the Laplacian constraints +//#define MAX_MEMORY_GB 15 // The maximum memory the application is allowed to use +#define MAX_MEMORY_GB 0 + +#include +#ifdef _OPENMP +#include +#endif // _OPENMP +#include "BSplineData.h" +#include "PointStream.h" +#include "Geometry.h" +#include "Octree.h" +#include "SparseMatrix.h" + +#ifndef _OPENMP +int omp_get_num_procs( void ){ return 1; } +int omp_get_thread_num( void ){ return 0; } +#endif // _OPENMP + +#define DERIVATIVES( Degree ) ( ( Degree>1 ) ? 2 : ( Degree==1 ? 1 : 0 ) ) + +class TreeNodeData +{ +public: + enum + { + SPACE_FLAG = 1 , + FEM_FLAG = 2 , + GHOST_FLAG = 1<<7 + }; + int nodeIndex; + char flags; + + void setGhostFlag( bool f ){ if( f ) flags |= GHOST_FLAG ; else flags &= ~GHOST_FLAG; } + bool getGhostFlag( void ) const { return ( flags & GHOST_FLAG )!=0; } + TreeNodeData( void ); + ~TreeNodeData( void ); +}; + +class VertexData +{ + typedef OctNode< TreeNodeData > TreeOctNode; +public: + static const int VERTEX_COORDINATE_SHIFT = ( sizeof( long long ) * 8 ) / 3; + static long long EdgeIndex( const TreeOctNode* node , int eIndex , int maxDepth , int index[DIMENSION] ); + static long long EdgeIndex( const TreeOctNode* node , int eIndex , int maxDepth ); + static long long FaceIndex( const TreeOctNode* node , int fIndex , int maxDepth,int index[DIMENSION] ); + static long long FaceIndex( const TreeOctNode* node , int fIndex , int maxDepth ); + static long long CornerIndex( const TreeOctNode* node , int cIndex , int maxDepth , int index[DIMENSION] ); + static long long CornerIndex( const TreeOctNode* node , int cIndex , int maxDepth ); + static long long CenterIndex( const TreeOctNode* node , int maxDepth , int index[DIMENSION] ); + static long long CenterIndex( const TreeOctNode* node , int maxDepth ); + static long long CornerIndex( int depth , const int offSet[DIMENSION] , int cIndex , int maxDepth , int index[DIMENSION] ); + static long long CenterIndex( int depth , const int offSet[DIMENSION] , int maxDepth , int index[DIMENSION] ); + static long long CornerIndexKey( const int index[DIMENSION] ); +}; + +// This class stores the octree nodes, sorted by depth and then by z-slice. +// To support primal representations, the initializer takes a function that +// determines if a node should be included/indexed in the sorted list. +// [NOTE] Indexing of nodes is _GLOBAL_ +class SortedTreeNodes +{ + typedef OctNode< TreeNodeData > TreeOctNode; +protected: + Pointer( Pointer( int ) ) _sliceStart; + int _levels; +public: + Pointer( TreeOctNode* ) treeNodes; + int begin( int depth ) const{ return _sliceStart[depth][0]; } + int end( int depth ) const{ return _sliceStart[depth][(size_t)1<=_levels||slice<0||slice>=(1<=_levels) printf( "uhoh\n" ); return _sliceStart[depth][(size_t)1<* map ); + void set( TreeOctNode& root ); + + template< int Indices > + struct _Indices + { + int idx[Indices]; + _Indices( void ){ memset( idx , -1 , sizeof( int ) * Indices ); } + int& operator[] ( int i ) { return idx[i]; } + const int& operator[] ( int i ) const { return idx[i]; } + }; + typedef _Indices< Square::CORNERS > SquareCornerIndices; + typedef _Indices< Square::EDGES > SquareEdgeIndices; + typedef _Indices< Square::FACES > SquareFaceIndices; + + struct SliceTableData + { + Pointer( SquareCornerIndices ) cTable; + Pointer( SquareEdgeIndices ) eTable; + Pointer( SquareFaceIndices ) fTable; + int cCount , eCount , fCount , nodeOffset , nodeCount; + SliceTableData( void ){ fCount = eCount = cCount = 0 , cTable = NullPointer( SquareCornerIndices ) , eTable = NullPointer( SquareEdgeIndices ) , fTable = NullPointer( SquareFaceIndices ) , _cMap = _eMap = _fMap = NullPointer( int ); } + ~SliceTableData( void ){ clear(); } +#ifdef BRUNO_LEVY_FIX + void clear( void ){ DeletePointer( cTable ) ; DeletePointer( eTable ) ; DeletePointer( fTable ) ; DeletePointer( _cMap ) ; DeletePointer( _eMap ) ; DeletePointer( _fMap ) ; fCount = eCount = cCount = 0; } +#else // !BRUNO_LEVY_FIX + void clear( void ){ DeletePointer( cTable ) ; DeletePointer( eTable ) ; DeletePointer( fTable ) ; fCount = eCount = cCount = 0; } +#endif // BRUNO_LEVY_FIX + SquareCornerIndices& cornerIndices( const TreeOctNode* node ); + SquareCornerIndices& cornerIndices( int idx ); + const SquareCornerIndices& cornerIndices( const TreeOctNode* node ) const; + const SquareCornerIndices& cornerIndices( int idx ) const; + SquareEdgeIndices& edgeIndices( const TreeOctNode* node ); + SquareEdgeIndices& edgeIndices( int idx ); + const SquareEdgeIndices& edgeIndices( const TreeOctNode* node ) const; + const SquareEdgeIndices& edgeIndices( int idx ) const; + SquareFaceIndices& faceIndices( const TreeOctNode* node ); + SquareFaceIndices& faceIndices( int idx ); + const SquareFaceIndices& faceIndices( const TreeOctNode* node ) const; + const SquareFaceIndices& faceIndices( int idx ) const; + protected: + Pointer( int ) _cMap; + Pointer( int ) _eMap; + Pointer( int ) _fMap; + friend class SortedTreeNodes; + }; + struct XSliceTableData + { + Pointer( SquareCornerIndices ) eTable; + Pointer( SquareEdgeIndices ) fTable; + int fCount , eCount , nodeOffset , nodeCount; + XSliceTableData( void ){ fCount = eCount = 0 , eTable = NullPointer( SquareCornerIndices ) , fTable = NullPointer( SquareEdgeIndices ) , _eMap = _fMap = NullPointer( int ); } + ~XSliceTableData( void ){ clear(); } +#ifdef BRUNO_LEVY_FIX + void clear( void ) { DeletePointer( fTable ) ; DeletePointer( eTable ) ; DeletePointer( _eMap ) ; DeletePointer( _fMap ) ; fCount = eCount = 0; } +#else // !BRUNO_LEVY_FIX + void clear( void ) { DeletePointer( fTable ) ; DeletePointer( eTable ) ; fCount = eCount = 0; } +#endif // BRUNO_LEVY_FIX + SquareCornerIndices& edgeIndices( const TreeOctNode* node ); + SquareCornerIndices& edgeIndices( int idx ); + const SquareCornerIndices& edgeIndices( const TreeOctNode* node ) const; + const SquareCornerIndices& edgeIndices( int idx ) const; + SquareEdgeIndices& faceIndices( const TreeOctNode* node ); + SquareEdgeIndices& faceIndices( int idx ); + const SquareEdgeIndices& faceIndices( const TreeOctNode* node ) const; + const SquareEdgeIndices& faceIndices( int idx ) const; + protected: + Pointer( int ) _eMap; + Pointer( int ) _fMap; + friend class SortedTreeNodes; + }; + void setSliceTableData ( SliceTableData& sData , int depth , int offset , int threads ) const; + void setXSliceTableData( XSliceTableData& sData , int depth , int offset , int threads ) const; +}; + +template< int Degree > +struct PointSupportKey : public OctNode< TreeNodeData >::NeighborKey< BSplineSupportSizes< Degree >::SupportEnd , -BSplineSupportSizes< Degree >::SupportStart > +{ + static const int LeftRadius = BSplineSupportSizes< Degree >::SupportEnd; + static const int RightRadius = -BSplineSupportSizes< Degree >::SupportStart; + static const int Size = LeftRadius + RightRadius + 1; +}; +template< int Degree > +struct ConstPointSupportKey : public OctNode< TreeNodeData >::ConstNeighborKey< BSplineSupportSizes< Degree >::SupportEnd , -BSplineSupportSizes< Degree >::SupportStart > +{ + static const int LeftRadius = BSplineSupportSizes< Degree >::SupportEnd; + static const int RightRadius = -BSplineSupportSizes< Degree >::SupportStart; + static const int Size = LeftRadius + RightRadius + 1; +}; + +template< class Real , bool HasGradients > +struct SinglePointData +{ + Point3D< Real > position; + Real weight; + Real value , _value; + SinglePointData operator + ( const SinglePointData& p ) const { return SinglePointData( position + p.position , value + p.value , weight + p.weight ); } + SinglePointData& operator += ( const SinglePointData& p ){ position += p.position ; weight += p.weight , value += p.value ; return *this; } + SinglePointData operator * ( Real s ) const { return SinglePointData( position*s , weight*s , value*s ); } + SinglePointData& operator *= ( Real s ){ position *= s , weight *= s , value *= s ; return *this; } + SinglePointData operator / ( Real s ) const { return SinglePointData( position/s , weight/s , value/s ); } + SinglePointData& operator /= ( Real s ){ position /= s , weight /= s , value /= s ; return *this; } + SinglePointData( void ) : position( Point3D< Real >() ) , weight(0) , value(0) , _value(0) { ; } + SinglePointData( Point3D< Real > p , Real v , Real w ) { position = p , value = v , weight = w , _value = (Real)0; } +}; +template< class Real > +struct SinglePointData< Real , true > : public SinglePointData< Real , false > +{ + using SinglePointData< Real , false >::position; + using SinglePointData< Real , false >::weight; + using SinglePointData< Real , false >::value; + using SinglePointData< Real , false >::_value; + Point3D< Real > gradient , _gradient; + SinglePointData operator + ( const SinglePointData& p ) const { return SinglePointData( position + p.position , weight + p.weight , value + p.value , gradient + p.gradient ); } + SinglePointData& operator += ( const SinglePointData& p ){ position += p.position , weight += p.weight , value += p.value , gradient += p.gradient ; return *this; } + SinglePointData operator * ( Real s ) const { return SinglePointData( position*s , weight*s , value*s , gradient*s ); } + SinglePointData& operator *= ( Real s ){ position *= s , weight *= s , value *= s , gradient *= s ; return *this; } + SinglePointData operator / ( Real s ) const { return SinglePointData( position/s , weight/s , value/s , gradient/s ); } + SinglePointData& operator /= ( Real s ){ position /= s , weight /= s , value /= s , gradient /= s ; return *this; } + SinglePointData( void ) : SinglePointData< Real , false >() , gradient( Point3D< Real >() ) , _gradient( Point3D< Real >() ) { ; } + SinglePointData( Point3D< Real > p , Real v , Point3D< Real > g , Real w ) : SinglePointData< Real , false >( p , v , w ) { gradient = g , _gradient = Point3D< Real >(); } +}; + +#if POINT_DATA_RES +template< class Real , bool HasGradients > +struct PointData +{ + static const int RES = POINT_DATA_RES; + static const int SAMPLES = RES * RES * RES; + + SinglePointData< Real , HasGradients > points[SAMPLES]; + SinglePointData< Real , HasGradients >& operator[] ( int idx ) { return points[idx]; } + const SinglePointData< Real , HasGradients >& operator[] ( int idx ) const { return points[idx]; } + + static void SetIndices( Point3D< Real > p , Point3D< Real > c , Real w , int x[3] ) + { + for( int d=0 ; d<3 ; d++ ) x[d] = std::max< int >( 0 , std::min< int >( RES-1 , int( floor( ( p[d]-( c[d]-w/2 ) ) / w * RES ) ) ) ); + } + + void addPoint( SinglePointData< Real , HasGradients > p , Point3D< Real > center , Real width ) + { + int x[3]; + SetIndices( p.position , center , width , x ); + points[ x[0]+x[1]*RES+x[2]*RES*RES ] += p; + } + + PointData operator + ( const PointData& p ) const { PointData _p ; for( int c=0 ; c using PointData = SinglePointData< Real , HasGradients >; +#endif // POINT_DATA_RES + +template< class Data , int Degree > +struct SparseNodeData +{ + size_t size( void ) const { return _data.size(); } + const Data& operator[] ( int idx ) const { return _data[idx]; } + Data& operator[] ( int idx ) { return _data[idx]; } + void reserve( size_t sz ){ if( sz>_indices.size() ) _indices.resize( sz , -1 ); } + Data* operator()( const OctNode< TreeNodeData >* node ){ return ( node->nodeData.nodeIndex<0 || node->nodeData.nodeIndex>=(int)_indices.size() || _indices[ node->nodeData.nodeIndex ]<0 ) ? NULL : &_data[ _indices[ node->nodeData.nodeIndex ] ]; } + const Data* operator()( const OctNode< TreeNodeData >* node ) const { return ( node->nodeData.nodeIndex<0 || node->nodeData.nodeIndex>=(int)_indices.size() || _indices[ node->nodeData.nodeIndex ]<0 ) ? NULL : &_data[ _indices[ node->nodeData.nodeIndex ] ]; } + Data& operator[]( const OctNode< TreeNodeData >* node ) + { + if( node->nodeData.nodeIndex>=(int)_indices.size() ) _indices.resize( node->nodeData.nodeIndex+1 , -1 ); + if( _indices[ node->nodeData.nodeIndex ]==-1 ) + { + _indices[ node->nodeData.nodeIndex ] = (int)_data.size(); + _data.push_back( Data() ); + } + return _data[ _indices[ node->nodeData.nodeIndex ] ]; + } + void remapIndices( const std::vector< int >& map ) + { + std::vector< int > temp = _indices; + _indices.resize( map.size() ); + for( size_t i=0 ; i friend struct SparseNodeData; + template< class _Data , int _Degree > + void init( const SparseNodeData< _Data , _Degree >& snd ){ _indices = snd._indices , _data.resize( snd._data.size() ); } + void remove( const OctNode< TreeNodeData >* node ){ if( node->nodeData.nodeIndex<(int)_indices.size() && node->nodeData.nodeIndex>=0 ) _indices[ node->nodeData.nodeIndex ] = -1; } +protected: + std::vector< int > _indices; + std::vector< Data > _data; +}; +template< class Data , int Degree > +struct DenseNodeData +{ + DenseNodeData( void ){ _data = NullPointer( Data ) ; _sz = 0; } + DenseNodeData( size_t sz ){ _sz = sz ; if( sz ) _data = NewPointer< Data >( sz ) ; else _data = NullPointer( Data ); } + DenseNodeData( const DenseNodeData& d ) : DenseNodeData() { _resize( d._sz ) ; if( _sz ) memcpy( _data , d._data , sizeof(Data) * _sz ); } + DenseNodeData( DenseNodeData&& d ){ _data = d._data , _sz = d._sz ; d._data = NullPointer( Data ) , d._sz = 0; } + DenseNodeData& operator = ( const DenseNodeData& d ){ _resize( d._sz ) ; if( _sz ) memcpy( _data , d._data , sizeof(Data) * _sz ) ; return *this; } + DenseNodeData& operator = ( DenseNodeData&& d ){ size_t __sz = _sz ; Pointer( Data ) __data = _data ; _data = d._data , _sz = d._sz ; d._data = __data , d._sz = __sz ; return *this; } + ~DenseNodeData( void ){ DeletePointer( _data ) ; _sz = 0; } + + Data& operator[] ( int idx ) { return _data[idx]; } + const Data& operator[] ( int idx ) const { return _data[idx]; } + size_t size( void ) const { return _sz; } + Data& operator[]( const OctNode< TreeNodeData >* node ) { return _data[ node->nodeData.nodeIndex ]; } + Data* operator()( const OctNode< TreeNodeData >* node ) { return ( node==NULL || node->nodeData.nodeIndex>=(int)_sz ) ? NULL : &_data[ node->nodeData.nodeIndex ]; } + const Data* operator()( const OctNode< TreeNodeData >* node ) const { return ( node==NULL || node->nodeData.nodeIndex>=(int)_sz ) ? NULL : &_data[ node->nodeData.nodeIndex ]; } + int index( const OctNode< TreeNodeData >* node ) const { return ( !node || node->nodeData.nodeIndex<0 || node->nodeData.nodeIndex>=(int)this->_data.size() ) ? -1 : node->nodeData.nodeIndex; } +protected: + size_t _sz; + void _resize( size_t sz ){ DeletePointer( _data ) ; if( sz ) _data = NewPointer< Data >( sz ) ; else _data = NullPointer( Data ) ; _sz = sz; } + Pointer( Data ) _data; +}; + +// This is may be necessary in case the memory usage is larger than what fits on the stack +template< class C , int N > struct Stencil +{ + Stencil( void ){ _values = NewPointer< C >( N * N * N ); } + ~Stencil( void ){ DeletePointer( _values ); } + C& operator()( int i , int j , int k ){ return _values[ i*N*N + j*N + k ]; } + const C& operator()( int i , int j , int k ) const { return _values[ i*N*N + j*N + k ]; } +protected: + Pointer( C ) _values; +}; + +template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +class SystemCoefficients +{ + typedef typename BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::FunctionIntegrator FunctionIntegrator; + static const int OverlapSize = BSplineOverlapSizes< Degree1 , Degree2 >::OverlapSize; + static const int OverlapStart = BSplineOverlapSizes< Degree1 , Degree2 >::OverlapStart; + static const int OverlapEnd = BSplineOverlapSizes< Degree1 , Degree2 >::OverlapEnd; +public: + typedef typename BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::FunctionIntegrator::template Integrator< DERIVATIVES( Degree1 ) , DERIVATIVES( Degree2 ) > Integrator; + typedef typename BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::FunctionIntegrator::template ChildIntegrator< DERIVATIVES( Degree1 ) , DERIVATIVES( Degree2 ) > ChildIntegrator; + + // The FEMSystemFunctor is a class that takes an object of type Integrator/ChildIntegrator, as well as a pair of indices of octree nodes + // and returns the corresponding system coefficient. + template< class _FEMSystemFunctor > static void SetCentralSystemStencil ( const _FEMSystemFunctor& F , const Integrator& integrator , Stencil< double , OverlapSize >& stencil ); + template< class _FEMSystemFunctor > static void SetCentralSystemStencils( const _FEMSystemFunctor& F , const ChildIntegrator& integrator , Stencil< double , OverlapSize > stencils[2][2][2] ); + template< bool Reverse , class _FEMSystemFunctor > static void SetCentralConstraintStencil ( const _FEMSystemFunctor& F , const Integrator& integrator , Stencil< double , OverlapSize >& stencil ); + template< bool Reverse , class _FEMSystemFunctor > static void SetCentralConstraintStencils( const _FEMSystemFunctor& F , const ChildIntegrator& integrator , Stencil< double , OverlapSize > stencils[2][2][2] ); + template< bool Reverse , class _FEMSystemFunctor > static void SetCentralConstraintStencil ( const _FEMSystemFunctor& F , const Integrator& integrator , Stencil< Point3D< double > , OverlapSize >& stencil ); + template< bool Reverse , class _FEMSystemFunctor > static void SetCentralConstraintStencils( const _FEMSystemFunctor& F , const ChildIntegrator& integrator , Stencil< Point3D< double > , OverlapSize > stencils[2][2][2] ); +}; + +template< int FEMDegree , BoundaryType BType > +struct FEMSystemFunctor +{ + double massWeight , lapWeight , biLapWeight; + FEMSystemFunctor( double mWeight=0 , double lWeight=0 , double bWeight=0 ) : massWeight( mWeight ) , lapWeight( lWeight ) , biLapWeight( bWeight ) { ; } + double integrate( const typename SystemCoefficients< FEMDegree , BType , FEMDegree , BType >:: Integrator& integrator , const int off1[] , const int off2[] ) const { return _integrate( integrator , off1 , off2 ); } + double integrate( const typename SystemCoefficients< FEMDegree , BType , FEMDegree , BType >::ChildIntegrator& integrator , const int off1[] , const int off2[] ) const { return _integrate( integrator , off1 , off2 ); } + bool vanishesOnConstants( void ) const { return massWeight==0; } +protected: + template< class I > double _integrate( const I& integrator , const int off1[] , const int off2[] ) const; +}; +template< int SFDegree , BoundaryType SFBType , int FEMDegree , BoundaryType FEMBType > +struct FEMSFConstraintFunctor +{ + double massWeight , lapWeight , biLapWeight; + FEMSFConstraintFunctor( double mWeight=0 , double lWeight=0 , double bWeight=0 ) : massWeight( mWeight ) , lapWeight( lWeight ) , biLapWeight( bWeight ) { ; } + template< bool Reverse > + double integrate( const typename SystemCoefficients< Reverse ? FEMDegree : SFDegree , Reverse ? FEMBType : SFBType , Reverse ? SFDegree : FEMDegree , Reverse ? SFBType : FEMBType >:: Integrator& integrator , const int off1[] , const int off2[] ) const { return _integrate< Reverse >( integrator , off1 , off2 ); } + template< bool Reverse > + double integrate( const typename SystemCoefficients< Reverse ? FEMDegree : SFDegree , Reverse ? FEMBType : SFBType , Reverse ? SFDegree : FEMDegree , Reverse ? SFBType : FEMBType >::ChildIntegrator& integrator , const int off1[] , const int off2[] ) const { return _integrate< Reverse >( integrator , off1 , off2 ); } +protected: + template< bool Reverse , class I > double _integrate( const I& integrator , const int off1[] , const int off[2] ) const; +}; +template< int VFDegree , BoundaryType VFBType , int FEMDegree , BoundaryType FEMBType > +struct FEMVFConstraintFunctor +{ + double lapWeight , biLapWeight; + FEMVFConstraintFunctor( double lWeight=0 , double bWeight=0 ) : lapWeight( lWeight ) , biLapWeight( bWeight ) { ; } + template< bool Reverse > + Point3D< double > integrate( const typename SystemCoefficients< Reverse ? FEMDegree : VFDegree , Reverse ? FEMBType : VFBType , Reverse ? VFDegree : FEMDegree , Reverse ? VFBType : FEMBType >:: Integrator& integrator , const int off1[] , const int off2[] ) const { return _integrate< Reverse >( integrator , off1 , off2 ); } + template< bool Reverse > + Point3D< double > integrate( const typename SystemCoefficients< Reverse ? FEMDegree : VFDegree , Reverse ? FEMBType : VFBType , Reverse ? VFDegree : FEMDegree , Reverse ? VFBType : FEMBType >::ChildIntegrator& integrator , const int off1[] , const int off2[] ) const { return _integrate< Reverse >( integrator , off1 , off2 ); } +protected: + template< bool Reverse , class I > Point3D< double > _integrate( const I& integrator , const int off1[] , const int off[2] ) const; +}; + +inline void SetGhostFlag( OctNode< TreeNodeData >* node , bool flag ){ if( node && node->parent ) node->parent->nodeData.setGhostFlag( flag ); } +inline bool GetGhostFlag( const OctNode< TreeNodeData >* node ){ return node==NULL || node->parent==NULL || node->parent->nodeData.getGhostFlag( ); } +inline bool IsActiveNode( const OctNode< TreeNodeData >* node ){ return !GetGhostFlag( node ); } + +template< class Real > +class Octree +{ + typedef OctNode< TreeNodeData > TreeOctNode; + static int _NodeCount; + static void _NodeInitializer( TreeOctNode& node ){ node.nodeData.nodeIndex = _NodeCount++; } +public: +#if 0 + struct LocalDepth + { + LocalDepth( int d=0 ) : _d(d) { ; } + operator int&() { return _d; } + operator int () const { return _d; } + protected: + int _d; + }; + struct LocalOffset + { + LocalOffset( const int* off=NULL ){ if( off ) memcpy( _off , off , sizeof(_off) ) ; else memset( _off , 0 , sizeof( _off ) ); } + operator int*() { return _off; } + operator const int*() const { return _off; } + protected: + int _off[3]; + }; +#else + typedef int LocalDepth; + typedef int LocalOffset[3]; +#endif + + static void ResetNodeCount( void ){ _NodeCount = 0 ; } + static int NodeCount( void ){ return _NodeCount; } + template< int FEMDegree , BoundaryType BType > void functionIndex( const TreeOctNode* node , int idx[3] ) const; + + struct PointSample{ const TreeOctNode* node ; ProjectiveData< OrientedPoint3D< Real > , Real > sample; }; + + typedef typename TreeOctNode:: NeighborKey< 1 , 1 > AdjacenctNodeKey; + typedef typename TreeOctNode::ConstNeighborKey< 1 , 1 > ConstAdjacenctNodeKey; + + template< int FEMDegree , BoundaryType BType > bool isValidFEMNode( const TreeOctNode* node ) const; + bool isValidSpaceNode( const TreeOctNode* node ) const; + TreeOctNode* leaf( Point3D< Real > p ); + const TreeOctNode* leaf( Point3D< Real > p ) const; + + template< bool HasGradients > + struct InterpolationInfo + { + SparseNodeData< PointData< Real , HasGradients > , 0 > iData; + Real valueWeight , gradientWeight; + InterpolationInfo( const class Octree< Real >& tree , const std::vector< PointSample >& samples , Real pointValue , int adaptiveExponent , Real v , Real g ) : valueWeight(v) , gradientWeight(g) + { iData = tree._densifyInterpolationInfo< HasGradients >( samples , pointValue , adaptiveExponent ); } + PointData< Real , HasGradients >* operator()( const OctNode< TreeNodeData >* node ){ return iData(node); } + const PointData< Real , HasGradients >* operator()( const OctNode< TreeNodeData >* node ) const { return iData(node); } + }; + + template< int DensityDegree > struct DensityEstimator : public SparseNodeData< Real , DensityDegree > + { + DensityEstimator( int kernelDepth ) : _kernelDepth( kernelDepth ){ ; } + int kernelDepth( void ) const { return _kernelDepth; } + protected: + int _kernelDepth; + }; +protected: + bool _isValidSpaceNode( const TreeOctNode* node ) const { return !GetGhostFlag( node ) && ( node->nodeData.flags & TreeNodeData::SPACE_FLAG ); } + bool _isValidFEMNode( const TreeOctNode* node ) const { return !GetGhostFlag( node ) && ( node->nodeData.flags & TreeNodeData::FEM_FLAG ); } + + TreeOctNode* _tree; + TreeOctNode* _spaceRoot; + SortedTreeNodes _sNodes; + LocalDepth _fullDepth , _maxDepth; + + static bool _InBounds( Point3D< Real > p ); + + int _depthOffset; + int _localToGlobal( LocalDepth d ) const { return d + _depthOffset; } + LocalDepth _localDepth( const TreeOctNode* node ) const { return node->depth() - _depthOffset; } + LocalDepth _localMaxDepth( const TreeOctNode* tree ) const { return tree->maxDepth() - _depthOffset; } + int _localInset( LocalDepth d ) const { return _depthOffset<=1 ? 0 : 1<<( d + _depthOffset - 1 ); } + void _localDepthAndOffset( const TreeOctNode* node , LocalDepth& d , LocalOffset& off ) const + { + node->depthAndOffset( d , off ) ; d -= _depthOffset; + int inset = _localInset( d ); + off[0] -= inset , off[1] -= inset , off[2] -= inset; + } + template< int FEMDegree , BoundaryType BType > static int _BSplineBegin( LocalDepth depth ){ return BSplineEvaluationData< FEMDegree , BType >::Begin( depth ); } + template< int FEMDegree , BoundaryType BType > static int _BSplineEnd ( LocalDepth depth ){ return BSplineEvaluationData< FEMDegree , BType >::End ( depth ); } + template< int FEMDegree , BoundaryType BType > + bool _outOfBounds( const TreeOctNode* node ) const + { + if( !node ) return true; + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + return d<0 || BSplineEvaluationData< FEMDegree , BType >::OutOfBounds( d , off[0] ) || BSplineEvaluationData< FEMDegree , BType >::OutOfBounds( d , off[1] ) || BSplineEvaluationData< FEMDegree , BType >::OutOfBounds( d , off[2] ); + } + int _sNodesBegin( LocalDepth d ) const { return _sNodes.begin( _localToGlobal( d ) ); } + int _sNodesEnd ( LocalDepth d ) const { return _sNodes.end ( _localToGlobal( d ) ); } + int _sNodesSize ( LocalDepth d ) const { return _sNodes.size ( _localToGlobal( d ) ); } + int _sNodesBegin( LocalDepth d , int slice ) const { return _sNodes.begin( _localToGlobal( d ) , slice + _localInset( d ) ); } + int _sNodesEnd ( LocalDepth d , int slice ) const { return _sNodes.end ( _localToGlobal( d ) , slice + _localInset( d ) ); } + int _sNodesSize ( LocalDepth d , int slice ) const { return _sNodes.size ( _localToGlobal( d ) , slice + _localInset( d ) ); } + + template< int FEMDegree > static bool _IsInteriorlySupported( LocalDepth depth , const LocalOffset off ) + { + if( depth>=0 ) + { + int begin , end; + BSplineSupportSizes< FEMDegree >::InteriorSupportedSpan( depth , begin , end ); + return ( off[0]>=begin && off[0]=begin && off[1]=begin && off[2] bool _isInteriorlySupported( const TreeOctNode* node ) const + { + if( !node ) return false; + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + return _IsInteriorlySupported< FEMDegree >( d , off ); + } + template< int FEMDegree1 , int FEMDegree2 > static bool _IsInteriorlyOverlapped( LocalDepth depth , const LocalOffset off ) + { + if( depth>=0 ) + { + int begin , end; + BSplineIntegrationData< FEMDegree1 , BOUNDARY_NEUMANN , FEMDegree2 , BOUNDARY_NEUMANN >::InteriorOverlappedSpan( depth , begin , end ); + return ( off[0]>=begin && off[0]=begin && off[1]=begin && off[2] bool _isInteriorlyOverlapped( const TreeOctNode* node ) const + { + if( !node ) return false; + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + return _IsInteriorlyOverlapped< FEMDegree1 , FEMDegree2 >( d , off ); + } + void _startAndWidth( const TreeOctNode* node , Point3D< Real >& start , Real& width ) const + { + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + if( d>=0 ) width = Real( 1.0 / (1<< d ) ); + else width = Real( 1.0 * (1<<(-d)) ); + for( int dd=0 ; dd& center , Real& width ) const + { + int d , off[3]; + _localDepthAndOffset( node , d , off ); + width = Real( 1.0 / (1< p ) const + { + Point3D< Real > c ; Real w; + _centerAndWidth( node , c , w ); + return ( p[0] void _setFullDepth( TreeOctNode* node , LocalDepth depth ) const; + template< int Degree , BoundaryType BType > void _setFullDepth( LocalDepth depth ); + + template< int LeftRadius , int RightRadius > + static typename TreeOctNode::ConstNeighbors< LeftRadius + RightRadius + 1 >& _neighbors( TreeOctNode::ConstNeighborKey< LeftRadius , RightRadius >& key , const TreeOctNode* node ){ return key.neighbors[ node->depth() ]; } + template< int LeftRadius , int RightRadius > + static typename TreeOctNode::Neighbors< LeftRadius + RightRadius + 1 >& _neighbors( TreeOctNode::NeighborKey< LeftRadius , RightRadius >& key , const TreeOctNode* node ){ return key.neighbors[ node->depth() ]; } + template< int LeftRadius , int RightRadius > + static const typename TreeOctNode::template Neighbors< LeftRadius + RightRadius + 1 >& _neighbors( const typename TreeOctNode::template NeighborKey< LeftRadius , RightRadius >& key , const TreeOctNode* node ){ return key.neighbors[ node->depth() ]; } + template< int LeftRadius , int RightRadius > + static const typename TreeOctNode::template ConstNeighbors< LeftRadius + RightRadius + 1 >& _neighbors( const typename TreeOctNode::template ConstNeighborKey< LeftRadius , RightRadius >& key , const TreeOctNode* node ){ return key.neighbors[ node->depth() ]; } + +public: + LocalDepth depth( const TreeOctNode* node ) const { return _localDepth( node ); } + void depthAndOffset( const TreeOctNode* node , LocalDepth& depth , LocalOffset& offset ) const { _localDepthAndOffset( node , depth , offset ); } + + int nodesBegin( LocalDepth d ) const { return _sNodes.begin( _localToGlobal( d ) ); } + int nodesEnd ( LocalDepth d ) const { return _sNodes.end ( _localToGlobal( d ) ); } + int nodesSize ( LocalDepth d ) const { return _sNodes.size ( _localToGlobal( d ) ); } + int nodesBegin( LocalDepth d , int slice ) const { return _sNodes.begin( _localToGlobal( d ) , slice + _localInset( d ) ); } + int nodesEnd ( LocalDepth d , int slice ) const { return _sNodes.end ( _localToGlobal( d ) , slice + _localInset( d ) ); } + int nodesSize ( LocalDepth d , int slice ) const { return _sNodes.size ( _localToGlobal( d ) , slice + _localInset( d ) ); } + const TreeOctNode* node( int idx ) const { return _sNodes.treeNodes[idx]; } +protected: + + //////////////////////////////////// + // System construction code // + // MultiGridOctreeData.System.inl // + //////////////////////////////////// + template< int FEMDegree > + void _setMultiColorIndices( int start , int end , std::vector< std::vector< int > >& indices ) const; + struct _SolverStats + { + double evaluateTime , systemTime , solveTime; + double bNorm2 , inRNorm2 , outRNorm2; + }; + template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > + int _solveSystemGS( const FEMSystemFunctor& F , const BSplineData< FEMDegree , BType >& bsData , InterpolationInfo< HasGradients >* interpolationInfo , LocalDepth depth , DenseNodeData< Real , FEMDegree >& solution , DenseNodeData< Real , FEMDegree >& constraints , DenseNodeData< Real , FEMDegree >& metSolutionConstraints , int iters , bool coarseToFine , _SolverStats& stats , bool computeNorms ); + template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > + int _solveSystemCG( const FEMSystemFunctor& F , const BSplineData< FEMDegree , BType >& bsData , InterpolationInfo< HasGradients >* interpolationInfo , LocalDepth depth , DenseNodeData< Real , FEMDegree >& solution , DenseNodeData< Real , FEMDegree >& constraints , DenseNodeData< Real , FEMDegree >& metSolutionConstraints , int iters , bool coarseToFine , _SolverStats& stats , bool computeNorms , double accuracy ); + template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > + int _setMatrixRow( const FEMSystemFunctor& F , const InterpolationInfo< HasGradients >* interpolationInfo , const typename TreeOctNode::Neighbors< BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& neighbors , Pointer( MatrixEntry< Real > ) row , int offset , const typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template Integrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) >& integrator , const Stencil< double , BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& stencil , const BSplineData< FEMDegree , BType >& bsData ) const; + template< int FEMDegree , BoundaryType BType > + int _getMatrixRowSize( const typename TreeOctNode::Neighbors< BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& neighbors ) const; + + template< int FEMDegree1 , int FEMDegree2 > static void _SetParentOverlapBounds( const TreeOctNode* node , int& startX , int& endX , int& startY , int& endY , int& startZ , int& endZ ); + // Updates the constraints @(depth) based on the solution coefficients @(depth-1) + + template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > + void _updateConstraintsFromCoarser( const FEMSystemFunctor& F , const InterpolationInfo< HasGradients >* interpolationInfo , const typename TreeOctNode::Neighbors< BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& neighbors , const typename TreeOctNode::Neighbors< BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& pNeighbors , TreeOctNode* node , DenseNodeData< Real , FEMDegree >& constraints , const DenseNodeData< Real , FEMDegree >& metSolution , const typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template ChildIntegrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) >& childIntegrator , const Stencil< double , BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& stencil , const BSplineData< FEMDegree , BType >& bsData ) const; + + // evaluate the points @(depth) using coefficients @(depth-1) + template< int FEMDegree , BoundaryType BType , bool HasGradients > + void _setPointValuesFromCoarser( InterpolationInfo< HasGradients >& interpolationInfo , LocalDepth highDepth , const BSplineData< FEMDegree , BType >& bsData , const DenseNodeData< Real , FEMDegree >& upSampledCoefficients ); + + // Updates the cumulative integral constraints @(depth-1) based on the change in solution coefficients @(depth) + template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor > + void _updateCumulativeIntegralConstraintsFromFiner( const FEMSystemFunctor& F , + const BSplineData< FEMDegree , BType >& bsData , LocalDepth highDepth , const DenseNodeData< Real , FEMDegree >& fineSolution , DenseNodeData< Real , FEMDegree >& cumulativeConstraints ) const; + // Updates the cumulative interpolation constraints @(depth-1) based on the change in solution coefficient @(depth) + template< int FEMDegree , BoundaryType BType , bool HasGradients > + void _updateCumulativeInterpolationConstraintsFromFiner( const InterpolationInfo< HasGradients >& interpolationInfo , + const BSplineData< FEMDegree , BType >& bsData , LocalDepth highDepth , const DenseNodeData< Real , FEMDegree >& fineSolution , DenseNodeData< Real , FEMDegree >& cumulativeConstraints ) const; + + template< int FEMDegree , BoundaryType BType > + Real _coarserFunctionValue( Point3D< Real > p , const PointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , const BSplineData< FEMDegree , BType >& bsData , const DenseNodeData< Real , FEMDegree >& upSampledCoefficients ) const; + template< int FEMDegree , BoundaryType BType > + Point3D< Real > _coarserFunctionGradient( Point3D< Real > p , const PointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , const BSplineData< FEMDegree , BType >& bsData , const DenseNodeData< Real , FEMDegree >& upSampledCoefficients ) const; + template< int FEMDegree , BoundaryType BType > + Real _finerFunctionValue( Point3D< Real > p , const PointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , const BSplineData< FEMDegree , BType >& bsData , const DenseNodeData< Real , FEMDegree >& coefficients ) const; + template< int FEMDegree , BoundaryType BType > + Point3D< Real > _finerFunctionGradient( Point3D< Real > p , const PointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , const BSplineData< FEMDegree , BType >& bsData , const DenseNodeData< Real , FEMDegree >& coefficients ) const; + template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > + int _getSliceMatrixAndUpdateConstraints( const FEMSystemFunctor& F , const InterpolationInfo< HasGradients >* interpolationInfo , SparseMatrix< Real >& matrix , DenseNodeData< Real , FEMDegree >& constraints , typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template Integrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) >& integrator , typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template ChildIntegrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) >& childIntegrator , const BSplineData< FEMDegree , BType >& bsData , LocalDepth depth , int slice , const DenseNodeData< Real , FEMDegree >& metSolution , bool coarseToFine ); + template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > + int _getMatrixAndUpdateConstraints( const FEMSystemFunctor& F , const InterpolationInfo< HasGradients >* interpolationInfo , SparseMatrix< Real >& matrix , DenseNodeData< Real , FEMDegree >& constraints , typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template Integrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) >& integrator , typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template ChildIntegrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) >& childIntegrator , const BSplineData< FEMDegree , BType >& bsData , LocalDepth depth , const DenseNodeData< Real , FEMDegree >& metSolution , bool coarseToFine ); + + // Down samples constraints @(depth) to constraints @(depth-1) + template< class C , int FEMDegree , BoundaryType BType > void _downSample( LocalDepth highDepth , DenseNodeData< C , FEMDegree >& constraints ) const; + // Up samples coefficients @(depth-1) to coefficients @(depth) + template< class C , int FEMDegree , BoundaryType BType > void _upSample( LocalDepth highDepth , DenseNodeData< C , FEMDegree >& coefficients ) const; + template< class C , int FEMDegree , BoundaryType BType > static void _UpSample( LocalDepth highDepth , ConstPointer( C ) lowCoefficients , Pointer( C ) highCoefficients , int threads ); +public: + template< class C , int FEMDegree , BoundaryType BType > DenseNodeData< C , FEMDegree > coarseCoefficients( const DenseNodeData< C , FEMDegree >& coefficients ) const; + template< class C , int FEMDegree , BoundaryType BType > DenseNodeData< C , FEMDegree > coarseCoefficients( const SparseNodeData< C , FEMDegree >& coefficients ) const; +protected: + + ///////////////////////////////////////////// + // Code for splatting point-sample data // + // MultiGridOctreeData.WeightedSamples.inl // + ///////////////////////////////////////////// + template< int WeightDegree > + void _addWeightContribution( DensityEstimator< WeightDegree >& densityWeights , TreeOctNode* node , Point3D< Real > position , PointSupportKey< WeightDegree >& weightKey , Real weight=Real(1.0) ); + template< int WeightDegree , class PointSupportKey > + Real _getSamplesPerNode( const DensityEstimator< WeightDegree >& densityWeights , const TreeOctNode* node , Point3D< Real > position , PointSupportKey& weightKey ) const; + template< int WeightDegree , class PointSupportKey > + void _getSampleDepthAndWeight( const DensityEstimator< WeightDegree >& densityWeights , const TreeOctNode* node , Point3D< Real > position , PointSupportKey& weightKey , Real& depth , Real& weight ) const; + template< int WeightDegree , class PointSupportKey > + void _getSampleDepthAndWeight( const DensityEstimator< WeightDegree >& densityWeights , Point3D< Real > position , PointSupportKey& weightKey , Real& depth , Real& weight ) const; + template< bool CreateNodes , int DataDegree , class V > void _splatPointData( TreeOctNode* node , Point3D< Real > point , V v , SparseNodeData< V , DataDegree >& data , PointSupportKey< DataDegree >& dataKey ); + template< bool CreateNodes , int WeightDegree , int DataDegree , class V > Real _splatPointData( const DensityEstimator< WeightDegree >& densityWeights , Point3D< Real > point , V v , SparseNodeData< V , DataDegree >& data , PointSupportKey< WeightDegree >& weightKey , PointSupportKey< DataDegree >& dataKey , LocalDepth minDepth , LocalDepth maxDepth , int dim=DIMENSION ); + template< bool CreateNodes , int WeightDegree , int DataDegree , class V > Real _multiSplatPointData( const DensityEstimator< WeightDegree >* densityWeights , TreeOctNode* node , Point3D< Real > point , V v , SparseNodeData< V , DataDegree >& data , PointSupportKey< WeightDegree >& weightKey , PointSupportKey< DataDegree >& dataKey , int dim=DIMENSION ); + template< class V , int DataDegree , BoundaryType BType , class Coefficients > V _evaluate( const Coefficients& coefficients , Point3D< Real > p , const BSplineData< DataDegree , BType >& bsData , const ConstPointSupportKey< DataDegree >& dataKey ) const; +public: + template< class V , int DataDegree , BoundaryType BType > Pointer( V ) voxelEvaluate( const DenseNodeData< V , DataDegree >& coefficients , int& res , Real isoValue=0.f , LocalDepth depth=-1 , bool primal=false ); + + template< int NormalDegree > + struct HasNormalDataFunctor + { + const SparseNodeData< Point3D< Real > , NormalDegree >& normalInfo; + HasNormalDataFunctor( const SparseNodeData< Point3D< Real > , NormalDegree >& ni ) : normalInfo( ni ){ ; } + bool operator() ( const TreeOctNode* node ) const + { + const Point3D< Real >* n = normalInfo( node ); + if( n ) + { + const Point3D< Real >& normal = *n; + if( normal[0]!=0 || normal[1]!=0 || normal[2]!=0 ) return true; + } + if( node->children ) for( int c=0 ; cchildren + c ) ) return true; + return false; + } + }; + struct TrivialHasDataFunctor{ bool operator() ( const TreeOctNode* node ) const{ return true; } }; + + // [NOTE] The input/output for this method is pre-scaled by weight + template< bool HasGradients > bool _setInterpolationInfoFromChildren( TreeOctNode* node , SparseNodeData< PointData< Real , HasGradients > , 0 >& iInfo ) const; + template< bool HasGradients > SparseNodeData< PointData< Real , HasGradients > , 0 > _densifyInterpolationInfo( const std::vector< PointSample >& samples , Real pointValue , int adaptiveExponent ) const; + + template< int FEMDegree , BoundaryType BType > void _setValidityFlags( void ); + template< class HasDataFunctor > void _clipTree( const HasDataFunctor& f ); + + template< int FEMDegree , BoundaryType BType > SparseNodeData< Real , 0 > leafValues ( const DenseNodeData< Real , FEMDegree >& coefficients ) const; + template< int FEMDegree , BoundaryType BType > SparseNodeData< Point3D< Real > , 0 > leafGradients( const DenseNodeData< Real , FEMDegree >& coefficients ) const; + + //////////////////////////////////// + // Evaluation Methods // + // MultiGridOctreeData.Evaluation // + //////////////////////////////////// + static const int CHILDREN = Cube::CORNERS; + template< int FEMDegree , BoundaryType BType > + struct _Evaluator + { + typename BSplineEvaluationData< FEMDegree , BType >::Evaluator evaluator; + typename BSplineEvaluationData< FEMDegree , BType >::ChildEvaluator childEvaluator; + Stencil< double , BSplineSupportSizes< FEMDegree >::SupportSize > cellStencil; + Stencil< double , BSplineSupportSizes< FEMDegree >::SupportSize > cellStencils [CHILDREN]; + Stencil< double , BSplineSupportSizes< FEMDegree >::SupportSize > edgeStencil [Cube::EDGES ]; + Stencil< double , BSplineSupportSizes< FEMDegree >::SupportSize > edgeStencils [CHILDREN][Cube::EDGES ]; + Stencil< double , BSplineSupportSizes< FEMDegree >::SupportSize > faceStencil [Cube::FACES ]; + Stencil< double , BSplineSupportSizes< FEMDegree >::SupportSize > faceStencils [CHILDREN][Cube::FACES ]; + Stencil< double , BSplineSupportSizes< FEMDegree >::SupportSize > cornerStencil [Cube::CORNERS]; + Stencil< double , BSplineSupportSizes< FEMDegree >::SupportSize > cornerStencils[CHILDREN][Cube::CORNERS]; + + Stencil< Point3D< double > , BSplineSupportSizes< FEMDegree >::SupportSize > dCellStencil; + Stencil< Point3D< double > , BSplineSupportSizes< FEMDegree >::SupportSize > dCellStencils [CHILDREN]; + Stencil< Point3D< double > , BSplineSupportSizes< FEMDegree >::SupportSize > dEdgeStencil [Cube::EDGES ]; + Stencil< Point3D< double > , BSplineSupportSizes< FEMDegree >::SupportSize > dEdgeStencils [CHILDREN][Cube::EDGES ]; + Stencil< Point3D< double > , BSplineSupportSizes< FEMDegree >::SupportSize > dFaceStencil [Cube::FACES ]; + Stencil< Point3D< double > , BSplineSupportSizes< FEMDegree >::SupportSize > dFaceStencils [CHILDREN][Cube::FACES ]; + Stencil< Point3D< double > , BSplineSupportSizes< FEMDegree >::SupportSize > dCornerStencil [Cube::CORNERS]; + Stencil< Point3D< double > , BSplineSupportSizes< FEMDegree >::SupportSize > dCornerStencils[CHILDREN][Cube::CORNERS]; + + void set( LocalDepth depth ); + _Evaluator( void ){ _bsData = NULL; } + ~_Evaluator( void ){ if( _bsData ) delete _bsData , _bsData = NULL; } + protected: + BSplineData< FEMDegree , BType >* _bsData; + friend Octree; + }; + template< class V , int FEMDegree , BoundaryType BType > + V _getCenterValue( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , const DenseNodeData< V , FEMDegree >& solution , const DenseNodeData< V , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator , bool isInterior ) const; + template< class V , int FEMDegree , BoundaryType BType > + V _getCornerValue( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , int corner , const DenseNodeData< V , FEMDegree >& solution , const DenseNodeData< V , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator , bool isInterior ) const; + template< class V , int FEMDegree , BoundaryType BType > + V _getEdgeValue ( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , int edge , const DenseNodeData< V , FEMDegree >& solution , const DenseNodeData< V , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator , bool isInterior ) const; + template< class V , int FEMDegree , BoundaryType BType > + V _getValue ( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , Point3D< Real > p , const DenseNodeData< V , FEMDegree >& solution , const DenseNodeData< V , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator ) const; + + template< int FEMDegree , BoundaryType BType > + std::pair< Real , Point3D< Real > > _getCenterValueAndGradient( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , const DenseNodeData< Real , FEMDegree >& solution , const DenseNodeData< Real , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator , bool isInterior ) const; + template< int FEMDegree , BoundaryType BType > + std::pair< Real , Point3D< Real > > _getCornerValueAndGradient( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , int corner , const DenseNodeData< Real , FEMDegree >& solution , const DenseNodeData< Real , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator , bool isInterior ) const; + template< int FEMDegree , BoundaryType BType > + std::pair< Real , Point3D< Real > > _getEdgeValueAndGradient ( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , int edge , const DenseNodeData< Real , FEMDegree >& solution , const DenseNodeData< Real , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator , bool isInterior ) const; + template< int FEMDegree , BoundaryType BType > + std::pair< Real , Point3D< Real > > _getValueAndGradient ( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , Point3D< Real > p , const DenseNodeData< Real , FEMDegree >& solution , const DenseNodeData< Real , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator ) const; + +public: + template< int Degree , BoundaryType BType > + class MultiThreadedEvaluator + { + const Octree* _tree; + int _threads; + std::vector< ConstPointSupportKey< Degree > > _neighborKeys; + _Evaluator< Degree , BType > _evaluator; + const DenseNodeData< Real , Degree >& _coefficients; + DenseNodeData< Real , Degree > _coarseCoefficients; + public: + MultiThreadedEvaluator( const Octree* tree , const DenseNodeData< Real , Degree >& coefficients , int threads=1 ); + Real value( Point3D< Real > p , int thread=0 , const TreeOctNode* node=NULL ); + std::pair< Real , Point3D< Real > > valueAndGradient( Point3D< Real > , int thread=0 , const TreeOctNode* node=NULL ); + }; + + //////////////////////////////////////// + // Iso-Surfacing Methods // + // MultiGridOctreeData.IsoSurface.inl // + //////////////////////////////////////// +protected: + struct _IsoEdge + { + long long edges[2]; + _IsoEdge( void ){ edges[0] = edges[1] = 0; } + _IsoEdge( long long v1 , long long v2 ){ edges[0] = v1 , edges[1] = v2; } + long long& operator[]( int idx ){ return edges[idx]; } + const long long& operator[]( int idx ) const { return edges[idx]; } + }; + struct _FaceEdges + { + _IsoEdge edges[2]; + int count; + }; + template< class Vertex > + struct _SliceValues + { + typename SortedTreeNodes::SliceTableData sliceData; + Pointer( Real ) cornerValues ; Pointer( Point3D< Real > ) cornerGradients ; Pointer( char ) cornerSet; + Pointer( long long ) edgeKeys ; Pointer( char ) edgeSet; + Pointer( _FaceEdges ) faceEdges ; Pointer( char ) faceSet; + Pointer( char ) mcIndices; + std::unordered_map< long long, std::vector< _IsoEdge > > faceEdgeMap; + std::unordered_map< long long, std::pair< int, Vertex > > edgeVertexMap; + std::unordered_map< long long, long long > vertexPairMap; + + _SliceValues( void ); + ~_SliceValues( void ); + void reset( bool nonLinearFit ); + protected: + int _oldCCount , _oldECount , _oldFCount , _oldNCount; + }; + template< class Vertex > + struct _XSliceValues + { + typename SortedTreeNodes::XSliceTableData xSliceData; + Pointer( long long ) edgeKeys ; Pointer( char ) edgeSet; + Pointer( _FaceEdges ) faceEdges ; Pointer( char ) faceSet; + std::unordered_map< long long, std::vector< _IsoEdge > > faceEdgeMap; + std::unordered_map< long long, std::pair< int, Vertex > > edgeVertexMap; + std::unordered_map< long long, long long > vertexPairMap; + + _XSliceValues( void ); + ~_XSliceValues( void ); + void reset( void ); + protected: + int _oldECount , _oldFCount; + }; + template< class Vertex > + struct _SlabValues + { + protected: + _XSliceValues< Vertex > _xSliceValues[2]; + _SliceValues< Vertex > _sliceValues[2]; + public: + _SliceValues< Vertex >& sliceValues( int idx ){ return _sliceValues[idx&1]; } + const _SliceValues< Vertex >& sliceValues( int idx ) const { return _sliceValues[idx&1]; } + _XSliceValues< Vertex >& xSliceValues( int idx ){ return _xSliceValues[idx&1]; } + const _XSliceValues< Vertex >& xSliceValues( int idx ) const { return _xSliceValues[idx&1]; } + }; + template< class Vertex , int FEMDegree , BoundaryType BType > + void _setSliceIsoCorners( const DenseNodeData< Real , FEMDegree >& solution , const DenseNodeData< Real , FEMDegree >& coarseSolution , Real isoValue , LocalDepth depth , int slice , std::vector< _SlabValues< Vertex > >& sValues , const _Evaluator< FEMDegree , BType >& evaluator , int threads ); + template< class Vertex , int FEMDegree , BoundaryType BType > + void _setSliceIsoCorners( const DenseNodeData< Real , FEMDegree >& solution , const DenseNodeData< Real , FEMDegree >& coarseSolution , Real isoValue , LocalDepth depth , int slice , int z , std::vector< _SlabValues< Vertex > >& sValues , const _Evaluator< FEMDegree , BType >& evaluator , int threads ); + template< int WeightDegree , int ColorDegree , BoundaryType BType , class Vertex > + void _setSliceIsoVertices( const BSplineData< ColorDegree , BType >* colorBSData , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Point3D< Real > , Real > , ColorDegree >* colorData , Real isoValue , LocalDepth depth , int slice , int& vOffset , CoredMeshData< Vertex >& mesh , std::vector< _SlabValues< Vertex > >& sValues , int threads ); + template< int WeightDegree , int ColorDegree , BoundaryType BType , class Vertex > + void _setSliceIsoVertices( const BSplineData< ColorDegree , BType >* colorBSData , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Point3D< Real > , Real > , ColorDegree >* colorData , Real isoValue , LocalDepth depth , int slice , int z , int& vOffset , CoredMeshData< Vertex >& mesh , std::vector< _SlabValues< Vertex > >& sValues , int threads ); + template< int WeightDegree , int ColorDegree , BoundaryType BType , class Vertex > + void _setXSliceIsoVertices( const BSplineData< ColorDegree , BType >* colorBSData , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Point3D< Real > , Real > , ColorDegree >* colorData , Real isoValue , LocalDepth depth , int slab , int& vOffset , CoredMeshData< Vertex >& mesh , std::vector< _SlabValues< Vertex > >& sValues , int threads ); + template< class Vertex > + void _setSliceIsoEdges( LocalDepth depth , int slice , std::vector< _SlabValues< Vertex > >& slabValues , int threads ); + template< class Vertex > + void _setSliceIsoEdges( LocalDepth depth , int slice , int z , std::vector< _SlabValues< Vertex > >& slabValues , int threads ); + template< class Vertex > + void _setXSliceIsoEdges( LocalDepth depth , int slice , std::vector< _SlabValues< Vertex > >& slabValues , int threads ); + template< class Vertex > + void _copyFinerSliceIsoEdgeKeys( LocalDepth depth , int slice , std::vector< _SlabValues< Vertex > >& sValues , int threads ); + template< class Vertex > + void _copyFinerSliceIsoEdgeKeys( LocalDepth depth , int slice , int z , std::vector< _SlabValues< Vertex > >& sValues , int threads ); + template< class Vertex > + void _copyFinerXSliceIsoEdgeKeys( LocalDepth depth , int slab , std::vector< _SlabValues< Vertex > >& sValues , int threads ); + + template< class Vertex > + void _setIsoSurface( LocalDepth depth , int offset , const _SliceValues< Vertex >& bValues , const _SliceValues< Vertex >& fValues , const _XSliceValues< Vertex >& xValues , CoredMeshData< Vertex >& mesh , bool polygonMesh , bool addBarycenter , int& vOffset , int threads ); + + template< class Vertex > + static int _addIsoPolygons( CoredMeshData< Vertex >& mesh , std::vector< std::pair< int , Vertex > >& polygon , bool polygonMesh , bool addBarycenter , int& vOffset ); + + template< int WeightDegree , int ColorDegree , BoundaryType BType , class Vertex > + bool _getIsoVertex( const BSplineData< ColorDegree , BType >* colorBSData , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Point3D< Real > , Real > , ColorDegree >* colorData , Real isoValue , ConstPointSupportKey< WeightDegree >& weightKey , ConstPointSupportKey< ColorDegree >& colorKey , const TreeOctNode* node , int edgeIndex , int z , const _SliceValues< Vertex >& sValues , Vertex& vertex ); + template< int WeightDegree , int ColorDegree , BoundaryType BType , class Vertex > + bool _getIsoVertex( const BSplineData< ColorDegree , BType >* colorBSData , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Point3D< Real > , Real > , ColorDegree >* colorData , Real isoValue , ConstPointSupportKey< WeightDegree >& weightKey , ConstPointSupportKey< ColorDegree >& colorKey , const TreeOctNode* node , int cornerIndex , const _SliceValues< Vertex >& bValues , const _SliceValues< Vertex >& fValues , Vertex& vertex ); + + void _init( TreeOctNode* node , LocalDepth maxDepth , bool (*Refine)( LocalDepth d , LocalOffset off ) ); + + double _maxMemoryUsage , _localMemoryUsage; +public: + int threads; + double maxMemoryUsage( void ) const { return _maxMemoryUsage; } + double localMemoryUsage( void ) const { return _localMemoryUsage; } + void resetLocalMemoryUsage( void ){ _localMemoryUsage = 0; } + double memoryUsage( void ); + + Octree( void ); + + void init( LocalDepth maxDepth , bool (*Refine)( LocalDepth d , LocalOffset off ) ); + template< class Data > + int init( OrientedPointStream< Real >& pointStream , LocalDepth maxDepth , bool useConfidence , std::vector< PointSample >& samples , std::vector< ProjectiveData< Data , Real > >* sampleData ); + template< int DensityDegree > + typename Octree::template DensityEstimator< DensityDegree >* setDensityEstimator( const std::vector< PointSample >& samples , LocalDepth splatDepth , Real samplesPerNode ); + template< int NormalDegree , int DensityDegree > + SparseNodeData< Point3D< Real > , NormalDegree > setNormalField( const std::vector< PointSample >& samples , const DensityEstimator< DensityDegree >& density , Real& pointWeightSum , bool forceNeumann ); + template< int DataDegree , bool CreateNodes , int DensityDegree , class Data > + SparseNodeData< ProjectiveData< Data , Real > , DataDegree > setDataField( const std::vector< PointSample >& samples , std::vector< ProjectiveData< Data , Real > >& sampleData , const DensityEstimator< DensityDegree >* density ); + template< int MaxDegree , int FEMDegree , BoundaryType FEMBType , class HasDataFunctor > void inalizeForBroodedMultigrid( LocalDepth fullDepth , const HasDataFunctor& F , std::vector< int >* map=NULL ); + + // Generate an empty set of constraints + template< int FEMDegree > DenseNodeData< Real , FEMDegree > initDenseNodeData( void ); + + // Add finite-elements constraints (derived from a sparse scalar field) + template< int FEMDegree , BoundaryType FEMBType , int SFDegree , BoundaryType SFBType , class FEMSFConstraintFunctor > void addFEMConstraints( const FEMSFConstraintFunctor& F , const SparseNodeData< Real , SFDegree >& sfCoefficients , DenseNodeData< Real , FEMDegree >& constraints , LocalDepth maxDepth ) + { return _addFEMConstraints< FEMDegree , FEMBType , SFDegree , SFBType , FEMSFConstraintFunctor , const SparseNodeData< Real , SFDegree > , Real , double >( F , sfCoefficients , constraints , maxDepth ); } + // Add finite-elements constraints (derived from a dense scalar field) + template< int FEMDegree , BoundaryType FEMBType , int SFDegree , BoundaryType SFBType , class FEMSFConstraintFunctor > void addFEMConstraints( const FEMSFConstraintFunctor& F , const DenseNodeData< Real , SFDegree >& sfCoefficients , DenseNodeData< Real , FEMDegree >& constraints , LocalDepth maxDepth ) + { return _addFEMConstraints< FEMDegree , FEMBType , SFDegree , SFBType , FEMSFConstraintFunctor , const DenseNodeData< Real , SFDegree > , Real , double >( F , sfCoefficients , constraints , maxDepth ); } + // Add finite-elements constraints (derived from a sparse vector field) + template< int FEMDegree , BoundaryType FEMBType , int VFDegree , BoundaryType VFBType , class FEMVFConstraintFunctor > void addFEMConstraints( const FEMVFConstraintFunctor& F , const SparseNodeData< Point3D< Real > , VFDegree >& vfCoefficients , DenseNodeData< Real , FEMDegree >& constraints , LocalDepth maxDepth ) + { return _addFEMConstraints< FEMDegree , FEMBType , VFDegree , VFBType , FEMVFConstraintFunctor , const SparseNodeData< Point3D< Real > , VFDegree > , Point3D< Real > , Point3D< double > >( F , vfCoefficients , constraints , maxDepth ); } + // Add finite-elements constraints (derived from a dense vector field) + template< int FEMDegree , BoundaryType FEMBType , int VFDegree , BoundaryType VFBType , class FEMVFConstraintFunctor > void addFEMConstraints( const FEMVFConstraintFunctor& F , const DenseNodeData< Point3D< Real > , VFDegree >& vfCoefficients , DenseNodeData< Real , FEMDegree >& constraints , LocalDepth maxDepth ) + { return _addFEMConstraints< FEMDegree , FEMBType , VFDegree , VFBType , FEMVFConstraintFunctor , const DenseNodeData< Point3D< Real > , VFDegree > , Point3D< Real > , Point3D< double > >( F , vfCoefficients , constraints , maxDepth ); } + // Add interpolation constraints + template< int FEMDegree , BoundaryType FEMBType , bool HasGradients > void addInterpolationConstraints( const InterpolationInfo< HasGradients >& interpolationInfo , DenseNodeData< Real , FEMDegree >& constraints , LocalDepth maxDepth ); + + template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 , class DotFunctor > double dot( const DotFunctor& F , const SparseNodeData< Real , Degree1 >& coefficients1 , const SparseNodeData< Real , Degree2 >& coefficients2 ) const + { return _dot< Degree1 , BType1 , Degree2 , BType2 , DotFunctor , false >( F , (const InterpolationInfo< false >*)NULL , coefficients1 , coefficients2 ); } + template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 , class DotFunctor > double dot( const DotFunctor& F , const SparseNodeData< Real , Degree1 >& coefficients1 , const DenseNodeData< Real , Degree2 >& coefficients2 ) const + { return _dot< Degree1 , BType1 , Degree2 , BType2 , DotFunctor , false >( F , (const InterpolationInfo< false >*)NULL , coefficients1 , coefficients2 ); } + template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 , class DotFunctor > double dot( const DotFunctor& F , const DenseNodeData< Real , Degree1 >& coefficients1 , const SparseNodeData< Real , Degree2 >& coefficients2 ) const + { return _dot< Degree1 , BType1 , Degree2 , BType2 , DotFunctor , false >( F , (const InterpolationInfo< false >*)NULL , coefficients1 , coefficients2 ); } + template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 , class DotFunctor > double dot( const DotFunctor& F , const DenseNodeData< Real , Degree1 >& coefficients1 , const DenseNodeData< Real , Degree2 >& coefficients2 ) const + { return _dot< Degree1 , BType1 , Degree2 , BType2 , DotFunctor , false >( F , (const InterpolationInfo< false >*)NULL , coefficients1 , coefficients2 ); } + + template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 , class DotFunctor , bool HasGradients > double dot( const DotFunctor& F , const InterpolationInfo< HasGradients >* iInfo , const SparseNodeData< Real , Degree1 >& coefficients1 , const SparseNodeData< Real , Degree2 >& coefficients2 ) const + { return _dot< Degree1 , BType1 , Degree2 , BType2 , DotFunctor , HasGradients >( F , iInfo , coefficients1 , coefficients2 ); } + template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 , class DotFunctor , bool HasGradients > double dot( const DotFunctor& F , const InterpolationInfo< HasGradients >* iInfo , const SparseNodeData< Real , Degree1 >& coefficients1 , const DenseNodeData< Real , Degree2 >& coefficients2 ) const + { return _dot< Degree1 , BType1 , Degree2 , BType2 , DotFunctor , HasGradients >( F , iInfo , coefficients1 , coefficients2 ); } + template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 , class DotFunctor , bool HasGradients > double dot( const DotFunctor& F , const InterpolationInfo< HasGradients >* iInfo , const DenseNodeData< Real , Degree1 >& coefficients1 , const SparseNodeData< Real , Degree2 >& coefficients2 ) const + { return _dot< Degree1 , BType1 , Degree2 , BType2 , DotFunctor , HasGradients >( F , iInfo , coefficients1 , coefficients2 ); } + template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 , class DotFunctor , bool HasGradients > double dot( const DotFunctor& F , const InterpolationInfo< HasGradients >* iInfo , const DenseNodeData< Real , Degree1 >& coefficients1 , const DenseNodeData< Real , Degree2 >& coefficients2 ) const + { return _dot< Degree1 , BType1 , Degree2 , BType2 , DotFunctor , HasGradients >( F , iInfo , coefficients1 , coefficients2 ); } + + template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > + void setSystemMatrix( const FEMSystemFunctor& F , const InterpolationInfo< HasGradients >* interpolationInfo , LocalDepth depth , SparseMatrix< Real >& matrix ) const; + + // Solve the linear system + struct SolverInfo + { + // How to solve + LocalDepth cgDepth; + int iters; + double cgAccuracy , lowResIterMultiplier; + // What to output + bool verbose , showResidual; + + SolverInfo( void ) : cgDepth(0) , iters(1), cgAccuracy(0) , lowResIterMultiplier(0) , verbose(false) , showResidual(false) { ; } + }; + template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > + DenseNodeData< Real , FEMDegree > solveSystem( const FEMSystemFunctor& F , InterpolationInfo< HasGradients >* iData , DenseNodeData< Real , FEMDegree >& constraints , LocalDepth maxSolveDepth , const SolverInfo& solverInfo ); + + template< int FEMDegree , BoundaryType BType , int WeightDegree , int ColorDegree , class Vertex > + void getMCIsoSurface( const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Point3D< Real > , Real > , ColorDegree >* colorData , const DenseNodeData< Real , FEMDegree >& solution , Real isoValue , CoredMeshData< Vertex >& mesh , bool nonLinearFit=true , bool addBarycenter=false , bool polygonMesh=false ); + + + const TreeOctNode& tree( void ) const{ return *_tree; } + size_t leaves( void ) const { return _tree->leaves(); } + size_t nodes( void ) const { int count = 0 ; for( const TreeOctNode* n=_tree->nextNode() ; n ; n=_tree->nextNode( n ) ) if( IsActiveNode( n ) ) count++ ; return count; } + size_t ghostNodes( void ) const { int count = 0 ; for( const TreeOctNode* n=_tree->nextNode() ; n ; n=_tree->nextNode( n ) ) if( !IsActiveNode( n ) ) count++ ; return count; } + inline size_t validSpaceNodes( void ) const { int count = 0 ; for( const TreeOctNode* n=_tree->nextNode() ; n ; n=_tree->nextNode( n ) ) if( isValidSpaceNode( n ) ) count++ ; return count; } + inline size_t validSpaceNodes( LocalDepth d ) const { int count = 0 ; for( const TreeOctNode* n=_tree->nextNode() ; n ; n=_tree->nextNode( n ) ) if( _localDepth(n)==d && isValidSpaceNode( n ) ) count++ ; return count; } + template< int Degree , BoundaryType BType > size_t validFEMNodes( void ) const { int count = 0 ; for( const TreeOctNode* n=_tree->nextNode() ; n ; n=_tree->nextNode( n ) ) if( isValidFEMNode< Degree , BType >( n ) ) count++ ; return count; } + template< int Degree , BoundaryType BType > size_t validFEMNodes( LocalDepth d ) const { int count = 0 ; for( const TreeOctNode* n=_tree->nextNode() ; n ; n=_tree->nextNode( n ) ) if( _localDepth(n)==d && isValidFEMNode< Degree , BType >( n ) ) count++ ; return count; } + LocalDepth depth( void ) const { return _localMaxDepth( _tree ); } + void resetNodeIndices( void ){ _NodeCount = 0 ; for( TreeOctNode* node=_tree->nextNode() ; node ; node=_tree->nextNode( node ) ) _NodeInitializer( *node ) , node->nodeData.flags=0; } + +protected: + template< class D > static bool _IsZero( const D& d ); + template< class D > static Real _Dot( const D& d1 , const D& d2 ); + template< int FEMDegree , BoundaryType FEMBType , int CDegree , BoundaryType CBType , class FEMConstraintFunctor , class Coefficients , class D , class _D > + void _addFEMConstraints( const FEMConstraintFunctor& F , const Coefficients& coefficients , DenseNodeData< Real , FEMDegree >& constraints , LocalDepth maxDepth ); + template< int FEMDegree1 , BoundaryType FEMBType1 , int FEMDegree2 , BoundaryType FEMBType2 , class DotFunctor , bool HasGradients , class Coefficients1 , class Coefficients2 > + double _dot( const DotFunctor& F , const InterpolationInfo< HasGradients >* iInfo , const Coefficients1& coefficients1 , const Coefficients2& coefficients2 ) const; +}; +template< class Real > int Octree< Real >::_NodeCount = 0; + + +template< class Real > void Reset( void ){ Octree< Real >::ResetNodeCount(); } + + +#include "MultiGridOctreeData.inl" +#include "MultiGridOctreeData.SortedTreeNodes.inl" +#include "MultiGridOctreeData.WeightedSamples.inl" +#include "MultiGridOctreeData.System.inl" +#include "MultiGridOctreeData.IsoSurface.inl" +#include "MultiGridOctreeData.Evaluation.inl" +#endif // MULTI_GRID_OCTREE_DATA_INCLUDED diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.inl b/src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.inl new file mode 100644 index 000000000..0dee9319d --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/MultiGridOctreeData.inl @@ -0,0 +1,654 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ +#ifdef FAST_SET_UP +#include +#endif // FAST_SET_UP +#include +#include "PointStream.h" + +#define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 +//#define MEMORY_ALLOCATOR_BLOCK_SIZE 0 + +const double MATRIX_ENTRY_EPSILON = 0; +const double EPSILON = 1e-6; +const double ROUND_EPS = 1e-5; + +////////////////// +// TreeNodeData // +////////////////// +TreeNodeData::TreeNodeData( void ){ flags = 0; } +TreeNodeData::~TreeNodeData( void ) { } + + +//////////// +// Octree // +//////////// +template< class Real > +double Octree< Real >::memoryUsage( void ) +{ + double mem = double( MemoryInfo::Usage() ) / (1<<20); + _maxMemoryUsage = std::max< double >( mem , _maxMemoryUsage ); + _localMemoryUsage = std::max< double >( mem , _localMemoryUsage ); + return mem; +} + +template< class Real > Octree< Real >::Octree( void ) : threads(1) , _maxMemoryUsage(0) , _localMemoryUsage(0) +{ + _tree = TreeOctNode::NewBrood( _NodeInitializer ); + _tree->initChildren( _NodeInitializer ) , _spaceRoot = _tree->children; + _depthOffset = 1; +} + +template< class Real > +template< int FEMDegree , BoundaryType BType > +void Octree< Real >::functionIndex( const TreeOctNode* node , int idx[3] ) const +{ + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + for( int dd=0 ; dd::FunctionIndex( d , off[dd] ); +} + +template< class Real > +OctNode< TreeNodeData >* Octree< Real >::leaf( Point3D< Real > p ) +{ + if( !_InBounds( p ) ) return NULL; + Point3D< Real > center = Point3D< Real >( Real(0.5) , Real(0.5) , Real(0.5) ); + Real width = Real(1.0); + TreeOctNode* node = _spaceRoot; + while( node->children ) + { + int cIndex = TreeOctNode::CornerIndex( center , p ); + node = node->children + cIndex; + width /= 2; + if( cIndex&1 ) center[0] += width/2; + else center[0] -= width/2; + if( cIndex&2 ) center[1] += width/2; + else center[1] -= width/2; + if( cIndex&4 ) center[2] += width/2; + else center[2] -= width/2; + } + return node; +} +template< class Real > +const OctNode< TreeNodeData >* Octree< Real >::leaf( Point3D< Real > p ) const +{ + if( !_InBounds( p ) ) return NULL; + Point3D< Real > center = Point3D< Real >( Real(0.5) , Real(0.5) , Real(0.5) ); + Real width = Real(1.0); + TreeOctNode* node = _spaceRoot; + while( node->children ) + { + int cIndex = TreeOctNode::CornerIndex( center , p ); + node = node->children + cIndex; + width /= 2; + if( cIndex&1 ) center[0] += width/2; + else center[0] -= width/2; + if( cIndex&2 ) center[1] += width/2; + else center[1] -= width/2; + if( cIndex&4 ) center[2] += width/2; + else center[2] -= width/2; + } + return node; +} +template< class Real > bool Octree< Real >::_InBounds( Point3D< Real > p ){ return p[0]>=Real(0.) && p[0]<=Real(1.0) && p[1]>=Real(0.) && p[1]<=Real(1.0) && p[2]>=Real(0.) && p[2]<=Real(1.0); } +template< class Real > +template< int FEMDegree , BoundaryType BType > +bool Octree< Real >::isValidFEMNode( const TreeOctNode* node ) const +{ + if( GetGhostFlag( node ) ) return false; + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + if( d<0 ) return false; + return !BSplineEvaluationData< FEMDegree , BType >::OutOfBounds( d , off[0] ) && !BSplineEvaluationData< FEMDegree , BType >::OutOfBounds( d , off[1] ) && !BSplineEvaluationData< FEMDegree , BType >::OutOfBounds( d , off[2] ); +} +template< class Real > +bool Octree< Real >::isValidSpaceNode( const TreeOctNode* node ) const +{ + if( !node ) return false; + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + if( d<0 ) return false; + int res = 1<=0 && off[0]=0 && off[1]=0 && off[2] +template< int Degree , BoundaryType BType > +void Octree< Real >::_setFullDepth( TreeOctNode* node , LocalDepth depth ) const +{ + bool refine = false; + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + if( d( node ) ) { refine = true; } + else if( !BSplineSupportSizes< Degree >::OutOfBounds( d , off[0] ) && !BSplineSupportSizes< Degree >::OutOfBounds( d , off[1] ) && !BSplineSupportSizes< Degree >::OutOfBounds( d , off[2] ) ) { refine = true; } + if( refine ) + { + if( !node->children ) node->initChildren( _NodeInitializer ); + for( int c=0 ; c( node->children+c , depth ); + } +} +template< class Real > +template< int Degree , BoundaryType BType > +void Octree< Real >::_setFullDepth( LocalDepth depth ) +{ + if( !_tree->children ) _tree->initChildren( _NodeInitializer ); + for( int c=0 ; c( _tree->children+c , depth ); +} + +template< class Real , bool HasGradients > +struct _PointDataAccumulator_ +{ +#if POINT_DATA_RES + static inline void _AddToPointData_( PointData< Real , HasGradients >& pData , Point3D< Real > position , Real value , Point3D< Real > gradient , Point3D< Real > center , Real width , Real weight ); +#else // !POINT_DATA_RES + static inline void _AddToPointData_( PointData< Real , HasGradients >& pData , Point3D< Real > position , Real value , Point3D< Real > gradient , Real weight ); +#endif // POINT_DATA_RES +}; +template< class Real > +struct _PointDataAccumulator_< Real , false > +{ +#if POINT_DATA_RES + static inline void _AddToPointData_( PointData< Real , false >& pData , Point3D< Real > position , Real value , Point3D< Real > gradient , Point3D< Real > center , Real width , Real weight ){ pData.addPoint( SinglePointData< Real , false >( position , value , weight ) , center , width ); } +#else // !POINT_DATA_RES + static inline void _AddToPointData_( PointData< Real , false >& pData , Point3D< Real > position , Real value , Point3D< Real > gradient , Real weight ){ pData.position += position , pData.value += value , pData.weight += weight; } +#endif // POINT_DATA_RES +}; +template< class Real > +struct _PointDataAccumulator_< Real , true > +{ +#if POINT_DATA_RES + static inline void _AddToPointData_( PointData< Real , true >& pData , Point3D< Real > position , Real value , Point3D< Real > gradient , Point3D< Real > center , Real width , Real weight ){ pData.addPoint( SinglePointData< Real , true >( position , value , gradient , weight ) , center , width ); } +#else // !POINT_DATA_RES + static inline void _AddToPointData_( PointData< Real , true >& pData , Point3D< Real > position , Real value , Point3D< Real > gradient , Real weight ){ pData.position += position , pData.value += value , pData.gradient += gradient , pData.weight += weight; } +#endif // POINT_DATA_RES +}; + +template< class Real > +void Octree< Real >::_init( TreeOctNode* node , LocalDepth maxDepth , bool (*Refine)( LocalDepth , LocalOffset ) ) +{ + if( _localDepth( node )initChildren( _NodeInitializer ); + for( int c=0 ; cchildren + c , maxDepth , Refine ); + } + } +} +template< class Real > void Octree< Real >::init( LocalDepth maxDepth , bool (*Refine)( LocalDepth , LocalOffset ) ){ _init( _spaceRoot , maxDepth , Refine ); } +template< class Real > +template< class Data > +int Octree< Real >::init( OrientedPointStream< Real >& pointStream , LocalDepth maxDepth , bool useConfidence , std::vector< PointSample >& samples , std::vector< ProjectiveData< Data , Real > >* sampleData ) +{ + OrientedPointStreamWithData< Real , Data >& pointStreamWithData = ( OrientedPointStreamWithData< Real , Data >& )pointStream; + + // Add the point data + int outOfBoundPoints = 0 , zeroLengthNormals = 0 , undefinedNormals = 0 , pointCount = 0; + { + std::vector< int > nodeToIndexMap; + Point3D< Real > p , n; + OrientedPoint3D< Real > _p; + Data _d; + while( ( sampleData ? pointStreamWithData.nextPoint( _p , _d ) : pointStream.nextPoint( _p ) ) ) + { + p = Point3D< Real >(_p.p) , n = Point3D< Real >(_p.n); + Real len = (Real)Length( n ); + if( !_InBounds(p) ){ outOfBoundPoints++ ; continue; } + if( !len ){ zeroLengthNormals++ ; continue; } + if( len!=len ){ undefinedNormals++ ; continue; } + n /= len; + Point3D< Real > center = Point3D< Real >( Real(0.5) , Real(0.5) , Real(0.5) ); + Real width = Real(1.0); + TreeOctNode* temp = _spaceRoot; + LocalDepth depth = _localDepth( temp ); + while( depthchildren ) temp->initChildren( _NodeInitializer ); + int cIndex = TreeOctNode::CornerIndex( center , p ); + temp = temp->children + cIndex; + width /= 2; + if( cIndex&1 ) center[0] += width/2; + else center[0] -= width/2; + if( cIndex&2 ) center[1] += width/2; + else center[1] -= width/2; + if( cIndex&4 ) center[2] += width/2; + else center[2] -= width/2; + depth++; + } + Real weight = (Real)( useConfidence ? len : 1. ); + int nodeIndex = temp->nodeData.nodeIndex; + if( nodeIndex>=nodeToIndexMap.size() ) nodeToIndexMap.resize( nodeIndex+1 , -1 ); + int idx = nodeToIndexMap[ nodeIndex ]; + if( idx==-1 ) + { + idx = (int)samples.size(); + nodeToIndexMap[ nodeIndex ] = idx; + samples.resize( idx+1 ) , samples[idx].node = temp; + if( sampleData ) sampleData->resize( idx+1 ); + } + samples[idx].sample += ProjectiveData< OrientedPoint3D< Real > , Real >( OrientedPoint3D< Real >( p * weight , n * weight ) , weight ); + if( sampleData ) (*sampleData)[ idx ] += ProjectiveData< Data , Real >( _d * weight , weight ); + pointCount++; + } + pointStream.reset(); + } + if( outOfBoundPoints ) fprintf( stderr , "[WARNING] Found out-of-bound points: %d\n" , outOfBoundPoints ); + if( zeroLengthNormals ) fprintf( stderr , "[WARNING] Found zero-length normals: %d\n" , zeroLengthNormals ); + if( undefinedNormals ) fprintf( stderr , "[WARNING] Found undefined normals: %d\n" , undefinedNormals ); + + memoryUsage(); + return pointCount; +} +template< class Real > +template< int DensityDegree > +typename Octree< Real >::template DensityEstimator< DensityDegree >* Octree< Real >::setDensityEstimator( const std::vector< PointSample >& samples , LocalDepth splatDepth , Real samplesPerNode ) +{ + LocalDepth maxDepth = _localMaxDepth( _tree ); + splatDepth = std::max< LocalDepth >( 0 , std::min< LocalDepth >( splatDepth , maxDepth ) ); + DensityEstimator< DensityDegree >* _density = new DensityEstimator< DensityDegree >( splatDepth ); + DensityEstimator< DensityDegree >& density = *_density; + PointSupportKey< DensityDegree > densityKey; + densityKey.set( _localToGlobal( splatDepth ) ); + +#ifdef FAST_SET_UP + std::vector< int > sampleMap( NodeCount() , -1 ); +#pragma omp parallel for num_threads( threads ) + for( int i=0 ; i0 ) sampleMap[ samples[i].node->nodeData.nodeIndex ] = i; + std::function< ProjectiveData< OrientedPoint3D< Real > , Real > ( TreeOctNode* ) > SetDensity = [&] ( TreeOctNode* node ) + { + ProjectiveData< OrientedPoint3D< Real > , Real > sample; + LocalDepth d = _localDepth( node ); + int idx = node->nodeData.nodeIndex; + if( node->children ) + for( int c=0 ; c , Real > s = SetDensity( node->children + c ); + if( d<=splatDepth && s.weight>0 ) + { + Point3D< Real > p = s.data.p / s.weight; + Real w = s.weight / samplesPerNode; + _addWeightContribution( density , node , p , densityKey , w ); + } + sample += s; + } + else if( idx0 ) + { + Point3D< Real > p = sample.data.p / sample.weight; + Real w = sample.weight / samplesPerNode; + _addWeightContribution( density , node , p , densityKey , w ); + } + } + return sample; + }; + SetDensity( _spaceRoot ); +#else // !FAST_SET_UP + for( int i=0 ; i , Real >& sample = samples[i].sample; + if( sample.weight>0 ) + { + Point3D< Real > p = sample.data.p / sample.weight; + Real w = sample.weight / samplesPerNode; + for( TreeOctNode* _node=(TreeOctNode*)node ; _node ; _node=_node->parent ) if( _localDepth( _node )<=splatDepth ) _addWeightContribution( density , _node , p , densityKey , w ); + } + } +#endif // FAST_SET_UP + + memoryUsage(); + return _density; +} +template< class Real > +template< int NormalDegree , int DensityDegree > +SparseNodeData< Point3D< Real > , NormalDegree > Octree< Real >::setNormalField( const std::vector< PointSample >& samples , const DensityEstimator< DensityDegree >& density , Real& pointWeightSum , bool forceNeumann ) +{ + LocalDepth maxDepth = _localMaxDepth( _tree ); + PointSupportKey< DensityDegree > densityKey; + PointSupportKey< NormalDegree > normalKey; + densityKey.set( _localToGlobal( maxDepth ) ) , normalKey.set( _localToGlobal( maxDepth ) ); + + Real weightSum = 0; + pointWeightSum = 0; + SparseNodeData< Point3D< Real > , NormalDegree > normalField; + for( int i=0 ; i , Real >& sample = samples[i].sample; + if( sample.weight>0 ) + { + Point3D< Real > p = sample.data.p / sample.weight , n = sample.data.n; + weightSum += sample.weight; + if( !_InBounds(p) ){ fprintf( stderr , "[WARNING] Octree:setNormalField: Point sample is out of bounds\n" ) ; continue; } + pointWeightSum += _splatPointData< true >( density , p , n , normalField , densityKey , normalKey , 0 , maxDepth , 3 ); + } + } + pointWeightSum /= weightSum; + memoryUsage(); + + return normalField; +} +template< class Real > +template< int DataDegree , bool CreateNodes , int DensityDegree , class Data > +SparseNodeData< ProjectiveData< Data , Real > , DataDegree > Octree< Real >::setDataField( const std::vector< PointSample >& samples , std::vector< ProjectiveData< Data , Real > >& sampleData , const DensityEstimator< DensityDegree >* density ) +{ + LocalDepth maxDepth = _localMaxDepth( _tree ); + PointSupportKey< DensityDegree > densityKey; + PointSupportKey< DataDegree > dataKey; + densityKey.set( _localToGlobal( maxDepth ) ) , dataKey.set( _localToGlobal( maxDepth ) ); + + SparseNodeData< ProjectiveData< Data , Real > , DataDegree > dataField; + for( int i=0 ; i , Real >& sample = samples[i].sample; + const ProjectiveData< Data , Real >& data = sampleData[i]; + Point3D< Real > p = sample.weight==0 ? sample.data.p : sample.data.p / sample.weight; + if( !_InBounds(p) ){ fprintf( stderr , "[WARNING] Point is out of bounds: %f %f %f <- %f %f %f [%f]\n" , p[0] , p[1] , p[2] , sample.data.p[0] , sample.data.p[1] , sample.data.p[2] , sample.weight ) ; continue; } + _multiSplatPointData< CreateNodes >( density , (TreeOctNode*)samples[i].node , p , data , dataField , densityKey , dataKey , 2 ); + } + memoryUsage(); + return dataField; +} +template< class Real > +template< int MaxDegree , int FEMDegree , BoundaryType FEMBType , class HasDataFunctor > +void Octree< Real >::inalizeForBroodedMultigrid( LocalDepth fullDepth , const HasDataFunctor& F , std::vector< int >* map ) +{ + if( FEMDegree>MaxDegree ) fprintf( stderr , "[ERROR] MaxDegree must be at least as large as the FEM degree: %d <= %d\n" , FEMDegree , MaxDegree ); + while( _localInset( 0 ) + BSplineEvaluationData< MaxDegree , BOUNDARY_FREE >::Begin( 0 )<0 || _localInset( 0 ) + BSplineEvaluationData< MaxDegree , BOUNDARY_FREE >::End( 0 )>(1<<_depthOffset) ) + { + // +-+-+-+-+-+-+-+-+ + // | | | | | | | | | + // +-+-+-+-+-+-+-+-+ + // | | | | | | | | | + // +-+-+-+-+ +-+-+-+-+-+-+-+-+ + // | | | | | | | | | | | | | | + // +-+-+ +-+-+-+-+ +-+-+-+-+-+-+-+-+ + // |*| | | | | | | | | | | | | | | | + // +-o-+ -> +-+-o-+-+ -> +-+-+-+-o-+-+-+-+ + // | | | | | |*| | | | | | |*| | | | + // +-+-+ +-+-+-+-+ +-+-+-+-+-+-+-+-+ + // | | | | | | | | | | | | | | + // +-+-+-+-+ +-+-+-+-+-+-+-+-+ + // | | | | | | | | | + // +-+-+-+-+-+-+-+-+ + // | | | | | | | | | + // +-+-+-+-+-+-+-+-+ + + TreeOctNode* newSpaceRootParent = TreeOctNode::NewBrood( _NodeInitializer ); + TreeOctNode* oldSpaceRootParent = _spaceRoot->parent; + int corner = _depthOffset<=1 ? Cube::CORNERS-1 : 0; + newSpaceRootParent[corner].children = _spaceRoot; + oldSpaceRootParent->children = newSpaceRootParent; + for( int c=0 ; c( 0 , std::min< LocalDepth >( _maxDepth , fullDepth ) ); + _setFullDepth< MaxDegree , BOUNDARY_FREE >( _fullDepth ); + // Clear all the flags and make everything that is not low-res a ghost node + for( TreeOctNode* node=_tree->nextNode() ; node ; node=_tree->nextNode( node ) ) node->nodeData.flags = 0 , SetGhostFlag( node , _localDepth( node )>_fullDepth ); + + // Set the ghost nodes for the high-res part of the tree + _clipTree( F ); + + const int OverlapRadius = -BSplineOverlapSizes< MaxDegree , MaxDegree >::OverlapStart; + typename TreeOctNode::NeighborKey< OverlapRadius , OverlapRadius > neighborKey; + neighborKey.set( _localToGlobal( _maxDepth-1 ) ); + + for( LocalDepth d=_maxDepth-1 ; d>=0 ; d-- ) + for( TreeOctNode* node=_tree->nextNode() ; node ; node=_tree->nextNode( node ) ) if( _localDepth( node )==d && IsActiveNode( node->children ) ) + { + neighborKey.template getNeighbors< true >( node , _NodeInitializer ); + for( int i=0 ; i(); + for( TreeOctNode* node=_tree->nextNode() ; node ; node=_tree->nextNode( node ) ) if( !IsActiveNode( node ) ) node->nodeData.nodeIndex = -1; + memoryUsage(); +} + + +template< class Real > +template< int FEMDegree , BoundaryType BType > +void Octree< Real >::_setValidityFlags( void ) +{ + for( int i=0 ; i<_sNodes.size() ; i++ ) + { + const unsigned char MASK = ~( TreeNodeData::SPACE_FLAG | TreeNodeData::FEM_FLAG ); + _sNodes.treeNodes[i]->nodeData.flags &= MASK; + if( isValidSpaceNode( _sNodes.treeNodes[i] ) ) _sNodes.treeNodes[i]->nodeData.flags |= TreeNodeData::SPACE_FLAG; + if( isValidFEMNode< FEMDegree , BType >( _sNodes.treeNodes[i] ) ) _sNodes.treeNodes[i]->nodeData.flags |= TreeNodeData::FEM_FLAG; + } +} + +// Trim off the branches of the tree (finer than _fullDepth) that don't contain data +template< class Real > +template< class HasDataFunctor > +void Octree< Real >::_clipTree( const HasDataFunctor& f ) +{ + // Because we are doing things in a brooded fashion, if any of the children has data then the whole brood is active + for( TreeOctNode* temp=_tree->nextNode() ; temp ; temp=_tree->nextNode(temp) ) if( temp->children && _localDepth( temp )>=_fullDepth ) + { + bool hasData = false; + for( int c=0 ; cchildren + c ); + for( int c=0 ; cchildren+c , !hasData ); + } +} + +template< class Real > +template< bool HasGradients > +bool Octree< Real >::_setInterpolationInfoFromChildren( TreeOctNode* node , SparseNodeData< PointData< Real , HasGradients > , 0 >& interpolationInfo ) const +{ + if( IsActiveNode( node->children ) ) + { + bool hasChildData = false; + PointData< Real , HasGradients > pData; +#if POINT_DATA_RES + Point3D< Real > center; + Real width; + _centerAndWidth( node , center , width ); + for( int c=0 ; cchildren + c , interpolationInfo ) ) + { + const PointData< Real , HasGradients >& _pData = interpolationInfo[ node->children + c ]; + for( int cc=0 ; cc::SAMPLES ; cc++ ) + { + int x[3]; + PointData< Real , HasGradients >::SetIndices( _pData[cc].position / _pData[cc].weight , center , width , x ); + pData[ x[0] + x[1]*PointData< Real , HasGradients >::RES + x[2]*PointData< Real , HasGradients >::RES*PointData< Real , HasGradients >::RES ] += _pData[cc]; + } + hasChildData = true; + } +#else // !POINT_DATA_RES + for( int c=0 ; cchildren + c , interpolationInfo ) ) + { + pData += interpolationInfo[ node->children + c ]; + hasChildData = true; + } +#endif // POINT_DATA_RES + if( hasChildData && IsActiveNode( node ) ) interpolationInfo[ node ] += pData; + return hasChildData; + } + else return interpolationInfo( node )!=NULL; +} +template< class Real > +template< bool HasGradients > +SparseNodeData< PointData< Real , HasGradients > , 0 > Octree< Real >::_densifyInterpolationInfo( const std::vector< PointSample >& samples , Real pointValue , int adaptiveExponent ) const +{ + SparseNodeData< PointData< Real , HasGradients > , 0 > iInfo; + for( int i=0 ; i , Real >& pData = samples[i].sample; + while( !IsActiveNode( node ) ) node = node->parent; + if( pData.weight ) + { +#if POINT_DATA_RES + Point3D< Real > center; + Real width; + _centerAndWidth( node , center , width ); + _PointDataAccumulator_< Real , HasGradients >::_AddToPointData_( iInfo[node] , pData.data.p , pointValue * pData.weight , pData.data.n , center , width , pData.weight ); +#else // !POINT_DATA_RES + _PointDataAccumulator_< Real , HasGradients >::_AddToPointData_( iInfo[node] , pData.data.p , pointValue * pData.weight , pData.data.n , pData.weight ); +#endif // POINT_DATA_RES + } + } + + // Set the interior values + _setInterpolationInfoFromChildren( _spaceRoot, iInfo ); +#pragma omp parallel for + for( int i=0 ; i<(int)iInfo.size() ; i++ ) +#if POINT_DATA_RES + for( int c=0 ; c::SAMPLES ; c++ ) + { + Real w = iInfo[i][c].weight; + iInfo[i][c] /= w ; iInfo[i][c].weight = w; + } +#else // !POINT_DATA_RES + { + Real w = iInfo[i].weight; + iInfo[i] /= w ; iInfo[i].weight = w; + } +#endif // POINT_DATA_RES + LocalDepth maxDepth = _localMaxDepth( _tree ); + + // Set the average position and scale the weights + for( const TreeOctNode* node=_tree->nextNode() ; node ; node=_tree->nextNode(node) ) if( IsActiveNode( node ) ) + { + PointData< Real , HasGradients >* pData = iInfo( node ); + if( pData ) + { + int e = _localDepth( node ) * adaptiveExponent - ( maxDepth ) * (adaptiveExponent-1); +#if POINT_DATA_RES + for( int c=0 ; c::SAMPLES ; c++ ) if( (*pData)[c].weight ) + { + if( e<0 ) (*pData)[c].weight /= Real( 1<<(-e) ); + else (*pData)[c].weight *= Real( 1<< e ); + } +#else // !POINT_DATA_RES + if( e<0 ) pData->weight /= Real( 1<<(-e) ); + else pData->weight *= Real( 1<< e ); +#endif // POINT_DATA_RES + } + } + return iInfo; +} +//////////////// +// VertexData // +//////////////// +long long VertexData::CenterIndex( const TreeOctNode* node , int maxDepth ) +{ + int idx[DIMENSION]; + return CenterIndex(node,maxDepth,idx); +} +long long VertexData::CenterIndex(const TreeOctNode* node,int maxDepth,int idx[DIMENSION]) +{ + int d , o[3]; + node->depthAndOffset( d , o ); + for( int i=0 ; idepthAndOffset( d , o ); + for( int i=0 ; idepthAndOffset(d,o); + for(int i=0;idepthAndOffset( d ,off ); + Cube::FactorEdgeIndex( eIndex , o , i1 , i2 ); + for( int i=0 ; i +#include +#ifndef WIN32 +#include +#endif // WIN32 + +inline double Time( void ) +{ +#ifdef WIN32 + struct _timeb t; + _ftime( &t ); + return double( t.time ) + double( t.millitm ) / 1000.0; +#else // WIN32 + struct timeval t; + gettimeofday( &t , NULL ); + return t.tv_sec + double( t.tv_usec ) / 1000000; +#endif // WIN32 +} + +#endif // MY_TIME_INCLUDED diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/Octree.h b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Octree.h new file mode 100644 index 000000000..837339655 --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Octree.h @@ -0,0 +1,184 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +#ifndef OCT_NODE_INCLUDED +#define OCT_NODE_INCLUDED + +#define NEW_OCTNODE_CODE + +#include "Allocator.h" +#include "BinaryNode.h" +#include "MarchingCubes.h" + + +#define DIMENSION 3 + +template< class NodeData > +class OctNode +{ +private: + static int UseAlloc; + unsigned long long _depthAndOffset; + + const OctNode* __faceNeighbor( int dir , int off ) const; + const OctNode* __edgeNeighbor( int o , const int i[2] , const int idx[2] ) const; + OctNode* __faceNeighbor( int dir , int off , int forceChildren , void (*Initializer)( OctNode& ) ); + OctNode* __edgeNeighbor( int o , const int i[2] , const int idx[2] , int forceChildren , void (*Initializer)( OctNode& ) ); +public: + static const int DepthShift , OffsetShift , OffsetShift1 , OffsetShift2 , OffsetShift3; + static const int DepthMask , OffsetMask; + + static Allocator< OctNode > NodeAllocator; + static int UseAllocator( void ); + static void SetAllocator( int blockSize ); + + OctNode* parent; + OctNode* children; + NodeData nodeData; + + OctNode( void (*Initializer)( OctNode& )=NULL ); + static OctNode* NewBrood( void (*initializer)( OctNode& )=NULL ); + static void ResetDepthAndOffset( OctNode* root , int d , int off[3] ); + ~OctNode( void ); + int initChildren( void (*Initializer)( OctNode& )=NULL ); + + void depthAndOffset( int& depth , int offset[DIMENSION] ) const; + void centerIndex( int index[DIMENSION] ) const; + int depth( void ) const; + static inline void DepthAndOffset( const long long& index , int& depth , int offset[DIMENSION] ); + template< class Real > static inline void CenterAndWidth( const long long& index , Point3D< Real >& center , Real& width ); + template< class Real > static inline void StartAndWidth( const long long& index , Point3D< Real >& start , Real& width ); + static inline int Depth( const long long& index ); + static inline void Index( int depth , const int offset[3] , short& d , short off[DIMENSION] ); + static inline unsigned long long Index( int depth , const int offset[3] ); + template< class Real > void centerAndWidth( Point3D& center , Real& width ) const; + template< class Real > void startAndWidth( Point3D< Real >& start , Real& width ) const; + template< class Real > bool isInside( Point3D< Real > p ) const; + + size_t leaves( void ) const; + size_t maxDepthLeaves( int maxDepth ) const; + size_t nodes( void ) const; + int maxDepth( void ) const; + + const OctNode* root( void ) const; + + const OctNode* nextLeaf( const OctNode* currentLeaf=NULL ) const; + OctNode* nextLeaf( OctNode* currentLeaf=NULL ); + const OctNode* nextNode( const OctNode* currentNode=NULL ) const; + OctNode* nextNode( OctNode* currentNode=NULL ); + const OctNode* nextBranch( const OctNode* current ) const; + OctNode* nextBranch( OctNode* current ); + const OctNode* prevBranch( const OctNode* current ) const; + OctNode* prevBranch( OctNode* current ); + + void setFullDepth( int maxDepth , void (*Initializer)( OctNode& )=NULL ); + + void printLeaves( void ) const; + void printRange( void ) const; + + template< class Real > static int CornerIndex( const Point3D& center , const Point3D &p ); + + OctNode* faceNeighbor( int faceIndex , int forceChildren , void (*Initializer)( OctNode& )=NULL ); + const OctNode* faceNeighbor( int faceIndex ) const; + OctNode* edgeNeighbor( int edgeIndex , int forceChildren , void (*Initializer)( OctNode& )=NULL ); + const OctNode* edgeNeighbor( int edgeIndex ) const; + OctNode* cornerNeighbor( int cornerIndex , int forceChildren , void (*Initializer)( OctNode& )=NULL ); + const OctNode* cornerNeighbor( int cornerIndex ) const; + + int write( const char* fileName ) const; + int write( FILE* fp ) const; + int read( const char* fileName , void (*Initializer)( OctNode& )=NULL ); + int read( FILE* fp , void (*Initializer)( OctNode& )=NULL ); + + template< unsigned int Width > + struct Neighbors + { + OctNode* neighbors[Width][Width][Width]; + Neighbors( void ); + void clear( void ); + }; + template< unsigned int Width > + struct ConstNeighbors + { + const OctNode* neighbors[Width][Width][Width]; + ConstNeighbors( void ); + void clear( void ); + }; + + template< unsigned int LeftRadius , unsigned int RightRadius > + class NeighborKey + { + int _depth; + public: + template< int Width > using Neighbors = typename OctNode::template Neighbors< Width >; + static const int Width = LeftRadius + RightRadius + 1; + Neighbors< Width >* neighbors; + + NeighborKey( void ); + NeighborKey( const NeighborKey& key ); + ~NeighborKey( void ); + int depth( void ) const { return _depth; } + + void set( int depth ); + template< bool CreateNodes > typename OctNode< NodeData >::template Neighbors< LeftRadius+RightRadius+1 >& getNeighbors( OctNode* node , void (*Initializer)( OctNode& )=NULL ); + template< bool CreateNodes , unsigned int _LeftRadius , unsigned int _RightRadius > void getNeighbors( OctNode* node , Neighbors< _LeftRadius + _RightRadius + 1 >& neighbors , void (*Initializer)( OctNode& )=NULL ); + template< bool CreateNodes > bool getChildNeighbors( int cIdx , int d , Neighbors< Width >& childNeighbors , void (*Initializer)( OctNode& )=NULL ) const; + template< bool CreateNodes , class Real > bool getChildNeighbors( Point3D< Real > p , int d , Neighbors< Width >& childNeighbors , void (*Initializer)( OctNode& )=NULL ) const; + typename OctNode< NodeData >::template Neighbors< LeftRadius+RightRadius+1 >& getNeighbors( const OctNode* node ) { return getNeighbors< false >( (OctNode*)node , NULL ); } + template< unsigned int _LeftRadius , unsigned int _RightRadius > void getNeighbors( const OctNode* node , Neighbors< _LeftRadius + _RightRadius + 1 >& neighbors ){ return getNeighbors< false , _LeftRadius , _RightRadius >( (OctNode*)node , NULL ); } + bool getChildNeighbors( int cIdx , int d , Neighbors< Width >& childNeighbors ) const { return getChildNeighbors< false >( cIdx , d , childNeighbors , NULL ); } + template< class Real > bool getChildNeighbors( Point3D< Real > p , int d , Neighbors< Width >& childNeighbors ) const { return getChildNeighbors< false , Real >( p , d , childNeighbors , NULL ); } + }; + + template< unsigned int LeftRadius , unsigned int RightRadius > + class ConstNeighborKey + { + int _depth; + public: + template< int Width > using Neighbors = typename OctNode::template ConstNeighbors< Width >; + static const int Width = LeftRadius + RightRadius + 1; + ConstNeighbors< Width >* neighbors; + + ConstNeighborKey( void ); + ConstNeighborKey( const ConstNeighborKey& key ); + ~ConstNeighborKey( void ); + int depth( void ) const { return _depth; } + + void set( int depth ); + typename OctNode< NodeData >::template ConstNeighbors< LeftRadius+RightRadius+1 >& getNeighbors( const OctNode* node ); + template< unsigned int _LeftRadius , unsigned int _RightRadius > void getNeighbors( const OctNode* node , ConstNeighbors< _LeftRadius + _RightRadius + 1 >& neighbors ); + }; + + void centerIndex( int maxDepth , int index[DIMENSION] ) const; + int width( int maxDepth ) const; +}; + + +#include "Octree.inl" + +#endif // OCT_NODE_INCLUDED diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/Octree.inl b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Octree.inl new file mode 100644 index 000000000..6ff14f994 --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Octree.inl @@ -0,0 +1,1135 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +#include +#include +#include +#include + +///////////// +// OctNode // +///////////// +template< class NodeData > const int OctNode< NodeData >::DepthShift=5; +template< class NodeData > const int OctNode< NodeData >::OffsetShift = ( sizeof(long long)*8 - DepthShift ) / 3; +template< class NodeData > const int OctNode< NodeData >::DepthMask=(1< const int OctNode< NodeData >::OffsetMask=(1< const int OctNode< NodeData >::OffsetShift1=DepthShift; +template< class NodeData > const int OctNode< NodeData >::OffsetShift2=OffsetShift1+OffsetShift; +template< class NodeData > const int OctNode< NodeData >::OffsetShift3=OffsetShift2+OffsetShift; + +template< class NodeData > int OctNode< NodeData >::UseAlloc=0; +template< class NodeData > Allocator > OctNode< NodeData >::NodeAllocator; + +template< class NodeData > +void OctNode< NodeData >::SetAllocator(int blockSize) +{ + if(blockSize>0) + { + UseAlloc=1; + NodeAllocator.set(blockSize); + } + else{UseAlloc=0;} +} +template< class NodeData > int OctNode< NodeData >::UseAllocator( void ){ return UseAlloc; } + +template< class NodeData > +OctNode< NodeData >::OctNode( void (*Initializer)( OctNode& ) ) +{ + parent = children = NULL; + _depthAndOffset = 0; + if( Initializer ) Initializer( *this ); +} +template< class NodeData > +OctNode< NodeData >::~OctNode( void ) +{ + if( !UseAlloc && children ) delete[] children; + parent = children = NULL; +} + +template< class NodeData > +OctNode< NodeData >* OctNode< NodeData >::NewBrood( void (*Initializer)( OctNode& ) ) +{ + OctNode< NodeData >* brood; + if( UseAlloc ) brood = NodeAllocator.newElements( Cube::CORNERS ); + else brood = new OctNode[Cube::CORNERS]; + for( int i=0 ; i<2 ; i++ ) for( int j=0 ; j<2 ; j++ ) for( int k=0 ; k<2 ; k++ ) + { + int off[] = { i , j , k }; + int idx = Cube::CornerIndex( i , j , k ); + if( Initializer ) Initializer( brood[idx] ); + brood[idx]._depthAndOffset = Index( 0 , off ); + } + return brood; +} +template< class NodeData > +void OctNode< NodeData >::ResetDepthAndOffset( OctNode* root , int d , int off[3] ) +{ + // Recursive lambda requires an explicit declaration +#define PARENT_DEPTH_AND_OFFSET( d , off ) ( d-- , off[0]>>=1 , off[1]>>=1 , off[2]>>=1 ) +#define CHILD_DEPTH_AND_OFFSET( d , off ) ( d++ , off[0]<<=1 , off[1]<<=1 , off[2]<<=1 ) + std::function< OctNode* ( OctNode* , int& , int[] ) > _nextBranch = [&]( OctNode* current , int& d , int off[3] ) + { + if( current==root ) return (OctNode*)NULL; + else + { + int c = (int)( current - current->parent->children ); + + if( c==Cube::CORNERS-1 ) + { + PARENT_DEPTH_AND_OFFSET( d , off ); + return _nextBranch( current->parent , d , off ); + } + else + { + int x , y , z; + Cube::FactorCornerIndex( c+1 , x , y , z ); + PARENT_DEPTH_AND_OFFSET( d , off ) ; CHILD_DEPTH_AND_OFFSET( d , off ); + off[0] |= x , off[1] |= y , off[2] |= z; + return current+1; + } + } + }; + auto _nextNode = [&]( OctNode* current , int& d , int off[3] ) + { + if( !current ) return root; + else if( current->children ) + { + CHILD_DEPTH_AND_OFFSET( d , off ); + return current->children; + } + else return _nextBranch( current , d , off ); + }; +#undef PARENT_DEPTH_AND_OFFSET +#undef CHILD_DEPTH_AND_OFFSET + for( OctNode* node=_nextNode( NULL , d , off ) ; node ; node = _nextNode( node , d , off ) ) node->_depthAndOffset = Index( d , off ); +} + +template< class NodeData > +void OctNode< NodeData >::setFullDepth( int maxDepth , void (*Initializer)( OctNode& ) ) +{ + if( maxDepth ) + { + if( !children ) initChildren( Initializer ); + for( int i=0 ; i<8 ; i++ ) children[i].setFullDepth( maxDepth-1 , Initializer ); + } +} + +template< class NodeData > +int OctNode< NodeData >::initChildren( void (*Initializer)( OctNode& ) ) +{ + { + if( UseAlloc ) children = NodeAllocator.newElements( Cube::CORNERS ); + else + { + if( children ) delete[] children; + children = new OctNode[Cube::CORNERS]; + } + if( !children ) fprintf( stderr , "[ERROR] OctNode::initChildren: Failed to initialize children in OctNode::initChildren\n" ) , exit(0); + int d , off[3]; + depthAndOffset( d , off ); + for( int i=0 ; i<2 ; i++ ) for( int j=0 ; j<2 ; j++ ) for( int k=0 ; k<2 ; k++ ) + { + int idx=Cube::CornerIndex(i,j,k); + children[idx].parent = this; + children[idx].children = NULL; + if( Initializer ) Initializer( children[idx] ); + int off2[3]; + off2[0] = (off[0]<<1)+i; + off2[1] = (off[1]<<1)+j; + off2[2] = (off[2]<<1)+k; + children[idx]._depthAndOffset = Index( d+1 , off2 ); + } + } + return 1; +} +template< class NodeData > +inline void OctNode< NodeData >::Index(int depth,const int offset[3],short& d,short off[3]){ + d=short(depth); + off[0]=short((1< +inline void OctNode< NodeData >::depthAndOffset( int& depth , int offset[DIMENSION] ) const +{ + depth = int( _depthAndOffset & DepthMask ); + offset[0] = int( (_depthAndOffset>>OffsetShift1) & OffsetMask ); + offset[1] = int( (_depthAndOffset>>OffsetShift2) & OffsetMask ); + offset[2] = int( (_depthAndOffset>>OffsetShift3) & OffsetMask ); +} +template< class NodeData > +inline void OctNode< NodeData >::centerIndex( int index[DIMENSION] ) const +{ + int d , off[DIMENSION]; + depthAndOffset( d , off ); + for( int i=0 ; i +inline unsigned long long OctNode< NodeData >::Index( int depth , const int offset[3] ) +{ + unsigned long long idx=0; + idx |= ( ( (unsigned long long)(depth ) ) & DepthMask ); + idx |= ( ( (unsigned long long)(offset[0]) ) & OffsetMask ) << OffsetShift1; + idx |= ( ( (unsigned long long)(offset[1]) ) & OffsetMask ) << OffsetShift2; + idx |= ( ( (unsigned long long)(offset[2]) ) & OffsetMask ) << OffsetShift3; + return idx; +} +template< class NodeData > +inline int OctNode< NodeData >::depth( void ) const {return int( _depthAndOffset & DepthMask );} +template< class NodeData > +inline void OctNode< NodeData >::DepthAndOffset(const long long& index,int& depth,int offset[3]){ + depth=int(index&DepthMask); + offset[0]=(int((index>>OffsetShift1)&OffsetMask)+1)&(~(1<>OffsetShift2)&OffsetMask)+1)&(~(1<>OffsetShift3)&OffsetMask)+1)&(~(1< +inline int OctNode< NodeData >::Depth(const long long& index){return int(index&DepthMask);} +template< class NodeData > +template< class Real > +void OctNode< NodeData >::centerAndWidth( Point3D& center , Real& width ) const +{ + int depth , offset[3]; + depthAndOffset( depth , offset ); + width = Real( 1.0 / (1< +template< class Real > +void OctNode< NodeData >::startAndWidth( Point3D& start , Real& width ) const +{ + int depth , offset[3]; + depthAndOffset( depth , offset ); + width = Real( 1.0 / (1< +template< class Real > +bool OctNode< NodeData >::isInside( Point3D< Real > p ) const +{ + Point3D< Real > c; + Real w; + centerAndWidth( c , w ); + w /= 2; + return (c[0]-w) +template< class Real > +inline void OctNode< NodeData >::CenterAndWidth(const long long& index,Point3D& center,Real& width){ + int depth,offset[3]; + depth=index&DepthMask; + offset[0]=(int((index>>OffsetShift1)&OffsetMask)+1)&(~(1<>OffsetShift2)&OffsetMask)+1)&(~(1<>OffsetShift3)&OffsetMask)+1)&(~(1< +template< class Real > +inline void OctNode< NodeData >::StartAndWidth( const long long& index , Point3D< Real >& start , Real& width ) +{ + int depth,offset[3]; + depth = index&DepthMask; + offset[0] = (int((index>>OffsetShift1)&OffsetMask)+1)&(~(1<>OffsetShift2)&OffsetMask)+1)&(~(1<>OffsetShift3)&OffsetMask)+1)&(~(1< +int OctNode< NodeData >::maxDepth(void) const{ + if(!children){return 0;} + else{ + int c,d; + for(int i=0;ic){c=d;} + } + return c+1; + } +} +template< class NodeData > +size_t OctNode< NodeData >::nodes( void ) const +{ + if( !children ) return 1; + else + { + size_t c=0; + for( int i=0 ; i +size_t OctNode< NodeData >::leaves( void ) const +{ + if( !children ) return 1; + else + { + size_t c=0; + for( int i=0 ; i +size_t OctNode< NodeData >::maxDepthLeaves( int maxDepth ) const +{ + if( depth()>maxDepth ) return 0; + if( !children ) return 1; + else + { + size_t c=0; + for( int i=0 ; i +const OctNode< NodeData >* OctNode< NodeData >::root(void) const{ + const OctNode* temp=this; + while(temp->parent){temp=temp->parent;} + return temp; +} + + +template< class NodeData > +const OctNode< NodeData >* OctNode< NodeData >::nextBranch( const OctNode* current ) const +{ + if( !current->parent || current==this ) return NULL; + if( current-current->parent->children==Cube::CORNERS-1 ) return nextBranch( current->parent ); + else return current+1; +} +template< class NodeData > +OctNode< NodeData >* OctNode< NodeData >::nextBranch(OctNode* current){ + if(!current->parent || current==this){return NULL;} + if(current-current->parent->children==Cube::CORNERS-1){return nextBranch(current->parent);} + else{return current+1;} +} +template< class NodeData > +const OctNode< NodeData >* OctNode< NodeData >::prevBranch( const OctNode* current ) const +{ + if( !current->parent || current==this ) return NULL; + if( current-current->parent->children==0 ) return prevBranch( current->parent ); + else return current-1; +} +template< class NodeData > +OctNode< NodeData >* OctNode< NodeData >::prevBranch( OctNode* current ) +{ + if( !current->parent || current==this ) return NULL; + if( current-current->parent->children==0 ) return prevBranch( current->parent ); + else return current-1; +} +template< class NodeData > +const OctNode< NodeData >* OctNode< NodeData >::nextLeaf(const OctNode* current) const{ + if( !current ) + { + const OctNode< NodeData >* temp=this; + while( temp->children ) temp=&temp->children[0]; + return temp; + } + if( current->children ) return current->nextLeaf(); + const OctNode* temp = nextBranch(current); + if( !temp ) return NULL; + else return temp->nextLeaf(); +} +template< class NodeData > +OctNode< NodeData >* OctNode< NodeData >::nextLeaf( OctNode* current ) +{ + if( !current ) + { + OctNode< NodeData >* temp=this; + while(temp->children){temp=&temp->children[0];} + return temp; + } + if(current->children){return current->nextLeaf();} + OctNode* temp=nextBranch(current); + if(!temp){return NULL;} + else{return temp->nextLeaf();} +} + +template< class NodeData > +const OctNode< NodeData >* OctNode< NodeData >::nextNode( const OctNode* current ) const +{ + if( !current ) return this; + else if( current->children ) return ¤t->children[0]; + else return nextBranch(current); +} +template< class NodeData > +OctNode< NodeData >* OctNode< NodeData >::nextNode( OctNode* current ) +{ + if( !current ) return this; + else if( current->children ) return ¤t->children[0]; + else return nextBranch( current ); +} + +template< class NodeData > +void OctNode< NodeData >::printRange(void) const +{ + Point3D< float > center; + float width; + centerAndWidth(center,width); + for(int dim=0;dim +template< class Real > +int OctNode< NodeData >::CornerIndex(const Point3D& center,const Point3D& p){ + int cIndex=0; + if(p.coords[0]>center.coords[0]){cIndex|=1;} + if(p.coords[1]>center.coords[1]){cIndex|=2;} + if(p.coords[2]>center.coords[2]){cIndex|=4;} + return cIndex; +} + +template< class NodeData > +OctNode< NodeData >* OctNode< NodeData >::faceNeighbor( int faceIndex , int forceChildren , void (*Initializer)( OctNode& ) ){return __faceNeighbor( faceIndex>>1 , faceIndex&1 , forceChildren , Initializer ); } +template< class NodeData > +const OctNode< NodeData >* OctNode< NodeData >::faceNeighbor(int faceIndex) const {return __faceNeighbor(faceIndex>>1,faceIndex&1);} +template< class NodeData > +OctNode< NodeData >* OctNode< NodeData >::__faceNeighbor( int dir , int off , int forceChildren , void (*Initializer)( OctNode& ) ) +{ + if(!parent){return NULL;} + int pIndex=int(this-parent->children); + pIndex^=(1<children[pIndex];} + else{ + OctNode* temp=parent->__faceNeighbor(dir,off,forceChildren); + if( !temp ) return NULL; + if( !temp->children ) + { + if( forceChildren ) temp->initChildren( Initializer ); + else return temp; + } + return &temp->children[pIndex]; + } +} +template< class NodeData > +const OctNode< NodeData >* OctNode< NodeData >::__faceNeighbor(int dir,int off) const { + if(!parent){return NULL;} + int pIndex=int(this-parent->children); + pIndex^=(1<children[pIndex];} + else{ + const OctNode* temp=parent->__faceNeighbor(dir,off); + if(!temp || !temp->children){return temp;} + else{return &temp->children[pIndex];} + } +} + +template< class NodeData > +OctNode< NodeData >* OctNode< NodeData >::edgeNeighbor( int edgeIndex , int forceChildren , void (*Initializer)( OctNode& ) ) +{ + int idx[2],o,i[2]; + Cube::FactorEdgeIndex( edgeIndex , o , i[0] , i[1] ); + switch(o){ + case 0: idx[0]=1; idx[1]=2; break; + case 1: idx[0]=0; idx[1]=2; break; + case 2: idx[0]=0; idx[1]=1; break; + }; + return __edgeNeighbor( o , i , idx , forceChildren , Initializer ); +} +template< class NodeData > +const OctNode< NodeData >* OctNode< NodeData >::edgeNeighbor(int edgeIndex) const { + int idx[2],o,i[2]; + Cube::FactorEdgeIndex(edgeIndex,o,i[0],i[1]); + switch(o){ + case 0: idx[0]=1; idx[1]=2; break; + case 1: idx[0]=0; idx[1]=2; break; + case 2: idx[0]=0; idx[1]=1; break; + }; + return __edgeNeighbor(o,i,idx); +} +template< class NodeData > +const OctNode< NodeData >* OctNode< NodeData >::__edgeNeighbor(int o,const int i[2],const int idx[2]) const{ + if(!parent){return NULL;} + int pIndex=int(this-parent->children); + int aIndex,x[DIMENSION]; + + Cube::FactorCornerIndex(pIndex,x[0],x[1],x[2]); + aIndex=(~((i[0] ^ x[idx[0]]) | ((i[1] ^ x[idx[1]])<<1))) & 3; + pIndex^=(7 ^ (1<__faceNeighbor(idx[0],i[0]); + if(!temp || !temp->children){return NULL;} + else{return &temp->children[pIndex];} + } + else if(aIndex==2) { // I can get the neighbor from the parent's face adjacent neighbor + const OctNode* temp=parent->__faceNeighbor(idx[1],i[1]); + if(!temp || !temp->children){return NULL;} + else{return &temp->children[pIndex];} + } + else if(aIndex==0) { // I can get the neighbor from the parent + return &parent->children[pIndex]; + } + else if(aIndex==3) { // I can get the neighbor from the parent's edge adjacent neighbor + const OctNode* temp=parent->__edgeNeighbor(o,i,idx); + if(!temp || !temp->children){return temp;} + else{return &temp->children[pIndex];} + } + else{return NULL;} +} +template< class NodeData > +OctNode< NodeData >* OctNode< NodeData >::__edgeNeighbor( int o , const int i[2] , const int idx[2] , int forceChildren , void (*Initializer)( OctNode& ) ) +{ + if(!parent){return NULL;} + int pIndex=int(this-parent->children); + int aIndex,x[DIMENSION]; + + Cube::FactorCornerIndex(pIndex,x[0],x[1],x[2]); + aIndex=(~((i[0] ^ x[idx[0]]) | ((i[1] ^ x[idx[1]])<<1))) & 3; + pIndex^=(7 ^ (1<__faceNeighbor(idx[0],i[0],0); + if(!temp || !temp->children){return NULL;} + else{return &temp->children[pIndex];} + } + else if(aIndex==2) { // I can get the neighbor from the parent's face adjacent neighbor + OctNode* temp=parent->__faceNeighbor(idx[1],i[1],0); + if(!temp || !temp->children){return NULL;} + else{return &temp->children[pIndex];} + } + else if(aIndex==0) { // I can get the neighbor from the parent + return &parent->children[pIndex]; + } + else if(aIndex==3) { // I can get the neighbor from the parent's edge adjacent neighbor + OctNode* temp=parent->__edgeNeighbor(o,i,idx,forceChildren); + if( !temp ) return NULL; + if( !temp->children ) + { + if( forceChildren ) temp->initChildren( Initializer ); + else return temp; + } + return &temp->children[pIndex]; + } + else{return NULL;} +} + +template< class NodeData > +const OctNode< NodeData >* OctNode< NodeData >::cornerNeighbor(int cornerIndex) const { + int pIndex,aIndex=0; + if(!parent){return NULL;} + + pIndex=int(this-parent->children); + aIndex=(cornerIndex ^ pIndex); // The disagreement bits + pIndex=(~pIndex)&7; // The antipodal point + if(aIndex==7){ // Agree on no bits + return &parent->children[pIndex]; + } + else if(aIndex==0){ // Agree on all bits + const OctNode* temp=((const OctNode*)parent)->cornerNeighbor(cornerIndex); + if(!temp || !temp->children){return temp;} + else{return &temp->children[pIndex];} + } + else if(aIndex==6){ // Agree on face 0 + const OctNode* temp=((const OctNode*)parent)->__faceNeighbor(0,cornerIndex & 1); + if(!temp || !temp->children){return NULL;} + else{return & temp->children[pIndex];} + } + else if(aIndex==5){ // Agree on face 1 + const OctNode* temp=((const OctNode*)parent)->__faceNeighbor(1,(cornerIndex & 2)>>1); + if(!temp || !temp->children){return NULL;} + else{return & temp->children[pIndex];} + } + else if(aIndex==3){ // Agree on face 2 + const OctNode* temp=((const OctNode*)parent)->__faceNeighbor(2,(cornerIndex & 4)>>2); + if(!temp || !temp->children){return NULL;} + else{return & temp->children[pIndex];} + } + else if(aIndex==4){ // Agree on edge 2 + const OctNode* temp=((const OctNode*)parent)->edgeNeighbor(8 | (cornerIndex & 1) | (cornerIndex & 2) ); + if(!temp || !temp->children){return NULL;} + else{return & temp->children[pIndex];} + } + else if(aIndex==2){ // Agree on edge 1 + const OctNode* temp=((const OctNode*)parent)->edgeNeighbor(4 | (cornerIndex & 1) | ((cornerIndex & 4)>>1) ); + if(!temp || !temp->children){return NULL;} + else{return & temp->children[pIndex];} + } + else if(aIndex==1){ // Agree on edge 0 + const OctNode* temp=((const OctNode*)parent)->edgeNeighbor(((cornerIndex & 2) | (cornerIndex & 4))>>1 ); + if(!temp || !temp->children){return NULL;} + else{return & temp->children[pIndex];} + } + else{return NULL;} +} +template< class NodeData > +OctNode< NodeData >* OctNode< NodeData >::cornerNeighbor( int cornerIndex , int forceChildren , void (*Initializer)( OctNode& ) ) +{ + int pIndex,aIndex=0; + if(!parent){return NULL;} + + pIndex=int(this-parent->children); + aIndex=(cornerIndex ^ pIndex); // The disagreement bits + pIndex=(~pIndex)&7; // The antipodal point + if(aIndex==7){ // Agree on no bits + return &parent->children[pIndex]; + } + else if(aIndex==0){ // Agree on all bits + OctNode* temp=((OctNode*)parent)->cornerNeighbor( cornerIndex , forceChildren , Initializer ); + if( !temp ) return NULL; + if( !temp->children ) + { + if(forceChildren) temp->initChildren( Initializer ); + else return temp; + } + return &temp->children[pIndex]; + } + else if(aIndex==6){ // Agree on face 0 + OctNode* temp=((OctNode*)parent)->__faceNeighbor(0,cornerIndex & 1,0); + if(!temp || !temp->children){return NULL;} + else{return & temp->children[pIndex];} + } + else if(aIndex==5){ // Agree on face 1 + OctNode* temp=((OctNode*)parent)->__faceNeighbor(1,(cornerIndex & 2)>>1,0); + if(!temp || !temp->children){return NULL;} + else{return & temp->children[pIndex];} + } + else if(aIndex==3){ // Agree on face 2 + OctNode* temp=((OctNode*)parent)->__faceNeighbor(2,(cornerIndex & 4)>>2,0); + if(!temp || !temp->children){return NULL;} + else{return & temp->children[pIndex];} + } + else if(aIndex==4){ // Agree on edge 2 + OctNode* temp=((OctNode*)parent)->edgeNeighbor(8 | (cornerIndex & 1) | (cornerIndex & 2) ); + if(!temp || !temp->children){return NULL;} + else{return & temp->children[pIndex];} + } + else if(aIndex==2){ // Agree on edge 1 + OctNode* temp=((OctNode*)parent)->edgeNeighbor(4 | (cornerIndex & 1) | ((cornerIndex & 4)>>1) ); + if(!temp || !temp->children){return NULL;} + else{return & temp->children[pIndex];} + } + else if(aIndex==1){ // Agree on edge 0 + OctNode* temp=((OctNode*)parent)->edgeNeighbor(((cornerIndex & 2) | (cornerIndex & 4))>>1 ); + if(!temp || !temp->children){return NULL;} + else{return & temp->children[pIndex];} + } + else{return NULL;} +} + +//////////////////////// +// OctNode::Neighbors // +//////////////////////// +template< class NodeData > +template< unsigned int Width > +OctNode< NodeData >::Neighbors< Width >::Neighbors( void ){ clear(); } +template< class NodeData > +template< unsigned int Width > +void OctNode< NodeData >::Neighbors< Width >::clear( void ){ for( int i=0 ; i +template< unsigned int Width > +OctNode< NodeData >::ConstNeighbors< Width >::ConstNeighbors( void ){ clear(); } +template< class NodeData > +template< unsigned int Width > +void OctNode< NodeData >::ConstNeighbors< Width >::clear( void ){ for( int i=0 ; i +template< unsigned int LeftRadius , unsigned int RightRadius > +OctNode< NodeData >::NeighborKey< LeftRadius , RightRadius >::NeighborKey( void ){ _depth=-1 , neighbors=NULL; } +template< class NodeData > +template< unsigned int LeftRadius , unsigned int RightRadius > +OctNode< NodeData >::NeighborKey< LeftRadius , RightRadius >::NeighborKey( const NeighborKey& nKey ) +{ + _depth = 0 , neighbors = NULL; + set( nKey._depth ); + for( int d=0 ; d<=_depth ; d++ ) memcpy( &neighbors[d] , &nKey.neighbors[d] , sizeof( Neighbors< Width > ) ); +} +template< class NodeData > +template< unsigned int LeftRadius , unsigned int RightRadius > +OctNode< NodeData >::NeighborKey< LeftRadius , RightRadius >::~NeighborKey( void ) +{ + if( neighbors ) delete[] neighbors; + neighbors = NULL; +} + +template< class NodeData > +template< unsigned int LeftRadius , unsigned int RightRadius > +void OctNode< NodeData >::NeighborKey< LeftRadius , RightRadius >::set( int d ) +{ + if( neighbors ) delete[] neighbors; + neighbors = NULL; + _depth = d; + if( d<0 ) return; + neighbors = new Neighbors< Width >[d+1]; +} +template< class NodeData > +template< unsigned int LeftRadius , unsigned int RightRadius > +template< bool CreateNodes > +bool OctNode< NodeData >::NeighborKey< LeftRadius , RightRadius >::getChildNeighbors( int cIdx , int d , Neighbors< Width >& cNeighbors , void (*Initializer)( OctNode& ) ) const +{ + Neighbors< Width >& pNeighbors = neighbors[d]; + // Check that we actuall have a center node + if( !pNeighbors.neighbors[LeftRadius][LeftRadius][LeftRadius] ) return false; + + // Get the indices of the child node that would contain the point (and its antipode) + int cx , cy , cz; + Cube::FactorCornerIndex( cIdx , cx , cy , cz ); + + + // Iterate over the finer neighbors and set them (if you can) + // Here: + // (x,y,z) give the position of the finer nodes relative to the center, + // (_x,_y,_z) give a positive global position, up to an even offset, and + // (px-LeftRadius,py-LeftRadius,pz-LeftRadius) give the positions of their parents relative to the parent of the center + for( int z=-(int)LeftRadius ; z<=(int)RightRadius ; z++ ) + { + int _z = (z+cz) + (LeftRadius<<1) , pz = ( _z>>1 ) , zz = z+LeftRadius; + for( int y=-(int)LeftRadius ; y<=(int)RightRadius ; y++ ) + { + int _y = (y+cy) + (LeftRadius<<1) , py = ( _y>>1 ) , yy = y+LeftRadius; + + int cornerIndex = ( (_z&1)<<2 ) | ( (_y&1)<<1 ); + for( int x=-(int)LeftRadius ; x<=(int)RightRadius ; x++ ) + { + int _x = (x+cx) + (LeftRadius<<1) , px = ( _x>>1 ) , xx = x+LeftRadius; + + if( CreateNodes ) + { + if( pNeighbors.neighbors[px][py][pz] ) + { + if( !pNeighbors.neighbors[px][py][pz]->children ) pNeighbors.neighbors[px][py][pz]->initChildren( Initializer ); + cNeighbors.neighbors[xx][yy][zz] = pNeighbors.neighbors[px][py][pz]->children + ( cornerIndex | (_x&1) ); + } + else cNeighbors.neighbors[xx][yy][zz] = NULL; + } + else + { + if( pNeighbors.neighbors[px][py][pz] && pNeighbors.neighbors[px][py][pz]->children ) + cNeighbors.neighbors[xx][yy][zz] = pNeighbors.neighbors[px][py][pz]->children + ( cornerIndex | (_x&1) ); + else cNeighbors.neighbors[xx][yy][zz] = NULL; + } + } + } + } + return true; +} +template< class NodeData > +template< unsigned int LeftRadius , unsigned int RightRadius > +template< bool CreateNodes , class Real > +bool OctNode< NodeData >::NeighborKey< LeftRadius , RightRadius >::getChildNeighbors( Point3D< Real > p , int d , Neighbors< Width >& cNeighbors , void (*Initializer)( OctNode& ) ) const +{ + Neighbors< Width >& pNeighbors = neighbors[d]; + // Check that we actuall have a center node + if( !pNeighbors.neighbors[LeftRadius][LeftRadius][LeftRadius] ) return false; + Point3D< Real > c; + Real w; + pNeighbors.neighbors[LeftRadius][LeftRadius][LeftRadius]->centerAndWidth( c , w ); + return getChildNeighbors< CreateNodes >( CornerIndex( c , p ) , d , cNeighbors , Initializer ); +} + +template< class NodeData > +template< unsigned int LeftRadius , unsigned int RightRadius > +template< bool CreateNodes > +typename OctNode< NodeData >::template Neighbors< LeftRadius+RightRadius+1 >& OctNode< NodeData >::NeighborKey< LeftRadius , RightRadius >::getNeighbors( OctNode< NodeData >* node , void (*Initializer)( OctNode& ) ) +{ + Neighbors< Width >& neighbors = this->neighbors[ node->depth() ]; + if( node==neighbors.neighbors[LeftRadius][LeftRadius][LeftRadius] ) + { + bool reset = false; + for( int i=0 ; iparent ) neighbors.neighbors[LeftRadius][LeftRadius][LeftRadius] = node; + else + { + Neighbors< Width >& pNeighbors = getNeighbors< CreateNodes >( node->parent , Initializer ); + + // Get the indices of the child node that would contain the point (and its antipode) + int cx , cy , cz; + Cube::FactorCornerIndex( (int)( node - node->parent->children ) , cx , cy , cz ); + + + // Iterate over the finer neighbors and set them (if you can) + // Here: + // (x,y,z) give the position of the finer nodes relative to the center, + // (_x,_y,_z) give a positive global position, up to an even offset, and + // (px-LeftRadius,py-LeftRadius,pz-LeftRadius) give the positions of their parents relative to the parent of the center + for( int z=-(int)LeftRadius ; z<=(int)RightRadius ; z++ ) + { + int _z = (z+cz) + (LeftRadius<<1) , pz = ( _z>>1 ) , zz = z+LeftRadius; + for( int y=-(int)LeftRadius ; y<=(int)RightRadius ; y++ ) + { + int _y = (y+cy) + (LeftRadius<<1) , py = ( _y>>1 ) , yy = y+LeftRadius; + + int cornerIndex = ( (_z&1)<<2 ) | ( (_y&1)<<1 ); + for( int x=-(int)LeftRadius ; x<=(int)RightRadius ; x++ ) + { + int _x = (x+cx) + (LeftRadius<<1) , px = ( _x>>1 ) , xx = x+LeftRadius; + if( CreateNodes ) + { + if( pNeighbors.neighbors[px][py][pz] ) + { + if( !pNeighbors.neighbors[px][py][pz]->children ) pNeighbors.neighbors[px][py][pz]->initChildren( Initializer ); + neighbors.neighbors[xx][yy][zz] = pNeighbors.neighbors[px][py][pz]->children + ( cornerIndex | (_x&1) ); + } + else neighbors.neighbors[xx][yy][zz] = NULL; + } + else + { + if( pNeighbors.neighbors[px][py][pz] && pNeighbors.neighbors[px][py][pz]->children ) + neighbors.neighbors[xx][yy][zz] = pNeighbors.neighbors[px][py][pz]->children + ( cornerIndex | (_x&1) ); + else neighbors.neighbors[xx][yy][zz] = NULL; + } + } + } + } + } + } + return neighbors; +} +template< class NodeData > +template< unsigned int LeftRadius , unsigned int RightRadius > +template< bool CreateNodes , unsigned int _LeftRadius , unsigned int _RightRadius > +void OctNode< NodeData >::NeighborKey< LeftRadius , RightRadius >::getNeighbors( OctNode< NodeData >* node , Neighbors< _LeftRadius + _RightRadius + 1 >& neighbors , void (*Initializer)( OctNode& ) ) +{ + neighbors.clear(); + if( !node ) return; + + // [WARNING] This estimate of the required radius is somewhat conservative if the radius is odd (depending on where the node is relative to its parent) + const unsigned int _PLeftRadius = (_LeftRadius+1)/2 , _PRightRadius = (_RightRadius+1)/2; + // If we are at the root of the tree, we are done + if( !node->parent ) neighbors.neighbors[_LeftRadius][_LeftRadius][_LeftRadius] = node; + // If we can get the data from the the key for the parent node, do that + else if( _PLeftRadius<=LeftRadius && _PRightRadius<=RightRadius ) + { + getNeighbors< CreateNodes >( node->parent , Initializer ); + const Neighbors< LeftRadius + RightRadius + 1 >& pNeighbors = this->neighbors[ node->depth()-1 ]; + // Get the indices of the child node that would contain the point (and its antipode) + int cx , cy , cz; + Cube::FactorCornerIndex( (int)( node - node->parent->children ) , cx , cy , cz ); + + + // Iterate over the finer neighbors + // Here: + // (x,y,z) give the position of the finer nodes relative to the center, + // (_x,_y,_z) give a positive global position, up to an even offset, and + // (px-LeftRadius,py-LeftRadius,pz-LeftRadius) give the positions of their parents relative to the parent of the center + for( int z=-(int)_LeftRadius ; z<=(int)_RightRadius ; z++ ) + { + int _z = (z+cz) + (_LeftRadius<<1) , pz = ( _z>>1 ) - _LeftRadius + LeftRadius , zz = z + _LeftRadius; + for( int y=-(int)_LeftRadius ; y<=(int)_RightRadius ; y++ ) + { + int _y = (y+cy) + (_LeftRadius<<1) , py = ( _y>>1 ) - _LeftRadius + LeftRadius , yy = y + _LeftRadius; + + int cornerIndex = ( (_z&1)<<2 ) | ( (_y&1)<<1 ); + for( int x=-(int)_LeftRadius ; x<=(int)_RightRadius ; x++ ) + { + int _x = (x+cx) + (_LeftRadius<<1) , px = ( _x>>1 ) - _LeftRadius + LeftRadius , xx = x + _LeftRadius; + if( CreateNodes ) + { + if( pNeighbors.neighbors[px][py][pz] ) + { + if( !pNeighbors.neighbors[px][py][pz]->children ) pNeighbors.neighbors[px][py][pz]->initChildren( Initializer ); + neighbors.neighbors[xx][yy][zz] = pNeighbors.neighbors[px][py][pz]->children + ( cornerIndex | (_x&1) ); + } + else neighbors.neighbors[xx][yy][zz] = NULL; + } + else + { + if( pNeighbors.neighbors[px][py][pz] && pNeighbors.neighbors[px][py][pz]->children ) + neighbors.neighbors[xx][yy][zz] = pNeighbors.neighbors[px][py][pz]->children + ( cornerIndex | (_x&1) ); + else neighbors.neighbors[xx][yy][zz] = NULL; + } + } + } + } + } + // Otherwise recurse + else + { + Neighbors< _PLeftRadius + _PRightRadius + 1 > pNeighbors; + getNeighbors< CreateNodes , _PLeftRadius , _PRightRadius >( node->parent , pNeighbors , Initializer ); + + // Get the indices of the child node that would contain the point (and its antipode) + int cx , cy , cz; + Cube::FactorCornerIndex( (int)( node - node->parent->children ) , cx , cy , cz ); + + + // Iterate over the finer neighbors + // Here: + // (x,y,z) give the position of the finer nodes relative to the center, + // (_x,_y,_z) give a positive global position, up to an even offset, and + // (px-LeftRadius,py-LeftRadius,pz-LeftRadius) give the positions of their parents relative to the parent of the center + for( int z=-(int)_LeftRadius ; z<=(int)_RightRadius ; z++ ) + { + int _z = (z+cz) + (_LeftRadius<<1) , pz = ( _z>>1 ) - _LeftRadius + _PLeftRadius , zz = z + _LeftRadius; + for( int y=-(int)_LeftRadius ; y<=(int)_RightRadius ; y++ ) + { + int _y = (y+cy) + (_LeftRadius<<1) , py = ( _y>>1 ) - _LeftRadius + _PLeftRadius , yy = y + _LeftRadius; + + int cornerIndex = ( (_z&1)<<2 ) | ( (_y&1)<<1 ); + for( int x=-(int)_LeftRadius ; x<=(int)_RightRadius ; x++ ) + { + int _x = (x+cx) + (_LeftRadius<<1) , px = ( _x>>1 ) - _LeftRadius + _PLeftRadius , xx = x + _LeftRadius; + if( CreateNodes ) + { + if( pNeighbors.neighbors[px][py][pz] ) + { + if( !pNeighbors.neighbors[px][py][pz]->children ) pNeighbors.neighbors[px][py][pz]->initChildren( Initializer ); + neighbors.neighbors[xx][yy][zz] = pNeighbors.neighbors[px][py][pz]->children + ( cornerIndex | (_x&1) ); + } + else neighbors.neighbors[xx][yy][zz] = NULL; + } + else + { + if( pNeighbors.neighbors[px][py][pz] && pNeighbors.neighbors[px][py][pz]->children ) + neighbors.neighbors[xx][yy][zz] = pNeighbors.neighbors[px][py][pz]->children + ( cornerIndex | (_x&1) ); + else neighbors.neighbors[xx][yy][zz] = NULL; + } + } + } + } + } +} + +/////////////////////////////// +// OctNode::ConstNeighborKey // +/////////////////////////////// +template< class NodeData > +template< unsigned int LeftRadius , unsigned int RightRadius > +OctNode< NodeData >::ConstNeighborKey< LeftRadius , RightRadius >::ConstNeighborKey( void ){ _depth=-1 , neighbors=NULL; } +template< class NodeData > +template< unsigned int LeftRadius , unsigned int RightRadius > +OctNode< NodeData >::ConstNeighborKey< LeftRadius , RightRadius >::ConstNeighborKey( const ConstNeighborKey& key ) +{ + _depth = 0 , neighbors = NULL; + set( key._depth ); + for( int d=0 ; d<=_depth ; d++ ) memcpy( &neighbors[d] , &key.neighbors[d] , sizeof( ConstNeighbors< Width > ) ); +} +template< class NodeData > +template< unsigned int LeftRadius , unsigned int RightRadius > +OctNode< NodeData >::ConstNeighborKey< LeftRadius , RightRadius >::~ConstNeighborKey( void ) +{ + if( neighbors ) delete[] neighbors; + neighbors=NULL; +} + +template< class NodeData > +template< unsigned int LeftRadius , unsigned int RightRadius > +void OctNode< NodeData >::ConstNeighborKey< LeftRadius , RightRadius >::set( int d ) +{ + if( neighbors ) delete[] neighbors; + neighbors = NULL; + _depth = d; + if( d<0 ) return; + neighbors = new ConstNeighbors< Width >[d+1]; +} +template< class NodeData > +template< unsigned int LeftRadius , unsigned int RightRadius > +typename OctNode< NodeData >::template ConstNeighbors< LeftRadius+RightRadius+1 >& OctNode< NodeData >::ConstNeighborKey< LeftRadius , RightRadius >::getNeighbors( const OctNode< NodeData >* node ) +{ + ConstNeighbors< Width >& neighbors = this->neighbors[ node->depth() ]; + if( node!=neighbors.neighbors[LeftRadius][LeftRadius][LeftRadius]) + { + neighbors.clear(); + + if( !node->parent ) neighbors.neighbors[LeftRadius][LeftRadius][LeftRadius] = node; + else + { + ConstNeighbors< Width >& pNeighbors = getNeighbors( node->parent ); + + // Get the indices of the child node that would contain the point (and its antipode) + int cx , cy , cz; + Cube::FactorCornerIndex( (int)( node - node->parent->children ) , cx , cy , cz ); + + + // Iterate over the finer neighbors and set them (if you can) + // Here: + // (x,y,z) give the position of the finer nodes relative to the center, + // (_x,_y,_z) give a positive global position, up to an even offset, and + // (px-LeftRadius,py-LeftRadius,pz-LeftRadius) give the positions of their parents relative to the parent of the center + for( int z=-(int)LeftRadius ; z<=(int)RightRadius ; z++ ) + { + int _z = (z+cz) + (LeftRadius<<1) , pz = ( _z>>1 ) , zz = z+LeftRadius; + for( int y=-(int)LeftRadius ; y<=(int)RightRadius ; y++ ) + { + int _y = (y+cy) + (LeftRadius<<1) , py = ( _y>>1 ) , yy = y+LeftRadius; + + int cornerIndex = ( (_z&1)<<2 ) | ( (_y&1)<<1 ); + for( int x=-(int)LeftRadius ; x<=(int)RightRadius ; x++ ) + { + int _x = (x+cx) + (LeftRadius<<1) , px = ( _x>>1 ) , xx = x+LeftRadius; + if( pNeighbors.neighbors[px][py][pz] && pNeighbors.neighbors[px][py][pz]->children ) + neighbors.neighbors[xx][yy][zz] = pNeighbors.neighbors[px][py][pz]->children + ( cornerIndex | (_x&1) ); + else + neighbors.neighbors[xx][yy][zz] = NULL; + } + } + } + } + } + return neighbors; +} +template< class NodeData > +template< unsigned int LeftRadius , unsigned int RightRadius > +template< unsigned int _LeftRadius , unsigned int _RightRadius > +void OctNode< NodeData >::ConstNeighborKey< LeftRadius , RightRadius >::getNeighbors( const OctNode< NodeData >* node , ConstNeighbors< _LeftRadius+_RightRadius+1 >& neighbors ) +{ + neighbors.clear(); + if( !node ) return; + + // [WARNING] This estimate of the required radius is somewhat conservative if the radius is odd (depending on where the node is relative to its parent) + const unsigned int _PLeftRadius = (_LeftRadius+1)/2 , _PRightRadius = (_RightRadius+1)/2; + // If we are at the root of the tree, we are done + if( !node->parent ) neighbors.neighbors[_LeftRadius][_LeftRadius][_LeftRadius] = node; + // If we can get the data from the the key for the parent node, do that + else if( _PLeftRadius<=LeftRadius && _PRightRadius<=RightRadius ) + { + getNeighbors( node->parent ); + const ConstNeighbors< LeftRadius + RightRadius + 1 >& pNeighbors = this->neighbors[ node->depth()-1 ]; + // Get the indices of the child node that would contain the point (and its antipode) + int cx , cy , cz; + Cube::FactorCornerIndex( (int)( node - node->parent->children ) , cx , cy , cz ); + + + // Iterate over the finer neighbors + // Here: + // (x,y,z) give the position of the finer nodes relative to the center, + // (_x,_y,_z) give a positive global position, up to an even offset, and + // (px-LeftRadius,py-LeftRadius,pz-LeftRadius) give the positions of their parents relative to the parent of the center + for( int z=-(int)_LeftRadius ; z<=(int)_RightRadius ; z++ ) + { + int _z = (z+cz) + (_LeftRadius<<1) , pz = ( _z>>1 ) - _LeftRadius + LeftRadius , zz = z + _LeftRadius; + for( int y=-(int)_LeftRadius ; y<=(int)_RightRadius ; y++ ) + { + int _y = (y+cy) + (_LeftRadius<<1) , py = ( _y>>1 ) - _LeftRadius + LeftRadius , yy = y + _LeftRadius; + + int cornerIndex = ( (_z&1)<<2 ) | ( (_y&1)<<1 ); + for( int x=-(int)_LeftRadius ; x<=(int)_RightRadius ; x++ ) + { + int _x = (x+cx) + (_LeftRadius<<1) , px = ( _x>>1 ) - _LeftRadius + LeftRadius , xx = x + _LeftRadius; + if( pNeighbors.neighbors[px][py][pz] && pNeighbors.neighbors[px][py][pz]->children ) + neighbors.neighbors[xx][yy][zz] = pNeighbors.neighbors[px][py][pz]->children + ( cornerIndex | (_x&1) ); + else + neighbors.neighbors[xx][yy][zz] = NULL; + } + } + } + } + // Otherwise recurse + else + { + ConstNeighbors< _PLeftRadius + _PRightRadius + 1 > pNeighbors; + getNeighbors< _PLeftRadius , _PRightRadius >( node->parent , pNeighbors ); + + // Get the indices of the child node that would contain the point (and its antipode) + int cx , cy , cz; + Cube::FactorCornerIndex( (int)( node - node->parent->children ) , cx , cy , cz ); + + + // Iterate over the finer neighbors + // Here: + // (x,y,z) give the position of the finer nodes relative to the center, + // (_x,_y,_z) give a positive global position, up to an even offset, and + // (px-LeftRadius,py-LeftRadius,pz-LeftRadius) give the positions of their parents relative to the parent of the center + for( int z=-(int)_LeftRadius ; z<=(int)_RightRadius ; z++ ) + { + int _z = (z+cz) + (_LeftRadius<<1) , pz = ( _z>>1 ) - _LeftRadius + _PLeftRadius , zz = z + _LeftRadius; + for( int y=-(int)_LeftRadius ; y<=(int)_RightRadius ; y++ ) + { + int _y = (y+cy) + (_LeftRadius<<1) , py = ( _y>>1 ) - _LeftRadius + _PLeftRadius , yy = y + _LeftRadius; + + int cornerIndex = ( (_z&1)<<2 ) | ( (_y&1)<<1 ); + for( int x=-(int)_LeftRadius ; x<=(int)_RightRadius ; x++ ) + { + int _x = (x+cx) + (_LeftRadius<<1) , px = ( _x>>1 ) - _LeftRadius + _PLeftRadius , xx = x + _LeftRadius; + + if( pNeighbors.neighbors[px][py][pz] && pNeighbors.neighbors[px][py][pz]->children ) + neighbors.neighbors[xx][yy][zz] = pNeighbors.neighbors[px][py][pz]->children + ( cornerIndex | (_x&1) ); + else + neighbors.neighbors[xx][yy][zz] = NULL; + } + } + } + } + return; +} + +template< class NodeData > +int OctNode< NodeData >::write(const char* fileName) const{ + FILE* fp=fopen(fileName,"wb"); + if(!fp){return 0;} + int ret=write(fp); + fclose(fp); + return ret; +} +template< class NodeData > +int OctNode< NodeData >::write(FILE* fp) const{ + fwrite(this,sizeof(OctNode< NodeData >),1,fp); + if(children){for(int i=0;i +int OctNode< NodeData >::read( const char* fileName , void (*Initializer)( OctNode& ) ) +{ + FILE* fp = fopen( fileName , "rb" ); + if( !fp ) return 0; + int ret = read( fp , Initializer ); + fclose( fp ); + return ret; +} +template< class NodeData > +int OctNode< NodeData >::read( FILE* fp , void (*Initializer)( OctNode& ) ) +{ + fread( this , sizeof( OctNode< NodeData > ) , 1 , fp ); + parent = NULL; + if( children ) + { + children=NULL; + initChildren( Initializer ); + for( int i=0 ; i +int OctNode< NodeData >::width(int maxDepth) const { + int d=depth(); + return 1<<(maxDepth-d); +} +template< class NodeData > +void OctNode< NodeData >::centerIndex(int maxDepth,int index[DIMENSION]) const +{ + int d,o[3]; + depthAndOffset(d,o); + for(int i=0;i +#include "Polynomial.h" +#include "Array.h" + +template< int Degree > +class StartingPolynomial +{ +public: + Polynomial< Degree > p; + double start; + + template< int Degree2 > + StartingPolynomial< Degree+Degree2 > operator * ( const StartingPolynomial< Degree2 >& p ) const; + StartingPolynomial scale( double s ) const; + StartingPolynomial shift( double t ) const; + int operator < ( const StartingPolynomial& sp ) const; + static int Compare( const void* v1 , const void* v2 ); +}; + +template< int Degree > +class PPolynomial +{ +public: + size_t polyCount; + Pointer( StartingPolynomial< Degree > ) polys; + + PPolynomial( void ); + PPolynomial( const PPolynomial& p ); + ~PPolynomial( void ); + + PPolynomial& operator = ( const PPolynomial& p ); + + int size( void ) const; + + void set( size_t size ); + // Note: this method will sort the elements in sps + void set( Pointer( StartingPolynomial ) sps , int count ); + void reset( size_t newSize ); + PPolynomial& compress( double delta=0. ); + + + double operator()( double t ) const; + double integral( double tMin , double tMax ) const; + double Integral( void ) const; + + template< int Degree2 > PPolynomial< Degree >& operator = ( const PPolynomial< Degree2 >& p ); + + PPolynomial operator + ( const PPolynomial& p ) const; + PPolynomial operator - ( const PPolynomial& p ) const; + + template< int Degree2 > PPolynomial< Degree+Degree2 > operator * ( const Polynomial< Degree2 >& p ) const; + template< int Degree2 > PPolynomial< Degree+Degree2 > operator * ( const PPolynomial< Degree2 >& p) const; + + + PPolynomial& operator += ( double s ); + PPolynomial& operator -= ( double s ); + PPolynomial& operator *= ( double s ); + PPolynomial& operator /= ( double s ); + PPolynomial operator + ( double s ) const; + PPolynomial operator - ( double s ) const; + PPolynomial operator * ( double s ) const; + PPolynomial operator / ( double s ) const; + + PPolynomial& addScaled( const PPolynomial& poly , double scale ); + + PPolynomial scale( double s ) const; + PPolynomial shift( double t ) const; + PPolynomial reflect( double r=0. ) const; + + PPolynomial< Degree-1 > derivative(void) const; + PPolynomial< Degree+1 > integral(void) const; + + void getSolutions( double c , std::vector< double >& roots , double EPS , double min=-DBL_MAX , double max=DBL_MAX ) const; + + void printnl( void ) const; + + PPolynomial< Degree+1 > MovingAverage( double radius ) const; + static PPolynomial BSpline( double radius=0.5 ); + + void write( FILE* fp , int samples , double min , double max ) const; +}; +#include "PPolynomial.inl" +#endif // P_POLYNOMIAL_INCLUDED diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/PPolynomial.inl b/src/plugins_unsupported/filter_screened_poisson_xml/Src/PPolynomial.inl new file mode 100644 index 000000000..a78ae580e --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/PPolynomial.inl @@ -0,0 +1,470 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +#include "Factor.h" + +//////////////////////// +// StartingPolynomial // +//////////////////////// +template +template +StartingPolynomial StartingPolynomial::operator * (const StartingPolynomial& p) const{ + StartingPolynomial sp; + if(start>p.start){sp.start=start;} + else{sp.start=p.start;} + sp.p=this->p*p.p; + return sp; +} +template +StartingPolynomial StartingPolynomial::scale( double s ) const +{ + StartingPolynomial q; + q.start = start*s; + q.p = p.scale(s); + return q; +} +template +StartingPolynomial StartingPolynomial::shift(double s) const{ + StartingPolynomial q; + q.start=start+s; + q.p=p.shift(s); + return q; +} + + +template +int StartingPolynomial::operator < (const StartingPolynomial& sp) const{ + if(start +int StartingPolynomial::Compare(const void* v1,const void* v2){ + double d=((StartingPolynomial*)(v1))->start-((StartingPolynomial*)(v2))->start; + if ( d<0 ) return -1; + else if( d>0 ) return 1; + else return 0; +} + +///////////////// +// PPolynomial // +///////////////// +template< int Degree > +PPolynomial< Degree >::PPolynomial( void ) +{ + polyCount = 0; + polys = NullPointer( StartingPolynomial< Degree > ); +} +template< int Degree > +PPolynomial::PPolynomial( const PPolynomial& p ) +{ + polyCount = 0; + polys = NullPointer( StartingPolynomial< Degree > ); + set( p.polyCount ); + memcpy( polys , p.polys , sizeof( StartingPolynomial ) * p.polyCount ); +} + +template< int Degree > +PPolynomial< Degree >::~PPolynomial( void ) +{ + FreePointer( polys ); + polyCount = 0; +} +template< int Degree > +void PPolynomial< Degree >::set( Pointer( StartingPolynomial< Degree > ) sps , int count ) +{ + int c=0; + set( count ); + qsort( sps , count , sizeof( StartingPolynomial< Degree > ) , StartingPolynomial< Degree >::Compare ); + for( int i=0 ; i int PPolynomial< Degree >::size( void ) const{ return int(sizeof(StartingPolynomial)*polyCount); } + +template< int Degree > +void PPolynomial::set( size_t size ) +{ + FreePointer( polys ); + polyCount = size; + if( size ) + { + polys = AllocPointer< StartingPolynomial< Degree > >( size ); + memset( polys , 0 , sizeof( StartingPolynomial< Degree > )*size ); + } +} +template< int Degree > +void PPolynomial::reset( size_t newSize ) +{ + polyCount = newSize; + polys = ReAllocPointer< StartingPolynomial< Degree > >( polys , newSize ); +} +template< int Degree > +PPolynomial< Degree >& PPolynomial< Degree >::compress( double delta ) +{ + int _polyCount = (int)polyCount; + Pointer( StartingPolynomial< Degree > ) _polys = polys; + + polyCount = 1 , polys = NullPointer( StartingPolynomial< Degree > ); + for( int i=1 ; i<_polyCount ; i++ ) if( _polys[i].start-_polys[i-1].start>delta ) polyCount++; + if( polyCount==_polyCount ) polys = _polys; + else + { + polys = AllocPointer< StartingPolynomial< Degree > >( polyCount ); + polys[0] = _polys[0] , polyCount = 0; + for( int i=1 ; i<_polyCount ; i++ ) + { + if( _polys[i].start-_polys[i-1].start>delta ) polys[ ++polyCount ] = _polys[i]; + else polys[ polyCount ].p += _polys[i].p; + } + polyCount++; + FreePointer( _polys ); + } + return *this; +} + +template< int Degree > +PPolynomial& PPolynomial::operator = (const PPolynomial& p){ + set(p.polyCount); + memcpy(polys,p.polys,sizeof(StartingPolynomial)*p.polyCount); + return *this; +} + +template +template +PPolynomial& PPolynomial::operator = (const PPolynomial& p){ + set(p.polyCount); + for(int i=0;i +double PPolynomial::operator ()( double t ) const +{ + double v=0; + for( int i=0 ; ipolys[i].start ; i++ ) v += polys[i].p(t); + return v; +} + +template +double PPolynomial::integral( double tMin , double tMax ) const +{ + int m=1; + double start,end,s,v=0; + start=tMin; + end=tMax; + if(tMin>tMax){ + m=-1; + start=tMax; + end=tMin; + } + for(int i=0;i +double PPolynomial::Integral(void) const{return integral(polys[0].start,polys[polyCount-1].start);} +template +PPolynomial PPolynomial::operator + (const PPolynomial& p) const{ + PPolynomial q; + int i,j; + size_t idx=0; + q.set(polyCount+p.polyCount); + i=j=-1; + + while(idx=int(p.polyCount)-1) {q.polys[idx]= polys[++i];} + else if (i>=int( polyCount)-1) {q.polys[idx]=p.polys[++j];} + else if(polys[i+1].start +PPolynomial PPolynomial::operator - (const PPolynomial& p) const{ + PPolynomial q; + int i,j; + size_t idx=0; + q.set(polyCount+p.polyCount); + i=j=-1; + + while(idx=int(p.polyCount)-1) {q.polys[idx]= polys[++i];} + else if (i>=int( polyCount)-1) {q.polys[idx].start=p.polys[++j].start;q.polys[idx].p=p.polys[j].p*(-1.0);} + else if(polys[i+1].start +PPolynomial& PPolynomial::addScaled(const PPolynomial& p,double scale){ + int i,j; + StartingPolynomial* oldPolys=polys; + size_t idx=0,cnt=0,oldPolyCount=polyCount; + polyCount=0; + polys=NULL; + set(oldPolyCount+p.polyCount); + i=j=-1; + while(cnt=int( p.polyCount)-1) {polys[idx]=oldPolys[++i];} + else if (i>=int(oldPolyCount)-1) {polys[idx].start= p.polys[++j].start;polys[idx].p=p.polys[j].p*scale;} + else if (oldPolys[i+1].start +template +PPolynomial PPolynomial::operator * (const PPolynomial& p) const{ + PPolynomial q; + StartingPolynomial *sp; + int i,j,spCount=int(polyCount*p.polyCount); + + sp=(StartingPolynomial*)malloc(sizeof(StartingPolynomial)*spCount); + for(i=0;i +template +PPolynomial PPolynomial::operator * (const Polynomial& p) const{ + PPolynomial q; + q.set(polyCount); + for(int i=0;i +PPolynomial PPolynomial::scale( double s ) const +{ + PPolynomial q; + q.set( polyCount ); + for( size_t i=0 ; i ) , StartingPolynomial< Degree >::Compare ); + return q; +} +template< int Degree > +PPolynomial< Degree > PPolynomial< Degree >::reflect( double r ) const +{ + PPolynomial q; + q.set( polyCount ); + for( size_t i=0 ; i ) , StartingPolynomial< Degree >::Compare ); + return q; +} +template +PPolynomial PPolynomial::shift( double s ) const +{ + PPolynomial q; + q.set(polyCount); + for(size_t i=0;i +PPolynomial PPolynomial::derivative(void) const{ + PPolynomial q; + q.set(polyCount); + for(size_t i=0;i +PPolynomial PPolynomial::integral(void) const{ + int i; + PPolynomial q; + q.set(polyCount); + for(i=0;i +PPolynomial& PPolynomial::operator += ( double s ) {polys[0].p+=s;} +template +PPolynomial& PPolynomial::operator -= ( double s ) {polys[0].p-=s;} +template +PPolynomial& PPolynomial::operator *= ( double s ) +{ + for(int i=0;i +PPolynomial& PPolynomial::operator /= ( double s ) +{ + for(size_t i=0;i +PPolynomial PPolynomial::operator + ( double s ) const +{ + PPolynomial q=*this; + q+=s; + return q; +} +template +PPolynomial PPolynomial::operator - ( double s ) const +{ + PPolynomial q=*this; + q-=s; + return q; +} +template +PPolynomial PPolynomial::operator * ( double s ) const +{ + PPolynomial q=*this; + q*=s; + return q; +} +template +PPolynomial PPolynomial::operator / ( double s ) const +{ + PPolynomial q=*this; + q/=s; + return q; +} + +template +void PPolynomial::printnl(void) const{ + Polynomial p; + + if(!polyCount){ + Polynomial p; + printf("[-Infinity,Infinity]\n"); + } + else{ + for(size_t i=0;i +PPolynomial< 0 > PPolynomial< 0 >::BSpline( double radius ) +{ + PPolynomial q; + q.set(2); + + q.polys[0].start=-radius; + q.polys[1].start= radius; + + q.polys[0].p.coefficients[0]= 1.0; + q.polys[1].p.coefficients[0]=-1.0; + return q; +} +template< int Degree > +PPolynomial< Degree > PPolynomial::BSpline( double radius ) +{ + return PPolynomial< Degree-1 >::BSpline().MovingAverage( radius ); +} +template +PPolynomial PPolynomial::MovingAverage( double radius ) const +{ + PPolynomial A; + Polynomial p; + Pointer( StartingPolynomial< Degree+1 > ) sps; + sps = AllocPointer< StartingPolynomial< Degree+1 > >( polyCount*2 ); + + + for(int i=0;i +void PPolynomial::getSolutions(double c,std::vector& roots,double EPS,double min,double max) const{ + Polynomial p; + std::vector tempRoots; + + p.setZero(); + for(size_t i=0;imax){break;} + if(ipolys[i].start && (i+1==polyCount || tempRoots[j]<=polys[i+1].start)){ + if(tempRoots[j]>min && tempRoots[j] +void PPolynomial::write(FILE* fp,int samples,double min,double max) const{ + fwrite(&samples,sizeof(int),1,fp); + for(int i=0;i +class PlyVertex +{ +public: + typedef PlyVertex Wrapper; + + const static int ReadComponents=3; + const static int WriteComponents=3; + Point3D< Real > point; + + PlyVertex( void ) { ; } + PlyVertex( Point3D< Real > p ) { point=p; } + PlyVertex operator + ( PlyVertex p ) const { return PlyVertex( point+p.point ); } + PlyVertex operator - ( PlyVertex p ) const { return PlyVertex( point-p.point ); } + template< class _Real > PlyVertex operator * ( _Real s ) const { return PlyVertex( point*s ); } + template< class _Real > PlyVertex operator / ( _Real s ) const { return PlyVertex( point/s ); } + PlyVertex& operator += ( PlyVertex p ) { point += p.point ; return *this; } + PlyVertex& operator -= ( PlyVertex p ) { point -= p.point ; return *this; } + template< class _Real > PlyVertex& operator *= ( _Real s ) { point *= s ; return *this; } + template< class _Real > PlyVertex& operator /= ( _Real s ) { point /= s ; return *this; } +}; + +template< class Real , class _Real > PlyVertex< Real > operator * ( XForm4x4< _Real > xForm , PlyVertex< Real > v ) { return PlyVertex< Real >( xForm * v.point ); } + +template< class Real > +class PlyValueVertex +{ +public: + typedef PlyValueVertex Wrapper; + + const static int ReadComponents=4; + const static int WriteComponents=4; + + Point3D point; + Real value; + + PlyValueVertex( void ) : value( Real(0) ) { ; } + PlyValueVertex( Point3D< Real > p , Real v ) : point(p) , value(v) { ; } + PlyValueVertex operator + ( PlyValueVertex p ) const { return PlyValueVertex( point+p.point , value+p.value ); } + PlyValueVertex operator - ( PlyValueVertex p ) const { return PlyValueVertex( point-p.value , value-p.value ); } + template< class _Real > PlyValueVertex operator * ( _Real s ) const { return PlyValueVertex( point*s , Real(value*s) ); } + template< class _Real > PlyValueVertex operator / ( _Real s ) const { return PlyValueVertex( point/s , Real(value/s) ); } + PlyValueVertex& operator += ( PlyValueVertex p ) { point += p.point , value += p.value ; return *this; } + PlyValueVertex& operator -= ( PlyValueVertex p ) { point -= p.point , value -= p.value ; return *this; } + template< class _Real > PlyValueVertex& operator *= ( _Real s ) { point *= s , value *= Real(s) ; return *this; } + template< class _Real > PlyValueVertex& operator /= ( _Real s ) { point /= s , value /= Real(s) ; return *this; } +}; +template< class Real , class _Real > PlyValueVertex< Real > operator * ( XForm4x4< _Real > xForm , PlyValueVertex< Real > v ) { return PlyValueVertex< Real >( xForm * v.point , v.value ); } + +template< class Real > +class PlyOrientedVertex +{ +public: + typedef PlyOrientedVertex Wrapper; + + const static int ReadComponents=6; + const static int WriteComponents=6; + + Point3D point , normal; + + PlyOrientedVertex( void ) { ; } + PlyOrientedVertex( Point3D< Real > p , Point3D< Real > n ) : point(p) , normal(n) { ; } + PlyOrientedVertex operator + ( PlyOrientedVertex p ) const { return PlyOrientedVertex( point+p.point , normal+p.normal ); } + PlyOrientedVertex operator - ( PlyOrientedVertex p ) const { return PlyOrientedVertex( point-p.value , normal-p.normal ); } + template< class _Real > PlyOrientedVertex operator * ( _Real s ) const { return PlyOrientedVertex( point*s , normal*s ); } + template< class _Real > PlyOrientedVertex operator / ( _Real s ) const { return PlyOrientedVertex( point/s , normal/s ); } + PlyOrientedVertex& operator += ( PlyOrientedVertex p ) { point += p.point , normal += p.normal ; return *this; } + PlyOrientedVertex& operator -= ( PlyOrientedVertex p ) { point -= p.point , normal -= p.normal ; return *this; } + template< class _Real > PlyOrientedVertex& operator *= ( _Real s ) { point *= s , normal *= s ; return *this; } + template< class _Real > PlyOrientedVertex& operator /= ( _Real s ) { point /= s , normal /= s ; return *this; } +}; +template< class Real , class _Real > PlyOrientedVertex< Real > operator * ( XForm4x4< _Real > xForm , PlyOrientedVertex< Real > v ) { return PlyOrientedVertex< Real >( xForm * v.point , xForm.inverse().transpose() * v.normal ); } + +template< class Real > +class PlyColorVertex +{ +public: + struct _PlyColorVertex + { + Point3D< Real > point , color; + _PlyColorVertex( void ) { ; } + _PlyColorVertex( Point3D< Real > p , Point3D< Real > c ) : point(p) , color(c) { ; } + _PlyColorVertex( PlyColorVertex< Real > p ){ point = p.point ; for( int c=0 ; c<3 ; c++ ) color[c] = (Real) p.color[c]; } + operator PlyColorVertex< Real > () + { + PlyColorVertex< Real > p; + p.point = point; + for( int c=0 ; c<3 ; c++ ) p.color[c] = (unsigned char)std::max< int >( 0 , std::min< int >( 255 , (int)( color[c]+0.5 ) ) ); + return p; + } + + _PlyColorVertex operator + ( _PlyColorVertex p ) const { return _PlyColorVertex( point+p.point , color+p.color ); } + _PlyColorVertex operator - ( _PlyColorVertex p ) const { return _PlyColorVertex( point-p.value , color-p.color ); } + template< class _Real > _PlyColorVertex operator * ( _Real s ) const { return _PlyColorVertex( point*s , color*s ); } + template< class _Real > _PlyColorVertex operator / ( _Real s ) const { return _PlyColorVertex( point/s , color/s ); } + _PlyColorVertex& operator += ( _PlyColorVertex p ) { point += p.point , color += p.color ; return *this; } + _PlyColorVertex& operator -= ( _PlyColorVertex p ) { point -= p.point , color -= p.color ; return *this; } + template< class _Real > _PlyColorVertex& operator *= ( _Real s ) { point *= s , color *= s ; return *this; } + template< class _Real > _PlyColorVertex& operator /= ( _Real s ) { point /= s , color /= s ; return *this; } + }; + + typedef _PlyColorVertex Wrapper; + + const static int ReadComponents=9; + const static int WriteComponents=6; + + Point3D< Real > point; + unsigned char color[3]; + + operator Point3D< Real >& (){ return point; } + operator const Point3D< Real >& () const { return point; } + PlyColorVertex( void ) { point.coords[0] = point.coords[1] = point.coords[2] = 0 , color[0] = color[1] = color[2] = 0; } + PlyColorVertex( const Point3D& p ) { point=p; } + PlyColorVertex( const Point3D< Real >& p , const unsigned char c[3] ) { point = p , color[0] = c[0] , color[1] = c[1] , color[2] = c[2]; } +}; +template< class Real , class _Real > PlyColorVertex< Real > operator * ( XForm4x4< _Real > xForm , PlyColorVertex< Real > v ) { return PlyColorVertex< Real >( xForm * v.point , v.color ); } + +template< class Real > +class PlyColorAndValueVertex +{ +public: + struct _PlyColorAndValueVertex + { + Point3D< Real > point , color; + Real value; + _PlyColorAndValueVertex( void ) : value(0) { ; } + _PlyColorAndValueVertex( Point3D< Real > p , Point3D< Real > c , Real v ) : point(p) , color(c) , value(v) { ; } + _PlyColorAndValueVertex( PlyColorAndValueVertex< Real > p ){ point = p.point ; for( int c=0 ; c<3 ; c++ ) color[c] = (Real) p.color[c] ; value = p.value; } + operator PlyColorAndValueVertex< Real > () + { + PlyColorAndValueVertex< Real > p; + p.point = point; + for( int c=0 ; c<3 ; c++ ) p.color[c] = (unsigned char)std::max< int >( 0 , std::min< int >( 255 , (int)( color[c]+0.5 ) ) ); + p.value = value; + return p; + } + + _PlyColorAndValueVertex operator + ( _PlyColorAndValueVertex p ) const { return _PlyColorAndValueVertex( point+p.point , color+p.color , value+p.value ); } + _PlyColorAndValueVertex operator - ( _PlyColorAndValueVertex p ) const { return _PlyColorAndValueVertex( point-p.value , color-p.color , value+p.value ); } + template< class _Real > _PlyColorAndValueVertex operator * ( _Real s ) const { return _PlyColorAndValueVertex( point*s , color*s , value*s ); } + template< class _Real > _PlyColorAndValueVertex operator / ( _Real s ) const { return _PlyColorAndValueVertex( point/s , color/s , value/s ); } + _PlyColorAndValueVertex& operator += ( _PlyColorAndValueVertex p ) { point += p.point , color += p.color , value += p.value ; return *this; } + _PlyColorAndValueVertex& operator -= ( _PlyColorAndValueVertex p ) { point -= p.point , color -= p.color , value -= p.value ; return *this; } + template< class _Real > _PlyColorAndValueVertex& operator *= ( _Real s ) { point *= s , color *= s , value *= (Real)s ; return *this; } + template< class _Real > _PlyColorAndValueVertex& operator /= ( _Real s ) { point /= s , color /= s , value /= (Real)s ; return *this; } + }; + + typedef _PlyColorAndValueVertex Wrapper; + + const static int ReadComponents=10; + const static int WriteComponents=7; + + Point3D< Real > point; + unsigned char color[3]; + Real value; + + operator Point3D< Real >& (){ return point; } + operator const Point3D< Real >& () const { return point; } + PlyColorAndValueVertex( void ) { point.coords[0] = point.coords[1] = point.coords[2] = (Real)0 , color[0] = color[1] = color[2] = 0 , value = (Real)0; } + PlyColorAndValueVertex( const Point3D< Real >& p ) { point=p; } + PlyColorAndValueVertex( const Point3D< Real >& p , const unsigned char c[3] , Real v) { point = p , color[0] = c[0] , color[1] = c[1] , color[2] = c[2] , value = v; } +}; +template< class Real , class _Real > PlyColorAndValueVertex< Real > operator * ( XForm4x4< _Real > xForm , PlyColorAndValueVertex< Real > v ) { return PlyColorAndValueVertex< Real >( xForm * v.point , v.color , v.value ); } + + diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/PointStream.h b/src/plugins_unsupported/filter_screened_poisson_xml/Src/PointStream.h new file mode 100644 index 000000000..bba2d7eb5 --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/PointStream.h @@ -0,0 +1,207 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior writften permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +#ifndef POINT_STREAM_INCLUDED +#define POINT_STREAM_INCLUDED + +// [Bruno Levy 2016]: using a replacement class for +// Ply vertices, so that we +// do not need importing all the Ply I/O code. +// Adapted from Ply.h + +#include "PlyVertexMini.h" + +template< class Real > +class OrientedPointStream +{ +public: + virtual ~OrientedPointStream( void ){} + virtual void reset( void ) = 0; + virtual bool nextPoint( OrientedPoint3D< Real >& p ) = 0; + virtual int nextPoints( OrientedPoint3D< Real >* p , int count ) + { + int c=0; + for( int i=0 ; i& min , Point3D< Real >& max ) + { + bool first = true; + OrientedPoint3D< Real > p; + while( nextPoint( p ) ) + { + for( int i=0 ; i<3 ; i++ ) + { + if( first || p.p[i]max[i] ) max[i] = p.p[i]; + } + first = false; + } + reset(); + } +}; + +template< class Real , class Data > +class OrientedPointStreamWithData : public OrientedPointStream< Real > +{ +public: + virtual ~OrientedPointStreamWithData( void ){} + virtual void reset( void ) = 0; + virtual bool nextPoint( OrientedPoint3D< Real >& p , Data& d ) = 0; + + virtual bool nextPoint( OrientedPoint3D< Real >& p ){ Data d ; return nextPoint( p , d ); } + virtual int nextPoints( OrientedPoint3D< Real >* p , Data* d , int count ) + { + int c=0; + for( int i=0 ; i* p , int count ){ return OrientedPointStream< Real >::nextPoints( p , count ); } +}; + +template< class Real > +class TransformedOrientedPointStream : public OrientedPointStream< Real > +{ + XForm4x4< Real > _xForm; + XForm3x3< Real > _normalXForm; + OrientedPointStream< Real >& _stream; +public: + TransformedOrientedPointStream( XForm4x4< Real > xForm , OrientedPointStream< Real >& stream ) : _xForm(xForm) , _stream(stream) + { + for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) _normalXForm(i,j) = _xForm(i,j); + _normalXForm = _normalXForm.transpose().inverse(); + }; + virtual void reset( void ){ _stream.reset(); } + virtual bool nextPoint( OrientedPoint3D< Real >& p ) + { + bool ret = _stream.nextPoint( p ); + p.p = _xForm * p.p , p.n = _normalXForm * p.n; + return ret; + } +}; + +template< class Real , class Data > +class TransformedOrientedPointStreamWithData : public OrientedPointStreamWithData< Real , Data > +{ + XForm4x4< Real > _xForm; + XForm3x3< Real > _normalXForm; + OrientedPointStreamWithData< Real , Data >& _stream; +public: + TransformedOrientedPointStreamWithData( XForm4x4< Real > xForm , OrientedPointStreamWithData< Real , Data >& stream ) : _xForm(xForm) , _stream(stream) + { + for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) _normalXForm(i,j) = _xForm(i,j); + _normalXForm = _normalXForm.transpose().inverse(); + }; + virtual void reset( void ){ _stream.reset(); } + virtual bool nextPoint( OrientedPoint3D< Real >& p , Data& d ) + { + bool ret = _stream.nextPoint( p , d ); + p.p = _xForm * p.p , p.n = _normalXForm * p.n; + return ret; + } +}; + +template< class Real > +class MemoryOrientedPointStream : public OrientedPointStream< Real > +{ + const OrientedPoint3D< Real >* _points; + size_t _pointCount; + size_t _current; +public: + MemoryOrientedPointStream( size_t pointCount , const OrientedPoint3D< Real >* points ); + ~MemoryOrientedPointStream( void ); + void reset( void ); + bool nextPoint( OrientedPoint3D< Real >& p ); +}; + +template< class Real , class Data > +class MemoryOrientedPointStreamWithData : public OrientedPointStreamWithData< Real , Data > +{ + const std::pair< OrientedPoint3D< Real > , Data >* _points; + size_t _pointCount; + size_t _current; +public: + MemoryOrientedPointStreamWithData( size_t pointCount , const std::pair< OrientedPoint3D< Real > , Data >* points ); + ~MemoryOrientedPointStreamWithData( void ); + void reset( void ); + bool nextPoint( OrientedPoint3D< Real >& p , Data& d ); +}; + +template< class Real > +class ASCIIOrientedPointStream : public OrientedPointStream< Real > +{ + FILE* _fp; +public: + ASCIIOrientedPointStream( const char* fileName ); + ~ASCIIOrientedPointStream( void ); + void reset( void ); + bool nextPoint( OrientedPoint3D< Real >& p ); +}; + +template< class Real , class Data > +class ASCIIOrientedPointStreamWithData : public OrientedPointStreamWithData< Real , Data > +{ + FILE* _fp; + Data (*_readData)( FILE* ); +public: + ASCIIOrientedPointStreamWithData( const char* fileName , Data (*readData)( FILE* ) ); + ~ASCIIOrientedPointStreamWithData( void ); + void reset( void ); + bool nextPoint( OrientedPoint3D< Real >& p , Data& d ); +}; + +template< class Real , class RealOnDisk=Real > +class BinaryOrientedPointStream : public OrientedPointStream< Real > +{ + FILE* _fp; + static const int POINT_BUFFER_SIZE=1024; + OrientedPoint3D< RealOnDisk > _pointBuffer[ POINT_BUFFER_SIZE ]; + int _pointsInBuffer , _currentPointIndex; +public: + BinaryOrientedPointStream( const char* filename ); + ~BinaryOrientedPointStream( void ); + void reset( void ); + bool nextPoint( OrientedPoint3D< Real >& p ); +}; + +template< class Real , class Data , class RealOnDisk=Real , class DataOnDisk=Data > +class BinaryOrientedPointStreamWithData : public OrientedPointStreamWithData< Real , Data > +{ + FILE* _fp; + static const int POINT_BUFFER_SIZE=1024; + std::pair< OrientedPoint3D< RealOnDisk > , DataOnDisk > _pointBuffer[ POINT_BUFFER_SIZE ]; + int _pointsInBuffer , _currentPointIndex; +public: + BinaryOrientedPointStreamWithData( const char* filename ); + ~BinaryOrientedPointStreamWithData( void ); + void reset( void ); + bool nextPoint( OrientedPoint3D< Real >& p , Data& d ); +}; + +#include "PointStream.inl" +#endif // POINT_STREAM_INCLUDED diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/PointStream.inl b/src/plugins_unsupported/filter_screened_poisson_xml/Src/PointStream.inl new file mode 100644 index 000000000..8f98702df --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/PointStream.inl @@ -0,0 +1,201 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + + +/////////////////////////////// +// MemoryOrientedPointStream // +/////////////////////////////// +template< class Real > +MemoryOrientedPointStream< Real >::MemoryOrientedPointStream( size_t pointCount , const OrientedPoint3D< Real >* points ){ _points = points , _pointCount = pointCount , _current = 0; } +template< class Real > +MemoryOrientedPointStream< Real >::~MemoryOrientedPointStream( void ){ ; } +template< class Real > +void MemoryOrientedPointStream< Real >::reset( void ) { _current=0; } +template< class Real > +bool MemoryOrientedPointStream< Real >::nextPoint( OrientedPoint3D< Real >& p ) +{ + if( _current>=_pointCount ) return false; + p = _points[_current]; + _current++; + return true; +} + +////////////////////////////// +// ASCIIOrientedPointStream // +////////////////////////////// +template< class Real > +ASCIIOrientedPointStream< Real >::ASCIIOrientedPointStream( const char* fileName ) +{ + _fp = fopen( fileName , "r" ); + if( !_fp ) fprintf( stderr , "Failed to open file for reading: %s\n" , fileName ) , exit( 0 ); +} +template< class Real > +ASCIIOrientedPointStream< Real >::~ASCIIOrientedPointStream( void ) +{ + fclose( _fp ); + _fp = NULL; +} +template< class Real > +void ASCIIOrientedPointStream< Real >::reset( void ) { fseek( _fp , SEEK_SET , 0 ); } +template< class Real > +bool ASCIIOrientedPointStream< Real >::nextPoint( OrientedPoint3D< Real >& p ) +{ + float c[2*3]; + if( fscanf( _fp , " %f %f %f %f %f %f " , &c[0] , &c[1] , &c[2] , &c[3] , &c[4] , &c[5] )!=2*3 ) return false; + p.p[0] = c[0] , p.p[1] = c[1] , p.p[2] = c[2]; + p.n[0] = c[3] , p.n[1] = c[4] , p.n[2] = c[5]; + return true; +} + +/////////////////////////////// +// BinaryOrientedPointStream // +/////////////////////////////// +template< class Real , class RealOnDisk > +BinaryOrientedPointStream< Real , RealOnDisk >::BinaryOrientedPointStream( const char* fileName ) +{ + _pointsInBuffer = _currentPointIndex = 0; + _fp = fopen( fileName , "rb" ); + if( !_fp ) fprintf( stderr , "Failed to open file for reading: %s\n" , fileName ) , exit( 0 ); +} +template< class Real , class RealOnDisk > +BinaryOrientedPointStream< Real , RealOnDisk >::~BinaryOrientedPointStream( void ) +{ + fclose( _fp ); + _fp = NULL; +} +template< class Real , class RealOnDisk > +void BinaryOrientedPointStream< Real , RealOnDisk >::reset( void ) +{ + fseek( _fp , SEEK_SET , 0 ); + _pointsInBuffer = _currentPointIndex = 0; +} +template< class Real , class RealOnDisk > +bool BinaryOrientedPointStream< Real , RealOnDisk >::nextPoint( OrientedPoint3D< Real >& p ) +{ + if( _currentPointIndex<_pointsInBuffer ) + { + p = OrientedPoint3D< Real >( _pointBuffer[ _currentPointIndex ] ); + _currentPointIndex++; + return true; + } + else + { + _currentPointIndex = 0; + _pointsInBuffer = int( fread( _pointBuffer , sizeof( OrientedPoint3D< RealOnDisk > ) , POINT_BUFFER_SIZE , _fp ) ); + if( !_pointsInBuffer ) return false; + else return nextPoint( p ); + } +} + +/////////////////////////////////////// +// MemoryOrientedPointStreamWithData // +/////////////////////////////////////// +template< class Real , class Data > +MemoryOrientedPointStreamWithData< Real , Data >::MemoryOrientedPointStreamWithData( size_t pointCount , const std::pair< OrientedPoint3D< Real > , Data >* points ){ _points = points , _pointCount = pointCount , _current = 0; } +template< class Real , class Data > +MemoryOrientedPointStreamWithData< Real , Data >::~MemoryOrientedPointStreamWithData( void ){ ; } +template< class Real , class Data > +void MemoryOrientedPointStreamWithData< Real , Data >::reset( void ) { _current=0; } +template< class Real , class Data > +bool MemoryOrientedPointStreamWithData< Real , Data >::nextPoint( OrientedPoint3D< Real >& p , Data& d ) +{ + if( _current>=_pointCount ) return false; + p = _points[_current].first; + d = _points[_current].second; + _current++; + return true; +} + +////////////////////////////////////// +// ASCIIOrientedPointStreamWithData // +////////////////////////////////////// +template< class Real , class Data > +ASCIIOrientedPointStreamWithData< Real , Data >::ASCIIOrientedPointStreamWithData( const char* fileName , Data (*readData)( FILE* ) ) : _readData( readData ) +{ + _fp = fopen( fileName , "r" ); + if( !_fp ) fprintf( stderr , "Failed to open file for reading: %s\n" , fileName ) , exit( 0 ); +} +template< class Real , class Data > +ASCIIOrientedPointStreamWithData< Real , Data >::~ASCIIOrientedPointStreamWithData( void ) +{ + fclose( _fp ); + _fp = NULL; +} +template< class Real , class Data > +void ASCIIOrientedPointStreamWithData< Real , Data >::reset( void ) { fseek( _fp , SEEK_SET , 0 ); } +template< class Real , class Data > +bool ASCIIOrientedPointStreamWithData< Real , Data >::nextPoint( OrientedPoint3D< Real >& p , Data& d ) +{ + float c[2*3]; + if( fscanf( _fp , " %f %f %f %f %f %f " , &c[0] , &c[1] , &c[2] , &c[3] , &c[4] , &c[5] )!=2*3 ) return false; + p.p[0] = c[0] , p.p[1] = c[1] , p.p[2] = c[2]; + p.n[0] = c[3] , p.n[1] = c[4] , p.n[2] = c[5]; + d = _readData( _fp ); + return true; +} + +/////////////////////////////////////// +// BinaryOrientedPointStreamWithData // +/////////////////////////////////////// +template< class Real , class Data , class RealOnDisk , class DataOnDisk > +BinaryOrientedPointStreamWithData< Real , Data , RealOnDisk , DataOnDisk >::BinaryOrientedPointStreamWithData( const char* fileName ) +{ + _pointsInBuffer = _currentPointIndex = 0; + _fp = fopen( fileName , "rb" ); + if( !_fp ) fprintf( stderr , "Failed to open file for reading: %s\n" , fileName ) , exit( 0 ); +} +template< class Real , class Data , class RealOnDisk , class DataOnDisk > +BinaryOrientedPointStreamWithData< Real , Data , RealOnDisk , DataOnDisk >::~BinaryOrientedPointStreamWithData( void ) +{ + fclose( _fp ); + _fp = NULL; +} +template< class Real , class Data , class RealOnDisk , class DataOnDisk > +void BinaryOrientedPointStreamWithData< Real , Data , RealOnDisk , DataOnDisk >::reset( void ) +{ + fseek( _fp , SEEK_SET , 0 ); + _pointsInBuffer = _currentPointIndex = 0; +} +template< class Real , class Data , class RealOnDisk , class DataOnDisk > +bool BinaryOrientedPointStreamWithData< Real , Data , RealOnDisk , DataOnDisk >::nextPoint( OrientedPoint3D< Real >& p , Data& d ) +{ + if( _currentPointIndex<_pointsInBuffer ) + { + p = OrientedPoint3D< Real >( _pointBuffer[ _currentPointIndex ].first ); + d = Data( _pointBuffer[ _currentPointIndex ].second ); + _currentPointIndex++; + return true; + } + else + { + _currentPointIndex = 0; + _pointsInBuffer = int( fread( _pointBuffer , sizeof( std::pair< OrientedPoint3D< RealOnDisk > , DataOnDisk > ) , POINT_BUFFER_SIZE , _fp ) ); + if( !_pointsInBuffer ) return false; + else return nextPoint( p , d ); + } +} diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/PoissonRecon.cpp b/src/plugins_unsupported/filter_screened_poisson_xml/Src/PoissonRecon.cpp new file mode 100644 index 000000000..033d7b388 --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/PoissonRecon.cpp @@ -0,0 +1,780 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +#undef FAST_COMPILE +#undef ARRAY_DEBUG +#define BRUNO_LEVY_FIX +#define FOR_RELEASE + +#include +#include +#include +#include +#if defined( _WIN32 ) || defined( _WIN64 ) +#include +#include +#endif // _WIN32 || _WIN64 +#include "MyTime.h" +#include "MarchingCubes.h" +#include "Octree.h" +#include "SparseMatrix.h" +#include "CmdLineParser.h" +#include "PPolynomial.h" +#include "Ply.h" +#include "MemoryUsage.h" +#ifdef _OPENMP +#include "omp.h" +#endif // _OPENMP +void DumpOutput( const char* format , ... ); +void DumpOutput2( std::vector< char* >& comments , const char* format , ... ); +#include "MultiGridOctreeData.h" + +#define DEFAULT_FULL_DEPTH 5 + +#define XSTR(x) STR(x) +#define STR(x) #x +#if DEFAULT_FULL_DEPTH +#pragma message ( "[WARNING] Setting default full depth to " XSTR(DEFAULT_FULL_DEPTH) ) +#endif // DEFAULT_FULL_DEPTH + +#include +char* outputFile=NULL; +int echoStdout=0; +void DumpOutput( const char* format , ... ) +{ + if( outputFile ) + { + FILE* fp = fopen( outputFile , "a" ); + va_list args; + va_start( args , format ); + vfprintf( fp , format , args ); + fclose( fp ); + va_end( args ); + } + if( echoStdout ) + { + va_list args; + va_start( args , format ); + vprintf( format , args ); + va_end( args ); + } +} +void DumpOutput2( std::vector< char* >& comments , const char* format , ... ) +{ + if( outputFile ) + { + FILE* fp = fopen( outputFile , "a" ); + va_list args; + va_start( args , format ); + vfprintf( fp , format , args ); + fclose( fp ); + va_end( args ); + } + if( echoStdout ) + { + va_list args; + va_start( args , format ); + vprintf( format , args ); + va_end( args ); + } + comments.push_back( new char[1024] ); + char* str = comments.back(); + va_list args; + va_start( args , format ); + vsprintf( str , format , args ); + va_end( args ); + if( str[strlen(str)-1]=='\n' ) str[strlen(str)-1] = 0; +} + + +cmdLineString + In( "in" ) , + Out( "out" ) , + VoxelGrid( "voxel" ) , + XForm( "xForm" ); + +cmdLineReadable +#if defined( _WIN32 ) || defined( _WIN64 ) + Performance( "performance" ) , +#endif // _WIN32 || _WIN64 + ShowResidual( "showResidual" ) , + NoComments( "noComments" ) , + PolygonMesh( "polygonMesh" ) , + Confidence( "confidence" ) , + NormalWeights( "nWeights" ) , + NonManifold( "nonManifold" ) , + ASCII( "ascii" ) , + Density( "density" ) , + LinearFit( "linearFit" ) , + PrimalVoxel( "primalVoxel" ) , +#ifndef FAST_COMPILE + Double( "double" ) , +#endif // !FAST_COMPILE + Verbose( "verbose" ); + +cmdLineInt +#ifndef FAST_COMPILE + Degree( "degree" , 2 ) , +#endif // !FAST_COMPILE + Depth( "depth" , 8 ) , + CGDepth( "cgDepth" , 0 ) , + KernelDepth( "kernelDepth" ) , + AdaptiveExponent( "adaptiveExp" , 1 ) , + Iters( "iters" , 8 ) , + VoxelDepth( "voxelDepth" , -1 ) , + FullDepth( "fullDepth" , DEFAULT_FULL_DEPTH ) , +#ifndef FAST_COMPILE + BType( "bType" , BOUNDARY_NEUMANN+1 ) , +#endif // !FAST_COMPILE + MaxSolveDepth( "maxSolveDepth" ) , + Threads( "threads" , omp_get_num_procs() ); + +cmdLineFloat + Color( "color" , 16.f ) , + SamplesPerNode( "samplesPerNode" , 1.5f ) , + Scale( "scale" , 1.1f ) , + CGSolverAccuracy( "cgAccuracy" , float(1e-3) ) , + LowResIterMultiplier( "iterMultiplier" , 1.f ) , + PointWeight( "pointWeight" , 4.f ); + + +cmdLineReadable* params[] = +{ +#ifndef FAST_COMPILE + &Degree , &Double , &BType , +#endif // !FAST_COMPILE + &In , &Depth , &Out , &XForm , + &Scale , &Verbose , &CGSolverAccuracy , &NoComments , &LowResIterMultiplier , + &KernelDepth , &SamplesPerNode , &Confidence , &NormalWeights , &NonManifold , &PolygonMesh , &ASCII , &ShowResidual , &VoxelDepth , + &PointWeight , &VoxelGrid , &Threads , &MaxSolveDepth , + &AdaptiveExponent , + &Density , + &FullDepth , + &CGDepth , &Iters , + &Color , + &LinearFit , + &PrimalVoxel , +#if defined( _WIN32 ) || defined( _WIN64 ) + &Performance , +#endif // _WIN32 || _WIN64 +}; + + +void ShowUsage(char* ex) +{ + printf( "Usage: %s\n" , ex ); + printf( "\t --%s \n" , In.name ); + + printf( "\t[--%s ]\n" , Out.name ); + + printf( "\t[--%s ]\n" , VoxelGrid.name ); + +#ifndef FAST_COMPILE + printf( "\t[--%s =%d]\n" , Degree.name , Degree.value ); + + printf( "\t[--%s =%d]\n" , BType.name , BType.value ); + for( int i=0 ; i=%d]\n" , Depth.name , Depth.value ); + + printf( "\t[--%s =%f]\n" , Scale.name , Scale.value ); + + printf( "\t[--%s =%f]\n" , SamplesPerNode.name, SamplesPerNode.value ); + + printf( "\t[--%s =%.3e]\n" , PointWeight.name , PointWeight.value ); + + printf( "\t[--%s]\n" , Confidence.name ); + + printf( "\t[--%s]\n" , NormalWeights.name ); + +#ifndef FOR_RELEASE + printf( "\t[--%s =%d]\n", AdaptiveExponent.name , AdaptiveExponent.value ); +#endif // !FOR_RELEASE + + printf( "\t[--%s =%d]\n" , Iters.name , Iters.value ); + +#ifndef FOR_RELEASE + printf( "\t[--%s =%f]\n" , LowResIterMultiplier.name , LowResIterMultiplier.value ); +#endif // FOR_RELEASE + + printf( "\t[--%s =%d]\n" , CGDepth.name , CGDepth.value ); + +#ifndef FOR_RELEASE + printf( "\t[--%s =%g]\n" , CGSolverAccuracy.name , CGSolverAccuracy.value ); +#endif // !FOR_RELEASE + + printf( "\t[--%s =%d]\n" , FullDepth.name , FullDepth.value ); + + printf( "\t[--%s =<%s>]\n" , VoxelDepth.name , Depth.name ); + + printf( "\t[--%s]\n" , PrimalVoxel.name ); + + printf( "\t[--%s ]\n" , Color.name ); + + printf( "\t[--%s]\n" , Density.name ); + + printf( "\t[--%s]\n" , LinearFit.name ); + + printf( "\t[--%s]\n" , PolygonMesh.name); + +#ifndef FOR_RELEASE + printf( "\t[--%s]\n" , NonManifold.name ); +#endif // !FOR_RELEASE + +#ifdef _OPENMP + printf( "\t[--%s =%d]\n" , Threads.name , Threads.value ); +#endif // _OPENMP + + printf( "\t[--%s]\n" , Verbose.name ); + +#ifndef FOR_RELEASE +#if defined( _WIN32 ) || defined( _WIN64 ) + printf( "\t[--%s]\n" , Performance.name ); +#endif // _WIN32 || _WIN64 +#endif // !FOR_RELEASE + +#ifndef FOR_RELEASE + printf( "\t[--%s]\n" , ASCII.name ); + + printf( "\t[--%s]\n" , NoComments.name ); + +#ifndef FAST_COMPILE + printf( "\t[--%s]\n" , Double.name ); +#endif // FAST_COMPILE +#endif // !FOR_RELEASE +} + +template< class Real > +struct ColorInfo +{ + static Point3D< Real > ReadASCII( FILE* fp ) + { + Point3D< unsigned char > c; + if( fscanf( fp , " %c %c %c " , &c[0] , &c[1] , &c[2] )!=3 ) fprintf( stderr , "[ERROR] Failed to read color\n" ) , exit( 0 ); + return Point3D< Real >( (Real)c[0] , (Real)c[1] , (Real)c[2] ); + }; + static bool ValidPlyProperties( const bool* props ){ return ( props[0] || props[3] ) && ( props[1] || props[4] ) && ( props[2] || props[5] ); } + const static PlyProperty PlyProperties[]; +}; +template<> +const PlyProperty ColorInfo< float >::PlyProperties[] = +{ + { "r" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Point3D< float > , coords[0] ) ) , 0 , 0 , 0 , 0 } , + { "g" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Point3D< float > , coords[1] ) ) , 0 , 0 , 0 , 0 } , + { "b" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Point3D< float > , coords[2] ) ) , 0 , 0 , 0 , 0 } , + { "red" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Point3D< float > , coords[0] ) ) , 0 , 0 , 0 , 0 } , + { "green" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Point3D< float > , coords[1] ) ) , 0 , 0 , 0 , 0 } , + { "blue" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Point3D< float > , coords[2] ) ) , 0 , 0 , 0 , 0 } +}; +template<> +const PlyProperty ColorInfo< double >::PlyProperties[] = +{ + { "r" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Point3D< double > , coords[0] ) ) , 0 , 0 , 0 , 0 } , + { "g" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Point3D< double > , coords[1] ) ) , 0 , 0 , 0 , 0 } , + { "b" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Point3D< double > , coords[2] ) ) , 0 , 0 , 0 , 0 } , + { "red" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Point3D< double > , coords[0] ) ) , 0 , 0 , 0 , 0 } , + { "green" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Point3D< double > , coords[1] ) ) , 0 , 0 , 0 , 0 } , + { "blue" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Point3D< double > , coords[2] ) ) , 0 , 0 , 0 , 0 } +}; + +double Weight( double v , double start , double end ) +{ + v = ( v - start ) / ( end - start ); + if ( v<0 ) return 1.; + else if( v>1 ) return 0.; + else + { + // P(x) = a x^3 + b x^2 + c x + d + // P (0) = 1 , P (1) = 0 , P'(0) = 0 , P'(1) = 0 + // => d = 1 , a + b + c + d = 0 , c = 0 , 3a + 2b + c = 0 + // => c = 0 , d = 1 , a + b = -1 , 3a + 2b = 0 + // => a = 2 , b = -3 , c = 0 , d = 1 + // => P(x) = 2 x^3 - 3 x^2 + 1 + return 2. * v * v * v - 3. * v * v + 1.; + } +} + +#if defined( _WIN32 ) || defined( _WIN64 ) +double PeakMemoryUsageMB( void ) +{ + HANDLE h = GetCurrentProcess(); + PROCESS_MEMORY_COUNTERS pmc; + return GetProcessMemoryInfo( h , &pmc , sizeof(pmc) ) ? ( (double)pmc.PeakWorkingSetSize )/(1<<20) : 0; +} +#endif // _WIN32 || _WIN64 + + +template< class Real > +struct OctreeProfiler +{ + Octree< Real >& tree; + double t; + + OctreeProfiler( Octree< Real >& t ) : tree(t) { ; } + void start( void ){ t = Time() , tree.resetLocalMemoryUsage(); } + void print( const char* header ) const + { + tree.memoryUsage(); +#if defined( _WIN32 ) || defined( _WIN64 ) + if( header ) printf( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); + else printf( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); +#else // !_WIN32 && !_WIN64 + if( header ) printf( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); + else printf( "%9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); +#endif // _WIN32 || _WIN64 + } + void dumpOutput( const char* header ) const + { + tree.memoryUsage(); +#if defined( _WIN32 ) || defined( _WIN64 ) + if( header ) DumpOutput( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); + else DumpOutput( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); +#else // !_WIN32 && !_WIN64 + if( header ) DumpOutput( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); + else DumpOutput( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); +#endif // _WIN32 || _WIN64 + } + void dumpOutput2( std::vector< char* >& comments , const char* header ) const + { + tree.memoryUsage(); +#if defined( _WIN32 ) || defined( _WIN64 ) + if( header ) DumpOutput2( comments , "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); + else DumpOutput2( comments , "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); +#else // !_WIN32 && !_WIN64 + if( header ) DumpOutput2( comments , "%s %9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); + else DumpOutput2( comments , "%9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); +#endif // _WIN32 || _WIN64 + } +}; + +template< class Real > +XForm4x4< Real > GetPointXForm( OrientedPointStream< Real >& stream , Real scaleFactor ) +{ + Point3D< Real > min , max; + stream.boundingBox( min , max ); + Point3D< Real > center = ( max + min ) / 2; + Real scale = std::max< Real >( max[0]-min[0] , std::max< Real >( max[1]-min[1] , max[2]-min[2] ) ); + scale *= scaleFactor; + for( int i=0 ; i<3 ; i++ ) center[i] -= scale/2; + XForm4x4< Real > tXForm = XForm4x4< Real >::Identity() , sXForm = XForm4x4< Real >::Identity(); + for( int i=0 ; i<3 ; i++ ) sXForm(i,i) = (Real)(1./scale ) , tXForm(3,i) = -center[i]; + return sXForm * tXForm; +} + +template< class Real , int Degree , BoundaryType BType , class Vertex > +int _Execute( int argc , char* argv[] ) +{ + typedef typename Octree< Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; + typedef typename Octree< Real >::template InterpolationInfo< false > InterpolationInfo; + typedef OrientedPointStream< Real > PointStream; + typedef OrientedPointStreamWithData< Real , Point3D< Real > > PointStreamWithData; + typedef TransformedOrientedPointStream< Real > XPointStream; + typedef TransformedOrientedPointStreamWithData< Real , Point3D< Real > > XPointStreamWithData; + Reset< Real >(); + int paramNum = sizeof(params)/sizeof(cmdLineReadable*); + std::vector< char* > comments; + + if( Verbose.set ) echoStdout=1; + + XForm4x4< Real > xForm , iXForm; + if( XForm.set ) + { + FILE* fp = fopen( XForm.value , "r" ); + if( !fp ) + { + fprintf( stderr , "[WARNING] Could not read x-form from: %s\n" , XForm.value ); + xForm = XForm4x4< Real >::Identity(); + } + else + { + for( int i=0 ; i<4 ; i++ ) for( int j=0 ; j<4 ; j++ ) + { + float f; + if( fscanf( fp , " %f " , &f )!=1 ) fprintf( stderr , "[ERROR] Execute: Failed to read xform\n" ) , exit( 0 ); + xForm(i,j) = (Real)f; + } + fclose( fp ); + } + } + else xForm = XForm4x4< Real >::Identity(); + + DumpOutput2( comments , "Running Screened Poisson Reconstruction (Version 9.01)\n" ); + char str[1024]; + for( int i=0 ; iset ) + { + params[i]->writeValue( str ); + if( strlen( str ) ) DumpOutput2( comments , "\t--%s %s\n" , params[i]->name , str ); + else DumpOutput2( comments , "\t--%s\n" , params[i]->name ); + } + + double startTime = Time(); + Real isoValue = 0; + + Octree< Real > tree; + OctreeProfiler< Real > profiler( tree ); + tree.threads = Threads.value; + if( !In.set ) + { + ShowUsage( argv[0] ); + return 0; + } + if( !MaxSolveDepth.set ) MaxSolveDepth.value = Depth.value; + + OctNode< TreeNodeData >::SetAllocator( MEMORY_ALLOCATOR_BLOCK_SIZE ); + + int kernelDepth = KernelDepth.set ? KernelDepth.value : Depth.value-2; + if( kernelDepth>Depth.value ) + { + fprintf( stderr,"[WARNING] %s can't be greater than %s: %d <= %d\n" , KernelDepth.name , Depth.name , KernelDepth.value , Depth.value ); + kernelDepth = Depth.value; + } + + int pointCount; + + Real pointWeightSum; + std::vector< typename Octree< Real >::PointSample >* samples = new std::vector< typename Octree< Real >::PointSample >(); + std::vector< ProjectiveData< Point3D< Real > , Real > >* sampleData = NULL; + DensityEstimator* density = NULL; + SparseNodeData< Point3D< Real > , NORMAL_DEGREE >* normalInfo = NULL; + Real targetValue = (Real)0.5; + // Read in the samples (and color data) + { + profiler.start(); + PointStream* pointStream; + char* ext = GetFileExtension( In.value ); + if( Color.set && Color.value>0 ) + { + sampleData = new std::vector< ProjectiveData< Point3D< Real > , Real > >(); + if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryOrientedPointStreamWithData< Real , Point3D< Real > , float , Point3D< unsigned char > >( In.value ); + else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYOrientedPointStreamWithData< Real , Point3D< Real > >( In.value , ColorInfo< Real >::PlyProperties , 6 , ColorInfo< Real >::ValidPlyProperties ); + else pointStream = new ASCIIOrientedPointStreamWithData< Real , Point3D< Real > >( In.value , ColorInfo< Real >::ReadASCII ); + } + else + { + if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryOrientedPointStream< Real , float >( In.value ); + else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYOrientedPointStream< Real >( In.value ); + else pointStream = new ASCIIOrientedPointStream< Real >( In.value ); + } + delete[] ext; + XPointStream _pointStream( xForm , *pointStream ); + xForm = GetPointXForm( _pointStream , (Real)Scale.value ) * xForm; + if( sampleData ) + { + XPointStreamWithData _pointStream( xForm , ( PointStreamWithData& )*pointStream ); + pointCount = tree.template init< Point3D< Real > >( _pointStream , Depth.value , Confidence.set , *samples , sampleData ); + } + else + { + XPointStream _pointStream( xForm , *pointStream ); + pointCount = tree.template init< Point3D< Real > >( _pointStream , Depth.value , Confidence.set , *samples , sampleData ); + } + iXForm = xForm.inverse(); + delete pointStream; +#pragma omp parallel for num_threads( Threads.value ) + for( int i=0 ; i<(int)samples->size() ; i++ ) (*samples)[i].sample.data.n *= (Real)-1; + + DumpOutput( "Input Points / Samples: %d / %d\n" , pointCount , samples->size() ); + profiler.dumpOutput2( comments , "# Read input into tree:" ); + } + DenseNodeData< Real , Degree > solution; + + { + DenseNodeData< Real , Degree > constraints; + InterpolationInfo* iInfo = NULL; + int solveDepth = MaxSolveDepth.value; + + tree.resetNodeIndices(); + + // Get the kernel density estimator [If discarding, compute anew. Otherwise, compute once.] + { + profiler.start(); + density = tree.template setDensityEstimator< WEIGHT_DEGREE >( *samples , kernelDepth , SamplesPerNode.value ); + profiler.dumpOutput2( comments , "# Got kernel density:" ); + } + + // Transform the Hermite samples into a vector field [If discarding, compute anew. Otherwise, compute once.] + { + profiler.start(); + normalInfo = new SparseNodeData< Point3D< Real > , NORMAL_DEGREE >(); + *normalInfo = tree.template setNormalField< NORMAL_DEGREE >( *samples , *density , pointWeightSum , BType==BOUNDARY_NEUMANN ); + profiler.dumpOutput2( comments , "# Got normal field:" ); + } + + if( !Density.set ) delete density , density = NULL; + + // Trim the tree and prepare for multigrid + { + profiler.start(); + std::vector< int > indexMap; + + constexpr int MAX_DEGREE = NORMAL_DEGREE > Degree ? NORMAL_DEGREE : Degree; + tree.template inalizeForBroodedMultigrid< MAX_DEGREE , Degree , BType >( FullDepth.value , typename Octree< Real >::template HasNormalDataFunctor< NORMAL_DEGREE >( *normalInfo ) , &indexMap ); + + if( normalInfo ) normalInfo->remapIndices( indexMap ); + if( density ) density->remapIndices( indexMap ); + profiler.dumpOutput2( comments , "# Finalized tree:" ); + } + + // Add the FEM constraints + { + profiler.start(); + constraints = tree.template initDenseNodeData< Degree >( ); + tree.template addFEMConstraints< Degree , BType , NORMAL_DEGREE , BType >( FEMVFConstraintFunctor< NORMAL_DEGREE , BType , Degree , BType >( 1. , 0. ) , *normalInfo , constraints , solveDepth ); + profiler.dumpOutput2( comments , "# Set FEM constraints:" ); + } + + // Free up the normal info [If we don't need it for subseequent iterations.] + delete normalInfo , normalInfo = NULL; + + // Add the interpolation constraints + if( PointWeight.value>0 ) + { + profiler.start(); + iInfo = new InterpolationInfo( tree , *samples , targetValue , AdaptiveExponent.value , (Real)PointWeight.value * pointWeightSum , (Real)0 ); + tree.template addInterpolationConstraints< Degree , BType >( *iInfo , constraints , solveDepth ); + profiler.dumpOutput2( comments , "#Set point constraints:" ); + } + + DumpOutput( "Leaf Nodes / Active Nodes / Ghost Nodes: %d / %d / %d\n" , (int)tree.leaves() , (int)tree.nodes() , (int)tree.ghostNodes() ); + DumpOutput( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage())/(1<<20) ); + + // Solve the linear system + { + profiler.start(); + typename Octree< Real >::SolverInfo solverInfo; + solverInfo.cgDepth = CGDepth.value , solverInfo.iters = Iters.value , solverInfo.cgAccuracy = CGSolverAccuracy.value , solverInfo.verbose = Verbose.set , solverInfo.showResidual = ShowResidual.set , solverInfo.lowResIterMultiplier = std::max< double >( 1. , LowResIterMultiplier.value ); + solution = tree.template solveSystem< Degree , BType >( FEMSystemFunctor< Degree , BType >( 0 , 1. , 0 ) , iInfo , constraints , solveDepth , solverInfo ); + profiler.dumpOutput2( comments , "# Linear system solved:" ); + if( iInfo ) delete iInfo , iInfo = NULL; + } + } + + CoredFileMeshData< Vertex > mesh; + + { + profiler.start(); + double valueSum = 0 , weightSum = 0; + typename Octree< Real >::template MultiThreadedEvaluator< Degree , BType > evaluator( &tree , solution , Threads.value ); +#pragma omp parallel for num_threads( Threads.value ) reduction( + : valueSum , weightSum ) + for( int j=0 ; jsize() ; j++ ) + { + ProjectiveData< OrientedPoint3D< Real > , Real >& sample = (*samples)[j].sample; + Real w = sample.weight; + if( w>0 ) weightSum += w , valueSum += evaluator.value( sample.data.p / sample.weight , omp_get_thread_num() , (*samples)[j].node ) * w; + } + isoValue = (Real)( valueSum / weightSum ); + if( !( Color.set && Color.value>0 ) && samples ) delete samples , samples = NULL; + profiler.dumpOutput( "Got average:" ); + DumpOutput( "Iso-Value: %e\n" , isoValue ); + } + + if( VoxelGrid.set ) + { + profiler.start(); + FILE* fp = fopen( VoxelGrid.value , "wb" ); + if( !fp ) fprintf( stderr , "Failed to open voxel file for writing: %s\n" , VoxelGrid.value ); + else + { + int res = 0; + Pointer( Real ) values = tree.template voxelEvaluate< Real , Degree , BType >( solution , res , isoValue , VoxelDepth.value , PrimalVoxel.set ); + fwrite( &res , sizeof(int) , 1 , fp ); + if( sizeof(Real)==sizeof(float) ) fwrite( values , sizeof(float) , res*res*res , fp ); + else + { + float *fValues = new float[res*res*res]; + for( int i=0 ; i , Real > , DATA_DEGREE >* colorData = NULL; + if( sampleData ) + { + colorData = new SparseNodeData< ProjectiveData< Point3D< Real > , Real > , DATA_DEGREE >(); + *colorData = tree.template setDataField< DATA_DEGREE , false >( *samples , *sampleData , (DensityEstimator*)NULL ); + delete sampleData , sampleData = NULL; + for( const OctNode< TreeNodeData >* n = tree.tree().nextNode() ; n ; n=tree.tree().nextNode( n ) ) + { + ProjectiveData< Point3D< Real > , Real >* clr = (*colorData)( n ); + if( clr ) (*clr) *= (Real)pow( Color.value , tree.depth( n ) ); + } + } + tree.template getMCIsoSurface< Degree , BType , WEIGHT_DEGREE , DATA_DEGREE >( density , colorData , solution , isoValue , mesh , !LinearFit.set , !NonManifold.set , PolygonMesh.set ); + DumpOutput( "Vertices / Polygons: %d / %d\n" , mesh.outOfCorePointCount()+mesh.inCorePoints.size() , mesh.polygonCount() ); + if( PolygonMesh.set ) profiler.dumpOutput2( comments , "# Got polygons:" ); + else profiler.dumpOutput2( comments , "# Got triangles:" ); + + if( colorData ) delete colorData , colorData = NULL; + + if( NoComments.set ) + { + if( ASCII.set ) PlyWritePolygons( Out.value , &mesh , PLY_ASCII , NULL , 0 , iXForm ); + else PlyWritePolygons( Out.value , &mesh , PLY_BINARY_NATIVE , NULL , 0 , iXForm ); + } + else + { + if( ASCII.set ) PlyWritePolygons( Out.value , &mesh , PLY_ASCII , &comments[0] , (int)comments.size() , iXForm ); + else PlyWritePolygons( Out.value , &mesh , PLY_BINARY_NATIVE , &comments[0] , (int)comments.size() , iXForm ); + } + } + if( density ) delete density , density = NULL; + DumpOutput2( comments , "# Total Solve: %9.1f (s), %9.1f (MB)\n" , Time()-startTime , tree.maxMemoryUsage() ); + + return 1; +} + +#if defined( _WIN32 ) || defined( _WIN64 ) +inline double to_seconds( const FILETIME& ft ) +{ + const double low_to_sec=100e-9; // 100 nanoseconds + const double high_to_sec=low_to_sec*4294967296.0; + return ft.dwLowDateTime*low_to_sec+ft.dwHighDateTime*high_to_sec; +} +#endif // _WIN32 || _WIN64 + +#ifndef FAST_COMPILE +template< class Real , class Vertex > +int Execute( int argc , char* argv[] ) +{ + switch( BType.value ) + { + case BOUNDARY_FREE+1: + { + switch( Degree.value ) + { + case 1: return _Execute< Real , 1 , BOUNDARY_FREE , Vertex >( argc , argv ); + case 2: return _Execute< Real , 2 , BOUNDARY_FREE , Vertex >( argc , argv ); + case 3: return _Execute< Real , 3 , BOUNDARY_FREE , Vertex >( argc , argv ); + case 4: return _Execute< Real , 4 , BOUNDARY_FREE , Vertex >( argc , argv ); + default: fprintf( stderr , "[ERROR] Only B-Splines of degree 1 - 4 are supported" ) ; return EXIT_FAILURE; + } + } + case BOUNDARY_NEUMANN+1: + { + switch( Degree.value ) + { + case 1: return _Execute< Real , 1 , BOUNDARY_NEUMANN , Vertex >( argc , argv ); + case 2: return _Execute< Real , 2 , BOUNDARY_NEUMANN , Vertex >( argc , argv ); + case 3: return _Execute< Real , 3 , BOUNDARY_NEUMANN , Vertex >( argc , argv ); + case 4: return _Execute< Real , 4 , BOUNDARY_NEUMANN , Vertex >( argc , argv ); + default: fprintf( stderr , "[ERROR] Only B-Splines of degree 1 - 4 are supported" ) ; return EXIT_FAILURE; + } + } + case BOUNDARY_DIRICHLET+1: + { + switch( Degree.value ) + { + case 1: return _Execute< Real , 1 , BOUNDARY_DIRICHLET , Vertex >( argc , argv ); + case 2: return _Execute< Real , 2 , BOUNDARY_DIRICHLET , Vertex >( argc , argv ); + case 3: return _Execute< Real , 3 , BOUNDARY_DIRICHLET , Vertex >( argc , argv ); + case 4: return _Execute< Real , 4 , BOUNDARY_DIRICHLET , Vertex >( argc , argv ); + default: fprintf( stderr , "[ERROR] Only B-Splines of degree 1 - 4 are supported" ) ; return EXIT_FAILURE; + } + } + default: fprintf( stderr , "[ERROR] Not a valid boundary type: %d\n" , BType.value ) ; return EXIT_FAILURE; + } +} +#endif // !FAST_COMPILE +int main( int argc , char* argv[] ) +{ +#ifdef ARRAY_DEBUG + fprintf( stderr , "[WARNING] Running in array debugging mode\n" ); +#endif // ARRAY_DEBUG +#if defined( WIN32 ) && defined( MAX_MEMORY_GB ) + if( MAX_MEMORY_GB>0 ) + { + SIZE_T peakMemory = 1; + peakMemory <<= 30; + peakMemory *= MAX_MEMORY_GB; + printf( "Limiting memory usage to %.2f GB\n" , float( peakMemory>>30 ) ); + HANDLE h = CreateJobObject( NULL , NULL ); + AssignProcessToJobObject( h , GetCurrentProcess() ); + + JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 }; + jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_JOB_MEMORY; + jeli.JobMemoryLimit = peakMemory; + if( !SetInformationJobObject( h , JobObjectExtendedLimitInformation , &jeli , sizeof( jeli ) ) ) + fprintf( stderr , "Failed to set memory limit\n" ); + } +#endif // defined( WIN32 ) && defined( MAX_MEMORY_GB ) + double t = Time(); + + cmdLineParse( argc-1 , &argv[1] , sizeof(params)/sizeof(cmdLineReadable*) , params , 1 ); +#ifdef FAST_COMPILE + static const int Degree = 2; + static const BoundaryType BType = BOUNDARY_NEUMANN; + fprintf( stderr , "[WARNING] Compiling for degree-%d, boundary-%s, single-precision _only_\n" , Degree , BoundaryNames[ BType ] ); + if( Density.set ) + if( Color.set && Color.value>0 ) return _Execute< float , Degree , BType , PlyColorAndValueVertex< float > >( argc , argv ); + else return _Execute< float , Degree , BType , PlyValueVertex< float > >( argc , argv ); + else + if( Color.set && Color.value>0 ) return _Execute< float , Degree , BType , PlyColorVertex< float > >( argc , argv ); + else return _Execute< float , Degree , BType , PlyVertex< float > >( argc , argv ); +#else // !FAST_COMPILE + { + if( Density.set ) + if( Color.set && Color.value>0 ) + if( Double.set ) Execute< double , PlyColorAndValueVertex< float > >( argc , argv ); + else Execute< float , PlyColorAndValueVertex< float > >( argc , argv ); + else + if( Double.set ) Execute< double , PlyValueVertex< float > >( argc , argv ); + else Execute< float , PlyValueVertex< float > >( argc , argv ); + else + if( Color.set && Color.value>0 ) + if( Double.set ) Execute< double , PlyColorVertex< float > >( argc , argv ); + else Execute< float , PlyColorVertex< float > >( argc , argv ); + else + if( Double.set ) Execute< double , PlyVertex< float > >( argc , argv ); + else Execute< float , PlyVertex< float > >( argc , argv ); + } +#endif // FAST_COMPILE +#if defined( _WIN32 ) || defined( _WIN64 ) + if( Performance.set ) + { + HANDLE cur_thread=GetCurrentThread(); + FILETIME tcreat, texit, tkernel, tuser; + if( GetThreadTimes( cur_thread , &tcreat , &texit , &tkernel , &tuser ) ) + printf( "Time (Wall/User/Kernel): %.2f / %.2f / %.2f\n" , Time()-t , to_seconds( tuser ) , to_seconds( tkernel ) ); + else printf( "Time: %.2f\n" , Time()-t ); + HANDLE h = GetCurrentProcess(); + PROCESS_MEMORY_COUNTERS pmc; + if( GetProcessMemoryInfo( h , &pmc , sizeof(pmc) ) ) printf( "Peak Memory (MB): %d\n" , (int)( pmc.PeakWorkingSetSize>>20 ) ); + } +#endif // _WIN32 || _WIN64 + return EXIT_SUCCESS; +} diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/Polynomial.h b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Polynomial.h new file mode 100644 index 000000000..397b7bdbb --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Polynomial.h @@ -0,0 +1,100 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +#ifndef POLYNOMIAL_INCLUDED +#define POLYNOMIAL_INCLUDED + +#define NEW_POLYNOMIAL_CODE 1 + +#include + +template< int Degree > +class Polynomial +{ +public: + double coefficients[Degree+1]; + + Polynomial(void); + template + Polynomial(const Polynomial& P); + double operator()( double t ) const; + double integral( double tMin , double tMax ) const; + + int operator == (const Polynomial& p) const; + int operator != (const Polynomial& p) const; + int isZero(void) const; + void setZero(void); + + template + Polynomial& operator = (const Polynomial &p); + Polynomial& operator += (const Polynomial& p); + Polynomial& operator -= (const Polynomial& p); + Polynomial operator - (void) const; + Polynomial operator + (const Polynomial& p) const; + Polynomial operator - (const Polynomial& p) const; + template + Polynomial operator * (const Polynomial& p) const; + + Polynomial& operator += ( double s ); + Polynomial& operator -= ( double s ); + Polynomial& operator *= ( double s ); + Polynomial& operator /= ( double s ); + Polynomial operator + ( double s ) const; + Polynomial operator - ( double s ) const; + Polynomial operator * ( double s ) const; + Polynomial operator / ( double s ) const; + + Polynomial scale( double s ) const; + Polynomial shift( double t ) const; + + Polynomial derivative(void) const; + Polynomial integral(void) const; + + void printnl(void) const; + + Polynomial& addScaled(const Polynomial& p,double scale); + + static void Negate(const Polynomial& in,Polynomial& out); + static void Subtract(const Polynomial& p1,const Polynomial& p2,Polynomial& q); + static void Scale(const Polynomial& p,double w,Polynomial& q); + static void AddScaled(const Polynomial& p1,double w1,const Polynomial& p2,double w2,Polynomial& q); + static void AddScaled(const Polynomial& p1,const Polynomial& p2,double w2,Polynomial& q); + static void AddScaled(const Polynomial& p1,double w1,const Polynomial& p2,Polynomial& q); + + void getSolutions(double c,std::vector& roots,double EPS) const; + int getSolutions( double c , double* roots , double EPS ) const; + + // [NOTE] Both of these methods define the indexing according to DeBoor's algorithm, so that + // Polynomial< Degree >BSplineComponent( 0 )( 1.0 )=0 for all Degree>0. + static Polynomial BSplineComponent( int i ); + static void BSplineComponentValues( double x , double* values ); + static void BinomialCoefficients( int bCoefficients[Degree+1] ); +}; + +#include "Polynomial.inl" +#endif // POLYNOMIAL_INCLUDED diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/Polynomial.inl b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Polynomial.inl new file mode 100644 index 000000000..ea7ae5044 --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Polynomial.inl @@ -0,0 +1,369 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +#include +#include +#include +#include "Factor.h" + +//////////////// +// Polynomial // +//////////////// +template +Polynomial::Polynomial(void){memset(coefficients,0,sizeof(double)*(Degree+1));} +template +template +Polynomial::Polynomial(const Polynomial& P){ + memset(coefficients,0,sizeof(double)*(Degree+1)); + for(int i=0;i<=Degree && i<=Degree2;i++){coefficients[i]=P.coefficients[i];} +} + + +template +template +Polynomial& Polynomial::operator = (const Polynomial &p){ + int d=Degree +Polynomial Polynomial::derivative(void) const{ + Polynomial p; + for(int i=0;i +Polynomial Polynomial::integral(void) const{ + Polynomial p; + p.coefficients[0]=0; + for(int i=0;i<=Degree;i++){p.coefficients[i+1]=coefficients[i]/(i+1);} + return p; +} +template<> double Polynomial< 0 >::operator() ( double t ) const { return coefficients[0]; } +template<> double Polynomial< 1 >::operator() ( double t ) const { return coefficients[0]+coefficients[1]*t; } +template<> double Polynomial< 2 >::operator() ( double t ) const { return coefficients[0]+(coefficients[1]+coefficients[2]*t)*t; } +template +double Polynomial::operator() ( double t ) const{ + double v=coefficients[Degree]; + for( int d=Degree-1 ; d>=0 ; d-- ) v = v*t + coefficients[d]; + return v; +} +template +double Polynomial::integral( double tMin , double tMax ) const +{ + double v=0; + double t1,t2; + t1=tMin; + t2=tMax; + for(int i=0;i<=Degree;i++){ + v+=coefficients[i]*(t2-t1)/(i+1); + if(t1!=-DBL_MAX && t1!=DBL_MAX){t1*=tMin;} + if(t2!=-DBL_MAX && t2!=DBL_MAX){t2*=tMax;} + } + return v; +} +template +int Polynomial::operator == (const Polynomial& p) const{ + for(int i=0;i<=Degree;i++){if(coefficients[i]!=p.coefficients[i]){return 0;}} + return 1; +} +template +int Polynomial::operator != (const Polynomial& p) const{ + for(int i=0;i<=Degree;i++){if(coefficients[i]==p.coefficients[i]){return 0;}} + return 1; +} +template +int Polynomial::isZero(void) const{ + for(int i=0;i<=Degree;i++){if(coefficients[i]!=0){return 0;}} + return 1; +} +template +void Polynomial::setZero(void){memset(coefficients,0,sizeof(double)*(Degree+1));} + +template +Polynomial& Polynomial::addScaled(const Polynomial& p,double s){ + for(int i=0;i<=Degree;i++){coefficients[i]+=p.coefficients[i]*s;} + return *this; +} +template +Polynomial& Polynomial::operator += (const Polynomial& p){ + for(int i=0;i<=Degree;i++){coefficients[i]+=p.coefficients[i];} + return *this; +} +template +Polynomial& Polynomial::operator -= (const Polynomial& p){ + for(int i=0;i<=Degree;i++){coefficients[i]-=p.coefficients[i];} + return *this; +} +template +Polynomial Polynomial::operator + (const Polynomial& p) const{ + Polynomial q; + for(int i=0;i<=Degree;i++){q.coefficients[i]=(coefficients[i]+p.coefficients[i]);} + return q; +} +template +Polynomial Polynomial::operator - (const Polynomial& p) const{ + Polynomial q; + for(int i=0;i<=Degree;i++) {q.coefficients[i]=coefficients[i]-p.coefficients[i];} + return q; +} +template +void Polynomial::Scale(const Polynomial& p,double w,Polynomial& q){ + for(int i=0;i<=Degree;i++){q.coefficients[i]=p.coefficients[i]*w;} +} +template +void Polynomial::AddScaled(const Polynomial& p1,double w1,const Polynomial& p2,double w2,Polynomial& q){ + for(int i=0;i<=Degree;i++){q.coefficients[i]=p1.coefficients[i]*w1+p2.coefficients[i]*w2;} +} +template +void Polynomial::AddScaled(const Polynomial& p1,double w1,const Polynomial& p2,Polynomial& q){ + for(int i=0;i<=Degree;i++){q.coefficients[i]=p1.coefficients[i]*w1+p2.coefficients[i];} +} +template +void Polynomial::AddScaled(const Polynomial& p1,const Polynomial& p2,double w2,Polynomial& q){ + for(int i=0;i<=Degree;i++){q.coefficients[i]=p1.coefficients[i]+p2.coefficients[i]*w2;} +} + +template +void Polynomial::Subtract(const Polynomial &p1,const Polynomial& p2,Polynomial& q){ + for(int i=0;i<=Degree;i++){q.coefficients[i]=p1.coefficients[i]-p2.coefficients[i];} +} +template +void Polynomial::Negate(const Polynomial& in,Polynomial& out){ + out=in; + for(int i=0;i<=Degree;i++){out.coefficients[i]=-out.coefficients[i];} +} + +template +Polynomial Polynomial::operator - (void) const{ + Polynomial q=*this; + for(int i=0;i<=Degree;i++){q.coefficients[i]=-q.coefficients[i];} + return q; +} +template +template +Polynomial Polynomial::operator * (const Polynomial& p) const{ + Polynomial q; + for(int i=0;i<=Degree;i++){for(int j=0;j<=Degree2;j++){q.coefficients[i+j]+=coefficients[i]*p.coefficients[j];}} + return q; +} + +template +Polynomial& Polynomial::operator += ( double s ) +{ + coefficients[0]+=s; + return *this; +} +template +Polynomial& Polynomial::operator -= ( double s ) +{ + coefficients[0]-=s; + return *this; +} +template +Polynomial& Polynomial::operator *= ( double s ) +{ + for(int i=0;i<=Degree;i++){coefficients[i]*=s;} + return *this; +} +template +Polynomial& Polynomial::operator /= ( double s ) +{ + for(int i=0;i<=Degree;i++){coefficients[i]/=s;} + return *this; +} +template +Polynomial Polynomial::operator + ( double s ) const +{ + Polynomial q=*this; + q.coefficients[0]+=s; + return q; +} +template +Polynomial Polynomial::operator - ( double s ) const +{ + Polynomial q=*this; + q.coefficients[0]-=s; + return q; +} +template +Polynomial Polynomial::operator * ( double s ) const +{ + Polynomial q; + for(int i=0;i<=Degree;i++){q.coefficients[i]=coefficients[i]*s;} + return q; +} +template +Polynomial Polynomial::operator / ( double s ) const +{ + Polynomial q; + for( int i=0 ; i<=Degree ; i++ ) q.coefficients[i] = coefficients[i]/s; + return q; +} +template +Polynomial Polynomial::scale( double s ) const +{ + Polynomial q=*this; + double s2=1.0; + for(int i=0;i<=Degree;i++){ + q.coefficients[i]*=s2; + s2/=s; + } + return q; +} +template +Polynomial Polynomial::shift( double t ) const +{ + Polynomial q; + for(int i=0;i<=Degree;i++){ + double temp=1; + for(int j=i;j>=0;j--){ + q.coefficients[j]+=coefficients[i]*temp; + temp*=-t*j; + temp/=(i-j+1); + } + } + return q; +} +template +void Polynomial::printnl(void) const{ + for(int j=0;j<=Degree;j++){ + printf("%6.4f x^%d ",coefficients[j],j); + if(j=0){printf("+");} + } + printf("\n"); +} +template +void Polynomial::getSolutions(double c,std::vector& roots,double EPS) const +{ + double r[4][2]; + int rCount=0; + roots.clear(); + switch(Degree){ + case 1: + rCount=Factor(coefficients[1],coefficients[0]-c,r,EPS); + break; + case 2: + rCount=Factor(coefficients[2],coefficients[1],coefficients[0]-c,r,EPS); + break; + case 3: + rCount=Factor(coefficients[3],coefficients[2],coefficients[1],coefficients[0]-c,r,EPS); + break; +// case 4: +// rCount=Factor(coefficients[4],coefficients[3],coefficients[2],coefficients[1],coefficients[0]-c,r,EPS); +// break; + default: + printf("Can't solve polynomial of degree: %d\n",Degree); + } + for(int i=0;i +int Polynomial::getSolutions( double c , double* roots , double EPS ) const +{ + double _roots[4][2]; + int _rCount=0; + switch( Degree ) + { + case 1: _rCount = Factor( coefficients[1] , coefficients[0]-c , _roots , EPS ) ; break; + case 2: _rCount = Factor( coefficients[2] , coefficients[1] , coefficients[0]-c , _roots , EPS ) ; break; + case 3: _rCount = Factor( coefficients[3] , coefficients[2] , coefficients[1] , coefficients[0]-c , _roots , EPS ) ; break; +// case 4: _rCount = Factor( coefficients[4] , coefficients[3] , coefficients[2] , coefficients[1] , coefficients[0]-c , _roots , EPS ) ; break; + default: printf( "Can't solve polynomial of degree: %d\n" , Degree ); + } + int rCount = 0; + for( int i=0 ; i<_rCount ; i++ ) if( fabs(_roots[i][1])<=EPS ) roots[rCount++] = _roots[i][0]; + return rCount; +} +// The 0-th order B-spline +template< > +Polynomial< 0 > Polynomial< 0 >::BSplineComponent( int i ) +{ + Polynomial p; + p.coefficients[0] = 1.; + return p; +} + +// The Degree-th order B-spline +template< int Degree > +Polynomial< Degree > Polynomial< Degree >::BSplineComponent( int i ) +{ + // B_d^i(x) = \int_x^1 B_{d-1}^{i}(y) dy + \int_0^x B_{d-1}^{i-1} y dy + // = \int_0^1 B_{d-1}^{i}(y) dy - \int_0^x B_{d-1}^{i}(y) dy + \int_0^x B_{d-1}^{i-1} y dy + Polynomial p; + if( i _p = Polynomial< Degree-1 >::BSplineComponent( i ).integral(); + p -= _p; + p.coefficients[0] += _p(1); + } + if( i>0 ) + { + Polynomial< Degree > _p = Polynomial< Degree-1 >::BSplineComponent( i-1 ).integral(); + p += _p; + } + return p; +} + + +// The 0-th order B-spline values +template< > void Polynomial< 0 >::BSplineComponentValues( double x , double* values ){ values[0] = 1.; } +// The Degree-th order B-spline +template< int Degree > void Polynomial< Degree >::BSplineComponentValues( double x , double* values ) +{ + const double Scale = 1./Degree; + Polynomial< Degree-1 >::BSplineComponentValues( x , values+1 ); + values[0] = values[1] * (1.-x) * Scale; + for( int i=1 ; i void Polynomial< 0 >::BinomialCoefficients( int bCoefficients[1] ){ bCoefficients[0] = 1; } +template< int Degree > void Polynomial< Degree >::BinomialCoefficients( int bCoefficients[Degree+1] ) +{ + Polynomial< Degree-1 >::BinomialCoefficients( bCoefficients ); + int leftValue = 0; + for( int i=0 ; i +#include +#include +#include +#if defined( _WIN32 ) || defined( _WIN64 ) +#include +#include +#endif // _WIN32 || _WIN64 +#include "MyTime.h" +#include "MarchingCubes.h" +#include "Octree.h" +#include "SparseMatrix.h" +#include "CmdLineParser.h" +#include "PPolynomial.h" +#include "Ply.h" +#include "MemoryUsage.h" +#ifdef _OPENMP +#include "omp.h" +#endif // _OPENMP +void DumpOutput( const char* format , ... ); +void DumpOutput2( std::vector< char* >& comments , const char* format , ... ); +#include "MultiGridOctreeData.h" + +#define DEFAULT_FULL_DEPTH 5 + +#define XSTR(x) STR(x) +#define STR(x) #x +#if DEFAULT_FULL_DEPTH +#pragma message ( "[WARNING] Setting default full depth to " XSTR(DEFAULT_FULL_DEPTH) ) +#endif // DEFAULT_FULL_DEPTH + +#include +char* outputFile=NULL; +int echoStdout=0; +void DumpOutput( const char* format , ... ) +{ + if( outputFile ) + { + FILE* fp = fopen( outputFile , "a" ); + va_list args; + va_start( args , format ); + vfprintf( fp , format , args ); + fclose( fp ); + va_end( args ); + } + if( echoStdout ) + { + va_list args; + va_start( args , format ); + vprintf( format , args ); + va_end( args ); + } +} +void DumpOutput2( std::vector< char* >& comments , const char* format , ... ) +{ + if( outputFile ) + { + FILE* fp = fopen( outputFile , "a" ); + va_list args; + va_start( args , format ); + vfprintf( fp , format , args ); + fclose( fp ); + va_end( args ); + } + if( echoStdout ) + { + va_list args; + va_start( args , format ); + vprintf( format , args ); + va_end( args ); + } + comments.push_back( new char[1024] ); + char* str = comments.back(); + va_list args; + va_start( args , format ); + vsprintf( str , format , args ); + va_end( args ); + if( str[strlen(str)-1]=='\n' ) str[strlen(str)-1] = 0; +} + + +cmdLineString + In( "in" ) , + Out( "out" ) , + VoxelGrid( "voxel" ) , + XForm( "xForm" ); + +cmdLineReadable +#if defined( _WIN32 ) || defined( _WIN64 ) + Performance( "performance" ) , +#endif // _WIN32 || _WIN64 + ShowResidual( "showResidual" ) , + NoComments( "noComments" ) , + PolygonMesh( "polygonMesh" ) , + Confidence( "confidence" ) , + NormalWeights( "nWeights" ) , + NonManifold( "nonManifold" ) , + ASCII( "ascii" ) , + Density( "density" ) , + NonLinearFit( "nonLinearFit" ) , + PrimalVoxel( "primalVoxel" ) , +#ifndef FAST_COMPILE + FreeBoundary( "freeBoundary" ) , + Double( "double" ) , +#endif // !FAST_COMPILE + Verbose( "verbose" ); + +cmdLineInt +#ifndef FAST_COMPILE + Degree( "degree" , 2 ) , +#endif // !FAST_COMPILE + Depth( "depth" , 8 ) , + CGDepth( "cgDepth" , 0 ) , + KernelDepth( "kernelDepth" ) , + AdaptiveExponent( "adaptiveExp" , 1 ) , + Iters( "iters" , 8 ) , + VoxelDepth( "voxelDepth" , -1 ) , + FullDepth( "fullDepth" , DEFAULT_FULL_DEPTH ) , + MaxSolveDepth( "maxSolveDepth" ) , + Threads( "threads" , omp_get_num_procs() ); + +cmdLineFloat + Color( "color" , 16.f ) , + SamplesPerNode( "samplesPerNode" , 1.5f ) , + Scale( "scale" , 1.1f ) , + CGSolverAccuracy( "cgAccuracy" , 1e-3f ) , + LowResIterMultiplier( "iterMultiplier" , 1.5f ) , + ValueWeight ( "valueWeight" , 4e-0f ) , + GradientWeight( "gradientWeight" , 1e-3f ) , + BiLapWeight ( "biLapWeight" , 1e-5f ); + + +cmdLineReadable* params[] = +{ +#ifndef FAST_COMPILE + &Degree , &Double , &FreeBoundary , +#endif // !FAST_COMPILE + &In , &Depth , &Out , &XForm , + &Scale , &Verbose , &CGSolverAccuracy , &NoComments , &LowResIterMultiplier , + &KernelDepth , &SamplesPerNode , &Confidence , &NormalWeights , &NonManifold , &PolygonMesh , &ASCII , &ShowResidual , &VoxelDepth , + &BiLapWeight , + &ValueWeight , &GradientWeight , &VoxelGrid , &Threads , &MaxSolveDepth , + &AdaptiveExponent , + &Density , + &FullDepth , + &CGDepth , &Iters , + &Color , + &NonLinearFit , + &PrimalVoxel , +#if defined( _WIN32 ) || defined( _WIN64 ) + &Performance , +#endif // _WIN32 || _WIN64 +}; + + +void ShowUsage( char* ex ) +{ + printf( "Usage: %s\n" , ex ); + printf( "\t --%s \n" , In.name ); + + printf( "\t[--%s ]\n" , Out.name ); + + printf( "\t[--%s ]\n" , VoxelGrid.name ); + +#ifndef FAST_COMPILE + printf( "\t[--%s =%d]\n" , Degree.name , Degree.value ); + +#ifndef FOR_RELEASE + printf( "\t[--%s]\n" , FreeBoundary.name ); +#endif // !FOR_RELEASE +#endif // !FAST_COMPILE + + printf( "\t[--%s =%d]\n" , Depth.name , Depth.value ); + + printf( "\t[--%s =%f]\n" , Scale.name , Scale.value ); + + printf( "\t[--%s =%f]\n" , SamplesPerNode.name, SamplesPerNode.value ); + + printf( "\t[--%s =%.3e]\n" , ValueWeight.name , ValueWeight.value ); + + printf( "\t[--%s =%.3e]\n" , GradientWeight.name , GradientWeight.value ); + + printf( "\t[--%s =%.3e]\n" , BiLapWeight.name , BiLapWeight.value ); + + printf( "\t[--%s]\n" , Confidence.name ); + + printf( "\t[--%s]\n" , NormalWeights.name ); + +#ifndef FOR_RELEASE + printf( "\t[--%s =%d]\n", AdaptiveExponent.name , AdaptiveExponent.value ); +#endif // !FOR_RELEASE + + printf( "\t[--%s =%d]\n" , Iters.name , Iters.value ); + +#ifndef FOR_RELEASE + printf( "\t[--%s =%f]\n" , LowResIterMultiplier.name , LowResIterMultiplier.value ); +#endif // FOR_RELEASE + + printf( "\t[--%s =%d]\n" , CGDepth.name , CGDepth.value ); + +#ifndef FOR_RELEASE + printf( "\t[--%s =%g]\n" , CGSolverAccuracy.name , CGSolverAccuracy.value ); +#endif // !FOR_RELEASE + + printf( "\t[--%s =%d]\n" , FullDepth.name , FullDepth.value ); + + printf( "\t[--%s =<%s>]\n" , VoxelDepth.name , Depth.name ); + + printf( "\t[--%s]\n" , PrimalVoxel.name ); + + printf( "\t[--%s ]\n" , Color.name ); + + printf( "\t[--%s]\n" , Density.name ); + + printf( "\t[--%s]\n" , NonLinearFit.name ); + + printf( "\t[--%s]\n" , PolygonMesh.name); + +#ifndef FOR_RELEASE + printf( "\t[--%s]\n" , NonManifold.name ); +#endif // !FOR_RELEASE + +#ifdef _OPENMP + printf( "\t[--%s =%d]\n" , Threads.name , Threads.value ); +#endif // _OPENMP + + printf( "\t[--%s]\n" , Verbose.name ); + +#ifndef FOR_RELEASE +#if defined( _WIN32 ) || defined( _WIN64 ) + printf( "\t[--%s]\n" , Performance.name ); +#endif // _WIN32 || _WIN64 + +#endif // !FOR_RELEASE +#ifndef FOR_RELEASE + printf( "\t[--%s]\n" , ASCII.name ); + + printf( "\t[--%s]\n" , NoComments.name ); +#endif // !FOR_RELEASE + +#ifndef FAST_COMPILE + printf( "\t[--%s]\n" , Double.name ); +#endif // !FAST_COMPILE +} + +template< class Real > +struct ColorInfo +{ + static Point3D< Real > ReadASCII( FILE* fp ) + { + Point3D< unsigned char > c; + if( fscanf( fp , " %c %c %c " , &c[0] , &c[1] , &c[2] )!=3 ) fprintf( stderr , "[ERROR] Failed to read color\n" ) , exit( 0 ); + return Point3D< Real >( (Real)c[0] , (Real)c[1] , (Real)c[2] ); + }; + static bool ValidPlyProperties( const bool* props ){ return ( props[0] || props[3] ) && ( props[1] || props[4] ) && ( props[2] || props[5] ); } + const static PlyProperty PlyProperties[]; +}; +template<> +const PlyProperty ColorInfo< float >::PlyProperties[] = +{ + { "r" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Point3D< float > , coords[0] ) ) , 0 , 0 , 0 , 0 } , + { "g" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Point3D< float > , coords[1] ) ) , 0 , 0 , 0 , 0 } , + { "b" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Point3D< float > , coords[2] ) ) , 0 , 0 , 0 , 0 } , + { "red" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Point3D< float > , coords[0] ) ) , 0 , 0 , 0 , 0 } , + { "green" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Point3D< float > , coords[1] ) ) , 0 , 0 , 0 , 0 } , + { "blue" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Point3D< float > , coords[2] ) ) , 0 , 0 , 0 , 0 } +}; +template<> +const PlyProperty ColorInfo< double >::PlyProperties[] = +{ + { "r" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Point3D< double > , coords[0] ) ) , 0 , 0 , 0 , 0 } , + { "g" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Point3D< double > , coords[1] ) ) , 0 , 0 , 0 , 0 } , + { "b" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Point3D< double > , coords[2] ) ) , 0 , 0 , 0 , 0 } , + { "red" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Point3D< double > , coords[0] ) ) , 0 , 0 , 0 , 0 } , + { "green" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Point3D< double > , coords[1] ) ) , 0 , 0 , 0 , 0 } , + { "blue" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Point3D< double > , coords[2] ) ) , 0 , 0 , 0 , 0 } +}; + +bool ValidPlyColorProperties( const bool* props ){ return ( props[0] || props[3] ) && ( props[1] || props[4] ) && ( props[2] || props[5] ); } + +double Weight( double v , double start , double end ) +{ + v = ( v - start ) / ( end - start ); + if ( v<0 ) return 1.; + else if( v>1 ) return 0.; + else + { + // P(x) = a x^3 + b x^2 + c x + d + // P (0) = 1 , P (1) = 0 , P'(0) = 0 , P'(1) = 0 + // => d = 1 , a + b + c + d = 0 , c = 0 , 3a + 2b + c = 0 + // => c = 0 , d = 1 , a + b = -1 , 3a + 2b = 0 + // => a = 2 , b = -3 , c = 0 , d = 1 + // => P(x) = 2 x^3 - 3 x^2 + 1 + return 2. * v * v * v - 3. * v * v + 1.; + } +} + +#if defined( _WIN32 ) || defined( _WIN64 ) +double PeakMemoryUsageMB( void ) +{ + HANDLE h = GetCurrentProcess(); + PROCESS_MEMORY_COUNTERS pmc; + return GetProcessMemoryInfo( h , &pmc , sizeof(pmc) ) ? ( (double)pmc.PeakWorkingSetSize )/(1<<20) : 0; +} +#endif // _WIN32 || _WIN64 + + +template< class Real > +struct OctreeProfiler +{ + Octree< Real >& tree; + double t; + + OctreeProfiler( Octree< Real >& t ) : tree(t) { ; } + void start( void ){ t = Time() , tree.resetLocalMemoryUsage(); } + void print( const char* header ) const + { + tree.memoryUsage(); +#if defined( _WIN32 ) || defined( _WIN64 ) + if( header ) printf( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); + else printf( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); +#else // !_WIN32 && !_WIN64 + if( header ) printf( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); + else printf( "%9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); +#endif // _WIN32 || _WIN64 + } + void dumpOutput( const char* header ) const + { + tree.memoryUsage(); +#if defined( _WIN32 ) || defined( _WIN64 ) + if( header ) DumpOutput( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); + else DumpOutput( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); +#else // !_WIN32 && !_WIN64 + if( header ) DumpOutput( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); + else DumpOutput( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); +#endif // _WIN32 || _WIN64 + } + void dumpOutput2( std::vector< char* >& comments , const char* header ) const + { + tree.memoryUsage(); +#if defined( _WIN32 ) || defined( _WIN64 ) + if( header ) DumpOutput2( comments , "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); + else DumpOutput2( comments , "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); +#else // !_WIN32 && !_WIN64 + if( header ) DumpOutput2( comments , "%s %9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); + else DumpOutput2( comments , "%9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); +#endif // _WIN32 || _WIN64 + } +}; + +template< class Real > +XForm4x4< Real > GetPointXForm( OrientedPointStream< Real >& stream , Real scaleFactor ) +{ + Point3D< Real > min , max; + stream.boundingBox( min , max ); + Point3D< Real > center = ( max + min ) / 2; + Real scale = std::max< Real >( max[0]-min[0] , std::max< Real >( max[1]-min[1] , max[2]-min[2] ) ); + scale *= scaleFactor; + for( int i=0 ; i<3 ; i++ ) center[i] -= scale/2; + XForm4x4< Real > tXForm = XForm4x4< Real >::Identity() , sXForm = XForm4x4< Real >::Identity(); + for( int i=0 ; i<3 ; i++ ) sXForm(i,i) = (Real)(1./scale ) , tXForm(3,i) = -center[i]; + return sXForm * tXForm; +} + +template< class Real , int Degree , BoundaryType BType , class Vertex > +int _Execute( int argc , char* argv[] ) +{ + typedef typename Octree< Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; + typedef typename Octree< Real >::template InterpolationInfo< true > InterpolationInfo; + typedef OrientedPointStream< Real > PointStream; + typedef OrientedPointStreamWithData< Real , Point3D< Real > > PointStreamWithData; + typedef TransformedOrientedPointStream< Real > XPointStream; + typedef TransformedOrientedPointStreamWithData< Real , Point3D< Real > > XPointStreamWithData; + Reset< Real >(); + int paramNum = sizeof(params)/sizeof(cmdLineReadable*); + std::vector< char* > comments; + + if( Verbose.set ) echoStdout=1; + + XForm4x4< Real > xForm , iXForm; + if( XForm.set ) + { + FILE* fp = fopen( XForm.value , "r" ); + if( !fp ) + { + fprintf( stderr , "[WARNING] Could not read x-form from: %s\n" , XForm.value ); + xForm = XForm4x4< Real >::Identity(); + } + else + { + for( int i=0 ; i<4 ; i++ ) for( int j=0 ; j<4 ; j++ ) + { + float f; + if( fscanf( fp , " %f " , &f )!=1 ) fprintf( stderr , "[ERROR] Execute: Failed to read xform\n" ) , exit( 0 ); + xForm(i,j) = (Real)f; + } + fclose( fp ); + } + } + else xForm = XForm4x4< Real >::Identity(); + + DumpOutput2( comments , "Running SSD Reconstruction (Version 9.01)\n" ); + char str[1024]; + for( int i=0 ; iset ) + { + params[i]->writeValue( str ); + if( strlen( str ) ) DumpOutput2( comments , "\t--%s %s\n" , params[i]->name , str ); + else DumpOutput2( comments , "\t--%s\n" , params[i]->name ); + } + + double startTime = Time(); + Real isoValue = 0; + + Octree< Real > tree; + OctreeProfiler< Real > profiler( tree ); + tree.threads = Threads.value; + if( !In.set ) + { + ShowUsage( argv[0] ); + return 0; + } + if( !MaxSolveDepth.set ) MaxSolveDepth.value = Depth.value; + + OctNode< TreeNodeData >::SetAllocator( MEMORY_ALLOCATOR_BLOCK_SIZE ); + + int kernelDepth = KernelDepth.set ? KernelDepth.value : Depth.value-2; + if( kernelDepth>Depth.value ) + { + fprintf( stderr,"[WARNING] %s can't be greater than %s: %d <= %d\n" , KernelDepth.name , Depth.name , KernelDepth.value , Depth.value ); + kernelDepth = Depth.value; + } + + int pointCount; + + Real pointWeightSum; + std::vector< typename Octree< Real >::PointSample >* samples = new std::vector< typename Octree< Real >::PointSample >(); + std::vector< ProjectiveData< Point3D< Real > , Real > >* sampleData = NULL; + DensityEstimator* density = NULL; + SparseNodeData< Point3D< Real > , NORMAL_DEGREE >* normalInfo = NULL; + Real targetValue = (Real)0.; + + // Read in the samples (and color data) + { + profiler.start(); + PointStream* pointStream; + char* ext = GetFileExtension( In.value ); + if( Color.set && Color.value>0 ) + { + sampleData = new std::vector< ProjectiveData< Point3D< Real > , Real > >(); + if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryOrientedPointStreamWithData< Real , Point3D< Real > , float , Point3D< unsigned char > >( In.value ); + else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYOrientedPointStreamWithData< Real , Point3D< Real > >( In.value , ColorInfo< Real >::PlyProperties , 6 , ColorInfo< Real >::ValidPlyProperties ); + else pointStream = new ASCIIOrientedPointStreamWithData< Real , Point3D< Real > >( In.value , ColorInfo< Real >::ReadASCII ); + } + else + { + if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryOrientedPointStream< Real , float >( In.value ); + else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYOrientedPointStream< Real >( In.value ); + else pointStream = new ASCIIOrientedPointStream< Real >( In.value ); + } + delete[] ext; + XPointStream _pointStream( xForm , *pointStream ); + xForm = GetPointXForm( _pointStream , (Real)Scale.value ) * xForm; + if( sampleData ) + { + XPointStreamWithData _pointStream( xForm , ( PointStreamWithData& )*pointStream ); + pointCount = tree.template init< Point3D< Real > >( _pointStream , Depth.value , Confidence.set , *samples , sampleData ); + } + else + { + XPointStream _pointStream( xForm , *pointStream ); + pointCount = tree.template init< Point3D< Real > >( _pointStream , Depth.value , Confidence.set , *samples , sampleData ); + } + iXForm = xForm.inverse(); + delete pointStream; +#pragma omp parallel for num_threads( Threads.value ) + for( int i=0 ; i<(int)samples->size() ; i++ ) (*samples)[i].sample.data.n *= (Real)-1; + + DumpOutput( "Input Points / Samples: %d / %d\n" , pointCount , samples->size() ); + profiler.dumpOutput2( comments , "# Read input into tree:" ); + } + + DenseNodeData< Real , Degree > solution; + // Solve + { + DenseNodeData< Real , Degree > constraints; + InterpolationInfo* iInfo = NULL; + int solveDepth = MaxSolveDepth.value; + + tree.resetNodeIndices(); + + // Get the kernel density estimator + { + profiler.start(); + density = tree.template setDensityEstimator< WEIGHT_DEGREE >( *samples , kernelDepth , SamplesPerNode.value ); + profiler.dumpOutput2( comments , "# Got kernel density:" ); + } + + // Transform the Hermite samples into a vector field + { + profiler.start(); + normalInfo = new SparseNodeData< Point3D< Real > , NORMAL_DEGREE >(); + *normalInfo = tree.template setNormalField< NORMAL_DEGREE >( *samples , *density , pointWeightSum , BType==BOUNDARY_NEUMANN ); + profiler.dumpOutput2( comments , "# Got normal field:" ); + } + + if( !Density.set ) delete density , density = NULL; + + // Trim the tree and prepare for multigrid + { + profiler.start(); + std::vector< int > indexMap; + + constexpr int MAX_DEGREE = NORMAL_DEGREE > Degree ? NORMAL_DEGREE : Degree; + tree.template inalizeForBroodedMultigrid< MAX_DEGREE , Degree , BType >( FullDepth.value , typename Octree< Real >::template HasNormalDataFunctor< NORMAL_DEGREE >( *normalInfo ) , &indexMap ); + + if( normalInfo ) normalInfo->remapIndices( indexMap ); + if( density ) density->remapIndices( indexMap ); + profiler.dumpOutput2( comments , "# Finalized tree:" ); + } + + // Free up the normal info + if( normalInfo ) delete normalInfo , normalInfo = NULL; + + // Add the interpolation constraints + if( ValueWeight.value>0 || GradientWeight.value>0 ) + { + profiler.start(); + iInfo = new InterpolationInfo( tree , *samples , targetValue , AdaptiveExponent.value , (Real)ValueWeight.value * pointWeightSum , (Real)GradientWeight.value * pointWeightSum ); + constraints = tree.template initDenseNodeData< Degree >( ); + tree.template addInterpolationConstraints< Degree , BType >( *iInfo , constraints , solveDepth ); + profiler.dumpOutput2( comments , "#Set point constraints:" ); + } + + DumpOutput( "Leaf Nodes / Active Nodes / Ghost Nodes: %d / %d / %d\n" , (int)tree.leaves() , (int)tree.nodes() , (int)tree.ghostNodes() ); + DumpOutput( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage())/(1<<20) ); + + // Solve the linear system + { + profiler.start(); + typename Octree< Real >::SolverInfo solverInfo; + solverInfo.cgDepth = CGDepth.value , solverInfo.iters = Iters.value , solverInfo.cgAccuracy = CGSolverAccuracy.value , solverInfo.verbose = Verbose.set , solverInfo.showResidual = ShowResidual.set , solverInfo.lowResIterMultiplier = std::max< double >( 1. , LowResIterMultiplier.value ); + solution = tree.template solveSystem< Degree , BType >( FEMSystemFunctor< Degree , BType >( 0 , 0 , BiLapWeight.value ) , iInfo , constraints , solveDepth , solverInfo ); + profiler.dumpOutput2( comments , "# Linear system solved:" ); + DumpOutput( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage() )/(1<<20) ); + if( iInfo ) delete iInfo , iInfo = NULL; + } + } + + CoredFileMeshData< Vertex > mesh; + + { + profiler.start(); + double valueSum = 0 , weightSum = 0; + typename Octree< Real >::template MultiThreadedEvaluator< Degree , BType > evaluator( &tree , solution , Threads.value ); +#pragma omp parallel for num_threads( Threads.value ) reduction( + : valueSum , weightSum ) + for( int j=0 ; jsize() ; j++ ) + { + ProjectiveData< OrientedPoint3D< Real > , Real >& sample = (*samples)[j].sample; + Real w = sample.weight; + if( w>0 ) weightSum += w , valueSum += evaluator.value( sample.data.p / sample.weight , omp_get_thread_num() , (*samples)[j].node ) * w; + } + isoValue = (Real)( valueSum / weightSum ); + if( !( Color.set && Color.value>0 ) && samples ) delete samples , samples = NULL; + profiler.dumpOutput( "Got average:" ); + DumpOutput( "Iso-Value: %e\n" , isoValue ); + } + + if( VoxelGrid.set ) + { + profiler.start(); + FILE* fp = fopen( VoxelGrid.value , "wb" ); + if( !fp ) fprintf( stderr , "Failed to open voxel file for writing: %s\n" , VoxelGrid.value ); + else + { + int res = 0; + Pointer( Real ) values = tree.template voxelEvaluate< Real , Degree , BType >( solution , res , isoValue , VoxelDepth.value , PrimalVoxel.set ); + fwrite( &res , sizeof(int) , 1 , fp ); + if( sizeof(Real)==sizeof(float) ) fwrite( values , sizeof(float) , res*res*res , fp ); + else + { + float *fValues = new float[res*res*res]; + for( int i=0 ; i , Real > , DATA_DEGREE >* colorData = NULL; + if( sampleData ) + { + colorData = new SparseNodeData< ProjectiveData< Point3D< Real > , Real > , DATA_DEGREE >(); + *colorData = tree.template setDataField< DATA_DEGREE , false >( *samples , *sampleData , (DensityEstimator*)NULL ); + delete sampleData , sampleData = NULL; + for( const OctNode< TreeNodeData >* n = tree.tree().nextNode() ; n ; n=tree.tree().nextNode( n ) ) + { + ProjectiveData< Point3D< Real > , Real >* clr = (*colorData)( n ); + if( clr ) (*clr) *= (Real)pow( Color.value , tree.depth( n ) ); + } + } + tree.template getMCIsoSurface< Degree , BType , WEIGHT_DEGREE , DATA_DEGREE >( density , colorData , solution , isoValue , mesh , NonLinearFit.set , !NonManifold.set , PolygonMesh.set ); + DumpOutput( "Vertices / Polygons: %d / %d\n" , mesh.outOfCorePointCount()+mesh.inCorePoints.size() , mesh.polygonCount() ); + if( PolygonMesh.set ) profiler.dumpOutput2( comments , "# Got polygons:" ); + else profiler.dumpOutput2( comments , "# Got triangles:" ); + + if( colorData ) delete colorData , colorData = NULL; + + if( NoComments.set ) + { + if( ASCII.set ) PlyWritePolygons( Out.value , &mesh , PLY_ASCII , NULL , 0 , iXForm ); + else PlyWritePolygons( Out.value , &mesh , PLY_BINARY_NATIVE , NULL , 0 , iXForm ); + } + else + { + if( ASCII.set ) PlyWritePolygons( Out.value , &mesh , PLY_ASCII , &comments[0] , (int)comments.size() , iXForm ); + else PlyWritePolygons( Out.value , &mesh , PLY_BINARY_NATIVE , &comments[0] , (int)comments.size() , iXForm ); + } + } + if( density ) delete density , density = NULL; + DumpOutput2( comments , "# Total Solve: %9.1f (s), %9.1f (MB)\n" , Time()-startTime , tree.maxMemoryUsage() ); + + return 1; +} + +#if defined( _WIN32 ) || defined( _WIN64 ) +inline double to_seconds( const FILETIME& ft ) +{ + const double low_to_sec=100e-9; // 100 nanoseconds + const double high_to_sec=low_to_sec*4294967296.0; + return ft.dwLowDateTime*low_to_sec+ft.dwHighDateTime*high_to_sec; +} +#endif // _WIN32 || _WIN64 + +#ifndef FAST_COMPILE +template< class Real , class Vertex > +int Execute( int argc , char* argv[] ) +{ + if( FreeBoundary.set ) + switch( Degree.value ) + { + case 2: return _Execute< Real , 2 , BOUNDARY_FREE , Vertex >( argc , argv ); + case 3: return _Execute< Real , 3 , BOUNDARY_FREE , Vertex >( argc , argv ); + case 4: return _Execute< Real , 4 , BOUNDARY_FREE , Vertex >( argc , argv ); + default: fprintf( stderr , "[ERROR] Only B-Splines of degree 2 - 4 are supported" ) ; return EXIT_FAILURE; + } + else + switch( Degree.value ) + { + case 2: return _Execute< Real , 2 , BOUNDARY_NEUMANN , Vertex >( argc , argv ); + case 3: return _Execute< Real , 3 , BOUNDARY_NEUMANN , Vertex >( argc , argv ); + case 4: return _Execute< Real , 4 , BOUNDARY_NEUMANN , Vertex >( argc , argv ); + default: fprintf( stderr , "[ERROR] Only B-Splines of degree 2 - 4 are supported" ) ; return EXIT_FAILURE; + } +} +#endif // !FAST_COMPILE +int main( int argc , char* argv[] ) +{ +#if defined(WIN32) && defined(MAX_MEMORY_GB) + if( MAX_MEMORY_GB>0 ) + { + SIZE_T peakMemory = 1; + peakMemory <<= 30; + peakMemory *= MAX_MEMORY_GB; + printf( "Limiting memory usage to %.2f GB\n" , float( peakMemory>>30 ) ); + HANDLE h = CreateJobObject( NULL , NULL ); + AssignProcessToJobObject( h , GetCurrentProcess() ); + + JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 }; + jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_JOB_MEMORY; + jeli.JobMemoryLimit = peakMemory; + if( !SetInformationJobObject( h , JobObjectExtendedLimitInformation , &jeli , sizeof( jeli ) ) ) + fprintf( stderr , "Failed to set memory limit\n" ); + } +#endif // defined(WIN32) && defined(MAX_MEMORY_GB) + double t = Time(); + + cmdLineParse( argc-1 , &argv[1] , sizeof(params)/sizeof(cmdLineReadable*) , params , 1 ); + if( GradientWeight.value<=0 ) fprintf( stderr , "[ERROR] Gradient weight must be positive: %g>=0\n" , GradientWeight.value ) , exit( 0 ); + if( BiLapWeight.value<=0 ) fprintf( stderr , "[ERROR] Bi-Laplacian weight must be positive: %g>=0\n" , BiLapWeight.value ) , exit( 0 ); +#ifdef FAST_COMPILE + static const int Degree = 2; + static const BoundaryType BType = BOUNDARY_NEUMANN; + fprintf( stderr , "[WARNING] Compiling for degree-%d, boundary-%s, single-precision _only_\n" , Degree , BoundaryNames[ BType ] ); + if( Density.set ) + if( Color.set && Color.value>0 ) _Execute< float , Degree , BType , PlyColorAndValueVertex< float > >( argc , argv ); + else _Execute< float , Degree , BType , PlyValueVertex< float > >( argc , argv ); + else + if( Color.set && Color.value>0 ) _Execute< float , Degree , BType , PlyColorVertex< float > >( argc , argv ); + else _Execute< float , Degree , BType , PlyVertex< float > >( argc , argv ); +#else // !FAST_COMPILE + if( Density.set ) + if( Color.set && Color.value>0 ) + if( Double.set ) Execute< double , PlyColorAndValueVertex< float > >( argc , argv ); + else Execute< float , PlyColorAndValueVertex< float > >( argc , argv ); + else + if( Double.set ) Execute< double , PlyValueVertex< float > >( argc , argv ); + else Execute< float , PlyValueVertex< float > >( argc , argv ); + else + if( Color.set && Color.value>0 ) + if( Double.set ) Execute< double , PlyColorVertex< float > >( argc , argv ); + else Execute< float , PlyColorVertex< float > >( argc , argv ); + else + if( Double.set ) Execute< double , PlyVertex< float > >( argc , argv ); + else Execute< float , PlyVertex< float > >( argc , argv ); +#endif // FAST_COMPILE +#if defined( _WIN32 ) || defined( _WIN64 ) + if( Performance.set ) + { + HANDLE cur_thread=GetCurrentThread(); + FILETIME tcreat, texit, tkernel, tuser; + if( GetThreadTimes( cur_thread , &tcreat , &texit , &tkernel , &tuser ) ) + printf( "Time (Wall/User/Kernel): %.2f / %.2f / %.2f\n" , Time()-t , to_seconds( tuser ) , to_seconds( tkernel ) ); + else printf( "Time: %.2f\n" , Time()-t ); + HANDLE h = GetCurrentProcess(); + PROCESS_MEMORY_COUNTERS pmc; + if( GetProcessMemoryInfo( h , &pmc , sizeof(pmc) ) ) printf( "Peak Memory (MB): %d\n" , (int)(pmc.PeakWorkingSetSize>>20) ); + } +#endif // _WIN32 || _WIN64 + return EXIT_SUCCESS; +} diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/SparseMatrix.h b/src/plugins_unsupported/filter_screened_poisson_xml/Src/SparseMatrix.h new file mode 100644 index 000000000..f133157ff --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/SparseMatrix.h @@ -0,0 +1,194 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +#ifndef __SPARSEMATRIX_HPP +#define __SPARSEMATRIX_HPP + +#define NEW_SPARSE_MATRIX 1 +#define ZERO_TESTING_JACOBI 1 + + +#include "Array.h" + +template +struct MatrixEntry +{ + MatrixEntry( void ) { N =-1; Value = 0; } + MatrixEntry( int i ) { N = i; Value = 0; } + MatrixEntry( int i , T v ) { N = i; Value = v; } + int N; + T Value; +}; + +template class SparseMatrix +{ +private: + bool _contiguous; + int _maxEntriesPerRow; + void _init( void ); +public: + int rows; + Pointer( int ) rowSizes; + Pointer( Pointer( MatrixEntry< T > ) ) m_ppElements; + Pointer( MatrixEntry< T > ) operator[] ( int idx ) { return m_ppElements[idx]; } + ConstPointer( MatrixEntry< T > ) operator[] ( int idx ) const { return m_ppElements[idx]; } + + SparseMatrix( void ); + SparseMatrix( int rows ); + SparseMatrix( int rows , int maxEntriesPerRow ); + void Resize( int rows ); + void Resize( int rows , int maxEntriesPerRow ); + void SetRowSize( int row , int count ); + int Entries( void ) const; + + SparseMatrix( const SparseMatrix& M ); + ~SparseMatrix(); + + void SetZero(); + + SparseMatrix& operator = (const SparseMatrix& M); + + SparseMatrix operator * (const T& V) const; + SparseMatrix& operator *= (const T& V); + + template< class T2 > void Multiply( ConstPointer( T2 ) in , Pointer( T2 ) out , int threads=1 ) const; + template< class T2 > void MultiplyAndAddAverage( ConstPointer( T2 ) in , Pointer( T2 ) out , int threads=1 ) const; + + bool write( FILE* fp ) const; + bool write( const char* fileName ) const; + bool read( FILE* fp ); + bool read( const char* fileName ); + + template< class T2 > void getDiagonal( Pointer( T2 ) diagonal , int threads=1 ) const; + template< class T2 > static int SolveJacobi( const SparseMatrix& M , ConstPointer( T2 ) b , Pointer( T2 ) x , Pointer( T2 ) Mx , T2 sor , int threads=1 ); + template< class T2 > static int SolveJacobi( const SparseMatrix& M , ConstPointer( T2 ) diagonal , ConstPointer( T2 ) b , Pointer( T2 ) x , Pointer( T2 ) Mx , T2 sor , int threads=1 ); + template< class T2 > static int SolveGS( const SparseMatrix& M , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward ); + template< class T2 > static int SolveGS( const SparseMatrix& M , ConstPointer( T2 ) diagonal , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward ); + template< class T2 > static int SolveGS( const std::vector< std::vector< int > >& mcIndices , const SparseMatrix& M , ConstPointer( T2 ) diagonal , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward , int threads=1 ); + template< class T2 > static int SolveGS( const std::vector< std::vector< int > >& mcIndices , const SparseMatrix& M , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward , int threads=1 ); + template< class T2 > static int SolveCG( const SparseMatrix& M , ConstPointer( T2 ) b , int iters , Pointer( T2 ) x , T2 eps=1e-8 , int reset=1 , bool addDCTerm=false , bool solveNormal=false , int threads=1 ); +}; + + +#if !NEW_SPARSE_MATRIX +template< class T2 > +struct MapReduceVector +{ +private: + int _dim; +public: + std::vector< T2* > out; + MapReduceVector( void ) { _dim = 0; } + ~MapReduceVector( void ) + { + if( _dim ) for( int t=0 ; t +class SparseSymmetricMatrix : public SparseMatrix< T > +{ +public: + + template< class T2 > + Vector< T2 > operator * ( const Vector& V ) const; + + template< class T2 > + Vector< T2 > Multiply( const Vector& V ) const; + + template< class T2 > + void Multiply( const Vector& In, Vector& Out , bool addDCTerm=false ) const; + + template< class T2 > + void Multiply( const Vector& In, Vector& Out , MapReduceVector< T2 >& OutScratch , bool addDCTerm=false ) const; + + template< class T2 > + void Multiply( const Vector& In, Vector& Out , std::vector< T2* >& OutScratch , const std::vector< int >& bounds ) const; + + template< class T2 > + static int SolveCG( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , T2 eps=1e-8 , int reset=1 , int threads=0 , bool addDCTerm=false , bool solveNormal=false ); + + template< class T2 > + static int SolveCG( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , MapReduceVector& scratch , T2 eps=1e-8 , int reset=1 , bool addDCTerm=false , bool solveNormal=false ); +#ifdef WIN32 + template< class T2 > + static int SolveCGAtomic( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , T2 eps=1e-8 , int reset=1 , int threads=0 , bool solveNormal=false ); +#endif // WIN32 + template< class T2 > + static int SolveJacobi( const SparseSymmetricMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , MapReduceVector& scratch , Vector& Mx , T2 sor , int reset ); + template< class T2 > + static int SolveJacobi( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , MapReduceVector& scratch , T2 sor=T2(1.) , int reset=1 ); + template< class T2 > + static int SolveJacobi( const SparseSymmetricMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , Vector& Mx , T2 sor , int reset ); + template< class T2 > + static int SolveJacobi( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , T2 sor=T2(1.) , int reset=1 ); + + enum + { + ORDERING_UPPER_TRIANGULAR , + ORDERING_LOWER_TRIANGULAR , + ORDERING_NONE + }; + template< class T2 > + static int SolveGS( const std::vector< std::vector< int > >& mcIndices , const SparseSymmetricMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , MapReduceVector& scratch , Vector& Mx , Vector& dx , bool forward , int reset ); + template< class T2 > + static int SolveGS( const std::vector< std::vector< int > >& mcIndices , const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , MapReduceVector& scratch , bool forward , int reset=1 ); + + template< class T2 > + static int SolveGS( const SparseSymmetricMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , MapReduceVector& scratch , Vector& Mx , Vector& dx , bool forward , int reset , int ordering ); + template< class T2 > + static int SolveGS( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , MapReduceVector& scratch , bool forward , int reset=1 , int ordering=ORDERING_NONE ); + template< class T2 > + static int SolveGS( const SparseSymmetricMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , Vector& Mx , Vector& dx , bool forward , int reset , int ordering ); + template< class T2 > + static int SolveGS( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , bool forward , int reset=1 , int ordering=ORDERING_NONE ); + + template< class T2 > + void getDiagonal( Vector< T2 >& diagonal , int threads=1 ) const; +}; +#endif // !NEW_SPARSE_MATRIX + +#include "SparseMatrix.inl" + +#endif + diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/SparseMatrix.inl b/src/plugins_unsupported/filter_screened_poisson_xml/Src/SparseMatrix.inl new file mode 100644 index 000000000..502f1a2fb --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/SparseMatrix.inl @@ -0,0 +1,504 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +#include +#include + + +/////////////////// +// SparseMatrix // +/////////////////// +/////////////////////////////////////// +// SparseMatrix Methods and Members // +/////////////////////////////////////// + +template< class T > +void SparseMatrix< T >::_init( void ) +{ + _contiguous = false; + _maxEntriesPerRow = 0; + rows = 0; + rowSizes = NullPointer( int ); + m_ppElements = NullPointer( Pointer( MatrixEntry< T > ) ); +} + +template< class T > SparseMatrix< T >::SparseMatrix( void ){ _init(); } + +template< class T > SparseMatrix< T >::SparseMatrix( int rows ){ _init() , Resize( rows ); } +template< class T > SparseMatrix< T >::SparseMatrix( int rows , int maxEntriesPerRow ){ _init() , Resize( rows , maxEntriesPerRow ); } + +template< class T > +SparseMatrix< T >::SparseMatrix( const SparseMatrix& M ) +{ + _init(); + if( M._contiguous ) Resize( M.rows , M._maxEntriesPerRow ); + else Resize( M.rows ); + for( int i=0 ; i ) * rowSizes[i] ); + } +} +template +int SparseMatrix::Entries( void ) const +{ + int e = 0; + for( int i=0 ; i +SparseMatrix& SparseMatrix::operator = (const SparseMatrix& M) +{ + if( M._contiguous ) Resize( M.rows , M._maxEntriesPerRow ); + else Resize( M.rows ); + for( int i=0 ; i ) * rowSizes[i] ); + } + return *this; +} + +template +SparseMatrix::~SparseMatrix( void ){ Resize( 0 ); } + +template< class T > +bool SparseMatrix< T >::write( const char* fileName ) const +{ + FILE* fp = fopen( fileName , "wb" ); + if( !fp ) return false; + bool ret = write( fp ); + fclose( fp ); + return ret; +} +template< class T > +bool SparseMatrix< T >::read( const char* fileName ) +{ + FILE* fp = fopen( fileName , "rb" ); + if( !fp ) return false; + bool ret = read( fp ); + fclose( fp ); + return ret; +} +template< class T > +bool SparseMatrix< T >::write( FILE* fp ) const +{ + if( fwrite( &rows , sizeof( int ) , 1 , fp )!=1 ) return false; + if( fwrite( rowSizes , sizeof( int ) , rows , fp )!=rows ) return false; + for( int i=0 ; i ) , rowSizes[i] , fp )!=rowSizes[i] ) return false; + return true; +} +template< class T > +bool SparseMatrix< T >::read( FILE* fp ) +{ + int r; + if( fread( &r , sizeof( int ) , 1 , fp )!=1 ) return false; + Resize( r ); + if( fread( rowSizes , sizeof( int ) , rows , fp )!=rows ) return false; + for( int i=0 ; i ) , rowSizes[i] , fp )!=rowSizes[i] ) return false; + } + return true; +} + + +template< class T > +void SparseMatrix< T >::Resize( int r ) +{ + if( rows>0 ) + { + if( _contiguous ){ if( _maxEntriesPerRow ) FreePointer( m_ppElements[0] ); } + else for( int i=0 ; i( r ); + m_ppElements = AllocPointer< Pointer( MatrixEntry< T > ) >( r ); + memset( rowSizes , 0 , sizeof( int ) * r ); + } + _contiguous = false; + _maxEntriesPerRow = 0; +} +template< class T > +void SparseMatrix< T >::Resize( int r , int e ) +{ + if( rows>0 ) + { + if( _contiguous ){ if( _maxEntriesPerRow ) FreePointer( m_ppElements[0] ); } + else for( int i=0 ; i( r ); + m_ppElements = AllocPointer< Pointer( MatrixEntry< T > ) >( r ); + m_ppElements[0] = AllocPointer< MatrixEntry< T > >( r * e ); + memset( rowSizes , 0 , sizeof( int ) * r ); + for( int i=1 ; i +void SparseMatrix< T >::SetRowSize( int row , int count ) +{ + if( _contiguous ) + { + if( count>_maxEntriesPerRow ) fprintf( stderr , "[ERROR] Cannot set row size on contiguous matrix: %d<=%d\n" , count , _maxEntriesPerRow ) , exit( 0 ); + rowSizes[row] = count; + } + else if( row>=0 && row0 ) m_ppElements[row] = AllocPointer< MatrixEntry< T > >( count ); + // [WARNING] Why wasn't this line here before??? + rowSizes[row] = count; + } +} + + +template +void SparseMatrix::SetZero() +{ + Resize(this->m_N, this->m_M); +} + +template +SparseMatrix SparseMatrix::operator * (const T& V) const +{ + SparseMatrix M(*this); + M *= V; + return M; +} + +template +SparseMatrix& SparseMatrix::operator *= (const T& V) +{ + for( int i=0 ; i +template< class T2 > +void SparseMatrix< T >::Multiply( ConstPointer( T2 ) in , Pointer( T2 ) out , int threads ) const +{ +#pragma omp parallel for num_threads( threads ) + for( int i=0 ; i ) start = m_ppElements[i]; + ConstPointer( MatrixEntry< T > ) end = start + rowSizes[i]; + ConstPointer( MatrixEntry< T > ) e; + for( e=start ; e!=end ; e++ ) _out += in[ e->N ] * e->Value; + out[i] = _out; + } +} +template< class T > +template< class T2 > +void SparseMatrix< T >::MultiplyAndAddAverage( ConstPointer( T2 ) in , Pointer( T2 ) out , int threads ) const +{ +#if 1 + int count = 0; + T2 average = 0; +#pragma omp parallel for num_threads( threads ) reduction( + : average , count ) + for( int i=0 ; i +template< class T2 > +int SparseMatrix::SolveJacobi( const SparseMatrix& M , ConstPointer( T2 ) diagonal , ConstPointer( T2 ) b , Pointer( T2 ) x , Pointer( T2 ) Mx , T2 sor , int threads ) +{ + M.Multiply( x , Mx , threads ); +#if ZERO_TESTING_JACOBI + for( int j=0 ; j +template< class T2 > +int SparseMatrix::SolveJacobi( const SparseMatrix& M , ConstPointer( T2 ) b , Pointer( T2 ) x , Pointer( T2 ) Mx , T2 sor , int threads ) +{ + M.Multiply( x , Mx , threads ); +#if ZERO_TESTING_JACOBI + for( int j=0 ; j +template +int SparseMatrix::SolveGS( const SparseMatrix& M , ConstPointer( T2 ) diagonal , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward ) +{ +#define ITERATE \ + { \ + ConstPointer( MatrixEntry< T > ) start = M[j]; \ + ConstPointer( MatrixEntry< T > ) end = start + M.rowSizes[j]; \ + ConstPointer( MatrixEntry< T > ) e; \ + T2 _b = b[j]; \ + for( e=start ; e!=end ; e++ ) _b -= x[ e->N ] * e->Value; \ + x[j] += _b / diagonal[j]; \ + } + +#if ZERO_TESTING_JACOBI + if( forward ) for( int j=0 ; j=0 ; j-- ){ if( diagonal[j] ){ ITERATE; } } +#else // !ZERO_TESTING_JACOBI + if( forward ) for( int j=0 ; j=0 ; j-- ){ ITERATE; } +#endif // ZERO_TESTING_JACOBI +#undef ITERATE + return M.rows; +} +template +template +int SparseMatrix::SolveGS( const std::vector< std::vector< int > >& mcIndices , const SparseMatrix& M , ConstPointer( T2 ) diagonal , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward , int threads ) +{ + int sum=0; +#ifdef _WIN32 +#define SetOMPParallel __pragma( omp parallel for num_threads( threads ) ) +#else // !_WIN32 +#define SetOMPParallel _Pragma( "omp parallel for num_threads( threads )" ) +#endif // _WIN32 +#if ZERO_TESTING_JACOBI +#define ITERATE( indices ) \ + { \ +SetOMPParallel \ + for( int k=0 ; k ) start = M[jj]; \ + ConstPointer( MatrixEntry< T > ) end = start + M.rowSizes[jj]; \ + ConstPointer( MatrixEntry< T > ) e; \ + T2 _b = b[jj]; \ + for( e=start ; e!=end ; e++ ) _b -= x[ e->N ] * e->Value; \ + x[jj] += _b / diagonal[jj]; \ + } \ + } +#else // !ZERO_TESTING_JACOBI +#define ITERATE( indices ) \ + { \ +SetOMPParallel \ + for( int k=0 ; k ) start = M[jj]; \ + ConstPointer( MatrixEntry< T > ) end = start + M.rowSizes[jj]; \ + ConstPointer( MatrixEntry< T > ) e; \ + T2 _b = b[jj]; \ + for( e=start ; e!=end ; e++ ) _b -= x[ e->N ] * e->Value; \ + x[jj] += _b / diagonal[jj]; \ + } \ + } +#endif // ZERO_TESTING_JACOBI + if( forward ) for( int j=0 ; j=0 ; j-- ){ sum += int( mcIndices[j].size() ) ; ITERATE( mcIndices[j] ); } +#undef ITERATE +#undef SetOMPParallel + return sum; +} +template +template +int SparseMatrix::SolveGS( const SparseMatrix& M , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward ) +{ + int start = forward ? 0 : M.rows-1 , end = forward ? M.rows : -1 , dir = forward ? 1 : -1; + for( int j=start ; j!=end ; j+=dir ) + { + T diagonal = M[j][0].Value; +#if ZERO_TESTING_JACOBI + if( diagonal ) +#endif // ZERO_TESTING_JACOBI + { + ConstPointer( MatrixEntry< T > ) start = M[j]; + ConstPointer( MatrixEntry< T > ) end = start + M.rowSizes[j]; + ConstPointer( MatrixEntry< T > ) e; + start++; + T2 _b = b[j]; + for( e=start ; e!=end ; e++ ) _b -= x[ e->N ] * e->Value; + x[j] = _b / diagonal; + } + } + return M.rows; +} +template +template +int SparseMatrix::SolveGS( const std::vector< std::vector< int > >& mcIndices , const SparseMatrix& M , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward , int threads ) +{ + int sum=0 , start = forward ? 0 : int( mcIndices.size() )-1 , end = forward ? int( mcIndices.size() ) : -1 , dir = forward ? 1 : -1; + for( int j=start ; j!=end ; j+=dir ) + { + const std::vector< int >& _mcIndices = mcIndices[j]; + sum += int( _mcIndices.size() ); + { +#pragma omp parallel for num_threads( threads ) + for( int k=0 ; k ) start = M[jj]; + ConstPointer( MatrixEntry< T > ) end = start + M.rowSizes[jj]; + ConstPointer( MatrixEntry< T > ) e; + start++; + T2 _b = b[jj]; + for( e=start ; e!=end ; e++ ) _b -= x[ e->N ] * e->Value; + x[jj] = _b / diagonal; + } + } + } + } + return sum; +} + +template< class T > +template< class T2 > +void SparseMatrix< T >::getDiagonal( Pointer( T2 ) diagonal , int threads ) const +{ +#pragma omp parallel for num_threads( threads ) + for( int i=0 ; i ) start = m_ppElements[i]; + ConstPointer( MatrixEntry< T > ) end = start + rowSizes[i]; + ConstPointer( MatrixEntry< T > ) e; + for( e=start ; e!=end ; e++ ) if( e->N==i ) d += e->Value; + diagonal[i] = d; + } +} +template< class T > +template< class T2 > +int SparseMatrix< T >::SolveCG( const SparseMatrix& A , ConstPointer( T2 ) b , int iters , Pointer( T2 ) x , T2 eps , int reset , bool addDCTerm , bool solveNormal , int threads ) +{ + eps *= eps; + int dim = A.rows; + Pointer( T2 ) r = AllocPointer< T2 >( dim ); + Pointer( T2 ) d = AllocPointer< T2 >( dim ); + Pointer( T2 ) q = AllocPointer< T2 >( dim ); + Pointer( T2 ) temp = NullPointer( T2 ); + if( reset ) memset( x , 0 , sizeof(T2)* dim ); + if( solveNormal ) temp = AllocPointer< T2 >( dim ); + + double delta_new = 0 , delta_0; + if( solveNormal ) + { + if( addDCTerm ) A.MultiplyAndAddAverage( ( ConstPointer( T2 ) )x , temp , threads ) , A.MultiplyAndAddAverage( ( ConstPointer( T2 ) )temp , r , threads ) , A.MultiplyAndAddAverage( ( ConstPointer( T2 ) )b , temp , threads ); + else A.Multiply( ( ConstPointer( T2 ) )x , temp , threads ) , A.Multiply( ( ConstPointer( T2 ) )temp , r , threads ) , A.Multiply( ( ConstPointer( T2 ) )b , temp , threads ); +#pragma omp parallel for num_threads( threads ) reduction( + : delta_new ) + for( int i=0 ; ieps*delta_0 ; ii++ ) + { + if( solveNormal ) + if( addDCTerm ) A.MultiplyAndAddAverage( ( ConstPointer( T2 ) )d , temp , threads ) , A.MultiplyAndAddAverage( ( ConstPointer( T2 ) )temp , q , threads ); + else A.Multiply( ( ConstPointer( T2 ) )d , temp , threads ) , A.Multiply( ( ConstPointer( T2 ) )temp , q , threads ); + else + if( addDCTerm ) A.MultiplyAndAddAverage( ( ConstPointer( T2 ) )d , q , threads ); + else A.Multiply( ( ConstPointer( T2 ) )d , q , threads ); + double dDotQ = 0; +#pragma omp parallel for num_threads( threads ) reduction( + : dDotQ ) + for( int i=0 ; i +#include +#include +#ifdef _OPENMP +#include +#endif // _OPENMP +#include +#include "CmdLineParser.h" +#include "Geometry.h" +#include "Ply.h" +#include "MAT.h" +#include "MyTime.h" + +cmdLineString In( "in" ) , Out( "out" ); +cmdLineInt Smooth( "smooth" , 5 ); +cmdLineFloat Trim( "trim" ) , IslandAreaRatio( "aRatio" , 0.001f ); +cmdLineReadable PolygonMesh( "polygonMesh" ); + +cmdLineReadable* params[] = +{ + &In , &Out , &Trim , &PolygonMesh , &Smooth , &IslandAreaRatio +}; + +void ShowUsage( char* ex ) +{ + printf( "Usage: %s\n" , ex ); + printf( "\t --%s \n" , In.name ); + printf( "\t[--%s ]\n" , Trim.name ); + printf( "\t[--%s ]\n" , Out.name ); + printf( "\t[--%s =%d]\n" , Smooth.name , Smooth.value ); + printf( "\t[--%s =%f]\n" , IslandAreaRatio.name , IslandAreaRatio.value ); + printf( "\t[--%s]\n" , PolygonMesh.name ); +} + +long long EdgeKey( int key1 , int key2 ) +{ + if( key1 +Vertex InterpolateVertices( const Vertex& v1 , const Vertex& v2 , Real value ) +{ + typename Vertex::Wrapper _v1(v1) , _v2(v2); + if( _v1.value==_v2.value ) return Vertex( (_v1+_v2)/Real(2.) ); + + Real dx = ( _v1.value-value ) / ( _v1.value-_v2.value ); + return Vertex( _v1*(1.f-dx) + _v2*dx ); +} +template< class Real , class Vertex > +void SmoothValues( std::vector< Vertex >& vertices , const std::vector< std::vector< int > >& polygons ) +{ + std::vector< int > count( vertices.size() ); + std::vector< Real > sums( vertices.size() , 0 ); + for( size_t i=0 ; i +void SplitPolygon + ( + const std::vector< int >& polygon , + std::vector< Vertex >& 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, + Real trimValue + ) +{ + int sz = int( polygon.size() ); + std::vector< bool > gt( sz ); + int gtCount = 0; + for( int j=0 ; jtrimValue ); + if( gt[j] ) gtCount++; + } + if ( gtCount==sz ){ if( gtPolygons ) gtPolygons->push_back( polygon ) ; if( gtFlags ) gtFlags->push_back( false ); } + else if( gtCount==0 ){ if( ltPolygons ) ltPolygons->push_back( polygon ) ; if( ltFlags ) ltFlags->push_back( false ); } + else + { + int start; + for( start=0 ; start poly; + + // Add the initial vertex + { + int j1 = (start+int(sz)-1)%sz , j2 = start; + int v1 = polygon[j1] , v2 = polygon[j2]; + int vIdx; + std::unordered_map< long long, int >::iterator iter = vertexTable.find(EdgeKey(v1, v2)); + if( iter==vertexTable.end() ) + { + vertexTable[ EdgeKey( v1 , v2 ) ] = vIdx = int( vertices.size() ); + vertices.push_back( InterpolateVertices( vertices[v1] , vertices[v2] , trimValue ) ); + } + else vIdx = iter->second; + poly.push_back( vIdx ); + } + + for( int _j=0 ; _j<=sz ; _j++ ) + { + int j1 = (_j+start+sz-1)%sz , j2 = (_j+start)%sz; + int v1 = polygon[j1] , v2 = polygon[j2]; + if( gt[j2]==gtFlag ) poly.push_back( v2 ); + else + { + int vIdx; + std::unordered_map< long long, int >::iterator iter = vertexTable.find(EdgeKey(v1, v2)); + if( iter==vertexTable.end() ) + { + vertexTable[ EdgeKey( v1 , v2 ) ] = vIdx = int( vertices.size() ); + vertices.push_back( InterpolateVertices( vertices[v1] , vertices[v2] , trimValue ) ); + } + else vIdx = iter->second; + poly.push_back( vIdx ); + if( gtFlag ){ if( gtPolygons ) gtPolygons->push_back( poly ) ; if( ltFlags ) ltFlags->push_back( true ); } + else { if( ltPolygons ) ltPolygons->push_back( poly ) ; if( gtFlags ) gtFlags->push_back( true ); } + poly.clear() , poly.push_back( vIdx ) , poly.push_back( v2 ); + gtFlag = !gtFlag; + } + } + } +} +template< class Real , class Vertex > +void Triangulate( const std::vector< Vertex >& vertices , const std::vector< std::vector< int > >& polygons , std::vector< std::vector< int > >& triangles ) +{ + triangles.clear(); + for( size_t i=0 ; i3 ) + { + MinimalAreaTriangulation< Real > mat; + std::vector< Point3D< Real > > _vertices( polygons[i].size() ); + std::vector< TriangleIndex > _triangles; + for( int j=0 ; j +double PolygonArea( const std::vector< Vertex >& vertices , const std::vector< int >& polygon ) +{ + if( polygon.size()<3 ) return 0.; + else if( polygon.size()==3 ) return TriangleArea( vertices[polygon[0]].point , vertices[polygon[1]].point , vertices[polygon[2]].point ); + else + { + Point3D< Real > center; + for( size_t i=0 ; i +void RemoveHangingVertices( std::vector< Vertex >& vertices , std::vector< std::vector< int > >& polygons ) +{ + std::unordered_map< int, int > vMap; + std::vector< bool > vertexFlags( vertices.size() , false ); + for( size_t i=0 ; i _vertices( vCount ); + for( int i=0 ; i >& polygons , std::vector< std::vector< int > >& components ) +{ + std::vector< int > polygonRoots( polygons.size() ); + for( size_t i=0 ; i edgeTable; + for( size_t i=0 ; i::iterator iter = edgeTable.find(eKey); + if( iter==edgeTable.end() ) edgeTable[ eKey ] = int(i); + else + { + int p = iter->second; + while( polygonRoots[p]!=p ) + { + int temp = polygonRoots[p]; + polygonRoots[p] = int(i); + p = temp; + } + polygonRoots[p] = int(i); + } + } + } + for( size_t i=0 ; i vMap; + for( int i= 0 ; i +inline Point3D< Real > CrossProduct( Point3D< Real > p1 , Point3D< Real > p2 ){ return Point3D< Real >( p1[1]*p2[2]-p1[2]*p2[1] , p1[2]*p2[0]-p1[0]*p2[2] , p1[0]*p1[1]-p1[1]*p2[0] ); } +template< class Real > +double TriangleArea( Point3D< Real > v1 , Point3D< Real > v2 , Point3D< Real > v3 ) +{ + Point3D< Real > n = CrossProduct( v2-v1 , v3-v1 ); + return sqrt( n[0]*n[0] + n[1]*n[1] + n[2]*n[2] ) / 2.; +} +template< class Vertex > +int Execute( void ) +{ + float min , max; + int paramNum = sizeof(params)/sizeof(cmdLineReadable*); + std::vector< Vertex > vertices; + std::vector< std::vector< int > > polygons; + + int ft , commentNum = paramNum+2; + char** comments; + PlyReadPolygons( In.value , vertices , polygons , Vertex::ReadProperties , Vertex::ReadComponents , 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 ); + printf( "Value Range: [%f,%f]\n" , min , max ); + + std::unordered_map< long long, int > vertexTable; + std::vector< std::vector< int > > ltPolygons , gtPolygons; + std::vector< bool > ltFlags , gtFlags; + + for( int i=0 ; i0 ) + { + std::vector< std::vector< int > > _ltPolygons , _gtPolygons; + std::vector< std::vector< int > > ltComponents , gtComponents; + SetConnectedComponents( ltPolygons , ltComponents ); + SetConnectedComponents( gtPolygons , gtComponents ); + std::vector< double > ltAreas( ltComponents.size() , 0. ) , gtAreas( gtComponents.size() , 0. ); + std::vector< bool > ltComponentFlags( ltComponents.size() , false ) , gtComponentFlags( gtComponents.size() , false ); + double area = 0.; + for( size_t i=0 ; i( vertices , ltPolygons[ ltComponents[i][j] ] ); + ltComponentFlags[i] = ( ltComponentFlags[i] || ltFlags[ ltComponents[i][j] ] ); + } + area += ltAreas[i]; + } + for( size_t i=0 ; i( vertices , gtPolygons[ gtComponents[i][j] ] ); + gtComponentFlags[i] = ( gtComponentFlags[i] || gtFlags[ gtComponents[i][j] ] ); + } + area += gtAreas[i]; + } + for( size_t i=0 ; i > polys = ltPolygons; + Triangulate< float , Vertex >( vertices , ltPolygons , polys ) , ltPolygons = polys; + } + { + std::vector< std::vector< int > > polys = gtPolygons; + Triangulate< float , Vertex >( vertices , gtPolygons , polys ) , gtPolygons = polys; + } + } + + RemoveHangingVertices( vertices , gtPolygons ); + sprintf( comments[commentNum++] , "#Trimmed In: %9.1f (s)" , Time()-t ); + if( Out.set ) PlyWritePolygons( Out.value , vertices , gtPolygons , Vertex::WriteProperties , Vertex::WriteComponents , ft , comments , commentNum ); + + return EXIT_SUCCESS; +} +int main( int argc , char* argv[] ) +{ + int paramNum = sizeof(params)/sizeof(cmdLineReadable*); + cmdLineParse( argc-1 , &argv[1] , paramNum , params , 0 ); + + if( !In.set || !Trim.set ) + { + ShowUsage( argv[0] ); + return EXIT_FAILURE; + } + bool readFlags[ PlyColorAndValueVertex< float >::ReadComponents ]; + if( !PlyReadHeader( In.value , PlyColorAndValueVertex< float >::ReadProperties , PlyColorAndValueVertex< float >::ReadComponents , readFlags ) ) fprintf( stderr , "[ERROR] Failed to read ply header: %s\n" , In.value ) , exit( 0 ); + + bool hasValue = readFlags[3]; + bool hasColor = ( readFlags[4] || readFlags[7] ) && ( readFlags[5] || readFlags[8] ) && ( readFlags[6] || readFlags[9] ); + + if( !hasValue ) fprintf( stderr , "[ERROR] Ply file does not contain values\n" ) , exit( 0 ); + if( hasColor ) return Execute< PlyColorAndValueVertex< float > >(); + else return Execute< PlyValueVertex< float > >(); +} diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/Time.cpp b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Time.cpp new file mode 100644 index 000000000..b6b6869bc --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Time.cpp @@ -0,0 +1,46 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +#include +#include +#ifndef WIN32 +#include +#endif // WIN32 + +double Time( void ) +{ +#ifdef WIN32 + struct _timeb t; + _ftime( &t ); + return double( t.time ) + double( t.millitm ) / 1000.0; +#else // WIN32 + struct timeval t; + gettimeofday( &t , NULL ); + return t.tv_sec + double( t.tv_usec ) / 1000000; +#endif // WIN32 +} diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/Time.h b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Time.h new file mode 100644 index 000000000..2b3cd59f3 --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Time.h @@ -0,0 +1,32 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +#ifndef TIME_INCLUDED +#define TIME_INCLUDED +double Time(void); +#endif // TIME_INCLUDED diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/Vector.h b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Vector.h new file mode 100644 index 000000000..ea9a6f24c --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Vector.h @@ -0,0 +1,111 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +#ifndef __VECTOR_HPP +#define __VECTOR_HPP + + +//#define Assert assert +#include +#include "Array.h" + +template< class T > +class Vector +{ +public: + Vector( void ); + Vector( const Vector& V ); + Vector( size_t N ); + Vector( size_t N, ConstPointer( T ) pV ); + ~Vector( void ); + + const T& operator () (size_t i) const; + T& operator () (size_t i); + const T& operator [] (size_t i) const; + T& operator [] (size_t i); + + void SetZero(); + + size_t Dimensions() const; + void Resize( size_t N ); + + Vector operator * (const T& A) const; + Vector operator / (const T& A) const; + Vector operator - (const T& A) const; + Vector operator + (const T& A) const; + Vector operator - (const Vector& V) const; + Vector operator + (const Vector& V) const; + + Vector& operator *= ( const T& A ); + Vector& operator /= ( const T& A ); + Vector& operator += ( const T& A ); + Vector& operator -= ( const T& A ); + Vector& operator += ( const Vector& V ); + Vector& operator -= ( const Vector& V ); + + Vector& Add( const Vector* V , int count ); + Vector& AddScaled( const Vector& V , const T& scale ); + Vector& SubtractScaled( const Vector& V , const T& scale ); + static void Add( const Vector& V1 , const T& scale1 , const Vector& V2 , const T& scale2 , Vector& Out ); + static void Add( const Vector& V1 , const T& scale1 , const Vector& V2 , Vector& Out ); + + Vector operator - () const; + + Vector& operator = (const Vector& V); + + T Dot( const Vector& V ) const; + + T Length() const; + + T Average() const; + + T Norm( size_t Ln ) const; + void Normalize(); + + bool write( FILE* fp ) const; + bool write( const char* fileName ) const; + bool read( FILE* fp ); + bool read( const char* fileName ); + + Pointer( T ) m_pV; +protected: + size_t m_N; + +}; + +#if ARRAY_DEBUG +template< class C > Array< C > GetPointer( Vector< C >& v ){ return Array< C >::FromPointer( &v[0] , v.Dimensions() ); } +template< class C > ConstArray< C > GetPointer( const Vector< C >& v ){ return ConstArray< C >::FromPointer( &v[0] , v.Dimensions() ); } +#else // !ARRAY_DEBUG +template< class C > C* GetPointer( Vector< C >& v ){ return &v[0]; } +template< class C > const C* GetPointer( const Vector< C >& v ){ return &v[0]; } +#endif // ARRAY_DEBUG + +#include "Vector.inl" + +#endif diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/Src/Vector.inl b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Vector.inl new file mode 100644 index 000000000..db06a3aa5 --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/Src/Vector.inl @@ -0,0 +1,304 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +#ifndef __VECTORIMPL_HPP +#define __VECTORIMPL_HPP + +#include + +//////////// +// Vector // +//////////// +template +Vector::Vector( void ) +{ + m_N = 0; + m_pV = NullPointer< T >(); +} +template< class T > +Vector< T >::Vector( const Vector& V ) +{ + m_N = 0; + m_pV = NullPointer< T >(); + Resize( V.m_N ); + memcpy( m_pV , V.m_pV , m_N*sizeof(T) ); +} +template +Vector::Vector( size_t N ) +{ + m_N=0; + m_pV = NullPointer< T >(); + Resize(N); +} +template +void Vector::Resize( size_t N ) +{ + if( m_N!=N ) + { + if( m_N ) DeletePointer( m_pV ); + m_N = N; + m_pV = NewPointer< T >( N ); + } + if( N ) memset( m_pV , 0 , N*sizeof(T) ); +} + +template +Vector::Vector( size_t N, ConstPointer( T ) pV ) +{ + Resize(N); + memcpy( m_pV, pV, N*sizeof(T) ); +} +template +Vector::~Vector(){Resize(0);} +template +Vector& Vector::operator = (const Vector& V) +{ + Resize(V.m_N); + memcpy( m_pV, V.m_pV, m_N*sizeof(T) ); + return *this; +} +template +size_t Vector::Dimensions() const{return m_N;} +template +void Vector::SetZero(void){for (size_t i=0; i +const T& Vector::operator () (size_t i) const +{ + return m_pV[i]; +} +template +T& Vector::operator () (size_t i) +{ + return m_pV[i]; +} +template +const T& Vector::operator [] (size_t i) const +{ + return m_pV[i]; +} +template +T& Vector::operator [] (size_t i) +{ + return m_pV[i]; +} +template +Vector Vector::operator * (const T& A) const +{ + Vector V(*this); + for (size_t i=0; i +Vector& Vector::operator *= (const T& A) +{ + for (size_t i=0; i +Vector Vector::operator / (const T& A) const +{ + Vector V(*this); + for (size_t i=0; i +Vector& Vector::operator /= (const T& A) +{ + for (size_t i=0; i +Vector Vector::operator + (const T& A) const +{ + Vector V(*this); + for (size_t i=0; i +Vector& Vector::operator += (const T& A) +{ + for (size_t i=0; i +Vector Vector::operator - (const T& A) const +{ + Vector V(*this); + for (size_t i=0; i +Vector& Vector::operator -= (const T& A) +{ + for (size_t i=0; i +Vector Vector::operator + (const Vector& V0) const +{ + Vector V(m_N); + for (size_t i=0; i +Vector& Vector::operator += (const Vector& V) +{ + for ( size_t i=0 ; i +Vector Vector::operator - (const Vector& V0) const +{ + Vector V(m_N); + for (size_t i=0; i +Vector& Vector::operator -= (const Vector& V) +{ + for (size_t i=0; i +Vector Vector::operator - (void) const +{ + Vector V(m_N); + for (size_t i=0; i +Vector< T >& Vector< T >::Add( const Vector< T >* V , int count ) +{ + for( int c=0 ; c +Vector< T >& Vector< T >::AddScaled( const Vector& V , const T& scale ) +{ + for (size_t i=0; i +Vector& Vector::SubtractScaled(const Vector& V,const T& scale) +{ + for (size_t i=0; i +void Vector::Add( const Vector& V1 , const T& scale1 , const Vector& V2 , const T& scale2 , Vector& Out ) +{ + for( size_t i=0 ; i +void Vector::Add(const Vector& V1,const T& scale1,const Vector& V2,Vector& Out) +{ + for( size_t i=0 ; i +T Vector::Norm( size_t Ln ) const +{ + T N = T(); + for (size_t i = 0; i +void Vector::Normalize() +{ + T N = 1.0f/Norm(2); + for (size_t i = 0; i +T Vector< T >::Average( void ) const +{ + T N = T(); + for( size_t i=0 ; i +T Vector::Length() const +{ + T N = T(); + for (size_t i = 0; i +T Vector::Dot( const Vector& V ) const +{ + T V0 = T(); + for( size_t i=0 ; i +bool Vector< T >::read( const char* fileName ) +{ + FILE* fp = fopen( fileName , "rb" ); + if( !fp ) return false; + bool ret = read( fp ); + fclose( fp ); + return ret; +} +template< class T > +bool Vector< T >::write( const char* fileName ) const +{ + FILE* fp = fopen( fileName , "wb" ); + if( !fp ) return false; + bool ret = write( fp ); + fclose( fp ); + return ret; +} +template< class T > +bool Vector< T >::read( FILE* fp ) +{ + int d; + if( fread( &d , sizeof(int) , 1 , fp )!=1 ) return false; + Resize( d ); + if( fread( &(*this)[0] , sizeof( T ) , d , fp )!=d ) return false; + return true; +} +template< class T > +bool Vector< T >::write( FILE* fp ) const +{ + if( fwrite( &m_N , sizeof( int ) , 1 , fp )!=1 ) return false; + if( fwrite( &(*this)[0] , sizeof( T ) , m_N , fp )!=m_N ) return false; + return true; +} + + + +#endif diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/filter_screened_poisson.cpp b/src/plugins_unsupported/filter_screened_poisson_xml/filter_screened_poisson.cpp new file mode 100644 index 000000000..e5450be5b --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/filter_screened_poisson.cpp @@ -0,0 +1,676 @@ +/**************************************************************************** +* MeshLab o o * +* A versatile mesh processing toolbox o o * +* _ O _ * +* Copyright(C) 2005 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + +#ifdef WIN32 +#include +#include +#endif +#include +#include "Src/MyTime.h" +#include "Src/MemoryUsage.h" +#include "Src/MarchingCubes.h" +#include "Src/Octree.h" +#include "Src/SparseMatrix.h" +#include "Src/CmdLineParser.h" +#include "Src/PPolynomial.h" +void DumpOutput( const char* format , ... ); +void DumpOutput2( char* str , const char* format , ... ); + +#include "Src/PointStream.h" + +#include "Src/MultiGridOctreeData.h" +#include "filter_screened_poisson.h" +#include + + + +void DumpOutput( const char* format , ... ) +{ + char buf[4096]; + va_list marker; + va_start( marker, format ); + + vsprintf(buf,format,marker); + va_end( marker ); + + qDebug(buf); + } +void DumpOutput2(std::vector< char* >& comments , const char* format , ... ) +{ + char buf[4096]; + va_list marker; + va_start( marker, format ); + + vsprintf(buf,format,marker); + va_end( marker ); + qDebug(buf); +} + + +#if defined( _WIN32 ) || defined( _WIN64 ) +double PeakMemoryUsageMB( void ) +{ + HANDLE h = GetCurrentProcess(); + PROCESS_MEMORY_COUNTERS pmc; + return GetProcessMemoryInfo( h , &pmc , sizeof(pmc) ) ? ( (double)pmc.PeakWorkingSetSize )/(1<<20) : 0; +} +#endif // _WIN32 || _WIN64 + +#if defined( _WIN32 ) || defined( _WIN64 ) +inline double to_seconds( const FILETIME& ft ) +{ + const double low_to_sec=100e-9; // 100 nanoseconds + const double high_to_sec=low_to_sec*4294967296.0; + return ft.dwLowDateTime*low_to_sec+ft.dwHighDateTime*high_to_sec; +} +#endif // _WIN32 || _WIN64 + + +template< class Real > +struct OctreeProfiler +{ + Octree< Real >& tree; + double t; + + OctreeProfiler( Octree< Real >& t ) : tree(t) { ; } + void start( void ){ t = Time() , tree.resetLocalMemoryUsage(); } + void print( const char* header ) const + { + tree.memoryUsage(); +#if defined( _WIN32 ) || defined( _WIN64 ) + if( header ) printf( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); + else printf( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); +#else // !_WIN32 && !_WIN64 + if( header ) printf( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); + else printf( "%9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); +#endif // _WIN32 || _WIN64 + } + void dumpOutput( const char* header ) const + { + tree.memoryUsage(); +#if defined( _WIN32 ) || defined( _WIN64 ) + if( header ) DumpOutput( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); + else DumpOutput( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); +#else // !_WIN32 && !_WIN64 + if( header ) DumpOutput( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); + else DumpOutput( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); +#endif // _WIN32 || _WIN64 + } + void dumpOutput2( std::vector< char* >& comments , const char* header ) const + { + tree.memoryUsage(); +#if defined( _WIN32 ) || defined( _WIN64 ) + if( header ) DumpOutput2( comments , "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); + else DumpOutput2( comments , "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); +#else // !_WIN32 && !_WIN64 + if( header ) DumpOutput2( comments , "%s %9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); + else DumpOutput2( comments , "%9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); +#endif // _WIN32 || _WIN64 + } +}; + + + +// Constructor usually performs only two simple tasks of filling the two lists +// - typeList: with all the possible id of the filtering actions +// - actionList with the corresponding actions. If you want to add icons to your filtering actions you can do here by construction the QActions accordingly + +FilterScreenedPoissonPlugin::FilterScreenedPoissonPlugin() +{ +} +template +class PoissonParam +{ +public: + int MaxDepthVal; + int MaxSolveDepthVal; + int KernelDepthVal; + int MinDepthVal; + int FullDepthVal; + Real SamplesPerNodeVal; + Real ScaleVal; + bool ConfidenceFlag; + bool CleanFlag; + bool DensityFlag; + Real PointWeightVal; + int AdaptiveExponentVal; + int BoundaryTypeVal; + bool CompleteFlag; + bool NonManifoldFlag; + bool ShowResidualFlag; + int CGDepthVal; + int ItersVal; + Real CSSolverAccuracyVal; + + bool VerboseFlag; + int ThreadsVal; + bool LinearFitFlag; + float LowResIterMultiplierVal; + float ColorVal; + + PoissonParam() + { + MaxDepthVal=8; + MaxSolveDepthVal=-1; + KernelDepthVal=-1; + MinDepthVal=0; + FullDepthVal=5; + SamplesPerNodeVal =1.5f; + ScaleVal=1.1f; + ConfidenceFlag=false; + CleanFlag=false; + DensityFlag=false; + PointWeightVal = 4.0f; + AdaptiveExponentVal=1; + BoundaryTypeVal=1; + CompleteFlag=false; + NonManifoldFlag=false; + ShowResidualFlag=false; + CGDepthVal=0; + ItersVal=8; + CSSolverAccuracyVal=1e-3f; + + VerboseFlag=true; + ThreadsVal=omp_get_num_procs(); + LinearFitFlag = false; + LowResIterMultiplierVal=1.f; + ColorVal=16.0f; + } +}; + + +template< class Real> +XForm4x4 GetPointStreamScale(vcg::Box3 &bb, float expFact) +{ + qDebug("bbox %f %f %f - %f %f %f ",bb.min[0],bb.min[1],bb.min[2],bb.max[0],bb.max[1],bb.max[2]); + Real scale = bb.Dim()[bb.MaxDim()] * expFact; + Point3m center = bb.Center(); + for( int i=0 ; i<3 ; i++ ) center[i] -= scale/2; + XForm4x4< Real > tXForm = XForm4x4< Real >::Identity() , sXForm = XForm4x4< Real >::Identity(); + for( int i=0 ; i<3 ; i++ ) sXForm(i,i) = (Real)(1./scale ) , tXForm(3,i) = -center[i]; + return sXForm * tXForm; +} + + +template< class Real > +class MeshModelPointStream : public OrientedPointStreamWithData< Real, Point3m > +{ + CMeshO &_m; + size_t _curPos; +public: + MeshModelPointStream( CMeshO &m):_m(m),_curPos(0) + { + vcg::tri::RequireCompactness(m); + } + ~MeshModelPointStream( void ){} + void reset( void ) { _curPos =0;} + bool nextPoint( OrientedPoint3D< Real >& pt, Point3m &d) + { + if(_curPos>=_m.vn) + return false; + Point3m &nn = _m.vert[_curPos].N(); + Point3m tp = _m.Tr * _m.vert[_curPos].P(); + Point4m np = _m.Tr * Point4m(nn[0],nn[1],nn[2],0); + + pt.p[0] = tp[0]; + pt.p[1] = tp[1]; + pt.p[2] = tp[2]; + pt.n[0] = np[0]; + pt.n[1] = np[1]; + pt.n[2] = np[2]; + + d[0]=Real(_m.vert[_curPos].C()[0]); + d[1]=Real(_m.vert[_curPos].C()[1]); + d[2]=Real(_m.vert[_curPos].C()[2]); + + ++_curPos; + return true; + } + +}; + +template< class Real > +class MeshDocumentPointStream : public OrientedPointStreamWithData< Real, Point3m > +{ + MeshDocument &_md; + MeshModel *_curMesh; + size_t _curPos; + size_t _totalSize; +public: + MeshDocumentPointStream( MeshDocument &md):_md(md),_curMesh(0),_curPos(0) + { + _totalSize=0; + MeshModel *m=0; + do + { + m=_md.nextVisibleMesh(m); + if(m!=0) + { + vcg::tri::RequireCompactness(m->cm); + _totalSize+=m->cm.vn; + } + } while(m); + qDebug("TotalSize %i",_totalSize); + } + ~MeshDocumentPointStream( void ){} + void reset( void ) { _curPos =0; _curMesh=0;} + bool nextPoint( OrientedPoint3D< Real >& pt, Point3m &d ) + { + Point3m nn(0,0,0); +// do + { + if((_curMesh==0) || (_curPos >= _curMesh->cm.vn) ) + { + _curMesh = _md.nextVisibleMesh(_curMesh); + _curPos = 0; + } + + if(_curMesh==0) + return false; + if(_curPos < _curMesh->cm.vn) + { + nn = _curMesh->cm.vert[_curPos].N(); + Point3m tp = _curMesh->cm.Tr * _curMesh->cm.vert[_curPos].P(); + Point4m np = _curMesh->cm.Tr * Point4m(nn[0],nn[1],nn[2],0); +// Point3m tp = _curMesh->cm.vert[_curPos].P(); +// Point3m np = nn; + pt.p[0] = tp[0]; + pt.p[1] = tp[1]; + pt.p[2] = tp[2]; + pt.n[0] = np[0]; + pt.n[1] = np[1]; + pt.n[2] = np[2]; + d[0]=Real(_curMesh->cm.vert[_curPos].C()[0]); + d[1]=Real(_curMesh->cm.vert[_curPos].C()[1]); + d[2]=Real(_curMesh->cm.vert[_curPos].C()[2]); + + ++_curPos; + } + } + assert(nn!=Point3m(0,0,0)); + return true; + } + +}; + + + + +template< class Real , int Degree , BoundaryType BType , class Vertex > +int _Execute(OrientedPointStream< Real > *pointStream, Box3m bb, CMeshO &pm, PoissonParam &pp, vcg::CallBackPos* cb) +{ + typedef typename Octree< Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; + typedef typename Octree< Real >::template InterpolationInfo< false > InterpolationInfo; + typedef OrientedPointStreamWithData< Real , Point3D< Real > > PointStreamWithData; + typedef TransformedOrientedPointStreamWithData< Real , Point3D< Real > > XPointStreamWithData; + Reset< Real >(); + std::vector< char* > comments; + + XForm4x4< Real > xForm = GetPointStreamScale(bb,pp.ScaleVal); + XForm4x4< Real > iXForm = xForm.inverse(); + DumpOutput2( comments , "Running Screened Poisson Reconstruction (Version 9.0)\n" ); + double startTime = Time(); + + OctNode< TreeNodeData >::SetAllocator(MEMORY_ALLOCATOR_BLOCK_SIZE); + Octree< Real > tree; + OctreeProfiler< Real > profiler( tree ); + tree.threads = pp.ThreadsVal; + if( pp.MaxSolveDepthVal<0 ) pp.MaxSolveDepthVal = pp.MaxDepthVal; + + + + qDebug("Using %i threads\n",pp.ThreadsVal); +// int kernelDepth = KernelDepth.set ? KernelDepth.value : Depth.value-2; + if(pp.KernelDepthVal<0) pp.KernelDepthVal =pp.MaxDepthVal-2; + if( pp.KernelDepthVal>pp.MaxDepthVal ) + { + printf("kernelDepth cannot be greateer Depth.value\n"); + return false; + } + + int pointCount; + + Real pointWeightSum; + std::vector< typename Octree< Real >::PointSample >* samples = new std::vector< typename Octree< Real >::PointSample >(); + std::vector< ProjectiveData< Point3D< Real > , Real > >* sampleData = NULL; + DensityEstimator* density = NULL; + SparseNodeData< Point3D< Real > , NORMAL_DEGREE >* normalInfo = NULL; + Real targetValue = (Real)0.5; + + // Read in the samples (and color data) + { + profiler.start(); +// PointStream* pointStream; + +// char* ext = GetFileExtension( In.value ); +// if( Color.set && Color.value>0 ) +// { +// sampleData = new std::vector< ProjectiveData< Point3D< Real > , Real > >(); +// if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryOrientedPointStreamWithData< Real , Point3D< Real > , float , Point3D< unsigned char > >( In.value ); +// else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYOrientedPointStreamWithData< Real , Point3D< Real > >( In.value , ColorInfo< Real >::PlyProperties , 6 , ColorInfo< Real >::ValidPlyProperties ); +// else pointStream = new ASCIIOrientedPointStreamWithData< Real , Point3D< Real > >( In.value , ColorInfo< Real >::ReadASCII ); +// } +// else +// { +// if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryOrientedPointStream< Real , float >( In.value ); +// else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYOrientedPointStream< Real >( In.value ); +// else pointStream = new ASCIIOrientedPointStream< Real >( In.value ); +// } +// delete[] ext; + sampleData = new std::vector< ProjectiveData< Point3D< Real > , Real > >(); + XPointStreamWithData _pointStream( xForm , ( PointStreamWithData& )*pointStream ); + pointCount = tree.template init< Point3D< Real > >( _pointStream , pp.MaxDepthVal , pp.ConfidenceFlag , *samples , sampleData ); + +#pragma omp parallel for num_threads( pp.ThreadsVal ) + for( int i=0 ; i<(int)samples->size() ; i++ ) (*samples)[i].sample.data.n *= (Real)-1; + + DumpOutput( "Input Points / Samples: %d / %d\n" , pointCount , samples->size() ); + profiler.dumpOutput2( comments , "# Read input into tree:" ); + } + + DenseNodeData< Real , Degree > solution; + + { + DenseNodeData< Real , Degree > constraints; + InterpolationInfo* iInfo = NULL; + int solveDepth = pp.MaxSolveDepthVal; + + tree.resetNodeIndices(); + + // Get the kernel density estimator [If discarding, compute anew. Otherwise, compute once.] + { + profiler.start(); + density = tree.template setDensityEstimator< WEIGHT_DEGREE >( *samples , pp.KernelDepthVal , pp.SamplesPerNodeVal ); + profiler.dumpOutput2( comments , "# Got kernel density:" ); + } + + // Transform the Hermite samples into a vector field [If discarding, compute anew. Otherwise, compute once.] + { + profiler.start(); + normalInfo = new SparseNodeData< Point3D< Real > , NORMAL_DEGREE >(); + *normalInfo = tree.template setNormalField< NORMAL_DEGREE >( *samples , *density , pointWeightSum , BType==BOUNDARY_NEUMANN ); + profiler.dumpOutput2( comments , "# Got normal field:" ); + } + + if( !pp.DensityFlag ) delete density , density = NULL; + + // Trim the tree and prepare for multigrid + { + profiler.start(); + std::vector< int > indexMap; + + constexpr int MAX_DEGREE = NORMAL_DEGREE > Degree ? NORMAL_DEGREE : Degree; + tree.template inalizeForBroodedMultigrid< MAX_DEGREE , Degree , BType >( pp.FullDepthVal , typename Octree< Real >::template HasNormalDataFunctor< NORMAL_DEGREE >( *normalInfo ) , &indexMap ); + + if( normalInfo ) normalInfo->remapIndices( indexMap ); + if( density ) density->remapIndices( indexMap ); + profiler.dumpOutput2( comments , "# Finalized tree:" ); + } + + // Add the FEM constraints + { + profiler.start(); + constraints = tree.template initDenseNodeData< Degree >( ); + tree.template addFEMConstraints< Degree , BType , NORMAL_DEGREE , BType >( FEMVFConstraintFunctor< NORMAL_DEGREE , BType , Degree , BType >( 1. , 0. ) , *normalInfo , constraints , solveDepth ); + profiler.dumpOutput2( comments , "# Set FEM constraints:" ); + } + + // Free up the normal info [If we don't need it for subseequent iterations.] + delete normalInfo , normalInfo = NULL; + + // Add the interpolation constraints + if( pp.PointWeightVal>0 ) + { + profiler.start(); + iInfo = new InterpolationInfo( tree , *samples , targetValue , pp.AdaptiveExponentVal , (Real)pp.PointWeightVal * pointWeightSum , (Real)0 ); + tree.template addInterpolationConstraints< Degree , BType >( *iInfo , constraints , solveDepth ); + profiler.dumpOutput2( comments , "#Set point constraints:" ); + } + + DumpOutput( "Leaf Nodes / Active Nodes / Ghost Nodes: %d / %d / %d\n" , (int)tree.leaves() , (int)tree.nodes() , (int)tree.ghostNodes() ); + DumpOutput( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage())/(1<<20) ); + + // Solve the linear system + { + profiler.start(); + typename Octree< Real >::SolverInfo solverInfo; + solverInfo.cgDepth = pp.CGDepthVal , solverInfo.iters = pp.ItersVal , solverInfo.cgAccuracy = pp.CSSolverAccuracyVal , solverInfo.verbose = pp.VerboseFlag , solverInfo.showResidual = pp.ShowResidualFlag , solverInfo.lowResIterMultiplier = std::max< double >( 1. , pp.LowResIterMultiplierVal ); + solution = tree.template solveSystem< Degree , BType >( FEMSystemFunctor< Degree , BType >( 0 , 1. , 0 ) , iInfo , constraints , solveDepth , solverInfo ); + profiler.dumpOutput2( comments , "# Linear system solved:" ); + if( iInfo ) delete iInfo , iInfo = NULL; + } + } + + CoredFileMeshData< Vertex > mesh; + + { + profiler.start(); + double valueSum = 0 , weightSum = 0; + typename Octree< Real >::template MultiThreadedEvaluator< Degree , BType > evaluator( &tree , solution , pp.ThreadsVal ); +#pragma omp parallel for num_threads( pp.ThreadsVal ) reduction( + : valueSum , weightSum ) + for( int j=0 ; jsize() ; j++ ) + { + ProjectiveData< OrientedPoint3D< Real > , Real >& sample = (*samples)[j].sample; + Real w = sample.weight; + if( w>0 ) weightSum += w , valueSum += evaluator.value( sample.data.p / sample.weight , omp_get_thread_num() , (*samples)[j].node ) * w; + } + Real isoValue = (Real)( valueSum / weightSum ); +// if( samples ) delete samples , samples = NULL; + profiler.dumpOutput( "Got average:" ); + DumpOutput( "Iso-Value: %e\n" , isoValue ); + + profiler.start(); + SparseNodeData< ProjectiveData< Point3D< Real > , Real > , DATA_DEGREE >* colorData = NULL; + if( sampleData ) + { + colorData = new SparseNodeData< ProjectiveData< Point3D< Real > , Real > , DATA_DEGREE >(); + *colorData = tree.template setDataField< DATA_DEGREE , false >( *samples , *sampleData , (DensityEstimator*)NULL ); + delete sampleData , sampleData = NULL; + for( const OctNode< TreeNodeData >* n = tree.tree().nextNode() ; n ; n=tree.tree().nextNode( n ) ) + { + ProjectiveData< Point3D< Real > , Real >* clr = (*colorData)( n ); + if( clr ) + (*clr) *= (Real)pow( pp.ColorVal , tree.depth( n ) ); + } + } + tree.template getMCIsoSurface< Degree , BType , WEIGHT_DEGREE , DATA_DEGREE >( density , colorData , solution , isoValue , mesh , !pp.LinearFitFlag , !pp.NonManifoldFlag , false /*PolygonMesh.set*/ ); + DumpOutput( "Vertices / Polygons: %d / %d\n" , mesh.outOfCorePointCount()+mesh.inCorePoints.size() , mesh.polygonCount() ); + profiler.dumpOutput2( comments , "# Got triangles:" ); + } + +// FreePointer( solution ); + + cb(90,"Creating Mesh"); + mesh.resetIterator(); + int vm = mesh.outOfCorePointCount()+mesh.inCorePoints.size(); + for(auto pt=mesh.inCorePoints.begin();pt!=mesh.inCorePoints.end();++pt) + { + Point3D pp = iXForm*pt->point; + vcg::tri::Allocator::AddVertex(pm,Point3m(pp[0],pp[1],pp[2])); + pm.vert.back().Q() = pt->value; + pm.vert.back().C()[0] = pt->color[0]; + pm.vert.back().C()[1] = pt->color[1]; + pm.vert.back().C()[2] = pt->color[2]; + } + for (int ii=0; ii < mesh.outOfCorePointCount(); ii++){ + Vertex pt; + mesh.nextOutOfCorePoint(pt); + Point3D pp = iXForm*pt.point; + vcg::tri::Allocator::AddVertex(pm,Point3m(pp[0],pp[1],pp[2])); + pm.vert.back().Q() = pt.value; + pm.vert.back().C()[0] = pt.color[0]; + pm.vert.back().C()[1] = pt.color[1]; + pm.vert.back().C()[2] = pt.color[2]; + } + + std::vector< CoredVertexIndex > polygon; + while(mesh.nextPolygon( polygon )) + { + assert(polygon.size()==3); + int indV[3]; + for( int i=0 ; i::AddFace(pm, &pm.vert[indV[0]], &pm.vert[indV[1]], &pm.vert[indV[2]]); + } + cb(100,"Done"); + +// if( colorData ) delete colorData , colorData = NULL; + + + if( density ) delete density , density = NULL; + DumpOutput2( comments , "# Total Solve: %9.1f (s), %9.1f (MB)\n" , Time()-startTime , tree.maxMemoryUsage() ); + + return 1; +} + + + +template +void PoissonClean(MeshType &m, bool scaleNormal, bool cleanFlag) +{ + vcg::tri::UpdateNormal::NormalizePerVertex(m); + + if(cleanFlag) { + for (auto vi = m.vert.begin(); vi != m.vert.end(); ++vi) + if (vcg::SquaredNorm(vi->N()) < std::numeric_limits::min()*10.0) + vcg::tri::Allocator::DeleteVertex(m,*vi); + + for (auto fi = m.face.begin(); fi != m.face.end(); ++fi) + if( fi->V(0)->IsD() || fi->V(1)->IsD() || fi->V(2)->IsD() ) + vcg::tri::Allocator::DeleteFace(m,*fi); + } + + vcg::tri::Allocator::CompactEveryVector(m); + if(scaleNormal) + { + for(auto vi=m.vert.begin();vi!=m.vert.end();++vi) + vi->N() *= vi->Q(); + } +} + +bool HasGoodNormal(CMeshO &m) +{ + for(auto vi=m.vert.begin();vi!=m.vert.end();++vi) + if(vcg::SquaredNorm(vi->N()) < std::numeric_limits::min()*10.0) + return false; + + return true; +} + +bool FilterScreenedPoissonPlugin::applyFilter( const QString& filterName,MeshDocument& md,EnvWrap& env, vcg::CallBackPos* cb) +{ + bool currDirChanged=false; + QDir currDir = QDir::current(); + + if (filterName == "Surface Reconstruction: Screened Poisson") + { + //check if folder is writable + QTemporaryFile file("./_tmp_XXXXXX.tmp"); + if (!file.open()) + { + currDirChanged=true; + QTemporaryDir tmpdir; + QDir::setCurrent(tmpdir.path()); + Log("Warning - current folder is not writable. Screened Poisson Merging needs to save intermediate files in the current working folder. Project and meshes must be in a write-enabled folder. Please save your data in a suitable folder before applying."); + //errorMessage = "current folder is not writable.
Screened Poisson Merging needs to save intermediate files in the current working folder.
Project and meshes must be in a write-enabled folder.
Please save your data in a suitable folder before applying."; + //return false; + } + + PoissonParam pp; + pp.MaxDepthVal = env.evalInt("depth"); + pp.FullDepthVal = env.evalInt("fullDepth"); + pp.CGDepthVal= env.evalInt("cgDepth"); + pp.ScaleVal = env.evalFloat("scale"); + pp.SamplesPerNodeVal = env.evalFloat("samplesPerNode"); + pp.PointWeightVal = env.evalFloat("pointWeight"); + pp.ItersVal = env.evalInt("iters"); + pp.ConfidenceFlag = env.evalBool("confidence"); + pp.DensityFlag = true; + pp.CleanFlag = env.evalBool("preClean"); + + bool goodNormal=true, goodColor=true; + if(env.evalBool("visibleLayer") == false) + { + PoissonClean(md.mm()->cm, pp.ConfidenceFlag, pp.CleanFlag); + goodNormal=HasGoodNormal(md.mm()->cm); + goodColor = md.mm()->hasDataMask(MeshModel::MM_VERTCOLOR); + } + else + { + MeshModel *_mm=0; + while(_mm=md.nextVisibleMesh(_mm)) { + PoissonClean(_mm->cm, pp.ConfidenceFlag, pp.CleanFlag); + goodNormal &= HasGoodNormal(_mm->cm); + goodColor &= _mm->hasDataMask(MeshModel::MM_VERTCOLOR); + } + } + + if(!goodNormal) + { + this->errorMessage = "Filter requires correct per vertex normals.
" + "E.g. it is necessary that your ALL the input vertices have a proper, not-null normal.
" + "Try enabling the pre-clean option and retry.

" + "To permanently remove this problem:
" + "If you encounter this error on a triangulated mesh try to use the Remove Unreferenced Vertices filter" + "If you encounter this error on a pointcloud try to use the Conditional Vertex Selection filter" + "with function '(nx==0.0) && (ny==0.0) && (nz==0.0)', and then delete selected vertices.
"; + return false; + } + + MeshModel *pm =md.addNewMesh("","Poisson mesh",false); + md.setVisible(pm->id(),false); + pm->updateDataMask(MeshModel::MM_VERTQUALITY); + if(goodColor) pm->updateDataMask(MeshModel::MM_VERTCOLOR); + + if(env.evalBool("visibleLayer")) + { + Box3m bb; + MeshModel *_mm=0; + while(_mm=md.nextVisibleMesh(_mm)) + bb.Add(_mm->cm.Tr,_mm->cm.bbox); + + MeshDocumentPointStream documentStream(md); + _Execute >(&documentStream,bb,pm->cm,pp,cb); + } + else + { + MeshModelPointStream meshStream(md.mm()->cm); + _Execute >(&meshStream,md.mm()->cm.bbox,pm->cm,pp,cb); + } + pm->UpdateBoxAndNormals(); + md.setVisible(pm->id(),true); + md.setCurrentMesh(pm->id()); + if(currDirChanged) QDir::setCurrent(currDir.path()); + return true; + } + return false; +} + + + + + +MESHLAB_PLUGIN_NAME_EXPORTER(FilterScreenedPoissonPlugin) diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/filter_screened_poisson.h b/src/plugins_unsupported/filter_screened_poisson_xml/filter_screened_poisson.h new file mode 100644 index 000000000..475a4400c --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/filter_screened_poisson.h @@ -0,0 +1,43 @@ +/**************************************************************************** +* MeshLab o o * +* A versatile mesh processing toolbox o o * +* _ O _ * +* Copyright(C) 2005 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + +#ifndef SAMPLEFILTERSPLUGIN_H +#define SAMPLEFILTERSPLUGIN_H + +#include +//class QScriptEngine; + +class FilterScreenedPoissonPlugin : public MeshLabFilterInterface +{ + Q_OBJECT + MESHLAB_PLUGIN_IID_EXPORTER(MESHLAB_FILTER_INTERFACE_IID) + Q_INTERFACES(MeshLabFilterInterface) +public: + + FilterScreenedPoissonPlugin(); + + bool applyFilter(const QString& filterName,MeshDocument& md,EnvWrap& env, vcg::CallBackPos* cb) ; +}; + + +#endif diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/filter_screened_poisson.pro b/src/plugins_unsupported/filter_screened_poisson_xml/filter_screened_poisson.pro new file mode 100644 index 000000000..a9a5f4702 --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/filter_screened_poisson.pro @@ -0,0 +1,21 @@ +include (../../shared.pri) + +win32:QMAKE_CXXFLAGS += -openmp +macx:QMAKE_CXXFLAGS_RELEASE+= -O3 -DRELEASE -funroll-loops -ffast-math -Wno-sign-compare -Wno-unused-parameter +linux:QMAKE_LFLAGS += -fopenmp -lgomp + +HEADERS += \ + filter_screened_poisson.h + +SOURCES += \ + filter_screened_poisson.cpp \ + Src/MarchingCubes.cpp \ + #Src/CmdLineParser.cpp \ + Src/Factor.cpp \ + Src/Geometry.cpp + +TARGET = filter_screened_poisson +DEFINES += BRUNO_LEVY_FIX +DEFINES += FOR_RELEASE + +include (../../shared_post.pri) diff --git a/src/plugins_unsupported/filter_screened_poisson_xml/filter_screened_poisson.xml b/src/plugins_unsupported/filter_screened_poisson_xml/filter_screened_poisson.xml new file mode 100644 index 000000000..aeae58d89 --- /dev/null +++ b/src/plugins_unsupported/filter_screened_poisson_xml/filter_screened_poisson.xml @@ -0,0 +1,76 @@ + + + + The filter uses the original code of Michael Kazhdan and Matthew Bolitho implementing the algorithm described in the following paper:
+Michael Kazhdan, Hugues Hoppe,
+"Screened Poisson surface reconstruction"
+ACM Trans. Graphics, 32(3), 2013

+WARNING: this filter saves intermediate cache files in the "working" folder (last folder used when loading/saving). Be sure you are not working in a READ-ONLY location.
+]]>
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
From 7f0315321b49d60df99c6e1fd331887d743355f2 Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Fri, 24 Apr 2020 17:21:03 +0200 Subject: [PATCH 2/8] non-xml screened poisson working --- .../filter_screened_poisson.cpp | 90 ++++++++++--------- .../filter_screened_poisson.h | 2 +- 2 files changed, 51 insertions(+), 41 deletions(-) diff --git a/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.cpp b/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.cpp index 9a372c863..9df1b0618 100644 --- a/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.cpp +++ b/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.cpp @@ -57,12 +57,16 @@ QString FilterScreenedPoissonPlugin::filterName(FilterIDType filter) const QString FilterScreenedPoissonPlugin::filterInfo(FilterIDType filter) const { if (filter == FP_SCREENED_POISSON) - return "This surface reconstruction algorithm creates watertight surfaces from oriented point sets.\n" - "The filter uses the original code of Michael Kazhdan and Matthew Bolitho implementing the algorithm described in the following paper:\n" - "Michael Kazhdan, Hugues Hoppe,\n" - "\"Screened Poisson surface reconstruction\"\n" - "ACM Trans. Graphics, 32(3), 2013\n" - "WARNING: this filter saves intermediate cache files in the \"working\" folder (last folder used when loading/saving). Be sure you are not working in a READ-ONLY location.\n"; + return "This surface reconstruction algorithm creates watertight surfaces " + "from oriented point sets.
" + "The filter uses the original code of Michael Kazhdan and Matthew Bolitho " + "implementing the algorithm described in the following paper:
" + "Michael Kazhdan, Hugues Hoppe,
" + "\"Screened Poisson surface reconstruction\"
" + "ACM Trans. Graphics, 32(3), 2013

" + "WARNING: this filter saves intermediate cache files in the \"working\" " + "folder (last folder used when loading/saving). Be sure you are not working in " + "a READ-ONLY location.
"; else { return "Error!"; } @@ -82,7 +86,7 @@ MeshFilterInterface::FilterClass FilterScreenedPoissonPlugin::getClass(QAction* int FilterScreenedPoissonPlugin::getRequirements(QAction* a) { if (ID(a) == FP_SCREENED_POISSON){ - + return MeshModel::MM_NONE; } else { assert(0); @@ -92,15 +96,13 @@ int FilterScreenedPoissonPlugin::getRequirements(QAction* a) bool FilterScreenedPoissonPlugin::applyFilter(QAction* filter, MeshDocument& md, RichParameterSet& params, vcg::CallBackPos* cb) { - /*bool currDirChanged=false; + bool currDirChanged=false; QDir currDir = QDir::current(); - if (filter == "Surface Reconstruction: Screened Poisson") - { + if (ID(filter) == FP_SCREENED_POISSON) { //check if folder is writable QTemporaryFile file("./_tmp_XXXXXX.tmp"); - if (!file.open()) - { + if (!file.open()) { currDirChanged=true; QTemporaryDir tmpdir; QDir::setCurrent(tmpdir.path()); @@ -110,36 +112,34 @@ bool FilterScreenedPoissonPlugin::applyFilter(QAction* filter, MeshDocument& md, } PoissonParam pp; - pp.MaxDepthVal = params.evalInt("depth"); - pp.FullDepthVal = params.evalInt("fullDepth"); - pp.CGDepthVal= params.evalInt("cgDepth"); - pp.ScaleVal = params.evalFloat("scale"); - pp.SamplesPerNodeVal = params.evalFloat("samplesPerNode"); - pp.PointWeightVal = params.evalFloat("pointWeight"); - pp.ItersVal = params.evalInt("iters"); - pp.ConfidenceFlag = params.evalBool("confidence"); + pp.MaxDepthVal = params.getInt("depth"); + pp.FullDepthVal = params.getInt("fullDepth"); + pp.CGDepthVal= params.getInt("cgDepth"); + pp.ScaleVal = params.getFloat("scale"); + pp.SamplesPerNodeVal = params.getFloat("samplesPerNode"); + pp.PointWeightVal = params.getFloat("pointWeight"); + pp.ItersVal = params.getInt("iters"); + pp.ConfidenceFlag = params.getBool("confidence"); pp.DensityFlag = true; - pp.CleanFlag = params.evalBool("preClean"); + pp.CleanFlag = params.getBool("preClean"); bool goodNormal=true, goodColor=true; - if(params.evalBool("visibleLayer") == false) - { + if(params.getBool("visibleLayer") == false) { PoissonClean(md.mm()->cm, pp.ConfidenceFlag, pp.CleanFlag); goodNormal=HasGoodNormal(md.mm()->cm); goodColor = md.mm()->hasDataMask(MeshModel::MM_VERTCOLOR); } - else - { - MeshModel *_mm=0; - while(_mm=md.nextVisibleMesh(_mm)) { + else { + MeshModel *_mm=md.nextVisibleMesh(_mm); + while(_mm != nullptr) { PoissonClean(_mm->cm, pp.ConfidenceFlag, pp.CleanFlag); goodNormal &= HasGoodNormal(_mm->cm); goodColor &= _mm->hasDataMask(MeshModel::MM_VERTCOLOR); + _mm=md.nextVisibleMesh(_mm); } } - if(!goodNormal) - { + if(!goodNormal) { this->errorMessage = "Filter requires correct per vertex normals.
" "E.g. it is necessary that your ALL the input vertices have a proper, not-null normal.
" "Try enabling the pre-clean option and retry.

" @@ -153,20 +153,21 @@ bool FilterScreenedPoissonPlugin::applyFilter(QAction* filter, MeshDocument& md, MeshModel *pm =md.addNewMesh("","Poisson mesh",false); md.setVisible(pm->id(),false); pm->updateDataMask(MeshModel::MM_VERTQUALITY); - if(goodColor) pm->updateDataMask(MeshModel::MM_VERTCOLOR); + if(goodColor) + pm->updateDataMask(MeshModel::MM_VERTCOLOR); - if(params.evalBool("visibleLayer")) - { + if(params.getBool("visibleLayer")) { Box3m bb; - MeshModel *_mm=0; - while(_mm=md.nextVisibleMesh(_mm)) + MeshModel *_mm=md.nextVisibleMesh(_mm); + while(_mm != nullptr){ bb.Add(_mm->cm.Tr,_mm->cm.bbox); + _mm=md.nextVisibleMesh(_mm); + } MeshDocumentPointStream documentStream(md); _Execute >(&documentStream,bb,pm->cm,pp,cb); } - else - { + else { MeshModelPointStream meshStream(md.mm()->cm); _Execute >(&meshStream,md.mm()->cm.bbox,pm->cm,pp,cb); } @@ -176,16 +177,25 @@ bool FilterScreenedPoissonPlugin::applyFilter(QAction* filter, MeshDocument& md, if(currDirChanged) QDir::setCurrent(currDir.path()); return true; } - return false;*/ + return false; } void FilterScreenedPoissonPlugin::initParameterSet( QAction* filter, - MeshModel& m, - RichParameterSet& parent) + MeshModel&, + RichParameterSet& parlist) { if (ID(filter) == FP_SCREENED_POISSON) { - + parlist.addParam(new RichBool("visibleLayer", false, "Merge all visible layers", "Enabling this flag means that all the visible layers will be used for providing the points.")); + parlist.addParam(new RichInt("depth", 8, "Reconstruction Depth", "This integer is the maximum depth of the tree that will be used for surface reconstruction. Running at depth d corresponds to solving on a voxel grid whose resolution is no larger than 2^d x 2^d x 2^d. Note that since the reconstructor adapts the octree to the sampling density, the specified reconstruction depth is only an upper bound. The default value for this parameter is 8.")); + parlist.addParam(new RichInt("fullDepth", 5, "Adaptive Octree Depth", "This integer specifies the depth beyond depth the octree will be adapted. At coarser depths, the octree will be complete, containing all 2^d x 2^d x 2^d nodes. The default value for this parameter is 5.")); + parlist.addParam(new RichInt("cgDepth", 0, "Conjugate Gradients Depth", "This integer is the depth up to which a conjugate-gradients solver will be used to solve the linear system. Beyond this depth Gauss-Seidel relaxation will be used. The default value for this parameter is 0.")); + parlist.addParam(new RichFloat("scale", 1.1, "Scale Factor", "This floating point value specifies the ratio between the diameter of the cube used for reconstruction and the diameter of the samples' bounding cube. The default value is 1.1.")); + parlist.addParam(new RichFloat("samplesPerNode", 1.5, "Minimum Number of Samples", "This floating point value specifies the minimum number of sample points that should fall within an octree node as the octree construction is adapted to sampling density. For noise-free samples, small values in the range [1.0 - 5.0] can be used. For more noisy samples, larger values in the range [15.0 - 20.0] may be needed to provide a smoother, noise-reduced, reconstruction. The default value is 1.5.")); + parlist.addParam(new RichFloat("pointWeight", 4, "Interpolation Weight", "This floating point value specifies the importants that interpolation of the point samples is given in the formulation of the screened Poisson equation. The results of the original (unscreened) Poisson Reconstruction can be obtained by setting this value to 0. The default value for this parameter is 4.")); + parlist.addParam(new RichInt("iters", 8, "Gauss-Seidel Relaxations", "This integer value specifies the number of Gauss-Seidel relaxations to be performed at each level of the hierarchy. The default value for this parameter is 8.")); + parlist.addParam(new RichBool("confidence", false, "Confidence Flag", "Enabling this flag tells the reconstructor to use the quality as confidence information; this is done by scaling the unit normals with the quality values. When the flag is not enabled, all normals are normalized to have unit-length prior to reconstruction.")); + parlist.addParam(new RichBool("preClean", false, "Pre-Clean", "Enabling this flag force a cleaning pre-pass on the data removing all unreferenced vertices or vertices with null normals.")); } } diff --git a/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.h b/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.h index eb7f858d0..b3dc1543c 100644 --- a/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.h +++ b/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.h @@ -53,7 +53,7 @@ public: RichParameterSet& params, vcg::CallBackPos* cb) ; - void initParameterSet(QAction* a,MeshModel& m, RichParameterSet& parent); + void initParameterSet(QAction* a, MeshModel&, RichParameterSet& parlist); int postCondition(QAction* filter) const; FILTER_ARITY filterArity(QAction*) const; }; From 46f10fed1f6bc0e5ee0a3f5d34a4374ce452e67b Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Fri, 24 Apr 2020 17:55:18 +0200 Subject: [PATCH 3/8] some cleanups --- .../filter_screened_poisson/Src/MemoryUsage.h | 2 ++ .../filter_screened_poisson/Src/MultiGridOctreeData.inl | 1 + .../filter_screened_poisson/Src/Polynomial.inl | 6 +++--- .../filter_screened_poisson/filter_screened_poisson.cpp | 2 +- .../filter_screened_poisson/filter_screened_poisson.pro | 2 -- src/meshlabplugins/filter_screened_poisson/poisson_utils.h | 5 ++--- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/meshlabplugins/filter_screened_poisson/Src/MemoryUsage.h b/src/meshlabplugins/filter_screened_poisson/Src/MemoryUsage.h index c6997b7cf..1d025b67e 100755 --- a/src/meshlabplugins/filter_screened_poisson/Src/MemoryUsage.h +++ b/src/meshlabplugins/filter_screened_poisson/Src/MemoryUsage.h @@ -48,6 +48,8 @@ struct MemoryInfo #include #include +#include +#include class MemoryInfo { diff --git a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.inl b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.inl index 0dee9319d..6061abe00 100755 --- a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.inl +++ b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.inl @@ -30,6 +30,7 @@ DAMAGE. #endif // FAST_SET_UP #include #include "PointStream.h" +#include "MemoryUsage.h" #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 //#define MEMORY_ALLOCATOR_BLOCK_SIZE 0 diff --git a/src/meshlabplugins/filter_screened_poisson/Src/Polynomial.inl b/src/meshlabplugins/filter_screened_poisson/Src/Polynomial.inl index ea7ae5044..d9fb669ea 100755 --- a/src/meshlabplugins/filter_screened_poisson/Src/Polynomial.inl +++ b/src/meshlabplugins/filter_screened_poisson/Src/Polynomial.inl @@ -67,7 +67,7 @@ Polynomial Polynomial::integral(void) const{ for(int i=0;i<=Degree;i++){p.coefficients[i+1]=coefficients[i]/(i+1);} return p; } -template<> double Polynomial< 0 >::operator() ( double t ) const { return coefficients[0]; } +template<> double Polynomial< 0 >::operator() ( double ) const { return coefficients[0]; } template<> double Polynomial< 1 >::operator() ( double t ) const { return coefficients[0]+coefficients[1]*t; } template<> double Polynomial< 2 >::operator() ( double t ) const { return coefficients[0]+(coefficients[1]+coefficients[2]*t)*t; } template @@ -308,7 +308,7 @@ int Polynomial::getSolutions( double c , double* roots , double EPS ) co } // The 0-th order B-spline template< > -Polynomial< 0 > Polynomial< 0 >::BSplineComponent( int i ) +Polynomial< 0 > Polynomial< 0 >::BSplineComponent( int ) { Polynomial p; p.coefficients[0] = 1.; @@ -338,7 +338,7 @@ Polynomial< Degree > Polynomial< Degree >::BSplineComponent( int i ) // The 0-th order B-spline values -template< > void Polynomial< 0 >::BSplineComponentValues( double x , double* values ){ values[0] = 1.; } +template< > void Polynomial< 0 >::BSplineComponentValues( double , double* values ){ values[0] = 1.; } // The Degree-th order B-spline template< int Degree > void Polynomial< Degree >::BSplineComponentValues( double x , double* values ) { diff --git a/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.cpp b/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.cpp index 9df1b0618..17f9f4eb2 100644 --- a/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.cpp +++ b/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.cpp @@ -85,7 +85,7 @@ MeshFilterInterface::FilterClass FilterScreenedPoissonPlugin::getClass(QAction* int FilterScreenedPoissonPlugin::getRequirements(QAction* a) { - if (ID(a) == FP_SCREENED_POISSON){ + if (ID(a) == FP_SCREENED_POISSON) { return MeshModel::MM_NONE; } else { diff --git a/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.pro b/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.pro index b9959898d..90c476745 100644 --- a/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.pro +++ b/src/meshlabplugins/filter_screened_poisson/filter_screened_poisson.pro @@ -11,8 +11,6 @@ HEADERS += \ SOURCES += \ filter_screened_poisson.cpp \ Src/MarchingCubes.cpp \ - #Src/CmdLineParser.cpp \ - Src/Factor.cpp \ Src/Geometry.cpp diff --git a/src/meshlabplugins/filter_screened_poisson/poisson_utils.h b/src/meshlabplugins/filter_screened_poisson/poisson_utils.h index bcf5b49be..0a7c8ed32 100644 --- a/src/meshlabplugins/filter_screened_poisson/poisson_utils.h +++ b/src/meshlabplugins/filter_screened_poisson/poisson_utils.h @@ -29,7 +29,6 @@ #endif #include #include "Src/MyTime.h" -#include "Src/MemoryUsage.h" #include "Src/MarchingCubes.h" #include "Src/Octree.h" #include "Src/SparseMatrix.h" @@ -439,7 +438,7 @@ int _Execute( } DumpOutput( "Leaf Nodes / Active Nodes / Ghost Nodes: %d / %d / %d\n" , (int)tree.leaves() , (int)tree.nodes() , (int)tree.ghostNodes() ); - DumpOutput( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage())/(1<<20) ); + //DumpOutput( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage())/(1<<20) ); // Solve the linear system { @@ -490,7 +489,7 @@ int _Execute( cb(90,"Creating Mesh"); mesh.resetIterator(); - int vm = mesh.outOfCorePointCount()+mesh.inCorePoints.size(); + //int vm = mesh.outOfCorePointCount()+mesh.inCorePoints.size(); for(auto pt=mesh.inCorePoints.begin();pt!=mesh.inCorePoints.end();++pt) { Point3D pp = iXForm*pt->point; vcg::tri::Allocator::AddVertex(pm,Point3m(pp[0],pp[1],pp[2])); From bbf744f40ffffe4d02fe879a7c68723e0a8dd82c Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Sat, 25 Apr 2020 17:47:02 +0200 Subject: [PATCH 4/8] warnings and cleanups --- .../filter_screened_poisson/Src/BSplineData.h | 4 +- .../Src/MarchingCubes.cpp | 2 +- .../filter_screened_poisson/Src/MemoryUsage.h | 6 +- .../Src/MultiGridOctreeData.Evaluation.inl | 179 +++++++++--------- .../MultiGridOctreeData.SortedTreeNodes.inl | 45 +++-- .../Src/MultiGridOctreeData.System.inl | 27 +-- .../MultiGridOctreeData.WeightedSamples.inl | 3 +- .../Src/MultiGridOctreeData.inl | 67 ++++--- .../filter_screened_poisson/Src/Octree.inl | 21 +- .../filter_screened_poisson.pro | 1 + .../filter_screened_poisson/poisson_utils.h | 8 +- 11 files changed, 205 insertions(+), 158 deletions(-) diff --git a/src/meshlabplugins/filter_screened_poisson/Src/BSplineData.h b/src/meshlabplugins/filter_screened_poisson/Src/BSplineData.h index 601253e73..bcc49d819 100755 --- a/src/meshlabplugins/filter_screened_poisson/Src/BSplineData.h +++ b/src/meshlabplugins/filter_screened_poisson/Src/BSplineData.h @@ -200,7 +200,7 @@ class BSplineEvaluationData { public: static const int Pad = (BType==BOUNDARY_FREE ) ? BSplineSupportSizes< Degree >::SupportEnd : ( (Degree&1) && BType==BOUNDARY_DIRICHLET ) ? -1 : 0; - inline static int Begin( int depth ){ return -Pad; } + inline static int Begin( int ){ return -Pad; } inline static int End ( int depth ){ return (1<=End(depth); } @@ -468,4 +468,4 @@ template< int Degree1 , int Degree2 > void SetBSplineElementIntegrals( double in #include "BSplineData.inl" -#endif // BSPLINE_DATA_INCLUDED \ No newline at end of file +#endif // BSPLINE_DATA_INCLUDED diff --git a/src/meshlabplugins/filter_screened_poisson/Src/MarchingCubes.cpp b/src/meshlabplugins/filter_screened_poisson/Src/MarchingCubes.cpp index b8040df34..9e511b730 100755 --- a/src/meshlabplugins/filter_screened_poisson/Src/MarchingCubes.cpp +++ b/src/meshlabplugins/filter_screened_poisson/Src/MarchingCubes.cpp @@ -303,7 +303,7 @@ int Cube::EdgeReflectEdgeIndex( int edgeIndex ) // MarchingSquares // ///////////////////// #if NEW_ORDERING -#pragma message ( "[WARNING] Not clear if MarchingSquares::edgeMask and MarchingSquares::edges are set correctly" ) +//#pragma message ( "[WARNING] Not clear if MarchingSquares::edgeMask and MarchingSquares::edges are set correctly" ) const int MarchingSquares::cornerMap[] = { 0 , 1 , 3 , 2 }; bool MarchingSquares::HasEdgeRoots( unsigned char mcIndex , int edgeIndex ) { diff --git a/src/meshlabplugins/filter_screened_poisson/Src/MemoryUsage.h b/src/meshlabplugins/filter_screened_poisson/Src/MemoryUsage.h index 1d025b67e..21235aa39 100755 --- a/src/meshlabplugins/filter_screened_poisson/Src/MemoryUsage.h +++ b/src/meshlabplugins/filter_screened_poisson/Src/MemoryUsage.h @@ -72,6 +72,11 @@ class MemoryInfo ,&pid ,s ,&c ,&d ,&d ,&d ,&d ,&d ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&ld ,&ld ,&ld ,&ld ,&d ,&ld ,&llu ,&vm ,&ld ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&d ,&d ,&lu ,&lu ); fclose(f); + + if (n >= 23) + return vm; + else + return 0; /* pid %d comm %s @@ -115,7 +120,6 @@ processor %d rt_priority %lu (since kernel 2.5.19) policy %lu (since kernel 2.5.19) */ - return vm; } }; diff --git a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.Evaluation.inl b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.Evaluation.inl index c965effbe..a4f57e94f 100644 --- a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.Evaluation.inl +++ b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.Evaluation.inl @@ -26,6 +26,8 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ +#include "MultiGridOctreeData.h" + template< class Real > template< int FEMDegree , BoundaryType BType> void Octree< Real >::_Evaluator< FEMDegree , BType >::set( LocalDepth depth ) @@ -306,12 +308,37 @@ V Octree< Real >::_getValue( const ConstPointSupportKey< FEMDegree >& neighborKe LocalDepth d = _localDepth( node ); for( int dd=0 ; dd<3 ; dd++ ) - if ( p[dd]==0 ) p[dd] = (Real)(0.+1e-6); - else if( p[dd]==1 ) p[dd] = (Real)(1.-1e-6); + if ( p[dd]==0 ) + p[dd] = (Real)(0.+1e-6); + else if( p[dd]==1 ) + p[dd] = (Real)(1.-1e-6); + { + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); + for( int i=0 ; i& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); - + const TreeOctNode* _n = neighbors.neighbors[i][j][k]; + if( _isValidFEMNode( _n ) ) + { + int _pIdx[3]; + Point3D< Real > _s ; Real _w; + _startAndWidth( _n , _s , _w ); + int _fIdx[3]; + functionIndex< FEMDegree , BType >( _n , _fIdx ); + for( int dd=0 ; dd<3 ; dd++ ) _pIdx[dd] = std::max< int >( 0 , std::min< int >( SupportSize-1 , LeftSupportRadius + (int)floor( ( p[dd]-_s[dd] ) / _w ) ) ); + value += + solution[ _n->nodeData.nodeIndex ] * + (Real) + ( + evaluator._bsData->baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * + evaluator._bsData->baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * + evaluator._bsData->baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) + ); + } + } + if( d>0 ) + { + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node->parent ); for( int i=0 ; i::_getValue( const ConstPointSupportKey< FEMDegree >& neighborKe int _fIdx[3]; functionIndex< FEMDegree , BType >( _n , _fIdx ); for( int dd=0 ; dd<3 ; dd++ ) _pIdx[dd] = std::max< int >( 0 , std::min< int >( SupportSize-1 , LeftSupportRadius + (int)floor( ( p[dd]-_s[dd] ) / _w ) ) ); - value += - solution[ _n->nodeData.nodeIndex ] * - (Real) - ( - evaluator._bsData->baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * - evaluator._bsData->baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * - evaluator._bsData->baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) - ); - } - } - if( d>0 ) - { - const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node->parent ); - for( int i=0 ; i _s ; Real _w; - _startAndWidth( _n , _s , _w ); - int _fIdx[3]; - functionIndex< FEMDegree , BType >( _n , _fIdx ); - for( int dd=0 ; dd<3 ; dd++ ) _pIdx[dd] = std::max< int >( 0 , std::min< int >( SupportSize-1 , LeftSupportRadius + (int)floor( ( p[dd]-_s[dd] ) / _w ) ) ); - value += - coarseSolution[ _n->nodeData.nodeIndex ] * - (Real) - ( - evaluator._bsData->baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * - evaluator._bsData->baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * - evaluator._bsData->baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) - ); - } + value += + coarseSolution[ _n->nodeData.nodeIndex ] * + (Real) + ( + evaluator._bsData->baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * + evaluator._bsData->baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * + evaluator._bsData->baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) + ); } } } - return value; + } + return value; } template< class Real > template< int FEMDegree , BoundaryType BType > @@ -413,12 +416,44 @@ std::pair< Real , Point3D< Real > > Octree< Real >::_getValueAndGradient( const LocalDepth d = _localDepth( node ); for( int dd=0 ; dd<3 ; dd++ ) - if ( p[dd]==0 ) p[dd] = (Real)(0.+1e-6); - else if( p[dd]==1 ) p[dd] = (Real)(1.-1e-6); + if ( p[dd]==0 ) + p[dd] = (Real)(0.+1e-6); + else if( p[dd]==1 ) + p[dd] = (Real)(1.-1e-6); + { + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); + + for( int i=0 ; i& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); + const TreeOctNode* _n = neighbors.neighbors[i][j][k]; + if( _isValidFEMNode( _n ) ) + { + int _pIdx[3]; + Point3D< Real > _s ; Real _w; + _startAndWidth( _n , _s , _w ); + int _fIdx[3]; + functionIndex< FEMDegree , BType >( _n , _fIdx ); + for( int dd=0 ; dd<3 ; dd++ ) _pIdx[dd] = std::max< int >( 0 , std::min< int >( SupportSize-1 , LeftSupportRadius + (int)floor( ( p[dd]-_s[dd] ) / _w ) ) ); + value += + solution[ _n->nodeData.nodeIndex ] * + (Real) + ( + evaluator._bsData->baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData->baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData->baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) + ); + gradient += + Point3D< Real > + ( + evaluator._bsData->dBaseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData-> baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData-> baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) , + evaluator._bsData-> baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData->dBaseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData-> baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) , + evaluator._bsData-> baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData-> baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData->dBaseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) + ) * solution[ _n->nodeData.nodeIndex ]; + } + } + if( d>0 ) + { + const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node->parent ); for( int i=0 ; i > Octree< Real >::_getValueAndGradient( const int _fIdx[3]; functionIndex< FEMDegree , BType >( _n , _fIdx ); for( int dd=0 ; dd<3 ; dd++ ) _pIdx[dd] = std::max< int >( 0 , std::min< int >( SupportSize-1 , LeftSupportRadius + (int)floor( ( p[dd]-_s[dd] ) / _w ) ) ); - value += - solution[ _n->nodeData.nodeIndex ] * - (Real) - ( - evaluator._bsData->baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData->baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData->baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) - ); - gradient += - Point3D< Real > - ( - evaluator._bsData->dBaseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData-> baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData-> baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) , - evaluator._bsData-> baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData->dBaseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData-> baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) , - evaluator._bsData-> baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData-> baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData->dBaseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) - ) * solution[ _n->nodeData.nodeIndex ]; - } - } - if( d>0 ) - { - const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node->parent ); - for( int i=0 ; i _s ; Real _w; - _startAndWidth( _n , _s , _w ); - int _fIdx[3]; - functionIndex< FEMDegree , BType >( _n , _fIdx ); - for( int dd=0 ; dd<3 ; dd++ ) _pIdx[dd] = std::max< int >( 0 , std::min< int >( SupportSize-1 , LeftSupportRadius + (int)floor( ( p[dd]-_s[dd] ) / _w ) ) ); - value += - coarseSolution[ _n->nodeData.nodeIndex ] * - (Real) - ( - evaluator._bsData->baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData->baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData->baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) - ); - gradient += - Point3D< Real > - ( - evaluator._bsData->dBaseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData-> baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData-> baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) , - evaluator._bsData-> baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData->dBaseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData-> baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) , - evaluator._bsData-> baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData-> baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData->dBaseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) - ) * coarseSolution[ _n->nodeData.nodeIndex ]; - } + value += + coarseSolution[ _n->nodeData.nodeIndex ] * + (Real) + ( + evaluator._bsData->baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData->baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData->baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) + ); + gradient += + Point3D< Real > + ( + evaluator._bsData->dBaseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData-> baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData-> baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) , + evaluator._bsData-> baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData->dBaseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData-> baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) , + evaluator._bsData-> baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData-> baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData->dBaseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) + ) * coarseSolution[ _n->nodeData.nodeIndex ]; } } } - return std::pair< Real , Point3D< Real > >( value , gradient ); + } + return std::pair< Real , Point3D< Real > >( value , gradient ); } template< class Real > template< class V , int FEMDegree , BoundaryType BType > @@ -1123,7 +1128,7 @@ std::pair< Real , Point3D< Real > > Octree< Real >::_getCornerValueAndGradient( } template< class Real > template< int Degree , BoundaryType BType > -Octree< Real >::MultiThreadedEvaluator< Degree , BType >::MultiThreadedEvaluator( const Octree< Real >* tree , const DenseNodeData< Real , Degree >& coefficients , int threads ) : _coefficients( coefficients ) , _tree( tree ) +Octree< Real >::MultiThreadedEvaluator< Degree , BType >::MultiThreadedEvaluator( const Octree< Real >* tree , const DenseNodeData< Real , Degree >& coefficients , int threads ) : _tree( tree ), _coefficients( coefficients ) { _threads = std::max< int >( 1 , threads ); _neighborKeys.resize( _threads ); diff --git a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.SortedTreeNodes.inl b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.SortedTreeNodes.inl index 7efc9f879..721d006c8 100755 --- a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.SortedTreeNodes.inl +++ b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.SortedTreeNodes.inl @@ -26,6 +26,7 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ +#include "MultiGridOctreeData.h" ///////////////////// // SortedTreeNodes // ///////////////////// @@ -81,7 +82,8 @@ void SortedTreeNodes::set( TreeOctNode& root ) for( int l=0 ; l<_levels ; l++ ) { _sliceStart[l][0] = levelOffset; - for( int s=0 ; s<((size_t)1<::template ConstNeighborKey< 1 , 1 > ConstAdjacenctNodeKey; - if( offset<0 || offset>((size_t)1<(int)((size_t)1< span( _sliceStart[depth][ std::max< int >( 0 , offset-1 ) ] , _sliceStart[depth][ std::min< int >( (size_t)1< neighborKeys( std::max< int >( 1 , threads ) ); for( size_t i=0 ; i::template ConstNeighborKey< 1 , 1 > ConstAdjacenctNodeKey; - if( offset<0 || offset>=((size_t)1<=(int)((size_t)1< span( _sliceStart[depth][offset] , _sliceStart[depth][offset+1] ); @@ -291,20 +293,19 @@ void SortedTreeNodes::setXSliceTableData( XSliceTableData& sData , int depth , i int d , off[3]; node->depthAndOffset( d , off ); // Process the edges - int o=2; for( int x=0 ; x<2 ; x++ ) for( int y=0 ; y<2 ; y++ ) { int fc = Square::CornerIndex( x , y ); bool edgeOwner = true; int ac = Square::AntipodalCornerIndex( Square::CornerIndex( x , y ) ); - for( int cc=0 ; cc struct _ConstraintCalculator_ { @@ -41,7 +43,7 @@ struct _ConstraintCalculator_ template< class Real , int Degree > struct _ConstraintCalculator_< Real , Degree , false > { - static inline Real _CalculateConstraint_( const PointData< Real , false >& p , const Polynomial< Degree >& px , const Polynomial< Degree >& py , const Polynomial< Degree >& pz , const Polynomial< Degree >& dpx , const Polynomial< Degree >& dpy , const Polynomial< Degree >& dpz , Real valueWeight , Real gradientWeight ) + static inline Real _CalculateConstraint_( const PointData< Real , false >& p , const Polynomial< Degree >& px , const Polynomial< Degree >& py , const Polynomial< Degree >& pz , const Polynomial< Degree >& , const Polynomial< Degree >& , const Polynomial< Degree >& , Real valueWeight , Real ) { #if POINT_DATA_RES Real constraint = 0; @@ -1383,7 +1385,7 @@ int Octree< Real >::_solveSystemGS( const FEMSystemFunctor& F , const BSplineDat // Compute the multicolor indices if( iters && frontSlice>=sliceBegin && frontSlice( _sNodesBegin( depth , s ) , _sNodesEnd( depth , s ) , __mcIndices[__s] ); } @@ -1737,7 +1739,6 @@ DenseNodeData< Real , FEMDegree > Octree< Real >::solveSystem( const FEMSystemFu BSplineData< FEMDegree , BType > bsData( maxSolveDepth ); maxSolveDepth = std::min< LocalDepth >( maxSolveDepth , _maxDepth ); - int iter = 0; const int _iters = std::max< int >( 0 , solverInfo.iters ); DenseNodeData< Real , FEMDegree > solution( _sNodesEnd( _maxDepth ) ); @@ -1749,14 +1750,14 @@ DenseNodeData< Real , FEMDegree > Octree< Real >::solveSystem( const FEMSystemFu { int iters = (int)ceil( _iters * pow( solverInfo.lowResIterMultiplier , maxSolveDepth-d ) ); _SolverStats sStats; - if( !d ) iter = _solveSystemCG( F , bsData , interpolationInfo , d , solution , constraints , metSolution , _sNodesSize(d) , true , sStats , solverInfo.showResidual , 0 ); + if( !d ) _solveSystemCG( F , bsData , interpolationInfo , d , solution , constraints , metSolution , _sNodesSize(d) , true , sStats , solverInfo.showResidual , 0 ); else { - if( d>solverInfo.cgDepth ) iter = _solveSystemGS( F , bsData , interpolationInfo , d , solution , constraints , metSolution , iters , true , sStats , solverInfo.showResidual ); - else iter = _solveSystemCG( F , bsData , interpolationInfo , d , solution , constraints , metSolution , iters , true , sStats , solverInfo.showResidual , solverInfo.cgAccuracy ); + if( d>solverInfo.cgDepth ) _solveSystemGS( F , bsData , interpolationInfo , d , solution , constraints , metSolution , iters , true , sStats , solverInfo.showResidual ); + else _solveSystemCG( F , bsData , interpolationInfo , d , solution , constraints , metSolution , iters , true , sStats , solverInfo.showResidual , solverInfo.cgAccuracy ); } int femNodes = 0; -#pragma omp parallel for reduction( + : femNodes ) + #pragma omp parallel for reduction( + : femNodes ) for( int i=_sNodesBegin(d) ; i<_sNodesEnd(d) ; i++ ) if( _isValidFEMNode( _sNodes.treeNodes[i] ) ) femNodes++; if( solverInfo.verbose ) { @@ -1825,7 +1826,7 @@ void Octree< Real >::_addFEMConstraints( const FEMConstraintFunctor& F , const C std::vector< SupportKey > neighborKeys( std::max< int >( 1 , threads ) ); for( size_t i=0 ; i::_addFEMConstraints( const FEMConstraintFunctor& F , const C if( isValidFEMNode< CDegree , CBType >( _node ) ) { const D* d = coefficients( _node ); - if( d ) + if( d ) { if( isInterior ) { constraints[i] += _Dot( (D)stencil( x , y , z ) , *d ); } else { @@ -1855,6 +1856,7 @@ void Octree< Real >::_addFEMConstraints( const FEMConstraintFunctor& F , const C _localDepthAndOffset( _node , _d , _off ); constraints[i] += _Dot( *d , (D)F.template integrate< false >( integrator , _off , off ) ); } + } } } _SetParentOverlapBounds< CDegree , FEMDegree >( node , startX , endX , startY , endY , startZ , endZ ); @@ -1924,14 +1926,14 @@ void Octree< Real >::_addFEMConstraints( const FEMConstraintFunctor& F , const C // Compute the contribution from all coarser depths for( LocalDepth d=1 ; d<=maxDepth ; d++ ) { - size_t start = _sNodesBegin( d ) , end = _sNodesEnd( d ) , range = end - start; + size_t start = _sNodesBegin( d ) , end = _sNodesEnd( d ); Stencil< _D , CFEMOverlapSize > stencils[2][2][2]; typename SystemCoefficients< CDegree , CBType , FEMDegree , FEMBType >::ChildIntegrator childIntegrator; BSplineIntegrationData< CDegree , CBType , FEMDegree , FEMBType >::SetChildIntegrator( childIntegrator , d-1 ); SystemCoefficients< CDegree , CBType , FEMDegree , FEMBType >::template SetCentralConstraintStencils< false >( F , childIntegrator , stencils ); std::vector< SupportKey > neighborKeys( std::max< int >( 1 , threads ) ); for( size_t i=0 ; i::_dot( const DotFunctor& F , const InterpolationInfo< HasG { const TreeOctNode* _node = neighbors.neighbors[x][y][z]; const Real* _data2; - if( isValidFEMNode< FEMDegree2 , FEMBType2 >( _node ) && ( _data2=coefficients2( _node ) ) ) + if( isValidFEMNode< FEMDegree2 , FEMBType2 >( _node ) && ( _data2=coefficients2( _node ) ) ) { if( isInterior ) { dot += (*_data1) * (*_data2 ) * stencil( x , y , z ); } else { @@ -2078,6 +2080,7 @@ double Octree< Real >::_dot( const DotFunctor& F , const InterpolationInfo< HasG _localDepthAndOffset( _node , _d , _off ); dot += (*_data1) * (*_data2) * F.template integrate< false >( integrator , off , _off ); } + } } } } diff --git a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.WeightedSamples.inl b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.WeightedSamples.inl index 279d91b91..68bd365f9 100644 --- a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.WeightedSamples.inl +++ b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.WeightedSamples.inl @@ -26,6 +26,8 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ +#include "MultiGridOctreeData.h" + // evaluate the result of splatting along a plane and then evaluating at a point on the plane. template< int Degree > double GetScaleValue( void ) { @@ -163,7 +165,6 @@ Real Octree< Real >::_splatPointData( const DensityEstimator< WeightDegree >& de double dx; V _v; TreeOctNode* temp; - int cnt=0; double width; Point3D< Real > myCenter( (Real)0.5 , (Real)0.5 , (Real)0.5 ); Real myWidth = (Real)1.; diff --git a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.inl b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.inl index 6061abe00..4aedb4ee7 100755 --- a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.inl +++ b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.inl @@ -28,6 +28,9 @@ DAMAGE. #ifdef FAST_SET_UP #include #endif // FAST_SET_UP + +#include "MultiGridOctreeData.h" + #include #include "PointStream.h" #include "MemoryUsage.h" @@ -58,7 +61,7 @@ double Octree< Real >::memoryUsage( void ) return mem; } -template< class Real > Octree< Real >::Octree( void ) : threads(1) , _maxMemoryUsage(0) , _localMemoryUsage(0) +template< class Real > Octree< Real >::Octree( void ) : _maxMemoryUsage(0) , _localMemoryUsage(0), threads(1) { _tree = TreeOctNode::NewBrood( _NodeInitializer ); _tree->initChildren( _NodeInitializer ) , _spaceRoot = _tree->children; @@ -144,14 +147,22 @@ void Octree< Real >::_setFullDepth( TreeOctNode* node , LocalDepth depth ) const bool refine = false; LocalDepth d ; LocalOffset off; _localDepthAndOffset( node , d , off ); - if( d( node ) ) { refine = true; } - else if( !BSplineSupportSizes< Degree >::OutOfBounds( d , off[0] ) && !BSplineSupportSizes< Degree >::OutOfBounds( d , off[1] ) && !BSplineSupportSizes< Degree >::OutOfBounds( d , off[2] ) ) { refine = true; } - if( refine ) - { - if( !node->children ) node->initChildren( _NodeInitializer ); - for( int c=0 ; c( node->children+c , depth ); + if( d( node ) ) { + refine = true; + } + else if( !BSplineSupportSizes< Degree >::OutOfBounds( d , off[0] ) && !BSplineSupportSizes< Degree >::OutOfBounds( d , off[1] ) && !BSplineSupportSizes< Degree >::OutOfBounds( d , off[2] ) ) { + refine = true; + } + } + if( refine ) { + if( !node->children ) + node->initChildren( _NodeInitializer ); + for( unsigned int c=0 ; c( node->children+c , depth ); } } template< class Real > @@ -159,7 +170,8 @@ template< int Degree , BoundaryType BType > void Octree< Real >::_setFullDepth( LocalDepth depth ) { if( !_tree->children ) _tree->initChildren( _NodeInitializer ); - for( int c=0 ; c( _tree->children+c , depth ); + for( unsigned int c=0 ; c( _tree->children+c , depth ); } template< class Real , bool HasGradients > @@ -246,7 +258,7 @@ int Octree< Real >::init( OrientedPointStream< Real >& pointStream , LocalDepth } Real weight = (Real)( useConfidence ? len : 1. ); int nodeIndex = temp->nodeData.nodeIndex; - if( nodeIndex>=nodeToIndexMap.size() ) nodeToIndexMap.resize( nodeIndex+1 , -1 ); + if( (unsigned int)nodeIndex>=nodeToIndexMap.size() ) nodeToIndexMap.resize( nodeIndex+1 , -1 ); int idx = nodeToIndexMap[ nodeIndex ]; if( idx==-1 ) { @@ -282,14 +294,16 @@ typename Octree< Real >::template DensityEstimator< DensityDegree >* Octree< Rea #ifdef FAST_SET_UP std::vector< int > sampleMap( NodeCount() , -1 ); #pragma omp parallel for num_threads( threads ) - for( int i=0 ; i0 ) sampleMap[ samples[i].node->nodeData.nodeIndex ] = i; + for( unsigned int i=0 ; i0 ) + sampleMap[ samples[i].node->nodeData.nodeIndex ] = i; std::function< ProjectiveData< OrientedPoint3D< Real > , Real > ( TreeOctNode* ) > SetDensity = [&] ( TreeOctNode* node ) { ProjectiveData< OrientedPoint3D< Real > , Real > sample; LocalDepth d = _localDepth( node ); int idx = node->nodeData.nodeIndex; if( node->children ) - for( int c=0 ; c , Real > s = SetDensity( node->children + c ); if( d<=splatDepth && s.weight>0 ) @@ -300,7 +314,7 @@ typename Octree< Real >::template DensityEstimator< DensityDegree >* Octree< Rea } sample += s; } - else if( idx0 ) @@ -314,7 +328,7 @@ typename Octree< Real >::template DensityEstimator< DensityDegree >* Octree< Rea }; SetDensity( _spaceRoot ); #else // !FAST_SET_UP - for( int i=0 ; i , Real >& sample = samples[i].sample; @@ -332,7 +346,7 @@ typename Octree< Real >::template DensityEstimator< DensityDegree >* Octree< Rea } template< class Real > template< int NormalDegree , int DensityDegree > -SparseNodeData< Point3D< Real > , NormalDegree > Octree< Real >::setNormalField( const std::vector< PointSample >& samples , const DensityEstimator< DensityDegree >& density , Real& pointWeightSum , bool forceNeumann ) +SparseNodeData< Point3D< Real > , NormalDegree > Octree< Real >::setNormalField( const std::vector< PointSample >& samples , const DensityEstimator< DensityDegree >& density , Real& pointWeightSum , bool ) { LocalDepth maxDepth = _localMaxDepth( _tree ); PointSupportKey< DensityDegree > densityKey; @@ -342,7 +356,7 @@ SparseNodeData< Point3D< Real > , NormalDegree > Octree< Real >::setNormalField( Real weightSum = 0; pointWeightSum = 0; SparseNodeData< Point3D< Real > , NormalDegree > normalField; - for( int i=0 ; i , Real >& sample = samples[i].sample; if( sample.weight>0 ) @@ -368,7 +382,7 @@ SparseNodeData< ProjectiveData< Data , Real > , DataDegree > Octree< Real >::set densityKey.set( _localToGlobal( maxDepth ) ) , dataKey.set( _localToGlobal( maxDepth ) ); SparseNodeData< ProjectiveData< Data , Real > , DataDegree > dataField; - for( int i=0 ; i , Real >& sample = samples[i].sample; const ProjectiveData< Data , Real >& data = sampleData[i]; @@ -409,7 +423,10 @@ void Octree< Real >::inalizeForBroodedMultigrid( LocalDepth fullDepth , const Ha int corner = _depthOffset<=1 ? Cube::CORNERS-1 : 0; newSpaceRootParent[corner].children = _spaceRoot; oldSpaceRootParent->children = newSpaceRootParent; - for( int c=0 ; c::_clipTree( const HasDataFunctor& f ) for( TreeOctNode* temp=_tree->nextNode() ; temp ; temp=_tree->nextNode(temp) ) if( temp->children && _localDepth( temp )>=_fullDepth ) { bool hasData = false; - for( int c=0 ; cchildren + c ); - for( int c=0 ; cchildren+c , !hasData ); + for( unsigned int c=0 ; cchildren + c ); + for( unsigned int c=0 ; cchildren+c , !hasData ); } } @@ -482,7 +501,7 @@ bool Octree< Real >::_setInterpolationInfoFromChildren( TreeOctNode* node , Spar Point3D< Real > center; Real width; _centerAndWidth( node , center , width ); - for( int c=0 ; cchildren + c , interpolationInfo ) ) { const PointData< Real , HasGradients >& _pData = interpolationInfo[ node->children + c ]; @@ -495,7 +514,7 @@ bool Octree< Real >::_setInterpolationInfoFromChildren( TreeOctNode* node , Spar hasChildData = true; } #else // !POINT_DATA_RES - for( int c=0 ; cchildren + c , interpolationInfo ) ) { pData += interpolationInfo[ node->children + c ]; @@ -512,7 +531,7 @@ template< bool HasGradients > SparseNodeData< PointData< Real , HasGradients > , 0 > Octree< Real >::_densifyInterpolationInfo( const std::vector< PointSample >& samples , Real pointValue , int adaptiveExponent ) const { SparseNodeData< PointData< Real , HasGradients > , 0 > iInfo; - for( int i=0 ; i , Real >& pData = samples[i].sample; diff --git a/src/meshlabplugins/filter_screened_poisson/Src/Octree.inl b/src/meshlabplugins/filter_screened_poisson/Src/Octree.inl index 6ff14f994..31cb24d89 100755 --- a/src/meshlabplugins/filter_screened_poisson/Src/Octree.inl +++ b/src/meshlabplugins/filter_screened_poisson/Src/Octree.inl @@ -30,6 +30,7 @@ DAMAGE. #include #include #include +#include "Octree.h" ///////////// // OctNode // @@ -268,7 +269,7 @@ int OctNode< NodeData >::maxDepth(void) const{ if(!children){return 0;} else{ int c,d; - for(int i=0;ic){c=d;} } @@ -293,7 +294,7 @@ size_t OctNode< NodeData >::leaves( void ) const else { size_t c=0; - for( int i=0 ; i::maxDepthLeaves( int maxDepth ) const else { size_t c=0; - for( int i=0 ; i OctNode< NodeData >::Neighbors< Width >::Neighbors( void ){ clear(); } template< class NodeData > template< unsigned int Width > -void OctNode< NodeData >::Neighbors< Width >::clear( void ){ for( int i=0 ; i::Neighbors< Width >::clear( void ){ + for( unsigned int i=0 ; i OctNode< NodeData >::ConstNeighbors< Width >::ConstNeighbors( void ){ clear(); } template< class NodeData > template< unsigned int Width > -void OctNode< NodeData >::ConstNeighbors< Width >::clear( void ){ for( int i=0 ; i::ConstNeighbors< Width >::clear( void ){ + for( unsigned int i=0 ; icm.vn; } } while(m); - qDebug("TotalSize %i",_totalSize); + qDebug("TotalSize %lu",_totalSize); } ~MeshDocumentPointStream( void ){} @@ -253,14 +253,14 @@ public: Point3m nn(0,0,0); // do { - if((_curMesh==0) || (_curPos >= _curMesh->cm.vn) ) { + if((_curMesh==0) || (_curPos >= (std::size_t)_curMesh->cm.vn) ) { _curMesh = _md.nextVisibleMesh(_curMesh); _curPos = 0; } if(_curMesh==0) return false; - if(_curPos < _curMesh->cm.vn) { + if(_curPos < (std::size_t)_curMesh->cm.vn) { nn = _curMesh->cm.vert[_curPos].N(); Point3m tp = _curMesh->cm.Tr * _curMesh->cm.vert[_curPos].P(); Point4m np = _curMesh->cm.Tr * Point4m(nn[0],nn[1],nn[2],0); @@ -458,7 +458,7 @@ int _Execute( double valueSum = 0 , weightSum = 0; typename Octree< Real >::template MultiThreadedEvaluator< Degree , BType > evaluator( &tree , solution , pp.ThreadsVal ); #pragma omp parallel for num_threads( pp.ThreadsVal ) reduction( + : valueSum , weightSum ) - for( int j=0 ; jsize() ; j++ ) { + for( unsigned int j=0 ; jsize() ; j++ ) { ProjectiveData< OrientedPoint3D< Real > , Real >& sample = (*samples)[j].sample; Real w = sample.weight; if( w>0 ) weightSum += w , valueSum += evaluator.value( sample.data.p / sample.weight , omp_get_thread_num() , (*samples)[j].node ) * w; From cd3119fa05c7f47ab0d8a153b743b5b3d56c8173 Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Sun, 26 Apr 2020 12:27:21 +0200 Subject: [PATCH 5/8] other warnings and cleanups --- .../filter_screened_poisson/Src/Allocator.h | 3 ++- .../filter_screened_poisson/Src/Array.h | 4 ++-- .../Src/MultiGridOctreeData.Evaluation.inl | 14 +++++------ .../Src/MultiGridOctreeData.IsoSurface.inl | 11 +++++---- .../Src/MultiGridOctreeData.System.inl | 16 ++++++------- .../Src/MultiGridOctreeData.h | 2 +- .../Src/MultiGridOctreeData.inl | 24 ++++++++++++++----- .../filter_screened_poisson/poisson_utils.h | 2 +- 8 files changed, 46 insertions(+), 30 deletions(-) diff --git a/src/meshlabplugins/filter_screened_poisson/Src/Allocator.h b/src/meshlabplugins/filter_screened_poisson/Src/Allocator.h index 3ba23d9d6..eb074095c 100755 --- a/src/meshlabplugins/filter_screened_poisson/Src/Allocator.h +++ b/src/meshlabplugins/filter_screened_poisson/Src/Allocator.h @@ -30,6 +30,7 @@ DAMAGE. #define ALLOCATOR_INCLUDED #include +#include class AllocatorState { @@ -148,7 +149,7 @@ public: if( elements>blockSize ) fprintf( stderr , "[ERROR] Allocator: elements bigger than block-size: %d>%d\n" , elements , blockSize ) , exit( 0 ); if( remains const C* GetPointer( const C& c ){ return &c; } template< class C > C* GetPointer( std::vector< C >& v ){ return &v[0]; } template< class C > const C* GetPointer( const std::vector< C >& v ){ return &v[0]; } -template< class C > C* GetPointer( C* c , int sz ) { return c; } -template< class C > const C* GetPointer( const C* c , int sz ) { return c; } +template< class C > C* GetPointer( C* c , int ) { return c; } +template< class C > const C* GetPointer( const C* c , int ) { return c; } #endif // ARRAY_DEBUG #endif // ARRAY_INCLUDED diff --git a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.Evaluation.inl b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.Evaluation.inl index a4f57e94f..1926977d1 100644 --- a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.Evaluation.inl +++ b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.Evaluation.inl @@ -57,7 +57,7 @@ void Octree< Real >::_Evaluator< FEMDegree , BType >::set( LocalDepth depth ) } //// The face stencil - for( int f=0 ; f::_Evaluator< FEMDegree , BType >::set( LocalDepth depth ) } //// The edge stencil - for( int e=0 ; e::_Evaluator< FEMDegree , BType >::set( LocalDepth depth ) } //// The corner stencil - for( int c=0 ; c::_Evaluator< FEMDegree , BType >::set( LocalDepth depth ) } //// The face stencil - for( int f=0 ; f::_Evaluator< FEMDegree , BType >::set( LocalDepth depth ) } //// The edge stencil - for( int e=0 ; e::_Evaluator< FEMDegree , BType >::set( LocalDepth depth ) } //// The corner stencil - for( int c=0 ; c::_getValue( const ConstPointSupportKey< FEMDegree >& neighborKe { static const int SupportSize = BSplineSupportSizes< FEMDegree >::SupportSize; static const int LeftSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; - static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + //static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; static const int RightPointSupportRadius = - BSplineSupportSizes< FEMDegree >::SupportStart; diff --git a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.IsoSurface.inl b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.IsoSurface.inl index 2be26dc51..fb8500208 100755 --- a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.IsoSurface.inl +++ b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.IsoSurface.inl @@ -26,6 +26,8 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ +#include "MultiGridOctreeData.h" + #include "Octree.h" #include "MyTime.h" #include "MemoryUsage.h" @@ -762,11 +764,11 @@ void Octree< Real >::_setIsoSurface( LocalDepth depth , int offset , const _Slic if( inBounds && !IsActiveNode( leaf->children ) ) { edges.clear(); - unsigned char mcIndex = ( bValues.mcIndices[ i - bValues.sliceData.nodeOffset ] ) | ( fValues.mcIndices[ i - fValues.sliceData.nodeOffset ]<<4 ); + //unsigned char mcIndex = ( bValues.mcIndices[ i - bValues.sliceData.nodeOffset ] ) | ( fValues.mcIndices[ i - fValues.sliceData.nodeOffset ]<<4 ); // [WARNING] Just because the node looks empty doesn't mean it doesn't get eges from finer neighbors { // Gather the edges from the faces (with the correct orientation) - for( int f=0 ; f::_setIsoSurface( LocalDepth depth , int offset , const _Slic long long start = edge[0] , current = edge[1]; while( current!=start ) { - int idx; - for( idx=0 ; idx<(int)edges.size() ; idx++ ) if( edges[idx][0]==current ) break; + unsigned int idx; + for( idx=0 ; idx::const_iterator iter; diff --git a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.System.inl b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.System.inl index be2140283..223358157 100644 --- a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.System.inl +++ b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.System.inl @@ -545,7 +545,7 @@ void Octree< Real >::_upSample( LocalDepth highDepth , DenseNodeData< C , FEMDeg static const int DownSampleSize = BSplineSupportSizes< FEMDegree >::DownSample0Size > BSplineSupportSizes< FEMDegree >::DownSample1Size ? BSplineSupportSizes< FEMDegree >::DownSample0Size : BSplineSupportSizes< FEMDegree >::DownSample1Size; Stencil< double , DownSampleSize > downSampleStencils[ Cube::CORNERS ]; int lowCenter = ( 1<>1; - for( int c=0 ; c::_updateCumulativeInterpolationConstraintsFromFiner( const I static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; static const int RightPointSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; static const int LeftSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; - static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + //static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; // Note: We can't iterate over the finer point nodes as the point weights might be // scaled incorrectly, due to the adaptive exponent. So instead, we will iterate // over the coarser nodes and evaluate the finer solution at the associated points. LocalDepth lowDepth = highDepth-1; if( lowDepth<0 ) return; - size_t start = _sNodesBegin(lowDepth) , end = _sNodesEnd(lowDepth); + //size_t start = _sNodesBegin(lowDepth) , end = _sNodesEnd(lowDepth); std::vector< PointSupportKey< FEMDegree > > neighborKeys( std::max< int >( 1 , threads ) ); for( size_t i=0 ; i::_getSliceMatrixAndUpdateConstraints( const FEMSystemFunctor& } } #if !defined( _WIN32 ) && !defined( _WIN64 ) -#pragma message( "[WARNING] I'm not sure how expensive this system call is on non-Windows system. (You may want to comment this out.)" ) +//#pragma message( "[WARNING] I'm not sure how expensive this system call is on non-Windows system. (You may want to comment this out.)" ) #endif // !_WIN32 && !_WIN64 memoryUsage(); return 1; @@ -1638,7 +1638,7 @@ void Octree< Real >::_updateConstraintsFromCoarser( const FEMSystemFunctor& F , // Given the solution @( depth ) add to the met constraints @( depth-1 ) template< class Real > template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor > -void Octree< Real >::_updateCumulativeIntegralConstraintsFromFiner( const FEMSystemFunctor& F , const BSplineData< FEMDegree , BType >& bsData , LocalDepth highDepth , const DenseNodeData< Real , FEMDegree >& fineSolution , DenseNodeData< Real , FEMDegree >& coarseConstraints ) const +void Octree< Real >::_updateCumulativeIntegralConstraintsFromFiner( const FEMSystemFunctor& F , const BSplineData< FEMDegree , BType >& , LocalDepth highDepth , const DenseNodeData< Real , FEMDegree >& fineSolution , DenseNodeData< Real , FEMDegree >& coarseConstraints ) const { typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template ChildIntegrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) > childIntegrator; BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::SetChildIntegrator( childIntegrator , highDepth-1 ); @@ -1651,8 +1651,8 @@ void Octree< Real >::_updateCumulativeIntegralConstraintsFromFiner( const FEMSys // Get the stencil describing the Laplacian relating coefficients @(depth) with coefficients @(depth-1) Stencil< double , OverlapSize > stencils[2][2][2]; SystemCoefficients< FEMDegree , BType , FEMDegree , BType >::SetCentralSystemStencils( F , childIntegrator , stencils ); - size_t start = _sNodesBegin( highDepth) , end = _sNodesEnd(highDepth) , range = end-start; - int lStart = _sNodesBegin(highDepth-1); + size_t start = _sNodesBegin( highDepth) , end = _sNodesEnd(highDepth) ; + //int lStart = _sNodesBegin(highDepth-1); // Iterate over the nodes @( depth ) std::vector< SupportKey > neighborKeys( std::max< int >( 1 , threads ) ); @@ -1926,7 +1926,7 @@ void Octree< Real >::_addFEMConstraints( const FEMConstraintFunctor& F , const C // Compute the contribution from all coarser depths for( LocalDepth d=1 ; d<=maxDepth ; d++ ) { - size_t start = _sNodesBegin( d ) , end = _sNodesEnd( d ); + //size_t start = _sNodesBegin( d ) , end = _sNodesEnd( d ); Stencil< _D , CFEMOverlapSize > stencils[2][2][2]; typename SystemCoefficients< CDegree , CBType , FEMDegree , FEMBType >::ChildIntegrator childIntegrator; BSplineIntegrationData< CDegree , CBType , FEMDegree , FEMBType >::SetChildIntegrator( childIntegrator , d-1 ); diff --git a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.h b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.h index b5aa80825..ab3e72cb1 100755 --- a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.h +++ b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.h @@ -692,7 +692,7 @@ public: const Point3D< Real >& normal = *n; if( normal[0]!=0 || normal[1]!=0 || normal[2]!=0 ) return true; } - if( node->children ) for( int c=0 ; cchildren + c ) ) return true; + if( node->children ) for( unsigned int c=0 ; cchildren + c ) ) return true; return false; } }; diff --git a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.inl b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.inl index 4aedb4ee7..0a93d14cb 100755 --- a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.inl +++ b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.inl @@ -187,18 +187,30 @@ template< class Real > struct _PointDataAccumulator_< Real , false > { #if POINT_DATA_RES - static inline void _AddToPointData_( PointData< Real , false >& pData , Point3D< Real > position , Real value , Point3D< Real > gradient , Point3D< Real > center , Real width , Real weight ){ pData.addPoint( SinglePointData< Real , false >( position , value , weight ) , center , width ); } + static inline void _AddToPointData_( PointData< Real , false >& pData , Point3D< Real > position , Real value , Point3D< Real > , Point3D< Real > center , Real width , Real weight ) + { + pData.addPoint( SinglePointData< Real , false >( position , value , weight ) , center , width ); + } #else // !POINT_DATA_RES - static inline void _AddToPointData_( PointData< Real , false >& pData , Point3D< Real > position , Real value , Point3D< Real > gradient , Real weight ){ pData.position += position , pData.value += value , pData.weight += weight; } + static inline void _AddToPointData_( PointData< Real , false >& pData , Point3D< Real > position , Real value , Point3D< Real > , Real weight ) + { + pData.position += position , pData.value += value , pData.weight += weight; + } #endif // POINT_DATA_RES }; template< class Real > struct _PointDataAccumulator_< Real , true > { #if POINT_DATA_RES - static inline void _AddToPointData_( PointData< Real , true >& pData , Point3D< Real > position , Real value , Point3D< Real > gradient , Point3D< Real > center , Real width , Real weight ){ pData.addPoint( SinglePointData< Real , true >( position , value , gradient , weight ) , center , width ); } + static inline void _AddToPointData_( PointData< Real , true >& pData , Point3D< Real > position , Real value , Point3D< Real > gradient , Point3D< Real > center , Real width , Real weight ) + { + pData.addPoint( SinglePointData< Real , true >( position , value , gradient , weight ) , center , width ); + } #else // !POINT_DATA_RES - static inline void _AddToPointData_( PointData< Real , true >& pData , Point3D< Real > position , Real value , Point3D< Real > gradient , Real weight ){ pData.position += position , pData.value += value , pData.gradient += gradient , pData.weight += weight; } + static inline void _AddToPointData_( PointData< Real , true >& pData , Point3D< Real > position , Real value , Point3D< Real > gradient , Real weight ) + { + pData.position += position , pData.value += value , pData.gradient += gradient , pData.weight += weight; + } #endif // POINT_DATA_RES }; @@ -294,7 +306,7 @@ typename Octree< Real >::template DensityEstimator< DensityDegree >* Octree< Rea #ifdef FAST_SET_UP std::vector< int > sampleMap( NodeCount() , -1 ); #pragma omp parallel for num_threads( threads ) - for( unsigned int i=0 ; i0 ) sampleMap[ samples[i].node->nodeData.nodeIndex ] = i; std::function< ProjectiveData< OrientedPoint3D< Real > , Real > ( TreeOctNode* ) > SetDensity = [&] ( TreeOctNode* node ) @@ -328,7 +340,7 @@ typename Octree< Real >::template DensityEstimator< DensityDegree >* Octree< Rea }; SetDensity( _spaceRoot ); #else // !FAST_SET_UP - for( unsigned int i=0 ; i , Real >& sample = samples[i].sample; diff --git a/src/meshlabplugins/filter_screened_poisson/poisson_utils.h b/src/meshlabplugins/filter_screened_poisson/poisson_utils.h index 6c8fccf0c..683f6cd74 100644 --- a/src/meshlabplugins/filter_screened_poisson/poisson_utils.h +++ b/src/meshlabplugins/filter_screened_poisson/poisson_utils.h @@ -458,7 +458,7 @@ int _Execute( double valueSum = 0 , weightSum = 0; typename Octree< Real >::template MultiThreadedEvaluator< Degree , BType > evaluator( &tree , solution , pp.ThreadsVal ); #pragma omp parallel for num_threads( pp.ThreadsVal ) reduction( + : valueSum , weightSum ) - for( unsigned int j=0 ; jsize() ; j++ ) { + for( int j=0 ; j<(int)samples->size() ; j++ ) { ProjectiveData< OrientedPoint3D< Real > , Real >& sample = (*samples)[j].sample; Real w = sample.weight; if( w>0 ) weightSum += w , valueSum += evaluator.value( sample.data.p / sample.weight , omp_get_thread_num() , (*samples)[j].node ) * w; From 6275641cff9b2c524fc83ae97b4f6716c0f75094 Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Sun, 26 Apr 2020 12:42:38 +0200 Subject: [PATCH 6/8] final poisson cleanups --- .../Src/BSplineData.inl | 20 ++++++++++--- .../filter_screened_poisson/Src/MAT.inl | 5 +++- .../Src/MultiGridOctreeData.Evaluation.inl | 8 +++--- .../Src/MultiGridOctreeData.IsoSurface.inl | 12 ++++---- .../Src/MultiGridOctreeData.System.inl | 28 +++++++++++-------- .../filter_screened_poisson/poisson_utils.h | 2 +- 6 files changed, 49 insertions(+), 26 deletions(-) diff --git a/src/meshlabplugins/filter_screened_poisson/Src/BSplineData.inl b/src/meshlabplugins/filter_screened_poisson/Src/BSplineData.inl index 225fed8f4..e5afce95c 100755 --- a/src/meshlabplugins/filter_screened_poisson/Src/BSplineData.inl +++ b/src/meshlabplugins/filter_screened_poisson/Src/BSplineData.inl @@ -458,10 +458,22 @@ BSplineElements< Degree >::BSplineElements( int res , int offset , BoundaryType _addPeriodic< true >( _ReflectLeft( offset , res ) , bType==BOUNDARY_DIRICHLET ) , _addPeriodic< false >( _ReflectRight( offset , res ) , bType==BOUNDARY_DIRICHLET ); } } -template< int Degree > int BSplineElements< Degree >::_ReflectLeft ( int offset , int res ){ return (Degree&1) ? -offset : -1-offset; } -template< int Degree > int BSplineElements< Degree >::_ReflectRight( int offset , int res ){ return (Degree&1) ? 2*res-offset : 2*res-1-offset; } -template< int Degree > int BSplineElements< Degree >::_RotateLeft ( int offset , int res ){ return offset-2*res; } -template< int Degree > int BSplineElements< Degree >::_RotateRight ( int offset , int res ){ return offset+2*res; } +template< int Degree > int BSplineElements< Degree >::_ReflectLeft ( int offset , int ) +{ + return (Degree&1) ? -offset : -1-offset; +} +template< int Degree > int BSplineElements< Degree >::_ReflectRight( int offset , int res ) +{ + return (Degree&1) ? 2*res-offset : 2*res-1-offset; +} +template< int Degree > int BSplineElements< Degree >::_RotateLeft ( int offset , int res ) +{ + return offset-2*res; +} +template< int Degree > int BSplineElements< Degree >::_RotateRight ( int offset , int res ) +{ + return offset+2*res; +} template< int Degree > template< bool Left > diff --git a/src/meshlabplugins/filter_screened_poisson/Src/MAT.inl b/src/meshlabplugins/filter_screened_poisson/Src/MAT.inl index 5106659fd..63893e709 100755 --- a/src/meshlabplugins/filter_screened_poisson/Src/MAT.inl +++ b/src/meshlabplugins/filter_screened_poisson/Src/MAT.inl @@ -28,6 +28,9 @@ DAMAGE. ////////////////////////////// // MinimalAreaTriangulation // ////////////////////////////// + +#include "MAT.h" + template MinimalAreaTriangulation::MinimalAreaTriangulation(void) { @@ -143,7 +146,7 @@ void MinimalAreaTriangulation::GetTriangulation(const size_t& i,const size size_t ii=i; if( i=ii ) + if( j+1>=(unsigned int)ii ) return; ii=midPoint[i*eCount+j]; if( ii>=0 ) diff --git a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.Evaluation.inl b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.Evaluation.inl index 1926977d1..1731c16fa 100644 --- a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.Evaluation.inl +++ b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.Evaluation.inl @@ -61,7 +61,7 @@ void Octree< Real >::_Evaluator< FEMDegree , BType >::set( LocalDepth depth ) { int dir , off; Cube::FactorFaceIndex( f , dir , off ); - double vv[3] , dv[3]; + double vv[3] = {0,0,0} , dv[3]={0,0,0}; switch( dir ) { case 0: @@ -98,7 +98,7 @@ void Octree< Real >::_Evaluator< FEMDegree , BType >::set( LocalDepth depth ) { int orientation , i1 , i2; Cube::FactorEdgeIndex( e , orientation , i1 , i2 ); - double vv[3] , dv[3]; + double vv[3] = {0,0,0}, dv[3] = {0,0,0}; switch( orientation ) { case 0: @@ -174,7 +174,7 @@ void Octree< Real >::_Evaluator< FEMDegree , BType >::set( LocalDepth depth ) { int dir , off; Cube::FactorFaceIndex( f , dir , off ); - double vv[3] , dv[3]; + double vv[3] = {0,0,0}, dv[3] = {0,0,0}; switch( dir ) { case 0: @@ -211,7 +211,7 @@ void Octree< Real >::_Evaluator< FEMDegree , BType >::set( LocalDepth depth ) { int orientation , i1 , i2; Cube::FactorEdgeIndex( e , orientation , i1 , i2 ); - double vv[3] , dv[3]; + double vv[3] = {0,0,0} , dv[3]={0,0,0}; switch( orientation ) { case 0: diff --git a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.IsoSurface.inl b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.IsoSurface.inl index fb8500208..d60e230ba 100755 --- a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.IsoSurface.inl +++ b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.IsoSurface.inl @@ -318,7 +318,7 @@ void Octree< Real >::_setSliceIsoVertices( const BSplineData< ColorDegree , BTyp neighborKey.getNeighbors( leaf ); if( densityWeights ) weightKey.getNeighbors( leaf ); if( colorData ) colorKey.getNeighbors( leaf ); - for( int e=0 ; e::_setSliceIsoVertices( const BSplineData< ColorDegree , BTyp if( stillOwner ) { // We only need to pass the iso-vertex down if the edge it lies on is adjacent to a coarser leaf - bool isNeeded; + bool isNeeded = false; switch( o ) { case 0: isNeeded = ( !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[1][2*y][1] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[1][2*y][2*z] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[1][1][2*z] ) ) ; break; @@ -1053,12 +1053,14 @@ int Octree< Real >::_addIsoPolygons( CoredMeshData< Vertex >& mesh , std::vector std::vector< int > triangle( 3 ); if( addBarycenter ) - for( int i=0 ; i<(int)polygon.size() ; i++ ) - for( int j=0 ; j return (Real)( px( q[0] ) * py( q[1] ) * pz( q[2] ) * p.weight * p.value ) * valueWeight; #endif // POINT_DATA_RES } - static inline Real _CalculateConstraint_( const PointData< Real , false >& p , const Polynomial< Degree >& px , const Polynomial< Degree >& py , const Polynomial< Degree >& pz , const Polynomial< Degree >& dpx , const Polynomial< Degree >& dpy , const Polynomial< Degree >& dpz ) + static inline Real _CalculateConstraint_( const PointData< Real , false >& p , const Polynomial< Degree >& px , const Polynomial< Degree >& py , const Polynomial< Degree >& pz , const Polynomial< Degree >& , const Polynomial< Degree >& , const Polynomial< Degree >& ) { #if POINT_DATA_RES Real constraint = 0; @@ -74,9 +74,15 @@ struct _ConstraintCalculator_< Real , Degree , false > #endif // POINT_DATA_RES } #if POINT_DATA_RES - static inline void _CalculateCoarser_( int c , PointData< Real , false >& p , Real value , Point3D< Real > gradient , Real valueWeight , Real gradientWeight ){ p[c]._value = value * valueWeight * p[c].weight; } + static inline void _CalculateCoarser_( int c , PointData< Real , false >& p , Real value , Point3D< Real > , Real valueWeight , Real ) + { + p[c]._value = value * valueWeight * p[c].weight; + } #else // !POINT_DATA_RES - static inline void _CalculateCoarser_( PointData< Real , false >& p , Real value , Point3D< Real > gradient , Real valueWeight , Real gradientWeight ){ p._value = value * valueWeight * p.weight; } + static inline void _CalculateCoarser_( PointData< Real , false >& p , Real value , Point3D< Real > , Real valueWeight , Real ) + { + p._value = value * valueWeight * p.weight; + } #endif // POINT_DATA_RES }; template< class Real , int Degree > @@ -738,7 +744,7 @@ Real Octree< Real >::_coarserFunctionValue( Point3D< Real > p , const PointSuppo { static const int SupportSize = BSplineSupportSizes< FEMDegree >::SupportSize; static const int LeftSupportRadius = - BSplineSupportSizes< FEMDegree >::SupportStart; - static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + //static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; static const int RightPointSupportRadius = - BSplineSupportSizes< FEMDegree >::SupportStart; @@ -783,7 +789,7 @@ Point3D< Real > Octree< Real >::_coarserFunctionGradient( Point3D< Real > p , co { static const int SupportSize = BSplineSupportSizes< FEMDegree >::SupportSize; static const int LeftSupportRadius = - BSplineSupportSizes< FEMDegree >::SupportStart; - static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + //static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; static const int RightPointSupportRadius = - BSplineSupportSizes< FEMDegree >::SupportStart; @@ -843,7 +849,7 @@ Real Octree< Real >::_finerFunctionValue( Point3D< Real > p , const PointSupport static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; static const int RightPointSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; static const int LeftSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; - static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + //static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; double pointValue = 0; LocalDepth depth = _localDepth( pointNode ); @@ -874,7 +880,7 @@ Point3D< Real > Octree< Real >::_finerFunctionGradient( Point3D< Real > p , cons static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; static const int RightPointSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; static const int LeftSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; - static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; + //static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; Point3D< double > pointGradient = 0; LocalDepth depth = _localDepth( pointNode ); @@ -1128,8 +1134,8 @@ int Octree< Real >::_setMatrixRow( const FEMSystemFunctor& F , const Interpolati const TreeOctNode* _node = neighbors.neighbors[i+OverlapRadius][j+OverlapRadius][k+OverlapRadius]; if( _isValidSpaceNode( _node ) && (*interpolationInfo)( _node ) ) { - const PointData< Real , HasGradients >& pData = *( (*interpolationInfo)( _node ) ); #if POINT_DATA_RES + const PointData< Real , HasGradients >& pData = *( (*interpolationInfo)( _node ) ); for( int c=0 ; c::SAMPLES ; c++ ) if( pData[c].weight ) #endif // POINT_DATA_RES { @@ -1545,10 +1551,10 @@ template< int FEMDegree , BoundaryType BType > int Octree< Real >::_getMatrixRowSize( const typename TreeOctNode::Neighbors< BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& neighbors ) const { static const int OverlapSize = BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize; - static const int OverlapRadius = - BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapStart; + //static const int OverlapRadius = - BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapStart; int count = 0; - int nodeIndex = neighbors.neighbors[OverlapRadius][OverlapRadius][OverlapRadius]->nodeData.nodeIndex; + //int nodeIndex = neighbors.neighbors[OverlapRadius][OverlapRadius][OverlapRadius]->nodeData.nodeIndex; const TreeOctNode* const * _nodes = &neighbors.neighbors[0][0][0]; for( int i=0 ; i::_updateCumulativeIntegralConstraintsFromFiner( const FEMSys // Get the stencil describing the Laplacian relating coefficients @(depth) with coefficients @(depth-1) Stencil< double , OverlapSize > stencils[2][2][2]; SystemCoefficients< FEMDegree , BType , FEMDegree , BType >::SetCentralSystemStencils( F , childIntegrator , stencils ); - size_t start = _sNodesBegin( highDepth) , end = _sNodesEnd(highDepth) ; + //size_t start = _sNodesBegin( highDepth) , end = _sNodesEnd(highDepth) ; //int lStart = _sNodesBegin(highDepth-1); // Iterate over the nodes @( depth ) diff --git a/src/meshlabplugins/filter_screened_poisson/poisson_utils.h b/src/meshlabplugins/filter_screened_poisson/poisson_utils.h index 683f6cd74..60658a6da 100644 --- a/src/meshlabplugins/filter_screened_poisson/poisson_utils.h +++ b/src/meshlabplugins/filter_screened_poisson/poisson_utils.h @@ -200,7 +200,7 @@ public: bool nextPoint( OrientedPoint3D< Real >& pt, Point3m &d) { - if(_curPos>=_m.vn) + if(_curPos>=(unsigned int)_m.vn) return false; Point3m &nn = _m.vert[_curPos].N(); Point3m tp = _m.Tr * _m.vert[_curPos].P(); From f91a8d0e0229ddc1befd721088162e6fd7d3a09a Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Mon, 27 Apr 2020 16:23:26 +0200 Subject: [PATCH 7/8] fix missing pragma omp --- .../Src/MultiGridOctreeData.SortedTreeNodes.inl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.SortedTreeNodes.inl b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.SortedTreeNodes.inl index 721d006c8..99971a52c 100755 --- a/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.SortedTreeNodes.inl +++ b/src/meshlabplugins/filter_screened_poisson/Src/MultiGridOctreeData.SortedTreeNodes.inl @@ -250,7 +250,7 @@ void SortedTreeNodes::setSliceTableData( SliceTableData& sData , int depth , int for( size_t i=0 ; i Date: Wed, 29 Apr 2020 21:05:42 +0200 Subject: [PATCH 8/8] missing include --- src/meshlabplugins/filter_screened_poisson/Src/SparseMatrix.inl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/meshlabplugins/filter_screened_poisson/Src/SparseMatrix.inl b/src/meshlabplugins/filter_screened_poisson/Src/SparseMatrix.inl index 502f1a2fb..4d9f226fe 100755 --- a/src/meshlabplugins/filter_screened_poisson/Src/SparseMatrix.inl +++ b/src/meshlabplugins/filter_screened_poisson/Src/SparseMatrix.inl @@ -29,6 +29,7 @@ DAMAGE. #include #include +#include "SparseMatrix.h" /////////////////// // SparseMatrix //