From 86aede4f687cd02407fc3a6faf506542fe30c3f1 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Mon, 17 Apr 2023 22:20:05 -0400 Subject: [PATCH 01/86] Version 13.99 --- AdaptiveSolvers.sln | 13 +- AdaptiveTreeVisualization.vcxproj | 4 +- ChunkPLY.vcxproj | 3 +- EDTInHeat.vcxproj | 3 +- ImageStitching.vcxproj | 3 +- JPEG.vcxproj | 3 +- Makefile | 27 +- PNG.vcxproj | 7 +- PNG/PNG.vcxproj | 176 ++ PNG/PNG.vcxproj.filters | 84 + PointInterpolant.vcxproj | 4 +- PoissonRecon.vcxproj | 3 +- README.md | 19 +- SSDRecon.vcxproj | 3 +- Src/AdaptiveTreeVisualization.cpp | 100 +- Src/Allocator.h | 71 +- Src/Array.h | 9 +- Src/Array.inl | 20 +- Src/BSplineData.h | 1 + Src/BlockedVector.h | 123 +- Src/ChunkPLY.cpp | 9 +- Src/CmdLineParser.inl | 49 +- Src/CoredMesh.h | 285 --- Src/CoredMesh.inl | 239 --- Src/EDTInHeat.cpp | 133 +- Src/FEMTree.Evaluation.inl | 191 +- Src/FEMTree.Initialize.inl | 172 +- Src/FEMTree.IsoSurface.specialized.inl | 1906 -------------------- Src/FEMTree.LevelSet.2D.inl | 1072 ++++++++++++ Src/FEMTree.LevelSet.3D.inl | 2221 ++++++++++++++++++++++++ Src/FEMTree.LevelSet.inl | 829 +++++++++ Src/FEMTree.SortedTreeNodes.inl | 85 +- Src/FEMTree.System.inl | 55 +- Src/FEMTree.WeightedSamples.inl | 100 +- Src/FEMTree.h | 763 ++++++-- Src/FEMTree.inl | 1303 ++++++++++---- Src/Geometry.h | 44 +- Src/Image.h | 4 +- Src/ImageStitching.cpp | 64 +- Src/MarchingCubes.h | 7 + Src/MyMiscellany.h | 238 ++- Src/PNG.inl | 5 - Src/Ply.h | 11 +- Src/Ply.inl | 101 +- Src/PlyFile.h | 24 + Src/PlyFile.inl | 4 +- Src/PointInterpolant.cpp | 187 +- Src/PoissonRecon.cpp | 380 ++-- Src/PoissonRecon.h | 113 ++ Src/PreProcessor.h | 5 +- Src/RegularTree.h | 84 +- Src/RegularTree.inl | 350 ++-- Src/SSDRecon.cpp | 267 ++- Src/StreamingMesh.h | 286 +++ Src/StreamingMesh.inl | 266 +++ Src/Streams.h | 158 ++ Src/SurfaceTrimmer.cpp | 49 +- Src/VertexFactory.h | 167 +- Src/VertexFactory.inl | 16 +- Src/VertexStream.h | 27 +- Src/VertexStream.inl | 57 +- Src/Window.h | 9 + SurfaceTrimmer.vcxproj | 3 +- ZLIB.vcxproj | 3 +- 64 files changed, 8720 insertions(+), 4297 deletions(-) create mode 100644 PNG/PNG.vcxproj create mode 100644 PNG/PNG.vcxproj.filters delete mode 100644 Src/CoredMesh.h delete mode 100644 Src/CoredMesh.inl delete mode 100644 Src/FEMTree.IsoSurface.specialized.inl create mode 100644 Src/FEMTree.LevelSet.2D.inl create mode 100644 Src/FEMTree.LevelSet.3D.inl create mode 100644 Src/FEMTree.LevelSet.inl create mode 100644 Src/PoissonRecon.h create mode 100644 Src/StreamingMesh.h create mode 100644 Src/StreamingMesh.inl create mode 100644 Src/Streams.h diff --git a/AdaptiveSolvers.sln b/AdaptiveSolvers.sln index 1cb3462d..add656d9 100644 --- a/AdaptiveSolvers.sln +++ b/AdaptiveSolvers.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30309.148 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33424.131 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZLIB", "ZLIB.vcxproj", "{D3D173AB-D306-4179-BEC4-95CE1B14E647}" EndProject @@ -49,7 +49,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Header Files", "Header File Src\BlockedVector.h = Src\BlockedVector.h Src\BSplineData.h = Src\BSplineData.h Src\CmdLineParser.h = Src\CmdLineParser.h - Src\CoredMesh.h = Src\CoredMesh.h Src\Factor.h = Src\Factor.h Src\FEMTree.h = Src\FEMTree.h Src\FunctionData.h = Src\FunctionData.h @@ -63,6 +62,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Header Files", "Header File Src\Ply.h = Src\Ply.h Src\PlyFile.h = Src\PlyFile.h Src\PNG.h = Src\PNG.h + Src\PoissonRecon.h = Src\PoissonRecon.h Src\Polynomial.h = Src\Polynomial.h Src\PPolynomial.h = Src\PPolynomial.h Src\PreProcessor.h = Src\PreProcessor.h @@ -71,6 +71,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Header Files", "Header File Src\RegularTree.h = Src\RegularTree.h Src\SparseMatrix.h = Src\SparseMatrix.h Src\SparseMatrixInterface.h = Src\SparseMatrixInterface.h + Src\StreamingMesh.h = Src\StreamingMesh.h Src\VertexFactory.h = Src\VertexFactory.h Src\VertexStream.h = Src\VertexStream.h Src\Window.h = Src\Window.h @@ -82,11 +83,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Inline Files", "Inline File Src\BMPStream.inl = Src\BMPStream.inl Src\BSplineData.inl = Src\BSplineData.inl Src\CmdLineParser.inl = Src\CmdLineParser.inl - Src\CoredMesh.inl = Src\CoredMesh.inl Src\FEMTree.Evaluation.inl = Src\FEMTree.Evaluation.inl Src\FEMTree.Initialize.inl = Src\FEMTree.Initialize.inl Src\FEMTree.inl = Src\FEMTree.inl - Src\FEMTree.IsoSurface.specialized.inl = Src\FEMTree.IsoSurface.specialized.inl + Src\FEMTree.LevelSet.2D.inl = Src\FEMTree.LevelSet.2D.inl + Src\FEMTree.LevelSet.3D.inl = Src\FEMTree.LevelSet.3D.inl + Src\FEMTree.LevelSet.inl = Src\FEMTree.LevelSet.inl Src\FEMTree.SortedTreeNodes.inl = Src\FEMTree.SortedTreeNodes.inl Src\FEMTree.System.inl = Src\FEMTree.System.inl Src\FEMTree.WeightedSamples.inl = Src\FEMTree.WeightedSamples.inl @@ -104,6 +106,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Inline Files", "Inline File Src\RegularTree.inl = Src\RegularTree.inl Src\SparseMatrix.inl = Src\SparseMatrix.inl Src\SparseMatrixInterface.inl = Src\SparseMatrixInterface.inl + Src\StreamingMesh.inl = Src\StreamingMesh.inl Src\VertexFactory.inl = Src\VertexFactory.inl Src\VertexStream.inl = Src\VertexStream.inl Src\Window.inl = Src\Window.inl diff --git a/AdaptiveTreeVisualization.vcxproj b/AdaptiveTreeVisualization.vcxproj index a1880ea1..42ee0efc 100644 --- a/AdaptiveTreeVisualization.vcxproj +++ b/AdaptiveTreeVisualization.vcxproj @@ -50,7 +50,7 @@ Application false - v142 + v143 true Unicode @@ -106,6 +106,7 @@ Level3 Disabled _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + stdcpp17 Console @@ -143,6 +144,7 @@ . true + stdcpp17 Console diff --git a/ChunkPLY.vcxproj b/ChunkPLY.vcxproj index a2246e03..f245d0e9 100644 --- a/ChunkPLY.vcxproj +++ b/ChunkPLY.vcxproj @@ -51,7 +51,7 @@ Application false - v142 + v143 true Unicode @@ -100,6 +100,7 @@ pch.h . true + stdcpp17 Console diff --git a/EDTInHeat.vcxproj b/EDTInHeat.vcxproj index 647ee4c0..4b89ed10 100644 --- a/EDTInHeat.vcxproj +++ b/EDTInHeat.vcxproj @@ -50,7 +50,7 @@ Application false - v142 + v143 true Unicode @@ -143,6 +143,7 @@ true + stdcpp17 Console diff --git a/ImageStitching.vcxproj b/ImageStitching.vcxproj index cbb33dc0..8790825d 100644 --- a/ImageStitching.vcxproj +++ b/ImageStitching.vcxproj @@ -50,7 +50,7 @@ Application false - v142 + v143 true Unicode @@ -142,6 +142,7 @@ . true true + stdcpp17 Console diff --git a/JPEG.vcxproj b/JPEG.vcxproj index 7b563c54..22bb606b 100644 --- a/JPEG.vcxproj +++ b/JPEG.vcxproj @@ -111,7 +111,7 @@ false true Unicode - v142 + v143 @@ -188,6 +188,7 @@ WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) . true + stdcpp17 Windows diff --git a/Makefile b/Makefile index 6bd2a3be..f0d6c564 100644 --- a/Makefile +++ b/Makefile @@ -19,15 +19,19 @@ COMPILER ?= gcc #COMPILER ?= clang ifeq ($(COMPILER),gcc) - CFLAGS += -fopenmp -Wno-deprecated -std=c++14 -pthread -Wno-invalid-offsetof + CFLAGS += -fopenmp -Wno-deprecated -std=c++17 -pthread -Wno-invalid-offsetof + LFLAGS += -lgomp -lstdc++ -lpthread +else ifeq ($(COMPILER),gcc-11) + CFLAGS += -fopenmp -Wno-deprecated -std=c++17 -pthread -Wno-invalid-offsetof -Werror=strict-aliasing -Wno-nonnull LFLAGS += -lgomp -lstdc++ -lpthread else -# CFLAGS += -fopenmp=libiomp5 -Wno-deprecated -Wno-write-strings -std=c++14 -Wno-invalid-offsetof +# CFLAGS += -fopenmp=libiomp5 -Wno-deprecated -Wno-write-strings -std=c++17 -Wno-invalid-offsetof # LFLAGS += -liomp5 -lstdc++ - CFLAGS += -Wno-deprecated -std=c++14 -pthread -Wno-invalid-offsetof -Wno-dangling-else + CFLAGS += -Wno-deprecated -std=c++17 -pthread -Wno-invalid-offsetof -Wno-dangling-else LFLAGS += -lstdc++ endif -#LFLAGS += -lz -lpng -ljpeg +LFLAGS += -lz -lpng -ljpeg +#LFLAGS += -ljpeg -lmypng -lz CFLAGS_DEBUG = -DDEBUG -g3 LFLAGS_DEBUG = @@ -45,6 +49,9 @@ INCLUDE = . ifeq ($(COMPILER),gcc) CC=gcc CXX=g++ +else ifeq ($(COMPILER),gcc-11) + CC=gcc-11 + CXX=g++-11 else CC=clang CXX=clang++ @@ -151,15 +158,15 @@ make_dir: $(BIN)$(PR_TARGET): $(PR_OBJECTS) cd PNG && make COMPILER=$(COMPILER) - $(CXX) -pthread -o $@ $(PR_OBJECTS) -L$(BIN) $(LFLAGS) -ljpeg -lmypng -lz + $(CXX) -pthread -o $@ $(PR_OBJECTS) -L$(BIN) $(LFLAGS) $(BIN)$(SR_TARGET): $(SR_OBJECTS) cd PNG && make COMPILER=$(COMPILER) - $(CXX) -pthread -o $@ $(SR_OBJECTS) -L$(BIN) $(LFLAGS) -ljpeg -lmypng -lz + $(CXX) -pthread -o $@ $(SR_OBJECTS) -L$(BIN) $(LFLAGS) $(BIN)$(PI_TARGET): $(PI_OBJECTS) cd PNG && make COMPILER=$(COMPILER) - $(CXX) -pthread -o $@ $(PI_OBJECTS) -L$(BIN) $(LFLAGS) -ljpeg -lmypng -lz + $(CXX) -pthread -o $@ $(PI_OBJECTS) -L$(BIN) $(LFLAGS) $(BIN)$(ST_TARGET): $(ST_OBJECTS) $(CXX) -pthread -o $@ $(ST_OBJECTS) $(LFLAGS) @@ -169,15 +176,15 @@ $(BIN)$(EH_TARGET): $(EH_OBJECTS) $(BIN)$(IS_TARGET): $(IS_OBJECTS) cd PNG && make COMPILER=$(COMPILER) - $(CXX) -pthread -o $@ $(IS_OBJECTS) -L$(BIN) $(LFLAGS) -ljpeg -lmypng -lz + $(CXX) -pthread -o $@ $(IS_OBJECTS) -L$(BIN) $(LFLAGS) $(BIN)$(AV_TARGET): $(AV_OBJECTS) cd PNG && make COMPILER=$(COMPILER) - $(CXX) -pthread -o $@ $(AV_OBJECTS) -L$(BIN) $(LFLAGS) -ljpeg -lmypng -lz + $(CXX) -pthread -o $@ $(AV_OBJECTS) -L$(BIN) $(LFLAGS) $(BIN)$(CP_TARGET): $(CP_OBJECTS) cd PNG && make COMPILER=$(COMPILER) - $(CXX) -pthread -o $@ $(CP_OBJECTS) -L$(BIN) $(LFLAGS) -ljpeg -lmypng -lz + $(CXX) -pthread -o $@ $(CP_OBJECTS) -L$(BIN) $(LFLAGS) $(BIN)%.o: $(SRC)%.c $(CC) -c -o $@ -I$(INCLUDE) $< diff --git a/PNG.vcxproj b/PNG.vcxproj index 1c96e742..203fca53 100644 --- a/PNG.vcxproj +++ b/PNG.vcxproj @@ -65,7 +65,7 @@ StaticLibrary Unicode true - v142 + v143 StaticLibrary @@ -159,14 +159,15 @@ X64 - . + ..;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) MultiThreadedDLL - TurnOffAllWarnings + Level3 ProgramDatabase true + stdcpp17 diff --git a/PNG/PNG.vcxproj b/PNG/PNG.vcxproj new file mode 100644 index 00000000..5ebc26b0 --- /dev/null +++ b/PNG/PNG.vcxproj @@ -0,0 +1,176 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {B5899B32-FAC2-477E-99AA-86736B97F2FC} + PNG + Win32Proj + 10.0 + + + + StaticLibrary + Unicode + true + v142 + + + StaticLibrary + Unicode + v142 + + + StaticLibrary + Unicode + true + v142 + + + StaticLibrary + Unicode + v142 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + $(SolutionDir)$(Configuration)\ + $(SolutionDir)Intermediate\$(ProjectName)\$(Configuration)\ + $(SolutionDir)\Bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\Obj\$(TargetName)\$(Platform)\$(Configuration)\ + $(SolutionDir)\Bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\Obj\$(TargetName)\$(Platform)\$(Configuration)\ + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + + + true + ..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + + + X64 + + + Disabled + ..;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + + + + + X64 + + + ..;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + true + stdcpp17 + + + + + + \ No newline at end of file diff --git a/PNG/PNG.vcxproj.filters b/PNG/PNG.vcxproj.filters new file mode 100644 index 00000000..43cf39d6 --- /dev/null +++ b/PNG/PNG.vcxproj.filters @@ -0,0 +1,84 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/PointInterpolant.vcxproj b/PointInterpolant.vcxproj index c05114c7..47200e41 100644 --- a/PointInterpolant.vcxproj +++ b/PointInterpolant.vcxproj @@ -52,7 +52,7 @@ Application false - v142 + v143 true MultiByte @@ -102,6 +102,7 @@ .;%(AdditionalIncludeDirectories) AdvancedVectorExtensions2 true + stdcpp17 Console @@ -136,6 +137,7 @@ _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true pch.h + stdcpp17 Console diff --git a/PoissonRecon.vcxproj b/PoissonRecon.vcxproj index 10e8bae7..bffa049d 100644 --- a/PoissonRecon.vcxproj +++ b/PoissonRecon.vcxproj @@ -41,7 +41,7 @@ Application MultiByte true - v142 + v143 Application @@ -168,6 +168,7 @@ true + stdcpp17 true diff --git a/README.md b/README.md index cd58edda..d81f6673 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

Adaptive Multigrid Solvers (Version 13.8)

+

Adaptive Multigrid Solvers (Version 13.99)

links executables @@ -26,10 +26,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan, Chuang, Rusinkiewicz, and Hoppe, 2020]
Executables: -Win64
+Win64
Source Code: -ZIP GitHub
+ZIP GitHub
Older Versions: +V13.80, V13.74, V13.73, V13.72, @@ -123,7 +124,7 @@ of the implicit function.
[--degree <B-spline degree>]
This integer specifies the degree of the B-spline that is to be used to define the finite elements system. Larger degrees support higher order approximations, but come at the cost of denser system matrices (incurring a cost in both space and time).
-The default value for this parameter is 2. +The default value for this parameter is 1.
[--bType <boundary type>]
This integer specifies the boundary type for the finite elements. Valid values are: @@ -155,7 +156,7 @@ The default value is 1.1. 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.0. +The default value is 1.5.
[--pointWeight <interpolation weight>]
This floating point value specifies the importance that interpolation of the point samples @@ -1087,11 +1088,17 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • Fixed a bug that could result in reconstruction failure when the reconstruction depth (e.g. computed using the --width argument) was lower than the full depth value. -Version 13.8: +Version 13.80:
    1. Updated the SurfaceTrimmer code to better handle small islands.
    +Version 13.99: +
      +
    1. Modified the --width parameter so that it serves as an upper bound on the width of a cell at the finest resolution. +
    2. Modified the code so that the output mesh no longer has statistics about processing time/memory. +
    + diff --git a/SSDRecon.vcxproj b/SSDRecon.vcxproj index 5cd68a9c..00ac642b 100644 --- a/SSDRecon.vcxproj +++ b/SSDRecon.vcxproj @@ -51,7 +51,7 @@ Application false - v142 + v143 true MultiByte @@ -145,6 +145,7 @@ true . true + stdcpp17 Console diff --git a/Src/AdaptiveTreeVisualization.cpp b/Src/AdaptiveTreeVisualization.cpp index d5a790ae..e0fdd712 100644 --- a/Src/AdaptiveTreeVisualization.cpp +++ b/Src/AdaptiveTreeVisualization.cpp @@ -46,6 +46,7 @@ cmdLineParameter< char* > Samples( "samples" ) , OutMesh( "mesh" ) , OutTree( "tree" ) , + OutSlice( "slice" ) , OutGrid( "grid" ); cmdLineReadable @@ -66,6 +67,11 @@ cmdLineParameter< int > ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , Threads( "threads" , (int)std::thread::hardware_concurrency() ) , + IsoSlabDepth( "sDepth" , 0 ) , + IsoSlabStart( "sStart" , 0 ) , + IsoSlabEnd ( "sEnd" , 1 ) , + SliceDepth( "sliceDepth" ) , + SliceIndex( "sliceIndex" ) , TreeScale( "treeScale" , 1 ) , TreeDepth( "treeDepth" , -1 ); @@ -85,6 +91,8 @@ cmdLineReadable* params[] = &ParallelType , &ScheduleType , &ThreadChunkSize , + &IsoSlabDepth , &IsoSlabStart , &IsoSlabEnd , + &OutSlice , &SliceDepth , &SliceIndex, NULL }; @@ -105,6 +113,12 @@ void ShowUsage( char* ex ) for( size_t i=0 ; i=%d]\n" , ThreadChunkSize.name , ThreadChunkSize.value ); printf( "\t[--%s =%f]\n" , IsoValue.name , IsoValue.value ); + printf( "\t[-%s =%d]\n" , IsoSlabDepth.name , IsoSlabDepth.value ); + printf( "\t[-%s =%d]\n" , IsoSlabStart.name , IsoSlabStart.value ); + printf( "\t[-%s =%d]\n" , IsoSlabEnd .name , IsoSlabEnd .value ); + printf( "\t[--%s ]\n" , OutSlice.name ); + printf( "\t[--%s ]\n" , SliceDepth.name ); + printf( "\t[--%s ]\n" , SliceIndex.name ); printf( "\t[--%s]\n" , NonManifold.name ); printf( "\t[--%s]\n" , PolygonMesh.name ); printf( "\t[--%s]\n" , NonLinearFit.name ); @@ -182,13 +196,13 @@ void WriteGrid( const char *fileName , ConstPointer( Real ) values , unsigned in delete[] ext; } template< unsigned int Dim , class Real , unsigned int FEMSig > -void _Execute( const FEMTree< Dim , Real >* tree , XForm< Real , Dim+1 > modelToUnitCube , FILE* fp ) +void _Execute( const FEMTree< Dim , Real > *tree , XForm< Real , Dim+1 > modelToUnitCube , BinaryStream &stream ) { ThreadPool::Init( (ThreadPool::ParallelType)ParallelType.value , Threads.value ); static const unsigned int Degree = FEMSignature< FEMSig >::Degree; DenseNodeData< Real , IsotropicUIntPack< Dim , FEMSig > > coefficients; - coefficients.read( fp ); + coefficients.read( stream ); // Evaluate at the sample positions if( Samples.set ) @@ -347,61 +361,90 @@ void _Execute( const FEMTree< Dim , Real >* tree , XForm< Real , Dim+1 > modelTo DeletePointer( dValues ); } + if( OutSlice.set && SliceDepth.set && SliceIndex.set ) + { + using SliceFEMTreeNode = RegularTreeNode< Dim-1 , FEMTreeNodeData , depth_and_offset_type >; + + FEMTree< Dim-1 , Real > *sliceTree = FEMTree< Dim-1 , Real >::template Slice< Degree , 0 >( *tree , SliceDepth.value , SliceIndex.value , true , MEMORY_ALLOCATOR_BLOCK_SIZE ); + + DenseNodeData< Real , IsotropicUIntPack< Dim-1 , FEMSig > > sliceCoefficients = sliceTree->initDenseNodeData( IsotropicUIntPack< Dim-1 , FEMSig >() ); + sliceTree->template slice< 0 , FEMSig >( *tree , 0 , coefficients , sliceCoefficients , SliceDepth.value , SliceIndex.value ); + + XForm< Real , Dim > sliceModelToUnitCube; + sliceModelToUnitCube( Dim-1 , Dim-1 ) = 1.; + for( unsigned int i=0 ; i<(Dim-1) ; i++ ) + { + for( unsigned int j=0 ; j<(Dim-1) ; j++ ) sliceModelToUnitCube(i,j) = modelToUnitCube(i,j); + sliceModelToUnitCube(Dim-1,i) = modelToUnitCube(Dim,i); + } + FILE *fp = fopen( OutSlice.value , "wb" ); + if( !fp ) ERROR_OUT( "Failed to open file for writing: " , OutSlice.value ); + FileStream fs(fp); + FEMTree< Dim-1 , Real >::WriteParameter( fs ); + DenseNodeData< Real , IsotropicUIntPack< Dim-1 , FEMSig > >::WriteSignatures( fs ); + sliceTree->write( fs , sliceModelToUnitCube , false ); + sliceCoefficients.write( fs ); + fclose( fp ); + + delete sliceTree; + } + // Output the mesh - if( OutMesh.set ) + if constexpr( Dim==3 ) if( OutMesh.set ) { double t = Time(); typedef VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > > FullVertexFactory; typedef typename FullVertexFactory::VertexType VertexType; FullVertexFactory vertexFactory; - CoredFileMeshData< node_index_type , FullVertexFactory > mesh( vertexFactory ); + FileStreamingMesh< FullVertexFactory , node_index_type > mesh( vertexFactory ); std::function< void ( VertexType& , Point< Real , Dim > , Point< Real , Dim > , Real , Real ) > SetVertex = []( VertexType& v , Point< Real , Dim > p , Point< Real , Dim > , Real , Real ){ v.template get<0>() = p; }; #if defined( __GNUC__ ) && __GNUC__ < 5 #ifdef SHOW_WARNINGS #warning "you've got me gcc version<5" #endif // SHOW_WARNINGS static const unsigned int DataSig = FEMDegreeAndBType< 0 , BOUNDARY_FREE >::Signature; - IsoSurfaceExtractor< Dim , Real , VertexType >::template Extract< Real >( IsotropicUIntPack< Dim , FEMSig >() , UIntPack< 0 >() , UIntPack< FEMTrivialSignature >() , *tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , ( SparseNodeData< ProjectiveData< Real , Real > , IsotropicUIntPack< Dim , DataSig > > * )NULL , coefficients , IsoValue.value , mesh , (Real)0 , SetVertex , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , FlipOrientation.set ); + LevelSetExtractor< Dim , Real , VertexType >::template Extract< Real >( IsotropicUIntPack< Dim , FEMSig >() , UIntPack< 0 >() , UIntPack< FEMTrivialSignature >() , *tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , ( SparseNodeData< ProjectiveData< Real , Real > , IsotropicUIntPack< Dim , DataSig > > * )NULL , coefficients , IsoValue.value , IsoSlabDepth.value , IsoSlabStart.value , IsoSlabEnd.value , mesh , (Real)0 , SetVertex , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , FlipOrientation.set ); #else // !__GNUC__ || __GNUC__ >=5 - IsoSurfaceExtractor< Dim , Real , VertexType >::template Extract< Real >( IsotropicUIntPack< Dim , FEMSig >() , UIntPack< 0 >() , UIntPack< FEMTrivialSignature >() , *tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , NULL , coefficients , IsoValue.value , mesh , (Real)0 , SetVertex , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , FlipOrientation.set ); + LevelSetExtractor< Dim , Real , VertexType >::template Extract< Real >( IsotropicUIntPack< Dim , FEMSig >() , UIntPack< 0 >() , UIntPack< FEMTrivialSignature >() , *tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , NULL , coefficients , IsoValue.value , IsoSlabDepth.value , IsoSlabStart.value , IsoSlabEnd.value , mesh , (Real)0 , SetVertex , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , FlipOrientation.set ); #endif // __GNUC__ || __GNUC__ < 4 - if( Verbose.set ) printf( "Got iso-surface: %.2f(s)\n" , Time()-t ); - if( Verbose.set ) printf( "Vertices / Polygons: %llu / %llu\n" , (unsigned long long)( mesh.outOfCoreVertexNum()+mesh.inCoreVertices.size() ) , (unsigned long long)mesh.polygonNum() ); + if( Verbose.set ) printf( "Got level-set surface: %.2f(s)\n" , Time()-t ); + if( Verbose.set ) printf( "Vertices / Polygons: %llu / %llu\n" , (unsigned long long)mesh.vertexNum() , (unsigned long long)mesh.polygonNum() ); std::vector< std::string > comments; typename FullVertexFactory::Transform unitCubeToModelTransform( modelToUnitCube.inverse() ); - PLY::WritePolygons< FullVertexFactory , node_index_type , Real , Dim >( OutMesh.value , FullVertexFactory() , &mesh , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , comments , unitCubeToModelTransform ); + auto xForm = [&]( typename FullVertexFactory::VertexType & v ){ unitCubeToModelTransform.inPlace( v ); }; + PLY::WritePolygons< FullVertexFactory , node_index_type , Real , Dim >( OutMesh.value , FullVertexFactory() , &mesh , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , comments , xForm ); } } template< unsigned int Dim , class Real , BoundaryType BType > -void Execute( FILE* fp , int degree , FEMTree< Dim , Real > *tree , XForm< Real , Dim+1 > modelToUnitCube ) +void Execute( BinaryStream &stream , int degree , FEMTree< Dim , Real > *tree , XForm< Real , Dim+1 > modelToUnitCube ) { switch( degree ) { - case 1: _Execute< Dim , Real , FEMDegreeAndBType< 1 , BType >::Signature >( tree , modelToUnitCube , fp ) ; break; - case 2: _Execute< Dim , Real , FEMDegreeAndBType< 2 , BType >::Signature >( tree , modelToUnitCube , fp ) ; break; - case 3: _Execute< Dim , Real , FEMDegreeAndBType< 3 , BType >::Signature >( tree , modelToUnitCube , fp ) ; break; - case 4: _Execute< Dim , Real , FEMDegreeAndBType< 4 , BType >::Signature >( tree , modelToUnitCube , fp ) ; break; - default: ERROR_OUT( "Only B-Splines of degree 1 - 4 are supported" ); + case 1: _Execute< Dim , Real , FEMDegreeAndBType< 1 , BType >::Signature >( tree , modelToUnitCube , stream ) ; break; + case 2: _Execute< Dim , Real , FEMDegreeAndBType< 2 , BType >::Signature >( tree , modelToUnitCube , stream ) ; break; + case 3: _Execute< Dim , Real , FEMDegreeAndBType< 3 , BType >::Signature >( tree , modelToUnitCube , stream ) ; break; + case 4: _Execute< Dim , Real , FEMDegreeAndBType< 4 , BType >::Signature >( tree , modelToUnitCube , stream ) ; break; + default: ERROR_OUT( "Only B-Splines of degree 1 - 4 are supported" ); } } template< unsigned int Dim , class Real > -void Execute( FILE* fp , int degree , BoundaryType bType ) +void Execute( BinaryStream &stream , int degree , BoundaryType bType ) { XForm< Real , Dim+1 > modelToUnitCube; - FEMTree< Dim , Real > tree( fp , modelToUnitCube , MEMORY_ALLOCATOR_BLOCK_SIZE ); + FEMTree< Dim , Real > tree( stream , modelToUnitCube , MEMORY_ALLOCATOR_BLOCK_SIZE ); - if( Verbose.set ) printf( "Leaf Nodes / Active Nodes / Ghost Nodes: %llu / %llu / %llu\n" , (unsigned long long)tree.leaves() , (unsigned long long)tree.nodes() , (unsigned long long)tree.ghostNodes() ); + if( Verbose.set ) printf( "All Nodes / Active Nodes / Ghost Nodes: %llu / %llu / %llu\n" , (unsigned long long)tree.allNodes() , (unsigned long long)tree.activeNodes() , (unsigned long long)tree.ghostNodes() ); switch( bType ) { - case BOUNDARY_FREE: return Execute< Dim , Real , BOUNDARY_FREE >( fp , degree , &tree , modelToUnitCube ); - case BOUNDARY_NEUMANN: return Execute< Dim , Real , BOUNDARY_NEUMANN >( fp , degree , &tree , modelToUnitCube ); - case BOUNDARY_DIRICHLET: return Execute< Dim , Real , BOUNDARY_DIRICHLET >( fp , degree , &tree , modelToUnitCube ); - default: ERROR_OUT( "Not a valid boundary type: " , bType ); + case BOUNDARY_FREE: return Execute< Dim , Real , BOUNDARY_FREE >( stream , degree , &tree , modelToUnitCube ); + case BOUNDARY_NEUMANN: return Execute< Dim , Real , BOUNDARY_NEUMANN >( stream , degree , &tree , modelToUnitCube ); + case BOUNDARY_DIRICHLET: return Execute< Dim , Real , BOUNDARY_DIRICHLET >( stream , degree , &tree , modelToUnitCube ); + default: ERROR_OUT( "Not a valid boundary type: " , bType ); } } @@ -432,10 +475,11 @@ int main( int argc , char* argv[] ) if( !fp ) ERROR_OUT( "Failed to open file for reading: " , In.value ); FEMTreeRealType realType ; int degree ; BoundaryType bType; unsigned int dimension; - ReadFEMTreeParameter( fp , realType , dimension ); + FileStream fs(fp); + ReadFEMTreeParameter( fs , realType , dimension ); { unsigned int dim = dimension; - unsigned int* sigs = ReadDenseNodeDataSignatures( fp , dim ); + unsigned int* sigs = ReadDenseNodeDataSignatures( fs , dim ); if( dimension!=dim ) ERROR_OUT( "Octree and node data dimensions don't math: " , dimension , " != " , dim ); for( unsigned int d=1 ; d( fp , degree , bType ) ; break; - case FEM_TREE_REAL_DOUBLE: Execute< 2 , double >( fp , degree , bType ) ; break; + case FEM_TREE_REAL_FLOAT: Execute< 2 , float >( fs , degree , bType ) ; break; + case FEM_TREE_REAL_DOUBLE: Execute< 2 , double >( fs , degree , bType ) ; break; default: ERROR_OUT( "Unrecognized real type: " , realType ); } break; case 3: switch( realType ) { - case FEM_TREE_REAL_FLOAT: Execute< 3 , float >( fp , degree , bType ) ; break; - case FEM_TREE_REAL_DOUBLE: Execute< 3 , double >( fp , degree , bType ) ; break; + case FEM_TREE_REAL_FLOAT: Execute< 3 , float >( fs , degree , bType ) ; break; + case FEM_TREE_REAL_DOUBLE: Execute< 3 , double >( fs , degree , bType ) ; break; default: ERROR_OUT( "Unrecognized real type: " , realType ); } break; diff --git a/Src/Allocator.h b/Src/Allocator.h index 651c78e0..e6548fc5 100644 --- a/Src/Allocator.h +++ b/Src/Allocator.h @@ -29,6 +29,7 @@ DAMAGE. #ifndef ALLOCATOR_INCLUDED #define ALLOCATOR_INCLUDED #include +#include "Array.h" struct AllocatorState { @@ -49,7 +50,7 @@ class Allocator { size_t _blockSize; AllocatorState _state; - std::vector< T* > _memory; + std::vector< Pointer( T ) > _memory; public: Allocator( void ) : _blockSize(0) {} ~Allocator( void ){ reset(); } @@ -58,7 +59,7 @@ class Allocator * it has allocated. */ void reset( void ) { - for( size_t i=0 ; i<_memory.size() ; i++ ) delete[] _memory[i]; + for( size_t i=0 ; i<_memory.size() ; i++ ) DeletePointer( _memory[i] ); _memory.clear(); _blockSize = 0; _state = AllocatorState(); @@ -66,62 +67,6 @@ class Allocator /** This method returns the memory state of the allocator. */ AllocatorState getState( void ) const { return _state; } - - /** This method rolls back the allocator so that it makes all of the memory previously - * allocated available for re-allocation. Note that it does it not call the constructor - * again, so after this method has been called, assumptions about the state of the values - * in memory are no longer valid. */ - void rollBack( void ) - { - if( _memory.size() ) - { - for( size_t i=0 ; i<_memory.size() ; i++ ) for( size_t j=0 ; j<_blockSize ; j++ ) - { - _memory[i][j].~T(); - new( &_memory[i][j] ) T(); - } - _state = AllocatorState(); - } - } - /** This method rolls back the allocator to the previous memory state and makes all of the memory previously - * allocated available for re-allocation. Note that it does it not call the constructor - * again, so after this method has been called, assumptions about the state of the values - * in memory are no longer valid. */ - void rollBack( const AllocatorState& state ) - { - if( state.index<_state.index || ( state.index==_state.index && state.remains<_state.remains ) ) - { - if( state.index<_state.index ) - { - for( size_t j=state.remains ; j<_blockSize ; j++ ) - { - _memory[ state.index ][j].~T(); - new( &_memory[ state.index ][j] ) T(); - } - for( size_t i=state.index+1 ; i<_state.index-1 ; i++ ) for( size_t j=0 ; j<_blockSize ; j++ ) - { - _memory[i][j].~T(); - new( &_memory[i][j] ) T(); - } - for( size_t j=0 ; j<_state.remains ; j++ ) - { - _memory[ _state.index ][j].~T(); - new( &_memory[ _state.index ][j] ) T(); - } - _state = state; - } - else - { - for( size_t j=0 ; j_blockSize ) ERROR_OUT( "elements bigger than block-size: " , elements , " > " , _blockSize ); if( _state.remains( _blockSize ); if( !mem ) ERROR_OUT( "Failed to allocate memory" ); _memory.push_back( mem ); } _state.index++; _state.remains = _blockSize; } - mem = &( _memory[ _state.index ][ _blockSize-_state.remains ] ); + mem = _memory[ _state.index ] + ( _blockSize-_state.remains ); _state.remains -= elements; return mem; } diff --git a/Src/Array.h b/Src/Array.h index 1bf00e1c..95d71c4e 100644 --- a/Src/Array.h +++ b/Src/Array.h @@ -60,10 +60,13 @@ inline void aligned_free( void* mem ) { free( ( ( void** )mem )[-1] ); } #ifdef SHOW_WARNINGS #pragma message ( "[WARNING] Array debugging is enabled" ) #endif // SHOW_WARNINGS -#include "Array.inl" + #define Pointer( ... ) Array< __VA_ARGS__ > #define ConstPointer( ... ) ConstArray< __VA_ARGS__ > #define NullPointer( ... ) Array< __VA_ARGS__ >() + +#include "Array.inl" + 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( ); } @@ -74,8 +77,8 @@ template< class C > Array< C > AllocPointer( size_t size 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 > 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() ); } diff --git a/Src/Array.inl b/Src/Array.inl index de95fccc..67d17ad8 100644 --- a/Src/Array.inl +++ b/Src/Array.inl @@ -36,6 +36,7 @@ DAMAGE. #include #include #include +#include "MyMiscellany.h" template< class C > class ConstArray; @@ -118,7 +119,7 @@ public: min = max = 0; } template< class D > - Array( Array< D >& a ) + Array( Array< D > a ) { _data = NULL; if( !a ) @@ -273,7 +274,7 @@ public: max = a.maximum(); } template< class D > - inline ConstArray( const Array< D >& a ) + inline ConstArray( Array< D > a ) { // [WARNING] Changing szC and szD to size_t causes some really strange behavior. std::ptrdiff_t szC = (std::ptrdiff_t)sizeof( C ); @@ -284,7 +285,7 @@ public: if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD ) ERROR_OUT( "Could not convert const array [ " , a.minimum() , " , " , a.maximum() , " ] * " , szD , " => [ " , min , " , " , max , " ] * " , szC ); } template< class D > - inline ConstArray( const ConstArray< D >& a ) + inline ConstArray( ConstArray< D > a ) { // [WARNING] Chaning szC and szD to size_t causes some really strange behavior. std::ptrdiff_t szC = (std::ptrdiff_t)sizeof( C ); @@ -369,8 +370,8 @@ public: std::ptrdiff_t operator - ( const Array< C >& a ) const { return data - a.pointer(); } const C* pointer( void ) const { return data; } - bool operator !( void ) { return data==NULL; } - operator bool( ) { return data!=NULL; } + bool operator !( void ) const { return data==NULL; } + operator bool( ) const { return data!=NULL; } }; template< class C > @@ -422,19 +423,22 @@ template< class C > size_t fread( Array< C > destination , size_t eSize , size_t count , FILE* fp ) { if( count*eSize>destination.maximum()*sizeof( C ) ) ERROR_OUT( "Size of read exceeds source maximum: " , count*eSize , " > " , destination.maximum()*sizeof( C ) ); - return fread( &destination[0] , eSize , count , fp ); + if( count ) return fread( &destination[0] , eSize , count , fp ); + else return 0; } template< class C > size_t fwrite( Array< C > source , size_t eSize , size_t count , FILE* fp ) { if( count*eSize>source.maximum()*sizeof( C ) ) ERROR_OUT( "Size of write exceeds source maximum: " , count*eSize , " > " , source.maximum()*sizeof( C ) ); - return fwrite( &source[0] , eSize , count , fp ); + if( count ) return fwrite( &source[0] , eSize , count , fp ); + else return 0; } template< class C > size_t fwrite( ConstArray< C > source , size_t eSize , size_t count , FILE* fp ) { if( count*eSize>source.maximum()*sizeof( C ) ) ERROR_OUT( "Size of write exceeds source maximum: " , count*eSize , " > " , source.maximum()*sizeof( C ) ); - return fwrite( &source[0] , eSize , count , fp ); + if( count ) return fwrite( &source[0] , eSize , count , fp ); + else return 0; } template< class C > void qsort( Array< C > base , size_t numElements , size_t elementSize , int (*compareFunction)( const void* , const void* ) ) diff --git a/Src/BSplineData.h b/Src/BSplineData.h index eff38aef..ee385a21 100644 --- a/Src/BSplineData.h +++ b/Src/BSplineData.h @@ -140,6 +140,7 @@ struct BSplineElements : public std::vector< BSplineElementCoefficients< Degree template< unsigned int Degree , unsigned int DDegree > struct Differentiator { static void Differentiate( const BSplineElements< Degree >& bse , BSplineElements< DDegree >& dbse ); }; template< unsigned int Degree > struct Differentiator< Degree , Degree >{ static void Differentiate( const BSplineElements< Degree >& bse , BSplineElements< Degree >& dbse ); }; +// Note that these bounds are inclusive -- [s,e] #define BSPLINE_SET_BOUNDS( name , s , e ) \ static const int name ## Start = (s); \ static const int name ## End = (e); \ diff --git a/Src/BlockedVector.h b/Src/BlockedVector.h index b23406b5..4158925a 100644 --- a/Src/BlockedVector.h +++ b/Src/BlockedVector.h @@ -37,18 +37,21 @@ DAMAGE. template< typename T , unsigned int LogBlockSize=10 , unsigned int InitialBlocks=10 , unsigned int AllocationMultiplier=2 > struct BlockedVector { - BlockedVector( T defaultValue=T() ) : _defaultValue( defaultValue ) + BlockedVector( size_t sz=0 , T defaultValue=T() ) : _defaultValue( defaultValue ) { _reservedBlocks = InitialBlocks; _blocks = NewPointer< Pointer( T ) >( _reservedBlocks ); for( size_t i=0 ; i<_reservedBlocks ; i++ ) _blocks[i] = NullPointer( T ); _allocatedBlocks = _size = 0; + if( sz ) resize( sz ); } + ~BlockedVector( void ) { for( size_t i=0 ; i<_allocatedBlocks ; i++ ) DeletePointer( _blocks[i] ); DeletePointer( _blocks ); } + BlockedVector( const BlockedVector& v ) { _reservedBlocks = v._reservedBlocks , _allocatedBlocks = v._allocatedBlocks , _size = v._size , _defaultValue = v._defaultValue; @@ -60,6 +63,7 @@ struct BlockedVector } for( size_t i=_allocatedBlocks ; i<_reservedBlocks ; i++ ) _blocks[i] = NullPointer( Pointer ( T ) ); } + BlockedVector& operator = ( const BlockedVector& v ) { for( size_t i=0 ; i<_allocatedBlocks ; i++ ) DeletePointer( _blocks[i] ); @@ -74,11 +78,13 @@ struct BlockedVector for( size_t i=_allocatedBlocks ; i<_reservedBlocks ; i++ ) _blocks[i] = NullPointer( T ); return *this; } + BlockedVector( BlockedVector&& v ) { _reservedBlocks = v._reservedBlocks , _allocatedBlocks = v._allocatedBlocks , _size = v._size , _defaultValue = v._defaultValue , _blocks = v._blocks; v._reservedBlocks = v._allocatedBlocks = v._size = 0 , v._blocks = NullPointer( Pointer( T ) ); } + BlockedVector& operator = ( BlockedVector&& v ) { for( size_t i=0 ; i<_allocatedBlocks ; i++ ) DeletePointer( _blocks[i] ); @@ -89,21 +95,25 @@ struct BlockedVector } size_t size( void ) const { return _size; } + const T& operator[]( size_t idx ) const { return _blocks[idx>>LogBlockSize][idx&_Mask]; } T& operator[]( size_t idx ){ return _blocks[idx>>LogBlockSize][idx&_Mask]; } - size_t resize( size_t size ){ return resize( size , _defaultValue ); } - size_t resize( size_t size , const T& defaultValue ) + void resize( size_t size ){ resize( size , _defaultValue ); } + void resize( size_t size , const T& defaultValue ) { - if( size<=_size ) - { -#ifdef _MSC_VER - WARN( "BlockedVector::resize: new size must be greater than old size: " , size , " > " , _size ); -#else // !MSC_VER - WARN( "BlockedVector::resize: new size must be greater than old size: " , size , " > ", _size ); -#endif // _MSC_VER - return _size; - } + reserve( size , defaultValue ); + _size = size; + } + + void clear( void ){ _size = 0; } + + size_t reserved( void ) const { return _allocatedBlocks * _BlockSize; } + + void reserve( size_t size ){ reserve( size , _defaultValue ); } + void reserve( size_t size , const T& defaultValue ) + { + if( size<=_allocatedBlocks * _BlockSize ) return; size_t index = size-1; size_t block = index >> LogBlockSize; size_t blockIndex = index & _Mask; @@ -131,41 +141,98 @@ struct BlockedVector } _allocatedBlocks = block+1; } - _size = index+1; - return index; } - size_t push( void ){ return resize( _size+1 ); } + void push_back( const T &value ) + { + resize( _size+1 ); + operator[]( _size-1 ) = value; + } + T &back( void ){ return operator[]( _size-1 ); } + const T &back( void ) const { return operator[]( _size-1 ); } + void pop_back( void ){ _size--; } - void write( FILE *fp ) const + void write( BinaryStream &stream ) const { - fwrite( &_size , sizeof(size_t) , 1 , fp ); - fwrite( &_defaultValue , sizeof(T) , 1 , fp ); - fwrite( &_reservedBlocks , sizeof(size_t) , 1 , fp ); - fwrite( &_allocatedBlocks , sizeof(size_t) , 1 , fp ); - for( size_t i=0 ; i<_allocatedBlocks ; i++ ) fwrite( _blocks[i] , sizeof(T) , _BlockSize , fp ); + stream.write( _size ); + stream.write( _defaultValue ); + stream.write( _reservedBlocks ); + stream.write( _allocatedBlocks ); + for( size_t i=0 ; i<_allocatedBlocks ; i++ ) stream.write( _blocks[i] , _BlockSize ); } - void read( FILE *fp ) + void read( BinaryStream &stream ) { for( size_t i=0 ; i<_allocatedBlocks ; i++ ) DeletePointer( _blocks[i] ); DeletePointer( _blocks ); - - if( fread( &_size , sizeof(size_t) , 1 , fp )!=1 ) ERROR_OUT( "Failed to read _size" ); - if( fread( &_defaultValue , sizeof(T) , 1 , fp )!=1 ) ERROR_OUT( "Failed to read _defaultValue" ); - if( fread( &_reservedBlocks , sizeof(size_t) , 1 , fp )!=1 ) ERROR_OUT( "Failed to read _reservedBlocks" ); - if( fread( &_allocatedBlocks , sizeof(size_t) , 1 , fp )!=1 ) ERROR_OUT( "Failed to read _allocatedBlocks" ); + if( !stream.read( _size ) ) ERROR_OUT( "Failed to read _size" ); + if( !stream.read( _defaultValue ) ) ERROR_OUT( "Failed to read _defaultValue" ); + if( !stream.read( _reservedBlocks ) ) ERROR_OUT( "Failed to read _reservedBlocks" ); + if( !stream.read( _allocatedBlocks ) ) ERROR_OUT( "Failed to read _allocatedBlocks" ); _blocks = NewPointer< Pointer( T ) >( _reservedBlocks ); if( !_blocks ) ERROR_OUT( "Failed to allocate _blocks: " , _reservedBlocks ); + for( size_t i=0 ; i<_allocatedBlocks ; i++ ) { _blocks[i] = NewPointer< T >( _BlockSize ); if( !_blocks[i] ) ERROR_OUT( "Failed to allocate _blocks[" , i , "]" ); - if( fread( _blocks[i] , sizeof(T) , _BlockSize , fp )!=_BlockSize ) ERROR_OUT( "Failed to read _blocks[" , i , "]" ); + if( !stream.read( _blocks[i] , _BlockSize ) ) ERROR_OUT( "Failed to read _blocks[" , i , "]" ); } for( size_t i=_allocatedBlocks ; i<_reservedBlocks ; i++ ) _blocks[i] = NullPointer( T ); } + void read( BinaryStream &stream , const Serializer< T > &serializer ) + { + const size_t serializedSize = serializer.size(); + + for( size_t i=0 ; i<_allocatedBlocks ; i++ ) DeletePointer( _blocks[i] ); + DeletePointer( _blocks ); + _size = _allocatedBlocks = _reservedBlocks = 0; + + if( !stream.read( _size ) ) ERROR_OUT( "Failed to read _size" ); +#ifdef SHOW_WARNINGS +#pragma message( "[WARNING] Should deserialize default value" ) +#endif // SHOW_WARNINGS + if( !stream.read( _defaultValue ) ) ERROR_OUT( "Failed to read _defaultValue" ); + if( !stream.read( _reservedBlocks ) ) ERROR_OUT( "Failed to read _reservedBlocks" ); + if( !stream.read( _allocatedBlocks ) ) ERROR_OUT( "Failed to read _allocatedBlocks" ); + _blocks = NewPointer< Pointer( T ) >( _reservedBlocks ); + if( !_blocks ) ERROR_OUT( "Failed to allocate _blocks: " , _reservedBlocks ); + for( size_t i=0 ; i<_allocatedBlocks ; i++ ) + { + _blocks[i] = NewPointer< T >( _BlockSize ); + if( !_blocks[i] ) ERROR_OUT( "Failed to allocate _blocks[" , i , "]" ); + } + if( _size ) + { + Pointer( char ) buffer = NewPointer< char >( _size * serializedSize ); + if( !stream.read( buffer , serializedSize*_size ) ) ERROR_OUT( "Failed tor read in data" ); + for( unsigned int i=0 ; i<_size ; i++ ) serializer.deserialize( buffer+i*serializedSize , operator[]( i ) ); + DeletePointer( buffer ); + } + } + + void write( BinaryStream &stream , const Serializer< T > &serializer ) const + { + const size_t serializedSize = serializer.size(); + + stream.write( _size ); +#ifdef SHOW_WARNINGS +#pragma message( "[WARNING] Should serialize default value" ) +#endif // SHOW_WARNINGS + stream.write( _defaultValue ); + stream.write( _reservedBlocks ); + stream.write( _allocatedBlocks ); + if( _size ) + { + Pointer( char ) buffer = NewPointer< char >( _size * serializedSize ); + for( unsigned int i=0 ; i<_size ; i++ ) serializer.serialize( operator[]( i ) , buffer+i*serializedSize ); + stream.write( buffer , serializedSize*_size ); + DeletePointer( buffer ); + } + } + + protected: static const size_t _BlockSize = 1< >( fileNames[i] , vertexFactory ); else pointStream = new ASCIIInputDataStream< FullVertexFactory< Real , Dim , VertexDataFactory > >( fileNames[i] , vertexFactory ); size_t count = 0; - VertexType< Real , Dim , VertexDataFactory > v; + VertexType< Real , Dim , VertexDataFactory > v = vertexFactory(); while( pointStream->next( v ) ) count++; pointStream->reset(); - _vertices.resize( count ); + _vertices.resize( count , v ); comments.resize( 0 ); ft = PLY_BINARY_NATIVE; @@ -549,11 +549,6 @@ int main( int argc , char* argv[] ) static constexpr unsigned int Dim = 3; cmdLineParse( argc-1 , &argv[1] , params ); -#ifdef USE_SEG_FAULT_HANDLER - WARN( "using seg-fault handler" ); - StackTracer::exec = argv[0]; - signal( SIGSEGV , SignalHandler ); -#endif // USE_SEG_FAULT_HANDLER #ifdef ARRAY_DEBUG WARN( "Array debugging enabled" ); #endif // ARRAY_DEBUG diff --git a/Src/CmdLineParser.inl b/Src/CmdLineParser.inl index aef9635e..a81566cc 100644 --- a/Src/CmdLineParser.inl +++ b/Src/CmdLineParser.inl @@ -33,34 +33,39 @@ DAMAGE. inline int strcasecmp( const char* c1 , const char* c2 ){ return _stricmp( c1 , c2 ); } #endif // WIN32 || _WIN64 -template< > void cmdLineCleanUp< int >( int* t ){ } -template< > void cmdLineCleanUp< float >( float* t ){ } -template< > void cmdLineCleanUp< double >( double* t ){ } -template< > void cmdLineCleanUp< char* >( char** t ){ if( *t ) free( *t ) ; *t = NULL; } -template< > int cmdLineInitialize< int >( void ){ return 0; } -template< > float cmdLineInitialize< float >( void ){ return 0.f; } -template< > double cmdLineInitialize< double >( void ){ return 0.; } -template< > char* cmdLineInitialize< char* >( void ){ return NULL; } -template< > void cmdLineWriteValue< int >( int t , char* str ){ sprintf( str , "%d" , t ); } -template< > void cmdLineWriteValue< float >( float t , char* str ){ sprintf( str , "%f" , t ); } -template< > void cmdLineWriteValue< double >( double t , char* str ){ sprintf( str , "%f" , t ); } -template< > void cmdLineWriteValue< char* >( char* t , char* str ){ if( t ) sprintf( str , "%s" , t ) ; else str[0]=0; } -template< > int cmdLineCopy( int t ){ return t; } -template< > float cmdLineCopy( float t ){ return t; } -template< > double cmdLineCopy( double t ){ return t; } +template< > void cmdLineCleanUp< int >( int* t ){ } +template< > void cmdLineCleanUp< float >( float* t ){ } +template< > void cmdLineCleanUp< double >( double* t ){ } +template< > void cmdLineCleanUp< char* >( char** t ){ if( *t ) free( *t ) ; *t = NULL; } +template< > void cmdLineCleanUp< std::string >( std::string* t ){ } +template< > int cmdLineInitialize< int >( void ){ return 0; } +template< > float cmdLineInitialize< float >( void ){ return 0.f; } +template< > double cmdLineInitialize< double >( void ){ return 0.; } +template< > char* cmdLineInitialize< char* >( void ){ return NULL; } +template< > std::string cmdLineInitialize< std::string >( void ){ return std::string(); } +template< > void cmdLineWriteValue< int >( int t , char* str ){ sprintf( str , "%d" , t ); } +template< > void cmdLineWriteValue< float >( float t , char* str ){ sprintf( str , "%f" , t ); } +template< > void cmdLineWriteValue< double >( double t , char* str ){ sprintf( str , "%f" , t ); } +template< > void cmdLineWriteValue< char* >( char* t , char* str ){ if( t ) sprintf( str , "%s" , t ) ; else str[0]=0; } +template< > void cmdLineWriteValue< std::string >( std::string t , char* str ){ sprintf( str , "%s" , t.c_str() ); } +template< > int cmdLineCopy( int t ){ return t; } +template< > float cmdLineCopy( float t ){ return t; } +template< > double cmdLineCopy( double t ){ return t; } #if defined( WIN32 ) || defined( _WIN64 ) -template< > char* cmdLineCopy( char* t ){ return _strdup( t ); } +template< > char* cmdLineCopy( char* t ){ return _strdup( t ); } #else // !WIN32 && !_WIN64 -template< > char* cmdLineCopy( char* t ){ return strdup( t ); } +template< > char* cmdLineCopy( char* t ){ return strdup( t ); } #endif // WIN32 || _WIN64 -template< > int cmdLineStringToType( const char* str ){ return atoi( str ); } -template< > float cmdLineStringToType( const char* str ){ return float( atof( str ) ); } -template< > double cmdLineStringToType( const char* str ){ return double( atof( str ) ); } +template< > std::string cmdLineCopy( std::string t ){ return t; } +template< > int cmdLineStringToType( const char* str ){ return atoi( str ); } +template< > float cmdLineStringToType( const char* str ){ return float( atof( str ) ); } +template< > double cmdLineStringToType( const char* str ){ return double( atof( str ) ); } #if defined( WIN32 ) || defined( _WIN64 ) -template< > char* cmdLineStringToType( const char* str ){ return _strdup( str ); } +template< > char* cmdLineStringToType( const char* str ){ return _strdup( str ); } #else // !WIN32 && !_WIN64 -template< > char* cmdLineStringToType( const char* str ){ return strdup( str ); } +template< > char* cmdLineStringToType( const char* str ){ return strdup( str ); } #endif // WIN32 || _WIN64 +template< > std::string cmdLineStringToType( const char* str ){ return std::string( str ); } ///////////////////// diff --git a/Src/CoredMesh.h b/Src/CoredMesh.h deleted file mode 100644 index 86db7873..00000000 --- a/Src/CoredMesh.h +++ /dev/null @@ -1,285 +0,0 @@ -/* -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 CORED_MESH_INCLUDED -#define CORED_MESH_INCLUDED - -#include "Geometry.h" -#include "MyMiscellany.h" - -template< typename Index > -class CoredPointIndex -{ -public: - Index index; - char inCore; - - bool operator == (const CoredPointIndex& cpi) const {return (index==cpi.index) && (inCore==cpi.inCore);}; - bool operator != (const CoredPointIndex& cpi) const {return (index!=cpi.index) || (inCore!=cpi.inCore);}; -}; - -template< typename Index > struct CoredEdgeIndex{ CoredPointIndex< Index > idx[2]; }; - -template< typename Index > -struct CoredVertexIndex -{ - Index idx; - bool inCore; -}; - -template< class Vertex , typename Index > -class CoredCurveData -{ -public: - std::vector< Vertex > inCoreVertices; - virtual void resetIterator( void ) = 0; - - virtual Index addOutOfCoreVertex ( const Vertex& v ) = 0; - virtual Index addOutOfCoreVertex_s( unsigned int thread , const Vertex& v ) = 0; - virtual void addEdge_s( unsigned int thread , CoredVertexIndex< Index > v1 , CoredVertexIndex< Index > v2 ) = 0; - virtual void addEdge_s( unsigned int thread , Index v1 , Index v2 ) = 0; - - virtual Index nextOutOfCoreVertex( Vertex &v )=0; - virtual Index nextEdge( CoredVertexIndex< Index >& v1 , CoredVertexIndex< Index >& v2 ) = 0; - - virtual size_t outOfCoreVertexNum(void)=0; - virtual size_t edgeCount( void ) = 0; -}; - -template< class Vertex , typename Index > -class CoredMeshData -{ -public: - virtual ~CoredMeshData( void ){} - std::vector< Vertex > inCoreVertices; - virtual void resetIterator( void ) = 0; - - virtual Index addOutOfCoreVertex ( const Vertex &v ) = 0; - virtual Index addOutOfCoreVertex_s( unsigned int thread , const Vertex &v ) = 0; - virtual void addPolygon_s( unsigned int thread , const std::vector< CoredVertexIndex< Index > >& vertices ) = 0; - virtual void addPolygon_s( unsigned int thread , const std::vector< Index >& vertices ) = 0; - - virtual Index nextOutOfCoreVertex( Vertex &v )=0; - virtual Index nextPolygon( std::vector< CoredVertexIndex< Index > >& vertices ) = 0; - - virtual size_t outOfCoreVertexNum( void )=0; - virtual size_t polygonNum( void ) = 0; -}; - -template< class Vertex , typename Index > -class CoredVectorCurveData : public CoredCurveData< Vertex , Index > -{ - std::vector< Vertex > oocPoints; - std::vector< std::pair< Index , Index > > edges; - unsigned int threadIndex; - Index edgeIndex; - Index oocPointIndex; -public: - CoredVectorCurveData( void ); - - void resetIterator( void ); - - Index addOutOfCoreVertex ( const Vertex &v ); - Index addOutOfCoreVertex_s( unsigned int thread , const Vertex &v ); - void addEdge_s( unsigned int thread , CoredVertexIndex< Index > v1 , CoredVertexIndex< Index > v2 ); - void addEdge_s( unsigned int thread , Index v1 , Index v2 ); - - Index nextOutOfCoreVertex( Vertex &v ); - Index nextEdge( CoredVertexIndex< Index > &v1 , CoredVertexIndex< Index > &v2 ); - - size_t outOfCoreVertexNum( void ); - size_t edgeCount( void ); -}; -template< class Vertex , typename Index > -class CoredVectorMeshData : public CoredMeshData< Vertex , Index > -{ - std::vector< Vertex > oocPoints; - std::vector< std::vector< std::vector< Index > > > polygons; - unsigned int threadIndex; - Index polygonIndex; - Index oocPointIndex; -public: - CoredVectorMeshData( void ); - - void resetIterator( void ); - - Index addOutOfCoreVertex ( const Vertex &v ); - Index addOutOfCoreVertex_s( unsigned int thread , const Vertex &v ); - void addPolygon_s( unsigned int thread , const std::vector< CoredVertexIndex< Index > >& vertices ); - void addPolygon_s( unsigned int thread , const std::vector< Index >& vertices ); - - Index nextOutOfCoreVertex( Vertex &v ); - Index nextPolygon( std::vector< CoredVertexIndex< Index > >& vertices ); - - size_t outOfCoreVertexNum( void ); - size_t polygonNum( void ); -}; -class BufferedReadWriteFile -{ - bool tempFile; - FILE* _fp; - char *_buffer , _fileName[1024]; - size_t _bufferIndex , _bufferSize; -public: - BufferedReadWriteFile( const char* fileName=NULL , const char* fileHeader="" , unsigned int bufferSize=(1<<20) ) - { - _bufferIndex = 0; - _bufferSize = bufferSize; - if( fileName ) strcpy( _fileName , fileName ) , tempFile = false , _fp = fopen( _fileName , "w+b" ); - else - { - if( fileHeader && strlen(fileHeader) ) sprintf( _fileName , "%sXXXXXX" , fileHeader ); - else strcpy( _fileName , "XXXXXX" ); -#ifdef _WIN32 - _mktemp( _fileName ); - _fp = fopen( _fileName , "w+b" ); -#else // !_WIN32 - _fp = fdopen( mkstemp( _fileName ) , "w+b" ); -#endif // _WIN32 - tempFile = true; - } - if( !_fp ) ERROR_OUT( "Failed to open file: " , _fileName ); - _buffer = (char*) malloc( _bufferSize ); - } - ~BufferedReadWriteFile( void ) - { - free( _buffer ); - fclose( _fp ); - if( tempFile ) remove( _fileName ); - } - bool write( const void* data , size_t size ) - { - if( !size ) return true; - const 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 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; - } - void reset( void ) - { - if( _bufferIndex ) fwrite( _buffer , 1 , _bufferIndex , _fp ); - _bufferIndex = 0; - fseek( _fp , 0 , SEEK_SET ); - _bufferIndex = 0; - _bufferSize = fread( _buffer , 1 , _bufferSize , _fp ); - } -}; -template< class Vertex , typename Index > -class CoredFileCurveData : public CoredCurveData< Vertex , Index > -{ - BufferedReadWriteFile *oocPointFile; - Index oocPoints; - std::vector< BufferedReadWriteFile* > edgeFiles; - unsigned int threadIndex; -public: - CoredFileCurveData( const char* fileHeader="" ); - ~CoredFileCurveData( void ); - - void resetIterator( void ); - - Index addOutOfCoreVertex ( const Vertex &v ); - Index addOutOfCoreVertex_s( unsigned int thread , const Vertex &v ); - void addEdge_s( unsigned int thread , CoredVertexIndex< Index > v1 , CoredVertexIndex< Index > v2 ); - void addEdge_s( unsigned int thread , Index v1 , Index v2 ); - - Index nextOutOfCoreVertex( Vertex &v ); - Index nextEdge( CoredVertexIndex< Index > &v1 , CoredVertexIndex< Index > &v2 ); - - size_t outOfCoreVertexNum( void ); - size_t edgeCount( void ); -}; - -template< typename Index , typename VertexFactory > -class CoredFileMeshData : public CoredMeshData< typename VertexFactory::VertexType , Index > -{ - typedef typename VertexFactory::VertexType VertexType; - BufferedReadWriteFile *_oocVertexFile; - Index _oocVertexNum; - std::vector< Index > _polygonNum; - std::vector< BufferedReadWriteFile * > _polygonFiles; - unsigned int _threadIndex; - const VertexFactory &_factory; - char *_buffer; -public: - CoredFileMeshData( const VertexFactory &vFactory , const char* fileHeader="" ); - ~CoredFileMeshData( void ); - - void resetIterator( void ); - - Index addOutOfCoreVertex ( const VertexType& v ); - Index addOutOfCoreVertex_s( unsigned int thread , const VertexType& v ); - void addPolygon_s( unsigned int thread , const std::vector< CoredVertexIndex< Index > >& vertices ); - void addPolygon_s( unsigned int thread , const std::vector< Index >& vertices ); - - Index nextOutOfCoreVertex( VertexType &v ); - Index nextPolygon( std::vector< CoredVertexIndex< Index > >& vertices ); - - size_t outOfCoreVertexNum( void ); - size_t polygonNum( void ); -}; - -#include "CoredMesh.inl" - -#endif // CORED_MESH diff --git a/Src/CoredMesh.inl b/Src/CoredMesh.inl deleted file mode 100644 index 4323738a..00000000 --- a/Src/CoredMesh.inl +++ /dev/null @@ -1,239 +0,0 @@ -/* -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. -*/ - - -///////////////////////// -// CoredVectorMeshData // -///////////////////////// -template< class Vertex , typename Index > -CoredVectorMeshData< Vertex , Index >::CoredVectorMeshData( void ) { oocPointIndex = polygonIndex = threadIndex = 0 ; polygons.resize( std::thread::hardware_concurrency() ); } -template< class Vertex , typename Index > -void CoredVectorMeshData< Vertex , Index >::resetIterator ( void ) { oocPointIndex = polygonIndex = threadIndex = 0; } -template< class Vertex , typename Index > -Index CoredVectorMeshData< Vertex , Index >::addOutOfCoreVertex( const Vertex& p ) -{ - oocPoints.push_back(p); - return ( Index )oocPoints.size()-1; -} -template< class Vertex , typename Index > -Index CoredVectorMeshData< Vertex , Index >::addOutOfCoreVertex_s( unsigned int thread , const Vertex& p ) -{ - size_t sz; - { - static std::mutex m; - std::lock_guard< std::mutex > lock(m); - sz = oocPoints.size(); - oocPoints.push_back(p); - } - return (Index)sz; -} -template< class Vertex , typename Index > -void CoredVectorMeshData< Vertex , Index >::addPolygon_s( unsigned int thread , const std::vector< Index >& polygon ) -{ - polygons[ thread ].push_back( polygon ); -} -template< class Vertex , typename Index > -void CoredVectorMeshData< Vertex , Index >::addPolygon_s( unsigned int thread , const std::vector< CoredVertexIndex< Index > >& vertices ) -{ - std::vector< Index > 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( thread , polygon ); -} -template< class Vertex , typename Index > -Index CoredVectorMeshData< Vertex , Index >::nextOutOfCoreVertex( Vertex &p ) -{ - if( oocPointIndex<(Index)oocPoints.size() ) - { - p=oocPoints[oocPointIndex++]; - return 1; - } - else return 0; -} -template< class Vertex , typename Index > -Index CoredVectorMeshData< Vertex , Index >::nextPolygon( std::vector< CoredVertexIndex< Index > >& vertices ) -{ - while( true ) - { - if( threadIndex<(int)polygons.size() ) - { - if( polygonIndex<(Index)( polygons[threadIndex].size() ) ) - { - std::vector< Index >& polygon = polygons[threadIndex][ polygonIndex++ ]; - vertices.resize( polygon.size() ); - for( int i=0 ; i -size_t CoredVectorMeshData< Vertex , Index >::outOfCoreVertexNum( void ){ return oocPoints.size(); } -template< class Vertex , typename Index > -size_t CoredVectorMeshData< Vertex , Index >::polygonNum( void ) -{ - size_t count = 0; - for( size_t i=0 ; i -CoredFileMeshData< Index , VertexFactory >::CoredFileMeshData( const VertexFactory &factory , const char* fileHeader ) : _factory(factory) -{ - _threadIndex = 0; - _oocVertexNum = 0; - _polygonNum.resize( std::thread::hardware_concurrency() ); - for( unsigned int i=0 ; i<_polygonNum.size() ; i++ ) _polygonNum[i] = 0; - - char _fileHeader[1024]; - sprintf( _fileHeader , "%s_points_" , fileHeader ); - _oocVertexFile = new BufferedReadWriteFile( NULL , _fileHeader ); - _polygonFiles.resize( std::thread::hardware_concurrency() ); - for( unsigned int i=0 ; i<_polygonFiles.size() ; i++ ) - { - sprintf( _fileHeader , "%s_polygons_t%d_" , fileHeader , i ); - _polygonFiles[i] = new BufferedReadWriteFile( NULL , _fileHeader ); - } - - _buffer = new char[ factory.bufferSize() ]; -} - -template< typename Index , typename VertexFactory > -CoredFileMeshData< Index , VertexFactory >::~CoredFileMeshData( void ) -{ - delete _oocVertexFile; - for( unsigned int i=0 ; i<_polygonFiles.size() ; i++ ) delete _polygonFiles[i]; - delete[] _buffer; -} - -template< typename Index , typename VertexFactory > -void CoredFileMeshData< Index , VertexFactory >::resetIterator ( void ) -{ - _oocVertexFile->reset(); - _threadIndex = 0; - for( unsigned int i=0 ; i<_polygonFiles.size() ; i++ ) _polygonFiles[i]->reset(); -} - -template< typename Index , typename VertexFactory > -Index CoredFileMeshData< Index , VertexFactory >::addOutOfCoreVertex( const VertexType& v ) -{ - _factory.toBuffer( v , _buffer ); - _oocVertexFile->write( _buffer , _factory.bufferSize() ); - return _oocVertexNum++; -} - -template< typename Index , typename VertexFactory > -Index CoredFileMeshData< Index , VertexFactory >::addOutOfCoreVertex_s( unsigned int thread , const VertexType& v ) -{ - Index sz; - { - static std::mutex m; - std::lock_guard< std::mutex > lock(m); - sz = _oocVertexNum; - _factory.toBuffer( v , _buffer ); - _oocVertexFile->write( _buffer , _factory.bufferSize() ); - _oocVertexNum++; - } - return sz; -} - -template< typename Index , typename VertexFactory > -void CoredFileMeshData< Index , VertexFactory >::addPolygon_s( unsigned int thread , const std::vector< Index >& vertices ) -{ - unsigned int vSize = (unsigned int)vertices.size(); - _polygonFiles[thread]->write( &vSize , sizeof(unsigned int) ); - _polygonFiles[thread]->write( &vertices[0] , sizeof(Index) * vSize ); - _polygonNum[thread]++; -} - -template< typename Index , typename VertexFactory > -void CoredFileMeshData< Index , VertexFactory >::addPolygon_s( unsigned int thread , const std::vector< CoredVertexIndex< Index > >& vertices ) -{ - std::vector< Index > polygon( vertices.size() ); - for( unsigned int i=0 ; i<(unsigned int)vertices.size() ; i++ ) - if( vertices[i].inCore ) polygon[i] = vertices[i].idx; - else polygon[i] = -vertices[i].idx-1; - return addPolygon_s( thread , polygon ); -} - -template< typename Index , typename VertexFactory > -Index CoredFileMeshData< Index , VertexFactory >::nextOutOfCoreVertex( VertexType& v ) -{ - if( _oocVertexFile->read( _buffer , _factory.bufferSize() ) ) - { - _factory.fromBuffer( _buffer , v ); - return 1; - } - else return 0; -} - -template< typename Index , typename VertexFactory > -Index CoredFileMeshData< Index , VertexFactory >::nextPolygon( std::vector< CoredVertexIndex< Index > >& vertices ) -{ - while( true ) - { - if( _threadIndex<(unsigned int)_polygonFiles.size() ) - { - unsigned int pSize; - if( _polygonFiles[ _threadIndex ]->read( &pSize , sizeof(unsigned int) ) ) - { - std::vector< Index > polygon( pSize ); - if( _polygonFiles[ _threadIndex ]->read( &polygon[0] , sizeof(Index)*pSize ) ) - { - vertices.resize( pSize ); - for( unsigned int i=0 ; i<(unsigned int)polygon.size() ; i++ ) - if( polygon[i]<0 ) vertices[i].idx = -polygon[i]-1 , vertices[i].inCore = false; - else vertices[i].idx = polygon[i] , vertices[i].inCore = true; - return 1; - } - ERROR_OUT( "Failed to read polygon from file" ); - } - else _threadIndex++; - } - else return 0; - } -} - -template< typename Index , typename VertexFactory > -size_t CoredFileMeshData< Index , VertexFactory >::outOfCoreVertexNum( void ){ return _oocVertexNum; } - -template< typename Index , typename VertexFactory > -size_t CoredFileMeshData< Index , VertexFactory >::polygonNum( void ) -{ - size_t count = 0; - for( size_t i=0 ; i<_polygonNum.size() ; i++ ) count += _polygonNum[i]; - return count; -} \ No newline at end of file diff --git a/Src/EDTInHeat.cpp b/Src/EDTInHeat.cpp index ac2945ea..b725b409 100644 --- a/Src/EDTInHeat.cpp +++ b/Src/EDTInHeat.cpp @@ -44,8 +44,6 @@ DAMAGE. #include "Ply.h" #include "VertexFactory.h" -MessageWriter messageWriter; - cmdLineParameter< char* > In( "in" ) , Out( "out" ) , @@ -137,34 +135,6 @@ void ShowUsage( char* ex ) printf( "\t[--%s]\n" , Verbose.name ); } -template< unsigned int Dim , class Real > -struct FEMTreeProfiler -{ - FEMTree< Dim , Real >& tree; - double t; - - FEMTreeProfiler( FEMTree< Dim , Real >& t ) : tree(t) { ; } - void start( void ){ t = Time() , FEMTree< Dim , Real >::ResetLocalMemoryUsage(); } - void print( const char* header ) const - { - FEMTree< Dim , Real >::MemoryUsage(); - if( header ) printf( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %d (MB)\n" , header , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); - else printf( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %d (MB)\n" , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); - } - void dumpOutput( const char* header ) const - { - FEMTree< Dim , Real >::MemoryUsage(); - if( header ) messageWriter( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %d (MB)\n" , header , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); - else messageWriter( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %d (MB)\n" , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); - } - void dumpOutput2( std::vector< std::string >& comments , const char* header ) const - { - FEMTree< Dim , Real >::MemoryUsage(); - if( header ) messageWriter( comments , "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %d (MB)\n" , header , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); - else messageWriter( comments , "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %d (MB)\n" , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); - } -}; - template< class Real , unsigned int Dim > XForm< Real , Dim+1 > GetPointXForm( const std::vector< Point< Real , Dim > >& vertices , Real scaleFactor ) { @@ -222,12 +192,15 @@ void _Execute( int argc , char* argv[] ) typedef typename FEMTree< Dim , Real >::template InterpolationInfo< Real , 0 > InterpolationInfo; typedef typename FEMTree< Dim , Real >::FEMTreeNode FEMTreeNode; std::vector< std::string > comments; - messageWriter( comments , "*****************************************\n" ); - messageWriter( comments , "*****************************************\n" ); - messageWriter( comments , "** Running EDT in Heat (Version %s) **\n" , VERSION ); - messageWriter( comments , "*****************************************\n" ); - messageWriter( comments , "*****************************************\n" ); - if( !Threads.set ) messageWriter( comments , "Running with %d threads\n" , Threads.value ); + if( Verbose.set ) + { + std::cout << "*****************************************" << std::endl; + std::cout << "*****************************************" << std::endl; + std::cout << "** Running EDT in Heat (Version " << VERSION ") **" << std::endl; + std::cout << "*****************************************" << std::endl; + std::cout << "*****************************************" << std::endl; + if( !Threads.set ) std::cout << "Running with " << Threads.value << " threads" << std::endl; + } XForm< Real , Dim+1 > modelToUnitCube , unitCubeToModel; if( InXForm.set ) @@ -256,14 +229,17 @@ void _Execute( int argc , char* argv[] ) if( params[i]->set ) { params[i]->writeValue( str ); - if( strlen( str ) ) messageWriter( comments , "\t--%s %s\n" , params[i]->name , str ); - else messageWriter( comments , "\t--%s\n" , params[i]->name ); + if( Verbose.set ) + { + if( strlen( str ) ) std::cout << "\t--" << params[i]->name << " " << str << std::endl; + else std::cout << "\t--" << params[i]->name << std::endl; + } } double startTime = Time(); FEMTree< Dim , Real > tree( MEMORY_ALLOCATOR_BLOCK_SIZE ); - FEMTreeProfiler< Dim , Real > profiler( tree ); + Profiler profiler(20); if( !In.set ) { ShowUsage( argv[0] ); @@ -276,7 +252,7 @@ void _Execute( int argc , char* argv[] ) // Read the mesh into the tree { - profiler.start(); + profiler.reset(); // Read the mesh std::vector< Point< Real , Dim > > vertices; std::vector< TriangleIndex< node_index_type > > triangles; @@ -320,38 +296,48 @@ void _Execute( int argc , char* argv[] ) } ); for( unsigned int t=0 ; t( nodes , (int)geometrySamples.size() , std::make_tuple() ); - profiler.dumpOutput2( comments , "# Thickened tree:" ); + if( Verbose.set ) std::cout << "# Thickened tree: " << profiler << std::endl; delete[] nodes; } InterpolationInfo *valueInfo = NULL; if( ValueWeight.value>0 ) { - profiler.start(); + profiler.reset(); if( ExactInterpolation.set ) valueInfo = FEMTree< Dim , Real >::template InitializeExactPointInterpolationInfo< Real , 0 >( tree , geometrySamples , ConstraintDual< Dim , Real >() , SystemDual< Dim , Real >( std::max< Real >( 0 , (Real)ValueWeight.value ) ) , true , false ); - else valueInfo = FEMTree< Dim , Real >::template InitializeApproximatePointInterpolationInfo< Real , 0 >( tree , geometrySamples , ConstraintDual< Dim , Real >() , SystemDual< Dim , Real >( std::max< Real >( 0 , (Real)ValueWeight.value ) ) , true , 0 ); - profiler.dumpOutput2( comments , "#Initialized point interpolation constraints:" ); + else valueInfo = FEMTree< Dim , Real >::template InitializeApproximatePointInterpolationInfo< Real , 0 >( tree , geometrySamples , ConstraintDual< Dim , Real >() , SystemDual< Dim , Real >( std::max< Real >( 0 , (Real)ValueWeight.value ) ) , true , Depth.value , 0 ); + if( Verbose.set ) std::cout << "#Initialized point interpolation constraints: " << profiler << std::endl; } // Finalize the topology of the tree { - profiler.start(); - tree.template finalizeForMultigrid< Degree , Degree >( BaseDepth.value , FullDepth.value , typename FEMTree< Dim , Real >::TrivialHasDataFunctor() , []( const FEMTreeNode * ){ return false; } , std::make_tuple( valueInfo ) ); - profiler.dumpOutput2( comments , "# Finalized tree:" ); + profiler.reset(); + + auto addNodeFunctor = [&]( int d , const int off[Dim] ){ return d<=FullDepth.value; }; + tree.template finalizeForMultigrid< Degree , Degree >( BaseDepth.value , addNodeFunctor , typename FEMTree< Dim , Real >::TrivialHasDataFunctor() , std::make_tuple( valueInfo ) ); + + if( Verbose.set ) std::cout << "# Finalized tree: " << profiler << std::endl; } - messageWriter( "Leaf Nodes / Active Nodes / Ghost Nodes: %llu / %llu / %llu\n" , (unsigned long long)tree.leaves() , (unsigned long long)tree.nodes() , (unsigned long long)tree.ghostNodes() ); - messageWriter( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage())/(1<<20) ); + if( Verbose.set ) + { + std::cout << "All Nodes / Active Nodes / Ghost Nodes: " << tree.allNodes() << " / " << tree.activeNodes() << " / " << tree.ghostNodes() << std::endl; + std::cout << "Memory Usage: " << float( MemoryInfo::Usage())/(1<<20) << " MB" << std::endl; + } SparseNodeData< Point< Real , Dim+1 > , IsotropicUIntPack< Dim , FEMTrivialSignature > > leafValues; const double GradientCutOff = 0; @@ -362,32 +348,32 @@ void _Execute( int argc , char* argv[] ) // Add the FEM constraints { - profiler.start(); + profiler.reset(); constraints = tree.initDenseNodeData( IsotropicUIntPack< Dim , FEMSig >() ); DenseNodeData< Point< Real , 1 > , IsotropicUIntPack< Dim , FEMTrivialSignature > > _constraints( tree.nodesSize() ); for( int i=0 ; i , IsotropicUIntPack< Dim , 0 > , IsotropicUIntPack< Dim , FEMTrivialSignature > , IsotropicUIntPack< Dim , 0 > > F( {1.} ); tree.addFEMConstraints( F , _constraints , constraints , Depth.value ); - profiler.dumpOutput2( comments , "# Set heat constraints:" ); + if( Verbose.set ) std::cout << "# Set heat constraints: " << profiler << std::endl; } // Solve the linear system { - profiler.start(); + profiler.reset(); typename FEMTree< Dim , Real >::SolverInfo sInfo; sInfo.cgDepth = 0 , sInfo.cascadic = false , sInfo.iters = GSIterations.value , sInfo.vCycles = 1 , sInfo.cgAccuracy = CGSolverAccuracy.value , sInfo.verbose = Verbose.set , sInfo.showResidual = ShowResidual.set , sInfo.showGlobalResidual = SHOW_GLOBAL_RESIDUAL_NONE , sInfo.sliceBlockSize = 1; sInfo.useSupportWeights = true; sInfo.sorRestrictionFunction = [&]( Real w , Real ){ return ( Real )( WeightScale.value * pow( w , WeightExponent.value ) ); }; { typename FEMIntegrator::template System< IsotropicUIntPack< Dim , FEMSig > , IsotropicUIntPack< Dim , 1 > > F( { 1. , (double)DiffusionTime.value } ); - heatSolution = tree.solveSystem( IsotropicUIntPack< Dim , FEMSig >() , F , constraints , Depth.value , sInfo ); + heatSolution = tree.solveSystem( IsotropicUIntPack< Dim , FEMSig >() , F , constraints , BaseDepth.value , Depth.value , sInfo ); } sInfo.baseVCycles = BaseVCycles.value; - profiler.dumpOutput2( comments , "# Heat system solved:" ); + if( Verbose.set ) std::cout << "# Heat system solved: " << profiler << std::endl; } // Evaluate the gradients at the leaves { - profiler.start(); + profiler.reset(); typename FEMTree< Dim , Real >::template MultiThreadedEvaluator< IsotropicUIntPack< Dim , FEMSig > , 0 > evaluator( &tree , heatSolution ); typedef typename RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >::template ConstNeighbors< IsotropicUIntPack< Dim , 3 > > OneRingNeighbors; @@ -467,7 +453,7 @@ void _Execute( int argc , char* argv[] ) } } ); - profiler.dumpOutput2( comments , "# Evaluated gradients:" ); + if( Verbose.set ) std::cout << "# Evaluated gradients: " << profiler << std::endl; } @@ -478,7 +464,7 @@ void _Execute( int argc , char* argv[] ) // Add the FEM constraints { - profiler.start(); + profiler.reset(); constraints = tree.initDenseNodeData( IsotropicUIntPack< Dim , FEMSig >() ); typename FEMIntegrator::template Constraint< IsotropicUIntPack< Dim , FEMSig > , IsotropicUIntPack< Dim , 1 > , IsotropicUIntPack< Dim , FEMTrivialSignature > , IsotropicUIntPack< Dim , 0 > , Dim+1 > F; typedef IsotropicUIntPack< Dim , 1 > Derivatives1; @@ -492,20 +478,20 @@ void _Execute( int argc , char* argv[] ) F.weights[d+1][TensorDerivatives< Derivatives1 >::Index( derivatives1 )][ TensorDerivatives< Derivatives2 >::Index( derivatives2 )] = 1.; } tree.addFEMConstraints( F , leafValues , constraints , Depth.value ); - profiler.dumpOutput2( comments , "# Set EDT constraints:" ); + if( Verbose.set ) std::cout << "# Set EDT constraints: " << profiler << std::endl; } // Add the interpolation constraints if( valueInfo ) { - profiler.start(); + profiler.reset(); tree.addInterpolationConstraints( constraints , Depth.value , std::make_tuple( valueInfo ) ); - profiler.dumpOutput2( comments , "#Set point constraints:" ); + if( Verbose.set ) std::cout << "#Set point constraints: " << profiler << std::endl; } // Solve the linear system { - profiler.start(); + profiler.reset(); typename FEMTree< Dim , Real >::SolverInfo sInfo; sInfo.cgDepth = 0 , sInfo.cascadic = true , sInfo.vCycles = 1 , sInfo.cgAccuracy = CGSolverAccuracy.value , sInfo.verbose = Verbose.set , sInfo.showResidual = ShowResidual.set , sInfo.showGlobalResidual = SHOW_GLOBAL_RESIDUAL_NONE , sInfo.sliceBlockSize = 1; sInfo.iters = GSIterations.value; @@ -513,8 +499,8 @@ void _Execute( int argc , char* argv[] ) sInfo.useSupportWeights = true; sInfo.sorRestrictionFunction = [&]( Real w , Real ){ return (Real)( WeightScale.value * pow( w , WeightExponent.value ) ); }; typename FEMIntegrator::template System< IsotropicUIntPack< Dim , FEMSig > , IsotropicUIntPack< Dim , 1 > > F( { 0. , 1. } ); - edtSolution = tree.solveSystem( IsotropicUIntPack< Dim , FEMSig >() , F , constraints , Depth.value , sInfo , std::make_tuple( valueInfo ) ); - profiler.dumpOutput2( comments , "# EDT system solved:" ); + edtSolution = tree.solveSystem( IsotropicUIntPack< Dim , FEMSig >() , F , constraints , BaseDepth.value , Depth.value , sInfo , std::make_tuple( valueInfo ) ); + if( Verbose.set ) std::cout << "# EDT system solved: " << profiler << std::endl; } { @@ -546,10 +532,11 @@ void _Execute( int argc , char* argv[] ) { FILE* fp = fopen( Out.value , "wb" ); if( !fp ) ERROR_OUT( "Failed to open file for writing: " , Out.value ); - FEMTree< Dim , Real >::WriteParameter( fp ); - DenseNodeData< Real , IsotropicUIntPack< Dim , FEMSig > >::WriteSignatures( fp ); - tree.write( fp , modelToUnitCube ); - edtSolution.write( fp ); + FileStream fs(fp); + FEMTree< Dim , Real >::WriteParameter( fs ); + DenseNodeData< Real , IsotropicUIntPack< Dim , FEMSig > >::WriteSignatures( fs ); + tree.write( fs , modelToUnitCube , false ); + edtSolution.write( fs ); fclose( fp ); } } @@ -573,11 +560,6 @@ void Execute( int argc , char* argv[] ) int main( int argc , char* argv[] ) { Timer timer; -#ifdef USE_SEG_FAULT_HANDLER - WARN( "using seg-fault handler" ); - StackTracer::exec = argv[0]; - signal( SIGSEGV , SignalHandler ); -#endif // USE_SEG_FAULT_HANDLER #ifdef ARRAY_DEBUG WARN( "Array debugging enabled" ); #endif // ARRAY_DEBUG @@ -585,7 +567,6 @@ int main( int argc , char* argv[] ) ThreadPool::DefaultChunkSize = ThreadChunkSize.value; ThreadPool::DefaultSchedule = (ThreadPool::ScheduleType)ScheduleType.value; if( MaxMemoryGB.value>0 ) SetPeakMemoryMB( MaxMemoryGB.value<<10 ); - messageWriter.echoSTDOUT = Verbose.set; #ifdef USE_DOUBLE typedef double Real; diff --git a/Src/FEMTree.Evaluation.inl b/Src/FEMTree.Evaluation.inl index 72638baf..8c0ff73f 100644 --- a/Src/FEMTree.Evaluation.inl +++ b/Src/FEMTree.Evaluation.inl @@ -772,11 +772,200 @@ Pointer( V ) FEMTree< Dim , Real >::regularGridEvaluate( const DenseNodeData< V ); for( int d=0 ; d +template< bool XMajor , class V , unsigned int ... DataSigs > +Pointer( V ) FEMTree< Dim , Real >::regularGridEvaluate( const DenseNodeData< V , UIntPack< DataSigs ... > >& coefficients , const unsigned int begin[Dim] , const unsigned int end[Dim] , unsigned int res[Dim] , bool primal ) const +{ + LocalDepth depth = _maxDepth; + Pointer( V ) _coefficients = regularGridUpSample< XMajor >( coefficients , depth ); + + const int _begin[] = { _BSplineBegin< DataSigs >( depth ) ... }; + const int _end [] = { _BSplineEnd< DataSigs >( depth ) ... }; + const int _dim [] = { ( _BSplineEnd< DataSigs >( depth ) - _BSplineBegin< DataSigs >( depth ) ) ... }; + + size_t cellCount = 1; + for( unsigned int d=0 ; d( cellCount ); + memset( values , 0 , sizeof(V) * cellCount ); + + if( primal ) + { + // evaluate at the cell corners + typedef UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::CornerSize ... > CornerSizes; + typedef UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::CornerEnd ... > CornerEnds; + + EvaluationData::CornerEvaluator* evaluators[] = { ( new typename BSplineEvaluationData< DataSigs >::template CornerEvaluator< 0 >::Evaluator() ) ... }; + for( int d=0 ; dset( depth ); + // Compute the offest from coefficient index to voxel index and the value of the stencil (if the voxel is interior) + StaticWindow< long long , UIntPack< ( BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::CornerSize ? BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::CornerSize : 1 ) ... > > offsets; + StaticWindow< double , UIntPack< ( BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::CornerSize ? BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::CornerSize : 1 ) ... > > cornerValues; + int dimMultiplier[Dim]; + if( XMajor ) + { + dimMultiplier[0] = 1; + for( int d=1 ; d=0 ; d-- ) dimMultiplier[d] = dimMultiplier[d+1] * _dim[d+1]; + } + + { + int center = ( 1<>1; + long long offset[Dim+1] ; offset[0] = 0; + double upValue[Dim+1] ; upValue[0] = 1; + WindowLoop< Dim >::Run + ( + ZeroUIntPack< Dim >() , CornerSizes() , + [&]( int d , int i ){ offset[d+1] = offset[d] + ( i - (int)CornerEnds::Values[d] - _begin[d] ) * dimMultiplier[d] ; upValue[d+1] = upValue[d] * evaluators[d]->value( center + i - (int)CornerEnds::Values[d] , center , false ); } , + [&]( long long& offsetValue , double& cornerValue ){ offsetValue = offset[Dim] , cornerValue = upValue[Dim]; } , + offsets() , cornerValues() + ); + } + ThreadPool::Parallel_for( 0 , cellCount , [&]( unsigned int , size_t c ) + { + V &value = values[c]; + int idx[Dim]; + { + size_t _c = c; + if( XMajor ) for( int d=0 ; d=_end[d] ) isInterior = false; + + if( isInterior ) + { +#ifdef SHOW_WARNINGS +#pragma message( "[WARNING] This should be modified to support 0-degree elements" ) +#endif // SHOW_WARNINGS + ConstPointer( long long ) offsetValues = offsets().data; + ConstPointer( double ) _cornerValues = cornerValues().data; + for( int i=0 ; i::Size ; i++ ) value += _coefficients[ offsetValues[i]+ii ] * (Real)_cornerValues[i]; + } + else + { + double upValues[Dim+1] ; upValues[0] = 1; // Accumulates the product of the weights + bool isValid[Dim+1] ; isValid[0] = true; + WindowLoop< Dim >::Run + ( + ZeroUIntPack< Dim >() , CornerSizes() , + [&]( int d , int i ) + { + int ii = idx[d] + i - (int)CornerEnds::Values[d]; + if( ii>=_begin[d] && ii<_end[d] ) + { + upValues[d+1] = upValues[d] * evaluators[d]->value( ii , idx[d] , false ); + isValid[d+1] = isValid[d]; + } + else isValid[d+1] = false; + } , + [&]( long long offsetValue ){ if( isValid[Dim] ) value += _coefficients[ offsetValue + ii ] * (Real)upValues[Dim]; } , + offsets() + ); + } + } + ); + for( int d=0 ; d::Degree >::SupportSize ... > SupportSizes; + typedef UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportEnd ... > SupportEnds; + + EvaluationData::CenterEvaluator* evaluators[] = { ( new typename BSplineEvaluationData< DataSigs >::template CenterEvaluator< 0 >::Evaluator() ) ... }; + for( int d=0 ; dset( depth ); + // Compute the offest from coefficient index to voxel index and the value of the stencil (if the voxel is interior) + StaticWindow< long long , UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportSize ... > > offsets; + StaticWindow< double , UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportSize ... > > centerValues; + + int dimMultiplier[Dim]; + if( XMajor ) + { + dimMultiplier[0] = 1; + for( int d=1 ; d=0 ; d-- ) dimMultiplier[d] = dimMultiplier[d+1] * _dim[d+1]; + } + + { + int center = ( 1<>1; + long long offset[Dim+1] ; offset[0] = 0; + double upValue[Dim+1] ; upValue[0] = 1; + WindowLoop< Dim >::Run + ( + ZeroUIntPack< Dim >() , SupportSizes() , + [&]( int d , int i ){ offset[d+1] = offset[d] + ( i - (int)SupportEnds::Values[d] - _begin[d] ) * dimMultiplier[d] ; upValue[d+1] = upValue[d] * evaluators[d]->value( center + i - (int)SupportEnds::Values[d] , center , false ); } , + [&]( long long& offsetValue , double& centerValue ){ offsetValue = offset[Dim] , centerValue = upValue[Dim]; } , + offsets() , centerValues() + ); + } + ThreadPool::Parallel_for( 0 , cellCount , [&]( unsigned int , size_t c ) + { + V &value = values[c]; + int idx[Dim]; + { + size_t _c = c; + if( XMajor ) for( int d=0 ; d=_end[d] ) isInterior = false; + + if( isInterior ) + { + ConstPointer( long long ) offsetValues = offsets().data; + ConstPointer( double ) _centerValues = centerValues().data; + for( int i=0 ; i::Size ; i++ ) value += _coefficients[ offsetValues[i] + ii ] * (Real)_centerValues[i]; + } + else + { + double upValues[Dim+1] ; upValues[0] = 1; // Accumulates the product of the weights + bool isValid[Dim+1] ; isValid[0] = true; + WindowLoop< Dim >::Run + ( + ZeroUIntPack< Dim >() , SupportSizes() , + [&]( int d , int i ) + { + int ii = idx[d] + i - (int)SupportEnds::Values[d]; + if( ii>=_begin[d] && ii<_end[d] ) + { + upValues[d+1] = upValues[d] * evaluators[d]->value( ii , idx[d] , false ); + isValid[d+1] = isValid[d]; + } + else isValid[d+1] = false; + } , + [&]( long long offsetValue ){ if( isValid[Dim] ) value += _coefficients[ offsetValue + ii ] * (Real)upValues[Dim]; } , + offsets() + ); + } + } + ); + for( int d=0 ; d template< bool XMajor , class V , unsigned int ... DataSigs > Pointer( V ) FEMTree< Dim , Real >::regularGridUpSample( const DenseNodeData< V , UIntPack< DataSigs ... > >& coefficients , LocalDepth depth ) const diff --git a/Src/FEMTree.Initialize.inl b/Src/FEMTree.Initialize.inl index d7ca71aa..b5a8ee53 100644 --- a/Src/FEMTree.Initialize.inl +++ b/Src/FEMTree.Initialize.inl @@ -30,122 +30,62 @@ DAMAGE. // FEMTreeInitializer // //////////////////////// template< unsigned int Dim , class Real > -size_t FEMTreeInitializer< Dim , Real >::Initialize( FEMTreeNode& node , int maxDepth , std::function< bool ( int , int[] ) > Refine , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ) +size_t FEMTreeInitializer< Dim , Real >::Initialize( FEMTreeNode &root , int maxDepth , std::function< bool ( int , int[] ) > Refine , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ) +{ + typename FEMTreeNode::SubTreeExtractor subtreeExtractor( root ); + return _Initialize( root , maxDepth , Refine , nodeAllocator , NodeInitializer ); +} + +template< unsigned int Dim , class Real > +size_t FEMTreeInitializer< Dim , Real >::_Initialize( FEMTreeNode &node , int maxDepth , std::function< bool ( int , int[] ) > Refine , Allocator< FEMTreeNode > *nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ) { size_t count = 0; int d , off[3]; node.depthAndOffset( d , off ); - if( node.depth()( nodeAllocator , NodeInitializer ) , count += 1<( nodeAllocator , NodeInitializer ) , count += 1< template< typename AuxData > -size_t FEMTreeInitializer< Dim , Real >::Initialize( FEMTreeNode& root , typename InputPointStream< AuxData >::StreamType &pointStream , int maxDepth , std::vector< PointSample >& samplePoints , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ) +size_t FEMTreeInitializer< Dim , Real >::Initialize( StreamInitializationData &sid , FEMTreeNode &root , typename InputPointStream< AuxData >::StreamType &pointStream , AuxData zeroData , int maxDepth , std::vector< PointSample >& samplePoints , std::vector< typename InputPointStream< AuxData >::DataType > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , typename InputPointStream< AuxData >::DataType & ) > ProcessData ) { - auto Leaf = [&]( FEMTreeNode& root , Point< Real , Dim > p , int maxDepth ) - { - for( int d=0 ; d1 ) return (FEMTreeNode*)NULL; - Point< Real , Dim > center; - for( int d=0 ; dchildren ) node->template initChildren< false >( nodeAllocator , NodeInitializer ); - int cIndex = FEMTreeNode::ChildIndex( center , p ); - node = node->children + cIndex; - d++; - width /= 2; - for( int dd=0 ; dd>dd) & 1 ) center[dd] += width/2; - else center[dd] -= width/2; - } - return node; - }; - - // Add the point data - size_t outOfBoundPoints = 0 , pointCount = 0; - { - std::vector< node_index_type > nodeToIndexMap; - Point< Real , Dim > p; - while( pointStream.nextPoint( p ) ) - { - Real weight = (Real)1.; - FEMTreeNode* temp = Leaf( root , p , maxDepth ); - if( !temp ){ outOfBoundPoints++ ; continue; } - node_index_type nodeIndex = temp->nodeData.nodeIndex; - if( nodeIndex>=(node_index_type)nodeToIndexMap.size() ) nodeToIndexMap.resize( nodeIndex+1 , -1 ); - node_index_type idx = nodeToIndexMap[ nodeIndex ]; - if( idx==-1 ) - { - idx = (node_index_type)samplePoints.size(); - nodeToIndexMap[ nodeIndex ] = idx; - samplePoints.resize( idx+1 ) , samplePoints[idx].node = temp; - } - samplePoints[idx].sample += ProjectiveData< Point< Real , Dim > , Real >( p*weight , weight ); - pointCount++; - } - pointStream.reset(); - } - if( outOfBoundPoints ) WARN( "Found out-of-bound points: " , outOfBoundPoints ); - if( std::is_same< Real , float >::value ) - { - std::vector< size_t > badNodeCounts( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , samplePoints.size() , [&]( unsigned int thread , size_t i ) - { - Point< Real , Dim > start; - Real width; - samplePoints[i].node->startAndWidth( start , width ); - Point< Real , Dim > p = samplePoints[i].sample.data / samplePoints[i].sample.weight; - bool foundBadNode = false; - for( int d=0 ; dstart[d]+width ) foundBadNode = true , p[d] = start[d] + width; - } - if( foundBadNode ) - { - samplePoints[i].sample.data = p * samplePoints[i].sample.weight; - badNodeCounts[ thread ]++; - } - } - ); - size_t badNodeCount = 0; - for( int i=0 ; i::MemoryUsage(); - return pointCount; + return Initialize< AuxData >( sid , root , pointStream , zeroData , maxDepth , [&]( Point< Real , Dim > ){ return maxDepth; } , samplePoints , sampleData , mergeNodeSamples , nodeAllocator , NodeInitializer , ProcessData ); } template< unsigned int Dim , class Real > template< typename AuxData > -size_t FEMTreeInitializer< Dim , Real >::Initialize( FEMTreeNode& root , typename InputPointStream< AuxData >::StreamType &pointStream , int maxDepth , std::vector< PointSample >& samplePoints , std::vector< typename InputPointStream< AuxData >::DataType > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , typename InputPointStream< AuxData >::DataType & ) > ProcessData ) +size_t FEMTreeInitializer< Dim , Real >::Initialize( StreamInitializationData &sid , FEMTreeNode& root , typename InputPointStream< AuxData >::StreamType &pointStream , AuxData zeroData , int maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , std::vector< PointSample >& samplePoints , std::vector< typename InputPointStream< AuxData >::DataType > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , typename InputPointStream< AuxData >::DataType & ) > ProcessData ) { - auto Leaf = [&]( FEMTreeNode& root , Point< Real , Dim > p , int maxDepth ) + typename FEMTreeNode::SubTreeExtractor subtreeExtractor( root ); + + + auto Leaf = [&]( FEMTreeNode& root , Point< Real , Dim > p , unsigned int maxDepth ) { for( int d=0 ; d1 ) return (FEMTreeNode*)NULL; Point< Real , Dim > center; - for( int d=0 ; d::LocalDepth depth; + typename FEMTree< Dim , Real >::LocalOffset offset; + root.centerAndWidth( center , width ); + root.depthAndOffset( depth , offset ); + FEMTreeNode* node = &root; - int d = 0; - while( dchildren ) node->template initChildren< false >( nodeAllocator , NodeInitializer ); int cIndex = FEMTreeNode::ChildIndex( center , p ); node = node->children + cIndex; - d++; width /= 2; + + depth++; for( int dd=0 ; dd>dd) & 1 ) center[dd] += width/2; - else center[dd] -= width/2; + if( (cIndex>>dd) & 1 ) center[dd] += width/2 , offset[dd] = (offset[dd]<<1) | 1; + else center[dd] -= width/2 , offset[dd] = (offset[dd]<<1) | 0; } return node; }; @@ -153,15 +93,16 @@ size_t FEMTreeInitializer< Dim , Real >::Initialize( FEMTreeNode& root , typenam // Add the point data size_t outOfBoundPoints = 0 , badData = 0 , pointCount = 0; { - std::vector< node_index_type > nodeToIndexMap; + std::vector< node_index_type > &nodeToIndexMap = sid._nodeToIndexMap; typename InputPointStream< AuxData >::PointAndDataType pd; + pd.template get<1>() = zeroData; while( pointStream.next( pd ) ) { Point< Real , Dim > p = pd.template get<0>(); typename InputPointStream< AuxData >::DataType d = InputPointStream< AuxData >::GetData( pd ); Real weight = ProcessData( p , d ); if( weight<=0 ){ badData++ ; continue; } - FEMTreeNode* temp = Leaf( root , p , maxDepth ); + FEMTreeNode *temp = Leaf( root , p , pointDepthFunctor(p) ); if( !temp ){ outOfBoundPoints++ ; continue; } node_index_type nodeIndex = temp->nodeData.nodeIndex; if( mergeNodeSamples ) @@ -195,40 +136,14 @@ size_t FEMTreeInitializer< Dim , Real >::Initialize( FEMTreeNode& root , typenam } pointStream.reset(); } - if( outOfBoundPoints ) WARN( "Found out-of-bound points: " , outOfBoundPoints ); - if( badData ) WARN( "Found bad data: " , badData ); - if( std::is_same< Real , float >::value ) - { - std::vector< size_t > badNodeCounts( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , samplePoints.size() , [&]( unsigned int thread , size_t i ) - { - Point< Real , Dim > start; - Real width; - samplePoints[i].node->startAndWidth( start , width ); - Point< Real , Dim > p = samplePoints[i].sample.data / samplePoints[i].sample.weight; - bool foundBadNode = false; - for( int d=0 ; dstart[d]+width ) foundBadNode = true , p[d] = start[d] + width; - } - if( foundBadNode ) - { - samplePoints[i].sample.data = p * samplePoints[i].sample.weight; - badNodeCounts[ thread ]++; - } - } - ); - size_t badNodeCount = 0; - for( int i=0 ; i::MemoryUsage(); return pointCount; } + template< unsigned int Dim , class Real > void FEMTreeInitializer< Dim , Real >::Initialize( FEMTreeNode& root , const std::vector< Point< Real , Dim > >& vertices , const std::vector< SimplexIndex< Dim-1 , node_index_type > >& simplices , int maxDepth , std::vector< PointSample >& samples , bool mergeNodeSamples , std::vector< Allocator< FEMTreeNode > * > &nodeAllocators , std::function< void ( FEMTreeNode& ) > NodeInitializer ) { + typename FEMTreeNode::SubTreeExtractor subtreeExtractor( root ); + std::vector< node_index_type > nodeToIndexMap; ThreadPool::Parallel_for( 0 , simplices.size() , [&]( unsigned int t , size_t i ) { @@ -238,29 +153,30 @@ void FEMTreeInitializer< Dim , Real >::Initialize( FEMTreeNode& root , const std else _AddSimplex< true >( root , s , maxDepth , samples , NULL , nodeAllocators.size() ? nodeAllocators[t] : NULL , NodeInitializer ); } ); - FEMTree< Dim , Real >::MemoryUsage(); } template< unsigned int Dim , class Real > void FEMTreeInitializer< Dim , Real >::Initialize( FEMTreeNode &root , const std::vector< ProjectiveData< Point< Real , Dim > , Real > > &points , int maxDepth , std::vector< PointSample >& samples , bool mergeNodeSamples , std::vector< Allocator< FEMTreeNode > * > &nodeAllocators , std::function< void ( FEMTreeNode& ) > NodeInitializer ) { + typename FEMTreeNode::SubTreeExtractor subtreeExtractor( root ); + std::vector< node_index_type > nodeToIndexMap; ThreadPool::Parallel_for( 0 , points.size() , [&]( unsigned int t , size_t i ) { _AddSample< true >( root , points[i] , maxDepth , samples , mergeNodeSamples ? &nodeToIndexMap :NULL , nodeAllocators.size() ? nodeAllocators[t] : NULL , NodeInitializer ); } ); - FEMTree< Dim , Real >::MemoryUsage(); } template< unsigned int Dim , class Real > void FEMTreeInitializer< Dim , Real >::Initialize( FEMTreeNode &root , const std::vector< ProjectiveData< Point< Real , Dim > , Real > > &points , int maxDepth , std::vector< PointSample >& samples , bool mergeNodeSamples ) { + typename FEMTreeNode::SubTreeExtractor subtreeExtractor( root ); + std::vector< node_index_type > nodeToIndexMap; ThreadPool::Parallel_for( 0 , points.size() , [&]( unsigned int t , size_t i ) { _AddSample( root , points[i] , maxDepth , samples , mergeNodeSamples ? &nodeToIndexMap : NULL ); } ); - FEMTree< Dim , Real >::MemoryUsage(); } template< unsigned int Dim , class Real > @@ -590,8 +506,6 @@ void FEMTreeInitializer< Dim , Real >::Initialize( FEMTreeNode& root , const std for( int j=0 ; j( *roots[i] , cellSimplices[j].first , cellSimplices[j].second , maxDepth , nodeSimplices , nodeToIndexMap , _nodeAllocators[t] , NodeInitializer ); } ); } - - FEMTree< Dim , Real >::MemoryUsage(); } template< unsigned int Dim , class Real > @@ -781,7 +695,7 @@ size_t FEMTreeInitializer< Dim , Real >::Initialize( FEMTreeNode& root , ConstPo template< unsigned int Dim , class Real > template< bool Dual , class Data > -unsigned int FEMTreeInitializer< Dim , Real >::Initialize( FEMTreeNode& root , DerivativeStream< Data >& dStream , std::vector< NodeSample< Dim , Data > > derivatives[Dim] , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ) +unsigned int FEMTreeInitializer< Dim , Real >::Initialize( FEMTreeNode& root , DerivativeStream< Data >& dStream , Data zeroData , std::vector< NodeSample< Dim , Data > > derivatives[Dim] , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ) { // Note: // -- Dual: The difference between [i] and [i+1] is stored at cell [i+1] @@ -813,7 +727,7 @@ unsigned int FEMTreeInitializer< Dim , Real >::Initialize( FEMTreeNode& root , D while( (unsigned int)( (1< DenseNodeData< typename FEMTreeInitializer< Dim , Real >::GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > FEMTreeInitializer< Dim , Real >::_GetGeometryNodeDesignators( FEMTreeNode *root , const std::vector< Point< Real , Dim > >& vertices , const std::vector< SimplexIndex< Dim-1 , node_index_type > >& simplices , const std::vector< Point< Real , Dim > > &normals , unsigned int regularGridDepth , unsigned int maxDepth , std::vector< Allocator< FEMTreeNode > * > &nodeAllocators , std::function< void ( FEMTreeNode& ) > NodeInitializer ) { + typename FEMTreeNode::SubTreeExtractor subtreeExtractor( root ); + typedef typename FEMTreeNode::template ConstNeighborKey< IsotropicUIntPack< Dim , 1 > , IsotropicUIntPack< Dim , 1 > > NeighborKey; typedef typename FEMTreeNode::template ConstNeighbors< IsotropicUIntPack< Dim , 3 > > Neighbors; DenseNodeData< typename FEMTreeInitializer< Dim , Real >::GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > geometryNodeDesignators; @@ -875,7 +791,7 @@ DenseNodeData< typename FEMTreeInitializer< Dim , Real >::GeometryNodeType , Iso // Mark all the nodes containing geometry node_index_type nodeCount = 0; - for( FEMTreeNode *node=root->nextNode() ; node ; node=root->nextNode( node ) ) nodeCount = std::max< node_index_type >( nodeCount , node->nodeData.nodeIndex ); + root->processNodes( [&]( FEMTreeNode *node ){ nodeCount = std::max< node_index_type >( nodeCount , node->nodeData.nodeIndex ); } ); nodeCount++; geometryNodeDesignators.resize( nodeCount ); diff --git a/Src/FEMTree.IsoSurface.specialized.inl b/Src/FEMTree.IsoSurface.specialized.inl deleted file mode 100644 index 9743c5dd..00000000 --- a/Src/FEMTree.IsoSurface.specialized.inl +++ /dev/null @@ -1,1906 +0,0 @@ -/* -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 -#include "MyMiscellany.h" -#include "MarchingCubes.h" -#include "MAT.h" - - -// Specialized iso-surface extraction -template< class Real , class Vertex > -struct IsoSurfaceExtractor< 3 , Real , Vertex > -{ - static const unsigned int Dim = 3; - typedef typename FEMTree< Dim , Real >::LocalDepth LocalDepth; - typedef typename FEMTree< Dim , Real >::LocalOffset LocalOffset; - typedef typename FEMTree< Dim , Real >::ConstOneRingNeighborKey ConstOneRingNeighborKey; - typedef typename FEMTree< Dim , Real >::ConstOneRingNeighbors ConstOneRingNeighbors; - typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > TreeNode; - template< unsigned int WeightDegree > using DensityEstimator = typename FEMTree< Dim , Real >::template DensityEstimator< WeightDegree >; - template< typename FEMSigPack , unsigned int PointD > using _Evaluator = typename FEMTree< Dim , Real >::template _Evaluator< FEMSigPack , PointD >; -protected: - static std::mutex _pointInsertionMutex; - static std::atomic< size_t > _BadRootCount; - ////////// - // _Key // - ////////// - struct _Key - { - int idx[Dim]; - - _Key( void ){ for( unsigned int d=0 ; d TreeOctNode; - public: - template< unsigned int Indices > - struct _Indices - { - node_index_type idx[Indices]; - _Indices( void ){ for( unsigned int i=0 ; i::template ElementNum< 0 >() > SquareCornerIndices; - typedef _Indices< HyperCube::Cube< Dim-1 >::template ElementNum< 1 >() > SquareEdgeIndices; - typedef _Indices< HyperCube::Cube< Dim-1 >::template ElementNum< 2 >() > SquareFaceIndices; - - struct SliceTableData - { - Pointer( SquareCornerIndices ) cTable; - Pointer( SquareEdgeIndices ) eTable; - Pointer( SquareFaceIndices ) fTable; - node_index_type nodeOffset; - node_index_type cCount , eCount , fCount; - node_index_type nodeCount; - SliceTableData( void ){ fCount = eCount = cCount = 0 , _oldNodeCount = 0 , cTable = NullPointer( SquareCornerIndices ) , eTable = NullPointer( SquareEdgeIndices ) , fTable = NullPointer( SquareFaceIndices ) , _cMap = _eMap = _fMap = NullPointer( node_index_type ) , _processed = NullPointer( char ); } - void clear( void ){ DeletePointer( cTable ) ; DeletePointer( eTable ) ; DeletePointer( fTable ) ; DeletePointer( _cMap ) ; DeletePointer( _eMap ) ; DeletePointer( _fMap ) ; DeletePointer( _processed ) ; fCount = eCount = cCount = 0; } - ~SliceTableData( void ){ clear(); } - - SquareCornerIndices& cornerIndices( const TreeOctNode* node ) { return cTable[ node->nodeData.nodeIndex - nodeOffset ]; } - SquareCornerIndices& cornerIndices( node_index_type idx ) { return cTable[ idx - nodeOffset ]; } - const SquareCornerIndices& cornerIndices( const TreeOctNode* node ) const { return cTable[ node->nodeData.nodeIndex - nodeOffset ]; } - const SquareCornerIndices& cornerIndices( node_index_type idx ) const { return cTable[ idx - nodeOffset ]; } - SquareEdgeIndices& edgeIndices( const TreeOctNode* node ) { return eTable[ node->nodeData.nodeIndex - nodeOffset ]; } - SquareEdgeIndices& edgeIndices( node_index_type idx ) { return eTable[ idx - nodeOffset ]; } - const SquareEdgeIndices& edgeIndices( const TreeOctNode* node ) const { return eTable[ node->nodeData.nodeIndex - nodeOffset ]; } - const SquareEdgeIndices& edgeIndices( node_index_type idx ) const { return eTable[ idx - nodeOffset ]; } - SquareFaceIndices& faceIndices( const TreeOctNode* node ) { return fTable[ node->nodeData.nodeIndex - nodeOffset ]; } - SquareFaceIndices& faceIndices( node_index_type idx ) { return fTable[ idx - nodeOffset ]; } - const SquareFaceIndices& faceIndices( const TreeOctNode* node ) const { return fTable[ node->nodeData.nodeIndex - nodeOffset ]; } - const SquareFaceIndices& faceIndices( node_index_type idx ) const { return fTable[ idx - nodeOffset ]; } - - protected: - Pointer( node_index_type ) _cMap; - Pointer( node_index_type ) _eMap; - Pointer( node_index_type ) _fMap; - Pointer( char ) _processed; - node_index_type _oldNodeCount; - friend SliceData; - }; - struct XSliceTableData - { - Pointer( SquareCornerIndices ) eTable; - Pointer( SquareEdgeIndices ) fTable; - node_index_type nodeOffset; - node_index_type fCount , eCount; - node_index_type nodeCount; - XSliceTableData( void ){ fCount = eCount = 0 , _oldNodeCount = 0 , eTable = NullPointer( SquareCornerIndices ) , fTable = NullPointer( SquareEdgeIndices ) , _eMap = _fMap = NullPointer( node_index_type ); } - ~XSliceTableData( void ){ clear(); } - void clear( void ) { DeletePointer( fTable ) ; DeletePointer( eTable ) ; DeletePointer( _eMap ) ; DeletePointer( _fMap ) ; fCount = eCount = 0; } - - SquareCornerIndices& edgeIndices( const TreeOctNode* node ) { return eTable[ node->nodeData.nodeIndex - nodeOffset ]; } - SquareCornerIndices& edgeIndices( node_index_type idx ) { return eTable[ idx - nodeOffset ]; } - const SquareCornerIndices& edgeIndices( const TreeOctNode* node ) const { return eTable[ node->nodeData.nodeIndex - nodeOffset ]; } - const SquareCornerIndices& edgeIndices( node_index_type idx ) const { return eTable[ idx - nodeOffset ]; } - SquareEdgeIndices& faceIndices( const TreeOctNode* node ) { return fTable[ node->nodeData.nodeIndex - nodeOffset ]; } - SquareEdgeIndices& faceIndices( node_index_type idx ) { return fTable[ idx - nodeOffset ]; } - const SquareEdgeIndices& faceIndices( const TreeOctNode* node ) const { return fTable[ node->nodeData.nodeIndex - nodeOffset ]; } - const SquareEdgeIndices& faceIndices( node_index_type idx ) const { return fTable[ idx - nodeOffset ]; } - protected: - Pointer( node_index_type ) _eMap; - Pointer( node_index_type ) _fMap; - node_index_type _oldNodeCount; - friend SliceData; - }; - template< unsigned int D , unsigned int ... Ks > struct HyperCubeTables{}; - template< unsigned int D , unsigned int K > - struct HyperCubeTables< D , K > - { - static constexpr unsigned int IncidentCubeNum = HyperCube::Cube< D >::template IncidentCubeNum< K >(); - static constexpr unsigned int ElementNum = HyperCube::Cube< D >::template ElementNum< K >(); - static unsigned int CellOffset[ ElementNum ][ IncidentCubeNum ]; - static unsigned int IncidentElementCoIndex[ ElementNum ][ IncidentCubeNum ]; - static unsigned int CellOffsetAntipodal[ ElementNum ]; - static typename HyperCube::Cube< D >::template IncidentCubeIndex< K > IncidentCube[ ElementNum ]; - static typename HyperCube::Direction Directions[ ElementNum ][ D ]; - - static void SetTables( void ) - { - for( typename HyperCube::Cube< D >::template Element< K > e ; e::template ElementNum< K >() ; e++ ) - { - for( typename HyperCube::Cube< D >::template IncidentCubeIndex< K > i ; i::template IncidentCubeNum< K >() ; i++ ) - { - CellOffset[e.index][i.index] = HyperCube::Cube< D >::CellOffset( e , i ); - IncidentElementCoIndex[e.index][i.index] = HyperCube::Cube< D >::IncidentElement( e , i ).coIndex(); - } - CellOffsetAntipodal[e.index] = HyperCube::Cube< D >::CellOffset( e , HyperCube::Cube< D >::IncidentCube( e ).antipodal() ); - IncidentCube[ e.index ] = HyperCube::Cube< D >::IncidentCube( e ); - e.directions( Directions[e.index] ); - } - } - }; - template< unsigned int D , unsigned int K1 , unsigned int K2 > - struct HyperCubeTables< D , K1 , K2 > - { - static constexpr unsigned int ElementNum1 = HyperCube::Cube< D >::template ElementNum< K1 >(); - static constexpr unsigned int ElementNum2 = HyperCube::Cube< D >::template ElementNum< K2 >(); - static constexpr unsigned int OverlapElementNum = HyperCube::Cube< D >::template OverlapElementNum< K1 , K2 >(); - static typename HyperCube::Cube< D >::template Element< K2 > OverlapElements[ ElementNum1 ][ OverlapElementNum ]; - static bool Overlap[ ElementNum1 ][ ElementNum2 ]; - - static void SetTables( void ) - { - for( typename HyperCube::Cube< D >::template Element< K1 > e ; e::template ElementNum< K1 >() ; e++ ) - { - for( typename HyperCube::Cube< D >::template Element< K2 > _e ; _e::template ElementNum< K2 >() ; _e++ ) - Overlap[e.index][_e.index] = HyperCube::Cube< D >::Overlap( e , _e ); - HyperCube::Cube< D >::OverlapElements( e , OverlapElements[e.index] ); - } - if( !K2 ) HyperCubeTables< D , K1 >::SetTables(); - } - }; - - template< unsigned int D=Dim , unsigned int K1=Dim , unsigned int K2=Dim > static typename std::enable_if< K2!=0 >::type SetHyperCubeTables( void ) - { - HyperCubeTables< D , K1 , K2 >::SetTables() ; SetHyperCubeTables< D , K1 , K2-1 >(); - } - template< unsigned int D=Dim , unsigned int K1=Dim , unsigned int K2=Dim > static typename std::enable_if< K1!=0 && K2==0 >::type SetHyperCubeTables( void ) - { - HyperCubeTables< D , K1 , K2 >::SetTables(); SetHyperCubeTables< D , K1-1 , D >(); - } - template< unsigned int D=Dim , unsigned int K1=Dim , unsigned int K2=Dim > static typename std::enable_if< D!=1 && K1==0 && K2==0 >::type SetHyperCubeTables( void ) - { - HyperCubeTables< D , K1 , K2 >::SetTables() ; SetHyperCubeTables< D-1 , D-1 , D-1 >(); - } - template< unsigned int D=Dim , unsigned int K1=Dim , unsigned int K2=Dim > static typename std::enable_if< D==1 && K1==0 && K2==0 >::type SetHyperCubeTables( void ) - { - HyperCubeTables< D , K1 , K2 >::SetTables(); - } - - static void SetSliceTableData( const SortedTreeNodes< Dim >& sNodes , SliceTableData* sData0 , XSliceTableData* xData , SliceTableData* sData1 , int depth , int offset ) - { - // [NOTE] This is structure is purely for determining adjacency and is independent of the FEM degree - typedef typename FEMTree< Dim , Real >::ConstOneRingNeighborKey ConstOneRingNeighborKey; - if( offset<0 || offset>((size_t)1< span( sNodes.begin( depth , offset-1 ) , sNodes.end( depth , offset ) ); - sData0->nodeOffset = span.first , sData0->nodeCount = span.second - span.first; - } - if( sData1 ) - { - std::pair< node_index_type , node_index_type > span( sNodes.begin( depth , offset ) , sNodes.end( depth , offset+1 ) ); - sData1->nodeOffset = span.first , sData1->nodeCount = span.second - span.first; - } - if( xData ) - { - std::pair< node_index_type , node_index_type > span( sNodes.begin( depth , offset ) , sNodes.end( depth , offset ) ); - xData->nodeOffset = span.first , xData->nodeCount = span.second - span.first; - } - SliceTableData* sData[] = { sData0 , sData1 }; - for( int i=0 ; i<2 ; i++ ) if( sData[i] ) - { - if( sData[i]->nodeCount>sData[i]->_oldNodeCount ) - { - DeletePointer( sData[i]->_cMap ) ; DeletePointer( sData[i]->_eMap ) ; DeletePointer( sData[i]->_fMap ); - DeletePointer( sData[i]->cTable ) ; DeletePointer( sData[i]->eTable ) ; DeletePointer( sData[i]->fTable ); - DeletePointer( sData[i]->_processed ); - sData[i]->_cMap = NewPointer< node_index_type >( sData[i]->nodeCount * HyperCube::Cube< Dim-1 >::template ElementNum< 0 >() ); - sData[i]->_eMap = NewPointer< node_index_type >( sData[i]->nodeCount * HyperCube::Cube< Dim-1 >::template ElementNum< 1 >() ); - sData[i]->_fMap = NewPointer< node_index_type >( sData[i]->nodeCount * HyperCube::Cube< Dim-1 >::template ElementNum< 2 >() ); - sData[i]->_processed = NewPointer< char >( sData[i]->nodeCount ); - sData[i]->cTable = NewPointer< typename SliceData::SquareCornerIndices >( sData[i]->nodeCount ); - sData[i]->eTable = NewPointer< typename SliceData::SquareEdgeIndices >( sData[i]->nodeCount ); - sData[i]->fTable = NewPointer< typename SliceData::SquareFaceIndices >( sData[i]->nodeCount ); - sData[i]->_oldNodeCount = sData[i]->nodeCount; - } - memset( sData[i]->_cMap , 0 , sizeof(node_index_type) * sData[i]->nodeCount * HyperCube::Cube< Dim-1 >::template ElementNum< 0 >() ); - memset( sData[i]->_eMap , 0 , sizeof(node_index_type) * sData[i]->nodeCount * HyperCube::Cube< Dim-1 >::template ElementNum< 1 >() ); - memset( sData[i]->_fMap , 0 , sizeof(node_index_type) * sData[i]->nodeCount * HyperCube::Cube< Dim-1 >::template ElementNum< 2 >() ); - memset( sData[i]->_processed , 0 , sizeof(char) * sData[i]->nodeCount ); - } - if( xData ) - { - if( xData->nodeCount>xData->_oldNodeCount ) - { - DeletePointer( xData->_eMap ) ; DeletePointer( xData->_fMap ); - DeletePointer( xData->eTable ) ; DeletePointer( xData->fTable ); - xData->_eMap = NewPointer< node_index_type >( xData->nodeCount * HyperCube::Cube< Dim-1 >::template ElementNum< 0 >() ); - xData->_fMap = NewPointer< node_index_type >( xData->nodeCount * HyperCube::Cube< Dim-1 >::template ElementNum< 1 >() ); - xData->eTable = NewPointer< typename SliceData::SquareCornerIndices >( xData->nodeCount ); - xData->fTable = NewPointer< typename SliceData::SquareEdgeIndices >( xData->nodeCount ); - xData->_oldNodeCount = xData->nodeCount; - } - memset( xData->_eMap , 0 , sizeof(node_index_type) * xData->nodeCount * HyperCube::Cube< Dim-1 >::template ElementNum< 0 >() ); - memset( xData->_fMap , 0 , sizeof(node_index_type) * xData->nodeCount * HyperCube::Cube< Dim-1 >::template ElementNum< 1 >() ); - } - std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); - for( size_t i=0 ; i::ConstOneRingNeighbors ConstNeighbors; - - // Process the corners - // z: which side of the cell \in {0,1} - // zOff: which neighbor \in {-1,0,1} - auto ProcessCorners = []( SliceTableData& sData , const ConstNeighbors& neighbors , HyperCube::Direction zDir , int zOff ) - { - const TreeOctNode* node = neighbors.neighbors[1][1][1+zOff]; - node_index_type i = node->nodeData.nodeIndex; - // Iterate over the corners in the face - for( typename HyperCube::Cube< Dim-1 >::template Element< 0 > _c ; _c::template ElementNum< 0 >() ; _c++ ) - { - bool owner = true; - - typename HyperCube::Cube< Dim >::template Element< 0 > c( zDir , _c.index ); // Corner-in-cube index - typename HyperCube::Cube< Dim >::template IncidentCubeIndex< 0 > my_ic = HyperCubeTables< Dim , 0 >::IncidentCube[c.index]; // The index of the node relative to the corner - for( typename HyperCube::Cube< Dim >::template IncidentCubeIndex< 0 > ic ; ic::template IncidentCubeNum< 0 >() ; ic++ ) // Iterate over the nodes adjacent to the corner - { - // Get the index of cube relative to the corner neighbors - unsigned int xx = HyperCubeTables< Dim , 0 >::CellOffset[c.index][ic.index] + zOff; - // If the neighbor exists and comes before, they own the corner - if( neighbors.neighbors.data[xx] && ic::template ElementNum< 0 >() + _c.index; - sData._cMap[ myCount ] = 1; - // Set the corner pointer for all cubes incident on the corner - for( typename HyperCube::Cube< Dim >::template IncidentCubeIndex< 0 > ic ; ic::template IncidentCubeNum< 0 >() ; ic++ ) // Iterate over the nodes adjacent to the corner - { - unsigned int xx = HyperCubeTables< Dim , 0 >::CellOffset[c.index][ic.index] + zOff; - // If the neighbor exits, sets its corner - if( neighbors.neighbors.data[xx] ) sData.cornerIndices( neighbors.neighbors.data[xx] )[ HyperCubeTables< Dim , 0 >::IncidentElementCoIndex[c.index][ic.index] ] = myCount; - } - } - } - }; - // Process the in-plane edges - auto ProcessIEdges = []( SliceTableData& sData , const ConstNeighbors& neighbors , HyperCube::Direction zDir , int zOff ) - { - const TreeOctNode* node = neighbors.neighbors[1][1][1+zOff]; - node_index_type i = node->nodeData.nodeIndex; - // Iterate over the edges in the face - for( typename HyperCube::Cube< Dim-1 >::template Element< 1 > _e ; _e::template ElementNum< 1 >() ; _e++ ) - { - bool owner = true; - - // The edge in the cube - typename HyperCube::Cube< Dim >::template Element< 1 > e( zDir , _e.index ); - // The index of the cube relative to the edge - typename HyperCube::Cube< Dim >::template IncidentCubeIndex< 1 > my_ic = HyperCubeTables< Dim , 1 >::IncidentCube[e.index]; - // Iterate over the cubes incident on the edge - for( typename HyperCube::Cube< Dim >::template IncidentCubeIndex< 1 > ic ; ic::template IncidentCubeNum< 1 >() ; ic++ ) - { - // Get the indices of the cube relative to the center - unsigned int xx = HyperCubeTables< Dim , 1 >::CellOffset[e.index][ic.index] + zOff; - // If the neighbor exists and comes before, they own the corner - if( neighbors.neighbors.data[xx] && ic::template ElementNum< 1 >() + _e.index; - sData._eMap[ myCount ] = 1; - // Set all edge indices - for( typename HyperCube::Cube< Dim >::template IncidentCubeIndex< 1 > ic ; ic::template IncidentCubeNum< 1 >() ; ic++ ) - { - unsigned int xx = HyperCubeTables< Dim , 1 >::CellOffset[e.index][ic.index] + zOff; - // If the neighbor exists, set the index - if( neighbors.neighbors.data[xx] ) sData.edgeIndices( neighbors.neighbors.data[xx] )[ HyperCubeTables< Dim , 1 >::IncidentElementCoIndex[e.index][ic.index] ] = myCount; - } - } - } - }; - // Process the cross-plane edges - auto ProcessXEdges = []( XSliceTableData& xData , const ConstNeighbors& neighbors ) - { - const TreeOctNode* node = neighbors.neighbors[1][1][1]; - node_index_type i = node->nodeData.nodeIndex; - for( typename HyperCube::Cube< Dim-1 >::template Element< 0 > _c ; _c::template ElementNum< 0 >() ; _c++ ) - { - bool owner = true; - - typename HyperCube::Cube< Dim >::template Element< 1 > e( HyperCube::CROSS , _c.index ); - typename HyperCube::Cube< Dim >::template IncidentCubeIndex< 1 > my_ic = HyperCubeTables< Dim , 1 >::IncidentCube[e.index]; - - for( typename HyperCube::Cube< Dim >::template IncidentCubeIndex< 1 > ic ; ic::template IncidentCubeNum< 1 >() ; ic++ ) - { - unsigned int xx = HyperCubeTables< Dim , 1 >::CellOffset[e.index][ic.index]; - if( neighbors.neighbors.data[xx] && ic::template ElementNum< 0 >() + _c.index; - xData._eMap[ myCount ] = 1; - - // Set all edge indices - for( typename HyperCube::Cube< Dim >::template IncidentCubeIndex< 1 > ic ; ic::template IncidentCubeNum< 1 >() ; ic++ ) - { - unsigned int xx = HyperCubeTables< Dim , 1 >::CellOffset[e.index][ic.index]; - if( neighbors.neighbors.data[xx] ) xData.edgeIndices( neighbors.neighbors.data[xx] )[ HyperCubeTables< Dim , 1 >::IncidentElementCoIndex[e.index][ic.index] ] = myCount; - } - } - } - }; - // Process the in-plane faces - auto ProcessIFaces = []( SliceTableData& sData , const ConstNeighbors& neighbors , HyperCube::Direction zDir , int zOff ) - { - const TreeOctNode* node = neighbors.neighbors[1][1][1+zOff]; - node_index_type i = node->nodeData.nodeIndex; - for( typename HyperCube::Cube< Dim-1 >::template Element< 2 > _f ; _f::template ElementNum< 2 >() ; _f++ ) - { - bool owner = true; - - typename HyperCube::Cube< Dim >::template Element< 2 > f( zDir , _f.index ); - typename HyperCube::Cube< Dim >::template IncidentCubeIndex< 2 > my_ic = HyperCubeTables< Dim , 2 >::IncidentCube[f.index]; - - for( typename HyperCube::Cube< Dim >::template IncidentCubeIndex< 2 > ic ; ic::template IncidentCubeNum< 2 >() ; ic++ ) - { - unsigned int xx = HyperCubeTables< Dim , 2 >::CellOffset[f.index][ic.index] + zOff; - if( neighbors.neighbors.data[xx] && ic::template ElementNum< 2 >() + _f.index; - sData._fMap[ myCount ] = 1; - - // Set all the face indices - for( typename HyperCube::Cube< Dim >::template IncidentCubeIndex< 2 > ic ; ic::template IncidentCubeNum< 2 >() ; ic++ ) - { - unsigned int xx = HyperCubeTables< Dim , 2 >::CellOffset[f.index][ic.index] + zOff; - if( neighbors.neighbors.data[xx] ) sData.faceIndices( neighbors.neighbors.data[xx] )[ HyperCubeTables< Dim , 2 >::IncidentElementCoIndex[f.index][ic.index] ] = myCount; - } - } - } - }; - - // Process the cross-plane faces - auto ProcessXFaces = []( XSliceTableData& xData , const ConstNeighbors& neighbors ) - { - const TreeOctNode* node = neighbors.neighbors[1][1][1]; - node_index_type i = node->nodeData.nodeIndex; - for( typename HyperCube::Cube< Dim-1 >::template Element< 1 > _e ; _e::template ElementNum< 1 >() ; _e++ ) - { - bool owner = true; - - typename HyperCube::Cube< Dim >::template Element< 2 > f( HyperCube::CROSS , _e.index ); - typename HyperCube::Cube< Dim >::template IncidentCubeIndex< 2 > my_ic = HyperCubeTables< Dim , 2 >::IncidentCube[f.index]; - - for( typename HyperCube::Cube< Dim >::template IncidentCubeIndex< 2 > ic ; ic::template IncidentCubeNum< 2 >() ; ic++ ) - { - unsigned int xx = HyperCubeTables< Dim , 2 >::CellOffset[f.index][ic.index]; - if( neighbors.neighbors.data[xx] && ic::template ElementNum< 1 >() + _e.index; - xData._fMap[ myCount ] = 1; - - // Set all the face indices - for( typename HyperCube::Cube< Dim >::template IncidentCubeIndex< 2 > ic ; ic::template IncidentCubeNum< 2 >() ; ic++ ) - { - unsigned int xx = HyperCubeTables< Dim , 2 >::CellOffset[f.index][ic.index]; - if( neighbors.neighbors.data[xx] ) xData.faceIndices( neighbors.neighbors.data[xx] )[ HyperCubeTables< Dim , 2 >::IncidentElementCoIndex[f.index][ic.index] ] = myCount; - } - } - } - }; - - // Try and get at the nodes outside of the slab through the neighbor key - ThreadPool::Parallel_for( sNodes.begin(depth,offset) , sNodes.end(depth,offset) , [&]( unsigned int thread , size_t i ) - { - ConstOneRingNeighborKey& neighborKey = neighborKeys[ thread ]; - const TreeOctNode* node = sNodes.treeNodes[i]; - ConstNeighbors& neighbors = neighborKey.getNeighbors( node ); - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) if( !IsActiveNode< Dim >( neighbors.neighbors[i][j][k] ) ) neighbors.neighbors[i][j][k] = NULL; - - if( sData0 ) - { - ProcessCorners( *sData0 , neighbors , HyperCube::BACK , 0 ) , ProcessIEdges( *sData0 , neighbors , HyperCube::BACK , 0 ) , ProcessIFaces( *sData0 , neighbors , HyperCube::BACK , 0 ); - const TreeOctNode* _node = neighbors.neighbors[1][1][0]; - if( _node ) - { - ProcessCorners( *sData0 , neighbors , HyperCube::FRONT , -1 ) , ProcessIEdges( *sData0 , neighbors , HyperCube::FRONT , -1 ) , ProcessIFaces( *sData0 , neighbors , HyperCube::FRONT , -1 ); - sData0->_processed[ _node->nodeData.nodeIndex - sNodes.begin(depth,offset-1) ] = 1; - } - } - if( sData1 ) - { - ProcessCorners( *sData1 , neighbors , HyperCube::FRONT , 0 ) , ProcessIEdges( *sData1 , neighbors , HyperCube::FRONT , 0 ) , ProcessIFaces( *sData1 , neighbors , HyperCube::FRONT , 0 ); - const TreeOctNode* _node = neighbors.neighbors[1][1][2]; - if( _node ) - { - ProcessCorners( *sData1 , neighbors , HyperCube::BACK , 1 ) , ProcessIEdges( *sData1 , neighbors , HyperCube::BACK , 1 ) , ProcessIFaces( *sData1, neighbors , HyperCube::BACK , 1 ); - sData1->_processed[ _node->nodeData.nodeIndex - sNodes.begin(depth,offset+1) ] = true; - } - } - if( xData ) ProcessXEdges( *xData , neighbors ) , ProcessXFaces( *xData , neighbors ); - } - ); - if( sData0 ) - { - node_index_type off = sNodes.begin(depth,offset-1); - node_index_type size = sNodes.end(depth,offset-1) - sNodes.begin(depth,offset-1); - ThreadPool::Parallel_for( 0 , size , [&]( unsigned int thread , size_t i ) - { - if( !sData0->_processed[i] ) - { - ConstOneRingNeighborKey& neighborKey = neighborKeys[ thread ]; - const TreeOctNode* node = sNodes.treeNodes[i+off]; - ConstNeighbors& neighbors = neighborKey.getNeighbors( node ); - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) if( !IsActiveNode< Dim >( neighbors.neighbors[i][j][k] ) ) neighbors.neighbors[i][j][k] = NULL; - ProcessCorners( *sData0 , neighbors , HyperCube::FRONT , 0 ) , ProcessIEdges( *sData0 , neighbors , HyperCube::FRONT , 0 ) , ProcessIFaces( *sData0 , neighbors , HyperCube::FRONT , 0 ); - } - } - ); - } - if( sData1 ) - { - node_index_type off = sNodes.begin(depth,offset+1); - node_index_type size = sNodes.end(depth,offset+1) - sNodes.begin(depth,offset+1); - ThreadPool::Parallel_for( 0 , size , [&]( unsigned int thread , size_t i ) - { - if( !sData1->_processed[i] ) - { - ConstOneRingNeighborKey& neighborKey = neighborKeys[ thread ]; - const TreeOctNode* node = sNodes.treeNodes[i+off]; - ConstNeighbors& neighbors = neighborKey.getNeighbors( node ); - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) if( !IsActiveNode< Dim >( neighbors.neighbors[i][j][k] ) ) neighbors.neighbors[i][j][k] = NULL; - ProcessCorners( *sData1 , neighbors , HyperCube::BACK , 0 ) , ProcessIEdges( *sData1 , neighbors , HyperCube::BACK , 0 ) , ProcessIFaces( *sData1 , neighbors , HyperCube::BACK , 0 ); - } - } - ); - } - - auto SetICounts = [&]( SliceTableData& sData ) - { - node_index_type cCount = 0 , eCount = 0 , fCount = 0; - - for( node_index_type i=0 ; i::template ElementNum< 0 >() ; i++ ) if( sData._cMap[i] ) sData._cMap[i] = cCount++; - for( node_index_type i=0 ; i::template ElementNum< 1 >() ; i++ ) if( sData._eMap[i] ) sData._eMap[i] = eCount++; - for( node_index_type i=0 ; i::template ElementNum< 2 >() ; i++ ) if( sData._fMap[i] ) sData._fMap[i] = fCount++; - ThreadPool::Parallel_for( 0 , sData.nodeCount , [&]( unsigned int , size_t i ) - { - for( unsigned int j=0 ; j::template ElementNum< 0 >() ; j++ ) sData.cTable[i][j] = sData._cMap[ sData.cTable[i][j] ]; - for( unsigned int j=0 ; j::template ElementNum< 1 >() ; j++ ) sData.eTable[i][j] = sData._eMap[ sData.eTable[i][j] ]; - for( unsigned int j=0 ; j::template ElementNum< 2 >() ; j++ ) sData.fTable[i][j] = sData._fMap[ sData.fTable[i][j] ]; - } - ); - sData.cCount = cCount , sData.eCount = eCount , sData.fCount = fCount; - }; - auto SetXCounts = [&]( XSliceTableData& xData ) - { - node_index_type eCount = 0 , fCount = 0; - - for( node_index_type i=0 ; i::template ElementNum< 0 >() ; i++ ) if( xData._eMap[i] ) xData._eMap[i] = eCount++; - for( node_index_type i=0 ; i::template ElementNum< 1 >() ; i++ ) if( xData._fMap[i] ) xData._fMap[i] = fCount++; - ThreadPool::Parallel_for( 0 , xData.nodeCount , [&]( unsigned int , size_t i ) - { - for( unsigned int j=0 ; j::template ElementNum< 0 >() ; j++ ) xData.eTable[i][j] = xData._eMap[ xData.eTable[i][j] ]; - for( unsigned int j=0 ; j::template ElementNum< 1 >() ; j++ ) xData.fTable[i][j] = xData._fMap[ xData.fTable[i][j] ]; - } - ); - xData.eCount = eCount , xData.fCount = fCount; - }; - - if( sData0 ) SetICounts( *sData0 ); - if( sData1 ) SetICounts( *sData1 ); - if( xData ) SetXCounts( *xData ); - } - }; - - ////////////////// - // _SliceValues // - ////////////////// - struct _SliceValues - { - typename SliceData::SliceTableData sliceData; - Pointer( Real ) cornerValues ; Pointer( Point< Real , Dim > ) cornerGradients ; Pointer( char ) cornerSet; - Pointer( _Key ) edgeKeys ; Pointer( char ) edgeSet; - Pointer( _FaceEdges ) faceEdges ; Pointer( char ) faceSet; - Pointer( char ) mcIndices; - std::unordered_map< _Key , std::vector< _IsoEdge > , typename _Key::Hasher > faceEdgeMap; - std::unordered_map< _Key , std::pair< node_index_type, Vertex > , typename _Key::Hasher > edgeVertexMap; - std::unordered_map< _Key , _Key , typename _Key::Hasher > vertexPairMap; - std::vector< std::vector< std::pair< _Key , std::vector< _IsoEdge > > > > faceEdgeKeyValues; - std::vector< std::vector< std::pair< _Key , std::pair< node_index_type , Vertex > > > > edgeVertexKeyValues; - std::vector< std::vector< std::pair< _Key , _Key > > > vertexPairKeyValues; - - _SliceValues( void ) - { - _oldCCount = _oldECount = _oldFCount = 0; - _oldNCount = 0; - cornerValues = NullPointer( Real ) ; cornerGradients = NullPointer( Point< Real , Dim > ) ; cornerSet = NullPointer( char ); - edgeKeys = NullPointer( _Key ) ; edgeSet = NullPointer( char ); - faceEdges = NullPointer( _FaceEdges ) ; faceSet = NullPointer( char ); - mcIndices = NullPointer( char ); - edgeVertexKeyValues.resize( ThreadPool::NumThreads() ); - vertexPairKeyValues.resize( ThreadPool::NumThreads() ); - faceEdgeKeyValues.resize( ThreadPool::NumThreads() ); - } - ~_SliceValues( void ) - { - _oldCCount = _oldECount = _oldFCount = 0; - _oldNCount = 0; - FreePointer( cornerValues ) ; FreePointer( cornerGradients ) ; FreePointer( cornerSet ); - FreePointer( edgeKeys ) ; FreePointer( edgeSet ); - FreePointer( faceEdges ) ; FreePointer( faceSet ); - FreePointer( mcIndices ); - } - void setEdgeVertexMap( void ) - { - for( node_index_type i=0 ; i<(node_index_type)edgeVertexKeyValues.size() ; i++ ) - { - for( int j=0 ; jsecond.push_back( faceEdgeKeyValues[i][j].second[k] ); - } - faceEdgeKeyValues[i].clear(); - } - } - void reset( bool computeGradients ) - { - faceEdgeMap.clear() , edgeVertexMap.clear() , vertexPairMap.clear(); - for( node_index_type i=0 ; i<(node_index_type)edgeVertexKeyValues.size() ; i++ ) edgeVertexKeyValues[i].clear(); - for( node_index_type i=0 ; i<(node_index_type)vertexPairKeyValues.size() ; i++ ) vertexPairKeyValues[i].clear(); - for( node_index_type i=0 ; i<(node_index_type)faceEdgeKeyValues.size() ; i++ ) faceEdgeKeyValues[i].clear(); - - if( _oldNCount0 ) mcIndices = AllocPointer< char >( _oldNCount ); - } - if( _oldCCount0 ) - { - cornerValues = AllocPointer< Real >( _oldCCount ); - if( computeGradients ) cornerGradients = AllocPointer< Point< Real , Dim > >( _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 ); - } - protected: - node_index_type _oldCCount , _oldECount , _oldFCount; - node_index_type _oldNCount; - }; - - /////////////////// - // _XSliceValues // - /////////////////// - struct _XSliceValues - { - typename SliceData::XSliceTableData xSliceData; - Pointer( _Key ) edgeKeys ; Pointer( char ) edgeSet; - Pointer( _FaceEdges ) faceEdges ; Pointer( char ) faceSet; - std::unordered_map< _Key , std::vector< _IsoEdge > , typename _Key::Hasher > faceEdgeMap; - std::unordered_map< _Key , std::pair< node_index_type , Vertex > , typename _Key::Hasher > edgeVertexMap; - std::unordered_map< _Key , _Key , typename _Key::Hasher > vertexPairMap; - std::vector< std::vector< std::pair< _Key , std::pair< node_index_type , Vertex > > > > edgeVertexKeyValues; - std::vector< std::vector< std::pair< _Key , _Key > > > vertexPairKeyValues; - std::vector< std::vector< std::pair< _Key , std::vector< _IsoEdge > > > > faceEdgeKeyValues; - - _XSliceValues( void ) - { - _oldECount = _oldFCount = 0; - edgeKeys = NullPointer( _Key ) ; edgeSet = NullPointer( char ); - faceEdges = NullPointer( _FaceEdges ) ; faceSet = NullPointer( char ); - edgeVertexKeyValues.resize( ThreadPool::NumThreads() ); - vertexPairKeyValues.resize( ThreadPool::NumThreads() ); - faceEdgeKeyValues.resize( ThreadPool::NumThreads() ); - } - ~_XSliceValues( void ) - { - _oldECount = _oldFCount = 0; - FreePointer( edgeKeys ) ; FreePointer( edgeSet ); - FreePointer( faceEdges ) ; FreePointer( faceSet ); - } - void setEdgeVertexMap( void ) - { - for( node_index_type i=0 ; i<(node_index_type)edgeVertexKeyValues.size() ; i++ ) - { - for( int j=0 ; jsecond.push_back( faceEdgeKeyValues[i][j].second[k] ); - } - faceEdgeKeyValues[i].clear(); - } - } - void reset( void ) - { - faceEdgeMap.clear() , edgeVertexMap.clear() , vertexPairMap.clear(); - for( node_index_type i=0 ; i<(node_index_type)edgeVertexKeyValues.size() ; i++ ) edgeVertexKeyValues[i].clear(); - for( node_index_type i=0 ; i<(node_index_type)vertexPairKeyValues.size() ; i++ ) vertexPairKeyValues[i].clear(); - for( node_index_type i=0 ; i<(node_index_type)faceEdgeKeyValues.size() ; i++ ) faceEdgeKeyValues[i].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 ); - } - - protected: - node_index_type _oldECount , _oldFCount; - }; - - ///////////////// - // _SlabValues // - ///////////////// - struct _SlabValues - { - protected: - _XSliceValues _xSliceValues[2]; - _SliceValues _sliceValues[2]; - public: - _SliceValues& sliceValues( int idx ){ return _sliceValues[idx&1]; } - const _SliceValues& sliceValues( int idx ) const { return _sliceValues[idx&1]; } - _XSliceValues& xSliceValues( int idx ){ return _xSliceValues[idx&1]; } - const _XSliceValues& xSliceValues( int idx ) const { return _xSliceValues[idx&1]; } - }; - - template< unsigned int ... FEMSigs > - static void _SetSliceIsoCorners( const FEMTree< Dim , Real >& tree , ConstPointer( Real ) coefficients , ConstPointer( Real ) coarseCoefficients , Real isoValue , LocalDepth depth , int slice , std::vector< _SlabValues >& slabValues , const _Evaluator< UIntPack< FEMSigs ... > , 1 >& evaluator ) - { - if( slice>0 ) _SetSliceIsoCorners< FEMSigs ... >( tree , coefficients , coarseCoefficients , isoValue , depth , slice , HyperCube::FRONT , slabValues , evaluator ); - if( slice<(1<( tree , coefficients , coarseCoefficients , isoValue , depth , slice , HyperCube::BACK , slabValues , evaluator ); - } - template< unsigned int ... FEMSigs > - static void _SetSliceIsoCorners( const FEMTree< Dim , Real >& tree , ConstPointer( Real ) coefficients , ConstPointer( Real ) coarseCoefficients , Real isoValue , LocalDepth depth , int slice , HyperCube::Direction zDir , std::vector< _SlabValues >& slabValues , const _Evaluator< UIntPack< FEMSigs ... > , 1 >& evaluator ) - { - static const unsigned int FEMDegrees[] = { FEMSignature< FEMSigs >::Degree ... }; - _SliceValues& sValues = slabValues[depth].sliceValues( slice ); - bool useBoundaryEvaluation = false; - for( int d=0 ; d::Degree ... > > > neighborKeys( ThreadPool::NumThreads() ); - std::vector< ConstCornerSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > > > bNeighborKeys( ThreadPool::NumThreads() ); - if( useBoundaryEvaluation ) for( size_t i=0 ; i::template ElementNum< 0 >() ]; - ConstPointSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& neighborKey = neighborKeys[ thread ]; - ConstCornerSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bNeighborKey = bNeighborKeys[ thread ]; - TreeNode* leaf = tree._sNodes.treeNodes[i]; - if( !IsActiveNode< Dim >( leaf->children ) ) - { - const typename SliceData::SquareCornerIndices& cIndices = sValues.sliceData.cornerIndices( leaf ); - - bool isInterior = tree._isInteriorlySupported( UIntPack< FEMSignature< FEMSigs >::Degree ... >() , leaf->parent ); - if( useBoundaryEvaluation ) bNeighborKey.getNeighbors( leaf ); - else neighborKey.getNeighbors( leaf ); - - for( typename HyperCube::Cube< Dim-1 >::template Element< 0 > _c ; _c::template ElementNum< 0 >() ; _c++ ) - { - typename HyperCube::Cube< Dim >::template Element< 0 > c( zDir , _c.index ); - node_index_type vIndex = cIndices[_c.index]; - if( !sValues.cornerSet[vIndex] ) - { - if( sValues.cornerGradients ) - { - CumulativeDerivativeValues< Real , Dim , 1 > p; - if( useBoundaryEvaluation ) p = tree.template _getCornerValues< Real , 1 >( bNeighborKey , leaf , c.index , coefficients , coarseCoefficients , evaluator , tree._maxDepth , isInterior ); - else p = tree.template _getCornerValues< Real , 1 >( neighborKey , leaf , c.index , coefficients , coarseCoefficients , evaluator , tree._maxDepth , isInterior ); - sValues.cornerValues[vIndex] = p[0] , sValues.cornerGradients[vIndex] = Point< Real , Dim >( p[1] , p[2] , p[3] ); - } - else - { - if( useBoundaryEvaluation ) sValues.cornerValues[vIndex] = tree.template _getCornerValues< Real , 0 >( bNeighborKey , leaf , c.index , coefficients , coarseCoefficients , evaluator , tree._maxDepth , isInterior )[0]; - else sValues.cornerValues[vIndex] = tree.template _getCornerValues< Real , 0 >( neighborKey , leaf , c.index , coefficients , coarseCoefficients , evaluator , tree._maxDepth , isInterior )[0]; - } - sValues.cornerSet[vIndex] = 1; - } - squareValues[_c.index] = sValues.cornerValues[ vIndex ]; - TreeNode* node = leaf; - LocalDepth _depth = depth; - int _slice = slice; - while( tree._isValidSpaceNode( node->parent ) && (node-node->parent->children)==c.index ) - { - node = node->parent , _depth-- , _slice >>= 1; - _SliceValues& _sValues = slabValues[_depth].sliceValues( _slice ); - const typename SliceData::SquareCornerIndices& _cIndices = _sValues.sliceData.cornerIndices( node ); - node_index_type _vIndex = _cIndices[_c.index]; - _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 ] = HyperCube::Cube< Dim-1 >::MCIndex( squareValues , isoValue ); - } - } - } - ); - } - ///////////////// - // _VertexData // - ///////////////// - class _VertexData - { - public: - static _Key EdgeIndex( const TreeNode* node , typename HyperCube::Cube< Dim >::template Element< 1 > e , int maxDepth ) - { - _Key key; - const HyperCube::Direction* x = SliceData::template HyperCubeTables< Dim , 1 >::Directions[ e.index ]; - int d , off[Dim]; - node->depthAndOffset( d , off ); - for( int dd=0 ; dd::template Element< Dim-1 > f , int maxDepth ) - { - _Key key; - const HyperCube::Direction* x = SliceData::template HyperCubeTables< Dim , 2 >::Directions[ f.index ]; - int d , o[Dim]; - node->depthAndOffset( d , o ); - for( int dd=0 ; dd - static void _SetSliceIsoVertices( const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , int slice , node_index_type& vOffset , CoredMeshData< Vertex , node_index_type >& mesh , std::vector< _SlabValues >& slabValues , const Data &zeroData , std::function< void ( Vertex& , Point< Real , Dim > , Point< Real , Dim > , Real , Data ) > SetVertex ) - { - if( slice>0 ) _SetSliceIsoVertices< WeightDegree , Data , DataSig >( tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , depth , slice , HyperCube::FRONT , vOffset , mesh , slabValues , zeroData , SetVertex ); - if( slice<(1<( tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , depth , slice , HyperCube::BACK , vOffset , mesh , slabValues , zeroData , SetVertex ); - } - template< unsigned int WeightDegree , typename Data , unsigned int DataSig > - static void _SetSliceIsoVertices( const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , int slice , HyperCube::Direction zDir , node_index_type& vOffset , CoredMeshData< Vertex , node_index_type >& mesh , std::vector< _SlabValues >& slabValues , const Data &zeroData , std::function< void ( Vertex& , Point< Real , Dim > , Point< Real , Dim > , Real , Data ) > SetVertex ) - { - static const unsigned int DataDegree = FEMSignature< DataSig >::Degree; - _SliceValues& 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< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); - std::vector< ConstPointSupportKey< IsotropicUIntPack< Dim , WeightDegree > > > weightKeys( ThreadPool::NumThreads() ); - std::vector< ConstPointSupportKey< IsotropicUIntPack< Dim , DataDegree > > > dataKeys( ThreadPool::NumThreads() ); - for( size_t i=0 ; i >& weightKey = weightKeys[ thread ]; - ConstPointSupportKey< IsotropicUIntPack< Dim , DataDegree > >& dataKey = dataKeys[ thread ]; - TreeNode* leaf = tree._sNodes.treeNodes[i]; - if( !IsActiveNode< Dim >( leaf->children ) ) - { - node_index_type idx = (node_index_type)i - sValues.sliceData.nodeOffset; - const typename SliceData::SquareEdgeIndices& eIndices = sValues.sliceData.edgeIndices( leaf ); - if( HyperCube::Cube< Dim-1 >::HasMCRoots( sValues.mcIndices[idx] ) ) - { - neighborKey.getNeighbors( leaf ); - if( densityWeights ) weightKey.getNeighbors( leaf ); - if( data ) dataKey.getNeighbors( leaf ); - - for( typename HyperCube::Cube< Dim-1 >::template Element< 1 > _e ; _e::template ElementNum< 1 >() ; _e++ ) - if( HyperCube::Cube< 1 >::HasMCRoots( HyperCube::Cube< Dim-1 >::ElementMCIndex( _e , sValues.mcIndices[idx] ) ) ) - { - typename HyperCube::Cube< Dim >::template Element< 1 > e( zDir , _e.index ); - node_index_type vIndex = eIndices[_e.index]; - volatile char &edgeSet = sValues.edgeSet[vIndex]; - if( !edgeSet ) - { - Vertex vertex; - _Key key = _VertexData::EdgeIndex( leaf , e , tree._localToGlobal( tree._maxDepth ) ); - _GetIsoVertex< WeightDegree , Data , DataSig >( tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , _e , zDir , sValues , vertex , zeroData , SetVertex ); - bool stillOwner = false; - std::pair< node_index_type , Vertex > hashed_vertex; - { - std::lock_guard< std::mutex > lock( _pointInsertionMutex ); - if( !edgeSet ) - { - mesh.addOutOfCoreVertex( vertex ); - edgeSet = 1; - hashed_vertex = std::pair< node_index_type , Vertex >( vOffset , vertex ); - sValues.edgeKeys[ vIndex ] = key; - vOffset++; - stillOwner = true; - } - } - if( stillOwner ) sValues.edgeVertexKeyValues[ thread ].push_back( std::pair< _Key , std::pair< node_index_type , Vertex > >( key , hashed_vertex ) ); - if( stillOwner ) - { - // We only need to pass the iso-vertex down if the edge it lies on is adjacent to a coarser leaf - auto IsNeeded = [&]( unsigned int depth ) - { - bool isNeeded = false; - typename HyperCube::Cube< Dim >::template IncidentCubeIndex< 1 > my_ic = SliceData::template HyperCubeTables< Dim , 1 >::IncidentCube[e.index]; - for( typename HyperCube::Cube< Dim >::template IncidentCubeIndex< 1 > ic ; ic::template IncidentCubeNum< 1 >() ; ic++ ) if( ic!=my_ic ) - { - unsigned int xx = SliceData::template HyperCubeTables< Dim , 1 >::CellOffset[e.index][ic.index]; - isNeeded |= !tree._isValidSpaceNode( neighborKey.neighbors[ tree._localToGlobal( depth ) ].neighbors.data[xx] ); - } - return isNeeded; - }; - if( IsNeeded( depth ) ) - { - const typename HyperCube::Cube< Dim >::template Element< Dim-1 > *f = SliceData::template HyperCubeTables< Dim , 1 , Dim-1 >::OverlapElements[e.index]; - for( int k=0 ; k<2 ; k++ ) - { - TreeNode* node = leaf; - LocalDepth _depth = depth; - int _slice = slice; - while( tree._isValidSpaceNode( node->parent ) && SliceData::template HyperCubeTables< Dim , 2 , 0 >::Overlap[f[k].index][(unsigned int)(node-node->parent->children) ] ) - { - node = node->parent , _depth-- , _slice >>= 1; - _SliceValues& _sValues = slabValues[_depth].sliceValues( _slice ); - _sValues.edgeVertexKeyValues[ thread ].push_back( std::pair< _Key , std::pair< node_index_type , Vertex > >( key , hashed_vertex ) ); - if( !IsNeeded( _depth ) ) break; - } - } - } - } - } - } - } - } - } - } - ); - } - - //////////////////// - // Iso-Extraction // - //////////////////// - template< unsigned int WeightDegree , typename Data , unsigned int DataSig > - static void _SetXSliceIsoVertices( const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , int slab , node_index_type &vOffset , CoredMeshData< Vertex , node_index_type >& mesh , std::vector< _SlabValues >& slabValues , const Data &zeroData , std::function< void ( Vertex& , Point< Real , Dim > , Point< Real , Dim > , Real , Data ) > SetVertex ) - { - static const unsigned int DataDegree = FEMSignature< DataSig >::Degree; - _SliceValues& bValues = slabValues[depth].sliceValues ( slab ); - _SliceValues& fValues = slabValues[depth].sliceValues ( slab+1 ); - _XSliceValues& 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< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); - std::vector< ConstPointSupportKey< IsotropicUIntPack< Dim , WeightDegree > > > weightKeys( ThreadPool::NumThreads() ); - std::vector< ConstPointSupportKey< IsotropicUIntPack< Dim , DataDegree > > > dataKeys( ThreadPool::NumThreads() ); - for( size_t i=0 ; i >& weightKey = weightKeys[ thread ]; - ConstPointSupportKey< IsotropicUIntPack< Dim , DataDegree > >& dataKey = dataKeys[ thread ]; - TreeNode* leaf = tree._sNodes.treeNodes[i]; - if( !IsActiveNode< Dim >( leaf->children ) ) - { - unsigned char mcIndex = ( bValues.mcIndices[ i - bValues.sliceData.nodeOffset ] ) | ( fValues.mcIndices[ i - fValues.sliceData.nodeOffset ] )<<4; - const typename SliceData::SquareCornerIndices& eIndices = xValues.xSliceData.edgeIndices( leaf ); - if( HyperCube::Cube< Dim >::HasMCRoots( mcIndex ) ) - { - neighborKey.getNeighbors( leaf ); - if( densityWeights ) weightKey.getNeighbors( leaf ); - if( data ) dataKey.getNeighbors( leaf ); - for( typename HyperCube::Cube< Dim-1 >::template Element< 0 > _c ; _c::template ElementNum< 0 >() ; _c++ ) - { - typename HyperCube::Cube< Dim >::template Element< 1 > e( HyperCube::CROSS , _c.index ); - unsigned int _mcIndex = HyperCube::Cube< Dim >::ElementMCIndex( e , mcIndex ); - if( HyperCube::Cube< 1 >::HasMCRoots( _mcIndex ) ) - { - node_index_type vIndex = eIndices[_c.index]; - volatile char &edgeSet = xValues.edgeSet[vIndex]; - if( !edgeSet ) - { - Vertex vertex; - _Key key = _VertexData::EdgeIndex( leaf , e.index , tree._localToGlobal( tree._maxDepth ) ); - _GetIsoVertex< WeightDegree , Data , DataSig >( tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , _c , bValues , fValues , vertex , zeroData , SetVertex ); - bool stillOwner = false; - std::pair< node_index_type , Vertex > hashed_vertex; - { - std::lock_guard< std::mutex > lock( _pointInsertionMutex ); - if( !edgeSet ) - { - mesh.addOutOfCoreVertex( vertex ); - edgeSet = 1; - hashed_vertex = std::pair< node_index_type , Vertex >( vOffset , vertex ); - xValues.edgeKeys[ vIndex ] = key; - vOffset++; - stillOwner = true; - } - } - if( stillOwner ) xValues.edgeVertexKeyValues[ thread ].push_back( std::pair< _Key , std::pair< node_index_type , Vertex > >( key , hashed_vertex ) ); - if( stillOwner ) - { - // We only need to pass the iso-vertex down if the edge it lies on is adjacent to a coarser leaf - auto IsNeeded = [&]( unsigned int depth ) - { - bool isNeeded = false; - typename HyperCube::Cube< Dim >::template IncidentCubeIndex< 1 > my_ic = SliceData::template HyperCubeTables< Dim , 1 >::IncidentCube[e.index]; - for( typename HyperCube::Cube< Dim >::template IncidentCubeIndex< 1 > ic ; ic::template IncidentCubeNum< 1 >() ; ic++ ) if( ic!=my_ic ) - { - unsigned int xx = SliceData::template HyperCubeTables< Dim , 1 >::CellOffset[e.index][ic.index]; - isNeeded |= !tree._isValidSpaceNode( neighborKey.neighbors[ tree._localToGlobal( depth ) ].neighbors.data[xx] ); - } - return isNeeded; - }; - if( IsNeeded( depth ) ) - { - const typename HyperCube::Cube< Dim >::template Element< Dim-1 > *f = SliceData::template HyperCubeTables< Dim , 1 , Dim-1 >::OverlapElements[e.index]; - for( int k=0 ; k<2 ; k++ ) - { - TreeNode* node = leaf; - LocalDepth _depth = depth; - int _slab = slab; - while( tree._isValidSpaceNode( node->parent ) && SliceData::template HyperCubeTables< Dim , 2 , 0 >::Overlap[f[k].index][(unsigned int)(node-node->parent->children) ] ) - { - node = node->parent , _depth-- , _slab >>= 1; - _XSliceValues& _xValues = slabValues[_depth].xSliceValues( _slab ); - _xValues.edgeVertexKeyValues[ thread ].push_back( std::pair< _Key , std::pair< node_index_type , Vertex > >( key , hashed_vertex ) ); - if( !IsNeeded( _depth ) ) break; - } - } - } - } - } - } - } - } - } - } - } - ); - } - static void _CopyFinerSliceIsoEdgeKeys( const FEMTree< Dim , Real >& tree , LocalDepth depth , int slice , std::vector< _SlabValues >& slabValues ) - { - if( slice>0 ) _CopyFinerSliceIsoEdgeKeys( tree , depth , slice , HyperCube::FRONT , slabValues ); - if( slice<(1<& tree , LocalDepth depth , int slice , HyperCube::Direction zDir , std::vector< _SlabValues >& slabValues ) - { - _SliceValues& pSliceValues = slabValues[depth ].sliceValues(slice ); - _SliceValues& cSliceValues = slabValues[depth+1].sliceValues(slice<<1); - typename SliceData::SliceTableData& pSliceData = pSliceValues.sliceData; - typename SliceData::SliceTableData& cSliceData = cSliceValues.sliceData; - ThreadPool::Parallel_for( tree._sNodesBegin(depth,slice-(zDir==HyperCube::BACK ? 0 : 1)) , tree._sNodesEnd(depth,slice-(zDir==HyperCube::BACK ? 0 : 1)) , [&]( unsigned int thread , size_t i ) - { - if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i] ) ) if( IsActiveNode< Dim >( tree._sNodes.treeNodes[i]->children ) ) - { - typename SliceData::SquareEdgeIndices& pIndices = pSliceData.edgeIndices( (node_index_type)i ); - // Copy the edges that overlap the coarser edges - for( typename HyperCube::Cube< Dim-1 >::template Element< 1 > _e ; _e::template ElementNum< 1 >() ; _e++ ) - { - node_index_type pIndex = pIndices[_e.index]; - if( !pSliceValues.edgeSet[ pIndex ] ) - { - typename HyperCube::Cube< Dim >::template Element< 1 > e( zDir , _e.index ); - const typename HyperCube::Cube< Dim >::template Element< 0 > *c = SliceData::template HyperCubeTables< Dim , 1 , 0 >::OverlapElements[e.index]; - // [SANITY CHECK] - // if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[0].index )!=tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[1].index ) ) ERROR_OUT( "Finer edges should both be valid or invalid" ); - if( !tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[0].index ) || !tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[1].index ) ) continue; - - node_index_type cIndex1 = cSliceData.edgeIndices( tree._sNodes.treeNodes[i]->children + c[0].index )[_e.index]; - node_index_type cIndex2 = cSliceData.edgeIndices( tree._sNodes.treeNodes[i]->children + c[1].index )[_e.index]; - if( cSliceValues.edgeSet[cIndex1] != cSliceValues.edgeSet[cIndex2] ) - { - _Key key; - if( cSliceValues.edgeSet[cIndex1] ) key = cSliceValues.edgeKeys[cIndex1]; - else key = cSliceValues.edgeKeys[cIndex2]; - pSliceValues.edgeKeys[pIndex] = key; - pSliceValues.edgeSet[pIndex] = 1; - } - else if( cSliceValues.edgeSet[cIndex1] && cSliceValues.edgeSet[cIndex2] ) - { - _Key key1 = cSliceValues.edgeKeys[cIndex1] , key2 = cSliceValues.edgeKeys[cIndex2]; - pSliceValues.vertexPairKeyValues[ thread ].push_back( std::pair< _Key , _Key >( key1 , key2 ) ); - - const TreeNode* node = tree._sNodes.treeNodes[i]; - LocalDepth _depth = depth; - int _slice = slice; - while( tree._isValidSpaceNode( node->parent ) && SliceData::template HyperCubeTables< Dim , 1 , 0 >::Overlap[e.index][(unsigned int)(node-node->parent->children) ] ) - { - node = node->parent , _depth-- , _slice >>= 1; - _SliceValues& _pSliceValues = slabValues[_depth].sliceValues(_slice); - _pSliceValues.vertexPairKeyValues[ thread ].push_back( std::pair< _Key , _Key >( key1 , key2 ) ); - } - } - } - } - } - } - ); - } - static void _CopyFinerXSliceIsoEdgeKeys( const FEMTree< Dim , Real >& tree , LocalDepth depth , int slab , std::vector< _SlabValues>& slabValues ) - { - _XSliceValues& pSliceValues = slabValues[depth ].xSliceValues(slab); - _XSliceValues& cSliceValues0 = slabValues[depth+1].xSliceValues( (slab<<1)|0 ); - _XSliceValues& cSliceValues1 = slabValues[depth+1].xSliceValues( (slab<<1)|1 ); - typename SliceData::XSliceTableData& pSliceData = pSliceValues.xSliceData; - typename SliceData::XSliceTableData& cSliceData0 = cSliceValues0.xSliceData; - typename SliceData::XSliceTableData& cSliceData1 = cSliceValues1.xSliceData; - ThreadPool::Parallel_for( tree._sNodesBegin(depth,slab) , tree._sNodesEnd(depth,slab) , [&]( unsigned int thread , size_t i ) - { - if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i] ) ) if( IsActiveNode< Dim >( tree._sNodes.treeNodes[i]->children ) ) - { - typename SliceData::SquareCornerIndices& pIndices = pSliceData.edgeIndices( (node_index_type)i ); - for( typename HyperCube::Cube< Dim-1 >::template Element< 0 > _c ; _c::template ElementNum< 0 >() ; _c++ ) - { - typename HyperCube::Cube< Dim >::template Element< 1 > e( HyperCube::CROSS , _c.index ); - node_index_type pIndex = pIndices[ _c.index ]; - if( !pSliceValues.edgeSet[pIndex] ) - { - typename HyperCube::Cube< Dim >::template Element< 0 > c0( HyperCube::BACK , _c.index ) , c1( HyperCube::FRONT , _c.index ); - - // [SANITY CHECK] - // if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c0 )!=tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c1 ) ) ERROR_OUT( "Finer edges should both be valid or invalid" ); - if( !tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c0.index ) || !tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c1.index ) ) continue; - - node_index_type cIndex0 = cSliceData0.edgeIndices( tree._sNodes.treeNodes[i]->children + c0.index )[_c.index]; - node_index_type cIndex1 = cSliceData1.edgeIndices( tree._sNodes.treeNodes[i]->children + c1.index )[_c.index]; - // If there's one zero-crossing along the edge - if( cSliceValues0.edgeSet[cIndex0] != cSliceValues1.edgeSet[cIndex1] ) - { - _Key key; - 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; - pSliceValues.edgeKeys[ pIndex ] = key; - pSliceValues.edgeSet[ pIndex ] = 1; - } - // If there's are two zero-crossings along the edge - else if( cSliceValues0.edgeSet[cIndex0] && cSliceValues1.edgeSet[cIndex1] ) - { - _Key key0 = cSliceValues0.edgeKeys[cIndex0] , key1 = cSliceValues1.edgeKeys[cIndex1]; - pSliceValues.vertexPairKeyValues[ thread ].push_back( std::pair< _Key , _Key >( key0 , key1 ) ); - const TreeNode* node = tree._sNodes.treeNodes[i]; - LocalDepth _depth = depth; - int _slab = slab; - while( tree._isValidSpaceNode( node->parent ) && SliceData::template HyperCubeTables< Dim , 1 , 0 >::Overlap[e.index][(unsigned int)(node-node->parent->children) ] ) - { - node = node->parent , _depth-- , _slab>>= 1; - _SliceValues& _pSliceValues = slabValues[_depth].sliceValues(_slab); - _pSliceValues.vertexPairKeyValues[ thread ].push_back( std::pair< _Key , _Key >( key0 , key1 ) ); - } - } - } - } - } - } - ); - } - static void _SetSliceIsoEdges( const FEMTree< Dim , Real >& tree , LocalDepth depth , int slice , std::vector< _SlabValues >& slabValues ) - { - if( slice>0 ) _SetSliceIsoEdges( tree , depth , slice , HyperCube::FRONT , slabValues ); - if( slice<(1<& tree , LocalDepth depth , int slice , HyperCube::Direction zDir , std::vector< _SlabValues >& slabValues ) - { - _SliceValues& sValues = slabValues[depth].sliceValues( slice ); - std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); - for( size_t i=0 ; i( leaf->children ) ) - { - node_index_type idx = (node_index_type)i - sValues.sliceData.nodeOffset; - const typename SliceData::SquareEdgeIndices& eIndices = sValues.sliceData.edgeIndices( leaf ); - const typename SliceData::SquareFaceIndices& fIndices = sValues.sliceData.faceIndices( leaf ); - unsigned char mcIndex = sValues.mcIndices[idx]; - if( !sValues.faceSet[ fIndices[0] ] ) - { - neighborKey.getNeighbors( leaf ); - unsigned int xx = WindowIndex< IsotropicUIntPack< Dim , 3 > , IsotropicUIntPack< Dim , 1 > >::Index + (zDir==HyperCube::BACK ? -1 : 1); - if( !IsActiveNode< Dim >( neighborKey.neighbors[ tree._localToGlobal( depth ) ].neighbors.data[xx] ) || !IsActiveNode< Dim >( neighborKey.neighbors[ tree._localToGlobal( depth ) ].neighbors.data[xx]->children ) ) - { - _FaceEdges fe; - fe.count = HyperCube::MarchingSquares::AddEdgeIndices( mcIndex , isoEdges ); - for( int j=0 ; j::template Element< Dim-1 > f( zDir , 0 ); - std::vector< _IsoEdge > edges; - edges.resize( fe.count ); - for( int j=0 ; jparent ) && SliceData::template HyperCubeTables< Dim , 2 , 0 >::Overlap[f.index][(unsigned int)(node-node->parent->children) ] ) - { - node = node->parent , _depth-- , _slice >>= 1; - if( IsActiveNode< Dim >( neighborKey.neighbors[ tree._localToGlobal( _depth ) ].neighbors.data[xx] ) && IsActiveNode< Dim >( neighborKey.neighbors[ tree._localToGlobal( _depth ) ].neighbors.data[xx]->children ) ) break; - _Key key = _VertexData::FaceIndex( node , f , tree._localToGlobal( tree._maxDepth ) ); - _SliceValues& _sValues = slabValues[_depth].sliceValues( _slice ); - _sValues.faceEdgeKeyValues[ thread ].push_back( std::pair< _Key , std::vector< _IsoEdge > >( key , edges ) ); - } - } - } - } - } - } - ); - } - static void _SetXSliceIsoEdges( const FEMTree< Dim , Real >& tree , LocalDepth depth , int slab , std::vector< _SlabValues >& slabValues ) - { - _SliceValues& bValues = slabValues[depth].sliceValues ( slab ); - _SliceValues& fValues = slabValues[depth].sliceValues ( slab+1 ); - _XSliceValues& xValues = slabValues[depth].xSliceValues( slab ); - - std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); - for( size_t i=0 ; i( leaf->children ) ) - { - const typename SliceData::SquareCornerIndices& cIndices = xValues.xSliceData.edgeIndices( leaf ); - const typename SliceData::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 ); - // Iterate over the edges on the back - for( typename HyperCube::Cube< Dim-1 >::template Element< 1 > _e ; _e::template ElementNum< 1 >() ; _e++ ) - { - typename HyperCube::Cube< Dim >::template Element< 2 > f( HyperCube::CROSS , _e.index ); - unsigned char _mcIndex = HyperCube::Cube< Dim >::template ElementMCIndex< 2 >( f , mcIndex ); - - unsigned int xx = SliceData::template HyperCubeTables< Dim , 2 >::CellOffsetAntipodal[f.index]; - if( !xValues.faceSet[ eIndices[_e.index] ] && ( !IsActiveNode< Dim >( neighborKey.neighbors[ tree._localToGlobal( depth ) ].neighbors.data[xx] ) || !IsActiveNode< Dim >( neighborKey.neighbors[ tree._localToGlobal( depth ) ].neighbors.data[xx]->children ) ) ) - { - _FaceEdges fe; - fe.count = HyperCube::MarchingSquares::AddEdgeIndices( _mcIndex , isoEdges ); - for( int j=0 ; j::template Element< 1 > e( f , typename HyperCube::Cube< Dim-1 >::template Element< 1 >( isoEdges[2*j+k] ) ); - HyperCube::Direction dir ; unsigned int coIndex; - e.factor( dir , coIndex ); - if( dir==HyperCube::CROSS ) // Cross-edge - { - node_index_type idx = cIndices[ coIndex ]; - if( !xValues.edgeSet[ idx ] ) ERROR_OUT( "Edge not set: " , slab , " / " , 1< edges; - edges.resize( fe.count ); - for( int j=0 ; jparent ) && SliceData::template HyperCubeTables< Dim , 2 , 0 >::Overlap[f.index][(unsigned int)(node-node->parent->children) ] ) - { - node = node->parent , _depth-- , _slab >>= 1; - if( IsActiveNode< Dim >( neighborKey.neighbors[ tree._localToGlobal( _depth ) ].neighbors.data[xx] ) && IsActiveNode< Dim >( neighborKey.neighbors[ tree._localToGlobal( _depth ) ].neighbors.data[xx]->children ) ) break; - _Key key = _VertexData::FaceIndex( node , f , tree._localToGlobal( tree._maxDepth ) ); - _XSliceValues& _xValues = slabValues[_depth].xSliceValues( _slab ); - _xValues.faceEdgeKeyValues[ thread ].push_back( std::pair< _Key , std::vector< _IsoEdge > >( key , edges ) ); - } - } - } - } - } - } - } - ); - } - - static void _SetIsoSurface( const FEMTree< Dim , Real >& tree , LocalDepth depth , int offset , const _SliceValues& bValues , const _SliceValues& fValues , const _XSliceValues& xValues , CoredMeshData< Vertex , node_index_type >& mesh , bool polygonMesh , bool addBarycenter , node_index_type& vOffset , bool flipOrientation ) - { - std::vector< std::pair< node_index_type , Vertex > > polygon; - std::vector< std::vector< _IsoEdge > > edgess( ThreadPool::NumThreads() ); - ThreadPool::Parallel_for( tree._sNodesBegin(depth,offset) , tree._sNodesEnd(depth,offset) , [&]( unsigned int thread , size_t i ) - { - if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i] ) ) - { - std::vector< _IsoEdge >& edges = edgess[ thread ]; - TreeNode* leaf = tree._sNodes.treeNodes[i]; - int res = 1<=0 && off[0]=0 && off[1]=0 && off[2]( leaf->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( typename HyperCube::Cube< Dim >::template Element< Dim-1 > f ; f::template ElementNum< Dim-1 >() ; f++ ) - { - int flip = HyperCube::Cube< Dim >::IsOriented( f ) ? 0 : 1; - HyperCube::Direction fDir = f.direction(); - if( fDir==HyperCube::BACK || fDir==HyperCube::FRONT ) - { - const _SliceValues& sValues = (fDir==HyperCube::BACK) ? bValues : fValues; - node_index_type fIdx = sValues.sliceData.faceIndices((node_index_type)i)[0]; - if( sValues.faceSet[fIdx] ) - { - const _FaceEdges& fe = sValues.faceEdges[ fIdx ]; - for( int j=0 ; j , typename _Key::Hasher >::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 ERROR_OUT( "Invalid faces: " , i , " " , fDir==HyperCube::BACK ? "back" : ( fDir==HyperCube::FRONT ? "front" : ( fDir==HyperCube::CROSS ? "cross" : "unknown" ) ) ); - } - } - else - { - node_index_type fIdx = xValues.xSliceData.faceIndices((node_index_type)i)[ f.coIndex() ]; - if( xValues.faceSet[fIdx] ) - { - const _FaceEdges& fe = xValues.faceEdges[ fIdx ]; - for( int j=0 ; j , typename _Key::Hasher >::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 ERROR_OUT( "Invalid faces: " , i , " " , fDir==HyperCube::BACK ? "back" : ( fDir==HyperCube::FRONT ? "front" : ( fDir==HyperCube::CROSS ? "cross" : "unknown" ) ) ); - } - } - } - // Get the edge loops - std::vector< std::vector< _Key > > loops; - while( edges.size() ) - { - loops.resize( loops.size()+1 ); - _IsoEdge edge = edges.back(); - edges.pop_back(); - _Key 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< _Key , _Key , typename _Key::Hasher >::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; - tree._localDepthAndOffset( leaf , d , off ); - ERROR_OUT( "Failed to close loop [" , d-1 , ": " , off[0] , " " , off[1] , " " , off[2] , "] | (" , i , "): " , current.to_string() ); - } - } - 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 , typename _Key::Hasher >::const_iterator iter; - size_t kk = flipOrientation ? loops[j].size()-1-k : k; - if ( ( iter=bValues.edgeVertexMap.find( key ) )!=bValues.edgeVertexMap.end() ) polygon[kk] = iter->second; - else if( ( iter=fValues.edgeVertexMap.find( key ) )!=fValues.edgeVertexMap.end() ) polygon[kk] = iter->second; - else if( ( iter=xValues.edgeVertexMap.find( key ) )!=xValues.edgeVertexMap.end() ) polygon[kk] = iter->second; - else ERROR_OUT( "Couldn't find vertex in edge map" ); - } - _AddIsoPolygons( thread , mesh , polygon , polygonMesh , addBarycenter , vOffset ); - } - } - } - } - } - ); - } - - template< unsigned int WeightDegree , typename Data , unsigned int DataSig > - static bool _GetIsoVertex( const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , ConstPointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , ConstPointSupportKey< IsotropicUIntPack< Dim , FEMSignature< DataSig >::Degree > >& dataKey , const TreeNode* node , typename HyperCube::template Cube< Dim-1 >::template Element< 1 > _e , HyperCube::Direction zDir , const _SliceValues& sValues , Vertex& vertex , const Data &zeroData , std::function< void ( Vertex& , Point< Real , Dim > , Point< Real , Dim > , Real , Data ) > SetVertex ) - { - static const unsigned int DataDegree = FEMSignature< DataSig >::Degree; - Point< Real , Dim > position , gradient; - int c0 , c1; - const typename HyperCube::Cube< Dim-1 >::template Element< 0 > *_c = SliceData::template HyperCubeTables< Dim-1 , 1 , 0 >::OverlapElements[_e.index]; - c0 = _c[0].index , c1 = _c[1].index; - - const typename SliceData::SquareCornerIndices& idx = sValues.sliceData.cornerIndices( node ); - Real x0 = sValues.cornerValues[idx[c0]] , x1 = sValues.cornerValues[idx[c1]]; - Point< Real , 3 > dx0 , dx1; - if( gradientNormals ) dx0 = sValues.cornerGradients[idx[c0]] , dx1 = sValues.cornerGradients[idx[c1]]; - Point< Real , Dim > s; - Real start , width; - tree._startAndWidth( node , s , width ); - int o; - { - const HyperCube::Direction* dirs = SliceData::template HyperCubeTables< Dim-1 , 1 >::Directions[ _e.index ]; - for( int d=0 ; d 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 ) ERROR_OUT( "Not a zero-crossing root: " , x0 , " " , x1 ); - averageRoot = ( isoValue - x0 ) / ( x1 - x0 ); - } - if( averageRoot<=0 || averageRoot>=1 ) - { - _BadRootCount++; - if( averageRoot<0 ) averageRoot = 0; - if( averageRoot>1 ) averageRoot = 1; - } - position[o] = Real( start + width*averageRoot ); - gradient = dx0 * (Real)( 1.-averageRoot ) + dx1 * (Real)averageRoot; - Real depth = (Real)1.; - Data dataValue; - if( densityWeights ) - { - Real weight; - tree._getSampleDepthAndWeight( *densityWeights , node , position , weightKey , depth , weight ); - } - if( data ) - { - if( DataDegree==0 ) - { - Point< Real , 3 > center( s[0] + width/2 , s[1] + width/2 , s[2] + width/2 ); - ProjectiveData< Data , Real > pValue( zeroData ); - tree.template _addEvaluation< ProjectiveData< Data , Real > , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > , 0 >( *data , center , *pointEvaluator , dataKey , pValue ); - dataValue = pValue.weight ? pValue.value() : zeroData; - } - else - { - ProjectiveData< Data , Real > pValue( zeroData ); - tree.template _addEvaluation< ProjectiveData< Data , Real > , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > , 0 >( *data , position , *pointEvaluator , dataKey , pValue ); - dataValue = pValue.weight ? pValue.value() : zeroData; - } - } - SetVertex( vertex , position , gradient , depth , dataValue ); - return true; - } - - template< unsigned int WeightDegree , typename Data , unsigned int DataSig > - static bool _GetIsoVertex( const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , ConstPointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , ConstPointSupportKey< IsotropicUIntPack< Dim , FEMSignature< DataSig >::Degree > >& dataKey , const TreeNode* node , typename HyperCube::template Cube< Dim-1 >::template Element< 0 > _c , const _SliceValues& bValues , const _SliceValues& fValues , Vertex& vertex , const Data &zeroData , std::function< void ( Vertex& , Point< Real , Dim > , Point< Real , Dim > , Real , Data ) > SetVertex ) - { - static const unsigned int DataDegree = FEMSignature< DataSig >::Degree; - Point< Real , Dim > position , gradient; - - const typename SliceData::SquareCornerIndices& idx0 = bValues.sliceData.cornerIndices( node ); - const typename SliceData::SquareCornerIndices& idx1 = fValues.sliceData.cornerIndices( node ); - Real x0 = bValues.cornerValues[ idx0[_c.index] ] , x1 = fValues.cornerValues[ idx1[_c.index] ]; - Point< Real , 3 > dx0 , dx1; - if( gradientNormals ) dx0 = bValues.cornerGradients[ idx0[_c.index] ] , dx1 = fValues.cornerGradients[ idx1[_c.index] ]; - Point< Real , Dim > s; - Real start , width; - tree._startAndWidth( node , s , width ); - start = s[2]; - int x , y; - { - const HyperCube::Direction* xx = SliceData::template HyperCubeTables< Dim-1 , 0 >::Directions[ _c.index ]; - x = xx[0]==HyperCube::BACK ? 0 : 1 , y = xx[1]==HyperCube::BACK ? 0 : 1; - } - - position[0] = s[0] + width*x; - position[1] = s[1] + width*y; - - double averageRoot; - bool rootFound = false; - - if( nonLinearFit ) - { - double dx0 = bValues.cornerGradients[ idx0[_c.index] ][2] * width , dx1 = fValues.cornerGradients[ idx1[_c.index] ][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 ) ERROR_OUT( "Not a zero-crossing root: " , x0 , " " , x1 ); - averageRoot = ( isoValue - x0 ) / ( x1 - x0 ); - } - if( averageRoot<=0 || averageRoot>=1 ) - { - _BadRootCount++; - if( averageRoot<0 ) averageRoot = 0; - if( averageRoot>1 ) averageRoot = 1; - } - position[2] = Real( start + width*averageRoot ); - gradient = dx0 * (Real)( 1.-averageRoot ) + dx1 * (Real)averageRoot; - Real depth = (Real)1.; - Data dataValue; - if( densityWeights ) - { - Real weight; - tree._getSampleDepthAndWeight( *densityWeights , node , position , weightKey , depth , weight ); - } - if( data ) - { - if( DataDegree==0 ) - { - Point< Real , 3 > center( s[0] + width/2 , s[1] + width/2 , s[2] + width/2 ); - ProjectiveData< Data , Real > pValue( zeroData ); - tree.template _addEvaluation< ProjectiveData< Data , Real > , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > , 0 >( *data , center , *pointEvaluator , dataKey , pValue ); - dataValue = pValue.weight ? pValue.value() : zeroData; - } - else - { - ProjectiveData< Data , Real > pValue( zeroData ); - tree.template _addEvaluation< ProjectiveData< Data , Real > , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > , 0 >( *data , position , *pointEvaluator , dataKey , pValue ); - dataValue = pValue.weight ? pValue.value() : zeroData; - } - } - SetVertex( vertex , position , gradient , depth , dataValue ); - return true; - } - - static unsigned int _AddIsoPolygons( unsigned int thread , CoredMeshData< Vertex , node_index_type >& mesh , std::vector< std::pair< node_index_type , Vertex > >& polygon , bool polygonMesh , bool addBarycenter , node_index_type &vOffset ) - { - if( polygonMesh ) - { - std::vector< node_index_type > vertices( polygon.size() ); - for( unsigned int i=0 ; i3 ) - { - bool isCoplanar = false; - std::vector< node_index_type > triangle( 3 ); - - if( addBarycenter ) - for( unsigned int i=0 ; i()[k]==v2.template get<0>()[k] ) isCoplanar = true; - } - if( isCoplanar ) - { - Vertex c; - c *= 0; - for( unsigned int i=0 ; i lock( _pointInsertionMutex ); - cIdx = mesh.addOutOfCoreVertex( c ); - vOffset++; - } - for( unsigned i=0 ; i > vertices( polygon.size() ); - for( unsigned int i=0 ; i(); - std::vector< TriangleIndex< node_index_type > > triangles = MinimalAreaTriangulation< node_index_type , Real , Dim >( ( ConstPointer( Point< Real , Dim > ) )GetPointer( vertices ) , (node_index_type)vertices.size() ); - if( triangles.size()!=polygon.size()-2 ) ERROR_OUT( "Minimal area triangulation failed:" , triangles.size() , " != " , polygon.size()-2 ); - for( unsigned int i=0 ; i vertices( 3 ); - for( int i=0 ; i<3 ; i++ ) vertices[2-i] = polygon[i].first; - mesh.addPolygon_s( thread , vertices ); - } - return (unsigned int)polygon.size()-2; - } -public: - struct IsoStats - { - double cornersTime , verticesTime , edgesTime , surfaceTime; - double copyFinerTime , setTableTime; - IsoStats( void ) : cornersTime(0) , verticesTime(0) , edgesTime(0) , surfaceTime(0) , copyFinerTime(0) , setTableTime(0) {;} - std::string toString( void ) const - { - std::stringstream stream; - stream << "Corners / Vertices / Edges / Surface / Set Table / Copy Finer: "; - stream << std::fixed << std::setprecision(1) << cornersTime << " / " << verticesTime << " / " << edgesTime << " / " << surfaceTime << " / " << setTableTime << " / " << copyFinerTime; - stream << " (s)"; - return stream.str(); - } - }; - template< typename Data , typename SetVertexFunction , unsigned int ... FEMSigs , unsigned int WeightDegree , unsigned int DataSig > - static IsoStats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , CoredMeshData< Vertex , node_index_type >& mesh , const Data &zeroData , const SetVertexFunction &SetVertex , bool nonLinearFit , bool gradientNormals , bool addBarycenter , bool polygonMesh , bool flipOrientation ) - { - _BadRootCount = 0u; - IsoStats isoStats; - static_assert( sizeof...(FEMSigs)==Dim , "[ERROR] Number of signatures should match dimension" ); - tree._setFEM1ValidityFlags( UIntPack< FEMSigs ... >() ); - static const unsigned int DataDegree = FEMSignature< DataSig >::Degree; - static const int FEMDegrees[] = { FEMSignature< FEMSigs >::Degree ... }; - for( int d=0 ; d , ZeroUIntPack< Dim > >* pointEvaluator = NULL; - if( data ) pointEvaluator = new typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >( tree._maxDepth ); - DenseNodeData< Real , UIntPack< FEMSigs ... > > coarseCoefficients( tree._sNodesEnd( tree._maxDepth-1 ) ); - memset( coarseCoefficients() , 0 , sizeof(Real)*tree._sNodesEnd( tree._maxDepth-1 ) ); - ThreadPool::Parallel_for( tree._sNodesBegin(0) , tree._sNodesEnd( tree._maxDepth-1 ) , [&]( unsigned int, size_t i ){ coarseCoefficients[i] = coefficients[i]; } ); - typename FEMIntegrator::template RestrictionProlongation< UIntPack< FEMSigs ... > > rp; - for( LocalDepth d=1 ; d() , rp , d , ( ConstPointer(Real) )coarseCoefficients()+tree._sNodesBegin(d-1) , coarseCoefficients()+tree._sNodesBegin(d) ); - FEMTree< Dim , Real >::MemoryUsage(); - - std::vector< _Evaluator< UIntPack< FEMSigs ... > , 1 > > evaluators( tree._maxDepth+1 ); - for( LocalDepth d=0 ; d<=tree._maxDepth ; d++ ) evaluators[d].set( tree._maxDepth ); - - node_index_type vertexOffset = 0; - - std::vector< _SlabValues > slabValues( tree._maxDepth+1 ); - - // Initialize the back slice - for( LocalDepth d=tree._maxDepth ; d>=0 ; d-- ) - { - double t = Time(); - SliceData::SetSliceTableData( tree._sNodes , &slabValues[d].sliceValues(0).sliceData , &slabValues[d].xSliceValues(0).xSliceData , &slabValues[d].sliceValues(1).sliceData , tree._localToGlobal( d ) , tree._localInset( d ) ); - isoStats.setTableTime += Time()-t; - slabValues[d].sliceValues (0).reset( nonLinearFit || gradientNormals ); - slabValues[d].sliceValues (1).reset( nonLinearFit || gradientNormals ); - slabValues[d].xSliceValues(0).reset( ); - } - for( LocalDepth d=tree._maxDepth ; d>=0 ; d-- ) - { - // Copy edges from finer - double t = Time(); - if( d( tree , coefficients() , coarseCoefficients() , isoValue , d , 0 , slabValues , evaluators[d] ); - isoStats.cornersTime += Time()-t , t = Time(); - _SetSliceIsoVertices< WeightDegree , Data , DataSig >( tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , d , 0 , vertexOffset , mesh , slabValues , zeroData , SetVertex ); - isoStats.verticesTime += Time()-t , t = Time(); - _SetSliceIsoEdges( tree , d , 0 , slabValues ); - isoStats.edgesTime += Time()-t , t = Time(); - } - - // Iterate over the slices at the finest level - for( int slice=0 ; slice<( 1<=0 ; d-- , o>>=1 ) - { - // Copy edges from finer (required to ensure we correctly track edge cancellations) - double t = Time(); - if( d( tree , coefficients() , coarseCoefficients() , isoValue , d , o , slabValues , evaluators[d] ); - isoStats.cornersTime += Time()-t , t = Time(); - _SetSliceIsoVertices< WeightDegree , Data , DataSig >( tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , d , o , vertexOffset , mesh , slabValues , zeroData , SetVertex ); - isoStats.verticesTime += Time()-t , t = Time(); - _SetSliceIsoEdges( tree , d , o , slabValues ); - isoStats.edgesTime += Time()-t , t = Time(); - - // Set the cross-slice edges - _SetXSliceIsoVertices< WeightDegree , Data , DataSig >( tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , d , o-1 , vertexOffset , mesh , slabValues , zeroData , SetVertex ); - isoStats.verticesTime += Time()-t , t = Time(); - _SetXSliceIsoEdges( tree , d , o-1 , slabValues ); - isoStats.edgesTime += Time()-t , t = Time(); - - ThreadPool::ParallelSections - ( - [ &slabValues , d , o ]( void ){ slabValues[d]. sliceValues(o-1).setEdgeVertexMap(); } , - [ &slabValues , d , o ]( void ){ slabValues[d]. sliceValues(o ).setEdgeVertexMap(); } , - [ &slabValues , d , o ]( void ){ slabValues[d].xSliceValues(o-1).setEdgeVertexMap(); } , - [ &slabValues , d , o ]( void ){ slabValues[d]. sliceValues(o-1).setVertexPairMap(); } , - [ &slabValues , d , o ]( void ){ slabValues[d]. sliceValues(o ).setVertexPairMap(); } , - [ &slabValues , d , o ]( void ){ slabValues[d].xSliceValues(o-1).setVertexPairMap(); } , - [ &slabValues , d , o ]( void ){ slabValues[d]. sliceValues(o-1).setFaceEdgeMap(); } , - [ &slabValues , d , o ]( void ){ slabValues[d]. sliceValues(o ).setFaceEdgeMap(); } , - [ &slabValues , d , o ]( void ){ slabValues[d].xSliceValues(o-1).setFaceEdgeMap(); } - ); - // Add the triangles - t = Time(); - _SetIsoSurface( tree , d , o-1 , slabValues[d].sliceValues(o-1) , slabValues[d].sliceValues(o) , slabValues[d].xSliceValues(o-1) , mesh , polygonMesh , addBarycenter , vertexOffset , flipOrientation ); - isoStats.surfaceTime += Time()-t; - - if( o&1 ) break; - } - - for( d=tree._maxDepth , o=slice+1 ; d>=0 ; d-- , o>>=1 ) - { - // Initialize for the next pass - if( o<(1<<(d+1)) ) - { - double t = Time(); - SliceData::SetSliceTableData( tree._sNodes , NULL , &slabValues[d].xSliceValues(o).xSliceData , &slabValues[d].sliceValues(o+1).sliceData , tree._localToGlobal( d ) , o + tree._localInset( d ) ); - isoStats.setTableTime += Time()-t; - slabValues[d].sliceValues(o+1).reset( nonLinearFit || gradientNormals ); - slabValues[d].xSliceValues(o).reset(); - } - if( o&1 ) break; - } - } - FEMTree< Dim , Real >::MemoryUsage(); - if( pointEvaluator ) delete pointEvaluator; - size_t badRootCount = _BadRootCount; - if( badRootCount!=0 ) WARN( "bad average roots: " , badRootCount ); - return isoStats; - } -}; -template< class Real , class Vertex > std::mutex IsoSurfaceExtractor< 3 , Real , Vertex >::_pointInsertionMutex; -template< class Real , class Vertex > std::atomic< size_t > IsoSurfaceExtractor< 3 , Real , Vertex >::_BadRootCount; - -template< class Real , class Vertex > template< unsigned int D , unsigned int K > -unsigned int IsoSurfaceExtractor< 3 , Real , Vertex >::SliceData::HyperCubeTables< D , K >::CellOffset[ ElementNum ][ IncidentCubeNum ]; -template< class Real , class Vertex > template< unsigned int D , unsigned int K > -unsigned int IsoSurfaceExtractor< 3 , Real , Vertex >::SliceData::HyperCubeTables< D , K >::IncidentElementCoIndex[ ElementNum ][ IncidentCubeNum ]; -template< class Real , class Vertex > template< unsigned int D , unsigned int K > -unsigned int IsoSurfaceExtractor< 3 , Real , Vertex >::SliceData::HyperCubeTables< D , K >::CellOffsetAntipodal[ ElementNum ]; -template< class Real , class Vertex > template< unsigned int D , unsigned int K > -typename HyperCube::Cube< D >::template IncidentCubeIndex < K > IsoSurfaceExtractor< 3 , Real , Vertex >::SliceData::HyperCubeTables< D , K >::IncidentCube[ ElementNum ]; -template< class Real , class Vertex > template< unsigned int D , unsigned int K > -typename HyperCube::Direction IsoSurfaceExtractor< 3 , Real , Vertex >::SliceData::HyperCubeTables< D , K >::Directions[ ElementNum ][ D ]; -template< class Real , class Vertex > template< unsigned int D , unsigned int K1 , unsigned int K2 > -typename HyperCube::Cube< D >::template Element< K2 > IsoSurfaceExtractor< 3 , Real , Vertex >::SliceData::HyperCubeTables< D , K1 , K2 >::OverlapElements[ ElementNum1 ][ OverlapElementNum ]; -template< class Real , class Vertex > template< unsigned int D , unsigned int K1 , unsigned int K2 > -bool IsoSurfaceExtractor< 3 , Real , Vertex >::SliceData::HyperCubeTables< D , K1 , K2 >::Overlap[ ElementNum1 ][ ElementNum2 ]; diff --git a/Src/FEMTree.LevelSet.2D.inl b/Src/FEMTree.LevelSet.2D.inl new file mode 100644 index 00000000..f6230b11 --- /dev/null +++ b/Src/FEMTree.LevelSet.2D.inl @@ -0,0 +1,1072 @@ +/* +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 FEM_TREE_LEVEL_SET_2D_INL_INCLUDED +#define FEM_TREE_LEVEL_SET_2D_INL_INCLUDED + +#include +#include +#include +#include +#include "MyMiscellany.h" +#include "MarchingCubes.h" +#include "MAT.h" + +// Specialized level-set curve extraction +template< class Real , typename Vertex > +struct LevelSetExtractor< 2 , Real , Vertex > +{ +protected: + static std::mutex _pointInsertionMutex; + static std::atomic< size_t > _BadRootCount; +public: + + static const unsigned int Dim = 2; + using LocalDepth = typename FEMTree< Dim , Real >::LocalDepth; + using LocalOffset = typename FEMTree< Dim , Real >::LocalOffset; + using ConstOneRingNeighborKey = typename FEMTree< Dim , Real >::ConstOneRingNeighborKey; + using ConstOneRingNeighbors = typename FEMTree< Dim , Real >::ConstOneRingNeighbors; + using TreeNode = RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >; + template< unsigned int WeightDegree > using DensityEstimator = typename FEMTree< Dim , Real >::template DensityEstimator< WeightDegree >; + template< typename FEMSigPack , unsigned int PointD > using _Evaluator = typename FEMTree< Dim , Real >::template _Evaluator< FEMSigPack , PointD >; + + using Key = LevelSetExtraction::Key< Dim >; + using IsoEdge = LevelSetExtraction::IsoEdge< Dim >; + template< unsigned int D , unsigned int ... Ks > + using HyperCubeTables = typename LevelSetExtraction::template HyperCubeTables< D , Ks ... >; + + //////////////// + // FaceEdges // + //////////////// + struct FaceEdges + { + IsoEdge edges[2]; + int count; + FaceEdges( void ) : count(-1){} + }; + + ///////////////// + // SliceValues // + ///////////////// + struct SliceValues + { + struct Scratch + { + using FKeyValues = std::vector< std::vector< std::pair< Key , std::vector< IsoEdge > > > >; + using EKeyValues = std::vector< std::vector< std::pair< Key , node_index_type > > >; + using VKeyValues = std::vector< std::vector< std::pair< Key , Key > > >; + + FKeyValues fKeyValues; + EKeyValues eKeyValues; + VKeyValues vKeyValues; + + Pointer( char ) cSet; + Pointer( char ) eSet; + + Scratch( void ) + { + vKeyValues.resize( ThreadPool::NumThreads() ); + eKeyValues.resize( ThreadPool::NumThreads() ); + fKeyValues.resize( ThreadPool::NumThreads() ); + cSet = NullPointer( char ); + eSet = NullPointer( char ); + } + + ~Scratch( void ) + { + FreePointer( cSet ); + FreePointer( eSet ); + } + + void reset( const LevelSetExtraction::FullCellIndexData< Dim > &cellIndices ) + { + for( size_t i=0 ; i( cellIndices.counts[0] ); + memset( cSet , 0 , sizeof( char ) * cellIndices.counts[0] ); + } + if( cellIndices.counts[1] ) + { + eSet = AllocPointer< char >( cellIndices.counts[1] ); + memset( eSet , 0 , sizeof( char ) * cellIndices.counts[1] ); + } + } + }; + + // A data-structure for taking the a node index and the local index of a cell within the node and returning the global index for that cell + LevelSetExtraction::FullCellIndexData< Dim > cellIndices; + + // A table taking a node index and returning the associated marching squares index + Pointer( char ) mcIndices; + + // Tables taking a corner index and returning the value (and possibly the gradient) at the corresponding location + Pointer( Real ) cornerValues ; Pointer( Point< Real , Dim > ) cornerGradients; + + // A table taking an edge index and returning the associated key + Pointer( Key ) edgeKeys; + + // A table taking a face index and returning the associated key + Pointer( FaceEdges ) faceEdges; + + // A map taking a key for a face and returning the iso-edges within that face + LevelSetExtraction::KeyMap< Dim , std::vector< IsoEdge > > faceEdgeMap; + // A map taking a key for an edge and returning the index of the iso-vertex along that edge + LevelSetExtraction::KeyMap< Dim , node_index_type > edgeVertexMap; + // A map linking an iso-vertex to its pair + LevelSetExtraction::KeyMap< Dim , Key > vertexPairMap; + + SliceValues( void ) + { + cornerValues = NullPointer( Real ) ; cornerGradients = NullPointer( Point< Real , Dim > ); + edgeKeys = NullPointer( Key ); + faceEdges = NullPointer( FaceEdges ); + mcIndices = NullPointer( char ); + } + + ~SliceValues( void ){ clear(); } + + void clear( void ) + { + cellIndices.clear(); + FreePointer( cornerValues ) ; FreePointer( cornerGradients ); + DeletePointer( edgeKeys ); + DeletePointer( faceEdges ); + FreePointer( mcIndices ); + } + + void read( BinaryStream &stream ) + { + clear(); + + cellIndices.read( stream ); + + if( cellIndices.size() ) + { + mcIndices = AllocPointer< char >( cellIndices.size() ); + if( !stream.read( mcIndices , cellIndices.size() ) ) ERROR_OUT( "Failed to read mc indices" ); + } + if( cellIndices.counts[0] ) + { + cornerValues = AllocPointer< Real >( cellIndices.counts[0] ); + if( !stream.read( cornerValues , cellIndices.counts[0] ) ) ERROR_OUT( "Failed to read corner values" ); + char hasCornerGradients; + if( !stream.read( hasCornerGradients ) ) ERROR_OUT( "Could not read corner gradient state" ); + if( hasCornerGradients ) + { + cornerGradients = AllocPointer< Point< Real , Dim > >( cellIndices.counts[0] ); + if( !stream.read( cornerGradients , cellIndices.counts[0] ) ) ERROR_OUT( "Could not read corner gradients" ); + } + } + + if( cellIndices.counts[1] ) + { + edgeKeys = NewPointer< Key >( cellIndices.counts[1] ); + if( !stream.read( edgeKeys , cellIndices.counts[1]) ) ERROR_OUT( "Could not read edge keys" ); + } + + if( cellIndices.counts[2] ) + { + faceEdges = NewPointer< FaceEdges >( cellIndices.counts[2] ); + if( !stream.read( faceEdges , cellIndices.counts[2] ) ) ERROR_OUT( "Could not read face edges" ); + } + + auto ReadIsoEdgeVector = [&]( BinaryStream &stream , std::vector< IsoEdge > &edges ) + { + size_t sz; + if( !stream.read( sz ) ) ERROR_OUT( "Could not read iso-edge vector size" ); + edges.resize( sz ); + if( sz && !stream.read( GetPointer( edges ) , sz ) ) ERROR_OUT( "Could not read iso-edges" ); + }; + { + size_t sz; + if( !stream.read( sz ) ) ERROR_OUT( "Could not read face-edge-map size" ); + for( unsigned int i=0 ; i &edges ) + { + size_t sz = edges.size(); + stream.write( sz ); + if( sz ) stream.write( GetPointer( edges ) , sz ); + }; + + auto SerializeFaceEdgeMap = [&]( size_t &sz ) + { + using map = LevelSetExtraction::KeyMap< Dim , std::vector< IsoEdge > >; + + sz = 0; + for( typename map::const_iterator iter=faceEdgeMap.begin() ; iter!=faceEdgeMap.end() ; iter++ ) + sz += sizeof( typename LevelSetExtraction::Key< Dim > ) + sizeof( size_t ) + sizeof( IsoEdge ) * iter->second.size(); + + Pointer( char ) buffer = NewPointer< char >( sz ); + Pointer( char ) _buffer = buffer; + for( typename map::const_iterator iter=faceEdgeMap.begin() ; iter!=faceEdgeMap.end() ; iter++ ) + { + memcpy( _buffer , &iter->first , sizeof( typename LevelSetExtraction::Key< Dim > ) ) ; _buffer += sizeof( typename LevelSetExtraction::Key< Dim > ); + size_t num = iter->second.size(); + memcpy( _buffer , &num , sizeof( size_t ) ) ; _buffer += sizeof( size_t ); + if( num ) memcpy( _buffer , &iter->second[0] , sizeof(IsoEdge) * iter->second.size() ) ; _buffer += sizeof(IsoEdge) * iter->second.size(); + } + return buffer; + }; + + { + using map = LevelSetExtraction::KeyMap< Dim , std::vector< IsoEdge > >; + if( serialize ) + { + size_t sz = faceEdgeMap.size(); + stream.write( sz ); + if( sz ) + { + Pointer( char ) buffer = SerializeFaceEdgeMap( sz ); + stream.write( buffer , sz ); + DeletePointer( buffer ); + } + } + else + { + size_t sz = faceEdgeMap.size(); + stream.write( sz ); + for( typename map::const_iterator iter=faceEdgeMap.begin() ; iter!=faceEdgeMap.end() ; iter++ ) + { + stream.write( iter->first ); + WriteIsoEdgeVector( stream , iter->second ); + } + } + } + + { + using map = LevelSetExtraction::KeyMap< Dim , node_index_type >; + if( serialize ) + { + size_t sz = edgeVertexMap.size(); + stream.write( sz ); + if( sz ) + { + size_t elementSize = sizeof( typename LevelSetExtraction::Key< Dim > ) + sizeof( node_index_type ); + Pointer( char ) buffer = NewPointer< char >( edgeVertexMap.size() * elementSize ); + { + Pointer( char ) _buffer = buffer; + for( typename map::const_iterator iter=edgeVertexMap.begin() ; iter!=edgeVertexMap.end() ; iter++ ) + { + memcpy( _buffer , &iter->first , sizeof( typename LevelSetExtraction::Key< Dim > ) ) ; _buffer += sizeof( typename LevelSetExtraction::Key< Dim > ); + memcpy( _buffer , &iter->second , sizeof( node_index_type ) ) ; _buffer += sizeof( node_index_type ); + } + } + stream.write( buffer , edgeVertexMap.size() * elementSize ); + DeletePointer( buffer ); + } + } + else + { + size_t sz = edgeVertexMap.size(); + stream.write( sz ); + for( typename map::const_iterator iter=edgeVertexMap.begin() ; iter!=edgeVertexMap.end() ; iter++ ) + { + stream.write( iter->first ); + stream.write( iter->second ); + } + } + } + + { + using map = LevelSetExtraction::KeyMap< Dim , Key >; + if( serialize ) + { + std::vector< std::pair< typename LevelSetExtraction::Key< Dim > , Key > > pairs; + pairs.reserve( vertexPairMap.size() ); + for( typename map::const_iterator iter=vertexPairMap.begin() ; iter!=vertexPairMap.end() ; iter++ ) + pairs.push_back( std::pair< typename LevelSetExtraction::Key< Dim > , Key >( iter->first , iter->second ) ); + stream.write( pairs ); + } + else + { + size_t sz = vertexPairMap.size(); + stream.write( sz ); + for( typename map::const_iterator iter=vertexPairMap.begin() ; iter!=vertexPairMap.end() ; iter++ ) + { + stream.write( iter->first ); + stream.write( iter->second ); + } + } + } + } + + void setFromScratch( typename Scratch::EKeyValues &scratch ) + { + for( node_index_type i=0 ; i<(node_index_type)scratch.size() ; i++ ) + { + for( int j=0 ; j &faceEdges = faceEdgeMap[ scratch[i][j].first ]; + faceEdges.insert( faceEdges.end() , scratch[i][j].second.begin() , scratch[i][j].second.end() ); + } + scratch[i].clear(); + } + } + + void reset( bool computeGradients ) + { + faceEdgeMap.clear() , edgeVertexMap.clear() , vertexPairMap.clear(); + + FreePointer( mcIndices ); + if( cellIndices.size()>0 ) mcIndices = AllocPointer< char >( cellIndices.size() ); + + FreePointer( cornerValues ) ; FreePointer( cornerGradients ); + if( cellIndices.counts[0]>0 ) + { + cornerValues = AllocPointer< Real >( cellIndices.counts[0] ); + if( computeGradients ) cornerGradients = AllocPointer< Point< Real , Dim > >( cellIndices.counts[0] ); + } + + DeletePointer( edgeKeys ); + edgeKeys = NewPointer< Key >( cellIndices.counts[1] ); + + DeletePointer( faceEdges ); + faceEdges = NewPointer< FaceEdges >( cellIndices.counts[2] ); + + } + + bool setVertexPair( Key current , Key &pair ) const + { + typename LevelSetExtraction::KeyMap< Dim , Key >::const_iterator iter; + + if( (iter=vertexPairMap.find(current))!=vertexPairMap.end() ) + { + pair = iter->second; + return true; + } + else return false; + } + }; + + struct TreeSliceValuesAndVertexPositions + { + const FEMTree< Dim , Real > sliceTree; + std::vector< SliceValues > sliceValues; + // [WARNING] Should really be using Vertex instead of Point< Real , Dim > + std::vector< Point< Real , Dim > > vertexPositions; + + TreeSliceValuesAndVertexPositions( void ) : sliceTree(NULL){} + TreeSliceValuesAndVertexPositions( BinaryStream &stream , XForm< Real , Dim+1 > &xForm , size_t blockSize ) : sliceTree( stream , xForm , blockSize ) + { + size_t sz; + if( !stream.read( sz ) ) ERROR_OUT( "Could not read slice count" ); + sliceValues.resize( sz ); + for( unsigned int i=0 ; i vertexKeys( void ) const + { + std::vector< Key > keys( vertexPositions.size() ); + for( unsigned int i=0 ; i::const_iterator iter=sliceValues[i].edgeVertexMap.cbegin() ; iter!=sliceValues[i].edgeVertexMap.cend() ; iter++ ) + { + if( iter->second>=(node_index_type)vertexPositions.size() ) ERROR_OUT( "Unexpected vertex index: " , iter->second , " <= " , vertexPositions.size() ); + keys[iter->second] = iter->first; + } + return keys; + }; + + static void Write( BinaryStream &stream , const FEMTree< Dim , Real > *sliceTree , XForm< Real , Dim+1 > xForm , const std::vector< SliceValues > &sliceValues , const std::vector< Point< Real , Dim > > &vertices , bool serialize ) + { + sliceTree->write( stream , xForm , serialize ); + + size_t sz = sliceValues.size(); + stream.write( sz ); + for( unsigned int i=0 ; i xForm , bool serialize ) const + { + Write( stream , &sliceTree , xForm , sliceValues , vertexPositions , serialize ); + } + }; + + + template< unsigned int ... FEMSigs > + static void SetSCornerValues( const FEMTree< Dim , Real >& tree , ConstPointer( Real ) coefficients , ConstPointer( Real ) coarseCoefficients , Real isoValue , LocalDepth depth , LocalDepth fullDepth , std::vector< SliceValues >& sliceValues , std::vector< typename SliceValues::Scratch > &scratchValues , const _Evaluator< UIntPack< FEMSigs ... > , 1 >& evaluator ) + { + static const unsigned int FEMDegrees[] = { FEMSignature< FEMSigs >::Degree ... }; + SliceValues& sValues = sliceValues[depth]; + Pointer( char ) cornerSet = scratchValues[depth].cSet; + bool useBoundaryEvaluation = false; + for( int d=0 ; d::Degree ... > > > neighborKeys( ThreadPool::NumThreads() ); + std::vector< ConstCornerSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > > > bNeighborKeys( ThreadPool::NumThreads() ); + if( useBoundaryEvaluation ) for( size_t i=0 ; i::template ElementNum< 0 >() ]; + ConstPointSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& neighborKey = neighborKeys[ thread ]; + ConstCornerSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bNeighborKey = bNeighborKeys[ thread ]; + TreeNode* leaf = tree._sNodes.treeNodes[i]; + // Iterate over all leaf nodes + if( !IsActiveNode< Dim >( leaf->children ) ) + { + const typename LevelSetExtraction::FullCellIndexData< Dim >::template CellIndices<0> &cIndices = sValues.cellIndices.template indices<0>( leaf ); + + bool isInterior = tree._isInteriorlySupported( UIntPack< FEMSignature< FEMSigs >::Degree ... >() , leaf->parent ); + if( useBoundaryEvaluation ) bNeighborKey.getNeighbors( leaf ); + else neighborKey.getNeighbors( leaf ); + + // Iterate over the corners of the cell + for( typename HyperCube::Cube< Dim >::template Element< 0 > c ; c::template ElementNum< 0 >() ; c++ ) + { + // Grab the global corner index, and if its value hasn't been set yet get the values (and gradients) and store them + node_index_type vIndex = cIndices[c.index]; + if( !cornerSet[vIndex] ) + { + if( sValues.cornerGradients ) + { + CumulativeDerivativeValues< Real , Dim , 1 > p; + if( useBoundaryEvaluation ) p = tree.template _getCornerValues< Real , 1 >( bNeighborKey , leaf , c.index , coefficients , coarseCoefficients , evaluator , tree._maxDepth , isInterior ); + else p = tree.template _getCornerValues< Real , 1 >( neighborKey , leaf , c.index , coefficients , coarseCoefficients , evaluator , tree._maxDepth , isInterior ); + sValues.cornerValues[vIndex] = p[0] , sValues.cornerGradients[vIndex] = Point< Real , Dim >( p[1] , p[2] ); + } + else + { + if( useBoundaryEvaluation ) sValues.cornerValues[vIndex] = tree.template _getCornerValues< Real , 0 >( bNeighborKey , leaf , c.index , coefficients , coarseCoefficients , evaluator , tree._maxDepth , isInterior )[0]; + else sValues.cornerValues[vIndex] = tree.template _getCornerValues< Real , 0 >( neighborKey , leaf , c.index , coefficients , coarseCoefficients , evaluator , tree._maxDepth , isInterior )[0]; + } + cornerSet[vIndex] = 1; + } + squareValues[c.index] = sValues.cornerValues[ vIndex ]; + + // Copy from the finer depth to the coarser depth + TreeNode* node = leaf; + LocalDepth _depth = depth; + // Iterate to the parents as long as they contain the corner + while( _depth>fullDepth && tree._isValidSpaceNode( node->parent ) && (node-node->parent->children)==c.index ) + { + node = node->parent , _depth--; + SliceValues& _sValues = sliceValues[_depth]; + Pointer( char ) _cornerSet = scratchValues[_depth].cSet; + const typename LevelSetExtraction::FullCellIndexData< Dim >::template CellIndices<0> &_cIndices = _sValues.cellIndices.template indices<0>( node ); + node_index_type _vIndex = _cIndices[c.index]; + _sValues.cornerValues[_vIndex] = sValues.cornerValues[vIndex]; + if( _sValues.cornerGradients ) _sValues.cornerGradients[_vIndex] = sValues.cornerGradients[vIndex]; + _cornerSet[_vIndex] = 1; + } + } + + // Set the marching squares index for the face + sValues.mcIndices[ i - sValues.cellIndices.nodeOffset ] = HyperCube::Cube< Dim >::MCIndex( squareValues , isoValue ); + } + } + } + ); + } + + template< unsigned int WeightDegree , typename Data , unsigned int DataSig > + static void SetIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > > *pointEvaluator , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , node_index_type &vOffset , StreamingVertices< Vertex , node_index_type > *vertices , std::vector< SliceValues > &sliceValues , std::vector< typename SliceValues::Scratch > &scratchValues , const Data &zeroData , std::function< void ( Vertex& , Point< Real , Dim > , Point< Real , Dim > , Real , Data ) > SetVertex ) + { + auto _EdgeIndex = [&]( const TreeNode *node , typename HyperCube::Cube< Dim >::template Element< 1 > e ) + { + int depth , offset[Dim]; + tree.depthAndOffset( node , depth , offset ); + return keyGenerator( depth , offset , e ); + }; + static const unsigned int DataDegree = FEMSignature< DataSig >::Degree; + + SliceValues &sValues = sliceValues[depth]; + typename SliceValues::Scratch &scValues = scratchValues[depth]; + // [WARNING] In the case Degree=2, these two keys are the same, so we don't have to maintain them separately. + std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); + std::vector< ConstPointSupportKey< IsotropicUIntPack< Dim , WeightDegree > > > weightKeys( ThreadPool::NumThreads() ); + std::vector< ConstPointSupportKey< IsotropicUIntPack< Dim , DataDegree > > > dataKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i >& weightKey = weightKeys[ thread ]; + ConstPointSupportKey< IsotropicUIntPack< Dim , DataDegree > >& dataKey = dataKeys[ thread ]; + TreeNode* leaf = tree._sNodes.treeNodes[i]; + + // Iterate over all leaf nodes in the tree + if( !IsActiveNode< Dim >( leaf->children ) ) + { + node_index_type idx = (node_index_type)i - sValues.cellIndices.nodeOffset; + const typename LevelSetExtraction::FullCellIndexData< Dim >::template CellIndices<1> eIndices = sValues.cellIndices.template indices<1>( leaf ); + + // Check if the face has zero-crossings + if( HyperCube::Cube< Dim >::HasMCRoots( sValues.mcIndices[idx] ) ) + { + neighborKey.getNeighbors( leaf ); + if( densityWeights ) weightKey.getNeighbors( leaf ); + if( data ) dataKey.getNeighbors( leaf ); + + // Check if the individual edges have zero-crossings + for( typename HyperCube::Cube< Dim >::template Element< 1 > e ; e::template ElementNum< 1 >() ; e++ ) + if( HyperCube::Cube< 1 >::HasMCRoots( HyperCube::Cube< Dim >::ElementMCIndex( e , sValues.mcIndices[idx] ) ) ) + { + node_index_type vIndex = eIndices[e.index]; + volatile char &edgeSet = scValues.eSet[vIndex]; + // If the edge hasn't been set already (e.g. either by another thread or from a finer resolution) + if( !edgeSet ) + { + Vertex vertex; + Key key = _EdgeIndex( leaf , e ); + GetIsoVertex< WeightDegree , Data , DataSig >( tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , e , sValues , vertex , zeroData , SetVertex ); + bool stillOwner = false; + node_index_type hashed_vertex; + { + std::lock_guard< std::mutex > lock( _pointInsertionMutex ); + if( !edgeSet ) + { + if( vertices ) vertices->addVertex( vertex ); + edgeSet = 1; + hashed_vertex = vOffset; + sValues.edgeKeys[ vIndex ] = key; + vOffset++; + stillOwner = true; + } + } + if( stillOwner ) // If this edge is the one generating the iso-vertex + { + scValues.eKeyValues[ thread ].push_back( std::pair< Key , node_index_type >( key , hashed_vertex ) ); + // We only need to pass the iso-vertex down if the edge it lies on is adjacent to a coarser leaf + + { + const typename HyperCube::Cube< Dim >::template Element< Dim > *f = HyperCubeTables< Dim , 1 , Dim >::OverlapElements[e.index]; + // Note that this is a trivial loop of size 1 + for( int k=0 ; k::OverlapElementNum ; k++ ) + { + TreeNode *node = leaf; + LocalDepth _depth = depth; + while( _depth>fullDepth && tree._isValidSpaceNode( node->parent ) && HyperCubeTables< Dim , Dim , 0 >::Overlap[f[k].index][(unsigned int)(node-node->parent->children) ] ) + { + node = node->parent , _depth--; + typename SliceValues::Scratch &_scValues = scratchValues[_depth]; + _scValues.eKeyValues[ thread ].push_back( std::pair< Key , node_index_type >( key , hashed_vertex ) ); + } + } + } + } + } + } + } + } + } + } + ); + } + + static void CopyFinerSliceIsoEdgeKeys( const FEMTree< Dim , Real >& tree , LocalDepth depth , LocalDepth fullDepth , std::vector< SliceValues >& sliceValues , std::vector< typename SliceValues::Scratch > &scratchValues ) + { + SliceValues& pSliceValues = sliceValues[depth ]; + SliceValues& cSliceValues = sliceValues[depth+1]; + typename SliceValues::Scratch &pScratchSliceValues = scratchValues[depth ]; + typename SliceValues::Scratch &cScratchSliceValues = scratchValues[depth+1]; + LevelSetExtraction::FullCellIndexData< Dim > &pCellIndices = pSliceValues.cellIndices; + LevelSetExtraction::FullCellIndexData< Dim > &cCellIndices = cSliceValues.cellIndices; + ThreadPool::Parallel_for( tree._sNodesBegin(depth) , tree._sNodesEnd(depth) , [&]( unsigned int thread , size_t i ) + { + if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i] ) ) if( IsActiveNode< Dim >( tree._sNodes.treeNodes[i]->children ) ) + { + // Get the mapping from local edge indices to global edge indices + typename LevelSetExtraction::FullCellIndexData< Dim >::template CellIndices<1> &pIndices = pCellIndices.template indices<1>( (node_index_type)i ); + // Copy the edges that overlap the coarser edges + for( typename HyperCube::Cube< Dim >::template Element< 1 > e ; e::template ElementNum< 1 >() ; e++ ) + { + // The global (coarse) edge index + node_index_type pIndex = pIndices[e.index]; + if( !pScratchSliceValues.eSet[ pIndex ] ) + { + // The corner indices incident on the edeg + const typename HyperCube::Cube< Dim >::template Element< 0 > *c = HyperCubeTables< Dim , 1 , 0 >::OverlapElements[e.index]; + // [SANITY CHECK] + // if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[0].index )!=tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[1].index ) ) ERROR_OUT( "Finer edges should both be valid or invalid" ); + // Can only copy edge information from the finer nodes incident on the edge if they are valid (note since we refine in broods, we can't have one child in and the other out) + if( !tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[0].index ) || !tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[1].index ) ) continue; + + + // The global (fine) edge indices + node_index_type cIndex1 = cCellIndices.template indices<1>( tree._sNodes.treeNodes[i]->children + c[0].index )[e.index]; + node_index_type cIndex2 = cCellIndices.template indices<1>( tree._sNodes.treeNodes[i]->children + c[1].index )[e.index]; + + // If only one of the finer edges has a zero-crossing, then the coarse edge will as well + if( cScratchSliceValues.eSet[cIndex1] != cScratchSliceValues.eSet[cIndex2] ) + { + Key key; + if( cScratchSliceValues.eSet[cIndex1] ) key = cSliceValues.edgeKeys[cIndex1]; + else key = cSliceValues.edgeKeys[cIndex2]; + pSliceValues.edgeKeys[pIndex] = key; + pScratchSliceValues.eSet[pIndex] = 1; + } + // If both of the finer edges have a zero-crossing, those will form a pair (but the coarser edge will not have a zero crossing) + else if( cScratchSliceValues.eSet[cIndex1] && cScratchSliceValues.eSet[cIndex2] ) + { + Key key1 = cSliceValues.edgeKeys[cIndex1] , key2 = cSliceValues.edgeKeys[cIndex2]; + pScratchSliceValues.vKeyValues[ thread ].push_back( std::pair< Key , Key >( key1 , key2 ) ); + + const TreeNode* node = tree._sNodes.treeNodes[i]; + LocalDepth _depth = depth; + while( _depth>fullDepth && tree._isValidSpaceNode( node->parent ) && HyperCubeTables< Dim , 1 , 0 >::Overlap[e.index][(unsigned int)(node-node->parent->children) ] ) + { + node = node->parent , _depth--; + typename SliceValues::Scratch &_pScratchSliceValues = scratchValues[_depth]; + _pScratchSliceValues.vKeyValues[ thread ].push_back( std::pair< Key , Key >( key1 , key2 ) ); + } + } + } + } + } + } + ); + } + + + static void SetIsoEdges( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , LocalDepth depth , LocalDepth fullDepth , std::vector< SliceValues >& sliceValues , std::vector< typename SliceValues::Scratch > &scratchValues ) + { + auto _FaceIndex = [&]( const TreeNode *node , typename HyperCube::Cube< Dim >::template Element< 2 > f ) + { + int depth , offset[Dim]; + tree.depthAndOffset( node , depth , offset ); + return keyGenerator( depth , offset , f ); + }; + + SliceValues& sValues = sliceValues[depth]; + Pointer( char ) edgeSet = scratchValues[depth].eSet; + std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i( leaf->children ) ) + { + const typename LevelSetExtraction::FullCellIndexData< Dim >::template CellIndices<1> &eIndices = sValues.cellIndices.template indices<1>( leaf ); + const typename LevelSetExtraction::FullCellIndexData< Dim >::template CellIndices<2> &fIndices = sValues.cellIndices.template indices<2>( leaf ); + unsigned char mcIndex = sValues.mcIndices[ (node_index_type)i - sValues.cellIndices.nodeOffset ]; + + // [NOTE] We do not add the vector of iso-edges at the depth where they are generate (as there can be at most two). + // We only add them to the coarser resolutions. + // Calculate the iso-edges for the face + FaceEdges fe; + fe.count = HyperCube::MarchingSquares::AddEdgeIndices( mcIndex , isoEdges ); + for( int j=0 ; j::template Element< Dim > f( 0u ); + + // Add the edges to the vector of iso-edges associated with a face + std::vector< IsoEdge > edges( fe.count ); + for( int j=0 ; jfullDepth && tree._isValidSpaceNode( node->parent ) && HyperCubeTables< Dim , 2 , 0 >::Overlap[f.index][(unsigned int)(node-node->parent->children) ] ) + { + node = node->parent , _depth--; + Key key = _FaceIndex( node , f ); + typename SliceValues::Scratch &_scValues = scratchValues[_depth]; + _scValues.fKeyValues[ thread ].push_back( std::pair< Key , std::vector< IsoEdge > >( key , edges ) ); + } + } + } + } + ); + } + + static void SetLevelSet( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , LocalDepth depth , const SliceValues &sValues , StreamingCurve< Vertex , node_index_type >& curve , bool flipOrientation ) + { + auto _FaceIndex = [&]( const TreeNode *node , typename HyperCube::Cube< Dim >::template Element< 2 > f ) + { + int depth , offset[Dim]; + tree.depthAndOffset( node , depth , offset ); + return keyGenerator( depth , offset , f ); + }; + + auto AddEdge = [&]( unsigned int thread , IsoEdge e ) + { + typename LevelSetExtraction::KeyMap< Dim , node_index_type >::const_iterator iter; + node_index_type idx1 , idx2; + if( ( iter=sValues.edgeVertexMap.find( e[0] ) )!=sValues.edgeVertexMap.end() ) idx1 = iter->second; + else ERROR_OUT( "Couldn't find vertex in edge map" ); + if( ( iter=sValues.edgeVertexMap.find( e[1] ) )!=sValues.edgeVertexMap.end() ) idx2 = iter->second; + else ERROR_OUT( "Couldn't find vertex in edge map" ); + if( flipOrientation ) curve.addEdge_s( thread , idx2 , idx1 ); + else curve.addEdge_s( thread , idx1 , idx2 ); + }; + + ThreadPool::Parallel_for( tree._sNodesBegin(depth) , tree._sNodesEnd(depth) , [&]( unsigned int thread , size_t i ) + { + if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i] ) ) + { + TreeNode *leaf = tree._sNodes.treeNodes[i]; + int res = 1<=0 && off[0]=0 && off[1]( leaf->children ) ) + { + // Gather the edges from the faces + for( typename HyperCube::Cube< Dim >::template Element< 2 > f ; f::template ElementNum< 2 >() ; f++ ) + { + node_index_type fIdx = sValues.cellIndices.template indices<2>((node_index_type)i)[0]; + { + const FaceEdges& fe = sValues.faceEdges[ fIdx ]; + for( int j=0 ; j + static bool GetIsoVertex( const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , ConstPointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , ConstPointSupportKey< IsotropicUIntPack< Dim , FEMSignature< DataSig >::Degree > >& dataKey , const TreeNode* node , typename HyperCube::template Cube< Dim >::template Element< 1 > e , const SliceValues& sValues , Vertex& vertex , const Data &zeroData , std::function< void ( Vertex& , Point< Real , Dim > , Point< Real , Dim > , Real , Data ) > SetVertex ) + { + static const unsigned int DataDegree = FEMSignature< DataSig >::Degree; + Point< Real , Dim > position , gradient; + int c0 , c1; + const typename HyperCube::Cube< Dim >::template Element< 0 > *c = HyperCubeTables< Dim , 1 , 0 >::OverlapElements[e.index]; + c0 = c[0].index , c1 = c[1].index; + + const typename LevelSetExtraction::FullCellIndexData< Dim >::template CellIndices<0> &idx = sValues.cellIndices.template indices<0>( node ); + Real x0 = sValues.cornerValues[idx[c0]] , x1 = sValues.cornerValues[idx[c1]]; + Point< Real , Dim > dx0 , dx1; + if( gradientNormals ) dx0 = sValues.cornerGradients[idx[c0]] , dx1 = sValues.cornerGradients[idx[c1]]; + Point< Real , Dim > s; + Real start , width; + tree._startAndWidth( node , s , width ); + int o; + { + const HyperCube::Direction* dirs = HyperCubeTables< Dim , 1 >::Directions[ e.index ]; + for( int d=0 ; d 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 ) ERROR_OUT( "Not a zero-crossing root: " , x0 , " " , x1 ); + averageRoot = ( isoValue - x0 ) / ( x1 - x0 ); + } + if( averageRoot<=0 || averageRoot>=1 ) + { + _BadRootCount++; + if( averageRoot<0 ) averageRoot = 0; + if( averageRoot>1 ) averageRoot = 1; + } + position[o] = Real( start + width*averageRoot ); + gradient = dx0 * (Real)( 1.-averageRoot ) + dx1 * (Real)averageRoot; + Real depth = (Real)1.; + Data dataValue; + if( densityWeights ) + { + Real weight; + tree._getSampleDepthAndWeight( *densityWeights , node , position , weightKey , depth , weight ); + } + if( data ) + { + if( DataDegree==0 ) + { + Point< Real , 2 > center( s[0] + width/2 , s[1] + width/2 ); + ProjectiveData< Data , Real > pValue( zeroData ); + tree.template _addEvaluation< ProjectiveData< Data , Real > , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > , 0 >( *data , center , *pointEvaluator , dataKey , pValue ); + dataValue = pValue.weight ? pValue.value() : zeroData; + } + else + { + ProjectiveData< Data , Real > pValue( zeroData ); + tree.template _addEvaluation< ProjectiveData< Data , Real > , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > , 0 >( *data , position , *pointEvaluator , dataKey , pValue ); + dataValue = pValue.weight ? pValue.value() : zeroData; + } + } + SetVertex( vertex , position , gradient , depth , dataValue ); + return true; + } + + struct Stats + { + double cornersTime , verticesTime , edgesTime , curveTime; + double copyFinerTime , setTableTime; + Stats( void ) : cornersTime(0) , verticesTime(0) , edgesTime(0) , curveTime(0), copyFinerTime(0) , setTableTime(0) {;} + std::string toString( void ) const + { + std::stringstream stream; + stream << "Corners / Vertices / Edges / Curve / Set Table / Copy Finer: "; + stream << std::fixed << std::setprecision(1) << cornersTime << " / " << verticesTime << " / " << edgesTime << " / " << curveTime << " / " << setTableTime << " / " << copyFinerTime; + stream << " (s)"; + return stream.str(); + } + }; + + protected: + enum _SetFlag + { + CORNER_VALUES = 1, + ISO_VERTICES = 2, + ISO_EDGES = 4 + }; + public: + static int SetCornerValuesFlag( void ){ return _SetFlag::CORNER_VALUES; } + static int SetIsoVerticesFlag ( void ){ return _SetFlag::CORNER_VALUES | _SetFlag::ISO_VERTICES; } + static int SetIsoEdgesFlag ( void ){ return _SetFlag::CORNER_VALUES | _SetFlag::ISO_VERTICES | _SetFlag::ISO_EDGES; } + + template< typename Data , typename SetVertexFunction , unsigned int ... FEMSigs , unsigned int WeightDegree , unsigned int DataSig > + static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , StreamingVertices< Vertex , node_index_type > *vertices , const Data &zeroData , const SetVertexFunction &SetVertex , bool nonLinearFit , bool gradientNormals , std::vector< SliceValues > &sliceValues , int setFlag ) + { + if( maxKeyDepth() ); + static const int FEMDegrees[] = { FEMSignature< FEMSigs >::Degree ... }; + for( int d=0 ; d(); + node_index_type vOffset = 0; + + typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator = NULL; + if( data ) pointEvaluator = new typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >( tree._maxDepth ); + DenseNodeData< Real , UIntPack< FEMSigs ... > > coarseCoefficients( tree._sNodesEnd( tree._maxDepth-1 ) ); + memset( coarseCoefficients() , 0 , sizeof(Real)*tree._sNodesEnd( tree._maxDepth-1 ) ); + ThreadPool::Parallel_for( tree._sNodesBegin(0) , tree._sNodesEnd( tree._maxDepth-1 ) , [&]( unsigned int, size_t i ){ coarseCoefficients[i] = coefficients[i]; } ); + typename FEMIntegrator::template RestrictionProlongation< UIntPack< FEMSigs ... > > rp; + for( LocalDepth d=1 ; d() , rp , d , ( ConstPointer(Real) )coarseCoefficients()+tree._sNodesBegin(d-1) , coarseCoefficients()+tree._sNodesBegin(d) ); + + std::vector< _Evaluator< UIntPack< FEMSigs ... > , 1 > > evaluators( tree._maxDepth+1 ); + for( LocalDepth d=0 ; d<=tree._maxDepth ; d++ ) evaluators[d].set( tree._maxDepth ); + + sliceValues.resize( tree._maxDepth+1 ); + std::vector< typename SliceValues::Scratch > scratchValues( tree._maxDepth+1 ); + + // Initialize the slice + for( LocalDepth d=tree._maxDepth ; d>=fullDepth ; d-- ) + { + double t = Time(); + sliceValues[d].cellIndices.set( tree._sNodes , tree._localToGlobal( d ) ); + stats.setTableTime += Time()-t; + sliceValues[d].reset( nonLinearFit || gradientNormals ); + scratchValues[d].reset( sliceValues[d].cellIndices ); + } + + for( LocalDepth d=tree._maxDepth; d>=fullDepth ; d-- ) + { + // Copy edges from finer + if( setFlag & _SetFlag::ISO_EDGES ) + { + double t = Time(); + if( d( tree , coefficients() , coarseCoefficients() , isoValue , d , fullDepth , sliceValues , scratchValues , evaluators[d] ); + stats.cornersTime += Time()-t; + } + + if( setFlag & _SetFlag::ISO_VERTICES ) + { + double t = Time(); + SetIsoVertices< WeightDegree , Data , DataSig >( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , d , fullDepth , vOffset , vertices , sliceValues , scratchValues , zeroData , SetVertex ); + stats.verticesTime += Time()-t; + } + + if( setFlag & _SetFlag::ISO_EDGES ) + { + double t = Time(); + SetIsoEdges( keyGenerator , tree , d , fullDepth , sliceValues , scratchValues ); + stats.edgesTime += Time()-t , t = Time(); + } + } + + for( LocalDepth d=tree._maxDepth ; d>=fullDepth ; d-- ) + { + ThreadPool::ParallelSections + ( + [ &sliceValues , &scratchValues , d ]( void ){ sliceValues[d].setFromScratch( scratchValues[d].vKeyValues ); } , + [ &sliceValues , &scratchValues , d ]( void ){ sliceValues[d].setFromScratch( scratchValues[d].eKeyValues ); } , + [ &sliceValues , &scratchValues , d ]( void ){ sliceValues[d].setFromScratch( scratchValues[d].fKeyValues ); } + ); + if( ( setFlag & _SetFlag::ISO_VERTICES) && dfirst ] = iter->second; + } + + size_t badRootCount = _BadRootCount; + if( badRootCount!=0 ) WARN( "bad average roots: " , badRootCount ); + return stats; + } + + static void SetLevelSets( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , LocalDepth fullDepth , const std::vector< SliceValues > &sliceValues , StreamingCurve< Vertex , node_index_type >& curve , bool flipOrientation ) + { + for( LocalDepth d=tree._maxDepth ; d>=fullDepth ; d-- ) SetLevelSet( keyGenerator , tree , d , sliceValues[d] , curve , flipOrientation ); + } + + template< typename Data , typename SetVertexFunction , unsigned int ... FEMSigs , unsigned int WeightDegree , unsigned int DataSig > + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , StreamingCurve< Vertex , node_index_type > &curve , const Data &zeroData , const SetVertexFunction &SetVertex , bool nonLinearFit , bool gradientNormals , bool flipOrientation ) + { + std::vector< SliceValues > sliceValues; + Stats stats = SetSliceValues< Data >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , tree.maxDepth() , densityWeights , data , coefficients , isoValue , &curve , zeroData , SetVertex , nonLinearFit , gradientNormals , sliceValues ); + LevelSetExtraction::KeyGenerator< Dim > keyGenerator( tree.maxDepth() ); + { + double t = Time(); + SetLevelSets( keyGenerator , tree , tree.getFullDepth( UIntPack< FEMSignature< FEMSigs >::Degree ... >() ) , sliceValues , curve , flipOrientation ); + stats.curveTime += Time()-t; + } + return stats; + } +}; + +template< class Real , typename Vertex > std::mutex LevelSetExtractor< 2 , Real , Vertex >::_pointInsertionMutex; +template< class Real , typename Vertex > std::atomic< size_t > LevelSetExtractor< 2 , Real , Vertex >::_BadRootCount; + +#endif // FEM_TREE_LEVEL_SET_2D_INL_INCLUDED \ No newline at end of file diff --git a/Src/FEMTree.LevelSet.3D.inl b/Src/FEMTree.LevelSet.3D.inl new file mode 100644 index 00000000..9b08d84f --- /dev/null +++ b/Src/FEMTree.LevelSet.3D.inl @@ -0,0 +1,2221 @@ +/* +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 +#include "MyMiscellany.h" +#include "MarchingCubes.h" +#include "MAT.h" +#include "FEMTree.LevelSet.inl" +#include "FEMTree.LevelSet.2D.inl" + + +// Specialized level-set surface extraction +template< class Real , class Vertex > +struct LevelSetExtractor< 3 , Real , Vertex > +{ +protected: + static std::mutex _pointInsertionMutex; + static std::atomic< size_t > _BadRootCount; + +public: + static const unsigned int Dim = 3; + typedef typename FEMTree< Dim , Real >::LocalDepth LocalDepth; + typedef typename FEMTree< Dim , Real >::LocalOffset LocalOffset; + typedef typename FEMTree< Dim , Real >::ConstOneRingNeighborKey ConstOneRingNeighborKey; + typedef typename FEMTree< Dim , Real >::ConstOneRingNeighbors ConstOneRingNeighbors; + typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > TreeNode; + template< unsigned int WeightDegree > using DensityEstimator = typename FEMTree< Dim , Real >::template DensityEstimator< WeightDegree >; + template< typename FEMSigPack , unsigned int PointD > using _Evaluator = typename FEMTree< Dim , Real >::template _Evaluator< FEMSigPack , PointD >; + + using Key = LevelSetExtraction::Key< Dim >; + using IsoEdge = LevelSetExtraction::IsoEdge< Dim >; + template< unsigned int D , unsigned int ... Ks > + using HyperCubeTables = LevelSetExtraction::HyperCubeTables< D , Ks ... >; + + //////////////// + // FaceEdges // + //////////////// + struct FaceEdges + { + IsoEdge edges[2]; + int count; + FaceEdges( void ) : count(-1){} + }; + + /////////////// + // SliceData // + /////////////// + class SliceData + { + public: + template< unsigned int Indices > + struct _Indices + { + node_index_type idx[Indices]; + _Indices( void ){ for( unsigned int i=0 ; i::template ElementNum< 0 >() >; + // The four edge indices associated with a square face + using SquareEdgeIndices = _Indices< HyperCube::Cube< Dim-1 >::template ElementNum< 1 >() >; + // The one face index associated with a square face + using SquareFaceIndices = _Indices< HyperCube::Cube< Dim-1 >::template ElementNum< 2 >() >; + }; + + ///////////////// + // SliceValues // + ///////////////// + struct SliceValues + { + struct Scratch + { + using FKeyValues = std::vector< std::vector< std::pair< Key , std::vector< IsoEdge > > > >; + using EKeyValues = std::vector< std::vector< std::pair< Key , std::pair< node_index_type , Vertex > > > >; + using VKeyValues = std::vector< std::vector< std::pair< Key , Key > > >; + + FKeyValues fKeyValues; + EKeyValues eKeyValues; + VKeyValues vKeyValues; + + Pointer( char ) cSet; + Pointer( char ) eSet; + Pointer( char ) fSet; + + Scratch( void ) + { + vKeyValues.resize( ThreadPool::NumThreads() ); + eKeyValues.resize( ThreadPool::NumThreads() ); + fKeyValues.resize( ThreadPool::NumThreads() ); + cSet = NullPointer( char ); + eSet = NullPointer( char ); + fSet = NullPointer( char ); + } + + ~Scratch( void ) + { + FreePointer( cSet ); + FreePointer( eSet ); + FreePointer( fSet ); + } + + void reset( const LevelSetExtraction::SliceCellIndexData< Dim > &cellIndices ) + { + for( size_t i=0 ; i( cellIndices.counts[0] ); + memset( cSet , 0 , sizeof( char ) * cellIndices.counts[0] ); + } + if( cellIndices.counts[1] ) + { + eSet = AllocPointer< char >( cellIndices.counts[1] ); + memset( eSet , 0 , sizeof( char ) * cellIndices.counts[1] ); + } + if( cellIndices.counts[2] ) + { + fSet = AllocPointer< char >( cellIndices.counts[2] ); + memset( fSet , 0 , sizeof( char ) * cellIndices.counts[2] ); + } + } + }; + + LevelSetExtraction::SliceCellIndexData< Dim > cellIndices; + Pointer( Real ) cornerValues ; Pointer( Point< Real , Dim > ) cornerGradients; + Pointer( Key ) edgeKeys; + Pointer( FaceEdges ) faceEdges; + Pointer( char ) mcIndices; + LevelSetExtraction::KeyMap< Dim , std::vector< IsoEdge > > faceEdgeMap; + LevelSetExtraction::KeyMap< Dim , std::pair< node_index_type , Vertex > > edgeVertexMap; + LevelSetExtraction::KeyMap< Dim , Key > vertexPairMap; + + SliceValues( void ) + { + _slice = -1; + _oldCCount = _oldECount = _oldFCount = 0; + _oldNCount = 0; + cornerValues = NullPointer( Real ) ; cornerGradients = NullPointer( Point< Real , Dim > ); + edgeKeys = NullPointer( Key ); + faceEdges = NullPointer( FaceEdges ); + mcIndices = NullPointer( char ); + } + ~SliceValues( void ) + { + _oldCCount = _oldECount = _oldFCount = 0; + _oldNCount = 0; + FreePointer( cornerValues ) ; FreePointer( cornerGradients ); + DeletePointer( edgeKeys ); + DeletePointer( faceEdges ); + FreePointer( mcIndices ); + } + + void setFromScratch( typename Scratch::VKeyValues &scratch ) + { + for( unsigned int t=0 ; t &faceEdges = faceEdgeMap[ scratch[t][i].first ]; + faceEdges.insert( faceEdges.end() , scratch[t][i].second.begin() , scratch[t][i].second.end() ); + } + scratch[t].clear(); + } + } + + unsigned int slice( void ) const { return _slice; } + void reset( unsigned int slice , bool computeGradients ) + { + _slice = slice; + faceEdgeMap.clear() , edgeVertexMap.clear() , vertexPairMap.clear(); + + if( _oldNCount<(node_index_type)cellIndices.size() ) + { + _oldNCount = (node_index_type)cellIndices.size(); + FreePointer( mcIndices ); + if( _oldNCount>0 ) mcIndices = AllocPointer< char >( _oldNCount ); + } + if( _oldCCount<(node_index_type)cellIndices.counts[0] ) + { + _oldCCount = (node_index_type)cellIndices.counts[0]; + FreePointer( cornerValues ) ; FreePointer( cornerGradients ); + if( cellIndices.counts[0]>0 ) + { + cornerValues = AllocPointer< Real >( _oldCCount ); + if( computeGradients ) cornerGradients = AllocPointer< Point< Real , Dim > >( _oldCCount ); + } + } + if( _oldECount<(node_index_type)cellIndices.counts[1] ) + { + _oldECount = (node_index_type)cellIndices.counts[1]; + DeletePointer( edgeKeys ); + edgeKeys = NewPointer< Key >( _oldECount ); + } + if( _oldFCount<(node_index_type)cellIndices.counts[2] ) + { + _oldFCount = (node_index_type)cellIndices.counts[2]; + DeletePointer( faceEdges ); + faceEdges = NewPointer< FaceEdges >( _oldFCount ); + } + } + + template< typename FaceIndexFunctor /* = std::function< LevelSetExtraction::Key< Dim > ( const TreeNode * , typename HyperCube::Cube< Dim >::template Element< 2 > ) */ > + void addIsoEdges( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , FaceIndexFunctor &faceIndexFunctor , const FEMTree< Dim , Real > &tree , const Scratch &scratch , const TreeNode *leaf , unsigned int sliceIndex , std::vector< IsoEdge > &edges , bool isOriented ) const + { + auto _FaceIndex = [&]( const TreeNode *node ) + { + int depth , offset[Dim]; + tree.depthAndOffset( node , depth , offset ); + typename HyperCube::Cube< Dim >::template Element< 2 > f; + if ( offset[Dim-1]+0==sliceIndex ) f = typename HyperCube::Cube< Dim >::template Element< 2 >( HyperCube::BACK , 0 ); + else if( offset[Dim-1]+1==sliceIndex ) f = typename HyperCube::Cube< Dim >::template Element< 2 >( HyperCube::FRONT , 0 ); + else ERROR_OUT( "Node/slice-index mismatch: " , offset[Dim-1] , " <-> " , sliceIndex ); + return faceIndexFunctor( node , f ); + }; + + int flip = isOriented ? 0 : 1; + + node_index_type fIdx = cellIndices.template indices<2>(leaf->nodeData.nodeIndex)[0]; + if( scratch.fSet[fIdx] ) + { + const FaceEdges &fe = faceEdges[ fIdx ]; + for( int i=0 ; i >::const_iterator iter = faceEdgeMap.find( key ); + if( iter!=faceEdgeMap.end() ) + { + const std::vector< IsoEdge >& _edges = iter->second; + for( size_t i=0 ; i<_edges.size() ; i++ ) edges.push_back( IsoEdge( _edges[i][flip] , _edges[i][1-flip] ) ); + } + else + { + LocalDepth d ; LocalOffset off; + tree.depthAndOffset( leaf , d , off ); + // [WARNING] Is this right? If the face isn't set, wouldn't it inherit? + WARN( "Invalid face: [" , off[0] , " " , off[1] , " " , off[2] , " @ " , d , " | " , sliceIndex , " : " , leaf->nodeData.nodeIndex , " ( " , keyGenerator.to_string(key) , " | " , key.to_string() , " )" ); + } + } + } + + bool setVertexPair( Key current , Key &pair ) const + { + typename LevelSetExtraction::KeyMap< Dim , Key >::const_iterator iter; + + if( (iter=vertexPairMap.find(current))!=vertexPairMap.end() ) + { + pair = iter->second; + return true; + } + else return false; + } + + bool setEdgeVertex( Key key , std::pair< node_index_type , Vertex > &edgeVertex ) const + { + typename LevelSetExtraction::KeyMap< Dim , std::pair< node_index_type , Vertex > >::const_iterator iter; + if( ( iter=edgeVertexMap.find( key ) )!=edgeVertexMap.end() ) + { + edgeVertex = iter->second; + return true; + } + else return false; + } + protected: + node_index_type _oldCCount , _oldECount , _oldFCount; + node_index_type _oldNCount; + unsigned int _slice; + }; + + ////////////////// + // XSliceValues // + ////////////////// + struct XSliceValues + { + struct Scratch + { + using FKeyValues = std::vector< std::vector< std::pair< Key , std::vector< IsoEdge > > > >; + using EKeyValues = std::vector< std::vector< std::pair< Key , std::pair< node_index_type , Vertex > > > >; + using VKeyValues = std::vector< std::vector< std::pair< Key , Key > > >; + + FKeyValues fKeyValues; + EKeyValues eKeyValues; + VKeyValues vKeyValues; + + Pointer( char ) eSet; + Pointer( char ) fSet; + + Scratch( void ) + { + vKeyValues.resize( ThreadPool::NumThreads() ); + eKeyValues.resize( ThreadPool::NumThreads() ); + fKeyValues.resize( ThreadPool::NumThreads() ); + eSet = NullPointer( char ); + fSet = NullPointer( char ); + } + + ~Scratch( void ) + { + FreePointer( eSet ); + FreePointer( fSet ); + } + + void reset( const LevelSetExtraction::SlabCellIndexData< Dim > &cellIndices ) + { + for( size_t i=0 ; i( cellIndices.counts[0] ); + memset( eSet , 0 , sizeof( char ) * cellIndices.counts[0] ); + } + if( cellIndices.counts[1] ) + { + fSet = AllocPointer< char >( cellIndices.counts[1] ); + memset( fSet , 0 , sizeof( char ) * cellIndices.counts[1] ); + } + } + }; + + LevelSetExtraction::SlabCellIndexData< Dim > cellIndices; + Pointer( Key ) edgeKeys; + Pointer( FaceEdges ) faceEdges; + LevelSetExtraction::KeyMap< Dim , std::vector< IsoEdge > > faceEdgeMap; + LevelSetExtraction::KeyMap< Dim , std::pair< node_index_type , Vertex > > edgeVertexMap; + LevelSetExtraction::KeyMap< Dim , Key > vertexPairMap; + + XSliceValues( void ) + { + _slab = -1; + _oldECount = _oldFCount = 0; + edgeKeys = NullPointer( Key ); + faceEdges = NullPointer( FaceEdges ); + } + + ~XSliceValues( void ) + { + _oldECount = _oldFCount = 0; + DeletePointer( edgeKeys ); + DeletePointer( faceEdges ); + } + + void setFromScratch( typename Scratch::VKeyValues &scratch ) + { + for( unsigned int t=0 ; tsecond.push_back( scratch[t][i].second[j] ); + } + scratch[t].clear(); + } + } + + unsigned int slab( void ) const { return _slab; } + void reset( unsigned int slab ) + { + _slab = slab; + faceEdgeMap.clear() , edgeVertexMap.clear() , vertexPairMap.clear(); + + if( _oldECount<(node_index_type)cellIndices.counts[0] ) + { + _oldECount = (node_index_type)cellIndices.counts[0]; + DeletePointer( edgeKeys ); + edgeKeys = NewPointer< Key >( _oldECount ); + } + if( _oldFCount<(node_index_type)cellIndices.counts[1] ) + { + _oldFCount = (node_index_type)cellIndices.counts[1]; + DeletePointer( faceEdges ); + faceEdges = NewPointer< FaceEdges >( _oldFCount ); + } + } + + protected: + node_index_type _oldECount , _oldFCount; + unsigned int _slab; + }; + + //////////////// + // SlabValues // + //////////////// + struct SlabValues + { + protected: + XSliceValues _xSliceValues[2]; + SliceValues _sliceValues[2]; + typename SliceValues::Scratch _sliceScratch[2]; + typename XSliceValues::Scratch _xSliceScratch[2]; + public: + SliceValues& sliceValues( int idx ){ return _sliceValues[idx&1]; } + const SliceValues& sliceValues( int idx ) const { return _sliceValues[idx&1]; } + XSliceValues& xSliceValues( int idx ){ return _xSliceValues[idx&1]; } + const XSliceValues& xSliceValues( int idx ) const { return _xSliceValues[idx&1]; } + typename SliceValues::Scratch &sliceScratch ( int idx ) { return _sliceScratch[idx&1]; } + const typename SliceValues::Scratch &sliceScratch ( int idx ) const { return _sliceScratch[idx&1]; } + typename XSliceValues::Scratch &xSliceScratch( int idx ) { return _xSliceScratch[idx&1]; } + const typename XSliceValues::Scratch &xSliceScratch( int idx ) const { return _xSliceScratch[idx&1]; } + + bool validSlice( int slice ) const { return _sliceValues[slice&1].slice()==slice; } + bool validXSlice( int slab ) const { return _xSliceValues[slab&1].slab()==slab; } + }; + + static std::vector< std::pair< node_index_type , node_index_type > > SetIncidence( const FEMTree< Dim , Real > &tree , const FEMTree< Dim-1 , Real > &sliceTree , LocalDepth fullDepth , unsigned int sliceAtMaxDepth , unsigned int maxDepth ) + { + using SliceTreeNode = typename LevelSetExtractor< Dim-1 , Real , Point< Real , Dim-1 > >::TreeNode; + using SliceLocalDepth = typename FEMTree< Dim-1 , Real >::LocalDepth; + using SliceLocalOffset = typename FEMTree< Dim-1 , Real >::LocalOffset; + + std::vector< std::pair< node_index_type , node_index_type > > incidence( sliceTree.nodesSize() , std::pair< node_index_type , node_index_type >( -1 , -1 ) ); + + // Recursively set the incidence + std::function< void ( const TreeNode * , const SliceTreeNode * ) > SetIncidenceFunctor = [&]( const TreeNode *node , const SliceTreeNode *sliceNode ) + { + LocalDepth depth ; LocalOffset offset; + SliceLocalDepth sliceDepth ; SliceLocalOffset sliceOffset; + tree.depthAndOffset( node , depth , offset ); + sliceTree.depthAndOffset( sliceNode , sliceDepth , sliceOffset ); + if( depth!=sliceDepth ) ERROR_OUT( "Depths do not match: " , depth , " != " , sliceDepth ); + for( unsigned int i=0 ; iendAtMaxDepth ) ERROR_OUT( "Bad slice: " , sliceAtMaxDepth , " in [ " , beginAtMaxDepth , " , " , endAtMaxDepth , " ]" ); + if( depth>=fullDepth ) + { + // Set the incidence + if ( sliceAtMaxDepth==beginAtMaxDepth ) incidence[ sliceNode->nodeData.nodeIndex ].second = node->nodeData.nodeIndex; + else if( sliceAtMaxDepth==endAtMaxDepth ) incidence[ sliceNode->nodeData.nodeIndex ].first = node->nodeData.nodeIndex; + else + { + incidence[ sliceNode->nodeData.nodeIndex ].second = node->nodeData.nodeIndex; + incidence[ sliceNode->nodeData.nodeIndex ].first = node->nodeData.nodeIndex; + } + } + + if( !GetGhostFlag( node->children ) ) + { + if( !sliceNode->children ) + { + int d , off[Dim] , _d , _off[Dim-1]; + Point< int , Dim > p; + Point< int , Dim-1 > _p; + for( unsigned int d=0 ; d " , _p , " @ " , _d , " : ", node->nodeData.nodeIndex , " <-> " , sliceNode->nodeData.nodeIndex ); + } + if( sliceAtMaxDepth<=midAtMaxDepth ) for( int c=0 ; c<(1<<(Dim-1)) ; c++ ) SetIncidenceFunctor( node->children+(c ) , sliceNode->children + c ); + if( sliceAtMaxDepth>=midAtMaxDepth ) for( int c=0 ; c<(1<<(Dim-1)) ; c++ ) SetIncidenceFunctor( node->children+(c|(1<<(Dim-1))) , sliceNode->children + c ); + } + }; + SetIncidenceFunctor( &tree.spaceRoot() , &sliceTree.spaceRoot() ); + return incidence; + } + + template< unsigned int WeightDegree , typename Data , unsigned int DataSig , typename SliceFunctor /* = std::function< SliceValues & ( unsigned int ) > */ , typename ScratchFunctor /* = std::function< typename SliceValues::Scratch & ( unsigned int ) */ > + static void CopyIsoStructure + ( + const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , + const typename LevelSetExtractor< Dim-1 , Real , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions &boundaryInfo , + const FEMTree< Dim , Real > &tree , + LocalDepth fullDepth , + unsigned int sliceAtMaxDepth , + unsigned int maxDepth , + SliceFunctor sliceFunctor , + ScratchFunctor scratchFunctor , + const std::vector< std::pair< node_index_type , node_index_type > > &incidence , + StreamingVertices< Vertex , node_index_type >& vertexStream , + bool gradientNormals , + typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , + const DensityEstimator< WeightDegree >* densityWeights , + const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , + node_index_type& vOffset , + const Data &zeroData , + std::function< void ( Vertex& , Point< Real , Dim > , Point< Real , Dim > , Real , Data ) > SetVertex + ) + { + using SliceTreeNode = typename LevelSetExtractor< Dim-1 , Real , Point< Real , Dim-1 > >::TreeNode; + using SliceSliceValues = typename LevelSetExtractor< Dim-1 , Real , Point< Real , Dim-1 > >::SliceValues; + using SliceKey = LevelSetExtraction::Key< Dim-1 >; + using SliceIsoEdge = LevelSetExtraction::IsoEdge< Dim-1 >; + + auto PromoteIsoVertex = [&]( SliceKey key ) + { + return keyGenerator( maxDepth , sliceAtMaxDepth , key ); + }; + + auto PromoteIsoEdge = [&]( SliceIsoEdge edge ) + { + IsoEdge pEdge; + for( unsigned int i=0 ; i<2 ; i++ ) pEdge[i] = keyGenerator( maxDepth , sliceAtMaxDepth , edge[i] ); + return pEdge; + }; + + std::vector< node_index_type > vertexIndices( boundaryInfo.vertexPositions.size() ); + std::vector< Vertex > vertices( boundaryInfo.vertexPositions.size() ); + // Add the iso-vertices + { + static const unsigned int DataDegree = FEMSignature< DataSig >::Degree; + + // A functor returning the finest leaf node containing the iso-vertex + std::function< const TreeNode * ( const TreeNode * , Key ) > FinestLeaf = [&]( const TreeNode *node , Key key ) + { + const TreeNode *candidate = node; + if( node->children ) + { + LocalDepth depth ; LocalOffset offset; + int start[Dim] , mid[Dim] , end[Dim]; + tree.depthAndOffset( node , depth , offset ); + for( unsigned int d=0 ; d>1; + } + for( unsigned int c=0 ; c<(1<=mid [d] && (int)key[d]<=end[d]); + else containsKey &= ((int)key[d]>=start[d] && (int)key[d]<=mid[d]); + if( containsKey ) + { + const TreeNode *_candidate = FinestLeaf( node->children+c , key ); + if( tree.depth(_candidate)>tree.depth(candidate) ) candidate = _candidate; + } + } + } + return candidate; + }; + + std::vector< Key > keys; + { + std::vector< LevelSetExtraction::Key< Dim-1 > > _keys = boundaryInfo.vertexKeys(); + keys.resize( _keys.size() ); + for( unsigned int i=0 ; i<_keys.size() ; i++ ) keys[i] = PromoteIsoVertex( _keys[i] ); + } + + for( unsigned int i=0 ; i > weightKey; + ConstPointSupportKey< IsotropicUIntPack< Dim , DataDegree > > dataKey; + vertexIndices[i] = vOffset++; + Point< Real , Dim > p; + for( unsigned int d=0 ; ddepth() ); + weightKey.getNeighbors( node ); + Real weight; + tree._getSampleDepthAndWeight( *densityWeights , node , p , weightKey , depth , weight ); + } + if( data ) + { + dataKey.set( node->depth() ); + dataKey.getNeighbors( node ); + Point< Real , Dim > start; + Real width; + tree.startAndWidth( node , start , width ); + if( DataDegree==0 ) + { + Point< Real , Dim > center( start[0] + width/2 , start[1] + width/2 , start[2] + width/2 ); + ProjectiveData< Data , Real > pValue( zeroData ); + tree.template _addEvaluation< ProjectiveData< Data , Real > , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > , 0 >( *data , center , *pointEvaluator , dataKey , pValue ); + dataValue = pValue.weight ? pValue.value() : zeroData; + } + else + { + ProjectiveData< Data , Real > pValue( zeroData ); + tree.template _addEvaluation< ProjectiveData< Data , Real > , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > , 0 >( *data , p , *pointEvaluator , dataKey , pValue ); + dataValue = pValue.weight ? pValue.value() : zeroData; + } + } + SetVertex( vertices[i] , p , Point< Real , Dim >() , depth , dataValue ); + vertexStream.addVertex( vertices[i] ); + } + } + + // Copy over the edge/face -> key tables + for( unsigned int depth=fullDepth ; depth<=std::min< unsigned int >( tree._maxDepth , boundaryInfo.sliceTree.depth() ) ; depth++ ) + { + SliceValues &sValues = sliceFunctor( depth ); + typename SliceValues::Scratch &sScratch = scratchFunctor( depth ); + const SliceSliceValues &ssValues = boundaryInfo.sliceValues[depth]; + + auto CopyEdgeAndFaceInfo = [&]( node_index_type sliceIndex , node_index_type index ) + { + if( index==-1 ) return; + const TreeNode *node = tree._sNodes.treeNodes[ index ]; + const SliceTreeNode *sliceNode = boundaryInfo.sliceTree._sNodes.treeNodes[ sliceIndex ]; + + const typename LevelSetExtraction::SliceCellIndexData< Dim >::template CellIndices<1> &eIndices = sValues.cellIndices.template indices<1>( node ); + const typename LevelSetExtraction::FullCellIndexData< Dim-1 >::template CellIndices<1> &sliceEIndices = ssValues.cellIndices.template indices< 1 >( sliceNode ); + for( typename HyperCube::Cube< Dim-1 >::template Element< 1 > _e ; _e::template ElementNum< 1 >() ; _e++ ) + { + node_index_type eIndex = eIndices[_e.index]; + node_index_type sliceEIndex = sliceEIndices[_e.index]; + if( ssValues.edgeKeys[sliceEIndex].idx[0]!=-1 ) + { + sValues.edgeKeys[eIndex] = keyGenerator( maxDepth , sliceAtMaxDepth , ssValues.edgeKeys[sliceEIndex] ); + sScratch.eSet[eIndex] = 1; + } + else sScratch.eSet[eIndex] = 0; + } + + const typename LevelSetExtraction::SliceCellIndexData< Dim >::template CellIndices<2> &fIndices = sValues.cellIndices.template indices<2>( node ); + const typename LevelSetExtraction::FullCellIndexData< Dim-1 >::template CellIndices< 2 > &sliceFIndices = ssValues.cellIndices.template indices<2>( sliceNode ); + for( typename HyperCube::Cube< Dim-1 >::template Element< 2 > _f ; _f::template ElementNum< 2 >() ; _f++ ) + { + node_index_type fIndex = fIndices[_f.index]; + node_index_type sliceFIndex = sliceFIndices[_f.index]; + sValues.faceEdges[fIndex].count = ssValues.faceEdges[sliceFIndex].count; + for( int c=0 ; c( tree._maxDepth , boundaryInfo.sliceTree.depth() ) ; depth++ ) + { + SliceValues &sValues = sliceFunctor( depth ); + const SliceSliceValues &ssValues = boundaryInfo.sliceValues[depth]; + + // Copy the face->edge map + for( auto iter=ssValues.faceEdgeMap.cbegin() ; iter!=ssValues.faceEdgeMap.cend() ; iter++ ) + { + Key key = keyGenerator( maxDepth , sliceAtMaxDepth , iter->first ); + std::vector< IsoEdge > edges( iter->second.size() ); + for( unsigned int i=0 ; isecond.size() ; i++ ) edges[i] = PromoteIsoEdge( iter->second[i] ); + sValues.faceEdgeMap[key] = edges; + } + + // Copy the edge-vertex map + for( auto iter=ssValues.edgeVertexMap.cbegin() ; iter!=ssValues.edgeVertexMap.cend() ; iter++ ) + { + Key key = keyGenerator( maxDepth , sliceAtMaxDepth , iter->first ); + node_index_type idx = iter->second; + sValues.edgeVertexMap[key] = std::pair< node_index_type , Vertex >( vertexIndices[idx] , vertices[idx] ); + } + + // Copy the vertex-vertex map + for( auto iter=ssValues.vertexPairMap.cbegin() ; iter!=ssValues.vertexPairMap.cend() ; iter++ ) + { + Key key = keyGenerator( maxDepth , sliceAtMaxDepth , iter->first ); + sValues.vertexPairMap[key] = keyGenerator( maxDepth , sliceAtMaxDepth , iter->second ); + } + } + } + + static void OverwriteCornerValues( const typename LevelSetExtractor< Dim-1 , Real , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions &boundaryInfo , const std::vector< Real > &dValues , const FEMTree< Dim , Real > &tree , LocalDepth depth , unsigned int sliceAtMaxDepth , unsigned int maxDepth , bool isBack , std::vector< SlabValues > &slabValues , const std::vector< std::pair< node_index_type , node_index_type > > &incidence ) + { + using SliceTreeNode = typename LevelSetExtractor< Dim-1 , Real , Point< Real , Dim-1 > >::TreeNode; + using SliceSliceValues = typename LevelSetExtractor< Dim-1 , Real , Point< Real , Dim-1 > >::SliceValues; + + unsigned int slice = sliceAtMaxDepth>>( maxDepth - depth ); + if( !isBack && sliceAtMaxDepth!=( slice<<(maxDepth-depth ) ) ) slice++; + if( !slabValues[depth].validSlice( slice ) ) ERROR_OUT( "Invalid slice: " , slice , " @ " , depth , " : " , slabValues[depth].sliceValues(slice).slice() ); + SliceValues &sValues = slabValues[depth].sliceValues( slice ); + const SliceSliceValues &ssValues = boundaryInfo.sliceValues[depth]; + + if( sValues.cornerGradients && !ssValues.cornerGradients ) ERROR_OUT( "Epxected slice gradients" ); + + auto CopyCornerInfo = [&]( node_index_type sliceIndex , node_index_type index ) + { + + if( index==-1 ) return; + const TreeNode *node = tree._sNodes.treeNodes[ index ]; + const SliceTreeNode *sliceNode = boundaryInfo.sliceTree._sNodes.treeNodes[ sliceIndex ]; + + const typename LevelSetExtraction::SliceCellIndexData< Dim >::template CellIndices< 0 > &cIndices = sValues.cellIndices.template indices<0>( node ); + const typename LevelSetExtraction::FullCellIndexData< Dim-1 >::template CellIndices< 0 > &sliceCIndices = ssValues.cellIndices.template indices< 0 >( sliceNode ); + for( typename HyperCube::Cube< Dim-1 >::template Element< 0 > _c ; _c::template ElementNum< 0 >() ; _c++ ) + { + node_index_type vIndex = cIndices[_c.index]; + node_index_type sliceVIndex = sliceCIndices[_c.index]; + sValues.cornerValues[vIndex] = ssValues.cornerValues[sliceVIndex]; + if( sValues.cornerGradients ) + { + for( unsigned int i=0 ; i + static void SetSliceCornerValuesAndMCIndices( const FEMTree< Dim , Real >& tree , ConstPointer( Real ) coefficients , ConstPointer( Real ) coarseCoefficients , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slice , std::vector< SlabValues >& slabValues , const _Evaluator< UIntPack< FEMSigs ... > , 1 >& evaluator ) + { + if( slice>0 ) SetSliceCornerValuesAndMCIndices< FEMSigs ... >( tree , coefficients , coarseCoefficients , isoValue , depth , fullDepth , slice , HyperCube::FRONT , slabValues , evaluator ); + if( slice<(1<( tree , coefficients , coarseCoefficients , isoValue , depth , fullDepth , slice , HyperCube::BACK , slabValues , evaluator ); + } + + template< unsigned int ... FEMSigs > + static void SetSliceCornerValuesAndMCIndices( const FEMTree< Dim , Real >& tree , ConstPointer( Real ) coefficients , ConstPointer( Real ) coarseCoefficients , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slice , HyperCube::Direction zDir , std::vector< SlabValues >& slabValues , const _Evaluator< UIntPack< FEMSigs ... > , 1 >& evaluator ) + { + static const unsigned int FEMDegrees[] = { FEMSignature< FEMSigs >::Degree ... }; + SliceValues& sValues = slabValues[depth].sliceValues( slice ); + typename SliceValues::Scratch &sScratch = slabValues[depth].sliceScratch( slice ); + bool useBoundaryEvaluation = false; + for( int d=0 ; d::Degree ... > > > neighborKeys( ThreadPool::NumThreads() ); + std::vector< ConstCornerSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > > > bNeighborKeys( ThreadPool::NumThreads() ); + if( useBoundaryEvaluation ) for( size_t i=0 ; i::template ElementNum< 0 >() ]; + ConstPointSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& neighborKey = neighborKeys[ thread ]; + ConstCornerSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bNeighborKey = bNeighborKeys[ thread ]; + TreeNode* leaf = tree._sNodes.treeNodes[i]; + if( !IsActiveNode< Dim >( leaf->children ) ) + { + const typename LevelSetExtraction::SliceCellIndexData< Dim >::template CellIndices<0> &cIndices = sValues.cellIndices.template indices<0>( leaf ); + + bool isInterior = tree._isInteriorlySupported( UIntPack< FEMSignature< FEMSigs >::Degree ... >() , leaf->parent ); + if( useBoundaryEvaluation ) bNeighborKey.getNeighbors( leaf ); + else neighborKey.getNeighbors( leaf ); + + for( typename HyperCube::Cube< Dim-1 >::template Element< 0 > _c ; _c::template ElementNum< 0 >() ; _c++ ) + { + typename HyperCube::Cube< Dim >::template Element< 0 > c( zDir , _c.index ); + node_index_type vIndex = cIndices[_c.index]; + if( !sScratch.cSet[vIndex] ) + { + if( sValues.cornerGradients ) + { + CumulativeDerivativeValues< Real , Dim , 1 > p; + if( useBoundaryEvaluation ) p = tree.template _getCornerValues< Real , 1 >( bNeighborKey , leaf , c.index , coefficients , coarseCoefficients , evaluator , tree._maxDepth , isInterior ); + else p = tree.template _getCornerValues< Real , 1 >( neighborKey , leaf , c.index , coefficients , coarseCoefficients , evaluator , tree._maxDepth , isInterior ); + sValues.cornerValues[vIndex] = p[0] , sValues.cornerGradients[vIndex] = Point< Real , Dim >( p[1] , p[2] , p[3] ); + } + else + { + if( useBoundaryEvaluation ) sValues.cornerValues[vIndex] = tree.template _getCornerValues< Real , 0 >( bNeighborKey , leaf , c.index , coefficients , coarseCoefficients , evaluator , tree._maxDepth , isInterior )[0]; + else sValues.cornerValues[vIndex] = tree.template _getCornerValues< Real , 0 >( neighborKey , leaf , c.index , coefficients , coarseCoefficients , evaluator , tree._maxDepth , isInterior )[0]; + } + sScratch.cSet[vIndex] = 1; + } + squareValues[_c.index] = sValues.cornerValues[ vIndex ]; + TreeNode* node = leaf; + LocalDepth _depth = depth; + int _slice = slice; + while( _depth>fullDepth && tree._isValidSpaceNode( node->parent ) && (node-node->parent->children)==c.index ) + { + node = node->parent , _depth-- , _slice >>= 1; + SliceValues &_sValues = slabValues[_depth].sliceValues( _slice ); + typename SliceValues::Scratch &_sScratch = slabValues[_depth].sliceScratch( _slice ); + const typename LevelSetExtraction::SliceCellIndexData< Dim >::template CellIndices<0> &_cIndices = _sValues.cellIndices.template indices<0>( node ); + node_index_type _vIndex = _cIndices[_c.index]; + _sValues.cornerValues[_vIndex] = sValues.cornerValues[vIndex]; + if( _sValues.cornerGradients ) _sValues.cornerGradients[_vIndex] = sValues.cornerGradients[vIndex]; + _sScratch.cSet[_vIndex] = 1; + } + } + sValues.mcIndices[ i - sValues.cellIndices.nodeOffset ] = HyperCube::Cube< Dim-1 >::MCIndex( squareValues , isoValue ); + } + } + } + ); + } + + static void SetMCIndices( const FEMTree< Dim , Real >& tree , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slice , std::vector< SlabValues >& slabValues ) + { + if( slice>0 ) SetMCIndices( tree , isoValue , depth , fullDepth , slice , HyperCube::FRONT , slabValues ); + if( slice<(1<& tree , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slice , HyperCube::Direction zDir , std::vector< SlabValues >& slabValues ) + { + SliceValues& sValues = slabValues[depth].sliceValues( slice ); + bool useBoundaryEvaluation = false; + ThreadPool::Parallel_for( tree._sNodesBegin(depth,slice-(zDir==HyperCube::BACK ? 0 : 1)) , tree._sNodesEnd(depth,slice-(zDir==HyperCube::BACK ? 0 : 1)) , [&]( unsigned int thread , size_t i ) + { + Real squareValues[ HyperCube::Cube< Dim-1 >::template ElementNum< 0 >() ]; + TreeNode* leaf = tree._sNodes.treeNodes[i]; + + if( tree._isValidSpaceNode( leaf ) && !IsActiveNode< Dim >( leaf->children ) ) + { + const typename LevelSetExtraction::SliceCellIndexData< Dim >::template CellIndices<0> &cIndices = sValues.cellIndices.template indices<0>( leaf ); + + for( typename HyperCube::Cube< Dim-1 >::template Element< 0 > _c ; _c::template ElementNum< 0 >() ; _c++ ) + { + typename HyperCube::Cube< Dim >::template Element< 0 > c( zDir , _c.index ); + node_index_type vIndex = cIndices[_c.index]; + squareValues[_c.index] = sValues.cornerValues[ vIndex ]; + sValues.mcIndices[ i - sValues.cellIndices.nodeOffset ] = HyperCube::Cube< Dim-1 >::MCIndex( squareValues , isoValue ); + } + } + } + ); + } + + template< unsigned int WeightDegree , typename Data , unsigned int DataSig > + static void SetSliceIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slice , node_index_type& vOffset , StreamingVertices< Vertex , node_index_type >& vertices , std::vector< SlabValues >& slabValues , const Data &zeroData , std::function< void ( Vertex& , Point< Real , Dim > , Point< Real , Dim > , Real , Data ) > SetVertex ) + { + if( slice>0 ) SetSliceIsoVertices< WeightDegree , Data , DataSig >( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , depth , fullDepth , slice , HyperCube::FRONT , vOffset , vertices , slabValues , zeroData , SetVertex ); + if( slice<(1<( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , depth , fullDepth , slice , HyperCube::BACK , vOffset , vertices , slabValues , zeroData , SetVertex ); + } + + template< unsigned int WeightDegree , typename Data , unsigned int DataSig > + static void SetSliceIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slice , HyperCube::Direction zDir , node_index_type& vOffset , StreamingVertices< Vertex , node_index_type >& vertices , std::vector< SlabValues >& slabValues , const Data &zeroData , std::function< void ( Vertex& , Point< Real , Dim > , Point< Real , Dim > , Real , Data ) > SetVertex ) + { + auto _EdgeIndex = [&]( const TreeNode *node , typename HyperCube::Cube< Dim >::template Element< 1 > e ) + { + int depth , offset[Dim]; + tree.depthAndOffset( node , depth , offset ); + return keyGenerator( depth , offset , e ); + }; + + static const unsigned int DataDegree = FEMSignature< DataSig >::Degree; + SliceValues &sValues = slabValues[depth].sliceValues( slice ); + typename SliceValues::Scratch &sScratch = slabValues[depth].sliceScratch( slice ); + // [WARNING] In the case Degree=2, these two keys are the same, so we don't have to maintain them separately. + std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); + std::vector< ConstPointSupportKey< IsotropicUIntPack< Dim , WeightDegree > > > weightKeys( ThreadPool::NumThreads() ); + std::vector< ConstPointSupportKey< IsotropicUIntPack< Dim , DataDegree > > > dataKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i >& weightKey = weightKeys[ thread ]; + ConstPointSupportKey< IsotropicUIntPack< Dim , DataDegree > >& dataKey = dataKeys[ thread ]; + TreeNode* leaf = tree._sNodes.treeNodes[i]; + if( !IsActiveNode< Dim >( leaf->children ) ) + { + node_index_type idx = (node_index_type)i - sValues.cellIndices.nodeOffset; + const typename LevelSetExtraction::SliceCellIndexData< Dim >::template CellIndices<1> &eIndices = sValues.cellIndices.template indices<1>( leaf ); + if( HyperCube::Cube< Dim-1 >::HasMCRoots( sValues.mcIndices[idx] ) ) + { + neighborKey.getNeighbors( leaf ); + if( densityWeights ) weightKey.getNeighbors( leaf ); + if( data ) dataKey.getNeighbors( leaf ); + + for( typename HyperCube::Cube< Dim-1 >::template Element< 1 > _e ; _e::template ElementNum< 1 >() ; _e++ ) + if( HyperCube::Cube< 1 >::HasMCRoots( HyperCube::Cube< Dim-1 >::ElementMCIndex( _e , sValues.mcIndices[idx] ) ) ) + { + typename HyperCube::Cube< Dim >::template Element< 1 > e( zDir , _e.index ); + node_index_type vIndex = eIndices[_e.index]; + volatile char &edgeSet = sScratch.eSet[vIndex]; + if( !edgeSet ) + { + Vertex vertex; + Key key = _EdgeIndex( leaf , e ); + GetIsoVertex< WeightDegree , Data , DataSig >( tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , _e , zDir , sValues , vertex , zeroData , SetVertex ); + bool stillOwner = false; + std::pair< node_index_type , Vertex > hashed_vertex; + { + std::lock_guard< std::mutex > lock( _pointInsertionMutex ); + if( !edgeSet ) + { + vertices.addVertex( vertex ); + edgeSet = 1; + hashed_vertex = std::pair< node_index_type , Vertex >( vOffset , vertex ); + sValues.edgeKeys[ vIndex ] = key; + vOffset++; + stillOwner = true; + } + } + if( stillOwner ) + { + sScratch.eKeyValues[ thread ].push_back( std::pair< Key , std::pair< node_index_type , Vertex > >( key , hashed_vertex ) ); + // We only need to pass the iso-vertex down if the edge it lies on is adjacent to a coarser leaf + auto IsNeeded = [&]( unsigned int depth ) + { + bool isNeeded = false; + typename HyperCube::Cube< Dim >::template IncidentCubeIndex< 1 > my_ic = HyperCubeTables< Dim , 1 >::IncidentCube[e.index]; + for( typename HyperCube::Cube< Dim >::template IncidentCubeIndex< 1 > ic ; ic::template IncidentCubeNum< 1 >() ; ic++ ) if( ic!=my_ic ) + { + unsigned int xx = HyperCubeTables< Dim , 1 >::CellOffset[e.index][ic.index]; + isNeeded |= !tree._isValidSpaceNode( neighborKey.neighbors[ tree._localToGlobal( depth ) ].neighbors.data[xx] ); + } + return isNeeded; + }; + if( IsNeeded( depth ) ) + { + const typename HyperCube::Cube< Dim >::template Element< Dim-1 > *f = HyperCubeTables< Dim , 1 , Dim-1 >::OverlapElements[e.index]; + for( int k=0 ; k::OverlapElementNum ; k++ ) + { + TreeNode* node = leaf; + LocalDepth _depth = depth; + int _slice = slice; + bool _cross = false; + while( tree._isValidSpaceNode( node->parent ) && HyperCubeTables< Dim , Dim-1 , 0 >::Overlap[f[k].index][(unsigned int)(node-node->parent->children) ] ) + { + if( _slice&1 ) _cross = true; + node = node->parent , _depth-- , _slice >>= 1; + SliceValues &_sValues = slabValues[_depth].sliceValues( _slice ); + typename SliceValues::Scratch &_sScratch = slabValues[_depth].sliceScratch( _slice ); + + if( _depth>=fullDepth && !_cross ) + { + const typename LevelSetExtraction::SliceCellIndexData< Dim >::template CellIndices<1> &_eIndices = _sValues.cellIndices.template indices<1>( node ); + node_index_type _vIndex = _eIndices[_e.index]; + _sScratch.eSet[_vIndex] = 1; + } + + if( _cross ) + { + XSliceValues& _xValues = slabValues[_depth].xSliceValues( _slice ); + typename XSliceValues::Scratch &_xScratch = slabValues[_depth].xSliceScratch( _slice ); + _xScratch.eKeyValues[ thread ].push_back( std::pair< Key , std::pair< node_index_type , Vertex > >( key , hashed_vertex ) ); + } + else + { + SliceValues& _sValues = slabValues[_depth].sliceValues( _slice ); + typename SliceValues::Scratch &_sScratch = slabValues[_depth].sliceScratch( _slice ); + _sScratch.eKeyValues[ thread ].push_back( std::pair< Key , std::pair< node_index_type , Vertex > >( key , hashed_vertex ) ); + } + if( !IsNeeded( _depth ) ) break; + } + } + } + } + } + } + } + } + } + } + ); + } + + //////////////////// + // Iso-Extraction // + //////////////////// + template< unsigned int WeightDegree , typename Data , unsigned int DataSig > + static void SetXSliceIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slab , Real bCoordinate , Real fCoordinate , node_index_type &vOffset , StreamingVertices< Vertex , node_index_type > &vertices , std::vector< SlabValues >& slabValues , const Data &zeroData , std::function< void ( Vertex& , Point< Real , Dim > , Point< Real , Dim > , Real , Data ) > SetVertex ) + { + auto _EdgeIndex = [&]( const TreeNode *node , typename HyperCube::Cube< Dim >::template Element< 1 > e ) + { + int depth , offset[Dim]; + tree.depthAndOffset( node , depth , offset ); + return keyGenerator( depth , offset , e ); + }; + + static const unsigned int DataDegree = FEMSignature< DataSig >::Degree; + SliceValues& bValues = slabValues[depth].sliceValues ( slab ); + SliceValues& fValues = slabValues[depth].sliceValues ( slab+1 ); + XSliceValues& xValues = slabValues[depth].xSliceValues( slab ); + typename SliceValues::Scratch &bScratch = slabValues[depth]. sliceScratch( slab ); + typename SliceValues::Scratch &fScratch = slabValues[depth]. sliceScratch( slab+1 ); + typename XSliceValues::Scratch &xScratch = slabValues[depth].xSliceScratch( slab ); + + // [WARNING] In the case Degree=2, these two keys are the same, so we don't have to maintain them separately. + std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); + std::vector< ConstPointSupportKey< IsotropicUIntPack< Dim , WeightDegree > > > weightKeys( ThreadPool::NumThreads() ); + std::vector< ConstPointSupportKey< IsotropicUIntPack< Dim , DataDegree > > > dataKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i >& weightKey = weightKeys[ thread ]; + ConstPointSupportKey< IsotropicUIntPack< Dim , DataDegree > >& dataKey = dataKeys[ thread ]; + TreeNode* leaf = tree._sNodes.treeNodes[i]; + if( !IsActiveNode< Dim >( leaf->children ) ) + { + unsigned char mcIndex = ( bValues.mcIndices[ i - bValues.cellIndices.nodeOffset ] ) | ( fValues.mcIndices[ i - fValues.cellIndices.nodeOffset ] )<<4; + const typename LevelSetExtraction::SlabCellIndexData< Dim >::template CellIndices<0> &eIndices = xValues.cellIndices.template indices<0>( leaf ); + if( HyperCube::Cube< Dim >::HasMCRoots( mcIndex ) ) + { + neighborKey.getNeighbors( leaf ); + if( densityWeights ) weightKey.getNeighbors( leaf ); + if( data ) dataKey.getNeighbors( leaf ); + for( typename HyperCube::Cube< Dim-1 >::template Element< 0 > _c ; _c::template ElementNum< 0 >() ; _c++ ) + { + typename HyperCube::Cube< Dim >::template Element< 1 > e( HyperCube::CROSS , _c.index ); + unsigned int _mcIndex = HyperCube::Cube< Dim >::ElementMCIndex( e , mcIndex ); + if( HyperCube::Cube< 1 >::HasMCRoots( _mcIndex ) ) + { + node_index_type vIndex = eIndices[_c.index]; + volatile char &edgeSet = xScratch.eSet[vIndex]; + if( !edgeSet ) + { + Vertex vertex; + Key key = _EdgeIndex( leaf , e.index ); + GetIsoVertex< WeightDegree , Data , DataSig >( tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , _c , bCoordinate , fCoordinate , bValues , fValues , vertex , zeroData , SetVertex ); + bool stillOwner = false; + std::pair< node_index_type , Vertex > hashed_vertex; + { + std::lock_guard< std::mutex > lock( _pointInsertionMutex ); + if( !edgeSet ) + { + vertices.addVertex( vertex ); + edgeSet = 1; + hashed_vertex = std::pair< node_index_type , Vertex >( vOffset , vertex ); + xValues.edgeKeys[ vIndex ] = key; + vOffset++; + stillOwner = true; + } + } + if( stillOwner ) + { + + xScratch.eKeyValues[ thread ].push_back( std::pair< Key , std::pair< node_index_type , Vertex > >( key , hashed_vertex ) ); + + // We only need to pass the iso-vertex down if the edge it lies on is adjacent to a coarser leaf + auto IsNeeded = [&]( unsigned int depth ) + { + bool isNeeded = false; + typename HyperCube::Cube< Dim >::template IncidentCubeIndex< 1 > my_ic = HyperCubeTables< Dim , 1 >::IncidentCube[e.index]; + for( typename HyperCube::Cube< Dim >::template IncidentCubeIndex< 1 > ic ; ic::template IncidentCubeNum< 1 >() ; ic++ ) if( ic!=my_ic ) + { + unsigned int xx = HyperCubeTables< Dim , 1 >::CellOffset[e.index][ic.index]; + isNeeded |= !tree._isValidSpaceNode( neighborKey.neighbors[ tree._localToGlobal( depth ) ].neighbors.data[xx] ); + } + return isNeeded; + }; + if( IsNeeded( depth ) ) + { + const typename HyperCube::Cube< Dim >::template Element< Dim-1 > *f = HyperCubeTables< Dim , 1 , Dim-1 >::OverlapElements[e.index]; + for( int k=0 ; k<2 ; k++ ) + { + TreeNode* node = leaf; + LocalDepth _depth = depth; + int _slab = slab; + // As long as we are still in the tree and the parent is also adjacent to the node + while( tree._isValidSpaceNode( node->parent ) && HyperCubeTables< Dim , Dim-1 , 0 >::Overlap[f[k].index][(unsigned int)(node-node->parent->children) ] ) + { + node = node->parent , _depth-- , _slab >>= 1; + XSliceValues& _xValues = slabValues[_depth].xSliceValues( _slab ); + typename XSliceValues::Scratch &_xScratch = slabValues[_depth].xSliceScratch( _slab ); + _xScratch.eKeyValues[ thread ].push_back( std::pair< Key , std::pair< node_index_type , Vertex > >( key , hashed_vertex ) ); + + if( _depth>=fullDepth ) + { + const typename LevelSetExtraction::SlabCellIndexData< Dim >::template CellIndices<0> &_eIndices = _xValues.cellIndices.template indices<0>( node ); + node_index_type _vIndex = _eIndices[_c.index]; + _xScratch.eSet[_vIndex] = 1; + } + + if( !IsNeeded( _depth ) ) break; + } + } + } + } + } + } + } + } + } + } + } + ); + } + + static void CopyFinerSliceIsoEdgeKeys( const FEMTree< Dim , Real >& tree , LocalDepth depth , LocalDepth fullDepth , int slice , std::vector< SlabValues >& slabValues ) + { + if( slice>0 ) CopyFinerSliceIsoEdgeKeys( tree , depth , fullDepth , slice , HyperCube::FRONT , slabValues ); + if( slice<(1<& tree , LocalDepth depth , LocalDepth fullDepth , int slice , HyperCube::Direction zDir , std::vector< SlabValues >& slabValues ) + { + SliceValues& pSliceValues = slabValues[depth ].sliceValues(slice ); + SliceValues& cSliceValues = slabValues[depth+1].sliceValues(slice<<1); + typename SliceValues::Scratch &pSliceScratch = slabValues[depth ].sliceScratch(slice ); + typename SliceValues::Scratch &cSliceScratch = slabValues[depth+1].sliceScratch(slice<<1); + LevelSetExtraction::SliceCellIndexData< Dim > &pCellIndices = pSliceValues.cellIndices; + LevelSetExtraction::SliceCellIndexData< Dim > &cCellIndices = cSliceValues.cellIndices; + ThreadPool::Parallel_for( tree._sNodesBegin(depth,slice-(zDir==HyperCube::BACK ? 0 : 1)) , tree._sNodesEnd(depth,slice-(zDir==HyperCube::BACK ? 0 : 1)) , [&]( unsigned int thread , size_t i ) + { + if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i] ) ) if( IsActiveNode< Dim >( tree._sNodes.treeNodes[i]->children ) ) + { + typename LevelSetExtraction::SliceCellIndexData< Dim >::template CellIndices<1> &pIndices = pCellIndices.template indices<1>( (node_index_type)i ); + // Copy the edges that overlap the coarser edges + for( typename HyperCube::Cube< Dim-1 >::template Element< 1 > _e ; _e::template ElementNum< 1 >() ; _e++ ) + { + node_index_type pIndex = pIndices[_e.index]; + { + typename HyperCube::Cube< Dim >::template Element< 1 > e( zDir , _e.index ); + const typename HyperCube::Cube< Dim >::template Element< 0 > *c = HyperCubeTables< Dim , 1 , 0 >::OverlapElements[e.index]; + // [SANITY CHECK] + // if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[0].index )!=tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[1].index ) ) ERROR_OUT( "Finer edges should both be valid or invalid" ); + if( !tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[0].index ) || !tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[1].index ) ) continue; + + node_index_type cIndex1 = cCellIndices.template indices<1>( tree._sNodes.treeNodes[i]->children + c[0].index )[_e.index]; + node_index_type cIndex2 = cCellIndices.template indices<1>( tree._sNodes.treeNodes[i]->children + c[1].index )[_e.index]; + if( cSliceScratch.eSet[cIndex1] != cSliceScratch.eSet[cIndex2] ) + { + Key key; + if( cSliceScratch.eSet[cIndex1] ) key = cSliceValues.edgeKeys[cIndex1]; + else key = cSliceValues.edgeKeys[cIndex2]; + pSliceValues.edgeKeys[pIndex] = key; + pSliceScratch.eSet[pIndex] = 1; + } + else if( cSliceScratch.eSet[cIndex1] && cSliceScratch.eSet[cIndex2] ) + { + Key key1 = cSliceValues.edgeKeys[cIndex1] , key2 = cSliceValues.edgeKeys[cIndex2]; + pSliceScratch.vKeyValues[ thread ].push_back( std::pair< Key , Key >( key1 , key2 ) ); + + const TreeNode* node = tree._sNodes.treeNodes[i]; + LocalDepth _depth = depth; + int _slice = slice; + while( _depth>fullDepth && tree._isValidSpaceNode( node->parent ) && HyperCubeTables< Dim , 1 , 0 >::Overlap[e.index][(unsigned int)(node-node->parent->children) ] ) + { + node = node->parent , _depth-- , _slice >>= 1; + SliceValues& _pSliceValues = slabValues[_depth].sliceValues(_slice); + typename SliceValues::Scratch &_pSliceScratch = slabValues[_depth].sliceScratch(_slice); + _pSliceScratch.vKeyValues[ thread ].push_back( std::pair< Key , Key >( key1 , key2 ) ); + } + } + } + } + } + } + ); + } + + static void CopyFinerXSliceIsoEdgeKeys( const FEMTree< Dim , Real >& tree , LocalDepth depth , LocalDepth fullDepth , int slab , std::vector< SlabValues>& slabValues ) + { + XSliceValues& pSliceValues = slabValues[depth ].xSliceValues(slab); + XSliceValues& cSliceValues0 = slabValues[depth+1].xSliceValues( (slab<<1)|0 ); + XSliceValues& cSliceValues1 = slabValues[depth+1].xSliceValues( (slab<<1)|1 ); + typename XSliceValues::Scratch &pSliceScratch = slabValues[depth ].xSliceScratch(slab); + typename XSliceValues::Scratch &cSliceScratch0 = slabValues[depth+1].xSliceScratch( (slab<<1)|0 ); + typename XSliceValues::Scratch &cSliceScratch1 = slabValues[depth+1].xSliceScratch( (slab<<1)|1 ); + LevelSetExtraction::SlabCellIndexData< Dim > &pCellIndices = pSliceValues. cellIndices; + LevelSetExtraction::SlabCellIndexData< Dim > &cCellIndices0 = cSliceValues0.cellIndices; + LevelSetExtraction::SlabCellIndexData< Dim > &cCellIndices1 = cSliceValues1.cellIndices; + + bool has0 = cSliceValues0.slab()==((slab<<1)|0); + bool has1 = cSliceValues1.slab()==((slab<<1)|1); + + ThreadPool::Parallel_for( tree._sNodesBegin(depth,slab) , tree._sNodesEnd(depth,slab) , [&]( unsigned int thread , size_t i ) + { + // If the node is not a leaf, inherit iso-edges from children + if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i] ) && IsActiveNode< Dim >( tree._sNodes.treeNodes[i]->children ) ) + { + // Get the mapping from node + local face-corner -> global corner + typename LevelSetExtraction::SlabCellIndexData< Dim >::template CellIndices<0> &pIndices = pCellIndices.template indices<0>( (node_index_type)i ); + for( typename HyperCube::Cube< Dim-1 >::template Element< 0 > _c ; _c::template ElementNum< 0 >() ; _c++ ) + { + // Transform the face-corner index to a cross-edge index + typename HyperCube::Cube< Dim >::template Element< 1 > e( HyperCube::CROSS , _c.index ); + node_index_type pIndex = pIndices[ _c.index ]; + + { + typename HyperCube::Cube< Dim >::template Element< 0 > c0( HyperCube::BACK , _c.index ) , c1( HyperCube::FRONT , _c.index ); + + // [SANITY CHECK] + // if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c0 )!=tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c1 ) ) ERROR_OUT( "Finer edges should both be valid or invalid" ); + if( !tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c0.index ) || !tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c1.index ) ) continue; + + node_index_type cIndex0 , cIndex1; + if( has0 ) cIndex0 = cCellIndices0.template indices<0>( tree._sNodes.treeNodes[i]->children + c0.index )[_c.index]; + if( has1 ) cIndex1 = cCellIndices1.template indices<0>( tree._sNodes.treeNodes[i]->children + c1.index )[_c.index]; + char eSet0 = has0 && cSliceScratch0.eSet[cIndex0] , eSet1 = has1 && cSliceScratch1.eSet[cIndex1]; + + // If there's one zero-crossing along the edge + if( eSet0 != eSet1 ) + { + Key key; + if( eSet0 ) key = cSliceValues0.edgeKeys[cIndex0]; //, vPair = cSliceValues0.edgeVertexMap.find( key )->second; + else key = cSliceValues1.edgeKeys[cIndex1]; //, vPair = cSliceValues1.edgeVertexMap.find( key )->second; + pSliceValues.edgeKeys[ pIndex ] = key; + pSliceScratch.eSet[ pIndex ] = 1; + } + // If there's are two zero-crossings along the edge + else if( eSet0 && eSet1 ) + { + Key key0 = cSliceValues0.edgeKeys[cIndex0] , key1 = cSliceValues1.edgeKeys[cIndex1]; + pSliceScratch.vKeyValues[ thread ].push_back( std::pair< Key , Key >( key0 , key1 ) ); + const TreeNode* node = tree._sNodes.treeNodes[i]; + LocalDepth _depth = depth; + int _slab = slab; + while( _depth>fullDepth && tree._isValidSpaceNode( node->parent ) && HyperCubeTables< Dim , 1 , 0 >::Overlap[e.index][(unsigned int)(node-node->parent->children) ] ) + { + node = node->parent , _depth-- , _slab>>= 1; + SliceValues& _pSliceValues = slabValues[_depth].sliceValues(_slab); + typename SliceValues::Scratch &_pSliceScratch = slabValues[_depth].sliceScratch(_slab); + _pSliceScratch.vKeyValues[ thread ].push_back( std::pair< Key , Key >( key0 , key1 ) ); + } + } + } + } + } + } + ); + } + + static void SetSliceIsoEdges( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , LocalDepth depth , int slice , std::vector< SlabValues >& slabValues ) + { + if( slice>0 ) SetSliceIsoEdges( keyGenerator , tree , depth , slice , HyperCube::FRONT , slabValues ); + if( slice<(1< &keyGenerator , const FEMTree< Dim , Real >& tree , LocalDepth depth , int slice , HyperCube::Direction zDir , std::vector< SlabValues >& slabValues ) + { + auto _FaceIndex = [&]( const TreeNode *node , typename HyperCube::Cube< Dim >::template Element< 2 > f ) + { + int depth , offset[Dim]; + tree.depthAndOffset( node , depth , offset ); + return keyGenerator( depth , offset , f ); + }; + + SliceValues& sValues = slabValues[depth].sliceValues( slice ); + typename SliceValues::Scratch &sScratch = slabValues[depth].sliceScratch( slice ); + std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i( leaf->children ) ) + { + node_index_type idx = (node_index_type)i - sValues.cellIndices.nodeOffset; + const typename LevelSetExtraction::SliceCellIndexData< Dim >::template CellIndices<1> &eIndices = sValues.cellIndices.template indices<1>( leaf ); + const typename LevelSetExtraction::SliceCellIndexData< Dim >::template CellIndices<2> &fIndices = sValues.cellIndices.template indices<2>( leaf ); + unsigned char mcIndex = sValues.mcIndices[idx]; + if( !sScratch.fSet[ fIndices[0] ] ) + { + neighborKey.getNeighbors( leaf ); + unsigned int xx = WindowIndex< IsotropicUIntPack< Dim , 3 > , IsotropicUIntPack< Dim , 1 > >::Index + (zDir==HyperCube::BACK ? -1 : 1); + if( !IsActiveNode< Dim >( neighborKey.neighbors[ tree._localToGlobal( depth ) ].neighbors.data[xx] ) || !IsActiveNode< Dim >( neighborKey.neighbors[ tree._localToGlobal( depth ) ].neighbors.data[xx]->children ) ) + { + FaceEdges fe; + fe.count = HyperCube::MarchingSquares::AddEdgeIndices( mcIndex , isoEdges ); + for( int j=0 ; j::template Element< Dim-1 > f( zDir , 0 ); + std::vector< IsoEdge > edges; + edges.resize( fe.count ); + for( int j=0 ; jparent ) && HyperCubeTables< Dim , 2 , 0 >::Overlap[f.index][(unsigned int)(node-node->parent->children) ] ) + { + node = node->parent , _depth-- , _slice >>= 1; + if( IsActiveNode< Dim >( neighborKey.neighbors[ tree._localToGlobal( _depth ) ].neighbors.data[xx] ) && IsActiveNode< Dim >( neighborKey.neighbors[ tree._localToGlobal( _depth ) ].neighbors.data[xx]->children ) ) break; + Key key = _FaceIndex( node , f ); + SliceValues& _sValues = slabValues[_depth].sliceValues( _slice ); + typename SliceValues::Scratch &_sScratch = slabValues[_depth].sliceScratch( _slice ); + _sScratch.fKeyValues[ thread ].push_back( std::pair< Key , std::vector< IsoEdge > >( key , edges ) ); + } + } + } + } + } + } + ); + } + + static void SetXSliceIsoEdges( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , LocalDepth depth , int slab , std::vector< SlabValues >& slabValues ) + { + auto _FaceIndex = [&]( const TreeNode *node , typename HyperCube::Cube< Dim >::template Element< 2 > f ) + { + int depth , offset[Dim]; + tree.depthAndOffset( node , depth , offset ); + return keyGenerator( depth , offset , f ); + }; + + SliceValues& bValues = slabValues[depth].sliceValues ( slab ); + SliceValues& fValues = slabValues[depth].sliceValues ( slab+1 ); + XSliceValues& xValues = slabValues[depth].xSliceValues( slab ); + typename SliceValues::Scratch &bScratch = slabValues[depth]. sliceScratch( slab ); + typename SliceValues::Scratch &fScratch = slabValues[depth]. sliceScratch( slab+1 ); + typename XSliceValues::Scratch &xScratch = slabValues[depth].xSliceScratch( slab ); + + std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i( leaf->children ) ) + { + const typename LevelSetExtraction::SlabCellIndexData< Dim >::template CellIndices<0> &cIndices = xValues.cellIndices.template indices<0>( leaf ); + const typename LevelSetExtraction::SlabCellIndexData< Dim >::template CellIndices<1> &eIndices = xValues.cellIndices.template indices<1>( leaf ); + unsigned char mcIndex = ( bValues.mcIndices[ i - bValues.cellIndices.nodeOffset ] ) | ( fValues.mcIndices[ i - fValues.cellIndices.nodeOffset ]<<4 ); + { + neighborKey.getNeighbors( leaf ); + // Iterate over the edges on the back + for( typename HyperCube::Cube< Dim-1 >::template Element< 1 > _e ; _e::template ElementNum< 1 >() ; _e++ ) + { + typename HyperCube::Cube< Dim >::template Element< 2 > f( HyperCube::CROSS , _e.index ); + unsigned char _mcIndex = HyperCube::Cube< Dim >::template ElementMCIndex< 2 >( f , mcIndex ); + + unsigned int xx = HyperCubeTables< Dim , 2 >::CellOffsetAntipodal[f.index]; + if( !xScratch.fSet[ eIndices[_e.index] ] && ( !IsActiveNode< Dim >( neighborKey.neighbors[ tree._localToGlobal( depth ) ].neighbors.data[xx] ) || !IsActiveNode< Dim >( neighborKey.neighbors[ tree._localToGlobal( depth ) ].neighbors.data[xx]->children ) ) ) + { + FaceEdges fe; + fe.count = HyperCube::MarchingSquares::AddEdgeIndices( _mcIndex , isoEdges ); + for( int j=0 ; j::template Element< 1 > e( f , typename HyperCube::Cube< Dim-1 >::template Element< 1 >( isoEdges[2*j+k] ) ); + HyperCube::Direction dir ; unsigned int coIndex; + e.factor( dir , coIndex ); + if( dir==HyperCube::CROSS ) // Cross-edge + { + node_index_type idx = cIndices[ coIndex ]; + if( !xScratch.eSet[ idx ] ) ERROR_OUT( "Edge not set: " , slab , " / " , 1<((node_index_type)i)[ coIndex ]; + if( !sScratch.eSet[ idx ] ) ERROR_OUT( "Edge not set: " , slab , " / " , 1< edges; + edges.resize( fe.count ); + for( int j=0 ; jparent ) && HyperCubeTables< Dim , 2 , 0 >::Overlap[f.index][(unsigned int)(node-node->parent->children) ] ) + { + node = node->parent , _depth-- , _slab >>= 1; + if( IsActiveNode< Dim >( neighborKey.neighbors[ tree._localToGlobal( _depth ) ].neighbors.data[xx] ) && IsActiveNode< Dim >( neighborKey.neighbors[ tree._localToGlobal( _depth ) ].neighbors.data[xx]->children ) ) break; + Key key = _FaceIndex( node , f ); + XSliceValues& _xValues = slabValues[_depth].xSliceValues( _slab ); + typename XSliceValues::Scratch &_xScratch = slabValues[_depth].xSliceScratch( _slab ); + _xScratch.fKeyValues[ thread ].push_back( std::pair< Key , std::vector< IsoEdge > >( key , edges ) ); + } + } + } + } + } + } + } + ); + } + + template< typename FaceIndexFunctor /* = std::function< LevelSetExtraction::Key< Dim > ( const TreeNode * , typename HyperCube::Cube< Dim >::template Element< 2 > ) */ > + static void SetLevelSet( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , FaceIndexFunctor faceIndexFunctor , const FEMTree< Dim , Real >& tree , LocalDepth depth , int offset , const SliceValues& bValues , const SliceValues& fValues , const XSliceValues& xValues , const typename SliceValues::Scratch &bScratch , const typename SliceValues::Scratch &fScratch , const typename XSliceValues::Scratch &xScratch , StreamingMesh< Vertex , node_index_type >& mesh , bool polygonMesh , bool addBarycenter , node_index_type& vOffset , bool flipOrientation ) + { + std::vector< std::pair< node_index_type , Vertex > > polygon; + std::vector< std::vector< IsoEdge > > edgess( ThreadPool::NumThreads() ); + ThreadPool::Parallel_for( tree._sNodesBegin(depth,offset) , tree._sNodesEnd(depth,offset) , [&]( unsigned int thread , size_t i ) + { + if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i] ) ) + { + std::vector< IsoEdge >& edges = edgess[ thread ]; + TreeNode* leaf = tree._sNodes.treeNodes[i]; + int res = 1<=0 && off[0]=0 && off[1]=0 && off[2]( leaf->children ) ) + { + edges.clear(); + { + // Gather the edges from the faces (with the correct orientation) + for( typename HyperCube::Cube< Dim >::template Element< Dim-1 > f ; f::template ElementNum< Dim-1 >() ; f++ ) + { + bool isOriented = HyperCube::Cube< Dim >::IsOriented( f ); + int flip = isOriented ? 0 : 1; + HyperCube::Direction fDir = f.direction(); + + if ( fDir==HyperCube::BACK ) bValues.addIsoEdges( keyGenerator , faceIndexFunctor , tree , bScratch , leaf , offset+0 , edges , isOriented ); + else if( fDir==HyperCube::FRONT ) fValues.addIsoEdges( keyGenerator , faceIndexFunctor , tree , fScratch , leaf , offset+1 , edges , isOriented ); + else + { + node_index_type fIdx = xValues.cellIndices.template indices<1>((node_index_type)i)[ f.coIndex() ]; + if( xScratch.fSet[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 ERROR_OUT( "Invalid faces: " , i , " " , fDir==HyperCube::BACK ? "back" : ( fDir==HyperCube::FRONT ? "front" : ( fDir==HyperCube::CROSS ? "cross" : "unknown" ) ) ); + } + } + } + // Get the edge loops + std::vector< std::vector< Key > > loops; + while( edges.size() ) + { + loops.resize( loops.size()+1 ); + IsoEdge edge = edges.back(); + edges.pop_back(); + Key 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 LevelSetExtraction::KeyMap< Dim , Key >::const_iterator iter; + Key pair; + if ( bValues.setVertexPair(current,pair) ) loops.back().push_back( current ) , current = pair; + else if( fValues.setVertexPair(current,pair) ) loops.back().push_back( current ) , current = pair; + else if( (iter=xValues.vertexPairMap.find(current))!=xValues.vertexPairMap.end() ) loops.back().push_back( current ) , current = iter->second; + else ERROR_OUT( "Failed to close loop for node[" , i , "]: [" , off[0] , " " , off[1] , " " , off[2] , " @ " , d , "] | " , keyGenerator.to_string( current ) , " -- " , keyGenerator.to_string( start ) , " | " , current.to_string() , " -- " , start.to_string() ); + } + 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; + size_t kk = flipOrientation ? loops[j].size()-1-k : k; + if ( bValues.setEdgeVertex( key , polygon[kk] ) ); + else if( fValues.setEdgeVertex( key , polygon[kk] ) ); + else if( ( iter=xValues.edgeVertexMap.find( key ) )!=xValues.edgeVertexMap.end() ) polygon[kk] = iter->second; + else ERROR_OUT( "Couldn't find vertex in edge map: " , off[0] , " , " , off[1] , " , " , off[2] , " @ " , depth , " : " , keyGenerator.to_string( key ) , " | " , key.to_string() ); + } + AddIsoPolygons( thread , mesh , polygon , polygonMesh , addBarycenter , vOffset ); + } + } + } + } + } + ); + } + + template< unsigned int WeightDegree , typename Data , unsigned int DataSig > + static bool GetIsoVertex( const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , ConstPointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , ConstPointSupportKey< IsotropicUIntPack< Dim , FEMSignature< DataSig >::Degree > >& dataKey , const TreeNode* node , typename HyperCube::template Cube< Dim-1 >::template Element< 1 > _e , HyperCube::Direction zDir , const SliceValues& sValues , Vertex& vertex , const Data &zeroData , std::function< void ( Vertex& , Point< Real , Dim > , Point< Real , Dim > , Real , Data ) > SetVertex ) + { + static const unsigned int DataDegree = FEMSignature< DataSig >::Degree; + Point< Real , Dim > position , gradient; + int c0 , c1; + const typename HyperCube::Cube< Dim-1 >::template Element< 0 > *_c = HyperCubeTables< Dim-1 , 1 , 0 >::OverlapElements[_e.index]; + c0 = _c[0].index , c1 = _c[1].index; + + const typename LevelSetExtraction::SliceCellIndexData< Dim >::template CellIndices<0> &idx = sValues.cellIndices.template indices<0>( node ); + Real x0 = sValues.cornerValues[idx[c0]] , x1 = sValues.cornerValues[idx[c1]]; + Point< Real , 3 > dx0 , dx1; + if( gradientNormals ) dx0 = sValues.cornerGradients[idx[c0]] , dx1 = sValues.cornerGradients[idx[c1]]; + Point< Real , Dim > s; + Real start , width; + tree._startAndWidth( node , s , width ); + int o; + { + const HyperCube::Direction* dirs = HyperCubeTables< Dim-1 , 1 >::Directions[ _e.index ]; + for( int d=0 ; d 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 ) ERROR_OUT( "Not a zero-crossing root: " , x0 , " " , x1 ); + averageRoot = ( isoValue - x0 ) / ( x1 - x0 ); + } + if( averageRoot<=0 || averageRoot>=1 ) + { + _BadRootCount++; + if( averageRoot<0 ) averageRoot = 0; + if( averageRoot>1 ) averageRoot = 1; + } + position[o] = Real( start + width*averageRoot ); + gradient = dx0 * (Real)( 1.-averageRoot ) + dx1 * (Real)averageRoot; + Real depth = (Real)1.; + Data dataValue; + if( densityWeights ) + { + Real weight; + tree._getSampleDepthAndWeight( *densityWeights , node , position , weightKey , depth , weight ); + } + if( data ) + { + if( DataDegree==0 ) + { + Point< Real , 3 > center( s[0] + width/2 , s[1] + width/2 , s[2] + width/2 ); + ProjectiveData< Data , Real > pValue( zeroData ); + tree.template _addEvaluation< ProjectiveData< Data , Real > , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > , 0 >( *data , center , *pointEvaluator , dataKey , pValue ); + dataValue = pValue.weight ? pValue.value() : zeroData; + } + else + { + ProjectiveData< Data , Real > pValue( zeroData ); + tree.template _addEvaluation< ProjectiveData< Data , Real > , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > , 0 >( *data , position , *pointEvaluator , dataKey , pValue ); + dataValue = pValue.weight ? pValue.value() : zeroData; + } + } + SetVertex( vertex , position , gradient , depth , dataValue ); + return true; + } + + template< unsigned int WeightDegree , typename Data , unsigned int DataSig > + static bool GetIsoVertex( const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , ConstPointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , ConstPointSupportKey< IsotropicUIntPack< Dim , FEMSignature< DataSig >::Degree > >& dataKey , const TreeNode* node , typename HyperCube::template Cube< Dim-1 >::template Element< 0 > _c , Real bCoordinate , Real fCoordinate , const SliceValues& bValues , const SliceValues& fValues , Vertex& vertex , const Data &zeroData , std::function< void ( Vertex& , Point< Real , Dim > , Point< Real , Dim > , Real , Data ) > SetVertex ) + { + static const unsigned int DataDegree = FEMSignature< DataSig >::Degree; + Point< Real , Dim > position , gradient; + + const typename LevelSetExtraction::SliceCellIndexData< Dim >::template CellIndices<0> &idx0 = bValues.cellIndices.template indices<0>( node ); + const typename LevelSetExtraction::SliceCellIndexData< Dim >::template CellIndices<0> &idx1 = fValues.cellIndices.template indices<0>( node ); + Real x0 = bValues.cornerValues[ idx0[_c.index] ] , x1 = fValues.cornerValues[ idx1[_c.index] ]; + Point< Real , 3 > dx0 , dx1; + if( gradientNormals ) dx0 = bValues.cornerGradients[ idx0[_c.index] ] , dx1 = fValues.cornerGradients[ idx1[_c.index] ]; + Point< Real , Dim > s; + Real w; + tree._startAndWidth( node , s , w ); + int x , y; + { + const HyperCube::Direction* xx = HyperCubeTables< Dim-1 , 0 >::Directions[ _c.index ]; + x = xx[0]==HyperCube::BACK ? 0 : 1 , y = xx[1]==HyperCube::BACK ? 0 : 1; + } + + position[0] = s[0] + w*x; + position[1] = s[1] + w*y; + + double averageRoot; + bool rootFound = false; + + if( nonLinearFit ) + { + double dx0 = bValues.cornerGradients[ idx0[_c.index] ][2] * (fCoordinate-bCoordinate) , dx1 = fValues.cornerGradients[ idx1[_c.index] ][2] * (fCoordinate-bCoordinate); + // 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 ) ERROR_OUT( "Not a zero-crossing root: " , x0 , " " , x1 ); + averageRoot = ( isoValue - x0 ) / ( x1 - x0 ); + } + if( averageRoot<=0 || averageRoot>=1 ) + { + _BadRootCount++; + if( averageRoot<0 ) averageRoot = 0; + if( averageRoot>1 ) averageRoot = 1; + } + position[2] = Real( bCoordinate + (fCoordinate-bCoordinate)*averageRoot ); + gradient = dx0 * (Real)( 1.-averageRoot ) + dx1 * (Real)averageRoot; + Real depth = (Real)1.; + Data dataValue; + if( densityWeights ) + { + Real weight; + tree._getSampleDepthAndWeight( *densityWeights , node , position , weightKey , depth , weight ); + } + if( data ) + { + if( DataDegree==0 ) + { + Point< Real , 3 > center( s[0] + w/2 , s[1] + w/2 , (bCoordinate+fCoordinate)/2 ); + ProjectiveData< Data , Real > pValue( zeroData ); + tree.template _addEvaluation< ProjectiveData< Data , Real > , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > , 0 >( *data , center , *pointEvaluator , dataKey , pValue ); + dataValue = pValue.weight ? pValue.value() : zeroData; + } + else + { + ProjectiveData< Data , Real > pValue( zeroData ); + tree.template _addEvaluation< ProjectiveData< Data , Real > , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > , 0 >( *data , position , *pointEvaluator , dataKey , pValue ); + dataValue = pValue.weight ? pValue.value() : zeroData; + } + } + SetVertex( vertex , position , gradient , depth , dataValue ); + return true; + } + + static unsigned int AddIsoPolygons( unsigned int thread , StreamingMesh< Vertex , node_index_type >& mesh , std::vector< std::pair< node_index_type , Vertex > >& polygon , bool polygonMesh , bool addBarycenter , node_index_type &vOffset ) + { + if( polygonMesh ) + { + std::vector< node_index_type > vertices( polygon.size() ); + for( unsigned int i=0 ; i3 ) + { + bool isCoplanar = false; + std::vector< node_index_type > triangle( 3 ); + + if( addBarycenter ) + for( unsigned int i=0 ; i()[k]==v2.template get<0>()[k] ) isCoplanar = true; + } + if( isCoplanar ) + { + Vertex c; + c *= 0; + for( unsigned int i=0 ; i lock( _pointInsertionMutex ); + cIdx = mesh.addVertex( c ); + vOffset++; + } + for( unsigned i=0 ; i > vertices( polygon.size() ); + for( unsigned int i=0 ; i(); + std::vector< TriangleIndex< node_index_type > > triangles = MinimalAreaTriangulation< node_index_type , Real , Dim >( ( ConstPointer( Point< Real , Dim > ) )GetPointer( vertices ) , (node_index_type)vertices.size() ); + if( triangles.size()!=polygon.size()-2 ) ERROR_OUT( "Minimal area triangulation failed:" , triangles.size() , " != " , polygon.size()-2 ); + for( unsigned int i=0 ; i vertices( 3 ); + for( int i=0 ; i<3 ; i++ ) vertices[2-i] = polygon[i].first; + mesh.addPolygon_s( thread , vertices ); + } + return (unsigned int)polygon.size()-2; + } + + struct Stats + { + double cornersTime , verticesTime , edgesTime , surfaceTime; + double setTableTime; + Stats( void ) : cornersTime(0) , verticesTime(0) , edgesTime(0) , surfaceTime(0) , setTableTime(0) {;} + std::string toString( void ) const + { + std::stringstream stream; + stream << "Corners / Vertices / Edges / Surface / Set Table: "; + stream << std::fixed << std::setprecision(1) << cornersTime << " / " << verticesTime << " / " << edgesTime << " / " << surfaceTime << " / " << setTableTime; + stream << " (s)"; + return stream.str(); + } + }; + + template< typename Data , typename SetVertexFunction , unsigned int ... FEMSigs , unsigned int WeightDegree , unsigned int DataSig > + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , StreamingMesh< Vertex , node_index_type >& mesh , const Data &zeroData , const SetVertexFunction &SetVertex , bool nonLinearFit , bool gradientNormals , bool addBarycenter , bool polygonMesh , bool flipOrientation ) + { + return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , 0 , 0 , 1 , mesh , zeroData , SetVertex , nonLinearFit , gradientNormals , addBarycenter , polygonMesh , flipOrientation ); + } + + template< typename Data , typename SetVertexFunction , unsigned int ... FEMSigs , unsigned int WeightDegree , unsigned int DataSig > + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , StreamingMesh< Vertex , node_index_type >& mesh , const Data &zeroData , const SetVertexFunction &SetVertex , bool nonLinearFit , bool gradientNormals , bool addBarycenter , bool polygonMesh , bool flipOrientation ) + { + std::vector< std::vector< Real > > dValues; + return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , tree._maxDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , mesh , zeroData , SetVertex , nonLinearFit , gradientNormals , addBarycenter , polygonMesh , flipOrientation , NULL , NULL , dValues , dValues , false ); + } + + template< typename Data , typename SetVertexFunction , unsigned int ... FEMSigs , unsigned int WeightDegree , unsigned int DataSig > + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , int maxKeyDepth , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , StreamingMesh< Vertex , node_index_type >& mesh , const Data &zeroData , const SetVertexFunction &SetVertex , bool nonLinearFit , bool gradientNormals , bool addBarycenter , bool polygonMesh , bool flipOrientation , const typename LevelSetExtractor< Dim-1 , Real , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *backBoundary , const typename LevelSetExtractor< Dim-1 , Real , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *frontBoundary , const std::vector< std::vector< Real > > &backDValues , const std::vector< std::vector< Real > > &frontDValues , bool copyTopology ) + { + if( maxKeyDepth(1u<() ); + static const unsigned int DataDegree = FEMSignature< DataSig >::Degree; + static const int FEMDegrees[] = { FEMSignature< FEMSigs >::Degree ... }; + for( int d=0 ; d(); + LevelSetExtraction::SetHyperCubeTables< Dim-1 >(); + + typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator = NULL; + if( data ) pointEvaluator = new typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >( tree._maxDepth ); + DenseNodeData< Real , UIntPack< FEMSigs ... > > coarseCoefficients( tree._sNodesEnd( tree._maxDepth-1 ) ); + memset( coarseCoefficients() , 0 , sizeof(Real)*tree._sNodesEnd( tree._maxDepth-1 ) ); + ThreadPool::Parallel_for( tree._sNodesBegin(0) , tree._sNodesEnd( tree._maxDepth-1 ) , [&]( unsigned int, size_t i ){ coarseCoefficients[i] = coefficients[i]; } ); + typename FEMIntegrator::template RestrictionProlongation< UIntPack< FEMSigs ... > > rp; + for( LocalDepth d=1 ; d() , rp , d , ( ConstPointer(Real) )coarseCoefficients()+tree._sNodesBegin(d-1) , coarseCoefficients()+tree._sNodesBegin(d) ); + + std::vector< _Evaluator< UIntPack< FEMSigs ... > , 1 > > evaluators( tree._maxDepth+1 ); + for( LocalDepth d=0 ; d<=tree._maxDepth ; d++ ) evaluators[d].set( tree._maxDepth ); + + node_index_type vertexOffset = 0; + + std::vector< SlabValues > slabValues( tree._maxDepth+1 ); + std::vector< std::pair< node_index_type , node_index_type > > backIncidence , frontIncidence; + if( backBoundary ) backIncidence = SetIncidence( tree , backBoundary->sliceTree , fullDepth , slabStartAtMaxDepth , maxDepth ); + if( frontBoundary ) frontIncidence = SetIncidence( tree , frontBoundary->sliceTree , fullDepth , slabEndAtMaxDepth , maxDepth ); + + enum BoundarySliceType { BACK , FRONT , NEITHER }; + + auto BoundarySlice = [&]( unsigned int sliceAtMaxDepth ) + { + if ( backBoundary && sliceAtMaxDepth==slabStartAtMaxDepth ) return BoundarySliceType::BACK; + else if( frontBoundary && sliceAtMaxDepth== slabEndAtMaxDepth ) return BoundarySliceType::FRONT; + else return BoundarySliceType::NEITHER; + }; + + + auto SetCoarseSlice = [&]( unsigned int sliceAtMaxDepth , unsigned int coarseDepth , unsigned int &coarseSlice ) + { + BoundarySliceType bst = BoundarySlice( sliceAtMaxDepth ); + unsigned dOff = maxDepth - coarseDepth; + coarseSlice = sliceAtMaxDepth>>dOff; + if( sliceAtMaxDepth!=( coarseSlice<= slabEndAtMaxDepth ) return false; + if( startAtMaxDepth slabEndAtMaxDepth && !frontBoundary ) return false; + return true; + }; + + auto SetSlabBounds = [&]( unsigned int d , unsigned int o , Real &bCoordinate , Real &fCoordinate ) + { + unsigned int start = std::max< unsigned int >( (o+0)<<(maxDepth-d) , slabStartAtMaxDepth ); + unsigned int end = std::min< unsigned int >( (o+1)<<(maxDepth-d) , slabEndAtMaxDepth ); + bCoordinate = start/(Real)(1<=fullDepth ; d-- ) + { + unsigned int slice; + if( !SetCoarseSlice( sliceAtMaxDepth , d , slice ) ) break; + if( d<=tree._maxDepth ) + { + double t = Time(); + slabValues[d].sliceValues(slice).cellIndices.set( tree._sNodes , tree._localToGlobal( d ) , slice + tree._localInset( d ) ); + stats.setTableTime += Time()-t; + + slabValues[d].sliceValues(slice).reset( slice , nonLinearFit || gradientNormals ); + + slabValues[d].sliceScratch(slice).reset( slabValues[d].sliceValues(slice).cellIndices ); + } + } + }; + + auto InitSlab = [&]( unsigned int slabAtMaxDepth , bool first ) + { + unsigned int slab = slabAtMaxDepth; + for( LocalDepth d=maxDepth ; d>=fullDepth ; d-- , slab>>=1 ) + { + if( d<=tree._maxDepth ) + { + double t = Time(); + slabValues[d].xSliceValues(slab).cellIndices.set( tree._sNodes , tree._localToGlobal( d ) , slab + tree._localInset( d ) ); + stats.setTableTime += Time()-t; + + slabValues[d].xSliceValues(slab).reset(slab); + + slabValues[d].xSliceScratch(slab).reset( slabValues[d].xSliceValues(slab).cellIndices ); + } + if( (slab&1) && !first ) break; + } + }; + + auto FinalizeSlice = [&]( unsigned int sliceAtMaxDepth ) + { + + bool useBoundary = ( ( sliceAtMaxDepth==slabStartAtMaxDepth && backBoundary ) || ( sliceAtMaxDepth==slabEndAtMaxDepth && frontBoundary ) ) && copyTopology; + if( !useBoundary ) + { + LocalDepth d ; unsigned int o; + for( d=maxDepth , o=sliceAtMaxDepth ; d>=fullDepth ; d-- , o>>=1 ) + { + if( d<=tree._maxDepth ) + { + ThreadPool::ParallelSections + ( + [ &slabValues , d , o ]( void ){ slabValues[d].sliceValues(o).setFromScratch( slabValues[d].sliceScratch(o).vKeyValues ); } , + [ &slabValues , d , o ]( void ){ slabValues[d].sliceValues(o).setFromScratch( slabValues[d].sliceScratch(o).eKeyValues ); } , + [ &slabValues , d , o ]( void ){ slabValues[d].sliceValues(o).setFromScratch( slabValues[d].sliceScratch(o).fKeyValues ); } + ); + } + if( o&1 ) break; + } + } + }; + + auto FinalizeSlab = [&]( unsigned int slabAtMaxDepth ) + { + LocalDepth d ; unsigned int o; + bool boundary = (slabAtMaxDepth+1)==slabEndAtMaxDepth && frontBoundary; + for( d=maxDepth , o=slabAtMaxDepth ; d>=fullDepth ; d-- , o>>=1 ) + { + if( d<=tree._maxDepth ) + { + ThreadPool::ParallelSections + ( + [ &slabValues , d , o ]( void ){ slabValues[d].xSliceValues(o).setFromScratch( slabValues[d].xSliceScratch(o).vKeyValues ); } , + [ &slabValues , d , o ]( void ){ slabValues[d].xSliceValues(o).setFromScratch( slabValues[d].xSliceScratch(o).eKeyValues ); } , + [ &slabValues , d , o ]( void ){ slabValues[d].xSliceValues(o).setFromScratch( slabValues[d].xSliceScratch(o).fKeyValues ); } + ); + } + if( !(o&1) && !boundary ) break; + } + }; + + auto SetSliceValues = [&]( unsigned int sliceAtMaxDepth ) + { + + LocalDepth d ; unsigned int o; + const typename LevelSetExtractor< Dim-1 , Real , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *boundary = NULL; + const std::vector< std::pair< node_index_type , node_index_type > > *incidence = NULL; + const std::vector< std::vector< Real > > *dValues = NULL; + if ( sliceAtMaxDepth==slabStartAtMaxDepth ) boundary = backBoundary , incidence = &backIncidence , dValues = & backDValues; + else if( sliceAtMaxDepth== slabEndAtMaxDepth ) boundary = frontBoundary , incidence = &frontIncidence , dValues = &frontDValues; + + if( boundary && copyTopology ) + { + double t = Time(); + for( LocalDepth d=maxDepth ; d>=fullDepth ; d-- ) if( d<=boundary->sliceTree.depth() && d<=tree._maxDepth ) + { + unsigned int slice; + if( !SetCoarseSlice( sliceAtMaxDepth , d , slice ) ) ERROR_OUT( "Could not set coarse slice" ); + OverwriteCornerValues( *boundary , (*dValues)[d] , tree , d , sliceAtMaxDepth , maxDepth , sliceAtMaxDepth==slabStartAtMaxDepth , slabValues , *incidence ); + SetMCIndices( tree , isoValue , d , fullDepth , slice , slabValues ); + } + stats.cornersTime += Time()-t , t = Time(); + } + else + { + double t; + + t = Time(); + for( d=maxDepth , o=sliceAtMaxDepth ; d>=fullDepth ; d-- , o>>=1 ) + { + if( d<=tree._maxDepth ) + { + if( boundary ) + { + if( d<=boundary->sliceTree.depth() ) + { + OverwriteCornerValues( *boundary , (*dValues)[d] , tree , d , sliceAtMaxDepth , maxDepth , sliceAtMaxDepth==slabStartAtMaxDepth , slabValues , backIncidence ); + SetMCIndices( tree , isoValue , d , fullDepth , o , slabValues ); + } + } + else SetSliceCornerValuesAndMCIndices< FEMSigs ... >( tree , coefficients() , coarseCoefficients() , isoValue , d , fullDepth , o , slabValues , evaluators[d] ); + } + if( o&1 ) break; + } + stats.cornersTime += Time()-t; + } + }; + + auto SetSliceIso = [&]( unsigned int sliceAtMaxDepth ) + { + LocalDepth d ; unsigned int o; + + const typename LevelSetExtractor< Dim-1 , Real , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *boundary = NULL; + const std::vector< std::pair< node_index_type , node_index_type > > *incidence = NULL; + const std::vector< std::vector< Real > > *dValues = NULL; + if ( sliceAtMaxDepth==slabStartAtMaxDepth ) boundary = backBoundary , incidence = &backIncidence , dValues = & backDValues; + else if( sliceAtMaxDepth== slabEndAtMaxDepth ) boundary = frontBoundary , incidence = &frontIncidence , dValues = &frontDValues; + + if( boundary && copyTopology ) + { + auto sliceFunctor = [&]( unsigned int depth ) -> SliceValues & + { + unsigned int slice; + if( !SetCoarseSlice( sliceAtMaxDepth , depth , slice ) ) ERROR_OUT( "Could not set coarse slice" ); + return slabValues[depth].sliceValues( slice ); + }; + auto scratchFunctor = [&]( unsigned int depth ) -> typename SliceValues::Scratch & + { + unsigned int slice; + if( !SetCoarseSlice( sliceAtMaxDepth , depth , slice ) ) ERROR_OUT( "Could not set coarse slice" ); + return slabValues[depth].sliceScratch( slice ); + }; + CopyIsoStructure< WeightDegree , Data , DataSig >( keyGenerator , *boundary , tree , fullDepth , sliceAtMaxDepth , maxDepth , sliceFunctor , scratchFunctor , *incidence , mesh , gradientNormals , pointEvaluator , densityWeights , data , vertexOffset , zeroData , SetVertex ); + } + else + { + double t; + // Set the iso-vertices + t = Time(); + for( d=maxDepth , o=sliceAtMaxDepth ; d>=fullDepth ; d-- , o>>=1 ) + { + if( d<=tree._maxDepth ) + { + SetSliceIsoVertices< WeightDegree , Data , DataSig >( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , d , fullDepth , o , vertexOffset , mesh , slabValues , zeroData , SetVertex ); + } + if( o&1 ) break; + } + stats.verticesTime += Time()-t; + + // Set the iso-edges + t = Time(); + for( d=maxDepth , o=sliceAtMaxDepth ; d>=fullDepth ; d-- , o>>=1 ) + { + if( d<=tree._maxDepth ) + { + if( d=fullDepth ; d-- , o>>=1 ) + { + if( d<=tree._maxDepth ) + { + if( InteriorSlab( d , o ) ) + { + // Set the iso-vertices + Real bCoordinate , fCoordinate; + SetSlabBounds( d , o , bCoordinate , fCoordinate ); + SetXSliceIsoVertices< WeightDegree , Data , DataSig >( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , d , std::max< unsigned int >( slabDepth , fullDepth ) , o , bCoordinate , fCoordinate , vertexOffset , mesh , slabValues , zeroData , SetVertex ); + } + } + + if( !(o&1) && !boundary ) break; + } + stats.edgesTime += Time()-t; + }; + + auto SetSlabIsoEdges = [&]( unsigned int slabAtMaxDepth ) + { + LocalDepth d ; unsigned int o; + double t = Time(); + + bool boundary = (slabAtMaxDepth+1)==slabEndAtMaxDepth && frontBoundary; + + // Set the iso-edges + for( d=maxDepth , o=slabAtMaxDepth ; d>=fullDepth ; d-- , o>>=1 ) + { + if( d<=tree._maxDepth ) + { + if( InteriorSlab( d , o ) ) + { + // Copy the edges from finer + if( d=fullDepth ; d-- , o>>=1 ) + { + if( d<=tree._maxDepth ) + { + auto faceIndexFunctor = [&]( const TreeNode *node , typename HyperCube::Cube< Dim >::template Element< 2 > f ) + { + HyperCube::Direction dir ; unsigned int coIndex; + f.factor( dir , coIndex ); + int depth , offset[Dim]; + tree.depthAndOffset( node , depth , offset ); + LevelSetExtraction::Key< Dim > key = keyGenerator( depth , offset , f ); + if ( dir==HyperCube::BACK && ( (((unsigned int)offset[Dim-1]+0)<<(maxDepth-depth)) slabEndAtMaxDepth ) ) key[Dim-1] = keyGenerator.cornerIndex( maxDepth , slabEndAtMaxDepth ); + return key; + }; + if( InteriorSlab( d , o ) ) SetLevelSet( keyGenerator , faceIndexFunctor , tree , d , o , slabValues[d].sliceValues(o) , slabValues[d].sliceValues(o+1) , slabValues[d].xSliceValues(o) , slabValues[d].sliceScratch(o) , slabValues[d].sliceScratch(o+1) , slabValues[d].xSliceScratch(o) , mesh , polygonMesh , addBarycenter , vertexOffset , flipOrientation ); + } + if( !(o&1) && !boundary ) break; + } + stats.surfaceTime += Time()-t; + }; + + InitSlice( slabStartAtMaxDepth ); + InitSlab( slabStartAtMaxDepth , true ); // This needs to be done in case the slice wants to push iso-vertices down to the slab + SetSliceValues( slabStartAtMaxDepth ); + SetSliceIso( slabStartAtMaxDepth ); + FinalizeSlice( slabStartAtMaxDepth ); + + // Iterate over the slabs at the finest level + for( unsigned int slab=slabStartAtMaxDepth ; slab std::mutex LevelSetExtractor< 3 , Real , Vertex >::_pointInsertionMutex; +template< class Real , class Vertex > std::atomic< size_t > LevelSetExtractor< 3 , Real , Vertex >::_BadRootCount; diff --git a/Src/FEMTree.LevelSet.inl b/Src/FEMTree.LevelSet.inl new file mode 100644 index 00000000..034ae03d --- /dev/null +++ b/Src/FEMTree.LevelSet.inl @@ -0,0 +1,829 @@ +/* +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 "PreProcessor.h" +#include "MarchingCubes.h" + +// Level-set extraction data +namespace LevelSetExtraction +{ + ///////// + // Key // + ///////// + template< unsigned int Dim > + struct Key + { + protected: + template< unsigned int _Dim > friend struct KeyGenerator; + public: + unsigned int idx[Dim]; + + Key( void ){ for( unsigned int d=0 ; d using KeyMap = std::unordered_map< Key< Dim > , Data , typename Key< Dim >::Hasher >; + + ///////////// + // IsoEdge // + ///////////// + template< unsigned int Dim > + struct IsoEdge + { + Key< Dim > vertices[2]; + IsoEdge( void ) {} + IsoEdge( Key< Dim > v1 , Key< Dim > v2 ){ vertices[0] = v1 , vertices[1] = v2; } + Key< Dim > &operator[]( int idx ){ return vertices[idx]; } + const Key< Dim > &operator[]( int idx ) const { return vertices[idx]; } + }; + + ///////////////////// + // HyperCubeTables // + ///////////////////// + template< unsigned int D , unsigned int ... Ks > struct HyperCubeTables{}; + + template< unsigned int D , unsigned int K1 , unsigned int K2 > + struct HyperCubeTables< D , K1 , K2 > + { + // The number of K1-dimensional elements in a D-dimensional cube + static constexpr unsigned int ElementNum1 = HyperCube::Cube< D >::template ElementNum< K1 >(); + // The number of K2-dimensional elements in a D-dimensional cube + static constexpr unsigned int ElementNum2 = HyperCube::Cube< D >::template ElementNum< K2 >(); + // The number of K2-dimensional elements overlapping the K1-dimensional element + static constexpr unsigned int OverlapElementNum = HyperCube::Cube< D >::template OverlapElementNum< K1 , K2 >(); + // The list of K2-dimensional elements overlapping the K1-dimensional element + static typename HyperCube::Cube< D >::template Element< K2 > OverlapElements[ ElementNum1 ][ OverlapElementNum ]; + // Indicates if the K2-dimensional element overlaps the K1-dimensional element + static bool Overlap[ ElementNum1 ][ ElementNum2 ]; + + static void SetTables( void ) + { + for( typename HyperCube::Cube< D >::template Element< K1 > e ; e::template ElementNum< K1 >() ; e++ ) + { + for( typename HyperCube::Cube< D >::template Element< K2 > _e ; _e::template ElementNum< K2 >() ; _e++ ) + Overlap[e.index][_e.index] = HyperCube::Cube< D >::Overlap( e , _e ); + HyperCube::Cube< D >::OverlapElements( e , OverlapElements[e.index] ); + } + if( !K2 ) HyperCubeTables< D , K1 >::SetTables(); + } + }; + + template< unsigned int D , unsigned int K > + struct HyperCubeTables< D , K > + { + static constexpr unsigned int IncidentCubeNum = HyperCube::Cube< D >::template IncidentCubeNum< K >(); + static constexpr unsigned int ElementNum = HyperCube::Cube< D >::template ElementNum< K >(); + static unsigned int CellOffset[ ElementNum ][ IncidentCubeNum ]; + static unsigned int IncidentElementCoIndex[ ElementNum ][ IncidentCubeNum ]; + static unsigned int IncidentElementIndex[ ElementNum ][ IncidentCubeNum ]; + static unsigned int CellOffsetAntipodal[ ElementNum ]; + static typename HyperCube::Cube< D >::template IncidentCubeIndex< K > IncidentCube[ ElementNum ]; + static typename HyperCube::Direction Directions[ ElementNum ][ D ]; + + static void SetTables( void ) + { + for( typename HyperCube::Cube< D >::template Element< K > e ; e::template ElementNum< K >() ; e++ ) + { + for( typename HyperCube::Cube< D >::template IncidentCubeIndex< K > i ; i::template IncidentCubeNum< K >() ; i++ ) + { + CellOffset[e.index][i.index] = HyperCube::Cube< D >::CellOffset( e , i ); + IncidentElementCoIndex[e.index][i.index] = HyperCube::Cube< D >::IncidentElement( e , i ).coIndex(); + IncidentElementIndex[e.index][i.index] = HyperCube::Cube< D >::IncidentElement( e , i ).index; + } + CellOffsetAntipodal[e.index] = HyperCube::Cube< D >::CellOffset( e , HyperCube::Cube< D >::IncidentCube( e ).antipodal() ); + IncidentCube[ e.index ] = HyperCube::Cube< D >::IncidentCube( e ); + e.directions( Directions[e.index] ); + } + } + }; + + template< unsigned int D , unsigned int K1=D , unsigned int K2=D > + static void SetHyperCubeTables( void ) + { + if constexpr( K2!=0 ) + { + HyperCubeTables< D , K1 , K2 >::SetTables(); + SetHyperCubeTables< D , K1 , K2-1 >(); + } + else if constexpr( K1!=0 && K2==0 ) + { + HyperCubeTables< D , K1 , K2 >::SetTables(); + SetHyperCubeTables< D , K1-1 , D >(); + } + else if constexpr( D!=1 && K1==0 && K2==0 ) + { + HyperCubeTables< D , K1 , K2 >::SetTables(); + SetHyperCubeTables< D-1 , D-1 , D-1 >(); + } + else HyperCubeTables< D , K1 , K2 >::SetTables(); + } + + // A helper class for storing a static array + template< unsigned int Indices > + struct _Indices + { + node_index_type idx[Indices]; + _Indices( void ){ for( unsigned int i=0 ; i + struct _CellIndices + { + static const unsigned int ElementNum = HyperCube::Cube< Dim >::template ElementNum< CellDim >(); + using Type = _Indices< ElementNum >; + }; + + // A helper struct for storing arrays of different types of indices + template< unsigned int Dim , typename T > struct _Tables{}; + template< unsigned int Dim , unsigned int ... CellDimensions > struct _Tables< Dim , std::integer_sequence< unsigned int , CellDimensions ... > > + { + typedef std::tuple< Pointer( typename _CellIndices< Dim , CellDimensions >::Type ) ... > Type; + }; + + // Temporary data used for tracking ownership of cells shared by different nodes + template< unsigned int Dim , unsigned int MaxCellDim > + struct _Scratch + { + Pointer( node_index_type ) maps[MaxCellDim+1]; + _Scratch( void ) : _reserved(0) { for( unsigned int i=0 ; i<=MaxCellDim ; i++ ) maps[i] = NullPointer( node_index_type ); } + ~_Scratch( void ){ clear(); } + void clear( void ){ for( unsigned int i=0 ; i<=MaxCellDim ; i++ ) DeletePointer( maps[i] ); } + void resize( size_t sz ) + { + if( sz>_reserved ) + { + clear(); + _allocate<0>( sz ); + _reserved = sz; + } + _zeroOut<0>( sz ); + } + protected: + + template< unsigned int CellDim > + void _allocate( size_t sz ) + { + maps[ CellDim ] = NewPointer< node_index_type >( sz * HyperCube::Cube< Dim >::template ElementNum< CellDim >() ); + + if constexpr( CellDim==MaxCellDim ) return; + else _allocate< CellDim+1 >( sz ); + } + + template< unsigned int CellDim > + void _zeroOut( size_t sz ) + { + memset( maps[CellDim] , 0 , sizeof(node_index_type) * sz * HyperCube::Cube< Dim >::template ElementNum< CellDim >() ); + + if constexpr( CellDim==MaxCellDim ) return; + else _zeroOut< CellDim+1 >( sz ); + } + size_t _reserved; + }; + + /////////////////// + // CellIndexData // + /////////////////// + // A data-struture that allows us to take a node together with a local cell index and returns the global cell's index + template< unsigned int Dim , unsigned int _MaxCellDim > + struct CellIndexData + { + static const unsigned int MaxCellDim = _MaxCellDim; + using TreeNode = RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >; + + // Static arrays for holding specific dimension cell indices + template< unsigned int CellDim > using CellIndices = typename _CellIndices< Dim , CellDim >::Type; + + // A tuple of pointers to cell indices of dimensions {0,...,MaxCellDim} + using TablesType = typename _Tables< Dim , std::make_integer_sequence< unsigned int , MaxCellDim+1 > >::Type; + + // The tables holding the cell indices of different dimensions + TablesType tables; + + // The count of the different number of cells + size_t counts[MaxCellDim+1]; + + CellIndexData( void ) : _size(0) , _capacity(0) { _init<0>(); } + ~CellIndexData( void ){ clear(); } + + void clear( void ){ _clear<0>(); } + void resize( size_t sz ) + { + if( sz>_capacity ) + { + _clear<0>(); + _allocate<0>( sz ); + _capacity = sz; + } + else for( unsigned int d=0 ; d<=MaxCellDim ; d++ ) counts[d] = 0; + _size = sz; + } + size_t size( void ) const { return _size; } + + void read( BinaryStream &stream ) + { + if( !stream.read( _size ) ) ERROR_OUT( "Failed to read node count" ); + resize( _size ); + if( _size ) _read<0>( stream ); + } + + void write( BinaryStream &stream ) const + { + stream.write( _size ); + if( _size ) _write<0>( stream ); + } + + protected: + size_t _size , _capacity; + + template< unsigned int CellDim > + void _init( void ) + { + counts[CellDim] = 0; + std::get< CellDim >( tables ) = NullPointer( CellIndices< CellDim > ); + + if constexpr( CellDim==MaxCellDim ) return; + else _init< CellDim+1 >(); + } + + template< unsigned int CellDim > + void _clear( void ) + { + counts[CellDim] = 0; + DeletePointer( std::get< CellDim >( tables ) ); + + if constexpr( CellDim==MaxCellDim ) return; + else _clear< CellDim+1 >(); + } + + template< unsigned int CellDim > + void _allocate( size_t sz ) + { + std::get< CellDim >( tables ) = NewPointer< CellIndices< CellDim > >( sz ); + + if constexpr( CellDim==MaxCellDim ) return; + else _allocate< CellDim+1 >( sz ); + } + + template< unsigned int CellDim > + void _read( BinaryStream &stream ) + { + if( !stream.read( counts[CellDim] ) ) ERROR_OUT( "Failed to read count at dimension: " , CellDim ); + if( !stream.read( std::get< CellDim >( tables ) , _size ) ) ERROR_OUT( "Failed to read table at dimension: " , CellDim ); + + if constexpr( CellDim==MaxCellDim ) return; + else _read< CellDim+1 >( stream ); + } + + template< unsigned int CellDim > + void _write( BinaryStream &stream ) const + { + stream.write( counts[CellDim] ); + stream.write( std::get< CellDim >( tables ) , _size ); + + if constexpr( CellDim==MaxCellDim ) return; + else _write< CellDim+1 >( stream ); + } + }; + + /////////////////////// + // FullCellIndexData // + /////////////////////// + // A data-struture that allows us to take a node together with a local cell index and returns the global cell's index + // [WARNING] Do we want to go up to Dim or up to Dim-1? + template< unsigned int Dim > + struct FullCellIndexData : public CellIndexData< Dim , Dim > + { + static const unsigned int MaxCellDim = CellIndexData< Dim , Dim >::MaxCellDim; + template< unsigned int CellDim > using CellIndices = typename CellIndexData< Dim , Dim >::template CellIndices< CellDim >; + using TreeNode = RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >; + using ConstOneRingNeighborKey = typename TreeNode::template ConstNeighborKey< IsotropicUIntPack< Dim , 1 > , IsotropicUIntPack< Dim , 1 > >; + using ConstNeighbors = typename TreeNode::template ConstNeighbors< IsotropicUIntPack< Dim , 3 > >; + using CellIndexData< Dim , Dim >::tables; + using CellIndexData< Dim , Dim >::size; + using CellIndexData< Dim , Dim >::resize; + using CellIndexData< Dim , Dim >::counts; + + node_index_type nodeOffset; + + FullCellIndexData( void ) : nodeOffset(0) {} + + void read( BinaryStream &stream ) + { + if( !stream.read( nodeOffset ) ) ERROR_OUT( "Failed to read node ofset" ); + CellIndexData< Dim , MaxCellDim >::read( stream ); + } + + void write( BinaryStream &stream ) const + { + stream.write( nodeOffset ); + CellIndexData< Dim , MaxCellDim >::write( stream ); + } + + void set( const SortedTreeNodes< Dim > &sNodes , int depth ) + { + std::pair< node_index_type , node_index_type > span( sNodes.begin( depth ) , sNodes.end( depth ) ); + nodeOffset = (size_t)span.first; + resize( (size_t)( span.second-span.first ) ); + _scratch.resize( size() ); + + std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i( neighbors , _scratch.maps ); + } + ); + + _setCounts<0>( _scratch.maps ); + ThreadPool::Parallel_for( 0 , size() , [&]( unsigned int , size_t i ){ _setTables<0>( (unsigned int)i , _scratch.maps ); } ); + } + + // Maps from tree nodes (and their associated indices) to the associated indices for the cell indices + template< unsigned int CellDim > CellIndices< CellDim > &indices( const TreeNode *node ) { return std::get< CellDim >( tables )[ node->nodeData.nodeIndex - nodeOffset ]; } + template< unsigned int CellDim > CellIndices< CellDim > &indices( node_index_type nodeIndex ) { return std::get< CellDim >( tables )[ nodeIndex - nodeOffset ]; } + template< unsigned int CellDim > const CellIndices< CellDim > &indices( const TreeNode *node ) const { return std::get< CellDim >( tables )[ node->nodeData.nodeIndex - nodeOffset ]; } + template< unsigned int CellDim > const CellIndices< CellDim > &indices( node_index_type nodeIndex ) const { return std::get< CellDim >( tables )[ nodeIndex - nodeOffset ]; } + + protected: + _Scratch< Dim , MaxCellDim > _scratch; + + template< unsigned int CellDim > + void _setProcess( const ConstNeighbors& neighbors , Pointer( node_index_type ) maps[MaxCellDim+1] ) + { + const TreeNode *node = neighbors.neighbors.data[ WindowIndex< IsotropicUIntPack< Dim , 3 > , IsotropicUIntPack< Dim , 1 > >::Index ]; + node_index_type i = node->nodeData.nodeIndex; + + // Iterate over the cells in the node + for( typename HyperCube::Cube< Dim >::template Element< CellDim > c ; c::template ElementNum< CellDim >() ; c++ ) + { + bool owner = true; + + // The index of the node relative to the cell + typename HyperCube::Cube< Dim >::template IncidentCubeIndex< CellDim > my_ic = HyperCubeTables< Dim , CellDim >::IncidentCube[c.index]; + + // Iterate over the nodes adjacent to the cell + for( typename HyperCube::Cube< Dim >::template IncidentCubeIndex< CellDim > ic ; ic::template IncidentCubeNum< CellDim >() ; ic++ ) + { + // Get the index of node relative to the cell neighbors + unsigned int xx = HyperCubeTables< Dim , CellDim >::CellOffset[c.index][ic.index]; + // If the neighbor exists and comes before, they own the corner + if( IsActiveNode< Dim >( neighbors.neighbors.data[xx] ) && ic::template ElementNum< CellDim >() + c.index; + maps[CellDim][ myCount ] = 1; + // Set the cell index for all nodes incident on the cell + for( typename HyperCube::Cube< Dim >::template IncidentCubeIndex< CellDim > ic ; ic::template IncidentCubeNum< CellDim >() ; ic++ ) // Iterate over the nodes adjacent to the cell + { + unsigned int xx = HyperCubeTables< Dim , CellDim >::CellOffset[c.index][ic.index]; + // If the neighbor exits, sets its corner + if( IsActiveNode< Dim >( neighbors.neighbors.data[xx] ) ) this->template indices< CellDim >( neighbors.neighbors.data[xx] )[ HyperCubeTables< Dim , CellDim >::IncidentElementIndex[c.index][ic.index] ] = myCount; + } + } + } + + if constexpr( CellDim==MaxCellDim ) return; + else _setProcess< CellDim+1 >( neighbors , maps ); + } + + template< unsigned int CellDim > + void _setCounts( Pointer( node_index_type ) maps[MaxCellDim+1] ) + { + node_index_type count = 0; + for( node_index_type i=0 ; i<(node_index_type)size() * (node_index_type)HyperCube::Cube< Dim >::template ElementNum< CellDim >() ; i++ ) + if( maps[CellDim][i] ) maps[CellDim][i] = count++; + counts[ CellDim ] = count; + + if constexpr( CellDim==MaxCellDim ) return; + else _setCounts< CellDim+1 >( maps ); + } + + template< unsigned int CellDim > + void _setTables( unsigned int i , Pointer( node_index_type ) maps[MaxCellDim+1] ) + { + for( unsigned int j=0 ; j::template ElementNum< CellDim >() ; j++ ) + std::get< CellDim >( tables )[i][j] = maps[CellDim][ std::get< CellDim >( tables )[i][j] ]; + + if constexpr( CellDim==MaxCellDim ) return; + else _setTables< CellDim+1 >( i , maps ); + } + }; + + //////////////////////// + // SliceCellIndexData // + //////////////////////// + // A data-struture that allows us to take a node adjacent to a slice together with a local cell index and returns the global cell's index + template< unsigned int Dim > + struct SliceCellIndexData : public CellIndexData< Dim-1 , Dim-1 > + { + static const unsigned int _Dim = Dim-1; + static const unsigned int MaxCellDim = CellIndexData< _Dim , _Dim >::MaxCellDim; + template< unsigned int CellDim > using CellIndices = typename CellIndexData< _Dim , _Dim >::template CellIndices< CellDim >; + using TreeNode = RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >; + using ConstOneRingNeighborKey = typename TreeNode::template ConstNeighborKey< IsotropicUIntPack< Dim , 1 > , IsotropicUIntPack< Dim , 1 > >; + using ConstNeighbors = typename TreeNode::template ConstNeighbors< IsotropicUIntPack< Dim , 3 > >; + using CellIndexData< _Dim , _Dim >::tables; + using CellIndexData< _Dim , _Dim >::size; + using CellIndexData< _Dim , _Dim >::resize; + using CellIndexData< _Dim , _Dim >::counts; + + node_index_type nodeOffset; + + SliceCellIndexData( void ) : nodeOffset(0) {} + + void read( BinaryStream &stream ) + { + if( !stream.read( nodeOffset ) ) ERROR_OUT( "Failed to read node ofset" ); + CellIndexData< _Dim , _Dim >::read( stream ); + } + + void write( BinaryStream &stream ) const + { + stream.write( nodeOffset ); + CellIndexData< _Dim , _Dim >::write( stream ); + } + + void set( const SortedTreeNodes< Dim > &sNodes , int depth , int slice ) + { + std::pair< node_index_type , node_index_type > span( sNodes.begin( depth , slice-1 ) , sNodes.end( depth , slice ) ); + nodeOffset = (size_t)span.first; + resize( (size_t)( span.second - span.first ) ); + _scratch.resize( size() ); + + std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i( neighbors , i<(size_t)sNodes.end( depth , slice-1 ) , _scratch.maps ); + } + ); + + _setCounts<0>( _scratch.maps ); + ThreadPool::Parallel_for( 0 , size() , [&]( unsigned int , size_t i ){ _setTables<0>( (unsigned int)i , _scratch.maps ); } ); + } + + // Maps from tree nodes (and their associated indices) to the associated indices for the cell indices + template< unsigned int CellDim > CellIndices< CellDim > &indices( const TreeNode *node ) { return std::get< CellDim >( tables )[ node->nodeData.nodeIndex - nodeOffset ]; } + template< unsigned int CellDim > CellIndices< CellDim > &indices( node_index_type nodeIndex ) { return std::get< CellDim >( tables )[ nodeIndex - nodeOffset ]; } + template< unsigned int CellDim > const CellIndices< CellDim > &indices( const TreeNode *node ) const { return std::get< CellDim >( tables )[ node->nodeData.nodeIndex - nodeOffset ]; } + template< unsigned int CellDim > const CellIndices< CellDim > &indices( node_index_type nodeIndex ) const { return std::get< CellDim >( tables )[ nodeIndex - nodeOffset ]; } + + protected: + _Scratch< _Dim , MaxCellDim > _scratch; + + template< unsigned int CellDim > + void _setProcess( const ConstNeighbors& neighbors , bool fromBehind , Pointer( node_index_type ) maps[MaxCellDim+1] ) + { + HyperCube::Direction dir = fromBehind ? HyperCube::FRONT : HyperCube::BACK; + const TreeNode *node = neighbors.neighbors.data[ WindowIndex< IsotropicUIntPack< Dim , 3 > , IsotropicUIntPack< Dim , 1 > >::Index ]; + node_index_type i = node->nodeData.nodeIndex; + + // Iterate over the cells in the face + for( typename HyperCube::Cube< _Dim >::template Element< CellDim > _c ; _c::template ElementNum< CellDim >() ; _c++ ) + { + // Get the corresponding index of the cell in the node + typename HyperCube::Cube< Dim >::template Element< CellDim > c( dir , _c.index ); + + bool owner = true; + + // The index of the node relative to the cell + typename HyperCube::Cube< Dim >::template IncidentCubeIndex< CellDim > my_ic = HyperCubeTables< Dim , CellDim >::IncidentCube[c.index]; + + // Iterate over the nodes adjacent to the cell + for( typename HyperCube::Cube< Dim >::template IncidentCubeIndex< CellDim > ic ; ic::template IncidentCubeNum< CellDim >() ; ic++ ) + { + // Get the index of node relative to the cell neighbors + unsigned int xx = HyperCubeTables< Dim , CellDim >::CellOffset[c.index][ic.index]; + // If the neighbor exists and comes before, they own the corner + if( IsActiveNode< Dim >( neighbors.neighbors.data[xx] ) && ic::template ElementNum< CellDim >() + _c.index; + maps[CellDim][ myCount ] = 1; + // Set the cell index for all nodes incident on the cell + for( typename HyperCube::Cube< Dim >::template IncidentCubeIndex< CellDim > ic ; ic::template IncidentCubeNum< CellDim >() ; ic++ ) // Iterate over the nodes adjacent to the cell + { + unsigned int xx = HyperCubeTables< Dim , CellDim >::CellOffset[c.index][ic.index]; + // If the neighbor exits, sets its cell + if( IsActiveNode< Dim >( neighbors.neighbors.data[xx] ) ) this->template indices< CellDim >( neighbors.neighbors.data[xx] )[ HyperCubeTables< Dim , CellDim >::IncidentElementCoIndex[c.index][ic.index] ] = myCount; + } + } + } + + if constexpr( CellDim==MaxCellDim ) return; + else _setProcess< CellDim+1 >( neighbors , fromBehind , maps ); + } + + template< unsigned int CellDim > + void _setCounts( Pointer( node_index_type ) maps[MaxCellDim+1] ) + { + node_index_type count = 0; + for( node_index_type i=0 ; i<(node_index_type)size() * (node_index_type)HyperCube::Cube< _Dim >::template ElementNum< CellDim >() ; i++ ) + if( maps[CellDim][i] ) maps[CellDim][i] = count++; + counts[ CellDim ] = count; + + if constexpr( CellDim==MaxCellDim ) return; + else _setCounts< CellDim+1 >( maps ); + } + + template< unsigned int CellDim > + void _setTables( unsigned int i , Pointer( node_index_type ) maps[MaxCellDim+1] ) + { + for( unsigned int j=0 ; j::template ElementNum< CellDim >() ; j++ ) + std::get< CellDim >( tables )[i][j] = maps[CellDim][ std::get< CellDim >( tables )[i][j] ]; + + if constexpr( CellDim==MaxCellDim ) return; + else _setTables< CellDim+1 >( i , maps ); + } + }; + + /////////////////////// + // SlabCellIndexData // + /////////////////////// + // A data-struture that allows us to take a node adjacent to together with a local cell index and returns the global cell's index + template< unsigned int Dim > + struct SlabCellIndexData : public CellIndexData< Dim-1 , Dim-1 > + { + static const unsigned int _Dim = Dim-1; + static const unsigned int _MaxCellDim = CellIndexData< _Dim , _Dim >::MaxCellDim; + template< unsigned int _CellDim > using CellIndices = typename CellIndexData< _Dim , _Dim >::template CellIndices< _CellDim >; + using TreeNode = RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >; + using ConstOneRingNeighborKey = typename TreeNode::template ConstNeighborKey< IsotropicUIntPack< Dim , 1 > , IsotropicUIntPack< Dim , 1 > >; + using ConstNeighbors = typename TreeNode::template ConstNeighbors< IsotropicUIntPack< Dim , 3 > >; + using CellIndexData< _Dim , _Dim >::tables; + using CellIndexData< _Dim , _Dim >::size; + using CellIndexData< _Dim , _Dim >::resize; + using CellIndexData< _Dim , _Dim >::counts; + + node_index_type nodeOffset; + + SlabCellIndexData( void ) : nodeOffset(0) {} + + void read( BinaryStream &stream ) + { + if( !stream.read( nodeOffset ) ) ERROR_OUT( "Failed to read node ofset" ); + CellIndexData< _Dim , _Dim >::read( stream ); + } + + void write( BinaryStream &stream ) const + { + stream.write( nodeOffset ); + CellIndexData< _Dim , _Dim >::write( stream ); + } + + void set( const SortedTreeNodes< Dim > &sNodes , int depth , int slab ) + { + std::pair< node_index_type , node_index_type > span( sNodes.begin( depth , slab ) , sNodes.end( depth , slab ) ); + nodeOffset = (size_t)span.first; + resize( (size_t)( span.second - span.first ) ); + _scratch.resize( size() ); + + std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i( neighbors , _scratch.maps ); + } + ); + + _setCounts<0>( _scratch.maps ); + ThreadPool::Parallel_for( 0 , size() , [&]( unsigned int , size_t i ){ _setTables<0>( (unsigned int)i , _scratch.maps ); } ); + } + + // Maps from tree nodes (and their associated indices) to the associated indices for the cell indices + template< unsigned int CellDim > CellIndices< CellDim > &indices( const TreeNode *node ) { return std::get< CellDim >( tables )[ node->nodeData.nodeIndex - nodeOffset ]; } + template< unsigned int CellDim > CellIndices< CellDim > &indices( node_index_type nodeIndex ) { return std::get< CellDim >( tables )[ nodeIndex - nodeOffset ]; } + template< unsigned int CellDim > const CellIndices< CellDim > &indices( const TreeNode *node ) const { return std::get< CellDim >( tables )[ node->nodeData.nodeIndex - nodeOffset ]; } + template< unsigned int CellDim > const CellIndices< CellDim > &indices( node_index_type nodeIndex ) const { return std::get< CellDim >( tables )[ nodeIndex - nodeOffset ]; } + + protected: + _Scratch< _Dim , _MaxCellDim > _scratch; + + + template< unsigned int _CellDim > + void _setProcess( const ConstNeighbors& neighbors , Pointer( node_index_type ) maps[_MaxCellDim+1] ) + { + static const unsigned int CellDim = _CellDim+1; + const TreeNode *node = neighbors.neighbors.data[ WindowIndex< IsotropicUIntPack< Dim , 3 > , IsotropicUIntPack< Dim , 1 > >::Index ]; + node_index_type i = node->nodeData.nodeIndex; + + // Iterate over the cells in the face + for( typename HyperCube::Cube< _Dim >::template Element< _CellDim > _c ; _c::template ElementNum< _CellDim >() ; _c++ ) + { + // Get the index of the extruded cell + typename HyperCube::Cube< Dim >::template Element< CellDim > c( HyperCube::CROSS , _c.index ); + bool owner = true; + + // The index of the node relative to the extruded cell + typename HyperCube::Cube< Dim >::template IncidentCubeIndex< CellDim > my_ic = HyperCubeTables< Dim , CellDim >::IncidentCube[c.index]; + + // Iterate over the nodes adjacent to the cell + for( typename HyperCube::Cube< Dim >::template IncidentCubeIndex< CellDim > ic ; ic::template IncidentCubeNum< CellDim >() ; ic++ ) + { + // Get the index of node relative to the cell neighbors + unsigned int xx = HyperCubeTables< Dim , CellDim >::CellOffset[c.index][ic.index]; + // If the neighbor exists and comes before, they own the corner + if( IsActiveNode< Dim >( neighbors.neighbors.data[xx] ) && ic::template ElementNum< _CellDim >() + _c.index; + maps[_CellDim][ myCount ] = 1; + // Set the cell index for all nodes incident on the cell + for( typename HyperCube::Cube< Dim >::template IncidentCubeIndex< CellDim > ic ; ic::template IncidentCubeNum< CellDim >() ; ic++ ) // Iterate over the nodes adjacent to the cell + { + unsigned int xx = HyperCubeTables< Dim , CellDim >::CellOffset[c.index][ic.index]; + // If the neighbor exits, sets its cell + if( IsActiveNode< Dim >( neighbors.neighbors.data[xx] ) ) + this->template indices< _CellDim >( neighbors.neighbors.data[xx] )[ HyperCubeTables< Dim , CellDim >::IncidentElementCoIndex[c.index][ic.index] ] = myCount; + } + } + } + + if constexpr( _CellDim==_MaxCellDim ) return; + else _setProcess< _CellDim+1 >( neighbors , maps ); + } + + template< unsigned int _CellDim > + void _setCounts( Pointer( node_index_type ) maps[_MaxCellDim+1] ) + { + node_index_type count = 0; + for( node_index_type i=0 ; i<(node_index_type)size() * (node_index_type)HyperCube::Cube< _Dim >::template ElementNum< _CellDim >() ; i++ ) + if( maps[_CellDim][i] ) maps[_CellDim][i] = count++; + counts[ _CellDim ] = count; + + if constexpr( _CellDim==_MaxCellDim ) return; + else _setCounts< _CellDim+1 >( maps ); + } + + template< unsigned int _CellDim > + void _setTables( unsigned int i , Pointer( node_index_type ) maps[_MaxCellDim+1] ) + { + for( unsigned int j=0 ; j::template ElementNum< _CellDim >() ; j++ ) + std::get< _CellDim >( tables )[i][j] = maps[_CellDim][ std::get< _CellDim >( tables )[i][j] ]; + + if constexpr( _CellDim==_MaxCellDim ) return; + else _setTables< _CellDim+1 >( i , maps ); + } + }; + + ////////////////// + // KeyGenerator // + ////////////////// + template< unsigned int Dim > + struct KeyGenerator + { + KeyGenerator( int maxDepth ) : _maxDepth(maxDepth){} + + template< unsigned int CellDim > + Key< Dim > operator()( int depth , const int offset[Dim] , typename HyperCube::Cube< Dim >::template Element< CellDim > e ) const + { + static_assert( ( CellDim<=Dim ) , "[ERROR] Cell dimension cannot exceed total dimension" ); + Key< Dim > key; + const HyperCube::Direction* x = HyperCubeTables< Dim , CellDim >::Directions[ e.index ]; + for( int dd=0 ; dd operator()( int depth , int offset , Key< Dim-1 > key ) const + { + Key< Dim > pKey; + if( depth>_maxDepth ) ERROR_OUT( "Depth cannot exceed max depth: " , depth , " <= " , _maxDepth ); + for( unsigned int d=0 ; d key ) const + { + std::stringstream stream; + stream << "("; + for( unsigned int d=0 ; d>=1; + while( !(key[d]&1) ) depth-- , key[d]>>=1; + stream << "[" << (((key[d]-1)/2)<<(_maxDepth-depth)) << "," << (((key[d]+1)/2)<<(_maxDepth-depth)) << "]"; + } + else stream << (key[d]>>2); + } + stream << ")/" << (1<<_maxDepth); + return stream.str(); + } + + int maxDepth( void ) const { return _maxDepth; } + + protected: + int _maxDepth; + }; + + template< unsigned int D , unsigned int K > + unsigned int HyperCubeTables< D , K >::CellOffset[ ElementNum ][ IncidentCubeNum ]; + template< unsigned int D , unsigned int K > + unsigned int HyperCubeTables< D , K >::IncidentElementCoIndex[ ElementNum ][ IncidentCubeNum ]; + template< unsigned int D , unsigned int K > + unsigned int HyperCubeTables< D , K >::IncidentElementIndex[ ElementNum ][ IncidentCubeNum ]; + template< unsigned int D , unsigned int K > + unsigned int HyperCubeTables< D , K >::CellOffsetAntipodal[ ElementNum ]; + template< unsigned int D , unsigned int K > + typename HyperCube::Cube< D >::template IncidentCubeIndex < K > HyperCubeTables< D , K >::IncidentCube[ ElementNum ]; + template< unsigned int D , unsigned int K > + typename HyperCube::Direction HyperCubeTables< D , K >::Directions[ ElementNum ][ D ]; + template< unsigned int D , unsigned int K1 , unsigned int K2 > + typename HyperCube::Cube< D >::template Element< K2 > HyperCubeTables< D , K1 , K2 >::OverlapElements[ ElementNum1 ][ OverlapElementNum ]; + template< unsigned int D , unsigned int K1 , unsigned int K2 > + bool HyperCubeTables< D , K1 , K2 >::Overlap[ ElementNum1 ][ ElementNum2 ]; +} diff --git a/Src/FEMTree.SortedTreeNodes.inl b/Src/FEMTree.SortedTreeNodes.inl index 702e95f9..3d3b28d7 100644 --- a/Src/FEMTree.SortedTreeNodes.inl +++ b/Src/FEMTree.SortedTreeNodes.inl @@ -36,6 +36,7 @@ SortedTreeNodes< Dim >::SortedTreeNodes( void ) treeNodes = NullPointer( TreeNode* ); _levels = 0; } + template< unsigned int Dim > SortedTreeNodes< Dim >::~SortedTreeNodes( void ) { @@ -43,27 +44,72 @@ SortedTreeNodes< Dim >::~SortedTreeNodes( void ) FreePointer( _sliceStart ); DeletePointer( treeNodes ); } + template< unsigned int Dim > -void SortedTreeNodes< Dim >::set( TreeNode& root , std::vector< node_index_type >* map ) +void SortedTreeNodes< Dim >::write( BinaryStream &stream ) const { - size_t sz = set( root ); + stream.write( _levels ); + for( int l=0 ; l<_levels ; l++ ) + { + size_t sz = ((size_t)1< +void SortedTreeNodes< Dim >::read( BinaryStream &stream , TreeNode &root ) +{ + for( int l=0 ; l<_levels ; l++ ) FreePointer( _sliceStart[l] ); + FreePointer( _sliceStart ); + DeletePointer( treeNodes ); + + _levels = 0; + _sliceStart = NullPointer( Pointer( node_index_type ) ); + treeNodes = NullPointer( TreeNode* ); + + if( !stream.read( _levels ) ) ERROR_OUT( "Failed to read levels" ); + if( _levels ) { - map->resize( sz , -1 ); - for( node_index_type i=0 ; i<_sliceStart[_levels-1][(size_t)1<<(_levels-1)] ; i++ ) if( treeNodes[i]->nodeData.nodeIndex>=0 ) (*map)[ treeNodes[i]->nodeData.nodeIndex ] = i; + _sliceStart = AllocPointer< Pointer( node_index_type ) >( _levels ); + for( int l=0 ; l<_levels ; l++ ) + { + size_t sz = ((size_t)1<( sz ); + if( !stream.read( _sliceStart[l] , sz ) ) ERROR_OUT( "Failed to read slices at level: " , l ); + } + + size_t sz = _sliceStart[_levels-1][(size_t)1<<(_levels-1)]; + treeNodes = NewPointer< TreeNode* >( sz ); + auto nodeFunctor = [&]( TreeNode *n ){ if( n->nodeData.nodeIndex>=0 && n->nodeData.nodeIndex<(node_index_type)sz ) treeNodes[ n->nodeData.nodeIndex ] = n; }; + root.processNodes( nodeFunctor ); } - for( node_index_type i=0 ; i<_sliceStart[_levels-1][(size_t)1<<(_levels-1)] ; i++ ) treeNodes[i]->nodeData.nodeIndex = i; } + template< unsigned int Dim > -size_t SortedTreeNodes< Dim >::set( TreeNode& root ) +void SortedTreeNodes< Dim >::reset( TreeNode& root , std::vector< node_index_type > &map ) { - size_t sz = 0; - _levels = root.maxDepth()+1; + _set( root ); + map.resize( _sliceStart[_levels-1][(size_t)1<<(_levels-1)] , -1 ); + for( node_index_type i=0 ; i<_sliceStart[_levels-1][(size_t)1<<(_levels-1)] ; i++ ) + { + if( treeNodes[i]->nodeData.nodeIndex>=0 ) map[i] = treeNodes[i]->nodeData.nodeIndex; + treeNodes[i]->nodeData.nodeIndex = i; + }} + +template< unsigned int Dim > +void SortedTreeNodes< Dim >::set( TreeNode& root ) +{ + _set( root ); + for( node_index_type i=0 ; i<_sliceStart[_levels-1][(size_t)1<<(_levels-1)] ; i++ ) treeNodes[i]->nodeData.nodeIndex = i; +} +template< unsigned int Dim > +void SortedTreeNodes< Dim >::_set( TreeNode& root ) +{ if( _sliceStart ) for( int d=0 ; d<_levels ; d++ ) FreePointer( _sliceStart[d] ); FreePointer( _sliceStart ); DeletePointer( treeNodes ); + _levels = root.maxDepth()+1; _sliceStart = AllocPointer< Pointer( node_index_type ) >( _levels ); for( int l=0 ; l<_levels ; l++ ) @@ -73,16 +119,16 @@ size_t SortedTreeNodes< Dim >::set( TreeNode& root ) } // Count the number of nodes in each slice - for( TreeNode* node = root.nextNode() ; node ; node = root.nextNode( node ) ) + auto nodeFunctor = [&]( TreeNode *node ) { - if( node->nodeData.nodeIndex>=0 ) sz = std::max< size_t >( node->nodeData.nodeIndex+1 , sz ); if( !GetGhostFlag< Dim >( node ) ) { int d , off[Dim]; node->depthAndOffset( d , off ); _sliceStart[d][ off[Dim-1]+1 ]++; } - } + }; + root.processNodes( nodeFunctor ); // Get the start index for each slice { @@ -98,11 +144,17 @@ size_t SortedTreeNodes< Dim >::set( TreeNode& root ) treeNodes = NewPointer< TreeNode* >( _sliceStart[_levels-1][(size_t)1<<(_levels-1)] ); // Add the tree nodes - for( TreeNode* node=root.nextNode() ; node ; node=root.nextNode( node ) ) if( !GetGhostFlag< Dim >( node ) ) { - int d , off[Dim]; - node->depthAndOffset( d , off ); - treeNodes[ _sliceStart[d][ off[Dim-1] ]++ ] = node; + auto nodeFunctor = [&]( TreeNode *node ) + { + if( !GetGhostFlag< Dim >( node ) ) + { + int d , off[Dim]; + node->depthAndOffset( d , off ); + treeNodes[ _sliceStart[d][ off[Dim-1] ]++ ] = node; + } + }; + root.processNodes( nodeFunctor ); } // Shift the slice offsets up since we incremented as we added @@ -111,6 +163,5 @@ size_t SortedTreeNodes< Dim >::set( TreeNode& root ) 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; } - return sz; } diff --git a/Src/FEMTree.System.inl b/Src/FEMTree.System.inl index 36f301c5..6ad00ce6 100644 --- a/Src/FEMTree.System.inl +++ b/Src/FEMTree.System.inl @@ -287,7 +287,6 @@ int FEMTree< Dim , Real >::_solveFullSystemGS( UIntPack< FEMSigs ... > , const t } t = Time(); - MemoryUsage(); for( int i=0 ; i::_solveFullSystemGS( UIntPack< FEMSigs ... > , const t FreePointer( _constraints ); } if( computeNorms ) stats.bNorm2 = bNorm , stats.inRNorm2 = inRNorm , stats.outRNorm2 = outRNorm; - MemoryUsage(); return iters; } @@ -539,7 +537,6 @@ int FEMTree< Dim , Real >::_solveSlicedSystemGS( UIntPack< FEMSigs ... > , const DeletePointer( mcIndices ); FreePointer( _D ); } - MemoryUsage(); return iters; } #undef MOD @@ -637,8 +634,6 @@ int FEMTree< Dim , Real >::_solveSystemCG( UIntPack< FEMSigs ... > , const typen stats.bNorm2 = bNorm , stats.inRNorm2 = inRNorm , stats.outRNorm2 = outRNorm; } FreePointer( _constraints ); - - MemoryUsage(); return iter; } @@ -797,8 +792,6 @@ void FEMTree< Dim , Real >::_solveRegularMG( UIntPack< FEMSigs ... > , typename } solveTime = Time() - solveTime; - MemoryUsage(); - for( int d=0 ; d<=_baseDepth ; d++ ) { FreePointer( D[d] ); @@ -1621,7 +1614,6 @@ int FEMTree< Dim , Real >::_getSliceMatrixAndProlongationConstraints( UIntPack< #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 // SHOW_WARNINGS #endif // !_WIN32 && !_WIN64 - MemoryUsage(); return 1; } @@ -2627,18 +2619,31 @@ void FEMTree< Dim , Real >::_RegularGridUpSample( UIntPack< FEMSigs ... > , cons template< unsigned int Dim , class Real > template< unsigned int ... FEMSigs , typename T , typename TDotT , typename ... InterpolationInfos > -DenseNodeData< T , UIntPack< FEMSigs ... > > FEMTree< Dim , Real >::solveSystem( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , TDotT Dot , LocalDepth maxSolveDepth , const typename FEMTree< Dim , Real >::SolverInfo& solverInfo , std::tuple< InterpolationInfos *... > interpolationInfos ) const +DenseNodeData< T , UIntPack< FEMSigs ... > > FEMTree< Dim , Real >::solveSystem( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , TDotT Dot , LocalDepth minSolveDepth , LocalDepth maxSolveDepth , const typename FEMTree< Dim , Real >::SolverInfo& solverInfo , std::tuple< InterpolationInfos *... > interpolationInfos ) const { DenseNodeData< T , UIntPack< FEMSigs ... > > solution; - solveSystem( UIntPack< FEMSigs ... >() , F , constraints , solution , Dot , maxSolveDepth , solverInfo , interpolationInfos ); + solveSystem( UIntPack< FEMSigs ... >() , F , constraints , solution , Dot , minSolveDepth , maxSolveDepth , solverInfo , interpolationInfos ); return solution; } template< unsigned int Dim , class Real > template< unsigned int ... FEMSigs , typename T , typename TDotT , typename ... InterpolationInfos > -void FEMTree< Dim , Real >::solveSystem( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , DenseNodeData< T , UIntPack< FEMSigs ... > >& solution , TDotT Dot , LocalDepth maxSolveDepth , const typename FEMTree< Dim , Real >::SolverInfo& solverInfo , std::tuple< InterpolationInfos *... > interpolationInfos ) const +void FEMTree< Dim , Real >::solveSystem( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , DenseNodeData< T , UIntPack< FEMSigs ... > >& solution , TDotT Dot , LocalDepth minSolveDepth , LocalDepth maxSolveDepth , const typename FEMTree< Dim , Real >::SolverInfo& solverInfo , std::tuple< InterpolationInfos *... > interpolationInfos ) const { static_assert( Dim==sizeof ... ( FEMSigs ) , "[ERROR] FEMTree:solveSystem: Dimensions and number of signatures don't match" ); - if( maxSolveDepth>_maxDepth ) ERROR_OUT( "Solver depth cannot exceed maximum depth: " , maxSolveDepth , " <= " , _maxDepth ); + + if( maxSolveDepth>_maxDepth ) + { + WARN( "Solver depth should not exceed maximum depth: " , maxSolveDepth , " <= " , _maxDepth ); + maxSolveDepth = _maxDepth; + } + if( minSolveDepth>maxSolveDepth ) return; + else if( minSolveDepth<_baseDepth ) + { + WARN( "Minimum solver depth should not be smaller than base solver depth: " , minSolveDepth , " >= " , _baseDepth ); + minSolveDepth = _baseDepth; + } + + // Mark all nodes that define valid finite elements _setFEM1ValidityFlags( UIntPack< FEMSigs ... >() ); PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > > bsData( sizeof...(InterpolationInfos)==0 ? 0 : maxSolveDepth ); @@ -2733,7 +2738,7 @@ void FEMTree< Dim , Real >::solveSystem( UIntPack< FEMSigs ... > , typename Base else if( solverInfo.vCycles<10 ) printf( "Cycle[%d] Depth[%2d/%d]:\t" , cycle , depth , maxSolveDepth ); else printf( "Cycle[%2d] Depth[%2d/%d]:\t" , cycle , depth , maxSolveDepth ); - printf( "Updated constraints / Got system / Solved in: %6.3f / %6.3f / %6.3f\t(%.3f MB)\tNodes: %llu\n" , sStats.constraintUpdateTime , sStats.systemTime , sStats.solveTime , _LocalMemoryUsage , (unsigned long long)femNodes ); + printf( "Updated constraints / Got system / Solved in: %6.3f / %6.3f / %6.3f\t(%d MB)\tNodes: %llu\n" , sStats.constraintUpdateTime , sStats.systemTime , sStats.solveTime , MemoryInfo::PeakMemoryUsageMB() , (unsigned long long)femNodes ); } if( solverInfo.showResidual && showResidual ) { @@ -2782,7 +2787,7 @@ void FEMTree< Dim , Real >::solveSystem( UIntPack< FEMSigs ... > , typename Base else { bool coarseToFine = false; - for( LocalDepth d=depth ; d>=_baseDepth ; d-- ) + for( LocalDepth d=depth ; d>=minSolveDepth ; d-- ) { sStats.constraintUpdateTime = 0; showResidual = ( d!=_baseDepth ); @@ -2793,7 +2798,10 @@ void FEMTree< Dim , Real >::solveSystem( UIntPack< FEMSigs ... > , typename Base sStats.constraintUpdateTime += Time()-t; actualIters = iters; // In the restriction phase we do not solve at the coarsest resolution since we will do so in the prolongation phase - if( d==_baseDepth ) _solveRegularMG( UIntPack< FEMSigs ... >() , F , bsData , std::min< LocalDepth >( _baseDepth , maxSolveDepth ) , _solution , d==_maxDepth ? _constraints : _residualConstraints , Dot , solverInfo.baseVCycles , iters , sStats , solverInfo.showResidual , solverInfo.cgAccuracy , interpolationInfos ); + if( d==_baseDepth ) + { + if( solverInfo.baseVCycles ) _solveRegularMG( UIntPack< FEMSigs ... >() , F , bsData , std::min< LocalDepth >( _baseDepth , maxSolveDepth ) , _solution , d==_maxDepth ? _constraints : _residualConstraints , Dot , solverInfo.baseVCycles , iters , sStats , solverInfo.showResidual , solverInfo.cgAccuracy , interpolationInfos ); + } else { if( d>solverInfo.cgDepth ) actualIters = _solveSystemGS( UIntPack< FEMSigs ... >() , Dim!=1 , F , bsData , d , _solution , ( ConstPointer( T ) )_prolongedSolution , d==_maxDepth ? _constraints : _residualConstraints , Dot , iters , coarseToFine , solverInfo.sliceBlockSize , sorWeights , sStats , solverInfo.showResidual , interpolationInfos ); @@ -2812,7 +2820,7 @@ void FEMTree< Dim , Real >::solveSystem( UIntPack< FEMSigs ... > , typename Base sorWeights.sorFunction = solverInfo.sorProlongationFunction; showResidual = true; bool coarseToFine = true; - for( LocalDepth d=_baseDepth ; d<=depth ; d++ ) + for( LocalDepth d=minSolveDepth ; d<=depth ; d++ ) { sStats.constraintUpdateTime = 0; int iters = solverInfo.iters( v , false , d ); @@ -2821,7 +2829,10 @@ void FEMTree< Dim , Real >::solveSystem( UIntPack< FEMSigs ... > , typename Base SetResidualConstraints( d ); sStats.constraintUpdateTime += Time()-t; actualIters = iters; - if( d==_baseDepth ) _solveRegularMG( UIntPack< FEMSigs ... >() , F , bsData , std::min< LocalDepth >( _baseDepth , maxSolveDepth ) , _solution , d==_maxDepth ? _constraints : _residualConstraints , Dot , solverInfo.baseVCycles , iters , sStats , solverInfo.showResidual , solverInfo.cgAccuracy , interpolationInfos ); + if( d==_baseDepth ) + { + if( solverInfo.baseVCycles ) _solveRegularMG( UIntPack< FEMSigs ... >() , F , bsData , std::min< LocalDepth >( _baseDepth , maxSolveDepth ) , _solution , d==_maxDepth ? _constraints : _residualConstraints , Dot , solverInfo.baseVCycles , iters , sStats , solverInfo.showResidual , solverInfo.cgAccuracy , interpolationInfos ); + } else { if( d>solverInfo.cgDepth ) actualIters = _solveSystemGS( UIntPack< FEMSigs ... >() , Dim!=1 , F , bsData , d , _solution , ( ConstPointer( T ) )_prolongedSolution , d==_maxDepth ? _constraints : _residualConstraints , Dot , iters , coarseToFine , solverInfo.sliceBlockSize , sorWeights , sStats , solverInfo.showResidual , interpolationInfos ); @@ -2838,7 +2849,7 @@ void FEMTree< Dim , Real >::solveSystem( UIntPack< FEMSigs ... > , typename Base { if( solverInfo.wCycle ) { - for( int d=maxSolveDepth ; d>_baseDepth ; d-- ) + for( int d=maxSolveDepth ; d>minSolveDepth ; d-- ) { SolveRestriction ( v , d ); SolveProlongation( v , d-1 ); @@ -2858,7 +2869,7 @@ void FEMTree< Dim , Real >::solveSystem( UIntPack< FEMSigs ... > , typename Base { bool coarseToFine = false; std::vector< double > rNorms( maxSolveDepth+1 ); - for( LocalDepth d=maxSolveDepth ; d>=_baseDepth ; d-- ) + for( LocalDepth d=maxSolveDepth ; d>=minSolveDepth ; d-- ) { F.init( d ); SetResidualConstraints( d ); @@ -2871,7 +2882,6 @@ void FEMTree< Dim , Real >::solveSystem( UIntPack< FEMSigs ... > , typename Base printf( "\n" ); } } - MemoryUsage(); FreePointer( _residualConstraints ); FreePointer( _restrictedConstraints ); @@ -2924,7 +2934,6 @@ void FEMTree< Dim , Real >::_addFEMConstraints( UIntPack< FEMSigs ... > , UIntPa maxDepth = std::min< LocalDepth >( maxDepth , _maxDepth ); Pointer( T ) _constraints = AllocPointer< T >( _sNodesEnd( maxDepth-1 ) ); memset( _constraints , 0 , sizeof(T)*( _sNodesEnd(maxDepth-1) ) ); - MemoryUsage(); static const WindowLoopData< UIntPack< BSplineOverlapSizes< CDegrees , FEMDegrees >::OverlapSize ... > > cfemLoopData( []( int c , int* start , int* end ){ BaseFEMIntegrator::ParentOverlapBounds( UIntPack< CDegrees ... >() , UIntPack< FEMDegrees ... >() , c , start , end ); } ); static const WindowLoopData< UIntPack< BSplineOverlapSizes< FEMDegrees , CDegrees >::OverlapSize ... > > femcLoopData( []( int c , int* start , int* end ){ BaseFEMIntegrator::ParentOverlapBounds( UIntPack< FEMDegrees ... >() , UIntPack< CDegrees ... >() , c , start , end ); } ); @@ -3044,7 +3053,6 @@ void FEMTree< Dim , Real >::_addFEMConstraints( UIntPack< FEMSigs ... > , UIntPa } ); if( d>0 && d() , F.tRestrictionProlongation() , d , ( ConstPointer(T) )_constraints + _sNodesBegin(d) , _constraints + _sNodesBegin(d-1) ); - MemoryUsage(); } FreePointer( _constraints ); if( hasCoarserCoefficients ) @@ -3132,8 +3140,6 @@ void FEMTree< Dim , Real >::_addFEMConstraints( UIntPack< FEMSigs ... > , UIntPa { if( _isValidFEM1Node( _sNodes.treeNodes[i] ) && _sNodes.treeNodes[i]->nodeData.getDirichletElementFlag() ) constraints[i] *= (Real)0; } ); - - MemoryUsage(); } template< unsigned int Dim , class Real > @@ -3208,7 +3214,6 @@ void FEMTree< Dim , Real >::_addInterpolationConstraints( DenseNodeData< T , UIn } ); } - MemoryUsage(); } } diff --git a/Src/FEMTree.WeightedSamples.inl b/Src/FEMTree.WeightedSamples.inl index 7b0d6b4a..c6d4e6c6 100644 --- a/Src/FEMTree.WeightedSamples.inl +++ b/Src/FEMTree.WeightedSamples.inl @@ -164,7 +164,7 @@ void FEMTree< Dim , Real >::_addWeightContribution( Allocator< FEMTreeNode > *no { Point< Real , Dim > start; Real w; - _startAndWidth( node , start , w ); + node->startAndWidth( start , w ); for( int dim=0 ; dim::BSplineComponentValues( ( position[dim]-start[dim] ) / w , values[dim] ); } @@ -295,19 +295,13 @@ void FEMTree< Dim , Real >::_splatPointData( Allocator< FEMTreeNode > *nodeAlloc ( ZeroUIntPack< Dim >() , UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportSize ... >() , [&]( int d , int i ){ scratch[d+1] = scratch[d] * values[d][i]; } , - [&]( FEMTreeNode* node ) - { - if( IsActiveNode< Dim >( node ) ) - { - AddAtomic( dataInfo[ node ] , v * (Real)scratch[Dim] ); - } - } , + [&]( FEMTreeNode* node ){ if( IsActiveNode< Dim >( node ) ) AddAtomic( dataInfo[ node ] , v * (Real)scratch[Dim] ); } , neighbors.neighbors() ); } template< unsigned int Dim , class Real > template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > -Real FEMTree< Dim , Real >::_splatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >& densityWeights , Real minDepthCutoff , Point< Real , Dim > position , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& dataInfo , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , LocalDepth minDepth , LocalDepth maxDepth , int dim , Real depthBias ) +Point< Real , 2 > FEMTree< Dim , Real >::_splatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >& densityWeights , Real minDepthCutoff , Point< Real , Dim > position , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& dataInfo , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , LocalDepth minDepth , LocalDepth maxDepth , int dim , Real depthBias ) { // Get the depth and weight at position Real weight , depth; @@ -331,7 +325,8 @@ Real FEMTree< Dim , Real >::_splatPointData( Allocator< FEMTreeNode > *nodeAlloc depth += depthBias; } - if( depth( (Real)-1. , (Real)0. ); + Real rawDepth = depth; if( depthmaxDepth ) depth = Real(maxDepth); @@ -373,16 +368,93 @@ Real FEMTree< Dim , Real >::_splatPointData( Allocator< FEMTreeNode > *nodeAlloc }; Splat( temp , (Real)dx ); if( fabs(1.-dx)>1e-6 ) Splat( temp->parent , (Real)(1.-dx) ); - return weight; + return Point< Real , 2 >( rawDepth , weight ); +} + +template< unsigned int Dim , class Real > +template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > +Point< Real , 2 > FEMTree< Dim , Real >::_splatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >& densityWeights , Real minDepthCutoff , Point< Real , Dim > position , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& dataInfo , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , LocalDepth minDepth , std::function< int ( Point< Real , Dim > ) > &pointDepthFunctor , int dim , Real depthBias ) +{ + // Get the depth and weight at position + Real sampleWeight , sampleDepth; + FEMTreeNode *temp = _spaceRoot; + Point< Real , Dim > myCenter; + Real myWidth; + + int maxDepth = pointDepthFunctor( position ); + { + int depth = 0; + for( int d=0 ; d( temp->children ) ) break; + int cIndex = FEMTreeNode::ChildIndex( myCenter , position ); + temp = temp->children + cIndex; + myWidth /= 2; + for( int d=0 ; d>d) & 1 ) myCenter[d] += myWidth/2; + else myCenter[d] -= myWidth/2; + depth++; + } + _getSampleDepthAndWeight( densityWeights , temp , position , weightKey , sampleDepth , sampleWeight ); + sampleDepth += depthBias; + } + + if( sampleDepth( (Real)-1. , (Real)0. ); + Real rawSampleDepth = sampleDepth; + + if( sampleDepthmaxDepth ) sampleDepth = (Real)maxDepth; + int topDepth = (int)ceil(sampleDepth); + + double dx = 1.0-(topDepth-sampleDepth); + 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->template initChildren< ThreadSafe >( nodeAllocator , _nodeInitializer ); + int cIndex = FEMTreeNode::ChildIndex( myCenter , position ); + temp = &temp->children[cIndex]; + myWidth/=2; + for( int d=0 ; d>d) & 1 ) myCenter[d] += myWidth/2; + else myCenter[d] -= myWidth/2; + } + + auto Splat = [&]( FEMTreeNode *node , Real dx ) + { + double width = 1.0 / ( 1<<_localDepth( temp ) ); + // Scale by: + // weight: the area/volume associated with the sample + // dx: the fraction of the sample splatted into the current depth + // pow( width , -dim ): So that each sample is splatted with a unit volume + V _v = v * sampleWeight / Real( pow( width , dim ) ) * dx; + // V _v = v / Length(v) * dx; +#if defined( __GNUC__ ) && __GNUC__ < 5 +#ifdef SHOW_WARNINGS + #warning "you've got me gcc version<5" +#endif // SHOW_WARNINGS + _splatPointData< CreateNodes , ThreadSafe , V >( nodeAllocator , temp , position , _v , dataInfo , dataKey ); +#else // !__GNUC__ || __GNUC__ >=5 + _splatPointData< CreateNodes , ThreadSafe , V , DataSigs ... >( nodeAllocator , temp , position , _v , dataInfo , dataKey ); +#endif // __GNUC__ || __GNUC__ < 4 + }; + Splat( temp , (Real)dx ); + if( fabs(1.-dx)>1e-6 ) Splat( temp->parent , (Real)(1.-dx) ); + return Point< Real , 2 >( rawSampleDepth , sampleWeight ); } + template< unsigned int Dim , class Real > template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > -Real FEMTree< Dim , Real >::_multiSplatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >* densityWeights , FEMTreeNode* node , Point< Real , Dim > position , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& dataInfo , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , int dim ) +Point< Real , 2 > FEMTree< Dim , Real >::_multiSplatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >* densityWeights , FEMTreeNode* node , Point< Real , Dim > position , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& dataInfo , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , int dim ) { typedef UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportSize ... > SupportSizes; Real _depth , weight; if( densityWeights ) _getSampleDepthAndWeight( *densityWeights , position , weightKey , _depth , weight ); - else weight = (Real)1.; + else _depth=(Real)-1. , weight = (Real)1.; V _v = v * weight; double values[ Dim ][ SupportSizes::Max() ]; @@ -406,7 +478,7 @@ Real FEMTree< Dim , Real >::_multiSplatPointData( Allocator< FEMTreeNode > *node neighbors.neighbors() ); } - return weight; + return Point< Real , 2 >( _depth , weight ); } template< unsigned int Dim , class Real > diff --git a/Src/FEMTree.h b/Src/FEMTree.h index 8f000459..a32d13b6 100644 --- a/Src/FEMTree.h +++ b/Src/FEMTree.h @@ -34,12 +34,13 @@ DAMAGE. // -- [TODO] Modify (public) functions so that template parameters don't need to be passed when they are called // -- [TODO] Confirm that whenever _isValidFEM*Node is called, the flags have already been set. // -- [TODO] Make weight evaluation more efficient in _getSamplesPerNode by reducing the number of calls to getNeighbors - // -- [TODO] For point evaluation: // 1. Have the evaluator store stencils for all depths [DONE] // 2. When testing centers/corners, don't use generic evaluation - // -- [TODO] Support nested parallelism with thread pools +// -- [TODO] Make the node flags protected +// -- [TODO] Identify members that are only valid after finalization +// -- [TODO] Force the MaxDegree and finite-element degrees into the template parameters for the FEMTree so that root vs space-root are set up on construction #ifndef FEM_TREE_INCLUDED #define FEM_TREE_INCLUDED @@ -58,6 +59,7 @@ DAMAGE. #include #include + #ifdef BIG_DATA // The integer type used for indexing the nodes in the octree typedef long long node_index_type; @@ -109,7 +111,6 @@ class FEMTreeNodeData bool getDirichletElementFlag( void ) const { return ( flags & DIRICHLET_ELEMENT_FLAG )!=0; } void setScratchFlag( bool f ) const { if( f ) flags |= SCRATCH_FLAG ; else flags &= ~SCRATCH_FLAG; } bool getScratchFlag( void ) const { return ( flags & SCRATCH_FLAG )!=0; } - bool isGeometrySupported; FEMTreeNodeData( void ); ~FEMTreeNodeData( void ); }; @@ -121,13 +122,15 @@ class SortedTreeNodes protected: Pointer( Pointer( node_index_type ) ) _sliceStart; int _levels; + + void _set( TreeNode& root ); public: Pointer( TreeNode* ) treeNodes; node_index_type begin( int depth ) const { return _sliceStart[depth][0]; } node_index_type end( int depth ) const { return _sliceStart[depth][(size_t)1<(1<=_levels ) ERROR_OUT( "bad depth: 0 <= " , depth , " < " , _levels ); @@ -138,8 +141,12 @@ class SortedTreeNodes SortedTreeNodes( void ); ~SortedTreeNodes( void ); - void set( TreeNode& root , std::vector< node_index_type >* map ); - size_t set( TreeNode& root ); + // Resets the sorted tree nodes and sets map[i] to the index previously stored with the i-th node. + void reset( TreeNode& root , std::vector< node_index_type > &map ); + void set( TreeNode& root ); + + void write( BinaryStream &stream ) const; + void read( BinaryStream &stream , TreeNode &root ); }; template< typename T > struct DotFunctor{}; @@ -167,6 +174,7 @@ struct SupportKey< UIntPack< Degrees ... > > : public RegularTreeNode< sizeof... typedef UIntPack< ( BSplineSupportSizes< Degrees >::SupportEnd ) ... > RightRadii; typedef UIntPack< ( BSplineSupportSizes< Degrees >::SupportSize ) ... > Sizes; }; + template< typename Pack > struct ConstSupportKey{ }; template< unsigned int ... Degrees > struct ConstSupportKey< UIntPack< Degrees ... > > : public RegularTreeNode< sizeof...(Degrees) , FEMTreeNodeData , depth_and_offset_type >::template ConstNeighborKey< UIntPack< (-BSplineSupportSizes< Degrees >::SupportStart ) ... > , UIntPack< BSplineSupportSizes< Degrees >::SupportEnd ... > > @@ -175,6 +183,7 @@ struct ConstSupportKey< UIntPack< Degrees ... > > : public RegularTreeNode< size typedef UIntPack< ( BSplineSupportSizes< Degrees >::SupportEnd ) ... > RightRadii; typedef UIntPack< ( BSplineSupportSizes< Degrees >::SupportSize ) ... > Sizes; }; + template< typename Pack > struct OverlapKey{ }; template< unsigned int ... Degrees > struct OverlapKey< UIntPack< Degrees ... > > : public RegularTreeNode< sizeof...(Degrees) , FEMTreeNodeData , depth_and_offset_type >::template NeighborKey< UIntPack< (-BSplineOverlapSizes< Degrees , Degrees >::OverlapStart ) ... > , UIntPack< BSplineOverlapSizes< Degrees , Degrees >::OverlapEnd ... > > @@ -183,6 +192,7 @@ struct OverlapKey< UIntPack< Degrees ... > > : public RegularTreeNode< sizeof... typedef UIntPack< ( BSplineOverlapSizes< Degrees , Degrees >::OverlapEnd ) ... > RightRadii; typedef UIntPack< ( BSplineOverlapSizes< Degrees , Degrees >::OverlapSize ) ... > Sizes; }; + template< typename Pack > struct ConstOverlapKey{ }; template< unsigned int ... Degrees > struct ConstOverlapKey< UIntPack< Degrees ... > > : public RegularTreeNode< sizeof...(Degrees) , FEMTreeNodeData , depth_and_offset_type >::template ConstNeighborKey< UIntPack< (-BSplineOverlapSizes< Degrees , Degrees >::OverlapStart ) ... > , UIntPack< BSplineOverlapSizes< Degrees , Degrees >::OverlapEnd ... > > @@ -200,6 +210,7 @@ struct PointSupportKey< UIntPack< Degrees ... > > : public RegularTreeNode< size typedef UIntPack< (-BSplineSupportSizes< Degrees >::SupportStart ) ... > RightRadii; typedef UIntPack< ( BSplineSupportSizes< Degrees >::SupportEnd - BSplineSupportSizes< Degrees >::SupportStart + 1 ) ... > Sizes; }; + template< typename Pack > struct ConstPointSupportKey{ }; template< unsigned int ... Degrees > struct ConstPointSupportKey< UIntPack< Degrees ... > > : public RegularTreeNode< sizeof...(Degrees) , FEMTreeNodeData , depth_and_offset_type >::template ConstNeighborKey< UIntPack< BSplineSupportSizes< Degrees >::SupportEnd ... > , UIntPack< (-BSplineSupportSizes< Degrees >::SupportStart ) ... > > @@ -217,6 +228,7 @@ struct CornerSupportKey< UIntPack< Degrees ... > > : public RegularTreeNode< siz typedef UIntPack< (-BSplineSupportSizes< Degrees >::BCornerStart + 1 ) ... > RightRadii; typedef UIntPack< ( BSplineSupportSizes< Degrees >::BCornerSize + 1 ) ... > Sizes; }; + template< typename Pack > struct ConstCornerSupportKey{ }; template< unsigned int ... Degrees > struct ConstCornerSupportKey< UIntPack< Degrees ... > > : public RegularTreeNode< sizeof...(Degrees) , FEMTreeNodeData , depth_and_offset_type >::template ConstNeighborKey< UIntPack< BSplineSupportSizes< Degrees >::BCornerEnd ... > , UIntPack< ( -BSplineSupportSizes< Degrees >::BCornerStart + 1 ) ... > > @@ -256,50 +268,65 @@ struct SparseNodeData< Data , UIntPack< FEMSigs ... > > : public _SparseOrDenseN { static const unsigned int Dim = sizeof ... ( FEMSigs ); - static void WriteSignatures( FILE* fp ) + static void WriteSignatures( BinaryStream &stream ) { unsigned int dim = sizeof ... ( FEMSigs ); - fwrite( &dim , sizeof(unsigned int) , 1 , fp ); + stream.write( dim ); unsigned int femSigs[] = { FEMSigs ... }; - fwrite( femSigs , sizeof(unsigned int) , dim , fp ); + stream.write( femSigs , dim ); + } + void write( BinaryStream &stream , const Serializer< Data > &serializer ) const + { + _indices.write( stream ); + _data.write( stream , serializer ); } - void write( FILE* fp ) const + void read( BinaryStream &stream , const Serializer< Data > &serializer ) { - _indices.write( fp ); - _data.write( fp ); + _indices.read( stream ); + _data.read( stream , serializer ); } - void read( FILE* fp ) + void write( BinaryStream &stream ) const { - _indices.read( fp ); - _data.read( fp ); + _indices.write( stream ); + _data.write( stream ); + } + void read( BinaryStream &stream ) + { + _indices.read( stream ); + _data.read( stream ); } SparseNodeData( void ){} - SparseNodeData( FILE *fp ){ read(fp); } + SparseNodeData( BinaryStream &stream ){ read(stream); } + SparseNodeData( BinaryStream &stream , const Serializer< Data > &serializer ){ read(stream,serializer); } size_t size( void ) const { return _data.size(); } const Data& operator[] ( size_t idx ) const { return _data[idx]; } Data& operator[] ( size_t idx ) { return _data[idx]; } void reserve( size_t sz ){ if( sz>_indices.size() ) _indices.resize( sz , -1 ); } + size_t reserved( void ) const { return _indices.size(); } Data* operator()( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ){ return ( node->nodeData.nodeIndex<0 || node->nodeData.nodeIndex>=(node_index_type)_indices.size() || _indices[ node->nodeData.nodeIndex ]==-1 ) ? NULL : &_data[ _indices[ node->nodeData.nodeIndex ] ]; } const Data* operator()( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ) const { return ( node->nodeData.nodeIndex<0 || node->nodeData.nodeIndex>=(node_index_type)_indices.size() || _indices[ node->nodeData.nodeIndex ]==-1 ) ? NULL : &_data[ _indices[ node->nodeData.nodeIndex ] ]; } Data& operator[]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ) { static std::mutex _insertionMutex; - // If the node hasn't been indexed yet if( node->nodeData.nodeIndex>=(node_index_type)_indices.size() ) { std::lock_guard< std::mutex > lock( _insertionMutex ); if( node->nodeData.nodeIndex>=(node_index_type)_indices.size() ) _indices.resize( node->nodeData.nodeIndex+1 , -1 ); } - // If the node hasn't been allocated yet volatile node_index_type &_index = _indices[ node->nodeData.nodeIndex ]; if( _index==-1 ) { std::lock_guard< std::mutex > lock( _insertionMutex ); - if( _index==-1 ) _index = (node_index_type)_data.push(); + if( _index==-1 ) + { + size_t sz = _data.size(); + _data.resize( sz + 1 ); + _index = (node_index_type)sz; + } } return _data[ _index ]; } @@ -309,17 +336,123 @@ struct SparseNodeData< Data , UIntPack< FEMSigs ... > > : public _SparseOrDenseN else return _indices[ node->nodeData.nodeIndex ]; } + node_index_type index( node_index_type idx ) const + { + if( idx<0 || idx>=(node_index_type)_indices.size() ) return -1; + else return _indices[ idx ]; + } + + void merge( const SparseNodeData &data ){ return merge( data , []( const Data &data ){ return data; } ); } + + template< typename MergeFunctor > + void merge( const SparseNodeData &data , const MergeFunctor &mergeFunctor ) + { + size_t sz = _indices.size(); + node_index_type newDataCount = 0; + for( unsigned int j=0 ; j + void mergeFromTarget( const SparseNodeData &data , const TargetToSourceFunctor &targetToSourceFunctor ){ return mergeFromTarget( data , targetToSourceFunctor , []( const Data &data ){ return data; } ); } + + template< typename TargetToSourceFunctor , typename MergeFunctor > + void mergeFromTarget( const SparseNodeData &target , const TargetToSourceFunctor &targetToSourceFunctor , const MergeFunctor &mergeFunctor ) + { + size_t sz = _indices.size(); + node_index_type newDataCount = 0; + for( unsigned int j=0 ; j + void mergeToSource( const SparseNodeData &data , const SourceToTargetFunctor &sourceToTargetFunctor ){ return mergeToSource( data , sourceToTargetFunctor , []( const Data &data ){ return data; } ); } + + template< typename SourceToTargetFunctor , typename MergeFunctor > + void mergeToSource( const SparseNodeData &target , const SourceToTargetFunctor &sourceToTargetFunctor , const MergeFunctor &mergeFunctor ) + { + size_t _sz = target._indices.size(); + node_index_type newDataCount = 0; + for( unsigned int j=0 ; j<_indices.size() ; j++ ) if( _indices[j]==-1 ) + { + unsigned int _j = sourceToTargetFunctor( j ); + if( _j<(node_index_type)_sz && target._indices[_j]!=-1 ) newDataCount++; + } + size_t oldSize = _data.size(); + _data.resize( oldSize + newDataCount ); + newDataCount = 0; + for( unsigned int j=0 ; j<_indices.size() ; j++ ) + { + unsigned int _j = sourceToTargetFunctor( j ); + if( _j<(node_index_type)_sz && target._indices[_j]!=-1 ) + if( _indices[j]==-1 ) + { + _indices[j] = (node_index_type)oldSize + newDataCount; + _data[ oldSize + newDataCount ] = mergeFunctor( target._data[ target._indices[_j] ] ); + newDataCount++; + } + else _data[ _indices[j] ] += mergeFunctor( target._data[ target._indices[_j] ] ); + } + } + protected: template< unsigned int _Dim , class _Real > friend class FEMTree; - // Map should be the size of the old number of entries and map[i] should give the new index of the old i-th node - void _remapIndices( ConstPointer( node_index_type ) newNodeIndices , size_t newNodeCount ) + + // Map should be the size of the new number of entries and map[i] should give the old index of the i-th node + void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ) { BlockedVector< node_index_type > newIndices; newIndices.resize( newNodeCount ); - for( node_index_type i=0 ; i<(node_index_type)newNodeCount ; i++ ) newIndices[i] = -1; - for( node_index_type i=0 ; i<(node_index_type)_indices.size() ; i++ ) if( newNodeIndices[i]!=-1 && newNodeIndices[i]<(node_index_type)newNodeCount ) newIndices[ newNodeIndices[i] ] = _indices[i]; + for( node_index_type i=0 ; i<(node_index_type)newNodeCount ; i++ ) + { + newIndices[i] = -1; + if( oldNodeIndices[i]!=-1 && oldNodeIndices[i]<(node_index_type)_indices.size() ) newIndices[i] = _indices[ oldNodeIndices[i] ]; + } _indices = newIndices; } + + SparseNodeData _trim( node_index_type endIndex ) const + { + size_t dataCount = 0; + for( node_index_type i=0 ; i _indices; BlockedVector< Data > _data; }; @@ -335,22 +468,26 @@ struct DenseNodeData< Data , UIntPack< FEMSigs ... > > : public _SparseOrDenseNo 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( FILE *fp ) : DenseNodeData() { read(fp); } + DenseNodeData( BinaryStream &stream ) : DenseNodeData() { read(stream); } ~DenseNodeData( void ){ DeletePointer( _data ) ; _sz = 0; } void resize( size_t sz ){ DeletePointer( _data ) ; _sz = sz ; if( sz ) _data = NewPointer< Data >( sz ) ; else _data = NullPointer( Data ); } - static void WriteSignatures( FILE* fp ) + static void WriteSignatures( BinaryStream &stream ) { unsigned int dim = sizeof ... ( FEMSigs ); - fwrite( &dim , sizeof(unsigned int) , 1 , fp ); + stream.write( dim ); unsigned int femSigs[] = { FEMSigs ... }; - fwrite( femSigs , sizeof(unsigned int) , dim , fp ); + stream.write( GetPointer( femSigs , dim ) , dim ); } - void write( FILE* fp ) const { fwrite( &_sz , sizeof(size_t) , 1 , fp ) ; fwrite( _data , sizeof(Data) , _sz , fp ); } - void read( FILE* fp ) + void write( BinaryStream &stream ) const { - if( fread( &_sz , sizeof(size_t) , 1 , fp )!=1 ) ERROR_OUT( "Failed to read size" ); + stream.write( _sz ); + stream.write( _data , _sz ); + } + void read( BinaryStream &stream ) + { + if( !stream.read( _sz ) ) ERROR_OUT( "Failed to read size" ); _data = NewPointer< Data >( _sz ); - if( fread ( _data , sizeof(Data) , _sz , fp )!=_sz ) ERROR_OUT( "failed to read data" ); + if( !stream.read( _data , _sz ) ) ERROR_OUT( "failed to read data" ); } Data& operator[] ( size_t idx ) { return _data[idx]; } @@ -364,20 +501,32 @@ struct DenseNodeData< Data , UIntPack< FEMSigs ... > > : public _SparseOrDenseNo ConstPointer( Data ) operator()( void ) const { return ( ConstPointer( Data ) )_data; } protected: template< unsigned int _Dim , class _Real > friend class FEMTree; - // Map should be the size of the old number of entries and map[i] should give the new index of the old i-th node - void _remapIndices( ConstPointer( node_index_type ) newNodeIndices , size_t newNodeCount ) + + // Map should be the size of the new number of entries and map[i] should give the old index of the i-th node + void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ) { Pointer( Data ) newData = NewPointer< Data >( newNodeCount ); memset( newData , 0 , sizeof(Data)*newNodeCount ); - for( size_t i=0 ; i<_sz ; i++ ) if( newNodeIndices[i]>=0 && newNodeIndices[i]<(node_index_type)newNodeCount ) newData[ newNodeIndices[i] ] = _data[i]; + for( size_t i=0 ; i=0 && oldNodeIndices[i]<(node_index_type)_sz ) newData[i] = _data[ oldNodeIndices[i] ]; DeletePointer( _data ); _data = newData; _sz = newNodeCount; } + + DenseNodeData _trim( node_index_type endIndex ) const + { + DenseNodeData denseNodeData; + denseNodeData._sz = endIndex; + denseNodeData._data = NewPointer< Data >( endIndex ); + memcpy( denseNodeData._data , _data , sizeof(Data) * denseNodeData._sz ); + return denseNodeData; + } + 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; }; + enum FEMTreeRealType { FEM_TREE_REAL_FLOAT , @@ -386,17 +535,17 @@ enum FEMTreeRealType }; const char* FEMTreeRealNames[] = { "float" , "double" }; -void ReadFEMTreeParameter( FILE* fp , FEMTreeRealType& realType , unsigned int &dimension ) +void ReadFEMTreeParameter( BinaryStream &stream , FEMTreeRealType& realType , unsigned int &dimension ) { - if( fread( &realType , sizeof(FEMTreeRealType) , 1 , fp )!=1 ) ERROR_OUT( "Failed to read real type" ); - if( fread( &dimension , sizeof(unsigned int) , 1 , fp )!=1 ) ERROR_OUT( "Failed to read dimension" ); + if( !stream.read( realType ) ) ERROR_OUT( "Failed to read real type" ); + if( !stream.read( dimension ) ) ERROR_OUT( "Failed to read dimension" ); } -unsigned int* ReadDenseNodeDataSignatures( FILE* fp , unsigned int &dim ) +unsigned int* ReadDenseNodeDataSignatures( BinaryStream &stream , unsigned int &dim ) { - if( fread( &dim , sizeof(unsigned int) , 1 , fp )!=1 ) ERROR_OUT( "Failed to read dimension" ); + if( !stream.read( dim ) ) ERROR_OUT( "Failed to read dimension" ); unsigned int* femSigs = new unsigned int[dim]; - if( fread( femSigs , sizeof(unsigned int) , dim , fp )!=dim ) ERROR_OUT( "Failed to read signatures" ); + if( !stream.read( GetPointer( femSigs , dim ) , dim ) ) ERROR_OUT( "Failed to read signatures" ); return femSigs; } @@ -1184,18 +1333,18 @@ template< unsigned int Dim > inline void SetGhostFlag( RegularTreeNode< Di template< unsigned int Dim > inline bool GetGhostFlag( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ){ return node==NULL || node->parent==NULL || node->parent->nodeData.getGhostFlag( ); } template< unsigned int Dim > inline bool IsActiveNode( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ){ return !GetGhostFlag( node ); } -template< unsigned int Dim , class Real , class Vertex > struct IsoSurfaceExtractor; +template< unsigned int Dim , class Real , class Vertex > struct LevelSetExtractor; template< unsigned int Dim , class Data > struct NodeSample { - RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node; + RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *node; Data data; }; template< unsigned int Dim , class Real > struct NodeAndPointSample { - RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node; + RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *node; ProjectiveData< Point< Real , Dim > , Real > sample; }; template< unsigned int Dim , class Real > using NodeSimplices = NodeSample< Dim , std::vector< std::pair< node_index_type , Simplex< Real , Dim , Dim-1 > > > >; @@ -1254,7 +1403,21 @@ class FEMTree template< unsigned int ... FEMSigs > using SystemMatrixType = SparseMatrix< Real , matrix_index_type , WindowSize< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >::Size >; std::vector< Allocator< FEMTreeNode > * > nodeAllocators; protected: - template< unsigned int _Dim , class _Real , class Vertex > friend struct IsoSurfaceExtractor; + template< unsigned int _Dim , class _Real > friend class FEMTree; + struct SubTreeExtractor : public FEMTreeNode::SubTreeExtractor + { + SubTreeExtractor( FEMTreeNode &node , int &depthOffset ) : FEMTreeNode::SubTreeExtractor( node ) , _depthOffset( depthOffset ) + { + _depthOffsetValue = _depthOffset; + _depthOffset = 0; + } + SubTreeExtractor( FEMTreeNode *node , int &depthOffset ) : SubTreeExtractor( *node , depthOffset ){} + ~SubTreeExtractor( void ){ _depthOffset = _depthOffsetValue; } + protected: + int &_depthOffset , _depthOffsetValue; + }; + + template< unsigned int _Dim , class _Real , class Vertex > friend struct LevelSetExtractor; std::atomic< node_index_type > _nodeCount; struct _NodeInitializer { @@ -1287,7 +1450,9 @@ class FEMTree const FEMTreeNode* leaf( Point< Real , Dim > p ) const; protected: template< bool ThreadSafe > - FEMTreeNode* _leaf( Allocator< FEMTreeNode > * nodeAllocator , Point< Real , Dim > p , LocalDepth maxDepth=-1 ); + FEMTreeNode* _leaf( Allocator< FEMTreeNode > *nodeAllocator , Point< Real , Dim > p , LocalDepth maxDepth=-1 ); + template< bool ThreadSafe > + FEMTreeNode* _leaf( Allocator< FEMTreeNode > *nodeAllocator , Point< Real , Dim > p , std::function< int ( Point< Real , Dim > ) > &pointDepthFunctor ); public: // [NOTE] In the case that T != double, we require both operators() for computing the system dual @@ -1304,7 +1469,7 @@ class FEMTree DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIndex ){ return const_cast< DualPointInfo< Dim , Real , T , PointD >& >( ( ( const InterpolationInfo* )this )->operator[]( pointIndex ) ); } protected: - virtual void _remapIndices( ConstPointer( node_index_type ) newNodeIndices , size_t newNodeCount ) = 0; + virtual void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ) = 0; friend class FEMTree< Dim , Real >; }; @@ -1320,108 +1485,210 @@ class FEMTree DualPointInfo< Dim , Real , double , PointD >& operator[]( size_t pointIndex ){ return const_cast< DualPointInfo< Dim , Real , double , PointD >& >( ( ( const InterpolationInfo* )this )->operator[]( pointIndex ) ); } protected: - virtual void _remapIndices( ConstPointer( node_index_type ) newNodeIndices , size_t newNodeCount ) = 0; + virtual void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ) = 0; friend class FEMTree< Dim , Real >; }; template< typename T , unsigned int PointD , typename ConstraintDual , typename SystemDual > struct ApproximatePointInterpolationInfo : public InterpolationInfo< T , PointD > { + using Data = DualPointInfo< Dim , Real , T , PointD >; void range( const FEMTreeNode *node , size_t &begin , size_t &end ) const { - node_index_type idx = _iData.index( node ); + node_index_type idx = iData.index( node ); if( idx==-1 ) begin = end = 0; else begin = idx , end = idx+1; } bool constrainsDCTerm( void ) const { return _constrainsDCTerm; } - const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const { return _iData[ pointIdx ]; } - Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( _iData[ pointIdx ].position ); } - Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( _iData[ pointIdx ].position , dValues ); } - Point< double , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< double , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( _iData[ pointIdx ].position , dValues ); } + const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const { return iData[ pointIdx ]; } + Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( iData[ pointIdx ].position ); } + Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( iData[ pointIdx ].position , dValues ); } + Point< double , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< double , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( iData[ pointIdx ].position , dValues ); } ApproximatePointInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _constraintDual( constraintDual ) , _systemDual( systemDual ) , _constrainsDCTerm( constrainsDCTerm ) { } + + void write( BinaryStream &stream ) const + { + unsigned char constrainsDCTerm = _constrainsDCTerm ? 1 : 0; + stream.write( constrainsDCTerm ); + stream.write( _constraintDual ); + stream.write( _systemDual ); + iData.write( stream ); + } + void read( BinaryStream &stream ) + { + unsigned char constrainsDCTerm; + if( !stream.read( constrainsDCTerm ) ) ERROR_OUT( "Failed to read constrainsDCTerm" ); + _constrainsDCTerm = constrainsDCTerm!=0; + if( !stream.read( _constraintDual ) ) ERROR_OUT( "Failed to read _constraintDual" ); + if( !stream.read( _systemDual ) ) ERROR_OUT( "Failed to read _systemDual" ); + iData.read( stream ); + } + ApproximatePointInterpolationInfo( BinaryStream &stream ){ read(stream); } + ApproximatePointInterpolationInfo( void ){} + + SparseNodeData< DualPointInfo< Dim , Real , T , PointD > , ZeroUIntPack< Dim > > iData; + protected: - SparseNodeData< DualPointInfo< Dim , Real , T , PointD > , ZeroUIntPack< Dim > > _iData; + bool _constrainsDCTerm; ConstraintDual _constraintDual; SystemDual _systemDual; - void _remapIndices( ConstPointer( node_index_type ) newNodeIndices , size_t newNodeCount ){ _iData._remapIndices( newNodeIndices , newNodeCount ); } + void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ){ iData._remapIndices( oldNodeIndices , newNodeCount ); } + friend class FEMTree< Dim , Real >; }; + template< unsigned int PointD , typename ConstraintDual , typename SystemDual > struct ApproximatePointInterpolationInfo< double , PointD , ConstraintDual , SystemDual > : public InterpolationInfo< double , PointD > { typedef double T; + using Data = DualPointInfo< Dim , Real , T , PointD >; void range( const FEMTreeNode* node , size_t& begin , size_t& end ) const { - node_index_type idx = _iData.index( node ); + node_index_type idx = iData.index( node ); if( idx==-1 ) begin = end = 0; else begin = idx , end = idx+1; } bool constrainsDCTerm( void ) const { return _constrainsDCTerm; } - const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const { return _iData[ pointIdx ]; } - Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( _iData[ pointIdx ].position ); } - Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( _iData[ pointIdx ].position , dValues ); } + const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const { return iData[ pointIdx ]; } + Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( iData[ pointIdx ].position ); } + Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( iData[ pointIdx ].position , dValues ); } ApproximatePointInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _constraintDual( constraintDual ) , _systemDual( systemDual ) , _constrainsDCTerm( constrainsDCTerm ) { } + + void write( BinaryStream &stream ) const + { + unsigned char constrainsDCTerm = _constrainsDCTerm ? 1 : 0; + stream.write( constrainsDCTerm ); + stream.write( _constraintDual ); + stream.write( _systemDual ); + iData.write( stream ); + } + void read( BinaryStream &stream ) + { + unsigned char constrainsDCTerm; + if( !stream.read( constrainsDCTerm ) ) ERROR_OUT( "Failed to read constrainsDCTerm" ); + _constrainsDCTerm = constrainsDCTerm!=0; + if( !stream.read( _constraintDual ) ) ERROR_OUT( "Failed to read _constraintDual" ); + if( !stream.read( _systemDual ) ) ERROR_OUT( "Failed to read _systemDual" ); + iData.read( stream ); + } + ApproximatePointInterpolationInfo( BinaryStream &stream ){ read(stream); } + ApproximatePointInterpolationInfo( void ){} + + SparseNodeData< DualPointInfo< Dim , Real , T , PointD > , ZeroUIntPack< Dim > > iData; + protected: - SparseNodeData< DualPointInfo< Dim , Real , T , PointD > , ZeroUIntPack< Dim > > _iData; + bool _constrainsDCTerm; ConstraintDual _constraintDual; SystemDual _systemDual; - void _remapIndices( ConstPointer( node_index_type ) newNodeIndices , size_t newNodeCount ){ _iData._remapIndices( newNodeIndices , newNodeCount ); } + void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ){ iData._remapIndices( oldNodeIndices , newNodeCount ); } + friend class FEMTree< Dim , Real >; }; + template< typename T , typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > struct ApproximatePointAndDataInterpolationInfo : public InterpolationInfo< T , PointD > { void range( const FEMTreeNode* node , size_t& begin , size_t& end ) const { - node_index_type idx = _iData.index( node ); + node_index_type idx = iData.index( node ); if( idx==-1 ) begin = end = 0; else begin = idx , end = idx+1; } bool constrainsDCTerm( void ) const { return _constrainsDCTerm; } - const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const { return _iData[ pointIdx ].pointInfo; } - Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( _iData[ pointIdx ].pointInfo.position , _iData[ pointIdx ].data ); } - Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( _iData[ pointIdx ].pointInfo.position , _iData[ (int)pointIdx ].data , dValues ); } - Point< double , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< double , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( _iData[ (int)pointIdx ].pointInfo.position , _iData[ (int)pointIdx ].data , dValues ); } + const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const { return iData[ pointIdx ].pointInfo; } + Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( iData[ pointIdx ].pointInfo.position , iData[ pointIdx ].data ); } + Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( iData[ pointIdx ].pointInfo.position , iData[ (int)pointIdx ].data , dValues ); } + typename std::enable_if< !std::is_same< T , double >::value , Point< double , CumulativeDerivatives< Dim , PointD >::Size > >::type operator() ( size_t pointIdx , const Point< double , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( iData[ (int)pointIdx ].pointInfo.position , iData[ (int)pointIdx ].data , dValues ); } ApproximatePointAndDataInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _constraintDual( constraintDual ) , _systemDual( systemDual ) , _constrainsDCTerm( constrainsDCTerm ) { } + + void write( BinaryStream &stream ) const + { + unsigned char constrainsDCTerm = _constrainsDCTerm ? 1 : 0; + stream.write( constrainsDCTerm ); + stream.write( _constraintDual ); + stream.write( _systemDual ); + iData.write( stream ); + } + void read( BinaryStream &stream ) + { + unsigned char constrainsDCTerm; + if( !stream.read( constrainsDCTerm ) ) ERROR_OUT( "Failed to read constrainsDCTerm" ); + _constrainsDCTerm = constrainsDCTerm!=0; + if( !stream.read( _constraintDual ) ) ERROR_OUT( "Failed to read _constraintDual" ); + if( !stream.read( _systemDual ) ) ERROR_OUT( "Failed to read _systemDual" ); + iData.read( stream ); + } + ApproximatePointAndDataInterpolationInfo( BinaryStream &stream ){ read(stream); } + + SparseNodeData< DualPointAndDataInfo< Dim , Real , Data , T , PointD > , ZeroUIntPack< Dim > > iData; + protected: - SparseNodeData< DualPointAndDataInfo< Dim , Real , Data , T , PointD > , ZeroUIntPack< Dim > > _iData; + bool _constrainsDCTerm; ConstraintDual _constraintDual; SystemDual _systemDual; - void _remapIndices( ConstPointer( node_index_type ) newNodeIndices , size_t newNodeCount ){ _iData._remapIndices( newNodeIndices , newNodeCount ); } + void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ){ iData._remapIndices( oldNodeIndices , newNodeCount ); } + + ApproximatePointAndDataInterpolationInfo( void ){} friend class FEMTree< Dim , Real >; }; + template< typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > struct ApproximatePointAndDataInterpolationInfo< double , Data , PointD , ConstraintDual , SystemDual > : public InterpolationInfo< double , PointD > { typedef double T; void range( const FEMTreeNode* node , size_t& begin , size_t& end ) const { - node_index_type idx = _iData.index( node ); + node_index_type idx = iData.index( node ); if( idx==-1 ) begin = end = 0; else begin = idx , end = idx+1; } bool constrainsDCTerm( void ) const { return _constrainsDCTerm; } - const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const { return _iData[ pointIdx ].pointInfo; } - Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( _iData[ pointIdx ].pointInfo.position , _iData[ pointIdx ].data ); } - Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( _iData[ pointIdx ].pointInfo.position , _iData[ pointIdx ].data , dValues ); } + const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const { return iData[ pointIdx ].pointInfo; } + Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( iData[ pointIdx ].pointInfo.position , iData[ pointIdx ].data ); } + Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( iData[ pointIdx ].pointInfo.position , iData[ pointIdx ].data , dValues ); } ApproximatePointAndDataInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _constraintDual( constraintDual ) , _systemDual( systemDual ) , _constrainsDCTerm( constrainsDCTerm ) { } + + void write( BinaryStream &stream ) const + { + unsigned char constrainsDCTerm = _constrainsDCTerm ? 1 : 0; + stream.write( constrainsDCTerm ); + stream.write( _constraintDual ); + stream.write( _systemDual ); + iData.write( stream ); + } + void read( BinaryStream &stream ) + { + unsigned char constrainsDCTerm; + if( !stream.read( constrainsDCTerm ) ) ERROR_OUT( "Failed to read constrainsDCTerm" ); + _constrainsDCTerm = constrainsDCTerm!=0; + if( !stream.read( _constraintDual ) ) ERROR_OUT( "Failed to read _constraintDual" ); + if( !stream.read( _systemDual ) ) ERROR_OUT( "Failed to read _systemDual" ); + iData.read( stream ); + } + + ApproximatePointAndDataInterpolationInfo( BinaryStream &stream ){ read(stream); } + + SparseNodeData< DualPointAndDataInfo< Dim , Real , Data , T , PointD > , ZeroUIntPack< Dim > > iData; + protected: - SparseNodeData< DualPointAndDataInfo< Dim , Real , Data , T , PointD > , ZeroUIntPack< Dim > > _iData; + bool _constrainsDCTerm; ConstraintDual _constraintDual; SystemDual _systemDual; - void _remapIndices( ConstPointer( node_index_type ) newNodeIndices , size_t newNodeCount ){ _iData._remapIndices( newNodeIndices , newNodeCount ); } + void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ){ iData._remapIndices( oldNodeIndices , newNodeCount ); } + + ApproximatePointAndDataInterpolationInfo( void ){} friend class FEMTree< Dim , Real >; }; @@ -1433,7 +1700,7 @@ class FEMTree const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const { return _iData[ pointIdx ]; } Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( _iData[ pointIdx ].position ); } Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( _iData[ pointIdx ].position , dValues ); } - Point< double , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< double , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( _iData[ pointIdx ].position , dValues ); } + typename std::enable_if< !std::is_same< T , double >::value , Point< double , CumulativeDerivatives< Dim , PointD >::Size > >::type operator() ( size_t pointIdx , const Point< double , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( _iData[ pointIdx ].position , dValues ); } ExactPointInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _constraintDual( constraintDual ) , _systemDual( systemDual ) , _constrainsDCTerm( constrainsDCTerm ) { } protected: @@ -1445,14 +1712,16 @@ class FEMTree ConstraintDual _constraintDual; SystemDual _systemDual; - void _remapIndices( ConstPointer( node_index_type ) newNodeIndices , size_t newNodeCount ) + void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ) { std::vector< std::pair< node_index_type , node_index_type > > _newSampleSpan( newNodeCount ); - for( int i=0 ; i<_sampleSpan.size() ; i++ ) if( newNodeIndices[i]!=-1 ) _newSampleSpan[ newNodeIndices[i] ] = _sampleSpan[i]; + for( size_t i=0 ; i; }; + template< unsigned int PointD , typename ConstraintDual , typename SystemDual > struct ExactPointInterpolationInfo< double , PointD , ConstraintDual , SystemDual > : public InterpolationInfo< double , PointD > { @@ -1473,14 +1742,16 @@ class FEMTree ConstraintDual _constraintDual; SystemDual _systemDual; - void _remapIndices( ConstPointer( node_index_type ) newNodeIndices , size_t newNodeCount ) + void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ) { std::vector< std::pair< node_index_type , node_index_type > > _newSampleSpan( newNodeCount ); - for( int i=0 ; i<_sampleSpan.size() ; i++ ) if( newNodeIndices[i]!=-1 ) _newSampleSpan[ newNodeIndices[i] ] = _sampleSpan[i]; + for( int i=0 ; i; }; + template< typename T , typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > struct _ExactPointAndDataInterpolationInfo : public InterpolationInfo< T , PointD > { @@ -1495,12 +1766,13 @@ class FEMTree ConstraintDual _constraintDual; SystemDual _systemDual; - void _remapIndices( ConstPointer( node_index_type ) newNodeIndices , size_t newNodeCount ) + void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ) { std::vector< std::pair< node_index_type , node_index_type > > _newSampleSpan( newNodeCount ); - for( int i=0 ; i<_sampleSpan.size() ; i++ ) if( newNodeIndices[i]!=-1 ) _newSampleSpan[ newNodeIndices[i] ] = _sampleSpan[i]; + for( size_t i=0 ; i; }; @@ -1521,6 +1793,7 @@ class FEMTree ExactPointAndDataInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _ExactPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >( constraintDual , systemDual , constrainsDCTerm ) { } }; + template< typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > struct ExactPointAndDataInterpolationInfo< double , Data , PointD , ConstraintDual , SystemDual > : public _ExactPointAndDataInterpolationInfo< double , Data , PointD , ConstraintDual , SystemDual > { @@ -1534,21 +1807,22 @@ class FEMTree const DualPointInfo< Dim , Real , double , PointD >& operator[]( size_t pointIdx ) const { return _iData[ pointIdx ].pointInfo; } Point< double , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( _iData[ pointIdx ].pointInfo.position , _iData[ pointIdx ].data ); } Point< double , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< double , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( _iData[ pointIdx ].pointInfo.position , _iData[ (int)pointIdx ].data , dValues ); } + ExactPointAndDataInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _ExactPointAndDataInterpolationInfo< double , Data , PointD , ConstraintDual , SystemDual >( constraintDual , systemDual , constrainsDCTerm ) { } }; - template< typename T , unsigned int PointD , typename ConstraintDual , typename SystemDual > - static ApproximatePointInterpolationInfo< T , PointD , ConstraintDual , SystemDual >* InitializeApproximatePointInterpolationInfo( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm , int adaptiveExponent ) + template< typename T , unsigned int PointD , typename ConstraintDual , typename SystemDual > + static ApproximatePointInterpolationInfo< T , PointD , ConstraintDual , SystemDual >* InitializeApproximatePointInterpolationInfo( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm , LocalDepth maxDepth , int adaptiveExponent ) { ApproximatePointInterpolationInfo< T , PointD , ConstraintDual , SystemDual >* a = new ApproximatePointInterpolationInfo< T , PointD , ConstraintDual , SystemDual >( constraintDual , systemDual , constrainsDCTerm ); - a->_iData = tree._densifyInterpolationInfoAndSetDualConstraints< T , PointD >( samples , constraintDual , adaptiveExponent ); + a->iData = tree._densifyInterpolationInfoAndSetDualConstraints< T , PointD >( samples , constraintDual , maxDepth , adaptiveExponent ); return a; } template< typename T , typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > - static ApproximatePointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >* InitializeApproximatePointAndDataInterpolationInfo( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , ConstPointer( Data ) sampleData , ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm , int adaptiveExponent ) + static ApproximatePointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >* InitializeApproximatePointAndDataInterpolationInfo( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , ConstPointer( Data ) sampleData , ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm , LocalDepth maxDepth , int adaptiveExponent ) { ApproximatePointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >* a = new ApproximatePointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >( constraintDual , systemDual , constrainsDCTerm ); - a->_iData = tree._densifyInterpolationInfoAndSetDualConstraints< T , Data , PointD >( samples , sampleData , constraintDual , adaptiveExponent ); + a->iData = tree._densifyInterpolationInfoAndSetDualConstraints< T , Data , PointD >( samples , sampleData , constraintDual , maxDepth , adaptiveExponent ); return a; } @@ -1592,45 +1866,51 @@ class FEMTree Real samplesPerNode( void ) const { return _samplesPerNode; } int coDimension( void ) const { return _coDimension; } int kernelDepth( void ) const { return _kernelDepth; } - void write( FILE *fp ) const + + void write( BinaryStream &stream ) const { - fwrite( &_kernelDepth , sizeof(int) , 1 , fp ); - fwrite( &_coDimension , sizeof(int) , 1 , fp ); - fwrite( &_samplesPerNode , sizeof(Real) , 1 , fp ); - SparseNodeData< Real , IsotropicUIntPack< Dim , FEMDegreeAndBType< DensityDegree >::Signature > >::write( fp ); + stream.write( _kernelDepth ); + stream.write( _coDimension ); + stream.write( _samplesPerNode ); + SparseNodeData< Real , IsotropicUIntPack< Dim , FEMDegreeAndBType< DensityDegree >::Signature > >::write( stream ); } - void read( FILE *fp ) + void read( BinaryStream &stream ) { - if( fread( &_kernelDepth , sizeof(int) , 1 , fp )!=1 ) ERROR_OUT( "Failed to read _kernelDepth" ); - if( fread( &_coDimension , sizeof(int) , 1 , fp )!=1 ) ERROR_OUT( "Failed to read _coDimension" ); - if( fread( &_samplesPerNode , sizeof(Real) , 1 , fp )!=1 ) ERROR_OUT( "Failed to read _samplesPerNode" ); - SparseNodeData< Real , IsotropicUIntPack< Dim , FEMDegreeAndBType< DensityDegree >::Signature > >::read( fp ); + if( !stream.read( _kernelDepth ) ) ERROR_OUT( "Failed to read _kernelDepth" ); + if( !stream.read( _coDimension ) ) ERROR_OUT( "Failed to read _coDimension" ); + if( !stream.read( _samplesPerNode ) ) ERROR_OUT( "Failed to read _samplesPerNode" ); + SparseNodeData< Real , IsotropicUIntPack< Dim , FEMDegreeAndBType< DensityDegree >::Signature > >::read( stream ); } - DensityEstimator( FILE *fp ){ read(fp); } + DensityEstimator( BinaryStream &stream ){ read(stream); } + protected: Real _samplesPerNode; int _kernelDepth , _coDimension; }; protected: - bool _isValidSpaceNode( const FEMTreeNode* node ) const { return !GetGhostFlag< Dim >( node ) && ( node->nodeData.flags & FEMTreeNodeData::SPACE_FLAG ); } - bool _isValidFEM1Node ( const FEMTreeNode* node ) const { return !GetGhostFlag< Dim >( node ) && ( node->nodeData.flags & FEMTreeNodeData::FEM_FLAG_1 ); } - bool _isValidFEM2Node ( const FEMTreeNode* node ) const { return !GetGhostFlag< Dim >( node ) && ( node->nodeData.flags & FEMTreeNodeData::FEM_FLAG_2 ); } + bool _isValidSpaceNode( const FEMTreeNode* node ) const { return !GetGhostFlag< Dim >( node ) && ( node->nodeData.flags & FEMTreeNodeData::SPACE_FLAG ); } + bool _isValidFEM1Node ( const FEMTreeNode* node ) const { return !GetGhostFlag< Dim >( node ) && ( node->nodeData.flags & FEMTreeNodeData::FEM_FLAG_1 ); } + bool _isValidFEM2Node ( const FEMTreeNode* node ) const { return !GetGhostFlag< Dim >( node ) && ( node->nodeData.flags & FEMTreeNodeData::FEM_FLAG_2 ); } - FEMTreeNode* _tree; - FEMTreeNode* _spaceRoot; + FEMTreeNode _tree; + mutable FEMTreeNode* _spaceRoot; SortedTreeNodes< Dim > _sNodes; LocalDepth _maxDepth; int _depthOffset; - LocalDepth _baseDepth , _fullDepth; + LocalDepth _baseDepth; +#ifdef USE_EXACT_PROLONGATION + LocalDepth _exactDepth; +#endif // USE_EXACT_PROLONGATION mutable unsigned int _femSigs1[ Dim ]; mutable unsigned int _femSigs2[ Dim ]; + void _init( void ); static bool _InBounds( Point< Real , Dim > p ); int _localToGlobal( LocalDepth d ) const { return d + _depthOffset; } LocalDepth _globalToLocal( int d ) const { return d - _depthOffset; } LocalDepth _localDepth( const FEMTreeNode* node ) const { return node->depth() - _depthOffset; } - int _localInset( LocalDepth d ) const { return _depthOffset<=1 ? 0 : 1<<( d + _depthOffset - 1 ); } + int _localInset( LocalDepth d ) const { return _depthOffset==0 ? 0 : 1<<( d + _depthOffset - 1 ); } void _localDepthAndOffset( const FEMTreeNode* node , LocalDepth& d , LocalOffset& off ) const { node->depthAndOffset( d , off ) ; d -= _depthOffset; @@ -1663,6 +1943,7 @@ class FEMTree _localDepthAndOffset( femNode , femDepth , femOffset ) , _localDepthAndOffset( spaceNode , spaceDepth , spaceOffset ); return _IsSupported( UIntPack< FEMDegrees ... >() , femDepth , femOffset , spaceDepth , spaceOffset ); } + template< unsigned int FEMDegree > static bool _IsInteriorlySupported( LocalDepth depth , const LocalOffset off ) { if( depth>=0 ) @@ -1675,6 +1956,7 @@ class FEMTree } else return false; } + template< unsigned int FEMDegree > bool _isInteriorlySupported( const FEMTreeNode* node ) const { if( !node ) return false; @@ -1701,6 +1983,7 @@ class FEMTree } else return false; } + template< unsigned int FEMDegree1 , unsigned int FEMDegree2 > bool _isInteriorlyOverlapped( const FEMTreeNode* node ) const { if( !node ) return false; @@ -1715,6 +1998,7 @@ class FEMTree LocalDepth d ; LocalOffset off ; _localDepthAndOffset( node , d , off ); return _IsInteriorlyOverlapped( UIntPack< FEMDegrees1 ... >() , UIntPack< FEMDegrees2 ... >() , d , off ); } + void _startAndWidth( const FEMTreeNode* node , Point< Real , Dim >& start , Real& width ) const { LocalDepth d ; LocalOffset off; @@ -1723,6 +2007,7 @@ class FEMTree else width = Real( 1.0 * (1<<(-d)) ); for( int dd=0 ; dd& center , Real& width ) const { int d , off[Dim]; @@ -1730,6 +2015,7 @@ class FEMTree width = Real( 1.0 / (1< p ) const { Point< Real , Dim > c ; Real w; @@ -1742,14 +2028,19 @@ class FEMTree template< bool ThreadSafe , unsigned int ... Degrees > void _setFullDepth( UIntPack< Degrees ... > , Allocator< FEMTreeNode > *nodeAllocator , FEMTreeNode* node , LocalDepth depth ); template< bool ThreadSafe , unsigned int ... Degrees > void _setFullDepth( UIntPack< Degrees ... > , Allocator< FEMTreeNode > *nodeAllocator , LocalDepth depth ); template< unsigned int ... Degrees > LocalDepth _getFullDepth( UIntPack< Degrees ... > , const FEMTreeNode* node ) const; + template< unsigned int ... Degrees > LocalDepth _getFullDepth( UIntPack< Degrees ... > , const LocalDepth depth , const LocalOffset begin , const LocalOffset end , const FEMTreeNode *node ) const; + + template< bool ThreadSafe , typename AddNodeFunctor , unsigned int ... Degrees > void _refine( UIntPack< Degrees ... > , Allocator< FEMTreeNode > *nodeAllocator , const AddNodeFunctor &addNodeFunctor , FEMTreeNode *node ); + template< bool ThreadSafe , typename AddNodeFunctor , unsigned int ... Degrees > void _refine( UIntPack< Degrees ... > , Allocator< FEMTreeNode > *nodeAllocator , const AddNodeFunctor &addNodeFunctor ); public: template< unsigned int ... Degrees > LocalDepth getFullDepth( UIntPack< Degrees ... > ) const; + template< unsigned int ... Degrees > LocalDepth getFullDepth( UIntPack< Degrees ... > , const LocalDepth depth , const LocalOffset begin , const LocalOffset end ) const; LocalDepth depth( const FEMTreeNode* node ) const { return _localDepth( node ); } void depthAndOffset( const FEMTreeNode* node , LocalDepth& depth , LocalOffset& offset ) const { _localDepthAndOffset( node , depth , offset ); } - size_t nodesSize ( void ) const { return _sNodes.size( ); } + size_t nodesSize( void ) const { return _sNodes.size(); } node_index_type nodesBegin( LocalDepth d ) const { return _sNodes.begin( _localToGlobal( d ) ); } node_index_type nodesEnd ( LocalDepth d ) const { return _sNodes.end ( _localToGlobal( d ) ); } size_t nodesSize ( LocalDepth d ) const { return _sNodes.size ( _localToGlobal( d ) ); } @@ -1889,6 +2180,11 @@ class FEMTree template< unsigned int ... FEMSigs , typename T , typename ... InterpolationInfos > int _getSliceMatrixAndProlongationConstraints( UIntPack< FEMSigs ... > , const BaseSystem< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , SystemMatrixType< FEMSigs ... > &matrix , Pointer( Real ) diagonalR , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , LocalDepth depth , node_index_type nBegin , node_index_type nEnd , ConstPointer( T ) prolongedSolution , Pointer( T ) constraints , const CCStencil < UIntPack< FEMSignature< FEMSigs >::Degree ... > >& ccStencil , const PCStencils< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& pcStencils , std::tuple< InterpolationInfos *... > interpolationInfos ) const; + // Down samples constraints @(depth) to constraints @(depth-1) + template< class C , typename ArrayWrapper , unsigned ... Degrees , unsigned int ... FEMSigs > void _downSample( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template RestrictionProlongation< UIntPack< Degrees ... > >& RP , LocalDepth highDepth , ArrayWrapper finerConstraints , Pointer( C ) coarserConstraints ) const; + // Up samples coefficients @(depth-1) to coefficients @(depth) + template< class C , typename ArrayWrapper , unsigned ... Degrees , unsigned int ... FEMSigs > void _upSample( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template RestrictionProlongation< UIntPack< Degrees ... > >& RP , LocalDepth highDepth , ArrayWrapper coarserCoefficients , Pointer( C ) finerCoefficients ) const; + template< unsigned int ... FEMSigs , typename ValidNodeFunctor > SparseMatrix< Real , matrix_index_type > _downSampleMatrix( UIntPack< FEMSigs ... > , LocalDepth highDepth , ValidNodeFunctor validNodeFunctor ) const; template< unsigned int ... FEMSigs , typename ValidNodeFunctor > @@ -1896,11 +2192,6 @@ class FEMTree template< unsigned int ... FEMSigs , typename ValidNodeFunctor > SparseMatrix< Real , matrix_index_type > _restrictSystemMatrix( UIntPack< FEMSigs ... > , LocalDepth highDepth , const SparseMatrix< Real , matrix_index_type > &M , ValidNodeFunctor validNodeFunctor ) const; - // Down samples constraints @(depth) to constraints @(depth-1) - template< class C , typename ArrayWrapper , unsigned ... Degrees , unsigned int ... FEMSigs > void _downSample( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template RestrictionProlongation< UIntPack< Degrees ... > >& RP , LocalDepth highDepth , ArrayWrapper finerConstraints , Pointer( C ) coarserConstraints ) const; - // Up samples coefficients @(depth-1) to coefficients @(depth) - template< class C , typename ArrayWrapper , unsigned ... Degrees , unsigned int ... FEMSigs > void _upSample( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template RestrictionProlongation< UIntPack< Degrees ... > >& RP , LocalDepth highDepth , ArrayWrapper coarserCoefficients , Pointer( C ) finerCoefficients ) const; - template< bool XMajor , class C , unsigned int ... FEMSigs > static void _RegularGridUpSample( UIntPack< FEMSigs ... > , LocalDepth highDepth , ConstPointer( C ) lowCoefficients , Pointer( C ) highCoefficients ); template< bool XMajor , class C , unsigned int ... FEMSigs > static void _RegularGridUpSample( UIntPack< FEMSigs ... > , const int lowBegin[] , const int lowEnd[] , const int highBegin[] , const int highEnd[] , LocalDepth highDepth , ConstPointer( C ) lowCoefficients , Pointer( C ) highCoefficients ); public: @@ -1908,12 +2199,22 @@ class FEMTree template< class C , unsigned int ... FEMSigs > DenseNodeData< C , UIntPack< FEMSigs ... > > coarseCoefficients( const SparseNodeData< C , UIntPack< FEMSigs ... > >& coefficients ) const; template< class C , unsigned int ... FEMSigs > DenseNodeData< C , UIntPack< FEMSigs ... > > denseCoefficients( const SparseNodeData< C , UIntPack< FEMSigs ... > >& coefficients ) const; + void trimToDepth( LocalDepth coarseDepth ); + + template< class C , unsigned int ... FEMSigs > DenseNodeData< C , UIntPack< FEMSigs ... > > trimToDepth( const DenseNodeData< C , UIntPack< FEMSigs ... > >& coefficients , LocalDepth coarseDepth ) const; + template< class C , unsigned int ... FEMSigs > SparseNodeData< C , UIntPack< FEMSigs ... > > trimToDepth( const SparseNodeData< C , UIntPack< FEMSigs ... > >& coefficients , LocalDepth coarseDepth ) const; + + template< typename T , unsigned int PointD , typename ConstraintDual , typename SystemDual > + ApproximatePointInterpolationInfo< T , PointD , ConstraintDual , SystemDual > trimToDepth( const ApproximatePointInterpolationInfo< T , PointD , ConstraintDual , SystemDual > &iInfo , LocalDepth coarseDepth ) const; + template< typename T , typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > + ApproximatePointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual > trimToDepth( const ApproximatePointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual > &iInfo , LocalDepth coarseDepth ) const; // For each (valid) fem node, compute the ratio of the sum of active prolongation weights to the sum of total prolongation weights // If the prolongToChildren flag is set, then these weights are pushed to the children by computing the ratio of the prolongation of the above weights to the prolongation of unity weights template< unsigned int ... FEMSigs > DenseNodeData< Real , UIntPack< FEMSigs ... > > supportWeights( UIntPack< FEMSigs ... > ) const; template< unsigned int ... FEMSigs > DenseNodeData< Real , UIntPack< FEMSigs ... > > prolongationWeights( UIntPack< FEMSigs ... > , bool prolongToChildren ) const; + protected: ////////////////////////////////////////////// @@ -1931,16 +2232,20 @@ class FEMTree template< unsigned int WeightDegree , class WeightKey > void _getSampleDepthAndWeight( const DensityEstimator< WeightDegree >& densityWeights , const FEMTreeNode* node , Point< Real , Dim > position , WeightKey& weightKey , Real& depth , Real& weight ) const; template< unsigned int WeightDegree , class WeightKey > - void _getSampleDepthAndWeight( const DensityEstimator< WeightDegree >& densityWeights , Point< Real , Dim > position , WeightKey& weightKey , Real& depth , Real& weight ) const; + void _getSampleDepthAndWeight( const DensityEstimator< WeightDegree >& densityWeights , Point< Real , Dim > position , WeightKey& weightKey , Real& depth , Real& weight ) const; template< bool CreateNodes , bool ThreadSafe , class V , unsigned int ... DataSigs > void _splatPointData( Allocator< FEMTreeNode > *nodeAllocator , FEMTreeNode* node , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey ); - template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > Real _splatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >& densityWeights , Real minDepthCutoff , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , LocalDepth minDepth , LocalDepth maxDepth , int dim , Real depthBias ); - template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > Real _multiSplatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >* densityWeights , FEMTreeNode* node , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , int dim ); + template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > Point< Real , 2 > _splatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >& densityWeights , Real minDepthCutoff , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , LocalDepth minDepth , LocalDepth maxDepth , int dim , Real depthBias ); + template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > Point< Real , 2 > _splatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >& densityWeights , Real minDepthCutoff , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , LocalDepth minDepth , std::function< int ( Point< Real , Dim > ) > &pointDepthFunctor , int dim , Real depthBias ); + template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > Point< Real , 2 > _multiSplatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >* densityWeights , FEMTreeNode* node , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , int dim ); template< unsigned int WeightDegree , class V , unsigned int ... DataSigs > Real _nearestMultiSplatPointData( const DensityEstimator< WeightDegree >* densityWeights , FEMTreeNode* node , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , int dim=Dim ); template< class V , class Coefficients , unsigned int D , unsigned int ... DataSigs > void _addEvaluation( const Coefficients& coefficients , Point< Real , Dim > p , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , V &value ) const; template< class V , class Coefficients , unsigned int D , unsigned int ... DataSigs > void _addEvaluation( const Coefficients& coefficients , Point< Real , Dim > p , LocalDepth pointDepth , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , V &value ) const; + public: + template< bool XMajor , class V , unsigned int ... DataSigs > Pointer( V ) regularGridEvaluate( const DenseNodeData< V , UIntPack< DataSigs ... > >& coefficients , int& res , LocalDepth depth=-1 , bool primal=false ) const; + template< bool XMajor , class V , unsigned int ... DataSigs > Pointer( V ) regularGridEvaluate( const DenseNodeData< V , UIntPack< DataSigs ... > >& coefficients , const unsigned int begin[Dim] , const unsigned int end[Dim] , unsigned int res[Dim] , bool primal=false ) const; template< bool XMajor , class V , unsigned int ... DataSigs > Pointer( V ) regularGridUpSample( const DenseNodeData< V , UIntPack< DataSigs ... > >& coefficients , LocalDepth depth=-1 ) const; template< bool XMajor , class V , unsigned int ... DataSigs > Pointer( V ) regularGridUpSample( const DenseNodeData< V , UIntPack< DataSigs ... > >& coefficients , const int begin[Dim] , const int end[Dim] , LocalDepth depth=-1 ) const; template< class V , unsigned int ... DataSigs > V average( const DenseNodeData< V , UIntPack< DataSigs ... > >& coefficients ) const; @@ -1967,8 +2272,10 @@ class FEMTree protected: // [NOTE] The input/output for this method is pre-scaled by weight template< typename T > bool _setInterpolationInfoFromChildren( FEMTreeNode* node , SparseNodeData< T , IsotropicUIntPack< Dim , FEMTrivialSignature > >& iInfo ) const; - template< typename T , unsigned int PointD , typename ConstraintDual > SparseNodeData< DualPointInfo < Dim , Real , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > _densifyInterpolationInfoAndSetDualConstraints( const std::vector< PointSample >& samples , ConstraintDual constraintDual , int adaptiveExponent ) const; - template< typename T , typename Data , unsigned int PointD , typename ConstraintDual > SparseNodeData< DualPointAndDataInfo< Dim , Real , Data , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > _densifyInterpolationInfoAndSetDualConstraints( const std::vector< PointSample >& samples , ConstPointer( Data ) sampleData , ConstraintDual constraintDual , int adaptiveExponent ) const; + template< typename T , unsigned int PointD , typename ConstraintDual > SparseNodeData< DualPointInfo < Dim , Real , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > _densifyInterpolationInfoAndSetDualConstraints( const std::vector< PointSample >& samples , ConstraintDual constraintDual , LocalDepth maxDepth , int adaptiveExponent ) const; + template< typename T , typename Data , unsigned int PointD , typename ConstraintDual > SparseNodeData< DualPointAndDataInfo< Dim , Real , Data , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > _densifyInterpolationInfoAndSetDualConstraints( const std::vector< PointSample >& samples , ConstPointer( Data ) sampleData , ConstraintDual constraintDual , LocalDepth maxDepth , int adaptiveExponent ) const; + template< typename T , unsigned int PointD , typename ConstraintDual > void _densifyInterpolationInfoAndSetDualConstraints( SparseNodeData< DualPointInfo < Dim , Real , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > &iInfo , const std::vector< PointSample >& samples , ConstraintDual constraintDual , LocalDepth maxDepth , int adaptiveExponent ) const; + template< typename T , typename Data , unsigned int PointD , typename ConstraintDual > void _densifyInterpolationInfoAndSetDualConstraints( SparseNodeData< DualPointAndDataInfo< Dim , Real , Data , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > &iInfo , const std::vector< PointSample >& samples , ConstPointer( Data ) sampleData , ConstraintDual constraintDual , LocalDepth maxDepth , int adaptiveExponent ) const; template< typename T , unsigned int PointD , typename ConstraintDual > SparseNodeData< DualPointInfoBrood < Dim , Real , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > _densifyChildInterpolationInfoAndSetDualConstraints( const std::vector< PointSample >& samples , ConstraintDual constraintDual , bool noRescale ) const; template< typename T , typename Data , unsigned int PointD , typename ConstraintDual > SparseNodeData< DualPointAndDataInfoBrood< Dim , Real , Data , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > _densifyChildInterpolationInfoAndSetDualConstraints( const std::vector< PointSample >& samples , ConstPointer( Data ) sampleData , ConstraintDual constraintDual , bool noRescale ) const; @@ -1976,8 +2283,11 @@ class FEMTree template< unsigned int ... FEMSigs1 > void _setFEM1ValidityFlags( UIntPack< FEMSigs1 ... > ) const; template< unsigned int ... FEMSigs2 > void _setFEM2ValidityFlags( UIntPack< FEMSigs2 ... > ) const; template< class HasDataFunctor > void _clipTree( const HasDataFunctor& f , LocalDepth fullDepth ); + public: + template< unsigned int PointD , unsigned int ... FEMSigs > SparseNodeData< CumulativeDerivativeValues< Real , Dim , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > leafValues( const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , int maxDepth=-1 ) const; + protected: ///////////////////////////////////// @@ -2034,6 +2344,7 @@ class FEMTree typename FEMIntegrator::template PointEvaluator< UIntPack< FEMSigs ... > , IsotropicUIntPack< Dim , PointD > >* _pointEvaluator; friend FEMTree; }; + template< class V , unsigned int _PointD , unsigned int ... FEMSigs , unsigned int PointD > CumulativeDerivativeValues< V , Dim , _PointD > _getCenterValues( const ConstPointSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& neighborKey , const FEMTreeNode* node , ConstPointer( V ) solution , ConstPointer( V ) coarseSolution , const _Evaluator< UIntPack< FEMSigs ... > , PointD >& evaluator , int maxDepth , bool isInterior ) const; template< class V , unsigned int _PointD , unsigned int ... FEMSigs , unsigned int PointD > @@ -2046,7 +2357,7 @@ class FEMTree struct CornerLoopData { typedef UIntPack< SupportSizes ... > _SupportSizes; -// static const unsigned int supportSizes[] = { SupportSizes ... }; + // static const unsigned int supportSizes[] = { SupportSizes ... }; static const unsigned int supportSizes[]; unsigned int ccSize[1<::Size ]; @@ -2141,7 +2452,7 @@ class FEMTree void addValue( Point< Real , Dim > p , T &t , int thread=0 , const FEMTreeNode* node=NULL ); }; - static double _MaxMemoryUsage , _LocalMemoryUsage; +protected: template< unsigned int Idx , typename ... DenseOrSparseNodeData > typename std::enable_if< ( Idx==sizeof...(DenseOrSparseNodeData) ) >::type _reorderDenseOrSparseNodeData( ConstPointer( node_index_type ) map , size_t sz , std::tuple< DenseOrSparseNodeData* ... > data ){} @@ -2162,27 +2473,28 @@ class FEMTree } public: - static double MaxMemoryUsage( void ){ return _MaxMemoryUsage; } - static double LocalMemoryUsage( void ){ return _LocalMemoryUsage; } - static void ResetLocalMemoryUsage( void ){ _LocalMemoryUsage = 0; } - static double MemoryUsage( void ); + FEMTree( size_t blockSize ); - FEMTree( FILE* fp , XForm< Real , Dim+1 > &xForm , size_t blockSize ); + FEMTree( BinaryStream &stream , XForm< Real , Dim+1 > &xForm , size_t blockSize ); + template< unsigned int CrossDegree , unsigned int Pad > + static FEMTree< Dim , Real > *Slice( const FEMTree< Dim+1 , Real > &tree , unsigned int sliceDepth , unsigned int sliceIndex , bool includeBounds , size_t blockSize ); + + static FEMTree< Dim , Real > *Merge( const FEMTree< Dim , Real > &tree1 , const FEMTree< Dim , Real > &tree2 , size_t blockSize ); ~FEMTree( void ) { - if( _tree ) for( int c=0 ; c<(1< xForm ) const; - static void WriteParameter( FILE* fp ) + void write( BinaryStream &stream , XForm< Real , Dim+1 > xForm , bool serialize ) const; + static void WriteParameter( BinaryStream &stream ) { FEMTreeRealType realType; if ( typeid( Real )==typeid( float ) ) realType=FEM_TREE_REAL_FLOAT; else if( typeid( Real )==typeid( double ) ) realType=FEM_TREE_REAL_DOUBLE; else ERROR_OUT( "Unrecognized real type" ); - fwrite( &realType , sizeof(FEMTreeRealType) , 1 , fp ); + stream.write( realType ); int dim = Dim; - fwrite( &dim , sizeof(int) , 1 , fp ); + stream.write( dim ); } template< unsigned int LeftRadius , unsigned int RightRadius , bool CreateNodes , typename ProcessingNodeFunctor , typename ... DenseOrSparseNodeData , typename InitializeFunctor > void processNeighbors( ProcessingNodeFunctor processNodes , std::tuple< DenseOrSparseNodeData *... > data , InitializeFunctor initialize ); @@ -2190,10 +2502,10 @@ class FEMTree template< unsigned int Radius , bool CreateNodes , typename ProcessingNodeFunctor , typename ... DenseOrSparseNodeData , typename InitializeFunctor > void processNeighbors( ProcessingNodeFunctor processNodes , std::tuple< DenseOrSparseNodeData *... > data , InitializeFunctor initialize ){ processNeighbors< Radius , Radius , CreateNodes >( processNodes , data , initialize ); } template< unsigned int Radius , bool CreateNodes , typename ... DenseOrSparseNodeData , typename InitializeFunctor > void processNeighbors( FEMTreeNode** nodes , size_t nodeCount , std::tuple< DenseOrSparseNodeData *... > data , InitializeFunctor initialize ){ processNeighbors< Radius , Radius , CreateNodes >( nodes , nodeCount , data , initialize ); } - template< unsigned int LeftRadius , unsigned int RightRadius , bool CreateNodes , typename ProcessingNodeFunctor , typename ... DenseOrSparseNodeData > void processNeighbors( ProcessingNodeFunctor processNodes , std::tuple< DenseOrSparseNodeData *... > data ){ return processNeighbors< LeftRadius , RightRadius , CreateNodes >( processNodes , data , []( const FEMTreeNode * ){} ); } - template< unsigned int LeftRadius , unsigned int RightRadius , bool CreateNodes , typename ... DenseOrSparseNodeData > void processNeighbors( FEMTreeNode** nodes , size_t nodeCount , std::tuple< DenseOrSparseNodeData *... > data ){ return processNeighbors< LeftRadius , RightRadius , CreateNodes >( nodes , nodeCount , data , []( const FEMTreeNode * ){} ); } - template< unsigned int Radius , bool CreateNodes , typename ProcessingNodeFunctor , typename ... DenseOrSparseNodeData > void processNeighbors( ProcessingNodeFunctor processNodes , std::tuple< DenseOrSparseNodeData *... > data ){ return processNeighbors< Radius , CreateNodes >( processNodes , data , []( const FEMTreeNode * ){} ); } - template< unsigned int Radius , bool CreateNodes , typename ... DenseOrSparseNodeData > void processNeighbors( FEMTreeNode** nodes , size_t nodeCount , std::tuple< DenseOrSparseNodeData *... > data ){ return processNeighbors< Radius , CreateNodes >( nodes , nodeCount , data , []( const FEMTreeNode * ){} ) ; } + template< unsigned int LeftRadius , unsigned int RightRadius , bool CreateNodes , typename ProcessingNodeFunctor , typename ... DenseOrSparseNodeData > void processNeighbors( ProcessingNodeFunctor processNodes , std::tuple< DenseOrSparseNodeData *... > data ){ return processNeighbors< LeftRadius , RightRadius , CreateNodes >( processNodes , data , []( const FEMTreeNode * ){} ); } + template< unsigned int LeftRadius , unsigned int RightRadius , bool CreateNodes , typename ... DenseOrSparseNodeData > void processNeighbors( FEMTreeNode** nodes , size_t nodeCount , std::tuple< DenseOrSparseNodeData *... > data ){ return processNeighbors< LeftRadius , RightRadius , CreateNodes >( nodes , nodeCount , data , []( const FEMTreeNode * ){} ); } + template< unsigned int Radius , bool CreateNodes , typename ProcessingNodeFunctor , typename ... DenseOrSparseNodeData > void processNeighbors( ProcessingNodeFunctor processNodes , std::tuple< DenseOrSparseNodeData *... > data ){ return processNeighbors< Radius , CreateNodes >( processNodes , data , []( const FEMTreeNode * ){} ); } + template< unsigned int Radius , bool CreateNodes , typename ... DenseOrSparseNodeData > void processNeighbors( FEMTreeNode** nodes , size_t nodeCount , std::tuple< DenseOrSparseNodeData *... > data ){ return processNeighbors< Radius , CreateNodes >( nodes , nodeCount , data , []( const FEMTreeNode * ){} ) ; } template< unsigned int LeftRadius , unsigned int RightRadius , typename IsProcessingNodeFunctor , typename ProcessingKernel > void processNeighboringLeaves( IsProcessingNodeFunctor isProcessingNode , ProcessingKernel kernel , bool processSubTree ); template< unsigned int LeftRadius , unsigned int RightRadius , typename ProcessingKernel > void processNeighboringLeaves( FEMTreeNode** nodes , size_t nodeCount , ProcessingKernel kernel , bool processSubTree ); @@ -2201,33 +2513,72 @@ class FEMTree template< unsigned int Radius , typename ProcessingKernel > void processNeighboringLeaves( FEMTreeNode** nodes , size_t nodeCount , ProcessingKernel kernel , bool processSubTree ){ return processNeighboringLeaves< Radius , Radius >( nodes , nodeCount , kernel , processSubTree ); } template< unsigned int CoDim , unsigned int DensityDegree > - typename FEMTree::template DensityEstimator< DensityDegree >* setDensityEstimator( const std::vector< PointSample >& samples , LocalDepth splatDepth , Real samplesPerNode ); + typename FEMTree::template DensityEstimator< DensityDegree > *setDensityEstimator( const std::vector< PointSample >& samples , LocalDepth splatDepth , Real samplesPerNode ); + template< unsigned int CoDim , unsigned int DensityDegree > + void updateDensityEstimator( typename FEMTree::template DensityEstimator< DensityDegree > &density , const std::vector< PointSample >& samples , LocalDepth minSplatDepth , LocalDepth maxSplatDepth , Real samplesPerNode ); + template< unsigned int CoDim , unsigned int DensityDegree > + typename FEMTree::template DensityEstimator< DensityDegree > *setDensityEstimator( const std::vector< PointSample >& samples , LocalDepth splatDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real samplesPerNode ); + template< unsigned int CoDim , unsigned int DensityDegree > + void updateDensityEstimator( typename FEMTree::template DensityEstimator< DensityDegree > &density , const std::vector< PointSample >& samples , LocalDepth minSplatDepth , LocalDepth maxSplatDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real samplesPerNode ); template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > - SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , Real& pointWeightSum , std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction ); + SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction ); +#if defined(_WIN32) || defined(_WIN64) + template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > + SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction = []( InData ){ return 0.f; } ); +#else // !_WIN32 && !_WIN64 + template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > + SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction = []( InData ){ return (Real)0; } ); +#endif // _WIN32 || _WIN64 template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > + SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction ); #if defined(_WIN32) || defined(_WIN64) - SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , Real& pointWeightSum , std::function< bool ( InData , OutData & ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction = []( InData ){ return 0.f; } ); + template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > + SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction = []( InData ){ return 0.f; } ); #else // !_WIN32 && !_WIN64 - SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , Real& pointWeightSum , std::function< bool ( InData , OutData & ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction = []( InData ){ return (Real)0; } ); + template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > + SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction = []( InData ){ return (Real)0; } ); #endif // _WIN32 || _WIN64 template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data > - SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > setExtrapolatedDataField( const std::vector< PointSample >& samples , std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density , bool nearest=false ); - template< unsigned int MaxDegree , unsigned int SystemDegree , typename HasDataFunctor , typename IsDirichletLeafFunctor , typename ... InterpolationInfos , typename ... DenseOrSparseNodeData > void finalizeForMultigrid( LocalDepth baseDepth , LocalDepth fullDepth , const HasDataFunctor hasData , const IsDirichletLeafFunctor isDirichletLeaf , std::tuple< InterpolationInfos *... > interpolationInfos , std::tuple< DenseOrSparseNodeData *... > data ); - template< unsigned int MaxDegree , unsigned int SystemDegree , typename HasDataFunctor , typename IsDirichletLeafFunctor , typename ... InterpolationInfos > void finalizeForMultigrid( LocalDepth baseDepth , LocalDepth fullDepth , const HasDataFunctor hasData , const IsDirichletLeafFunctor isDirichletLeaf , std::tuple< InterpolationInfos *... > interpolationInfos ){ finalizeForMultigrid< MaxDegree , SystemDegree , HasDataFunctor >( baseDepth , fullDepth , hasData , isDirichletLeaf , interpolationInfos , std::make_tuple() ); } + SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > setExtrapolatedDataField( const std::vector< PointSample >& samples , const std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density , bool nearest=false ); + template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data > + void updateExtrapolatedDataField( SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > &dataField , const std::vector< PointSample >& samples , const std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density , bool nearest=false ); + + template< unsigned int MaxDegree , unsigned int SystemDegree , typename AddNodeFunctor , typename HasDataFunctor , typename IsDirichletLeafFunctor , typename ... InterpolationInfos , typename ... DenseOrSparseNodeData > std::vector< node_index_type > finalizeForMultigridWithDirichlet( LocalDepth baseDepth , const AddNodeFunctor addNodeFunctor , const HasDataFunctor hasDataFunctor , const IsDirichletLeafFunctor isDirichletLeafFunctor , std::tuple< InterpolationInfos *... > interpolationInfos , std::tuple< DenseOrSparseNodeData *... > data ); + template< unsigned int MaxDegree , unsigned int SystemDegree , typename AddNodeFunctor , typename HasDataFunctor , typename IsDirichletLeafFunctor , typename ... InterpolationInfos > std::vector< node_index_type > finalizeForMultigridWithDirichlet( LocalDepth baseDepth , const AddNodeFunctor addNodeFunctor , const HasDataFunctor hasDataFunctor , const IsDirichletLeafFunctor isDirichletLeafFunctor , std::tuple< InterpolationInfos *... > interpolationInfos ){ return finalizeForMultigridWithDirichlet< MaxDegree , SystemDegree , AddNodeFunctor , HasDataFunctor >( baseDepth , addNodeFunctor , hasDataFunctor , isDirichletLeafFunctor , interpolationInfos , std::make_tuple() ); } + + template< unsigned int MaxDegree , unsigned int SystemDegree , typename AddNodeFunctor , typename HasDataFunctor , typename ... InterpolationInfos , typename ... DenseOrSparseNodeData > std::vector< node_index_type > finalizeForMultigrid( LocalDepth baseDepth , const AddNodeFunctor addNodeFunctor , const HasDataFunctor hasDataFunctor , std::tuple< InterpolationInfos *... > interpolationInfos , std::tuple< DenseOrSparseNodeData *... > data ); + template< unsigned int MaxDegree , unsigned int SystemDegree , typename AddNodeFunctor , typename HasDataFunctor , typename ... InterpolationInfos > std::vector< node_index_type > finalizeForMultigrid( LocalDepth baseDepth , const AddNodeFunctor addNodeFunctor , const HasDataFunctor hasDataFunctor , std::tuple< InterpolationInfos *... > interpolationInfos ){ return finalizeForMultigrid< MaxDegree , SystemDegree , AddNodeFunctor , HasDataFunctor >( baseDepth , addNodeFunctor , hasDataFunctor , interpolationInfos , std::make_tuple() ); } + +protected: + template< bool HasDirichlet , unsigned int MaxDegree , unsigned int SystemDegree , typename AddNodeFunctor , typename HasDataFunctor , typename IsDirichletLeafFunctor , typename ... InterpolationInfos , typename ... DenseOrSparseNodeData > + std::vector< node_index_type > _finalizeForMultigrid( LocalDepth baseDepth , const AddNodeFunctor addNodeFunctor , const HasDataFunctor hasDataFunctor , const IsDirichletLeafFunctor isDirichletLeafFunctor , std::tuple< InterpolationInfos *... > interpolationInfos , std::tuple< DenseOrSparseNodeData *... > data ); +public: + template< typename ... InterpolationInfos , typename ... DenseOrSparseNodeData > std::vector< node_index_type > setSortedTreeNodes( std::tuple< InterpolationInfos *... > interpolationInfos , std::tuple< DenseOrSparseNodeData *... > data ); + template< typename ... InterpolationInfos > std::vector< node_index_type > setSortedTreeNodes( std::tuple< InterpolationInfos *... > interpolationInfos ){ return setSortedTreeNodes( interpolationInfos , std::make_tuple() ); } + template< class ... DenseOrSparseNodeData > void resetIndices( std::tuple< DenseOrSparseNodeData *... > data ); + template< typename PruneChildrenFunctor , typename ... InterpolationInfos , typename ... DenseOrSparseNodeData > + void pruneChildren( const PruneChildrenFunctor pruneChildren , std::tuple< InterpolationInfos *... > interpolationInfos , std::tuple< DenseOrSparseNodeData *... > data ); + template< unsigned int ... FEMSigs > DenseNodeData< Real , UIntPack< FEMSigs ... > > initDenseNodeData( UIntPack< FEMSigs ... > ) const; template< class Data , unsigned int ... FEMSigs > DenseNodeData< Data , UIntPack< FEMSigs ... > > initDenseNodeData( UIntPack< FEMSigs ... > ) const; + template< unsigned int Pad , unsigned int FEMSig , unsigned int ... FEMSigs , typename Data > + void slice( const FEMTree< Dim+1 , Real > &tree , unsigned int d , const DenseNodeData< Data , UIntPack< FEMSigs ... , FEMSig > > &coefficients , DenseNodeData< Data , UIntPack< FEMSigs ... > > &sliceCoefficients , unsigned int sliceDepth , unsigned int sliceIndex ) const; + + template< unsigned int ... FEMSigs , typename Data > + void merge( const FEMTree< Dim , Real > &tree , const DenseNodeData< Data , UIntPack< FEMSigs ... > > &coefficients , DenseNodeData< Data , UIntPack< FEMSigs ... > > &mergedCoefficients ) const; + // Add multiple-dimensions -> one-dimension constraints template< typename T , unsigned int ... FEMDegrees , unsigned int ... FEMSigs , unsigned int ... CDegrees , unsigned int ... CSigs , unsigned int CDim > void addFEMConstraints( typename BaseFEMIntegrator::template Constraint< UIntPack< FEMDegrees ... > , UIntPack< CDegrees ... > , CDim >& F , const _SparseOrDenseNodeData< Point< T , CDim > , UIntPack< CSigs ... > >& coefficients , DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , LocalDepth maxDepth ) const { typedef SparseNodeData< Point< T , CDim > , UIntPack< CSigs ... > > SparseType; typedef DenseNodeData< Point< T , CDim > , UIntPack< CSigs ... > > DenseType; - static_assert( sizeof...( FEMDegrees )==Dim && sizeof...( FEMSigs )==Dim && sizeof...( CDegrees )==Dim && sizeof...( CSigs )==Dim , "[ERROR] Dimensions don't match" ); + static_assert( sizeof...( FEMDegrees )==Dim && sizeof...( FEMSigs )==Dim && sizeof...( CDegrees )==Dim && sizeof...( CSigs )==Dim , "[ERROR] Dimensions don't match" ); static_assert( UIntPack< FEMDegrees ... >::template Compare< UIntPack< FEMSignature< FEMSigs >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); static_assert( UIntPack< CDegrees ... >::template Compare< UIntPack< FEMSignature< CSigs >::Degree ... > >::Equal , "[ERROR] Constraint signature and degrees don't match" ); if ( typeid(coefficients)==typeid(SparseType) ) return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< CSigs ... >() , F , static_cast< const SparseType& >( coefficients ) , constraints() , maxDepth ); @@ -2263,6 +2614,8 @@ class FEMTree protected: template< unsigned int MaxDegree > void _supportApproximateProlongation( void ); + template< unsigned int SystemDegree > void _markInexactInterpolationElements( void); + template< unsigned int SystemDegree > void _addAndMarkExactInterpolationElements( void ); template< unsigned int SystemDegree > void _markNonBaseDirichletElements( void ); template< unsigned int SystemDegree > void _markBaseDirichletElements( void ); @@ -2457,36 +2810,42 @@ class FEMTree SolverInfo( void ) : cgDepth(0) , wCycle(false) , cascadic(true) , iters(1) , vCycles(1) , cgAccuracy(0.) , verbose(false) , showResidual(false) , showGlobalResidual(SHOW_GLOBAL_RESIDUAL_NONE) , sliceBlockSize(1) , sorRestrictionFunction( []( Real , Real ){ return (Real)1; } ) , sorProlongationFunction( []( Real , Real ){ return (Real)1; } ) , useSupportWeights( false ) , useProlongationSupportWeights( false ) , baseVCycles(1) , clearSolution(true) { } }; // Solve the linear system + // There are several depths playing into the solver: + // 1. maxDepth: The maximum depth of the tree + // 2. solveDepth: The depth up to which we can solve (solveDepth<=maxDepth) + // 3. fullDepth: The depth up to which the octree is completely refined (fullDepth<=maxDepth) + // 4. baseDepth: The depth up to which the system is defined through the regular prolongation operators (baseDepth<=fullDepth) template< unsigned int ... FEMSigs , typename T , typename TDotT , typename ... InterpolationInfos > - void solveSystem( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , DenseNodeData< T , UIntPack< FEMSigs ... > >& solution , TDotT Dot , LocalDepth maxSolveDepth , const SolverInfo& solverInfo , std::tuple< InterpolationInfos *... > interpolationInfos=std::make_tuple() ) const; + void solveSystem( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , DenseNodeData< T , UIntPack< FEMSigs ... > >& solution , TDotT Dot , LocalDepth minSolveDepth , LocalDepth maxSolveDepth , const SolverInfo& solverInfo , std::tuple< InterpolationInfos *... > interpolationInfos=std::make_tuple() ) const; template< unsigned int ... FEMSigs , typename T , typename TDotT , typename ... InterpolationInfos > - DenseNodeData< T , UIntPack< FEMSigs ... > > solveSystem( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , TDotT Dot , LocalDepth maxSolveDepth , const SolverInfo& solverInfo , std::tuple< InterpolationInfos *... > interpolationInfos=std::make_tuple() ) const; + DenseNodeData< T , UIntPack< FEMSigs ... > > solveSystem( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , TDotT Dot , LocalDepth minSolveDepth , LocalDepth maxSolveDepth , const SolverInfo& solverInfo , std::tuple< InterpolationInfos *... > interpolationInfos=std::make_tuple() ) const; template< unsigned int ... FEMSigs , typename ... InterpolationInfos > - void solveSystem( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& constraints , DenseNodeData< Real , UIntPack< FEMSigs ... > >& solution , LocalDepth maxSolveDepth , const SolverInfo& solverInfo , std::tuple< InterpolationInfos *... > interpolationInfos=std::make_tuple() ) const + void solveSystem( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& constraints , DenseNodeData< Real , UIntPack< FEMSigs ... > >& solution , LocalDepth minSolveDepth , LocalDepth maxSolveDepth , const SolverInfo& solverInfo , std::tuple< InterpolationInfos *... > interpolationInfos=std::make_tuple() ) const { - return solveSystem< FEMSigs ... , Real >( UIntPack< FEMSigs ... >() , F , constraints , solution , []( Real v , Real w ){ return v*w; } , maxSolveDepth , solverInfo , interpolationInfos ); + return solveSystem< FEMSigs ... , Real >( UIntPack< FEMSigs ... >() , F , constraints , solution , []( Real v , Real w ){ return v*w; } , minSolveDepth , maxSolveDepth , solverInfo , interpolationInfos ); } template< unsigned int ... FEMSigs , typename ... InterpolationInfos > - DenseNodeData< Real , UIntPack< FEMSigs ... > > solveSystem( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& constraints , LocalDepth maxSolveDepth , const SolverInfo& solverInfo , std::tuple< InterpolationInfos *... > interpolationInfos=std::make_tuple() ) const + DenseNodeData< Real , UIntPack< FEMSigs ... > > solveSystem( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& constraints , LocalDepth minSolveDepth , LocalDepth maxSolveDepth , const SolverInfo& solverInfo , std::tuple< InterpolationInfos *... > interpolationInfos=std::make_tuple() ) const { - return solveSystem( UIntPack< FEMSigs ... >() , F , constraints , []( Real v , Real w ){ return v*w; } , maxSolveDepth , solverInfo , interpolationInfos ); + return solveSystem( UIntPack< FEMSigs ... >() , F , constraints , []( Real v , Real w ){ return v*w; } , minSolveDepth , maxSolveDepth , solverInfo , interpolationInfos ); } FEMTreeNode& spaceRoot( void ){ return *_spaceRoot; } const FEMTreeNode &spaceRoot( void ) const { return *_spaceRoot; } - const FEMTreeNode& tree( void ) const { return *_tree; } + const FEMTreeNode& tree( void ) const { return _tree; } _NodeInitializer &initializer( void ){ return _nodeInitializer; } - size_t leaves( void ) const { return _tree->leaves(); } - size_t nodes( void ) const { int count = 0 ; for( const FEMTreeNode* n=_tree->nextNode() ; n ; n=_tree->nextNode( n ) ) if( IsActiveNode< Dim >( n ) ) count++ ; return count; } - size_t ghostNodes( void ) const { int count = 0 ; for( const FEMTreeNode* n=_tree->nextNode() ; n ; n=_tree->nextNode( n ) ) if( !IsActiveNode< Dim >( n ) ) count++ ; return count; } - size_t dirichletNodes( void ) const { int count = 0 ; for( const FEMTreeNode* n=_tree->nextNode() ; n ; n=_tree->nextNode( n ) ) if( n->nodeData.getDirichletNodeFlag() ) count++ ; return count; } - size_t dirichletElements( void ) const { int count = 0 ; for( const FEMTreeNode* n=_tree->nextNode() ; n ; n=_tree->nextNode( n ) ) if( n->nodeData.getDirichletElementFlag() ) count++ ; return count; } - inline size_t validSpaceNodes( void ) const { int count = 0 ; for( const FEMTreeNode* 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 FEMTreeNode* n=_tree->nextNode() ; n ; n=_tree->nextNode( n ) ) if( _localDepth(n)==d && isValidSpaceNode( n ) ) count++ ; return count; } - template< unsigned int ... FEMSigs > size_t validFEMNodes( UIntPack< FEMSigs ... > ) const { int count = 0 ; for( const FEMTreeNode* n=_tree->nextNode() ; n ; n=_tree->nextNode( n ) ) if( isValidFEMNode( UIntPack< FEMSigs ... >() , n ) ) count++ ; return count; } - template< unsigned int ... FEMSigs > size_t validFEMNodes( UIntPack< FEMSigs ... > , LocalDepth d ) const { int count = 0 ; for( const FEMTreeNode* n=_tree->nextNode() ; n ; n=_tree->nextNode( n ) ) if( _localDepth(n)==d && isValidFEMNode( UIntPack< FEMSigs ... >() , n ) ) count++ ; return count; } - template< unsigned int ... FEMSigs > size_t validUnlockedFEMNodes( UIntPack< FEMSigs ... > ) const { int count = 0 ; for( const FEMTreeNode* n=_tree->nextNode() ; n ; n=_tree->nextNode( n ) ) if( isValidFEMNode( UIntPack< FEMSigs ... >() , n ) && !n->nodeData.getDirichletSupportedFlag() ) count++ ; return count; } - template< unsigned int ... FEMSigs > size_t validUnlockedFEMNodes( UIntPack< FEMSigs ... > , LocalDepth d ) const { int count = 0 ; for( const FEMTreeNode* n=_tree->nextNode() ; n ; n=_tree->nextNode( n ) ) if( _localDepth(n)==d && isValidFEMNode( UIntPack< FEMSigs ... >() , n ) && !n->nodeData.getDirichletElementFlag() ) count++ ; return count; } + size_t leaves( void ) const { return _tree.leaves(); } + size_t allNodes ( void ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode * ){ count++; } ) ; return count; } + size_t activeNodes ( void ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( IsActiveNode< Dim >( n ) ) count++; } ) ; return count; } + size_t ghostNodes ( void ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( !IsActiveNode< Dim >( n ) ) count++; } ) ; return count; } + size_t dirichletNodes ( void ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( n->nodeData.getDirichletNodeFlag() ) count++; } ) ; return count; } + size_t dirichletElements ( void ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( n->nodeData.getDirichletElementFlag() ) count++; } ) ; return count; } + inline size_t validSpaceNodes( void ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( isValidSpaceNode( n ) ) count++; } ) ; return count; } + inline size_t validSpaceNodes( LocalDepth d ) const { size_t count = 0 ; _tree.process( [&]( const FEMTreeNode *n ){ if( _localDepth(n)==d && isValidSpaceNode( n ) ) count++; } ) ; return count; } + template< unsigned int ... FEMSigs > size_t validFEMNodes ( UIntPack< FEMSigs ... > ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( isValidFEMNode( UIntPack< FEMSigs ... >() , n ) ) count++; } ) ; return count; } + template< unsigned int ... FEMSigs > size_t validFEMNodes ( UIntPack< FEMSigs ... > , LocalDepth d ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( _localDepth(n)==d && isValidFEMNode( UIntPack< FEMSigs ... >() , n ) ) count++; } ) ; return count; } + template< unsigned int ... FEMSigs > size_t validUnlockedFEMNodes( UIntPack< FEMSigs ... > ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( isValidFEMNode( UIntPack< FEMSigs ... >() , n ) && !n->nodeData.getDirichletSupportedFlag() ) count++; } ) ; return count; } + template< unsigned int ... FEMSigs > size_t validUnlockedFEMNodes( UIntPack< FEMSigs ... > , LocalDepth d ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( _localDepth(n)==d && isValidFEMNode( UIntPack< FEMSigs ... >() , n ) && !n->nodeData.getDirichletElementFlag() ) count++; } ) ; return count; } LocalDepth depth( void ) const { return _spaceRoot->maxDepth(); } LocalDepth maxDepth( void ) const { return _maxDepth; } template< typename ... DenseOrSparseNodeData > @@ -2497,23 +2856,26 @@ class FEMTree { std::vector< node_index_type > map( _nodeCount ); _nodeCount = 0; - for( FEMTreeNode* node=_tree->nextNode() ; node ; node=_tree->nextNode( node ) ) + auto nodeFunctor = [&]( FEMTreeNode *node ) { node_index_type idx = node->nodeData.nodeIndex; _nodeInitializer( *node ); - if( idx!=-1 ) map[idx] = node->nodeData.nodeIndex; + if( node->nodeData.nodeIndex!=-1 ) map[ node->nodeData.nodeIndex ] = idx; node->nodeData.flags &= mask; - } + }; + _tree.processNodes( nodeFunctor ); + _reorderDenseOrSparseNodeData< 0 >( GetPointer( map ) , (size_t)_nodeCount , data ); } else { _nodeCount = 0; - for( FEMTreeNode* node=_tree->nextNode() ; node ; node=_tree->nextNode( node ) ) + auto nodeFunctor = [&]( FEMTreeNode *node ) { _nodeInitializer( *node ); node->nodeData.flags &= mask; - } + }; + _tree.processNodes( nodeFunctor ); } return _nodeCount; } @@ -2528,7 +2890,7 @@ class FEMTree template< class SReal , class Data > static Data _StencilDot( SReal p1 , Point< Data , 1 > p2 ); template< class SReal , class Data > static Data _StencilDot( Point< SReal , 1 > p1 , Data p2 ); template< class SReal , class Data > static Data _StencilDot( SReal p1 , Data p2 ); - + // We need the signatures to test if nodes are valid template< typename T , unsigned int ... FEMSigs , unsigned int ... CSigs , unsigned int ... FEMDegrees , unsigned int ... CDegrees , unsigned int CDim , class Coefficients > void _addFEMConstraints( UIntPack< FEMSigs ... > , UIntPack< CSigs ... > , typename BaseFEMIntegrator::Constraint< UIntPack< FEMDegrees ... > , UIntPack< CDegrees ... > , CDim >& F , const Coefficients& coefficients , Pointer( T ) constraints , LocalDepth maxDepth ) const; @@ -2545,19 +2907,17 @@ class FEMTree } template< typename T , typename TDotT , unsigned int ... FEMSigs1 , unsigned int ... FEMSigs2 , class Coefficients1 , class Coefficients2 > double _interpolationDot( UIntPack< FEMSigs1 ... > , UIntPack< FEMSigs2 ... > , const Coefficients1& coefficients1 , const Coefficients2& coefficients2 , TDotT Dot ) const{ return 0; } }; -template< unsigned int Dim , class Real > double FEMTree< Dim , Real >::_MaxMemoryUsage = 0; -template< unsigned int Dim , class Real > double FEMTree< Dim , Real >::_LocalMemoryUsage = 0; - template< unsigned int Dim , class Real , class Vertex > -struct IsoSurfaceExtractor +struct LevelSetExtractor { - struct IsoStats + struct Stats { - std::string toString( void ) const { return std::string( "Iso-surface extraction not supported for dimension %d" , Dim ); } + std::string toString( void ) const { return std::string( "Level-set extraction not supported for dimension %d" , Dim ); } }; + template< typename Data , typename SetVertexFunction , unsigned int ... FEMSigs , unsigned int WeightDegree , unsigned int DataSig > - static IsoStats Extract + static Stats Extract ( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , // Dummy variables for grouping the parameter const FEMTree< Dim , Real >& tree , // The tree over which the system is discretized @@ -2565,7 +2925,10 @@ struct IsoSurfaceExtractor const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , // Auxiliary spatial data const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , // The coefficients of the function Real isoValue , // The value at which to extract the level-set - CoredMeshData< Vertex , node_index_type >& mesh , // The mesh in which to store the output + unsigned int slabDepth , // The depth at which the slabs are specified + unsigned int slabStart , // The beginning slab + unsigned int slabEnd , // The ending slab + StreamingMesh< Vertex , node_index_type >& mesh , // The mesh in which to store the output const Data &zeroData , // Zero value for data (in case of dynamic allocation) const SetVertexFunction &SetVertex , // A function for setting the depth and data of a vertex bool nonLinearFit , // Should a linear interpolant be used @@ -2576,8 +2939,29 @@ struct IsoSurfaceExtractor ) { // The unspecialized implementation is not supported - WARN( "Iso-surface extraction not supported for dimension " , Dim ); - return IsoStats(); + WARN( "Level-set extraction not supported for dimension " , Dim ); + return Stats(); + } + template< typename Data , typename SetVertexFunction , unsigned int ... FEMSigs , unsigned int WeightDegree , unsigned int DataSig > + static Stats Extract + ( + UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , // Dummy variables for grouping the parameter + const FEMTree< Dim , Real >& tree , // The tree over which the system is discretized + const typename FEMTree< Dim , Real >::template DensityEstimator< WeightDegree >* densityWeights , // Density weights + const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , // Auxiliary spatial data + const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , // The coefficients of the function + Real isoValue , // The value at which to extract the level-set + StreamingMesh< Vertex , node_index_type >& mesh , // The mesh in which to store the output + const Data &zeroData , // Zero value for data (in case of dynamic allocation) + const SetVertexFunction &SetVertex , // A function for setting the depth and data of a vertex + bool nonLinearFit , // Should a linear interpolant be used + bool gradientNormals , // Compute the gradient at the iso-vertex position + bool addBarycenter , // Should we triangulate polygons by adding a mid-point + bool polygonMesh , // Should we output triangles or polygons + bool flipOrientation // Should we flip the orientation + ) + { + return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , 0 , 0 , 1 , mesh , zeroData , SetVertex , nonLinearFit , gradientNormals , addBarycenter , polygonMesh , flipOrientation ); } }; @@ -2609,9 +2993,10 @@ struct FEMTreeInitializer static DataType &GetData( PointAndDataType &pd ){ return pd.template get<1>(); } static const DataType &GetData( const PointAndDataType &pd ){ return pd.template get<1>(); } - static void BoundingBox( StreamType &stream , Point< Real , Dim >& min , Point< Real , Dim >& max ) + static void BoundingBox( StreamType &stream , Data d , Point< Real , Dim >& min , Point< Real , Dim >& max ) { PointAndDataType p; + p.template get<1>() = d; for( unsigned int d=0 ; d::infinity() , max[d] = -std::numeric_limits< Real >::infinity(); while( stream.next( p ) ) for( unsigned int d=0 ; d( min[d] , p.template get<0>()[d] ) , max[d] = std::max< Real >( max[d] , p.template get<0>()[d] ); stream.reset(); @@ -2619,9 +3004,30 @@ struct FEMTreeInitializer }; template< typename Data > - static size_t Initialize( FEMTreeNode& root , typename InputPointStream< Data >::StreamType &pointStream , int maxDepth , std::vector< PointSample >& samplePoints , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); + struct OutputPointStream + { + typedef Data DataType; + typedef VectorTypeUnion< Real , Point< Real , Dim > , Data > PointAndDataType; + typedef OutputDataStream< PointAndDataType > StreamType; + static Point< Real , Dim > &GetPoint( PointAndDataType &pd ){ return pd.template get<0>(); } + static const Point< Real , Dim > &GetPoint( const PointAndDataType &pd ){ return pd.template get<0>(); } + static DataType &GetData( PointAndDataType &pd ){ return pd.template get<1>(); } + static const DataType &GetData( const PointAndDataType &pd ){ return pd.template get<1>(); } + }; + + struct StreamInitializationData + { + friend FEMTreeInitializer; + protected: + std::vector< node_index_type > _nodeToIndexMap; + }; + + template< typename Data > + static size_t Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , typename InputPointStream< Data >::StreamType &pointStream , Data zeroData , int maxDepth , std::vector< PointSample >& samplePoints , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); template< typename Data > - static size_t Initialize( FEMTreeNode& root , typename InputPointStream< Data >::StreamType &pointStream , int maxDepth , std::vector< PointSample >& samplePoints , std::vector< typename InputPointStream< Data >::DataType > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , typename InputPointStream< Data >::DataType & ) > ProcessData = []( const Point< Real , Dim > & , typename InputPointStream< Data >::DataType & ){ return (Real)1.; } ); + static size_t Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , typename InputPointStream< Data >::StreamType &pointStream , Data zeroData , int maxDepth , std::vector< PointSample >& samplePoints , std::vector< typename InputPointStream< Data >::DataType > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , typename InputPointStream< Data >::DataType & ) > ProcessData = []( const Point< Real , Dim > & , typename InputPointStream< Data >::DataType & ){ return (Real)1.; } ); + template< typename Data > + static size_t Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , typename InputPointStream< Data >::StreamType &pointStream , Data zeroData , int maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , std::vector< PointSample >& samplePoints , std::vector< typename InputPointStream< Data >::DataType > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , typename InputPointStream< Data >::DataType & ) > ProcessData = []( const Point< Real , Dim > & , typename InputPointStream< Data >::DataType & ){ return (Real)1.; } ); // Initialize the tree using simplices static void Initialize( FEMTreeNode& root , const std::vector< Point< Real , Dim > >& vertices , const std::vector< SimplexIndex< Dim-1 , node_index_type > >& simplices , int maxDepth , std::vector< PointSample >& samples , bool mergeNodeSamples , std::vector< Allocator< FEMTreeNode > * > &nodeAllocators , std::function< void ( FEMTreeNode& ) > NodeInitializer ); @@ -2651,7 +3057,6 @@ struct FEMTreeInitializer else if( type.type==EXTERIOR ) return os << "exterior"; return os; } - }; template< unsigned int _Dim=Dim > @@ -2669,9 +3074,10 @@ struct FEMTreeInitializer template< class Data , class _Data , bool Dual=true > static size_t Initialize( FEMTreeNode& root , ConstPointer( Data ) values , ConstPointer( int ) labels , int resolution[Dim] , std::vector< NodeSample< Dim , _Data > > derivatives[Dim] , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< _Data ( const Data& ) > DataConverter = []( const Data& d ){ return (_Data)d; } ); template< bool Dual , class Data > - static unsigned int Initialize( FEMTreeNode& root , DerivativeStream< Data >& dStream , std::vector< NodeSample< Dim , Data > > derivatives[Dim] , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); + static unsigned int Initialize( FEMTreeNode& root , DerivativeStream< Data >& dStream , Data zeroData , std::vector< NodeSample< Dim , Data > > derivatives[Dim] , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); protected: + static size_t _Initialize( FEMTreeNode &node , int maxDepth , std::function< bool ( int , int[] ) > Refine , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); template< bool ThreadSafe > static size_t _AddSimplex( FEMTreeNode& root , Simplex< Real , Dim , Dim-1 >& s , int maxDepth , std::vector< PointSample >& samples , std::vector< node_index_type >* nodeToIndexMap , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); template< bool ThreadSafe > static size_t _AddSimplex( FEMTreeNode* node , Simplex< Real , Dim , Dim-1 >& s , int maxDepth , std::vector< PointSample >& samples , std::vector< node_index_type >* nodeToIndexMap , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); template< bool ThreadSafeAllocation , bool ThreadSafeSimplices > static size_t _AddSimplex( FEMTreeNode& root , node_index_type id , Simplex< Real , Dim , Dim-1 >& s , int maxDepth , std::vector< NodeSimplices< Dim , Real > >& simplices , std::vector< node_index_type >& nodeToIndexMap , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); @@ -2685,11 +3091,12 @@ template< unsigned int Dim , class Real > template< unsigned int ... SupportSizes > const unsigned int FEMTree< Dim , Real >::CornerLoopData< SupportSizes ... >::supportSizes[] = { SupportSizes ... }; + #include "FEMTree.inl" #include "FEMTree.SortedTreeNodes.inl" #include "FEMTree.WeightedSamples.inl" #include "FEMTree.System.inl" #include "FEMTree.Evaluation.inl" -#include "FEMTree.IsoSurface.specialized.inl" +#include "FEMTree.LevelSet.3D.inl" #include "FEMTree.Initialize.inl" #endif // FEM_TREE_INCLUDED diff --git a/Src/FEMTree.inl b/Src/FEMTree.inl index 814f1aee..d68efd50 100644 --- a/Src/FEMTree.inl +++ b/Src/FEMTree.inl @@ -34,49 +34,316 @@ DAMAGE. ///////////////////// // FEMTreeNodeData // ///////////////////// -FEMTreeNodeData::FEMTreeNodeData( void ){ flags = 0 , isGeometrySupported = false; } +FEMTreeNodeData::FEMTreeNodeData( void ){ flags = 0; } FEMTreeNodeData::~FEMTreeNodeData( void ) { } ///////////// // FEMTree // ///////////// + template< unsigned int Dim , class Real > -double FEMTree< Dim , Real >::MemoryUsage( void ) +void FEMTree< Dim , Real >::_init( void ) { - double mem = double( MemoryInfo::Usage() ) / (1<<20); - _MaxMemoryUsage = std::max< double >( mem , _MaxMemoryUsage ); - _LocalMemoryUsage = std::max< double >( mem , _LocalMemoryUsage ); - return mem; + // Reset the depths and offsets + int offset[Dim]; + for( int d=0 ; d::ResetDepthAndOffset( &_tree , 0 , offset ); + + // Set the _spaceRoot + _spaceRoot = &_tree; + for( int d=0 ; d<_depthOffset ; d++ ) + { + if( !_spaceRoot->children ) ERROR_OUT( "Expected child node: " , d , " / " , _depthOffset ); + else if( d==0 ) _spaceRoot = _spaceRoot->children + (1<children; + } } -template< unsigned int Dim , class Real > FEMTree< Dim , Real >::FEMTree( size_t blockSize ) : _nodeInitializer( *this ) +template< unsigned int Dim , class Real > +FEMTree< Dim , Real > *FEMTree< Dim , Real >::Merge( const FEMTree< Dim , Real > &tree1 , const FEMTree< Dim , Real > &tree2 , size_t blockSize ) { - if( blockSize ) + if( tree1._baseDepth != tree2._baseDepth ) ERROR_OUT( "Base depths differ: " , tree1._baseDepth , " != " , tree2._baseDepth ); + if( tree1._depthOffset != tree2._depthOffset ) ERROR_OUT( "Depth offsets differ: " , tree1._depthOffset , " != " , tree2._depthOffset ); + FEMTree< Dim , Real > *mergeTree = new FEMTree( blockSize ); + + // have support overlapping the slice. + std::function< void ( const FEMTreeNode *node1 , const FEMTreeNode *node2 , FEMTreeNode *mergeNode ) > mergeTrees = + [&]( const FEMTreeNode *node1 , const FEMTreeNode *node2 , FEMTreeNode *mergeNode ) { - nodeAllocators.resize( std::thread::hardware_concurrency() ); - for( size_t i=0 ; ichildren ) || ( node2 && node2->children ) ) { - nodeAllocators[i] = new Allocator< FEMTreeNode >(); - nodeAllocators[i]->set( blockSize ); + if( !mergeNode->children ) mergeNode->template initChildren< false >( mergeTree->nodeAllocators.size() ? mergeTree->nodeAllocators[0] : NULL , mergeTree->_nodeInitializer ); + + for( unsigned int c=0 ; c<(1<children && node2 && node2->children ) mergeTrees( node1->children+c , node2->children+c , mergeNode->children+c ); + else if( node1 && node1->children ) mergeTrees( node1->children+c , NULL , mergeNode->children+c ); + else if( node2 && node2->children ) mergeTrees( NULL , node2->children+c , mergeNode->children+c ); } + }; + mergeTrees( &tree1._tree , &tree2._tree , &mergeTree->_tree ); + + int d=0 , off[Dim]; + for( int d=0 ; d_tree , d , off ); + mergeTree->_depthOffset = tree1._depthOffset; + mergeTree->_baseDepth = tree1._baseDepth; + + mergeTree->_init(); + mergeTree->_maxDepth = mergeTree->_spaceRoot->maxDepth(); + + std::vector< node_index_type > map; + mergeTree->_sNodes.reset( mergeTree->_tree , map ); + mergeTree->_setSpaceValidityFlags(); + + return mergeTree; +} + +template< unsigned int Dim , class Real > +template< unsigned int CrossDegree , unsigned int Pad > +FEMTree< Dim , Real > *FEMTree< Dim , Real >::Slice( const FEMTree< Dim+1 , Real > &tree , unsigned int sliceDepth , unsigned int sliceIndex , bool includeBounds , size_t blockSize ) +{ + if( sliceIndex>(unsigned int)(1< accumulateCoefficients = + [&]( const FEMTreeNode *node , const FEMTreeNode *mergeNode ) + { + if( node && node->nodeData.nodeIndex!=-1 ) + { + if( !mergeNode || mergeNode->nodeData.nodeIndex==-1 ) ERROR_OUT( "Merge node not set" ); + LocalDepth d ; LocalOffset off; + tree.depthAndOffset( node , d , off ); + mergeCoefficients[ mergeNode->nodeData.nodeIndex ] += coefficients[ node->nodeData.nodeIndex ]; + } + if( node && node->children ) for( unsigned int c=0 ; c<(1<children+c , mergeNode->children+c ); + }; + accumulateCoefficients( &tree._tree , &_tree ); +} + +template< unsigned int Dim , class Real > +template< unsigned int Pad , unsigned int FEMSig , unsigned int ... FEMSigs , typename Data > +void FEMTree< Dim , Real >::slice( const FEMTree< Dim+1 , Real > &tree , unsigned int d , const DenseNodeData< Data , UIntPack< FEMSigs ... , FEMSig > > &coefficients , DenseNodeData< Data , UIntPack< FEMSigs ... > > &sliceCoefficients , unsigned int sliceDepth , unsigned int sliceIndex ) const +{ + static_assert( sizeof ... ( FEMSigs )==Dim , "[ERROR] Signature count and dimension don't match" ); +#ifdef __GNUC__ #ifdef SHOW_WARNINGS -#pragma message( "[WARNING] _spaceRoot is the root of the tree until finalization" ) + #warning "you've got me gcc version<5" #endif // SHOW_WARNINGS - _spaceRoot->parent = NULL; - int offset[Dim]; - for( int d=0 ; d::ResetDepthAndOffset( _spaceRoot , 0 , offset ); - _depthOffset = 0; - memset( _femSigs1 , -1 , sizeof( _femSigs1 ) ); - memset( _femSigs2 , -1 , sizeof( _femSigs2 ) ); +#else // !__GNUC__ + static const unsigned int CrossDegree = FEMSignature< FEMSig >::Degree; + static const unsigned int _Pad = Pad; +#endif // __GNUC__ + + unsigned int maxDepth = tree.maxDepth(); + if( sliceDepth::Degree >::SupportStart-(int)Pad; + const int EndOffset = BSplineSupportSizes< FEMSignature< FEMSig >::Degree >::SupportEnd+1+(int)Pad; +#else // !__GNUC__ + const int StartOffset = BSplineSupportSizes< CrossDegree >::SupportStart-(int)Pad; + const int EndOffset = BSplineSupportSizes< CrossDegree >::SupportEnd+1+(int)Pad; +#endif // __GNUC__ + + struct SliceEvaluator + { + struct _SliceEvaluator + { +#ifdef __GNUC__ + const int StartOffset = BSplineSupportSizes< FEMSignature< FEMSig >::Degree >::SupportStart-(int)Pad; + const int EndOffset = BSplineSupportSizes< FEMSignature< FEMSig >::Degree >::SupportEnd+1+(int)Pad; +#else // !__GNUC__ + const int StartOffset = BSplineSupportSizes< CrossDegree >::SupportStart-(int)_Pad; + const int EndOffset = BSplineSupportSizes< CrossDegree >::SupportEnd+1+(int)_Pad; +#endif // __GNUC__ + int start; +#ifdef __GNUC__ + Real values[ BSplineSupportSizes< FEMSignature< FEMSig >::Degree >::SupportSize+2*Pad ]; +#else // !__GNUC__ + Real values[ BSplineSupportSizes< CrossDegree >::SupportSize+2*Pad ]; +#endif // __GNUC__ + void init( unsigned int depth , double x , unsigned int d ) + { + // off @ depthsupports the slice if + // x>(off+StartOffset)/(1< x*(1<off && x*(1< off \in ( x*(1<::Degree ) for( int i=0 ; i::Value( depth , start+i , x , d ); + else if( d==FEMSignature< FEMSig >::Degree ) +#else // !__GNUC__ + if( d::Value( depth , start+i , x , d ); + else if( d==CrossDegree ) +#endif // __GNUC__ + { + double eps = 1e-4/(1<::Value( depth , start+i , x-eps , d ); + value += BSplineEvaluationData< FEMSig >::Value( depth , start+i , x+eps , d ); + values[i] = (Real)(value/2); + } + } + else // Otherwise we compute the discrete derivative + { + for( int i=0 ; i::Value( depth , start+i , x , d-1 ) - BSplineEvaluationData< FEMSig >::Value( depth , start+i , x-eps , d-1 ); + value += BSplineEvaluationData< FEMSig >::Value( depth , start+i , x+eps , d-1 ) - BSplineEvaluationData< FEMSig >::Value( depth , start+i , x , d-1 ); + values[i] = (Real)(value/(2*eps) ); + } + } + + } +#ifdef __GNUC__ + else ERROR_OUT( "Derivative exceeds degree: " , d , " > " , FEMSignature< FEMSig >::Degree ); +#else // !__GNUC__ + else ERROR_OUT( "Derivative exceeds degree: " , d , " > " , CrossDegree ); +#endif // __GNUC__ + } + Real operator()( int off ) const + { + if( off=start+(EndOffset-StartOffset ) ) return 0; + else return values[off-start]; + } + }; + + std::vector< _SliceEvaluator > evaluators; + void init( unsigned int maxDepth , double x , unsigned int d ) + { + evaluators.resize( maxDepth+1 ); + for( unsigned int depth=0 ; depth<=maxDepth ; depth++ ) evaluators[depth].init( depth , x , d ); + } + Real operator()( int d , int off ) const + { + if( d<0 || d>=(int)evaluators.size() ) return 0; + else return evaluators[d]( off ); + } + }; + + SliceEvaluator sliceEvaluator; + sliceEvaluator.init( maxDepth , s , d ); + + // A function return true if the function indexed by the node has support overlapping the slice + auto OverlapsSlice = [&]( const typename FEMTree< Dim+1 , Real >::FEMTreeNode *node ) + { + typename FEMTree< Dim+1 , Real >::LocalDepth d ; typename FEMTree< Dim+1 , Real >::LocalOffset off; + tree.depthAndOffset( node , d , off ); + if( d<0 ) return true; + else + { + int start = ( off[Dim] + StartOffset )<<(sliceDepth-d); + int end = ( off[Dim] + EndOffset )<<(sliceDepth-d); + return (int)sliceIndex>start && (int)sliceIndex::FEMTreeNode * , const typename FEMTree< Dim , Real >::FEMTreeNode * ) > accumulateSliceCoefficients = + [&]( const typename FEMTree< Dim+1 , Real >::FEMTreeNode *node , const typename FEMTree< Dim , Real >::FEMTreeNode *sliceNode ) + { + if( node->nodeData.nodeIndex!=-1 ) + { + if( sliceNode->nodeData.nodeIndex==-1 ) ERROR_OUT( "Slice node not set" ); + typename FEMTree< Dim+1 , Real >::LocalDepth d ; typename FEMTree< Dim+1 , Real >::LocalOffset off; + tree.depthAndOffset( node , d , off ); + sliceCoefficients[ sliceNode->nodeData.nodeIndex ] += coefficients[ node->nodeData.nodeIndex ] * sliceEvaluator( d , off[Dim] ); + } + if( !GetGhostFlag( node->children ) ) + { + if( OverlapsSlice( node->children ) ) for( unsigned int c=0 ; c<(1<children+( c ) , sliceNode->children+c ); + if( OverlapsSlice( node->children+(1<children+( c|(1<children+c ); + } + }; + accumulateSliceCoefficients( &tree._tree , &_tree ); } + template< unsigned int Dim , class Real > -FEMTree< Dim , Real >::FEMTree( FILE* fp , XForm< Real , Dim+1 > &xForm , size_t blockSize ) : _nodeInitializer( *this ) +FEMTree< Dim , Real >::FEMTree( size_t blockSize ) : _nodeInitializer( *this ) , _depthOffset(1) { if( blockSize ) { @@ -87,41 +354,41 @@ FEMTree< Dim , Real >::FEMTree( FILE* fp , XForm< Real , Dim+1 > &xForm , size_t nodeAllocators[i]->set( blockSize ); } } - Allocator< FEMTreeNode > *nodeAllocator = nodeAllocators.size() ? nodeAllocators[0] : NULL; - if( fp ) - { - if( fread( xForm.coords , sizeof( Real ) , (Dim+1)*(Dim+1) , fp )!=(Dim+1)*(Dim+1) ) ERROR_OUT( "Failed to read transform" ); - if( fread( &_depthOffset , sizeof( int ) , 1 , fp )!=1 ) ERROR_OUT( "Failed to read depth offset" ); - _tree = FEMTreeNode::NewBrood( nodeAllocator , _nodeInitializer ); - _tree->read( fp , nodeAllocator , _nodeInitializer ); - _maxDepth = _tree->maxDepth() - _depthOffset; - - _spaceRoot = _tree->children; + _nodeCount = 0; + // Initialize the root + _nodeInitializer( _tree ); + _tree.template initChildren< false >( nodeAllocators.size() ? nodeAllocators[0] : NULL , _nodeInitializer ); + _init(); + memset( _femSigs1 , -1 , sizeof( _femSigs1 ) ); + memset( _femSigs2 , -1 , sizeof( _femSigs2 ) ); +} - if( _depthOffset>1 ) - { - _spaceRoot = _tree->children + (1<children ) ERROR_OUT( "Expected children" ); - else _spaceRoot = _spaceRoot->children; - } - _sNodes.set( *_tree , NULL ); - } - else - { - _tree = FEMTreeNode::NewBrood( nodeAllocator , _nodeInitializer ); - _tree->template initChildren< false >( nodeAllocator , _nodeInitializer ) , _spaceRoot = _tree->children; - int offset[Dim]; - for( int d=0 ; d::ResetDepthAndOffset( _spaceRoot , 0 , offset ); - _depthOffset = 0; - } +template< unsigned int Dim , class Real > +FEMTree< Dim , Real >::FEMTree( BinaryStream &stream , XForm< Real , Dim+1 > &xForm , size_t blockSize ) : FEMTree( blockSize ) +{ + Allocator< FEMTreeNode > *nodeAllocator = nodeAllocators.size() ? nodeAllocators[0] : NULL; + if( !stream.read( xForm.coords ) ) ERROR_OUT( "Failed to read transform" ); + node_index_type nodeCount; + if( !stream.read( nodeCount ) ) ERROR_OUT( "Failed to read nodeCount" ); + _nodeCount = nodeCount; + if( !stream.read( _maxDepth ) ) ERROR_OUT( "Failed to read _maxDepth" ); + if( !stream.read( _depthOffset ) ) ERROR_OUT( "Failed to read _depthOffset" ); + if( !stream.read( _baseDepth ) ) ERROR_OUT( "Failed to read _baseDepth" ); + _tree.read( stream , nodeAllocator ); + _init(); + _sNodes.read( stream , _tree ); } -template< unsigned int Dim , class Real > void FEMTree< Dim , Real >::write( FILE* fp , XForm< Real , Dim+1 > xForm ) const + +template< unsigned int Dim , class Real > void FEMTree< Dim , Real >::write( BinaryStream &stream , XForm< Real , Dim+1 > xForm , bool serialize ) const { - fwrite( xForm.coords , sizeof( Real ) , (Dim+1)*(Dim+1) , fp ); - fwrite( &_depthOffset , sizeof( int ) , 1 , fp ); - _tree->write( fp ); + stream.write( xForm ); + node_index_type nodeCount = _nodeCount; + stream.write( nodeCount ); + stream.write( _maxDepth ); + stream.write( _depthOffset ); + stream.write( _baseDepth ); + _tree.write( stream , serialize ); + _sNodes.write( stream ); } template< unsigned int Dim , class Real > @@ -167,6 +434,34 @@ RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* FEMTree< Dim , return node; } +template< unsigned int Dim , class Real > +template< bool ThreadSafe > +RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* FEMTree< Dim , Real >::_leaf( Allocator< FEMTreeNode > *nodeAllocator , Point< Real , Dim > p , std::function< int ( Point< Real , Dim > ) > &pointDepthFunctor ) +{ + if( !_InBounds( p ) ) return NULL; + int maxDepth = pointDepthFunctor( p ); + Point< Real , Dim > center; + for( int d=0 ; dchildren ) node->template initChildren< ThreadSafe >( nodeAllocator , _nodeInitializer ); + int cIndex = FEMTreeNode::ChildIndex( center , p ); + node = node->children + cIndex; + + depth++; + width /= 2; + for( int d=0 ; d>d) & 1 ) center[d] += width/2; + else center[d] -= width/2; + } + return node; +} + template< unsigned int Dim , class Real > bool FEMTree< Dim , Real >::_InBounds( Point< Real , Dim > p ){ for( int d=0 ; d1 ) return false ; return true; } template< unsigned int Dim , class Real > template< unsigned int ... FEMSignatures > @@ -188,6 +483,37 @@ bool FEMTree< Dim , Real >::isValidSpaceNode( const FEMTreeNode* node ) const return true; } +template< unsigned int Dim , class Real > +template< bool ThreadSafe , typename AddNodeFunctor , unsigned int ... Degrees > +void FEMTree< Dim , Real >::_refine( UIntPack< Degrees ... > , Allocator< FEMTreeNode > *nodeAllocator , const AddNodeFunctor &addNodeFunctor , FEMTreeNode *node ) +{ + LocalDepth d , _d ; LocalOffset off , _off; + _localDepthAndOffset( node , d , off ); + _d = d+1; + + bool refine = d<0; + for( int c=0 ; c<(1<::Signature ... >() , _d , _off ) && addNodeFunctor( _d , _off ); + } + if( refine ) + { + if( !node->children ) node->template initChildren< ThreadSafe >( nodeAllocator , _nodeInitializer ); + for( int c=0 ; c<(1<( UIntPack< Degrees ... >() , nodeAllocator , addNodeFunctor , node->children+c ); + } +} + +template< unsigned int Dim , class Real > +template< bool ThreadSafe , typename AddNodeFunctor , unsigned int ... Degrees > +void FEMTree< Dim , Real >::_refine( UIntPack< Degrees ... > , Allocator< FEMTreeNode > *nodeAllocator , const AddNodeFunctor &addNodeFunctor ) +{ + if( !_tree.children ) _tree.template initChildren< ThreadSafe >( nodeAllocator , _nodeInitializer ); + for( int c=0 ; c<(1<( UIntPack< Degrees ... >() , nodeAllocator , addNodeFunctor , _tree.children+c ); +} + template< unsigned int Dim , class Real > template< bool ThreadSafe , unsigned int ... Degrees > void FEMTree< Dim , Real >::_setFullDepth( UIntPack< Degrees ... > , Allocator< FEMTreeNode > *nodeAllocator , FEMTreeNode* node , LocalDepth depth ) @@ -201,13 +527,15 @@ void FEMTree< Dim , Real >::_setFullDepth( UIntPack< Degrees ... > , Allocator< for( int c=0 ; c<(1<( UIntPack< Degrees ... >() , nodeAllocator , node->children+c , depth ); } } + template< unsigned int Dim , class Real > template< bool ThreadSafe , unsigned int ... Degrees > void FEMTree< Dim , Real >::_setFullDepth( UIntPack< Degrees ... > , Allocator< FEMTreeNode > *nodeAllocator , LocalDepth depth ) { - if( !_tree->children ) _tree->template initChildren< ThreadSafe >( nodeAllocator , _nodeInitializer ); - for( int c=0 ; c<(1<( UIntPack< Degrees ... >() , nodeAllocator , _tree->children+c , depth ); + if( !_tree.children ) _tree.template initChildren< ThreadSafe >( nodeAllocator , _nodeInitializer ); + for( int c=0 ; c<(1<( UIntPack< Degrees ... >() , nodeAllocator , _tree.children+c , depth ); } + template< unsigned int Dim , class Real > template< unsigned int ... Degrees > typename FEMTree< Dim , Real >::LocalDepth FEMTree< Dim , Real >::_getFullDepth( UIntPack< Degrees ... > , const FEMTreeNode* node ) const @@ -232,27 +560,119 @@ typename FEMTree< Dim , Real >::LocalDepth FEMTree< Dim , Real >::_getFullDepth( } else return INT_MAX; } + +template< unsigned int Dim , class Real > +template< unsigned int ... Degrees > +typename FEMTree< Dim , Real >::LocalDepth FEMTree< Dim , Real >::_getFullDepth( UIntPack< Degrees ... > , const LocalDepth depth , const LocalOffset begin , const LocalOffset end , const FEMTreeNode* node ) const +{ + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + + // [NOTE]: Changing closed interval to half open interval + const int StartOffsets[] = { BSplineSupportSizes< Degrees >::SupportStart ... }; + const int EndOffsets[] = { BSplineSupportSizes< Degrees >::SupportEnd + 1 ... }; + + auto IsSupported = [&]( LocalDepth d , LocalOffset off ) + { + LocalOffset supportStart , supportEnd; + for( unsigned int dim=0 ; dim=0 ) for( unsigned int dim=0 ; dim=end[dim] || supportEnd[dim]<=begin[dim] ) return false; + return true; + }; + + { + if( !node->children ) + { + LocalDepth _d=d+1; + LocalOffset _off; + bool childrenSupported = false; + for( unsigned int c=0 ; c<(1<() , depth , begin , end , node->children+c ); + if( d template< unsigned int ... Degrees > typename FEMTree< Dim , Real >::LocalDepth FEMTree< Dim , Real >::getFullDepth( UIntPack< Degrees ... > ) const { - if( !_tree->children ) return -1; + if( !_tree.children ) return -1; LocalDepth depth = INT_MAX; for( int c=0 ; c<(1<() , _tree->children+c ); + LocalDepth d = _getFullDepth( UIntPack< Degrees ... >() , _tree.children+c ); if( d +template< unsigned int ... Degrees > +typename FEMTree< Dim , Real >::LocalDepth FEMTree< Dim , Real >::getFullDepth( UIntPack< Degrees ... > , const LocalDepth depth , const LocalOffset begin , const LocalOffset end ) const +{ + LocalDepth maxDepth = this->maxDepth(); + LocalDepth _depth ; LocalOffset _begin , _end; + for( unsigned int d=0 ; dend[d] ) ERROR_OUT( "Bad bounds [" , d , "]: " , begin[d] , " <= " , end[d] ); + if( begin[d]<0 ) ERROR_OUT( "Start bound cannot be negative [" , d , "]: 0 <= " , begin[d] ); + if( end[d]>(1< > densityKey; + densityKey.set( maxSplatDepth ); + + std::vector< node_index_type > sampleMap( nodeCount() , -1 ); + + // Initialize the map from node indices to samples + ThreadPool::Parallel_for( 0 , samples.size() , [&]( unsigned int , size_t i ){ if( samples[i].sample.weight>0 ) sampleMap[ samples[i].node->nodeData.nodeIndex ] = (node_index_type)i; } ); + + std::function< ProjectiveData< Point< Real , Dim > , Real > ( FEMTreeNode* ) > SetDensity = [&] ( FEMTreeNode* node ) { - typedef StaticWindow< FEMTreeNode * , IsotropicUIntPack< Dim , LeftRadius+RightRadius+1 > > NeighborLeafNodes; - NeighborLeafNodes neighborLeafNodes; - neighborKeys[t].setLeafNeighbors( nodes[i] , neighborLeafNodes ); - for( int i=0 ; i , Real > sample; + LocalDepth d = node->depth(); + node_index_type idx = node->nodeData.nodeIndex; + if( node->children ) for( int c=0 ; c<(1<children + c ); + if( idx<(node_index_type)sampleMap.size() && sampleMap[idx]!=-1 ) sample += samples[ sampleMap[ idx ] ].sample; + if( d>=minSplatDepth && d<=maxSplatDepth && sample.weight>0 ) _addWeightContribution< true , CoDim >( nodeAllocator , density , node , sample.data / sample.weight , densityKey , sample.weight ); + return sample; + }; + SetDensity( _spaceRoot ); } template< unsigned int Dim , class Real > template< unsigned int CoDim , unsigned int DensityDegree > -typename FEMTree< Dim , Real >::template DensityEstimator< DensityDegree >* FEMTree< Dim , Real >::setDensityEstimator( const std::vector< PointSample >& samples , LocalDepth splatDepth , Real samplesPerNode ) +void FEMTree< Dim , Real >::updateDensityEstimator( typename FEMTree< Dim , Real >::template DensityEstimator< DensityDegree > &density , const std::vector< PointSample >& samples , LocalDepth minSplatDepth , LocalDepth maxSplatDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real samplesPerNode ) { + // typename FEMTreeNode::SubTreeExtractor subtreeExtractor( _spaceRoot ); + SubTreeExtractor subtreeExtractor( _spaceRoot , _depthOffset ); Allocator< FEMTreeNode > *nodeAllocator = nodeAllocators.size() ? nodeAllocators[0] : NULL; LocalDepth maxDepth = _spaceRoot->maxDepth(); - splatDepth = std::max< LocalDepth >( 0 , std::min< LocalDepth >( splatDepth , maxDepth ) ); - DensityEstimator< DensityDegree >* _density = new DensityEstimator< DensityDegree >( splatDepth , CoDim , samplesPerNode ); - DensityEstimator< DensityDegree >& density = *_density; + maxSplatDepth = std::max< LocalDepth >( 0 , std::min< LocalDepth >( maxSplatDepth , maxDepth ) ); + minSplatDepth = std::max< LocalDepth >( 0 , std::min< LocalDepth >( minSplatDepth , maxDepth ) ); + if( minSplatDepth>maxSplatDepth ) ERROR_OUT( "Minimum splat depth exceeds maximum splat depth" ); PointSupportKey< IsotropicUIntPack< Dim , DensityDegree > > densityKey; - densityKey.set( _localToGlobal( splatDepth ) ); + densityKey.set( maxSplatDepth ); std::vector< node_index_type > sampleMap( nodeCount() , -1 ); + + // Initialize the map from node indices to samples ThreadPool::Parallel_for( 0 , samples.size() , [&]( unsigned int , size_t i ){ if( samples[i].sample.weight>0 ) sampleMap[ samples[i].node->nodeData.nodeIndex ] = (node_index_type)i; } ); + std::function< ProjectiveData< Point< Real , Dim > , Real > ( FEMTreeNode* ) > SetDensity = [&] ( FEMTreeNode* node ) { ProjectiveData< Point< Real , Dim > , Real > sample; - LocalDepth d = _localDepth( node ); + LocalDepth d = node->depth(); node_index_type idx = node->nodeData.nodeIndex; - if( node->children ) - for( int c=0 ; c<(1< , Real > s = SetDensity( node->children + c ); - if( d<=splatDepth && s.weight>0 ) - { - Point< Real , Dim > p = s.data / s.weight; - _addWeightContribution< true , CoDim >( nodeAllocator , density , node , p , densityKey , s.weight ); - } - sample += s; - } - else if( idx<(node_index_type)sampleMap.size() && sampleMap[idx]!=-1 ) + if( node->children ) for( int c=0 ; c<(1<children + c ); + if( idx<(node_index_type)sampleMap.size() && sampleMap[idx]!=-1 ) sample += samples[ sampleMap[ idx ] ].sample; + + if( d>=minSplatDepth && d<=maxSplatDepth && sample.weight>0 ) { - sample = samples[ sampleMap[ idx ] ].sample; - if( d<=splatDepth && sample.weight>0 ) - { - Point< Real , Dim > p = sample.data / sample.weight; - _addWeightContribution< true , CoDim >( nodeAllocator , density , node , p , densityKey , sample.weight ); - } + // The average position of samples accumulated in the node + Point< Real , Dim > p = sample.data / sample.weight; + if( d<=pointDepthFunctor( p ) ) _addWeightContribution< true , CoDim >( nodeAllocator , density , node , p , densityKey , sample.weight ); } return sample; }; SetDensity( _spaceRoot ); +} - MemoryUsage(); - return _density; +template< unsigned int Dim , class Real > +template< unsigned int CoDim , unsigned int DensityDegree > +typename FEMTree< Dim , Real >::template DensityEstimator< DensityDegree >* FEMTree< Dim , Real >::setDensityEstimator( const std::vector< PointSample >& samples , LocalDepth splatDepth , Real samplesPerNode ) +{ + LocalDepth maxDepth = _spaceRoot->maxDepth(); + splatDepth = std::max< LocalDepth >( 0 , std::min< LocalDepth >( splatDepth , maxDepth ) ); + DensityEstimator< DensityDegree > *density = new DensityEstimator< DensityDegree >( splatDepth , CoDim , samplesPerNode ); + this->template updateDensityEstimator< CoDim , DensityDegree >( *density , samples , 0 , splatDepth , samplesPerNode ); + + return density; +} + +template< unsigned int Dim , class Real > +template< unsigned int CoDim , unsigned int DensityDegree > +typename FEMTree< Dim , Real >::template DensityEstimator< DensityDegree >* FEMTree< Dim , Real >::setDensityEstimator( const std::vector< PointSample >& samples , LocalDepth splatDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real samplesPerNode ) +{ + LocalDepth maxDepth = _spaceRoot->maxDepth(); + splatDepth = std::max< LocalDepth >( 0 , std::min< LocalDepth >( splatDepth , maxDepth ) ); + DensityEstimator< DensityDegree > *density = new DensityEstimator< DensityDegree >( splatDepth , CoDim , samplesPerNode ); + this->template updateDensityEstimator< CoDim , DensityDegree >( *density , samples , 0 , splatDepth , pointDepthFunctor , samplesPerNode ); + + return density; } template< unsigned int Dim , class Real > template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > -SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , Real& pointWeightSum , std::function< bool ( InData , OutData& ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction ) +SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData& ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction ) { std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction = [&]( InData in , OutData &out , Real &bias ) { @@ -389,12 +898,16 @@ SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setI } else return false; }; - return setInterpolatedDataField( UIntPack< DataSigs ... >() , samples , data , density , minDepth , maxDepth , minDepthCutoff , pointWeightSum , ConversionAndBiasFunction ); + return setInterpolatedDataField( UIntPack< DataSigs ... >() , samples , data , density , minDepth , maxDepth , minDepthCutoff , pointDepthAndWeight , ConversionAndBiasFunction ); } + template< unsigned int Dim , class Real > template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > -SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , Real& pointWeightSum , std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction ) +SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction ) { + // typename FEMTreeNode::SubTreeExtractor subtreeExtractor( _spaceRoot ); + SubTreeExtractor subtreeExtractor( _spaceRoot , _depthOffset ); + typedef PointSupportKey< IsotropicUIntPack< Dim , DensityDegree > > DensityKey; typedef UIntPack< FEMSignature< DataSigs >::Degree ... > DataDegrees; typedef PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > > DataKey; @@ -403,61 +916,164 @@ SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setI bool oneKey = DensityDegree==DataDegrees::Min() && DensityDegree==DataDegrees::Max(); for( size_t i=0 ; i depthAndWeightSums( ThreadPool::NumThreads() , 0 ); + pointDepthAndWeight.data = Point< Real , 2 >(); + pointDepthAndWeight.weight = 0; SparseNodeData< OutData , UIntPack< DataSigs ... > > dataField; - Real _pointWeightSum = 0; + std::vector< Point< Real , 2 > > pointDepthAndWeightSums( ThreadPool::NumThreads() , Point< Real , 2 >() ); ThreadPool::Parallel_for( 0 , samples.size() , [&]( unsigned int thread , size_t i ) - { - DensityKey& densityKey = densityKeys[ thread ]; - DataKey& dataKey = dataKeys[ thread ]; - const ProjectiveData< Point< Real , Dim > , Real >& sample = samples[i].sample; - if( sample.weight>0 ) { - Point< Real , Dim > p = sample.data / sample.weight; - InData in = data[i] / sample.weight; - OutData out; - - Real depthBias; - if( !_InBounds(p) ) WARN( "Point sample is out of bounds" ); - else if( ConversionAndBiasFunction( in , out , depthBias ) ) + DensityKey& densityKey = densityKeys[ thread ]; + DataKey& dataKey = dataKeys[ thread ]; + const ProjectiveData< Point< Real , Dim > , Real >& sample = samples[i].sample; + if( sample.weight>0 ) { - AddAtomic( weightSum , sample.weight ); - out *= sample.weight; - Allocator< FEMTreeNode > *nodeAllocator = nodeAllocators.size() ? nodeAllocators[ thread ] : NULL; + Point< Real , Dim > p = sample.data / sample.weight; + InData in = data[i] / sample.weight; + OutData out; + + Real depthBias; + if( !_InBounds(p) ) WARN( "Point sample is out of bounds" ); + else if( ConversionAndBiasFunction( in , out , depthBias ) ) + { + depthAndWeightSums[thread] += sample.weight; +#ifdef SHOW_WARNINGS +#pragma message( "[WARNING] Should the next line be commented out?" ) +#endif // SHOW_WARNINGS + out *= sample.weight; + Allocator< FEMTreeNode > *nodeAllocator = nodeAllocators.size() ? nodeAllocators[ thread ] : NULL; #if defined( __GNUC__ ) && __GNUC__ < 5 #ifdef SHOW_WARNINGS #warning "you've got me gcc version<5" #endif // SHOW_WARNINGS - if( density ) AddAtomic( _pointWeightSum , _splatPointData< true , true , DensityDegree , OutData >( nodeAllocator , *density , minDepthCutoff , p , out , dataField , densityKey , oneKey ? *( (DataKey*)&densityKey ) : dataKey , minDepth , maxDepth , Dim , depthBias ) * sample.weight ); + if( density ) pointDepthAndWeightSums[thread] += _splatPointData< true , true , DensityDegree , OutData >( nodeAllocator , *density , minDepthCutoff , p , out , dataField , densityKey , oneKey ? *( (DataKey*)&densityKey ) : dataKey , minDepth , maxDepth , Dim , depthBias ) * sample.weight; +#else // !__GNUC__ || __GNUC__ >=5 + if( density ) pointDepthAndWeightSums[thread] += _splatPointData< true , true , DensityDegree , OutData , DataSigs ... >( nodeAllocator , *density , minDepthCutoff , p , out , dataField , densityKey , oneKey ? *( (DataKey*)&densityKey ) : dataKey , minDepth , maxDepth , Dim , depthBias ) * sample.weight; +#endif // __GNUC__ && __GNUC__ < 5 + else + { + Real width = (Real)( 1.0 / ( 1<( nodeAllocator , _leaf< true >( nodeAllocator , p , maxDepth ) , p , out / (Real)pow( width , Dim ) , dataField , oneKey ? *( (DataKey*)&densityKey ) : dataKey ); #else // !__GNUC__ || __GNUC__ >=5 - if( density ) AddAtomic( _pointWeightSum , _splatPointData< true , true , DensityDegree , OutData , DataSigs ... >( nodeAllocator , *density , minDepthCutoff , p , out , dataField , densityKey , oneKey ? *( (DataKey*)&densityKey ) : dataKey , minDepth , maxDepth , Dim , depthBias ) * sample.weight ); + _splatPointData< true , true , OutData , DataSigs ... >( nodeAllocator , _leaf< true >( nodeAllocator , p , maxDepth ) , p , out / (Real)pow( width , Dim ) , dataField , oneKey ? *( (DataKey*)&densityKey ) : dataKey ); #endif // __GNUC__ && __GNUC__ < 5 - else + pointDepthAndWeightSums[thread] += Point< Real , 2 >( (Real)1. , (Real)maxDepth ) * sample.weight; + } + } + } + } + ); + pointDepthAndWeight.data = Point< Real , 2 >(); + for( unsigned int i=0 ; i +template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > +SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData& ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction ) +{ + std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction = [&]( InData in , OutData &out , Real &bias ) + { + if( ConversionFunction( in , out ) ) + { + bias = BiasFunction( in ); + return true; + } + else return false; + }; + return setInterpolatedDataField( UIntPack< DataSigs ... >() , samples , data , density , minDepth , maxDepth , pointDepthFunctor , minDepthCutoff , pointDepthAndWeight , ConversionAndBiasFunction ); +} + +template< unsigned int Dim , class Real > +template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > +SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction ) +{ + // typename FEMTreeNode::SubTreeExtractor subtreeExtractor( _spaceRoot ); + SubTreeExtractor subtreeExtractor( _spaceRoot , _depthOffset ); + + typedef PointSupportKey< IsotropicUIntPack< Dim , DensityDegree > > DensityKey; + typedef UIntPack< FEMSignature< DataSigs >::Degree ... > DataDegrees; + typedef PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > > DataKey; + std::vector< DensityKey > densityKeys( ThreadPool::NumThreads() ); + std::vector< DataKey > dataKeys( ThreadPool::NumThreads() ); + bool oneKey = DensityDegree==DataDegrees::Min() && DensityDegree==DataDegrees::Max(); + for( size_t i=0 ; i depthAndWeightSums( ThreadPool::NumThreads() , 0 ); + pointDepthAndWeight.data = Point< Real , 2 >(); + pointDepthAndWeight.weight = 0; + SparseNodeData< OutData , UIntPack< DataSigs ... > > dataField; + std::vector< Point< Real , 2 > > pointDepthAndWeightSums( ThreadPool::NumThreads() , Point< Real , 2 >() ); + ThreadPool::Parallel_for( 0 , samples.size() , [&]( unsigned int thread , size_t i ) + { + DensityKey& densityKey = densityKeys[ thread ]; + DataKey& dataKey = dataKeys[ thread ]; + const ProjectiveData< Point< Real , Dim > , Real >& sample = samples[i].sample; + if( sample.weight>0 ) + { + Point< Real , Dim > p = sample.data / sample.weight; + InData in = data[i] / sample.weight; + OutData out; + + Real depthBias; + if( !_InBounds(p) ) WARN( "Point sample is out of bounds" ); + else if( ConversionAndBiasFunction( in , out , depthBias ) ) { - Real width = (Real)( 1.0 / ( 1< *nodeAllocator = nodeAllocators.size() ? nodeAllocators[ thread ] : NULL; #if defined( __GNUC__ ) && __GNUC__ < 5 #ifdef SHOW_WARNINGS #warning "you've got me gcc version<5" #endif // SHOW_WARNINGS - _splatPointData< true , true , OutData >( nodeAllocator , _leaf< true >( nodeAllocator , p , maxDepth ) , p , out / (Real)pow( width , Dim ) , dataField , oneKey ? *( (DataKey*)&densityKey ) : dataKey ); + if( density ) pointDepthAndWeightSums[thread] += _splatPointData< true , true , DensityDegree , OutData >( nodeAllocator , *density , minDepthCutoff , p , out , dataField , densityKey , oneKey ? *( (DataKey*)&densityKey ) : dataKey , minDepth , pointDepthFunctor , Dim , depthBias ) * sample.weight; +#else // !__GNUC__ || __GNUC__ >=5 + if( density ) pointDepthAndWeightSums[thread] += _splatPointData< true , true , DensityDegree , OutData , DataSigs ... >( nodeAllocator , *density , minDepthCutoff , p , out , dataField , densityKey , oneKey ? *( (DataKey*)&densityKey ) : dataKey , minDepth , pointDepthFunctor , Dim , depthBias ) * sample.weight; +#endif // __GNUC__ && __GNUC__ < 5 + else + { + Real width = (Real)( 1.0 / ( 1<( nodeAllocator , _leaf< true >( nodeAllocator , p , pointDepthFunctor ) , p , out / (Real)pow( width , Dim ) , dataField , oneKey ? *( (DataKey*)&densityKey ) : dataKey ); #else // !__GNUC__ || __GNUC__ >=5 - _splatPointData< true , true , OutData , DataSigs ... >( nodeAllocator , _leaf< true >( nodeAllocator , p , maxDepth ) , p , out / (Real)pow( width , Dim ) , dataField , oneKey ? *( (DataKey*)&densityKey ) : dataKey ); -#endif // __GNUC__ || __GNUC__ < 4 - AddAtomic( _pointWeightSum , sample.weight ); + _splatPointData< true , true , OutData , DataSigs ... >( nodeAllocator , _leaf< true >( nodeAllocator , p , pointDepthFunctor ) , p , out / (Real)pow( width , Dim ) , dataField , oneKey ? *( (DataKey*)&densityKey ) : dataKey ); +#endif // __GNUC__ && __GNUC__ < 5 + pointDepthAndWeightSums[thread] += Point< Real , 2 >( (Real)1 , (Real)maxDepth ) * sample.weight; + } } } } - } ); - pointWeightSum = _pointWeightSum / weightSum; - MemoryUsage(); + pointDepthAndWeight.data = Point< Real , 2 >(); + for( unsigned int i=0 ; i template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data > -SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > FEMTree< Dim , Real >::setExtrapolatedDataField( const std::vector< PointSample >& samples , std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density , bool nearest ) +SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > FEMTree< Dim , Real >::setExtrapolatedDataField( const std::vector< PointSample >& samples , const std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density , bool nearest ) +{ + SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > dataField; + this->template updateExtrapolatedDataField< DataSig , CreateNodes >( dataField , samples , sampleData , density , nearest ); + return dataField; +} +template< unsigned int Dim , class Real > +template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data > +void FEMTree< Dim , Real >::updateExtrapolatedDataField( SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > &dataField , const std::vector< PointSample >& samples , const std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density , bool nearest ) { Allocator< FEMTreeNode > *nodeAllocator = nodeAllocators.size() ? nodeAllocators[0] : NULL; LocalDepth maxDepth = _spaceRoot->maxDepth(); @@ -465,7 +1081,6 @@ SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig PointSupportKey< IsotropicUIntPack< Dim , FEMSignature< DataSig >::Degree > > dataKey; densityKey.set( _localToGlobal( maxDepth ) ) , dataKey.set( _localToGlobal( maxDepth ) ); - SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > dataField; for( node_index_type i=0 ; i<(node_index_type)samples.size() ; i++ ) { const ProjectiveData< Point< Real , Dim > , Real >& sample = samples[i].sample; @@ -479,8 +1094,6 @@ SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig if( nearest ) _nearestMultiSplatPointData< DensityDegree >( density , (FEMTreeNode*)samples[i].node , p , ProjectiveData< Data , Real >( data , sample.weight ) , dataField , densityKey , 2 ); else _multiSplatPointData< CreateNodes , false , DensityDegree >( nodeAllocator , density , (FEMTreeNode*)samples[i].node , p , ProjectiveData< Data , Real >( data , sample.weight ) , dataField , densityKey , dataKey , 2 ); } - MemoryUsage(); - return dataField; } template< unsigned int Dim , class Real > @@ -494,32 +1107,29 @@ void FEMTree< Dim , Real >::_supportApproximateProlongation( void ) std::vector< NeighborKey > neighborKeys( ThreadPool::NumThreads() ); for( int i=0 ; i_fullDepth ; d-- ) + for( LocalDepth d=_maxDepth-1 ; d>_baseDepth ; d-- ) { // Compute the set of nodes at depth d that have (non-ghost) children at depth d+1. std::vector< FEMTreeNode* > nodes; - { - auto NodeTerminationLambda = [&]( const FEMTreeNode *node ){ return _localDepth( node )==d; }; - for( FEMTreeNode* node=_tree->nextNode( NodeTerminationLambda , NULL ) ; node ; node=_tree->nextNode( NodeTerminationLambda , node ) ) if( _localDepth( node )==d && IsActiveNode( node->children ) ) nodes.push_back( node ); - } + _tree.processNodes( [&]( FEMTreeNode *node ){ if( _localDepth( node )==d && IsActiveNode( node->children ) ) nodes.push_back( node ) ; return _localDepth(node)( node , nodeAllocators.size() ? nodeAllocators[ thread ] : NULL , _nodeInitializer ); + // Create the neighbors if they are not already in the tree + neighborKey.template getNeighbors< true , true >( node , nodeAllocators.size() ? nodeAllocators[ thread ] : NULL , _nodeInitializer ); - // Mark the neighbors as active - Pointer( FEMTreeNode* ) nodes = neighborKey.neighbors[ _localToGlobal(d) ].neighbors().data; - unsigned int size = neighborKey.neighbors[ _localToGlobal(d) ].neighbors.Size; - for( unsigned int i=0 ; i::_markNonBaseDirichletElements( void ) // Get the list of nodes @{_baseDepth) std::vector< FEMTreeNode * > baseNodes; - for( FEMTreeNode* node=_tree->nextNode() ; node ; node=_tree->nextNode( node ) ) if( _localDepth( node )==_baseDepth ) baseNodes.push_back( node ); + _tree.processNodes( [&]( FEMTreeNode *node ){ if( _localDepth( node )==_baseDepth ) baseNodes.push_back( node ); } ); // Process the sub-tree rooted at the node: // -- For each non-ghost node in the sub-tree check if the finite element associated to the node is supported on a Dirichlet node. @@ -572,26 +1182,41 @@ void FEMTree< Dim , Real >::_markBaseDirichletElements( void ) for( int i=0 ; i nodes; - auto TerminationLambda = [&]( const FEMTreeNode *node ){ return _localDepth(node)==_baseDepth; }; - for( FEMTreeNode* node=_tree->nextNode( TerminationLambda , NULL ) ; node ; node=_tree->nextNode( TerminationLambda , node ) ) if( _localDepth( node )==_baseDepth && node->nodeData.getDirichletNodeFlag() ) nodes.push_back( node ); + _tree.processNodes( [&]( FEMTreeNode *node ){ if( _localDepth( node )==_baseDepth && node->nodeData.getDirichletNodeFlag() ) nodes.push_back( node ) ; return _localDepth(node)<_baseDepth; } ); ThreadPool::Parallel_for( 0 , nodes.size() , [&]( unsigned int thread , size_t i ) - { - SupportKey &supportKey = supportKeys[ thread ]; - FEMTreeNode *node = nodes[i]; - supportKey.getNeighbors( node ); - for( LocalDepth d=0 ; d<=_baseDepth ; d++ ) { - Pointer( FEMTreeNode* ) _nodes = supportKey.neighbors[ _localToGlobal(d) ].neighbors().data; - unsigned int size = supportKey.neighbors[ _localToGlobal(d) ].neighbors.Size; - for( unsigned int i=0 ; inodeData.setDirichletElementFlag( true ); - } - } ); + SupportKey &supportKey = supportKeys[ thread ]; + FEMTreeNode *node = nodes[i]; + supportKey.getNeighbors( node ); + for( LocalDepth d=0 ; d<=_baseDepth ; d++ ) + { + Pointer( FEMTreeNode* ) _nodes = supportKey.neighbors[ _localToGlobal(d) ].neighbors().data; + unsigned int size = supportKey.neighbors[ _localToGlobal(d) ].neighbors.Size; + for( unsigned int i=0 ; inodeData.setDirichletElementFlag( true ); + } + } ); +} + +template< unsigned int Dim , class Real > +template< unsigned int MaxDegree , unsigned int SystemDegree , typename AddNodeFunctor , typename HasDataFunctor , typename ... InterpolationInfos , typename ... DenseOrSparseNodeData > +std::vector< node_index_type > FEMTree< Dim , Real >::finalizeForMultigrid( LocalDepth baseDepth , const AddNodeFunctor addNodeFunctor , const HasDataFunctor hasDataFunctor , std::tuple< InterpolationInfos *... > interpolationInfos , std::tuple< DenseOrSparseNodeData *... > data ) +{ + auto isDirichletLeafFunctor = []( const FEMTreeNode * ){ return false; }; + return _finalizeForMultigrid< false , MaxDegree , SystemDegree >( baseDepth , addNodeFunctor , hasDataFunctor , isDirichletLeafFunctor , interpolationInfos , data ); } template< unsigned int Dim , class Real > -template< unsigned int MaxDegree , unsigned int SystemDegree , typename HasDataFunctor , typename IsDirichletLeafFunctor , typename ... InterpolationInfos , typename ... DenseOrSparseNodeData > -void FEMTree< Dim , Real >::finalizeForMultigrid( LocalDepth baseDepth , LocalDepth fullDepth , const HasDataFunctor hasData , const IsDirichletLeafFunctor isDirichletLeaf , std::tuple< InterpolationInfos *... > interpolationInfos , std::tuple< DenseOrSparseNodeData *... > data ) +template< unsigned int MaxDegree , unsigned int SystemDegree , typename AddNodeFunctor , typename HasDataFunctor , typename IsDirichletLeafFunctor , typename ... InterpolationInfos , typename ... DenseOrSparseNodeData > +std::vector< node_index_type > FEMTree< Dim , Real >::finalizeForMultigridWithDirichlet( LocalDepth baseDepth , const AddNodeFunctor addNodeFunctor , const HasDataFunctor hasDataFunctor , const IsDirichletLeafFunctor isDirichletLeafFunctor , std::tuple< InterpolationInfos *... > interpolationInfos , std::tuple< DenseOrSparseNodeData *... > data ) +{ + return _finalizeForMultigrid< true , MaxDegree , SystemDegree >( baseDepth , addNodeFunctor , hasDataFunctor , isDirichletLeafFunctor , interpolationInfos , data ); +} + + +template< unsigned int Dim , class Real > +template< bool HasDirichlet , unsigned int MaxDegree , unsigned int SystemDegree , typename AddNodeFunctor , typename HasDataFunctor , typename IsDirichletLeafFunctor , typename ... InterpolationInfos , typename ... DenseOrSparseNodeData > +std::vector< node_index_type > FEMTree< Dim , Real >::_finalizeForMultigrid( LocalDepth baseDepth , const AddNodeFunctor addNodeFunctor , const HasDataFunctor hasDataFunctor , const IsDirichletLeafFunctor isDirichletLeafFunctor , std::tuple< InterpolationInfos *... > interpolationInfos , std::tuple< DenseOrSparseNodeData *... > data ) { std::function< void ( FEMTreeNode * ) > pushFullDirichletFlag = [&]( FEMTreeNode *node ) { @@ -624,12 +1249,11 @@ void FEMTree< Dim , Real >::finalizeForMultigrid( LocalDepth baseDepth , LocalDe if( node->children ) for( int c=0 ; c<(1<children+c , newNodeIndex , isDirichletNode ); }; - if( baseDepth>fullDepth ) ERROR_OUT( "Base depth cannot exceed full depth: " , baseDepth , " <= " , fullDepth ); _baseDepth = baseDepth; - _spaceRoot->parent = _tree; + // Expand the tree to ensure supporting finite elements can be indexed by octree nodes Allocator< FEMTreeNode > *nodeAllocator = nodeAllocators.size() ? nodeAllocators[0] : NULL; - _depthOffset = 1; + while( _localInset( 0 ) + BSplineEvaluationData< FEMDegreeAndBType< MaxDegree >::Signature >::Begin( 0 )<0 || _localInset( 0 ) + BSplineEvaluationData< FEMDegreeAndBType< MaxDegree >::Signature >::End( 0 )>(1<<_depthOffset) ) { // +-+-+-+-+-+-+-+-+ @@ -650,44 +1274,74 @@ void FEMTree< Dim , Real >::finalizeForMultigrid( LocalDepth baseDepth , LocalDe // | | | | | | | | | // +-+-+-+-+-+-+-+-+ - FEMTreeNode* newSpaceRootParent = FEMTreeNode::NewBrood( nodeAllocator , _nodeInitializer ); - FEMTreeNode* oldSpaceRootParent = _spaceRoot->parent; - int corner = _depthOffset<=1 ? (1<children = newSpaceRootParent; - for( int c=0 ; c<(1<maxDepth(); - _fullDepth = std::min( fullDepth , _maxDepth ); // Mark leaf nodes that are Dirichlet constraints so they do not get clipped out. // Need to do this before introducing new nodes into the tree (since isDirichletLeaf depends on the structure at input). - for( FEMTreeNode *leaf=_spaceRoot->nextLeaf() ; leaf ; leaf=_spaceRoot->nextLeaf(leaf) ) leaf->nodeData.setDirichletNodeFlag( isDirichletLeaf( leaf ) ); + if constexpr( HasDirichlet ) _spaceRoot->processLeaves( [&]( FEMTreeNode *leaf ){ leaf->nodeData.setDirichletNodeFlag( isDirichletLeafFunctor( leaf ) ); } ); // Make the low-resolution part of the tree be complete - _setFullDepth< false >( IsotropicUIntPack< Dim , MaxDegree >() , nodeAllocator , _fullDepth ); + _setFullDepth< false >( IsotropicUIntPack< Dim , MaxDegree >() , nodeAllocator , _baseDepth ); + _refine< false >( IsotropicUIntPack< Dim , MaxDegree >() , nodeAllocator , addNodeFunctor ); - // Mark new leaf nodes - pushFullDirichletFlag( _spaceRoot ); + if constexpr( HasDirichlet ) + { + // Mark new leaf nodes + pushFullDirichletFlag( _spaceRoot ); + + // Pull the Dirichlet designator from the leaves so that nodes are now marked if they contain (possibly partial Dirichlet constraints + pullPartialDirichletFlag( _spaceRoot ); - // Pull the Dirichlet designator from the leaves so that nodes are now marked if they contain (possibly partial Dirichlet constraints - pullPartialDirichletFlag( _spaceRoot ); + // Use the node Dirichlet designators to set the coarser finite element Dirichlet designators + _markBaseDirichletElements< SystemDegree >(); + } - // Use the node Dirichlet designators to set the coarser finite element Dirichlet designators - _markBaseDirichletElements< SystemDegree >(); + // Clear all the flags and make everything that is not low-res a ghost node, and clip the tree + auto _addNodeFunctor = [&]( const FEMTreeNode *node ) + { + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + return addNodeFunctor( d , off ); + }; - // Clear all the flags and make everything that is not low-res a ghost node - for( FEMTreeNode* node=_tree->nextNode() ; node ; node=_tree->nextNode( node ) ) node->nodeData.flags &= ( FEMTreeNodeData::SCRATCH_FLAG | FEMTreeNodeData::DIRICHLET_NODE_FLAG | FEMTreeNodeData::DIRICHLET_ELEMENT_FLAG ) , SetGhostFlag( node , _localDepth( node )>fullDepth ); + auto nodeFunctor = [&]( FEMTreeNode *node ) + { + if constexpr( HasDirichlet ) node->nodeData.flags &= ( FEMTreeNodeData::SCRATCH_FLAG | FEMTreeNodeData::DIRICHLET_NODE_FLAG | FEMTreeNodeData::DIRICHLET_ELEMENT_FLAG ); + else node->nodeData.flags &= ( FEMTreeNodeData::SCRATCH_FLAG ); + SetGhostFlag( node , !_addNodeFunctor( node ) && _localDepth( node )>_baseDepth ); + }; + _tree.processNodes( nodeFunctor ); // Clip off nodes that not have data and do not contain geometry or Dirichlet constraints below the exactDepth - _clipTree( [&]( const FEMTreeNode *node ){ return hasData(node) || ( ( node->nodeData.getDirichletNodeFlag() || node->nodeData.getDirichletElementFlag() ) && _localDepth(node)<=_baseDepth ); } , fullDepth ); + if constexpr( HasDirichlet ) _clipTree( [&]( const FEMTreeNode *node ){ return _addNodeFunctor(node) || hasDataFunctor(node) || ( ( node->nodeData.getDirichletNodeFlag() || node->nodeData.getDirichletElementFlag() ) && _localDepth(node)<=_baseDepth ); } , _baseDepth ); + else _clipTree( [&]( const FEMTreeNode *node ){ return _addNodeFunctor(node) || hasDataFunctor(node); } , _baseDepth ); // It is possible for the tree to have become shallower after clipping - _maxDepth = _tree->maxDepth() - _depthOffset; + _maxDepth = _tree.maxDepth() - _depthOffset; node_index_type oldNodeCount = _nodeCount; @@ -695,16 +1349,30 @@ void FEMTree< Dim , Real >::finalizeForMultigrid( LocalDepth baseDepth , LocalDe _supportApproximateProlongation< MaxDegree >(); // Mark new leaf nodes - pushDirichletFlag( _spaceRoot , oldNodeCount , _spaceRoot->nodeData.getDirichletNodeFlag() ); + if constexpr( HasDirichlet ) + { + pushDirichletFlag( _spaceRoot , oldNodeCount , _spaceRoot->nodeData.getDirichletNodeFlag() ); + _markNonBaseDirichletElements< SystemDegree >(); + } _markNonBaseDirichletElements< SystemDegree >(); + return setSortedTreeNodes( interpolationInfos , data ); +} + +template< unsigned int Dim , class Real > +template< typename ... InterpolationInfos , typename ... DenseOrSparseNodeData > +std::vector< node_index_type > FEMTree< Dim , Real >::setSortedTreeNodes( std::tuple< InterpolationInfos *... > interpolationInfos , std::tuple< DenseOrSparseNodeData *... > data ) +{ + _maxDepth = _tree.maxDepth() - _depthOffset; std::vector< node_index_type > map; - _sNodes.set( *_tree , &map ); + _sNodes.reset( _tree , map ); _setSpaceValidityFlags(); - for( FEMTreeNode* node=_tree->nextNode() ; node ; node=_tree->nextNode( node ) ) if( !IsActiveNode( node ) ) node->nodeData.nodeIndex = -1; + _tree.processNodes( [&]( FEMTreeNode *node ){ if( !IsActiveNode( node ) ) node->nodeData.nodeIndex = -1; } ); _reorderDenseOrSparseNodeData< 0 >( GetPointer( map ) , _sNodes.size() , data ); _reorderInterpolationInfo< 0 >( GetPointer( map ) , _sNodes.size() , interpolationInfos ); - MemoryUsage(); + memset( _femSigs1 , -1 , sizeof( _femSigs1 ) ); + memset( _femSigs2 , -1 , sizeof( _femSigs2 ) ); + return map; } template< unsigned int Dim , class Real > @@ -712,22 +1380,34 @@ template< class ... DenseOrSparseNodeData > void FEMTree< Dim , Real >::resetIndices( std::tuple< DenseOrSparseNodeData *... > data ) { std::vector< node_index_type > map; - _sNodes.set( *_tree , &map ); + _sNodes.reset( _tree , map ); _setSpaceValidityFlags(); - for( FEMTreeNode* node=_tree->nextNode() ; node ; node=_tree->nextNode( node ) ) if( !IsActiveNode< Dim >( node ) ) node->nodeData.nodeIndex = -1; - _reorderDenseOrSparseNodeData< 0 >( &map[0] , _sNodes.size() , data ); - MemoryUsage(); + _tree.processNodes( [&]( FEMTreeNode *node ){ if( !IsActiveNode< Dim >( node ) ) node->nodeData.nodeIndex = -1; } ); + _reorderDenseOrSparseNodeData< 0 >( GetPointer( map ) , _sNodes.size() , data ); +} + +template< unsigned int Dim , class Real > +template< typename PruneChildrenFunctor , typename ... InterpolationInfos , typename ... DenseOrSparseNodeData > +void FEMTree< Dim , Real >::pruneChildren( const PruneChildrenFunctor pruneChildren , std::tuple< InterpolationInfos *... > interpolationInfos , std::tuple< DenseOrSparseNodeData *... > data ) +{ + _tree.pruneChildren( pruneChildren , false ); + std::vector< node_index_type > map; + _sNodes.reset( _tree , map ); + _setSpaceValidityFlags(); + _tree.processNodes( [&]( FEMTreeNode *node ){ if( !IsActiveNode< Dim >( node ) ) node->nodeData.nodeIndex = -1; } ); + _reorderDenseOrSparseNodeData< 0 >( GetPointer( map ) , _sNodes.size() , data ); + _reorderInterpolationInfo< 0 >( GetPointer( map ) , _sNodes.size() , interpolationInfos ); } template< unsigned int Dim , class Real > void FEMTree< Dim , Real >::_setSpaceValidityFlags( void ) const { + const unsigned char MASK = ~( FEMTreeNodeData::SPACE_FLAG ); ThreadPool::Parallel_for( 0 , _sNodes.size() , [&]( unsigned int , size_t i ) - { - const unsigned char MASK = ~( FEMTreeNodeData::SPACE_FLAG ); - _sNodes.treeNodes[i]->nodeData.flags &= MASK; - if( isValidSpaceNode( _sNodes.treeNodes[i] ) ) _sNodes.treeNodes[i]->nodeData.flags |= FEMTreeNodeData::SPACE_FLAG; - } + { + _sNodes.treeNodes[i]->nodeData.flags &= MASK; + if( isValidSpaceNode( _sNodes.treeNodes[i] ) ) _sNodes.treeNodes[i]->nodeData.flags |= FEMTreeNodeData::SPACE_FLAG; + } ); } template< unsigned int Dim , class Real > @@ -777,19 +1457,22 @@ template< class HasDataFunctor > void FEMTree< Dim , Real >::_clipTree( const HasDataFunctor& f , LocalDepth fullDepth ) { std::vector< FEMTreeNode * > regularNodes; - auto NodeTerminationLambda = [&]( const FEMTreeNode *node ){ return _localDepth( node )==fullDepth; }; - for( FEMTreeNode* temp=_tree->nextNode( NodeTerminationLambda , NULL ) ; temp ; temp=_tree->nextNode( NodeTerminationLambda , temp ) ) if( _localDepth( temp )==fullDepth ) regularNodes.push_back( temp ); + _tree.processNodes( [&]( FEMTreeNode *node ){ if( _localDepth( node )==fullDepth ) regularNodes.push_back( node ) ; return _localDepth( node ) nodeHasData( nodeCount() , 0 ); + // [NOTE] Have to use an array of chars instead of bools because the latter is not thread safe + size_t sz = nodeCount(); + Pointer( char ) nodeHasData = NewPointer< char >( sz ); + for( unsigned int i=0 ; inextNode() ; node ; node=regularNodes[i]->nextNode(node) ) nodeHasData[node->nodeData.nodeIndex] = f( node ) ? 1 : 0; - } ); + { + regularNodes[i]->processNodes( [&]( FEMTreeNode *node ){ if( node->nodeData.nodeIndex!=-1 ) nodeHasData[node->nodeData.nodeIndex] = f( node ) ? 1 : 0; } ); + } ); // Pull the data status from the leaves std::function< char ( const FEMTreeNode * ) > PullHasDataFromChildren = [&]( const FEMTreeNode *node ) { + if( node->nodeData.nodeIndex==-1 ) return (char)0; char hasData = nodeHasData[node->nodeData.nodeIndex]; if( node->children ) for( int c=0 ; c<(1<children+c ); nodeHasData[node->nodeData.nodeIndex] = hasData; @@ -800,14 +1483,19 @@ void FEMTree< Dim , Real >::_clipTree( const HasDataFunctor& f , LocalDepth full // Mark all children of a node as ghost if none of them have data ThreadPool::Parallel_for( 0 , regularNodes.size() , [&]( unsigned int , size_t i ) - { - for( FEMTreeNode* node=regularNodes[i]->nextNode() ; node ; node=regularNodes[i]->nextNode(node) ) if( node->children ) { - char childHasData = 0; - for( int c=0 ; c<(1<children[c].nodeData.nodeIndex]; - for( int c=0 ; c<(1<( node->children+c , !childHasData ); - } - } ); + auto nodeFunctor = [&]( FEMTreeNode *node ) + { + if( node->children ) + { + char childHasData = 0; + for( int c=0 ; c<(1<children[c].nodeData.nodeIndex!=-1 ) childHasData |= nodeHasData[node->children[c].nodeData.nodeIndex]; + for( int c=0 ; c<(1<( node->children+c , !childHasData ); + } + }; + regularNodes[i]->processNodes( nodeFunctor ); + } ); + DeletePointer( nodeHasData ); } template< unsigned int Dim , class Real > @@ -843,8 +1531,11 @@ void FEMTree< Dim , Real >::_ExactPointAndDataInterpolationInfo< T , Data , Poin node_index_type start = 0; SetRange( tree._spaceRoot , start ); - for( FEMTreeNode* node=tree._spaceRoot->nextNode() ; node ; node=tree._spaceRoot->nextNode(node) ) + auto nodeFunctor = [&]( FEMTreeNode *node ) + { if( tree._isValidSpaceNode( node ) && !tree._isValidSpaceNode( node->children ) ) _sampleSpan[ node->nodeData.nodeIndex ].second = _sampleSpan[ node->nodeData.nodeIndex ].first; + }; + tree._spaceRoot->processNodes( nodeFunctor ); for( node_index_type i=0 ; i<(node_index_type)samples.size() ; i++ ) { @@ -862,14 +1553,13 @@ void FEMTree< Dim , Real >::_ExactPointAndDataInterpolationInfo< T , Data , Poin } ThreadPool::Parallel_for( 0 , _iData.size() , [&]( unsigned int , size_t i ) - { - Real w = _iData[i].pointInfo.weight; - _iData[i] /= w; - if( noRescale ) _iData[i].pointInfo.weight = w; - else _iData[i].pointInfo.weight = w * ( 1< @@ -905,8 +1595,12 @@ void FEMTree< Dim , Real >::ExactPointInterpolationInfo< T , PointD , Constraint node_index_type start=0; SetRange( tree._spaceRoot , start ); - for( FEMTreeNode* node=tree._spaceRoot->nextNode() ; node ; node=tree._spaceRoot->nextNode(node) ) + + auto nodeFunctor = [&]( FEMTreeNode *node ) + { if( tree._isValidSpaceNode( node ) && !tree._isValidSpaceNode( node->children ) ) _sampleSpan[ node->nodeData.nodeIndex ].second = _sampleSpan[ node->nodeData.nodeIndex ].first; + }; + tree._spaceRoot->processNodes( nodeFunctor ); for( node_index_type i=0 ; i<(node_index_type)samples.size() ; i++ ) { @@ -923,22 +1617,22 @@ void FEMTree< Dim , Real >::ExactPointInterpolationInfo< T , PointD , Constraint } ThreadPool::Parallel_for( 0 , _iData.size() , [&]( unsigned int , size_t i ) - { - Real w = _iData[i].weight; - _iData[i] /= w; - if( noRescale ) _iData[i].weight = w; - else _iData[i].weight = w * ( 1< template< unsigned int PointD , typename ConstraintDual , typename SystemDual > void FEMTree< Dim , Real >::ExactPointInterpolationInfo< double , PointD , ConstraintDual , SystemDual >::_init( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , bool noRescale ) { _sampleSpan.resize( tree.nodesSize() ); ThreadPool::Parallel_for( 0 , tree.nodesSize() , [&]( unsigned int , size_t i ){ _sampleSpan[i] = std::pair< node_index_type , node_index_type >( 0 , 0 ); } ); - for( node_index_type i=0 ; iparent; @@ -965,8 +1659,11 @@ void FEMTree< Dim , Real >::ExactPointInterpolationInfo< double , PointD , Const node_index_type start = 0; SetRange( tree._spaceRoot , start ); - for( FEMTreeNode* node=tree._spaceRoot->nextNode() ; node ; node=tree._spaceRoot->nextNode(node) ) + auto nodeFunctor = [&]( FEMTreeNode *node ) + { if( tree._isValidSpaceNode( node ) && !tree._isValidSpaceNode( node->children ) ) _sampleSpan[ node->nodeData.nodeIndex ].second = _sampleSpan[ node->nodeData.nodeIndex ].first; + }; + tree._spaceRoot->processNodes( nodeFunctor ); for( node_index_type i=0 ; i::ExactPointInterpolationInfo< double , PointD , Const } ThreadPool::Parallel_for( 0 , _iData.size() , [&]( unsigned int , size_t i ) - { - Real w = _iData[i].weight; - _iData[i] /= w; - if( noRescale ) _iData[i].weight = w; - else _iData[i].weight = w * ( 1< template< typename T > bool FEMTree< Dim , Real >::_setInterpolationInfoFromChildren( FEMTreeNode* node , SparseNodeData< T , IsotropicUIntPack< Dim , FEMTrivialSignature > >& interpolationInfo ) const @@ -1011,11 +1709,11 @@ bool FEMTree< Dim , Real >::_setInterpolationInfoFromChildren( FEMTreeNode* node } else return interpolationInfo( node )!=NULL; } + template< unsigned int Dim , class Real > template< typename T , unsigned int PointD , typename ConstraintDual > -SparseNodeData< DualPointInfo< Dim , Real , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > FEMTree< Dim , Real >::_densifyInterpolationInfoAndSetDualConstraints( const std::vector< PointSample >& samples , ConstraintDual constraintDual , int adaptiveExponent ) const +void FEMTree< Dim , Real >::_densifyInterpolationInfoAndSetDualConstraints( SparseNodeData< DualPointInfo< Dim , Real , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > & iInfo , const std::vector< PointSample >& samples , ConstraintDual constraintDual , LocalDepth maxDepth , int adaptiveExponent ) const { - SparseNodeData< DualPointInfo< Dim , Real , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > iInfo; for( node_index_type i=0 ; i<(node_index_type)samples.size() ; i++ ) { const FEMTreeNode* node = samples[i].node; @@ -1034,32 +1732,32 @@ SparseNodeData< DualPointInfo< Dim , Real , T , PointD > , IsotropicUIntPack< Di _setInterpolationInfoFromChildren( _spaceRoot , iInfo ); ThreadPool::Parallel_for( 0 , iInfo.size() , [&]( unsigned int , size_t i ) - { - Real w = iInfo[i].weight; - iInfo[i] /= w ; iInfo[i].weight = w; - } - ); - LocalDepth maxDepth = _spaceRoot->maxDepth(); + { + Real w = iInfo[i].weight; + iInfo[i] /= w ; iInfo[i].weight = w; + } ); // Set the average position and scale the weights - for( const FEMTreeNode* node=_tree->nextNode() ; node ; node=_tree->nextNode(node) ) if( IsActiveNode< Dim >( node ) ) + auto nodeFunctor = [&]( const FEMTreeNode *node ) { - DualPointInfo< Dim , Real , T , PointD >* pData = iInfo( node ); - if( pData ) + if( IsActiveNode< Dim >( node ) ) { - int e = _localDepth( node ) * adaptiveExponent - ( maxDepth ) * (adaptiveExponent-1); - if( e<0 ) pData->weight /= Real( 1<<(-e) ); - else pData->weight *= Real( 1<< e ); - pData->dualValues *= pData->weight; + DualPointInfo< Dim , Real , T , PointD >* pData = iInfo( node ); + if( pData ) + { + int e = _localDepth( node ) * adaptiveExponent - ( maxDepth ) * (adaptiveExponent-1); + if( e<0 ) pData->weight /= Real( 1<<(-e) ); + else pData->weight *= Real( 1<< e ); + pData->dualValues *= pData->weight; + } } - } - return iInfo; + }; + _tree.processNodes( nodeFunctor ); } template< unsigned int Dim , class Real > template< typename T , typename Data , unsigned int PointD , typename ConstraintDual > -SparseNodeData< DualPointAndDataInfo< Dim , Real , Data , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > FEMTree< Dim , Real >::_densifyInterpolationInfoAndSetDualConstraints( const std::vector< PointSample >& samples , ConstPointer( Data ) sampleData , ConstraintDual constraintDual , int adaptiveExponent ) const +void FEMTree< Dim , Real >::_densifyInterpolationInfoAndSetDualConstraints( SparseNodeData< DualPointAndDataInfo< Dim , Real , Data , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > &iInfo , const std::vector< PointSample >& samples , ConstPointer( Data ) sampleData , ConstraintDual constraintDual , LocalDepth maxDepth , int adaptiveExponent ) const { - SparseNodeData< DualPointAndDataInfo< Dim , Real , Data , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > iInfo; for( node_index_type i=0 ; i<(node_index_type)samples.size() ; i++ ) { const FEMTreeNode* node = samples[i].node; @@ -1079,27 +1777,47 @@ SparseNodeData< DualPointAndDataInfo< Dim , Real , Data , T , PointD > , Isotrop _setInterpolationInfoFromChildren( _spaceRoot , iInfo ); ThreadPool::Parallel_for( 0 , iInfo.size() , [&]( unsigned int , size_t i ) - { - Real w = iInfo[i].pointInfo.weight; - iInfo[i] /= w ; iInfo[i].pointInfo.weight = w; - } + { + Real w = iInfo[i].pointInfo.weight; + iInfo[i] /= w ; iInfo[i].pointInfo.weight = w; + } ); - LocalDepth maxDepth = _spaceRoot->maxDepth(); // Set the average position and scale the weights - for( const FEMTreeNode* node=_tree->nextNode() ; node ; node=_tree->nextNode(node) ) if( IsActiveNode< Dim >( node ) ) + auto nodeFunctor = [&]( const FEMTreeNode *node ) { - DualPointAndDataInfo< Dim , Real , Data , T , PointD >* pData = iInfo( node ); - if( pData ) + if( IsActiveNode< Dim >( node ) ) { - int e = _localDepth( node ) * adaptiveExponent - ( maxDepth ) * (adaptiveExponent-1); - if( e<0 ) pData->pointInfo.weight /= Real( 1<<(-e) ); - else pData->pointInfo.weight *= Real( 1<< e ); - pData->pointInfo.dualValues *= pData->pointInfo.weight; + DualPointAndDataInfo< Dim , Real , Data , T , PointD >* pData = iInfo( node ); + if( pData ) + { + int e = _localDepth( node ) * adaptiveExponent - ( maxDepth ) * (adaptiveExponent-1); + if( e<0 ) pData->pointInfo.weight /= Real( 1<<(-e) ); + else pData->pointInfo.weight *= Real( 1<< e ); + pData->pointInfo.dualValues *= pData->pointInfo.weight; + } } - } + }; + _tree.processNodes( nodeFunctor ); +} +template< unsigned int Dim , class Real > +template< typename T , unsigned int PointD , typename ConstraintDual > +SparseNodeData< DualPointInfo< Dim , Real , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > FEMTree< Dim , Real >::_densifyInterpolationInfoAndSetDualConstraints( const std::vector< PointSample >& samples , ConstraintDual constraintDual , LocalDepth maxDepth , int adaptiveExponent ) const +{ + SparseNodeData< DualPointInfo< Dim , Real , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > iInfo; + _densifyInterpolationInfoAndSetDualConstraints( iInfo , samples , constraintDual , maxDepth , adaptiveExponent ); + return iInfo; +} +template< unsigned int Dim , class Real > +template< typename T , typename Data , unsigned int PointD , typename ConstraintDual > +SparseNodeData< DualPointAndDataInfo< Dim , Real , Data , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > FEMTree< Dim , Real >::_densifyInterpolationInfoAndSetDualConstraints( const std::vector< PointSample >& samples , ConstPointer( Data ) sampleData , ConstraintDual constraintDual , LocalDepth maxDepth , int adaptiveExponent ) const +{ + SparseNodeData< DualPointAndDataInfo< Dim , Real , Data , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > iInfo; + _densifyInterpolationInfoAndSetDualConstraints( iInfo , samples , sampleData , constraintDual , maxDepth , adaptiveExponent ); return iInfo; } + + template< unsigned int Dim , class Real > template< typename T , unsigned int PointD , typename ConstraintDual > SparseNodeData< DualPointInfoBrood< Dim , Real , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > FEMTree< Dim , Real >::_densifyChildInterpolationInfoAndSetDualConstraints( const std::vector< PointSample >& samples , ConstraintDual constraintDual , bool noRescale ) const @@ -1125,18 +1843,18 @@ SparseNodeData< DualPointInfoBrood< Dim , Real , T , PointD > , IsotropicUIntPac _setInterpolationInfoFromChildren( _spaceRoot , iInfo ); ThreadPool::Parallel_for( 0 , iInfo.size() , [&]( unsigned int , size_t i ) - { - iInfo[i].finalize(); - for( size_t c=0 ; c , Is _setInterpolationInfoFromChildren( _spaceRoot , iInfo ); ThreadPool::Parallel_for( 0 , iInfo.size() , [&]( unsigned int , size_t i ) - { - iInfo[i].finalize(); - for( size_t c=0 ; c FEMTree< Dim , Real >::merge( FEMTree* tree ) // Compute the next available index node_index_type nextIndex = 0; - for( const FEMTreeNode* node=_tree->nextNode() ; node!=NULL ; node=_tree->nextNode( node ) ) nextIndex = std::max< node_index_type >( nextIndex , node->nodeData.nodeIndex+1 ); + _tree.processNodes( [&]( const FEMTreeNode *node ){ nextIndex = std::max< node_index_type >( nextIndex , node->nodeData.nodeIndex+1 ); } ); // Set the size of the map { node_index_type mapSize = 0; - for( const FEMTreeNode* node=tree->_tree->nextNode() ; node!=NULL ; node=tree->_tree->nextNode( node ) ) mapSize = std::max< node_index_type >( mapSize , node->nodeData.nodeIndex+1 ); + tree->_tree.processNodes( [&]( const FEMTreeNode *node ){ mapSize = std::max< node_index_type >( mapSize , node->nodeData.nodeIndex+1 ); } ); map.resize( mapSize ); } @@ -1230,5 +1948,4 @@ std::vector< node_index_type > FEMTree< Dim , Real >::merge( FEMTree* tree ) MergeNodes( _tree , tree->_tree , map , nextIndex ); return map; -} - +} \ No newline at end of file diff --git a/Src/Geometry.h b/Src/Geometry.h index 2a228d31..9e1f6903 100644 --- a/Src/Geometry.h +++ b/Src/Geometry.h @@ -38,6 +38,8 @@ DAMAGE. #ifdef _WIN32 #include #endif // _WIN32 +#include "MyMiscellany.h" +#include "Array.h" // An empty type template< typename Real > @@ -137,6 +139,8 @@ struct Point< Real , Dim > Point( const Point& p ){ memcpy( coords , p.coords , sizeof(Real)*Dim ); } template< class ... _Reals > Point( _Reals ... values ){ static_assert( sizeof...(values)==Dim || sizeof...(values)==0 , "[ERROR] Point::Point: Invalid number of coefficients" ) ; _init( 0 , values... ); } template< class _Real > Point( const Point< _Real , Dim >& p ){ for( unsigned int d=0 ; d } static Point CrossProduct( Point* points ){ return CrossProduct( ( const Point* )points ); } - friend std::ostream &operator << ( std::ostream &os , const Point &p ) - { - os << "( "; - for( int d=0 ; d + friend std::ostream &operator << ( std::ostream &os , const Point< _Real , _Dim > &p ); }; template< class Real , unsigned int Dim > Point< Real , Dim > operator * ( Real r , Point< Real , Dim > p ){ return p*r; } template< class Real , unsigned int Dim > Point< Real , Dim > operator / ( Real r , Point< Real , Dim > p ){ return p/r; } +template< class Real , unsigned int Dim > +std::ostream &operator << ( std::ostream &os , const Point< Real , Dim > &p ) +{ + os << "( "; + for( int d=0 ; d Point< Real , Dim > operator / ( Real template< class Real > struct Point< Real > { - Point( void ) : _coords(NULL) , _dim(0){} - Point( size_t dim ) : _coords(NULL) , _dim(0) { if( dim ){ _resize( (unsigned int)dim ) ; memset( _coords , 0 , sizeof(Real)*_dim ); } } - Point( const Point &p ) : _coords(NULL) , _dim(0) { if( p._dim ){ _resize( p._dim ) ; memcpy( _coords , p._coords , sizeof(Real)*_dim ); } } - ~Point( void ){ delete[] _coords ; _coords = NULL; } + Point( void ) : _coords( NullPointer(Real) ) , _dim(0){} + Point( size_t dim ) : _coords( NullPointer(Real) ) , _dim(0) { if( dim ){ _resize( (unsigned int)dim ) ; memset( _coords , 0 , sizeof(Real)*_dim ); } } + Point( const Point &p ) : _coords( NullPointer(Real) ) , _dim(0) { if( p._dim ){ _resize( p._dim ) ; memcpy( _coords , p._coords , sizeof(Real)*_dim ); } } + ~Point( void ){ DeletePointer( _coords ); } Point &operator = ( const Point &p ) { @@ -264,9 +271,14 @@ struct Point< Real > return os << " )"; } protected: - Real *_coords; + Pointer( Real ) _coords; unsigned int _dim; - void _resize( unsigned int dim ){ if( dim ){ _coords = new Real[dim] ; _dim = dim; } } + void _resize( unsigned int dim ) + { + DeletePointer( _coords ); + if( dim ) _coords = NewPointer< Real >( dim ); + _dim = dim; + } }; template< class Real > Point< Real > operator * ( Real s , Point< Real > p ){ return p*s; } diff --git a/Src/Image.h b/Src/Image.h index 067147f0..d7027935 100644 --- a/Src/Image.h +++ b/Src/Image.h @@ -285,7 +285,7 @@ bool TiledImageReader::GetInfo( const char* fileName , unsigned int& width , uns _tileHeights = new unsigned int[ _tileRows+1 ]; _tileWidths = new unsigned int[ _tileColumns+1 ]; - char tileName[1024]; + char tileName[2048]; for( unsigned int r=0 ; r<_tileRows ; r++ ) for( unsigned int c=0 ; c<_tileColumns ; c++ ) { if( !fgets( line , 1024 , fp ) ) ERROR_OUT( "Failed to read tile name from: " , fileName ); @@ -331,7 +331,7 @@ TiledImageReader::TiledImageReader( const char* fileName , unsigned int& width , _tileWidths = new unsigned int[ _tileColumns+1 ]; _tileNames = new char*[ _tileColumns * _tileRows ]; - char tileName[1024]; + char tileName[2048]; for( unsigned int r=0 ; r<_tileRows ; r++ ) for( unsigned int c=0 ; c<_tileColumns ; c++ ) { if( !fgets( line , 1024 , fp ) ) ERROR_OUT( "Failed to read tile name from: " , fileName ); diff --git a/Src/ImageStitching.cpp b/Src/ImageStitching.cpp index 7d144b73..a9addd3e 100644 --- a/Src/ImageStitching.cpp +++ b/Src/ImageStitching.cpp @@ -160,17 +160,6 @@ void WriteImage( char* fileName , RGBPixel* pixels , int w , int h ) ImageWriter::Write( fileName , (const unsigned char*)pixels , _w , _h , _c ); } -struct Profiler -{ - double t; - Profiler( void ){ t = Time(); } - void print( bool newLine=false ) const - { - printf( "%.2f (s) ; %d (MB)" , Time()-t , MemoryInfo::PeakMemoryUsageMB() ); - if( newLine ) printf( "\n" ); - } -}; - template< unsigned int Colors > void ReadAndWrite( ImageReader* pixels , ImageReader* labels , ImageWriter* output ) { @@ -309,7 +298,6 @@ void _Execute( void ) int maxDepth; DenseNodeData< Point< Real , Colors > , IsotropicUIntPack< Dim , FEMSig > > constraints; DenseNodeData< Point< Real , Colors > , IsotropicUIntPack< Dim , FEMSig > > solution; - { Profiler p; ImageReader* pixels = ImageReader::Get( In.values[0] ); @@ -318,14 +306,14 @@ void _Execute( void ) BufferedImageDerivativeStream< Real , Colors > dStream( resolution , pixels , labels ); for( int j=0 ; j zeroData; ThreadPool::ParallelSections - ( - [&]( void ){ dStream.prefetch(); } , - [&]( void ){ maxDepth = FEMTreeInitializer< Dim , Real >::template Initialize< (Degree&1)==0 , Point< Real , Colors > >( tree.spaceRoot() , dStream , derivatives , tree.nodeAllocators.size() ? tree.nodeAllocators[0] : NULL , tree.initializer() ); } - ); + ( + [&]( void ){ dStream.prefetch(); } , + [&]( void ){ maxDepth = FEMTreeInitializer< Dim , Real >::template Initialize< (Degree&1)==0 , Point< Real , Colors > >( tree.spaceRoot() , dStream , zeroData , derivatives , tree.nodeAllocators.size() ? tree.nodeAllocators[0] : NULL , tree.initializer() ); } + ); dStream.advance(); } - delete pixels; delete labels; { @@ -335,11 +323,15 @@ void _Execute( void ) for( int i=0 ; i( &nodes[0] , (int)nodes.size() , std::make_tuple() ); } - tree.template finalizeForMultigrid< Degree , Degree >( BaseDepth.value , FullDepth.value , []( const FEMTreeNode * ){ return true; } , []( const FEMTreeNode * ){ return false; } , std::make_tuple() ); + + auto addNodeFunctor = [&]( int d , const int off[Dim] ){ return d<=FullDepth.value; }; + tree.template finalizeForMultigrid< Degree , Degree >( BaseDepth.value , addNodeFunctor , []( const FEMTreeNode * ){ return true; } , std::make_tuple() ); + if( Verbose.set ) { printf( "Valid FEM Nodes / Edges: %llu %llu\n" , (unsigned long long)tree.validFEMNodes( IsotropicUIntPack< Dim , FEMSig >() ) , (unsigned long long)( derivatives[0].size() + derivatives[1].size() ) ); - printf( "Set tree [%d]: " , maxDepth ) , p.print( true ); + std::string str = p(); + printf( "Set tree [%d]: %s\n" , maxDepth , str.c_str() ); } } @@ -375,7 +367,11 @@ void _Execute( void ) F.weights[0][ TensorDerivatives< FEMDerivative >::Index( derivatives1 ) ][ TensorDerivatives< CDerivative >::Index( derivatives2 ) ] = 1; tree.addFEMConstraints( F , partialY , constraints , maxDepth ); } - if( Verbose.set ) printf( "Set constraints: " ) , p.print( true ); + if( Verbose.set ) + { + std::string str = p(); + printf( "Set constraints: %s\n" , str.c_str() ); + } } // Solve the system { @@ -386,14 +382,17 @@ void _Execute( void ) sInfo.cgDepth = 0 , sInfo.cascadic = false , sInfo.vCycles = 1 , sInfo.cgAccuracy = 0 , sInfo.verbose = Verbose.set , sInfo.showResidual = ShowResidual.set , sInfo.showGlobalResidual = false , sInfo.sliceBlockSize = ROW_BLOCK_SIZE; sInfo.baseVCycles = BaseVCycles.value; sInfo.iters = GSIterations.value; - sInfo.useSupportWeights = true; sInfo.sorRestrictionFunction = [&] ( Real w , Real ){ return (Real)( WeightScale.value * pow( w , WeightExponent.value ) ); }; sInfo.wCycle = false; typename FEMIntegrator::template System< IsotropicUIntPack< Dim , FEMSig > , IsotropicUIntPack< Dim , 1 > > F( { 0. , 1. } ); DenseNodeData< Point< Real , Colors > , IsotropicUIntPack< Dim , FEMSig > > _constraints = tree.template initDenseNodeData< Point< Real , Colors > >( IsotropicUIntPack< Dim , FEMSig >() ); - tree.solveSystem( IsotropicUIntPack< Dim , FEMSig >() , F , constraints , solution , Point< Real , Colors >::Dot , maxDepth , sInfo ); - if( Verbose.set ) printf( "Solved system: " ) , p.print( true ); + tree.solveSystem( IsotropicUIntPack< Dim , FEMSig >() , F , constraints , solution , Point< Real , Colors >::Dot , BaseDepth.value , maxDepth , sInfo ); + if( Verbose.set ) + { + std::string str = p(); + printf( "Solved system: %s\n" , str.c_str() ); + } } Point< Real , Colors > average; @@ -401,7 +400,11 @@ void _Execute( void ) Profiler p; Real begin[] = { 0 , 0 } , end[] = { (Real)w/(1< +#include ////////////////// // OpenMP Stuff // @@ -37,6 +38,28 @@ DAMAGE. #include #endif // _OPENMP +//////////////////////////// +// Formatted float output // +//////////////////////////// +struct StreamFloatPrecision +{ + StreamFloatPrecision( std::ostream &str , unsigned int precision , bool scientific=false ) : _str(str) + { + _defaultPrecision = (int)_str.precision(); + _str.precision( precision ); + if( scientific ) _str << std::scientific; + else _str << std::fixed; + } + ~StreamFloatPrecision( void ) + { + _str << std::defaultfloat; + _str.precision( _defaultPrecision ); + } +protected: + int _defaultPrecision; + std::ostream &_str; +}; + //////////////// // Time Stuff // //////////////// @@ -89,88 +112,20 @@ const char FileSeparator = '/'; #endif // _WIN32 || _WIN64 #endif // !SetTempDirectory -#include -#include -#include -struct MessageWriter +#if defined( _WIN32 ) || defined( _WIN64 ) +#include +inline void FSync( FILE *fp ) { - char* outputFile; - bool echoSTDOUT; - MessageWriter( void ){ outputFile = NULL , echoSTDOUT = true; } - void operator() ( 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 operator() ( std::vector< char* >& messages , 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 ); - } - // [WARNING] We are not checking the string is small enough to fit in 1024 characters - messages.push_back( new char[1024] ); - char* str = messages.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; - } - void operator() ( std::vector< std::string >& messages , 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 ); - } - // [WARNING] We are not checking the string is small enough to fit in 1024 characters - char message[1024]; - va_list args; - va_start( args , format ); - vsprintf( message , format , args ); - va_end( args ); - if( message[strlen(message)-1]=='\n' ) message[strlen(message)-1] = 0; - messages.push_back( std::string( message ) ); - } -}; + // FlushFileBuffers( (HANDLE)_fileno( fp ) ); + _commit( _fileno( fp ) ); +} +#else // !_WIN32 && !_WIN64 +#include +inline void FSync( FILE *fp ) +{ + fsync( fileno( fp ) ); +} +#endif // _WIN32 || _WIN64 ///////////////////////////////////// // Exception, Warnings, and Errors // @@ -247,6 +202,28 @@ namespace MKExceptions #define ERROR_OUT( ... ) MKExceptions::ErrorOut( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) #endif // ERROR_OUT +struct FunctionCallNotifier +{ + FunctionCallNotifier( std::string str ) : _str(str) + { + _depth = _Depth++; + for( unsigned int i=0 ; i<_depth ; i++ ) std::cout << " "; + std::cout << "[START] " << _str << std::endl; + }; + ~FunctionCallNotifier( void ) + { + for( unsigned int i=0 ; i<_depth ; i++ ) std::cout << " "; + std::cout << "[END] " << _str << std::endl; + _Depth--; + } +protected: + static unsigned int _Depth; + unsigned int _depth; + std::string _str; +}; +unsigned int FunctionCallNotifier::_Depth = 0; +#define FUNCTION_NOTIFY FunctionCallNotifier ___myFunctionCallNotifier___( __FUNCTION__ ) + #include #if defined(_WIN32) || defined( _WIN64 ) #else // !WINDOWS @@ -588,7 +565,7 @@ bool SetAtomic64( volatile Value *value , Value newValue , Value oldValue ) } template< typename Number > -void AddAtomic32( Number &a , Number b ) +void AddAtomic32( volatile Number &a , Number b ) { #if defined( _WIN32 ) || defined( _WIN64 ) Number current = a; @@ -606,7 +583,7 @@ void AddAtomic32( Number &a , Number b ) } template< typename Number > -void AddAtomic64( Number &a , Number b ) +void AddAtomic64( volatile Number &a , Number b ) { #if 1 Number current = a; @@ -762,11 +739,95 @@ struct VectorWrapper : public std::vector< Data > size_t getPeakRSS( void ); size_t getCurrentRSS( void ); +struct Profiler +{ + Profiler( unsigned int ms=0 ) + { + _t = Time(); + _currentPeak = 0; + if( ms ) + { + _thread = std::thread( &Profiler::_updatePeakMemoryFunction , std::ref( *this ) , ms ); + _spawnedSampler = true; + } + else _spawnedSampler = false; + } + + ~Profiler( void ) + { + if( _spawnedSampler ) + { + { + std::lock_guard< std::mutex > lock( _mutex ); + _terminate = true; + } + _thread.join(); + } + } + + void reset( void ) + { + _t = Time(); + if( _spawnedSampler ) + { + std::lock_guard< std::mutex > lock( _mutex ); + _currentPeak = 0; + } + else _currentPeak = 0; + } + + void update( void ) + { + size_t currentPeak = getCurrentRSS(); + if( _spawnedSampler ) + { + std::lock_guard< std::mutex > lock( _mutex ); + if( currentPeak>_currentPeak ) _currentPeak = currentPeak; + } + else if( currentPeak>_currentPeak ) _currentPeak = currentPeak; + } + + std::string operator()( std::string header="" ) const + { + std::stringstream ss; + double dt = Time()-_t; + double localPeakMB = ( (double)_currentPeak )/(1<<20); + double globalPeakMB = ( (double)getPeakRSS() )/(1<<20); + { + StreamFloatPrecision sfp( ss , 1 ); + if( header.length() ) ss << header << " "; + ss << dt << " (s), " << localPeakMB << " (MB) / " << globalPeakMB << " (MB)"; + } + return ss.str(); + } + + friend std::ostream &operator << ( std::ostream &os , const Profiler &profiler ){ return os << profiler(); } + +protected: + std::thread _thread; + std::mutex _mutex; + bool _spawnedSampler; + double _t; + volatile size_t _currentPeak; + volatile bool _terminate; + + void _updatePeakMemoryFunction( unsigned int ms ) + { + while( true ) + { + std::this_thread::sleep_for( std::chrono::milliseconds( ms ) ); + update(); + if( _terminate ) return; + } + }; +}; + struct MemoryInfo { static size_t Usage( void ){ return getCurrentRSS(); } static int PeakMemoryUsageMB( void ){ return (int)( getPeakRSS()>>20 ); } }; + #if defined( _WIN32 ) || defined( _WIN64 ) #include #include @@ -918,13 +979,4 @@ inline size_t getCurrentRSS( ) #endif } -#include "Array.h" -template< typename C > -struct Serializer -{ - virtual size_t size( void ) const = 0; - virtual void serialize( const C & , Pointer( char ) buffer ) const = 0; - virtual void deserialize( ConstPointer( char ) buffer , C & ) const = 0; -}; - #endif // MY_MISCELLANY_INCLUDED diff --git a/Src/PNG.inl b/Src/PNG.inl index 7f820e5a..fb37449a 100644 --- a/Src/PNG.inl +++ b/Src/PNG.inl @@ -1,10 +1,5 @@ #include #include -#ifdef _WIN32 -#include "PNG/png.h" -#else // !_WIN32 -#include -#endif // _WIN32 inline PNGReader::PNGReader( const char* fileName , unsigned int& width , unsigned int& height , unsigned int& channels ) { diff --git a/Src/Ply.h b/Src/Ply.h index 4868b2e1..27d37a56 100644 --- a/Src/Ply.h +++ b/Src/Ply.h @@ -53,8 +53,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "PlyFile.h" #include "Geometry.h" -#include "CoredMesh.h" +#include "StreamingMesh.h" #include "MyMiscellany.h" +#include "Array.h" namespace PLY { @@ -65,7 +66,7 @@ namespace PLY template< typename Integer > struct Traits{ static const std::string name; }; // A structure representing a face - template< typename Index > + template< typename Index , bool UseCharIndex=false > struct Face { unsigned int nr_vertices; @@ -90,10 +91,10 @@ namespace PLY int ReadVertexHeader( std::string fileName , const VertexFactory &vFactory , bool *readFlags , std::vector< PlyProperty > &unprocessedProperties ); // PLY write mesh functionality - template< typename VertexFactory , typename Index , class Real , int Dim , typename OutputIndex=int > - void WritePolygons( std::string fileName , const VertexFactory &vFactory , CoredMeshData< typename VertexFactory::VertexType , Index > *mesh , int file_type , const std::vector< std::string >& comments , std::function< typename VertexFactory::VertexType ( typename VertexFactory::VertexType ) > xForm = []( typename VertexFactory::VertexType v ){ return v; } ); + template< typename VertexFactory , typename Index , class Real , int Dim , typename OutputIndex=int , bool UseCharIndex=false > + void WritePolygons( std::string fileName , const VertexFactory &vFactory , StreamingMesh< typename VertexFactory::VertexType , Index > *mesh , int file_type , const std::vector< std::string >& comments , std::function< void ( typename VertexFactory::VertexType & ) > xForm = []( typename VertexFactory::VertexType &v ){} ); - template< typename VertexFactory , typename Index > + template< typename VertexFactory , typename Index , bool UseCharIndex=false > void WritePolygons( std::string fileName , const VertexFactory &vFactory , const std::vector< typename VertexFactory::VertexType > &vertices , const std::vector< std::vector< Index > > &polygons , int file_type , const std::vector< std::string > &comments ); // PLY read mesh functionality diff --git a/Src/Ply.inl b/Src/Ply.inl index 186600b0..65d4a0a1 100644 --- a/Src/Ply.inl +++ b/Src/Ply.inl @@ -49,14 +49,21 @@ namespace PLY template<> const std::string Traits< unsigned long long >::name="unsigned long long"; template<> - PlyProperty Face< int >::Properties[] = { PlyProperty( "vertex_indices" , PLY_INT , PLY_INT , offsetof( Face , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( Face , nr_vertices ) ) }; + PlyProperty Face< int , false >::Properties[] = { PlyProperty( "vertex_indices" , PLY_INT , PLY_INT , offsetof( Face , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( Face , nr_vertices ) ) }; template<> - PlyProperty Face< unsigned int >::Properties[] = { PlyProperty( "vertex_indices" , PLY_UINT , PLY_UINT , offsetof( Face , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( Face , nr_vertices ) ) }; + PlyProperty Face< unsigned int , false >::Properties[] = { PlyProperty( "vertex_indices" , PLY_UINT , PLY_UINT , offsetof( Face , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( Face , nr_vertices ) ) }; template<> - PlyProperty Face< long long >::Properties[] = { PlyProperty( "vertex_indices" , PLY_LONGLONG , PLY_LONGLONG , offsetof( Face , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( Face , nr_vertices ) ) }; + PlyProperty Face< long long , false >::Properties[] = { PlyProperty( "vertex_indices" , PLY_LONGLONG , PLY_LONGLONG , offsetof( Face , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( Face , nr_vertices ) ) }; template<> - PlyProperty Face< unsigned long long >::Properties[] = { PlyProperty( "vertex_indices" , PLY_ULONGLONG , PLY_ULONGLONG , offsetof( Face , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( Face , nr_vertices ) ) }; - + PlyProperty Face< unsigned long long , false >::Properties[] = { PlyProperty( "vertex_indices" , PLY_ULONGLONG , PLY_ULONGLONG , offsetof( Face , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( Face , nr_vertices ) ) }; + template<> + PlyProperty Face< int , true >::Properties[] = { PlyProperty( "vertex_indices" , PLY_INT , PLY_INT , offsetof( Face , vertices ) , 1 , PLY_CHAR , PLY_CHAR , offsetof( Face , nr_vertices ) ) }; + template<> + PlyProperty Face< unsigned int , true >::Properties[] = { PlyProperty( "vertex_indices" , PLY_UINT , PLY_UINT , offsetof( Face , vertices ) , 1 , PLY_CHAR , PLY_CHAR , offsetof( Face , nr_vertices ) ) }; + template<> + PlyProperty Face< long long , true >::Properties[] = { PlyProperty( "vertex_indices" , PLY_LONGLONG , PLY_LONGLONG , offsetof( Face , vertices ) , 1 , PLY_CHAR , PLY_CHAR , offsetof( Face , nr_vertices ) ) }; + template<> + PlyProperty Face< unsigned long long , true >::Properties[] = { PlyProperty( "vertex_indices" , PLY_ULONGLONG , PLY_ULONGLONG , offsetof( Face , vertices ) , 1 , PLY_CHAR , PLY_CHAR , offsetof( Face , nr_vertices ) ) }; // Read template< typename VertexFactory > inline int ReadVertexHeader( std::string fileName , const VertexFactory &vFactory , bool *readFlags ) @@ -79,7 +86,7 @@ namespace PLY } template< typename VertexFactory > - inline int ReadVertexHeader( std::string fileName , const VertexFactory &vFactory , bool *readFlags , std::vector< PlyProperty > &unprocessedProperties ) + inline int ReadVertexHeader( std::string fileName , const VertexFactory &vFactory , bool *readFlags , std::vector< PlyProperty > &unprocessedProperties , size_t &vNum ) { int fileType; std::vector< std::string > elist; @@ -88,8 +95,7 @@ namespace PLY PlyFile *ply = PlyFile::Read( fileName, elist, fileType, version ); if( !ply ) ERROR_OUT( "Failed to open ply file for reading: " , fileName ); - size_t numElems; - std::vector< PlyProperty > plist = ply->get_element_description( "vertex" , numElems ); + std::vector< PlyProperty > plist = ply->get_element_description( "vertex" , vNum ); if( !plist.size() ) ERROR_OUT( "Failed to get element description: vertex" ); for( unsigned int i=0 ; i + inline int ReadVertexHeader( std::string fileName , const VertexFactory &vFactory , bool *readFlags , std::vector< PlyProperty > &unprocessedProperties ) + { + size_t vNum; + return ReadVertexHeader( fileName , vFactory , readFlags , unprocessedProperties , vNum ); + } - inline int ReadVertexHeader( std::string fileName , std::vector< PlyProperty > &properties ) + inline int ReadVertexHeader( std::string fileName , std::vector< PlyProperty > &properties , size_t &vNum ) { int fileType; std::vector< std::string > elist; @@ -116,13 +128,17 @@ namespace PLY PlyFile *ply = PlyFile::Read( fileName, elist, fileType, version ); if( !ply ) ERROR_OUT( "Failed to open ply file for reading: " , fileName ); - size_t numElems; - std::vector< PlyProperty > plist = ply->get_element_description( "vertex" , numElems ); + std::vector< PlyProperty > plist = ply->get_element_description( "vertex" , vNum ); for( int i=0 ; i &properties ) + { + size_t vNum; + return ReadVertexHeader( fileName , properties , vNum ); + } template< typename VertexFactory , typename Index > void ReadPolygons( std::string fileName , const VertexFactory &vFactory , std::vector< typename VertexFactory::VertexType > &vertices , std::vector< std::vector< Index > > &polygons , int &file_type , std::vector< std::string > &comments , bool *readFlags ) @@ -151,17 +167,17 @@ namespace PLY if( readFlags ) readFlags[i] = (hasProperty!=0); } vertices.resize( num_elems , vFactory() ); - char *buffer = new char[ vFactory.bufferSize() ]; + Pointer( char ) buffer = NewPointer< char >( vFactory.bufferSize() ); for( size_t j=0 ; jget_element( (void *)&vertices[j] ); else { - ply->get_element( (void *)buffer ); + ply->get_element( PointerAddress( buffer ) ); vFactory.fromBuffer( buffer , vertices[j] ); } } - delete[] buffer; + DeletePointer( buffer ); } else if( elem_name=="face" ) { @@ -182,7 +198,7 @@ namespace PLY delete ply; } - template< typename VertexFactory , typename Index > + template< typename VertexFactory , typename Index , bool UseCharIndex > void WritePolygons( std::string fileName , const VertexFactory &vFactory , const std::vector< typename VertexFactory::VertexType > &vertices , const std::vector< std::vector< Index > > &polygons , int file_type , const std::vector< std::string > &comments ) { size_t nr_vertices = vertices.size(); @@ -202,7 +218,7 @@ namespace PLY ply->describe_property( "vertex" , &prop ); } ply->element_count( "face" , nr_faces ); - ply->describe_property( "face" , Face< Index >::Properties ); + ply->describe_property( "face" , Face< Index , UseCharIndex >::Properties ); // Write in the comments for( int i=0 ; iput_comment( comments[i] ); @@ -211,17 +227,17 @@ namespace PLY // write vertices ply->put_element_setup( elem_names[0] ); - char *buffer = new char[ vFactory.bufferSize() ]; + Pointer( char ) buffer = NewPointer< char >( vFactory.bufferSize() ); for( size_t j=0 ; jput_element( (void *)&vertices[j] ); else { vFactory.toBuffer( vertices[j] , buffer ); - ply->put_element( (void *)buffer ); + ply->put_element( PointerAddress( buffer ) ); } } - delete[] buffer; + DeletePointer( buffer ); // write faces Face< Index > ply_face; @@ -247,16 +263,16 @@ namespace PLY delete ply; } - template< typename VertexFactory , typename Index , class Real , int Dim , typename OutputIndex > - void WritePolygons( std::string fileName , const VertexFactory &vFactory , CoredMeshData< typename VertexFactory::VertexType , Index >* mesh , int file_type , const std::vector< std::string > &comments , std::function< typename VertexFactory::VertexType ( typename VertexFactory::VertexType ) > xForm ) + template< typename VertexFactory , typename Index , class Real , int Dim , typename OutputIndex , bool UseCharIndex > + void WritePolygons( std::string fileName , const VertexFactory &vFactory , StreamingMesh< typename VertexFactory::VertexType , Index >* mesh , int file_type , const std::vector< std::string > &comments , std::function< void ( typename VertexFactory::VertexType & ) > xForm ) { - if( mesh->outOfCoreVertexNum()+mesh->inCoreVertices.size()>(size_t)std::numeric_limits< OutputIndex >::max() ) + if( mesh->vertexNum()>(size_t)std::numeric_limits< OutputIndex >::max() ) { if( std::is_same< Index , OutputIndex >::value ) ERROR_OUT( "more vertices than can be represented using " , Traits< Index >::name ); WARN( "more vertices than can be represented using " , Traits< OutputIndex >::name , " using " , Traits< Index >::name , " instead" ); return WritePolygons< VertexFactory , Index , Real , Dim , Index >( fileName , vFactory , mesh , file_type , comments , xForm ); } - size_t nr_vertices = mesh->outOfCoreVertexNum()+mesh->inCoreVertices.size(); + size_t nr_vertices = mesh->vertexNum(); size_t nr_faces = mesh->polygonNum(); float version; std::vector< std::string > elem_names = { std::string( "vertex" ) , std::string( "face" ) }; @@ -275,7 +291,7 @@ namespace PLY ply->describe_property( "vertex" , &prop ); } ply->element_count( "face" , nr_faces ); - ply->describe_property( "face" , Face< OutputIndex >::Properties ); + ply->describe_property( "face" , Face< OutputIndex , UseCharIndex >::Properties ); // Write in the comments for( int i=0 ; iput_comment( comments[i] ); @@ -285,40 +301,30 @@ namespace PLY ply->put_element_setup( "vertex" ); if( vFactory.isStaticallyAllocated() ) { - for( size_t i=0 ; iinCoreVertices.size() ; i++ ) - { - typename VertexFactory::VertexType vertex = xForm( mesh->inCoreVertices[i] ); - ply->put_element( (void *)&vertex ); - } - for( size_t i=0; ioutOfCoreVertexNum() ; i++ ) + for( size_t i=0; ivertexNum() ; i++ ) { typename VertexFactory::VertexType vertex = vFactory(); - mesh->nextOutOfCoreVertex( vertex ); - vertex = xForm( vertex ); + mesh->nextVertex( vertex ); + xForm( vertex ); ply->put_element( (void *)&vertex ); } } else { - char *buffer = new char[ vFactory.bufferSize() ]; - for( size_t i=0 ; iinCoreVertices.size() ; i++ ) - { - typename VertexFactory::VertexType vertex = xForm( mesh->inCoreVertices[i] ); - vFactory.toBuffer( vertex , buffer ); - ply->put_element( (void *)buffer ); - } - for( size_t i=0; ioutOfCoreVertexNum() ; i++ ) + Pointer( char ) buffer = NewPointer< char >( vFactory.bufferSize() ); + for( size_t i=0; ivertexNum() ; i++ ) { typename VertexFactory::VertexType vertex = vFactory(); - mesh->nextOutOfCoreVertex( vertex ); - vFactory.toBuffer( xForm( vertex ) , buffer ); - ply->put_element( (void *)buffer ); + mesh->nextVertex( vertex ); + xForm( vertex ); + vFactory.toBuffer( vertex , buffer ); + ply->put_element( PointerAddress( buffer ) ); } - delete[] buffer; + DeletePointer( buffer ); } // write faces - std::vector< CoredVertexIndex< Index > > polygon; + std::vector< Index > polygon; ply->put_element_setup( "face" ); for( size_t i=0 ; inextPolygon( polygon ); ply_face.nr_vertices = int( polygon.size() ); ply_face.vertices = new OutputIndex[ polygon.size() ]; - for( int j=0 ; jinCoreVertices.size() ); + for( int j=0 ; jput_element( (void *)&ply_face ); delete[] ply_face.vertices; } // for, write faces + delete ply; } } diff --git a/Src/PlyFile.h b/Src/PlyFile.h index 989cc497..8a109e7d 100644 --- a/Src/PlyFile.h +++ b/Src/PlyFile.h @@ -55,6 +55,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include "MyMiscellany.h" +#include "Streams.h" + #define PLY_ASCII 1 /* ascii PLY file */ #define PLY_BINARY_BE 2 /* binary PLY file, big endian */ @@ -136,6 +139,27 @@ struct PlyProperty PlyProperty( const std::string &n , int et , int it , int o , int il=0 , int ce=0 , int ci=0 , int co=0 ) : name(n) , external_type(et) , internal_type(it) , offset(o) , is_list(il) , count_external(ce) , count_internal(ci) , count_offset(co){ } PlyProperty( const std::string &n ) : PlyProperty( n , 0 , 0 , 0 , 0 , 0 , 0 , 0 ){ } PlyProperty( void ) : external_type(0) , internal_type(0) , offset(0) , is_list(0) , count_external(0) , count_internal(0) , count_offset(0){ } + + void write( BinaryStream &stream ) const + { + stream.write( name ); + stream.write( external_type ); + stream.write( offset ); + stream.write( is_list ); + stream.write( count_external ); + stream.write( count_internal ); + stream.write( count_offset ); + } + void read( BinaryStream &stream ) + { + if( !stream.read( name ) ) ERROR_OUT( "Failed to read name" ); + if( !stream.read( external_type ) ) ERROR_OUT( "Failed to read external_type" ); + if( !stream.read( offset ) ) ERROR_OUT( "Failed to read offset" ); + if( !stream.read( is_list ) ) ERROR_OUT( "Failed to read is_list" ); + if( !stream.read( count_external ) ) ERROR_OUT( "Failed to read count_external" ); + if( !stream.read( count_internal ) ) ERROR_OUT( "Failed to read count_internal" ); + if( !stream.read( count_offset ) ) ERROR_OUT( "Failed to read count_offset" ); + } }; std::ostream &operator << ( std::ostream &os , PlyProperty p ) diff --git a/Src/PlyFile.inl b/Src/PlyFile.inl index 3d0310bd..a5c6f146 100644 --- a/Src/PlyFile.inl +++ b/Src/PlyFile.inl @@ -1450,7 +1450,7 @@ void write_binary_item( FILE *fp , int file_type , int int_val , unsigned int ui unsigned short ushort_val; short short_val; float float_val; - void *value; + void *value = NULL; switch (type) { case PLY_CHAR: @@ -1679,7 +1679,7 @@ void get_binary_item( FILE *fp , int file_type , int type , int &int_val , unsig ptr = ( void * )c; - if( fread( ptr , ply_type_size[type] , 1 , fp )!=1 ) ERROR_OUT( "fread() failed -- aborting." ); + if( fread( ptr , ply_type_size[type] , 1 , fp )!=1 ) ERROR_OUT( "fread() failed -- aborting: " , std::string( type_names[type] ) ); if( ( file_type!=native_binary_type ) && ( ply_type_size[type]>1 ) ) swap_bytes( (char *)ptr , ply_type_size[type] ); switch( type ) diff --git a/Src/PointInterpolant.cpp b/Src/PointInterpolant.cpp index bf703f35..9a9efd06 100644 --- a/Src/PointInterpolant.cpp +++ b/Src/PointInterpolant.cpp @@ -48,8 +48,6 @@ DAMAGE. #include "Image.h" #include "RegularGrid.h" -MessageWriter messageWriter; - cmdLineParameter< char* > InValues( "inValues" ) , InGradients( "inGradients" ) , @@ -184,33 +182,6 @@ void ShowUsage(char* ex) printf( "\t[--%s]\n" , Verbose.name ); } -template< unsigned int Dim , class Real > -struct FEMTreeProfiler -{ - FEMTree< Dim , Real >& tree; - double t; - - FEMTreeProfiler( FEMTree< Dim , Real >& t ) : tree(t) { ; } - void start( void ){ t = Time() , FEMTree< Dim , Real >::ResetLocalMemoryUsage(); } - void print( const char* header ) const - { - FEMTree< Dim , Real >::MemoryUsage(); - if( header ) printf( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %d (MB)\n" , header , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); - else printf( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %d (MB)\n" , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); - } - void dumpOutput( const char* header ) const - { - FEMTree< Dim , Real >::MemoryUsage(); - if( header ) messageWriter( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %d (MB)\n" , header , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); - else messageWriter( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %d (MB)\n" , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); - } - void dumpOutput2( std::vector< std::string >& comments , const char* header ) const - { - FEMTree< Dim , Real >::MemoryUsage(); - if( header ) messageWriter( comments , "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %d (MB)\n" , header , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); - else messageWriter( comments , "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %d (MB)\n" , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); - } -}; template< class Real , unsigned int Dim > XForm< Real , Dim+1 > GetBoundingBoxXForm( Point< Real , Dim > min , Point< Real , Dim > max , Real scaleFactor ) @@ -375,9 +346,9 @@ void ExtractMesh typedef UIntPack< FEMSigs ... > Sigs; static const unsigned int DataSig = FEMDegreeAndBType< WEIGHT_DEGREE , BOUNDARY_FREE >::Signature; - FEMTreeProfiler< Dim , Real > profiler( tree ); + Profiler profiler(20); - char tempHeader[1024]; + char tempHeader[2048]; { char tempPath[1024]; tempPath[0] = 0; @@ -389,24 +360,26 @@ void ExtractMesh } typedef EmptyVectorType< Real > EmptyVectorType; - CoredMeshData< typename VertexFactory::VertexType , node_index_type > *mesh; - if( InCore.set ) mesh = new CoredVectorMeshData< typename VertexFactory::VertexType , node_index_type >(); - else mesh = new CoredFileMeshData< node_index_type , VertexFactory >( vertexFactory , tempHeader ); - profiler.start(); - typename IsoSurfaceExtractor< Dim , Real , typename VertexFactory::VertexType >::IsoStats isoStats; + StreamingMesh< typename VertexFactory::VertexType , node_index_type > *mesh; + if( InCore.set ) mesh = new VectorStreamingMesh< typename VertexFactory::VertexType , node_index_type >(); + else mesh = new FileStreamingMesh< VertexFactory , node_index_type >( vertexFactory , tempHeader ); + profiler.reset(); + typename LevelSetExtractor< Dim , Real , typename VertexFactory::VertexType >::Stats stats; #if defined( __GNUC__ ) && __GNUC__ < 5 #ifdef SHOW_WARNINGS #warning "you've got me gcc version<5" #endif // SHOW_WARNINGS - isoStats = IsoSurfaceExtractor< Dim , Real , typename VertexFactory::VertexType >::template Extract< EmptyVectorType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , (typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE >*)NULL , (SparseNodeData< ProjectiveData< EmptyVectorType , Real > , IsotropicUIntPack< Dim , DataSig > > *)NULL , solution , isoValue , *mesh , EmptyVectorType() , SetVertex , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , false ); + stats = LevelSetExtractor< Dim , Real , typename VertexFactory::VertexType >::template Extract< EmptyVectorType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , (typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE >*)NULL , (SparseNodeData< ProjectiveData< EmptyVectorType , Real > , IsotropicUIntPack< Dim , DataSig > > *)NULL , solution , isoValue , *mesh , EmptyVectorType() , SetVertex , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , false ); #else // !__GNUC__ || __GNUC__ >=5 - isoStats = IsoSurfaceExtractor< Dim , Real , typename VertexFactory::VertexType >::template Extract< EmptyVectorType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , (typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE >*)NULL , NULL , solution , isoValue , *mesh , EmptyVectorType() , SetVertex , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , false ); + stats = LevelSetExtractor< Dim , Real , typename VertexFactory::VertexType >::template Extract< EmptyVectorType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , (typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE >*)NULL , NULL , solution , isoValue , *mesh , EmptyVectorType() , SetVertex , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , false ); #endif // __GNUC__ || __GNUC__ < 4 - messageWriter( "Vertices / Polygons: %llu / %llu\n" , (unsigned long long)( mesh->outOfCoreVertexNum()+mesh->inCoreVertices.size() ) , (unsigned long long)mesh->polygonNum() ); - std::string isoStatsString = isoStats.toString() + std::string( "\n" ); - messageWriter( isoStatsString.c_str() ); - if( PolygonMesh.set ) profiler.dumpOutput2( comments , "# Got polygons:" ); - else profiler.dumpOutput2( comments , "# Got triangles:" ); + if( Verbose.set ) + { + std::cout << "Vertices / Polygons: " << mesh->vertexNum() << " / " << mesh->polygonNum() << std::endl; + std::cout << stats.toString() << std::endl; + if( PolygonMesh.set ) std::cout << "# Got polygons: " << profiler << std::endl; + else std::cout << "# Got triangles: " << profiler << std::endl; + } std::vector< std::string > noComments; typename VertexFactory::Transform unitCubeToModelTransform( unitCubeToModel ); @@ -527,12 +500,15 @@ void Execute( UIntPack< FEMSigs ... > ) typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; std::vector< std::string > comments; - messageWriter( comments , "***********************************************\n" ); - messageWriter( comments , "***********************************************\n" ); - messageWriter( comments , "** Running Point Interpolant (Version %s) **\n" , VERSION ); - messageWriter( comments , "***********************************************\n" ); - messageWriter( comments , "***********************************************\n" ); - if( !Threads.set ) messageWriter( comments , "Running with %d threads\n" , Threads.value ); + if( Verbose.set ) + { + std::cout << "***********************************************" << std::endl; + std::cout << "***********************************************" << std::endl; + std::cout << "** Running Point Interpolant (Version " << VERSION << ") **" << std::endl; + std::cout << "***********************************************" << std::endl; + std::cout << "***********************************************" << std::endl; + if( !Threads.set ) std::cout << "Running with " << Threads.value << " threads" << std::endl; + } ThreadPool::Init( (ThreadPool::ParallelType)ParallelType.value , Threads.value ); @@ -563,14 +539,17 @@ void Execute( UIntPack< FEMSigs ... > ) if( params[i]->set ) { params[i]->writeValue( str ); - if( strlen( str ) ) messageWriter( comments , "\t--%s %s\n" , params[i]->name , str ); - else messageWriter( comments , "\t--%s\n" , params[i]->name ); + if( Verbose.set ) + { + if( strlen( str ) ) std::cout << "\t--" << params[i]->name << " " << str << std::endl; + else std::cout << "\t--" << params[i]->name << std::endl; + } } double startTime = Time(); FEMTree< Dim , Real > tree( MEMORY_ALLOCATOR_BLOCK_SIZE ); - FEMTreeProfiler< Dim , Real > profiler( tree ); + Profiler profiler(20); if( Depth.set && Width.value>0 ) { @@ -587,7 +566,7 @@ void Execute( UIntPack< FEMSigs ... > ) // Read in the samples { - profiler.start(); + profiler.reset(); InputPointValueStream *pointValueStream = NULL; InputPointGradientStream *pointGradientStream = NULL; Point< Real , Dim > valueMin , valueMax , gradientMin , gradientMax; @@ -604,7 +583,7 @@ void Execute( UIntPack< FEMSigs ... > ) if ( !strcasecmp( ext , "bnpts" ) ) _pointValueStream = new BinaryInputDataStream< InputSampleValueFactory>( InValues.value , inputSampleValueFactory ); else if( !strcasecmp( ext , "ply" ) ) _pointValueStream = new PLYInputDataStream< InputSampleValueFactory>( InValues.value , inputSampleValueFactory ); else _pointValueStream = new ASCIIInputDataStream< InputSampleValueFactory>( InValues.value , inputSampleValueFactory ); - InputSampleValueType s; + InputSampleValueType s = inputSampleValueFactory(); while( _pointValueStream->next( s ) ) inCorePointsAndValues.push_back( s ); delete _pointValueStream; @@ -619,9 +598,10 @@ void Execute( UIntPack< FEMSigs ... > ) delete[] ext; typename InputSampleValueFactory::Transform _modelToUnitCube( modelToUnitCube ); - auto XFormFunctor = [&]( InputSampleValueType &p ){ p = _modelToUnitCube( p ); }; + auto XFormFunctor = [&]( InputSampleValueType &p ){ _modelToUnitCube.inPlace( p ); }; XInputPointValueStream _pointStream( XFormFunctor , *pointValueStream ); - InputPointStreamInfo< Real , Dim , FunctionValueType >::BoundingBox( _pointStream , valueMin , valueMax ); + FunctionValueType s = functionValueFactory(); + InputPointStreamInfo< Real , Dim , FunctionValueType >::BoundingBox( _pointStream , s , valueMin , valueMax ); } if( GradientWeight.value>0 ) { @@ -633,7 +613,7 @@ void Execute( UIntPack< FEMSigs ... > ) if ( !strcasecmp( ext , "bnpts" ) ) _pointGradientStream = new BinaryInputDataStream< InputSampleGradientFactory>( InGradients.value , inputSampleGradientFactory ); else if( !strcasecmp( ext , "ply" ) ) _pointGradientStream = new PLYInputDataStream< InputSampleGradientFactory>( InGradients.value , inputSampleGradientFactory ); else _pointGradientStream = new ASCIIInputDataStream< InputSampleGradientFactory>( InGradients.value , inputSampleGradientFactory ); - InputSampleGradientType s; + InputSampleGradientType s = inputSampleGradientFactory(); while( _pointGradientStream->next( s ) ) inCorePointsAndGradients.push_back( s ); delete _pointGradientStream; @@ -648,9 +628,10 @@ void Execute( UIntPack< FEMSigs ... > ) delete[] ext; typename InputSampleGradientFactory::Transform _modelToUnitCube( modelToUnitCube ); - auto XFormFunctor = [&]( InputSampleGradientType &p ){ p = _modelToUnitCube( p ); }; + auto XFormFunctor = [&]( InputSampleGradientType &p ){ _modelToUnitCube.inPlace( p ); }; XInputPointGradientStream _pointStream( XFormFunctor , *pointGradientStream ); - InputPointStreamInfo< Real , Dim , FunctionGradientType >::BoundingBox( _pointStream , gradientMin , gradientMax ); + FunctionGradientType s = functionGradientFactory(); + InputPointStreamInfo< Real , Dim , FunctionGradientType >::BoundingBox( _pointStream , s , gradientMin , gradientMax ); } { @@ -686,10 +667,12 @@ void Execute( UIntPack< FEMSigs ... > ) { valueSamples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); typename InputSampleValueFactory::Transform _modelToUnitCube( modelToUnitCube ); - auto XFormFunctor = [&]( InputSampleValueType &p ){ p = _modelToUnitCube( p ); }; + auto XFormFunctor = [&]( InputSampleValueType &p ){ _modelToUnitCube.inPlace( p ); }; XInputPointValueStream _pointStream( XFormFunctor , *pointValueStream ); auto ProcessData = []( const Point< Real , Dim > &p , FunctionValueType &d ){ return (Real)1.; }; - pointValueCount = FEMTreeInitializer< Dim , Real >::template Initialize< FunctionValueType >( tree.spaceRoot() , _pointStream , Depth.value , *valueSamples , *valueSampleData , true , tree.nodeAllocators.size() ? tree.nodeAllocators[0] : NULL , tree.initializer() , ProcessData ); + FunctionValueType zeroGradient = functionValueFactory(); + typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; + pointValueCount = FEMTreeInitializer< Dim , Real >::template Initialize< FunctionValueType >( sid , tree.spaceRoot() , _pointStream , zeroGradient , Depth.value , *valueSamples , *valueSampleData , true , tree.nodeAllocators.size() ? tree.nodeAllocators[0] : NULL , tree.initializer() , ProcessData ); delete pointValueStream; } else pointValueCount = 0; @@ -698,19 +681,24 @@ void Execute( UIntPack< FEMSigs ... > ) { gradientSamples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); typename InputSampleGradientFactory::Transform _modelToUnitCube( modelToUnitCube ); - auto XFormFunctor = [&]( InputSampleGradientType &p ){ p = _modelToUnitCube( p ); }; + auto XFormFunctor = [&]( InputSampleGradientType &p ){ _modelToUnitCube.inPlace( p ); }; XInputPointGradientStream _pointStream( XFormFunctor , *pointGradientStream ); auto ProcessData = []( const Point< Real , Dim > &p , FunctionGradientType &d ){ return (Real)1.; }; - pointGradientCount = FEMTreeInitializer< Dim , Real >::template Initialize< FunctionGradientType >( tree.spaceRoot() , _pointStream , Depth.value , *gradientSamples , *gradientSampleData , true , tree.nodeAllocators.size() ? tree.nodeAllocators[0] : NULL , tree.initializer() , ProcessData ); + FunctionGradientType zeroGradient = functionGradientFactory(); + typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; + pointGradientCount = FEMTreeInitializer< Dim , Real >::template Initialize< FunctionGradientType >( sid , tree.spaceRoot() , _pointStream , zeroGradient , Depth.value , *gradientSamples , *gradientSampleData , true , tree.nodeAllocators.size() ? tree.nodeAllocators[0] : NULL , tree.initializer() , ProcessData ); delete pointGradientStream; } else pointGradientCount = 0; unitCubeToModel = modelToUnitCube.inverse(); - if( valueSamples ) messageWriter( "Input Value Points / Value Samples: %llu / %llu\n" , pointValueCount , (unsigned long long)valueSamples->size() ); - if( gradientSamples ) messageWriter( "Input Gradient Points / Gradient Samples: %llu / %llu\n" , pointGradientCount , (unsigned long long)gradientSamples->size() ); - profiler.dumpOutput2( comments , "# Read input into tree:" ); + if( Verbose.set ) + { + if( valueSamples ) std::cout << "Input Value Points / Value Samples: " << pointValueCount << " / " << valueSamples->size() << std::endl; + if( gradientSamples ) std::cout << "Input Gradient Points / Gradient Samples: " << pointGradientCount << " / " << gradientSamples->size() << std::endl; + std::cout << "# Read input into tree: " << profiler << std::endl; + } } DenseNodeData< Real , Sigs > solution; @@ -725,50 +713,56 @@ void Execute( UIntPack< FEMSigs ... > ) if( ValueWeight.value>0 ) { if( ExactInterpolation.set ) valueInterpolationInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , FunctionValueType , 0 >( tree , *valueSamples , GetPointer( *valueSampleData ) , ConstraintDual< Dim , Real , FunctionValueType >( (Real)ValueWeight.value ) , SystemDual< Dim , Real , FunctionValueType >( (Real)ValueWeight.value ) , true , false ); - else valueInterpolationInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , FunctionValueType , 0 >( tree , *valueSamples , GetPointer( *valueSampleData ) , ConstraintDual< Dim , Real , FunctionValueType >( (Real)ValueWeight.value ) , SystemDual< Dim , Real , FunctionValueType >( (Real)ValueWeight.value ) , true , 1 ); + else valueInterpolationInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , FunctionValueType , 0 >( tree , *valueSamples , GetPointer( *valueSampleData ) , ConstraintDual< Dim , Real , FunctionValueType >( (Real)ValueWeight.value ) , SystemDual< Dim , Real , FunctionValueType >( (Real)ValueWeight.value ) , true , Depth.value , 1 ); } if( GradientWeight.value>0 ) { if( ExactInterpolation.set ) gradientInterpolationInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , FunctionGradientType , 1 >( tree , *gradientSamples , GetPointer( *gradientSampleData ) , ConstraintDual< Dim , Real , FunctionGradientType >( (Real)GradientWeight.value ) , SystemDual< Dim , Real , FunctionGradientType >( (Real)GradientWeight.value ) , true , false ); - else gradientInterpolationInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , FunctionGradientType , 1 >( tree , *gradientSamples , GetPointer( *gradientSampleData ) , ConstraintDual< Dim , Real , FunctionGradientType >( (Real)GradientWeight.value ) , SystemDual< Dim , Real , FunctionGradientType >( (Real)GradientWeight.value ) , true , 1 ); + else gradientInterpolationInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , FunctionGradientType , 1 >( tree , *gradientSamples , GetPointer( *gradientSampleData ) , ConstraintDual< Dim , Real , FunctionGradientType >( (Real)GradientWeight.value ) , SystemDual< Dim , Real , FunctionGradientType >( (Real)GradientWeight.value ) , true , Depth.value , 1 ); } // Prepare for multigrid { - profiler.start(); + profiler.reset(); + + auto addNodeFunctor = [&]( int d , const int off[Dim] ){ return d<=FullDepth.value; }; if( ValueWeight.value>0 && GradientWeight.value>0 ) - tree.template finalizeForMultigrid< Degrees::Max() , Degrees::Max() >( BaseDepth.value , FullDepth.value , []( const FEMTreeNode * ){ return true; } , []( const FEMTreeNode * ){ return false; } , std::make_tuple( valueInterpolationInfo , gradientInterpolationInfo ) ); + tree.template finalizeForMultigrid< Degrees::Max() , Degrees::Max() >( BaseDepth.value , addNodeFunctor , []( const FEMTreeNode * ){ return true; } , std::make_tuple( valueInterpolationInfo , gradientInterpolationInfo ) ); else if( ValueWeight.value>0 ) - tree.template finalizeForMultigrid< Degrees::Max() , Degrees::Max() >( BaseDepth.value , FullDepth.value , []( const FEMTreeNode * ){ return true; } , []( const FEMTreeNode * ){ return false; } , std::make_tuple( valueInterpolationInfo ) ); + tree.template finalizeForMultigrid< Degrees::Max() , Degrees::Max() >( BaseDepth.value , addNodeFunctor , []( const FEMTreeNode * ){ return true; } , std::make_tuple( valueInterpolationInfo ) ); else if( GradientWeight.value>0 ) - tree.template finalizeForMultigrid< Degrees::Max() , Degrees::Max() >( BaseDepth.value , FullDepth.value , []( const FEMTreeNode * ){ return true; } , []( const FEMTreeNode * ){ return false; } , std::make_tuple( gradientInterpolationInfo ) ); - profiler.dumpOutput2( comments , "# Finalized tree:" ); + tree.template finalizeForMultigrid< Degrees::Max() , Degrees::Max() >( BaseDepth.value , addNodeFunctor , []( const FEMTreeNode * ){ return true; } , std::make_tuple( gradientInterpolationInfo ) ); + + if( Verbose.set ) std::cout << "# Finalized tree: " << profiler << std::endl; } // Add the interpolation constraints { - profiler.start(); + profiler.reset(); constraints = tree.initDenseNodeData( Sigs() ); if( ValueWeight.value>0 && GradientWeight.value>0 ) tree.addInterpolationConstraints( constraints , solveDepth , std::make_tuple( valueInterpolationInfo , gradientInterpolationInfo ) ); else if( ValueWeight.value>0 ) tree.addInterpolationConstraints( constraints , solveDepth , std::make_tuple( valueInterpolationInfo ) ); else if( GradientWeight.value>0 ) tree.addInterpolationConstraints( constraints , solveDepth , std::make_tuple( gradientInterpolationInfo ) ); - profiler.dumpOutput2( comments , "#Set point constraints:" ); + if( Verbose.set ) std::cout << "#Set point constraints: " << profiler << std::endl; } - messageWriter( "Leaf Nodes / Active Nodes / Ghost Nodes: %llu / %llu / %llu\n" , (unsigned long long)tree.leaves() , (unsigned long long)tree.nodes() , (unsigned long long)tree.ghostNodes() ); - messageWriter( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage())/(1<<20) ); + if( Verbose.set ) + { + std::cout << "All Nodes / Active Nodes / Ghost Nodes: " << tree.allNodes() << " / " << tree.activeNodes() << " / " << tree.ghostNodes() << std::endl; + std::cout << "Memory Usage: " << float( MemoryInfo::Usage() )/(1<<20) << " MB" << std::endl; + } // Solve the linear system { - profiler.start(); + profiler.reset(); typename FEMTree< Dim , Real >::SolverInfo sInfo; sInfo.cgDepth = 0 , sInfo.cascadic = true , sInfo.vCycles = 1 , sInfo.iters = Iters.value , sInfo.cgAccuracy = CGSolverAccuracy.value , sInfo.verbose = Verbose.set , sInfo.showResidual = ShowResidual.set , sInfo.showGlobalResidual = SHOW_GLOBAL_RESIDUAL_NONE , sInfo.sliceBlockSize = 1; sInfo.baseVCycles = BaseVCycles.value; typename FEMIntegrator::template System< Sigs , IsotropicUIntPack< Dim , 2 > > F( { 0. , (double)LapWeight.value , (double)BiLapWeight.value } ); - if( ValueWeight.value>0 && GradientWeight.value>0 ) solution = tree.solveSystem( Sigs() , F , constraints , SolveDepth.value , sInfo , std::make_tuple( valueInterpolationInfo , gradientInterpolationInfo ) ); - else if( ValueWeight.value>0 ) solution = tree.solveSystem( Sigs() , F , constraints , SolveDepth.value , sInfo , std::make_tuple( valueInterpolationInfo ) ); - else if( GradientWeight.value>0 ) solution = tree.solveSystem( Sigs() , F , constraints , SolveDepth.value , sInfo , std::make_tuple( gradientInterpolationInfo ) ); - profiler.dumpOutput2( comments , "# Linear system solved:" ); + if( ValueWeight.value>0 && GradientWeight.value>0 ) solution = tree.solveSystem( Sigs() , F , constraints , BaseDepth.value , SolveDepth.value , sInfo , std::make_tuple( valueInterpolationInfo , gradientInterpolationInfo ) ); + else if( ValueWeight.value>0 ) solution = tree.solveSystem( Sigs() , F , constraints , BaseDepth.value , SolveDepth.value , sInfo , std::make_tuple( valueInterpolationInfo ) ); + else if( GradientWeight.value>0 ) solution = tree.solveSystem( Sigs() , F , constraints , BaseDepth.value , SolveDepth.value , sInfo , std::make_tuple( gradientInterpolationInfo ) ); + if( Verbose.set ) std::cout << "# Linear system solved: " << profiler << std::endl; delete valueInterpolationInfo , valueInterpolationInfo = NULL; delete gradientInterpolationInfo , gradientInterpolationInfo = NULL; } @@ -796,7 +790,7 @@ void Execute( UIntPack< FEMSigs ... > ) } ); for( unsigned int t=0 ; t ) } ); for( unsigned int t=0 ; t ) { FILE* fp = fopen( Tree.value , "wb" ); if( !fp ) ERROR_OUT( "Failed to open file for writing: " , Tree.value ); - FEMTree< Dim , Real >::WriteParameter( fp ); - DenseNodeData< Real , Sigs >::WriteSignatures( fp ); - tree.write( fp , modelToUnitCube ); - solution.write( fp ); + FileStream fs( fp ); + FEMTree< Dim , Real >::WriteParameter( fs ); + DenseNodeData< Real , Sigs >::WriteSignatures( fs ); + tree.write( fs , modelToUnitCube , false ); + solution.write( fs ); fclose( fp ); } if( Grid.set ) { int res = 0; - profiler.start(); + profiler.reset(); Pointer( Real ) values = tree.template regularGridEvaluate< true >( solution , res , -1 , PrimalGrid.set ); size_t resolution = 1; for( int d=0 ; d voxelToUnitCube = XForm< Real , Dim+1 >::Identity(); if( PrimalGrid.set ) for( int d=0 ; d ) if( Out.set ) { - if( Dim==3 ) + if constexpr ( Dim==3 ) { typedef VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::EmptyFactory< Real > > VertexFactory; std::function< void ( typename VertexFactory::VertexType & , Point< Real , Dim > , Point< Real , Dim > , Real , EmptyVectorType< Real > ) > SetVertex = []( typename VertexFactory::VertexType &v , Point< Real , Dim > p , Point< Real , Dim > , Real , EmptyVectorType< Real > ){ v.template get<0>() = p; }; ExtractMesh( UIntPack< FEMSigs ... >() , tree , solution , (Real)IsoValue.value , VertexFactory() , SetVertex , comments , unitCubeToModel ); } - else if( Dim==2 ) + else if constexpr ( Dim==2 ) { typedef VertexFactory::PositionFactory< Real , 3 > VertexFactory; int res = 0; @@ -895,7 +890,7 @@ void Execute( UIntPack< FEMSigs ... > ) } } - messageWriter( comments , "# Total Solve: %9.1f (s), %9.1f (MB)\n" , Time()-startTime , FEMTree< Dim , Real >::MaxMemoryUsage() ); + if( Verbose.set ) std::cout <<"# Total Solve: " << Time()-startTime << " (s), " << MemoryInfo::PeakMemoryUsageMB() << " (MB)" << std::endl; } #ifndef FAST_COMPILE @@ -928,11 +923,6 @@ void Execute( void ) int main( int argc , char* argv[] ) { Timer timer; -#ifdef USE_SEG_FAULT_HANDLER - WARN( "using seg-fault handler" ); - StackTracer::exec = argv[0]; - signal( SIGSEGV , SignalHandler ); -#endif // USE_SEG_FAULT_HANDLER #ifdef ARRAY_DEBUG WARN( "Array debugging enabled" ); #endif // ARRAY_DEBUG @@ -942,7 +932,6 @@ int main( int argc , char* argv[] ) if( MaxMemoryGB.value>0 ) SetPeakMemoryMB( MaxMemoryGB.value<<10 ); ThreadPool::DefaultChunkSize = ThreadChunkSize.value; ThreadPool::DefaultSchedule = (ThreadPool::ScheduleType)ScheduleType.value; - messageWriter.echoSTDOUT = Verbose.set; if( !InValues.set && !InGradients.set ) { diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index e3d2daa5..de3ce401 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -27,15 +27,7 @@ DAMAGE. */ #include "PreProcessor.h" - -#undef USE_DOUBLE // If enabled, double-precesion is used - -#define DATA_DEGREE 0 // 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 in the normals for constructing the Laplacian constraints -#define DEFAULT_FEM_DEGREE 1 // The default finite-element degree -#define DEFAULT_FEM_BOUNDARY BOUNDARY_NEUMANN // The default finite-element boundary type -#define DEFAULT_DIMENSION 3 // The dimension of the system +#include "PoissonRecon.h" #include #include @@ -50,10 +42,6 @@ DAMAGE. #include "Image.h" #include "RegularGrid.h" -MessageWriter messageWriter; - -const float DefaultPointWeightMultiplier = 2.f; - enum NormalType { NORMALS_NONE , @@ -237,108 +225,6 @@ double Weight( double v , double start , double end ) } } -template< unsigned int Dim , class Real > -struct FEMTreeProfiler -{ - double t; - - void start( void ){ t = Time() , FEMTree< Dim , Real >::ResetLocalMemoryUsage(); } - void print( const char* header ) const - { - FEMTree< Dim , Real >::MemoryUsage(); - if( header ) printf( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %d (MB)\n" , header , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); - else printf( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %d (MB)\n" , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); - } - void dumpOutput( const char* header ) const - { - FEMTree< Dim , Real >::MemoryUsage(); - if( header ) messageWriter( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %d (MB)\n" , header , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); - else messageWriter( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %d (MB)\n" , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); - } - void dumpOutput2( std::vector< std::string >& comments , const char* header ) const - { - FEMTree< Dim , Real >::MemoryUsage(); - if( header ) messageWriter( comments , "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %d (MB)\n" , header , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); - else messageWriter( comments , "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %d (MB)\n" , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); - } -}; - -template< class Real , unsigned int Dim > -XForm< Real , Dim+1 > GetBoundingBoxXForm( Point< Real , Dim > min , Point< Real , Dim > max , Real scaleFactor ) -{ - Point< Real , Dim > center = ( max + min ) / 2; - Real scale = max[0] - min[0]; - for( int d=1 ; d( scale , max[d]-min[d] ); - scale *= scaleFactor; - for( int i=0 ; i tXForm = XForm< Real , Dim+1 >::Identity() , sXForm = XForm< Real , Dim+1 >::Identity(); - for( int i=0 ; i -XForm< Real , Dim+1 > GetBoundingBoxXForm( Point< Real , Dim > min , Point< Real , Dim > max , Real width , Real scaleFactor , int& depth ) -{ - // Get the target resolution (along the largest dimension) - Real resolution = ( max[0]-min[0] ) / width; - for( int d=1 ; d( resolution , ( max[d]-min[d] ) / width ); - resolution *= scaleFactor; - depth = 0; - while( (1< center = ( max + min ) / 2; - Real scale = (1< tXForm = XForm< Real , Dim+1 >::Identity() , sXForm = XForm< Real , Dim+1 >::Identity(); - for( int i=0 ; i -using InputOrientedPointStreamInfo = typename FEMTreeInitializer< Dim , Real >::template InputPointStream< VectorTypeUnion< Real , typename VertexFactory::NormalFactory< Real , Dim >::VertexType , AuxData > >; - -template< typename Real , unsigned int Dim , typename AuxData > -using InputOrientedPointStream = typename InputOrientedPointStreamInfo< Real , Dim , AuxData >::StreamType; - -template< class Real , unsigned int Dim , typename AuxData > -XForm< Real , Dim+1 > GetPointXForm( InputOrientedPointStream< Real , Dim , AuxData > &stream , Real width , Real scaleFactor , int& depth ) -{ - Point< Real , Dim > min , max; - InputOrientedPointStreamInfo< Real , Dim , AuxData >::BoundingBox( stream , min , max ); - return GetBoundingBoxXForm( min , max , width , scaleFactor , depth ); -} -template< class Real , unsigned int Dim , typename AuxData > -XForm< Real , Dim+1 > GetPointXForm( InputOrientedPointStream< Real , Dim , AuxData > &stream , Real scaleFactor ) -{ - Point< Real , Dim > min , max; - InputOrientedPointStreamInfo< Real , Dim , AuxData >::BoundingBox( stream , min , max ); - return GetBoundingBoxXForm( min , max , scaleFactor ); -} - -template< unsigned int Dim , typename Real > -struct ConstraintDual -{ - Real target , weight; - ConstraintDual( Real t , Real w ) : target(t) , weight(w){ } - CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim >& p ) const { return CumulativeDerivativeValues< Real , Dim , 0 >( target*weight ); }; -}; -template< unsigned int Dim , typename Real > -struct SystemDual -{ - Real weight; - SystemDual( Real w ) : weight(w){ } - CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim >& p , const CumulativeDerivativeValues< Real , Dim , 0 >& dValues ) const { return dValues * weight; }; - CumulativeDerivativeValues< double , Dim , 0 > operator()( const Point< Real , Dim >& p , const CumulativeDerivativeValues< double , Dim , 0 >& dValues ) const { return dValues * weight; }; -}; -template< unsigned int Dim > -struct SystemDual< Dim , double > -{ - typedef double Real; - Real weight; - SystemDual( Real w ) : weight(w){ } - CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim >& p , const CumulativeDerivativeValues< Real , Dim , 0 >& dValues ) const { return dValues * weight; }; -}; - template< typename Real , typename SetVertexFunction , typename InputSampleDataType , typename VertexFactory , unsigned int ... FEMSigs > void ExtractMesh ( @@ -363,9 +249,9 @@ void ExtractMesh static const unsigned int DataSig = FEMDegreeAndBType< DATA_DEGREE , BOUNDARY_FREE >::Signature; typedef typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; - FEMTreeProfiler< Dim , Real > profiler; + Profiler profiler(20); - char tempHeader[1024]; + char tempHeader[2048]; { char tempPath[1024]; tempPath[0] = 0; @@ -375,39 +261,43 @@ void ExtractMesh if( tempPath[ strlen( tempPath )-1 ]==FileSeparator ) sprintf( tempHeader , "%sPR_" , tempPath ); else sprintf( tempHeader , "%s%cPR_" , tempPath , FileSeparator ); } - CoredMeshData< Vertex , node_index_type > *mesh; - if( InCore.set ) mesh = new CoredVectorMeshData< Vertex , node_index_type >(); - else mesh = new CoredFileMeshData< node_index_type , VertexFactory >( vertexFactory , tempHeader ); + StreamingMesh< Vertex , node_index_type > *mesh; + if( InCore.set ) mesh = new VectorStreamingMesh< Vertex , node_index_type >(); + else mesh = new FileStreamingMesh< VertexFactory , node_index_type >( vertexFactory , tempHeader ); - profiler.start(); - typename IsoSurfaceExtractor< Dim , Real , Vertex >::IsoStats isoStats; + profiler.reset(); + typename LevelSetExtractor< Dim , Real , Vertex >::Stats stats; if( sampleData ) { SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > _sampleData = tree.template setExtrapolatedDataField< DataSig , false >( *samples , *sampleData , (DensityEstimator*)NULL ); - for( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* n = tree.tree().nextNode() ; n ; n=tree.tree().nextNode( n ) ) + auto nodeFunctor = [&]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *n ) { ProjectiveData< InputSampleDataType , Real >* clr = _sampleData( n ); if( clr ) (*clr) *= (Real)pow( DataX.value , tree.depth( n ) ); - } - isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< InputSampleDataType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , &_sampleData , solution , isoValue , *mesh , zeroInputSampleDataType , SetVertex , !LinearFit.set , Normals.value==NORMALS_GRADIENTS , !NonManifold.set , PolygonMesh.set , false ); + }; + tree.tree().processNodes( nodeFunctor ); + stats = LevelSetExtractor< Dim , Real , Vertex >::template Extract< InputSampleDataType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , &_sampleData , solution , isoValue , *mesh , zeroInputSampleDataType , SetVertex , !LinearFit.set , Normals.value==NORMALS_GRADIENTS , !NonManifold.set , PolygonMesh.set , false ); } #if defined( __GNUC__ ) && __GNUC__ < 5 #ifdef SHOW_WARNINGS #warning "you've got me gcc version<5" #endif // SHOW_WARNINGS - else isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< InputSampleDataType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , (SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > *)NULL , solution , isoValue , *mesh , zeroInputSampleDataType , SetVertex , !LinearFit.set , Normals.value==NORMALS_GRADIENTS , !NonManifold.set , PolygonMesh.set , false ); + else stats = LevelSetExtractor< Dim , Real , Vertex >::template Extract< InputSampleDataType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , (SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > *)NULL , solution , isoValue , *mesh , zeroInputSampleDataType , SetVertex , !LinearFit.set , Normals.value==NORMALS_GRADIENTS , !NonManifold.set , PolygonMesh.set , false ); #else // !__GNUC__ || __GNUC__ >=5 - else isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< InputSampleDataType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , NULL , solution , isoValue , *mesh , zeroInputSampleDataType , SetVertex , !LinearFit.set , Normals.value==NORMALS_GRADIENTS , !NonManifold.set , PolygonMesh.set , false ); + else stats = LevelSetExtractor< Dim , Real , Vertex >::template Extract< InputSampleDataType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , NULL , solution , isoValue , *mesh , zeroInputSampleDataType , SetVertex , !LinearFit.set , Normals.value==NORMALS_GRADIENTS , !NonManifold.set , PolygonMesh.set , false ); #endif // __GNUC__ || __GNUC__ < 4 - messageWriter( "Vertices / Polygons: %llu / %llu\n" , (unsigned long long)( mesh->outOfCoreVertexNum()+mesh->inCoreVertices.size() ) , (unsigned long long)mesh->polygonNum() ); - std::string isoStatsString = isoStats.toString() + std::string( "\n" ); - messageWriter( isoStatsString.c_str() ); - if( PolygonMesh.set ) profiler.dumpOutput2( comments , "# Got polygons:" ); - else profiler.dumpOutput2( comments , "# Got triangles:" ); + if( Verbose.set ) + { + std::cout << "Vertices / Polygons: " << mesh->vertexNum() << " / " << mesh->polygonNum() << std::endl; + std::cout << stats.toString() << std::endl; + if( PolygonMesh.set ) std::cout << "# Got polygons: " << profiler << std::endl; + else std::cout << "# Got triangles: " << profiler << std::endl; + } std::vector< std::string > noComments; typename VertexFactory::Transform unitCubeToModelTransform( unitCubeToModel ); - PLY::WritePolygons< VertexFactory , node_index_type , Real , Dim >( Out.value , vertexFactory , mesh , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , NoComments.set ? noComments : comments , unitCubeToModelTransform ); + auto xForm = [&]( typename VertexFactory::VertexType & v ){ unitCubeToModelTransform.inPlace( v ); }; + PLY::WritePolygons< VertexFactory , node_index_type , Real , Dim >( Out.value , vertexFactory , mesh , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , NoComments.set ? noComments : comments , xForm ); delete mesh; } @@ -515,12 +405,15 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; typedef typename FEMTreeInitializer< Dim , Real >::GeometryNodeType GeometryNodeType; std::vector< std::string > comments; - messageWriter( comments , "*************************************************************\n" ); - messageWriter( comments , "*************************************************************\n" ); - messageWriter( comments , "** Running Screened Poisson Reconstruction (Version %s) **\n" , VERSION ); - messageWriter( comments , "*************************************************************\n" ); - messageWriter( comments , "*************************************************************\n" ); - if( !Threads.set ) messageWriter( comments , "Running with %d threads\n" , Threads.value ); + if( Verbose.set ) + { + std::cout << "*************************************************************" << std::endl; + std::cout << "*************************************************************" << std::endl; + std::cout << "** Running Screened Poisson Reconstruction (Version " << VERSION << ") **" << std::endl; + std::cout << "*************************************************************" << std::endl; + std::cout << "*************************************************************" << std::endl; + if( !Threads.set ) std::cout << "Running with " << Threads.value << " threads" << std::endl; + } bool needNormalData = DataX.value>0 && Normals.value; bool needAuxData = DataX.value>0 && auxDataFactory.bufferSize(); @@ -552,15 +445,16 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) if( params[i]->set ) { params[i]->writeValue( str ); - if( strlen( str ) ) messageWriter( comments , "\t--%s %s\n" , params[i]->name , str ); - else messageWriter( comments , "\t--%s\n" , params[i]->name ); + if( Verbose.set ) + if( strlen( str ) ) std::cout << "\t--" << params[i]->name << " " << str << std::endl; + else std::cout << "\t--" << params[i]->name << std::endl; } double startTime = Time(); Real isoValue = 0; FEMTree< Dim , Real > tree( MEMORY_ALLOCATOR_BLOCK_SIZE ); - FEMTreeProfiler< Dim , Real > profiler; + Profiler profiler(20); if( Depth.set && Width.value>0 ) { @@ -570,7 +464,7 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) size_t pointCount; - Real pointWeightSum; + ProjectiveData< Point< Real , 2 > , Real > pointDepthAndWeight; std::vector< typename FEMTree< Dim , Real >::PointSample >* samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); DenseNodeData< GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > geometryNodeDesignators; std::vector< InputSampleDataType >* sampleData = NULL; @@ -580,7 +474,7 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) // Read in the samples (and color data) { - profiler.start(); + profiler.reset(); InputPointStream* pointStream; char* ext = GetFileExtension( In.value ); sampleData = new std::vector< InputSampleDataType >(); @@ -592,7 +486,7 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) if ( !strcasecmp( ext , "bnpts" ) ) _pointStream = new BinaryInputDataStream< InputSampleFactory >( In.value , inputSampleFactory ); else if( !strcasecmp( ext , "ply" ) ) _pointStream = new PLYInputDataStream< InputSampleFactory >( In.value , inputSampleFactory ); else _pointStream = new ASCIIInputDataStream< InputSampleFactory >( In.value , inputSampleFactory ); - InputSampleType p; + InputSampleType p = inputSampleFactory(); while( _pointStream->next( p ) ) inCorePoints.push_back( p ); delete _pointStream; @@ -607,33 +501,38 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) delete[] ext; typename InputSampleFactory::Transform _modelToUnitCube( modelToUnitCube ); - auto XFormFunctor = [&]( InputSampleType &p ){ p = _modelToUnitCube( p ); }; + auto XFormFunctor = [&]( InputSampleType &p ){ _modelToUnitCube.inPlace( p ); }; XInputPointStream _pointStream( XFormFunctor , *pointStream ); + + { + typename InputSampleDataFactory::VertexType zeroData = inputSampleDataFactory(); + modelToUnitCube = Scale.value>0 ? GetPointXForm< Real , Dim , typename AuxDataFactory::VertexType >( _pointStream , zeroData , (Real)Scale.value ) * modelToUnitCube : modelToUnitCube; + } if( Width.value>0 ) { - modelToUnitCube = GetPointXForm< Real , Dim , typename AuxDataFactory::VertexType >( _pointStream , Width.value , (Real)( Scale.value>0 ? Scale.value : 1. ) , Depth.value ) * modelToUnitCube; - if( !SolveDepth.set ) SolveDepth.value = Depth.value; - if( SolveDepth.value>Depth.value ) - { - WARN( "Solution depth cannot exceed system depth: " , SolveDepth.value , " <= " , Depth.value ); - SolveDepth.value = Depth.value; - } - if( FullDepth.value>Depth.value ) - { - WARN( "Full depth cannot exceed system depth: " , FullDepth.value , " <= " , Depth.value ); - FullDepth.value = Depth.value; - } - if( BaseDepth.value>FullDepth.value ) - { - if( BaseDepth.set ) WARN( "Base depth must be smaller than full depth: " , BaseDepth.value , " <= " , FullDepth.value ); - BaseDepth.value = FullDepth.value; - } + Real maxScale = 0; + for( unsigned int i=0 ; i( maxScale , (Real)1./modelToUnitCube(i,i) ); + Depth.value = (unsigned int)ceil( std::max< double >( 0. , log( maxScale/Width.value )/log(2.) ) ); + } + if( SolveDepth.value>Depth.value ) + { + WARN( "Solution depth cannot exceed system depth: " , SolveDepth.value , " <= " , Depth.value ); + SolveDepth.value = Depth.value; + } + if( FullDepth.value>Depth.value ) + { + WARN( "Full depth cannot exceed system depth: " , FullDepth.value , " <= " , Depth.value ); + FullDepth.value = Depth.value; + } + if( BaseDepth.value>FullDepth.value ) + { + if( BaseDepth.set ) WARN( "Base depth must be smaller than full depth: " , BaseDepth.value , " <= " , FullDepth.value ); + BaseDepth.value = FullDepth.value; } - else modelToUnitCube = Scale.value>0 ? GetPointXForm< Real , Dim , typename AuxDataFactory::VertexType >( _pointStream , (Real)Scale.value ) * modelToUnitCube : modelToUnitCube; { typename InputSampleFactory::Transform _modelToUnitCube( modelToUnitCube ); - auto XFormFunctor = [&]( InputSampleType &p ){ p = _modelToUnitCube( p ); }; + auto XFormFunctor = [&]( InputSampleType &p ){ _modelToUnitCube.inPlace( p ); }; XInputPointStream _pointStream( XFormFunctor , *pointStream ); auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , typename InputPointStreamInfo::DataType &d ) { @@ -648,15 +547,21 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) d.template get<0>() /= l; return (Real)1.; }; - if( Confidence.value>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( tree.spaceRoot() , _pointStream , Depth.value , *samples , *sampleData , true , tree.nodeAllocators[0] , tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( tree.spaceRoot() , _pointStream , Depth.value , *samples , *sampleData , true , tree.nodeAllocators[0] , tree.initializer() , ProcessData ); + + typename InputSampleDataFactory::VertexType zeroData = inputSampleDataFactory(); + typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; + if( Confidence.value>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , tree.spaceRoot() , _pointStream , zeroData , Depth.value , *samples , *sampleData , true , tree.nodeAllocators[0] , tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , tree.spaceRoot() , _pointStream , zeroData , Depth.value , *samples , *sampleData , true , tree.nodeAllocators[0] , tree.initializer() , ProcessData ); } unitCubeToModel = modelToUnitCube.inverse(); delete pointStream; - messageWriter( "Input Points / Samples: %llu / %llu\n" , (unsigned long long)pointCount , (unsigned long long)samples->size() ); - profiler.dumpOutput2( comments , "# Read input into tree:" ); + if( Verbose.set ) + { + std::cout << "Input Points / Samples: " << pointCount << " / " << samples->size() << std::endl; + std::cout << "# Read input into tree: " << profiler << std::endl; + } } DenseNodeData< Real , Sigs > solution; @@ -669,14 +574,14 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) // Get the kernel density estimator { - profiler.start(); + profiler.reset(); density = tree.template setDensityEstimator< 1 , WEIGHT_DEGREE >( *samples , KernelDepth.value , SamplesPerNode.value ); - profiler.dumpOutput2( comments , "# Got kernel density:" ); + if( Verbose.set ) std::cout << "# Got kernel density: " << profiler << std::endl; } // Transform the Hermite samples into a vector field { - profiler.start(); + profiler.reset(); normalInfo = new SparseNodeData< Point< Real , Dim > , NormalSigs >(); std::function< bool ( InputSampleDataType , Point< Real , Dim >& ) > ConversionFunction = []( InputSampleDataType in , Point< Real , Dim > &out ) { @@ -697,33 +602,23 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) bias = (Real)( log( l ) * ConfidenceBias.value / log( 1<<(Dim-1) ) ); return true; }; -#if 1 - if( ConfidenceBias.value>0 ) *normalInfo = tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleData , density , BaseDepth.value , Depth.value , (Real)LowDepthCutOff.value , pointWeightSum , ConversionAndBiasFunction ); - else *normalInfo = tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleData , density , BaseDepth.value , Depth.value , (Real)LowDepthCutOff.value , pointWeightSum , ConversionFunction ); -#else - if( ConfidenceBias.value>0 ) *normalInfo = tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleData , density , 0 , Depth.value , (Real)LowDepthCutOff.value , pointWeightSum , ConversionAndBiasFunction ); - else *normalInfo = tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleData , density , 0 , Depth.value , (Real)LowDepthCutOff.value , pointWeightSum , ConversionFunction ); -#endif + if( ConfidenceBias.value>0 ) *normalInfo = tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleData , density , BaseDepth.value , Depth.value , (Real)LowDepthCutOff.value , pointDepthAndWeight , ConversionAndBiasFunction ); + else *normalInfo = tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleData , density , BaseDepth.value , Depth.value , (Real)LowDepthCutOff.value , pointDepthAndWeight , ConversionFunction ); ThreadPool::Parallel_for( 0 , normalInfo->size() , [&]( unsigned int , size_t i ){ (*normalInfo)[i] *= (Real)-1.; } ); - profiler.dumpOutput2( comments , "# Got normal field:" ); - messageWriter( "Point weight / Estimated Measure: %g / %g\n" , pointWeightSum , pointCount*pointWeightSum ); + if( Verbose.set ) + { + std::cout << "# Got normal field: " << profiler << std::endl; + std::cout << "Point depth / Point weight / Estimated measure: " << pointDepthAndWeight.value()[0] << " / " << pointDepthAndWeight.value()[1] << " / " << pointCount*pointDepthAndWeight.value()[1] << std::endl; + } } // Get the geometry designators indicating if the space node are interior to, exterior to, or contain the envelope boundary if( Envelope.set ) { - profiler.start(); + profiler.reset(); { // Make the octree complete up to the base depth - std::function< void ( FEMTreeNode * , unsigned int ) > MakeComplete = [&]( FEMTreeNode *node , unsigned int depth ) - { - if( node->depth()<(int)depth ) - { - if( !node->children ) node->template initChildren< false >( tree.nodeAllocators.size() ? tree.nodeAllocators[0] : NULL , tree.initializer() ); - for( int c=0 ; c<(1<children+c , depth ); - } - }; - MakeComplete( &tree.spaceRoot() , BaseDepth.value ); + FEMTreeInitializer< Dim , Real >::Initialize( tree.spaceRoot() , BaseDepth.value , []( int , int[] ){ return true; } , tree.nodeAllocators.size() ? tree.nodeAllocators[0] : NULL , tree.initializer() ); // Read in the envelope geometry std::vector< Point< Real , Dim > > vertices; @@ -768,8 +663,12 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) // Get the set of base nodes std::vector< FEMTreeNode * > baseNodes; - auto TerminationLambda = []( const FEMTreeNode *node ){ return node->depth()==BaseDepth.value; }; - for( FEMTreeNode *node=tree.spaceRoot().nextNode( TerminationLambda , NULL ) ; node ; node=tree.spaceRoot().nextNode( TerminationLambda , node ) ) if( node->depth()==BaseDepth.value ) baseNodes.push_back( node ); + auto nodeFunctor = [&]( FEMTreeNode *node ) + { + if( node->depth()==BaseDepth.value ) baseNodes.push_back( node ); + return node->depth() vectorFieldElementCounts( baseNodes.size() ); for( int i=0 ; i , const AuxDataFactory &auxDataFactory ) // In parallel, iterate over the base nodes and mark the nodes containing non-zero vector field coefficients ThreadPool::Parallel_for( 0 , baseNodes.size() , [&]( unsigned int t , size_t i ) { - for( FEMTreeNode *node=baseNodes[i]->nextNode() ; node ; node=baseNodes[i]->nextNode(node) ) + auto nodeFunctor = [&]( FEMTreeNode *node ) { Point< Real , Dim > *n = (*normalInfo)( node ); if( n && Point< Real , Dim >::SquareNorm( *n ) ) isVectorFieldElement[ node->nodeData.nodeIndex ] = true , vectorFieldElementCounts[i]++; - } + }; + baseNodes[i]->processNodes( nodeFunctor ); } ); size_t vectorFieldElementCount = 0; for( int i=0 ; i , const AuxDataFactory &auxDataFactory ) for( int i=0 ; i<_vectorFieldElements.size() ; i++ ) _vectorFieldElements[i].reserve( vectorFieldElementCounts[i] ); ThreadPool::Parallel_for( 0 , baseNodes.size() , [&]( unsigned int t , size_t i ) { - for( FEMTreeNode *node=baseNodes[i]->nextNode() ; node ; node=baseNodes[i]->nextNode(node) ) + auto nodeFunctor = [&]( FEMTreeNode *node ) { if( isVectorFieldElement[ node->nodeData.nodeIndex ] ) _vectorFieldElements[i].push_back( node ); node->nodeData.setScratchFlag( false ); - } + }; + baseNodes[i]->processNodes( nodeFunctor ); } ); for( int i=0 ; i<_vectorFieldElements.size() ; i++ ) vectorFieldElements.insert( vectorFieldElements.end() , _vectorFieldElements[i].begin() , _vectorFieldElements[i].end() ); } @@ -817,7 +718,7 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) FEMTreeInitializer< Dim , Real >::PullGeometryNodeDesignatorsFromFiner( &tree.spaceRoot() , geometryNodeDesignators , BaseDepth.value ); } } - profiler.dumpOutput2( comments , "# Initialized envelope constraints:" ); + if( Verbose.set ) std::cout << "# Initialized envelope constraints: " << profiler << std::endl; } if( !Density.set ) delete density , density = NULL; @@ -826,20 +727,21 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) // Add the interpolation constraints if( PointWeight.value>0 ) { - profiler.start(); - if( ExactInterpolation.set ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointInterpolationInfo< Real , 0 > ( tree , *samples , ConstraintDual< Dim , Real >( targetValue , (Real)PointWeight.value * pointWeightSum ) , SystemDual< Dim , Real >( (Real)PointWeight.value * pointWeightSum ) , true , false ); - else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointInterpolationInfo< Real , 0 > ( tree , *samples , ConstraintDual< Dim , Real >( targetValue , (Real)PointWeight.value * pointWeightSum ) , SystemDual< Dim , Real >( (Real)PointWeight.value * pointWeightSum ) , true , 1 ); - profiler.dumpOutput2( comments , "#Initialized point interpolation constraints:" ); + profiler.reset(); + if( ExactInterpolation.set ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointInterpolationInfo< Real , 0 > ( tree , *samples , ConstraintDual< Dim , Real >( targetValue , (Real)PointWeight.value * pointDepthAndWeight.value()[1] ) , SystemDual< Dim , Real >( (Real)PointWeight.value * pointDepthAndWeight.value()[1] ) , true , false ); + else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointInterpolationInfo< Real , 0 > ( tree , *samples , ConstraintDual< Dim , Real >( targetValue , (Real)PointWeight.value * pointDepthAndWeight.value()[1] ) , SystemDual< Dim , Real >( (Real)PointWeight.value * pointDepthAndWeight.value()[1] ) , true , Depth.value , 1 ); + if( Verbose.set ) std::cout << "#Initialized point interpolation constraints: " << profiler << std::endl; } // Trim the tree and prepare for multigrid { - profiler.start(); + profiler.reset(); constexpr int MAX_DEGREE = NORMAL_DEGREE > Degrees::Max() ? NORMAL_DEGREE : Degrees::Max(); typename FEMTree< Dim , Real >::template HasNormalDataFunctor< NormalSigs > hasNormalDataFunctor( *normalInfo ); auto hasDataFunctor = [&]( const FEMTreeNode *node ){ return hasNormalDataFunctor( node ); }; - if( geometryNodeDesignators.size() ) tree.template finalizeForMultigrid< MAX_DEGREE , Degrees::Max() >( BaseDepth.value , FullDepth.value , hasDataFunctor , [&]( const FEMTreeNode *node ){ return node->nodeData.nodeIndex<(node_index_type)geometryNodeDesignators.size() && geometryNodeDesignators[node]==GeometryNodeType::EXTERIOR; } , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , density , &geometryNodeDesignators ) ); - else tree.template finalizeForMultigrid< MAX_DEGREE , Degrees::Max() >( BaseDepth.value , FullDepth.value , hasDataFunctor , []( const FEMTreeNode * ){ return false; } , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , density ) ); + auto addNodeFunctor = [&]( int d , const int off[Dim] ){ return d<=FullDepth.value; }; + if( geometryNodeDesignators.size() ) tree.template finalizeForMultigridWithDirichlet< MAX_DEGREE , Degrees::Max() >( BaseDepth.value , addNodeFunctor , hasDataFunctor , [&]( const FEMTreeNode *node ){ return node->nodeData.nodeIndex<(node_index_type)geometryNodeDesignators.size() && geometryNodeDesignators[node]==GeometryNodeType::EXTERIOR; } , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , density , &geometryNodeDesignators ) ); + else tree.template finalizeForMultigrid< MAX_DEGREE , Degrees::Max() >( BaseDepth.value , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , density ) ); if( geometryNodeDesignators.size() && EnvelopeGrid.set ) { @@ -850,7 +752,8 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) { int res = 0; DenseNodeData< Real , IsotropicUIntPack< Dim , FEMTrivialSignature > > coefficients = tree.initDenseNodeData( IsotropicUIntPack< Dim , FEMTrivialSignature >() ); - for( const FEMTreeNode* n = tree.spaceRoot().nextNode() ; n ; n=tree.spaceRoot().nextNode( n ) ) + auto nodeFunctor = [&]( const FEMTreeNode *n ) + { if( n->nodeData.nodeIndex!=-1 && ( ( showFinest && !n->children ) || ( !showFinest && geometryNodeDesignators[n->parent]==GeometryNodeType::BOUNDARY ) ) ) { #if 0 // Randomize the colors @@ -864,6 +767,8 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) else if( geometryNodeDesignators[n]==GeometryNodeType::EXTERIOR ) coefficients[n] = (Real)-1.; #endif } + }; + tree.spaceRoot().processNodes( nodeFunctor ); Pointer( Real ) values = tree.template regularGridEvaluate< true >( coefficients , res , -1 , false ); XForm< Real , Dim+1 > voxelToUnitCube = XForm< Real , Dim+1 >::Identity(); for( int d=0 ; d , const AuxDataFactory &auxDataFactory ) WriteEnvelopeGrid( true ); } - profiler.dumpOutput2( comments , "# Finalized tree:" ); + if( Verbose.set ) std::cout << "# Finalized tree: " << profiler << std::endl; } + // Add the FEM constraints { - profiler.start(); + profiler.reset(); constraints = tree.initDenseNodeData( Sigs() ); typename FEMIntegrator::template Constraint< Sigs , IsotropicUIntPack< Dim , 1 > , NormalSigs , IsotropicUIntPack< Dim , 0 > , Dim > F; unsigned int derivatives2[Dim]; @@ -893,7 +799,7 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) F.weights[d][ TensorDerivatives< Derivatives1 >::Index( derivatives1 ) ][ TensorDerivatives< Derivatives2 >::Index( derivatives2 ) ] = 1; } tree.addFEMConstraints( F , *normalInfo , constraints , solveDepth ); - profiler.dumpOutput2( comments , "# Set FEM constraints:" ); + if( Verbose.set ) std::cout << "# Set FEM constraints: " << profiler << std::endl; } // Free up the normal info @@ -902,29 +808,32 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) // Add the interpolation constraints if( PointWeight.value>0 ) { - profiler.start(); + profiler.reset(); tree.addInterpolationConstraints( constraints , solveDepth , std::make_tuple( iInfo ) ); - profiler.dumpOutput2( comments , "#Set point constraints:" ); + if( Verbose.set ) std::cout << "#Set point constraints: " << profiler << std::endl; } - messageWriter( "Leaf Nodes / Active Nodes / Ghost Nodes / Dirichlet Supported Nodes: %llu / %llu / %llu / %llu\n" , (unsigned long long)tree.leaves() , (unsigned long long)tree.nodes() , (unsigned long long)tree.ghostNodes() , (unsigned long long)tree.dirichletElements() ); - messageWriter( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage())/(1<<20) ); + if( Verbose.set ) + { + std::cout << "All Nodes / Active Nodes / Ghost Nodes / Dirichlet Supported Nodes: " << tree.allNodes() << " / " << tree.activeNodes() << " / " << tree.ghostNodes() << " / " << tree.dirichletElements() << std::endl; + std::cout << "Memory Usage: " << float( MemoryInfo::Usage())/(1<<20) << " MB" << std::endl; + } // Solve the linear system { - profiler.start(); + profiler.reset(); typename FEMTree< Dim , Real >::SolverInfo sInfo; sInfo.cgDepth = 0 , sInfo.cascadic = true , sInfo.vCycles = 1 , sInfo.iters = Iters.value , sInfo.cgAccuracy = CGSolverAccuracy.value , sInfo.verbose = Verbose.set , sInfo.showResidual = ShowResidual.set , sInfo.showGlobalResidual = SHOW_GLOBAL_RESIDUAL_NONE , sInfo.sliceBlockSize = 1; sInfo.baseVCycles = BaseVCycles.value; typename FEMIntegrator::template System< Sigs , IsotropicUIntPack< Dim , 1 > > F( { 0. , 1. } ); - solution = tree.solveSystem( Sigs() , F , constraints , SolveDepth.value , sInfo , std::make_tuple( iInfo ) ); - profiler.dumpOutput2( comments , "# Linear system solved:" ); + solution = tree.solveSystem( Sigs() , F , constraints , BaseDepth.value , SolveDepth.value , sInfo , std::make_tuple( iInfo ) ); + if( Verbose.set ) std::cout << "# Linear system solved: " << profiler << std::endl; if( iInfo ) delete iInfo , iInfo = NULL; } } { - profiler.start(); + profiler.reset(); double valueSum = 0 , weightSum = 0; typename FEMTree< Dim , Real >::template MultiThreadedEvaluator< Sigs , 0 > evaluator( &tree , solution ); std::vector< double > valueSums( ThreadPool::NumThreads() , 0 ) , weightSums( ThreadPool::NumThreads() , 0 ); @@ -938,37 +847,42 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) for( size_t t=0 ; t::WriteParameter( fp ); - DenseNodeData< Real , Sigs >::WriteSignatures( fp ); - tree.write( fp , modelToUnitCube ); - solution.write( fp ); + FileStream fs(fp); + FEMTree< Dim , Real >::WriteParameter( fs ); + DenseNodeData< Real , Sigs >::WriteSignatures( fs ); + tree.write( fs , modelToUnitCube , false ); + solution.write( fs ); if( sampleData ) { SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > _sampleData = tree.template setExtrapolatedDataField< DataSig , false >( *samples , *sampleData , (DensityEstimator*)NULL ); - for( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* n = tree.tree().nextNode() ; n ; n=tree.tree().nextNode( n ) ) + auto nodeFunctor = [&]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *n ) { ProjectiveData< InputSampleDataType , Real >* clr = _sampleData( n ); if( clr ) (*clr) *= (Real)pow( DataX.value , tree.depth( n ) ); - } - _sampleData.write( fp ); + }; + tree.tree().processNodes( nodeFunctor ); + _sampleData.write( fs ); } - if( density ) density->write( fp ); + if( density ) density->write( fs ); fclose( fp ); } if( Grid.set ) { int res = 0; - profiler.start(); + profiler.reset(); Pointer( Real ) values = tree.template regularGridEvaluate< true >( solution , res , -1 , PrimalGrid.set ); - profiler.dumpOutput( "Got grid:" ); + if( Verbose.set ) std::cout << "Got grid: " << profiler << std::endl; XForm< Real , Dim+1 > voxelToUnitCube = XForm< Real , Dim+1 >::Identity(); if( PrimalGrid.set ) for( int d=0 ; d , const AuxDataFactory &auxDataFactory ) if( sampleData ){ delete sampleData ; sampleData = NULL; } } if( density ) delete density , density = NULL; - messageWriter( comments , "# Total Solve: %9.1f (s), %9.1f (MB)\n" , Time()-startTime , FEMTree< Dim , Real >::MaxMemoryUsage() ); + if( Verbose.set ) std::cout << "# Total Solve: " << Time()-startTime << " (s), " << MemoryInfo::PeakMemoryUsageMB() << " (MB)" << std::endl; } #ifndef FAST_COMPILE @@ -1064,11 +978,6 @@ void Execute( const AuxDataFactory &auxDataFactory ) int main( int argc , char* argv[] ) { Timer timer; -#ifdef USE_SEG_FAULT_HANDLER - WARN( "using seg-fault handler" ); - StackTracer::exec = argv[0]; - signal( SIGSEGV , SignalHandler ); -#endif // USE_SEG_FAULT_HANDLER #ifdef ARRAY_DEBUG WARN( "Array debugging enabled" ); #endif // ARRAY_DEBUG @@ -1078,7 +987,6 @@ int main( int argc , char* argv[] ) ThreadPool::DefaultSchedule = (ThreadPool::ScheduleType)ScheduleType.value; ThreadPool::Init( (ThreadPool::ParallelType)ParallelType.value , Threads.value ); - messageWriter.echoSTDOUT = Verbose.set; if( !In.set ) { ShowUsage( argv[0] ); diff --git a/Src/PoissonRecon.h b/Src/PoissonRecon.h new file mode 100644 index 00000000..4336f067 --- /dev/null +++ b/Src/PoissonRecon.h @@ -0,0 +1,113 @@ +/* +Copyright (c) 2022, 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 POISSON_RECON_INCLUDED +#define POISSON_RECON_INCLUDED + +#include "FEMTree.h" +#include "VertexFactory.h" + +#undef USE_DOUBLE // If enabled, double-precesion is used + +#define DATA_DEGREE 0 // 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 in the normals for constructing the Laplacian constraints +#define DEFAULT_FEM_DEGREE 1 // The default finite-element degree +#define DEFAULT_FEM_BOUNDARY BOUNDARY_NEUMANN // The default finite-element boundary type +#define DEFAULT_DIMENSION 3 // The dimension of the system + +const float DefaultPointWeightMultiplier = 2.f; + +template< unsigned int Dim , typename Real > +struct ConstraintDual +{ + Real target , weight; + ConstraintDual( void ) : target(0) , weight(0) {} + ConstraintDual( Real t , Real w ) : target(t) , weight(w) {} + CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim >& p ) const { return CumulativeDerivativeValues< Real , Dim , 0 >( target*weight ); }; +}; + +template< unsigned int Dim , typename Real > +struct SystemDual +{ + Real weight; + SystemDual( void ) : weight(0) {} + SystemDual( Real w ) : weight(w) {} + CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim >& p , const CumulativeDerivativeValues< Real , Dim , 0 >& dValues ) const { return dValues * weight; }; + CumulativeDerivativeValues< double , Dim , 0 > operator()( const Point< Real , Dim >& p , const CumulativeDerivativeValues< double , Dim , 0 >& dValues ) const { return dValues * weight; }; +}; + +template< unsigned int Dim > +struct SystemDual< Dim , double > +{ + typedef double Real; + Real weight; + SystemDual( void ) : weight(0) {} + SystemDual( Real w ) : weight(w) {} + CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim >& p , const CumulativeDerivativeValues< Real , Dim , 0 >& dValues ) const { return dValues * weight; }; +}; + +template< typename Real , unsigned int Dim , typename AuxData > +using InputOrientedPointStreamInfo = typename FEMTreeInitializer< Dim , Real >::template InputPointStream< VectorTypeUnion< Real , typename VertexFactory::NormalFactory< Real , Dim >::VertexType , AuxData > >; + +template< typename Real , unsigned int Dim , typename AuxData > +using InputOrientedPointStream = typename InputOrientedPointStreamInfo< Real , Dim , AuxData >::StreamType; + +template< typename Real , unsigned int Dim , typename AuxData > +using OutputOrientedPointStreamInfo = typename FEMTreeInitializer< Dim , Real >::template OutputPointStream< VectorTypeUnion< Real , typename VertexFactory::NormalFactory< Real , Dim >::VertexType , AuxData > >; + +template< typename Real , unsigned int Dim , typename AuxData > +using OutputOrientedPointStream = typename OutputOrientedPointStreamInfo< Real , Dim , AuxData >::StreamType; + +template< class Real , unsigned int Dim > +XForm< Real , Dim+1 > GetBoundingBoxXForm( Point< Real , Dim > min , Point< Real , Dim > max , Real scaleFactor ) +{ + Point< Real , Dim > center = ( max + min ) / 2; + Real scale = max[0] - min[0]; + for( int d=1 ; d( scale , max[d]-min[d] ); + scale *= scaleFactor; + for( int i=0 ; i tXForm = XForm< Real , Dim+1 >::Identity() , sXForm = XForm< Real , Dim+1 >::Identity(); + for( int i=0 ; i(max[maxDim]-min[maxDim]) ) maxDim = i; + XForm< Real , Dim+1 > rXForm; + for( int i=0 ; i +XForm< Real , Dim+1 > GetPointXForm( InputOrientedPointStream< Real , Dim , AuxData > &stream , typename InputOrientedPointStreamInfo< Real , Dim , AuxData >::DataType d , Real scaleFactor ) +{ + Point< Real , Dim > min , max; + InputOrientedPointStreamInfo< Real , Dim , AuxData >::BoundingBox( stream , d , min , max ); + return GetBoundingBoxXForm( min , max , scaleFactor ); +} + +#endif // POISSON_RECON_INCLUDED \ No newline at end of file diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 7bc24927..d9b4c14e 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -35,16 +35,15 @@ DAMAGE. // The executable ChunkPLY can help by partitioning the mesh into more manageable chunks // (each of which is small enough to be represented using 32-bit indexing.) -#undef FAST_COMPILE // If enabled, only a single version of the code is compiled +#define FAST_COMPILE // If enabled, only a single version of the code is compiled #undef SHOW_WARNINGS // Display compilation warnings #undef ARRAY_DEBUG // If enabled, array access is tested for validity -#undef USE_SEG_FAULT_HANDLER // Tries to dump a stack trace in the case of a segfault (gcc only) #ifdef BIG_DATA #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define VERSION "13.8" // The version of the code +#define VERSION "13.99" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file diff --git a/Src/RegularTree.h b/Src/RegularTree.h index 810a1c8c..3412b1bd 100644 --- a/Src/RegularTree.h +++ b/Src/RegularTree.h @@ -37,6 +37,28 @@ DAMAGE. template< unsigned int Dim , class NodeData , class DepthAndOffsetType > struct RegularTreeNode { + // This struct temporarily makes a node appear to be a root node by removing the parent reference + struct SubTreeExtractor + { + SubTreeExtractor( RegularTreeNode &root ) : _root(root) + { + _rootParent = _root.parent; + _root.parent = NULL; + _root.depthAndOffset( _depth , _offset ); + int depth=0 , offset[Dim]; + for( unsigned int d=0 ; d + template< typename KeepNodeFunctor > + void copySubTree( RegularTreeNode &subTree , const KeepNodeFunctor &keepNodeFunctor , Allocator< RegularTreeNode > *nodeAllocator=NULL ) const; + + template< typename KeepNodeFunctor > + Pointer( RegularTreeNode ) serializeSubTree( const KeepNodeFunctor &keepNodeFunctor , size_t &nodeCount ) const; + // The merge functor takes two objects of type NodeData and returns an object of type NodeData // [NOTE] We are assuming that the merge functor is symmetric, f(a,b) = f(b,a), and implicity satisfies f(a) = a template< class MergeFunctor > @@ -114,21 +143,25 @@ struct RegularTreeNode const RegularTreeNode* root( void ) const; - const RegularTreeNode* nextLeaf( const RegularTreeNode* currentLeaf=NULL ) const; - RegularTreeNode* nextLeaf( RegularTreeNode* currentLeaf=NULL ); - - // This lambda takes a RegularTreeNode* as an argument and returns true if we do not need to traverse the tree beyond the specified node. - template< typename NodeTerminationLambda > - const RegularTreeNode* nextNode( NodeTerminationLambda &ntl , const RegularTreeNode* currentNode ) const; - template< typename NodeTerminationLambda > - RegularTreeNode* nextNode( NodeTerminationLambda &ntl , RegularTreeNode* currentNode ); - - const RegularTreeNode* nextNode( const RegularTreeNode* currentNode=NULL ) const; - RegularTreeNode* nextNode( RegularTreeNode* currentNode=NULL ); - const RegularTreeNode* nextBranch( const RegularTreeNode* current ) const; - RegularTreeNode* nextBranch( RegularTreeNode* current ); - const RegularTreeNode* prevBranch( const RegularTreeNode* current ) const; - RegularTreeNode* prevBranch( RegularTreeNode* current ); + /* These functions apply the functor to the node and all descendents, terminating either at a leaf or when the functor returns false. */ + template< typename NodeFunctor /* = std::function< bool/void ( RegularTreeNode * ) > */ > + void processNodes( NodeFunctor nodeFunctor ); + template< typename NodeFunctor /* = std::function< bool/void ( const RegularTreeNode * ) > */ > + void processNodes( NodeFunctor nodeFunctor ) const; + template< typename NodeFunctor /* = std::function< void ( RegularTreeNode * ) > */ > + void processLeaves( NodeFunctor nodeFunctor ); + template< typename NodeFunctor /* = std::function< void ( const RegularTreeNode * ) > */ > + void processLeaves( NodeFunctor nodeFunctor ) const; +protected: + template< typename NodeFunctor /* = std::function< bool/void ( RegularTreeNode * ) > */ > + void _processChildNodes( NodeFunctor &nodeFunctor ); + template< typename NodeFunctor /* = std::function< bool/void ( const RegularTreeNode * ) > */ > + void _processChildNodes( NodeFunctor &nodeFunctor ) const; + template< typename NodeFunctor /* = std::function< bool/void ( RegularTreeNode * ) > */ > + void _processChildLeaves( NodeFunctor &nodeFunctor ); + template< typename NodeFunctor /* = std::function< bool/void ( const RegularTreeNode * ) > */ > + void _processChildLeaves( NodeFunctor &nodeFunctor ) const; +public: void setFullDepth( int maxDepth , Allocator< RegularTreeNode >* nodeAllocator ) { @@ -138,22 +171,25 @@ struct RegularTreeNode template< typename Initializer > void setFullDepth( int maxDepth , Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ); + template< typename PruneChildrenFunctor > + void pruneChildren( const PruneChildrenFunctor pruneFunctor , bool deleteChildren ); + void printLeaves( void ) const; void printRange( void ) const; template< class Real > static int ChildIndex( const Point< Real , Dim >& center , const Point< Real , Dim > &p ); - bool write( const char* fileName ) const; - bool write( FILE* fp ) const; - bool read( const char* fileName , Allocator< RegularTreeNode >* nodeAllocator ) - { - auto initializer = []( RegularTreeNode & ){}; - return read( fileName , nodeAllocator , initializer ); - } - bool read( FILE* fp , Allocator< RegularTreeNode >* nodeAllocator ) + // WriteNodeFunctor looks like std::function< bool ( const RegularTreeNode * ) > + template< typename WriteNodeFunctor > + bool write( BinaryStream &stream , bool serialize , const WriteNodeFunctor &writeNodeFunctor ) const; + bool write( BinaryStream &stream , bool serialize ) const { return write( stream , serialize , []( const RegularTreeNode * ){ return true; } ); } + + template< typename Initializer > + bool read( BinaryStream &stream , Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ); + bool read( BinaryStream &stream , Allocator< RegularTreeNode >* nodeAllocator ) { auto initializer = []( RegularTreeNode & ){}; - return read( fp , nodeAllocator , initializer ); + return read( stream , nodeAllocator , initializer ); } template< typename Initializer > diff --git a/Src/RegularTree.inl b/Src/RegularTree.inl index ee832f81..d6337c4e 100644 --- a/Src/RegularTree.inl +++ b/Src/RegularTree.inl @@ -53,7 +53,7 @@ void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::cleanChildren( bool for( int c=0 ; c<(1< RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::~RegularTreeNode(void) @@ -68,7 +68,7 @@ template< typename Initializer > RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NewBrood( Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ) { RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* brood; - if( nodeAllocator ) brood = nodeAllocator->newElements( 1<newElements( 1<* RegularTreeNode< Dim , N return brood; } template< unsigned int Dim , class NodeData , class DepthAndOffsetType > -void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ResetDepthAndOffset( RegularTreeNode* root , int d , int off[Dim] ) +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ResetDepthAndOffset( RegularTreeNode* root , int depth , int offset[Dim] ) { - std::function< void ( int& , int[Dim] ) > ParentDepthAndOffset = [] ( int& d , int off[Dim] ){ d-- ; for( int _d=0 ; _d>=1 ; }; - std::function< void ( int& , int[Dim] ) > ChildDepthAndOffset = [] ( int& d , int off[Dim] ){ d++ ; for( int _d=0 ; _d _nextBranch = [&]( RegularTreeNode* current , int& d , int off[Dim] ) - { - if( current==root ) return (RegularTreeNode*)NULL; - else - { - int c = (int)( current - current->parent->children ); - - if( c==(1<parent , d , off ); - } - else - { - ParentDepthAndOffset( d , off ) ; ChildDepthAndOffset( d , off ); - for( int _d=0 ; _d>_d ) & 1 ); - return current+1; - } - } - }; - auto _nextNode = [&]( RegularTreeNode* current , int& d , int off[Dim] ) + root->_depth = depth; + for( unsigned int d=0 ; d_offset[d] = offset[d]; + if( root->children ) { - if( !current ) return root; - else if( current->children ) + int _offset[Dim]; + for( unsigned int d=0 ; dchildren; + for( unsigned int d=0 ; d>d) & 1 ); + ResetDepthAndOffset( root->children + c , depth+1 , _offset ); } - else return _nextBranch( current , d , off ); - }; - for( RegularTreeNode* node=_nextNode( NULL , d , off ) ; node ; node = _nextNode( node , d , off ) ) - { - node->_depth = (DepthAndOffsetType)d; - for( int _d=0 ; _d_offset[_d] = (DepthAndOffsetType)off[_d]; } } @@ -131,11 +106,22 @@ void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::setFullDepth( int m } } +template< unsigned int Dim , class NodeData , class DepthAndOffsetType > +template< typename PruneChildrenFunctor > +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::pruneChildren( PruneChildrenFunctor pruneFunctor , bool deleteChildren ) +{ + if( children ) + { + if( pruneFunctor( this ) ) cleanChildren( deleteChildren ); + else for( int i=0 ; i<(1< template< typename Initializer > bool RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::_initChildren( Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ) { - if( nodeAllocator ) children = nodeAllocator->newElements( 1<newElements( 1<::_initChildren_s( Al RegularTreeNode *_children; // Allocate the children - if( nodeAllocator ) _children = nodeAllocator->newElements( 1<newElements( 1<::maxDepthLeaves( i return c; } } + template< unsigned int Dim , class NodeData , class DepthAndOffsetType > const RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::root( void ) const { @@ -303,89 +290,133 @@ const RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* RegularTreeNode< D while( temp->parent ) temp = temp->parent; return temp; } + template< unsigned int Dim , class NodeData , class DepthAndOffsetType > -const RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::nextBranch( const RegularTreeNode* current ) const +template< typename NodeFunctor /* = std::function< bool/void ( RegularTreeNode * ) > */ > +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::processNodes( NodeFunctor nodeFunctor ) { - if( !current->parent || current==this ) return NULL; - if( current-current->parent->children==(1<parent ); - else return current+1; -} -template< unsigned int Dim , class NodeData , class DepthAndOffsetType > -RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::nextBranch(RegularTreeNode* current){ - if( !current->parent || current==this ) return NULL; - if( current-current->parent->children==(1<parent); - else return current+1; + if constexpr( std::is_same< bool , typename std::invoke_result< NodeFunctor , RegularTreeNode * >::type >::value ) + { + if( nodeFunctor( this ) && children ) + for( int c=0 ; c<(1< -const RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::prevBranch( const RegularTreeNode* current ) const +template< typename NodeFunctor /* = std::function< bool/void ( const RegularTreeNode * ) > */ > +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::processNodes( NodeFunctor nodeFunctor ) const { - if( !current->parent || current==this ) return NULL; - if( current-current->parent->children==0 ) return prevBranch( current->parent ); - else return current-1; + if constexpr( std::is_same< bool , typename std::invoke_result< NodeFunctor , RegularTreeNode * >::type >::value ) + { + if( nodeFunctor( this ) && children ) + for( int c=0 ; c<(1< -RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::prevBranch( RegularTreeNode* current ) +template< typename NodeFunctor /* = std::function< void ( RegularTreeNode * ) > */ > +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::processLeaves( NodeFunctor nodeFunctor ) { - if( !current->parent || current==this ) return NULL; - if( current-current->parent->children==0 ) return prevBranch( current->parent ); - else return current-1; -} -template< unsigned int Dim , class NodeData , class DepthAndOffsetType > -const RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::nextLeaf(const RegularTreeNode* current) const{ - if(!current) + if( children ) { - const RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* temp=this; - while( temp->children ) temp = temp->children; - return temp; + for( int c=0 ; c<(1<children ) return current->nextLeaf(); - const RegularTreeNode* temp=nextBranch( current ); - if( !temp ) return NULL; - else return temp->nextLeaf(); + else nodeFunctor( this ); } + template< unsigned int Dim , class NodeData , class DepthAndOffsetType > -RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::nextLeaf(RegularTreeNode* current){ - if( !current ) +template< typename NodeFunctor /* = std::function< void ( const RegularTreeNode * ) > */ > +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::processLeaves( NodeFunctor nodeFunctor ) const +{ + if( children ) { - RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* temp=this; - while( temp->children ) temp = temp->children; - return temp; + for( int c=0 ; c<(1<children ) return current->nextLeaf(); - RegularTreeNode* temp=nextBranch( current) ; - if( !temp ) return NULL; - else return temp->nextLeaf(); + else nodeFunctor( this ); } + template< unsigned int Dim , class NodeData , class DepthAndOffsetType > -template< typename NodeTerminationLambda > -const RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::nextNode( NodeTerminationLambda &ntl , const RegularTreeNode *current ) const +template< typename NodeFunctor /* = std::function< bool/void ( RegularTreeNode * ) > */ > +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::_processChildNodes( NodeFunctor &nodeFunctor ) { - if( !current ) return this; - else if( current->children && !ntl(current) ) return current->children; - else return nextBranch( current ); + if constexpr( std::is_same< bool , typename std::invoke_result< NodeFunctor , RegularTreeNode * >::type >::value ) + { + for( int c=0 ; c<(1< -template< typename NodeTerminationLambda > -RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::nextNode( NodeTerminationLambda &ntl , RegularTreeNode* current ) +template< typename NodeFunctor /* = std::function< bool/void ( const RegularTreeNode * ) > */ > +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::_processChildNodes( NodeFunctor &nodeFunctor ) const { - if( !current ) return this; - else if( current->children && !ntl(current) ) return current->children; - else return nextBranch( current ); + if constexpr( std::is_same< bool , typename std::invoke_result< NodeFunctor , RegularTreeNode * >::type >::value ) + { + for( int c=0 ; c<(1< -const RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::nextNode( const RegularTreeNode* current ) const +template< typename NodeFunctor /* = std::function< void ( RegularTreeNode * ) > */ > +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::_processChildLeaves( NodeFunctor &nodeFunctor ) { - if( !current ) return this; - else if( current->children ) return current->children; - else return nextBranch( current ); + for( int c=0 ; c<(1< -RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::nextNode( RegularTreeNode* current ) +template< typename NodeFunctor /* = std::function< void ( const RegularTreeNode * ) > */ > +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::_processChildLeaves( NodeFunctor &nodeFunctor ) const { - if( !current ) return this; - else if( current->children ) return current->children; - else return nextBranch( current ); + for( int c=0 ; c<(1< @@ -412,45 +443,126 @@ int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ChildIndex( const Po } template< unsigned int Dim , class NodeData , class DepthAndOffsetType > -bool RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::write( const char* fileName ) const +template< typename KeepNodeFunctor > +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::copySubTree( RegularTreeNode< Dim , NodeData , DepthAndOffsetType > &subTree , const KeepNodeFunctor &keepNodeFunctor , Allocator< RegularTreeNode > *nodeAllocator ) const { - FILE* fp=fopen( fileName , "wb" ); - if( !fp ) return false; - bool ret = write(fp); - fclose(fp); - return ret; + bool copyChildren = false; + if( children ) for( unsigned int c=0 ; c<(1<newElements( 1< template< unsigned int Dim , class NodeData , class DepthAndOffsetType > -bool RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::write( FILE* fp ) const +template< typename KeepNodeFunctor > +Pointer( RegularTreeNode< Dim , NodeData , DepthAndOffsetType > ) RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::serializeSubTree( const KeepNodeFunctor &keepNodeFunctor , size_t &nodeCount ) const { - fwrite( this , sizeof( RegularTreeNode< Dim , NodeData , DepthAndOffsetType > ) , 1 , fp ); - if( children ) for( int i=0 ; i<(1< ChildNodeCount = [&]( const RegularTreeNode *node ) + { + size_t count = 0; + bool keepChildren = false; + if( node->children ) for( unsigned int c=0 ; c<(1<children+c ); + if( keepChildren ) + { + count += 1<children+c ); + } + return count; + }; + + nodeCount = 1 + ChildNodeCount( this ); + Pointer( RegularTreeNode ) nodes = NewPointer< RegularTreeNode >( nodeCount ); + + std::function< Pointer( RegularTreeNode ) ( const RegularTreeNode * , RegularTreeNode & , Pointer( RegularTreeNode ) ) > SetChildNodes = [&]( const RegularTreeNode *node , RegularTreeNode &subNode , Pointer( RegularTreeNode ) buffer ) + { + bool keepChildren = false; + if( node->children ) for( unsigned int c=0 ; c<(1<children+c ); + if( keepChildren ) + { + subNode.children = PointerAddress( buffer ); + for( unsigned int c=0 ; c<(1<children[c]; + buffer[c].parent = &subNode; + buffer[c].children = NULL; + } + buffer += 1<children+c , subNode.children[c] , buffer ); + } + return buffer; + }; + + nodes[0] = *this; + nodes[0].parent = NULL; + nodes[0].children = NULL; + + SetChildNodes( this , nodes[0] , nodes+1 ); + + return nodes; } + template< unsigned int Dim , class NodeData , class DepthAndOffsetType > -template< typename Initializer > -bool RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::read( const char* fileName , Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ) +template< typename WriteNodeFunctor > +bool RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::write( BinaryStream &stream , bool serialize , const WriteNodeFunctor &writeNodeFunctor ) const { - FILE* fp = fopen( fileName , "rb" ); - if( !fp ) return false; - bool ret = read( fp , nodeAllocator , initializer ); - fclose( fp ); - return ret; + if( serialize ) + { + size_t nodeCount; + Pointer( RegularTreeNode ) nodes = serializeSubTree( writeNodeFunctor , nodeCount ); + stream.write( nodes , nodeCount ); + DeletePointer( nodes ); + } + else + { + std::function< void ( const RegularTreeNode *node ) > WriteChildren = [&]( const RegularTreeNode *node ) + { + bool writeChildren = false; + if( node->children ) for( unsigned int c=0 ; c<(1<children+c ); + if( writeChildren ) + { + stream.write( GetPointer( node->children , 1<children+c ); + } + }; + stream.write( *this ); + WriteChildren( this ); + } + return true; } + template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< typename Initializer > -bool RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::read( FILE* fp , Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ) +bool RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::read( BinaryStream &stream , Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ) { - if( fread( this , sizeof( RegularTreeNode< Dim , NodeData , DepthAndOffsetType > ) , 1 , fp )!=1 ) ERROR_OUT( "Failed to read node" ); - parent = NULL; - if( children ) + std::function< void ( RegularTreeNode *node ) > ReadChildren = [&]( RegularTreeNode *node ) { - children = NULL; - initChildren< false >( nodeAllocator , initializer ); - for( int i=0 ; i<(1<children ) + { + node->children = NULL; + node->initChildren< false >( nodeAllocator , initializer ); + if( !stream.read( GetPointer( node->children , 1<children[i].parent = node; + ReadChildren( node->children+i ); + } + } + }; + if( !stream.read( *this ) ) ERROR_OUT( "Failed to read root" ); + ReadChildren( this ); return true; } + template< unsigned int Dim , class NodeData , class DepthAndOffsetType > int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::width( int maxDepth ) const { diff --git a/Src/SSDRecon.cpp b/Src/SSDRecon.cpp index d5304e5c..f9240a98 100644 --- a/Src/SSDRecon.cpp +++ b/Src/SSDRecon.cpp @@ -50,8 +50,6 @@ DAMAGE. #include "Image.h" #include "RegularGrid.h" -MessageWriter messageWriter; - double BaseSSDWeights[] = { 5e+1f , 5e-4f , 1e-5f }; enum NormalType @@ -230,32 +228,6 @@ double Weight( double v , double start , double end ) } } -template< unsigned int Dim , class Real > -struct FEMTreeProfiler -{ - double t; - - void start( void ){ t = Time() , FEMTree< Dim , Real >::ResetLocalMemoryUsage(); } - void print( const char* header ) const - { - FEMTree< Dim , Real >::MemoryUsage(); - if( header ) printf( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %d (MB)\n" , header , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); - else printf( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %d (MB)\n" , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); - } - void dumpOutput( const char* header ) const - { - FEMTree< Dim , Real >::MemoryUsage(); - if( header ) messageWriter( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %d (MB)\n" , header , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); - else messageWriter( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %d (MB)\n" , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); - } - void dumpOutput2( std::vector< std::string >& comments , const char* header ) const - { - FEMTree< Dim , Real >::MemoryUsage(); - if( header ) messageWriter( comments , "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %d (MB)\n" , header , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); - else messageWriter( comments , "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %d (MB)\n" , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); - } -}; - template< class Real , unsigned int Dim > XForm< Real , Dim+1 > GetBoundingBoxXForm( Point< Real , Dim > min , Point< Real , Dim > max , Real scaleFactor ) { @@ -268,24 +240,7 @@ XForm< Real , Dim+1 > GetBoundingBoxXForm( Point< Real , Dim > min , Point< Real for( int i=0 ; i -XForm< Real , Dim+1 > GetBoundingBoxXForm( Point< Real , Dim > min , Point< Real , Dim > max , Real width , Real scaleFactor , int& depth ) -{ - // Get the target resolution (along the largest dimension) - Real resolution = ( max[0]-min[0] ) / width; - for( int d=1 ; d( resolution , ( max[d]-min[d] ) / width ); - resolution *= scaleFactor; - depth = 0; - while( (1< center = ( max + min ) / 2; - Real scale = (1< tXForm = XForm< Real , Dim+1 >::Identity() , sXForm = XForm< Real , Dim+1 >::Identity(); - for( int i=0 ; i using InputOrientedPointStreamInfo = typename FEMTreeInitializer< Dim , Real >::template InputPointStream< VectorTypeUnion< Real , typename VertexFactory::NormalFactory< Real , Dim >::VertexType , AuxData > >; @@ -294,17 +249,10 @@ template< typename Real , unsigned int Dim , typename AuxData > using InputOrientedPointStream = typename InputOrientedPointStreamInfo< Real , Dim , AuxData >::StreamType; template< class Real , unsigned int Dim , typename AuxData > -XForm< Real , Dim+1 > GetPointXForm( InputOrientedPointStream< Real , Dim , AuxData > &stream , Real width , Real scaleFactor , int& depth ) -{ - Point< Real , Dim > min , max; - InputOrientedPointStreamInfo< Real , Dim , AuxData >::BoundingBox( stream , min , max ); - return GetBoundingBoxXForm( min , max , width , scaleFactor , depth ); -} -template< class Real , unsigned int Dim , typename AuxData > -XForm< Real , Dim+1 > GetPointXForm( InputOrientedPointStream< Real , Dim , AuxData > &stream , Real scaleFactor ) +XForm< Real , Dim+1 > GetPointXForm( InputOrientedPointStream< Real , Dim , AuxData > &stream , typename InputOrientedPointStreamInfo< Real , Dim , AuxData >::DataType d , Real scaleFactor ) { Point< Real , Dim > min , max; - InputOrientedPointStreamInfo< Real , Dim , AuxData >::BoundingBox( stream , min , max ); + InputOrientedPointStreamInfo< Real , Dim , AuxData >::BoundingBox( stream , d , min , max ); return GetBoundingBoxXForm( min , max , scaleFactor ); } @@ -375,9 +323,9 @@ void ExtractMesh static const unsigned int DataSig = FEMDegreeAndBType< DATA_DEGREE , BOUNDARY_FREE >::Signature; typedef typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; - FEMTreeProfiler< Dim , Real > profiler; + Profiler profiler(20); - char tempHeader[1024]; + char tempHeader[2048]; { char tempPath[1024]; tempPath[0] = 0; @@ -388,39 +336,43 @@ void ExtractMesh else sprintf( tempHeader , "%s%cPR_" , tempPath , FileSeparator ); } - CoredMeshData< Vertex , node_index_type > *mesh; - if( InCore.set ) mesh = new CoredVectorMeshData< Vertex , node_index_type >(); - else mesh = new CoredFileMeshData< node_index_type , VertexFactory >( vertexFactory , tempHeader ); - profiler.start(); - typename IsoSurfaceExtractor< Dim , Real , Vertex >::IsoStats isoStats; + StreamingMesh< Vertex , node_index_type > *mesh; + if( InCore.set ) mesh = new VectorStreamingMesh< Vertex , node_index_type >(); + else mesh = new FileStreamingMesh< VertexFactory , node_index_type >( vertexFactory , tempHeader ); + + profiler.reset(); + typename LevelSetExtractor< Dim , Real , Vertex >::Stats stats; if( sampleData ) { SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > _sampleData = tree.template setExtrapolatedDataField< DataSig , false >( *samples , *sampleData , (DensityEstimator*)NULL ); - for( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* n = tree.tree().nextNode() ; n ; n=tree.tree().nextNode( n ) ) + auto nodeFunctor = [&]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *n ) { ProjectiveData< InputSampleDataType , Real >* clr = _sampleData( n ); if( clr ) (*clr) *= (Real)pow( DataX.value , tree.depth( n ) ); - } - isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< InputSampleDataType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , &_sampleData , solution , isoValue , *mesh , zeroInputSampleDataType , SetVertex , NonLinearFit.set , Normals.value==NORMALS_GRADIENTS , !NonManifold.set , PolygonMesh.set , false ); + }; + tree.tree().processNodes( nodeFunctor ); + stats = LevelSetExtractor< Dim , Real , Vertex >::template Extract< InputSampleDataType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , &_sampleData , solution , isoValue , *mesh , zeroInputSampleDataType , SetVertex , NonLinearFit.set , Normals.value==NORMALS_GRADIENTS , !NonManifold.set , PolygonMesh.set , false ); } #if defined( __GNUC__ ) && __GNUC__ < 5 #ifdef SHOW_WARNINGS #warning "you've got me gcc version<5" #endif // SHOW_WARNINGS - else isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< InputSampleDataType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , (SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > *)NULL , solution , isoValue , *mesh , zeroInputSampleDataType , SetVertex , NonLinearFit.set , Normals.value==NORMALS_GRADIENTS , !NonManifold.set , PolygonMesh.set , false ); + else stats = LevelSetExtractor< Dim , Real , Vertex >::template Extract< InputSampleDataType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , (SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > *)NULL , solution , isoValue , *mesh , zeroInputSampleDataType , SetVertex , NonLinearFit.set , Normals.value==NORMALS_GRADIENTS , !NonManifold.set , PolygonMesh.set , false ); #else // !__GNUC__ || __GNUC__ >=5 - else isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< InputSampleDataType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , NULL , solution , isoValue , *mesh , zeroInputSampleDataType , SetVertex , NonLinearFit.set , Normals.value==NORMALS_GRADIENTS , !NonManifold.set , PolygonMesh.set , false ); + else stats = LevelSetExtractor< Dim , Real , Vertex >::template Extract< InputSampleDataType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , NULL , solution , isoValue , *mesh , zeroInputSampleDataType , SetVertex , NonLinearFit.set , Normals.value==NORMALS_GRADIENTS , !NonManifold.set , PolygonMesh.set , false ); #endif // __GNUC__ || __GNUC__ < 4 - messageWriter( "Vertices / Polygons: %llu / %llu\n" , (unsigned long long)( mesh->outOfCoreVertexNum()+mesh->inCoreVertices.size() ) , (unsigned long long)mesh->polygonNum() ); - - std::string isoStatsString = isoStats.toString() + std::string( "\n" ); - messageWriter( isoStatsString.c_str() ); - if( PolygonMesh.set ) profiler.dumpOutput2( comments , "# Got polygons:" ); - else profiler.dumpOutput2( comments , "# Got triangles:" ); + if( Verbose.set ) + { + std::cout << "Vertices / Polygons: " << mesh->vertexNum() << " / " << mesh->polygonNum() << std::endl; + std::cout << stats.toString() << std::endl; + if( PolygonMesh.set ) std::cout << "# Got polygons: " << profiler << std::endl; + else std::cout << "# Got triangles: " << profiler << std::endl; + } std::vector< std::string > noComments; typename VertexFactory::Transform unitCubeToModelTransform( unitCubeToModel ); - PLY::WritePolygons< VertexFactory , node_index_type , Real , Dim >( Out.value , vertexFactory , mesh , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , NoComments.set ? noComments : comments , unitCubeToModelTransform ); + auto xForm = [&]( typename VertexFactory::VertexType & v ){ unitCubeToModelTransform.inPlace( v ); }; + PLY::WritePolygons< VertexFactory , node_index_type , Real , Dim >( Out.value , vertexFactory , mesh , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , NoComments.set ? noComments : comments , xForm ); delete mesh; } @@ -528,12 +480,15 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; std::vector< std::string > comments; - messageWriter( comments , "************************************************\n" ); - messageWriter( comments , "************************************************\n" ); - messageWriter( comments , "** Running SSD Reconstruction (Version %s) **\n" , VERSION ); - messageWriter( comments , "************************************************\n" ); - messageWriter( comments , "************************************************\n" ); - if( !Threads.set ) messageWriter( comments , "Running with %d threads\n" , Threads.value ); + if( Verbose.set ) + { + std::cout << "************************************************" << std::endl; + std::cout << "************************************************" << std::endl; + std::cout << "** Running SSD Reconstruction (Version " << VERSION << ") **" << std::endl; + std::cout << "************************************************" << std::endl; + std::cout << "************************************************" << std::endl; + if( !Threads.set ) std::cout << "Running with " << Threads.value << " threads" << std::endl; + } bool needNormalData = DataX.value>0 && Normals.value; bool needAuxData = DataX.value>0 && auxDataFactory.bufferSize(); @@ -567,15 +522,18 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) if( params[i]->set ) { params[i]->writeValue( str ); - if( strlen( str ) ) messageWriter( comments , "\t--%s %s\n" , params[i]->name , str ); - else messageWriter( comments , "\t--%s\n" , params[i]->name ); + if( Verbose.set ) + { + if( strlen( str ) ) std::cout << "\t--" << params[i]->name << " " << str << std::endl; + else std::cout << "\t--" << params[i]->name << std::endl; + } } double startTime = Time(); Real isoValue = 0; FEMTree< Dim , Real > tree( MEMORY_ALLOCATOR_BLOCK_SIZE ); - FEMTreeProfiler< Dim , Real > profiler; + Profiler profiler(20); if( Depth.set && Width.value>0 ) { @@ -585,7 +543,7 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) size_t pointCount; - Real pointWeightSum; + ProjectiveData< Point< Real , 2 > , Real > pointDepthAndWeight; std::vector< typename FEMTree< Dim , Real >::PointSample >* samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); std::vector< InputSampleDataType >* sampleData = NULL; DensityEstimator* density = NULL; @@ -594,7 +552,7 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) // Read in the samples (and color data) { - profiler.start(); + profiler.reset(); InputPointStream* pointStream; char* ext = GetFileExtension( In.value ); sampleData = new std::vector< InputSampleDataType >(); @@ -605,7 +563,7 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) if ( !strcasecmp( ext , "bnpts" ) ) _pointStream = new BinaryInputDataStream< InputSampleFactory >( In.value , inputSampleFactory ); else if( !strcasecmp( ext , "ply" ) ) _pointStream = new PLYInputDataStream< InputSampleFactory >( In.value , inputSampleFactory ); else _pointStream = new ASCIIInputDataStream< InputSampleFactory >( In.value , inputSampleFactory ); - InputSampleType p; + InputSampleType p = inputSampleFactory(); while( _pointStream->next( p ) ) inCorePoints.push_back( p ); delete _pointStream; @@ -619,33 +577,38 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) delete[] ext; typename InputSampleFactory::Transform _modelToUnitCube( modelToUnitCube ); - auto XFormFunctor = [&]( InputSampleType &p ){ p = _modelToUnitCube( p ); }; + auto XFormFunctor = [&]( InputSampleType &p ){ _modelToUnitCube.inPlace( p ); }; XInputPointStream _pointStream( XFormFunctor , *pointStream ); + + { + typename InputSampleDataFactory::VertexType zeroData = inputSampleDataFactory(); + modelToUnitCube = Scale.value>0 ? GetPointXForm< Real , Dim , typename AuxDataFactory::VertexType >( _pointStream , zeroData , (Real)Scale.value ) * modelToUnitCube : modelToUnitCube; + } if( Width.value>0 ) { - modelToUnitCube = GetPointXForm< Real , Dim , typename AuxDataFactory::VertexType >( _pointStream , Width.value , (Real)( Scale.value>0 ? Scale.value : 1. ) , Depth.value ) * modelToUnitCube; - if( !SolveDepth.set ) SolveDepth.value = Depth.value; - if( SolveDepth.value>Depth.value ) - { - WARN( "Solution depth cannot exceed system depth: " , SolveDepth.value , " <= " , Depth.value ); - SolveDepth.value = Depth.value; - } - if( FullDepth.value>Depth.value ) - { - WARN( "Full depth cannot exceed system depth: " , FullDepth.value , " <= " , Depth.value ); - FullDepth.value = Depth.value; - } - if( BaseDepth.value>FullDepth.value ) - { - if( BaseDepth.set ) WARN( "Base depth must be smaller than full depth: " , BaseDepth.value , " <= " , FullDepth.value ); - BaseDepth.value = FullDepth.value; - } + Real maxScale = 0; + for( unsigned int i=0 ; i( maxScale , (Real)1./modelToUnitCube(i,i) ); + Depth.value = (unsigned int)ceil( std::max< double >( 0. , log( maxScale/Width.value )/log(2.) ) ); + } + if( SolveDepth.value>Depth.value ) + { + WARN( "Solution depth cannot exceed system depth: " , SolveDepth.value , " <= " , Depth.value ); + SolveDepth.value = Depth.value; + } + if( FullDepth.value>Depth.value ) + { + WARN( "Full depth cannot exceed system depth: " , FullDepth.value , " <= " , Depth.value ); + FullDepth.value = Depth.value; + } + if( BaseDepth.value>FullDepth.value ) + { + if( BaseDepth.set ) WARN( "Base depth must be smaller than full depth: " , BaseDepth.value , " <= " , FullDepth.value ); + BaseDepth.value = FullDepth.value; } - else modelToUnitCube = Scale.value>0 ? GetPointXForm< Real , Dim , typename AuxDataFactory::VertexType >( _pointStream , (Real)Scale.value ) * modelToUnitCube : modelToUnitCube; { typename InputSampleFactory::Transform _modelToUnitCube( modelToUnitCube ); - auto XFormFunctor = [&]( InputSampleType &p ){ p = _modelToUnitCube( p ); }; + auto XFormFunctor = [&]( InputSampleType &p ){ _modelToUnitCube.inPlace( p ); }; XInputPointStream _pointStream( XFormFunctor , *pointStream ); auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , typename InputPointStreamInfo::DataType &d ) { @@ -660,14 +623,19 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) d.template get<0>() /= l; return (Real)1.; }; - if( Confidence.value>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( tree.spaceRoot() , _pointStream , Depth.value , *samples , *sampleData , true , tree.nodeAllocators.size() ? tree.nodeAllocators[0] : NULL , tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( tree.spaceRoot() , _pointStream , Depth.value , *samples , *sampleData , true , tree.nodeAllocators.size() ? tree.nodeAllocators[0] : NULL , tree.initializer() , ProcessData ); + typename InputSampleDataFactory::VertexType zeroData = inputSampleDataFactory(); + typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; + if( Confidence.value>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , tree.spaceRoot() , _pointStream , zeroData , Depth.value , *samples , *sampleData , true , tree.nodeAllocators.size() ? tree.nodeAllocators[0] : NULL , tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , tree.spaceRoot() , _pointStream , zeroData , Depth.value , *samples , *sampleData , true , tree.nodeAllocators.size() ? tree.nodeAllocators[0] : NULL , tree.initializer() , ProcessData ); } unitCubeToModel = modelToUnitCube.inverse(); delete pointStream; - messageWriter( "Input Points / Samples: %llu / %llu\n" , pointCount , (unsigned long long)samples->size() ); - profiler.dumpOutput2( comments , "# Read input into tree:" ); + if( Verbose.set ) + { + std::cout << "Input Points / Samples: " << pointCount << " / " << samples->size() << std::endl; + std::cout << "# Read input into tree: " << profiler << std::endl; + } } int kernelDepth = KernelDepth.set ? KernelDepth.value : Depth.value-2; if( kernelDepth>Depth.value ) @@ -686,14 +654,14 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) // Get the kernel density estimator { - profiler.start(); + profiler.reset(); density = tree.template setDensityEstimator< 1 , WEIGHT_DEGREE >( *samples , kernelDepth , SamplesPerNode.value ); - profiler.dumpOutput2( comments , "# Got kernel density:" ); + if( Verbose.set ) std::cout << "# Got kernel density: " << profiler << std::endl; } // Transform the Hermite samples into a vector field { - profiler.start(); + profiler.reset(); normalInfo = new SparseNodeData< Point< Real , Dim > , NormalSigs >(); std::function< bool ( InputSampleDataType , Point< Real , Dim >& ) > ConversionFunction = []( InputSampleDataType in , Point< Real , Dim > &out ) { @@ -715,10 +683,13 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) return true; }; - if( ConfidenceBias.value>0 ) *normalInfo = tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleData , density , BaseDepth.value , Depth.value , (Real)LowDepthCutOff.value , pointWeightSum , ConversionAndBiasFunction ); - else *normalInfo = tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleData , density , BaseDepth.value , Depth.value , (Real)LowDepthCutOff.value , pointWeightSum , ConversionFunction ); - profiler.dumpOutput2( comments , "# Got normal field:" ); - messageWriter( "Point weight / Estimated Measure: %g / %g\n" , pointWeightSum , pointCount*pointWeightSum ); + if( ConfidenceBias.value>0 ) *normalInfo = tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleData , density , 0 , Depth.value , (Real)LowDepthCutOff.value , pointDepthAndWeight , ConversionAndBiasFunction ); + else *normalInfo = tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleData , density , 0 , Depth.value , (Real)LowDepthCutOff.value , pointDepthAndWeight , ConversionFunction ); + if( Verbose.set ) + { + std::cout << "# Got normal field: " << profiler << std::endl; + std::cout << "Point depth / Point weight / Estimated Measure: " << pointDepthAndWeight.value()[0] << " / " << pointDepthAndWeight.value()[1]<< " / " << pointCount*pointDepthAndWeight.value()[1] << std::endl; + } } if( !Density.set ) delete density , density = NULL; @@ -726,18 +697,21 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) // Add the interpolation constraints if( ValueWeight.value>0 || GradientWeight.value>0 ) { - profiler.start(); - if( ExactInterpolation.set ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , InputSampleDataType , 1 >( tree , *samples , GetPointer( *sampleData ) , ConstraintDual< Dim , Real , InputSampleDataType >( targetValue , (Real)ValueWeight.value * pointWeightSum , (Real)GradientWeight.value * pointWeightSum ) , SystemDual< Dim , Real , InputSampleDataType >( (Real)ValueWeight.value * pointWeightSum , (Real)GradientWeight.value * pointWeightSum ) , true , false ); - else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , InputSampleDataType , 1 >( tree , *samples , GetPointer( *sampleData ) , ConstraintDual< Dim , Real , InputSampleDataType >( targetValue , (Real)ValueWeight.value * pointWeightSum , (Real)GradientWeight.value * pointWeightSum ) , SystemDual< Dim , Real , InputSampleDataType >( (Real)ValueWeight.value * pointWeightSum , (Real)GradientWeight.value * pointWeightSum ) , true , 1 ); - profiler.dumpOutput2( comments , "#Initialized point interpolation constraints:" ); + profiler.reset(); + if( ExactInterpolation.set ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , InputSampleDataType , 1 >( tree , *samples , GetPointer( *sampleData ) , ConstraintDual< Dim , Real , InputSampleDataType >( targetValue , (Real)ValueWeight.value * pointDepthAndWeight.value()[1] , (Real)GradientWeight.value * pointDepthAndWeight.value()[1] ) , SystemDual< Dim , Real , InputSampleDataType >( (Real)ValueWeight.value * pointDepthAndWeight.value()[1] , (Real)GradientWeight.value * pointDepthAndWeight.value()[1] ) , true , false ); + else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , InputSampleDataType , 1 >( tree , *samples , GetPointer( *sampleData ) , ConstraintDual< Dim , Real , InputSampleDataType >( targetValue , (Real)ValueWeight.value * pointDepthAndWeight.value()[1] , (Real)GradientWeight.value * pointDepthAndWeight.value()[1] ) , SystemDual< Dim , Real , InputSampleDataType >( (Real)ValueWeight.value * pointDepthAndWeight.value()[1] , (Real)GradientWeight.value * pointDepthAndWeight.value()[1] ) , true , Depth.value , 1 ); + if( Verbose.set ) std::cout << "#Initialized point interpolation constraints: " << profiler << std::endl; } // Trim the tree and prepare for multigrid { - profiler.start(); + profiler.reset(); + + auto addNodeFunctor = [&]( int d , const int off[Dim] ){ return d<=FullDepth.value; }; constexpr int MAX_DEGREE = NORMAL_DEGREE > Degrees::Max() ? NORMAL_DEGREE : Degrees::Max(); - tree.template finalizeForMultigrid< MAX_DEGREE , Degrees::Max() >( BaseDepth.value , FullDepth.value , typename FEMTree< Dim , Real >::template HasNormalDataFunctor< NormalSigs >( *normalInfo ) , []( const FEMTreeNode * ){ return false; } , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , density ) ); - profiler.dumpOutput2( comments , "# Finalized tree:" ); + tree.template finalizeForMultigrid< MAX_DEGREE , Degrees::Max() >( BaseDepth.value , addNodeFunctor , typename FEMTree< Dim , Real >::template HasNormalDataFunctor< NormalSigs >( *normalInfo ) , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , density ) ); + + if( Verbose.set ) std::cout << "# Finalized tree: " << profiler << std::endl; } // Free up the normal info [If we don't need it for subsequent iterations.] @@ -746,31 +720,34 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) // Add the interpolation constraints if( ValueWeight.value>0 || GradientWeight.value>0 ) { - profiler.start(); + profiler.reset(); constraints = tree.initDenseNodeData( Sigs() ); tree.addInterpolationConstraints( constraints , solveDepth , std::make_tuple( iInfo ) ); - profiler.dumpOutput2( comments , "#Set point constraints:" ); + if( Verbose.set ) std::cout << "#Set point constraints: " << profiler << std::endl; if( !needNormalData && !needAuxData ) delete sampleData , sampleData = NULL; } - messageWriter( "Leaf Nodes / Active Nodes / Ghost Nodes: %llu / %llu / %llu\n" , (unsigned long long)tree.leaves() , (unsigned long long)tree.nodes() , (unsigned long long)tree.ghostNodes() ); - messageWriter( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage())/(1<<20) ); + if( Verbose.set ) + { + std::cout << "All Nodes / Active Nodes / Ghost Nodes: " << tree.allNodes() << " / " << tree.activeNodes() << " / " << tree.ghostNodes() << std::endl; + std::cout << "Memory Usage: " << float( MemoryInfo::Usage())/(1<<20) << std::endl; + } // Solve the linear system { - profiler.start(); + profiler.reset(); typename FEMTree< Dim , Real >::SolverInfo sInfo; sInfo.cgDepth = 0 , sInfo.cascadic = true , sInfo.vCycles = 1 , sInfo.iters = Iters.value , sInfo.cgAccuracy = CGSolverAccuracy.value , sInfo.verbose = Verbose.set , sInfo.showResidual = ShowResidual.set , sInfo.showGlobalResidual = SHOW_GLOBAL_RESIDUAL_NONE , sInfo.sliceBlockSize = 1; sInfo.baseVCycles = BaseVCycles.value; typename FEMIntegrator::template System< Sigs , IsotropicUIntPack< Dim , 2 > > F( { 0. , 0. , (double)BiLapWeight.value } ); - solution = tree.solveSystem( Sigs() , F , constraints , SolveDepth.value , sInfo , std::make_tuple( iInfo ) ); - profiler.dumpOutput2( comments , "# Linear system solved:" ); + solution = tree.solveSystem( Sigs() , F , constraints , BaseDepth.value , SolveDepth.value , sInfo , std::make_tuple( iInfo ) ); + if( Verbose.set ) std::cout << "# Linear system solved: " << profiler << std::endl; if( iInfo ) delete iInfo , iInfo = NULL; } } { - profiler.start(); + profiler.reset(); double valueSum = 0 , weightSum = 0; typename FEMTree< Dim , Real >::template MultiThreadedEvaluator< Sigs , 0 > evaluator( &tree , solution ); std::vector< double > valueSums( ThreadPool::NumThreads() , 0 ) , weightSums( ThreadPool::NumThreads() , 0 ); @@ -784,27 +761,31 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) for( unsigned int t=0 ; t::WriteParameter( fp ); - DenseNodeData< Real , Sigs >::WriteSignatures( fp ); - tree.write( fp , modelToUnitCube ); - solution.write( fp ); + FileStream fs(fp); + FEMTree< Dim , Real >::WriteParameter( fs ); + DenseNodeData< Real , Sigs >::WriteSignatures( fs ); + tree.write( fs , modelToUnitCube , false ); + solution.write( fs ); fclose( fp ); } if( Grid.set ) { int res = 0; - profiler.start(); + profiler.reset(); Pointer( Real ) values = tree.template regularGridEvaluate< true >( solution , res , -1 , PrimalGrid.set ); size_t resolution = 1; - profiler.dumpOutput( "Got grid:" ); + if( Verbose.set ) std::cout << "Got grid: " << profiler << std::endl; XForm< Real , Dim+1 > voxelToUnitCube = XForm< Real , Dim+1 >::Identity(); if( PrimalGrid.set ) for( int d=0 ; d , const AuxDataFactory &auxDataFactory ) if( sampleData ){ delete sampleData ; sampleData = NULL; } } if( density ) delete density , density = NULL; - messageWriter( comments , "# Total Solve: %9.1f (s), %9.1f (MB)\n" , Time()-startTime , FEMTree< Dim , Real >::MaxMemoryUsage() ); + if( Verbose.set ) std::cout << "# Total Solve: " << Time()-startTime << " (s), " << MemoryInfo::PeakMemoryUsageMB() << " (MB)" << std::endl; } #ifndef FAST_COMPILE @@ -900,11 +881,6 @@ void Execute( const AuxDataFactory &auxDataFactory ) int main( int argc , char* argv[] ) { Timer timer; -#ifdef USE_SEG_FAULT_HANDLER - WARN( "using seg-fault handler" ); - StackTracer::exec = argv[0]; - signal( SIGSEGV , SignalHandler ); -#endif // USE_SEG_FAULT_HANDLER #ifdef ARRAY_DEBUG WARN( "Array debugging enabled" ); #endif // ARRAY_DEBUG @@ -913,7 +889,6 @@ int main( int argc , char* argv[] ) if( MaxMemoryGB.value>0 ) SetPeakMemoryMB( MaxMemoryGB.value<<10 ); ThreadPool::DefaultChunkSize = ThreadChunkSize.value; ThreadPool::DefaultSchedule = (ThreadPool::ScheduleType)ScheduleType.value; - messageWriter.echoSTDOUT = Verbose.set; if( !In.set ) { diff --git a/Src/StreamingMesh.h b/Src/StreamingMesh.h new file mode 100644 index 00000000..dbb9215f --- /dev/null +++ b/Src/StreamingMesh.h @@ -0,0 +1,286 @@ +/* +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 STREAMING_MESH_INCLUDED +#define STREAMING_MESH_INCLUDED + +#include "Geometry.h" +#include "MyMiscellany.h" + +template< typename Vertex , typename Index > +class StreamingVertices +{ +public: + virtual void resetIterator( void ) = 0; + virtual Index addVertex( const Vertex &v ) = 0; + virtual bool nextVertex( Vertex &v ) = 0; + virtual size_t vertexNum( void ) const = 0; +}; + +template< class Vertex , typename Index > +class StreamingCurve : public StreamingVertices< Vertex , Index > +{ +public: + virtual void resetIterator( void ) = 0; + virtual void addEdge_s( unsigned int thread , Index v1 , Index v2 ) = 0; + virtual bool nextEdge( std::pair< Index , Index > &e ) = 0; + virtual size_t edgeNum( void ) const = 0; +}; + +template< class Vertex , typename Index > +class StreamingMesh : public StreamingVertices< Vertex , Index > +{ +public: + virtual ~StreamingMesh( void ){} + virtual void resetIterator( void ) = 0; + virtual void addPolygon_s( unsigned int thread , const std::vector< Index >& vertices ) = 0; + virtual bool nextPolygon( std::vector< Index >& vertices ) = 0; + virtual size_t polygonNum( void ) const = 0; +}; + +template< typename Vertex , typename Index > +class VectorStreamingVertices : public StreamingVertices< Vertex , Index > +{ + std::vector< Vertex > _vertices; + Index _vertexIndex; +public: + VectorStreamingVertices( void ); + + void resetIterator( void ); + + Index addVertex( const Vertex &v ); + + bool nextVertex( Vertex &v ); + + size_t vertexNum( void ) const; + + Vertex &vertex( unsigned int idx ){ return _vertices[idx]; } + const Vertex &vertex( unsigned int idx ) const { return _vertices[idx]; } +}; + +template< class Vertex , typename Index > +class VectorStreamingCurve : public StreamingCurve< Vertex , Index > , public VectorStreamingVertices< Vertex , Index > +{ + std::vector< std::vector< std::pair< Index , Index > > > _edges; + unsigned int _threadIndex; + Index _edgeIndex; +public: + VectorStreamingCurve( void ); + + void resetIterator( void ); + + Index addVertex( const Vertex &v ){ return VectorStreamingVertices< Vertex , Index >::addVertex( v ); } + void addEdge_s( unsigned int thread , Index v1 , Index v2 ); + + bool nextVertex( Vertex &v ){ return VectorStreamingVertices< Vertex , Index >::nextVertex(v); } + bool nextEdge( std::pair< Index , Index > &e ); + + size_t vertexNum( void ) const { return VectorStreamingVertices< Vertex , Index >::vertexNum(); } + size_t edgeNum( void ) const; +}; + +template< class Vertex , typename Index > +class VectorStreamingMesh : public StreamingMesh< Vertex , Index > , public VectorStreamingVertices< Vertex , Index > +{ + std::vector< std::vector< std::vector< Index > > > _polygons; + unsigned int _threadIndex; + Index _polygonIndex; +public: + VectorStreamingMesh( void ); + + void resetIterator( void ); + + Index addVertex( const Vertex &v ){ return VectorStreamingVertices< Vertex , Index >::addVertex( v ); } + void addPolygon_s( unsigned int thread , const std::vector< Index >& vertices ); + + bool nextVertex( Vertex &v ){ return VectorStreamingVertices< Vertex , Index >::nextVertex(v); } + bool nextPolygon( std::vector< Index > &vertices ); + + size_t vertexNum( void ) const { return VectorStreamingVertices< Vertex , Index >::vertexNum(); } + size_t polygonNum( void ) const; +}; + +class BufferedReadWriteFile +{ + bool tempFile; + FILE* _fp; + Pointer( char ) _buffer; + char _fileName[2048]; + size_t _bufferIndex , _bufferSize; +public: + BufferedReadWriteFile( const char* fileName=NULL , const char* fileHeader="" , unsigned int bufferSize=(1<<20) ) + { + _bufferIndex = 0; + _bufferSize = bufferSize; + if( fileName ) strcpy( _fileName , fileName ) , tempFile = false , _fp = fopen( _fileName , "w+b" ); + else + { + if( fileHeader && strlen(fileHeader) ) sprintf( _fileName , "%sXXXXXX" , fileHeader ); + else strcpy( _fileName , "XXXXXX" ); +#ifdef _WIN32 + _mktemp( _fileName ); + _fp = fopen( _fileName , "w+b" ); +#else // !_WIN32 + _fp = fdopen( mkstemp( _fileName ) , "w+b" ); +#endif // _WIN32 + tempFile = true; + } + if( !_fp ) ERROR_OUT( "Failed to open file: " , _fileName ); + _buffer = AllocPointer< char >( _bufferSize ); + } + ~BufferedReadWriteFile( void ) + { + FreePointer( _buffer ); + fclose( _fp ); + if( tempFile ) remove( _fileName ); + } + bool write( ConstPointer( char ) data , size_t size ) + { + if( !size ) return true; + ConstPointer( char ) _data = 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 read( Pointer( char ) data , size_t size ) + { + if( !size ) return true; + Pointer( char ) _data = 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; + } + void reset( void ) + { + if( _bufferIndex ) fwrite( _buffer , 1 , _bufferIndex , _fp ); + _bufferIndex = 0; + fseek( _fp , 0 , SEEK_SET ); + _bufferIndex = 0; + _bufferSize = fread( _buffer , 1 , _bufferSize , _fp ); + } +}; + +template< typename VertexFactory , typename Index > +class FileStreamingVertices : public StreamingVertices< typename VertexFactory::VertexType , Index > +{ + BufferedReadWriteFile *_vertexFile; + Index _vertexNum; + const VertexFactory &_factory; + Pointer( char ) _buffer; +public: + using Vertex = typename VertexFactory::VertexType; + FileStreamingVertices( const VertexFactory &vFactory , const char* fileHeader="" ); + ~FileStreamingVertices( void ); + + void resetIterator( void ); + + Index addVertex( const Vertex &v ); + + bool nextVertex( Vertex &v ); + + size_t vertexNum( void ) const; +}; + + +template< typename VertexFactory , typename Index > +class FileStreamingCurve : public StreamingCurve< typename VertexFactory::VertexType , Index > , public FileStreamingVertices< VertexFactory , Index > +{ + std::vector< BufferedReadWriteFile* > _edgeFiles; + unsigned int _threadIndex; +public: + using Vertex = typename VertexFactory::VertexType; + FileStreamingCurve( const char* fileHeader="" ); + ~FileStreamingCurve( void ); + + void resetIterator( void ); + + Index addVertex( const Vertex &v ){ return FileStreamingVertices< VertexFactory , Index >::addVertex( v ); } + void addEdge_s( unsigned int thread , Index v1 , Index v2 ); + + bool nextVertex( Vertex &v ){ return FileStreamingVertices< VertexFactory , Index >::nextVertex(v); } + bool nextEdge( std::pair< Index , Index > &e ); + + size_t vertexNum( void ) const { return FileStreamingVertices< VertexFactory , Index >::vertexNum(); } + size_t edgeNum( void ) const; +}; + +template< typename VertexFactory , typename Index > +class FileStreamingMesh : public StreamingMesh< typename VertexFactory::VertexType , Index > , public FileStreamingVertices< VertexFactory , Index > +{ + std::vector< Index > _polygonNum; + std::vector< BufferedReadWriteFile * > _polygonFiles; + unsigned int _threadIndex; +public: + using Vertex = typename VertexFactory::VertexType; + FileStreamingMesh( const VertexFactory &vFactory , const char* fileHeader="" ); + ~FileStreamingMesh( void ); + + void resetIterator( void ); + + Index addVertex( const Vertex &v ){ return FileStreamingVertices< VertexFactory , Index >::addVertex( v ); } + void addPolygon_s( unsigned int thread , const std::vector< Index >& vertices ); + + bool nextVertex( Vertex &v ) { return FileStreamingVertices< VertexFactory , Index >::nextVertex(v); } + bool nextPolygon( std::vector< Index >& vertices ); + + size_t vertexNum( void ) const { return FileStreamingVertices< VertexFactory , Index >::vertexNum(); } + size_t polygonNum( void ) const; +}; + +#include "StreamingMesh.inl" + +#endif // STREAMING_MESH_INCLUDED diff --git a/Src/StreamingMesh.inl b/Src/StreamingMesh.inl new file mode 100644 index 00000000..4e51ea10 --- /dev/null +++ b/Src/StreamingMesh.inl @@ -0,0 +1,266 @@ +/* +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. +*/ + +///////////////////////////// +// VectorStreamingVertices // +///////////////////////////// +template< typename Vertex , typename Index > +VectorStreamingVertices< Vertex , Index >::VectorStreamingVertices( void ) { _vertexIndex = 0; } + +template< typename Vertex , typename Index > +void VectorStreamingVertices< Vertex , Index >::resetIterator ( void ) { _vertexIndex = 0; } + +template< typename Vertex , typename Index > +Index VectorStreamingVertices< Vertex , Index >::addVertex( const Vertex& p ) +{ + _vertices.push_back(p); + return ( Index )_vertices.size()-1; +} + +template< typename Vertex , typename Index > +bool VectorStreamingVertices< Vertex , Index >::nextVertex( Vertex &p ) +{ + if( _vertexIndex<(Index)_vertices.size() ) + { + p = _vertices[ _vertexIndex++ ]; + return true; + } + else return false; +} + +template< typename Vertex , typename Index > +size_t VectorStreamingVertices< Vertex , Index >::vertexNum( void ) const { return _vertices.size(); } + +////////////////////////// +// VectorStreamingCurve // +////////////////////////// +template< class Vertex , typename Index > +VectorStreamingCurve< Vertex , Index >::VectorStreamingCurve( void ) { _threadIndex = _edgeIndex = 0 ; _edges.resize( std::thread::hardware_concurrency() ); } + +template< class Vertex , typename Index > +void VectorStreamingCurve< Vertex , Index >::resetIterator ( void ) { _threadIndex = _edgeIndex = 0 ; VectorStreamingVertices< Vertex , Index >::resetIterator(); } + + +template< class Vertex , typename Index > +void VectorStreamingCurve< Vertex , Index >::addEdge_s( unsigned int thread , Index v1 , Index v2 ) +{ + _edges[ thread ].push_back( std::make_pair( v1 , v2 ) ); +} + +template< class Vertex , typename Index > +bool VectorStreamingCurve< Vertex , Index >::nextEdge( std::pair< Index , Index > &e ) +{ + while( true ) + { + if( _threadIndex<(int)_edges.size() ) + { + if( _edgeIndex<(Index)( _edges[_threadIndex].size() ) ) + { + e = _edges[_threadIndex][ _edgeIndex++ ]; + return true; + } + else _threadIndex++ , _edgeIndex = 0; + } + else return false; + } +} + +template< class Vertex , typename Index > +size_t VectorStreamingCurve< Vertex , Index >::edgeNum( void ) const +{ + size_t count = 0; + for( size_t i=0 ; i<_edges.size() ; i++ ) count += _edges[i].size(); + return count; +} + +///////////////////////// +// VectorStreamingMesh // +///////////////////////// +template< class Vertex , typename Index > +VectorStreamingMesh< Vertex , Index >::VectorStreamingMesh( void ) { _threadIndex = 0 ; _polygonIndex = 0 ; _polygons.resize( std::thread::hardware_concurrency() ); } + +template< class Vertex , typename Index > +void VectorStreamingMesh< Vertex , Index >::resetIterator ( void ){ _threadIndex = 0 ; _polygonIndex = 0 ; VectorStreamingVertices< Vertex , Index >::resetIterator(); } + +template< class Vertex , typename Index > +void VectorStreamingMesh< Vertex , Index >::addPolygon_s( unsigned int thread , const std::vector< Index >& polygon ) +{ + _polygons[ thread ].push_back( polygon ); +} + +template< class Vertex , typename Index > +bool VectorStreamingMesh< Vertex , Index >::nextPolygon( std::vector< Index >& vertices ) +{ + while( true ) + { + if( _threadIndex<(int)_polygons.size() ) + { + if( _polygonIndex<(Index)( _polygons[_threadIndex].size() ) ) + { + vertices = _polygons[ _threadIndex ][ _polygonIndex++ ]; + return true; + } + else _threadIndex++ , _polygonIndex = 0; + } + else return false; + } +} + +template< class Vertex , typename Index > +size_t VectorStreamingMesh< Vertex , Index >::polygonNum( void ) const +{ + size_t count = 0; + for( size_t i=0 ; i<_polygons.size() ; i++ ) count += _polygons[i].size(); + return count; +} + +/////////////////////// +// FileStreamingMesh // +/////////////////////// +template< typename VertexFactory , typename Index > +FileStreamingVertices< VertexFactory , Index >::FileStreamingVertices( const VertexFactory &factory , const char* fileHeader ) : _factory(factory) +{ + _vertexNum = 0; + + char _fileHeader[1024]; + sprintf( _fileHeader , "%s_points_" , fileHeader ); + _vertexFile = new BufferedReadWriteFile( NULL , _fileHeader ); + _buffer = NewPointer< char >( factory.bufferSize() ); +} + +template< typename VertexFactory , typename Index > +FileStreamingVertices< VertexFactory , Index >::~FileStreamingVertices( void ) +{ + delete _vertexFile; + DeletePointer( _buffer ); +} + +template< typename VertexFactory , typename Index > +void FileStreamingVertices< VertexFactory , Index >::resetIterator( void ) +{ + _vertexFile->reset(); +#if 1 +#ifdef SHOW_WARNINGS +#pragma message( "[WARNING] Why are we not resetting _vertexNum to zero?" ) +#endif // SHOW_WARNINGS +#else + _vertexNum = 0; +#endif +} + +template< typename VertexFactory , typename Index > +Index FileStreamingVertices< VertexFactory , Index >::addVertex( const Vertex &v ) +{ + _factory.toBuffer( v , _buffer ); + _vertexFile->write( _buffer , _factory.bufferSize() ); + return _vertexNum++; +} + +template< typename VertexFactory , typename Index > +bool FileStreamingVertices< VertexFactory , Index >::nextVertex( Vertex &v ) +{ + if( _vertexFile->read( _buffer , _factory.bufferSize() ) ) + { + _factory.fromBuffer( _buffer , v ); + return true; + } + else return false; +} + +template< typename VertexFactory , typename Index > +size_t FileStreamingVertices< VertexFactory , Index >::vertexNum( void ) const { return _vertexNum; } + +/////////////////////// +// FileStreamingMesh // +/////////////////////// +template< typename VertexFactory , typename Index > +FileStreamingMesh< VertexFactory , Index >::FileStreamingMesh( const VertexFactory &factory , const char* fileHeader ) : FileStreamingVertices< VertexFactory , Index >( factory , fileHeader ) +{ + _threadIndex = 0; + _polygonNum.resize( std::thread::hardware_concurrency() ); + for( unsigned int i=0 ; i<_polygonNum.size() ; i++ ) _polygonNum[i] = 0; + + char _fileHeader[1024]; + _polygonFiles.resize( std::thread::hardware_concurrency() ); + for( unsigned int i=0 ; i<_polygonFiles.size() ; i++ ) + { + sprintf( _fileHeader , "%s_polygons_t%d_" , fileHeader , i ); + _polygonFiles[i] = new BufferedReadWriteFile( NULL , _fileHeader ); + } +} + +template< typename VertexFactory , typename Index > +FileStreamingMesh< VertexFactory , Index >::~FileStreamingMesh( void ) +{ + for( unsigned int i=0 ; i<_polygonFiles.size() ; i++ ) delete _polygonFiles[i]; +} + +template< typename VertexFactory , typename Index > +void FileStreamingMesh< VertexFactory , Index >::resetIterator ( void ) +{ + _threadIndex = 0; + for( unsigned int i=0 ; i<_polygonFiles.size() ; i++ ) _polygonFiles[i]->reset(); + FileStreamingVertices< VertexFactory , Index >::resetIterator(); +} + +template< typename VertexFactory , typename Index > +void FileStreamingMesh< VertexFactory , Index >::addPolygon_s( unsigned int thread , const std::vector< Index >& vertices ) +{ + unsigned int vSize = (unsigned int)vertices.size(); + _polygonFiles[thread]->write( ( ConstPointer( char ) )GetPointer( vSize ), sizeof(unsigned int) ); + _polygonFiles[thread]->write( ( ConstPointer( char ) )GetPointer( vertices ) , sizeof(Index) * vSize ); + _polygonNum[thread]++; +} + +template< typename VertexFactory , typename Index > +bool FileStreamingMesh< VertexFactory , Index >::nextPolygon( std::vector< Index > &vertices ) +{ + while( true ) + { + if( _threadIndex<(unsigned int)_polygonFiles.size() ) + { + unsigned int pSize; + if( _polygonFiles[ _threadIndex ]->read( ( Pointer( char ) )GetPointer( pSize ) , sizeof(unsigned int) ) ) + { + vertices.resize( pSize ); + if( _polygonFiles[ _threadIndex ]->read( ( Pointer( char ) )GetPointer( vertices ) , sizeof(Index)*pSize ) ) return true; + ERROR_OUT( "Failed to read polygon from file" ); + } + else _threadIndex++; + } + else return false; + } +} + +template< typename VertexFactory , typename Index > +size_t FileStreamingMesh< VertexFactory , Index >::polygonNum( void ) const +{ + size_t count = 0; + for( size_t i=0 ; i<_polygonNum.size() ; i++ ) count += _polygonNum[i]; + return count; +} diff --git a/Src/Streams.h b/Src/Streams.h new file mode 100644 index 00000000..ada40c9c --- /dev/null +++ b/Src/Streams.h @@ -0,0 +1,158 @@ +/* +Copyright (c) 2022, 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 STREAMS_INCLUDED +#define STREAMS_INCLUDED + +#include "Array.h" + +////////////////// +// BinaryStream // +////////////////// +struct BinaryStream +{ + size_t ioBytes; + BinaryStream( void ) : ioBytes(0) {} + + template< typename C > bool read( C &c ){ return __read( ( Pointer( unsigned char ) )GetPointer( c ) , sizeof(C) ); } + template< typename C > bool write( const C &c ){ return __write( ( ConstPointer( unsigned char ) )GetPointer( c ) , sizeof(C) ); } + template< typename C > bool write( C &c ){ return __write( ( ConstPointer( unsigned char ) )GetPointer( c ) , sizeof(C) ); } + template< typename C > bool read( Pointer( C ) c , size_t sz ){ return __read( ( Pointer( unsigned char ) )c , sizeof(C)*sz ); } + template< typename C > bool write( ConstPointer( C ) c , size_t sz ){ return __write( ( ConstPointer( unsigned char ) )c , sizeof(C)*sz ); } + template< typename C > bool write( Pointer( C ) c , size_t sz ){ return __write( ( ConstPointer( unsigned char ) )c , sizeof(C)*sz ); } + + template< typename C > + bool read( std::vector< std::vector< C > > &c ) + { + size_t sz; + if( !read( sz ) ) return false; + c.resize( sz ); + bool ret = true; + for( size_t i=0 ; i + bool read( std::vector< C > &c ) + { + size_t sz; + if( !read( sz ) ) return false; + c.resize( sz ); + if( sz ) return read( GetPointer( c ) , sz ); + else return true; + } + + template< typename C > + bool write( const std::vector< std::vector< C > > &c ) + { + size_t sz = c.size(); + if( !write( sz ) ) return false; + bool ret = true; + for( size_t i=0 ; i + bool write( const std::vector< C > &c ) + { + size_t sz = c.size(); + if( !write( sz ) ) return false; + if( sz ) return write( GetPointer( c ) , sz ); + else return true; + } + + template< typename C > + bool write( std::vector< std::vector< C > > &c ) + { + size_t sz = c.size(); + if( !write( sz ) ) return false; + bool ret = true; + for( size_t i=0 ; i + bool write( std::vector< C > &c ) + { + size_t sz = c.size(); + if( !write( sz ) ) return false; + if( sz ) return write( GetPointer( c ) , sz ); + else return true; + } + + bool read( std::string &str ) + { + size_t sz; + if( !read( sz ) ) return false; + char *_str = new char[sz+1]; + bool ret = read( GetPointer( _str , sz+1 ) , sz+1 ); + if( ret ) str = std::string( _str ); + delete[] _str; + return ret; + } + + bool write( const std::string &str ) + { + size_t sz = strlen( str.c_str() ); + if( !write( sz ) ) return false; + return write( GetPointer( str.c_str() , sz+1 ) , sz+1 ); + } + + bool write( std::string &str ) + { + size_t sz = strlen( str.c_str() ); + if( !write( sz ) ) return false; + return write( GetPointer( str.c_str() , sz+1 ) , sz+1 ); + } +protected: + virtual bool _read( Pointer( unsigned char ) ptr , size_t sz ) = 0; + virtual bool _write( ConstPointer( unsigned char ) ptr , size_t sz ) = 0; + bool _write( Pointer( unsigned char ) ptr , size_t sz ){ return _write( ( ConstPointer( unsigned char ) )ptr , sz ); } + bool __read( Pointer( unsigned char ) ptr , size_t sz ){ ioBytes += sz ; return _read( ptr , sz ); } + bool __write( ConstPointer( unsigned char ) ptr , size_t sz ){ ioBytes += sz ; return _write( ptr , sz ); } + bool __write( Pointer( unsigned char ) ptr , size_t sz ){ ioBytes += sz ; return _write( ( ConstPointer( unsigned char ) )ptr , sz ); } +}; + +struct FileStream : public BinaryStream +{ + FileStream( FILE *fp ) : _fp(fp){} + void reset( void ){ std::rewind( _fp ); } +protected: + FILE *_fp; + bool _read( Pointer( unsigned char ) ptr , size_t sz ){ return fread( ptr , sizeof(unsigned char) , sz , _fp )==sz; } + bool _write( ConstPointer( unsigned char ) ptr , size_t sz ){ return fwrite( ptr , sizeof(unsigned char) , sz , _fp )==sz; } +}; + +template< typename C > +struct Serializer +{ + virtual size_t size( void ) const = 0; + virtual void serialize( const C & , Pointer( char ) buffer ) const = 0; + virtual void deserialize( ConstPointer( char ) buffer , C & ) const = 0; +}; + +#endif // STREAMS_INCLUDED diff --git a/Src/SurfaceTrimmer.cpp b/Src/SurfaceTrimmer.cpp index 15a684bb..69d89c3a 100644 --- a/Src/SurfaceTrimmer.cpp +++ b/Src/SurfaceTrimmer.cpp @@ -44,9 +44,6 @@ DAMAGE. #include "Ply.h" #include "VertexFactory.h" -MessageWriter messageWriter; - - cmdLineParameter< char* > In( "in" ) , Out( "out" ); @@ -176,6 +173,14 @@ struct ComponentGraph template< typename Real , unsigned int Dim , typename ... AuxData > using ValuedPointData = VectorTypeUnion< Real , Point< Real , Dim > , Real , AuxData ... >; +template< typename Index > +size_t BoostHash( Index i1 , Index i2 ) +{ + size_t hash = (size_t)i1 + 0x9e3779b9; + hash ^= (size_t)i2 + 0x9e3779b9 + (hash<<6) + (hash>>2); + return hash; +} + template< typename Index > struct EdgeKey { @@ -186,11 +191,7 @@ struct EdgeKey else key1 = k2 , key2 = k1; } bool operator == ( const EdgeKey &key ) const { return key1==key.key1 && key2==key.key2; } -#if 1 - struct Hasher{ size_t operator()( const EdgeKey &key ) const { return (size_t)( key.key1 * key.key2 ); } }; -#else - struct Hasher{ size_t operator()( const EdgeKey &key ) const { return key.key1 ^ key.key2; } }; -#endif + struct Hasher{ size_t operator()( const EdgeKey &key ) const { return BoostHash(key.key1,key.key2); } }; }; template< typename Index > @@ -200,11 +201,7 @@ struct HalfEdgeKey HalfEdgeKey( Index k1=0 , Index k2=0 ) : key1(k1) , key2(k2) {} HalfEdgeKey opposite( void ) const { return HalfEdgeKey( key2 , key1 ); } bool operator == ( const HalfEdgeKey &key ) const { return key1==key.key1 && key2==key.key2; } -#if 1 - struct Hasher{ size_t operator()( const HalfEdgeKey &key ) const { return (size_t)( key.key1 * key.key2 ); } }; -#else - struct Hasher{ size_t operator()( const HalfEdgeKey &key ) const { return key.key1 ^ key.key2; } }; -#endif + struct Hasher{ size_t operator()( const HalfEdgeKey &key ) const { return BoostHash(key.key1,key.key2); } }; }; template< typename Real , unsigned int Dim , typename ... AuxData > @@ -440,18 +437,24 @@ int Execute( AuxDataFactories ... auxDataFactories ) std::vector< std::vector< Index > > ltPolygons , gtPolygons; std::vector< bool > ltFlags , gtFlags; - messageWriter( comments , "*********************************************\n" ); - messageWriter( comments , "*********************************************\n" ); - messageWriter( comments , "** Running Surface Trimmer (Version %s) **\n" , VERSION ); - messageWriter( comments , "*********************************************\n" ); - messageWriter( comments , "*********************************************\n" ); + if( Verbose.set ) + { + std::cout << "*********************************************" << std::endl; + std::cout << "*********************************************" << std::endl; + std::cout << "** Running Surface Trimmer (Version " << VERSION << ") **" << std::endl; + std::cout << "*********************************************" << std::endl; + std::cout << "*********************************************" << std::endl; + } char str[1024]; for( int i=0 ; params[i] ; i++ ) if( params[i]->set ) { params[i]->writeValue( str ); - if( strlen( str ) ) messageWriter( comments , "\t--%s %s\n" , params[i]->name , str ); - else messageWriter( comments , "\t--%s\n" , params[i]->name ); + if( Verbose.set ) + { + if( strlen( str ) ) std::cout << "\t--" << params[i]->name << " " << str << std::endl; + else std::cout << "\t--" << params[i]->name << std::endl; + } } if( Verbose.set ) printf( "Value Range: [%f,%f]\n" , min , max ); @@ -488,7 +491,7 @@ int Execute( AuxDataFactories ... auxDataFactories ) // Compute the connectivity // A map identifying half-edges along the boundaries of components and associating them with the component - std::unordered_map< HalfEdgeKey< Index > , size_t , typename HalfEdgeKey< Index >::Hasher > componentBoundaryHalfEdges; + std::unordered_map< HalfEdgeKey< Index > , Index , typename HalfEdgeKey< Index >::Hasher > componentBoundaryHalfEdges; for( unsigned int i=0 ; i<_components.size() ; i++ ) { // All the half-edges for a given component @@ -507,7 +510,7 @@ int Execute( AuxDataFactories ... auxDataFactories ) { HalfEdgeKey< Index > key = *iter; HalfEdgeKey< Index > _key = key.opposite(); - if( componentHalfEdges.find( _key )==componentHalfEdges.end() ) componentBoundaryHalfEdges[ key ] = i; + if( componentHalfEdges.find( _key )==componentHalfEdges.end() ) componentBoundaryHalfEdges[ key ] = (Index)i; } } @@ -576,7 +579,6 @@ int Execute( AuxDataFactories ... auxDataFactories ) RemoveHangingVertices( vertices , gtPolygons ); char comment[1024]; sprintf( comment , "#Trimmed In: %9.1f (s)" , Time()-t ); - comments.push_back( comment ); if( Out.set ) PLY::WritePolygons( Out.value , factory , vertices , gtPolygons , ASCII.set ? PLY_ASCII : ft , comments ); return EXIT_SUCCESS; @@ -584,7 +586,6 @@ int Execute( AuxDataFactories ... auxDataFactories ) int main( int argc , char* argv[] ) { cmdLineParse( argc-1 , &argv[1] , params ); - messageWriter.echoSTDOUT = Verbose.set; if( !In.set || !Trim.set ) { diff --git a/Src/VertexFactory.h b/Src/VertexFactory.h index 676b8fd2..f8a126e8 100644 --- a/Src/VertexFactory.h +++ b/Src/VertexFactory.h @@ -29,6 +29,7 @@ DAMAGE. #define VERTEX_FACTORY_INCLUDED #include "Ply.h" +#include "Array.h" namespace VertexFactory { @@ -88,8 +89,8 @@ namespace VertexFactory virtual void writeBinary( FILE *fp , const VertexType &dt ) const = 0; virtual size_t bufferSize( void ) const = 0; - virtual void toBuffer( const VertexType &dt , char *buffer ) const = 0; - virtual void fromBuffer( const char *buffer , VertexType &dt ) const = 0; + virtual void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const = 0; + virtual void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const = 0; virtual bool isStaticallyAllocated( void ) const = 0; virtual PlyProperty plyStaticReadProperty( unsigned int idx ) const = 0; @@ -109,7 +110,7 @@ namespace VertexFactory { Transform( void ){} template< typename X > Transform( X ){} - VertexType operator()( VertexType dt ) const { return dt; } + void inPlace( VertexType &dt ) const {} }; VertexType operator()( void ) const { return VertexType(); } @@ -129,8 +130,8 @@ namespace VertexFactory PlyProperty plyStaticWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ) ; return PlyProperty(); } size_t bufferSize( void ) const { return 0; } - void toBuffer( const VertexType &dt , char *buffer ) const {} - void fromBuffer( const char* buffer , VertexType &dt ) const {} + void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const {} + void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const {} bool operator == ( const EmptyFactory &factory ) const { return true; } @@ -147,7 +148,7 @@ namespace VertexFactory Transform( void ){ _xForm = XForm< Real , Dim+1 >::Identity(); } Transform( XForm< Real , Dim > xForm ){ _xForm = XForm< Real , Dim+1 >::Identity() ; for( int i=0 ; i xForm ) : _xForm(xForm) {} - VertexType operator()( VertexType dt ) const { return _xForm * dt; } + void inPlace( VertexType &dt ) const { dt = _xForm * dt; } protected: XForm< Real , Dim+1 > _xForm; }; @@ -160,23 +161,32 @@ namespace VertexFactory PlyProperty plyReadProperty( unsigned int idx ) const; PlyProperty plyWriteProperty( unsigned int idx ) const; bool readASCII( FILE *fp , VertexType &dt ) const { return VertexIO< Real >:: ReadASCII( fp , _typeOnDisk , Dim , &dt[0] ); } - bool readBinary( FILE *fp , VertexType &dt ) const { return VertexIO< Real >::ReadBinary( fp , _typeOnDisk , Dim , &dt[0] ); } void writeASCII( FILE *fp , const VertexType &dt ) const { VertexIO< Real >:: WriteASCII( fp , _typeOnDisk , Dim , &dt[0] ); } - void writeBinary( FILE *fp , const VertexType &dt ) const { VertexIO< Real >::WriteBinary( fp , _typeOnDisk , Dim , &dt[0] ); } - + bool readBinary( FILE *fp , VertexType &dt ) const + { + if( _realTypeOnDisk ) return fread( &dt[0] , sizeof(Real) , Dim , fp )==Dim; + else return VertexIO< Real >::ReadBinary( fp , _typeOnDisk , Dim , &dt[0] ); + } + void writeBinary( FILE *fp , const VertexType &dt ) const + { + if( _realTypeOnDisk ) fwrite( &dt[0] , sizeof(Real) , Dim , fp ); + else VertexIO< Real >::WriteBinary( fp , _typeOnDisk , Dim , &dt[0] ); + } bool isStaticallyAllocated( void ) const{ return true; } + PlyProperty plyStaticReadProperty( unsigned int idx ) const; PlyProperty plyStaticWriteProperty( unsigned int idx ) const; - PositionFactory( TypeOnDisk typeOnDisk=GetTypeOnDisk< Real >() ) : _typeOnDisk( typeOnDisk ) {} + PositionFactory( TypeOnDisk typeOnDisk=GetTypeOnDisk< Real >() ) : _typeOnDisk( typeOnDisk ) { _realTypeOnDisk = GetTypeOnDisk< Real >()==_typeOnDisk; } size_t bufferSize( void ) const { return sizeof( VertexType ); } - void toBuffer( const VertexType &dt , char *buffer ) const { *( (VertexType*)buffer ) = dt; } - void fromBuffer( const char *buffer , VertexType &dt ) const { dt = *( (VertexType*)buffer ); } + void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { memcpy( buffer , &dt , sizeof( VertexType ) ); } + void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const { memcpy( &dt , buffer , sizeof( VertexType ) ); } bool operator == ( const PositionFactory &factory ) const { return _typeOnDisk==factory._typeOnDisk; } protected: TypeOnDisk _typeOnDisk; + bool _realTypeOnDisk; static const std::string _PlyNames[]; }; @@ -195,7 +205,7 @@ namespace VertexFactory for( int i=0 ; i _xForm; }; @@ -208,23 +218,32 @@ namespace VertexFactory PlyProperty plyReadProperty( unsigned int idx ) const; PlyProperty plyWriteProperty( unsigned int idx ) const; bool readASCII( FILE *fp , VertexType &dt ) const { return VertexIO< Real >:: ReadASCII( fp , _typeOnDisk , Dim , &dt[0] ); } - bool readBinary( FILE *fp , VertexType &dt ) const { return VertexIO< Real >::ReadBinary( fp , _typeOnDisk , Dim , &dt[0] ); } void writeASCII( FILE *fp , const VertexType &dt ) const { VertexIO< Real >:: WriteASCII( fp , _typeOnDisk , Dim , &dt[0] ); } - void writeBinary( FILE *fp , const VertexType &dt ) const { VertexIO< Real >::WriteBinary( fp , _typeOnDisk , Dim , &dt[0] ); } + bool readBinary( FILE *fp , VertexType &dt ) const + { + if( _realTypeOnDisk ) return fread( &dt[0] , sizeof(Real) , Dim , fp )==Dim; + else return VertexIO< Real >::ReadBinary( fp , _typeOnDisk , Dim , &dt[0] ); + } + void writeBinary( FILE *fp , const VertexType &dt ) const + { + if( _realTypeOnDisk ) fwrite( &dt[0] , sizeof(Real) , Dim , fp ); + else VertexIO< Real >::WriteBinary( fp , _typeOnDisk , Dim , &dt[0] ); + } bool isStaticallyAllocated( void ) const{ return true; } PlyProperty plyStaticReadProperty( unsigned int idx ) const; PlyProperty plyStaticWriteProperty( unsigned int idx ) const; - NormalFactory( TypeOnDisk typeOnDisk=GetTypeOnDisk< Real >() ) : _typeOnDisk( typeOnDisk ) {} + NormalFactory( TypeOnDisk typeOnDisk=GetTypeOnDisk< Real >() ) : _typeOnDisk( typeOnDisk ) { _realTypeOnDisk = GetTypeOnDisk< Real >()==_typeOnDisk; } size_t bufferSize( void ) const { return sizeof( VertexType ); } - void toBuffer( const VertexType &dt , char *buffer ) const { *( (VertexType*)buffer ) = dt; } - void fromBuffer( const char *buffer , VertexType &dt ) const { dt = *( (VertexType*)buffer ); } + void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { memcpy( buffer , &dt , sizeof( VertexType ) ); } + void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const { memcpy( &dt , buffer , sizeof( VertexType ) ); } bool operator == ( const NormalFactory &factory ) const { return _typeOnDisk==factory._typeOnDisk; } protected: TypeOnDisk _typeOnDisk; + bool _realTypeOnDisk; static const std::string _PlyNames[]; }; @@ -238,7 +257,7 @@ namespace VertexFactory { Transform( void ){} template< typename XForm > Transform( XForm xForm ){} - VertexType operator()( VertexType dt ) const { return dt; } + void inPlace( VertexType &dt ) const {} }; VertexType operator()( void ) const { return VertexType(); } @@ -249,23 +268,33 @@ namespace VertexFactory PlyProperty plyReadProperty( unsigned int idx ) const; PlyProperty plyWriteProperty( unsigned int idx ) const; bool readASCII( FILE *fp , VertexType &dt ) const { return VertexIO< Real >:: ReadASCII( fp , _typeOnDisk , Dim , &dt[0] ); } - bool readBinary( FILE *fp , VertexType &dt ) const { return VertexIO< Real >::ReadBinary( fp , _typeOnDisk , Dim , &dt[0] ); } void writeASCII( FILE *fp , const VertexType &dt ) const { VertexIO< Real >:: WriteASCII( fp , _typeOnDisk , Dim , &dt[0] ); } - void writeBinary( FILE *fp , const VertexType &dt ) const { VertexIO< Real >::WriteBinary( fp , _typeOnDisk , Dim , &dt[0] ); } + bool readBinary( FILE *fp , VertexType &dt ) const + { + if( _realTypeOnDisk ) return fread( &dt[0] , sizeof(Real) , Dim , fp )==Dim; + else return VertexIO< Real >::ReadBinary( fp , _typeOnDisk , Dim , &dt[0] ); + } + void writeBinary( FILE *fp , const VertexType &dt ) const + { + if( _realTypeOnDisk ) fwrite( &dt[0] , sizeof(Real) , Dim , fp ); + VertexIO< Real >::WriteBinary( fp , _typeOnDisk , Dim , &dt[0] ); + } bool isStaticallyAllocated( void ) const{ return true; } PlyProperty plyStaticReadProperty( unsigned int idx ) const; PlyProperty plyStaticWriteProperty( unsigned int idx ) const; - TextureFactory( TypeOnDisk typeOnDisk=GetTypeOnDisk< Real >() ) : _typeOnDisk( typeOnDisk ) {} + TextureFactory( TypeOnDisk typeOnDisk=GetTypeOnDisk< Real >() ) : _typeOnDisk( typeOnDisk ) { _realTypeOnDisk = GetTypeOnDisk< Real >()==_typeOnDisk; } + size_t bufferSize( void ) const { return sizeof( VertexType ); } - void toBuffer( const VertexType &dt , char *buffer ) const { *( (VertexType*)buffer ) = dt; } - void fromBuffer( const char *buffer , VertexType &dt ) const { dt = *( (VertexType*)buffer ); } + void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { memcpy( buffer , &dt , sizeof( VertexType ) ); } + void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const { memcpy( &dt , buffer , sizeof( VertexType ) ); } bool operator == ( const TextureFactory &factory ) const { return _typeOnDisk==factory._typeOnDisk; } protected: TypeOnDisk _typeOnDisk; + bool _realTypeOnDisk; static const std::string _PlyNames[]; }; @@ -279,7 +308,7 @@ namespace VertexFactory { Transform( void ){} template< typename XForm > Transform( XForm xForm ){} - VertexType operator()( VertexType dt ) const { return dt; } + void inPlace( VertexType &dt ) const {} }; VertexType operator()( void ) const { return VertexType(); } @@ -290,22 +319,32 @@ namespace VertexFactory PlyProperty plyReadProperty( unsigned int idx ) const; PlyProperty plyWriteProperty( unsigned int idx ) const; bool readASCII( FILE *fp , VertexType &dt ) const { return VertexIO< Real >:: ReadASCII( fp , _typeOnDisk , 3 , &dt[0] ); } - bool readBinary( FILE *fp , VertexType &dt ) const { return VertexIO< Real >::ReadBinary( fp , _typeOnDisk , 3 , &dt[0] ); } void writeASCII( FILE *fp , const VertexType &dt ) const { VertexIO< Real >:: WriteASCII( fp , _typeOnDisk , 3 , &dt[0] ); } - void writeBinary( FILE *fp , const VertexType &dt ) const { VertexIO< Real >::WriteBinary( fp , _typeOnDisk , 3 , &dt[0] ); } + bool readBinary( FILE *fp , VertexType &dt ) const + { + if( _realTypeOnDisk ) return fread( &dt[0] , sizeof(Real) , 3 , fp )==3; + else return VertexIO< Real >::ReadBinary( fp , _typeOnDisk , 3 , &dt[0] ); + } + void writeBinary( FILE *fp , const VertexType &dt ) const + { + if( _realTypeOnDisk ) fwrite( &dt[0] , sizeof(Real) , 3 , fp ); + VertexIO< Real >::WriteBinary( fp , _typeOnDisk , 3 , &dt[0] ); + } bool isStaticallyAllocated( void ) const{ return true; } PlyProperty plyStaticReadProperty( unsigned int idx ) const; PlyProperty plyStaticWriteProperty( unsigned int idx ) const; - RGBColorFactory( TypeOnDisk typeOnDisk=GetTypeOnDisk< unsigned char >() ) : _typeOnDisk( typeOnDisk ) {} + RGBColorFactory( TypeOnDisk typeOnDisk=GetTypeOnDisk< unsigned char >() ) : _typeOnDisk( typeOnDisk ) { _realTypeOnDisk = GetTypeOnDisk< Real >()==_typeOnDisk; } + size_t bufferSize( void ) const { return sizeof( VertexType ); } - void toBuffer( const VertexType &dt , char *buffer ) const { *( (VertexType*)buffer ) = dt; } - void fromBuffer( const char *buffer , VertexType &dt ) const { dt = *( (VertexType*)buffer ); } + void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { memcpy( buffer , &dt , sizeof( VertexType ) ); } + void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const { memcpy( &dt , buffer , sizeof( VertexType ) ); } bool operator == ( const RGBColorFactory &factory ) const { return _typeOnDisk==factory._typeOnDisk; } protected: TypeOnDisk _typeOnDisk; + bool _realTypeOnDisk; static const std::string _PlyNames[]; }; @@ -319,7 +358,7 @@ namespace VertexFactory { Transform( void ){} template< typename XForm > Transform( XForm xForm ){} - VertexType operator()( VertexType dt ) const { return dt; } + void inPlace( VertexType &dt ) const {} }; VertexType operator()( void ) const { return VertexType(); } @@ -330,22 +369,31 @@ namespace VertexFactory PlyProperty plyReadProperty( unsigned int idx ) const; PlyProperty plyWriteProperty( unsigned int idx ) const; bool readASCII( FILE *fp , VertexType &dt ) const { return VertexIO< Real >:: ReadASCII( fp , _typeOnDisk , 4 , &dt[0] ); } - bool readBinary( FILE *fp , VertexType &dt ) const { return VertexIO< Real >::ReadBinary( fp , _typeOnDisk , 4 , &dt[0] ); } void writeASCII( FILE *fp , const VertexType &dt ) const { VertexIO< Real >:: WriteASCII( fp , _typeOnDisk , 4 , &dt[0] ); } - void writeBinary( FILE *fp , const VertexType &dt ) const { VertexIO< Real >::WriteBinary( fp , _typeOnDisk , 4 , &dt[0] ); } + bool readBinary( FILE *fp , VertexType &dt ) const + { + if( _realTypeOnDisk ) return fread( &dt[0] , sizeof(Real) , 4 , fp )==4; + else return VertexIO< Real >::ReadBinary( fp , _typeOnDisk , 4 , &dt[0] ); + } + void writeBinary( FILE *fp , const VertexType &dt ) const + { + if( _realTypeOnDisk ) fwrite( &dt[0] , sizeof(Real) , 4 , fp ); + VertexIO< Real >::WriteBinary( fp , _typeOnDisk , 4 , &dt[0] ); + } bool isStaticallyAllocated( void ) const{ return true; } PlyProperty plyStaticReadProperty( unsigned int idx ) const; PlyProperty plyStaticWriteProperty( unsigned int idx ) const; - RGBAColorFactory( TypeOnDisk typeOnDisk=GetTypeOnDisk< unsigned char >() ) : _typeOnDisk( typeOnDisk ) {} + RGBAColorFactory( TypeOnDisk typeOnDisk=GetTypeOnDisk< unsigned char >() ) : _typeOnDisk( typeOnDisk ) { _realTypeOnDisk = GetTypeOnDisk< Real >()==_typeOnDisk; } size_t bufferSize( void ) const { return sizeof( VertexType ); } - void toBuffer( const VertexType &dt , char *buffer ) const { *( (VertexType*)buffer ) = dt; } - void fromBuffer( const char *buffer , VertexType &dt ) const { dt = *( (VertexType*)buffer ); } + void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { memcpy( buffer , &dt , sizeof( VertexType ) ); } + void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const { memcpy( &dt , buffer , sizeof( VertexType ) ); } bool operator == ( const RGBAColorFactory &factory ) const { return _typeOnDisk==factory._typeOnDisk; } protected: TypeOnDisk _typeOnDisk; + bool _realTypeOnDisk; static const std::string _PlyNames[]; }; @@ -359,7 +407,7 @@ namespace VertexFactory { Transform( void ){} template< typename XForm > Transform( XForm xForm ){} - VertexType operator()( VertexType dt ) const { return dt; } + void inPlace( VertexType &dt ) const {} }; VertexType operator()( void ) const { return (Real)0; } @@ -370,22 +418,32 @@ namespace VertexFactory PlyProperty plyReadProperty( unsigned int idx ) const; PlyProperty plyWriteProperty( unsigned int idx ) const; bool readASCII( FILE *fp , VertexType &dt ) const { return VertexIO< Real >:: ReadASCII( fp , _typeOnDisk , 1 , &dt ); } - bool readBinary( FILE *fp , VertexType &dt ) const { return VertexIO< Real >::ReadBinary( fp , _typeOnDisk , 1 , &dt ); } void writeASCII( FILE *fp , const VertexType &dt ) const { VertexIO< Real >:: WriteASCII( fp , _typeOnDisk , 1 , &dt ); } - void writeBinary( FILE *fp , const VertexType &dt ) const { VertexIO< Real >::WriteBinary( fp , _typeOnDisk , 1 , &dt ); } + bool readBinary( FILE *fp , VertexType &dt ) const + { + if( _realTypeOnDisk ) return fread( &dt , sizeof(Real) , 1 , fp )==1; + else return VertexIO< Real >::ReadBinary( fp , _typeOnDisk , 1 , &dt ); + } + void writeBinary( FILE *fp , const VertexType &dt ) const + { + if( _realTypeOnDisk ) fwrite( &dt , sizeof(Real) , 1 , fp ); + else VertexIO< Real >::WriteBinary( fp , _typeOnDisk , 1 , &dt ); + } bool isStaticallyAllocated( void ) const{ return true; } PlyProperty plyStaticReadProperty( unsigned int idx ) const; PlyProperty plyStaticWriteProperty( unsigned int idx ) const; - ValueFactory( TypeOnDisk typeOnDisk=GetTypeOnDisk< Real >() ) : _typeOnDisk( typeOnDisk ) {} + ValueFactory( TypeOnDisk typeOnDisk=GetTypeOnDisk< Real >() ) : _typeOnDisk( typeOnDisk ) { _realTypeOnDisk = GetTypeOnDisk< Real >()==_typeOnDisk; } + size_t bufferSize( void ) const { return sizeof( VertexType ); } - void toBuffer( const VertexType &dt , char *buffer ) const { *( (VertexType*)buffer ) = dt; } - void fromBuffer( const char *buffer , VertexType &dt ) const { dt = *( (VertexType*)buffer ); } + void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { memcpy( buffer , &dt , sizeof( VertexType ) ); } + void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const { memcpy( &dt , buffer , sizeof( VertexType ) ); } bool operator == ( const ValueFactory &factory ) const { return _typeOnDisk==factory._typeOnDisk; } protected: TypeOnDisk _typeOnDisk; + bool _realTypeOnDisk; static const std::string _PlyNames[]; }; @@ -399,7 +457,7 @@ namespace VertexFactory { Transform( void ){} template< typename XForm > Transform( XForm xForm ){} - VertexType operator()( VertexType dt ) const { return dt; } + void inPlace( VertexType &dt ) const {} }; VertexType operator()( void ) const { return Point< Real >( _namesAndTypesOnDisk.size() ); } @@ -423,11 +481,12 @@ namespace VertexFactory DynamicFactory( const std::vector< std::pair< std::string , TypeOnDisk > > &namesAndTypesOnDisk ); DynamicFactory( const std::vector< PlyProperty > &plyProperties ); size_t bufferSize( void ) const { return sizeof(Real) * _namesAndTypesOnDisk.size(); } - void toBuffer( const VertexType &dt , char *buffer ) const { for( size_t i=0 ; i<_namesAndTypesOnDisk.size() ; i++ ) ( (Real*)buffer )[i] = dt[i]; } - void fromBuffer( const char *buffer , VertexType &dt ) const { for( size_t i=0 ; i<_namesAndTypesOnDisk.size() ; i++ ) dt[i] = ( (const Real*)buffer )[i]; } + void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { for( size_t i=0 ; i<_namesAndTypesOnDisk.size() ; i++ ) ( ( Pointer(Real) )(buffer) )[i] = dt[i]; } + void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const { for( size_t i=0 ; i<_namesAndTypesOnDisk.size() ; i++ ) dt[i] = ( ( ConstPointer( Real ) )(buffer) )[i]; } bool operator == ( const DynamicFactory &factory ) const; protected: + bool _realTypeOnDisk; std::vector< std::pair< std::string , TypeOnDisk > > _namesAndTypesOnDisk; }; @@ -451,7 +510,7 @@ namespace VertexFactory Transform( void ){} template< typename XForm > Transform( XForm xForm ){ _set<0>( xForm ); } - VertexType operator()( VertexType in ) const { VertexType out ; _xForm< 0 >( in , out ) ; return out; } + void inPlace( VertexType &dt ) const { _inPlace< 0 >( dt ); } template< unsigned int I > using TransformType = typename std::tuple_element< I , _TransformTuple >::type; template< unsigned int I > TransformType< I >& get( void ) { return std::get< I >( _transformTuple ); } @@ -460,8 +519,8 @@ namespace VertexFactory _TransformTuple _transformTuple; template< unsigned int I , typename XForm > typename std::enable_if< I!=sizeof...(Factories) >::type _set( XForm xForm ){ this->template get() = xForm ; _set< I+1 >( xForm ); } template< unsigned int I , typename XForm > typename std::enable_if< I==sizeof...(Factories) >::type _set( XForm xForm ){} - template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) >::type _xForm( const VertexType &in , VertexType &out ) const { out.template get() = this->template get()( in.template get() ) ; _xForm< I+1 >( in , out ); } - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) >::type _xForm( const VertexType &in , VertexType &out ) const {} + template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) >::type _inPlace( VertexType &dt ) const { this->template get().inPlace( dt.template get() ) ; _inPlace< I+1 >( dt ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) >::type _inPlace( VertexType &dt ) const {} }; Factory( void ){} @@ -485,8 +544,8 @@ namespace VertexFactory PlyProperty plyStaticWriteProperty( unsigned int idx ) const { return _plyStaticWriteProperty<0>( idx ); } size_t bufferSize( void ) const { return _bufferSize<0>(); } - void toBuffer( const VertexType &dt , char *buffer ) const { _toBuffer<0>( dt , buffer ); } - void fromBuffer( const char *buffer , VertexType &dt ) const { _fromBuffer<0>( buffer , dt ); } + void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { _toBuffer<0>( dt , buffer ); } + void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const { _fromBuffer<0>( buffer , dt ); } bool operator == ( const Factory &factory ) const { return _equal<0>( factory ); } protected: @@ -529,10 +588,10 @@ namespace VertexFactory template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , size_t >::type _bufferSize( void ) const { return this->template get().bufferSize() + _bufferSize< I+1 >(); } template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , size_t >::type _bufferSize( void ) const { return 0; } - template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) >::type _toBuffer( const VertexType &dt , char *buffer ) const { this->template get().toBuffer( dt.template get() , buffer ) ; _toBuffer< I+1 >( dt , buffer + this->template get().bufferSize() ); } - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) >::type _toBuffer( const VertexType &dt , char *buffer ) const {} - template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) >::type _fromBuffer( const char * buffer , VertexType &dt ) const {this->template get().fromBuffer( buffer , dt.template get() ) ; _fromBuffer< I+1 >( buffer + this->template get().bufferSize() , dt ); } - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) >::type _fromBuffer( const char * buffer , VertexType &dt ) const {} + template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) >::type _toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { this->template get().toBuffer( dt.template get() , buffer ) ; _toBuffer< I+1 >( dt , buffer + this->template get().bufferSize() ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) >::type _toBuffer( const VertexType &dt , Pointer( char ) buffer ) const {} + template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) >::type _fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const {this->template get().fromBuffer( buffer , dt.template get() ) ; _fromBuffer< I+1 >( buffer + this->template get().bufferSize() , dt ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) >::type _fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const {} template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , bool >::type _equal( const Factory &factory ) const { return _EqualFactories< FactoryType , Factory >( this->template get< I >() , factory.template get() ) && _equal< I+1 >( factory ); } template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , bool >::type _equal( const Factory &factory ) const { return true; } diff --git a/Src/VertexFactory.inl b/Src/VertexFactory.inl index d88ca89b..cec12038 100644 --- a/Src/VertexFactory.inl +++ b/Src/VertexFactory.inl @@ -369,12 +369,16 @@ namespace VertexFactory template< typename Real > DynamicFactory< Real >::DynamicFactory( const std::vector< std::pair< std::string , TypeOnDisk > > &namesAndTypesOnDisk ) : _namesAndTypesOnDisk(namesAndTypesOnDisk) { + _realTypeOnDisk = true; + for( unsigned int i=0 ; i<_namesAndTypesOnDisk.size() ; i++ ) _realTypeOnDisk &= GetTypeOnDisk< Real>()!=_namesAndTypesOnDisk[i].second; } template< typename Real > DynamicFactory< Real >::DynamicFactory( const std::vector< PlyProperty > &plyProperties ) { _namesAndTypesOnDisk.resize( plyProperties.size() ); for( int i=0 ; i( plyProperties[i].name , FromPlyType( plyProperties[i].external_type ) ); + _realTypeOnDisk = true; + for( unsigned int i=0 ; i<_namesAndTypesOnDisk.size() ; i++ ) _realTypeOnDisk &= GetTypeOnDisk< Real>()!=_namesAndTypesOnDisk[i].second; } template< typename Real > @@ -386,7 +390,14 @@ namespace VertexFactory template< typename Real > bool DynamicFactory< Real >::readBinary( FILE *fp , VertexType &dt ) const { - for( unsigned int i=0 ; i::ReadBinary( fp , _namesAndTypesOnDisk[i].second , dt[i] ) ) return false; + if( _realTypeOnDisk ) + { + if( fread( &dt[0] , sizeof(Real) , dt.dim() , fp )!=dt.dim() ) return false; + } + else + { + for( unsigned int i=0 ; i::ReadBinary( fp , _namesAndTypesOnDisk[i].second , dt[i] ) ) return false; + } return true; } template< typename Real > @@ -397,7 +408,8 @@ namespace VertexFactory template< typename Real > void DynamicFactory< Real >::writeBinary( FILE *fp , const VertexType &dt ) const { - for( unsigned int i=0 ; i::WriteBinary( fp , _namesAndTypesOnDisk[i].second , dt[i] ); + if( _realTypeOnDisk ) fwrite( &dt[0] , sizeof(Real) , dt.dim() , fp ); + else for( unsigned int i=0 ; i::WriteBinary( fp , _namesAndTypesOnDisk[i].second , dt[i] ); } template< typename Real > diff --git a/Src/VertexStream.h b/Src/VertexStream.h index 5f6d9a56..a4dbd1d9 100644 --- a/Src/VertexStream.h +++ b/Src/VertexStream.h @@ -48,6 +48,26 @@ class InputDataStream } }; +template< typename InputStream , typename Data > +struct MultiInputDataStream : public InputDataStream< Data > +{ + MultiInputDataStream( InputStream **streams , size_t N ) : _current(0) , _streams( streams , streams+N ) {} + MultiInputDataStream( const std::vector< InputStream * > &streams ) : _current(0) , _streams( streams ) {} + void reset( void ){ for( unsigned int i=0 ; i<_streams.size() ; i++ ) _streams[i]->reset(); } + bool next( Data &d ) + { + while( _current<_streams.size() ) + { + if( _streams[_current]->next( d ) ) return true; + else _current++; + } + return false; + } +protected: + std::vector< InputStream * > _streams; + unsigned int _current; +}; + template< typename Data > class OutputDataStream { @@ -161,7 +181,7 @@ class BinaryOutputDataStream : public OutputDataStream< typename Factory::Vertex public: BinaryOutputDataStream( const char* filename , const Factory &factory ); ~BinaryOutputDataStream( void ){ fclose( _fp ) , _fp=NULL; } - void reset( void ){ fseek( _fp , SEEK_SET , 0 ); } + void reset( void ){ fseek( _fp , 0 , SEEK_SET ); } void next( const Data &d ); }; @@ -173,12 +193,13 @@ class PLYInputDataStream : public InputDataStream< typename Factory::VertexType char* _fileName; PlyFile *_ply; std::vector< std::string > _elist; - char *_buffer; + Pointer( char ) _buffer; size_t _pCount , _pIdx; void _free( void ); public: PLYInputDataStream( const char* fileName , const Factory &factory ); + PLYInputDataStream( const char* fileName , const Factory &factory , size_t &count ); ~PLYInputDataStream( void ); void reset( void ); bool next( Data &d ); @@ -191,7 +212,7 @@ class PLYOutputDataStream : public OutputDataStream< typename Factory::VertexTyp const Factory &_factory; PlyFile *_ply; size_t _pCount , _pIdx; - char *_buffer; + Pointer( char ) _buffer; public: PLYOutputDataStream( const char* fileName , const Factory &factory , size_t count , int fileType=PLY_BINARY_NATIVE ); ~PLYOutputDataStream( void ); diff --git a/Src/VertexStream.inl b/Src/VertexStream.inl index a59fdfbb..617d2131 100644 --- a/Src/VertexStream.inl +++ b/Src/VertexStream.inl @@ -51,10 +51,7 @@ MemoryOutputDataStream< Data >::MemoryOutputDataStream( size_t size , Data *data template< typename Data > MemoryOutputDataStream< Data >::~MemoryOutputDataStream( void ){ ; } template< typename Data > -void MemoryOutputDataStream< Data >::next( const Data &d ) -{ - _data[_current++] = d; -} +void MemoryOutputDataStream< Data >::next( const Data &d ){ _data[_current++] = d; } ////////////////////////// // ASCIIInputDataStream // @@ -72,13 +69,9 @@ ASCIIInputDataStream< Factory >::~ASCIIInputDataStream( void ) _fp = NULL; } template< typename Factory > -void ASCIIInputDataStream< Factory >::reset( void ) { fseek( _fp , SEEK_SET , 0 ); } +void ASCIIInputDataStream< Factory >::reset( void ) { fseek( _fp , 0 , SEEK_SET ); } template< typename Factory > -bool ASCIIInputDataStream< Factory >::next( Data &d ) -{ - d = _factory(); - return _factory.readASCII( _fp , d ); -} +bool ASCIIInputDataStream< Factory >::next( Data &d ){ return _factory.readASCII( _fp , d ); } /////////////////////////// // ASCIIOutputDataStream // @@ -96,10 +89,7 @@ ASCIIOutputDataStream< Factory >::~ASCIIOutputDataStream( void ) _fp = NULL; } template< typename Factory > -void ASCIIOutputDataStream< Factory >::next( const Data &d ) -{ - _factory.writeASCII( _fp , d ); -} +void ASCIIOutputDataStream< Factory >::next( const Data &d ){ _factory.writeASCII( _fp , d ); } /////////////////////////// // BinaryInputDataStream // @@ -111,13 +101,9 @@ BinaryInputDataStream< Factory >::BinaryInputDataStream( const char* fileName , if( !_fp ) ERROR_OUT( "Failed to open file for reading: %s" , fileName ); } template< typename Factory > -void BinaryInputDataStream< Factory >::reset( void ) { fseek( _fp , SEEK_SET , 0 ); } +void BinaryInputDataStream< Factory >::reset( void ) { fseek( _fp , 0 , SEEK_SET ); } template< typename Factory > -bool BinaryInputDataStream< Factory >::next( Data &d ) -{ - d = _factory(); - return _factory.readBinary( _fp , d ); -} +bool BinaryInputDataStream< Factory >::next( Data &d ){ return _factory.readBinary( _fp , d ); } //////////////////////////// // BinaryOutputDataStream // @@ -134,14 +120,26 @@ void BinaryOutputDataStream< Factory >::next( const Data &d ){ return _factory.w //////////////////////// // PLYInputDataStream // //////////////////////// +template< typename Factory > +PLYInputDataStream< Factory >::PLYInputDataStream( const char* fileName , const Factory &factory , size_t &count ) : _factory(factory) +{ + _fileName = new char[ strlen( fileName )+1 ]; + strcpy( _fileName , fileName ); + _ply = NULL; + if( factory.bufferSize() ) _buffer = NewPointer< char >( factory.bufferSize() ); + else _buffer = NullPointer( char ); + reset(); + count = _pCount; +} + template< typename Factory > PLYInputDataStream< Factory >::PLYInputDataStream( const char* fileName , const Factory &factory ) : _factory(factory) { _fileName = new char[ strlen( fileName )+1 ]; strcpy( _fileName , fileName ); _ply = NULL; - if( factory.bufferSize() ) _buffer = new char[ factory.bufferSize() ]; - else _buffer = NULL; + if( factory.bufferSize() ) _buffer = NewPointer< char >( factory.bufferSize() ); + else _buffer = NullPointer( char ); reset(); } template< typename Factory > @@ -151,7 +149,7 @@ void PLYInputDataStream< Factory >::reset( void ) float version; if( _ply ) _free(); _ply = PlyFile::Read( _fileName, _elist, fileType, version ); - if( !_ply ) ERROR_OUT( "Failed to open ply file for reading: %s" , _fileName ); + if( !_ply ) ERROR_OUT( "Failed to open ply file for reading: " , _fileName ); bool foundData = false; for( int i=0 ; i<_elist.size() ; i++ ) @@ -189,18 +187,17 @@ PLYInputDataStream< Factory >::~PLYInputDataStream( void ) { _free(); if( _fileName ) delete[] _fileName , _fileName = NULL; - if( _buffer ) delete[] _buffer , _buffer = NULL; + DeletePointer( _buffer ); } template< typename Factory > bool PLYInputDataStream< Factory >::next( Data &d ) { if( _pIdx<_pCount ) { - d = _factory(); if( _factory.isStaticallyAllocated() ) _ply->get_element( (void *)&d ); else { - _ply->get_element( (void *)_buffer ); + _ply->get_element( PointerAddress( _buffer ) ); _factory.fromBuffer( _buffer , d ); } _pIdx++; @@ -230,15 +227,15 @@ PLYOutputDataStream< Factory >::PLYOutputDataStream( const char* fileName , cons } _ply->header_complete(); _ply->put_element_setup( "vertex" ); - if( _factory.bufferSize() ) _buffer = new char[ _factory.bufferSize() ]; - else _buffer = NULL; + if( _factory.bufferSize() ) _buffer = NewPointer< char >( _factory.bufferSize() ); + else _buffer = NullPointer( char ); } template< typename Factory > PLYOutputDataStream< Factory >::~PLYOutputDataStream( void ) { if( _pIdx!=_pCount ) ERROR_OUT( "Streamed points not equal to total count: " , _pIdx , " != " , _pCount ); delete _ply; - if( _buffer ) delete[] _buffer , _buffer = NULL; + DeletePointer( _buffer ); } template< typename Factory > void PLYOutputDataStream< Factory >::next( const Data &d ) @@ -248,7 +245,7 @@ void PLYOutputDataStream< Factory >::next( const Data &d ) else { _factory.toBuffer( d , _buffer ); - _ply->put_element( (void *)_buffer ); + _ply->put_element( PointerAddress( _buffer ) ); } _pIdx++; } diff --git a/Src/Window.h b/Src/Window.h index 5a5bbbda..e936e42a 100644 --- a/Src/Window.h +++ b/Src/Window.h @@ -52,6 +52,8 @@ template< unsigned int _Value , unsigned int ... _Values > struct UIntPack< _Val static constexpr unsigned int Min( void ){ return _Value < Rest::Min() ? _Value : Rest::Min(); } static constexpr unsigned int Max( void ){ return _Value > Rest::Max() ? _Value : Rest::Max(); } + using Reverse = typename Rest::Reverse::template Append< First >; + template< typename T > struct Plus{}; template< typename T > struct Minus{}; template< typename T > struct Compare{}; @@ -79,6 +81,7 @@ template< unsigned int _Value , unsigned int ... _Values > struct UIntPack< _Val template< unsigned int __Value , unsigned int ... __Values > constexpr bool operator == ( UIntPack< __Value , __Values ... > ) const { return _Value==__Value && Rest()==UIntPack< __Values ... >(); } template< unsigned int __Value , unsigned int ... __Values > constexpr bool operator != ( UIntPack< __Value , __Values ... > ) const { return _Value!=__Value && Rest()!=UIntPack< __Values ... >(); } }; + template< unsigned int _Value > struct UIntPack< _Value > { static const unsigned int First = _Value; @@ -90,6 +93,8 @@ template< unsigned int _Value > struct UIntPack< _Value > static constexpr unsigned int Min( void ){ return _Value; } static constexpr unsigned int Max( void ){ return _Value; } + using Reverse = UIntPack< _Value >; + template< typename T > struct Plus{}; template< typename T > struct Minus{}; template< typename T > struct Compare{}; @@ -133,6 +138,8 @@ template< int _Value , int ... _Values > struct IntPack< _Value , _Values ... > static constexpr int Min( void ){ return _Value < Rest::Min ? _Value : Rest::Min; } static constexpr int Max( void ){ return _Value > Rest::Max ? _Value : Rest::Max; } + using Reverse = typename Rest::Reverse::template Append< First >; + template< typename T > struct Plus{}; template< typename T > struct Minus{}; template< typename T > struct Compare{}; @@ -171,6 +178,8 @@ template< int _Value > struct IntPack< _Value > static constexpr int Min( void ){ return _Value; } static constexpr int Max( void ){ return _Value; } + using Reverse = IntPack< _Value >; + template< typename T > struct Plus{}; template< typename T > struct Minus{}; template< typename T > struct Compare{}; diff --git a/SurfaceTrimmer.vcxproj b/SurfaceTrimmer.vcxproj index 45cc3077..3382f951 100644 --- a/SurfaceTrimmer.vcxproj +++ b/SurfaceTrimmer.vcxproj @@ -36,7 +36,7 @@ Application Unicode true - v142 + v143 Application @@ -154,6 +154,7 @@ ProgramDatabase true true + stdcpp17 true diff --git a/ZLIB.vcxproj b/ZLIB.vcxproj index 183a6d1a..05eb804b 100644 --- a/ZLIB.vcxproj +++ b/ZLIB.vcxproj @@ -69,7 +69,7 @@ StaticLibrary Unicode true - v142 + v143 StaticLibrary @@ -168,6 +168,7 @@ ProgramDatabase . true + stdcpp17 From d9df5cd41331adc8779b18aa8cd354d4937e33bf Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Tue, 2 May 2023 18:26:03 -0400 Subject: [PATCH 02/86] Version 14.00 --- AdaptiveSolvers.sln | 102 +- Makefile | 44 +- PNG/PNG.vcxproj | 176 ---- PNG/PNG.vcxproj.filters | 84 -- PoissonReconClient.vcxproj | 171 ++++ PoissonReconServer.vcxproj | 171 ++++ Src/FEMTree.LevelSet.2D.inl | 2 +- Src/FEMTree.LevelSet.3D.inl | 4 +- Src/FEMTree.LevelSet.inl | 1 - Src/FEMTree.inl | 2 + Src/Image.h | 28 + Src/ImageStitching.cpp | 1 + Src/JPEG.h | 28 + Src/JPEG.inl | 28 + Src/MergePlyClientServer.h | 71 ++ Src/MergePlyClientServer.inl | 530 ++++++++++ Src/MyMiscellany.h | 17 +- Src/PNG.h | 28 + Src/PNG.inl | 28 + Src/Ply.inl | 59 +- Src/PointInterpolant.cpp | 5 +- Src/PointPartition.h | 161 +++ Src/PointPartition.inl | 659 ++++++++++++ Src/PointPartitionClientServer.h | 70 ++ Src/PointPartitionClientServer.inl | 471 +++++++++ Src/PoissonRecon.client.inl | 1535 ++++++++++++++++++++++++++++ Src/PoissonRecon.h | 4 +- Src/PoissonRecon.server.inl | 744 ++++++++++++++ Src/PoissonReconClient.cpp | 208 ++++ Src/PoissonReconClientServer.h | 97 ++ Src/PoissonReconClientServer.inl | 386 +++++++ Src/PoissonReconServer.cpp | 515 ++++++++++ Src/PreProcessor.h | 6 +- Src/SSDRecon.cpp | 2 +- Src/Socket.h | 151 +++ Src/Socket.inl | 239 +++++ Src/VertexFactory.h | 2 +- Src/VertexFactory.inl | 2 +- 38 files changed, 6547 insertions(+), 285 deletions(-) delete mode 100644 PNG/PNG.vcxproj delete mode 100644 PNG/PNG.vcxproj.filters create mode 100644 PoissonReconClient.vcxproj create mode 100644 PoissonReconServer.vcxproj create mode 100644 Src/MergePlyClientServer.h create mode 100644 Src/MergePlyClientServer.inl create mode 100644 Src/PointPartition.h create mode 100644 Src/PointPartition.inl create mode 100644 Src/PointPartitionClientServer.h create mode 100644 Src/PointPartitionClientServer.inl create mode 100644 Src/PoissonRecon.client.inl create mode 100644 Src/PoissonRecon.server.inl create mode 100644 Src/PoissonReconClient.cpp create mode 100644 Src/PoissonReconClientServer.h create mode 100644 Src/PoissonReconClientServer.inl create mode 100644 Src/PoissonReconServer.cpp create mode 100644 Src/Socket.h create mode 100644 Src/Socket.inl diff --git a/AdaptiveSolvers.sln b/AdaptiveSolvers.sln index add656d9..9e369fa3 100644 --- a/AdaptiveSolvers.sln +++ b/AdaptiveSolvers.sln @@ -53,22 +53,26 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Header Files", "Header File Src\FEMTree.h = Src\FEMTree.h Src\FunctionData.h = Src\FunctionData.h Src\Geometry.h = Src\Geometry.h - Src\GridWriter.h = Src\GridWriter.h Src\Image.h = Src\Image.h Src\JPEG.h = Src\JPEG.h Src\MarchingCubes.h = Src\MarchingCubes.h Src\MAT.h = Src\MAT.h + Src\MergePlyClientServer.h = Src\MergePlyClientServer.h Src\MyMiscellany.h = Src\MyMiscellany.h Src\Ply.h = Src\Ply.h Src\PlyFile.h = Src\PlyFile.h Src\PNG.h = Src\PNG.h + Src\PointPartition.h = Src\PointPartition.h + Src\PointPartitionClientServer.h = Src\PointPartitionClientServer.h Src\PoissonRecon.h = Src\PoissonRecon.h + Src\PoissonReconClientServer.h = Src\PoissonReconClientServer.h Src\Polynomial.h = Src\Polynomial.h Src\PPolynomial.h = Src\PPolynomial.h Src\PreProcessor.h = Src\PreProcessor.h Src\Rasterizer.h = Src\Rasterizer.h Src\RegularGrid.h = Src\RegularGrid.h Src\RegularTree.h = Src\RegularTree.h + Src\Socket.h = Src\Socket.h Src\SparseMatrix.h = Src\SparseMatrix.h Src\SparseMatrixInterface.h = Src\SparseMatrixInterface.h Src\StreamingMesh.h = Src\StreamingMesh.h @@ -96,14 +100,21 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Inline Files", "Inline File Src\Geometry.inl = Src\Geometry.inl Src\JPEG.inl = Src\JPEG.inl Src\MAT.inl = Src\MAT.inl + Src\MergePlyClientServer.inl = Src\MergePlyClientServer.inl Src\Ply.inl = Src\Ply.inl Src\PlyFile.inl = Src\PlyFile.inl Src\PNG.inl = Src\PNG.inl + Src\PointPartition.inl = Src\PointPartition.inl + Src\PointPartitionClientServer.inl = Src\PointPartitionClientServer.inl + Src\PoissonRecon.client.inl = Src\PoissonRecon.client.inl + Src\PoissonRecon.server.inl = Src\PoissonRecon.server.inl + Src\PoissonReconClientServer.inl = Src\PoissonReconClientServer.inl Src\Polynomial.inl = Src\Polynomial.inl Src\PPolynomial.inl = Src\PPolynomial.inl Src\Rasterizer.inl = Src\Rasterizer.inl Src\RegularGrid.inl = Src\RegularGrid.inl Src\RegularTree.inl = Src\RegularTree.inl + Src\Socket.inl = Src\Socket.inl Src\SparseMatrix.inl = Src\SparseMatrix.inl Src\SparseMatrixInterface.inl = Src\SparseMatrixInterface.inl Src\StreamingMesh.inl = Src\StreamingMesh.inl @@ -116,34 +127,123 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ChunkPLY", "ChunkPLY.vcxpro EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PointInterpolant", "PointInterpolant.vcxproj", "{D5516BBE-9613-4AE3-BE4D-E754995F944C}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PoissonReconClient", "PoissonReconClient.vcxproj", "{D9DFEEF0-7F6E-4381-9098-1363F385DEC3}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PoissonReconServer", "PoissonReconServer.vcxproj", "{649D8C83-6BE2-4419-B0A8-66F65CD4D4CB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D3D173AB-D306-4179-BEC4-95CE1B14E647}.Debug|x64.ActiveCfg = Debug|x64 + {D3D173AB-D306-4179-BEC4-95CE1B14E647}.Debug|x64.Build.0 = Debug|x64 + {D3D173AB-D306-4179-BEC4-95CE1B14E647}.Debug|x86.ActiveCfg = Debug|Win32 + {D3D173AB-D306-4179-BEC4-95CE1B14E647}.Debug|x86.Build.0 = Debug|Win32 {D3D173AB-D306-4179-BEC4-95CE1B14E647}.Release|x64.ActiveCfg = Release|x64 {D3D173AB-D306-4179-BEC4-95CE1B14E647}.Release|x64.Build.0 = Release|x64 + {D3D173AB-D306-4179-BEC4-95CE1B14E647}.Release|x86.ActiveCfg = Release|Win32 + {D3D173AB-D306-4179-BEC4-95CE1B14E647}.Release|x86.Build.0 = Release|Win32 + {477765F8-C16A-406B-807F-1302DAE74EBA}.Debug|x64.ActiveCfg = Debug|x64 + {477765F8-C16A-406B-807F-1302DAE74EBA}.Debug|x64.Build.0 = Debug|x64 + {477765F8-C16A-406B-807F-1302DAE74EBA}.Debug|x86.ActiveCfg = Debug|Win32 + {477765F8-C16A-406B-807F-1302DAE74EBA}.Debug|x86.Build.0 = Debug|Win32 {477765F8-C16A-406B-807F-1302DAE74EBA}.Release|x64.ActiveCfg = Release|x64 {477765F8-C16A-406B-807F-1302DAE74EBA}.Release|x64.Build.0 = Release|x64 + {477765F8-C16A-406B-807F-1302DAE74EBA}.Release|x86.ActiveCfg = Release|Win32 + {477765F8-C16A-406B-807F-1302DAE74EBA}.Release|x86.Build.0 = Release|Win32 + {B5899B32-FAC2-477E-99AA-86736B97F2FC}.Debug|x64.ActiveCfg = Debug|x64 + {B5899B32-FAC2-477E-99AA-86736B97F2FC}.Debug|x64.Build.0 = Debug|x64 + {B5899B32-FAC2-477E-99AA-86736B97F2FC}.Debug|x86.ActiveCfg = Debug|Win32 + {B5899B32-FAC2-477E-99AA-86736B97F2FC}.Debug|x86.Build.0 = Debug|Win32 {B5899B32-FAC2-477E-99AA-86736B97F2FC}.Release|x64.ActiveCfg = Release|x64 {B5899B32-FAC2-477E-99AA-86736B97F2FC}.Release|x64.Build.0 = Release|x64 + {B5899B32-FAC2-477E-99AA-86736B97F2FC}.Release|x86.ActiveCfg = Release|Win32 + {B5899B32-FAC2-477E-99AA-86736B97F2FC}.Release|x86.Build.0 = Release|Win32 + {0BE55595-4080-4265-82AF-51108EC956B2}.Debug|x64.ActiveCfg = Debug|x64 + {0BE55595-4080-4265-82AF-51108EC956B2}.Debug|x64.Build.0 = Debug|x64 + {0BE55595-4080-4265-82AF-51108EC956B2}.Debug|x86.ActiveCfg = Debug|Win32 + {0BE55595-4080-4265-82AF-51108EC956B2}.Debug|x86.Build.0 = Debug|Win32 {0BE55595-4080-4265-82AF-51108EC956B2}.Release|x64.ActiveCfg = Release|x64 {0BE55595-4080-4265-82AF-51108EC956B2}.Release|x64.Build.0 = Release|x64 + {0BE55595-4080-4265-82AF-51108EC956B2}.Release|x86.ActiveCfg = Release|Win32 + {0BE55595-4080-4265-82AF-51108EC956B2}.Release|x86.Build.0 = Release|Win32 + {E09D1615-1036-4F43-909A-2E751FC947F6}.Debug|x64.ActiveCfg = Debug|x64 + {E09D1615-1036-4F43-909A-2E751FC947F6}.Debug|x64.Build.0 = Debug|x64 + {E09D1615-1036-4F43-909A-2E751FC947F6}.Debug|x86.ActiveCfg = Debug|Win32 + {E09D1615-1036-4F43-909A-2E751FC947F6}.Debug|x86.Build.0 = Debug|Win32 {E09D1615-1036-4F43-909A-2E751FC947F6}.Release|x64.ActiveCfg = Release|x64 {E09D1615-1036-4F43-909A-2E751FC947F6}.Release|x64.Build.0 = Release|x64 + {E09D1615-1036-4F43-909A-2E751FC947F6}.Release|x86.ActiveCfg = Release|Win32 + {E09D1615-1036-4F43-909A-2E751FC947F6}.Release|x86.Build.0 = Release|Win32 + {3B94F9AD-35E8-4E1E-B176-AAA091E4C3CC}.Debug|x64.ActiveCfg = Debug|x64 + {3B94F9AD-35E8-4E1E-B176-AAA091E4C3CC}.Debug|x64.Build.0 = Debug|x64 + {3B94F9AD-35E8-4E1E-B176-AAA091E4C3CC}.Debug|x86.ActiveCfg = Debug|Win32 + {3B94F9AD-35E8-4E1E-B176-AAA091E4C3CC}.Debug|x86.Build.0 = Debug|Win32 {3B94F9AD-35E8-4E1E-B176-AAA091E4C3CC}.Release|x64.ActiveCfg = Release|x64 {3B94F9AD-35E8-4E1E-B176-AAA091E4C3CC}.Release|x64.Build.0 = Release|x64 {3B94F9AD-35E8-4E1E-B176-AAA091E4C3CC}.Release|x64.Deploy.0 = Release|x64 + {3B94F9AD-35E8-4E1E-B176-AAA091E4C3CC}.Release|x86.ActiveCfg = Release|Win32 + {3B94F9AD-35E8-4E1E-B176-AAA091E4C3CC}.Release|x86.Build.0 = Release|Win32 + {99BEAFED-8DB9-4B7D-A0BE-5186158193FE}.Debug|x64.ActiveCfg = Debug|x64 + {99BEAFED-8DB9-4B7D-A0BE-5186158193FE}.Debug|x64.Build.0 = Debug|x64 + {99BEAFED-8DB9-4B7D-A0BE-5186158193FE}.Debug|x86.ActiveCfg = Debug|Win32 + {99BEAFED-8DB9-4B7D-A0BE-5186158193FE}.Debug|x86.Build.0 = Debug|Win32 {99BEAFED-8DB9-4B7D-A0BE-5186158193FE}.Release|x64.ActiveCfg = Release|x64 {99BEAFED-8DB9-4B7D-A0BE-5186158193FE}.Release|x64.Build.0 = Release|x64 + {99BEAFED-8DB9-4B7D-A0BE-5186158193FE}.Release|x86.ActiveCfg = Release|Win32 + {99BEAFED-8DB9-4B7D-A0BE-5186158193FE}.Release|x86.Build.0 = Release|Win32 + {46F87D0E-C53A-4F95-AB48-A5DBA8014340}.Debug|x64.ActiveCfg = Debug|x64 + {46F87D0E-C53A-4F95-AB48-A5DBA8014340}.Debug|x64.Build.0 = Debug|x64 + {46F87D0E-C53A-4F95-AB48-A5DBA8014340}.Debug|x86.ActiveCfg = Debug|Win32 + {46F87D0E-C53A-4F95-AB48-A5DBA8014340}.Debug|x86.Build.0 = Debug|Win32 {46F87D0E-C53A-4F95-AB48-A5DBA8014340}.Release|x64.ActiveCfg = Release|x64 {46F87D0E-C53A-4F95-AB48-A5DBA8014340}.Release|x64.Build.0 = Release|x64 + {46F87D0E-C53A-4F95-AB48-A5DBA8014340}.Release|x86.ActiveCfg = Release|Win32 + {46F87D0E-C53A-4F95-AB48-A5DBA8014340}.Release|x86.Build.0 = Release|Win32 + {742064B3-CEBB-4AF8-B43C-D213EB1C6D7A}.Debug|x64.ActiveCfg = Debug|x64 + {742064B3-CEBB-4AF8-B43C-D213EB1C6D7A}.Debug|x64.Build.0 = Debug|x64 + {742064B3-CEBB-4AF8-B43C-D213EB1C6D7A}.Debug|x86.ActiveCfg = Debug|Win32 + {742064B3-CEBB-4AF8-B43C-D213EB1C6D7A}.Debug|x86.Build.0 = Debug|Win32 {742064B3-CEBB-4AF8-B43C-D213EB1C6D7A}.Release|x64.ActiveCfg = Release|x64 {742064B3-CEBB-4AF8-B43C-D213EB1C6D7A}.Release|x64.Build.0 = Release|x64 + {742064B3-CEBB-4AF8-B43C-D213EB1C6D7A}.Release|x86.ActiveCfg = Release|Win32 + {742064B3-CEBB-4AF8-B43C-D213EB1C6D7A}.Release|x86.Build.0 = Release|Win32 + {95B998F8-A73B-40AB-AF35-C38F2CB89480}.Debug|x64.ActiveCfg = Debug|x64 + {95B998F8-A73B-40AB-AF35-C38F2CB89480}.Debug|x64.Build.0 = Debug|x64 + {95B998F8-A73B-40AB-AF35-C38F2CB89480}.Debug|x86.ActiveCfg = Debug|Win32 + {95B998F8-A73B-40AB-AF35-C38F2CB89480}.Debug|x86.Build.0 = Debug|Win32 {95B998F8-A73B-40AB-AF35-C38F2CB89480}.Release|x64.ActiveCfg = Release|x64 {95B998F8-A73B-40AB-AF35-C38F2CB89480}.Release|x64.Build.0 = Release|x64 + {95B998F8-A73B-40AB-AF35-C38F2CB89480}.Release|x86.ActiveCfg = Release|Win32 + {95B998F8-A73B-40AB-AF35-C38F2CB89480}.Release|x86.Build.0 = Release|Win32 + {D5516BBE-9613-4AE3-BE4D-E754995F944C}.Debug|x64.ActiveCfg = Debug|x64 + {D5516BBE-9613-4AE3-BE4D-E754995F944C}.Debug|x64.Build.0 = Debug|x64 + {D5516BBE-9613-4AE3-BE4D-E754995F944C}.Debug|x86.ActiveCfg = Debug|Win32 + {D5516BBE-9613-4AE3-BE4D-E754995F944C}.Debug|x86.Build.0 = Debug|Win32 {D5516BBE-9613-4AE3-BE4D-E754995F944C}.Release|x64.ActiveCfg = Release|x64 {D5516BBE-9613-4AE3-BE4D-E754995F944C}.Release|x64.Build.0 = Release|x64 + {D5516BBE-9613-4AE3-BE4D-E754995F944C}.Release|x86.ActiveCfg = Release|Win32 + {D5516BBE-9613-4AE3-BE4D-E754995F944C}.Release|x86.Build.0 = Release|Win32 + {D9DFEEF0-7F6E-4381-9098-1363F385DEC3}.Debug|x64.ActiveCfg = Debug|x64 + {D9DFEEF0-7F6E-4381-9098-1363F385DEC3}.Debug|x64.Build.0 = Debug|x64 + {D9DFEEF0-7F6E-4381-9098-1363F385DEC3}.Debug|x86.ActiveCfg = Debug|Win32 + {D9DFEEF0-7F6E-4381-9098-1363F385DEC3}.Debug|x86.Build.0 = Debug|Win32 + {D9DFEEF0-7F6E-4381-9098-1363F385DEC3}.Release|x64.ActiveCfg = Release|x64 + {D9DFEEF0-7F6E-4381-9098-1363F385DEC3}.Release|x64.Build.0 = Release|x64 + {D9DFEEF0-7F6E-4381-9098-1363F385DEC3}.Release|x86.ActiveCfg = Release|Win32 + {D9DFEEF0-7F6E-4381-9098-1363F385DEC3}.Release|x86.Build.0 = Release|Win32 + {649D8C83-6BE2-4419-B0A8-66F65CD4D4CB}.Debug|x64.ActiveCfg = Debug|x64 + {649D8C83-6BE2-4419-B0A8-66F65CD4D4CB}.Debug|x64.Build.0 = Debug|x64 + {649D8C83-6BE2-4419-B0A8-66F65CD4D4CB}.Debug|x86.ActiveCfg = Debug|Win32 + {649D8C83-6BE2-4419-B0A8-66F65CD4D4CB}.Debug|x86.Build.0 = Debug|Win32 + {649D8C83-6BE2-4419-B0A8-66F65CD4D4CB}.Release|x64.ActiveCfg = Release|x64 + {649D8C83-6BE2-4419-B0A8-66F65CD4D4CB}.Release|x64.Build.0 = Release|x64 + {649D8C83-6BE2-4419-B0A8-66F65CD4D4CB}.Release|x86.ActiveCfg = Release|Win32 + {649D8C83-6BE2-4419-B0A8-66F65CD4D4CB}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Makefile b/Makefile index f0d6c564..dff1c29b 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,6 @@ PR_TARGET=PoissonRecon +PRC_TARGET=PoissonReconClient +PRS_TARGET=PoissonReconServer SR_TARGET=SSDRecon PI_TARGET=PointInterpolant ST_TARGET=SurfaceTrimmer @@ -7,6 +9,8 @@ IS_TARGET=ImageStitching AV_TARGET=AdaptiveTreeVisualization CP_TARGET=ChunkPLY PR_SOURCE=PoissonRecon.cpp +PRC_SOURCE=PoissonReconClient.cpp +PRS_SOURCE=PoissonReconServer.cpp SR_SOURCE=SSDRecon.cpp PI_SOURCE=PointInterpolant.cpp ST_SOURCE=SurfaceTrimmer.cpp @@ -30,7 +34,7 @@ else CFLAGS += -Wno-deprecated -std=c++17 -pthread -Wno-invalid-offsetof -Wno-dangling-else LFLAGS += -lstdc++ endif -LFLAGS += -lz -lpng -ljpeg +LFLAGS_IMG += -lz -lpng -ljpeg #LFLAGS += -ljpeg -lmypng -lz CFLAGS_DEBUG = -DDEBUG -g3 @@ -60,6 +64,8 @@ endif MD=mkdir PR_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(PR_SOURCE)))) +PRC_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(PRC_SOURCE)))) +PRS_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(PRS_SOURCE)))) SR_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(SR_SOURCE)))) PI_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(PI_SOURCE)))) ST_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(ST_SOURCE)))) @@ -73,6 +79,8 @@ all: CFLAGS += $(CFLAGS_RELEASE) all: LFLAGS += $(LFLAGS_RELEASE) all: make_dir all: $(BIN)$(PR_TARGET) +all: $(BIN)$(PRC_TARGET) +all: $(BIN)$(PRS_TARGET) all: $(BIN)$(SR_TARGET) all: $(BIN)$(PI_TARGET) all: $(BIN)$(ST_TARGET) @@ -85,6 +93,8 @@ debug: CFLAGS += $(CFLAGS_DEBUG) debug: LFLAGS += $(LFLAGS_DEBUG) debug: make_dir debug: $(BIN)$(PR_TARGET) +debug: $(BIN)$(PRC_TARGET) +debug: $(BIN)$(PRS_TARGET) debug: $(BIN)$(SR_TARGET) debug: $(BIN)$(PI_TARGET) debug: $(BIN)$(ST_TARGET) @@ -98,6 +108,16 @@ poissonrecon: LFLAGS += $(LFLAGS_RELEASE) poissonrecon: make_dir poissonrecon: $(BIN)$(PR_TARGET) +poissonreconclient: CFLAGS += $(CFLAGS_RELEASE) +poissonreconclient: LFLAGS += $(LFLAGS_RELEASE) +poissonreconclient: make_dir +poissonreconclient: $(BIN)$(PRC_TARGET) + +poissonreconserver: CFLAGS += $(CFLAGS_RELEASE) +poissonreconserver: LFLAGS += $(LFLAGS_RELEASE) +poissonreconserver: make_dir +poissonreconserver: $(BIN)$(PRS_TARGET) + ssdrecon: CFLAGS += $(CFLAGS_RELEASE) ssdrecon: LFLAGS += $(LFLAGS_RELEASE) ssdrecon: make_dir @@ -135,6 +155,8 @@ chunkply: $(BIN)$(CP_TARGET) clean: rm -rf $(BIN)$(PR_TARGET) + rm -rf $(BIN)$(PRC_TARGET) + rm -rf $(BIN)$(PRS_TARGET) rm -rf $(BIN)$(SR_TARGET) rm -rf $(BIN)$(PI_TARGET) rm -rf $(BIN)$(ST_TARGET) @@ -143,6 +165,8 @@ clean: rm -rf $(BIN)$(AV_TARGET) rm -rf $(BIN)$(CP_TARGET) rm -rf $(PR_OBJECTS) + rm -rf $(PRC_OBJECTS) + rm -rf $(PRS_OBJECTS) rm -rf $(SR_OBJECTS) rm -rf $(PI_OBJECTS) rm -rf $(ST_OBJECTS) @@ -158,15 +182,21 @@ make_dir: $(BIN)$(PR_TARGET): $(PR_OBJECTS) cd PNG && make COMPILER=$(COMPILER) - $(CXX) -pthread -o $@ $(PR_OBJECTS) -L$(BIN) $(LFLAGS) + $(CXX) -pthread -o $@ $(PR_OBJECTS) -L$(BIN) $(LFLAGS) $(LFLAGS_IMG) + +$(BIN)$(PRC_TARGET): $(PRC_OBJECTS) + $(CXX) -pthread -o $@ $(PRC_OBJECTS) -L$(BIN) -lboost_system $(LFLAGS) + +$(BIN)$(PRS_TARGET): $(PRS_OBJECTS) + $(CXX) -pthread -o $@ $(PRS_OBJECTS) -L$(BIN) -lboost_system $(LFLAGS) $(BIN)$(SR_TARGET): $(SR_OBJECTS) cd PNG && make COMPILER=$(COMPILER) - $(CXX) -pthread -o $@ $(SR_OBJECTS) -L$(BIN) $(LFLAGS) + $(CXX) -pthread -o $@ $(SR_OBJECTS) -L$(BIN) $(LFLAGS) $(LFLAGS_IMG) $(BIN)$(PI_TARGET): $(PI_OBJECTS) cd PNG && make COMPILER=$(COMPILER) - $(CXX) -pthread -o $@ $(PI_OBJECTS) -L$(BIN) $(LFLAGS) + $(CXX) -pthread -o $@ $(PI_OBJECTS) -L$(BIN) $(LFLAGS) $(LFLAGS_IMG) $(BIN)$(ST_TARGET): $(ST_OBJECTS) $(CXX) -pthread -o $@ $(ST_OBJECTS) $(LFLAGS) @@ -176,15 +206,15 @@ $(BIN)$(EH_TARGET): $(EH_OBJECTS) $(BIN)$(IS_TARGET): $(IS_OBJECTS) cd PNG && make COMPILER=$(COMPILER) - $(CXX) -pthread -o $@ $(IS_OBJECTS) -L$(BIN) $(LFLAGS) + $(CXX) -pthread -o $@ $(IS_OBJECTS) -L$(BIN) $(LFLAGS) $(LFLAGS_IMG) $(BIN)$(AV_TARGET): $(AV_OBJECTS) cd PNG && make COMPILER=$(COMPILER) - $(CXX) -pthread -o $@ $(AV_OBJECTS) -L$(BIN) $(LFLAGS) + $(CXX) -pthread -o $@ $(AV_OBJECTS) -L$(BIN) $(LFLAGS) $(LFLAGS_IMG) $(BIN)$(CP_TARGET): $(CP_OBJECTS) cd PNG && make COMPILER=$(COMPILER) - $(CXX) -pthread -o $@ $(CP_OBJECTS) -L$(BIN) $(LFLAGS) + $(CXX) -pthread -o $@ $(CP_OBJECTS) -L$(BIN) $(LFLAGS) $(LFLAGS_IMG) $(BIN)%.o: $(SRC)%.c $(CC) -c -o $@ -I$(INCLUDE) $< diff --git a/PNG/PNG.vcxproj b/PNG/PNG.vcxproj deleted file mode 100644 index 5ebc26b0..00000000 --- a/PNG/PNG.vcxproj +++ /dev/null @@ -1,176 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {B5899B32-FAC2-477E-99AA-86736B97F2FC} - PNG - Win32Proj - 10.0 - - - - StaticLibrary - Unicode - true - v142 - - - StaticLibrary - Unicode - v142 - - - StaticLibrary - Unicode - true - v142 - - - StaticLibrary - Unicode - v142 - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.40219.1 - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - $(SolutionDir)$(Configuration)\ - $(SolutionDir)Intermediate\$(ProjectName)\$(Configuration)\ - $(SolutionDir)\Bin\$(Platform)\$(Configuration)\ - $(SolutionDir)\Obj\$(TargetName)\$(Platform)\$(Configuration)\ - $(SolutionDir)\Bin\$(Platform)\$(Configuration)\ - $(SolutionDir)\Obj\$(TargetName)\$(Platform)\$(Configuration)\ - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - - - - Disabled - ..;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - EditAndContinue - - - - - true - ..;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreadedDLL - - - Level3 - ProgramDatabase - - - - - X64 - - - Disabled - ..;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - ProgramDatabase - - - - - X64 - - - ..;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreadedDLL - - - Level3 - ProgramDatabase - true - stdcpp17 - - - - - - \ No newline at end of file diff --git a/PNG/PNG.vcxproj.filters b/PNG/PNG.vcxproj.filters deleted file mode 100644 index 43cf39d6..00000000 --- a/PNG/PNG.vcxproj.filters +++ /dev/null @@ -1,84 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/PoissonReconClient.vcxproj b/PoissonReconClient.vcxproj new file mode 100644 index 00000000..c6d784d7 --- /dev/null +++ b/PoissonReconClient.vcxproj @@ -0,0 +1,171 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + 15.0 + {D9DFEEF0-7F6E-4381-9098-1363F385DEC3} + Win32Proj + MultiPoissonRecon + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + false + $(SolutionDir)\Bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\Obj\$(TargetName)\$(Platform)\$(Configuration)\ + + + true + + + true + + + false + + + + NotUsing + Level3 + MaxSpeed + true + true + true + NOMINMAX;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + false + pch.h + AdvancedVectorExtensions2 + true + stdcpp17 + C:\Research\Libraries\ + + + Console + true + true + true + $(OutDir) + ZLIB.lib;JPEG.lib;PNG.lib;psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Use + Level3 + Disabled + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + + + Console + true + + + + + NotUsing + Level3 + Disabled + true + NOMINMAX;WIN32;_CRT_SECURE_NO_DEPRECATE;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + C:\Research\Libraries\ + true + stdcpp17 + /bigobj %(AdditionalOptions) + + + Console + true + + + + + Use + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + + + Console + true + true + true + + + + + + \ No newline at end of file diff --git a/PoissonReconServer.vcxproj b/PoissonReconServer.vcxproj new file mode 100644 index 00000000..6a704575 --- /dev/null +++ b/PoissonReconServer.vcxproj @@ -0,0 +1,171 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + 15.0 + {649D8C83-6BE2-4419-B0A8-66F65CD4D4CB} + Win32Proj + MultiPoissonRecon + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + false + $(SolutionDir)\Bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\Obj\$(TargetName)\$(Platform)\$(Configuration)\ + + + true + + + true + + + false + + + + NotUsing + Level3 + MaxSpeed + true + true + true + NOMINMAX;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + false + pch.h + AdvancedVectorExtensions2 + true + stdcpp17 + C:\Research\Libraries\ + + + Console + true + true + true + $(OutDir) + ZLIB.lib;JPEG.lib;PNG.lib;psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Use + Level3 + Disabled + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + + + Console + true + + + + + NotUsing + Level3 + Disabled + true + _CRT_SECURE_NO_DEPRECATE;NOMINMAX;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + true + C:\Research\Libraries\ + stdcpp17 + /bigobj %(AdditionalOptions) + + + Console + true + + + + + Use + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + + + Console + true + true + true + + + + + + \ No newline at end of file diff --git a/Src/FEMTree.LevelSet.2D.inl b/Src/FEMTree.LevelSet.2D.inl index f6230b11..c29c8e1b 100644 --- a/Src/FEMTree.LevelSet.2D.inl +++ b/Src/FEMTree.LevelSet.2D.inl @@ -1,5 +1,5 @@ /* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +Copyright (c) 2022, Michael Kazhdan All rights reserved. Redistribution and use in source and binary forms, with or without modification, diff --git a/Src/FEMTree.LevelSet.3D.inl b/Src/FEMTree.LevelSet.3D.inl index 9b08d84f..e2850381 100644 --- a/Src/FEMTree.LevelSet.3D.inl +++ b/Src/FEMTree.LevelSet.3D.inl @@ -1,5 +1,5 @@ /* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +Copyright (c) 2022, Michael Kazhdan All rights reserved. Redistribution and use in source and binary forms, with or without modification, @@ -1838,7 +1838,9 @@ public: unsigned int maxDepth = std::max< unsigned int >( tree._maxDepth , slabDepth ); unsigned int slabStartAtMaxDepth = slabStart << ( maxDepth - slabDepth ); unsigned int slabEndAtMaxDepth = slabEnd << ( maxDepth - slabDepth ); +#ifdef SHOW_WARNINGS if( slabDepth>(unsigned int)fullDepth && ( ( slabStart!=0 && !backBoundary ) || ( slabEnd+1!=1<<(slabDepth) && !frontBoundary ) ) ) WARN( "Slab depth exceeds full depth, reconstruction may not be water-tight: " , slabDepth , " <= " , fullDepth , " [ " , slabStart , " , " , slabEnd , " )" ); +#endif // SHOW_WARNINGS _BadRootCount = 0u; Stats stats; diff --git a/Src/FEMTree.LevelSet.inl b/Src/FEMTree.LevelSet.inl index 034ae03d..86d72165 100644 --- a/Src/FEMTree.LevelSet.inl +++ b/Src/FEMTree.LevelSet.inl @@ -26,7 +26,6 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ -#include "PreProcessor.h" #include "MarchingCubes.h" // Level-set extraction data diff --git a/Src/FEMTree.inl b/Src/FEMTree.inl index d68efd50..b59deec8 100644 --- a/Src/FEMTree.inl +++ b/Src/FEMTree.inl @@ -256,7 +256,9 @@ void FEMTree< Dim , Real >::slice( const FEMTree< Dim+1 , Real > &tree , unsigne #endif // __GNUC__ { double eps = 1e-4/(1< #include diff --git a/Src/MergePlyClientServer.h b/Src/MergePlyClientServer.h new file mode 100644 index 00000000..614db6b0 --- /dev/null +++ b/Src/MergePlyClientServer.h @@ -0,0 +1,71 @@ +/* +Copyright (c) 2023, 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 MERGE_PLY_CLIENT_SERVER_INCLUDED +#define MERGE_PLY_CLIENT_SERVER_INCLUDED + +#include +#include "Socket.h" +#include "MyMiscellany.h" +#include "CmdLineParser.h" + + +namespace MergePlyClientServer +{ + struct ClientMergePlyInfo + { + std::vector< PlyProperty > auxProperties; + size_t bufferSize; + bool verbose; + + ClientMergePlyInfo( void ); + ClientMergePlyInfo( BinaryStream &stream ); + + void write( BinaryStream &stream ) const; + }; + + template< typename Real , unsigned int Dim > + void RunServer + ( + std::string inDir , + std::string tempDir , + std::string header , + std::string out , + std::vector< Socket > &clientSockets , + const std::vector< unsigned int > &sharedVertexCounts , + ClientMergePlyInfo clientMergePlyInfo , + unsigned int sampleMS + ); + + template< typename Real , unsigned int Dim > + void RunClients( std::vector< Socket > &serverSockets , unsigned int sampleMS ); + +#include "MergePlyClientServer.inl" +} + +#endif // MERGE_PLY_CLIENT_SERVER_INCLUDED \ No newline at end of file diff --git a/Src/MergePlyClientServer.inl b/Src/MergePlyClientServer.inl new file mode 100644 index 00000000..b7e15102 --- /dev/null +++ b/Src/MergePlyClientServer.inl @@ -0,0 +1,530 @@ +/* +Copyright (c) 2023, 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. +*/ + +enum _IndexType{ INT , U_INT , LONG_LONG }; + +inline std::string _FullFileName( std::string dir , std::string fileName ) +{ + if( dir.back()!=FileSeparator ) dir += std::string(1,FileSeparator); + return dir + fileName; +} + +inline void _Copy( FILE *target , FILE *source , size_t sz , size_t bufferSize=1<<20 ) +{ + Pointer( unsigned char ) buffer = NewPointer< unsigned char >( bufferSize ); + if( sz==-1 ) + { + size_t ioBytes; + while( ioBytes=fread( buffer , sizeof(unsigned char) , bufferSize , source ) ) fwrite( buffer , sizeof(unsigned char) , ioBytes , target ); + } + else + { + while( sz ) + { + size_t ioBytes = std::min< size_t >( bufferSize , sz ); + if( ioBytes!=fread( buffer , sizeof(unsigned char) , ioBytes , source ) ) ERROR_OUT( "Failed to read from source: " , ioBytes ); + if( ioBytes!=fwrite( buffer , sizeof(unsigned char) , ioBytes , target ) ) ERROR_OUT( "Failed to write to target: " , ioBytes ); + sz -= ioBytes; + } + } + DeletePointer( buffer ); +} + +template< typename Index , typename Factory > +void _OffsetPolygons( const Factory &factory , std::string in , std::string out , size_t offset , Profiler &profiler ) +{ +#if 1 +// PlyProperty faceProperty( "vertex_indices" , PLY::DefaultFileType< Index >() , PLY::DefaultFileType< Index >() , sizeof(int) , 1 , PLY::DefaultFileType< int >() , PLY::DefaultFileType< int >() , 0 ); + + int ft; + std::vector< std::string > comments; + + std::vector< std::tuple< std::string , size_t , std::vector< PlyProperty > > > _elems; + PlyFile *inPly = PLY::ReadHeader( in , ft , _elems ); + + size_t sizeOnDisk = 0; + if( factory.isStaticallyAllocated() ) + for( unsigned int i=0 ; ifp , sizeOnDisk * std::get<1>( _elems[0] ) , SEEK_CUR ); +#else // !_WIN32 && !_WIN64 + fseek( inPly->fp , sizeOnDisk * std::get<1>( _elems[0] ) , SEEK_CUR ); +#endif // _WIN32 || _WIN64 + } + + std::vector< std::tuple< std::string , size_t , std::vector< PlyProperty > > > elems(1); + std::get<0>( elems[0] ) = std::string( "face" ); + std::get<1>( elems[0] ) = std::get<1>( _elems[1] ); + std::get<2>( elems[0] ).resize(1); + std::get<2>( elems[0] )[0] = PLY::Face< Index >::Properties[0]; + + PlyFile *outPly = PLY::WriteHeader( out , ft , elems , comments ); + + // Read and offset the polygons + { + int maxIndices = 64; + Index *faceIndices = (Index*)malloc( sizeof(Index) * maxIndices ); + + auto ReadPolygon = [&]( FILE *fp ) + { + int n; + if( fread( &n , sizeof(int) , 1 , fp )!=1 ) ERROR_OUT( "Failed to read polygon size" ); + if( n>maxIndices ) + { + maxIndices = n; + faceIndices = (Index*)realloc( faceIndices , sizeof(Index) * maxIndices ); + } + if( fread( faceIndices , sizeof(Index) , n , fp )!=n ) ERROR_OUT( "Failed to read polygon indices" ); + return n; + }; + + auto WritePolygon = [&]( FILE *fp , int n ) + { + fwrite( &n , sizeof(int) , 1 , fp ); + fwrite( faceIndices , sizeof(Index) , n , fp ); + }; + + for( unsigned int j=0 ; j( _elems[1] ).size() ; j++ ) inPly->get_property( std::get<0>( _elems[1] ) , &std::get<2>( _elems[1] )[j] ); + outPly->put_element_setup( std::string( "face" ) ); + + for( size_t i=0 ; i( _elems[1] ) ; i++ ) + { + int n = ReadPolygon( inPly->fp ); + for( int j=0 ; jfp , n ); + } + + profiler.update(); + + delete[] faceIndices; + } + delete inPly; + delete outPly; +#else + typedef typename Factory::VertexType Vertex; + std::vector< Vertex > vertices; + std::vector< std::vector< Index > > polygons; + + int ft; + std::vector< std::string > comments; + + PLY::ReadPolygons< Factory , Index >( in , factory , vertices , polygons , ft , comments ); + std::vector< std::tuple< std::string , size_t , std::vector< PlyProperty > > > elems(1); + std::get<0>( elems[0] ) = std::string( "face" ); + std::get<1>( elems[0] ) = polygons.size(); + std::get<2>( elems[0] ).resize(1); + std::get<2>( elems[0] )[0] = PLY::Face< Index >::Properties[0]; + + PlyFile *ply = PLY::WriteHeader( out , ft , elems , comments ); + + { + PLY::Face< Index > face; + unsigned int maxFaceVerts=3; + face.nr_vertices = 3; + face.vertices = new Index[ face.nr_vertices ]; + + ply->put_element_setup( std::string( "face" ) ); + for( size_t i=0 ; imaxFaceVerts ) + { + delete[] face.vertices; + maxFaceVerts = (unsigned int)polygons[i].size(); + face.vertices=new Index[ maxFaceVerts ]; + } + face.nr_vertices = (unsigned int)polygons[i].size(); + for( size_t j=0 ; jput_element( (void *)&face ); + } + + profiler.update(); + + delete[] face.vertices; + } + delete ply; +#endif +} + + +//////////// +// Server // +//////////// + +template< typename Real , unsigned int Dim , typename Factory > +void _RunServer +( + std::string inDir , + std::string tempDir , + std::string header , + std::string out , + std::vector< Socket > &clientSockets , + const std::vector< unsigned int > &sharedVertexCounts , + ClientMergePlyInfo clientMergePlyInfo , + const Factory &factory , + unsigned int sampleMS +) +{ + Profiler profiler(sampleMS); + typedef typename Factory::VertexType Vertex; + + auto ClientFile = []( std::string dir , std::string header , unsigned int idx ) + { + std::stringstream ss; + ss << _FullFileName( dir , header ) << "." << idx << ".ply"; + return ss.str(); + }; + + auto InFile = [&]( unsigned int idx ){ return ClientFile( inDir , header , idx ); }; + auto TempPolygonFile = [&]( unsigned int idx ){ return ClientFile( tempDir , header + std::string( ".polygons" ) , idx ); }; + + profiler.reset(); + + // Get the number of vertices and polygons per file + std::vector< size_t > vNum( sharedVertexCounts.size()+1 ) , fNum( sharedVertexCounts.size()+1 ) , offsets( sharedVertexCounts.size()+1 ); + { + for( unsigned int i=0 ; i<=sharedVertexCounts.size() ; i++ ) + { + std::string inFile = InFile(i); + int ft; + std::vector< std::tuple< std::string , size_t , std::vector< PlyProperty > > > elems; + PlyFile *ply = PLY::ReadHeader( inFile , ft , elems ); + delete ply; + bool foundVertices = false , foundFaces = false; + for( unsigned int j=0 ; j( elems[j] )==std::string( "vertex" ) ) foundVertices = true , vNum[i] = std::get<1>( elems[j] ); + else if( std::get<0>( elems[j] )==std::string( "face" ) ) foundFaces = true , fNum[i] = std::get<1>( elems[j] ); + if( !foundVertices ) ERROR_OUT( "Could not find vertices" ); + if( !foundFaces ) ERROR_OUT( "Could not find faces" ); + profiler.update(); + } + offsets[0] = 0; + for( unsigned int i=1 ; i<=sharedVertexCounts.size() ; i++ ) offsets[i] = offsets[i-1] + vNum[i-1] - sharedVertexCounts[i-1]; + } + + // Strip out the polygons (though perhaps we should just have the reconstruction code do this). +#ifdef SHOW_WARNINGS + WARN( "Should split the mesh during reconstruction" ); +#endif // SHOW_WARNINGS + + _IndexType idxType; + if( offsets.back()+vNum.back()>std::numeric_limits< int >::max() ) + { + if( offsets.back()+vNum.back()>std::numeric_limits< unsigned int >::max () ) idxType = LONG_LONG; + else idxType = U_INT; + } + else idxType = INT; + + if( clientMergePlyInfo.verbose ) std::cout << "Got mesh info: " << profiler(true) << std::endl; + + + for( unsigned int i=0 ; i > > elems(2); + { + std::get<0>( elems[0] ) = std::string( "vertex" ); + std::get<1>( elems[0] ) = 0; + for( unsigned int i=0 ; i( elems[0] ) += vNum[i]; + for( unsigned int i=0 ; i( elems[0] ) -= sharedVertexCounts[i]; + std::get<2>( elems[0] ).resize( factory.plyWriteNum() ); + for( unsigned int i=0 ; i( elems[0] )[i] = factory.isStaticallyAllocated() ? factory.plyStaticWriteProperty(i) : factory.plyWriteProperty(i); + + std::get<0>( elems[1] ) = std::string( "face" ); + std::get<1>( elems[1] ) = 0; + for( unsigned int i=0 ; i( elems[1] ) += fNum[i]; + std::get<2>( elems[1] ).resize(1); + switch( idxType ) + { + case INT: std::get<2>( elems[1] )[0] = PLY::Face< int >::Properties[0] ; break; + case U_INT: std::get<2>( elems[1] )[0] = PLY::Face< unsigned int >::Properties[0] ; break; + case LONG_LONG: std::get<2>( elems[1] )[0] = PLY::Face< long long >::Properties[0] ; break; + default: ERROR_OUT( "Unrecognized output type" ); + } + } + PlyFile *outPly = PLY::WriteHeader( out , PLY_BINARY_NATIVE , elems ); + + // Write out the (merged) vertices + { + Pointer( char ) vBuffer = NewPointer< char >( factory.bufferSize() ); + + outPly->put_element_setup( std::string( "vertex" ) ); + + size_t sizeOnDisk = 0; + if( factory.isStaticallyAllocated() ) + for( unsigned int i=0 ; i sharedVertices; + for( unsigned int i=0 ; i<=sharedVertexCounts.size() ; i++ ) + { + std::vector< std::tuple< std::string , size_t , std::vector< PlyProperty > > > _elems; + int ft; + PlyFile *inPly = PLY::ReadHeader( InFile(i) , ft , _elems ); + + for( unsigned int j=0 ; j( elems[0] ).size() ; j++ ) inPly->get_property( std::get<0>( elems[0] ) , &std::get<2>( elems[0] )[j] ); + + // Merge the start vertices + Vertex v = factory(); + for( unsigned int j=0 ; jget_element( &v ); + sharedVertices[j] = ( sharedVertices[j] + v ) / (Real)2.; + outPly->put_element( (void*)&sharedVertices[j] ); + } + else + { + inPly->get_element( PointerAddress( vBuffer ) ); + factory.fromBuffer( vBuffer , v ); + sharedVertices[j] = ( sharedVertices[j] + v ) / (Real)2.; + factory.toBuffer( sharedVertices[j] , vBuffer ); + outPly->put_element( PointerAddress( vBuffer ) ); + } + } + + // Copy the interior vertices + { + size_t vNum = std::get<1>( _elems[0] ) - sharedVertices.size(); + if( ifp , inPly->fp , vNum*sizeOnDisk , clientMergePlyInfo.bufferSize ); + } + + // Buffer the end vertices + if( iget_element( (void*)&sharedVertices[j] ); + else + { + inPly->get_element( PointerAddress( vBuffer ) ); + factory.fromBuffer( vBuffer , sharedVertices[j] ); + } + } + } + profiler.update(); + + delete inPly; + } + DeletePointer( vBuffer ); + if( clientMergePlyInfo.verbose ) std::cout << "Merged vertices: " << profiler(true) << std::endl; + } + + profiler.reset(); + // Write out the polygons + { + outPly->put_element_setup( std::string( "face" ) ); + for( unsigned int i=0 ; i<=sharedVertexCounts.size() ; i++ ) + { + std::vector< std::tuple< std::string , size_t , std::vector< PlyProperty > > > _elems; + int ft; + PlyFile *inPly = PLY::ReadHeader( TempPolygonFile(i) , ft , _elems ); + + _Copy( outPly->fp , inPly->fp , -1 , clientMergePlyInfo.bufferSize ); + profiler.update(); + delete inPly; + } + if( clientMergePlyInfo.verbose ) std::cout << "Merged polygons: " << profiler(true) << std::endl; + } + delete outPly; + + for( unsigned int i=0 ; i<=sharedVertexCounts.size() ; i++ ) + { + std::string fileName = TempPolygonFile(i); + std::remove( fileName.c_str() ); + } +} + +template< typename Real , unsigned int Dim > +void RunServer +( + std::string inDir , + std::string tempDir , + std::string header , + std::string out , + std::vector< Socket > &clientSockets , + const std::vector< unsigned int > &sharedVertexCounts , + ClientMergePlyInfo clientMergePlyInfo , + unsigned int sampleMS +) +{ + if( clientSockets.size()!=sharedVertexCounts.size()+1 ) ERROR_OUT( "Socket num and shared vertex count don't match: " , clientSockets.size() , " / " , sharedVertexCounts.size() ); + + for( unsigned int i=0 ; i , VertexFactory::DynamicFactory< Real > > Factory; + VertexFactory::PositionFactory< Real , Dim > vFactory; + VertexFactory::DynamicFactory< Real > dFactory( clientMergePlyInfo.auxProperties ); + Factory factory( vFactory , dFactory ); + _RunServer< Real , Dim >( inDir , tempDir , header , out , clientSockets , sharedVertexCounts , clientMergePlyInfo , factory , sampleMS ); + } + else + { + typedef VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > > Factory; + Factory factory; + _RunServer< Real , Dim >( inDir , tempDir , header , out , clientSockets , sharedVertexCounts , clientMergePlyInfo , factory , sampleMS ); + } + +} + +//////////// +// Client // +//////////// +template< typename Real , unsigned int Dim , typename Factory > +void _RunClients +( + ClientMergePlyInfo clientMergePlyInfo , + const Factory &factory , + std::vector< Socket > &serverSockets , + unsigned int sampleMS +) +{ + Profiler profiler( sampleMS ); + + for( unsigned int c=0 ; c( factory , in , out , offset , profiler ) ; break; + case U_INT: _OffsetPolygons< unsigned int >( factory , in , out , offset , profiler ) ; break; + case LONG_LONG: _OffsetPolygons< long long >( factory , in , out , offset , profiler ) ; break; + default: ERROR_OUT( "Unrecognized output index type" ); + } + char done = 1; + socketStream.write( done ); + } + if( clientMergePlyInfo.verbose ) std::cout << "Offset polygons: " << profiler(true) << std::endl; +} + +template< typename Real , unsigned int Dim > +void RunClients( std::vector< Socket > &serverSockets , unsigned int sampleMS ) +{ + + ClientMergePlyInfo clientMergePlyInfo; + + for( unsigned int i=0 ; i , VertexFactory::DynamicFactory< Real > > Factory; + VertexFactory::PositionFactory< Real , Dim > vFactory; + VertexFactory::DynamicFactory< Real > dFactory( clientMergePlyInfo.auxProperties ); + Factory factory( vFactory , dFactory ); + _RunClients< Real , Dim >( clientMergePlyInfo , factory , serverSockets , sampleMS ); + } + else + { + typedef VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > > Factory; + Factory factory; + _RunClients< Real , Dim >( clientMergePlyInfo , factory , serverSockets , sampleMS ); + } +} + +///////////////////////// +// ClientPartitionInfo // +///////////////////////// +ClientMergePlyInfo::ClientMergePlyInfo( void ){} + +ClientMergePlyInfo::ClientMergePlyInfo( BinaryStream &stream ) +{ + auto ReadBool = [&]( bool &b ) + { + char _b; + if( !stream.read( _b ) ) return false; + b = _b!=0; + return true; + }; + + if( !stream.read( bufferSize ) ) ERROR_OUT( "Failed to read buffer size" ); + { + size_t sz; + if( !stream.read( sz ) ) ERROR_OUT( "Failed to read number of auxiliary properties" ); + auxProperties.resize(sz); + for( size_t i=0 ; i diff = (std::chrono::system_clock::now() - _startWallClock) ; return diff.count(); } + double wallTime( void ) const{ std::chrono::duration diff = (std::chrono::system_clock::now() - _startWallClock) ; return diff.count(); } + std::string operator()( bool showCpuTime , unsigned int precision=1 ) const + { + std::stringstream ss; + StreamFloatPrecision sfp( ss , precision ); + ss << wallTime() << " (s)"; + if( showCpuTime ) ss << " / " << cpuTime() << " (s)"; + return ss.str(); + } + friend std::ostream &operator << ( std::ostream &os , const Timer &timer ){ return os << timer(false); } protected: std::clock_t _startCPUClock; std::chrono::time_point< std::chrono::system_clock > _startWallClock; @@ -787,7 +796,7 @@ struct Profiler else if( currentPeak>_currentPeak ) _currentPeak = currentPeak; } - std::string operator()( std::string header="" ) const + std::string operator()( bool showTime=true ) const { std::stringstream ss; double dt = Time()-_t; @@ -795,8 +804,8 @@ struct Profiler double globalPeakMB = ( (double)getPeakRSS() )/(1<<20); { StreamFloatPrecision sfp( ss , 1 ); - if( header.length() ) ss << header << " "; - ss << dt << " (s), " << localPeakMB << " (MB) / " << globalPeakMB << " (MB)"; + if( showTime ) ss << dt << " (s), "; + ss << localPeakMB << " (MB) / " << globalPeakMB << " (MB)"; } return ss.str(); } diff --git a/Src/PNG.h b/Src/PNG.h index 120fb669..94850725 100644 --- a/Src/PNG.h +++ b/Src/PNG.h @@ -1,3 +1,31 @@ +/* +Copyright (c) 2010, 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 PNG_INCLUDED #define PNG_INCLUDED diff --git a/Src/PNG.inl b/Src/PNG.inl index fb37449a..273f8052 100644 --- a/Src/PNG.inl +++ b/Src/PNG.inl @@ -1,3 +1,31 @@ +/* +Copyright (c) 2010, 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. +*/ + #include #include diff --git a/Src/Ply.inl b/Src/Ply.inl index 65d4a0a1..18b12ac5 100644 --- a/Src/Ply.inl +++ b/Src/Ply.inl @@ -64,7 +64,64 @@ namespace PLY PlyProperty Face< long long , true >::Properties[] = { PlyProperty( "vertex_indices" , PLY_LONGLONG , PLY_LONGLONG , offsetof( Face , vertices ) , 1 , PLY_CHAR , PLY_CHAR , offsetof( Face , nr_vertices ) ) }; template<> PlyProperty Face< unsigned long long , true >::Properties[] = { PlyProperty( "vertex_indices" , PLY_ULONGLONG , PLY_ULONGLONG , offsetof( Face , vertices ) , 1 , PLY_CHAR , PLY_CHAR , offsetof( Face , nr_vertices ) ) }; + // Read + inline PlyFile *ReadHeader( std::string fileName , int &fileType , std::vector< std::tuple< std::string , size_t , std::vector< PlyProperty > > > &elems , std::vector< std::string > &comments ) + { + std::vector< std::string > elist; + float version; + + PlyFile *ply = PlyFile::Read( fileName , elist , fileType , version ); + if( !ply ) ERROR_OUT( "Could not open ply file for reading: " , fileName ); + + elems.resize( elist.size() ); + for( unsigned int i=0 ; i( elems[i] ) = elist[i]; + std::get<2>( elems[i] ) = ply->get_element_description( std::get<0>( elems[i] ) , std::get<1>( elems[i] ) ); + } + + comments.resize( ply->comments.size() ); + for( int i=0 ; icomments.size() ; i++ ) comments[i] = ply->comments[i]; + + return ply; + } + + inline PlyFile *WriteHeader( std::string fileName , int fileType , const std::vector< std::tuple< std::string , size_t , std::vector< PlyProperty > > > &elems , const std::vector< std::string > &comments ) + { + PlyFile *ply = NULL; + { + float version; + std::vector< std::string > elist( elems.size() ); + for( unsigned int i=0 ; i( elems[i] ); + ply = PlyFile::Write( fileName , elist , fileType , version ); + } + if( !ply ) ERROR_OUT( "Could not open ply for writing: " , fileName ); + for( unsigned int i=0 ; ielement_count( std::get<0>( elems[i] ) , std::get<1>( elems[i] ) ); + const std::vector< PlyProperty > &props = std::get<2>( elems[i] ); + for( unsigned int j=0 ; jdescribe_property( std::get<0>( elems[i] ) , &props[j] ); + } + + for( int i=0 ; iput_comment( comments[i] ); + ply->header_complete(); + + return ply; + } + + inline PlyFile *ReadHeader( std::string fileName , int &fileType , std::vector< std::tuple< std::string , size_t , std::vector< PlyProperty > > > &elems ) + { + std::vector< std::string > comments; + return ReadHeader( fileName , fileType , elems , comments ); + } + + inline PlyFile *WriteHeader( std::string fileName , int fileType , const std::vector< std::tuple< std::string , size_t , std::vector< PlyProperty > > > &elems ) + { + std::vector< std::string > comments; + return WriteHeader( fileName , fileType , elems , comments ); + } + template< typename VertexFactory > inline int ReadVertexHeader( std::string fileName , const VertexFactory &vFactory , bool *readFlags ) { @@ -143,7 +200,7 @@ namespace PLY template< typename VertexFactory , typename Index > void ReadPolygons( std::string fileName , const VertexFactory &vFactory , std::vector< typename VertexFactory::VertexType > &vertices , std::vector< std::vector< Index > > &polygons , int &file_type , std::vector< std::string > &comments , bool *readFlags ) { - std::vector< std::string > elist = { std::string( "vertex" ) , std::string( "face" ) }; + std::vector< std::string > elist; float version; PlyFile *ply = PlyFile::Read( fileName , elist , file_type , version ); diff --git a/Src/PointInterpolant.cpp b/Src/PointInterpolant.cpp index 9a9efd06..a5bab1ad 100644 --- a/Src/PointInterpolant.cpp +++ b/Src/PointInterpolant.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +Copyright (c) 2014, Michael Kazhdan All rights reserved. Redistribution and use in source and binary forms, with or without modification, @@ -383,7 +383,8 @@ void ExtractMesh std::vector< std::string > noComments; typename VertexFactory::Transform unitCubeToModelTransform( unitCubeToModel ); - PLY::WritePolygons< VertexFactory , node_index_type , Real , Dim >( Out.value , vertexFactory , mesh , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , NoComments.set ? noComments : comments , unitCubeToModelTransform ); + auto xForm = [&]( typename VertexFactory::VertexType &v ){ unitCubeToModelTransform.inPlace(v); }; + PLY::WritePolygons< VertexFactory , node_index_type , Real , Dim >( Out.value , vertexFactory , mesh , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , NoComments.set ? noComments : comments , xForm ); delete mesh; } diff --git a/Src/PointPartition.h b/Src/PointPartition.h new file mode 100644 index 00000000..a0c7c66a --- /dev/null +++ b/Src/PointPartition.h @@ -0,0 +1,161 @@ +/* +Copyright (c) 2023, 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 POINT_PARTITION_INCLUDED +#define POINT_PARTITION_INCLUDED + +#include +#include +#include +#include "Streams.h" +#include "MyMiscellany.h" +#include "Ply.h" +#include "VertexStream.h" + +#define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth +#define BUFFER_IO (1<<14) // Buffer the points before reading/writing +//#define AXIS_ONLY_ALIGNMENT // Only align to the three coordinate axes (should be disabled) + + +namespace PointPartition +{ + template< typename Real , unsigned int Dim > + struct PointSetInfo + { + std::string header; + unsigned filesPerDir; + XForm< Real , Dim+1 > modelToUnitCube; + std::vector< size_t > pointsPerSlab; + std::vector< PlyProperty > auxiliaryProperties; + + PointSetInfo( void ); + PointSetInfo( unsigned int slabs ); + PointSetInfo( BinaryStream &stream ); + + void write( BinaryStream &stream ) const; + }; + + template< typename Real > + struct Extent + { +#ifdef AXIS_ONLY_ALIGNMENT + static const unsigned int DirectionN = 3; +#else // !AXIS_ONLY_ALIGNMENT + static const unsigned int DirectionN = 9; +#endif // AXIS_ONLY_ALIGNMENT + static const Point< Real , 3 > Directions[ DirectionN ]; + static const unsigned int Frames[DirectionN][3]; + std::pair< Real , Real > extents[DirectionN]; + + Extent( void ); + void add( Point< Real , 3 > p ); + Extent operator + ( const Extent &e ) const; + }; + + struct Partition + { + Partition( void ); + Partition( unsigned int dCount , const std::vector< size_t > &slabSizes ); + +#ifdef ADAPTIVE_PADDING + void optimize( bool useMax ); + std::pair< unsigned int , unsigned int > range( unsigned int i ) const; + size_t size( unsigned int i ) const; + void printDistribution( void ) const; + double l2Energy( void ) const; + double maxEnergy( void ) const; +#else // !ADAPTIVE_PADDING + void optimize( bool useMax , unsigned int padSize ); + std::pair< unsigned int , unsigned int > range( unsigned int i , unsigned int padSize ) const; + size_t size( unsigned int i , unsigned int padSize ) const; + void printDistribution( unsigned int padSize ) const; + double l2Energy( unsigned int padSize ) const; + double maxEnergy( unsigned int padSize ) const; +#endif // ADAPTIVE_PADDING + size_t size( void ) const; + unsigned int slabs( void ) const; + + protected: + std::vector< unsigned int > _starts; + std::vector< size_t > _slabSizes; + }; + + long ReadPLYProperties( FILE *fp , std::vector< PlyProperty > &properties ); + long ReadPLYProperties( const char *fileName , std::vector< PlyProperty > &properties ); + long WritePLYProperties( FILE *fp , const std::vector< PlyProperty > &properties ); + long WritePLYProperties( const char *fileName , const std::vector< PlyProperty > &properties ); + + template< typename InputFactory > + struct BufferedBinaryInputDataStream : public InputDataStream< typename InputFactory::VertexType > + { + + typedef typename InputFactory::VertexType Data; + BufferedBinaryInputDataStream( const char *fileName , const InputFactory &factory , size_t bufferSize ); + ~BufferedBinaryInputDataStream( void ); + void reset( void ); + bool next( Data &d ); + protected: + size_t _bufferSize , _current , _inBuffer , _elementSize; + Pointer( char ) _buffer; + FILE *_fp; + const InputFactory &_factory; + long _inset; + }; + + template< typename OutputFactory > + struct BufferedBinaryOutputDataStream : public OutputDataStream< typename OutputFactory::VertexType > + { + typedef typename OutputFactory::VertexType Data; + BufferedBinaryOutputDataStream( const char *fileName , const OutputFactory &factory , size_t bufferSize ); + ~BufferedBinaryOutputDataStream( void ); + void reset( void ); + void next( const Data &d ); + protected: + size_t _bufferSize , _current , _elementSize; + Pointer( char ) _buffer; + FILE *_fp; + const OutputFactory &_factory; + long _inset; + }; + + void RemovePointSlabDirs( std::string dir ); + static void CreatePointSlabDirs( std::string dir , unsigned int count , unsigned int filesPerDir ); + + std::string FileDir( std::string dir , std::string header ); + std::string FileDir( std::string dir , std::string header , unsigned int clientIndex ); + + std::string FileName( std::string dir , unsigned int slab , unsigned int slabs , unsigned int filesPerDir ); + std::string FileName( std::string dir , std::string header , unsigned int slab , unsigned int slabs , unsigned int filesPerDir ); + std::string FileName( std::string dir , std::string header , unsigned int clientIndex , unsigned int slab , unsigned int slabs , unsigned int filesPerDir ); + + std::string PointSetInfoName( std::string dir , std::string header ); + +#include "PointPartition.inl" +} + +#endif // POINT_PARTITION_INCLUDED \ No newline at end of file diff --git a/Src/PointPartition.inl b/Src/PointPartition.inl new file mode 100644 index 00000000..a7302eac --- /dev/null +++ b/Src/PointPartition.inl @@ -0,0 +1,659 @@ +/* +Copyright (c) 2023, 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. +*/ + +std::string FileDir( std::string dir , std::string header ) +{ + if( dir.back()!=FileSeparator ) dir += std::string(1,FileSeparator); + return dir + header; +} + +std::string FileDir( std::string dir , std::string header , unsigned int clientIndex ) +{ + std::stringstream sStream; + sStream << header << "_" << clientIndex; + return FileDir( dir , sStream.str() ); +} + +std::string FileName( std::string dir , unsigned int slab , unsigned int slabs , unsigned int filesPerDir ) +{ + if( filesPerDir<=1 ) ERROR_OUT( "Need at least two files per directory" ); + + if( !dir.length() ) dir = std::string( "." ); + if( dir.back()!=FileSeparator ) dir.push_back( FileSeparator ); + + std::vector< unsigned int > factors; + factors.push_back(slab); + while( slabs>filesPerDir ) + { + factors.push_back( (slab / filesPerDir) % filesPerDir ); + slab /= filesPerDir; + slabs /= filesPerDir; + } + + std::stringstream sStream; + sStream << dir; + + for( unsigned int i=(unsigned int)factors.size()-1 ; i!=0 ; i-- ) sStream << factors[i] << std::string(1,FileSeparator); + sStream << factors[0] << ".points"; + return sStream.str(); +} + +std::string FileName( std::string dir , std::string header , unsigned int slab , unsigned int slabs , unsigned int filesPerDir ) +{ + return FileName( FileDir( dir , header ) , slab , slabs , filesPerDir ); +} + +std::string FileName( std::string dir , std::string header , unsigned int clientIndex , unsigned int slab , unsigned int slabs , unsigned int filesPerDir ) +{ + return FileName( FileDir( dir , header , clientIndex ) , slab , slabs , filesPerDir ); +} + +std::string PointSetInfoName( std::string dir , std::string header ) +{ + if( dir.back()==FileSeparator ) return dir + header + std::string( ".psi" ); + else return dir + std::string(1,FileSeparator) + header + std::string( ".psi" ); +} + + + +//////////// +// Extent // +//////////// +template< typename Real > +Extent< Real >::Extent( void ) +{ + Real inf = std::numeric_limits< Real >::infinity(); + for( unsigned int d=0 ; d +void Extent< Real >::add( Point< Real , 3 > p ) +{ + for( unsigned int d=0 ; d( extents[d].first , Point< Real , 3 >::Dot( p , Directions[d] ) ); + extents[d].second = std::max< Real >( extents[d].second , Point< Real , 3 >::Dot( p , Directions[d] ) ); + } +} + +template< typename Real > +Extent< Real > Extent< Real >::operator + ( const Extent< Real > &e ) const +{ + Extent _e; + for( unsigned int d=0 ; d( extents[d].first , e.extents[d].first ); + _e.extents[d].second = std::max< Real >( extents[d].second , e.extents[d].second ); + } + return _e; +} + +template< typename Real > +const Point< Real , 3 > Extent< Real >::Directions[] = +{ + Point< Real , 3 >( 1 , 0 , 0 ) , // 0 + Point< Real , 3 >( 0 , 1 , 0 ) , // 1 + Point< Real , 3 >( 0 , 0 , 1 ) , // 2 +#ifdef AXIS_ONLY_ALIGNMENT +#else // !AXIS_ONLY_ALIGNMENT + Point< Real , 3 >( 1 , 1 , 0 )/(Real)sqrt(2.) , // 3 + Point< Real , 3 >( 1 , 0 , 1 )/(Real)sqrt(2.) , // 4 + Point< Real , 3 >( 0 , 1 , 1 )/(Real)sqrt(2.) , // 5 + Point< Real , 3 >( 1 ,-1 , 0 )/(Real)sqrt(2.) , // 6 + Point< Real , 3 >( 1 , 0 ,-1 )/(Real)sqrt(2.) , // 7 + Point< Real , 3 >( 0 , 1 ,-1 )/(Real)sqrt(2.) // 8 +#endif +}; + +template< typename Real > +const unsigned int Extent< Real >::Frames[ DirectionN ][3] = +{ + {1,2,0} , + {2,0,1} , + {0,1,2} , +#ifdef AXIS_ONLY_ALIGNMENT +#else // !AXIS_ONLY_ALIGNMENT + {2,6,3} , + {7,1,4} , + {0,8,5} , + {3,2,6} , + {1,4,7} , + {5,0,8} +#endif // AXIS_ONLY_ALIGNMENT +}; + +template< typename Real > +std::ostream &operator << ( std::ostream &os , const Extent< Real > &e ) +{ + for( unsigned int d=0 ; d::DirectionN ; d++ ) + { + os << Extent< Real >::Directions[d] << " : [ " << e.extents[d].first << " , " << e.extents[d].second << " ]"; + os << "\t(" << e.extents[d].second - e.extents[d].first << " )" << std::endl; + } + return os; +} + + +////////////////// +// PointSetInfo // +////////////////// +template< typename Real , unsigned int Dim > +PointSetInfo< Real , Dim >::PointSetInfo( void ) : modelToUnitCube( XForm< Real , Dim+1 >::Identity() ) , filesPerDir(-1) {} + +template< typename Real , unsigned int Dim > +PointSetInfo< Real , Dim >::PointSetInfo( unsigned int slabs ) : modelToUnitCube( XForm< Real , Dim+1 >::Identity() ) , filesPerDir(-1) +{ + pointsPerSlab.resize( slabs , 0 ); +} + +template< typename Real , unsigned int Dim > +PointSetInfo< Real , Dim >::PointSetInfo( BinaryStream &stream ) +{ + if( !stream.read( header ) ) ERROR_OUT( "Failed to read header" ); + if( !stream.read( modelToUnitCube ) ) ERROR_OUT( "Failed to read model-to-unit-cube transform" ); + if( !stream.read( pointsPerSlab ) ) ERROR_OUT( "Failed to read points-per-slab" ); + { + size_t sz; + if( !stream.read( sz ) ) ERROR_OUT( "Failed to read number of auxiliary properties" ); + auxiliaryProperties.resize(sz); + for( size_t i=0 ; i +void PointSetInfo< Real , Dim >::write( BinaryStream &stream ) const +{ + stream.write( header ); + stream.write( modelToUnitCube ); + stream.write( pointsPerSlab ); + { + size_t sz = auxiliaryProperties.size(); + stream.write( sz ); + for( size_t i=0 ; i_filesPerDir ) _filesPerDir *= filesPerDir , depth++; + } + + auto _exp = []( unsigned int filesPerDir , unsigned int depth ) + { + unsigned int e = 1; + for( unsigned int d=0 ; d MakeDirs = [&]( std::string dir , unsigned int count , unsigned int depth , unsigned int filesPerDir ) + { + if( depth ) + { + unsigned int _filesPerDir = _exp( filesPerDir , depth ); + for( unsigned int i=0 ; i*_filesPerDir( count-(i*_filesPerDir) , _filesPerDir ) , depth-1 , filesPerDir ); + } + } + }; + MakeDirs( dir , count , depth , filesPerDir ); +} +/////////////// +// Partition // +/////////////// +// Energy: +// An object supporting bool operator < ( const Energy & ) const; +template< typename Energy > +struct _DynamicProgrammingPartition +{ + // EnergyFunctor: + // A functor that that takes the start and end of the range and returns the associated energy + // MergeFunctor: + // A functor that takes two energies and turns them into one + template< typename EnergyFunctor , typename MergeFunctor > + _DynamicProgrammingPartition( const EnergyFunctor &energy , const MergeFunctor &merge , unsigned int slabs , unsigned int interiorBoundaries ) + { + _solutions.resize( slabs+1 ); + for( unsigned int start=0 ; start<_solutions.size() ; start++ ) + { + _solutions[start].resize( slabs+1 ); + for( unsigned int end=start+1 ; end<_solutions[start].size() ; end++ ) _solutions[start][end].resize( interiorBoundaries+1 ); + } + _energies.resize( slabs+1 ); + for( unsigned int i=0 ; i<=slabs ; i++ ) + { + _energies[i].resize( slabs+1 ); + for( unsigned int j=i ; j<=slabs ; j++ ) _energies[i][j] = energy( i , j ); + } + _getSolution( merge , 0 , slabs , interiorBoundaries , Energy() ); + } + + std::pair< Energy , std::vector< unsigned int > > solution( void ) const + { + std::pair< Energy , std::vector< unsigned int > > sol; + unsigned int start = 0 , end = (unsigned int)_solutions[0].size()-1; + unsigned int interiorBoundaries = (unsigned int)_solutions[start][end].size()-1; + sol.first = _solutions[0].back().back().e; + while( _solutions[start][end][interiorBoundaries].idx!=-1 ) + { + sol.second.push_back( _solutions[start][end][interiorBoundaries].idx ); + start = _solutions[start][end][interiorBoundaries].idx; + interiorBoundaries--; + } + return sol; + } + + template< typename EnergyFunctor , typename MergeFunctor > + static std::pair< Energy , std::vector< unsigned int > > Partition( const EnergyFunctor &energy , const MergeFunctor &merge , unsigned int slabs , unsigned int interiorBoundaries ) + { + return _DynamicProgrammingPartition( energy , merge , slabs , interiorBoundaries ).solution(); + } + +protected: + struct _Solution + { + unsigned int idx; + Energy e; + _Solution( void ) : idx(-1){} + }; + + + // A solution is indexed by the start index, end index, and the number of interior boundaries + // The extent is defined by [start,end) + std::vector< std::vector< std::vector< _Solution > > > _solutions; + std::vector< std::vector< Energy > > _energies; + template< typename MergeFunctor > + Energy _getSolution( const MergeFunctor &merge , unsigned int start , unsigned int end , unsigned int interiorBoundaries , Energy minEnergy ) + { + // Assuming that: + // start &slabSizes ) : _slabSizes( slabSizes ) +{ + unsigned int sCount = (unsigned int)_slabSizes.size(); + _starts.resize( dCount-1 ); + for( unsigned int i=1 ; ipadSize ? (start-padSize) : 0; }; + auto paddedEnd = [&]( unsigned int end ){ return ( end+padSize<=_slabSizes.size() ) ? (end+padSize) : (unsigned int)_slabSizes.size(); }; +#endif // ADAPTIVE_PADDING + + struct L2Energy + { + double e; + L2Energy( void ) : e( std::numeric_limits::infinity() ) {} + L2Energy( double e ) : e(e) {} + bool operator < ( const L2Energy &energy ) const { return e e; + MaxEnergy( void ){} + MaxEnergy( double e ) { this->e.resize(1,e); } + bool operator < ( const MaxEnergy &energy ) const + { + for( unsigned int i=0 ; ienergy.e[i] ) return false; + } + return false; + } + }; + + auto energy = [&]( unsigned int start , unsigned int end ) + { + double e = 0; +#ifdef ADAPTIVE_PADDING + for( unsigned int i=start ; ie2; } ); + return e; + }; + + if( useMax ) _starts = _DynamicProgrammingPartition< MaxEnergy >::Partition( maxEnergy , maxMerge , (unsigned)_slabSizes.size() , (unsigned int)_starts.size() ).second; + else _starts = _DynamicProgrammingPartition< L2Energy >::Partition( l2Energy , l2Merge , (unsigned)_slabSizes.size() , (unsigned int)_starts.size() ).second; +} + +#ifdef ADAPTIVE_PADDING +std::pair< unsigned int , unsigned int > Partition::range( unsigned int i ) const +#else // !ADAPTIVE_PADDING +std::pair< unsigned int , unsigned int > Partition::range( unsigned int i , unsigned int padSize ) const +#endif // ADAPTIVE_PADDING +{ + unsigned int begin = i==0 ? 0 : _starts[i-1]; + unsigned int end = i==_starts.size() ? (unsigned int)_slabSizes.size() : _starts[i]; +#ifdef ADAPTIVE_PADDING +#else // !ADAPTIVE_PADDING + if( begin_slabSizes.size() ) end = (unsigned int)_slabSizes.size(); + else end += padSize; +#endif // ADAPTIVE_PADDING + return std::pair< unsigned int , unsigned int >( begin , end ); +} + +#ifdef ADAPTIVE_PADDING +size_t Partition::size( unsigned int i ) const +#else // !ADAPTIVE_PADDING +size_t Partition::size( unsigned int i , unsigned int padSize ) const +#endif // ADAPTIVE_PADDING +{ + if( i>_starts.size() ) ERROR_OUT( "Index out of bounds: 0 <= " , i , " <= " , _starts.size() ); +#ifdef ADAPTIVE_PADDING + std::pair< unsigned int , unsigned int > r = range( i ); +#else // !ADAPTIVE_PADDING + std::pair< unsigned int , unsigned int > r = range( i , padSize ); +#endif // ADAPTIVE_PADDING + size_t count = 0; + for( unsigned int j=r.first ; j r = range(i); + std::cout << "Slab[ " << i << " ] [ " << r.first << " , " << r.second << " ) " << size(i) << std::endl; +#else // !ADAPTIVE_PADDING + std::pair< unsigned int , unsigned int > r = range(i,0) , _r = range( i , padSize ); + if( padSize ) + std::cout << "Slab[ " << i << " ] [ " << r.first << " , " << r.second << " ) [ " << _r.first << " , " << _r.second << " ) " << size(i,0) << " " << size(i,padSize) << std::endl; + else + std::cout << "Slab[ " << i << " ] [ " << r.first << " , " << r.second << " ) " << size(i,0) << std::endl; +#endif // ADAPTIVE_PADDING + } +} + +#ifdef ADAPTIVE_PADDING +double Partition::l2Energy( void ) const +#else // !ADAPTIVE_PADDING +double Partition::l2Energy( unsigned int padSize ) const +#endif // ADAPTIVE_PADDING +{ + double e = 0; + for( unsigned int i=0 ; i<=_starts.size() ; i++ ) + { +#ifdef ADAPTIVE_PADDING + double d = (double)size(i); +#else // !ADAPTIVE_PADDING + double d = (double)size(i,padSize); +#endif // ADAPTIVE_PADDING + e += d*d; + } + return sqrt(e); +} + +#ifdef ADAPTIVE_PADDING +double Partition::maxEnergy( void ) const +#else // !ADAPTIVE_PADDING +double Partition::maxEnergy( unsigned int padSize ) const +#endif // ADAPTIVE_PADDING +{ + double e = 0; +#ifdef ADAPTIVE_PADDING + for( unsigned int i=0 ; i<=_starts.size() ; i++ ) e = std::max< double >( e , (double)size(i) ); +#else // !ADAPTIVE_PADDING + for( unsigned int i=0 ; i<=_starts.size() ; i++ ) e = std::max< double >( e , (double)size(i,padSize) ); +#endif // ADAPTIVE_PADDING + return e; +} + +unsigned int Partition::slabs( void ) const { return (unsigned int)_slabSizes.size(); } + +/////////////////////////////// +// Read/Write Ply Properties // +/////////////////////////////// +long ReadPLYProperties( FILE *fp , std::vector< PlyProperty > &properties ) +{ + size_t sz; + if( fread( &sz , sizeof( size_t ) , 1 , fp )!=1 ) ERROR_OUT( "Failed to read property size" ); + properties.resize( sz ); + FileStream fs(fp); + for( size_t i=0 ; i &properties ) +{ + FILE *fp = fopen( fileName , "rb" ); + if( !fp ) ERROR_OUT( "Could not open file for reading: " , fileName ); + long pos = ReadPLYProperties( fp , properties ); + fclose( fp ); + return pos; +} + +long WritePLYProperties( FILE *fp , const std::vector< PlyProperty > &properties ) +{ + size_t sz = properties.size(); + fwrite( &sz , sizeof( size_t ) , 1 , fp ); + FileStream fs(fp); + for( size_t i=0 ; i &properties ) +{ + FILE *fp = fopen( fileName , "wb" ); + if( !fp ) ERROR_OUT( "Could not open file for writing: " , fileName ); + long pos = WritePLYProperties( fp , properties ); + fclose( fp ); + return pos; +} + +/////////////////////////////////// +// BufferedBinaryInputDataStream // +/////////////////////////////////// +template< typename InputFactory > +BufferedBinaryInputDataStream< InputFactory >::BufferedBinaryInputDataStream( const char *fileName , const InputFactory &factory , size_t bufferSize ) : _factory(factory) , _bufferSize(bufferSize) , _current(0) , _inBuffer(0) +{ + + if( !_bufferSize ) + { + WARN_ONCE( "BufferSize cannot be zero , setting to one" ); + _bufferSize = 1; + } + _elementSize = _factory.bufferSize(); + _buffer = AllocPointer< char >( _elementSize*_bufferSize ); + _fp = fopen( fileName , "rb" ); + if( !_fp ) ERROR_OUT( "Could not open file for reading: " , fileName ); + std::vector< PlyProperty > properties; + _inset = ReadPLYProperties( _fp , properties ); +} + +template< typename InputFactory > +BufferedBinaryInputDataStream< InputFactory >::~BufferedBinaryInputDataStream( void ) +{ + FreePointer( _buffer ); + fclose( _fp ); +} + +template< typename InputFactory > +void BufferedBinaryInputDataStream< InputFactory >::reset( void ) +{ + fseek( _fp , _inset , SEEK_SET ); + _current = 0; + _inBuffer = 0; +} + +template< typename InputFactory > +bool BufferedBinaryInputDataStream< InputFactory >::next( Data &d ) +{ + if( _current==_inBuffer ) + { + _inBuffer = fread( _buffer , _elementSize , _bufferSize , _fp ); + _current = 0; + } + if( !_inBuffer ) return false; + + _factory.fromBuffer( _buffer + _elementSize*_current , d ); + _current++; + + return true; +} + +//////////////////////////////////// +// BufferedBinaryOutputDataStream // +//////////////////////////////////// + +template< typename OutputFactory > +BufferedBinaryOutputDataStream< OutputFactory >::BufferedBinaryOutputDataStream( const char *fileName , const OutputFactory &factory , size_t bufferSize ) : _factory(factory) , _bufferSize(bufferSize) , _current(0) +{ + if( !_bufferSize ) + { + WARN_ONCE( "BufferSize cannot be zero , setting to one" ); + _bufferSize = 1; + } + _elementSize = _factory.bufferSize(); + _buffer = AllocPointer< char >( _elementSize*_bufferSize ); + _fp = fopen( fileName , "wb" ); + if( !_fp ) ERROR_OUT( "Could not open file for writing: " , fileName ); + std::vector< PlyProperty > properties( factory.plyWriteNum() ); + for( unsigned int i=0 ; i +BufferedBinaryOutputDataStream< OutputFactory >::~BufferedBinaryOutputDataStream( void ) +{ + if( _current ) fwrite( _buffer , _elementSize , _current , _fp ); + FreePointer( _buffer ); + fclose( _fp ); +} + +template< typename OutputFactory > +void BufferedBinaryOutputDataStream< OutputFactory >::reset( void ) +{ + fseek( _fp , _inset , SEEK_SET ); + _current = 0; +} + +template< typename OutputFactory > +void BufferedBinaryOutputDataStream< OutputFactory >::next( const Data &d ) +{ + if( _current==_bufferSize ) + { + fwrite( _buffer , _elementSize , _bufferSize , _fp ); + _current = 0; + } + _factory.toBuffer( d , _buffer + _elementSize*_current ); + _current++; +} diff --git a/Src/PointPartitionClientServer.h b/Src/PointPartitionClientServer.h new file mode 100644 index 00000000..6bf719db --- /dev/null +++ b/Src/PointPartitionClientServer.h @@ -0,0 +1,70 @@ +/* +Copyright (c) 2023, 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 POINT_PARTITION_CLIENT_SERVER_INCLUDED +#define POINT_PARTITION_CLIENT_SERVER_INCLUDED + +#include +#include "PointPartition.h" +#include "Socket.h" +#include "MyMiscellany.h" +#include "CmdLineParser.h" + + +namespace PointPartitionClientServer +{ + template< typename Real > + struct ClientPartitionInfo + { + std::string in , tempDir , outDir , outHeader; + unsigned int slabs , filesPerDir , bufferSize , clientCount; + Real scale; + bool verbose; + + ClientPartitionInfo( void ); + ClientPartitionInfo( BinaryStream &stream ); + + void write( BinaryStream &stream ) const; + }; + + + template< typename Real , unsigned int Dim > + std::pair< PointPartition::PointSetInfo< Real , Dim > , PointPartition::Partition > RunServer + ( + std::vector< Socket > &clientSockets , + ClientPartitionInfo< Real > clientPartitionInfo , + bool loadBalance + ); + + template< typename Real , unsigned int Dim > + void RunClients( std::vector< Socket > &serverSockets ); + +#include "PointPartitionClientServer.inl" +} + +#endif // POINT_PARTITION_CLIENT_SERVER_INCLUDED \ No newline at end of file diff --git a/Src/PointPartitionClientServer.inl b/Src/PointPartitionClientServer.inl new file mode 100644 index 00000000..56e56536 --- /dev/null +++ b/Src/PointPartitionClientServer.inl @@ -0,0 +1,471 @@ +/* +Copyright (c) 2023, 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. +*/ + +template< typename Real , unsigned int Dim > +size_t _SampleCount( std::string in , std::vector< PlyProperty > &auxProperties ) +{ + char *ext = GetFileExtension( in.c_str() ); + if( strcasecmp( ext , "ply" ) ) ERROR_OUT( "Only .ply files supported: " , in ); + delete[] ext; + + size_t vNum; + typedef VertexFactory::Factory< Real , typename VertexFactory::PositionFactory< Real , Dim > , typename VertexFactory::NormalFactory< Real , Dim > > Factory; + Factory factory; + bool *readFlags = new bool[ factory.plyReadNum() ]; + int fileType = PLY::ReadVertexHeader( in , factory , readFlags , auxProperties , vNum ); + if( fileType==PLY_ASCII ) ERROR_OUT( "Point set must be in binary format" ); + if( !factory.template plyValidReadProperties<0>( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); + if( !factory.template plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain normals" ); + delete[] readFlags; + return vNum; +} + +template< typename Factory , typename VertexFunctor /* = std::function< void ( Factory::VertexType ) > */ > +void _ProcessPLY( std::string in , std::pair< size_t , size_t > range , const Factory &factory , VertexFunctor vf ) +{ + using Vertex = typename Factory::VertexType; + std::vector< std::string > elist = { std::string( "vertex" ) }; + + float version; + int file_type; + + PlyFile *ply = PlyFile::Read( in , elist , file_type , version ); + if( !ply ) ERROR_OUT( "Could not create ply file for reading: " , in ); + if( file_type==PLY_ASCII ) ERROR_OUT( "Only binary file type supported" ); + + size_t vCount; + std::vector< PlyProperty > plist = ply->get_element_description( std::string( "vertex" ) , vCount ); + if( !plist.size() ) ERROR_OUT( "Could not read element properties: vertex" ); + if( range.second==-1 ) range.second = vCount; + if( range.first>=range.second ) ERROR_OUT( "Bad Range: [ " , range.first , " , " , range.second , " )" ); + if( range.second>vCount ) + { + WARN( "Max range too large, resetting" ); + range.second = vCount; + } + + size_t leftToReadCount = range.second - range.first; + size_t vSize = factory.isStaticallyAllocated() ? sizeof( Vertex ) : factory.bufferSize(); + + for( unsigned int i=0 ; iget_property( std::string( "vertex" ) , &prop ); + } + + size_t sizeOnDisk = 0; + for( unsigned int i=0 ; ifp , sizeOnDisk * range.first , SEEK_CUR ); +#else // !_WIN32 && !_WIN64 + fseek( ply->fp , sizeOnDisk * range.first , SEEK_CUR ); +#endif // _WIN32 || _WIN64 + + Vertex vertex = factory(); + Pointer( char ) buffer = NewPointer< char >( factory.bufferSize() ); + for( size_t i=range.first ; iget_element( (void *)&vertex ); + else + { + ply->get_element( PointerAddress( buffer ) ); + factory.fromBuffer( buffer , vertex ); + } + vf( vertex ); + } + DeletePointer( buffer ); + + delete ply; +} + +template< typename Real , unsigned int Dim , typename Factory > +void _MergeSlabs( std::string inDir , std::string outDir , std::string header , unsigned int clientCount , std::pair< unsigned int , unsigned int > slabRange , unsigned int slabs , unsigned int filesPerDir , const Factory &factory , size_t bufferSize ) +{ + using Vertex = typename Factory::VertexType; + + Vertex v = factory(); + + for( unsigned int s=slabRange.first ; s outStream( outFileName.c_str() , factory , bufferSize ); + for( unsigned int c=0 ; c inStream( inFileName.c_str() , factory , bufferSize ); + while( inStream.next( v ) ) outStream.next( v ); + } + } +} + +template< typename Real , unsigned int Dim , typename Factory > +std::vector< size_t > _PartitionIntoSlabs( std::string in , std::string dir , std::string header , unsigned int clientIndex , std::pair< size_t , size_t > range , unsigned int slabs , unsigned int filesPerDir , XForm< Real , Dim+1 > xForm , const Factory &factory , size_t bufferSize ) +{ + using Vertex = typename Factory::VertexType; + using _XForm = typename Factory::Transform; + + _XForm _xForm(xForm); + std::vector< size_t > slabSizes( slabs , 0 ); + + using OutputPointStream = OutputDataStream< Vertex >; + + std::vector< OutputPointStream * > outStreams( slabs ); + for( unsigned int s=0 ; s( fileName.c_str() , factory , bufferSize ); + } + + size_t outOfRangeCount = 0; + auto vertexFunctor = [&]( Vertex v ) + { + _xForm.inPlace( v ); + Point< Real , Dim > p = v.template get<0>(); + int slab = (int)floor( p[Dim-1] * slabs ); + if( slab>=0 && slab<(int)slabs ) + { + outStreams[slab]->next( v ); + slabSizes[slab]++; + } + else outOfRangeCount++; + }; + _ProcessPLY( in , range , factory , vertexFunctor ); + for( unsigned int i=0 ; i +PointPartition::Extent< Real > _GetExtent( std::string in , std::pair< size_t , size_t > range , const Factory &factory ) +{ + using Vertex = typename Factory::VertexType; + PointPartition::Extent< Real > extent; + _ProcessPLY( in , range , factory , [&]( const Vertex &vertex ){ extent.add( vertex.template get<0>() ); } ); + return extent; +} + +template< typename Real , unsigned int Dim > +std::vector< PlyProperty > _GetUnprocessedProperties( std::string in ) +{ + char *ext = GetFileExtension( in.c_str() ); + if( strcasecmp( ext , "ply" ) ) ERROR_OUT( "Expected .ply file" ); + delete[] ext; + + std::vector< PlyProperty > unprocessedProperties; + { + typedef VertexFactory::Factory< Real , typename VertexFactory::PositionFactory< Real , Dim > , typename VertexFactory::NormalFactory< Real , Dim > > Factory; + Factory factory; + bool *readFlags = new bool[ factory.plyReadNum() ]; + PLY::ReadVertexHeader( in , factory , readFlags , unprocessedProperties ); + if( !factory.template plyValidReadProperties<0>( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); + if( !factory.template plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain normals" ); + delete[] readFlags; + } + return unprocessedProperties; +} + +//////////// +// Server // +//////////// + +template< typename Real , unsigned int Dim > +std::pair< PointPartition::PointSetInfo< Real , Dim > , PointPartition::Partition > RunServer +( + std::vector< Socket > &clientSockets , + ClientPartitionInfo< Real > clientPartitionInfo , + bool loadBalance +) +{ + Timer timer; + clientPartitionInfo.clientCount = ( unsigned int )clientSockets.size(); + for( unsigned int c=0 ; c pointSetInfo( clientPartitionInfo.slabs ); + pointSetInfo.header = clientPartitionInfo.outHeader; + pointSetInfo.filesPerDir = clientPartitionInfo.filesPerDir; + + // Create the directory for the slabs + PointPartition::CreatePointSlabDirs( PointPartition::FileDir( clientPartitionInfo.outDir , clientPartitionInfo.outHeader ) , clientPartitionInfo.slabs , clientPartitionInfo.filesPerDir ); + + ///////////// + // Phase 1 // + ///////////// + // Get the number of samples + size_t sampleCount = _SampleCount< Real , Dim >( clientPartitionInfo.in , pointSetInfo.auxiliaryProperties ); + if( clientPartitionInfo.verbose ) std::cout << "Samples: " << sampleCount << std::endl; + + // Send the partitions to the clients + for( unsigned int c=0 ; c e; + unsigned int idx; + { + for( unsigned int c=0 ; c _e; + SocketStream( clientSockets[c] ).read( _e ); + e = e + _e; + } + idx = 0; + for( unsigned int d=1 ; d::DirectionN ; d++ ) if( e.extents[d].second - e.extents[d].first > e.extents[idx].second - e.extents[idx].first ) idx = d; + } + + // Compute the transformation taking the points to the unit cube + { + XForm< Real , Dim+1 > R = XForm< Real , Dim+1 >::Identity(); + for( unsigned int c=0 ; c::Directions[ PointPartition::Extent< Real >::Frames[idx][c] ][r]; + + Point< Real , Dim > bBox[2]; + for( unsigned int d=0 ; d<3 ; d++ ) bBox[0][d] = e.extents[ PointPartition::Extent< Real >::Frames[idx][d] ].first , bBox[1][d] = e.extents[ PointPartition::Extent< Real >::Frames[idx][d] ].second; + + pointSetInfo.modelToUnitCube = GetBoundingBoxXForm( bBox[0] , bBox[1] , clientPartitionInfo.scale ) * R; + } + + // Send the transformation to the clients + for( unsigned int c=0 ; c slabSizes; + SocketStream( clientSockets[c] ).read( slabSizes ); + if( slabSizes.size()!=clientPartitionInfo.slabs ) ERROR_OUT( "Unexpected number of slabs: " , slabSizes.size() , " != " , clientPartitionInfo.slabs ); + for( unsigned int i=0 ; i range = pointPartition.range( c ); + if( clientPartitionInfo.verbose ) std::cout << "Range[ " << c << " ]: [ " << range.first << " , " << range.second << " )" << std::endl; + SocketStream( clientSockets[c] ).write( range ); + } + + // Check that the clients are done + for( unsigned int c=0 ; c +void _RunClients +( + ClientPartitionInfo< Real > clientPartitionInfo , + const Factory &factory , + std::vector< Socket > &serverSockets +) +{ + std::vector< unsigned int > clientIndices( serverSockets.size() ); + + for( unsigned int c=0 ; c > ranges( serverSockets.size() ); + for( unsigned int i=0 ; i e = _GetExtent< Real , Dim >( clientPartitionInfo.in , ranges[i] , factory ); + SocketStream( serverSockets[i] ).write( e ); + if( clientPartitionInfo.verbose ) std::cout << "Sent extent: " << MemoryInfo::PeakMemoryUsageMB() << " (MB)" << std::endl; + } + + ///////////// + // Phase 2 // + ///////////// + for( unsigned int i=0 ; i xForm; + SocketStream( serverSockets[i] ).read( xForm ); + if( clientPartitionInfo.verbose ) std::cout << "Got transform: " << MemoryInfo::PeakMemoryUsageMB() << " (MB)" << std::endl; + + PointPartition::CreatePointSlabDirs( PointPartition::FileDir( clientPartitionInfo.tempDir , clientPartitionInfo.outHeader , clientIndices[i] ) , clientPartitionInfo.slabs , clientPartitionInfo.filesPerDir ); + std::vector< size_t > slabSizes = _PartitionIntoSlabs< Real , Dim >( clientPartitionInfo.in , clientPartitionInfo.tempDir , clientPartitionInfo.outHeader , clientIndices[i] , ranges[i] , clientPartitionInfo.slabs , clientPartitionInfo.filesPerDir , xForm , factory , clientPartitionInfo.bufferSize ); + SocketStream( serverSockets[i] ).write( slabSizes ); + if( clientPartitionInfo.verbose ) std::cout << "Wrote slab sizes: " << MemoryInfo::PeakMemoryUsageMB() << " (MB)" << std::endl; + } + + ///////////// + // Phase 3 // + ///////////// + for( unsigned int i=0 ; i slabRange; + SocketStream( serverSockets[i] ).read( slabRange ); + if( clientPartitionInfo.verbose ) std::cout << "Slab range: [ " << slabRange.first << " , " << slabRange.second << " )" << std::endl; + _MergeSlabs< Real , Dim >( clientPartitionInfo.tempDir , clientPartitionInfo.outDir , clientPartitionInfo.outHeader , clientPartitionInfo.clientCount , slabRange , clientPartitionInfo.slabs , clientPartitionInfo.filesPerDir , factory , clientPartitionInfo.bufferSize ); + if( clientPartitionInfo.verbose ) std::cout << "Merged slabs: " << MemoryInfo::PeakMemoryUsageMB() << " (MB)" << std::endl; + + // Notify the server that you're done + unsigned int done = 1; + SocketStream( serverSockets[i] ).write( done ); + } + + for( unsigned int i=0 ; i +void RunClients( std::vector< Socket > &serverSockets ) +{ + ClientPartitionInfo< Real > clientPartitionInfo; + for( unsigned int i=0 ; i( serverSocketStream ); + } + std::vector< PlyProperty > unprocessedProperties = _GetUnprocessedProperties< Real , Dim >( clientPartitionInfo.in ); + + if( unprocessedProperties.size() ) + { + typedef VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::NormalFactory< Real , Dim > , VertexFactory::DynamicFactory< Real > > Factory; + VertexFactory::PositionFactory< Real , Dim > vFactory; + VertexFactory::NormalFactory< Real , Dim > nFactory; + VertexFactory::DynamicFactory< Real > dFactory( unprocessedProperties ); + Factory factory( vFactory , nFactory , dFactory ); + _RunClients< Real , Dim >( clientPartitionInfo , factory , serverSockets ); + } + else + { + typedef VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::NormalFactory< Real , Dim > > Factory; + Factory factory; + _RunClients< Real , Dim >( clientPartitionInfo , factory , serverSockets ); + } +} + +///////////////////////// +// ClientPartitionInfo // +///////////////////////// +template< typename Real > +ClientPartitionInfo< Real >::ClientPartitionInfo( void ) : scale((Real)1.1) , verbose(false) , slabs(0) , filesPerDir(-1) , bufferSize(BUFFER_IO) , clientCount(0) {} + +template< typename Real > +ClientPartitionInfo< Real >::ClientPartitionInfo( BinaryStream &stream ) +{ + auto ReadBool = [&]( bool &b ) + { + char _b; + if( !stream.read( _b ) ) return false; + b = _b!=0; + return true; + }; + if( !stream.read( in ) ) ERROR_OUT( "Failed to read in" ); + if( !stream.read( tempDir ) ) ERROR_OUT( "Failed to read temp dir" ); + if( !stream.read( outDir ) ) ERROR_OUT( "Failed to read out dir" ); + if( !stream.read( outHeader ) ) ERROR_OUT( "Failed to read out header" ); + if( !stream.read( slabs ) ) ERROR_OUT( "Failed to read slabs" ); + if( !stream.read( filesPerDir ) ) ERROR_OUT( "Failed to read files per dir" ); + if( !stream.read( bufferSize ) ) ERROR_OUT( "Failed to read buffer size" ); + if( !stream.read( scale ) ) ERROR_OUT( "Failed to read scale" ); + if( !stream.read( clientCount ) ) ERROR_OUT( "Failed to read client count" ); + if( !ReadBool( verbose ) ) ERROR_OUT( "Failed to read verbose flag" ); +} + +template< typename Real > +void ClientPartitionInfo< Real >::write( BinaryStream &stream ) const +{ + auto WriteBool = [&]( bool b ) + { + char _b = b ? 1 : 0; + stream.write( _b ); + }; + stream.write( in ); + stream.write( tempDir ); + stream.write( outDir ); + stream.write( outHeader ); + stream.write( slabs ); + stream.write( filesPerDir ); + stream.write( bufferSize ); + stream.write( scale ); + stream.write( clientCount ); + WriteBool( verbose ); +} diff --git a/Src/PoissonRecon.client.inl b/Src/PoissonRecon.client.inl new file mode 100644 index 00000000..61297e2b --- /dev/null +++ b/Src/PoissonRecon.client.inl @@ -0,0 +1,1535 @@ +/* +Copyright (c) 2023, 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. +*/ + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +struct Client +{ + typedef typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; + typedef typename FEMTree< Dim , Real >::template ApproximatePointInterpolationInfo< Real , 0 , ConstraintDual< Dim , Real > , SystemDual< Dim , Real > > ApproximatePointInterpolationInfo; + typedef IsotropicUIntPack< Dim , FEMDegreeAndBType< Degree , BType >::Signature > Sigs; + typedef IsotropicUIntPack< Dim , Degree > Degrees; + typedef IsotropicUIntPack< Dim , FEMDegreeAndBType< NORMAL_DEGREE , DerivativeBoundary< BType , 1 >::BType >::Signature > NormalSigs; + static const unsigned int DataSig = FEMDegreeAndBType< DATA_DEGREE , BOUNDARY_FREE >::Signature; + typedef VertexFactory::DynamicFactory< Real > AuxDataFactory; + typedef VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::Factory< Real , VertexFactory::NormalFactory< Real , Dim > , AuxDataFactory > > InputSampleFactory; + typedef VertexFactory::Factory< Real , VertexFactory::NormalFactory< Real , Dim > , AuxDataFactory > InputSampleDataFactory; + typedef InputOrientedPointStreamInfo< Real , Dim , typename AuxDataFactory::VertexType > InputPointStreamInfo; + typedef typename InputPointStreamInfo::PointAndDataType InputSampleType; + typedef typename InputPointStreamInfo::DataType InputSampleDataType; + typedef InputDataStream< InputSampleType > InputPointStream; + typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; + using BoundaryData = typename LevelSetExtractor< Dim-1 , Real , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions; + + ~Client( void ); + + static std::function< int ( Point< Real , Dim > ) > PointDepthFunctor( Real begin , Real end , unsigned int padSize , unsigned int minDepth , unsigned int maxDepth ); +protected: + unsigned int _index; + SocketStream _serverSocket; + std::pair< unsigned int , unsigned int > _range; + XForm< Real , Dim+1 > _modelToUnitCube; + FEMTree< Dim , Real > _tree; + + DensityEstimator *_density; // Phases [1,7] + SparseNodeData< Point< Real , Dim > , NormalSigs > *_normalInfo , *_paddedNormalInfo; // Phases [1,3] + std::vector< typename FEMTree< Dim , Real >::PointSample > _samples; // Phases [1,5] + std::vector< typename FEMTree< Dim , Real >::PointSample > _paddedSamples; // Phases [1,3] + std::vector< InputSampleDataType > _sampleData , _paddedSampleData; // Phases [1,3] + DenseNodeData< Real , Sigs > _constraints; // Phases [3,5] + DenseNodeData< Real , Sigs > _solution; // Phases [5,7] + ApproximatePointInterpolationInfo *_iInfo; // Phases [3,5] + SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > _dataField; // Phases [3,7] + + static std::pair< unsigned int , unsigned int > _PaddedRange( std::pair< unsigned int , unsigned int > range , unsigned int depth , unsigned int padSize ); + + struct _State3 + { + _State3( void ) : subNodes( NullPointer( FEMTreeNode ) ) {} + ~_State3( void ){ DeletePointer( subNodes ); } + Pointer( FEMTreeNode ) subNodes; + size_t subNodeCount; + DenseNodeData< Real , Sigs > constraints; + ApproximatePointInterpolationInfo iInfo; + SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > dataField; + }; + struct _State5 + { + using Data = ProjectiveData< InputSampleDataType , Real >; + + _State5( void ) : dataField(NULL) , subNodes( NullPointer( FEMTreeNode ) ) {} + ~_State5( void ) + { + DeletePointer( subNodes ); + if( dataField ) delete dataField; + } + + struct BoundaryInfo + { + using SliceSigs = typename Sigs::Reverse::Rest::Reverse; + FEMTree< Dim-1 , Real > *tree; + DenseNodeData< Real , SliceSigs > solution , dSolution; + BoundaryInfo( void ) : tree(NULL) {} + ~BoundaryInfo( void ){ delete tree; } + }; + + Pointer( FEMTreeNode ) subNodes; + DenseNodeData< Real , Sigs > solution; + SparseNodeData< Data , IsotropicUIntPack< Dim , DataSig > > *dataField; + std::pair< BoundaryInfo , BoundaryInfo > boundaryInfo; + }; + struct _State7 + { + BoundaryData *backBoundary , *frontBoundary; + std::vector< std::vector< Real > > backDValues , frontDValues; + Real isoValue; + + _State7( void ) : backBoundary(NULL) , frontBoundary(NULL) , isoValue((Real)0.5){} + ~_State7( void ) + { + delete backBoundary; + delete frontBoundary; + } + }; + + PhaseInfo _phase1( const ClientReconstructionInfo< Real , Dim > &clientReconInfo, Profiler &profiler ); + PhaseInfo _phase3( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , _State3 &state3 , Profiler &profiler ); + PhaseInfo _phase5( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , Profiler &profiler ); + PhaseInfo _phase7( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , Profiler &profiler ); + + size_t _receive1( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , Profiler &profiler ); + void _process1( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::pair< size_t , size_t > &nodeCounts , Profiler &profiler ); + size_t _send1( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , ProjectiveData< Real , Real > pointWeight , std::pair< size_t , size_t > nodeCounts , Profiler &profiler ); + + size_t _receive3( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , ProjectiveData< Real , Real > &cumulativePointWeight , Profiler &profiler ); + void _process3( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , ProjectiveData< Real , Real > cumulativePointWeight , _State3 &state3 , Profiler &profiler ); + size_t _send3( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , const _State3 &state3 , Profiler &profiler ); + + size_t _receive5( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , _State5 &state5 , Profiler &profiler ); + std::pair< double , double > _process5( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , _State5 &state5 , Profiler &profiler ); + size_t _send5( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , const _State5 &state5 , Profiler &profiler ); + + size_t _receive7( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , _State7 &state7 , Profiler &profiler ); + void _process7( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , _State7 &state7 , Profiler &profiler ); + + Client( void ); + Client( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , BinaryStream &stream , unsigned int phase ); + void _write( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , BinaryStream &stream , unsigned int phase ) const; + + template< typename _Real , unsigned int _Dim , BoundaryType _BType , unsigned int _Degree > + friend void RunClient( std::vector< Socket > &serverSockets , unsigned int sampleMS ); +}; + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +void RunClient( std::vector< Socket > &serverSockets , unsigned int sampleMS ) +{ + std::vector< SocketStream > serverSocketStreams( serverSockets.size() ); + for( unsigned int i=0 ; i cacheFiles; + ClientReconstructionInfo< Real , Dim > clientReconInfo; + std::vector< unsigned int > clientIndices( serverSocketStreams.size() ); + + for( unsigned int i=0 ; i( serverSocketStreams[i] ); + for( unsigned int i=0 ; i1 ) for( unsigned int idx=0 ; idx *client = NULL; + if( serverSocketStreams.size()==1 ) + { + client = new Client< Real , Dim , BType , Degree >(); + client->_serverSocket = serverSocketStreams[0]; + client->_index = clientIndices[0]; + } + + // Phase 1 + { + PhaseInfo phaseInfo; + double cacheTime = 0; + size_t cacheBytes = 0; + + profiler.reset(); + for( unsigned int i=0 ; i1 ) + { + client = new Client< Real , Dim , BType , Degree >(); + client->_serverSocket = serverSocketStreams[i]; + client->_index = clientIndices[i]; + } + + phaseInfo += client->_phase1( clientReconInfo , profiler ); + + if( serverSocketStreams.size()>1 ) + { + Timer timer; + + cacheFiles[i].reset(); + cacheFiles[i].ioBytes = 0; + client->_write( clientReconInfo , cacheFiles[i] , 1 ); + cacheBytes += cacheFiles[i].ioBytes; + delete client; + client = NULL; + + cacheTime += timer.wallTime(); + } + } + if( clientReconInfo.verbose>0 ) + { + StreamFloatPrecision sfp( std::cout , 1 ); + std::cout << ReceiveDataString( 1 , phaseInfo.readBytes ) << phaseInfo.readTime << " (s)" << std::endl; + std::cout << "[PROCESS 1] : " << phaseInfo.processTime << " (s), " << profiler(false) << std::endl; + std::cout << SendDataString( 1 , phaseInfo.writeBytes ) << phaseInfo.writeTime << " (s)" << std::endl; + if( serverSocketStreams.size()>1 ) std::cout << "[CACHE 1] : " << cacheTime << " (s) , " << (cacheBytes>>20) << " (MB)" << std::endl; + } + } + + // Phase 3 + { + PhaseInfo phaseInfo; + double cacheTime = 0; + size_t cacheBytes = 0; + + profiler.reset(); + for( unsigned int i=0 ; i::_State3 state3; + + if( serverSocketStreams.size()>1 ) + { + Timer timer; + cacheFiles[i].ioBytes = 0; + cacheFiles[i].reset(); + client = new Client< Real , Dim , BType , Degree >( clientReconInfo , cacheFiles[i] , 3 ); + cacheTime += timer.wallTime(); + cacheBytes += cacheFiles[i].ioBytes; + client->_serverSocket = serverSocketStreams[i]; + } + + phaseInfo += client->_phase3( clientReconInfo , state3 , profiler ); + + if( serverSocketStreams.size()>1 ) + { + Timer timer; + cacheFiles[i].ioBytes = 0; + cacheFiles[i].reset(); + client->_write( clientReconInfo , cacheFiles[i] , 3 ); + delete client; + client = NULL; + cacheTime += timer.wallTime(); + cacheBytes += cacheFiles[i].ioBytes; + } + } + + if( clientReconInfo.verbose>0 ) + { + StreamFloatPrecision sfp( std::cout , 1 ); + std::cout << ReceiveDataString( 3 , phaseInfo.readBytes ) << phaseInfo.readTime << " (s)" << std::endl; + std::cout << "[PROCESS 3] : " << phaseInfo.processTime << " (s), " << profiler(false) << std::endl; + std::cout << SendDataString( 3 , phaseInfo.writeBytes ) << phaseInfo.writeTime << " (s)" << std::endl; + if( serverSocketStreams.size()>1 ) std::cout << "[CACHE 3] : " << cacheTime << " (s) , " << (cacheBytes>>20) << " (MB)" << std::endl; + } + } + + // Phase 5 + { + PhaseInfo phaseInfo; + double cacheTime = 0; + size_t cacheBytes = 0; + + profiler.reset(); + for( unsigned int i=0 ; i1 ) + { + Timer timer; + cacheFiles[i].ioBytes = 0; + cacheFiles[i].reset(); + client = new Client< Real , Dim , BType , Degree >( clientReconInfo , cacheFiles[i] , 5 ); + cacheTime += timer.wallTime(); + cacheBytes += cacheFiles[i].ioBytes; + client->_serverSocket = serverSocketStreams[i]; + } + + phaseInfo += client->_phase5( clientReconInfo , profiler ); + + if( serverSocketStreams.size()>1 ) + { + Timer timer; + cacheFiles[i].ioBytes; + cacheFiles[i].reset(); + client->_write( clientReconInfo , cacheFiles[i] , 5 ); + delete client; + client = NULL; + cacheTime += timer.wallTime(); + cacheBytes += cacheFiles[i].ioBytes; + } + } + + if( clientReconInfo.verbose>0 ) + { + StreamFloatPrecision sfp( std::cout , 1 ); + std::cout << ReceiveDataString( 5 , phaseInfo.readBytes ) << phaseInfo.readTime << " (s)" << std::endl; + std::cout << "[PROCESS 5] : " << phaseInfo.processTime << " (s), " << profiler(false) << std::endl; + std::cout << SendDataString( 5 , phaseInfo.writeBytes ) << phaseInfo.writeTime << " (s)" << std::endl; + if( serverSocketStreams.size()>1 ) std::cout << "[CACHE 5] : " << cacheTime << " (s) , " << (cacheBytes>>20) << " (MB)" << std::endl; + } + } + // Phase 7 + { + PhaseInfo phaseInfo; + double cacheTime = 0; + size_t cacheBytes = 0; + + profiler.reset(); + for( unsigned int i=0 ; i1 ) + { + Timer timer; + cacheFiles[i].ioBytes = 0; + cacheFiles[i].reset(); + client = new Client< Real , Dim , BType , Degree >( clientReconInfo , cacheFiles[i] , 7 ); + cacheTime += timer.wallTime(); + cacheBytes += cacheFiles[i].ioBytes; + client->_serverSocket = serverSocketStreams[i]; + } + + phaseInfo += client->_phase7( clientReconInfo , profiler ); + + if( serverSocketStreams.size()>1 ) + { + delete client; + client = NULL; + } + } + + if( clientReconInfo.verbose>0 ) + { + StreamFloatPrecision sfp( std::cout , 1 ); + std::cout << ReceiveDataString( 7 , phaseInfo.readBytes ) << phaseInfo.readTime << " (s)" << std::endl; + std::cout << "[PROCESS 7] : " << phaseInfo.processTime << " (s), " << profiler(false) << std::endl; + if( serverSocketStreams.size()>1 ) std::cout << "[CACHE 7] : " << cacheTime << " (s) , " << (cacheBytes>>20) << " (MB)" << std::endl; + } + } + if( serverSocketStreams.size()==1 ) delete client; +} + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +Client< Real , Dim , BType , Degree >::Client( void ) + : _serverSocket( _INVALID_SOCKET_ ) , _tree( MEMORY_ALLOCATOR_BLOCK_SIZE ) , _density(NULL) , _normalInfo(NULL) , _paddedNormalInfo(NULL) , _iInfo(NULL) , _index(-1) +{ +} + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +Client< Real , Dim , BType , Degree >::~Client( void ) +{ + if( _density ) delete _density; + if( _normalInfo ) delete _normalInfo; + if( _paddedNormalInfo ) delete _paddedNormalInfo; + if( _iInfo ) delete _iInfo; +} + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +std::pair< unsigned int , unsigned int > Client< Real , Dim , BType , Degree >::_PaddedRange( std::pair< unsigned int , unsigned int > range , unsigned int depth , unsigned int padSize ) +{ + std::pair< unsigned int , unsigned int > paddedRange; + if( range.first<=padSize ) paddedRange.first = 0; + else paddedRange.first = range.first - padSize; + if( range.second+padSize>(1u< +std::function< int ( Point< Real , Dim > ) > Client< Real , Dim , BType , Degree >::PointDepthFunctor( Real begin , Real end , unsigned int padSize , unsigned int minDepth , unsigned int maxDepth ) +{ + // Using a padding size of two should do the trick. And it does, but only if we don't use adaptive + const double Log2 = log(2.); + return [begin,end,padSize,minDepth,maxDepth,Log2]( Point< Real , Dim > p ) + { + // For interior points, add to the full depth + if( p[Dim-1]>=begin && p[Dim-1]<=end ) return (int)maxDepth; + else if( p[Dim-1]= b-padSize/(1<= (1<= d + // => d = floor( log_2( padSize/(b-p[Dim-1]) ) ) + return std::max< int >( std::min< int >( (int)floor( log( padSize/( begin - p[Dim-1] ) ) / Log2 ) , (int)maxDepth ) , (int)minDepth ); + } + else if( p[Dim-1]>end ) + { + // Solve for the largest d s.t.: + // p[Dim-1] <= e+padSize/(1<= (1<= d + // => d = floor( log_2( padSize/(p[Dim-1]-e) ) ) + return std::max< int >( std::min< int >( (int)floor( log( padSize/( p[Dim-1] - end ) ) / Log2 ) , (int)maxDepth ) , (int)minDepth ); + } + else return -1; + }; +} + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +PhaseInfo Client< Real , Dim , BType , Degree >::_phase1( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , Profiler &profiler ) +{ + PhaseInfo phaseInfo; + ProjectiveData< Point< Real , 2 > , Real > pointDepthAndWeight; + std::pair< size_t , size_t > nodeCounts; + + { + Timer timer; + phaseInfo.readBytes += _receive1( clientReconInfo , profiler ); + phaseInfo.readTime += timer.wallTime(); + } + if( clientReconInfo.verbose>1 ) std::cout << "Range[" << _index << "]: [ " << _range.first << " , " << _range.second << " ) +/- " << clientReconInfo.padSize << std::endl; + + { + Timer timer; + _process1( clientReconInfo , pointDepthAndWeight , nodeCounts , profiler ); + phaseInfo.processTime += timer.wallTime(); + } + + ProjectiveData< Real , Real > pointWeight; + pointWeight.data = pointDepthAndWeight.data[1]; + pointWeight.weight = pointDepthAndWeight.weight; + { + Timer timer; + phaseInfo.writeBytes += _send1( clientReconInfo , pointWeight , nodeCounts , profiler ); + phaseInfo.writeTime += timer.wallTime(); + } + return phaseInfo; +} + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +size_t Client< Real , Dim , BType , Degree >::_receive1( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , Profiler &profiler ) +{ + ClientServerStream< true > serverStream( _serverSocket , _index , clientReconInfo ); + serverStream.ioBytes = 0; + + if( !serverStream.read( _modelToUnitCube ) ) ERROR_OUT( "Failed to read model-to-unit-cube transform" ); + serverStream.read( _range ); + profiler.update(); + + return serverStream.ioBytes; +} + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +size_t Client< Real , Dim , BType , Degree >::_send1( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , ProjectiveData< Real , Real > pointWeight , std::pair< size_t , size_t > nodeCounts , Profiler &profiler ) +{ + ClientServerStream< false > serverStream( _serverSocket , _index , clientReconInfo ); + serverStream.ioBytes = 0; + serverStream.write( pointWeight ); + serverStream.write( nodeCounts ); + profiler.update(); + return serverStream.ioBytes; +} + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +void Client< Real , Dim , BType , Degree >::_process1( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::pair< size_t , size_t > &nodeCounts , Profiler &profiler ) +{ + std::pair< unsigned int , unsigned int > paddedRange = _PaddedRange( _range , clientReconInfo.sharedDepth , clientReconInfo.padSize ); + AuxDataFactory auxDataFactory( clientReconInfo.auxProperties ); + InputSampleFactory inputSampleFactory( VertexFactory::PositionFactory< Real , Dim >() , InputSampleDataFactory( VertexFactory::NormalFactory< Real , Dim >() , auxDataFactory ) ); + InputSampleDataFactory inputSampleDataFactory( VertexFactory::NormalFactory< Real , Dim >() , auxDataFactory ); + + size_t pointCount = 0 , paddedPointCount = 0; + ProjectiveData< Point< Real , 2 > , Real > paddedPointDepthAndWeight; + paddedPointDepthAndWeight.data = Point< Real , 2 >(); + paddedPointDepthAndWeight.weight = 0; + + unsigned int beginIndex=_range.first , endIndex = _range.second; + unsigned int beginPaddedIndex = paddedRange.first , endPaddedIndex = paddedRange.second; + + pointDepthAndWeight.data = Point< Real , 2 >(); + pointDepthAndWeight.weight = 0; + + FEMTreeInitializer< Dim , Real >::Initialize( _tree.spaceRoot() , clientReconInfo.baseDepth , []( int , int[] ){ return true; } , _tree.nodeAllocators[0] , _tree.initializer() ); + + +#ifdef ADAPTIVE_PADDING + std::function< int ( Point< Real , Dim > ) > pointDepthFunctor = PointDepthFunctor( (Real)_range.first/(1< &p , typename InputPointStreamInfo::DataType &d ) + { + Real l = (Real)Length( d.template get<0>() ); + if( !l || !std::isfinite( l ) ) return (Real)-1.; + return (Real)pow( l , clientReconInfo.confidence ); + }; + auto ProcessData = []( const Point< Real , Dim > &p , typename InputPointStreamInfo::DataType &d ) + { + Real l = (Real)Length( d.template get<0>() ); + if( !l || !std::isfinite( l ) ) return (Real)-1.; + d.template get<0>() /= l; + return (Real)1.; + }; + + std::vector< PointPartition::BufferedBinaryInputDataStream< InputSampleFactory > * > pointStreams( endPaddedIndex - beginPaddedIndex , NULL ); + auto PointStreamFunctor = [&]( unsigned int idx ) + { + std::string fileName = PointPartition::FileName( clientReconInfo.header , idx , 1<( fileName.c_str() , inputSampleFactory , clientReconInfo.bufferSize ); + }; + { + std::vector< std::thread > pointStreamThreads; + pointStreamThreads.reserve( endPaddedIndex - beginPaddedIndex ); + for( unsigned int i=beginPaddedIndex ; i , typename InputSampleFactory::VertexType >; + + auto ProcessInteriorPointSlabs = [&]( typename FEMTreeInitializer< Dim , Real >::StreamInitializationData &sid , unsigned int start , unsigned int end ) + { + if( start==end ) return; + MultiPointStream pointStream( &pointStreams[start-beginPaddedIndex] , end - start ); + typename InputSampleDataFactory::VertexType zeroData = inputSampleDataFactory(); + if( clientReconInfo.confidence>0 ) pointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , pointStream , zeroData , clientReconInfo.reconstructionDepth , _samples , _sampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessDataWithConfidence ); + else pointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , pointStream , zeroData , clientReconInfo.reconstructionDepth , _samples , _sampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); + profiler.update(); + }; + auto ProcessPadPointSlabs = [&]( typename FEMTreeInitializer< Dim , Real >::StreamInitializationData &sid , unsigned int start , unsigned int end ) + { + if( start==end ) return; + MultiPointStream pointStream( &pointStreams[start-beginPaddedIndex] , end - start ); + typename InputSampleDataFactory::VertexType zeroData = inputSampleDataFactory(); +#ifdef ADAPTIVE_PADDING + if( clientReconInfo.confidence>0 ) paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , pointStream , zeroData , clientReconInfo.reconstructionDepth , pointDepthFunctor , _paddedSamples , _paddedSampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessDataWithConfidence ); + else paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , pointStream , zeroData , clientReconInfo.reconstructionDepth , pointDepthFunctor , _paddedSamples , _paddedSampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); +#else // !ADAPTIVE_PADDING + if( clientReconInfo.confidence>0 ) paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , pointStream , zeroData , clientReconInfo.reconstructionDepth , _paddedSamples , _paddedSampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessDataWithConfidence ); + else paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , pointStream , zeroData , clientReconInfo.reconstructionDepth , _paddedSamples , _paddedSampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); +#endif // ADAPTIVE_PADDING + profiler.update(); + }; + + auto ProcessPointSlab = [&]( typename FEMTreeInitializer< Dim , Real >::StreamInitializationData &sid , unsigned int idx ) + { + PointPartition::BufferedBinaryInputDataStream< InputSampleFactory > &pointStream = *pointStreams[idx-beginPaddedIndex]; + + if( idx>=beginIndex && idx0 ) pointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , pointStream , zeroData , clientReconInfo.reconstructionDepth , _samples , _sampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessDataWithConfidence ); + else pointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , pointStream , zeroData , clientReconInfo.reconstructionDepth , _samples , _sampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); + } + else + { + typename InputSampleDataFactory::VertexType zeroData = inputSampleDataFactory(); +#ifdef ADAPTIVE_PADDING + if( clientReconInfo.confidence>0 ) paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , pointStream , zeroData , clientReconInfo.reconstructionDepth , pointDepthFunctor , _paddedSamples , _paddedSampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessDataWithConfidence ); + else paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , pointStream , zeroData , clientReconInfo.reconstructionDepth , pointDepthFunctor , _paddedSamples , _paddedSampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); +#else // !ADAPTIVE_PADDING + if( clientReconInfo.confidence>0 ) paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( _tree.spaceRoot() , pointStream , zeroData , clientReconInfo.reconstructionDepth , _paddedSamples , _paddedSampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessDataWithConfidence ); + else paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( _tree.spaceRoot() , pointStream , zeroData , clientReconInfo.reconstructionDepth , _paddedSamples , _paddedSampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); +#endif // ADAPTIVE_PADDING + } + profiler.update(); + }; + + { + typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; + ProcessInteriorPointSlabs( sid , beginIndex , endIndex ); + } + nodeCounts.first = _tree.spaceRoot().nodes(); + + { + typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; + ProcessPadPointSlabs( sid , beginPaddedIndex , beginIndex ); + ProcessPadPointSlabs( sid , endIndex , endPaddedIndex ); + } + for( unsigned int i=0 ; i1 ) std::cout << "Input Points / Padded Input Points / Samples / Padded Samples: " << pointCount << " / " << paddedPointCount << " / " << _samples.size() << " / " << _paddedSamples.size() << std::endl; + if( clientReconInfo.verbose>1 ) std::cout << "# Read input into tree: " << timer << std::endl; + } + + if( clientReconInfo.verbose>1 ) std::cout << "Nodes [Initialized]: " << _tree.allNodes() << std::endl; + + // Get the kernel density estimator + { + Timer timer; + _density = _tree.template setDensityEstimator< 1 , WEIGHT_DEGREE >( _samples , clientReconInfo.kernelDepth , clientReconInfo.samplesPerNode ); +#ifdef ADAPTIVE_PADDING + _tree.template updateDensityEstimator< 1 , WEIGHT_DEGREE >( *_density , _paddedSamples , 0 , clientReconInfo.kernelDepth , pointDepthFunctor , clientReconInfo.samplesPerNode ); +#else // !ADAPTIVE_PADDING + _tree.template updateDensityEstimator< 1 , WEIGHT_DEGREE >( *_density , _paddedSamples , 0 , clientReconInfo.kernelDepth , clientReconInfo.samplesPerNode ); +#endif // ADAPTIVE_PADDING + profiler.update(); + if( clientReconInfo.verbose>1 ) std::cout << "# Got kernel density: " << timer << std::endl; + } + + if( clientReconInfo.verbose>1 ) std::cout << "Nodes [Density Estimator]: " << _tree.allNodes() << std::endl; + + // Transform the Hermite samples into a vector field + { + Timer timer; + _normalInfo = new SparseNodeData< Point< Real , Dim > , NormalSigs >(); + _paddedNormalInfo = new SparseNodeData< Point< Real , Dim > , NormalSigs >(); + + std::function< bool ( InputSampleDataType , Point< Real , Dim >& ) > ConversionFunction = []( InputSampleDataType in , Point< Real , Dim > &out ) + { + Point< Real , Dim > n = in.template get<0>(); + Real l = (Real)Length( n ); + // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... + if( !l ) return false; + out = n / l; + return true; + }; + + std::function< bool ( InputSampleDataType , Point< Real , Dim >& , Real & ) > ConversionAndBiasFunction = [&]( InputSampleDataType in , Point< Real , Dim > &out , Real &bias ) + { + Point< Real , Dim > n = in.template get<0>(); + Real l = (Real)Length( n ); + // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... + if( !l ) return false; + out = n / l; + bias = (Real)( log( l ) * clientReconInfo.confidenceBias / log( 1<<(Dim-1) ) ); + return true; + }; + + if( clientReconInfo.confidenceBias>0 ) + { + *_normalInfo = _tree.setInterpolatedDataField( NormalSigs() , _samples , _sampleData , _density , clientReconInfo.sharedDepth , clientReconInfo.reconstructionDepth , (Real)0 , pointDepthAndWeight , ConversionAndBiasFunction ); + if( clientReconInfo.verbose>1 ) std::cout << "Nodes [Interior Data Field " << _normalInfo->size() << " / " << _normalInfo->reserved() << "]: " << _tree.allNodes() << std::endl; +#ifdef ADAPTIVE_PADDING + *_paddedNormalInfo = _tree.setInterpolatedDataField( NormalSigs() , _paddedSamples , _paddedSampleData , _density , clientReconInfo.sharedDepth , clientReconInfo.reconstructionDepth , pointDepthFunctor , (Real)0 , paddedPointDepthAndWeight , ConversionAndBiasFunction ); +#else // !ADAPTIVE_PADDING + *_paddedNormalInfo = _tree.setInterpolatedDataField( NormalSigs() , _paddedSamples , _paddedSampleData , _density , clientReconInfo.sharedDepth , clientReconInfo.reconstructionDepth , (Real)0 , paddedPointDepthAndWeight , ConversionAndBiasFunction ); +#endif // ADAPTIVE_PADDING + } + else + { + *_normalInfo = _tree.setInterpolatedDataField( NormalSigs() , _samples , _sampleData , _density , clientReconInfo.sharedDepth , clientReconInfo.reconstructionDepth , (Real)0 , pointDepthAndWeight , ConversionFunction ); + if( clientReconInfo.verbose>1 ) std::cout << "Nodes [Interior Data Field " << _normalInfo->size() << " / " << _normalInfo->reserved() << "]: " << _tree.allNodes() << std::endl; +#ifdef ADAPTIVE_PADDING + *_paddedNormalInfo = _tree.setInterpolatedDataField( NormalSigs() , _paddedSamples , _paddedSampleData , _density , clientReconInfo.sharedDepth , clientReconInfo.reconstructionDepth , pointDepthFunctor , (Real)0 , paddedPointDepthAndWeight , ConversionFunction ); +#else // !ADAPTIVE_PADDING + *_paddedNormalInfo = _tree.setInterpolatedDataField( NormalSigs() , _paddedSamples , _paddedSampleData , _density , clientReconInfo.sharedDepth , clientReconInfo.reconstructionDepth , (Real)0 , paddedPointDepthAndWeight , ConversionFunction ); +#endif // ADAPTIVE_PADDING + } + + ThreadPool::Parallel_for( 0 , _normalInfo->size() , [&]( unsigned int , size_t i ){ (*_normalInfo)[i] *= (Real)-1.; } ); + ThreadPool::Parallel_for( 0 , _paddedNormalInfo->size() , [&]( unsigned int , size_t i ){ (*_paddedNormalInfo)[i] *= (Real)-1.; } ); + profiler.update(); + if( clientReconInfo.verbose>1 ) + { + std::cout << "# Got normal field: " << timer << std::endl; + std::cout << "Point Depth / Point Weight / Padded Point Depth / Padded Point Weight / Estimated Measure / Estimated Padded Measure: " << pointDepthAndWeight.value()[0] << " / " << pointDepthAndWeight.value()[1] << " / " << paddedPointDepthAndWeight.value()[0] << " / " << paddedPointDepthAndWeight.value()[1] << " / " << pointCount* pointDepthAndWeight.value()[1] << " / " << paddedPointCount* paddedPointDepthAndWeight.value()[1] << std::endl; + } + } + if( clientReconInfo.verbose>1 ) std::cout << "Nodes [Padded Data Field " << _paddedNormalInfo->size() << " / " << _paddedNormalInfo->reserved() << "]: " << _tree.allNodes() << std::endl; + + _tree.resetNodeIndices( 0 , std::make_tuple( _density , _normalInfo , _paddedNormalInfo ) ); + + if( clientReconInfo.verbose>1 ) std::cout << "Memory Usage: " << float( MemoryInfo::Usage() )/(1<<20) << " MB" << std::endl; + profiler.update(); +} + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +PhaseInfo Client< Real , Dim , BType , Degree >::_phase3( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , _State3 &state3 , Profiler &profiler ) +{ + PhaseInfo phaseInfo; + ProjectiveData< Real , Real > cumulativePointWeight; + + { + Timer timer; + phaseInfo.readBytes += _receive3( clientReconInfo , cumulativePointWeight , profiler ); + phaseInfo.readTime += timer.wallTime(); + } + + { + Timer timer; + _process3( clientReconInfo , cumulativePointWeight , state3 , profiler ); + phaseInfo.processTime += timer.wallTime(); + } + + { + Timer timer; + phaseInfo.writeBytes += _send3( clientReconInfo , state3 , profiler ); + phaseInfo.writeTime += timer.wallTime(); + } + + return phaseInfo; +} + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +size_t Client< Real , Dim , BType , Degree >::_receive3( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , ProjectiveData< Real , Real > &cumulativePointWeight , Profiler &profiler ) +{ + ClientServerStream< true > serverStream( _serverSocket , _index , clientReconInfo ); + serverStream.ioBytes = 0; + if( !serverStream.read( cumulativePointWeight ) ) ERROR_OUT( "Could not read cumulative point weight" ); + profiler.update(); + return serverStream.ioBytes; +} + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +size_t Client< Real , Dim , BType , Degree >::_send3( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , const _State3 &state3 , Profiler &profiler ) +{ + size_t ioBytes = 0; + { + ClientServerStream< false > serverStream( _serverSocket , _index , clientReconInfo , ClientReconstructionInfo< Real , Dim >::BACK ); + serverStream.ioBytes = 0; + + serverStream.write( state3.subNodeCount ); + TreeAddressesToIndices( state3.subNodes , state3.subNodeCount ); + serverStream.write( state3.subNodes , state3.subNodeCount ); + ioBytes += serverStream.ioBytes; + profiler.update(); + } + { + AuxDataFactory auxDataFactory( clientReconInfo.auxProperties ); + bool needAuxData = clientReconInfo.dataX>0 && auxDataFactory.bufferSize(); + + ClientServerStream< false > serverStream( _serverSocket , _index , clientReconInfo , ClientReconstructionInfo< Real , Dim >::FRONT ); + serverStream.ioBytes = 0; + + state3.constraints.write( serverStream ); + state3.iInfo.write( serverStream ); + + if( needAuxData ) + { + if( !auxDataFactory.isStaticallyAllocated() ) + { + ProjectiveSampleDataTypeSerializer< Real , Dim > serializer( clientReconInfo.auxProperties ); + state3.dataField.write( serverStream , serializer ); + } + else state3.dataField.write( serverStream ); + } + ioBytes += serverStream.ioBytes; + profiler.update(); + } + return ioBytes; +} + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +void Client< Real , Dim , BType , Degree >::_process3( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , ProjectiveData< Real , Real > cumulativePointWeight , _State3 &state3 , Profiler &profiler ) +{ + std::pair< unsigned int , unsigned int > paddedRange = _PaddedRange( _range , clientReconInfo.sharedDepth , clientReconInfo.padSize ); + AuxDataFactory auxDataFactory( clientReconInfo.auxProperties ); + + InputSampleFactory inputSampleFactory( VertexFactory::PositionFactory< Real , Dim >() , InputSampleDataFactory( VertexFactory::NormalFactory< Real , Dim >() , auxDataFactory ) ); + InputSampleDataFactory inputSampleDataFactory( VertexFactory::NormalFactory< Real , Dim >() , auxDataFactory ); + + bool needAuxData = clientReconInfo.dataX>0 && auxDataFactory.bufferSize(); + + Real targetValue = (Real)0.5; + + unsigned int beginIndex = _range.first , endIndex = _range.second; + unsigned int beginPaddedIndex = paddedRange.first , endPaddedIndex = paddedRange.second; + + ApproximatePointInterpolationInfo *iInfo = NULL; + ApproximatePointInterpolationInfo *paddedIInfo = NULL; + + // Add the interpolation constraints + { + Timer timer; + iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointInterpolationInfo< Real , 0 > ( _tree , _samples , ConstraintDual< Dim , Real >( targetValue , clientReconInfo.pointWeight * cumulativePointWeight.value() ) , SystemDual< Dim , Real >( clientReconInfo.pointWeight * cumulativePointWeight.value() ) , true , clientReconInfo.reconstructionDepth , 1 ); + paddedIInfo = FEMTree< Dim , Real >::template InitializeApproximatePointInterpolationInfo< Real , 0 > ( _tree , _paddedSamples , ConstraintDual< Dim , Real >( targetValue , clientReconInfo.pointWeight * cumulativePointWeight.value() ) , SystemDual< Dim , Real >( clientReconInfo.pointWeight * cumulativePointWeight.value() ) , true , clientReconInfo.reconstructionDepth , 1 ); + profiler.update(); + + if( clientReconInfo.verbose>1 ) std::cout << "# Set interpolation constraints: " << timer << std::endl; + } + + // Trim the tree and prepare for multigrid + { + Timer timer; + + constexpr int MAX_DEGREE = NORMAL_DEGREE > Degrees::Max() ? NORMAL_DEGREE : Degrees::Max(); + typename FEMTree< Dim , Real >::template HasNormalDataFunctor< NormalSigs > hasNormalDataFunctor( *_normalInfo ); + typename FEMTree< Dim , Real >::template HasNormalDataFunctor< NormalSigs > hasPaddedNormalDataFunctor( *_paddedNormalInfo ); + auto hasDataFunctor = [&]( const FEMTreeNode *node ){ return hasNormalDataFunctor( node ) || hasPaddedNormalDataFunctor( node ); }; + + const int StartOffset = BSplineSupportSizes< MAX_DEGREE >::SupportStart; + const int EndOffset = BSplineSupportSizes< MAX_DEGREE >::SupportEnd+1; + auto addNodeFunctor = [&]( int d , const int off[Dim] ) + { + if( d<0 ) return true; + else if( d>(int)clientReconInfo.baseDepth ) return false; + else + { + int start = ( off[Dim-1] + StartOffset )<<(clientReconInfo.sharedDepth-d); + int end = ( off[Dim-1] + EndOffset )<<(clientReconInfo.sharedDepth-d); + return start<(int)endPaddedIndex && end>(int)beginPaddedIndex; + } + }; + _tree.template finalizeForMultigrid< MAX_DEGREE , Degrees::Max() >( clientReconInfo.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo , paddedIInfo ) , std::make_tuple( _normalInfo , _paddedNormalInfo , _density ) ); + profiler.update(); + if( clientReconInfo.verbose>1 ) + { + std::cout << "All Nodes / Active Nodes / Ghost Nodes: " << _tree.allNodes() << " / " << _tree.activeNodes() << " / " << _tree.ghostNodes() << std::endl; + std::cout << "# Finalized tree: " << timer << std::endl; + } + } + + // Compute the FEM constraints for the points interior to the slab + { + _constraints = _tree.initDenseNodeData( Sigs() ); + + // Add Poisson constraints + { + Timer timer; + typename FEMIntegrator::template Constraint< Sigs , IsotropicUIntPack< Dim , 1 > , NormalSigs , IsotropicUIntPack< Dim , 0 > , Dim > F; + unsigned int derivatives2[Dim]; + for( int d=0 ; d Derivatives1; + typedef IsotropicUIntPack< Dim , 0 > Derivatives2; + for( int d=0 ; d::Index( derivatives1 ) ][ TensorDerivatives< Derivatives2 >::Index( derivatives2 ) ] = 1; + } + _tree.addFEMConstraints( F , *_normalInfo , _constraints , clientReconInfo.reconstructionDepth ); + if( clientReconInfo.verbose>1 ) std::cout << "# Set interior FEM constraints: " << timer << std::endl; + } + profiler.update(); + + // Free up the normal info + delete _normalInfo , _normalInfo = NULL; + + { + Timer timer; + _tree.addInterpolationConstraints( _constraints , clientReconInfo.reconstructionDepth , std::make_tuple( iInfo ) ); + profiler.update(); + if( clientReconInfo.verbose>1 ) std::cout << "#Set interior point constraints: " << timer << std::endl; + } + } + if( needAuxData ) _dataField = _tree.template setExtrapolatedDataField< DataSig , false >( _samples , _sampleData , (DensityEstimator*)NULL ); + + // Get the shared tree, constraints, interpolation info, and data-field + { + auto keepNodeFunctor = [&]( const FEMTreeNode *node ) + { + int d , off[Dim]; + _tree.depthAndOffset( node , d , off ); + + return d<=(int)clientReconInfo.sharedDepth; + }; + state3.subNodes = _tree.tree().serializeSubTree( keepNodeFunctor , state3.subNodeCount ); + state3.constraints = _tree.trimToDepth( _constraints , clientReconInfo.sharedDepth ); + state3.iInfo = _tree.trimToDepth( *iInfo , clientReconInfo.sharedDepth ); + if( needAuxData ) state3.dataField = _tree.trimToDepth( _dataField , clientReconInfo.sharedDepth ); + } + + if( needAuxData ) + { + _tree.template updateExtrapolatedDataField< DataSig , false >( _dataField , _paddedSamples , _paddedSampleData , (DensityEstimator*)NULL ); + auto nodeFunctor = [&]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *n ) + { + ProjectiveData< InputSampleDataType , Real >* clr = _dataField( n ); + if( clr ) (*clr) *= (Real)pow( clientReconInfo.dataX , _tree.depth( n ) ); + }; + _tree.tree().processNodes( nodeFunctor ); + } + + // Add the FEM constraints for the points in the padding region + { + Timer timer; + // Add Poisson constraints + { + typename FEMIntegrator::template Constraint< Sigs , IsotropicUIntPack< Dim , 1 > , NormalSigs , IsotropicUIntPack< Dim , 0 > , Dim > F; + unsigned int derivatives2[Dim]; + for( int d=0 ; d Derivatives1; + typedef IsotropicUIntPack< Dim , 0 > Derivatives2; + for( int d=0 ; d::Index( derivatives1 ) ][ TensorDerivatives< Derivatives2 >::Index( derivatives2 ) ] = 1; + } + _tree.addFEMConstraints( F , *_paddedNormalInfo , _constraints , clientReconInfo.reconstructionDepth ); + } + if( clientReconInfo.verbose>1 ) std::cout << "# Set padded FEM constraints: " << timer << std::endl; + + profiler.update(); + + // Free up the normal info + delete _paddedNormalInfo , _paddedNormalInfo = NULL; + + { + Timer timer; + _tree.addInterpolationConstraints( _constraints , clientReconInfo.reconstructionDepth , std::make_tuple( paddedIInfo ) ); + profiler.update(); + if( clientReconInfo.verbose>1 ) std::cout << "# Set padded point constraints: " << timer << std::endl; + } + } + + // Merge the interpolation information + { + Timer timer; + using InterpolationData = typename ApproximatePointInterpolationInfo::Data; + auto preMergeFunctor = []( InterpolationData data ){ data.position *= data.weight ; return data; }; + auto postMergeFunctor = []( InterpolationData data ){ data.position /= data.weight ; return data; }; + + _iInfo = new ApproximatePointInterpolationInfo( ConstraintDual< Dim , Real >( targetValue , clientReconInfo.pointWeight * cumulativePointWeight.value() ) , SystemDual< Dim , Real >( clientReconInfo.pointWeight * cumulativePointWeight.value() ) , true ); + _iInfo->iData.reserve( _tree.nodesSize() ); + + _iInfo->iData.merge( iInfo->iData , preMergeFunctor ); + _iInfo->iData.merge( paddedIInfo->iData , preMergeFunctor ); + + for( unsigned int i=0 ; i<_iInfo->iData.size() ; i++ ) _iInfo->iData[i] = postMergeFunctor( _iInfo->iData[i] ); + + if( clientReconInfo.verbose>1 ) std::cout << "# Merged interpolation: " << timer << std::endl; + } + if( clientReconInfo.verbose>1 ) std::cout << "Memory Usage: " << float( MemoryInfo::Usage() )/(1<<20) << " MB" << std::endl; + profiler.update(); + delete iInfo; + delete paddedIInfo; +} + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +PhaseInfo Client< Real , Dim , BType , Degree >::_phase5( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , Profiler &profiler ) +{ + PhaseInfo phaseInfo; + std::pair< double , double > isoInfo; + + typename Client< Real , Dim , BType , Degree >::_State5 state5; + { + Timer timer; + phaseInfo.readBytes += _receive5( clientReconInfo , state5 , profiler ); + phaseInfo.readTime += timer.wallTime(); + } + + { + Timer timer; + isoInfo = _process5( clientReconInfo , state5 , profiler ); + phaseInfo.processTime += timer.wallTime(); + } + + { + Timer timer; + _serverSocket.write( isoInfo ); + phaseInfo.writeBytes += _send5( clientReconInfo , state5 , profiler ); + phaseInfo.writeTime += timer.wallTime(); + } + return phaseInfo; +} + + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +size_t Client< Real , Dim , BType , Degree >::_receive5( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , _State5 &state5 , Profiler &profiler ) +{ + AuxDataFactory auxDataFactory( clientReconInfo.auxProperties ); + bool needAuxData = clientReconInfo.dataX>0 && auxDataFactory.bufferSize(); + + ClientServerStream< true > serverStream( _serverSocket , _index , clientReconInfo ); + serverStream.ioBytes = 0; + size_t subNodeCount; + serverStream.read( subNodeCount ); + state5.subNodes = NewPointer< FEMTreeNode >( subNodeCount ); + serverStream.read( state5.subNodes , subNodeCount ); + TreeIndicesToAddresses( state5.subNodes , subNodeCount ); + state5.solution.read( serverStream ); + + if( needAuxData ) + { + using Data = typename _State5::Data; + Data defaultValue; + defaultValue.data.template get<1>() = auxDataFactory(); + + if( !auxDataFactory.isStaticallyAllocated() ) + { + ProjectiveSampleDataTypeSerializer< Real , Dim > serializer( clientReconInfo.auxProperties ); + state5.dataField = new SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > >( serverStream , serializer ); + } + else state5.dataField = new SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > >( serverStream ); + } + profiler.update(); + + return serverStream.ioBytes; +} + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +size_t Client< Real , Dim , BType , Degree >::_send5( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , const _State5 &state5 , Profiler &profiler ) +{ + size_t ioBytes = 0; + + auto Send = [&]( const typename Client::_State5::BoundaryInfo &bInfo , typename ClientReconstructionInfo< Real , Dim >::ShareType st ) + { + ClientServerStream< false > serverStream( _serverSocket , _index , clientReconInfo , st ); + serverStream.ioBytes=0; + + XForm< Real , Dim > sliceModelToUnitCube; + { + for( unsigned int i=0 ; iwrite( serverStream , sliceModelToUnitCube , true ); + bInfo.solution.write( serverStream ); + bInfo.dSolution.write( serverStream ); + } + profiler.update(); + return serverStream.ioBytes; + }; + if( _range.first!=0 ) ioBytes += Send( state5.boundaryInfo.first , ClientReconstructionInfo< Real , Dim >::BACK ); + if( _range.second!=(1<::FRONT ); + + return ioBytes; +} + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +std::pair< double , double > Client< Real , Dim , BType , Degree >::_process5( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , _State5 &state5 , Profiler &profiler ) +{ + AuxDataFactory auxDataFactory( clientReconInfo.auxProperties ); + bool needAuxData = clientReconInfo.dataX>0 && auxDataFactory.bufferSize(); + + // Refine the client's tree so that it contains the server's subtree + { + Timer timer; + // Refine client nodes as needed + std::function< void ( const FEMTreeNode * , FEMTreeNode * ) > ProcessIndices = [&]( const FEMTreeNode *serverNode , FEMTreeNode *clientNode ) + { + if( serverNode->children ) + { + if( !clientNode->children ) clientNode->template initChildren< false >( _tree.nodeAllocators[0] , _tree.initializer() ); + for( int c=0 ; c<(1<children+c , clientNode->children+c ); + } + }; + ProcessIndices( &state5.subNodes[0] , const_cast< FEMTreeNode * >( &_tree.tree() ) ); + // Re-finalize and re-index + auto addNodeFunctor = [&]( int d , const int off[Dim] ){ return d<=(int)clientReconInfo.baseDepth; }; + auto hasDataFunctor = []( const FEMTreeNode * ){ return true; }; + + constexpr int MAX_DEGREE = NORMAL_DEGREE > Degrees::Max() ? NORMAL_DEGREE : Degrees::Max(); + SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > *dataField = needAuxData ? &_dataField : NULL; + DenseNodeData< Real , Sigs > *constraints = &_constraints; + + // [WARNING] This assumes that nothing needs to be done with the Dirichlet flags + _tree.setSortedTreeNodes( std::make_tuple( _iInfo ) , std::make_tuple( _density , constraints , dataField ) ); + profiler.update(); + + if( clientReconInfo.verbose>1 ) std::cout << "# Updated client tree: " << timer << std::endl; + } + + { + Timer timer; + _solution = _tree.initDenseNodeData( Sigs() ); + std::vector< node_index_type > clientToServer( _tree.nodesSize() , -1 ); + { + std::function< void ( const FEMTreeNode * , const FEMTreeNode * ) > ProcessIndices = [&]( const FEMTreeNode *serverNode , const FEMTreeNode *clientNode ) + { + if( clientNode->nodeData.nodeIndex!=-1 ) + { + if( clientNode->nodeData.nodeIndex>=(node_index_type)clientToServer.size() ) ERROR_OUT( "More client nodes than server nodes" ); + clientToServer[ clientNode->nodeData.nodeIndex ] = serverNode->nodeData.nodeIndex; + } + if( _tree.depth( clientNode )<(int)clientReconInfo.sharedDepth && clientNode->children ) + { + if( serverNode->children ) for( int c=0 ; c<(1<children+c , clientNode->children+c ); + } + }; + ProcessIndices( &state5.subNodes[0] , &_tree.tree() ); + } + profiler.update(); + if( clientReconInfo.verbose>1 ) std::cout << "# Set client-to-server: " << timer << std::endl; + + if( needAuxData ) + { + Timer timer; + using Data = ProjectiveData< InputSampleDataType , Real >; + Data defaultValue; + defaultValue.data.template get<1>() = auxDataFactory(); + + // Clearing the low freqeuncy + auto nodeFunctor = [&]( const FEMTreeNode *n ) + { + if( n->nodeData.nodeIndex!=-1 ) + { + node_index_type idx = state5.dataField->index( clientToServer[ n->nodeData.nodeIndex ] ); + if( idx!=-1 ) _dataField[n] = (*state5.dataField)[idx]; + } + return _tree.depth( n )<(int)clientReconInfo.sharedDepth; + }; + _tree.tree().processNodes( nodeFunctor ); + profiler.update(); + if( clientReconInfo.verbose>1 ) std::cout << "# Copied aux data: " << profiler << std::endl; + } + + // (Over-)write coarse solution + for( unsigned int i=0 ; i<_solution.size() ; i++ ) if( clientToServer[i]!=-1 ) _solution[i] = state5.solution[ clientToServer[i] ]; + profiler.update(); + if( clientReconInfo.verbose>1 ) std::cout << "# Copied solution: " << timer << std::endl; + } + + // Solve the linear system + { + Timer timer; + typename FEMTree< Dim , Real >::SolverInfo sInfo; + sInfo.cgDepth = 0 , sInfo.cascadic = true , sInfo.vCycles = 1 , sInfo.iters = clientReconInfo.iters , sInfo.cgAccuracy = 0 , sInfo.verbose = clientReconInfo.verbose>1 , sInfo.showResidual = clientReconInfo.verbose>2 , sInfo.showGlobalResidual = SHOW_GLOBAL_RESIDUAL_NONE , sInfo.sliceBlockSize = 1; + sInfo.baseVCycles = 0 , sInfo.clearSolution = false; + typename FEMIntegrator::template System< Sigs , IsotropicUIntPack< Dim , 1 > > F( { 0. , 1. } ); + _tree.solveSystem( Sigs() , F , _constraints , _solution , []( Real v , Real w ){ return v*w; } , clientReconInfo.sharedDepth+1 , clientReconInfo.solveDepth , sInfo , std::make_tuple( _iInfo ) ); + + profiler.update(); + if( _iInfo ) delete _iInfo , _iInfo = NULL; + + if( clientReconInfo.verbose>1 ) std::cout << "# Linear system solved: " << timer << std::endl; + } + + std::pair< double , double > isoInfo(0.,0.); + // Compute the average iso-value + { + Timer timer; + typename FEMTree< Dim , Real >::template MultiThreadedEvaluator< Sigs , 0 > evaluator( &_tree , _solution ); + std::vector< double > valueSums( ThreadPool::NumThreads() , 0 ) , weightSums( ThreadPool::NumThreads() , 0 ); + ThreadPool::Parallel_for( 0 , _samples.size() , [&]( unsigned int thread , size_t j ) + { + ProjectiveData< Point< Real , Dim > , Real > &sample = _samples[j].sample; + Real w = sample.weight; + if( w>0 ) weightSums[thread] += w , valueSums[thread] += evaluator.values( sample.data / sample.weight , thread , _samples[j].node )[0] * w; + } + ); + for( size_t t=0 ; t1 ) std::cout << "# Got iso-value: " << timer << std::endl; + } + + // Set the boundary information + { + Timer timer; + using SliceSigs = typename Sigs::Reverse::Rest::Reverse; + static const unsigned int CrossSig = Sigs::Reverse::First; + + auto SetBoundary = [&]( unsigned int index , typename _State5::BoundaryInfo &boundaryInfo ) + { + bool needsPadding = !clientReconInfo.linearFit && FEMSignature< CrossSig >::Degree==1; + if( needsPadding ) boundaryInfo.tree = FEMTree< Dim-1 , Real >::template Slice< FEMSignature< CrossSig >::Degree , 1 >( _tree , clientReconInfo.sharedDepth , index , true , MEMORY_ALLOCATOR_BLOCK_SIZE ); + else boundaryInfo.tree = FEMTree< Dim-1 , Real >::template Slice< FEMSignature< CrossSig >::Degree , 0 >( _tree , clientReconInfo.sharedDepth , index , true , MEMORY_ALLOCATOR_BLOCK_SIZE ); + boundaryInfo.solution = boundaryInfo.tree->initDenseNodeData( SliceSigs() ); + boundaryInfo.dSolution = boundaryInfo.tree->initDenseNodeData( SliceSigs() ); + boundaryInfo.tree->template slice< 0 , CrossSig >( _tree , 0 , _solution , boundaryInfo.solution , clientReconInfo.sharedDepth , index ); + if( needsPadding ) boundaryInfo.tree->template slice< 1 , CrossSig >( _tree , 1 , _solution , boundaryInfo.dSolution , clientReconInfo.sharedDepth , index ); + else boundaryInfo.tree->template slice< 0 , CrossSig >( _tree , 1 , _solution , boundaryInfo.dSolution , clientReconInfo.sharedDepth , index ); + }; + if( _range.first !=0 ) SetBoundary( _range.first , state5.boundaryInfo.first ); + if( _range.second!=(1<1 ) std::cout << "# Set boundary info: " << timer << std::endl; + } + return isoInfo; +} + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +PhaseInfo Client< Real , Dim , BType , Degree >::_phase7( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , Profiler &profiler ) +{ + PhaseInfo phaseInfo; + + typename Client< Real , Dim , BType , Degree >::_State7 state7; + if( clientReconInfo.mergeType!=ClientReconstructionInfo< Real , Dim >::MergeType::NONE ) + { + Timer timer; + phaseInfo.readBytes += _receive7( clientReconInfo , state7 , profiler ); + phaseInfo.readTime += timer.wallTime(); + } + + { + Timer timer; + _process7( clientReconInfo , state7 , profiler ); + phaseInfo.processTime += timer.wallTime(); + } + return phaseInfo; +} + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +size_t Client< Real , Dim , BType , Degree >::_receive7( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , _State7 &state7 , Profiler &profiler ) +{ + size_t ioBytes = 0; + auto Receive = [&]( BoundaryData *&boundary , std::vector< std::vector< Real > > &dValues , typename ClientReconstructionInfo< Real , Dim >::ShareType st ) + { + ClientServerStream< true > serverStream( _serverSocket , _index , clientReconInfo , st ); + serverStream.ioBytes = 0; + serverStream.read( state7.isoValue ); + if( clientReconInfo.mergeType!=ClientReconstructionInfo< Real , Dim >::MergeType::NONE ) + { + XForm< Real , Dim > modelToUnitCube; + boundary = new BoundaryData( serverStream , modelToUnitCube , MEMORY_ALLOCATOR_BLOCK_SIZE ); + if( !clientReconInfo.linearFit ) + { + dValues.resize( boundary->sliceValues.size() ); + for( unsigned int i=0 ; i::BACK ); + if( _range.second!=(1<::FRONT ); + + return ioBytes; +} + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +void Client< Real , Dim , BType , Degree >::_process7( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , _State7 &state7 , Profiler &profiler ) +{ + AuxDataFactory auxDataFactory( clientReconInfo.auxProperties ); + + typedef VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::ValueFactory< Real > , AuxDataFactory > OutputVertexFactory; + typedef typename OutputVertexFactory::VertexType OutputVertex; + + // Extract the mesh + { + using namespace VertexFactory; + + typedef Factory< Real , NormalFactory< Real , Dim > , AuxDataFactory > InputSampleDataFactory; + InputSampleDataFactory inputSampleDataFactory( NormalFactory< Real , Dim >() , auxDataFactory ); + + Timer timer; + + std::string tempHeader( "PR_" ); + if( clientReconInfo.tempDir.length() ) tempHeader = PointPartition::FileDir( clientReconInfo.tempDir , tempHeader ); + + SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > *dataField = NULL; + if( _dataField.size() ) dataField = &_dataField; + + XForm< Real , Dim+1 > unitCubeToModel = _modelToUnitCube.inverse(); + std::string outFileName; + { + std::stringstream ss; + ss << clientReconInfo.header << "." << _index << ".ply"; + outFileName = ss.str(); + } + + if( clientReconInfo.outDir.length() ) outFileName = PointPartition::FileDir( clientReconInfo.outDir , outFileName ); + if( clientReconInfo.density ) + { + typedef Factory< Real , PositionFactory< Real , Dim > , ValueFactory< Real > , AuxDataFactory > VertexFactory; + VertexFactory vertexFactory( PositionFactory< Real , Dim >() , ValueFactory< Real >() , auxDataFactory ); + typedef typename VertexFactory::VertexType Vertex; + + FileStreamingMesh< VertexFactory , node_index_type > mesh( vertexFactory , tempHeader.c_str() ); + + auto SetVertex = []( typename VertexFactory::VertexType &v , Point< Real , Dim > p , Point< Real , Dim > g , Real w , InputSampleDataType d ){ v.template get<0>() = p , v.template get<1>() = w , v.template get<2>() = d.template get<1>(); }; + typename LevelSetExtractor< Dim , Real , Vertex >::Stats stats; + stats = LevelSetExtractor< Dim , Real , Vertex >::template Extract< InputSampleDataType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , _tree , clientReconInfo.reconstructionDepth , _density , dataField , _solution , state7.isoValue , clientReconInfo.sharedDepth , _range.first , _range.second , mesh , inputSampleDataFactory() , SetVertex , !clientReconInfo.linearFit , false , false , true , false , state7.backBoundary , state7.frontBoundary , state7.backDValues , state7.frontDValues , clientReconInfo.mergeType==ClientReconstructionInfo< Real , Dim >::MergeType::TOPOLOGY_AND_FUNCTION ); + + if( clientReconInfo.verbose>1 ) + { + std::cout << "Vertices / Polygons: " << mesh.vertexNum() << " / " << mesh.polygonNum() << std::endl; + std::cout << stats.toString() << std::endl; + std::cout << "# Got polygons: " << timer << std::endl; + } + + std::vector< std::string > noComments; + typename VertexFactory::Transform unitCubeToModelTransform( unitCubeToModel ); + + auto xForm = [&]( typename VertexFactory::VertexType & v ){ unitCubeToModelTransform.inPlace( v ); }; + PLY::WritePolygons< VertexFactory , node_index_type , Real , Dim >( outFileName.c_str() , vertexFactory , &mesh , PLY_BINARY_NATIVE , noComments , xForm ); + } + else + { + typedef Factory< Real , PositionFactory< Real , Dim > , AuxDataFactory > VertexFactory; + VertexFactory vertexFactory( PositionFactory< Real , Dim >() , auxDataFactory ); + typedef typename VertexFactory::VertexType Vertex; + + FileStreamingMesh< VertexFactory , node_index_type > mesh( vertexFactory , tempHeader.c_str() ); + + const typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE > *density=NULL; + auto SetVertex = []( typename VertexFactory::VertexType &v , Point< Real , Dim > p , Point< Real , Dim > g , Real w , InputSampleDataType d ){ v.template get<0>() = p , v.template get<1>() = d.template get<1>(); }; + typename LevelSetExtractor< Dim , Real , Vertex >::Stats stats; + stats = LevelSetExtractor< Dim , Real , Vertex >::template Extract< InputSampleDataType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , _tree , clientReconInfo.reconstructionDepth , _density , dataField , _solution , state7.isoValue , clientReconInfo.sharedDepth , _range.first , _range.second , mesh , inputSampleDataFactory() , SetVertex , !clientReconInfo.linearFit , false , false , true , false , state7.backBoundary , state7.frontBoundary , state7.backDValues , state7.frontDValues , clientReconInfo.mergeType==ClientReconstructionInfo< Real , Dim >::MergeType::TOPOLOGY_AND_FUNCTION ); + + if( clientReconInfo.verbose>1 ) + { + std::cout << "Vertices / Polygons: " << mesh.vertexNum() << " / " << mesh.polygonNum() << std::endl; + std::cout << stats.toString() << std::endl; + std::cout << "# Got polygons: " << timer << std::endl; + } + + std::vector< std::string > noComments; + typename VertexFactory::Transform unitCubeToModelTransform( unitCubeToModel ); + + auto xForm = [&]( typename VertexFactory::VertexType & v ){ unitCubeToModelTransform.inPlace( v ); }; + PLY::WritePolygons< VertexFactory , node_index_type , Real , Dim >( outFileName.c_str() , vertexFactory , &mesh , PLY_BINARY_NATIVE , noComments , xForm ); + } + } + + if( clientReconInfo.ouputVoxelGrid ) + { + std::string outFileName; + { + std::stringstream ss; + ss << clientReconInfo.header << "." << _index << ".grid"; + outFileName = ss.str(); + } + + if( clientReconInfo.outDir.length() ) outFileName = PointPartition::FileDir( clientReconInfo.outDir , outFileName ); + + unsigned int begin[Dim] , end[Dim] , res[Dim]; + for( unsigned int d=0 ; d( _solution , begin , end , res ); + + XForm< Real , Dim+1 > voxelToUnitCube = XForm< Real , Dim+1 >::Identity(); + for( int d=0 ; d unitCubeToModel = _modelToUnitCube.inverse(); + RegularGrid< Real , Dim >::Write( outFileName , res , values , unitCubeToModel * voxelToUnitCube ); + + DeletePointer( values ); + } + + profiler.update(); +} + + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +Client< Real , Dim , BType , Degree >::Client( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , BinaryStream &stream , unsigned int phase ) + : _serverSocket( _INVALID_SOCKET_ ) , _tree( stream , _modelToUnitCube , MEMORY_ALLOCATOR_BLOCK_SIZE ) , _density(NULL) , _normalInfo(NULL) , _paddedNormalInfo(NULL) , _iInfo(NULL) , _index(-1) +{ + AuxDataFactory auxDataFactory( clientReconInfo.auxProperties ); + bool needAuxData = clientReconInfo.dataX>0 && auxDataFactory.bufferSize(); + + if( phase!=3 && phase!=5 && phase!=7 ) ERROR_OUT( "Only phases 3, 5, and 7 supported: " , phase ); + + stream.read( _index ); + stream.read( _range ); + + _density = new DensityEstimator( stream ); + + auto readSamples = [&]( BinaryStream &stream , std::vector< typename FEMTree< Dim , Real >::PointSample > &samples ) + { + using SampleType = ProjectiveData< Point< Real , Dim > , Real >; + struct T{ SampleType sample; node_index_type index; }; + + { + std::vector< FEMTreeNode * > nodes( _tree.spaceRoot().nodes() , NULL ); + size_t idx = 0; + _tree.spaceRoot().processNodes( [&]( FEMTreeNode *node ){ nodes[idx++] = node; } ); +if( idx!=nodes.size() ) ERROR_OUT( "uhoh" ); + + std::vector< T > _samples; + if( !stream.read( _samples ) ) ERROR_OUT( "Failed to read samples" ); + samples.resize( _samples.size() ); + // Convert indices to node pointers + for( size_t i=0 ; i nodes; + auto readSamplesAndData = [&]( BinaryStream &stream , std::vector< typename FEMTree< Dim , Real >::PointSample > &samples , std::vector< InputSampleDataType > &sampleData ) + { + using SampleType = ProjectiveData< Point< Real , Dim > , Real >; + struct T + { + SampleType sample; + node_index_type index; + }; + { + std::vector< T > _samples; + if( !stream.read( _samples ) ) ERROR_OUT( "Failed to read samples" ); + size_t sz = _samples.size(); + SampleDataTypeSerializer< Real , Dim > serializer( clientReconInfo.auxProperties ); + samples.resize( sz ); + sampleData.resize( sz ); + size_t serializedSize = serializer.size(); + { + Pointer( char ) buffer = NewPointer< char >( sz * serializedSize ); + if( !stream.read( buffer , sz*serializedSize ) ) ERROR_OUT( "Failed to read sample data" ); + for( unsigned int i=0 ; iparent ) root = root->parent; + nodes.reserve( _tree.tree().nodes() ); + root->processNodes( [&]( FEMTreeNode *node ){ nodes.push_back( node ); } ); + } + _normalInfo = new SparseNodeData< Point< Real , Dim > , NormalSigs >( stream ); + _paddedNormalInfo = new SparseNodeData< Point< Real , Dim > , NormalSigs >( stream ); + readSamplesAndData( stream , _samples , _sampleData ); + readSamplesAndData( stream , _paddedSamples , _paddedSampleData ); + } + else if( phase==5 ) + { + _constraints.read( stream ); + + _iInfo = new ApproximatePointInterpolationInfo( stream ); + + readSamples( stream , _samples ); + + if( needAuxData ) + { + if( !auxDataFactory.isStaticallyAllocated() ) + { + ProjectiveSampleDataTypeSerializer< Real , Dim > serializer( clientReconInfo.auxProperties ); + _dataField.read( stream , serializer ); + } + else _dataField.read( stream ); + } + } + else if( phase==7 ) + { + _solution.read( stream ); + + bool needAuxData = clientReconInfo.dataX>0 && auxDataFactory.bufferSize(); + if( needAuxData ) + { + if( !auxDataFactory.isStaticallyAllocated() ) + { + ProjectiveSampleDataTypeSerializer< Real , Dim > serializer( clientReconInfo.auxProperties ); + _dataField.read( stream , serializer ); + } + else _dataField.read( stream ); + } + } +} + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +void Client< Real , Dim , BType , Degree >::_write( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , BinaryStream &stream , unsigned int phase ) const +{ + AuxDataFactory auxDataFactory( clientReconInfo.auxProperties ); + bool needAuxData = clientReconInfo.dataX>0 && auxDataFactory.bufferSize(); + + if( phase!=1 && phase!=3 && phase!=5 ) ERROR_OUT( "Only phases 1, 3, and 5 supported: " , phase ); + + _tree.write( stream , _modelToUnitCube , false ); + + stream.write( _index ); + stream.write( _range ); + + _density->write( stream ); + + auto writeSamples = [&]( BinaryStream &stream , const std::vector< typename FEMTree< Dim , Real >::PointSample > &samples ) + { + // [NOTE] The samples may be assigned to ghost nodes, so we can't just use the node index + using SampleType = ProjectiveData< Point< Real , Dim > , Real >; + struct T { SampleType sample ; node_index_type index; }; + + std::vector< node_index_type > oldIndices( _tree.spaceRoot().nodes() , -1 ); + std::vector< T > _samples( samples.size() ); + + // Grab the old indices and over-write + { + size_t idx = 0; + const_cast< FEMTree< Dim , Real > & >( _tree ).spaceRoot().processNodes( [&]( FEMTreeNode *node ){ oldIndices[idx] = node->nodeData.nodeIndex ; node->nodeData.nodeIndex = idx++; } ); + } + + for( size_t i=0 ; inodeData.nodeIndex; + stream.write( _samples ); + + // Set the node indices back + { + size_t idx = 0; + const_cast< FEMTree< Dim , Real > & >( _tree ).spaceRoot().processNodes( [&]( FEMTreeNode *node ){ node->nodeData.nodeIndex = oldIndices[ idx++ ]; } ); + } + }; + + if( phase==1 ) + { + auto writeSamplesAndData = [&]( BinaryStream &stream , const std::vector< typename FEMTree< Dim , Real >::PointSample > &samples , const std::vector< InputSampleDataType > &sampleData ) + { + using SampleType = ProjectiveData< Point< Real , Dim > , Real >; + struct T + { + SampleType sample; + node_index_type index; + }; + std::vector< T > _samples( samples.size() ); + for( size_t i=0 ; inodeData.nodeIndex; + stream.write( _samples ); + + SampleDataTypeSerializer< Real , Dim > serializer( clientReconInfo.auxProperties ); + size_t serializedSize = serializer.size(); + { + Pointer( char ) buffer = NewPointer< char >( samples.size() * serializedSize ); + for( unsigned int i=0 ; iwrite( stream ); + _paddedNormalInfo->write( stream ); + writeSamplesAndData( stream , _samples , _sampleData ); + writeSamplesAndData( stream , _paddedSamples , _paddedSampleData ); + } + else if( phase==3 ) + { + _constraints.write( stream ); + + _iInfo->write( stream ); + + writeSamples( stream , _samples ); + + if( needAuxData ) + { + if( !auxDataFactory.isStaticallyAllocated() ) + { + ProjectiveSampleDataTypeSerializer< Real , Dim > serializer( clientReconInfo.auxProperties ); + _dataField.write( stream , serializer ); + } + else _dataField.write( stream ); + } + } + else if( phase==5 ) + { + _solution.write( stream ); + + if( _dataField.size() ) + { + if( !auxDataFactory.isStaticallyAllocated() ) + { + ProjectiveSampleDataTypeSerializer< Real , Dim > serializer( clientReconInfo.auxProperties ); + _dataField.write( stream , serializer ); + } + else _dataField.write( stream ); + } + } +} diff --git a/Src/PoissonRecon.h b/Src/PoissonRecon.h index 4336f067..9b938050 100644 --- a/Src/PoissonRecon.h +++ b/Src/PoissonRecon.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2022, Michael Kazhdan and Matthew Bolitho +Copyright (c) 2023, Michael Kazhdan All rights reserved. Redistribution and use in source and binary forms, with or without modification, @@ -38,7 +38,7 @@ DAMAGE. #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 in the normals for constructing the Laplacian constraints #define DEFAULT_FEM_DEGREE 1 // The default finite-element degree -#define DEFAULT_FEM_BOUNDARY BOUNDARY_NEUMANN // The default finite-element boundary type +#define DEFAULT_FEM_BOUNDARY BOUNDARY_NEUMANN // The default finite-element boundary type {BOUNDARY_FREE, BOUNDARY_DIRICHLET, BOUNDARY_NEUMANN} #define DEFAULT_DIMENSION 3 // The dimension of the system const float DefaultPointWeightMultiplier = 2.f; diff --git a/Src/PoissonRecon.server.inl b/Src/PoissonRecon.server.inl new file mode 100644 index 00000000..c40f31c4 --- /dev/null +++ b/Src/PoissonRecon.server.inl @@ -0,0 +1,744 @@ +/* +Copyright (c) 2023, 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. +*/ + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +struct Server +{ + typedef typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; + typedef typename FEMTree< Dim , Real >::template ApproximatePointInterpolationInfo< Real , 0 , ConstraintDual< Dim , Real > , SystemDual< Dim , Real > > ApproximatePointInterpolationInfo; + typedef IsotropicUIntPack< Dim , FEMDegreeAndBType< Degree , BType >::Signature > Sigs; + typedef IsotropicUIntPack< Dim , Degree > Degrees; + typedef IsotropicUIntPack< Dim , FEMDegreeAndBType< NORMAL_DEGREE , DerivativeBoundary< BType , 1 >::BType >::Signature > NormalSigs; + static const unsigned int DataSig = FEMDegreeAndBType< DATA_DEGREE , BOUNDARY_FREE >::Signature; + typedef VertexFactory::DynamicFactory< Real > AuxDataFactory; + typedef VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::Factory< Real , VertexFactory::NormalFactory< Real , Dim > , AuxDataFactory > > InputSampleFactory; + typedef VertexFactory::Factory< Real , VertexFactory::NormalFactory< Real , Dim > , AuxDataFactory > InputSampleDataFactory; + typedef InputOrientedPointStreamInfo< Real , Dim , typename AuxDataFactory::VertexType > InputPointStreamInfo; + typedef typename InputPointStreamInfo::PointAndDataType InputSampleType; + typedef typename InputPointStreamInfo::DataType InputSampleDataType; + typedef InputDataStream< InputSampleType > InputPointStream; + typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; + +protected: + std::vector< SocketStream > _clientSockets; + PointPartition::PointSetInfo< Real , Dim > _pointSetInfo; + PointPartition::Partition _pointPartition; + + struct _State4 + { + FEMTree< Dim , Real > tree; + DenseNodeData< Real , Sigs > constraints , solution; + ApproximatePointInterpolationInfo *iInfo; + SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > *dataField; + + _State4( void ) : tree( MEMORY_ALLOCATOR_BLOCK_SIZE ) , iInfo(NULL) , dataField(NULL) {} + ~_State4( void ){ delete iInfo ; delete dataField; } + }; + struct _State6 + { + using SliceSigs = typename Sigs::Reverse::Rest::Reverse; + using Vertex = typename VertexFactory::PositionFactory< Real , Dim-1 >::VertexType; + FEMTree< Dim-1 , Real > *sliceTree; + XForm< Real , Dim > xForm; + DenseNodeData< Real , SliceSigs > solution , dSolution; + std::vector< typename LevelSetExtractor< Dim-1 , Real , Vertex >::SliceValues > sliceValues , dSliceValues; + std::vector< Point< Real , Dim-1 > > vertices; + + _State6( void ) : sliceTree(NULL) {} + ~_State6( void ){ delete sliceTree; } + }; + + PhaseInfo _phase0( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , Profiler &profiler ); + PhaseInfo _phase2( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , ProjectiveData< Real , Real > &cumulativePointWeight , Profiler &profiler ); + PhaseInfo _phase4( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , ProjectiveData< Real , Real > cumulativePointWeight , unsigned int baseVCycles , Real &isoValue , Profiler &profiler ); + PhaseInfo _phase6( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , Real isoValue , bool showDiscontinuity , bool outputBoundarySlices , std::vector< unsigned int > &sharedVertexCounts , Profiler &profiler ); + + template< typename _Real , unsigned int _Dim , BoundaryType _BType , unsigned int _Degree > + friend std::vector< unsigned int > RunServer( PointPartition::PointSetInfo< _Real , _Dim > , PointPartition::Partition , std::vector< Socket > , ClientReconstructionInfo< _Real , _Dim > , unsigned int , unsigned int , bool , bool ); +}; + + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +static std::vector< unsigned int > RunServer +( + PointPartition::PointSetInfo< Real , Dim > pointSetInfo , + PointPartition::Partition pointPartition , + std::vector< Socket > clientSockets , + ClientReconstructionInfo< Real , Dim > clientReconInfo , + unsigned int baseVCycles , + unsigned int sampleMS , + bool showDiscontinuity , + bool outputBoundarySlices +) +{ + std::vector< unsigned int > sharedVertexCounts; + Server< Real , Dim , BType , Degree > server; + Profiler profiler( sampleMS ); + + clientReconInfo.auxProperties = pointSetInfo.auxiliaryProperties; + + // Initialization + { + server._pointSetInfo = pointSetInfo; + server._pointPartition = pointPartition; + server._clientSockets.resize( clientSockets.size() ); + + for( unsigned int i=0 ; i1 ) + { + for( unsigned int i=0 ; i range = pointPartition.range( i ); + if( range.firstpointPartition.slabs() ) range.second = pointPartition.slabs(); + else range.second += clientReconInfo.padSize; +#else // !ADAPTIVE_PADDING + std::pair< unsigned int , unsigned int > range = pointPartition.range( i , clientReconInfo.padSize ); +#endif // ADAPTIVE_PADDING + std::cout << "Range[ " << i << " ]: [ " << range.first << " , " << range.second << " )" << std::endl; + } + std::cout << "Boundary-type = " << BoundaryNames[BType] << " ; Degree = " << Degree << std::endl; + } + + ProjectiveData< Real , Real > cumulativePointWeight; + Real isoValue; + + // [PHASE 0] Send the client initial information + { + profiler.reset(); + PhaseInfo phaseInfo = server._phase0( clientReconInfo , profiler ); + if( clientReconInfo.verbose>0 ) + { + StreamFloatPrecision sfp( std::cout , 1 ); + std::cout << SendDataString( 0 , phaseInfo.writeBytes ) << phaseInfo.writeTime << " (s)" << std::endl; + } + } + + // [PHASE 2] Accumulate/Send the point weight + { + profiler.reset(); + PhaseInfo phaseInfo = server._phase2( clientReconInfo , cumulativePointWeight , profiler ); + if( clientReconInfo.verbose>0 ) + { + StreamFloatPrecision sfp( std::cout , 1 ); + std::cout << ReceiveDataString( 2 , phaseInfo.readBytes ) << phaseInfo.readTime << " (s)" << std::endl; + std::cout << "[PROCESS 2] : " << phaseInfo.processTime << " (s), " << profiler(false) << std::endl; + std::cout << SendDataString( 2 , phaseInfo.writeBytes ) << phaseInfo.writeTime << " (s)" << std::endl; + } + } + + // [PHASE 4] Accumulate/solve/send coarse system + { + profiler.reset(); + PhaseInfo phaseInfo = server._phase4( clientReconInfo , cumulativePointWeight , baseVCycles , isoValue , profiler ); + if( clientReconInfo.verbose>0 ) + { + StreamFloatPrecision sfp( std::cout , 1 ); + std::cout << ReceiveDataString( 4 , phaseInfo.readBytes ) << phaseInfo.readTime << " (s)" << std::endl; + std::cout << "[PROCESS 4] : " << phaseInfo.processTime << " (s), " << profiler(false) << std::endl; + std::cout << SendDataString( 4 , phaseInfo.writeBytes ) << phaseInfo.writeTime << " (s)" << std::endl; + } + } + + // [PHASE 6] Accumulate/merge/send boundary tree info + { + profiler.reset(); + PhaseInfo phaseInfo = server._phase6( clientReconInfo , isoValue , showDiscontinuity , outputBoundarySlices , sharedVertexCounts , profiler ); + if( clientReconInfo.verbose>0 ) + { + StreamFloatPrecision sfp( std::cout , 1 ); + std::cout << ReceiveDataString( 6 , phaseInfo.readBytes ) << phaseInfo.readTime << " (s)" << std::endl; + std::cout << "[PROCESS 6] : " << phaseInfo.processTime << " (s), " << profiler(false) << std::endl; + std::cout << SendDataString( 6 , phaseInfo.writeBytes ) << phaseInfo.writeTime << " (s)" << std::endl; + } + } + return sharedVertexCounts; +} + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +PhaseInfo Server< Real , Dim , BType , Degree >::_phase0( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , Profiler &profiler ) +{ + PhaseInfo phaseInfo; + + Timer timer; + for( unsigned int i=0 ; i<_clientSockets.size() ; i++ ) + { + ClientServerStream< false > clientStream( _clientSockets[i] , i , clientReconInfo ); + clientStream.ioBytes = 0; + + // Send the information about the point-set + clientStream.write( _pointSetInfo.modelToUnitCube ); + + // Send the client's range +#ifdef ADAPTIVE_PADDING + std::pair< unsigned int , unsigned int > range = _pointPartition.range( i ); +#else // !ADAPTIVE_PADDING + std::pair< unsigned int , unsigned int > range = _pointPartition.range( i , 0 ); +#endif // ADAPTIVE_PADDING + clientStream.write( range ); + + phaseInfo.writeBytes += clientStream.ioBytes; + } + phaseInfo.writeTime += timer.wallTime(); + profiler.update(); + return phaseInfo; +} + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +PhaseInfo Server< Real , Dim , BType , Degree >::_phase2( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , ProjectiveData< Real , Real > &cumulativePointWeight , Profiler &profiler ) +{ + PhaseInfo phaseInfo; + std::pair< size_t , size_t > cumulativeNodeCounts; + + + cumulativeNodeCounts = std::pair< size_t , size_t >(0,0); + cumulativePointWeight = ProjectiveData< Real , Real >( (Real)0. ); + + for( unsigned int i=0 ; i<_clientSockets.size() ; i++ ) + { + Timer timer; + ProjectiveData< Real , Real > pointWeight; + std::pair< size_t , size_t > nodeCounts; + ClientServerStream< true > clientStream( _clientSockets[i] , i , clientReconInfo ); + clientStream.ioBytes = 0; + clientStream.read( pointWeight ); + clientStream.read( nodeCounts ); + phaseInfo.readBytes += clientStream.ioBytes; + phaseInfo.readTime += timer.wallTime(); + + timer = Timer(); + cumulativePointWeight += pointWeight; + cumulativeNodeCounts.first += nodeCounts.first; + cumulativeNodeCounts.second += nodeCounts.second; + phaseInfo.processTime += timer.wallTime(); + } + + Timer timer; + for( unsigned int i=0 ; i<_clientSockets.size() ; i++ ) + { + ClientServerStream< false > clientStream( _clientSockets[i] , i , clientReconInfo ); + clientStream.ioBytes = 0; + clientStream.write( cumulativePointWeight ); + phaseInfo.writeBytes += clientStream.ioBytes; + } + phaseInfo.writeTime = timer.wallTime(); + + if( clientReconInfo.verbose>1 ) std::cout << "Redundancy: " << cumulativeNodeCounts.second << " / " << cumulativeNodeCounts.first << " = " << (double)cumulativeNodeCounts.second/cumulativeNodeCounts.first << std::endl; + + profiler.update(); + + return phaseInfo; +} + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +PhaseInfo Server< Real , Dim , BType , Degree >::_phase4( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , ProjectiveData< Real , Real > cumulativePointWeight , unsigned int baseVCycles , Real &isoValue , Profiler &profiler ) +{ + constexpr int MAX_DEGREE = NORMAL_DEGREE > Degrees::Max() ? NORMAL_DEGREE : Degrees::Max(); + const int StartOffset = BSplineSupportSizes< MAX_DEGREE >::SupportStart; + const int EndOffset = BSplineSupportSizes< MAX_DEGREE >::SupportEnd+1; + PhaseInfo phaseInfo; + + _State4 state4; + + std::vector< std::vector< node_index_type > > clientsToServer( _clientSockets.size() ); + + // Initialize the tree + { + Timer timer; + FEMTreeInitializer< Dim , Real >::Initialize( state4.tree.spaceRoot() , clientReconInfo.baseDepth , []( int , int[] ){ return true; } , state4.tree.nodeAllocators[0] , state4.tree.initializer() ); + + auto hasDataFunctor = []( const FEMTreeNode * ){ return false; }; + + // Set the root of the tree so we can copy constraints into it + auto addNodeFunctor = [&]( int d , const int off[Dim] ){ return d<=(int)clientReconInfo.baseDepth; }; + state4.tree.template finalizeForMultigrid< MAX_DEGREE , Degrees::Max() >( clientReconInfo.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple() , std::make_tuple() ); + phaseInfo.processTime += timer.wallTime(); + profiler.update(); + } + + // Get/merge client data + for( unsigned int i=0 ; i<_clientSockets.size() ; i++ ) + { + Timer timer; + + std::vector< node_index_type > &clientToServer = clientsToServer[i]; + ClientServerStream< true > clientStream( _clientSockets[i] , i , clientReconInfo , ClientReconstructionInfo< Real , Dim >::BACK ); + clientStream.ioBytes = 0; + + // The number of nodes in the client's coarse sub-tree + size_t subNodeCount; + clientStream.read( subNodeCount ); + + // The nodes in the client's coarse sub-tree + Pointer( FEMTreeNode ) subNodes = NewPointer< FEMTreeNode >( subNodeCount ); + clientStream.read( subNodes , subNodeCount ); + + phaseInfo.readBytes += clientStream.ioBytes; + phaseInfo.readTime += timer.wallTime(); + + + timer = Timer(); + // Transform the nodes indices back to pointers + TreeIndicesToAddresses( subNodes , subNodeCount ); + clientToServer.resize( subNodeCount , -1 ); + + // Find the map from client to index to server index and add client nodes as necessary + std::function< void ( FEMTreeNode * , const FEMTreeNode * ) > ProcessIndices = [&]( FEMTreeNode *serverNode , const FEMTreeNode *clientNode ) + { + if( clientNode->nodeData.nodeIndex!=-1 ) clientToServer[ clientNode->nodeData.nodeIndex ] = serverNode->nodeData.nodeIndex; + if( clientNode->children ) + { + if( !serverNode->children ) serverNode->template initChildren< false >( state4.tree.nodeAllocators[0] , state4.tree.initializer() ); + for( int c=0 ; c<(1<children+c , clientNode->children+c ); + } + }; + ProcessIndices( const_cast< FEMTreeNode * >( &state4.tree.tree() ) , &subNodes[0] ); + profiler.update(); + DeletePointer( subNodes ); + phaseInfo.processTime += timer.wallTime(); + } + + { + Timer timer; + constexpr int MAX_DEGREE = NORMAL_DEGREE > Degrees::Max() ? NORMAL_DEGREE : Degrees::Max(); + auto hasDataFunctor = []( const FEMTreeNode * ){ return true; }; + auto addNodeFunctor = [&]( int d , const int off[Dim] ){ return d<=(int)clientReconInfo.baseDepth; }; + std::vector< node_index_type > newToOld = state4.tree.template finalizeForMultigrid< MAX_DEGREE , Degrees::Max() >( clientReconInfo.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple() , std::make_tuple() ); + node_index_type idx = newToOld[0]; + for( unsigned int i=0 ; i( idx , newToOld[i] ); + idx++; + std::vector< node_index_type > oldToNew( idx , -1 ); + for( unsigned int i=0 ; i0 && auxDataFactory.bufferSize(); + + state4.constraints = state4.tree.initDenseNodeData( Sigs() ); + + { + Real targetValue = (Real)0.5; + state4.iInfo = new ApproximatePointInterpolationInfo( ConstraintDual< Dim , Real >( targetValue , clientReconInfo.pointWeight * cumulativePointWeight.value() ) , SystemDual< Dim , Real >( clientReconInfo.pointWeight * cumulativePointWeight.value() ) , true ); + state4.iInfo->iData.reserve( state4.tree.nodesSize() ); + } + + using InterpolationData = typename ApproximatePointInterpolationInfo::Data; + auto preMergeFunctor = []( InterpolationData data ){ data.position *= data.weight ; return data; }; + auto postMergeFunctor = []( InterpolationData data ){ data.position /= data.weight ; return data; }; + + if( needAuxData ) + { + state4.dataField = new SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > >(); + state4.dataField->reserve( state4.tree.nodesSize() ); + } + phaseInfo.processTime += timer.wallTime(); + profiler.update(); + + for( unsigned int i=0 ; i<_clientSockets.size() ; i++ ) + { + std::vector< node_index_type > &clientToServer = clientsToServer[i]; + ClientServerStream< true > clientStream( _clientSockets[i] , i , clientReconInfo , ClientReconstructionInfo< Real , Dim >::FRONT ); + clientStream.ioBytes = 0; + + // The constraints + { + Timer timer; + DenseNodeData< Real , Sigs > _constraints( clientStream ); + phaseInfo.readTime += timer.wallTime(); + + timer = Timer(); + for( unsigned int i=0 ; i<_constraints.size() ; i++ ) + if( clientToServer[i]==-1 || clientToServer[i]>=(node_index_type)state4.constraints.size() ){ WARN_ONCE( "Unmatched client node(s): " , clientToServer[i] ); } + else state4.constraints[ clientToServer[i] ] += _constraints[i]; + phaseInfo.processTime += timer.wallTime(); + } + + // The points + { + Timer timer; + ApproximatePointInterpolationInfo _iInfo( clientStream ); + phaseInfo.readTime += timer.wallTime(); + + timer = Timer(); + state4.iInfo->iData.mergeFromTarget( _iInfo.iData , [&]( unsigned int idx ){ return clientToServer[idx]; } , preMergeFunctor ); + phaseInfo.processTime += timer.wallTime(); + } + // The data field + if( needAuxData ) + { + Timer timer; + SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > *_dataField; + if( !auxDataFactory.isStaticallyAllocated() ) + { + ProjectiveSampleDataTypeSerializer< Real , Dim > serializer( clientReconInfo.auxProperties ); + _dataField = new SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > >( clientStream , serializer ); + } + else _dataField = new SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > >( clientStream ); + phaseInfo.readTime += timer.wallTime(); + + timer = Timer(); + state4.dataField->mergeFromTarget( *_dataField , [&]( unsigned int idx ){ return clientToServer[idx]; } ); + phaseInfo.processTime += timer.wallTime(); + + profiler.update(); + delete _dataField; + } + else profiler.update(); + phaseInfo.readBytes += clientStream.ioBytes; + } + + if( needAuxData ) + { + Timer timer; + auto nodeFunctor = [&]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* n ) + { + ProjectiveData< InputSampleDataType , Real >* clr = state4.dataField->operator()( n ); + if( clr ) (*clr) *= (Real)pow( clientReconInfo.dataX , state4.tree.depth( n ) ); + }; + state4.tree.tree().processNodes( nodeFunctor ); + phaseInfo.processTime += timer.wallTime(); + } + { + Timer timer; + for( unsigned int i=0 ; iiData.size() ; i++ ) state4.iInfo->iData[i] = postMergeFunctor( state4.iInfo->iData[i] ); + phaseInfo.processTime += timer.wallTime(); + } + + { + Timer timer; + + typename FEMTree< Dim , Real >::SolverInfo sInfo; + sInfo.cgDepth = 0 , sInfo.cascadic = true , sInfo.vCycles = 1 , sInfo.iters = clientReconInfo.iters , sInfo.cgAccuracy = clientReconInfo.cgSolverAccuracy , sInfo.verbose = clientReconInfo.verbose>1 , sInfo.showResidual = clientReconInfo.verbose>2 , sInfo.showGlobalResidual = SHOW_GLOBAL_RESIDUAL_NONE , sInfo.sliceBlockSize = 1; + sInfo.baseVCycles = baseVCycles; + typename FEMIntegrator::template System< Sigs , IsotropicUIntPack< Dim , 1 > > F( { 0. , 1. } ); + state4.solution = state4.tree.solveSystem( Sigs() , F , state4.constraints , clientReconInfo.baseDepth , std::min< unsigned int >( clientReconInfo.sharedDepth , clientReconInfo.solveDepth ) , sInfo , std::make_tuple( state4.iInfo ) ); + phaseInfo.processTime += timer.wallTime(); + + profiler.update(); + } + + for( unsigned int i=0 ; i<_clientSockets.size() ; i++ ) + { + Timer timer; + std::pair< unsigned int , unsigned int > range; +#ifdef ADAPTIVE_PADDING + // Compute the range of slices @ clientReconInfo.sharedDepth that can contribute to the client + { + range = _pointPartition.range( i ); + if( range.first_pointPartition.slabs() ) range.second = _pointPartition.slabs(); + else range.second += clientReconInfo.padSize; + } +#else // !ADAPTIVE_PADDING + range = _pointPartition.range( i , clientReconInfo.padSize ); +#endif // ADAPTIVE_PADDING + + ClientServerStream< false > clientStream( _clientSockets[i] , i , clientReconInfo ); + clientStream.ioBytes = 0; + auto keepNodeFunctor = [&]( const FEMTreeNode *node ) + { + int d , off[Dim]; + state4.tree.depthAndOffset( node , d , off ); + + // Pre-tree nodes need to be shared and nodes finer than @ clientReconInfo.sharedDepth don't need to be + if( d<0 ) return true; + else if( d>(int)clientReconInfo.sharedDepth ) + { + WARN( "Why does the client have fine nodes?" ); + return false; + } + else + { + // Compute the space of the range of the support @ clientReconInfo.sharedDepth + int start = ( off[Dim-1] + StartOffset )<<(clientReconInfo.sharedDepth-d); + int end = ( off[Dim-1] + EndOffset )<<(clientReconInfo.sharedDepth-d); + + // Keep the node if its support fall within the client's range + return start<(int)range.second && end>(int)range.first; + } + }; + size_t subNodeCount; + Pointer( FEMTreeNode ) subNodes = state4.tree.tree().serializeSubTree( keepNodeFunctor , subNodeCount ); + + node_index_type count = 0; + subNodes[0].processNodes( [&]( const FEMTreeNode *node ){ if( node->nodeData.nodeIndex!=-1 ) count++; } ); + std::vector< node_index_type > newToOld( count ); + count = 0; + for( size_t i=0 ; i _solution( count ); + for( unsigned int i=0 ; i , IsotropicUIntPack< Dim , DataSig > > _dataField; + _dataField.reserve( count ); + for( size_t i=0 ; i *data = state4.dataField->operator()( node ); + if( data ) _dataField[ subNodes+i ] = *data; + } + phaseInfo.processTime += timer.wallTime(); + + timer = Timer(); + if( !auxDataFactory.isStaticallyAllocated() ) + { + ProjectiveSampleDataTypeSerializer< Real , Dim > serializer( clientReconInfo.auxProperties ); + _dataField.write( clientStream , serializer ); + } + else _dataField.write( clientStream ); + phaseInfo.writeTime += timer.wallTime(); + } + profiler.update(); + DeletePointer( subNodes ); + phaseInfo.writeBytes += clientStream.ioBytes; + } + + { + std::pair< double , double > isoInfo(0.,0.); + for( unsigned int i=0 ; i<_clientSockets.size() ; i++ ) + { + std::pair< double , double > _isoInfo(0.,0.); + _clientSockets[i].read( _isoInfo ); + isoInfo.first += _isoInfo.first; + isoInfo.second += _isoInfo.second; + } + if( clientReconInfo.verbose>1 ) std::cout << "Iso-value: " << ( isoInfo.first / isoInfo.second ) << std::endl; + isoValue = (Real)( isoInfo.first / isoInfo.second ); + } + + return phaseInfo; +} + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +PhaseInfo Server< Real , Dim , BType , Degree >::_phase6( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , Real isoValue , bool showDiscontinuity , bool outputBoundarySlices , std::vector< unsigned int > &sharedVertexCounts , Profiler &profiler ) +{ + using SliceSigs = typename _State6::SliceSigs; + using Vertex = typename _State6::Vertex; + PhaseInfo phaseInfo; + + sharedVertexCounts.resize( _clientSockets.size()-1 ); + + for( unsigned int i=0 ; i<_clientSockets.size()-1 ; i++ ) + { + _State6 state6; + + auto ReadSlice = [&]( BinaryStream &clientStream , DenseNodeData< Real , SliceSigs > &solution , DenseNodeData< Real , SliceSigs > &dSolution , XForm< Real , Dim > &modelToUnitCube ) + { + FEMTree< Dim-1 , Real > *sliceTree = new FEMTree< Dim-1 , Real >( clientStream , modelToUnitCube , MEMORY_ALLOCATOR_BLOCK_SIZE ); + solution.read( clientStream ); + if( !clientReconInfo.linearFit ) dSolution.read( clientStream ); + return sliceTree; + }; + + + { + ClientServerStream< true > clientStream0( _clientSockets[i+0] , i+0 , clientReconInfo , ClientReconstructionInfo< Real , Dim >::FRONT ); + ClientServerStream< true > clientStream1( _clientSockets[i+1] , i+1 , clientReconInfo , ClientReconstructionInfo< Real , Dim >::BACK ); + DenseNodeData< Real , SliceSigs > backSolution , frontSolution , backDSolution , frontDSolution; + FEMTree< Dim-1 , Real > *backSliceTree , *frontSliceTree; + XForm< Real , Dim > backXForm , frontXForm; + + Timer timer; + backSliceTree = ReadSlice( clientStream0 , backSolution , backDSolution , backXForm ); + frontSliceTree = ReadSlice( clientStream1 , frontSolution , frontDSolution , frontXForm ); + phaseInfo.readTime += timer.wallTime(); + + if( showDiscontinuity ) + { + double discontinuityTime = 0; + size_t discontinuityCount = 0; + double l1 = 0 , l2 = 0 , d2 = 0 , dInf = 0; + + double t = Time(); + + int res1 = 0 , res2 = 0; + Pointer( Real ) values1 = backSliceTree->template regularGridEvaluate< true >( backSolution , res1 , -1 , false ); + Pointer( Real ) values2 = frontSliceTree->template regularGridEvaluate< true >( frontSolution , res2 , -1 , false ); + if( res1!=res2 ) ERROR_OUT( "Different resolutions: " , res1 , " != " , res2 ); + size_t count = 1; + for( unsigned int d=0 ; d<(Dim-1) ; d++ ) count *= (unsigned int)res1; + discontinuityCount += count; + for( unsigned int i=0 ; i( dInf , fabs( values1[i]-values2[i] ) ); + DeletePointer( values1 ); + DeletePointer( values2 ); + + discontinuityTime += Time()-t; + + if( discontinuityCount ) + { + d2 /= discontinuityCount; + l1 /= discontinuityCount; + l2 /= discontinuityCount; + std::cout << "Discontinuity L2 / L-infinity: " << sqrt(d2) << " / " << dInf << " [ " << sqrt(l1) << " , " << sqrt(l2) << " ] " << discontinuityTime << " (s)" << std::endl; + } + profiler.update(); + } + + timer = Timer(); + state6.sliceTree = FEMTree< Dim-1 , Real >::Merge( *backSliceTree , *frontSliceTree , MEMORY_ALLOCATOR_BLOCK_SIZE ); + state6.solution = state6.sliceTree->initDenseNodeData( SliceSigs() ); + state6.sliceTree->merge( * backSliceTree , backSolution , state6.solution ); + state6.sliceTree->merge( *frontSliceTree , frontSolution , state6.solution ); + for( unsigned int j=0 ; jinitDenseNodeData( SliceSigs() ); + state6.sliceTree->merge( * backSliceTree , backDSolution , state6.dSolution ); + state6.sliceTree->merge( *frontSliceTree , frontDSolution , state6.dSolution ); + for( unsigned int j=0 ; j *sliceTree , const DenseNodeData< Real , SliceSigs > &solution ) + { + FILE* fp = fopen( fileName.c_str() , "wb" ); + if( !fp ) ERROR_OUT( "Failed to open file for writing: " , fileName ); + FileStream fs(fp); + FEMTree< Dim-1 , Real >::WriteParameter( fs ); + DenseNodeData< Real , SliceSigs >::WriteSignatures( fs ); + sliceTree->write( fs , state6.xForm , false ); + solution.write( fs ); + fclose( fp ); + }; + { + std::stringstream ss; + ss << "back." << i << ".tree"; + WriteBoundary( ss.str() , backSliceTree , backSolution ); + } + { + std::stringstream ss; + ss << "front." << i << ".tree"; + WriteBoundary( ss.str() , frontSliceTree , frontSolution ); + } + { + std::stringstream ss; + ss << "merged." << i << ".tree"; + WriteBoundary( ss.str() , state6.sliceTree , state6.solution ); + } + } + delete backSliceTree; + delete frontSliceTree; + + phaseInfo.readBytes += clientStream0.ioBytes + clientStream1.ioBytes; + } + + { + Timer timer; + using Factory = VertexFactory::EmptyFactory< Real >; + using Data = typename Factory::VertexType; + Factory factory; + const typename FEMTree< Dim-1 , Real >::template DensityEstimator< WEIGHT_DEGREE > *density=NULL; + const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim-1 , DataSig > > *data=NULL; + auto SetVertex = []( Vertex &v , Point< Real , Dim-1 > p , Point< Real , Dim-1 > g , Real w , Data d ){ v = p; }; + { + VectorStreamingVertices< Point< Real , Dim-1 > , node_index_type > _vertices; + LevelSetExtractor< Dim-1 , Real , Vertex >::template SetSliceValues< Data >( SliceSigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , *state6.sliceTree , clientReconInfo.reconstructionDepth , density , data , state6.solution , isoValue , &_vertices , factory() , SetVertex , !clientReconInfo.linearFit , false , state6.sliceValues , LevelSetExtractor< Dim-1 , Real , Vertex >::SetIsoEdgesFlag() ); + if( !clientReconInfo.linearFit ) LevelSetExtractor< Dim-1 , Real , Vertex >::template SetSliceValues< Data >( SliceSigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , *state6.sliceTree , clientReconInfo.reconstructionDepth , density , data , state6.dSolution , isoValue , &_vertices , factory() , SetVertex , false , false , state6.dSliceValues , LevelSetExtractor< Dim-1 , Real , Vertex >::SetCornerValuesFlag() ); + state6.vertices.resize( _vertices.vertexNum() ); + for( unsigned int j=0 ; j<_vertices.vertexNum() ; j++ ) state6.vertices[j] = _vertices.vertex(j); + } + sharedVertexCounts[i] = (unsigned int)state6.vertices.size(); + phaseInfo.processTime += timer.wallTime(); + } + profiler.update(); + + { + Timer timer; + ClientServerStream< false > clientStream0( _clientSockets[i+0] , i+0 , clientReconInfo , ClientReconstructionInfo< Real , Dim >::FRONT ); + ClientServerStream< false > clientStream1( _clientSockets[i+1] , i+1 , clientReconInfo , ClientReconstructionInfo< Real , Dim >::BACK ); + clientStream0.ioBytes = 0; + clientStream1.ioBytes = 0; + clientStream0.write( isoValue ); + clientStream1.write( isoValue ); + if( clientReconInfo.mergeType!=ClientReconstructionInfo< Real , Dim >::MergeType::NONE ) + { + LevelSetExtractor< Dim-1 , Real , Vertex >::TreeSliceValuesAndVertexPositions::Write( clientStream0 , state6.sliceTree , state6.xForm , state6.sliceValues , state6.vertices , true ); + if( !clientReconInfo.linearFit ) + { + for( unsigned int i=0 ; i::TreeSliceValuesAndVertexPositions::Write( clientStream1 , state6.sliceTree , state6.xForm , state6.sliceValues , state6.vertices , true ); + if( !clientReconInfo.linearFit ) + { + for( unsigned int i=0 ; i +#include +#include +#include "MyMiscellany.h" +#include "PoissonRecon.h" +#include "CmdLineParser.h" + +cmdLineParameter< std::string > + Address( "address" , "127.0.0.1" ); + +cmdLineParameter< int > + MaxMemoryGB( "maxMemory" , 0 ) , +#ifdef _OPENMP + ParallelType( "parallel" , (int)ThreadPool::OPEN_MP ) , +#else // !_OPENMP + ParallelType( "parallel" , (int)ThreadPool::THREAD_POOL ) , +#endif // _OPENMP + ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , + ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , + Threads( "threads" , (int)std::thread::hardware_concurrency() ) , + MultiClient( "multi" , 1 ) , + Port( "port" , 0 ) , + PeakMemorySampleMS( "sampleMS" , 10 ); + +cmdLineReadable + Pause( "pause" ); + + +cmdLineReadable* params[] = +{ + &Port , &MultiClient , &Address , + &MaxMemoryGB , &ParallelType , &ScheduleType , &ThreadChunkSize , &Threads , + &Pause , + &PeakMemorySampleMS , + NULL +}; + +void ShowUsage( char* ex ) +{ + printf( "Usage: %s\n" , ex ); + printf( "\t --%s \n" , Port.name ); + printf( "\t[--%s =%d]\n" , MultiClient.name , MultiClient.value ); + printf( "\t[--%s =%s]\n" , Address.name , Address.value.c_str() ); + printf( "\t[--%s =%d]\n" , Threads.name , Threads.value ); + printf( "\t[--%s =%d]\n" , ParallelType.name , ParallelType.value ); + for( size_t i=0 ; i=%d]\n" , ScheduleType.name , ScheduleType.value ); + for( size_t i=0 ; i=%d]\n" , ThreadChunkSize.name , ThreadChunkSize.value ); + printf( "\t[--%s =%d]\n" , PeakMemorySampleMS.name , PeakMemorySampleMS.value ); + printf( "\t[--%s =%d]\n" , MaxMemoryGB.name , MaxMemoryGB.value ); + printf( "\t[--%s]\n" , Pause.name ); +} + +template< typename Real , unsigned int Dim > +void Partition( std::vector< Socket > &serverSockets ) +{ + PointPartitionClientServer::RunClients< Real , Dim >( serverSockets ); + unsigned int peakMem = MemoryInfo::PeakMemoryUsageMB(); + for( unsigned int i=0 ; i +void Reconstruct( std::vector< Socket > &serverSockets ) +{ + PoissonReconClientServer::RunClient< Real , Dim , BType , Degree >( serverSockets , PeakMemorySampleMS.value ); + unsigned int peakMem = MemoryInfo::PeakMemoryUsageMB(); + for( unsigned int i=0 ; i +void Merge( std::vector< Socket > &serverSockets ) +{ + MergePlyClientServer::RunClients< Real , Dim >( serverSockets , PeakMemorySampleMS.value ); + unsigned int peakMem = MemoryInfo::PeakMemoryUsageMB(); + for( unsigned int i=0 ; i +void Reconstruct( unsigned int degree , std::vector< Socket > &serverSockets ) +{ + switch( degree ) + { + case 1: return Reconstruct< Real , Dim , BType , 1 >( serverSockets ); + case 2: return Reconstruct< Real , Dim , BType , 2 >( serverSockets ); + default: ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); + } +} + +template< typename Real , unsigned int Dim > +void Reconstruct( BoundaryType bType , unsigned int degree , std::vector< Socket > &serverSockets ) +{ + switch( bType ) + { + case BOUNDARY_FREE: return Reconstruct< Real , Dim , BOUNDARY_FREE >( degree , serverSockets ); + case BOUNDARY_NEUMANN: return Reconstruct< Real , Dim , BOUNDARY_NEUMANN >( degree , serverSockets ); + case BOUNDARY_DIRICHLET: return Reconstruct< Real , Dim , BOUNDARY_DIRICHLET >( degree , serverSockets ); + default: ERROR_OUT( "Not a valid boundary type: " , bType ); + } +} + +template< typename Real , unsigned int Dim > +void Reconstruct( std::vector< Socket > &serverSockets ) +{ + BoundaryType bType; + unsigned int degree; + for( unsigned int i=0 ; i( bType , degree , serverSockets ); +} + +#endif // FAST_COMPILE + +int main( int argc , char* argv[] ) +{ +#ifdef ARRAY_DEBUG + WARN( "Array debugging enabled" ); +#endif // ARRAY_DEBUG +#ifdef USE_DOUBLE + typedef double Real; +#else // !USE_DOUBLE + typedef float Real; +#endif // USE_DOUBLE + static const unsigned int Dim = DEFAULT_DIMENSION; + + Timer timer; + cmdLineParse( argc-1 , &argv[1] , params ); + + if( !Port.set ) + { + ShowUsage( argv[0] ); + return 0; + } + + if( MaxMemoryGB.value>0 ) SetPeakMemoryMB( MaxMemoryGB.value<<10 ); + ThreadPool::DefaultChunkSize = ThreadChunkSize.value; + ThreadPool::DefaultSchedule = (ThreadPool::ScheduleType)ScheduleType.value; + ThreadPool::Init( (ThreadPool::ParallelType)ParallelType.value , Threads.value ); + + std::vector< Socket > serverSockets( MultiClient.value , NULL ); + for( unsigned int i=0 ; i<(unsigned int)MultiClient.value ; i++ ) serverSockets[i] = GetConnectSocket( Address.value.c_str() , Port.value , SOCKET_CONNECT_WAIT , false ); + + { + Partition< Real , Dim >( serverSockets ); + +#ifdef FAST_COMPILE + Reconstruct< Real , Dim , DEFAULT_FEM_BOUNDARY , DEFAULT_FEM_DEGREE >( serverSockets ); +#else // !FAST_COMPILE + Reconstruct< Real , Dim >( serverSockets ); +#endif // FAST_COMPILE + + Merge< Real , Dim >( serverSockets ); + + for( unsigned int i=0 ; i +#include +#include +#include +#include "PointPartition.h" +#include "FEMTree.h" +#include "VertexFactory.h" +#include "Socket.h" +#include "PoissonRecon.h" + +namespace PoissonReconClientServer +{ + template< typename Real , unsigned int Dim > + struct ClientReconstructionInfo + { + enum ShareType + { + BACK , + CENTER , + FRONT + }; + enum MergeType + { + TOPOLOGY_AND_FUNCTION , // Identical topology across slice + FUNCTION , // Identical function across slice + NONE + }; + + std::string header , inDir , tempDir , outDir; + unsigned int solveDepth , reconstructionDepth , sharedDepth , distributionDepth , baseDepth , kernelDepth , iters , bufferSize , filesPerDir , padSize , verbose; + Real pointWeight , confidence , confidenceBias , samplesPerNode , dataX , cgSolverAccuracy; + MergeType mergeType; + bool density , linearFit , ouputVoxelGrid; + std::vector< PlyProperty > auxProperties; + + ClientReconstructionInfo( void ); + ClientReconstructionInfo( BinaryStream &stream ); + + void write( BinaryStream &stream ) const; + + std::string sharedFile( unsigned int idx , ShareType shareType=CENTER ) const; + }; + + template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > + std::vector< unsigned int > RunServer + ( + PointPartition::PointSetInfo< Real , Dim > pointSetInfo , + PointPartition::Partition pointPartition , + std::vector< Socket > clientSockets , + ClientReconstructionInfo< Real , Dim > clientReconInfo , + unsigned int baseVCycles , + unsigned int sampleMS , + bool showDiscontinuity=false , + bool outputBoundarySlices=false + ); + + template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > + void RunClient( std::vector< Socket > &serverSockets , unsigned int sampleMS ); + +#include "PoissonReconClientServer.inl" +#include "PoissonRecon.server.inl" +#include "PoissonRecon.client.inl" +} + +#endif // POISSON_RECON_CLIENT_SERVER_INCLUDED \ No newline at end of file diff --git a/Src/PoissonReconClientServer.inl b/Src/PoissonReconClientServer.inl new file mode 100644 index 00000000..1da6f7cc --- /dev/null +++ b/Src/PoissonReconClientServer.inl @@ -0,0 +1,386 @@ +/* +Copyright (c) 2023, 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. +*/ + + +template< typename Real , unsigned int Dim > +using SampleDataType = VectorTypeUnion< Real , typename VertexFactory::NormalFactory< Real , Dim >::VertexType , typename VertexFactory::DynamicFactory< Real >::VertexType >; + +template< typename Real , unsigned int Dim > +struct SampleDataTypeSerializer : public Serializer< SampleDataType< Real , Dim > > +{ + using Normal = typename VertexFactory::NormalFactory< Real , Dim >::VertexType; + using AuxData = typename VertexFactory::DynamicFactory< Real >::VertexType; + using Data = VectorTypeUnion< Real , Normal , AuxData >; + + SampleDataTypeSerializer( const std::vector< PlyProperty > &properties ) : _factory( properties ){} + + size_t size( void ) const { return sizeof(Normal) + _factory.bufferSize(); } + + void serialize( const Data &data , Pointer( char )buffer ) const + { + memcpy( buffer , &data.template get<0>() , sizeof(Normal) ); + _factory.toBuffer( data.template get<1>() , buffer+sizeof(Normal) ); + } + void deserialize( ConstPointer( char ) buffer , Data &data ) const + { + Point< Real > p = _factory(); + memcpy( &data.template get<0>() , buffer , sizeof(Normal) ); + _factory.fromBuffer( buffer+sizeof(Normal) , p ); + data.template get<1>() = p; + } +protected: + VertexFactory::DynamicFactory< Real > _factory; +}; + +template< typename Real , unsigned int Dim > +struct ProjectiveSampleDataTypeSerializer : public Serializer< ProjectiveData< SampleDataType< Real , Dim > , Real > > +{ + using Normal = typename VertexFactory::NormalFactory< Real , Dim >::VertexType; + using AuxData = typename VertexFactory::DynamicFactory< Real >::VertexType; + using Data = ProjectiveData< VectorTypeUnion< Real , Normal , AuxData > , Real >; + + ProjectiveSampleDataTypeSerializer( const std::vector< PlyProperty > &properties ) : _factory( properties ){} + + size_t size( void ) const { return sizeof( Real ) + sizeof(Normal) + _factory.bufferSize(); } + + void serialize( const Data &data , Pointer( char )buffer ) const + { + memcpy( buffer , &data.weight , sizeof(Real) ); + memcpy( buffer + sizeof(Real) , &data.data.template get<0>() , sizeof(Normal) ); + _factory.toBuffer( data.data.template get<1>() , buffer+sizeof(Real)+sizeof(Normal) ); + } + void deserialize( ConstPointer( char ) buffer , Data &data ) const + { + Point< Real > p = _factory(); + memcpy( &data.weight , buffer , sizeof(Real) ); + memcpy( &data.data.template get<0>() , buffer+sizeof(Real) , sizeof(Normal) ); + _factory.fromBuffer( buffer+sizeof(Real)+sizeof(Normal) , p ); + data.data.template get<1>() = p; + } +protected: + VertexFactory::DynamicFactory< Real > _factory; +}; + +std::string SendDataString( unsigned int phase , size_t ioBytes ) +{ + std::stringstream ss; + ss << "[SEND " << phase << "] "; + size_t sz; + std::string type; + if ( ioBytes<(1<<10) ) sz = (ioBytes>> 0) , type = " B"; + else if( ioBytes<(1<<20) ) sz = (ioBytes>>10) , type = "KiB"; + else if( ioBytes<(1<<30) ) sz = (ioBytes>>20) , type = "MiB"; + else sz = (ioBytes>>30) , type = "GiB"; + if ( sz<10 ) ss << " "; + else if( sz<100 ) ss << " "; + else if( sz<1000 ) ss << " "; + ss << sz << " " << type << ": "; + return ss.str(); +} +std::string ReceiveDataString( unsigned int phase , size_t ioBytes ) +{ + std::stringstream ss; + ss << "[RECEIVE " << phase << "] "; + size_t sz; + std::string type; + if ( ioBytes<(1<<10) ) sz = (ioBytes>> 0) , type = " B"; + else if( ioBytes<(1<<20) ) sz = (ioBytes>>10) , type = "KiB"; + else if( ioBytes<(1<<30) ) sz = (ioBytes>>20) , type = "MiB"; + else sz = (ioBytes>>30) , type = "GiB"; + if ( sz<10 ) ss << " "; + else if( sz<100 ) ss << " "; + else if( sz<1000 ) ss << " "; + ss << sz << " " << type << ": "; + return ss.str(); +} + +template< unsigned int Dim > +void TreeAddressesToIndices( Pointer( RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > ) nodes , size_t nodeCount ) +{ + typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; + + for( size_t i=0 ; i +void TreeIndicesToAddresses( Pointer( RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > ) nodes , size_t nodeCount ) +{ + typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; + + for( size_t i=0 ; i +struct ClientServerStream : BinaryStream +{ + template< typename Real , unsigned int Dim > + static void Reset( unsigned int idx , const ClientReconstructionInfo< Real , Dim > &clientReconInfo ) + { + auto CleanUp =[]( std::string fileName ) + { + std::ifstream fs; + fs.open( fileName , std::ios::in | std::ios::binary ); + if( fs.is_open() ) + { + fs.close(); + remove( fileName.c_str() ); + } + }; + { + CleanUp( clientReconInfo.sharedFile( idx , ClientReconstructionInfo< Real , Dim >::ShareType::BACK ) ); + CleanUp( clientReconInfo.sharedFile( idx , ClientReconstructionInfo< Real , Dim >::ShareType::CENTER ) ); + CleanUp( clientReconInfo.sharedFile( idx , ClientReconstructionInfo< Real , Dim >::ShareType::FRONT ) ); + } + } + + ClientServerStream( ClientServerStream &&css ) : _socket( std::move( css )._socket ) , _fs( std::move( css )._fs ) , _fileName( std::move( css )._fileName ) {} + + template< typename Real , unsigned int Dim > + ClientServerStream( SocketStream &socket , unsigned int idx , const ClientReconstructionInfo< Real , Dim > &clientReconInfo , typename ClientReconstructionInfo< Real , Dim >::ShareType shareType = ClientReconstructionInfo< Real , Dim >::CENTER , unsigned int maxTries=-1 ) + : _socket(socket) + { + _fileName = clientReconInfo.sharedFile( idx , shareType ); + if constexpr( ReadFromFile ) + { + // Check that the file exists and is the right size + auto validFile = []( std::string fileName , size_t sz ) + { + std::ifstream fs; + fs.open( fileName , std::ios::in | std::ios::binary ); + if( !fs.is_open() ) return false; + + fs.seekg ( 0 , fs.end ); + if( fs.tellg()!=sz ) + { + std::cout << fs.tellg() << " / " << sz << std::endl; + return false; + } + else return true; + }; + size_t sz; + _socket.read( sz ); + unsigned int tries=0; + while( !validFile( _fileName , sz ) && tries::type _fs; + SocketStream &_socket; + std::string _fileName; + + bool _read( Pointer( unsigned char ) ptr , size_t sz ) + { + if constexpr( ReadFromFile ) return (bool)_fs.read ( ( char * )PointerAddress( ptr ) , sz ); + else return false; + } + bool _write( ConstPointer( unsigned char ) ptr , size_t sz ) + { + if constexpr( !ReadFromFile ) return (bool)_fs.write( ( const char * )PointerAddress( ptr ) , sz ); + else return false; + } +}; + +struct PhaseInfo +{ + double processTime , readTime , writeTime; + size_t readBytes , writeBytes; + + PhaseInfo( void ) : processTime(0) , readTime(0) , writeTime(0) , readBytes(0) , writeBytes(0) {} + + PhaseInfo &operator += ( const PhaseInfo &pi ) + { + processTime += pi.processTime; + readTime += pi.readTime; + readBytes += pi.readBytes; + writeBytes += pi.writeBytes; + return *this; + } +}; + +////////////////////////////// +// ClientReconstructionInfo // +////////////////////////////// +template< typename Real , unsigned int Dim > +ClientReconstructionInfo< Real , Dim >::ClientReconstructionInfo( void ) +{ + distributionDepth = 0; + baseDepth = 5; + iters = 8; + confidence = (Real)0.; + confidenceBias = (Real)0.; + samplesPerNode = (Real)1.5; + dataX = (Real)32.; + density = false; + linearFit = false; + mergeType = MergeType::TOPOLOGY_AND_FUNCTION; + bufferSize = BUFFER_IO; + filesPerDir = -1; +} + +template< typename Real , unsigned int Dim > +ClientReconstructionInfo< Real , Dim >::ClientReconstructionInfo( BinaryStream &stream ) +{ + auto ReadBool = [&]( bool &b ) + { + char _b; + if( !stream.read( _b ) ) return false; + b = _b!=0; + return true; + }; + if( !stream.read( inDir ) ) ERROR_OUT( "Failed to read in dir" ); + if( !stream.read( tempDir ) ) ERROR_OUT( "Failed to read temp dir" ); + if( !stream.read( outDir ) ) ERROR_OUT( "Failed to read out dir" ); + if( !stream.read( header ) ) ERROR_OUT( "Failed to read header" ); + if( !stream.read( bufferSize ) ) ERROR_OUT( "Failed to read buffer size" ); + if( !stream.read( filesPerDir ) ) ERROR_OUT( "Failed to read files per dir" ); + if( !stream.read( reconstructionDepth ) ) ERROR_OUT( "Failed to read reconstruction depth" ); + if( !stream.read( sharedDepth ) ) ERROR_OUT( "Failed to read shared depth" ); + if( !stream.read( distributionDepth ) ) ERROR_OUT( "Failed to read distribution depth" ); + if( !stream.read( baseDepth ) ) ERROR_OUT( "Failed to read base depth" ); + if( !stream.read( kernelDepth ) ) ERROR_OUT( "Failed to read kernel depth" ); + if( !stream.read( solveDepth ) ) ERROR_OUT( "Failed to read solveDepth depth" ); + if( !stream.read( iters ) ) ERROR_OUT( "Failed to read iters" ); + if( !stream.read( cgSolverAccuracy ) ) ERROR_OUT( "Failed to read CG-solver-accuracy" ); + if( !stream.read( pointWeight ) ) ERROR_OUT( "Failed to read point-weight" ); + if( !stream.read( confidence ) ) ERROR_OUT( "Failed to read confidence" ); + if( !stream.read( confidenceBias ) ) ERROR_OUT( "Failed to read confidence-bias" ); + if( !stream.read( samplesPerNode ) ) ERROR_OUT( "Failed to read samples-per-node" ); + if( !stream.read( dataX ) ) ERROR_OUT( "Failed to read data-multiplier" ); + if( !stream.read( padSize ) ) ERROR_OUT( "Failed to read padSize" ); + if( !stream.read( verbose ) ) ERROR_OUT( "Failed to read verbose" ); + if( !stream.read( mergeType ) ) ERROR_OUT( "Failed to read merge-type" ); + if( !ReadBool( density ) ) ERROR_OUT( "Failed to read density flag" ); + if( !ReadBool( linearFit ) ) ERROR_OUT( "Failed to read linear-fit flag" ); + if( !ReadBool( ouputVoxelGrid ) ) ERROR_OUT( "Failed to read output-voxel-grid flag" ); + { + size_t sz; + if( !stream.read( sz ) ) ERROR_OUT( "Failed to read number of auxiliary properties" ); + auxProperties.resize(sz); + for( size_t i=0 ; i +void ClientReconstructionInfo< Real , Dim >::write( BinaryStream &stream ) const +{ + auto WriteBool = [&]( bool b ) + { + char _b = b ? 1 : 0; + stream.write( _b ); + }; + stream.write( inDir ); + stream.write( tempDir ); + stream.write( outDir ); + stream.write( header ); + stream.write( bufferSize ); + stream.write( filesPerDir ); + stream.write( reconstructionDepth ); + stream.write( sharedDepth ); + stream.write( distributionDepth ); + stream.write( baseDepth ); + stream.write( kernelDepth ); + stream.write( solveDepth ); + stream.write( iters ); + stream.write( cgSolverAccuracy ); + stream.write( pointWeight ); + stream.write( confidence ); + stream.write( confidenceBias ); + stream.write( samplesPerNode ); + stream.write( dataX ); + stream.write( padSize ); + stream.write( verbose ); + stream.write( mergeType ); + WriteBool( density ); + WriteBool( linearFit ); + WriteBool( ouputVoxelGrid ); + { + size_t sz = auxProperties.size(); + stream.write( sz ); + for( size_t j=0 ; j +std::string ClientReconstructionInfo< Real , Dim >::sharedFile( unsigned int idx , ShareType shareType ) const +{ + std::stringstream sStream; + switch( shareType ) + { + case BACK: sStream << PointPartition::FileDir( tempDir , header ) << "." << idx << ".back.shared" ; break; + case CENTER: sStream << PointPartition::FileDir( tempDir , header ) << "." << idx << ".shared" ; break; + case FRONT: sStream << PointPartition::FileDir( tempDir , header ) << "." << idx << ".front.shared" ; break; + default: ERROR_OUT( "Unrecognized share type: " , shareType ); + } + return sStream.str(); +} + diff --git a/Src/PoissonReconServer.cpp b/Src/PoissonReconServer.cpp new file mode 100644 index 00000000..403072ee --- /dev/null +++ b/Src/PoissonReconServer.cpp @@ -0,0 +1,515 @@ +/* +Copyright (c) 2023, 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. +*/ + +#define BIG_DATA +#include "PreProcessor.h" + +#include "Socket.h" +#include "PoissonReconClientServer.h" +#include "PointPartitionClientServer.h" +#include "MergePlyClientServer.h" + +#include +#include +#include +#include "MyMiscellany.h" +#include "CmdLineParser.h" +#include "PoissonRecon.h" + + +cmdLineParameter< std::string > + AddressPrefix( "prefix" ) , + In( "in" ) , + TempDir( "tempDir" ) , + Out( "out" ); + +cmdLineParameter< int > + ClientCount( "count" ) , + Port( "port" , 0 ) , + Verbose( "verbose" , 0 ) , +#ifdef FAST_COMPILE +#else // !FAST_COMPILE + Degree( "degree" , DEFAULT_FEM_DEGREE ) , + BType( "bType" , DEFAULT_FEM_BOUNDARY ) , +#endif // FAST_COMPILE + Iters( "iters" , 8 ) , + BaseVCycles( "vCycles" , 1 ) , + KernelDepth( "kernelDepth" ) , + BaseDepth( "baseDepth" , 5 ) , + SolveDepth( "solveDepth" ) , + PadSize( "pad" , 4 ) , + BufferSize( "buffer" , BUFFER_IO ) , + Depth( "depth" , 8 ) , + PartitionDepth( "pDepth" , 5 ) , + FilesPerDir( "filesPerDir" , -1 ) , + MaxMemoryGB( "maxMemory" , 0 ) , + PeakMemorySampleMS( "sampleMS" , 10 ) , +#ifdef _OPENMP + ParallelType( "parallel" , (int)ThreadPool::OPEN_MP ) , +#else // !_OPENMP + ParallelType( "parallel" , (int)ThreadPool::THREAD_POOL ) , +#endif // _OPENMP + ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , + ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , + Threads( "threads" , (int)std::thread::hardware_concurrency() ) ; + +cmdLineReadable + Performance( "performance" ) , + NoLoadBalance( "noLoadBalance" ) , + Density( "density" ) , + LinearFit( "linearFit" ) , + OutputVoxelGrid( "grid" ) , + OutputBoundarySlices( "boundary" ) , + NoFuse( "noFuse" ) , + ShowDiscontinuity( "showDiscontinuity" ); + +cmdLineParameter< float > + Scale( "scale" , 1.1f ) , + Width( "width" , 0.f ) , + Confidence( "confidence" , 0.f ) , + ConfidenceBias( "confidenceBias" , 0.f ) , + SamplesPerNode( "samplesPerNode" , 1.5f ) , + DataX( "data" , 32.f ) , + PointWeight( "pointWeight" ) , + CGSolverAccuracy( "cgAccuracy" , 1e-3f ); + +cmdLineReadable* params[] = +{ + &Port , &ClientCount , &AddressPrefix , &Performance , &Verbose , + &In , + &Scale , + &PartitionDepth , + &FilesPerDir , + &TempDir , + &Out , +#ifdef FAST_COMPILE +#else // !FAST_COMPILE + &Degree , &BType , +#endif // FAST_COMPILE + &Iters , &BaseVCycles , &KernelDepth , &BaseDepth , &PadSize , &BufferSize , &Depth , + &SolveDepth , + &NoLoadBalance , &Density , &LinearFit , + &NoFuse , + &Width , &Confidence , &ConfidenceBias , &SamplesPerNode , &DataX , &PointWeight , &CGSolverAccuracy , + &MaxMemoryGB , &ParallelType , &ScheduleType , &ThreadChunkSize , &Threads , + &PeakMemorySampleMS , + &OutputVoxelGrid , + &OutputBoundarySlices , + &ShowDiscontinuity , + NULL +}; + +void ShowUsage( char* ex ) +{ + printf( "Usage: %s\n" , ex ); + printf( "\t --%s \n" , In.name ); + printf( "\t --%s \n" , TempDir.name ); + printf( "\t --%s \n" , Out.name ); + printf( "\t --%s \n" , ClientCount.name ); + + printf( "\t[--%s ]\n" , AddressPrefix.name ); + printf( "\t[--%s =%d]\n" , Port.name , Port.value ); + +#ifdef FAST_COMPILE +#else // !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=%f]\n" , SamplesPerNode.name, SamplesPerNode.value ); + printf( "\t[--%s =%d]\n" , BaseDepth.name , BaseDepth.value ); + printf( "\t[--%s =%d]\n" , Depth.name , Depth.value ); + printf( "\t[--%s =%d]\n" , PartitionDepth.name , PartitionDepth.value ); + printf( "\t[--%s ]\n" , KernelDepth.name ); + printf( "\t[--%s ]\n" , SolveDepth.name ); + printf( "\t[--%s =%f]\n" , Scale.name , Scale.value ); + printf( "\t[--%s ]\n" , Width.name ); + printf( "\t[--%s =%d]\n" , Iters.name , Iters.value ); + printf( "\t[--%s =%d]\n" , BaseVCycles.name , BaseVCycles.value ); + printf( "\t[--%s =%g]\n" , CGSolverAccuracy.name , CGSolverAccuracy.value ); + printf( "\t[--%s =%.3e * ]\n" , PointWeight.name , DefaultPointWeightMultiplier ); + printf( "\t[--%s =%f]\n" , Confidence.name , Confidence.value ); + printf( "\t[--%s =%f]\n" , ConfidenceBias.name , ConfidenceBias.value ); + printf( "\t[--%s =%f]\n" , DataX.name , DataX.value ); + printf( "\t[--%s =%d]\n" , PadSize.name , PadSize.value ); + printf( "\t[--%s =%d]\n" , BufferSize.name , BufferSize.value ); + printf( "\t[--%s =%d]\n" , Threads.name , Threads.value ); + printf( "\t[--%s =%d]\n" , ParallelType.name , ParallelType.value ); + for( size_t i=0 ; i=%d]\n" , ScheduleType.name , ScheduleType.value ); + for( size_t i=0 ; i=%d]\n" , ThreadChunkSize.name , ThreadChunkSize.value ); + printf( "\t[--%s =%d]\n" , PeakMemorySampleMS.name , PeakMemorySampleMS.value ); + printf( "\t[--%s =%d]\n" , MaxMemoryGB.name , MaxMemoryGB.value ); + printf( "\t[--%s =%u]\n" , FilesPerDir.name , (unsigned int)FilesPerDir.value ); + printf( "\t[--%s =%d]\n" , Verbose.name , Verbose.value ); + printf( "\t[--%s]\n" , NoLoadBalance.name ); + printf( "\t[--%s]\n" , Density.name ); + printf( "\t[--%s]\n" , LinearFit.name ); + printf( "\t[--%s]\n" , OutputVoxelGrid.name ); + printf( "\t[--%s]\n" , OutputBoundarySlices.name ); + printf( "\t[--%s]\n" , ShowDiscontinuity.name ); + printf( "\t[--%s]\n" , NoFuse.name ); + + printf( "\t[--%s]\n" , Performance.name ); +} + +template< typename Real , unsigned int Dim > +std::pair< PointPartition::PointSetInfo< Real , Dim > , PointPartition::Partition > +Partition +( + std::vector< Socket > &clientSockets , + const PointPartitionClientServer::ClientPartitionInfo< Real > &clientPartitionInfo , + bool loadBalance , + bool performance +) +{ + Timer timer; + + std::pair< PointPartition::PointSetInfo< Real , Dim > , PointPartition::Partition > pointSetInfoAndPartition = PointPartitionClientServer::RunServer< Real , Dim >( clientSockets , clientPartitionInfo , loadBalance ); + unsigned int peakMem = 0; + for( unsigned int c=0 ; c( peakMem , _peakMem ); + } + + if( performance ) + { + StreamFloatPrecision sfp( std::cout , 2 ); + std::cout << "Partition performance:" << std::endl; + std::cout << "\tPeak client memory: " << peakMem << " (MB)" << std::endl; + std::cout << "\tPeak server memory: " << MemoryInfo::PeakMemoryUsageMB() << " (MB)" << std::endl; + std::cout << "\tServer Time: " << timer.wallTime() << " (s)" << std::endl; + } + return pointSetInfoAndPartition; +} + +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +std::vector< unsigned int > +Reconstruct +( + const PointPartition::PointSetInfo< Real , Dim > &pointSetInfo , + const PointPartition::Partition &pointPartition , + std::vector< Socket > &clientSockets , + const PoissonReconClientServer::ClientReconstructionInfo< Real , Dim > &clientReconInfo +) +{ + Timer timer; + + // Clean up files if they were not propertly cleaned up before. + for( unsigned int i=0 ; i::Reset( i , clientReconInfo ); + + std::vector< unsigned int > sharedVertexCounts = PoissonReconClientServer::RunServer< Real , Dim , BType , Degree >( pointSetInfo , pointPartition , clientSockets , clientReconInfo , BaseVCycles.value , PeakMemorySampleMS.value<0 ? 0 : PeakMemorySampleMS.value , ShowDiscontinuity.set , OutputBoundarySlices.set ); + + unsigned int peakMem = 0; + for( unsigned int i=0 ; i( peakMem , _peakMem ); + } + + if( Performance.set ) + { + StreamFloatPrecision sfp( std::cout , 2 ); + std::cout << "Reconstruction performance:" << std::endl; + std::cout << "\tPeak client memory: " << peakMem << " (MB)" << std::endl; + std::cout << "\tPeak server memory: " << MemoryInfo::PeakMemoryUsageMB() << " (MB)" << std::endl; + std::cout << "\tServer Time: " << timer.wallTime() << " (s)" << std::endl; + } + + return sharedVertexCounts; +} + + +#ifdef FAST_COMPILE +#else // !FAST_COMPILE +template< typename Real , unsigned int Dim , BoundaryType BType > +std::vector< unsigned int > Reconstruct( unsigned int degree , const PointPartition::PointSetInfo< Real , Dim > &pointSetInfo , const PointPartition::Partition &partition , std::vector< Socket > clientSockets , const PoissonReconClientServer::ClientReconstructionInfo< Real , Dim > &clientReconInfo ) +{ + switch( degree ) + { + case 1: return Reconstruct< Real , Dim , BType , 1 >( pointSetInfo , partition , clientSockets , clientReconInfo ); + case 2: return Reconstruct< Real , Dim , BType , 2 >( pointSetInfo , partition , clientSockets , clientReconInfo ); + default: ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); + } + return std::vector< unsigned int >(); +} + +template< typename Real , unsigned int Dim > +std::vector< unsigned int > Reconstruct( BoundaryType bType , unsigned int degree , const PointPartition::PointSetInfo< Real , Dim > &pointSetInfo , const PointPartition::Partition &partition , std::vector< Socket > clientSockets , const PoissonReconClientServer::ClientReconstructionInfo< Real , Dim > &clientReconInfo ) +{ + for( unsigned int i=0 ; i( degree , pointSetInfo , partition , clientSockets , clientReconInfo ); + case BOUNDARY_NEUMANN: return Reconstruct< Real , Dim , BOUNDARY_NEUMANN >( degree , pointSetInfo , partition , clientSockets , clientReconInfo ); + case BOUNDARY_DIRICHLET: return Reconstruct< Real , Dim , BOUNDARY_DIRICHLET >( degree , pointSetInfo , partition , clientSockets , clientReconInfo ); + default: ERROR_OUT( "Not a valid boundary type: " , bType ); + } + return std::vector< unsigned int >(); +} +#endif // FAST_COMPILE + +template< typename Real , unsigned int Dim> +void Merge +( + const std::vector< unsigned int > &sharedVertexCounts , + std::string header , + std::vector< Socket > &clientSockets , + const MergePlyClientServer::ClientMergePlyInfo &clientMergePlyInfo +) +{ + Timer timer; + + MergePlyClientServer::RunServer< Real , Dim >( TempDir.value , TempDir.value , header , Out.value , clientSockets , sharedVertexCounts , clientMergePlyInfo , PeakMemorySampleMS.value ); + + unsigned int peakMem = 0; + for( unsigned int i=0 ; i( peakMem , _peakMem ); + } + + if( Performance.set ) + { + StreamFloatPrecision sfp( std::cout , 2 ); + std::cout << "Merge performance:" << std::endl; + std::cout << "\tPeak client memory: " << peakMem << " (MB)" << std::endl; + std::cout << "\tPeak server memory: " << MemoryInfo::PeakMemoryUsageMB() << " (MB)" << std::endl; + std::cout << "\tServer Time: " << timer.wallTime() << " (s)" << std::endl; + } +} + +int main( int argc , char* argv[] ) +{ +#ifdef ARRAY_DEBUG + WARN( "Array debugging enabled" ); +#endif // ARRAY_DEBUG +#ifdef USE_DOUBLE + typedef double Real; +#else // !USE_DOUBLE + typedef float Real; +#endif // USE_DOUBLE + static const unsigned int Dim = DEFAULT_DIMENSION; + + cmdLineParse( argc-1 , &argv[1] , params ); + + if( !In.set || !TempDir.set || !Out.set || !ClientCount.set ) + { + ShowUsage( argv[0] ); + return 0; + } + if( PadSize.value<0 ) ERROR_OUT( "Padding size cannot be negative" ); + + if( Verbose.value>1 ) + { + std::cout << "***********************************************************" << std::endl; + std::cout << "***********************************************************" << std::endl; + std::cout << "** Running Poisson Reconstruction Server (Version " << VERSION << ") **" << std::endl; + std::cout << "***********************************************************" << std::endl; + std::cout << "***********************************************************" << std::endl; + } + +#ifdef FAST_COMPILE + if( !PointWeight.set ) PointWeight.value = DefaultPointWeightMultiplier * DEFAULT_FEM_DEGREE; +#else // !FAST_COMPILE + if( !PointWeight.set ) PointWeight.value = DefaultPointWeightMultiplier * Degree.value; +#endif // FAST_COMPILE + + if( Depth.set && Width.value>0 ) + { + WARN( "Both --" , Depth.name , " and --" , Width.name , " set, ignoring --" , Width.name ); + Width.value = 0; + } + + if( MaxMemoryGB.value>0 ) SetPeakMemoryMB( MaxMemoryGB.value<<10 ); + ThreadPool::DefaultChunkSize = ThreadChunkSize.value; + ThreadPool::DefaultSchedule = (ThreadPool::ScheduleType)ScheduleType.value; + ThreadPool::Init( (ThreadPool::ParallelType)ParallelType.value , Threads.value ); + if( !Threads.set && Verbose.value>1 ) std::cout << "Running with " << Threads.value << " threads" << std::endl; + std::string header; + + // Create the connections to the clients + std::vector< Socket > clientSockets( ClientCount.value ); + { + int port = Port.value; + + char address[512]; + GetHostAddress( address , AddressPrefix.value.c_str() ); + + // Create a listening SOCKET for connecting to server + AcceptorSocket listenSocket = GetListenSocket( port ); + if( listenSocket == _INVALID_ACCEPTOR_SOCKET_ ) ERROR_OUT( "Could not create listener socket" ); + std::cout << "Server Address: " << address << ":" << port << std::endl; + { + std::stringstream ss; + ss << "PR_" << port; + header = ss.str(); + } + + // Establish a connection to the clients + for( unsigned int i=0 ; i<(unsigned int)ClientCount.value ; i++ ) + { + clientSockets[i] = AcceptSocket( listenSocket ); + if( Verbose.value>1 ) std::cout << "Connected to process: " << (i+1) << " / " << ClientCount.value << std::endl; + } + CloseAcceptorSocket( listenSocket ); + } + std::vector< unsigned int > sharedVertexCounts; + + + std::pair< PointPartition::PointSetInfo< Real , Dim > , PointPartition::Partition > pointSetInfoAndPartition; + + // Get the partitioned points + { + PointPartition::CreatePointSlabDirs( PointPartition::FileDir( TempDir.value , header ) , 1< clientPartitionInfo; + clientPartitionInfo.in = In.value; + clientPartitionInfo.tempDir = TempDir.value; + clientPartitionInfo.outDir = TempDir.value; + clientPartitionInfo.outHeader = header; + clientPartitionInfo.slabs = 1<1; + pointSetInfoAndPartition = Partition< Real , Dim >( clientSockets , clientPartitionInfo , !NoLoadBalance.set , Performance.set ); + } + + // Reconstruct the slabs + { + if( Width.value>0 ) + { + Real maxScale = 0; + for( unsigned int i=0 ; i( maxScale , (Real)1./pointSetInfoAndPartition.first.modelToUnitCube(i,i) ); + Depth.value = (unsigned int)ceil( std::max< double >( 0. , log( maxScale/Width.value )/log(2.) ) ); + } + PoissonReconClientServer::ClientReconstructionInfo< Real , Dim > clientReconInfo; + clientReconInfo.inDir = TempDir.value; + clientReconInfo.tempDir = TempDir.value; + clientReconInfo.outDir = TempDir.value; + clientReconInfo.header = header; + clientReconInfo.bufferSize = BufferSize.value; + clientReconInfo.iters = Iters.value; + clientReconInfo.pointWeight = PointWeight.value; + clientReconInfo.confidence = Confidence.value; + clientReconInfo.confidenceBias = ConfidenceBias.value; + clientReconInfo.kernelDepth = KernelDepth.value; + clientReconInfo.solveDepth = SolveDepth.value; + clientReconInfo.samplesPerNode = SamplesPerNode.value; + clientReconInfo.dataX = DataX.value; + clientReconInfo.density = Density.set; + clientReconInfo.linearFit = LinearFit.set; + PoissonReconClientServer::ClientReconstructionInfo< Real , Dim >::MergeType::TOPOLOGY_AND_FUNCTION; + clientReconInfo.ouputVoxelGrid = OutputVoxelGrid.set; + clientReconInfo.verbose = Verbose.value; + clientReconInfo.filesPerDir = FilesPerDir.value; + clientReconInfo.padSize = PadSize.value; + + clientReconInfo.reconstructionDepth = Depth.value; + clientReconInfo.sharedDepth = 0; + while( ((size_t)1<clientReconInfo.reconstructionDepth ) ERROR_OUT( "Slab depth cannot exceed reconstruction depth: " , clientReconInfo.sharedDepth , " <= " , clientReconInfo.reconstructionDepth ); + if( clientReconInfo.baseDepth>clientReconInfo.sharedDepth ) + { + if( BaseDepth.set ) ERROR_OUT( "Base depth cannot exceed shared depth: " , clientReconInfo.baseDepth , " <=" , clientReconInfo.sharedDepth ); + else clientReconInfo.baseDepth = clientReconInfo.sharedDepth; + } + if( !KernelDepth.set ) KernelDepth.value = clientReconInfo.reconstructionDepth-2; + clientReconInfo.kernelDepth = KernelDepth.value; + + if( clientReconInfo.kernelDepth>clientReconInfo.reconstructionDepth ) + { + WARN( "Kernel depth should not exceed depth: " , clientReconInfo.kernelDepth , " <= " , clientReconInfo.reconstructionDepth ); + clientReconInfo.kernelDepth = clientReconInfo.reconstructionDepth; + } + + clientReconInfo.solveDepth = SolveDepth.set ? SolveDepth.value : clientReconInfo.reconstructionDepth; + if( clientReconInfo.solveDepth>clientReconInfo.reconstructionDepth ) + { + WARN( "Solve depth cannot exceed reconstruction depth: " , clientReconInfo.solveDepth , " <= " , clientReconInfo.reconstructionDepth ); + clientReconInfo.solveDepth = clientReconInfo.reconstructionDepth; + } + if( clientReconInfo.solveDepth= " , clientReconInfo.baseDepth ); + clientReconInfo.solveDepth = clientReconInfo.baseDepth; + } +#ifdef FAST_COMPILE + sharedVertexCounts = Reconstruct< Real , Dim , DEFAULT_FEM_BOUNDARY , DEFAULT_FEM_DEGREE >( pointSetInfoAndPartition.first , pointSetInfoAndPartition.second , clientSockets , clientReconInfo ); +#else // !FAST_COMPILE + sharedVertexCounts = Reconstruct< Real , Dim >( (BoundaryType)BType.value , Degree.value , pointSetInfoAndPartition.first , pointSetInfoAndPartition.second , clientSockets , clientReconInfo ); +#endif // FAST_COMPILE + } + + if( Verbose.value>1 && !NoFuse.set ) + for( unsigned int i=0 ; i( sharedVertexCounts , header , clientSockets , clientMergePlyInfo ); + + auto InFile = [&]( unsigned int idx ) + { + std::stringstream ss; + ss << header << "." << idx << ".ply"; + return PointPartition::FileDir( TempDir.value , ss.str() ); + }; + + for( unsigned int i=0 ; i15. #endif // BIG_DATA -#define VERSION "13.99" // The version of the code +#define VERSION "14.00" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file diff --git a/Src/SSDRecon.cpp b/Src/SSDRecon.cpp index f9240a98..43affc71 100644 --- a/Src/SSDRecon.cpp +++ b/Src/SSDRecon.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +Copyright (c) 2014, Michael Kazhdan All rights reserved. Redistribution and use in source and binary forms, with or without modification, diff --git a/Src/Socket.h b/Src/Socket.h new file mode 100644 index 00000000..481297ee --- /dev/null +++ b/Src/Socket.h @@ -0,0 +1,151 @@ +/* +Copyright (c) 2008, 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 SOCKET_INCLUDED +#define SOCKET_INCLUDED + +#ifdef _WIN32 +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0601 +#endif // _WIN32_WINNT +#endif // _WIN32 + +#include +#include +#include +#include +#include "Array.h" +#include "MyMiscellany.h" +#include "Streams.h" + +static const unsigned int SOCKET_CONNECT_WAIT = 500; // Default time to wait on a socket (in ms) + +typedef boost::asio::ip::tcp::socket *Socket; +typedef boost::asio::ip::tcp::acceptor *AcceptorSocket; +typedef boost::asio::ip::address EndpointAddress; +const Socket _INVALID_SOCKET_ = (Socket)NULL; +const AcceptorSocket _INVALID_ACCEPTOR_SOCKET_ = (AcceptorSocket)NULL; +static boost::asio::io_service io_service; + +template< class C > int socket_receive( Socket &s , C *destination , size_t len ) +{ + boost::system::error_code ec; + int ret = (int)( boost::asio::read( *s , boost::asio::buffer( destination , len ) , ec ) ); + if( ec ) ERROR_OUT( "Failed to read from socket" ); + return ret; +} + +template< class C > int socket_send( Socket& s , const C* source , size_t len ) +{ + boost::system::error_code ec; + int ret = (int)( boost::asio::write( *s , boost::asio::buffer( source , len ) , ec ) ); + if( ec ) ERROR_OUT( "Failed to write to socket" ); + return ret; +} + +inline bool AddressesEqual( const EndpointAddress& a1 , const EndpointAddress& a2 ){ return a1.to_string()==a2.to_string(); } +inline const char *LastSocketError( void ){ return ""; } +inline void PrintHostAddresses( FILE* fp ) +{ + boost::asio::ip::tcp::resolver resolver( io_service ); + boost::asio::ip::tcp::resolver::query query( boost::asio::ip::host_name() , std::string( "" ) , boost::asio::ip::resolver_query_base::numeric_service ); + boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve( query ) , end; + for( int count=0 ; iterator!=end ; ) + { + if( (*iterator).endpoint().address().is_v4() ) fprintf( fp , "%d] %s\n" , count++ , (*iterator).endpoint().address().to_string().c_str() ); + // else fprintf( fp , "%d]* %s\n" , count++ , (*iterator).endpoint().address().to_string().c_str() ); + iterator++; + } +} + +#ifdef ARRAY_DEBUG +template< class C > +int socket_receive( Socket& s , Array< C > destination , size_t len ) +{ + if( len>destination.maximum()*sizeof( C ) ) + { + fprintf( stderr , "Size of socket_receive exceeds destination maximum: %zd > %zd\n" , len , destination.maximum()*sizeof( C ) ); + ASSERT( 0 ); + exit( 0 ); + } + return socket_receive( s , (char*)&destination[0] , len ); +} +template< class C > +int socket_send( Socket s , ConstArray< C > source , size_t len ) +{ + if( len>source.maximum()*sizeof( C ) ) + { + fprintf( stderr , "Size of socket_send exceeds source maximum: %zd > %zd\n" , len , source.maximum()*sizeof( C ) ); + ASSERT( 0 ); + exit( 0 ); + } + return socket_send( s , (char*)&source[0] , len ); +} +#endif // ARRAY_DEBUG + +class ConnectionData +{ +public: + EndpointAddress localAddr , peerAddr; + int localPort , peerPort; +}; + + +template< class C > bool ReceiveOnSocket( Socket &s , Pointer( C ) data , size_t dataSize ); +template< class C > bool SendOnSocket ( Socket &s , ConstPointer( C ) data , size_t dataSize ); +template< class C > bool SendOnSocket ( Socket &s , Pointer( C ) data , size_t dataSize ); +template< class C > void ReceiveOnSocket( Socket &s , Pointer( C ) data , size_t dataSize , const char *errorMessage , ... ); +template< class C > void SendOnSocket ( Socket &s , ConstPointer( C ) data , size_t dataSize , const char *errorMessage , ... ); +template< class C > void SendOnSocket ( Socket &s , Pointer( C ) data , size_t dataSize , const char *errorMessage , ... ); + +AcceptorSocket GetListenSocket( int& port ); +Socket AcceptSocket( AcceptorSocket listen ); +Socket GetConnectSocket( const char* address , int port , int ms=5 , bool progress=false ); +Socket GetConnectSocket( EndpointAddress , int port , int ms=5 , bool progress=false ); +void CloseSocket( Socket& s ); +void CloseAcceptorSocket( AcceptorSocket& s ); +EndpointAddress GetLocalSocketEndpointAddress( Socket& s ); +int GetLocalSocketPort ( Socket& s ); +EndpointAddress GetLocalSocketEndpointAddress( Socket& s ); +int GetPeerSocketPort ( Socket& s ); +bool GetHostAddress( char* address , const char* prefix = NULL ); +bool GetHostEndpointAddress( EndpointAddress* address , const char* prefix=NULL ); +void PrintHostAddress( void ); + +struct SocketStream : public BinaryStream +{ + SocketStream( Socket socket=_INVALID_SOCKET_ ) : _socket(socket){} +protected: + Socket _socket; + bool _read( Pointer( unsigned char ) ptr , size_t sz ){ return socket_receive( _socket , ptr , sizeof(unsigned char)*sz )==sz; } + bool _write( ConstPointer( unsigned char ) ptr , size_t sz ){ return socket_send ( _socket , ptr , sizeof(unsigned char)*sz )==sz; } +}; + + +#include "Socket.inl" +#endif // SOCKET_INCLUDED diff --git a/Src/Socket.inl b/Src/Socket.inl new file mode 100644 index 00000000..aee55835 --- /dev/null +++ b/Src/Socket.inl @@ -0,0 +1,239 @@ +/* +Copyright (c) 2008, 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. +*/ + +template +bool ReceiveOnSocket( Socket& s , Pointer( C ) data , size_t dataSize ) +{ +#ifdef ARRAY_DEBUG + if( dataSize>data.maximum()*sizeof( C ) ) ERROR_OUT( "Size of socket read exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); +#endif // ARRAY_DEBUG + unsigned long long rec=0; + while( rec!=dataSize ) + { + int tmp = socket_receive( s , ( ( Pointer( char ) ) data) + rec , dataSize-rec ); + if( tmp<=0 ) + { + if( !tmp ) ERROR_OUT( "Connection Closed" ); + else ERROR_OUT( "socket_receive from client failed: " , LastSocketError() ); + return false; + } + rec+=tmp; + } + return true; +} + +template +bool SendOnSocket( Socket& s , ConstPointer( C ) data , size_t dataSize ) +{ +#ifdef ARRAY_DEBUG + if( dataSize>data.maximum()*sizeof( C ) ) ERROR_OUT( "Size of socket write exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); +#endif // ARRAY_DEBUG + if( socket_send( s , ( ConstPointer( char ) )data , dataSize )<0 ) + { + ERROR_OUT( "socket_send to client failed (" , s , "): " , LastSocketError() ); + return false; + } + return true; +} + +template +bool SendOnSocket( Socket& s , Pointer( C ) data , size_t dataSize ){ return SendOnSocket( ( ConstPointer( C ) )data , dataSize ); } + +template +void ReceiveOnSocket( Socket& s , Pointer( C ) data , size_t dataSize , const char* errorMessage , ... ) +{ +#ifdef ARRAY_DEBUG + if( dataSize>data.maximum()*sizeof( C ) ) ERROR_OUT( "Size of socket read exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); +#endif // ARRAY_DEBUG + unsigned long long rec=0; + while( rec!=dataSize ) + { + int tmp = socket_receive( s , ( ( Pointer( char ) ) data) + rec , dataSize-rec ); + if( tmp<=0 ) + { + if( !tmp ) ERROR_OUT( "Connection Closed" ); + else ERROR_OUT( "socket_receive from client failed: " , LastSocketError() ); + { + fprintf( stderr , "\t" ); + va_list args; + va_start( args , errorMessage ); + vfprintf( stderr , errorMessage , args ); + va_end( args ); + fprintf( stderr , "\n" ); + } + exit(0); + } + rec+=tmp; + } +} + +template +void SendOnSocket( Socket& s , ConstPointer( C ) data , size_t dataSize , const char* errorMessage , ... ) +{ +#ifdef ARRAY_DEBUG + if( dataSize>data.maximum()*sizeof( C ) ) ERROR_OUT( "Size of socket write exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); +#endif // ARRAY_DEBUG + if( socket_send( s , ( ConstPointer( char ) )data , dataSize )<0 ) + { + fprintf( stderr , "socket_send to client failed: %s\n" , LastSocketError()); + exit(0); + } +} + +template +void SendOnSocket( Socket& s , Pointer( C ) data , size_t dataSize , const char* errorMessage , ... ) +{ +#ifdef ARRAY_DEBUG + if( dataSize>data.maximum()*sizeof( C ) ) ERROR_OUT( "Size of socket write exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); +#endif // ARRAY_DEBUG + if( socket_send( s , ( ConstPointer( char ) )data , dataSize )<0 ) + { + fprintf( stderr , "socket_send to client failed: %s\n" , LastSocketError()); + exit(0); + } +} + +inline bool GetHostEndpointAddress( EndpointAddress* address , const char* prefix ) +{ + boost::asio::ip::tcp::resolver resolver( io_service ); + boost::asio::ip::tcp::resolver::query query( boost::asio::ip::host_name() , std::string( "" ) , boost::asio::ip::resolver_query_base::numeric_service ); + boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve( query ) , end; + for( int count=0 ; iterator!=end ; ) + { + if( (*iterator).endpoint().address().is_v4() ) + { + std::string addrss_string = (*iterator).endpoint().address().to_string(); + const char* _address = addrss_string.c_str(); + if( !prefix || strstr( _address , prefix ) ) + { + *address = (*iterator).endpoint().address(); + return true; + } + } + iterator++; + } + return false; +} + +inline bool GetHostAddress( char* address , const char* prefix ) +{ + EndpointAddress _address; + if( !GetHostEndpointAddress( &_address , prefix ) ) return false; + strcpy( address , _address.to_string().c_str() ); + return true; +} + +inline int GetLocalSocketPort( Socket& s ) +{ + return s->local_endpoint().port(); +} + +inline EndpointAddress GetLocalSocketEndpointAddress( Socket& s ) +{ + return s->local_endpoint().address(); +} + +inline int GetPeerSocketPort( Socket& s ) +{ + return s->remote_endpoint().port(); +} + +inline EndpointAddress GetPeerSocketEndpointAddress( Socket& s ) +{ + return s->remote_endpoint().address(); +} + +inline Socket GetConnectSocket( const char* address , int port , int ms , bool progress ) +{ + char _port[128]; + sprintf( _port , "%d" , port ); + boost::asio::ip::tcp::resolver resolver( io_service ); + boost::asio::ip::tcp::resolver::query query( address , _port ); + boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve( query ); + Socket s = new boost::asio::ip::tcp::socket( io_service ); + boost::system::error_code ec; + long long sleepCount = 0; + do + { + boost::asio::connect( *s , resolver.resolve(query) , ec ); + sleepCount++; + std::this_thread::sleep_for( std::chrono::milliseconds( 1 ) ); + if( progress && !(sleepCount%ms) ) printf( "." ); + } + while( ec ); + if( progress ) printf( "\n" ) , fflush( stdout ); + return s; +} + +inline Socket GetConnectSocket( EndpointAddress address , int port , int ms , bool progress ) +{ + char _port[128]; + sprintf( _port , "%d" , port ); + boost::asio::ip::tcp::resolver resolver( io_service ); + boost::asio::ip::tcp::resolver::query query( address.to_string().c_str() , _port ); + boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve( query ); + Socket s = new boost::asio::ip::tcp::socket( io_service ); + boost::system::error_code ec; + long long sleepCount = 0; + do + { + boost::asio::connect( *s , resolver.resolve(query) , ec ); + sleepCount++; + std::this_thread::sleep_for( std::chrono::milliseconds( 1 ) ); + if( progress && !(sleepCount%ms) ) std::cout << "."; + } + while( ec ); + if( progress ) std::cout << std::endl; + return s; +} + +inline Socket AcceptSocket( AcceptorSocket listen ) +{ + Socket s = new boost::asio::ip::tcp::socket( io_service ); + listen->accept( *s ); + return s; +} + +inline AcceptorSocket GetListenSocket( int &port ) +{ + AcceptorSocket s = new boost::asio::ip::tcp::acceptor( io_service , boost::asio::ip::tcp::endpoint( boost::asio::ip::tcp::v4() , port ) ); + port = s->local_endpoint().port(); + return s; +} + +inline void CloseSocket( Socket& s ) +{ + delete s; + s = _INVALID_SOCKET_; +} + +inline void CloseAcceptorSocket( AcceptorSocket& s ) +{ + delete s; + s = _INVALID_ACCEPTOR_SOCKET_; +} diff --git a/Src/VertexFactory.h b/Src/VertexFactory.h index f8a126e8..1c0d1eca 100644 --- a/Src/VertexFactory.h +++ b/Src/VertexFactory.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +Copyright (c) 2020, Michael Kazhdan All rights reserved. Redistribution and use in source and binary forms, with or without modification, diff --git a/Src/VertexFactory.inl b/Src/VertexFactory.inl index cec12038..a71a7fad 100644 --- a/Src/VertexFactory.inl +++ b/Src/VertexFactory.inl @@ -1,5 +1,5 @@ /* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +Copyright (c) 2020, Michael Kazhdan All rights reserved. Redistribution and use in source and binary forms, with or without modification, From 8ff2fadf6a8f8ce5636c79095dc633e5fda07e56 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Tue, 2 May 2023 18:26:08 -0400 Subject: [PATCH 03/86] Update README.md --- README.md | 511 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 378 insertions(+), 133 deletions(-) diff --git a/README.md b/README.md index d81f6673..3bf666b2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ -

    Adaptive Multigrid Solvers (Version 13.99)

    +

    Adaptive Multigrid Solvers (Version 14.00)

    links +compilation executables usage changes @@ -17,80 +18,93 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo LINKS
    + +
    +COMPILATION
    +
      +
    • For efficiency, the code is designed to compile for the specific FEM degree and boundary condition specified in PoissonRecon.h. (Specifically, DEFAULT_FEM_DEGREE is set to 1 and DEFAULT_FEM_BOUNDARY is set to Neumann.) You can change the default values in PoissonRecon.h. You can also compile the code so that it supports varying FEM degrees and boundary conditions by un-#define-ing FAST_COMPILE in PreProcess.h. However, this will make the compilation significantly slower. +
    • By default, the implementation assumes that all indexing can be done with 32-bit integers. If you are reconstructing large scenes and need more bits for indexing, you should enable the BIG_DATA flag in PreProcessor.h. Note that if the generated mesh has more primitives than can be indexed by a 32-bit integer, the output .ply file will store the integers using 64-bit precision (designated by the long long type) instead of the standard 32-bit precision (designated by the int type). Note that this is not a standard format and software like MeshLab may not be able to read the file. +
    • The distributed PSR code uses sockets for communication between the client and the server. These are supported in a cross-platform way via Boost. (The code was developed and tested under Boost version 1.80.0.)
      +
    • To support reading/writing images, the code requires installation of the zlib, png, and jpg libraries. Source code for these is included for compilation using Visual Studios. The Makefile assumes that the header files can be found in /usr/local/include/ and that the library files can be found in /usr/local/lib/. +

    EXECUTABLES
    + +
      PoissonRecon: -Reconstructs a triangle mesh from a set of oriented 3D points by solving a Poisson system (solving a 3D Laplacian system with positional value constraints) [Kazhdan, Bolitho, and Hoppe, 2006], -[Kazhdan and Hoppe, 2013], -[Kazhdan and Hoppe, 2018], -[Kazhdan, Chuang, Rusinkiewicz, and Hoppe, 2020] +Reconstructs a triangle mesh from a set of oriented 3D points by solving a Poisson system (solving a 3D Laplacian system with positional value constraints) [Kazhdan, Bolitho, and Hoppe, 2006], +[Kazhdan and Hoppe, 2013], +[Kazhdan and Hoppe, 2018], +[Kazhdan, Chuang, Rusinkiewicz, and Hoppe, 2020]
      --in <input points>
      This string is the name of the file from which the point set will be read.
      If the file extension is .ply, the file should be in -PLY format, giving the list of oriented +PLY format, giving the list of oriented vertices with the x-, y-, and z-coordinates of the positions encoded by the properties x, y, and z and the x-, y-, and z-coordinates of the normals encoded by the properties nx, ny, and nz .
      @@ -105,12 +119,12 @@ by the x-, y- and z-coordinates of the point's normal. (No information about the
      [--envelope <constraint envelope>]
      This string is the name of the file from which the constraint envelope will be read.
      The file should be a water-tight triangle mesh in -PLY format, oriented so that the normals are pointing +PLY format, oriented so that the normals are pointing in the direction that should be outside of the reconstructed surface.
      [--out <output triangle mesh>]
      This string is the name of the file to which the triangle mesh will be written. -The file is written in PLY format. +The file is written in PLY format.
      [--tree <output octree and coefficients>]
      This string is the name of the file to which the the octree and solution coefficients are to be written. @@ -221,17 +235,204 @@ The default value for this parameter is equal to the numer of (virtual) processo
    + +
      +
      +
      + +PoissonReconServer: +The server responsible for distributed Poisson Surface reconstruction + + +
      --in <input points>
      +
      This string is the name of the file from which the point set will be read.
      +The file is assumed to be in binary PLY format, giving the list of oriented +vertices with the x-, y-, and z-coordinates of the positions encoded by the properties x, y, and +z and the x-, y-, and z-coordinates of the normals encoded by the properties nx, ny, and +nz. (If additional properties, e.g. color, are provided per sample, these will be interpolated in the reconstruction.)
      +
      + +
      --tempDir <networked temporary output directory>
      +
      This string is the name of the directory to which temporary files will be written.
      +The specified (networked) path is assumed to accessible to the server and all clients. +
      + +
      --out <output polygon mesh>
      +
      This string is the name of the file to which the polygon mesh will be written.
      +The file is written in PLY format. +
      + +
      --count <client count>
      +
      This integer values specifies the number of clients that will be connecting to the server to peform the partitioning. +
      + +
      [--port <listening port>]
      +
      This optional integer specifies the port at which the server should listen for client requests.
      +If no port is specified, the server will ask the system to provide one.
      +Regardless of verbosity value, the server will print out the address and port to the command line. +
      + +
      [--depth <reconstruction depth>=8] +
      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 grid whose resolution is no larger than +2^d x 2^d x ... Note that since the reconstructor adapts the octree to the +sampling density, the specified reconstruction depth is only an upper bound.
      +
      + +
      [--pDepth <partition/server depth>=5] +
      This integer is the depth of the tree at which the server performs the reconstruction and is also the depth at which the partitioning of the points happens. Running at a partition/server depth d corresponds to having the server solve over a grid whose resolution is 2^d x 2^d x ... and partitions the point set into 2^d slabs.
      +
      + +
      [--width <finest cell width>] +
      This floating point value specifies the target width of the finest level octree cells.
      +This parameter is ignored if the --depth flag is also specified. +
      + +
      [--degree <B-spline degree>=1] +
      This integer specifies the degree of the B-spline that is to be used to define the finite elements system. +Larger degrees support higher order approximations, but come at the cost of denser system matrices (incurring a cost in both space and time).
      +This option is only available if the code is compiled without the FAST_COMPILE flag #define-ed. +
      + +
      [--bType <boundary type>=3] +
      This integer specifies the boundary type for the finite elements. Valid values are: +
        +
      • 1: Free boundary constraints +
      • 2: Dirichlet boundary constraints +
      • 3: Neumann boundary constraints +
      +This option is only available if the code is compiled without the FAST_COMPILE flag #define-ed. +
      + +
      [--scale <scale factor>=1.1] +
      This floating point value specifies the ratio between the diameter of the cube used for reconstruction +and the diameter of the samples' bounding cube.
      +
      + +
      [--samplesPerNode <minimum number of samples>=1.5] +
      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.
      +
      + +
      [--pointWeight <interpolation weight>=2*<B-spline degree>] +
      This floating point value specifies the importance 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.
      +
      + +
      [--iters <Gauss-Seidel iterations per level>=8] +
      This integer value specifies the number of Gauss-Seidel relaxations to be performed at each level of the octree hierarchy.
      +
      + +
      [--density] +
      Enabling this flag tells the reconstructor to output the estimated depth values of the iso-surface vertices. +
      + +
      [--data <pull factor>=32] +
      If the input points have additional data (e.g. color) that is to be sampled at the output vertices, this floating point value specifies the relative importance +of finer data over lower data in performing the extrapolation.
      +
      + +
      [--confidence <normal confidence exponent>=0] +
      This floating point value specifies the exponent to be applied to a point's confidence to adjust its weight. (A point's confidence is defined by the magnitude of its normal.)
      +
      + +
      [--confidenceBias <normal confidence bias exponent>=0] +
      This floating point value specifies the exponent to be applied to a point's confidence to bias the resolution at which the sample contributes to the linear system. (Points with lower confidence are biased to contribute at coarser resolutions.)
      +
      + +
      [--verbose <verbosity>=0] +
      This integer value specifies the level of verbosity of output provided by the client and server, with "0" corresponding to no output and "4" giving the most.
      +
      + +
      [--linearFit] +
      Enabling this flag has the reconstructor use linear interpolation to estimate the positions of iso-vertices. +
      + +
      [--threads <number of processing threads>={number of (virtual) processors on the executing machine}] +
      This integer specifies the number of threads across which the algorithm should be parallelized. +
      + +
      [--maxMemory <maximum memory usage (in GB)>] +
      If positive, this integer value specifies the peak memory utilization for running the reconstruction code (forcing the execution to terminate if the limit is exceeded).
      +The default value for this parameter is 0. +
      + +
  • [--performance] +
    Enabling this flag provides running time and peak memory usage at the end of the execution. +
    + +
    [--noFuse] +
    Enabling this flag keeps the server from fusing shared vertices across slabs. (The reconstructions from the different clients will still be merged into a single .ply file.) +
    + + + + + +
      +
      +
      + +PoissonReconClient: +The client responsible for distributed Poisson Surface reconstruction + + +
      --port <server port>
      +
      This integer specifies the port at which to connect to the server. +
      + +
      [--address <server address>="127.0.0.1"]
      +
      This optional string specifies the IPv4 address of the server.
      +
      + +
      [--multi <sub-client multiplicity>=1]
      +
      This optional integer specifies the number of sub-clients the client should be running serially. +
      + +
      [--threads <number of processing threads>={number of (virtual) processors on the executing machine}] +
      This integer specifies the number of threads across which the algorithm should be parallelized.
      +The default value for this parameter is equal to the numer of (virtual) processors on the executing machine. +
      + +
      [--maxMemory <maximum memory usage (in GB)>=0] +
      If positive, this integer value specifies the peak memory utilization for running the reconstruction code (forcing the execution to terminate if the limit is exceeded). +
      + +
      [--pause] +
      Enabling this flag has the client wait for the user to enter [ENTER] before closing the process. (Useful if the client is opened in a temporary window, you are running the client with verbose output, and want to see the output.) +
      + +
      +
      +
    + + + +
      SSDRecon: -Reconstructs a surface mesh from a set of oriented 3D points by solving for a Smooth Signed Distance function (solving a 3D bi-Laplacian system with positional value and gradient constraints) [Calakli and Taubin, 2011] +Reconstructs a surface mesh from a set of oriented 3D points by solving for a Smooth Signed Distance function (solving a 3D bi-Laplacian system with positional value and gradient constraints) [Calakli and Taubin, 2011]
      --in <input points>
      This string is the name of the file from which the point set will be read.
      If the file extension is .ply, the file should be in -PLY format, giving the list of oriented +PLY format, giving the list of oriented vertices with the x-, y-, and z-coordinates of the positions encoded by the properties x, y, and z and the x-, y-, and z-coordinates of the normals encoded by the properties nx, ny, and nz .
      @@ -244,7 +445,7 @@ by the x-, y- and z-coordinates of the point's normal. (No information about the
      [--out <output triangle mesh>]
      This string is the name of the file to which the triangle mesh will be written. -The file is written in PLY format. +The file is written in PLY format.
      [--tree <output octree and coefficients>]
      This string is the name of the file to which the the octree and solution coefficients are to be written. @@ -269,7 +470,7 @@ The default value for this parameter is 8.
      [--width <finest cell width>]
      This floating point value specifies the target width of the finest level octree cells.
      -This parameter is ignored if the --depth is also specified. +This parameter is ignored if the --depth flag is also specified.
      [--scale <scale factor>]
      This floating point value specifies the ratio between the diameter of the cube used for reconstruction @@ -465,14 +666,14 @@ Trims off parts of a triangle mesh with a per-vertex signal whose value falls be
      --in <input triangle mesh>
      This string is the name of the file from which the triangle mesh will be read. -The file is read in PLY format and it is assumed that the vertices have a value field which stores the signal's value. (When run with --density flag, the reconstructor will output this field with the mesh vertices.) +The file is read in PLY format and it is assumed that the vertices have a value field which stores the signal's value. (When run with --density flag, the reconstructor will output this field with the mesh vertices.)
      --trim <trimming value>
      This floating point values specifies the value for mesh trimming. The subset of the mesh with signal value less than the trim value is discarded.
      [--out <output triangle mesh>]
      This string is the name of the file to which the triangle mesh will be written. -The file is written in PLY format. +The file is written in PLY format.
      [--smooth <smoothing iterations>]
      This integer values the number of umbrella smoothing operations to perform on the signal before trimming.
      @@ -502,7 +703,7 @@ The default value 0.001.
      ImageStitching: -Stitches together a composite of image tiles into a seamless panorama by solving for the correction term (solving a 2D Laplacian system) [Agarwala, 2007] +Stitches together a composite of image tiles into a seamless panorama by solving for the correction term (solving a 2D Laplacian system) [Agarwala, 2007]
      --in <input composite image> <input label image>
      This pair of strings give the name of the composite image file and the associated label file.
      @@ -516,7 +717,7 @@ PNG and JPG files are supported.
      [--degree <B-spline degree>]
      This integer specifies the degree of the B-spline that is to be used to define the finite elements system. Larger degrees support higher order approximations, but come at the cost of denser system matrices (incurring a cost in both space and time).
      -The default value for this parameter is 1. +The default value for this parameter is 1.
      [--wScl <successive under-relaxation scale>]
      This floating point value specifies the scale for the adapted successive under-relaxation used to remove ringing.
      @@ -559,7 +760,7 @@ Computes the unsigned Euclidean Distance Transform of a triangle mesh (solving t
      --in <input mesh>
      This string is the name of the file from which the triangle mesh will be read. -The file is assumed to be in PLY format. +The file is assumed to be in PLY format.
      [--out <output octree and coefficients>]
      This string is the name of the file to which the the octree and solution coefficients are to be written. @@ -646,7 +847,7 @@ and the next 4 x R^D bytes corresponding to the (single precision)
      [--mesh <output triangle mesh>]
      This string is the name of the file to which the triangle mesh will be written. -The file is written in PLY format.
      +The file is written in PLY format.
      This is only supported for dimension 3.
      [--iso <iso-value for mesh extraction>] @@ -723,10 +924,10 @@ individual components of the visualizer. PoissonRecon / SSDRecon / SurfaceTrimmer / ChunkPly -For testing purposes, three point sets are provided: +For testing purposes, four point sets are provided:
        -
      1. Horse: +
      2. Horse: A set of 100,000 oriented point samples (represented in ASCII format) was obtained by sampling a virtual horse model with a sampling density proportional to curvature, giving a set of non-uniformly distributed points.
        The surface of the model can be reconstructed by calling the either Poisson surface reconstructor:
        % PoissonRecon --in horse.npts --out horse.ply --depth 10
        @@ -734,7 +935,7 @@ or the SSD surface reconstructor
        % SSDRecon --in horse.npts --out horse.ply --depth 10
      3. -
      4. Bunny: +
      5. Bunny: A set of 362,271 oriented point samples (represented in PLY format) was obtained by merging the data from the original Stanford Bunny range scans. The orientation of the sample points was estimated using the connectivity information within individual range scans.
        @@ -745,8 +946,8 @@ By default, the Poisson surface reconstructor uses degree-2 B-splines. A more ef (The SSD reconstructor requires B-splines of degree at least 2 since second derivatives are required to formulate the bi-Laplacian energy.)
      6. -
      7. Eagle: -A set of 796,825 oriented point samples with color (represented in PLY format) was obtained in the EPFL Scanning 3D Statues from Photos course.
        +
      8. Eagle: +A set of 796,825 oriented point samples with color (represented in PLY format) was obtained in the EPFL Scanning 3D Statues from Photos course.
        A reconstruction of the eagle can be obtained by calling:
        % PoissonRecon --in eagle.points.ply --out eagle.pr.ply --depth 10
        (with the RGBA color properties automatically detected from the .ply header).
        @@ -759,7 +960,7 @@ This reconstruction can be chunked into cubes of size 4×4×4 by calli
        % ChunkPly --in 1 eagle.ssd.trimmed.ply --out eagle.ssd.trimmed.chnks --width 4
        which partitions the reconstruction into 11 pieces. -
      9. Torso: +
      10. Torso: A set of 3,488,432 (torso.points.ply) and an envelope (torso.envelope.ply).
        A reconstruction of the torso that constrains the reconstruction to be contained within the envelope can be obtained by calling:
        % PoissonRecon --in torso.points.ply --envelope torso.envelope.ply --out torso.pr.ply --depth 10
        @@ -772,6 +973,41 @@ using the --envelope flag to specify the water-tight mesh constraining th
    + +
      +
      +
      + +PoissonReconServer / PoissonReconClient + +For testing purposes, two point sets are provided: +
        + +
      1. Eagle: +A set of 796,825 oriented point samples with color was obtained in the EPFL Scanning 3D Statues from Photos course.
        +Assuming the point-set is placed in the networked file <in dir> and that a networked temporary folder <temp dir> exists, a distributed reconstruction of the eagle over 4 clients at depth 10, outputting the reconstruction to eagle.ply (relative to the directory from the server is run), can be obtained by calling: +
        % PoissonReconServer --count 4 --depth 10 --in <in dir>/eagle.points.ply --tempDir <temp dir>/temp --out eagle.ply
        +(with the RGBA color properties automatically detected from the .ply header).
        +This will initiate the server which will output the address and port for the clients to connect to: +
        Server Address: <IPv4 address>:<port>
        +The four clients can then be executed by connecting them to the server: +
        % PoissonReconClient --port <port> --address <IPv4 address>
        +
        % PoissonReconClient --port <port> --address <IPv4 address>
        +
        % PoissonReconClient --port <port> --address <IPv4 address>
        +
        % PoissonReconClient --port <port> --address <IPv4 address>
        +Alternatively, the four clients can be executed serially: +
        % PoissonReconClient --port <port> --address <IPv4 address> --multi 4
        + +
      2. Safra Square: +For testing purposes, the Safra-Square point set, containing 2,364,268,059 oriented point samples with color, has been generously provided by Resonai. +
      3. + +
      + +
      +
      +
    +
      @@ -781,9 +1017,9 @@ using the --envelope flag to specify the water-tight mesh constraining th For testing purposes, a pair of point-sets is provided:
        -
      1. fitting samples: +
      2. fitting samples: A set of 1000 random 2D samples from within the square [-1,1,]x[-1,1] along with the evaluation of the quadratic f(x,y)=x*x+y*y at each sample point (represented in ASCII format). -
      3. evaluation samples: +
      4. evaluation samples: A set of 4 2D positions at which the fit function is to be evaluated (represented in ASCII format).
      @@ -807,7 +1043,7 @@ Note that because the (last) evaluation position (2,2) is outside the bounding b ImageStitching -For testing purposes, two panoramas are provided: Jaffa (23794 x 9492 pixels) and OldRag (87722 x 12501 pixels). +For testing purposes, two panoramas are provided: Jaffa (23794 x 9492 pixels) and OldRag (87722 x 12501 pixels). A seamless panorama can be obtained by running:
      % ImageSitching --in pixels.png labels.png --out out.png
      @@ -845,107 +1081,107 @@ To obtain a sampling of the implicit function over a regular grid: HISTORY OF CHANGES -Version 3: +Version 3:
      1. The implementation of the --samplesPerNode parameter has been modified so that a value of "1" more closely corresponds to a distribution with one sample per leaf node.
      2. The code has been modified to support compilation under MSVC 2010 and the associated solution and project files are now provided. (Due to a bug in the Visual Studios compiler, this required modifying the implementation of some of the bit-shifting operators.)
      -Version 4: +Version 4:
      1. The code supports screened reconstruction, with interpolation weight specified through the --pointWeight parameter.
      2. The code has been implemented to support parallel processing, with the number of threads used for parallelization specified by the --threads parameter. -
      3. The input point set can now also be in PLY format, and the file-type is determined by the extension, so that the --binary flag is now obsolete. +
      4. The input point set can now also be in PLY format, and the file-type is determined by the extension, so that the --binary flag is now obsolete.
      5. At depths coarser than the one specified by the value --minDepth the octree is no longer adaptive but rather complete, simplifying the prolongation operator.
      -Version 4.5: +Version 4.5:
      1. The algorithmic complexity of the solver was reduced from log-linear to linear.
      -Version 4.51: +Version 4.51:
      1. Smart pointers were added to ensure that memory accesses were in bounds.
      -Version 5: +Version 5:
      1. The --density flag was added to the reconstructor to output the estimated depth of the iso-vertices.
      2. The SurfaceTrimmer executable was added to support trimming off the subset of the reconstructed surface that are far away from the input samples, thereby allowing for the generation of non-water-tight surface.
      -Version 5.1: +Version 5.1:
      1. Minor bug-fix to address incorrect neighborhood estimation in the octree finalization.
      -Version 5.5a: +Version 5.5a:
      1. Modified to support depths greater than 14. (Should work up to 18 or 19 now.)
      2. Improved speed and memory performance by removing the construction of integral and value tables.
      3. Fixed a bug in Version 5.5 that used memory and took more time without doing anything useful.
      -Version 5.6: +Version 5.6:
      1. Added the --normalWeight flag to support setting a point's interpolation weight in proportion to the magnitude of its normal.
      -Version 5.7: +Version 5.7:
      1. Modified the setting of the constraints, replacing the map/reduce implementation with OpenMP atomics to reduce memory usage.
      2. Fixed bugs that caused numerical overflow when processing large point clouds on multi-core machines.
      3. Improved efficiency of the iso-surface extraction phse.
      -Version 5.71: +Version 5.71:
      1. Added the function GetSolutionValue to support the evaluation of the implicit function at a specific point.
      -Version 6: +Version 6:
      1. Modified the solver to use Gauss-Seidel relaxation instead of conjugate-gradients at finer resolution.
      2. Re-ordered the implementation of the solver so that only a windowed subset of the matrix is in memory at any time, thereby reducing the memory usage during the solver phase.
      3. Separated the storage of the data associated with the octree nodes from the topology.
      -Version 6.1: +Version 6.1:
      1. Re-ordered the implementation of the iso-surface extraction so that only a windowed subset of the octree is in memory at any time, thereby reducing the memory usage during the extracted phase.
      -Version 6.11: +Version 6.11:
      1. Fixed a bug that created a crash in the evaluation phase when --pointWeight is set zero.
      -Version 6.12: +Version 6.12:
      1. Removed the OpenMP firstprivate directive as it seemed to cause trouble under Linux compilations.
      -Version 6.13: +Version 6.13:
      1. Added a MemoryPointStream class in PointStream.inl to support in-memory point clouds.
      2. Modified the signature of Octree::SetTree in MultiGridOctreeData.h to take in a pointer to an object of type PointStream rather than a file-name.
      -Version 6.13a: +Version 6.13a:
        -
      1. Modified the signature of Octree::SetIsoSurface to rerun a void. [cloudcompare] -
      2. Added a definition of SetIsoVertexValue supporting double precision vertices. [cloudcompare] -
      3. Removed Time.[h/cpp] from the repository. [cloudcompare/asmaloney] -
      4. Fixed assignment bug in Octree::SetSliceIsoVertices. [asmaloney] -
      5. Fixed initialization bug in SortedTreeNodes::SliceTableData and SortedTreeNodes::XSliceTableData. [asmaloney] -
      6. Included stdlib.h in Geometry.h. [asmaloney] -
      7. Fixed default value bug in declaration of Octree::SetTree. [asmaloney] +
      8. Modified the signature of Octree::SetIsoSurface to rerun a void. [cloudcompare] +
      9. Added a definition of SetIsoVertexValue supporting double precision vertices. [cloudcompare] +
      10. Removed Time.[h/cpp] from the repository. [cloudcompare/asmaloney] +
      11. Fixed assignment bug in Octree::SetSliceIsoVertices. [asmaloney] +
      12. Fixed initialization bug in SortedTreeNodes::SliceTableData and SortedTreeNodes::XSliceTableData. [asmaloney] +
      13. Included stdlib.h in Geometry.h. [asmaloney] +
      14. Fixed default value bug in declaration of Octree::SetTree. [asmaloney]
      -Version 7.0: +Version 7.0:
      1. Added functionality to support color extrapolation if present in the input.
      2. Modified a bug with the way in which sample contributions were scaled.
      -Version 8.0: +Version 8.0:
      1. Added support for different degree B-splines. (Note that as the B-spline degree is a template parameter, only degree 1 through 4 are supported. @@ -955,153 +1191,162 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
      2. Changed the implementation of the grid sampling so that computation is now linear, rather than log-linear, in the number of samples.
      -Version 9.0: +Version 9.0:
      1. Added support for free boundary conditions. -
      2. Extended the solver to support more general linear systems. This makes it possible to use the same framework to implement the Smoothed Signed Distance Reconstruction of Calakli and Taubin (2011). +
      3. Extended the solver to support more general linear systems. This makes it possible to use the same framework to implement the Smoothed Signed Distance Reconstruction of Calakli and Taubin (2011).
      4. Modified the implementation of density estimation and input representation. This tends to define a slightly larger system. On its own, this results in slightly increased running-time/footprint for full-res reconstructions, but provides a substantially faster implementation when the output complexity is smaller than the input.
      -Version 9.01: +Version 9.01:
      1. Reverted the density estimation to behave as in Version 8.0.
      -Version 9.011: +Version 9.011:
      1. Added a parameter for specifying the temporary directory.
      -Version 10.00: +Version 10.00:
      1. The code has been reworked to support arbitrary dimensions, finite elements of arbitrary degree, generally SPD systems in the evaluated/integrated values and derivatives of the functions, etc.
      2. For the reconstruction code, added the --width flag which allows the system to compute the depth of the octree given a target depth for the finest resolution nodes.
      3. For the reconstruction code, fixed a bug in the handling of the confidence encoded in the lengths of the normals. In addition, added the flags --confidence and --confidenceBias which allow the user more control of how confidence is used to affect the contribution of a sample.
      -Version 10.01: +Version 10.01:
      1. Modified the reconstruction code to facilitate interpolation of other input-sample quantities, in addition to color.
      -Version 10.02: +Version 10.02:
      1. Set the default value for --degree in PoissonRecon to 1 and change the definitiion of DATA_DEGREE to 0 for sharper color interpolation.
      -Version 10.03: +Version 10.03:
      1. Cleaned up memory leaks and fixed a bug causing ImageStitching and EDTInHeat to SEGFAULT on Linux.
      -Version 10.04: +Version 10.04:
      1. Replaced the ply I/O code with an object-oriented implementation.
      2. Updated the code to support compilation under gcc version 4.8.
      -Version 10.05: +Version 10.05:
      1. Added cleaner support for warning and error handling.
      2. Minor bug fixes.
      3. Added a --inCore flag that enables keeping the pointset in memory instead of streaming it in from disk.
      -Version 10.06: +Version 10.06:
      1. Improved performance.
      2. Modified PoissonRecon and SSDRecon to support processing of 2D point sets.
      3. Modified the 2D implementations of PoissonRecon, SSDRecon, and AdaptiveTreeVisualization to support ouput to .jpg and .png image files.
      -Version 10.07: +Version 10.07:
      1. Removed a bug that would cause memory access errors when some slices were empty.
      -Version 11.00: +Version 11.00:
      1. Added support for processing point-sets so large that 32-bit indices for octrees are not sufficient. (Enabled by defining the preprocessor variable BIG_DATA in the file PreProcessor.h.
      2. Added C++11 parallelism for compilers that do not support OpenMP.
      3. Added the code for ChunkPly which breaks up large meshes and/or point-sets into chunks.
      -Version 11.01: +Version 11.01:
      1. Fixed bug with _mktemp that caused the code to crash on Windows machine with more than 26 cores.
      -Version 11.02: +Version 11.02:
      1. Added error handling for numerical imprecision issues arrising when too many samples fall into a leaf node.
      -Version 12.00: +Version 12.00:
      1. Added functionality enabling AdaptiveTreeVisualization to output the values of a function at prescribed sample positions.
      2. Added the implementation of PointInterpolant that fits a function to a discrete set of sample values.
      -Version 13.00: +Version 13.00:
      1. Enabled passing in a constraint envelope to PoissonRecon, allowing one to define a region that is known to be outside the surface.
      2. Updated ChunkPLY to support processing of input points in either ASCII or binary format.
      -Version 13.50: +Version 13.50:
      1. Enabled support for automatically detecting attirbutes of input point cloud (in addition to positions and normals) when provided in .ply format.
      -Version 13.60: +Version 13.60:
      1. Modified the implementation of PointInterpolant to support separately prescribing value and gradient constraints.
      -Version 13.61: +Version 13.61:
      1. Bug fix addressing the problem that the memory for a DynamicFactory object is dynamically allocated and not only known at construction time.
      -Version 13.70: +Version 13.70:
      1. Using the updated PLY libraray with the less restrictive BSD license.
      -Version 13.71: +Version 13.71:
      1. Fixed a bug that resulted in incorrect point weighting when the samples were too sparse.
      -Version 13.72: +Version 13.72:
      1. Fixed a bug that could result in the reconstruction not solving up to the finest depth when the --width argument is used.
      -Version 13.73: +Version 13.73:
      1. Re-fixed a bug that could result in the reconstruction not solving up to the finest depth when the --width argument is used.
      -Version 13.74: +Version 13.74:
      1. Fixed a bug that could result in reconstruction failure when the reconstruction depth (e.g. computed using the --width argument) was lower than the full depth value.
      -Version 13.80: +Version 13.80:
      1. Updated the SurfaceTrimmer code to better handle small islands.
      -Version 13.99: +Version 13.99:
      1. Modified the --width parameter so that it serves as an upper bound on the width of a cell at the finest resolution.
      2. Modified the code so that the output mesh no longer has statistics about processing time/memory.
      +Version 14.00: +
        +
      1. Added support for distributed screened Poisson Surface Reconstruction. +
      +

      SUPPORT
      -This work genersouly supported by NSF grants #0746039 and #1422325. + From cae152bc7bd59449b550a574b91fde5f47bf5de6 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Thu, 4 May 2023 11:08:23 -0400 Subject: [PATCH 04/86] Version 14.01 --- README.md | 12 +++-- Src/PreProcessor.h | 2 +- Src/VertexFactory.h | 9 ++++ Src/VertexFactory.inl | 113 +++++++++++++++++++++++++++++++----------- 4 files changed, 102 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 3bf666b2..82e7b656 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

      Adaptive Multigrid Solvers (Version 14.00)

      +

      Adaptive Multigrid Solvers (Version 14.01)

      links compilation @@ -27,10 +27,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan, Chuang, Rusinkiewicz, and Hoppe, 2020]
      Executables: -Win64
      +Win64
      Source Code: -ZIP GitHub
      +ZIP GitHub
      Older Versions: +V14.00, V13.99, V13.80, V13.74, @@ -1340,6 +1341,11 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
    • Added support for distributed screened Poisson Surface Reconstruction. +Version 14.01: +
        +
      1. Added support for fixed width integer types. +
      + diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index cb282262..93964547 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -45,7 +45,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define VERSION "14.00" // The version of the code +#define VERSION "14.01" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file diff --git a/Src/VertexFactory.h b/Src/VertexFactory.h index 1c0d1eca..09e19523 100644 --- a/Src/VertexFactory.h +++ b/Src/VertexFactory.h @@ -28,6 +28,7 @@ DAMAGE. #ifndef VERTEX_FACTORY_INCLUDED #define VERTEX_FACTORY_INCLUDED +#include #include "Ply.h" #include "Array.h" @@ -43,6 +44,14 @@ namespace VertexFactory UINT , FLOAT , DOUBLE , + INT_8 , + UINT_8 , + INT_16 , + UINT_16 , + INT_32 , + UINT_32 , + INT_64 , + UINT_64 , UNKNOWN }; diff --git a/Src/VertexFactory.inl b/Src/VertexFactory.inl index a71a7fad..3d2664b1 100644 --- a/Src/VertexFactory.inl +++ b/Src/VertexFactory.inl @@ -32,12 +32,20 @@ namespace VertexFactory { switch( typeOnDisk ) { - case TypeOnDisk::CHAR: return PLY::Type< char >(); - case TypeOnDisk::UCHAR: return PLY::Type< unsigned char >(); - case TypeOnDisk::INT: return PLY::Type< int >(); - case TypeOnDisk::UINT: return PLY::Type< unsigned int >(); - case TypeOnDisk::FLOAT: return PLY::Type< float >(); - case TypeOnDisk::DOUBLE: return PLY::Type< double >(); + case TypeOnDisk::CHAR: return PLY::Type< char >(); + case TypeOnDisk::UCHAR: return PLY::Type< unsigned char >(); + case TypeOnDisk::INT: return PLY::Type< int >(); + case TypeOnDisk::UINT: return PLY::Type< unsigned int >(); + case TypeOnDisk::FLOAT: return PLY::Type< float >(); + case TypeOnDisk::DOUBLE: return PLY::Type< double >(); + case TypeOnDisk::INT_8: return PLY::Type< int8_t >(); + case TypeOnDisk::UINT_8: return PLY::Type< uint8_t >(); + case TypeOnDisk::INT_16: return PLY::Type< int16_t >(); + case TypeOnDisk::UINT_16: return PLY::Type< uint16_t >(); + case TypeOnDisk::INT_32: return PLY::Type< int32_t >(); + case TypeOnDisk::UINT_32: return PLY::Type< uint32_t >(); + case TypeOnDisk::INT_64: return PLY::Type< int64_t >(); + case TypeOnDisk::UINT_64: return PLY::Type< uint64_t >(); default: ERROR_OUT( "Unrecognized type: " , typeOnDisk ); } return -1; @@ -53,17 +61,38 @@ namespace VertexFactory case PLY_UCHAR: return TypeOnDisk::UCHAR; case PLY_FLOAT: return TypeOnDisk::FLOAT; case PLY_DOUBLE: return TypeOnDisk::DOUBLE; + case PLY_INT_8: return TypeOnDisk::INT_8; + case PLY_UINT_8: return TypeOnDisk::UINT_8; + case PLY_INT_16: return TypeOnDisk::INT_16; + case PLY_UINT_16: return TypeOnDisk::UINT_16; + case PLY_INT_32: return TypeOnDisk::INT_32; + case PLY_UINT_32: return TypeOnDisk::UINT_32; + case PLY_INT_64: return TypeOnDisk::INT_64; + case PLY_UINT_64: return TypeOnDisk::UINT_64; default: ERROR_OUT( "Unrecognized type: " , plyType ); } return TypeOnDisk::UNKNOWN; } - template<> TypeOnDisk GetTypeOnDisk< char >( void ){ return TypeOnDisk::CHAR; } - template<> TypeOnDisk GetTypeOnDisk< unsigned char >( void ){ return TypeOnDisk::UCHAR; } - template<> TypeOnDisk GetTypeOnDisk< int >( void ){ return TypeOnDisk::INT; } - template<> TypeOnDisk GetTypeOnDisk< unsigned int >( void ){ return TypeOnDisk::UINT; } - template<> TypeOnDisk GetTypeOnDisk< float >( void ){ return TypeOnDisk::FLOAT; } - template<> TypeOnDisk GetTypeOnDisk< double >( void ){ return TypeOnDisk::DOUBLE; } + template< typename Type > TypeOnDisk GetTypeOnDisk( void ) + { + if constexpr( std::is_same< Type , char >::value ) return TypeOnDisk::CHAR; + else if constexpr( std::is_same< Type , unsigned char >::value ) return TypeOnDisk::UCHAR; + else if constexpr( std::is_same< Type , int >::value ) return TypeOnDisk::INT; + else if constexpr( std::is_same< Type , unsigned int >::value ) return TypeOnDisk::UINT; + else if constexpr( std::is_same< Type , int8_t >::value ) return TypeOnDisk::INT_8; + else if constexpr( std::is_same< Type , uint8_t >::value ) return TypeOnDisk::UINT_8; + else if constexpr( std::is_same< Type , int16_t >::value ) return TypeOnDisk::INT_16; + else if constexpr( std::is_same< Type , uint16_t >::value ) return TypeOnDisk::UINT_16; + else if constexpr( std::is_same< Type , int32_t >::value ) return TypeOnDisk::INT_32; + else if constexpr( std::is_same< Type , uint32_t >::value ) return TypeOnDisk::UINT_32; + else if constexpr( std::is_same< Type , int64_t >::value ) return TypeOnDisk::INT_64; + else if constexpr( std::is_same< Type , uint64_t >::value ) return TypeOnDisk::UINT_64; + else if constexpr( std::is_same< Type , float >::value ) return TypeOnDisk::FLOAT; + else if constexpr( std::is_same< Type , double >::value ) return TypeOnDisk::DOUBLE; + else ERROR_OUT( "Unrecognized type" ); + return TypeOnDisk::UNKNOWN; + } template< typename Real > template< typename Type > @@ -94,12 +123,20 @@ namespace VertexFactory if( TypeOnDisk()==typeOnDisk ) return fread( &s , sizeof(Real) , 1 , fp )==1; switch( typeOnDisk ) { - case TypeOnDisk::CHAR: return _ReadBinary< char >( fp , s ); - case TypeOnDisk::UCHAR: return _ReadBinary< unsigned char >( fp , s ); - case TypeOnDisk::INT: return _ReadBinary< int >( fp , s ); - case TypeOnDisk::UINT: return _ReadBinary< unsigned int >( fp , s ); - case TypeOnDisk::FLOAT: return _ReadBinary< float >( fp , s ); - case TypeOnDisk::DOUBLE: return _ReadBinary< double >( fp , s ); + case TypeOnDisk::CHAR: return _ReadBinary< char >( fp , s ); + case TypeOnDisk::UCHAR: return _ReadBinary< unsigned char >( fp , s ); + case TypeOnDisk::INT: return _ReadBinary< int >( fp , s ); + case TypeOnDisk::UINT: return _ReadBinary< unsigned int >( fp , s ); + case TypeOnDisk::FLOAT: return _ReadBinary< float >( fp , s ); + case TypeOnDisk::DOUBLE: return _ReadBinary< double >( fp , s ); + case TypeOnDisk::INT_8: return _ReadBinary< int8_t >( fp , s ); + case TypeOnDisk::UINT_8: return _ReadBinary< uint8_t >( fp , s ); + case TypeOnDisk::INT_16: return _ReadBinary< int16_t >( fp , s ); + case TypeOnDisk::UINT_16: return _ReadBinary< uint16_t >( fp , s ); + case TypeOnDisk::INT_32: return _ReadBinary< int32_t >( fp , s ); + case TypeOnDisk::UINT_32: return _ReadBinary< uint32_t >( fp , s ); + case TypeOnDisk::INT_64: return _ReadBinary< int64_t >( fp , s ); + case TypeOnDisk::UINT_64: return _ReadBinary< uint64_t >( fp , s ); default: ERROR_OUT( "Unrecognized type: " , typeOnDisk ); } return true; @@ -109,12 +146,20 @@ namespace VertexFactory { switch( typeOnDisk ) { - case TypeOnDisk::CHAR: fprintf( fp , " %d" , ( char)s ) ; break; - case TypeOnDisk::UCHAR: fprintf( fp , " %u" , (unsigned char)s ) ; break; - case TypeOnDisk::INT: fprintf( fp , " %d" , ( int)s ) ; break; - case TypeOnDisk::UINT: fprintf( fp , " %u" , (unsigned int)s ) ; break; - case TypeOnDisk::FLOAT: fprintf( fp , " %f" , ( float)s ) ; break; - case TypeOnDisk::DOUBLE: fprintf( fp , " %f" , ( double)s ) ; break; + case TypeOnDisk::CHAR: fprintf( fp , " %d" , ( char)s ) ; break; + case TypeOnDisk::UCHAR: fprintf( fp , " %u" , (unsigned char)s ) ; break; + case TypeOnDisk::INT: fprintf( fp , " %d" , ( int)s ) ; break; + case TypeOnDisk::UINT: fprintf( fp , " %u" , (unsigned int)s ) ; break; + case TypeOnDisk::FLOAT: fprintf( fp , " %f" , ( float)s ) ; break; + case TypeOnDisk::DOUBLE: fprintf( fp , " %f" , ( double)s ) ; break; + case TypeOnDisk::INT_8: fprintf( fp , " %" PRId8 , ( int8_t)s ) ; break; + case TypeOnDisk::UINT_8: fprintf( fp , " %" PRIu8 , ( uint8_t)s ) ; break; + case TypeOnDisk::INT_16: fprintf( fp , " %" PRId16 , ( int16_t)s ) ; break; + case TypeOnDisk::UINT_16: fprintf( fp , " %" PRIu16 , ( uint16_t)s ) ; break; + case TypeOnDisk::INT_32: fprintf( fp , " %" PRId32 , ( int32_t)s ) ; break; + case TypeOnDisk::UINT_32: fprintf( fp , " %" PRIu32 , ( uint32_t)s ) ; break; + case TypeOnDisk::INT_64: fprintf( fp , " %" PRId64 , ( int64_t)s ) ; break; + case TypeOnDisk::UINT_64: fprintf( fp , " %" PRIu64 , ( uint64_t)s ) ; break; default: ERROR_OUT( "Unrecongized type: " , typeOnDisk ); } } @@ -125,12 +170,20 @@ namespace VertexFactory if( TypeOnDisk()==typeOnDisk ) fwrite( &s , sizeof(Real) , 1 , fp ); switch( typeOnDisk ) { - case TypeOnDisk::CHAR: _WriteBinary< char >( fp , s ) ; break; - case TypeOnDisk::UCHAR: _WriteBinary< unsigned char >( fp , s ) ; break; - case TypeOnDisk::INT: _WriteBinary< int >( fp , s ) ; break; - case TypeOnDisk::UINT: _WriteBinary< unsigned int >( fp , s ) ; break; - case TypeOnDisk::FLOAT: _WriteBinary< float >( fp , s ) ; break; - case TypeOnDisk::DOUBLE: _WriteBinary< double >( fp , s ) ; break; + case TypeOnDisk::CHAR: _WriteBinary< char >( fp , s ) ; break; + case TypeOnDisk::UCHAR: _WriteBinary< unsigned char >( fp , s ) ; break; + case TypeOnDisk::INT: _WriteBinary< int >( fp , s ) ; break; + case TypeOnDisk::UINT: _WriteBinary< unsigned int >( fp , s ) ; break; + case TypeOnDisk::FLOAT: _WriteBinary< float >( fp , s ) ; break; + case TypeOnDisk::DOUBLE: _WriteBinary< double >( fp , s ) ; break; + case TypeOnDisk::INT_8: _WriteBinary< int8_t >( fp , s ) ; break; + case TypeOnDisk::UINT_8: _WriteBinary< uint8_t >( fp , s ) ; break; + case TypeOnDisk::INT_16: _WriteBinary< int16_t >( fp , s ) ; break; + case TypeOnDisk::UINT_16: _WriteBinary< uint16_t >( fp , s ) ; break; + case TypeOnDisk::INT_32: _WriteBinary< int32_t >( fp , s ) ; break; + case TypeOnDisk::UINT_32: _WriteBinary< uint32_t >( fp , s ) ; break; + case TypeOnDisk::INT_64: _WriteBinary< int64_t >( fp , s ) ; break; + case TypeOnDisk::UINT_64: _WriteBinary< uint64_t >( fp , s ) ; break; default: ERROR_OUT( "Unrecongized type: " , typeOnDisk ); } } From 350071f05cfd64c95c05eb8cf8369e0c501d280d Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Sun, 6 Aug 2023 16:34:01 -0400 Subject: [PATCH 05/86] Version 14,02 --- README.md | 12 +++++++++--- Src/FEMTree.inl | 4 ++-- Src/PreProcessor.h | 4 ++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 82e7b656..f4dc214e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

      Adaptive Multigrid Solvers (Version 14.01)

      +

      Adaptive Multigrid Solvers (Version 14.02)

      links compilation @@ -27,10 +27,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan, Chuang, Rusinkiewicz, and Hoppe, 2020]
      Executables: -Win64
      +Win64
      Source Code: -ZIP GitHub
      +ZIP GitHub
      Older Versions: +V14.01, V14.00, V13.99, V13.80, @@ -1346,6 +1347,11 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
    • Added support for fixed width integer types. +Version 14.02: +
        +
      1. Fixed overflow bug when there are more than 2^32 nodes in the tree. +
      + diff --git a/Src/FEMTree.inl b/Src/FEMTree.inl index b59deec8..053df209 100644 --- a/Src/FEMTree.inl +++ b/Src/FEMTree.inl @@ -1463,9 +1463,9 @@ void FEMTree< Dim , Real >::_clipTree( const HasDataFunctor& f , LocalDepth full // Get the data status of each node // [NOTE] Have to use an array of chars instead of bools because the latter is not thread safe - size_t sz = nodeCount(); + node_index_type sz = nodeCount(); Pointer( char ) nodeHasData = NewPointer< char >( sz ); - for( unsigned int i=0 ; iprocessNodes( [&]( FEMTreeNode *node ){ if( node->nodeData.nodeIndex!=-1 ) nodeHasData[node->nodeData.nodeIndex] = f( node ) ? 1 : 0; } ); diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 93964547..cd1f1f75 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -37,7 +37,7 @@ DAMAGE. // (each of which is small enough to be represented using 32-bit indexing.) #endif // BIG_DATA -#define FAST_COMPILE // If enabled, only a single version of the code is compiled +//#define FAST_COMPILE // If enabled, only a single version of the code is compiled #undef SHOW_WARNINGS // Display compilation warnings #undef ARRAY_DEBUG // If enabled, array access is tested for validity @@ -45,7 +45,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define VERSION "14.01" // The version of the code +#define VERSION "14.02" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file From 8acea363ba32c67e8f171dbafb79f5e4827ef025 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Mon, 21 Aug 2023 13:26:21 -0400 Subject: [PATCH 06/86] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f4dc214e..143a02bc 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2013], [Kazhdan and Hoppe, 2018], [Kazhdan, Chuang, Rusinkiewicz, and Hoppe, 2020] +[Kazhdan and Hoppe, 2023]
      Executables: Win64
      From 0f1f6dc958b66a48dcf8057d82728c53ab5b1917 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Thu, 5 Oct 2023 22:24:55 -0400 Subject: [PATCH 07/86] Version 15.00 --- AdaptiveSolvers.sln | 20 +- Makefile | 15 + README.md | 66 +- Reconstruction.example.vcxproj | 141 ++ Src/AdaptiveTreeVisualization.cpp | 59 +- Src/ChunkPLY.cpp | 9 +- Src/DataStream.h | 149 ++ Src/DataStream.imp.h | 289 ++++ Src/{VertexStream.inl => DataStream.imp.inl} | 52 +- Src/FEMTree.Initialize.inl | 2 +- Src/FEMTree.LevelSet.2D.inl | 160 ++- Src/FEMTree.LevelSet.3D.inl | 277 +++- Src/FEMTree.h | 77 +- Src/FEMTree.inl | 32 +- Src/Geometry.h | 9 +- Src/MyMiscellany.h | 43 + Src/Ply.h | 4 +- Src/Ply.inl | 31 +- Src/PointInterpolant.cpp | 133 +- Src/PointPartition.h | 6 +- Src/PointPartition.inl | 4 +- Src/PointPartitionClientServer.h | 2 + Src/PointPartitionClientServer.inl | 6 +- Src/PoissonRecon.client.inl | 267 ++-- Src/PoissonRecon.cpp | 888 ++++-------- Src/PoissonRecon.h | 113 -- Src/PoissonRecon.server.inl | 96 +- Src/PoissonReconClient.cpp | 6 +- Src/PoissonReconClientServer.h | 2 +- Src/PoissonReconClientServer.inl | 46 + Src/PoissonReconServer.cpp | 52 +- Src/PreProcessor.h | 2 +- Src/Reconstruction.example.cpp | 352 +++++ Src/Reconstructors.h | 1356 ++++++++++++++++++ Src/Reconstructors.streams.h | 645 +++++++++ Src/RegularTree.h | 1 + Src/SSDRecon.cpp | 784 +++------- Src/StreamingMesh.h | 286 ---- Src/StreamingMesh.inl | 266 ---- Src/VertexStream.h | 224 --- 40 files changed, 4379 insertions(+), 2593 deletions(-) create mode 100644 Reconstruction.example.vcxproj create mode 100644 Src/DataStream.h create mode 100644 Src/DataStream.imp.h rename Src/{VertexStream.inl => DataStream.imp.inl} (83%) delete mode 100644 Src/PoissonRecon.h create mode 100644 Src/Reconstruction.example.cpp create mode 100644 Src/Reconstructors.h create mode 100644 Src/Reconstructors.streams.h delete mode 100644 Src/StreamingMesh.h delete mode 100644 Src/StreamingMesh.inl delete mode 100644 Src/VertexStream.h diff --git a/AdaptiveSolvers.sln b/AdaptiveSolvers.sln index 9e369fa3..757af954 100644 --- a/AdaptiveSolvers.sln +++ b/AdaptiveSolvers.sln @@ -49,6 +49,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Header Files", "Header File Src\BlockedVector.h = Src\BlockedVector.h Src\BSplineData.h = Src\BSplineData.h Src\CmdLineParser.h = Src\CmdLineParser.h + Src\DataStream.h = Src\DataStream.h + Src\DataStream.imp.h = Src\DataStream.imp.h Src\Factor.h = Src\Factor.h Src\FEMTree.h = Src\FEMTree.h Src\FunctionData.h = Src\FunctionData.h @@ -64,20 +66,19 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Header Files", "Header File Src\PNG.h = Src\PNG.h Src\PointPartition.h = Src\PointPartition.h Src\PointPartitionClientServer.h = Src\PointPartitionClientServer.h - Src\PoissonRecon.h = Src\PoissonRecon.h Src\PoissonReconClientServer.h = Src\PoissonReconClientServer.h Src\Polynomial.h = Src\Polynomial.h Src\PPolynomial.h = Src\PPolynomial.h Src\PreProcessor.h = Src\PreProcessor.h Src\Rasterizer.h = Src\Rasterizer.h + Src\Reconstructors.h = Src\Reconstructors.h + Src\Reconstructors.streams.h = Src\Reconstructors.streams.h Src\RegularGrid.h = Src\RegularGrid.h Src\RegularTree.h = Src\RegularTree.h Src\Socket.h = Src\Socket.h Src\SparseMatrix.h = Src\SparseMatrix.h Src\SparseMatrixInterface.h = Src\SparseMatrixInterface.h - Src\StreamingMesh.h = Src\StreamingMesh.h Src\VertexFactory.h = Src\VertexFactory.h - Src\VertexStream.h = Src\VertexStream.h Src\Window.h = Src\Window.h EndProjectSection EndProject @@ -87,6 +88,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Inline Files", "Inline File Src\BMPStream.inl = Src\BMPStream.inl Src\BSplineData.inl = Src\BSplineData.inl Src\CmdLineParser.inl = Src\CmdLineParser.inl + Src\DataStream.imp.inl = Src\DataStream.imp.inl Src\FEMTree.Evaluation.inl = Src\FEMTree.Evaluation.inl Src\FEMTree.Initialize.inl = Src\FEMTree.Initialize.inl Src\FEMTree.inl = Src\FEMTree.inl @@ -117,9 +119,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Inline Files", "Inline File Src\Socket.inl = Src\Socket.inl Src\SparseMatrix.inl = Src\SparseMatrix.inl Src\SparseMatrixInterface.inl = Src\SparseMatrixInterface.inl - Src\StreamingMesh.inl = Src\StreamingMesh.inl Src\VertexFactory.inl = Src\VertexFactory.inl - Src\VertexStream.inl = Src\VertexStream.inl Src\Window.inl = Src\Window.inl EndProjectSection EndProject @@ -131,6 +131,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PoissonReconClient", "Poiss EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PoissonReconServer", "PoissonReconServer.vcxproj", "{649D8C83-6BE2-4419-B0A8-66F65CD4D4CB}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Reconstruction.example", "..\..\..\Users\mkazh\OneDrive - Johns Hopkins\Research\PoissonRecon\PoissonRecon\Reconstruction.example.vcxproj", "{F40103C1-D18D-4C34-992C-F78D4DCD4A87}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -244,6 +246,14 @@ Global {649D8C83-6BE2-4419-B0A8-66F65CD4D4CB}.Release|x64.Build.0 = Release|x64 {649D8C83-6BE2-4419-B0A8-66F65CD4D4CB}.Release|x86.ActiveCfg = Release|Win32 {649D8C83-6BE2-4419-B0A8-66F65CD4D4CB}.Release|x86.Build.0 = Release|Win32 + {F40103C1-D18D-4C34-992C-F78D4DCD4A87}.Debug|x64.ActiveCfg = Debug|x64 + {F40103C1-D18D-4C34-992C-F78D4DCD4A87}.Debug|x64.Build.0 = Debug|x64 + {F40103C1-D18D-4C34-992C-F78D4DCD4A87}.Debug|x86.ActiveCfg = Debug|Win32 + {F40103C1-D18D-4C34-992C-F78D4DCD4A87}.Debug|x86.Build.0 = Debug|Win32 + {F40103C1-D18D-4C34-992C-F78D4DCD4A87}.Release|x64.ActiveCfg = Release|x64 + {F40103C1-D18D-4C34-992C-F78D4DCD4A87}.Release|x64.Build.0 = Release|x64 + {F40103C1-D18D-4C34-992C-F78D4DCD4A87}.Release|x86.ActiveCfg = Release|Win32 + {F40103C1-D18D-4C34-992C-F78D4DCD4A87}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Makefile b/Makefile index dff1c29b..7947cb4d 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,8 @@ EH_TARGET=EDTInHeat IS_TARGET=ImageStitching AV_TARGET=AdaptiveTreeVisualization CP_TARGET=ChunkPLY +RE_TARGET=ReconExample + PR_SOURCE=PoissonRecon.cpp PRC_SOURCE=PoissonReconClient.cpp PRS_SOURCE=PoissonReconServer.cpp @@ -18,6 +20,7 @@ EH_SOURCE=EDTInHeat.cpp IS_SOURCE=ImageStitching.cpp AV_SOURCE=AdaptiveTreeVisualization.cpp CP_SOURCE=ChunkPLY.cpp +RE_SOURCE=Reconstruction.example.cpp COMPILER ?= gcc #COMPILER ?= clang @@ -73,6 +76,7 @@ EH_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(EH_SOURCE)))) IS_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(IS_SOURCE)))) AV_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(AV_SOURCE)))) CP_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(CP_SOURCE)))) +RE_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(RE_SOURCE)))) all: CFLAGS += $(CFLAGS_RELEASE) @@ -88,6 +92,7 @@ all: $(BIN)$(EH_TARGET) all: $(BIN)$(IS_TARGET) all: $(BIN)$(AV_TARGET) all: $(BIN)$(CP_TARGET) +all: $(BIN)$(RE_TARGET) debug: CFLAGS += $(CFLAGS_DEBUG) debug: LFLAGS += $(LFLAGS_DEBUG) @@ -102,6 +107,7 @@ debug: $(BIN)$(EH_TARGET) debug: $(BIN)$(IS_TARGET) debug: $(BIN)$(AV_TARGET) debug: $(BIN)$(CP_TARGET) +debug: $(BIN)$(RE_TARGET) poissonrecon: CFLAGS += $(CFLAGS_RELEASE) poissonrecon: LFLAGS += $(LFLAGS_RELEASE) @@ -152,6 +158,10 @@ chunkply: CFLAGS += $(CFLAGS_RELEASE) chunkply: LFLAGS += $(LFLAGS_RELEASE) chunkply: make_dir chunkply: $(BIN)$(CP_TARGET) +reconexample: CFLAGS += $(CFLAGS_RELEASE) +reconexample: LFLAGS += $(LFLAGS_RELEASE) +reconexample: make_dir +reconexample: $(BIN)$(RE_TARGET) clean: rm -rf $(BIN)$(PR_TARGET) @@ -164,6 +174,7 @@ clean: rm -rf $(BIN)$(IS_TARGET) rm -rf $(BIN)$(AV_TARGET) rm -rf $(BIN)$(CP_TARGET) + rm -rf $(BIN)$(RE_TARGET) rm -rf $(PR_OBJECTS) rm -rf $(PRC_OBJECTS) rm -rf $(PRS_OBJECTS) @@ -174,6 +185,7 @@ clean: rm -rf $(IS_OBJECTS) rm -rf $(AV_OBJECTS) rm -rf $(CP_OBJECTS) + rm -rf $(RE_OBJECTS) cd PNG && make clean @@ -216,6 +228,9 @@ $(BIN)$(CP_TARGET): $(CP_OBJECTS) cd PNG && make COMPILER=$(COMPILER) $(CXX) -pthread -o $@ $(CP_OBJECTS) -L$(BIN) $(LFLAGS) $(LFLAGS_IMG) +$(BIN)$(RE_TARGET): $(RE_OBJECTS) + $(CXX) -pthread -o $@ $(RE_OBJECTS) -L$(BIN) $(LFLAGS) $(LFLAGS_IMG) + $(BIN)%.o: $(SRC)%.c $(CC) -c -o $@ -I$(INCLUDE) $< diff --git a/README.md b/README.md index 143a02bc..d9e76a3d 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ -

      Adaptive Multigrid Solvers (Version 14.02)

      +

      Adaptive Multigrid Solvers (Version 15.00)

      links compilation executables +library usage changes
      @@ -28,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
      Executables: -Win64
      +Win64
      Source Code: -ZIP GitHub
      +ZIP GitHub
      Older Versions: +V14.02, V14.01, V14.00, V13.99, @@ -918,6 +920,58 @@ individual components of the visualizer.
    +
    +HEADER-ONLY LIBRARY
    +
      +
      +
      + +Reconstruction.example.cpp + +In addition to exeuctables, the reconstruction code can be interfaced into through the functionality implemented in Reconstructors.h. +Using the functionality requires requires defining one input stream and two output streams. In the descriptions below, the template parameter Real is the floating point type used to represent data (typically float) and Dim is the integer dimension of the space (fixed at Dim=3). Also, the namespace Reconstructor is omitted for brevity. +
        +
      • Input sample stream: This class derives from the InputSampleStream< Real , Dim > class. +The base class has two pure virtual methods that need to be over-ridden: +
          +
        • void reset( void ):
          +This method resets the stream to the start (necessary because the reconstruction code performs two passes over the input samples). +
        • bool base_read( Point< Real , Dim > &p , Point< Real , Dim > &n ):
          +This method tries to read the next pair of positions/normals from the stream, returning true if the read was successful and false if the read failed (i.e. the end of the stream was reached). The class Point< Real , Dim > represents a point in Dim-dimensional space, can be accessed like an array (i.e. overloads the bracked operator) and supports algebraic manipulation like addition and scalar multiplication. +
        +
      • Output vertex stream: This class derives from the OutputVertexStream< Real , Dim > class. +The base class has one pure virtual method that needs to be over-ridden: +
          +
        • void base_write( Point< Real , Dim > p , Point< Real , Dim > g , Real w ):
          +This method writes the information for the next vertx into the stream. The data includes the positiono of the vertex, p, and will also include the gradient, g, and/or density weight, w if the extraction code is asked to compute those. +
        +
      • Output polygon stream: This class derives from the OutputPolygonStream class. +The base class has one pure virtual method that needs to be over-ridden: +
          +
        • void base_write( const std::vector< node_index_type > &polygon ):
          +This method writes the information for the next polygon into the stream, with the polygon represented as a std::vector of integral indices. (In the implementation node_index_type is an unsigned int if the BIG_DATA is not defined an unsigned long long if it is.) +
        +
      +With the streams defined and an FEM degree and boundary type encapsulated in the integer parameter FEMSig , the reconstruction is performed by calling two functions: +
        +
      • Poisson::Solve< Real , Dim , FEMSig >( InputSampleStream< Real , Dim > &sStream , SolutionParameters< Real > sParams ):
        +This function takes in an input sample stream (sStream) and a description of the reconstruction parameters (sParams) desribing the depth, number of samples per node, etc. and returns a pointer to an object of type ReconstructionInfo< Real , Dim , FEMSig > which stores the octree and coefficients describing the implicit function, as long as (possibly) the sampling density information. +
      • ExtractMesh< Real , Dim , FEMSig >( ReconstructionInfo< Real , Dim , FEMSig > &rInfo , OutputVertexStream< Real , Dim > &vStream , &pStream , MeshExtractionParameters meParams ):
        +This function takes in a reference to the recontruction infromation (rInfo), references to the vertex and polygon streams (vStream and pStream) and parameters for mesh extraction (meParams)and computes the extracted triangle/polygon mesh and writes its vertices and faces into the two output streams. +
      +Code walk-through:
      +These steps can be found in the Reconstruction.example.cpp code. +
        +
      • An input sample stream generating a specified number of random points on the surface of the sphere is described in lines 78-115 and constructed in line 299. +
      • An output vertex stream that pushes just the position information to an std::vector of Reals is described in lines 182-192 and constructed in line 311. +
      • An output polygon stream that pushes the polygon to an std::vector of std::vector< int > is described in lines 164-179 and constructed in line 310. +
      • The reconstructor is called on line 303. +
      • The mesh extraction is called on line 314. +
      +Note that a similar approach can be used to perform the Smoothed Signed Distance reconstruction (line 302). The approach also supports reconstruction of meshes with auxiliary information like color (lines 263-292), with the only constraint that the auxiliary data type supports the computation affine combinations (e.g. the RGBColor type defined in lines 60-75). +
      +
    +
    USAGE EXAMPLES (WITH SAMPLE DATA)
    @@ -1353,6 +1407,12 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • Fixed overflow bug when there are more than 2^32 nodes in the tree. +Version 15.00: +
      +
    1. Added support for header-only interface. +
    2. Added example using the header-only interface for reconstructing surfaces from points randomly sampled from a sphere. +
    + diff --git a/Reconstruction.example.vcxproj b/Reconstruction.example.vcxproj new file mode 100644 index 00000000..b13889eb --- /dev/null +++ b/Reconstruction.example.vcxproj @@ -0,0 +1,141 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + 17.0 + Win32Proj + {f40103c1-d18d-4c34-992c-f78d4dcd4a87} + Reconstructionexample + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)\Bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\Obj\$(TargetName)\$(Platform)\$(Configuration)\ + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + NOMINMAX;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + stdcpp17 + true + + + Console + true + true + true + + + + + + \ No newline at end of file diff --git a/Src/AdaptiveTreeVisualization.cpp b/Src/AdaptiveTreeVisualization.cpp index e0fdd712..056a7cf3 100644 --- a/Src/AdaptiveTreeVisualization.cpp +++ b/Src/AdaptiveTreeVisualization.cpp @@ -40,6 +40,8 @@ DAMAGE. #include "VertexFactory.h" #include "Image.h" #include "RegularGrid.h" +#include "DataStream.imp.h" +#include "Reconstructors.h" cmdLineParameter< char* > In( "in" ) , @@ -219,7 +221,13 @@ void _Execute( const FEMTree< Dim , Real > *tree , XForm< Real , Dim+1 > modelTo Point< Real , Dim > points[ CHUNK_SIZE ]; Real values[ CHUNK_SIZE ]; size_t pointsRead; - while( ( pointsRead=pointStream->next( points , CHUNK_SIZE ) ) ) + auto ReadBatch = [&]( void ) + { + size_t c=0; + for( size_t i=0 ; iread( points[i] ) ) break; + return c; + }; + while( ( pointsRead=ReadBatch() ) ) { ThreadPool::Parallel_for( 0 , pointsRead , [&]( unsigned int thread , size_t j ) { @@ -393,28 +401,33 @@ void _Execute( const FEMTree< Dim , Real > *tree , XForm< Real , Dim+1 > modelTo if constexpr( Dim==3 ) if( OutMesh.set ) { double t = Time(); - typedef VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > > FullVertexFactory; - typedef typename FullVertexFactory::VertexType VertexType; - FullVertexFactory vertexFactory; - FileStreamingMesh< FullVertexFactory , node_index_type > mesh( vertexFactory ); - std::function< void ( VertexType& , Point< Real , Dim > , Point< Real , Dim > , Real , Real ) > SetVertex = []( VertexType& v , Point< Real , Dim > p , Point< Real , Dim > , Real , Real ){ v.template get<0>() = p; }; -#if defined( __GNUC__ ) && __GNUC__ < 5 -#ifdef SHOW_WARNINGS -#warning "you've got me gcc version<5" -#endif // SHOW_WARNINGS - static const unsigned int DataSig = FEMDegreeAndBType< 0 , BOUNDARY_FREE >::Signature; - LevelSetExtractor< Dim , Real , VertexType >::template Extract< Real >( IsotropicUIntPack< Dim , FEMSig >() , UIntPack< 0 >() , UIntPack< FEMTrivialSignature >() , *tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , ( SparseNodeData< ProjectiveData< Real , Real > , IsotropicUIntPack< Dim , DataSig > > * )NULL , coefficients , IsoValue.value , IsoSlabDepth.value , IsoSlabStart.value , IsoSlabEnd.value , mesh , (Real)0 , SetVertex , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , FlipOrientation.set ); -#else // !__GNUC__ || __GNUC__ >=5 - LevelSetExtractor< Dim , Real , VertexType >::template Extract< Real >( IsotropicUIntPack< Dim , FEMSig >() , UIntPack< 0 >() , UIntPack< FEMTrivialSignature >() , *tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , NULL , coefficients , IsoValue.value , IsoSlabDepth.value , IsoSlabStart.value , IsoSlabEnd.value , mesh , (Real)0 , SetVertex , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , FlipOrientation.set ); -#endif // __GNUC__ || __GNUC__ < 4 - - if( Verbose.set ) printf( "Got level-set surface: %.2f(s)\n" , Time()-t ); - if( Verbose.set ) printf( "Vertices / Polygons: %llu / %llu\n" , (unsigned long long)mesh.vertexNum() , (unsigned long long)mesh.polygonNum() ); - - std::vector< std::string > comments; - typename FullVertexFactory::Transform unitCubeToModelTransform( modelToUnitCube.inverse() ); - auto xForm = [&]( typename FullVertexFactory::VertexType & v ){ unitCubeToModelTransform.inPlace( v ); }; - PLY::WritePolygons< FullVertexFactory , node_index_type , Real , Dim >( OutMesh.value , FullVertexFactory() , &mesh , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , comments , xForm ); + + // A description of the output vertex information + using VInfo = Reconstructor::OutputVertexInfo< Real , Dim , false , false >; + + // A factory generating the output vertices + using Factory = typename VInfo::Factory; + Factory factory = VInfo::GetFactory(); + + // A backing stream for the vertices + Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , false , false , std::string( "v_" ) ); + Reconstructor::OutputInputPolygonStream polygonStream( false , true , std::string( "p_" ) ); + + { + // The wrapper converting native to output types + typename VInfo::StreamWrapper _vertexStream( vertexStream , factory() ); + Reconstructor::TransformedOutputVertexStream< Real , Dim > __vertexStream( modelToUnitCube.inverse() , _vertexStream ); + + // Extract the mesh + LevelSetExtractor< Real , Dim >::Extract( IsotropicUIntPack< Dim , FEMSig >() , UIntPack< 0 >() , *tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , coefficients , IsoValue.value , IsoSlabDepth.value , IsoSlabStart.value , IsoSlabEnd.value , __vertexStream , polygonStream , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , FlipOrientation.set ); + } + + if( Verbose.set ) printf( "Got level-set: %.2f(s)\n" , Time()-t ); + if( Verbose.set ) printf( "Vertices / Polygons: %llu / %llu\n" , (unsigned long long)vertexStream.size() , (unsigned long long)polygonStream.size() ); + + // Write the mesh to a .ply file + std::vector< std::string > noComments; + PLY::WritePolygons< Factory , node_index_type , Real , Dim >( OutMesh.value , factory , vertexStream.size() , polygonStream.size() , vertexStream , polygonStream , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); } } diff --git a/Src/ChunkPLY.cpp b/Src/ChunkPLY.cpp index 899e8130..bd02016b 100644 --- a/Src/ChunkPLY.cpp +++ b/Src/ChunkPLY.cpp @@ -41,8 +41,9 @@ DAMAGE. #include "CmdLineParser.h" #include "Geometry.h" #include "Ply.h" -#include "VertexStream.h" +#include "DataStream.h" #include "VertexFactory.h" +#include "DataStream.imp.h" cmdLineParameters< char* > In( "in" ); cmdLineParameter< char* > Out( "out" ); @@ -103,14 +104,14 @@ void Read( char *const *fileNames , unsigned int fileNum , VertexDataFactory ver else pointStream = new ASCIIInputDataStream< FullVertexFactory< Real , Dim , VertexDataFactory > >( fileNames[i] , vertexFactory ); size_t count = 0; VertexType< Real , Dim , VertexDataFactory > v = vertexFactory(); - while( pointStream->next( v ) ) count++; + while( pointStream->read( v ) ) count++; pointStream->reset(); _vertices.resize( count , v ); comments.resize( 0 ); ft = PLY_BINARY_NATIVE; count = 0; - while( pointStream->next( _vertices[count++] ) ); + while( pointStream->read( _vertices[count++] ) ); delete pointStream; } delete[] ext; @@ -142,7 +143,7 @@ void WritePoints( const char *fileName , int ft , VertexDataFactory vertexDataFa if ( !strcasecmp( ext , "ply" ) ) pointStream = new PLYOutputDataStream< FullVertexFactory< Real , Dim , VertexDataFactory > >( fileName , vertexFactory , vertices.size() , ft ); else if( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryOutputDataStream< FullVertexFactory< Real , Dim , VertexDataFactory > >( fileName , vertexFactory ); else pointStream = new ASCIIOutputDataStream< FullVertexFactory< Real , Dim , VertexDataFactory > >( fileName , vertexFactory ); - for( size_t i=0 ; inext( vertices[i] ); + for( size_t i=0 ; iwrite( vertices[i] ); delete pointStream; delete[] ext; diff --git a/Src/DataStream.h b/Src/DataStream.h new file mode 100644 index 00000000..9ddb2bbd --- /dev/null +++ b/Src/DataStream.h @@ -0,0 +1,149 @@ +/* +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 DATA_STREAM_INCLUDED +#define DATA_STREAM_INCLUDED + +#include +#include +#include + +// Pre-declare so we can make friends +template< typename Data > struct MultiInputDataStream; +template< typename Data > struct MultiOutputDataStream; + +//////////////////////////////////////// +// Abstract input/output data streams // +//////////////////////////////////////// + +// An input stream containing "Data" types +// Supporting: +// -- Resetting the stream to the start +// -- Trying to read the next element from the stream +template< typename Data > +struct InputDataStream +{ + friend struct MultiInputDataStream< Data >; + + virtual ~InputDataStream( void ){} + + // Reset to the start of the stream + virtual void reset( void ) = 0; + + bool read( Data &d ){ return base_read(d); } + bool read( unsigned int thread , Data &d ){ return base_read(thread,d); } + +protected: + std::mutex _insertionMutex; + + // Read in data in a single-threaded context + virtual bool base_read( Data &d ) = 0; + + // Read in data in a multi-threaded context + virtual bool base_read( unsigned int thread , Data &d ) + { + std::lock_guard< std::mutex > lock( _insertionMutex ); + return base_read(d); + } +}; + +// An output stream containing "Data" types +// Supporting: +// -- Writing the next element to the stream +// -- Writing the next element to the stream by a particular thread +template< typename Data > +struct OutputDataStream +{ + friend struct MultiOutputDataStream< Data >; + + OutputDataStream( void ) : _size(0) {} + virtual ~OutputDataStream( void ){} + + // Returns the number of items written to the stream + size_t size( void ) const { return _size; } + + void write( const Data &d ){ base_write(d) ; _size++; } + void write( unsigned int thread , const Data &d ){ base_write( thread , d ) ; _size++; } + +protected: + std::mutex _insertionMutex; + std::atomic< size_t > _size; + + // Write out data in a single-threaded context + virtual void base_write( const Data &d ) = 0; + // Write out data in a multi-threaded context + virtual void base_write( unsigned int thread , const Data &d ) + { + std::lock_guard< std::mutex > lock( _insertionMutex ); + return base_write(d); + } + +}; + +////////////////////////////////////////// +// Multi-streams for multi-threaded I/O // +////////////////////////////////////////// +template< typename Data > +struct MultiInputDataStream : public InputDataStream< Data > +{ + MultiInputDataStream( InputDataStream< Data > **streams , size_t N ) : _current(0) , _streams( streams , streams+N ) {} + MultiInputDataStream( const std::vector< InputDataStream< Data > * > &streams ) : _current(0) , _streams( streams ) {} + void reset( void ){ for( unsigned int i=0 ; i<_streams.size() ; i++ ) _streams[i]->reset(); } + +protected: + std::vector< InputDataStream< Data > * > _streams; + unsigned int _current; + + bool base_read( unsigned int t , Data &d ){ return _streams[t]->base_read(d); } + bool base_read( Data &d ) + { + while( _current<_streams.size() ) + { + if( _streams[_current]->read( d ) ) return true; + else _current++; + } + return false; + } +}; + +template< typename Data > +struct MultiOutputDataStream : public OutputDataStream< Data > +{ + MultiOutputDataStream( OutputDataStream< Data > **streams , size_t N ) : _current(0) , _streams( streams , streams+N ) {} + MultiOutputDataStream( const std::vector< OutputDataStream< Data > * > &streams ) : _current(0) , _streams( streams ) {} + +protected: + std::vector< OutputDataStream< Data > * > _streams; + unsigned int _current; + + void base_write( const Data &d ){ _streams[0]->base_write(d); } + void base_write( unsigned int t , const Data &d ){ _streams[t]->base_write(d); } +}; + + +#endif // DATA_STREAM_INCLUDED diff --git a/Src/DataStream.imp.h b/Src/DataStream.imp.h new file mode 100644 index 00000000..d46cefc6 --- /dev/null +++ b/Src/DataStream.imp.h @@ -0,0 +1,289 @@ +/* +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 DATA_STREAM_IMPLEMENTATION_INCLUDED +#define DATA_STREAM_IMPLEMENTATION_INCLUDED + +#include +#include "DataStream.h" +#include "VertexFactory.h" +#include "Ply.h" + +//////////////////////////////// +// Vector-backed data streams // +//////////////////////////////// +template< typename Data > +struct VectorBackedInputDataStream : public InputDataStream< Data > +{ + VectorBackedInputDataStream( const std::vector< Data > &data ) : _data(data) , _current(0) {} + void reset( void ) { _current = 0; } + +protected: + const std::vector< Data > &_data; + size_t _current; + + bool base_read( Data &d ){ if( _current<_data.size() ){ d = _data[_current++] ; return true; } else return false; } +}; + +template< typename Data > +struct VectorBackedOutputDataStream : public OutputDataStream< Data > +{ + VectorBackedOutputDataStream( std::vector< Data > &data ) : _data(data) {} + +protected: + std::vector< Data > &_data; + + void base_write( const Data &d ){ _data.push_back(d); } +}; + +//////////////////////////////////////////////////////////////////// +// File-backed data stream (assumes Data is statically allocated) // +//////////////////////////////////////////////////////////////////// +template< typename Data > +struct FileBackedInputDataStream : public InputDataStream< Data > +{ + // It is assumed that the file pointer was open for binary reading + FileBackedInputDataStream( FILE *fp ) : _fp(fp) {} + void reset( void ){ fseek( _fp , 0 , SEEK_SET ); } + +protected: + FILE *_fp; + + bool base_read( Data &d ){ return fread( &d , sizeof(Data) , 1 , _fp )==1; } +}; + +template< typename Data > +struct FileBackedOutputDataStream : public OutputDataStream< Data > +{ + // It is assumed that the file pointer was open for binary writing + FileBackedOutputDataStream( FILE *fp ) : _fp(fp) {} + +protected: + FILE *_fp; + + void base_write( const Data &d ){ fwrite( &d , sizeof(Data) , 1 , _fp ); } +}; + +///////////////////////////////////////////////////////////////////////////////////////////// +// File-backed data stream specialized for vectors (assumes Data is statically allocated) // +///////////////////////////////////////////////////////////////////////////////////////////// +template< typename Data > +struct FileBackedInputDataStream< std::vector< Data > > : public InputDataStream< std::vector< Data > > +{ + // It is assumed that the file pointer was open for binary reading + FileBackedInputDataStream( FILE *fp ) : _fp(fp) {} + void reset( void ){ fseek( _fp , 0 , SEEK_SET ); } + +protected: + FILE *_fp; + + bool base_read( std::vector< Data > &d ) + { + unsigned int pSize; + if( fread( &pSize , sizeof(unsigned int) , 1 , _fp )==1 ) + { + d.resize( pSize ); + if( fread( &d[0] , sizeof(Data) , pSize , _fp )==pSize ) return true; + ERROR_OUT( "Failed to read polygon from file" ); + return true; + } + else return false; + } +}; + +template< typename Data > +struct FileBackedOutputDataStream< std::vector< Data > > : public OutputDataStream< std::vector< Data > > +{ + // It is assumed that the file pointer was open for binary writing + FileBackedOutputDataStream( FILE *fp ) : _fp(fp) {} + + +protected: + FILE *_fp; + + void base_write( const std::vector< Data > &d ) + { + unsigned int pSize = (unsigned int)d.size(); + fwrite( &pSize , sizeof(unsigned int) , 1 , _fp ); + fwrite( &d[0] , sizeof(Data) , pSize , _fp ); + } +}; + +//////////////////////////////////////////////////////// +// File-backed stream with data desribed by a factory // +//////////////////////////////////////////////////////// +template< typename Factory > +struct FileBackedInputFactoryTypeStream : public InputDataStream< typename Factory::VertexType > +{ + typedef typename Factory::VertexType Data; + // It is assumed that the file pointer was open for binary reading + FileBackedInputFactoryTypeStream( FILE *fp , const Factory &factory ) : _fp(fp) , _factory(factory) , _buffer( NewPointer< char >( _factory.bufferSize() ) ) , _bufferSize( _factory.bufferSize() ) {} + ~FileBackedInputFactoryTypeStream( void ){ DeletePointer( _buffer ); } + void reset( void ){ fseek( _fp , 0 , SEEK_SET ); } + +protected: + FILE *_fp; + const Factory _factory; + Pointer( char ) _buffer; + const size_t _bufferSize; + + bool base_read( Data &d ){ if( fread( _buffer , sizeof(unsigned char) , _bufferSize , _fp )==_bufferSize ){ _factory.fromBuffer( _buffer , d ) ; return true; } else return false; } +}; + +template< typename Factory > +struct FileBackedOutputFactoryTypeStream : public OutputDataStream< typename Factory::VertexType > +{ + typedef typename Factory::VertexType Data; + + // It is assumed that the file pointer was open for binary reading + FileBackedOutputFactoryTypeStream( FILE *fp , const Factory &factory ) : _fp(fp) , _factory(factory) , _buffer( NewPointer< char >( _factory.bufferSize() ) ) , _bufferSize( _factory.bufferSize() ) {} + ~FileBackedOutputFactoryTypeStream( void ){ DeletePointer( _buffer ); } + +protected: + FILE *_fp; + const Factory _factory; + Pointer( char ) _buffer; + const size_t _bufferSize; + + void base_write( const Data &d ){ _factory.toBuffer( d , _buffer ) ; fwrite( _buffer , sizeof(unsigned char) , _bufferSize , _fp ); } +}; + + +/////////////////////////////////////////////////////////////////////////////////// +// File-backed data streams, with functionality for reading/writing from/to disk // +/////////////////////////////////////////////////////////////////////////////////// + +template< typename Factory > +struct ASCIIInputDataStream : public InputDataStream< typename Factory::VertexType > +{ + typedef typename Factory::VertexType Data; + + ASCIIInputDataStream( const char* fileName , const Factory &factory ); + ~ASCIIInputDataStream( void ); + void reset( void ); + +protected: + const Factory _factory; + FILE *_fp; + + bool base_read( Data &d ); +}; + +template< typename Factory > +struct ASCIIOutputDataStream : public OutputDataStream< typename Factory::VertexType > +{ + typedef typename Factory::VertexType Data; + + ASCIIOutputDataStream( const char* fileName , const Factory &factory ); + ~ASCIIOutputDataStream( void ); + +protected: + const Factory _factory; + FILE *_fp; + + void base_write( const Data &d ); +}; + +template< typename Factory > +struct BinaryInputDataStream : public InputDataStream< typename Factory::VertexType > +{ + typedef typename Factory::VertexType Data; + + BinaryInputDataStream( const char* filename , const Factory &factory ); + ~BinaryInputDataStream( void ){ fclose( _fp ) , _fp=NULL; } + void reset( void ); + +protected: + const Factory _factory; + FILE* _fp; + + bool base_read( Data &d ); +}; + +template< typename Factory > +struct BinaryOutputDataStream : public OutputDataStream< typename Factory::VertexType > +{ + typedef typename Factory::VertexType Data; + + BinaryOutputDataStream( const char* filename , const Factory &factory ); + ~BinaryOutputDataStream( void ){ fclose( _fp ) , _fp=NULL; } + void reset( void ){ fseek( _fp , 0 , SEEK_SET ); } + +protected: + const Factory _factory; + FILE* _fp; + + void base_write( const Data &d ); +}; + +//////////////////////////////////////////// +// File-backed PLY-described data streams // +//////////////////////////////////////////// + +template< typename Factory > +struct PLYInputDataStream : public InputDataStream< typename Factory::VertexType > +{ + typedef typename Factory::VertexType Data; + + PLYInputDataStream( const char* fileName , const Factory &factory ); + PLYInputDataStream( const char* fileName , const Factory &factory , size_t &count ); + ~PLYInputDataStream( void ); + void reset( void ); + +protected: + const Factory _factory; + char* _fileName; + PlyFile *_ply; + std::vector< std::string > _elist; + Pointer( char ) _buffer; + + size_t _pCount , _pIdx; + void _free( void ); + bool base_read( Data &d ); +}; + +template< typename Factory > +struct PLYOutputDataStream : public OutputDataStream< typename Factory::VertexType > +{ + typedef typename Factory::VertexType Data; + + PLYOutputDataStream( const char* fileName , const Factory &factory , size_t count , int fileType=PLY_BINARY_NATIVE ); + ~PLYOutputDataStream( void ); + +protected: + const Factory _factory; + PlyFile *_ply; + size_t _pCount , _pIdx; + Pointer( char ) _buffer; + + void base_write( const Data &d ); +}; + +#include "DataStream.imp.inl" + +#endif // DATA_STREAM_IMPLEMENTATION_INCLUDED diff --git a/Src/VertexStream.inl b/Src/DataStream.imp.inl similarity index 83% rename from Src/VertexStream.inl rename to Src/DataStream.imp.inl index 617d2131..e4fc1d14 100644 --- a/Src/VertexStream.inl +++ b/Src/DataStream.imp.inl @@ -26,33 +26,6 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ -/////////////////////////// -// MemoryInputDataStream // -/////////////////////////// -template< typename Data > -MemoryInputDataStream< Data >::MemoryInputDataStream( size_t size , const Data *data ) : _data(data) , _size(size) , _current(0) {} -template< typename Data > -MemoryInputDataStream< Data >::~MemoryInputDataStream( void ){ ; } -template< typename Data > -void MemoryInputDataStream< Data >::reset( void ) { _current=0; } -template< typename Data > -bool MemoryInputDataStream< Data >::next( Data &d ) -{ - if( _current>=_size ) return false; - d = _data[_current++]; - return true; -} - -//////////////////////////// -// MemoryOutputDataStream // -//////////////////////////// -template< typename Data > -MemoryOutputDataStream< Data >::MemoryOutputDataStream( size_t size , Data *data ) : _data(data) , _size(size) , _current(0) {} -template< typename Data > -MemoryOutputDataStream< Data >::~MemoryOutputDataStream( void ){ ; } -template< typename Data > -void MemoryOutputDataStream< Data >::next( const Data &d ){ _data[_current++] = d; } - ////////////////////////// // ASCIIInputDataStream // ////////////////////////// @@ -62,16 +35,19 @@ ASCIIInputDataStream< Factory >::ASCIIInputDataStream( const char* fileName , co _fp = fopen( fileName , "r" ); if( !_fp ) ERROR_OUT( "Failed to open file for reading: %s" , fileName ); } + template< typename Factory > ASCIIInputDataStream< Factory >::~ASCIIInputDataStream( void ) { fclose( _fp ); _fp = NULL; } + template< typename Factory > void ASCIIInputDataStream< Factory >::reset( void ) { fseek( _fp , 0 , SEEK_SET ); } + template< typename Factory > -bool ASCIIInputDataStream< Factory >::next( Data &d ){ return _factory.readASCII( _fp , d ); } +bool ASCIIInputDataStream< Factory >::base_read( Data &d ){ return _factory.readASCII( _fp , d ); } /////////////////////////// // ASCIIOutputDataStream // @@ -82,14 +58,16 @@ ASCIIOutputDataStream< Factory >::ASCIIOutputDataStream( const char* fileName , _fp = fopen( fileName , "w" ); if( !_fp ) ERROR_OUT( "Failed to open file for writing: %s" , fileName ); } + template< typename Factory > ASCIIOutputDataStream< Factory >::~ASCIIOutputDataStream( void ) { fclose( _fp ); _fp = NULL; } + template< typename Factory > -void ASCIIOutputDataStream< Factory >::next( const Data &d ){ _factory.writeASCII( _fp , d ); } +void ASCIIOutputDataStream< Factory >::base_write( const Data &d ){ _factory.writeASCII( _fp , d ); } /////////////////////////// // BinaryInputDataStream // @@ -100,10 +78,12 @@ BinaryInputDataStream< Factory >::BinaryInputDataStream( const char* fileName , _fp = fopen( fileName , "rb" ); if( !_fp ) ERROR_OUT( "Failed to open file for reading: %s" , fileName ); } + template< typename Factory > void BinaryInputDataStream< Factory >::reset( void ) { fseek( _fp , 0 , SEEK_SET ); } + template< typename Factory > -bool BinaryInputDataStream< Factory >::next( Data &d ){ return _factory.readBinary( _fp , d ); } +bool BinaryInputDataStream< Factory >::base_read( Data &d ){ return _factory.readBinary( _fp , d ); } //////////////////////////// // BinaryOutputDataStream // @@ -114,8 +94,9 @@ BinaryOutputDataStream< Factory >::BinaryOutputDataStream( const char* fileName _fp = fopen( fileName , "wb" ); if( !_fp ) ERROR_OUT( "Failed to open file for writing: %s" , fileName ); } + template< typename Factory > -void BinaryOutputDataStream< Factory >::next( const Data &d ){ return _factory.writeBinary( _fp , d ); } +void BinaryOutputDataStream< Factory >::base_write( const Data &d ){ return _factory.writeBinary( _fp , d ); } //////////////////////// // PLYInputDataStream // @@ -142,6 +123,7 @@ PLYInputDataStream< Factory >::PLYInputDataStream( const char* fileName , const else _buffer = NullPointer( char ); reset(); } + template< typename Factory > void PLYInputDataStream< Factory >::reset( void ) { @@ -179,6 +161,7 @@ void PLYInputDataStream< Factory >::reset( void ) } if( !foundData ) ERROR_OUT( "Could not find data in ply file" ); } + template< typename Factory > void PLYInputDataStream< Factory >::_free( void ){ delete _ply; } @@ -189,8 +172,9 @@ PLYInputDataStream< Factory >::~PLYInputDataStream( void ) if( _fileName ) delete[] _fileName , _fileName = NULL; DeletePointer( _buffer ); } + template< typename Factory > -bool PLYInputDataStream< Factory >::next( Data &d ) +bool PLYInputDataStream< Factory >::base_read( Data &d ) { if( _pIdx<_pCount ) { @@ -230,6 +214,7 @@ PLYOutputDataStream< Factory >::PLYOutputDataStream( const char* fileName , cons if( _factory.bufferSize() ) _buffer = NewPointer< char >( _factory.bufferSize() ); else _buffer = NullPointer( char ); } + template< typename Factory > PLYOutputDataStream< Factory >::~PLYOutputDataStream( void ) { @@ -237,8 +222,9 @@ PLYOutputDataStream< Factory >::~PLYOutputDataStream( void ) delete _ply; DeletePointer( _buffer ); } + template< typename Factory > -void PLYOutputDataStream< Factory >::next( const Data &d ) +void PLYOutputDataStream< Factory >::base_write( const Data &d ) { if( _pIdx==_pCount ) ERROR_OUT( "Trying to add more points than total: " , _pIdx , " < " , _pCount ); if( _factory.isStaticallyAllocated() ) _ply->put_element( (void *)&d ); diff --git a/Src/FEMTree.Initialize.inl b/Src/FEMTree.Initialize.inl index b5a8ee53..2efc9ccf 100644 --- a/Src/FEMTree.Initialize.inl +++ b/Src/FEMTree.Initialize.inl @@ -96,7 +96,7 @@ size_t FEMTreeInitializer< Dim , Real >::Initialize( StreamInitializationData &s std::vector< node_index_type > &nodeToIndexMap = sid._nodeToIndexMap; typename InputPointStream< AuxData >::PointAndDataType pd; pd.template get<1>() = zeroData; - while( pointStream.next( pd ) ) + while( pointStream.read( pd ) ) { Point< Real , Dim > p = pd.template get<0>(); typename InputPointStream< AuxData >::DataType d = InputPointStream< AuxData >::GetData( pd ); diff --git a/Src/FEMTree.LevelSet.2D.inl b/Src/FEMTree.LevelSet.2D.inl index c29c8e1b..a2278e9f 100644 --- a/Src/FEMTree.LevelSet.2D.inl +++ b/Src/FEMTree.LevelSet.2D.inl @@ -38,15 +38,22 @@ DAMAGE. #include "MAT.h" // Specialized level-set curve extraction -template< class Real , typename Vertex > -struct LevelSetExtractor< 2 , Real , Vertex > +template< bool HasData , typename Real , typename Data > +struct _LevelSetExtractor< HasData , Real , 2 , Data > { + static const unsigned int Dim = 2; + // Store the position, the (interpolated) gradient, the weight, and possibly data + typedef typename std::conditional + < + HasData , + VectorTypeUnion< Real , Point< Real , Dim > , Point< Real , Dim > , Real , Data > , + VectorTypeUnion< Real , Point< Real , Dim > , Point< Real , Dim > , Real > + >::type Vertex; protected: static std::mutex _pointInsertionMutex; static std::atomic< size_t > _BadRootCount; public: - static const unsigned int Dim = 2; using LocalDepth = typename FEMTree< Dim , Real >::LocalDepth; using LocalOffset = typename FEMTree< Dim , Real >::LocalOffset; using ConstOneRingNeighborKey = typename FEMTree< Dim , Real >::ConstOneRingNeighborKey; @@ -563,8 +570,9 @@ public: ); } - template< unsigned int WeightDegree , typename Data , unsigned int DataSig > - static void SetIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > > *pointEvaluator , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , node_index_type &vOffset , StreamingVertices< Vertex , node_index_type > *vertices , std::vector< SliceValues > &sliceValues , std::vector< typename SliceValues::Scratch > &scratchValues , const Data &zeroData , std::function< void ( Vertex& , Point< Real , Dim > , Point< Real , Dim > , Real , Data ) > SetVertex ) + + template< unsigned int WeightDegree , unsigned int DataSig > + static void SetIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool outputGradients , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > > *pointEvaluator , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , node_index_type &vOffset , OutputDataStream< Vertex > &vertexStream , std::vector< SliceValues > &sliceValues , std::vector< typename SliceValues::Scratch > &scratchValues , const Data &zeroData ) { auto _EdgeIndex = [&]( const TreeNode *node , typename HyperCube::Cube< Dim >::template Element< 1 > e ) { @@ -602,7 +610,7 @@ public: { neighborKey.getNeighbors( leaf ); if( densityWeights ) weightKey.getNeighbors( leaf ); - if( data ) dataKey.getNeighbors( leaf ); + if constexpr( HasData ) if( data ) dataKey.getNeighbors( leaf ); // Check if the individual edges have zero-crossings for( typename HyperCube::Cube< Dim >::template Element< 1 > e ; e::template ElementNum< 1 >() ; e++ ) @@ -615,14 +623,14 @@ public: { Vertex vertex; Key key = _EdgeIndex( leaf , e ); - GetIsoVertex< WeightDegree , Data , DataSig >( tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , e , sValues , vertex , zeroData , SetVertex ); + GetIsoVertex< WeightDegree , DataSig >( tree , nonLinearFit , outputGradients , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , e , sValues , vertex , zeroData ); bool stillOwner = false; node_index_type hashed_vertex; { std::lock_guard< std::mutex > lock( _pointInsertionMutex ); if( !edgeSet ) { - if( vertices ) vertices->addVertex( vertex ); + vertexStream.write( vertex ); edgeSet = 1; hashed_vertex = vOffset; sValues.edgeKeys[ vIndex ] = key; @@ -787,7 +795,7 @@ public: ); } - static void SetLevelSet( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , LocalDepth depth , const SliceValues &sValues , StreamingCurve< Vertex , node_index_type >& curve , bool flipOrientation ) + static void SetLevelSet( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , LocalDepth depth , const SliceValues &sValues , OutputDataStream< std::pair< node_index_type , node_index_type > >& edgeStream , bool flipOrientation ) { auto _FaceIndex = [&]( const TreeNode *node , typename HyperCube::Cube< Dim >::template Element< 2 > f ) { @@ -804,8 +812,8 @@ public: else ERROR_OUT( "Couldn't find vertex in edge map" ); if( ( iter=sValues.edgeVertexMap.find( e[1] ) )!=sValues.edgeVertexMap.end() ) idx2 = iter->second; else ERROR_OUT( "Couldn't find vertex in edge map" ); - if( flipOrientation ) curve.addEdge_s( thread , idx2 , idx1 ); - else curve.addEdge_s( thread , idx1 , idx2 ); + if( flipOrientation ) edgeStream.write( thread , std::make_pair( idx2 , idx1 ) ); + else edgeStream.write( thread , std::make_pair( idx1 , idx2 ) ); }; ThreadPool::Parallel_for( tree._sNodesBegin(depth) , tree._sNodesEnd(depth) , [&]( unsigned int thread , size_t i ) @@ -835,8 +843,9 @@ public: ); } - template< unsigned int WeightDegree , typename Data , unsigned int DataSig > - static bool GetIsoVertex( const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , ConstPointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , ConstPointSupportKey< IsotropicUIntPack< Dim , FEMSignature< DataSig >::Degree > >& dataKey , const TreeNode* node , typename HyperCube::template Cube< Dim >::template Element< 1 > e , const SliceValues& sValues , Vertex& vertex , const Data &zeroData , std::function< void ( Vertex& , Point< Real , Dim > , Point< Real , Dim > , Real , Data ) > SetVertex ) + + template< unsigned int WeightDegree , unsigned int DataSig > + static bool GetIsoVertex( const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool outputGradients , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , ConstPointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , ConstPointSupportKey< IsotropicUIntPack< Dim , FEMSignature< DataSig >::Degree > >& dataKey , const TreeNode* node , typename HyperCube::template Cube< Dim >::template Element< 1 > e , const SliceValues& sValues , Vertex& vertex , const Data &zeroData ) { static const unsigned int DataDegree = FEMSignature< DataSig >::Degree; Point< Real , Dim > position , gradient; @@ -847,7 +856,7 @@ public: const typename LevelSetExtraction::FullCellIndexData< Dim >::template CellIndices<0> &idx = sValues.cellIndices.template indices<0>( node ); Real x0 = sValues.cornerValues[idx[c0]] , x1 = sValues.cornerValues[idx[c1]]; Point< Real , Dim > dx0 , dx1; - if( gradientNormals ) dx0 = sValues.cornerGradients[idx[c0]] , dx1 = sValues.cornerGradients[idx[c1]]; + if( outputGradients ) dx0 = sValues.cornerGradients[idx[c0]] , dx1 = sValues.cornerGradients[idx[c1]]; Point< Real , Dim > s; Real start , width; tree._startAndWidth( node , s , width ); @@ -908,7 +917,7 @@ public: Real weight; tree._getSampleDepthAndWeight( *densityWeights , node , position , weightKey , depth , weight ); } - if( data ) + if constexpr( HasData ) if( data ) { if( DataDegree==0 ) { @@ -924,7 +933,10 @@ public: dataValue = pValue.weight ? pValue.value() : zeroData; } } - SetVertex( vertex , position , gradient , depth , dataValue ); + vertex.template get<0>() = position; + vertex.template get<1>() = gradient; + vertex.template get<2>() = depth; + if constexpr( HasData ) vertex.template get<3>() = dataValue; return true; } @@ -943,20 +955,22 @@ public: } }; - protected: - enum _SetFlag - { - CORNER_VALUES = 1, - ISO_VERTICES = 2, - ISO_EDGES = 4 - }; - public: - static int SetCornerValuesFlag( void ){ return _SetFlag::CORNER_VALUES; } - static int SetIsoVerticesFlag ( void ){ return _SetFlag::CORNER_VALUES | _SetFlag::ISO_VERTICES; } - static int SetIsoEdgesFlag ( void ){ return _SetFlag::CORNER_VALUES | _SetFlag::ISO_VERTICES | _SetFlag::ISO_EDGES; } +protected: + enum _SetFlag + { + CORNER_VALUES = 1, + ISO_VERTICES = 2, + ISO_EDGES = 4 + }; + +public: + static int SetCornerValuesFlag( void ){ return _SetFlag::CORNER_VALUES; } + static int SetIsoVerticesFlag ( void ){ return _SetFlag::CORNER_VALUES | _SetFlag::ISO_VERTICES; } + static int SetIsoEdgesFlag ( void ){ return _SetFlag::CORNER_VALUES | _SetFlag::ISO_VERTICES | _SetFlag::ISO_EDGES; } + - template< typename Data , typename SetVertexFunction , unsigned int ... FEMSigs , unsigned int WeightDegree , unsigned int DataSig > - static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , StreamingVertices< Vertex , node_index_type > *vertices , const Data &zeroData , const SetVertexFunction &SetVertex , bool nonLinearFit , bool gradientNormals , std::vector< SliceValues > &sliceValues , int setFlag ) + template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > + static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputDataStream< Vertex > &vertexStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , std::vector< SliceValues > &sliceValues , int setFlag ) { if( maxKeyDepth -struct LevelSetExtractor< 3 , Real , Vertex > +template< bool HasData , typename Real , typename Data > +struct _LevelSetExtractor< HasData , Real , 3 , Data > { + static const unsigned int Dim = 3; + // Store the position, the (interpolated) gradient, the weight, and possibly data + typedef typename std::conditional + < + HasData , + VectorTypeUnion< Real , Point< Real , Dim > , Point< Real , Dim > , Real , Data > , + VectorTypeUnion< Real , Point< Real , Dim > , Point< Real , Dim > , Real > + >::type Vertex; + protected: static std::mutex _pointInsertionMutex; static std::atomic< size_t > _BadRootCount; public: - static const unsigned int Dim = 3; typedef typename FEMTree< Dim , Real >::LocalDepth LocalDepth; typedef typename FEMTree< Dim , Real >::LocalOffset LocalOffset; typedef typename FEMTree< Dim , Real >::ConstOneRingNeighborKey ConstOneRingNeighborKey; @@ -485,7 +494,7 @@ public: static std::vector< std::pair< node_index_type , node_index_type > > SetIncidence( const FEMTree< Dim , Real > &tree , const FEMTree< Dim-1 , Real > &sliceTree , LocalDepth fullDepth , unsigned int sliceAtMaxDepth , unsigned int maxDepth ) { - using SliceTreeNode = typename LevelSetExtractor< Dim-1 , Real , Point< Real , Dim-1 > >::TreeNode; + using SliceTreeNode = typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeNode; using SliceLocalDepth = typename FEMTree< Dim-1 , Real >::LocalDepth; using SliceLocalOffset = typename FEMTree< Dim-1 , Real >::LocalOffset; @@ -542,11 +551,11 @@ public: return incidence; } - template< unsigned int WeightDegree , typename Data , unsigned int DataSig , typename SliceFunctor /* = std::function< SliceValues & ( unsigned int ) > */ , typename ScratchFunctor /* = std::function< typename SliceValues::Scratch & ( unsigned int ) */ > + template< unsigned int WeightDegree , unsigned int DataSig , typename SliceFunctor /* = std::function< SliceValues & ( unsigned int ) > */ , typename ScratchFunctor /* = std::function< typename SliceValues::Scratch & ( unsigned int ) */ > static void CopyIsoStructure ( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , - const typename LevelSetExtractor< Dim-1 , Real , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions &boundaryInfo , + const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions &boundaryInfo , const FEMTree< Dim , Real > &tree , LocalDepth fullDepth , unsigned int sliceAtMaxDepth , @@ -554,18 +563,17 @@ public: SliceFunctor sliceFunctor , ScratchFunctor scratchFunctor , const std::vector< std::pair< node_index_type , node_index_type > > &incidence , - StreamingVertices< Vertex , node_index_type >& vertexStream , + OutputDataStream< Vertex > &vertexStream , bool gradientNormals , - typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , + typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > > *pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , node_index_type& vOffset , - const Data &zeroData , - std::function< void ( Vertex& , Point< Real , Dim > , Point< Real , Dim > , Real , Data ) > SetVertex + const Data &zeroData ) { - using SliceTreeNode = typename LevelSetExtractor< Dim-1 , Real , Point< Real , Dim-1 > >::TreeNode; - using SliceSliceValues = typename LevelSetExtractor< Dim-1 , Real , Point< Real , Dim-1 > >::SliceValues; + using SliceTreeNode = typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeNode; + using SliceSliceValues = typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::SliceValues; using SliceKey = LevelSetExtraction::Key< Dim-1 >; using SliceIsoEdge = LevelSetExtraction::IsoEdge< Dim-1 >; @@ -647,7 +655,7 @@ public: Real weight; tree._getSampleDepthAndWeight( *densityWeights , node , p , weightKey , depth , weight ); } - if( data ) + if constexpr( HasData ) if( data ) { dataKey.set( node->depth() ); dataKey.getNeighbors( node ); @@ -668,8 +676,11 @@ public: dataValue = pValue.weight ? pValue.value() : zeroData; } } - SetVertex( vertices[i] , p , Point< Real , Dim >() , depth , dataValue ); - vertexStream.addVertex( vertices[i] ); + vertices[i].template get<0>() = p; + vertices[i].template get<1>() = Point< Real , Dim >(); + vertices[i].template get<2>() = depth; + if constexpr( HasData ) vertices[i].template get<3>() = dataValue; + vertexStream.write( vertices[i] ); } } @@ -746,10 +757,10 @@ public: } } - static void OverwriteCornerValues( const typename LevelSetExtractor< Dim-1 , Real , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions &boundaryInfo , const std::vector< Real > &dValues , const FEMTree< Dim , Real > &tree , LocalDepth depth , unsigned int sliceAtMaxDepth , unsigned int maxDepth , bool isBack , std::vector< SlabValues > &slabValues , const std::vector< std::pair< node_index_type , node_index_type > > &incidence ) + static void OverwriteCornerValues( const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions &boundaryInfo , const std::vector< Real > &dValues , const FEMTree< Dim , Real > &tree , LocalDepth depth , unsigned int sliceAtMaxDepth , unsigned int maxDepth , bool isBack , std::vector< SlabValues > &slabValues , const std::vector< std::pair< node_index_type , node_index_type > > &incidence ) { - using SliceTreeNode = typename LevelSetExtractor< Dim-1 , Real , Point< Real , Dim-1 > >::TreeNode; - using SliceSliceValues = typename LevelSetExtractor< Dim-1 , Real , Point< Real , Dim-1 > >::SliceValues; + using SliceTreeNode = typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeNode; + using SliceSliceValues = typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::SliceValues; unsigned int slice = sliceAtMaxDepth>>( maxDepth - depth ); if( !isBack && sliceAtMaxDepth!=( slice<<(maxDepth-depth ) ) ) slice++; @@ -892,15 +903,15 @@ public: ); } - template< unsigned int WeightDegree , typename Data , unsigned int DataSig > - static void SetSliceIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slice , node_index_type& vOffset , StreamingVertices< Vertex , node_index_type >& vertices , std::vector< SlabValues >& slabValues , const Data &zeroData , std::function< void ( Vertex& , Point< Real , Dim > , Point< Real , Dim > , Real , Data ) > SetVertex ) + template< unsigned int WeightDegree , unsigned int DataSig > + static void SetSliceIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slice , node_index_type& vOffset , OutputDataStream< Vertex >& vertices , std::vector< SlabValues >& slabValues , const Data &zeroData ) { - if( slice>0 ) SetSliceIsoVertices< WeightDegree , Data , DataSig >( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , depth , fullDepth , slice , HyperCube::FRONT , vOffset , vertices , slabValues , zeroData , SetVertex ); - if( slice<(1<( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , depth , fullDepth , slice , HyperCube::BACK , vOffset , vertices , slabValues , zeroData , SetVertex ); + if( slice>0 ) SetSliceIsoVertices< WeightDegree , DataSig >( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , depth , fullDepth , slice , HyperCube::FRONT , vOffset , vertices , slabValues , zeroData ); + if( slice<(1<( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , depth , fullDepth , slice , HyperCube::BACK , vOffset , vertices , slabValues , zeroData ); } - template< unsigned int WeightDegree , typename Data , unsigned int DataSig > - static void SetSliceIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slice , HyperCube::Direction zDir , node_index_type& vOffset , StreamingVertices< Vertex , node_index_type >& vertices , std::vector< SlabValues >& slabValues , const Data &zeroData , std::function< void ( Vertex& , Point< Real , Dim > , Point< Real , Dim > , Real , Data ) > SetVertex ) + template< unsigned int WeightDegree , unsigned int DataSig > + static void SetSliceIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slice , HyperCube::Direction zDir , node_index_type& vOffset , OutputDataStream< Vertex >& vertices , std::vector< SlabValues >& slabValues , const Data &zeroData ) { auto _EdgeIndex = [&]( const TreeNode *node , typename HyperCube::Cube< Dim >::template Element< 1 > e ) { @@ -933,7 +944,7 @@ public: { neighborKey.getNeighbors( leaf ); if( densityWeights ) weightKey.getNeighbors( leaf ); - if( data ) dataKey.getNeighbors( leaf ); + if constexpr( HasData ) if( data ) dataKey.getNeighbors( leaf ); for( typename HyperCube::Cube< Dim-1 >::template Element< 1 > _e ; _e::template ElementNum< 1 >() ; _e++ ) if( HyperCube::Cube< 1 >::HasMCRoots( HyperCube::Cube< Dim-1 >::ElementMCIndex( _e , sValues.mcIndices[idx] ) ) ) @@ -945,14 +956,14 @@ public: { Vertex vertex; Key key = _EdgeIndex( leaf , e ); - GetIsoVertex< WeightDegree , Data , DataSig >( tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , _e , zDir , sValues , vertex , zeroData , SetVertex ); + GetIsoVertex< WeightDegree , DataSig >( tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , _e , zDir , sValues , vertex , zeroData ); bool stillOwner = false; std::pair< node_index_type , Vertex > hashed_vertex; { std::lock_guard< std::mutex > lock( _pointInsertionMutex ); if( !edgeSet ) { - vertices.addVertex( vertex ); + vertices.write( vertex ); edgeSet = 1; hashed_vertex = std::pair< node_index_type , Vertex >( vOffset , vertex ); sValues.edgeKeys[ vIndex ] = key; @@ -1027,8 +1038,8 @@ public: //////////////////// // Iso-Extraction // //////////////////// - template< unsigned int WeightDegree , typename Data , unsigned int DataSig > - static void SetXSliceIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slab , Real bCoordinate , Real fCoordinate , node_index_type &vOffset , StreamingVertices< Vertex , node_index_type > &vertices , std::vector< SlabValues >& slabValues , const Data &zeroData , std::function< void ( Vertex& , Point< Real , Dim > , Point< Real , Dim > , Real , Data ) > SetVertex ) + template< unsigned int WeightDegree , unsigned int DataSig > + static void SetXSliceIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slab , Real bCoordinate , Real fCoordinate , node_index_type &vOffset , OutputDataStream< Vertex > &vertices , std::vector< SlabValues >& slabValues , const Data &zeroData ) { auto _EdgeIndex = [&]( const TreeNode *node , typename HyperCube::Cube< Dim >::template Element< 1 > e ) { @@ -1066,7 +1077,7 @@ public: { neighborKey.getNeighbors( leaf ); if( densityWeights ) weightKey.getNeighbors( leaf ); - if( data ) dataKey.getNeighbors( leaf ); + if constexpr( HasData ) if( data ) dataKey.getNeighbors( leaf ); for( typename HyperCube::Cube< Dim-1 >::template Element< 0 > _c ; _c::template ElementNum< 0 >() ; _c++ ) { typename HyperCube::Cube< Dim >::template Element< 1 > e( HyperCube::CROSS , _c.index ); @@ -1079,14 +1090,14 @@ public: { Vertex vertex; Key key = _EdgeIndex( leaf , e.index ); - GetIsoVertex< WeightDegree , Data , DataSig >( tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , _c , bCoordinate , fCoordinate , bValues , fValues , vertex , zeroData , SetVertex ); + GetIsoVertex< WeightDegree , DataSig >( tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , _c , bCoordinate , fCoordinate , bValues , fValues , vertex , zeroData ); bool stillOwner = false; std::pair< node_index_type , Vertex > hashed_vertex; { std::lock_guard< std::mutex > lock( _pointInsertionMutex ); if( !edgeSet ) { - vertices.addVertex( vertex ); + vertices.write( vertex ); edgeSet = 1; hashed_vertex = std::pair< node_index_type , Vertex >( vOffset , vertex ); xValues.edgeKeys[ vIndex ] = key; @@ -1447,7 +1458,7 @@ public: } template< typename FaceIndexFunctor /* = std::function< LevelSetExtraction::Key< Dim > ( const TreeNode * , typename HyperCube::Cube< Dim >::template Element< 2 > ) */ > - static void SetLevelSet( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , FaceIndexFunctor faceIndexFunctor , const FEMTree< Dim , Real >& tree , LocalDepth depth , int offset , const SliceValues& bValues , const SliceValues& fValues , const XSliceValues& xValues , const typename SliceValues::Scratch &bScratch , const typename SliceValues::Scratch &fScratch , const typename XSliceValues::Scratch &xScratch , StreamingMesh< Vertex , node_index_type >& mesh , bool polygonMesh , bool addBarycenter , node_index_type& vOffset , bool flipOrientation ) + static void SetLevelSet( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , FaceIndexFunctor faceIndexFunctor , const FEMTree< Dim , Real >& tree , LocalDepth depth , int offset , const SliceValues& bValues , const SliceValues& fValues , const XSliceValues& xValues , const typename SliceValues::Scratch &bScratch , const typename SliceValues::Scratch &fScratch , const typename XSliceValues::Scratch &xScratch , OutputDataStream< Vertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool polygonMesh , bool addBarycenter , node_index_type& vOffset , bool flipOrientation ) { std::vector< std::pair< node_index_type , Vertex > > polygon; std::vector< std::vector< IsoEdge > > edgess( ThreadPool::NumThreads() ); @@ -1539,7 +1550,7 @@ public: else if( ( iter=xValues.edgeVertexMap.find( key ) )!=xValues.edgeVertexMap.end() ) polygon[kk] = iter->second; else ERROR_OUT( "Couldn't find vertex in edge map: " , off[0] , " , " , off[1] , " , " , off[2] , " @ " , depth , " : " , keyGenerator.to_string( key ) , " | " , key.to_string() ); } - AddIsoPolygons( thread , mesh , polygon , polygonMesh , addBarycenter , vOffset ); + AddIsoPolygons( thread , vertexStream , polygonStream , polygon , polygonMesh , addBarycenter , vOffset ); } } } @@ -1548,8 +1559,25 @@ public: ); } - template< unsigned int WeightDegree , typename Data , unsigned int DataSig > - static bool GetIsoVertex( const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , ConstPointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , ConstPointSupportKey< IsotropicUIntPack< Dim , FEMSignature< DataSig >::Degree > >& dataKey , const TreeNode* node , typename HyperCube::template Cube< Dim-1 >::template Element< 1 > _e , HyperCube::Direction zDir , const SliceValues& sValues , Vertex& vertex , const Data &zeroData , std::function< void ( Vertex& , Point< Real , Dim > , Point< Real , Dim > , Real , Data ) > SetVertex ) + template< unsigned int WeightDegree , unsigned int DataSig > + static bool GetIsoVertex + ( + const FEMTree< Dim , Real >& tree , + bool nonLinearFit , + bool gradientNormals , + typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > > *pointEvaluator , + const DensityEstimator< WeightDegree > *densityWeights , + const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , + Real isoValue , + ConstPointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , + ConstPointSupportKey< IsotropicUIntPack< Dim , FEMSignature< DataSig >::Degree > > &dataKey , + const TreeNode *node , + typename HyperCube::template Cube< Dim-1 >::template Element< 1 > _e , + HyperCube::Direction zDir , + const SliceValues& sValues , + Vertex& vertex , + const Data &zeroData + ) { static const unsigned int DataDegree = FEMSignature< DataSig >::Degree; Point< Real , Dim > position , gradient; @@ -1622,7 +1650,7 @@ public: Real weight; tree._getSampleDepthAndWeight( *densityWeights , node , position , weightKey , depth , weight ); } - if( data ) + if constexpr( HasData ) if( data ) { if( DataDegree==0 ) { @@ -1638,12 +1666,34 @@ public: dataValue = pValue.weight ? pValue.value() : zeroData; } } - SetVertex( vertex , position , gradient , depth , dataValue ); + vertex.template get<0>() = position; + vertex.template get<1>() = gradient; + vertex.template get<2>() = depth; + if constexpr( HasData ) vertex.template get<3>() = dataValue; return true; } - template< unsigned int WeightDegree , typename Data , unsigned int DataSig > - static bool GetIsoVertex( const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , ConstPointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , ConstPointSupportKey< IsotropicUIntPack< Dim , FEMSignature< DataSig >::Degree > >& dataKey , const TreeNode* node , typename HyperCube::template Cube< Dim-1 >::template Element< 0 > _c , Real bCoordinate , Real fCoordinate , const SliceValues& bValues , const SliceValues& fValues , Vertex& vertex , const Data &zeroData , std::function< void ( Vertex& , Point< Real , Dim > , Point< Real , Dim > , Real , Data ) > SetVertex ) + template< unsigned int WeightDegree , unsigned int DataSig > + static bool GetIsoVertex + ( + const FEMTree< Dim , Real > &tree , + bool nonLinearFit , + bool gradientNormals , + typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > > *pointEvaluator , + const DensityEstimator< WeightDegree > *densityWeights , + const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , + Real isoValue , + ConstPointSupportKey< IsotropicUIntPack< Dim , WeightDegree > > &weightKey , + ConstPointSupportKey< IsotropicUIntPack< Dim , FEMSignature< DataSig >::Degree > > &dataKey , + const TreeNode *node , + typename HyperCube::template Cube< Dim-1 >::template Element< 0 > _c , + Real bCoordinate , + Real fCoordinate , + const SliceValues &bValues , + const SliceValues &fValues , + Vertex &vertex , + const Data &zeroData + ) { static const unsigned int DataDegree = FEMSignature< DataSig >::Degree; Point< Real , Dim > position , gradient; @@ -1711,7 +1761,7 @@ public: Real weight; tree._getSampleDepthAndWeight( *densityWeights , node , position , weightKey , depth , weight ); } - if( data ) + if constexpr( HasData ) if( data ) { if( DataDegree==0 ) { @@ -1727,17 +1777,20 @@ public: dataValue = pValue.weight ? pValue.value() : zeroData; } } - SetVertex( vertex , position , gradient , depth , dataValue ); + vertex.template get<0>() = position; + vertex.template get<1>() = gradient; + vertex.template get<2>() = depth; + if constexpr( HasData ) vertex.template get<3>() = dataValue; return true; } - static unsigned int AddIsoPolygons( unsigned int thread , StreamingMesh< Vertex , node_index_type >& mesh , std::vector< std::pair< node_index_type , Vertex > >& polygon , bool polygonMesh , bool addBarycenter , node_index_type &vOffset ) + static unsigned int AddIsoPolygons( unsigned int thread , OutputDataStream< Vertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , std::vector< std::pair< node_index_type , Vertex > >& polygon , bool polygonMesh , bool addBarycenter , node_index_type &vOffset ) { if( polygonMesh ) { std::vector< node_index_type > vertices( polygon.size() ); for( unsigned int i=0 ; i3 ) @@ -1761,15 +1814,15 @@ public: node_index_type cIdx; { std::lock_guard< std::mutex > lock( _pointInsertionMutex ); - cIdx = mesh.addVertex( c ); - vOffset++; + vertexStream.write( c ); + cIdx = vOffset++; } for( unsigned i=0 ; i vertices( 3 ); for( int i=0 ; i<3 ; i++ ) vertices[2-i] = polygon[i].first; - mesh.addPolygon_s( thread , vertices ); + polygonStream.write( thread , vertices ); } return (unsigned int)polygon.size()-2; } @@ -1810,21 +1863,36 @@ public: } }; - template< typename Data , typename SetVertexFunction , unsigned int ... FEMSigs , unsigned int WeightDegree , unsigned int DataSig > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , StreamingMesh< Vertex , node_index_type >& mesh , const Data &zeroData , const SetVertexFunction &SetVertex , bool nonLinearFit , bool gradientNormals , bool addBarycenter , bool polygonMesh , bool flipOrientation ) - { - return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , 0 , 0 , 1 , mesh , zeroData , SetVertex , nonLinearFit , gradientNormals , addBarycenter , polygonMesh , flipOrientation ); - } - - template< typename Data , typename SetVertexFunction , unsigned int ... FEMSigs , unsigned int WeightDegree , unsigned int DataSig > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , StreamingMesh< Vertex , node_index_type >& mesh , const Data &zeroData , const SetVertexFunction &SetVertex , bool nonLinearFit , bool gradientNormals , bool addBarycenter , bool polygonMesh , bool flipOrientation ) - { - std::vector< std::vector< Real > > dValues; - return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , tree._maxDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , mesh , zeroData , SetVertex , nonLinearFit , gradientNormals , addBarycenter , polygonMesh , flipOrientation , NULL , NULL , dValues , dValues , false ); - } - template< typename Data , typename SetVertexFunction , unsigned int ... FEMSigs , unsigned int WeightDegree , unsigned int DataSig > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , int maxKeyDepth , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , StreamingMesh< Vertex , node_index_type >& mesh , const Data &zeroData , const SetVertexFunction &SetVertex , bool nonLinearFit , bool gradientNormals , bool addBarycenter , bool polygonMesh , bool flipOrientation , const typename LevelSetExtractor< Dim-1 , Real , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *backBoundary , const typename LevelSetExtractor< Dim-1 , Real , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *frontBoundary , const std::vector< std::vector< Real > > &backDValues , const std::vector< std::vector< Real > > &frontDValues , bool copyTopology ) + template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > + static Stats Extract + ( + UIntPack< FEMSigs ... > , + UIntPack< WeightDegree > , + UIntPack< DataSig > , + const FEMTree< Dim , Real > &tree , + int maxKeyDepth , + const DensityEstimator< WeightDegree > *densityWeights , + const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , + const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , + Real isoValue , + unsigned int slabDepth , + unsigned int slabStart , + unsigned int slabEnd , + OutputDataStream< Vertex > &vertexStream , + OutputDataStream< std::vector< node_index_type > > &polygonStream , + const Data &zeroData , + bool nonLinearFit , + bool gradientNormals , + bool addBarycenter , + bool polygonMesh , + bool flipOrientation , + const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions * backBoundary , + const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *frontBoundary , + const std::vector< std::vector< Real > > &backDValues , + const std::vector< std::vector< Real > > &frontDValues , + bool copyTopology + ) { if( maxKeyDepth(); typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator = NULL; - if( data ) pointEvaluator = new typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >( tree._maxDepth ); + if constexpr( HasData ) if( data ) pointEvaluator = new typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >( tree._maxDepth ); DenseNodeData< Real , UIntPack< FEMSigs ... > > coarseCoefficients( tree._sNodesEnd( tree._maxDepth-1 ) ); memset( coarseCoefficients() , 0 , sizeof(Real)*tree._sNodesEnd( tree._maxDepth-1 ) ); ThreadPool::Parallel_for( tree._sNodesBegin(0) , tree._sNodesEnd( tree._maxDepth-1 ) , [&]( unsigned int, size_t i ){ coarseCoefficients[i] = coefficients[i]; } ); @@ -2002,7 +2070,7 @@ public: { LocalDepth d ; unsigned int o; - const typename LevelSetExtractor< Dim-1 , Real , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *boundary = NULL; + const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *boundary = NULL; const std::vector< std::pair< node_index_type , node_index_type > > *incidence = NULL; const std::vector< std::vector< Real > > *dValues = NULL; if ( sliceAtMaxDepth==slabStartAtMaxDepth ) boundary = backBoundary , incidence = &backIncidence , dValues = & backDValues; @@ -2049,7 +2117,7 @@ public: { LocalDepth d ; unsigned int o; - const typename LevelSetExtractor< Dim-1 , Real , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *boundary = NULL; + const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *boundary = NULL; const std::vector< std::pair< node_index_type , node_index_type > > *incidence = NULL; const std::vector< std::vector< Real > > *dValues = NULL; if ( sliceAtMaxDepth==slabStartAtMaxDepth ) boundary = backBoundary , incidence = &backIncidence , dValues = & backDValues; @@ -2069,7 +2137,7 @@ public: if( !SetCoarseSlice( sliceAtMaxDepth , depth , slice ) ) ERROR_OUT( "Could not set coarse slice" ); return slabValues[depth].sliceScratch( slice ); }; - CopyIsoStructure< WeightDegree , Data , DataSig >( keyGenerator , *boundary , tree , fullDepth , sliceAtMaxDepth , maxDepth , sliceFunctor , scratchFunctor , *incidence , mesh , gradientNormals , pointEvaluator , densityWeights , data , vertexOffset , zeroData , SetVertex ); + CopyIsoStructure< WeightDegree , DataSig >( keyGenerator , *boundary , tree , fullDepth , sliceAtMaxDepth , maxDepth , sliceFunctor , scratchFunctor , *incidence , vertexStream , gradientNormals , pointEvaluator , densityWeights , data , vertexOffset , zeroData ); } else { @@ -2080,7 +2148,7 @@ public: { if( d<=tree._maxDepth ) { - SetSliceIsoVertices< WeightDegree , Data , DataSig >( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , d , fullDepth , o , vertexOffset , mesh , slabValues , zeroData , SetVertex ); + SetSliceIsoVertices< WeightDegree , DataSig >( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , d , fullDepth , o , vertexOffset , vertexStream , slabValues , zeroData ); } if( o&1 ) break; } @@ -2119,7 +2187,7 @@ public: // Set the iso-vertices Real bCoordinate , fCoordinate; SetSlabBounds( d , o , bCoordinate , fCoordinate ); - SetXSliceIsoVertices< WeightDegree , Data , DataSig >( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , d , std::max< unsigned int >( slabDepth , fullDepth ) , o , bCoordinate , fCoordinate , vertexOffset , mesh , slabValues , zeroData , SetVertex ); + SetXSliceIsoVertices< WeightDegree , DataSig >( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , d , std::max< unsigned int >( slabDepth , fullDepth ) , o , bCoordinate , fCoordinate , vertexOffset , vertexStream , slabValues , zeroData ); } } @@ -2177,7 +2245,7 @@ public: else if( dir==HyperCube::FRONT && ( (((unsigned int)offset[Dim-1]+1)<<(maxDepth-depth))> slabEndAtMaxDepth ) ) key[Dim-1] = keyGenerator.cornerIndex( maxDepth , slabEndAtMaxDepth ); return key; }; - if( InteriorSlab( d , o ) ) SetLevelSet( keyGenerator , faceIndexFunctor , tree , d , o , slabValues[d].sliceValues(o) , slabValues[d].sliceValues(o+1) , slabValues[d].xSliceValues(o) , slabValues[d].sliceScratch(o) , slabValues[d].sliceScratch(o+1) , slabValues[d].xSliceScratch(o) , mesh , polygonMesh , addBarycenter , vertexOffset , flipOrientation ); + if( InteriorSlab( d , o ) ) SetLevelSet( keyGenerator , faceIndexFunctor , tree , d , o , slabValues[d].sliceValues(o) , slabValues[d].sliceValues(o+1) , slabValues[d].xSliceValues(o) , slabValues[d].sliceScratch(o) , slabValues[d].sliceScratch(o+1) , slabValues[d].xSliceScratch(o) , vertexStream , polygonStream , polygonMesh , addBarycenter , vertexOffset , flipOrientation ); } if( !(o&1) && !boundary ) break; } @@ -2219,5 +2287,70 @@ public: return stats; } }; -template< class Real , class Vertex > std::mutex LevelSetExtractor< 3 , Real , Vertex >::_pointInsertionMutex; -template< class Real , class Vertex > std::atomic< size_t > LevelSetExtractor< 3 , Real , Vertex >::_BadRootCount; + +template< bool HasData , typename Real , typename Data > std::mutex _LevelSetExtractor< HasData , Real , 3 , Data >::_pointInsertionMutex; +template< bool HasData , typename Real , typename Data > std::atomic< size_t > _LevelSetExtractor< HasData , Real , 3 , Data >::_BadRootCount; + +template< typename Real > +struct LevelSetExtractor< Real , 3 > +{ + static const unsigned int Dim = 3; + static const bool HasData = false; + typedef unsigned char Data; + typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::Stats Stats; + typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::Vertex Vertex; + typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::TreeNode TreeNode; + template< unsigned int WeightDegree > using DensityEstimator = typename _LevelSetExtractor< HasData , Real , Dim , Data >::template DensityEstimator< WeightDegree >; + + template< unsigned int WeightDegree , unsigned int ... FEMSigs > + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree > *densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputDataStream< Vertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) + { + return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , tree , densityWeights , coefficients , isoValue , 0 , 0 , 1 , vertexStream , polygonStream , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation ); + } + + template< unsigned int WeightDegree , unsigned int ... FEMSigs > + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputDataStream< Vertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) + { + std::vector< std::vector< Real > > dValues; + return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , tree , tree._maxDepth , densityWeights , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , NULL , NULL , dValues , dValues , false ); + } + + template< unsigned int WeightDegree , unsigned int ... FEMSigs > + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , int maxKeyDepth , const DensityEstimator< WeightDegree >* densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputDataStream< Vertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *backBoundary , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *frontBoundary , const std::vector< std::vector< Real > > &backDValues , const std::vector< std::vector< Real > > &frontDValues , bool copyTopology ) + { + static const unsigned int DataSig = FEMDegreeAndBType< 0 , BOUNDARY_FREE >::Signature; + const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data = NULL; + Data zeroData = 0; + return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , backBoundary , frontBoundary , backDValues , frontDValues , copyTopology ); + } +}; + +template< typename Real , typename Data > +struct LevelSetExtractor< Real , 3 , Data > +{ + static const unsigned int Dim = 3; + static const bool HasData = true; + typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::Stats Stats; + typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::Vertex Vertex; + typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::TreeNode TreeNode; + template< unsigned int WeightDegree > using DensityEstimator = typename _LevelSetExtractor< HasData , Real , Dim , Data >::template DensityEstimator< WeightDegree >; + + template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputDataStream< Vertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) + { + return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , 0 , 0 , 1 , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation ); + } + + template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputDataStream< Vertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) + { + std::vector< std::vector< Real > > dValues; + return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , tree._maxDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , NULL , NULL , dValues , dValues , false ); + } + + template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , int maxKeyDepth , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputDataStream< Vertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *backBoundary , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *frontBoundary , const std::vector< std::vector< Real > > &backDValues , const std::vector< std::vector< Real > > &frontDValues , bool copyTopology ) + { + return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , backBoundary , frontBoundary , backDValues , frontDValues , copyTopology ); + } +}; diff --git a/Src/FEMTree.h b/Src/FEMTree.h index a32d13b6..681875f6 100644 --- a/Src/FEMTree.h +++ b/Src/FEMTree.h @@ -49,7 +49,7 @@ DAMAGE. #include "MyMiscellany.h" #include "BSplineData.h" #include "Geometry.h" -#include "VertexStream.h" +#include "DataStream.h" #include "RegularTree.h" #include "SparseMatrix.h" #include "BlockedVector.h" @@ -1333,7 +1333,11 @@ template< unsigned int Dim > inline void SetGhostFlag( RegularTreeNode< Di template< unsigned int Dim > inline bool GetGhostFlag( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ){ return node==NULL || node->parent==NULL || node->parent->nodeData.getGhostFlag( ); } template< unsigned int Dim > inline bool IsActiveNode( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ){ return !GetGhostFlag( node ); } -template< unsigned int Dim , class Real , class Vertex > struct LevelSetExtractor; +// A class representing an extractot with and without auxiliary data +template< typename Real , unsigned int Dim , typename ... Params > struct LevelSetExtractor; + +// A helper class which consolidates the two extractors, templated over HasData +template< bool HasData , typename Real , unsigned int Dim , typename Data > struct _LevelSetExtractor; template< unsigned int Dim , class Data > struct NodeSample @@ -1417,7 +1421,9 @@ class FEMTree int &_depthOffset , _depthOffsetValue; }; - template< unsigned int _Dim , class _Real , class Vertex > friend struct LevelSetExtractor; + // Don't need this first one + template< typename _Real , unsigned int _Dim , typename ... _Params > friend struct LevelSetExtractor; + template< bool _HasData , typename _Real , unsigned int _Dim , typename _Data > friend struct _LevelSetExtractor; std::atomic< node_index_type > _nodeCount; struct _NodeInitializer { @@ -2545,6 +2551,11 @@ class FEMTree template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data > void updateExtrapolatedDataField( SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > &dataField , const std::vector< PointSample >& samples , const std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density , bool nearest=false ); + template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data , class SampleFunctor /* = std::function< const PointSample & (size_t) >*/ , class SampleDataFunctor /* = std::function< const Data & (size_t) > */ > + SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > setExtrapolatedDataField( size_t sampleNum , SampleFunctor sampleFunctor , SampleDataFunctor sampleDataFunctor , const DensityEstimator< DensityDegree >* density , bool nearest=false ); + template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data , class SampleFunctor /* = std::function< const PointSample & (size_t) >*/ , class SampleDataFunctor /* = std::function< const Data & (size_t) > */ > + void updateExtrapolatedDataField( SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > &dataField , size_t sampleNum , SampleFunctor sampleFunctor , SampleDataFunctor sampleDataFunctor , const DensityEstimator< DensityDegree >* density , bool nearest=false ); + template< unsigned int MaxDegree , unsigned int SystemDegree , typename AddNodeFunctor , typename HasDataFunctor , typename IsDirichletLeafFunctor , typename ... InterpolationInfos , typename ... DenseOrSparseNodeData > std::vector< node_index_type > finalizeForMultigridWithDirichlet( LocalDepth baseDepth , const AddNodeFunctor addNodeFunctor , const HasDataFunctor hasDataFunctor , const IsDirichletLeafFunctor isDirichletLeafFunctor , std::tuple< InterpolationInfos *... > interpolationInfos , std::tuple< DenseOrSparseNodeData *... > data ); template< unsigned int MaxDegree , unsigned int SystemDegree , typename AddNodeFunctor , typename HasDataFunctor , typename IsDirichletLeafFunctor , typename ... InterpolationInfos > std::vector< node_index_type > finalizeForMultigridWithDirichlet( LocalDepth baseDepth , const AddNodeFunctor addNodeFunctor , const HasDataFunctor hasDataFunctor , const IsDirichletLeafFunctor isDirichletLeafFunctor , std::tuple< InterpolationInfos *... > interpolationInfos ){ return finalizeForMultigridWithDirichlet< MaxDegree , SystemDegree , AddNodeFunctor , HasDataFunctor >( baseDepth , addNodeFunctor , hasDataFunctor , isDirichletLeafFunctor , interpolationInfos , std::make_tuple() ); } @@ -2908,62 +2919,6 @@ class FEMTree template< typename T , typename TDotT , unsigned int ... FEMSigs1 , unsigned int ... FEMSigs2 , class Coefficients1 , class Coefficients2 > double _interpolationDot( UIntPack< FEMSigs1 ... > , UIntPack< FEMSigs2 ... > , const Coefficients1& coefficients1 , const Coefficients2& coefficients2 , TDotT Dot ) const{ return 0; } }; -template< unsigned int Dim , class Real , class Vertex > -struct LevelSetExtractor -{ - struct Stats - { - std::string toString( void ) const { return std::string( "Level-set extraction not supported for dimension %d" , Dim ); } - }; - - template< typename Data , typename SetVertexFunction , unsigned int ... FEMSigs , unsigned int WeightDegree , unsigned int DataSig > - static Stats Extract - ( - UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , // Dummy variables for grouping the parameter - const FEMTree< Dim , Real >& tree , // The tree over which the system is discretized - const typename FEMTree< Dim , Real >::template DensityEstimator< WeightDegree >* densityWeights , // Density weights - const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , // Auxiliary spatial data - const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , // The coefficients of the function - Real isoValue , // The value at which to extract the level-set - unsigned int slabDepth , // The depth at which the slabs are specified - unsigned int slabStart , // The beginning slab - unsigned int slabEnd , // The ending slab - StreamingMesh< Vertex , node_index_type >& mesh , // The mesh in which to store the output - const Data &zeroData , // Zero value for data (in case of dynamic allocation) - const SetVertexFunction &SetVertex , // A function for setting the depth and data of a vertex - bool nonLinearFit , // Should a linear interpolant be used - bool gradientNormals , // Compute the gradient at the iso-vertex position - bool addBarycenter , // Should we triangulate polygons by adding a mid-point - bool polygonMesh , // Should we output triangles or polygons - bool flipOrientation // Should we flip the orientation - ) - { - // The unspecialized implementation is not supported - WARN( "Level-set extraction not supported for dimension " , Dim ); - return Stats(); - } - template< typename Data , typename SetVertexFunction , unsigned int ... FEMSigs , unsigned int WeightDegree , unsigned int DataSig > - static Stats Extract - ( - UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , // Dummy variables for grouping the parameter - const FEMTree< Dim , Real >& tree , // The tree over which the system is discretized - const typename FEMTree< Dim , Real >::template DensityEstimator< WeightDegree >* densityWeights , // Density weights - const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , // Auxiliary spatial data - const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , // The coefficients of the function - Real isoValue , // The value at which to extract the level-set - StreamingMesh< Vertex , node_index_type >& mesh , // The mesh in which to store the output - const Data &zeroData , // Zero value for data (in case of dynamic allocation) - const SetVertexFunction &SetVertex , // A function for setting the depth and data of a vertex - bool nonLinearFit , // Should a linear interpolant be used - bool gradientNormals , // Compute the gradient at the iso-vertex position - bool addBarycenter , // Should we triangulate polygons by adding a mid-point - bool polygonMesh , // Should we output triangles or polygons - bool flipOrientation // Should we flip the orientation - ) - { - return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , 0 , 0 , 1 , mesh , zeroData , SetVertex , nonLinearFit , gradientNormals , addBarycenter , polygonMesh , flipOrientation ); - } -}; template< unsigned int Dim , class Real > struct FEMTreeInitializer @@ -2998,7 +2953,7 @@ struct FEMTreeInitializer PointAndDataType p; p.template get<1>() = d; for( unsigned int d=0 ; d::infinity() , max[d] = -std::numeric_limits< Real >::infinity(); - while( stream.next( p ) ) for( unsigned int d=0 ; d( min[d] , p.template get<0>()[d] ) , max[d] = std::max< Real >( max[d] , p.template get<0>()[d] ); + while( stream.read( p ) ) for( unsigned int d=0 ; d( min[d] , p.template get<0>()[d] ) , max[d] = std::max< Real >( max[d] , p.template get<0>()[d] ); stream.reset(); } }; @@ -3022,8 +2977,6 @@ struct FEMTreeInitializer std::vector< node_index_type > _nodeToIndexMap; }; - template< typename Data > - static size_t Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , typename InputPointStream< Data >::StreamType &pointStream , Data zeroData , int maxDepth , std::vector< PointSample >& samplePoints , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); template< typename Data > static size_t Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , typename InputPointStream< Data >::StreamType &pointStream , Data zeroData , int maxDepth , std::vector< PointSample >& samplePoints , std::vector< typename InputPointStream< Data >::DataType > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , typename InputPointStream< Data >::DataType & ) > ProcessData = []( const Point< Real , Dim > & , typename InputPointStream< Data >::DataType & ){ return (Real)1.; } ); template< typename Data > diff --git a/Src/FEMTree.inl b/Src/FEMTree.inl index 053df209..6d87802a 100644 --- a/Src/FEMTree.inl +++ b/Src/FEMTree.inl @@ -1069,13 +1069,28 @@ template< unsigned int Dim , class Real > template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data > SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > FEMTree< Dim , Real >::setExtrapolatedDataField( const std::vector< PointSample >& samples , const std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density , bool nearest ) { - SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > dataField; - this->template updateExtrapolatedDataField< DataSig , CreateNodes >( dataField , samples , sampleData , density , nearest ); - return dataField; + return this->template setExtrapolatedDataField< DataSig , CreateNodes , DensityDegree , Data >( samples.size() , [&]( size_t i ) -> const PointSample & { return samples[i]; } , [&]( size_t i ) -> const Data & { return sampleData[i]; } , density , nearest ); } + template< unsigned int Dim , class Real > template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data > void FEMTree< Dim , Real >::updateExtrapolatedDataField( SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > &dataField , const std::vector< PointSample >& samples , const std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density , bool nearest ) +{ + return this->template updateExtrapolatedDataField< DataSig , CreateNodes , DensityDegree , Data >( dataField , samples.size() , [&]( size_t i ) -> const PointSample & { return samples[i]; } , [&]( size_t i ) -> const Data & { return sampleData[i]; } , density , nearest ); +} + +template< unsigned int Dim , class Real > +template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data , class SampleFunctor /* = std::function< const PointSample & (size_t) >*/ , class SampleDataFunctor /* = std::function< const Data & (size_t) > */ > +SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > FEMTree< Dim , Real >::setExtrapolatedDataField( size_t sampleNum , SampleFunctor sampleFunctor , SampleDataFunctor sampleDataFunctor , const DensityEstimator< DensityDegree >* density , bool nearest ) +{ + SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > dataField; + this->template updateExtrapolatedDataField< DataSig , CreateNodes , DensityDegree , Data >( dataField , sampleNum , sampleFunctor , sampleDataFunctor , density , nearest ); + return dataField; +} + +template< unsigned int Dim , class Real > +template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data , class SampleFunctor /* = std::function< const PointSample & (size_t) >*/ , class SampleDataFunctor /* = std::function< const Data & (size_t) > */ > +void FEMTree< Dim , Real >::updateExtrapolatedDataField( SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > &dataField , size_t sampleNum , SampleFunctor sampleFunctor , SampleDataFunctor sampleDataFunctor , const DensityEstimator< DensityDegree >* density , bool nearest ) { Allocator< FEMTreeNode > *nodeAllocator = nodeAllocators.size() ? nodeAllocators[0] : NULL; LocalDepth maxDepth = _spaceRoot->maxDepth(); @@ -1083,18 +1098,19 @@ void FEMTree< Dim , Real >::updateExtrapolatedDataField( SparseNodeData< Project PointSupportKey< IsotropicUIntPack< Dim , FEMSignature< DataSig >::Degree > > dataKey; densityKey.set( _localToGlobal( maxDepth ) ) , dataKey.set( _localToGlobal( maxDepth ) ); - for( node_index_type i=0 ; i<(node_index_type)samples.size() ; i++ ) + for( node_index_type i=0 ; i<(node_index_type)sampleNum ; i++ ) { - const ProjectiveData< Point< Real , Dim > , Real >& sample = samples[i].sample; - const Data& data = sampleData[i]; + const PointSample &sampleAndNode = sampleFunctor(i); + const ProjectiveData< Point< Real , Dim > , Real >& sample = sampleAndNode.sample; + const Data& data = sampleDataFunctor(i); Point< Real , Dim > p = sample.weight==0 ? sample.data : sample.data / sample.weight; if( !_InBounds(p) ) { WARN( "Point is out of bounds" ); continue; } - if( nearest ) _nearestMultiSplatPointData< DensityDegree >( density , (FEMTreeNode*)samples[i].node , p , ProjectiveData< Data , Real >( data , sample.weight ) , dataField , densityKey , 2 ); - else _multiSplatPointData< CreateNodes , false , DensityDegree >( nodeAllocator , density , (FEMTreeNode*)samples[i].node , p , ProjectiveData< Data , Real >( data , sample.weight ) , dataField , densityKey , dataKey , 2 ); + if( nearest ) _nearestMultiSplatPointData< DensityDegree >( density , (FEMTreeNode*)sampleAndNode.node , p , ProjectiveData< Data , Real >( data , sample.weight ) , dataField , densityKey , 2 ); + else _multiSplatPointData< CreateNodes , false , DensityDegree >( nodeAllocator , density , (FEMTreeNode*)sampleAndNode.node , p , ProjectiveData< Data , Real >( data , sample.weight ) , dataField , densityKey , dataKey , 2 ); } } diff --git a/Src/Geometry.h b/Src/Geometry.h index 9e1f6903..2748620f 100644 --- a/Src/Geometry.h +++ b/Src/Geometry.h @@ -391,8 +391,13 @@ struct XForm XForm( void ) { memset( coords , 0 , sizeof(Real) * Dim * Dim ); } XForm( const Matrix< Real , Dim , Dim > &M ){ memcpy( coords , M.coords , sizeof(Real)*Dim*Dim ); } XForm( const XForm &M ){ memcpy( coords , M.coords , sizeof(Real)*Dim*Dim ); } - XForm operator = ( const Matrix< Real , Dim , Dim > &M ){ memcpy( coords , M.coords , sizeof(Real)*Dim*Dim ) ; return *this; } - XForm operator = ( const XForm< Real , Dim > &M ){ memcpy( coords , M.coords , sizeof(Real)*Dim*Dim ) ; return *this; } + XForm( const Matrix< Real , Dim+1 , Dim+1 > &M ){ for( unsigned int i=0 ; ioperator()(i,j) = M(i,j); } + XForm( const XForm< Real , Dim+1 > &M ){ for( unsigned int i=0 ; ioperator()(i,j) = M(i,j); } + XForm &operator = ( const Matrix< Real , Dim , Dim > &M ){ memcpy( coords , M.coords , sizeof(Real)*Dim*Dim ) ; return *this; } + XForm &operator = ( const XForm< Real , Dim > &M ){ memcpy( coords , M.coords , sizeof(Real)*Dim*Dim ) ; return *this; } + XForm &operator = ( const Matrix< Real , Dim+1 , Dim+1> &M ){ for( unsigned int i=0 ; ioperator()(i,j) = M(i,j) ; return *this; } + XForm &operator = ( const XForm< Real , Dim+1 > &M ){ for( unsigned int i=0 ; ioperator()(i,j) = M(i,j) ; return *this; } + static XForm Identity( void ) { XForm xForm; diff --git a/Src/MyMiscellany.h b/Src/MyMiscellany.h index c225694f..17170104 100644 --- a/Src/MyMiscellany.h +++ b/Src/MyMiscellany.h @@ -331,6 +331,49 @@ inline void SignalHandler( int signal ) template< typename Value > bool SetAtomic( volatile Value *value , Value newValue , Value oldValue ); template< typename Data > void AddAtomic( Data& a , Data b ); +////////////////////////////////// +// File-backed streaming memory // +////////////////////////////////// +#include "Array.h" +class FileBackedReadWriteStream +{ +public: + struct FileDescription + { + FILE *fp; + char fileName[2048]; + + FileDescription( void ) : fp(NULL) { fileName[0] = 0; } + FileDescription( const FileDescription &fd ) : fp(fd.fp) { strcpy( fileName , fd.fileName ); } + FileDescription( FILE *fp ) : fp(fp) { fileName[0] = 0; } + FileDescription( const char *fileHeader ) : fp(NULL) + { + if( fileHeader && strlen(fileHeader) ) sprintf( fileName , "%sXXXXXX" , fileHeader ); + else strcpy( fileName , "XXXXXX" ); +#ifdef _WIN32 + _mktemp( fileName ); + fp = fopen( fileName , "w+b" ); +#else // !_WIN32 + fp = fdopen( mkstemp( fileName ) , "w+b" ); +#endif // _WIN32 + if( !fp ) ERROR_OUT( "Failed to open file: " , fileName ); + } + void remove( void ){ if( fp ){ fclose( fp ) ; fp = NULL ; std::remove( fileName ); } } + }; + + FileBackedReadWriteStream( const char* fileHeader="" ) : _fd( fileHeader ) , _fileHandleOwner(true) {} + FileBackedReadWriteStream( FILE *fp ) : _fd(fp) , _fileHandleOwner(false) {} + ~FileBackedReadWriteStream( void ){ if( _fileHandleOwner ) _fd.remove(); } + bool write( ConstPointer(char) data , size_t size ){ return fwrite( data , sizeof(char) , size , _fd.fp )==size; } + bool read( Pointer(char) data , size_t size ){ return fread( data , sizeof(char) , size , _fd.fp )==size; } + void reset( void ){ fseek( _fd.fp , 0 , SEEK_SET ); } +protected: + bool _fileHandleOwner; + FileDescription _fd; +}; + + + //////////////////// // MKThread Stuff // //////////////////// diff --git a/Src/Ply.h b/Src/Ply.h index 27d37a56..4818edf1 100644 --- a/Src/Ply.h +++ b/Src/Ply.h @@ -53,7 +53,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "PlyFile.h" #include "Geometry.h" -#include "StreamingMesh.h" +#include "DataStream.h" #include "MyMiscellany.h" #include "Array.h" @@ -92,7 +92,7 @@ namespace PLY // PLY write mesh functionality template< typename VertexFactory , typename Index , class Real , int Dim , typename OutputIndex=int , bool UseCharIndex=false > - void WritePolygons( std::string fileName , const VertexFactory &vFactory , StreamingMesh< typename VertexFactory::VertexType , Index > *mesh , int file_type , const std::vector< std::string >& comments , std::function< void ( typename VertexFactory::VertexType & ) > xForm = []( typename VertexFactory::VertexType &v ){} ); + void WritePolygons( std::string fileName , const VertexFactory &vFactory , size_t vertexNum , size_t polygonNum , InputDataStream< typename VertexFactory::VertexType > &vertexStream , InputDataStream< std::vector< Index > > &polygonStream , int file_type , const std::vector< std::string >& comments ); template< typename VertexFactory , typename Index , bool UseCharIndex=false > void WritePolygons( std::string fileName , const VertexFactory &vFactory , const std::vector< typename VertexFactory::VertexType > &vertices , const std::vector< std::vector< Index > > &polygons , int file_type , const std::vector< std::string > &comments ); diff --git a/Src/Ply.inl b/Src/Ply.inl index 18b12ac5..a5a37171 100644 --- a/Src/Ply.inl +++ b/Src/Ply.inl @@ -321,33 +321,32 @@ namespace PLY } template< typename VertexFactory , typename Index , class Real , int Dim , typename OutputIndex , bool UseCharIndex > - void WritePolygons( std::string fileName , const VertexFactory &vFactory , StreamingMesh< typename VertexFactory::VertexType , Index >* mesh , int file_type , const std::vector< std::string > &comments , std::function< void ( typename VertexFactory::VertexType & ) > xForm ) + void WritePolygons( std::string fileName , const VertexFactory &vFactory , size_t vertexNum , size_t polygonNum , InputDataStream< typename VertexFactory::VertexType > &vertexStream , InputDataStream< std::vector< Index > > &polygonStream , int file_type , const std::vector< std::string > &comments ) { - if( mesh->vertexNum()>(size_t)std::numeric_limits< OutputIndex >::max() ) + if( vertexNum>(size_t)std::numeric_limits< OutputIndex >::max() ) { if( std::is_same< Index , OutputIndex >::value ) ERROR_OUT( "more vertices than can be represented using " , Traits< Index >::name ); WARN( "more vertices than can be represented using " , Traits< OutputIndex >::name , " using " , Traits< Index >::name , " instead" ); - return WritePolygons< VertexFactory , Index , Real , Dim , Index >( fileName , vFactory , mesh , file_type , comments , xForm ); + return WritePolygons< VertexFactory , Index , Real , Dim , Index >( fileName , vFactory , vertexNum , polygonNum , vertexStream , polygonStream , file_type , comments ); } - size_t nr_vertices = mesh->vertexNum(); - size_t nr_faces = mesh->polygonNum(); float version; std::vector< std::string > elem_names = { std::string( "vertex" ) , std::string( "face" ) }; PlyFile *ply = PlyFile::Write( fileName , elem_names , file_type , version ); if( !ply ) ERROR_OUT( "Could not create ply file for writing: " , fileName ); - mesh->resetIterator(); + vertexStream.reset(); + polygonStream.reset(); // // describe vertex and face properties // - ply->element_count( "vertex" , nr_vertices ); + ply->element_count( "vertex" , vertexNum ); for( unsigned int i=0 ; idescribe_property( "vertex" , &prop ); } - ply->element_count( "face" , nr_faces ); + ply->element_count( "face" , polygonNum ); ply->describe_property( "face" , Face< OutputIndex , UseCharIndex >::Properties ); // Write in the comments @@ -358,38 +357,36 @@ namespace PLY ply->put_element_setup( "vertex" ); if( vFactory.isStaticallyAllocated() ) { - for( size_t i=0; ivertexNum() ; i++ ) + for( size_t i=0; inextVertex( vertex ); - xForm( vertex ); + if( !vertexStream.read( vertex ) ) ERROR_OUT( "Failed to read vertex " , i , " / " , vertexNum ); ply->put_element( (void *)&vertex ); } } else { Pointer( char ) buffer = NewPointer< char >( vFactory.bufferSize() ); - for( size_t i=0; ivertexNum() ; i++ ) + for( size_t i=0; inextVertex( vertex ); - xForm( vertex ); + if( !vertexStream.read( vertex ) ) ERROR_OUT( "Failed to read vertex " , i , " / " , vertexNum ); vFactory.toBuffer( vertex , buffer ); ply->put_element( PointerAddress( buffer ) ); } DeletePointer( buffer ); } - // write faces + // write faces std::vector< Index > polygon; ply->put_element_setup( "face" ); - for( size_t i=0 ; i ply_face; - mesh->nextPolygon( polygon ); + if( !polygonStream.read( polygon ) ) ERROR_OUT( "Failed to read polygon " , i , " / " , polygonNum ); ply_face.nr_vertices = int( polygon.size() ); ply_face.vertices = new OutputIndex[ polygon.size() ]; for( int j=0 ; j InValues( "inValues" ) , @@ -63,7 +64,6 @@ cmdLineReadable PrimalGrid( "primalGrid" ) , ExactInterpolation( "exact" ) , InCore( "inCore" ) , - NoComments( "noComments" ) , PolygonMesh( "polygonMesh" ) , NonManifold( "nonManifold" ) , NonLinearFit( "nonLinearFit" ) , @@ -113,7 +113,7 @@ cmdLineReadable* params[] = &InValues , &InGradients , &Out , &Depth , &Transform , &Width , - &Scale , &Verbose , &CGSolverAccuracy , &NoComments , + &Scale , &Verbose , &CGSolverAccuracy , &NonManifold , &PolygonMesh , &ASCII , &ShowResidual , &ValueWeight , &GradientWeight , &LapWeight , &BiLapWeight , @@ -173,8 +173,6 @@ void ShowUsage(char* ex) printf( "\t[--%s =%f]\n" , IsoValue.name , IsoValue.value ); printf( "\t[--%s]\n" , Performance.name ); printf( "\t[--%s]\n" , PrimalGrid.name ); - printf( "\t[--%s]\n" , NoComments.name ); - printf( "\t[--%s]\n" , PolygonMesh.name ); printf( "\t[--%s]\n" , NonManifold.name ); printf( "\t[--%s]\n" , NonLinearFit.name ); printf( "\t[--%s]\n" , ASCII.name ); @@ -329,17 +327,15 @@ struct SystemDual< Dim , double , VectorTypeUnion< double , Point< double , Dim } }; -template< typename Real , typename SetVertexFunction , typename VertexFactory , unsigned int ... FEMSigs > +template< typename Real , unsigned int ... FEMSigs > void ExtractMesh ( UIntPack< FEMSigs ... > , FEMTree< sizeof ... ( FEMSigs ) , Real >& tree , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& solution , Real isoValue , - const VertexFactory &vertexFactory , - SetVertexFunction SetVertex , - std::vector< std::string > &comments , - XForm< Real , sizeof...(FEMSigs)+1 > unitCubeToModel + XForm< Real , sizeof...(FEMSigs)+1 > unitCubeToModel , + std::vector< std::string > &comments ) { static const int Dim = sizeof ... ( FEMSigs ); @@ -359,33 +355,38 @@ void ExtractMesh else sprintf( tempHeader , "%s%cPR_" , tempPath , FileSeparator ); } - typedef EmptyVectorType< Real > EmptyVectorType; - StreamingMesh< typename VertexFactory::VertexType , node_index_type > *mesh; - if( InCore.set ) mesh = new VectorStreamingMesh< typename VertexFactory::VertexType , node_index_type >(); - else mesh = new FileStreamingMesh< VertexFactory , node_index_type >( vertexFactory , tempHeader ); - profiler.reset(); - typename LevelSetExtractor< Dim , Real , typename VertexFactory::VertexType >::Stats stats; -#if defined( __GNUC__ ) && __GNUC__ < 5 -#ifdef SHOW_WARNINGS -#warning "you've got me gcc version<5" -#endif // SHOW_WARNINGS - stats = LevelSetExtractor< Dim , Real , typename VertexFactory::VertexType >::template Extract< EmptyVectorType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , (typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE >*)NULL , (SparseNodeData< ProjectiveData< EmptyVectorType , Real > , IsotropicUIntPack< Dim , DataSig > > *)NULL , solution , isoValue , *mesh , EmptyVectorType() , SetVertex , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , false ); -#else // !__GNUC__ || __GNUC__ >=5 - stats = LevelSetExtractor< Dim , Real , typename VertexFactory::VertexType >::template Extract< EmptyVectorType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , (typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE >*)NULL , NULL , solution , isoValue , *mesh , EmptyVectorType() , SetVertex , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , false ); -#endif // __GNUC__ || __GNUC__ < 4 + // A description of the output vertex information + using VInfo = Reconstructor::OutputVertexInfo< Real , Dim , false , false >; + + // A factory generating the output vertices + using Factory = typename VInfo::Factory; + Factory factory = VInfo::GetFactory(); + + // A backing stream for the vertices + Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , false , false , std::string( "v_" ) ); + Reconstructor::OutputInputPolygonStream polygonStream( false , true , std::string( "p_" ) ); + typename LevelSetExtractor< Real , Dim >::Stats stats; + + { + // The wrapper converting native to output types + typename VInfo::StreamWrapper _vertexStream( vertexStream , factory() ); + Reconstructor::TransformedOutputVertexStream< Real , Dim > __vertexStream( unitCubeToModel , _vertexStream ); + + // Extract the mesh + stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< 0 >() , tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , solution , isoValue , __vertexStream , polygonStream , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , false ); + } + if( Verbose.set ) { - std::cout << "Vertices / Polygons: " << mesh->vertexNum() << " / " << mesh->polygonNum() << std::endl; + std::cout << "Vertices / Polygons: " << vertexStream.size() << " / " << polygonStream.size() << std::endl; std::cout << stats.toString() << std::endl; if( PolygonMesh.set ) std::cout << "# Got polygons: " << profiler << std::endl; else std::cout << "# Got triangles: " << profiler << std::endl; } + // Write the mesh to a .ply file std::vector< std::string > noComments; - typename VertexFactory::Transform unitCubeToModelTransform( unitCubeToModel ); - auto xForm = [&]( typename VertexFactory::VertexType &v ){ unitCubeToModelTransform.inPlace(v); }; - PLY::WritePolygons< VertexFactory , node_index_type , Real , Dim >( Out.value , vertexFactory , mesh , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , NoComments.set ? noComments : comments , xForm ); - delete mesh; + PLY::WritePolygons< Factory , node_index_type , Real , Dim >( Out.value , factory , vertexStream.size() , polygonStream.size() , vertexStream , polygonStream , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); } template< typename Real , unsigned int Dim > @@ -488,11 +489,49 @@ void Execute( UIntPack< FEMSigs ... > ) // The type of the input gradient typedef typename InputSampleGradientFactory::VertexType InputSampleGradientType; - typedef InputDataStream< InputSampleValueType > InputPointValueStream; - typedef TransformedInputDataStream< InputSampleValueType > XInputPointValueStream; - typedef InputDataStream< InputSampleGradientType > InputPointGradientStream; - typedef TransformedInputDataStream< InputSampleGradientType > XInputPointGradientStream; + typedef InputDataStream< InputSampleValueType > InputPointValueStream; + typedef InputDataStream< InputSampleGradientType > InputPointGradientStream; + struct XInputPointValueStream : public InputDataStream< InputSampleValueType > + { + InputDataStream< InputSampleValueType > &stream; + XForm< Real , Dim+1 > pointTransform; + XInputPointValueStream( InputDataStream< InputSampleValueType > &stream , XForm< Real , Dim+1 > modelToUnitCube ) : stream(stream) , pointTransform( modelToUnitCube ){} + bool base_read( InputSampleValueType &s ) + { + if( stream.read( s ) ){ s.template get<0>() = pointTransform * s.template get<0>() ; return true; } + else return false; + } + void reset( void ){ return stream.reset(); } + }; + struct XInputPointGradientStream : public InputDataStream< InputSampleGradientType > + { + // G(p) = F( A*p ) + // F(p+d) = F(p) + < \nabla F(p) , d > + // G(p+d) = F( A*p ) + < \nabla F(A*p) , A*d > + // = G(p) + < A^t * \nabla F(A*p) , d > + // => \nabla G(p) = A^t * \nabla F(A*p) + + InputDataStream< InputSampleGradientType > &stream; + XForm< Real , Dim+1 > pointTransform; + XForm< Real , Dim > gradientTransform; + XInputPointGradientStream( InputDataStream< InputSampleGradientType > &stream , XForm< Real , Dim+1 > modelToUnitCube ) : stream(stream) + { + pointTransform = modelToUnitCube; + gradientTransform = XForm< Real , Dim >( pointTransform ).inverse().transpose(); + } + bool base_read( InputSampleGradientType &s ) + { + if( stream.read( s ) ) + { + s.template get<0>() = pointTransform * s.template get<0>(); + s.template get<1>() = gradientTransform * s.template get<1>().template get<0>(); + return true; + } + else return false; + } + void reset( void ){ return stream.reset(); } + }; FunctionValueFactory functionValueFactory; FunctionGradientFactory functionGradientFactory; @@ -585,10 +624,10 @@ void Execute( UIntPack< FEMSigs ... > ) else if( !strcasecmp( ext , "ply" ) ) _pointValueStream = new PLYInputDataStream< InputSampleValueFactory>( InValues.value , inputSampleValueFactory ); else _pointValueStream = new ASCIIInputDataStream< InputSampleValueFactory>( InValues.value , inputSampleValueFactory ); InputSampleValueType s = inputSampleValueFactory(); - while( _pointValueStream->next( s ) ) inCorePointsAndValues.push_back( s ); + while( _pointValueStream->read( s ) ) inCorePointsAndValues.push_back( s ); delete _pointValueStream; - pointValueStream = new MemoryInputDataStream< InputSampleValueType >( inCorePointsAndValues.size() , &inCorePointsAndValues[0] ); + pointValueStream = new VectorBackedInputDataStream< InputSampleValueType >( inCorePointsAndValues ); } else { @@ -598,9 +637,7 @@ void Execute( UIntPack< FEMSigs ... > ) } delete[] ext; - typename InputSampleValueFactory::Transform _modelToUnitCube( modelToUnitCube ); - auto XFormFunctor = [&]( InputSampleValueType &p ){ _modelToUnitCube.inPlace( p ); }; - XInputPointValueStream _pointStream( XFormFunctor , *pointValueStream ); + XInputPointValueStream _pointStream( *pointValueStream , modelToUnitCube ); FunctionValueType s = functionValueFactory(); InputPointStreamInfo< Real , Dim , FunctionValueType >::BoundingBox( _pointStream , s , valueMin , valueMax ); } @@ -615,10 +652,10 @@ void Execute( UIntPack< FEMSigs ... > ) else if( !strcasecmp( ext , "ply" ) ) _pointGradientStream = new PLYInputDataStream< InputSampleGradientFactory>( InGradients.value , inputSampleGradientFactory ); else _pointGradientStream = new ASCIIInputDataStream< InputSampleGradientFactory>( InGradients.value , inputSampleGradientFactory ); InputSampleGradientType s = inputSampleGradientFactory(); - while( _pointGradientStream->next( s ) ) inCorePointsAndGradients.push_back( s ); + while( _pointGradientStream->read( s ) ) inCorePointsAndGradients.push_back( s ); delete _pointGradientStream; - pointGradientStream = new MemoryInputDataStream< InputSampleGradientType >( inCorePointsAndGradients.size() , &inCorePointsAndGradients[0] ); + pointGradientStream = new VectorBackedInputDataStream< InputSampleGradientType >( inCorePointsAndGradients ); } else { @@ -628,9 +665,7 @@ void Execute( UIntPack< FEMSigs ... > ) } delete[] ext; - typename InputSampleGradientFactory::Transform _modelToUnitCube( modelToUnitCube ); - auto XFormFunctor = [&]( InputSampleGradientType &p ){ _modelToUnitCube.inPlace( p ); }; - XInputPointGradientStream _pointStream( XFormFunctor , *pointGradientStream ); + XInputPointGradientStream _pointStream( *pointGradientStream , modelToUnitCube ); FunctionGradientType s = functionGradientFactory(); InputPointStreamInfo< Real , Dim , FunctionGradientType >::BoundingBox( _pointStream , s , gradientMin , gradientMax ); } @@ -667,9 +702,7 @@ void Execute( UIntPack< FEMSigs ... > ) if( ValueWeight.value>0 ) { valueSamples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); - typename InputSampleValueFactory::Transform _modelToUnitCube( modelToUnitCube ); - auto XFormFunctor = [&]( InputSampleValueType &p ){ _modelToUnitCube.inPlace( p ); }; - XInputPointValueStream _pointStream( XFormFunctor , *pointValueStream ); + XInputPointValueStream _pointStream( *pointValueStream , modelToUnitCube ); auto ProcessData = []( const Point< Real , Dim > &p , FunctionValueType &d ){ return (Real)1.; }; FunctionValueType zeroGradient = functionValueFactory(); typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; @@ -681,9 +714,7 @@ void Execute( UIntPack< FEMSigs ... > ) if( GradientWeight.value>0 ) { gradientSamples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); - typename InputSampleGradientFactory::Transform _modelToUnitCube( modelToUnitCube ); - auto XFormFunctor = [&]( InputSampleGradientType &p ){ _modelToUnitCube.inPlace( p ); }; - XInputPointGradientStream _pointStream( XFormFunctor , *pointGradientStream ); + XInputPointGradientStream _pointStream( *pointGradientStream , modelToUnitCube ); auto ProcessData = []( const Point< Real , Dim > &p , FunctionGradientType &d ){ return (Real)1.; }; FunctionGradientType zeroGradient = functionGradientFactory(); typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; @@ -854,9 +885,7 @@ void Execute( UIntPack< FEMSigs ... > ) { if constexpr ( Dim==3 ) { - typedef VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::EmptyFactory< Real > > VertexFactory; - std::function< void ( typename VertexFactory::VertexType & , Point< Real , Dim > , Point< Real , Dim > , Real , EmptyVectorType< Real > ) > SetVertex = []( typename VertexFactory::VertexType &v , Point< Real , Dim > p , Point< Real , Dim > , Real , EmptyVectorType< Real > ){ v.template get<0>() = p; }; - ExtractMesh( UIntPack< FEMSigs ... >() , tree , solution , (Real)IsoValue.value , VertexFactory() , SetVertex , comments , unitCubeToModel ); + ExtractMesh( UIntPack< FEMSigs ... >() , tree , solution , (Real)IsoValue.value , unitCubeToModel , comments ); } else if constexpr ( Dim==2 ) { @@ -887,7 +916,7 @@ void Execute( UIntPack< FEMSigs ... > ) DeletePointer( values ); std::vector< std::string > noComments; - PLY::WritePolygons( Out.value , VertexFactory() , vertices , polygons , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , NoComments.set ? noComments : comments ); + PLY::WritePolygons( Out.value , VertexFactory() , vertices , polygons , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); } } diff --git a/Src/PointPartition.h b/Src/PointPartition.h index a0c7c66a..5c25a7a0 100644 --- a/Src/PointPartition.h +++ b/Src/PointPartition.h @@ -35,7 +35,7 @@ DAMAGE. #include "Streams.h" #include "MyMiscellany.h" #include "Ply.h" -#include "VertexStream.h" +#include "DataStream.h" #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth #define BUFFER_IO (1<<14) // Buffer the points before reading/writing @@ -118,7 +118,7 @@ namespace PointPartition BufferedBinaryInputDataStream( const char *fileName , const InputFactory &factory , size_t bufferSize ); ~BufferedBinaryInputDataStream( void ); void reset( void ); - bool next( Data &d ); + bool base_read( Data &d ); protected: size_t _bufferSize , _current , _inBuffer , _elementSize; Pointer( char ) _buffer; @@ -134,7 +134,7 @@ namespace PointPartition BufferedBinaryOutputDataStream( const char *fileName , const OutputFactory &factory , size_t bufferSize ); ~BufferedBinaryOutputDataStream( void ); void reset( void ); - void next( const Data &d ); + void base_write( const Data &d ); protected: size_t _bufferSize , _current , _elementSize; Pointer( char ) _buffer; diff --git a/Src/PointPartition.inl b/Src/PointPartition.inl index a7302eac..9a4e4e11 100644 --- a/Src/PointPartition.inl +++ b/Src/PointPartition.inl @@ -595,7 +595,7 @@ void BufferedBinaryInputDataStream< InputFactory >::reset( void ) } template< typename InputFactory > -bool BufferedBinaryInputDataStream< InputFactory >::next( Data &d ) +bool BufferedBinaryInputDataStream< InputFactory >::base_read( Data &d ) { if( _current==_inBuffer ) { @@ -647,7 +647,7 @@ void BufferedBinaryOutputDataStream< OutputFactory >::reset( void ) } template< typename OutputFactory > -void BufferedBinaryOutputDataStream< OutputFactory >::next( const Data &d ) +void BufferedBinaryOutputDataStream< OutputFactory >::base_write( const Data &d ) { if( _current==_bufferSize ) { diff --git a/Src/PointPartitionClientServer.h b/Src/PointPartitionClientServer.h index 6bf719db..dc6ba771 100644 --- a/Src/PointPartitionClientServer.h +++ b/Src/PointPartitionClientServer.h @@ -34,6 +34,8 @@ DAMAGE. #include "Socket.h" #include "MyMiscellany.h" #include "CmdLineParser.h" +#include "VertexFactory.h" +#include "Reconstructors.h" namespace PointPartitionClientServer diff --git a/Src/PointPartitionClientServer.inl b/Src/PointPartitionClientServer.inl index 56e56536..ead7cfac 100644 --- a/Src/PointPartitionClientServer.inl +++ b/Src/PointPartitionClientServer.inl @@ -119,7 +119,7 @@ void _MergeSlabs( std::string inDir , std::string outDir , std::string header , { std::string inFileName = PointPartition::FileName( inDir , header , c , s , slabs , filesPerDir ); PointPartition::BufferedBinaryInputDataStream< Factory > inStream( inFileName.c_str() , factory , bufferSize ); - while( inStream.next( v ) ) outStream.next( v ); + while( inStream.read( v ) ) outStream.write( v ); } } } @@ -150,7 +150,7 @@ std::vector< size_t > _PartitionIntoSlabs( std::string in , std::string dir , st int slab = (int)floor( p[Dim-1] * slabs ); if( slab>=0 && slab<(int)slabs ) { - outStreams[slab]->next( v ); + outStreams[slab]->write( v ); slabSizes[slab]++; } else outOfRangeCount++; @@ -259,7 +259,7 @@ std::pair< PointPartition::PointSetInfo< Real , Dim > , PointPartition::Partitio Point< Real , Dim > bBox[2]; for( unsigned int d=0 ; d<3 ; d++ ) bBox[0][d] = e.extents[ PointPartition::Extent< Real >::Frames[idx][d] ].first , bBox[1][d] = e.extents[ PointPartition::Extent< Real >::Frames[idx][d] ].second; - pointSetInfo.modelToUnitCube = GetBoundingBoxXForm( bBox[0] , bBox[1] , clientPartitionInfo.scale ) * R; + pointSetInfo.modelToUnitCube = Reconstructor::GetBoundingBoxXForm( bBox[0] , bBox[1] , clientPartitionInfo.scale ) * R; } // Send the transformation to the clients diff --git a/Src/PoissonRecon.client.inl b/Src/PoissonRecon.client.inl index 61297e2b..5b9cdb14 100644 --- a/Src/PoissonRecon.client.inl +++ b/Src/PoissonRecon.client.inl @@ -29,21 +29,21 @@ DAMAGE. template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > struct Client { - typedef typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; - typedef typename FEMTree< Dim , Real >::template ApproximatePointInterpolationInfo< Real , 0 , ConstraintDual< Dim , Real > , SystemDual< Dim , Real > > ApproximatePointInterpolationInfo; + typedef typename FEMTree< Dim , Real >::template DensityEstimator< Reconstructor::WeightDegree > DensityEstimator; + typedef typename FEMTree< Dim , Real >::template ApproximatePointInterpolationInfo< Real , 0 , Reconstructor::Poisson::ConstraintDual< Dim , Real > , Reconstructor::Poisson::SystemDual< Dim , Real > > ApproximatePointInterpolationInfo; typedef IsotropicUIntPack< Dim , FEMDegreeAndBType< Degree , BType >::Signature > Sigs; typedef IsotropicUIntPack< Dim , Degree > Degrees; - typedef IsotropicUIntPack< Dim , FEMDegreeAndBType< NORMAL_DEGREE , DerivativeBoundary< BType , 1 >::BType >::Signature > NormalSigs; - static const unsigned int DataSig = FEMDegreeAndBType< DATA_DEGREE , BOUNDARY_FREE >::Signature; + typedef IsotropicUIntPack< Dim , FEMDegreeAndBType< Reconstructor::Poisson::NormalDegree , DerivativeBoundary< BType , 1 >::BType >::Signature > NormalSigs; + static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; typedef VertexFactory::DynamicFactory< Real > AuxDataFactory; + typedef typename AuxDataFactory::VertexType AuxData; typedef VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::Factory< Real , VertexFactory::NormalFactory< Real , Dim > , AuxDataFactory > > InputSampleFactory; typedef VertexFactory::Factory< Real , VertexFactory::NormalFactory< Real , Dim > , AuxDataFactory > InputSampleDataFactory; - typedef InputOrientedPointStreamInfo< Real , Dim , typename AuxDataFactory::VertexType > InputPointStreamInfo; - typedef typename InputPointStreamInfo::PointAndDataType InputSampleType; - typedef typename InputPointStreamInfo::DataType InputSampleDataType; + typedef VectorTypeUnion< Real , Point< Real , Dim > , typename AuxDataFactory::VertexType > InputSampleDataType; + typedef VectorTypeUnion< Real , Point< Real , Dim > , InputSampleDataType > InputSampleType; typedef InputDataStream< InputSampleType > InputPointStream; typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; - using BoundaryData = typename LevelSetExtractor< Dim-1 , Real , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions; + using BoundaryData = typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions; ~Client( void ); @@ -63,7 +63,7 @@ protected: DenseNodeData< Real , Sigs > _constraints; // Phases [3,5] DenseNodeData< Real , Sigs > _solution; // Phases [5,7] ApproximatePointInterpolationInfo *_iInfo; // Phases [3,5] - SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > _dataField; // Phases [3,7] + SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > > _auxDataField; // Phases [3,7] static std::pair< unsigned int , unsigned int > _PaddedRange( std::pair< unsigned int , unsigned int > range , unsigned int depth , unsigned int padSize ); @@ -75,17 +75,17 @@ protected: size_t subNodeCount; DenseNodeData< Real , Sigs > constraints; ApproximatePointInterpolationInfo iInfo; - SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > dataField; + SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > > auxDataField; }; struct _State5 { - using Data = ProjectiveData< InputSampleDataType , Real >; + using Data = ProjectiveData< AuxData , Real >; - _State5( void ) : dataField(NULL) , subNodes( NullPointer( FEMTreeNode ) ) {} + _State5( void ) : auxDataField(NULL) , subNodes( NullPointer( FEMTreeNode ) ) {} ~_State5( void ) { DeletePointer( subNodes ); - if( dataField ) delete dataField; + delete auxDataField; } struct BoundaryInfo @@ -99,7 +99,7 @@ protected: Pointer( FEMTreeNode ) subNodes; DenseNodeData< Real , Sigs > solution; - SparseNodeData< Data , IsotropicUIntPack< Dim , DataSig > > *dataField; + SparseNodeData< Data , IsotropicUIntPack< Dim , DataSig > > *auxDataField; std::pair< BoundaryInfo , BoundaryInfo > boundaryInfo; }; struct _State7 @@ -142,6 +142,9 @@ protected: template< typename _Real , unsigned int _Dim , BoundaryType _BType , unsigned int _Degree > friend void RunClient( std::vector< Socket > &serverSockets , unsigned int sampleMS ); + + template< bool HasGradients , bool HasDensity > + void _writeMeshWithData( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , _State7 &state7 , XForm< Real , Dim+1 > unitCubeToModel ); }; template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > @@ -484,13 +487,13 @@ void Client< Real , Dim , BType , Degree >::_process1( const ClientReconstructio // Read in the samples (and color data) { Timer timer; - auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , typename InputPointStreamInfo::DataType &d ) + auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , InputSampleDataType &d ) { Real l = (Real)Length( d.template get<0>() ); if( !l || !std::isfinite( l ) ) return (Real)-1.; return (Real)pow( l , clientReconInfo.confidence ); }; - auto ProcessData = []( const Point< Real , Dim > &p , typename InputPointStreamInfo::DataType &d ) + auto ProcessData = []( const Point< Real , Dim > &p , InputSampleDataType &d ) { Real l = (Real)Length( d.template get<0>() ); if( !l || !std::isfinite( l ) ) return (Real)-1.; @@ -498,7 +501,7 @@ void Client< Real , Dim , BType , Degree >::_process1( const ClientReconstructio return (Real)1.; }; - std::vector< PointPartition::BufferedBinaryInputDataStream< InputSampleFactory > * > pointStreams( endPaddedIndex - beginPaddedIndex , NULL ); + std::vector< InputDataStream< typename InputSampleFactory::VertexType > * > pointStreams( endPaddedIndex - beginPaddedIndex , NULL ); auto PointStreamFunctor = [&]( unsigned int idx ) { std::string fileName = PointPartition::FileName( clientReconInfo.header , idx , 1<::_process1( const ClientReconstructio for( unsigned int i=0 ; i<( endPaddedIndex - beginPaddedIndex ) ; i++ ) pointStreamThreads[i].join(); } - using MultiPointStream = MultiInputDataStream< PointPartition::BufferedBinaryInputDataStream< InputSampleFactory > , typename InputSampleFactory::VertexType >; + using MultiPointStream = MultiInputDataStream< typename InputSampleFactory::VertexType >; auto ProcessInteriorPointSlabs = [&]( typename FEMTreeInitializer< Dim , Real >::StreamInitializationData &sid , unsigned int start , unsigned int end ) { @@ -541,8 +544,8 @@ void Client< Real , Dim , BType , Degree >::_process1( const ClientReconstructio auto ProcessPointSlab = [&]( typename FEMTreeInitializer< Dim , Real >::StreamInitializationData &sid , unsigned int idx ) { - PointPartition::BufferedBinaryInputDataStream< InputSampleFactory > &pointStream = *pointStreams[idx-beginPaddedIndex]; - + InputDataStream< typename InputSampleFactory::VertexType > &pointStream = *pointStreams[idx-beginPaddedIndex]; + if( idx>=beginIndex && idx::_process1( const ClientReconstructio // Get the kernel density estimator { Timer timer; - _density = _tree.template setDensityEstimator< 1 , WEIGHT_DEGREE >( _samples , clientReconInfo.kernelDepth , clientReconInfo.samplesPerNode ); + _density = _tree.template setDensityEstimator< 1 , Reconstructor::WeightDegree >( _samples , clientReconInfo.kernelDepth , clientReconInfo.samplesPerNode ); #ifdef ADAPTIVE_PADDING - _tree.template updateDensityEstimator< 1 , WEIGHT_DEGREE >( *_density , _paddedSamples , 0 , clientReconInfo.kernelDepth , pointDepthFunctor , clientReconInfo.samplesPerNode ); + _tree.template updateDensityEstimator< 1 , Reconstructor::WeightDegree >( *_density , _paddedSamples , 0 , clientReconInfo.kernelDepth , pointDepthFunctor , clientReconInfo.samplesPerNode ); #else // !ADAPTIVE_PADDING - _tree.template updateDensityEstimator< 1 , WEIGHT_DEGREE >( *_density , _paddedSamples , 0 , clientReconInfo.kernelDepth , clientReconInfo.samplesPerNode ); + _tree.template updateDensityEstimator< 1 , Reconstructor::WeightDegree >( *_density , _paddedSamples , 0 , clientReconInfo.kernelDepth , clientReconInfo.samplesPerNode ); #endif // ADAPTIVE_PADDING profiler.update(); if( clientReconInfo.verbose>1 ) std::cout << "# Got kernel density: " << timer << std::endl; @@ -731,10 +734,10 @@ size_t Client< Real , Dim , BType , Degree >::_send3( const ClientReconstruction { if( !auxDataFactory.isStaticallyAllocated() ) { - ProjectiveSampleDataTypeSerializer< Real , Dim > serializer( clientReconInfo.auxProperties ); - state3.dataField.write( serverStream , serializer ); + ProjectiveAuxDataTypeSerializer< Real > serializer( clientReconInfo.auxProperties ); + state3.auxDataField.write( serverStream , serializer ); } - else state3.dataField.write( serverStream ); + else state3.auxDataField.write( serverStream ); } ioBytes += serverStream.ioBytes; profiler.update(); @@ -764,8 +767,8 @@ void Client< Real , Dim , BType , Degree >::_process3( const ClientReconstructio // Add the interpolation constraints { Timer timer; - iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointInterpolationInfo< Real , 0 > ( _tree , _samples , ConstraintDual< Dim , Real >( targetValue , clientReconInfo.pointWeight * cumulativePointWeight.value() ) , SystemDual< Dim , Real >( clientReconInfo.pointWeight * cumulativePointWeight.value() ) , true , clientReconInfo.reconstructionDepth , 1 ); - paddedIInfo = FEMTree< Dim , Real >::template InitializeApproximatePointInterpolationInfo< Real , 0 > ( _tree , _paddedSamples , ConstraintDual< Dim , Real >( targetValue , clientReconInfo.pointWeight * cumulativePointWeight.value() ) , SystemDual< Dim , Real >( clientReconInfo.pointWeight * cumulativePointWeight.value() ) , true , clientReconInfo.reconstructionDepth , 1 ); + iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointInterpolationInfo< Real , 0 > ( _tree , _samples , Reconstructor::Poisson::ConstraintDual< Dim , Real >( targetValue , clientReconInfo.pointWeight * cumulativePointWeight.value() ) , Reconstructor::Poisson::SystemDual< Dim , Real >( clientReconInfo.pointWeight * cumulativePointWeight.value() ) , true , clientReconInfo.reconstructionDepth , 1 ); + paddedIInfo = FEMTree< Dim , Real >::template InitializeApproximatePointInterpolationInfo< Real , 0 > ( _tree , _paddedSamples , Reconstructor::Poisson::ConstraintDual< Dim , Real >( targetValue , clientReconInfo.pointWeight * cumulativePointWeight.value() ) , Reconstructor::Poisson::SystemDual< Dim , Real >( clientReconInfo.pointWeight * cumulativePointWeight.value() ) , true , clientReconInfo.reconstructionDepth , 1 ); profiler.update(); if( clientReconInfo.verbose>1 ) std::cout << "# Set interpolation constraints: " << timer << std::endl; @@ -775,13 +778,13 @@ void Client< Real , Dim , BType , Degree >::_process3( const ClientReconstructio { Timer timer; - constexpr int MAX_DEGREE = NORMAL_DEGREE > Degrees::Max() ? NORMAL_DEGREE : Degrees::Max(); + constexpr int MaxDegree = Reconstructor::Poisson::NormalDegree > Degrees::Max() ? Reconstructor::Poisson::NormalDegree : Degrees::Max(); typename FEMTree< Dim , Real >::template HasNormalDataFunctor< NormalSigs > hasNormalDataFunctor( *_normalInfo ); typename FEMTree< Dim , Real >::template HasNormalDataFunctor< NormalSigs > hasPaddedNormalDataFunctor( *_paddedNormalInfo ); auto hasDataFunctor = [&]( const FEMTreeNode *node ){ return hasNormalDataFunctor( node ) || hasPaddedNormalDataFunctor( node ); }; - const int StartOffset = BSplineSupportSizes< MAX_DEGREE >::SupportStart; - const int EndOffset = BSplineSupportSizes< MAX_DEGREE >::SupportEnd+1; + const int StartOffset = BSplineSupportSizes< MaxDegree >::SupportStart; + const int EndOffset = BSplineSupportSizes< MaxDegree >::SupportEnd+1; auto addNodeFunctor = [&]( int d , const int off[Dim] ) { if( d<0 ) return true; @@ -793,7 +796,7 @@ void Client< Real , Dim , BType , Degree >::_process3( const ClientReconstructio return start<(int)endPaddedIndex && end>(int)beginPaddedIndex; } }; - _tree.template finalizeForMultigrid< MAX_DEGREE , Degrees::Max() >( clientReconInfo.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo , paddedIInfo ) , std::make_tuple( _normalInfo , _paddedNormalInfo , _density ) ); + _tree.template finalizeForMultigrid< MaxDegree , Degrees::Max() >( clientReconInfo.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo , paddedIInfo ) , std::make_tuple( _normalInfo , _paddedNormalInfo , _density ) ); profiler.update(); if( clientReconInfo.verbose>1 ) { @@ -835,7 +838,7 @@ void Client< Real , Dim , BType , Degree >::_process3( const ClientReconstructio if( clientReconInfo.verbose>1 ) std::cout << "#Set interior point constraints: " << timer << std::endl; } } - if( needAuxData ) _dataField = _tree.template setExtrapolatedDataField< DataSig , false >( _samples , _sampleData , (DensityEstimator*)NULL ); + if( needAuxData ) _auxDataField = _tree.template setExtrapolatedDataField< DataSig , false , Reconstructor::WeightDegree , AuxData >( _samples.size() , [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return _samples[i]; } , [&]( size_t i ) -> const AuxData & { return _sampleData[i].template get<1>(); } , (DensityEstimator*)NULL ); // Get the shared tree, constraints, interpolation info, and data-field { @@ -849,15 +852,15 @@ void Client< Real , Dim , BType , Degree >::_process3( const ClientReconstructio state3.subNodes = _tree.tree().serializeSubTree( keepNodeFunctor , state3.subNodeCount ); state3.constraints = _tree.trimToDepth( _constraints , clientReconInfo.sharedDepth ); state3.iInfo = _tree.trimToDepth( *iInfo , clientReconInfo.sharedDepth ); - if( needAuxData ) state3.dataField = _tree.trimToDepth( _dataField , clientReconInfo.sharedDepth ); + if( needAuxData ) state3.auxDataField = _tree.trimToDepth( _auxDataField , clientReconInfo.sharedDepth ); } if( needAuxData ) { - _tree.template updateExtrapolatedDataField< DataSig , false >( _dataField , _paddedSamples , _paddedSampleData , (DensityEstimator*)NULL ); + _tree.template updateExtrapolatedDataField< DataSig , false >( _auxDataField , _paddedSamples.size() , [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return _paddedSamples[i]; } , [&]( size_t i ) -> const AuxData & { return _paddedSampleData[i].template get<1>(); } , (DensityEstimator*)NULL ); auto nodeFunctor = [&]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *n ) { - ProjectiveData< InputSampleDataType , Real >* clr = _dataField( n ); + ProjectiveData< AuxData , Real >* clr = _auxDataField( n ); if( clr ) (*clr) *= (Real)pow( clientReconInfo.dataX , _tree.depth( n ) ); }; _tree.tree().processNodes( nodeFunctor ); @@ -903,7 +906,7 @@ void Client< Real , Dim , BType , Degree >::_process3( const ClientReconstructio auto preMergeFunctor = []( InterpolationData data ){ data.position *= data.weight ; return data; }; auto postMergeFunctor = []( InterpolationData data ){ data.position /= data.weight ; return data; }; - _iInfo = new ApproximatePointInterpolationInfo( ConstraintDual< Dim , Real >( targetValue , clientReconInfo.pointWeight * cumulativePointWeight.value() ) , SystemDual< Dim , Real >( clientReconInfo.pointWeight * cumulativePointWeight.value() ) , true ); + _iInfo = new ApproximatePointInterpolationInfo( Reconstructor::Poisson::ConstraintDual< Dim , Real >( targetValue , clientReconInfo.pointWeight * cumulativePointWeight.value() ) , Reconstructor::Poisson::SystemDual< Dim , Real >( clientReconInfo.pointWeight * cumulativePointWeight.value() ) , true ); _iInfo->iData.reserve( _tree.nodesSize() ); _iInfo->iData.merge( iInfo->iData , preMergeFunctor ); @@ -967,14 +970,13 @@ size_t Client< Real , Dim , BType , Degree >::_receive5( const ClientReconstruct { using Data = typename _State5::Data; Data defaultValue; - defaultValue.data.template get<1>() = auxDataFactory(); if( !auxDataFactory.isStaticallyAllocated() ) { - ProjectiveSampleDataTypeSerializer< Real , Dim > serializer( clientReconInfo.auxProperties ); - state5.dataField = new SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > >( serverStream , serializer ); + ProjectiveAuxDataTypeSerializer< Real > serializer( clientReconInfo.auxProperties ); + state5.auxDataField = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( serverStream , serializer ); } - else state5.dataField = new SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > >( serverStream ); + else state5.auxDataField = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( serverStream ); } profiler.update(); @@ -1039,12 +1041,12 @@ std::pair< double , double > Client< Real , Dim , BType , Degree >::_process5( c auto addNodeFunctor = [&]( int d , const int off[Dim] ){ return d<=(int)clientReconInfo.baseDepth; }; auto hasDataFunctor = []( const FEMTreeNode * ){ return true; }; - constexpr int MAX_DEGREE = NORMAL_DEGREE > Degrees::Max() ? NORMAL_DEGREE : Degrees::Max(); - SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > *dataField = needAuxData ? &_dataField : NULL; + constexpr int MaxDegree = Reconstructor::Poisson::NormalDegree > Degrees::Max() ? Reconstructor::Poisson::NormalDegree : Degrees::Max(); + SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > > *auxDataField = needAuxData ? &_auxDataField : NULL; DenseNodeData< Real , Sigs > *constraints = &_constraints; // [WARNING] This assumes that nothing needs to be done with the Dirichlet flags - _tree.setSortedTreeNodes( std::make_tuple( _iInfo ) , std::make_tuple( _density , constraints , dataField ) ); + _tree.setSortedTreeNodes( std::make_tuple( _iInfo ) , std::make_tuple( _density , constraints , auxDataField ) ); profiler.update(); if( clientReconInfo.verbose>1 ) std::cout << "# Updated client tree: " << timer << std::endl; @@ -1075,17 +1077,16 @@ std::pair< double , double > Client< Real , Dim , BType , Degree >::_process5( c if( needAuxData ) { Timer timer; - using Data = ProjectiveData< InputSampleDataType , Real >; - Data defaultValue; - defaultValue.data.template get<1>() = auxDataFactory(); + using Data = ProjectiveData< AuxData , Real >; + Data defaultValue = auxDataFactory(); // Clearing the low freqeuncy auto nodeFunctor = [&]( const FEMTreeNode *n ) { if( n->nodeData.nodeIndex!=-1 ) { - node_index_type idx = state5.dataField->index( clientToServer[ n->nodeData.nodeIndex ] ); - if( idx!=-1 ) _dataField[n] = (*state5.dataField)[idx]; + node_index_type idx = state5.auxDataField->index( clientToServer[ n->nodeData.nodeIndex ] ); + if( idx!=-1 ) _auxDataField[n] = (*state5.auxDataField)[idx]; } return _tree.depth( n )<(int)clientReconInfo.sharedDepth; }; @@ -1209,88 +1210,98 @@ size_t Client< Real , Dim , BType , Degree >::_receive7( const ClientReconstruct } template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > -void Client< Real , Dim , BType , Degree >::_process7( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , _State7 &state7 , Profiler &profiler ) +template< bool HasGradients , bool HasDensity > +void Client< Real , Dim , BType , Degree >::_writeMeshWithData( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , _State7 &state7 , XForm< Real , Dim+1 > unitCubeToModel ) { + Timer timer; + std::string tempHeader( "PR_" ); + using AuxData = typename AuxDataFactory::VertexType; AuxDataFactory auxDataFactory( clientReconInfo.auxProperties ); + if( clientReconInfo.tempDir.length() ) tempHeader = PointPartition::FileDir( clientReconInfo.tempDir , tempHeader ); - typedef VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::ValueFactory< Real > , AuxDataFactory > OutputVertexFactory; - typedef typename OutputVertexFactory::VertexType OutputVertex; + SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > > *auxDataField = NULL; + if( _auxDataField.size() ) auxDataField = &_auxDataField; - // Extract the mesh + std::string outFileName; { - using namespace VertexFactory; - - typedef Factory< Real , NormalFactory< Real , Dim > , AuxDataFactory > InputSampleDataFactory; - InputSampleDataFactory inputSampleDataFactory( NormalFactory< Real , Dim >() , auxDataFactory ); - - Timer timer; - - std::string tempHeader( "PR_" ); - if( clientReconInfo.tempDir.length() ) tempHeader = PointPartition::FileDir( clientReconInfo.tempDir , tempHeader ); - - SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > *dataField = NULL; - if( _dataField.size() ) dataField = &_dataField; - - XForm< Real , Dim+1 > unitCubeToModel = _modelToUnitCube.inverse(); - std::string outFileName; - { - std::stringstream ss; - ss << clientReconInfo.header << "." << _index << ".ply"; - outFileName = ss.str(); - } + std::stringstream ss; + ss << clientReconInfo.header << "." << _index << ".ply"; + outFileName = ss.str(); + } - if( clientReconInfo.outDir.length() ) outFileName = PointPartition::FileDir( clientReconInfo.outDir , outFileName ); - if( clientReconInfo.density ) - { - typedef Factory< Real , PositionFactory< Real , Dim > , ValueFactory< Real > , AuxDataFactory > VertexFactory; - VertexFactory vertexFactory( PositionFactory< Real , Dim >() , ValueFactory< Real >() , auxDataFactory ); - typedef typename VertexFactory::VertexType Vertex; + if( clientReconInfo.outDir.length() ) outFileName = PointPartition::FileDir( clientReconInfo.outDir , outFileName ); - FileStreamingMesh< VertexFactory , node_index_type > mesh( vertexFactory , tempHeader.c_str() ); - auto SetVertex = []( typename VertexFactory::VertexType &v , Point< Real , Dim > p , Point< Real , Dim > g , Real w , InputSampleDataType d ){ v.template get<0>() = p , v.template get<1>() = w , v.template get<2>() = d.template get<1>(); }; - typename LevelSetExtractor< Dim , Real , Vertex >::Stats stats; - stats = LevelSetExtractor< Dim , Real , Vertex >::template Extract< InputSampleDataType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , _tree , clientReconInfo.reconstructionDepth , _density , dataField , _solution , state7.isoValue , clientReconInfo.sharedDepth , _range.first , _range.second , mesh , inputSampleDataFactory() , SetVertex , !clientReconInfo.linearFit , false , false , true , false , state7.backBoundary , state7.frontBoundary , state7.backDValues , state7.frontDValues , clientReconInfo.mergeType==ClientReconstructionInfo< Real , Dim >::MergeType::TOPOLOGY_AND_FUNCTION ); + // A description of the output vertex information + using VInfo = Reconstructor::OutputVertexWithDataInfo< Real , Dim , AuxDataFactory , HasGradients , HasDensity >; - if( clientReconInfo.verbose>1 ) - { - std::cout << "Vertices / Polygons: " << mesh.vertexNum() << " / " << mesh.polygonNum() << std::endl; - std::cout << stats.toString() << std::endl; - std::cout << "# Got polygons: " << timer << std::endl; - } + // A factory generating the output vertices + using Factory = typename VInfo::Factory; + Factory factory = VInfo::GetFactory( auxDataFactory ); - std::vector< std::string > noComments; - typename VertexFactory::Transform unitCubeToModelTransform( unitCubeToModel ); + // A backing stream for the vertices + Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , false , false , tempHeader + std::string( "v_" ) ); + Reconstructor::OutputInputPolygonStream polygonStream( false , true , tempHeader + std::string( "p_" ) ); - auto xForm = [&]( typename VertexFactory::VertexType & v ){ unitCubeToModelTransform.inPlace( v ); }; - PLY::WritePolygons< VertexFactory , node_index_type , Real , Dim >( outFileName.c_str() , vertexFactory , &mesh , PLY_BINARY_NATIVE , noComments , xForm ); - } - else - { - typedef Factory< Real , PositionFactory< Real , Dim > , AuxDataFactory > VertexFactory; - VertexFactory vertexFactory( PositionFactory< Real , Dim >() , auxDataFactory ); - typedef typename VertexFactory::VertexType Vertex; + typename LevelSetExtractor< Real , Dim , AuxData >::Stats stats; - FileStreamingMesh< VertexFactory , node_index_type > mesh( vertexFactory , tempHeader.c_str() ); + { + // The wrapper converting native to output types + typename VInfo::StreamWrapper _vertexStream( vertexStream , factory() ); + + // The transformed stream + Reconstructor::TransformedOutputVertexWithDataStream< Real , Dim , AuxData > __vertexStream( unitCubeToModel , _vertexStream ); + + // Extract the mesh + stats = LevelSetExtractor< Real , Dim , AuxData >::template Extract< Reconstructor::WeightDegree , DataSig > + ( + Sigs() , + UIntPack< Reconstructor::WeightDegree >() , + UIntPack< DataSig >() , + _tree , + clientReconInfo.reconstructionDepth , + _density , + auxDataField , + _solution , + state7.isoValue , + clientReconInfo.sharedDepth , + _range.first , + _range.second , + __vertexStream , + polygonStream , + auxDataFactory() , + !clientReconInfo.linearFit , + HasGradients , false , true , false , + state7.backBoundary , + state7.frontBoundary , + state7.backDValues , + state7.frontDValues , + clientReconInfo.mergeType==ClientReconstructionInfo< Real , Dim >::MergeType::TOPOLOGY_AND_FUNCTION + ); + } - const typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE > *density=NULL; - auto SetVertex = []( typename VertexFactory::VertexType &v , Point< Real , Dim > p , Point< Real , Dim > g , Real w , InputSampleDataType d ){ v.template get<0>() = p , v.template get<1>() = d.template get<1>(); }; - typename LevelSetExtractor< Dim , Real , Vertex >::Stats stats; - stats = LevelSetExtractor< Dim , Real , Vertex >::template Extract< InputSampleDataType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , _tree , clientReconInfo.reconstructionDepth , _density , dataField , _solution , state7.isoValue , clientReconInfo.sharedDepth , _range.first , _range.second , mesh , inputSampleDataFactory() , SetVertex , !clientReconInfo.linearFit , false , false , true , false , state7.backBoundary , state7.frontBoundary , state7.backDValues , state7.frontDValues , clientReconInfo.mergeType==ClientReconstructionInfo< Real , Dim >::MergeType::TOPOLOGY_AND_FUNCTION ); + if( clientReconInfo.verbose>1 ) + { + std::cout << "Vertices / Polygons: " << vertexStream.size() << " / " << polygonStream.size() << std::endl; + std::cout << stats.toString() << std::endl; + std::cout << "# Got polygons: " << timer << std::endl; + } - if( clientReconInfo.verbose>1 ) - { - std::cout << "Vertices / Polygons: " << mesh.vertexNum() << " / " << mesh.polygonNum() << std::endl; - std::cout << stats.toString() << std::endl; - std::cout << "# Got polygons: " << timer << std::endl; - } + // Write the mesh to a .ply file + std::vector< std::string > noComments; + PLY::WritePolygons< Factory , node_index_type , Real , Dim >( outFileName.c_str() , factory , vertexStream.size() , polygonStream.size() , vertexStream , polygonStream , PLY_BINARY_NATIVE , noComments ); +} - std::vector< std::string > noComments; - typename VertexFactory::Transform unitCubeToModelTransform( unitCubeToModel ); +template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > +void Client< Real , Dim , BType , Degree >::_process7( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , _State7 &state7 , Profiler &profiler ) +{ + static const bool HasAuxData = !std::is_same< AuxDataFactory , VertexFactory::EmptyFactory< Real > >::value; + AuxDataFactory auxDataFactory( clientReconInfo.auxProperties ); - auto xForm = [&]( typename VertexFactory::VertexType & v ){ unitCubeToModelTransform.inPlace( v ); }; - PLY::WritePolygons< VertexFactory , node_index_type , Real , Dim >( outFileName.c_str() , vertexFactory , &mesh , PLY_BINARY_NATIVE , noComments , xForm ); - } + // Extract the mesh + { + if( clientReconInfo.density ) _writeMeshWithData< false , true >( clientReconInfo , state7 , _modelToUnitCube.inverse() ); + else _writeMeshWithData< false , false >( clientReconInfo , state7 , _modelToUnitCube.inverse() ); } if( clientReconInfo.ouputVoxelGrid ) @@ -1409,10 +1420,10 @@ if( idx!=nodes.size() ) ERROR_OUT( "uhoh" ); { if( !auxDataFactory.isStaticallyAllocated() ) { - ProjectiveSampleDataTypeSerializer< Real , Dim > serializer( clientReconInfo.auxProperties ); - _dataField.read( stream , serializer ); + ProjectiveAuxDataTypeSerializer< Real > serializer( clientReconInfo.auxProperties ); + _auxDataField.read( stream , serializer ); } - else _dataField.read( stream ); + else _auxDataField.read( stream ); } } else if( phase==7 ) @@ -1424,10 +1435,10 @@ if( idx!=nodes.size() ) ERROR_OUT( "uhoh" ); { if( !auxDataFactory.isStaticallyAllocated() ) { - ProjectiveSampleDataTypeSerializer< Real , Dim > serializer( clientReconInfo.auxProperties ); - _dataField.read( stream , serializer ); + ProjectiveAuxDataTypeSerializer< Real > serializer( clientReconInfo.auxProperties ); + _auxDataField.read( stream , serializer ); } - else _dataField.read( stream ); + else _auxDataField.read( stream ); } } } @@ -1512,24 +1523,24 @@ void Client< Real , Dim , BType , Degree >::_write( const ClientReconstructionIn { if( !auxDataFactory.isStaticallyAllocated() ) { - ProjectiveSampleDataTypeSerializer< Real , Dim > serializer( clientReconInfo.auxProperties ); - _dataField.write( stream , serializer ); + ProjectiveAuxDataTypeSerializer< Real > serializer( clientReconInfo.auxProperties ); + _auxDataField.write( stream , serializer ); } - else _dataField.write( stream ); + else _auxDataField.write( stream ); } } else if( phase==5 ) { _solution.write( stream ); - if( _dataField.size() ) + if( _auxDataField.size() ) { if( !auxDataFactory.isStaticallyAllocated() ) { - ProjectiveSampleDataTypeSerializer< Real , Dim > serializer( clientReconInfo.auxProperties ); - _dataField.write( stream , serializer ); + ProjectiveAuxDataTypeSerializer< Real > serializer( clientReconInfo.auxProperties ); + _auxDataField.write( stream , serializer ); } - else _dataField.write( stream ); + else _auxDataField.write( stream ); } } } diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index de3ce401..94d2e6fe 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -27,7 +27,7 @@ DAMAGE. */ #include "PreProcessor.h" -#include "PoissonRecon.h" +#include "Reconstructors.h" #include #include @@ -41,15 +41,9 @@ DAMAGE. #include "VertexFactory.h" #include "Image.h" #include "RegularGrid.h" +#include "DataStream.imp.h" -enum NormalType -{ - NORMALS_NONE , - NORMALS_SAMPLES , - NORMALS_GRADIENTS , - NORMALS_COUNT -}; -const char* NormalsNames[] = { "none" , "samples" , "gradients" }; +#define DEFAULT_DIMENSION 3 cmdLineParameter< char* > In( "in" ) , @@ -58,13 +52,11 @@ cmdLineParameter< char* > Grid( "grid" ) , Tree( "tree" ) , Envelope( "envelope" ) , - EnvelopeGrid( "envelopeGrid" ), Transform( "xForm" ); cmdLineReadable Performance( "performance" ) , ShowResidual( "showResidual" ) , - NoComments( "noComments" ) , PolygonMesh( "polygonMesh" ) , NonManifold( "nonManifold" ) , ASCII( "ascii" ) , @@ -75,11 +67,12 @@ cmdLineReadable Colors( "colors" ) , InCore( "inCore" ) , NoDirichletErode( "noErode" ) , + Gradients( "gradients" ) , Verbose( "verbose" ); cmdLineParameter< int > #ifndef FAST_COMPILE - Degree( "degree" , DEFAULT_FEM_DEGREE ) , + Degree( "degree" , Reconstructor::Poisson::DefaultFEMDegree ) , #endif // !FAST_COMPILE Depth( "depth" , 8 ) , KernelDepth( "kernelDepth" ) , @@ -90,9 +83,8 @@ cmdLineParameter< int > BaseDepth( "baseDepth" ) , BaseVCycles( "baseVCycles" , 1 ) , #ifndef FAST_COMPILE - BType( "bType" , DEFAULT_FEM_BOUNDARY+1 ) , + BType( "bType" , Reconstructor::Poisson::DefaultFEMBoundary+1 ) , #endif // !FAST_COMPILE - Normals( "normals" , NORMALS_NONE ) , MaxMemoryGB( "maxMemory" , 0 ) , #ifdef _OPENMP ParallelType( "parallel" , (int)ThreadPool::OPEN_MP ) , @@ -122,9 +114,8 @@ cmdLineReadable* params[] = &In , &Depth , &Out , &Transform , &SolveDepth , &Envelope , - &EnvelopeGrid , &Width , - &Scale , &Verbose , &CGSolverAccuracy , &NoComments , + &Scale , &Verbose , &CGSolverAccuracy , &KernelDepth , &SamplesPerNode , &Confidence , &NonManifold , &PolygonMesh , &ASCII , &ShowResidual , &EnvelopeDepth , &NoDirichletErode , @@ -138,7 +129,7 @@ cmdLineReadable* params[] = &Iters , &DataX , &Colors , - &Normals , + &Gradients , &LinearFit , &PrimalGrid , &TempDir , @@ -160,7 +151,6 @@ void ShowUsage(char* ex) printf( "\t[--%s \n" , Envelope.name ); printf( "\t[--%s ]\n" , Out.name ); printf( "\t[--%s ]\n" , Grid.name ); - printf( "\t[--%s \n" , EnvelopeGrid.name ); printf( "\t[--%s ]\n" , Tree.name ); #ifndef FAST_COMPILE printf( "\t[--%s =%d]\n" , Degree.name , Degree.value ); @@ -176,13 +166,12 @@ void ShowUsage(char* ex) printf( "\t[--%s =%d]\n" , BaseVCycles.name , BaseVCycles.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 , DefaultPointWeightMultiplier * DEFAULT_FEM_DEGREE ); + printf( "\t[--%s =%.3e * ]\n" , PointWeight.name , Reconstructor::Poisson::WeightMultiplier * Reconstructor::Poisson::DefaultFEMDegree ); printf( "\t[--%s =%d]\n" , Iters.name , Iters.value ); printf( "\t[--%s]\n" , ExactInterpolation.name ); printf( "\t[--%s =%f]\n" , DataX.name , DataX.value ); printf( "\t[--%s]\n" , Colors.name ); - printf( "\t[--%s =%d]\n" , Normals.name , Normals.value ); - for( int i=0 ; i=%d]\n" , Threads.name , Threads.value ); printf( "\t[--%s =%d]\n" , ParallelType.name , ParallelType.value ); for( size_t i=0 ; i1 ) 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.; - } -} - -template< typename Real , typename SetVertexFunction , typename InputSampleDataType , typename VertexFactory , unsigned int ... FEMSigs > -void ExtractMesh +template< typename Real , unsigned int Dim , unsigned int FEMSig , bool HasGradients , bool HasDensity > +void WriteMesh ( - UIntPack< FEMSigs ... > , - FEMTree< sizeof ... ( FEMSigs ) , Real >& tree , - const DenseNodeData< Real , UIntPack< FEMSigs ... > >& solution , - Real isoValue , - const std::vector< typename FEMTree< sizeof ... ( FEMSigs ) , Real >::PointSample > *samples , - std::vector< InputSampleDataType > *sampleData , - const typename FEMTree< sizeof ... ( FEMSigs ) , Real >::template DensityEstimator< WEIGHT_DEGREE > *density , - const VertexFactory &vertexFactory , - const InputSampleDataType &zeroInputSampleDataType , - SetVertexFunction SetVertex , - std::vector< std::string > &comments , - XForm< Real , sizeof...(FEMSigs)+1 > unitCubeToModel + bool inCore , + Reconstructor::ReconstructionInfo< Real , Dim , FEMSig > &reconInfo , + const Reconstructor::MeshExtractionParameters &meParams , + std::string fileName , + bool ascii ) { - static const int Dim = sizeof ... ( FEMSigs ); - typedef UIntPack< FEMSigs ... > Sigs; - typedef typename VertexFactory::VertexType Vertex; + // A description of the output vertex information + using VInfo = Reconstructor::OutputVertexInfo< Real , Dim , HasGradients , HasDensity >; - static const unsigned int DataSig = FEMDegreeAndBType< DATA_DEGREE , BOUNDARY_FREE >::Signature; - typedef typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; + // A factory generating the output vertices + using Factory = typename VInfo::Factory; + Factory factory = VInfo::GetFactory(); - Profiler profiler(20); + // A backing stream for the vertices + Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , inCore , false , std::string( "v_" ) ); + Reconstructor::OutputInputPolygonStream polygonStream( inCore , true , std::string( "p_" ) ); - char tempHeader[2048]; { - char tempPath[1024]; - tempPath[0] = 0; - if( TempDir.set ) strcpy( tempPath , TempDir.value ); - else SetTempDirectory( tempPath , sizeof(tempPath) ); - if( strlen(tempPath)==0 ) sprintf( tempPath , ".%c" , FileSeparator ); - if( tempPath[ strlen( tempPath )-1 ]==FileSeparator ) sprintf( tempHeader , "%sPR_" , tempPath ); - else sprintf( tempHeader , "%s%cPR_" , tempPath , FileSeparator ); - } - StreamingMesh< Vertex , node_index_type > *mesh; - if( InCore.set ) mesh = new VectorStreamingMesh< Vertex , node_index_type >(); - else mesh = new FileStreamingMesh< VertexFactory , node_index_type >( vertexFactory , tempHeader ); + // The wrapper converting native to output types + typename VInfo::StreamWrapper _vertexStream( vertexStream , factory() ); - profiler.reset(); - typename LevelSetExtractor< Dim , Real , Vertex >::Stats stats; - if( sampleData ) - { - SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > _sampleData = tree.template setExtrapolatedDataField< DataSig , false >( *samples , *sampleData , (DensityEstimator*)NULL ); - auto nodeFunctor = [&]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *n ) - { - ProjectiveData< InputSampleDataType , Real >* clr = _sampleData( n ); - if( clr ) (*clr) *= (Real)pow( DataX.value , tree.depth( n ) ); - }; - tree.tree().processNodes( nodeFunctor ); - stats = LevelSetExtractor< Dim , Real , Vertex >::template Extract< InputSampleDataType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , &_sampleData , solution , isoValue , *mesh , zeroInputSampleDataType , SetVertex , !LinearFit.set , Normals.value==NORMALS_GRADIENTS , !NonManifold.set , PolygonMesh.set , false ); - } -#if defined( __GNUC__ ) && __GNUC__ < 5 -#ifdef SHOW_WARNINGS -#warning "you've got me gcc version<5" -#endif // SHOW_WARNINGS - else stats = LevelSetExtractor< Dim , Real , Vertex >::template Extract< InputSampleDataType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , (SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > *)NULL , solution , isoValue , *mesh , zeroInputSampleDataType , SetVertex , !LinearFit.set , Normals.value==NORMALS_GRADIENTS , !NonManifold.set , PolygonMesh.set , false ); -#else // !__GNUC__ || __GNUC__ >=5 - else stats = LevelSetExtractor< Dim , Real , Vertex >::template Extract< InputSampleDataType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , NULL , solution , isoValue , *mesh , zeroInputSampleDataType , SetVertex , !LinearFit.set , Normals.value==NORMALS_GRADIENTS , !NonManifold.set , PolygonMesh.set , false ); -#endif // __GNUC__ || __GNUC__ < 4 - if( Verbose.set ) - { - std::cout << "Vertices / Polygons: " << mesh->vertexNum() << " / " << mesh->polygonNum() << std::endl; - std::cout << stats.toString() << std::endl; - if( PolygonMesh.set ) std::cout << "# Got polygons: " << profiler << std::endl; - else std::cout << "# Got triangles: " << profiler << std::endl; + // Extract the mesh + Reconstructor::ExtractMesh< Real >( reconInfo , _vertexStream , polygonStream , meParams ); } + // Write the mesh to a .ply file std::vector< std::string > noComments; - typename VertexFactory::Transform unitCubeToModelTransform( unitCubeToModel ); - auto xForm = [&]( typename VertexFactory::VertexType & v ){ unitCubeToModelTransform.inPlace( v ); }; - PLY::WritePolygons< VertexFactory , node_index_type , Real , Dim >( Out.value , vertexFactory , mesh , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , NoComments.set ? noComments : comments , xForm ); - delete mesh; + PLY::WritePolygons< Factory , node_index_type , Real , Dim >( fileName , factory , vertexStream.size() , polygonStream.size() , vertexStream , polygonStream , ascii ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); } -template< typename Real , unsigned int Dim > -void WriteGrid( const char *fileName , ConstPointer( Real ) values , unsigned int res , XForm< Real , Dim+1 > voxelToModel , bool verbose ) +template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxDataFactory , bool HasGradients , bool HasDensity > +void WriteMeshWithData +( + const AuxDataFactory &auxDataFactory , + bool inCore , + Reconstructor::ReconstructionInfo< Real , Dim , FEMSig , typename AuxDataFactory::VertexType > &reconInfo , + const Reconstructor::MeshExtractionParameters &meParams , + std::string fileName , + bool ascii +) { - char *ext = GetFileExtension( fileName ); + // A description of the output vertex information + using VInfo = Reconstructor::OutputVertexWithDataInfo< Real , Dim , AuxDataFactory , HasGradients , HasDensity >; - if( Dim==2 && ImageWriter::ValidExtension( ext ) ) - { - unsigned int totalResolution = 1; - for( int d=0 ; d avgs( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , totalResolution , [&]( unsigned int thread , size_t i ){ avgs[thread] += values[i]; } ); - for( unsigned int t=0 ; t stds( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , totalResolution , [&]( unsigned int thread , size_t i ){ stds[thread] += ( values[i] - avg ) * ( values[i] - avg ); } ); - for( unsigned int t=0 ; t [0,255]\n" , avg - 2*std , avg + 2*std ); - printf( "Transform:\n" ); - for( int i=0 ; i vertexStream( factory , inCore , false , std::string( "v_" ) ); + Reconstructor::OutputInputPolygonStream polygonStream( inCore , true , std::string( "p_" ) ); - unsigned char *pixels = new unsigned char[ totalResolution*3 ]; - ThreadPool::Parallel_for( 0 , totalResolution , [&]( unsigned int , size_t i ) - { - Real v = (Real)std::min< Real >( (Real)1. , std::max< Real >( (Real)-1. , ( values[i] - avg ) / (2*std ) ) ); - v = (Real)( ( v + 1. ) / 2. * 256. ); - unsigned char color = (unsigned char )std::min< Real >( (Real)255. , std::max< Real >( (Real)0. , v ) ); - for( int c=0 ; c<3 ; c++ ) pixels[i*3+c ] = color; - } - ); - ImageWriter::Write( fileName , pixels , res , res , 3 ); - delete[] pixels; - } - else if( !strcasecmp( ext , "iso" ) ) - { - FILE *fp = fopen( fileName , "wb" ); - if( !fp ) ERROR_OUT( "Failed to open file for writing: " , fileName ); - int r = (int)res; - fwrite( &r , sizeof(int) , 1 , fp ); - size_t count = 1; - for( unsigned int d=0 ; d::Write( fileName , _res , values , voxelToModel ); + // The wrapper converting native to output types + typename VInfo::StreamWrapper _vertexStream( vertexStream , factory() ); + + // Extract the mesh + Reconstructor::ExtractMesh< Real >( reconInfo , _vertexStream , polygonStream , meParams ); } - delete[] ext; + + // Write the mesh to a .ply file + std::vector< std::string > noComments; + PLY::WritePolygons< Factory , node_index_type , Real , Dim >( fileName , factory , vertexStream.size() , polygonStream.size() , vertexStream , polygonStream , ascii ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); } -template< class Real , typename AuxDataFactory , unsigned int ... FEMSigs > -void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) +template< class Real , unsigned int Dim , unsigned int FEMSig , typename AuxDataFactory > +void Execute( const AuxDataFactory &auxDataFactory ) { - static const int Dim = sizeof ... ( FEMSigs ); - typedef UIntPack< FEMSigs ... > Sigs; - typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > Degrees; - typedef UIntPack< FEMDegreeAndBType< NORMAL_DEGREE , DerivativeBoundary< FEMSignature< FEMSigs >::BType , 1 >::BType >::Signature ... > NormalSigs; - static const unsigned int DataSig = FEMDegreeAndBType< DATA_DEGREE , BOUNDARY_FREE >::Signature; - typedef typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; - typedef typename FEMTree< Dim , Real >::template InterpolationInfo< Real , 0 > InterpolationInfo; - using namespace VertexFactory; + static const bool HasAuxData = !std::is_same< AuxDataFactory , VertexFactory::EmptyFactory< Real > >::value; - // The factory for constructing an input sample - typedef Factory< Real , PositionFactory< Real , Dim > , Factory< Real , NormalFactory< Real , Dim > , AuxDataFactory > > InputSampleFactory; + /////////////// + // Types --> // + typedef IsotropicUIntPack< Dim , FEMSig > Sigs; + using namespace VertexFactory; // The factory for constructing an input sample's data - typedef Factory< Real , NormalFactory< Real , Dim > , AuxDataFactory > InputSampleDataFactory; - - // The input point stream information: First piece of data is the normal; the remainder is the auxiliary data - typedef InputOrientedPointStreamInfo< Real , Dim , typename AuxDataFactory::VertexType > InputPointStreamInfo; + typedef typename std::conditional< HasAuxData , Factory< Real , NormalFactory< Real , Dim > , AuxDataFactory > , NormalFactory< Real , Dim > >::type InputSampleDataFactory; - // The type of the input sample - typedef typename InputPointStreamInfo::PointAndDataType InputSampleType; - - // The type of the input sample's data - typedef typename InputPointStreamInfo::DataType InputSampleDataType; + // The factory for constructing an input sample + typedef Factory< Real , PositionFactory< Real , Dim > , InputSampleDataFactory > InputSampleFactory; - typedef InputDataStream< InputSampleType > InputPointStream; - typedef TransformedInputDataStream< InputSampleType > XInputPointStream; + typedef InputDataStream< typename InputSampleFactory::VertexType > InputPointStream; - InputSampleFactory inputSampleFactory( PositionFactory< Real , Dim >() , InputSampleDataFactory( NormalFactory< Real , Dim >() , auxDataFactory ) ); - InputSampleDataFactory inputSampleDataFactory( NormalFactory< Real , Dim >() , auxDataFactory ); + // The type storing the reconstruction solution (depending on whether auxiliary data is provided or not) + using ReconstructionInfo = typename std::conditional< HasAuxData , Reconstructor::ReconstructionInfo< Real , Dim , FEMSig , typename AuxDataFactory::VertexType > , Reconstructor::ReconstructionInfo< Real , Dim , FEMSig > >::type; + // <-- Types // + /////////////// - typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; - typedef typename FEMTreeInitializer< Dim , Real >::GeometryNodeType GeometryNodeType; - std::vector< std::string > comments; if( Verbose.set ) { std::cout << "*************************************************************" << std::endl; @@ -413,72 +296,80 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) std::cout << "*************************************************************" << std::endl; std::cout << "*************************************************************" << std::endl; if( !Threads.set ) std::cout << "Running with " << Threads.value << " threads" << std::endl; + + char str[1024]; + for( int i=0 ; params[i] ; i++ ) if( params[i]->set ) + { + params[i]->writeValue( str ); + if( strlen( str ) ) std::cout << "\t--" << params[i]->name << " " << str << std::endl; + else std::cout << "\t--" << params[i]->name << std::endl; + } } - bool needNormalData = DataX.value>0 && Normals.value; - bool needAuxData = DataX.value>0 && auxDataFactory.bufferSize(); + Profiler profiler(20); + ReconstructionInfo *sInfo = NULL; + typename Reconstructor::Poisson::SolutionParameters< Real > sParams; + typename Reconstructor::MeshExtractionParameters meParams; + + sParams.verbose = Verbose.set; + sParams.dirichletErode = !NoDirichletErode.set; + sParams.outputDensity = Density.set; + sParams.exactInterpolation = ExactInterpolation.set; + sParams.showResidual = ShowResidual.set; + sParams.scale = (Real)Scale.value; + sParams.confidence = (Real)Confidence.value; + sParams.confidenceBias = (Real)ConfidenceBias.value; + sParams.lowDepthCutOff = (Real)LowDepthCutOff.value; + sParams.width = (Real)Width.value; + sParams.pointWeight = (Real)PointWeight.value; + sParams.samplesPerNode = (Real)SamplesPerNode.value; + sParams.cgSolverAccuracy = (Real)CGSolverAccuracy.value; + sParams.depth = (unsigned int)Depth.value; + sParams.baseDepth = (unsigned int)BaseDepth.value; + sParams.solveDepth = (unsigned int)SolveDepth.value; + sParams.fullDepth = (unsigned int)FullDepth.value; + sParams.kernelDepth = (unsigned int)KernelDepth.value; + sParams.envelopeDepth = (unsigned int)EnvelopeDepth.value; + sParams.baseVCycles = (unsigned int)BaseVCycles.value; + sParams.iters = (unsigned int)Iters.value; + + meParams.linearFit = LinearFit.set; + meParams.outputGradients = Gradients.set; + meParams.forceManifold = !NonManifold.set; + meParams.polygonMesh = PolygonMesh.set; + meParams.verbose = Verbose.set; + + double startTime = Time(); + + InputSampleFactory *_inputSampleFactory; + if constexpr( HasAuxData ) _inputSampleFactory = new InputSampleFactory( VertexFactory::PositionFactory< Real , Dim >() , InputSampleDataFactory( VertexFactory::NormalFactory< Real , Dim >() , auxDataFactory ) ); + else _inputSampleFactory = new InputSampleFactory( VertexFactory::PositionFactory< Real , Dim >() , VertexFactory::NormalFactory< Real , Dim >() ); + InputSampleFactory &inputSampleFactory = *_inputSampleFactory; + XForm< Real , Dim+1 > toModel = XForm< Real , Dim+1 >::Identity(); - XForm< Real , Dim+1 > modelToUnitCube , unitCubeToModel; + // Read in the transform, if we want to apply one to the points before processing if( Transform.set ) { FILE* fp = fopen( Transform.value , "r" ); - if( !fp ) - { - WARN( "Could not read x-form from: " , Transform.value ); - modelToUnitCube = XForm< Real , Dim+1 >::Identity(); - } + if( !fp ) WARN( "Could not read x-form from: " , Transform.value ); else { for( int i=0 ; i::Identity(); + std::vector< typename InputSampleFactory::VertexType > inCorePoints; + InputPointStream *pointStream; - char str[1024]; - for( int i=0 ; params[i] ; i++ ) - if( params[i]->set ) - { - params[i]->writeValue( str ); - if( Verbose.set ) - if( strlen( str ) ) std::cout << "\t--" << params[i]->name << " " << str << std::endl; - else std::cout << "\t--" << params[i]->name << std::endl; - } - - double startTime = Time(); - Real isoValue = 0; - - FEMTree< Dim , Real > tree( MEMORY_ALLOCATOR_BLOCK_SIZE ); - Profiler profiler(20); - - if( Depth.set && Width.value>0 ) - { - WARN( "Both --" , Depth.name , " and --" , Width.name , " set, ignoring --" , Width.name ); - Width.value = 0; - } - - size_t pointCount; - - ProjectiveData< Point< Real , 2 > , Real > pointDepthAndWeight; - std::vector< typename FEMTree< Dim , Real >::PointSample >* samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); - DenseNodeData< GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > geometryNodeDesignators; - std::vector< InputSampleDataType >* sampleData = NULL; - DensityEstimator* density = NULL; - SparseNodeData< Point< Real , Dim > , NormalSigs >* normalInfo = NULL; - Real targetValue = (Real)0.5; - - // Read in the samples (and color data) + // Get the point stream { profiler.reset(); - InputPointStream* pointStream; - char* ext = GetFileExtension( In.value ); - sampleData = new std::vector< InputSampleDataType >(); - std::vector< InputSampleType > inCorePoints; + char *ext = GetFileExtension( In.value ); if( InCore.set ) { @@ -486,11 +377,11 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) if ( !strcasecmp( ext , "bnpts" ) ) _pointStream = new BinaryInputDataStream< InputSampleFactory >( In.value , inputSampleFactory ); else if( !strcasecmp( ext , "ply" ) ) _pointStream = new PLYInputDataStream< InputSampleFactory >( In.value , inputSampleFactory ); else _pointStream = new ASCIIInputDataStream< InputSampleFactory >( In.value , inputSampleFactory ); - InputSampleType p = inputSampleFactory(); - while( _pointStream->next( p ) ) inCorePoints.push_back( p ); + typename InputSampleFactory::VertexType p = inputSampleFactory(); + while( _pointStream->read( p ) ) inCorePoints.push_back( p ); delete _pointStream; - pointStream = new MemoryInputDataStream< InputSampleType >( inCorePoints.size() , &inCorePoints[0] ); + pointStream = new VectorBackedInputDataStream< typename InputSampleFactory::VertexType >( inCorePoints ); } else { @@ -499,360 +390,98 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) else pointStream = new ASCIIInputDataStream< InputSampleFactory >( In.value , inputSampleFactory ); } delete[] ext; - - typename InputSampleFactory::Transform _modelToUnitCube( modelToUnitCube ); - auto XFormFunctor = [&]( InputSampleType &p ){ _modelToUnitCube.inPlace( p ); }; - XInputPointStream _pointStream( XFormFunctor , *pointStream ); - - { - typename InputSampleDataFactory::VertexType zeroData = inputSampleDataFactory(); - modelToUnitCube = Scale.value>0 ? GetPointXForm< Real , Dim , typename AuxDataFactory::VertexType >( _pointStream , zeroData , (Real)Scale.value ) * modelToUnitCube : modelToUnitCube; - } - if( Width.value>0 ) - { - Real maxScale = 0; - for( unsigned int i=0 ; i( maxScale , (Real)1./modelToUnitCube(i,i) ); - Depth.value = (unsigned int)ceil( std::max< double >( 0. , log( maxScale/Width.value )/log(2.) ) ); - } - if( SolveDepth.value>Depth.value ) - { - WARN( "Solution depth cannot exceed system depth: " , SolveDepth.value , " <= " , Depth.value ); - SolveDepth.value = Depth.value; - } - if( FullDepth.value>Depth.value ) - { - WARN( "Full depth cannot exceed system depth: " , FullDepth.value , " <= " , Depth.value ); - FullDepth.value = Depth.value; - } - if( BaseDepth.value>FullDepth.value ) - { - if( BaseDepth.set ) WARN( "Base depth must be smaller than full depth: " , BaseDepth.value , " <= " , FullDepth.value ); - BaseDepth.value = FullDepth.value; - } - - { - typename InputSampleFactory::Transform _modelToUnitCube( modelToUnitCube ); - auto XFormFunctor = [&]( InputSampleType &p ){ _modelToUnitCube.inPlace( p ); }; - XInputPointStream _pointStream( XFormFunctor , *pointStream ); - auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , typename InputPointStreamInfo::DataType &d ) - { - Real l = (Real)Length( d.template get<0>() ); - if( !l || !std::isfinite( l ) ) return (Real)-1.; - return (Real)pow( l , Confidence.value ); - }; - auto ProcessData = []( const Point< Real , Dim > &p , typename InputPointStreamInfo::DataType &d ) - { - Real l = (Real)Length( d.template get<0>() ); - if( !l || !std::isfinite( l ) ) return (Real)-1.; - d.template get<0>() /= l; - return (Real)1.; - }; - - typename InputSampleDataFactory::VertexType zeroData = inputSampleDataFactory(); - typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; - if( Confidence.value>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , tree.spaceRoot() , _pointStream , zeroData , Depth.value , *samples , *sampleData , true , tree.nodeAllocators[0] , tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , tree.spaceRoot() , _pointStream , zeroData , Depth.value , *samples , *sampleData , true , tree.nodeAllocators[0] , tree.initializer() , ProcessData ); - } - - unitCubeToModel = modelToUnitCube.inverse(); - delete pointStream; - - if( Verbose.set ) - { - std::cout << "Input Points / Samples: " << pointCount << " / " << samples->size() << std::endl; - std::cout << "# Read input into tree: " << profiler << std::endl; - } } - DenseNodeData< Real , Sigs > solution; + typename Reconstructor::Poisson::EnvelopeMesh< Real , Dim > *envelopeMesh = NULL; + if( Envelope.set ) { - DenseNodeData< Real , Sigs > constraints; - InterpolationInfo* iInfo = NULL; - int solveDepth = Depth.value; - - tree.resetNodeIndices( 0 , std::make_tuple() ); - - // Get the kernel density estimator + envelopeMesh = new typename Reconstructor::Poisson::EnvelopeMesh< Real , Dim >(); { - profiler.reset(); - density = tree.template setDensityEstimator< 1 , WEIGHT_DEGREE >( *samples , KernelDepth.value , SamplesPerNode.value ); - if( Verbose.set ) std::cout << "# Got kernel density: " << profiler << std::endl; - } - - // Transform the Hermite samples into a vector field - { - profiler.reset(); - normalInfo = new SparseNodeData< Point< Real , Dim > , NormalSigs >(); - std::function< bool ( InputSampleDataType , Point< Real , Dim >& ) > ConversionFunction = []( InputSampleDataType in , Point< Real , Dim > &out ) - { - Point< Real , Dim > n = in.template get<0>(); - Real l = (Real)Length( n ); - // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... - if( !l ) return false; - out = n / l; - return true; - }; - std::function< bool ( InputSampleDataType , Point< Real , Dim >& , Real & ) > ConversionAndBiasFunction = []( InputSampleDataType in , Point< Real , Dim > &out , Real &bias ) - { - Point< Real , Dim > n = in.template get<0>(); - Real l = (Real)Length( n ); - // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... - if( !l ) return false; - out = n / l; - bias = (Real)( log( l ) * ConfidenceBias.value / log( 1<<(Dim-1) ) ); - return true; - }; - if( ConfidenceBias.value>0 ) *normalInfo = tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleData , density , BaseDepth.value , Depth.value , (Real)LowDepthCutOff.value , pointDepthAndWeight , ConversionAndBiasFunction ); - else *normalInfo = tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleData , density , BaseDepth.value , Depth.value , (Real)LowDepthCutOff.value , pointDepthAndWeight , ConversionFunction ); - ThreadPool::Parallel_for( 0 , normalInfo->size() , [&]( unsigned int , size_t i ){ (*normalInfo)[i] *= (Real)-1.; } ); - if( Verbose.set ) - { - std::cout << "# Got normal field: " << profiler << std::endl; - std::cout << "Point depth / Point weight / Estimated measure: " << pointDepthAndWeight.value()[0] << " / " << pointDepthAndWeight.value()[1] << " / " << pointCount*pointDepthAndWeight.value()[1] << std::endl; - } + std::vector< std::vector< int > > polygons; + std::vector< std::string > comments; + int file_type; + PLY::ReadPolygons( Envelope.value , PositionFactory< Real , Dim >() , envelopeMesh->vertices , polygons , file_type , comments ); + envelopeMesh->simplices.resize( polygons.size() ); + for( int i=0 ; isimplices[i][j] = polygons[i][j]; } + } - // Get the geometry designators indicating if the space node are interior to, exterior to, or contain the envelope boundary - if( Envelope.set ) + // A wrapper class to realize InputDataStream< SampleType > as an InputSampleStream + struct _InputSampleStream : public Reconstructor::InputSampleStream< Real , Dim > + { + typedef Reconstructor::Normal< Real , Dim > DataType; + typedef VectorTypeUnion< Real , Reconstructor::Position< Real , Dim > , DataType > SampleType; + typedef InputDataStream< SampleType > _InputPointStream; + _InputPointStream &pointStream; + SampleType scratch; + _InputSampleStream( _InputPointStream &pointStream ) : pointStream( pointStream ) { - profiler.reset(); - { - // Make the octree complete up to the base depth - FEMTreeInitializer< Dim , Real >::Initialize( tree.spaceRoot() , BaseDepth.value , []( int , int[] ){ return true; } , tree.nodeAllocators.size() ? tree.nodeAllocators[0] : NULL , tree.initializer() ); - - // Read in the envelope geometry - std::vector< Point< Real , Dim > > vertices; - std::vector< SimplexIndex< Dim-1 , node_index_type > > simplices; - { - std::vector< typename PositionFactory< Real , Dim >::VertexType > _vertices; - std::vector< std::vector< int > > polygons; - std::vector< std::string > comments; - int file_type; - PLY::ReadPolygons( Envelope.value , PositionFactory< Real , Dim >() , _vertices , polygons , file_type , comments ); - vertices.resize( _vertices.size() ); - for( int i=0 ; i::template GetGeometryNodeDesignators( &tree.spaceRoot() , vertices , simplices , BaseDepth.value , EnvelopeDepth.value , tree.nodeAllocators , tree.initializer() ); - - // Make nodes in the support of the vector field @{ExactDepth} interior - if( !NoDirichletErode.set ) - { - // What to do if we find a node in the support of the vector field - auto SetScratchFlag = [&]( FEMTreeNode *node ) - { - if( node ) - { - while( node->depth()>BaseDepth.value ) node = node->parent; - node->nodeData.setScratchFlag( true ); - } - }; - - std::function< void ( FEMTreeNode * ) > PropagateToLeaves = [&]( const FEMTreeNode *node ) - { - geometryNodeDesignators[ node ] = GeometryNodeType::INTERIOR; - if( node->children ) for( int c=0 ; c<(1<children+c ); - }; - - // Flags indicating if a node contains a non-zero vector field coefficient - std::vector< bool > isVectorFieldElement( tree.nodeCount() , false ); - - // Get the set of base nodes - std::vector< FEMTreeNode * > baseNodes; - auto nodeFunctor = [&]( FEMTreeNode *node ) - { - if( node->depth()==BaseDepth.value ) baseNodes.push_back( node ); - return node->depth() vectorFieldElementCounts( baseNodes.size() ); - for( int i=0 ; i *n = (*normalInfo)( node ); - if( n && Point< Real , Dim >::SquareNorm( *n ) ) isVectorFieldElement[ node->nodeData.nodeIndex ] = true , vectorFieldElementCounts[i]++; - }; - baseNodes[i]->processNodes( nodeFunctor ); - } ); - size_t vectorFieldElementCount = 0; - for( int i=0 ; i vectorFieldElements; - vectorFieldElements.reserve( vectorFieldElementCount ); - { - std::vector< std::vector< FEMTreeNode * > > _vectorFieldElements( baseNodes.size() ); - for( int i=0 ; i<_vectorFieldElements.size() ; i++ ) _vectorFieldElements[i].reserve( vectorFieldElementCounts[i] ); - ThreadPool::Parallel_for( 0 , baseNodes.size() , [&]( unsigned int t , size_t i ) - { - auto nodeFunctor = [&]( FEMTreeNode *node ) - { - if( isVectorFieldElement[ node->nodeData.nodeIndex ] ) _vectorFieldElements[i].push_back( node ); - node->nodeData.setScratchFlag( false ); - }; - baseNodes[i]->processNodes( nodeFunctor ); - } ); - for( int i=0 ; i<_vectorFieldElements.size() ; i++ ) vectorFieldElements.insert( vectorFieldElements.end() , _vectorFieldElements[i].begin() , _vectorFieldElements[i].end() ); - } - - // Set the scratch flag for the base nodes on which the vector field is supported -#ifdef SHOW_WARNINGS -#pragma message( "[WARNING] In principal, we should unlock finite elements whose support overlaps the vector field" ) -#endif // SHOW_WARNINGS - tree.template processNeighboringLeaves< -BSplineSupportSizes< NORMAL_DEGREE >::SupportStart , BSplineSupportSizes< NORMAL_DEGREE >::SupportEnd >( &vectorFieldElements[0] , vectorFieldElements.size() , SetScratchFlag , false ); - - // Set sub-trees rooted at interior nodes @ ExactDepth to interior - ThreadPool::Parallel_for( 0 , baseNodes.size() , [&]( unsigned int , size_t i ){ if( baseNodes[i]->nodeData.getScratchFlag() ) PropagateToLeaves( baseNodes[i] ); } ); - - // Adjust the coarser node designators in case exterior nodes have become boundary. - ThreadPool::Parallel_for( 0 , baseNodes.size() , [&]( unsigned int , size_t i ){ FEMTreeInitializer< Dim , Real >::PullGeometryNodeDesignatorsFromFiner( baseNodes[i] , geometryNodeDesignators ); } ); - FEMTreeInitializer< Dim , Real >::PullGeometryNodeDesignatorsFromFiner( &tree.spaceRoot() , geometryNodeDesignators , BaseDepth.value ); - } - } - if( Verbose.set ) std::cout << "# Initialized envelope constraints: " << profiler << std::endl; + scratch = SampleType( Reconstructor::Position< Real , Dim >() , Reconstructor::Normal< Real , Dim >() ); } - - if( !Density.set ) delete density , density = NULL; - if( !needNormalData && !needAuxData ) delete sampleData , sampleData = NULL; - - // Add the interpolation constraints - if( PointWeight.value>0 ) + void reset( void ){ pointStream.reset(); } + bool base_read( Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n ) { - profiler.reset(); - if( ExactInterpolation.set ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointInterpolationInfo< Real , 0 > ( tree , *samples , ConstraintDual< Dim , Real >( targetValue , (Real)PointWeight.value * pointDepthAndWeight.value()[1] ) , SystemDual< Dim , Real >( (Real)PointWeight.value * pointDepthAndWeight.value()[1] ) , true , false ); - else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointInterpolationInfo< Real , 0 > ( tree , *samples , ConstraintDual< Dim , Real >( targetValue , (Real)PointWeight.value * pointDepthAndWeight.value()[1] ) , SystemDual< Dim , Real >( (Real)PointWeight.value * pointDepthAndWeight.value()[1] ) , true , Depth.value , 1 ); - if( Verbose.set ) std::cout << "#Initialized point interpolation constraints: " << profiler << std::endl; + bool ret = pointStream.read( scratch ); + if( ret ) p = scratch.template get<0>() , n = scratch.template get<1>(); + return ret; } + }; - // Trim the tree and prepare for multigrid + // A wrapper class to realize InputDataStream< SampleType > as an InputSampleWithDataStream + struct _InputSampleWithDataStream : public Reconstructor::InputSampleWithDataStream< Real , Dim , typename AuxDataFactory::VertexType > + { + typedef VectorTypeUnion< Real , Reconstructor::Normal< Real , Dim > , typename AuxDataFactory::VertexType > DataType; + typedef VectorTypeUnion< Real , Reconstructor::Position< Real , Dim > , DataType > SampleType; + typedef InputDataStream< SampleType > _InputPointStream; + _InputPointStream &pointStream; + SampleType scratch; + _InputSampleWithDataStream( _InputPointStream &pointStream , typename AuxDataFactory::VertexType zero ) : Reconstructor::InputSampleWithDataStream< Real , Dim , typename AuxDataFactory::VertexType >( zero ) , pointStream( pointStream ) { - profiler.reset(); - constexpr int MAX_DEGREE = NORMAL_DEGREE > Degrees::Max() ? NORMAL_DEGREE : Degrees::Max(); - typename FEMTree< Dim , Real >::template HasNormalDataFunctor< NormalSigs > hasNormalDataFunctor( *normalInfo ); - auto hasDataFunctor = [&]( const FEMTreeNode *node ){ return hasNormalDataFunctor( node ); }; - auto addNodeFunctor = [&]( int d , const int off[Dim] ){ return d<=FullDepth.value; }; - if( geometryNodeDesignators.size() ) tree.template finalizeForMultigridWithDirichlet< MAX_DEGREE , Degrees::Max() >( BaseDepth.value , addNodeFunctor , hasDataFunctor , [&]( const FEMTreeNode *node ){ return node->nodeData.nodeIndex<(node_index_type)geometryNodeDesignators.size() && geometryNodeDesignators[node]==GeometryNodeType::EXTERIOR; } , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , density , &geometryNodeDesignators ) ); - else tree.template finalizeForMultigrid< MAX_DEGREE , Degrees::Max() >( BaseDepth.value , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , density ) ); - - if( geometryNodeDesignators.size() && EnvelopeGrid.set ) - { - FEMTreeInitializer< Dim , Real >::PushGeometryNodeDesignatorsToFiner( &tree.spaceRoot() , geometryNodeDesignators ); - FEMTreeInitializer< Dim , Real >::PullGeometryNodeDesignatorsFromFiner( &tree.spaceRoot() , geometryNodeDesignators ); - - auto WriteEnvelopeGrid = [&]( bool showFinest ) - { - int res = 0; - DenseNodeData< Real , IsotropicUIntPack< Dim , FEMTrivialSignature > > coefficients = tree.initDenseNodeData( IsotropicUIntPack< Dim , FEMTrivialSignature >() ); - auto nodeFunctor = [&]( const FEMTreeNode *n ) - { - if( n->nodeData.nodeIndex!=-1 && ( ( showFinest && !n->children ) || ( !showFinest && geometryNodeDesignators[n->parent]==GeometryNodeType::BOUNDARY ) ) ) - { -#if 0 // Randomize the colors - auto Value = []( double v , double eps ){ return (Real)( v + Random< double >() * 2. * eps - eps ); }; - // Show the octree structure - if ( geometryNodeDesignators[n]==GeometryNodeType::INTERIOR ) coefficients[n] = Value( 0.75 , 0.25 ); - else if( geometryNodeDesignators[n]==GeometryNodeType::EXTERIOR ) coefficients[n] = Value( -0.75 , 0.25 ); - -#else - if ( geometryNodeDesignators[n]==GeometryNodeType::INTERIOR ) coefficients[n] = (Real) 1.; - else if( geometryNodeDesignators[n]==GeometryNodeType::EXTERIOR ) coefficients[n] = (Real)-1.; -#endif - } - }; - tree.spaceRoot().processNodes( nodeFunctor ); - Pointer( Real ) values = tree.template regularGridEvaluate< true >( coefficients , res , -1 , false ); - XForm< Real , Dim+1 > voxelToUnitCube = XForm< Real , Dim+1 >::Identity(); - for( int d=0 ; d( EnvelopeGrid.value , values , res , unitCubeToModel * voxelToUnitCube , Verbose.set ); - DeletePointer( values ); - }; - - WriteEnvelopeGrid( true ); - } - - if( Verbose.set ) std::cout << "# Finalized tree: " << profiler << std::endl; + scratch = SampleType( Reconstructor::Position< Real , Dim >() , DataType( Reconstructor::Normal< Real , Dim >() , zero ) ); } - - // Add the FEM constraints + void reset( void ){ pointStream.reset(); } + bool base_read( Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n , typename AuxDataFactory::VertexType &d ) { - profiler.reset(); - constraints = tree.initDenseNodeData( Sigs() ); - typename FEMIntegrator::template Constraint< Sigs , IsotropicUIntPack< Dim , 1 > , NormalSigs , IsotropicUIntPack< Dim , 0 > , Dim > F; - unsigned int derivatives2[Dim]; - for( int d=0 ; d Derivatives1; - typedef IsotropicUIntPack< Dim , 0 > Derivatives2; - for( int d=0 ; d::Index( derivatives1 ) ][ TensorDerivatives< Derivatives2 >::Index( derivatives2 ) ] = 1; - } - tree.addFEMConstraints( F , *normalInfo , constraints , solveDepth ); - if( Verbose.set ) std::cout << "# Set FEM constraints: " << profiler << std::endl; + bool ret = pointStream.read( scratch ); + if( ret ) p = scratch.template get<0>() , n = scratch.template get<1>().template get<0>() , d = scratch.template get<1>().template get<1>(); + return ret; } + }; - // Free up the normal info - delete normalInfo , normalInfo = NULL; - - // Add the interpolation constraints - if( PointWeight.value>0 ) - { - profiler.reset(); - tree.addInterpolationConstraints( constraints , solveDepth , std::make_tuple( iInfo ) ); - if( Verbose.set ) std::cout << "#Set point constraints: " << profiler << std::endl; - } + if( Transform.set and envelopeMesh ) for( unsigned int i=0 ; ivertices.size() ; i++ ) envelopeMesh->vertices[i] = toModel * envelopeMesh->vertices[i]; + if constexpr( HasAuxData ) + { + _InputSampleWithDataStream sampleStream( *pointStream , auxDataFactory() ); - if( Verbose.set ) - { - std::cout << "All Nodes / Active Nodes / Ghost Nodes / Dirichlet Supported Nodes: " << tree.allNodes() << " / " << tree.activeNodes() << " / " << tree.ghostNodes() << " / " << tree.dirichletElements() << std::endl; - std::cout << "Memory Usage: " << float( MemoryInfo::Usage())/(1<<20) << " MB" << std::endl; - } - - // Solve the linear system + if( Transform.set ) { - profiler.reset(); - typename FEMTree< Dim , Real >::SolverInfo sInfo; - sInfo.cgDepth = 0 , sInfo.cascadic = true , sInfo.vCycles = 1 , sInfo.iters = Iters.value , sInfo.cgAccuracy = CGSolverAccuracy.value , sInfo.verbose = Verbose.set , sInfo.showResidual = ShowResidual.set , sInfo.showGlobalResidual = SHOW_GLOBAL_RESIDUAL_NONE , sInfo.sliceBlockSize = 1; - sInfo.baseVCycles = BaseVCycles.value; - typename FEMIntegrator::template System< Sigs , IsotropicUIntPack< Dim , 1 > > F( { 0. , 1. } ); - solution = tree.solveSystem( Sigs() , F , constraints , BaseDepth.value , SolveDepth.value , sInfo , std::make_tuple( iInfo ) ); - if( Verbose.set ) std::cout << "# Linear system solved: " << profiler << std::endl; - if( iInfo ) delete iInfo , iInfo = NULL; + Reconstructor::TransformedInputSampleWithDataStream< Real , Dim , typename AuxDataFactory::VertexType > _sampleStream( toModel , sampleStream ); + sInfo = Reconstructor::Poisson::Solve< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( _sampleStream , sParams , envelopeMesh ); + sInfo->unitCubeToModel = toModel.inverse() * sInfo->unitCubeToModel; } + else sInfo = Reconstructor::Poisson::Solve< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( sampleStream , sParams , envelopeMesh ); } - + else { - profiler.reset(); - double valueSum = 0 , weightSum = 0; - typename FEMTree< Dim , Real >::template MultiThreadedEvaluator< Sigs , 0 > evaluator( &tree , solution ); - std::vector< double > valueSums( ThreadPool::NumThreads() , 0 ) , weightSums( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , samples->size() , [&]( unsigned int thread , size_t j ) - { - ProjectiveData< Point< Real , Dim > , Real >& sample = (*samples)[j].sample; - Real w = sample.weight; - if( w>0 ) weightSums[thread] += w , valueSums[thread] += evaluator.values( sample.data / sample.weight , thread , (*samples)[j].node )[0] * w; - } - ); - for( size_t t=0 ; t _sampleStream( toModel , sampleStream ); + sInfo = Reconstructor::Poisson::Solve< Real , Dim , FEMSig >( _sampleStream , sParams , envelopeMesh ); + sInfo->unitCubeToModel = toModel.inverse() * sInfo->unitCubeToModel; } + else sInfo = Reconstructor::Poisson::Solve< Real , Dim , FEMSig >( sampleStream , sParams , envelopeMesh ); } + + delete pointStream; + delete _inputSampleFactory; + delete envelopeMesh; + + if constexpr( HasAuxData ) if( sInfo->auxData ) sInfo->weightAuxDataByDepth( (Real)DataX.value ); + if( Tree.set ) { FILE* fp = fopen( Tree.value , "wb" ); @@ -860,20 +489,10 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) FileStream fs(fp); FEMTree< Dim , Real >::WriteParameter( fs ); DenseNodeData< Real , Sigs >::WriteSignatures( fs ); - tree.write( fs , modelToUnitCube , false ); - solution.write( fs ); - if( sampleData ) - { - SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > _sampleData = tree.template setExtrapolatedDataField< DataSig , false >( *samples , *sampleData , (DensityEstimator*)NULL ); - auto nodeFunctor = [&]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *n ) - { - ProjectiveData< InputSampleDataType , Real >* clr = _sampleData( n ); - if( clr ) (*clr) *= (Real)pow( DataX.value , tree.depth( n ) ); - }; - tree.tree().processNodes( nodeFunctor ); - _sampleData.write( fs ); - } - if( density ) density->write( fs ); + sInfo->tree.write( fs , sInfo->unitCubeToModel.inverse() , false ); + sInfo->solution.write( fs ); + if constexpr( HasAuxData ) if( sInfo->auxData ) sInfo->auxData->write( fs ); + if( sInfo->density ) sInfo->density->write( fs ); fclose( fp ); } @@ -881,71 +500,67 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) { int res = 0; profiler.reset(); - Pointer( Real ) values = tree.template regularGridEvaluate< true >( solution , res , -1 , PrimalGrid.set ); + Pointer( Real ) values = sInfo->tree.template regularGridEvaluate< true >( sInfo->solution , res , -1 , PrimalGrid.set ); if( Verbose.set ) std::cout << "Got grid: " << profiler << std::endl; XForm< Real , Dim+1 > voxelToUnitCube = XForm< Real , Dim+1 >::Identity(); if( PrimalGrid.set ) for( int d=0 ; d( Grid.value , values , res , unitCubeToModel * voxelToUnitCube , Verbose.set ); + + unsigned int _res[Dim]; + for( int d=0 ; d::Write( Grid.value , _res , values , sInfo->unitCubeToModel * voxelToUnitCube ); + DeletePointer( values ); } - if( Out.set ) + + if( Out.set && Dim!=3 ) WARN( "Mesh extraction is only supported in dimension 3" ); + else if( Out.set && Dim==3 ) { - if( Normals.value ) + // Create the output mesh + char tempHeader[2048]; + { + char tempPath[1024]; + tempPath[0] = 0; + if( TempDir.set ) strcpy( tempPath , TempDir.value ); + else SetTempDirectory( tempPath , sizeof(tempPath) ); + if( strlen(tempPath)==0 ) sprintf( tempPath , ".%c" , FileSeparator ); + if( tempPath[ strlen( tempPath )-1 ]==FileSeparator ) sprintf( tempHeader , "%sPR_" , tempPath ); + else sprintf( tempHeader , "%s%cPR_" , tempPath , FileSeparator ); + } + + XForm< Real , Dim+1 > pXForm = sInfo->unitCubeToModel; + XForm< Real , Dim > nXForm = XForm< Real , Dim >( pXForm ).inverse().transpose(); + + if( Gradients.set ) { if( Density.set ) { - typedef Factory< Real , PositionFactory< Real , Dim > , NormalFactory< Real , Dim > , ValueFactory< Real > , AuxDataFactory > VertexFactory; - VertexFactory vertexFactory( PositionFactory< Real , Dim >() , NormalFactory< Real , Dim >() , ValueFactory< Real >() , auxDataFactory ); - if( Normals.value==NORMALS_SAMPLES ) - { - auto SetVertex = []( typename VertexFactory::VertexType &v , Point< Real , Dim > p , Point< Real , Dim > g , Real w , InputSampleDataType d ){ v.template get<0>() = p , v.template get<1>() = d.template get<0>() , v.template get<2>() = w , v.template get<3>() = d.template get<1>(); }; - ExtractMesh( UIntPack< FEMSigs ... >() , tree , solution , isoValue , samples , sampleData , density , vertexFactory , inputSampleDataFactory() , SetVertex , comments , unitCubeToModel ); - } - else if( Normals.value==NORMALS_GRADIENTS ) - { - auto SetVertex = []( typename VertexFactory::VertexType &v , Point< Real , Dim > p , Point< Real , Dim > g , Real w , InputSampleDataType d ){ v.template get<0>() = p , v.template get<1>() = -g/(1<() = w , v.template get<3>() = d.template get<1>(); }; - ExtractMesh( UIntPack< FEMSigs ... >() , tree , solution , isoValue , samples , sampleData , density , vertexFactory , inputSampleDataFactory() , SetVertex , comments , unitCubeToModel ); - } + if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , true , true >( auxDataFactory , InCore.set , *sInfo , meParams , Out.value , ASCII.set ); + else WriteMesh < Real , Dim , FEMSig , true , true >( InCore.set , *sInfo , meParams , Out.value , ASCII.set ); } else { - typedef Factory< Real , PositionFactory< Real , Dim > , NormalFactory< Real , Dim > , AuxDataFactory > VertexFactory; - VertexFactory vertexFactory( PositionFactory< Real , Dim >() , NormalFactory< Real , Dim >() , auxDataFactory ); - if( Normals.value==NORMALS_SAMPLES ) - { - auto SetVertex = []( typename VertexFactory::VertexType &v , Point< Real , Dim > p , Point< Real , Dim > g , Real w , InputSampleDataType d ){ v.template get<0>() = p , v.template get<1>() = d.template get<0>() , v.template get<2>() = d.template get<1>(); }; - ExtractMesh( UIntPack< FEMSigs ... >() , tree , solution , isoValue , samples , sampleData , density , vertexFactory , inputSampleDataFactory() , SetVertex , comments , unitCubeToModel ); - } - else if( Normals.value==NORMALS_GRADIENTS ) - { - auto SetVertex = []( typename VertexFactory::VertexType &v , Point< Real , Dim > p , Point< Real , Dim > g , Real w , InputSampleDataType d ){ v.template get<0>() = p , v.template get<1>() = -g/(1<() = d.template get<1>(); }; - ExtractMesh( UIntPack< FEMSigs ... >() , tree , solution , isoValue , samples , sampleData , density , vertexFactory , inputSampleDataFactory() , SetVertex , comments , unitCubeToModel ); - } + if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , true , false >( auxDataFactory , InCore.set , *sInfo , meParams , Out.value , ASCII.set ); + else WriteMesh < Real , Dim , FEMSig , true , false >( InCore.set , *sInfo , meParams , Out.value , ASCII.set ); } } else { if( Density.set ) { - typedef Factory< Real , PositionFactory< Real , Dim > , ValueFactory< Real > , AuxDataFactory > VertexFactory; - VertexFactory vertexFactory( PositionFactory< Real , Dim >() , ValueFactory< Real >() , auxDataFactory ); - auto SetVertex = []( typename VertexFactory::VertexType &v , Point< Real , Dim > p , Point< Real , Dim > g , Real w , InputSampleDataType d ){ v.template get<0>() = p , v.template get<1>() = w , v.template get<2>() = d.template get<1>(); }; - ExtractMesh( UIntPack< FEMSigs ... >() , tree , solution , isoValue , samples , sampleData , density , vertexFactory , inputSampleDataFactory() , SetVertex , comments , unitCubeToModel ); + if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , false , true >( auxDataFactory , InCore.set , *sInfo , meParams , Out.value , ASCII.set ); + else WriteMesh < Real , Dim , FEMSig , false , true >( InCore.set , *sInfo , meParams , Out.value , ASCII.set ); } else { - typedef Factory< Real , PositionFactory< Real , Dim > , AuxDataFactory > VertexFactory; - VertexFactory vertexFactory( PositionFactory< Real , Dim >() , auxDataFactory ); - auto SetVertex = []( typename VertexFactory::VertexType &v , Point< Real , Dim > p , Point< Real , Dim > g , Real w , InputSampleDataType d ){ v.template get<0>() = p , v.template get<1>() = d.template get<1>(); }; - ExtractMesh( UIntPack< FEMSigs ... >() , tree , solution , isoValue , samples , sampleData , density , vertexFactory , inputSampleDataFactory() , SetVertex , comments , unitCubeToModel ); + if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , false , false >( auxDataFactory , InCore.set , *sInfo , meParams , Out.value , ASCII.set ); + else WriteMesh < Real , Dim , FEMSig , false , false >( InCore.set , *sInfo , meParams , Out.value , ASCII.set ); } } - if( sampleData ){ delete sampleData ; sampleData = NULL; } } - if( density ) delete density , density = NULL; if( Verbose.set ) std::cout << "# Total Solve: " << Time()-startTime << " (s), " << MemoryInfo::PeakMemoryUsageMB() << " (MB)" << std::endl; + delete sInfo; } #ifndef FAST_COMPILE @@ -954,10 +569,10 @@ void Execute( const AuxDataFactory &auxDataFactory ) { switch( Degree.value ) { - case 1: return Execute< Real >( IsotropicUIntPack< Dim , FEMDegreeAndBType< 1 , BType >::Signature >() , auxDataFactory ); - case 2: return Execute< Real >( IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BType >::Signature >() , auxDataFactory ); -// case 3: return Execute< Real >( IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BType >::Signature >() , auxDataFactory ); -// case 4: return Execute< Real >( IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BType >::Signature >() , auxDataFactory ); + case 1: return Execute< Real , Dim , FEMDegreeAndBType< 1 , BType >::Signature >( auxDataFactory ); + case 2: return Execute< Real , Dim , FEMDegreeAndBType< 2 , BType >::Signature >( auxDataFactory ); +// case 3: return Execute< Real , Dim , FEMDegreeAndBType< 3 , BType >::Signature >( auxDataFactory ); +// case 4: return Execute< Real , Dim , FEMDegreeAndBType< 4 , BType >::Signature >( auxDataFactory ); default: ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); } } @@ -1032,11 +647,12 @@ int main( int argc , char* argv[] ) #endif // USE_DOUBLE #ifdef FAST_COMPILE - static const int Degree = DEFAULT_FEM_DEGREE; - static const BoundaryType BType = DEFAULT_FEM_BOUNDARY; - typedef IsotropicUIntPack< DEFAULT_DIMENSION , FEMDegreeAndBType< Degree , BType >::Signature > FEMSigs; + static const int Degree = Reconstructor::Poisson::DefaultFEMDegree; + static const BoundaryType BType = Reconstructor::Poisson::DefaultFEMBoundary; + static const unsigned int Dim = DEFAULT_DIMENSION; + static const unsigned int FEMSig = FEMDegreeAndBType< Degree , BType >::Signature; WARN( "Compiled for degree-" , Degree , ", boundary-" , BoundaryNames[ BType ] , ", " , sizeof(Real)==4 ? "single" : "double" , "-precision _only_" ); - if( !PointWeight.set ) PointWeight.value = DefaultPointWeightMultiplier*Degree; + if( !PointWeight.set ) PointWeight.value = Reconstructor::Poisson::WeightMultiplier*Degree; char *ext = GetFileExtension( In.value ); if( !strcasecmp( ext , "ply" ) ) { @@ -1049,17 +665,17 @@ int main( int argc , char* argv[] ) if( !factory.plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain normals" ); delete[] readFlags; - if( unprocessedProperties.size() ) Execute< Real >( FEMSigs() , VertexFactory::DynamicFactory< Real >( unprocessedProperties ) ); - else Execute< Real >( FEMSigs() , VertexFactory::EmptyFactory< Real >() ); + if( unprocessedProperties.size() ) Execute< Real , Dim , FEMSig >( VertexFactory::DynamicFactory< Real >( unprocessedProperties ) ); + else Execute< Real , Dim , FEMSig >( VertexFactory::EmptyFactory< Real >() ); } else { - if( Colors.set ) Execute< Real >( FEMSigs() , VertexFactory::RGBColorFactory< Real >() ); - else Execute< Real >( FEMSigs() , VertexFactory::EmptyFactory< Real >() ); + if( Colors.set ) Execute< Real , Dim , FEMSig >( VertexFactory::RGBColorFactory< Real >() ); + else Execute< Real , Dim , FEMSig >( VertexFactory::EmptyFactory< Real >() ); } delete[] ext; #else // !FAST_COMPILE - if( !PointWeight.set ) PointWeight.value = DefaultPointWeightMultiplier*Degree.value; + if( !PointWeight.set ) PointWeight.value = Reconstructor::Poisson::WeightMultiplier * Degree.value; char *ext = GetFileExtension( In.value ); if( !strcasecmp( ext , "ply" ) ) { diff --git a/Src/PoissonRecon.h b/Src/PoissonRecon.h deleted file mode 100644 index 9b938050..00000000 --- a/Src/PoissonRecon.h +++ /dev/null @@ -1,113 +0,0 @@ -/* -Copyright (c) 2023, 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 POISSON_RECON_INCLUDED -#define POISSON_RECON_INCLUDED - -#include "FEMTree.h" -#include "VertexFactory.h" - -#undef USE_DOUBLE // If enabled, double-precesion is used - -#define DATA_DEGREE 0 // 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 in the normals for constructing the Laplacian constraints -#define DEFAULT_FEM_DEGREE 1 // The default finite-element degree -#define DEFAULT_FEM_BOUNDARY BOUNDARY_NEUMANN // The default finite-element boundary type {BOUNDARY_FREE, BOUNDARY_DIRICHLET, BOUNDARY_NEUMANN} -#define DEFAULT_DIMENSION 3 // The dimension of the system - -const float DefaultPointWeightMultiplier = 2.f; - -template< unsigned int Dim , typename Real > -struct ConstraintDual -{ - Real target , weight; - ConstraintDual( void ) : target(0) , weight(0) {} - ConstraintDual( Real t , Real w ) : target(t) , weight(w) {} - CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim >& p ) const { return CumulativeDerivativeValues< Real , Dim , 0 >( target*weight ); }; -}; - -template< unsigned int Dim , typename Real > -struct SystemDual -{ - Real weight; - SystemDual( void ) : weight(0) {} - SystemDual( Real w ) : weight(w) {} - CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim >& p , const CumulativeDerivativeValues< Real , Dim , 0 >& dValues ) const { return dValues * weight; }; - CumulativeDerivativeValues< double , Dim , 0 > operator()( const Point< Real , Dim >& p , const CumulativeDerivativeValues< double , Dim , 0 >& dValues ) const { return dValues * weight; }; -}; - -template< unsigned int Dim > -struct SystemDual< Dim , double > -{ - typedef double Real; - Real weight; - SystemDual( void ) : weight(0) {} - SystemDual( Real w ) : weight(w) {} - CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim >& p , const CumulativeDerivativeValues< Real , Dim , 0 >& dValues ) const { return dValues * weight; }; -}; - -template< typename Real , unsigned int Dim , typename AuxData > -using InputOrientedPointStreamInfo = typename FEMTreeInitializer< Dim , Real >::template InputPointStream< VectorTypeUnion< Real , typename VertexFactory::NormalFactory< Real , Dim >::VertexType , AuxData > >; - -template< typename Real , unsigned int Dim , typename AuxData > -using InputOrientedPointStream = typename InputOrientedPointStreamInfo< Real , Dim , AuxData >::StreamType; - -template< typename Real , unsigned int Dim , typename AuxData > -using OutputOrientedPointStreamInfo = typename FEMTreeInitializer< Dim , Real >::template OutputPointStream< VectorTypeUnion< Real , typename VertexFactory::NormalFactory< Real , Dim >::VertexType , AuxData > >; - -template< typename Real , unsigned int Dim , typename AuxData > -using OutputOrientedPointStream = typename OutputOrientedPointStreamInfo< Real , Dim , AuxData >::StreamType; - -template< class Real , unsigned int Dim > -XForm< Real , Dim+1 > GetBoundingBoxXForm( Point< Real , Dim > min , Point< Real , Dim > max , Real scaleFactor ) -{ - Point< Real , Dim > center = ( max + min ) / 2; - Real scale = max[0] - min[0]; - for( int d=1 ; d( scale , max[d]-min[d] ); - scale *= scaleFactor; - for( int i=0 ; i tXForm = XForm< Real , Dim+1 >::Identity() , sXForm = XForm< Real , Dim+1 >::Identity(); - for( int i=0 ; i(max[maxDim]-min[maxDim]) ) maxDim = i; - XForm< Real , Dim+1 > rXForm; - for( int i=0 ; i -XForm< Real , Dim+1 > GetPointXForm( InputOrientedPointStream< Real , Dim , AuxData > &stream , typename InputOrientedPointStreamInfo< Real , Dim , AuxData >::DataType d , Real scaleFactor ) -{ - Point< Real , Dim > min , max; - InputOrientedPointStreamInfo< Real , Dim , AuxData >::BoundingBox( stream , d , min , max ); - return GetBoundingBoxXForm( min , max , scaleFactor ); -} - -#endif // POISSON_RECON_INCLUDED \ No newline at end of file diff --git a/Src/PoissonRecon.server.inl b/Src/PoissonRecon.server.inl index c40f31c4..c876f157 100644 --- a/Src/PoissonRecon.server.inl +++ b/Src/PoissonRecon.server.inl @@ -26,21 +26,23 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ +#include "DataStream.imp.h" + template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > struct Server { - typedef typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; - typedef typename FEMTree< Dim , Real >::template ApproximatePointInterpolationInfo< Real , 0 , ConstraintDual< Dim , Real > , SystemDual< Dim , Real > > ApproximatePointInterpolationInfo; + typedef typename FEMTree< Dim , Real >::template DensityEstimator< Reconstructor::WeightDegree > DensityEstimator; + typedef typename FEMTree< Dim , Real >::template ApproximatePointInterpolationInfo< Real , 0 , Reconstructor::Poisson::ConstraintDual< Dim , Real > , Reconstructor::Poisson::SystemDual< Dim , Real > > ApproximatePointInterpolationInfo; typedef IsotropicUIntPack< Dim , FEMDegreeAndBType< Degree , BType >::Signature > Sigs; typedef IsotropicUIntPack< Dim , Degree > Degrees; - typedef IsotropicUIntPack< Dim , FEMDegreeAndBType< NORMAL_DEGREE , DerivativeBoundary< BType , 1 >::BType >::Signature > NormalSigs; - static const unsigned int DataSig = FEMDegreeAndBType< DATA_DEGREE , BOUNDARY_FREE >::Signature; + typedef IsotropicUIntPack< Dim , FEMDegreeAndBType< Reconstructor::Poisson::NormalDegree , DerivativeBoundary< BType , 1 >::BType >::Signature > NormalSigs; + static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; typedef VertexFactory::DynamicFactory< Real > AuxDataFactory; + typedef typename AuxDataFactory::VertexType AuxData; typedef VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::Factory< Real , VertexFactory::NormalFactory< Real , Dim > , AuxDataFactory > > InputSampleFactory; typedef VertexFactory::Factory< Real , VertexFactory::NormalFactory< Real , Dim > , AuxDataFactory > InputSampleDataFactory; - typedef InputOrientedPointStreamInfo< Real , Dim , typename AuxDataFactory::VertexType > InputPointStreamInfo; - typedef typename InputPointStreamInfo::PointAndDataType InputSampleType; - typedef typename InputPointStreamInfo::DataType InputSampleDataType; + typedef VectorTypeUnion< Real , Point< Real , Dim > , typename AuxDataFactory::VertexType > InputSampleDataType; + typedef VectorTypeUnion< Real , Point< Real , Dim > , InputSampleDataType > InputSampleType; typedef InputDataStream< InputSampleType > InputPointStream; typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; @@ -54,10 +56,10 @@ protected: FEMTree< Dim , Real > tree; DenseNodeData< Real , Sigs > constraints , solution; ApproximatePointInterpolationInfo *iInfo; - SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > *dataField; + SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > > *auxDataField; - _State4( void ) : tree( MEMORY_ALLOCATOR_BLOCK_SIZE ) , iInfo(NULL) , dataField(NULL) {} - ~_State4( void ){ delete iInfo ; delete dataField; } + _State4( void ) : tree( MEMORY_ALLOCATOR_BLOCK_SIZE ) , iInfo(NULL) , auxDataField(NULL) {} + ~_State4( void ){ delete iInfo ; delete auxDataField; } }; struct _State6 { @@ -66,7 +68,7 @@ protected: FEMTree< Dim-1 , Real > *sliceTree; XForm< Real , Dim > xForm; DenseNodeData< Real , SliceSigs > solution , dSolution; - std::vector< typename LevelSetExtractor< Dim-1 , Real , Vertex >::SliceValues > sliceValues , dSliceValues; + std::vector< typename LevelSetExtractor< Real , Dim-1 >::SliceValues > sliceValues , dSliceValues; std::vector< Point< Real , Dim-1 > > vertices; _State6( void ) : sliceTree(NULL) {} @@ -84,7 +86,7 @@ protected: template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > -static std::vector< unsigned int > RunServer +std::vector< unsigned int > RunServer ( PointPartition::PointSetInfo< Real , Dim > pointSetInfo , PointPartition::Partition pointPartition , @@ -265,9 +267,9 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase2( const ClientReconstruc template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > PhaseInfo Server< Real , Dim , BType , Degree >::_phase4( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , ProjectiveData< Real , Real > cumulativePointWeight , unsigned int baseVCycles , Real &isoValue , Profiler &profiler ) { - constexpr int MAX_DEGREE = NORMAL_DEGREE > Degrees::Max() ? NORMAL_DEGREE : Degrees::Max(); - const int StartOffset = BSplineSupportSizes< MAX_DEGREE >::SupportStart; - const int EndOffset = BSplineSupportSizes< MAX_DEGREE >::SupportEnd+1; + constexpr int MaxDegree = Reconstructor::Poisson::NormalDegree > Degrees::Max() ? Reconstructor::Poisson::NormalDegree : Degrees::Max(); + const int StartOffset = BSplineSupportSizes< MaxDegree >::SupportStart; + const int EndOffset = BSplineSupportSizes< MaxDegree >::SupportEnd+1; PhaseInfo phaseInfo; _State4 state4; @@ -283,7 +285,7 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase4( const ClientReconstruc // Set the root of the tree so we can copy constraints into it auto addNodeFunctor = [&]( int d , const int off[Dim] ){ return d<=(int)clientReconInfo.baseDepth; }; - state4.tree.template finalizeForMultigrid< MAX_DEGREE , Degrees::Max() >( clientReconInfo.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple() , std::make_tuple() ); + state4.tree.template finalizeForMultigrid< MaxDegree , Degrees::Max() >( clientReconInfo.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple() , std::make_tuple() ); phaseInfo.processTime += timer.wallTime(); profiler.update(); } @@ -332,10 +334,10 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase4( const ClientReconstruc { Timer timer; - constexpr int MAX_DEGREE = NORMAL_DEGREE > Degrees::Max() ? NORMAL_DEGREE : Degrees::Max(); + constexpr int MaxDegree = Reconstructor::Poisson::NormalDegree > Degrees::Max() ? Reconstructor::Poisson::NormalDegree : Degrees::Max(); auto hasDataFunctor = []( const FEMTreeNode * ){ return true; }; auto addNodeFunctor = [&]( int d , const int off[Dim] ){ return d<=(int)clientReconInfo.baseDepth; }; - std::vector< node_index_type > newToOld = state4.tree.template finalizeForMultigrid< MAX_DEGREE , Degrees::Max() >( clientReconInfo.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple() , std::make_tuple() ); + std::vector< node_index_type > newToOld = state4.tree.template finalizeForMultigrid< MaxDegree , Degrees::Max() >( clientReconInfo.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple() , std::make_tuple() ); node_index_type idx = newToOld[0]; for( unsigned int i=0 ; i( idx , newToOld[i] ); idx++; @@ -354,7 +356,7 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase4( const ClientReconstruc { Real targetValue = (Real)0.5; - state4.iInfo = new ApproximatePointInterpolationInfo( ConstraintDual< Dim , Real >( targetValue , clientReconInfo.pointWeight * cumulativePointWeight.value() ) , SystemDual< Dim , Real >( clientReconInfo.pointWeight * cumulativePointWeight.value() ) , true ); + state4.iInfo = new ApproximatePointInterpolationInfo( Reconstructor::Poisson::ConstraintDual< Dim , Real >( targetValue , clientReconInfo.pointWeight * cumulativePointWeight.value() ) , Reconstructor::Poisson::SystemDual< Dim , Real >( clientReconInfo.pointWeight * cumulativePointWeight.value() ) , true ); state4.iInfo->iData.reserve( state4.tree.nodesSize() ); } @@ -364,8 +366,8 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase4( const ClientReconstruc if( needAuxData ) { - state4.dataField = new SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > >(); - state4.dataField->reserve( state4.tree.nodesSize() ); + state4.auxDataField = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >(); + state4.auxDataField->reserve( state4.tree.nodesSize() ); } phaseInfo.processTime += timer.wallTime(); profiler.update(); @@ -403,21 +405,21 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase4( const ClientReconstruc if( needAuxData ) { Timer timer; - SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > *_dataField; + SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > > *_auxDataField; if( !auxDataFactory.isStaticallyAllocated() ) { - ProjectiveSampleDataTypeSerializer< Real , Dim > serializer( clientReconInfo.auxProperties ); - _dataField = new SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > >( clientStream , serializer ); + ProjectiveAuxDataTypeSerializer< Real > serializer( clientReconInfo.auxProperties ); + _auxDataField = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( clientStream , serializer ); } - else _dataField = new SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > >( clientStream ); + else _auxDataField = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( clientStream ); phaseInfo.readTime += timer.wallTime(); timer = Timer(); - state4.dataField->mergeFromTarget( *_dataField , [&]( unsigned int idx ){ return clientToServer[idx]; } ); + state4.auxDataField->mergeFromTarget( *_auxDataField , [&]( unsigned int idx ){ return clientToServer[idx]; } ); phaseInfo.processTime += timer.wallTime(); profiler.update(); - delete _dataField; + delete _auxDataField; } else profiler.update(); phaseInfo.readBytes += clientStream.ioBytes; @@ -428,7 +430,7 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase4( const ClientReconstruc Timer timer; auto nodeFunctor = [&]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* n ) { - ProjectiveData< InputSampleDataType , Real >* clr = state4.dataField->operator()( n ); + ProjectiveData< AuxData , Real >* clr = state4.auxDataField->operator()( n ); if( clr ) (*clr) *= (Real)pow( clientReconInfo.dataX , state4.tree.depth( n ) ); }; state4.tree.tree().processNodes( nodeFunctor ); @@ -527,23 +529,23 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase4( const ClientReconstruc if( needAuxData ) { Timer timer; - SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > _dataField; - _dataField.reserve( count ); + SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > > _auxDataField; + _auxDataField.reserve( count ); for( size_t i=0 ; i *data = state4.dataField->operator()( node ); - if( data ) _dataField[ subNodes+i ] = *data; + ProjectiveData< AuxData , Real > *data = state4.auxDataField->operator()( node ); + if( data ) _auxDataField[ subNodes+i ] = *data; } phaseInfo.processTime += timer.wallTime(); timer = Timer(); if( !auxDataFactory.isStaticallyAllocated() ) { - ProjectiveSampleDataTypeSerializer< Real , Dim > serializer( clientReconInfo.auxProperties ); - _dataField.write( clientStream , serializer ); + ProjectiveAuxDataTypeSerializer< Real > serializer( clientReconInfo.auxProperties ); + _auxDataField.write( clientStream , serializer ); } - else _dataField.write( clientStream ); + else _auxDataField.write( clientStream ); phaseInfo.writeTime += timer.wallTime(); } profiler.update(); @@ -690,15 +692,21 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase6( const ClientReconstruc using Factory = VertexFactory::EmptyFactory< Real >; using Data = typename Factory::VertexType; Factory factory; - const typename FEMTree< Dim-1 , Real >::template DensityEstimator< WEIGHT_DEGREE > *density=NULL; + const typename FEMTree< Dim-1 , Real >::template DensityEstimator< Reconstructor::WeightDegree > *density=NULL; const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim-1 , DataSig > > *data=NULL; - auto SetVertex = []( Vertex &v , Point< Real , Dim-1 > p , Point< Real , Dim-1 > g , Real w , Data d ){ v = p; }; { - VectorStreamingVertices< Point< Real , Dim-1 > , node_index_type > _vertices; - LevelSetExtractor< Dim-1 , Real , Vertex >::template SetSliceValues< Data >( SliceSigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , *state6.sliceTree , clientReconInfo.reconstructionDepth , density , data , state6.solution , isoValue , &_vertices , factory() , SetVertex , !clientReconInfo.linearFit , false , state6.sliceValues , LevelSetExtractor< Dim-1 , Real , Vertex >::SetIsoEdgesFlag() ); - if( !clientReconInfo.linearFit ) LevelSetExtractor< Dim-1 , Real , Vertex >::template SetSliceValues< Data >( SliceSigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , *state6.sliceTree , clientReconInfo.reconstructionDepth , density , data , state6.dSolution , isoValue , &_vertices , factory() , SetVertex , false , false , state6.dSliceValues , LevelSetExtractor< Dim-1 , Real , Vertex >::SetCornerValuesFlag() ); - state6.vertices.resize( _vertices.vertexNum() ); - for( unsigned int j=0 ; j<_vertices.vertexNum() ; j++ ) state6.vertices[j] = _vertices.vertex(j); + VectorBackedOutputDataStream< Point< Real , Dim-1 > > _vertices( state6.vertices ); + struct VertexStreamWrapper : public Reconstructor::OutputVertexStreamWrapper< Real , Dim-1 , Point< Real , Dim-1 > > + { + typedef Point< Real , Dim-1 > Vertex; + VertexStreamWrapper( OutputDataStream< Vertex > &stream , Vertex out ) : + Reconstructor::OutputVertexStreamWrapper< Real , Dim-1 , Point< Real , Dim-1 > >( stream , out ) {} + void set( Vertex &out , const Reconstructor::BaseVertex< Real , Dim-1 > &in ){ out = in.template get<0>(); } + }; + VertexStreamWrapper __vertexStream( _vertices , Point< Real , Dim-1 >() ); + + LevelSetExtractor< Real , Dim-1 >::SetSliceValues( SliceSigs() , UIntPack< Reconstructor::WeightDegree >() , *state6.sliceTree , clientReconInfo.reconstructionDepth , density , state6.solution , isoValue , __vertexStream , !clientReconInfo.linearFit , false , state6.sliceValues , LevelSetExtractor< Real , Dim-1 , Vertex >::SetIsoEdgesFlag() ); + if( !clientReconInfo.linearFit ) LevelSetExtractor< Real , Dim-1 >::SetSliceValues( SliceSigs() , UIntPack< Reconstructor::WeightDegree >() , *state6.sliceTree , clientReconInfo.reconstructionDepth , density , state6.dSolution , isoValue , __vertexStream , false , false , state6.dSliceValues , LevelSetExtractor< Real , Dim-1 , Vertex >::SetCornerValuesFlag() ); } sharedVertexCounts[i] = (unsigned int)state6.vertices.size(); phaseInfo.processTime += timer.wallTime(); @@ -715,7 +723,7 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase6( const ClientReconstruc clientStream1.write( isoValue ); if( clientReconInfo.mergeType!=ClientReconstructionInfo< Real , Dim >::MergeType::NONE ) { - LevelSetExtractor< Dim-1 , Real , Vertex >::TreeSliceValuesAndVertexPositions::Write( clientStream0 , state6.sliceTree , state6.xForm , state6.sliceValues , state6.vertices , true ); + LevelSetExtractor< Real , Dim-1 >::TreeSliceValuesAndVertexPositions::Write( clientStream0 , state6.sliceTree , state6.xForm , state6.sliceValues , state6.vertices , true ); if( !clientReconInfo.linearFit ) { for( unsigned int i=0 ; i::_phase6( const ClientReconstruc clientStream0.write( state6.dSliceValues[i].cornerValues , state6.dSliceValues[i].cellIndices.counts[0] ); } } - LevelSetExtractor< Dim-1 , Real , Vertex >::TreeSliceValuesAndVertexPositions::Write( clientStream1 , state6.sliceTree , state6.xForm , state6.sliceValues , state6.vertices , true ); + LevelSetExtractor< Real , Dim-1 >::TreeSliceValuesAndVertexPositions::Write( clientStream1 , state6.sliceTree , state6.xForm , state6.sliceValues , state6.vertices , true ); if( !clientReconInfo.linearFit ) { for( unsigned int i=0 ; i #include #include "MyMiscellany.h" -#include "PoissonRecon.h" +#include "Reconstructors.h" #include "CmdLineParser.h" +#define DEFAULT_DIMENSION 3 + cmdLineParameter< std::string > Address( "address" , "127.0.0.1" ); @@ -185,7 +187,7 @@ int main( int argc , char* argv[] ) Partition< Real , Dim >( serverSockets ); #ifdef FAST_COMPILE - Reconstruct< Real , Dim , DEFAULT_FEM_BOUNDARY , DEFAULT_FEM_DEGREE >( serverSockets ); + Reconstruct< Real , Dim , Reconstructor::Poisson::DefaultFEMBoundary , Reconstructor::Poisson::DefaultFEMDegree >( serverSockets ); #else // !FAST_COMPILE Reconstruct< Real , Dim >( serverSockets ); #endif // FAST_COMPILE diff --git a/Src/PoissonReconClientServer.h b/Src/PoissonReconClientServer.h index d1b92d6f..c017bc6f 100644 --- a/Src/PoissonReconClientServer.h +++ b/Src/PoissonReconClientServer.h @@ -38,7 +38,7 @@ DAMAGE. #include "FEMTree.h" #include "VertexFactory.h" #include "Socket.h" -#include "PoissonRecon.h" +#include "Reconstructors.h" namespace PoissonReconClientServer { diff --git a/Src/PoissonReconClientServer.inl b/Src/PoissonReconClientServer.inl index 1da6f7cc..c96fcea3 100644 --- a/Src/PoissonReconClientServer.inl +++ b/Src/PoissonReconClientServer.inl @@ -26,6 +26,52 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ +template< typename Real > +using AuxDataType = typename VertexFactory::DynamicFactory< Real >::VertexType; + +template< typename Real > +struct AuxDataTypeSerializer : public Serializer< AuxDataType< Real > > +{ + AuxDataTypeSerializer( const std::vector< PlyProperty > &properties ) : _factory( properties ){} + + size_t size( void ) const { return _factory.bufferSize(); } + + void serialize( const AuxDataType< Real > &data , Pointer( char )buffer ) const + { + _factory.toBuffer( data , buffer ); + } + void deserialize( ConstPointer( char ) buffer , AuxDataType< Real > &data ) const + { + data = _factory(); + _factory.fromBuffer( buffer , data ); + } +protected: + VertexFactory::DynamicFactory< Real > _factory; +}; + +template< typename Real > +struct ProjectiveAuxDataTypeSerializer : public Serializer< ProjectiveData< AuxDataType< Real > , Real > > +{ + using Data = ProjectiveData< AuxDataType< Real > , Real >; + + ProjectiveAuxDataTypeSerializer( const std::vector< PlyProperty > &properties ) : _factory( properties ){} + + size_t size( void ) const { return sizeof( Real ) + _factory.bufferSize(); } + + void serialize( const Data &data , Pointer( char )buffer ) const + { + memcpy( buffer , &data.weight , sizeof(Real) ); + _factory.toBuffer( data.data , buffer+sizeof(Real) ); + } + void deserialize( ConstPointer( char ) buffer , Data &data ) const + { + data.data = _factory(); + memcpy( &data.weight , buffer , sizeof(Real) ); + _factory.fromBuffer( buffer+sizeof(Real) , data.data ); + } +protected: + VertexFactory::DynamicFactory< Real > _factory; +}; template< typename Real , unsigned int Dim > using SampleDataType = VectorTypeUnion< Real , typename VertexFactory::NormalFactory< Real , Dim >::VertexType , typename VertexFactory::DynamicFactory< Real >::VertexType >; diff --git a/Src/PoissonReconServer.cpp b/Src/PoissonReconServer.cpp index 403072ee..a2e8e870 100644 --- a/Src/PoissonReconServer.cpp +++ b/Src/PoissonReconServer.cpp @@ -39,8 +39,20 @@ DAMAGE. #include #include "MyMiscellany.h" #include "CmdLineParser.h" -#include "PoissonRecon.h" +#include "Reconstructors.h" +#define DEFAULT_DIMENSION 3 + +enum MergeSlabType +{ + NONE , + FUNCTION , // Identical functions across slice + TOPOLOGY_AND_FUNCTION , // Identical topologies across slice + SEAMLESS , // Merge across the shared slice + COUNT +}; + +const std::string MergeSlabNames[] = { "none" , "function" , "topology" , "seamless" }; cmdLineParameter< std::string > AddressPrefix( "prefix" ) , @@ -54,8 +66,8 @@ cmdLineParameter< int > Verbose( "verbose" , 0 ) , #ifdef FAST_COMPILE #else // !FAST_COMPILE - Degree( "degree" , DEFAULT_FEM_DEGREE ) , - BType( "bType" , DEFAULT_FEM_BOUNDARY ) , + Degree( "degree" , Reconstructor::Poisson::DefaultFEMDegree ) , + BType( "bType" , Reconstructor::Poisson::DefaultFEMBoundary ) , #endif // FAST_COMPILE Iters( "iters" , 8 ) , BaseVCycles( "vCycles" , 1 ) , @@ -76,6 +88,7 @@ cmdLineParameter< int > #endif // _OPENMP ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , + MergeSlabs( "merge" , MergeSlabType::SEAMLESS ) , Threads( "threads" , (int)std::thread::hardware_concurrency() ) ; cmdLineReadable @@ -85,7 +98,6 @@ cmdLineReadable LinearFit( "linearFit" ) , OutputVoxelGrid( "grid" ) , OutputBoundarySlices( "boundary" ) , - NoFuse( "noFuse" ) , ShowDiscontinuity( "showDiscontinuity" ); cmdLineParameter< float > @@ -114,7 +126,7 @@ cmdLineReadable* params[] = &Iters , &BaseVCycles , &KernelDepth , &BaseDepth , &PadSize , &BufferSize , &Depth , &SolveDepth , &NoLoadBalance , &Density , &LinearFit , - &NoFuse , + &MergeSlabs , &Width , &Confidence , &ConfidenceBias , &SamplesPerNode , &DataX , &PointWeight , &CGSolverAccuracy , &MaxMemoryGB , &ParallelType , &ScheduleType , &ThreadChunkSize , &Threads , &PeakMemorySampleMS , @@ -152,7 +164,7 @@ void ShowUsage( char* ex ) printf( "\t[--%s =%d]\n" , Iters.name , Iters.value ); printf( "\t[--%s =%d]\n" , BaseVCycles.name , BaseVCycles.value ); printf( "\t[--%s =%g]\n" , CGSolverAccuracy.name , CGSolverAccuracy.value ); - printf( "\t[--%s =%.3e * ]\n" , PointWeight.name , DefaultPointWeightMultiplier ); + printf( "\t[--%s =%.3e * ]\n" , PointWeight.name , Reconstructor::Poisson::WeightMultiplier ); printf( "\t[--%s =%f]\n" , Confidence.name , Confidence.value ); printf( "\t[--%s =%f]\n" , ConfidenceBias.name , ConfidenceBias.value ); printf( "\t[--%s =%f]\n" , DataX.name , DataX.value ); @@ -167,6 +179,8 @@ void ShowUsage( char* ex ) printf( "\t[--%s =%d]\n" , PeakMemorySampleMS.name , PeakMemorySampleMS.value ); printf( "\t[--%s =%d]\n" , MaxMemoryGB.name , MaxMemoryGB.value ); printf( "\t[--%s =%u]\n" , FilesPerDir.name , (unsigned int)FilesPerDir.value ); + printf( "\t[--%s =%d]\n" , MergeSlabs.name , MergeSlabs.value ); + for( unsigned int i=0 ; i=%d]\n" , Verbose.name , Verbose.value ); printf( "\t[--%s]\n" , NoLoadBalance.name ); printf( "\t[--%s]\n" , Density.name ); @@ -174,7 +188,6 @@ void ShowUsage( char* ex ) printf( "\t[--%s]\n" , OutputVoxelGrid.name ); printf( "\t[--%s]\n" , OutputBoundarySlices.name ); printf( "\t[--%s]\n" , ShowDiscontinuity.name ); - printf( "\t[--%s]\n" , NoFuse.name ); printf( "\t[--%s]\n" , Performance.name ); } @@ -344,9 +357,9 @@ int main( int argc , char* argv[] ) } #ifdef FAST_COMPILE - if( !PointWeight.set ) PointWeight.value = DefaultPointWeightMultiplier * DEFAULT_FEM_DEGREE; + if( !PointWeight.set ) PointWeight.value = Reconstructor::Poisson::WeightMultiplier * Reconstructor::Poisson::DefaultFEMDegree; #else // !FAST_COMPILE - if( !PointWeight.set ) PointWeight.value = DefaultPointWeightMultiplier * Degree.value; + if( !PointWeight.set ) PointWeight.value = Reconstructor::Poisson::WeightMultiplier * Degree.value; #endif // FAST_COMPILE if( Depth.set && Width.value>0 ) @@ -433,7 +446,12 @@ int main( int argc , char* argv[] ) clientReconInfo.dataX = DataX.value; clientReconInfo.density = Density.set; clientReconInfo.linearFit = LinearFit.set; - PoissonReconClientServer::ClientReconstructionInfo< Real , Dim >::MergeType::TOPOLOGY_AND_FUNCTION; + switch( MergeSlabs.value ) + { + case MergeSlabType::NONE: clientReconInfo.mergeType = PoissonReconClientServer::ClientReconstructionInfo< Real , Dim >::MergeType::NONE ; break; + case MergeSlabType::FUNCTION: clientReconInfo.mergeType = PoissonReconClientServer::ClientReconstructionInfo< Real , Dim >::MergeType::FUNCTION ; break; + default: clientReconInfo.mergeType = PoissonReconClientServer::ClientReconstructionInfo< Real , Dim >::MergeType::TOPOLOGY_AND_FUNCTION; + } clientReconInfo.ouputVoxelGrid = OutputVoxelGrid.set; clientReconInfo.verbose = Verbose.value; clientReconInfo.filesPerDir = FilesPerDir.value; @@ -474,21 +492,27 @@ int main( int argc , char* argv[] ) clientReconInfo.solveDepth = clientReconInfo.baseDepth; } #ifdef FAST_COMPILE - sharedVertexCounts = Reconstruct< Real , Dim , DEFAULT_FEM_BOUNDARY , DEFAULT_FEM_DEGREE >( pointSetInfoAndPartition.first , pointSetInfoAndPartition.second , clientSockets , clientReconInfo ); + sharedVertexCounts = Reconstruct< Real , Dim , Reconstructor::Poisson::DefaultFEMBoundary , Reconstructor::Poisson::DefaultFEMDegree >( pointSetInfoAndPartition.first , pointSetInfoAndPartition.second , clientSockets , clientReconInfo ); #else // !FAST_COMPILE sharedVertexCounts = Reconstruct< Real , Dim >( (BoundaryType)BType.value , Degree.value , pointSetInfoAndPartition.first , pointSetInfoAndPartition.second , clientSockets , clientReconInfo ); #endif // FAST_COMPILE } - if( Verbose.value>1 && !NoFuse.set ) + if( Verbose.value>1 && ( MergeSlabs.value==MergeSlabType::SEAMLESS || MergeSlabs.value==MergeSlabType::TOPOLOGY_AND_FUNCTION ) ) for( unsigned int i=0 ; i vFactory; + for( unsigned int i=0 ; i( sharedVertexCounts , header , clientSockets , clientMergePlyInfo ); diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index cd1f1f75..411d6000 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -45,7 +45,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define VERSION "14.02" // The version of the code +#define VERSION "15.00" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file diff --git a/Src/Reconstruction.example.cpp b/Src/Reconstruction.example.cpp new file mode 100644 index 00000000..4915486e --- /dev/null +++ b/Src/Reconstruction.example.cpp @@ -0,0 +1,352 @@ +/* +Copyright (c) 2023, 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. +*/ + +#include "PreProcessor.h" +#include "Reconstructors.h" + +#include +#include +#include +#include +#include +#include +#include "MyMiscellany.h" +#include "CmdLineParser.h" + +cmdLineParameter< char* > Out( "out" ); +cmdLineReadable SSDReconstruction( "ssd" ) , UseColor( "color" ) , Verbose( "verbose" ); +cmdLineParameter< int > Depth( "depth" , 8 ) , SampleNum( "samples" , 100000 ); + +cmdLineReadable* params[] = { &Out , &SSDReconstruction , &UseColor , &Verbose , &Depth , &SampleNum , NULL }; + +void ShowUsage( char* ex ) +{ + printf( "Usage: %s\n" , ex ); + printf( "\t --%s \n" , SampleNum.name ); + printf( "\t[--%s ]\n" , Out.name ); + printf( "\t[--%s =%d]\n" , Depth.name , Depth.value ); + printf( "\t[--%s]\n" , UseColor.name ); + printf( "\t[--%s]\n" , SSDReconstruction.name ); + printf( "\t[--%s]\n" , Verbose.name ); +} + +// A simple structure for representing colors. +// Assuming values are in the range [0,1]. +template< typename Real > +struct RGBColor +{ + // The channels + RGBColor( Real r=0 , Real g=0 , Real b=0 ) : r(r) , g(g) , b(b){} + Real r,g,b; + + // Methods supporting affine re-combination + RGBColor &operator += ( const RGBColor &c ){ r += c.r , g += c.g , b += c.b ; return *this; } + RGBColor &operator *= ( Real s ){ r *= s , g *= s , b *= s ; return *this; } + RGBColor &operator /= ( Real s ){ return operator *= (1/s); } + + RGBColor operator + ( const RGBColor &c ) const { return RGBColor( r+c.r , g+c.g , b+c.b ); } + RGBColor operator * ( Real s ) const { return RGBColor( r*s , g*s , b*s ); } + RGBColor operator / ( Real s ) const { return operator * (1/s); } +}; + +// A stream for generating random samples on the sphere +template< typename Real , unsigned int Dim > +struct SphereSampleStream : public Reconstructor::InputSampleStream< Real , Dim > +{ + // from https://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution + std::random_device randomDevice; + std::default_random_engine generator; + std::uniform_real_distribution< Real > distribution; + + // Constructs a stream that contains the specified number of samples + SphereSampleStream( unsigned int sz ) : _size(sz) , _current(0) , generator(0) , distribution((Real)-1.0,(Real)1.0) {} + + // Overrides the pure abstract method from InputSampleStream< Real , Dim > + void reset( void ){ generator.seed(0) ; _current = 0; } + + // Overrides the pure abstract method from InputSampleStream< Real , Dim > + bool base_read( Point< Real , Dim > &p , Point< Real , Dim > &n ) + { + if( _current<_size ) + { + p = n = RandomSpherePoint( generator , distribution ); + _current++; + return true; + } + else return false; + } + + static Point< Real , Dim > RandomSpherePoint( std::default_random_engine &generator , std::uniform_real_distribution< Real > &distribution ) + { + while( true ) + { + Point< Real , Dim > p; + for( unsigned int d=0 ; d::SquareNorm( p )<1 ) return p / (Real)sqrt( Point< Real , Dim >::SquareNorm(p) ); + } + } +protected: + unsigned int _size , _current; +}; + +// A stream for generating random samples with color on the sphere +template< typename Real , unsigned int Dim > +struct SphereSampleWithColorStream : public Reconstructor::InputSampleWithDataStream< Real , Dim , RGBColor< Real > > +{ + // from https://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution + std::random_device randomDevice; + std::default_random_engine generator; + std::uniform_real_distribution< Real > distribution; + + // Constructs a stream that contains the specified number of samples + SphereSampleWithColorStream( unsigned int sz ) : + _size(sz) , _current(0) , generator(0) , distribution((Real)-1.0,(Real)1.0) , + Reconstructor::InputSampleWithDataStream< Real , Dim , RGBColor< Real > >( RGBColor< Real >() ) {} + + // Overrides the pure abstract method from InputSampleWithDataStream< Real , Dim , RGBColor< Real > > + void reset( void ){ generator.seed(0) ; _current = 0; } + + // Overrides the pure abstract method from InputSampleWithDataStream< Real , Dim , RGBColor< Real > > + bool base_read( Point< Real , Dim > &p , Point< Real , Dim > &n , RGBColor< Real > &c ) + { + if( _current<_size ) + { + p = n = RandomSpherePoint( generator , distribution ); + _current++; + c.r = c.g = c.b = 0; + if ( p[0]<-1.f/3 ) c.r = 1.f; + else if( p[0]< 1.f/3 ) c.g = 1.f; + else c.b = 1.f; + return true; + } + else return false; + } + + static Point< Real , Dim > RandomSpherePoint( std::default_random_engine &generator , std::uniform_real_distribution< Real > &distribution ) + { + while( true ) + { + Point< Real , Dim > p; + for( unsigned int d=0 ; d::SquareNorm( p )<1 ) return p / (Real)sqrt( Point< Real , Dim >::SquareNorm(p) ); + } + } +protected: + unsigned int _size , _current; +}; + +// A stream into which we can write polygons of the form std::vector< node_index_type > +template< typename Index > +struct PolygonStream : public Reconstructor::OutputPolygonStream +{ + // Construct a stream that adds polygons to the vector of polygons + PolygonStream( std::vector< std::vector< Index > > &polygonStream ) : _polygons( polygonStream ) {} + + // Override the pure abstract method from OutputPolygonStream + void base_write( const std::vector< node_index_type > &polygon ) + { + std::vector< Index > poly( polygon.size() ); + for( unsigned int i=0 ; i > &_polygons; +}; + +// A stream into which we can write the output vertices of the extracted mesh +template< typename Real , unsigned int Dim > +struct VertexStream : public Reconstructor::OutputVertexStream< Real , Dim > +{ + // Construct a stream that adds vertices into the coordinates + VertexStream( std::vector< Real > &vCoordinates ) : _vCoordinates( vCoordinates ) {} + + // Override the pure abstract method from Reconstructor::OutputVertexStream< Real , Dim > + void base_write( Point< Real , Dim > p , Point< Real , Dim > , Real ){ for( unsigned int d=0 ; d &_vCoordinates; +}; + +// A stream into which we can write the output vertices and colors of the extracted mesh +template< typename Real , unsigned int Dim > +struct VertexWithColorStream : public Reconstructor::OutputVertexWithDataStream< Real , Dim , RGBColor< Real > > +{ + // Construct a stream that adds vertices into the coordinates + VertexWithColorStream( std::vector< Real > &vCoordinates , std::vector< Real > &rgbCoordinates ) : + _vCoordinates( vCoordinates ) , _rgbCoordinates( rgbCoordinates ) {} + + // Override the pure abstract methodfrom Reconstructor::OutputVertexWithColorStream< Real , Dim > + void base_write( Point< Real , Dim > p , Point< Real , Dim > , Real , RGBColor< Real > c ) + { + for( unsigned int d=0 ; d &_vCoordinates; + std::vector< Real > &_rgbCoordinates; +}; + +template< typename Real > +void WritePly( std::string fileName , size_t vNum , const Real *vCoordinates , const Real *rgbCoordinates , const std::vector< std::vector< int > > &polygons ) +{ + std::fstream file( fileName , std::ios::out ); + file << "ply" << std::endl; + file << "format ascii 1.0" << std::endl; + file << "element vertex " << vNum << std::endl; + file << "property float x" << std::endl << "property float y" << std::endl << "property float z" << std::endl; + if( rgbCoordinates ) file << "property uchar red" << std::endl << "property uchar green" << std::endl << "property uchar blue" << std::endl; + file << "element face " << polygons.size() << std::endl; + file << "property list uchar int vertex_indices" << std::endl; + file << "end_header" << std::endl; + + auto ColorChannel = []( Real v ){ return std::max( 0 , std::min( 255 , (int)floor(255*v+0.5) ) ); }; + + for( size_t i=0 ; i +void Execute( void ) +{ + // Parameters for performing the reconstruction + typename std::conditional + < + SSD , + typename Reconstructor:: SSD::SolutionParameters< Real > , + typename Reconstructor::Poisson::SolutionParameters< Real > + >::type solverParams; + + solverParams.verbose = Verbose.set; + solverParams.depth = (unsigned int)Depth.value; + + // Parameters for exracting the level-set surface + typename Reconstructor::MeshExtractionParameters extractionParams; + extractionParams.linearFit = SSD; // Since the SSD solution approximates a TSDF, linear fitting works well + extractionParams.verbose = Verbose.set; + + if( UseColor.set ) + { + // Storage for the reconstruction information + Reconstructor::ReconstructionInfo< Real , Dim , FEMSig , RGBColor< Real > > *reconstructionInfo = NULL; + + // A stream generating random points on the sphere with color + SphereSampleWithColorStream< Real , Dim > sampleStream( SampleNum.value ); + + // Compute the reconstruction coefficients + if constexpr( SSD ) reconstructionInfo = Reconstructor:: SSD::Solve< Real , Dim , FEMSig , RGBColor< Real > >( sampleStream , solverParams ); + else reconstructionInfo = Reconstructor::Poisson::Solve< Real , Dim , FEMSig , RGBColor< Real > >( sampleStream , solverParams ); + + // Scale the color information to give extrapolation preference to data at finer depths + reconstructionInfo->weightAuxDataByDepth( (Real)32. ); + + // vectors for storing the polygons (specifically, triangles), the coordinates of the vertices, and the colors at the vertices + std::vector< std::vector< int > > polygons; + std::vector< Real > vCoordinates , rgbCoordinates; + + // Streams backed by these vectors + VertexWithColorStream< Real , Dim > vStream( vCoordinates , rgbCoordinates ); + PolygonStream< int > pStream( polygons ); + + // Extract the iso-surface + Reconstructor::ExtractMesh< Real , Dim , FEMSig , RGBColor< Real > >( *reconstructionInfo , vStream , pStream , extractionParams ); + + if( Out.set ) WritePly( Out.value , vStream.size() , &vCoordinates[0] , &rgbCoordinates[0] , polygons ); + + delete reconstructionInfo; + } + else + { + // Storage for the reconstruction information + Reconstructor::ReconstructionInfo< Real , Dim , FEMSig > *reconstructionInfo = NULL; + + // A stream generating random points on the sphere + SphereSampleStream< Real , Dim > sampleStream( SampleNum.value ); + + // Compute the reconstruction coefficients + if constexpr( SSD ) reconstructionInfo = Reconstructor:: SSD::Solve< Real , Dim , FEMSig >( sampleStream , solverParams ); + else reconstructionInfo = Reconstructor::Poisson::Solve< Real , Dim , FEMSig >( sampleStream , solverParams ); + + // vectors for storing the polygons (specifically, triangles) and the coordinates of the vertices + std::vector< std::vector< int > > polygons; + std::vector< Real > vCoordinates; + + // Streams backed by these vectors + PolygonStream< int > pStream( polygons ); + VertexStream< Real , Dim > vStream( vCoordinates ); + + // Extract the iso-surface + Reconstructor::ExtractMesh< Real , Dim , FEMSig >( *reconstructionInfo , vStream , pStream , extractionParams ); + + if( Out.set ) WritePly( Out.value , vStream.size() , &vCoordinates[0] , (Real*)NULL , polygons ); + + delete reconstructionInfo; + } +} + +int main( int argc , char* argv[] ) +{ + using namespace Reconstructor; + + Timer timer; + cmdLineParse( argc-1 , &argv[1] , params ); +#ifdef _OPENMP + ThreadPool::Init( ThreadPool::OPEN_MP , std::thread::hardware_concurrency() ); +#else // !_OPENMP + ThreadPool::Init( ThreadPool::THREAD_POOL , std::thread::hardware_concurrency() ); +#endif // _OPENMP + + if( !SampleNum.set ) + { + ShowUsage( argv[0] ); + return 0; + } + + // Solve using single float precision, in dimension 3, w/ finite-elements of degree 2 for SSD and degree 1 for Poisson, and using Neumann boundaries + if( SSDReconstruction.set ) Execute< float , 3 , FEMDegreeAndBType< SSD::DefaultFEMDegree , SSD::DefaultFEMBoundary >::Signature , true >(); + else Execute< float , 3 , FEMDegreeAndBType< Poisson::DefaultFEMDegree , Poisson::DefaultFEMBoundary >::Signature , false >(); + + if( Verbose.set ) + { + printf( "Time (Wall/CPU): %.2f / %.2f\n" , timer.wallTime() , timer.cpuTime() ); + printf( "Peak Memory (MB): %d\n" , MemoryInfo::PeakMemoryUsageMB() ); + } + + ThreadPool::Terminate(); + return EXIT_SUCCESS; +} diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h new file mode 100644 index 00000000..826e4c22 --- /dev/null +++ b/Src/Reconstructors.h @@ -0,0 +1,1356 @@ +/* +Copyright (c) 2022, 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 RECONSTRUCTORS_INCLUDED +#define RECONSTRUCTORS_INCLUDED + +#include "MyMiscellany.h" +#include "DataStream.imp.h" +#include "FEMTree.h" + +namespace Reconstructor +{ + static const unsigned int DataDegree = 0; // The order of the B-Spline used to splat in data for auxiliary data interpolation + static const unsigned int WeightDegree = 2; // The order of the B-Spline used to splat in the weights for density estimation + + // For clarity, to distinguies betwen the case that a Point is referencing a position and a normal + template< typename Real , unsigned int Dim > using Position = Point< Real , Dim >; + template< typename Real , unsigned int Dim > using Normal = Point< Real , Dim >; + template< typename Real , unsigned int Dim > using Gradient = Point< Real , Dim >; + +#include "Reconstructors.streams.h" + + // Declare a type for storing the solution information + template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... AuxData > struct ReconstructionInfo; + + // Specialized solution information without auxiliary data + template< typename Real , unsigned int Dim , unsigned int FEMSig > + struct ReconstructionInfo< Real , Dim , FEMSig > + { + // The signature pack + typedef IsotropicUIntPack< Dim , FEMSig > Sigs; + + // The type representing the point sampling density + typedef typename FEMTree< Dim , Real >::template DensityEstimator< Reconstructor::WeightDegree > DensityEstimator; + + // The constructor + ReconstructionInfo( void ) : density(NULL) , isoValue(0) , tree(MEMORY_ALLOCATOR_BLOCK_SIZE) , unitCubeToModel( XForm< Real , Dim+1 >::Identity() ){} + + // The desctructor + ~ReconstructionInfo( void ){ delete density ; density = NULL; } + + // The transformation taking points in the unit cube back to world coordinates + XForm< Real , Dim+1 > unitCubeToModel; + + // The octree adapted to the points + FEMTree< Dim , Real > tree; + + // The solution coefficients + DenseNodeData< Real , Sigs > solution; + + // The average value at the sample positions + Real isoValue; + + // The density estimator computed from the samples + DensityEstimator *density; + }; + + // Specialized solution information with auxiliary data + template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > + struct ReconstructionInfo< Real , Dim , FEMSig , AuxData > : public ReconstructionInfo< Real , Dim , FEMSig > + { + typedef IsotropicUIntPack< Dim , FEMSig > Sigs; + + // The signature of the finite-element used for data extrapolation + static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; + + // The constructor + ReconstructionInfo( AuxData zeroAuxData ) : auxData(NULL) , zeroAuxData(zeroAuxData) {} + + // The desctructor + ~ReconstructionInfo( void ){ delete auxData ; auxData = NULL; } + + // The auxiliary information stored with the oriented vertices + SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > > *auxData; + + // An instance of "zero" AuxData + AuxData zeroAuxData; + + // a method for rescaling the contents of the auxiliary data to give interpolation-preference to finer levels + void weightAuxDataByDepth( Real perLevelScaleFactor ) + { + auto nodeFunctor = [&]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *n ) + { + ProjectiveData< AuxData , Real >* clr = (*auxData)( n ); + if( clr ) (*clr) *= (Real)pow( (Real)perLevelScaleFactor , ReconstructionInfo< Real , Dim , FEMSig>::tree.depth( n ) ); + }; + ReconstructionInfo< Real , Dim , FEMSig>::tree.tree().processNodes( nodeFunctor ); + } + }; + + struct MeshExtractionParameters + { + bool linearFit; + bool outputGradients; + bool forceManifold; + bool polygonMesh; + bool verbose; + MeshExtractionParameters( void ) : linearFit(false) , outputGradients(false) , forceManifold(true) , polygonMesh(false) , verbose(false) {} + }; + + template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ReconstructionInfoType , unsigned int ... FEMSigs > + void _ExtractMesh( UIntPack< FEMSigs ... > , const ReconstructionInfoType &sInfo , OutputVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , MeshExtractionParameters params ); + + template< typename Real , unsigned int Dim , unsigned int FEMSig > + void ExtractMesh( const ReconstructionInfo< Real , Dim , FEMSig > &sInfo , OutputVertexStream< Real , Dim > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , MeshExtractionParameters params ) + { + typedef unsigned char AuxData; + _ExtractMesh< false , Real , Dim , FEMSig , AuxData , OutputVertexStream< Real , Dim > , ReconstructionInfo< Real , Dim , FEMSig > >( IsotropicUIntPack< Dim , FEMSig >() , sInfo , vertexStream , polygonStream , params ); + } + + template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > + void ExtractMesh( const ReconstructionInfo< Real , Dim , FEMSig , AuxData > &sInfo , OutputVertexWithDataStream< Real , Dim , AuxData > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , MeshExtractionParameters params ) + { + _ExtractMesh< true , Real , Dim , FEMSig , AuxData , OutputVertexWithDataStream< Real , Dim , AuxData > , ReconstructionInfo< Real , Dim , FEMSig , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , sInfo , vertexStream , polygonStream , params ); + } + + namespace Poisson + { + static const unsigned int NormalDegree = 2; // The order of the B-Spline used to splat in the normals for constructing the Laplacian constraints + static const unsigned int DefaultFEMDegree = 1; // The default finite-element degree (has to be at least 1) + static const BoundaryType DefaultFEMBoundary = BOUNDARY_NEUMANN; // The default finite-element boundary type {BOUNDARY_FREE, BOUNDARY_DIRICHLET, BOUNDARY_NEUMANN} + static const float WeightMultiplier = 2.f; // The default degree-to-point-weight scaling + + template< unsigned int Dim , typename Real > + struct ConstraintDual + { + Real target , weight; + ConstraintDual( void ) : target(0) , weight(0) {} + ConstraintDual( Real t , Real w ) : target(t) , weight(w) {} + CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim >& p ) const { return CumulativeDerivativeValues< Real , Dim , 0 >( target*weight ); }; + }; + + template< unsigned int Dim , typename Real > + struct SystemDual + { + Real weight; + SystemDual( void ) : weight(0) {} + SystemDual( Real w ) : weight(w) {} + CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim >& p , const CumulativeDerivativeValues< Real , Dim , 0 >& dValues ) const { return dValues * weight; }; + CumulativeDerivativeValues< double , Dim , 0 > operator()( const Point< Real , Dim >& p , const CumulativeDerivativeValues< double , Dim , 0 >& dValues ) const { return dValues * weight; }; + }; + + template< unsigned int Dim > + struct SystemDual< Dim , double > + { + typedef double Real; + Real weight; + SystemDual( void ) : weight(0) {} + SystemDual( Real w ) : weight(w) {} + CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim >& p , const CumulativeDerivativeValues< Real , Dim , 0 >& dValues ) const { return dValues * weight; }; + }; + + template< typename Real > + struct SolutionParameters + { + bool verbose; + bool dirichletErode; + bool outputDensity; + bool exactInterpolation; + bool showResidual; + Real scale; + Real confidence; + Real confidenceBias; + Real lowDepthCutOff; + Real width; + Real pointWeight; + Real samplesPerNode; + Real cgSolverAccuracy; +#ifdef SOFT_DIRICHLET + Real dirichletWeight; +#endif // SOFT_DIRICHLET + unsigned int depth; + unsigned int solveDepth; + unsigned int baseDepth; + unsigned int fullDepth; + unsigned int kernelDepth; + unsigned int envelopeDepth; + unsigned int baseVCycles; + unsigned int iters; + + SolutionParameters( void ) : + verbose(false) , dirichletErode(false) , outputDensity(false) , exactInterpolation(false) , showResidual(false) , + scale((Real)1.1) , confidence((Real)0.) , confidenceBias((Real)0.) , lowDepthCutOff((Real)0.) , width((Real)0.) , + pointWeight((Real)0.) , samplesPerNode((Real)1.5) , cgSolverAccuracy((Real)1e-3 ) , +#ifdef SOFT_DIRICHLET + dirichletWeight((Real)0.) , +#endif // SOFT_DIRICHLET + depth((unsigned int)8) , solveDepth((unsigned int)-1) , baseDepth((unsigned int)-1) , fullDepth((unsigned int)5) , kernelDepth((unsigned int)-1) , + envelopeDepth((unsigned int)-1) , baseVCycles((unsigned int)1) , iters((unsigned int)8) + {} + }; + + template< typename Real , unsigned int Dim > + struct EnvelopeMesh + { + std::vector< Point< Real , Dim > > vertices; + std::vector< SimplexIndex< Dim-1 , node_index_type > > simplices; + }; + + template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > + static typename std::conditional< HasAuxData , ReconstructionInfo< Real , Dim , FEMSig , AuxData > , ReconstructionInfo< Real , Dim , FEMSig > >::type *_Solve( UIntPack< FEMSigs... > , InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh ); + +#ifdef DE_VIRTUALIZE_INPUT + template< typename Real , unsigned int Dim , unsigned int FEMSig , typename InputSampleStreamType > + ReconstructionInfo< Real , Dim , FEMSig > *Solve( InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL ) + { + static_assert( std::is_base_of< InputSampleStream< Real , Dim > , InputSampleStreamType >::value , "[ERROR] Unexpected sample stream type" ); + typedef unsigned char AuxData; + return _Solve< false , Real , Dim , FEMSig , AuxData , InputSampleStreamType >( IsotropicUIntPack< Dim , FEMSig >() , pointStream , params , envelopeMesh ); + } + + template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType > + ReconstructionInfo< Real , Dim , FEMSig , AuxData > *Solve( InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL ) + { + static_assert( std::is_base_of< InputSampleWithDataStream< Real , Dim , AuxData > , InputSampleStreamType >::value , "[ERROR] Unexpected sample stream type" ); + return _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleStreamType >( IsotropicUIntPack< Dim , FEMSig >() , pointStream , params , envelopeMesh ); + } +#else // !DE_VIRTUALIZE_INPUT + template< typename Real , unsigned int Dim , unsigned int FEMSig > + ReconstructionInfo< Real , Dim , FEMSig > *Solve( InputSampleStream< Real , Dim > &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL ) + { + typedef unsigned char AuxData; + return _Solve< false , Real , Dim , FEMSig , AuxData , InputSampleStream< Real , Dim > >( IsotropicUIntPack< Dim , FEMSig >() , pointStream , params , envelopeMesh ); + } + + template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > + ReconstructionInfo< Real , Dim , FEMSig , AuxData > *Solve( InputSampleWithDataStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL ) + { + return _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleWithDataStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , pointStream , params , envelopeMesh ); + } +#endif // DE_VIRTUALIZE_INPUT + } + + namespace SSD + { + static const unsigned int NormalDegree = 2; // The order of the B-Spline used to splat in the normals for constructing the Laplacian constraints + static const unsigned int DefaultFEMDegree = 2; // The default finite-element degree (has to be at least 2) + static const BoundaryType DefaultFEMBoundary = BOUNDARY_NEUMANN; // The default finite-element boundary type {BOUNDARY_FREE, BOUNDARY_DIRICHLET, BOUNDARY_NEUMANN} + static const double WeightMultipliers[] = { 5e+1f , 5e-4f , 1e-5f }; // The default weights for balancing the value, gradient, and laplacian energy terms + + template< unsigned int Dim , typename ... > struct ConstraintDual; + template< unsigned int Dim , typename ... > struct SystemDual; + + template< unsigned int Dim , typename Real > + struct ConstraintDual< Dim , Real > + { + Real target , vWeight , gWeight; + ConstraintDual( Real t , Real v , Real g ) : target(t) , vWeight(v) , gWeight(g) { } + CumulativeDerivativeValues< Real , Dim , 1 > operator()( const Point< Real , Dim >& p , const Point< Real , Dim > &n ) const + { + CumulativeDerivativeValues< Real , Dim , 1 > cdv; + cdv[0] = target*vWeight; + for( int d=0 ; d + struct ConstraintDual< Dim , Real , AuxData > + { + Real target , vWeight , gWeight; + ConstraintDual( Real t , Real v , Real g ) : target(t) , vWeight(v) , gWeight(g) { } + CumulativeDerivativeValues< Real , Dim , 1 > operator()( const Point< Real , Dim >& p , const VectorTypeUnion< Real , Point< Real , Dim > , AuxData > &normalAndAuxData ) const + { + Point< Real , Dim > n = normalAndAuxData.template get<0>(); + CumulativeDerivativeValues< Real , Dim , 1 > cdv; + cdv[0] = target*vWeight; + for( int d=0 ; d + struct SystemDual< Dim , Real > + { + CumulativeDerivativeValues< Real , Dim , 1 > weight; + SystemDual( Real v , Real g ) + { + weight[0] = v; + for( int d=0 ; d operator()( Point< Real , Dim > p , const Point< Real , Dim > & , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const + { + return dValues * weight; + } + CumulativeDerivativeValues< double , Dim , 1 > operator()( Point< Real , Dim > p , const Point< Real , Dim > & , const CumulativeDerivativeValues< double , Dim , 1 >& dValues ) const + { + return dValues * weight; + }; + }; + + template< unsigned int Dim > + struct SystemDual< Dim , double > + { + typedef double Real; + CumulativeDerivativeValues< Real , Dim , 1 > weight; + SystemDual( Real v , Real g ) : weight( v , g , g , g ) { } + CumulativeDerivativeValues< Real , Dim , 1 > operator()( Point< Real , Dim > p , const Point< Real , Dim > & , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const + { + return dValues * weight; + } + }; + + template< unsigned int Dim , typename Real , typename AuxData > + struct SystemDual< Dim , Real , AuxData > + { + CumulativeDerivativeValues< Real , Dim , 1 > weight; + SystemDual( Real v , Real g ) + { + weight[0] = v; + for( int d=0 ; d operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Point< Real , Dim > , AuxData > & , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const + { + return dValues * weight; + } + CumulativeDerivativeValues< double , Dim , 1 > operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Point< Real , Dim > , AuxData > & , const CumulativeDerivativeValues< double , Dim , 1 >& dValues ) const + { + return dValues * weight; + }; + }; + + template< unsigned int Dim , class AuxData > + struct SystemDual< Dim , double , AuxData > + { + typedef double Real; + CumulativeDerivativeValues< Real , Dim , 1 > weight; + SystemDual( Real v , Real g ) : weight( v , g , g , g ) { } + CumulativeDerivativeValues< Real , Dim , 1 > operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Point< Real , Dim > , AuxData > & , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const + { + return dValues * weight; + } + }; + + template< typename Real > + struct SolutionParameters + { + bool verbose; + bool outputDensity; + bool exactInterpolation; + bool showResidual; + Real scale; + Real confidence; + Real confidenceBias; + Real lowDepthCutOff; + Real width; + Real pointWeight; + Real gradientWeight; + Real biLapWeight; + Real samplesPerNode; + Real cgSolverAccuracy; + unsigned int depth; + unsigned int solveDepth; + unsigned int baseDepth; + unsigned int fullDepth; + unsigned int kernelDepth; + unsigned int baseVCycles; + unsigned int iters; + + SolutionParameters( void ) : + verbose(false) , outputDensity(false) , exactInterpolation(false) , showResidual(false) , + scale((Real)1.1) , confidence((Real)0.) , confidenceBias((Real)0.) , lowDepthCutOff((Real)0.) , width((Real)0.) , + pointWeight((Real)WeightMultipliers[0]) , gradientWeight((Real)WeightMultipliers[1]) , biLapWeight((Real)WeightMultipliers[2]) , samplesPerNode((Real)1.5) , cgSolverAccuracy((Real)1e-3 ) , + depth((unsigned int)8) , solveDepth((unsigned int)-1) , baseDepth((unsigned int)-1) , fullDepth((unsigned int)5) , kernelDepth((unsigned int)-1) , + baseVCycles((unsigned int)1) , iters((unsigned int)8) + {} + + }; + + template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > + typename std::conditional< HasAuxData , ReconstructionInfo< Real , Dim , FEMSig , AuxData > , ReconstructionInfo< Real , Dim , FEMSig > >::type *_Solve( UIntPack< FEMSigs ... > , InputSampleStreamType &pointStream , SolutionParameters< Real > params ); + +#ifdef DE_VIRTUALIZE_INPUT + template< typename Real , unsigned int Dim , unsigned int FEMSig , typename InputSampleStreamType > + ReconstructionInfo< Real , Dim , FEMSig > *Solve( InputSampleStreamType &pointStream , SolutionParameters< Real > params ) + { + static_assert( std::is_base_of< InputSampleStream< Real , Dim > , InputSampleStreamType >::value , "[ERROR] Unexpected sample stream type" ); + typedef unsigned char AuxData; + return _Solve< false , Real , Dim , FEMSig , AuxData , InputSampleStreamType >( IsotropicUIntPack< Dim , FEMSig >() , pointStream , params ); + } + + template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType > + ReconstructionInfo< Real , Dim , FEMSig , AuxData > *Solve( InputSampleStreamType &pointStream , SolutionParameters< Real > params ) + { + static_assert( std::is_base_of< InputSampleWithDataStream< Real , Dim , AuxData > , InputSampleStreamType >::value , "[ERROR] Unexpected sample stream type" ); + return _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleStreamType >( IsotropicUIntPack< Dim , FEMSig >() , pointStream , params ); + } +#else // !DE_VIRTUALIZE_INPUT + template< typename Real , unsigned int Dim , unsigned int FEMSig > + ReconstructionInfo< Real , Dim , FEMSig > *Solve( InputSampleStream< Real , Dim > &pointStream , SolutionParameters< Real > params ) + { + typedef unsigned char AuxData; + return _Solve< false , Real , Dim , FEMSig , AuxData , InputSampleStream< Real , Dim > >( IsotropicUIntPack< Dim , FEMSig >() , pointStream , params ); + } + + template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > + ReconstructionInfo< Real , Dim , FEMSig , AuxData > *Solve( InputSampleWithDataStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params ) + { + return _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleWithDataStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , pointStream , params ); + } +#endif // DE_VIRTUALIZE_INPUT + } + + template< class Real , unsigned int Dim > + XForm< Real , Dim+1 > GetBoundingBoxXForm( Point< Real , Dim > min , Point< Real , Dim > max , Real scaleFactor ) + { + Point< Real , Dim > center = ( max + min ) / 2; + Real scale = max[0] - min[0]; + for( int d=1 ; d( scale , max[d]-min[d] ); + scale *= scaleFactor; + for( int i=0 ; i tXForm = XForm< Real , Dim+1 >::Identity() , sXForm = XForm< Real , Dim+1 >::Identity(); + for( int i=0 ; i(max[maxDim]-min[maxDim]) ) maxDim = i; + XForm< Real , Dim+1 > rXForm; + for( int i=0 ; i + void SetBoundingBox( SampleStream &stream , Point< Real , Dim >& min , Point< Real , Dim >& max ) + { + using Sample = Point< Real , Dim >; + static_assert( std::is_base_of< InputDataStream< Sample > , SampleStream >::value , "[ERROR] Unexpected sample stream type" ); + Sample s; + for( unsigned int d=0 ; d::infinity() , max[d] = -std::numeric_limits< Real >::infinity(); + while( stream.read( s ) ) for( unsigned int d=0 ; d( min[d] , s[d] ) , max[d] = std::max< Real >( max[d] , s[d] ); + stream.reset(); + } + + template< class Real , unsigned int Dim , typename AuxData , typename SampleStream > + void SetBoundingBox( SampleStream &stream , AuxData d , Point< Real , Dim >& min , Point< Real , Dim >& max ) + { + using Sample = VectorTypeUnion< Real , Point< Real , Dim > , AuxData >; + static_assert( std::is_base_of< InputDataStream< Sample > , SampleStream >::value , "[ERROR] Unexpected sample stream type" ); + Sample s( Point< Real , Dim >() , d ); + for( unsigned int d=0 ; d::infinity() , max[d] = -std::numeric_limits< Real >::infinity(); + while( stream.read( s ) ) for( unsigned int d=0 ; d( min[d] , s.template get<0>()[d] ) , max[d] = std::max< Real >( max[d] , s.template get<0>()[d] ); + stream.reset(); + } + + template< class Real , unsigned int Dim , typename SampleStream > + XForm< Real , Dim+1 > GetPointXForm( SampleStream &stream , Real scaleFactor ) + { + using Sample = Point< Real , Dim >; + static_assert( std::is_base_of< InputDataStream< Sample > , SampleStream >::value , "[ERROR] Unexpected sample stream type" ); + Point< Real , Dim > min , max; + SetBoundingBox< Real , Dim , SampleStream >( stream , min , max ); + return GetBoundingBoxXForm( min , max , scaleFactor ); + } + + template< class Real , unsigned int Dim , typename AuxData , typename SampleStream > + XForm< Real , Dim+1 > GetPointXForm( SampleStream &stream , AuxData d , Real scaleFactor ) + { + using Sample = VectorTypeUnion< Real , Point< Real , Dim > , AuxData >; + static_assert( std::is_base_of< InputDataStream< Sample > , SampleStream >::value , "[ERROR] Unexpected sample stream type" ); + Point< Real , Dim > min , max; + SetBoundingBox< Real , Dim , AuxData , SampleStream >( stream , d , min , max ); + return GetBoundingBoxXForm( min , max , scaleFactor ); + } +#else // !DE_VIRTUALIZE_INPUT + template< class Real , unsigned int Dim > + void SetBoundingBox( InputDataStream< Point< Real , Dim > > &stream , Point< Real , Dim >& min , Point< Real , Dim >& max ) + { + Point< Real , Dim > p; + for( unsigned int d=0 ; d::infinity() , max[d] = -std::numeric_limits< Real >::infinity(); + while( stream.read( p ) ) for( unsigned int d=0 ; d( min[d] , p[d] ) , max[d] = std::max< Real >( max[d] , p[d] ); + stream.reset(); + } + + template< class Real , unsigned int Dim , typename AuxData > + void SetBoundingBox( InputDataStream< VectorTypeUnion< Real , Point< Real , Dim > , AuxData > > &stream , AuxData d , Point< Real , Dim >& min , Point< Real , Dim >& max ) + { + VectorTypeUnion< Real , Point< Real , Dim > , AuxData > p( Point< Real , Dim >() , d ); + for( unsigned int d=0 ; d::infinity() , max[d] = -std::numeric_limits< Real >::infinity(); + while( stream.read( p ) ) for( unsigned int d=0 ; d( min[d] , p.template get<0>()[d] ) , max[d] = std::max< Real >( max[d] , p.template get<0>()[d] ); + stream.reset(); + } + + template< class Real , unsigned int Dim > + XForm< Real , Dim+1 > GetPointXForm( InputDataStream< Point< Real , Dim > > &stream , Real scaleFactor ) + { + Point< Real , Dim > min , max; + SetBoundingBox( stream , min , max ); + return GetBoundingBoxXForm( min , max , scaleFactor ); + } + + template< class Real , unsigned int Dim , typename AuxData > + XForm< Real , Dim+1 > GetPointXForm( InputDataStream< VectorTypeUnion< Real , Point< Real , Dim > , AuxData > > &stream , AuxData d , Real scaleFactor ) + { + Point< Real , Dim > min , max; + SetBoundingBox( stream , d , min , max ); + return GetBoundingBoxXForm( min , max , scaleFactor ); + } +#endif // DE_VIRTUALIZE_INPUT + + template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ReconstructionInfoType , unsigned int ... FEMSigs > + void _ExtractMesh( UIntPack< FEMSigs ... > , const ReconstructionInfoType &sInfo , OutputVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , MeshExtractionParameters params ) + { + typedef UIntPack< FEMSigs ... > Sigs; + static_assert( std::is_same< IsotropicUIntPack< Dim , FEMSig > , UIntPack< FEMSigs ... > >::value , "[ERROR] Signatures don't match" ); + static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; + typedef typename ReconstructionInfoType::DensityEstimator DensityEstimator; + + if constexpr( Dim!=3 ) + { + WARN( "Extraction only supported for dimension 3" ); + return; + } + else + { + Profiler profiler(20); + + std::string statsString; + + if constexpr( HasAuxData ) + { + typename LevelSetExtractor< Real , Dim , AuxData >::Stats stats; + TransformedOutputVertexWithDataStream< Real , Dim , AuxData > _vertexStream( sInfo.unitCubeToModel , vertexStream ); + stats = LevelSetExtractor< Real , Dim , AuxData >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , UIntPack< DataSig >() , sInfo.tree , sInfo.density , sInfo.auxData , sInfo.solution , sInfo.isoValue , _vertexStream , polygonStream , sInfo.zeroAuxData , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); + statsString = stats.toString(); + } + else + { + typename LevelSetExtractor< Real , Dim >::Stats stats; + TransformedOutputVertexStream< Real , Dim > _vertexStream( sInfo.unitCubeToModel , vertexStream ); + stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , sInfo.tree , sInfo.density , sInfo.solution , sInfo.isoValue , _vertexStream , polygonStream , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); + statsString = stats.toString(); + } + if( params.verbose ) + { + std::cout << "Vertices / Polygons: " << vertexStream.size() << " / " << polygonStream.size() << std::endl; + std::cout << statsString << std::endl; + if( params.polygonMesh ) std::cout << "# Got polygons: " << profiler << std::endl; + else std::cout << "# Got triangles: " << profiler << std::endl; + } + } + } + + template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > + static typename std::conditional< HasAuxData , ReconstructionInfo< Real , Dim , FEMSig , AuxData > , ReconstructionInfo< Real , Dim , FEMSig > >::type *Poisson::_Solve( UIntPack< FEMSigs ... > , InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh ) + { + static_assert( std::is_same< IsotropicUIntPack< Dim , FEMSig > , UIntPack< FEMSigs... > >::value , "[ERROR] Signatures don't match" ); + + // The signature for the finite-elements representing the auxiliary data (if it's there) + static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; + + /////////////// + // Types --> // + // The packed finite elements signature + typedef UIntPack< FEMSigs ... > Sigs; + + // The degrees of the finite elements across the different axes + typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > Degrees; + + // The signature describing the normals elements + typedef UIntPack< FEMDegreeAndBType< Poisson::NormalDegree , DerivativeBoundary< FEMSignature< FEMSigs >::BType , 1 >::BType >::Signature ... > NormalSigs; + + // Type for tracking sample interpolation + typedef typename FEMTree< Dim , Real >::template InterpolationInfo< Real , 0 > InterpolationInfo; + + // The finite-element tracking tree node + typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; + + typedef typename FEMTreeInitializer< Dim , Real >::GeometryNodeType GeometryNodeType; + + // The type of the auxiliary information (including the normal) + typedef typename std::conditional< HasAuxData , VectorTypeUnion< Real , Normal< Real , Dim > , AuxData > , Normal< Real , Dim > >::type NormalAndAuxData; + + // The type describing the sampling density + typedef typename std::conditional< HasAuxData , ReconstructionInfo< Real , Dim , FEMSig , AuxData > , ReconstructionInfo< Real , Dim , FEMSig > >::type::DensityEstimator DensityEstimator; + // <-- Types // + /////////////// + + // The solution info to be returned + typename std::conditional< HasAuxData , ReconstructionInfo< Real , Dim , FEMSig , AuxData > , ReconstructionInfo< Real , Dim , FEMSig > >::type *sInfo; + if constexpr( HasAuxData ) sInfo = new ReconstructionInfo< Real , Dim , FEMSig , AuxData >( pointStream.zero() ); + else sInfo = new ReconstructionInfo< Real , Dim , FEMSig >(); + + NormalAndAuxData zeroNormalAndAuxData; + if constexpr( HasAuxData ) zeroNormalAndAuxData = NormalAndAuxData( Normal< Real , Dim >() , sInfo->zeroAuxData ); + + XForm< Real , Dim+1 > modelToUnitCube = XForm< Real , Dim+1 >::Identity(); + + Profiler profiler(20); + + size_t pointCount; + + ProjectiveData< Point< Real , 2 > , Real > pointDepthAndWeight; +#ifdef SOFT_DIRICHLET + std::vector< typename FEMTree< Dim , Real >::PointSample > *dirichletSamples = NULL; +#endif // SOFT_DIRICHLET + DenseNodeData< GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > geometryNodeDesignators; + SparseNodeData< Point< Real , Dim > , NormalSigs > *normalInfo = NULL; + std::vector< typename FEMTree< Dim , Real >::PointSample > *samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); + std::vector< NormalAndAuxData > *sampleNormalAndAuxData = NULL; + + Real targetValue = (Real)0.5; + + // Read in the samples (and auxiliary data) + { + profiler.reset(); + + pointStream.reset(); + sampleNormalAndAuxData = new std::vector< NormalAndAuxData >(); + + modelToUnitCube = params.scale>0 ? GetPointXForm< Real , Dim >( pointStream , zeroNormalAndAuxData , params.scale ) * modelToUnitCube : modelToUnitCube; + + if( params.width>0 ) + { + Real maxScale = 0; + for( unsigned int i=0 ; i( maxScale , (Real)1./modelToUnitCube(i,i) ); + params.depth = (unsigned int)ceil( std::max< double >( 0. , log( maxScale/params.width )/log(2.) ) ); + } + if( params.solveDepth>params.depth ) + { + if( params.solveDepth!=-1 ) WARN( "Solution depth cannot exceed system depth: " , params.solveDepth , " <= " , params.depth ); + params.solveDepth = params.depth; + } + if( params.fullDepth>params.solveDepth ) + { + if( params.fullDepth!=-1 ) WARN( "Full depth cannot exceed system depth: " , params.fullDepth , " <= " , params.solveDepth ); + params.fullDepth = params.solveDepth; + } + if( params.baseDepth>params.fullDepth ) + { + if( params.baseDepth!=-1 ) WARN( "Base depth must be smaller than full depth: " , params.baseDepth , " <= " , params.fullDepth ); + params.baseDepth = params.fullDepth; + } + if( params.kernelDepth==-1 ) params.kernelDepth = params.depth>2 ? params.depth-2 : 0; + if( params.kernelDepth>params.depth ) + { + if( params.kernelDepth!=-1 ) WARN( "Kernel depth cannot exceed system depth: " , params.kernelDepth , " <= " , params.depth ); + params.kernelDepth = params.depth; + } + + if constexpr( HasAuxData ) + { +#ifdef DE_VIRTUALIZE_OUTPUT + TransformedInputSampleWithDataStream< Real , Dim , AuxData , InputSampleStreamType > _pointStream( modelToUnitCube , pointStream ); +#else // !DE_VIRTUALIZE_OUTPUT + TransformedInputSampleWithDataStream< Real , Dim , AuxData > _pointStream( modelToUnitCube , pointStream ); +#endif // DE_VIRTUALIZE_OUTPUT + auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , NormalAndAuxData &d ) + { + Real l = (Real)Length( d.template get<0>() ); + if( !l || !std::isfinite( l ) ) return (Real)-1.; + return (Real)pow( l , params.confidence ); + }; + auto ProcessData = []( const Point< Real , Dim > &p , NormalAndAuxData &d ) + { + Real l = (Real)Length( d.template get<0>() ); + if( !l || !std::isfinite( l ) ) return (Real)-1.; + d.template get<0>() /= l; + return (Real)1.; + }; + + typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; + if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , sInfo->tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , sInfo->tree.nodeAllocators.size() ? sInfo->tree.nodeAllocators[0] : NULL , sInfo->tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , sInfo->tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , sInfo->tree.nodeAllocators.size() ? sInfo->tree.nodeAllocators[0] : NULL , sInfo->tree.initializer() , ProcessData ); + } + else + { +#ifdef DE_VIRTUALIZE_OUTPUT + TransformedInputSampleStream< Real , Dim , InputSampleStreamType > _pointStream( modelToUnitCube , pointStream ); +#else // !DE_VIRTUALIZE_OUTPUT + TransformedInputSampleStream< Real , Dim > _pointStream( modelToUnitCube , pointStream ); +#endif // DE_VIRTUALIZE_OUTPUT + auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , NormalAndAuxData &d ) + { + Real l = (Real)Length( d ); + if( !l || !std::isfinite( l ) ) return (Real)-1.; + return (Real)pow( l , params.confidence ); + }; + auto ProcessData = []( const Point< Real , Dim > &p , NormalAndAuxData &d ) + { + Real l = (Real)Length( d ); + if( !l || !std::isfinite( l ) ) return (Real)-1.; + d /= l; + return (Real)1.; + }; + + typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; + if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , sInfo->tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , sInfo->tree.nodeAllocators.size() ? sInfo->tree.nodeAllocators[0] : NULL , sInfo->tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , sInfo->tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , sInfo->tree.nodeAllocators.size() ? sInfo->tree.nodeAllocators[0] : NULL , sInfo->tree.initializer() , ProcessData ); + } + + sInfo->unitCubeToModel = modelToUnitCube.inverse(); + + if( params.verbose ) + { + std::cout << "Input Points / Samples: " << pointCount << " / " << samples->size() << std::endl; + std::cout << "# Read input into tree: " << profiler << std::endl; + } + } + { +#ifdef SOFT_DIRICHLET + InterpolationInfo *dirichletInfo = NULL; +#endif // SOFT_DIRICHLET + DenseNodeData< Real , Sigs > constraints; + InterpolationInfo *iInfo = NULL; + int solveDepth = params.depth; + + sInfo->tree.resetNodeIndices( 0 , std::make_tuple() ); + + // Get the kernel density estimator + { + profiler.reset(); + sInfo->density = sInfo->tree.template setDensityEstimator< 1 , Reconstructor::WeightDegree >( *samples , params.kernelDepth , params.samplesPerNode ); + if( params.verbose ) std::cout << "# Got kernel density: " << profiler << std::endl; + } + + // Transform the Hermite samples into a vector field + { + profiler.reset(); + normalInfo = new SparseNodeData< Point< Real , Dim > , NormalSigs >(); + std::function< bool ( NormalAndAuxData , Point< Real , Dim > & ) > ConversionFunction; + std::function< bool ( NormalAndAuxData , Point< Real , Dim > & , Real & ) > ConversionAndBiasFunction; + if constexpr( HasAuxData ) + { + ConversionFunction = []( NormalAndAuxData in , Point< Real , Dim > &out ) + { + Point< Real , Dim > n = in.template get<0>(); + Real l = (Real)Length( n ); + // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... + if( !l ) return false; + out = n / l; + return true; + }; + ConversionAndBiasFunction = [&]( NormalAndAuxData in , Point< Real , Dim > &out , Real &bias ) + { + Point< Real , Dim > n = in.template get<0>(); + Real l = (Real)Length( n ); + // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... + if( !l ) return false; + out = n / l; + bias = (Real)( log( l ) * params.confidenceBias / log( 1<<(Dim-1) ) ); + return true; + }; + } + else + { + // In this case NormalAndAuxData = Point< Real , Dim > + ConversionFunction = []( NormalAndAuxData in , Point< Real , Dim > &out ) + { + Real l = (Real)Length( in ); + // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... + if( !l ) return false; + out = in / l; + return true; + }; + ConversionAndBiasFunction = [&]( NormalAndAuxData in , Point< Real , Dim > &out , Real &bias ) + { + Real l = (Real)Length( in ); + // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... + if( !l ) return false; + out = in / l; + bias = (Real)( log( l ) * params.confidenceBias / log( 1<<(Dim-1) ) ); + return true; + }; + } + if( params.confidenceBias>0 ) *normalInfo = sInfo->tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , sInfo->density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionAndBiasFunction ); + else *normalInfo = sInfo->tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , sInfo->density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionFunction ); + ThreadPool::Parallel_for( 0 , normalInfo->size() , [&]( unsigned int , size_t i ){ (*normalInfo)[i] *= (Real)-1.; } ); + if( params.verbose ) + { + std::cout << "# Got normal field: " << profiler << std::endl; + std::cout << "Point depth / Point weight / Estimated measure: " << pointDepthAndWeight.value()[0] << " / " << pointDepthAndWeight.value()[1] << " / " << pointCount*pointDepthAndWeight.value()[1] << std::endl; + } + } + + // Get the geometry designators indicating if the space node are interior to, exterior to, or contain the envelope boundary + if( envelopeMesh ) + { + profiler.reset(); +#ifdef SOFT_DIRICHLET + if( params.dirichletWeight>0 ) + { + std::vector< Point< Real , Dim > > vertices( envelopeMesh->vertices.size() ); + for( unsigned int i=0 ; ivertices[i]; + +#if 0 + // Get the coarsest interior/boundary/exterior designators + if( exteriorConstraintType!=ExteriorConstraint::NONE || interiorConstraintType!=InteriorConstraint::NONE ) + geometryNodeDesignators = FEMTreeInitializer< Dim , Real >::template GetGeometryNodeDesignators( sInfo->tree.spaceRoot() , vertices , envelopeMesh->simplices , params.envelopeDepth , tree.nodeAllocators , tree.initializer() ); +#endif + // Get the samples of the envelope that will act as Dirichlet point constraints and turn on the scratch flags for nodes containing constraints + dirichletSamples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); + FEMTreeInitializer< Dim , Real >::Initialize( sInfo->tree.spaceRoot() , vertices , envelopeMesh->simplices , params.envelopeDepth , *dirichletSamples , true , sInfo->tree.nodeAllocators , sInfo->tree.initializer() ); + ThreadPool::Parallel_for( 0 , dirichletSamples->size() , [&]( unsigned int , size_t i ){ for( FEMTreeNode *node=(*dirichletSamples)[i].node ; node ; node=node->parent ) node->nodeData.setScratchFlag( true ); } ); + } + else +#endif // SOFT_DIRICHLET + { + // Make the octree complete up to the base depth + FEMTreeInitializer< Dim , Real >::Initialize( sInfo->tree.spaceRoot() , params.baseDepth , []( int , int[] ){ return true; } , sInfo->tree.nodeAllocators.size() ? sInfo->tree.nodeAllocators[0] : NULL , sInfo->tree.initializer() ); + + std::vector< Point< Real , Dim > > vertices( envelopeMesh->vertices.size() ); + for( unsigned int i=0 ; ivertices[i]; + geometryNodeDesignators = FEMTreeInitializer< Dim , Real >::template GetGeometryNodeDesignators( &sInfo->tree.spaceRoot() , vertices , envelopeMesh->simplices , params.baseDepth , params.envelopeDepth , sInfo->tree.nodeAllocators , sInfo->tree.initializer() ); + + // Make nodes in the support of the vector field @{ExactDepth} interior + if( params.dirichletErode ) + { + // What to do if we find a node in the support of the vector field + auto SetScratchFlag = [&]( FEMTreeNode *node ) + { + if( node ) + { + while( node->depth()>(int)params.baseDepth ) node = node->parent; + node->nodeData.setScratchFlag( true ); + } + }; + + std::function< void ( FEMTreeNode * ) > PropagateToLeaves = [&]( const FEMTreeNode *node ) + { + geometryNodeDesignators[ node ] = GeometryNodeType::INTERIOR; + if( node->children ) for( int c=0 ; c<(1<children+c ); + }; + + // Flags indicating if a node contains a non-zero vector field coefficient + std::vector< bool > isVectorFieldElement( sInfo->tree.nodeCount() , false ); + + // Get the set of base nodes + std::vector< FEMTreeNode * > baseNodes; + auto nodeFunctor = [&]( FEMTreeNode *node ) + { + if( node->depth()==params.baseDepth ) baseNodes.push_back( node ); + return node->depth()<(int)params.baseDepth; + }; + sInfo->tree.spaceRoot().processNodes( nodeFunctor ); + + std::vector< node_index_type > vectorFieldElementCounts( baseNodes.size() ); + for( int i=0 ; i *n = (*normalInfo)( node ); + if( n && Point< Real , Dim >::SquareNorm( *n ) ) isVectorFieldElement[ node->nodeData.nodeIndex ] = true , vectorFieldElementCounts[i]++; + }; + baseNodes[i]->processNodes( nodeFunctor ); + } ); + size_t vectorFieldElementCount = 0; + for( int i=0 ; i vectorFieldElements; + vectorFieldElements.reserve( vectorFieldElementCount ); + { + std::vector< std::vector< FEMTreeNode * > > _vectorFieldElements( baseNodes.size() ); + for( int i=0 ; i<_vectorFieldElements.size() ; i++ ) _vectorFieldElements[i].reserve( vectorFieldElementCounts[i] ); + ThreadPool::Parallel_for( 0 , baseNodes.size() , [&]( unsigned int t , size_t i ) + { + auto nodeFunctor = [&]( FEMTreeNode *node ) + { + if( isVectorFieldElement[ node->nodeData.nodeIndex ] ) _vectorFieldElements[i].push_back( node ); + node->nodeData.setScratchFlag( false ); + }; + baseNodes[i]->processNodes( nodeFunctor ); + } ); + for( int i=0 ; i<_vectorFieldElements.size() ; i++ ) vectorFieldElements.insert( vectorFieldElements.end() , _vectorFieldElements[i].begin() , _vectorFieldElements[i].end() ); + } + + // Set the scratch flag for the base nodes on which the vector field is supported +#ifdef SHOW_WARNINGS +#pragma message( "[WARNING] In principal, we should unlock finite elements whose support overlaps the vector field" ) +#endif // SHOW_WARNINGS + sInfo->tree.template processNeighboringLeaves< -BSplineSupportSizes< Poisson::NormalDegree >::SupportStart , BSplineSupportSizes< Poisson::NormalDegree >::SupportEnd >( &vectorFieldElements[0] , vectorFieldElements.size() , SetScratchFlag , false ); + + // Set sub-trees rooted at interior nodes @ ExactDepth to interior + ThreadPool::Parallel_for( 0 , baseNodes.size() , [&]( unsigned int , size_t i ){ if( baseNodes[i]->nodeData.getScratchFlag() ) PropagateToLeaves( baseNodes[i] ); } ); + + // Adjust the coarser node designators in case exterior nodes have become boundary. + ThreadPool::Parallel_for( 0 , baseNodes.size() , [&]( unsigned int , size_t i ){ FEMTreeInitializer< Dim , Real >::PullGeometryNodeDesignatorsFromFiner( baseNodes[i] , geometryNodeDesignators ); } ); + FEMTreeInitializer< Dim , Real >::PullGeometryNodeDesignatorsFromFiner( &sInfo->tree.spaceRoot() , geometryNodeDesignators , params.baseDepth ); + } + } + if( params.verbose ) std::cout << "# Initialized envelope constraints: " << profiler << std::endl; + } + + if( !params.outputDensity ){ delete sInfo->density ; sInfo->density = NULL; } + if constexpr( HasAuxData ) sInfo->auxData = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( sInfo->tree.template setExtrapolatedDataField< DataSig , false , Reconstructor::WeightDegree , AuxData >( samples->size() , [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return (*samples)[i]; } , [&]( size_t i ) -> const AuxData & { return (*sampleNormalAndAuxData)[i].template get<1>(); } , (DensityEstimator*)NULL ) ); + delete sampleNormalAndAuxData; + + // Add the interpolation constraints + if( params.pointWeight>0 ) + { + profiler.reset(); + if( params.exactInterpolation ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointInterpolationInfo< Real , 0 > ( sInfo->tree , *samples , Poisson::ConstraintDual< Dim , Real >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] ) , Poisson::SystemDual< Dim , Real >( params.pointWeight * pointDepthAndWeight.value()[1] ) , true , false ); + else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointInterpolationInfo< Real , 0 > ( sInfo->tree , *samples , Poisson::ConstraintDual< Dim , Real >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] ) , Poisson::SystemDual< Dim , Real >( params.pointWeight * pointDepthAndWeight.value()[1] ) , true , params.depth , 1 ); + if( params.verbose ) std::cout << "#Initialized point interpolation constraints: " << profiler << std::endl; + } + + // Trim the tree and prepare for multigrid + { + profiler.reset(); + constexpr int MaxDegree = Poisson::NormalDegree > Degrees::Max() ? Poisson::NormalDegree : Degrees::Max(); + typename FEMTree< Dim , Real >::template HasNormalDataFunctor< NormalSigs > hasNormalDataFunctor( *normalInfo ); + auto hasDataFunctor = [&]( const FEMTreeNode *node ){ return hasNormalDataFunctor( node ); }; + auto addNodeFunctor = [&]( int d , const int off[Dim] ){ return d<=(int)params.fullDepth; }; + if constexpr( HasAuxData ) + { + if( geometryNodeDesignators.size() ) sInfo->tree.template finalizeForMultigridWithDirichlet< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , [&]( const FEMTreeNode *node ){ return node->nodeData.nodeIndex<(node_index_type)geometryNodeDesignators.size() && geometryNodeDesignators[node]==GeometryNodeType::EXTERIOR; } , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , sInfo->density , sInfo->auxData , &geometryNodeDesignators ) ); + else sInfo->tree.template finalizeForMultigrid < MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , sInfo->density , sInfo->auxData ) ); + } + else + { + if( geometryNodeDesignators.size() ) sInfo->tree.template finalizeForMultigridWithDirichlet< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , [&]( const FEMTreeNode *node ){ return node->nodeData.nodeIndex<(node_index_type)geometryNodeDesignators.size() && geometryNodeDesignators[node]==GeometryNodeType::EXTERIOR; } , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , sInfo->density , &geometryNodeDesignators ) ); + else sInfo->tree.template finalizeForMultigrid < MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , sInfo->density ) ); + } + + if( params.verbose ) std::cout << "# Finalized tree: " << profiler << std::endl; + } + + // Add the FEM constraints + { + profiler.reset(); + constraints = sInfo->tree.initDenseNodeData( Sigs() ); + + // Add Poisson constraints + { + typename FEMIntegrator::template Constraint< Sigs , IsotropicUIntPack< Dim , 1 > , NormalSigs , IsotropicUIntPack< Dim , 0 > , Dim > F; + unsigned int derivatives2[Dim]; + for( int d=0 ; d Derivatives1; + typedef IsotropicUIntPack< Dim , 0 > Derivatives2; + for( int d=0 ; d::Index( derivatives1 ) ][ TensorDerivatives< Derivatives2 >::Index( derivatives2 ) ] = 1; + } + sInfo->tree.addFEMConstraints( F , *normalInfo , constraints , solveDepth ); + } + if( params.verbose ) std::cout << "# Set FEM constraints: " << profiler << std::endl; + } + + // Free up the normal info + delete normalInfo , normalInfo = NULL; + + if( params.pointWeight>0 ) + { + profiler.reset(); + sInfo->tree.addInterpolationConstraints( constraints , solveDepth , std::make_tuple( iInfo ) ); + if( params.verbose ) std::cout << "#Set point constraints: " << profiler << std::endl; + } + +#ifdef SOFT_DIRICHLET + if( dirichletSamples ) + { + if( params.exactInterpolation ) dirichletInfo = FEMTree< Dim , Real >::template InitializeExactPointInterpolationInfo< Real , 0 > ( sInfo->tree , *dirichletSamples , Poisson::ConstraintDual< Dim , Real >( 0. , params.dirichletWeight ) , Poisson::SystemDual< Dim , Real >( params.dirichletWeight ) , true , false ); + else dirichletInfo = FEMTree< Dim , Real >::template InitializeApproximatePointInterpolationInfo< Real , 0 > ( sInfo->tree , *dirichletSamples , Poisson::ConstraintDual< Dim , Real >( 0. , params.dirichletWeight ) , Poisson::SystemDual< Dim , Real >( params.dirichletWeight ) , true , 1 ); + // if( exteriorConstraintValue ) sInfo->tree.addInterpolationConstraints( constraints , solveDepth , *dirichletInfo ); + if( params.verbose ) std::cout << "# Set exterior envelope constraints: " << profiler << std::endl; + delete dirichletSamples , dirichletSamples = NULL; + } +#endif // SOFT_DIRICHLET + + +#ifdef SOFT_DIRICHLET + if( params.verbose ) + if( params.dirichletWeight>0 ) std::cout << "All Nodes / Active Nodes / Ghost Nodes: " << sInfo->tree.allNodes() << " / " << sInfo->tree.activeNodes() << " / " << sInfo->tree.ghostNodes() << std::endl; + else std::cout << "All Nodes / Active Nodes / Ghost Nodes / Dirichlet Supported Nodes: " << sInfo->tree.allNodes() << " / " << sInfo->tree.activeNodes() << " / " << sInfo->tree.ghostNodes() << " / " << sInfo->tree.dirichletElements() << std::endl; +#else // !SOFT_DIRICHLET + if( params.verbose ) std::cout << "All Nodes / Active Nodes / Ghost Nodes / Dirichlet Supported Nodes: " << sInfo->tree.allNodes() << " / " << sInfo->tree.activeNodes() << " / " << sInfo->tree.ghostNodes() << " / " << sInfo->tree.dirichletElements() << std::endl; +#endif // SOFT_DIRICHLET + if( params.verbose ) std::cout << "Memory Usage: " << float( MemoryInfo::Usage())/(1<<20) << " MB" << std::endl; + + // Solve the linear system + { + profiler.reset(); + typename FEMTree< Dim , Real >::SolverInfo _sInfo; + _sInfo.cgDepth = 0 , _sInfo.cascadic = true , _sInfo.vCycles = 1 , _sInfo.iters = params.iters , _sInfo.cgAccuracy = params.cgSolverAccuracy , _sInfo.verbose = params.verbose , _sInfo.showResidual = params.showResidual , _sInfo.showGlobalResidual = SHOW_GLOBAL_RESIDUAL_NONE , _sInfo.sliceBlockSize = 1; + _sInfo.baseVCycles = params.baseVCycles; + typename FEMIntegrator::template System< Sigs , IsotropicUIntPack< Dim , 1 > > F( { 0. , 1. } ); +#ifdef SOFT_DIRICHLET + if( dirichletInfo ) sInfo->solution = sInfo->tree.solveSystem( Sigs() , F , constraints , params.baseDepth , params.solveDepth , _sInfo , std::make_tuple( iInfo , dirichletInfo ) ); + else sInfo->solution = sInfo->tree.solveSystem( Sigs() , F , constraints , params.baseDepth , params.solveDepth , _sInfo , std::make_tuple( iInfo ) ); +#else // !SOFT_DIRICHLET + sInfo->solution = sInfo->tree.solveSystem( Sigs() , F , constraints , params.baseDepth , params.solveDepth , _sInfo , std::make_tuple( iInfo ) ); +#endif // SOFT_DIRICHLET + if( params.verbose ) std::cout << "# Linear system solved: " << profiler << std::endl; + if( iInfo ) delete iInfo , iInfo = NULL; +#ifdef SOFT_DIRICHLET + if( dirichletInfo ) delete dirichletInfo , dirichletInfo = NULL; +#endif // SOFT_DIRICHLET + } + } + + // Get the iso-value + { + profiler.reset(); + double valueSum = 0 , weightSum = 0; + typename FEMTree< Dim , Real >::template MultiThreadedEvaluator< Sigs , 0 > evaluator( &sInfo->tree , sInfo->solution ); + std::vector< double > valueSums( ThreadPool::NumThreads() , 0 ) , weightSums( ThreadPool::NumThreads() , 0 ); + ThreadPool::Parallel_for( 0 , samples->size() , [&]( unsigned int thread , size_t j ) + { + ProjectiveData< Point< Real , Dim > , Real >& sample = (*samples)[j].sample; + Real w = sample.weight; + if( w>0 ) weightSums[thread] += w , valueSums[thread] += evaluator.values( sample.data / sample.weight , thread , (*samples)[j].node )[0] * w; + } ); + for( size_t t=0 ; tisoValue = (Real)( valueSum / weightSum ); + if( params.verbose ) + { + std::cout << "Got average: " << profiler << std::endl; + std::cout << "Iso-Value: " << sInfo->isoValue << " = " << valueSum << " / " << weightSum << std::endl; + } + } + delete samples; + return sInfo; + } + + template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > + typename std::conditional< HasAuxData , ReconstructionInfo< Real , Dim , FEMSig , AuxData > , ReconstructionInfo< Real , Dim , FEMSig > >::type *SSD::_Solve( UIntPack< FEMSigs ... > , InputSampleStreamType &pointStream , SolutionParameters< Real > params ) + { + static_assert( std::is_same< IsotropicUIntPack< Dim , FEMSig > , UIntPack< FEMSigs... > >::value , "[ERROR] Signatures don't match" ); + + // The signature for the finite-elements representing the auxiliary data (if it's there) + static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; + + /////////////// + // Types --> // + // The packed finite elements signature + typedef UIntPack< FEMSigs ... > Sigs; + + // The degrees of the finite elements across the different axes + typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > Degrees; + + // The signature describing the normals elements + typedef UIntPack< FEMDegreeAndBType< SSD::NormalDegree , DerivativeBoundary< FEMSignature< FEMSigs >::BType , 1 >::BType >::Signature ... > NormalSigs; + + // Type for tracking sample interpolation + typedef typename FEMTree< Dim , Real >::template InterpolationInfo< Real , 1 > InterpolationInfo; + + // The finite-element tracking tree node + typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; + + // The type of the auxiliary information (including the normal) + typedef typename std::conditional< HasAuxData , VectorTypeUnion< Real , Normal< Real , Dim > , AuxData > , Normal< Real , Dim > >::type NormalAndAuxData; + + // The type describing the sampling density + typedef typename std::conditional< HasAuxData , ReconstructionInfo< Real , Dim , FEMSig , AuxData > , ReconstructionInfo< Real , Dim , FEMSig > >::type::DensityEstimator DensityEstimator; + // <-- Types // + /////////////// + + // The solution info to be returned + typename std::conditional< HasAuxData , ReconstructionInfo< Real , Dim , FEMSig , AuxData > , ReconstructionInfo< Real , Dim , FEMSig > >::type *sInfo; + if constexpr( HasAuxData ) sInfo = new ReconstructionInfo< Real , Dim , FEMSig , AuxData >( pointStream.zero() ); + else sInfo = new ReconstructionInfo< Real , Dim , FEMSig >(); + + NormalAndAuxData zeroNormalAndAuxData; + if constexpr( HasAuxData ) zeroNormalAndAuxData = NormalAndAuxData( Normal< Real , Dim >() , sInfo->zeroAuxData ); + + XForm< Real , Dim+1 > modelToUnitCube = XForm< Real , Dim+1 >::Identity(); + + Profiler profiler(20); + + size_t pointCount; + + ProjectiveData< Point< Real , 2 > , Real > pointDepthAndWeight; + SparseNodeData< Point< Real , Dim > , NormalSigs > *normalInfo = NULL; + std::vector< typename FEMTree< Dim , Real >::PointSample > *samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); + std::vector< NormalAndAuxData > *sampleNormalAndAuxData = NULL; + + Real targetValue = (Real)0.0; + + // Read in the samples (and auxiliary data) + { + profiler.reset(); + + pointStream.reset(); + sampleNormalAndAuxData = new std::vector< NormalAndAuxData >(); + + modelToUnitCube = params.scale>0 ? GetPointXForm< Real , Dim >( pointStream , zeroNormalAndAuxData , params.scale ) * modelToUnitCube : modelToUnitCube; + + if( params.width>0 ) + { + Real maxScale = 0; + for( unsigned int i=0 ; i( maxScale , (Real)1./modelToUnitCube(i,i) ); + params.depth = (unsigned int)ceil( std::max< double >( 0. , log( maxScale/params.width )/log(2.) ) ); + } + if( params.solveDepth>params.depth ) + { + if( params.solveDepth!=-1 ) WARN( "Solution depth cannot exceed system depth: " , params.solveDepth , " <= " , params.depth ); + params.solveDepth = params.depth; + } + if( params.fullDepth>params.solveDepth ) + { + if( params.fullDepth!=-1 ) WARN( "Full depth cannot exceed system depth: " , params.fullDepth , " <= " , params.solveDepth ); + params.fullDepth = params.solveDepth; + } + if( params.baseDepth>params.fullDepth ) + { + if( params.baseDepth!=-1 ) WARN( "Base depth must be smaller than full depth: " , params.baseDepth , " <= " , params.fullDepth ); + params.baseDepth = params.fullDepth; + } + if( params.kernelDepth==-1 ) params.kernelDepth = params.depth>2 ? params.depth-2 : 0; + if( params.kernelDepth>params.depth ) + { + if( params.kernelDepth!=-1 ) WARN( "Kernel depth cannot exceed system depth: " , params.kernelDepth , " <= " , params.depth ); + params.kernelDepth = params.depth; + } + + if constexpr( HasAuxData ) + { +#ifdef DE_VIRTUALIZE_OUTPUT + TransformedInputSampleWithDataStream< Real , Dim , AuxData , InputSampleStreamType > _pointStream( modelToUnitCube , pointStream ); +#else // !DE_VIRTUALIZE_OUTPUT + TransformedInputSampleWithDataStream< Real , Dim , AuxData > _pointStream( modelToUnitCube , pointStream ); +#endif // DE_VIRTUALIZE_OUTPUT + auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , NormalAndAuxData &d ) + { + Real l = (Real)Length( d.template get<0>() ); + if( !l || !std::isfinite( l ) ) return (Real)-1.; + return (Real)pow( l , params.confidence ); + }; + auto ProcessData = []( const Point< Real , Dim > &p , NormalAndAuxData &d ) + { + Real l = (Real)Length( d.template get<0>() ); + if( !l || !std::isfinite( l ) ) return (Real)-1.; + d.template get<0>() /= l; + return (Real)1.; + }; + + typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; + if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , sInfo->tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , sInfo->tree.nodeAllocators.size() ? sInfo->tree.nodeAllocators[0] : NULL , sInfo->tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , sInfo->tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , sInfo->tree.nodeAllocators.size() ? sInfo->tree.nodeAllocators[0] : NULL , sInfo->tree.initializer() , ProcessData ); + } + else + { +#ifdef DE_VIRTUALIZE_OUTPUT + TransformedInputSampleStream< Real , Dim , InputSampleStreamType > _pointStream( modelToUnitCube , pointStream ); +#else // !DE_VIRTUALIZE_OUTPUT + TransformedInputSampleStream< Real , Dim > _pointStream( modelToUnitCube , pointStream ); +#endif // DE_VIRTUALIZE_OUTPUT + auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , NormalAndAuxData &d ) + { + Real l = (Real)Length( d ); + if( !l || !std::isfinite( l ) ) return (Real)-1.; + return (Real)pow( l , params.confidence ); + }; + auto ProcessData = []( const Point< Real , Dim > &p , NormalAndAuxData &d ) + { + Real l = (Real)Length( d ); + if( !l || !std::isfinite( l ) ) return (Real)-1.; + d /= l; + return (Real)1.; + }; + + typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; + if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , sInfo->tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , sInfo->tree.nodeAllocators.size() ? sInfo->tree.nodeAllocators[0] : NULL , sInfo->tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , sInfo->tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , sInfo->tree.nodeAllocators.size() ? sInfo->tree.nodeAllocators[0] : NULL , sInfo->tree.initializer() , ProcessData ); + } + + sInfo->unitCubeToModel = modelToUnitCube.inverse(); + + if( params.verbose ) + { + std::cout << "Input Points / Samples: " << pointCount << " / " << samples->size() << std::endl; + std::cout << "# Read input into tree: " << profiler << std::endl; + } + } + { + DenseNodeData< Real , Sigs > constraints; + InterpolationInfo *iInfo = NULL; + int solveDepth = params.depth; + + sInfo->tree.resetNodeIndices( 0 , std::make_tuple() ); + + // Get the kernel density estimator + { + profiler.reset(); + sInfo->density = sInfo->tree.template setDensityEstimator< 1 , Reconstructor::WeightDegree >( *samples , params.kernelDepth , params.samplesPerNode ); + if( params.verbose ) std::cout << "# Got kernel density: " << profiler << std::endl; + } + + // Transform the Hermite samples into a vector field + { + profiler.reset(); + normalInfo = new SparseNodeData< Point< Real , Dim > , NormalSigs >(); + std::function< bool ( NormalAndAuxData , Point< Real , Dim > & ) > ConversionFunction; + std::function< bool ( NormalAndAuxData , Point< Real , Dim > & , Real & ) > ConversionAndBiasFunction; + if constexpr( HasAuxData ) + { + ConversionFunction = []( NormalAndAuxData in , Point< Real , Dim > &out ) + { + Point< Real , Dim > n = in.template get<0>(); + Real l = (Real)Length( n ); + // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... + if( !l ) return false; + out = n / l; + return true; + }; + ConversionAndBiasFunction = [&]( NormalAndAuxData in , Point< Real , Dim > &out , Real &bias ) + { + Point< Real , Dim > n = in.template get<0>(); + Real l = (Real)Length( n ); + // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... + if( !l ) return false; + out = n / l; + bias = (Real)( log( l ) * params.confidenceBias / log( 1<<(Dim-1) ) ); + return true; + }; + } + else + { + // In this case NormalAndAuxData = Point< Real , Dim > + ConversionFunction = []( NormalAndAuxData in , Point< Real , Dim > &out ) + { + Real l = (Real)Length( in ); + // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... + if( !l ) return false; + out = in / l; + return true; + }; + ConversionAndBiasFunction = [&]( NormalAndAuxData in , Point< Real , Dim > &out , Real &bias ) + { + Real l = (Real)Length( in ); + // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... + if( !l ) return false; + out = in / l; + bias = (Real)( log( l ) * params.confidenceBias / log( 1<<(Dim-1) ) ); + return true; + }; + } + if( params.confidenceBias>0 ) *normalInfo = sInfo->tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , sInfo->density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionAndBiasFunction ); + else *normalInfo = sInfo->tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , sInfo->density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionFunction ); + if( params.verbose ) + { + std::cout << "# Got normal field: " << profiler << std::endl; + std::cout << "Point depth / Point weight / Estimated measure: " << pointDepthAndWeight.value()[0] << " / " << pointDepthAndWeight.value()[1] << " / " << pointCount*pointDepthAndWeight.value()[1] << std::endl; + } + } + + if( !params.outputDensity ){ delete sInfo->density ; sInfo->density = NULL; } + if constexpr( HasAuxData ) sInfo->auxData = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( sInfo->tree.template setExtrapolatedDataField< DataSig , false , Reconstructor::WeightDegree , AuxData >( samples->size() , [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return (*samples)[i]; } , [&]( size_t i ) -> const AuxData & { return (*sampleNormalAndAuxData)[i].template get<1>(); } , (DensityEstimator*)NULL ) ); + + // Add the interpolation constraints + if( params.pointWeight>0 || params.gradientWeight>0 ) + { + profiler.reset(); + if constexpr( HasAuxData ) + { + if( params.exactInterpolation ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , NormalAndAuxData , 1 >( sInfo->tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real , AuxData >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real , AuxData >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , false ); + else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , NormalAndAuxData , 1 >( sInfo->tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real , AuxData >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real , AuxData >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , params.depth , 1 ); + } + else + { + if( params.exactInterpolation ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , Point< Real , Dim > , 1 >( sInfo->tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , false ); + else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , Point< Real , Dim > , 1 >( sInfo->tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , params.depth , 1 ); + } + if( params.verbose ) std::cout << "#Initialized point interpolation constraints: " << profiler << std::endl; + } + + delete sampleNormalAndAuxData; + + + // Trim the tree and prepare for multigrid + { + profiler.reset(); + constexpr int MaxDegree = SSD::NormalDegree > Degrees::Max() ? SSD::NormalDegree : Degrees::Max(); + typename FEMTree< Dim , Real >::template HasNormalDataFunctor< NormalSigs > hasNormalDataFunctor( *normalInfo ); + auto hasDataFunctor = [&]( const FEMTreeNode *node ){ return hasNormalDataFunctor( node ); }; + auto addNodeFunctor = [&]( int d , const int off[Dim] ){ return d<=(int)params.fullDepth; }; + if constexpr( HasAuxData ) sInfo->tree.template finalizeForMultigrid< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , sInfo->density , sInfo->auxData ) ); + else sInfo->tree.template finalizeForMultigrid< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , sInfo->density ) ); + + if( params.verbose ) std::cout << "# Finalized tree: " << profiler << std::endl; + } + + // Free up the normal info + delete normalInfo , normalInfo = NULL; + + if( params.pointWeight>0 || params.gradientWeight>0 ) + { + profiler.reset(); + constraints = sInfo->tree.initDenseNodeData( Sigs() ); + sInfo->tree.addInterpolationConstraints( constraints , solveDepth , std::make_tuple( iInfo ) ); + if( params.verbose ) std::cout << "#Set point constraints: " << profiler << std::endl; + } + + if( params.verbose ) std::cout << "All Nodes / Active Nodes / Ghost Nodes: " << sInfo->tree.allNodes() << " / " << sInfo->tree.activeNodes() << " / " << sInfo->tree.ghostNodes() << std::endl; + if( params.verbose ) std::cout << "Memory Usage: " << float( MemoryInfo::Usage())/(1<<20) << " MB" << std::endl; + + // Solve the linear system + { + profiler.reset(); + typename FEMTree< Dim , Real >::SolverInfo _sInfo; + _sInfo.cgDepth = 0 , _sInfo.cascadic = true , _sInfo.vCycles = 1 , _sInfo.iters = params.iters , _sInfo.cgAccuracy = params.cgSolverAccuracy , _sInfo.verbose = params.verbose , _sInfo.showResidual = params.showResidual , _sInfo.showGlobalResidual = SHOW_GLOBAL_RESIDUAL_NONE , _sInfo.sliceBlockSize = 1; + _sInfo.baseVCycles = params.baseVCycles; + typename FEMIntegrator::template System< Sigs , IsotropicUIntPack< Dim , 2 > > F( { 0. , 0. , (double)params.biLapWeight } ); + sInfo->solution = sInfo->tree.solveSystem( Sigs() , F , constraints , params.baseDepth , params.solveDepth , _sInfo , std::make_tuple( iInfo ) ); + if( params.verbose ) std::cout << "# Linear system solved: " << profiler << std::endl; + if( iInfo ) delete iInfo , iInfo = NULL; + } + } + + // Get the iso-value + { + profiler.reset(); + double valueSum = 0 , weightSum = 0; + typename FEMTree< Dim , Real >::template MultiThreadedEvaluator< Sigs , 0 > evaluator( &sInfo->tree , sInfo->solution ); + std::vector< double > valueSums( ThreadPool::NumThreads() , 0 ) , weightSums( ThreadPool::NumThreads() , 0 ); + ThreadPool::Parallel_for( 0 , samples->size() , [&]( unsigned int thread , size_t j ) + { + ProjectiveData< Point< Real , Dim > , Real >& sample = (*samples)[j].sample; + Real w = sample.weight; + if( w>0 ) weightSums[thread] += w , valueSums[thread] += evaluator.values( sample.data / sample.weight , thread , (*samples)[j].node )[0] * w; + } ); + for( size_t t=0 ; tisoValue = (Real)( valueSum / weightSum ); + if( params.verbose ) + { + std::cout << "Got average: " << profiler << std::endl; + std::cout << "Iso-Value: " << sInfo->isoValue << " = " << valueSum << " / " << weightSum << std::endl; + } + } + delete samples; + return sInfo; + } +} + + +#endif // RECONSTRUCTORS_INCLUDED \ No newline at end of file diff --git a/Src/Reconstructors.streams.h b/Src/Reconstructors.streams.h new file mode 100644 index 00000000..fef15dcb --- /dev/null +++ b/Src/Reconstructors.streams.h @@ -0,0 +1,645 @@ +/* +Copyright (c) 2022, 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 RECONSTRUCTORS_STREAMS_INCLUDED +#define RECONSTRUCTORS_STREAMS_INCLUDED + +#include + +// Basic types +template< typename Real , unsigned int Dim > +using BaseSample = VectorTypeUnion< Real , Position< Real , Dim > , Normal< Real , Dim > >; + +template< typename Real , unsigned int Dim , typename Data > +using BaseSampleWithData = VectorTypeUnion< Real , Position< Real , Dim > , VectorTypeUnion< Real , Normal< Real , Dim > , Data > >; + +template< typename Real , unsigned int Dim > +using BaseVertex = VectorTypeUnion< Real , Position< Real , Dim > , Normal< Real , Dim > , Real >; + +template< typename Real , unsigned int Dim , typename Data > +using BaseVertexWithData = VectorTypeUnion< Real , Position< Real , Dim > , Gradient< Real , Dim > , Real , Data >; + +using Polygon = std::vector< node_index_type >; + +// Basic streams +template< typename Real , unsigned int Dim > using BaseInputSampleStream = InputDataStream< BaseSample < Real , Dim > >; +template< typename Real , unsigned int Dim , typename Data > using BaseInputSampleWithDataStream = InputDataStream< BaseSampleWithData< Real , Dim , Data > >; + +template< typename Real , unsigned int Dim > using BaseOutputVertexStream = OutputDataStream< BaseVertex < Real , Dim > >; +template< typename Real , unsigned int Dim , typename Data > using BaseOutputVertexWithDataStream = OutputDataStream< BaseVertexWithData< Real , Dim , Data > >; + +using InputPolygonStream = InputDataStream< Polygon >; +using OutputPolygonStream = OutputDataStream< Polygon >; + +/////////////////////////// +// Oriented Point Stream // +/////////////////////////// +template< typename Real , unsigned int Dim > +struct InputSampleStream : public BaseInputSampleStream< Real , Dim > +{ + // Functionality to reset the stream to the start + virtual void reset( void ) = 0; + + // Functionality to extract the next position/normal pair. + // The method returns true if there was another point in the stream to read, and false otherwise + virtual bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n ) = 0; + // Implementation of InputDataStream::read + bool base_read( BaseSample< Real , Dim > &s ){ return base_read( s.template get<0>() , s.template get<1>() ); } +}; + +/////////////////////////////////// +// Oriented Point w/ Data Stream // +/////////////////////////////////// +template< typename Real , unsigned int Dim , typename Data > +struct InputSampleWithDataStream : public BaseInputSampleWithDataStream< Real , Dim , Data > +{ + // A constructor initialized with an instance of "zero" data + InputSampleWithDataStream( Data zero ) : _zero(zero) {} + + // Functionality to reset the stream to the start + virtual void reset( void ) = 0; + + // Returns the zero instance + const Data &zero( void ) const{ return _zero; } + + // Functionality to extract the next position/normal pair. + // The method returns true if there was another point in the stream to read, and false otherwise + virtual bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n , Data &d ) = 0; + bool base_read( BaseSampleWithData< Real , Dim , Data > &s ){ return base_read( s.template get<0>() , s.template get<1>().template get<0>() , s.template get<1>().template get<1>() ); } + + // An instance of "zero" data + Data _zero; +}; + + +/////////////////////////////////////// +// Transformed Oriented Point Stream // +/////////////////////////////////////// +#ifdef DE_VIRTUALIZE_INPUT +template< typename Real , unsigned int Dim , typename InputStream > +#else // !DE_VIRTUALIZE_INPUT +template< typename Real , unsigned int Dim > +#endif // DE_VIRTUALIZE_INPUT +struct TransformedInputSampleStream : public InputSampleStream< Real , Dim > +{ +#ifdef DE_VIRTUALIZE_INPUT + static_assert( std::is_base_of< InputSampleStream< Real , Dim > , InputStream >::value , "[ERROR] Unexpected stream type" ); +#endif // DE_VIRTUALIZE_INPUT + // A constructor initialized with the transformation to be applied to the samples, and a sample stream +#ifdef DE_VIRTUALIZE_INPUT + TransformedInputSampleStream( XForm< Real , Dim+1 > xForm , InputStream &stream ) : _stream(stream) , _positionXForm(xForm) +#else // !DE_VIRTUALIZE_INPUT + TransformedInputSampleStream( XForm< Real , Dim+1 > xForm , InputSampleStream< Real , Dim > &stream ) : _stream(stream) , _positionXForm(xForm) +#endif // DE_VIRTUALIZE_INPUT + { + _normalXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); + } + + // Functionality to reset the stream to the start + void reset( void ){ _stream.reset(); } + + // Functionality to extract the next position/normal pair. + // The method returns true if there was another point in the stream to read, and false otherwise + bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n ) + { + BaseSample< Real , Dim > s; + bool ret = _stream.read( s ); + if( ret ) p = _positionXForm * s.template get<0>() , n = _normalXForm * s.template get<1>(); + return ret; + } + +protected: + // A reference to the underlying stream +#ifdef DE_VIRTUALIZE_INPUT + InputStream &_stream; +#else // !DE_VIRTUALIZE_INPUT + InputSampleStream< Real , Dim > &_stream; +#endif // DE_VIRTUALIZE_INPUT + + // The affine transformation to be applied to the positions + XForm< Real , Dim+1 > _positionXForm; + + // The linear transformation to be applied to the normals + XForm< Real , Dim > _normalXForm; +}; + +/////////////////////////////////////////////// +// Transformed Oriented Point w/ Data Stream // +/////////////////////////////////////////////// +#ifdef DE_VIRTUALIZE_INPUT +template< typename Real , unsigned int Dim , typename Data , typename InputStream > +#else // !DE_VIRTUALIZE_INPUT +template< typename Real , unsigned int Dim , typename Data > +#endif // DE_VIRTUALIZE_INPUT +struct TransformedInputSampleWithDataStream : public InputSampleWithDataStream< Real , Dim , Data > +{ +#ifdef DE_VIRTUALIZE_INPUT + static_assert( std::is_base_of< InputSampleWithDataStream< Real , Dim , Data > , InputStream >::value , "[ERROR] Unexpected stream type" ); +#endif // DE_VIRTUALIZE_INPUT + // A constructor initialized with an instance of "zero" data +#ifdef DE_VIRTUALIZE_INPUT + TransformedInputSampleWithDataStream( XForm< Real , Dim+1 > xForm , InputStream &stream ) : InputSampleWithDataStream< Real , Dim , Data >( stream.zero() ) , _stream(stream) , _positionXForm(xForm) +#else // !DE_VIRTUALIZE_INPUT + TransformedInputSampleWithDataStream( XForm< Real , Dim+1 > xForm , InputSampleWithDataStream< Real , Dim , Data > &stream ) : InputSampleWithDataStream< Real , Dim , Data >( stream.zero() ) , _stream(stream) , _positionXForm(xForm) +#endif // DE_VIRTUALIZE_INPUT + { + _normalXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); + } + + // Functionality to reset the stream to the start + void reset( void ){ _stream.reset(); } + + // Functionality to extract the next position/normal pair. + // The method returns true if there was another point in the stream to read, and false otherwise + bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n , Data &d ) + { + BaseSampleWithData< Real , Dim , Data > s( Position< Real , Dim >() , VectorTypeUnion< Real , Normal< Real , Dim > , Data >( Normal< Real , Dim >() , _stream.zero() ) ); + bool ret = _stream.read( s ); + if( ret ) p = _positionXForm * s.template get<0>() , n = _normalXForm * s.template get<1>().template get<0>() , d = s.template get<1>().template get<1>(); + return ret; + } + +protected: + // A reference to the underlying stream +#ifdef DE_VIRTUALIZE_INPUT + InputStream &_stream; +#else // !DE_VIRTUALIZE_INPUT + InputSampleWithDataStream< Real , Dim , Data > &_stream; +#endif // DE_VIRTUALIZE_INPUT + + // The affine transformation to be applied to the positions + XForm< Real , Dim+1 > _positionXForm; + + // The linear transformation to be applied to the normals + XForm< Real , Dim > _normalXForm; +}; + + +/////////////////// +// Vertex Stream // +/////////////////// +template< typename Real , unsigned int Dim > +struct OutputVertexStream : public BaseOutputVertexStream< Real , Dim > +{ + // Need to provide access to base write for counter support + using BaseOutputVertexStream< Real , Dim >::write; + + // Functionality to insert the next vertex + virtual void base_write( Position< Real , Dim > p , Gradient< Real , Dim > g , Real w ) = 0; + void base_write( const BaseVertex< Real , Dim > &v ){ base_write( v.template get<0>() , v.template get<1>() , v.template get<2>() ); } +}; + +/////////////////////////// +// Vertex w/ Data Stream // +/////////////////////////// +template< typename Real , unsigned int Dim , typename Data > +struct OutputVertexWithDataStream : public BaseOutputVertexWithDataStream< Real , Dim , Data > +{ + // Need to provide access to base write for counter support + using BaseOutputVertexWithDataStream< Real , Dim , Data >::write; + + // Functionality to insert the next vertex + virtual void base_write( Position< Real , Dim > p , Gradient< Real , Dim > g , Real w , Data d ) = 0; + void base_write( const BaseVertexWithData< Real , Dim , Data > &v ){ return base_write( v.template get<0>() , v.template get<1>() , v.template get<2>() , v.template get<3>() ); } +}; + +/////////////////////////////// +// Transformed Vertex Stream // +/////////////////////////////// +template< typename Real , unsigned int Dim > +struct TransformedOutputVertexStream : public OutputVertexStream< Real , Dim > +{ + // A constructor initialized with the transformation to be applied to the samples, and a sample stream + TransformedOutputVertexStream( XForm< Real , Dim+1 > xForm , OutputVertexStream< Real , Dim > &stream ) : _stream(stream) , _positionXForm(xForm) + { + _gradientXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); + } + + // Need to write the union to ensure that the counter gets set + void base_write( Position< Real , Dim > p , Normal< Real , Dim > g , Real w ){ _stream.write( BaseVertex< Real , Dim >( _positionXForm * p , _gradientXForm * g , w ) ); } + +protected: + // A reference to the underlying stream + OutputVertexStream< Real , Dim > &_stream; + + // The affine transformation to be applied to the positions + XForm< Real , Dim+1 > _positionXForm; + + // The linear transformation to be applied to the normals + XForm< Real , Dim > _gradientXForm; +}; + + +/////////////////////////////////////// +// Transformed Vertex w/ Data Stream // +/////////////////////////////////////// +template< typename Real , unsigned int Dim , typename Data > +struct TransformedOutputVertexWithDataStream : public OutputVertexWithDataStream< Real , Dim , Data > +{ + // A constructor initialized with the transformation to be applied to the samples, and a sample stream + TransformedOutputVertexWithDataStream( XForm< Real , Dim+1 > xForm , OutputVertexWithDataStream< Real , Dim , Data > &stream ) : _stream(stream) , _positionXForm(xForm) + { + _gradientXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); + } + + void base_write( Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ){ _stream.write( BaseVertexWithData< Real , Dim , Data >( _positionXForm * p , _gradientXForm * g , w , d ) ); } + +protected: + // A reference to the underlying stream + OutputVertexWithDataStream< Real , Dim , Data > &_stream; + + // The affine transformation to be applied to the positions + XForm< Real , Dim+1 > _positionXForm; + + // The linear transformation to be applied to the normals + XForm< Real , Dim > _gradientXForm; +}; + +/////////////////////////////////////////// +// A wrapper class to write out vertices // +/////////////////////////////////////////// +template< typename Real , unsigned int Dim , typename Vertex > +struct OutputVertexStreamWrapper : public OutputVertexStream< Real , Dim > +{ + virtual void set( Vertex &out , const BaseVertex< Real , Dim > &in ) = 0; + + OutputVertexStreamWrapper( OutputDataStream< Vertex > &stream , Vertex out ) : _stream(stream) , _out(out) {} + + void base_write( Position< Real , Dim > p , Normal< Real , Dim > g , Real w ) + { + _in.template get<0>() = p; + _in.template get<1>() = g; + _in.template get<2>() = w; + set( _out , _in ); + _stream.write( _out ); + } +protected: + OutputDataStream< Vertex > &_stream; + BaseVertex< Real , Dim > _in; + Vertex _out; +}; + +template< typename Real , unsigned int Dim , typename Data , typename Vertex > +struct OutputVertexWithDataStreamWrapper : public OutputVertexWithDataStream< Real , Dim , Data > +{ + virtual void set( Vertex &out , const BaseVertexWithData< Real , Dim , Data > &in ) = 0; + + OutputVertexWithDataStreamWrapper( OutputDataStream< Vertex > &stream , BaseVertexWithData< Real , Dim , Data > in , Vertex out ) : _stream(stream) , _in(in) , _out(out) {} + + void base_write( Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ) + { + _in.template get<0>() = p; + _in.template get<1>() = g; + _in.template get<2>() = w; + _in.template get<3>() = d; + set( _out , _in ); + _stream.write( _out ); + } +protected: + OutputDataStream< Vertex > &_stream; + BaseVertexWithData< Real , Dim , Data > _in; + Vertex _out; +}; + + +///////////////////////////////////////////////////////////////////////////////// +// Output and the input polygon stream, backed either by a file or by a vector // +///////////////////////////////////////////////////////////////////////////////// +// [WARNING] These assume that the stream starts as write-only and after the reset method is invoked, the stream becomes read-only. + +struct OutputInputPolygonStream : public OutputPolygonStream , public InputPolygonStream +{ + // The streams for communicating the information + InputPolygonStream * inStream; + OutputPolygonStream *outStream; + + void reset( void ){ inStream->reset(); } + bool base_read( Polygon &p ){ return inStream->read(p); } + bool base_read( unsigned int t , Polygon &p ){ return inStream->read(t,p); } + void base_write( const Polygon &p ){ outStream->write(p); } + void base_write( unsigned int t , const Polygon &p ){ outStream->write(t,p); } + + OutputInputPolygonStream( bool inCore , bool multi , std::string header="" ) + { + size_t sz = std::thread::hardware_concurrency(); + + _backingVector = NULL; + _backingVectors.resize( sz , NULL ); + + _backingFile = NULL; + _backingFiles.resize( sz , NULL ); + + _inStreams.resize( sz , NULL ); + _outStreams.resize( sz , NULL ); + + if( inCore ) + { + if( multi ) + { + for( unsigned int i=0 ; i(); + _inStreams[i] = new VectorBackedInputDataStream< Polygon >( *_backingVectors[i] ); + _outStreams[i] = new VectorBackedOutputDataStream< Polygon >( *_backingVectors[i] ); + } + inStream = new MultiInputDataStream< Polygon >( _inStreams ); + outStream = new MultiOutputDataStream< Polygon >( _outStreams ); + } + else + { + _backingVector = new std::vector< Polygon >(); + + inStream = new VectorBackedInputDataStream< Polygon >( *_backingVector ); + outStream = new VectorBackedOutputDataStream< Polygon >( *_backingVector ); + } + } + else + { + if( multi ) + { + for( unsigned int i=0 ; i( _backingFiles[i]->fp ); + _outStreams[i] = new FileBackedOutputDataStream< Polygon >( _backingFiles[i]->fp ); + } + inStream = new MultiInputDataStream< std::vector< node_index_type > >( _inStreams ); + outStream = new MultiOutputDataStream< std::vector< node_index_type > >( _outStreams ); + } + else + { + _backingFile = new FileBackedReadWriteStream::FileDescription( header.c_str() ); + + inStream = new FileBackedInputDataStream< Polygon >( _backingFile->fp ); + outStream = new FileBackedOutputDataStream< Polygon >( _backingFile->fp ); + } + } + } + ~OutputInputPolygonStream( void ) + { + size_t sz = std::thread::hardware_concurrency(); + + delete _backingVector; + + if( _backingFile ) _backingFile->remove(); + delete _backingFile; + + for( unsigned int i=0 ; iremove(); + delete _backingFiles[i]; + + delete _inStreams[i]; + delete _outStreams[i]; + } + + delete inStream; + delete outStream; + } +protected: + std::vector< Polygon > *_backingVector; + FileBackedReadWriteStream::FileDescription *_backingFile; + std::vector< std::vector< Polygon > * > _backingVectors; + std::vector< FileBackedReadWriteStream::FileDescription * > _backingFiles; + std::vector< InputDataStream< Polygon > * > _inStreams; + std::vector< OutputDataStream< Polygon > * > _outStreams; +}; + +template< typename Factory > +struct OutputInputFactoryTypeStream : public OutputDataStream< typename Factory::VertexType > , public InputDataStream< typename Factory::VertexType > +{ + typedef typename Factory::VertexType Vertex; + // The streams for communicating the information + InputDataStream < Vertex > * inStream; + OutputDataStream< Vertex > *outStream; + + void reset( void ){ inStream->reset(); } + void base_write( const Vertex &v ){ outStream->write( v ); } + bool base_read( Vertex &v ){ return inStream->read( v ); } + + OutputInputFactoryTypeStream( Factory &factory , bool inCore , bool multi , std::string header="" ) + { + size_t sz = std::thread::hardware_concurrency(); + + _backingVector = NULL; + _backingVectors.resize( sz , NULL ); + + _backingFile = NULL; + _backingFiles.resize( sz , NULL ); + + _inStreams.resize( sz , NULL ); + _outStreams.resize( sz , NULL ); + + if( inCore ) + { + if( multi ) + { + for( unsigned int i=0 ; i(); + _inStreams[i] = new VectorBackedInputDataStream< Vertex >( *_backingVectors[i] ); + _outStreams[i] = new VectorBackedOutputDataStream< Vertex >( *_backingVectors[i] ); + } + inStream = new MultiInputDataStream< Vertex >( _inStreams ); + outStream = new MultiOutputDataStream< Vertex >( _outStreams ); + } + else + { + _backingVector = new std::vector< Vertex >(); + + inStream = new VectorBackedInputDataStream< Vertex >( *_backingVector ); + outStream = new VectorBackedOutputDataStream< Vertex >( *_backingVector ); + } + } + else + { + if( multi ) + { + for( unsigned int i=0 ; i( _backingFiles[i]->fp , factory ); + _outStreams[i] = new FileBackedOutputFactoryTypeStream< Factory >( _backingFiles[i]->fp , factory ); + } + inStream = new MultiInputDataStream< Vertex >( _inStreams ); + outStream = new MultiOutputDataStream< Vertex >( _outStreams ); + } + else + { + _backingFile = new FileBackedReadWriteStream::FileDescription( header.c_str() ); + + inStream = new FileBackedInputFactoryTypeStream< Factory >( _backingFile->fp , factory ); + outStream = new FileBackedOutputFactoryTypeStream< Factory >( _backingFile->fp , factory ); + } + } + } + + ~OutputInputFactoryTypeStream( void ) + { + size_t sz = std::thread::hardware_concurrency(); + + delete _backingVector; + if( _backingFile ) _backingFile->remove(); + delete _backingFile; + + for( unsigned int i=0 ; iremove(); + delete _backingFiles[i]; + + delete _inStreams[i]; + delete _outStreams[i]; + } + + delete inStream; + delete outStream; + } +protected: + std::vector< Vertex > *_backingVector; + FileBackedReadWriteStream::FileDescription *_backingFile; + std::vector< std::vector< Vertex > * >_backingVectors; + std::vector< FileBackedReadWriteStream::FileDescription * > _backingFiles; + std::vector< InputDataStream< Vertex > * > _inStreams; + std::vector< OutputDataStream< Vertex > * > _outStreams; +}; + +template< typename Real , unsigned int Dim , bool HasGradients , bool HasDensity > +struct OutputVertexInfo +{ + using Factory = + typename std::conditional + < + HasGradients , + typename std::conditional + < + HasDensity , + VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::NormalFactory< Real , Dim > , VertexFactory::ValueFactory< Real > > , + VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::NormalFactory< Real , Dim > > + >::type , + typename std::conditional + < + HasDensity , + VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::ValueFactory< Real > > , + VertexFactory::PositionFactory< Real , Dim > + >::type + >::type; + using Vertex = typename Factory::VertexType; + + static Factory GetFactory( void ){ return Factory(); } + + struct StreamWrapper : public Reconstructor::OutputVertexStreamWrapper< Real , Dim , Vertex > + { + StreamWrapper( OutputDataStream< Vertex > &stream , Vertex out ) : + Reconstructor::OutputVertexStreamWrapper< Real , Dim , Vertex >( stream , out ){} + void set( Vertex &out , const Reconstructor::BaseVertex< Real , Dim > &in ) + { + if constexpr( HasGradients || HasDensity ) + { + out.template get<0>() = in.template get<0>(); + if constexpr( HasGradients ) + { + out.template get<1>() = in.template get<1>(); + if constexpr( HasDensity ) out.template get<2>() = in.template get<2>(); + } + else + { + if constexpr( HasDensity ) out.template get<1>() = in.template get<2>(); + } + } + else out = in.template get<0>(); + } + }; +}; + +template< typename Real , unsigned int Dim , typename AuxDataFactory , bool HasGradients , bool HasDensity > +struct OutputVertexWithDataInfo +{ + using Factory = + typename std::conditional + < + HasGradients , + typename std::conditional + < + HasDensity , + VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::NormalFactory< Real , Dim > , VertexFactory::ValueFactory< Real > , AuxDataFactory > , + VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::NormalFactory< Real , Dim > , AuxDataFactory > + >::type , + typename std::conditional + < + HasDensity , + VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::ValueFactory< Real > , AuxDataFactory > , + VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , AuxDataFactory > + >::type + >::type; + using AuxData = typename AuxDataFactory::VertexType; + + using _Vertex = VectorTypeUnion< Real , Point< Real , Dim > , Point< Real , Dim > , Real , typename AuxDataFactory::VertexType >; + using Vertex = typename Factory::VertexType; + + static Factory GetFactory( AuxDataFactory auxDataFactory ) + { + if constexpr( HasGradients ) + { + if constexpr( HasDensity ) return Factory( VertexFactory::PositionFactory< Real , Dim >() , VertexFactory::NormalFactory< Real , Dim >() , VertexFactory::ValueFactory< Real >() , auxDataFactory ); + else return Factory( VertexFactory::PositionFactory< Real , Dim >() , VertexFactory::NormalFactory< Real , Dim >() , auxDataFactory ); + } + else + { + if constexpr( HasDensity ) return Factory( VertexFactory::PositionFactory< Real , Dim >() , VertexFactory::ValueFactory< Real >() , auxDataFactory ); + else return Factory( VertexFactory::PositionFactory< Real , Dim >() , auxDataFactory ); + } + } + + struct StreamWrapper : public Reconstructor::OutputVertexWithDataStreamWrapper< Real , Dim , AuxData , Vertex > + { + StreamWrapper( OutputDataStream< Vertex > &stream , Vertex out ) : + Reconstructor::OutputVertexWithDataStreamWrapper< Real , Dim , AuxData , Vertex >( stream , _Vertex() , out ){} + + void set( Vertex &out , const Reconstructor::BaseVertexWithData< Real , Dim , AuxData > &in ) + { + out.template get<0>() = in.template get<0>(); + if constexpr( HasGradients ) + { + out.template get<1>() = in.template get<1>(); + if constexpr( HasDensity ) out.template get<2>() = in.template get<2>() , out.template get<3>() = in.template get<3>(); + else out.template get<2>() = in.template get<3>(); + } + else + { + if constexpr( HasDensity ) out.template get<1>() = in.template get<2>() , out.template get<2>() = in.template get<3>(); + else out.template get<1>() = in.template get<3>(); + } + } + }; +}; + +#endif // RECONSTRUCTORS_STREAMS_INCLUDED \ No newline at end of file diff --git a/Src/RegularTree.h b/Src/RegularTree.h index 3412b1bd..55eea7ec 100644 --- a/Src/RegularTree.h +++ b/Src/RegularTree.h @@ -30,6 +30,7 @@ DAMAGE. #define REGULAR_TREE_NODE_INCLUDED #include +#include "Streams.h" #include "Allocator.h" #include "BinaryNode.h" #include "Window.h" diff --git a/Src/SSDRecon.cpp b/Src/SSDRecon.cpp index 43affc71..3192c4b1 100644 --- a/Src/SSDRecon.cpp +++ b/Src/SSDRecon.cpp @@ -27,15 +27,7 @@ DAMAGE. */ #include "PreProcessor.h" - -#undef USE_DOUBLE // If enabled, double-precesion is used -#define DATA_DEGREE 0 // The order of the B-Spline used to splat in data for color interpolation - // This can be changed to zero if more interpolatory performance is desired. -#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 DEFAULT_FEM_DEGREE 2 // The default finite-element degree -#define DEFAULT_FEM_BOUNDARY BOUNDARY_NEUMANN // The default finite-element boundary type -#define DEFAULT_DIMENSION 3 // The dimension of the system +#include "Reconstructors.h" #include #include @@ -49,17 +41,9 @@ DAMAGE. #include "VertexFactory.h" #include "Image.h" #include "RegularGrid.h" +#include "DataStream.imp.h" -double BaseSSDWeights[] = { 5e+1f , 5e-4f , 1e-5f }; - -enum NormalType -{ - NORMALS_NONE , - NORMALS_SAMPLES , - NORMALS_GRADIENTS , - NORMALS_COUNT -}; -const char* NormalsNames[] = { "none" , "samples" , "gradients" }; +#define DEFAULT_DIMENSION 3 cmdLineParameter< char* > In( "in" ) , @@ -72,7 +56,6 @@ cmdLineParameter< char* > cmdLineReadable Performance( "performance" ) , ShowResidual( "showResidual" ) , - NoComments( "noComments" ) , PolygonMesh( "polygonMesh" ) , NonManifold( "nonManifold" ) , ASCII( "ascii" ) , @@ -82,11 +65,12 @@ cmdLineReadable ExactInterpolation( "exact" ) , Colors( "colors" ) , InCore( "inCore" ) , + Gradients( "gradients" ) , Verbose( "verbose" ); cmdLineParameter< int > #ifndef FAST_COMPILE - Degree( "degree" , DEFAULT_FEM_DEGREE ) , + Degree( "degree" , Reconstructor::SSD::DefaultFEMDegree ) , #endif // !FAST_COMPILE Depth( "depth" , 8 ) , KernelDepth( "kernelDepth" ) , @@ -96,9 +80,8 @@ cmdLineParameter< int > BaseDepth( "baseDepth" ) , BaseVCycles( "baseVCycles" , 4 ) , #ifndef FAST_COMPILE - BType( "bType" , DEFAULT_FEM_BOUNDARY+1 ) , + BType( "bType" , Reconstructor::SSD::DefaultFEMBoundary+1 ) , #endif // !FAST_COMPILE - Normals( "normals" , NORMALS_NONE ) , MaxMemoryGB( "maxMemory" , 0 ) , #ifdef _OPENMP ParallelType( "parallel" , (int)ThreadPool::OPEN_MP ) , @@ -131,7 +114,7 @@ cmdLineReadable* params[] = &SolveDepth , &In , &Depth , &Out , &Transform , &Width , - &Scale , &Verbose , &CGSolverAccuracy , &NoComments , + &Scale , &Verbose , &CGSolverAccuracy , &KernelDepth , &SamplesPerNode , &Confidence , &NonManifold , &PolygonMesh , &ASCII , &ShowResidual , &ConfidenceBias , &ValueWeight , &GradientWeight , &BiLapWeight , @@ -143,7 +126,7 @@ cmdLineReadable* params[] = &Iters , &DataX , &Colors , - &Normals , + &Gradients , &NonLinearFit , &PrimalGrid , &TempDir , @@ -185,8 +168,7 @@ void ShowUsage(char* ex) printf( "\t[--%s]\n" , ExactInterpolation.name ); printf( "\t[--%s =%f]\n" , DataX.name , DataX.value ); printf( "\t[--%s]\n" , Colors.name ); - printf( "\t[--%s =%d]\n" , Normals.name , Normals.value ); - for( int i=0 ; i=%d]\n" , Threads.name , Threads.value ); printf( "\t[--%s =%d]\n" , ParallelType.name , ParallelType.value ); for( size_t i=0 ; i +void WriteMesh +( + bool inCore , + Reconstructor::ReconstructionInfo< Real , Dim , FEMSig > &reconInfo , + const Reconstructor::MeshExtractionParameters &meParams , + std::string fileName , + bool ascii +) { - 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.; - } -} + // A description of the output vertex information + using VInfo = Reconstructor::OutputVertexInfo< Real , Dim , HasGradients , HasDensity >; -template< class Real , unsigned int Dim > -XForm< Real , Dim+1 > GetBoundingBoxXForm( Point< Real , Dim > min , Point< Real , Dim > max , Real scaleFactor ) -{ - Point< Real , Dim > center = ( max + min ) / 2; - Real scale = max[0] - min[0]; - for( int d=1 ; d( scale , max[d]-min[d] ); - scale *= scaleFactor; - for( int i=0 ; i tXForm = XForm< Real , Dim+1 >::Identity() , sXForm = XForm< Real , Dim+1 >::Identity(); - for( int i=0 ; i vertexStream( factory , inCore , false , std::string( "v_" ) ); + Reconstructor::OutputInputPolygonStream polygonStream( inCore , true , std::string( "p_" ) ); -template< typename Real , unsigned int Dim , typename AuxData > -using InputOrientedPointStreamInfo = typename FEMTreeInitializer< Dim , Real >::template InputPointStream< VectorTypeUnion< Real , typename VertexFactory::NormalFactory< Real , Dim >::VertexType , AuxData > >; + { + // The wrapper converting native to output types + typename VInfo::StreamWrapper _vertexStream( vertexStream , factory() ); -template< typename Real , unsigned int Dim , typename AuxData > -using InputOrientedPointStream = typename InputOrientedPointStreamInfo< Real , Dim , AuxData >::StreamType; + // Extract the mesh + Reconstructor::ExtractMesh< Real >( reconInfo , _vertexStream , polygonStream , meParams ); + } -template< class Real , unsigned int Dim , typename AuxData > -XForm< Real , Dim+1 > GetPointXForm( InputOrientedPointStream< Real , Dim , AuxData > &stream , typename InputOrientedPointStreamInfo< Real , Dim , AuxData >::DataType d , Real scaleFactor ) -{ - Point< Real , Dim > min , max; - InputOrientedPointStreamInfo< Real , Dim , AuxData >::BoundingBox( stream , d , min , max ); - return GetBoundingBoxXForm( min , max , scaleFactor ); + // Write the mesh to a .ply file + std::vector< std::string > noComments; + PLY::WritePolygons< Factory , node_index_type , Real , Dim >( fileName , factory , vertexStream.size() , polygonStream.size() , vertexStream , polygonStream , ascii ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); } -template< unsigned int Dim , typename Real , typename TotalPointSampleData > -struct ConstraintDual -{ - Real target , vWeight , gWeight; - ConstraintDual( Real t , Real v , Real g ) : target(t) , vWeight(v) , gWeight(g) { } - CumulativeDerivativeValues< Real , Dim , 1 > operator()( const Point< Real , Dim >& p , const TotalPointSampleData& data ) const - { - Point< Real , Dim > n = data.template get<0>(); - CumulativeDerivativeValues< Real , Dim , 1 > cdv; - cdv[0] = target*vWeight; - for( int d=0 ; d -struct SystemDual -{ - CumulativeDerivativeValues< Real , Dim , 1 > weight; - SystemDual( Real v , Real g ) - { - weight[0] = v; - for( int d=0 ; d operator()( Point< Real , Dim > p , const TotalPointSampleData& data , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const - { - return dValues * weight; - } - CumulativeDerivativeValues< double , Dim , 1 > operator()( Point< Real , Dim > p , const TotalPointSampleData& data , const CumulativeDerivativeValues< double , Dim , 1 >& dValues ) const - { - return dValues * weight; - }; -}; -template< unsigned int Dim , class TotalPointSampleData > -struct SystemDual< Dim , double , TotalPointSampleData > -{ - typedef double Real; - CumulativeDerivativeValues< Real , Dim , 1 > weight; - SystemDual( Real v , Real g ) : weight( v , g , g , g ) { } - CumulativeDerivativeValues< Real , Dim , 1 > operator()( Point< Real , Dim > p , const TotalPointSampleData& data , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const - { - return dValues * weight; - } -}; - -template< typename Real , typename SetVertexFunction , typename InputSampleDataType , typename VertexFactory , unsigned int ... FEMSigs > -void ExtractMesh +template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxDataFactory , bool HasGradients , bool HasDensity > +void WriteMeshWithData ( - UIntPack< FEMSigs ... > , - FEMTree< sizeof ... ( FEMSigs ) , Real >& tree , - const DenseNodeData< Real , UIntPack< FEMSigs ... > >& solution , - Real isoValue , - const std::vector< typename FEMTree< sizeof ... ( FEMSigs ) , Real >::PointSample > *samples , - std::vector< InputSampleDataType > *sampleData , - const typename FEMTree< sizeof ... ( FEMSigs ) , Real >::template DensityEstimator< WEIGHT_DEGREE > *density , - const VertexFactory &vertexFactory , - const InputSampleDataType &zeroInputSampleDataType , - SetVertexFunction SetVertex , - std::vector< std::string > &comments , - XForm< Real , sizeof...(FEMSigs)+1 > unitCubeToModel + const AuxDataFactory &auxDataFactory , + bool inCore , + Reconstructor::ReconstructionInfo< Real , Dim , FEMSig , typename AuxDataFactory::VertexType > &reconInfo , + const Reconstructor::MeshExtractionParameters &meParams , + std::string fileName , + bool ascii ) { - static const int Dim = sizeof ... ( FEMSigs ); - typedef UIntPack< FEMSigs ... > Sigs; - typedef typename VertexFactory::VertexType Vertex; - static const unsigned int DataSig = FEMDegreeAndBType< DATA_DEGREE , BOUNDARY_FREE >::Signature; - typedef typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; - - Profiler profiler(20); + // A description of the output vertex information + using VInfo = Reconstructor::OutputVertexWithDataInfo< Real , Dim , AuxDataFactory , HasGradients , HasDensity >; - char tempHeader[2048]; - { - char tempPath[1024]; - tempPath[0] = 0; - if( TempDir.set ) strcpy( tempPath , TempDir.value ); - else SetTempDirectory( tempPath , sizeof(tempPath) ); - if( strlen(tempPath)==0 ) sprintf( tempPath , ".%c" , FileSeparator ); - if( tempPath[ strlen( tempPath )-1 ]==FileSeparator ) sprintf( tempHeader , "%sPR_" , tempPath ); - else sprintf( tempHeader , "%s%cPR_" , tempPath , FileSeparator ); - } + // A factory generating the output vertices + using Factory = typename VInfo::Factory; + Factory factory = VInfo::GetFactory( auxDataFactory ); - StreamingMesh< Vertex , node_index_type > *mesh; - if( InCore.set ) mesh = new VectorStreamingMesh< Vertex , node_index_type >(); - else mesh = new FileStreamingMesh< VertexFactory , node_index_type >( vertexFactory , tempHeader ); + // A backing stream for the vertices + Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , inCore , false , std::string( "v_" ) ); + Reconstructor::OutputInputPolygonStream polygonStream( inCore , true , std::string( "p_" ) ); - profiler.reset(); - typename LevelSetExtractor< Dim , Real , Vertex >::Stats stats; - if( sampleData ) { - SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > _sampleData = tree.template setExtrapolatedDataField< DataSig , false >( *samples , *sampleData , (DensityEstimator*)NULL ); - auto nodeFunctor = [&]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *n ) - { - ProjectiveData< InputSampleDataType , Real >* clr = _sampleData( n ); - if( clr ) (*clr) *= (Real)pow( DataX.value , tree.depth( n ) ); - }; - tree.tree().processNodes( nodeFunctor ); - stats = LevelSetExtractor< Dim , Real , Vertex >::template Extract< InputSampleDataType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , &_sampleData , solution , isoValue , *mesh , zeroInputSampleDataType , SetVertex , NonLinearFit.set , Normals.value==NORMALS_GRADIENTS , !NonManifold.set , PolygonMesh.set , false ); - } -#if defined( __GNUC__ ) && __GNUC__ < 5 -#ifdef SHOW_WARNINGS -#warning "you've got me gcc version<5" -#endif // SHOW_WARNINGS - else stats = LevelSetExtractor< Dim , Real , Vertex >::template Extract< InputSampleDataType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , (SparseNodeData< ProjectiveData< InputSampleDataType , Real > , IsotropicUIntPack< Dim , DataSig > > *)NULL , solution , isoValue , *mesh , zeroInputSampleDataType , SetVertex , NonLinearFit.set , Normals.value==NORMALS_GRADIENTS , !NonManifold.set , PolygonMesh.set , false ); -#else // !__GNUC__ || __GNUC__ >=5 - else stats = LevelSetExtractor< Dim , Real , Vertex >::template Extract< InputSampleDataType >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , NULL , solution , isoValue , *mesh , zeroInputSampleDataType , SetVertex , NonLinearFit.set , Normals.value==NORMALS_GRADIENTS , !NonManifold.set , PolygonMesh.set , false ); -#endif // __GNUC__ || __GNUC__ < 4 - if( Verbose.set ) - { - std::cout << "Vertices / Polygons: " << mesh->vertexNum() << " / " << mesh->polygonNum() << std::endl; - std::cout << stats.toString() << std::endl; - if( PolygonMesh.set ) std::cout << "# Got polygons: " << profiler << std::endl; - else std::cout << "# Got triangles: " << profiler << std::endl; + // The wrapper converting native to output types + typename VInfo::StreamWrapper _vertexStream( vertexStream , factory() ); + + // Extract the mesh + Reconstructor::ExtractMesh< Real >( reconInfo , _vertexStream , polygonStream , meParams ); } + // Write the mesh to a .ply file std::vector< std::string > noComments; - typename VertexFactory::Transform unitCubeToModelTransform( unitCubeToModel ); - auto xForm = [&]( typename VertexFactory::VertexType & v ){ unitCubeToModelTransform.inPlace( v ); }; - PLY::WritePolygons< VertexFactory , node_index_type , Real , Dim >( Out.value , vertexFactory , mesh , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , NoComments.set ? noComments : comments , xForm ); - - delete mesh; + PLY::WritePolygons< Factory , node_index_type , Real , Dim >( fileName , factory , vertexStream.size() , polygonStream.size() , vertexStream , polygonStream , ascii ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); } -template< typename Real , unsigned int Dim > -void WriteGrid( const char *fileName , ConstPointer( Real ) values , unsigned int res , XForm< Real , Dim+1 > voxelToModel , bool verbose ) +template< class Real , unsigned int Dim , unsigned int FEMSig , typename AuxDataFactory > +void Execute( const AuxDataFactory &auxDataFactory ) { - char *ext = GetFileExtension( fileName ); - - if( Dim==2 && ImageWriter::ValidExtension( ext ) ) - { - unsigned int totalResolution = 1; - for( int d=0 ; d avgs( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , totalResolution , [&]( unsigned int thread , size_t i ){ avgs[thread] += values[i]; } ); - for( unsigned int t=0 ; t stds( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , totalResolution , [&]( unsigned int thread , size_t i ){ stds[thread] += ( values[i] - avg ) * ( values[i] - avg ); } ); - for( unsigned int t=0 ; t [0,255]\n" , avg - 2*std , avg + 2*std ); - printf( "Transform:\n" ); - for( int i=0 ; i( (Real)1. , std::max< Real >( (Real)-1. , ( values[i] - avg ) / (2*std ) ) ); - v = (Real)( ( v + 1. ) / 2. * 256. ); - unsigned char color = (unsigned char )std::min< Real >( (Real)255. , std::max< Real >( (Real)0. , v ) ); - for( int c=0 ; c<3 ; c++ ) pixels[i*3+c ] = color; - } - ); - ImageWriter::Write( fileName , pixels , res , res , 3 ); - delete[] pixels; - } - else if( !strcasecmp( ext , "iso" ) ) - { - FILE *fp = fopen( fileName , "wb" ); - if( !fp ) ERROR_OUT( "Failed to open file for writing: " , fileName ); - int r = (int)res; - fwrite( &r , sizeof(int) , 1 , fp ); - size_t count = 1; - for( unsigned int d=0 ; d::Write( fileName , _res , values , voxelToModel ); - } - delete[] ext; -} + static const bool HasAuxData = !std::is_same< AuxDataFactory , VertexFactory::EmptyFactory< Real > >::value; -template< class Real , typename AuxDataFactory , unsigned int ... FEMSigs > -void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) -{ - static const int Dim = sizeof ... ( FEMSigs ); - typedef UIntPack< FEMSigs ... > Sigs; - typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > Degrees; - typedef UIntPack< FEMDegreeAndBType< NORMAL_DEGREE , DerivativeBoundary< FEMSignature< FEMSigs >::BType , 1 >::BType >::Signature ... > NormalSigs; - static const unsigned int DataSig = FEMDegreeAndBType< DATA_DEGREE , BOUNDARY_FREE >::Signature; - typedef typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; - typedef typename FEMTree< Dim , Real >::template InterpolationInfo< Real , 1 > InterpolationInfo; + /////////////// + // Types --> // + typedef IsotropicUIntPack< Dim , FEMSig > Sigs; using namespace VertexFactory; - // The factory for constructing an input sample - typedef Factory< Real , PositionFactory< Real , Dim > , Factory< Real , NormalFactory< Real , Dim > , AuxDataFactory > > InputSampleFactory; - // The factory for constructing an input sample's data - typedef Factory< Real , NormalFactory< Real , Dim > , AuxDataFactory > InputSampleDataFactory; - - // The input point stream information: First piece of data is the normal; the remainder is the auxiliary data - typedef InputOrientedPointStreamInfo< Real , Dim , typename AuxDataFactory::VertexType > InputPointStreamInfo; + typedef typename std::conditional< HasAuxData , Factory< Real , NormalFactory< Real , Dim > , AuxDataFactory > , NormalFactory< Real , Dim > >::type InputSampleDataFactory; - // The type of the input sample - typedef typename InputPointStreamInfo::PointAndDataType InputSampleType; - - // The type of the input sample's data - typedef typename InputPointStreamInfo::DataType InputSampleDataType; + // The factory for constructing an input sample + typedef Factory< Real , PositionFactory< Real , Dim > , InputSampleDataFactory > InputSampleFactory; - typedef InputDataStream< InputSampleType > InputPointStream; - typedef TransformedInputDataStream< InputSampleType > XInputPointStream; + typedef InputDataStream< typename InputSampleFactory::VertexType > InputPointStream; - InputSampleFactory inputSampleFactory( PositionFactory< Real , Dim >() , InputSampleDataFactory( NormalFactory< Real , Dim >() , auxDataFactory ) ); - InputSampleDataFactory inputSampleDataFactory( NormalFactory< Real , Dim >() , auxDataFactory ); + // The type storing the reconstruction solution (depending on whether auxiliary data is provided or not) + using ReconstructionInfo = typename std::conditional< HasAuxData , Reconstructor::ReconstructionInfo< Real , Dim , FEMSig , typename AuxDataFactory::VertexType > , Reconstructor::ReconstructionInfo< Real , Dim , FEMSig > >::type; + // <-- Types // + /////////////// - typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; - std::vector< std::string > comments; if( Verbose.set ) { std::cout << "************************************************" << std::endl; @@ -488,86 +292,93 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) std::cout << "************************************************" << std::endl; std::cout << "************************************************" << std::endl; if( !Threads.set ) std::cout << "Running with " << Threads.value << " threads" << std::endl; + + char str[1024]; + for( int i=0 ; params[i] ; i++ ) if( params[i]->set ) + { + params[i]->writeValue( str ); + if( strlen( str ) ) std::cout << "\t--" << params[i]->name << " " << str << std::endl; + else std::cout << "\t--" << params[i]->name << std::endl; + } } - bool needNormalData = DataX.value>0 && Normals.value; - bool needAuxData = DataX.value>0 && auxDataFactory.bufferSize(); + Profiler profiler(20); + ReconstructionInfo *sInfo = NULL; + typename Reconstructor::SSD::SolutionParameters< Real > sParams; + typename Reconstructor::MeshExtractionParameters meParams; + + sParams.verbose = Verbose.set; + sParams.outputDensity = Density.set; + sParams.exactInterpolation = ExactInterpolation.set; + sParams.showResidual = ShowResidual.set; + sParams.scale = (Real)Scale.value; + sParams.confidence = (Real)Confidence.value; + sParams.confidenceBias = (Real)ConfidenceBias.value; + sParams.lowDepthCutOff = (Real)LowDepthCutOff.value; + sParams.width = (Real)Width.value; + sParams.pointWeight = (Real)ValueWeight.value; + sParams.gradientWeight = (Real)GradientWeight.value; + sParams.biLapWeight = (Real)BiLapWeight.value; + sParams.samplesPerNode = (Real)SamplesPerNode.value; + sParams.cgSolverAccuracy = (Real)CGSolverAccuracy.value; + sParams.depth = (unsigned int)Depth.value; + sParams.baseDepth = (unsigned int)BaseDepth.value; + sParams.solveDepth = (unsigned int)SolveDepth.value; + sParams.fullDepth = (unsigned int)FullDepth.value; + sParams.kernelDepth = (unsigned int)KernelDepth.value; + sParams.baseVCycles = (unsigned int)BaseVCycles.value; + sParams.iters = (unsigned int)Iters.value; + + meParams.linearFit = !NonLinearFit.set; + meParams.outputGradients = Gradients.set; + meParams.forceManifold = !NonManifold.set; + meParams.polygonMesh = PolygonMesh.set; + meParams.verbose = Verbose.set; + + double startTime = Time(); - ThreadPool::Init( (ThreadPool::ParallelType)ParallelType.value , Threads.value ); + InputSampleFactory *_inputSampleFactory; + if constexpr( HasAuxData ) _inputSampleFactory = new InputSampleFactory( VertexFactory::PositionFactory< Real , Dim >() , InputSampleDataFactory( VertexFactory::NormalFactory< Real , Dim >() , auxDataFactory ) ); + else _inputSampleFactory = new InputSampleFactory( VertexFactory::PositionFactory< Real , Dim >() , VertexFactory::NormalFactory< Real , Dim >() ); + InputSampleFactory &inputSampleFactory = *_inputSampleFactory; + XForm< Real , Dim+1 > toModel = XForm< Real , Dim+1 >::Identity(); - XForm< Real , Dim+1 > modelToUnitCube , unitCubeToModel; + // Read in the transform, if we want to apply one to the points before processing if( Transform.set ) { FILE* fp = fopen( Transform.value , "r" ); - if( !fp ) - { - WARN( "Could not read x-form from: " , Transform.value ); - modelToUnitCube = XForm< Real , Dim+1 >::Identity(); - } + if( !fp ) WARN( "Could not read x-form from: " , Transform.value ); else { for( int i=0 ; i::Identity(); + std::vector< typename InputSampleFactory::VertexType > inCorePoints; + InputPointStream *pointStream; - char str[1024]; - for( int i=0 ; params[i] ; i++ ) - if( params[i]->set ) - { - params[i]->writeValue( str ); - if( Verbose.set ) - { - if( strlen( str ) ) std::cout << "\t--" << params[i]->name << " " << str << std::endl; - else std::cout << "\t--" << params[i]->name << std::endl; - } - } - - double startTime = Time(); - Real isoValue = 0; - - FEMTree< Dim , Real > tree( MEMORY_ALLOCATOR_BLOCK_SIZE ); - Profiler profiler(20); - - if( Depth.set && Width.value>0 ) - { - WARN( "Both --" , Depth.name , " and --" , Width.name , " set, ignoring --" , Width.name ); - Width.value = 0; - } - - size_t pointCount; - - ProjectiveData< Point< Real , 2 > , Real > pointDepthAndWeight; - std::vector< typename FEMTree< Dim , Real >::PointSample >* samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); - std::vector< InputSampleDataType >* sampleData = NULL; - DensityEstimator* density = NULL; - SparseNodeData< Point< Real , Dim > , NormalSigs >* normalInfo = NULL; - Real targetValue = (Real)0.; - - // Read in the samples (and color data) + // Get the point stream { profiler.reset(); - InputPointStream* pointStream; - char* ext = GetFileExtension( In.value ); - sampleData = new std::vector< InputSampleDataType >(); - std::vector< InputSampleType > inCorePoints; + char *ext = GetFileExtension( In.value ); + if( InCore.set ) { InputPointStream *_pointStream; if ( !strcasecmp( ext , "bnpts" ) ) _pointStream = new BinaryInputDataStream< InputSampleFactory >( In.value , inputSampleFactory ); else if( !strcasecmp( ext , "ply" ) ) _pointStream = new PLYInputDataStream< InputSampleFactory >( In.value , inputSampleFactory ); else _pointStream = new ASCIIInputDataStream< InputSampleFactory >( In.value , inputSampleFactory ); - InputSampleType p = inputSampleFactory(); - while( _pointStream->next( p ) ) inCorePoints.push_back( p ); + typename InputSampleFactory::VertexType p = inputSampleFactory(); + while( _pointStream->read( p ) ) inCorePoints.push_back( p ); delete _pointStream; - pointStream = new MemoryInputDataStream< InputSampleType >( inCorePoints.size() , &inCorePoints[0] ); } + pointStream = new VectorBackedInputDataStream< typename InputSampleFactory::VertexType >( inCorePoints ); + } else { if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryInputDataStream< InputSampleFactory >( In.value , inputSampleFactory ); @@ -575,198 +386,80 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) else pointStream = new ASCIIInputDataStream< InputSampleFactory >( In.value , inputSampleFactory ); } delete[] ext; - - typename InputSampleFactory::Transform _modelToUnitCube( modelToUnitCube ); - auto XFormFunctor = [&]( InputSampleType &p ){ _modelToUnitCube.inPlace( p ); }; - XInputPointStream _pointStream( XFormFunctor , *pointStream ); - - { - typename InputSampleDataFactory::VertexType zeroData = inputSampleDataFactory(); - modelToUnitCube = Scale.value>0 ? GetPointXForm< Real , Dim , typename AuxDataFactory::VertexType >( _pointStream , zeroData , (Real)Scale.value ) * modelToUnitCube : modelToUnitCube; - } - if( Width.value>0 ) - { - Real maxScale = 0; - for( unsigned int i=0 ; i( maxScale , (Real)1./modelToUnitCube(i,i) ); - Depth.value = (unsigned int)ceil( std::max< double >( 0. , log( maxScale/Width.value )/log(2.) ) ); - } - if( SolveDepth.value>Depth.value ) - { - WARN( "Solution depth cannot exceed system depth: " , SolveDepth.value , " <= " , Depth.value ); - SolveDepth.value = Depth.value; - } - if( FullDepth.value>Depth.value ) - { - WARN( "Full depth cannot exceed system depth: " , FullDepth.value , " <= " , Depth.value ); - FullDepth.value = Depth.value; - } - if( BaseDepth.value>FullDepth.value ) - { - if( BaseDepth.set ) WARN( "Base depth must be smaller than full depth: " , BaseDepth.value , " <= " , FullDepth.value ); - BaseDepth.value = FullDepth.value; - } - - { - typename InputSampleFactory::Transform _modelToUnitCube( modelToUnitCube ); - auto XFormFunctor = [&]( InputSampleType &p ){ _modelToUnitCube.inPlace( p ); }; - XInputPointStream _pointStream( XFormFunctor , *pointStream ); - auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , typename InputPointStreamInfo::DataType &d ) - { - Real l = (Real)Length( d.template get<0>() ); - if( !l || !std::isfinite( l ) ) return (Real)-1.; - return (Real)pow( l , Confidence.value ); - }; - auto ProcessData = []( const Point< Real , Dim > &p , typename InputPointStreamInfo::DataType &d ) - { - Real l = (Real)Length( d.template get<0>() ); - if( !l || !std::isfinite( l ) ) return (Real)-1.; - d.template get<0>() /= l; - return (Real)1.; - }; - typename InputSampleDataFactory::VertexType zeroData = inputSampleDataFactory(); - typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; - if( Confidence.value>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , tree.spaceRoot() , _pointStream , zeroData , Depth.value , *samples , *sampleData , true , tree.nodeAllocators.size() ? tree.nodeAllocators[0] : NULL , tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , tree.spaceRoot() , _pointStream , zeroData , Depth.value , *samples , *sampleData , true , tree.nodeAllocators.size() ? tree.nodeAllocators[0] : NULL , tree.initializer() , ProcessData ); - } - unitCubeToModel = modelToUnitCube.inverse(); - delete pointStream; - - if( Verbose.set ) - { - std::cout << "Input Points / Samples: " << pointCount << " / " << samples->size() << std::endl; - std::cout << "# Read input into tree: " << profiler << std::endl; - } - } - int kernelDepth = KernelDepth.set ? KernelDepth.value : Depth.value-2; - if( kernelDepth>Depth.value ) - { - WARN( KernelDepth.name , " can't be greater than " , Depth.name , ": " , KernelDepth.value , " <= " , Depth.value ); - kernelDepth = Depth.value; } - DenseNodeData< Real , Sigs > solution; + // A wrapper class to realize InputPointStream as an InputSampleWithDataStream + struct _InputSampleStream : public Reconstructor::InputSampleStream< Real , Dim > { - DenseNodeData< Real , Sigs > constraints; - InterpolationInfo* iInfo = NULL; - int solveDepth = Depth.value; - - tree.resetNodeIndices( 0 ); - - // Get the kernel density estimator + typedef Reconstructor::Normal< Real , Dim > DataType; + typedef VectorTypeUnion< Real , Reconstructor::Position< Real , Dim > , DataType > SampleType; + typedef InputDataStream< SampleType > _InputPointStream; + _InputPointStream &pointStream; + SampleType scratch; + _InputSampleStream( _InputPointStream &pointStream ) : pointStream( pointStream ) { - profiler.reset(); - density = tree.template setDensityEstimator< 1 , WEIGHT_DEGREE >( *samples , kernelDepth , SamplesPerNode.value ); - if( Verbose.set ) std::cout << "# Got kernel density: " << profiler << std::endl; - } - - // Transform the Hermite samples into a vector field - { - profiler.reset(); - normalInfo = new SparseNodeData< Point< Real , Dim > , NormalSigs >(); - std::function< bool ( InputSampleDataType , Point< Real , Dim >& ) > ConversionFunction = []( InputSampleDataType in , Point< Real , Dim > &out ) - { - Point< Real , Dim > n = in.template get<0>(); - Real l = (Real)Length( n ); - // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... - if( !l ) return false; - out = n / l; - return true; - }; - std::function< bool ( InputSampleDataType , Point< Real , Dim >& , Real & ) > ConversionAndBiasFunction = []( InputSampleDataType in , Point< Real , Dim > &out , Real &bias ) - { - Point< Real , Dim > n = in.template get<0>(); - Real l = (Real)Length( n ); - // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... - if( !l ) return false; - out = n / l; - bias = (Real)( log( l ) * ConfidenceBias.value / log( 1<<(Dim-1) ) ); - return true; - }; - - if( ConfidenceBias.value>0 ) *normalInfo = tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleData , density , 0 , Depth.value , (Real)LowDepthCutOff.value , pointDepthAndWeight , ConversionAndBiasFunction ); - else *normalInfo = tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleData , density , 0 , Depth.value , (Real)LowDepthCutOff.value , pointDepthAndWeight , ConversionFunction ); - if( Verbose.set ) - { - std::cout << "# Got normal field: " << profiler << std::endl; - std::cout << "Point depth / Point weight / Estimated Measure: " << pointDepthAndWeight.value()[0] << " / " << pointDepthAndWeight.value()[1]<< " / " << pointCount*pointDepthAndWeight.value()[1] << std::endl; - } + scratch = SampleType( Reconstructor::Position< Real , Dim >() , Reconstructor::Normal< Real , Dim >() ); } - - if( !Density.set ) delete density , density = NULL; - - // Add the interpolation constraints - if( ValueWeight.value>0 || GradientWeight.value>0 ) + void reset( void ){ pointStream.reset(); } + bool base_read( Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n ) { - profiler.reset(); - if( ExactInterpolation.set ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , InputSampleDataType , 1 >( tree , *samples , GetPointer( *sampleData ) , ConstraintDual< Dim , Real , InputSampleDataType >( targetValue , (Real)ValueWeight.value * pointDepthAndWeight.value()[1] , (Real)GradientWeight.value * pointDepthAndWeight.value()[1] ) , SystemDual< Dim , Real , InputSampleDataType >( (Real)ValueWeight.value * pointDepthAndWeight.value()[1] , (Real)GradientWeight.value * pointDepthAndWeight.value()[1] ) , true , false ); - else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , InputSampleDataType , 1 >( tree , *samples , GetPointer( *sampleData ) , ConstraintDual< Dim , Real , InputSampleDataType >( targetValue , (Real)ValueWeight.value * pointDepthAndWeight.value()[1] , (Real)GradientWeight.value * pointDepthAndWeight.value()[1] ) , SystemDual< Dim , Real , InputSampleDataType >( (Real)ValueWeight.value * pointDepthAndWeight.value()[1] , (Real)GradientWeight.value * pointDepthAndWeight.value()[1] ) , true , Depth.value , 1 ); - if( Verbose.set ) std::cout << "#Initialized point interpolation constraints: " << profiler << std::endl; + bool ret = pointStream.read( scratch ); + if( ret ) p = scratch.template get<0>() , n = scratch.template get<1>(); + return ret; } + }; - // Trim the tree and prepare for multigrid + // A wrapper class to realize InputPointStream as an InputSampleWithDataStream + struct _InputSampleWithDataStream : public Reconstructor::InputSampleWithDataStream< Real , Dim , typename AuxDataFactory::VertexType > + { + typedef VectorTypeUnion< Real , Reconstructor::Normal< Real , Dim > , typename AuxDataFactory::VertexType > DataType; + typedef VectorTypeUnion< Real , Reconstructor::Position< Real , Dim > , DataType > SampleType; + typedef InputDataStream< SampleType > _InputPointStream; + _InputPointStream &pointStream; + SampleType scratch; + _InputSampleWithDataStream( _InputPointStream &pointStream , typename AuxDataFactory::VertexType zero ) : Reconstructor::InputSampleWithDataStream< Real , Dim , typename AuxDataFactory::VertexType >( zero ) , pointStream( pointStream ) { - profiler.reset(); - - auto addNodeFunctor = [&]( int d , const int off[Dim] ){ return d<=FullDepth.value; }; - constexpr int MAX_DEGREE = NORMAL_DEGREE > Degrees::Max() ? NORMAL_DEGREE : Degrees::Max(); - tree.template finalizeForMultigrid< MAX_DEGREE , Degrees::Max() >( BaseDepth.value , addNodeFunctor , typename FEMTree< Dim , Real >::template HasNormalDataFunctor< NormalSigs >( *normalInfo ) , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , density ) ); - - if( Verbose.set ) std::cout << "# Finalized tree: " << profiler << std::endl; + scratch = SampleType( Reconstructor::Position< Real , Dim >() , DataType( Reconstructor::Normal< Real , Dim >() , zero ) ); } - - // Free up the normal info [If we don't need it for subsequent iterations.] - if( normalInfo ) delete normalInfo , normalInfo = NULL; - - // Add the interpolation constraints - if( ValueWeight.value>0 || GradientWeight.value>0 ) + void reset( void ){ pointStream.reset(); } + bool base_read( Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n , typename AuxDataFactory::VertexType &d ) { - profiler.reset(); - constraints = tree.initDenseNodeData( Sigs() ); - tree.addInterpolationConstraints( constraints , solveDepth , std::make_tuple( iInfo ) ); - if( Verbose.set ) std::cout << "#Set point constraints: " << profiler << std::endl; - if( !needNormalData && !needAuxData ) delete sampleData , sampleData = NULL; + bool ret = pointStream.read( scratch ); + if( ret ) p = scratch.template get<0>() , n = scratch.template get<1>().template get<0>() , d = scratch.template get<1>().template get<1>(); + return ret; } + }; - if( Verbose.set ) - { - std::cout << "All Nodes / Active Nodes / Ghost Nodes: " << tree.allNodes() << " / " << tree.activeNodes() << " / " << tree.ghostNodes() << std::endl; - std::cout << "Memory Usage: " << float( MemoryInfo::Usage())/(1<<20) << std::endl; - } + if constexpr( HasAuxData ) + { + _InputSampleWithDataStream sampleStream( *pointStream , auxDataFactory() ); - // Solve the linear system + if( Transform.set ) { - profiler.reset(); - typename FEMTree< Dim , Real >::SolverInfo sInfo; - sInfo.cgDepth = 0 , sInfo.cascadic = true , sInfo.vCycles = 1 , sInfo.iters = Iters.value , sInfo.cgAccuracy = CGSolverAccuracy.value , sInfo.verbose = Verbose.set , sInfo.showResidual = ShowResidual.set , sInfo.showGlobalResidual = SHOW_GLOBAL_RESIDUAL_NONE , sInfo.sliceBlockSize = 1; - sInfo.baseVCycles = BaseVCycles.value; - typename FEMIntegrator::template System< Sigs , IsotropicUIntPack< Dim , 2 > > F( { 0. , 0. , (double)BiLapWeight.value } ); - solution = tree.solveSystem( Sigs() , F , constraints , BaseDepth.value , SolveDepth.value , sInfo , std::make_tuple( iInfo ) ); - if( Verbose.set ) std::cout << "# Linear system solved: " << profiler << std::endl; - if( iInfo ) delete iInfo , iInfo = NULL; + Reconstructor::TransformedInputSampleWithDataStream< Real , Dim , typename AuxDataFactory::VertexType > _sampleStream( toModel , sampleStream ); + sInfo = Reconstructor::SSD::Solve< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( _sampleStream , sParams ); + sInfo->unitCubeToModel = toModel.inverse() * sInfo->unitCubeToModel; } + else sInfo = Reconstructor::SSD::Solve< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( sampleStream , sParams ); } - + else { - profiler.reset(); - double valueSum = 0 , weightSum = 0; - typename FEMTree< Dim , Real >::template MultiThreadedEvaluator< Sigs , 0 > evaluator( &tree , solution ); - std::vector< double > valueSums( ThreadPool::NumThreads() , 0 ) , weightSums( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , samples->size() , [&]( unsigned int thread , size_t j ) - { - ProjectiveData< Point< Real , Dim > , Real >& sample = (*samples)[j].sample; - Real w = sample.weight; - if( w>0 ) weightSums[thread] += w , valueSums[thread] += evaluator.values( sample.data / sample.weight , thread , (*samples)[j].node )[0] * w; - } - ); - for( unsigned int t=0 ; t _sampleStream( toModel , sampleStream ); + sInfo = Reconstructor::SSD::Solve< Real , Dim , FEMSig >( _sampleStream , sParams ); + sInfo->unitCubeToModel = toModel.inverse() * sInfo->unitCubeToModel; } + else sInfo = Reconstructor::SSD::Solve< Real , Dim , FEMSig >( sampleStream , sParams ); } + + delete pointStream; + delete _inputSampleFactory; + + if constexpr( HasAuxData ) if( sInfo->auxData ) sInfo->weightAuxDataByDepth( (Real)DataX.value ); + if( Tree.set ) { FILE* fp = fopen( Tree.value , "wb" ); @@ -774,81 +467,79 @@ void Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory ) FileStream fs(fp); FEMTree< Dim , Real >::WriteParameter( fs ); DenseNodeData< Real , Sigs >::WriteSignatures( fs ); - tree.write( fs , modelToUnitCube , false ); - solution.write( fs ); + sInfo->tree.write( fs , sInfo->unitCubeToModel.inverse() , false ); + sInfo->solution.write( fs ); + if constexpr( HasAuxData ) if( sInfo->auxData ) sInfo->auxData->write( fs ); + if( sInfo->density ) sInfo->density->write( fs ); fclose( fp ); } + if( Grid.set ) { int res = 0; profiler.reset(); - Pointer( Real ) values = tree.template regularGridEvaluate< true >( solution , res , -1 , PrimalGrid.set ); - size_t resolution = 1; + Pointer( Real ) values = sInfo->tree.template regularGridEvaluate< true >( sInfo->solution , res , -1 , PrimalGrid.set ); if( Verbose.set ) std::cout << "Got grid: " << profiler << std::endl; XForm< Real , Dim+1 > voxelToUnitCube = XForm< Real , Dim+1 >::Identity(); if( PrimalGrid.set ) for( int d=0 ; d( Grid.value , values , res , unitCubeToModel * voxelToUnitCube , Verbose.set ); + + unsigned int _res[Dim]; + for( int d=0 ; d::Write( Grid.value , _res , values , sInfo->unitCubeToModel * voxelToUnitCube ); + DeletePointer( values ); } - if( Out.set ) + + if( Out.set && Dim!=3 ) WARN( "Mesh extraction is only supported in dimension 3" ); + else if( Out.set && Dim==3 ) { - if( Normals.value ) + // Create the output mesh + char tempHeader[2048]; + { + char tempPath[1024]; + tempPath[0] = 0; + if( TempDir.set ) strcpy( tempPath , TempDir.value ); + else SetTempDirectory( tempPath , sizeof(tempPath) ); + if( strlen(tempPath)==0 ) sprintf( tempPath , ".%c" , FileSeparator ); + if( tempPath[ strlen( tempPath )-1 ]==FileSeparator ) sprintf( tempHeader , "%sPR_" , tempPath ); + else sprintf( tempHeader , "%s%cPR_" , tempPath , FileSeparator ); + } + + XForm< Real , Dim+1 > pXForm = sInfo->unitCubeToModel; + XForm< Real , Dim > nXForm = XForm< Real , Dim >( pXForm ).inverse().transpose(); + + if( Gradients.set ) { if( Density.set ) { - typedef Factory< Real , PositionFactory< Real , Dim > , NormalFactory< Real , Dim > , ValueFactory< Real > , AuxDataFactory > VertexFactory; - VertexFactory vertexFactory( PositionFactory< Real , Dim >() , NormalFactory< Real , Dim >() , ValueFactory< Real >() , auxDataFactory ); - if( Normals.value==NORMALS_SAMPLES ) - { - auto SetVertex = []( typename VertexFactory::VertexType &v , Point< Real , Dim > p , Point< Real , Dim > g , Real w , InputSampleDataType d ){ v.template get<0>() = p , v.template get<1>() = d.template get<0>() , v.template get<2>() = w , v.template get<3>() = d.template get<1>(); }; - ExtractMesh( UIntPack< FEMSigs ... >() , tree , solution , isoValue , samples , sampleData , density , vertexFactory , inputSampleDataFactory() , SetVertex , comments , unitCubeToModel ); - } - else if( Normals.value==NORMALS_GRADIENTS ) - { - auto SetVertex = []( typename VertexFactory::VertexType &v , Point< Real , Dim > p , Point< Real , Dim > g , Real w , InputSampleDataType d ){ v.template get<0>() = p , v.template get<1>() = -g/(1<() = w , v.template get<3>() = d.template get<1>(); }; - ExtractMesh( UIntPack< FEMSigs ... >() , tree , solution , isoValue , samples , sampleData , density , vertexFactory , inputSampleDataFactory() , SetVertex , comments , unitCubeToModel ); - } + if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , true , true >( auxDataFactory , InCore.set , *sInfo , meParams , Out.value , ASCII.set ); + else WriteMesh < Real , Dim , FEMSig , true , true >( InCore.set , *sInfo , meParams , Out.value , ASCII.set ); } else { - typedef Factory< Real , PositionFactory< Real , Dim > , NormalFactory< Real , Dim > , AuxDataFactory > VertexFactory; - VertexFactory vertexFactory( PositionFactory< Real , Dim >() , NormalFactory< Real , Dim >() , auxDataFactory ); - if( Normals.value==NORMALS_SAMPLES ) - { - auto SetVertex = []( typename VertexFactory::VertexType &v , Point< Real , Dim > p , Point< Real , Dim > g , Real w , InputSampleDataType d ){ v.template get<0>() = p , v.template get<1>() = d.template get<0>() , v.template get<2>() = d.template get<1>(); }; - ExtractMesh( UIntPack< FEMSigs ... >() , tree , solution , isoValue , samples , sampleData , density , vertexFactory , inputSampleDataFactory() , SetVertex , comments , unitCubeToModel ); - } - else if( Normals.value==NORMALS_GRADIENTS ) - { - auto SetVertex = []( typename VertexFactory::VertexType &v , Point< Real , Dim > p , Point< Real , Dim > g , Real w , InputSampleDataType d ){ v.template get<0>() = p , v.template get<1>() = -g/(1<() = d.template get<1>(); }; - ExtractMesh( UIntPack< FEMSigs ... >() , tree , solution , isoValue , samples , sampleData , density , vertexFactory , inputSampleDataFactory() , SetVertex , comments , unitCubeToModel ); - } + if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , true , false >( auxDataFactory , InCore.set , *sInfo , meParams , Out.value , ASCII.set ); + else WriteMesh < Real , Dim , FEMSig , true , false >( InCore.set , *sInfo , meParams , Out.value , ASCII.set ); } } else { if( Density.set ) { - typedef Factory< Real , PositionFactory< Real , Dim > , ValueFactory< Real > , AuxDataFactory > VertexFactory; - VertexFactory vertexFactory( PositionFactory< Real , Dim >() , ValueFactory< Real >() , auxDataFactory ); - auto SetVertex = []( typename VertexFactory::VertexType &v , Point< Real , Dim > p , Point< Real , Dim > g , Real w , InputSampleDataType d ){ v.template get<0>() = p , v.template get<1>() = w , v.template get<2>() = d.template get<1>(); }; - ExtractMesh( UIntPack< FEMSigs ... >() , tree , solution , isoValue , samples , sampleData , density , vertexFactory , inputSampleDataFactory() , SetVertex , comments , unitCubeToModel ); + if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , false , true >( auxDataFactory , InCore.set , *sInfo , meParams , Out.value , ASCII.set ); + else WriteMesh < Real , Dim , FEMSig , false , true >( InCore.set , *sInfo , meParams , Out.value , ASCII.set ); } else { - typedef Factory< Real , PositionFactory< Real , Dim > , AuxDataFactory > VertexFactory; - VertexFactory vertexFactory( PositionFactory< Real , Dim >() , auxDataFactory ); - auto SetVertex = []( typename VertexFactory::VertexType &v , Point< Real , Dim > p , Point< Real , Dim > g , Real w , InputSampleDataType d ){ v.template get<0>() = p , v.template get<1>() = d.template get<1>(); }; - ExtractMesh( UIntPack< FEMSigs ... >() , tree , solution , isoValue , samples , sampleData , density , vertexFactory , inputSampleDataFactory() , SetVertex , comments , unitCubeToModel ); + if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , false , false >( auxDataFactory , InCore.set , *sInfo , meParams , Out.value , ASCII.set ); + else WriteMesh < Real , Dim , FEMSig , false , false >( InCore.set , *sInfo , meParams , Out.value , ASCII.set ); } } - if( sampleData ){ delete sampleData ; sampleData = NULL; } } - if( density ) delete density , density = NULL; if( Verbose.set ) std::cout << "# Total Solve: " << Time()-startTime << " (s), " << MemoryInfo::PeakMemoryUsageMB() << " (MB)" << std::endl; + delete sInfo; } #ifndef FAST_COMPILE @@ -857,10 +548,9 @@ void Execute( const AuxDataFactory &auxDataFactory ) { switch( Degree.value ) { -// case 1: return Execute< Real >( IsotropicUIntPack< Dim , FEMDegreeAndBType< 1 , BType >::Signature >() , auxDataFactory ); - case 2: return Execute< Real >( IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BType >::Signature >() , auxDataFactory ); - case 3: return Execute< Real >( IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BType >::Signature >() , auxDataFactory ); -// case 4: return Execute< Real >( IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BType >::Signature >() , auxDataFactory ); + case 2: return Execute< Real , Dim , FEMDegreeAndBType< 2 , BType >::Signature >( auxDataFactory ); + case 3: return Execute< Real , Dim , FEMDegreeAndBType< 3 , BType >::Signature >( auxDataFactory ); +// case 4: return Execute< Real , Dim , FEMDegreeAndBType< 4 , BType >::Signature >( auxDataFactory ); default: ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); } } @@ -889,6 +579,7 @@ int main( int argc , char* argv[] ) if( MaxMemoryGB.value>0 ) SetPeakMemoryMB( MaxMemoryGB.value<<10 ); ThreadPool::DefaultChunkSize = ThreadChunkSize.value; ThreadPool::DefaultSchedule = (ThreadPool::ScheduleType)ScheduleType.value; + ThreadPool::Init( (ThreadPool::ParallelType)ParallelType.value , Threads.value ); if( !In.set ) { @@ -910,9 +601,9 @@ int main( int argc , char* argv[] ) SolveDepth.value = Depth.value; } - ValueWeight.value *= (float)BaseSSDWeights[0]; - GradientWeight.value *= (float)BaseSSDWeights[1]; - BiLapWeight.value *= (float)BaseSSDWeights[2]; + ValueWeight.value *= (float)Reconstructor::SSD::WeightMultipliers[0]; + GradientWeight.value *= (float)Reconstructor::SSD::WeightMultipliers[1]; + BiLapWeight.value *= (float)Reconstructor::SSD::WeightMultipliers[2]; #ifdef USE_DOUBLE typedef double Real; @@ -921,9 +612,10 @@ int main( int argc , char* argv[] ) #endif // USE_DOUBLE #ifdef FAST_COMPILE - static const int Degree = DEFAULT_FEM_DEGREE; - static const BoundaryType BType = DEFAULT_FEM_BOUNDARY; - typedef IsotropicUIntPack< DEFAULT_DIMENSION , FEMDegreeAndBType< Degree , BType >::Signature > FEMSigs; + static const int Degree = Reconstructor::SSD::DefaultFEMDegree; + static const BoundaryType BType = Reconstructor::SSD::DefaultFEMBoundary; + static const unsigned int Dim = DEFAULT_DIMENSION; + static const unsigned int FEMSig = FEMDegreeAndBType< Degree , BType >::Signature; WARN( "Compiled for degree-" , Degree , ", boundary-" , BoundaryNames[ BType ] , ", " , sizeof(Real)==4 ? "single" : "double" , "-precision _only_" ); char *ext = GetFileExtension( In.value ); @@ -938,13 +630,13 @@ int main( int argc , char* argv[] ) if( !factory.plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain normals" ); delete[] readFlags; - if( unprocessedProperties.size() ) Execute< Real >( FEMSigs() , VertexFactory::DynamicFactory< Real >( unprocessedProperties ) ); - else Execute< Real >( FEMSigs() , VertexFactory::EmptyFactory< Real >() ); + if( unprocessedProperties.size() ) Execute< Real , Dim , FEMSig >( VertexFactory::DynamicFactory< Real >( unprocessedProperties ) ); + else Execute< Real , Dim , FEMSig >( VertexFactory::EmptyFactory< Real >() ); } else { - if( Colors.set ) Execute< Real >( FEMSigs() , VertexFactory::RGBColorFactory< Real >() ); - else Execute< Real >( FEMSigs() , VertexFactory::EmptyFactory< Real >() ); + if( Colors.set ) Execute< Real , Dim , FEMSig >( VertexFactory::RGBColorFactory< Real >() ); + else Execute< Real , Dim , FEMSig >( VertexFactory::EmptyFactory< Real >() ); } delete[] ext; #else // !FAST_COMPILE diff --git a/Src/StreamingMesh.h b/Src/StreamingMesh.h deleted file mode 100644 index dbb9215f..00000000 --- a/Src/StreamingMesh.h +++ /dev/null @@ -1,286 +0,0 @@ -/* -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 STREAMING_MESH_INCLUDED -#define STREAMING_MESH_INCLUDED - -#include "Geometry.h" -#include "MyMiscellany.h" - -template< typename Vertex , typename Index > -class StreamingVertices -{ -public: - virtual void resetIterator( void ) = 0; - virtual Index addVertex( const Vertex &v ) = 0; - virtual bool nextVertex( Vertex &v ) = 0; - virtual size_t vertexNum( void ) const = 0; -}; - -template< class Vertex , typename Index > -class StreamingCurve : public StreamingVertices< Vertex , Index > -{ -public: - virtual void resetIterator( void ) = 0; - virtual void addEdge_s( unsigned int thread , Index v1 , Index v2 ) = 0; - virtual bool nextEdge( std::pair< Index , Index > &e ) = 0; - virtual size_t edgeNum( void ) const = 0; -}; - -template< class Vertex , typename Index > -class StreamingMesh : public StreamingVertices< Vertex , Index > -{ -public: - virtual ~StreamingMesh( void ){} - virtual void resetIterator( void ) = 0; - virtual void addPolygon_s( unsigned int thread , const std::vector< Index >& vertices ) = 0; - virtual bool nextPolygon( std::vector< Index >& vertices ) = 0; - virtual size_t polygonNum( void ) const = 0; -}; - -template< typename Vertex , typename Index > -class VectorStreamingVertices : public StreamingVertices< Vertex , Index > -{ - std::vector< Vertex > _vertices; - Index _vertexIndex; -public: - VectorStreamingVertices( void ); - - void resetIterator( void ); - - Index addVertex( const Vertex &v ); - - bool nextVertex( Vertex &v ); - - size_t vertexNum( void ) const; - - Vertex &vertex( unsigned int idx ){ return _vertices[idx]; } - const Vertex &vertex( unsigned int idx ) const { return _vertices[idx]; } -}; - -template< class Vertex , typename Index > -class VectorStreamingCurve : public StreamingCurve< Vertex , Index > , public VectorStreamingVertices< Vertex , Index > -{ - std::vector< std::vector< std::pair< Index , Index > > > _edges; - unsigned int _threadIndex; - Index _edgeIndex; -public: - VectorStreamingCurve( void ); - - void resetIterator( void ); - - Index addVertex( const Vertex &v ){ return VectorStreamingVertices< Vertex , Index >::addVertex( v ); } - void addEdge_s( unsigned int thread , Index v1 , Index v2 ); - - bool nextVertex( Vertex &v ){ return VectorStreamingVertices< Vertex , Index >::nextVertex(v); } - bool nextEdge( std::pair< Index , Index > &e ); - - size_t vertexNum( void ) const { return VectorStreamingVertices< Vertex , Index >::vertexNum(); } - size_t edgeNum( void ) const; -}; - -template< class Vertex , typename Index > -class VectorStreamingMesh : public StreamingMesh< Vertex , Index > , public VectorStreamingVertices< Vertex , Index > -{ - std::vector< std::vector< std::vector< Index > > > _polygons; - unsigned int _threadIndex; - Index _polygonIndex; -public: - VectorStreamingMesh( void ); - - void resetIterator( void ); - - Index addVertex( const Vertex &v ){ return VectorStreamingVertices< Vertex , Index >::addVertex( v ); } - void addPolygon_s( unsigned int thread , const std::vector< Index >& vertices ); - - bool nextVertex( Vertex &v ){ return VectorStreamingVertices< Vertex , Index >::nextVertex(v); } - bool nextPolygon( std::vector< Index > &vertices ); - - size_t vertexNum( void ) const { return VectorStreamingVertices< Vertex , Index >::vertexNum(); } - size_t polygonNum( void ) const; -}; - -class BufferedReadWriteFile -{ - bool tempFile; - FILE* _fp; - Pointer( char ) _buffer; - char _fileName[2048]; - size_t _bufferIndex , _bufferSize; -public: - BufferedReadWriteFile( const char* fileName=NULL , const char* fileHeader="" , unsigned int bufferSize=(1<<20) ) - { - _bufferIndex = 0; - _bufferSize = bufferSize; - if( fileName ) strcpy( _fileName , fileName ) , tempFile = false , _fp = fopen( _fileName , "w+b" ); - else - { - if( fileHeader && strlen(fileHeader) ) sprintf( _fileName , "%sXXXXXX" , fileHeader ); - else strcpy( _fileName , "XXXXXX" ); -#ifdef _WIN32 - _mktemp( _fileName ); - _fp = fopen( _fileName , "w+b" ); -#else // !_WIN32 - _fp = fdopen( mkstemp( _fileName ) , "w+b" ); -#endif // _WIN32 - tempFile = true; - } - if( !_fp ) ERROR_OUT( "Failed to open file: " , _fileName ); - _buffer = AllocPointer< char >( _bufferSize ); - } - ~BufferedReadWriteFile( void ) - { - FreePointer( _buffer ); - fclose( _fp ); - if( tempFile ) remove( _fileName ); - } - bool write( ConstPointer( char ) data , size_t size ) - { - if( !size ) return true; - ConstPointer( char ) _data = 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 read( Pointer( char ) data , size_t size ) - { - if( !size ) return true; - Pointer( char ) _data = 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; - } - void reset( void ) - { - if( _bufferIndex ) fwrite( _buffer , 1 , _bufferIndex , _fp ); - _bufferIndex = 0; - fseek( _fp , 0 , SEEK_SET ); - _bufferIndex = 0; - _bufferSize = fread( _buffer , 1 , _bufferSize , _fp ); - } -}; - -template< typename VertexFactory , typename Index > -class FileStreamingVertices : public StreamingVertices< typename VertexFactory::VertexType , Index > -{ - BufferedReadWriteFile *_vertexFile; - Index _vertexNum; - const VertexFactory &_factory; - Pointer( char ) _buffer; -public: - using Vertex = typename VertexFactory::VertexType; - FileStreamingVertices( const VertexFactory &vFactory , const char* fileHeader="" ); - ~FileStreamingVertices( void ); - - void resetIterator( void ); - - Index addVertex( const Vertex &v ); - - bool nextVertex( Vertex &v ); - - size_t vertexNum( void ) const; -}; - - -template< typename VertexFactory , typename Index > -class FileStreamingCurve : public StreamingCurve< typename VertexFactory::VertexType , Index > , public FileStreamingVertices< VertexFactory , Index > -{ - std::vector< BufferedReadWriteFile* > _edgeFiles; - unsigned int _threadIndex; -public: - using Vertex = typename VertexFactory::VertexType; - FileStreamingCurve( const char* fileHeader="" ); - ~FileStreamingCurve( void ); - - void resetIterator( void ); - - Index addVertex( const Vertex &v ){ return FileStreamingVertices< VertexFactory , Index >::addVertex( v ); } - void addEdge_s( unsigned int thread , Index v1 , Index v2 ); - - bool nextVertex( Vertex &v ){ return FileStreamingVertices< VertexFactory , Index >::nextVertex(v); } - bool nextEdge( std::pair< Index , Index > &e ); - - size_t vertexNum( void ) const { return FileStreamingVertices< VertexFactory , Index >::vertexNum(); } - size_t edgeNum( void ) const; -}; - -template< typename VertexFactory , typename Index > -class FileStreamingMesh : public StreamingMesh< typename VertexFactory::VertexType , Index > , public FileStreamingVertices< VertexFactory , Index > -{ - std::vector< Index > _polygonNum; - std::vector< BufferedReadWriteFile * > _polygonFiles; - unsigned int _threadIndex; -public: - using Vertex = typename VertexFactory::VertexType; - FileStreamingMesh( const VertexFactory &vFactory , const char* fileHeader="" ); - ~FileStreamingMesh( void ); - - void resetIterator( void ); - - Index addVertex( const Vertex &v ){ return FileStreamingVertices< VertexFactory , Index >::addVertex( v ); } - void addPolygon_s( unsigned int thread , const std::vector< Index >& vertices ); - - bool nextVertex( Vertex &v ) { return FileStreamingVertices< VertexFactory , Index >::nextVertex(v); } - bool nextPolygon( std::vector< Index >& vertices ); - - size_t vertexNum( void ) const { return FileStreamingVertices< VertexFactory , Index >::vertexNum(); } - size_t polygonNum( void ) const; -}; - -#include "StreamingMesh.inl" - -#endif // STREAMING_MESH_INCLUDED diff --git a/Src/StreamingMesh.inl b/Src/StreamingMesh.inl deleted file mode 100644 index 4e51ea10..00000000 --- a/Src/StreamingMesh.inl +++ /dev/null @@ -1,266 +0,0 @@ -/* -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. -*/ - -///////////////////////////// -// VectorStreamingVertices // -///////////////////////////// -template< typename Vertex , typename Index > -VectorStreamingVertices< Vertex , Index >::VectorStreamingVertices( void ) { _vertexIndex = 0; } - -template< typename Vertex , typename Index > -void VectorStreamingVertices< Vertex , Index >::resetIterator ( void ) { _vertexIndex = 0; } - -template< typename Vertex , typename Index > -Index VectorStreamingVertices< Vertex , Index >::addVertex( const Vertex& p ) -{ - _vertices.push_back(p); - return ( Index )_vertices.size()-1; -} - -template< typename Vertex , typename Index > -bool VectorStreamingVertices< Vertex , Index >::nextVertex( Vertex &p ) -{ - if( _vertexIndex<(Index)_vertices.size() ) - { - p = _vertices[ _vertexIndex++ ]; - return true; - } - else return false; -} - -template< typename Vertex , typename Index > -size_t VectorStreamingVertices< Vertex , Index >::vertexNum( void ) const { return _vertices.size(); } - -////////////////////////// -// VectorStreamingCurve // -////////////////////////// -template< class Vertex , typename Index > -VectorStreamingCurve< Vertex , Index >::VectorStreamingCurve( void ) { _threadIndex = _edgeIndex = 0 ; _edges.resize( std::thread::hardware_concurrency() ); } - -template< class Vertex , typename Index > -void VectorStreamingCurve< Vertex , Index >::resetIterator ( void ) { _threadIndex = _edgeIndex = 0 ; VectorStreamingVertices< Vertex , Index >::resetIterator(); } - - -template< class Vertex , typename Index > -void VectorStreamingCurve< Vertex , Index >::addEdge_s( unsigned int thread , Index v1 , Index v2 ) -{ - _edges[ thread ].push_back( std::make_pair( v1 , v2 ) ); -} - -template< class Vertex , typename Index > -bool VectorStreamingCurve< Vertex , Index >::nextEdge( std::pair< Index , Index > &e ) -{ - while( true ) - { - if( _threadIndex<(int)_edges.size() ) - { - if( _edgeIndex<(Index)( _edges[_threadIndex].size() ) ) - { - e = _edges[_threadIndex][ _edgeIndex++ ]; - return true; - } - else _threadIndex++ , _edgeIndex = 0; - } - else return false; - } -} - -template< class Vertex , typename Index > -size_t VectorStreamingCurve< Vertex , Index >::edgeNum( void ) const -{ - size_t count = 0; - for( size_t i=0 ; i<_edges.size() ; i++ ) count += _edges[i].size(); - return count; -} - -///////////////////////// -// VectorStreamingMesh // -///////////////////////// -template< class Vertex , typename Index > -VectorStreamingMesh< Vertex , Index >::VectorStreamingMesh( void ) { _threadIndex = 0 ; _polygonIndex = 0 ; _polygons.resize( std::thread::hardware_concurrency() ); } - -template< class Vertex , typename Index > -void VectorStreamingMesh< Vertex , Index >::resetIterator ( void ){ _threadIndex = 0 ; _polygonIndex = 0 ; VectorStreamingVertices< Vertex , Index >::resetIterator(); } - -template< class Vertex , typename Index > -void VectorStreamingMesh< Vertex , Index >::addPolygon_s( unsigned int thread , const std::vector< Index >& polygon ) -{ - _polygons[ thread ].push_back( polygon ); -} - -template< class Vertex , typename Index > -bool VectorStreamingMesh< Vertex , Index >::nextPolygon( std::vector< Index >& vertices ) -{ - while( true ) - { - if( _threadIndex<(int)_polygons.size() ) - { - if( _polygonIndex<(Index)( _polygons[_threadIndex].size() ) ) - { - vertices = _polygons[ _threadIndex ][ _polygonIndex++ ]; - return true; - } - else _threadIndex++ , _polygonIndex = 0; - } - else return false; - } -} - -template< class Vertex , typename Index > -size_t VectorStreamingMesh< Vertex , Index >::polygonNum( void ) const -{ - size_t count = 0; - for( size_t i=0 ; i<_polygons.size() ; i++ ) count += _polygons[i].size(); - return count; -} - -/////////////////////// -// FileStreamingMesh // -/////////////////////// -template< typename VertexFactory , typename Index > -FileStreamingVertices< VertexFactory , Index >::FileStreamingVertices( const VertexFactory &factory , const char* fileHeader ) : _factory(factory) -{ - _vertexNum = 0; - - char _fileHeader[1024]; - sprintf( _fileHeader , "%s_points_" , fileHeader ); - _vertexFile = new BufferedReadWriteFile( NULL , _fileHeader ); - _buffer = NewPointer< char >( factory.bufferSize() ); -} - -template< typename VertexFactory , typename Index > -FileStreamingVertices< VertexFactory , Index >::~FileStreamingVertices( void ) -{ - delete _vertexFile; - DeletePointer( _buffer ); -} - -template< typename VertexFactory , typename Index > -void FileStreamingVertices< VertexFactory , Index >::resetIterator( void ) -{ - _vertexFile->reset(); -#if 1 -#ifdef SHOW_WARNINGS -#pragma message( "[WARNING] Why are we not resetting _vertexNum to zero?" ) -#endif // SHOW_WARNINGS -#else - _vertexNum = 0; -#endif -} - -template< typename VertexFactory , typename Index > -Index FileStreamingVertices< VertexFactory , Index >::addVertex( const Vertex &v ) -{ - _factory.toBuffer( v , _buffer ); - _vertexFile->write( _buffer , _factory.bufferSize() ); - return _vertexNum++; -} - -template< typename VertexFactory , typename Index > -bool FileStreamingVertices< VertexFactory , Index >::nextVertex( Vertex &v ) -{ - if( _vertexFile->read( _buffer , _factory.bufferSize() ) ) - { - _factory.fromBuffer( _buffer , v ); - return true; - } - else return false; -} - -template< typename VertexFactory , typename Index > -size_t FileStreamingVertices< VertexFactory , Index >::vertexNum( void ) const { return _vertexNum; } - -/////////////////////// -// FileStreamingMesh // -/////////////////////// -template< typename VertexFactory , typename Index > -FileStreamingMesh< VertexFactory , Index >::FileStreamingMesh( const VertexFactory &factory , const char* fileHeader ) : FileStreamingVertices< VertexFactory , Index >( factory , fileHeader ) -{ - _threadIndex = 0; - _polygonNum.resize( std::thread::hardware_concurrency() ); - for( unsigned int i=0 ; i<_polygonNum.size() ; i++ ) _polygonNum[i] = 0; - - char _fileHeader[1024]; - _polygonFiles.resize( std::thread::hardware_concurrency() ); - for( unsigned int i=0 ; i<_polygonFiles.size() ; i++ ) - { - sprintf( _fileHeader , "%s_polygons_t%d_" , fileHeader , i ); - _polygonFiles[i] = new BufferedReadWriteFile( NULL , _fileHeader ); - } -} - -template< typename VertexFactory , typename Index > -FileStreamingMesh< VertexFactory , Index >::~FileStreamingMesh( void ) -{ - for( unsigned int i=0 ; i<_polygonFiles.size() ; i++ ) delete _polygonFiles[i]; -} - -template< typename VertexFactory , typename Index > -void FileStreamingMesh< VertexFactory , Index >::resetIterator ( void ) -{ - _threadIndex = 0; - for( unsigned int i=0 ; i<_polygonFiles.size() ; i++ ) _polygonFiles[i]->reset(); - FileStreamingVertices< VertexFactory , Index >::resetIterator(); -} - -template< typename VertexFactory , typename Index > -void FileStreamingMesh< VertexFactory , Index >::addPolygon_s( unsigned int thread , const std::vector< Index >& vertices ) -{ - unsigned int vSize = (unsigned int)vertices.size(); - _polygonFiles[thread]->write( ( ConstPointer( char ) )GetPointer( vSize ), sizeof(unsigned int) ); - _polygonFiles[thread]->write( ( ConstPointer( char ) )GetPointer( vertices ) , sizeof(Index) * vSize ); - _polygonNum[thread]++; -} - -template< typename VertexFactory , typename Index > -bool FileStreamingMesh< VertexFactory , Index >::nextPolygon( std::vector< Index > &vertices ) -{ - while( true ) - { - if( _threadIndex<(unsigned int)_polygonFiles.size() ) - { - unsigned int pSize; - if( _polygonFiles[ _threadIndex ]->read( ( Pointer( char ) )GetPointer( pSize ) , sizeof(unsigned int) ) ) - { - vertices.resize( pSize ); - if( _polygonFiles[ _threadIndex ]->read( ( Pointer( char ) )GetPointer( vertices ) , sizeof(Index)*pSize ) ) return true; - ERROR_OUT( "Failed to read polygon from file" ); - } - else _threadIndex++; - } - else return false; - } -} - -template< typename VertexFactory , typename Index > -size_t FileStreamingMesh< VertexFactory , Index >::polygonNum( void ) const -{ - size_t count = 0; - for( size_t i=0 ; i<_polygonNum.size() ; i++ ) count += _polygonNum[i]; - return count; -} diff --git a/Src/VertexStream.h b/Src/VertexStream.h deleted file mode 100644 index a4dbd1d9..00000000 --- a/Src/VertexStream.h +++ /dev/null @@ -1,224 +0,0 @@ -/* -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 VERTEX_STREAM_INCLUDED -#define VERTEX_STREAM_INCLUDED - -#include -#include "Ply.h" -#include "Geometry.h" - -template< typename Data > -class InputDataStream -{ -public: - virtual ~InputDataStream( void ){} - virtual void reset( void ) = 0; - virtual bool next( Data &d ) = 0; - virtual size_t next( Data *d , size_t count ) - { - size_t c=0; - for( size_t i=0 ; i -struct MultiInputDataStream : public InputDataStream< Data > -{ - MultiInputDataStream( InputStream **streams , size_t N ) : _current(0) , _streams( streams , streams+N ) {} - MultiInputDataStream( const std::vector< InputStream * > &streams ) : _current(0) , _streams( streams ) {} - void reset( void ){ for( unsigned int i=0 ; i<_streams.size() ; i++ ) _streams[i]->reset(); } - bool next( Data &d ) - { - while( _current<_streams.size() ) - { - if( _streams[_current]->next( d ) ) return true; - else _current++; - } - return false; - } -protected: - std::vector< InputStream * > _streams; - unsigned int _current; -}; - -template< typename Data > -class OutputDataStream -{ -public: - virtual ~OutputDataStream( void ){} - virtual void next( const Data &d ) = 0; - virtual void next( const Data *d , size_t count ){ for( size_t i=0 ; i -class TransformedInputDataStream : public InputDataStream< Data > -{ - std::function< void ( Data& ) > _xForm; - InputDataStream< Data >& _stream; -public: - TransformedInputDataStream( std::function< void ( Data & ) > xForm , InputDataStream< Data > &stream ) : _xForm(xForm) , _stream(stream) {;} - virtual void reset( void ){ _stream.reset(); } - virtual bool next( Data &d ) - { - bool ret = _stream.next( d ); - _xForm( d ); - return ret; - } -}; - -template< typename Data > -class TransformedOutputDataStream : public OutputDataStream< Data > -{ - std::function< void ( Data & ) > _xForm; - OutputDataStream< Data > &_stream; -public: - TransformedOutputDataStream( std::function< void ( Data & ) > xForm , OutputDataStream< Data >& stream ) : _xForm(xForm) , _stream(stream) {;} - virtual void reset( void ){ _stream.reset(); } - virtual bool next( const Data& p ) - { - Data _p = p; - _xForm( _p ); - return _stream.next( _p ); - } -}; - -template< typename Data > -class MemoryInputDataStream : public InputDataStream< Data > -{ - const Data *_data; - size_t _size; - size_t _current; -public: - MemoryInputDataStream( size_t size , const Data *data ); - ~MemoryInputDataStream( void ); - void reset( void ); - bool next( Data &d ); -}; - -template< typename Data > -class MemoryOutputDataStream : public OutputDataStream< Data > -{ - Data *_data; - size_t _size; - size_t _current; -public: - MemoryOutputDataStream( size_t size , Data *data ); - ~MemoryOutputDataStream( void ); - void next( const Data &d ); -}; - -template< typename Factory > -class ASCIIInputDataStream : public InputDataStream< typename Factory::VertexType > -{ - typedef typename Factory::VertexType Data; - const Factory &_factory; - FILE *_fp; -public: - ASCIIInputDataStream( const char* fileName , const Factory &factory ); - ~ASCIIInputDataStream( void ); - void reset( void ); - bool next( Data &d ); -}; - -template< typename Factory > -class ASCIIOutputDataStream : public OutputDataStream< typename Factory::VertexType > -{ - typedef typename Factory::VertexType Data; - const Factory &_factory; - FILE *_fp; -public: - ASCIIOutputDataStream( const char* fileName , const Factory &factory ); - ~ASCIIOutputDataStream( void ); - void next( const Data &d ); -}; - -template< typename Factory > -class BinaryInputDataStream : public InputDataStream< typename Factory::VertexType > -{ - typedef typename Factory::VertexType Data; - const Factory &_factory; - FILE* _fp; -public: - BinaryInputDataStream( const char* filename , const Factory &factory ); - ~BinaryInputDataStream( void ){ fclose( _fp ) , _fp=NULL; } - void reset( void ); - bool next( Data &d ); -}; - -template< typename Factory > -class BinaryOutputDataStream : public OutputDataStream< typename Factory::VertexType > -{ - typedef typename Factory::VertexType Data; - const Factory &_factory; - FILE* _fp; -public: - BinaryOutputDataStream( const char* filename , const Factory &factory ); - ~BinaryOutputDataStream( void ){ fclose( _fp ) , _fp=NULL; } - void reset( void ){ fseek( _fp , 0 , SEEK_SET ); } - void next( const Data &d ); -}; - -template< typename Factory > -class PLYInputDataStream : public InputDataStream< typename Factory::VertexType > -{ - typedef typename Factory::VertexType Data; - const Factory &_factory; - char* _fileName; - PlyFile *_ply; - std::vector< std::string > _elist; - Pointer( char ) _buffer; - - size_t _pCount , _pIdx; - void _free( void ); -public: - PLYInputDataStream( const char* fileName , const Factory &factory ); - PLYInputDataStream( const char* fileName , const Factory &factory , size_t &count ); - ~PLYInputDataStream( void ); - void reset( void ); - bool next( Data &d ); -}; - -template< typename Factory > -class PLYOutputDataStream : public OutputDataStream< typename Factory::VertexType > -{ - typedef typename Factory::VertexType Data; - const Factory &_factory; - PlyFile *_ply; - size_t _pCount , _pIdx; - Pointer( char ) _buffer; -public: - PLYOutputDataStream( const char* fileName , const Factory &factory , size_t count , int fileType=PLY_BINARY_NATIVE ); - ~PLYOutputDataStream( void ); - void next( const Data &d ); -}; - -#include "VertexStream.inl" - -#endif // VERTEX_STREAM_INCLUDED From c2e7f70896c867ea727b40becd1346c65e6a9924 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Thu, 5 Oct 2023 22:27:50 -0400 Subject: [PATCH 08/86] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d9e76a3d..271a3824 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo Papers: [Kazhdan, Bolitho, and Hoppe, 2006], [Agarwala, 2007] -[Calakli and Taubin, 2011], +[Calakli and Taubin, 2011], [Crane, Weischedel, and Wardetzky, 2013], [Kazhdan and Hoppe, 2013], [Kazhdan and Hoppe, 2018], @@ -432,7 +432,7 @@ The default value for this parameter is equal to the numer of (virtual) processo
    SSDRecon: -Reconstructs a surface mesh from a set of oriented 3D points by solving for a Smooth Signed Distance function (solving a 3D bi-Laplacian system with positional value and gradient constraints) [Calakli and Taubin, 2011] +Reconstructs a surface mesh from a set of oriented 3D points by solving for a Smooth Signed Distance function (solving a 3D bi-Laplacian system with positional value and gradient constraints) [Calakli and Taubin, 2011]
    --in <input points>
    This string is the name of the file from which the point set will be read.
    @@ -968,7 +968,7 @@ These steps can be found in the Reconstruction.example.cpp code.
  • The reconstructor is called on line 303.
  • The mesh extraction is called on line 314. -Note that a similar approach can be used to perform the Smoothed Signed Distance reconstruction (line 302). The approach also supports reconstruction of meshes with auxiliary information like color (lines 263-292), with the only constraint that the auxiliary data type supports the computation affine combinations (e.g. the RGBColor type defined in lines 60-75). +Note that a similar approach can be used to perform the Smoothed Signed Distance reconstruction (line 302). The approach also supports reconstruction of meshes with auxiliary information like color (lines 263-292), with the only constraint that the auxiliary data type supports the computation affine combinations (e.g. the RGBColor type defined in lines 60-75). @@ -1251,7 +1251,7 @@ Similarly, to reduce compilation times, support for specific degrees can be remo Version 9.0:
    1. Added support for free boundary conditions. -
    2. Extended the solver to support more general linear systems. This makes it possible to use the same framework to implement the Smoothed Signed Distance Reconstruction of Calakli and Taubin (2011). +
    3. Extended the solver to support more general linear systems. This makes it possible to use the same framework to implement the Smoothed Signed Distance Reconstruction of Calakli and Taubin (2011).
    4. Modified the implementation of density estimation and input representation. This tends to define a slightly larger system. On its own, this results in slightly increased running-time/footprint for full-res reconstructions, but provides a substantially faster implementation when the output complexity is smaller than the input.
    From 4a51dfab3b4ec49fbf86e65e3c86a8843f4688fb Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Thu, 5 Oct 2023 22:31:19 -0400 Subject: [PATCH 09/86] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 271a3824..be6f41c4 100644 --- a/README.md +++ b/README.md @@ -921,7 +921,7 @@ individual components of the visualizer.
    -HEADER-ONLY LIBRARY
    +HEADER-ONLY LIBRARY
      From 3e03ec98bb45ca20c7dce73b9aa839b21c6c76b3 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Thu, 5 Oct 2023 22:43:27 -0400 Subject: [PATCH 10/86] Update README.md --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index be6f41c4..ed4c337b 100644 --- a/README.md +++ b/README.md @@ -943,30 +943,30 @@ This method tries to read the next pair of positions/normals from the stream, re The base class has one pure virtual method that needs to be over-ridden:
      • void base_write( Point< Real , Dim > p , Point< Real , Dim > g , Real w ):
        -This method writes the information for the next vertx into the stream. The data includes the positiono of the vertex, p, and will also include the gradient, g, and/or density weight, w if the extraction code is asked to compute those. +This method writes the information for the next vertx into the stream. The data includes the position of the vertex, p, as well as the gradient, g, and density weight, w if the extraction code is asked to compute those.
    • Output polygon stream: This class derives from the OutputPolygonStream class. The base class has one pure virtual method that needs to be over-ridden:
      • void base_write( const std::vector< node_index_type > &polygon ):
        -This method writes the information for the next polygon into the stream, with the polygon represented as a std::vector of integral indices. (In the implementation node_index_type is an unsigned int if the BIG_DATA is not defined an unsigned long long if it is.) +This method writes the information for the next polygon into the stream, with the polygon represented as a std::vector of integral indices. (The type node_index_type is an unsigned int if the BIG_DATA macro is not defined an unsigned long long if it is.)
    -With the streams defined and an FEM degree and boundary type encapsulated in the integer parameter FEMSig , the reconstruction is performed by calling two functions: +With the streams defined and an FEM degree and boundary type encapsulated in the integer parameter FEMSig (see line 342 for an example), the reconstruction is performed by calling two functions:
    • Poisson::Solve< Real , Dim , FEMSig >( InputSampleStream< Real , Dim > &sStream , SolutionParameters< Real > sParams ):
      This function takes in an input sample stream (sStream) and a description of the reconstruction parameters (sParams) desribing the depth, number of samples per node, etc. and returns a pointer to an object of type ReconstructionInfo< Real , Dim , FEMSig > which stores the octree and coefficients describing the implicit function, as long as (possibly) the sampling density information.
    • ExtractMesh< Real , Dim , FEMSig >( ReconstructionInfo< Real , Dim , FEMSig > &rInfo , OutputVertexStream< Real , Dim > &vStream , &pStream , MeshExtractionParameters meParams ):
      -This function takes in a reference to the recontruction infromation (rInfo), references to the vertex and polygon streams (vStream and pStream) and parameters for mesh extraction (meParams)and computes the extracted triangle/polygon mesh and writes its vertices and faces into the two output streams. +This function takes in a reference to the recontruction infromation (rInfo), references to the vertex and polygon streams (vStream and pStream) and parameters for mesh extraction (meParams) and computes the extracted triangle/polygon mesh, writing its vertices and faces into the corresponding output streams as they are generated.
    Code walk-through:
    These steps can be found in the Reconstruction.example.cpp code.
      -
    • An input sample stream generating a specified number of random points on the surface of the sphere is described in lines 78-115 and constructed in line 299. -
    • An output vertex stream that pushes just the position information to an std::vector of Reals is described in lines 182-192 and constructed in line 311. -
    • An output polygon stream that pushes the polygon to an std::vector of std::vector< int > is described in lines 164-179 and constructed in line 310. +
    • An input sample stream generating a specified number of random points on the surface of the sphere is defined in lines 78-115 and constructed in line 299. +
    • An output vertex stream that pushes just the position information to an std::vector of Reals is defined in lines 182-192 and constructed in line 311. +
    • An output polygon stream that pushes the polygon to an std::vector of std::vector< int >s is defined in lines 164-179 and constructed in line 310.
    • The reconstructor is called on line 303. -
    • The mesh extraction is called on line 314. +
    • The mesh extraction is performed on line 314.
    Note that a similar approach can be used to perform the Smoothed Signed Distance reconstruction (line 302). The approach also supports reconstruction of meshes with auxiliary information like color (lines 263-292), with the only constraint that the auxiliary data type supports the computation affine combinations (e.g. the RGBColor type defined in lines 60-75). From 70462c60fbcee7d64ca11746b887c99cd1d1dde2 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Fri, 6 Oct 2023 17:25:48 -0400 Subject: [PATCH 11/86] Version 15.01 --- README.md | 51 +++-- Src/PointInterpolant.cpp | 4 +- Src/PoissonRecon.cpp | 68 +++--- Src/PreProcessor.h | 2 +- Src/Reconstruction.example.cpp | 54 +++-- Src/Reconstructors.h | 402 ++++++++++++--------------------- Src/SSDRecon.cpp | 68 +++--- 7 files changed, 274 insertions(+), 375 deletions(-) diff --git a/README.md b/README.md index ed4c337b..92a56578 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 15.00)

    +

    Adaptive Multigrid Solvers (Version 15.01)

    links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
    Executables: -Win64
    +Win64
    Source Code: -ZIP GitHub
    +ZIP GitHub
    Older Versions: +V14.02, V14.02, V14.01, V14.00, @@ -928,8 +929,15 @@ individual components of the visualizer. Reconstruction.example.cpp -In addition to exeuctables, the reconstruction code can be interfaced into through the functionality implemented in Reconstructors.h. -Using the functionality requires requires defining one input stream and two output streams. In the descriptions below, the template parameter Real is the floating point type used to represent data (typically float) and Dim is the integer dimension of the space (fixed at Dim=3). Also, the namespace Reconstructor is omitted for brevity. +In addition to executables, the reconstruction code can be interfaced into through the functionality implemented in Reconstructors.h. +Using the functionality requires requires choosing a finite element type, FEMSig and defining one input stream and two output streams. +
      +
    • The template parameter FEMSig describes the finite element type, which is a composite of the degree of the finite element and the boundary conditions it satisfies. Given an integer valued Degree and boundary type BType (one of BOUNDARY_FREE, BOUNDARY_DIRICHLET, and BOUNDARY_NEUMANN defined in BSplineData.h), the signature is defined by setting: +
      +static const unsigned int FEMSig = FEMDegreeAndBType< Degree , BoundaryType >::Signature;
      +
      +
    +The three streams are defined by overriding virtual stream classes. In the descriptions below, the template parameter Real is the floating point type used to represent data (typically float) and Dim is the integer dimension of the space (fixed at Dim=3). The namespace Reconstructor is omitted for brevity.
    • Input sample stream: This class derives from the InputSampleStream< Real , Dim > class. The base class has two pure virtual methods that need to be over-ridden: @@ -952,23 +960,25 @@ The base class has one pure virtual method that needs to be over-ridden: This method writes the information for the next polygon into the stream, with the polygon represented as a std::vector of integral indices. (The type node_index_type is an unsigned int if the BIG_DATA macro is not defined an unsigned long long if it is.)
    -With the streams defined and an FEM degree and boundary type encapsulated in the integer parameter FEMSig (see line 342 for an example), the reconstruction is performed by calling two functions: +The reconstructed surface is then computed in two steps:
      -
    • Poisson::Solve< Real , Dim , FEMSig >( InputSampleStream< Real , Dim > &sStream , SolutionParameters< Real > sParams ):
      -This function takes in an input sample stream (sStream) and a description of the reconstruction parameters (sParams) desribing the depth, number of samples per node, etc. and returns a pointer to an object of type ReconstructionInfo< Real , Dim , FEMSig > which stores the octree and coefficients describing the implicit function, as long as (possibly) the sampling density information. -
    • ExtractMesh< Real , Dim , FEMSig >( ReconstructionInfo< Real , Dim , FEMSig > &rInfo , OutputVertexStream< Real , Dim > &vStream , &pStream , MeshExtractionParameters meParams ):
      -This function takes in a reference to the recontruction infromation (rInfo), references to the vertex and polygon streams (vStream and pStream) and parameters for mesh extraction (meParams) and computes the extracted triangle/polygon mesh, writing its vertices and faces into the corresponding output streams as they are generated. +
    • Poisson::ImplicitRepresentation< Real , Dim , FEMSig >::ImplicitRepresentation( InputSampleStream< Real , Dim > &sStream , SolutionParameters< Real > sParams ):
      +This constructor creates a Poisson reconstruction object from an input sample stream (sStream) and a description of the reconstruction parameters (sParams) desribing the depth, number of samples per node, etc. (Reconstructors.h, line 229). This object derives from ImplicitRepresentation< Real , Dim , FEMSig >. +
    • void ImplicitRepresentation< Real , Dim , FEMSig >::extractLevelSet( OutputVertexStream< Real , Dim > &vStream , &pStream , LevelSetExtractionParameters meParams ):
      +This member function takes references to the output vertex and polygon streams (vStream and pStream) and parameters for level-set extraction (meParams) and computes the extracted triangle/polygon mesh, writing its vertices and faces into the corresponding output streams as they are generated (Reconstructors.h, line 98).
    Code walk-through:
    -These steps can be found in the Reconstruction.example.cpp code.
      -
    • An input sample stream generating a specified number of random points on the surface of the sphere is defined in lines 78-115 and constructed in line 299. -
    • An output vertex stream that pushes just the position information to an std::vector of Reals is defined in lines 182-192 and constructed in line 311. -
    • An output polygon stream that pushes the polygon to an std::vector of std::vector< int >s is defined in lines 164-179 and constructed in line 310. -
    • The reconstructor is called on line 303. -
    • The mesh extraction is performed on line 314. +These steps can be found in the Reconstruction.example.cpp code. +
        +
      • An input sample stream generating a specified number of random points on the surface of the sphere is defined in lines 78-115 and constructed in line 307. +
      • An output vertex stream that pushes just the position information to an std::vector of Reals is desfined in lines 182-192 and constructed in line 318. +
      • An output polygon stream that pushes the polygon to an std::vector of std::vector< int >s is defined in lines 164-179 and constructed in line 317. +
      • The reconstructor is constructed in line 310. +
      • The level-set extraction is performed on line 321. +
      +Note that a similar approach can be used to perform the Smoothed Signed Distance reconstruction (line 302). The approach also supports reconstruction of meshes with auxiliary information like color (lines 263-295), with the only constraint that the auxiliary data type supports the computation affine combinations (e.g. the RGBColor type defined in lines 60-75).
    -Note that a similar approach can be used to perform the Smoothed Signed Distance reconstruction (line 302). The approach also supports reconstruction of meshes with auxiliary information like color (lines 263-292), with the only constraint that the auxiliary data type supports the computation affine combinations (e.g. the RGBColor type defined in lines 60-75). @@ -1413,6 +1423,11 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • Added example using the header-only interface for reconstructing surfaces from points randomly sampled from a sphere. +Version 15.01: +
      +
    1. Cleaned up interface into the reconstruction library. +
    +
  • @@ -1422,4 +1437,4 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • This work was genersouly supported by the National Science Foundation (NSF) grant numbers 0746039 and 1422325.
  • We are extremely grateful to the EPFL Scanning 3D Statues from Photos course, the Stanford 3D Scanning Repository, and Resonai for sharing their data.
  • This work was carried out at the Advanced Research Computing at Hopkins (ARCH) core facility, which is supported by the National Science Foundation (NSF) grant number 1920103. - + \ No newline at end of file diff --git a/Src/PointInterpolant.cpp b/Src/PointInterpolant.cpp index 28cdf187..422ba240 100644 --- a/Src/PointInterpolant.cpp +++ b/Src/PointInterpolant.cpp @@ -328,7 +328,7 @@ struct SystemDual< Dim , double , VectorTypeUnion< double , Point< double , Dim }; template< typename Real , unsigned int ... FEMSigs > -void ExtractMesh +void ExtractLevelSet ( UIntPack< FEMSigs ... > , FEMTree< sizeof ... ( FEMSigs ) , Real >& tree , @@ -885,7 +885,7 @@ void Execute( UIntPack< FEMSigs ... > ) { if constexpr ( Dim==3 ) { - ExtractMesh( UIntPack< FEMSigs ... >() , tree , solution , (Real)IsoValue.value , unitCubeToModel , comments ); + ExtractLevelSet( UIntPack< FEMSigs ... >() , tree , solution , (Real)IsoValue.value , unitCubeToModel , comments ); } else if constexpr ( Dim==2 ) { diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index 94d2e6fe..60466169 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -200,8 +200,8 @@ template< typename Real , unsigned int Dim , unsigned int FEMSig , bool HasGradi void WriteMesh ( bool inCore , - Reconstructor::ReconstructionInfo< Real , Dim , FEMSig > &reconInfo , - const Reconstructor::MeshExtractionParameters &meParams , + Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig > &implicit , + const Reconstructor::LevelSetExtractionParameters &meParams , std::string fileName , bool ascii ) @@ -221,8 +221,8 @@ void WriteMesh // The wrapper converting native to output types typename VInfo::StreamWrapper _vertexStream( vertexStream , factory() ); - // Extract the mesh - Reconstructor::ExtractMesh< Real >( reconInfo , _vertexStream , polygonStream , meParams ); + // Extract the level set + implicit.extractLevelSet( _vertexStream , polygonStream , meParams ); } // Write the mesh to a .ply file @@ -235,8 +235,8 @@ void WriteMeshWithData ( const AuxDataFactory &auxDataFactory , bool inCore , - Reconstructor::ReconstructionInfo< Real , Dim , FEMSig , typename AuxDataFactory::VertexType > &reconInfo , - const Reconstructor::MeshExtractionParameters &meParams , + Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig , typename AuxDataFactory::VertexType > &implicit , + const Reconstructor::LevelSetExtractionParameters &meParams , std::string fileName , bool ascii ) @@ -256,8 +256,8 @@ void WriteMeshWithData // The wrapper converting native to output types typename VInfo::StreamWrapper _vertexStream( vertexStream , factory() ); - // Extract the mesh - Reconstructor::ExtractMesh< Real >( reconInfo , _vertexStream , polygonStream , meParams ); + // Extract the level set + implicit.extractLevelSet( _vertexStream , polygonStream , meParams ); } // Write the mesh to a .ply file @@ -284,7 +284,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) typedef InputDataStream< typename InputSampleFactory::VertexType > InputPointStream; // The type storing the reconstruction solution (depending on whether auxiliary data is provided or not) - using ReconstructionInfo = typename std::conditional< HasAuxData , Reconstructor::ReconstructionInfo< Real , Dim , FEMSig , typename AuxDataFactory::VertexType > , Reconstructor::ReconstructionInfo< Real , Dim , FEMSig > >::type; + using ImplicitRepresentation = typename std::conditional< HasAuxData , Reconstructor::Poisson::ImplicitRepresentation< Real , Dim , FEMSig , typename AuxDataFactory::VertexType > , Reconstructor::Poisson::ImplicitRepresentation< Real , Dim , FEMSig > >::type; // <-- Types // /////////////// @@ -307,9 +307,9 @@ void Execute( const AuxDataFactory &auxDataFactory ) } Profiler profiler(20); - ReconstructionInfo *sInfo = NULL; + ImplicitRepresentation *implicit = NULL; typename Reconstructor::Poisson::SolutionParameters< Real > sParams; - typename Reconstructor::MeshExtractionParameters meParams; + Reconstructor::LevelSetExtractionParameters meParams; sParams.verbose = Verbose.set; sParams.dirichletErode = !NoDirichletErode.set; @@ -458,10 +458,10 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( Transform.set ) { Reconstructor::TransformedInputSampleWithDataStream< Real , Dim , typename AuxDataFactory::VertexType > _sampleStream( toModel , sampleStream ); - sInfo = Reconstructor::Poisson::Solve< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( _sampleStream , sParams , envelopeMesh ); - sInfo->unitCubeToModel = toModel.inverse() * sInfo->unitCubeToModel; + implicit = new typename Reconstructor::Poisson::ImplicitRepresentation< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( _sampleStream , sParams , envelopeMesh ); + implicit->unitCubeToModel = toModel.inverse() * implicit->unitCubeToModel; } - else sInfo = Reconstructor::Poisson::Solve< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( sampleStream , sParams , envelopeMesh ); + else implicit = new typename Reconstructor::Poisson::ImplicitRepresentation< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( sampleStream , sParams , envelopeMesh ); } else { @@ -470,17 +470,17 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( Transform.set ) { Reconstructor::TransformedInputSampleStream< Real , Dim > _sampleStream( toModel , sampleStream ); - sInfo = Reconstructor::Poisson::Solve< Real , Dim , FEMSig >( _sampleStream , sParams , envelopeMesh ); - sInfo->unitCubeToModel = toModel.inverse() * sInfo->unitCubeToModel; + implicit = new typename Reconstructor::Poisson::ImplicitRepresentation< Real , Dim , FEMSig >( _sampleStream , sParams , envelopeMesh ); + implicit->unitCubeToModel = toModel.inverse() * implicit->unitCubeToModel; } - else sInfo = Reconstructor::Poisson::Solve< Real , Dim , FEMSig >( sampleStream , sParams , envelopeMesh ); + else implicit = new typename Reconstructor::Poisson::ImplicitRepresentation< Real , Dim , FEMSig >( sampleStream , sParams , envelopeMesh ); } delete pointStream; delete _inputSampleFactory; delete envelopeMesh; - if constexpr( HasAuxData ) if( sInfo->auxData ) sInfo->weightAuxDataByDepth( (Real)DataX.value ); + if constexpr( HasAuxData ) if( implicit->auxData ) implicit->weightAuxDataByDepth( (Real)DataX.value ); if( Tree.set ) { @@ -489,10 +489,10 @@ void Execute( const AuxDataFactory &auxDataFactory ) FileStream fs(fp); FEMTree< Dim , Real >::WriteParameter( fs ); DenseNodeData< Real , Sigs >::WriteSignatures( fs ); - sInfo->tree.write( fs , sInfo->unitCubeToModel.inverse() , false ); - sInfo->solution.write( fs ); - if constexpr( HasAuxData ) if( sInfo->auxData ) sInfo->auxData->write( fs ); - if( sInfo->density ) sInfo->density->write( fs ); + implicit->tree.write( fs , implicit->unitCubeToModel.inverse() , false ); + implicit->solution.write( fs ); + if constexpr( HasAuxData ) if( implicit->auxData ) implicit->auxData->write( fs ); + if( implicit->density ) implicit->density->write( fs ); fclose( fp ); } @@ -500,7 +500,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) { int res = 0; profiler.reset(); - Pointer( Real ) values = sInfo->tree.template regularGridEvaluate< true >( sInfo->solution , res , -1 , PrimalGrid.set ); + Pointer( Real ) values = implicit->tree.template regularGridEvaluate< true >( implicit->solution , res , -1 , PrimalGrid.set ); if( Verbose.set ) std::cout << "Got grid: " << profiler << std::endl; XForm< Real , Dim+1 > voxelToUnitCube = XForm< Real , Dim+1 >::Identity(); if( PrimalGrid.set ) for( int d=0 ; d::Write( Grid.value , _res , values , sInfo->unitCubeToModel * voxelToUnitCube ); + RegularGrid< Real , Dim >::Write( Grid.value , _res , values , implicit->unitCubeToModel * voxelToUnitCube ); DeletePointer( values ); } @@ -529,38 +529,38 @@ void Execute( const AuxDataFactory &auxDataFactory ) else sprintf( tempHeader , "%s%cPR_" , tempPath , FileSeparator ); } - XForm< Real , Dim+1 > pXForm = sInfo->unitCubeToModel; + XForm< Real , Dim+1 > pXForm = implicit->unitCubeToModel; XForm< Real , Dim > nXForm = XForm< Real , Dim >( pXForm ).inverse().transpose(); if( Gradients.set ) { if( Density.set ) { - if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , true , true >( auxDataFactory , InCore.set , *sInfo , meParams , Out.value , ASCII.set ); - else WriteMesh < Real , Dim , FEMSig , true , true >( InCore.set , *sInfo , meParams , Out.value , ASCII.set ); + if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , true , true >( auxDataFactory , InCore.set , *implicit , meParams , Out.value , ASCII.set ); + else WriteMesh < Real , Dim , FEMSig , true , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); } else { - if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , true , false >( auxDataFactory , InCore.set , *sInfo , meParams , Out.value , ASCII.set ); - else WriteMesh < Real , Dim , FEMSig , true , false >( InCore.set , *sInfo , meParams , Out.value , ASCII.set ); + if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , true , false >( auxDataFactory , InCore.set , *implicit , meParams , Out.value , ASCII.set ); + else WriteMesh < Real , Dim , FEMSig , true , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); } } else { if( Density.set ) { - if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , false , true >( auxDataFactory , InCore.set , *sInfo , meParams , Out.value , ASCII.set ); - else WriteMesh < Real , Dim , FEMSig , false , true >( InCore.set , *sInfo , meParams , Out.value , ASCII.set ); + if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , false , true >( auxDataFactory , InCore.set , *implicit , meParams , Out.value , ASCII.set ); + else WriteMesh < Real , Dim , FEMSig , false , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); } else { - if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , false , false >( auxDataFactory , InCore.set , *sInfo , meParams , Out.value , ASCII.set ); - else WriteMesh < Real , Dim , FEMSig , false , false >( InCore.set , *sInfo , meParams , Out.value , ASCII.set ); + if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , false , false >( auxDataFactory , InCore.set , *implicit , meParams , Out.value , ASCII.set ); + else WriteMesh < Real , Dim , FEMSig , false , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); } } } if( Verbose.set ) std::cout << "# Total Solve: " << Time()-startTime << " (s), " << MemoryInfo::PeakMemoryUsageMB() << " (MB)" << std::endl; - delete sInfo; + delete implicit; } #ifndef FAST_COMPILE diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 411d6000..08ed2851 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -45,7 +45,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define VERSION "15.00" // The version of the code +#define VERSION "15.01" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file diff --git a/Src/Reconstruction.example.cpp b/Src/Reconstruction.example.cpp index 4915486e..bb4c62b4 100644 --- a/Src/Reconstruction.example.cpp +++ b/Src/Reconstruction.example.cpp @@ -57,7 +57,6 @@ void ShowUsage( char* ex ) // A simple structure for representing colors. // Assuming values are in the range [0,1]. -template< typename Real > struct RGBColor { // The channels @@ -241,7 +240,7 @@ void WritePly( std::string fileName , size_t vNum , const Real *vCoordinates , c } } -template< typename Real , unsigned int Dim , unsigned int FEMSig , bool SSD > +template< typename Real , unsigned int Dim , unsigned int FEMSig , bool SSD , bool UseColor > void Execute( void ) { // Parameters for performing the reconstruction @@ -256,24 +255,29 @@ void Execute( void ) solverParams.depth = (unsigned int)Depth.value; // Parameters for exracting the level-set surface - typename Reconstructor::MeshExtractionParameters extractionParams; + Reconstructor::LevelSetExtractionParameters extractionParams; extractionParams.linearFit = SSD; // Since the SSD solution approximates a TSDF, linear fitting works well extractionParams.verbose = Verbose.set; - if( UseColor.set ) + if constexpr( UseColor ) { - // Storage for the reconstruction information - Reconstructor::ReconstructionInfo< Real , Dim , FEMSig , RGBColor< Real > > *reconstructionInfo = NULL; + // The type of the reconstructor + using ImplicitRepresentation = typename std::conditional + < + SSD , + Reconstructor:: SSD::ImplicitRepresentation< Real , Dim , FEMSig , RGBColor< Real > > , + Reconstructor::Poisson::ImplicitRepresentation< Real , Dim , FEMSig , RGBColor< Real > > + >::type; // A stream generating random points on the sphere with color SphereSampleWithColorStream< Real , Dim > sampleStream( SampleNum.value ); - // Compute the reconstruction coefficients - if constexpr( SSD ) reconstructionInfo = Reconstructor:: SSD::Solve< Real , Dim , FEMSig , RGBColor< Real > >( sampleStream , solverParams ); - else reconstructionInfo = Reconstructor::Poisson::Solve< Real , Dim , FEMSig , RGBColor< Real > >( sampleStream , solverParams ); + // Construct the implicit representation + ImplicitRepresentation implicit( sampleStream , solverParams ); // Scale the color information to give extrapolation preference to data at finer depths - reconstructionInfo->weightAuxDataByDepth( (Real)32. ); + implicit.weightAuxDataByDepth( (Real)32. ); + // vectors for storing the polygons (specifically, triangles), the coordinates of the vertices, and the colors at the vertices std::vector< std::vector< int > > polygons; @@ -284,23 +288,25 @@ void Execute( void ) PolygonStream< int > pStream( polygons ); // Extract the iso-surface - Reconstructor::ExtractMesh< Real , Dim , FEMSig , RGBColor< Real > >( *reconstructionInfo , vStream , pStream , extractionParams ); + implicit.extractLevelSet( vStream , pStream , extractionParams ); if( Out.set ) WritePly( Out.value , vStream.size() , &vCoordinates[0] , &rgbCoordinates[0] , polygons ); - - delete reconstructionInfo; } else { - // Storage for the reconstruction information - Reconstructor::ReconstructionInfo< Real , Dim , FEMSig > *reconstructionInfo = NULL; + // The type of the reconstructor + using ImplicitRepresentation = typename std::conditional + < + SSD , + Reconstructor:: SSD::ImplicitRepresentation< Real , Dim , FEMSig > , + Reconstructor::Poisson::ImplicitRepresentation< Real , Dim , FEMSig > + >::type; // A stream generating random points on the sphere SphereSampleStream< Real , Dim > sampleStream( SampleNum.value ); - // Compute the reconstruction coefficients - if constexpr( SSD ) reconstructionInfo = Reconstructor:: SSD::Solve< Real , Dim , FEMSig >( sampleStream , solverParams ); - else reconstructionInfo = Reconstructor::Poisson::Solve< Real , Dim , FEMSig >( sampleStream , solverParams ); + // Construct the implicit representation + ImplicitRepresentation implicit( sampleStream , solverParams ); // vectors for storing the polygons (specifically, triangles) and the coordinates of the vertices std::vector< std::vector< int > > polygons; @@ -311,11 +317,9 @@ void Execute( void ) VertexStream< Real , Dim > vStream( vCoordinates ); // Extract the iso-surface - Reconstructor::ExtractMesh< Real , Dim , FEMSig >( *reconstructionInfo , vStream , pStream , extractionParams ); + implicit.extractLevelSet( vStream , pStream , extractionParams ); if( Out.set ) WritePly( Out.value , vStream.size() , &vCoordinates[0] , (Real*)NULL , polygons ); - - delete reconstructionInfo; } } @@ -338,8 +342,12 @@ int main( int argc , char* argv[] ) } // Solve using single float precision, in dimension 3, w/ finite-elements of degree 2 for SSD and degree 1 for Poisson, and using Neumann boundaries - if( SSDReconstruction.set ) Execute< float , 3 , FEMDegreeAndBType< SSD::DefaultFEMDegree , SSD::DefaultFEMBoundary >::Signature , true >(); - else Execute< float , 3 , FEMDegreeAndBType< Poisson::DefaultFEMDegree , Poisson::DefaultFEMBoundary >::Signature , false >(); + if( SSDReconstruction.set ) + if( UseColor.set ) Execute< float , 3 , FEMDegreeAndBType< SSD::DefaultFEMDegree , SSD::DefaultFEMBoundary >::Signature , true , true >(); + else Execute< float , 3 , FEMDegreeAndBType< SSD::DefaultFEMDegree , SSD::DefaultFEMBoundary >::Signature , true , false >(); + else + if( UseColor.set ) Execute< float , 3 , FEMDegreeAndBType< Poisson::DefaultFEMDegree , Poisson::DefaultFEMBoundary >::Signature , false , true >(); + else Execute< float , 3 , FEMDegreeAndBType< Poisson::DefaultFEMDegree , Poisson::DefaultFEMBoundary >::Signature , false , false >(); if( Verbose.set ) { diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h index 826e4c22..2254b738 100644 --- a/Src/Reconstructors.h +++ b/Src/Reconstructors.h @@ -46,11 +46,26 @@ namespace Reconstructor #include "Reconstructors.streams.h" // Declare a type for storing the solution information - template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... AuxData > struct ReconstructionInfo; + template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... AuxData > struct ImplicitRepresentation; + + // Parameters for mesh extraction + struct LevelSetExtractionParameters + { + bool linearFit; + bool outputGradients; + bool forceManifold; + bool polygonMesh; + bool verbose; + LevelSetExtractionParameters( void ) : linearFit(false) , outputGradients(false) , forceManifold(true) , polygonMesh(false) , verbose(false) {} + }; + + // "Private" function for extracting meshes + template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ImplicitRepresentationType , unsigned int ... FEMSigs > + void _ExtractLevelSet( UIntPack< FEMSigs ... > , const ImplicitRepresentationType &implicit , OutputVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , LevelSetExtractionParameters params ); // Specialized solution information without auxiliary data template< typename Real , unsigned int Dim , unsigned int FEMSig > - struct ReconstructionInfo< Real , Dim , FEMSig > + struct ImplicitRepresentation< Real , Dim , FEMSig > { // The signature pack typedef IsotropicUIntPack< Dim , FEMSig > Sigs; @@ -59,10 +74,10 @@ namespace Reconstructor typedef typename FEMTree< Dim , Real >::template DensityEstimator< Reconstructor::WeightDegree > DensityEstimator; // The constructor - ReconstructionInfo( void ) : density(NULL) , isoValue(0) , tree(MEMORY_ALLOCATOR_BLOCK_SIZE) , unitCubeToModel( XForm< Real , Dim+1 >::Identity() ){} + ImplicitRepresentation( void ) : density(NULL) , isoValue(0) , tree(MEMORY_ALLOCATOR_BLOCK_SIZE) , unitCubeToModel( XForm< Real , Dim+1 >::Identity() ){} // The desctructor - ~ReconstructionInfo( void ){ delete density ; density = NULL; } + ~ImplicitRepresentation( void ){ delete density ; density = NULL; } // The transformation taking points in the unit cube back to world coordinates XForm< Real , Dim+1 > unitCubeToModel; @@ -78,11 +93,18 @@ namespace Reconstructor // The density estimator computed from the samples DensityEstimator *density; + + // A method that writes the extracted mesh to the streams + void extractLevelSet( OutputVertexStream< Real , Dim > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , LevelSetExtractionParameters params ) const + { + typedef unsigned char AuxData; + _ExtractLevelSet< false , Real , Dim , FEMSig , AuxData , OutputVertexStream< Real , Dim > , ImplicitRepresentation< Real , Dim , FEMSig > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , polygonStream , params ); + } }; // Specialized solution information with auxiliary data template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > - struct ReconstructionInfo< Real , Dim , FEMSig , AuxData > : public ReconstructionInfo< Real , Dim , FEMSig > + struct ImplicitRepresentation< Real , Dim , FEMSig , AuxData > : public ImplicitRepresentation< Real , Dim , FEMSig > { typedef IsotropicUIntPack< Dim , FEMSig > Sigs; @@ -90,10 +112,10 @@ namespace Reconstructor static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; // The constructor - ReconstructionInfo( AuxData zeroAuxData ) : auxData(NULL) , zeroAuxData(zeroAuxData) {} + ImplicitRepresentation( AuxData zeroAuxData ) : auxData(NULL) , zeroAuxData(zeroAuxData) {} // The desctructor - ~ReconstructionInfo( void ){ delete auxData ; auxData = NULL; } + ~ImplicitRepresentation( void ){ delete auxData ; auxData = NULL; } // The auxiliary information stored with the oriented vertices SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > > *auxData; @@ -107,38 +129,18 @@ namespace Reconstructor auto nodeFunctor = [&]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *n ) { ProjectiveData< AuxData , Real >* clr = (*auxData)( n ); - if( clr ) (*clr) *= (Real)pow( (Real)perLevelScaleFactor , ReconstructionInfo< Real , Dim , FEMSig>::tree.depth( n ) ); + if( clr ) (*clr) *= (Real)pow( (Real)perLevelScaleFactor , ImplicitRepresentation< Real , Dim , FEMSig>::tree.depth( n ) ); }; - ReconstructionInfo< Real , Dim , FEMSig>::tree.tree().processNodes( nodeFunctor ); + ImplicitRepresentation< Real , Dim , FEMSig>::tree.tree().processNodes( nodeFunctor ); } - }; - struct MeshExtractionParameters - { - bool linearFit; - bool outputGradients; - bool forceManifold; - bool polygonMesh; - bool verbose; - MeshExtractionParameters( void ) : linearFit(false) , outputGradients(false) , forceManifold(true) , polygonMesh(false) , verbose(false) {} + // A method for writing the extracted mesh to the streams + void extractLevelSet( OutputVertexWithDataStream< Real , Dim , AuxData > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , LevelSetExtractionParameters params ) const + { + _ExtractLevelSet< true , Real , Dim , FEMSig , AuxData , OutputVertexWithDataStream< Real , Dim , AuxData > , ImplicitRepresentation< Real , Dim , FEMSig , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , polygonStream , params ); + } }; - template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ReconstructionInfoType , unsigned int ... FEMSigs > - void _ExtractMesh( UIntPack< FEMSigs ... > , const ReconstructionInfoType &sInfo , OutputVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , MeshExtractionParameters params ); - - template< typename Real , unsigned int Dim , unsigned int FEMSig > - void ExtractMesh( const ReconstructionInfo< Real , Dim , FEMSig > &sInfo , OutputVertexStream< Real , Dim > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , MeshExtractionParameters params ) - { - typedef unsigned char AuxData; - _ExtractMesh< false , Real , Dim , FEMSig , AuxData , OutputVertexStream< Real , Dim > , ReconstructionInfo< Real , Dim , FEMSig > >( IsotropicUIntPack< Dim , FEMSig >() , sInfo , vertexStream , polygonStream , params ); - } - - template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > - void ExtractMesh( const ReconstructionInfo< Real , Dim , FEMSig , AuxData > &sInfo , OutputVertexWithDataStream< Real , Dim , AuxData > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , MeshExtractionParameters params ) - { - _ExtractMesh< true , Real , Dim , FEMSig , AuxData , OutputVertexWithDataStream< Real , Dim , AuxData > , ReconstructionInfo< Real , Dim , FEMSig , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , sInfo , vertexStream , polygonStream , params ); - } - namespace Poisson { static const unsigned int NormalDegree = 2; // The order of the B-Spline used to splat in the normals for constructing the Laplacian constraints @@ -191,9 +193,6 @@ namespace Reconstructor Real pointWeight; Real samplesPerNode; Real cgSolverAccuracy; -#ifdef SOFT_DIRICHLET - Real dirichletWeight; -#endif // SOFT_DIRICHLET unsigned int depth; unsigned int solveDepth; unsigned int baseDepth; @@ -207,9 +206,6 @@ namespace Reconstructor verbose(false) , dirichletErode(false) , outputDensity(false) , exactInterpolation(false) , showResidual(false) , scale((Real)1.1) , confidence((Real)0.) , confidenceBias((Real)0.) , lowDepthCutOff((Real)0.) , width((Real)0.) , pointWeight((Real)0.) , samplesPerNode((Real)1.5) , cgSolverAccuracy((Real)1e-3 ) , -#ifdef SOFT_DIRICHLET - dirichletWeight((Real)0.) , -#endif // SOFT_DIRICHLET depth((unsigned int)8) , solveDepth((unsigned int)-1) , baseDepth((unsigned int)-1) , fullDepth((unsigned int)5) , kernelDepth((unsigned int)-1) , envelopeDepth((unsigned int)-1) , baseVCycles((unsigned int)1) , iters((unsigned int)8) {} @@ -222,38 +218,32 @@ namespace Reconstructor std::vector< SimplexIndex< Dim-1 , node_index_type > > simplices; }; + template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct ImplicitRepresentation; + template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > - static typename std::conditional< HasAuxData , ReconstructionInfo< Real , Dim , FEMSig , AuxData > , ReconstructionInfo< Real , Dim , FEMSig > >::type *_Solve( UIntPack< FEMSigs... > , InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh ); + void _Solve( UIntPack< FEMSigs... > , typename std::conditional< HasAuxData , Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig , AuxData > , ImplicitRepresentation< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh ); -#ifdef DE_VIRTUALIZE_INPUT - template< typename Real , unsigned int Dim , unsigned int FEMSig , typename InputSampleStreamType > - ReconstructionInfo< Real , Dim , FEMSig > *Solve( InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL ) - { - static_assert( std::is_base_of< InputSampleStream< Real , Dim > , InputSampleStreamType >::value , "[ERROR] Unexpected sample stream type" ); - typedef unsigned char AuxData; - return _Solve< false , Real , Dim , FEMSig , AuxData , InputSampleStreamType >( IsotropicUIntPack< Dim , FEMSig >() , pointStream , params , envelopeMesh ); - } + template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct ImplicitRepresentation; - template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType > - ReconstructionInfo< Real , Dim , FEMSig , AuxData > *Solve( InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL ) - { - static_assert( std::is_base_of< InputSampleWithDataStream< Real , Dim , AuxData > , InputSampleStreamType >::value , "[ERROR] Unexpected sample stream type" ); - return _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleStreamType >( IsotropicUIntPack< Dim , FEMSig >() , pointStream , params , envelopeMesh ); - } -#else // !DE_VIRTUALIZE_INPUT template< typename Real , unsigned int Dim , unsigned int FEMSig > - ReconstructionInfo< Real , Dim , FEMSig > *Solve( InputSampleStream< Real , Dim > &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL ) + struct ImplicitRepresentation< Real , Dim , FEMSig > : public Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig > { - typedef unsigned char AuxData; - return _Solve< false , Real , Dim , FEMSig , AuxData , InputSampleStream< Real , Dim > >( IsotropicUIntPack< Dim , FEMSig >() , pointStream , params , envelopeMesh ); - } + ImplicitRepresentation( InputSampleStream< Real , Dim > &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL ) + { + typedef unsigned char AuxData; + _Solve< false , Real , Dim , FEMSig , AuxData , InputSampleStream< Real , Dim > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params , envelopeMesh ); + } + }; template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > - ReconstructionInfo< Real , Dim , FEMSig , AuxData > *Solve( InputSampleWithDataStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL ) + struct ImplicitRepresentation< Real , Dim , FEMSig , AuxData > : public Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig , AuxData > { - return _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleWithDataStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , pointStream , params , envelopeMesh ); - } -#endif // DE_VIRTUALIZE_INPUT + ImplicitRepresentation( InputSampleWithDataStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL ) + : Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig , AuxData >( pointStream.zero() ) + { + _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleWithDataStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params , envelopeMesh ); + } + }; } namespace SSD @@ -392,38 +382,30 @@ namespace Reconstructor }; - template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > - typename std::conditional< HasAuxData , ReconstructionInfo< Real , Dim , FEMSig , AuxData > , ReconstructionInfo< Real , Dim , FEMSig > >::type *_Solve( UIntPack< FEMSigs ... > , InputSampleStreamType &pointStream , SolutionParameters< Real > params ); + template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct ImplicitRepresentation; -#ifdef DE_VIRTUALIZE_INPUT - template< typename Real , unsigned int Dim , unsigned int FEMSig , typename InputSampleStreamType > - ReconstructionInfo< Real , Dim , FEMSig > *Solve( InputSampleStreamType &pointStream , SolutionParameters< Real > params ) - { - static_assert( std::is_base_of< InputSampleStream< Real , Dim > , InputSampleStreamType >::value , "[ERROR] Unexpected sample stream type" ); - typedef unsigned char AuxData; - return _Solve< false , Real , Dim , FEMSig , AuxData , InputSampleStreamType >( IsotropicUIntPack< Dim , FEMSig >() , pointStream , params ); - } + template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > + void _Solve( UIntPack< FEMSigs... > , typename std::conditional< HasAuxData , Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig , AuxData > , ImplicitRepresentation< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params ); - template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType > - ReconstructionInfo< Real , Dim , FEMSig , AuxData > *Solve( InputSampleStreamType &pointStream , SolutionParameters< Real > params ) - { - static_assert( std::is_base_of< InputSampleWithDataStream< Real , Dim , AuxData > , InputSampleStreamType >::value , "[ERROR] Unexpected sample stream type" ); - return _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleStreamType >( IsotropicUIntPack< Dim , FEMSig >() , pointStream , params ); - } -#else // !DE_VIRTUALIZE_INPUT template< typename Real , unsigned int Dim , unsigned int FEMSig > - ReconstructionInfo< Real , Dim , FEMSig > *Solve( InputSampleStream< Real , Dim > &pointStream , SolutionParameters< Real > params ) + struct ImplicitRepresentation< Real , Dim , FEMSig > : public Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig > { - typedef unsigned char AuxData; - return _Solve< false , Real , Dim , FEMSig , AuxData , InputSampleStream< Real , Dim > >( IsotropicUIntPack< Dim , FEMSig >() , pointStream , params ); - } + ImplicitRepresentation( InputSampleStream< Real , Dim > &pointStream , SolutionParameters< Real > params ) + { + typedef unsigned char AuxData; + _Solve< false , Real , Dim , FEMSig , AuxData , InputSampleStream< Real , Dim > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params ); + } + }; template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > - ReconstructionInfo< Real , Dim , FEMSig , AuxData > *Solve( InputSampleWithDataStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params ) + struct ImplicitRepresentation< Real , Dim , FEMSig , AuxData > : public Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig , AuxData > { - return _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleWithDataStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , pointStream , params ); - } -#endif // DE_VIRTUALIZE_INPUT + ImplicitRepresentation( InputSampleWithDataStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params ) + : Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig , AuxData >( pointStream.zero() ) + { + _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleWithDataStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params ); + } + }; } template< class Real , unsigned int Dim > @@ -444,49 +426,6 @@ namespace Reconstructor return rXForm * sXForm * tXForm; } -#ifdef DE_VIRTUALIZE_INPUT - template< class Real , unsigned int Dim , typename SampleStream > - void SetBoundingBox( SampleStream &stream , Point< Real , Dim >& min , Point< Real , Dim >& max ) - { - using Sample = Point< Real , Dim >; - static_assert( std::is_base_of< InputDataStream< Sample > , SampleStream >::value , "[ERROR] Unexpected sample stream type" ); - Sample s; - for( unsigned int d=0 ; d::infinity() , max[d] = -std::numeric_limits< Real >::infinity(); - while( stream.read( s ) ) for( unsigned int d=0 ; d( min[d] , s[d] ) , max[d] = std::max< Real >( max[d] , s[d] ); - stream.reset(); - } - - template< class Real , unsigned int Dim , typename AuxData , typename SampleStream > - void SetBoundingBox( SampleStream &stream , AuxData d , Point< Real , Dim >& min , Point< Real , Dim >& max ) - { - using Sample = VectorTypeUnion< Real , Point< Real , Dim > , AuxData >; - static_assert( std::is_base_of< InputDataStream< Sample > , SampleStream >::value , "[ERROR] Unexpected sample stream type" ); - Sample s( Point< Real , Dim >() , d ); - for( unsigned int d=0 ; d::infinity() , max[d] = -std::numeric_limits< Real >::infinity(); - while( stream.read( s ) ) for( unsigned int d=0 ; d( min[d] , s.template get<0>()[d] ) , max[d] = std::max< Real >( max[d] , s.template get<0>()[d] ); - stream.reset(); - } - - template< class Real , unsigned int Dim , typename SampleStream > - XForm< Real , Dim+1 > GetPointXForm( SampleStream &stream , Real scaleFactor ) - { - using Sample = Point< Real , Dim >; - static_assert( std::is_base_of< InputDataStream< Sample > , SampleStream >::value , "[ERROR] Unexpected sample stream type" ); - Point< Real , Dim > min , max; - SetBoundingBox< Real , Dim , SampleStream >( stream , min , max ); - return GetBoundingBoxXForm( min , max , scaleFactor ); - } - - template< class Real , unsigned int Dim , typename AuxData , typename SampleStream > - XForm< Real , Dim+1 > GetPointXForm( SampleStream &stream , AuxData d , Real scaleFactor ) - { - using Sample = VectorTypeUnion< Real , Point< Real , Dim > , AuxData >; - static_assert( std::is_base_of< InputDataStream< Sample > , SampleStream >::value , "[ERROR] Unexpected sample stream type" ); - Point< Real , Dim > min , max; - SetBoundingBox< Real , Dim , AuxData , SampleStream >( stream , d , min , max ); - return GetBoundingBoxXForm( min , max , scaleFactor ); - } -#else // !DE_VIRTUALIZE_INPUT template< class Real , unsigned int Dim > void SetBoundingBox( InputDataStream< Point< Real , Dim > > &stream , Point< Real , Dim >& min , Point< Real , Dim >& max ) { @@ -520,15 +459,14 @@ namespace Reconstructor SetBoundingBox( stream , d , min , max ); return GetBoundingBoxXForm( min , max , scaleFactor ); } -#endif // DE_VIRTUALIZE_INPUT - template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ReconstructionInfoType , unsigned int ... FEMSigs > - void _ExtractMesh( UIntPack< FEMSigs ... > , const ReconstructionInfoType &sInfo , OutputVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , MeshExtractionParameters params ) + template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ImplicitRepresentationType , unsigned int ... FEMSigs > + void _ExtractLevelSet( UIntPack< FEMSigs ... > , const ImplicitRepresentationType &implicit , OutputVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , LevelSetExtractionParameters params ) { typedef UIntPack< FEMSigs ... > Sigs; static_assert( std::is_same< IsotropicUIntPack< Dim , FEMSig > , UIntPack< FEMSigs ... > >::value , "[ERROR] Signatures don't match" ); static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; - typedef typename ReconstructionInfoType::DensityEstimator DensityEstimator; + typedef typename ImplicitRepresentationType::DensityEstimator DensityEstimator; if constexpr( Dim!=3 ) { @@ -544,15 +482,15 @@ namespace Reconstructor if constexpr( HasAuxData ) { typename LevelSetExtractor< Real , Dim , AuxData >::Stats stats; - TransformedOutputVertexWithDataStream< Real , Dim , AuxData > _vertexStream( sInfo.unitCubeToModel , vertexStream ); - stats = LevelSetExtractor< Real , Dim , AuxData >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , UIntPack< DataSig >() , sInfo.tree , sInfo.density , sInfo.auxData , sInfo.solution , sInfo.isoValue , _vertexStream , polygonStream , sInfo.zeroAuxData , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); + TransformedOutputVertexWithDataStream< Real , Dim , AuxData > _vertexStream( implicit.unitCubeToModel , vertexStream ); + stats = LevelSetExtractor< Real , Dim , AuxData >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , UIntPack< DataSig >() , implicit.tree , implicit.density , implicit.auxData , implicit.solution , implicit.isoValue , _vertexStream , polygonStream , implicit.zeroAuxData , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); statsString = stats.toString(); } else { typename LevelSetExtractor< Real , Dim >::Stats stats; - TransformedOutputVertexStream< Real , Dim > _vertexStream( sInfo.unitCubeToModel , vertexStream ); - stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , sInfo.tree , sInfo.density , sInfo.solution , sInfo.isoValue , _vertexStream , polygonStream , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); + TransformedOutputVertexStream< Real , Dim > _vertexStream( implicit.unitCubeToModel , vertexStream ); + stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , implicit.tree , implicit.density , implicit.solution , implicit.isoValue , _vertexStream , polygonStream , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); statsString = stats.toString(); } if( params.verbose ) @@ -566,7 +504,7 @@ namespace Reconstructor } template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > - static typename std::conditional< HasAuxData , ReconstructionInfo< Real , Dim , FEMSig , AuxData > , ReconstructionInfo< Real , Dim , FEMSig > >::type *Poisson::_Solve( UIntPack< FEMSigs ... > , InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh ) + void Poisson::_Solve( UIntPack< FEMSigs ... > , typename std::conditional< HasAuxData , Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig , AuxData > , ImplicitRepresentation< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh ) { static_assert( std::is_same< IsotropicUIntPack< Dim , FEMSig > , UIntPack< FEMSigs... > >::value , "[ERROR] Signatures don't match" ); @@ -596,17 +534,12 @@ namespace Reconstructor typedef typename std::conditional< HasAuxData , VectorTypeUnion< Real , Normal< Real , Dim > , AuxData > , Normal< Real , Dim > >::type NormalAndAuxData; // The type describing the sampling density - typedef typename std::conditional< HasAuxData , ReconstructionInfo< Real , Dim , FEMSig , AuxData > , ReconstructionInfo< Real , Dim , FEMSig > >::type::DensityEstimator DensityEstimator; + typedef typename std::conditional< HasAuxData , ImplicitRepresentation< Real , Dim , FEMSig , AuxData > , ImplicitRepresentation< Real , Dim , FEMSig > >::type::DensityEstimator DensityEstimator; // <-- Types // /////////////// - // The solution info to be returned - typename std::conditional< HasAuxData , ReconstructionInfo< Real , Dim , FEMSig , AuxData > , ReconstructionInfo< Real , Dim , FEMSig > >::type *sInfo; - if constexpr( HasAuxData ) sInfo = new ReconstructionInfo< Real , Dim , FEMSig , AuxData >( pointStream.zero() ); - else sInfo = new ReconstructionInfo< Real , Dim , FEMSig >(); - NormalAndAuxData zeroNormalAndAuxData; - if constexpr( HasAuxData ) zeroNormalAndAuxData = NormalAndAuxData( Normal< Real , Dim >() , sInfo->zeroAuxData ); + if constexpr( HasAuxData ) zeroNormalAndAuxData = NormalAndAuxData( Normal< Real , Dim >() , implicit.zeroAuxData ); XForm< Real , Dim+1 > modelToUnitCube = XForm< Real , Dim+1 >::Identity(); @@ -615,9 +548,6 @@ namespace Reconstructor size_t pointCount; ProjectiveData< Point< Real , 2 > , Real > pointDepthAndWeight; -#ifdef SOFT_DIRICHLET - std::vector< typename FEMTree< Dim , Real >::PointSample > *dirichletSamples = NULL; -#endif // SOFT_DIRICHLET DenseNodeData< GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > geometryNodeDesignators; SparseNodeData< Point< Real , Dim > , NormalSigs > *normalInfo = NULL; std::vector< typename FEMTree< Dim , Real >::PointSample > *samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); @@ -684,8 +614,8 @@ namespace Reconstructor }; typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; - if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , sInfo->tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , sInfo->tree.nodeAllocators.size() ? sInfo->tree.nodeAllocators[0] : NULL , sInfo->tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , sInfo->tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , sInfo->tree.nodeAllocators.size() ? sInfo->tree.nodeAllocators[0] : NULL , sInfo->tree.initializer() , ProcessData ); + if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); } else { @@ -709,11 +639,11 @@ namespace Reconstructor }; typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; - if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , sInfo->tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , sInfo->tree.nodeAllocators.size() ? sInfo->tree.nodeAllocators[0] : NULL , sInfo->tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , sInfo->tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , sInfo->tree.nodeAllocators.size() ? sInfo->tree.nodeAllocators[0] : NULL , sInfo->tree.initializer() , ProcessData ); + if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); } - sInfo->unitCubeToModel = modelToUnitCube.inverse(); + implicit.unitCubeToModel = modelToUnitCube.inverse(); if( params.verbose ) { @@ -722,19 +652,16 @@ namespace Reconstructor } } { -#ifdef SOFT_DIRICHLET - InterpolationInfo *dirichletInfo = NULL; -#endif // SOFT_DIRICHLET DenseNodeData< Real , Sigs > constraints; InterpolationInfo *iInfo = NULL; int solveDepth = params.depth; - sInfo->tree.resetNodeIndices( 0 , std::make_tuple() ); + implicit.tree.resetNodeIndices( 0 , std::make_tuple() ); // Get the kernel density estimator { profiler.reset(); - sInfo->density = sInfo->tree.template setDensityEstimator< 1 , Reconstructor::WeightDegree >( *samples , params.kernelDepth , params.samplesPerNode ); + implicit.density = implicit.tree.template setDensityEstimator< 1 , Reconstructor::WeightDegree >( *samples , params.kernelDepth , params.samplesPerNode ); if( params.verbose ) std::cout << "# Got kernel density: " << profiler << std::endl; } @@ -787,8 +714,8 @@ namespace Reconstructor return true; }; } - if( params.confidenceBias>0 ) *normalInfo = sInfo->tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , sInfo->density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionAndBiasFunction ); - else *normalInfo = sInfo->tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , sInfo->density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionFunction ); + if( params.confidenceBias>0 ) *normalInfo = implicit.tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , implicit.density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionAndBiasFunction ); + else *normalInfo = implicit.tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , implicit.density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionFunction ); ThreadPool::Parallel_for( 0 , normalInfo->size() , [&]( unsigned int , size_t i ){ (*normalInfo)[i] *= (Real)-1.; } ); if( params.verbose ) { @@ -801,31 +728,13 @@ namespace Reconstructor if( envelopeMesh ) { profiler.reset(); -#ifdef SOFT_DIRICHLET - if( params.dirichletWeight>0 ) - { - std::vector< Point< Real , Dim > > vertices( envelopeMesh->vertices.size() ); - for( unsigned int i=0 ; ivertices[i]; - -#if 0 - // Get the coarsest interior/boundary/exterior designators - if( exteriorConstraintType!=ExteriorConstraint::NONE || interiorConstraintType!=InteriorConstraint::NONE ) - geometryNodeDesignators = FEMTreeInitializer< Dim , Real >::template GetGeometryNodeDesignators( sInfo->tree.spaceRoot() , vertices , envelopeMesh->simplices , params.envelopeDepth , tree.nodeAllocators , tree.initializer() ); -#endif - // Get the samples of the envelope that will act as Dirichlet point constraints and turn on the scratch flags for nodes containing constraints - dirichletSamples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); - FEMTreeInitializer< Dim , Real >::Initialize( sInfo->tree.spaceRoot() , vertices , envelopeMesh->simplices , params.envelopeDepth , *dirichletSamples , true , sInfo->tree.nodeAllocators , sInfo->tree.initializer() ); - ThreadPool::Parallel_for( 0 , dirichletSamples->size() , [&]( unsigned int , size_t i ){ for( FEMTreeNode *node=(*dirichletSamples)[i].node ; node ; node=node->parent ) node->nodeData.setScratchFlag( true ); } ); - } - else -#endif // SOFT_DIRICHLET { // Make the octree complete up to the base depth - FEMTreeInitializer< Dim , Real >::Initialize( sInfo->tree.spaceRoot() , params.baseDepth , []( int , int[] ){ return true; } , sInfo->tree.nodeAllocators.size() ? sInfo->tree.nodeAllocators[0] : NULL , sInfo->tree.initializer() ); + FEMTreeInitializer< Dim , Real >::Initialize( implicit.tree.spaceRoot() , params.baseDepth , []( int , int[] ){ return true; } , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() ); std::vector< Point< Real , Dim > > vertices( envelopeMesh->vertices.size() ); for( unsigned int i=0 ; ivertices[i]; - geometryNodeDesignators = FEMTreeInitializer< Dim , Real >::template GetGeometryNodeDesignators( &sInfo->tree.spaceRoot() , vertices , envelopeMesh->simplices , params.baseDepth , params.envelopeDepth , sInfo->tree.nodeAllocators , sInfo->tree.initializer() ); + geometryNodeDesignators = FEMTreeInitializer< Dim , Real >::template GetGeometryNodeDesignators( &implicit.tree.spaceRoot() , vertices , envelopeMesh->simplices , params.baseDepth , params.envelopeDepth , implicit.tree.nodeAllocators , implicit.tree.initializer() ); // Make nodes in the support of the vector field @{ExactDepth} interior if( params.dirichletErode ) @@ -847,7 +756,7 @@ namespace Reconstructor }; // Flags indicating if a node contains a non-zero vector field coefficient - std::vector< bool > isVectorFieldElement( sInfo->tree.nodeCount() , false ); + std::vector< bool > isVectorFieldElement( implicit.tree.nodeCount() , false ); // Get the set of base nodes std::vector< FEMTreeNode * > baseNodes; @@ -856,7 +765,7 @@ namespace Reconstructor if( node->depth()==params.baseDepth ) baseNodes.push_back( node ); return node->depth()<(int)params.baseDepth; }; - sInfo->tree.spaceRoot().processNodes( nodeFunctor ); + implicit.tree.spaceRoot().processNodes( nodeFunctor ); std::vector< node_index_type > vectorFieldElementCounts( baseNodes.size() ); for( int i=0 ; itree.template processNeighboringLeaves< -BSplineSupportSizes< Poisson::NormalDegree >::SupportStart , BSplineSupportSizes< Poisson::NormalDegree >::SupportEnd >( &vectorFieldElements[0] , vectorFieldElements.size() , SetScratchFlag , false ); + implicit.tree.template processNeighboringLeaves< -BSplineSupportSizes< Poisson::NormalDegree >::SupportStart , BSplineSupportSizes< Poisson::NormalDegree >::SupportEnd >( &vectorFieldElements[0] , vectorFieldElements.size() , SetScratchFlag , false ); // Set sub-trees rooted at interior nodes @ ExactDepth to interior ThreadPool::Parallel_for( 0 , baseNodes.size() , [&]( unsigned int , size_t i ){ if( baseNodes[i]->nodeData.getScratchFlag() ) PropagateToLeaves( baseNodes[i] ); } ); // Adjust the coarser node designators in case exterior nodes have become boundary. ThreadPool::Parallel_for( 0 , baseNodes.size() , [&]( unsigned int , size_t i ){ FEMTreeInitializer< Dim , Real >::PullGeometryNodeDesignatorsFromFiner( baseNodes[i] , geometryNodeDesignators ); } ); - FEMTreeInitializer< Dim , Real >::PullGeometryNodeDesignatorsFromFiner( &sInfo->tree.spaceRoot() , geometryNodeDesignators , params.baseDepth ); + FEMTreeInitializer< Dim , Real >::PullGeometryNodeDesignatorsFromFiner( &implicit.tree.spaceRoot() , geometryNodeDesignators , params.baseDepth ); } } if( params.verbose ) std::cout << "# Initialized envelope constraints: " << profiler << std::endl; } - if( !params.outputDensity ){ delete sInfo->density ; sInfo->density = NULL; } - if constexpr( HasAuxData ) sInfo->auxData = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( sInfo->tree.template setExtrapolatedDataField< DataSig , false , Reconstructor::WeightDegree , AuxData >( samples->size() , [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return (*samples)[i]; } , [&]( size_t i ) -> const AuxData & { return (*sampleNormalAndAuxData)[i].template get<1>(); } , (DensityEstimator*)NULL ) ); + if( !params.outputDensity ){ delete implicit.density ; implicit.density = NULL; } + if constexpr( HasAuxData ) implicit.auxData = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( implicit.tree.template setExtrapolatedDataField< DataSig , false , Reconstructor::WeightDegree , AuxData >( samples->size() , [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return (*samples)[i]; } , [&]( size_t i ) -> const AuxData & { return (*sampleNormalAndAuxData)[i].template get<1>(); } , (DensityEstimator*)NULL ) ); delete sampleNormalAndAuxData; // Add the interpolation constraints if( params.pointWeight>0 ) { profiler.reset(); - if( params.exactInterpolation ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointInterpolationInfo< Real , 0 > ( sInfo->tree , *samples , Poisson::ConstraintDual< Dim , Real >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] ) , Poisson::SystemDual< Dim , Real >( params.pointWeight * pointDepthAndWeight.value()[1] ) , true , false ); - else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointInterpolationInfo< Real , 0 > ( sInfo->tree , *samples , Poisson::ConstraintDual< Dim , Real >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] ) , Poisson::SystemDual< Dim , Real >( params.pointWeight * pointDepthAndWeight.value()[1] ) , true , params.depth , 1 ); + if( params.exactInterpolation ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointInterpolationInfo< Real , 0 > ( implicit.tree , *samples , Poisson::ConstraintDual< Dim , Real >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] ) , Poisson::SystemDual< Dim , Real >( params.pointWeight * pointDepthAndWeight.value()[1] ) , true , false ); + else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointInterpolationInfo< Real , 0 > ( implicit.tree , *samples , Poisson::ConstraintDual< Dim , Real >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] ) , Poisson::SystemDual< Dim , Real >( params.pointWeight * pointDepthAndWeight.value()[1] ) , true , params.depth , 1 ); if( params.verbose ) std::cout << "#Initialized point interpolation constraints: " << profiler << std::endl; } @@ -931,13 +840,13 @@ namespace Reconstructor auto addNodeFunctor = [&]( int d , const int off[Dim] ){ return d<=(int)params.fullDepth; }; if constexpr( HasAuxData ) { - if( geometryNodeDesignators.size() ) sInfo->tree.template finalizeForMultigridWithDirichlet< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , [&]( const FEMTreeNode *node ){ return node->nodeData.nodeIndex<(node_index_type)geometryNodeDesignators.size() && geometryNodeDesignators[node]==GeometryNodeType::EXTERIOR; } , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , sInfo->density , sInfo->auxData , &geometryNodeDesignators ) ); - else sInfo->tree.template finalizeForMultigrid < MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , sInfo->density , sInfo->auxData ) ); + if( geometryNodeDesignators.size() ) implicit.tree.template finalizeForMultigridWithDirichlet< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , [&]( const FEMTreeNode *node ){ return node->nodeData.nodeIndex<(node_index_type)geometryNodeDesignators.size() && geometryNodeDesignators[node]==GeometryNodeType::EXTERIOR; } , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density , implicit.auxData , &geometryNodeDesignators ) ); + else implicit.tree.template finalizeForMultigrid < MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density , implicit.auxData ) ); } else { - if( geometryNodeDesignators.size() ) sInfo->tree.template finalizeForMultigridWithDirichlet< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , [&]( const FEMTreeNode *node ){ return node->nodeData.nodeIndex<(node_index_type)geometryNodeDesignators.size() && geometryNodeDesignators[node]==GeometryNodeType::EXTERIOR; } , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , sInfo->density , &geometryNodeDesignators ) ); - else sInfo->tree.template finalizeForMultigrid < MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , sInfo->density ) ); + if( geometryNodeDesignators.size() ) implicit.tree.template finalizeForMultigridWithDirichlet< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , [&]( const FEMTreeNode *node ){ return node->nodeData.nodeIndex<(node_index_type)geometryNodeDesignators.size() && geometryNodeDesignators[node]==GeometryNodeType::EXTERIOR; } , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density , &geometryNodeDesignators ) ); + else implicit.tree.template finalizeForMultigrid < MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density ) ); } if( params.verbose ) std::cout << "# Finalized tree: " << profiler << std::endl; @@ -946,7 +855,7 @@ namespace Reconstructor // Add the FEM constraints { profiler.reset(); - constraints = sInfo->tree.initDenseNodeData( Sigs() ); + constraints = implicit.tree.initDenseNodeData( Sigs() ); // Add Poisson constraints { @@ -961,7 +870,7 @@ namespace Reconstructor for( int dd=0 ; dd::Index( derivatives1 ) ][ TensorDerivatives< Derivatives2 >::Index( derivatives2 ) ] = 1; } - sInfo->tree.addFEMConstraints( F , *normalInfo , constraints , solveDepth ); + implicit.tree.addFEMConstraints( F , *normalInfo , constraints , solveDepth ); } if( params.verbose ) std::cout << "# Set FEM constraints: " << profiler << std::endl; } @@ -972,29 +881,11 @@ namespace Reconstructor if( params.pointWeight>0 ) { profiler.reset(); - sInfo->tree.addInterpolationConstraints( constraints , solveDepth , std::make_tuple( iInfo ) ); + implicit.tree.addInterpolationConstraints( constraints , solveDepth , std::make_tuple( iInfo ) ); if( params.verbose ) std::cout << "#Set point constraints: " << profiler << std::endl; } -#ifdef SOFT_DIRICHLET - if( dirichletSamples ) - { - if( params.exactInterpolation ) dirichletInfo = FEMTree< Dim , Real >::template InitializeExactPointInterpolationInfo< Real , 0 > ( sInfo->tree , *dirichletSamples , Poisson::ConstraintDual< Dim , Real >( 0. , params.dirichletWeight ) , Poisson::SystemDual< Dim , Real >( params.dirichletWeight ) , true , false ); - else dirichletInfo = FEMTree< Dim , Real >::template InitializeApproximatePointInterpolationInfo< Real , 0 > ( sInfo->tree , *dirichletSamples , Poisson::ConstraintDual< Dim , Real >( 0. , params.dirichletWeight ) , Poisson::SystemDual< Dim , Real >( params.dirichletWeight ) , true , 1 ); - // if( exteriorConstraintValue ) sInfo->tree.addInterpolationConstraints( constraints , solveDepth , *dirichletInfo ); - if( params.verbose ) std::cout << "# Set exterior envelope constraints: " << profiler << std::endl; - delete dirichletSamples , dirichletSamples = NULL; - } -#endif // SOFT_DIRICHLET - - -#ifdef SOFT_DIRICHLET - if( params.verbose ) - if( params.dirichletWeight>0 ) std::cout << "All Nodes / Active Nodes / Ghost Nodes: " << sInfo->tree.allNodes() << " / " << sInfo->tree.activeNodes() << " / " << sInfo->tree.ghostNodes() << std::endl; - else std::cout << "All Nodes / Active Nodes / Ghost Nodes / Dirichlet Supported Nodes: " << sInfo->tree.allNodes() << " / " << sInfo->tree.activeNodes() << " / " << sInfo->tree.ghostNodes() << " / " << sInfo->tree.dirichletElements() << std::endl; -#else // !SOFT_DIRICHLET - if( params.verbose ) std::cout << "All Nodes / Active Nodes / Ghost Nodes / Dirichlet Supported Nodes: " << sInfo->tree.allNodes() << " / " << sInfo->tree.activeNodes() << " / " << sInfo->tree.ghostNodes() << " / " << sInfo->tree.dirichletElements() << std::endl; -#endif // SOFT_DIRICHLET + if( params.verbose ) std::cout << "All Nodes / Active Nodes / Ghost Nodes / Dirichlet Supported Nodes: " << implicit.tree.allNodes() << " / " << implicit.tree.activeNodes() << " / " << implicit.tree.ghostNodes() << " / " << implicit.tree.dirichletElements() << std::endl; if( params.verbose ) std::cout << "Memory Usage: " << float( MemoryInfo::Usage())/(1<<20) << " MB" << std::endl; // Solve the linear system @@ -1004,17 +895,9 @@ namespace Reconstructor _sInfo.cgDepth = 0 , _sInfo.cascadic = true , _sInfo.vCycles = 1 , _sInfo.iters = params.iters , _sInfo.cgAccuracy = params.cgSolverAccuracy , _sInfo.verbose = params.verbose , _sInfo.showResidual = params.showResidual , _sInfo.showGlobalResidual = SHOW_GLOBAL_RESIDUAL_NONE , _sInfo.sliceBlockSize = 1; _sInfo.baseVCycles = params.baseVCycles; typename FEMIntegrator::template System< Sigs , IsotropicUIntPack< Dim , 1 > > F( { 0. , 1. } ); -#ifdef SOFT_DIRICHLET - if( dirichletInfo ) sInfo->solution = sInfo->tree.solveSystem( Sigs() , F , constraints , params.baseDepth , params.solveDepth , _sInfo , std::make_tuple( iInfo , dirichletInfo ) ); - else sInfo->solution = sInfo->tree.solveSystem( Sigs() , F , constraints , params.baseDepth , params.solveDepth , _sInfo , std::make_tuple( iInfo ) ); -#else // !SOFT_DIRICHLET - sInfo->solution = sInfo->tree.solveSystem( Sigs() , F , constraints , params.baseDepth , params.solveDepth , _sInfo , std::make_tuple( iInfo ) ); -#endif // SOFT_DIRICHLET + implicit.solution = implicit.tree.solveSystem( Sigs() , F , constraints , params.baseDepth , params.solveDepth , _sInfo , std::make_tuple( iInfo ) ); if( params.verbose ) std::cout << "# Linear system solved: " << profiler << std::endl; if( iInfo ) delete iInfo , iInfo = NULL; -#ifdef SOFT_DIRICHLET - if( dirichletInfo ) delete dirichletInfo , dirichletInfo = NULL; -#endif // SOFT_DIRICHLET } } @@ -1022,7 +905,7 @@ namespace Reconstructor { profiler.reset(); double valueSum = 0 , weightSum = 0; - typename FEMTree< Dim , Real >::template MultiThreadedEvaluator< Sigs , 0 > evaluator( &sInfo->tree , sInfo->solution ); + typename FEMTree< Dim , Real >::template MultiThreadedEvaluator< Sigs , 0 > evaluator( &implicit.tree , implicit.solution ); std::vector< double > valueSums( ThreadPool::NumThreads() , 0 ) , weightSums( ThreadPool::NumThreads() , 0 ); ThreadPool::Parallel_for( 0 , samples->size() , [&]( unsigned int thread , size_t j ) { @@ -1031,19 +914,18 @@ namespace Reconstructor if( w>0 ) weightSums[thread] += w , valueSums[thread] += evaluator.values( sample.data / sample.weight , thread , (*samples)[j].node )[0] * w; } ); for( size_t t=0 ; tisoValue = (Real)( valueSum / weightSum ); + implicit.isoValue = (Real)( valueSum / weightSum ); if( params.verbose ) { std::cout << "Got average: " << profiler << std::endl; - std::cout << "Iso-Value: " << sInfo->isoValue << " = " << valueSum << " / " << weightSum << std::endl; + std::cout << "Iso-Value: " << implicit.isoValue << " = " << valueSum << " / " << weightSum << std::endl; } } delete samples; - return sInfo; } template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > - typename std::conditional< HasAuxData , ReconstructionInfo< Real , Dim , FEMSig , AuxData > , ReconstructionInfo< Real , Dim , FEMSig > >::type *SSD::_Solve( UIntPack< FEMSigs ... > , InputSampleStreamType &pointStream , SolutionParameters< Real > params ) + void SSD::_Solve( UIntPack< FEMSigs ... > , typename std::conditional< HasAuxData , Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig , AuxData > , ImplicitRepresentation< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params ) { static_assert( std::is_same< IsotropicUIntPack< Dim , FEMSig > , UIntPack< FEMSigs... > >::value , "[ERROR] Signatures don't match" ); @@ -1071,17 +953,12 @@ namespace Reconstructor typedef typename std::conditional< HasAuxData , VectorTypeUnion< Real , Normal< Real , Dim > , AuxData > , Normal< Real , Dim > >::type NormalAndAuxData; // The type describing the sampling density - typedef typename std::conditional< HasAuxData , ReconstructionInfo< Real , Dim , FEMSig , AuxData > , ReconstructionInfo< Real , Dim , FEMSig > >::type::DensityEstimator DensityEstimator; + typedef typename std::conditional< HasAuxData , ImplicitRepresentation< Real , Dim , FEMSig , AuxData > , ImplicitRepresentation< Real , Dim , FEMSig > >::type::DensityEstimator DensityEstimator; // <-- Types // /////////////// - // The solution info to be returned - typename std::conditional< HasAuxData , ReconstructionInfo< Real , Dim , FEMSig , AuxData > , ReconstructionInfo< Real , Dim , FEMSig > >::type *sInfo; - if constexpr( HasAuxData ) sInfo = new ReconstructionInfo< Real , Dim , FEMSig , AuxData >( pointStream.zero() ); - else sInfo = new ReconstructionInfo< Real , Dim , FEMSig >(); - NormalAndAuxData zeroNormalAndAuxData; - if constexpr( HasAuxData ) zeroNormalAndAuxData = NormalAndAuxData( Normal< Real , Dim >() , sInfo->zeroAuxData ); + if constexpr( HasAuxData ) zeroNormalAndAuxData = NormalAndAuxData( Normal< Real , Dim >() , implicit.zeroAuxData ); XForm< Real , Dim+1 > modelToUnitCube = XForm< Real , Dim+1 >::Identity(); @@ -1155,8 +1032,8 @@ namespace Reconstructor }; typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; - if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , sInfo->tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , sInfo->tree.nodeAllocators.size() ? sInfo->tree.nodeAllocators[0] : NULL , sInfo->tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , sInfo->tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , sInfo->tree.nodeAllocators.size() ? sInfo->tree.nodeAllocators[0] : NULL , sInfo->tree.initializer() , ProcessData ); + if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); } else { @@ -1180,11 +1057,11 @@ namespace Reconstructor }; typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; - if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , sInfo->tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , sInfo->tree.nodeAllocators.size() ? sInfo->tree.nodeAllocators[0] : NULL , sInfo->tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , sInfo->tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , sInfo->tree.nodeAllocators.size() ? sInfo->tree.nodeAllocators[0] : NULL , sInfo->tree.initializer() , ProcessData ); + if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); } - sInfo->unitCubeToModel = modelToUnitCube.inverse(); + implicit.unitCubeToModel = modelToUnitCube.inverse(); if( params.verbose ) { @@ -1197,12 +1074,12 @@ namespace Reconstructor InterpolationInfo *iInfo = NULL; int solveDepth = params.depth; - sInfo->tree.resetNodeIndices( 0 , std::make_tuple() ); + implicit.tree.resetNodeIndices( 0 , std::make_tuple() ); // Get the kernel density estimator { profiler.reset(); - sInfo->density = sInfo->tree.template setDensityEstimator< 1 , Reconstructor::WeightDegree >( *samples , params.kernelDepth , params.samplesPerNode ); + implicit.density = implicit.tree.template setDensityEstimator< 1 , Reconstructor::WeightDegree >( *samples , params.kernelDepth , params.samplesPerNode ); if( params.verbose ) std::cout << "# Got kernel density: " << profiler << std::endl; } @@ -1255,8 +1132,8 @@ namespace Reconstructor return true; }; } - if( params.confidenceBias>0 ) *normalInfo = sInfo->tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , sInfo->density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionAndBiasFunction ); - else *normalInfo = sInfo->tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , sInfo->density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionFunction ); + if( params.confidenceBias>0 ) *normalInfo = implicit.tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , implicit.density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionAndBiasFunction ); + else *normalInfo = implicit.tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , implicit.density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionFunction ); if( params.verbose ) { std::cout << "# Got normal field: " << profiler << std::endl; @@ -1264,8 +1141,8 @@ namespace Reconstructor } } - if( !params.outputDensity ){ delete sInfo->density ; sInfo->density = NULL; } - if constexpr( HasAuxData ) sInfo->auxData = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( sInfo->tree.template setExtrapolatedDataField< DataSig , false , Reconstructor::WeightDegree , AuxData >( samples->size() , [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return (*samples)[i]; } , [&]( size_t i ) -> const AuxData & { return (*sampleNormalAndAuxData)[i].template get<1>(); } , (DensityEstimator*)NULL ) ); + if( !params.outputDensity ){ delete implicit.density ; implicit.density = NULL; } + if constexpr( HasAuxData ) implicit.auxData = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( implicit.tree.template setExtrapolatedDataField< DataSig , false , Reconstructor::WeightDegree , AuxData >( samples->size() , [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return (*samples)[i]; } , [&]( size_t i ) -> const AuxData & { return (*sampleNormalAndAuxData)[i].template get<1>(); } , (DensityEstimator*)NULL ) ); // Add the interpolation constraints if( params.pointWeight>0 || params.gradientWeight>0 ) @@ -1273,13 +1150,13 @@ namespace Reconstructor profiler.reset(); if constexpr( HasAuxData ) { - if( params.exactInterpolation ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , NormalAndAuxData , 1 >( sInfo->tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real , AuxData >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real , AuxData >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , false ); - else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , NormalAndAuxData , 1 >( sInfo->tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real , AuxData >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real , AuxData >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , params.depth , 1 ); + if( params.exactInterpolation ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , NormalAndAuxData , 1 >( implicit.tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real , AuxData >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real , AuxData >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , false ); + else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , NormalAndAuxData , 1 >( implicit.tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real , AuxData >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real , AuxData >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , params.depth , 1 ); } else { - if( params.exactInterpolation ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , Point< Real , Dim > , 1 >( sInfo->tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , false ); - else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , Point< Real , Dim > , 1 >( sInfo->tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , params.depth , 1 ); + if( params.exactInterpolation ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , Point< Real , Dim > , 1 >( implicit.tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , false ); + else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , Point< Real , Dim > , 1 >( implicit.tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , params.depth , 1 ); } if( params.verbose ) std::cout << "#Initialized point interpolation constraints: " << profiler << std::endl; } @@ -1294,8 +1171,8 @@ namespace Reconstructor typename FEMTree< Dim , Real >::template HasNormalDataFunctor< NormalSigs > hasNormalDataFunctor( *normalInfo ); auto hasDataFunctor = [&]( const FEMTreeNode *node ){ return hasNormalDataFunctor( node ); }; auto addNodeFunctor = [&]( int d , const int off[Dim] ){ return d<=(int)params.fullDepth; }; - if constexpr( HasAuxData ) sInfo->tree.template finalizeForMultigrid< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , sInfo->density , sInfo->auxData ) ); - else sInfo->tree.template finalizeForMultigrid< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , sInfo->density ) ); + if constexpr( HasAuxData ) implicit.tree.template finalizeForMultigrid< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density , implicit.auxData ) ); + else implicit.tree.template finalizeForMultigrid< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density ) ); if( params.verbose ) std::cout << "# Finalized tree: " << profiler << std::endl; } @@ -1306,12 +1183,12 @@ namespace Reconstructor if( params.pointWeight>0 || params.gradientWeight>0 ) { profiler.reset(); - constraints = sInfo->tree.initDenseNodeData( Sigs() ); - sInfo->tree.addInterpolationConstraints( constraints , solveDepth , std::make_tuple( iInfo ) ); + constraints = implicit.tree.initDenseNodeData( Sigs() ); + implicit.tree.addInterpolationConstraints( constraints , solveDepth , std::make_tuple( iInfo ) ); if( params.verbose ) std::cout << "#Set point constraints: " << profiler << std::endl; } - if( params.verbose ) std::cout << "All Nodes / Active Nodes / Ghost Nodes: " << sInfo->tree.allNodes() << " / " << sInfo->tree.activeNodes() << " / " << sInfo->tree.ghostNodes() << std::endl; + if( params.verbose ) std::cout << "All Nodes / Active Nodes / Ghost Nodes: " << implicit.tree.allNodes() << " / " << implicit.tree.activeNodes() << " / " << implicit.tree.ghostNodes() << std::endl; if( params.verbose ) std::cout << "Memory Usage: " << float( MemoryInfo::Usage())/(1<<20) << " MB" << std::endl; // Solve the linear system @@ -1321,7 +1198,7 @@ namespace Reconstructor _sInfo.cgDepth = 0 , _sInfo.cascadic = true , _sInfo.vCycles = 1 , _sInfo.iters = params.iters , _sInfo.cgAccuracy = params.cgSolverAccuracy , _sInfo.verbose = params.verbose , _sInfo.showResidual = params.showResidual , _sInfo.showGlobalResidual = SHOW_GLOBAL_RESIDUAL_NONE , _sInfo.sliceBlockSize = 1; _sInfo.baseVCycles = params.baseVCycles; typename FEMIntegrator::template System< Sigs , IsotropicUIntPack< Dim , 2 > > F( { 0. , 0. , (double)params.biLapWeight } ); - sInfo->solution = sInfo->tree.solveSystem( Sigs() , F , constraints , params.baseDepth , params.solveDepth , _sInfo , std::make_tuple( iInfo ) ); + implicit.solution = implicit.tree.solveSystem( Sigs() , F , constraints , params.baseDepth , params.solveDepth , _sInfo , std::make_tuple( iInfo ) ); if( params.verbose ) std::cout << "# Linear system solved: " << profiler << std::endl; if( iInfo ) delete iInfo , iInfo = NULL; } @@ -1331,7 +1208,7 @@ namespace Reconstructor { profiler.reset(); double valueSum = 0 , weightSum = 0; - typename FEMTree< Dim , Real >::template MultiThreadedEvaluator< Sigs , 0 > evaluator( &sInfo->tree , sInfo->solution ); + typename FEMTree< Dim , Real >::template MultiThreadedEvaluator< Sigs , 0 > evaluator( &implicit.tree , implicit.solution ); std::vector< double > valueSums( ThreadPool::NumThreads() , 0 ) , weightSums( ThreadPool::NumThreads() , 0 ); ThreadPool::Parallel_for( 0 , samples->size() , [&]( unsigned int thread , size_t j ) { @@ -1340,15 +1217,14 @@ namespace Reconstructor if( w>0 ) weightSums[thread] += w , valueSums[thread] += evaluator.values( sample.data / sample.weight , thread , (*samples)[j].node )[0] * w; } ); for( size_t t=0 ; tisoValue = (Real)( valueSum / weightSum ); + implicit.isoValue = (Real)( valueSum / weightSum ); if( params.verbose ) { std::cout << "Got average: " << profiler << std::endl; - std::cout << "Iso-Value: " << sInfo->isoValue << " = " << valueSum << " / " << weightSum << std::endl; + std::cout << "Iso-Value: " << implicit.isoValue << " = " << valueSum << " / " << weightSum << std::endl; } } delete samples; - return sInfo; } } diff --git a/Src/SSDRecon.cpp b/Src/SSDRecon.cpp index 3192c4b1..ddd91560 100644 --- a/Src/SSDRecon.cpp +++ b/Src/SSDRecon.cpp @@ -196,8 +196,8 @@ template< typename Real , unsigned int Dim , unsigned int FEMSig , bool HasGradi void WriteMesh ( bool inCore , - Reconstructor::ReconstructionInfo< Real , Dim , FEMSig > &reconInfo , - const Reconstructor::MeshExtractionParameters &meParams , + Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig > &implicit , + const Reconstructor::LevelSetExtractionParameters &meParams , std::string fileName , bool ascii ) @@ -217,8 +217,8 @@ void WriteMesh // The wrapper converting native to output types typename VInfo::StreamWrapper _vertexStream( vertexStream , factory() ); - // Extract the mesh - Reconstructor::ExtractMesh< Real >( reconInfo , _vertexStream , polygonStream , meParams ); + // Extract the level set + implicit.extractLevelSet( _vertexStream , polygonStream , meParams ); } // Write the mesh to a .ply file @@ -231,8 +231,8 @@ void WriteMeshWithData ( const AuxDataFactory &auxDataFactory , bool inCore , - Reconstructor::ReconstructionInfo< Real , Dim , FEMSig , typename AuxDataFactory::VertexType > &reconInfo , - const Reconstructor::MeshExtractionParameters &meParams , + Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig , typename AuxDataFactory::VertexType > &implicit , + const Reconstructor::LevelSetExtractionParameters &meParams , std::string fileName , bool ascii ) @@ -252,8 +252,8 @@ void WriteMeshWithData // The wrapper converting native to output types typename VInfo::StreamWrapper _vertexStream( vertexStream , factory() ); - // Extract the mesh - Reconstructor::ExtractMesh< Real >( reconInfo , _vertexStream , polygonStream , meParams ); + // Extract the level set + implicit.extractLevelSet( _vertexStream , polygonStream , meParams ); } // Write the mesh to a .ply file @@ -280,7 +280,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) typedef InputDataStream< typename InputSampleFactory::VertexType > InputPointStream; // The type storing the reconstruction solution (depending on whether auxiliary data is provided or not) - using ReconstructionInfo = typename std::conditional< HasAuxData , Reconstructor::ReconstructionInfo< Real , Dim , FEMSig , typename AuxDataFactory::VertexType > , Reconstructor::ReconstructionInfo< Real , Dim , FEMSig > >::type; + using ImplicitRepresentation = typename std::conditional< HasAuxData , Reconstructor::SSD::ImplicitRepresentation< Real , Dim , FEMSig , typename AuxDataFactory::VertexType > , Reconstructor::SSD::ImplicitRepresentation< Real , Dim , FEMSig > >::type; // <-- Types // /////////////// @@ -303,9 +303,9 @@ void Execute( const AuxDataFactory &auxDataFactory ) } Profiler profiler(20); - ReconstructionInfo *sInfo = NULL; + ImplicitRepresentation *implicit = NULL; typename Reconstructor::SSD::SolutionParameters< Real > sParams; - typename Reconstructor::MeshExtractionParameters meParams; + Reconstructor::LevelSetExtractionParameters meParams; sParams.verbose = Verbose.set; sParams.outputDensity = Density.set; @@ -437,10 +437,10 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( Transform.set ) { Reconstructor::TransformedInputSampleWithDataStream< Real , Dim , typename AuxDataFactory::VertexType > _sampleStream( toModel , sampleStream ); - sInfo = Reconstructor::SSD::Solve< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( _sampleStream , sParams ); - sInfo->unitCubeToModel = toModel.inverse() * sInfo->unitCubeToModel; + implicit = new Reconstructor::SSD::ImplicitRepresentation< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( _sampleStream , sParams ); + implicit->unitCubeToModel = toModel.inverse() * implicit->unitCubeToModel; } - else sInfo = Reconstructor::SSD::Solve< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( sampleStream , sParams ); + else implicit = new Reconstructor::SSD::ImplicitRepresentation< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( sampleStream , sParams ); } else { @@ -449,16 +449,16 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( Transform.set ) { Reconstructor::TransformedInputSampleStream< Real , Dim > _sampleStream( toModel , sampleStream ); - sInfo = Reconstructor::SSD::Solve< Real , Dim , FEMSig >( _sampleStream , sParams ); - sInfo->unitCubeToModel = toModel.inverse() * sInfo->unitCubeToModel; + implicit = new Reconstructor::SSD::ImplicitRepresentation< Real , Dim , FEMSig >( _sampleStream , sParams ); + implicit->unitCubeToModel = toModel.inverse() * implicit->unitCubeToModel; } - else sInfo = Reconstructor::SSD::Solve< Real , Dim , FEMSig >( sampleStream , sParams ); + else implicit = new Reconstructor::SSD::ImplicitRepresentation< Real , Dim , FEMSig >( sampleStream , sParams ); } delete pointStream; delete _inputSampleFactory; - if constexpr( HasAuxData ) if( sInfo->auxData ) sInfo->weightAuxDataByDepth( (Real)DataX.value ); + if constexpr( HasAuxData ) if( implicit->auxData ) implicit->weightAuxDataByDepth( (Real)DataX.value ); if( Tree.set ) { @@ -467,10 +467,10 @@ void Execute( const AuxDataFactory &auxDataFactory ) FileStream fs(fp); FEMTree< Dim , Real >::WriteParameter( fs ); DenseNodeData< Real , Sigs >::WriteSignatures( fs ); - sInfo->tree.write( fs , sInfo->unitCubeToModel.inverse() , false ); - sInfo->solution.write( fs ); - if constexpr( HasAuxData ) if( sInfo->auxData ) sInfo->auxData->write( fs ); - if( sInfo->density ) sInfo->density->write( fs ); + implicit->tree.write( fs , implicit->unitCubeToModel.inverse() , false ); + implicit->solution.write( fs ); + if constexpr( HasAuxData ) if( implicit->auxData ) implicit->auxData->write( fs ); + if( implicit->density ) implicit->density->write( fs ); fclose( fp ); } @@ -479,7 +479,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) { int res = 0; profiler.reset(); - Pointer( Real ) values = sInfo->tree.template regularGridEvaluate< true >( sInfo->solution , res , -1 , PrimalGrid.set ); + Pointer( Real ) values = implicit->tree.template regularGridEvaluate< true >( implicit->solution , res , -1 , PrimalGrid.set ); if( Verbose.set ) std::cout << "Got grid: " << profiler << std::endl; XForm< Real , Dim+1 > voxelToUnitCube = XForm< Real , Dim+1 >::Identity(); if( PrimalGrid.set ) for( int d=0 ; d::Write( Grid.value , _res , values , sInfo->unitCubeToModel * voxelToUnitCube ); + RegularGrid< Real , Dim >::Write( Grid.value , _res , values , implicit->unitCubeToModel * voxelToUnitCube ); DeletePointer( values ); } @@ -508,38 +508,38 @@ void Execute( const AuxDataFactory &auxDataFactory ) else sprintf( tempHeader , "%s%cPR_" , tempPath , FileSeparator ); } - XForm< Real , Dim+1 > pXForm = sInfo->unitCubeToModel; + XForm< Real , Dim+1 > pXForm = implicit->unitCubeToModel; XForm< Real , Dim > nXForm = XForm< Real , Dim >( pXForm ).inverse().transpose(); if( Gradients.set ) { if( Density.set ) { - if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , true , true >( auxDataFactory , InCore.set , *sInfo , meParams , Out.value , ASCII.set ); - else WriteMesh < Real , Dim , FEMSig , true , true >( InCore.set , *sInfo , meParams , Out.value , ASCII.set ); + if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , true , true >( auxDataFactory , InCore.set , *implicit , meParams , Out.value , ASCII.set ); + else WriteMesh < Real , Dim , FEMSig , true , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); } else { - if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , true , false >( auxDataFactory , InCore.set , *sInfo , meParams , Out.value , ASCII.set ); - else WriteMesh < Real , Dim , FEMSig , true , false >( InCore.set , *sInfo , meParams , Out.value , ASCII.set ); + if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , true , false >( auxDataFactory , InCore.set , *implicit , meParams , Out.value , ASCII.set ); + else WriteMesh < Real , Dim , FEMSig , true , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); } } else { if( Density.set ) { - if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , false , true >( auxDataFactory , InCore.set , *sInfo , meParams , Out.value , ASCII.set ); - else WriteMesh < Real , Dim , FEMSig , false , true >( InCore.set , *sInfo , meParams , Out.value , ASCII.set ); + if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , false , true >( auxDataFactory , InCore.set , *implicit , meParams , Out.value , ASCII.set ); + else WriteMesh < Real , Dim , FEMSig , false , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); } else { - if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , false , false >( auxDataFactory , InCore.set , *sInfo , meParams , Out.value , ASCII.set ); - else WriteMesh < Real , Dim , FEMSig , false , false >( InCore.set , *sInfo , meParams , Out.value , ASCII.set ); + if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , false , false >( auxDataFactory , InCore.set , *implicit , meParams , Out.value , ASCII.set ); + else WriteMesh < Real , Dim , FEMSig , false , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); } } } if( Verbose.set ) std::cout << "# Total Solve: " << Time()-startTime << " (s), " << MemoryInfo::PeakMemoryUsageMB() << " (MB)" << std::endl; - delete sInfo; + delete implicit; } #ifndef FAST_COMPILE From df08e54058cad6d2e7118550ca5352731b928a0d Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Fri, 6 Oct 2023 17:59:08 -0400 Subject: [PATCH 12/86] Version 15.01 ImplicitRepresentation -> Implicit --- Src/PoissonRecon.cpp | 16 ++++---- Src/Reconstruction.example.cpp | 17 +++++---- Src/Reconstructors.h | 70 +++++++++++++++++----------------- Src/SSDRecon.cpp | 16 ++++---- 4 files changed, 60 insertions(+), 59 deletions(-) diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index 60466169..5b4c2a56 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -200,7 +200,7 @@ template< typename Real , unsigned int Dim , unsigned int FEMSig , bool HasGradi void WriteMesh ( bool inCore , - Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig > &implicit , + Reconstructor::Implicit< Real , Dim , FEMSig > &implicit , const Reconstructor::LevelSetExtractionParameters &meParams , std::string fileName , bool ascii @@ -235,7 +235,7 @@ void WriteMeshWithData ( const AuxDataFactory &auxDataFactory , bool inCore , - Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig , typename AuxDataFactory::VertexType > &implicit , + Reconstructor::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType > &implicit , const Reconstructor::LevelSetExtractionParameters &meParams , std::string fileName , bool ascii @@ -284,7 +284,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) typedef InputDataStream< typename InputSampleFactory::VertexType > InputPointStream; // The type storing the reconstruction solution (depending on whether auxiliary data is provided or not) - using ImplicitRepresentation = typename std::conditional< HasAuxData , Reconstructor::Poisson::ImplicitRepresentation< Real , Dim , FEMSig , typename AuxDataFactory::VertexType > , Reconstructor::Poisson::ImplicitRepresentation< Real , Dim , FEMSig > >::type; + using Implicit = typename std::conditional< HasAuxData , Reconstructor::Poisson::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType > , Reconstructor::Poisson::Implicit< Real , Dim , FEMSig > >::type; // <-- Types // /////////////// @@ -307,7 +307,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) } Profiler profiler(20); - ImplicitRepresentation *implicit = NULL; + Implicit *implicit = NULL; typename Reconstructor::Poisson::SolutionParameters< Real > sParams; Reconstructor::LevelSetExtractionParameters meParams; @@ -458,10 +458,10 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( Transform.set ) { Reconstructor::TransformedInputSampleWithDataStream< Real , Dim , typename AuxDataFactory::VertexType > _sampleStream( toModel , sampleStream ); - implicit = new typename Reconstructor::Poisson::ImplicitRepresentation< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( _sampleStream , sParams , envelopeMesh ); + implicit = new typename Reconstructor::Poisson::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( _sampleStream , sParams , envelopeMesh ); implicit->unitCubeToModel = toModel.inverse() * implicit->unitCubeToModel; } - else implicit = new typename Reconstructor::Poisson::ImplicitRepresentation< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( sampleStream , sParams , envelopeMesh ); + else implicit = new typename Reconstructor::Poisson::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( sampleStream , sParams , envelopeMesh ); } else { @@ -470,10 +470,10 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( Transform.set ) { Reconstructor::TransformedInputSampleStream< Real , Dim > _sampleStream( toModel , sampleStream ); - implicit = new typename Reconstructor::Poisson::ImplicitRepresentation< Real , Dim , FEMSig >( _sampleStream , sParams , envelopeMesh ); + implicit = new typename Reconstructor::Poisson::Implicit< Real , Dim , FEMSig >( _sampleStream , sParams , envelopeMesh ); implicit->unitCubeToModel = toModel.inverse() * implicit->unitCubeToModel; } - else implicit = new typename Reconstructor::Poisson::ImplicitRepresentation< Real , Dim , FEMSig >( sampleStream , sParams , envelopeMesh ); + else implicit = new typename Reconstructor::Poisson::Implicit< Real , Dim , FEMSig >( sampleStream , sParams , envelopeMesh ); } delete pointStream; diff --git a/Src/Reconstruction.example.cpp b/Src/Reconstruction.example.cpp index bb4c62b4..dd8de2d5 100644 --- a/Src/Reconstruction.example.cpp +++ b/Src/Reconstruction.example.cpp @@ -57,6 +57,7 @@ void ShowUsage( char* ex ) // A simple structure for representing colors. // Assuming values are in the range [0,1]. +template< typename Real > struct RGBColor { // The channels @@ -262,18 +263,18 @@ void Execute( void ) if constexpr( UseColor ) { // The type of the reconstructor - using ImplicitRepresentation = typename std::conditional + using Implicit = typename std::conditional < SSD , - Reconstructor:: SSD::ImplicitRepresentation< Real , Dim , FEMSig , RGBColor< Real > > , - Reconstructor::Poisson::ImplicitRepresentation< Real , Dim , FEMSig , RGBColor< Real > > + Reconstructor:: SSD::Implicit< Real , Dim , FEMSig , RGBColor< Real > > , + Reconstructor::Poisson::Implicit< Real , Dim , FEMSig , RGBColor< Real > > >::type; // A stream generating random points on the sphere with color SphereSampleWithColorStream< Real , Dim > sampleStream( SampleNum.value ); // Construct the implicit representation - ImplicitRepresentation implicit( sampleStream , solverParams ); + Implicit implicit( sampleStream , solverParams ); // Scale the color information to give extrapolation preference to data at finer depths implicit.weightAuxDataByDepth( (Real)32. ); @@ -295,18 +296,18 @@ void Execute( void ) else { // The type of the reconstructor - using ImplicitRepresentation = typename std::conditional + using Implicit = typename std::conditional < SSD , - Reconstructor:: SSD::ImplicitRepresentation< Real , Dim , FEMSig > , - Reconstructor::Poisson::ImplicitRepresentation< Real , Dim , FEMSig > + Reconstructor:: SSD::Implicit< Real , Dim , FEMSig > , + Reconstructor::Poisson::Implicit< Real , Dim , FEMSig > >::type; // A stream generating random points on the sphere SphereSampleStream< Real , Dim > sampleStream( SampleNum.value ); // Construct the implicit representation - ImplicitRepresentation implicit( sampleStream , solverParams ); + Implicit implicit( sampleStream , solverParams ); // vectors for storing the polygons (specifically, triangles) and the coordinates of the vertices std::vector< std::vector< int > > polygons; diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h index 2254b738..23df9330 100644 --- a/Src/Reconstructors.h +++ b/Src/Reconstructors.h @@ -46,7 +46,7 @@ namespace Reconstructor #include "Reconstructors.streams.h" // Declare a type for storing the solution information - template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... AuxData > struct ImplicitRepresentation; + template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... AuxData > struct Implicit; // Parameters for mesh extraction struct LevelSetExtractionParameters @@ -60,12 +60,12 @@ namespace Reconstructor }; // "Private" function for extracting meshes - template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ImplicitRepresentationType , unsigned int ... FEMSigs > - void _ExtractLevelSet( UIntPack< FEMSigs ... > , const ImplicitRepresentationType &implicit , OutputVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , LevelSetExtractionParameters params ); + template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ImplicitType , unsigned int ... FEMSigs > + void _ExtractLevelSet( UIntPack< FEMSigs ... > , const ImplicitType &implicit , OutputVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , LevelSetExtractionParameters params ); // Specialized solution information without auxiliary data template< typename Real , unsigned int Dim , unsigned int FEMSig > - struct ImplicitRepresentation< Real , Dim , FEMSig > + struct Implicit< Real , Dim , FEMSig > { // The signature pack typedef IsotropicUIntPack< Dim , FEMSig > Sigs; @@ -74,10 +74,10 @@ namespace Reconstructor typedef typename FEMTree< Dim , Real >::template DensityEstimator< Reconstructor::WeightDegree > DensityEstimator; // The constructor - ImplicitRepresentation( void ) : density(NULL) , isoValue(0) , tree(MEMORY_ALLOCATOR_BLOCK_SIZE) , unitCubeToModel( XForm< Real , Dim+1 >::Identity() ){} + Implicit( void ) : density(NULL) , isoValue(0) , tree(MEMORY_ALLOCATOR_BLOCK_SIZE) , unitCubeToModel( XForm< Real , Dim+1 >::Identity() ){} // The desctructor - ~ImplicitRepresentation( void ){ delete density ; density = NULL; } + ~Implicit( void ){ delete density ; density = NULL; } // The transformation taking points in the unit cube back to world coordinates XForm< Real , Dim+1 > unitCubeToModel; @@ -98,13 +98,13 @@ namespace Reconstructor void extractLevelSet( OutputVertexStream< Real , Dim > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , LevelSetExtractionParameters params ) const { typedef unsigned char AuxData; - _ExtractLevelSet< false , Real , Dim , FEMSig , AuxData , OutputVertexStream< Real , Dim > , ImplicitRepresentation< Real , Dim , FEMSig > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , polygonStream , params ); + _ExtractLevelSet< false , Real , Dim , FEMSig , AuxData , OutputVertexStream< Real , Dim > , Implicit< Real , Dim , FEMSig > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , polygonStream , params ); } }; // Specialized solution information with auxiliary data template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > - struct ImplicitRepresentation< Real , Dim , FEMSig , AuxData > : public ImplicitRepresentation< Real , Dim , FEMSig > + struct Implicit< Real , Dim , FEMSig , AuxData > : public Implicit< Real , Dim , FEMSig > { typedef IsotropicUIntPack< Dim , FEMSig > Sigs; @@ -112,10 +112,10 @@ namespace Reconstructor static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; // The constructor - ImplicitRepresentation( AuxData zeroAuxData ) : auxData(NULL) , zeroAuxData(zeroAuxData) {} + Implicit( AuxData zeroAuxData ) : auxData(NULL) , zeroAuxData(zeroAuxData) {} // The desctructor - ~ImplicitRepresentation( void ){ delete auxData ; auxData = NULL; } + ~Implicit( void ){ delete auxData ; auxData = NULL; } // The auxiliary information stored with the oriented vertices SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > > *auxData; @@ -129,15 +129,15 @@ namespace Reconstructor auto nodeFunctor = [&]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *n ) { ProjectiveData< AuxData , Real >* clr = (*auxData)( n ); - if( clr ) (*clr) *= (Real)pow( (Real)perLevelScaleFactor , ImplicitRepresentation< Real , Dim , FEMSig>::tree.depth( n ) ); + if( clr ) (*clr) *= (Real)pow( (Real)perLevelScaleFactor , Implicit< Real , Dim , FEMSig>::tree.depth( n ) ); }; - ImplicitRepresentation< Real , Dim , FEMSig>::tree.tree().processNodes( nodeFunctor ); + Implicit< Real , Dim , FEMSig>::tree.tree().processNodes( nodeFunctor ); } // A method for writing the extracted mesh to the streams void extractLevelSet( OutputVertexWithDataStream< Real , Dim , AuxData > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , LevelSetExtractionParameters params ) const { - _ExtractLevelSet< true , Real , Dim , FEMSig , AuxData , OutputVertexWithDataStream< Real , Dim , AuxData > , ImplicitRepresentation< Real , Dim , FEMSig , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , polygonStream , params ); + _ExtractLevelSet< true , Real , Dim , FEMSig , AuxData , OutputVertexWithDataStream< Real , Dim , AuxData > , Implicit< Real , Dim , FEMSig , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , polygonStream , params ); } }; @@ -218,17 +218,17 @@ namespace Reconstructor std::vector< SimplexIndex< Dim-1 , node_index_type > > simplices; }; - template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct ImplicitRepresentation; + template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct Implicit; template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > - void _Solve( UIntPack< FEMSigs... > , typename std::conditional< HasAuxData , Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig , AuxData > , ImplicitRepresentation< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh ); + void _Solve( UIntPack< FEMSigs... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh ); - template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct ImplicitRepresentation; + template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct Implicit; template< typename Real , unsigned int Dim , unsigned int FEMSig > - struct ImplicitRepresentation< Real , Dim , FEMSig > : public Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig > + struct Implicit< Real , Dim , FEMSig > : public Reconstructor::Implicit< Real , Dim , FEMSig > { - ImplicitRepresentation( InputSampleStream< Real , Dim > &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL ) + Implicit( InputSampleStream< Real , Dim > &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL ) { typedef unsigned char AuxData; _Solve< false , Real , Dim , FEMSig , AuxData , InputSampleStream< Real , Dim > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params , envelopeMesh ); @@ -236,10 +236,10 @@ namespace Reconstructor }; template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > - struct ImplicitRepresentation< Real , Dim , FEMSig , AuxData > : public Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig , AuxData > + struct Implicit< Real , Dim , FEMSig , AuxData > : public Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > { - ImplicitRepresentation( InputSampleWithDataStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL ) - : Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig , AuxData >( pointStream.zero() ) + Implicit( InputSampleWithDataStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL ) + : Reconstructor::Implicit< Real , Dim , FEMSig , AuxData >( pointStream.zero() ) { _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleWithDataStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params , envelopeMesh ); } @@ -382,15 +382,15 @@ namespace Reconstructor }; - template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct ImplicitRepresentation; + template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct Implicit; template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > - void _Solve( UIntPack< FEMSigs... > , typename std::conditional< HasAuxData , Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig , AuxData > , ImplicitRepresentation< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params ); + void _Solve( UIntPack< FEMSigs... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params ); template< typename Real , unsigned int Dim , unsigned int FEMSig > - struct ImplicitRepresentation< Real , Dim , FEMSig > : public Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig > + struct Implicit< Real , Dim , FEMSig > : public Reconstructor::Implicit< Real , Dim , FEMSig > { - ImplicitRepresentation( InputSampleStream< Real , Dim > &pointStream , SolutionParameters< Real > params ) + Implicit( InputSampleStream< Real , Dim > &pointStream , SolutionParameters< Real > params ) { typedef unsigned char AuxData; _Solve< false , Real , Dim , FEMSig , AuxData , InputSampleStream< Real , Dim > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params ); @@ -398,10 +398,10 @@ namespace Reconstructor }; template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > - struct ImplicitRepresentation< Real , Dim , FEMSig , AuxData > : public Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig , AuxData > + struct Implicit< Real , Dim , FEMSig , AuxData > : public Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > { - ImplicitRepresentation( InputSampleWithDataStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params ) - : Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig , AuxData >( pointStream.zero() ) + Implicit( InputSampleWithDataStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params ) + : Reconstructor::Implicit< Real , Dim , FEMSig , AuxData >( pointStream.zero() ) { _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleWithDataStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params ); } @@ -460,13 +460,13 @@ namespace Reconstructor return GetBoundingBoxXForm( min , max , scaleFactor ); } - template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ImplicitRepresentationType , unsigned int ... FEMSigs > - void _ExtractLevelSet( UIntPack< FEMSigs ... > , const ImplicitRepresentationType &implicit , OutputVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , LevelSetExtractionParameters params ) + template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ImplicitType , unsigned int ... FEMSigs > + void _ExtractLevelSet( UIntPack< FEMSigs ... > , const ImplicitType &implicit , OutputVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , LevelSetExtractionParameters params ) { typedef UIntPack< FEMSigs ... > Sigs; static_assert( std::is_same< IsotropicUIntPack< Dim , FEMSig > , UIntPack< FEMSigs ... > >::value , "[ERROR] Signatures don't match" ); static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; - typedef typename ImplicitRepresentationType::DensityEstimator DensityEstimator; + typedef typename ImplicitType::DensityEstimator DensityEstimator; if constexpr( Dim!=3 ) { @@ -504,7 +504,7 @@ namespace Reconstructor } template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > - void Poisson::_Solve( UIntPack< FEMSigs ... > , typename std::conditional< HasAuxData , Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig , AuxData > , ImplicitRepresentation< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh ) + void Poisson::_Solve( UIntPack< FEMSigs ... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh ) { static_assert( std::is_same< IsotropicUIntPack< Dim , FEMSig > , UIntPack< FEMSigs... > >::value , "[ERROR] Signatures don't match" ); @@ -534,7 +534,7 @@ namespace Reconstructor typedef typename std::conditional< HasAuxData , VectorTypeUnion< Real , Normal< Real , Dim > , AuxData > , Normal< Real , Dim > >::type NormalAndAuxData; // The type describing the sampling density - typedef typename std::conditional< HasAuxData , ImplicitRepresentation< Real , Dim , FEMSig , AuxData > , ImplicitRepresentation< Real , Dim , FEMSig > >::type::DensityEstimator DensityEstimator; + typedef typename std::conditional< HasAuxData , Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type::DensityEstimator DensityEstimator; // <-- Types // /////////////// @@ -925,7 +925,7 @@ namespace Reconstructor } template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > - void SSD::_Solve( UIntPack< FEMSigs ... > , typename std::conditional< HasAuxData , Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig , AuxData > , ImplicitRepresentation< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params ) + void SSD::_Solve( UIntPack< FEMSigs ... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params ) { static_assert( std::is_same< IsotropicUIntPack< Dim , FEMSig > , UIntPack< FEMSigs... > >::value , "[ERROR] Signatures don't match" ); @@ -953,7 +953,7 @@ namespace Reconstructor typedef typename std::conditional< HasAuxData , VectorTypeUnion< Real , Normal< Real , Dim > , AuxData > , Normal< Real , Dim > >::type NormalAndAuxData; // The type describing the sampling density - typedef typename std::conditional< HasAuxData , ImplicitRepresentation< Real , Dim , FEMSig , AuxData > , ImplicitRepresentation< Real , Dim , FEMSig > >::type::DensityEstimator DensityEstimator; + typedef typename std::conditional< HasAuxData , Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type::DensityEstimator DensityEstimator; // <-- Types // /////////////// diff --git a/Src/SSDRecon.cpp b/Src/SSDRecon.cpp index ddd91560..4a1d97f0 100644 --- a/Src/SSDRecon.cpp +++ b/Src/SSDRecon.cpp @@ -196,7 +196,7 @@ template< typename Real , unsigned int Dim , unsigned int FEMSig , bool HasGradi void WriteMesh ( bool inCore , - Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig > &implicit , + Reconstructor::Implicit< Real , Dim , FEMSig > &implicit , const Reconstructor::LevelSetExtractionParameters &meParams , std::string fileName , bool ascii @@ -231,7 +231,7 @@ void WriteMeshWithData ( const AuxDataFactory &auxDataFactory , bool inCore , - Reconstructor::ImplicitRepresentation< Real , Dim , FEMSig , typename AuxDataFactory::VertexType > &implicit , + Reconstructor::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType > &implicit , const Reconstructor::LevelSetExtractionParameters &meParams , std::string fileName , bool ascii @@ -280,7 +280,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) typedef InputDataStream< typename InputSampleFactory::VertexType > InputPointStream; // The type storing the reconstruction solution (depending on whether auxiliary data is provided or not) - using ImplicitRepresentation = typename std::conditional< HasAuxData , Reconstructor::SSD::ImplicitRepresentation< Real , Dim , FEMSig , typename AuxDataFactory::VertexType > , Reconstructor::SSD::ImplicitRepresentation< Real , Dim , FEMSig > >::type; + using Implicit = typename std::conditional< HasAuxData , Reconstructor::SSD::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType > , Reconstructor::SSD::Implicit< Real , Dim , FEMSig > >::type; // <-- Types // /////////////// @@ -303,7 +303,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) } Profiler profiler(20); - ImplicitRepresentation *implicit = NULL; + Implicit *implicit = NULL; typename Reconstructor::SSD::SolutionParameters< Real > sParams; Reconstructor::LevelSetExtractionParameters meParams; @@ -437,10 +437,10 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( Transform.set ) { Reconstructor::TransformedInputSampleWithDataStream< Real , Dim , typename AuxDataFactory::VertexType > _sampleStream( toModel , sampleStream ); - implicit = new Reconstructor::SSD::ImplicitRepresentation< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( _sampleStream , sParams ); + implicit = new Reconstructor::SSD::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( _sampleStream , sParams ); implicit->unitCubeToModel = toModel.inverse() * implicit->unitCubeToModel; } - else implicit = new Reconstructor::SSD::ImplicitRepresentation< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( sampleStream , sParams ); + else implicit = new Reconstructor::SSD::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( sampleStream , sParams ); } else { @@ -449,10 +449,10 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( Transform.set ) { Reconstructor::TransformedInputSampleStream< Real , Dim > _sampleStream( toModel , sampleStream ); - implicit = new Reconstructor::SSD::ImplicitRepresentation< Real , Dim , FEMSig >( _sampleStream , sParams ); + implicit = new Reconstructor::SSD::Implicit< Real , Dim , FEMSig >( _sampleStream , sParams ); implicit->unitCubeToModel = toModel.inverse() * implicit->unitCubeToModel; } - else implicit = new Reconstructor::SSD::ImplicitRepresentation< Real , Dim , FEMSig >( sampleStream , sParams ); + else implicit = new Reconstructor::SSD::Implicit< Real , Dim , FEMSig >( sampleStream , sParams ); } delete pointStream; From 6272080cd0a38591823a0fb343dde82c40954636 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Fri, 6 Oct 2023 18:00:24 -0400 Subject: [PATCH 13/86] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 92a56578..1527e8f2 100644 --- a/README.md +++ b/README.md @@ -962,9 +962,9 @@ This method writes the information for the next polygon into the stream, with th The reconstructed surface is then computed in two steps:
      -
    • Poisson::ImplicitRepresentation< Real , Dim , FEMSig >::ImplicitRepresentation( InputSampleStream< Real , Dim > &sStream , SolutionParameters< Real > sParams ):
      -This constructor creates a Poisson reconstruction object from an input sample stream (sStream) and a description of the reconstruction parameters (sParams) desribing the depth, number of samples per node, etc. (Reconstructors.h, line 229). This object derives from ImplicitRepresentation< Real , Dim , FEMSig >. -
    • void ImplicitRepresentation< Real , Dim , FEMSig >::extractLevelSet( OutputVertexStream< Real , Dim > &vStream , &pStream , LevelSetExtractionParameters meParams ):
      +
    • Poisson::Implicit< Real , Dim , FEMSig >::Implicit( InputSampleStream< Real , Dim > &sStream , SolutionParameters< Real > sParams ):
      +This constructor creates a Poisson reconstruction object from an input sample stream (sStream) and a description of the reconstruction parameters (sParams) desribing the depth, number of samples per node, etc. (Reconstructors.h, line 229). This object derives from Implicit< Real , Dim , FEMSig >. +
    • void Implicit< Real , Dim , FEMSig >::extractLevelSet( OutputVertexStream< Real , Dim > &vStream , &pStream , LevelSetExtractionParameters meParams ):
      This member function takes references to the output vertex and polygon streams (vStream and pStream) and parameters for level-set extraction (meParams) and computes the extracted triangle/polygon mesh, writing its vertices and faces into the corresponding output streams as they are generated (Reconstructors.h, line 98).
    Code walk-through:
    From 1943704ee7c7a04384ca820f87cdcb1eed66f54d Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Sun, 8 Oct 2023 22:06:11 -0400 Subject: [PATCH 14/86] Version 15.02 --- README.md | 32 +++++++++++-------- Src/AdaptiveTreeVisualization.cpp | 2 +- Src/EDTInHeat.cpp | 2 +- Src/ImageStitching.cpp | 2 +- Src/PointInterpolant.cpp | 2 +- Src/PoissonRecon.cpp | 2 +- Src/PoissonReconServer.cpp | 2 +- Src/PreProcessor.h | 2 +- Src/Reconstruction.example.cpp | 53 ++++++++++++++++--------------- Src/Reconstructors.h | 23 +++++++------- Src/SSDRecon.cpp | 2 +- Src/SurfaceTrimmer.cpp | 2 +- 12 files changed, 67 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 1527e8f2..93e5503d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 15.01)

    +

    Adaptive Multigrid Solvers (Version 15.02)

    links compilation @@ -29,11 +29,12 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
    Executables: -Win64
    +Win64
    Source Code: -ZIP GitHub
    +ZIP GitHub
    Older Versions: -V14.02, +V15.01, +V15.00, V14.02, V14.01, V14.00, @@ -947,18 +948,18 @@ This method resets the stream to the start (necessary because the reconstruction
  • bool base_read( Point< Real , Dim > &p , Point< Real , Dim > &n ):
    This method tries to read the next pair of positions/normals from the stream, returning true if the read was successful and false if the read failed (i.e. the end of the stream was reached). The class Point< Real , Dim > represents a point in Dim-dimensional space, can be accessed like an array (i.e. overloads the bracked operator) and supports algebraic manipulation like addition and scalar multiplication. -
  • Output vertex stream: This class derives from the OutputVertexStream< Real , Dim > class. -The base class has one pure virtual method that needs to be over-ridden: -
      -
    • void base_write( Point< Real , Dim > p , Point< Real , Dim > g , Real w ):
      -This method writes the information for the next vertx into the stream. The data includes the position of the vertex, p, as well as the gradient, g, and density weight, w if the extraction code is asked to compute those. -
  • Output polygon stream: This class derives from the OutputPolygonStream class. The base class has one pure virtual method that needs to be over-ridden:
    • void base_write( const std::vector< node_index_type > &polygon ):
      This method writes the information for the next polygon into the stream, with the polygon represented as a std::vector of integral indices. (The type node_index_type is an unsigned int if the BIG_DATA macro is not defined an unsigned long long if it is.)
    +
  • Output vertex stream: This class derives from the OutputVertexStream< Real , Dim > class. +The base class has one pure virtual method that needs to be over-ridden: +
      +
    • void base_write( Point< Real , Dim > p , Point< Real , Dim > g , Real w ):
      +This method writes the information for the next vertx into the stream. The data includes the position of the vertex, p, as well as the gradient, g, and density weight, w if the extraction code is asked to compute those. +
    The reconstructed surface is then computed in two steps:
      @@ -971,9 +972,9 @@ This member function takes references to the output vertex and polygon streams (
        These steps can be found in the Reconstruction.example.cpp code.
          -
        • An input sample stream generating a specified number of random points on the surface of the sphere is defined in lines 78-115 and constructed in line 307. -
        • An output vertex stream that pushes just the position information to an std::vector of Reals is desfined in lines 182-192 and constructed in line 318. -
        • An output polygon stream that pushes the polygon to an std::vector of std::vector< int >s is defined in lines 164-179 and constructed in line 317. +
        • An input sample stream generating a specified number of random points on the surface of the sphere is defined in lines 78-115 and constructed in line 301. +
        • An output polygon stream that pushes the polygon to an std::vector of std::vector< int >s is defined in lines 164-179 and constructed in line 311. +
        • An output vertex stream that pushes just the position information to an std::vector of Reals is desfined in lines 182-192 and constructed in line 312.
        • The reconstructor is constructed in line 310.
        • The level-set extraction is performed on line 321.
        @@ -1428,6 +1429,11 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
      • Cleaned up interface into the reconstruction library. +Version 15.01: +
          +
        1. Changed Poisson and SSD to be classes for cleaner library interface in Reconstruction.example.cpp. +
        + diff --git a/Src/AdaptiveTreeVisualization.cpp b/Src/AdaptiveTreeVisualization.cpp index 056a7cf3..5fa2d815 100644 --- a/Src/AdaptiveTreeVisualization.cpp +++ b/Src/AdaptiveTreeVisualization.cpp @@ -473,7 +473,7 @@ int main( int argc , char* argv[] ) { printf( "**************************************************\n" ); printf( "**************************************************\n" ); - printf( "** Running Octree Visualization (Version %s) **\n" , VERSION ); + printf( "** Running Octree Visualization (Version %s) **\n" , ADAPTIVE_SOLVERS_VERSION ); printf( "**************************************************\n" ); printf( "**************************************************\n" ); if( !Threads.set ) printf( "Running with %d threads\n" , Threads.value ); diff --git a/Src/EDTInHeat.cpp b/Src/EDTInHeat.cpp index b725b409..be3d0ef1 100644 --- a/Src/EDTInHeat.cpp +++ b/Src/EDTInHeat.cpp @@ -196,7 +196,7 @@ void _Execute( int argc , char* argv[] ) { std::cout << "*****************************************" << std::endl; std::cout << "*****************************************" << std::endl; - std::cout << "** Running EDT in Heat (Version " << VERSION ") **" << std::endl; + std::cout << "** Running EDT in Heat (Version " << ADAPTIVE_SOLVERS_VERSION ") **" << std::endl; std::cout << "*****************************************" << std::endl; std::cout << "*****************************************" << std::endl; if( !Threads.set ) std::cout << "Running with " << Threads.value << " threads" << std::endl; diff --git a/Src/ImageStitching.cpp b/Src/ImageStitching.cpp index 5823d9a8..92ac9297 100644 --- a/Src/ImageStitching.cpp +++ b/Src/ImageStitching.cpp @@ -518,7 +518,7 @@ int main( int argc , char* argv[] ) { printf( "*********************************************\n" ); printf( "*********************************************\n" ); - printf( "** Running Image Stitching (Version %s) **\n" , VERSION ); + printf( "** Running Image Stitching (Version %s) **\n" , ADAPTIVE_SOLVERS_VERSION ); printf( "*********************************************\n" ); printf( "*********************************************\n" ); if( !Threads.set ) printf( "Running with %d threads\n" , Threads.value ); diff --git a/Src/PointInterpolant.cpp b/Src/PointInterpolant.cpp index 422ba240..c90edc06 100644 --- a/Src/PointInterpolant.cpp +++ b/Src/PointInterpolant.cpp @@ -544,7 +544,7 @@ void Execute( UIntPack< FEMSigs ... > ) { std::cout << "***********************************************" << std::endl; std::cout << "***********************************************" << std::endl; - std::cout << "** Running Point Interpolant (Version " << VERSION << ") **" << std::endl; + std::cout << "** Running Point Interpolant (Version " << ADAPTIVE_SOLVERS_VERSION << ") **" << std::endl; std::cout << "***********************************************" << std::endl; std::cout << "***********************************************" << std::endl; if( !Threads.set ) std::cout << "Running with " << Threads.value << " threads" << std::endl; diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index 5b4c2a56..c2c89917 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -292,7 +292,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) { std::cout << "*************************************************************" << std::endl; std::cout << "*************************************************************" << std::endl; - std::cout << "** Running Screened Poisson Reconstruction (Version " << VERSION << ") **" << std::endl; + std::cout << "** Running Screened Poisson Reconstruction (Version " << ADAPTIVE_SOLVERS_VERSION << ") **" << std::endl; std::cout << "*************************************************************" << std::endl; std::cout << "*************************************************************" << std::endl; if( !Threads.set ) std::cout << "Running with " << Threads.value << " threads" << std::endl; diff --git a/Src/PoissonReconServer.cpp b/Src/PoissonReconServer.cpp index a2e8e870..8c9d0417 100644 --- a/Src/PoissonReconServer.cpp +++ b/Src/PoissonReconServer.cpp @@ -351,7 +351,7 @@ int main( int argc , char* argv[] ) { std::cout << "***********************************************************" << std::endl; std::cout << "***********************************************************" << std::endl; - std::cout << "** Running Poisson Reconstruction Server (Version " << VERSION << ") **" << std::endl; + std::cout << "** Running Poisson Reconstruction Server (Version " << ADAPTIVE_SOLVERS_VERSION << ") **" << std::endl; std::cout << "***********************************************************" << std::endl; std::cout << "***********************************************************" << std::endl; } diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 08ed2851..4dbb0694 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -45,7 +45,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define VERSION "15.01" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "15.02" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file diff --git a/Src/Reconstruction.example.cpp b/Src/Reconstruction.example.cpp index dd8de2d5..f3c4b63b 100644 --- a/Src/Reconstruction.example.cpp +++ b/Src/Reconstruction.example.cpp @@ -241,34 +241,33 @@ void WritePly( std::string fileName , size_t vNum , const Real *vCoordinates , c } } -template< typename Real , unsigned int Dim , unsigned int FEMSig , bool SSD , bool UseColor > +template +< + typename Real , // Arithmetic type (float or double) + unsigned int Dim , // Dimensionality of the reconstruction (=3) + typename ReconType , // Reconstructor type (Reconstructor::Poisson or Reconstructctor::Poisson) + bool UseColor // Should could be reconstructed as well? +> void Execute( void ) { + // Finite-elements signature + static const unsigned int FEMSig = FEMDegreeAndBType< ReconType::DefaultFEMDegree , ReconType::DefaultFEMBoundary >::Signature; + // Parameters for performing the reconstruction - typename std::conditional - < - SSD , - typename Reconstructor:: SSD::SolutionParameters< Real > , - typename Reconstructor::Poisson::SolutionParameters< Real > - >::type solverParams; + typename ReconType::template SolutionParameters< Real > solverParams; solverParams.verbose = Verbose.set; solverParams.depth = (unsigned int)Depth.value; // Parameters for exracting the level-set surface Reconstructor::LevelSetExtractionParameters extractionParams; - extractionParams.linearFit = SSD; // Since the SSD solution approximates a TSDF, linear fitting works well + extractionParams.linearFit = SSDReconstruction.set; // Since the SSD solution approximates a TSDF, linear fitting works well extractionParams.verbose = Verbose.set; if constexpr( UseColor ) { // The type of the reconstructor - using Implicit = typename std::conditional - < - SSD , - Reconstructor:: SSD::Implicit< Real , Dim , FEMSig , RGBColor< Real > > , - Reconstructor::Poisson::Implicit< Real , Dim , FEMSig , RGBColor< Real > > - >::type; + using Implicit = typename ReconType::template Implicit< Real , Dim , FEMSig , RGBColor< Real > >; // A stream generating random points on the sphere with color SphereSampleWithColorStream< Real , Dim > sampleStream( SampleNum.value ); @@ -296,12 +295,7 @@ void Execute( void ) else { // The type of the reconstructor - using Implicit = typename std::conditional - < - SSD , - Reconstructor:: SSD::Implicit< Real , Dim , FEMSig > , - Reconstructor::Poisson::Implicit< Real , Dim , FEMSig > - >::type; + using Implicit = typename ReconType::template Implicit< Real , Dim , FEMSig >; // A stream generating random points on the sphere SphereSampleStream< Real , Dim > sampleStream( SampleNum.value ); @@ -326,8 +320,6 @@ void Execute( void ) int main( int argc , char* argv[] ) { - using namespace Reconstructor; - Timer timer; cmdLineParse( argc-1 , &argv[1] , params ); #ifdef _OPENMP @@ -341,14 +333,23 @@ int main( int argc , char* argv[] ) ShowUsage( argv[0] ); return 0; } + + if( Verbose.set ) + { + std::cout << "************************************************" << std::endl; + std::cout << "************************************************" << std::endl; + std::cout << "** Running SSD Reconstruction (Version " << ADAPTIVE_SOLVERS_VERSION << ") **" << std::endl; + std::cout << "************************************************" << std::endl; + std::cout << "************************************************" << std::endl; + } // Solve using single float precision, in dimension 3, w/ finite-elements of degree 2 for SSD and degree 1 for Poisson, and using Neumann boundaries if( SSDReconstruction.set ) - if( UseColor.set ) Execute< float , 3 , FEMDegreeAndBType< SSD::DefaultFEMDegree , SSD::DefaultFEMBoundary >::Signature , true , true >(); - else Execute< float , 3 , FEMDegreeAndBType< SSD::DefaultFEMDegree , SSD::DefaultFEMBoundary >::Signature , true , false >(); + if( UseColor.set ) Execute< float , 3 , Reconstructor:: SSD , true >(); + else Execute< float , 3 , Reconstructor:: SSD , false >(); else - if( UseColor.set ) Execute< float , 3 , FEMDegreeAndBType< Poisson::DefaultFEMDegree , Poisson::DefaultFEMBoundary >::Signature , false , true >(); - else Execute< float , 3 , FEMDegreeAndBType< Poisson::DefaultFEMDegree , Poisson::DefaultFEMBoundary >::Signature , false , false >(); + if( UseColor.set ) Execute< float , 3 , Reconstructor::Poisson , true >(); + else Execute< float , 3 , Reconstructor::Poisson , false >(); if( Verbose.set ) { diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h index 23df9330..bbcd726d 100644 --- a/Src/Reconstructors.h +++ b/Src/Reconstructors.h @@ -29,6 +29,7 @@ DAMAGE. #ifndef RECONSTRUCTORS_INCLUDED #define RECONSTRUCTORS_INCLUDED +#include "PreProcessor.h" #include "MyMiscellany.h" #include "DataStream.imp.h" #include "FEMTree.h" @@ -141,12 +142,12 @@ namespace Reconstructor } }; - namespace Poisson + struct Poisson { static const unsigned int NormalDegree = 2; // The order of the B-Spline used to splat in the normals for constructing the Laplacian constraints static const unsigned int DefaultFEMDegree = 1; // The default finite-element degree (has to be at least 1) static const BoundaryType DefaultFEMBoundary = BOUNDARY_NEUMANN; // The default finite-element boundary type {BOUNDARY_FREE, BOUNDARY_DIRICHLET, BOUNDARY_NEUMANN} - static const float WeightMultiplier = 2.f; // The default degree-to-point-weight scaling + inline static const float WeightMultiplier = 2.f; // The default degree-to-point-weight scaling template< unsigned int Dim , typename Real > struct ConstraintDual @@ -221,7 +222,7 @@ namespace Reconstructor template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct Implicit; template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > - void _Solve( UIntPack< FEMSigs... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh ); + static void _Solve( UIntPack< FEMSigs... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh ); template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct Implicit; @@ -244,14 +245,14 @@ namespace Reconstructor _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleWithDataStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params , envelopeMesh ); } }; - } + }; - namespace SSD + struct SSD { - static const unsigned int NormalDegree = 2; // The order of the B-Spline used to splat in the normals for constructing the Laplacian constraints - static const unsigned int DefaultFEMDegree = 2; // The default finite-element degree (has to be at least 2) - static const BoundaryType DefaultFEMBoundary = BOUNDARY_NEUMANN; // The default finite-element boundary type {BOUNDARY_FREE, BOUNDARY_DIRICHLET, BOUNDARY_NEUMANN} - static const double WeightMultipliers[] = { 5e+1f , 5e-4f , 1e-5f }; // The default weights for balancing the value, gradient, and laplacian energy terms + static const unsigned int NormalDegree = 2; // The order of the B-Spline used to splat in the normals for constructing the Laplacian constraints + static const unsigned int DefaultFEMDegree = 2; // The default finite-element degree (has to be at least 2) + static const BoundaryType DefaultFEMBoundary = BOUNDARY_NEUMANN; // The default finite-element boundary type {BOUNDARY_FREE, BOUNDARY_DIRICHLET, BOUNDARY_NEUMANN} + inline static const double WeightMultipliers[] = { 5e+1f , 5e-4f , 1e-5f }; // The default weights for balancing the value, gradient, and laplacian energy terms template< unsigned int Dim , typename ... > struct ConstraintDual; template< unsigned int Dim , typename ... > struct SystemDual; @@ -385,7 +386,7 @@ namespace Reconstructor template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct Implicit; template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > - void _Solve( UIntPack< FEMSigs... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params ); + static void _Solve( UIntPack< FEMSigs... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params ); template< typename Real , unsigned int Dim , unsigned int FEMSig > struct Implicit< Real , Dim , FEMSig > : public Reconstructor::Implicit< Real , Dim , FEMSig > @@ -406,7 +407,7 @@ namespace Reconstructor _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleWithDataStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params ); } }; - } + }; template< class Real , unsigned int Dim > XForm< Real , Dim+1 > GetBoundingBoxXForm( Point< Real , Dim > min , Point< Real , Dim > max , Real scaleFactor ) diff --git a/Src/SSDRecon.cpp b/Src/SSDRecon.cpp index 4a1d97f0..c002f3b9 100644 --- a/Src/SSDRecon.cpp +++ b/Src/SSDRecon.cpp @@ -288,7 +288,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) { std::cout << "************************************************" << std::endl; std::cout << "************************************************" << std::endl; - std::cout << "** Running SSD Reconstruction (Version " << VERSION << ") **" << std::endl; + std::cout << "** Running SSD Reconstruction (Version " << ADAPTIVE_SOLVERS_VERSION << ") **" << std::endl; std::cout << "************************************************" << std::endl; std::cout << "************************************************" << std::endl; if( !Threads.set ) std::cout << "Running with " << Threads.value << " threads" << std::endl; diff --git a/Src/SurfaceTrimmer.cpp b/Src/SurfaceTrimmer.cpp index 69d89c3a..66030ab9 100644 --- a/Src/SurfaceTrimmer.cpp +++ b/Src/SurfaceTrimmer.cpp @@ -441,7 +441,7 @@ int Execute( AuxDataFactories ... auxDataFactories ) { std::cout << "*********************************************" << std::endl; std::cout << "*********************************************" << std::endl; - std::cout << "** Running Surface Trimmer (Version " << VERSION << ") **" << std::endl; + std::cout << "** Running Surface Trimmer (Version " << ADAPTIVE_SOLVERS_VERSION << ") **" << std::endl; std::cout << "*********************************************" << std::endl; std::cout << "*********************************************" << std::endl; } From 297d699e9a9c76c3f8fee268f4308d3bf7ccef86 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Mon, 9 Oct 2023 15:01:54 -0400 Subject: [PATCH 15/86] Version 15.03 --- Src/PreProcessor.h | 2 +- Src/Reconstruction.example.cpp | 12 ++++++------ Src/Reconstructors.h | 8 ++++++-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 4dbb0694..3a5fbfef 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -45,7 +45,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "15.02" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "15.03" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file diff --git a/Src/Reconstruction.example.cpp b/Src/Reconstruction.example.cpp index f3c4b63b..2a43439d 100644 --- a/Src/Reconstruction.example.cpp +++ b/Src/Reconstruction.example.cpp @@ -42,7 +42,7 @@ cmdLineParameter< char* > Out( "out" ); cmdLineReadable SSDReconstruction( "ssd" ) , UseColor( "color" ) , Verbose( "verbose" ); cmdLineParameter< int > Depth( "depth" , 8 ) , SampleNum( "samples" , 100000 ); -cmdLineReadable* params[] = { &Out , &SSDReconstruction , &UseColor , &Verbose , &Depth , &SampleNum , NULL }; +cmdLineReadable* params[] = { &Out , &SSDReconstruction , &UseColor , &Verbose , &Depth , &SampleNum , nullptr }; void ShowUsage( char* ex ) { @@ -233,10 +233,10 @@ void WritePly( std::string fileName , size_t vNum , const Real *vCoordinates , c if( rgbCoordinates ) file << " " << ColorChannel( rgbCoordinates[3*i+0] ) << " " << ColorChannel( rgbCoordinates[3*i+1] ) << " " << ColorChannel( rgbCoordinates[3*i+2] ); file << std::endl; } - for( size_t i=0 ; i0 ) { + // Assuming the transformation is rigid so that the (max) scale can be pulled from the Frobenius norm Real maxScale = 0; - for( unsigned int i=0 ; i( maxScale , (Real)1./modelToUnitCube(i,i) ); + for( unsigned int i=0 ; i( 0. , log( maxScale/params.width )/log(2.) ) ); } if( params.solveDepth>params.depth ) @@ -985,8 +987,10 @@ namespace Reconstructor if( params.width>0 ) { + // Assuming the transformation is rigid so that the (max) scale can be pulled from the Frobenius norm Real maxScale = 0; - for( unsigned int i=0 ; i( maxScale , (Real)1./modelToUnitCube(i,i) ); + for( unsigned int i=0 ; i( 0. , log( maxScale/params.width )/log(2.) ) ); } if( params.solveDepth>params.depth ) From a3ab3435e64987d3518d2b0a68722193bc3d17a1 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Mon, 9 Oct 2023 15:02:55 -0400 Subject: [PATCH 16/86] Update README.md --- README.md | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 93e5503d..dc6a76d8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

        Adaptive Multigrid Solvers (Version 15.02)

        +

        Adaptive Multigrid Solvers (Version 15.03)

        links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
        Executables: -Win64
        +Win64
        Source Code: -ZIP GitHub
        +ZIP GitHub
        Older Versions: +V15.02, V15.01, V15.00, V14.02, @@ -972,11 +973,12 @@ This member function takes references to the output vertex and polygon streams (
          These steps can be found in the Reconstruction.example.cpp code.
            +
          • The finite-elements signature is created in line 254.
          • An input sample stream generating a specified number of random points on the surface of the sphere is defined in lines 78-115 and constructed in line 301.
          • An output polygon stream that pushes the polygon to an std::vector of std::vector< int >s is defined in lines 164-179 and constructed in line 311.
          • An output vertex stream that pushes just the position information to an std::vector of Reals is desfined in lines 182-192 and constructed in line 312. -
          • The reconstructor is constructed in line 310. -
          • The level-set extraction is performed on line 321. +
          • The reconstructor is constructed in line 304. +
          • The level-set extraction is performed on line 315.
          Note that a similar approach can be used to perform the Smoothed Signed Distance reconstruction (line 302). The approach also supports reconstruction of meshes with auxiliary information like color (lines 263-295), with the only constraint that the auxiliary data type supports the computation affine combinations (e.g. the RGBColor type defined in lines 60-75).
        @@ -1429,11 +1431,16 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
      • Cleaned up interface into the reconstruction library. -Version 15.01: +Version 15.02:
        1. Changed Poisson and SSD to be classes for cleaner library interface in Reconstruction.example.cpp.
        +Version 15.03: +
          +
        1. Fixed --width bug in estimating scale factor. +
        + @@ -1443,4 +1450,4 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
      • This work was genersouly supported by the National Science Foundation (NSF) grant numbers 0746039 and 1422325.
      • We are extremely grateful to the EPFL Scanning 3D Statues from Photos course, the Stanford 3D Scanning Repository, and Resonai for sharing their data.
      • This work was carried out at the Advanced Research Computing at Hopkins (ARCH) core facility, which is supported by the National Science Foundation (NSF) grant number 1920103. -
      \ No newline at end of file +
    From aff7459cc2c1d95aedc151a8016344a86ab88b74 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Mon, 9 Oct 2023 17:06:41 -0400 Subject: [PATCH 17/86] Update Reconstruction.example.cpp --- Src/Reconstruction.example.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Src/Reconstruction.example.cpp b/Src/Reconstruction.example.cpp index 2a43439d..d6babb3c 100644 --- a/Src/Reconstruction.example.cpp +++ b/Src/Reconstruction.example.cpp @@ -245,8 +245,8 @@ template < typename Real , // Arithmetic type (float or double) unsigned int Dim , // Dimensionality of the reconstruction (=3) - typename ReconType , // Reconstructor type (Reconstructor::Poisson or Reconstructctor::Poisson) - bool UseColor // Should could be reconstructed as well? + typename ReconType , // Reconstructor type (Reconstructor::Poisson or Reconstructor::SSD) + bool UseColor // Should color be reconstructed as well? > void Execute( void ) { From d4e87157cf9b2152cd6a46886c8d36bda4acba85 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Tue, 31 Oct 2023 10:44:21 -0400 Subject: [PATCH 18/86] exit with failure --- Src/Array.h | 2 +- Src/MyMiscellany.h | 4 ++-- Src/Socket.h | 12 ++---------- Src/Socket.inl | 12 +++--------- 4 files changed, 8 insertions(+), 22 deletions(-) diff --git a/Src/Array.h b/Src/Array.h index 95d71c4e..6a0cca50 100644 --- a/Src/Array.h +++ b/Src/Array.h @@ -37,7 +37,7 @@ DAMAGE. #ifdef _WIN32 #define ASSERT( x ) { if( !( x ) ) _asm{ int 0x03 } } #else // !_WIN32 -#define ASSERT( x ) { if( !( x ) ) exit(0); } +#define ASSERT( x ) { if( !( x ) ) exit( EXIT_FAILURE ); } #endif // _WIN32 #endif // _WIN64 diff --git a/Src/MyMiscellany.h b/Src/MyMiscellany.h index 17170104..0b83fa97 100644 --- a/Src/MyMiscellany.h +++ b/Src/MyMiscellany.h @@ -195,7 +195,7 @@ namespace MKExceptions void ErrorOut( const char *fileName , int line , const char *functionName , const char *format , Args ... args ) { std::cerr << MakeMessageString( "[ERROR]" , fileName , line , functionName , format , args ... ) << std::endl; - exit( 0 ); + exit( EXIT_FAILURE ); } } #ifndef WARN @@ -324,7 +324,7 @@ inline void SignalHandler( int signal ) { printf( "Signal: %d\n" , signal ); StackTracer::Trace(); - exit( 0 ); + exit( EXIT_FAILURE ); }; diff --git a/Src/Socket.h b/Src/Socket.h index 481297ee..0b25b671 100644 --- a/Src/Socket.h +++ b/Src/Socket.h @@ -88,22 +88,14 @@ template< class C > int socket_receive( Socket& s , Array< C > destination , size_t len ) { if( len>destination.maximum()*sizeof( C ) ) - { - fprintf( stderr , "Size of socket_receive exceeds destination maximum: %zd > %zd\n" , len , destination.maximum()*sizeof( C ) ); - ASSERT( 0 ); - exit( 0 ); - } + ERROR_OUT( "Size of socket_receive exceeds destination maximum: " , len , " > " , destination.maximum()*sizeof( C ) ); return socket_receive( s , (char*)&destination[0] , len ); } template< class C > int socket_send( Socket s , ConstArray< C > source , size_t len ) { if( len>source.maximum()*sizeof( C ) ) - { - fprintf( stderr , "Size of socket_send exceeds source maximum: %zd > %zd\n" , len , source.maximum()*sizeof( C ) ); - ASSERT( 0 ); - exit( 0 ); - } + ERROR_OUT( "Size of socket_send exceeds source maximum: " , len , " > " , source.maximum()*sizeof( C ) ); return socket_send( s , (char*)&source[0] , len ); } #endif // ARRAY_DEBUG diff --git a/Src/Socket.inl b/Src/Socket.inl index aee55835..09c17c58 100644 --- a/Src/Socket.inl +++ b/Src/Socket.inl @@ -86,7 +86,7 @@ void ReceiveOnSocket( Socket& s , Pointer( C ) data , size_t dataSize , const ch va_end( args ); fprintf( stderr , "\n" ); } - exit(0); + exit( EXIT_FAILURE ); } rec+=tmp; } @@ -99,10 +99,7 @@ void SendOnSocket( Socket& s , ConstPointer( C ) data , size_t dataSize , const if( dataSize>data.maximum()*sizeof( C ) ) ERROR_OUT( "Size of socket write exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); #endif // ARRAY_DEBUG if( socket_send( s , ( ConstPointer( char ) )data , dataSize )<0 ) - { - fprintf( stderr , "socket_send to client failed: %s\n" , LastSocketError()); - exit(0); - } + ERROR_OUT( "socket_send to client failed: " , LastSocketError() ); } template @@ -112,10 +109,7 @@ void SendOnSocket( Socket& s , Pointer( C ) data , size_t dataSize , const char* if( dataSize>data.maximum()*sizeof( C ) ) ERROR_OUT( "Size of socket write exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); #endif // ARRAY_DEBUG if( socket_send( s , ( ConstPointer( char ) )data , dataSize )<0 ) - { - fprintf( stderr , "socket_send to client failed: %s\n" , LastSocketError()); - exit(0); - } + ERROR_OUT( "socket_send to client failed: " , LastSocketError() ); } inline bool GetHostEndpointAddress( EndpointAddress* address , const char* prefix ) From b858ece5054425fc3ba271f022272d3ae8b6974e Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Tue, 5 Dec 2023 00:23:36 -0500 Subject: [PATCH 19/86] Version 15.10 Added support for iso-curve extraction from quadtrees --- README.md | 12 ++- Src/AdaptiveTreeVisualization.cpp | 11 +- Src/FEMTree.LevelSet.2D.inl | 2 +- Src/Ply.h | 16 ++- Src/Ply.inl | 167 ++++++++++++++++++++++++++---- Src/PointInterpolant.cpp | 11 +- Src/PoissonRecon.client.inl | 12 +-- Src/PoissonRecon.cpp | 17 +-- Src/PreProcessor.h | 2 +- Src/Reconstruction.example.cpp | 2 +- Src/Reconstructors.h | 53 +++++++--- Src/Reconstructors.streams.h | 73 ++++++------- Src/SSDRecon.cpp | 17 +-- 13 files changed, 286 insertions(+), 109 deletions(-) diff --git a/README.md b/README.md index dc6a76d8..f26e85a1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 15.03)

    +

    Adaptive Multigrid Solvers (Version 15.10)

    links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
    Executables: -Win64
    +Win64
    Source Code: -ZIP GitHub
    +ZIP GitHub
    Older Versions: +V15.03, V15.02, V15.01, V15.00, @@ -1441,6 +1442,11 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • Fixed --width bug in estimating scale factor. +Version 15.10: +
      +
    1. Added iso-curve extraction support (for 2D reconstruction) +
    + diff --git a/Src/AdaptiveTreeVisualization.cpp b/Src/AdaptiveTreeVisualization.cpp index 5fa2d815..f0a1c484 100644 --- a/Src/AdaptiveTreeVisualization.cpp +++ b/Src/AdaptiveTreeVisualization.cpp @@ -398,7 +398,7 @@ void _Execute( const FEMTree< Dim , Real > *tree , XForm< Real , Dim+1 > modelTo } // Output the mesh - if constexpr( Dim==3 ) if( OutMesh.set ) + if constexpr( Dim==2 || Dim==3 ) if( OutMesh.set ) { double t = Time(); @@ -411,7 +411,7 @@ void _Execute( const FEMTree< Dim , Real > *tree , XForm< Real , Dim+1 > modelTo // A backing stream for the vertices Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , false , false , std::string( "v_" ) ); - Reconstructor::OutputInputPolygonStream polygonStream( false , true , std::string( "p_" ) ); + Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( false , true , std::string( "f_" ) ); { // The wrapper converting native to output types @@ -419,15 +419,16 @@ void _Execute( const FEMTree< Dim , Real > *tree , XForm< Real , Dim+1 > modelTo Reconstructor::TransformedOutputVertexStream< Real , Dim > __vertexStream( modelToUnitCube.inverse() , _vertexStream ); // Extract the mesh - LevelSetExtractor< Real , Dim >::Extract( IsotropicUIntPack< Dim , FEMSig >() , UIntPack< 0 >() , *tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , coefficients , IsoValue.value , IsoSlabDepth.value , IsoSlabStart.value , IsoSlabEnd.value , __vertexStream , polygonStream , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , FlipOrientation.set ); + if constexpr( Dim==3 ) LevelSetExtractor< Real , Dim >::Extract( IsotropicUIntPack< Dim , FEMSig >() , UIntPack< 0 >() , *tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , coefficients , IsoValue.value , IsoSlabDepth.value , IsoSlabStart.value , IsoSlabEnd.value , __vertexStream , faceStream , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , FlipOrientation.set ); + else if constexpr( Dim==2 ) LevelSetExtractor< Real , Dim >::Extract( IsotropicUIntPack< Dim , FEMSig >() , UIntPack< 0 >() , *tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , coefficients , IsoValue.value , __vertexStream , faceStream , NonLinearFit.set , false , FlipOrientation.set ); } if( Verbose.set ) printf( "Got level-set: %.2f(s)\n" , Time()-t ); - if( Verbose.set ) printf( "Vertices / Polygons: %llu / %llu\n" , (unsigned long long)vertexStream.size() , (unsigned long long)polygonStream.size() ); + if( Verbose.set ) printf( "Vertices / Faces: %llu / %llu\n" , (unsigned long long)vertexStream.size() , (unsigned long long)faceStream.size() ); // Write the mesh to a .ply file std::vector< std::string > noComments; - PLY::WritePolygons< Factory , node_index_type , Real , Dim >( OutMesh.value , factory , vertexStream.size() , polygonStream.size() , vertexStream , polygonStream , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); + PLY::Write< Factory , node_index_type , Real , Dim >( OutMesh.value , factory , vertexStream.size() , faceStream.size() , vertexStream , faceStream , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); } } diff --git a/Src/FEMTree.LevelSet.2D.inl b/Src/FEMTree.LevelSet.2D.inl index a2278e9f..d1319889 100644 --- a/Src/FEMTree.LevelSet.2D.inl +++ b/Src/FEMTree.LevelSet.2D.inl @@ -1071,7 +1071,7 @@ public: { std::vector< SliceValues > sliceValues; - Stats stats = SetSliceValues< Data >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , tree.maxDepth() , densityWeights , data , coefficients , isoValue , vertexStream , zeroData , nonLinearFit , outputGradients , sliceValues , SetIsoEdgesFlag() ); + Stats stats = SetSliceValues( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , tree.maxDepth() , densityWeights , data , coefficients , isoValue , vertexStream , zeroData , nonLinearFit , outputGradients , sliceValues , SetIsoEdgesFlag() ); LevelSetExtraction::KeyGenerator< Dim > keyGenerator( tree.maxDepth() ); { double t = Time(); diff --git a/Src/Ply.h b/Src/Ply.h index 4818edf1..ece6acff 100644 --- a/Src/Ply.h +++ b/Src/Ply.h @@ -65,6 +65,14 @@ namespace PLY // Converts from C-type to PLY name template< typename Integer > struct Traits{ static const std::string name; }; + // A structure representing a face + template< typename Index > + struct Edge + { + Index v1 , v2; + static PlyProperty Properties[]; + }; + // A structure representing a face template< typename Index , bool UseCharIndex=false > struct Face @@ -92,7 +100,10 @@ namespace PLY // PLY write mesh functionality template< typename VertexFactory , typename Index , class Real , int Dim , typename OutputIndex=int , bool UseCharIndex=false > - void WritePolygons( std::string fileName , const VertexFactory &vFactory , size_t vertexNum , size_t polygonNum , InputDataStream< typename VertexFactory::VertexType > &vertexStream , InputDataStream< std::vector< Index > > &polygonStream , int file_type , const std::vector< std::string >& comments ); + void Write( std::string fileName , const VertexFactory &vFactory , size_t vertexNum , size_t polygonNum , InputDataStream< typename VertexFactory::VertexType > &vertexStream , InputDataStream< std::vector< Index > > &polygonStream , int file_type , const std::vector< std::string >& comments ); + + template< typename VertexFactory , typename Index , class Real , int Dim , typename OutputIndex=int > + void Write( std::string fileName , const VertexFactory &vFactory , size_t vertexNum , size_t edgeNum , InputDataStream< typename VertexFactory::VertexType > &vertexStream , InputDataStream< std::pair< Index , Index > > &edgeStream , int file_type , const std::vector< std::string >& comments ); template< typename VertexFactory , typename Index , bool UseCharIndex=false > void WritePolygons( std::string fileName , const VertexFactory &vFactory , const std::vector< typename VertexFactory::VertexType > &vertices , const std::vector< std::vector< Index > > &polygons , int file_type , const std::vector< std::string > &comments ); @@ -100,6 +111,9 @@ namespace PLY // PLY read mesh functionality template< typename VertexFactory , typename Index > void ReadPolygons( std::string fileName , const VertexFactory &vFactory , std::vector< typename VertexFactory::VertexType > &vertices , std::vector< std::vector< Index > >& polygons , int &file_type , std::vector< std::string > &comments , bool* readFlags=NULL ); + + template< typename VertexFactory , typename Index > + void ReadEdges( std::string fileName , const VertexFactory &vFactory , std::vector< typename VertexFactory::VertexType > &vertices , std::vector< std::pair< Index , Index > >& edges , int &file_type , std::vector< std::string > &comments , bool* readFlags=NULL ); } #include "Ply.inl" #endif // PLY_INCLUDED diff --git a/Src/Ply.inl b/Src/Ply.inl index a5a37171..fd44fd12 100644 --- a/Src/Ply.inl +++ b/Src/Ply.inl @@ -48,22 +48,19 @@ namespace PLY template<> const std::string Traits< long long >::name="long long"; template<> const std::string Traits< unsigned long long >::name="unsigned long long"; - template<> - PlyProperty Face< int , false >::Properties[] = { PlyProperty( "vertex_indices" , PLY_INT , PLY_INT , offsetof( Face , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( Face , nr_vertices ) ) }; - template<> - PlyProperty Face< unsigned int , false >::Properties[] = { PlyProperty( "vertex_indices" , PLY_UINT , PLY_UINT , offsetof( Face , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( Face , nr_vertices ) ) }; - template<> - PlyProperty Face< long long , false >::Properties[] = { PlyProperty( "vertex_indices" , PLY_LONGLONG , PLY_LONGLONG , offsetof( Face , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( Face , nr_vertices ) ) }; - template<> - PlyProperty Face< unsigned long long , false >::Properties[] = { PlyProperty( "vertex_indices" , PLY_ULONGLONG , PLY_ULONGLONG , offsetof( Face , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( Face , nr_vertices ) ) }; - template<> - PlyProperty Face< int , true >::Properties[] = { PlyProperty( "vertex_indices" , PLY_INT , PLY_INT , offsetof( Face , vertices ) , 1 , PLY_CHAR , PLY_CHAR , offsetof( Face , nr_vertices ) ) }; - template<> - PlyProperty Face< unsigned int , true >::Properties[] = { PlyProperty( "vertex_indices" , PLY_UINT , PLY_UINT , offsetof( Face , vertices ) , 1 , PLY_CHAR , PLY_CHAR , offsetof( Face , nr_vertices ) ) }; - template<> - PlyProperty Face< long long , true >::Properties[] = { PlyProperty( "vertex_indices" , PLY_LONGLONG , PLY_LONGLONG , offsetof( Face , vertices ) , 1 , PLY_CHAR , PLY_CHAR , offsetof( Face , nr_vertices ) ) }; - template<> - PlyProperty Face< unsigned long long , true >::Properties[] = { PlyProperty( "vertex_indices" , PLY_ULONGLONG , PLY_ULONGLONG , offsetof( Face , vertices ) , 1 , PLY_CHAR , PLY_CHAR , offsetof( Face , nr_vertices ) ) }; + template<> PlyProperty Edge< int >::Properties[] = { PlyProperty( "v1" , PLY_INT , PLY_INT , offsetof( Edge , v1 ) ) , PlyProperty( "v2" , PLY_INT , PLY_INT , offsetof( Edge , v2 ) ) }; + template<> PlyProperty Edge< unsigned int >::Properties[] = { PlyProperty( "v1" , PLY_UINT , PLY_UINT , offsetof( Edge , v1 ) ) , PlyProperty( "v2" , PLY_UINT , PLY_UINT , offsetof( Edge , v2 ) ) }; + template<> PlyProperty Edge< long long >::Properties[] = { PlyProperty( "v1" , PLY_LONGLONG , PLY_LONGLONG , offsetof( Edge , v1 ) ) , PlyProperty( "v2" , PLY_LONGLONG , PLY_LONGLONG , offsetof( Edge , v2 ) ) }; + template<> PlyProperty Edge< unsigned long long >::Properties[] = { PlyProperty( "v1" , PLY_ULONGLONG , PLY_ULONGLONG , offsetof( Edge , v1 ) ) , PlyProperty( "v2" , PLY_ULONGLONG , PLY_ULONGLONG , offsetof( Edge , v2 ) ) }; + + template<> PlyProperty Face< int , false >::Properties[] = { PlyProperty( "vertex_indices" , PLY_INT , PLY_INT , offsetof( Face , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( Face , nr_vertices ) ) }; + template<> PlyProperty Face< unsigned int , false >::Properties[] = { PlyProperty( "vertex_indices" , PLY_UINT , PLY_UINT , offsetof( Face , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( Face , nr_vertices ) ) }; + template<> PlyProperty Face< long long , false >::Properties[] = { PlyProperty( "vertex_indices" , PLY_LONGLONG , PLY_LONGLONG , offsetof( Face , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( Face , nr_vertices ) ) }; + template<> PlyProperty Face< unsigned long long , false >::Properties[] = { PlyProperty( "vertex_indices" , PLY_ULONGLONG , PLY_ULONGLONG , offsetof( Face , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( Face , nr_vertices ) ) }; + template<> PlyProperty Face< int , true >::Properties[] = { PlyProperty( "vertex_indices" , PLY_INT , PLY_INT , offsetof( Face , vertices ) , 1 , PLY_CHAR , PLY_CHAR , offsetof( Face , nr_vertices ) ) }; + template<> PlyProperty Face< unsigned int , true >::Properties[] = { PlyProperty( "vertex_indices" , PLY_UINT , PLY_UINT , offsetof( Face , vertices ) , 1 , PLY_CHAR , PLY_CHAR , offsetof( Face , nr_vertices ) ) }; + template<> PlyProperty Face< long long , true >::Properties[] = { PlyProperty( "vertex_indices" , PLY_LONGLONG , PLY_LONGLONG , offsetof( Face , vertices ) , 1 , PLY_CHAR , PLY_CHAR , offsetof( Face , nr_vertices ) ) }; + template<> PlyProperty Face< unsigned long long , true >::Properties[] = { PlyProperty( "vertex_indices" , PLY_ULONGLONG , PLY_ULONGLONG , offsetof( Face , vertices ) , 1 , PLY_CHAR , PLY_CHAR , offsetof( Face , nr_vertices ) ) }; // Read inline PlyFile *ReadHeader( std::string fileName , int &fileType , std::vector< std::tuple< std::string , size_t , std::vector< PlyProperty > > > &elems , std::vector< std::string > &comments ) @@ -197,6 +194,64 @@ namespace PLY return ReadVertexHeader( fileName , properties , vNum ); } + template< typename VertexFactory , typename Index > + void ReadEdges( std::string fileName , const VertexFactory &vFactory , std::vector< typename VertexFactory::VertexType > &vertices , std::vector< std::pair< Index , Index > > &edges , int &file_type , std::vector< std::string > &comments , bool *readFlags ) + { + std::vector< std::string > elist; + float version; + + PlyFile *ply = PlyFile::Read( fileName , elist , file_type , version ); + if( !ply ) ERROR_OUT( "Could not create ply file for reading: " , fileName ); + + comments.reserve( comments.size() + ply->comments.size() ); + for( int i=0 ; icomments.size() ; i++ ) comments.push_back( ply->comments[i] ); + + for( int i=0 ; i plist = ply->get_element_description( elem_name , num_elems ); + if( !plist.size() ) ERROR_OUT( "Could not read element properties: " , elem_name ); + if( elem_name=="vertex" ) + { + for( unsigned int i=0 ; iget_property( elem_name , &prop ); + if( readFlags ) readFlags[i] = (hasProperty!=0); + } + vertices.resize( num_elems , vFactory() ); + Pointer( char ) buffer = NewPointer< char >( vFactory.bufferSize() ); + for( size_t j=0 ; jget_element( (void*)&vertices[j] ); + else + { + ply->get_element( PointerAddress( buffer ) ); + vFactory.fromBuffer( buffer , vertices[j] ); + } + } + DeletePointer( buffer ); + } + else if( elem_name=="edge" ) + { + ply->get_property( elem_name , &Edge< Index >::Properties[0] ); + ply->get_property( elem_name , &Edge< Index >::Properties[1] ); + edges.resize( num_elems ); + for( size_t j=0 ; j ply_edge; + ply->get_element( (void *)&ply_edge ); + edges[j].first = ply_edge.v1; + edges[j].second = ply_edge.v2; + } // for, read edges + } // if face + else ply->get_other_element( elem_name , num_elems ); + } // for each type of element + + delete ply; + } + template< typename VertexFactory , typename Index > void ReadPolygons( std::string fileName , const VertexFactory &vFactory , std::vector< typename VertexFactory::VertexType > &vertices , std::vector< std::vector< Index > > &polygons , int &file_type , std::vector< std::string > &comments , bool *readFlags ) { @@ -321,13 +376,13 @@ namespace PLY } template< typename VertexFactory , typename Index , class Real , int Dim , typename OutputIndex , bool UseCharIndex > - void WritePolygons( std::string fileName , const VertexFactory &vFactory , size_t vertexNum , size_t polygonNum , InputDataStream< typename VertexFactory::VertexType > &vertexStream , InputDataStream< std::vector< Index > > &polygonStream , int file_type , const std::vector< std::string > &comments ) + void Write( std::string fileName , const VertexFactory &vFactory , size_t vertexNum , size_t polygonNum , InputDataStream< typename VertexFactory::VertexType > &vertexStream , InputDataStream< std::vector< Index > > &polygonStream , int file_type , const std::vector< std::string > &comments ) { if( vertexNum>(size_t)std::numeric_limits< OutputIndex >::max() ) { if( std::is_same< Index , OutputIndex >::value ) ERROR_OUT( "more vertices than can be represented using " , Traits< Index >::name ); WARN( "more vertices than can be represented using " , Traits< OutputIndex >::name , " using " , Traits< Index >::name , " instead" ); - return WritePolygons< VertexFactory , Index , Real , Dim , Index >( fileName , vFactory , vertexNum , polygonNum , vertexStream , polygonStream , file_type , comments ); + return Write< VertexFactory , Index , Real , Dim , Index >( fileName , vFactory , vertexNum , polygonNum , vertexStream , polygonStream , file_type , comments ); } float version; std::vector< std::string > elem_names = { std::string( "vertex" ) , std::string( "face" ) }; @@ -395,6 +450,82 @@ namespace PLY } // for, write faces + delete ply; + } + + template< typename VertexFactory , typename Index , class Real , int Dim , typename OutputIndex > + void Write( std::string fileName , const VertexFactory &vFactory , size_t vertexNum , size_t edgeNum , InputDataStream< typename VertexFactory::VertexType > &vertexStream , InputDataStream< std::pair< Index , Index > > &edgeStream , int file_type , const std::vector< std::string > &comments ) + { + if( vertexNum>(size_t)std::numeric_limits< OutputIndex >::max() ) + { + if( std::is_same< Index , OutputIndex >::value ) ERROR_OUT( "more vertices than can be represented using " , Traits< Index >::name ); + WARN( "more vertices than can be represented using " , Traits< OutputIndex >::name , " using " , Traits< Index >::name , " instead" ); + return Write< VertexFactory , Index , Real , Dim , Index >( fileName , vFactory , vertexNum , edgeNum , vertexStream , edgeStream , file_type , comments ); + } + float version; + std::vector< std::string > elem_names = { std::string( "vertex" ) , std::string( "edge" ) }; + PlyFile *ply = PlyFile::Write( fileName , elem_names , file_type , version ); + if( !ply ) ERROR_OUT( "Could not create ply file for writing: " , fileName ); + + vertexStream.reset(); + edgeStream.reset(); + + // + // describe vertex and face properties + // + ply->element_count( "vertex" , vertexNum ); + for( unsigned int i=0 ; idescribe_property( "vertex" , &prop ); + } + ply->element_count( "edge" , edgeNum ); + ply->describe_property( "edge" , &Edge< OutputIndex >::Properties[0] ); + ply->describe_property( "edge" , &Edge< OutputIndex >::Properties[1] ); + + // Write in the comments + for( int i=0 ; iput_comment( comments[i] ); + ply->header_complete(); + + // write vertices + ply->put_element_setup( "vertex" ); + if( vFactory.isStaticallyAllocated() ) + { + for( size_t i=0; iput_element( (void *)&vertex ); + } + } + else + { + Pointer( char ) buffer = NewPointer< char >( vFactory.bufferSize() ); + for( size_t i=0; iput_element( PointerAddress( buffer ) ); + } + DeletePointer( buffer ); + } + + // write edges + std::pair< Index , Index > edge; + ply->put_element_setup( "edge" ); + for( size_t i=0 ; i ply_edge; + if( !edgeStream.read( edge ) ) ERROR_OUT( "Failed to read edge " , i , " / " , edgeNum ); + ply_edge.v1 = (Index)edge.first; + ply_edge.v2 = (Index)edge.second; + ply->put_element( (void *)&ply_edge ); + } // for, write edges + delete ply; } } diff --git a/Src/PointInterpolant.cpp b/Src/PointInterpolant.cpp index c90edc06..1c36c26f 100644 --- a/Src/PointInterpolant.cpp +++ b/Src/PointInterpolant.cpp @@ -364,7 +364,7 @@ void ExtractLevelSet // A backing stream for the vertices Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , false , false , std::string( "v_" ) ); - Reconstructor::OutputInputPolygonStream polygonStream( false , true , std::string( "p_" ) ); + Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( false , true , std::string( "f_" ) ); typename LevelSetExtractor< Real , Dim >::Stats stats; { @@ -373,20 +373,19 @@ void ExtractLevelSet Reconstructor::TransformedOutputVertexStream< Real , Dim > __vertexStream( unitCubeToModel , _vertexStream ); // Extract the mesh - stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< 0 >() , tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , solution , isoValue , __vertexStream , polygonStream , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , false ); + stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< 0 >() , tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , solution , isoValue , __vertexStream , faceStream , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , false ); } if( Verbose.set ) { - std::cout << "Vertices / Polygons: " << vertexStream.size() << " / " << polygonStream.size() << std::endl; + std::cout << "Vertices / Faces: " << vertexStream.size() << " / " << faceStream.size() << std::endl; std::cout << stats.toString() << std::endl; - if( PolygonMesh.set ) std::cout << "# Got polygons: " << profiler << std::endl; - else std::cout << "# Got triangles: " << profiler << std::endl; + std::cout << "# Got faces: " << profiler << std::endl; } // Write the mesh to a .ply file std::vector< std::string > noComments; - PLY::WritePolygons< Factory , node_index_type , Real , Dim >( Out.value , factory , vertexStream.size() , polygonStream.size() , vertexStream , polygonStream , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); + PLY::Write< Factory , node_index_type , Real , Dim >( Out.value , factory , vertexStream.size() , faceStream.size() , vertexStream , faceStream , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); } template< typename Real , unsigned int Dim > diff --git a/Src/PoissonRecon.client.inl b/Src/PoissonRecon.client.inl index 5b9cdb14..fee876cd 100644 --- a/Src/PoissonRecon.client.inl +++ b/Src/PoissonRecon.client.inl @@ -284,7 +284,7 @@ void RunClient( std::vector< Socket > &serverSockets , unsigned int sampleMS ) if( serverSocketStreams.size()>1 ) { Timer timer; - cacheFiles[i].ioBytes; + cacheFiles[i].ioBytes = 0; cacheFiles[i].reset(); client->_write( clientReconInfo , cacheFiles[i] , 5 ); delete client; @@ -1241,7 +1241,7 @@ void Client< Real , Dim , BType , Degree >::_writeMeshWithData( const ClientReco // A backing stream for the vertices Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , false , false , tempHeader + std::string( "v_" ) ); - Reconstructor::OutputInputPolygonStream polygonStream( false , true , tempHeader + std::string( "p_" ) ); + Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( false , true , tempHeader + std::string( "f_" ) ); typename LevelSetExtractor< Real , Dim , AuxData >::Stats stats; @@ -1268,7 +1268,7 @@ void Client< Real , Dim , BType , Degree >::_writeMeshWithData( const ClientReco _range.first , _range.second , __vertexStream , - polygonStream , + faceStream , auxDataFactory() , !clientReconInfo.linearFit , HasGradients , false , true , false , @@ -1282,14 +1282,14 @@ void Client< Real , Dim , BType , Degree >::_writeMeshWithData( const ClientReco if( clientReconInfo.verbose>1 ) { - std::cout << "Vertices / Polygons: " << vertexStream.size() << " / " << polygonStream.size() << std::endl; + std::cout << "Vertices / Faces: " << vertexStream.size() << " / " << faceStream.size() << std::endl; std::cout << stats.toString() << std::endl; - std::cout << "# Got polygons: " << timer << std::endl; + std::cout << "# Got faces: " << timer << std::endl; } // Write the mesh to a .ply file std::vector< std::string > noComments; - PLY::WritePolygons< Factory , node_index_type , Real , Dim >( outFileName.c_str() , factory , vertexStream.size() , polygonStream.size() , vertexStream , polygonStream , PLY_BINARY_NATIVE , noComments ); + PLY::Write< Factory , node_index_type , Real , Dim >( outFileName.c_str() , factory , vertexStream.size() , faceStream.size() , vertexStream , faceStream , PLY_BINARY_NATIVE , noComments ); } template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index c2c89917..8cd202f4 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -215,19 +215,19 @@ void WriteMesh // A backing stream for the vertices Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , inCore , false , std::string( "v_" ) ); - Reconstructor::OutputInputPolygonStream polygonStream( inCore , true , std::string( "p_" ) ); + Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( inCore , true , std::string( "f_" ) ); { // The wrapper converting native to output types typename VInfo::StreamWrapper _vertexStream( vertexStream , factory() ); // Extract the level set - implicit.extractLevelSet( _vertexStream , polygonStream , meParams ); + implicit.extractLevelSet( _vertexStream , faceStream , meParams ); } // Write the mesh to a .ply file std::vector< std::string > noComments; - PLY::WritePolygons< Factory , node_index_type , Real , Dim >( fileName , factory , vertexStream.size() , polygonStream.size() , vertexStream , polygonStream , ascii ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); + PLY::Write< Factory , node_index_type , Real , Dim >( fileName , factory , vertexStream.size() , faceStream.size() , vertexStream , faceStream , ascii ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); } template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxDataFactory , bool HasGradients , bool HasDensity > @@ -250,19 +250,19 @@ void WriteMeshWithData // A backing stream for the vertices Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , inCore , false , std::string( "v_" ) ); - Reconstructor::OutputInputPolygonStream polygonStream( inCore , true , std::string( "p_" ) ); + Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( inCore , true , std::string( "f_" ) ); { // The wrapper converting native to output types typename VInfo::StreamWrapper _vertexStream( vertexStream , factory() ); // Extract the level set - implicit.extractLevelSet( _vertexStream , polygonStream , meParams ); + implicit.extractLevelSet( _vertexStream , faceStream , meParams ); } // Write the mesh to a .ply file std::vector< std::string > noComments; - PLY::WritePolygons< Factory , node_index_type , Real , Dim >( fileName , factory , vertexStream.size() , polygonStream.size() , vertexStream , polygonStream , ascii ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); + PLY::Write< Factory , node_index_type , Real , Dim >( fileName , factory , vertexStream.size() , faceStream.size() , vertexStream , faceStream , ascii ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); } template< class Real , unsigned int Dim , unsigned int FEMSig , typename AuxDataFactory > @@ -514,8 +514,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) } - if( Out.set && Dim!=3 ) WARN( "Mesh extraction is only supported in dimension 3" ); - else if( Out.set && Dim==3 ) + if( Out.set && ( Dim==2 || Dim==3 ) ) { // Create the output mesh char tempHeader[2048]; @@ -559,6 +558,8 @@ void Execute( const AuxDataFactory &auxDataFactory ) } } } + else WARN( "Mesh extraction is only supported in dimensions 2 and 3" ); + if( Verbose.set ) std::cout << "# Total Solve: " << Time()-startTime << " (s), " << MemoryInfo::PeakMemoryUsageMB() << " (MB)" << std::endl; delete implicit; } diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 3a5fbfef..af620001 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -45,7 +45,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "15.03" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "15.10" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file diff --git a/Src/Reconstruction.example.cpp b/Src/Reconstruction.example.cpp index d6babb3c..fa4c10cb 100644 --- a/Src/Reconstruction.example.cpp +++ b/Src/Reconstruction.example.cpp @@ -162,7 +162,7 @@ struct SphereSampleWithColorStream : public Reconstructor::InputSampleWithDataSt // A stream into which we can write polygons of the form std::vector< node_index_type > template< typename Index > -struct PolygonStream : public Reconstructor::OutputPolygonStream +struct PolygonStream : public Reconstructor::OutputFaceStream< 2 > { // Construct a stream that adds polygons to the vector of polygons PolygonStream( std::vector< std::vector< Index > > &polygonStream ) : _polygons( polygonStream ) {} diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h index 67c343f1..6c0e85db 100644 --- a/Src/Reconstructors.h +++ b/Src/Reconstructors.h @@ -62,7 +62,7 @@ namespace Reconstructor // "Private" function for extracting meshes template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ImplicitType , unsigned int ... FEMSigs > - void _ExtractLevelSet( UIntPack< FEMSigs ... > , const ImplicitType &implicit , OutputVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , LevelSetExtractionParameters params ); + void _ExtractLevelSet( UIntPack< FEMSigs ... > , const ImplicitType &implicit , OutputVertexStream &vertexStream , OutputFaceStream< Dim-1 > &faceStream , typename Implicit< Real , Dim , FEMSig >::LevelSetExtractionParameters params ); // Specialized solution information without auxiliary data template< typename Real , unsigned int Dim , unsigned int FEMSig > @@ -96,10 +96,10 @@ namespace Reconstructor DensityEstimator *density; // A method that writes the extracted mesh to the streams - void extractLevelSet( OutputVertexStream< Real , Dim > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , LevelSetExtractionParameters params ) const + void extractLevelSet( OutputVertexStream< Real , Dim > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const { typedef unsigned char AuxData; - _ExtractLevelSet< false , Real , Dim , FEMSig , AuxData , OutputVertexStream< Real , Dim > , Implicit< Real , Dim , FEMSig > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , polygonStream , params ); + _ExtractLevelSet< false , Real , Dim , FEMSig , AuxData , OutputVertexStream< Real , Dim > , Implicit< Real , Dim , FEMSig > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); } }; @@ -136,9 +136,9 @@ namespace Reconstructor } // A method for writing the extracted mesh to the streams - void extractLevelSet( OutputVertexWithDataStream< Real , Dim , AuxData > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , LevelSetExtractionParameters params ) const + void extractLevelSet( OutputVertexWithDataStream< Real , Dim , AuxData > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const { - _ExtractLevelSet< true , Real , Dim , FEMSig , AuxData , OutputVertexWithDataStream< Real , Dim , AuxData > , Implicit< Real , Dim , FEMSig , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , polygonStream , params ); + _ExtractLevelSet< true , Real , Dim , FEMSig , AuxData , OutputVertexWithDataStream< Real , Dim , AuxData > , Implicit< Real , Dim , FEMSig , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); } }; @@ -462,19 +462,41 @@ namespace Reconstructor } template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ImplicitType , unsigned int ... FEMSigs > - void _ExtractLevelSet( UIntPack< FEMSigs ... > , const ImplicitType &implicit , OutputVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , LevelSetExtractionParameters params ) + void _ExtractLevelSet( UIntPack< FEMSigs ... > , const ImplicitType &implicit , OutputVertexStream &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) { typedef UIntPack< FEMSigs ... > Sigs; static_assert( std::is_same< IsotropicUIntPack< Dim , FEMSig > , UIntPack< FEMSigs ... > >::value , "[ERROR] Signatures don't match" ); static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; typedef typename ImplicitType::DensityEstimator DensityEstimator; - if constexpr( Dim!=3 ) + if constexpr( Dim==3 ) { - WARN( "Extraction only supported for dimension 3" ); - return; + Profiler profiler(20); + + std::string statsString; + + if constexpr( HasAuxData ) + { + typename LevelSetExtractor< Real , Dim , AuxData >::Stats stats; + TransformedOutputVertexWithDataStream< Real , Dim , AuxData > _vertexStream( implicit.unitCubeToModel , vertexStream ); + stats = LevelSetExtractor< Real , Dim , AuxData >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , UIntPack< DataSig >() , implicit.tree , implicit.density , implicit.auxData , implicit.solution , implicit.isoValue , _vertexStream , faceStream , implicit.zeroAuxData , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); + statsString = stats.toString(); + } + else + { + typename LevelSetExtractor< Real , Dim >::Stats stats; + TransformedOutputVertexStream< Real , Dim > _vertexStream( implicit.unitCubeToModel , vertexStream ); + stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , implicit.tree , implicit.density , implicit.solution , implicit.isoValue , _vertexStream , faceStream , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); + statsString = stats.toString(); + } + if( params.verbose ) + { + std::cout << "Vertices / Faces: " << vertexStream.size() << " / " << faceStream.size() << std::endl; + std::cout << statsString << std::endl; + std::cout << "# Got Faces: " << profiler << std::endl; + } } - else + else if constexpr( Dim==2 ) { Profiler profiler(20); @@ -484,25 +506,24 @@ namespace Reconstructor { typename LevelSetExtractor< Real , Dim , AuxData >::Stats stats; TransformedOutputVertexWithDataStream< Real , Dim , AuxData > _vertexStream( implicit.unitCubeToModel , vertexStream ); - stats = LevelSetExtractor< Real , Dim , AuxData >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , UIntPack< DataSig >() , implicit.tree , implicit.density , implicit.auxData , implicit.solution , implicit.isoValue , _vertexStream , polygonStream , implicit.zeroAuxData , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); + stats = LevelSetExtractor< Real , Dim , AuxData >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , UIntPack< DataSig >() , implicit.tree , implicit.density , implicit.auxData , implicit.solution , implicit.isoValue , _vertexStream , faceStream , implicit.zeroAuxData , !params.linearFit , params.outputGradients , false ); statsString = stats.toString(); } else { typename LevelSetExtractor< Real , Dim >::Stats stats; TransformedOutputVertexStream< Real , Dim > _vertexStream( implicit.unitCubeToModel , vertexStream ); - stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , implicit.tree , implicit.density , implicit.solution , implicit.isoValue , _vertexStream , polygonStream , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); + stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , implicit.tree , implicit.density , implicit.solution , implicit.isoValue , _vertexStream , faceStream , !params.linearFit , params.outputGradients , false ); statsString = stats.toString(); } if( params.verbose ) { - std::cout << "Vertices / Polygons: " << vertexStream.size() << " / " << polygonStream.size() << std::endl; + std::cout << "Vertices / Faces: " << vertexStream.size() << " / " << faceStream.size() << std::endl; std::cout << statsString << std::endl; - if( params.polygonMesh ) std::cout << "# Got polygons: " << profiler << std::endl; - else std::cout << "# Got triangles: " << profiler << std::endl; + std::cout << "# Got faces: " << profiler << std::endl; } } - } + else WARN( "Extraction only supported for dimensions 2 and 3" ); } template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > void Poisson::_Solve( UIntPack< FEMSigs ... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh ) diff --git a/Src/Reconstructors.streams.h b/Src/Reconstructors.streams.h index fef15dcb..80c7ea48 100644 --- a/Src/Reconstructors.streams.h +++ b/Src/Reconstructors.streams.h @@ -44,8 +44,11 @@ using BaseVertex = VectorTypeUnion< Real , Position< Real , Dim > , Normal< Real template< typename Real , unsigned int Dim , typename Data > using BaseVertexWithData = VectorTypeUnion< Real , Position< Real , Dim > , Gradient< Real , Dim > , Real , Data >; +using Edge = std::pair< node_index_type , node_index_type >; using Polygon = std::vector< node_index_type >; +template< unsigned int FaceDim > using Face = std::conditional_t< FaceDim==2 , Polygon , std::conditional_t< FaceDim==1 , Edge , void * > >; + // Basic streams template< typename Real , unsigned int Dim > using BaseInputSampleStream = InputDataStream< BaseSample < Real , Dim > >; template< typename Real , unsigned int Dim , typename Data > using BaseInputSampleWithDataStream = InputDataStream< BaseSampleWithData< Real , Dim , Data > >; @@ -53,8 +56,8 @@ template< typename Real , unsigned int Dim , typename Data > using BaseInputSamp template< typename Real , unsigned int Dim > using BaseOutputVertexStream = OutputDataStream< BaseVertex < Real , Dim > >; template< typename Real , unsigned int Dim , typename Data > using BaseOutputVertexWithDataStream = OutputDataStream< BaseVertexWithData< Real , Dim , Data > >; -using InputPolygonStream = InputDataStream< Polygon >; -using OutputPolygonStream = OutputDataStream< Polygon >; +template< unsigned int FaceDim > using InputFaceStream = InputDataStream< Face< FaceDim > >; +template< unsigned int FaceDim > using OutputFaceStream = OutputDataStream< Face< FaceDim > >; /////////////////////////// // Oriented Point Stream // @@ -117,7 +120,7 @@ struct TransformedInputSampleStream : public InputSampleStream< Real , Dim > TransformedInputSampleStream( XForm< Real , Dim+1 > xForm , InputSampleStream< Real , Dim > &stream ) : _stream(stream) , _positionXForm(xForm) #endif // DE_VIRTUALIZE_INPUT { - _normalXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); + _normalXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( fabs( xForm.determinant() ) , 1./Dim ); } // Functionality to reset the stream to the start @@ -327,24 +330,25 @@ struct OutputVertexWithDataStreamWrapper : public OutputVertexWithDataStream< Re }; -///////////////////////////////////////////////////////////////////////////////// -// Output and the input polygon stream, backed either by a file or by a vector // -///////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +// Output and the input face stream, backed either by a file or by a vector // +////////////////////////////////////////////////////////////////////////////// // [WARNING] These assume that the stream starts as write-only and after the reset method is invoked, the stream becomes read-only. -struct OutputInputPolygonStream : public OutputPolygonStream , public InputPolygonStream +template< unsigned int FaceDim > +struct OutputInputFaceStream : public OutputFaceStream< FaceDim > , public InputFaceStream< FaceDim > { // The streams for communicating the information - InputPolygonStream * inStream; - OutputPolygonStream *outStream; + InputFaceStream < FaceDim > * inStream; + OutputFaceStream< FaceDim > *outStream; void reset( void ){ inStream->reset(); } - bool base_read( Polygon &p ){ return inStream->read(p); } - bool base_read( unsigned int t , Polygon &p ){ return inStream->read(t,p); } - void base_write( const Polygon &p ){ outStream->write(p); } - void base_write( unsigned int t , const Polygon &p ){ outStream->write(t,p); } + bool base_read( Face< FaceDim > &f ){ return inStream->read(f); } + bool base_read( unsigned int t , Face< FaceDim > &f ){ return inStream->read(t,f); } + void base_write( const Face< FaceDim > &f ){ outStream->write(f); } + void base_write( unsigned int t , const Face< FaceDim > &f ){ outStream->write(t,f); } - OutputInputPolygonStream( bool inCore , bool multi , std::string header="" ) + OutputInputFaceStream( bool inCore , bool multi , std::string header="" ) { size_t sz = std::thread::hardware_concurrency(); @@ -363,19 +367,18 @@ struct OutputInputPolygonStream : public OutputPolygonStream , public InputPolyg { for( unsigned int i=0 ; i(); - _inStreams[i] = new VectorBackedInputDataStream< Polygon >( *_backingVectors[i] ); - _outStreams[i] = new VectorBackedOutputDataStream< Polygon >( *_backingVectors[i] ); + _backingVectors[i] = new std::vector< Face< FaceDim > >(); + _inStreams[i] = new VectorBackedInputDataStream< Face< FaceDim > >( *_backingVectors[i] ); + _outStreams[i] = new VectorBackedOutputDataStream< Face< FaceDim > >( *_backingVectors[i] ); } - inStream = new MultiInputDataStream< Polygon >( _inStreams ); - outStream = new MultiOutputDataStream< Polygon >( _outStreams ); + inStream = new MultiInputDataStream< Face< FaceDim > >( _inStreams ); + outStream = new MultiOutputDataStream< Face< FaceDim > >( _outStreams ); } else { - _backingVector = new std::vector< Polygon >(); - - inStream = new VectorBackedInputDataStream< Polygon >( *_backingVector ); - outStream = new VectorBackedOutputDataStream< Polygon >( *_backingVector ); + _backingVector = new std::vector< Face< FaceDim > >(); + inStream = new VectorBackedInputDataStream< Face< FaceDim > >( *_backingVector ); + outStream = new VectorBackedOutputDataStream< Face< FaceDim > >( *_backingVector ); } } else @@ -385,22 +388,22 @@ struct OutputInputPolygonStream : public OutputPolygonStream , public InputPolyg for( unsigned int i=0 ; i( _backingFiles[i]->fp ); - _outStreams[i] = new FileBackedOutputDataStream< Polygon >( _backingFiles[i]->fp ); + _inStreams[i] = new FileBackedInputDataStream< Face< FaceDim > >( _backingFiles[i]->fp ); + _outStreams[i] = new FileBackedOutputDataStream< Face< FaceDim > >( _backingFiles[i]->fp ); } - inStream = new MultiInputDataStream< std::vector< node_index_type > >( _inStreams ); - outStream = new MultiOutputDataStream< std::vector< node_index_type > >( _outStreams ); + inStream = new MultiInputDataStream< Face< FaceDim > >( _inStreams ); + outStream = new MultiOutputDataStream< Face< FaceDim > >( _outStreams ); } else { _backingFile = new FileBackedReadWriteStream::FileDescription( header.c_str() ); - - inStream = new FileBackedInputDataStream< Polygon >( _backingFile->fp ); - outStream = new FileBackedOutputDataStream< Polygon >( _backingFile->fp ); + inStream = new FileBackedInputDataStream< Face< FaceDim > >( _backingFile->fp ); + outStream = new FileBackedOutputDataStream< Face< FaceDim > >( _backingFile->fp ); } } } - ~OutputInputPolygonStream( void ) + + ~OutputInputFaceStream( void ) { size_t sz = std::thread::hardware_concurrency(); @@ -424,12 +427,12 @@ struct OutputInputPolygonStream : public OutputPolygonStream , public InputPolyg delete outStream; } protected: - std::vector< Polygon > *_backingVector; + std::vector< Face< FaceDim > > *_backingVector; FileBackedReadWriteStream::FileDescription *_backingFile; - std::vector< std::vector< Polygon > * > _backingVectors; + std::vector< std::vector< Face< FaceDim > > * > _backingVectors; std::vector< FileBackedReadWriteStream::FileDescription * > _backingFiles; - std::vector< InputDataStream< Polygon > * > _inStreams; - std::vector< OutputDataStream< Polygon > * > _outStreams; + std::vector< InputDataStream< Face< FaceDim > > * > _inStreams; + std::vector< OutputDataStream< Face< FaceDim > > * > _outStreams; }; template< typename Factory > diff --git a/Src/SSDRecon.cpp b/Src/SSDRecon.cpp index c002f3b9..2fc497c2 100644 --- a/Src/SSDRecon.cpp +++ b/Src/SSDRecon.cpp @@ -211,19 +211,19 @@ void WriteMesh // A backing stream for the vertices Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , inCore , false , std::string( "v_" ) ); - Reconstructor::OutputInputPolygonStream polygonStream( inCore , true , std::string( "p_" ) ); + Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( inCore , true , std::string( "f_" ) ); { // The wrapper converting native to output types typename VInfo::StreamWrapper _vertexStream( vertexStream , factory() ); // Extract the level set - implicit.extractLevelSet( _vertexStream , polygonStream , meParams ); + implicit.extractLevelSet( _vertexStream , faceStream , meParams ); } // Write the mesh to a .ply file std::vector< std::string > noComments; - PLY::WritePolygons< Factory , node_index_type , Real , Dim >( fileName , factory , vertexStream.size() , polygonStream.size() , vertexStream , polygonStream , ascii ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); + PLY::Write< Factory , node_index_type , Real , Dim >( fileName , factory , vertexStream.size() , faceStream.size() , vertexStream , faceStream , ascii ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); } template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxDataFactory , bool HasGradients , bool HasDensity > @@ -246,19 +246,19 @@ void WriteMeshWithData // A backing stream for the vertices Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , inCore , false , std::string( "v_" ) ); - Reconstructor::OutputInputPolygonStream polygonStream( inCore , true , std::string( "p_" ) ); + Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( inCore , true , std::string( "f_" ) ); { // The wrapper converting native to output types typename VInfo::StreamWrapper _vertexStream( vertexStream , factory() ); // Extract the level set - implicit.extractLevelSet( _vertexStream , polygonStream , meParams ); + implicit.extractLevelSet( _vertexStream , faceStream , meParams ); } // Write the mesh to a .ply file std::vector< std::string > noComments; - PLY::WritePolygons< Factory , node_index_type , Real , Dim >( fileName , factory , vertexStream.size() , polygonStream.size() , vertexStream , polygonStream , ascii ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); + PLY::Write< Factory , node_index_type , Real , Dim >( fileName , factory , vertexStream.size() , faceStream.size() , vertexStream , faceStream , ascii ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); } template< class Real , unsigned int Dim , unsigned int FEMSig , typename AuxDataFactory > @@ -493,8 +493,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) } - if( Out.set && Dim!=3 ) WARN( "Mesh extraction is only supported in dimension 3" ); - else if( Out.set && Dim==3 ) + if( Out.set && ( Dim==2 || Dim==3 ) ) { // Create the output mesh char tempHeader[2048]; @@ -538,6 +537,8 @@ void Execute( const AuxDataFactory &auxDataFactory ) } } } + else WARN( "Mesh extraction is only supported in dimensions 2 and 3" ); + if( Verbose.set ) std::cout << "# Total Solve: " << Time()-startTime << " (s), " << MemoryInfo::PeakMemoryUsageMB() << " (MB)" << std::endl; delete implicit; } From 9e5312d6653e699f2c564c11f81f5cfccaf8175b Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Tue, 5 Dec 2023 14:39:11 -0500 Subject: [PATCH 20/86] Update AdaptiveSolvers.sln --- AdaptiveSolvers.sln | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AdaptiveSolvers.sln b/AdaptiveSolvers.sln index 757af954..dadfb963 100644 --- a/AdaptiveSolvers.sln +++ b/AdaptiveSolvers.sln @@ -131,7 +131,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PoissonReconClient", "Poiss EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PoissonReconServer", "PoissonReconServer.vcxproj", "{649D8C83-6BE2-4419-B0A8-66F65CD4D4CB}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Reconstruction.example", "..\..\..\Users\mkazh\OneDrive - Johns Hopkins\Research\PoissonRecon\PoissonRecon\Reconstruction.example.vcxproj", "{F40103C1-D18D-4C34-992C-F78D4DCD4A87}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Reconstruction.example", "Reconstruction.example.vcxproj", "{F40103C1-D18D-4C34-992C-F78D4DCD4A87}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution From 60b4e4b7bf51a473da3c547e8fbc1c731688cd82 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Tue, 5 Dec 2023 21:57:26 -0500 Subject: [PATCH 21/86] Update PoissonRecon.cpp --- Src/PoissonRecon.cpp | 73 ++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index 8cd202f4..ae4911d7 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -514,51 +514,52 @@ void Execute( const AuxDataFactory &auxDataFactory ) } - if( Out.set && ( Dim==2 || Dim==3 ) ) - { - // Create the output mesh - char tempHeader[2048]; + if( Out.set ) + if( Dim==2 || Dim==3 ) { - char tempPath[1024]; - tempPath[0] = 0; - if( TempDir.set ) strcpy( tempPath , TempDir.value ); - else SetTempDirectory( tempPath , sizeof(tempPath) ); - if( strlen(tempPath)==0 ) sprintf( tempPath , ".%c" , FileSeparator ); - if( tempPath[ strlen( tempPath )-1 ]==FileSeparator ) sprintf( tempHeader , "%sPR_" , tempPath ); - else sprintf( tempHeader , "%s%cPR_" , tempPath , FileSeparator ); - } - - XForm< Real , Dim+1 > pXForm = implicit->unitCubeToModel; - XForm< Real , Dim > nXForm = XForm< Real , Dim >( pXForm ).inverse().transpose(); - - if( Gradients.set ) - { - if( Density.set ) - { - if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , true , true >( auxDataFactory , InCore.set , *implicit , meParams , Out.value , ASCII.set ); - else WriteMesh < Real , Dim , FEMSig , true , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); - } - else + // Create the output mesh + char tempHeader[2048]; { - if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , true , false >( auxDataFactory , InCore.set , *implicit , meParams , Out.value , ASCII.set ); - else WriteMesh < Real , Dim , FEMSig , true , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); + char tempPath[1024]; + tempPath[0] = 0; + if( TempDir.set ) strcpy( tempPath , TempDir.value ); + else SetTempDirectory( tempPath , sizeof(tempPath) ); + if( strlen(tempPath)==0 ) sprintf( tempPath , ".%c" , FileSeparator ); + if( tempPath[ strlen( tempPath )-1 ]==FileSeparator ) sprintf( tempHeader , "%sPR_" , tempPath ); + else sprintf( tempHeader , "%s%cPR_" , tempPath , FileSeparator ); } - } - else - { - if( Density.set ) + + XForm< Real , Dim+1 > pXForm = implicit->unitCubeToModel; + XForm< Real , Dim > nXForm = XForm< Real , Dim >( pXForm ).inverse().transpose(); + + if( Gradients.set ) { - if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , false , true >( auxDataFactory , InCore.set , *implicit , meParams , Out.value , ASCII.set ); - else WriteMesh < Real , Dim , FEMSig , false , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); + if( Density.set ) + { + if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , true , true >( auxDataFactory , InCore.set , *implicit , meParams , Out.value , ASCII.set ); + else WriteMesh < Real , Dim , FEMSig , true , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); + } + else + { + if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , true , false >( auxDataFactory , InCore.set , *implicit , meParams , Out.value , ASCII.set ); + else WriteMesh < Real , Dim , FEMSig , true , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); + } } else { - if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , false , false >( auxDataFactory , InCore.set , *implicit , meParams , Out.value , ASCII.set ); - else WriteMesh < Real , Dim , FEMSig , false , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); + if( Density.set ) + { + if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , false , true >( auxDataFactory , InCore.set , *implicit , meParams , Out.value , ASCII.set ); + else WriteMesh < Real , Dim , FEMSig , false , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); + } + else + { + if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , false , false >( auxDataFactory , InCore.set , *implicit , meParams , Out.value , ASCII.set ); + else WriteMesh < Real , Dim , FEMSig , false , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); + } } } - } - else WARN( "Mesh extraction is only supported in dimensions 2 and 3" ); + else WARN( "Mesh extraction is only supported in dimensions 2 and 3" ); if( Verbose.set ) std::cout << "# Total Solve: " << Time()-startTime << " (s), " << MemoryInfo::PeakMemoryUsageMB() << " (MB)" << std::endl; delete implicit; From 6439de117e19f1d501d80a369e3b4069a2aa6644 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Wed, 13 Dec 2023 17:47:18 -0500 Subject: [PATCH 22/86] Version 16.01 --- README.md | 14 ++++-- Src/PointInterpolant.cpp | 4 +- Src/PreProcessor.h | 2 +- Src/Reconstruction.example.cpp | 10 ++-- Src/Reconstructors.h | 86 ++++++++++++++++++++++++++++++---- Src/Reconstructors.streams.h | 46 ++++++++++++++++++ 6 files changed, 142 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index f26e85a1..fd0d10b6 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 15.10)

    +

    Adaptive Multigrid Solvers (Version 16.01)

    links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
    Executables: -Win64
    +Win64
    Source Code: -ZIP GitHub
    +ZIP GitHub
    Older Versions: +V15.10, V15.03, V15.02, V15.01, @@ -1447,6 +1448,11 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • Added iso-curve extraction support (for 2D reconstruction) +Version 16.01: +
      +
    1. Added support for separte value interpolation in Poisson Surface Reconstruction +
    + @@ -1456,4 +1462,4 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • This work was genersouly supported by the National Science Foundation (NSF) grant numbers 0746039 and 1422325.
  • We are extremely grateful to the EPFL Scanning 3D Statues from Photos course, the Stanford 3D Scanning Repository, and Resonai for sharing their data.
  • This work was carried out at the Advanced Research Computing at Hopkins (ARCH) core facility, which is supported by the National Science Foundation (NSF) grant number 1920103. - + \ No newline at end of file diff --git a/Src/PointInterpolant.cpp b/Src/PointInterpolant.cpp index 1c36c26f..fb890d74 100644 --- a/Src/PointInterpolant.cpp +++ b/Src/PointInterpolant.cpp @@ -703,9 +703,9 @@ void Execute( UIntPack< FEMSigs ... > ) valueSamples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); XInputPointValueStream _pointStream( *pointValueStream , modelToUnitCube ); auto ProcessData = []( const Point< Real , Dim > &p , FunctionValueType &d ){ return (Real)1.; }; - FunctionValueType zeroGradient = functionValueFactory(); + FunctionValueType zeroValue = functionValueFactory(); typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; - pointValueCount = FEMTreeInitializer< Dim , Real >::template Initialize< FunctionValueType >( sid , tree.spaceRoot() , _pointStream , zeroGradient , Depth.value , *valueSamples , *valueSampleData , true , tree.nodeAllocators.size() ? tree.nodeAllocators[0] : NULL , tree.initializer() , ProcessData ); + pointValueCount = FEMTreeInitializer< Dim , Real >::template Initialize< FunctionValueType >( sid , tree.spaceRoot() , _pointStream , zeroValue , Depth.value , *valueSamples , *valueSampleData , true , tree.nodeAllocators.size() ? tree.nodeAllocators[0] : NULL , tree.initializer() , ProcessData ); delete pointValueStream; } else pointValueCount = 0; diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index af620001..39924287 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -45,7 +45,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "15.10" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "16.01" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file diff --git a/Src/Reconstruction.example.cpp b/Src/Reconstruction.example.cpp index fa4c10cb..670b4137 100644 --- a/Src/Reconstruction.example.cpp +++ b/Src/Reconstruction.example.cpp @@ -336,11 +336,11 @@ int main( int argc , char* argv[] ) if( Verbose.set ) { - std::cout << "************************************************" << std::endl; - std::cout << "************************************************" << std::endl; - std::cout << "** Running SSD Reconstruction (Version " << ADAPTIVE_SOLVERS_VERSION << ") **" << std::endl; - std::cout << "************************************************" << std::endl; - std::cout << "************************************************" << std::endl; + std::cout << "****************************************************" << std::endl; + std::cout << "****************************************************" << std::endl; + std::cout << "** Running Reconstruction Example (Version " << ADAPTIVE_SOLVERS_VERSION << ") **" << std::endl; + std::cout << "****************************************************" << std::endl; + std::cout << "****************************************************" << std::endl; } // Solve using single float precision, in dimension 3, w/ finite-elements of degree 2 for SSD and degree 1 for Poisson, and using Neumann boundaries diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h index 6c0e85db..390c78ba 100644 --- a/Src/Reconstructors.h +++ b/Src/Reconstructors.h @@ -178,6 +178,36 @@ namespace Reconstructor CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim >& p , const CumulativeDerivativeValues< Real , Dim , 0 >& dValues ) const { return dValues * weight; }; }; + template< unsigned int Dim , typename Real > + struct ValueInterpolationConstraintDual + { + typedef VectorTypeUnion< Real , Real > PointSampleData; + Real vWeight; + ValueInterpolationConstraintDual( Real v ) : vWeight(v){ } + CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim > &p , const VectorTypeUnion< Real , Real >& data ) const + { + Real value = data.template get<0>(); + CumulativeDerivativeValues< Real , Dim , 0 > cdv; + cdv[0] = value*vWeight; + return cdv; + } + }; + + template< unsigned int Dim , typename Real > + struct ValueInterpolationSystemDual + { + CumulativeDerivativeValues< Real , Dim , 0 > weight; + ValueInterpolationSystemDual( Real v ){ weight[0] = v; } + CumulativeDerivativeValues< Real , Dim , 0 > operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Real > &data , const CumulativeDerivativeValues< Real , Dim , 0 > &dValues ) const + { + return dValues * weight; + } + CumulativeDerivativeValues< double , Dim , 0 > operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Real > &data , const CumulativeDerivativeValues< double , Dim , 0 > &dValues ) const + { + return dValues * weight; + }; + }; + template< typename Real > struct SolutionParameters { @@ -192,6 +222,7 @@ namespace Reconstructor Real lowDepthCutOff; Real width; Real pointWeight; + Real valueInterpolationWeight; Real samplesPerNode; Real cgSolverAccuracy; unsigned int depth; @@ -206,7 +237,7 @@ namespace Reconstructor SolutionParameters( void ) : verbose(false) , dirichletErode(false) , outputDensity(false) , exactInterpolation(false) , showResidual(false) , scale((Real)1.1) , confidence((Real)0.) , confidenceBias((Real)0.) , lowDepthCutOff((Real)0.) , width((Real)0.) , - pointWeight((Real)0.) , samplesPerNode((Real)1.5) , cgSolverAccuracy((Real)1e-3 ) , + pointWeight((Real)0.) , valueInterpolationWeight((Real)0.) , samplesPerNode((Real)1.5) , cgSolverAccuracy((Real)1e-3 ) , depth((unsigned int)8) , solveDepth((unsigned int)-1) , baseDepth((unsigned int)-1) , fullDepth((unsigned int)5) , kernelDepth((unsigned int)-1) , envelopeDepth((unsigned int)-1) , baseVCycles((unsigned int)1) , iters((unsigned int)8) {} @@ -222,27 +253,27 @@ namespace Reconstructor template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct Implicit; template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > - static void _Solve( UIntPack< FEMSigs... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh ); + static void _Solve( UIntPack< FEMSigs... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh , ValueInterpolationStream< Real , Dim > *valueInterpolationStream ); template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct Implicit; template< typename Real , unsigned int Dim , unsigned int FEMSig > struct Implicit< Real , Dim , FEMSig > : public Reconstructor::Implicit< Real , Dim , FEMSig > { - Implicit( InputSampleStream< Real , Dim > &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL ) + Implicit( InputSampleStream< Real , Dim > &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL , ValueInterpolationStream< Real , Dim > *valueInterpolationStream=NULL ) { typedef unsigned char AuxData; - _Solve< false , Real , Dim , FEMSig , AuxData , InputSampleStream< Real , Dim > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params , envelopeMesh ); + _Solve< false , Real , Dim , FEMSig , AuxData , InputSampleStream< Real , Dim > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params , envelopeMesh , valueInterpolationStream ); } }; template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > struct Implicit< Real , Dim , FEMSig , AuxData > : public Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > { - Implicit( InputSampleWithDataStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL ) + Implicit( InputSampleWithDataStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL , ValueInterpolationStream< Real , Dim > *valueInterpolationStream=NULL ) : Reconstructor::Implicit< Real , Dim , FEMSig , AuxData >( pointStream.zero() ) { - _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleWithDataStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params , envelopeMesh ); + _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleWithDataStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params , envelopeMesh , valueInterpolationStream ); } }; }; @@ -526,9 +557,15 @@ namespace Reconstructor else WARN( "Extraction only supported for dimensions 2 and 3" ); } template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > - void Poisson::_Solve( UIntPack< FEMSigs ... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh ) + void Poisson::_Solve( UIntPack< FEMSigs ... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh , ValueInterpolationStream< Real , Dim > *valueInterpolationStream ) { static_assert( std::is_same< IsotropicUIntPack< Dim , FEMSig > , UIntPack< FEMSigs... > >::value , "[ERROR] Signatures don't match" ); + if( params.valueInterpolationWeight<0 ) + { + WARN( "Negative value interpolation weight clamped to zero" ); + params.valueInterpolationWeight = 0; + } + if( valueInterpolationStream && !params.valueInterpolationWeight ) WARN( "Value interpolation stream provided but interpolation weight is zero" ); // The signature for the finite-elements representing the auxiliary data (if it's there) static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; @@ -570,6 +607,8 @@ namespace Reconstructor size_t pointCount; ProjectiveData< Point< Real , 2 > , Real > pointDepthAndWeight; + std::vector< typename FEMTree< Dim , Real >::PointSample > *valueInterpolationSamples = NULL; + std::vector< Real > *valueInterpolationSampleData = NULL; DenseNodeData< GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > geometryNodeDesignators; SparseNodeData< Point< Real , Dim > , NormalSigs > *normalInfo = NULL; std::vector< typename FEMTree< Dim , Real >::PointSample > *samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); @@ -675,7 +714,24 @@ namespace Reconstructor std::cout << "# Read input into tree: " << profiler << std::endl; } } + + if( valueInterpolationStream && params.valueInterpolationWeight ) + { + valueInterpolationSamples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); + valueInterpolationSampleData = new std::vector< Real >(); + // Wrap the point stream in a transforming stream + TransformedValueInterpolationStream< Real , Dim > _valueInterpolationStream( modelToUnitCube , *valueInterpolationStream ); + + // Assign each sample a weight of 1. + auto ProcessData = []( const Point< Real , Dim > &p , Real &d ){ return (Real)1.; }; + Real zeroValue = (Real)0.; + typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; + size_t count = FEMTreeInitializer< Dim , Real >::template Initialize< Real >( sid , implicit.tree.spaceRoot() , _valueInterpolationStream , zeroValue , params.depth , *valueInterpolationSamples , *valueInterpolationSampleData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); + if( params.verbose ) std::cout << "Input Interpolation Points / Samples: " << count << " / " << valueInterpolationSamples->size() << std::endl; + } + { + InterpolationInfo *valueInterpolationInfo = NULL; DenseNodeData< Real , Sigs > constraints; InterpolationInfo *iInfo = NULL; int solveDepth = params.depth; @@ -909,6 +965,18 @@ namespace Reconstructor if( params.verbose ) std::cout << "#Set point constraints: " << profiler << std::endl; } + if( valueInterpolationSamples && params.valueInterpolationWeight ) + { + profiler.reset(); + if( params.exactInterpolation ) valueInterpolationInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , Real , 0 > ( implicit.tree , *valueInterpolationSamples , GetPointer( *valueInterpolationSampleData ) , Poisson::ValueInterpolationConstraintDual< Dim , Real >( params.valueInterpolationWeight ) , Poisson::ValueInterpolationSystemDual< Dim , Real >( params.valueInterpolationWeight ) , true , false ); + else valueInterpolationInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , Real , 0 > ( implicit.tree , *valueInterpolationSamples , GetPointer( *valueInterpolationSampleData ) , Poisson::ValueInterpolationConstraintDual< Dim , Real >( params.valueInterpolationWeight ) , Poisson::ValueInterpolationSystemDual< Dim , Real >( params.valueInterpolationWeight ) , true , params.depth , 1 ); + delete valueInterpolationSamples , valueInterpolationSamples = NULL; + delete valueInterpolationSampleData , valueInterpolationSampleData = NULL; + + implicit.tree.addInterpolationConstraints( constraints , solveDepth , std::make_tuple( valueInterpolationInfo ) ); + if( params.verbose ) std::cout << "#Set value interpolation constraints: " << profiler << std::endl; + } + if( params.verbose ) std::cout << "All Nodes / Active Nodes / Ghost Nodes / Dirichlet Supported Nodes: " << implicit.tree.allNodes() << " / " << implicit.tree.activeNodes() << " / " << implicit.tree.ghostNodes() << " / " << implicit.tree.dirichletElements() << std::endl; if( params.verbose ) std::cout << "Memory Usage: " << float( MemoryInfo::Usage())/(1<<20) << " MB" << std::endl; @@ -919,9 +987,11 @@ namespace Reconstructor _sInfo.cgDepth = 0 , _sInfo.cascadic = true , _sInfo.vCycles = 1 , _sInfo.iters = params.iters , _sInfo.cgAccuracy = params.cgSolverAccuracy , _sInfo.verbose = params.verbose , _sInfo.showResidual = params.showResidual , _sInfo.showGlobalResidual = SHOW_GLOBAL_RESIDUAL_NONE , _sInfo.sliceBlockSize = 1; _sInfo.baseVCycles = params.baseVCycles; typename FEMIntegrator::template System< Sigs , IsotropicUIntPack< Dim , 1 > > F( { 0. , 1. } ); - implicit.solution = implicit.tree.solveSystem( Sigs() , F , constraints , params.baseDepth , params.solveDepth , _sInfo , std::make_tuple( iInfo ) ); + if( valueInterpolationInfo ) implicit.solution = implicit.tree.solveSystem( Sigs() , F , constraints , params.baseDepth , params.solveDepth , _sInfo , std::make_tuple( iInfo , valueInterpolationInfo ) ); + else implicit.solution = implicit.tree.solveSystem( Sigs() , F , constraints , params.baseDepth , params.solveDepth , _sInfo , std::make_tuple( iInfo ) ); if( params.verbose ) std::cout << "# Linear system solved: " << profiler << std::endl; if( iInfo ) delete iInfo , iInfo = NULL; + if( valueInterpolationInfo ) delete valueInterpolationInfo , valueInterpolationInfo = NULL; } } diff --git a/Src/Reconstructors.streams.h b/Src/Reconstructors.streams.h index 80c7ea48..54e544cf 100644 --- a/Src/Reconstructors.streams.h +++ b/Src/Reconstructors.streams.h @@ -59,6 +59,52 @@ template< typename Real , unsigned int Dim , typename Data > using BaseOutputVer template< unsigned int FaceDim > using InputFaceStream = InputDataStream< Face< FaceDim > >; template< unsigned int FaceDim > using OutputFaceStream = OutputDataStream< Face< FaceDim > >; +///////////////////////////////////// +// Value Interpolation Data Stream // +///////////////////////////////////// +template< typename Real , unsigned int Dim > +struct ValueInterpolationStream : public InputDataStream< VectorTypeUnion< Real , Point< Real , Dim > , Real > > +{ + // Functionality to reset the stream to the start + virtual void reset( void ) = 0; + + // Functionality to extract the next position/normal pair. + // The method returns true if there was another point in the stream to read, and false otherwise + virtual bool base_read( Position< Real , Dim > &p , Real &v ) = 0; + // Implementation of InputDataStream::read + bool base_read( VectorTypeUnion< Real , Point< Real , Dim > , Real > &s ){ return base_read( s.template get<0>() , s.template get<1>() ); } +}; + +///////////////////////////////////////////////// +// Transformed Value Interpolation Data Stream // +///////////////////////////////////////////////// +template< typename Real , unsigned int Dim > +struct TransformedValueInterpolationStream : public ValueInterpolationStream< Real , Dim > +{ + // A constructor initialized with the transformation to be applied to the samples, and a sample stream + TransformedValueInterpolationStream( XForm< Real , Dim+1 > xForm , ValueInterpolationStream< Real , Dim > &stream ) : _stream(stream) , _xForm(xForm) {} + + // Functionality to reset the stream to the start + void reset( void ){ _stream.reset(); } + + // Functionality to extract the next position/normal pair. + // The method returns true if there was another point in the stream to read, and false otherwise + bool base_read( Position< Real , Dim > &p , Real &v ) + { + VectorTypeUnion< Real , Point< Real , Dim > , Real > s; + bool ret = _stream.read( s ); + if( ret ) p = _xForm * s.template get<0>() , v = s.template get<1>(); + return ret; + } + +protected: + // A reference to the underlying stream + ValueInterpolationStream< Real , Dim > &_stream; + + // The affine transformation to be applied to the positions + XForm< Real , Dim+1 > _xForm; +}; + /////////////////////////// // Oriented Point Stream // /////////////////////////// From 86cbd22492438ae88dc2027864390d385b2e1f5a Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Thu, 14 Dec 2023 07:32:32 -0500 Subject: [PATCH 23/86] Bug fix for double interpolation --- Src/FEMTree.h | 2 +- Src/FEMTree.inl | 2 +- Src/MergePlyClientServer.inl | 2 +- Src/Reconstructors.h | 15 ++++++++++++++- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Src/FEMTree.h b/Src/FEMTree.h index 681875f6..60c1c8ed 100644 --- a/Src/FEMTree.h +++ b/Src/FEMTree.h @@ -1751,7 +1751,7 @@ class FEMTree void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ) { std::vector< std::pair< node_index_type , node_index_type > > _newSampleSpan( newNodeCount ); - for( int i=0 ; i::ExactPointInterpolationInfo< double , PointD , Const }; tree._spaceRoot->processNodes( nodeFunctor ); - for( node_index_type i=0 ; iparent; diff --git a/Src/MergePlyClientServer.inl b/Src/MergePlyClientServer.inl index b7e15102..ec0cac42 100644 --- a/Src/MergePlyClientServer.inl +++ b/Src/MergePlyClientServer.inl @@ -40,7 +40,7 @@ inline void _Copy( FILE *target , FILE *source , size_t sz , size_t bufferSize=1 if( sz==-1 ) { size_t ioBytes; - while( ioBytes=fread( buffer , sizeof(unsigned char) , bufferSize , source ) ) fwrite( buffer , sizeof(unsigned char) , ioBytes , target ); + while( ( ioBytes=fread( buffer , sizeof(unsigned char) , bufferSize , source ) ) ) fwrite( buffer , sizeof(unsigned char) , ioBytes , target ); } else { diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h index 390c78ba..78506f05 100644 --- a/Src/Reconstructors.h +++ b/Src/Reconstructors.h @@ -205,7 +205,20 @@ namespace Reconstructor CumulativeDerivativeValues< double , Dim , 0 > operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Real > &data , const CumulativeDerivativeValues< double , Dim , 0 > &dValues ) const { return dValues * weight; - }; + } + }; + + template< unsigned int Dim > + struct ValueInterpolationSystemDual< Dim , double > + { + typedef double Real; + Real weight; + ValueInterpolationSystemDual( void ) : weight(0) {} + ValueInterpolationSystemDual( Real v ) : weight(v) {} + CumulativeDerivativeValues< Real , Dim , 0 > operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Real > &data , const CumulativeDerivativeValues< Real , Dim , 0 > &dValues ) const + { + return dValues * weight; + } }; template< typename Real > From 4902d0da3d671bd5cfd8170e7911b200de6b972a Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Wed, 27 Mar 2024 22:54:56 -0400 Subject: [PATCH 24/86] Version 16.02 --- README.md | 12 +++++++++--- Src/Ply.inl | 5 +++-- Src/PlyFile.h | 3 ++- Src/PreProcessor.h | 2 +- Src/VertexFactory.inl | 35 +++++++++++++++++++---------------- 5 files changed, 34 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index fd0d10b6..2154125c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 16.01)

    +

    Adaptive Multigrid Solvers (Version 16.02)

    links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
    Executables: -Win64
    +Win64
    Source Code: -ZIP GitHub
    +ZIP GitHub
    Older Versions: +V16.01, V15.10, V15.03, V15.02, @@ -1453,6 +1454,11 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • Added support for separte value interpolation in Poisson Surface Reconstruction +Version 16.02: +
      +
    1. Added support for additional .ply types +
    + diff --git a/Src/Ply.inl b/Src/Ply.inl index fd44fd12..efcb5295 100644 --- a/Src/Ply.inl +++ b/Src/Ply.inl @@ -30,14 +30,15 @@ namespace PLY { inline int DefaultFileType( void ){ return PLY_ASCII; } - template<> inline int Type< int >( void ){ return PLY_INT ; } + template<> inline int Type< int >( void ){ return PLY_INT ; } + template<> inline int Type< unsigned int >( void ){ return PLY_UINT ; } template<> inline int Type< char >( void ){ return PLY_CHAR ; } template<> inline int Type< unsigned char >( void ){ return PLY_UCHAR ; } template<> inline int Type< float >( void ){ return PLY_FLOAT ; } template<> inline int Type< double >( void ){ return PLY_DOUBLE; } template< class Scalar > inline int Type( void ) { - ERROR_OUT( "Unrecognized scalar type" ); + ERROR_OUT( "Unrecognized scalar type: " , typeid(Scalar).name() ); return -1; } diff --git a/Src/PlyFile.h b/Src/PlyFile.h index 8a109e7d..7a2a6e26 100644 --- a/Src/PlyFile.h +++ b/Src/PlyFile.h @@ -164,7 +164,8 @@ struct PlyProperty std::ostream &operator << ( std::ostream &os , PlyProperty p ) { - return os << "{ " << p.name << " , " << PlyTypes[ p.external_type ] << " , " << PlyTypes[ p.internal_type ] << " , " << p.offset << " }"; + if( p.is_list ) return os << "{ " << p.name << " , " << PlyTypes[ p.count_external ] << " -> " << PlyTypes[ p.count_internal ] << " , " << PlyTypes[ p.external_type ] << " -> " << PlyTypes[ p.internal_type ] << " , " << p.offset << " }"; + else return os << "{ " << p.name << " , " << PlyTypes[ p.external_type ] << " -> " << PlyTypes[ p.internal_type ] << " , " << p.offset << " }"; } struct PlyStoredProperty diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 39924287..af9d1b25 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -45,7 +45,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "16.01" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "16.02" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file diff --git a/Src/VertexFactory.inl b/Src/VertexFactory.inl index 3d2664b1..3a4c6150 100644 --- a/Src/VertexFactory.inl +++ b/Src/VertexFactory.inl @@ -55,20 +55,22 @@ namespace VertexFactory { switch( plyType ) { - case PLY_INT: return TypeOnDisk::INT; - case PLY_UINT: return TypeOnDisk::UINT; - case PLY_CHAR: return TypeOnDisk::CHAR; - case PLY_UCHAR: return TypeOnDisk::UCHAR; - case PLY_FLOAT: return TypeOnDisk::FLOAT; - case PLY_DOUBLE: return TypeOnDisk::DOUBLE; - case PLY_INT_8: return TypeOnDisk::INT_8; - case PLY_UINT_8: return TypeOnDisk::UINT_8; - case PLY_INT_16: return TypeOnDisk::INT_16; - case PLY_UINT_16: return TypeOnDisk::UINT_16; - case PLY_INT_32: return TypeOnDisk::INT_32; - case PLY_UINT_32: return TypeOnDisk::UINT_32; - case PLY_INT_64: return TypeOnDisk::INT_64; - case PLY_UINT_64: return TypeOnDisk::UINT_64; + case PLY_INT: return TypeOnDisk::INT; + case PLY_UINT: return TypeOnDisk::UINT; + case PLY_CHAR: return TypeOnDisk::CHAR; + case PLY_UCHAR: return TypeOnDisk::UCHAR; + case PLY_FLOAT: return TypeOnDisk::FLOAT; + case PLY_DOUBLE: return TypeOnDisk::DOUBLE; + case PLY_INT_8: return TypeOnDisk::INT_8; + case PLY_UINT_8: return TypeOnDisk::UINT_8; + case PLY_INT_16: return TypeOnDisk::INT_16; + case PLY_UINT_16: return TypeOnDisk::UINT_16; + case PLY_INT_32: return TypeOnDisk::INT_32; + case PLY_UINT_32: return TypeOnDisk::UINT_32; + case PLY_INT_64: return TypeOnDisk::INT_64; + case PLY_UINT_64: return TypeOnDisk::UINT_64; + case PLY_FLOAT_32: return TypeOnDisk::FLOAT; + case PLY_FLOAT_64: return TypeOnDisk::DOUBLE; default: ERROR_OUT( "Unrecognized type: " , plyType ); } return TypeOnDisk::UNKNOWN; @@ -428,8 +430,9 @@ namespace VertexFactory template< typename Real > DynamicFactory< Real >::DynamicFactory( const std::vector< PlyProperty > &plyProperties ) { - _namesAndTypesOnDisk.resize( plyProperties.size() ); - for( int i=0 ; i( plyProperties[i].name , FromPlyType( plyProperties[i].external_type ) ); + for( int i=0 ; i( plyProperties[i].name , FromPlyType( plyProperties[i].external_type ) ) ); + else WARN( "List property not supported: " , plyProperties[i].name ); _realTypeOnDisk = true; for( unsigned int i=0 ; i<_namesAndTypesOnDisk.size() ; i++ ) _realTypeOnDisk &= GetTypeOnDisk< Real>()!=_namesAndTypesOnDisk[i].second; } From 14c8733458b7bb76fea1f08af93a1910bffb638d Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Sat, 30 Mar 2024 23:11:31 -0400 Subject: [PATCH 25/86] Version 16.03 --- README.md | 12 +++++++++--- Src/PointInterpolant.cpp | 6 +++--- Src/PoissonRecon.cpp | 8 +------- Src/PoissonReconServer.cpp | 5 ++--- Src/PreProcessor.h | 2 +- Src/SSDRecon.cpp | 8 +------- 6 files changed, 17 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 2154125c..775190f8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 16.02)

    +

    Adaptive Multigrid Solvers (Version 16.03)

    links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
    Executables: -Win64
    +Win64
    Source Code: -ZIP GitHub
    +ZIP GitHub
    Older Versions: +V16.02, V16.01, V15.10, V15.03, @@ -1459,6 +1460,11 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • Added support for additional .ply types +Version 16.03: +
      +
    1. Fixed --width compatibility bug with default depth. +
    + diff --git a/Src/PointInterpolant.cpp b/Src/PointInterpolant.cpp index fb890d74..981c019a 100644 --- a/Src/PointInterpolant.cpp +++ b/Src/PointInterpolant.cpp @@ -75,7 +75,7 @@ cmdLineParameter< int > Degree( "degree" , DEFAULT_FEM_DEGREE ) , #endif // !FAST_COMPILE Depth( "depth" , 8 ) , - SolveDepth( "solveDepth" ) , + SolveDepth( "solveDepth" , -1 ) , Iters( "iters" , 8 ) , FullDepth( "fullDepth" , 5 ) , BaseDepth( "baseDepth" ) , @@ -678,7 +678,7 @@ void Execute( UIntPack< FEMSigs ... > ) if( Width.value>0 ) { modelToUnitCube = GetBoundingBoxXForm( min , max , (Real)Width.value , (Real)( Scale.value>0 ? Scale.value : 1. ) , Depth.value ) * modelToUnitCube; - if( !SolveDepth.set ) SolveDepth.value = Depth.value; + if( !SolveDepth.set || SolveDepth.value==-1 ) SolveDepth.value = Depth.value; if( SolveDepth.value>Depth.value ) { WARN( "Solution depth cannot exceed system depth: " , SolveDepth.value , " <= " , Depth.value ); @@ -985,7 +985,7 @@ int main( int argc , char* argv[] ) if( BaseDepth.set ) WARN( "Base depth must be smaller than full depth: " , BaseDepth.value , " <= " , FullDepth.value ); BaseDepth.value = FullDepth.value; } - if( !SolveDepth.set ) SolveDepth.value = Depth.value; + if( !SolveDepth.set || SolveDepth.value==-1 ) SolveDepth.value = Depth.value; if( SolveDepth.value>Depth.value ) { WARN( "Solution depth cannot exceed system depth: " , SolveDepth.value , " <= " , Depth.value ); diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index ae4911d7..d4df809b 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -76,7 +76,7 @@ cmdLineParameter< int > #endif // !FAST_COMPILE Depth( "depth" , 8 ) , KernelDepth( "kernelDepth" ) , - SolveDepth( "solveDepth" ) , + SolveDepth( "solveDepth" , -1 ) , EnvelopeDepth( "envelopeDepth" ) , Iters( "iters" , 8 ) , FullDepth( "fullDepth" , 5 ) , @@ -611,18 +611,12 @@ int main( int argc , char* argv[] ) } if( !BaseDepth.set ) BaseDepth.value = FullDepth.value; - if( !SolveDepth.set ) SolveDepth.value = Depth.value; if( BaseDepth.value>FullDepth.value ) { if( BaseDepth.set ) WARN( "Base depth must be smaller than full depth: " , BaseDepth.value , " <= " , FullDepth.value ); BaseDepth.value = FullDepth.value; } - if( SolveDepth.value>Depth.value ) - { - WARN( "Solution depth cannot exceed system depth: " , SolveDepth.value , " <= " , Depth.value ); - SolveDepth.value = Depth.value; - } if( !KernelDepth.set ) KernelDepth.value = Depth.value-2; if( KernelDepth.value>Depth.value ) { diff --git a/Src/PoissonReconServer.cpp b/Src/PoissonReconServer.cpp index 8c9d0417..6ddd3309 100644 --- a/Src/PoissonReconServer.cpp +++ b/Src/PoissonReconServer.cpp @@ -73,7 +73,7 @@ cmdLineParameter< int > BaseVCycles( "vCycles" , 1 ) , KernelDepth( "kernelDepth" ) , BaseDepth( "baseDepth" , 5 ) , - SolveDepth( "solveDepth" ) , + SolveDepth( "solveDepth" , -1 ) , PadSize( "pad" , 4 ) , BufferSize( "buffer" , BUFFER_IO ) , Depth( "depth" , 8 ) , @@ -441,7 +441,6 @@ int main( int argc , char* argv[] ) clientReconInfo.confidence = Confidence.value; clientReconInfo.confidenceBias = ConfidenceBias.value; clientReconInfo.kernelDepth = KernelDepth.value; - clientReconInfo.solveDepth = SolveDepth.value; clientReconInfo.samplesPerNode = SamplesPerNode.value; clientReconInfo.dataX = DataX.value; clientReconInfo.density = Density.set; @@ -480,7 +479,7 @@ int main( int argc , char* argv[] ) clientReconInfo.kernelDepth = clientReconInfo.reconstructionDepth; } - clientReconInfo.solveDepth = SolveDepth.set ? SolveDepth.value : clientReconInfo.reconstructionDepth; + clientReconInfo.solveDepth = ( SolveDepth.set && SolveDepth.value!=-1 ) ? SolveDepth.value : clientReconInfo.reconstructionDepth; if( clientReconInfo.solveDepth>clientReconInfo.reconstructionDepth ) { WARN( "Solve depth cannot exceed reconstruction depth: " , clientReconInfo.solveDepth , " <= " , clientReconInfo.reconstructionDepth ); diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index af9d1b25..149d2707 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -45,7 +45,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "16.02" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "16.03" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file diff --git a/Src/SSDRecon.cpp b/Src/SSDRecon.cpp index 2fc497c2..5a784598 100644 --- a/Src/SSDRecon.cpp +++ b/Src/SSDRecon.cpp @@ -74,7 +74,7 @@ cmdLineParameter< int > #endif // !FAST_COMPILE Depth( "depth" , 8 ) , KernelDepth( "kernelDepth" ) , - SolveDepth( "solveDepth" ) , + SolveDepth( "solveDepth" , -1 ) , Iters( "iters" , 8 ) , FullDepth( "fullDepth" , 5 ) , BaseDepth( "baseDepth" ) , @@ -595,12 +595,6 @@ int main( int argc , char* argv[] ) if( BaseDepth.set ) WARN( "Base depth must be smaller than full depth: " , BaseDepth.value , " <= " , FullDepth.value ); BaseDepth.value = FullDepth.value; } - if( !SolveDepth.set ) SolveDepth.value = Depth.value; - if( SolveDepth.value>Depth.value ) - { - WARN( "Solution depth cannot exceed system depth: " , SolveDepth.value , " <= " , Depth.value ); - SolveDepth.value = Depth.value; - } ValueWeight.value *= (float)Reconstructor::SSD::WeightMultipliers[0]; GradientWeight.value *= (float)Reconstructor::SSD::WeightMultipliers[1]; From e04a91d40093dd80669afb07f7d3f586db063ee9 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Sat, 30 Mar 2024 23:56:48 -0400 Subject: [PATCH 26/86] Version 16.04 --- README.md | 12 +++++++++--- Src/FEMTree.inl | 4 ++-- Src/PreProcessor.h | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 775190f8..e6915f68 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 16.03)

    +

    Adaptive Multigrid Solvers (Version 16.04)

    links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
    Executables: -Win64
    +Win64
    Source Code: -ZIP GitHub
    +ZIP GitHub
    Older Versions: +V16.03, V16.02, V16.01, V15.10, @@ -1465,6 +1466,11 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • Fixed --width compatibility bug with default depth. +Version 16.04: +
      +
    1. Fixed --exact bug. +
    + diff --git a/Src/FEMTree.inl b/Src/FEMTree.inl index de4acafd..1995398c 100644 --- a/Src/FEMTree.inl +++ b/Src/FEMTree.inl @@ -1584,7 +1584,7 @@ template< unsigned int Dim , class Real > template< typename T , unsigned int PointD , typename ConstraintDual , typename SystemDual > void FEMTree< Dim , Real >::ExactPointInterpolationInfo< T , PointD , ConstraintDual , SystemDual >::_init( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , bool noRescale ) { - _sampleSpan.resize( tree.nodesSize() ); + _sampleSpan.resize( tree._nodeCount ); ThreadPool::Parallel_for( 0 , tree.nodesSize() , [&]( unsigned int , size_t i ){ _sampleSpan[i] = std::pair< node_index_type , node_index_type >( 0 , 0 ); } ); for( node_index_type i=0 ; i<(node_index_type)samples.size() ; i++ ) { @@ -1648,7 +1648,7 @@ template< unsigned int Dim , class Real > template< unsigned int PointD , typename ConstraintDual , typename SystemDual > void FEMTree< Dim , Real >::ExactPointInterpolationInfo< double , PointD , ConstraintDual , SystemDual >::_init( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , bool noRescale ) { - _sampleSpan.resize( tree.nodesSize() ); + _sampleSpan.resize( tree._nodeCount ); ThreadPool::Parallel_for( 0 , tree.nodesSize() , [&]( unsigned int , size_t i ){ _sampleSpan[i] = std::pair< node_index_type , node_index_type >( 0 , 0 ); } ); for( node_index_type i=0 ; i<(node_index_type)samples.size() ; i++ ) { diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 149d2707..654467d0 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -45,7 +45,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "16.03" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "16.04" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file From d0556f55b0ed3680b39992ae6ac5574a7fe911d7 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Wed, 10 Jul 2024 00:34:46 -0400 Subject: [PATCH 27/86] Version 16.05 --- AdaptiveSolvers.sln | 2 + Src/ChunkPLY.cpp | 1 + Src/PointExtent.h | 79 ++++++++++++++ Src/PointExtent.inl | 163 +++++++++++++++++++++++++++++ Src/PointPartition.h | 18 +--- Src/PointPartition.inl | 79 -------------- Src/PointPartitionClientServer.h | 3 +- Src/PointPartitionClientServer.inl | 39 +++---- Src/PoissonRecon.client.inl | 29 ++++- Src/PoissonRecon.cpp | 8 ++ Src/PoissonRecon.server.inl | 22 +++- Src/PoissonReconClient.cpp | 2 +- Src/PoissonReconClientServer.h | 4 +- Src/PoissonReconClientServer.inl | 6 ++ Src/PoissonReconServer.cpp | 15 ++- Src/PreProcessor.h | 2 +- Src/Reconstructors.h | 70 +++++-------- Src/SSDRecon.cpp | 4 + 18 files changed, 368 insertions(+), 178 deletions(-) create mode 100644 Src/PointExtent.h create mode 100644 Src/PointExtent.inl diff --git a/AdaptiveSolvers.sln b/AdaptiveSolvers.sln index dadfb963..36862735 100644 --- a/AdaptiveSolvers.sln +++ b/AdaptiveSolvers.sln @@ -64,6 +64,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Header Files", "Header File Src\Ply.h = Src\Ply.h Src\PlyFile.h = Src\PlyFile.h Src\PNG.h = Src\PNG.h + Src\PointExtent.h = Src\PointExtent.h Src\PointPartition.h = Src\PointPartition.h Src\PointPartitionClientServer.h = Src\PointPartitionClientServer.h Src\PoissonReconClientServer.h = Src\PoissonReconClientServer.h @@ -106,6 +107,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Inline Files", "Inline File Src\Ply.inl = Src\Ply.inl Src\PlyFile.inl = Src\PlyFile.inl Src\PNG.inl = Src\PNG.inl + Src\PointExtent.inl = Src\PointExtent.inl Src\PointPartition.inl = Src\PointPartition.inl Src\PointPartitionClientServer.inl = Src\PointPartitionClientServer.inl Src\PoissonRecon.client.inl = Src\PoissonRecon.client.inl diff --git a/Src/ChunkPLY.cpp b/Src/ChunkPLY.cpp index bd02016b..77b83e86 100644 --- a/Src/ChunkPLY.cpp +++ b/Src/ChunkPLY.cpp @@ -368,6 +368,7 @@ void Execute( VertexDataFactory vertexDataFactory ) { float radius = PadRadius.value * width; size_t vCount=0 , pCount=0; + for( unsigned int d=0 ; d<3 ; d++ ) min[d] -= radius , max[d] += radius; for( unsigned int d=0 ; d<3 ; d++ ) min[d] -= width/10000.f , max[d] += width/10000.f; int begin[] = { (int)floor( min[0]/width ) , (int)floor( min[1]/width ) , (int)floor( min[2]/width ) }; int end [] = { (int)ceil ( max[0]/width ) , (int)ceil ( max[1]/width ) , (int)ceil ( max[2]/width ) }; diff --git a/Src/PointExtent.h b/Src/PointExtent.h new file mode 100644 index 00000000..d85e0b34 --- /dev/null +++ b/Src/PointExtent.h @@ -0,0 +1,79 @@ +/* +Copyright (c) 2023, 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 POINT_EXTENT_INCLUDED +#define POINT_EXTENT_INCLUDED + +#include +#include "Geometry.h" + +namespace PointExtent +{ + template< typename Real , unsigned int Dim , bool ExtendedAxes > + struct Frame + { + static const unsigned int DirectionN = ExtendedAxes ? ( Dim==2 ? 4 : 9 ) : Dim; + Point< Real , Dim > directions[ DirectionN ]; + unsigned int frames[DirectionN][Dim]; + Frame( void ); + }; + + template< typename Real , unsigned int Dim , bool ExtendedAxes=true > + struct Extent + { + static const unsigned int DirectionN = Frame< Real , Dim , ExtendedAxes >::DirectionN; + static Point< Real , Dim > Direction( unsigned int d ){ return _Frame.directions[d]; } + static const unsigned int *Frame( unsigned int d ){ return _Frame.frames[d]; } + + std::pair< Real , Real > extents[ DirectionN ]; + std::pair< Real , Real > &operator[]( unsigned int d ){ return extents[d]; } + const std::pair< Real , Real > &operator[]( unsigned int d ) const { return extents[d]; } + + Extent( void ); + void add( Point< Real , Dim > p ); + Extent operator + ( const Extent &e ) const; + protected: + static const struct Frame< Real , Dim , ExtendedAxes > _Frame; + + friend std::ostream &operator << ( std::ostream & , const Extent & ); + }; + + template< typename Real , unsigned int Dim , bool ExtendedAxes > + const Frame< Real , Dim , ExtendedAxes > Extent< Real , Dim , ExtendedAxes >::_Frame; + + template< class Real , unsigned int Dim > + XForm< Real , Dim+1 > GetBoundingBoxXForm( Point< Real , Dim > min , Point< Real , Dim > max , Real scaleFactor , bool rotate=true ); + + template< class Real , unsigned int Dim , bool ExtendedAxes > + XForm< Real , Dim+1 > GetBoundingBoxXForm( const Extent< Real , Dim , ExtendedAxes > &extent , Real scaleFactor , unsigned int dir ); + + +#include "PointExtent.inl" +} + +#endif // POINT_EXTENT_INCLUDED \ No newline at end of file diff --git a/Src/PointExtent.inl b/Src/PointExtent.inl new file mode 100644 index 00000000..f06c6c98 --- /dev/null +++ b/Src/PointExtent.inl @@ -0,0 +1,163 @@ +/* +Copyright (c) 2023, 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. +*/ + + +//////////////////// +// GetBoundingBox // +//////////////////// +template< class Real , unsigned int Dim > +XForm< Real , Dim+1 > GetBoundingBoxXForm( Point< Real , Dim > min , Point< Real , Dim > max , Real scaleFactor , bool rotate ) +{ + Point< Real , Dim > center = ( max + min ) / 2; + Real scale = max[0] - min[0]; + for( int d=1 ; d( scale , max[d]-min[d] ); + scale *= scaleFactor; + for( int i=0 ; i tXForm = XForm< Real , Dim+1 >::Identity() , sXForm = XForm< Real , Dim+1 >::Identity() , rXForm = XForm< Real , Dim+1 >::Identity(); + for( int i=0 ; i(max[maxDim]-min[maxDim]) ) maxDim = i; + if( rotate ) + { + for( int i=0 ; i +XForm< Real , Dim+1 > GetBoundingBoxXForm( const Extent< Real , Dim , ExtendedAxes > &extent , Real scaleFactor , unsigned int dir ) +{ + using _Extent = Extent< Real , Dim , ExtendedAxes >; + bool rotate = ( dir >= _Extent::DirectionN ); + + if( rotate ) // Find the direction of maximal extent + { + dir = 0; + for( unsigned int d=1 ; d<_Extent::DirectionN ; d++ ) if( extent[d].second - extent[d].first > extent[dir].second - extent[dir].first ) dir = d; + } + + const unsigned int *frame = _Extent::Frame(dir); + + // Compute the rotation taking the direction of maximal extent to the last axis + XForm< Real , Dim+1 > R = XForm< Real , Dim+1 >::Identity(); + for( unsigned int c=0 ; c bBox[2]; + for( unsigned int d=0 ; d +Frame< Real , Dim , ExtendedAxes >::Frame( void ) +{ + for( unsigned int d=0 ; d( 1 , 1 )/(Real)sqrt(2.); + directions[3] = Point< Real , 2 >( 1 ,-1 )/(Real)sqrt(2.); + frames[2][0] = 2 , frames[2][1] = 3; + frames[3][0] = 3 , frames[3][1] = 2; + } + else + { + directions[3] = Point< Real , 3 >( 1 , 1 , 0 )/(Real)sqrt(2.); + directions[4] = Point< Real , 3 >( 1 , 0 , 1 )/(Real)sqrt(2.); + directions[5] = Point< Real , 3 >( 0 , 1 , 1 )/(Real)sqrt(2.); + directions[6] = Point< Real , 3 >( 1 ,-1 , 0 )/(Real)sqrt(2.); + directions[7] = Point< Real , 3 >( 1 , 0 ,-1 )/(Real)sqrt(2.); + directions[8] = Point< Real , 3 >( 0 , 1 ,-1 )/(Real)sqrt(2.); + frames[3][0] = 2 , frames[3][1] = 6 , frames[3][2] = 3; + frames[4][0] = 7 , frames[4][1] = 1 , frames[4][2] = 4; + frames[5][0] = 0 , frames[5][1] = 8 , frames[5][2] = 5; + frames[6][0] = 3 , frames[6][1] = 2 , frames[6][2] = 6; + frames[7][0] = 1 , frames[7][1] = 4 , frames[7][2] = 7; + frames[8][0] = 5 , frames[8][1] = 0 , frames[8][2] = 8; + } + } +} + +//////////// +// Extent // +//////////// +template< typename Real , unsigned int Dim , bool ExtendedAxes > +Extent< Real , Dim , ExtendedAxes >::Extent( void ) +{ + Real inf = std::numeric_limits< Real >::infinity(); + for( unsigned int d=0 ; d +void Extent< Real , Dim , ExtendedAxes >::add( Point< Real , Dim > p ) +{ + for( unsigned int d=0 ; d( extents[d].first , Point< Real , Dim >::Dot( p , _Frame.directions[d] ) ); + extents[d].second = std::max< Real >( extents[d].second , Point< Real , Dim >::Dot( p , _Frame.directions[d] ) ); + } +} + +template< typename Real , unsigned int Dim , bool ExtendedAxes > +Extent< Real , Dim , ExtendedAxes > Extent< Real , Dim , ExtendedAxes >::operator + ( const Extent &e ) const +{ + Extent _e; + for( unsigned int d=0 ; d( extents[d].first , e.extents[d].first ); + _e.extents[d].second = std::max< Real >( extents[d].second , e.extents[d].second ); + } + return _e; +} + +template< typename Real , unsigned int Dim , bool ExtendedAxes > +std::ostream &operator << ( std::ostream &os , const Extent< Real , Dim , ExtendedAxes > &e ) +{ + for( unsigned int d=0 ; d::DirectionN ; d++ ) + { + os << Extent< Real , Dim , ExtendedAxes >::_Frame.directions[d] << " : [ " << e.extents[d].first << " , " << e.extents[d].second << " ]"; + os << "\t(" << e.extents[d].second - e.extents[d].first << " )" << std::endl; + } + return os; +} diff --git a/Src/PointPartition.h b/Src/PointPartition.h index 5c25a7a0..3500bf0f 100644 --- a/Src/PointPartition.h +++ b/Src/PointPartition.h @@ -36,10 +36,10 @@ DAMAGE. #include "MyMiscellany.h" #include "Ply.h" #include "DataStream.h" +#include "PointExtent.h" #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth #define BUFFER_IO (1<<14) // Buffer the points before reading/writing -//#define AXIS_ONLY_ALIGNMENT // Only align to the three coordinate axes (should be disabled) namespace PointPartition @@ -60,22 +60,6 @@ namespace PointPartition void write( BinaryStream &stream ) const; }; - template< typename Real > - struct Extent - { -#ifdef AXIS_ONLY_ALIGNMENT - static const unsigned int DirectionN = 3; -#else // !AXIS_ONLY_ALIGNMENT - static const unsigned int DirectionN = 9; -#endif // AXIS_ONLY_ALIGNMENT - static const Point< Real , 3 > Directions[ DirectionN ]; - static const unsigned int Frames[DirectionN][3]; - std::pair< Real , Real > extents[DirectionN]; - - Extent( void ); - void add( Point< Real , 3 > p ); - Extent operator + ( const Extent &e ) const; - }; struct Partition { diff --git a/Src/PointPartition.inl b/Src/PointPartition.inl index 9a4e4e11..504a6611 100644 --- a/Src/PointPartition.inl +++ b/Src/PointPartition.inl @@ -80,85 +80,6 @@ std::string PointSetInfoName( std::string dir , std::string header ) } - -//////////// -// Extent // -//////////// -template< typename Real > -Extent< Real >::Extent( void ) -{ - Real inf = std::numeric_limits< Real >::infinity(); - for( unsigned int d=0 ; d -void Extent< Real >::add( Point< Real , 3 > p ) -{ - for( unsigned int d=0 ; d( extents[d].first , Point< Real , 3 >::Dot( p , Directions[d] ) ); - extents[d].second = std::max< Real >( extents[d].second , Point< Real , 3 >::Dot( p , Directions[d] ) ); - } -} - -template< typename Real > -Extent< Real > Extent< Real >::operator + ( const Extent< Real > &e ) const -{ - Extent _e; - for( unsigned int d=0 ; d( extents[d].first , e.extents[d].first ); - _e.extents[d].second = std::max< Real >( extents[d].second , e.extents[d].second ); - } - return _e; -} - -template< typename Real > -const Point< Real , 3 > Extent< Real >::Directions[] = -{ - Point< Real , 3 >( 1 , 0 , 0 ) , // 0 - Point< Real , 3 >( 0 , 1 , 0 ) , // 1 - Point< Real , 3 >( 0 , 0 , 1 ) , // 2 -#ifdef AXIS_ONLY_ALIGNMENT -#else // !AXIS_ONLY_ALIGNMENT - Point< Real , 3 >( 1 , 1 , 0 )/(Real)sqrt(2.) , // 3 - Point< Real , 3 >( 1 , 0 , 1 )/(Real)sqrt(2.) , // 4 - Point< Real , 3 >( 0 , 1 , 1 )/(Real)sqrt(2.) , // 5 - Point< Real , 3 >( 1 ,-1 , 0 )/(Real)sqrt(2.) , // 6 - Point< Real , 3 >( 1 , 0 ,-1 )/(Real)sqrt(2.) , // 7 - Point< Real , 3 >( 0 , 1 ,-1 )/(Real)sqrt(2.) // 8 -#endif -}; - -template< typename Real > -const unsigned int Extent< Real >::Frames[ DirectionN ][3] = -{ - {1,2,0} , - {2,0,1} , - {0,1,2} , -#ifdef AXIS_ONLY_ALIGNMENT -#else // !AXIS_ONLY_ALIGNMENT - {2,6,3} , - {7,1,4} , - {0,8,5} , - {3,2,6} , - {1,4,7} , - {5,0,8} -#endif // AXIS_ONLY_ALIGNMENT -}; - -template< typename Real > -std::ostream &operator << ( std::ostream &os , const Extent< Real > &e ) -{ - for( unsigned int d=0 ; d::DirectionN ; d++ ) - { - os << Extent< Real >::Directions[d] << " : [ " << e.extents[d].first << " , " << e.extents[d].second << " ]"; - os << "\t(" << e.extents[d].second - e.extents[d].first << " )" << std::endl; - } - return os; -} - - ////////////////// // PointSetInfo // ////////////////// diff --git a/Src/PointPartitionClientServer.h b/Src/PointPartitionClientServer.h index dc6ba771..3dd84a3d 100644 --- a/Src/PointPartitionClientServer.h +++ b/Src/PointPartitionClientServer.h @@ -36,6 +36,7 @@ DAMAGE. #include "CmdLineParser.h" #include "VertexFactory.h" #include "Reconstructors.h" +#include "PointExtent.h" namespace PointPartitionClientServer @@ -44,7 +45,7 @@ namespace PointPartitionClientServer struct ClientPartitionInfo { std::string in , tempDir , outDir , outHeader; - unsigned int slabs , filesPerDir , bufferSize , clientCount; + unsigned int slabs , filesPerDir , bufferSize , clientCount , sliceDir; Real scale; bool verbose; diff --git a/Src/PointPartitionClientServer.inl b/Src/PointPartitionClientServer.inl index ead7cfac..27d25457 100644 --- a/Src/PointPartitionClientServer.inl +++ b/Src/PointPartitionClientServer.inl @@ -161,11 +161,11 @@ std::vector< size_t > _PartitionIntoSlabs( std::string in , std::string dir , st return slabSizes; } -template< typename Real , unsigned int Dim , typename Factory > -PointPartition::Extent< Real > _GetExtent( std::string in , std::pair< size_t , size_t > range , const Factory &factory ) +template< typename Real , unsigned int Dim , typename Factory , bool ExtendedAxes=true > +PointExtent::Extent< Real , Dim , ExtendedAxes > _GetExtent( std::string in , std::pair< size_t , size_t > range , const Factory &factory ) { using Vertex = typename Factory::VertexType; - PointPartition::Extent< Real > extent; + PointExtent::Extent< Real , Dim , ExtendedAxes > extent; _ProcessPLY( in , range , factory , [&]( const Vertex &vertex ){ extent.add( vertex.template get<0>() ); } ); return extent; } @@ -238,29 +238,14 @@ std::pair< PointPartition::PointSetInfo< Real , Dim > , PointPartition::Partitio // Phase 2 // ///////////// // Merge the clients' extents and get the direction of maximal extent - PointPartition::Extent< Real > e; - unsigned int idx; - { - for( unsigned int c=0 ; c _e; - SocketStream( clientSockets[c] ).read( _e ); - e = e + _e; - } - idx = 0; - for( unsigned int d=1 ; d::DirectionN ; d++ ) if( e.extents[d].second - e.extents[d].first > e.extents[idx].second - e.extents[idx].first ) idx = d; - } - - // Compute the transformation taking the points to the unit cube + PointExtent::Extent< Real , Dim > e; + for( unsigned int c=0 ; c R = XForm< Real , Dim+1 >::Identity(); - for( unsigned int c=0 ; c::Directions[ PointPartition::Extent< Real >::Frames[idx][c] ][r]; - - Point< Real , Dim > bBox[2]; - for( unsigned int d=0 ; d<3 ; d++ ) bBox[0][d] = e.extents[ PointPartition::Extent< Real >::Frames[idx][d] ].first , bBox[1][d] = e.extents[ PointPartition::Extent< Real >::Frames[idx][d] ].second; - - pointSetInfo.modelToUnitCube = Reconstructor::GetBoundingBoxXForm( bBox[0] , bBox[1] , clientPartitionInfo.scale ) * R; + PointExtent::Extent< Real , Dim > _e; + SocketStream( clientSockets[c] ).read( _e ); + e = e + _e; } + pointSetInfo.modelToUnitCube = PointExtent::GetBoundingBoxXForm( e , clientPartitionInfo.scale , clientPartitionInfo.sliceDir ); // Send the transformation to the clients for( unsigned int c=0 ; c e = _GetExtent< Real , Dim >( clientPartitionInfo.in , ranges[i] , factory ); + PointExtent::Extent< Real , Dim > e = _GetExtent< Real , Dim >( clientPartitionInfo.in , ranges[i] , factory ); SocketStream( serverSockets[i] ).write( e ); if( clientPartitionInfo.verbose ) std::cout << "Sent extent: " << MemoryInfo::PeakMemoryUsageMB() << " (MB)" << std::endl; } @@ -426,7 +411,7 @@ void RunClients( std::vector< Socket > &serverSockets ) // ClientPartitionInfo // ///////////////////////// template< typename Real > -ClientPartitionInfo< Real >::ClientPartitionInfo( void ) : scale((Real)1.1) , verbose(false) , slabs(0) , filesPerDir(-1) , bufferSize(BUFFER_IO) , clientCount(0) {} +ClientPartitionInfo< Real >::ClientPartitionInfo( void ) : scale((Real)1.1) , sliceDir(-1) , verbose(false) , slabs(0) , filesPerDir(-1) , bufferSize(BUFFER_IO) , clientCount(0) {} template< typename Real > ClientPartitionInfo< Real >::ClientPartitionInfo( BinaryStream &stream ) @@ -447,6 +432,7 @@ ClientPartitionInfo< Real >::ClientPartitionInfo( BinaryStream &stream ) if( !stream.read( bufferSize ) ) ERROR_OUT( "Failed to read buffer size" ); if( !stream.read( scale ) ) ERROR_OUT( "Failed to read scale" ); if( !stream.read( clientCount ) ) ERROR_OUT( "Failed to read client count" ); + if( !stream.read( sliceDir ) ) ERROR_OUT( "Failed to read slice direction" ); if( !ReadBool( verbose ) ) ERROR_OUT( "Failed to read verbose flag" ); } @@ -467,5 +453,6 @@ void ClientPartitionInfo< Real >::write( BinaryStream &stream ) const stream.write( bufferSize ); stream.write( scale ); stream.write( clientCount ); + stream.write( sliceDir ); WriteBool( verbose ); } diff --git a/Src/PoissonRecon.client.inl b/Src/PoissonRecon.client.inl index fee876cd..8c0ac520 100644 --- a/Src/PoissonRecon.client.inl +++ b/Src/PoissonRecon.client.inl @@ -43,7 +43,7 @@ struct Client typedef VectorTypeUnion< Real , Point< Real , Dim > , InputSampleDataType > InputSampleType; typedef InputDataStream< InputSampleType > InputPointStream; typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; - using BoundaryData = typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions; + using BoundaryData = std::conditional_t< Dim==3 , typename LevelSetExtractor< Real , 2 , Point< Real , 2 > >::TreeSliceValuesAndVertexPositions , char >; ~Client( void ); @@ -756,7 +756,7 @@ void Client< Real , Dim , BType , Degree >::_process3( const ClientReconstructio bool needAuxData = clientReconInfo.dataX>0 && auxDataFactory.bufferSize(); - Real targetValue = (Real)0.5; + Real targetValue = clientReconInfo.targetValue; unsigned int beginIndex = _range.first , endIndex = _range.second; unsigned int beginPaddedIndex = paddedRange.first , endPaddedIndex = paddedRange.second; @@ -1135,6 +1135,7 @@ std::pair< double , double > Client< Real , Dim , BType , Degree >::_process5( c } // Set the boundary information + if constexpr( Dim==3 ) { Timer timer; using SliceSigs = typename Sigs::Reverse::Rest::Reverse; @@ -1156,6 +1157,23 @@ std::pair< double , double > Client< Real , Dim , BType , Degree >::_process5( c profiler.update(); if( clientReconInfo.verbose>1 ) std::cout << "# Set boundary info: " << timer << std::endl; } + + if( clientReconInfo.outputSolution ) + { + std::string outFileName = std::string( "solution." ) + std::to_string(_index) + std::string( ".tree" ); + if( clientReconInfo.outDir.length() ) outFileName = PointPartition::FileDir( clientReconInfo.outDir , outFileName ); + + FILE* fp = fopen( outFileName.c_str() , "wb" ); + if( !fp ) ERROR_OUT( "Failed to open file for writing: " , outFileName ); + FileStream fs(fp); + FEMTree< Dim , Real >::WriteParameter( fs ); + DenseNodeData< Real , Sigs >::WriteSignatures( fs ); + XForm< Real , Dim+1 > voxelToUnitCube = XForm< Real , Dim+1 >::Identity(); + _tree.write( fs , voxelToUnitCube , false ); + _solution.write( fs ); + fclose( fp ); + } + return isoInfo; } @@ -1165,7 +1183,7 @@ PhaseInfo Client< Real , Dim , BType , Degree >::_phase7( const ClientReconstruc PhaseInfo phaseInfo; typename Client< Real , Dim , BType , Degree >::_State7 state7; - if( clientReconInfo.mergeType!=ClientReconstructionInfo< Real , Dim >::MergeType::NONE ) + if constexpr( Dim==3 ) if( clientReconInfo.mergeType!=ClientReconstructionInfo< Real , Dim >::MergeType::NONE ) { Timer timer; phaseInfo.readBytes += _receive7( clientReconInfo , state7 , profiler ); @@ -1299,9 +1317,10 @@ void Client< Real , Dim , BType , Degree >::_process7( const ClientReconstructio AuxDataFactory auxDataFactory( clientReconInfo.auxProperties ); // Extract the mesh + if constexpr( Dim==3 ) { - if( clientReconInfo.density ) _writeMeshWithData< false , true >( clientReconInfo , state7 , _modelToUnitCube.inverse() ); - else _writeMeshWithData< false , false >( clientReconInfo , state7 , _modelToUnitCube.inverse() ); + if( clientReconInfo.density ) _writeMeshWithData< false , true >( clientReconInfo , state7 , _modelToUnitCube.inverse() ); + else _writeMeshWithData< false , false >( clientReconInfo , state7 , _modelToUnitCube.inverse() ); } if( clientReconInfo.ouputVoxelGrid ) diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index d4df809b..d598da9e 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -91,6 +91,7 @@ cmdLineParameter< int > #else // !_OPENMP ParallelType( "parallel" , (int)ThreadPool::THREAD_POOL ) , #endif // _OPENMP + AlignmentDir( "alignDir" , DEFAULT_DIMENSION-1 ) , ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , Threads( "threads" , (int)std::thread::hardware_concurrency() ); @@ -104,6 +105,7 @@ cmdLineParameter< float > ConfidenceBias( "confidenceBias" , 0.f ) , CGSolverAccuracy( "cgAccuracy" , 1e-3f ) , LowDepthCutOff( "lowDepthCutOff" , 0.f ) , + TargetValue( "targetValue" , 0.5f ) , PointWeight( "pointWeight" ); cmdLineReadable* params[] = @@ -141,6 +143,8 @@ cmdLineReadable* params[] = &ScheduleType , &ThreadChunkSize , &LowDepthCutOff , + &AlignmentDir , + &TargetValue , NULL }; @@ -167,6 +171,7 @@ void ShowUsage(char* ex) 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 , Reconstructor::Poisson::WeightMultiplier * Reconstructor::Poisson::DefaultFEMDegree ); + printf( "\t[--%s =%f]\n" , TargetValue.name , TargetValue.value ); printf( "\t[--%s =%d]\n" , Iters.name , Iters.value ); printf( "\t[--%s]\n" , ExactInterpolation.name ); printf( "\t[--%s =%f]\n" , DataX.name , DataX.value ); @@ -181,6 +186,7 @@ void ShowUsage(char* ex) printf( "\t[--%s =%f]\n" , LowDepthCutOff.name , LowDepthCutOff.value ); printf( "\t[--%s =%f]\n" , Confidence.name , Confidence.value ); printf( "\t[--%s =%f]\n" , ConfidenceBias.name , ConfidenceBias.value ); + printf( "\t[--%s =%d]\n" , AlignmentDir.name , AlignmentDir.value ); printf( "\t[--%s]\n" , NonManifold.name ); printf( "\t[--%s]\n" , PolygonMesh.name ); printf( "\t[--%s =%g]\n" , CGSolverAccuracy.name , CGSolverAccuracy.value ); @@ -324,6 +330,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) sParams.pointWeight = (Real)PointWeight.value; sParams.samplesPerNode = (Real)SamplesPerNode.value; sParams.cgSolverAccuracy = (Real)CGSolverAccuracy.value; + sParams.targetValue = (Real)TargetValue.value; sParams.depth = (unsigned int)Depth.value; sParams.baseDepth = (unsigned int)BaseDepth.value; sParams.solveDepth = (unsigned int)SolveDepth.value; @@ -332,6 +339,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) sParams.envelopeDepth = (unsigned int)EnvelopeDepth.value; sParams.baseVCycles = (unsigned int)BaseVCycles.value; sParams.iters = (unsigned int)Iters.value; + sParams.alignDir = (unsigned int)AlignmentDir.value; meParams.linearFit = LinearFit.set; meParams.outputGradients = Gradients.set; diff --git a/Src/PoissonRecon.server.inl b/Src/PoissonRecon.server.inl index c876f157..41abe0ca 100644 --- a/Src/PoissonRecon.server.inl +++ b/Src/PoissonRecon.server.inl @@ -68,7 +68,7 @@ protected: FEMTree< Dim-1 , Real > *sliceTree; XForm< Real , Dim > xForm; DenseNodeData< Real , SliceSigs > solution , dSolution; - std::vector< typename LevelSetExtractor< Real , Dim-1 >::SliceValues > sliceValues , dSliceValues; + std::vector< std::conditional_t< Dim==3 , typename LevelSetExtractor< Real , 2 >::SliceValues , char > > sliceValues , dSliceValues; std::vector< Point< Real , Dim-1 > > vertices; _State6( void ) : sliceTree(NULL) {} @@ -355,7 +355,7 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase4( const ClientReconstruc state4.constraints = state4.tree.initDenseNodeData( Sigs() ); { - Real targetValue = (Real)0.5; + Real targetValue = clientReconInfo.targetValue; state4.iInfo = new ApproximatePointInterpolationInfo( Reconstructor::Poisson::ConstraintDual< Dim , Real >( targetValue , clientReconInfo.pointWeight * cumulativePointWeight.value() ) , Reconstructor::Poisson::SystemDual< Dim , Real >( clientReconInfo.pointWeight * cumulativePointWeight.value() ) , true ); state4.iInfo->iData.reserve( state4.tree.nodesSize() ); } @@ -566,6 +566,22 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase4( const ClientReconstruc isoValue = (Real)( isoInfo.first / isoInfo.second ); } + if( clientReconInfo.outputSolution ) + { + std::string outFileName = std::string( "solution.tree" ); + if( clientReconInfo.outDir.length() ) outFileName = PointPartition::FileDir( clientReconInfo.outDir , outFileName ); + + FILE* fp = fopen( outFileName.c_str() , "wb" ); + if( !fp ) ERROR_OUT( "Failed to open file for writing: " , outFileName ); + FileStream fs(fp); + FEMTree< Dim , Real >::WriteParameter( fs ); + DenseNodeData< Real , Sigs >::WriteSignatures( fs ); + XForm< Real , Dim+1 > voxelToUnitCube = XForm< Real , Dim+1 >::Identity(); + state4.tree.write( fs , voxelToUnitCube , false ); + state4.solution.write( fs ); + fclose( fp ); + } + return phaseInfo; } @@ -578,7 +594,7 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase6( const ClientReconstruc sharedVertexCounts.resize( _clientSockets.size()-1 ); - for( unsigned int i=0 ; i<_clientSockets.size()-1 ; i++ ) + if constexpr( Dim==3 ) for( unsigned int i=0 ; i<_clientSockets.size()-1 ; i++ ) { _State6 state6; diff --git a/Src/PoissonReconClient.cpp b/Src/PoissonReconClient.cpp index 58cc5721..b10a1dc6 100644 --- a/Src/PoissonReconClient.cpp +++ b/Src/PoissonReconClient.cpp @@ -192,7 +192,7 @@ int main( int argc , char* argv[] ) Reconstruct< Real , Dim >( serverSockets ); #endif // FAST_COMPILE - Merge< Real , Dim >( serverSockets ); + if constexpr( Dim==3 ) Merge< Real , Dim >( serverSockets ); for( unsigned int i=0 ; i auxProperties; ClientReconstructionInfo( void ); diff --git a/Src/PoissonReconClientServer.inl b/Src/PoissonReconClientServer.inl index c96fcea3..b911a133 100644 --- a/Src/PoissonReconClientServer.inl +++ b/Src/PoissonReconClientServer.inl @@ -331,6 +331,8 @@ ClientReconstructionInfo< Real , Dim >::ClientReconstructionInfo( void ) mergeType = MergeType::TOPOLOGY_AND_FUNCTION; bufferSize = BUFFER_IO; filesPerDir = -1; + outputSolution = false; + targetValue = (Real)0.5; } template< typename Real , unsigned int Dim > @@ -357,6 +359,7 @@ ClientReconstructionInfo< Real , Dim >::ClientReconstructionInfo( BinaryStream & if( !stream.read( solveDepth ) ) ERROR_OUT( "Failed to read solveDepth depth" ); if( !stream.read( iters ) ) ERROR_OUT( "Failed to read iters" ); if( !stream.read( cgSolverAccuracy ) ) ERROR_OUT( "Failed to read CG-solver-accuracy" ); + if( !stream.read( targetValue ) ) ERROR_OUT( "Failed to read target-value" ); if( !stream.read( pointWeight ) ) ERROR_OUT( "Failed to read point-weight" ); if( !stream.read( confidence ) ) ERROR_OUT( "Failed to read confidence" ); if( !stream.read( confidenceBias ) ) ERROR_OUT( "Failed to read confidence-bias" ); @@ -367,6 +370,7 @@ ClientReconstructionInfo< Real , Dim >::ClientReconstructionInfo( BinaryStream & if( !stream.read( mergeType ) ) ERROR_OUT( "Failed to read merge-type" ); if( !ReadBool( density ) ) ERROR_OUT( "Failed to read density flag" ); if( !ReadBool( linearFit ) ) ERROR_OUT( "Failed to read linear-fit flag" ); + if( !ReadBool( outputSolution ) ) ERROR_OUT( "Failed to read output-solution flag" ); if( !ReadBool( ouputVoxelGrid ) ) ERROR_OUT( "Failed to read output-voxel-grid flag" ); { size_t sz; @@ -398,6 +402,7 @@ void ClientReconstructionInfo< Real , Dim >::write( BinaryStream &stream ) const stream.write( solveDepth ); stream.write( iters ); stream.write( cgSolverAccuracy ); + stream.write( targetValue ); stream.write( pointWeight ); stream.write( confidence ); stream.write( confidenceBias ); @@ -408,6 +413,7 @@ void ClientReconstructionInfo< Real , Dim >::write( BinaryStream &stream ) const stream.write( mergeType ); WriteBool( density ); WriteBool( linearFit ); + WriteBool( outputSolution ); WriteBool( ouputVoxelGrid ); { size_t sz = auxProperties.size(); diff --git a/Src/PoissonReconServer.cpp b/Src/PoissonReconServer.cpp index 6ddd3309..1eef7cf5 100644 --- a/Src/PoissonReconServer.cpp +++ b/Src/PoissonReconServer.cpp @@ -89,6 +89,7 @@ cmdLineParameter< int > ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , MergeSlabs( "merge" , MergeSlabType::SEAMLESS ) , + AlignmentDir( "alignDir" , -1 ) , Threads( "threads" , (int)std::thread::hardware_concurrency() ) ; cmdLineReadable @@ -98,6 +99,7 @@ cmdLineReadable LinearFit( "linearFit" ) , OutputVoxelGrid( "grid" ) , OutputBoundarySlices( "boundary" ) , + OutputSolution( "solution" ) , ShowDiscontinuity( "showDiscontinuity" ); cmdLineParameter< float > @@ -108,6 +110,7 @@ cmdLineParameter< float > SamplesPerNode( "samplesPerNode" , 1.5f ) , DataX( "data" , 32.f ) , PointWeight( "pointWeight" ) , + TargetValue( "targetValue" , 0.5f ) , CGSolverAccuracy( "cgAccuracy" , 1e-3f ); cmdLineReadable* params[] = @@ -128,10 +131,13 @@ cmdLineReadable* params[] = &NoLoadBalance , &Density , &LinearFit , &MergeSlabs , &Width , &Confidence , &ConfidenceBias , &SamplesPerNode , &DataX , &PointWeight , &CGSolverAccuracy , + &TargetValue , &MaxMemoryGB , &ParallelType , &ScheduleType , &ThreadChunkSize , &Threads , &PeakMemorySampleMS , &OutputVoxelGrid , &OutputBoundarySlices , + &OutputSolution , + &AlignmentDir , &ShowDiscontinuity , NULL }; @@ -164,6 +170,7 @@ void ShowUsage( char* ex ) printf( "\t[--%s =%d]\n" , Iters.name , Iters.value ); printf( "\t[--%s =%d]\n" , BaseVCycles.name , BaseVCycles.value ); printf( "\t[--%s =%g]\n" , CGSolverAccuracy.name , CGSolverAccuracy.value ); + printf( "\t[--%s =%f]\n" , TargetValue.name , TargetValue.value ); printf( "\t[--%s =%.3e * ]\n" , PointWeight.name , Reconstructor::Poisson::WeightMultiplier ); printf( "\t[--%s =%f]\n" , Confidence.name , Confidence.value ); printf( "\t[--%s =%f]\n" , ConfidenceBias.name , ConfidenceBias.value ); @@ -181,12 +188,14 @@ void ShowUsage( char* ex ) printf( "\t[--%s =%u]\n" , FilesPerDir.name , (unsigned int)FilesPerDir.value ); printf( "\t[--%s =%d]\n" , MergeSlabs.name , MergeSlabs.value ); for( unsigned int i=0 ; i=%d]\n" , AlignmentDir.name , AlignmentDir.value ); printf( "\t[--%s =%d]\n" , Verbose.name , Verbose.value ); printf( "\t[--%s]\n" , NoLoadBalance.name ); printf( "\t[--%s]\n" , Density.name ); printf( "\t[--%s]\n" , LinearFit.name ); printf( "\t[--%s]\n" , OutputVoxelGrid.name ); printf( "\t[--%s]\n" , OutputBoundarySlices.name ); + printf( "\t[--%s]\n" , OutputSolution.name ); printf( "\t[--%s]\n" , ShowDiscontinuity.name ); printf( "\t[--%s]\n" , Performance.name ); @@ -418,6 +427,7 @@ int main( int argc , char* argv[] ) clientPartitionInfo.filesPerDir = FilesPerDir.value; clientPartitionInfo.bufferSize = BufferSize.value; clientPartitionInfo.scale = Scale.value; + clientPartitionInfo.sliceDir = AlignmentDir.value; clientPartitionInfo.verbose = Verbose.value>1; pointSetInfoAndPartition = Partition< Real , Dim >( clientSockets , clientPartitionInfo , !NoLoadBalance.set , Performance.set ); } @@ -452,6 +462,8 @@ int main( int argc , char* argv[] ) default: clientReconInfo.mergeType = PoissonReconClientServer::ClientReconstructionInfo< Real , Dim >::MergeType::TOPOLOGY_AND_FUNCTION; } clientReconInfo.ouputVoxelGrid = OutputVoxelGrid.set; + clientReconInfo.targetValue = TargetValue.value; + clientReconInfo.outputSolution = OutputSolution.set; clientReconInfo.verbose = Verbose.value; clientReconInfo.filesPerDir = FilesPerDir.value; clientReconInfo.padSize = PadSize.value; @@ -497,11 +509,12 @@ int main( int argc , char* argv[] ) #endif // FAST_COMPILE } - if( Verbose.value>1 && ( MergeSlabs.value==MergeSlabType::SEAMLESS || MergeSlabs.value==MergeSlabType::TOPOLOGY_AND_FUNCTION ) ) + if constexpr( Dim==3 ) if( Verbose.value>1 && ( MergeSlabs.value==MergeSlabType::SEAMLESS || MergeSlabs.value==MergeSlabType::TOPOLOGY_AND_FUNCTION ) ) for( unsigned int i=0 ; i15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "16.04" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "16.05" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h index 78506f05..6ec5d922 100644 --- a/Src/Reconstructors.h +++ b/Src/Reconstructors.h @@ -33,6 +33,7 @@ DAMAGE. #include "MyMiscellany.h" #include "DataStream.imp.h" #include "FEMTree.h" +#include "PointExtent.h" namespace Reconstructor { @@ -238,6 +239,7 @@ namespace Reconstructor Real valueInterpolationWeight; Real samplesPerNode; Real cgSolverAccuracy; + Real targetValue; unsigned int depth; unsigned int solveDepth; unsigned int baseDepth; @@ -246,13 +248,14 @@ namespace Reconstructor unsigned int envelopeDepth; unsigned int baseVCycles; unsigned int iters; + unsigned int alignDir; SolutionParameters( void ) : verbose(false) , dirichletErode(false) , outputDensity(false) , exactInterpolation(false) , showResidual(false) , scale((Real)1.1) , confidence((Real)0.) , confidenceBias((Real)0.) , lowDepthCutOff((Real)0.) , width((Real)0.) , - pointWeight((Real)0.) , valueInterpolationWeight((Real)0.) , samplesPerNode((Real)1.5) , cgSolverAccuracy((Real)1e-3 ) , + pointWeight((Real)0.) , valueInterpolationWeight((Real)0.) , samplesPerNode((Real)1.5) , cgSolverAccuracy((Real)1e-3 ) , targetValue((Real)0.) , depth((unsigned int)8) , solveDepth((unsigned int)-1) , baseDepth((unsigned int)-1) , fullDepth((unsigned int)5) , kernelDepth((unsigned int)-1) , - envelopeDepth((unsigned int)-1) , baseVCycles((unsigned int)1) , iters((unsigned int)8) + envelopeDepth((unsigned int)-1) , baseVCycles((unsigned int)1) , iters((unsigned int)8) , alignDir(0) {} }; @@ -416,12 +419,13 @@ namespace Reconstructor unsigned int kernelDepth; unsigned int baseVCycles; unsigned int iters; + unsigned int alignDir; SolutionParameters( void ) : verbose(false) , outputDensity(false) , exactInterpolation(false) , showResidual(false) , scale((Real)1.1) , confidence((Real)0.) , confidenceBias((Real)0.) , lowDepthCutOff((Real)0.) , width((Real)0.) , pointWeight((Real)WeightMultipliers[0]) , gradientWeight((Real)WeightMultipliers[1]) , biLapWeight((Real)WeightMultipliers[2]) , samplesPerNode((Real)1.5) , cgSolverAccuracy((Real)1e-3 ) , - depth((unsigned int)8) , solveDepth((unsigned int)-1) , baseDepth((unsigned int)-1) , fullDepth((unsigned int)5) , kernelDepth((unsigned int)-1) , + depth((unsigned int)8) , solveDepth((unsigned int)-1) , baseDepth((unsigned int)-1) , fullDepth((unsigned int)5) , kernelDepth((unsigned int)-1) , alignDir(0) , baseVCycles((unsigned int)1) , iters((unsigned int)8) {} @@ -453,56 +457,38 @@ namespace Reconstructor }; }; - template< class Real , unsigned int Dim > - XForm< Real , Dim+1 > GetBoundingBoxXForm( Point< Real , Dim > min , Point< Real , Dim > max , Real scaleFactor ) - { - Point< Real , Dim > center = ( max + min ) / 2; - Real scale = max[0] - min[0]; - for( int d=1 ; d( scale , max[d]-min[d] ); - scale *= scaleFactor; - for( int i=0 ; i tXForm = XForm< Real , Dim+1 >::Identity() , sXForm = XForm< Real , Dim+1 >::Identity(); - for( int i=0 ; i(max[maxDim]-min[maxDim]) ) maxDim = i; - XForm< Real , Dim+1 > rXForm; - for( int i=0 ; i - void SetBoundingBox( InputDataStream< Point< Real , Dim > > &stream , Point< Real , Dim >& min , Point< Real , Dim >& max ) + template< class Real , unsigned int Dim , bool ExtendedAxes > + PointExtent::Extent< Real , Dim , ExtendedAxes > GetExtent( InputDataStream< Point< Real , Dim > > &stream ) { Point< Real , Dim > p; - for( unsigned int d=0 ; d::infinity() , max[d] = -std::numeric_limits< Real >::infinity(); - while( stream.read( p ) ) for( unsigned int d=0 ; d( min[d] , p[d] ) , max[d] = std::max< Real >( max[d] , p[d] ); + PointExtent::Extent< Real , Dim , ExtendedAxes > e; + while( stream.read( p ) ) e.add( p ); stream.reset(); + return e; } - template< class Real , unsigned int Dim , typename AuxData > - void SetBoundingBox( InputDataStream< VectorTypeUnion< Real , Point< Real , Dim > , AuxData > > &stream , AuxData d , Point< Real , Dim >& min , Point< Real , Dim >& max ) + template< class Real , unsigned int Dim , bool ExtendedAxes , typename AuxData > + PointExtent::Extent< Real , Dim , ExtendedAxes > GetExtent( InputDataStream< VectorTypeUnion< Real , Point< Real , Dim > , AuxData > > &stream , AuxData d ) { VectorTypeUnion< Real , Point< Real , Dim > , AuxData > p( Point< Real , Dim >() , d ); - for( unsigned int d=0 ; d::infinity() , max[d] = -std::numeric_limits< Real >::infinity(); - while( stream.read( p ) ) for( unsigned int d=0 ; d( min[d] , p.template get<0>()[d] ) , max[d] = std::max< Real >( max[d] , p.template get<0>()[d] ); + PointExtent::Extent< Real , Dim , ExtendedAxes > e; + while( stream.read( p ) ) e.add( p.template get<0>() ); stream.reset(); + return e; } - template< class Real , unsigned int Dim > - XForm< Real , Dim+1 > GetPointXForm( InputDataStream< Point< Real , Dim > > &stream , Real scaleFactor ) + template< class Real , unsigned int Dim , bool ExtendedAxes > + XForm< Real , Dim+1 > GetPointXForm( InputDataStream< Point< Real , Dim > > &stream , Real scaleFactor , unsigned int dir ) { - Point< Real , Dim > min , max; - SetBoundingBox( stream , min , max ); - return GetBoundingBoxXForm( min , max , scaleFactor ); + PointExtent::Extent< Real , Dim , ExtendedAxes > e = GetExtent< Real , Dim , ExtendedAxes >( stream ); + return PointExtent::GetBoundingBoxXForm( e , scaleFactor , dir ); } - template< class Real , unsigned int Dim , typename AuxData > - XForm< Real , Dim+1 > GetPointXForm( InputDataStream< VectorTypeUnion< Real , Point< Real , Dim > , AuxData > > &stream , AuxData d , Real scaleFactor ) + template< class Real , unsigned int Dim , bool ExtendedAxes , typename AuxData > + XForm< Real , Dim+1 > GetPointXForm( InputDataStream< VectorTypeUnion< Real , Point< Real , Dim > , AuxData > > &stream , AuxData d , Real scaleFactor , unsigned int dir ) { - Point< Real , Dim > min , max; - SetBoundingBox( stream , d , min , max ); - return GetBoundingBoxXForm( min , max , scaleFactor ); + PointExtent::Extent< Real , Dim , ExtendedAxes > e = GetExtent< Real , Dim , ExtendedAxes , AuxData >( stream , d ); + return PointExtent::GetBoundingBoxXForm( e , scaleFactor , dir ); } template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ImplicitType , unsigned int ... FEMSigs > @@ -627,7 +613,7 @@ namespace Reconstructor std::vector< typename FEMTree< Dim , Real >::PointSample > *samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); std::vector< NormalAndAuxData > *sampleNormalAndAuxData = NULL; - Real targetValue = (Real)0.5; + Real targetValue = params.targetValue; // Read in the samples (and auxiliary data) { @@ -636,7 +622,7 @@ namespace Reconstructor pointStream.reset(); sampleNormalAndAuxData = new std::vector< NormalAndAuxData >(); - modelToUnitCube = params.scale>0 ? GetPointXForm< Real , Dim >( pointStream , zeroNormalAndAuxData , params.scale ) * modelToUnitCube : modelToUnitCube; + modelToUnitCube = params.scale>0 ? GetPointXForm< Real , Dim , true >( pointStream , zeroNormalAndAuxData , params.scale , params.alignDir ) * modelToUnitCube : modelToUnitCube; if( params.width>0 ) { @@ -1087,7 +1073,7 @@ namespace Reconstructor pointStream.reset(); sampleNormalAndAuxData = new std::vector< NormalAndAuxData >(); - modelToUnitCube = params.scale>0 ? GetPointXForm< Real , Dim >( pointStream , zeroNormalAndAuxData , params.scale ) * modelToUnitCube : modelToUnitCube; + modelToUnitCube = params.scale>0 ? GetPointXForm< Real , Dim , true >( pointStream , zeroNormalAndAuxData , params.scale , params.alignDir ) * modelToUnitCube : modelToUnitCube; if( params.width>0 ) { diff --git a/Src/SSDRecon.cpp b/Src/SSDRecon.cpp index 5a784598..2df9a0ed 100644 --- a/Src/SSDRecon.cpp +++ b/Src/SSDRecon.cpp @@ -88,6 +88,7 @@ cmdLineParameter< int > #else // !_OPENMP ParallelType( "parallel" , (int)ThreadPool::THREAD_POOL ) , #endif // _OPENMP + AlignmentDir( "alignDir" , DEFAULT_DIMENSION-1 ) , ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , Threads( "threads" , (int)std::thread::hardware_concurrency() ); @@ -138,6 +139,7 @@ cmdLineReadable* params[] = &ScheduleType , &ThreadChunkSize , &LowDepthCutOff , + &AlignmentDir , NULL }; @@ -178,6 +180,7 @@ void ShowUsage(char* ex) printf( "\t[--%s =%f]\n" , Confidence.name , Confidence.value ); printf( "\t[--%s =%f]\n" , ConfidenceBias.name , ConfidenceBias.value ); printf( "\t[--%s =%f]\n" , LowDepthCutOff.name , LowDepthCutOff.value ); + printf( "\t[--%s =%d]\n" , AlignmentDir.name , AlignmentDir.value ); printf( "\t[--%s]\n" , NonManifold.name ); printf( "\t[--%s]\n" , PolygonMesh.name ); printf( "\t[--%s =%g]\n" , CGSolverAccuracy.name , CGSolverAccuracy.value ); @@ -328,6 +331,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) sParams.kernelDepth = (unsigned int)KernelDepth.value; sParams.baseVCycles = (unsigned int)BaseVCycles.value; sParams.iters = (unsigned int)Iters.value; + sParams.alignDir = (unsigned int)AlignmentDir.value; meParams.linearFit = !NonLinearFit.set; meParams.outputGradients = Gradients.set; From 3ee5f7c74e7acfb3ee8b35b3d24e682d3efa4049 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Wed, 10 Jul 2024 00:42:33 -0400 Subject: [PATCH 28/86] Update README.md --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e6915f68..68307dc0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 16.04)

    +

    Adaptive Multigrid Solvers (Version 16.05)

    links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
    Executables: -Win64
    +Win64
    Source Code: -ZIP GitHub
    +ZIP GitHub
    Older Versions: +V16.04, V16.03, V16.02, V16.01, @@ -1471,6 +1472,11 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • Fixed --exact bug. +Version 16.05: +
      +
    1. Fixed ChunkPly bug. +
    + From e398802d0bfa834c4b92e0e9f0fd237019b005e6 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Wed, 10 Jul 2024 12:04:49 -0400 Subject: [PATCH 29/86] Version 16.06 Added support for keeping client reconstructions separate --- README.md | 16 +++- Src/MergePlyClientServer.h | 2 +- Src/MergePlyClientServer.inl | 138 +++++++++++++++++------------------ Src/PoissonReconServer.cpp | 6 +- Src/PreProcessor.h | 2 +- 5 files changed, 89 insertions(+), 75 deletions(-) diff --git a/README.md b/README.md index 68307dc0..7963ac33 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 16.05)

    +

    Adaptive Multigrid Solvers (Version 16.06)

    links compilation @@ -33,6 +33,7 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo Source Code: ZIP GitHub
    Older Versions: +V16.05, V16.04, V16.03, V16.02, @@ -276,8 +277,8 @@ vertices with the x-, y-, and z-coordinates of the positions encoded by the prop The specified (networked) path is assumed to accessible to the server and all clients. -
    --out <output polygon mesh>
    -
    This string is the name of the file to which the polygon mesh will be written.
    +
    --out <output polygon mesh (header)>
    +
    This string is the name of the file to which the polygon mesh will be written (or the header, in the case --keepSeparate is specified).
    The file is written in PLY format.
    @@ -387,6 +388,10 @@ The default value for this parameter is 0.
    Enabling this flag keeps the server from fusing shared vertices across slabs. (The reconstructions from the different clients will still be merged into a single .ply file.)
    +
    [--keepSeparate] +
    Enabling this flag keeps the reconstructions computed by the clients separate. In this case, the value of --out is treated as a header and the the geometries are output to files <output header>.<client index>.ply. +
    + @@ -1477,6 +1482,11 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • Fixed ChunkPly bug. +Version 16.06: +
      +
    1. Added --keepSeparate flag to PoissonReconServer to output non-fused geometry.. +
    + diff --git a/Src/MergePlyClientServer.h b/Src/MergePlyClientServer.h index 614db6b0..da305cf2 100644 --- a/Src/MergePlyClientServer.h +++ b/Src/MergePlyClientServer.h @@ -41,7 +41,7 @@ namespace MergePlyClientServer { std::vector< PlyProperty > auxProperties; size_t bufferSize; - bool verbose; + bool keepSeparate , verbose; ClientMergePlyInfo( void ); ClientMergePlyInfo( BinaryStream &stream ); diff --git a/Src/MergePlyClientServer.inl b/Src/MergePlyClientServer.inl index ec0cac42..0918c32f 100644 --- a/Src/MergePlyClientServer.inl +++ b/Src/MergePlyClientServer.inl @@ -55,11 +55,18 @@ inline void _Copy( FILE *target , FILE *source , size_t sz , size_t bufferSize=1 DeletePointer( buffer ); } +template< typename Factory > +size_t SizeOnDisk( const Factory &factory ) +{ + size_t sizeOnDisk = 0; + if( factory.isStaticallyAllocated() ) for( unsigned int i=0 ; i void _OffsetPolygons( const Factory &factory , std::string in , std::string out , size_t offset , Profiler &profiler ) { -#if 1 -// PlyProperty faceProperty( "vertex_indices" , PLY::DefaultFileType< Index >() , PLY::DefaultFileType< Index >() , sizeof(int) , 1 , PLY::DefaultFileType< int >() , PLY::DefaultFileType< int >() , 0 ); int ft; std::vector< std::string > comments; @@ -67,11 +74,7 @@ void _OffsetPolygons( const Factory &factory , std::string in , std::string out std::vector< std::tuple< std::string , size_t , std::vector< PlyProperty > > > _elems; PlyFile *inPly = PLY::ReadHeader( in , ft , _elems ); - size_t sizeOnDisk = 0; - if( factory.isStaticallyAllocated() ) - for( unsigned int i=0 ; i vertices; - std::vector< std::vector< Index > > polygons; - - int ft; - std::vector< std::string > comments; - - PLY::ReadPolygons< Factory , Index >( in , factory , vertices , polygons , ft , comments ); - std::vector< std::tuple< std::string , size_t , std::vector< PlyProperty > > > elems(1); - std::get<0>( elems[0] ) = std::string( "face" ); - std::get<1>( elems[0] ) = polygons.size(); - std::get<2>( elems[0] ).resize(1); - std::get<2>( elems[0] )[0] = PLY::Face< Index >::Properties[0]; - - PlyFile *ply = PLY::WriteHeader( out , ft , elems , comments ); - - { - PLY::Face< Index > face; - unsigned int maxFaceVerts=3; - face.nr_vertices = 3; - face.vertices = new Index[ face.nr_vertices ]; - - ply->put_element_setup( std::string( "face" ) ); - for( size_t i=0 ; imaxFaceVerts ) - { - delete[] face.vertices; - maxFaceVerts = (unsigned int)polygons[i].size(); - face.vertices=new Index[ maxFaceVerts ]; - } - face.nr_vertices = (unsigned int)polygons[i].size(); - for( size_t j=0 ; jput_element( (void *)&face ); - } - - profiler.update(); - - delete[] face.vertices; - } - delete ply; -#endif } @@ -228,7 +188,7 @@ void _RunServer profiler.update(); } offsets[0] = 0; - for( unsigned int i=1 ; i<=sharedVertexCounts.size() ; i++ ) offsets[i] = offsets[i-1] + vNum[i-1] - sharedVertexCounts[i-1]; + for( unsigned int i=1 ; i<=sharedVertexCounts.size() ; i++ ) offsets[i] = clientMergePlyInfo.keepSeparate ? 0 : offsets[i-1] + vNum[i-1] - sharedVertexCounts[i-1]; } // Strip out the polygons (though perhaps we should just have the reconstruction code do this). @@ -237,12 +197,22 @@ void _RunServer #endif // SHOW_WARNINGS _IndexType idxType; - if( offsets.back()+vNum.back()>std::numeric_limits< int >::max() ) { - if( offsets.back()+vNum.back()>std::numeric_limits< unsigned int >::max () ) idxType = LONG_LONG; - else idxType = U_INT; + size_t maxV; + if( clientMergePlyInfo.keepSeparate ) + { + maxV = 0; + for( unsigned int i=0 ; i( maxV , vNum[i] ); + } + else maxV = offsets.back()+vNum.back(); + + if( maxV>std::numeric_limits< int >::max() ) + { + if( maxV>std::numeric_limits< unsigned int >::max () ) idxType = LONG_LONG; + else idxType = U_INT; + } + else idxType = INT; } - else idxType = INT; if( clientMergePlyInfo.verbose ) std::cout << "Got mesh info: " << profiler(true) << std::endl; @@ -285,19 +255,30 @@ void _RunServer default: ERROR_OUT( "Unrecognized output type" ); } } - PlyFile *outPly = PLY::WriteHeader( out , PLY_BINARY_NATIVE , elems ); + + std::vector< PlyFile * > outPly( clientMergePlyInfo.keepSeparate ? sharedVertexCounts.size()+1 : 1 , NULL ); + if( clientMergePlyInfo.keepSeparate ) + for( unsigned int i=0 ; i<=sharedVertexCounts.size() ; i++ ) + { + std::string fileName = out + std::string( "." ) + std::to_string(i) + std::string( ".ply" ); + std::get<1>( elems[0] ) = vNum[i]; + std::get<1>( elems[1] ) = fNum[i]; + std::pair< unsigned , unsigned int > shared; + shared.first = i>0 ? sharedVertexCounts[i-1] : 0; + shared.second = i comments(1); + comments[0] = std::string( "Shared: " ) + std::to_string( shared.first ) + std::string( "|" ) + std::to_string( shared.second ); + outPly[i] = PLY::WriteHeader( fileName , PLY_BINARY_NATIVE , elems , comments ); + } + else outPly[0] = PLY::WriteHeader( out , PLY_BINARY_NATIVE , elems ); // Write out the (merged) vertices { Pointer( char ) vBuffer = NewPointer< char >( factory.bufferSize() ); - outPly->put_element_setup( std::string( "vertex" ) ); + for( unsigned int i=0 ; iput_element_setup( std::string( "vertex" ) ); - size_t sizeOnDisk = 0; - if( factory.isStaticallyAllocated() ) - for( unsigned int i=0 ; i sharedVertices; for( unsigned int i=0 ; i<=sharedVertexCounts.size() ; i++ ) @@ -308,7 +289,7 @@ void _RunServer for( unsigned int j=0 ; j( elems[0] ).size() ; j++ ) inPly->get_property( std::get<0>( elems[0] ) , &std::get<2>( elems[0] )[j] ); - // Merge the start vertices + // Merge the start vertices with the end vertices from the previous client Vertex v = factory(); for( unsigned int j=0 ; jget_element( &v ); sharedVertices[j] = ( sharedVertices[j] + v ) / (Real)2.; - outPly->put_element( (void*)&sharedVertices[j] ); + if( clientMergePlyInfo.keepSeparate ) + { + // Write the merged vertices into the end of the previous + if( i ) outPly[i-1]->put_element( (void*)&sharedVertices[j] ); + // Write the merged vertices into the beginning of the current + outPly[i]->put_element( (void*)&sharedVertices[j] ); + } + else outPly[0]->put_element( (void*)&sharedVertices[j] ); } else { @@ -324,7 +312,14 @@ void _RunServer factory.fromBuffer( vBuffer , v ); sharedVertices[j] = ( sharedVertices[j] + v ) / (Real)2.; factory.toBuffer( sharedVertices[j] , vBuffer ); - outPly->put_element( PointerAddress( vBuffer ) ); + if( clientMergePlyInfo.keepSeparate ) + { + // Write the merged vertices into the end of the previous + if( i ) outPly[i-1]->put_element( PointerAddress( vBuffer ) ); + // Write the merged vertices into the beginning of the current + outPly[i]->put_element( PointerAddress( vBuffer ) ); + } + else outPly[0]->put_element( PointerAddress( vBuffer ) ); } } @@ -332,7 +327,7 @@ void _RunServer { size_t vNum = std::get<1>( _elems[0] ) - sharedVertices.size(); if( ifp , inPly->fp , vNum*sizeOnDisk , clientMergePlyInfo.bufferSize ); + _Copy( outPly[ clientMergePlyInfo.keepSeparate ? i : 0 ]->fp , inPly->fp , vNum*sizeOnDisk , clientMergePlyInfo.bufferSize ); } // Buffer the end vertices @@ -350,6 +345,7 @@ void _RunServer } } } + else sharedVertices.resize(0); profiler.update(); delete inPly; @@ -361,20 +357,22 @@ void _RunServer profiler.reset(); // Write out the polygons { - outPly->put_element_setup( std::string( "face" ) ); + for( unsigned int i=0 ; iput_element_setup( std::string( "face" ) ); + for( unsigned int i=0 ; i<=sharedVertexCounts.size() ; i++ ) { std::vector< std::tuple< std::string , size_t , std::vector< PlyProperty > > > _elems; int ft; PlyFile *inPly = PLY::ReadHeader( TempPolygonFile(i) , ft , _elems ); - _Copy( outPly->fp , inPly->fp , -1 , clientMergePlyInfo.bufferSize ); + _Copy( outPly[ clientMergePlyInfo.keepSeparate ? i : 0 ]->fp , inPly->fp , -1 , clientMergePlyInfo.bufferSize ); profiler.update(); delete inPly; } if( clientMergePlyInfo.verbose ) std::cout << "Merged polygons: " << profiler(true) << std::endl; } - delete outPly; + for( unsigned int i=0 ; i\n" , In.name ); printf( "\t --%s \n" , TempDir.name ); - printf( "\t --%s \n" , Out.name ); + printf( "\t --%s \n" , Out.name ); printf( "\t --%s \n" , ClientCount.name ); printf( "\t[--%s ]\n" , AddressPrefix.name ); @@ -197,6 +199,7 @@ void ShowUsage( char* ex ) printf( "\t[--%s]\n" , OutputBoundarySlices.name ); printf( "\t[--%s]\n" , OutputSolution.name ); printf( "\t[--%s]\n" , ShowDiscontinuity.name ); + printf( "\t[--%s]\n" , KeepSeparate.name ); printf( "\t[--%s]\n" , Performance.name ); } @@ -526,6 +529,7 @@ int main( int argc , char* argv[] ) } else clientMergePlyInfo.auxProperties = pointSetInfoAndPartition.first.auxiliaryProperties; clientMergePlyInfo.bufferSize = BufferSize.value; + clientMergePlyInfo.keepSeparate = KeepSeparate.set; clientMergePlyInfo.verbose = Verbose.value!=0; Merge< Real , Dim >( sharedVertexCounts , header , clientSockets , clientMergePlyInfo ); diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 802b9387..27ef2709 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -45,7 +45,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "16.05" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "16.06" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file From 4dc1d9b5fae85c87c44eef364370a8469d89826e Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Sun, 14 Jul 2024 00:06:04 -0400 Subject: [PATCH 30/86] Version 16.07 Fixed bug with the --width flag --- README.md | 12 +++++++++--- Src/ChunkPLY.cpp | 2 ++ Src/PoissonReconServer.cpp | 10 +++++++++- Src/PreProcessor.h | 2 +- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7963ac33..b23275fd 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 16.06)

    +

    Adaptive Multigrid Solvers (Version 16.07)

    links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
    Executables: -Win64
    +Win64
    Source Code: -ZIP GitHub
    +ZIP GitHub
    Older Versions: +V16.06, V16.05, V16.04, V16.03, @@ -1487,6 +1488,11 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • Added --keepSeparate flag to PoissonReconServer to output non-fused geometry.. +Version 16.07: +
      +
    1. Fixed --width bug. +
    + diff --git a/Src/ChunkPLY.cpp b/Src/ChunkPLY.cpp index 77b83e86..c9b439ec 100644 --- a/Src/ChunkPLY.cpp +++ b/Src/ChunkPLY.cpp @@ -74,6 +74,8 @@ void PrintBoundingBox( Point< float , 3 > min , Point< float , 3 > max ) for( unsigned int d=0 ; d<3 ; d++ ) printf( " %f" , min[d] ); printf( " ] [" ); for( unsigned int d=0 ; d<3 ; d++ ) printf( " %f" , max[d] ); + printf( " ] ->" ); + for( unsigned int d=0 ; d<3 ; d++ ) printf( " %.2e" , max[d]-min[d] ); printf( " ]" ); } diff --git a/Src/PoissonReconServer.cpp b/Src/PoissonReconServer.cpp index 587bde53..ccec8edd 100644 --- a/Src/PoissonReconServer.cpp +++ b/Src/PoissonReconServer.cpp @@ -439,8 +439,16 @@ int main( int argc , char* argv[] ) { if( Width.value>0 ) { + XForm< Real , Dim > unitCubeToModel = pointSetInfoAndPartition.first.modelToUnitCube.inverse(); + Real maxScale = 0; - for( unsigned int i=0 ; i( maxScale , (Real)1./pointSetInfoAndPartition.first.modelToUnitCube(i,i) ); + for( unsigned int i=0 ; imaxScale ) maxScale = l2; + } + maxScale = sqrt( maxScale ); Depth.value = (unsigned int)ceil( std::max< double >( 0. , log( maxScale/Width.value )/log(2.) ) ); } PoissonReconClientServer::ClientReconstructionInfo< Real , Dim > clientReconInfo; diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 27ef2709..85346b93 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -45,7 +45,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "16.06" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "16.07" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file From a335cb96b1f904f28489b339c7554fbc65c1df3e Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Sun, 14 Jul 2024 00:21:57 -0400 Subject: [PATCH 31/86] Version 16.07 Fixed a bug with the --width flag. --- Src/Reconstructors.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h index 6ec5d922..ce2a1369 100644 --- a/Src/Reconstructors.h +++ b/Src/Reconstructors.h @@ -626,10 +626,16 @@ namespace Reconstructor if( params.width>0 ) { - // Assuming the transformation is rigid so that the (max) scale can be pulled from the Frobenius norm + XForm< Real , Dim > unitCubeToModel = modelToUnitCube.inverse(); + Real maxScale = 0; - for( unsigned int i=0 ; imaxScale ) maxScale = l2; + } + maxScale = sqrt( maxScale ); params.depth = (unsigned int)ceil( std::max< double >( 0. , log( maxScale/params.width )/log(2.) ) ); } if( params.solveDepth>params.depth ) From 5893dce7a3b5b10d20453ec328a6b33b3d1f4810 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Wed, 17 Jul 2024 22:11:59 -0400 Subject: [PATCH 32/86] Version 16.08 Moved parameter testing into Reconstructors.h, after depth is set (in case it is set from --width). --- README.md | 16 +++++++++++----- Src/PoissonRecon.cpp | 34 ++++------------------------------ Src/PreProcessor.h | 2 +- Src/Reconstructors.h | 11 +++++++++++ Src/SSDRecon.cpp | 12 +++--------- 5 files changed, 30 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index b23275fd..fd25ba35 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 16.07)

    +

    Adaptive Multigrid Solvers (Version 16.08)

    links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
    Executables: -Win64
    +Win64
    Source Code: -ZIP GitHub
    +ZIP GitHub
    Older Versions: +V16.07, V16.06, V16.05, V16.04, @@ -1483,16 +1484,21 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • Fixed ChunkPly bug. -Version 16.06: +Version 16.06:
    1. Added --keepSeparate flag to PoissonReconServer to output non-fused geometry..
    -Version 16.07: +Version 16.07:
    1. Fixed --width bug.
    +Version 16.08: +
      +
    1. Fixed --kernelDepth bug that occured when the --width flag was used to set the reconstruction depth. +
    + diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index d598da9e..f23ff860 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -75,12 +75,12 @@ cmdLineParameter< int > Degree( "degree" , Reconstructor::Poisson::DefaultFEMDegree ) , #endif // !FAST_COMPILE Depth( "depth" , 8 ) , - KernelDepth( "kernelDepth" ) , + KernelDepth( "kernelDepth" , -1 ) , SolveDepth( "solveDepth" , -1 ) , - EnvelopeDepth( "envelopeDepth" ) , - Iters( "iters" , 8 ) , + EnvelopeDepth( "envelopeDepth" , -1 ) , FullDepth( "fullDepth" , 5 ) , - BaseDepth( "baseDepth" ) , + BaseDepth( "baseDepth" , -1 ) , + Iters( "iters" , 8 ) , BaseVCycles( "baseVCycles" , 1 ) , #ifndef FAST_COMPILE BType( "bType" , Reconstructor::Poisson::DefaultFEMBoundary+1 ) , @@ -618,32 +618,6 @@ int main( int argc , char* argv[] ) return 0; } - if( !BaseDepth.set ) BaseDepth.value = FullDepth.value; - - if( BaseDepth.value>FullDepth.value ) - { - if( BaseDepth.set ) WARN( "Base depth must be smaller than full depth: " , BaseDepth.value , " <= " , FullDepth.value ); - BaseDepth.value = FullDepth.value; - } - if( !KernelDepth.set ) KernelDepth.value = Depth.value-2; - if( KernelDepth.value>Depth.value ) - { - WARN( "Kernel depth should not exceed depth: " , KernelDepth.name , " <= " , KernelDepth.value ); - KernelDepth.value = Depth.value; - } - - if( !EnvelopeDepth.set ) EnvelopeDepth.value = BaseDepth.value; - if( EnvelopeDepth.value>Depth.value ) - { - WARN( EnvelopeDepth.name , " can't be greater than " , Depth.name , ": " , EnvelopeDepth.value , " <= " , Depth.value ); - EnvelopeDepth.value = Depth.value; - } - if( EnvelopeDepth.value= " , BaseDepth.value ); - EnvelopeDepth.value = BaseDepth.value; - } - #ifdef USE_DOUBLE typedef double Real; #else // !USE_DOUBLE diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 85346b93..6b390f59 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -45,7 +45,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "16.07" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "16.08" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h index ce2a1369..f259b064 100644 --- a/Src/Reconstructors.h +++ b/Src/Reconstructors.h @@ -659,6 +659,17 @@ namespace Reconstructor if( params.kernelDepth!=-1 ) WARN( "Kernel depth cannot exceed system depth: " , params.kernelDepth , " <= " , params.depth ); params.kernelDepth = params.depth; } + if( params.envelopeDepth==-1 ) params.envelopeDepth = params.baseDepth; + if( params.envelopeDepth>params.depth ) + { + if( params.envelopeDepth!=-1 ) WARN( "Envelope dpeth cannot exceed system depth: " , params.envelopeDepth , " <= " , params.depth ); + params.envelopeDepth = params.depth; + } + if( params.envelopeDepth= " , params.baseDepth ); + params.envelopeDepth = params.baseDepth; + } if constexpr( HasAuxData ) { diff --git a/Src/SSDRecon.cpp b/Src/SSDRecon.cpp index 2df9a0ed..6d095471 100644 --- a/Src/SSDRecon.cpp +++ b/Src/SSDRecon.cpp @@ -73,11 +73,11 @@ cmdLineParameter< int > Degree( "degree" , Reconstructor::SSD::DefaultFEMDegree ) , #endif // !FAST_COMPILE Depth( "depth" , 8 ) , - KernelDepth( "kernelDepth" ) , + KernelDepth( "kernelDepth" , -1 ) , SolveDepth( "solveDepth" , -1 ) , - Iters( "iters" , 8 ) , FullDepth( "fullDepth" , 5 ) , - BaseDepth( "baseDepth" ) , + BaseDepth( "baseDepth" , -1 ) , + Iters( "iters" , 8 ) , BaseVCycles( "baseVCycles" , 4 ) , #ifndef FAST_COMPILE BType( "bType" , Reconstructor::SSD::DefaultFEMBoundary+1 ) , @@ -593,12 +593,6 @@ int main( int argc , char* argv[] ) } if( GradientWeight.value<=0 ) ERROR_OUT( "Gradient weight must be positive: " , GradientWeight.value , "> 0" ); if( BiLapWeight.value<=0 ) ERROR_OUT( "Bi-Laplacian weight must be positive: " , BiLapWeight.value , " > 0" ); - if( !BaseDepth.set ) BaseDepth.value = FullDepth.value; - if( BaseDepth.value>FullDepth.value ) - { - if( BaseDepth.set ) WARN( "Base depth must be smaller than full depth: " , BaseDepth.value , " <= " , FullDepth.value ); - BaseDepth.value = FullDepth.value; - } ValueWeight.value *= (float)Reconstructor::SSD::WeightMultipliers[0]; GradientWeight.value *= (float)Reconstructor::SSD::WeightMultipliers[1]; From af519160baf12d0f1068ef792fbc710ad6464f4c Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Fri, 19 Jul 2024 00:05:41 -0400 Subject: [PATCH 33/86] Version 16.09 Removed dependence on mktemp --- README.md | 14 ++++++++++---- Src/AdaptiveTreeVisualization.cpp | 4 ++-- Src/MyMiscellany.h | 32 +++++++++++++------------------ Src/PointInterpolant.cpp | 4 ++-- Src/PoissonRecon.client.inl | 4 ++-- Src/PoissonRecon.cpp | 8 ++++---- Src/PreProcessor.h | 2 +- Src/Reconstructors.streams.h | 22 ++++++--------------- Src/SSDRecon.cpp | 8 ++++---- 9 files changed, 44 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index fd25ba35..01abbd45 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 16.08)

    +

    Adaptive Multigrid Solvers (Version 16.09)

    links compilation @@ -29,11 +29,12 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
    Executables: -Win64
    +Win64
    Source Code: -ZIP GitHub
    +ZIP GitHub
    Older Versions: -V16.07, +V16.08, +V16.07, V16.06, V16.05, V16.04, @@ -1499,6 +1500,11 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • Fixed --kernelDepth bug that occured when the --width flag was used to set the reconstruction depth. +Version 16.09: +
      +
    1. Removed dependence on _mktemp. +
    + diff --git a/Src/AdaptiveTreeVisualization.cpp b/Src/AdaptiveTreeVisualization.cpp index f0a1c484..5d753bb3 100644 --- a/Src/AdaptiveTreeVisualization.cpp +++ b/Src/AdaptiveTreeVisualization.cpp @@ -410,8 +410,8 @@ void _Execute( const FEMTree< Dim , Real > *tree , XForm< Real , Dim+1 > modelTo Factory factory = VInfo::GetFactory(); // A backing stream for the vertices - Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , false , false , std::string( "v_" ) ); - Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( false , true , std::string( "f_" ) ); + Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , false , false ); + Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( false , true ); { // The wrapper converting native to output types diff --git a/Src/MyMiscellany.h b/Src/MyMiscellany.h index 0b83fa97..90dc82d2 100644 --- a/Src/MyMiscellany.h +++ b/Src/MyMiscellany.h @@ -30,6 +30,8 @@ DAMAGE. #include #include +#include +#include ////////////////// // OpenMP Stuff // @@ -341,34 +343,26 @@ class FileBackedReadWriteStream struct FileDescription { FILE *fp; - char fileName[2048]; - FileDescription( void ) : fp(NULL) { fileName[0] = 0; } - FileDescription( const FileDescription &fd ) : fp(fd.fp) { strcpy( fileName , fd.fileName ); } - FileDescription( FILE *fp ) : fp(fp) { fileName[0] = 0; } - FileDescription( const char *fileHeader ) : fp(NULL) + FileDescription( FILE *fp ) : fp(fp) , _closeFile(false) { - if( fileHeader && strlen(fileHeader) ) sprintf( fileName , "%sXXXXXX" , fileHeader ); - else strcpy( fileName , "XXXXXX" ); -#ifdef _WIN32 - _mktemp( fileName ); - fp = fopen( fileName , "w+b" ); -#else // !_WIN32 - fp = fdopen( mkstemp( fileName ) , "w+b" ); -#endif // _WIN32 - if( !fp ) ERROR_OUT( "Failed to open file: " , fileName ); + if( !this->fp ) + { + this->fp = std::tmpfile(); + _closeFile = true; + if( !this->fp ) ERROR_OUT( "Failed to open temporary file" ); + } } - void remove( void ){ if( fp ){ fclose( fp ) ; fp = NULL ; std::remove( fileName ); } } + ~FileDescription( void ){ if( _closeFile ) fclose(fp); } + protected: + bool _closeFile; }; - FileBackedReadWriteStream( const char* fileHeader="" ) : _fd( fileHeader ) , _fileHandleOwner(true) {} - FileBackedReadWriteStream( FILE *fp ) : _fd(fp) , _fileHandleOwner(false) {} - ~FileBackedReadWriteStream( void ){ if( _fileHandleOwner ) _fd.remove(); } + FileBackedReadWriteStream( FILE *fp ) : _fd(fp) {} bool write( ConstPointer(char) data , size_t size ){ return fwrite( data , sizeof(char) , size , _fd.fp )==size; } bool read( Pointer(char) data , size_t size ){ return fread( data , sizeof(char) , size , _fd.fp )==size; } void reset( void ){ fseek( _fd.fp , 0 , SEEK_SET ); } protected: - bool _fileHandleOwner; FileDescription _fd; }; diff --git a/Src/PointInterpolant.cpp b/Src/PointInterpolant.cpp index 981c019a..f696979c 100644 --- a/Src/PointInterpolant.cpp +++ b/Src/PointInterpolant.cpp @@ -363,8 +363,8 @@ void ExtractLevelSet Factory factory = VInfo::GetFactory(); // A backing stream for the vertices - Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , false , false , std::string( "v_" ) ); - Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( false , true , std::string( "f_" ) ); + Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , false , false ); + Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( false , true ); typename LevelSetExtractor< Real , Dim >::Stats stats; { diff --git a/Src/PoissonRecon.client.inl b/Src/PoissonRecon.client.inl index 8c0ac520..8cfc1e42 100644 --- a/Src/PoissonRecon.client.inl +++ b/Src/PoissonRecon.client.inl @@ -1258,8 +1258,8 @@ void Client< Real , Dim , BType , Degree >::_writeMeshWithData( const ClientReco Factory factory = VInfo::GetFactory( auxDataFactory ); // A backing stream for the vertices - Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , false , false , tempHeader + std::string( "v_" ) ); - Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( false , true , tempHeader + std::string( "f_" ) ); + Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , false , false ); + Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( false , true ); typename LevelSetExtractor< Real , Dim , AuxData >::Stats stats; diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index f23ff860..262bb281 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -220,8 +220,8 @@ void WriteMesh Factory factory = VInfo::GetFactory(); // A backing stream for the vertices - Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , inCore , false , std::string( "v_" ) ); - Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( inCore , true , std::string( "f_" ) ); + Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , inCore , false ); + Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( inCore , true ); { // The wrapper converting native to output types @@ -255,8 +255,8 @@ void WriteMeshWithData Factory factory = VInfo::GetFactory( auxDataFactory ); // A backing stream for the vertices - Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , inCore , false , std::string( "v_" ) ); - Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( inCore , true , std::string( "f_" ) ); + Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , inCore , false ); + Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( inCore , true ); { // The wrapper converting native to output types diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 6b390f59..5a34cf43 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -45,7 +45,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "16.08" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "16.09" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file diff --git a/Src/Reconstructors.streams.h b/Src/Reconstructors.streams.h index 54e544cf..6432a6eb 100644 --- a/Src/Reconstructors.streams.h +++ b/Src/Reconstructors.streams.h @@ -394,7 +394,7 @@ struct OutputInputFaceStream : public OutputFaceStream< FaceDim > , public Input void base_write( const Face< FaceDim > &f ){ outStream->write(f); } void base_write( unsigned int t , const Face< FaceDim > &f ){ outStream->write(t,f); } - OutputInputFaceStream( bool inCore , bool multi , std::string header="" ) + OutputInputFaceStream( bool inCore , bool multi ) { size_t sz = std::thread::hardware_concurrency(); @@ -433,7 +433,7 @@ struct OutputInputFaceStream : public OutputFaceStream< FaceDim > , public Input { for( unsigned int i=0 ; i >( _backingFiles[i]->fp ); _outStreams[i] = new FileBackedOutputDataStream< Face< FaceDim > >( _backingFiles[i]->fp ); } @@ -442,7 +442,7 @@ struct OutputInputFaceStream : public OutputFaceStream< FaceDim > , public Input } else { - _backingFile = new FileBackedReadWriteStream::FileDescription( header.c_str() ); + _backingFile = new FileBackedReadWriteStream::FileDescription( NULL ); inStream = new FileBackedInputDataStream< Face< FaceDim > >( _backingFile->fp ); outStream = new FileBackedOutputDataStream< Face< FaceDim > >( _backingFile->fp ); } @@ -454,17 +454,12 @@ struct OutputInputFaceStream : public OutputFaceStream< FaceDim > , public Input size_t sz = std::thread::hardware_concurrency(); delete _backingVector; - - if( _backingFile ) _backingFile->remove(); delete _backingFile; for( unsigned int i=0 ; iremove(); delete _backingFiles[i]; - delete _inStreams[i]; delete _outStreams[i]; } @@ -493,7 +488,7 @@ struct OutputInputFactoryTypeStream : public OutputDataStream< typename Factory: void base_write( const Vertex &v ){ outStream->write( v ); } bool base_read( Vertex &v ){ return inStream->read( v ); } - OutputInputFactoryTypeStream( Factory &factory , bool inCore , bool multi , std::string header="" ) + OutputInputFactoryTypeStream( Factory &factory , bool inCore , bool multi ) { size_t sz = std::thread::hardware_concurrency(); @@ -533,7 +528,7 @@ struct OutputInputFactoryTypeStream : public OutputDataStream< typename Factory: { for( unsigned int i=0 ; i( _backingFiles[i]->fp , factory ); _outStreams[i] = new FileBackedOutputFactoryTypeStream< Factory >( _backingFiles[i]->fp , factory ); } @@ -542,8 +537,7 @@ struct OutputInputFactoryTypeStream : public OutputDataStream< typename Factory: } else { - _backingFile = new FileBackedReadWriteStream::FileDescription( header.c_str() ); - + _backingFile = new FileBackedReadWriteStream::FileDescription( NULL ); inStream = new FileBackedInputFactoryTypeStream< Factory >( _backingFile->fp , factory ); outStream = new FileBackedOutputFactoryTypeStream< Factory >( _backingFile->fp , factory ); } @@ -555,16 +549,12 @@ struct OutputInputFactoryTypeStream : public OutputDataStream< typename Factory: size_t sz = std::thread::hardware_concurrency(); delete _backingVector; - if( _backingFile ) _backingFile->remove(); delete _backingFile; for( unsigned int i=0 ; iremove(); delete _backingFiles[i]; - delete _inStreams[i]; delete _outStreams[i]; } diff --git a/Src/SSDRecon.cpp b/Src/SSDRecon.cpp index 6d095471..1a04a9fd 100644 --- a/Src/SSDRecon.cpp +++ b/Src/SSDRecon.cpp @@ -213,8 +213,8 @@ void WriteMesh Factory factory = VInfo::GetFactory(); // A backing stream for the vertices - Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , inCore , false , std::string( "v_" ) ); - Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( inCore , true , std::string( "f_" ) ); + Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , inCore , false ); + Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( inCore , true ); { // The wrapper converting native to output types @@ -248,8 +248,8 @@ void WriteMeshWithData Factory factory = VInfo::GetFactory( auxDataFactory ); // A backing stream for the vertices - Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , inCore , false , std::string( "v_" ) ); - Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( inCore , true , std::string( "f_" ) ); + Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , inCore , false ); + Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( inCore , true ); { // The wrapper converting native to output types From 6cb2a8186db2e8293027026beeec29e44131fc99 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Tue, 30 Jul 2024 00:38:53 -0400 Subject: [PATCH 34/86] Version 16.10 Added support for half-space chunking --- README.md | 12 +++- Src/ChunkPLY.cpp | 41 +++++++---- Src/CmdLineParser.h | 27 ++++++-- Src/CmdLineParser.inl | 129 ++++++++++++++++++++++++----------- Src/MergePlyClientServer.h | 4 +- Src/MergePlyClientServer.inl | 20 ++++-- Src/PointExtent.h | 3 +- Src/PointPartition.h | 1 + Src/PointPartition.inl | 2 + Src/PoissonReconServer.cpp | 68 +++++++++++++++++- Src/PreProcessor.h | 2 +- Src/SurfaceTrimmer.cpp | 8 ++- 12 files changed, 241 insertions(+), 76 deletions(-) diff --git a/README.md b/README.md index 01abbd45..e009c57c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 16.09)

    +

    Adaptive Multigrid Solvers (Version 16.10)

    links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
    Executables: -Win64
    +Win64
    Source Code: -ZIP GitHub
    +ZIP GitHub
    Older Versions: +V16.09, V16.08, V16.07, V16.06, @@ -1505,6 +1506,11 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • Removed dependence on _mktemp. +Version 16.10: +
      +
    1. Removed dependence on _mktemp. +
    + diff --git a/Src/ChunkPLY.cpp b/Src/ChunkPLY.cpp index c9b439ec..66edc9cf 100644 --- a/Src/ChunkPLY.cpp +++ b/Src/ChunkPLY.cpp @@ -49,9 +49,10 @@ cmdLineParameters< char* > In( "in" ); cmdLineParameter< char* > Out( "out" ); cmdLineParameter< float > Width( "width" , -1.f ) , PadRadius( "radius" , 0.f ); cmdLineParameterArray< float , 6 > BoundingBox( "bBox" ); +cmdLineParameters< Point< float , 4 > > HalfSpaces( "halfSpaces" ); cmdLineReadable ASCII( "ascii" ) , Verbose( "verbose" ) , NoNormals( "noNormals" ) , Colors( "colors" ) , Values( "values" ); -cmdLineReadable* params[] = { &In , &Out , &Width , &PadRadius , &ASCII , &Verbose , &BoundingBox , &NoNormals , &Colors , &Values , NULL }; +cmdLineReadable* params[] = { &In , &Out , &Width , &PadRadius , &ASCII , &Verbose , &BoundingBox , &NoNormals , &Colors , &Values , &HalfSpaces , NULL }; void ShowUsage( char* ex ) { @@ -61,6 +62,7 @@ void ShowUsage( char* ex ) printf( "\t[--%s =%f]\n" , Width.name , Width.value ); printf( "\t[--%s =%f]\n" , PadRadius.name , PadRadius.value ); printf( "\t[--%s ]\n" , BoundingBox.name ); + printf( "\t[--%s ]\n" , HalfSpaces.name ); printf( "\t[--%s]\n" , NoNormals.name ); printf( "\t[--%s]\n" , Colors.name ); printf( "\t[--%s]\n" , Values.name ); @@ -278,17 +280,28 @@ void Execute( VertexDataFactory vertexDataFactory ) float width = Width.value; - if( BoundingBox.set ) + if( BoundingBox.set || HalfSpaces.set ) { - Point< float , 3 > min( BoundingBox.values[0] , BoundingBox.values[1] , BoundingBox.values[2] ); - Point< float , 3 > max( BoundingBox.values[3] , BoundingBox.values[4] , BoundingBox.values[5] ); - auto InBoundingBox = [&]( Point< float , 3 > p ) + Point< float , 3 > min , max; + + if( BoundingBox.set ) { - return - p[0]>=min[0] && p[0]=min[1] && p[1]=min[2] && p[2]( BoundingBox.values[0] , BoundingBox.values[1] , BoundingBox.values[2] ); + max = Point< float , 3 >( BoundingBox.values[3] , BoundingBox.values[4] , BoundingBox.values[5] ); + } + + auto Inside = [&]( Point< float , 3 > p ) + { + bool inside = true; + if( BoundingBox.set ) inside &= p[0]>=min[0] && p[0]=min[1] && p[1]=min[2] && p[2] _p( p[0] , p[1] , p[2] , 1.f ); + for( unsigned int i=0 ; i::Dot( _p , HalfSpaces.values[i] )<=0; + } + return inside; + }; + if( polygons.size() ) { std::vector< std::vector< long long > > _polygons; @@ -302,7 +315,7 @@ void Execute( VertexDataFactory vertexDataFactory ) Point< float , 3 > center; for( int j=0 ; j(); center /= polygons[i].size(); - if( InBoundingBox( center ) ) polygonCount++; + if( Inside( center ) ) polygonCount++; } _polygons.reserve( polygonCount ); } @@ -312,7 +325,7 @@ void Execute( VertexDataFactory vertexDataFactory ) Point< float , 3 > center; for( int j=0 ; j(); center /= polygons[i].size(); - if( InBoundingBox( center ) ) _polygons.push_back( polygons[i] ); + if( Inside( center ) ) _polygons.push_back( polygons[i] ); } printf( "\tChunked polygons:\n" ); printf( "\t\tTime (Wall/CPU): %.2f / %.2f\n" , timer.wallTime() , timer.cpuTime() ); @@ -342,12 +355,12 @@ void Execute( VertexDataFactory vertexDataFactory ) #ifdef NEW_CHUNKS { size_t vertexCount = 0; - for( size_t i=0 ; i() ) ) vertexCount++; + for( size_t i=0 ; i() ) ) vertexCount++; _vertices.reserve( vertexCount ); } #endif // NEW_CHUNKS - for( size_t i=0 ; i() ) ) _vertices.push_back( vertices[i] ); + for( size_t i=0 ; i() ) ) _vertices.push_back( vertices[i] ); printf( "\tChunked vertices:\n" ); printf( "\t\tTime (Wall/CPU): %.2f / %.2f\n" , timer.wallTime() , timer.cpuTime() ); printf( "\t\tPeak Memory (MB): %d\n" , MemoryInfo::PeakMemoryUsageMB() ); diff --git a/Src/CmdLineParser.h b/Src/CmdLineParser.h index a1fbd0e3..f71b55c2 100644 --- a/Src/CmdLineParser.h +++ b/Src/CmdLineParser.h @@ -34,6 +34,7 @@ DAMAGE. #include #include #include +#include "Geometry.h" #ifdef WIN32 int strcasecmp( const char* c1 , const char* c2 ); @@ -50,12 +51,28 @@ class cmdLineReadable virtual void writeValue( char* str ) const; }; -template< class Type > void cmdLineWriteValue( Type t , char* str ); -template< class Type > void cmdLineCleanUp( Type* t ); -template< class Type > Type cmdLineInitialize( void ); -template< class Type > Type cmdLineCopy( Type t ); -template< class Type > Type cmdLineStringToType( const char* str ); +template< typename Type > struct CmdLineType; +template< typename Type > +struct CmdLineType +{ + static void WriteValue( Type t , char* str ); + static void CleanUp( Type* t ){} + static Type Initialize( void ){ return Type(); } + static Type Copy( Type t ){ return t; } + static Type StringToType( const char *str ); +}; + +template< typename Real , unsigned int Dim > +struct CmdLineType< Point< Real , Dim > > +{ + using Type = Point< Real , Dim >; + static void WriteValue( Type t , char* str ); + static void CleanUp( Type* t ){} + static Type Initialize( void ){ return Type(); } + static Type Copy( Type t ){ return t; } + static Type StringToType( const char *str ); +}; template< class Type > class cmdLineParameter : public cmdLineReadable { diff --git a/Src/CmdLineParser.inl b/Src/CmdLineParser.inl index a81566cc..7435192b 100644 --- a/Src/CmdLineParser.inl +++ b/Src/CmdLineParser.inl @@ -33,39 +33,81 @@ DAMAGE. inline int strcasecmp( const char* c1 , const char* c2 ){ return _stricmp( c1 , c2 ); } #endif // WIN32 || _WIN64 -template< > void cmdLineCleanUp< int >( int* t ){ } -template< > void cmdLineCleanUp< float >( float* t ){ } -template< > void cmdLineCleanUp< double >( double* t ){ } -template< > void cmdLineCleanUp< char* >( char** t ){ if( *t ) free( *t ) ; *t = NULL; } -template< > void cmdLineCleanUp< std::string >( std::string* t ){ } -template< > int cmdLineInitialize< int >( void ){ return 0; } -template< > float cmdLineInitialize< float >( void ){ return 0.f; } -template< > double cmdLineInitialize< double >( void ){ return 0.; } -template< > char* cmdLineInitialize< char* >( void ){ return NULL; } -template< > std::string cmdLineInitialize< std::string >( void ){ return std::string(); } -template< > void cmdLineWriteValue< int >( int t , char* str ){ sprintf( str , "%d" , t ); } -template< > void cmdLineWriteValue< float >( float t , char* str ){ sprintf( str , "%f" , t ); } -template< > void cmdLineWriteValue< double >( double t , char* str ){ sprintf( str , "%f" , t ); } -template< > void cmdLineWriteValue< char* >( char* t , char* str ){ if( t ) sprintf( str , "%s" , t ) ; else str[0]=0; } -template< > void cmdLineWriteValue< std::string >( std::string t , char* str ){ sprintf( str , "%s" , t.c_str() ); } -template< > int cmdLineCopy( int t ){ return t; } -template< > float cmdLineCopy( float t ){ return t; } -template< > double cmdLineCopy( double t ){ return t; } +template< > void CmdLineType< char* >::CleanUp( char** t ){ if( *t ) free( *t ) ; *t = NULL; } + +template< > int CmdLineType< int >::Initialize( void ){ return 0; } +template< > float CmdLineType< float >::Initialize( void ){ return 0.f; } +template< > double CmdLineType< double >::Initialize( void ){ return 0.; } +template< > char* CmdLineType< char* >::Initialize( void ){ return NULL; } + +template< > void CmdLineType< int >::WriteValue( int t , char* str ){ sprintf( str , "%d" , t ); } +template< > void CmdLineType< float >::WriteValue( float t , char* str ){ sprintf( str , "%f" , t ); } +template< > void CmdLineType< double >::WriteValue( double t , char* str ){ sprintf( str , "%f" , t ); } +template< > void CmdLineType< char* >::WriteValue( char* t , char* str ){ if( t ) sprintf( str , "%s" , t ) ; else str[0]=0; } +template< > void CmdLineType< std::string >::WriteValue( std::string t , char* str ){ sprintf( str , "%s" , t.c_str() ); } +template< typename Real , unsigned int Dim > +void CmdLineType< Point< Real , Dim > >::WriteValue( Point< Real , Dim > t , char *str ) +{ + size_t start = 0; + sprintf( str , "{" ); + start = strlen( str ); + for( unsigned int d=0 ; d char* cmdLineCopy( char* t ){ return _strdup( t ); } +template< > char* CmdLineType< char* >::Copy( char* t ){ return _strdup( t ); } #else // !WIN32 && !_WIN64 -template< > char* cmdLineCopy( char* t ){ return strdup( t ); } +template< > char* CmdLineType< char* >::Copy( char* t ){ return strdup( t ); } #endif // WIN32 || _WIN64 -template< > std::string cmdLineCopy( std::string t ){ return t; } -template< > int cmdLineStringToType( const char* str ){ return atoi( str ); } -template< > float cmdLineStringToType( const char* str ){ return float( atof( str ) ); } -template< > double cmdLineStringToType( const char* str ){ return double( atof( str ) ); } + +template< > int CmdLineType< int >::StringToType( const char* str ){ return atoi( str ); } +template< > float CmdLineType< float >::StringToType( const char* str ){ return float( atof( str ) ); } +template< > double CmdLineType< double >::StringToType( const char* str ){ return double( atof( str ) ); } #if defined( WIN32 ) || defined( _WIN64 ) -template< > char* cmdLineStringToType( const char* str ){ return _strdup( str ); } +template< > char* CmdLineType< char* >::StringToType( const char* str ){ return _strdup( str ); } #else // !WIN32 && !_WIN64 -template< > char* cmdLineStringToType( const char* str ){ return strdup( str ); } +template< > char* CmdLineType< char* >::StringToType( const char* str ){ return strdup( str ); } #endif // WIN32 || _WIN64 -template< > std::string cmdLineStringToType( const char* str ){ return std::string( str ); } +template< > std::string CmdLineType< std::string >::StringToType( const char* str ){ return std::string( str ); } + +template< typename Real , unsigned int Dim > +Point< Real , Dim > CmdLineType< Point< Real , Dim > >::StringToType( const char *str ) +{ + Point< Real , Dim > t; + + char *_str = new char[ strlen(str)+1 ]; + assert( _str ); + strcpy( _str , str ); + char *temp = strtok( _str , "," ); + + unsigned int d = 0; + while( temp!=NULL ) + { + if( d==0 ) + { + if( temp[0]!='{' ) ERROR_OUT( "Expected opening brace: " , std::string( str ) ); + t[d++] = CmdLineType< Real >::StringToType( temp+1 ); + } + else if( d==Dim-1 ) + { + if( temp[ strlen(temp)-1 ]!='}' ) ERROR_OUT( "Expected closing brace: " , std::string( str ) ); + temp[ strlen(temp)-1 ] = 0; + t[d++] = CmdLineType< Real >::StringToType( temp ); + break; + } + else t[d++] = CmdLineType< Real >::StringToType( temp ); + temp = strtok( NULL ,"," ); + } + if( d cmdLineParameter< Type >::~cmdLineParameter( void ) { cmdLineCleanUp( &value ); } -template< class Type > cmdLineParameter< Type >::cmdLineParameter( const char *name ) : cmdLineReadable( name ){ value = cmdLineInitialize< Type >(); } -template< class Type > cmdLineParameter< Type >::cmdLineParameter( const char *name , Type v ) : cmdLineReadable( name ){ value = cmdLineCopy< Type >( v ); } +template< class Type > cmdLineParameter< Type >::~cmdLineParameter( void ) { CmdLineType< Type >::CleanUp( &value ); } +template< class Type > cmdLineParameter< Type >::cmdLineParameter( const char *name ) : cmdLineReadable( name ){ value = CmdLineType< Type >::Initialize(); } +template< class Type > cmdLineParameter< Type >::cmdLineParameter( const char *name , Type v ) : cmdLineReadable( name ){ value = CmdLineType< Type >::Copy( v ); } template< class Type > int cmdLineParameter< Type >::read( char** argv , int argc ) { if( argc>0 ) { - cmdLineCleanUp< Type >( &value ) , value = cmdLineStringToType< Type >( argv[0] ); + CmdLineType< Type >::CleanUp( &value ); + value = CmdLineType< Type >::StringToType( argv[0] ); set = true; return 1; } else return 0; } template< class Type > -void cmdLineParameter< Type >::writeValue( char* str ) const { cmdLineWriteValue< Type >( value , str ); } +void cmdLineParameter< Type >::writeValue( char* str ) const { CmdLineType< Type >::WriteValue( value , str ); } /////////////////////////// @@ -108,17 +151,19 @@ void cmdLineParameter< Type >::writeValue( char* str ) const { cmdLineWriteValue template< class Type , int Dim > cmdLineParameterArray< Type , Dim >::cmdLineParameterArray( const char *name , const Type* v ) : cmdLineReadable( name ) { - if( v ) for( int i=0 ; i( v[i] ); - else for( int i=0 ; i(); + if( v ) for( int i=0 ; i::Copy( v[i] ); + else for( int i=0 ; i::Initialize(); } + template< class Type , int Dim > -cmdLineParameterArray< Type , Dim >::~cmdLineParameterArray( void ){ for( int i=0 ; i( values+i ); } +cmdLineParameterArray< Type , Dim >::~cmdLineParameterArray( void ){ for( int i=0 ; i::CleanUp( values+i ); } + template< class Type , int Dim > int cmdLineParameterArray< Type , Dim >::read( char** argv , int argc ) { if( argc>=Dim ) { - for( int i=0 ; i( values+i ) , values[i] = cmdLineStringToType< Type >( argv[i] ); + for( int i=0 ; i::CleanUp( values+i ) , values[i] = CmdLineType< Type >::StringToType( argv[i] ); set = true; return Dim; } @@ -130,7 +175,7 @@ void cmdLineParameterArray< Type , Dim >::writeValue( char* str ) const char* temp=str; for( int i=0 ; i( values[i] , temp ); + CmdLineType< Type >::WriteValue( values[i] , temp ); temp = str+strlen( str ); } } @@ -139,6 +184,7 @@ void cmdLineParameterArray< Type , Dim >::writeValue( char* str ) const /////////////////////// template< class Type > cmdLineParameters< Type >::cmdLineParameters( const char* name ) : cmdLineReadable( name ) , values(NULL) , count(0) { } + template< class Type > cmdLineParameters< Type >::~cmdLineParameters( void ) { @@ -146,6 +192,7 @@ cmdLineParameters< Type >::~cmdLineParameters( void ) values = NULL; count = 0; } + template< class Type > int cmdLineParameters< Type >::read( char** argv , int argc ) { @@ -158,27 +205,27 @@ int cmdLineParameters< Type >::read( char** argv , int argc ) if( count <= 0 || argc <= count ) return 1; values = new Type[count]; if( !values ) return 0; - for( int i=0 ; i( argv[i+1] ); + for( int i=0 ; i::StringToType( argv[i+1] ); set = true; return count+1; } else return 0; } + template< class Type > void cmdLineParameters< Type >::writeValue( char* str ) const { char* temp=str; - cmdLineWriteValue< int >( count , temp ); + CmdLineType< int >::WriteValue( count , temp ); temp = str + strlen( str ); for( int i=0 ; i( values[i] , temp ); + CmdLineType< Type >::WriteValue( values[i] , temp ); temp = str+strlen( str ); } } - inline char* FileExtension( char* fileName ) { char* temp = fileName; diff --git a/Src/MergePlyClientServer.h b/Src/MergePlyClientServer.h index da305cf2..22b48de2 100644 --- a/Src/MergePlyClientServer.h +++ b/Src/MergePlyClientServer.h @@ -30,6 +30,7 @@ DAMAGE. #define MERGE_PLY_CLIENT_SERVER_INCLUDED #include +#include #include "Socket.h" #include "MyMiscellany.h" #include "CmdLineParser.h" @@ -59,7 +60,8 @@ namespace MergePlyClientServer std::vector< Socket > &clientSockets , const std::vector< unsigned int > &sharedVertexCounts , ClientMergePlyInfo clientMergePlyInfo , - unsigned int sampleMS + unsigned int sampleMS , + std::function< std::vector< std::string > (unsigned int) > commentFunctor=[](unsigned int){ return std::vector< std::string >(); } ); template< typename Real , unsigned int Dim > diff --git a/Src/MergePlyClientServer.inl b/Src/MergePlyClientServer.inl index 0918c32f..700a28d4 100644 --- a/Src/MergePlyClientServer.inl +++ b/Src/MergePlyClientServer.inl @@ -151,7 +151,8 @@ void _RunServer const std::vector< unsigned int > &sharedVertexCounts , ClientMergePlyInfo clientMergePlyInfo , const Factory &factory , - unsigned int sampleMS + unsigned int sampleMS , + std::function< std::vector< std::string > (unsigned int) > commentFunctor ) { Profiler profiler(sampleMS); @@ -266,11 +267,17 @@ void _RunServer std::pair< unsigned , unsigned int > shared; shared.first = i>0 ? sharedVertexCounts[i-1] : 0; shared.second = i comments(1); + std::vector< std::string > _comments = commentFunctor( i ); + std::vector< std::string > comments( 1+_comments.size() ); comments[0] = std::string( "Shared: " ) + std::to_string( shared.first ) + std::string( "|" ) + std::to_string( shared.second ); + for( unsigned int j=0 ; j<_comments.size() ; j++ ) comments[j+1] = _comments[j]; outPly[i] = PLY::WriteHeader( fileName , PLY_BINARY_NATIVE , elems , comments ); } - else outPly[0] = PLY::WriteHeader( out , PLY_BINARY_NATIVE , elems ); + else + { + std::vector< std::string > comments = commentFunctor(-1); + outPly[0] = PLY::WriteHeader( out , PLY_BINARY_NATIVE , elems , comments ); + } // Write out the (merged) vertices { @@ -391,7 +398,8 @@ void RunServer std::vector< Socket > &clientSockets , const std::vector< unsigned int > &sharedVertexCounts , ClientMergePlyInfo clientMergePlyInfo , - unsigned int sampleMS + unsigned int sampleMS , + std::function< std::vector< std::string > (unsigned int) > commentFunctor ) { if( clientSockets.size()!=sharedVertexCounts.size()+1 ) ERROR_OUT( "Socket num and shared vertex count don't match: " , clientSockets.size() , " / " , sharedVertexCounts.size() ); @@ -408,13 +416,13 @@ void RunServer VertexFactory::PositionFactory< Real , Dim > vFactory; VertexFactory::DynamicFactory< Real > dFactory( clientMergePlyInfo.auxProperties ); Factory factory( vFactory , dFactory ); - _RunServer< Real , Dim >( inDir , tempDir , header , out , clientSockets , sharedVertexCounts , clientMergePlyInfo , factory , sampleMS ); + _RunServer< Real , Dim >( inDir , tempDir , header , out , clientSockets , sharedVertexCounts , clientMergePlyInfo , factory , sampleMS , commentFunctor ); } else { typedef VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > > Factory; Factory factory; - _RunServer< Real , Dim >( inDir , tempDir , header , out , clientSockets , sharedVertexCounts , clientMergePlyInfo , factory , sampleMS ); + _RunServer< Real , Dim >( inDir , tempDir , header , out , clientSockets , sharedVertexCounts , clientMergePlyInfo , factory , sampleMS , commentFunctor ); } } diff --git a/Src/PointExtent.h b/Src/PointExtent.h index d85e0b34..5e1b05c8 100644 --- a/Src/PointExtent.h +++ b/Src/PointExtent.h @@ -60,7 +60,8 @@ namespace PointExtent protected: static const struct Frame< Real , Dim , ExtendedAxes > _Frame; - friend std::ostream &operator << ( std::ostream & , const Extent & ); + template< typename _Real , unsigned int _Dim , bool _ExtendedAxes > + friend std::ostream &operator << ( std::ostream & , const Extent< _Real , _Dim , _ExtendedAxes > & ); }; template< typename Real , unsigned int Dim , bool ExtendedAxes > diff --git a/Src/PointPartition.h b/Src/PointPartition.h index 3500bf0f..e0fe8c5f 100644 --- a/Src/PointPartition.h +++ b/Src/PointPartition.h @@ -82,6 +82,7 @@ namespace PointPartition double maxEnergy( unsigned int padSize ) const; #endif // ADAPTIVE_PADDING size_t size( void ) const; + unsigned int partitions( void ) const; unsigned int slabs( void ) const; protected: diff --git a/Src/PointPartition.inl b/Src/PointPartition.inl index 504a6611..a36f00f6 100644 --- a/Src/PointPartition.inl +++ b/Src/PointPartition.inl @@ -440,6 +440,8 @@ double Partition::maxEnergy( unsigned int padSize ) const unsigned int Partition::slabs( void ) const { return (unsigned int)_slabSizes.size(); } +unsigned int Partition::partitions( void ) const{ return (unsigned int)_starts.size()+1; } + /////////////////////////////// // Read/Write Ply Properties // /////////////////////////////// diff --git a/Src/PoissonReconServer.cpp b/Src/PoissonReconServer.cpp index ccec8edd..4d3d9e3d 100644 --- a/Src/PoissonReconServer.cpp +++ b/Src/PoissonReconServer.cpp @@ -313,12 +313,45 @@ void Merge const std::vector< unsigned int > &sharedVertexCounts , std::string header , std::vector< Socket > &clientSockets , - const MergePlyClientServer::ClientMergePlyInfo &clientMergePlyInfo + const MergePlyClientServer::ClientMergePlyInfo &clientMergePlyInfo , + const std::pair< PointPartition::PointSetInfo< Real , Dim > , PointPartition::Partition > &pointSetInfoAndPartition ) { Timer timer; - MergePlyClientServer::RunServer< Real , Dim >( TempDir.value , TempDir.value , header , Out.value , clientSockets , sharedVertexCounts , clientMergePlyInfo , PeakMemorySampleMS.value ); + std::function< std::vector< std::string > ( unsigned int ) > commentFunctor = [&]( unsigned int partition ) + { + if( partition==-1 ) return std::vector< std::string >(); + else + { + Real res = (Real)( 1< range = pointSetInfoAndPartition.second.range( partition ); + Point< Real , Dim > axis; + Real offset = pointSetInfoAndPartition.first.modelToUnitCube( Dim , Dim-1 ); + for( unsigned int d=0 ; d comments( 1 ); + std::stringstream sStream; + + Point< Real , Dim+1 > front , back; + for( unsigned int d=0 ; d >::WriteValue( front , frontStr ); + CmdLineType< Point< Real , Dim+1 > >::WriteValue( back , backStr ); + sStream << "Partition: " << std::string( frontStr ) << " " << std::string( backStr ); + + comments[0] = sStream.str(); + return comments; + } + }; + + MergePlyClientServer::RunServer< Real , Dim >( TempDir.value , TempDir.value , header , Out.value , clientSockets , sharedVertexCounts , clientMergePlyInfo , PeakMemorySampleMS.value , commentFunctor ); unsigned int peakMem = 0; for( unsigned int i=0 ; i( sharedVertexCounts , header , clientSockets , clientMergePlyInfo ); + + Merge< Real , Dim >( sharedVertexCounts , header , clientSockets , clientMergePlyInfo , pointSetInfoAndPartition ); auto InFile = [&]( unsigned int idx ) { @@ -557,6 +591,34 @@ int main( int argc , char* argv[] ) for( unsigned int i=0 ; i=1 ) + { + Real res = (Real)( 1< axis; + Real offset = pointSetInfoAndPartition.first.modelToUnitCube( Dim , Dim-1 ); + for( unsigned int d=0 ; d front , back; + for( unsigned int d=0 ; d range = pointSetInfoAndPartition.second.range( i ); + front[Dim] = (range.first/res)-offset; + back[Dim] = offset-(range.second/res); + char frontStr[ 1024 ] , backStr[ 1024 ]; + CmdLineType< Point< Real , Dim+1 > >::WriteValue( front , frontStr ); + CmdLineType< Point< Real , Dim+1 > >::WriteValue( back , backStr ); + std::cout << "\t[ " << offset-(range.first/res) << " , " << offset-(range.second/res) << " ] ->"; + std::cout << std::string( frontStr ) << " " << std::string( backStr ) << std::endl; + } + } + ThreadPool::Terminate(); return EXIT_SUCCESS; diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 5a34cf43..19db7a4e 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -45,7 +45,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "16.09" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "16.10" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file diff --git a/Src/SurfaceTrimmer.cpp b/Src/SurfaceTrimmer.cpp index 66030ab9..91e6f534 100644 --- a/Src/SurfaceTrimmer.cpp +++ b/Src/SurfaceTrimmer.cpp @@ -598,7 +598,13 @@ int main( int argc , char* argv[] ) Factory factory; bool *readFlags = new bool[ factory.plyReadNum() ]; std::vector< PlyProperty > unprocessedProperties; - PLY::ReadVertexHeader( In.value , factory , readFlags , unprocessedProperties ); + size_t vNum; + PLY::ReadVertexHeader( In.value , factory , readFlags , unprocessedProperties , vNum ); + if( vNum>std::numeric_limits< int >::max() ) + { + if( !Long.set ) WARN( "Number of vertices not supported by 32-bit indexing. Switching to 64-bit indexing" ); + Long.set = true; + } if( !factory.plyValidReadProperties<0>( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); if( !factory.plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain values" ); delete[] readFlags; From fb9f99f2d24f2a7551e743ca2c07dad127cb92d4 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Thu, 15 Aug 2024 01:37:58 -0400 Subject: [PATCH 35/86] Version 17.00 Added support for transforming oriented points to disks. --- AdaptiveSolvers.sln | 10 ++ Makefile | 15 +++ PointsToDisks.vcxproj | 164 ++++++++++++++++++++++++++ README.md | 53 ++++++++- Src/CmdLineParser.inl | 35 +++--- Src/Geometry.inl | 2 +- Src/PointExtent.h | 2 +- Src/PointsToDisks.cpp | 267 ++++++++++++++++++++++++++++++++++++++++++ Src/PreProcessor.h | 2 +- 9 files changed, 528 insertions(+), 22 deletions(-) create mode 100644 PointsToDisks.vcxproj create mode 100644 Src/PointsToDisks.cpp diff --git a/AdaptiveSolvers.sln b/AdaptiveSolvers.sln index 36862735..d5e5cda7 100644 --- a/AdaptiveSolvers.sln +++ b/AdaptiveSolvers.sln @@ -135,6 +135,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PoissonReconServer", "Poiss EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Reconstruction.example", "Reconstruction.example.vcxproj", "{F40103C1-D18D-4C34-992C-F78D4DCD4A87}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PointsToDisks", "PointsToDisks.vcxproj", "{6AE727A9-A3F0-4970-8F5B-1F1A3AEAC552}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -256,6 +258,14 @@ Global {F40103C1-D18D-4C34-992C-F78D4DCD4A87}.Release|x64.Build.0 = Release|x64 {F40103C1-D18D-4C34-992C-F78D4DCD4A87}.Release|x86.ActiveCfg = Release|Win32 {F40103C1-D18D-4C34-992C-F78D4DCD4A87}.Release|x86.Build.0 = Release|Win32 + {6AE727A9-A3F0-4970-8F5B-1F1A3AEAC552}.Debug|x64.ActiveCfg = Debug|x64 + {6AE727A9-A3F0-4970-8F5B-1F1A3AEAC552}.Debug|x64.Build.0 = Debug|x64 + {6AE727A9-A3F0-4970-8F5B-1F1A3AEAC552}.Debug|x86.ActiveCfg = Debug|Win32 + {6AE727A9-A3F0-4970-8F5B-1F1A3AEAC552}.Debug|x86.Build.0 = Debug|Win32 + {6AE727A9-A3F0-4970-8F5B-1F1A3AEAC552}.Release|x64.ActiveCfg = Release|x64 + {6AE727A9-A3F0-4970-8F5B-1F1A3AEAC552}.Release|x64.Build.0 = Release|x64 + {6AE727A9-A3F0-4970-8F5B-1F1A3AEAC552}.Release|x86.ActiveCfg = Release|Win32 + {6AE727A9-A3F0-4970-8F5B-1F1A3AEAC552}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Makefile b/Makefile index 7947cb4d..22458b08 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ IS_TARGET=ImageStitching AV_TARGET=AdaptiveTreeVisualization CP_TARGET=ChunkPLY RE_TARGET=ReconExample +PTD_TARGET=PointsToDisks PR_SOURCE=PoissonRecon.cpp PRC_SOURCE=PoissonReconClient.cpp @@ -21,6 +22,7 @@ IS_SOURCE=ImageStitching.cpp AV_SOURCE=AdaptiveTreeVisualization.cpp CP_SOURCE=ChunkPLY.cpp RE_SOURCE=Reconstruction.example.cpp +PTD_SOURCE=PointsToDisks.cpp COMPILER ?= gcc #COMPILER ?= clang @@ -77,6 +79,7 @@ IS_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(IS_SOURCE)))) AV_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(AV_SOURCE)))) CP_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(CP_SOURCE)))) RE_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(RE_SOURCE)))) +PTD_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(PTD_SOURCE)))) all: CFLAGS += $(CFLAGS_RELEASE) @@ -93,6 +96,7 @@ all: $(BIN)$(IS_TARGET) all: $(BIN)$(AV_TARGET) all: $(BIN)$(CP_TARGET) all: $(BIN)$(RE_TARGET) +all: $(BIN)$(PTD_TARGET) debug: CFLAGS += $(CFLAGS_DEBUG) debug: LFLAGS += $(LFLAGS_DEBUG) @@ -108,6 +112,7 @@ debug: $(BIN)$(IS_TARGET) debug: $(BIN)$(AV_TARGET) debug: $(BIN)$(CP_TARGET) debug: $(BIN)$(RE_TARGET) +debug: $(BIN)$(PTD_TARGET) poissonrecon: CFLAGS += $(CFLAGS_RELEASE) poissonrecon: LFLAGS += $(LFLAGS_RELEASE) @@ -158,11 +163,17 @@ chunkply: CFLAGS += $(CFLAGS_RELEASE) chunkply: LFLAGS += $(LFLAGS_RELEASE) chunkply: make_dir chunkply: $(BIN)$(CP_TARGET) + reconexample: CFLAGS += $(CFLAGS_RELEASE) reconexample: LFLAGS += $(LFLAGS_RELEASE) reconexample: make_dir reconexample: $(BIN)$(RE_TARGET) +pointstodisks: CFLAGS += $(CFLAGS_RELEASE) +pointstodisks: LFLAGS += $(LFLAGS_RELEASE) +pointstodisks: make_dir +pointstodisks: $(BIN)$(PTD_TARGET) + clean: rm -rf $(BIN)$(PR_TARGET) rm -rf $(BIN)$(PRC_TARGET) @@ -186,6 +197,7 @@ clean: rm -rf $(AV_OBJECTS) rm -rf $(CP_OBJECTS) rm -rf $(RE_OBJECTS) + rm -rf $(PTD_OBJECTS) cd PNG && make clean @@ -231,6 +243,9 @@ $(BIN)$(CP_TARGET): $(CP_OBJECTS) $(BIN)$(RE_TARGET): $(RE_OBJECTS) $(CXX) -pthread -o $@ $(RE_OBJECTS) -L$(BIN) $(LFLAGS) $(LFLAGS_IMG) +$(BIN)$(PTD_TARGET): $(PTD_OBJECTS) + $(CXX) -pthread -o $@ $(PTD_OBJECTS) -L$(BIN) $(LFLAGS) + $(BIN)%.o: $(SRC)%.c $(CC) -c -o $@ -I$(INCLUDE) $< diff --git a/PointsToDisks.vcxproj b/PointsToDisks.vcxproj new file mode 100644 index 00000000..bd675b4e --- /dev/null +++ b/PointsToDisks.vcxproj @@ -0,0 +1,164 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + 15.0 + {6AE727A9-A3F0-4970-8F5B-1F1A3AEAC552} + Win32Proj + PointsToDisks + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + false + $(SolutionDir)\Bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\Obj\$(TargetName)\$(Platform)\$(Configuration)\ + + + true + + + true + + + false + + + + NotUsing + Level3 + MaxSpeed + true + true + true + NOMINMAX;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + pch.h + . + true + stdcpp17 + + + Console + true + true + true + + + + + Use + Level3 + Disabled + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + + + Console + true + + + + + Use + Level3 + Disabled + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + + + Console + true + + + + + Use + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + pch.h + + + Console + true + true + true + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index e009c57c..0554cc99 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 16.10)

    +

    Adaptive Multigrid Solvers (Version 17.00)

    links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
    Executables: -Win64
    +Win64
    Source Code: -ZIP GitHub
    +ZIP GitHub
    Older Versions: +V16.10, V16.09, V16.08, V16.07, @@ -938,6 +939,48 @@ individual components of the visualizer. +
      +
      +
      + +PointsToDisks: +Converts oriented points to disks. + +
      --in <input points> +
      This string is the name of the file from which the point set will be read.
      +The file is assumed to be in PLY format.
      + +
      [--out <output ply file name>] +
      This string is the name of the file to which the disks should be written.
      +The file will be written out in PLY format.
      + +
      [--scale <radius scale>] +
      This floating point value specifies the radius of the disks, relative to the width of the bounding cube.
      +The default value for this parameter is 0.005 + +
      [--res <angular resolution>] +
      This integer v value specifies thangular resolution of the disk.
      +The default value for this parameter is 12. + +
      [--keep <number of points to keep>] +
      This integer value specifies the maximum number of point to transform to disks.
      +If the value of this parameter is less than the number of points, the subset of points transformed to disks will be generated by regular sub-sampling.
      +If the value of this parameter is not set and the --fraction parameter is not set, then all points will be transformed to disks. + +
      [--fraction <faction of points to keep>] +
      This floating point value specifies the fraction of points to transform to disks.
      +The default value for this parameter is 1.0.
      +If both the --keep flag and the --fraction flag are set, the --fraction flag will be ignored. + +
      [--verbose] +
      Enabling this flag provides a description of running state. + +
      +
      +
      +
    + +
    HEADER-ONLY LIBRARY
      @@ -1511,6 +1554,10 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
    • Removed dependence on _mktemp. +Version 17.00: +
        +
      1. Added code for converting oriented points to disks for visualization. +
      diff --git a/Src/CmdLineParser.inl b/Src/CmdLineParser.inl index 7435192b..dd019266 100644 --- a/Src/CmdLineParser.inl +++ b/Src/CmdLineParser.inl @@ -35,16 +35,18 @@ inline int strcasecmp( const char* c1 , const char* c2 ){ return _stricmp( c1 , template< > void CmdLineType< char* >::CleanUp( char** t ){ if( *t ) free( *t ) ; *t = NULL; } -template< > int CmdLineType< int >::Initialize( void ){ return 0; } -template< > float CmdLineType< float >::Initialize( void ){ return 0.f; } -template< > double CmdLineType< double >::Initialize( void ){ return 0.; } -template< > char* CmdLineType< char* >::Initialize( void ){ return NULL; } - -template< > void CmdLineType< int >::WriteValue( int t , char* str ){ sprintf( str , "%d" , t ); } -template< > void CmdLineType< float >::WriteValue( float t , char* str ){ sprintf( str , "%f" , t ); } -template< > void CmdLineType< double >::WriteValue( double t , char* str ){ sprintf( str , "%f" , t ); } -template< > void CmdLineType< char* >::WriteValue( char* t , char* str ){ if( t ) sprintf( str , "%s" , t ) ; else str[0]=0; } -template< > void CmdLineType< std::string >::WriteValue( std::string t , char* str ){ sprintf( str , "%s" , t.c_str() ); } +template< > int CmdLineType< int >::Initialize( void ){ return 0; } +template< > unsigned int CmdLineType< unsigned int >::Initialize( void ){ return 0u; } +template< > float CmdLineType< float >::Initialize( void ){ return 0.f; } +template< > double CmdLineType< double >::Initialize( void ){ return 0.; } +template< > char * CmdLineType< char * >::Initialize( void ){ return NULL; } + +template< > void CmdLineType< int >::WriteValue( int t , char* str ){ sprintf( str , "%d" , t ); } +template< > void CmdLineType< unsigned int >::WriteValue( unsigned int t , char* str ){ sprintf( str , "%u" , t ); } +template< > void CmdLineType< float >::WriteValue( float t , char* str ){ sprintf( str , "%f" , t ); } +template< > void CmdLineType< double >::WriteValue( double t , char* str ){ sprintf( str , "%f" , t ); } +template< > void CmdLineType< char * >::WriteValue( char *t , char* str ){ if( t ) sprintf( str , "%s" , t ) ; else str[0]=0; } +template< > void CmdLineType< std::string >::WriteValue( std::string t , char* str ){ sprintf( str , "%s" , t.c_str() ); } template< typename Real , unsigned int Dim > void CmdLineType< Point< Real , Dim > >::WriteValue( Point< Real , Dim > t , char *str ) { @@ -66,15 +68,16 @@ template< > char* CmdLineType< char* >::Copy( char* t ){ return _strdup( template< > char* CmdLineType< char* >::Copy( char* t ){ return strdup( t ); } #endif // WIN32 || _WIN64 -template< > int CmdLineType< int >::StringToType( const char* str ){ return atoi( str ); } -template< > float CmdLineType< float >::StringToType( const char* str ){ return float( atof( str ) ); } -template< > double CmdLineType< double >::StringToType( const char* str ){ return double( atof( str ) ); } +template< > int CmdLineType< int >::StringToType( const char* str ){ return atoi( str ); } +template< > unsigned int CmdLineType< unsigned int >::StringToType( const char* str ){ return (unsigned int)atoll( str ); } +template< > float CmdLineType< float >::StringToType( const char* str ){ return float( atof( str ) ); } +template< > double CmdLineType< double >::StringToType( const char* str ){ return double( atof( str ) ); } #if defined( WIN32 ) || defined( _WIN64 ) -template< > char* CmdLineType< char* >::StringToType( const char* str ){ return _strdup( str ); } +template< > char * CmdLineType< char* >::StringToType( const char* str ){ return _strdup( str ); } #else // !WIN32 && !_WIN64 -template< > char* CmdLineType< char* >::StringToType( const char* str ){ return strdup( str ); } +template< > char * CmdLineType< char* >::StringToType( const char* str ){ return strdup( str ); } #endif // WIN32 || _WIN64 -template< > std::string CmdLineType< std::string >::StringToType( const char* str ){ return std::string( str ); } +template< > std::string CmdLineType< std::string >::StringToType( const char* str ){ return std::string( str ); } template< typename Real , unsigned int Dim > Point< Real , Dim > CmdLineType< Point< Real , Dim > >::StringToType( const char *str ) diff --git a/Src/Geometry.inl b/Src/Geometry.inl index 78bf8bff..b9965d19 100644 --- a/Src/Geometry.inl +++ b/Src/Geometry.inl @@ -29,7 +29,7 @@ DAMAGE. #include #include "MyMiscellany.h" -template< class Real > Real Random( void ){ return Real( rand() )/RAND_MAX; } +template< class Real > Real Random( void ){ return Real( rand() )/Real( RAND_MAX ); } template< class Real , int Dim > Point< Real , Dim > RandomBallPoint( void ) diff --git a/Src/PointExtent.h b/Src/PointExtent.h index 5e1b05c8..be8a036a 100644 --- a/Src/PointExtent.h +++ b/Src/PointExtent.h @@ -58,7 +58,7 @@ namespace PointExtent void add( Point< Real , Dim > p ); Extent operator + ( const Extent &e ) const; protected: - static const struct Frame< Real , Dim , ExtendedAxes > _Frame; + static const PointExtent::Frame< Real , Dim , ExtendedAxes > _Frame; template< typename _Real , unsigned int _Dim , bool _ExtendedAxes > friend std::ostream &operator << ( std::ostream & , const Extent< _Real , _Dim , _ExtendedAxes > & ); diff --git a/Src/PointsToDisks.cpp b/Src/PointsToDisks.cpp new file mode 100644 index 00000000..55e919b5 --- /dev/null +++ b/Src/PointsToDisks.cpp @@ -0,0 +1,267 @@ +/* +Copyright (c) 2024, 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. +*/ + +#include "PreProcessor.h" + +#include +#include +#include +#include +#include +#define _USE_MATH_DEFINES +#include +#include "Ply.h" +#include "CmdLineParser.h" +#include "Geometry.h" +#include "VertexFactory.h" +#include "MyMiscellany.h" +#include "DataStream.imp.h" + + +cmdLineParameter< std::string > + In( "in" ) , + Out( "out" ); + +cmdLineParameter< unsigned int > + Res( "res" , 12 ) , + PointsToKeep( "keep" ); + +cmdLineParameter< float > + Scale( "scale" , 0.005f ) , + Fraction( "fraction" , 1.f ); + +cmdLineReadable + Verbose( "verbose" ); + +cmdLineParameter< float > + LengthToRadiusExponent( "lExp" , 0.66f ); + +cmdLineReadable* params[] = +{ + &In , + &Out , + &Scale , + &Res , + &PointsToKeep , + &Fraction , + &LengthToRadiusExponent , + &Verbose , + NULL +}; + + +void ShowUsage( char* ex ) +{ + printf( "Usage: %s\n" , ex ); + printf( "\t --%s \n" , In.name ); + printf( "\t --%s \n" , Out.name ); + printf( "\t[--%s =%f]\n" , Scale.name , Scale.value ); + printf( "\t[--%s =%d]\n" , Res.name , Res.value ); + printf( "\t[--%s ]\n" , PointsToKeep.name ); + printf( "\t[--%s =%f]\n" , Fraction.name , Fraction.value ); + printf( "\t[--%s =%f]\n" , LengthToRadiusExponent.name , LengthToRadiusExponent.value ); + printf( "\t[--%s]\n" , Verbose.name ); +} + +int main( int argc , char* argv[] ) +{ + auto SampleRadius = []( float length , float radius ){ return radius * (float)pow(length,0.66); }; + + auto NormalColor = []( Point< float , 3 > n ) + { + Point< float , 3 > color = + ( + ( ( n[0]<0 ) ? Point< float , 3 >( 0 , -n[0] , -n[0] ) : Point< float , 3 >( n[0] , 0 , 0 ) ) + + ( ( n[1]<0 ) ? Point< float , 3 >( -n[1] , 0 , -n[1] ) : Point< float , 3 >( 0 , n[1] , 0 ) ) + + ( ( n[2]<0 ) ? Point< float , 3 >( -n[2] , -n[2] , 0 ) : Point< float , 3 >( 0 , 0 , n[2] ) ) + ) * 255; + color[0] = std::min< float >( 255.f , color[0] ); + color[1] = std::min< float >( 255.f , color[1] ); + color[2] = std::min< float >( 255.f , color[2] ); + return color; + }; + + cmdLineParse( argc-1 , &argv[1] , params ); + if( !In.set || !Out.set ) + { + ShowUsage( argv [0] ); + return EXIT_FAILURE; + } + + if( Verbose.set ) + { + std::cout << "***********************************************************" << std::endl; + std::cout << "***********************************************************" << std::endl; + std::cout << "** Running Points to Disks (Version " << ADAPTIVE_SOLVERS_VERSION << ") **" << std::endl; + std::cout << "***********************************************************" << std::endl; + std::cout << "***********************************************************" << std::endl; + } + + if( PointsToKeep.set && Fraction.set ) + { + WARN( "One of --" , PointsToKeep.name , " and --" , Fraction.name , " should be set. Using --" , PointsToKeep.name ); + Fraction.set = false; + } + + using InFactory = VertexFactory::Factory< float , VertexFactory::PositionFactory< float , 3 > , VertexFactory::NormalFactory< float , 3 > , VertexFactory::RGBColorFactory< float > >; + using InVertex = typename InFactory::VertexType; + std::vector< InVertex > vertices; + + bool hasNormals = true; + bool hasColors = false; + int fileType = PLY_BINARY_NATIVE; + { + std::vector< std::vector< int > > polygons; + char *ext = GetFileExtension( In.value.c_str() ); + + if( !strcasecmp( ext , "bnpts" ) ) + { + using Factory = VertexFactory::Factory< float , VertexFactory::PositionFactory< float , 3 > , VertexFactory::NormalFactory< float , 3 > >; + using Vertex = typename Factory::VertexType; + Factory factory; + BinaryInputDataStream< Factory > pointStream( In.value.c_str() , factory ); + Vertex v; + while( pointStream.read( v ) ) + { + InVertex _v; + _v.template get<0>() = v.template get<0>(); + _v.template get<1>() = v.template get<1>(); + vertices.push_back( _v ); + } + } + else if( !strcasecmp( ext , "ply" ) ) + { + InFactory inFactory; + bool *readFlags = new bool[ inFactory.plyReadNum() ]; + int file_type; + std::vector< std::string > comments; + PLY::ReadPolygons( In.value , inFactory , vertices , polygons , file_type , comments , readFlags ); + hasNormals = readFlags[3] && readFlags[4] && readFlags[5]; + hasColors = ( readFlags[6] && readFlags[7] && readFlags[8] ) || ( readFlags[9] && readFlags[10] && readFlags[11] ); + delete[] readFlags; + } + else + { + using Factory = VertexFactory::Factory< float , VertexFactory::PositionFactory< float , 3 > , VertexFactory::NormalFactory< float , 3 > >; + using Vertex = typename Factory::VertexType; + Factory factory; + ASCIIInputDataStream< Factory > pointStream( In.value.c_str() , factory ); + Vertex v; + while( pointStream.read( v ) ) + { + InVertex _v; + _v.template get<0>() = v.template get<0>(); + _v.template get<1>() = v.template get<1>(); + vertices.push_back( _v ); + } + } + delete[] ext; + } + if( Verbose.set ) std::cout << "Input points: " << vertices.size() << std::endl; + if( PointsToKeep.set && PointsToKeep.value>vertices.size() ) + { + WARN( "--" , PointsToKeep.name , " value exceeds number of points: " , PointsToKeep.value , " > " , vertices.size() ); + PointsToKeep.value = vertices.size(); + } + + if( !hasNormals ) ERROR_OUT( "Input is not oriented" ); + + if( PointsToKeep.set ) + { + std::vector< InVertex > _vertices( PointsToKeep.value ); + for( unsigned int i=0 ; i _vertices; + for( unsigned int i=0 ; i()<=Fraction.value ) _vertices.push_back( vertices[i] ); + vertices = _vertices; + } + + Point< float , 3 > min , max; + min = max = vertices[0].template get<0>(); + for( int i=0 ; i()[j]()[j]; + if( vertices[i].template get<0>()[j]>max[j] ) max[j] = vertices[i].template get<0>()[j]; + } + float radius = (float)sqrt( Point< float , 3 >::SquareNorm( max-min ) ) * Scale.value; + if( Verbose.set ) std::cout << "Scale -> Radius: " << Scale.value << " -> " << radius << std::endl; + + { + std::vector< InVertex > verts; + std::vector< std::vector< int > > polygons; + + verts.reserve( vertices.size() * Res.value ); + polygons.reserve( vertices.size() ); + + auto ProcessPoint = [&]( Point< float , 3 > p , Point< float , 3 > n , Point< float , 3 > c ) + { + unsigned int vIdx = (unsigned int)verts.size(); + Point< float , 3 > v1 , v2; + double l = sqrt( Point< float , 3 >::SquareNorm( n ) ); + if( !l ) return; + n /= (float)l; + + p += n; + + float radiusScale = (float)pow( l , LengthToRadiusExponent.value ); + v1 = Point< float , 3 >( -n[2] , 0 , n[0] ); + if( Point< float , 3 >::SquareNorm( v1 )<0.0000001 ) v1 = Point< float , 3 >( 1 , 0 , 0 ); + v2 = Point< float , 3 >::CrossProduct( n , v1 ); + v1 /= sqrt( Point< float , 3 >::SquareNorm( v1 ) ); + v2 /= sqrt( Point< float , 3 >::SquareNorm( v2 ) ); + + InVertex v; + v.template get<2>() = hasColors ? c : NormalColor( n ); + v.template get<1>() = n; + + for( unsigned int j=0 ; j() = p + ( v1 * (float)cos(theta) + v2 * (float)sin(theta) ) * radius * radiusScale; + verts.push_back( v ); + } + std::vector< int > polygon( Res.value ); + for( unsigned int j=0 ; j() , vertices[i].template get<1>() , vertices[i].template get<2>() ); + + InFactory inFactory; + std::vector< std::string > comments; + PLY::WritePolygons( Out.value , inFactory , verts , polygons, fileType , comments ); + } + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 19db7a4e..90458de0 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -45,7 +45,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "16.10" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "17.00" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file From 1449a82e7189f9f109f3b0f77c9bf766d2b87d88 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Thu, 5 Sep 2024 23:04:02 -0400 Subject: [PATCH 36/86] Version 18.00 Added PoissonRecon namespace --- AdaptiveSolvers.sln | 5 +- README.md | 13 +- Src/AdaptiveTreeVisualization.cpp | 14 +- Src/Allocator.h | 129 +- Src/Array.h | 106 +- Src/Array.inl | 12 - Src/BMPStream.inl | 207 -- Src/BSplineData.h | 961 +++--- Src/BSplineData.inl | 6 +- Src/BinaryNode.h | 76 +- Src/BlockedVector.h | 339 +- Src/ChunkPLY.cpp | 20 +- Src/CmdLineParser.h | 151 +- Src/CmdLineParser.inl | 51 +- Src/DataStream.h | 183 +- Src/DataStream.imp.h | 405 +-- Src/EDTInHeat.cpp | 14 +- Src/FEMTree.LevelSet.2D.inl | 12 - Src/FEMTree.LevelSet.3D.inl | 12 - Src/FEMTree.LevelSet.inl | 2 - Src/FEMTree.System.inl | 20 +- Src/FEMTree.h | 5331 +++++++++++++++-------------- Src/FEMTree.inl | 166 +- Src/Factor.h | 220 +- Src/FunctionData.h | 109 - Src/FunctionData.inl | 415 --- Src/Geometry.h | 1462 ++++---- Src/Geometry.inl | 3 - Src/Image.h | 687 ++-- Src/ImageStitching.cpp | 16 +- Src/JPEG.h | 65 +- Src/JPEG.inl | 4 - Src/MAT.h | 56 +- Src/MarchingCubes.h | 1257 ++++--- Src/MergePlyClientServer.h | 53 +- Src/MyExceptions.h | 120 + Src/MyMiscellany.h | 1323 +++---- Src/PNG.h | 59 +- Src/PNG.inl | 3 - Src/PPolynomial.h | 122 +- Src/PPolynomial.inl | 2 - Src/Ply.h | 91 +- Src/PlyFile.h | 323 +- Src/PlyFile.inl | 54 +- Src/PointExtent.h | 79 +- Src/PointInterpolant.cpp | 15 +- Src/PointPartition.h | 182 +- Src/PointPartitionClientServer.h | 45 +- Src/PointsToDisks.cpp | 17 +- Src/PoissonRecon.cpp | 14 +- Src/PoissonRecon.server.inl | 2 - Src/PoissonReconClient.cpp | 12 +- Src/PoissonReconClientServer.h | 90 +- Src/PoissonReconServer.cpp | 14 +- Src/Polynomial.h | 139 +- Src/Polynomial.inl | 5 - Src/PreProcessor.h | 4 +- Src/Rasterizer.h | 162 +- Src/Reconstruction.example.cpp | 12 +- Src/Reconstructors.h | 2130 ++++++------ Src/Reconstructors.streams.h | 1090 +++--- Src/RegularGrid.h | 226 +- Src/RegularGrid.inl | 2 - Src/RegularTree.h | 648 ++-- Src/RegularTree.inl | 5 - Src/SSDRecon.cpp | 14 +- Src/Socket.h | 172 +- Src/SparseMatrix.h | 238 +- Src/SparseMatrix.inl | 4 - Src/SparseMatrixInterface.h | 223 +- Src/SparseMatrixInterface.inl | 97 +- Src/Streams.h | 239 +- Src/SurfaceTrimmer.cpp | 14 +- Src/VertexFactory.h | 1041 +++--- Src/Window.h | 760 ++-- 75 files changed, 10765 insertions(+), 11609 deletions(-) delete mode 100644 Src/BMPStream.inl delete mode 100644 Src/FunctionData.h delete mode 100644 Src/FunctionData.inl create mode 100644 Src/MyExceptions.h diff --git a/AdaptiveSolvers.sln b/AdaptiveSolvers.sln index d5e5cda7..02fbc9b9 100644 --- a/AdaptiveSolvers.sln +++ b/AdaptiveSolvers.sln @@ -53,13 +53,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Header Files", "Header File Src\DataStream.imp.h = Src\DataStream.imp.h Src\Factor.h = Src\Factor.h Src\FEMTree.h = Src\FEMTree.h - Src\FunctionData.h = Src\FunctionData.h Src\Geometry.h = Src\Geometry.h Src\Image.h = Src\Image.h Src\JPEG.h = Src\JPEG.h Src\MarchingCubes.h = Src\MarchingCubes.h Src\MAT.h = Src\MAT.h Src\MergePlyClientServer.h = Src\MergePlyClientServer.h + Src\MyExceptions.h = Src\MyExceptions.h Src\MyMiscellany.h = Src\MyMiscellany.h Src\Ply.h = Src\Ply.h Src\PlyFile.h = Src\PlyFile.h @@ -79,6 +79,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Header Files", "Header File Src\Socket.h = Src\Socket.h Src\SparseMatrix.h = Src\SparseMatrix.h Src\SparseMatrixInterface.h = Src\SparseMatrixInterface.h + Src\Streams.h = Src\Streams.h Src\VertexFactory.h = Src\VertexFactory.h Src\Window.h = Src\Window.h EndProjectSection @@ -86,7 +87,6 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Inline Files", "Inline Files", "{ACD217C3-BE24-4438-A4E6-C713312FEA34}" ProjectSection(SolutionItems) = preProject Src\Array.inl = Src\Array.inl - Src\BMPStream.inl = Src\BMPStream.inl Src\BSplineData.inl = Src\BSplineData.inl Src\CmdLineParser.inl = Src\CmdLineParser.inl Src\DataStream.imp.inl = Src\DataStream.imp.inl @@ -99,7 +99,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Inline Files", "Inline File Src\FEMTree.SortedTreeNodes.inl = Src\FEMTree.SortedTreeNodes.inl Src\FEMTree.System.inl = Src\FEMTree.System.inl Src\FEMTree.WeightedSamples.inl = Src\FEMTree.WeightedSamples.inl - Src\FunctionData.inl = Src\FunctionData.inl Src\Geometry.inl = Src\Geometry.inl Src\JPEG.inl = Src\JPEG.inl Src\MAT.inl = Src\MAT.inl diff --git a/README.md b/README.md index 0554cc99..dda1d27c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

      Adaptive Multigrid Solvers (Version 17.00)

      +

      Adaptive Multigrid Solvers (Version 18.00)

      links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
      Executables: -Win64
      +Win64
      Source Code: -ZIP GitHub
      +ZIP GitHub
      Older Versions: +V17.00, V16.10, V16.09, V16.08, @@ -1558,8 +1559,12 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
      1. Added code for converting oriented points to disks for visualization.
      - +Version 18.00: +
        +
      1. Encapsulated the code within the PoissonRecon namespace. +
      +
      SUPPORT
      diff --git a/Src/AdaptiveTreeVisualization.cpp b/Src/AdaptiveTreeVisualization.cpp index 5d753bb3..7b0de9bc 100644 --- a/Src/AdaptiveTreeVisualization.cpp +++ b/Src/AdaptiveTreeVisualization.cpp @@ -43,7 +43,9 @@ DAMAGE. #include "DataStream.imp.h" #include "Reconstructors.h" -cmdLineParameter< char* > +using namespace PoissonRecon; + +CmdLineParameter< char* > In( "in" ) , Samples( "samples" ) , OutMesh( "mesh" ) , @@ -51,7 +53,7 @@ cmdLineParameter< char* > OutSlice( "slice" ) , OutGrid( "grid" ); -cmdLineReadable +CmdLineReadable PolygonMesh( "polygonMesh" ) , NonManifold( "nonManifold" ) , FlipOrientation( "flip" ) , @@ -60,7 +62,7 @@ cmdLineReadable PrimalGrid( "primalGrid" ) , Verbose( "verbose" ); -cmdLineParameter< int > +CmdLineParameter< int > #ifdef _OPENMP ParallelType( "parallel" , (int)ThreadPool::OPEN_MP ) , #else // !_OPENMP @@ -78,10 +80,10 @@ cmdLineParameter< int > TreeDepth( "treeDepth" , -1 ); -cmdLineParameter< float > +CmdLineParameter< float > IsoValue( "iso" , 0.f ); -cmdLineReadable* params[] = +CmdLineReadable* params[] = { &In , &Samples , @@ -467,7 +469,7 @@ int main( int argc , char* argv[] ) #ifdef ARRAY_DEBUG WARN( "Array debugging enabled" ); #endif // ARRAY_DEBUG - cmdLineParse( argc-1 , &argv[1] , params ); + CmdLineParse( argc-1 , &argv[1] , params ); ThreadPool::DefaultChunkSize = ThreadChunkSize.value; ThreadPool::DefaultSchedule = (ThreadPool::ScheduleType)ScheduleType.value; if( Verbose.set ) diff --git a/Src/Allocator.h b/Src/Allocator.h index e6548fc5..7ecd050d 100644 --- a/Src/Allocator.h +++ b/Src/Allocator.h @@ -31,76 +31,79 @@ DAMAGE. #include #include "Array.h" -struct AllocatorState +namespace PoissonRecon { - size_t index , remains; - AllocatorState( void ) : index(0) , remains(0) {} -}; - -/** 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 T > -class Allocator -{ - size_t _blockSize; - AllocatorState _state; - std::vector< Pointer( T ) > _memory; -public: - Allocator( void ) : _blockSize(0) {} - ~Allocator( void ){ reset(); } - - /** This method is the allocators destructor. It frees up any of the memory that - * it has allocated. */ - void reset( void ) + struct AllocatorState { - for( size_t i=0 ; i<_memory.size() ; i++ ) DeletePointer( _memory[i] ); - _memory.clear(); - _blockSize = 0; - _state = AllocatorState(); - } - /** This method returns the memory state of the allocator. */ - AllocatorState getState( void ) const { return _state; } + size_t index , remains; + AllocatorState( void ) : index(0) , remains(0) {} + }; - /** This method initiallizes the constructor and the blockSize variable specifies the - * the number of objects that should be pre-allocated at a time. */ - void set( size_t blockSize ) + /** 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 T > + class Allocator { - reset(); - _blockSize = blockSize; - _state.index = -1; - _state.remains = 0; - } + size_t _blockSize; + AllocatorState _state; + std::vector< Pointer( T ) > _memory; + public: + Allocator( void ) : _blockSize(0) {} + ~Allocator( void ){ reset(); } - /** 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. - */ - Pointer( T ) newElements( size_t elements=1 ) - { - Pointer( T ) mem; - if( !elements ) return NullPointer( T ); - if( elements>_blockSize ) ERROR_OUT( "elements bigger than block-size: " , elements , " > " , _blockSize ); - if( _state.remains_blockSize ) ERROR_OUT( "elements bigger than block-size: " , elements , " > " , _blockSize ); + if( _state.remains( _blockSize ); - if( !mem ) ERROR_OUT( "Failed to allocate memory" ); - _memory.push_back( mem ); + if( _state.index==_memory.size()-1 ) + { + mem = NewPointer< T >( _blockSize ); + if( !mem ) ERROR_OUT( "Failed to allocate memory" ); + _memory.push_back( mem ); + } + _state.index++; + _state.remains = _blockSize; } - _state.index++; - _state.remains = _blockSize; + mem = _memory[ _state.index ] + ( _blockSize-_state.remains ); + _state.remains -= elements; + return mem; } - mem = _memory[ _state.index ] + ( _blockSize-_state.remains ); - _state.remains -= elements; - return mem; - } -}; + }; +} #endif // ALLOCATOR_INCLUDE diff --git a/Src/Array.h b/Src/Array.h index 6a0cca50..234ff893 100644 --- a/Src/Array.h +++ b/Src/Array.h @@ -30,31 +30,24 @@ DAMAGE. #define ARRAY_INCLUDED #include +#include "MyExceptions.h" -#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( EXIT_FAILURE ); } -#endif // _WIN32 -#endif // _WIN64 - -// Code from http://stackoverflow.com -inline void* aligned_malloc( size_t size , size_t align ) +namespace PoissonRecon { - // 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; -} -inline void aligned_free( void* mem ) { free( ( ( void** )mem )[-1] ); } + // Code from http://stackoverflow.com + inline 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; + } + inline void aligned_free( void* mem ) { free( ( ( void** )mem )[-1] ); } #ifdef ARRAY_DEBUG #ifdef SHOW_WARNINGS @@ -67,27 +60,27 @@ inline void aligned_free( void* mem ) { free( ( ( void** )mem )[-1] ); } #include "Array.inl" -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 > 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 > 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 > 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 , size_t sz ) { return Array< C >::FromPointer( c , sz ); } -template< class C > ConstArray< C > GetPointer( const C* c , size_t sz ) { return ConstArray< C >::FromPointer( c , sz ); } -template< class C > Array< C > GetPointer( C* c , std::ptrdiff_t start , std::ptrdiff_t end ) { return Array< C >::FromPointer( c , start , end ); } -template< class C > ConstArray< C > GetPointer( const C* c , std::ptrdiff_t start , std::ptrdiff_t end ) { return ConstArray< C >::FromPointer( c , start , end ); } + template< class C > Array< C > GetPointer( C* c , size_t sz ) { return Array< C >::FromPointer( c , sz ); } + template< class C > ConstArray< C > GetPointer( const C* c , size_t sz ) { return ConstArray< C >::FromPointer( c , sz ); } + template< class C > Array< C > GetPointer( C* c , std::ptrdiff_t start , std::ptrdiff_t end ) { return Array< C >::FromPointer( c , start , end ); } + template< class C > ConstArray< C > GetPointer( const C* c , std::ptrdiff_t start , std::ptrdiff_t end ) { return ConstArray< C >::FromPointer( c , start , end ); } #else // !ARRAY_DEBUG #define Pointer( ... ) __VA_ARGS__* @@ -98,23 +91,24 @@ template< class C > ConstArray< C > GetPointer( const C* c , std::ptrdiff_t star #define AlignedFreePointer( ... ) { if( __VA_ARGS__ ) aligned_free( __VA_ARGS__ ) , __VA_ARGS__ = NULL; } #define DeletePointer( ... ) { if( __VA_ARGS__ ) delete[] __VA_ARGS__ , __VA_ARGS__ = NULL; } -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*) malloc( sizeof(C) * size ); } -template< class C > C* AlignedAllocPointer( size_t size , size_t alignment , const char* name=NULL ){ return (C*)aligned_malloc( sizeof(C) * size , alignment ); } -template< class C > C* ReAllocPointer( C* c , size_t size , const char* name=NULL ){ return (C*) realloc( c , sizeof(C) * size ); } + 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*) malloc( sizeof(C) * size ); } + template< class C > C* AlignedAllocPointer( size_t size , size_t alignment , const char* name=NULL ){ return (C*)aligned_malloc( sizeof(C) * size , alignment ); } + template< class C > C* ReAllocPointer( C* c , size_t size , const char* name=NULL ){ return (C*) realloc( c , sizeof(C) * size ); } -//template< class C > C* NullPointer( void ){ return NULL; } + //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* 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 , size_t sz ) { return c; } -template< class C > const C* GetPointer( const C* c , size_t sz ) { return c; } -template< class C > C* GetPointer( C* c , std::ptrdiff_t start , std::ptrdiff_t end ) { return c; } -template< class C > const C* GetPointer( const C* c , std::ptrdiff_t start , std::ptrdiff_t end ) { return c; } + template< class C > C* GetPointer( C* c , size_t sz ) { return c; } + template< class C > const C* GetPointer( const C* c , size_t sz ) { return c; } + template< class C > C* GetPointer( C* c , std::ptrdiff_t start , std::ptrdiff_t end ) { return c; } + template< class C > const C* GetPointer( const C* c , std::ptrdiff_t start , std::ptrdiff_t end ) { return c; } #endif // ARRAY_DEBUG +} #endif // ARRAY_INCLUDED diff --git a/Src/Array.inl b/Src/Array.inl index 67d17ad8..0d634f78 100644 --- a/Src/Array.inl +++ b/Src/Array.inl @@ -26,18 +26,6 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ -#include -#include -#include -#include -#ifdef _WIN32 -#include -#endif // _WIN32 -#include -#include -#include -#include "MyMiscellany.h" - template< class C > class ConstArray; template< class C > diff --git a/Src/BMPStream.inl b/Src/BMPStream.inl deleted file mode 100644 index f544d8e4..00000000 --- a/Src/BMPStream.inl +++ /dev/null @@ -1,207 +0,0 @@ -/* -Copyright (c) 2010, 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 BMP_STREAM_INCLUDED -#define BMP_STREAM_INCLUDED - -#include -#include "Array.h" - -/* constants for the biCompression field */ -#define BI_RGB 0L -#define BI_RLE8 1L -#define BI_RLE4 2L -#define BI_BITFIELDS 3L - -/* Some magic numbers */ - -#define BMP_BF_TYPE 0x4D42 -/* word BM */ - -#define BMP_BF_OFF_BITS 54 -/* 14 for file header + 40 for info header (not sizeof(), but packed size) */ - -#define BMP_BI_SIZE 40 -/* packed size of info header */ - -#ifndef _WIN32 -typedef struct tagBITMAPFILEHEADER -{ - unsigned short int bfType; - unsigned int bfSize; - unsigned short int bfReserved1; - unsigned short int bfReserved2; - unsigned int bfOffBits; -} BITMAPFILEHEADER; - -typedef struct tagBITMAPINFOHEADER { - unsigned int biSize; - int biWidth; - int biHeight; - unsigned short int biPlanes; - unsigned short int biBitCount; - unsigned int biCompression; - unsigned int biSizeImage; - int biXPelsPerMeter; - int biYPelsPerMeter; - unsigned int biClrUsed; - unsigned int biClrImportant; -} BITMAPINFOHEADER; -#endif // !_WIN32 - - -struct BMPInfo -{ - FILE* fp; - Pointer( unsigned char ) data; - int width , lineLength; -}; -inline void BMPGetImageInfo( char* fileName , int& width , int& height , int& channels , int& bytesPerChannel ) -{ - BITMAPFILEHEADER bmfh; - BITMAPINFOHEADER bmih; - - FILE* fp = fopen( fileName , "rb" ); - if( !fp ) ERROR_OUT( "Failed to open: %s" , fileName ); - - fread( &bmfh , sizeof( BITMAPFILEHEADER ) , 1 , fp ); - fread( &bmih , sizeof( BITMAPINFOHEADER ) , 1 , fp ); - - if( bmfh.bfType!=BMP_BF_TYPE || bmfh.bfOffBits!=BMP_BF_OFF_BITS ){ fclose(fp) ; ERROR_OUT( "Bad bitmap file header" ); }; - if( bmih.biSize!=BMP_BI_SIZE || bmih.biWidth<=0 || bmih.biHeight<=0 || bmih.biPlanes!=1 || bmih.biBitCount!=24 || bmih.biCompression!=BI_RGB ) { fclose(fp) ; ERROR_OUT( "Bad bitmap file info" ); } - width = bmih.biWidth; - height = bmih.biHeight; - channels = 3; - bytesPerChannel = 1; - int lineLength = width * channels; - if( lineLength % 4 ) lineLength = (lineLength / 4 + 1) * 4; - if( bmih.biSizeImage!=lineLength*height ){ fclose(fp) ; ERROR_OUT( "Bad bitmap image size" ) , fclose( fp ); }; - fclose( fp ); -} - -inline void* BMPInitRead( char* fileName , int& width , int& height ) -{ - BITMAPFILEHEADER bmfh; - BITMAPINFOHEADER bmih; - - BMPInfo* info = (BMPInfo*)malloc( sizeof( BMPInfo ) ); - info->fp = fopen( fileName , "rb" ); - if( !info->fp ) ERROR_OUT( "Failed to open: %s" , fileName ); - - fread( &bmfh , sizeof( BITMAPFILEHEADER ) , 1 , info->fp ); - fread( &bmih , sizeof( BITMAPINFOHEADER ) , 1 , info->fp ); - - if( bmfh.bfType!=BMP_BF_TYPE || bmfh.bfOffBits!=BMP_BF_OFF_BITS ) ERROR_OUT( "Bad bitmap file header" ); - if( bmih.biSize!=BMP_BI_SIZE || bmih.biWidth<=0 || bmih.biHeight<=0 || bmih.biPlanes!=1 || bmih.biBitCount!=24 || bmih.biCompression!=BI_RGB ) ERROR_OUT( "Bad bitmap file info" ); - - info->width = width = bmih.biWidth; - height = bmih.biHeight; - info->lineLength = width * 3; - if( info->lineLength % 4 ) info->lineLength = (info->lineLength / 4 + 1) * 4; - if( bmih.biSizeImage!=info->lineLength*height ) ERROR_OUT( "Bad bitmap image size" ); - info->data = AllocPointer< unsigned char >( info->lineLength ); - if( !info->data ) ERROR_OUT( "Could not allocate memory for bitmap data" ); - - fseek( info->fp , (long) bmfh.bfOffBits , SEEK_SET ); - fseek( info->fp , (long) info->lineLength * height , SEEK_CUR ); - return info; -} -template< int Channels , bool HDR > -inline void* BMPInitWrite( char* fileName , int width , int height , int quality ) -{ - if( HDR ) WARN( "No HDR support for JPEG" ); - BITMAPFILEHEADER bmfh; - BITMAPINFOHEADER bmih; - - BMPInfo* info = (BMPInfo*)malloc( sizeof( BMPInfo ) ); - info->fp = fopen( fileName , "wb" ); - if( !info->fp ) ERROR_OUT( "Failed to open: %s" , fileName ); - info->width = width; - - info->lineLength = width * 3; /* RGB */ - if( info->lineLength % 4 ) info->lineLength = (info->lineLength / 4 + 1) * 4; - info->data = AllocPointer< unsigned char >( info->lineLength ); - if( !info->data ) ERROR_OUT( "Could not allocate memory for bitmap data" ); - /* Write file header */ - - bmfh.bfType = BMP_BF_TYPE; - bmfh.bfSize = BMP_BF_OFF_BITS + info->lineLength * height; - bmfh.bfReserved1 = 0; - bmfh.bfReserved2 = 0; - bmfh.bfOffBits = BMP_BF_OFF_BITS; - - fwrite( &bmfh , sizeof(BITMAPFILEHEADER) , 1 , info->fp ); - - bmih.biSize = BMP_BI_SIZE; - bmih.biWidth = width; - bmih.biHeight = -height; - bmih.biPlanes = 1; - bmih.biBitCount = 24; /* RGB */ - bmih.biCompression = BI_RGB; /* RGB */ - bmih.biSizeImage = info->lineLength * (unsigned int) bmih.biHeight; /* RGB */ - bmih.biXPelsPerMeter = 2925; - bmih.biYPelsPerMeter = 2925; - bmih.biClrUsed = 0; - bmih.biClrImportant = 0; - - fwrite( &bmih , sizeof(BITMAPINFOHEADER) , 1 , info->fp ); - - return info; -} -template< int Channels , class ChannelType > -inline void BMPWriteRow( Pointer( ChannelType ) pixels , void* v , int j ) -{ - BMPInfo* info = (BMPInfo*)v; - ConvertRow< ChannelType , unsigned char >( pixels , info->data , info->width , Channels , 3 ); - for( int i=0 ; iwidth ; i++ ) { unsigned char temp = info->data[i*3] ; info->data[i*3] = info->data[i*3+2] ; info->data[i*3+2] = temp; } - fwrite( info->data , sizeof(unsigned char) , info->width*3 , info->fp ); - int nbytes = info->width*3; - while( nbytes % 4 ) putc( 0 , info->fp ) , nbytes++; -} -template< int Channels , class ChannelType > -void BMPReadRow( Pointer( ChannelType ) pixels , void* v , int j ) -{ - BMPInfo* info = (BMPInfo*)v; - - fseek( info->fp , -info->lineLength , SEEK_CUR ); - fread( info->data , 1 , info->lineLength , info->fp ); - fseek( info->fp , -info->lineLength , SEEK_CUR ); - if( ferror(info->fp) ) ERROR_OUT( "Error reading bitmap row" ); - for( int i=0 ; iwidth ; i++ ) { unsigned char temp = info->data[i*3] ; info->data[i*3] = info->data[i*3+2] ; info->data[i*3+2] = temp; } - ConvertRow< unsigned char , ChannelType >( ( ConstPointer( unsigned char ) )info->data , pixels , info->width , 3 , Channels ); -} -inline void BMPFinalize( void* v ) -{ - BMPInfo* info = (BMPInfo*)v; - fclose( info->fp ); - FreePointer( info->data ); - free( info ); -} - -inline void BMPFinalizeWrite( void* v ){ BMPFinalize( v ); } -inline void BMPFinalizeRead ( void* v ){ BMPFinalize( v ); } -#endif // BMP_STREAM_INCLUDED \ No newline at end of file diff --git a/Src/BSplineData.h b/Src/BSplineData.h index ee385a21..5aae800a 100644 --- a/Src/BSplineData.h +++ b/Src/BSplineData.h @@ -35,537 +35,540 @@ DAMAGE. #include "PPolynomial.h" #include "Array.h" -enum BoundaryType +namespace PoissonRecon { - BOUNDARY_FREE , - BOUNDARY_DIRICHLET , - BOUNDARY_NEUMANN , - BOUNDARY_COUNT -}; -const char* BoundaryNames[] = { "free" , "Dirichlet" , "Neumann" }; -template< BoundaryType BType > inline bool HasPartitionOfUnity( void ){ return BType!=BOUNDARY_DIRICHLET; } -inline bool HasPartitionOfUnity( BoundaryType bType ){ return bType!=BOUNDARY_DIRICHLET; } -template< BoundaryType BType , unsigned int D > struct DerivativeBoundary{}; -template< unsigned int D > struct DerivativeBoundary< BOUNDARY_FREE , D >{ static const BoundaryType BType = BOUNDARY_FREE; }; -template< unsigned int D > struct DerivativeBoundary< BOUNDARY_DIRICHLET , D >{ static const BoundaryType BType = DerivativeBoundary< BOUNDARY_NEUMANN , D-1 >::BType; }; -template< unsigned int D > struct DerivativeBoundary< BOUNDARY_NEUMANN , D >{ static const BoundaryType BType = DerivativeBoundary< BOUNDARY_DIRICHLET , D-1 >::BType; }; -template< > struct DerivativeBoundary< BOUNDARY_FREE , 0 >{ static const BoundaryType BType = BOUNDARY_FREE; }; -template< > struct DerivativeBoundary< BOUNDARY_DIRICHLET , 0 >{ static const BoundaryType BType = BOUNDARY_DIRICHLET; }; -template< > struct DerivativeBoundary< BOUNDARY_NEUMANN , 0 >{ static const BoundaryType BType = BOUNDARY_NEUMANN; }; - - -// Generate a single signature that combines the degree, boundary type, and number of supported derivatives -template< unsigned int Degree , BoundaryType BType=BOUNDARY_FREE > struct FEMDegreeAndBType { static const unsigned int Signature = Degree * BOUNDARY_COUNT + BType; }; - -// Extract the degree and boundary type from the signaure -template< unsigned int Signature > struct FEMSignature -{ - static const unsigned int Degree = ( Signature / BOUNDARY_COUNT ); - static const BoundaryType BType = (BoundaryType)( Signature % BOUNDARY_COUNT ); - template< unsigned int D=1 > - static constexpr typename std::enable_if< (Degree>=D) , unsigned int >::type DSignature( void ){ return FEMDegreeAndBType< Degree-D , DerivativeBoundary< BType , D >::BType >::Signature; } -}; - -unsigned int FEMSignatureDegree( unsigned int signature ){ return signature / BOUNDARY_COUNT; } -BoundaryType FEMSignatureBType ( unsigned int signature ){ return (BoundaryType)( signature % BOUNDARY_COUNT ); } - -static const unsigned int FEMTrivialSignature = FEMDegreeAndBType< 0 , BOUNDARY_FREE >::Signature; - -// This class represents a function that is a linear combination of B-spline elements, -// with 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< unsigned 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< unsigned 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 + enum BoundaryType { - 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 + BOUNDARY_FREE , + BOUNDARY_DIRICHLET , + BOUNDARY_NEUMANN , + BOUNDARY_COUNT + }; + const char* BoundaryNames[] = { "free" , "Dirichlet" , "Neumann" }; + template< BoundaryType BType > inline bool HasPartitionOfUnity( void ){ return BType!=BOUNDARY_DIRICHLET; } + inline bool HasPartitionOfUnity( BoundaryType bType ){ return bType!=BOUNDARY_DIRICHLET; } + template< BoundaryType BType , unsigned int D > struct DerivativeBoundary{}; + template< unsigned int D > struct DerivativeBoundary< BOUNDARY_FREE , D >{ static const BoundaryType BType = BOUNDARY_FREE; }; + template< unsigned int D > struct DerivativeBoundary< BOUNDARY_DIRICHLET , D >{ static const BoundaryType BType = DerivativeBoundary< BOUNDARY_NEUMANN , D-1 >::BType; }; + template< unsigned int D > struct DerivativeBoundary< BOUNDARY_NEUMANN , D >{ static const BoundaryType BType = DerivativeBoundary< BOUNDARY_DIRICHLET , D-1 >::BType; }; + template< > struct DerivativeBoundary< BOUNDARY_FREE , 0 >{ static const BoundaryType BType = BOUNDARY_FREE; }; + template< > struct DerivativeBoundary< BOUNDARY_DIRICHLET , 0 >{ static const BoundaryType BType = BOUNDARY_DIRICHLET; }; + template< > struct DerivativeBoundary< BOUNDARY_NEUMANN , 0 >{ static const BoundaryType BType = BOUNDARY_NEUMANN; }; + + + // Generate a single signature that combines the degree, boundary type, and number of supported derivatives + template< unsigned int Degree , BoundaryType BType=BOUNDARY_FREE > struct FEMDegreeAndBType { static const unsigned int Signature = Degree * BOUNDARY_COUNT + BType; }; + + // Extract the degree and boundary type from the signaure + template< unsigned int Signature > struct FEMSignature { - 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< unsigned int Degree , unsigned int DDegree > struct Differentiator { static void Differentiate( const BSplineElements< Degree >& bse , BSplineElements< DDegree >& dbse ); }; -template< unsigned int Degree > struct Differentiator< Degree , Degree >{ static void Differentiate( const BSplineElements< Degree >& bse , BSplineElements< Degree >& dbse ); }; - -// Note that these bounds are inclusive -- [s,e] -#define BSPLINE_SET_BOUNDS( name , s , e ) \ - static const int name ## Start = (s); \ - static const int name ## End = (e); \ - static const unsigned int name ## Size = (e)-(s)+1 + static const unsigned int Degree = ( Signature / BOUNDARY_COUNT ); + static const BoundaryType BType = (BoundaryType)( Signature % BOUNDARY_COUNT ); + template< unsigned int D=1 > + static constexpr typename std::enable_if< (Degree>=D) , unsigned int >::type DSignature( void ){ return FEMDegreeAndBType< Degree-D , DerivativeBoundary< BType , D >::BType >::Signature; } + }; -// 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< unsigned int Degree > -struct BSplineSupportSizes -{ -protected: - static const int _Degree = Degree; -public: - inline static int Nodes( int depth ){ return ( 1<=0 || offset=0 && offset+SupportEnd<(1< [-(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[]; - static const unsigned int DownSampleSize[]; -}; -template< unsigned int Degree > const int BSplineSupportSizes< Degree >::DownSampleStart[] = { DownSample0Start , DownSample1Start }; -template< unsigned int Degree > const int BSplineSupportSizes< Degree >::DownSampleEnd [] = { DownSample0End , DownSample1End }; -template< unsigned int Degree > const unsigned int BSplineSupportSizes< Degree >::DownSampleSize [] = { DownSample0Size , DownSample1Size }; - -template< unsigned int Degree1 , unsigned int Degree2=Degree1 > -struct BSplineOverlapSizes -{ -protected: - static const int _Degree1 = Degree1; - static const int _Degree2 = Degree2; -public: - 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< unsigned int Degree1 , unsigned int Degree2 > const int BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapStart[] = { ParentOverlap0Start , ParentOverlap1Start }; -template< unsigned int Degree1 , unsigned int Degree2 > const int BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapEnd [] = { ParentOverlap0End , ParentOverlap1End }; -template< unsigned int Degree1 , unsigned int Degree2 > const int BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapSize [] = { ParentOverlap0Size , ParentOverlap1Size }; - -struct EvaluationData -{ - struct CornerEvaluator + unsigned int FEMSignatureDegree( unsigned int signature ){ return signature / BOUNDARY_COUNT; } + BoundaryType FEMSignatureBType ( unsigned int signature ){ return (BoundaryType)( signature % BOUNDARY_COUNT ); } + + static const unsigned int FEMTrivialSignature = FEMDegreeAndBType< 0 , BOUNDARY_FREE >::Signature; + + // This class represents a function that is a linear combination of B-spline elements, + // with 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< unsigned int Degree > + struct BSplineElementCoefficients { - virtual double value( int fIdx , int cIdx , int d ) const = 0; - virtual void set( int depth ) = 0; - virtual ~CornerEvaluator( void ){} + 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]; } }; - struct CenterEvaluator + + // 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< unsigned int Degree > + struct BSplineElements : public std::vector< BSplineElementCoefficients< Degree > > { - virtual double value( int fIdx , int cIdx , int d ) const = 0; - virtual void set( int depth ) = 0; - virtual ~CenterEvaluator( void ){} + 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); + } }; - struct UpSampleEvaluator + + template< unsigned int Degree , unsigned int DDegree > struct Differentiator { static void Differentiate( const BSplineElements< Degree >& bse , BSplineElements< DDegree >& dbse ); }; + template< unsigned int Degree > struct Differentiator< Degree , Degree >{ static void Differentiate( const BSplineElements< Degree >& bse , BSplineElements< Degree >& dbse ); }; + + // Note that these bounds are inclusive -- [s,e] +#define PR_BSPLINE_SET_BOUNDS( name , s , e ) \ + static const int name ## Start = (s); \ + static const int name ## End = (e); \ + static const unsigned int name ## Size = (e)-(s)+1 + + // Assumes that x is non-negative +#define PR__FLOOR_OF_HALF( x ) ( (x) >>1 ) +#define PR__CEIL_OF_HALF( x ) ( ( (x)+1 )>>1 ) + // Done with the assumption +#define PR_FLOOR_OF_HALF( x ) ( (x)<0 ? - PR__CEIL_OF_HALF( -(x) ) : PR__FLOOR_OF_HALF( x ) ) +#define PR_CEIL_OF_HALF( x ) ( (x)<0 ? - PR__FLOOR_OF_HALF( -(x) ) : PR__CEIL_OF_HALF( x ) ) +#define PR_SMALLEST_INTEGER_LARGER_THAN_HALF( x ) ( PR_CEIL_OF_HALF( (x)+1 ) ) +#define PR_LARGEST_INTEGER_SMALLER_THAN_HALF( x ) ( PR_FLOOR_OF_HALF( (x)-1 ) ) +#define PR_SMALLEST_INTEGER_LARGER_THAN_OR_EQUAL_TO_HALF( x ) ( PR_CEIL_OF_HALF( x ) ) +#define PR_LARGEST_INTEGER_SMALLER_THAN_OR_EQUAL_TO_HALF( x ) ( PR_FLOOR_OF_HALF( x ) ) + + template< unsigned int Degree > + struct BSplineSupportSizes { - virtual double value( int pIdx , int cIdx ) const = 0; - virtual void set( int depth ) = 0; - virtual ~UpSampleEvaluator( void ){} + protected: + static const int _Degree = Degree; + public: + inline static int Nodes( int depth ){ return ( 1<=0 || offset=0 && offset+SupportEnd<(1< [-(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 + PR_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 + PR_BSPLINE_SET_BOUNDS( DownSample0 , PR_SMALLEST_INTEGER_LARGER_THAN_OR_EQUAL_TO_HALF( 0 - ( _Degree + 1 + Inset ) / 2 ) , PR_LARGEST_INTEGER_SMALLER_THAN_OR_EQUAL_TO_HALF( 0 + ( _Degree + 1 - Inset ) / 2 ) ); + PR_BSPLINE_SET_BOUNDS( DownSample1 , PR_SMALLEST_INTEGER_LARGER_THAN_OR_EQUAL_TO_HALF( 1 - ( _Degree + 1 + Inset ) / 2 ) , PR_LARGEST_INTEGER_SMALLER_THAN_OR_EQUAL_TO_HALF( 1 + ( _Degree + 1 - Inset ) / 2 ) ); + static const int DownSampleStart[] , DownSampleEnd[]; + static const unsigned int DownSampleSize[]; }; -}; + template< unsigned int Degree > const int BSplineSupportSizes< Degree >::DownSampleStart[] = { DownSample0Start , DownSample1Start }; + template< unsigned int Degree > const int BSplineSupportSizes< Degree >::DownSampleEnd [] = { DownSample0End , DownSample1End }; + template< unsigned int Degree > const unsigned int BSplineSupportSizes< Degree >::DownSampleSize [] = { DownSample0Size , DownSample1Size }; -template< unsigned int FEMSig > -class BSplineEvaluationData -{ -public: - static const unsigned int Degree = FEMSignature< FEMSig >::Degree; - static const int Pad = (FEMSignature< FEMSig >::BType==BOUNDARY_FREE ) ? BSplineSupportSizes< Degree >::SupportEnd : ( (Degree&1) && FEMSignature< FEMSig >::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 ); - static double Value( int depth , int off , double s , int d ); - static double Integral( int depth , int off , double b , double e , int d ); - - struct BSplineUpSamplingCoefficients + template< unsigned int Degree1 , unsigned int Degree2=Degree1 > + struct BSplineOverlapSizes { protected: - int _coefficients[ BSplineSupportSizes< Degree >::UpSampleSize ]; + static const int _Degree1 = Degree1; + static const int _Degree2 = Degree2; public: - BSplineUpSamplingCoefficients( void ){ ; } - BSplineUpSamplingCoefficients( int depth , int offset ); - double operator[] ( int idx ){ return (double)_coefficients[idx] / (1< EData1; + typedef BSplineSupportSizes< Degree2 > EData2; + PR_BSPLINE_SET_BOUNDS( Overlap , EData1:: SupportStart - EData2::SupportEnd , EData1:: SupportEnd - EData2::SupportStart ); + PR_BSPLINE_SET_BOUNDS( ChildOverlap , EData1::ChildSupportStart - EData2::SupportEnd , EData1::ChildSupportEnd - EData2::SupportStart ); + PR_BSPLINE_SET_BOUNDS( OverlapSupport , OverlapStart + EData2::SupportStart , OverlapEnd + EData2::SupportEnd ); + PR_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 + PR_BSPLINE_SET_BOUNDS( ParentOverlap0 , PR_SMALLEST_INTEGER_LARGER_THAN_HALF( 0 - ( 2*_Degree2 + _Degree1 + 3 + 2*EData2::Inset - EData1::Inset ) / 2 ) , PR_LARGEST_INTEGER_SMALLER_THAN_HALF( 0 + ( 2*_Degree2 + _Degree1 + 3 - 2*EData2::Inset + EData1::Inset ) / 2 ) ); + PR_BSPLINE_SET_BOUNDS( ParentOverlap1 , PR_SMALLEST_INTEGER_LARGER_THAN_HALF( 1 - ( 2*_Degree2 + _Degree1 + 3 + 2*EData2::Inset - EData1::Inset ) / 2 ) , PR_LARGEST_INTEGER_SMALLER_THAN_HALF( 1 + ( 2*_Degree2 + _Degree1 + 3 - 2*EData2::Inset + EData1::Inset ) / 2 ) ); + static const int ParentOverlapStart[] , ParentOverlapEnd[] , ParentOverlapSize[]; }; + template< unsigned int Degree1 , unsigned int Degree2 > const int BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapStart[] = { ParentOverlap0Start , ParentOverlap1Start }; + template< unsigned int Degree1 , unsigned int Degree2 > const int BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapEnd [] = { ParentOverlap0End , ParentOverlap1End }; + template< unsigned int Degree1 , unsigned int Degree2 > const int BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapSize [] = { ParentOverlap0Size , ParentOverlap1Size }; - template< unsigned int D > - struct CenterEvaluator + struct EvaluationData { - struct Evaluator : public EvaluationData::CenterEvaluator + struct CornerEvaluator { - protected: - friend BSplineEvaluationData; - int _depth; - double _ccValues[D+1][IndexSize][BSplineSupportSizes< Degree >::SupportSize]; - public: - Evaluator( void ){ _depth = 0 ; memset( _ccValues , 0 , sizeof(_ccValues) ); } - double value( int fIdx , int cIdx , int d ) const; - int depth( void ) const { return _depth; } - void set( int depth ){ BSplineEvaluationData< FEMSig >::template SetCenterEvaluator< D >( *this , depth ); } + virtual double value( int fIdx , int cIdx , int d ) const = 0; + virtual void set( int depth ) = 0; + virtual ~CornerEvaluator( void ){} }; - struct ChildEvaluator : public EvaluationData::CenterEvaluator + struct CenterEvaluator { - protected: - friend BSplineEvaluationData; - int _parentDepth; - double _pcValues[D+1][IndexSize][BSplineSupportSizes< Degree >::ChildSupportSize]; - public: - ChildEvaluator( void ){ _parentDepth = 0 ; memset( _pcValues , 0 , sizeof(_pcValues) ); } - double value( int fIdx , int cIdx , int d ) const; - int parentDepth( void ) const { return _parentDepth; } - int childDepth( void ) const { return _parentDepth+1; } - void set( int parentDepth ){ BSplineEvaluationData< FEMSig >::template SetChildCenterEvaluator< D >( *this , parentDepth ); } + virtual double value( int fIdx , int cIdx , int d ) const = 0; + virtual void set( int depth ) = 0; + virtual ~CenterEvaluator( void ){} + }; + struct UpSampleEvaluator + { + virtual double value( int pIdx , int cIdx ) const = 0; + virtual void set( int depth ) = 0; + virtual ~UpSampleEvaluator( void ){} }; }; - template< unsigned int D > static void SetCenterEvaluator( typename CenterEvaluator< D >::Evaluator& evaluator , int depth ); - template< unsigned int D > static void SetChildCenterEvaluator( typename CenterEvaluator< D >::ChildEvaluator& evaluator , int parentDepth ); - template< unsigned int D > - struct CornerEvaluator + template< unsigned int FEMSig > + class BSplineEvaluationData { - struct Evaluator : public EvaluationData::CornerEvaluator + public: + static const unsigned int Degree = FEMSignature< FEMSig >::Degree; + static const int Pad = (FEMSignature< FEMSig >::BType==BOUNDARY_FREE ) ? BSplineSupportSizes< Degree >::SupportEnd : ( (Degree&1) && FEMSignature< FEMSig >::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 ); + static double Value( int depth , int off , double s , int d ); + static double Integral( int depth , int off , double b , double e , int d ); + + struct BSplineUpSamplingCoefficients { protected: - friend BSplineEvaluationData; - int _depth; - double _ccValues[D+1][IndexSize][BSplineSupportSizes< Degree >::BCornerSize]; + int _coefficients[ BSplineSupportSizes< Degree >::UpSampleSize ]; public: - Evaluator( void ){ _depth = 0 ; memset( _ccValues , 0 , sizeof( _ccValues ) ); } - double value( int fIdx , int cIdx , int d ) const; - int depth( void ) const { return _depth; } - void set( int depth ){ BSplineEvaluationData< FEMSig >::template SetCornerEvaluator< D >( *this , depth ); } + BSplineUpSamplingCoefficients( void ){ ; } + BSplineUpSamplingCoefficients( int depth , int offset ); + double operator[] ( int idx ){ return (double)_coefficients[idx] / (1< + struct CenterEvaluator + { + struct Evaluator : public EvaluationData::CenterEvaluator + { + protected: + friend BSplineEvaluationData; + int _depth; + double _ccValues[D+1][IndexSize][BSplineSupportSizes< Degree >::SupportSize]; + public: + Evaluator( void ){ _depth = 0 ; memset( _ccValues , 0 , sizeof(_ccValues) ); } + double value( int fIdx , int cIdx , int d ) const; + int depth( void ) const { return _depth; } + void set( int depth ){ BSplineEvaluationData< FEMSig >::template SetCenterEvaluator< D >( *this , depth ); } + }; + struct ChildEvaluator : public EvaluationData::CenterEvaluator + { + protected: + friend BSplineEvaluationData; + int _parentDepth; + double _pcValues[D+1][IndexSize][BSplineSupportSizes< Degree >::ChildSupportSize]; + public: + ChildEvaluator( void ){ _parentDepth = 0 ; memset( _pcValues , 0 , sizeof(_pcValues) ); } + double value( int fIdx , int cIdx , int d ) const; + int parentDepth( void ) const { return _parentDepth; } + int childDepth( void ) const { return _parentDepth+1; } + void set( int parentDepth ){ BSplineEvaluationData< FEMSig >::template SetChildCenterEvaluator< D >( *this , parentDepth ); } + }; + }; + template< unsigned int D > static void SetCenterEvaluator( typename CenterEvaluator< D >::Evaluator& evaluator , int depth ); + template< unsigned int D > static void SetChildCenterEvaluator( typename CenterEvaluator< D >::ChildEvaluator& evaluator , int parentDepth ); + + template< unsigned int D > + struct CornerEvaluator + { + struct Evaluator : public EvaluationData::CornerEvaluator + { + protected: + friend BSplineEvaluationData; + int _depth; + double _ccValues[D+1][IndexSize][BSplineSupportSizes< Degree >::BCornerSize]; + public: + Evaluator( void ){ _depth = 0 ; memset( _ccValues , 0 , sizeof( _ccValues ) ); } + double value( int fIdx , int cIdx , int d ) const; + int depth( void ) const { return _depth; } + void set( int depth ){ BSplineEvaluationData< FEMSig >::template SetCornerEvaluator< D >( *this , depth ); } + }; + struct ChildEvaluator : public EvaluationData::CornerEvaluator + { + protected: + friend BSplineEvaluationData; + int _parentDepth; + double _pcValues[D+1][IndexSize][BSplineSupportSizes< Degree >::ChildBCornerSize]; + public: + ChildEvaluator( void ){ _parentDepth = 0 ; memset( _pcValues , 0 , sizeof( _pcValues ) ); } + double value( int fIdx , int cIdx , int d ) const; + int parentDepth( void ) const { return _parentDepth; } + int childDepth( void ) const { return _parentDepth+1; } + void set( int parentDepth ){ BSplineEvaluationData< FEMSig >::template SetChildCornerEvaluator< D >( *this , parentDepth ); } + }; + }; + template< unsigned int D > static void SetCornerEvaluator( typename CornerEvaluator< D >::Evaluator& evaluator , int depth ); + template< unsigned int D > static void SetChildCornerEvaluator( typename CornerEvaluator< D >::ChildEvaluator& evaluator , int parentDepth ); + + template< unsigned int D > + struct Evaluator + { + typename CenterEvaluator< D >::Evaluator centerEvaluator; + typename CornerEvaluator< D >::Evaluator cornerEvaluator; + double centerValue( int fIdx , int cIdx , int d ) const { return centerEvaluator.value( fIdx , cIdx , d ); } + double cornerValue( int fIdx , int cIdx , int d ) const { return cornerEvaluator.value( fIdx , cIdx , d ); } + }; + template< unsigned int D > static void SetEvaluator( Evaluator< D >& evaluator , int depth ){ SetCenterEvaluator< D >( evaluator.centerEvaluator , depth ) , SetCornerEvaluator< D >( evaluator.cornerEvaluator , depth ); } + template< unsigned int D > + struct ChildEvaluator + { + typename CenterEvaluator< D >::ChildEvaluator centerEvaluator; + typename CornerEvaluator< D >::ChildEvaluator cornerEvaluator; + double centerValue( int fIdx , int cIdx , int d ) const { return centerEvaluator.value( fIdx , cIdx , d ); } + double cornerValue( int fIdx , int cIdx , int d ) const { return cornerEvaluator.value( fIdx , cIdx , d ); } }; - struct ChildEvaluator : public EvaluationData::CornerEvaluator + template< unsigned int D > static void SetChildEvaluator( ChildEvaluator< D >& evaluator , int depth ){ SetChildCenterEvaluator< D >( evaluator.centerEvaluator , depth ) , SetChildCornerEvaluator< D >( evaluator.cornerEvaluator , depth ); } + + struct UpSampleEvaluator : public EvaluationData::UpSampleEvaluator { protected: friend BSplineEvaluationData; - int _parentDepth; - double _pcValues[D+1][IndexSize][BSplineSupportSizes< Degree >::ChildBCornerSize]; + int _lowDepth; + double _pcValues[IndexSize][BSplineSupportSizes< Degree >::UpSampleSize]; public: - ChildEvaluator( void ){ _parentDepth = 0 ; memset( _pcValues , 0 , sizeof( _pcValues ) ); } - double value( int fIdx , int cIdx , int d ) const; - int parentDepth( void ) const { return _parentDepth; } - int childDepth( void ) const { return _parentDepth+1; } - void set( int parentDepth ){ BSplineEvaluationData< FEMSig >::template SetChildCornerEvaluator< D >( *this , parentDepth ); } + UpSampleEvaluator( void ){ _lowDepth = 0 ; memset( _pcValues , 0 , sizeof( _pcValues ) ); } + double value( int pIdx , int cIdx ) const; + int lowDepth( void ) const { return _lowDepth; } + void set( int lowDepth ){ BSplineEvaluationData::SetUpSampleEvaluator( *this , lowDepth ); } }; + static void SetUpSampleEvaluator( UpSampleEvaluator& evaluator , int lowDepth ); }; - template< unsigned int D > static void SetCornerEvaluator( typename CornerEvaluator< D >::Evaluator& evaluator , int depth ); - template< unsigned int D > static void SetChildCornerEvaluator( typename CornerEvaluator< D >::ChildEvaluator& evaluator , int parentDepth ); - template< unsigned int D > - struct Evaluator + template< unsigned int FEMSig1 , unsigned int FEMSig2 > + class BSplineIntegrationData { - typename CenterEvaluator< D >::Evaluator centerEvaluator; - typename CornerEvaluator< D >::Evaluator cornerEvaluator; - double centerValue( int fIdx , int cIdx , int d ) const { return centerEvaluator.value( fIdx , cIdx , d ); } - double cornerValue( int fIdx , int cIdx , int d ) const { return cornerEvaluator.value( fIdx , cIdx , d ); } - }; - template< unsigned int D > static void SetEvaluator( Evaluator< D >& evaluator , int depth ){ SetCenterEvaluator< D >( evaluator.centerEvaluator , depth ) , SetCornerEvaluator< D >( evaluator.cornerEvaluator , depth ); } - template< unsigned int D > - struct ChildEvaluator - { - typename CenterEvaluator< D >::ChildEvaluator centerEvaluator; - typename CornerEvaluator< D >::ChildEvaluator cornerEvaluator; - double centerValue( int fIdx , int cIdx , int d ) const { return centerEvaluator.value( fIdx , cIdx , d ); } - double cornerValue( int fIdx , int cIdx , int d ) const { return cornerEvaluator.value( fIdx , cIdx , d ); } - }; - template< unsigned int D > static void SetChildEvaluator( ChildEvaluator< D >& evaluator , int depth ){ SetChildCenterEvaluator< D >( evaluator.centerEvaluator , depth ) , SetChildCornerEvaluator< D >( evaluator.cornerEvaluator , depth ); } - - struct UpSampleEvaluator : public EvaluationData::UpSampleEvaluator - { - protected: - friend BSplineEvaluationData; - int _lowDepth; - double _pcValues[IndexSize][BSplineSupportSizes< Degree >::UpSampleSize]; public: - UpSampleEvaluator( void ){ _lowDepth = 0 ; memset( _pcValues , 0 , sizeof( _pcValues ) ); } - double value( int pIdx , int cIdx ) const; - int lowDepth( void ) const { return _lowDepth; } - void set( int lowDepth ){ BSplineEvaluationData::SetUpSampleEvaluator( *this , lowDepth ); } - }; - static void SetUpSampleEvaluator( UpSampleEvaluator& evaluator , int lowDepth ); -}; + static const unsigned int Degree1 = FEMSignature< FEMSig1 >::Degree; + static const unsigned int Degree2 = FEMSignature< FEMSig2 >::Degree; + static const int OffsetStart = - BSplineOverlapSizes< Degree1 , Degree2 >::OverlapSupportStart; + static const int OffsetStop = BSplineOverlapSizes< Degree1 , Degree2 >::OverlapSupportEnd + ( Degree1&1 ); + static const int IndexSize = OffsetStart + OffsetStop + 1 + 2 * BSplineEvaluationData< FEMSig1 >::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< FEMSig1 >::Pad + OffsetStart + 1 + offset - ( dim-OffsetStop ); + else return BSplineEvaluationData< FEMSig1 >::Pad + OffsetStart; + } + static inline int IndexToOffset( int depth , int idx ){ return ( idx-BSplineEvaluationData< FEMSig1 >::Pad<=OffsetStart ? idx-BSplineEvaluationData< FEMSig1 >::Pad : ( BSplineSupportSizes< Degree1 >::Nodes(depth) + BSplineEvaluationData< FEMSig1 >::Pad - IndexSize + idx ) ); } -template< unsigned int FEMSig1 , unsigned int FEMSig2 > -class BSplineIntegrationData -{ -public: - static const unsigned int Degree1 = FEMSignature< FEMSig1 >::Degree; - static const unsigned int Degree2 = FEMSignature< FEMSig2 >::Degree; - static const int OffsetStart = - BSplineOverlapSizes< Degree1 , Degree2 >::OverlapSupportStart; - static const int OffsetStop = BSplineOverlapSizes< Degree1 , Degree2 >::OverlapSupportEnd + ( Degree1&1 ); - static const int IndexSize = OffsetStart + OffsetStop + 1 + 2 * BSplineEvaluationData< FEMSig1 >::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< FEMSig1 >::Pad + OffsetStart + 1 + offset - ( dim-OffsetStop ); - else return BSplineEvaluationData< FEMSig1 >::Pad + OffsetStart; - } - static inline int IndexToOffset( int depth , int idx ){ return ( idx-BSplineEvaluationData< FEMSig1 >::Pad<=OffsetStart ? idx-BSplineEvaluationData< FEMSig1 >::Pad : ( BSplineSupportSizes< Degree1 >::Nodes(depth) + BSplineEvaluationData< FEMSig1 >::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=Degree1 , unsigned int D2=Degree2 > - struct Integrator + 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 { - protected: - friend BSplineIntegrationData; - int _depth; - double _ccIntegrals[D1+1][D2+1][IndexSize][BSplineOverlapSizes< Degree1 , Degree2 >::OverlapSize]; - public: - Integrator( void ) + template< unsigned int D1=Degree1 , unsigned int D2=Degree2 > + struct Integrator { - _depth = 0; - memset(_ccIntegrals, 0, sizeof(_ccIntegrals)); - } - double dot( int fIdx1 , int fidx2 , int d1 , int d2 ) const; - int depth( void ) const { return _depth; } - void set( int depth ){ BSplineIntegrationData::SetIntegrator( *this , depth ); } - }; - template< unsigned int D1=Degree1 , unsigned int D2=Degree2 > - struct ChildIntegrator - { - protected: - friend BSplineIntegrationData; - int _parentDepth; - double _pcIntegrals[D1+1][D2+1][IndexSize][BSplineOverlapSizes< Degree1 , Degree2 >::ChildOverlapSize]; - public: - ChildIntegrator( void ) + protected: + friend BSplineIntegrationData; + int _depth; + double _ccIntegrals[D1+1][D2+1][IndexSize][BSplineOverlapSizes< Degree1 , Degree2 >::OverlapSize]; + public: + Integrator( void ) + { + _depth = 0; + memset(_ccIntegrals, 0, sizeof(_ccIntegrals)); + } + double dot( int fIdx1 , int fidx2 , int d1 , int d2 ) const; + int depth( void ) const { return _depth; } + void set( int depth ){ BSplineIntegrationData::SetIntegrator( *this , depth ); } + }; + template< unsigned int D1=Degree1 , unsigned int D2=Degree2 > + struct ChildIntegrator { - _parentDepth = 0; - memset( _pcIntegrals , 0 , sizeof( _pcIntegrals ) ); - } - double dot( int fIdx1 , int fidx2 , int d1 , int d2 ) const; - int parentDepth( void ) const { return _parentDepth; } - int childDepth( void ) const { return _parentDepth+1; } - void set( int depth ){ BSplineIntegrationData::SetChildIntegrator( *this , depth ); } + protected: + friend BSplineIntegrationData; + int _parentDepth; + double _pcIntegrals[D1+1][D2+1][IndexSize][BSplineOverlapSizes< Degree1 , Degree2 >::ChildOverlapSize]; + public: + ChildIntegrator( void ) + { + _parentDepth = 0; + memset( _pcIntegrals , 0 , sizeof( _pcIntegrals ) ); + } + double dot( int fIdx1 , int fidx2 , int d1 , int d2 ) const; + int parentDepth( void ) const { return _parentDepth; } + int childDepth( void ) const { return _parentDepth+1; } + void set( int depth ){ BSplineIntegrationData::SetChildIntegrator( *this , depth ); } + }; }; - }; - // 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 ); - }; + // 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 ); - 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< unsigned int FEMSig , unsigned int D=0 > -struct BSplineData -{ - static const unsigned int Degree = FEMSignature< FEMSig >::Degree; - static const int _Degree = Degree; - // Note that this struct stores the components in left-to-right order - struct BSplineComponents - { - BSplineComponents( void ){ ; } - BSplineComponents( int depth , int offset ); - const Polynomial< Degree >* operator[] ( int idx ) const { return _polys[idx]; } protected: - Polynomial< Degree > _polys[Degree+1][D+1]; - }; - struct SparseBSplineEvaluator - { - void init( unsigned int depth ) + // _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 { - _depth = depth , _width = 1./(1<::SupportEnd >=0 - _preStart = -BSplineSupportSizes< _Degree >::SupportEnd; - // _postStart + BSplineSupportSizes< _Degree >::SupportEnd <= (1<::SupportEnd; - _preEnd = _preStart + _Degree + 1; - _postEnd = _postStart + _Degree + 1; - _centerIndex = ( ( _preStart + _Degree + 1 ) + ( _postStart - 1 ) ) / 2; - _centerComponents = BSplineComponents( depth , _centerIndex ); - for( int i=0 ; i<=Degree ; i++ ) _preComponents[i] = BSplineComponents( depth , _preStart+i ) , _postComponents[i] = BSplineComponents( depth , _postStart+i ); - } - double value( double p , int fIdx , int d ) const { return value( p , (int)( p * (1<<_depth ) ) , fIdx , d ); } - double value( double p , int pIdx , int fIdx , int d ) const + 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 { - if ( fIdx<_preStart ) return 0; - else if( fIdx<_preEnd ) return _preComponents [fIdx-_preStart ][pIdx-fIdx+_LeftSupportRadius][d]( p ); - else if( fIdx<_postStart ) return _centerComponents [pIdx-fIdx+_LeftSupportRadius][d]( p+_width*(_centerIndex-fIdx) ); - else if( fIdx<_postEnd ) return _postComponents[fIdx-_postStart][pIdx-fIdx+_LeftSupportRadius][d]( p ); - else return 0; - } - const Polynomial< _Degree >* polynomialsAndOffset( double& p , int fIdx ) const { return polynomialsAndOffset( p , (int)( p * (1<<_depth ) ) , fIdx ); } - const Polynomial< _Degree >* polynomialsAndOffset( double& p , int pIdx , int fIdx ) const + 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 > { - if ( fIdx<_preEnd ){ return _preComponents [fIdx-_preStart ][pIdx-fIdx+_LeftSupportRadius]; } - else if( fIdx<_postStart ){ p += _width*(_centerIndex-fIdx) ; return _centerComponents [pIdx-fIdx+_LeftSupportRadius]; } - else { return _postComponents[fIdx-_postStart][pIdx-fIdx+_LeftSupportRadius]; } - } - protected: - static const int _LeftSupportRadius = -BSplineSupportSizes< _Degree >::SupportStart; - BSplineComponents _preComponents[_Degree+1] , _postComponents[_Degree+1] ,_centerComponents; - int _preStart , _preEnd , _postStart , _postEnd , _centerIndex; - unsigned int _depth; - double _width; + 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 ); + }; }; - const SparseBSplineEvaluator& operator[]( int depth ) const { return _evaluators[depth]; } - - inline static int RemapOffset( int depth , int idx , bool& reflect ); +#undef PR_BSPLINE_SET_BOUNDS +#undef PR__FLOOR_OF_HALF +#undef PR__CEIL_OF_HALF +#undef PR_FLOOR_OF_HALF +#undef PR_CEIL_OF_HALF +#undef PR_SMALLEST_INTEGER_LARGER_THAN_HALF +#undef PR_LARGEST_INTEGER_SMALLER_THAN_HALF +#undef PR_SMALLEST_INTEGER_LARGER_THAN_OR_EQUAL_TO_HALF +#undef PR_LARGEST_INTEGER_SMALLER_THAN_OR_EQUAL_TO_HALF + + + template< unsigned int FEMSig , unsigned int D=0 > + struct BSplineData + { + static const unsigned int Degree = FEMSignature< FEMSig >::Degree; + static const int _Degree = Degree; + // Note that this struct stores the components in left-to-right order + struct BSplineComponents + { + BSplineComponents( void ){ ; } + BSplineComponents( int depth , int offset ); + const Polynomial< Degree >* operator[] ( int idx ) const { return _polys[idx]; } + protected: + Polynomial< Degree > _polys[Degree+1][D+1]; + }; + struct SparseBSplineEvaluator + { + void init( unsigned int depth ) + { + _depth = depth , _width = 1./(1<::SupportEnd >=0 + _preStart = -BSplineSupportSizes< _Degree >::SupportEnd; + // _postStart + BSplineSupportSizes< _Degree >::SupportEnd <= (1<::SupportEnd; + _preEnd = _preStart + _Degree + 1; + _postEnd = _postStart + _Degree + 1; + _centerIndex = ( ( _preStart + _Degree + 1 ) + ( _postStart - 1 ) ) / 2; + _centerComponents = BSplineComponents( depth , _centerIndex ); + for( int i=0 ; i<=Degree ; i++ ) _preComponents[i] = BSplineComponents( depth , _preStart+i ) , _postComponents[i] = BSplineComponents( depth , _postStart+i ); + } + double value( double p , int fIdx , int d ) const { return value( p , (int)( p * (1<<_depth ) ) , fIdx , d ); } + double value( double p , int pIdx , int fIdx , int d ) const + { + if ( fIdx<_preStart ) return 0; + else if( fIdx<_preEnd ) return _preComponents [fIdx-_preStart ][pIdx-fIdx+_LeftSupportRadius][d]( p ); + else if( fIdx<_postStart ) return _centerComponents [pIdx-fIdx+_LeftSupportRadius][d]( p+_width*(_centerIndex-fIdx) ); + else if( fIdx<_postEnd ) return _postComponents[fIdx-_postStart][pIdx-fIdx+_LeftSupportRadius][d]( p ); + else return 0; + } + const Polynomial< _Degree >* polynomialsAndOffset( double& p , int fIdx ) const { return polynomialsAndOffset( p , (int)( p * (1<<_depth ) ) , fIdx ); } + const Polynomial< _Degree >* polynomialsAndOffset( double& p , int pIdx , int fIdx ) const + { + if ( fIdx<_preEnd ){ return _preComponents [fIdx-_preStart ][pIdx-fIdx+_LeftSupportRadius]; } + else if( fIdx<_postStart ){ p += _width*(_centerIndex-fIdx) ; return _centerComponents [pIdx-fIdx+_LeftSupportRadius]; } + else { return _postComponents[fIdx-_postStart][pIdx-fIdx+_LeftSupportRadius]; } + } + protected: + static const int _LeftSupportRadius = -BSplineSupportSizes< _Degree >::SupportStart; + BSplineComponents _preComponents[_Degree+1] , _postComponents[_Degree+1] ,_centerComponents; + int _preStart , _preEnd , _postStart , _postEnd , _centerIndex; + unsigned int _depth; + double _width; + }; + const SparseBSplineEvaluator& operator[]( int depth ) const { return _evaluators[depth]; } - BSplineData( void ); - void reset( int maxDepth ); - BSplineData( int maxDepth ); - ~BSplineData( void ); + inline static int RemapOffset( int depth , int idx , bool& reflect ); -protected: - unsigned int _maxDepth; - Pointer( SparseBSplineEvaluator ) _evaluators; -}; + BSplineData( void ); + void reset( int maxDepth ); + BSplineData( int maxDepth ); + ~BSplineData( void ); -template< unsigned int Degree1 , unsigned int Degree2 > void SetBSplineElementIntegrals( double integrals[Degree1+1][Degree2+1] ); + protected: + unsigned int _maxDepth; + Pointer( SparseBSplineEvaluator ) _evaluators; + }; + template< unsigned int Degree1 , unsigned 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/BSplineData.inl b/Src/BSplineData.inl index e13f8a5e..9ee58fa6 100644 --- a/Src/BSplineData.inl +++ b/Src/BSplineData.inl @@ -441,7 +441,7 @@ double BSplineIntegrationData< FEMSig1 , FEMSig2 >::FunctionIntegrator::ChildInt ///////////////// // BSplineData // ///////////////// -#define MODULO( A , B ) ( (A)<0 ? ( (B)-((-(A))%(B)) ) % (B) : (A) % (B) ) +#define PR_MODULO( A , B ) ( (A)<0 ? ( (B)-((-(A))%(B)) ) % (B) : (A) % (B) ) template< unsigned int FEMSig , unsigned int D > BSplineData< FEMSig , D >::BSplineComponents::BSplineComponents( int depth , int offset ) @@ -476,12 +476,12 @@ int BSplineData< FEMSig , D >::RemapOffset( int depth , int offset , bool& refle const int I = ( Degree&1 ) ? 0 : 1; if( FEMSignature< FEMSig >::BType==BOUNDARY_FREE ){ reflect = false ; return offset; } int dim = BSplineEvaluationData< FEMDegreeAndBType< Degree , BOUNDARY_NEUMANN >::Signature >::End( depth ) - BSplineEvaluationData< FEMDegreeAndBType< Degree , BOUNDARY_NEUMANN >::Signature >::Begin( depth ); - offset = MODULO( offset , 2*(dim-1+I) ); + offset = PR_MODULO( offset , 2*(dim-1+I) ); reflect = offset>=dim; if( reflect ) return 2*(dim-1+I) - (offset+I); else return offset; } -#undef MODULO +#undef PR_MODULO template< unsigned int FEMSig , unsigned int D > BSplineData< FEMSig , D >::BSplineData( void ) diff --git a/Src/BinaryNode.h b/Src/BinaryNode.h index e0561ae5..85e1b2d0 100644 --- a/Src/BinaryNode.h +++ b/Src/BinaryNode.h @@ -29,44 +29,46 @@ DAMAGE. #ifndef BINARY_NODE_INCLUDED #define BINARY_NODE_INCLUDED -class BinaryNode +namespace PoissonRecon { -public: - static inline size_t CenterCount( unsigned int depth ) { return (size_t)1< static inline Real Width( unsigned int depth ){ return Real(1.0/((size_t)1< static inline void CenterAndWidth( unsigned int depth , size_t offset , Real& center , Real& width ){ width = Real (1.0/((size_t)1< static inline void CornerAndWidth( unsigned int depth , size_t offset , Real& corner , Real& width ){ width = Real(1.0/((size_t)1< static inline void CenterAndWidth( size_t idx , Real& center , Real& width ) - { - unsigned int depth; - size_t offset; - CenterDepthAndOffset( idx , depth , offset ); - CenterAndWidth( depth , offset , center , width ); - } - template< class Real > static inline void CornerAndWidth( size_t idx , Real& corner , Real& width ) - { - unsigned int depth; - size_t offset; - CornerDepthAndOffset( idx , depth , offset ); - CornerAndWidth( depth , offset , corner , width ); - } - static inline void CenterDepthAndOffset( size_t idx , unsigned int &depth , size_t &offset ) - { - offset = idx , depth = 0; - while( offset>=((size_t)1<=( ((size_t)1< static inline Real Width( unsigned int depth ){ return Real(1.0/((size_t)1< static inline void CenterAndWidth( unsigned int depth , size_t offset , Real& center , Real& width ){ width = Real (1.0/((size_t)1< static inline void CornerAndWidth( unsigned int depth , size_t offset , Real& corner , Real& width ){ width = Real(1.0/((size_t)1< static inline void CenterAndWidth( size_t idx , Real& center , Real& width ) + { + unsigned int depth; + size_t offset; + CenterDepthAndOffset( idx , depth , offset ); + CenterAndWidth( depth , offset , center , width ); + } + template< class Real > static inline void CornerAndWidth( size_t idx , Real& corner , Real& width ) + { + unsigned int depth; + size_t offset; + CornerDepthAndOffset( idx , depth , offset ); + CornerAndWidth( depth , offset , corner , width ); + } + static inline void CenterDepthAndOffset( size_t idx , unsigned int &depth , size_t &offset ) + { + offset = idx , depth = 0; + while( offset>=((size_t)1<=( ((size_t)1< -struct BlockedVector +namespace PoissonRecon { - BlockedVector( size_t sz=0 , T defaultValue=T() ) : _defaultValue( defaultValue ) + // This represents a vector that can only grow in size. + // It has the property that once a reference to an element is returned, that reference remains valid until the vector is destroyed. + template< typename T , unsigned int LogBlockSize=10 , unsigned int InitialBlocks=10 , unsigned int AllocationMultiplier=2 > + struct BlockedVector { - _reservedBlocks = InitialBlocks; - _blocks = NewPointer< Pointer( T ) >( _reservedBlocks ); - for( size_t i=0 ; i<_reservedBlocks ; i++ ) _blocks[i] = NullPointer( T ); - _allocatedBlocks = _size = 0; - if( sz ) resize( sz ); - } - - ~BlockedVector( void ) - { - for( size_t i=0 ; i<_allocatedBlocks ; i++ ) DeletePointer( _blocks[i] ); - DeletePointer( _blocks ); - } + BlockedVector( size_t sz=0 , T defaultValue=T() ) : _defaultValue( defaultValue ) + { + _reservedBlocks = InitialBlocks; + _blocks = NewPointer< Pointer( T ) >( _reservedBlocks ); + for( size_t i=0 ; i<_reservedBlocks ; i++ ) _blocks[i] = NullPointer( T ); + _allocatedBlocks = _size = 0; + if( sz ) resize( sz ); + } - BlockedVector( const BlockedVector& v ) - { - _reservedBlocks = v._reservedBlocks , _allocatedBlocks = v._allocatedBlocks , _size = v._size , _defaultValue = v._defaultValue; - _blocks = NewPointer< Pointer( T ) >( _reservedBlocks ); - for( size_t i=0 ; i<_allocatedBlocks ; i++ ) + ~BlockedVector( void ) { - _blocks[i] = NewPointer< T >( _BlockSize ); - memcpy( _blocks[i] , v._blocks[i] , sizeof(T)*_BlockSize ); + for( size_t i=0 ; i<_allocatedBlocks ; i++ ) DeletePointer( _blocks[i] ); + DeletePointer( _blocks ); } - for( size_t i=_allocatedBlocks ; i<_reservedBlocks ; i++ ) _blocks[i] = NullPointer( Pointer ( T ) ); - } - BlockedVector& operator = ( const BlockedVector& v ) - { - for( size_t i=0 ; i<_allocatedBlocks ; i++ ) DeletePointer( _blocks[i] ); - DeletePointer( _blocks ); - _reservedBlocks = v._reservedBlocks , _blocks = v._blocks , _allocatedBlocks = v._allocatedBlocks , _size = v._size , _defaultValue = v._defaultValue; - _blocks = NewPointer< Pointer( T ) >( _reservedBlocks ); - for( size_t i=0 ; i<_allocatedBlocks ; i++ ) + BlockedVector( const BlockedVector& v ) { - _blocks[i] = NewPointer< T >( _BlockSize ); - memcpy( _blocks[i] , v._blocks[i] , sizeof(T)*_BlockSize ); + _reservedBlocks = v._reservedBlocks , _allocatedBlocks = v._allocatedBlocks , _size = v._size , _defaultValue = v._defaultValue; + _blocks = NewPointer< Pointer( T ) >( _reservedBlocks ); + for( size_t i=0 ; i<_allocatedBlocks ; i++ ) + { + _blocks[i] = NewPointer< T >( _BlockSize ); + memcpy( _blocks[i] , v._blocks[i] , sizeof(T)*_BlockSize ); + } + for( size_t i=_allocatedBlocks ; i<_reservedBlocks ; i++ ) _blocks[i] = NullPointer( Pointer ( T ) ); } - for( size_t i=_allocatedBlocks ; i<_reservedBlocks ; i++ ) _blocks[i] = NullPointer( T ); - return *this; - } - BlockedVector( BlockedVector&& v ) - { - _reservedBlocks = v._reservedBlocks , _allocatedBlocks = v._allocatedBlocks , _size = v._size , _defaultValue = v._defaultValue , _blocks = v._blocks; - v._reservedBlocks = v._allocatedBlocks = v._size = 0 , v._blocks = NullPointer( Pointer( T ) ); - } + BlockedVector& operator = ( const BlockedVector& v ) + { + for( size_t i=0 ; i<_allocatedBlocks ; i++ ) DeletePointer( _blocks[i] ); + DeletePointer( _blocks ); + _reservedBlocks = v._reservedBlocks , _blocks = v._blocks , _allocatedBlocks = v._allocatedBlocks , _size = v._size , _defaultValue = v._defaultValue; + _blocks = NewPointer< Pointer( T ) >( _reservedBlocks ); + for( size_t i=0 ; i<_allocatedBlocks ; i++ ) + { + _blocks[i] = NewPointer< T >( _BlockSize ); + memcpy( _blocks[i] , v._blocks[i] , sizeof(T)*_BlockSize ); + } + for( size_t i=_allocatedBlocks ; i<_reservedBlocks ; i++ ) _blocks[i] = NullPointer( T ); + return *this; + } - BlockedVector& operator = ( BlockedVector&& v ) - { - for( size_t i=0 ; i<_allocatedBlocks ; i++ ) DeletePointer( _blocks[i] ); - DeletePointer( _blocks ); - _reservedBlocks = v._reservedBlocks , _allocatedBlocks = v._allocatedBlocks , _size = v._size , _defaultValue = v._defaultValue , _blocks = v._blocks; - v._reservedBlocks = v._allocatedBlocks = v._size = 0 , v._blocks = NullPointer( Pointer( T ) ); - return *this; - } + BlockedVector( BlockedVector&& v ) + { + _reservedBlocks = v._reservedBlocks , _allocatedBlocks = v._allocatedBlocks , _size = v._size , _defaultValue = v._defaultValue , _blocks = v._blocks; + v._reservedBlocks = v._allocatedBlocks = v._size = 0 , v._blocks = NullPointer( Pointer( T ) ); + } - size_t size( void ) const { return _size; } + BlockedVector& operator = ( BlockedVector&& v ) + { + for( size_t i=0 ; i<_allocatedBlocks ; i++ ) DeletePointer( _blocks[i] ); + DeletePointer( _blocks ); + _reservedBlocks = v._reservedBlocks , _allocatedBlocks = v._allocatedBlocks , _size = v._size , _defaultValue = v._defaultValue , _blocks = v._blocks; + v._reservedBlocks = v._allocatedBlocks = v._size = 0 , v._blocks = NullPointer( Pointer( T ) ); + return *this; + } - const T& operator[]( size_t idx ) const { return _blocks[idx>>LogBlockSize][idx&_Mask]; } - T& operator[]( size_t idx ){ return _blocks[idx>>LogBlockSize][idx&_Mask]; } + size_t size( void ) const { return _size; } - void resize( size_t size ){ resize( size , _defaultValue ); } - void resize( size_t size , const T& defaultValue ) - { - reserve( size , defaultValue ); - _size = size; - } + const T& operator[]( size_t idx ) const { return _blocks[idx>>LogBlockSize][idx&_Mask]; } + T& operator[]( size_t idx ){ return _blocks[idx>>LogBlockSize][idx&_Mask]; } - void clear( void ){ _size = 0; } + void resize( size_t size ){ resize( size , _defaultValue ); } + void resize( size_t size , const T& defaultValue ) + { + reserve( size , defaultValue ); + _size = size; + } - size_t reserved( void ) const { return _allocatedBlocks * _BlockSize; } + void clear( void ){ _size = 0; } - void reserve( size_t size ){ reserve( size , _defaultValue ); } - void reserve( size_t size , const T& defaultValue ) - { - if( size<=_allocatedBlocks * _BlockSize ) return; - size_t index = size-1; - size_t block = index >> LogBlockSize; - size_t blockIndex = index & _Mask; + size_t reserved( void ) const { return _allocatedBlocks * _BlockSize; } - // If there are insufficiently many blocks - if( block>=_reservedBlocks ) + void reserve( size_t size ){ reserve( size , _defaultValue ); } + void reserve( size_t size , const T& defaultValue ) { - size_t newReservedSize = std::max< size_t >( _reservedBlocks * AllocationMultiplier , block+1 ); - Pointer( Pointer( T ) ) __blocks = NewPointer< Pointer( T ) >( newReservedSize ); - memcpy( __blocks , _blocks , sizeof( Pointer( T ) ) * _reservedBlocks ); - for( size_t i=_reservedBlocks ; i> LogBlockSize; + size_t blockIndex = index & _Mask; - // If the block hasn't been allocated - if( block>=_allocatedBlocks ) - { - for( size_t b=_allocatedBlocks ; b<=block ; b++ ) + // If there are insufficiently many blocks + if( block>=_reservedBlocks ) + { + size_t newReservedSize = std::max< size_t >( _reservedBlocks * AllocationMultiplier , block+1 ); + Pointer( Pointer( T ) ) __blocks = NewPointer< Pointer( T ) >( newReservedSize ); + memcpy( __blocks , _blocks , sizeof( Pointer( T ) ) * _reservedBlocks ); + for( size_t i=_reservedBlocks ; i=_allocatedBlocks ) { - _blocks[b] = NewPointer< T >( _BlockSize ); - for( size_t i=0 ; i<_BlockSize ; i++ ) _blocks[b][i] = defaultValue; + for( size_t b=_allocatedBlocks ; b<=block ; b++ ) + { + _blocks[b] = NewPointer< T >( _BlockSize ); + for( size_t i=0 ; i<_BlockSize ; i++ ) _blocks[b][i] = defaultValue; + } + _allocatedBlocks = block+1; } - _allocatedBlocks = block+1; } - } - void push_back( const T &value ) - { - resize( _size+1 ); - operator[]( _size-1 ) = value; - } - T &back( void ){ return operator[]( _size-1 ); } - const T &back( void ) const { return operator[]( _size-1 ); } - void pop_back( void ){ _size--; } - - void write( BinaryStream &stream ) const - { - stream.write( _size ); - stream.write( _defaultValue ); - stream.write( _reservedBlocks ); - stream.write( _allocatedBlocks ); - for( size_t i=0 ; i<_allocatedBlocks ; i++ ) stream.write( _blocks[i] , _BlockSize ); - } - - void read( BinaryStream &stream ) - { - for( size_t i=0 ; i<_allocatedBlocks ; i++ ) DeletePointer( _blocks[i] ); - DeletePointer( _blocks ); - if( !stream.read( _size ) ) ERROR_OUT( "Failed to read _size" ); - if( !stream.read( _defaultValue ) ) ERROR_OUT( "Failed to read _defaultValue" ); - if( !stream.read( _reservedBlocks ) ) ERROR_OUT( "Failed to read _reservedBlocks" ); - if( !stream.read( _allocatedBlocks ) ) ERROR_OUT( "Failed to read _allocatedBlocks" ); + void push_back( const T &value ) + { + resize( _size+1 ); + operator[]( _size-1 ) = value; + } + T &back( void ){ return operator[]( _size-1 ); } + const T &back( void ) const { return operator[]( _size-1 ); } + void pop_back( void ){ _size--; } - _blocks = NewPointer< Pointer( T ) >( _reservedBlocks ); - if( !_blocks ) ERROR_OUT( "Failed to allocate _blocks: " , _reservedBlocks ); + void write( BinaryStream &stream ) const + { + stream.write( _size ); + stream.write( _defaultValue ); + stream.write( _reservedBlocks ); + stream.write( _allocatedBlocks ); + for( size_t i=0 ; i<_allocatedBlocks ; i++ ) stream.write( _blocks[i] , _BlockSize ); + } - for( size_t i=0 ; i<_allocatedBlocks ; i++ ) + void read( BinaryStream &stream ) { - _blocks[i] = NewPointer< T >( _BlockSize ); - if( !_blocks[i] ) ERROR_OUT( "Failed to allocate _blocks[" , i , "]" ); - if( !stream.read( _blocks[i] , _BlockSize ) ) ERROR_OUT( "Failed to read _blocks[" , i , "]" ); + for( size_t i=0 ; i<_allocatedBlocks ; i++ ) DeletePointer( _blocks[i] ); + DeletePointer( _blocks ); + if( !stream.read( _size ) ) ERROR_OUT( "Failed to read _size" ); + if( !stream.read( _defaultValue ) ) ERROR_OUT( "Failed to read _defaultValue" ); + if( !stream.read( _reservedBlocks ) ) ERROR_OUT( "Failed to read _reservedBlocks" ); + if( !stream.read( _allocatedBlocks ) ) ERROR_OUT( "Failed to read _allocatedBlocks" ); + + _blocks = NewPointer< Pointer( T ) >( _reservedBlocks ); + if( !_blocks ) ERROR_OUT( "Failed to allocate _blocks: " , _reservedBlocks ); + + for( size_t i=0 ; i<_allocatedBlocks ; i++ ) + { + _blocks[i] = NewPointer< T >( _BlockSize ); + if( !_blocks[i] ) ERROR_OUT( "Failed to allocate _blocks[" , i , "]" ); + if( !stream.read( _blocks[i] , _BlockSize ) ) ERROR_OUT( "Failed to read _blocks[" , i , "]" ); + } + for( size_t i=_allocatedBlocks ; i<_reservedBlocks ; i++ ) _blocks[i] = NullPointer( T ); } - for( size_t i=_allocatedBlocks ; i<_reservedBlocks ; i++ ) _blocks[i] = NullPointer( T ); - } - void read( BinaryStream &stream , const Serializer< T > &serializer ) - { - const size_t serializedSize = serializer.size(); + void read( BinaryStream &stream , const Serializer< T > &serializer ) + { + const size_t serializedSize = serializer.size(); - for( size_t i=0 ; i<_allocatedBlocks ; i++ ) DeletePointer( _blocks[i] ); - DeletePointer( _blocks ); - _size = _allocatedBlocks = _reservedBlocks = 0; + for( size_t i=0 ; i<_allocatedBlocks ; i++ ) DeletePointer( _blocks[i] ); + DeletePointer( _blocks ); + _size = _allocatedBlocks = _reservedBlocks = 0; - if( !stream.read( _size ) ) ERROR_OUT( "Failed to read _size" ); + if( !stream.read( _size ) ) ERROR_OUT( "Failed to read _size" ); #ifdef SHOW_WARNINGS #pragma message( "[WARNING] Should deserialize default value" ) #endif // SHOW_WARNINGS - if( !stream.read( _defaultValue ) ) ERROR_OUT( "Failed to read _defaultValue" ); - if( !stream.read( _reservedBlocks ) ) ERROR_OUT( "Failed to read _reservedBlocks" ); - if( !stream.read( _allocatedBlocks ) ) ERROR_OUT( "Failed to read _allocatedBlocks" ); - _blocks = NewPointer< Pointer( T ) >( _reservedBlocks ); - if( !_blocks ) ERROR_OUT( "Failed to allocate _blocks: " , _reservedBlocks ); - for( size_t i=0 ; i<_allocatedBlocks ; i++ ) - { - _blocks[i] = NewPointer< T >( _BlockSize ); - if( !_blocks[i] ) ERROR_OUT( "Failed to allocate _blocks[" , i , "]" ); - } - if( _size ) - { - Pointer( char ) buffer = NewPointer< char >( _size * serializedSize ); - if( !stream.read( buffer , serializedSize*_size ) ) ERROR_OUT( "Failed tor read in data" ); - for( unsigned int i=0 ; i<_size ; i++ ) serializer.deserialize( buffer+i*serializedSize , operator[]( i ) ); - DeletePointer( buffer ); + if( !stream.read( _defaultValue ) ) ERROR_OUT( "Failed to read _defaultValue" ); + if( !stream.read( _reservedBlocks ) ) ERROR_OUT( "Failed to read _reservedBlocks" ); + if( !stream.read( _allocatedBlocks ) ) ERROR_OUT( "Failed to read _allocatedBlocks" ); + _blocks = NewPointer< Pointer( T ) >( _reservedBlocks ); + if( !_blocks ) ERROR_OUT( "Failed to allocate _blocks: " , _reservedBlocks ); + for( size_t i=0 ; i<_allocatedBlocks ; i++ ) + { + _blocks[i] = NewPointer< T >( _BlockSize ); + if( !_blocks[i] ) ERROR_OUT( "Failed to allocate _blocks[" , i , "]" ); + } + if( _size ) + { + Pointer( char ) buffer = NewPointer< char >( _size * serializedSize ); + if( !stream.read( buffer , serializedSize*_size ) ) ERROR_OUT( "Failed tor read in data" ); + for( unsigned int i=0 ; i<_size ; i++ ) serializer.deserialize( buffer+i*serializedSize , operator[]( i ) ); + DeletePointer( buffer ); + } } - } - void write( BinaryStream &stream , const Serializer< T > &serializer ) const - { - const size_t serializedSize = serializer.size(); + void write( BinaryStream &stream , const Serializer< T > &serializer ) const + { + const size_t serializedSize = serializer.size(); - stream.write( _size ); + stream.write( _size ); #ifdef SHOW_WARNINGS #pragma message( "[WARNING] Should serialize default value" ) #endif // SHOW_WARNINGS - stream.write( _defaultValue ); - stream.write( _reservedBlocks ); - stream.write( _allocatedBlocks ); - if( _size ) - { - Pointer( char ) buffer = NewPointer< char >( _size * serializedSize ); - for( unsigned int i=0 ; i<_size ; i++ ) serializer.serialize( operator[]( i ) , buffer+i*serializedSize ); - stream.write( buffer , serializedSize*_size ); - DeletePointer( buffer ); + stream.write( _defaultValue ); + stream.write( _reservedBlocks ); + stream.write( _allocatedBlocks ); + if( _size ) + { + Pointer( char ) buffer = NewPointer< char >( _size * serializedSize ); + for( unsigned int i=0 ; i<_size ; i++ ) serializer.serialize( operator[]( i ) , buffer+i*serializedSize ); + stream.write( buffer , serializedSize*_size ); + DeletePointer( buffer ); + } } - } -protected: - static const size_t _BlockSize = 1< In( "in" ); -cmdLineParameter< char* > Out( "out" ); -cmdLineParameter< float > Width( "width" , -1.f ) , PadRadius( "radius" , 0.f ); -cmdLineParameterArray< float , 6 > BoundingBox( "bBox" ); -cmdLineParameters< Point< float , 4 > > HalfSpaces( "halfSpaces" ); -cmdLineReadable ASCII( "ascii" ) , Verbose( "verbose" ) , NoNormals( "noNormals" ) , Colors( "colors" ) , Values( "values" ); +using namespace PoissonRecon; -cmdLineReadable* params[] = { &In , &Out , &Width , &PadRadius , &ASCII , &Verbose , &BoundingBox , &NoNormals , &Colors , &Values , &HalfSpaces , NULL }; +CmdLineParameters< char* > In( "in" ); +CmdLineParameter< char* > Out( "out" ); +CmdLineParameter< float > Width( "width" , -1.f ) , PadRadius( "radius" , 0.f ); +CmdLineParameterArray< float , 6 > BoundingBox( "bBox" ); +CmdLineParameters< Point< float , 4 > > HalfSpaces( "halfSpaces" ); +CmdLineReadable ASCII( "ascii" ) , Verbose( "verbose" ) , NoNormals( "noNormals" ) , Colors( "colors" ) , Values( "values" ); + +CmdLineReadable* params[] = { &In , &Out , &Width , &PadRadius , &ASCII , &Verbose , &BoundingBox , &NoNormals , &Colors , &Values , &HalfSpaces , NULL }; void ShowUsage( char* ex ) { @@ -297,7 +299,7 @@ void Execute( VertexDataFactory vertexDataFactory ) if( inside && HalfSpaces.set ) { Point< float , 4 > _p( p[0] , p[1] , p[2] , 1.f ); - for( unsigned int i=0 ; i::Dot( _p , HalfSpaces.values[i] )<=0; + for( unsigned int i=0 ; i<(unsigned int)HalfSpaces.count ; i++ ) inside &= Point< float , 4 >::Dot( _p , HalfSpaces.values[i] )<=0; } return inside; }; @@ -565,7 +567,7 @@ int main( int argc , char* argv[] ) typedef float Real; static constexpr unsigned int Dim = 3; - cmdLineParse( argc-1 , &argv[1] , params ); + CmdLineParse( argc-1 , &argv[1] , params ); #ifdef ARRAY_DEBUG WARN( "Array debugging enabled" ); #endif // ARRAY_DEBUG diff --git a/Src/CmdLineParser.h b/Src/CmdLineParser.h index f71b55c2..c8ecafc6 100644 --- a/Src/CmdLineParser.h +++ b/Src/CmdLineParser.h @@ -33,91 +33,96 @@ DAMAGE. #include #include #include +#include +#include #include #include "Geometry.h" +namespace PoissonRecon +{ #ifdef WIN32 -int strcasecmp( const char* c1 , const char* c2 ); + int strcasecmp( const char* c1 , const char* c2 ); #endif // WIN32 -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 ) const; -}; + 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 ) const; + }; -template< typename Type > struct CmdLineType; + template< typename Type > struct CmdLineType; -template< typename Type > -struct CmdLineType -{ - static void WriteValue( Type t , char* str ); - static void CleanUp( Type* t ){} - static Type Initialize( void ){ return Type(); } - static Type Copy( Type t ){ return t; } - static Type StringToType( const char *str ); -}; + template< typename Type > + struct CmdLineType + { + static void WriteValue( Type t , char* str ); + static void CleanUp( Type* t ){} + static Type Initialize( void ){ return Type(); } + static Type Copy( Type t ){ return t; } + static Type StringToType( const char *str ); + }; -template< typename Real , unsigned int Dim > -struct CmdLineType< Point< Real , Dim > > -{ - using Type = Point< Real , Dim >; - static void WriteValue( Type t , char* str ); - static void CleanUp( Type* t ){} - static Type Initialize( void ){ return Type(); } - static Type Copy( Type t ){ return t; } - static Type StringToType( const char *str ); -}; -template< class Type > -class cmdLineParameter : public cmdLineReadable -{ -public: - Type value; - cmdLineParameter( const char *name ); - cmdLineParameter( const char *name , Type v ); - ~cmdLineParameter( void ); - int read( char** argv , int argc ); - void writeValue( char* str ) const; - bool expectsArg( void ) const { return true; } -}; + template< typename Real , unsigned int Dim > + struct CmdLineType< Point< Real , Dim > > + { + using Type = Point< Real , Dim >; + static void WriteValue( Type t , char* str ); + static void CleanUp( Type* t ){} + static Type Initialize( void ){ return Type(); } + static Type Copy( Type t ){ return t; } + static Type StringToType( const char *str ); + }; + template< class Type > + class CmdLineParameter : public CmdLineReadable + { + public: + Type value; + CmdLineParameter( const char *name ); + CmdLineParameter( const char *name , Type v ); + ~CmdLineParameter( void ); + int read( char** argv , int argc ); + void writeValue( char* str ) const; + bool expectsArg( void ) const { return true; } + }; -template< class Type , int Dim > -class cmdLineParameterArray : public cmdLineReadable -{ -public: - Type values[Dim]; - cmdLineParameterArray( const char *name, const Type* v=NULL ); - ~cmdLineParameterArray( void ); - int read( char** argv , int argc ); - void writeValue( char* str ) const; - bool expectsArg( void ) const { return true; } -}; + template< class Type , int Dim > + class CmdLineParameterArray : public CmdLineReadable + { + public: + Type values[Dim]; + CmdLineParameterArray( const char *name, const Type* v=NULL ); + ~CmdLineParameterArray( void ); + int read( char** argv , int argc ); + void writeValue( char* str ) const; + bool expectsArg( void ) const { return true; } + }; -template< class Type > -class cmdLineParameters : public cmdLineReadable -{ -public: - int count; - Type *values; - cmdLineParameters( const char* name ); - ~cmdLineParameters( void ); - int read( char** argv , int argc ); - void writeValue( char* str ) const; - bool expectsArg( void ) const { return true; } -}; + template< class Type > + class CmdLineParameters : public CmdLineReadable + { + public: + int count; + Type *values; + CmdLineParameters( const char* name ); + ~CmdLineParameters( void ); + int read( char** argv , int argc ); + void writeValue( char* str ) const; + bool expectsArg( void ) const { return true; } + }; -void cmdLineParse( int argc , char **argv, cmdLineReadable** params ); -char* FileExtension( char* fileName ); -char* LocalFileName( char* fileName ); -char* DirectoryName( char* fileName ); -char* GetFileExtension( const char* fileName ); -char* GetLocalFileName( const char* fileName ); -char** ReadWords( const char* fileName , int& cnt ); + void CmdLineParse( int argc , char **argv, CmdLineReadable** params ); + char* FileExtension( char* fileName ); + char* LocalFileName( char* fileName ); + char* DirectoryName( char* fileName ); + char* GetFileExtension( const char* fileName ); + char* GetLocalFileName( const char* fileName ); + char** ReadWords( const char* fileName , int& cnt ); #include "CmdLineParser.inl" +} #endif // CMD_LINE_PARSER_INCLUDED diff --git a/Src/CmdLineParser.inl b/Src/CmdLineParser.inl index dd019266..8d5d195b 100644 --- a/Src/CmdLineParser.inl +++ b/Src/CmdLineParser.inl @@ -26,9 +26,6 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ -#include -#include - #if defined( WIN32 ) || defined( _WIN64 ) inline int strcasecmp( const char* c1 , const char* c2 ){ return _stricmp( c1 , c2 ); } #endif // WIN32 || _WIN64 @@ -114,26 +111,26 @@ Point< Real , Dim > CmdLineType< Point< Real , Dim > >::StringToType( const char ///////////////////// -// cmdLineReadable // +// CmdLineReadable // ///////////////////// #if defined( WIN32 ) || defined( _WIN64 ) -inline cmdLineReadable::cmdLineReadable( const char *name ) : set(false) { this->name = _strdup( name ); } +inline CmdLineReadable::CmdLineReadable( const char *name ) : set(false) { this->name = _strdup( name ); } #else // !WIN32 && !_WIN64 -inline cmdLineReadable::cmdLineReadable( const char *name ) : set(false) { this->name = strdup( name ); } +inline CmdLineReadable::CmdLineReadable( const char *name ) : set(false) { this->name = strdup( name ); } #endif // WIN32 || _WIN64 -inline cmdLineReadable::~cmdLineReadable( void ){ if( name ) free( name ) ; name = NULL; } -inline int cmdLineReadable::read( char** , int ){ set = true ; return 0; } -inline void cmdLineReadable::writeValue( char* str ) const { str[0] = 0; } +inline CmdLineReadable::~CmdLineReadable( void ){ if( name ) free( name ) ; name = NULL; } +inline int CmdLineReadable::read( char** , int ){ set = true ; return 0; } +inline void CmdLineReadable::writeValue( char* str ) const { str[0] = 0; } ////////////////////// -// cmdLineParameter // +// CmdLineParameter // ////////////////////// -template< class Type > cmdLineParameter< Type >::~cmdLineParameter( void ) { CmdLineType< Type >::CleanUp( &value ); } -template< class Type > cmdLineParameter< Type >::cmdLineParameter( const char *name ) : cmdLineReadable( name ){ value = CmdLineType< Type >::Initialize(); } -template< class Type > cmdLineParameter< Type >::cmdLineParameter( const char *name , Type v ) : cmdLineReadable( name ){ value = CmdLineType< Type >::Copy( v ); } +template< class Type > CmdLineParameter< Type >::~CmdLineParameter( void ) { CmdLineType< Type >::CleanUp( &value ); } +template< class Type > CmdLineParameter< Type >::CmdLineParameter( const char *name ) : CmdLineReadable( name ){ value = CmdLineType< Type >::Initialize(); } +template< class Type > CmdLineParameter< Type >::CmdLineParameter( const char *name , Type v ) : CmdLineReadable( name ){ value = CmdLineType< Type >::Copy( v ); } template< class Type > -int cmdLineParameter< Type >::read( char** argv , int argc ) +int CmdLineParameter< Type >::read( char** argv , int argc ) { if( argc>0 ) { @@ -145,24 +142,24 @@ int cmdLineParameter< Type >::read( char** argv , int argc ) else return 0; } template< class Type > -void cmdLineParameter< Type >::writeValue( char* str ) const { CmdLineType< Type >::WriteValue( value , str ); } +void CmdLineParameter< Type >::writeValue( char* str ) const { CmdLineType< Type >::WriteValue( value , str ); } /////////////////////////// -// cmdLineParameterArray // +// CmdLineParameterArray // /////////////////////////// template< class Type , int Dim > -cmdLineParameterArray< Type , Dim >::cmdLineParameterArray( const char *name , const Type* v ) : cmdLineReadable( name ) +CmdLineParameterArray< Type , Dim >::CmdLineParameterArray( const char *name , const Type* v ) : CmdLineReadable( name ) { if( v ) for( int i=0 ; i::Copy( v[i] ); else for( int i=0 ; i::Initialize(); } template< class Type , int Dim > -cmdLineParameterArray< Type , Dim >::~cmdLineParameterArray( void ){ for( int i=0 ; i::CleanUp( values+i ); } +CmdLineParameterArray< Type , Dim >::~CmdLineParameterArray( void ){ for( int i=0 ; i::CleanUp( values+i ); } template< class Type , int Dim > -int cmdLineParameterArray< Type , Dim >::read( char** argv , int argc ) +int CmdLineParameterArray< Type , Dim >::read( char** argv , int argc ) { if( argc>=Dim ) { @@ -173,7 +170,7 @@ int cmdLineParameterArray< Type , Dim >::read( char** argv , int argc ) else return 0; } template< class Type , int Dim > -void cmdLineParameterArray< Type , Dim >::writeValue( char* str ) const +void CmdLineParameterArray< Type , Dim >::writeValue( char* str ) const { char* temp=str; for( int i=0 ; i::writeValue( char* str ) const } } /////////////////////// -// cmdLineParameters // +// CmdLineParameters // /////////////////////// template< class Type > -cmdLineParameters< Type >::cmdLineParameters( const char* name ) : cmdLineReadable( name ) , values(NULL) , count(0) { } +CmdLineParameters< Type >::CmdLineParameters( const char* name ) : CmdLineReadable( name ) , values(NULL) , count(0) { } template< class Type > -cmdLineParameters< Type >::~cmdLineParameters( void ) +CmdLineParameters< Type >::~CmdLineParameters( void ) { if( values ) delete[] values; values = NULL; @@ -197,7 +194,7 @@ cmdLineParameters< Type >::~cmdLineParameters( void ) } template< class Type > -int cmdLineParameters< Type >::read( char** argv , int argc ) +int CmdLineParameters< Type >::read( char** argv , int argc ) { if( values ) delete[] values; values = NULL; @@ -216,7 +213,7 @@ int cmdLineParameters< Type >::read( char** argv , int argc ) } template< class Type > -void cmdLineParameters< Type >::writeValue( char* str ) const +void CmdLineParameters< Type >::writeValue( char* str ) const { char* temp=str; CmdLineType< int >::WriteValue( count , temp ); @@ -295,13 +292,13 @@ inline char* DirectoryName( char* fileName ) return fileName; } -inline void cmdLineParse( int argc , char **argv , cmdLineReadable** params ) +inline void CmdLineParse( int argc , char **argv , CmdLineReadable** params ) { while( argc>0 ) { if( argv[0][0]=='-' && argv[0][1]=='-' ) { - cmdLineReadable* readable=NULL; + CmdLineReadable* readable=NULL; for( int i=0 ; params[i]!=NULL && readable==NULL ; i++ ) if( !strcasecmp( params[i]->name , argv[0]+2 ) ) readable = params[i]; if( readable ) { diff --git a/Src/DataStream.h b/Src/DataStream.h index 9ddb2bbd..14666790 100644 --- a/Src/DataStream.h +++ b/Src/DataStream.h @@ -33,117 +33,120 @@ DAMAGE. #include #include -// Pre-declare so we can make friends -template< typename Data > struct MultiInputDataStream; -template< typename Data > struct MultiOutputDataStream; - -//////////////////////////////////////// -// Abstract input/output data streams // -//////////////////////////////////////// - -// An input stream containing "Data" types -// Supporting: -// -- Resetting the stream to the start -// -- Trying to read the next element from the stream -template< typename Data > -struct InputDataStream +namespace PoissonRecon { - friend struct MultiInputDataStream< Data >; - virtual ~InputDataStream( void ){} + // Pre-declare so we can make friends + template< typename Data > struct MultiInputDataStream; + template< typename Data > struct MultiOutputDataStream; - // Reset to the start of the stream - virtual void reset( void ) = 0; + //////////////////////////////////////// + // Abstract input/output data streams // + //////////////////////////////////////// - bool read( Data &d ){ return base_read(d); } - bool read( unsigned int thread , Data &d ){ return base_read(thread,d); } + // An input stream containing "Data" types + // Supporting: + // -- Resetting the stream to the start + // -- Trying to read the next element from the stream + template< typename Data > + struct InputDataStream + { + friend struct MultiInputDataStream< Data >; -protected: - std::mutex _insertionMutex; + virtual ~InputDataStream( void ){} - // Read in data in a single-threaded context - virtual bool base_read( Data &d ) = 0; + // Reset to the start of the stream + virtual void reset( void ) = 0; - // Read in data in a multi-threaded context - virtual bool base_read( unsigned int thread , Data &d ) - { - std::lock_guard< std::mutex > lock( _insertionMutex ); - return base_read(d); - } -}; - -// An output stream containing "Data" types -// Supporting: -// -- Writing the next element to the stream -// -- Writing the next element to the stream by a particular thread -template< typename Data > -struct OutputDataStream -{ - friend struct MultiOutputDataStream< Data >; + bool read( Data &d ){ return base_read(d); } + bool read( unsigned int thread , Data &d ){ return base_read(thread,d); } - OutputDataStream( void ) : _size(0) {} - virtual ~OutputDataStream( void ){} + protected: + std::mutex _insertionMutex; - // Returns the number of items written to the stream - size_t size( void ) const { return _size; } + // Read in data in a single-threaded context + virtual bool base_read( Data &d ) = 0; - void write( const Data &d ){ base_write(d) ; _size++; } - void write( unsigned int thread , const Data &d ){ base_write( thread , d ) ; _size++; } + // Read in data in a multi-threaded context + virtual bool base_read( unsigned int thread , Data &d ) + { + std::lock_guard< std::mutex > lock( _insertionMutex ); + return base_read(d); + } + }; + + // An output stream containing "Data" types + // Supporting: + // -- Writing the next element to the stream + // -- Writing the next element to the stream by a particular thread + template< typename Data > + struct OutputDataStream + { + friend struct MultiOutputDataStream< Data >; -protected: - std::mutex _insertionMutex; - std::atomic< size_t > _size; + OutputDataStream( void ) : _size(0) {} + virtual ~OutputDataStream( void ){} - // Write out data in a single-threaded context - virtual void base_write( const Data &d ) = 0; - // Write out data in a multi-threaded context - virtual void base_write( unsigned int thread , const Data &d ) - { - std::lock_guard< std::mutex > lock( _insertionMutex ); - return base_write(d); - } + // Returns the number of items written to the stream + size_t size( void ) const { return _size; } -}; + void write( const Data &d ){ base_write(d) ; _size++; } + void write( unsigned int thread , const Data &d ){ base_write( thread , d ) ; _size++; } -////////////////////////////////////////// -// Multi-streams for multi-threaded I/O // -////////////////////////////////////////// -template< typename Data > -struct MultiInputDataStream : public InputDataStream< Data > -{ - MultiInputDataStream( InputDataStream< Data > **streams , size_t N ) : _current(0) , _streams( streams , streams+N ) {} - MultiInputDataStream( const std::vector< InputDataStream< Data > * > &streams ) : _current(0) , _streams( streams ) {} - void reset( void ){ for( unsigned int i=0 ; i<_streams.size() ; i++ ) _streams[i]->reset(); } + protected: + std::mutex _insertionMutex; + std::atomic< size_t > _size; -protected: - std::vector< InputDataStream< Data > * > _streams; - unsigned int _current; + // Write out data in a single-threaded context + virtual void base_write( const Data &d ) = 0; + // Write out data in a multi-threaded context + virtual void base_write( unsigned int thread , const Data &d ) + { + std::lock_guard< std::mutex > lock( _insertionMutex ); + return base_write(d); + } - bool base_read( unsigned int t , Data &d ){ return _streams[t]->base_read(d); } - bool base_read( Data &d ) + }; + + ////////////////////////////////////////// + // Multi-streams for multi-threaded I/O // + ////////////////////////////////////////// + template< typename Data > + struct MultiInputDataStream : public InputDataStream< Data > { - while( _current<_streams.size() ) + MultiInputDataStream( InputDataStream< Data > **streams , size_t N ) : _current(0) , _streams( streams , streams+N ) {} + MultiInputDataStream( const std::vector< InputDataStream< Data > * > &streams ) : _current(0) , _streams( streams ) {} + void reset( void ){ for( unsigned int i=0 ; i<_streams.size() ; i++ ) _streams[i]->reset(); } + + protected: + std::vector< InputDataStream< Data > * > _streams; + unsigned int _current; + + bool base_read( unsigned int t , Data &d ){ return _streams[t]->base_read(d); } + bool base_read( Data &d ) { - if( _streams[_current]->read( d ) ) return true; - else _current++; + while( _current<_streams.size() ) + { + if( _streams[_current]->read( d ) ) return true; + else _current++; + } + return false; } - return false; - } -}; - -template< typename Data > -struct MultiOutputDataStream : public OutputDataStream< Data > -{ - MultiOutputDataStream( OutputDataStream< Data > **streams , size_t N ) : _current(0) , _streams( streams , streams+N ) {} - MultiOutputDataStream( const std::vector< OutputDataStream< Data > * > &streams ) : _current(0) , _streams( streams ) {} + }; -protected: - std::vector< OutputDataStream< Data > * > _streams; - unsigned int _current; + template< typename Data > + struct MultiOutputDataStream : public OutputDataStream< Data > + { + MultiOutputDataStream( OutputDataStream< Data > **streams , size_t N ) : _current(0) , _streams( streams , streams+N ) {} + MultiOutputDataStream( const std::vector< OutputDataStream< Data > * > &streams ) : _current(0) , _streams( streams ) {} - void base_write( const Data &d ){ _streams[0]->base_write(d); } - void base_write( unsigned int t , const Data &d ){ _streams[t]->base_write(d); } -}; + protected: + std::vector< OutputDataStream< Data > * > _streams; + unsigned int _current; + void base_write( const Data &d ){ _streams[0]->base_write(d); } + void base_write( unsigned int t , const Data &d ){ _streams[t]->base_write(d); } + }; +} #endif // DATA_STREAM_INCLUDED diff --git a/Src/DataStream.imp.h b/Src/DataStream.imp.h index d46cefc6..bb25d2bb 100644 --- a/Src/DataStream.imp.h +++ b/Src/DataStream.imp.h @@ -34,256 +34,259 @@ DAMAGE. #include "VertexFactory.h" #include "Ply.h" -//////////////////////////////// -// Vector-backed data streams // -//////////////////////////////// -template< typename Data > -struct VectorBackedInputDataStream : public InputDataStream< Data > +namespace PoissonRecon { - VectorBackedInputDataStream( const std::vector< Data > &data ) : _data(data) , _current(0) {} - void reset( void ) { _current = 0; } + //////////////////////////////// + // Vector-backed data streams // + //////////////////////////////// + template< typename Data > + struct VectorBackedInputDataStream : public InputDataStream< Data > + { + VectorBackedInputDataStream( const std::vector< Data > &data ) : _data(data) , _current(0) {} + void reset( void ) { _current = 0; } -protected: - const std::vector< Data > &_data; - size_t _current; + protected: + const std::vector< Data > &_data; + size_t _current; - bool base_read( Data &d ){ if( _current<_data.size() ){ d = _data[_current++] ; return true; } else return false; } -}; + bool base_read( Data &d ){ if( _current<_data.size() ){ d = _data[_current++] ; return true; } else return false; } + }; -template< typename Data > -struct VectorBackedOutputDataStream : public OutputDataStream< Data > -{ - VectorBackedOutputDataStream( std::vector< Data > &data ) : _data(data) {} + template< typename Data > + struct VectorBackedOutputDataStream : public OutputDataStream< Data > + { + VectorBackedOutputDataStream( std::vector< Data > &data ) : _data(data) {} -protected: - std::vector< Data > &_data; + protected: + std::vector< Data > &_data; - void base_write( const Data &d ){ _data.push_back(d); } -}; + void base_write( const Data &d ){ _data.push_back(d); } + }; -//////////////////////////////////////////////////////////////////// -// File-backed data stream (assumes Data is statically allocated) // -//////////////////////////////////////////////////////////////////// -template< typename Data > -struct FileBackedInputDataStream : public InputDataStream< Data > -{ - // It is assumed that the file pointer was open for binary reading - FileBackedInputDataStream( FILE *fp ) : _fp(fp) {} - void reset( void ){ fseek( _fp , 0 , SEEK_SET ); } + //////////////////////////////////////////////////////////////////// + // File-backed data stream (assumes Data is statically allocated) // + //////////////////////////////////////////////////////////////////// + template< typename Data > + struct FileBackedInputDataStream : public InputDataStream< Data > + { + // It is assumed that the file pointer was open for binary reading + FileBackedInputDataStream( FILE *fp ) : _fp(fp) {} + void reset( void ){ fseek( _fp , 0 , SEEK_SET ); } -protected: - FILE *_fp; + protected: + FILE *_fp; - bool base_read( Data &d ){ return fread( &d , sizeof(Data) , 1 , _fp )==1; } -}; + bool base_read( Data &d ){ return fread( &d , sizeof(Data) , 1 , _fp )==1; } + }; -template< typename Data > -struct FileBackedOutputDataStream : public OutputDataStream< Data > -{ - // It is assumed that the file pointer was open for binary writing - FileBackedOutputDataStream( FILE *fp ) : _fp(fp) {} + template< typename Data > + struct FileBackedOutputDataStream : public OutputDataStream< Data > + { + // It is assumed that the file pointer was open for binary writing + FileBackedOutputDataStream( FILE *fp ) : _fp(fp) {} -protected: - FILE *_fp; + protected: + FILE *_fp; - void base_write( const Data &d ){ fwrite( &d , sizeof(Data) , 1 , _fp ); } -}; + void base_write( const Data &d ){ fwrite( &d , sizeof(Data) , 1 , _fp ); } + }; -///////////////////////////////////////////////////////////////////////////////////////////// -// File-backed data stream specialized for vectors (assumes Data is statically allocated) // -///////////////////////////////////////////////////////////////////////////////////////////// -template< typename Data > -struct FileBackedInputDataStream< std::vector< Data > > : public InputDataStream< std::vector< Data > > -{ - // It is assumed that the file pointer was open for binary reading - FileBackedInputDataStream( FILE *fp ) : _fp(fp) {} - void reset( void ){ fseek( _fp , 0 , SEEK_SET ); } + ///////////////////////////////////////////////////////////////////////////////////////////// + // File-backed data stream specialized for vectors (assumes Data is statically allocated) // + ///////////////////////////////////////////////////////////////////////////////////////////// + template< typename Data > + struct FileBackedInputDataStream< std::vector< Data > > : public InputDataStream< std::vector< Data > > + { + // It is assumed that the file pointer was open for binary reading + FileBackedInputDataStream( FILE *fp ) : _fp(fp) {} + void reset( void ){ fseek( _fp , 0 , SEEK_SET ); } -protected: - FILE *_fp; + protected: + FILE *_fp; - bool base_read( std::vector< Data > &d ) - { - unsigned int pSize; - if( fread( &pSize , sizeof(unsigned int) , 1 , _fp )==1 ) + bool base_read( std::vector< Data > &d ) { - d.resize( pSize ); - if( fread( &d[0] , sizeof(Data) , pSize , _fp )==pSize ) return true; - ERROR_OUT( "Failed to read polygon from file" ); - return true; + unsigned int pSize; + if( fread( &pSize , sizeof(unsigned int) , 1 , _fp )==1 ) + { + d.resize( pSize ); + if( fread( &d[0] , sizeof(Data) , pSize , _fp )==pSize ) return true; + ERROR_OUT( "Failed to read polygon from file" ); + return true; + } + else return false; } - else return false; - } -}; + }; -template< typename Data > -struct FileBackedOutputDataStream< std::vector< Data > > : public OutputDataStream< std::vector< Data > > -{ - // It is assumed that the file pointer was open for binary writing - FileBackedOutputDataStream( FILE *fp ) : _fp(fp) {} + template< typename Data > + struct FileBackedOutputDataStream< std::vector< Data > > : public OutputDataStream< std::vector< Data > > + { + // It is assumed that the file pointer was open for binary writing + FileBackedOutputDataStream( FILE *fp ) : _fp(fp) {} -protected: - FILE *_fp; + protected: + FILE *_fp; + + void base_write( const std::vector< Data > &d ) + { + unsigned int pSize = (unsigned int)d.size(); + fwrite( &pSize , sizeof(unsigned int) , 1 , _fp ); + fwrite( &d[0] , sizeof(Data) , pSize , _fp ); + } + }; - void base_write( const std::vector< Data > &d ) + //////////////////////////////////////////////////////// + // File-backed stream with data desribed by a factory // + //////////////////////////////////////////////////////// + template< typename Factory > + struct FileBackedInputFactoryTypeStream : public InputDataStream< typename Factory::VertexType > { - unsigned int pSize = (unsigned int)d.size(); - fwrite( &pSize , sizeof(unsigned int) , 1 , _fp ); - fwrite( &d[0] , sizeof(Data) , pSize , _fp ); - } -}; - -//////////////////////////////////////////////////////// -// File-backed stream with data desribed by a factory // -//////////////////////////////////////////////////////// -template< typename Factory > -struct FileBackedInputFactoryTypeStream : public InputDataStream< typename Factory::VertexType > -{ - typedef typename Factory::VertexType Data; - // It is assumed that the file pointer was open for binary reading - FileBackedInputFactoryTypeStream( FILE *fp , const Factory &factory ) : _fp(fp) , _factory(factory) , _buffer( NewPointer< char >( _factory.bufferSize() ) ) , _bufferSize( _factory.bufferSize() ) {} - ~FileBackedInputFactoryTypeStream( void ){ DeletePointer( _buffer ); } - void reset( void ){ fseek( _fp , 0 , SEEK_SET ); } - -protected: - FILE *_fp; - const Factory _factory; - Pointer( char ) _buffer; - const size_t _bufferSize; - - bool base_read( Data &d ){ if( fread( _buffer , sizeof(unsigned char) , _bufferSize , _fp )==_bufferSize ){ _factory.fromBuffer( _buffer , d ) ; return true; } else return false; } -}; - -template< typename Factory > -struct FileBackedOutputFactoryTypeStream : public OutputDataStream< typename Factory::VertexType > -{ - typedef typename Factory::VertexType Data; + typedef typename Factory::VertexType Data; + // It is assumed that the file pointer was open for binary reading + FileBackedInputFactoryTypeStream( FILE *fp , const Factory &factory ) : _fp(fp) , _factory(factory) , _buffer( NewPointer< char >( _factory.bufferSize() ) ) , _bufferSize( _factory.bufferSize() ) {} + ~FileBackedInputFactoryTypeStream( void ){ DeletePointer( _buffer ); } + void reset( void ){ fseek( _fp , 0 , SEEK_SET ); } + + protected: + FILE *_fp; + const Factory _factory; + Pointer( char ) _buffer; + const size_t _bufferSize; + + bool base_read( Data &d ){ if( fread( _buffer , sizeof(unsigned char) , _bufferSize , _fp )==_bufferSize ){ _factory.fromBuffer( _buffer , d ) ; return true; } else return false; } + }; + + template< typename Factory > + struct FileBackedOutputFactoryTypeStream : public OutputDataStream< typename Factory::VertexType > + { + typedef typename Factory::VertexType Data; - // It is assumed that the file pointer was open for binary reading - FileBackedOutputFactoryTypeStream( FILE *fp , const Factory &factory ) : _fp(fp) , _factory(factory) , _buffer( NewPointer< char >( _factory.bufferSize() ) ) , _bufferSize( _factory.bufferSize() ) {} - ~FileBackedOutputFactoryTypeStream( void ){ DeletePointer( _buffer ); } + // It is assumed that the file pointer was open for binary reading + FileBackedOutputFactoryTypeStream( FILE *fp , const Factory &factory ) : _fp(fp) , _factory(factory) , _buffer( NewPointer< char >( _factory.bufferSize() ) ) , _bufferSize( _factory.bufferSize() ) {} + ~FileBackedOutputFactoryTypeStream( void ){ DeletePointer( _buffer ); } -protected: - FILE *_fp; - const Factory _factory; - Pointer( char ) _buffer; - const size_t _bufferSize; + protected: + FILE *_fp; + const Factory _factory; + Pointer( char ) _buffer; + const size_t _bufferSize; - void base_write( const Data &d ){ _factory.toBuffer( d , _buffer ) ; fwrite( _buffer , sizeof(unsigned char) , _bufferSize , _fp ); } -}; + void base_write( const Data &d ){ _factory.toBuffer( d , _buffer ) ; fwrite( _buffer , sizeof(unsigned char) , _bufferSize , _fp ); } + }; -/////////////////////////////////////////////////////////////////////////////////// -// File-backed data streams, with functionality for reading/writing from/to disk // -/////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////// + // File-backed data streams, with functionality for reading/writing from/to disk // + /////////////////////////////////////////////////////////////////////////////////// -template< typename Factory > -struct ASCIIInputDataStream : public InputDataStream< typename Factory::VertexType > -{ - typedef typename Factory::VertexType Data; + template< typename Factory > + struct ASCIIInputDataStream : public InputDataStream< typename Factory::VertexType > + { + typedef typename Factory::VertexType Data; - ASCIIInputDataStream( const char* fileName , const Factory &factory ); - ~ASCIIInputDataStream( void ); - void reset( void ); + ASCIIInputDataStream( const char* fileName , const Factory &factory ); + ~ASCIIInputDataStream( void ); + void reset( void ); -protected: - const Factory _factory; - FILE *_fp; + protected: + const Factory _factory; + FILE *_fp; - bool base_read( Data &d ); -}; + bool base_read( Data &d ); + }; -template< typename Factory > -struct ASCIIOutputDataStream : public OutputDataStream< typename Factory::VertexType > -{ - typedef typename Factory::VertexType Data; + template< typename Factory > + struct ASCIIOutputDataStream : public OutputDataStream< typename Factory::VertexType > + { + typedef typename Factory::VertexType Data; - ASCIIOutputDataStream( const char* fileName , const Factory &factory ); - ~ASCIIOutputDataStream( void ); + ASCIIOutputDataStream( const char* fileName , const Factory &factory ); + ~ASCIIOutputDataStream( void ); -protected: - const Factory _factory; - FILE *_fp; + protected: + const Factory _factory; + FILE *_fp; - void base_write( const Data &d ); -}; + void base_write( const Data &d ); + }; -template< typename Factory > -struct BinaryInputDataStream : public InputDataStream< typename Factory::VertexType > -{ - typedef typename Factory::VertexType Data; + template< typename Factory > + struct BinaryInputDataStream : public InputDataStream< typename Factory::VertexType > + { + typedef typename Factory::VertexType Data; - BinaryInputDataStream( const char* filename , const Factory &factory ); - ~BinaryInputDataStream( void ){ fclose( _fp ) , _fp=NULL; } - void reset( void ); + BinaryInputDataStream( const char* filename , const Factory &factory ); + ~BinaryInputDataStream( void ){ fclose( _fp ) , _fp=NULL; } + void reset( void ); -protected: - const Factory _factory; - FILE* _fp; + protected: + const Factory _factory; + FILE* _fp; - bool base_read( Data &d ); -}; + bool base_read( Data &d ); + }; -template< typename Factory > -struct BinaryOutputDataStream : public OutputDataStream< typename Factory::VertexType > -{ - typedef typename Factory::VertexType Data; + template< typename Factory > + struct BinaryOutputDataStream : public OutputDataStream< typename Factory::VertexType > + { + typedef typename Factory::VertexType Data; - BinaryOutputDataStream( const char* filename , const Factory &factory ); - ~BinaryOutputDataStream( void ){ fclose( _fp ) , _fp=NULL; } - void reset( void ){ fseek( _fp , 0 , SEEK_SET ); } + BinaryOutputDataStream( const char* filename , const Factory &factory ); + ~BinaryOutputDataStream( void ){ fclose( _fp ) , _fp=NULL; } + void reset( void ){ fseek( _fp , 0 , SEEK_SET ); } -protected: - const Factory _factory; - FILE* _fp; + protected: + const Factory _factory; + FILE* _fp; - void base_write( const Data &d ); -}; + void base_write( const Data &d ); + }; -//////////////////////////////////////////// -// File-backed PLY-described data streams // -//////////////////////////////////////////// + //////////////////////////////////////////// + // File-backed PLY-described data streams // + //////////////////////////////////////////// -template< typename Factory > -struct PLYInputDataStream : public InputDataStream< typename Factory::VertexType > -{ - typedef typename Factory::VertexType Data; - - PLYInputDataStream( const char* fileName , const Factory &factory ); - PLYInputDataStream( const char* fileName , const Factory &factory , size_t &count ); - ~PLYInputDataStream( void ); - void reset( void ); - -protected: - const Factory _factory; - char* _fileName; - PlyFile *_ply; - std::vector< std::string > _elist; - Pointer( char ) _buffer; - - size_t _pCount , _pIdx; - void _free( void ); - bool base_read( Data &d ); -}; - -template< typename Factory > -struct PLYOutputDataStream : public OutputDataStream< typename Factory::VertexType > -{ - typedef typename Factory::VertexType Data; + template< typename Factory > + struct PLYInputDataStream : public InputDataStream< typename Factory::VertexType > + { + typedef typename Factory::VertexType Data; + + PLYInputDataStream( const char* fileName , const Factory &factory ); + PLYInputDataStream( const char* fileName , const Factory &factory , size_t &count ); + ~PLYInputDataStream( void ); + void reset( void ); + + protected: + const Factory _factory; + char* _fileName; + PlyFile *_ply; + std::vector< std::string > _elist; + Pointer( char ) _buffer; + + size_t _pCount , _pIdx; + void _free( void ); + bool base_read( Data &d ); + }; + + template< typename Factory > + struct PLYOutputDataStream : public OutputDataStream< typename Factory::VertexType > + { + typedef typename Factory::VertexType Data; - PLYOutputDataStream( const char* fileName , const Factory &factory , size_t count , int fileType=PLY_BINARY_NATIVE ); - ~PLYOutputDataStream( void ); + PLYOutputDataStream( const char* fileName , const Factory &factory , size_t count , int fileType=PLY_BINARY_NATIVE ); + ~PLYOutputDataStream( void ); -protected: - const Factory _factory; - PlyFile *_ply; - size_t _pCount , _pIdx; - Pointer( char ) _buffer; + protected: + const Factory _factory; + PlyFile *_ply; + size_t _pCount , _pIdx; + Pointer( char ) _buffer; - void base_write( const Data &d ); -}; + void base_write( const Data &d ); + }; #include "DataStream.imp.inl" +} #endif // DATA_STREAM_IMPLEMENTATION_INCLUDED diff --git a/Src/EDTInHeat.cpp b/Src/EDTInHeat.cpp index be3d0ef1..a82153f1 100644 --- a/Src/EDTInHeat.cpp +++ b/Src/EDTInHeat.cpp @@ -44,19 +44,21 @@ DAMAGE. #include "Ply.h" #include "VertexFactory.h" -cmdLineParameter< char* > +using namespace PoissonRecon; + +CmdLineParameter< char* > In( "in" ) , Out( "out" ) , InXForm( "inXForm" ) , OutXForm( "outXForm" ); -cmdLineReadable +CmdLineReadable Performance( "performance" ) , ShowResidual( "showResidual" ) , ExactInterpolation( "exact" ) , Verbose( "verbose" ); -cmdLineParameter< int > +CmdLineParameter< int > #ifndef FAST_COMPILE Degree( "degree" , DEFAULT_FEM_DEGREE ) , #endif // !FAST_COMPILE @@ -75,7 +77,7 @@ cmdLineParameter< int > ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , Threads( "threads" , (int)std::thread::hardware_concurrency() ); -cmdLineParameter< float > +CmdLineParameter< float > Scale( "scale" , 2.f ) , CGSolverAccuracy( "cgAccuracy" , float(1e-3) ) , DiffusionTime( "diffusion" , 0.0005f ) , @@ -83,7 +85,7 @@ cmdLineParameter< float > WeightExponent( "wExp" , 6.f ) , ValueWeight( "valueWeight" , 1e-2f ); -cmdLineReadable* params[] = +CmdLineReadable* params[] = { #ifndef FAST_COMPILE &Degree , @@ -563,7 +565,7 @@ int main( int argc , char* argv[] ) #ifdef ARRAY_DEBUG WARN( "Array debugging enabled" ); #endif // ARRAY_DEBUG - cmdLineParse( argc-1 , &argv[1] , params ); + CmdLineParse( argc-1 , &argv[1] , params ); ThreadPool::DefaultChunkSize = ThreadChunkSize.value; ThreadPool::DefaultSchedule = (ThreadPool::ScheduleType)ScheduleType.value; if( MaxMemoryGB.value>0 ) SetPeakMemoryMB( MaxMemoryGB.value<<10 ); diff --git a/Src/FEMTree.LevelSet.2D.inl b/Src/FEMTree.LevelSet.2D.inl index d1319889..f4723244 100644 --- a/Src/FEMTree.LevelSet.2D.inl +++ b/Src/FEMTree.LevelSet.2D.inl @@ -26,17 +26,6 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ -#ifndef FEM_TREE_LEVEL_SET_2D_INL_INCLUDED -#define FEM_TREE_LEVEL_SET_2D_INL_INCLUDED - -#include -#include -#include -#include -#include "MyMiscellany.h" -#include "MarchingCubes.h" -#include "MAT.h" - // Specialized level-set curve extraction template< bool HasData , typename Real , typename Data > struct _LevelSetExtractor< HasData , Real , 2 , Data > @@ -1149,4 +1138,3 @@ struct LevelSetExtractor< Real , 2 , Data > return _LevelSetExtractor< HasData , Real , Dim , Data >::template SetSliceValues< WeightDegree , DataSig , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , vertexStream , zeroData , nonLinearFit , outputGradients , sliceValues , setFlag ); } }; -#endif // FEM_TREE_LEVEL_SET_2D_INL_INCLUDED \ No newline at end of file diff --git a/Src/FEMTree.LevelSet.3D.inl b/Src/FEMTree.LevelSet.3D.inl index 3e0c16dd..d64805fa 100644 --- a/Src/FEMTree.LevelSet.3D.inl +++ b/Src/FEMTree.LevelSet.3D.inl @@ -26,18 +26,6 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ -#include -#include -#include -#include -#include "MyMiscellany.h" -#include "MarchingCubes.h" -#include "MAT.h" -#include "FEMTree.LevelSet.inl" -#include "FEMTree.LevelSet.2D.inl" -#include "Reconstructors.h" - - // Specialized level-set surface extraction template< bool HasData , typename Real , typename Data > struct _LevelSetExtractor< HasData , Real , 3 , Data > diff --git a/Src/FEMTree.LevelSet.inl b/Src/FEMTree.LevelSet.inl index 86d72165..446de46e 100644 --- a/Src/FEMTree.LevelSet.inl +++ b/Src/FEMTree.LevelSet.inl @@ -26,8 +26,6 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ -#include "MarchingCubes.h" - // Level-set extraction data namespace LevelSetExtraction { diff --git a/Src/FEMTree.System.inl b/Src/FEMTree.System.inl index 6ad00ce6..a8d923af 100644 --- a/Src/FEMTree.System.inl +++ b/Src/FEMTree.System.inl @@ -180,9 +180,9 @@ Point< double , CDim > FEMIntegrator::Constraint< UIntPack< TSignatures ... > , return integral; } -#ifndef MOD -#define MOD( a , b ) ( (a)>0 ? (a) % (b) : ( (b) - ( -(a) % (b) ) ) % (b) ) -#endif // MOD +#ifndef PR_MODULO +#define PR_MODULO( a , b ) ( (a)>0 ? (a) % (b) : ( (b) - ( -(a) % (b) ) ) % (b) ) +#endif // PR_MODULO ///////////// // FEMTree // @@ -213,7 +213,7 @@ void FEMTree< Dim , Real >::_setMultiColorIndices( UIntPack< FEMSigs ... > , nod { LocalDepth d ; LocalOffset off ; _localDepthAndOffset( node , d , off ); int index = 0; - for( int dd=0 ; dd::_solveSlicedSystemGS( UIntPack< FEMSigs ... > , const BlockWindow solveWindow( FullWindow.begin(forward) - residualOffset*dir , FullWindow.begin(forward) - residualOffset*dir - ( ColorModulus*iters - ( ColorModulus-1 ) ) * dir ); // If we are solving forward we start in a block S with S mod ColorModulus = ColorModulus-1 // and end in a block E with E mod ColorModulus = 0 - while( MOD( solveWindow.begin(!forward) , ColorModulus )!=( forward ? ColorModulus-1 : 0 ) ) solveWindow -= dir , residualWindow -= dir; + while( PR_MODULO( solveWindow.begin(!forward) , ColorModulus )!=( forward ? ColorModulus-1 : 0 ) ) solveWindow -= dir , residualWindow -= dir; size_t maxBlockSize = 0; BlockWindow _residualWindow = residualWindow; for( ; _residualWindow.end(!forward)*dir::_solveSlicedSystemGS( UIntPack< FEMSigs ... > , const // to ensure that adjacent read-only blocks have not been updated yet. if( FullWindow.inBlock( residualBlock ) ) { - int b = residualBlock , _b = MOD( b , matrixBlocks ); + int b = residualBlock , _b = PR_MODULO( b , matrixBlocks ); t = Time(); _getSliceMatrixAndProlongationConstraints( UIntPack< FEMSigs ... >() , F , _M[_b] , _D[_b] , bsData , depth , _sNodesBegin( depth , BlockFirst( b ) ) , _sNodesEnd( depth , BlockLast( b ) ) , prolongedSolution , _constraints[_b] , ccStencil , pcStencils , interpolationInfos ); @@ -490,7 +490,7 @@ int FEMTree< Dim , Real >::_solveSlicedSystemGS( UIntPack< FEMSigs ... > , const // Get the leading multi-color indices if( iters && FullWindow.inBlock( frontSolveBlock ) ) { - int b = frontSolveBlock , _b = MOD( b , matrixBlocks ) , __b = MOD( b , solveBlocks ); + int b = frontSolveBlock , _b = PR_MODULO( b , matrixBlocks ) , __b = PR_MODULO( b , solveBlocks ); for( int i=0 ; i() , _sNodesBegin( depth , BlockFirst( b ) ) , _sNodesEnd( depth , BlockLast( b ) ) , mcIndices[__b] ); } @@ -499,7 +499,7 @@ int FEMTree< Dim , Real >::_solveSlicedSystemGS( UIntPack< FEMSigs ... > , const // Relax the system for( int block=solveWindow.begin(!forward) ; solveWindow.inBlock(block) ; block-=dir*ColorModulus ) if( FullWindow.inBlock( block ) ) { - int b = block , _b = MOD( b , matrixBlocks ) , __b = MOD( b , solveBlocks ); + int b = block , _b = PR_MODULO( b , matrixBlocks ) , __b = PR_MODULO( b , solveBlocks ); ConstPointer( T ) B = _constraints[_b]; Pointer( T ) X = XBlocks( depth , b , solution ); _M[_b].gsIteration( mcIndices[__b] , ( ConstPointer( Real ) )_D[_b] , B , X , coarseToFine , true ); @@ -511,7 +511,7 @@ int FEMTree< Dim , Real >::_solveSlicedSystemGS( UIntPack< FEMSigs ... > , const int residualBlock = residualWindow.begin(forward); if( computeNorms && FullWindow.inBlock( residualBlock ) ) { - int b = residualBlock , _b = MOD( b , matrixBlocks ); + int b = residualBlock , _b = PR_MODULO( b , matrixBlocks ); ConstPointer( T ) B = _constraints[_b]; ConstPointer( T ) X = XBlocks( depth , b , solution ); std::vector< double > outRNorms( ThreadPool::NumThreads() , 0 ); @@ -539,7 +539,7 @@ int FEMTree< Dim , Real >::_solveSlicedSystemGS( UIntPack< FEMSigs ... > , const } return iters; } -#undef MOD +#undef PR_MODULO template< unsigned int Dim , class Real > template< unsigned int ... FEMSigs , typename T , typename TDotT , typename ... InterpolationInfos > diff --git a/Src/FEMTree.h b/Src/FEMTree.h index 60c1c8ed..63508bb8 100644 --- a/Src/FEMTree.h +++ b/Src/FEMTree.h @@ -58,2991 +58,3002 @@ DAMAGE. #include #include #include - +#include +#include +#include +#include "MarchingCubes.h" +#include +#include +#include +#include +#include "MAT.h" + +namespace PoissonRecon +{ #ifdef BIG_DATA -// The integer type used for indexing the nodes in the octree -typedef long long node_index_type; -// The integer type used for indexing the entries of the matrix -typedef int matrix_index_type; + // The integer type used for indexing the nodes in the octree + typedef long long node_index_type; + // The integer type used for indexing the entries of the matrix + typedef int matrix_index_type; #else // !BIG_DATA -typedef int node_index_type; -typedef int matrix_index_type; + typedef int node_index_type; + typedef int matrix_index_type; #endif // BIG_DATA #ifdef USE_DEEP_TREE_NODES -// The integer type used for storing the depth and offset within an octree node -typedef unsigned int depth_and_offset_type; + // The integer type used for storing the depth and offset within an octree node + typedef unsigned int depth_and_offset_type; #else // !USE_DEEP_TREE_NODES -typedef unsigned short depth_and_offset_type; + typedef unsigned short depth_and_offset_type; #endif // USE_DEEP_TREE_NODES -template< unsigned int Dim , class Real > class FEMTree; + template< unsigned int Dim , class Real > class FEMTree; -enum -{ - SHOW_GLOBAL_RESIDUAL_NONE , - SHOW_GLOBAL_RESIDUAL_LAST , - SHOW_GLOBAL_RESIDUAL_ALL , - SHOW_GLOBAL_RESIDUAL_COUNT -}; -const char* ShowGlobalResidualNames[] = { "show none" , "show last" , "show all" }; - -class FEMTreeNodeData -{ -public: enum { - SPACE_FLAG = 1 << 0 , // Part of the partition of the unit cube - FEM_FLAG_1 = 1 << 1 , // Indexes a valid finite element - FEM_FLAG_2 = 1 << 2 , // Indexes a valid finite element - DIRICHLET_NODE_FLAG = 1 << 3 , // The finite elements should evaluate to zero on this node - DIRICHLET_ELEMENT_FLAG = 1 << 4 , // Coefficient of this node should be locked to zero - GEOMETRY_SUPPORTED_FLAG = 1 << 5 , // The finite element defined by this node has support overlapping geometry constraints - GHOST_FLAG = 1 << 6 , // Children are pruned out - SCRATCH_FLAG = 1 << 7 , + SHOW_GLOBAL_RESIDUAL_NONE , + SHOW_GLOBAL_RESIDUAL_LAST , + SHOW_GLOBAL_RESIDUAL_ALL , + SHOW_GLOBAL_RESIDUAL_COUNT }; - node_index_type nodeIndex; - mutable char flags; - void setGhostFlag( bool f ) const { if( f ) flags |= GHOST_FLAG ; else flags &= ~GHOST_FLAG; } - bool getGhostFlag( void ) const { return ( flags & GHOST_FLAG )!=0; } - void setDirichletNodeFlag( bool f ) const { if( f ) flags |= DIRICHLET_NODE_FLAG ; else flags &= ~DIRICHLET_NODE_FLAG; } - bool getDirichletNodeFlag( void ) const { return ( flags & DIRICHLET_NODE_FLAG )!=0; } - void setDirichletElementFlag( bool f ) const { if( f ) flags |= DIRICHLET_ELEMENT_FLAG ; else flags &= ~DIRICHLET_ELEMENT_FLAG; } - bool getDirichletElementFlag( void ) const { return ( flags & DIRICHLET_ELEMENT_FLAG )!=0; } - void setScratchFlag( bool f ) const { if( f ) flags |= SCRATCH_FLAG ; else flags &= ~SCRATCH_FLAG; } - bool getScratchFlag( void ) const { return ( flags & SCRATCH_FLAG )!=0; } - FEMTreeNodeData( void ); - ~FEMTreeNodeData( void ); -}; - -template< unsigned int Dim > -class SortedTreeNodes -{ - typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > TreeNode; -protected: - Pointer( Pointer( node_index_type ) ) _sliceStart; - int _levels; - - void _set( TreeNode& root ); -public: - Pointer( TreeNode* ) treeNodes; - node_index_type begin( int depth ) const { return _sliceStart[depth][0]; } - node_index_type end( int depth ) const { return _sliceStart[depth][(size_t)1<(1<=_levels ) ERROR_OUT( "bad depth: 0 <= " , depth , " < " , _levels ); - return _sliceStart[depth][(size_t)1< &map ); - void set( TreeNode& root ); + class FEMTreeNodeData + { + public: + enum + { + SPACE_FLAG = 1 << 0 , // Part of the partition of the unit cube + FEM_FLAG_1 = 1 << 1 , // Indexes a valid finite element + FEM_FLAG_2 = 1 << 2 , // Indexes a valid finite element + DIRICHLET_NODE_FLAG = 1 << 3 , // The finite elements should evaluate to zero on this node + DIRICHLET_ELEMENT_FLAG = 1 << 4 , // Coefficient of this node should be locked to zero + GEOMETRY_SUPPORTED_FLAG = 1 << 5 , // The finite element defined by this node has support overlapping geometry constraints + GHOST_FLAG = 1 << 6 , // Children are pruned out + SCRATCH_FLAG = 1 << 7 , + }; + node_index_type nodeIndex; + mutable char flags; + void setGhostFlag( bool f ) const { if( f ) flags |= GHOST_FLAG ; else flags &= ~GHOST_FLAG; } + bool getGhostFlag( void ) const { return ( flags & GHOST_FLAG )!=0; } + void setDirichletNodeFlag( bool f ) const { if( f ) flags |= DIRICHLET_NODE_FLAG ; else flags &= ~DIRICHLET_NODE_FLAG; } + bool getDirichletNodeFlag( void ) const { return ( flags & DIRICHLET_NODE_FLAG )!=0; } + void setDirichletElementFlag( bool f ) const { if( f ) flags |= DIRICHLET_ELEMENT_FLAG ; else flags &= ~DIRICHLET_ELEMENT_FLAG; } + bool getDirichletElementFlag( void ) const { return ( flags & DIRICHLET_ELEMENT_FLAG )!=0; } + void setScratchFlag( bool f ) const { if( f ) flags |= SCRATCH_FLAG ; else flags &= ~SCRATCH_FLAG; } + bool getScratchFlag( void ) const { return ( flags & SCRATCH_FLAG )!=0; } + FEMTreeNodeData( void ); + ~FEMTreeNodeData( void ); + }; - void write( BinaryStream &stream ) const; - void read( BinaryStream &stream , TreeNode &root ); -}; + template< unsigned int Dim > + class SortedTreeNodes + { + typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > TreeNode; + protected: + Pointer( Pointer( node_index_type ) ) _sliceStart; + int _levels; -template< typename T > struct DotFunctor{}; -template< > struct DotFunctor< float > -{ - double operator()( float v1 , float v2 ){ return v1*v2; } - unsigned int dimension( void ) const { return 1; } -}; -template< > struct DotFunctor< double > -{ - double operator()( double v1 , double v2 ){ return v1*v2; } - unsigned int dimension( void ) const { return 1; } -}; -template< class Real , unsigned int Dim > struct DotFunctor< Point< Real , Dim > > -{ - double operator()( Point< Real , Dim > v1 , Point< Real , Dim > v2 ){ return Point< Real , Dim >::Dot( v1 , v2 ); } - unsigned int dimension( void ) const { return Dim; } -}; + void _set( TreeNode& root ); + public: + Pointer( TreeNode* ) treeNodes; + node_index_type begin( int depth ) const { return _sliceStart[depth][0]; } + node_index_type end( int depth ) const { return _sliceStart[depth][(size_t)1<(1<=_levels ) ERROR_OUT( "bad depth: 0 <= " , depth , " < " , _levels ); + return _sliceStart[depth][(size_t)1< struct SupportKey{ }; -template< unsigned int ... Degrees > -struct SupportKey< UIntPack< Degrees ... > > : public RegularTreeNode< sizeof...(Degrees) , FEMTreeNodeData , depth_and_offset_type >::template NeighborKey< UIntPack< (-BSplineSupportSizes< Degrees >::SupportStart) ... > , UIntPack< BSplineSupportSizes< Degrees >::SupportEnd ... > > -{ - typedef UIntPack< (-BSplineSupportSizes< Degrees >::SupportStart ) ... > LeftRadii; - typedef UIntPack< ( BSplineSupportSizes< Degrees >::SupportEnd ) ... > RightRadii; - typedef UIntPack< ( BSplineSupportSizes< Degrees >::SupportSize ) ... > Sizes; -}; - -template< typename Pack > struct ConstSupportKey{ }; -template< unsigned int ... Degrees > -struct ConstSupportKey< UIntPack< Degrees ... > > : public RegularTreeNode< sizeof...(Degrees) , FEMTreeNodeData , depth_and_offset_type >::template ConstNeighborKey< UIntPack< (-BSplineSupportSizes< Degrees >::SupportStart ) ... > , UIntPack< BSplineSupportSizes< Degrees >::SupportEnd ... > > -{ - typedef UIntPack< (-BSplineSupportSizes< Degrees >::SupportStart ) ... > LeftRadii; - typedef UIntPack< ( BSplineSupportSizes< Degrees >::SupportEnd ) ... > RightRadii; - typedef UIntPack< ( BSplineSupportSizes< Degrees >::SupportSize ) ... > Sizes; -}; - -template< typename Pack > struct OverlapKey{ }; -template< unsigned int ... Degrees > -struct OverlapKey< UIntPack< Degrees ... > > : public RegularTreeNode< sizeof...(Degrees) , FEMTreeNodeData , depth_and_offset_type >::template NeighborKey< UIntPack< (-BSplineOverlapSizes< Degrees , Degrees >::OverlapStart ) ... > , UIntPack< BSplineOverlapSizes< Degrees , Degrees >::OverlapEnd ... > > -{ - typedef UIntPack< (-BSplineOverlapSizes< Degrees , Degrees >::OverlapStart ) ... > LeftRadii; - typedef UIntPack< ( BSplineOverlapSizes< Degrees , Degrees >::OverlapEnd ) ... > RightRadii; - typedef UIntPack< ( BSplineOverlapSizes< Degrees , Degrees >::OverlapSize ) ... > Sizes; -}; - -template< typename Pack > struct ConstOverlapKey{ }; -template< unsigned int ... Degrees > -struct ConstOverlapKey< UIntPack< Degrees ... > > : public RegularTreeNode< sizeof...(Degrees) , FEMTreeNodeData , depth_and_offset_type >::template ConstNeighborKey< UIntPack< (-BSplineOverlapSizes< Degrees , Degrees >::OverlapStart ) ... > , UIntPack< BSplineOverlapSizes< Degrees , Degrees >::OverlapEnd ... > > -{ - typedef UIntPack< (-BSplineOverlapSizes< Degrees , Degrees >::OverlapStart ) ... > LeftRadii; - typedef UIntPack< ( BSplineOverlapSizes< Degrees , Degrees >::OverlapEnd ) ... > RightRadii; - typedef UIntPack< ( BSplineOverlapSizes< Degrees , Degrees >::OverlapSize ) ... > Sizes; -}; - -template< typename Pack > struct PointSupportKey{ }; -template< unsigned int ... Degrees > -struct PointSupportKey< UIntPack< Degrees ... > > : public RegularTreeNode< sizeof...(Degrees) , FEMTreeNodeData , depth_and_offset_type >::template NeighborKey< UIntPack< BSplineSupportSizes< Degrees >::SupportEnd ... > , UIntPack< (-BSplineSupportSizes< Degrees >::SupportStart ) ... > > -{ - typedef UIntPack< ( BSplineSupportSizes< Degrees >::SupportEnd ) ... > LeftRadii; - typedef UIntPack< (-BSplineSupportSizes< Degrees >::SupportStart ) ... > RightRadii; - typedef UIntPack< ( BSplineSupportSizes< Degrees >::SupportEnd - BSplineSupportSizes< Degrees >::SupportStart + 1 ) ... > Sizes; -}; - -template< typename Pack > struct ConstPointSupportKey{ }; -template< unsigned int ... Degrees > -struct ConstPointSupportKey< UIntPack< Degrees ... > > : public RegularTreeNode< sizeof...(Degrees) , FEMTreeNodeData , depth_and_offset_type >::template ConstNeighborKey< UIntPack< BSplineSupportSizes< Degrees >::SupportEnd ... > , UIntPack< (-BSplineSupportSizes< Degrees >::SupportStart ) ... > > -{ - typedef UIntPack< ( BSplineSupportSizes< Degrees >::SupportEnd ) ... > LeftRadii; - typedef UIntPack< (-BSplineSupportSizes< Degrees >::SupportStart ) ... > RightRadii; - typedef UIntPack< ( BSplineSupportSizes< Degrees >::SupportEnd - BSplineSupportSizes< Degrees >::SupportStart + 1 ) ... > Sizes; -}; - -template< typename Pack > struct CornerSupportKey{ }; -template< unsigned int ... Degrees > -struct CornerSupportKey< UIntPack< Degrees ... > > : public RegularTreeNode< sizeof...(Degrees) , FEMTreeNodeData , depth_and_offset_type >::template NeighborKey< UIntPack< BSplineSupportSizes< Degrees >::BCornerEnd ... > , UIntPack< ( -BSplineSupportSizes< Degrees >::BCornerStart + 1 ) ... > > -{ - typedef UIntPack< ( BSplineSupportSizes< Degrees >::BCornerEnd ) ... > LeftRadii; - typedef UIntPack< (-BSplineSupportSizes< Degrees >::BCornerStart + 1 ) ... > RightRadii; - typedef UIntPack< ( BSplineSupportSizes< Degrees >::BCornerSize + 1 ) ... > Sizes; -}; - -template< typename Pack > struct ConstCornerSupportKey{ }; -template< unsigned int ... Degrees > -struct ConstCornerSupportKey< UIntPack< Degrees ... > > : public RegularTreeNode< sizeof...(Degrees) , FEMTreeNodeData , depth_and_offset_type >::template ConstNeighborKey< UIntPack< BSplineSupportSizes< Degrees >::BCornerEnd ... > , UIntPack< ( -BSplineSupportSizes< Degrees >::BCornerStart + 1 ) ... > > -{ - typedef UIntPack< ( BSplineSupportSizes< Degrees >::BCornerEnd ) ... > LeftRadii; - typedef UIntPack< (-BSplineSupportSizes< Degrees >::BCornerStart + 1 ) ... > RightRadii; - typedef UIntPack< ( BSplineSupportSizes< Degrees >::BCornerSize + 1 ) ... > Sizes; -}; + SortedTreeNodes( void ); + ~SortedTreeNodes( void ); + // Resets the sorted tree nodes and sets map[i] to the index previously stored with the i-th node. + void reset( TreeNode& root , std::vector< node_index_type > &map ); + void set( TreeNode& root ); + void write( BinaryStream &stream ) const; + void read( BinaryStream &stream , TreeNode &root ); + }; -template< class Data , typename Pack > struct _SparseOrDenseNodeData{}; -template< class Data , unsigned int ... FEMSigs > -struct _SparseOrDenseNodeData< Data , UIntPack< FEMSigs ... > > -{ - static const unsigned int Dim = sizeof ... ( FEMSigs ); - typedef UIntPack< FEMSigs ... > FEMSignatures; - typedef Data data_type; - - // Methods for accessing as an array - virtual size_t size( void ) const = 0; - virtual const Data& operator[] ( size_t idx ) const = 0; - virtual Data& operator[] ( size_t idx ) = 0; - - // Method for accessing (and inserting if necessary) using a node - virtual Data& operator[]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *node ) = 0; - // Methods for accessing using a node - virtual Data* operator()( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *node ) = 0; - virtual const Data* operator()( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ) const = 0; - - // Method for getting the actual index associated with a node - virtual node_index_type index( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ) const = 0; -}; - -template< class Data , typename Pack > struct SparseNodeData{}; -template< class Data , unsigned int ... FEMSigs > -struct SparseNodeData< Data , UIntPack< FEMSigs ... > > : public _SparseOrDenseNodeData< Data , UIntPack< FEMSigs ... > > -{ - static const unsigned int Dim = sizeof ... ( FEMSigs ); + template< typename T > struct DotFunctor{}; + template< > struct DotFunctor< float > + { + double operator()( float v1 , float v2 ){ return v1*v2; } + unsigned int dimension( void ) const { return 1; } + }; + template< > struct DotFunctor< double > + { + double operator()( double v1 , double v2 ){ return v1*v2; } + unsigned int dimension( void ) const { return 1; } + }; + template< class Real , unsigned int Dim > struct DotFunctor< Point< Real , Dim > > + { + double operator()( Point< Real , Dim > v1 , Point< Real , Dim > v2 ){ return Point< Real , Dim >::Dot( v1 , v2 ); } + unsigned int dimension( void ) const { return Dim; } + }; - static void WriteSignatures( BinaryStream &stream ) + template< typename Pack > struct SupportKey{ }; + template< unsigned int ... Degrees > + struct SupportKey< UIntPack< Degrees ... > > : public RegularTreeNode< sizeof...(Degrees) , FEMTreeNodeData , depth_and_offset_type >::template NeighborKey< UIntPack< (-BSplineSupportSizes< Degrees >::SupportStart) ... > , UIntPack< BSplineSupportSizes< Degrees >::SupportEnd ... > > { - unsigned int dim = sizeof ... ( FEMSigs ); - stream.write( dim ); - unsigned int femSigs[] = { FEMSigs ... }; - stream.write( femSigs , dim ); - } - void write( BinaryStream &stream , const Serializer< Data > &serializer ) const + typedef UIntPack< (-BSplineSupportSizes< Degrees >::SupportStart ) ... > LeftRadii; + typedef UIntPack< ( BSplineSupportSizes< Degrees >::SupportEnd ) ... > RightRadii; + typedef UIntPack< ( BSplineSupportSizes< Degrees >::SupportSize ) ... > Sizes; + }; + + template< typename Pack > struct ConstSupportKey{ }; + template< unsigned int ... Degrees > + struct ConstSupportKey< UIntPack< Degrees ... > > : public RegularTreeNode< sizeof...(Degrees) , FEMTreeNodeData , depth_and_offset_type >::template ConstNeighborKey< UIntPack< (-BSplineSupportSizes< Degrees >::SupportStart ) ... > , UIntPack< BSplineSupportSizes< Degrees >::SupportEnd ... > > { - _indices.write( stream ); - _data.write( stream , serializer ); - } - void read( BinaryStream &stream , const Serializer< Data > &serializer ) + typedef UIntPack< (-BSplineSupportSizes< Degrees >::SupportStart ) ... > LeftRadii; + typedef UIntPack< ( BSplineSupportSizes< Degrees >::SupportEnd ) ... > RightRadii; + typedef UIntPack< ( BSplineSupportSizes< Degrees >::SupportSize ) ... > Sizes; + }; + + template< typename Pack > struct OverlapKey{ }; + template< unsigned int ... Degrees > + struct OverlapKey< UIntPack< Degrees ... > > : public RegularTreeNode< sizeof...(Degrees) , FEMTreeNodeData , depth_and_offset_type >::template NeighborKey< UIntPack< (-BSplineOverlapSizes< Degrees , Degrees >::OverlapStart ) ... > , UIntPack< BSplineOverlapSizes< Degrees , Degrees >::OverlapEnd ... > > { - _indices.read( stream ); - _data.read( stream , serializer ); - } - void write( BinaryStream &stream ) const + typedef UIntPack< (-BSplineOverlapSizes< Degrees , Degrees >::OverlapStart ) ... > LeftRadii; + typedef UIntPack< ( BSplineOverlapSizes< Degrees , Degrees >::OverlapEnd ) ... > RightRadii; + typedef UIntPack< ( BSplineOverlapSizes< Degrees , Degrees >::OverlapSize ) ... > Sizes; + }; + + template< typename Pack > struct ConstOverlapKey{ }; + template< unsigned int ... Degrees > + struct ConstOverlapKey< UIntPack< Degrees ... > > : public RegularTreeNode< sizeof...(Degrees) , FEMTreeNodeData , depth_and_offset_type >::template ConstNeighborKey< UIntPack< (-BSplineOverlapSizes< Degrees , Degrees >::OverlapStart ) ... > , UIntPack< BSplineOverlapSizes< Degrees , Degrees >::OverlapEnd ... > > { - _indices.write( stream ); - _data.write( stream ); - } - void read( BinaryStream &stream ) + typedef UIntPack< (-BSplineOverlapSizes< Degrees , Degrees >::OverlapStart ) ... > LeftRadii; + typedef UIntPack< ( BSplineOverlapSizes< Degrees , Degrees >::OverlapEnd ) ... > RightRadii; + typedef UIntPack< ( BSplineOverlapSizes< Degrees , Degrees >::OverlapSize ) ... > Sizes; + }; + + template< typename Pack > struct PointSupportKey{ }; + template< unsigned int ... Degrees > + struct PointSupportKey< UIntPack< Degrees ... > > : public RegularTreeNode< sizeof...(Degrees) , FEMTreeNodeData , depth_and_offset_type >::template NeighborKey< UIntPack< BSplineSupportSizes< Degrees >::SupportEnd ... > , UIntPack< (-BSplineSupportSizes< Degrees >::SupportStart ) ... > > { - _indices.read( stream ); - _data.read( stream ); - } - SparseNodeData( void ){} - SparseNodeData( BinaryStream &stream ){ read(stream); } - SparseNodeData( BinaryStream &stream , const Serializer< Data > &serializer ){ read(stream,serializer); } - - size_t size( void ) const { return _data.size(); } - const Data& operator[] ( size_t idx ) const { return _data[idx]; } - Data& operator[] ( size_t idx ) { return _data[idx]; } - - void reserve( size_t sz ){ if( sz>_indices.size() ) _indices.resize( sz , -1 ); } - size_t reserved( void ) const { return _indices.size(); } - Data* operator()( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ){ return ( node->nodeData.nodeIndex<0 || node->nodeData.nodeIndex>=(node_index_type)_indices.size() || _indices[ node->nodeData.nodeIndex ]==-1 ) ? NULL : &_data[ _indices[ node->nodeData.nodeIndex ] ]; } - const Data* operator()( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ) const { return ( node->nodeData.nodeIndex<0 || node->nodeData.nodeIndex>=(node_index_type)_indices.size() || _indices[ node->nodeData.nodeIndex ]==-1 ) ? NULL : &_data[ _indices[ node->nodeData.nodeIndex ] ]; } - Data& operator[]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ) + typedef UIntPack< ( BSplineSupportSizes< Degrees >::SupportEnd ) ... > LeftRadii; + typedef UIntPack< (-BSplineSupportSizes< Degrees >::SupportStart ) ... > RightRadii; + typedef UIntPack< ( BSplineSupportSizes< Degrees >::SupportEnd - BSplineSupportSizes< Degrees >::SupportStart + 1 ) ... > Sizes; + }; + + template< typename Pack > struct ConstPointSupportKey{ }; + template< unsigned int ... Degrees > + struct ConstPointSupportKey< UIntPack< Degrees ... > > : public RegularTreeNode< sizeof...(Degrees) , FEMTreeNodeData , depth_and_offset_type >::template ConstNeighborKey< UIntPack< BSplineSupportSizes< Degrees >::SupportEnd ... > , UIntPack< (-BSplineSupportSizes< Degrees >::SupportStart ) ... > > { - static std::mutex _insertionMutex; - // If the node hasn't been indexed yet - if( node->nodeData.nodeIndex>=(node_index_type)_indices.size() ) - { - std::lock_guard< std::mutex > lock( _insertionMutex ); - if( node->nodeData.nodeIndex>=(node_index_type)_indices.size() ) _indices.resize( node->nodeData.nodeIndex+1 , -1 ); - } - // If the node hasn't been allocated yet - volatile node_index_type &_index = _indices[ node->nodeData.nodeIndex ]; - if( _index==-1 ) - { - std::lock_guard< std::mutex > lock( _insertionMutex ); - if( _index==-1 ) - { - size_t sz = _data.size(); - _data.resize( sz + 1 ); - _index = (node_index_type)sz; - } - } - return _data[ _index ]; - } - node_index_type index( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *node ) const + typedef UIntPack< ( BSplineSupportSizes< Degrees >::SupportEnd ) ... > LeftRadii; + typedef UIntPack< (-BSplineSupportSizes< Degrees >::SupportStart ) ... > RightRadii; + typedef UIntPack< ( BSplineSupportSizes< Degrees >::SupportEnd - BSplineSupportSizes< Degrees >::SupportStart + 1 ) ... > Sizes; + }; + + template< typename Pack > struct CornerSupportKey{ }; + template< unsigned int ... Degrees > + struct CornerSupportKey< UIntPack< Degrees ... > > : public RegularTreeNode< sizeof...(Degrees) , FEMTreeNodeData , depth_and_offset_type >::template NeighborKey< UIntPack< BSplineSupportSizes< Degrees >::BCornerEnd ... > , UIntPack< ( -BSplineSupportSizes< Degrees >::BCornerStart + 1 ) ... > > { - if( !node || node->nodeData.nodeIndex<0 || node->nodeData.nodeIndex>=(node_index_type)_indices.size() ) return -1; - else return _indices[ node->nodeData.nodeIndex ]; - } + typedef UIntPack< ( BSplineSupportSizes< Degrees >::BCornerEnd ) ... > LeftRadii; + typedef UIntPack< (-BSplineSupportSizes< Degrees >::BCornerStart + 1 ) ... > RightRadii; + typedef UIntPack< ( BSplineSupportSizes< Degrees >::BCornerSize + 1 ) ... > Sizes; + }; - node_index_type index( node_index_type idx ) const + template< typename Pack > struct ConstCornerSupportKey{ }; + template< unsigned int ... Degrees > + struct ConstCornerSupportKey< UIntPack< Degrees ... > > : public RegularTreeNode< sizeof...(Degrees) , FEMTreeNodeData , depth_and_offset_type >::template ConstNeighborKey< UIntPack< BSplineSupportSizes< Degrees >::BCornerEnd ... > , UIntPack< ( -BSplineSupportSizes< Degrees >::BCornerStart + 1 ) ... > > { - if( idx<0 || idx>=(node_index_type)_indices.size() ) return -1; - else return _indices[ idx ]; - } + typedef UIntPack< ( BSplineSupportSizes< Degrees >::BCornerEnd ) ... > LeftRadii; + typedef UIntPack< (-BSplineSupportSizes< Degrees >::BCornerStart + 1 ) ... > RightRadii; + typedef UIntPack< ( BSplineSupportSizes< Degrees >::BCornerSize + 1 ) ... > Sizes; + }; - void merge( const SparseNodeData &data ){ return merge( data , []( const Data &data ){ return data; } ); } - template< typename MergeFunctor > - void merge( const SparseNodeData &data , const MergeFunctor &mergeFunctor ) + template< class Data , typename Pack > struct _SparseOrDenseNodeData{}; + template< class Data , unsigned int ... FEMSigs > + struct _SparseOrDenseNodeData< Data , UIntPack< FEMSigs ... > > { - size_t sz = _indices.size(); - node_index_type newDataCount = 0; - for( unsigned int j=0 ; j FEMSignatures; + typedef Data data_type; + + // Methods for accessing as an array + virtual size_t size( void ) const = 0; + virtual const Data& operator[] ( size_t idx ) const = 0; + virtual Data& operator[] ( size_t idx ) = 0; - template< typename TargetToSourceFunctor > - void mergeFromTarget( const SparseNodeData &data , const TargetToSourceFunctor &targetToSourceFunctor ){ return mergeFromTarget( data , targetToSourceFunctor , []( const Data &data ){ return data; } ); } + // Method for accessing (and inserting if necessary) using a node + virtual Data& operator[]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *node ) = 0; + // Methods for accessing using a node + virtual Data* operator()( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *node ) = 0; + virtual const Data* operator()( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ) const = 0; - template< typename TargetToSourceFunctor , typename MergeFunctor > - void mergeFromTarget( const SparseNodeData &target , const TargetToSourceFunctor &targetToSourceFunctor , const MergeFunctor &mergeFunctor ) + // Method for getting the actual index associated with a node + virtual node_index_type index( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ) const = 0; + }; + + template< class Data , typename Pack > struct SparseNodeData{}; + template< class Data , unsigned int ... FEMSigs > + struct SparseNodeData< Data , UIntPack< FEMSigs ... > > : public _SparseOrDenseNodeData< Data , UIntPack< FEMSigs ... > > { - size_t sz = _indices.size(); - node_index_type newDataCount = 0; - for( unsigned int j=0 ; j &serializer ) const + { + _indices.write( stream ); + _data.write( stream , serializer ); + } + void read( BinaryStream &stream , const Serializer< Data > &serializer ) + { + _indices.read( stream ); + _data.read( stream , serializer ); + } + void write( BinaryStream &stream ) const + { + _indices.write( stream ); + _data.write( stream ); + } + void read( BinaryStream &stream ) + { + _indices.read( stream ); + _data.read( stream ); + } + SparseNodeData( void ){} + SparseNodeData( BinaryStream &stream ){ read(stream); } + SparseNodeData( BinaryStream &stream , const Serializer< Data > &serializer ){ read(stream,serializer); } + + size_t size( void ) const { return _data.size(); } + const Data& operator[] ( size_t idx ) const { return _data[idx]; } + Data& operator[] ( size_t idx ) { return _data[idx]; } + + void reserve( size_t sz ){ if( sz>_indices.size() ) _indices.resize( sz , -1 ); } + size_t reserved( void ) const { return _indices.size(); } + Data* operator()( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ){ return ( node->nodeData.nodeIndex<0 || node->nodeData.nodeIndex>=(node_index_type)_indices.size() || _indices[ node->nodeData.nodeIndex ]==-1 ) ? NULL : &_data[ _indices[ node->nodeData.nodeIndex ] ]; } + const Data* operator()( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ) const { return ( node->nodeData.nodeIndex<0 || node->nodeData.nodeIndex>=(node_index_type)_indices.size() || _indices[ node->nodeData.nodeIndex ]==-1 ) ? NULL : &_data[ _indices[ node->nodeData.nodeIndex ] ]; } + Data& operator[]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ) + { + static std::mutex _insertionMutex; + // If the node hasn't been indexed yet + if( node->nodeData.nodeIndex>=(node_index_type)_indices.size() ) { - _indices[_j] = (node_index_type)oldSize + newDataCount; - _data[ oldSize + newDataCount ] = mergeFunctor( target._data[ target._indices[j] ] ); - newDataCount++; + std::lock_guard< std::mutex > lock( _insertionMutex ); + if( node->nodeData.nodeIndex>=(node_index_type)_indices.size() ) _indices.resize( node->nodeData.nodeIndex+1 , -1 ); } - else _data[ _indices[_j] ] += mergeFunctor( target._data[ target._indices[j] ] ); + // If the node hasn't been allocated yet + volatile node_index_type &_index = _indices[ node->nodeData.nodeIndex ]; + if( _index==-1 ) + { + std::lock_guard< std::mutex > lock( _insertionMutex ); + if( _index==-1 ) + { + size_t sz = _data.size(); + _data.resize( sz + 1 ); + _index = (node_index_type)sz; + } + } + return _data[ _index ]; + } + node_index_type index( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *node ) const + { + if( !node || node->nodeData.nodeIndex<0 || node->nodeData.nodeIndex>=(node_index_type)_indices.size() ) return -1; + else return _indices[ node->nodeData.nodeIndex ]; } - } - - template< typename SourceToTargetFunctor > - void mergeToSource( const SparseNodeData &data , const SourceToTargetFunctor &sourceToTargetFunctor ){ return mergeToSource( data , sourceToTargetFunctor , []( const Data &data ){ return data; } ); } - template< typename SourceToTargetFunctor , typename MergeFunctor > - void mergeToSource( const SparseNodeData &target , const SourceToTargetFunctor &sourceToTargetFunctor , const MergeFunctor &mergeFunctor ) - { - size_t _sz = target._indices.size(); - node_index_type newDataCount = 0; - for( unsigned int j=0 ; j<_indices.size() ; j++ ) if( _indices[j]==-1 ) + node_index_type index( node_index_type idx ) const { - unsigned int _j = sourceToTargetFunctor( j ); - if( _j<(node_index_type)_sz && target._indices[_j]!=-1 ) newDataCount++; + if( idx<0 || idx>=(node_index_type)_indices.size() ) return -1; + else return _indices[ idx ]; } - size_t oldSize = _data.size(); - _data.resize( oldSize + newDataCount ); - newDataCount = 0; - for( unsigned int j=0 ; j<_indices.size() ; j++ ) + + void merge( const SparseNodeData &data ){ return merge( data , []( const Data &data ){ return data; } ); } + + template< typename MergeFunctor > + void merge( const SparseNodeData &data , const MergeFunctor &mergeFunctor ) { - unsigned int _j = sourceToTargetFunctor( j ); - if( _j<(node_index_type)_sz && target._indices[_j]!=-1 ) + size_t sz = _indices.size(); + node_index_type newDataCount = 0; + for( unsigned int j=0 ; j friend class FEMTree; + template< typename TargetToSourceFunctor > + void mergeFromTarget( const SparseNodeData &data , const TargetToSourceFunctor &targetToSourceFunctor ){ return mergeFromTarget( data , targetToSourceFunctor , []( const Data &data ){ return data; } ); } - // Map should be the size of the new number of entries and map[i] should give the old index of the i-th node - void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ) - { - BlockedVector< node_index_type > newIndices; - newIndices.resize( newNodeCount ); - for( node_index_type i=0 ; i<(node_index_type)newNodeCount ; i++ ) + template< typename TargetToSourceFunctor , typename MergeFunctor > + void mergeFromTarget( const SparseNodeData &target , const TargetToSourceFunctor &targetToSourceFunctor , const MergeFunctor &mergeFunctor ) { - newIndices[i] = -1; - if( oldNodeIndices[i]!=-1 && oldNodeIndices[i]<(node_index_type)_indices.size() ) newIndices[i] = _indices[ oldNodeIndices[i] ]; - } - _indices = newIndices; - } - - SparseNodeData _trim( node_index_type endIndex ) const - { - size_t dataCount = 0; - for( node_index_type i=0 ; i _indices; - BlockedVector< Data > _data; -}; + } -template< class Data , typename Pack > struct DenseNodeData{}; -template< class Data , unsigned int ... FEMSigs > -struct DenseNodeData< Data , UIntPack< FEMSigs ... > > : public _SparseOrDenseNodeData< Data , UIntPack< FEMSigs ... > > -{ - static const unsigned int Dim = sizeof ... ( FEMSigs ); - 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( BinaryStream &stream ) : DenseNodeData() { read(stream); } - ~DenseNodeData( void ){ DeletePointer( _data ) ; _sz = 0; } - void resize( size_t sz ){ DeletePointer( _data ) ; _sz = sz ; if( sz ) _data = NewPointer< Data >( sz ) ; else _data = NullPointer( Data ); } - static void WriteSignatures( BinaryStream &stream ) - { - unsigned int dim = sizeof ... ( FEMSigs ); - stream.write( dim ); - unsigned int femSigs[] = { FEMSigs ... }; - stream.write( GetPointer( femSigs , dim ) , dim ); - } - void write( BinaryStream &stream ) const - { - stream.write( _sz ); - stream.write( _data , _sz ); - } - void read( BinaryStream &stream ) - { - if( !stream.read( _sz ) ) ERROR_OUT( "Failed to read size" ); - _data = NewPointer< Data >( _sz ); - if( !stream.read( _data , _sz ) ) ERROR_OUT( "failed to read data" ); - } + template< typename SourceToTargetFunctor > + void mergeToSource( const SparseNodeData &data , const SourceToTargetFunctor &sourceToTargetFunctor ){ return mergeToSource( data , sourceToTargetFunctor , []( const Data &data ){ return data; } ); } - Data& operator[] ( size_t idx ) { return _data[idx]; } - const Data& operator[] ( size_t idx ) const { return _data[idx]; } - size_t size( void ) const { return _sz; } - Data& operator[]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ) { return _data[ node->nodeData.nodeIndex ]; } - Data* operator()( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ) { return ( node==NULL || node->nodeData.nodeIndex>=(node_index_type)_sz ) ? NULL : &_data[ node->nodeData.nodeIndex ]; } - const Data* operator()( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ) const { return ( node==NULL || node->nodeData.nodeIndex>=(node_index_type)_sz ) ? NULL : &_data[ node->nodeData.nodeIndex ]; } - node_index_type index( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ) const { return ( !node || node->nodeData.nodeIndex<0 || node->nodeData.nodeIndex>=(node_index_type)_sz ) ? -1 : node->nodeData.nodeIndex; } - Pointer( Data ) operator()( void ) { return _data; } - ConstPointer( Data ) operator()( void ) const { return ( ConstPointer( Data ) )_data; } -protected: - template< unsigned int _Dim , class _Real > friend class FEMTree; - - // Map should be the size of the new number of entries and map[i] should give the old index of the i-th node - void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ) - { - Pointer( Data ) newData = NewPointer< Data >( newNodeCount ); - memset( newData , 0 , sizeof(Data)*newNodeCount ); - for( size_t i=0 ; i=0 && oldNodeIndices[i]<(node_index_type)_sz ) newData[i] = _data[ oldNodeIndices[i] ]; - DeletePointer( _data ); - _data = newData; - _sz = newNodeCount; - } + template< typename SourceToTargetFunctor , typename MergeFunctor > + void mergeToSource( const SparseNodeData &target , const SourceToTargetFunctor &sourceToTargetFunctor , const MergeFunctor &mergeFunctor ) + { + size_t _sz = target._indices.size(); + node_index_type newDataCount = 0; + for( unsigned int j=0 ; j<_indices.size() ; j++ ) if( _indices[j]==-1 ) + { + unsigned int _j = sourceToTargetFunctor( j ); + if( _j<(node_index_type)_sz && target._indices[_j]!=-1 ) newDataCount++; + } + size_t oldSize = _data.size(); + _data.resize( oldSize + newDataCount ); + newDataCount = 0; + for( unsigned int j=0 ; j<_indices.size() ; j++ ) + { + unsigned int _j = sourceToTargetFunctor( j ); + if( _j<(node_index_type)_sz && target._indices[_j]!=-1 ) + if( _indices[j]==-1 ) + { + _indices[j] = (node_index_type)oldSize + newDataCount; + _data[ oldSize + newDataCount ] = mergeFunctor( target._data[ target._indices[_j] ] ); + newDataCount++; + } + else _data[ _indices[j] ] += mergeFunctor( target._data[ target._indices[_j] ] ); + } + } - DenseNodeData _trim( node_index_type endIndex ) const - { - DenseNodeData denseNodeData; - denseNodeData._sz = endIndex; - denseNodeData._data = NewPointer< Data >( endIndex ); - memcpy( denseNodeData._data , _data , sizeof(Data) * denseNodeData._sz ); - return denseNodeData; - } + protected: + template< unsigned int _Dim , class _Real > friend class FEMTree; - 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; -}; + // Map should be the size of the new number of entries and map[i] should give the old index of the i-th node + void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ) + { + BlockedVector< node_index_type > newIndices; + newIndices.resize( newNodeCount ); + for( node_index_type i=0 ; i<(node_index_type)newNodeCount ; i++ ) + { + newIndices[i] = -1; + if( oldNodeIndices[i]!=-1 && oldNodeIndices[i]<(node_index_type)_indices.size() ) newIndices[i] = _indices[ oldNodeIndices[i] ]; + } + _indices = newIndices; + } -enum FEMTreeRealType -{ - FEM_TREE_REAL_FLOAT , - FEM_TREE_REAL_DOUBLE , - FEM_TREE_REAL_COUNT -}; -const char* FEMTreeRealNames[] = { "float" , "double" }; + SparseNodeData _trim( node_index_type endIndex ) const + { + size_t dataCount = 0; + for( node_index_type i=0 ; i _indices; + BlockedVector< Data > _data; + }; -unsigned int* ReadDenseNodeDataSignatures( BinaryStream &stream , unsigned int &dim ) -{ - if( !stream.read( dim ) ) ERROR_OUT( "Failed to read dimension" ); - unsigned int* femSigs = new unsigned int[dim]; - if( !stream.read( GetPointer( femSigs , dim ) , dim ) ) ERROR_OUT( "Failed to read signatures" ); - return femSigs; -} + template< class Data , typename Pack > struct DenseNodeData{}; + template< class Data , unsigned int ... FEMSigs > + struct DenseNodeData< Data , UIntPack< FEMSigs ... > > : public _SparseOrDenseNodeData< Data , UIntPack< FEMSigs ... > > + { + static const unsigned int Dim = sizeof ... ( FEMSigs ); + 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( BinaryStream &stream ) : DenseNodeData() { read(stream); } + ~DenseNodeData( void ){ DeletePointer( _data ) ; _sz = 0; } + void resize( size_t sz ){ DeletePointer( _data ) ; _sz = sz ; if( sz ) _data = NewPointer< Data >( sz ) ; else _data = NullPointer( Data ); } + static void WriteSignatures( BinaryStream &stream ) + { + unsigned int dim = sizeof ... ( FEMSigs ); + stream.write( dim ); + unsigned int femSigs[] = { FEMSigs ... }; + stream.write( GetPointer( femSigs , dim ) , dim ); + } + void write( BinaryStream &stream ) const + { + stream.write( _sz ); + stream.write( _data , _sz ); + } + void read( BinaryStream &stream ) + { + if( !stream.read( _sz ) ) ERROR_OUT( "Failed to read size" ); + _data = NewPointer< Data >( _sz ); + if( !stream.read( _data , _sz ) ) ERROR_OUT( "failed to read data" ); + } -// The Derivative method needs static members: -// Dim: the dimensionality of the space in which derivatives are evaluated -// Size: the total number of derivatives -// and static methods: -// Index: takes the number of partials along each dimension and returns the index -// Factor: takes an index and sets the number of partials along each dimension + Data& operator[] ( size_t idx ) { return _data[idx]; } + const Data& operator[] ( size_t idx ) const { return _data[idx]; } + size_t size( void ) const { return _sz; } + Data& operator[]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ) { return _data[ node->nodeData.nodeIndex ]; } + Data* operator()( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ) { return ( node==NULL || node->nodeData.nodeIndex>=(node_index_type)_sz ) ? NULL : &_data[ node->nodeData.nodeIndex ]; } + const Data* operator()( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ) const { return ( node==NULL || node->nodeData.nodeIndex>=(node_index_type)_sz ) ? NULL : &_data[ node->nodeData.nodeIndex ]; } + node_index_type index( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ) const { return ( !node || node->nodeData.nodeIndex<0 || node->nodeData.nodeIndex>=(node_index_type)_sz ) ? -1 : node->nodeData.nodeIndex; } + Pointer( Data ) operator()( void ) { return _data; } + ConstPointer( Data ) operator()( void ) const { return ( ConstPointer( Data ) )_data; } + protected: + template< unsigned int _Dim , class _Real > friend class FEMTree; -template< typename T > struct TensorDerivatives{ }; -template< class Real , typename T > struct TensorDerivativeValues{ }; + // Map should be the size of the new number of entries and map[i] should give the old index of the i-th node + void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ) + { + Pointer( Data ) newData = NewPointer< Data >( newNodeCount ); + memset( newData , 0 , sizeof(Data)*newNodeCount ); + for( size_t i=0 ; i=0 && oldNodeIndices[i]<(node_index_type)_sz ) newData[i] = _data[ oldNodeIndices[i] ]; + DeletePointer( _data ); + _data = newData; + _sz = newNodeCount; + } -// Specify the derivatives for each dimension separately -template< unsigned int D , unsigned int ... Ds > -struct TensorDerivatives< UIntPack< D , Ds ... > > -{ - typedef TensorDerivatives< UIntPack< Ds ... > > _TensorDerivatives; - static const unsigned int LastDerivative = UIntPack< D , Ds ... >::template Get< sizeof ... (Ds) >(); - static const unsigned int Dim = _TensorDerivatives::Dim + 1; - static const unsigned int Size = _TensorDerivatives::Size * ( D+1 ); - static void Factor( unsigned int idx , unsigned int derivatives[Dim] ){ derivatives[0] = idx / _TensorDerivatives::Size ; _TensorDerivatives::Factor( idx % _TensorDerivatives::Size , derivatives+1 ); } - static unsigned int Index( const unsigned int derivatives[Dim] ){ return _TensorDerivatives::Index( derivatives + 1 ) + _TensorDerivatives::Size * derivatives[0]; } -}; -template< unsigned int D > -struct TensorDerivatives< UIntPack< D > > -{ - static const unsigned int LastDerivative = D; - static const unsigned int Dim = 1; - static const unsigned int Size = D+1; - static void Factor( unsigned int idx , unsigned int derivatives[1] ){ derivatives[0] = idx; } - static unsigned int Index( const unsigned int derivatives[1] ){ return derivatives[0]; } -}; -template< class Real , unsigned int ... Ds > struct TensorDerivativeValues< Real , UIntPack< Ds ... > > : public Point< Real , TensorDerivatives< UIntPack< Ds ... > >::Size >{ }; - -// Specify the sum of the derivatives -template< unsigned int Dim , unsigned int D > -struct CumulativeDerivatives -{ - typedef CumulativeDerivatives< Dim , D-1 > _CumulativeDerivatives; - static const unsigned int LastDerivative = D; - static const unsigned int Size = _CumulativeDerivatives::Size * Dim + 1; - static void Factor( unsigned int idx , unsigned int d[Dim] ) - { - if( idx<_CumulativeDerivatives::Size ) return _CumulativeDerivatives::Factor( idx , d ); - else _Factor( idx - _CumulativeDerivatives::Size , d ); - } - static unsigned int Index( const unsigned int derivatives[Dim] ) - { - unsigned int dCount = 0; - for( unsigned int d=0 ; d=D ) ERROR_OUT( "More derivatives than allowed" ); - else if( dCount( endIndex ); + memcpy( denseNodeData._data , _data , sizeof(Data) * denseNodeData._sz ); + return denseNodeData; } - ERROR_OUT( "No derivatives specified" ); - return -1; - } - friend CumulativeDerivatives< Dim , D+1 >; -}; -template< unsigned int Dim > -struct CumulativeDerivatives< Dim , 0 > -{ - static const unsigned int LastDerivative = 0; - static const unsigned int Size = 1; - static void Factor( unsigned int idx , unsigned int d[Dim] ){ memset( d , 0 , sizeof(unsigned int)*Dim ); } - static unsigned int Index( const unsigned int derivatives[Dim] ){ return 0; } -protected: - static const unsigned int _Size = 1; - static void _Factor( unsigned int idx , unsigned int d[Dim] ){ memset( d , 0 , sizeof(unsigned int)*Dim ); } - friend CumulativeDerivatives< Dim , 1 >; -}; -template< typename Real , unsigned int Dim , unsigned int D > using CumulativeDerivativeValues = Point< Real , CumulativeDerivatives< Dim , D >::Size >; - - -template< unsigned int Dim , class Real , unsigned int D > -CumulativeDerivativeValues< Real , Dim , D > Evaluate( const double dValues[Dim][D+1] ) -{ - CumulativeDerivativeValues< Real , Dim , D > v; - unsigned int _d[Dim]; - for( unsigned int d=0 ; d::Size ; d++ ) - { - CumulativeDerivatives< Dim , D >::Factor( d , _d ); - double value = dValues[0][ _d[0] ]; - for( unsigned int dd=1 ; dd -struct DualPointInfo -{ - Point< Real , Dim > position; - Real weight; - CumulativeDerivativeValues< T , Dim , D > dualValues; - DualPointInfo operator + ( const DualPointInfo& p ) const { return DualPointInfo( position + p.position , dualValues + p.dualValues , weight + p.weight ); } - DualPointInfo& operator += ( const DualPointInfo& p ){ position += p.position ; weight += p.weight , dualValues += p.dualValues ; return *this; } - DualPointInfo operator * ( Real s ) const { return DualPointInfo( position*s , weight*s , dualValues*s ); } - DualPointInfo& operator *= ( Real s ){ position *= s , weight *= s , dualValues *= s ; return *this; } - DualPointInfo operator / ( Real s ) const { return DualPointInfo( position/s , weight/s , dualValues/s ); } - DualPointInfo& operator /= ( Real s ){ position /= s , weight /= s , dualValues /= s ; return *this; } - DualPointInfo( void ) : weight(0) { } - DualPointInfo( Point< Real , Dim > p , CumulativeDerivativeValues< T , Dim , D > c , Real w ) { position = p , dualValues = c , weight = w; } -}; -template< unsigned int Dim , class Real , typename Data , typename T , unsigned int D > -struct DualPointAndDataInfo -{ - DualPointInfo< Dim , Real , T , D > pointInfo; - Data data; - DualPointAndDataInfo operator + ( const DualPointAndDataInfo& p ) const { return DualPointAndDataInfo( pointInfo + p.pointInfo , data + p.data ); } - DualPointAndDataInfo operator * ( Real s ) const { return DualPointAndDataInfo( pointInfo * s , data * s ); } - DualPointAndDataInfo operator / ( Real s ) const { return DualPointAndDataInfo( pointInfo / s , data / s ); } - DualPointAndDataInfo& operator += ( const DualPointAndDataInfo& p ){ pointInfo += p.pointInfo ; data += p.data ; return *this; } - DualPointAndDataInfo& operator *= ( Real s ) { pointInfo *= s , data *= s ; return *this; } - DualPointAndDataInfo& operator /= ( Real s ) { pointInfo /= s , data /= s ; return *this; } - DualPointAndDataInfo( void ){ } - DualPointAndDataInfo( DualPointInfo< Dim , Real , T , D > p , Data d ) { pointInfo = p , data = d; } -}; -template< unsigned int Dim , class Real , typename T , unsigned int D > -struct DualPointInfoBrood -{ - DualPointInfo< Dim , Real , T , D >& operator[]( size_t idx ){ return _dpInfo[idx]; } - const DualPointInfo< Dim , Real , T , D >& operator[]( size_t idx ) const { return _dpInfo[idx]; } - void finalize( void ){ _size = 0 ; for( unsigned int i=0 ; i<(1<0 ) _dpInfo[_size++] = _dpInfo[i]; } - unsigned int size( void ) const { return _size; } - - DualPointInfoBrood operator + ( const DualPointInfoBrood& p ) const { DualPointInfoBrood d ; for( unsigned int i=0 ; i<(1< _dpInfo[1< -struct DualPointAndDataInfoBrood -{ - DualPointAndDataInfo< Dim , Real , Data , T , D >& operator[]( size_t idx ){ return _dpInfo[idx]; } - const DualPointAndDataInfo< Dim , Real , Data , T , D >& operator[]( size_t idx ) const { return _dpInfo[idx]; } - void finalize( void ){ _size = 0 ; for( unsigned int i=0 ; i<(1<0 ) _dpInfo[_size++] = _dpInfo[i]; } - unsigned int size( void ) const { return _size; } - - DualPointAndDataInfoBrood operator + ( const DualPointAndDataInfoBrood& p ) const { DualPointAndDataInfoBrood d ; for( unsigned int i=0 ; i<(1< _dpInfo[1< struct System{}; - template< typename TDegreePack > struct RestrictionProlongation{}; - template< typename TDegreePack , typename CDegreePack , unsigned int CDim > struct Constraint{}; - template< typename TDegreePack > struct SystemConstraint{}; - template< typename TDegreePack > struct PointEvaluator{}; - -protected: - template< unsigned int Degree , unsigned int ... Degrees > - static typename std::enable_if< sizeof ... ( Degrees )==0 , bool >::type _IsSupported( UIntPack< Degree , Degrees ... > , unsigned int femDepth , const int femOffset[] , unsigned int spaceDepth , const int spaceOffset[] ) - { - int femRes = 1<::SupportStart ) * spaceRes; - int femEnd = ( 1 + femOffset[0] + BSplineSupportSizes< Degree >::SupportEnd ) * spaceRes; - int spaceBegin = ( 0 + spaceOffset[0] + BSplineSupportSizes< 0 >::SupportStart ) * femRes; - int spaceEnd = ( 1 + spaceOffset[0] + BSplineSupportSizes< 0 >::SupportEnd ) * femRes; - return spaceBeginfemBegin; - } - template< unsigned int Degree , unsigned int ... Degrees > - static typename std::enable_if< sizeof ... ( Degrees )!=0 , bool >::type _IsSupported( UIntPack< Degree , Degrees ... > , unsigned int femDepth , const int femOffset[] , unsigned int spaceDepth , const int spaceOffset[] ) - { - int femRes = 1<::SupportStart ) * spaceRes; - int femEnd = ( 1 + femOffset[0] + BSplineSupportSizes< Degree >::SupportEnd ) * spaceRes; - int spaceBegin = ( 0 + spaceOffset[0] + BSplineSupportSizes< 0 >::SupportStart ) * femRes; - int spaceEnd = ( 1 + spaceOffset[0] + BSplineSupportSizes< 0 >::SupportEnd ) * femRes; - return ( spaceBeginfemBegin ) && _IsSupported( UIntPack< Degrees ... >() , femDepth , femOffset+1 , spaceDepth , spaceOffset+1 ); - } - template< unsigned int Degree , unsigned int ... Degrees > - static typename std::enable_if< sizeof ... ( Degrees )==0 , bool >::type _IsInteriorlySupported( UIntPack< Degree , Degrees ... > , unsigned int depth , const int off[] ) - { - int begin , end; - BSplineSupportSizes< Degree >::InteriorSupportedSpan( depth , begin , end ); - return off[0]>=begin && off[0] - static typename std::enable_if< sizeof ... ( Degrees )!=0 , bool >::type _IsInteriorlySupported( UIntPack< Degree , Degrees ... > , unsigned int depth , const int off[] ) - { - int begin , end; - BSplineSupportSizes< Degree >::InteriorSupportedSpan( depth , begin , end ); - return ( off[0]>=begin && off[0]() , depth , off+1 ); - } - template< unsigned int Degree , unsigned int ... Degrees > - static typename std::enable_if< sizeof ... ( Degrees )==0 , bool >::type _IsInteriorlySupported( UIntPack< Degree , Degrees ... > , unsigned int depth , const int off[] , const double begin[] , const double end[] ) - { - int res = 1<::SupportStart ) / res; - double e = ( 1. + off[0] + BSplineSupportSizes< Degree >::SupportEnd ) / res; - return b>=begin[0] && e<=end[0]; - } - template< unsigned int Degree , unsigned int ... Degrees > - static typename std::enable_if< sizeof ... ( Degrees )!=0 , bool >::type _IsInteriorlySupported( UIntPack< Degree , Degrees ... > , unsigned int depth , const int off[] , const double begin[] , const double end[] ) - { - int res = 1<::SupportStart ) / res; - double e = ( 1. + off[0] + BSplineSupportSizes< Degree >::SupportEnd ) / res; - return b>=begin[0] && e<=end[0] && _IsInteriorlySupported( UIntPack< Degrees ... >() , depth , off+1 , begin+1 , end+1 ); - } - template< unsigned int Degree1 , unsigned int ... Degrees1 , unsigned int Degree2 , unsigned int ... Degrees2 > - static typename std::enable_if< sizeof ... ( Degrees1 )==0 >::type _InteriorOverlappedSpan( UIntPack< Degree1 , Degrees1 ... > , UIntPack< Degree2 , Degrees2 ... > , int depth , int begin[] , int end[] ) - { - BSplineIntegrationData< FEMDegreeAndBType< Degree1 , BOUNDARY_NEUMANN >::Signature , FEMDegreeAndBType< Degree2 , BOUNDARY_NEUMANN >::Signature >::InteriorOverlappedSpan( depth , begin[0] , end[0] ); - } - template< unsigned int Degree1 , unsigned int ... Degrees1 , unsigned int Degree2 , unsigned int ... Degrees2 > - static typename std::enable_if< sizeof ... ( Degrees1 )!=0 >::type _InteriorOverlappedSpan( UIntPack< Degree1 , Degrees1 ... > , UIntPack< Degree2 , Degrees2 ... > , int depth , int begin[] , int end[] ) - { - BSplineIntegrationData< FEMDegreeAndBType< Degree1 , BOUNDARY_NEUMANN >::Signature , FEMDegreeAndBType< Degree2 , BOUNDARY_NEUMANN >::Signature >::InteriorOverlappedSpan( depth , begin[0] , end[0] ); - _InteriorOverlappedSpan( UIntPack< Degrees1 ... >() , UIntPack< Degrees2 ... >() , depth , begin+1 , end+1 ); - } - template< unsigned int Degree1 , unsigned int ... Degrees1 , unsigned int Degree2 , unsigned int ... Degrees2 > - static typename std::enable_if< sizeof ... ( Degrees1 )==0 , bool >::type _IsInteriorlyOverlapped( UIntPack< Degree1 , Degrees1 ... > , UIntPack< Degree2 , Degrees2 ... > , unsigned int depth , const int off[] ) - { - int begin , end; - BSplineIntegrationData< FEMDegreeAndBType< Degree1 , BOUNDARY_NEUMANN >::Signature , FEMDegreeAndBType< Degree2 , BOUNDARY_NEUMANN >::Signature >::InteriorOverlappedSpan( depth , begin , end ); - return off[0]>= begin && off[0] - static typename std::enable_if< sizeof ... ( Degrees1 )!=0 , bool >::type _IsInteriorlyOverlapped( UIntPack< Degree1 , Degrees1 ... > , UIntPack< Degree2 , Degrees2 ... > , unsigned int depth , const int off[] ) - { - int begin , end; - BSplineIntegrationData< FEMDegreeAndBType< Degree1 , BOUNDARY_NEUMANN >::Signature , FEMDegreeAndBType< Degree2 , BOUNDARY_NEUMANN >::Signature >::InteriorOverlappedSpan( depth , begin , end ); - return ( off[0]>= begin && off[0]() , UIntPack< Degrees2 ... >() , depth , off+1 ); - } - template< unsigned int Degree1 , unsigned int ... Degrees1 , unsigned int Degree2 , unsigned int ... Degrees2 > - static typename std::enable_if< sizeof ... ( Degrees1 )==0 >::type _ParentOverlapBounds( UIntPack< Degree1 , Degrees1 ... > , UIntPack< Degree2 , Degrees2 ... > , unsigned int depth , const int off[] , int start[] , int end[] ) - { - const int OverlapStart = BSplineOverlapSizes< Degree1 , Degree2 >::OverlapStart; - start[0] = BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapStart[ off[0] & 1 ] - OverlapStart; - end [0] = BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapEnd [ off[0] & 1 ] - OverlapStart + 1; - } - template< unsigned int Degree1 , unsigned int ... Degrees1 , unsigned int Degree2 , unsigned int ... Degrees2 > - static typename std::enable_if< sizeof ... ( Degrees1 )!=0 >::type _ParentOverlapBounds( UIntPack< Degree1 , Degrees1 ... > , UIntPack< Degree2 , Degrees2 ... > , unsigned int depth , const int off[] , int start[] , int end[] ) + 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; + }; + + enum FEMTreeRealType { - const int OverlapStart = BSplineOverlapSizes< Degree1 , Degree2 >::OverlapStart; - start[0] = BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapStart[ off[0] & 1 ] - OverlapStart; - end [0] = BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapEnd [ off[0] & 1 ] - OverlapStart + 1; - _ParentOverlapBounds( UIntPack< Degrees1 ... >() , UIntPack< Degrees2 ... >() , depth , off+1 , start+1 , end+1 ); - } - template< unsigned int Degree1 , unsigned int ... Degrees1 , unsigned int Degree2 , unsigned int ... Degrees2 > - static typename std::enable_if< sizeof ... ( Degrees1 )==0 >::type _ParentOverlapBounds( UIntPack< Degree1 , Degrees1 ... > , UIntPack< Degree2 , Degrees2 ... > , int corner , int start[] , int end[] ) + FEM_TREE_REAL_FLOAT , + FEM_TREE_REAL_DOUBLE , + FEM_TREE_REAL_COUNT + }; + const char* FEMTreeRealNames[] = { "float" , "double" }; + + void ReadFEMTreeParameter( BinaryStream &stream , FEMTreeRealType& realType , unsigned int &dimension ) { - const int OverlapStart = BSplineOverlapSizes< Degree1 , Degree2 >::OverlapStart; - start[0] = BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapStart[ corner & 1 ] - OverlapStart; - end [0] = BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapEnd [ corner & 1 ] - OverlapStart + 1; + if( !stream.read( realType ) ) ERROR_OUT( "Failed to read real type" ); + if( !stream.read( dimension ) ) ERROR_OUT( "Failed to read dimension" ); } - template< unsigned int Degree1 , unsigned int ... Degrees1 , unsigned int Degree2 , unsigned int ... Degrees2 > - static typename std::enable_if< sizeof ... ( Degrees1 )!=0 >::type _ParentOverlapBounds( UIntPack< Degree1 , Degrees1 ... > , UIntPack< Degree2 , Degrees2 ... > , int corner , int start[] , int end[] ) + + unsigned int* ReadDenseNodeDataSignatures( BinaryStream &stream , unsigned int &dim ) { - const int OverlapStart = BSplineOverlapSizes< Degree1 , Degree2 >::OverlapStart; - start[0] = BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapStart[ corner & 1 ] - OverlapStart; - end [0] = BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapEnd [ corner & 1 ] - OverlapStart + 1; - _ParentOverlapBounds( UIntPack< Degrees1 ... >() , UIntPack< Degrees2 ... >() , corner>>1 , start+1 , end+1 ); + if( !stream.read( dim ) ) ERROR_OUT( "Failed to read dimension" ); + unsigned int* femSigs = new unsigned int[dim]; + if( !stream.read( GetPointer( femSigs , dim ) , dim ) ) ERROR_OUT( "Failed to read signatures" ); + return femSigs; } -public: - template< unsigned int ... Degrees > - static bool IsSupported( UIntPack< Degrees ... > , int femDepth , const int femOffset[] , int spaceDepth , const int spaceOffset[] ){ return femDepth>=0 && spaceDepth>=0 && _IsSupported( UIntPack< Degrees ... >() , femDepth , femOffset , spaceDepth , spaceOffset ); } - template< unsigned int ... Degrees > - static bool IsInteriorlySupported( UIntPack< Degrees ... > , int depth , const int offset[] ){ return depth>=0 && _IsInteriorlySupported( UIntPack< Degrees ... >() , depth , offset ); } - template< unsigned int ... Degrees > - static bool IsInteriorlySupported( UIntPack< Degrees ... > , int depth , const int offset[] , const double begin[] , const double end[] ){ return depth>=0 && _IsInteriorlySupported( UIntPack< Degrees ... >() , depth , offset , begin , end ); } + // The Derivative method needs static members: + // Dim: the dimensionality of the space in which derivatives are evaluated + // Size: the total number of derivatives + // and static methods: + // Index: takes the number of partials along each dimension and returns the index + // Factor: takes an index and sets the number of partials along each dimension - template< unsigned int ... Degrees1 , unsigned int ... Degrees2 > - static void InteriorOverlappedSpan( UIntPack< Degrees1 ... > , UIntPack< Degrees2 ... > , int depth , int begin[] , int end[] ) - { - static_assert( sizeof ... ( Degrees1 ) == sizeof ... ( Degrees2 ) , "[ERROR] Dimensions don't match" ); - _InteriorOverlappedSpan( UIntPack< Degrees1 ... >() , UIntPack< Degrees2 ... >() , depth , begin , end ); - } - template< unsigned int ... Degrees1 , unsigned int ... Degrees2 > - static bool IsInteriorlyOverlapped( UIntPack< Degrees1 ... > , UIntPack< Degrees2 ... > , int depth , const int offset[] ) - { - static_assert( sizeof ... ( Degrees1 ) == sizeof ... ( Degrees2 ) , "[ERROR] Dimensions don't match" ); - return depth>=0 && _IsInteriorlyOverlapped( UIntPack< Degrees1 ... >() , UIntPack< Degrees2 ... >() , depth , offset ); - } + template< typename T > struct TensorDerivatives{ }; + template< class Real , typename T > struct TensorDerivativeValues{ }; - template< unsigned int ... Degrees1 , unsigned int ... Degrees2 > - static void ParentOverlapBounds( UIntPack< Degrees1 ... > , UIntPack< Degrees2 ... > , int depth , const int offset[] , int start[] , int end[] ) + // Specify the derivatives for each dimension separately + template< unsigned int D , unsigned int ... Ds > + struct TensorDerivatives< UIntPack< D , Ds ... > > { - static_assert( sizeof ... ( Degrees1 ) == sizeof ... ( Degrees2 ) , "[ERROR] Dimensions don't match" ); - if( depth>0 ) _ParentOverlapBounds( UIntPack< Degrees1 ... >() , UIntPack< Degrees2 ... >() , depth , offset , start , end ); - } - template< unsigned int ... Degrees1 , unsigned int ... Degrees2 > - static void ParentOverlapBounds( UIntPack< Degrees1 ... > , UIntPack< Degrees2 ... > , int corner , int start[] , int end[] ) - { - static_assert( sizeof ... ( Degrees1 ) == sizeof ... ( Degrees2 ) , "[ERROR] Dimensions don't match" ); - _ParentOverlapBounds( UIntPack< Degrees1 ... >() , UIntPack< Degrees2 ... >() , corner , start , end ); - } + typedef TensorDerivatives< UIntPack< Ds ... > > _TensorDerivatives; + static const unsigned int LastDerivative = UIntPack< D , Ds ... >::template Get< sizeof ... (Ds) >(); + static const unsigned int Dim = _TensorDerivatives::Dim + 1; + static const unsigned int Size = _TensorDerivatives::Size * ( D+1 ); + static void Factor( unsigned int idx , unsigned int derivatives[Dim] ){ derivatives[0] = idx / _TensorDerivatives::Size ; _TensorDerivatives::Factor( idx % _TensorDerivatives::Size , derivatives+1 ); } + static unsigned int Index( const unsigned int derivatives[Dim] ){ return _TensorDerivatives::Index( derivatives + 1 ) + _TensorDerivatives::Size * derivatives[0]; } + }; + template< unsigned int D > + struct TensorDerivatives< UIntPack< D > > + { + static const unsigned int LastDerivative = D; + static const unsigned int Dim = 1; + static const unsigned int Size = D+1; + static void Factor( unsigned int idx , unsigned int derivatives[1] ){ derivatives[0] = idx; } + static unsigned int Index( const unsigned int derivatives[1] ){ return derivatives[0]; } + }; + template< class Real , unsigned int ... Ds > struct TensorDerivativeValues< Real , UIntPack< Ds ... > > : public Point< Real , TensorDerivatives< UIntPack< Ds ... > >::Size >{ }; - template< unsigned int Dim > - struct PointEvaluatorState + // Specify the sum of the derivatives + template< unsigned int Dim , unsigned int D > + struct CumulativeDerivatives { - virtual double value( const int offset[] , const unsigned int d[] ) const = 0; - virtual double subValue( const int offset[] , const unsigned int d[] ) const = 0; - template< class Real , typename DerivativeType > - Point< Real , DerivativeType::Size > dValues( const int offset[] ) const + typedef CumulativeDerivatives< Dim , D-1 > _CumulativeDerivatives; + static const unsigned int LastDerivative = D; + static const unsigned int Size = _CumulativeDerivatives::Size * Dim + 1; + static void Factor( unsigned int idx , unsigned int d[Dim] ) { - Point< Real , DerivativeType::Size > v; - unsigned int _d[Dim]; - for( int d=0 ; d=D ) ERROR_OUT( "More derivatives than allowed" ); + else if( dCount - Point< Real , DerivativeType::LastDerivative+1 > partialDotDValues( Point< Real , DerivativeType::Size > v , const int offset[] ) const + protected: + static const unsigned int _Size = _CumulativeDerivatives::_Size * Dim; + static void _Factor( unsigned int idx , unsigned int d[Dim] ) + { + _CumulativeDerivatives::_Factor( idx % _CumulativeDerivatives::_Size , d ); + d[ idx / _CumulativeDerivatives::_Size ]++; + } + static unsigned int _Index( const unsigned int d[Dim] ) { - Point< Real , DerivativeType::LastDerivative+1 > dot; unsigned int _d[Dim]; - for( int d=0 ; d; }; - - template< unsigned int ... TDegrees > - struct PointEvaluator< UIntPack< TDegrees ... > > + template< unsigned int Dim > + struct CumulativeDerivatives< Dim , 0 > { - static const unsigned int Dim = sizeof ... ( TDegrees ); + static const unsigned int LastDerivative = 0; + static const unsigned int Size = 1; + static void Factor( unsigned int idx , unsigned int d[Dim] ){ memset( d , 0 , sizeof(unsigned int)*Dim ); } + static unsigned int Index( const unsigned int derivatives[Dim] ){ return 0; } + protected: + static const unsigned int _Size = 1; + static void _Factor( unsigned int idx , unsigned int d[Dim] ){ memset( d , 0 , sizeof(unsigned int)*Dim ); } + friend CumulativeDerivatives< Dim , 1 >; }; + template< typename Real , unsigned int Dim , unsigned int D > using CumulativeDerivativeValues = Point< Real , CumulativeDerivatives< Dim , D >::Size >; + - template< unsigned int ... TDegrees > - struct RestrictionProlongation< UIntPack< TDegrees ... > > + template< unsigned int Dim , class Real , unsigned int D > + CumulativeDerivativeValues< Real , Dim , D > Evaluate( const double dValues[Dim][D+1] ) { - virtual void init( void ){ } - virtual double upSampleCoefficient( const int pOff[] , const int cOff[] ) const = 0; + CumulativeDerivativeValues< Real , Dim , D > v; + unsigned int _d[Dim]; + for( unsigned int d=0 ; d::Size ; d++ ) + { + CumulativeDerivatives< Dim , D >::Factor( d , _d ); + double value = dValues[0][ _d[0] ]; + for( unsigned int dd=1 ; dd + struct DualPointInfo + { + Point< Real , Dim > position; + Real weight; + CumulativeDerivativeValues< T , Dim , D > dualValues; + DualPointInfo operator + ( const DualPointInfo& p ) const { return DualPointInfo( position + p.position , dualValues + p.dualValues , weight + p.weight ); } + DualPointInfo& operator += ( const DualPointInfo& p ){ position += p.position ; weight += p.weight , dualValues += p.dualValues ; return *this; } + DualPointInfo operator * ( Real s ) const { return DualPointInfo( position*s , weight*s , dualValues*s ); } + DualPointInfo& operator *= ( Real s ){ position *= s , weight *= s , dualValues *= s ; return *this; } + DualPointInfo operator / ( Real s ) const { return DualPointInfo( position/s , weight/s , dualValues/s ); } + DualPointInfo& operator /= ( Real s ){ position /= s , weight /= s , dualValues /= s ; return *this; } + DualPointInfo( void ) : weight(0) { } + DualPointInfo( Point< Real , Dim > p , CumulativeDerivativeValues< T , Dim , D > c , Real w ) { position = p , dualValues = c , weight = w; } + }; + template< unsigned int Dim , class Real , typename Data , typename T , unsigned int D > + struct DualPointAndDataInfo + { + DualPointInfo< Dim , Real , T , D > pointInfo; + Data data; + DualPointAndDataInfo operator + ( const DualPointAndDataInfo& p ) const { return DualPointAndDataInfo( pointInfo + p.pointInfo , data + p.data ); } + DualPointAndDataInfo operator * ( Real s ) const { return DualPointAndDataInfo( pointInfo * s , data * s ); } + DualPointAndDataInfo operator / ( Real s ) const { return DualPointAndDataInfo( pointInfo / s , data / s ); } + DualPointAndDataInfo& operator += ( const DualPointAndDataInfo& p ){ pointInfo += p.pointInfo ; data += p.data ; return *this; } + DualPointAndDataInfo& operator *= ( Real s ) { pointInfo *= s , data *= s ; return *this; } + DualPointAndDataInfo& operator /= ( Real s ) { pointInfo /= s , data /= s ; return *this; } + DualPointAndDataInfo( void ){ } + DualPointAndDataInfo( DualPointInfo< Dim , Real , T , D > p , Data d ) { pointInfo = p , data = d; } + }; + template< unsigned int Dim , class Real , typename T , unsigned int D > + struct DualPointInfoBrood + { + DualPointInfo< Dim , Real , T , D >& operator[]( size_t idx ){ return _dpInfo[idx]; } + const DualPointInfo< Dim , Real , T , D >& operator[]( size_t idx ) const { return _dpInfo[idx]; } + void finalize( void ){ _size = 0 ; for( unsigned int i=0 ; i<(1<0 ) _dpInfo[_size++] = _dpInfo[i]; } + unsigned int size( void ) const { return _size; } + + DualPointInfoBrood operator + ( const DualPointInfoBrood& p ) const { DualPointInfoBrood d ; for( unsigned int i=0 ; i<(1< _dpInfo[1< + struct DualPointAndDataInfoBrood + { + DualPointAndDataInfo< Dim , Real , Data , T , D >& operator[]( size_t idx ){ return _dpInfo[idx]; } + const DualPointAndDataInfo< Dim , Real , Data , T , D >& operator[]( size_t idx ) const { return _dpInfo[idx]; } + void finalize( void ){ _size = 0 ; for( unsigned int i=0 ; i<(1<0 ) _dpInfo[_size++] = _dpInfo[i]; } + unsigned int size( void ) const { return _size; } + + DualPointAndDataInfoBrood operator + ( const DualPointAndDataInfoBrood& p ) const { DualPointAndDataInfoBrood d ; for( unsigned int i=0 ; i<(1< _dpInfo[1<::DownSample0Start + BSplineSupportSizes< TDegrees >::DownSample1End + 1 ) ... > > DownSampleStencil; - struct UpSampleStencil : public DynamicWindow< double , UIntPack< BSplineSupportSizes< TDegrees >::UpSampleSize ... > > { }; - struct DownSampleStencils : public DynamicWindow< DownSampleStencil , IsotropicUIntPack< sizeof ... ( TDegrees ) , 2 > > { }; - void init( int highDepth ){ _highDepth = highDepth ; init(); } - void setStencil ( UpSampleStencil & stencil ) const; - void setStencils( DownSampleStencils& stencils ) const; - int highDepth( void ) const { return _highDepth; } + //////////////////////////// + // The virtual integrator // + //////////////////////////// + struct BaseFEMIntegrator + { + template< typename TDegreePack > struct System{}; + template< typename TDegreePack > struct RestrictionProlongation{}; + template< typename TDegreePack , typename CDegreePack , unsigned int CDim > struct Constraint{}; + template< typename TDegreePack > struct SystemConstraint{}; + template< typename TDegreePack > struct PointEvaluator{}; protected: - int _highDepth; - }; + template< unsigned int Degree , unsigned int ... Degrees > + static typename std::enable_if< sizeof ... ( Degrees )==0 , bool >::type _IsSupported( UIntPack< Degree , Degrees ... > , unsigned int femDepth , const int femOffset[] , unsigned int spaceDepth , const int spaceOffset[] ) + { + int femRes = 1<::SupportStart ) * spaceRes; + int femEnd = ( 1 + femOffset[0] + BSplineSupportSizes< Degree >::SupportEnd ) * spaceRes; + int spaceBegin = ( 0 + spaceOffset[0] + BSplineSupportSizes< 0 >::SupportStart ) * femRes; + int spaceEnd = ( 1 + spaceOffset[0] + BSplineSupportSizes< 0 >::SupportEnd ) * femRes; + return spaceBeginfemBegin; + } + template< unsigned int Degree , unsigned int ... Degrees > + static typename std::enable_if< sizeof ... ( Degrees )!=0 , bool >::type _IsSupported( UIntPack< Degree , Degrees ... > , unsigned int femDepth , const int femOffset[] , unsigned int spaceDepth , const int spaceOffset[] ) + { + int femRes = 1<::SupportStart ) * spaceRes; + int femEnd = ( 1 + femOffset[0] + BSplineSupportSizes< Degree >::SupportEnd ) * spaceRes; + int spaceBegin = ( 0 + spaceOffset[0] + BSplineSupportSizes< 0 >::SupportStart ) * femRes; + int spaceEnd = ( 1 + spaceOffset[0] + BSplineSupportSizes< 0 >::SupportEnd ) * femRes; + return ( spaceBeginfemBegin ) && _IsSupported( UIntPack< Degrees ... >() , femDepth , femOffset+1 , spaceDepth , spaceOffset+1 ); + } + template< unsigned int Degree , unsigned int ... Degrees > + static typename std::enable_if< sizeof ... ( Degrees )==0 , bool >::type _IsInteriorlySupported( UIntPack< Degree , Degrees ... > , unsigned int depth , const int off[] ) + { + int begin , end; + BSplineSupportSizes< Degree >::InteriorSupportedSpan( depth , begin , end ); + return off[0]>=begin && off[0] + static typename std::enable_if< sizeof ... ( Degrees )!=0 , bool >::type _IsInteriorlySupported( UIntPack< Degree , Degrees ... > , unsigned int depth , const int off[] ) + { + int begin , end; + BSplineSupportSizes< Degree >::InteriorSupportedSpan( depth , begin , end ); + return ( off[0]>=begin && off[0]() , depth , off+1 ); + } + template< unsigned int Degree , unsigned int ... Degrees > + static typename std::enable_if< sizeof ... ( Degrees )==0 , bool >::type _IsInteriorlySupported( UIntPack< Degree , Degrees ... > , unsigned int depth , const int off[] , const double begin[] , const double end[] ) + { + int res = 1<::SupportStart ) / res; + double e = ( 1. + off[0] + BSplineSupportSizes< Degree >::SupportEnd ) / res; + return b>=begin[0] && e<=end[0]; + } + template< unsigned int Degree , unsigned int ... Degrees > + static typename std::enable_if< sizeof ... ( Degrees )!=0 , bool >::type _IsInteriorlySupported( UIntPack< Degree , Degrees ... > , unsigned int depth , const int off[] , const double begin[] , const double end[] ) + { + int res = 1<::SupportStart ) / res; + double e = ( 1. + off[0] + BSplineSupportSizes< Degree >::SupportEnd ) / res; + return b>=begin[0] && e<=end[0] && _IsInteriorlySupported( UIntPack< Degrees ... >() , depth , off+1 , begin+1 , end+1 ); + } + template< unsigned int Degree1 , unsigned int ... Degrees1 , unsigned int Degree2 , unsigned int ... Degrees2 > + static typename std::enable_if< sizeof ... ( Degrees1 )==0 >::type _InteriorOverlappedSpan( UIntPack< Degree1 , Degrees1 ... > , UIntPack< Degree2 , Degrees2 ... > , int depth , int begin[] , int end[] ) + { + BSplineIntegrationData< FEMDegreeAndBType< Degree1 , BOUNDARY_NEUMANN >::Signature , FEMDegreeAndBType< Degree2 , BOUNDARY_NEUMANN >::Signature >::InteriorOverlappedSpan( depth , begin[0] , end[0] ); + } + template< unsigned int Degree1 , unsigned int ... Degrees1 , unsigned int Degree2 , unsigned int ... Degrees2 > + static typename std::enable_if< sizeof ... ( Degrees1 )!=0 >::type _InteriorOverlappedSpan( UIntPack< Degree1 , Degrees1 ... > , UIntPack< Degree2 , Degrees2 ... > , int depth , int begin[] , int end[] ) + { + BSplineIntegrationData< FEMDegreeAndBType< Degree1 , BOUNDARY_NEUMANN >::Signature , FEMDegreeAndBType< Degree2 , BOUNDARY_NEUMANN >::Signature >::InteriorOverlappedSpan( depth , begin[0] , end[0] ); + _InteriorOverlappedSpan( UIntPack< Degrees1 ... >() , UIntPack< Degrees2 ... >() , depth , begin+1 , end+1 ); + } + template< unsigned int Degree1 , unsigned int ... Degrees1 , unsigned int Degree2 , unsigned int ... Degrees2 > + static typename std::enable_if< sizeof ... ( Degrees1 )==0 , bool >::type _IsInteriorlyOverlapped( UIntPack< Degree1 , Degrees1 ... > , UIntPack< Degree2 , Degrees2 ... > , unsigned int depth , const int off[] ) + { + int begin , end; + BSplineIntegrationData< FEMDegreeAndBType< Degree1 , BOUNDARY_NEUMANN >::Signature , FEMDegreeAndBType< Degree2 , BOUNDARY_NEUMANN >::Signature >::InteriorOverlappedSpan( depth , begin , end ); + return off[0]>= begin && off[0] + static typename std::enable_if< sizeof ... ( Degrees1 )!=0 , bool >::type _IsInteriorlyOverlapped( UIntPack< Degree1 , Degrees1 ... > , UIntPack< Degree2 , Degrees2 ... > , unsigned int depth , const int off[] ) + { + int begin , end; + BSplineIntegrationData< FEMDegreeAndBType< Degree1 , BOUNDARY_NEUMANN >::Signature , FEMDegreeAndBType< Degree2 , BOUNDARY_NEUMANN >::Signature >::InteriorOverlappedSpan( depth , begin , end ); + return ( off[0]>= begin && off[0]() , UIntPack< Degrees2 ... >() , depth , off+1 ); + } + template< unsigned int Degree1 , unsigned int ... Degrees1 , unsigned int Degree2 , unsigned int ... Degrees2 > + static typename std::enable_if< sizeof ... ( Degrees1 )==0 >::type _ParentOverlapBounds( UIntPack< Degree1 , Degrees1 ... > , UIntPack< Degree2 , Degrees2 ... > , unsigned int depth , const int off[] , int start[] , int end[] ) + { + const int OverlapStart = BSplineOverlapSizes< Degree1 , Degree2 >::OverlapStart; + start[0] = BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapStart[ off[0] & 1 ] - OverlapStart; + end [0] = BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapEnd [ off[0] & 1 ] - OverlapStart + 1; + } + template< unsigned int Degree1 , unsigned int ... Degrees1 , unsigned int Degree2 , unsigned int ... Degrees2 > + static typename std::enable_if< sizeof ... ( Degrees1 )!=0 >::type _ParentOverlapBounds( UIntPack< Degree1 , Degrees1 ... > , UIntPack< Degree2 , Degrees2 ... > , unsigned int depth , const int off[] , int start[] , int end[] ) + { + const int OverlapStart = BSplineOverlapSizes< Degree1 , Degree2 >::OverlapStart; + start[0] = BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapStart[ off[0] & 1 ] - OverlapStart; + end [0] = BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapEnd [ off[0] & 1 ] - OverlapStart + 1; + _ParentOverlapBounds( UIntPack< Degrees1 ... >() , UIntPack< Degrees2 ... >() , depth , off+1 , start+1 , end+1 ); + } + template< unsigned int Degree1 , unsigned int ... Degrees1 , unsigned int Degree2 , unsigned int ... Degrees2 > + static typename std::enable_if< sizeof ... ( Degrees1 )==0 >::type _ParentOverlapBounds( UIntPack< Degree1 , Degrees1 ... > , UIntPack< Degree2 , Degrees2 ... > , int corner , int start[] , int end[] ) + { + const int OverlapStart = BSplineOverlapSizes< Degree1 , Degree2 >::OverlapStart; + start[0] = BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapStart[ corner & 1 ] - OverlapStart; + end [0] = BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapEnd [ corner & 1 ] - OverlapStart + 1; + } + template< unsigned int Degree1 , unsigned int ... Degrees1 , unsigned int Degree2 , unsigned int ... Degrees2 > + static typename std::enable_if< sizeof ... ( Degrees1 )!=0 >::type _ParentOverlapBounds( UIntPack< Degree1 , Degrees1 ... > , UIntPack< Degree2 , Degrees2 ... > , int corner , int start[] , int end[] ) + { + const int OverlapStart = BSplineOverlapSizes< Degree1 , Degree2 >::OverlapStart; + start[0] = BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapStart[ corner & 1 ] - OverlapStart; + end [0] = BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapEnd [ corner & 1 ] - OverlapStart + 1; + _ParentOverlapBounds( UIntPack< Degrees1 ... >() , UIntPack< Degrees2 ... >() , corner>>1 , start+1 , end+1 ); + } + + public: + template< unsigned int ... Degrees > + static bool IsSupported( UIntPack< Degrees ... > , int femDepth , const int femOffset[] , int spaceDepth , const int spaceOffset[] ){ return femDepth>=0 && spaceDepth>=0 && _IsSupported( UIntPack< Degrees ... >() , femDepth , femOffset , spaceDepth , spaceOffset ); } + template< unsigned int ... Degrees > + static bool IsInteriorlySupported( UIntPack< Degrees ... > , int depth , const int offset[] ){ return depth>=0 && _IsInteriorlySupported( UIntPack< Degrees ... >() , depth , offset ); } + template< unsigned int ... Degrees > + static bool IsInteriorlySupported( UIntPack< Degrees ... > , int depth , const int offset[] , const double begin[] , const double end[] ){ return depth>=0 && _IsInteriorlySupported( UIntPack< Degrees ... >() , depth , offset , begin , end ); } + + template< unsigned int ... Degrees1 , unsigned int ... Degrees2 > + static void InteriorOverlappedSpan( UIntPack< Degrees1 ... > , UIntPack< Degrees2 ... > , int depth , int begin[] , int end[] ) + { + static_assert( sizeof ... ( Degrees1 ) == sizeof ... ( Degrees2 ) , "[ERROR] Dimensions don't match" ); + _InteriorOverlappedSpan( UIntPack< Degrees1 ... >() , UIntPack< Degrees2 ... >() , depth , begin , end ); + } + template< unsigned int ... Degrees1 , unsigned int ... Degrees2 > + static bool IsInteriorlyOverlapped( UIntPack< Degrees1 ... > , UIntPack< Degrees2 ... > , int depth , const int offset[] ) + { + static_assert( sizeof ... ( Degrees1 ) == sizeof ... ( Degrees2 ) , "[ERROR] Dimensions don't match" ); + return depth>=0 && _IsInteriorlyOverlapped( UIntPack< Degrees1 ... >() , UIntPack< Degrees2 ... >() , depth , offset ); + } + template< unsigned int ... Degrees1 , unsigned int ... Degrees2 > + static void ParentOverlapBounds( UIntPack< Degrees1 ... > , UIntPack< Degrees2 ... > , int depth , const int offset[] , int start[] , int end[] ) + { + static_assert( sizeof ... ( Degrees1 ) == sizeof ... ( Degrees2 ) , "[ERROR] Dimensions don't match" ); + if( depth>0 ) _ParentOverlapBounds( UIntPack< Degrees1 ... >() , UIntPack< Degrees2 ... >() , depth , offset , start , end ); + } + template< unsigned int ... Degrees1 , unsigned int ... Degrees2 > + static void ParentOverlapBounds( UIntPack< Degrees1 ... > , UIntPack< Degrees2 ... > , int corner , int start[] , int end[] ) + { + static_assert( sizeof ... ( Degrees1 ) == sizeof ... ( Degrees2 ) , "[ERROR] Dimensions don't match" ); + _ParentOverlapBounds( UIntPack< Degrees1 ... >() , UIntPack< Degrees2 ... >() , corner , start , end ); + } - template< unsigned int ... TDegrees > - struct System< UIntPack< TDegrees ... > > - { - virtual void init( void ){ } - virtual double ccIntegrate( const int off1[] , const int off2[] ) const = 0; - virtual double pcIntegrate( const int off1[] , const int off2[] ) const = 0; - virtual bool vanishesOnConstants( void ) const { return false; } - virtual RestrictionProlongation< UIntPack< TDegrees ... > >& restrictionProlongation( void ) = 0; + template< unsigned int Dim > + struct PointEvaluatorState + { + virtual double value( const int offset[] , const unsigned int d[] ) const = 0; + virtual double subValue( const int offset[] , const unsigned int d[] ) const = 0; + template< class Real , typename DerivativeType > + Point< Real , DerivativeType::Size > dValues( const int offset[] ) const + { + Point< Real , DerivativeType::Size > v; + unsigned int _d[Dim]; + for( int d=0 ; d + Point< Real , DerivativeType::LastDerivative+1 > partialDotDValues( Point< Real , DerivativeType::Size > v , const int offset[] ) const + { + Point< Real , DerivativeType::LastDerivative+1 > dot; + unsigned int _d[Dim]; + for( int d=0 ; d + struct PointEvaluator< UIntPack< TDegrees ... > > + { + static const unsigned int Dim = sizeof ... ( TDegrees ); + }; + + template< unsigned int ... TDegrees > + struct RestrictionProlongation< UIntPack< TDegrees ... > > + { + virtual void init( void ){ } + virtual double upSampleCoefficient( const int pOff[] , const int cOff[] ) const = 0; + + typedef DynamicWindow< double , UIntPack< ( - BSplineSupportSizes< TDegrees >::DownSample0Start + BSplineSupportSizes< TDegrees >::DownSample1End + 1 ) ... > > DownSampleStencil; + struct UpSampleStencil : public DynamicWindow< double , UIntPack< BSplineSupportSizes< TDegrees >::UpSampleSize ... > > { }; + struct DownSampleStencils : public DynamicWindow< DownSampleStencil , IsotropicUIntPack< sizeof ... ( TDegrees ) , 2 > > { }; - struct CCStencil : public DynamicWindow< double , UIntPack< BSplineOverlapSizes< TDegrees , TDegrees >::OverlapSize ... > >{ }; + void init( int highDepth ){ _highDepth = highDepth ; init(); } + void setStencil ( UpSampleStencil & stencil ) const; + void setStencils( DownSampleStencils& stencils ) const; + int highDepth( void ) const { return _highDepth; } + + protected: + int _highDepth; + }; + + + template< unsigned int ... TDegrees > + struct System< UIntPack< TDegrees ... > > + { + virtual void init( void ){ } + virtual double ccIntegrate( const int off1[] , const int off2[] ) const = 0; + virtual double pcIntegrate( const int off1[] , const int off2[] ) const = 0; + virtual bool vanishesOnConstants( void ) const { return false; } + virtual RestrictionProlongation< UIntPack< TDegrees ... > >& restrictionProlongation( void ) = 0; + + struct CCStencil : public DynamicWindow< double , UIntPack< BSplineOverlapSizes< TDegrees , TDegrees >::OverlapSize ... > >{ }; #ifdef SHOW_WARNINGS #pragma message ( "[WARNING] Why are the parent/child stencils so big?" ) #endif // SHOW_WARNINGS - struct PCStencils : public DynamicWindow< CCStencil , IsotropicUIntPack< sizeof ... ( TDegrees ) , 2 > >{ }; + struct PCStencils : public DynamicWindow< CCStencil , IsotropicUIntPack< sizeof ... ( TDegrees ) , 2 > >{ }; - void init( int highDepth ){ _highDepth = highDepth ; init(); } - template< bool IterateFirst > void setStencil ( CCStencil & stencil ) const; - template< bool IterateFirst > void setStencils( PCStencils& stencils ) const; - int highDepth( void ) const { return _highDepth; } + void init( int highDepth ){ _highDepth = highDepth ; init(); } + template< bool IterateFirst > void setStencil ( CCStencil & stencil ) const; + template< bool IterateFirst > void setStencils( PCStencils& stencils ) const; + int highDepth( void ) const { return _highDepth; } - protected: - int _highDepth; - }; + protected: + int _highDepth; + }; - template< unsigned int ... TDegrees , unsigned int ... CDegrees , unsigned int CDim > - struct Constraint< UIntPack< TDegrees ... > , UIntPack< CDegrees ... > , CDim > - { - static_assert( sizeof...(TDegrees)==sizeof...(CDegrees) , "[ERROR] BaseFEMIntegrator::Constraint: Test and constraint dimensions don't match" ); + template< unsigned int ... TDegrees , unsigned int ... CDegrees , unsigned int CDim > + struct Constraint< UIntPack< TDegrees ... > , UIntPack< CDegrees ... > , CDim > + { + static_assert( sizeof...(TDegrees)==sizeof...(CDegrees) , "[ERROR] BaseFEMIntegrator::Constraint: Test and constraint dimensions don't match" ); - virtual void init( void ){ ; } - virtual Point< double , CDim > ccIntegrate( const int off1[] , const int off2[] ) const = 0; - virtual Point< double , CDim > pcIntegrate( const int off1[] , const int off2[] ) const = 0; - virtual Point< double , CDim > cpIntegrate( const int off1[] , const int off2[] ) const = 0; - virtual RestrictionProlongation< UIntPack< TDegrees ... > >& tRestrictionProlongation( void ) = 0; - virtual RestrictionProlongation< UIntPack< CDegrees ... > >& cRestrictionProlongation( void ) = 0; + virtual void init( void ){ ; } + virtual Point< double , CDim > ccIntegrate( const int off1[] , const int off2[] ) const = 0; + virtual Point< double , CDim > pcIntegrate( const int off1[] , const int off2[] ) const = 0; + virtual Point< double , CDim > cpIntegrate( const int off1[] , const int off2[] ) const = 0; + virtual RestrictionProlongation< UIntPack< TDegrees ... > >& tRestrictionProlongation( void ) = 0; + virtual RestrictionProlongation< UIntPack< CDegrees ... > >& cRestrictionProlongation( void ) = 0; - struct CCStencil : public DynamicWindow< Point< double , CDim > , UIntPack< BSplineOverlapSizes< TDegrees , CDegrees >::OverlapSize ... > >{ }; + struct CCStencil : public DynamicWindow< Point< double , CDim > , UIntPack< BSplineOverlapSizes< TDegrees , CDegrees >::OverlapSize ... > >{ }; #ifdef SHOW_WARNINGS #pragma message ( "[WARNING] Why are the parent/child stencils so big?" ) #endif // SHOW_WARNINGS - struct PCStencils : public DynamicWindow< CCStencil , IsotropicUIntPack< sizeof ... ( TDegrees ) , 2 > >{ }; - struct CPStencils : public DynamicWindow< CCStencil , IsotropicUIntPack< sizeof ... ( TDegrees ) , 2 > >{ }; + struct PCStencils : public DynamicWindow< CCStencil , IsotropicUIntPack< sizeof ... ( TDegrees ) , 2 > >{ }; + struct CPStencils : public DynamicWindow< CCStencil , IsotropicUIntPack< sizeof ... ( TDegrees ) , 2 > >{ }; - void init( int highDepth ){ _highDepth = highDepth ; init(); } - template< bool IterateFirst > void setStencil ( CCStencil & stencil ) const; - template< bool IterateFirst > void setStencils( PCStencils& stencils ) const; - template< bool IterateFirst > void setStencils( CPStencils& stencils ) const; - int highDepth( void ) const { return _highDepth; } + void init( int highDepth ){ _highDepth = highDepth ; init(); } + template< bool IterateFirst > void setStencil ( CCStencil & stencil ) const; + template< bool IterateFirst > void setStencils( PCStencils& stencils ) const; + template< bool IterateFirst > void setStencils( CPStencils& stencils ) const; + int highDepth( void ) const { return _highDepth; } - protected: - int _highDepth; + protected: + int _highDepth; + }; + + template< unsigned int ... TDegrees > + struct SystemConstraint< UIntPack< TDegrees ... > > : public Constraint< UIntPack< TDegrees ... > , UIntPack< TDegrees ... > , 1 > + { + typedef Constraint< UIntPack< TDegrees ... > , UIntPack< TDegrees ... > , 1 > Base; + SystemConstraint( System< UIntPack< TDegrees ... > >& sys ) : _sys( sys ){;} + void init( void ){ _sys.init( Base::highDepth() ) ; _sys.init(); } + Point< double , 1 > ccIntegrate( const int off1[] , const int off2[] ) const{ return Point< double , 1 >( _sys.ccIntegrate( off1 , off2 ) ); } + Point< double , 1 > pcIntegrate( const int off1[] , const int off2[] ) const{ return Point< double , 1 >( _sys.pcIntegrate( off1 , off2 ) ); } + Point< double , 1 > cpIntegrate( const int off1[] , const int off2[] ) const{ return Point< double , 1 >( _sys.pcIntegrate( off2 , off1 ) ); } + RestrictionProlongation< UIntPack< TDegrees ... > >& tRestrictionProlongation( void ){ return _sys.restrictionProlongation(); } + RestrictionProlongation< UIntPack< TDegrees ... > >& cRestrictionProlongation( void ){ return _sys.restrictionProlongation(); } + protected: + System< UIntPack< TDegrees ... > >& _sys; + }; }; - template< unsigned int ... TDegrees > - struct SystemConstraint< UIntPack< TDegrees ... > > : public Constraint< UIntPack< TDegrees ... > , UIntPack< TDegrees ... > , 1 > + ///////////////////////////////////////////////// + // An implementation of the virtual integrator // + ///////////////////////////////////////////////// + struct FEMIntegrator { - typedef Constraint< UIntPack< TDegrees ... > , UIntPack< TDegrees ... > , 1 > Base; - SystemConstraint( System< UIntPack< TDegrees ... > >& sys ) : _sys( sys ){;} - void init( void ){ _sys.init( Base::highDepth() ) ; _sys.init(); } - Point< double , 1 > ccIntegrate( const int off1[] , const int off2[] ) const{ return Point< double , 1 >( _sys.ccIntegrate( off1 , off2 ) ); } - Point< double , 1 > pcIntegrate( const int off1[] , const int off2[] ) const{ return Point< double , 1 >( _sys.pcIntegrate( off1 , off2 ) ); } - Point< double , 1 > cpIntegrate( const int off1[] , const int off2[] ) const{ return Point< double , 1 >( _sys.pcIntegrate( off2 , off1 ) ); } - RestrictionProlongation< UIntPack< TDegrees ... > >& tRestrictionProlongation( void ){ return _sys.restrictionProlongation(); } - RestrictionProlongation< UIntPack< TDegrees ... > >& cRestrictionProlongation( void ){ return _sys.restrictionProlongation(); } protected: - System< UIntPack< TDegrees ... > >& _sys; - }; -}; + template< unsigned int FEMSig , unsigned int ... FEMSigs > + static typename std::enable_if< sizeof ... ( FEMSigs )==0 , bool >::type _IsValidFEMNode( UIntPack< FEMSig , FEMSigs ... > , unsigned int depth , const int offset[] ) + { + return !BSplineEvaluationData< FEMSig >::OutOfBounds( depth , offset[0] ); + } + template< unsigned int FEMSig , unsigned int ... FEMSigs > + static typename std::enable_if< sizeof ... ( FEMSigs )!=0 , bool >::type _IsValidFEMNode( UIntPack< FEMSig , FEMSigs ... > , unsigned int depth , const int offset[] ) + { + return !BSplineEvaluationData< FEMSig >::OutOfBounds( depth , offset[0] ) && _IsValidFEMNode( UIntPack< FEMSigs ... >() , depth , offset+1 ); + } + template< unsigned int FEMSig , unsigned ... FEMSigs > + static typename std::enable_if< sizeof ... ( FEMSigs )==0 , bool >::type _IsOutOfBounds( UIntPack< FEMSig , FEMSigs ... > , unsigned int depth , const int offset[] ) + { + return BSplineEvaluationData< FEMSig >::OutOfBounds( depth , offset[0] ); + } + template< unsigned int FEMSig , unsigned ... FEMSigs > + static typename std::enable_if< sizeof ... ( FEMSigs )!=0 , bool >::type _IsOutOfBounds( UIntPack< FEMSig , FEMSigs ... > , unsigned int depth , const int offset[] ) + { + return BSplineEvaluationData< FEMSig >::OutOfBounds( depth , offset[0] ) || _IsOutOfBounds( UIntPack< FEMSigs ... >() , depth , offset+1 ); + } + template< unsigned int FEMSig , unsigned int ... FEMSigs > + static typename std::enable_if< sizeof ... ( FEMSigs )==0 >::type _BSplineBegin( UIntPack< FEMSig , FEMSigs ... > , unsigned int depth , int begin[] ) + { + begin[0] = BSplineEvaluationData< FEMSig >::Begin( depth ); + } + template< unsigned int FEMSig , unsigned int ... FEMSigs > + static typename std::enable_if< sizeof ... ( FEMSigs )!=0 >::type _BSplineBegin( UIntPack< FEMSig , FEMSigs ... > , unsigned int depth , int begin[] ) + { + begin[0] = BSplineEvaluationData< FEMSig >::Begin( depth ) ; _BSplineBegin( UIntPack< FEMSigs ... >() , depth , begin+1 ); + } + template< unsigned int FEMSig , unsigned int ... FEMSigs > + static typename std::enable_if< sizeof ... ( FEMSigs )==0 >::type _BSplineEnd( UIntPack< FEMSig , FEMSigs ... > , unsigned int depth , int end[] ) + { + end[0] = BSplineEvaluationData< FEMSig >::End( depth ); + } + template< unsigned int FEMSig , unsigned int ... FEMSigs > + static typename std::enable_if< sizeof ... ( FEMSigs )!=0 >::type _BSplineEnd( UIntPack< FEMSig , FEMSigs ... > , unsigned int depth , int end[] ) + { + end[0] = BSplineEvaluationData< FEMSig >::End( depth ) ; _BSplineEnd( UIntPack< FEMSigs ... >() , depth , end+1 ); + } + template< unsigned int FEMSig , unsigned int ... FEMSigs > + static typename std::enable_if< sizeof ... ( FEMSigs )==0 , double >::type _Integral( UIntPack< FEMSig , FEMSigs ... > , unsigned int depth , const int offset[] , const double begin[] , const double end[] ) + { + return BSplineEvaluationData< FEMSig >::Integral( depth , offset[0] , begin[0] , end[0] , 0 ); + } + template< unsigned int FEMSig , unsigned int ... FEMSigs > + static typename std::enable_if< sizeof ... ( FEMSigs )!=0 , double >::type _Integral( UIntPack< FEMSig , FEMSigs ... > , unsigned int depth , const int offset[] , const double begin[] , const double end[] ) + { + return BSplineEvaluationData< FEMSig >::Integral( depth , offset[0] , begin[0] , end[0] , 0 ) * _Integral( UIntPack< FEMSigs ... >() , depth , offset+1 , begin+1 , end+1 ); + } + public: + template< unsigned int ... FEMSigs > + static double Integral( UIntPack< FEMSigs ... > , int depth , const int offset[] , const double begin[] , const double end[] ) + { + if( depth<0 ) return 0; + else return _Integral( UIntPack< FEMSigs ... >() , depth , offset , begin , end ); + } + template< unsigned int ... FEMSigs > static bool IsValidFEMNode( UIntPack< FEMSigs ... > , int depth , const int offset[] ){ return _IsValidFEMNode( UIntPack< FEMSigs ... >() , depth , offset ); } + template< unsigned int ... FEMSigs > static bool IsOutOfBounds( UIntPack< FEMSigs ... > , int depth , const int offset[] ){ return depth<0 || _IsOutOfBounds( UIntPack< FEMSigs ... >() , depth , offset ); } + template< unsigned int ... FEMSigs > static void BSplineBegin( UIntPack< FEMSigs ... > , int depth , int begin[] ){ if( depth>=0 ) _BSplineBegin( UIntPack< FEMSigs ... >() , depth , begin ); } + template< unsigned int ... FEMSigs > static void BSplineEnd ( UIntPack< FEMSigs ... > , int depth , int end [] ){ if( depth>=0 ) _BSplineEnd ( UIntPack< FEMSigs ... >() , depth , end ); } + + template< typename TSignatures , typename TDerivatives > struct System{}; + template< typename TSignatures , typename TDerivatives , typename CSignatures , typename CDerivatives , unsigned int CDim > struct Constraint{}; + template< typename TSignatures , typename TDerivatives , typename CSignatures , typename CDerivatives > struct ScalarConstraint{}; + template< typename TSignatures > struct RestrictionProlongation{}; + template< typename TSignatures , typename TDerivatives > struct PointEvaluator{}; + template< typename TSignatures , typename TDerivatives > struct PointEvaluatorState{}; + + template< unsigned int ... TSignatures , unsigned int ... TDs > + struct PointEvaluatorState< UIntPack< TSignatures ... > , UIntPack< TDs ... > > : public BaseFEMIntegrator::template PointEvaluatorState< sizeof ... ( TSignatures ) > + { + static_assert( sizeof...(TSignatures)==sizeof...(TDs) , "[ERROR] Degree and derivative dimensions don't match" ); + static_assert( UIntPack< FEMSignature< TSignatures >::Degree ... >::template Compare< UIntPack< TDs ... > >::GreaterThanOrEqual , "[ERROR] PointEvaluatorState: More derivatives than degrees" ); -///////////////////////////////////////////////// -// An implementation of the virtual integrator // -///////////////////////////////////////////////// -struct FEMIntegrator -{ -protected: - template< unsigned int FEMSig , unsigned int ... FEMSigs > - static typename std::enable_if< sizeof ... ( FEMSigs )==0 , bool >::type _IsValidFEMNode( UIntPack< FEMSig , FEMSigs ... > , unsigned int depth , const int offset[] ) - { - return !BSplineEvaluationData< FEMSig >::OutOfBounds( depth , offset[0] ); - } - template< unsigned int FEMSig , unsigned int ... FEMSigs > - static typename std::enable_if< sizeof ... ( FEMSigs )!=0 , bool >::type _IsValidFEMNode( UIntPack< FEMSig , FEMSigs ... > , unsigned int depth , const int offset[] ) - { - return !BSplineEvaluationData< FEMSig >::OutOfBounds( depth , offset[0] ) && _IsValidFEMNode( UIntPack< FEMSigs ... >() , depth , offset+1 ); - } - template< unsigned int FEMSig , unsigned ... FEMSigs > - static typename std::enable_if< sizeof ... ( FEMSigs )==0 , bool >::type _IsOutOfBounds( UIntPack< FEMSig , FEMSigs ... > , unsigned int depth , const int offset[] ) - { - return BSplineEvaluationData< FEMSig >::OutOfBounds( depth , offset[0] ); - } - template< unsigned int FEMSig , unsigned ... FEMSigs > - static typename std::enable_if< sizeof ... ( FEMSigs )!=0 , bool >::type _IsOutOfBounds( UIntPack< FEMSig , FEMSigs ... > , unsigned int depth , const int offset[] ) - { - return BSplineEvaluationData< FEMSig >::OutOfBounds( depth , offset[0] ) || _IsOutOfBounds( UIntPack< FEMSigs ... >() , depth , offset+1 ); - } - template< unsigned int FEMSig , unsigned int ... FEMSigs > - static typename std::enable_if< sizeof ... ( FEMSigs )==0 >::type _BSplineBegin( UIntPack< FEMSig , FEMSigs ... > , unsigned int depth , int begin[] ) - { - begin[0] = BSplineEvaluationData< FEMSig >::Begin( depth ); - } - template< unsigned int FEMSig , unsigned int ... FEMSigs > - static typename std::enable_if< sizeof ... ( FEMSigs )!=0 >::type _BSplineBegin( UIntPack< FEMSig , FEMSigs ... > , unsigned int depth , int begin[] ) - { - begin[0] = BSplineEvaluationData< FEMSig >::Begin( depth ) ; _BSplineBegin( UIntPack< FEMSigs ... >() , depth , begin+1 ); - } - template< unsigned int FEMSig , unsigned int ... FEMSigs > - static typename std::enable_if< sizeof ... ( FEMSigs )==0 >::type _BSplineEnd( UIntPack< FEMSig , FEMSigs ... > , unsigned int depth , int end[] ) - { - end[0] = BSplineEvaluationData< FEMSig >::End( depth ); - } - template< unsigned int FEMSig , unsigned int ... FEMSigs > - static typename std::enable_if< sizeof ... ( FEMSigs )!=0 >::type _BSplineEnd( UIntPack< FEMSig , FEMSigs ... > , unsigned int depth , int end[] ) - { - end[0] = BSplineEvaluationData< FEMSig >::End( depth ) ; _BSplineEnd( UIntPack< FEMSigs ... >() , depth , end+1 ); - } - template< unsigned int FEMSig , unsigned int ... FEMSigs > - static typename std::enable_if< sizeof ... ( FEMSigs )==0 , double >::type _Integral( UIntPack< FEMSig , FEMSigs ... > , unsigned int depth , const int offset[] , const double begin[] , const double end[] ) - { - return BSplineEvaluationData< FEMSig >::Integral( depth , offset[0] , begin[0] , end[0] , 0 ); - } - template< unsigned int FEMSig , unsigned int ... FEMSigs > - static typename std::enable_if< sizeof ... ( FEMSigs )!=0 , double >::type _Integral( UIntPack< FEMSig , FEMSigs ... > , unsigned int depth , const int offset[] , const double begin[] , const double end[] ) - { - return BSplineEvaluationData< FEMSig >::Integral( depth , offset[0] , begin[0] , end[0] , 0 ) * _Integral( UIntPack< FEMSigs ... >() , depth , offset+1 , begin+1 , end+1 ); - } -public: - template< unsigned int ... FEMSigs > - static double Integral( UIntPack< FEMSigs ... > , int depth , const int offset[] , const double begin[] , const double end[] ) - { - if( depth<0 ) return 0; - else return _Integral( UIntPack< FEMSigs ... >() , depth , offset , begin , end ); - } - template< unsigned int ... FEMSigs > static bool IsValidFEMNode( UIntPack< FEMSigs ... > , int depth , const int offset[] ){ return _IsValidFEMNode( UIntPack< FEMSigs ... >() , depth , offset ); } - template< unsigned int ... FEMSigs > static bool IsOutOfBounds( UIntPack< FEMSigs ... > , int depth , const int offset[] ){ return depth<0 || _IsOutOfBounds( UIntPack< FEMSigs ... >() , depth , offset ); } - template< unsigned int ... FEMSigs > static void BSplineBegin( UIntPack< FEMSigs ... > , int depth , int begin[] ){ if( depth>=0 ) _BSplineBegin( UIntPack< FEMSigs ... >() , depth , begin ); } - template< unsigned int ... FEMSigs > static void BSplineEnd ( UIntPack< FEMSigs ... > , int depth , int end [] ){ if( depth>=0 ) _BSplineEnd ( UIntPack< FEMSigs ... >() , depth , end ); } - - template< typename TSignatures , typename TDerivatives > struct System{}; - template< typename TSignatures , typename TDerivatives , typename CSignatures , typename CDerivatives , unsigned int CDim > struct Constraint{}; - template< typename TSignatures , typename TDerivatives , typename CSignatures , typename CDerivatives > struct ScalarConstraint{}; - template< typename TSignatures > struct RestrictionProlongation{}; - template< typename TSignatures , typename TDerivatives > struct PointEvaluator{}; - template< typename TSignatures , typename TDerivatives > struct PointEvaluatorState{}; - - template< unsigned int ... TSignatures , unsigned int ... TDs > - struct PointEvaluatorState< UIntPack< TSignatures ... > , UIntPack< TDs ... > > : public BaseFEMIntegrator::template PointEvaluatorState< sizeof ... ( TSignatures ) > - { - static_assert( sizeof...(TSignatures)==sizeof...(TDs) , "[ERROR] Degree and derivative dimensions don't match" ); - static_assert( UIntPack< FEMSignature< TSignatures >::Degree ... >::template Compare< UIntPack< TDs ... > >::GreaterThanOrEqual , "[ERROR] PointEvaluatorState: More derivatives than degrees" ); + static const unsigned int Dim = sizeof...(TSignatures); - static const unsigned int Dim = sizeof...(TSignatures); + double value ( const int offset[] , const unsigned int derivatives[] ) const { return _value< Dim >( offset , derivatives ); } + double subValue( const int offset[] , const unsigned int derivatives[] ) const { return _value< Dim-1 >( offset , derivatives ); } + // Bypassing the "auto" keyword + template< unsigned int _Dim > + const double (*(values)( void ) const )[ UIntPack< TDs ... >::template Get< _Dim >()+1 ] { return std::template get< _Dim >( _oneDValues ).values; } + protected: + int _pointOffset[Dim]; - double value ( const int offset[] , const unsigned int derivatives[] ) const { return _value< Dim >( offset , derivatives ); } - double subValue( const int offset[] , const unsigned int derivatives[] ) const { return _value< Dim-1 >( offset , derivatives ); } - // Bypassing the "auto" keyword - template< unsigned int _Dim > - const double (*(values)( void ) const )[ UIntPack< TDs ... >::template Get< _Dim >()+1 ] { return std::template get< _Dim >( _oneDValues ).values; } - protected: - int _pointOffset[Dim]; + template< unsigned int Degree , unsigned int D > struct _OneDValues + { + double values[ BSplineSupportSizes< Degree >::SupportSize ][ D+1 ]; + double value( int dOff , unsigned int d ) const + { + if( dOff>=-BSplineSupportSizes< Degree >::SupportEnd && dOff<=-BSplineSupportSizes< Degree >::SupportStart && d<=D ) return values[ dOff+BSplineSupportSizes< Degree >::SupportEnd][d]; + else return 0; + } + }; + std::tuple< _OneDValues< FEMSignature< TSignatures >::Degree , TDs > ... > _oneDValues; + template< unsigned int MaxDim=Dim , unsigned int I=0 > typename std::enable_if< I==MaxDim , double >::type _value( const int off[] , const unsigned int d[] ) const { return 1.; } + template< unsigned int MaxDim=Dim , unsigned int I=0 > typename std::enable_if< I!=MaxDim , double >::type _value( const int off[] , const unsigned int d[] ) const { return std::get< I >( _oneDValues ).value( off[I]-_pointOffset[I] , d[I] ) * _value< MaxDim , I+1 >( off , d ); } + template< typename T1 , typename T2 > friend struct PointEvaluator; + }; - template< unsigned int Degree , unsigned int D > struct _OneDValues + template< unsigned int ... TSignatures , unsigned int ... TDs > + struct PointEvaluator< UIntPack< TSignatures ... > , UIntPack< TDs ... > > : public BaseFEMIntegrator::template PointEvaluator< UIntPack< FEMSignature< TSignatures >::Degree ... > > { - double values[ BSplineSupportSizes< Degree >::SupportSize ][ D+1 ]; - double value( int dOff , unsigned int d ) const + static_assert( sizeof...(TSignatures)==sizeof...(TDs) , "[ERROR] PointEvaluator: Degree and derivative dimensions don't match" ); + static_assert( UIntPack< FEMSignature< TSignatures >::Degree ... >::template Compare< UIntPack< TDs ... > >::GreaterThanOrEqual , "[ERROR] PointEvaluator: More derivatives than degrees" ); + + static const unsigned int Dim = sizeof ... ( TSignatures ); + + typedef typename BaseFEMIntegrator::template PointEvaluator< UIntPack< FEMSignature< TSignatures >::Degree ... > > Base; + + PointEvaluator( unsigned int maxDepth ) : _maxDepth( maxDepth ) { _init(); } + template< unsigned int ... EDs > + void initEvaluationState( Point< double , Dim > p , unsigned int depth , PointEvaluatorState< UIntPack< TSignatures ... > , UIntPack< EDs ... > >& state ) const + { + unsigned int res = 1< + void initEvaluationState( Point< double , Dim > p , unsigned int depth , const int* offset , PointEvaluatorState< UIntPack< TSignatures ... > , UIntPack< EDs ... > >& state ) const { - if( dOff>=-BSplineSupportSizes< Degree >::SupportEnd && dOff<=-BSplineSupportSizes< Degree >::SupportStart && d<=D ) return values[ dOff+BSplineSupportSizes< Degree >::SupportEnd][d]; - else return 0; + static_assert( UIntPack< TDs ... >::template Compare< UIntPack< EDs ... > >::GreaterThanOrEqual , "[ERROR] PointEvaluator::init: More evaluation derivatives than stored derivatives" ); + for( int d=0 ; d() , UIntPack< EDs ... >() , &p[0] , depth , state ); + } + protected: + unsigned int _maxDepth; + std::tuple< BSplineData< TSignatures , TDs > ... > _bSplineData; + template< unsigned int I=0 > typename std::enable_if< I==Dim >::type _init( void ){} + template< unsigned int I=0 > typename std::enable_if< I< Dim >::type _init( void ){ std::get< I >( _bSplineData ).reset( _maxDepth ) ; _init< I+1 >( ); } + + template< unsigned int I , unsigned int TSig , unsigned int D , typename State > + void _setEvaluationState( const double* p , unsigned int depth , State& state ) const + { + static const int LeftSupportRadius = -BSplineSupportSizes< FEMSignature< TSig >::Degree >::SupportStart; + static const int LeftPointSupportRadius = BSplineSupportSizes< FEMSignature< TSig >::Degree >::SupportEnd ; + static const int RightSupportRadius = BSplineSupportSizes< FEMSignature< TSig >::Degree >::SupportEnd ; + static const int RightPointSupportRadius = -BSplineSupportSizes< FEMSignature< TSig >::Degree >::SupportStart; + for( int s=-LeftPointSupportRadius ; s<=RightPointSupportRadius ; s++ ) + { + int pIdx = state._pointOffset[I]; + int fIdx = state._pointOffset[I]+s; + double _p = p[I]; + const Polynomial< FEMSignature< TSig >::Degree >* components = std::get< I >( _bSplineData )[depth].polynomialsAndOffset( _p , pIdx , fIdx ); + for( int d=0 ; d<=D ; d++ ) std::get< I >( state._oneDValues ).values[ s+LeftPointSupportRadius ][d] = components[d]( _p ); + } + } + template< typename State , unsigned int TSig , unsigned int ... TSigs , unsigned int D , unsigned int ... Ds > + typename std::enable_if< sizeof...(TSigs)==0 >::type _initEvaluationState( UIntPack< TSig , TSigs ... > , UIntPack< D , Ds ... > , const double* p , unsigned int depth , State& state ) const + { + _setEvaluationState< Dim-1 , TSig , D >( p , depth , state ); + } + template< typename State , unsigned int TSig , unsigned int ... TSigs , unsigned int D , unsigned int ... Ds > + typename std::enable_if< sizeof...(TSigs)!=0 >::type _initEvaluationState( UIntPack< TSig , TSigs ... > , UIntPack< D , Ds ... > , const double* p , unsigned int depth , State& state ) const + { + _setEvaluationState< Dim-1-sizeof...(TSigs) , TSig , D >( p , depth , state ); + _initEvaluationState( UIntPack< TSigs ... >() , UIntPack< Ds ... >() , p , depth , state ); } }; - std::tuple< _OneDValues< FEMSignature< TSignatures >::Degree , TDs > ... > _oneDValues; - template< unsigned int MaxDim=Dim , unsigned int I=0 > typename std::enable_if< I==MaxDim , double >::type _value( const int off[] , const unsigned int d[] ) const { return 1.; } - template< unsigned int MaxDim=Dim , unsigned int I=0 > typename std::enable_if< I!=MaxDim , double >::type _value( const int off[] , const unsigned int d[] ) const { return std::get< I >( _oneDValues ).value( off[I]-_pointOffset[I] , d[I] ) * _value< MaxDim , I+1 >( off , d ); } - template< typename T1 , typename T2 > friend struct PointEvaluator; + + template< unsigned int ... TSignatures > + struct RestrictionProlongation< UIntPack< TSignatures ... > > : public BaseFEMIntegrator::template RestrictionProlongation< UIntPack< FEMSignature< TSignatures >::Degree ... > > + { + static const unsigned int Dim = sizeof ... ( TSignatures ); + typedef typename BaseFEMIntegrator::template RestrictionProlongation< UIntPack< FEMSignature< TSignatures >::Degree ... > > Base; + + double upSampleCoefficient( const int pOff[] , const int cOff[] ) const { return _coefficient( pOff , cOff ); } + void init( unsigned int depth ){ Base::init( depth ); } + void init( void ){ _init( Base::highDepth() ); } + + protected: + std::tuple< typename BSplineEvaluationData< TSignatures >::UpSampleEvaluator ... > _upSamplers; + + template< unsigned int D=0 > typename std::enable_if< D==Dim >::type _init( int highDepth ){ } + template< unsigned int D=0 > typename std::enable_if< D< Dim >::type _init( int highDepth ){ std::get< D >( _upSamplers ).set( highDepth-1 ) ; _init< D+1 >( highDepth ); } + template< unsigned int D=0 > typename std::enable_if< D==Dim , double >::type _coefficient( const int pOff[] , const int cOff[] ) const { return 1.; } + template< unsigned int D=0 > typename std::enable_if< D< Dim , double >::type _coefficient( const int pOff[] , const int cOff[] ) const { return _coefficient< D+1 >( pOff , cOff ) * std::get< D >( _upSamplers ).value( pOff[D] , cOff[D] ); } + }; + + template< unsigned int ... TSignatures , unsigned int ... TDerivatives , unsigned int ... CSignatures , unsigned int ... CDerivatives , unsigned int CDim > + struct Constraint< UIntPack< TSignatures ... > , UIntPack< TDerivatives ... > , UIntPack< CSignatures ... > , UIntPack< CDerivatives ... > , CDim > : public BaseFEMIntegrator::template Constraint< UIntPack< FEMSignature< TSignatures >::Degree ... > , UIntPack< FEMSignature< CSignatures >::Degree ... > , CDim > + { + static_assert( sizeof ... ( TSignatures ) == sizeof ... ( CSignatures ) , "[ERROR] Test signatures and contraint signatures must have the same dimension" ); + static_assert( sizeof ... ( TSignatures ) == sizeof ... ( TDerivatives ) , "[ERROR] Test signatures and derivatives must have the same dimension" ); + static_assert( sizeof ... ( CSignatures ) == sizeof ... ( CDerivatives ) , "[ERROR] Constraint signatures and derivatives must have the same dimension" ); + static_assert( UIntPack< FEMSignature< TSignatures >::Degree ... >::template Compare< UIntPack< TDerivatives ... > >::GreaterThanOrEqual , "[ERROR] Test functions cannot have more derivatives than the degree" ); + static_assert( UIntPack< FEMSignature< CSignatures >::Degree ... >::template Compare< UIntPack< CDerivatives ... > >::GreaterThanOrEqual , "[ERROR] Test functions cannot have more derivatives than the degree" ); + + static const unsigned int Dim = sizeof ... ( TSignatures ); + typedef typename BaseFEMIntegrator::template Constraint< UIntPack< FEMSignature< TSignatures >::Degree ... > , UIntPack< FEMSignature< CSignatures >::Degree ... > , CDim > Base; + + static const unsigned int TDerivativeSize = TensorDerivatives< UIntPack< TDerivatives ... > >::Size; + static const unsigned int CDerivativeSize = TensorDerivatives< UIntPack< CDerivatives ... > >::Size; + static inline void TFactorDerivatives( unsigned int idx , unsigned int d[ Dim ] ){ TensorDerivatives< UIntPack< TDerivatives ... > >::Factor( idx , d ); } + static inline void CFactorDerivatives( unsigned int idx , unsigned int d[ Dim ] ){ TensorDerivatives< UIntPack< CDerivatives ... > >::Factor( idx , d ); } + static inline unsigned int TDerivativeIndex( const unsigned int d[ Dim ] ){ return TensorDerivatives< UIntPack< TDerivatives ... > >::Index( d ); } + static inline unsigned int CDerivativeIndex( const unsigned int d[ Dim ] ){ return TensorDerivatives< UIntPack< CDerivatives ... > >::Index( d ); } + Matrix< double , TDerivativeSize , CDerivativeSize > weights[CDim]; + + Point< double , CDim > ccIntegrate( const int off1[] , const int off2[] ) const { return _integrate( INTEGRATE_CHILD_CHILD , off1 , off2 ); } + Point< double , CDim > pcIntegrate( const int off1[] , const int off2[] ) const { return _integrate( INTEGRATE_PARENT_CHILD , off1 , off2 ); } + Point< double , CDim > cpIntegrate( const int off1[] , const int off2[] ) const { return _integrate( INTEGRATE_CHILD_PARENT , off1 , off2 ); } + + void init( unsigned int depth ){ Base::init( depth ); } + void init( void ) + { + + _init( Base::highDepth() ); + _weightedIndices.resize(0); + for( unsigned int d1=0 ; d10 ) w.indices.push_back( std::pair< unsigned int , double >( c , weights[c](d1,d2) ) ); + if( w.indices.size() ) _weightedIndices.push_back(w); + } + } + typename BaseFEMIntegrator::template RestrictionProlongation< UIntPack< FEMSignature< TSignatures >::Degree ... > >& tRestrictionProlongation( void ){ return _tRestrictionProlongation; } + typename BaseFEMIntegrator::template RestrictionProlongation< UIntPack< FEMSignature< CSignatures >::Degree ... > >& cRestrictionProlongation( void ){ return _cRestrictionProlongation; } + protected: + RestrictionProlongation< UIntPack< TSignatures ... > > _tRestrictionProlongation; + RestrictionProlongation< UIntPack< CSignatures ... > > _cRestrictionProlongation; + struct _WeightedIndices + { + _WeightedIndices( unsigned int _d1=0 , unsigned int _d2=0 ) : d1(_d1) , d2(_d2) { ; } + unsigned int d1 , d2; + std::vector< std::pair< unsigned int , double > > indices; + }; + std::vector< _WeightedIndices > _weightedIndices; + enum IntegrationType + { + INTEGRATE_CHILD_CHILD , + INTEGRATE_PARENT_CHILD , + INTEGRATE_CHILD_PARENT + }; + + template< unsigned int _TSig , unsigned int _TDerivatives , unsigned int _CSig , unsigned int _CDerivatives > + struct _Integrators + { + typename BSplineIntegrationData< _TSig , _CSig >::FunctionIntegrator::template Integrator< _TDerivatives , _CDerivatives > ccIntegrator; + typename BSplineIntegrationData< _TSig , _CSig >::FunctionIntegrator::template ChildIntegrator< _TDerivatives , _CDerivatives > pcIntegrator; + typename BSplineIntegrationData< _CSig , _TSig >::FunctionIntegrator::template ChildIntegrator< _CDerivatives , _TDerivatives > cpIntegrator; + }; + std::tuple< _Integrators< TSignatures , TDerivatives , CSignatures , CDerivatives > ... > _integrators; + + template< unsigned int D=0 > + typename std::enable_if< D==Dim >::type _init( int depth ){ ; } + template< unsigned int D=0 > + typename std::enable_if< D< Dim >::type _init( int depth ) + { + std::get< D >( _integrators ).ccIntegrator.set( depth ); + if( depth ) std::get< D >( _integrators ).pcIntegrator.set( depth-1 ) , std::get< D >( _integrators ).cpIntegrator.set( depth-1 ); + _init< D+1 >( depth ); + } + template< unsigned int D=0 > + typename std::enable_if< D==Dim , double >::type _integral( IntegrationType iType , const int off1[] , const int off2[] , const unsigned int d1[] , const unsigned int d2[] ) const { return 1.; } + template< unsigned int D=0 > + typename std::enable_if< D< Dim , double >::type _integral( IntegrationType iType , const int off1[] , const int off2[] , const unsigned int d1[] , const unsigned int d2[] ) const + { + double remainingIntegral = _integral< D+1 >( iType , off1 , off2 , d1 , d2 ); + switch( iType ) + { + case INTEGRATE_CHILD_CHILD: return std::get< D >( _integrators ).ccIntegrator.dot( off1[D] , off2[D] , d1[D] , d2[D] ) * remainingIntegral; + case INTEGRATE_PARENT_CHILD: return std::get< D >( _integrators ).pcIntegrator.dot( off1[D] , off2[D] , d1[D] , d2[D] ) * remainingIntegral; + case INTEGRATE_CHILD_PARENT: return std::get< D >( _integrators ).cpIntegrator.dot( off2[D] , off1[D] , d2[D] , d1[D] ) * remainingIntegral; + default: ERROR_OUT( "Undefined integration type" ); + } + return 0; + } + Point< double , CDim > _integrate( IntegrationType iType , const int off1[] , const int off[] ) const; + }; + + template< unsigned int ... TSignatures , unsigned int ... TDerivatives , unsigned int ... CSignatures , unsigned int ... CDerivatives > + struct ScalarConstraint< UIntPack< TSignatures ... > , UIntPack< TDerivatives ... > , UIntPack< CSignatures ... > , UIntPack< CDerivatives ... > > : public Constraint< UIntPack< TSignatures ... > , UIntPack< TDerivatives ... > , UIntPack< CSignatures ... > , UIntPack< CDerivatives ... > , 1 > + { + static const unsigned int Dim = sizeof ... ( TSignatures ); + typedef typename BaseFEMIntegrator::template Constraint< UIntPack< FEMSignature< TSignatures >::Degree ... > , UIntPack< FEMSignature< CSignatures >::Degree ... > , 1 > Base; + + typedef Constraint< UIntPack< TSignatures ... > , UIntPack< TDerivatives ... > , UIntPack< CSignatures ... > , UIntPack< CDerivatives ... > , 1 > FullConstraint; + using FullConstraint::weights; + // [NOTE] We define the constructor using a recursive function call to take into account multiplicity (e.g. so that d^2/dxdy and d^2/dydx each contribute) + ScalarConstraint( const std::initializer_list< double >& w ) + { + std::function< void ( unsigned int[] , const double[] , unsigned int ) > SetDerivativeWeights = [&]( unsigned int derivatives[Dim] , const double w[] , unsigned int d ) + { + unsigned int idx1 = FullConstraint::TDerivativeIndex( derivatives ) , idx2 = FullConstraint::CDerivativeIndex( derivatives ); + weights[0][idx1][idx2] += w[0]; + if( d>0 ) for( int dd=0 ; dd( UIntPack< TDerivatives ... >::Min() , UIntPack< CDerivatives ... >::Min() ); + + unsigned int derivatives[Dim]; + double _w[DMax+1]; + memset( _w , 0 , sizeof(_w) ); + { + unsigned int dd=0; + for( typename std::initializer_list< double >::const_iterator iter=w.begin() ; iter!=w.end() && dd<=DMax ; dd++ , iter++ ) _w[dd] = *iter; + } + for( int d=0 ; d( DMax+1 , (unsigned int)w.size() )-1 ); + } + }; + + template< unsigned int ... TSignatures , unsigned int ... TDerivatives > + struct System< UIntPack< TSignatures ... > , UIntPack< TDerivatives ... > > : public BaseFEMIntegrator::template System< UIntPack< FEMSignature< TSignatures >::Degree... > > + { + static_assert( sizeof ... ( TSignatures ) == sizeof ... ( TDerivatives ) , "[ERROR] Test signatures and derivatives must have the same dimension" ); + + static const unsigned int Dim = sizeof ... ( TSignatures ); + typedef typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< TSignatures >::Degree... > > Base; + + System( const std::initializer_list< double >& w ) : _sc( w ){ ; } + void init( unsigned int depth ){ Base::init( depth ); } + void init( void ){ ( (BaseFEMIntegrator::template Constraint< UIntPack< FEMSignature< TSignatures >::Degree ... > , UIntPack< FEMSignature< TSignatures >::Degree ... > , 1 >&)_sc ).init( BaseFEMIntegrator::template System< UIntPack< FEMSignature< TSignatures >::Degree... > >::_highDepth ); } + double ccIntegrate( const int off1[] , const int off2[] ) const { return _sc.ccIntegrate( off1 , off2 )[0]; } + double pcIntegrate( const int off1[] , const int off2[] ) const { return _sc.pcIntegrate( off1 , off2 )[0]; } + bool vanishesOnConstants( void ) const { return _sc.weights[0][0][0]==0; } + + typename BaseFEMIntegrator::template RestrictionProlongation< UIntPack< FEMSignature< TSignatures >::Degree ... > >& restrictionProlongation( void ){ return _sc.tRestrictionProlongation(); } + + protected: + ScalarConstraint< UIntPack< TSignatures ... > , UIntPack< TDerivatives ... > , UIntPack< TSignatures ... > , UIntPack< TDerivatives ... > > _sc; + }; }; - template< unsigned int ... TSignatures , unsigned int ... TDs > - struct PointEvaluator< UIntPack< TSignatures ... > , UIntPack< TDs ... > > : public BaseFEMIntegrator::template PointEvaluator< UIntPack< FEMSignature< TSignatures >::Degree ... > > + ////////////////////////////////////////// + + template< unsigned int Dim > inline void SetGhostFlag( RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node , bool flag ){ if( node && node->parent ) node->parent->nodeData.setGhostFlag( flag ); } + template< unsigned int Dim > inline bool GetGhostFlag( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ){ return node==NULL || node->parent==NULL || node->parent->nodeData.getGhostFlag( ); } + template< unsigned int Dim > inline bool IsActiveNode( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ){ return !GetGhostFlag( node ); } + + // A class representing an extractot with and without auxiliary data + template< typename Real , unsigned int Dim , typename ... Params > struct LevelSetExtractor; + + // A helper class which consolidates the two extractors, templated over HasData + template< bool HasData , typename Real , unsigned int Dim , typename Data > struct _LevelSetExtractor; + + template< unsigned int Dim , class Data > + struct NodeSample + { + RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *node; + Data data; + }; + template< unsigned int Dim , class Real > + struct NodeAndPointSample { - static_assert( sizeof...(TSignatures)==sizeof...(TDs) , "[ERROR] PointEvaluator: Degree and derivative dimensions don't match" ); - static_assert( UIntPack< FEMSignature< TSignatures >::Degree ... >::template Compare< UIntPack< TDs ... > >::GreaterThanOrEqual , "[ERROR] PointEvaluator: More derivatives than degrees" ); + RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *node; + ProjectiveData< Point< Real , Dim > , Real > sample; + }; + template< unsigned int Dim , class Real > using NodeSimplices = NodeSample< Dim , std::vector< std::pair< node_index_type , Simplex< Real , Dim , Dim-1 > > > >; - static const unsigned int Dim = sizeof ... ( TSignatures ); - typedef typename BaseFEMIntegrator::template PointEvaluator< UIntPack< FEMSignature< TSignatures >::Degree ... > > Base; + template< typename T > struct WindowLoopData{ }; - PointEvaluator( unsigned int maxDepth ) : _maxDepth( maxDepth ) { _init(); } - template< unsigned int ... EDs > - void initEvaluationState( Point< double , Dim > p , unsigned int depth , PointEvaluatorState< UIntPack< TSignatures ... > , UIntPack< EDs ... > >& state ) const - { - unsigned int res = 1< - void initEvaluationState( Point< double , Dim > p , unsigned int depth , const int* offset , PointEvaluatorState< UIntPack< TSignatures ... > , UIntPack< EDs ... > >& state ) const + template< unsigned int ... Sizes > + struct WindowLoopData< UIntPack< Sizes ... > > + { + static const int Dim = sizeof ... ( Sizes ); + unsigned int size[1< >::Size ]; + template< typename BoundsFunction > + WindowLoopData( const BoundsFunction &boundsFunction ) { - static_assert( UIntPack< TDs ... >::template Compare< UIntPack< EDs ... > >::GreaterThanOrEqual , "[ERROR] PointEvaluator::init: More evaluation derivatives than stored derivatives" ); - for( int d=0 ; d() , UIntPack< EDs ... >() , &p[0] , depth , state ); - } - protected: - unsigned int _maxDepth; - std::tuple< BSplineData< TSignatures , TDs > ... > _bSplineData; - template< unsigned int I=0 > typename std::enable_if< I==Dim >::type _init( void ){} - template< unsigned int I=0 > typename std::enable_if< I< Dim >::type _init( void ){ std::get< I >( _bSplineData ).reset( _maxDepth ) ; _init< I+1 >( ); } - - template< unsigned int I , unsigned int TSig , unsigned int D , typename State > - void _setEvaluationState( const double* p , unsigned int depth , State& state ) const - { - static const int LeftSupportRadius = -BSplineSupportSizes< FEMSignature< TSig >::Degree >::SupportStart; - static const int LeftPointSupportRadius = BSplineSupportSizes< FEMSignature< TSig >::Degree >::SupportEnd ; - static const int RightSupportRadius = BSplineSupportSizes< FEMSignature< TSig >::Degree >::SupportEnd ; - static const int RightPointSupportRadius = -BSplineSupportSizes< FEMSignature< TSig >::Degree >::SupportStart; - for( int s=-LeftPointSupportRadius ; s<=RightPointSupportRadius ; s++ ) + int start[Dim] , end[Dim]; + for( int c=0 ; c<(1<::Degree >* components = std::get< I >( _bSplineData )[depth].polynomialsAndOffset( _p , pIdx , fIdx ); - for( int d=0 ; d<=D ; d++ ) std::get< I >( state._oneDValues ).values[ s+LeftPointSupportRadius ][d] = components[d]( _p ); + size[c] = 0; + boundsFunction( c , start , end ); + unsigned int idx[Dim]; + WindowLoop< Dim >::Run + ( + start , end , + [&]( int d , int i ){ idx[d] = i; } , + [&]( void ){ indices[c][ size[c]++ ] = GetWindowIndex( UIntPack< Sizes ... >() , idx ); } + ); } } - template< typename State , unsigned int TSig , unsigned int ... TSigs , unsigned int D , unsigned int ... Ds > - typename std::enable_if< sizeof...(TSigs)==0 >::type _initEvaluationState( UIntPack< TSig , TSigs ... > , UIntPack< D , Ds ... > , const double* p , unsigned int depth , State& state ) const + }; + + template< class Real , unsigned int Dim > + void AddAtomic( Point< Real , Dim >& a , const Point< Real , Dim >& b ) + { + for( int d=0 ; d + bool IsZero( const Data& data ){ return false; } + template< class Real , unsigned int Dim > + bool IsZero( const Point< Real , Dim >& d ) + { + bool zero = true; + for( int i=0 ; i + class FEMTree + { + public: + typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; + template< unsigned int ... FEMSigs > using SystemMatrixType = SparseMatrix< Real , matrix_index_type , WindowSize< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >::Size >; + std::vector< Allocator< FEMTreeNode > * > nodeAllocators; + protected: + template< unsigned int _Dim , class _Real > friend class FEMTree; + struct SubTreeExtractor : public FEMTreeNode::SubTreeExtractor { - _setEvaluationState< Dim-1 , TSig , D >( p , depth , state ); - } - template< typename State , unsigned int TSig , unsigned int ... TSigs , unsigned int D , unsigned int ... Ds > - typename std::enable_if< sizeof...(TSigs)!=0 >::type _initEvaluationState( UIntPack< TSig , TSigs ... > , UIntPack< D , Ds ... > , const double* p , unsigned int depth , State& state ) const + SubTreeExtractor( FEMTreeNode &node , int &depthOffset ) : FEMTreeNode::SubTreeExtractor( node ) , _depthOffset( depthOffset ) + { + _depthOffsetValue = _depthOffset; + _depthOffset = 0; + } + SubTreeExtractor( FEMTreeNode *node , int &depthOffset ) : SubTreeExtractor( *node , depthOffset ){} + ~SubTreeExtractor( void ){ _depthOffset = _depthOffsetValue; } + protected: + int &_depthOffset , _depthOffsetValue; + }; + + // Don't need this first one + template< typename _Real , unsigned int _Dim , typename ... _Params > friend struct LevelSetExtractor; + template< bool _HasData , typename _Real , unsigned int _Dim , typename _Data > friend struct _LevelSetExtractor; + std::atomic< node_index_type > _nodeCount; + struct _NodeInitializer { - _setEvaluationState< Dim-1-sizeof...(TSigs) , TSig , D >( p , depth , state ); - _initEvaluationState( UIntPack< TSigs ... >() , UIntPack< Ds ... >() , p , depth , state ); - } - }; + FEMTree& femTree; + _NodeInitializer( FEMTree& f ) : femTree(f){;} + void operator() ( FEMTreeNode& node ){ node.nodeData.nodeIndex = femTree._nodeCount++; } + }; + _NodeInitializer _nodeInitializer; + public: + typedef int LocalDepth; + typedef int LocalOffset[Dim]; - template< unsigned int ... TSignatures > - struct RestrictionProlongation< UIntPack< TSignatures ... > > : public BaseFEMIntegrator::template RestrictionProlongation< UIntPack< FEMSignature< TSignatures >::Degree ... > > - { - static const unsigned int Dim = sizeof ... ( TSignatures ); - typedef typename BaseFEMIntegrator::template RestrictionProlongation< UIntPack< FEMSignature< TSignatures >::Degree ... > > Base; + node_index_type nodeCount( void ) const { return _nodeCount; } - double upSampleCoefficient( const int pOff[] , const int cOff[] ) const { return _coefficient( pOff , cOff ); } - void init( unsigned int depth ){ Base::init( depth ); } - void init( void ){ _init( Base::highDepth() ); } + typedef NodeAndPointSample< Dim , Real > PointSample; - protected: - std::tuple< typename BSplineEvaluationData< TSignatures >::UpSampleEvaluator ... > _upSamplers; + typedef typename FEMTreeNode::template NeighborKey< IsotropicUIntPack< Dim , 1 > , IsotropicUIntPack< Dim , 1 > > OneRingNeighborKey; + typedef typename FEMTreeNode::template ConstNeighborKey< IsotropicUIntPack< Dim , 1 > , IsotropicUIntPack< Dim , 1 > > ConstOneRingNeighborKey; + typedef typename FEMTreeNode::template Neighbors< IsotropicUIntPack< Dim , 3 > > OneRingNeighbors; + typedef typename FEMTreeNode::template ConstNeighbors< IsotropicUIntPack< Dim , 3 > > ConstOneRingNeighbors; - template< unsigned int D=0 > typename std::enable_if< D==Dim >::type _init( int highDepth ){ } - template< unsigned int D=0 > typename std::enable_if< D< Dim >::type _init( int highDepth ){ std::get< D >( _upSamplers ).set( highDepth-1 ) ; _init< D+1 >( highDepth ); } - template< unsigned int D=0 > typename std::enable_if< D==Dim , double >::type _coefficient( const int pOff[] , const int cOff[] ) const { return 1.; } - template< unsigned int D=0 > typename std::enable_if< D< Dim , double >::type _coefficient( const int pOff[] , const int cOff[] ) const { return _coefficient< D+1 >( pOff , cOff ) * std::get< D >( _upSamplers ).value( pOff[D] , cOff[D] ); } - }; + template< typename FEMDegreePack > using BaseSystem = typename BaseFEMIntegrator::template System< FEMDegreePack >; + template< typename FEMSigPack , typename DerivativePack > using PointEvaluator = typename FEMIntegrator::template PointEvaluator< FEMSigPack , DerivativePack >; + template< typename FEMSigPack , typename DerivativePack > using PointEvaluatorState = typename FEMIntegrator::template PointEvaluatorState< FEMSigPack , DerivativePack >; + template< typename FEMDegreePack > using CCStencil = typename BaseSystem< FEMDegreePack >::CCStencil; + template< typename FEMDegreePack > using PCStencils = typename BaseSystem< FEMDegreePack >::PCStencils; - template< unsigned int ... TSignatures , unsigned int ... TDerivatives , unsigned int ... CSignatures , unsigned int ... CDerivatives , unsigned int CDim > - struct Constraint< UIntPack< TSignatures ... > , UIntPack< TDerivatives ... > , UIntPack< CSignatures ... > , UIntPack< CDerivatives ... > , CDim > : public BaseFEMIntegrator::template Constraint< UIntPack< FEMSignature< TSignatures >::Degree ... > , UIntPack< FEMSignature< CSignatures >::Degree ... > , CDim > - { - static_assert( sizeof ... ( TSignatures ) == sizeof ... ( CSignatures ) , "[ERROR] Test signatures and contraint signatures must have the same dimension" ); - static_assert( sizeof ... ( TSignatures ) == sizeof ... ( TDerivatives ) , "[ERROR] Test signatures and derivatives must have the same dimension" ); - static_assert( sizeof ... ( CSignatures ) == sizeof ... ( CDerivatives ) , "[ERROR] Constraint signatures and derivatives must have the same dimension" ); - static_assert( UIntPack< FEMSignature< TSignatures >::Degree ... >::template Compare< UIntPack< TDerivatives ... > >::GreaterThanOrEqual , "[ERROR] Test functions cannot have more derivatives than the degree" ); - static_assert( UIntPack< FEMSignature< CSignatures >::Degree ... >::template Compare< UIntPack< CDerivatives ... > >::GreaterThanOrEqual , "[ERROR] Test functions cannot have more derivatives than the degree" ); - - static const unsigned int Dim = sizeof ... ( TSignatures ); - typedef typename BaseFEMIntegrator::template Constraint< UIntPack< FEMSignature< TSignatures >::Degree ... > , UIntPack< FEMSignature< CSignatures >::Degree ... > , CDim > Base; - - static const unsigned int TDerivativeSize = TensorDerivatives< UIntPack< TDerivatives ... > >::Size; - static const unsigned int CDerivativeSize = TensorDerivatives< UIntPack< CDerivatives ... > >::Size; - static inline void TFactorDerivatives( unsigned int idx , unsigned int d[ Dim ] ){ TensorDerivatives< UIntPack< TDerivatives ... > >::Factor( idx , d ); } - static inline void CFactorDerivatives( unsigned int idx , unsigned int d[ Dim ] ){ TensorDerivatives< UIntPack< CDerivatives ... > >::Factor( idx , d ); } - static inline unsigned int TDerivativeIndex( const unsigned int d[ Dim ] ){ return TensorDerivatives< UIntPack< TDerivatives ... > >::Index( d ); } - static inline unsigned int CDerivativeIndex( const unsigned int d[ Dim ] ){ return TensorDerivatives< UIntPack< CDerivatives ... > >::Index( d ); } - Matrix< double , TDerivativeSize , CDerivativeSize > weights[CDim]; - - Point< double , CDim > ccIntegrate( const int off1[] , const int off2[] ) const { return _integrate( INTEGRATE_CHILD_CHILD , off1 , off2 ); } - Point< double , CDim > pcIntegrate( const int off1[] , const int off2[] ) const { return _integrate( INTEGRATE_PARENT_CHILD , off1 , off2 ); } - Point< double , CDim > cpIntegrate( const int off1[] , const int off2[] ) const { return _integrate( INTEGRATE_CHILD_PARENT , off1 , off2 ); } - - void init( unsigned int depth ){ Base::init( depth ); } - void init( void ) - { - - _init( Base::highDepth() ); - _weightedIndices.resize(0); - for( unsigned int d1=0 ; d10 ) w.indices.push_back( std::pair< unsigned int , double >( c , weights[c](d1,d2) ) ); - if( w.indices.size() ) _weightedIndices.push_back(w); - } - } - typename BaseFEMIntegrator::template RestrictionProlongation< UIntPack< FEMSignature< TSignatures >::Degree ... > >& tRestrictionProlongation( void ){ return _tRestrictionProlongation; } - typename BaseFEMIntegrator::template RestrictionProlongation< UIntPack< FEMSignature< CSignatures >::Degree ... > >& cRestrictionProlongation( void ){ return _cRestrictionProlongation; } + template< unsigned int ... FEMSigs > bool isValidFEMNode( UIntPack< FEMSigs ... > , const FEMTreeNode* node ) const; + bool isValidSpaceNode( const FEMTreeNode* node ) const; + const FEMTreeNode* leaf( Point< Real , Dim > p ) const; protected: - RestrictionProlongation< UIntPack< TSignatures ... > > _tRestrictionProlongation; - RestrictionProlongation< UIntPack< CSignatures ... > > _cRestrictionProlongation; - struct _WeightedIndices - { - _WeightedIndices( unsigned int _d1=0 , unsigned int _d2=0 ) : d1(_d1) , d2(_d2) { ; } - unsigned int d1 , d2; - std::vector< std::pair< unsigned int , double > > indices; - }; - std::vector< _WeightedIndices > _weightedIndices; - enum IntegrationType + template< bool ThreadSafe > + FEMTreeNode* _leaf( Allocator< FEMTreeNode > *nodeAllocator , Point< Real , Dim > p , LocalDepth maxDepth=-1 ); + template< bool ThreadSafe > + FEMTreeNode* _leaf( Allocator< FEMTreeNode > *nodeAllocator , Point< Real , Dim > p , std::function< int ( Point< Real , Dim > ) > &pointDepthFunctor ); + public: + + // [NOTE] In the case that T != double, we require both operators() for computing the system dual + template< typename T , unsigned int PointD > + struct InterpolationInfo { - INTEGRATE_CHILD_CHILD , - INTEGRATE_PARENT_CHILD , - INTEGRATE_CHILD_PARENT + virtual void range( const FEMTreeNode* node , size_t& begin , size_t& end ) const = 0; + virtual Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const = 0; + virtual Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const = 0; + virtual Point< double , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< double , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const = 0; + virtual const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const = 0; + virtual bool constrainsDCTerm( void ) const = 0; + virtual ~InterpolationInfo( void ){} + + DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIndex ){ return const_cast< DualPointInfo< Dim , Real , T , PointD >& >( ( ( const InterpolationInfo* )this )->operator[]( pointIndex ) ); } + protected: + virtual void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ) = 0; + friend class FEMTree< Dim , Real >; }; - template< unsigned int _TSig , unsigned int _TDerivatives , unsigned int _CSig , unsigned int _CDerivatives > - struct _Integrators + template< unsigned int PointD > + struct InterpolationInfo< double , PointD > { - typename BSplineIntegrationData< _TSig , _CSig >::FunctionIntegrator::template Integrator< _TDerivatives , _CDerivatives > ccIntegrator; - typename BSplineIntegrationData< _TSig , _CSig >::FunctionIntegrator::template ChildIntegrator< _TDerivatives , _CDerivatives > pcIntegrator; - typename BSplineIntegrationData< _CSig , _TSig >::FunctionIntegrator::template ChildIntegrator< _CDerivatives , _TDerivatives > cpIntegrator; + virtual void range( const FEMTreeNode* node , size_t& begin , size_t& end ) const = 0; + virtual Point< double , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const = 0; + virtual Point< double , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< double , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const = 0; + virtual const DualPointInfo< Dim , Real , double , PointD >& operator[]( size_t pointIdx ) const = 0; + virtual bool constrainsDCTerm( void ) const = 0; + virtual ~InterpolationInfo( void ){} + + DualPointInfo< Dim , Real , double , PointD >& operator[]( size_t pointIndex ){ return const_cast< DualPointInfo< Dim , Real , double , PointD >& >( ( ( const InterpolationInfo* )this )->operator[]( pointIndex ) ); } + protected: + virtual void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ) = 0; + friend class FEMTree< Dim , Real >; }; - std::tuple< _Integrators< TSignatures , TDerivatives , CSignatures , CDerivatives > ... > _integrators; - template< unsigned int D=0 > - typename std::enable_if< D==Dim >::type _init( int depth ){ ; } - template< unsigned int D=0 > - typename std::enable_if< D< Dim >::type _init( int depth ) - { - std::get< D >( _integrators ).ccIntegrator.set( depth ); - if( depth ) std::get< D >( _integrators ).pcIntegrator.set( depth-1 ) , std::get< D >( _integrators ).cpIntegrator.set( depth-1 ); - _init< D+1 >( depth ); - } - template< unsigned int D=0 > - typename std::enable_if< D==Dim , double >::type _integral( IntegrationType iType , const int off1[] , const int off2[] , const unsigned int d1[] , const unsigned int d2[] ) const { return 1.; } - template< unsigned int D=0 > - typename std::enable_if< D< Dim , double >::type _integral( IntegrationType iType , const int off1[] , const int off2[] , const unsigned int d1[] , const unsigned int d2[] ) const + template< typename T , unsigned int PointD , typename ConstraintDual , typename SystemDual > + struct ApproximatePointInterpolationInfo : public InterpolationInfo< T , PointD > { - double remainingIntegral = _integral< D+1 >( iType , off1 , off2 , d1 , d2 ); - switch( iType ) + using Data = DualPointInfo< Dim , Real , T , PointD >; + void range( const FEMTreeNode *node , size_t &begin , size_t &end ) const { - case INTEGRATE_CHILD_CHILD: return std::get< D >( _integrators ).ccIntegrator.dot( off1[D] , off2[D] , d1[D] , d2[D] ) * remainingIntegral; - case INTEGRATE_PARENT_CHILD: return std::get< D >( _integrators ).pcIntegrator.dot( off1[D] , off2[D] , d1[D] , d2[D] ) * remainingIntegral; - case INTEGRATE_CHILD_PARENT: return std::get< D >( _integrators ).cpIntegrator.dot( off2[D] , off1[D] , d2[D] , d1[D] ) * remainingIntegral; - default: ERROR_OUT( "Undefined integration type" ); + node_index_type idx = iData.index( node ); + if( idx==-1 ) begin = end = 0; + else begin = idx , end = idx+1; } - return 0; - } - Point< double , CDim > _integrate( IntegrationType iType , const int off1[] , const int off[] ) const; - }; + bool constrainsDCTerm( void ) const { return _constrainsDCTerm; } + const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const { return iData[ pointIdx ]; } + Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( iData[ pointIdx ].position ); } + Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( iData[ pointIdx ].position , dValues ); } + Point< double , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< double , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( iData[ pointIdx ].position , dValues ); } - template< unsigned int ... TSignatures , unsigned int ... TDerivatives , unsigned int ... CSignatures , unsigned int ... CDerivatives > - struct ScalarConstraint< UIntPack< TSignatures ... > , UIntPack< TDerivatives ... > , UIntPack< CSignatures ... > , UIntPack< CDerivatives ... > > : public Constraint< UIntPack< TSignatures ... > , UIntPack< TDerivatives ... > , UIntPack< CSignatures ... > , UIntPack< CDerivatives ... > , 1 > - { - static const unsigned int Dim = sizeof ... ( TSignatures ); - typedef typename BaseFEMIntegrator::template Constraint< UIntPack< FEMSignature< TSignatures >::Degree ... > , UIntPack< FEMSignature< CSignatures >::Degree ... > , 1 > Base; + ApproximatePointInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _constraintDual( constraintDual ) , _systemDual( systemDual ) , _constrainsDCTerm( constrainsDCTerm ) { } - typedef Constraint< UIntPack< TSignatures ... > , UIntPack< TDerivatives ... > , UIntPack< CSignatures ... > , UIntPack< CDerivatives ... > , 1 > FullConstraint; - using FullConstraint::weights; - // [NOTE] We define the constructor using a recursive function call to take into account multiplicity (e.g. so that d^2/dxdy and d^2/dydx each contribute) - ScalarConstraint( const std::initializer_list< double >& w ) - { - std::function< void ( unsigned int[] , const double[] , unsigned int ) > SetDerivativeWeights = [&]( unsigned int derivatives[Dim] , const double w[] , unsigned int d ) + void write( BinaryStream &stream ) const { - unsigned int idx1 = FullConstraint::TDerivativeIndex( derivatives ) , idx2 = FullConstraint::CDerivativeIndex( derivatives ); - weights[0][idx1][idx2] += w[0]; - if( d>0 ) for( int dd=0 ; dd( UIntPack< TDerivatives ... >::Min() , UIntPack< CDerivatives ... >::Min() ); - - unsigned int derivatives[Dim]; - double _w[DMax+1]; - memset( _w , 0 , sizeof(_w) ); + unsigned char constrainsDCTerm = _constrainsDCTerm ? 1 : 0; + stream.write( constrainsDCTerm ); + stream.write( _constraintDual ); + stream.write( _systemDual ); + iData.write( stream ); + } + void read( BinaryStream &stream ) { - unsigned int dd=0; - for( typename std::initializer_list< double >::const_iterator iter=w.begin() ; iter!=w.end() && dd<=DMax ; dd++ , iter++ ) _w[dd] = *iter; + unsigned char constrainsDCTerm; + if( !stream.read( constrainsDCTerm ) ) ERROR_OUT( "Failed to read constrainsDCTerm" ); + _constrainsDCTerm = constrainsDCTerm!=0; + if( !stream.read( _constraintDual ) ) ERROR_OUT( "Failed to read _constraintDual" ); + if( !stream.read( _systemDual ) ) ERROR_OUT( "Failed to read _systemDual" ); + iData.read( stream ); } - for( int d=0 ; d( DMax+1 , (unsigned int)w.size() )-1 ); - } - }; + ApproximatePointInterpolationInfo( BinaryStream &stream ){ read(stream); } + ApproximatePointInterpolationInfo( void ){} - template< unsigned int ... TSignatures , unsigned int ... TDerivatives > - struct System< UIntPack< TSignatures ... > , UIntPack< TDerivatives ... > > : public BaseFEMIntegrator::template System< UIntPack< FEMSignature< TSignatures >::Degree... > > - { - static_assert( sizeof ... ( TSignatures ) == sizeof ... ( TDerivatives ) , "[ERROR] Test signatures and derivatives must have the same dimension" ); + SparseNodeData< DualPointInfo< Dim , Real , T , PointD > , ZeroUIntPack< Dim > > iData; - static const unsigned int Dim = sizeof ... ( TSignatures ); - typedef typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< TSignatures >::Degree... > > Base; + protected: - System( const std::initializer_list< double >& w ) : _sc( w ){ ; } - void init( unsigned int depth ){ Base::init( depth ); } - void init( void ){ ( (BaseFEMIntegrator::template Constraint< UIntPack< FEMSignature< TSignatures >::Degree ... > , UIntPack< FEMSignature< TSignatures >::Degree ... > , 1 >&)_sc ).init( BaseFEMIntegrator::template System< UIntPack< FEMSignature< TSignatures >::Degree... > >::_highDepth ); } - double ccIntegrate( const int off1[] , const int off2[] ) const { return _sc.ccIntegrate( off1 , off2 )[0]; } - double pcIntegrate( const int off1[] , const int off2[] ) const { return _sc.pcIntegrate( off1 , off2 )[0]; } - bool vanishesOnConstants( void ) const { return _sc.weights[0][0][0]==0; } + bool _constrainsDCTerm; + ConstraintDual _constraintDual; + SystemDual _systemDual; - typename BaseFEMIntegrator::template RestrictionProlongation< UIntPack< FEMSignature< TSignatures >::Degree ... > >& restrictionProlongation( void ){ return _sc.tRestrictionProlongation(); } + void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ){ iData._remapIndices( oldNodeIndices , newNodeCount ); } - protected: - ScalarConstraint< UIntPack< TSignatures ... > , UIntPack< TDerivatives ... > , UIntPack< TSignatures ... > , UIntPack< TDerivatives ... > > _sc; - }; -}; + friend class FEMTree< Dim , Real >; + }; -////////////////////////////////////////// + template< unsigned int PointD , typename ConstraintDual , typename SystemDual > + struct ApproximatePointInterpolationInfo< double , PointD , ConstraintDual , SystemDual > : public InterpolationInfo< double , PointD > + { + typedef double T; + using Data = DualPointInfo< Dim , Real , T , PointD >; + void range( const FEMTreeNode* node , size_t& begin , size_t& end ) const + { + node_index_type idx = iData.index( node ); + if( idx==-1 ) begin = end = 0; + else begin = idx , end = idx+1; + } + bool constrainsDCTerm( void ) const { return _constrainsDCTerm; } + const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const { return iData[ pointIdx ]; } + Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( iData[ pointIdx ].position ); } + Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( iData[ pointIdx ].position , dValues ); } -template< unsigned int Dim > inline void SetGhostFlag( RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node , bool flag ){ if( node && node->parent ) node->parent->nodeData.setGhostFlag( flag ); } -template< unsigned int Dim > inline bool GetGhostFlag( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ){ return node==NULL || node->parent==NULL || node->parent->nodeData.getGhostFlag( ); } -template< unsigned int Dim > inline bool IsActiveNode( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ){ return !GetGhostFlag( node ); } + ApproximatePointInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _constraintDual( constraintDual ) , _systemDual( systemDual ) , _constrainsDCTerm( constrainsDCTerm ) { } -// A class representing an extractot with and without auxiliary data -template< typename Real , unsigned int Dim , typename ... Params > struct LevelSetExtractor; + void write( BinaryStream &stream ) const + { + unsigned char constrainsDCTerm = _constrainsDCTerm ? 1 : 0; + stream.write( constrainsDCTerm ); + stream.write( _constraintDual ); + stream.write( _systemDual ); + iData.write( stream ); + } + void read( BinaryStream &stream ) + { + unsigned char constrainsDCTerm; + if( !stream.read( constrainsDCTerm ) ) ERROR_OUT( "Failed to read constrainsDCTerm" ); + _constrainsDCTerm = constrainsDCTerm!=0; + if( !stream.read( _constraintDual ) ) ERROR_OUT( "Failed to read _constraintDual" ); + if( !stream.read( _systemDual ) ) ERROR_OUT( "Failed to read _systemDual" ); + iData.read( stream ); + } + ApproximatePointInterpolationInfo( BinaryStream &stream ){ read(stream); } + ApproximatePointInterpolationInfo( void ){} -// A helper class which consolidates the two extractors, templated over HasData -template< bool HasData , typename Real , unsigned int Dim , typename Data > struct _LevelSetExtractor; + SparseNodeData< DualPointInfo< Dim , Real , T , PointD > , ZeroUIntPack< Dim > > iData; -template< unsigned int Dim , class Data > -struct NodeSample -{ - RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *node; - Data data; -}; -template< unsigned int Dim , class Real > -struct NodeAndPointSample -{ - RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *node; - ProjectiveData< Point< Real , Dim > , Real > sample; -}; -template< unsigned int Dim , class Real > using NodeSimplices = NodeSample< Dim , std::vector< std::pair< node_index_type , Simplex< Real , Dim , Dim-1 > > > >; + protected: + bool _constrainsDCTerm; + ConstraintDual _constraintDual; + SystemDual _systemDual; -template< typename T > struct WindowLoopData{ }; + void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ){ iData._remapIndices( oldNodeIndices , newNodeCount ); } -template< unsigned int ... Sizes > -struct WindowLoopData< UIntPack< Sizes ... > > -{ - static const int Dim = sizeof ... ( Sizes ); - unsigned int size[1< >::Size ]; - template< typename BoundsFunction > - WindowLoopData( const BoundsFunction &boundsFunction ) - { - int start[Dim] , end[Dim]; - for( int c=0 ; c<(1<::Run - ( - start , end , - [&]( int d , int i ){ idx[d] = i; } , - [&]( void ){ indices[c][ size[c]++ ] = GetWindowIndex( UIntPack< Sizes ... >() , idx ); } - ); - } - } -}; + friend class FEMTree< Dim , Real >; + }; -template< class Real , unsigned int Dim > -void AddAtomic( Point< Real , Dim >& a , const Point< Real , Dim >& b ) -{ - for( int d=0 ; d + struct ApproximatePointAndDataInterpolationInfo : public InterpolationInfo< T , PointD > + { + void range( const FEMTreeNode* node , size_t& begin , size_t& end ) const + { + node_index_type idx = iData.index( node ); + if( idx==-1 ) begin = end = 0; + else begin = idx , end = idx+1; + } + bool constrainsDCTerm( void ) const { return _constrainsDCTerm; } + const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const { return iData[ pointIdx ].pointInfo; } + Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( iData[ pointIdx ].pointInfo.position , iData[ pointIdx ].data ); } + Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( iData[ pointIdx ].pointInfo.position , iData[ (int)pointIdx ].data , dValues ); } + typename std::enable_if< !std::is_same< T , double >::value , Point< double , CumulativeDerivatives< Dim , PointD >::Size > >::type operator() ( size_t pointIdx , const Point< double , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( iData[ (int)pointIdx ].pointInfo.position , iData[ (int)pointIdx ].data , dValues ); } -template< class Data > -bool IsZero( const Data& data ){ return false; } -template< class Real , unsigned int Dim > -bool IsZero( const Point< Real , Dim >& d ) -{ - bool zero = true; - for( int i=0 ; i -class FEMTree -{ -public: - typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; - template< unsigned int ... FEMSigs > using SystemMatrixType = SparseMatrix< Real , matrix_index_type , WindowSize< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >::Size >; - std::vector< Allocator< FEMTreeNode > * > nodeAllocators; -protected: - template< unsigned int _Dim , class _Real > friend class FEMTree; - struct SubTreeExtractor : public FEMTreeNode::SubTreeExtractor - { - SubTreeExtractor( FEMTreeNode &node , int &depthOffset ) : FEMTreeNode::SubTreeExtractor( node ) , _depthOffset( depthOffset ) - { - _depthOffsetValue = _depthOffset; - _depthOffset = 0; - } - SubTreeExtractor( FEMTreeNode *node , int &depthOffset ) : SubTreeExtractor( *node , depthOffset ){} - ~SubTreeExtractor( void ){ _depthOffset = _depthOffsetValue; } - protected: - int &_depthOffset , _depthOffsetValue; - }; + void write( BinaryStream &stream ) const + { + unsigned char constrainsDCTerm = _constrainsDCTerm ? 1 : 0; + stream.write( constrainsDCTerm ); + stream.write( _constraintDual ); + stream.write( _systemDual ); + iData.write( stream ); + } + void read( BinaryStream &stream ) + { + unsigned char constrainsDCTerm; + if( !stream.read( constrainsDCTerm ) ) ERROR_OUT( "Failed to read constrainsDCTerm" ); + _constrainsDCTerm = constrainsDCTerm!=0; + if( !stream.read( _constraintDual ) ) ERROR_OUT( "Failed to read _constraintDual" ); + if( !stream.read( _systemDual ) ) ERROR_OUT( "Failed to read _systemDual" ); + iData.read( stream ); + } + ApproximatePointAndDataInterpolationInfo( BinaryStream &stream ){ read(stream); } - // Don't need this first one - template< typename _Real , unsigned int _Dim , typename ... _Params > friend struct LevelSetExtractor; - template< bool _HasData , typename _Real , unsigned int _Dim , typename _Data > friend struct _LevelSetExtractor; - std::atomic< node_index_type > _nodeCount; - struct _NodeInitializer - { - FEMTree& femTree; - _NodeInitializer( FEMTree& f ) : femTree(f){;} - void operator() ( FEMTreeNode& node ){ node.nodeData.nodeIndex = femTree._nodeCount++; } - }; - _NodeInitializer _nodeInitializer; -public: - typedef int LocalDepth; - typedef int LocalOffset[Dim]; - - node_index_type nodeCount( void ) const { return _nodeCount; } - - typedef NodeAndPointSample< Dim , Real > PointSample; - - typedef typename FEMTreeNode::template NeighborKey< IsotropicUIntPack< Dim , 1 > , IsotropicUIntPack< Dim , 1 > > OneRingNeighborKey; - typedef typename FEMTreeNode::template ConstNeighborKey< IsotropicUIntPack< Dim , 1 > , IsotropicUIntPack< Dim , 1 > > ConstOneRingNeighborKey; - typedef typename FEMTreeNode::template Neighbors< IsotropicUIntPack< Dim , 3 > > OneRingNeighbors; - typedef typename FEMTreeNode::template ConstNeighbors< IsotropicUIntPack< Dim , 3 > > ConstOneRingNeighbors; - - template< typename FEMDegreePack > using BaseSystem = typename BaseFEMIntegrator::template System< FEMDegreePack >; - template< typename FEMSigPack , typename DerivativePack > using PointEvaluator = typename FEMIntegrator::template PointEvaluator< FEMSigPack , DerivativePack >; - template< typename FEMSigPack , typename DerivativePack > using PointEvaluatorState = typename FEMIntegrator::template PointEvaluatorState< FEMSigPack , DerivativePack >; - template< typename FEMDegreePack > using CCStencil = typename BaseSystem< FEMDegreePack >::CCStencil; - template< typename FEMDegreePack > using PCStencils = typename BaseSystem< FEMDegreePack >::PCStencils; - - template< unsigned int ... FEMSigs > bool isValidFEMNode( UIntPack< FEMSigs ... > , const FEMTreeNode* node ) const; - bool isValidSpaceNode( const FEMTreeNode* node ) const; - const FEMTreeNode* leaf( Point< Real , Dim > p ) const; -protected: - template< bool ThreadSafe > - FEMTreeNode* _leaf( Allocator< FEMTreeNode > *nodeAllocator , Point< Real , Dim > p , LocalDepth maxDepth=-1 ); - template< bool ThreadSafe > - FEMTreeNode* _leaf( Allocator< FEMTreeNode > *nodeAllocator , Point< Real , Dim > p , std::function< int ( Point< Real , Dim > ) > &pointDepthFunctor ); -public: - - // [NOTE] In the case that T != double, we require both operators() for computing the system dual - template< typename T , unsigned int PointD > - struct InterpolationInfo - { - virtual void range( const FEMTreeNode* node , size_t& begin , size_t& end ) const = 0; - virtual Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const = 0; - virtual Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const = 0; - virtual Point< double , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< double , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const = 0; - virtual const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const = 0; - virtual bool constrainsDCTerm( void ) const = 0; - virtual ~InterpolationInfo( void ){} - - DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIndex ){ return const_cast< DualPointInfo< Dim , Real , T , PointD >& >( ( ( const InterpolationInfo* )this )->operator[]( pointIndex ) ); } - protected: - virtual void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ) = 0; - friend class FEMTree< Dim , Real >; - }; + SparseNodeData< DualPointAndDataInfo< Dim , Real , Data , T , PointD > , ZeroUIntPack< Dim > > iData; - template< unsigned int PointD > - struct InterpolationInfo< double , PointD > - { - virtual void range( const FEMTreeNode* node , size_t& begin , size_t& end ) const = 0; - virtual Point< double , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const = 0; - virtual Point< double , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< double , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const = 0; - virtual const DualPointInfo< Dim , Real , double , PointD >& operator[]( size_t pointIdx ) const = 0; - virtual bool constrainsDCTerm( void ) const = 0; - virtual ~InterpolationInfo( void ){} - - DualPointInfo< Dim , Real , double , PointD >& operator[]( size_t pointIndex ){ return const_cast< DualPointInfo< Dim , Real , double , PointD >& >( ( ( const InterpolationInfo* )this )->operator[]( pointIndex ) ); } - protected: - virtual void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ) = 0; - friend class FEMTree< Dim , Real >; - }; + protected: - template< typename T , unsigned int PointD , typename ConstraintDual , typename SystemDual > - struct ApproximatePointInterpolationInfo : public InterpolationInfo< T , PointD > - { - using Data = DualPointInfo< Dim , Real , T , PointD >; - void range( const FEMTreeNode *node , size_t &begin , size_t &end ) const - { - node_index_type idx = iData.index( node ); - if( idx==-1 ) begin = end = 0; - else begin = idx , end = idx+1; - } - bool constrainsDCTerm( void ) const { return _constrainsDCTerm; } - const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const { return iData[ pointIdx ]; } - Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( iData[ pointIdx ].position ); } - Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( iData[ pointIdx ].position , dValues ); } - Point< double , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< double , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( iData[ pointIdx ].position , dValues ); } + bool _constrainsDCTerm; + ConstraintDual _constraintDual; + SystemDual _systemDual; - ApproximatePointInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _constraintDual( constraintDual ) , _systemDual( systemDual ) , _constrainsDCTerm( constrainsDCTerm ) { } + void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ){ iData._remapIndices( oldNodeIndices , newNodeCount ); } - void write( BinaryStream &stream ) const - { - unsigned char constrainsDCTerm = _constrainsDCTerm ? 1 : 0; - stream.write( constrainsDCTerm ); - stream.write( _constraintDual ); - stream.write( _systemDual ); - iData.write( stream ); - } - void read( BinaryStream &stream ) + ApproximatePointAndDataInterpolationInfo( void ){} + friend class FEMTree< Dim , Real >; + }; + + template< typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > + struct ApproximatePointAndDataInterpolationInfo< double , Data , PointD , ConstraintDual , SystemDual > : public InterpolationInfo< double , PointD > { - unsigned char constrainsDCTerm; - if( !stream.read( constrainsDCTerm ) ) ERROR_OUT( "Failed to read constrainsDCTerm" ); - _constrainsDCTerm = constrainsDCTerm!=0; - if( !stream.read( _constraintDual ) ) ERROR_OUT( "Failed to read _constraintDual" ); - if( !stream.read( _systemDual ) ) ERROR_OUT( "Failed to read _systemDual" ); - iData.read( stream ); - } - ApproximatePointInterpolationInfo( BinaryStream &stream ){ read(stream); } - ApproximatePointInterpolationInfo( void ){} + typedef double T; + void range( const FEMTreeNode* node , size_t& begin , size_t& end ) const + { + node_index_type idx = iData.index( node ); + if( idx==-1 ) begin = end = 0; + else begin = idx , end = idx+1; + } + bool constrainsDCTerm( void ) const { return _constrainsDCTerm; } + const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const { return iData[ pointIdx ].pointInfo; } + Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( iData[ pointIdx ].pointInfo.position , iData[ pointIdx ].data ); } + Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( iData[ pointIdx ].pointInfo.position , iData[ pointIdx ].data , dValues ); } - SparseNodeData< DualPointInfo< Dim , Real , T , PointD > , ZeroUIntPack< Dim > > iData; + ApproximatePointAndDataInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _constraintDual( constraintDual ) , _systemDual( systemDual ) , _constrainsDCTerm( constrainsDCTerm ) { } - protected: + void write( BinaryStream &stream ) const + { + unsigned char constrainsDCTerm = _constrainsDCTerm ? 1 : 0; + stream.write( constrainsDCTerm ); + stream.write( _constraintDual ); + stream.write( _systemDual ); + iData.write( stream ); + } + void read( BinaryStream &stream ) + { + unsigned char constrainsDCTerm; + if( !stream.read( constrainsDCTerm ) ) ERROR_OUT( "Failed to read constrainsDCTerm" ); + _constrainsDCTerm = constrainsDCTerm!=0; + if( !stream.read( _constraintDual ) ) ERROR_OUT( "Failed to read _constraintDual" ); + if( !stream.read( _systemDual ) ) ERROR_OUT( "Failed to read _systemDual" ); + iData.read( stream ); + } - bool _constrainsDCTerm; - ConstraintDual _constraintDual; - SystemDual _systemDual; + ApproximatePointAndDataInterpolationInfo( BinaryStream &stream ){ read(stream); } - void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ){ iData._remapIndices( oldNodeIndices , newNodeCount ); } + SparseNodeData< DualPointAndDataInfo< Dim , Real , Data , T , PointD > , ZeroUIntPack< Dim > > iData; - friend class FEMTree< Dim , Real >; - }; + protected: - template< unsigned int PointD , typename ConstraintDual , typename SystemDual > - struct ApproximatePointInterpolationInfo< double , PointD , ConstraintDual , SystemDual > : public InterpolationInfo< double , PointD > - { - typedef double T; - using Data = DualPointInfo< Dim , Real , T , PointD >; - void range( const FEMTreeNode* node , size_t& begin , size_t& end ) const - { - node_index_type idx = iData.index( node ); - if( idx==-1 ) begin = end = 0; - else begin = idx , end = idx+1; - } - bool constrainsDCTerm( void ) const { return _constrainsDCTerm; } - const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const { return iData[ pointIdx ]; } - Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( iData[ pointIdx ].position ); } - Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( iData[ pointIdx ].position , dValues ); } + bool _constrainsDCTerm; + ConstraintDual _constraintDual; + SystemDual _systemDual; - ApproximatePointInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _constraintDual( constraintDual ) , _systemDual( systemDual ) , _constrainsDCTerm( constrainsDCTerm ) { } + void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ){ iData._remapIndices( oldNodeIndices , newNodeCount ); } - void write( BinaryStream &stream ) const - { - unsigned char constrainsDCTerm = _constrainsDCTerm ? 1 : 0; - stream.write( constrainsDCTerm ); - stream.write( _constraintDual ); - stream.write( _systemDual ); - iData.write( stream ); - } - void read( BinaryStream &stream ) + ApproximatePointAndDataInterpolationInfo( void ){} + friend class FEMTree< Dim , Real >; + }; + + template< typename T , unsigned int PointD , typename ConstraintDual , typename SystemDual > + struct ExactPointInterpolationInfo : public InterpolationInfo< T , PointD > { - unsigned char constrainsDCTerm; - if( !stream.read( constrainsDCTerm ) ) ERROR_OUT( "Failed to read constrainsDCTerm" ); - _constrainsDCTerm = constrainsDCTerm!=0; - if( !stream.read( _constraintDual ) ) ERROR_OUT( "Failed to read _constraintDual" ); - if( !stream.read( _systemDual ) ) ERROR_OUT( "Failed to read _systemDual" ); - iData.read( stream ); - } - ApproximatePointInterpolationInfo( BinaryStream &stream ){ read(stream); } - ApproximatePointInterpolationInfo( void ){} + void range( const FEMTreeNode *node , size_t &begin , size_t &end ) const { begin = _sampleSpan[ node->nodeData.nodeIndex ].first , end = _sampleSpan[ node->nodeData.nodeIndex ].second; } + bool constrainsDCTerm( void ) const { return _constrainsDCTerm; } + const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const { return _iData[ pointIdx ]; } + Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( _iData[ pointIdx ].position ); } + Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( _iData[ pointIdx ].position , dValues ); } + typename std::enable_if< !std::is_same< T , double >::value , Point< double , CumulativeDerivatives< Dim , PointD >::Size > >::type operator() ( size_t pointIdx , const Point< double , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( _iData[ pointIdx ].position , dValues ); } + + ExactPointInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _constraintDual( constraintDual ) , _systemDual( systemDual ) , _constrainsDCTerm( constrainsDCTerm ) { } + protected: + void _init( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , bool noRescale ); - SparseNodeData< DualPointInfo< Dim , Real , T , PointD > , ZeroUIntPack< Dim > > iData; + std::vector< std::pair< node_index_type , node_index_type > > _sampleSpan; + std::vector< DualPointInfo< Dim , Real , T , PointD > > _iData; + bool _constrainsDCTerm; + ConstraintDual _constraintDual; + SystemDual _systemDual; - protected: + void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ) + { + std::vector< std::pair< node_index_type , node_index_type > > _newSampleSpan( newNodeCount ); + for( size_t i=0 ; i; + }; - void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ){ iData._remapIndices( oldNodeIndices , newNodeCount ); } + template< unsigned int PointD , typename ConstraintDual , typename SystemDual > + struct ExactPointInterpolationInfo< double , PointD , ConstraintDual , SystemDual > : public InterpolationInfo< double , PointD > + { + typedef double T; + void range( const FEMTreeNode* node , size_t& begin , size_t& end ) const { begin = _sampleSpan[ node->nodeData.nodeIndex ].first , end = _sampleSpan[ node->nodeData.nodeIndex ].second; } + bool constrainsDCTerm( void ) const { return _constrainsDCTerm; } + const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const { return _iData[ pointIdx ]; } + Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( _iData[ pointIdx ].position ); } + Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( _iData[ pointIdx ].position , dValues ); } + + ExactPointInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _constraintDual( constraintDual ) , _systemDual( systemDual ) , _constrainsDCTerm( constrainsDCTerm ) { } + protected: + void _init( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , bool noRescale ); - friend class FEMTree< Dim , Real >; - }; + std::vector< std::pair< node_index_type , node_index_type > > _sampleSpan; + std::vector< DualPointInfo< Dim , Real , T , PointD > > _iData; + bool _constrainsDCTerm; + ConstraintDual _constraintDual; + SystemDual _systemDual; - template< typename T , typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > - struct ApproximatePointAndDataInterpolationInfo : public InterpolationInfo< T , PointD > - { - void range( const FEMTreeNode* node , size_t& begin , size_t& end ) const - { - node_index_type idx = iData.index( node ); - if( idx==-1 ) begin = end = 0; - else begin = idx , end = idx+1; - } - bool constrainsDCTerm( void ) const { return _constrainsDCTerm; } - const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const { return iData[ pointIdx ].pointInfo; } - Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( iData[ pointIdx ].pointInfo.position , iData[ pointIdx ].data ); } - Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( iData[ pointIdx ].pointInfo.position , iData[ (int)pointIdx ].data , dValues ); } - typename std::enable_if< !std::is_same< T , double >::value , Point< double , CumulativeDerivatives< Dim , PointD >::Size > >::type operator() ( size_t pointIdx , const Point< double , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( iData[ (int)pointIdx ].pointInfo.position , iData[ (int)pointIdx ].data , dValues ); } + void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ) + { + std::vector< std::pair< node_index_type , node_index_type > > _newSampleSpan( newNodeCount ); + for( size_t i=0 ; i; + }; - void write( BinaryStream &stream ) const - { - unsigned char constrainsDCTerm = _constrainsDCTerm ? 1 : 0; - stream.write( constrainsDCTerm ); - stream.write( _constraintDual ); - stream.write( _systemDual ); - iData.write( stream ); - } - void read( BinaryStream &stream ) + template< typename T , typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > + struct _ExactPointAndDataInterpolationInfo : public InterpolationInfo< T , PointD > { - unsigned char constrainsDCTerm; - if( !stream.read( constrainsDCTerm ) ) ERROR_OUT( "Failed to read constrainsDCTerm" ); - _constrainsDCTerm = constrainsDCTerm!=0; - if( !stream.read( _constraintDual ) ) ERROR_OUT( "Failed to read _constraintDual" ); - if( !stream.read( _systemDual ) ) ERROR_OUT( "Failed to read _systemDual" ); - iData.read( stream ); - } - ApproximatePointAndDataInterpolationInfo( BinaryStream &stream ){ read(stream); } - - SparseNodeData< DualPointAndDataInfo< Dim , Real , Data , T , PointD > , ZeroUIntPack< Dim > > iData; + _ExactPointAndDataInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _constraintDual( constraintDual ) , _systemDual( systemDual ) , _constrainsDCTerm( constrainsDCTerm ) { } - protected: + protected: + void _init( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , ConstPointer( Data ) sampleData , bool noRescale ); - bool _constrainsDCTerm; - ConstraintDual _constraintDual; - SystemDual _systemDual; + std::vector< std::pair< node_index_type , node_index_type > > _sampleSpan; + std::vector< DualPointAndDataInfo< Dim , Real , Data , T , PointD > > _iData; + bool _constrainsDCTerm; + ConstraintDual _constraintDual; + SystemDual _systemDual; - void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ){ iData._remapIndices( oldNodeIndices , newNodeCount ); } + void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ) + { + std::vector< std::pair< node_index_type , node_index_type > > _newSampleSpan( newNodeCount ); + for( size_t i=0 ; i; - }; + friend class FEMTree< Dim , Real >; + }; - template< typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > - struct ApproximatePointAndDataInterpolationInfo< double , Data , PointD , ConstraintDual , SystemDual > : public InterpolationInfo< double , PointD > - { - typedef double T; - void range( const FEMTreeNode* node , size_t& begin , size_t& end ) const + template< typename T , typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > + struct ExactPointAndDataInterpolationInfo : public _ExactPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual > { - node_index_type idx = iData.index( node ); - if( idx==-1 ) begin = end = 0; - else begin = idx , end = idx+1; - } - bool constrainsDCTerm( void ) const { return _constrainsDCTerm; } - const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const { return iData[ pointIdx ].pointInfo; } - Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( iData[ pointIdx ].pointInfo.position , iData[ pointIdx ].data ); } - Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( iData[ pointIdx ].pointInfo.position , iData[ pointIdx ].data , dValues ); } + using _ExactPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >::_sampleSpan; + using _ExactPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >::_constrainsDCTerm; + using _ExactPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >::_iData; + using _ExactPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >::_constraintDual; + using _ExactPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >::_systemDual; + void range( const FEMTreeNode* node , size_t& begin , size_t& end ) const { begin = _sampleSpan[ node->nodeData.nodeIndex ].first , end = _sampleSpan[ node->nodeData.nodeIndex ].second; } + bool constrainsDCTerm( void ) const { return _constrainsDCTerm; } + const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const { return _iData[ pointIdx ].pointInfo; } + Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( _iData[ pointIdx ].pointInfo.position , _iData[ pointIdx ].data ); } + Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( _iData[ pointIdx ].pointInfo.position , _iData[ pointIdx ].data , dValues ); } + Point< double , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< double , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( _iData[ pointIdx ].pointInfo.position , _iData[ (int)pointIdx ].data , dValues ); } + + ExactPointAndDataInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _ExactPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >( constraintDual , systemDual , constrainsDCTerm ) { } + }; - ApproximatePointAndDataInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _constraintDual( constraintDual ) , _systemDual( systemDual ) , _constrainsDCTerm( constrainsDCTerm ) { } + template< typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > + struct ExactPointAndDataInterpolationInfo< double , Data , PointD , ConstraintDual , SystemDual > : public _ExactPointAndDataInterpolationInfo< double , Data , PointD , ConstraintDual , SystemDual > + { + using _ExactPointAndDataInterpolationInfo< double , Data , PointD , ConstraintDual , SystemDual >::_sampleSpan; + using _ExactPointAndDataInterpolationInfo< double , Data , PointD , ConstraintDual , SystemDual >::_constrainsDCTerm; + using _ExactPointAndDataInterpolationInfo< double , Data , PointD , ConstraintDual , SystemDual >::_iData; + using _ExactPointAndDataInterpolationInfo< double , Data , PointD , ConstraintDual , SystemDual >::_constraintDual; + using _ExactPointAndDataInterpolationInfo< double , Data , PointD , ConstraintDual , SystemDual >::_systemDual; + void range( const FEMTreeNode* node , size_t& begin , size_t& end ) const { begin = _sampleSpan[ node->nodeData.nodeIndex ].first , end = _sampleSpan[ node->nodeData.nodeIndex ].second; } + bool constrainsDCTerm( void ) const { return _constrainsDCTerm; } + const DualPointInfo< Dim , Real , double , PointD >& operator[]( size_t pointIdx ) const { return _iData[ pointIdx ].pointInfo; } + Point< double , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( _iData[ pointIdx ].pointInfo.position , _iData[ pointIdx ].data ); } + Point< double , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< double , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( _iData[ pointIdx ].pointInfo.position , _iData[ (int)pointIdx ].data , dValues ); } + + ExactPointAndDataInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _ExactPointAndDataInterpolationInfo< double , Data , PointD , ConstraintDual , SystemDual >( constraintDual , systemDual , constrainsDCTerm ) { } + }; - void write( BinaryStream &stream ) const + template< typename T , unsigned int PointD , typename ConstraintDual , typename SystemDual > + static ApproximatePointInterpolationInfo< T , PointD , ConstraintDual , SystemDual >* InitializeApproximatePointInterpolationInfo( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm , LocalDepth maxDepth , int adaptiveExponent ) { - unsigned char constrainsDCTerm = _constrainsDCTerm ? 1 : 0; - stream.write( constrainsDCTerm ); - stream.write( _constraintDual ); - stream.write( _systemDual ); - iData.write( stream ); + ApproximatePointInterpolationInfo< T , PointD , ConstraintDual , SystemDual >* a = new ApproximatePointInterpolationInfo< T , PointD , ConstraintDual , SystemDual >( constraintDual , systemDual , constrainsDCTerm ); + a->iData = tree._densifyInterpolationInfoAndSetDualConstraints< T , PointD >( samples , constraintDual , maxDepth , adaptiveExponent ); + return a; } - void read( BinaryStream &stream ) + template< typename T , typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > + static ApproximatePointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >* InitializeApproximatePointAndDataInterpolationInfo( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , ConstPointer( Data ) sampleData , ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm , LocalDepth maxDepth , int adaptiveExponent ) { - unsigned char constrainsDCTerm; - if( !stream.read( constrainsDCTerm ) ) ERROR_OUT( "Failed to read constrainsDCTerm" ); - _constrainsDCTerm = constrainsDCTerm!=0; - if( !stream.read( _constraintDual ) ) ERROR_OUT( "Failed to read _constraintDual" ); - if( !stream.read( _systemDual ) ) ERROR_OUT( "Failed to read _systemDual" ); - iData.read( stream ); + ApproximatePointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >* a = new ApproximatePointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >( constraintDual , systemDual , constrainsDCTerm ); + a->iData = tree._densifyInterpolationInfoAndSetDualConstraints< T , Data , PointD >( samples , sampleData , constraintDual , maxDepth , adaptiveExponent ); + return a; } - ApproximatePointAndDataInterpolationInfo( BinaryStream &stream ){ read(stream); } + template< typename T , unsigned int PointD , typename ConstraintDual , typename SystemDual > + static ExactPointInterpolationInfo< T , PointD , ConstraintDual , SystemDual >* InitializeExactPointInterpolationInfo( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm , bool noRescale ) + { + ExactPointInterpolationInfo< T , PointD , ConstraintDual , SystemDual >* e = new ExactPointInterpolationInfo< T , PointD , ConstraintDual , SystemDual >( constraintDual , systemDual , constrainsDCTerm ); + e->_init( tree , samples , noRescale ); + return e; + } + template< typename T , typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > + static ExactPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >* InitializeExactPointAndDataInterpolationInfo( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , ConstPointer( Data ) sampleData , ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm , bool noRescale ) + { + ExactPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >* e = new ExactPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >( constraintDual , systemDual , constrainsDCTerm ); + e->_init( tree , samples , sampleData , noRescale ); + return e; + } - SparseNodeData< DualPointAndDataInfo< Dim , Real , Data , T , PointD > , ZeroUIntPack< Dim > > iData; + template< typename T , unsigned int PointD , typename ConstraintDual , typename SystemDual > friend struct ExactPointInterpolationInfo; + template< typename T , typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > friend struct ExactPointAndDataInterpolationInfo; + template< typename ... InterpolationInfos > + static bool ConstrainsDCTerm( std::tuple< InterpolationInfos *... > interpolationInfos ){ return _ConstrainsDCTerm< 0 >( interpolationInfos ); } protected: + template< unsigned int Idx , typename ... InterpolationInfos > + static typename std::enable_if< ( Idx==sizeof...(InterpolationInfos) ) , bool >::type _ConstrainsDCTerm( std::tuple< InterpolationInfos *... > interpolationInfos ){ return false; } + template< unsigned int Idx , typename ... InterpolationInfos > + static typename std::enable_if< ( Idx ::type _ConstrainsDCTerm( std::tuple< InterpolationInfos *... > interpolationInfos ) + { + if( std::get< Idx >( interpolationInfos ) ) return _ConstrainsDCTerm< Idx+1 >( interpolationInfos ) || std::get< Idx >( interpolationInfos )->constrainsDCTerm(); + else return _ConstrainsDCTerm< Idx+1 >( interpolationInfos ); + } + public: - bool _constrainsDCTerm; - ConstraintDual _constraintDual; - SystemDual _systemDual; +#ifdef SHOW_WARNINGS +#pragma message( "[WARNING] This should not be isotropic" ) +#endif // SHOW_WARNINGS + template< unsigned int DensityDegree > struct DensityEstimator : public SparseNodeData< Real , IsotropicUIntPack< Dim , FEMDegreeAndBType< DensityDegree >::Signature > > + { + DensityEstimator( int kernelDepth , int coDimension , Real samplesPerNode ) : _kernelDepth( kernelDepth ) , _coDimension( coDimension ) , _samplesPerNode( samplesPerNode ){ } + Real samplesPerNode( void ) const { return _samplesPerNode; } + int coDimension( void ) const { return _coDimension; } + int kernelDepth( void ) const { return _kernelDepth; } - void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ){ iData._remapIndices( oldNodeIndices , newNodeCount ); } + void write( BinaryStream &stream ) const + { + stream.write( _kernelDepth ); + stream.write( _coDimension ); + stream.write( _samplesPerNode ); + SparseNodeData< Real , IsotropicUIntPack< Dim , FEMDegreeAndBType< DensityDegree >::Signature > >::write( stream ); + } + void read( BinaryStream &stream ) + { + if( !stream.read( _kernelDepth ) ) ERROR_OUT( "Failed to read _kernelDepth" ); + if( !stream.read( _coDimension ) ) ERROR_OUT( "Failed to read _coDimension" ); + if( !stream.read( _samplesPerNode ) ) ERROR_OUT( "Failed to read _samplesPerNode" ); + SparseNodeData< Real , IsotropicUIntPack< Dim , FEMDegreeAndBType< DensityDegree >::Signature > >::read( stream ); + } + DensityEstimator( BinaryStream &stream ){ read(stream); } - ApproximatePointAndDataInterpolationInfo( void ){} - friend class FEMTree< Dim , Real >; - }; + protected: + Real _samplesPerNode; + int _kernelDepth , _coDimension; + }; - template< typename T , unsigned int PointD , typename ConstraintDual , typename SystemDual > - struct ExactPointInterpolationInfo : public InterpolationInfo< T , PointD > - { - void range( const FEMTreeNode *node , size_t &begin , size_t &end ) const { begin = _sampleSpan[ node->nodeData.nodeIndex ].first , end = _sampleSpan[ node->nodeData.nodeIndex ].second; } - bool constrainsDCTerm( void ) const { return _constrainsDCTerm; } - const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const { return _iData[ pointIdx ]; } - Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( _iData[ pointIdx ].position ); } - Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( _iData[ pointIdx ].position , dValues ); } - typename std::enable_if< !std::is_same< T , double >::value , Point< double , CumulativeDerivatives< Dim , PointD >::Size > >::type operator() ( size_t pointIdx , const Point< double , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( _iData[ pointIdx ].position , dValues ); } - - ExactPointInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _constraintDual( constraintDual ) , _systemDual( systemDual ) , _constrainsDCTerm( constrainsDCTerm ) { } protected: - void _init( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , bool noRescale ); - - std::vector< std::pair< node_index_type , node_index_type > > _sampleSpan; - std::vector< DualPointInfo< Dim , Real , T , PointD > > _iData; - bool _constrainsDCTerm; - ConstraintDual _constraintDual; - SystemDual _systemDual; - - void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ) + bool _isValidSpaceNode( const FEMTreeNode* node ) const { return !GetGhostFlag< Dim >( node ) && ( node->nodeData.flags & FEMTreeNodeData::SPACE_FLAG ); } + bool _isValidFEM1Node ( const FEMTreeNode* node ) const { return !GetGhostFlag< Dim >( node ) && ( node->nodeData.flags & FEMTreeNodeData::FEM_FLAG_1 ); } + bool _isValidFEM2Node ( const FEMTreeNode* node ) const { return !GetGhostFlag< Dim >( node ) && ( node->nodeData.flags & FEMTreeNodeData::FEM_FLAG_2 ); } + + FEMTreeNode _tree; + mutable FEMTreeNode* _spaceRoot; + SortedTreeNodes< Dim > _sNodes; + LocalDepth _maxDepth; + int _depthOffset; + LocalDepth _baseDepth; +#ifdef USE_EXACT_PROLONGATION + LocalDepth _exactDepth; +#endif // USE_EXACT_PROLONGATION + mutable unsigned int _femSigs1[ Dim ]; + mutable unsigned int _femSigs2[ Dim ]; + void _init( void ); + + static bool _InBounds( Point< Real , Dim > p ); + int _localToGlobal( LocalDepth d ) const { return d + _depthOffset; } + LocalDepth _globalToLocal( int d ) const { return d - _depthOffset; } + LocalDepth _localDepth( const FEMTreeNode* node ) const { return node->depth() - _depthOffset; } + int _localInset( LocalDepth d ) const { return _depthOffset==0 ? 0 : 1<<( d + _depthOffset - 1 ); } + void _localDepthAndOffset( const FEMTreeNode* node , LocalDepth& d , LocalOffset& off ) const { - std::vector< std::pair< node_index_type , node_index_type > > _newSampleSpan( newNodeCount ); - for( size_t i=0 ; idepthAndOffset( d , off ) ; d -= _depthOffset; + int inset = _localInset( d ); + for( int d=0 ; d; - }; - - template< unsigned int PointD , typename ConstraintDual , typename SystemDual > - struct ExactPointInterpolationInfo< double , PointD , ConstraintDual , SystemDual > : public InterpolationInfo< double , PointD > - { - typedef double T; - void range( const FEMTreeNode* node , size_t& begin , size_t& end ) const { begin = _sampleSpan[ node->nodeData.nodeIndex ].first , end = _sampleSpan[ node->nodeData.nodeIndex ].second; } - bool constrainsDCTerm( void ) const { return _constrainsDCTerm; } - const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const { return _iData[ pointIdx ]; } - Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( _iData[ pointIdx ].position ); } - Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( _iData[ pointIdx ].position , dValues ); } - - ExactPointInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _constraintDual( constraintDual ) , _systemDual( systemDual ) , _constrainsDCTerm( constrainsDCTerm ) { } - protected: - void _init( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , bool noRescale ); - - std::vector< std::pair< node_index_type , node_index_type > > _sampleSpan; - std::vector< DualPointInfo< Dim , Real , T , PointD > > _iData; - bool _constrainsDCTerm; - ConstraintDual _constraintDual; - SystemDual _systemDual; - - void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ) + template< unsigned int FEMSig > static int _BSplineBegin( LocalDepth depth ){ return BSplineEvaluationData< FEMSig >::Begin( depth ); } + template< unsigned int FEMSig > static int _BSplineEnd ( LocalDepth depth ){ return BSplineEvaluationData< FEMSig >::End ( depth ); } + template< unsigned int ... FEMSigs > + bool _outOfBounds( UIntPack< FEMSigs ... > , const FEMTreeNode* node ) const { - std::vector< std::pair< node_index_type , node_index_type > > _newSampleSpan( newNodeCount ); - for( size_t i=0 ; i() , d , off ); } - - friend class FEMTree< Dim , Real >; - }; - - template< typename T , typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > - struct _ExactPointAndDataInterpolationInfo : public InterpolationInfo< T , PointD > - { - _ExactPointAndDataInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _constraintDual( constraintDual ) , _systemDual( systemDual ) , _constrainsDCTerm( constrainsDCTerm ) { } - - protected: - void _init( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , ConstPointer( Data ) sampleData , bool noRescale ); - - std::vector< std::pair< node_index_type , node_index_type > > _sampleSpan; - std::vector< DualPointAndDataInfo< Dim , Real , Data , T , PointD > > _iData; - bool _constrainsDCTerm; - ConstraintDual _constraintDual; - SystemDual _systemDual; - - void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ) + node_index_type _sNodesBegin( LocalDepth d ) const { return _sNodes.begin( _localToGlobal( d ) ); } + node_index_type _sNodesBegin( LocalDepth d , int slice ) const { return _sNodes.begin( _localToGlobal( d ) , slice + _localInset( d ) ); } + node_index_type _sNodesBeginSlice( LocalDepth d ) const { return _localInset(d); } + node_index_type _sNodesEnd( LocalDepth d ) const { return _sNodes.end ( _localToGlobal( d ) ); } + node_index_type _sNodesEnd( LocalDepth d , int slice ) const { return _sNodes.end ( _localToGlobal( d ) , slice + _localInset( d ) ); } + node_index_type _sNodesEndSlice( LocalDepth d ) const{ return ( 1<<_localToGlobal(d) ) - _localInset(d) - 1; } + size_t _sNodesSize( LocalDepth d ) const { return _sNodes.size( _localToGlobal( d ) ); } + size_t _sNodesSize( LocalDepth d , int slice ) const { return _sNodes.size( _localToGlobal( d ) , slice + _localInset( d ) ); } + + template< unsigned int ... FEMDegrees > static bool _IsSupported( UIntPack< FEMDegrees ... > , LocalDepth femDepth , const LocalOffset femOffset , LocalDepth spaceDepth , const LocalOffset spaceOffset){ return BaseFEMIntegrator::IsSupported( UIntPack< FEMDegrees ... >() , femDepth , femOffset , spaceDepth , spaceOffset ); } + template< unsigned int ... FEMDegrees > bool _isSupported( UIntPack< FEMDegrees ... > , const FEMTreeNode *femNode , const FEMTreeNode *spaceNode ) const { - std::vector< std::pair< node_index_type , node_index_type > > _newSampleSpan( newNodeCount ); - for( size_t i=0 ; i() , femDepth , femOffset , spaceDepth , spaceOffset ); } - friend class FEMTree< Dim , Real >; - }; - - template< typename T , typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > - struct ExactPointAndDataInterpolationInfo : public _ExactPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual > - { - using _ExactPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >::_sampleSpan; - using _ExactPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >::_constrainsDCTerm; - using _ExactPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >::_iData; - using _ExactPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >::_constraintDual; - using _ExactPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >::_systemDual; - void range( const FEMTreeNode* node , size_t& begin , size_t& end ) const { begin = _sampleSpan[ node->nodeData.nodeIndex ].first , end = _sampleSpan[ node->nodeData.nodeIndex ].second; } - bool constrainsDCTerm( void ) const { return _constrainsDCTerm; } - const DualPointInfo< Dim , Real , T , PointD >& operator[]( size_t pointIdx ) const { return _iData[ pointIdx ].pointInfo; } - Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( _iData[ pointIdx ].pointInfo.position , _iData[ pointIdx ].data ); } - Point< T , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< T , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( _iData[ pointIdx ].pointInfo.position , _iData[ pointIdx ].data , dValues ); } - Point< double , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< double , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( _iData[ pointIdx ].pointInfo.position , _iData[ (int)pointIdx ].data , dValues ); } - - ExactPointAndDataInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _ExactPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >( constraintDual , systemDual , constrainsDCTerm ) { } - }; - - template< typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > - struct ExactPointAndDataInterpolationInfo< double , Data , PointD , ConstraintDual , SystemDual > : public _ExactPointAndDataInterpolationInfo< double , Data , PointD , ConstraintDual , SystemDual > - { - using _ExactPointAndDataInterpolationInfo< double , Data , PointD , ConstraintDual , SystemDual >::_sampleSpan; - using _ExactPointAndDataInterpolationInfo< double , Data , PointD , ConstraintDual , SystemDual >::_constrainsDCTerm; - using _ExactPointAndDataInterpolationInfo< double , Data , PointD , ConstraintDual , SystemDual >::_iData; - using _ExactPointAndDataInterpolationInfo< double , Data , PointD , ConstraintDual , SystemDual >::_constraintDual; - using _ExactPointAndDataInterpolationInfo< double , Data , PointD , ConstraintDual , SystemDual >::_systemDual; - void range( const FEMTreeNode* node , size_t& begin , size_t& end ) const { begin = _sampleSpan[ node->nodeData.nodeIndex ].first , end = _sampleSpan[ node->nodeData.nodeIndex ].second; } - bool constrainsDCTerm( void ) const { return _constrainsDCTerm; } - const DualPointInfo< Dim , Real , double , PointD >& operator[]( size_t pointIdx ) const { return _iData[ pointIdx ].pointInfo; } - Point< double , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx ) const { return _constraintDual( _iData[ pointIdx ].pointInfo.position , _iData[ pointIdx ].data ); } - Point< double , CumulativeDerivatives< Dim , PointD >::Size > operator() ( size_t pointIdx , const Point< double , CumulativeDerivatives< Dim , PointD >::Size >& dValues ) const { return _systemDual( _iData[ pointIdx ].pointInfo.position , _iData[ (int)pointIdx ].data , dValues ); } - - ExactPointAndDataInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _ExactPointAndDataInterpolationInfo< double , Data , PointD , ConstraintDual , SystemDual >( constraintDual , systemDual , constrainsDCTerm ) { } - }; - - template< typename T , unsigned int PointD , typename ConstraintDual , typename SystemDual > - static ApproximatePointInterpolationInfo< T , PointD , ConstraintDual , SystemDual >* InitializeApproximatePointInterpolationInfo( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm , LocalDepth maxDepth , int adaptiveExponent ) - { - ApproximatePointInterpolationInfo< T , PointD , ConstraintDual , SystemDual >* a = new ApproximatePointInterpolationInfo< T , PointD , ConstraintDual , SystemDual >( constraintDual , systemDual , constrainsDCTerm ); - a->iData = tree._densifyInterpolationInfoAndSetDualConstraints< T , PointD >( samples , constraintDual , maxDepth , adaptiveExponent ); - return a; - } - template< typename T , typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > - static ApproximatePointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >* InitializeApproximatePointAndDataInterpolationInfo( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , ConstPointer( Data ) sampleData , ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm , LocalDepth maxDepth , int adaptiveExponent ) - { - ApproximatePointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >* a = new ApproximatePointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >( constraintDual , systemDual , constrainsDCTerm ); - a->iData = tree._densifyInterpolationInfoAndSetDualConstraints< T , Data , PointD >( samples , sampleData , constraintDual , maxDepth , adaptiveExponent ); - return a; - } - - template< typename T , unsigned int PointD , typename ConstraintDual , typename SystemDual > - static ExactPointInterpolationInfo< T , PointD , ConstraintDual , SystemDual >* InitializeExactPointInterpolationInfo( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm , bool noRescale ) - { - ExactPointInterpolationInfo< T , PointD , ConstraintDual , SystemDual >* e = new ExactPointInterpolationInfo< T , PointD , ConstraintDual , SystemDual >( constraintDual , systemDual , constrainsDCTerm ); - e->_init( tree , samples , noRescale ); - return e; - } - template< typename T , typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > - static ExactPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >* InitializeExactPointAndDataInterpolationInfo( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , ConstPointer( Data ) sampleData , ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm , bool noRescale ) - { - ExactPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >* e = new ExactPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >( constraintDual , systemDual , constrainsDCTerm ); - e->_init( tree , samples , sampleData , noRescale ); - return e; - } - - template< typename T , unsigned int PointD , typename ConstraintDual , typename SystemDual > friend struct ExactPointInterpolationInfo; - template< typename T , typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > friend struct ExactPointAndDataInterpolationInfo; - - template< typename ... InterpolationInfos > - static bool ConstrainsDCTerm( std::tuple< InterpolationInfos *... > interpolationInfos ){ return _ConstrainsDCTerm< 0 >( interpolationInfos ); } -protected: - template< unsigned int Idx , typename ... InterpolationInfos > - static typename std::enable_if< ( Idx==sizeof...(InterpolationInfos) ) , bool >::type _ConstrainsDCTerm( std::tuple< InterpolationInfos *... > interpolationInfos ){ return false; } - template< unsigned int Idx , typename ... InterpolationInfos > - static typename std::enable_if< ( Idx ::type _ConstrainsDCTerm( std::tuple< InterpolationInfos *... > interpolationInfos ) - { - if( std::get< Idx >( interpolationInfos ) ) return _ConstrainsDCTerm< Idx+1 >( interpolationInfos ) || std::get< Idx >( interpolationInfos )->constrainsDCTerm(); - else return _ConstrainsDCTerm< Idx+1 >( interpolationInfos ); - } -public: - -#ifdef SHOW_WARNINGS -#pragma message( "[WARNING] This should not be isotropic" ) -#endif // SHOW_WARNINGS - template< unsigned int DensityDegree > struct DensityEstimator : public SparseNodeData< Real , IsotropicUIntPack< Dim , FEMDegreeAndBType< DensityDegree >::Signature > > - { - DensityEstimator( int kernelDepth , int coDimension , Real samplesPerNode ) : _kernelDepth( kernelDepth ) , _coDimension( coDimension ) , _samplesPerNode( samplesPerNode ){ } - Real samplesPerNode( void ) const { return _samplesPerNode; } - int coDimension( void ) const { return _coDimension; } - int kernelDepth( void ) const { return _kernelDepth; } + template< unsigned int FEMDegree > static bool _IsInteriorlySupported( LocalDepth depth , const LocalOffset off ) + { + if( depth>=0 ) + { + int begin , end; + BSplineSupportSizes< FEMDegree >::InteriorSupportedSpan( depth , begin , end ); + bool interior = true; + for( int dd=0 ; dd=begin && off[dd] bool _isInteriorlySupported( const FEMTreeNode* node ) const { - stream.write( _kernelDepth ); - stream.write( _coDimension ); - stream.write( _samplesPerNode ); - SparseNodeData< Real , IsotropicUIntPack< Dim , FEMDegreeAndBType< DensityDegree >::Signature > >::write( stream ); + if( !node ) return false; + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + return _IsInteriorlySupported< FEMDegree >( d , off ); } - void read( BinaryStream &stream ) + template< unsigned int ... FEMDegrees > static bool _IsInteriorlySupported( UIntPack< FEMDegrees ... > , LocalDepth depth , const LocalOffset off ){ return BaseFEMIntegrator::IsInteriorlySupported( UIntPack< FEMDegrees ... >() , depth , off ); } + template< unsigned int ... FEMDegrees > bool _isInteriorlySupported( UIntPack< FEMDegrees ... > , const FEMTreeNode* node ) const { - if( !stream.read( _kernelDepth ) ) ERROR_OUT( "Failed to read _kernelDepth" ); - if( !stream.read( _coDimension ) ) ERROR_OUT( "Failed to read _coDimension" ); - if( !stream.read( _samplesPerNode ) ) ERROR_OUT( "Failed to read _samplesPerNode" ); - SparseNodeData< Real , IsotropicUIntPack< Dim , FEMDegreeAndBType< DensityDegree >::Signature > >::read( stream ); + if( !node ) return false; + LocalDepth d ; LocalOffset off ; _localDepthAndOffset( node , d , off ); + return _IsInteriorlySupported< FEMDegrees ... >( UIntPack< FEMDegrees ... >() , d , off ); + } + template< unsigned int FEMDegree1 , unsigned int FEMDegree2 > static bool _IsInteriorlyOverlapped( LocalDepth depth , const LocalOffset off ) + { + if( depth>=0 ) + { + int begin , end; + BSplineIntegrationData< FEMDegreeAndBType< FEMDegree1 , BOUNDARY_NEUMANN >::Signature , FEMDegreeAndBType< FEMDegree2 , BOUNDARY_NEUMANN >::Signature >::InteriorOverlappedSpan( depth , begin , end ); + bool interior = true; + for( int dd=0 ; dd=begin && off[dd]( node ) && ( node->nodeData.flags & FEMTreeNodeData::SPACE_FLAG ); } - bool _isValidFEM1Node ( const FEMTreeNode* node ) const { return !GetGhostFlag< Dim >( node ) && ( node->nodeData.flags & FEMTreeNodeData::FEM_FLAG_1 ); } - bool _isValidFEM2Node ( const FEMTreeNode* node ) const { return !GetGhostFlag< Dim >( node ) && ( node->nodeData.flags & FEMTreeNodeData::FEM_FLAG_2 ); } - - FEMTreeNode _tree; - mutable FEMTreeNode* _spaceRoot; - SortedTreeNodes< Dim > _sNodes; - LocalDepth _maxDepth; - int _depthOffset; - LocalDepth _baseDepth; -#ifdef USE_EXACT_PROLONGATION - LocalDepth _exactDepth; -#endif // USE_EXACT_PROLONGATION - mutable unsigned int _femSigs1[ Dim ]; - mutable unsigned int _femSigs2[ Dim ]; - void _init( void ); - - static bool _InBounds( Point< Real , Dim > p ); - int _localToGlobal( LocalDepth d ) const { return d + _depthOffset; } - LocalDepth _globalToLocal( int d ) const { return d - _depthOffset; } - LocalDepth _localDepth( const FEMTreeNode* node ) const { return node->depth() - _depthOffset; } - int _localInset( LocalDepth d ) const { return _depthOffset==0 ? 0 : 1<<( d + _depthOffset - 1 ); } - void _localDepthAndOffset( const FEMTreeNode* node , LocalDepth& d , LocalOffset& off ) const - { - node->depthAndOffset( d , off ) ; d -= _depthOffset; - int inset = _localInset( d ); - for( int d=0 ; d static int _BSplineBegin( LocalDepth depth ){ return BSplineEvaluationData< FEMSig >::Begin( depth ); } - template< unsigned int FEMSig > static int _BSplineEnd ( LocalDepth depth ){ return BSplineEvaluationData< FEMSig >::End ( depth ); } - template< unsigned int ... FEMSigs > - bool _outOfBounds( UIntPack< FEMSigs ... > , const FEMTreeNode* node ) const - { - if( !node ) return true; - LocalDepth d ; LocalOffset off ; _localDepthAndOffset( node , d , off ); - return FEMIntegrator::IsOutOfBounds( UIntPack< FEMSigs ... >() , d , off ); - } - node_index_type _sNodesBegin( LocalDepth d ) const { return _sNodes.begin( _localToGlobal( d ) ); } - node_index_type _sNodesBegin( LocalDepth d , int slice ) const { return _sNodes.begin( _localToGlobal( d ) , slice + _localInset( d ) ); } - node_index_type _sNodesBeginSlice( LocalDepth d ) const { return _localInset(d); } - node_index_type _sNodesEnd( LocalDepth d ) const { return _sNodes.end ( _localToGlobal( d ) ); } - node_index_type _sNodesEnd( LocalDepth d , int slice ) const { return _sNodes.end ( _localToGlobal( d ) , slice + _localInset( d ) ); } - node_index_type _sNodesEndSlice( LocalDepth d ) const{ return ( 1<<_localToGlobal(d) ) - _localInset(d) - 1; } - size_t _sNodesSize( LocalDepth d ) const { return _sNodes.size( _localToGlobal( d ) ); } - size_t _sNodesSize( LocalDepth d , int slice ) const { return _sNodes.size( _localToGlobal( d ) , slice + _localInset( d ) ); } - - template< unsigned int ... FEMDegrees > static bool _IsSupported( UIntPack< FEMDegrees ... > , LocalDepth femDepth , const LocalOffset femOffset , LocalDepth spaceDepth , const LocalOffset spaceOffset){ return BaseFEMIntegrator::IsSupported( UIntPack< FEMDegrees ... >() , femDepth , femOffset , spaceDepth , spaceOffset ); } - template< unsigned int ... FEMDegrees > bool _isSupported( UIntPack< FEMDegrees ... > , const FEMTreeNode *femNode , const FEMTreeNode *spaceNode ) const - { - if( !femNode || !spaceNode ) return false; - LocalDepth femDepth , spaceDepth ; LocalOffset femOffset , spaceOffset; - _localDepthAndOffset( femNode , femDepth , femOffset ) , _localDepthAndOffset( spaceNode , spaceDepth , spaceOffset ); - return _IsSupported( UIntPack< FEMDegrees ... >() , femDepth , femOffset , spaceDepth , spaceOffset ); - } + template< unsigned int FEMDegree1 , unsigned int FEMDegree2 > bool _isInteriorlyOverlapped( const FEMTreeNode* node ) const + { + if( !node ) return false; + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + return _IsInteriorlyOverlapped< FEMDegree1 , FEMDegree2 >( d , off ); + } + template< unsigned int ... FEMDegrees1 , unsigned int ... FEMDegrees2 > static bool _IsInteriorlyOverlapped( UIntPack< FEMDegrees1 ... > , UIntPack< FEMDegrees2 ... > , LocalDepth depth , const LocalOffset off ){ return BaseFEMIntegrator::IsInteriorlyOverlapped( UIntPack< FEMDegrees1 ... >() , UIntPack< FEMDegrees2 ... >() , depth , off ); } + template< unsigned int ... FEMDegrees1 , unsigned int ... FEMDegrees2 > bool _isInteriorlyOverlapped( UIntPack< FEMDegrees1 ... > , UIntPack< FEMDegrees2 ... > , const FEMTreeNode* node ) const + { + if( !node ) return false; + LocalDepth d ; LocalOffset off ; _localDepthAndOffset( node , d , off ); + return _IsInteriorlyOverlapped( UIntPack< FEMDegrees1 ... >() , UIntPack< FEMDegrees2 ... >() , d , off ); + } - template< unsigned int FEMDegree > static bool _IsInteriorlySupported( LocalDepth depth , const LocalOffset off ) - { - if( depth>=0 ) + void _startAndWidth( const FEMTreeNode* node , Point< Real , Dim >& start , Real& width ) const { - int begin , end; - BSplineSupportSizes< FEMDegree >::InteriorSupportedSpan( depth , begin , end ); - bool interior = true; - for( int dd=0 ; dd=begin && off[dd]=0 ) width = Real( 1.0 / (1<< d ) ); + else width = Real( 1.0 * (1<<(-d)) ); + for( int dd=0 ; dd bool _isInteriorlySupported( const FEMTreeNode* node ) const - { - if( !node ) return false; - LocalDepth d ; LocalOffset off; - _localDepthAndOffset( node , d , off ); - return _IsInteriorlySupported< FEMDegree >( d , off ); - } - template< unsigned int ... FEMDegrees > static bool _IsInteriorlySupported( UIntPack< FEMDegrees ... > , LocalDepth depth , const LocalOffset off ){ return BaseFEMIntegrator::IsInteriorlySupported( UIntPack< FEMDegrees ... >() , depth , off ); } - template< unsigned int ... FEMDegrees > bool _isInteriorlySupported( UIntPack< FEMDegrees ... > , const FEMTreeNode* node ) const - { - if( !node ) return false; - LocalDepth d ; LocalOffset off ; _localDepthAndOffset( node , d , off ); - return _IsInteriorlySupported< FEMDegrees ... >( UIntPack< FEMDegrees ... >() , d , off ); - } - template< unsigned int FEMDegree1 , unsigned int FEMDegree2 > static bool _IsInteriorlyOverlapped( LocalDepth depth , const LocalOffset off ) - { - if( depth>=0 ) + void _centerAndWidth( const FEMTreeNode* node , Point< Real , Dim >& center , Real& width ) const { - int begin , end; - BSplineIntegrationData< FEMDegreeAndBType< FEMDegree1 , BOUNDARY_NEUMANN >::Signature , FEMDegreeAndBType< FEMDegree2 , BOUNDARY_NEUMANN >::Signature >::InteriorOverlappedSpan( depth , begin , end ); - bool interior = true; - for( int dd=0 ; dd=begin && off[dd] bool _isInteriorlyOverlapped( const FEMTreeNode* node ) const - { - if( !node ) return false; - LocalDepth d ; LocalOffset off; - _localDepthAndOffset( node , d , off ); - return _IsInteriorlyOverlapped< FEMDegree1 , FEMDegree2 >( d , off ); - } - template< unsigned int ... FEMDegrees1 , unsigned int ... FEMDegrees2 > static bool _IsInteriorlyOverlapped( UIntPack< FEMDegrees1 ... > , UIntPack< FEMDegrees2 ... > , LocalDepth depth , const LocalOffset off ){ return BaseFEMIntegrator::IsInteriorlyOverlapped( UIntPack< FEMDegrees1 ... >() , UIntPack< FEMDegrees2 ... >() , depth , off ); } - template< unsigned int ... FEMDegrees1 , unsigned int ... FEMDegrees2 > bool _isInteriorlyOverlapped( UIntPack< FEMDegrees1 ... > , UIntPack< FEMDegrees2 ... > , const FEMTreeNode* node ) const - { - if( !node ) return false; - LocalDepth d ; LocalOffset off ; _localDepthAndOffset( node , d , off ); - return _IsInteriorlyOverlapped( UIntPack< FEMDegrees1 ... >() , UIntPack< FEMDegrees2 ... >() , d , off ); - } + int _childIndex( const FEMTreeNode* node , Point< Real , Dim > p ) const + { + Point< Real , Dim > c ; Real w; + _centerAndWidth( node , c , w ); + int cIdx = 0; + for( int d=0 ; d=c[d] ) cIdx |= (1<& 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 void _setFullDepth( UIntPack< Degrees ... > , Allocator< FEMTreeNode > *nodeAllocator , FEMTreeNode* node , LocalDepth depth ); + template< bool ThreadSafe , unsigned int ... Degrees > void _setFullDepth( UIntPack< Degrees ... > , Allocator< FEMTreeNode > *nodeAllocator , LocalDepth depth ); + template< unsigned int ... Degrees > LocalDepth _getFullDepth( UIntPack< Degrees ... > , const FEMTreeNode* node ) const; + template< unsigned int ... Degrees > LocalDepth _getFullDepth( UIntPack< Degrees ... > , const LocalDepth depth , const LocalOffset begin , const LocalOffset end , const FEMTreeNode *node ) const; - void _centerAndWidth( const FEMTreeNode* node , Point< Real , Dim >& center , Real& width ) const - { - int d , off[Dim]; - _localDepthAndOffset( node , d , off ); - width = Real( 1.0 / (1< void _refine( UIntPack< Degrees ... > , Allocator< FEMTreeNode > *nodeAllocator , const AddNodeFunctor &addNodeFunctor , FEMTreeNode *node ); + template< bool ThreadSafe , typename AddNodeFunctor , unsigned int ... Degrees > void _refine( UIntPack< Degrees ... > , Allocator< FEMTreeNode > *nodeAllocator , const AddNodeFunctor &addNodeFunctor ); - int _childIndex( const FEMTreeNode* node , Point< Real , Dim > p ) const - { - Point< Real , Dim > c ; Real w; - _centerAndWidth( node , c , w ); - int cIdx = 0; - for( int d=0 ; d=c[d] ) cIdx |= (1< LocalDepth getFullDepth( UIntPack< Degrees ... > ) const; + template< unsigned int ... Degrees > LocalDepth getFullDepth( UIntPack< Degrees ... > , const LocalDepth depth , const LocalOffset begin , const LocalOffset end ) const; + + LocalDepth depth( const FEMTreeNode* node ) const { return _localDepth( node ); } + void depthAndOffset( const FEMTreeNode* node , LocalDepth& depth , LocalOffset& offset ) const { _localDepthAndOffset( node , depth , offset ); } + + size_t nodesSize( void ) const { return _sNodes.size(); } + node_index_type nodesBegin( LocalDepth d ) const { return _sNodes.begin( _localToGlobal( d ) ); } + node_index_type nodesEnd ( LocalDepth d ) const { return _sNodes.end ( _localToGlobal( d ) ); } + size_t nodesSize ( LocalDepth d ) const { return _sNodes.size ( _localToGlobal( d ) ); } + node_index_type nodesBegin( LocalDepth d , int slice ) const { return _sNodes.begin( _localToGlobal( d ) , slice + _localInset( d ) ); } + node_index_type nodesEnd ( LocalDepth d , int slice ) const { return _sNodes.end ( _localToGlobal( d ) , slice + _localInset( d ) ); } + size_t nodesSize ( LocalDepth d , int slice ) const { return _sNodes.size ( _localToGlobal( d ) , slice + _localInset( d ) ); } + const FEMTreeNode* node( node_index_type idx ) const { return _sNodes.treeNodes[idx]; } + void centerAndWidth( node_index_type idx , Point< Real , Dim >& center , Real& width ) const { _centerAndWidth( _sNodes.treeNodes[idx] , center , width ); } + void startAndWidth( node_index_type idx , Point< Real , Dim >& center , Real& width ) const { _startAndWidth( _sNodes.treeNodes[idx] , center , width ); } + void centerAndWidth( const FEMTreeNode* node , Point< Real , Dim >& center , Real& width ) const { _centerAndWidth( node , center , width ); } + void startAndWidth( const FEMTreeNode* node , Point< Real , Dim >& start , Real& width ) const { _startAndWidth( node , start , width ); } - template< bool ThreadSafe , unsigned int ... Degrees > void _setFullDepth( UIntPack< Degrees ... > , Allocator< FEMTreeNode > *nodeAllocator , FEMTreeNode* node , LocalDepth depth ); - template< bool ThreadSafe , unsigned int ... Degrees > void _setFullDepth( UIntPack< Degrees ... > , Allocator< FEMTreeNode > *nodeAllocator , LocalDepth depth ); - template< unsigned int ... Degrees > LocalDepth _getFullDepth( UIntPack< Degrees ... > , const FEMTreeNode* node ) const; - template< unsigned int ... Degrees > LocalDepth _getFullDepth( UIntPack< Degrees ... > , const LocalDepth depth , const LocalOffset begin , const LocalOffset end , const FEMTreeNode *node ) const; - - template< bool ThreadSafe , typename AddNodeFunctor , unsigned int ... Degrees > void _refine( UIntPack< Degrees ... > , Allocator< FEMTreeNode > *nodeAllocator , const AddNodeFunctor &addNodeFunctor , FEMTreeNode *node ); - template< bool ThreadSafe , typename AddNodeFunctor , unsigned int ... Degrees > void _refine( UIntPack< Degrees ... > , Allocator< FEMTreeNode > *nodeAllocator , const AddNodeFunctor &addNodeFunctor ); - -public: - template< unsigned int ... Degrees > LocalDepth getFullDepth( UIntPack< Degrees ... > ) const; - template< unsigned int ... Degrees > LocalDepth getFullDepth( UIntPack< Degrees ... > , const LocalDepth depth , const LocalOffset begin , const LocalOffset end ) const; - - LocalDepth depth( const FEMTreeNode* node ) const { return _localDepth( node ); } - void depthAndOffset( const FEMTreeNode* node , LocalDepth& depth , LocalOffset& offset ) const { _localDepthAndOffset( node , depth , offset ); } - - size_t nodesSize( void ) const { return _sNodes.size(); } - node_index_type nodesBegin( LocalDepth d ) const { return _sNodes.begin( _localToGlobal( d ) ); } - node_index_type nodesEnd ( LocalDepth d ) const { return _sNodes.end ( _localToGlobal( d ) ); } - size_t nodesSize ( LocalDepth d ) const { return _sNodes.size ( _localToGlobal( d ) ); } - node_index_type nodesBegin( LocalDepth d , int slice ) const { return _sNodes.begin( _localToGlobal( d ) , slice + _localInset( d ) ); } - node_index_type nodesEnd ( LocalDepth d , int slice ) const { return _sNodes.end ( _localToGlobal( d ) , slice + _localInset( d ) ); } - size_t nodesSize ( LocalDepth d , int slice ) const { return _sNodes.size ( _localToGlobal( d ) , slice + _localInset( d ) ); } - const FEMTreeNode* node( node_index_type idx ) const { return _sNodes.treeNodes[idx]; } - void centerAndWidth( node_index_type idx , Point< Real , Dim >& center , Real& width ) const { _centerAndWidth( _sNodes.treeNodes[idx] , center , width ); } - void startAndWidth( node_index_type idx , Point< Real , Dim >& center , Real& width ) const { _startAndWidth( _sNodes.treeNodes[idx] , center , width ); } - void centerAndWidth( const FEMTreeNode* node , Point< Real , Dim >& center , Real& width ) const { _centerAndWidth( node , center , width ); } - void startAndWidth( const FEMTreeNode* node , Point< Real , Dim >& start , Real& width ) const { _startAndWidth( node , start , width ); } - -protected: - ///////////////////////////////////// - // System construction code // - // MultiGridFEMTreeData.System.inl // - ///////////////////////////////////// -public: - template< unsigned int ... FEMSigs > void setMultiColorIndices( UIntPack< FEMSigs ... > , int depth , std::vector< std::vector< size_t > >& indices ) const; -protected: - template< unsigned int ... FEMSigs > void _setMultiColorIndices( UIntPack< FEMSigs ... > , node_index_type start , node_index_type end , std::vector< std::vector< size_t > >& indices ) const; - - struct _SolverStats - { - double constraintUpdateTime , systemTime , solveTime; - double bNorm2 , inRNorm2 , outRNorm2; - }; + protected: + ///////////////////////////////////// + // System construction code // + // MultiGridFEMTreeData.System.inl // + ///////////////////////////////////// + public: + template< unsigned int ... FEMSigs > void setMultiColorIndices( UIntPack< FEMSigs ... > , int depth , std::vector< std::vector< size_t > >& indices ) const; + protected: + template< unsigned int ... FEMSigs > void _setMultiColorIndices( UIntPack< FEMSigs ... > , node_index_type start , node_index_type end , std::vector< std::vector< size_t > >& indices ) const; - // For some reason MSVC has trouble determining the template parameters when using: - // template< unsigned int Idx , unsigned int ... FEMSigs , typename ... InterpolationInfos > - template< unsigned int Idx , typename UIntPackFEMSigs , typename StaticWindow , typename ConstNeighbors , typename PointEvaluator , typename ... InterpolationInfos > - typename std::enable_if< ( Idx==sizeof...(InterpolationInfos) ) >::type _addPointValues( UIntPackFEMSigs , StaticWindow &pointValues , const ConstNeighbors &neighbors , const PointEvaluator &bsData , std::tuple< InterpolationInfos *... > interpolationInfos ) const {} - template< unsigned int Idx , typename UIntPackFEMSigs , typename StaticWindow , typename ConstNeighbors , typename PointEvaluator , typename ... InterpolationInfos > - typename std::enable_if< ( Idx ::type _addPointValues( UIntPackFEMSigs , StaticWindow &pointValues , const ConstNeighbors &neighbors , const PointEvaluator &bsData , std::tuple< InterpolationInfos *... > interpolationInfos ) const - { - _addPointValues( UIntPackFEMSigs() , pointValues , neighbors , bsData , std::get< Idx >( interpolationInfos ) ); - _addPointValues< Idx+1 >( UIntPackFEMSigs() , pointValues , neighbors , bsData , interpolationInfos ); - } - template< unsigned int ... FEMSigs , typename T , unsigned int PointD > - void _addPointValues( UIntPack< FEMSigs ... > , StaticWindow< Real , UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& pointValues , const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& neighbors , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , const InterpolationInfo< T , PointD >* interpolationInfo ) const; + struct _SolverStats + { + double constraintUpdateTime , systemTime , solveTime; + double bNorm2 , inRNorm2 , outRNorm2; + }; - template< unsigned int Idx , typename UIntPackFEMSigs , typename WindowSlice , typename ConstNeighbors , typename PointEvaluator , typename ... InterpolationInfos > - typename std::enable_if< ( Idx==sizeof...(InterpolationInfos) ) >::type _addProlongedPointValues( UIntPackFEMSigs , WindowSlice pointValues , const ConstNeighbors &neighbors , const ConstNeighbors &pNeighbors , const PointEvaluator &bsData , std::tuple< InterpolationInfos *... > interpolationInfos ) const {} - template< unsigned int Idx , typename UIntPackFEMSigs , typename WindowSlice , typename ConstNeighbors , typename PointEvaluator , typename ... InterpolationInfos > - typename std::enable_if< ( Idx ::type _addProlongedPointValues( UIntPackFEMSigs , WindowSlice pointValues , const ConstNeighbors &neighbors , const ConstNeighbors &pNeighbors , const PointEvaluator&bsData , std::tuple< InterpolationInfos *... > interpolationInfos ) const - { - _addProlongedPointValues( UIntPackFEMSigs() , pointValues , neighbors , pNeighbors , bsData , std::get< Idx >( interpolationInfos ) ); - _addProlongedPointValues< Idx+1 >( UIntPackFEMSigs() , pointValues , neighbors , pNeighbors , bsData , interpolationInfos ); - } - template< unsigned int ... FEMSigs , typename T , unsigned int PointD > - void _addProlongedPointValues( UIntPack< FEMSigs ... > , WindowSlice< Real , UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > > pointValues , const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& neighbors , const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& pNeighbors , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , const InterpolationInfo< T , PointD >* iInfo ) const; + // For some reason MSVC has trouble determining the template parameters when using: + // template< unsigned int Idx , unsigned int ... FEMSigs , typename ... InterpolationInfos > + template< unsigned int Idx , typename UIntPackFEMSigs , typename StaticWindow , typename ConstNeighbors , typename PointEvaluator , typename ... InterpolationInfos > + typename std::enable_if< ( Idx==sizeof...(InterpolationInfos) ) >::type _addPointValues( UIntPackFEMSigs , StaticWindow &pointValues , const ConstNeighbors &neighbors , const PointEvaluator &bsData , std::tuple< InterpolationInfos *... > interpolationInfos ) const {} + template< unsigned int Idx , typename UIntPackFEMSigs , typename StaticWindow , typename ConstNeighbors , typename PointEvaluator , typename ... InterpolationInfos > + typename std::enable_if< ( Idx ::type _addPointValues( UIntPackFEMSigs , StaticWindow &pointValues , const ConstNeighbors &neighbors , const PointEvaluator &bsData , std::tuple< InterpolationInfos *... > interpolationInfos ) const + { + _addPointValues( UIntPackFEMSigs() , pointValues , neighbors , bsData , std::get< Idx >( interpolationInfos ) ); + _addPointValues< Idx+1 >( UIntPackFEMSigs() , pointValues , neighbors , bsData , interpolationInfos ); + } + template< unsigned int ... FEMSigs , typename T , unsigned int PointD > + void _addPointValues( UIntPack< FEMSigs ... > , StaticWindow< Real , UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& pointValues , const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& neighbors , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , const InterpolationInfo< T , PointD >* interpolationInfo ) const; - template< unsigned int Idx , typename PointEvaluator , typename T , typename ... InterpolationInfos > - typename std::enable_if< ( Idx==sizeof...(InterpolationInfos) ) >::type _setPointValuesFromProlongedSolution( LocalDepth highDepth , const PointEvaluator &bsData , ConstPointer( T ) prolongedSolution , std::tuple< InterpolationInfos *... > interpolationInfos ) const {} - template< unsigned int Idx , typename PointEvaluator , typename T , typename ... InterpolationInfos > - typename std::enable_if< ( Idx ::type _setPointValuesFromProlongedSolution( LocalDepth highDepth , const PointEvaluator &bsData , ConstPointer( T ) prolongedSolution , std::tuple< InterpolationInfos *... > interpolationInfos ) const - { - _setPointValuesFromProlongedSolution( highDepth , bsData , prolongedSolution , std::get< Idx >( interpolationInfos ) ); - _setPointValuesFromProlongedSolution< Idx+1 >( highDepth , bsData , prolongedSolution , interpolationInfos ); - } - template< unsigned int ... FEMSigs , typename T , unsigned int PointD > - void _setPointValuesFromProlongedSolution( LocalDepth highDepth , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , ConstPointer( T ) prolongedSolution , InterpolationInfo< T , PointD >* interpolationInfo ) const; + template< unsigned int Idx , typename UIntPackFEMSigs , typename WindowSlice , typename ConstNeighbors , typename PointEvaluator , typename ... InterpolationInfos > + typename std::enable_if< ( Idx==sizeof...(InterpolationInfos) ) >::type _addProlongedPointValues( UIntPackFEMSigs , WindowSlice pointValues , const ConstNeighbors &neighbors , const ConstNeighbors &pNeighbors , const PointEvaluator &bsData , std::tuple< InterpolationInfos *... > interpolationInfos ) const {} + template< unsigned int Idx , typename UIntPackFEMSigs , typename WindowSlice , typename ConstNeighbors , typename PointEvaluator , typename ... InterpolationInfos > + typename std::enable_if< ( Idx ::type _addProlongedPointValues( UIntPackFEMSigs , WindowSlice pointValues , const ConstNeighbors &neighbors , const ConstNeighbors &pNeighbors , const PointEvaluator&bsData , std::tuple< InterpolationInfos *... > interpolationInfos ) const + { + _addProlongedPointValues( UIntPackFEMSigs() , pointValues , neighbors , pNeighbors , bsData , std::get< Idx >( interpolationInfos ) ); + _addProlongedPointValues< Idx+1 >( UIntPackFEMSigs() , pointValues , neighbors , pNeighbors , bsData , interpolationInfos ); + } + template< unsigned int ... FEMSigs , typename T , unsigned int PointD > + void _addProlongedPointValues( UIntPack< FEMSigs ... > , WindowSlice< Real , UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > > pointValues , const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& neighbors , const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& pNeighbors , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , const InterpolationInfo< T , PointD >* iInfo ) const; - template< unsigned int Idx , typename ConstNeighbors , typename T , typename PointEvaluator , typename ... InterpolationInfos > - typename std::enable_if< ( Idx==sizeof...(InterpolationInfos) ) , T >::type _getInterpolationConstraintFromProlongedSolution( const ConstNeighbors &neighbors , const FEMTreeNode* node , ConstPointer( T ) prolongedSolution , const PointEvaluator &bsData , std::tuple< InterpolationInfos ... > interpolationInfos ) const { return T{}; } - template< unsigned int Idx , typename ConstNeighbors , typename T , typename PointEvaluator , typename ... InterpolationInfos > - typename std::enable_if< ( Idx ::type _getInterpolationConstraintFromProlongedSolution( const ConstNeighbors &neighbors , const FEMTreeNode* node , ConstPointer( T ) prolongedSolution , const PointEvaluator &bsData , std::tuple< InterpolationInfos ... > interpolationInfos ) const - { - return - _getInterpolationConstraintFromProlongedSolution( neighbors , node , prolongedSolution , bsData , std::get< Idx >( interpolationInfos ) ) + - _getInterpolationConstraintFromProlongedSolution< Idx+1 >( neighbors , node , prolongedSolution , bsData , interpolationInfos ); - } - template< unsigned int ... FEMSigs , typename T , unsigned int PointD > - T _getInterpolationConstraintFromProlongedSolution( const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& neighbors , const FEMTreeNode* node , ConstPointer( T ) prolongedSolution , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , const InterpolationInfo< T , PointD >* iInfo ) const; + template< unsigned int Idx , typename PointEvaluator , typename T , typename ... InterpolationInfos > + typename std::enable_if< ( Idx==sizeof...(InterpolationInfos) ) >::type _setPointValuesFromProlongedSolution( LocalDepth highDepth , const PointEvaluator &bsData , ConstPointer( T ) prolongedSolution , std::tuple< InterpolationInfos *... > interpolationInfos ) const {} + template< unsigned int Idx , typename PointEvaluator , typename T , typename ... InterpolationInfos > + typename std::enable_if< ( Idx ::type _setPointValuesFromProlongedSolution( LocalDepth highDepth , const PointEvaluator &bsData , ConstPointer( T ) prolongedSolution , std::tuple< InterpolationInfos *... > interpolationInfos ) const + { + _setPointValuesFromProlongedSolution( highDepth , bsData , prolongedSolution , std::get< Idx >( interpolationInfos ) ); + _setPointValuesFromProlongedSolution< Idx+1 >( highDepth , bsData , prolongedSolution , interpolationInfos ); + } + template< unsigned int ... FEMSigs , typename T , unsigned int PointD > + void _setPointValuesFromProlongedSolution( LocalDepth highDepth , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , ConstPointer( T ) prolongedSolution , InterpolationInfo< T , PointD >* interpolationInfo ) const; - template< unsigned int Idx , typename PointEvaluator , typename T , typename ... InterpolationInfos > - typename std::enable_if< ( Idx==sizeof...(InterpolationInfos) ) >::type _updateRestrictedInterpolationConstraints( const PointEvaluator &bsData , LocalDepth highDepth , ConstPointer( T ) solution , Pointer( T ) cumulativeConstraints , std::tuple< InterpolationInfos ... > interpolationInfos ) const {} - template< unsigned int Idx , typename PointEvaluator , typename T , typename ... InterpolationInfos > - typename std::enable_if< ( Idx ::type _updateRestrictedInterpolationConstraints( const PointEvaluator &bsData , LocalDepth highDepth , ConstPointer( T ) solution , Pointer( T ) cumulativeConstraints , std::tuple< InterpolationInfos ... > interpolationInfos ) const - { - _updateRestrictedInterpolationConstraints( bsData , highDepth , solution , cumulativeConstraints , std::get< Idx >( interpolationInfos ) ); - _updateRestrictedInterpolationConstraints< Idx+1 >( bsData , highDepth , solution , cumulativeConstraints , interpolationInfos ); - } - template< unsigned int ... FEMSigs , typename T , unsigned int PointD > - void _updateRestrictedInterpolationConstraints( const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , LocalDepth highDepth , ConstPointer( T ) solution , Pointer( T ) cumulativeConstraints , const InterpolationInfo< T , PointD >* interpolationInfo ) const; + template< unsigned int Idx , typename ConstNeighbors , typename T , typename PointEvaluator , typename ... InterpolationInfos > + typename std::enable_if< ( Idx==sizeof...(InterpolationInfos) ) , T >::type _getInterpolationConstraintFromProlongedSolution( const ConstNeighbors &neighbors , const FEMTreeNode* node , ConstPointer( T ) prolongedSolution , const PointEvaluator &bsData , std::tuple< InterpolationInfos ... > interpolationInfos ) const { return T{}; } + template< unsigned int Idx , typename ConstNeighbors , typename T , typename PointEvaluator , typename ... InterpolationInfos > + typename std::enable_if< ( Idx ::type _getInterpolationConstraintFromProlongedSolution( const ConstNeighbors &neighbors , const FEMTreeNode* node , ConstPointer( T ) prolongedSolution , const PointEvaluator &bsData , std::tuple< InterpolationInfos ... > interpolationInfos ) const + { + return + _getInterpolationConstraintFromProlongedSolution( neighbors , node , prolongedSolution , bsData , std::get< Idx >( interpolationInfos ) ) + + _getInterpolationConstraintFromProlongedSolution< Idx+1 >( neighbors , node , prolongedSolution , bsData , interpolationInfos ); + } + template< unsigned int ... FEMSigs , typename T , unsigned int PointD > + T _getInterpolationConstraintFromProlongedSolution( const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& neighbors , const FEMTreeNode* node , ConstPointer( T ) prolongedSolution , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , const InterpolationInfo< T , PointD >* iInfo ) const; - template< unsigned int FEMDegree1 , unsigned int FEMDegree2 > static void _SetParentOverlapBounds( const FEMTreeNode* node , int start[Dim] , int end[Dim] ); - template< unsigned int FEMDegree1 , unsigned int FEMDegree2 > static void _SetParentOverlapBounds( int cIdx , int start[Dim] , int end[Dim] ); - template< unsigned int ... FEMDegrees1 , unsigned int ... FEMDegrees2 > static void _SetParentOverlapBounds( UIntPack< FEMDegrees1 ... > , UIntPack< FEMDegrees2 ... > , const FEMTreeNode* node , int start[Dim] , int end[Dim] ) - { - if( node ) + template< unsigned int Idx , typename PointEvaluator , typename T , typename ... InterpolationInfos > + typename std::enable_if< ( Idx==sizeof...(InterpolationInfos) ) >::type _updateRestrictedInterpolationConstraints( const PointEvaluator &bsData , LocalDepth highDepth , ConstPointer( T ) solution , Pointer( T ) cumulativeConstraints , std::tuple< InterpolationInfos ... > interpolationInfos ) const {} + template< unsigned int Idx , typename PointEvaluator , typename T , typename ... InterpolationInfos > + typename std::enable_if< ( Idx ::type _updateRestrictedInterpolationConstraints( const PointEvaluator &bsData , LocalDepth highDepth , ConstPointer( T ) solution , Pointer( T ) cumulativeConstraints , std::tuple< InterpolationInfos ... > interpolationInfos ) const { - int d , off[Dim] ; node->depthAndOffset( d , off ); - BaseFEMIntegrator::template ParentOverlapBounds( UIntPack< FEMDegrees1 ... >() , UIntPack< FEMDegrees2 ... >() , d , off , start , end ); + _updateRestrictedInterpolationConstraints( bsData , highDepth , solution , cumulativeConstraints , std::get< Idx >( interpolationInfos ) ); + _updateRestrictedInterpolationConstraints< Idx+1 >( bsData , highDepth , solution , cumulativeConstraints , interpolationInfos ); } - } - template< unsigned int ... FEMDegrees1 , unsigned int ... FEMDegrees2 > static void _SetParentOverlapBounds( UIntPack< FEMDegrees1 ... > , UIntPack< FEMDegrees2 ... > , int cIdx , int start[Dim] , int end[Dim] ) - { - BaseFEMIntegrator::template ParentOverlapBounds( UIntPack< FEMDegrees1 ... >() , UIntPack< FEMDegrees2 ... >() , cIdx , start , end ); - } + template< unsigned int ... FEMSigs , typename T , unsigned int PointD > + void _updateRestrictedInterpolationConstraints( const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , LocalDepth highDepth , ConstPointer( T ) solution , Pointer( T ) cumulativeConstraints , const InterpolationInfo< T , PointD >* interpolationInfo ) const; - template< unsigned int ... FEMSigs > - int _getProlongedMatrixRowSize( const FEMTreeNode* node , const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& pNeighbors ) const; - template< typename T , unsigned int ... FEMSigs , typename ... InterpolationInfos , typename MatrixType > - T _setMatrixRowAndGetConstraintFromProlongation( UIntPack< FEMSigs ... > , const BaseSystem< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& pNeighbors , const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& neighbors , size_t idx , MatrixType &M , node_index_type offset , const PCStencils< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& pcStencils , const CCStencil< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& ccStencil , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , ConstPointer( T ) prolongedSolution , std::tuple< InterpolationInfos *... > interpolationInfos ) const; - template< typename T , unsigned int ... FEMSigs , typename ... InterpolationInfos > - int _setProlongedMatrixRow( const typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& neighbors , const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& pNeighbors , Pointer( MatrixEntry< Real , matrix_index_type > ) row , node_index_type offset , const DynamicWindow< double , UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& stencil , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , std::tuple< InterpolationInfos *... > interpolationInfos ) const; - - // Updates the constraints @(depth) based on the solution coefficients @(depth-1) - template< unsigned int ... FEMSigs , typename T , typename ... InterpolationInfos > - T _getConstraintFromProlongedSolution( UIntPack< FEMSigs ... > , const BaseSystem< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& neighbors , const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& pNeighbors , const FEMTreeNode* node , ConstPointer( T ) prolongedSolution , const DynamicWindow< double , UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& stencil , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , std::tuple< InterpolationInfos *... > interpolationInfos ) const; - - template< unsigned int ... FEMSigs , typename T , typename TDotT , typename SORWeights , typename ... InterpolationInfos > - int _solveFullSystemGS( UIntPack< FEMSigs ... > , const typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , LocalDepth depth , Pointer( T ) solution , ConstPointer( T ) prolongedSolution , ConstPointer( T ) constraints , TDotT Dot , int iters , bool coarseToFine , SORWeights sorWeights , _SolverStats& stats , bool computeNorms , std::tuple< InterpolationInfos *... > interpolationInfos ) const; - template< unsigned int ... FEMSigs , typename T , typename TDotT , typename SORWeights , typename ... InterpolationInfos > - int _solveSlicedSystemGS( UIntPack< FEMSigs ... > , const typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , LocalDepth depth , Pointer( T ) solution , ConstPointer( T ) prolongedSolution , ConstPointer( T ) constraints , TDotT Dot , int iters , bool coarseToFine , unsigned int sliceBlockSize , SORWeights sorWeights , _SolverStats& stats , bool computeNorms , std::tuple< InterpolationInfos *... > interpolationInfos ) const; - template< unsigned int ... FEMSigs , typename T , typename TDotT , typename SORWeights , typename ... InterpolationInfos > - int _solveSystemGS( UIntPack< FEMSigs ... > , bool sliced , const typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , LocalDepth depth , Pointer( T ) solution , ConstPointer( T ) prolongedSolution , ConstPointer( T ) constraints , TDotT Dot , int iters , bool coarseToFine , unsigned int sliceBlockSize , SORWeights sorWeights , _SolverStats& stats , bool computeNorms , std::tuple< InterpolationInfos *... > interpolationInfos ) const - { - if( sliced ) return _solveSlicedSystemGS( UIntPack< FEMSigs ... >() , F , bsData , depth , solution , prolongedSolution , constraints , Dot , iters , coarseToFine , sliceBlockSize , sorWeights , stats , computeNorms , interpolationInfos ); - else return _solveFullSystemGS ( UIntPack< FEMSigs ... >() , F , bsData , depth , solution , prolongedSolution , constraints , Dot , iters , coarseToFine , sorWeights , stats , computeNorms , interpolationInfos ); - } - template< unsigned int ... FEMSigs , typename T , typename TDotT , typename ... InterpolationInfos > - int _solveSystemCG( UIntPack< FEMSigs ... > , const typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , LocalDepth depth , Pointer( T ) solution , ConstPointer( T ) prolongedSolution , ConstPointer( T ) constraints , TDotT Dot , int iters , bool coarseToFine , _SolverStats& stats , bool computeNorms , double cgAccuracy , std::tuple< InterpolationInfos *... > interpolationInfos ) const; - template< unsigned int ... FEMSigs , typename T , typename TDotT , typename ... InterpolationInfos > - void _solveRegularMG( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , LocalDepth depth , Pointer( T ) solution , ConstPointer( T ) constraints , TDotT Dot , int vCycles , int iters , _SolverStats& stats , bool computeNorms , double cgAccuracy , std::tuple< InterpolationInfos *... > interpolationInfos ) const; - - // Updates the cumulative integral constraints @(depth-1) based on the change in solution coefficients @(depth) - template< unsigned int ... FEMSigs , typename T > - void _updateRestrictedIntegralConstraints( UIntPack< FEMSigs ... > , const typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , LocalDepth highDepth , ConstPointer( T ) solution , Pointer( T ) cumulativeConstraints ) const; - - template< unsigned int PointD , typename T , unsigned int ... FEMSigs > - CumulativeDerivativeValues< T , Dim , PointD > _coarserFunctionValues( UIntPack< FEMSigs ... > , Point< Real , Dim > p , const ConstPointSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& neighborKey , const FEMTreeNode* node , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , ConstPointer( T ) coefficients ) const; - template< unsigned int PointD , typename T , unsigned int ... FEMSigs > - CumulativeDerivativeValues< T , Dim , PointD > _finerFunctionValues( UIntPack< FEMSigs ... > , Point< Real , Dim > p , const ConstPointSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& neighborKey , const FEMTreeNode* node , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , ConstPointer( T ) coefficients ) const; - - template< unsigned int ... FEMSigs , typename T , typename ... InterpolationInfos > - int _getSliceMatrixAndProlongationConstraints( UIntPack< FEMSigs ... > , const BaseSystem< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , SystemMatrixType< FEMSigs ... > &matrix , Pointer( Real ) diagonalR , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , LocalDepth depth , node_index_type nBegin , node_index_type nEnd , ConstPointer( T ) prolongedSolution , Pointer( T ) constraints , const CCStencil < UIntPack< FEMSignature< FEMSigs >::Degree ... > >& ccStencil , const PCStencils< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& pcStencils , std::tuple< InterpolationInfos *... > interpolationInfos ) const; - - // Down samples constraints @(depth) to constraints @(depth-1) - template< class C , typename ArrayWrapper , unsigned ... Degrees , unsigned int ... FEMSigs > void _downSample( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template RestrictionProlongation< UIntPack< Degrees ... > >& RP , LocalDepth highDepth , ArrayWrapper finerConstraints , Pointer( C ) coarserConstraints ) const; - // Up samples coefficients @(depth-1) to coefficients @(depth) - template< class C , typename ArrayWrapper , unsigned ... Degrees , unsigned int ... FEMSigs > void _upSample( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template RestrictionProlongation< UIntPack< Degrees ... > >& RP , LocalDepth highDepth , ArrayWrapper coarserCoefficients , Pointer( C ) finerCoefficients ) const; - - template< unsigned int ... FEMSigs , typename ValidNodeFunctor > - SparseMatrix< Real , matrix_index_type > _downSampleMatrix( UIntPack< FEMSigs ... > , LocalDepth highDepth , ValidNodeFunctor validNodeFunctor ) const; - template< unsigned int ... FEMSigs , typename ValidNodeFunctor > - SparseMatrix< Real , matrix_index_type > _upSampleMatrix( UIntPack< FEMSigs ... > , LocalDepth highDepth , ValidNodeFunctor validNodeFunctor ) const; - template< unsigned int ... FEMSigs , typename ValidNodeFunctor > - SparseMatrix< Real , matrix_index_type > _restrictSystemMatrix( UIntPack< FEMSigs ... > , LocalDepth highDepth , const SparseMatrix< Real , matrix_index_type > &M , ValidNodeFunctor validNodeFunctor ) const; - - template< bool XMajor , class C , unsigned int ... FEMSigs > static void _RegularGridUpSample( UIntPack< FEMSigs ... > , LocalDepth highDepth , ConstPointer( C ) lowCoefficients , Pointer( C ) highCoefficients ); - template< bool XMajor , class C , unsigned int ... FEMSigs > static void _RegularGridUpSample( UIntPack< FEMSigs ... > , const int lowBegin[] , const int lowEnd[] , const int highBegin[] , const int highEnd[] , LocalDepth highDepth , ConstPointer( C ) lowCoefficients , Pointer( C ) highCoefficients ); -public: - template< class C , unsigned int ... FEMSigs > DenseNodeData< C , UIntPack< FEMSigs ... > > coarseCoefficients( const DenseNodeData< C , UIntPack< FEMSigs ... > >& coefficients ) const; - template< class C , unsigned int ... FEMSigs > DenseNodeData< C , UIntPack< FEMSigs ... > > coarseCoefficients( const SparseNodeData< C , UIntPack< FEMSigs ... > >& coefficients ) const; - template< class C , unsigned int ... FEMSigs > DenseNodeData< C , UIntPack< FEMSigs ... > > denseCoefficients( const SparseNodeData< C , UIntPack< FEMSigs ... > >& coefficients ) const; - - void trimToDepth( LocalDepth coarseDepth ); - - template< class C , unsigned int ... FEMSigs > DenseNodeData< C , UIntPack< FEMSigs ... > > trimToDepth( const DenseNodeData< C , UIntPack< FEMSigs ... > >& coefficients , LocalDepth coarseDepth ) const; - template< class C , unsigned int ... FEMSigs > SparseNodeData< C , UIntPack< FEMSigs ... > > trimToDepth( const SparseNodeData< C , UIntPack< FEMSigs ... > >& coefficients , LocalDepth coarseDepth ) const; - - template< typename T , unsigned int PointD , typename ConstraintDual , typename SystemDual > - ApproximatePointInterpolationInfo< T , PointD , ConstraintDual , SystemDual > trimToDepth( const ApproximatePointInterpolationInfo< T , PointD , ConstraintDual , SystemDual > &iInfo , LocalDepth coarseDepth ) const; - template< typename T , typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > - ApproximatePointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual > trimToDepth( const ApproximatePointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual > &iInfo , LocalDepth coarseDepth ) const; - - // For each (valid) fem node, compute the ratio of the sum of active prolongation weights to the sum of total prolongation weights - // If the prolongToChildren flag is set, then these weights are pushed to the children by computing the ratio of the prolongation of the above weights to the prolongation of unity weights - - template< unsigned int ... FEMSigs > DenseNodeData< Real , UIntPack< FEMSigs ... > > supportWeights( UIntPack< FEMSigs ... > ) const; - template< unsigned int ... FEMSigs > DenseNodeData< Real , UIntPack< FEMSigs ... > > prolongationWeights( UIntPack< FEMSigs ... > , bool prolongToChildren ) const; - -protected: - - ////////////////////////////////////////////// - // Code for splatting point-sample data // - // MultiGridFEMTreeData.WeightedSamples.inl // - ////////////////////////////////////////////// - template< unsigned int CoDim , unsigned int Degree > - Real _GetScaleValue( unsigned int res ) const; - template< unsigned int CoDim , unsigned int Degree > - Real _GetScaleValue( Point< Real , Dim > p ) const; - template< bool ThreadSafe , unsigned int CoDim , unsigned int WeightDegree > - void _addWeightContribution( Allocator< FEMTreeNode > *nodeAllocator , DensityEstimator< WeightDegree >& densityWeights , FEMTreeNode* node , Point< Real , Dim > position , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , Real weight=Real(1.0) ); - template< unsigned int WeightDegree , class PointSupportKey > - Real _getSamplesPerNode( const DensityEstimator< WeightDegree >& densityWeights , const FEMTreeNode* node , Point< Real , Dim > position , PointSupportKey& weightKey ) const; - template< unsigned int WeightDegree , class WeightKey > - void _getSampleDepthAndWeight( const DensityEstimator< WeightDegree >& densityWeights , const FEMTreeNode* node , Point< Real , Dim > position , WeightKey& weightKey , Real& depth , Real& weight ) const; - template< unsigned int WeightDegree , class WeightKey > - void _getSampleDepthAndWeight( const DensityEstimator< WeightDegree >& densityWeights , Point< Real , Dim > position , WeightKey& weightKey , Real& depth , Real& weight ) const; - - template< bool CreateNodes , bool ThreadSafe , class V , unsigned int ... DataSigs > void _splatPointData( Allocator< FEMTreeNode > *nodeAllocator , FEMTreeNode* node , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey ); - template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > Point< Real , 2 > _splatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >& densityWeights , Real minDepthCutoff , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , LocalDepth minDepth , LocalDepth maxDepth , int dim , Real depthBias ); - template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > Point< Real , 2 > _splatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >& densityWeights , Real minDepthCutoff , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , LocalDepth minDepth , std::function< int ( Point< Real , Dim > ) > &pointDepthFunctor , int dim , Real depthBias ); - template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > Point< Real , 2 > _multiSplatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >* densityWeights , FEMTreeNode* node , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , int dim ); - template< unsigned int WeightDegree , class V , unsigned int ... DataSigs > Real _nearestMultiSplatPointData( const DensityEstimator< WeightDegree >* densityWeights , FEMTreeNode* node , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , int dim=Dim ); - template< class V , class Coefficients , unsigned int D , unsigned int ... DataSigs > void _addEvaluation( const Coefficients& coefficients , Point< Real , Dim > p , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , V &value ) const; - template< class V , class Coefficients , unsigned int D , unsigned int ... DataSigs > void _addEvaluation( const Coefficients& coefficients , Point< Real , Dim > p , LocalDepth pointDepth , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , V &value ) const; - -public: - - template< bool XMajor , class V , unsigned int ... DataSigs > Pointer( V ) regularGridEvaluate( const DenseNodeData< V , UIntPack< DataSigs ... > >& coefficients , int& res , LocalDepth depth=-1 , bool primal=false ) const; - template< bool XMajor , class V , unsigned int ... DataSigs > Pointer( V ) regularGridEvaluate( const DenseNodeData< V , UIntPack< DataSigs ... > >& coefficients , const unsigned int begin[Dim] , const unsigned int end[Dim] , unsigned int res[Dim] , bool primal=false ) const; - template< bool XMajor , class V , unsigned int ... DataSigs > Pointer( V ) regularGridUpSample( const DenseNodeData< V , UIntPack< DataSigs ... > >& coefficients , LocalDepth depth=-1 ) const; - template< bool XMajor , class V , unsigned int ... DataSigs > Pointer( V ) regularGridUpSample( const DenseNodeData< V , UIntPack< DataSigs ... > >& coefficients , const int begin[Dim] , const int end[Dim] , LocalDepth depth=-1 ) const; - template< class V , unsigned int ... DataSigs > V average( const DenseNodeData< V , UIntPack< DataSigs ... > >& coefficients ) const; - template< class V , unsigned int ... DataSigs > V average( const DenseNodeData< V , UIntPack< DataSigs ... > >& coefficients , const Real begin[Dim] , const Real end[Dim] ) const; - template< typename T > struct HasNormalDataFunctor{}; - template< unsigned int ... NormalSigs > - struct HasNormalDataFunctor< UIntPack< NormalSigs ... > > - { - const SparseNodeData< Point< Real , Dim > , UIntPack< NormalSigs ... > >& normalInfo; - HasNormalDataFunctor( const SparseNodeData< Point< Real , Dim > , UIntPack< NormalSigs ... > >& ni ) : normalInfo( ni ){ ; } - bool operator() ( const FEMTreeNode* node ) const + template< unsigned int FEMDegree1 , unsigned int FEMDegree2 > static void _SetParentOverlapBounds( const FEMTreeNode* node , int start[Dim] , int end[Dim] ); + template< unsigned int FEMDegree1 , unsigned int FEMDegree2 > static void _SetParentOverlapBounds( int cIdx , int start[Dim] , int end[Dim] ); + template< unsigned int ... FEMDegrees1 , unsigned int ... FEMDegrees2 > static void _SetParentOverlapBounds( UIntPack< FEMDegrees1 ... > , UIntPack< FEMDegrees2 ... > , const FEMTreeNode* node , int start[Dim] , int end[Dim] ) { - const Point< Real , Dim >* n = normalInfo( node ); - if( n ) + if( node ) { - const Point< Real , Dim >& normal = *n; - for( int d=0 ; ddepthAndOffset( d , off ); + BaseFEMIntegrator::template ParentOverlapBounds( UIntPack< FEMDegrees1 ... >() , UIntPack< FEMDegrees2 ... >() , d , off , start , end ); } - if( node->children ) for( int c=0 ; c<(1<children + c ) ) return true; - return false; } - }; - struct TrivialHasDataFunctor{ bool operator() ( const FEMTreeNode* node ) const { return true; } }; -protected: - // [NOTE] The input/output for this method is pre-scaled by weight - template< typename T > bool _setInterpolationInfoFromChildren( FEMTreeNode* node , SparseNodeData< T , IsotropicUIntPack< Dim , FEMTrivialSignature > >& iInfo ) const; - template< typename T , unsigned int PointD , typename ConstraintDual > SparseNodeData< DualPointInfo < Dim , Real , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > _densifyInterpolationInfoAndSetDualConstraints( const std::vector< PointSample >& samples , ConstraintDual constraintDual , LocalDepth maxDepth , int adaptiveExponent ) const; - template< typename T , typename Data , unsigned int PointD , typename ConstraintDual > SparseNodeData< DualPointAndDataInfo< Dim , Real , Data , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > _densifyInterpolationInfoAndSetDualConstraints( const std::vector< PointSample >& samples , ConstPointer( Data ) sampleData , ConstraintDual constraintDual , LocalDepth maxDepth , int adaptiveExponent ) const; - template< typename T , unsigned int PointD , typename ConstraintDual > void _densifyInterpolationInfoAndSetDualConstraints( SparseNodeData< DualPointInfo < Dim , Real , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > &iInfo , const std::vector< PointSample >& samples , ConstraintDual constraintDual , LocalDepth maxDepth , int adaptiveExponent ) const; - template< typename T , typename Data , unsigned int PointD , typename ConstraintDual > void _densifyInterpolationInfoAndSetDualConstraints( SparseNodeData< DualPointAndDataInfo< Dim , Real , Data , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > &iInfo , const std::vector< PointSample >& samples , ConstPointer( Data ) sampleData , ConstraintDual constraintDual , LocalDepth maxDepth , int adaptiveExponent ) const; - template< typename T , unsigned int PointD , typename ConstraintDual > SparseNodeData< DualPointInfoBrood < Dim , Real , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > _densifyChildInterpolationInfoAndSetDualConstraints( const std::vector< PointSample >& samples , ConstraintDual constraintDual , bool noRescale ) const; - template< typename T , typename Data , unsigned int PointD , typename ConstraintDual > SparseNodeData< DualPointAndDataInfoBrood< Dim , Real , Data , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > _densifyChildInterpolationInfoAndSetDualConstraints( const std::vector< PointSample >& samples , ConstPointer( Data ) sampleData , ConstraintDual constraintDual , bool noRescale ) const; - - void _setSpaceValidityFlags( void ) const; - template< unsigned int ... FEMSigs1 > void _setFEM1ValidityFlags( UIntPack< FEMSigs1 ... > ) const; - template< unsigned int ... FEMSigs2 > void _setFEM2ValidityFlags( UIntPack< FEMSigs2 ... > ) const; - template< class HasDataFunctor > void _clipTree( const HasDataFunctor& f , LocalDepth fullDepth ); - -public: - - template< unsigned int PointD , unsigned int ... FEMSigs > SparseNodeData< CumulativeDerivativeValues< Real , Dim , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > leafValues( const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , int maxDepth=-1 ) const; - -protected: - - ///////////////////////////////////// - // Evaluation Methods // - // MultiGridFEMTreeData.Evaluation // - ///////////////////////////////////// - static const unsigned int CHILDREN = 1< struct _Evaluator{ }; - template< unsigned int ... FEMSigs , unsigned int PointD > - struct _Evaluator< UIntPack< FEMSigs ... > , PointD > - { - static_assert( Dim == sizeof...(FEMSigs) , "[ERROR] Number of signatures doesn't match dimension" ); + template< unsigned int ... FEMDegrees1 , unsigned int ... FEMDegrees2 > static void _SetParentOverlapBounds( UIntPack< FEMDegrees1 ... > , UIntPack< FEMDegrees2 ... > , int cIdx , int start[Dim] , int end[Dim] ) + { + BaseFEMIntegrator::template ParentOverlapBounds( UIntPack< FEMDegrees1 ... >() , UIntPack< FEMDegrees2 ... >() , cIdx , start , end ); + } - typedef DynamicWindow< CumulativeDerivativeValues< double , Dim , PointD > , UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... > > CenterStencil; - typedef DynamicWindow< CumulativeDerivativeValues< double , Dim , PointD > , UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... > > CornerStencil; - typedef DynamicWindow< CumulativeDerivativeValues< double , Dim , PointD > , UIntPack< ( BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::BCornerSize + 1 ) ... > > BCornerStencil; + template< unsigned int ... FEMSigs > + int _getProlongedMatrixRowSize( const FEMTreeNode* node , const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& pNeighbors ) const; + template< typename T , unsigned int ... FEMSigs , typename ... InterpolationInfos , typename MatrixType > + T _setMatrixRowAndGetConstraintFromProlongation( UIntPack< FEMSigs ... > , const BaseSystem< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& pNeighbors , const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& neighbors , size_t idx , MatrixType &M , node_index_type offset , const PCStencils< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& pcStencils , const CCStencil< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& ccStencil , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , ConstPointer( T ) prolongedSolution , std::tuple< InterpolationInfos *... > interpolationInfos ) const; + template< typename T , unsigned int ... FEMSigs , typename ... InterpolationInfos > + int _setProlongedMatrixRow( const typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& neighbors , const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& pNeighbors , Pointer( MatrixEntry< Real , matrix_index_type > ) row , node_index_type offset , const DynamicWindow< double , UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& stencil , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , std::tuple< InterpolationInfos *... > interpolationInfos ) const; + + // Updates the constraints @(depth) based on the solution coefficients @(depth-1) + template< unsigned int ... FEMSigs , typename T , typename ... InterpolationInfos > + T _getConstraintFromProlongedSolution( UIntPack< FEMSigs ... > , const BaseSystem< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& neighbors , const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& pNeighbors , const FEMTreeNode* node , ConstPointer( T ) prolongedSolution , const DynamicWindow< double , UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& stencil , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , std::tuple< InterpolationInfos *... > interpolationInfos ) const; + + template< unsigned int ... FEMSigs , typename T , typename TDotT , typename SORWeights , typename ... InterpolationInfos > + int _solveFullSystemGS( UIntPack< FEMSigs ... > , const typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , LocalDepth depth , Pointer( T ) solution , ConstPointer( T ) prolongedSolution , ConstPointer( T ) constraints , TDotT Dot , int iters , bool coarseToFine , SORWeights sorWeights , _SolverStats& stats , bool computeNorms , std::tuple< InterpolationInfos *... > interpolationInfos ) const; + template< unsigned int ... FEMSigs , typename T , typename TDotT , typename SORWeights , typename ... InterpolationInfos > + int _solveSlicedSystemGS( UIntPack< FEMSigs ... > , const typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , LocalDepth depth , Pointer( T ) solution , ConstPointer( T ) prolongedSolution , ConstPointer( T ) constraints , TDotT Dot , int iters , bool coarseToFine , unsigned int sliceBlockSize , SORWeights sorWeights , _SolverStats& stats , bool computeNorms , std::tuple< InterpolationInfos *... > interpolationInfos ) const; + template< unsigned int ... FEMSigs , typename T , typename TDotT , typename SORWeights , typename ... InterpolationInfos > + int _solveSystemGS( UIntPack< FEMSigs ... > , bool sliced , const typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , LocalDepth depth , Pointer( T ) solution , ConstPointer( T ) prolongedSolution , ConstPointer( T ) constraints , TDotT Dot , int iters , bool coarseToFine , unsigned int sliceBlockSize , SORWeights sorWeights , _SolverStats& stats , bool computeNorms , std::tuple< InterpolationInfos *... > interpolationInfos ) const + { + if( sliced ) return _solveSlicedSystemGS( UIntPack< FEMSigs ... >() , F , bsData , depth , solution , prolongedSolution , constraints , Dot , iters , coarseToFine , sliceBlockSize , sorWeights , stats , computeNorms , interpolationInfos ); + else return _solveFullSystemGS ( UIntPack< FEMSigs ... >() , F , bsData , depth , solution , prolongedSolution , constraints , Dot , iters , coarseToFine , sorWeights , stats , computeNorms , interpolationInfos ); + } + template< unsigned int ... FEMSigs , typename T , typename TDotT , typename ... InterpolationInfos > + int _solveSystemCG( UIntPack< FEMSigs ... > , const typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , LocalDepth depth , Pointer( T ) solution , ConstPointer( T ) prolongedSolution , ConstPointer( T ) constraints , TDotT Dot , int iters , bool coarseToFine , _SolverStats& stats , bool computeNorms , double cgAccuracy , std::tuple< InterpolationInfos *... > interpolationInfos ) const; + template< unsigned int ... FEMSigs , typename T , typename TDotT , typename ... InterpolationInfos > + void _solveRegularMG( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , LocalDepth depth , Pointer( T ) solution , ConstPointer( T ) constraints , TDotT Dot , int vCycles , int iters , _SolverStats& stats , bool computeNorms , double cgAccuracy , std::tuple< InterpolationInfos *... > interpolationInfos ) const; + + // Updates the cumulative integral constraints @(depth-1) based on the change in solution coefficients @(depth) + template< unsigned int ... FEMSigs , typename T > + void _updateRestrictedIntegralConstraints( UIntPack< FEMSigs ... > , const typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , LocalDepth highDepth , ConstPointer( T ) solution , Pointer( T ) cumulativeConstraints ) const; + + template< unsigned int PointD , typename T , unsigned int ... FEMSigs > + CumulativeDerivativeValues< T , Dim , PointD > _coarserFunctionValues( UIntPack< FEMSigs ... > , Point< Real , Dim > p , const ConstPointSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& neighborKey , const FEMTreeNode* node , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , ConstPointer( T ) coefficients ) const; + template< unsigned int PointD , typename T , unsigned int ... FEMSigs > + CumulativeDerivativeValues< T , Dim , PointD > _finerFunctionValues( UIntPack< FEMSigs ... > , Point< Real , Dim > p , const ConstPointSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& neighborKey , const FEMTreeNode* node , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , ConstPointer( T ) coefficients ) const; + + template< unsigned int ... FEMSigs , typename T , typename ... InterpolationInfos > + int _getSliceMatrixAndProlongationConstraints( UIntPack< FEMSigs ... > , const BaseSystem< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , SystemMatrixType< FEMSigs ... > &matrix , Pointer( Real ) diagonalR , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , LocalDepth depth , node_index_type nBegin , node_index_type nEnd , ConstPointer( T ) prolongedSolution , Pointer( T ) constraints , const CCStencil < UIntPack< FEMSignature< FEMSigs >::Degree ... > >& ccStencil , const PCStencils< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& pcStencils , std::tuple< InterpolationInfos *... > interpolationInfos ) const; + + // Down samples constraints @(depth) to constraints @(depth-1) + template< class C , typename ArrayWrapper , unsigned ... Degrees , unsigned int ... FEMSigs > void _downSample( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template RestrictionProlongation< UIntPack< Degrees ... > >& RP , LocalDepth highDepth , ArrayWrapper finerConstraints , Pointer( C ) coarserConstraints ) const; + // Up samples coefficients @(depth-1) to coefficients @(depth) + template< class C , typename ArrayWrapper , unsigned ... Degrees , unsigned int ... FEMSigs > void _upSample( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template RestrictionProlongation< UIntPack< Degrees ... > >& RP , LocalDepth highDepth , ArrayWrapper coarserCoefficients , Pointer( C ) finerCoefficients ) const; + + template< unsigned int ... FEMSigs , typename ValidNodeFunctor > + SparseMatrix< Real , matrix_index_type > _downSampleMatrix( UIntPack< FEMSigs ... > , LocalDepth highDepth , ValidNodeFunctor validNodeFunctor ) const; + template< unsigned int ... FEMSigs , typename ValidNodeFunctor > + SparseMatrix< Real , matrix_index_type > _upSampleMatrix( UIntPack< FEMSigs ... > , LocalDepth highDepth , ValidNodeFunctor validNodeFunctor ) const; + template< unsigned int ... FEMSigs , typename ValidNodeFunctor > + SparseMatrix< Real , matrix_index_type > _restrictSystemMatrix( UIntPack< FEMSigs ... > , LocalDepth highDepth , const SparseMatrix< Real , matrix_index_type > &M , ValidNodeFunctor validNodeFunctor ) const; + + template< bool XMajor , class C , unsigned int ... FEMSigs > static void _RegularGridUpSample( UIntPack< FEMSigs ... > , LocalDepth highDepth , ConstPointer( C ) lowCoefficients , Pointer( C ) highCoefficients ); + template< bool XMajor , class C , unsigned int ... FEMSigs > static void _RegularGridUpSample( UIntPack< FEMSigs ... > , const int lowBegin[] , const int lowEnd[] , const int highBegin[] , const int highEnd[] , LocalDepth highDepth , ConstPointer( C ) lowCoefficients , Pointer( C ) highCoefficients ); + public: + template< class C , unsigned int ... FEMSigs > DenseNodeData< C , UIntPack< FEMSigs ... > > coarseCoefficients( const DenseNodeData< C , UIntPack< FEMSigs ... > >& coefficients ) const; + template< class C , unsigned int ... FEMSigs > DenseNodeData< C , UIntPack< FEMSigs ... > > coarseCoefficients( const SparseNodeData< C , UIntPack< FEMSigs ... > >& coefficients ) const; + template< class C , unsigned int ... FEMSigs > DenseNodeData< C , UIntPack< FEMSigs ... > > denseCoefficients( const SparseNodeData< C , UIntPack< FEMSigs ... > >& coefficients ) const; + + void trimToDepth( LocalDepth coarseDepth ); + + template< class C , unsigned int ... FEMSigs > DenseNodeData< C , UIntPack< FEMSigs ... > > trimToDepth( const DenseNodeData< C , UIntPack< FEMSigs ... > >& coefficients , LocalDepth coarseDepth ) const; + template< class C , unsigned int ... FEMSigs > SparseNodeData< C , UIntPack< FEMSigs ... > > trimToDepth( const SparseNodeData< C , UIntPack< FEMSigs ... > >& coefficients , LocalDepth coarseDepth ) const; + + template< typename T , unsigned int PointD , typename ConstraintDual , typename SystemDual > + ApproximatePointInterpolationInfo< T , PointD , ConstraintDual , SystemDual > trimToDepth( const ApproximatePointInterpolationInfo< T , PointD , ConstraintDual , SystemDual > &iInfo , LocalDepth coarseDepth ) const; + template< typename T , typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > + ApproximatePointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual > trimToDepth( const ApproximatePointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual > &iInfo , LocalDepth coarseDepth ) const; + + // For each (valid) fem node, compute the ratio of the sum of active prolongation weights to the sum of total prolongation weights + // If the prolongToChildren flag is set, then these weights are pushed to the children by computing the ratio of the prolongation of the above weights to the prolongation of unity weights + + template< unsigned int ... FEMSigs > DenseNodeData< Real , UIntPack< FEMSigs ... > > supportWeights( UIntPack< FEMSigs ... > ) const; + template< unsigned int ... FEMSigs > DenseNodeData< Real , UIntPack< FEMSigs ... > > prolongationWeights( UIntPack< FEMSigs ... > , bool prolongToChildren ) const; - typedef std::tuple< typename BSplineEvaluationData< FEMSigs >::template Evaluator< PointD > ... > Evaluators; - typedef std::tuple< typename BSplineEvaluationData< FEMSigs >::template ChildEvaluator< PointD > ... > ChildEvaluators; - struct StencilData + protected: + + ////////////////////////////////////////////// + // Code for splatting point-sample data // + // MultiGridFEMTreeData.WeightedSamples.inl // + ////////////////////////////////////////////// + template< unsigned int CoDim , unsigned int Degree > + Real _GetScaleValue( unsigned int res ) const; + template< unsigned int CoDim , unsigned int Degree > + Real _GetScaleValue( Point< Real , Dim > p ) const; + template< bool ThreadSafe , unsigned int CoDim , unsigned int WeightDegree > + void _addWeightContribution( Allocator< FEMTreeNode > *nodeAllocator , DensityEstimator< WeightDegree >& densityWeights , FEMTreeNode* node , Point< Real , Dim > position , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , Real weight=Real(1.0) ); + template< unsigned int WeightDegree , class PointSupportKey > + Real _getSamplesPerNode( const DensityEstimator< WeightDegree >& densityWeights , const FEMTreeNode* node , Point< Real , Dim > position , PointSupportKey& weightKey ) const; + template< unsigned int WeightDegree , class WeightKey > + void _getSampleDepthAndWeight( const DensityEstimator< WeightDegree >& densityWeights , const FEMTreeNode* node , Point< Real , Dim > position , WeightKey& weightKey , Real& depth , Real& weight ) const; + template< unsigned int WeightDegree , class WeightKey > + void _getSampleDepthAndWeight( const DensityEstimator< WeightDegree >& densityWeights , Point< Real , Dim > position , WeightKey& weightKey , Real& depth , Real& weight ) const; + + template< bool CreateNodes , bool ThreadSafe , class V , unsigned int ... DataSigs > void _splatPointData( Allocator< FEMTreeNode > *nodeAllocator , FEMTreeNode* node , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey ); + template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > Point< Real , 2 > _splatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >& densityWeights , Real minDepthCutoff , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , LocalDepth minDepth , LocalDepth maxDepth , int dim , Real depthBias ); + template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > Point< Real , 2 > _splatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >& densityWeights , Real minDepthCutoff , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , LocalDepth minDepth , std::function< int ( Point< Real , Dim > ) > &pointDepthFunctor , int dim , Real depthBias ); + template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > Point< Real , 2 > _multiSplatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >* densityWeights , FEMTreeNode* node , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , int dim ); + template< unsigned int WeightDegree , class V , unsigned int ... DataSigs > Real _nearestMultiSplatPointData( const DensityEstimator< WeightDegree >* densityWeights , FEMTreeNode* node , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , int dim=Dim ); + template< class V , class Coefficients , unsigned int D , unsigned int ... DataSigs > void _addEvaluation( const Coefficients& coefficients , Point< Real , Dim > p , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , V &value ) const; + template< class V , class Coefficients , unsigned int D , unsigned int ... DataSigs > void _addEvaluation( const Coefficients& coefficients , Point< Real , Dim > p , LocalDepth pointDepth , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , V &value ) const; + + public: + + template< bool XMajor , class V , unsigned int ... DataSigs > Pointer( V ) regularGridEvaluate( const DenseNodeData< V , UIntPack< DataSigs ... > >& coefficients , int& res , LocalDepth depth=-1 , bool primal=false ) const; + template< bool XMajor , class V , unsigned int ... DataSigs > Pointer( V ) regularGridEvaluate( const DenseNodeData< V , UIntPack< DataSigs ... > >& coefficients , const unsigned int begin[Dim] , const unsigned int end[Dim] , unsigned int res[Dim] , bool primal=false ) const; + template< bool XMajor , class V , unsigned int ... DataSigs > Pointer( V ) regularGridUpSample( const DenseNodeData< V , UIntPack< DataSigs ... > >& coefficients , LocalDepth depth=-1 ) const; + template< bool XMajor , class V , unsigned int ... DataSigs > Pointer( V ) regularGridUpSample( const DenseNodeData< V , UIntPack< DataSigs ... > >& coefficients , const int begin[Dim] , const int end[Dim] , LocalDepth depth=-1 ) const; + template< class V , unsigned int ... DataSigs > V average( const DenseNodeData< V , UIntPack< DataSigs ... > >& coefficients ) const; + template< class V , unsigned int ... DataSigs > V average( const DenseNodeData< V , UIntPack< DataSigs ... > >& coefficients , const Real begin[Dim] , const Real end[Dim] ) const; + template< typename T > struct HasNormalDataFunctor{}; + template< unsigned int ... NormalSigs > + struct HasNormalDataFunctor< UIntPack< NormalSigs ... > > { - CenterStencil ccCenterStencil , pcCenterStencils[CHILDREN]; - CornerStencil ccCornerStencil[CHILDREN] , pcCornerStencils[CHILDREN][CHILDREN]; - BCornerStencil ccBCornerStencil[CHILDREN] , pcBCornerStencils[CHILDREN][CHILDREN]; + const SparseNodeData< Point< Real , Dim > , UIntPack< NormalSigs ... > >& normalInfo; + HasNormalDataFunctor( const SparseNodeData< Point< Real , Dim > , UIntPack< NormalSigs ... > >& ni ) : normalInfo( ni ){ ; } + bool operator() ( const FEMTreeNode* node ) const + { + const Point< Real , Dim >* n = normalInfo( node ); + if( n ) + { + const Point< Real , Dim >& normal = *n; + for( int d=0 ; dchildren ) for( int c=0 ; c<(1<children + c ) ) return true; + return false; + } }; - Pointer( StencilData ) stencilData; - Pointer( Evaluators ) evaluators; - Pointer( ChildEvaluators ) childEvaluators; + struct TrivialHasDataFunctor{ bool operator() ( const FEMTreeNode* node ) const { return true; } }; + protected: + // [NOTE] The input/output for this method is pre-scaled by weight + template< typename T > bool _setInterpolationInfoFromChildren( FEMTreeNode* node , SparseNodeData< T , IsotropicUIntPack< Dim , FEMTrivialSignature > >& iInfo ) const; + template< typename T , unsigned int PointD , typename ConstraintDual > SparseNodeData< DualPointInfo < Dim , Real , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > _densifyInterpolationInfoAndSetDualConstraints( const std::vector< PointSample >& samples , ConstraintDual constraintDual , LocalDepth maxDepth , int adaptiveExponent ) const; + template< typename T , typename Data , unsigned int PointD , typename ConstraintDual > SparseNodeData< DualPointAndDataInfo< Dim , Real , Data , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > _densifyInterpolationInfoAndSetDualConstraints( const std::vector< PointSample >& samples , ConstPointer( Data ) sampleData , ConstraintDual constraintDual , LocalDepth maxDepth , int adaptiveExponent ) const; + template< typename T , unsigned int PointD , typename ConstraintDual > void _densifyInterpolationInfoAndSetDualConstraints( SparseNodeData< DualPointInfo < Dim , Real , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > &iInfo , const std::vector< PointSample >& samples , ConstraintDual constraintDual , LocalDepth maxDepth , int adaptiveExponent ) const; + template< typename T , typename Data , unsigned int PointD , typename ConstraintDual > void _densifyInterpolationInfoAndSetDualConstraints( SparseNodeData< DualPointAndDataInfo< Dim , Real , Data , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > &iInfo , const std::vector< PointSample >& samples , ConstPointer( Data ) sampleData , ConstraintDual constraintDual , LocalDepth maxDepth , int adaptiveExponent ) const; + template< typename T , unsigned int PointD , typename ConstraintDual > SparseNodeData< DualPointInfoBrood < Dim , Real , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > _densifyChildInterpolationInfoAndSetDualConstraints( const std::vector< PointSample >& samples , ConstraintDual constraintDual , bool noRescale ) const; + template< typename T , typename Data , unsigned int PointD , typename ConstraintDual > SparseNodeData< DualPointAndDataInfoBrood< Dim , Real , Data , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > _densifyChildInterpolationInfoAndSetDualConstraints( const std::vector< PointSample >& samples , ConstPointer( Data ) sampleData , ConstraintDual constraintDual , bool noRescale ) const; + + void _setSpaceValidityFlags( void ) const; + template< unsigned int ... FEMSigs1 > void _setFEM1ValidityFlags( UIntPack< FEMSigs1 ... > ) const; + template< unsigned int ... FEMSigs2 > void _setFEM2ValidityFlags( UIntPack< FEMSigs2 ... > ) const; + template< class HasDataFunctor > void _clipTree( const HasDataFunctor& f , LocalDepth fullDepth ); + + public: + + template< unsigned int PointD , unsigned int ... FEMSigs > SparseNodeData< CumulativeDerivativeValues< Real , Dim , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > leafValues( const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , int maxDepth=-1 ) const; - void set( LocalDepth depth ); - _Evaluator( void ){ _pointEvaluator = NULL ; stencilData = NullPointer( StencilData ) , evaluators = NullPointer( Evaluators ) , childEvaluators = NullPointer( ChildEvaluators ); } - ~_Evaluator( void ){ if( _pointEvaluator ) delete _pointEvaluator , _pointEvaluator = NULL ; if( stencilData ) DeletePointer( stencilData ) ; if( evaluators ) DeletePointer( evaluators ) ; if( childEvaluators ) DeletePointer( childEvaluators ); } protected: - enum _CenterOffset{ CENTER=-1 , BACK=0 , FRONT=1 }; - template< unsigned int _PointD=PointD > CumulativeDerivativeValues< double , Dim , _PointD > _values( unsigned int d , const int fIdx[Dim] , const int idx[Dim] , const _CenterOffset off[Dim] , bool parentChild ) const; - template< unsigned int _PointD=PointD > CumulativeDerivativeValues< double , Dim , _PointD > _centerValues( unsigned int d , const int fIdx[Dim] , const int idx[Dim] , bool parentChild ) const; - template< unsigned int _PointD=PointD > CumulativeDerivativeValues< double , Dim , _PointD > _cornerValues( unsigned int d , const int fIdx[Dim] , const int idx[Dim] , int corner , bool parentChild ) const; - template< unsigned int _PointD=PointD , unsigned int I=0 > typename std::enable_if< I==Dim >::type _setDValues( unsigned int d , const int fIdx[] , const int cIdx[] , const _CenterOffset off[] , bool pc , double dValues[][_PointD+1] ) const{ } - template< unsigned int _PointD=PointD , unsigned int I=0 > typename std::enable_if< I< Dim >::type _setDValues( unsigned int d , const int fIdx[] , const int cIdx[] , const _CenterOffset off[] , bool pc , double dValues[][_PointD+1] ) const - { - if( pc ) for( int dd=0 ; dd<=_PointD ; dd++ ) dValues[I][dd] = off[I]==CENTER ? std::get< I >( childEvaluators[d] ).centerValue( fIdx[I] , cIdx[I] , dd ) : std::get< I >( childEvaluators[d] ).cornerValue( fIdx[I] , cIdx[I]+off[I] , dd ); - else for( int dd=0 ; dd<=_PointD ; dd++ ) dValues[I][dd] = off[I]==CENTER ? std::get< I >( evaluators[d] ).centerValue( fIdx[I] , cIdx[I] , dd ) : std::get< I >( evaluators[d] ).cornerValue( fIdx[I] , cIdx[I]+off[I] , dd ); - _setDValues< _PointD , I+1 >( d , fIdx , cIdx , off , pc , dValues ); - } - template< unsigned int I=0 > typename std::enable_if< I==Dim >::type _setEvaluators( unsigned int maxDepth ){ } - template< unsigned int I=0 > typename std::enable_if< I< Dim >::type _setEvaluators( unsigned int maxDepth ) + ///////////////////////////////////// + // Evaluation Methods // + // MultiGridFEMTreeData.Evaluation // + ///////////////////////////////////// + static const unsigned int CHILDREN = 1< struct _Evaluator{ }; + template< unsigned int ... FEMSigs , unsigned int PointD > + struct _Evaluator< UIntPack< FEMSigs ... > , PointD > { - static const unsigned int FEMSig = UIntPack< FEMSigs ... >::template Get< I >(); - for( unsigned int d=0 ; d<=maxDepth ; d++ ) BSplineEvaluationData< FEMSig >:: SetEvaluator( std::template get< I >( evaluators[d] ) , d ); - for( unsigned int d=1 ; d<=maxDepth ; d++ ) BSplineEvaluationData< FEMSig >::SetChildEvaluator( std::template get< I >( childEvaluators[d] ) , d-1 ); - _setEvaluators< I+1 >( maxDepth ); - } - typename FEMIntegrator::template PointEvaluator< UIntPack< FEMSigs ... > , IsotropicUIntPack< Dim , PointD > >* _pointEvaluator; - friend FEMTree; - }; + static_assert( Dim == sizeof...(FEMSigs) , "[ERROR] Number of signatures doesn't match dimension" ); - template< class V , unsigned int _PointD , unsigned int ... FEMSigs , unsigned int PointD > - CumulativeDerivativeValues< V , Dim , _PointD > _getCenterValues( const ConstPointSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& neighborKey , const FEMTreeNode* node , ConstPointer( V ) solution , ConstPointer( V ) coarseSolution , const _Evaluator< UIntPack< FEMSigs ... > , PointD >& evaluator , int maxDepth , bool isInterior ) const; - template< class V , unsigned int _PointD , unsigned int ... FEMSigs , unsigned int PointD > - CumulativeDerivativeValues< V , Dim , _PointD > _getCornerValues( const ConstPointSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& neighborKey , const FEMTreeNode* node , int corner , ConstPointer( V ) solution , ConstPointer( V ) coarseSolution , const _Evaluator< UIntPack< FEMSigs ... > , PointD >& evaluator , int maxDepth , bool isInterior ) const; - template< class V , unsigned int _PointD , unsigned int ... FEMSigs , unsigned int PointD > - CumulativeDerivativeValues< V , Dim , _PointD > _getValues ( const ConstPointSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& neighborKey , const FEMTreeNode* node , Point< Real , Dim > p , ConstPointer( V ) solution , ConstPointer( V ) coarseSolution , const _Evaluator< UIntPack< FEMSigs ... > , PointD >& evaluator , int maxDepth ) const; - template< class V , unsigned int _PointD , unsigned int ... FEMSigs , unsigned int PointD > - CumulativeDerivativeValues< V , Dim , _PointD > _getCornerValues( const ConstCornerSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& neighborKey , const FEMTreeNode* node , int corner , ConstPointer( V ) solution , ConstPointer( V ) coarseSolution , const _Evaluator< UIntPack< FEMSigs ... > , PointD >& evaluator , int maxDepth , bool isInterior ) const; - template< unsigned int ... SupportSizes > - struct CornerLoopData - { - typedef UIntPack< SupportSizes ... > _SupportSizes; - // static const unsigned int supportSizes[] = { SupportSizes ... }; - static const unsigned int supportSizes[]; - unsigned int ccSize[1<::Size ]; - unsigned int pcIndices[1<::Size ]; - CornerLoopData( void ) - { - int start[Dim] , end[Dim] , _start[Dim] , _end[Dim]; - for( int c=0 ; c<(1< , UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... > > CenterStencil; + typedef DynamicWindow< CumulativeDerivativeValues< double , Dim , PointD > , UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... > > CornerStencil; + typedef DynamicWindow< CumulativeDerivativeValues< double , Dim , PointD > , UIntPack< ( BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::BCornerSize + 1 ) ... > > BCornerStencil; + + typedef std::tuple< typename BSplineEvaluationData< FEMSigs >::template Evaluator< PointD > ... > Evaluators; + typedef std::tuple< typename BSplineEvaluationData< FEMSigs >::template ChildEvaluator< PointD > ... > ChildEvaluators; + struct StencilData { - ccSize[c] = 0; - for( int dd=0 ; dd>dd) & 1 ) start[dd]++; - else end [dd]--; - } - unsigned int idx[Dim]; - WindowLoop< Dim >::Run - ( - start , end , - [&]( int d , int i ){ idx[d] = i; } , - [&]( void ){ ccIndices[c][ ccSize[c]++ ] = GetWindowIndex( _SupportSizes() , idx ); } - ); + CenterStencil ccCenterStencil , pcCenterStencils[CHILDREN]; + CornerStencil ccCornerStencil[CHILDREN] , pcCornerStencils[CHILDREN][CHILDREN]; + BCornerStencil ccBCornerStencil[CHILDREN] , pcBCornerStencils[CHILDREN][CHILDREN]; + }; + Pointer( StencilData ) stencilData; + Pointer( Evaluators ) evaluators; + Pointer( ChildEvaluators ) childEvaluators; + + void set( LocalDepth depth ); + _Evaluator( void ){ _pointEvaluator = NULL ; stencilData = NullPointer( StencilData ) , evaluators = NullPointer( Evaluators ) , childEvaluators = NullPointer( ChildEvaluators ); } + ~_Evaluator( void ){ if( _pointEvaluator ) delete _pointEvaluator , _pointEvaluator = NULL ; if( stencilData ) DeletePointer( stencilData ) ; if( evaluators ) DeletePointer( evaluators ) ; if( childEvaluators ) DeletePointer( childEvaluators ); } + protected: + enum _CenterOffset{ CENTER=-1 , BACK=0 , FRONT=1 }; + template< unsigned int _PointD=PointD > CumulativeDerivativeValues< double , Dim , _PointD > _values( unsigned int d , const int fIdx[Dim] , const int idx[Dim] , const _CenterOffset off[Dim] , bool parentChild ) const; + template< unsigned int _PointD=PointD > CumulativeDerivativeValues< double , Dim , _PointD > _centerValues( unsigned int d , const int fIdx[Dim] , const int idx[Dim] , bool parentChild ) const; + template< unsigned int _PointD=PointD > CumulativeDerivativeValues< double , Dim , _PointD > _cornerValues( unsigned int d , const int fIdx[Dim] , const int idx[Dim] , int corner , bool parentChild ) const; + template< unsigned int _PointD=PointD , unsigned int I=0 > typename std::enable_if< I==Dim >::type _setDValues( unsigned int d , const int fIdx[] , const int cIdx[] , const _CenterOffset off[] , bool pc , double dValues[][_PointD+1] ) const{ } + template< unsigned int _PointD=PointD , unsigned int I=0 > typename std::enable_if< I< Dim >::type _setDValues( unsigned int d , const int fIdx[] , const int cIdx[] , const _CenterOffset off[] , bool pc , double dValues[][_PointD+1] ) const + { + if( pc ) for( int dd=0 ; dd<=_PointD ; dd++ ) dValues[I][dd] = off[I]==CENTER ? std::get< I >( childEvaluators[d] ).centerValue( fIdx[I] , cIdx[I] , dd ) : std::get< I >( childEvaluators[d] ).cornerValue( fIdx[I] , cIdx[I]+off[I] , dd ); + else for( int dd=0 ; dd<=_PointD ; dd++ ) dValues[I][dd] = off[I]==CENTER ? std::get< I >( evaluators[d] ).centerValue( fIdx[I] , cIdx[I] , dd ) : std::get< I >( evaluators[d] ).cornerValue( fIdx[I] , cIdx[I]+off[I] , dd ); + _setDValues< _PointD , I+1 >( d , fIdx , cIdx , off , pc , dValues ); + } + + template< unsigned int I=0 > typename std::enable_if< I==Dim >::type _setEvaluators( unsigned int maxDepth ){ } + template< unsigned int I=0 > typename std::enable_if< I< Dim >::type _setEvaluators( unsigned int maxDepth ) + { + static const unsigned int FEMSig = UIntPack< FEMSigs ... >::template Get< I >(); + for( unsigned int d=0 ; d<=maxDepth ; d++ ) BSplineEvaluationData< FEMSig >:: SetEvaluator( std::template get< I >( evaluators[d] ) , d ); + for( unsigned int d=1 ; d<=maxDepth ; d++ ) BSplineEvaluationData< FEMSig >::SetChildEvaluator( std::template get< I >( childEvaluators[d] ) , d-1 ); + _setEvaluators< I+1 >( maxDepth ); + } + typename FEMIntegrator::template PointEvaluator< UIntPack< FEMSigs ... > , IsotropicUIntPack< Dim , PointD > >* _pointEvaluator; + friend FEMTree; + }; - for( int _c=0 ; _c<(1< + CumulativeDerivativeValues< V , Dim , _PointD > _getCenterValues( const ConstPointSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& neighborKey , const FEMTreeNode* node , ConstPointer( V ) solution , ConstPointer( V ) coarseSolution , const _Evaluator< UIntPack< FEMSigs ... > , PointD >& evaluator , int maxDepth , bool isInterior ) const; + template< class V , unsigned int _PointD , unsigned int ... FEMSigs , unsigned int PointD > + CumulativeDerivativeValues< V , Dim , _PointD > _getCornerValues( const ConstPointSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& neighborKey , const FEMTreeNode* node , int corner , ConstPointer( V ) solution , ConstPointer( V ) coarseSolution , const _Evaluator< UIntPack< FEMSigs ... > , PointD >& evaluator , int maxDepth , bool isInterior ) const; + template< class V , unsigned int _PointD , unsigned int ... FEMSigs , unsigned int PointD > + CumulativeDerivativeValues< V , Dim , _PointD > _getValues ( const ConstPointSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& neighborKey , const FEMTreeNode* node , Point< Real , Dim > p , ConstPointer( V ) solution , ConstPointer( V ) coarseSolution , const _Evaluator< UIntPack< FEMSigs ... > , PointD >& evaluator , int maxDepth ) const; + template< class V , unsigned int _PointD , unsigned int ... FEMSigs , unsigned int PointD > + CumulativeDerivativeValues< V , Dim , _PointD > _getCornerValues( const ConstCornerSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& neighborKey , const FEMTreeNode* node , int corner , ConstPointer( V ) solution , ConstPointer( V ) coarseSolution , const _Evaluator< UIntPack< FEMSigs ... > , PointD >& evaluator , int maxDepth , bool isInterior ) const; + template< unsigned int ... SupportSizes > + struct CornerLoopData + { + typedef UIntPack< SupportSizes ... > _SupportSizes; + // static const unsigned int supportSizes[] = { SupportSizes ... }; + static const unsigned int supportSizes[]; + unsigned int ccSize[1<::Size ]; + unsigned int pcIndices[1<::Size ]; + CornerLoopData( void ) + { + int start[Dim] , end[Dim] , _start[Dim] , _end[Dim]; + for( int c=0 ; c<(1<>dd) & 1 ) != ( (c>>dd) & 1 ) ) _start[dd] = 0 , _end[dd] = supportSizes[dd]; - else _start[dd] = start[dd] , _end[dd] = end[dd]; + start[dd] = 0 , end[dd] = supportSizes[dd]; + if( (c>>dd) & 1 ) start[dd]++; + else end [dd]--; } - unsigned int idx[Dim]; WindowLoop< Dim >::Run ( - _start , _end , + start , end , [&]( int d , int i ){ idx[d] = i; } , - [&]( void ){ pcIndices[c][_c][ pcSize[c][_c]++ ] = GetWindowIndex( _SupportSizes() , idx ); } + [&]( void ){ ccIndices[c][ ccSize[c]++ ] = GetWindowIndex( _SupportSizes() , idx ); } ); + + for( int _c=0 ; _c<(1<>dd) & 1 ) != ( (c>>dd) & 1 ) ) _start[dd] = 0 , _end[dd] = supportSizes[dd]; + else _start[dd] = start[dd] , _end[dd] = end[dd]; + } + + unsigned int idx[Dim]; + WindowLoop< Dim >::Run + ( + _start , _end , + [&]( int d , int i ){ idx[d] = i; } , + [&]( void ){ pcIndices[c][_c][ pcSize[c][_c]++ ] = GetWindowIndex( _SupportSizes() , idx ); } + ); + } } } - } - }; -public: - template< typename Pack , unsigned int PointD , typename T > struct _MultiThreadedEvaluator{ }; - template< unsigned int ... FEMSigs , unsigned int PointD , typename T > - struct _MultiThreadedEvaluator< UIntPack< FEMSigs ... > , PointD , T > - { - typedef UIntPack< FEMSigs ... > FEMSignatures; - typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > FEMDegrees; - const FEMTree* _tree; - int _threads; - std::vector< ConstPointSupportKey< FEMDegrees > > _pointNeighborKeys; - std::vector< ConstCornerSupportKey< FEMDegrees > > _cornerNeighborKeys; - _Evaluator< FEMSignatures , PointD > _evaluator; - const DenseNodeData< T , FEMSignatures >& _coefficients; - DenseNodeData< T , FEMSignatures > _coarseCoefficients; - public: - _MultiThreadedEvaluator( const FEMTree* tree , const DenseNodeData< T , FEMSignatures >& coefficients , int threads=std::thread::hardware_concurrency() ); - template< unsigned int _PointD=PointD > CumulativeDerivativeValues< T , Dim , _PointD > values( Point< Real , Dim > p , int thread=0 , const FEMTreeNode* node=NULL ); - template< unsigned int _PointD=PointD > CumulativeDerivativeValues< T , Dim , _PointD > centerValues( const FEMTreeNode* node , int thread=0 ); - template< unsigned int _PointD=PointD > CumulativeDerivativeValues< T , Dim , _PointD > cornerValues( const FEMTreeNode* node , int corner , int thread=0 ); - }; - template< typename Pack , unsigned int PointD , typename T=Real > using MultiThreadedEvaluator = _MultiThreadedEvaluator< Pack , PointD , T >; - template< unsigned int DensityDegree > - struct MultiThreadedWeightEvaluator - { - const FEMTree* _tree; - int _threads; - std::vector< ConstPointSupportKey< IsotropicUIntPack< Dim , DensityDegree > > > _neighborKeys; - const DensityEstimator< DensityDegree >& _density; + }; public: - MultiThreadedWeightEvaluator( const FEMTree* tree , const DensityEstimator< DensityDegree >& density , int threads=std::thread::hardware_concurrency() ); - Real weight( Point< Real , Dim > p , int thread=0 ); - }; + template< typename Pack , unsigned int PointD , typename T > struct _MultiThreadedEvaluator{ }; + template< unsigned int ... FEMSigs , unsigned int PointD , typename T > + struct _MultiThreadedEvaluator< UIntPack< FEMSigs ... > , PointD , T > + { + typedef UIntPack< FEMSigs ... > FEMSignatures; + typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > FEMDegrees; + const FEMTree* _tree; + int _threads; + std::vector< ConstPointSupportKey< FEMDegrees > > _pointNeighborKeys; + std::vector< ConstCornerSupportKey< FEMDegrees > > _cornerNeighborKeys; + _Evaluator< FEMSignatures , PointD > _evaluator; + const DenseNodeData< T , FEMSignatures >& _coefficients; + DenseNodeData< T , FEMSignatures > _coarseCoefficients; + public: + _MultiThreadedEvaluator( const FEMTree* tree , const DenseNodeData< T , FEMSignatures >& coefficients , int threads=std::thread::hardware_concurrency() ); + template< unsigned int _PointD=PointD > CumulativeDerivativeValues< T , Dim , _PointD > values( Point< Real , Dim > p , int thread=0 , const FEMTreeNode* node=NULL ); + template< unsigned int _PointD=PointD > CumulativeDerivativeValues< T , Dim , _PointD > centerValues( const FEMTreeNode* node , int thread=0 ); + template< unsigned int _PointD=PointD > CumulativeDerivativeValues< T , Dim , _PointD > cornerValues( const FEMTreeNode* node , int corner , int thread=0 ); + }; + template< typename Pack , unsigned int PointD , typename T=Real > using MultiThreadedEvaluator = _MultiThreadedEvaluator< Pack , PointD , T >; + template< unsigned int DensityDegree > + struct MultiThreadedWeightEvaluator + { + const FEMTree* _tree; + int _threads; + std::vector< ConstPointSupportKey< IsotropicUIntPack< Dim , DensityDegree > > > _neighborKeys; + const DensityEstimator< DensityDegree >& _density; + public: + MultiThreadedWeightEvaluator( const FEMTree* tree , const DensityEstimator< DensityDegree >& density , int threads=std::thread::hardware_concurrency() ); + Real weight( Point< Real , Dim > p , int thread=0 ); + }; - template< typename Pack , typename T > struct MultiThreadedSparseEvaluator{ }; - template< unsigned int ... FEMSigs , typename T > - struct MultiThreadedSparseEvaluator< UIntPack< FEMSigs ... > , T > - { - typedef UIntPack< FEMSigs ... > FEMSignatures; - typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > FEMDegrees; - const FEMTree* _tree; - int _threads; - std::vector< ConstPointSupportKey< FEMDegrees > > _pointNeighborKeys; - typename FEMIntegrator::template PointEvaluator< UIntPack< FEMSigs ... > , ZeroUIntPack< Dim > > *_pointEvaluator; - const SparseNodeData< T , FEMSignatures >& _coefficients; - public: - MultiThreadedSparseEvaluator( const FEMTree* tree , const SparseNodeData< T , FEMSignatures >& coefficients , int threads=std::thread::hardware_concurrency() ); - ~MultiThreadedSparseEvaluator( void ){ if( _pointEvaluator ) delete _pointEvaluator; } - void addValue( Point< Real , Dim > p , T &t , int thread=0 , const FEMTreeNode* node=NULL ); - }; + template< typename Pack , typename T > struct MultiThreadedSparseEvaluator{ }; + template< unsigned int ... FEMSigs , typename T > + struct MultiThreadedSparseEvaluator< UIntPack< FEMSigs ... > , T > + { + typedef UIntPack< FEMSigs ... > FEMSignatures; + typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > FEMDegrees; + const FEMTree* _tree; + int _threads; + std::vector< ConstPointSupportKey< FEMDegrees > > _pointNeighborKeys; + typename FEMIntegrator::template PointEvaluator< UIntPack< FEMSigs ... > , ZeroUIntPack< Dim > > *_pointEvaluator; + const SparseNodeData< T , FEMSignatures >& _coefficients; + public: + MultiThreadedSparseEvaluator( const FEMTree* tree , const SparseNodeData< T , FEMSignatures >& coefficients , int threads=std::thread::hardware_concurrency() ); + ~MultiThreadedSparseEvaluator( void ){ if( _pointEvaluator ) delete _pointEvaluator; } + void addValue( Point< Real , Dim > p , T &t , int thread=0 , const FEMTreeNode* node=NULL ); + }; -protected: + protected: - template< unsigned int Idx , typename ... DenseOrSparseNodeData > - typename std::enable_if< ( Idx==sizeof...(DenseOrSparseNodeData) ) >::type _reorderDenseOrSparseNodeData( ConstPointer( node_index_type ) map , size_t sz , std::tuple< DenseOrSparseNodeData* ... > data ){} - template< unsigned int Idx , typename ... DenseOrSparseNodeData > - typename std::enable_if< ( Idx ::type _reorderDenseOrSparseNodeData( ConstPointer( node_index_type ) map , size_t sz , std::tuple< DenseOrSparseNodeData* ... > data ) - { - if( std::get( data ) ) std::get( data )->_remapIndices( map , sz ); - _reorderDenseOrSparseNodeData< Idx+1 >( map , sz , data ); - } + template< unsigned int Idx , typename ... DenseOrSparseNodeData > + typename std::enable_if< ( Idx==sizeof...(DenseOrSparseNodeData) ) >::type _reorderDenseOrSparseNodeData( ConstPointer( node_index_type ) map , size_t sz , std::tuple< DenseOrSparseNodeData* ... > data ){} + template< unsigned int Idx , typename ... DenseOrSparseNodeData > + typename std::enable_if< ( Idx ::type _reorderDenseOrSparseNodeData( ConstPointer( node_index_type ) map , size_t sz , std::tuple< DenseOrSparseNodeData* ... > data ) + { + if( std::get( data ) ) std::get( data )->_remapIndices( map , sz ); + _reorderDenseOrSparseNodeData< Idx+1 >( map , sz , data ); + } - template< unsigned int Idx , typename ... InterpolationInfos > - typename std::enable_if< ( Idx==sizeof...(InterpolationInfos) ) >::type _reorderInterpolationInfo( ConstPointer( node_index_type ) map , size_t sz , std::tuple< InterpolationInfos* ... > interpolationInfos ){} - template< unsigned int Idx , typename ... InterpolationInfos > - typename std::enable_if< ( Idx ::type _reorderInterpolationInfo( ConstPointer( node_index_type ) map , size_t sz , std::tuple< InterpolationInfos* ... > interpolationInfos ) - { - if( std::get( interpolationInfos ) ) std::get( interpolationInfos )->_remapIndices( map , sz ); - _reorderInterpolationInfo< Idx+1 >( map , sz , interpolationInfos ); - } + template< unsigned int Idx , typename ... InterpolationInfos > + typename std::enable_if< ( Idx==sizeof...(InterpolationInfos) ) >::type _reorderInterpolationInfo( ConstPointer( node_index_type ) map , size_t sz , std::tuple< InterpolationInfos* ... > interpolationInfos ){} + template< unsigned int Idx , typename ... InterpolationInfos > + typename std::enable_if< ( Idx ::type _reorderInterpolationInfo( ConstPointer( node_index_type ) map , size_t sz , std::tuple< InterpolationInfos* ... > interpolationInfos ) + { + if( std::get( interpolationInfos ) ) std::get( interpolationInfos )->_remapIndices( map , sz ); + _reorderInterpolationInfo< Idx+1 >( map , sz , interpolationInfos ); + } -public: + public: - FEMTree( size_t blockSize ); - FEMTree( BinaryStream &stream , XForm< Real , Dim+1 > &xForm , size_t blockSize ); - template< unsigned int CrossDegree , unsigned int Pad > - static FEMTree< Dim , Real > *Slice( const FEMTree< Dim+1 , Real > &tree , unsigned int sliceDepth , unsigned int sliceIndex , bool includeBounds , size_t blockSize ); + FEMTree( size_t blockSize ); + FEMTree( BinaryStream &stream , XForm< Real , Dim+1 > &xForm , size_t blockSize ); + template< unsigned int CrossDegree , unsigned int Pad > + static FEMTree< Dim , Real > *Slice( const FEMTree< Dim+1 , Real > &tree , unsigned int sliceDepth , unsigned int sliceIndex , bool includeBounds , size_t blockSize ); - static FEMTree< Dim , Real > *Merge( const FEMTree< Dim , Real > &tree1 , const FEMTree< Dim , Real > &tree2 , size_t blockSize ); - ~FEMTree( void ) - { - _tree.cleanChildren( !nodeAllocators.size() ); - for( size_t i=0 ; i xForm , bool serialize ) const; - static void WriteParameter( BinaryStream &stream ) - { - FEMTreeRealType realType; - if ( typeid( Real )==typeid( float ) ) realType=FEM_TREE_REAL_FLOAT; - else if( typeid( Real )==typeid( double ) ) realType=FEM_TREE_REAL_DOUBLE; - else ERROR_OUT( "Unrecognized real type" ); - stream.write( realType ); - int dim = Dim; - stream.write( dim ); - } + static FEMTree< Dim , Real > *Merge( const FEMTree< Dim , Real > &tree1 , const FEMTree< Dim , Real > &tree2 , size_t blockSize ); + ~FEMTree( void ) + { + _tree.cleanChildren( !nodeAllocators.size() ); + for( size_t i=0 ; i xForm , bool serialize ) const; + static void WriteParameter( BinaryStream &stream ) + { + FEMTreeRealType realType; + if ( typeid( Real )==typeid( float ) ) realType=FEM_TREE_REAL_FLOAT; + else if( typeid( Real )==typeid( double ) ) realType=FEM_TREE_REAL_DOUBLE; + else ERROR_OUT( "Unrecognized real type" ); + stream.write( realType ); + int dim = Dim; + stream.write( dim ); + } - template< unsigned int LeftRadius , unsigned int RightRadius , bool CreateNodes , typename ProcessingNodeFunctor , typename ... DenseOrSparseNodeData , typename InitializeFunctor > void processNeighbors( ProcessingNodeFunctor processNodes , std::tuple< DenseOrSparseNodeData *... > data , InitializeFunctor initialize ); - template< unsigned int LeftRadius , unsigned int RightRadius , bool CreateNodes , typename ... DenseOrSparseNodeData , typename InitializeFunctor > void processNeighbors( FEMTreeNode** nodes , size_t nodeCount , std::tuple< DenseOrSparseNodeData *... > data , InitializeFunctor initialize ); - template< unsigned int Radius , bool CreateNodes , typename ProcessingNodeFunctor , typename ... DenseOrSparseNodeData , typename InitializeFunctor > void processNeighbors( ProcessingNodeFunctor processNodes , std::tuple< DenseOrSparseNodeData *... > data , InitializeFunctor initialize ){ processNeighbors< Radius , Radius , CreateNodes >( processNodes , data , initialize ); } - template< unsigned int Radius , bool CreateNodes , typename ... DenseOrSparseNodeData , typename InitializeFunctor > void processNeighbors( FEMTreeNode** nodes , size_t nodeCount , std::tuple< DenseOrSparseNodeData *... > data , InitializeFunctor initialize ){ processNeighbors< Radius , Radius , CreateNodes >( nodes , nodeCount , data , initialize ); } - - template< unsigned int LeftRadius , unsigned int RightRadius , bool CreateNodes , typename ProcessingNodeFunctor , typename ... DenseOrSparseNodeData > void processNeighbors( ProcessingNodeFunctor processNodes , std::tuple< DenseOrSparseNodeData *... > data ){ return processNeighbors< LeftRadius , RightRadius , CreateNodes >( processNodes , data , []( const FEMTreeNode * ){} ); } - template< unsigned int LeftRadius , unsigned int RightRadius , bool CreateNodes , typename ... DenseOrSparseNodeData > void processNeighbors( FEMTreeNode** nodes , size_t nodeCount , std::tuple< DenseOrSparseNodeData *... > data ){ return processNeighbors< LeftRadius , RightRadius , CreateNodes >( nodes , nodeCount , data , []( const FEMTreeNode * ){} ); } - template< unsigned int Radius , bool CreateNodes , typename ProcessingNodeFunctor , typename ... DenseOrSparseNodeData > void processNeighbors( ProcessingNodeFunctor processNodes , std::tuple< DenseOrSparseNodeData *... > data ){ return processNeighbors< Radius , CreateNodes >( processNodes , data , []( const FEMTreeNode * ){} ); } - template< unsigned int Radius , bool CreateNodes , typename ... DenseOrSparseNodeData > void processNeighbors( FEMTreeNode** nodes , size_t nodeCount , std::tuple< DenseOrSparseNodeData *... > data ){ return processNeighbors< Radius , CreateNodes >( nodes , nodeCount , data , []( const FEMTreeNode * ){} ) ; } - - template< unsigned int LeftRadius , unsigned int RightRadius , typename IsProcessingNodeFunctor , typename ProcessingKernel > void processNeighboringLeaves( IsProcessingNodeFunctor isProcessingNode , ProcessingKernel kernel , bool processSubTree ); - template< unsigned int LeftRadius , unsigned int RightRadius , typename ProcessingKernel > void processNeighboringLeaves( FEMTreeNode** nodes , size_t nodeCount , ProcessingKernel kernel , bool processSubTree ); - template< unsigned int Radius , typename IsProcessingNodeFunctor , typename ProcessingKernel > void processNeighboringLeaves( IsProcessingNodeFunctor isProcessingNode , ProcessingKernel kernel , bool processSubTree ){ return processNeighboringLeaves< Radius , Radius >( isProcessingNode , kernel , processSubTree ); } - template< unsigned int Radius , typename ProcessingKernel > void processNeighboringLeaves( FEMTreeNode** nodes , size_t nodeCount , ProcessingKernel kernel , bool processSubTree ){ return processNeighboringLeaves< Radius , Radius >( nodes , nodeCount , kernel , processSubTree ); } - - template< unsigned int CoDim , unsigned int DensityDegree > - typename FEMTree::template DensityEstimator< DensityDegree > *setDensityEstimator( const std::vector< PointSample >& samples , LocalDepth splatDepth , Real samplesPerNode ); - template< unsigned int CoDim , unsigned int DensityDegree > - void updateDensityEstimator( typename FEMTree::template DensityEstimator< DensityDegree > &density , const std::vector< PointSample >& samples , LocalDepth minSplatDepth , LocalDepth maxSplatDepth , Real samplesPerNode ); - template< unsigned int CoDim , unsigned int DensityDegree > - typename FEMTree::template DensityEstimator< DensityDegree > *setDensityEstimator( const std::vector< PointSample >& samples , LocalDepth splatDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real samplesPerNode ); - template< unsigned int CoDim , unsigned int DensityDegree > - void updateDensityEstimator( typename FEMTree::template DensityEstimator< DensityDegree > &density , const std::vector< PointSample >& samples , LocalDepth minSplatDepth , LocalDepth maxSplatDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real samplesPerNode ); - - template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > - SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction ); + template< unsigned int LeftRadius , unsigned int RightRadius , bool CreateNodes , typename ProcessingNodeFunctor , typename ... DenseOrSparseNodeData , typename InitializeFunctor > void processNeighbors( ProcessingNodeFunctor processNodes , std::tuple< DenseOrSparseNodeData *... > data , InitializeFunctor initialize ); + template< unsigned int LeftRadius , unsigned int RightRadius , bool CreateNodes , typename ... DenseOrSparseNodeData , typename InitializeFunctor > void processNeighbors( FEMTreeNode** nodes , size_t nodeCount , std::tuple< DenseOrSparseNodeData *... > data , InitializeFunctor initialize ); + template< unsigned int Radius , bool CreateNodes , typename ProcessingNodeFunctor , typename ... DenseOrSparseNodeData , typename InitializeFunctor > void processNeighbors( ProcessingNodeFunctor processNodes , std::tuple< DenseOrSparseNodeData *... > data , InitializeFunctor initialize ){ processNeighbors< Radius , Radius , CreateNodes >( processNodes , data , initialize ); } + template< unsigned int Radius , bool CreateNodes , typename ... DenseOrSparseNodeData , typename InitializeFunctor > void processNeighbors( FEMTreeNode** nodes , size_t nodeCount , std::tuple< DenseOrSparseNodeData *... > data , InitializeFunctor initialize ){ processNeighbors< Radius , Radius , CreateNodes >( nodes , nodeCount , data , initialize ); } + + template< unsigned int LeftRadius , unsigned int RightRadius , bool CreateNodes , typename ProcessingNodeFunctor , typename ... DenseOrSparseNodeData > void processNeighbors( ProcessingNodeFunctor processNodes , std::tuple< DenseOrSparseNodeData *... > data ){ return processNeighbors< LeftRadius , RightRadius , CreateNodes >( processNodes , data , []( const FEMTreeNode * ){} ); } + template< unsigned int LeftRadius , unsigned int RightRadius , bool CreateNodes , typename ... DenseOrSparseNodeData > void processNeighbors( FEMTreeNode** nodes , size_t nodeCount , std::tuple< DenseOrSparseNodeData *... > data ){ return processNeighbors< LeftRadius , RightRadius , CreateNodes >( nodes , nodeCount , data , []( const FEMTreeNode * ){} ); } + template< unsigned int Radius , bool CreateNodes , typename ProcessingNodeFunctor , typename ... DenseOrSparseNodeData > void processNeighbors( ProcessingNodeFunctor processNodes , std::tuple< DenseOrSparseNodeData *... > data ){ return processNeighbors< Radius , CreateNodes >( processNodes , data , []( const FEMTreeNode * ){} ); } + template< unsigned int Radius , bool CreateNodes , typename ... DenseOrSparseNodeData > void processNeighbors( FEMTreeNode** nodes , size_t nodeCount , std::tuple< DenseOrSparseNodeData *... > data ){ return processNeighbors< Radius , CreateNodes >( nodes , nodeCount , data , []( const FEMTreeNode * ){} ) ; } + + template< unsigned int LeftRadius , unsigned int RightRadius , typename IsProcessingNodeFunctor , typename ProcessingKernel > void processNeighboringLeaves( IsProcessingNodeFunctor isProcessingNode , ProcessingKernel kernel , bool processSubTree ); + template< unsigned int LeftRadius , unsigned int RightRadius , typename ProcessingKernel > void processNeighboringLeaves( FEMTreeNode** nodes , size_t nodeCount , ProcessingKernel kernel , bool processSubTree ); + template< unsigned int Radius , typename IsProcessingNodeFunctor , typename ProcessingKernel > void processNeighboringLeaves( IsProcessingNodeFunctor isProcessingNode , ProcessingKernel kernel , bool processSubTree ){ return processNeighboringLeaves< Radius , Radius >( isProcessingNode , kernel , processSubTree ); } + template< unsigned int Radius , typename ProcessingKernel > void processNeighboringLeaves( FEMTreeNode** nodes , size_t nodeCount , ProcessingKernel kernel , bool processSubTree ){ return processNeighboringLeaves< Radius , Radius >( nodes , nodeCount , kernel , processSubTree ); } + + template< unsigned int CoDim , unsigned int DensityDegree > + typename FEMTree::template DensityEstimator< DensityDegree > *setDensityEstimator( const std::vector< PointSample >& samples , LocalDepth splatDepth , Real samplesPerNode ); + template< unsigned int CoDim , unsigned int DensityDegree > + void updateDensityEstimator( typename FEMTree::template DensityEstimator< DensityDegree > &density , const std::vector< PointSample >& samples , LocalDepth minSplatDepth , LocalDepth maxSplatDepth , Real samplesPerNode ); + template< unsigned int CoDim , unsigned int DensityDegree > + typename FEMTree::template DensityEstimator< DensityDegree > *setDensityEstimator( const std::vector< PointSample >& samples , LocalDepth splatDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real samplesPerNode ); + template< unsigned int CoDim , unsigned int DensityDegree > + void updateDensityEstimator( typename FEMTree::template DensityEstimator< DensityDegree > &density , const std::vector< PointSample >& samples , LocalDepth minSplatDepth , LocalDepth maxSplatDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real samplesPerNode ); + + template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > + SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction ); #if defined(_WIN32) || defined(_WIN64) - template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > - SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction = []( InData ){ return 0.f; } ); + template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > + SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction = []( InData ){ return 0.f; } ); #else // !_WIN32 && !_WIN64 - template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > - SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction = []( InData ){ return (Real)0; } ); + template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > + SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction = []( InData ){ return (Real)0; } ); #endif // _WIN32 || _WIN64 - template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > - SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction ); + template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > + SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction ); #if defined(_WIN32) || defined(_WIN64) - template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > - SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction = []( InData ){ return 0.f; } ); + template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > + SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction = []( InData ){ return 0.f; } ); #else // !_WIN32 && !_WIN64 - template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > - SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction = []( InData ){ return (Real)0; } ); + template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > + SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction = []( InData ){ return (Real)0; } ); #endif // _WIN32 || _WIN64 - template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data > - SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > setExtrapolatedDataField( const std::vector< PointSample >& samples , const std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density , bool nearest=false ); - template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data > - void updateExtrapolatedDataField( SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > &dataField , const std::vector< PointSample >& samples , const std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density , bool nearest=false ); + template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data > + SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > setExtrapolatedDataField( const std::vector< PointSample >& samples , const std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density , bool nearest=false ); + template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data > + void updateExtrapolatedDataField( SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > &dataField , const std::vector< PointSample >& samples , const std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density , bool nearest=false ); - template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data , class SampleFunctor /* = std::function< const PointSample & (size_t) >*/ , class SampleDataFunctor /* = std::function< const Data & (size_t) > */ > - SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > setExtrapolatedDataField( size_t sampleNum , SampleFunctor sampleFunctor , SampleDataFunctor sampleDataFunctor , const DensityEstimator< DensityDegree >* density , bool nearest=false ); - template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data , class SampleFunctor /* = std::function< const PointSample & (size_t) >*/ , class SampleDataFunctor /* = std::function< const Data & (size_t) > */ > - void updateExtrapolatedDataField( SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > &dataField , size_t sampleNum , SampleFunctor sampleFunctor , SampleDataFunctor sampleDataFunctor , const DensityEstimator< DensityDegree >* density , bool nearest=false ); + template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data , class SampleFunctor /* = std::function< const PointSample & (size_t) >*/ , class SampleDataFunctor /* = std::function< const Data & (size_t) > */ > + SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > setExtrapolatedDataField( size_t sampleNum , SampleFunctor sampleFunctor , SampleDataFunctor sampleDataFunctor , const DensityEstimator< DensityDegree >* density , bool nearest=false ); + template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data , class SampleFunctor /* = std::function< const PointSample & (size_t) >*/ , class SampleDataFunctor /* = std::function< const Data & (size_t) > */ > + void updateExtrapolatedDataField( SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > &dataField , size_t sampleNum , SampleFunctor sampleFunctor , SampleDataFunctor sampleDataFunctor , const DensityEstimator< DensityDegree >* density , bool nearest=false ); - template< unsigned int MaxDegree , unsigned int SystemDegree , typename AddNodeFunctor , typename HasDataFunctor , typename IsDirichletLeafFunctor , typename ... InterpolationInfos , typename ... DenseOrSparseNodeData > std::vector< node_index_type > finalizeForMultigridWithDirichlet( LocalDepth baseDepth , const AddNodeFunctor addNodeFunctor , const HasDataFunctor hasDataFunctor , const IsDirichletLeafFunctor isDirichletLeafFunctor , std::tuple< InterpolationInfos *... > interpolationInfos , std::tuple< DenseOrSparseNodeData *... > data ); - template< unsigned int MaxDegree , unsigned int SystemDegree , typename AddNodeFunctor , typename HasDataFunctor , typename IsDirichletLeafFunctor , typename ... InterpolationInfos > std::vector< node_index_type > finalizeForMultigridWithDirichlet( LocalDepth baseDepth , const AddNodeFunctor addNodeFunctor , const HasDataFunctor hasDataFunctor , const IsDirichletLeafFunctor isDirichletLeafFunctor , std::tuple< InterpolationInfos *... > interpolationInfos ){ return finalizeForMultigridWithDirichlet< MaxDegree , SystemDegree , AddNodeFunctor , HasDataFunctor >( baseDepth , addNodeFunctor , hasDataFunctor , isDirichletLeafFunctor , interpolationInfos , std::make_tuple() ); } + template< unsigned int MaxDegree , unsigned int SystemDegree , typename AddNodeFunctor , typename HasDataFunctor , typename IsDirichletLeafFunctor , typename ... InterpolationInfos , typename ... DenseOrSparseNodeData > std::vector< node_index_type > finalizeForMultigridWithDirichlet( LocalDepth baseDepth , const AddNodeFunctor addNodeFunctor , const HasDataFunctor hasDataFunctor , const IsDirichletLeafFunctor isDirichletLeafFunctor , std::tuple< InterpolationInfos *... > interpolationInfos , std::tuple< DenseOrSparseNodeData *... > data ); + template< unsigned int MaxDegree , unsigned int SystemDegree , typename AddNodeFunctor , typename HasDataFunctor , typename IsDirichletLeafFunctor , typename ... InterpolationInfos > std::vector< node_index_type > finalizeForMultigridWithDirichlet( LocalDepth baseDepth , const AddNodeFunctor addNodeFunctor , const HasDataFunctor hasDataFunctor , const IsDirichletLeafFunctor isDirichletLeafFunctor , std::tuple< InterpolationInfos *... > interpolationInfos ){ return finalizeForMultigridWithDirichlet< MaxDegree , SystemDegree , AddNodeFunctor , HasDataFunctor >( baseDepth , addNodeFunctor , hasDataFunctor , isDirichletLeafFunctor , interpolationInfos , std::make_tuple() ); } - template< unsigned int MaxDegree , unsigned int SystemDegree , typename AddNodeFunctor , typename HasDataFunctor , typename ... InterpolationInfos , typename ... DenseOrSparseNodeData > std::vector< node_index_type > finalizeForMultigrid( LocalDepth baseDepth , const AddNodeFunctor addNodeFunctor , const HasDataFunctor hasDataFunctor , std::tuple< InterpolationInfos *... > interpolationInfos , std::tuple< DenseOrSparseNodeData *... > data ); - template< unsigned int MaxDegree , unsigned int SystemDegree , typename AddNodeFunctor , typename HasDataFunctor , typename ... InterpolationInfos > std::vector< node_index_type > finalizeForMultigrid( LocalDepth baseDepth , const AddNodeFunctor addNodeFunctor , const HasDataFunctor hasDataFunctor , std::tuple< InterpolationInfos *... > interpolationInfos ){ return finalizeForMultigrid< MaxDegree , SystemDegree , AddNodeFunctor , HasDataFunctor >( baseDepth , addNodeFunctor , hasDataFunctor , interpolationInfos , std::make_tuple() ); } + template< unsigned int MaxDegree , unsigned int SystemDegree , typename AddNodeFunctor , typename HasDataFunctor , typename ... InterpolationInfos , typename ... DenseOrSparseNodeData > std::vector< node_index_type > finalizeForMultigrid( LocalDepth baseDepth , const AddNodeFunctor addNodeFunctor , const HasDataFunctor hasDataFunctor , std::tuple< InterpolationInfos *... > interpolationInfos , std::tuple< DenseOrSparseNodeData *... > data ); + template< unsigned int MaxDegree , unsigned int SystemDegree , typename AddNodeFunctor , typename HasDataFunctor , typename ... InterpolationInfos > std::vector< node_index_type > finalizeForMultigrid( LocalDepth baseDepth , const AddNodeFunctor addNodeFunctor , const HasDataFunctor hasDataFunctor , std::tuple< InterpolationInfos *... > interpolationInfos ){ return finalizeForMultigrid< MaxDegree , SystemDegree , AddNodeFunctor , HasDataFunctor >( baseDepth , addNodeFunctor , hasDataFunctor , interpolationInfos , std::make_tuple() ); } -protected: - template< bool HasDirichlet , unsigned int MaxDegree , unsigned int SystemDegree , typename AddNodeFunctor , typename HasDataFunctor , typename IsDirichletLeafFunctor , typename ... InterpolationInfos , typename ... DenseOrSparseNodeData > - std::vector< node_index_type > _finalizeForMultigrid( LocalDepth baseDepth , const AddNodeFunctor addNodeFunctor , const HasDataFunctor hasDataFunctor , const IsDirichletLeafFunctor isDirichletLeafFunctor , std::tuple< InterpolationInfos *... > interpolationInfos , std::tuple< DenseOrSparseNodeData *... > data ); -public: - template< typename ... InterpolationInfos , typename ... DenseOrSparseNodeData > std::vector< node_index_type > setSortedTreeNodes( std::tuple< InterpolationInfos *... > interpolationInfos , std::tuple< DenseOrSparseNodeData *... > data ); - template< typename ... InterpolationInfos > std::vector< node_index_type > setSortedTreeNodes( std::tuple< InterpolationInfos *... > interpolationInfos ){ return setSortedTreeNodes( interpolationInfos , std::make_tuple() ); } + protected: + template< bool HasDirichlet , unsigned int MaxDegree , unsigned int SystemDegree , typename AddNodeFunctor , typename HasDataFunctor , typename IsDirichletLeafFunctor , typename ... InterpolationInfos , typename ... DenseOrSparseNodeData > + std::vector< node_index_type > _finalizeForMultigrid( LocalDepth baseDepth , const AddNodeFunctor addNodeFunctor , const HasDataFunctor hasDataFunctor , const IsDirichletLeafFunctor isDirichletLeafFunctor , std::tuple< InterpolationInfos *... > interpolationInfos , std::tuple< DenseOrSparseNodeData *... > data ); + public: + template< typename ... InterpolationInfos , typename ... DenseOrSparseNodeData > std::vector< node_index_type > setSortedTreeNodes( std::tuple< InterpolationInfos *... > interpolationInfos , std::tuple< DenseOrSparseNodeData *... > data ); + template< typename ... InterpolationInfos > std::vector< node_index_type > setSortedTreeNodes( std::tuple< InterpolationInfos *... > interpolationInfos ){ return setSortedTreeNodes( interpolationInfos , std::make_tuple() ); } - template< class ... DenseOrSparseNodeData > void resetIndices( std::tuple< DenseOrSparseNodeData *... > data ); + template< class ... DenseOrSparseNodeData > void resetIndices( std::tuple< DenseOrSparseNodeData *... > data ); - template< typename PruneChildrenFunctor , typename ... InterpolationInfos , typename ... DenseOrSparseNodeData > - void pruneChildren( const PruneChildrenFunctor pruneChildren , std::tuple< InterpolationInfos *... > interpolationInfos , std::tuple< DenseOrSparseNodeData *... > data ); + template< typename PruneChildrenFunctor , typename ... InterpolationInfos , typename ... DenseOrSparseNodeData > + void pruneChildren( const PruneChildrenFunctor pruneChildren , std::tuple< InterpolationInfos *... > interpolationInfos , std::tuple< DenseOrSparseNodeData *... > data ); - template< unsigned int ... FEMSigs > DenseNodeData< Real , UIntPack< FEMSigs ... > > initDenseNodeData( UIntPack< FEMSigs ... > ) const; - template< class Data , unsigned int ... FEMSigs > DenseNodeData< Data , UIntPack< FEMSigs ... > > initDenseNodeData( UIntPack< FEMSigs ... > ) const; + template< unsigned int ... FEMSigs > DenseNodeData< Real , UIntPack< FEMSigs ... > > initDenseNodeData( UIntPack< FEMSigs ... > ) const; + template< class Data , unsigned int ... FEMSigs > DenseNodeData< Data , UIntPack< FEMSigs ... > > initDenseNodeData( UIntPack< FEMSigs ... > ) const; - template< unsigned int Pad , unsigned int FEMSig , unsigned int ... FEMSigs , typename Data > - void slice( const FEMTree< Dim+1 , Real > &tree , unsigned int d , const DenseNodeData< Data , UIntPack< FEMSigs ... , FEMSig > > &coefficients , DenseNodeData< Data , UIntPack< FEMSigs ... > > &sliceCoefficients , unsigned int sliceDepth , unsigned int sliceIndex ) const; + template< unsigned int Pad , unsigned int FEMSig , unsigned int ... FEMSigs , typename Data > + void slice( const FEMTree< Dim+1 , Real > &tree , unsigned int d , const DenseNodeData< Data , UIntPack< FEMSigs ... , FEMSig > > &coefficients , DenseNodeData< Data , UIntPack< FEMSigs ... > > &sliceCoefficients , unsigned int sliceDepth , unsigned int sliceIndex ) const; - template< unsigned int ... FEMSigs , typename Data > - void merge( const FEMTree< Dim , Real > &tree , const DenseNodeData< Data , UIntPack< FEMSigs ... > > &coefficients , DenseNodeData< Data , UIntPack< FEMSigs ... > > &mergedCoefficients ) const; + template< unsigned int ... FEMSigs , typename Data > + void merge( const FEMTree< Dim , Real > &tree , const DenseNodeData< Data , UIntPack< FEMSigs ... > > &coefficients , DenseNodeData< Data , UIntPack< FEMSigs ... > > &mergedCoefficients ) const; - // Add multiple-dimensions -> one-dimension constraints - template< typename T , unsigned int ... FEMDegrees , unsigned int ... FEMSigs , unsigned int ... CDegrees , unsigned int ... CSigs , unsigned int CDim > - void addFEMConstraints( typename BaseFEMIntegrator::template Constraint< UIntPack< FEMDegrees ... > , UIntPack< CDegrees ... > , CDim >& F , const _SparseOrDenseNodeData< Point< T , CDim > , UIntPack< CSigs ... > >& coefficients , DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , LocalDepth maxDepth ) const - { - typedef SparseNodeData< Point< T , CDim > , UIntPack< CSigs ... > > SparseType; - typedef DenseNodeData< Point< T , CDim > , UIntPack< CSigs ... > > DenseType; - static_assert( sizeof...( FEMDegrees )==Dim && sizeof...( FEMSigs )==Dim && sizeof...( CDegrees )==Dim && sizeof...( CSigs )==Dim , "[ERROR] Dimensions don't match" ); - static_assert( UIntPack< FEMDegrees ... >::template Compare< UIntPack< FEMSignature< FEMSigs >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); - static_assert( UIntPack< CDegrees ... >::template Compare< UIntPack< FEMSignature< CSigs >::Degree ... > >::Equal , "[ERROR] Constraint signature and degrees don't match" ); - if ( typeid(coefficients)==typeid(SparseType) ) return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< CSigs ... >() , F , static_cast< const SparseType& >( coefficients ) , constraints() , maxDepth ); - else if( typeid(coefficients)==typeid( DenseType) ) return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< CSigs ... >() , F , static_cast< const DenseType& >( coefficients ) , constraints() , maxDepth ); - else return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< CSigs ... >() , F , coefficients , constraints() , maxDepth ); - } - // Add one-dimensions -> one-dimension constraints (with distinct signatures) - template< typename T , unsigned int ... FEMDegrees , unsigned int ... FEMSigs , unsigned int ... CDegrees , unsigned int ... CSigs > - void addFEMConstraints( typename BaseFEMIntegrator::template Constraint< UIntPack< FEMDegrees ... > , UIntPack< CDegrees ... > , 1 >& F , const _SparseOrDenseNodeData< T , UIntPack< CSigs ... > >& coefficients , DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , LocalDepth maxDepth ) const - { - typedef SparseNodeData< T , UIntPack< CSigs ... > > SparseType; - typedef DenseNodeData< T , UIntPack< CSigs ... > > DenseType; - static_assert( sizeof...( FEMDegrees )==Dim && sizeof...( FEMSigs )==Dim && sizeof...( CDegrees )==Dim && sizeof...( CSigs )==Dim , "[ERROR] Dimensions don't match" ); - static_assert( UIntPack< FEMDegrees ... >::template Compare< UIntPack< FEMSignature< FEMSigs >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); - static_assert( UIntPack< CDegrees ... >::template Compare< UIntPack< FEMSignature< CSigs >::Degree ... > >::Equal , "[ERROR] Constaint signature and degrees don't match" ); - if ( typeid(coefficients)==typeid(SparseType) ) return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< CSigs ... >() , F , static_cast< const SparseType& >( coefficients ) , constraints() , maxDepth ); - else if( typeid(coefficients)==typeid( DenseType) ) return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< CSigs ... >() , F , static_cast< const DenseType& >( coefficients ) , constraints() , maxDepth ); - else return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< CSigs ... >() , F , coefficients , constraints() , maxDepth ); - } - // Add one-dimensions -> one-dimension constraints (with the same signatures) - template< typename T , unsigned int ... FEMDegrees , unsigned int ... FEMSigs > - void addFEMConstraints( typename BaseFEMIntegrator::template System< UIntPack< FEMDegrees ... > >& F , const _SparseOrDenseNodeData< T , UIntPack< FEMSigs ... > >& coefficients , DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , LocalDepth maxDepth ) const - { - typedef SparseNodeData< T , UIntPack< FEMSigs ... > > SparseType; - typedef DenseNodeData< T , UIntPack< FEMSigs ... > > DenseType; - static_assert( sizeof...( FEMDegrees )==Dim && sizeof...( FEMSigs )==Dim , "[ERROR] Dimensions don't match" ); - static_assert( UIntPack< FEMDegrees ... >::template Compare< UIntPack< FEMSignature< FEMSigs >::Degree ... > >::Equal , "[ERROR] FEM signatures and degrees don't match" ); - typename BaseFEMIntegrator::template SystemConstraint< UIntPack< FEMDegrees ... > > _F( F ); - if ( typeid(coefficients)==typeid(SparseType) ) return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const SparseType& >( coefficients ) , constraints() , maxDepth ); - else if( typeid(coefficients)==typeid( DenseType) ) return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const DenseType& >( coefficients ) , constraints() , maxDepth ); - else return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , coefficients , constraints() , maxDepth ); - } + // Add multiple-dimensions -> one-dimension constraints + template< typename T , unsigned int ... FEMDegrees , unsigned int ... FEMSigs , unsigned int ... CDegrees , unsigned int ... CSigs , unsigned int CDim > + void addFEMConstraints( typename BaseFEMIntegrator::template Constraint< UIntPack< FEMDegrees ... > , UIntPack< CDegrees ... > , CDim >& F , const _SparseOrDenseNodeData< Point< T , CDim > , UIntPack< CSigs ... > >& coefficients , DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , LocalDepth maxDepth ) const + { + typedef SparseNodeData< Point< T , CDim > , UIntPack< CSigs ... > > SparseType; + typedef DenseNodeData< Point< T , CDim > , UIntPack< CSigs ... > > DenseType; + static_assert( sizeof...( FEMDegrees )==Dim && sizeof...( FEMSigs )==Dim && sizeof...( CDegrees )==Dim && sizeof...( CSigs )==Dim , "[ERROR] Dimensions don't match" ); + static_assert( UIntPack< FEMDegrees ... >::template Compare< UIntPack< FEMSignature< FEMSigs >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); + static_assert( UIntPack< CDegrees ... >::template Compare< UIntPack< FEMSignature< CSigs >::Degree ... > >::Equal , "[ERROR] Constraint signature and degrees don't match" ); + if ( typeid(coefficients)==typeid(SparseType) ) return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< CSigs ... >() , F , static_cast< const SparseType& >( coefficients ) , constraints() , maxDepth ); + else if( typeid(coefficients)==typeid( DenseType) ) return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< CSigs ... >() , F , static_cast< const DenseType& >( coefficients ) , constraints() , maxDepth ); + else return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< CSigs ... >() , F , coefficients , constraints() , maxDepth ); + } + // Add one-dimensions -> one-dimension constraints (with distinct signatures) + template< typename T , unsigned int ... FEMDegrees , unsigned int ... FEMSigs , unsigned int ... CDegrees , unsigned int ... CSigs > + void addFEMConstraints( typename BaseFEMIntegrator::template Constraint< UIntPack< FEMDegrees ... > , UIntPack< CDegrees ... > , 1 >& F , const _SparseOrDenseNodeData< T , UIntPack< CSigs ... > >& coefficients , DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , LocalDepth maxDepth ) const + { + typedef SparseNodeData< T , UIntPack< CSigs ... > > SparseType; + typedef DenseNodeData< T , UIntPack< CSigs ... > > DenseType; + static_assert( sizeof...( FEMDegrees )==Dim && sizeof...( FEMSigs )==Dim && sizeof...( CDegrees )==Dim && sizeof...( CSigs )==Dim , "[ERROR] Dimensions don't match" ); + static_assert( UIntPack< FEMDegrees ... >::template Compare< UIntPack< FEMSignature< FEMSigs >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); + static_assert( UIntPack< CDegrees ... >::template Compare< UIntPack< FEMSignature< CSigs >::Degree ... > >::Equal , "[ERROR] Constaint signature and degrees don't match" ); + if ( typeid(coefficients)==typeid(SparseType) ) return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< CSigs ... >() , F , static_cast< const SparseType& >( coefficients ) , constraints() , maxDepth ); + else if( typeid(coefficients)==typeid( DenseType) ) return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< CSigs ... >() , F , static_cast< const DenseType& >( coefficients ) , constraints() , maxDepth ); + else return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< CSigs ... >() , F , coefficients , constraints() , maxDepth ); + } + // Add one-dimensions -> one-dimension constraints (with the same signatures) + template< typename T , unsigned int ... FEMDegrees , unsigned int ... FEMSigs > + void addFEMConstraints( typename BaseFEMIntegrator::template System< UIntPack< FEMDegrees ... > >& F , const _SparseOrDenseNodeData< T , UIntPack< FEMSigs ... > >& coefficients , DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , LocalDepth maxDepth ) const + { + typedef SparseNodeData< T , UIntPack< FEMSigs ... > > SparseType; + typedef DenseNodeData< T , UIntPack< FEMSigs ... > > DenseType; + static_assert( sizeof...( FEMDegrees )==Dim && sizeof...( FEMSigs )==Dim , "[ERROR] Dimensions don't match" ); + static_assert( UIntPack< FEMDegrees ... >::template Compare< UIntPack< FEMSignature< FEMSigs >::Degree ... > >::Equal , "[ERROR] FEM signatures and degrees don't match" ); + typename BaseFEMIntegrator::template SystemConstraint< UIntPack< FEMDegrees ... > > _F( F ); + if ( typeid(coefficients)==typeid(SparseType) ) return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const SparseType& >( coefficients ) , constraints() , maxDepth ); + else if( typeid(coefficients)==typeid( DenseType) ) return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const DenseType& >( coefficients ) , constraints() , maxDepth ); + else return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , coefficients , constraints() , maxDepth ); + } -protected: - template< unsigned int MaxDegree > void _supportApproximateProlongation( void ); - template< unsigned int SystemDegree > void _markInexactInterpolationElements( void); - template< unsigned int SystemDegree > void _addAndMarkExactInterpolationElements( void ); - template< unsigned int SystemDegree > void _markNonBaseDirichletElements( void ); - template< unsigned int SystemDegree > void _markBaseDirichletElements( void ); - - template< unsigned int Idx , typename T , unsigned int ... FEMSigs , typename ... InterpolationInfos > - typename std::enable_if< ( Idx==sizeof...(InterpolationInfos) ) >::type _addInterpolationConstraints( DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , LocalDepth maxDepth , std::tuple< InterpolationInfos *... > interpolationInfos ) const {} - template< unsigned int Idx , typename T , unsigned int ... FEMSigs , typename ... InterpolationInfos > - typename std::enable_if< ( Idx ::type _addInterpolationConstraints( DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , LocalDepth maxDepth , std::tuple< InterpolationInfos *... > interpolationInfos ) const - { - _addInterpolationConstraints( constraints , maxDepth , std::get< Idx >( interpolationInfos ) ); - _addInterpolationConstraints< Idx+1 >( constraints , maxDepth , interpolationInfos ); - } - template< typename T , unsigned int ... FEMSigs , unsigned int PointD > - void _addInterpolationConstraints( DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , LocalDepth maxDepth , const InterpolationInfo< T , PointD > *interpolationInfo ) const; -public: - template< typename T , unsigned int ... FEMSigs , typename ... InterpolationInfos > - void addInterpolationConstraints( DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , LocalDepth maxDepth , std::tuple< InterpolationInfos *... > interpolationInfos ) const { return _addInterpolationConstraints< 0 >( constraints , maxDepth , interpolationInfos ); } - - // Real - template< unsigned int ... FEMDegrees1 , unsigned int ... FEMSigs1 , unsigned int ... FEMDegrees2 , unsigned int ... FEMSigs2 > - double dot( typename BaseFEMIntegrator::Constraint< UIntPack< FEMDegrees1 ... > , UIntPack< FEMDegrees2 ... > , 1 >& F , const _SparseOrDenseNodeData< Real , UIntPack< FEMSigs1 ... > >& coefficients1 , const _SparseOrDenseNodeData< Real , UIntPack< FEMSigs2 ... > >& coefficients2 ) const - { - typedef SparseNodeData< Real , UIntPack< FEMSigs1 ... > > SparseType1; - typedef DenseNodeData< Real , UIntPack< FEMSigs1 ... > > DenseType1; - typedef SparseNodeData< Real , UIntPack< FEMSigs2 ... > > SparseType2; - typedef DenseNodeData< Real , UIntPack< FEMSigs2 ... > > DenseType2; - static_assert( sizeof...( FEMDegrees1 )==Dim && sizeof...( FEMSigs1 )==Dim && sizeof...( FEMDegrees2 )==Dim && sizeof...( FEMSigs2 )==Dim , "[ERROR] Dimensions don't match" ); - static_assert( UIntPack< FEMDegrees1 ... >::template Compare< UIntPack< FEMSignature< FEMSigs1 >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); - static_assert( UIntPack< FEMDegrees2 ... >::template Compare< UIntPack< FEMSignature< FEMSigs2 >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); - if ( typeid(coefficients1)==typeid(SparseType1) && typeid(coefficients2)==typeid(SparseType2) ) return _dot< Real >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , static_cast< const SparseType1& >( coefficients1 ) , static_cast< const SparseType2& >( coefficients2 ) , []( Real v , Real w ){ return v*w; } ); - else if( typeid(coefficients1)==typeid(SparseType1) && typeid(coefficients2)==typeid( DenseType2) ) return _dot< Real >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , static_cast< const SparseType1& >( coefficients1 ) , static_cast< const DenseType2& >( coefficients2 ) , []( Real v , Real w ){ return v*w; } ); - else if( typeid(coefficients1)==typeid( DenseType1) && typeid(coefficients2)==typeid( DenseType2) ) return _dot< Real >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , static_cast< const DenseType1& >( coefficients1 ) , static_cast< const DenseType2& >( coefficients2 ) , []( Real v , Real w ){ return v*w; } ); - else if( typeid(coefficients1)==typeid( DenseType1) && typeid(coefficients2)==typeid(SparseType2) ) return _dot< Real >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , static_cast< const DenseType1& >( coefficients1 ) , static_cast< const SparseType2& >( coefficients2 ) , []( Real v , Real w ){ return v*w; } ); - else return _dot< Real >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , coefficients1 , coefficients2 , []( Real v , Real w ){ return v*w; } ); - } - template< unsigned int ... FEMDegrees , unsigned int ... FEMSigs > - double dot( typename BaseFEMIntegrator::System< UIntPack< FEMDegrees ... > >& F , const _SparseOrDenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients1 , const _SparseOrDenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients2 ) const - { - typedef SparseNodeData< Real , UIntPack< FEMSigs ... > > SparseType; - typedef DenseNodeData< Real , UIntPack< FEMSigs ... > > DenseType; - static_assert( sizeof...( FEMDegrees )==Dim && sizeof...( FEMSigs )==Dim , "[ERROR] Dimensions don't match" ); - static_assert( UIntPack< FEMDegrees ... >::template Compare< UIntPack< FEMSignature< FEMSigs >::Degree ... > >::Equal , "[ERROR] FEM signatures and degrees don't match" ); - typename BaseFEMIntegrator::template SystemConstraint< UIntPack< FEMDegrees ... > > _F( F ); - if ( typeid(coefficients1)==typeid(SparseType) && typeid(coefficients2)==typeid(SparseType) ) return _dot< Real >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const SparseType& >( coefficients1 ) , static_cast< const SparseType& >( coefficients2 ) , []( Real v , Real w ){ return v*w; } ); - else if( typeid(coefficients1)==typeid(SparseType) && typeid(coefficients2)==typeid( DenseType) ) return _dot< Real >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const SparseType& >( coefficients1 ) , static_cast< const DenseType& >( coefficients2 ) , []( Real v , Real w ){ return v*w; } ); - else if( typeid(coefficients1)==typeid( DenseType) && typeid(coefficients2)==typeid( DenseType) ) return _dot< Real >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const DenseType& >( coefficients1 ) , static_cast< const DenseType& >( coefficients2 ) , []( Real v , Real w ){ return v*w; } ); - else if( typeid(coefficients1)==typeid( DenseType) && typeid(coefficients2)==typeid(SparseType) ) return _dot< Real >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const DenseType& >( coefficients1 ) , static_cast< const SparseType& >( coefficients2 ) , []( Real v , Real w ){ return v*w; } ); - else return _dot< Real >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , coefficients1 , coefficients2 , []( Real v , Real w ){ return v*w; } ); - } - template< unsigned int ... FEMDegrees , unsigned int ... FEMSigs > - double squareNorm( typename BaseFEMIntegrator::template System< UIntPack< FEMDegrees ... > >& F , const _SparseOrDenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients ) const - { - typedef SparseNodeData< Real , UIntPack< FEMSigs ... > > SparseType; - typedef DenseNodeData< Real , UIntPack< FEMSigs ... > > DenseType; - typename BaseFEMIntegrator::template SystemConstraint< UIntPack< FEMDegrees ... > > _F( F ); - if ( typeid(coefficients)==typeid(SparseType) ) return _dot< Real >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const SparseType& >( coefficients ) , static_cast< const SparseType& >( coefficients ) , []( Real v , Real w ){ return v*w; } ); - else if( typeid(coefficients)==typeid( DenseType) ) return _dot< Real >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const DenseType& >( coefficients ) , static_cast< const DenseType& >( coefficients ) , []( Real v , Real w ){ return v*w; } ); - else return _dot< Real >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , coefficients , coefficients , []( Real v , Real w ){ return v*w; } ); - } + protected: + template< unsigned int MaxDegree > void _supportApproximateProlongation( void ); + template< unsigned int SystemDegree > void _markInexactInterpolationElements( void); + template< unsigned int SystemDegree > void _addAndMarkExactInterpolationElements( void ); + template< unsigned int SystemDegree > void _markNonBaseDirichletElements( void ); + template< unsigned int SystemDegree > void _markBaseDirichletElements( void ); + + template< unsigned int Idx , typename T , unsigned int ... FEMSigs , typename ... InterpolationInfos > + typename std::enable_if< ( Idx==sizeof...(InterpolationInfos) ) >::type _addInterpolationConstraints( DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , LocalDepth maxDepth , std::tuple< InterpolationInfos *... > interpolationInfos ) const {} + template< unsigned int Idx , typename T , unsigned int ... FEMSigs , typename ... InterpolationInfos > + typename std::enable_if< ( Idx ::type _addInterpolationConstraints( DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , LocalDepth maxDepth , std::tuple< InterpolationInfos *... > interpolationInfos ) const + { + _addInterpolationConstraints( constraints , maxDepth , std::get< Idx >( interpolationInfos ) ); + _addInterpolationConstraints< Idx+1 >( constraints , maxDepth , interpolationInfos ); + } + template< typename T , unsigned int ... FEMSigs , unsigned int PointD > + void _addInterpolationConstraints( DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , LocalDepth maxDepth , const InterpolationInfo< T , PointD > *interpolationInfo ) const; + public: + template< typename T , unsigned int ... FEMSigs , typename ... InterpolationInfos > + void addInterpolationConstraints( DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , LocalDepth maxDepth , std::tuple< InterpolationInfos *... > interpolationInfos ) const { return _addInterpolationConstraints< 0 >( constraints , maxDepth , interpolationInfos ); } - template< unsigned int ... FEMSigs1 , unsigned int ... FEMSigs2 , typename ... InterpolationInfos > - double interpolationDot( const DenseNodeData< Real , UIntPack< FEMSigs1 ... > >& coefficients1 , const DenseNodeData< Real , UIntPack< FEMSigs2 ... > >& coefficients2 , std::tuple< InterpolationInfos *... > interpolationInfos ) const - { - static_assert( sizeof...( FEMSigs1 )==Dim && sizeof...( FEMSigs2 )==Dim , "[ERROR] Dimensions don't match" ); - return _interpolationDot< 0 >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , coefficients1 , coefficients2 , []( Real v , Real w ){ return v*w; } , interpolationInfos ); - } - template< unsigned int ... FEMSigs , typename ... InterpolationInfos > - double interpolationSquareNorm( const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , std::tuple< InterpolationInfos *... > interpolationInfos ) const - { - static_assert( sizeof...( FEMSigs )==Dim , "[ERROR] Dimensions don't match" ); - return _interpolationDot< 0 , Real >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , coefficients , coefficients , []( Real v , Real w ){ return v*w; } , interpolationInfos ); - } + // Real + template< unsigned int ... FEMDegrees1 , unsigned int ... FEMSigs1 , unsigned int ... FEMDegrees2 , unsigned int ... FEMSigs2 > + double dot( typename BaseFEMIntegrator::Constraint< UIntPack< FEMDegrees1 ... > , UIntPack< FEMDegrees2 ... > , 1 >& F , const _SparseOrDenseNodeData< Real , UIntPack< FEMSigs1 ... > >& coefficients1 , const _SparseOrDenseNodeData< Real , UIntPack< FEMSigs2 ... > >& coefficients2 ) const + { + typedef SparseNodeData< Real , UIntPack< FEMSigs1 ... > > SparseType1; + typedef DenseNodeData< Real , UIntPack< FEMSigs1 ... > > DenseType1; + typedef SparseNodeData< Real , UIntPack< FEMSigs2 ... > > SparseType2; + typedef DenseNodeData< Real , UIntPack< FEMSigs2 ... > > DenseType2; + static_assert( sizeof...( FEMDegrees1 )==Dim && sizeof...( FEMSigs1 )==Dim && sizeof...( FEMDegrees2 )==Dim && sizeof...( FEMSigs2 )==Dim , "[ERROR] Dimensions don't match" ); + static_assert( UIntPack< FEMDegrees1 ... >::template Compare< UIntPack< FEMSignature< FEMSigs1 >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); + static_assert( UIntPack< FEMDegrees2 ... >::template Compare< UIntPack< FEMSignature< FEMSigs2 >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); + if ( typeid(coefficients1)==typeid(SparseType1) && typeid(coefficients2)==typeid(SparseType2) ) return _dot< Real >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , static_cast< const SparseType1& >( coefficients1 ) , static_cast< const SparseType2& >( coefficients2 ) , []( Real v , Real w ){ return v*w; } ); + else if( typeid(coefficients1)==typeid(SparseType1) && typeid(coefficients2)==typeid( DenseType2) ) return _dot< Real >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , static_cast< const SparseType1& >( coefficients1 ) , static_cast< const DenseType2& >( coefficients2 ) , []( Real v , Real w ){ return v*w; } ); + else if( typeid(coefficients1)==typeid( DenseType1) && typeid(coefficients2)==typeid( DenseType2) ) return _dot< Real >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , static_cast< const DenseType1& >( coefficients1 ) , static_cast< const DenseType2& >( coefficients2 ) , []( Real v , Real w ){ return v*w; } ); + else if( typeid(coefficients1)==typeid( DenseType1) && typeid(coefficients2)==typeid(SparseType2) ) return _dot< Real >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , static_cast< const DenseType1& >( coefficients1 ) , static_cast< const SparseType2& >( coefficients2 ) , []( Real v , Real w ){ return v*w; } ); + else return _dot< Real >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , coefficients1 , coefficients2 , []( Real v , Real w ){ return v*w; } ); + } + template< unsigned int ... FEMDegrees , unsigned int ... FEMSigs > + double dot( typename BaseFEMIntegrator::System< UIntPack< FEMDegrees ... > >& F , const _SparseOrDenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients1 , const _SparseOrDenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients2 ) const + { + typedef SparseNodeData< Real , UIntPack< FEMSigs ... > > SparseType; + typedef DenseNodeData< Real , UIntPack< FEMSigs ... > > DenseType; + static_assert( sizeof...( FEMDegrees )==Dim && sizeof...( FEMSigs )==Dim , "[ERROR] Dimensions don't match" ); + static_assert( UIntPack< FEMDegrees ... >::template Compare< UIntPack< FEMSignature< FEMSigs >::Degree ... > >::Equal , "[ERROR] FEM signatures and degrees don't match" ); + typename BaseFEMIntegrator::template SystemConstraint< UIntPack< FEMDegrees ... > > _F( F ); + if ( typeid(coefficients1)==typeid(SparseType) && typeid(coefficients2)==typeid(SparseType) ) return _dot< Real >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const SparseType& >( coefficients1 ) , static_cast< const SparseType& >( coefficients2 ) , []( Real v , Real w ){ return v*w; } ); + else if( typeid(coefficients1)==typeid(SparseType) && typeid(coefficients2)==typeid( DenseType) ) return _dot< Real >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const SparseType& >( coefficients1 ) , static_cast< const DenseType& >( coefficients2 ) , []( Real v , Real w ){ return v*w; } ); + else if( typeid(coefficients1)==typeid( DenseType) && typeid(coefficients2)==typeid( DenseType) ) return _dot< Real >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const DenseType& >( coefficients1 ) , static_cast< const DenseType& >( coefficients2 ) , []( Real v , Real w ){ return v*w; } ); + else if( typeid(coefficients1)==typeid( DenseType) && typeid(coefficients2)==typeid(SparseType) ) return _dot< Real >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const DenseType& >( coefficients1 ) , static_cast< const SparseType& >( coefficients2 ) , []( Real v , Real w ){ return v*w; } ); + else return _dot< Real >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , coefficients1 , coefficients2 , []( Real v , Real w ){ return v*w; } ); + } + template< unsigned int ... FEMDegrees , unsigned int ... FEMSigs > + double squareNorm( typename BaseFEMIntegrator::template System< UIntPack< FEMDegrees ... > >& F , const _SparseOrDenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients ) const + { + typedef SparseNodeData< Real , UIntPack< FEMSigs ... > > SparseType; + typedef DenseNodeData< Real , UIntPack< FEMSigs ... > > DenseType; + typename BaseFEMIntegrator::template SystemConstraint< UIntPack< FEMDegrees ... > > _F( F ); + if ( typeid(coefficients)==typeid(SparseType) ) return _dot< Real >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const SparseType& >( coefficients ) , static_cast< const SparseType& >( coefficients ) , []( Real v , Real w ){ return v*w; } ); + else if( typeid(coefficients)==typeid( DenseType) ) return _dot< Real >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const DenseType& >( coefficients ) , static_cast< const DenseType& >( coefficients ) , []( Real v , Real w ){ return v*w; } ); + else return _dot< Real >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , coefficients , coefficients , []( Real v , Real w ){ return v*w; } ); + } - // Generic - template< typename T , typename TDotT , unsigned int ... FEMDegrees1 , unsigned int ... FEMSigs1 , unsigned int ... FEMDegrees2 , unsigned int ... FEMSigs2 > - double dot( TDotT Dot , typename BaseFEMIntegrator::Constraint< UIntPack< FEMDegrees1 ... > , UIntPack< FEMDegrees2 ... > , 1 >& F , const _SparseOrDenseNodeData< T , UIntPack< FEMSigs1 ... > >& coefficients1 , const _SparseOrDenseNodeData< T , UIntPack< FEMSigs2 ... > >& coefficients2 ) const - { - typedef SparseNodeData< T , UIntPack< FEMSigs1 ... > > SparseType1; - typedef DenseNodeData< T , UIntPack< FEMSigs1 ... > > DenseType1; - typedef SparseNodeData< T , UIntPack< FEMSigs2 ... > > SparseType2; - typedef DenseNodeData< T , UIntPack< FEMSigs2 ... > > DenseType2; - static_assert( sizeof...( FEMDegrees1 )==Dim && sizeof...( FEMSigs1 )==Dim && sizeof...( FEMDegrees2 )==Dim && sizeof...( FEMSigs2 )==Dim , "[ERROR] Dimensions don't match" ); - static_assert( UIntPack< FEMDegrees1 ... >::template Compare< UIntPack< FEMSignature< FEMSigs1 >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); - static_assert( UIntPack< FEMDegrees2 ... >::template Compare< UIntPack< FEMSignature< FEMSigs2 >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); - if ( typeid(coefficients1)==typeid(SparseType1) && typeid(coefficients2)==typeid(SparseType2) ) return _dot< T >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , static_cast< const SparseType1& >( coefficients1 ) , static_cast< const SparseType2& >( coefficients2 ) , Dot ); - else if( typeid(coefficients1)==typeid(SparseType1) && typeid(coefficients2)==typeid( DenseType2) ) return _dot< T >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , static_cast< const SparseType1& >( coefficients1 ) , static_cast< const DenseType2& >( coefficients2 ) , Dot ); - else if( typeid(coefficients1)==typeid( DenseType1) && typeid(coefficients2)==typeid( DenseType2) ) return _dot< T >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , static_cast< const DenseType1& >( coefficients1 ) , static_cast< const DenseType2& >( coefficients2 ) , Dot ); - else if( typeid(coefficients1)==typeid( DenseType1) && typeid(coefficients2)==typeid(SparseType2) ) return _dot< T >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , static_cast< const DenseType1& >( coefficients1 ) , static_cast< const SparseType2& >( coefficients2 ) , Dot ); - else return _dot< T >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , coefficients1 , coefficients2 , Dot ); - } - template< typename T , typename TDotT , unsigned int ... FEMDegrees , unsigned int ... FEMSigs > - double dot( TDotT Dot , typename BaseFEMIntegrator::System< UIntPack< FEMDegrees ... > >& F , const _SparseOrDenseNodeData< T , UIntPack< FEMSigs ... > >& coefficients1 , const _SparseOrDenseNodeData< T , UIntPack< FEMSigs ... > >& coefficients2 ) const - { - typedef SparseNodeData< T , UIntPack< FEMSigs ... > > SparseType; - typedef DenseNodeData< T , UIntPack< FEMSigs ... > > DenseType; - static_assert( sizeof...( FEMDegrees )==Dim && sizeof...( FEMSigs )==Dim , "[ERROR] Dimensions don't match" ); - static_assert( UIntPack< FEMDegrees ... >::template Compare< UIntPack< FEMSignature< FEMSigs >::Degree ... > >::Equal , "[ERROR] FEM signatures and degrees don't match" ); - typename BaseFEMIntegrator::template SystemConstraint< UIntPack< FEMDegrees ... > > _F( F ); - if ( typeid(coefficients1)==typeid(SparseType) && typeid(coefficients2)==typeid(SparseType) ) return _dot< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const SparseType& >( coefficients1 ) , static_cast< const SparseType& >( coefficients2 ) , Dot ); - else if( typeid(coefficients1)==typeid(SparseType) && typeid(coefficients2)==typeid( DenseType) ) return _dot< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const SparseType& >( coefficients1 ) , static_cast< const DenseType& >( coefficients2 ) , Dot ); - else if( typeid(coefficients1)==typeid( DenseType) && typeid(coefficients2)==typeid( DenseType) ) return _dot< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const DenseType& >( coefficients1 ) , static_cast< const DenseType& >( coefficients2 ) , Dot ); - else if( typeid(coefficients1)==typeid( DenseType) && typeid(coefficients2)==typeid(SparseType) ) return _dot< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const DenseType& >( coefficients1 ) , static_cast< const SparseType& >( coefficients2 ) , Dot ); - else return _dot< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , coefficients1 , coefficients2 , Dot ); - } - template< typename T , typename TDotT , unsigned int ... FEMDegrees , unsigned int ... FEMSigs > - double squareNorm( TDotT Dot , typename BaseFEMIntegrator::template System< UIntPack< FEMDegrees ... > >& F , const _SparseOrDenseNodeData< T , UIntPack< FEMSigs ... > >& coefficients ) const - { - typedef SparseNodeData< T , UIntPack< FEMSigs ... > > SparseType; - typedef DenseNodeData< T , UIntPack< FEMSigs ... > > DenseType; - typename BaseFEMIntegrator::template SystemConstraint< UIntPack< FEMDegrees ... > > _F( F ); - if ( typeid(coefficients)==typeid(SparseType) ) return _dot< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const SparseType& >( coefficients ) , static_cast< const SparseType& >( coefficients ) , Dot ); - else if( typeid(coefficients)==typeid( DenseType) ) return _dot< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const DenseType& >( coefficients ) , static_cast< const DenseType& >( coefficients ) , Dot ); - else return _dot< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , coefficients , coefficients , Dot ); - } + template< unsigned int ... FEMSigs1 , unsigned int ... FEMSigs2 , typename ... InterpolationInfos > + double interpolationDot( const DenseNodeData< Real , UIntPack< FEMSigs1 ... > >& coefficients1 , const DenseNodeData< Real , UIntPack< FEMSigs2 ... > >& coefficients2 , std::tuple< InterpolationInfos *... > interpolationInfos ) const + { + static_assert( sizeof...( FEMSigs1 )==Dim && sizeof...( FEMSigs2 )==Dim , "[ERROR] Dimensions don't match" ); + return _interpolationDot< 0 >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , coefficients1 , coefficients2 , []( Real v , Real w ){ return v*w; } , interpolationInfos ); + } + template< unsigned int ... FEMSigs , typename ... InterpolationInfos > + double interpolationSquareNorm( const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , std::tuple< InterpolationInfos *... > interpolationInfos ) const + { + static_assert( sizeof...( FEMSigs )==Dim , "[ERROR] Dimensions don't match" ); + return _interpolationDot< 0 , Real >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , coefficients , coefficients , []( Real v , Real w ){ return v*w; } , interpolationInfos ); + } - template< typename T , typename TDotT , unsigned int ... FEMSigs1 , unsigned int ... FEMSigs2 , typename ... InterpolationInfos > - double interpolationDot( TDotT Dot , const DenseNodeData< T , UIntPack< FEMSigs1 ... > >& coefficients1 , const DenseNodeData< T , UIntPack< FEMSigs2 ... > >& coefficients2 , std::tuple< InterpolationInfos *... > interpolationInfos ) const - { - static_assert( sizeof...( FEMSigs1 )==Dim && sizeof...( FEMSigs2 )==Dim , "[ERROR] Dimensions don't match" ); - return _interpolationDot< T >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , coefficients1 , coefficients2 , Dot , interpolationInfos ); - } - template< typename T , typename TDotT , unsigned int ... FEMSigs , typename ... InterpolationInfos > - double interpolationSquareNorm( TDotT Dot , const DenseNodeData< T , UIntPack< FEMSigs ... > >& coefficients , std::tuple< InterpolationInfos *... > interpolationInfos ) const - { - static_assert( sizeof...( FEMSigs )==Dim , "[ERROR] Dimensions don't match" ); - return _interpolationDot< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , coefficients , coefficients , Dot , interpolationInfos ); - } + // Generic + template< typename T , typename TDotT , unsigned int ... FEMDegrees1 , unsigned int ... FEMSigs1 , unsigned int ... FEMDegrees2 , unsigned int ... FEMSigs2 > + double dot( TDotT Dot , typename BaseFEMIntegrator::Constraint< UIntPack< FEMDegrees1 ... > , UIntPack< FEMDegrees2 ... > , 1 >& F , const _SparseOrDenseNodeData< T , UIntPack< FEMSigs1 ... > >& coefficients1 , const _SparseOrDenseNodeData< T , UIntPack< FEMSigs2 ... > >& coefficients2 ) const + { + typedef SparseNodeData< T , UIntPack< FEMSigs1 ... > > SparseType1; + typedef DenseNodeData< T , UIntPack< FEMSigs1 ... > > DenseType1; + typedef SparseNodeData< T , UIntPack< FEMSigs2 ... > > SparseType2; + typedef DenseNodeData< T , UIntPack< FEMSigs2 ... > > DenseType2; + static_assert( sizeof...( FEMDegrees1 )==Dim && sizeof...( FEMSigs1 )==Dim && sizeof...( FEMDegrees2 )==Dim && sizeof...( FEMSigs2 )==Dim , "[ERROR] Dimensions don't match" ); + static_assert( UIntPack< FEMDegrees1 ... >::template Compare< UIntPack< FEMSignature< FEMSigs1 >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); + static_assert( UIntPack< FEMDegrees2 ... >::template Compare< UIntPack< FEMSignature< FEMSigs2 >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); + if ( typeid(coefficients1)==typeid(SparseType1) && typeid(coefficients2)==typeid(SparseType2) ) return _dot< T >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , static_cast< const SparseType1& >( coefficients1 ) , static_cast< const SparseType2& >( coefficients2 ) , Dot ); + else if( typeid(coefficients1)==typeid(SparseType1) && typeid(coefficients2)==typeid( DenseType2) ) return _dot< T >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , static_cast< const SparseType1& >( coefficients1 ) , static_cast< const DenseType2& >( coefficients2 ) , Dot ); + else if( typeid(coefficients1)==typeid( DenseType1) && typeid(coefficients2)==typeid( DenseType2) ) return _dot< T >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , static_cast< const DenseType1& >( coefficients1 ) , static_cast< const DenseType2& >( coefficients2 ) , Dot ); + else if( typeid(coefficients1)==typeid( DenseType1) && typeid(coefficients2)==typeid(SparseType2) ) return _dot< T >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , static_cast< const DenseType1& >( coefficients1 ) , static_cast< const SparseType2& >( coefficients2 ) , Dot ); + else return _dot< T >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , coefficients1 , coefficients2 , Dot ); + } + template< typename T , typename TDotT , unsigned int ... FEMDegrees , unsigned int ... FEMSigs > + double dot( TDotT Dot , typename BaseFEMIntegrator::System< UIntPack< FEMDegrees ... > >& F , const _SparseOrDenseNodeData< T , UIntPack< FEMSigs ... > >& coefficients1 , const _SparseOrDenseNodeData< T , UIntPack< FEMSigs ... > >& coefficients2 ) const + { + typedef SparseNodeData< T , UIntPack< FEMSigs ... > > SparseType; + typedef DenseNodeData< T , UIntPack< FEMSigs ... > > DenseType; + static_assert( sizeof...( FEMDegrees )==Dim && sizeof...( FEMSigs )==Dim , "[ERROR] Dimensions don't match" ); + static_assert( UIntPack< FEMDegrees ... >::template Compare< UIntPack< FEMSignature< FEMSigs >::Degree ... > >::Equal , "[ERROR] FEM signatures and degrees don't match" ); + typename BaseFEMIntegrator::template SystemConstraint< UIntPack< FEMDegrees ... > > _F( F ); + if ( typeid(coefficients1)==typeid(SparseType) && typeid(coefficients2)==typeid(SparseType) ) return _dot< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const SparseType& >( coefficients1 ) , static_cast< const SparseType& >( coefficients2 ) , Dot ); + else if( typeid(coefficients1)==typeid(SparseType) && typeid(coefficients2)==typeid( DenseType) ) return _dot< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const SparseType& >( coefficients1 ) , static_cast< const DenseType& >( coefficients2 ) , Dot ); + else if( typeid(coefficients1)==typeid( DenseType) && typeid(coefficients2)==typeid( DenseType) ) return _dot< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const DenseType& >( coefficients1 ) , static_cast< const DenseType& >( coefficients2 ) , Dot ); + else if( typeid(coefficients1)==typeid( DenseType) && typeid(coefficients2)==typeid(SparseType) ) return _dot< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const DenseType& >( coefficients1 ) , static_cast< const SparseType& >( coefficients2 ) , Dot ); + else return _dot< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , coefficients1 , coefficients2 , Dot ); + } + template< typename T , typename TDotT , unsigned int ... FEMDegrees , unsigned int ... FEMSigs > + double squareNorm( TDotT Dot , typename BaseFEMIntegrator::template System< UIntPack< FEMDegrees ... > >& F , const _SparseOrDenseNodeData< T , UIntPack< FEMSigs ... > >& coefficients ) const + { + typedef SparseNodeData< T , UIntPack< FEMSigs ... > > SparseType; + typedef DenseNodeData< T , UIntPack< FEMSigs ... > > DenseType; + typename BaseFEMIntegrator::template SystemConstraint< UIntPack< FEMDegrees ... > > _F( F ); + if ( typeid(coefficients)==typeid(SparseType) ) return _dot< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const SparseType& >( coefficients ) , static_cast< const SparseType& >( coefficients ) , Dot ); + else if( typeid(coefficients)==typeid( DenseType) ) return _dot< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const DenseType& >( coefficients ) , static_cast< const DenseType& >( coefficients ) , Dot ); + else return _dot< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , coefficients , coefficients , Dot ); + } - template< unsigned int ... FEMSigs , typename ... InterpolationInfos > - SparseMatrix< Real , matrix_index_type > systemMatrix( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , LocalDepth depth , std::tuple< InterpolationInfos *... > interpolationInfos ) const; - template< unsigned int ... FEMSigs , typename ... InterpolationInfos > - SparseMatrix< Real , matrix_index_type > prolongedSystemMatrix( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , LocalDepth highDepth , std::tuple< InterpolationInfos *... > interpolationInfos ) const; - template< unsigned int ... FEMSigs > - SparseMatrix< Real , matrix_index_type > downSampleMatrix( UIntPack< FEMSigs ... > , LocalDepth highDepth ) const; - template< unsigned int ... FEMSigs > - SparseMatrix< Real , matrix_index_type > upSampleMatrix( UIntPack< FEMSigs ... > , LocalDepth highDepth ) const; - template< unsigned int ... FEMSigs , typename ... InterpolationInfos > - SparseMatrix< Real , matrix_index_type > fullSystemMatrix( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , LocalDepth depth , std::tuple< InterpolationInfos *... > interpolationInfos ) const; - - template< typename T , unsigned int ... FEMSigs > - void pushToBaseDepth( DenseNodeData< T , UIntPack< FEMSigs ... > >& coefficients ) const; - - struct SolverInfo - { - protected: - struct _IterFunction - { - _IterFunction( int i ) : _i0(i) , _type(0) {} - _IterFunction( std::function< int ( int ) > iFunction ) : _i1(iFunction) , _type(1) {} - _IterFunction( std::function< int ( bool , int ) > iFunction ) : _i2(iFunction) , _type(2) {} - _IterFunction( std::function< int ( int , bool , int ) > iFunction ) : _i3(iFunction) , _type(3) {} - _IterFunction& operator = ( int i ){ *this = _IterFunction(i) ; return *this; } - _IterFunction& operator = ( std::function< int ( int ) > iFunction ){ *this = _IterFunction(iFunction) ; return *this; } - _IterFunction& operator = ( std::function< int ( bool , int ) > iFunction ){ *this = _IterFunction(iFunction) ; return *this; } - _IterFunction& operator = ( std::function< int ( int , bool , int ) > iFunction ){ *this = _IterFunction(iFunction) ; return *this; } - - int operator()( int vCycle , bool restriction , int depth ) const + template< typename T , typename TDotT , unsigned int ... FEMSigs1 , unsigned int ... FEMSigs2 , typename ... InterpolationInfos > + double interpolationDot( TDotT Dot , const DenseNodeData< T , UIntPack< FEMSigs1 ... > >& coefficients1 , const DenseNodeData< T , UIntPack< FEMSigs2 ... > >& coefficients2 , std::tuple< InterpolationInfos *... > interpolationInfos ) const + { + static_assert( sizeof...( FEMSigs1 )==Dim && sizeof...( FEMSigs2 )==Dim , "[ERROR] Dimensions don't match" ); + return _interpolationDot< T >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , coefficients1 , coefficients2 , Dot , interpolationInfos ); + } + template< typename T , typename TDotT , unsigned int ... FEMSigs , typename ... InterpolationInfos > + double interpolationSquareNorm( TDotT Dot , const DenseNodeData< T , UIntPack< FEMSigs ... > >& coefficients , std::tuple< InterpolationInfos *... > interpolationInfos ) const + { + static_assert( sizeof...( FEMSigs )==Dim , "[ERROR] Dimensions don't match" ); + return _interpolationDot< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , coefficients , coefficients , Dot , interpolationInfos ); + } + + template< unsigned int ... FEMSigs , typename ... InterpolationInfos > + SparseMatrix< Real , matrix_index_type > systemMatrix( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , LocalDepth depth , std::tuple< InterpolationInfos *... > interpolationInfos ) const; + template< unsigned int ... FEMSigs , typename ... InterpolationInfos > + SparseMatrix< Real , matrix_index_type > prolongedSystemMatrix( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , LocalDepth highDepth , std::tuple< InterpolationInfos *... > interpolationInfos ) const; + template< unsigned int ... FEMSigs > + SparseMatrix< Real , matrix_index_type > downSampleMatrix( UIntPack< FEMSigs ... > , LocalDepth highDepth ) const; + template< unsigned int ... FEMSigs > + SparseMatrix< Real , matrix_index_type > upSampleMatrix( UIntPack< FEMSigs ... > , LocalDepth highDepth ) const; + template< unsigned int ... FEMSigs , typename ... InterpolationInfos > + SparseMatrix< Real , matrix_index_type > fullSystemMatrix( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , LocalDepth depth , std::tuple< InterpolationInfos *... > interpolationInfos ) const; + + template< typename T , unsigned int ... FEMSigs > + void pushToBaseDepth( DenseNodeData< T , UIntPack< FEMSigs ... > >& coefficients ) const; + + struct SolverInfo + { + protected: + struct _IterFunction { - switch( _type ) + _IterFunction( int i ) : _i0(i) , _type(0) {} + _IterFunction( std::function< int ( int ) > iFunction ) : _i1(iFunction) , _type(1) {} + _IterFunction( std::function< int ( bool , int ) > iFunction ) : _i2(iFunction) , _type(2) {} + _IterFunction( std::function< int ( int , bool , int ) > iFunction ) : _i3(iFunction) , _type(3) {} + _IterFunction& operator = ( int i ){ *this = _IterFunction(i) ; return *this; } + _IterFunction& operator = ( std::function< int ( int ) > iFunction ){ *this = _IterFunction(iFunction) ; return *this; } + _IterFunction& operator = ( std::function< int ( bool , int ) > iFunction ){ *this = _IterFunction(iFunction) ; return *this; } + _IterFunction& operator = ( std::function< int ( int , bool , int ) > iFunction ){ *this = _IterFunction(iFunction) ; return *this; } + + int operator()( int vCycle , bool restriction , int depth ) const { - case 0: return _i0; - case 1: return _i1( depth ); - case 2: return _i2( restriction , depth ); - case 3: return _i3( vCycle , restriction , depth ); - default: return 0; + switch( _type ) + { + case 0: return _i0; + case 1: return _i1( depth ); + case 2: return _i2( restriction , depth ); + case 3: return _i3( vCycle , restriction , depth ); + default: return 0; + } } - } - protected: - int _i0; - std::function< int ( int ) > _i1; - std::function< int ( bool , int ) > _i2; - std::function< int ( int i3 , bool , int ) > _i3; - int _type; + protected: + int _i0; + std::function< int ( int ) > _i1; + std::function< int ( bool , int ) > _i2; + std::function< int ( int i3 , bool , int ) > _i3; + int _type; + }; + public: + // How to solve + bool wCycle; + LocalDepth cgDepth; + bool cascadic; + unsigned int sliceBlockSize; + bool useSupportWeights , useProlongationSupportWeights; + std::function< Real ( Real , Real ) > sorRestrictionFunction; + std::function< Real ( Real , Real ) > sorProlongationFunction; + _IterFunction iters; + int vCycles; + double cgAccuracy; + bool clearSolution; + int baseVCycles; + // What to output + bool verbose , showResidual; + int showGlobalResidual; + + SolverInfo( void ) : cgDepth(0) , wCycle(false) , cascadic(true) , iters(1) , vCycles(1) , cgAccuracy(0.) , verbose(false) , showResidual(false) , showGlobalResidual(SHOW_GLOBAL_RESIDUAL_NONE) , sliceBlockSize(1) , sorRestrictionFunction( []( Real , Real ){ return (Real)1; } ) , sorProlongationFunction( []( Real , Real ){ return (Real)1; } ) , useSupportWeights( false ) , useProlongationSupportWeights( false ) , baseVCycles(1) , clearSolution(true) { } }; - public: - // How to solve - bool wCycle; - LocalDepth cgDepth; - bool cascadic; - unsigned int sliceBlockSize; - bool useSupportWeights , useProlongationSupportWeights; - std::function< Real ( Real , Real ) > sorRestrictionFunction; - std::function< Real ( Real , Real ) > sorProlongationFunction; - _IterFunction iters; - int vCycles; - double cgAccuracy; - bool clearSolution; - int baseVCycles; - // What to output - bool verbose , showResidual; - int showGlobalResidual; - - SolverInfo( void ) : cgDepth(0) , wCycle(false) , cascadic(true) , iters(1) , vCycles(1) , cgAccuracy(0.) , verbose(false) , showResidual(false) , showGlobalResidual(SHOW_GLOBAL_RESIDUAL_NONE) , sliceBlockSize(1) , sorRestrictionFunction( []( Real , Real ){ return (Real)1; } ) , sorProlongationFunction( []( Real , Real ){ return (Real)1; } ) , useSupportWeights( false ) , useProlongationSupportWeights( false ) , baseVCycles(1) , clearSolution(true) { } - }; - // Solve the linear system - // There are several depths playing into the solver: - // 1. maxDepth: The maximum depth of the tree - // 2. solveDepth: The depth up to which we can solve (solveDepth<=maxDepth) - // 3. fullDepth: The depth up to which the octree is completely refined (fullDepth<=maxDepth) - // 4. baseDepth: The depth up to which the system is defined through the regular prolongation operators (baseDepth<=fullDepth) - template< unsigned int ... FEMSigs , typename T , typename TDotT , typename ... InterpolationInfos > - void solveSystem( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , DenseNodeData< T , UIntPack< FEMSigs ... > >& solution , TDotT Dot , LocalDepth minSolveDepth , LocalDepth maxSolveDepth , const SolverInfo& solverInfo , std::tuple< InterpolationInfos *... > interpolationInfos=std::make_tuple() ) const; - template< unsigned int ... FEMSigs , typename T , typename TDotT , typename ... InterpolationInfos > - DenseNodeData< T , UIntPack< FEMSigs ... > > solveSystem( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , TDotT Dot , LocalDepth minSolveDepth , LocalDepth maxSolveDepth , const SolverInfo& solverInfo , std::tuple< InterpolationInfos *... > interpolationInfos=std::make_tuple() ) const; - template< unsigned int ... FEMSigs , typename ... InterpolationInfos > - void solveSystem( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& constraints , DenseNodeData< Real , UIntPack< FEMSigs ... > >& solution , LocalDepth minSolveDepth , LocalDepth maxSolveDepth , const SolverInfo& solverInfo , std::tuple< InterpolationInfos *... > interpolationInfos=std::make_tuple() ) const - { - return solveSystem< FEMSigs ... , Real >( UIntPack< FEMSigs ... >() , F , constraints , solution , []( Real v , Real w ){ return v*w; } , minSolveDepth , maxSolveDepth , solverInfo , interpolationInfos ); - } - template< unsigned int ... FEMSigs , typename ... InterpolationInfos > - DenseNodeData< Real , UIntPack< FEMSigs ... > > solveSystem( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& constraints , LocalDepth minSolveDepth , LocalDepth maxSolveDepth , const SolverInfo& solverInfo , std::tuple< InterpolationInfos *... > interpolationInfos=std::make_tuple() ) const - { - return solveSystem( UIntPack< FEMSigs ... >() , F , constraints , []( Real v , Real w ){ return v*w; } , minSolveDepth , maxSolveDepth , solverInfo , interpolationInfos ); - } - - FEMTreeNode& spaceRoot( void ){ return *_spaceRoot; } - const FEMTreeNode &spaceRoot( void ) const { return *_spaceRoot; } - const FEMTreeNode& tree( void ) const { return _tree; } - _NodeInitializer &initializer( void ){ return _nodeInitializer; } - size_t leaves( void ) const { return _tree.leaves(); } - size_t allNodes ( void ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode * ){ count++; } ) ; return count; } - size_t activeNodes ( void ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( IsActiveNode< Dim >( n ) ) count++; } ) ; return count; } - size_t ghostNodes ( void ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( !IsActiveNode< Dim >( n ) ) count++; } ) ; return count; } - size_t dirichletNodes ( void ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( n->nodeData.getDirichletNodeFlag() ) count++; } ) ; return count; } - size_t dirichletElements ( void ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( n->nodeData.getDirichletElementFlag() ) count++; } ) ; return count; } - inline size_t validSpaceNodes( void ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( isValidSpaceNode( n ) ) count++; } ) ; return count; } - inline size_t validSpaceNodes( LocalDepth d ) const { size_t count = 0 ; _tree.process( [&]( const FEMTreeNode *n ){ if( _localDepth(n)==d && isValidSpaceNode( n ) ) count++; } ) ; return count; } - template< unsigned int ... FEMSigs > size_t validFEMNodes ( UIntPack< FEMSigs ... > ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( isValidFEMNode( UIntPack< FEMSigs ... >() , n ) ) count++; } ) ; return count; } - template< unsigned int ... FEMSigs > size_t validFEMNodes ( UIntPack< FEMSigs ... > , LocalDepth d ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( _localDepth(n)==d && isValidFEMNode( UIntPack< FEMSigs ... >() , n ) ) count++; } ) ; return count; } - template< unsigned int ... FEMSigs > size_t validUnlockedFEMNodes( UIntPack< FEMSigs ... > ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( isValidFEMNode( UIntPack< FEMSigs ... >() , n ) && !n->nodeData.getDirichletSupportedFlag() ) count++; } ) ; return count; } - template< unsigned int ... FEMSigs > size_t validUnlockedFEMNodes( UIntPack< FEMSigs ... > , LocalDepth d ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( _localDepth(n)==d && isValidFEMNode( UIntPack< FEMSigs ... >() , n ) && !n->nodeData.getDirichletElementFlag() ) count++; } ) ; return count; } - LocalDepth depth( void ) const { return _spaceRoot->maxDepth(); } - LocalDepth maxDepth( void ) const { return _maxDepth; } - template< typename ... DenseOrSparseNodeData > - node_index_type resetNodeIndices( char flagsToClear , std::tuple< DenseOrSparseNodeData *... > data ) - { - char mask = ~flagsToClear; - if( sizeof...( DenseOrSparseNodeData ) ) + // Solve the linear system + // There are several depths playing into the solver: + // 1. maxDepth: The maximum depth of the tree + // 2. solveDepth: The depth up to which we can solve (solveDepth<=maxDepth) + // 3. fullDepth: The depth up to which the octree is completely refined (fullDepth<=maxDepth) + // 4. baseDepth: The depth up to which the system is defined through the regular prolongation operators (baseDepth<=fullDepth) + template< unsigned int ... FEMSigs , typename T , typename TDotT , typename ... InterpolationInfos > + void solveSystem( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , DenseNodeData< T , UIntPack< FEMSigs ... > >& solution , TDotT Dot , LocalDepth minSolveDepth , LocalDepth maxSolveDepth , const SolverInfo& solverInfo , std::tuple< InterpolationInfos *... > interpolationInfos=std::make_tuple() ) const; + template< unsigned int ... FEMSigs , typename T , typename TDotT , typename ... InterpolationInfos > + DenseNodeData< T , UIntPack< FEMSigs ... > > solveSystem( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , TDotT Dot , LocalDepth minSolveDepth , LocalDepth maxSolveDepth , const SolverInfo& solverInfo , std::tuple< InterpolationInfos *... > interpolationInfos=std::make_tuple() ) const; + template< unsigned int ... FEMSigs , typename ... InterpolationInfos > + void solveSystem( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& constraints , DenseNodeData< Real , UIntPack< FEMSigs ... > >& solution , LocalDepth minSolveDepth , LocalDepth maxSolveDepth , const SolverInfo& solverInfo , std::tuple< InterpolationInfos *... > interpolationInfos=std::make_tuple() ) const { - std::vector< node_index_type > map( _nodeCount ); - _nodeCount = 0; - auto nodeFunctor = [&]( FEMTreeNode *node ) - { - node_index_type idx = node->nodeData.nodeIndex; - _nodeInitializer( *node ); - if( node->nodeData.nodeIndex!=-1 ) map[ node->nodeData.nodeIndex ] = idx; - node->nodeData.flags &= mask; - }; - _tree.processNodes( nodeFunctor ); - - _reorderDenseOrSparseNodeData< 0 >( GetPointer( map ) , (size_t)_nodeCount , data ); + return solveSystem< FEMSigs ... , Real >( UIntPack< FEMSigs ... >() , F , constraints , solution , []( Real v , Real w ){ return v*w; } , minSolveDepth , maxSolveDepth , solverInfo , interpolationInfos ); } - else + template< unsigned int ... FEMSigs , typename ... InterpolationInfos > + DenseNodeData< Real , UIntPack< FEMSigs ... > > solveSystem( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& constraints , LocalDepth minSolveDepth , LocalDepth maxSolveDepth , const SolverInfo& solverInfo , std::tuple< InterpolationInfos *... > interpolationInfos=std::make_tuple() ) const { - _nodeCount = 0; - auto nodeFunctor = [&]( FEMTreeNode *node ) - { - _nodeInitializer( *node ); - node->nodeData.flags &= mask; - }; - _tree.processNodes( nodeFunctor ); + return solveSystem( UIntPack< FEMSigs ... >() , F , constraints , []( Real v , Real w ){ return v*w; } , minSolveDepth , maxSolveDepth , solverInfo , interpolationInfos ); } - return _nodeCount; - } - node_index_type resetNodeIndices( char flagsToClear ){ return resetNodeIndices( flagsToClear , std::make_tuple() ); } - - std::vector< node_index_type > merge( FEMTree* tree ); -protected: - template< class Real1 , unsigned int _Dim > static bool _IsZero( Point< Real1 , _Dim > p ); - template< class Real1 > static bool _IsZero( Real1 p ); - template< class SReal , class Data , unsigned int _Dim > static Data _StencilDot( Point< SReal , _Dim > p1 , Point< Data , _Dim > p2 ); - template< class SReal , class Data > static Data _StencilDot( Point< SReal , 1 > p1 , Point< Data , 1 > p2 ); - template< class SReal , class Data > static Data _StencilDot( SReal p1 , Point< Data , 1 > p2 ); - template< class SReal , class Data > static Data _StencilDot( Point< SReal , 1 > p1 , Data p2 ); - template< class SReal , class Data > static Data _StencilDot( SReal p1 , Data p2 ); - - // We need the signatures to test if nodes are valid - template< typename T , unsigned int ... FEMSigs , unsigned int ... CSigs , unsigned int ... FEMDegrees , unsigned int ... CDegrees , unsigned int CDim , class Coefficients > - void _addFEMConstraints( UIntPack< FEMSigs ... > , UIntPack< CSigs ... > , typename BaseFEMIntegrator::Constraint< UIntPack< FEMDegrees ... > , UIntPack< CDegrees ... > , CDim >& F , const Coefficients& coefficients , Pointer( T ) constraints , LocalDepth maxDepth ) const; - template< typename T , typename TDotT , unsigned int ... FEMSigs1 , unsigned int ... FEMSigs2 , unsigned int ... Degrees1 , unsigned int ... Degrees2 , class Coefficients1 , class Coefficients2 > - double _dot( UIntPack< FEMSigs1 ... > , UIntPack< FEMSigs2 ... > , typename BaseFEMIntegrator::Constraint< UIntPack< Degrees1 ... > , UIntPack< Degrees2 ... > , 1 >& F , const Coefficients1& coefficients1 , const Coefficients2& coefficients2 , TDotT Dot ) const; - template< typename T , typename TDotT , unsigned int ... FEMSigs1 , unsigned int ... FEMSigs2 , class Coefficients1 , class Coefficients2 , unsigned int PointD > - double _interpolationDot( UIntPack< FEMSigs1 ... > , UIntPack< FEMSigs2 ... > , const Coefficients1& coefficients1 , const Coefficients2& coefficients2 , TDotT Dot , const InterpolationInfo< T , PointD >* iInfo ) const; - template< unsigned int Idx , typename T , typename TDotT , unsigned int ... FEMSigs1 , unsigned int ... FEMSigs2 , class Coefficients1 , class Coefficients2 , typename ... InterpolationInfos > - typename std::enable_if< ( Idx==sizeof...(InterpolationInfos) ) , double >::type _interpolationDot( UIntPack< FEMSigs1 ... > , UIntPack< FEMSigs2 ... > , const Coefficients1& coefficients1 , const Coefficients2& coefficients2 , TDotT Dot , std::tuple< InterpolationInfos *... > interpolationInfos ) const { return 0.; } - template< unsigned int Idx , typename T , typename TDotT , unsigned int ... FEMSigs1 , unsigned int ... FEMSigs2 , class Coefficients1 , class Coefficients2 , typename ... InterpolationInfos > - typename std::enable_if< ( Idx ::type _interpolationDot( UIntPack< FEMSigs1 ... > , UIntPack< FEMSigs2 ... > , const Coefficients1& coefficients1 , const Coefficients2& coefficients2 , TDotT Dot , std::tuple< InterpolationInfos *... > interpolationInfos ) const - { - return _interpolationDot< T >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , coefficients1 , coefficients2 , Dot , std::get< Idx >( interpolationInfos ) ) + _interpolationDot< Idx+1 , T >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , coefficients1 , coefficients2 , Dot , interpolationInfos ); - } - template< typename T , typename TDotT , unsigned int ... FEMSigs1 , unsigned int ... FEMSigs2 , class Coefficients1 , class Coefficients2 > double _interpolationDot( UIntPack< FEMSigs1 ... > , UIntPack< FEMSigs2 ... > , const Coefficients1& coefficients1 , const Coefficients2& coefficients2 , TDotT Dot ) const{ return 0; } -}; - -template< unsigned int Dim , class Real > -struct FEMTreeInitializer -{ - typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; - typedef NodeAndPointSample< Dim , Real > PointSample; + FEMTreeNode& spaceRoot( void ){ return *_spaceRoot; } + const FEMTreeNode &spaceRoot( void ) const { return *_spaceRoot; } + const FEMTreeNode& tree( void ) const { return _tree; } + _NodeInitializer &initializer( void ){ return _nodeInitializer; } + size_t leaves( void ) const { return _tree.leaves(); } + size_t allNodes ( void ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode * ){ count++; } ) ; return count; } + size_t activeNodes ( void ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( IsActiveNode< Dim >( n ) ) count++; } ) ; return count; } + size_t ghostNodes ( void ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( !IsActiveNode< Dim >( n ) ) count++; } ) ; return count; } + size_t dirichletNodes ( void ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( n->nodeData.getDirichletNodeFlag() ) count++; } ) ; return count; } + size_t dirichletElements ( void ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( n->nodeData.getDirichletElementFlag() ) count++; } ) ; return count; } + inline size_t validSpaceNodes( void ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( isValidSpaceNode( n ) ) count++; } ) ; return count; } + inline size_t validSpaceNodes( LocalDepth d ) const { size_t count = 0 ; _tree.process( [&]( const FEMTreeNode *n ){ if( _localDepth(n)==d && isValidSpaceNode( n ) ) count++; } ) ; return count; } + template< unsigned int ... FEMSigs > size_t validFEMNodes ( UIntPack< FEMSigs ... > ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( isValidFEMNode( UIntPack< FEMSigs ... >() , n ) ) count++; } ) ; return count; } + template< unsigned int ... FEMSigs > size_t validFEMNodes ( UIntPack< FEMSigs ... > , LocalDepth d ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( _localDepth(n)==d && isValidFEMNode( UIntPack< FEMSigs ... >() , n ) ) count++; } ) ; return count; } + template< unsigned int ... FEMSigs > size_t validUnlockedFEMNodes( UIntPack< FEMSigs ... > ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( isValidFEMNode( UIntPack< FEMSigs ... >() , n ) && !n->nodeData.getDirichletSupportedFlag() ) count++; } ) ; return count; } + template< unsigned int ... FEMSigs > size_t validUnlockedFEMNodes( UIntPack< FEMSigs ... > , LocalDepth d ) const { size_t count = 0 ; _tree.processNodes( [&]( const FEMTreeNode *n ){ if( _localDepth(n)==d && isValidFEMNode( UIntPack< FEMSigs ... >() , n ) && !n->nodeData.getDirichletElementFlag() ) count++; } ) ; return count; } + LocalDepth depth( void ) const { return _spaceRoot->maxDepth(); } + LocalDepth maxDepth( void ) const { return _maxDepth; } + template< typename ... DenseOrSparseNodeData > + node_index_type resetNodeIndices( char flagsToClear , std::tuple< DenseOrSparseNodeData *... > data ) + { + char mask = ~flagsToClear; + if( sizeof...( DenseOrSparseNodeData ) ) + { + std::vector< node_index_type > map( _nodeCount ); + _nodeCount = 0; + auto nodeFunctor = [&]( FEMTreeNode *node ) + { + node_index_type idx = node->nodeData.nodeIndex; + _nodeInitializer( *node ); + if( node->nodeData.nodeIndex!=-1 ) map[ node->nodeData.nodeIndex ] = idx; + node->nodeData.flags &= mask; + }; + _tree.processNodes( nodeFunctor ); + + _reorderDenseOrSparseNodeData< 0 >( GetPointer( map ) , (size_t)_nodeCount , data ); + } + else + { + _nodeCount = 0; + auto nodeFunctor = [&]( FEMTreeNode *node ) + { + _nodeInitializer( *node ); + node->nodeData.flags &= mask; + }; + _tree.processNodes( nodeFunctor ); + } + return _nodeCount; + } + node_index_type resetNodeIndices( char flagsToClear ){ return resetNodeIndices( flagsToClear , std::make_tuple() ); } - template< class Data > - struct DerivativeStream - { - virtual void resolution( unsigned int res[] ) const = 0; - virtual bool nextDerivative( unsigned int idx[] , unsigned int& dir , Data& dValue ) = 0; + std::vector< node_index_type > merge( FEMTree* tree ); + protected: + template< class Real1 , unsigned int _Dim > static bool _IsZero( Point< Real1 , _Dim > p ); + template< class Real1 > static bool _IsZero( Real1 p ); + template< class SReal , class Data , unsigned int _Dim > static Data _StencilDot( Point< SReal , _Dim > p1 , Point< Data , _Dim > p2 ); + template< class SReal , class Data > static Data _StencilDot( Point< SReal , 1 > p1 , Point< Data , 1 > p2 ); + template< class SReal , class Data > static Data _StencilDot( SReal p1 , Point< Data , 1 > p2 ); + template< class SReal , class Data > static Data _StencilDot( Point< SReal , 1 > p1 , Data p2 ); + template< class SReal , class Data > static Data _StencilDot( SReal p1 , Data p2 ); + + // We need the signatures to test if nodes are valid + template< typename T , unsigned int ... FEMSigs , unsigned int ... CSigs , unsigned int ... FEMDegrees , unsigned int ... CDegrees , unsigned int CDim , class Coefficients > + void _addFEMConstraints( UIntPack< FEMSigs ... > , UIntPack< CSigs ... > , typename BaseFEMIntegrator::Constraint< UIntPack< FEMDegrees ... > , UIntPack< CDegrees ... > , CDim >& F , const Coefficients& coefficients , Pointer( T ) constraints , LocalDepth maxDepth ) const; + template< typename T , typename TDotT , unsigned int ... FEMSigs1 , unsigned int ... FEMSigs2 , unsigned int ... Degrees1 , unsigned int ... Degrees2 , class Coefficients1 , class Coefficients2 > + double _dot( UIntPack< FEMSigs1 ... > , UIntPack< FEMSigs2 ... > , typename BaseFEMIntegrator::Constraint< UIntPack< Degrees1 ... > , UIntPack< Degrees2 ... > , 1 >& F , const Coefficients1& coefficients1 , const Coefficients2& coefficients2 , TDotT Dot ) const; + template< typename T , typename TDotT , unsigned int ... FEMSigs1 , unsigned int ... FEMSigs2 , class Coefficients1 , class Coefficients2 , unsigned int PointD > + double _interpolationDot( UIntPack< FEMSigs1 ... > , UIntPack< FEMSigs2 ... > , const Coefficients1& coefficients1 , const Coefficients2& coefficients2 , TDotT Dot , const InterpolationInfo< T , PointD >* iInfo ) const; + template< unsigned int Idx , typename T , typename TDotT , unsigned int ... FEMSigs1 , unsigned int ... FEMSigs2 , class Coefficients1 , class Coefficients2 , typename ... InterpolationInfos > + typename std::enable_if< ( Idx==sizeof...(InterpolationInfos) ) , double >::type _interpolationDot( UIntPack< FEMSigs1 ... > , UIntPack< FEMSigs2 ... > , const Coefficients1& coefficients1 , const Coefficients2& coefficients2 , TDotT Dot , std::tuple< InterpolationInfos *... > interpolationInfos ) const { return 0.; } + template< unsigned int Idx , typename T , typename TDotT , unsigned int ... FEMSigs1 , unsigned int ... FEMSigs2 , class Coefficients1 , class Coefficients2 , typename ... InterpolationInfos > + typename std::enable_if< ( Idx ::type _interpolationDot( UIntPack< FEMSigs1 ... > , UIntPack< FEMSigs2 ... > , const Coefficients1& coefficients1 , const Coefficients2& coefficients2 , TDotT Dot , std::tuple< InterpolationInfos *... > interpolationInfos ) const + { + return _interpolationDot< T >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , coefficients1 , coefficients2 , Dot , std::get< Idx >( interpolationInfos ) ) + _interpolationDot< Idx+1 , T >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , coefficients1 , coefficients2 , Dot , interpolationInfos ); + } + template< typename T , typename TDotT , unsigned int ... FEMSigs1 , unsigned int ... FEMSigs2 , class Coefficients1 , class Coefficients2 > double _interpolationDot( UIntPack< FEMSigs1 ... > , UIntPack< FEMSigs2 ... > , const Coefficients1& coefficients1 , const Coefficients2& coefficients2 , TDotT Dot ) const{ return 0; } }; - // Initialize the tree using a refinement avatar - static size_t Initialize( FEMTreeNode& root , int maxDepth , std::function< bool ( int , int[] ) > Refine , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); - // Initialize the tree using a point stream - template< typename Data > - struct InputPointStream + template< unsigned int Dim , class Real > + struct FEMTreeInitializer { - typedef Data DataType; - typedef VectorTypeUnion< Real , Point< Real , Dim > , Data > PointAndDataType; - typedef InputDataStream< PointAndDataType > StreamType; - static Point< Real , Dim > &GetPoint( PointAndDataType &pd ){ return pd.template get<0>(); } - static const Point< Real , Dim > &GetPoint( const PointAndDataType &pd ){ return pd.template get<0>(); } - static DataType &GetData( PointAndDataType &pd ){ return pd.template get<1>(); } - static const DataType &GetData( const PointAndDataType &pd ){ return pd.template get<1>(); } - - static void BoundingBox( StreamType &stream , Data d , Point< Real , Dim >& min , Point< Real , Dim >& max ) - { - PointAndDataType p; - p.template get<1>() = d; - for( unsigned int d=0 ; d::infinity() , max[d] = -std::numeric_limits< Real >::infinity(); - while( stream.read( p ) ) for( unsigned int d=0 ; d( min[d] , p.template get<0>()[d] ) , max[d] = std::max< Real >( max[d] , p.template get<0>()[d] ); - stream.reset(); - } - }; + typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; + typedef NodeAndPointSample< Dim , Real > PointSample; - template< typename Data > - struct OutputPointStream - { - typedef Data DataType; - typedef VectorTypeUnion< Real , Point< Real , Dim > , Data > PointAndDataType; - typedef OutputDataStream< PointAndDataType > StreamType; - static Point< Real , Dim > &GetPoint( PointAndDataType &pd ){ return pd.template get<0>(); } - static const Point< Real , Dim > &GetPoint( const PointAndDataType &pd ){ return pd.template get<0>(); } - static DataType &GetData( PointAndDataType &pd ){ return pd.template get<1>(); } - static const DataType &GetData( const PointAndDataType &pd ){ return pd.template get<1>(); } - }; + template< class Data > + struct DerivativeStream + { + virtual void resolution( unsigned int res[] ) const = 0; + virtual bool nextDerivative( unsigned int idx[] , unsigned int& dir , Data& dValue ) = 0; + }; - struct StreamInitializationData - { - friend FEMTreeInitializer; - protected: - std::vector< node_index_type > _nodeToIndexMap; - }; + // Initialize the tree using a refinement avatar + static size_t Initialize( FEMTreeNode& root , int maxDepth , std::function< bool ( int , int[] ) > Refine , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); - template< typename Data > - static size_t Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , typename InputPointStream< Data >::StreamType &pointStream , Data zeroData , int maxDepth , std::vector< PointSample >& samplePoints , std::vector< typename InputPointStream< Data >::DataType > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , typename InputPointStream< Data >::DataType & ) > ProcessData = []( const Point< Real , Dim > & , typename InputPointStream< Data >::DataType & ){ return (Real)1.; } ); - template< typename Data > - static size_t Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , typename InputPointStream< Data >::StreamType &pointStream , Data zeroData , int maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , std::vector< PointSample >& samplePoints , std::vector< typename InputPointStream< Data >::DataType > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , typename InputPointStream< Data >::DataType & ) > ProcessData = []( const Point< Real , Dim > & , typename InputPointStream< Data >::DataType & ){ return (Real)1.; } ); + // Initialize the tree using a point stream + template< typename Data > + struct InputPointStream + { + typedef Data DataType; + typedef VectorTypeUnion< Real , Point< Real , Dim > , Data > PointAndDataType; + typedef InputDataStream< PointAndDataType > StreamType; + static Point< Real , Dim > &GetPoint( PointAndDataType &pd ){ return pd.template get<0>(); } + static const Point< Real , Dim > &GetPoint( const PointAndDataType &pd ){ return pd.template get<0>(); } + static DataType &GetData( PointAndDataType &pd ){ return pd.template get<1>(); } + static const DataType &GetData( const PointAndDataType &pd ){ return pd.template get<1>(); } + + static void BoundingBox( StreamType &stream , Data d , Point< Real , Dim >& min , Point< Real , Dim >& max ) + { + PointAndDataType p; + p.template get<1>() = d; + for( unsigned int d=0 ; d::infinity() , max[d] = -std::numeric_limits< Real >::infinity(); + while( stream.read( p ) ) for( unsigned int d=0 ; d( min[d] , p.template get<0>()[d] ) , max[d] = std::max< Real >( max[d] , p.template get<0>()[d] ); + stream.reset(); + } + }; - // Initialize the tree using simplices - static void Initialize( FEMTreeNode& root , const std::vector< Point< Real , Dim > >& vertices , const std::vector< SimplexIndex< Dim-1 , node_index_type > >& simplices , int maxDepth , std::vector< PointSample >& samples , bool mergeNodeSamples , std::vector< Allocator< FEMTreeNode > * > &nodeAllocators , std::function< void ( FEMTreeNode& ) > NodeInitializer ); - static void Initialize( FEMTreeNode& root , const std::vector< Point< Real , Dim > >& vertices , const std::vector< SimplexIndex< Dim-1 , node_index_type > >& simplices , unsigned int regularGridDepth , unsigned int maxDepth , std::vector< NodeSimplices< Dim , Real > >& nodeSimplices , std::vector< Allocator< FEMTreeNode > * > &nodeAllocators , std::function< void ( FEMTreeNode& ) > NodeInitializer ); + template< typename Data > + struct OutputPointStream + { + typedef Data DataType; + typedef VectorTypeUnion< Real , Point< Real , Dim > , Data > PointAndDataType; + typedef OutputDataStream< PointAndDataType > StreamType; + static Point< Real , Dim > &GetPoint( PointAndDataType &pd ){ return pd.template get<0>(); } + static const Point< Real , Dim > &GetPoint( const PointAndDataType &pd ){ return pd.template get<0>(); } + static DataType &GetData( PointAndDataType &pd ){ return pd.template get<1>(); } + static const DataType &GetData( const PointAndDataType &pd ){ return pd.template get<1>(); } + }; - struct GeometryNodeType - { - enum Type : char + struct StreamInitializationData { - UNKNOWN , - INTERIOR , - BOUNDARY , - EXTERIOR + friend FEMTreeInitializer; + protected: + std::vector< node_index_type > _nodeToIndexMap; }; - Type type; - GeometryNodeType( Type t=UNKNOWN ) : type( t ){} - bool operator== ( GeometryNodeType gnt ) const { return type==gnt.type; } - bool operator!= ( GeometryNodeType gnt ) const { return type!=gnt.type; } - bool operator== ( Type type ) const { return this->type==type; } - bool operator!= ( Type type ) const { return this->type!=type; } - friend std::ostream &operator << ( std::ostream &os , const GeometryNodeType &type ) + template< typename Data > + static size_t Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , typename InputPointStream< Data >::StreamType &pointStream , Data zeroData , int maxDepth , std::vector< PointSample >& samplePoints , std::vector< typename InputPointStream< Data >::DataType > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , typename InputPointStream< Data >::DataType & ) > ProcessData = []( const Point< Real , Dim > & , typename InputPointStream< Data >::DataType & ){ return (Real)1.; } ); + template< typename Data > + static size_t Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , typename InputPointStream< Data >::StreamType &pointStream , Data zeroData , int maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , std::vector< PointSample >& samplePoints , std::vector< typename InputPointStream< Data >::DataType > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , typename InputPointStream< Data >::DataType & ) > ProcessData = []( const Point< Real , Dim > & , typename InputPointStream< Data >::DataType & ){ return (Real)1.; } ); + + // Initialize the tree using simplices + static void Initialize( FEMTreeNode& root , const std::vector< Point< Real , Dim > >& vertices , const std::vector< SimplexIndex< Dim-1 , node_index_type > >& simplices , int maxDepth , std::vector< PointSample >& samples , bool mergeNodeSamples , std::vector< Allocator< FEMTreeNode > * > &nodeAllocators , std::function< void ( FEMTreeNode& ) > NodeInitializer ); + static void Initialize( FEMTreeNode& root , const std::vector< Point< Real , Dim > >& vertices , const std::vector< SimplexIndex< Dim-1 , node_index_type > >& simplices , unsigned int regularGridDepth , unsigned int maxDepth , std::vector< NodeSimplices< Dim , Real > >& nodeSimplices , std::vector< Allocator< FEMTreeNode > * > &nodeAllocators , std::function< void ( FEMTreeNode& ) > NodeInitializer ); + + struct GeometryNodeType { - if ( type.type==UNKNOWN ) return os << "unknown"; - else if( type.type==INTERIOR ) return os << "interior"; - else if( type.type==BOUNDARY ) return os << "boundary"; - else if( type.type==EXTERIOR ) return os << "exterior"; - return os; - } - }; + enum Type : char + { + UNKNOWN , + INTERIOR , + BOUNDARY , + EXTERIOR + }; + Type type; + GeometryNodeType( Type t=UNKNOWN ) : type( t ){} + bool operator== ( GeometryNodeType gnt ) const { return type==gnt.type; } + bool operator!= ( GeometryNodeType gnt ) const { return type!=gnt.type; } + bool operator== ( Type type ) const { return this->type==type; } + bool operator!= ( Type type ) const { return this->type!=type; } + + friend std::ostream &operator << ( std::ostream &os , const GeometryNodeType &type ) + { + if ( type.type==UNKNOWN ) return os << "unknown"; + else if( type.type==INTERIOR ) return os << "interior"; + else if( type.type==BOUNDARY ) return os << "boundary"; + else if( type.type==EXTERIOR ) return os << "exterior"; + return os; + } + }; - template< unsigned int _Dim=Dim > - static typename std::enable_if< _Dim!=1 , DenseNodeData< GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > >::type GetGeometryNodeDesignators( FEMTreeNode *root , const std::vector< Point< Real , Dim > >& vertices , const std::vector< SimplexIndex< Dim-1 , node_index_type > >& simplices , unsigned int regularGridDepth , unsigned int maxDepth , std::vector< Allocator< FEMTreeNode > * > &nodeAllocators , std::function< void ( FEMTreeNode& ) > NodeInitializer ); - template< unsigned int _Dim=Dim > - static typename std::enable_if< _Dim==1 , DenseNodeData< GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > >::type GetGeometryNodeDesignators( FEMTreeNode *root , const std::vector< Point< Real , Dim > >& vertices , const std::vector< SimplexIndex< Dim-1 , node_index_type > >& simplices , unsigned int regularGridDepth , unsigned int maxDepth , std::vector< Allocator< FEMTreeNode > * > &nodeAllocators , std::function< void ( FEMTreeNode& ) > NodeInitializer ); - static void TestGeometryNodeDesignators( const FEMTreeNode *root , const DenseNodeData< GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > &geometryNodeDesignators ); - static void PushGeometryNodeDesignatorsToFiner( const FEMTreeNode *root , DenseNodeData< GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > &geometryNodeDesignators , unsigned int maxDepth=-1 ); - static void PullGeometryNodeDesignatorsFromFiner( const FEMTreeNode *root , DenseNodeData< GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > &geometryNodeDesignators , unsigned int maxDepth=-1 ); - - // Initialize the tree using weighted points - static void Initialize( FEMTreeNode &root , const std::vector< ProjectiveData< Point< Real , Dim > , Real > > &points , int maxDepth , std::vector< PointSample >& samples , bool mergeNodeSamples , std::vector< Allocator< FEMTreeNode > * > &nodeAllocators , std::function< void ( FEMTreeNode& ) > NodeInitializer ); - static void Initialize( FEMTreeNode &root , const std::vector< ProjectiveData< Point< Real , Dim > , Real > > &points , int maxDepth , std::vector< PointSample >& samples , bool mergeNodeSamples ); - - template< class Data , class _Data , bool Dual=true > - static size_t Initialize( FEMTreeNode& root , ConstPointer( Data ) values , ConstPointer( int ) labels , int resolution[Dim] , std::vector< NodeSample< Dim , _Data > > derivatives[Dim] , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< _Data ( const Data& ) > DataConverter = []( const Data& d ){ return (_Data)d; } ); - template< bool Dual , class Data > - static unsigned int Initialize( FEMTreeNode& root , DerivativeStream< Data >& dStream , Data zeroData , std::vector< NodeSample< Dim , Data > > derivatives[Dim] , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); - -protected: - static size_t _Initialize( FEMTreeNode &node , int maxDepth , std::function< bool ( int , int[] ) > Refine , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); - template< bool ThreadSafe > static size_t _AddSimplex( FEMTreeNode& root , Simplex< Real , Dim , Dim-1 >& s , int maxDepth , std::vector< PointSample >& samples , std::vector< node_index_type >* nodeToIndexMap , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); - template< bool ThreadSafe > static size_t _AddSimplex( FEMTreeNode* node , Simplex< Real , Dim , Dim-1 >& s , int maxDepth , std::vector< PointSample >& samples , std::vector< node_index_type >* nodeToIndexMap , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); - template< bool ThreadSafeAllocation , bool ThreadSafeSimplices > static size_t _AddSimplex( FEMTreeNode& root , node_index_type id , Simplex< Real , Dim , Dim-1 >& s , int maxDepth , std::vector< NodeSimplices< Dim , Real > >& simplices , std::vector< node_index_type >& nodeToIndexMap , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); - template< bool ThreadSafeAllocation , bool ThreadSafeSimplices > static size_t _AddSimplex( FEMTreeNode* node , node_index_type id , Simplex< Real , Dim , Dim-1 >& s , int maxDepth , std::vector< NodeSimplices< Dim , Real > >& simplices , std::vector< node_index_type >& nodeToIndexMap , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); - template< bool ThreadSafe > static size_t _AddSample( FEMTreeNode& root , ProjectiveData< Point< Real , Dim > , Real > s , int maxDepth , std::vector< PointSample >& samples , std::vector< node_index_type >* nodeToIndexMap , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); - static size_t _AddSample( FEMTreeNode& root , ProjectiveData< Point< Real , Dim > , Real > s , int maxDepth , std::vector< PointSample >& samples , std::vector< node_index_type >* nodeToIndexMap ); - static size_t _AddSample( FEMTreeNode* node , ProjectiveData< Point< Real , Dim > , Real > s , int maxDepth , std::vector< PointSample >& samples , std::vector< node_index_type >* nodeToIndexMap ); - static DenseNodeData< GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > _GetGeometryNodeDesignators( FEMTreeNode *root , const std::vector< Point< Real , Dim > >& vertices , const std::vector< SimplexIndex< Dim-1 , node_index_type > >& simplices , const std::vector< Point< Real , Dim > > &normals , unsigned int regularGridDepth , unsigned int maxDepth , std::vector< Allocator< FEMTreeNode > * > &nodeAllocators , std::function< void ( FEMTreeNode& ) > NodeInitializer ); -}; -template< unsigned int Dim , class Real > -template< unsigned int ... SupportSizes > -const unsigned int FEMTree< Dim , Real >::CornerLoopData< SupportSizes ... >::supportSizes[] = { SupportSizes ... }; + template< unsigned int _Dim=Dim > + static typename std::enable_if< _Dim!=1 , DenseNodeData< GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > >::type GetGeometryNodeDesignators( FEMTreeNode *root , const std::vector< Point< Real , Dim > >& vertices , const std::vector< SimplexIndex< Dim-1 , node_index_type > >& simplices , unsigned int regularGridDepth , unsigned int maxDepth , std::vector< Allocator< FEMTreeNode > * > &nodeAllocators , std::function< void ( FEMTreeNode& ) > NodeInitializer ); + template< unsigned int _Dim=Dim > + static typename std::enable_if< _Dim==1 , DenseNodeData< GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > >::type GetGeometryNodeDesignators( FEMTreeNode *root , const std::vector< Point< Real , Dim > >& vertices , const std::vector< SimplexIndex< Dim-1 , node_index_type > >& simplices , unsigned int regularGridDepth , unsigned int maxDepth , std::vector< Allocator< FEMTreeNode > * > &nodeAllocators , std::function< void ( FEMTreeNode& ) > NodeInitializer ); + static void TestGeometryNodeDesignators( const FEMTreeNode *root , const DenseNodeData< GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > &geometryNodeDesignators ); + static void PushGeometryNodeDesignatorsToFiner( const FEMTreeNode *root , DenseNodeData< GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > &geometryNodeDesignators , unsigned int maxDepth=-1 ); + static void PullGeometryNodeDesignatorsFromFiner( const FEMTreeNode *root , DenseNodeData< GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > &geometryNodeDesignators , unsigned int maxDepth=-1 ); + + // Initialize the tree using weighted points + static void Initialize( FEMTreeNode &root , const std::vector< ProjectiveData< Point< Real , Dim > , Real > > &points , int maxDepth , std::vector< PointSample >& samples , bool mergeNodeSamples , std::vector< Allocator< FEMTreeNode > * > &nodeAllocators , std::function< void ( FEMTreeNode& ) > NodeInitializer ); + static void Initialize( FEMTreeNode &root , const std::vector< ProjectiveData< Point< Real , Dim > , Real > > &points , int maxDepth , std::vector< PointSample >& samples , bool mergeNodeSamples ); + + template< class Data , class _Data , bool Dual=true > + static size_t Initialize( FEMTreeNode& root , ConstPointer( Data ) values , ConstPointer( int ) labels , int resolution[Dim] , std::vector< NodeSample< Dim , _Data > > derivatives[Dim] , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< _Data ( const Data& ) > DataConverter = []( const Data& d ){ return (_Data)d; } ); + template< bool Dual , class Data > + static unsigned int Initialize( FEMTreeNode& root , DerivativeStream< Data >& dStream , Data zeroData , std::vector< NodeSample< Dim , Data > > derivatives[Dim] , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); + + protected: + static size_t _Initialize( FEMTreeNode &node , int maxDepth , std::function< bool ( int , int[] ) > Refine , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); + template< bool ThreadSafe > static size_t _AddSimplex( FEMTreeNode& root , Simplex< Real , Dim , Dim-1 >& s , int maxDepth , std::vector< PointSample >& samples , std::vector< node_index_type >* nodeToIndexMap , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); + template< bool ThreadSafe > static size_t _AddSimplex( FEMTreeNode* node , Simplex< Real , Dim , Dim-1 >& s , int maxDepth , std::vector< PointSample >& samples , std::vector< node_index_type >* nodeToIndexMap , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); + template< bool ThreadSafeAllocation , bool ThreadSafeSimplices > static size_t _AddSimplex( FEMTreeNode& root , node_index_type id , Simplex< Real , Dim , Dim-1 >& s , int maxDepth , std::vector< NodeSimplices< Dim , Real > >& simplices , std::vector< node_index_type >& nodeToIndexMap , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); + template< bool ThreadSafeAllocation , bool ThreadSafeSimplices > static size_t _AddSimplex( FEMTreeNode* node , node_index_type id , Simplex< Real , Dim , Dim-1 >& s , int maxDepth , std::vector< NodeSimplices< Dim , Real > >& simplices , std::vector< node_index_type >& nodeToIndexMap , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); + template< bool ThreadSafe > static size_t _AddSample( FEMTreeNode& root , ProjectiveData< Point< Real , Dim > , Real > s , int maxDepth , std::vector< PointSample >& samples , std::vector< node_index_type >* nodeToIndexMap , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); + static size_t _AddSample( FEMTreeNode& root , ProjectiveData< Point< Real , Dim > , Real > s , int maxDepth , std::vector< PointSample >& samples , std::vector< node_index_type >* nodeToIndexMap ); + static size_t _AddSample( FEMTreeNode* node , ProjectiveData< Point< Real , Dim > , Real > s , int maxDepth , std::vector< PointSample >& samples , std::vector< node_index_type >* nodeToIndexMap ); + static DenseNodeData< GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > _GetGeometryNodeDesignators( FEMTreeNode *root , const std::vector< Point< Real , Dim > >& vertices , const std::vector< SimplexIndex< Dim-1 , node_index_type > >& simplices , const std::vector< Point< Real , Dim > > &normals , unsigned int regularGridDepth , unsigned int maxDepth , std::vector< Allocator< FEMTreeNode > * > &nodeAllocators , std::function< void ( FEMTreeNode& ) > NodeInitializer ); + }; + template< unsigned int Dim , class Real > + template< unsigned int ... SupportSizes > + const unsigned int FEMTree< Dim , Real >::CornerLoopData< SupportSizes ... >::supportSizes[] = { SupportSizes ... }; #include "FEMTree.inl" @@ -3050,6 +3061,10 @@ const unsigned int FEMTree< Dim , Real >::CornerLoopData< SupportSizes ... >::su #include "FEMTree.WeightedSamples.inl" #include "FEMTree.System.inl" #include "FEMTree.Evaluation.inl" +#include "FEMTree.LevelSet.inl" +#include "FEMTree.LevelSet.2D.inl" #include "FEMTree.LevelSet.3D.inl" #include "FEMTree.Initialize.inl" +} + #endif // FEM_TREE_INCLUDED diff --git a/Src/FEMTree.inl b/Src/FEMTree.inl index 1995398c..5a31b478 100644 --- a/Src/FEMTree.inl +++ b/Src/FEMTree.inl @@ -26,11 +26,6 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ -#include -#include -#include -#include "MyMiscellany.h" - ///////////////////// // FEMTreeNodeData // ///////////////////// @@ -189,6 +184,77 @@ void FEMTree< Dim , Real >::merge( const FEMTree< Dim , Real > &tree , const Den accumulateCoefficients( &tree._tree , &_tree ); } +template< unsigned int Dim , class Real , unsigned int Pad , unsigned int FEMSig > +struct SliceEvaluator +{ + struct _SliceEvaluator + { + const int StartOffset = BSplineSupportSizes< FEMSignature< FEMSig >::Degree >::SupportStart-(int)Pad; + const int EndOffset = BSplineSupportSizes< FEMSignature< FEMSig >::Degree >::SupportEnd+1+(int)Pad; + int start; + Real values[ BSplineSupportSizes< FEMSignature< FEMSig >::Degree >::SupportSize+2*Pad ]; + void init( unsigned int depth , double x , unsigned int d ) + { + // off @ depthsupports the slice if + // x>(off+StartOffset)/(1< x*(1<off && x*(1< off \in ( x*(1<::Degree ) for( int i=0 ; i::Value( depth , start+i , x , d ); + else if( d==FEMSignature< FEMSig >::Degree ) + { + double eps = 1e-4/(1<::Value( depth , start+i , x-eps , d ); + value += BSplineEvaluationData< FEMSig >::Value( depth , start+i , x+eps , d ); + values[i] = (Real)(value/2); + } + } + else // Otherwise we compute the discrete derivative + { + for( int i=0 ; i::Value( depth , start+i , x , d-1 ) - BSplineEvaluationData< FEMSig >::Value( depth , start+i , x-eps , d-1 ); + value += BSplineEvaluationData< FEMSig >::Value( depth , start+i , x+eps , d-1 ) - BSplineEvaluationData< FEMSig >::Value( depth , start+i , x , d-1 ); + values[i] = (Real)(value/(2*eps) ); + } + } + + } + else ERROR_OUT( "Derivative exceeds degree: " , d , " > " , FEMSignature< FEMSig >::Degree ); + } + Real operator()( int off ) const + { + if( off=start+(EndOffset-StartOffset ) ) return 0; + else return values[off-start]; + } + }; + + std::vector< _SliceEvaluator > evaluators; + void init( unsigned int maxDepth , double x , unsigned int d ) + { + evaluators.resize( maxDepth+1 ); + for( unsigned int depth=0 ; depth<=maxDepth ; depth++ ) evaluators[depth].init( depth , x , d ); + } + Real operator()( int d , int off ) const + { + if( d<0 || d>=(int)evaluators.size() ) return 0; + else return evaluators[d]( off ); + } +}; + template< unsigned int Dim , class Real > template< unsigned int Pad , unsigned int FEMSig , unsigned int ... FEMSigs , typename Data > void FEMTree< Dim , Real >::slice( const FEMTree< Dim+1 , Real > &tree , unsigned int d , const DenseNodeData< Data , UIntPack< FEMSigs ... , FEMSig > > &coefficients , DenseNodeData< Data , UIntPack< FEMSigs ... > > &sliceCoefficients , unsigned int sliceDepth , unsigned int sliceIndex ) const @@ -220,95 +286,7 @@ void FEMTree< Dim , Real >::slice( const FEMTree< Dim+1 , Real > &tree , unsigne const int EndOffset = BSplineSupportSizes< CrossDegree >::SupportEnd+1+(int)Pad; #endif // __GNUC__ - struct SliceEvaluator - { - struct _SliceEvaluator - { -#ifdef __GNUC__ - const int StartOffset = BSplineSupportSizes< FEMSignature< FEMSig >::Degree >::SupportStart-(int)Pad; - const int EndOffset = BSplineSupportSizes< FEMSignature< FEMSig >::Degree >::SupportEnd+1+(int)Pad; -#else // !__GNUC__ - const int StartOffset = BSplineSupportSizes< CrossDegree >::SupportStart-(int)_Pad; - const int EndOffset = BSplineSupportSizes< CrossDegree >::SupportEnd+1+(int)_Pad; -#endif // __GNUC__ - int start; -#ifdef __GNUC__ - Real values[ BSplineSupportSizes< FEMSignature< FEMSig >::Degree >::SupportSize+2*Pad ]; -#else // !__GNUC__ - Real values[ BSplineSupportSizes< CrossDegree >::SupportSize+2*Pad ]; -#endif // __GNUC__ - void init( unsigned int depth , double x , unsigned int d ) - { - // off @ depthsupports the slice if - // x>(off+StartOffset)/(1< x*(1<off && x*(1< off \in ( x*(1<::Degree ) for( int i=0 ; i::Value( depth , start+i , x , d ); - else if( d==FEMSignature< FEMSig >::Degree ) -#else // !__GNUC__ - if( d::Value( depth , start+i , x , d ); - else if( d==CrossDegree ) -#endif // __GNUC__ - { - double eps = 1e-4/(1<::Value( depth , start+i , x-eps , d ); - value += BSplineEvaluationData< FEMSig >::Value( depth , start+i , x+eps , d ); - values[i] = (Real)(value/2); - } - } - else // Otherwise we compute the discrete derivative - { - for( int i=0 ; i::Value( depth , start+i , x , d-1 ) - BSplineEvaluationData< FEMSig >::Value( depth , start+i , x-eps , d-1 ); - value += BSplineEvaluationData< FEMSig >::Value( depth , start+i , x+eps , d-1 ) - BSplineEvaluationData< FEMSig >::Value( depth , start+i , x , d-1 ); - values[i] = (Real)(value/(2*eps) ); - } - } - - } -#ifdef __GNUC__ - else ERROR_OUT( "Derivative exceeds degree: " , d , " > " , FEMSignature< FEMSig >::Degree ); -#else // !__GNUC__ - else ERROR_OUT( "Derivative exceeds degree: " , d , " > " , CrossDegree ); -#endif // __GNUC__ - } - Real operator()( int off ) const - { - if( off=start+(EndOffset-StartOffset ) ) return 0; - else return values[off-start]; - } - }; - - std::vector< _SliceEvaluator > evaluators; - void init( unsigned int maxDepth , double x , unsigned int d ) - { - evaluators.resize( maxDepth+1 ); - for( unsigned int depth=0 ; depth<=maxDepth ; depth++ ) evaluators[depth].init( depth , x , d ); - } - Real operator()( int d , int off ) const - { - if( d<0 || d>=(int)evaluators.size() ) return 0; - else return evaluators[d]( off ); - } - }; - - SliceEvaluator sliceEvaluator; + SliceEvaluator< Dim , Real , Pad , FEMSig > sliceEvaluator; sliceEvaluator.init( maxDepth , s , d ); // A function return true if the function indexed by the node has support overlapping the slice diff --git a/Src/Factor.h b/Src/Factor.h index 3845e174..7595eca8 100644 --- a/Src/Factor.h +++ b/Src/Factor.h @@ -31,124 +31,126 @@ DAMAGE. #include #include -#ifndef SQRT_3 -#define SQRT_3 1.7320508075688772935 -#endif // SQRT_3 -inline int Factor( double a1 , double a0 , std::complex< double > roots[1] , double EPS ) +namespace PoissonRecon { - if( fabs(a1)<=EPS ) return 0; - roots[0] = std::complex< double >( -a0/a1 , 0 ); - return 1; -} -inline int Factor( double a2 , double a1 , double a0 , std::complex< double > roots[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] = std::complex< double >( -a1 , -d ); - roots[1] = std::complex< double >( -a1 , d ); - } - else - { - d = sqrt(d)/(2*a2); - roots[0] = std::complex< double >( -a1-d , 0 ); - roots[1] = std::complex< double >( -a1+d , 0 ); - } - return 2; -} -// Solution taken from: http://mathworld.wolfram.com/CubicFormula.html -// and http://www.csit.fsu.edu/~burkardt/f_src/subpak/subpak.f90 -inline int Factor( double a3 , double a2 , double a1 , double a0 , std::complex< double > roots[3] , 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; + static const double SQRT_3 = 1.7320508075688772935; - if(r2 roots[1] , double EPS ) { - double sqrQ = sqrt(q); - double theta = acos ( r / (sqrQ*q) ); - double cTheta=cos(theta/3)*sqrQ; - double sTheta=sin(theta/3)*sqrQ*SQRT_3/2; - roots[0] = std::complex< double >( -2*cTheta , 0 ); - roots[1] = std::complex< double >( -2*(-cTheta*0.5-sTheta) , 0 ); - roots[2] = std::complex< double >( -2*(-cTheta*0.5+sTheta) , 0 ); + if( fabs(a1)<=EPS ) return 0; + roots[0] = std::complex< double >( -a0/a1 , 0 ); + return 1; } - else + inline int Factor( double a2 , double a1 , double a0 , std::complex< double > roots[2] , double EPS ) { - double t , s1 , s2 , sqr=sqrt(r2-q3); - t = -r+sqr; - if(t<0) s1 = -pow( -t , 1.0/3 ); - else s1 = pow( t , 1.0/3 ); - t = -r-sqr; - if( t<0 ) s2 = -pow( -t , 1.0/3 ); - else s2 = pow( t , 1.0/3 ); - roots[0] = std::complex< double >( s1+s2 , 0 ); - s1 /= 2 , s2 /= 2; - roots[1] = std::complex< double >( -s1-s2 , SQRT_3*(s1-s2) ); - roots[2] = std::complex< double >( -s1-s2 , -SQRT_3*(s1-s2) ); + 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] = std::complex< double >( -a1 , -d ); + roots[1] = std::complex< double >( -a1 , d ); + } + else + { + d = sqrt(d)/(2*a2); + roots[0] = std::complex< double >( -a1-d , 0 ); + roots[1] = std::complex< double >( -a1+d , 0 ); + } + return 2; } - roots[0] -= a2/3; - roots[1] -= a2/3; - roots[2] -= a2/3; - return 3; -} -// Solution taken from: http://mathworld.wolfram.com/QuarticEquation.html -// and http://www.csit.fsu.edu/~burkardt/f_src/subpak/subpak.f90 -inline int Factor( double a4 , double a3 , double a2 , double a1 , double a0 , std::complex< double > roots[4] , double EPS ) -{ - std::complex< double > R , D , E , R2; - - if( fabs(a4)( a3*a3/4.0-a2+roots[0].real() , 0 ); - R = sqrt( R2 ); - if( fabs( R.real() )>10e-8 ) + // Solution taken from: http://mathworld.wolfram.com/CubicFormula.html + // and http://www.csit.fsu.edu/~burkardt/f_src/subpak/subpak.f90 + inline int Factor( double a3 , double a2 , double a1 , double a0 , std::complex< double > roots[3] , double EPS ) { - std::complex< double > temp1 , temp2 , p1 , p2; - - p1 = std::complex< double >( a3*a3*0.75-2.0*a2-R2.real() , 0 ); - - temp2 = std::complex< double >( (4.0*a3*a2-8.0*a1-a3*a3*a3)/4.0 , 0 ); - p2 = temp2 / R; - temp1 = p1+p2; - temp2 = p1-p2; - D = sqrt( temp1 ); - E = sqrt( temp2 ); + 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(r2( -2*cTheta , 0 ); + roots[1] = std::complex< double >( -2*(-cTheta*0.5-sTheta) , 0 ); + roots[2] = std::complex< double >( -2*(-cTheta*0.5+sTheta) , 0 ); + } + else + { + double t , s1 , s2 , sqr=sqrt(r2-q3); + t = -r+sqr; + if(t<0) s1 = -pow( -t , 1.0/3 ); + else s1 = pow( t , 1.0/3 ); + t = -r-sqr; + if( t<0 ) s2 = -pow( -t , 1.0/3 ); + else s2 = pow( t , 1.0/3 ); + roots[0] = std::complex< double >( s1+s2 , 0 ); + s1 /= 2 , s2 /= 2; + roots[1] = std::complex< double >( -s1-s2 , SQRT_3*(s1-s2) ); + roots[2] = std::complex< double >( -s1-s2 , -SQRT_3*(s1-s2) ); + } + roots[0] -= a2/3; + roots[1] -= a2/3; + roots[2] -= a2/3; + return 3; } - else + // Solution taken from: http://mathworld.wolfram.com/QuarticEquation.html + // and http://www.csit.fsu.edu/~burkardt/f_src/subpak/subpak.f90 + inline int Factor( double a4 , double a3 , double a2 , double a1 , double a0 , std::complex< double > roots[4] , double EPS ) { - R = std::complex< double >( 0 , 0 ); - std::complex< double > temp1 , temp2; - temp1 = std::complex< double >( roots[0].real()*roots[0].real()-4.0*a0 , 0 ); - temp2 = sqrt( temp1 ); - - temp1 = std::complex< double >( a3*a3*0.75-2.0*a2+2.0*temp2.real() , 2.0*temp2.imag() ); - D = sqrt( temp1 ); - - temp1 = std::complex< double >( a3*a3*0.75-2.0*a2-2.0*temp2.real() , -2.0*temp2.imag() ); - E = sqrt( temp1 ); + std::complex< double > R , D , E , R2; + + if( fabs(a4)( a3*a3/4.0-a2+roots[0].real() , 0 ); + R = sqrt( R2 ); + if( fabs( R.real() )>10e-8 ) + { + std::complex< double > temp1 , temp2 , p1 , p2; + + p1 = std::complex< double >( a3*a3*0.75-2.0*a2-R2.real() , 0 ); + + temp2 = std::complex< double >( (4.0*a3*a2-8.0*a1-a3*a3*a3)/4.0 , 0 ); + p2 = temp2 / R; + temp1 = p1+p2; + temp2 = p1-p2; + D = sqrt( temp1 ); + E = sqrt( temp2 ); + } + else + { + R = std::complex< double >( 0 , 0 ); + std::complex< double > temp1 , temp2; + temp1 = std::complex< double >( roots[0].real()*roots[0].real()-4.0*a0 , 0 ); + temp2 = sqrt( temp1 ); + + temp1 = std::complex< double >( a3*a3*0.75-2.0*a2+2.0*temp2.real() , 2.0*temp2.imag() ); + D = sqrt( temp1 ); + + temp1 = std::complex< double >( a3*a3*0.75-2.0*a2-2.0*temp2.real() , -2.0*temp2.imag() ); + E = sqrt( temp1 ); + } + + roots[0] = R/2. + D/2. - a3/4; + roots[1] = R/2. - D/2. - a3/4; + roots[2] = -R/2. + E/2. - a3/4; + roots[3] = -R/2. - E/2. - a3/4; + + return 4; } - - roots[0] = R/2. + D/2. - a3/4; - roots[1] = R/2. - D/2. - a3/4; - roots[2] = -R/2. + E/2. - a3/4; - roots[3] = -R/2. - E/2. - a3/4; - - return 4; } #endif // FACTOR_INCLUDED \ No newline at end of file diff --git a/Src/FunctionData.h b/Src/FunctionData.h deleted file mode 100644 index 4df1b084..00000000 --- a/Src/FunctionData.h +++ /dev/null @@ -1,109 +0,0 @@ -/* -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 FUNCTION_DATA_INCLUDED -#define FUNCTION_DATA_INCLUDED - -#define BOUNDARY_CONDITIONS 1 - - -#include "PPolynomial.h" - -template -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 - * spcifies 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/FunctionData.inl b/Src/FunctionData.inl deleted file mode 100644 index 4e61b961..00000000 --- a/Src/FunctionData.inl +++ /dev/null @@ -1,415 +0,0 @@ -/* -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/Geometry.h b/Src/Geometry.h index 2748620f..5cb2f81f 100644 --- a/Src/Geometry.h +++ b/Src/Geometry.h @@ -41,641 +41,676 @@ DAMAGE. #include "MyMiscellany.h" #include "Array.h" -// An empty type -template< typename Real > -struct EmptyVectorType +namespace PoissonRecon { - EmptyVectorType& operator += ( const EmptyVectorType& p ){ return *this; } - EmptyVectorType& operator -= ( const EmptyVectorType& p ){ return *this; } - EmptyVectorType& operator *= ( Real s ) { return *this; } - EmptyVectorType& operator /= ( Real s ) { return *this; } - EmptyVectorType operator + ( const EmptyVectorType& p ) const { EmptyVectorType _p = *this ; _p += p ; return _p; } - EmptyVectorType operator - ( const EmptyVectorType& p ) const { EmptyVectorType _p = *this ; _p -= p ; return _p; } - EmptyVectorType operator * ( Real s ) const { EmptyVectorType _p = *this ; _p *= s ; return _p; } - EmptyVectorType operator / ( Real s ) const { EmptyVectorType _p = *this ; _p /= s ; return _p; } - - friend std::ostream &operator << ( std::ostream &os , const EmptyVectorType &v ){ return os; } -}; -template< typename Real > EmptyVectorType< Real > operator * ( Real s , EmptyVectorType< Real > v ){ return v*s; } - -template< typename _Real , typename ... VectorTypes > -struct VectorTypeUnion -{ -protected: - typedef std::tuple< VectorTypes ... > _VectorTuple; -public: - typedef _Real Real; - template< unsigned int I > using VectorType = typename std::tuple_element< I , _VectorTuple >::type; - template< unsigned int I > VectorType< I >& get( void ) { return std::get< I >( _vectorTypeTuple ); } - template< unsigned int I > const VectorType< I >& get( void ) const { return std::get< I >( _vectorTypeTuple ); } - - VectorTypeUnion& operator += ( const VectorTypeUnion& p ){ _add<0>( p ) ; return *this; } - VectorTypeUnion& operator -= ( const VectorTypeUnion& p ){ _sub<0>( p ) ; return *this; } - VectorTypeUnion& operator *= ( Real s ) { _mul<0>( s ) ; return *this; } - VectorTypeUnion& operator /= ( Real s ) { _div<0>( s ) ; return *this; } - VectorTypeUnion operator + ( const VectorTypeUnion& p ) const { VectorTypeUnion _p = *this ; _p += p ; return _p; } - VectorTypeUnion operator - ( const VectorTypeUnion& p ) const { VectorTypeUnion _p = *this ; _p -= p ; return _p; } - VectorTypeUnion operator * ( Real s ) const { VectorTypeUnion _p = *this ; _p *= s ; return _p; } - VectorTypeUnion operator / ( Real s ) const { VectorTypeUnion _p = *this ; _p /= s ; return _p; } - - VectorTypeUnion( void ){} - VectorTypeUnion( const VectorTypes & ... vectors ){ _set< 0 >( vectors ... ); } - - friend std::ostream &operator << ( std::ostream &os , const VectorTypeUnion &v ) - { - os << "{ "; - v._streamOut< 0 >( os ); - os << " }"; - return os; - } -protected: - std::tuple< VectorTypes ... > _vectorTypeTuple; - template< unsigned int I , typename _Vector , typename ... _Vectors > void _set( const _Vector &vector , const _Vectors & ... vectors ){ get< I >() = vector ; _set< I+1 >( vectors ... ); } - template< unsigned int I , typename _Vector > void _set( const _Vector &vector ){ get< I >() = vector ; } - template< unsigned int I > typename std::enable_if< I!=sizeof...(VectorTypes) >::type _add( const VectorTypeUnion& p ){ get() += p.get() ; _add< I+1 >( p ); } - template< unsigned int I > typename std::enable_if< I==sizeof...(VectorTypes) >::type _add( const VectorTypeUnion& p ){ } - template< unsigned int I > typename std::enable_if< I!=sizeof...(VectorTypes) >::type _sub( const VectorTypeUnion& p ){ get() -= p.get() ; _sub< I+1 >( p ); } - template< unsigned int I > typename std::enable_if< I==sizeof...(VectorTypes) >::type _sub( const VectorTypeUnion& p ){ } - template< unsigned int I > typename std::enable_if< I!=sizeof...(VectorTypes) >::type _mul( Real s ){ get() *= s ; _mul< I+1 >( s ); } - template< unsigned int I > typename std::enable_if< I==sizeof...(VectorTypes) >::type _mul( Real s ){ } - template< unsigned int I > typename std::enable_if< I!=sizeof...(VectorTypes) >::type _div( Real s ){ get() /= s ; _div< I+1 >( s ); } - template< unsigned int I > typename std::enable_if< I==sizeof...(VectorTypes) >::type _div( Real s ){ } - template< unsigned int I > typename std::enable_if< I!=sizeof...(VectorTypes) >::type _streamOut( std::ostream &os ) const { os << get() ; if( I!=sizeof...(VectorTypes)-1 ) os << " , "; _streamOut< I+1 >( os ); } - template< unsigned int I > typename std::enable_if< I==sizeof...(VectorTypes) >::type _streamOut( std::ostream &os ) const { } -}; -template< typename Real , typename ... Vectors > -VectorTypeUnion< Real , Vectors ... > operator * ( Real s , VectorTypeUnion< Real , Vectors ... > vu ){ return vu * s; } - -template< class Real > Real Random( void ); - -template< class Real , unsigned int Dim > struct XForm; - - -template< typename Real , unsigned int ... Dims > struct Point; - -template< class Real , unsigned int Dim > -struct Point< Real , Dim > -{ - void _init( unsigned int d ) - { - if( !d ) memset( coords , 0 , sizeof(Real)*Dim ); - else ERROR_OUT( "Should never be called" ); - } - template< class _Real , class ... _Reals > void _init( unsigned int d , _Real v , _Reals ... values ) - { - coords[d] = (Real)v; - if( d+1 - static void _AddColumnVector( XForm< Real , Dim >& x , unsigned int c , Point point , Points ... points ) - { - for( unsigned int r=0 ; r& x , unsigned int c ){ ; } -public: - Real coords[Dim]; - Point( void ) { memset( coords , 0 , sizeof(Real)*Dim ); } - Point( const Point& p ){ memcpy( coords , p.coords , sizeof(Real)*Dim ); } - template< class ... _Reals > Point( _Reals ... values ){ static_assert( sizeof...(values)==Dim || sizeof...(values)==0 , "[ERROR] Point::Point: Invalid number of coefficients" ) ; _init( 0 , values... ); } - template< class _Real > Point( const Point< _Real , Dim >& p ){ for( unsigned int d=0 ; d inline Point& operator += ( Point< _Real , Dim > p ) { for( unsigned int d=0 ; d inline Point operator + ( Point< _Real , Dim > p ) const { Point q ; for( unsigned int d=0 ; d inline Point& operator -= ( Point< _Real , Dim > p ) { return (*this)+=(-p); } - template< class _Real > inline Point operator - ( Point< _Real , Dim > p ) const { return (*this)+ (-p); } - template< class Scalar > inline Point& operator *= ( Scalar r ) { for( unsigned int d=0 ; d inline Point operator * ( Scalar r ) const { Point q ; for( unsigned int d=0 ; d inline Point& operator /= ( Scalar r ) { for( unsigned int d=0 ; d inline Point operator / ( Scalar r ) const { Point q ; for( unsigned int d=0 ; d inline Point& operator *= ( Point< _Real , Dim > p ) { for( unsigned int d=0 ; d inline Point operator * ( Point< _Real , Dim > p ) const { Point q ; for( unsigned int d=0 ; d inline Point& operator /= ( Point< _Real , Dim > p ) { for( unsigned int d=0 ; d inline Point operator / ( Point< _Real , Dim > p ) const { Point q ; for( unsigned int d=0 ; d static Point CrossProduct( Points ... points ) - { - static_assert( sizeof ... ( points )==Dim-1 , "Number of points in cross-product must be one less than the dimension" ); - XForm< Real , Dim > x; - _AddColumnVector( x , 0 , points ... ); - Point p; - for( unsigned int d=0 ; d x; - for( unsigned int d=0 ; d - friend std::ostream &operator << ( std::ostream &os , const Point< _Real , _Dim > &p ); -}; -template< class Real , unsigned int Dim > Point< Real , Dim > operator * ( Real r , Point< Real , Dim > p ){ return p*r; } -template< class Real , unsigned int Dim > Point< Real , Dim > operator / ( Real r , Point< Real , Dim > p ){ return p/r; } -template< class Real , unsigned int Dim > -std::ostream &operator << ( std::ostream &os , const Point< Real , Dim > &p ) -{ - os << "( "; - for( int d=0 ; d -struct Point< Real > -{ - Point( void ) : _coords( NullPointer(Real) ) , _dim(0){} - Point( size_t dim ) : _coords( NullPointer(Real) ) , _dim(0) { if( dim ){ _resize( (unsigned int)dim ) ; memset( _coords , 0 , sizeof(Real)*_dim ); } } - Point( const Point &p ) : _coords( NullPointer(Real) ) , _dim(0) { if( p._dim ){ _resize( p._dim ) ; memcpy( _coords , p._coords , sizeof(Real)*_dim ); } } - ~Point( void ){ DeletePointer( _coords ); } + // An empty type + template< typename Real > + struct EmptyVectorType + { + EmptyVectorType& operator += ( const EmptyVectorType& p ){ return *this; } + EmptyVectorType& operator -= ( const EmptyVectorType& p ){ return *this; } + EmptyVectorType& operator *= ( Real s ) { return *this; } + EmptyVectorType& operator /= ( Real s ) { return *this; } + EmptyVectorType operator + ( const EmptyVectorType& p ) const { EmptyVectorType _p = *this ; _p += p ; return _p; } + EmptyVectorType operator - ( const EmptyVectorType& p ) const { EmptyVectorType _p = *this ; _p -= p ; return _p; } + EmptyVectorType operator * ( Real s ) const { EmptyVectorType _p = *this ; _p *= s ; return _p; } + EmptyVectorType operator / ( Real s ) const { EmptyVectorType _p = *this ; _p /= s ; return _p; } + + friend std::ostream &operator << ( std::ostream &os , const EmptyVectorType &v ){ return os; } + }; + template< typename Real > EmptyVectorType< Real > operator * ( Real s , EmptyVectorType< Real > v ){ return v*s; } + + template< typename _Real , typename ... VectorTypes > + struct VectorTypeUnion + { + protected: + typedef std::tuple< VectorTypes ... > _VectorTuple; + public: + typedef _Real Real; + template< unsigned int I > using VectorType = typename std::tuple_element< I , _VectorTuple >::type; + template< unsigned int I > VectorType< I >& get( void ) { return std::get< I >( _vectorTypeTuple ); } + template< unsigned int I > const VectorType< I >& get( void ) const { return std::get< I >( _vectorTypeTuple ); } + + VectorTypeUnion& operator += ( const VectorTypeUnion& p ){ _add<0>( p ) ; return *this; } + VectorTypeUnion& operator -= ( const VectorTypeUnion& p ){ _sub<0>( p ) ; return *this; } + VectorTypeUnion& operator *= ( Real s ) { _mul<0>( s ) ; return *this; } + VectorTypeUnion& operator /= ( Real s ) { _div<0>( s ) ; return *this; } + VectorTypeUnion operator + ( const VectorTypeUnion& p ) const { VectorTypeUnion _p = *this ; _p += p ; return _p; } + VectorTypeUnion operator - ( const VectorTypeUnion& p ) const { VectorTypeUnion _p = *this ; _p -= p ; return _p; } + VectorTypeUnion operator * ( Real s ) const { VectorTypeUnion _p = *this ; _p *= s ; return _p; } + VectorTypeUnion operator / ( Real s ) const { VectorTypeUnion _p = *this ; _p /= s ; return _p; } + + VectorTypeUnion( void ){} + VectorTypeUnion( const VectorTypes & ... vectors ){ _set< 0 >( vectors ... ); } + + friend std::ostream &operator << ( std::ostream &os , const VectorTypeUnion &v ) + { + os << "{ "; + v._streamOut< 0 >( os ); + os << " }"; + return os; + } + protected: + std::tuple< VectorTypes ... > _vectorTypeTuple; + template< unsigned int I , typename _Vector , typename ... _Vectors > void _set( const _Vector &vector , const _Vectors & ... vectors ){ get< I >() = vector ; _set< I+1 >( vectors ... ); } + template< unsigned int I , typename _Vector > void _set( const _Vector &vector ){ get< I >() = vector ; } + template< unsigned int I > typename std::enable_if< I!=sizeof...(VectorTypes) >::type _add( const VectorTypeUnion& p ){ get() += p.get() ; _add< I+1 >( p ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(VectorTypes) >::type _add( const VectorTypeUnion& p ){ } + template< unsigned int I > typename std::enable_if< I!=sizeof...(VectorTypes) >::type _sub( const VectorTypeUnion& p ){ get() -= p.get() ; _sub< I+1 >( p ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(VectorTypes) >::type _sub( const VectorTypeUnion& p ){ } + template< unsigned int I > typename std::enable_if< I!=sizeof...(VectorTypes) >::type _mul( Real s ){ get() *= s ; _mul< I+1 >( s ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(VectorTypes) >::type _mul( Real s ){ } + template< unsigned int I > typename std::enable_if< I!=sizeof...(VectorTypes) >::type _div( Real s ){ get() /= s ; _div< I+1 >( s ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(VectorTypes) >::type _div( Real s ){ } + template< unsigned int I > typename std::enable_if< I!=sizeof...(VectorTypes) >::type _streamOut( std::ostream &os ) const { os << get() ; if( I!=sizeof...(VectorTypes)-1 ) os << " , "; _streamOut< I+1 >( os ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(VectorTypes) >::type _streamOut( std::ostream &os ) const { } + }; + template< typename Real , typename ... Vectors > + VectorTypeUnion< Real , Vectors ... > operator * ( Real s , VectorTypeUnion< Real , Vectors ... > vu ){ return vu * s; } + + template< class Real > Real Random( void ); + + template< class Real , unsigned int Dim > struct XForm; + + + template< typename Real , unsigned int ... Dims > struct Point; + + template< class Real , unsigned int Dim > + struct Point< Real , Dim > + { + void _init( unsigned int d ) + { + if( !d ) memset( coords , 0 , sizeof(Real)*Dim ); + else ERROR_OUT( "Should never be called" ); + } + template< class _Real , class ... _Reals > void _init( unsigned int d , _Real v , _Reals ... values ) + { + coords[d] = (Real)v; + if( d+1 + static void _AddColumnVector( XForm< Real , Dim >& x , unsigned int c , Point point , Points ... points ) + { + for( unsigned int r=0 ; r& x , unsigned int c ){ ; } + public: + Real coords[Dim]; + Point( void ) { memset( coords , 0 , sizeof(Real)*Dim ); } + Point( const Point& p ){ memcpy( coords , p.coords , sizeof(Real)*Dim ); } + template< class ... _Reals > Point( _Reals ... values ){ static_assert( sizeof...(values)==Dim || sizeof...(values)==0 , "[ERROR] Point::Point: Invalid number of coefficients" ) ; _init( 0 , values... ); } + template< class _Real > Point( const Point< _Real , Dim >& p ){ for( unsigned int d=0 ; d inline Point& operator += ( Point< _Real , Dim > p ) { for( unsigned int d=0 ; d inline Point operator + ( Point< _Real , Dim > p ) const { Point q ; for( unsigned int d=0 ; d inline Point& operator -= ( Point< _Real , Dim > p ) { return (*this)+=(-p); } + template< class _Real > inline Point operator - ( Point< _Real , Dim > p ) const { return (*this)+ (-p); } + template< class Scalar > inline Point& operator *= ( Scalar r ) { for( unsigned int d=0 ; d inline Point operator * ( Scalar r ) const { Point q ; for( unsigned int d=0 ; d inline Point& operator /= ( Scalar r ) { for( unsigned int d=0 ; d inline Point operator / ( Scalar r ) const { Point q ; for( unsigned int d=0 ; d inline Point& operator *= ( Point< _Real , Dim > p ) { for( unsigned int d=0 ; d inline Point operator * ( Point< _Real , Dim > p ) const { Point q ; for( unsigned int d=0 ; d inline Point& operator /= ( Point< _Real , Dim > p ) { for( unsigned int d=0 ; d inline Point operator / ( Point< _Real , Dim > p ) const { Point q ; for( unsigned int d=0 ; d static Point CrossProduct( Points ... points ) + { + static_assert( sizeof ... ( points )==Dim-1 , "Number of points in cross-product must be one less than the dimension" ); + XForm< Real , Dim > x; + _AddColumnVector( x , 0 , points ... ); + Point p; + for( unsigned int d=0 ; d x; + for( unsigned int d=0 ; d + friend std::ostream &operator << ( std::ostream &os , const Point< _Real , _Dim > &p ); + }; + template< class Real , unsigned int Dim > Point< Real , Dim > operator * ( Real r , Point< Real , Dim > p ){ return p*r; } + template< class Real , unsigned int Dim > Point< Real , Dim > operator / ( Real r , Point< Real , Dim > p ){ return p/r; } + template< class Real , unsigned int Dim > + std::ostream &operator << ( std::ostream &os , const Point< Real , Dim > &p ) { - if( !_dim ){ _resize( p._dim ) ; memcpy( _coords , p._coords , sizeof(Real)*_dim ); } - else if( _dim==p._dim ) memcpy( _coords , p._coords , sizeof(Real)*_dim ); - else ERROR_OUT( "Dimensions don't match: " , _dim , " != " , p._dim ); - return *this; + os << "( "; + for( int d=0 ; d + struct Point< Real > + { + Point( void ) : _coords( NullPointer(Real) ) , _dim(0){} + Point( size_t dim ) : _coords( NullPointer(Real) ) , _dim(0) { if( dim ){ _resize( (unsigned int)dim ) ; memset( _coords , 0 , sizeof(Real)*_dim ); } } + Point( const Point &p ) : _coords( NullPointer(Real) ) , _dim(0) { if( p._dim ){ _resize( p._dim ) ; memcpy( _coords , p._coords , sizeof(Real)*_dim ); } } + ~Point( void ){ DeletePointer( _coords ); } + Point &operator = ( const Point &p ) + { + if( !_dim ){ _resize( p._dim ) ; memcpy( _coords , p._coords , sizeof(Real)*_dim ); } + else if( _dim==p._dim ) memcpy( _coords , p._coords , sizeof(Real)*_dim ); + else ERROR_OUT( "Dimensions don't match: " , _dim , " != " , p._dim ); + return *this; + } - Point& operator += ( const Point& p ) - { - if( !_dim ){ _resize( p._dim ) ; for( unsigned int i=0 ; i<_dim ; i++ ) _coords[i] = p._coords[i]; } - else if( _dim==p._dim ) for( unsigned int i=0 ; i<_dim ; i++ ) _coords[i] += p._coords[i]; - else ERROR_OUT( "Dimensions don't match: " , _dim , " != " , p._dim ); - return *this; - } - Point& operator -= ( const Point& p ) - { - if( !_dim ){ _resize( p._dim ) ; for( unsigned int i=0 ; i<_dim ; i++ ) _coords[i] = -p._coords[i]; } - else if( _dim==p._dim ) for( unsigned int i=0 ; i<_dim ; i++ ) _coords[i] -= p._coords[i]; - else ERROR_OUT( "Dimensions don't match: " , _dim , " != " , p._dim ); - return *this; - } - Point& operator *= ( Real s ) - { - for( unsigned int i=0 ; i<_dim ; i++ ) (*this)[i] *= s; - return *this; - } - Point& operator /= ( Real s ) - { - for( unsigned int i=0 ; i<_dim ; i++ ) (*this)[i] /= s; - return *this; - } - Point operator + ( const Point& p ) const { Point _p = *this ; _p += p ; return _p; } - Point operator - ( const Point& p ) const { Point _p = *this ; _p -= p ; return _p; } - Point operator * ( Real s ) const { Point _p = *this ; _p *= s ; return _p; } - Point operator / ( Real s ) const { Point _p = *this ; _p /= s ; return _p; } + unsigned int dim( void ) const { return _dim; } + Real &operator[]( size_t idx ){ return _coords[idx]; } + const Real &operator[]( size_t idx ) const { return _coords[idx]; } - static Real Dot( const Point &p1 , const Point &p2 ) - { - Real dot; - if( p1._dim!=p2._dim ) ERROR_OUT( "Dimensions differ: " , p1._dim , " != " , p2._dim ); - for( size_t d=0 ; d( dim ); - _dim = dim; - } -}; -template< class Real > Point< Real > operator * ( Real s , Point< Real > p ){ return p*s; } + Point& operator -= ( const Point& p ) + { + if( !_dim ){ _resize( p._dim ) ; for( unsigned int i=0 ; i<_dim ; i++ ) _coords[i] = -p._coords[i]; } + else if( _dim==p._dim ) for( unsigned int i=0 ; i<_dim ; i++ ) _coords[i] -= p._coords[i]; + else ERROR_OUT( "Dimensions don't match: " , _dim , " != " , p._dim ); + return *this; + } + Point& operator *= ( Real s ) + { + for( unsigned int i=0 ; i<_dim ; i++ ) (*this)[i] *= s; + return *this; + } + Point& operator /= ( Real s ) + { + for( unsigned int i=0 ; i<_dim ; i++ ) (*this)[i] /= s; + return *this; + } + Point operator + ( const Point& p ) const { Point _p = *this ; _p += p ; return _p; } + Point operator - ( const Point& p ) const { Point _p = *this ; _p -= p ; return _p; } + Point operator * ( Real s ) const { Point _p = *this ; _p *= s ; return _p; } + Point operator / ( Real s ) const { Point _p = *this ; _p /= s ; return _p; } -/** This templated class represents a Ray.*/ -template< class Real , unsigned int Dim > -class Ray -{ -public: - /** The starting point of the ray */ - Point< Real , Dim > position; + static Real Dot( const Point &p1 , const Point &p2 ) + { + Real dot; + if( p1._dim!=p2._dim ) ERROR_OUT( "Dimensions differ: " , p1._dim , " != " , p2._dim ); + for( size_t d=0 ; d direction; + friend std::ostream &operator << ( std::ostream &os , const Point &p ) + { + os << "( "; + for( size_t i=0 ; i( dim ); + _dim = dim; + } + }; + template< class Real > Point< Real > operator * ( Real s , Point< Real > p ){ return p*s; } - /** The default constructor */ - Ray( void ){} + /** This templated class represents a Ray.*/ + template< class Real , unsigned int Dim > + class Ray + { + public: + /** The starting point of the ray */ + Point< Real , Dim > position; - /** The constructor settign the the position and direction of the ray */ - Ray( const Point< Real , Dim > &p , const Point< Real , Dim > &d ) : position(p) , direction(d){} + /** The direction of the ray */ + Point< Real , Dim > direction; - /** This method computes the translation of the ray by p and returns the translated ray.*/ - Ray operator + ( const Point< Real , Dim > &p ) const { return Ray( position+p , direction ); } + /** The default constructor */ + Ray( void ){} - /** This method translates the current ray by p.*/ - Ray &operator += ( const Point< Real , Dim > &p ){ position +=p ; return *this; } + /** The constructor settign the the position and direction of the ray */ + Ray( const Point< Real , Dim > &p , const Point< Real , Dim > &d ) : position(p) , direction(d){} - /** This method computes the translation of the ray by -p and returns the translated ray.*/ - Ray operator - ( const Point< Real , Dim > &p ) const { return Ray( position-p , direction ); } + /** This method computes the translation of the ray by p and returns the translated ray.*/ + Ray operator + ( const Point< Real , Dim > &p ) const { return Ray( position+p , direction ); } - /** This method translates the current ray by -p.*/ - Ray &operator -= ( const Point< Real , Dim > &p ){ position -= p ; return *this; } + /** This method translates the current ray by p.*/ + Ray &operator += ( const Point< Real , Dim > &p ){ position +=p ; return *this; } - /** This method returns the point at a distance of t along the ray. */ - Point< Real , Dim > operator() ( double t ) const { return position + direction * (Real)t; } -}; + /** This method computes the translation of the ray by -p and returns the translated ray.*/ + Ray operator - ( const Point< Real , Dim > &p ) const { return Ray( position-p , direction ); } -/** This function prints out the ray.*/ -template< class Real , unsigned int Dim > -std::ostream &operator << ( std::ostream &stream , const Ray< Real , Dim > &ray ) -{ - stream << "[ " << ray.position << " ] [ " << ray.direction << " ]"; - return stream; -} + /** This method translates the current ray by -p.*/ + Ray &operator -= ( const Point< Real , Dim > &p ){ position -= p ; return *this; } -template< class Real , unsigned int _Columns , unsigned int _Rows > -struct Matrix -{ - static const unsigned int Columns = _Columns; - static const unsigned int Rows = _Rows; - Real coords[Columns][Rows]; - Matrix( void ) { memset( coords , 0 , sizeof(coords) ); } - inline Real& operator() ( unsigned int c , unsigned int r ) { return coords[c][r]; } - inline const Real& operator() ( unsigned int c , unsigned int r ) const { return coords[c][r]; } - inline Real* operator[] ( unsigned int c ) { return coords[c] ; } - inline const Real* operator[] ( unsigned int c ) const { return coords[c] ; } - - inline Matrix operator - ( void ) const { Matrix m ; for( unsigned int c=0 ; c - inline Point< T , Rows > operator* ( const Point< T , Columns >& p ) const { Point< T , Rows > q ; for( unsigned int c=0 ; c - inline Matrix< Real , Cols , Rows > operator * ( const Matrix< Real , Cols , Columns > &M ) const - { - Matrix< Real , Cols , Rows > prod; - for( unsigned int c=0 ; c operator() ( double t ) const { return position + direction * (Real)t; } + }; - inline Matrix< Real , Rows , Columns > transpose( void ) const + /** This function prints out the ray.*/ + template< class Real , unsigned int Dim > + std::ostream &operator << ( std::ostream &stream , const Ray< Real , Dim > &ray ) { - Matrix< Real , Rows , Columns > t; - for( unsigned int c=0 ; c + struct Matrix { - os << "{ "; - for( int r=0 ; r + inline Point< T , Rows > operator* ( const Point< T , Columns >& p ) const { Point< T , Rows > q ; for( unsigned int c=0 ; c + inline Matrix< Real , Cols , Rows > operator * ( const Matrix< Real , Cols , Columns > &M ) const + { + Matrix< Real , Cols , Rows > prod; + for( unsigned int c=0 ; c transpose( void ) const + { + Matrix< Real , Rows , Columns > t; + for( unsigned int c=0 ; c -struct XForm -{ - Real coords[Dim][Dim]; - XForm( void ) { memset( coords , 0 , sizeof(Real) * Dim * Dim ); } - XForm( const Matrix< Real , Dim , Dim > &M ){ memcpy( coords , M.coords , sizeof(Real)*Dim*Dim ); } - XForm( const XForm &M ){ memcpy( coords , M.coords , sizeof(Real)*Dim*Dim ); } - XForm( const Matrix< Real , Dim+1 , Dim+1 > &M ){ for( unsigned int i=0 ; ioperator()(i,j) = M(i,j); } - XForm( const XForm< Real , Dim+1 > &M ){ for( unsigned int i=0 ; ioperator()(i,j) = M(i,j); } - XForm &operator = ( const Matrix< Real , Dim , Dim > &M ){ memcpy( coords , M.coords , sizeof(Real)*Dim*Dim ) ; return *this; } - XForm &operator = ( const XForm< Real , Dim > &M ){ memcpy( coords , M.coords , sizeof(Real)*Dim*Dim ) ; return *this; } - XForm &operator = ( const Matrix< Real , Dim+1 , Dim+1> &M ){ for( unsigned int i=0 ; ioperator()(i,j) = M(i,j) ; return *this; } - XForm &operator = ( const XForm< Real , Dim+1 > &M ){ for( unsigned int i=0 ; ioperator()(i,j) = M(i,j) ; return *this; } - - static XForm Identity( void ) - { - XForm xForm; - for( unsigned int d=0 ; d Point< _Real , Dim-1 > operator * ( const Point< _Real , Dim-1 >& p ) const - { - Point< _Real , Dim-1 > q; - for( unsigned int i=0 ; i + struct XForm + { + Real coords[Dim][Dim]; + XForm( void ) { memset( coords , 0 , sizeof(Real) * Dim * Dim ); } + XForm( const Matrix< Real , Dim , Dim > &M ){ memcpy( coords , M.coords , sizeof(Real)*Dim*Dim ); } + XForm( const XForm &M ){ memcpy( coords , M.coords , sizeof(Real)*Dim*Dim ); } + XForm( const Matrix< Real , Dim+1 , Dim+1 > &M ){ for( unsigned int i=0 ; ioperator()(i,j) = M(i,j); } + XForm( const XForm< Real , Dim+1 > &M ){ for( unsigned int i=0 ; ioperator()(i,j) = M(i,j); } + XForm &operator = ( const Matrix< Real , Dim , Dim > &M ){ memcpy( coords , M.coords , sizeof(Real)*Dim*Dim ) ; return *this; } + XForm &operator = ( const XForm< Real , Dim > &M ){ memcpy( coords , M.coords , sizeof(Real)*Dim*Dim ) ; return *this; } + XForm &operator = ( const Matrix< Real , Dim+1 , Dim+1> &M ){ for( unsigned int i=0 ; ioperator()(i,j) = M(i,j) ; return *this; } + XForm &operator = ( const XForm< Real , Dim+1 > &M ){ for( unsigned int i=0 ; ioperator()(i,j) = M(i,j) ; return *this; } + + static XForm Identity( void ) { - for( unsigned int j=0 ; j Point< _Real , Dim > operator * ( const Point< _Real , Dim >& p ) const - { - Point< _Real , Dim > q; - for( unsigned int i=0 ; i xForm; - unsigned int ii[Dim-1] , jj[Dim-1]; - for( unsigned int a=0 , _i=0 , _j=0 ; a Point< _Real , Dim-1 > operator * ( const Point< _Real , Dim-1 >& p ) const + { + Point< _Real , Dim-1 > q; + for( unsigned int i=0 ; i Point< _Real , Dim > operator * ( const Point< _Real , Dim >& p ) const { - if( a!=i ) ii[_i++] = a; - if( a!=j ) jj[_j++] = a; + Point< _Real , Dim > q; + for( unsigned int i=0 ; i xForm; + unsigned int ii[Dim-1] , jj[Dim-1]; + for( unsigned int a=0 , _i=0 , _j=0 ; a -inline XForm< float , 1 > XForm< float , 1 >::inverse( void ) const -{ - XForm< float , 1 > x; - x.coords[0][0] = (float)(1./coords[0][0] ); - return x; -} -template<> -inline XForm< double , 1 > XForm< double , 1 >::inverse( void ) const -{ - XForm< double , 1 > x; - x.coords[0][0] = (double)(1./coords[0][0] ); - return x; -} -template<> inline float XForm< float , 1 >::determinant( void ) const { return coords[0][0]; } -template<> inline double XForm< double , 1 >::determinant( void ) const { return coords[0][0]; } - -template< class Real , unsigned int Dim > -struct OrientedPoint -{ - Point< Real , Dim > p , n; - OrientedPoint( Point< Real , Dim > pp = Point< Real , Dim >() , Point< Real , Dim > nn=Point< Real , Dim >() ) : p(pp) , n(nn) { ; } - template< class _Real > OrientedPoint( const OrientedPoint< _Real , Dim>& p ) : OrientedPoint( Point< Real , Dim >( p.p ) , Point< Real , Dim >( p.n ) ){ ; } - - template< class _Real > inline OrientedPoint& operator += ( OrientedPoint< _Real , Dim > _p ){ p += _p.p , n += _p.n ; return *this; } - template< class _Real > inline OrientedPoint operator + ( OrientedPoint< _Real , Dim > _p ) const { return OrientedPoint< Real , Dim >( p+_p.p , n+_p.n ); } - template< class _Real > inline OrientedPoint& operator *= ( _Real r ) { p *= r , n *= r ; return *this; } - template< class _Real > inline OrientedPoint operator * ( _Real r ) const { return OrientedPoint< Real , Dim >( p*r , n*r ); } - - template< class _Real > inline OrientedPoint& operator -= ( OrientedPoint< _Real , Dim > p ){ return ( (*this)+=(-p) ); } - template< class _Real > inline OrientedPoint operator - ( OrientedPoint< _Real , Dim > p ) const { return (*this)+(-p); } - template< class _Real > inline OrientedPoint& operator /= ( _Real r ){ return ( (*this)*=Real(1./r) ); } - template< class _Real > inline OrientedPoint operator / ( _Real r ) const { return (*this) * ( Real(1.)/r ); } -}; - - -template< class Data , class Real > -struct ProjectiveData -{ - Data data; - Real weight; - ProjectiveData( Data d=Data() , Real w=(Real)0 ) : data(d) , weight(w) { ; } - operator Data (){ return weight!=0 ? data/weight : data*weight; } - Data value( void ) const { 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< class Real , unsigned int Dim > Point< Real , Dim > RandomBallPoint( void ); -template< class Real , unsigned int Dim > Point< Real , Dim > RandomSpherePoint( void ); -template< class Real , unsigned int Dim > Real Length( Point< Real , Dim > p ){ return (Real)sqrt( Point< Real , Dim >::SquareNorm( p ) ); } -template< class Real , unsigned int Dim > Real SquareLength( Point< Real , Dim > p ){ return Point< Real , Dim >::SquareNorm( p ); } -template< class Real , unsigned int Dim > Real Distance( Point< Real , Dim > p1 , Point< Real , Dim > p2 ){ return Length(p1-p2); } -template< class Real , unsigned int Dim > Real SquareDistance( Point< Real , Dim > p1 , Point< Real , Dim > p2 ){ return SquareLength( p1-p2 ); } -template< class Real > Point< Real , 3 > CrossProduct( Point< Real , 3 > p1 , Point< Real , 3 > p2 ){ return Point< Real , 3 >::CrossProduct( p1 , p2 ); } - -template< class Real , unsigned int Dim > Real SquareArea( Point< Real , Dim > p1 , Point< Real , Dim > p2 , Point< Real , Dim > p3 ) -{ - Point< Real , Dim > v1 = p2-p1 , v2 = p3-p1; - // Area^2 = ( |v1|^2 * |v2|^2 * sin^2( < v1 ,v2 ) ) / 4 - // = ( |v1|^2 * |v2|^2 * ( 1 - cos^2( < v1 ,v2 ) ) ) / 4 - // = ( |v1|^2 * |v2|^2 * ( 1 - < v1 , v2 >^2 / ( |v1|^2 * |v2|^2 ) ) ) / 4 - // = ( |v1|^2 * |v2|^2 - < v1 , v2 >^2 ) / 4 - Real dot = Point< Real , Dim >::Dot( v1 , v2 ); - Real l1 = Point< Real , Dim >::SquareNorm( v1 ) , l2 = Point< Real , Dim >::SquareNorm( v2 ); - return ( l1 * l2 - dot * dot ) / 4; -} -template< class Real , unsigned int Dim > Real Area( Point< Real , Dim > p1 , Point< Real , Dim > p2 , Point< Real , Dim > p3 ){ return (Real)sqrt( SquareArea( p1 , p2 , p3 ) ); } + }; + template<> + inline XForm< float , 1 > XForm< float , 1 >::inverse( void ) const + { + XForm< float , 1 > x; + x.coords[0][0] = (float)(1./coords[0][0] ); + return x; + } + template<> + inline XForm< double , 1 > XForm< double , 1 >::inverse( void ) const + { + XForm< double , 1 > x; + x.coords[0][0] = (double)(1./coords[0][0] ); + return x; + } + template<> inline float XForm< float , 1 >::determinant( void ) const { return coords[0][0]; } + template<> inline double XForm< double , 1 >::determinant( void ) const { return coords[0][0]; } + + template< class Real , unsigned int Dim > + struct OrientedPoint + { + Point< Real , Dim > p , n; + OrientedPoint( Point< Real , Dim > pp = Point< Real , Dim >() , Point< Real , Dim > nn=Point< Real , Dim >() ) : p(pp) , n(nn) { ; } + template< class _Real > OrientedPoint( const OrientedPoint< _Real , Dim>& p ) : OrientedPoint( Point< Real , Dim >( p.p ) , Point< Real , Dim >( p.n ) ){ ; } + + template< class _Real > inline OrientedPoint& operator += ( OrientedPoint< _Real , Dim > _p ){ p += _p.p , n += _p.n ; return *this; } + template< class _Real > inline OrientedPoint operator + ( OrientedPoint< _Real , Dim > _p ) const { return OrientedPoint< Real , Dim >( p+_p.p , n+_p.n ); } + template< class _Real > inline OrientedPoint& operator *= ( _Real r ) { p *= r , n *= r ; return *this; } + template< class _Real > inline OrientedPoint operator * ( _Real r ) const { return OrientedPoint< Real , Dim >( p*r , n*r ); } + + template< class _Real > inline OrientedPoint& operator -= ( OrientedPoint< _Real , Dim > p ){ return ( (*this)+=(-p) ); } + template< class _Real > inline OrientedPoint operator - ( OrientedPoint< _Real , Dim > p ) const { return (*this)+(-p); } + template< class _Real > inline OrientedPoint& operator /= ( _Real r ){ return ( (*this)*=Real(1./r) ); } + template< class _Real > inline OrientedPoint operator / ( _Real r ) const { return (*this) * ( Real(1.)/r ); } + }; + + + template< class Data , class Real > + struct ProjectiveData + { + Data data; + Real weight; + ProjectiveData( Data d=Data() , Real w=(Real)0 ) : data(d) , weight(w) { ; } + operator Data (){ return weight!=0 ? data/weight : data*weight; } + Data value( void ) const { 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< class Real , unsigned int Dim > Point< Real , Dim > RandomBallPoint( void ); + template< class Real , unsigned int Dim > Point< Real , Dim > RandomSpherePoint( void ); + template< class Real , unsigned int Dim > Real Length( Point< Real , Dim > p ){ return (Real)sqrt( Point< Real , Dim >::SquareNorm( p ) ); } + template< class Real , unsigned int Dim > Real SquareLength( Point< Real , Dim > p ){ return Point< Real , Dim >::SquareNorm( p ); } + template< class Real , unsigned int Dim > Real Distance( Point< Real , Dim > p1 , Point< Real , Dim > p2 ){ return Length(p1-p2); } + template< class Real , unsigned int Dim > Real SquareDistance( Point< Real , Dim > p1 , Point< Real , Dim > p2 ){ return SquareLength( p1-p2 ); } + template< class Real > Point< Real , 3 > CrossProduct( Point< Real , 3 > p1 , Point< Real , 3 > p2 ){ return Point< Real , 3 >::CrossProduct( p1 , p2 ); } + + template< class Real , unsigned int Dim > Real SquareArea( Point< Real , Dim > p1 , Point< Real , Dim > p2 , Point< Real , Dim > p3 ) + { + Point< Real , Dim > v1 = p2-p1 , v2 = p3-p1; + // Area^2 = ( |v1|^2 * |v2|^2 * sin^2( < v1 ,v2 ) ) / 4 + // = ( |v1|^2 * |v2|^2 * ( 1 - cos^2( < v1 ,v2 ) ) ) / 4 + // = ( |v1|^2 * |v2|^2 * ( 1 - < v1 , v2 >^2 / ( |v1|^2 * |v2|^2 ) ) ) / 4 + // = ( |v1|^2 * |v2|^2 - < v1 , v2 >^2 ) / 4 + Real dot = Point< Real , Dim >::Dot( v1 , v2 ); + Real l1 = Point< Real , Dim >::SquareNorm( v1 ) , l2 = Point< Real , Dim >::SquareNorm( v2 ); + return ( l1 * l2 - dot * dot ) / 4; + } + template< class Real , unsigned int Dim > Real Area( Point< Real , Dim > p1 , Point< Real , Dim > p2 , Point< Real , Dim > p3 ){ return (Real)sqrt( SquareArea( p1 , p2 , p3 ) ); } + + template< unsigned int K > struct Factorial{ static const unsigned long long Value = Factorial< K-1 >::Value * K; }; + template<> struct Factorial< 0 >{ static const unsigned long long Value = 1; }; + + template< class Real , unsigned int Dim , unsigned int K > + struct Simplex + { + Point< Real , Dim > p[K+1]; + Simplex( void ){ static_assert( K<=Dim , "[ERROR] Bad simplex dimension" ); } + Point< Real , Dim >& operator[]( unsigned int k ){ return p[k]; } + const Point< Real , Dim >& operator[]( unsigned int k ) const { return p[k]; } + Real measure( void ) const { return (Real)sqrt( squareMeasure() ); } + Real squareMeasure( void ) const + { + XForm< Real , K > mass; + for( unsigned int i=1 ; i<=K ; i++ ) for( unsigned int j=1 ; j<=K ; j++ ) mass(i-1,j-1) = Point< Real , Dim >::Dot( p[i]-p[0] , p[j]-p[0] ); + return mass.determinant() / ( Factorial< K >::Value * Factorial< K >::Value ); + } + Point< Real , Dim > center( void ) const + { + Point< Real , Dim > c; + for( unsigned int k=0 ; k<=K ; k++ ) c += p[k]; + return c / (K+1); + } + void split( Point< Real , Dim > pNormal , Real pOffset , std::vector< Simplex >& back , std::vector< Simplex >& front ) const; -template< unsigned int K > struct Factorial{ static const unsigned long long Value = Factorial< K-1 >::Value * K; }; -template<> struct Factorial< 0 >{ static const unsigned long long Value = 1; }; + template< unsigned int _K=K > + typename std::enable_if< _K==Dim-1 , Point< Real , Dim > >::type normal( void ) const + { + static_assert( K==Dim-1 , "[ERROR] Co-dimension is not one" ); + Point< Real , Dim > d[Dim-1]; + for( int k=1 ; k::CrossProduct( d ); + } + template< unsigned int _K=K > + typename std::enable_if< _K==Dim-1 , bool >::type intersect( Ray< Real , Dim > ray , Real &t , Real barycentricCoordinates[Dim] ) const + { + static_assert( K==Dim-1 , "[ERROR] Co-dimension is not one" ); + Point< Real , Dim > n = normal(); + Real denominator = Point< Real , Dim >::Dot( n , ray.direction ); + if( denominator==0 ) return false; + // Solve for t s.t. < ray(t) , n > = < p[0] , n > + t = Point< Real , Dim >::Dot( n , p[0] - ray.position ) / denominator; + Point< Real, Dim > q = ray(t); + + // Let C be the matrix whose columns are the simplex vertices. + // Solve for the barycentric coordinates, b, minimizing: + // E(b) = || C * b - q ||^2 + // = b^t * C^t * C * b - 2 * b^t * C^t * q + || q ||^2 + // Taking the gradient with respect to b gives: + // b = ( C^t * C )^{-1} * C^t * q + Matrix< Real , Dim-1 , Dim > C; + for( int c=0 ; c C_t = C.transpose(); + XForm< Real , Dim-1 > M = C_t * C; + Point< Real , Dim-1 > bc = M.inverse() * ( C_t * ( q - p[0] ) ); + barycentricCoordinates[0] = (Real)1.; + for( unsigned int d=0 ; d -struct Simplex -{ - Point< Real , Dim > p[K+1]; - Simplex( void ){ static_assert( K<=Dim , "[ERROR] Bad simplex dimension" ); } - Point< Real , Dim >& operator[]( unsigned int k ){ return p[k]; } - const Point< Real , Dim >& operator[]( unsigned int k ) const { return p[k]; } - Real measure( void ) const { return (Real)sqrt( squareMeasure() ); } - Real squareMeasure( void ) const - { - XForm< Real , K > mass; - for( unsigned int i=1 ; i<=K ; i++ ) for( unsigned int j=1 ; j<=K ; j++ ) mass(i-1,j-1) = Point< Real , Dim >::Dot( p[i]-p[0] , p[j]-p[0] ); - return mass.determinant() / ( Factorial< K >::Value * Factorial< K >::Value ); - } - Point< Real , Dim > center( void ) const - { - Point< Real , Dim > c; - for( unsigned int k=0 ; k<=K ; k++ ) c += p[k]; - return c / (K+1); - } - void split( Point< Real , Dim > pNormal , Real pOffset , std::vector< Simplex >& back , std::vector< Simplex >& front ) const; + template< unsigned int _K=K > + static typename std::enable_if< _K==Dim-1 , bool >::type IsInterior( Point< Real , Dim > p , const std::vector< Simplex< Real , Dim , Dim-1 > > &simplices ) + { + if( !simplices.size() ) ERROR_OUT( "No simplices provided" ); - template< unsigned int _K=K > - typename std::enable_if< _K==Dim-1 , Point< Real , Dim > >::type normal( void ) const - { - static_assert( K==Dim-1 , "[ERROR] Co-dimension is not one" ); - Point< Real , Dim > d[Dim-1]; - for( int k=1 ; k::CrossProduct( d ); - } - template< unsigned int _K=K > - typename std::enable_if< _K==Dim-1 , bool >::type intersect( Ray< Real , Dim > ray , Real &t , Real barycentricCoordinates[Dim] ) const - { - static_assert( K==Dim-1 , "[ERROR] Co-dimension is not one" ); - Point< Real , Dim > n = normal(); - Real denominator = Point< Real , Dim >::Dot( n , ray.direction ); - if( denominator==0 ) return false; - // Solve for t s.t. < ray(t) , n > = < p[0] , n > - t = Point< Real , Dim >::Dot( n , p[0] - ray.position ) / denominator; - Point< Real, Dim > q = ray(t); - - // Let C be the matrix whose columns are the simplex vertices. - // Solve for the barycentric coordinates, b, minimizing: - // E(b) = || C * b - q ||^2 - // = b^t * C^t * C * b - 2 * b^t * C^t * q + || q ||^2 - // Taking the gradient with respect to b gives: - // b = ( C^t * C )^{-1} * C^t * q - Matrix< Real , Dim-1 , Dim > C; - for( int c=0 ; c C_t = C.transpose(); - XForm< Real , Dim-1 > M = C_t * C; - Point< Real , Dim-1 > bc = M.inverse() * ( C_t * ( q - p[0] ) ); - barycentricCoordinates[0] = (Real)1.; - for( unsigned int d=0 ; dmaxMeasure ) maxMeasure = measure , idx = i; + } + } + Ray< Real , Dim > ray( p , simplices[idx].center() - p ); + Real l = (Real)Point< Real , Dim >::SquareNorm( ray.direction ); + if( !l ) ERROR_OUT( "point is on simplex" ); + l = (Real)sqrt(l); + ray.direction /= l; - template< unsigned int _K=K > - static typename std::enable_if< _K==Dim-1 , bool >::type IsInterior( Point< Real , Dim > p , const std::vector< Simplex< Real , Dim , Dim-1 > > &simplices ) - { - if( !simplices.size() ) ERROR_OUT( "No simplices provided" ); + // Make the assessment based on which side of the simplex the point p is + Real min_t = l; + bool isInside = Point< Real , Dim >::Dot( simplices[idx].normal() , ray.direction )*min_t>0; - // Create a ray that intersecting the largest simplex - int idx; - { - Real maxMeasure = 0; - for( int i=0 ; imaxMeasure ) maxMeasure = measure , idx = i; + Real t , barycentricCoordinates[ Dim ]; + if( simplices[i].intersect( ray , t , barycentricCoordinates ) && t::Dot( simplices[i].normal() , ray.direction )*t>0; } + return isInside; } - Ray< Real , Dim > ray( p , simplices[idx].center() - p ); - Real l = (Real)Point< Real , Dim >::SquareNorm( ray.direction ); - if( !l ) ERROR_OUT( "point is on simplex" ); - l = (Real)sqrt(l); - ray.direction /= l; - - // Make the assessment based on which side of the simplex the point p is - Real min_t = l; - bool isInside = Point< Real , Dim >::Dot( simplices[idx].normal() , ray.direction )*min_t>0; - // Look for intersections with closer simplices - for( size_t i=0 ; i + static typename std::enable_if< _K==Dim-1 , bool >::type IsInterior( Point< Real , Dim > p , const std::vector< Simplex< Real , Dim , Dim-1 > > &simplices , const std::vector< Point< Real , Dim > > &normals ) { - Real t , barycentricCoordinates[ Dim ]; - if( simplices[i].intersect( ray , t , barycentricCoordinates ) && t::Dot( simplices[i].normal() , ray.direction )*t>0; - } - return isInside; - } - - template< unsigned int _K=K > - static typename std::enable_if< _K==Dim-1 , bool >::type IsInterior( Point< Real , Dim > p , const std::vector< Simplex< Real , Dim , Dim-1 > > &simplices , const std::vector< Point< Real , Dim > > &normals ) - { - if( !simplices.size() ) ERROR_OUT( "No simplices provided" ); + if( !simplices.size() ) ERROR_OUT( "No simplices provided" ); #if 0 - // A more conservative approach for ray-tracing, sending a ray for each simplex and using the consensus solution - Real insideMeasure = 0; - for( int idx=0 ; idx ray( p , simplices[idx].center() - p ); + Real l = (Real)Point< Real , Dim >::SquareNorm( ray.direction ); + if( !l ){ WARN( "point is on simplex" ) ; continue; } + l = (Real)sqrt(l); + ray.direction /= l; + + // Make the assessment based on which side of the simplex the point p is + Real min_t = l; + bool isInside = Point< Real , Dim >::Dot( normals[idx] , ray.direction )*min_t>0; + + // Look for intersections with closer simplices + for( size_t i=0 ; i::Dot( normals[i] , ray.direction )*t>0; + } + Real measure = simplices[idx].measure(); + if( isInside ) insideMeasure += measure; + else insideMeasure -= measure; + } + return insideMeasure>0; +#else + // Create a ray that intersecting the largest simplex + int idx; + { + Real maxMeasure = 0; + for( int i=0 ; imaxMeasure ) maxMeasure = measure , idx = i; + } + } Ray< Real , Dim > ray( p , simplices[idx].center() - p ); Real l = (Real)Point< Real , Dim >::SquareNorm( ray.direction ); - if( !l ){ WARN( "point is on simplex" ) ; continue; } + if( !l ) ERROR_OUT( "point is on simplex" ); l = (Real)sqrt(l); ray.direction /= l; @@ -687,181 +722,150 @@ struct Simplex for( size_t i=0 ; i::Dot( normals[i] , ray.direction )*t>0; - } - Real measure = simplices[idx].measure(); - if( isInside ) insideMeasure += measure; - else insideMeasure -= measure; - } - return insideMeasure>0; -#else - // Create a ray that intersecting the largest simplex - int idx; - { - Real maxMeasure = 0; - for( int i=0 ; imaxMeasure ) maxMeasure = measure , idx = i; + if( simplices[i].intersect( ray , t , barycentricCoordinates ) && t::Dot( normals[i] , ray.direction )*t>0; } + return isInside; +#endif } - Ray< Real , Dim > ray( p , simplices[idx].center() - p ); - Real l = (Real)Point< Real , Dim >::SquareNorm( ray.direction ); - if( !l ) ERROR_OUT( "point is on simplex" ); - l = (Real)sqrt(l); - ray.direction /= l; + }; - // Make the assessment based on which side of the simplex the point p is - Real min_t = l; - bool isInside = Point< Real , Dim >::Dot( normals[idx] , ray.direction )*min_t>0; - // Look for intersections with closer simplices - for( size_t i=0 ; i + struct Simplex< Real , Dim , 0 > + { + static const unsigned int K=0; + Point< Real , Dim > p[1]; + Point< Real , Dim >& operator[]( unsigned int k ){ return p[k]; } + const Point< Real , Dim >& operator[]( unsigned int k ) const { return p[k]; } + Real squareMeasure( void ) const { return (Real)1.; } + Real measure( void ) const { return (Real)1.; } + Point< Real , Dim > center( void ) const { return p[0]; } + void split( Point< Real , Dim > pNormal , Real pOffset , std::vector< Simplex >& back , std::vector< Simplex >& front ) const { - Real t , barycentricCoordinates[ Dim ]; - if( simplices[i].intersect( ray , t , barycentricCoordinates ) && t::Dot( normals[i] , ray.direction )*t>0; + if( Point< Real , Dim >::Dot( p[0] , pNormal ) < pOffset ) back.push_back( *this ); + else front.push_back( *this ); } - return isInside; -#endif - } -}; + template< unsigned int _K=K > + typename std::enable_if< _K==Dim-1 , bool >::type intersect( Ray< Real , Dim > ray , Real &t , Real barycentricCoordinates[Dim] ) const + { + static_assert( K==Dim-1 , "[ERROR] Co-dimension is not one" ); + if( !ray.direction[0] ) return false; + // Solve for t s.t. ray(t) = p[0] + t = ( p[0][0] - ray.position[0] ) / ray.direction[0]; + barycentricCoordinates[0] = (Real)1.; + return true; + } + + template< unsigned int _K=0 > + static typename std::enable_if< _K==Dim-1 , bool >::type IsInterior( Point< Real , Dim > p , const std::vector< Simplex< Real , Dim , Dim-1 > > &simplices , const std::vector< Point< Real , Dim > > &normals ) + { + if( !simplices.size() ) ERROR_OUT( "No simplices provided" ); + Ray< Real , Dim > ray( p , simplices[0].center() - p ); + Real l = (Real)Point< Real , Dim >::SquareNorm( ray.direction ); + if( !l ) ERROR_OUT( "point is on simplex" ); + l = (Real)sqrt(l); + ray.direction /= l; -template< class Real , unsigned int Dim > -struct Simplex< Real , Dim , 0 > -{ - static const unsigned int K=0; - Point< Real , Dim > p[1]; - Point< Real , Dim >& operator[]( unsigned int k ){ return p[k]; } - const Point< Real , Dim >& operator[]( unsigned int k ) const { return p[k]; } - Real squareMeasure( void ) const { return (Real)1.; } - Real measure( void ) const { return (Real)1.; } - Point< Real , Dim > center( void ) const { return p[0]; } - void split( Point< Real , Dim > pNormal , Real pOffset , std::vector< Simplex >& back , std::vector< Simplex >& front ) const - { - if( Point< Real , Dim >::Dot( p[0] , pNormal ) < pOffset ) back.push_back( *this ); - else front.push_back( *this ); - } - template< unsigned int _K=K > - typename std::enable_if< _K==Dim-1 , bool >::type intersect( Ray< Real , Dim > ray , Real &t , Real barycentricCoordinates[Dim] ) const - { - static_assert( K==Dim-1 , "[ERROR] Co-dimension is not one" ); - if( !ray.direction[0] ) return false; - // Solve for t s.t. ray(t) = p[0] - t = ( p[0][0] - ray.position[0] ) / ray.direction[0]; - barycentricCoordinates[0] = (Real)1.; - return true; - } + // Make the assessment based on which side of the simplex the point p is + Real min_t = l; + bool isInside = Point< Real , Dim >::Dot( normals[0] , ray.direction )*min_t>0; - template< unsigned int _K=0 > - static typename std::enable_if< _K==Dim-1 , bool >::type IsInterior( Point< Real , Dim > p , const std::vector< Simplex< Real , Dim , Dim-1 > > &simplices , const std::vector< Point< Real , Dim > > &normals ) + // Look for intersections with closer simplices + for( size_t i=0 ; i::Dot( normals[i] , ray.direction )*t>0; + } + return isInside; + } + }; + template< typename Real , unsigned int Dim , unsigned int K > + std::ostream &operator << ( std::ostream &os , const Simplex< Real , Dim , K > &s ) { - if( !simplices.size() ) ERROR_OUT( "No simplices provided" ); + for( unsigned int k=0 ; k ray( p , simplices[0].center() - p ); - Real l = (Real)Point< Real , Dim >::SquareNorm( ray.direction ); - if( !l ) ERROR_OUT( "point is on simplex" ); - l = (Real)sqrt(l); - ray.direction /= l; - // Make the assessment based on which side of the simplex the point p is - Real min_t = l; - bool isInside = Point< Real , Dim >::Dot( normals[0] , ray.direction )*min_t>0; + template< class Real , unsigned int Dim > using Edge = Simplex< Real , Dim , 1 >; + template< class Real , unsigned int Dim > using Triangle = Simplex< Real , Dim , 2 >; - // Look for intersections with closer simplices - for( size_t i=0 ; i + struct SimplexIndex + { + Index idx[K+1]; + template< class ... Ints > + SimplexIndex( Ints ... values ){ static_assert( sizeof...(values)==K+1 || sizeof...(values)==0 , "[ERROR] Invalid number of coefficients" ) ; _init( 0 , values ... ); } + Index &operator[] ( unsigned int i ) { return idx[i] ;} + const Index &operator[] ( unsigned int i ) const { return idx[i]; } + protected: + void _init( unsigned int k ) { - Real t , barycentricCoordinates[ Dim ]; - if( simplices[i].intersect( ray , t , barycentricCoordinates ) && t::Dot( normals[i] , ray.direction )*t>0; + if( !k ) memset( idx , 0 , sizeof(idx) ); + else ERROR_OUT( "Should never be called" ); + } + template< class ... Ints > void _init( unsigned int k , Index v , Ints ... values ) + { + idx[k] = v; + if( k using EdgeIndex = SimplexIndex< 1 , Index >; + template< typename Index > using TriangleIndex = SimplexIndex< 2 , Index >; + + template< typename Real , unsigned int Dim , unsigned int K > + struct SimplicialComplex + { + SimplicialComplex( const std::vector< Simplex< Real , Dim , K > > &simplices ) : _simplices( simplices ){} + virtual size_t size( void ) const { return _simplices.size(); } + virtual Simplex< Real , Dim , K > operator[]( size_t idx ) const { return _simplices[idx]; } + protected: + SimplicialComplex( void ) :_simplices(__simplices) {} + const std::vector< Simplex< Real , Dim , K > > &_simplices; + const std::vector< Simplex< Real , Dim , K > > __simplices; + }; + + template< typename Real , unsigned int Dim , unsigned int K , typename IndexType > + struct IndexedSimplicialComplex : public SimplicialComplex< Real , Dim , K > + { + IndexedSimplicialComplex( const std::vector< Point< Real , Dim > > &vertices , const std::vector< SimplexIndex< K , IndexType > > &simplices ) : _vertices(vertices) , _simplices(simplices){} + IndexedSimplicialComplex( IndexedSimplicialComplex && isc ) + { + std::swap( _vertices , isc._vertices ); + std::swap( _simplices , isc._simplices ); } - return isInside; - } -}; -template< typename Real , unsigned int Dim , unsigned int K > -std::ostream &operator << ( std::ostream &os , const Simplex< Real , Dim , K > &s ) -{ - for( unsigned int k=0 ; k operator[]( size_t idx ) const + { + Simplex< Real , Dim , K > s; + for( unsigned int k=0 ; k<=K ; k++ ) s[k] = _vertices[ _simplices[idx][k] ]; + return s; + } + protected: + const std::vector< Point< Real , Dim > > &_vertices; + const std::vector< SimplexIndex< K , IndexType > > &_simplices; + }; -template< class Real , unsigned int Dim > using Edge = Simplex< Real , Dim , 1 >; -template< class Real , unsigned int Dim > using Triangle = Simplex< Real , Dim , 2 >; -template< unsigned int K , typename Index > -struct SimplexIndex -{ - Index idx[K+1]; - template< class ... Ints > - SimplexIndex( Ints ... values ){ static_assert( sizeof...(values)==K+1 || sizeof...(values)==0 , "[ERROR] Invalid number of coefficients" ) ; _init( 0 , values ... ); } - Index &operator[] ( unsigned int i ) { return idx[i] ;} - const Index &operator[] ( unsigned int i ) const { return idx[i]; } -protected: - void _init( unsigned int k ) + template< typename Index > + class TriangulationEdge { - if( !k ) memset( idx , 0 , sizeof(idx) ); - else ERROR_OUT( "Should never be called" ); - } - template< class ... Ints > void _init( unsigned int k , Index v , Ints ... values ) - { - idx[k] = v; - if( k using EdgeIndex = SimplexIndex< 1 , Index >; -template< typename Index > using TriangleIndex = SimplexIndex< 2 , Index >; - -template< typename Real , unsigned int Dim , unsigned int K > -struct SimplicialComplex -{ - SimplicialComplex( const std::vector< Simplex< Real , Dim , K > > &simplices ) : _simplices( simplices ){} - virtual size_t size( void ) const { return _simplices.size(); } - virtual Simplex< Real , Dim , K > operator[]( size_t idx ) const { return _simplices[idx]; } -protected: - SimplicialComplex( void ) :_simplices(__simplices) {} - const std::vector< Simplex< Real , Dim , K > > &_simplices; - const std::vector< Simplex< Real , Dim , K > > __simplices; -}; - -template< typename Real , unsigned int Dim , unsigned int K , typename IndexType > -struct IndexedSimplicialComplex : public SimplicialComplex< Real , Dim , K > -{ - IndexedSimplicialComplex( const std::vector< Point< Real , Dim > > &vertices , const std::vector< SimplexIndex< K , IndexType > > &simplices ) : _vertices(vertices) , _simplices(simplices){} - IndexedSimplicialComplex( IndexedSimplicialComplex && isc ) - { - std::swap( _vertices , isc._vertices ); - std::swap( _simplices , isc._simplices ); - } + public: + TriangulationEdge( void ){ pIndex[0] = pIndex[1] = tIndex[0] = tIndex[1] = -1; } + Index pIndex[2] , tIndex[2]; + }; - size_t size( void ) const { return _simplices.size(); } - Simplex< Real , Dim , K > operator[]( size_t idx ) const + template< typename Index > + class TriangulationTriangle { - Simplex< Real , Dim , K > s; - for( unsigned int k=0 ; k<=K ; k++ ) s[k] = _vertices[ _simplices[idx][k] ]; - return s; - } -protected: - const std::vector< Point< Real , Dim > > &_vertices; - const std::vector< SimplexIndex< K , IndexType > > &_simplices; -}; - - -template< typename Index > -class TriangulationEdge -{ -public: - TriangulationEdge( void ){ pIndex[0] = pIndex[1] = tIndex[0] = tIndex[1] = -1; } - Index pIndex[2] , tIndex[2]; -}; - -template< typename Index > -class TriangulationTriangle -{ -public: - TriangulationTriangle( void ){ eIndex[0] = eIndex[1] = eIndex[2] = -1; } - Index eIndex[3]; -}; + public: + TriangulationTriangle( void ){ eIndex[0] = eIndex[1] = eIndex[2] = -1; } + Index eIndex[3]; + }; #include "Geometry.inl" +} #endif // GEOMETRY_INCLUDED diff --git a/Src/Geometry.inl b/Src/Geometry.inl index b9965d19..f20259c1 100644 --- a/Src/Geometry.inl +++ b/Src/Geometry.inl @@ -26,9 +26,6 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ -#include -#include "MyMiscellany.h" - template< class Real > Real Random( void ){ return Real( rand() )/Real( RAND_MAX ); } template< class Real , int Dim > diff --git a/Src/Image.h b/Src/Image.h index 7da47a16..460d64a0 100644 --- a/Src/Image.h +++ b/Src/Image.h @@ -34,436 +34,443 @@ DAMAGE. #include #include "MyMiscellany.h" -struct ImageReader +namespace PoissonRecon { - virtual unsigned int nextRow( unsigned char* row ) = 0; - static unsigned char* Read( const char* fileName , unsigned int& width , unsigned int& height , unsigned int& channels ) - { - ImageReader* reader = Get( fileName ); - width = reader->width() , height = reader->height() , channels = reader->channels(); - unsigned char* pixels = new unsigned char[ width*height*channels ]; - for( unsigned int j=0 ; jnextRow( pixels + j*width*channels ); - delete reader; - return pixels; - } - static unsigned char* ReadColor( const char* fileName , unsigned int& width , unsigned int& height ) + + struct ImageReader { - unsigned int channels; - ImageReader* reader = Get( fileName ); - width = reader->width() , height = reader->height() , channels = reader->channels(); - if( channels!=1 && channels!=3 ) ERROR_OUT( "Requres one- or three-channel input" ); - unsigned char* pixels = new unsigned char[ width*height*3 ]; - unsigned char* pixelRow = new unsigned char[ width*channels]; - for( unsigned int j=0 ; jnextRow( pixelRow ); - if ( channels==3 ) memcpy( pixels+j*width*3 , pixelRow , sizeof(unsigned char)*width*3 ); - else if( channels==1 ) for( unsigned int i=0 ; iwidth() , height = reader->height() , channels = reader->channels(); + unsigned char* pixels = new unsigned char[ width*height*channels ]; + for( unsigned int j=0 ; jnextRow( pixels + j*width*channels ); + delete reader; + return pixels; + } + static unsigned char* ReadColor( const char* fileName , unsigned int& width , unsigned int& height ) + { + unsigned int channels; + ImageReader* reader = Get( fileName ); + width = reader->width() , height = reader->height() , channels = reader->channels(); + if( channels!=1 && channels!=3 ) ERROR_OUT( "Requres one- or three-channel input" ); + unsigned char* pixels = new unsigned char[ width*height*3 ]; + unsigned char* pixelRow = new unsigned char[ width*channels]; + for( unsigned int j=0 ; jnextRow( pixelRow ); + if ( channels==3 ) memcpy( pixels+j*width*3 , pixelRow , sizeof(unsigned char)*width*3 ); + else if( channels==1 ) for( unsigned int i=0 ; inextRow( pixels + j*width*channels ); - delete writer; - } + virtual unsigned int nextRow( const unsigned char* row ) = 0; + virtual unsigned int nextRows( const unsigned char* rows , unsigned int rowNum ){ unsigned int row ; for( unsigned int r=0 ; rnextRow( pixels + j*width*channels ); + delete writer; + } - static bool ValidExtension( const char *ext ); - static ImageWriter* Get( const char* fileName , unsigned int width , unsigned int height , unsigned int channels , ImageWriterParams params=ImageWriterParams() ); - virtual ~ImageWriter( void ){ } - unsigned int width( void ) const { return _width; } - unsigned int height( void ) const { return _height; } - unsigned int channels( void ) const { return _channels; } -protected: - unsigned int _width , _height , _channels; -}; + static bool ValidExtension( const char *ext ); + static ImageWriter* Get( const char* fileName , unsigned int width , unsigned int height , unsigned int channels , ImageWriterParams params=ImageWriterParams() ); + virtual ~ImageWriter( void ){ } + unsigned int width( void ) const { return _width; } + unsigned int height( void ) const { return _height; } + unsigned int channels( void ) const { return _channels; } + protected: + unsigned int _width , _height , _channels; + }; #ifdef SUPPORT_TILES -struct TiledImageReader : public ImageReader -{ - unsigned int nextRow( unsigned char* row ); - TiledImageReader( const char* fileName , unsigned int& width , unsigned int& height , unsigned int& channels ); - ~TiledImageReader( void ); - static bool GetInfo( const char* fileName , unsigned int& width , unsigned int& height , unsigned int& channels ); -protected: - ImageReader** _tileReaders; - char** _tileNames; - unsigned int _tileRows , _tileColumns , _currentPixelRow , _currentTileRow , *_tileWidths , *_tileHeights; -}; -struct TiledImageWriter : public ImageWriter -{ - unsigned int nextRow( const unsigned char* row ); - TiledImageWriter( const char* fileName , unsigned int width , unsigned int height , unsigned int channels , ImageWriterParams params ); - ~TiledImageWriter( void ); -protected: - ImageWriter** _tileWriters; - char** _tileNames; - unsigned int _tileWidth , _tileHeight , _tileRows , _tileColumns , _currentPixelRow; - ImageWriterParams _params; -}; + struct TiledImageReader : public ImageReader + { + unsigned int nextRow( unsigned char* row ); + TiledImageReader( const char* fileName , unsigned int& width , unsigned int& height , unsigned int& channels ); + ~TiledImageReader( void ); + static bool GetInfo( const char* fileName , unsigned int& width , unsigned int& height , unsigned int& channels ); + protected: + ImageReader** _tileReaders; + char** _tileNames; + unsigned int _tileRows , _tileColumns , _currentPixelRow , _currentTileRow , *_tileWidths , *_tileHeights; + }; + struct TiledImageWriter : public ImageWriter + { + unsigned int nextRow( const unsigned char* row ); + TiledImageWriter( const char* fileName , unsigned int width , unsigned int height , unsigned int channels , ImageWriterParams params ); + ~TiledImageWriter( void ); + protected: + ImageWriter** _tileWriters; + char** _tileNames; + unsigned int _tileWidth , _tileHeight , _tileRows , _tileColumns , _currentPixelRow; + ImageWriterParams _params; + }; #endif // SUPPORT_TILES +} // [WARNING] Need to include "png.h" before "jpeg.h" so that "setjmp.h" is not already included (?) #include "PNG.h" #include "JPEG.h" -struct FileNameParser +namespace PoissonRecon { + struct FileNameParser + { #if defined( _WIN32 ) || defined( _WIN64 ) - static const char Separator = (char)'\\'; + static const char Separator = (char)'\\'; #else // !_WIN - static const char Separator = (char)'/'; + static const char Separator = (char)'/'; #endif // _WIN - static inline char* Extension ( const char* fileName ){ return __Split( fileName , '.' , false , false ); } - static inline char* Header ( const char* fileName ){ return __Split( fileName , '.' , true , false ); } - static inline char* Local ( const char* fileName ){ return __Split( fileName , Separator , false , false ); } - static inline char* Dir ( const char* fileName ){ return __Split( fileName , Separator , true , false ); } - static inline char* LocalHeader( const char* fileName ) - { - char* localFileName = Local( fileName ); - if( !localFileName ) ERROR_OUT( "Couldn't get local file name: " , fileName ); - char* localFileHeader = Header( localFileName ); - delete[] localFileName; - return localFileHeader; - } - -protected: - static inline char* __Split( const char* fileName , char splitChar , bool front , bool first ) - { - int position; - char* out; - if( first ){ for( position=0 ; position=0 ; position-- ) if( fileName[position]==splitChar ) break; } + static inline char* Extension ( const char* fileName ){ return __Split( fileName , '.' , false , false ); } + static inline char* Header ( const char* fileName ){ return __Split( fileName , '.' , true , false ); } + static inline char* Local ( const char* fileName ){ return __Split( fileName , Separator , false , false ); } + static inline char* Dir ( const char* fileName ){ return __Split( fileName , Separator , true , false ); } + static inline char* LocalHeader( const char* fileName ) + { + char* localFileName = Local( fileName ); + if( !localFileName ) ERROR_OUT( "Couldn't get local file name: " , fileName ); + char* localFileHeader = Header( localFileName ); + delete[] localFileName; + return localFileHeader; + } - if( front ) + protected: + static inline char* __Split( const char* fileName , char splitChar , bool front , bool first ) { - if( position==-1 ) out = NULL; - else + int position; + char* out; + if( first ){ for( position=0 ; position=0 ; position-- ) if( fileName[position]==splitChar ) break; } + + if( front ) { - out = new char[ strlen(fileName)+1 ]; - strcpy( out , fileName ); - out[ position ] = 0; + if( position==-1 ) out = NULL; + else + { + out = new char[ strlen(fileName)+1 ]; + strcpy( out , fileName ); + out[ position ] = 0; + } } - } - else - { - if( position==strlen(fileName) ) out = NULL; else { - out = new char[ strlen(fileName)-position ]; - strcpy( out , fileName+position+1 ); + if( position==strlen(fileName) ) out = NULL; + else + { + out = new char[ strlen(fileName)-position ]; + strcpy( out , fileName+position+1 ); + } } + return out; } - return out; - } -}; + }; -inline bool ImageReader::ValidExtension( const char *ext ) -{ + inline bool ImageReader::ValidExtension( const char *ext ) + { #ifdef WIN32 - if ( !_stricmp( ext , "jpeg" ) || !_stricmp( ext , "jpg" ) ) return true; - else if( !_stricmp( ext , "png" ) ) return true; - else if( !_stricmp( ext , "iGrid" ) ) return true; + if ( !_stricmp( ext , "jpeg" ) || !_stricmp( ext , "jpg" ) ) return true; + else if( !_stricmp( ext , "png" ) ) return true; + else if( !_stricmp( ext , "iGrid" ) ) return true; #else // !WIN32 - if( !strcasecmp( ext , "jpeg" ) || !strcasecmp( ext , "jpg" ) ) return true; - else if( !strcasecmp( ext , "png" ) ) return true; - else if( !strcasecmp( ext , "iGrid" ) ) return true; + if( !strcasecmp( ext , "jpeg" ) || !strcasecmp( ext , "jpg" ) ) return true; + else if( !strcasecmp( ext , "png" ) ) return true; + else if( !strcasecmp( ext , "iGrid" ) ) return true; #endif // WIN32 - return false; -} + return false; + } -inline ImageReader* ImageReader::Get( const char* fileName ) -{ - unsigned int width , height , channels; - ImageReader* reader = NULL; - char* ext = FileNameParser::Extension( fileName ); + inline ImageReader* ImageReader::Get( const char* fileName ) + { + unsigned int width , height , channels; + ImageReader* reader = NULL; + char* ext = FileNameParser::Extension( fileName ); #ifdef WIN32 - if ( !_stricmp( ext , "jpeg" ) || !_stricmp( ext , "jpg" ) ) reader = new JPEGReader( fileName , width , height , channels ); - else if( !_stricmp( ext , "png" ) ) reader = new PNGReader( fileName , width , height , channels ); - else if( !_stricmp( ext , "iGrid" ) ) reader = new TiledImageReader( fileName , width , height , channels ); + if ( !_stricmp( ext , "jpeg" ) || !_stricmp( ext , "jpg" ) ) reader = new JPEGReader( fileName , width , height , channels ); + else if( !_stricmp( ext , "png" ) ) reader = new PNGReader( fileName , width , height , channels ); + else if( !_stricmp( ext , "iGrid" ) ) reader = new TiledImageReader( fileName , width , height , channels ); #else // !WIN32 - if( !strcasecmp( ext , "jpeg" ) || !strcasecmp( ext , "jpg" ) ) reader = new JPEGReader( fileName , width , height , channels ); - else if( !strcasecmp( ext , "png" ) ) reader = new PNGReader( fileName , width , height , channels ); - else if( !strcasecmp( ext , "iGrid" ) ) reader = new TiledImageReader( fileName , width , height , channels ); + if( !strcasecmp( ext , "jpeg" ) || !strcasecmp( ext , "jpg" ) ) reader = new JPEGReader( fileName , width , height , channels ); + else if( !strcasecmp( ext , "png" ) ) reader = new PNGReader( fileName , width , height , channels ); + else if( !strcasecmp( ext , "iGrid" ) ) reader = new TiledImageReader( fileName , width , height , channels ); #endif // WIN32 - else - { + else + { + delete[] ext; + THROW( "failed to get image reader for: " , fileName ); + } + reader->_width = width; + reader->_height = height; + reader->_channels = channels; + delete[] ext; - THROW( "failed to get image reader for: " , fileName ); + return reader; } - reader->_width = width; - reader->_height = height; - reader->_channels = channels; - - delete[] ext; - return reader; -} -inline void ImageReader::GetInfo( const char* fileName , unsigned int& width , unsigned int& height , unsigned int& channels ) -{ - char* ext = FileNameParser::Extension( fileName ); + inline void ImageReader::GetInfo( const char* fileName , unsigned int& width , unsigned int& height , unsigned int& channels ) + { + char* ext = FileNameParser::Extension( fileName ); #ifdef WIN32 - if( !_stricmp( ext , "jpeg" ) || !_stricmp( ext , "jpg" ) ) JPEGReader::GetInfo( fileName , width , height , channels ); - else if( !_stricmp( ext , "png" ) ) PNGReader::GetInfo( fileName , width , height , channels ); - else if( !_stricmp( ext , "iGrid" ) ) TiledImageReader::GetInfo( fileName , width , height , channels ); + if( !_stricmp( ext , "jpeg" ) || !_stricmp( ext , "jpg" ) ) JPEGReader::GetInfo( fileName , width , height , channels ); + else if( !_stricmp( ext , "png" ) ) PNGReader::GetInfo( fileName , width , height , channels ); + else if( !_stricmp( ext , "iGrid" ) ) TiledImageReader::GetInfo( fileName , width , height , channels ); #else // !WIN32 - if( !strcasecmp( ext , "jpeg" ) || !strcasecmp( ext , "jpg" ) ) JPEGReader::GetInfo( fileName , width , height , channels ); - else if( !strcasecmp( ext , "png" ) ) PNGReader::GetInfo( fileName , width , height , channels ); - else if( !strcasecmp( ext , "iGrid" ) ) TiledImageReader::GetInfo( fileName , width , height , channels ); + if( !strcasecmp( ext , "jpeg" ) || !strcasecmp( ext , "jpg" ) ) JPEGReader::GetInfo( fileName , width , height , channels ); + else if( !strcasecmp( ext , "png" ) ) PNGReader::GetInfo( fileName , width , height , channels ); + else if( !strcasecmp( ext , "iGrid" ) ) TiledImageReader::GetInfo( fileName , width , height , channels ); #endif // WIN32 - delete[] ext; -} + delete[] ext; + } -inline bool ImageWriter::ValidExtension( const char *ext ) -{ + inline bool ImageWriter::ValidExtension( const char *ext ) + { #ifdef WIN32 - if( !_stricmp( ext , "jpeg" ) || !_stricmp( ext , "jpg" ) ) return true; - else if( !_stricmp( ext , "png" ) ) return true; + if( !_stricmp( ext , "jpeg" ) || !_stricmp( ext , "jpg" ) ) return true; + else if( !_stricmp( ext , "png" ) ) return true; #ifdef SUPPORT_TILES - else if( !_stricmp( ext , "iGrid" ) ) return true; + else if( !_stricmp( ext , "iGrid" ) ) return true; #endif // SUPPORT_TILES #else // !WIN32 - if( !strcasecmp( ext , "jpeg" ) || !strcasecmp( ext , "jpg" ) ) return true; - else if( !strcasecmp( ext , "png" ) ) return true; + if( !strcasecmp( ext , "jpeg" ) || !strcasecmp( ext , "jpg" ) ) return true; + else if( !strcasecmp( ext , "png" ) ) return true; #ifdef SUPPORT_TILES - else if( !strcasecmp( ext , "iGrid" ) ) return true; + else if( !strcasecmp( ext , "iGrid" ) ) return true; #endif // SUPPORT_TILES #endif // WIN32 - return false; -} + return false; + } -inline ImageWriter* ImageWriter::Get( const char* fileName , unsigned int width , unsigned int height , unsigned int channels , ImageWriterParams params ) -{ - ImageWriter* writer = NULL; - char* ext = FileNameParser::Extension( fileName ); + inline ImageWriter* ImageWriter::Get( const char* fileName , unsigned int width , unsigned int height , unsigned int channels , ImageWriterParams params ) + { + ImageWriter* writer = NULL; + char* ext = FileNameParser::Extension( fileName ); #ifdef WIN32 - if( !_stricmp( ext , "jpeg" ) || !_stricmp( ext , "jpg" ) ) writer = new JPEGWriter( fileName , width , height , channels , params.quality ); - else if( !_stricmp( ext , "png" ) ) writer = new PNGWriter( fileName , width , height , channels , params.quality ); + if( !_stricmp( ext , "jpeg" ) || !_stricmp( ext , "jpg" ) ) writer = new JPEGWriter( fileName , width , height , channels , params.quality ); + else if( !_stricmp( ext , "png" ) ) writer = new PNGWriter( fileName , width , height , channels , params.quality ); #ifdef SUPPORT_TILES - else if( !_stricmp( ext , "iGrid" ) ) writer = new TiledImageWriter( fileName , width , height , channels , params ); + else if( !_stricmp( ext , "iGrid" ) ) writer = new TiledImageWriter( fileName , width , height , channels , params ); #endif // SUPPORT_TILES #else // !WIN32 - if( !strcasecmp( ext , "jpeg" ) || !strcasecmp( ext , "jpg" ) ) writer = new JPEGWriter( fileName , width , height , channels , params.quality ); - else if( !strcasecmp( ext , "png" ) ) writer = new PNGWriter( fileName , width , height , channels , params.quality ); + if( !strcasecmp( ext , "jpeg" ) || !strcasecmp( ext , "jpg" ) ) writer = new JPEGWriter( fileName , width , height , channels , params.quality ); + else if( !strcasecmp( ext , "png" ) ) writer = new PNGWriter( fileName , width , height , channels , params.quality ); #ifdef SUPPORT_TILES - else if( !strcasecmp( ext , "iGrid" ) ) writer = new TiledImageWriter( fileName , width , height , channels , params ); + else if( !strcasecmp( ext , "iGrid" ) ) writer = new TiledImageWriter( fileName , width , height , channels , params ); #endif // SUPPORT_TILES #endif // WIN32 - else - { + else + { + delete[] ext; + THROW( "failed to get image writer for: " , fileName ); + } + writer->_width = width; + writer->_height = height; + writer->_channels = channels; + delete[] ext; - THROW( "failed to get image writer for: " , fileName ); + return writer; } - writer->_width = width; - writer->_height = height; - writer->_channels = channels; - - delete[] ext; - return writer; -} #ifdef SUPPORT_TILES -bool TiledImageReader::GetInfo( const char* fileName , unsigned int& width , unsigned int& height , unsigned int& channels ) -{ - char* fileDir = FileNameParser::Dir( fileName ); - unsigned int *_tileHeights , *_tileWidths; - unsigned int _tileRows , _tileColumns , _channels; - FILE* fp = fopen( fileName , "r" ); - if( !fp ){ WARN( "Couldn't open file for reading: " , fileName ) ; return false; } + bool TiledImageReader::GetInfo( const char* fileName , unsigned int& width , unsigned int& height , unsigned int& channels ) { - char line[1024]; - if( !fgets( line , 1024 , fp ) ) ERROR_OUT( "Failed to read column line from: " , fileName ); - line[strlen(line)-1] = 0; - if( sscanf( line , "Columns: %d" , &_tileColumns )!=1 ) ERROR_OUT( "Failed to read column count from: " , fileName , " (" , line , ")" ); - if( !fgets( line , 1024 , fp ) ) ERROR_OUT( "Failed to read row line from: " , fileName ); - line[strlen(line)-1] = 0; - if( sscanf( line , "Rows: %d" , &_tileRows )!=1 ) ERROR_OUT( "Failed to read row count from: " , fileName , " (" , line , ")" ); - _tileHeights = new unsigned int[ _tileRows+1 ]; - _tileWidths = new unsigned int[ _tileColumns+1 ]; - - char tileName[2048]; - for( unsigned int r=0 ; r<_tileRows ; r++ ) for( unsigned int c=0 ; c<_tileColumns ; c++ ) + char* fileDir = FileNameParser::Dir( fileName ); + unsigned int *_tileHeights , *_tileWidths; + unsigned int _tileRows , _tileColumns , _channels; + FILE* fp = fopen( fileName , "r" ); + if( !fp ){ WARN( "Couldn't open file for reading: " , fileName ) ; return false; } + { + char line[1024]; + if( !fgets( line , 1024 , fp ) ) ERROR_OUT( "Failed to read column line from: " , fileName ); + line[strlen(line)-1] = 0; + if( sscanf( line , "Columns: %d" , &_tileColumns )!=1 ) ERROR_OUT( "Failed to read column count from: " , fileName , " (" , line , ")" ); + if( !fgets( line , 1024 , fp ) ) ERROR_OUT( "Failed to read row line from: " , fileName ); + line[strlen(line)-1] = 0; + if( sscanf( line , "Rows: %d" , &_tileRows )!=1 ) ERROR_OUT( "Failed to read row count from: " , fileName , " (" , line , ")" ); + _tileHeights = new unsigned int[ _tileRows+1 ]; + _tileWidths = new unsigned int[ _tileColumns+1 ]; + + char tileName[2048]; + for( unsigned int r=0 ; r<_tileRows ; r++ ) for( unsigned int c=0 ; c<_tileColumns ; c++ ) + { + if( !fgets( line , 1024 , fp ) ) ERROR_OUT( "Failed to read tile name from: " , fileName ); + line[strlen(line)-1] = 0; + if( fileDir ) sprintf( tileName , "%s%c%s" , fileDir , FileNameParser::Separator , line ); + else sprintf( tileName , "%s" , line ); + + unsigned int _w , _h , _c; + ImageReader::GetInfo( tileName , _w , _h , _c ); + if( !r && !c ) _channels = _c; + else if( _channels!=_c ) ERROR_OUT( "Number of color channels don't match: " , _channels , " != " , _c ); + if( !r ) _tileWidths[c+1] = _w; + else if( _tileWidths[c+1]!=_w ) ERROR_OUT( "Images in the same column must have the same width: " , _tileWidths[c+1] , " != " , _w ); + if( !c ) _tileHeights[r+1] = _h; + else if( _tileHeights[r+1]!=_h ) ERROR_OUT( "Images in the same row must have the same heights: " , _tileHeights[r+1] ," != " , _h ); + } + } + fclose( fp ); + if( fileDir ) delete[] fileDir; + _tileWidths[0] = _tileHeights[0] = 0; + for( unsigned int c=0 ; c<_tileColumns ; c++ ) _tileWidths[c+1] += _tileWidths[c]; + for( unsigned int r=0 ; r<_tileRows ; r++ ) _tileHeights[r+1] += _tileHeights[r]; + width = _tileWidths[_tileColumns] , height = _tileHeights[_tileRows] , channels = _channels; + return true; + } + + TiledImageReader::TiledImageReader( const char* fileName , unsigned int& width , unsigned int& height , unsigned int& channels ) + { + char* fileDir = FileNameParser::Dir( fileName ); + FILE* fp = fopen( fileName , "r" ); + if( !fp ) ERROR_OUT( "Couldn't open file for reading: " , fileName ); { - if( !fgets( line , 1024 , fp ) ) ERROR_OUT( "Failed to read tile name from: " , fileName ); + char line[1024]; + if( !fgets( line , 1024 , fp ) ) ERROR_OUT( "Failed read column line from: " , fileName ); line[strlen(line)-1] = 0; - if( fileDir ) sprintf( tileName , "%s%c%s" , fileDir , FileNameParser::Separator , line ); - else sprintf( tileName , "%s" , line ); + if( sscanf( line , "Columns: %d" , &_tileColumns )!=1 ) ERROR_OUT( "Failed to read column count from: " , fileName , " (" , line , ")" ); + if( !fgets( line , 1024 , fp ) ) ERROR_OUT( "Failed read row line from: " , fileName ); + line[strlen(line)-1] = 0; + if( sscanf( line , "Rows: %d" , &_tileRows )!=1 ) ERROR_OUT( "Failed to read row count from: " , fileName , " (" , line , ")" ); + + _tileReaders = new ImageReader*[ _tileColumns ]; + _tileHeights = new unsigned int[ _tileRows+1 ]; + _tileWidths = new unsigned int[ _tileColumns+1 ]; + _tileNames = new char*[ _tileColumns * _tileRows ]; + char tileName[2048]; + for( unsigned int r=0 ; r<_tileRows ; r++ ) for( unsigned int c=0 ; c<_tileColumns ; c++ ) + { + if( !fgets( line , 1024 , fp ) ) ERROR_OUT( "Failed to read tile name from: " , fileName ); + line[strlen(line)-1] = 0; + if( fileDir ) sprintf( tileName , "%s%c%s" , fileDir , FileNameParser::Separator , line ); + else sprintf( tileName , "%s" , line ); + _tileNames[r*_tileColumns+c] = new char[ strlen(tileName)+1 ]; + strcpy( _tileNames[r*_tileColumns+c] , tileName ); + } + } + fclose( fp ); + if( fileDir ) delete[] fileDir; + for( unsigned int r=0 ; r<_tileRows ; r++ ) for( unsigned int c=0 ; c<_tileColumns ; c++ ) + { unsigned int _w , _h , _c; - ImageReader::GetInfo( tileName , _w , _h , _c ); + ImageReader::GetInfo( _tileNames[r*_tileColumns+c] , _w , _h , _c ); if( !r && !c ) _channels = _c; else if( _channels!=_c ) ERROR_OUT( "Number of color channels don't match: " , _channels , " != " , _c ); if( !r ) _tileWidths[c+1] = _w; else if( _tileWidths[c+1]!=_w ) ERROR_OUT( "Images in the same column must have the same width: " , _tileWidths[c+1] , " != " , _w ); if( !c ) _tileHeights[r+1] = _h; - else if( _tileHeights[r+1]!=_h ) ERROR_OUT( "Images in the same row must have the same heights: " , _tileHeights[r+1] ," != " , _h ); + else if( _tileHeights[r+1]!=_h ) ERROR_OUT( "Images in the same row must have the same heights: " , _tileHeights[r+1] , " != " , _h ); } + _tileWidths[0] = _tileHeights[0] = 0; + for( unsigned int c=0 ; c<_tileColumns ; c++ ) _tileWidths[c+1] += _tileWidths[c]; + for( unsigned int r=0 ; r<_tileRows ; r++ ) _tileHeights[r+1] += _tileHeights[r]; + width = _width = _tileWidths[_tileColumns] , height = _height = _tileHeights[_tileRows] , channels = _channels; + _currentPixelRow = _currentTileRow = 0; } - fclose( fp ); - if( fileDir ) delete[] fileDir; - _tileWidths[0] = _tileHeights[0] = 0; - for( unsigned int c=0 ; c<_tileColumns ; c++ ) _tileWidths[c+1] += _tileWidths[c]; - for( unsigned int r=0 ; r<_tileRows ; r++ ) _tileHeights[r+1] += _tileHeights[r]; - width = _tileWidths[_tileColumns] , height = _tileHeights[_tileRows] , channels = _channels; - return true; -} - -TiledImageReader::TiledImageReader( const char* fileName , unsigned int& width , unsigned int& height , unsigned int& channels ) -{ - char* fileDir = FileNameParser::Dir( fileName ); - FILE* fp = fopen( fileName , "r" ); - if( !fp ) ERROR_OUT( "Couldn't open file for reading: " , fileName ); + TiledImageReader::~TiledImageReader( void ) { - char line[1024]; - if( !fgets( line , 1024 , fp ) ) ERROR_OUT( "Failed read column line from: " , fileName ); - line[strlen(line)-1] = 0; - if( sscanf( line , "Columns: %d" , &_tileColumns )!=1 ) ERROR_OUT( "Failed to read column count from: " , fileName , " (" , line , ")" ); - if( !fgets( line , 1024 , fp ) ) ERROR_OUT( "Failed read row line from: " , fileName ); - line[strlen(line)-1] = 0; - if( sscanf( line , "Rows: %d" , &_tileRows )!=1 ) ERROR_OUT( "Failed to read row count from: " , fileName , " (" , line , ")" ); - - _tileReaders = new ImageReader*[ _tileColumns ]; - _tileHeights = new unsigned int[ _tileRows+1 ]; - _tileWidths = new unsigned int[ _tileColumns+1 ]; + delete[] _tileReaders; + for( unsigned int i=0 ; i<_tileColumns*_tileRows ; i++ ) delete[] _tileNames[i]; + delete[] _tileNames; + delete[] _tileWidths; + delete[] _tileHeights; + } + unsigned TiledImageReader::nextRow( unsigned char* row ) + { + // If it's the first row, set up the readers + if( _currentPixelRow==_tileHeights[ _currentTileRow ] ) for( unsigned int c=0 ; c<_tileColumns ; c++ ) _tileReaders[c] = ImageReader::Get( _tileNames[ _currentTileRow * _tileColumns + c ] ); + // Read the row fragments + for( unsigned int c=0 ; c<_tileColumns ; c++ ) _tileReaders[c]->nextRow( row + c * _tileWidths[c] * _channels ); + + // If it's the last row of the tile, free up the readers + if( _currentPixelRow==_tileHeights[_currentTileRow+1]-1 ) + { + for( unsigned int c=0 ; c<_tileColumns ; c++ ) delete _tileReaders[c]; + _currentTileRow++; + } + + return _currentPixelRow++; + } + + TiledImageWriter::TiledImageWriter( const char* fileName , unsigned int width , unsigned int height , unsigned int channels , ImageWriterParams params ) + { + _width = width , _height = height , _channels = channels , _tileWidth = params.tileWidth , _tileHeight = params.tileHeight; + _tileColumns = ( _width + ( _tileWidth-1 ) ) / _tileWidth , _tileRows = ( _height + ( _tileHeight-1 ) ) / _tileHeight; + _tileWriters = new ImageWriter*[ _tileColumns ]; _tileNames = new char*[ _tileColumns * _tileRows ]; - char tileName[2048]; + if( params.tileParams ) _params = *params.tileParams; + + char tileName[1024]; + char* tileHeader = FileNameParser::Header( fileName ); for( unsigned int r=0 ; r<_tileRows ; r++ ) for( unsigned int c=0 ; c<_tileColumns ; c++ ) { - if( !fgets( line , 1024 , fp ) ) ERROR_OUT( "Failed to read tile name from: " , fileName ); - line[strlen(line)-1] = 0; - if( fileDir ) sprintf( tileName , "%s%c%s" , fileDir , FileNameParser::Separator , line ); - else sprintf( tileName , "%s" , line ); + sprintf( tileName , "%s.%d.%d.%s" , tileHeader , c , r , params.tileExtension ); _tileNames[r*_tileColumns+c] = new char[ strlen(tileName)+1 ]; strcpy( _tileNames[r*_tileColumns+c] , tileName ); } + delete[] tileHeader; + FILE* fp = fopen( fileName , "w" ); + if( !fp ) ERROR_OUT( "Failed to open file for writing: " , fileName ); + fprintf( fp , "Columns: %d\n" , _tileColumns ); + fprintf( fp , "Rows: %d\n" , _tileRows ); + for( unsigned int i=0 ; i<_tileRows*_tileColumns ; i++ ) + { + char* localTileName = FileNameParser::Local( _tileNames[i] ); + fprintf( fp , "%s\n" , localTileName ); + delete[] localTileName; + } + fclose( fp ); + _currentPixelRow = 0; } - fclose( fp ); - if( fileDir ) delete[] fileDir; - for( unsigned int r=0 ; r<_tileRows ; r++ ) for( unsigned int c=0 ; c<_tileColumns ; c++ ) + TiledImageWriter::~TiledImageWriter( void ) { - unsigned int _w , _h , _c; - ImageReader::GetInfo( _tileNames[r*_tileColumns+c] , _w , _h , _c ); - if( !r && !c ) _channels = _c; - else if( _channels!=_c ) ERROR_OUT( "Number of color channels don't match: " , _channels , " != " , _c ); - if( !r ) _tileWidths[c+1] = _w; - else if( _tileWidths[c+1]!=_w ) ERROR_OUT( "Images in the same column must have the same width: " , _tileWidths[c+1] , " != " , _w ); - if( !c ) _tileHeights[r+1] = _h; - else if( _tileHeights[r+1]!=_h ) ERROR_OUT( "Images in the same row must have the same heights: " , _tileHeights[r+1] , " != " , _h ); + delete[] _tileWriters; + for( unsigned int i=0 ; i<_tileColumns*_tileRows ; i++ ) delete[] _tileNames[i]; + delete[] _tileNames; } - _tileWidths[0] = _tileHeights[0] = 0; - for( unsigned int c=0 ; c<_tileColumns ; c++ ) _tileWidths[c+1] += _tileWidths[c]; - for( unsigned int r=0 ; r<_tileRows ; r++ ) _tileHeights[r+1] += _tileHeights[r]; - width = _width = _tileWidths[_tileColumns] , height = _height = _tileHeights[_tileRows] , channels = _channels; - _currentPixelRow = _currentTileRow = 0; -} -TiledImageReader::~TiledImageReader( void ) -{ - delete[] _tileReaders; - for( unsigned int i=0 ; i<_tileColumns*_tileRows ; i++ ) delete[] _tileNames[i]; - delete[] _tileNames; - delete[] _tileWidths; - delete[] _tileHeights; -} -unsigned TiledImageReader::nextRow( unsigned char* row ) -{ - // If it's the first row, set up the readers - if( _currentPixelRow==_tileHeights[ _currentTileRow ] ) for( unsigned int c=0 ; c<_tileColumns ; c++ ) _tileReaders[c] = ImageReader::Get( _tileNames[ _currentTileRow * _tileColumns + c ] ); - - // Read the row fragments - for( unsigned int c=0 ; c<_tileColumns ; c++ ) _tileReaders[c]->nextRow( row + c * _tileWidths[c] * _channels ); - - // If it's the last row of the tile, free up the readers - if( _currentPixelRow==_tileHeights[_currentTileRow+1]-1 ) + unsigned int TiledImageWriter::nextRow( const unsigned char* row ) { - for( unsigned int c=0 ; c<_tileColumns ; c++ ) delete _tileReaders[c]; - _currentTileRow++; - } - - return _currentPixelRow++; -} + unsigned int r = _currentPixelRow / _tileHeight; + if( ( _currentPixelRow % _tileHeight )==0 ) + { + for( unsigned int c=0 ; c<_tileColumns ; c++ ) + _tileWriters[c] = ImageWriter::Get( _tileNames[ r * _tileColumns + c ] , std::min< unsigned int >( _tileWidth , _width - _tileWidth*c ) , std::min< unsigned int >( _tileHeight , _height - _tileHeight*r ) , _channels , _params ); + } + for( int c=0 ; c<(int)_tileColumns ; c++ ) _tileWriters[c]->nextRow( row + c * _tileWidth * _channels ); + if( ( _currentPixelRow % _tileHeight )==( _tileHeight-1 ) || _currentPixelRow==(_height-1) ) for( unsigned int c=0 ; c<_tileColumns ; c++ ) delete _tileWriters[c]; -TiledImageWriter::TiledImageWriter( const char* fileName , unsigned int width , unsigned int height , unsigned int channels , ImageWriterParams params ) -{ - _width = width , _height = height , _channels = channels , _tileWidth = params.tileWidth , _tileHeight = params.tileHeight; - _tileColumns = ( _width + ( _tileWidth-1 ) ) / _tileWidth , _tileRows = ( _height + ( _tileHeight-1 ) ) / _tileHeight; - _tileWriters = new ImageWriter*[ _tileColumns ]; - _tileNames = new char*[ _tileColumns * _tileRows ]; - if( params.tileParams ) _params = *params.tileParams; - - char tileName[1024]; - char* tileHeader = FileNameParser::Header( fileName ); - for( unsigned int r=0 ; r<_tileRows ; r++ ) for( unsigned int c=0 ; c<_tileColumns ; c++ ) - { - sprintf( tileName , "%s.%d.%d.%s" , tileHeader , c , r , params.tileExtension ); - _tileNames[r*_tileColumns+c] = new char[ strlen(tileName)+1 ]; - strcpy( _tileNames[r*_tileColumns+c] , tileName ); + return _currentPixelRow++; } - delete[] tileHeader; - FILE* fp = fopen( fileName , "w" ); - if( !fp ) ERROR_OUT( "Failed to open file for writing: " , fileName ); - fprintf( fp , "Columns: %d\n" , _tileColumns ); - fprintf( fp , "Rows: %d\n" , _tileRows ); - for( unsigned int i=0 ; i<_tileRows*_tileColumns ; i++ ) - { - char* localTileName = FileNameParser::Local( _tileNames[i] ); - fprintf( fp , "%s\n" , localTileName ); - delete[] localTileName; - } - fclose( fp ); - _currentPixelRow = 0; -} -TiledImageWriter::~TiledImageWriter( void ) -{ - delete[] _tileWriters; - for( unsigned int i=0 ; i<_tileColumns*_tileRows ; i++ ) delete[] _tileNames[i]; - delete[] _tileNames; -} -unsigned int TiledImageWriter::nextRow( const unsigned char* row ) -{ - unsigned int r = _currentPixelRow / _tileHeight; - if( ( _currentPixelRow % _tileHeight )==0 ) - { - for( unsigned int c=0 ; c<_tileColumns ; c++ ) - _tileWriters[c] = ImageWriter::Get( _tileNames[ r * _tileColumns + c ] , std::min< unsigned int >( _tileWidth , _width - _tileWidth*c ) , std::min< unsigned int >( _tileHeight , _height - _tileHeight*r ) , _channels , _params ); - } - for( int c=0 ; c<(int)_tileColumns ; c++ ) _tileWriters[c]->nextRow( row + c * _tileWidth * _channels ); - if( ( _currentPixelRow % _tileHeight )==( _tileHeight-1 ) || _currentPixelRow==(_height-1) ) for( unsigned int c=0 ; c<_tileColumns ; c++ ) delete _tileWriters[c]; - - return _currentPixelRow++; -} #endif // SUPPORT_TILES +} #endif // IMAGE_INCLUDED diff --git a/Src/ImageStitching.cpp b/Src/ImageStitching.cpp index 92ac9297..52c2c2ed 100644 --- a/Src/ImageStitching.cpp +++ b/Src/ImageStitching.cpp @@ -49,11 +49,13 @@ DAMAGE. #include "Geometry.h" #include "FEMTree.h" -cmdLineParameterArray< char* , 2 > +using namespace PoissonRecon; + +CmdLineParameterArray< char* , 2 > In( "in" ); -cmdLineParameter< char* > +CmdLineParameter< char* > Out( "out" ); -cmdLineParameter< int > +CmdLineParameter< int > #ifdef FAST_COMPILE #else // !FAST_COMPILE Degree( "degree" , DEFAULT_FEM_DEGREE ) , @@ -71,15 +73,15 @@ cmdLineParameter< int > FullDepth( "fullDepth" , 6 ) , BaseDepth( "baseDepth" ) , BaseVCycles( "baseVCycles" , 4 ); -cmdLineReadable +CmdLineReadable Verbose( "verbose" ) , ShowResidual( "showResidual" ) , Performance( "performance" ); -cmdLineParameter< float > +CmdLineParameter< float > WeightScale ( "wScl", 0.125f ) , WeightExponent( "wExp" , 6.f ); -cmdLineReadable* params[] = +CmdLineReadable* params[] = { &In , &Out , &Threads , &Verbose , &ShowResidual , &GSIterations , &FullDepth , &BaseDepth , &BaseVCycles , @@ -510,7 +512,7 @@ int main( int argc , char* argv[] ) #ifdef ARRAY_DEBUG WARN( "Array debugging enabled" ); #endif // ARRAY_DEBUG - cmdLineParse( argc-1 , &argv[1] , params ); + CmdLineParse( argc-1 , &argv[1] , params ); if( MaxMemoryGB.value>0 ) SetPeakMemoryMB( MaxMemoryGB.value<<10 ); ThreadPool::DefaultChunkSize = ThreadChunkSize.value; ThreadPool::DefaultSchedule = (ThreadPool::ScheduleType)ScheduleType.value; diff --git a/Src/JPEG.h b/Src/JPEG.h index 3ce94f11..64ad9a7a 100644 --- a/Src/JPEG.h +++ b/Src/JPEG.h @@ -28,6 +28,8 @@ DAMAGE. #ifndef JPEG_INCLUDED #define JPEG_INCLUDED +#include +#include #include "Image.h" #include @@ -43,38 +45,43 @@ DAMAGE. #include #endif // _WIN32 -struct my_error_mgr +namespace PoissonRecon { - struct jpeg_error_mgr pub; // "public" fields - jmp_buf setjmp_buffer; // for return to caller -}; -typedef struct my_error_mgr * my_error_ptr; -struct JPEGReader : public ImageReader -{ - JPEGReader( const char* fileName , unsigned int& width , unsigned int& height , unsigned int& channels ); - ~JPEGReader( void ); - unsigned int nextRow( unsigned char* row ); - static bool GetInfo( const char* fileName , unsigned int& width , unsigned int& height , unsigned int& channels ); -protected: - FILE* _fp; - struct jpeg_decompress_struct _cInfo; - struct my_error_mgr _jErr; - unsigned int _currentRow; -}; + struct my_error_mgr + { + struct jpeg_error_mgr pub; // "public" fields + jmp_buf setjmp_buffer; // for return to caller + }; + typedef struct my_error_mgr * my_error_ptr; -struct JPEGWriter : public ImageWriter -{ - JPEGWriter( const char* fileName , unsigned int width , unsigned int height , unsigned int channels , unsigned int quality=100 ); - ~JPEGWriter( void ); - unsigned int nextRow( const unsigned char* row ); - unsigned int nextRows( const unsigned char* rows , unsigned int rowNum ); -protected: - FILE* _fp; - struct jpeg_compress_struct _cInfo; - struct my_error_mgr _jErr; - unsigned int _currentRow; -}; + struct JPEGReader : public ImageReader + { + JPEGReader( const char* fileName , unsigned int& width , unsigned int& height , unsigned int& channels ); + ~JPEGReader( void ); + unsigned int nextRow( unsigned char* row ); + static bool GetInfo( const char* fileName , unsigned int& width , unsigned int& height , unsigned int& channels ); + protected: + FILE* _fp; + struct jpeg_decompress_struct _cInfo; + struct my_error_mgr _jErr; + unsigned int _currentRow; + }; + + struct JPEGWriter : public ImageWriter + { + JPEGWriter( const char* fileName , unsigned int width , unsigned int height , unsigned int channels , unsigned int quality=100 ); + ~JPEGWriter( void ); + unsigned int nextRow( const unsigned char* row ); + unsigned int nextRows( const unsigned char* rows , unsigned int rowNum ); + protected: + FILE* _fp; + struct jpeg_compress_struct _cInfo; + struct my_error_mgr _jErr; + unsigned int _currentRow; + }; #include "JPEG.inl" +} + #endif //JPEG_INCLUDED diff --git a/Src/JPEG.inl b/Src/JPEG.inl index 35a376e2..09aeb76b 100644 --- a/Src/JPEG.inl +++ b/Src/JPEG.inl @@ -26,10 +26,6 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ -#include -#include - - inline METHODDEF( void ) my_error_exit (j_common_ptr cinfo) { diff --git a/Src/MAT.h b/Src/MAT.h index 844bf78d..839824f6 100644 --- a/Src/MAT.h +++ b/Src/MAT.h @@ -30,33 +30,37 @@ DAMAGE. #include "Geometry.h" #include "Array.h" -template< typename Index , class Real , unsigned int Dim > -std::vector< TriangleIndex< Index > > MinimalAreaTriangulation( ConstPointer( Point< Real , Dim > ) vertices , size_t vCount ); - -template< typename Index , class Real , unsigned int Dim > -class _MinimalAreaTriangulation -{ - Pointer( Real ) _bestTriangulation; - Pointer( Index ) _midpoint; - size_t _vCount; - ConstPointer( Point< Real , Dim > ) _vertices; - - void _set( void ); - Real _subPolygonArea( Index i , Index j ); - void _addTriangles( Index i , Index j , std::vector< TriangleIndex< Index > >& triangles ) const; - Index _subPolygonIndex( Index i , Index j ) const; - - _MinimalAreaTriangulation( ConstPointer( Point< Real , Dim > ) vertices , size_t vCount ); - ~_MinimalAreaTriangulation( void ); - std::vector< TriangleIndex< Index > > getTriangulation( void ); - friend std::vector< TriangleIndex< Index > > MinimalAreaTriangulation< Index , Real , Dim >( ConstPointer( Point< Real , Dim > ) vertices , size_t vCount ); -}; -template< typename Index , class Real , unsigned int Dim > -std::vector< TriangleIndex< Index > > MinimalAreaTriangulation( ConstPointer( Point< Real , Dim > ) vertices , size_t vCount ) +namespace PoissonRecon { - _MinimalAreaTriangulation< Index , Real , Dim > MAT( vertices , vCount ); - return MAT.getTriangulation(); -} + + template< typename Index , class Real , unsigned int Dim > + std::vector< TriangleIndex< Index > > MinimalAreaTriangulation( ConstPointer( Point< Real , Dim > ) vertices , size_t vCount ); + + template< typename Index , class Real , unsigned int Dim > + class _MinimalAreaTriangulation + { + Pointer( Real ) _bestTriangulation; + Pointer( Index ) _midpoint; + size_t _vCount; + ConstPointer( Point< Real , Dim > ) _vertices; + + void _set( void ); + Real _subPolygonArea( Index i , Index j ); + void _addTriangles( Index i , Index j , std::vector< TriangleIndex< Index > >& triangles ) const; + Index _subPolygonIndex( Index i , Index j ) const; + + _MinimalAreaTriangulation( ConstPointer( Point< Real , Dim > ) vertices , size_t vCount ); + ~_MinimalAreaTriangulation( void ); + std::vector< TriangleIndex< Index > > getTriangulation( void ); + friend std::vector< TriangleIndex< Index > > MinimalAreaTriangulation< Index , Real , Dim >( ConstPointer( Point< Real , Dim > ) vertices , size_t vCount ); + }; + template< typename Index , class Real , unsigned int Dim > + std::vector< TriangleIndex< Index > > MinimalAreaTriangulation( ConstPointer( Point< Real , Dim > ) vertices , size_t vCount ) + { + _MinimalAreaTriangulation< Index , Real , Dim > MAT( vertices , vCount ); + return MAT.getTriangulation(); + } #include "MAT.inl" +} #endif // MAT_INCLUDED diff --git a/Src/MarchingCubes.h b/Src/MarchingCubes.h index 089c46a5..2ab88c48 100644 --- a/Src/MarchingCubes.h +++ b/Src/MarchingCubes.h @@ -35,727 +35,726 @@ DAMAGE. #include "Window.h" -namespace HyperCube +namespace PoissonRecon { - enum Direction{ BACK , CROSS , FRONT }; - inline Direction Opposite( Direction dir ){ return dir==BACK ? FRONT : ( dir==FRONT ? BACK : CROSS ); } - std::string DirectionName( Direction dir ) + namespace HyperCube { - if( dir==BACK ) return std::string( "back" ); - else if( dir==CROSS ) return std::string( "cross" ); - else if( dir==FRONT ) return std::string( "front" ); - else{ ERROR_OUT( "Unrecognized direction" ) ; return std::string( "" ); } - } - - // The number of k-dimensional elements in a d-dimensional cube is equal to - // the number of (k-1)-dimensional elements in a (d-1)-dimensional hypercube plus twice the number of k-dimensional elements in a (d-1)-dimensional hypercube - - // Number of elements of dimension K in a cube of dimension D - template< unsigned int D , unsigned int K > struct ElementNum { static const unsigned int Value = 2 * ElementNum< D-1 , K >::Value + ElementNum< D-1 , K-1 >::Value; }; - template< unsigned int D > struct ElementNum< D , 0 >{ static const unsigned int Value = 2 * ElementNum< D-1 , 0 >::Value; }; - template< unsigned int D > struct ElementNum< D , D >{ static const unsigned int Value = 1; }; - template< > struct ElementNum< 0 , 0 >{ static const unsigned int Value = 1; }; - // [WARNING] This shouldn't really happen, but we need to support the definition of OverlapElementNum - template< unsigned int K > struct ElementNum< 0 , K >{ static const unsigned int Value = K==0 ? 1 : 0; }; - - template< unsigned int D , unsigned int K1 , unsigned int K2 > struct OverlapElementNum { static const unsigned int Value = K1>=K2 ? ElementNum< K1 , K2 >::Value : OverlapElementNum< D-1 , K1 , K2 >::Value + OverlapElementNum< D-1 , K1 , K2-1 >::Value; }; - template< unsigned int D , unsigned int K > struct OverlapElementNum< D , D , K >{ static const unsigned int Value = ElementNum< D , K >::Value; }; - template< unsigned int D > struct OverlapElementNum< D , D , 0 >{ static const unsigned int Value = ElementNum< D , 0 >::Value; }; - template< unsigned int D , unsigned int K > struct OverlapElementNum< D , K , 0 >{ static const unsigned int Value = ElementNum< K , 0 >::Value; }; - template< unsigned int D , unsigned int K > struct OverlapElementNum< D , K , K >{ static const unsigned int Value = 1; }; - template< unsigned int D , unsigned int K > struct OverlapElementNum< D , K , D >{ static const unsigned int Value = 1; }; - template< unsigned int D > struct OverlapElementNum< D , D , D >{ static const unsigned int Value = 1; }; - template< unsigned int D > struct OverlapElementNum< D , 0 , 0 >{ static const unsigned int Value = 1; }; - - template< unsigned int D > - struct Cube - { - // Corner index (x,y,z,...) -> x + 2*y + 4*z + ... - // CROSS -> the D-th axis - - // Representation of a K-dimensional element of the cube - template< unsigned int K > - struct Element - { - static_assert( D>=K , "[ERROR] Element dimension exceeds cube dimension" ); - - // The index of the element, sorted as: - // 1. All K-dimensional elements contained in the back face - // 2. All K-dimensional elements spanning the D-th axis - // 3. All K-dimensional elements contained in the front face - unsigned int index; - - // Initialize by index - Element( unsigned int idx=0 ); - - // Initialize by co-index: - // 1. A K-dimensional element in either BACK or FRONT - // 2. A (K-1)-dimensional element extruded across the D-th axis - Element( Direction dir , unsigned int coIndex ); - - // Given a K-Dimensional sub-element living inside a DK-dimensional sub-cube, get the element relative to the D-dimensional cube - template< unsigned int DK > - Element( Element< DK > subCube , typename Cube< DK >::template Element< K > subElement ); - - // Initialize by setting the directions - Element( const Direction dirs[D] ); - - // Print the element to the specified stream - void print( FILE* fp=stdout ) const; - - // Sets the direction and co-index of the element - void factor( Direction& dir , unsigned int& coIndex ) const; - - // Returns the direction along which the element lives - Direction direction( void ) const; - - // Returns the co-index of the element - unsigned int coIndex( void ) const; - - // Compute the directions of the element - void directions( Direction* dirs ) const; - - // Returns the antipodal element - typename Cube< D >::template Element< K > antipodal( void ) const; - - // Comparison operators - bool operator < ( Element e ) const { return index< e.index; } - bool operator <= ( Element e ) const { return index<=e.index; } - bool operator > ( Element e ) const { return index> e.index; } - bool operator >= ( Element e ) const { return index>=e.index; } - bool operator == ( Element e ) const { return index==e.index; } - bool operator != ( Element e ) const { return index!=e.index; } - bool operator < ( unsigned int i ) const { return index< i; } - bool operator <= ( unsigned int i ) const { return index<=i; } - bool operator > ( unsigned int i ) const { return index> i; } - bool operator >= ( unsigned int i ) const { return index>=i; } - bool operator == ( unsigned int i ) const { return index==i; } - bool operator != ( unsigned int i ) const { return index!=i; } - - // Increment operators - Element& operator ++ ( void ) { index++ ; return *this; } - Element operator ++ ( int ) { index++ ; return Element(index-1); } - protected: - template< unsigned int _D=D , unsigned int _K=K > typename std::enable_if< _D!=0 && _K!=0 >::type _setElement( Direction dir , unsigned int coIndex ); - template< unsigned int _D=D , unsigned int _K=K > typename std::enable_if< _D!=0 && _K==0 >::type _setElement( Direction dir , unsigned int coIndex ); - template< unsigned int _D=D , unsigned int _K=K > typename std::enable_if< _D==0 && _K==0 >::type _setElement( Direction dir , unsigned int coIndex ); - - template< unsigned int KD > typename std::enable_if< (D> KD) && (KD>K) && K!=0 >::type _setElement( typename Cube< D >::template Element< KD > subCube , typename Cube< KD >::template Element< K > subElement ); - template< unsigned int KD > typename std::enable_if< (D> KD) && (KD>K) && K==0 >::type _setElement( typename Cube< D >::template Element< KD > subCube , typename Cube< KD >::template Element< K > subElement ); - template< unsigned int KD > typename std::enable_if< (D==KD) && (KD>K) >::type _setElement( typename Cube< D >::template Element< KD > subCube , typename Cube< KD >::template Element< K > subElement ); - template< unsigned int KD > typename std::enable_if< (KD==K) >::type _setElement( typename Cube< D >::template Element< KD > subCube , typename Cube< KD >::template Element< K > subElement ); - - template< unsigned int _D=D > typename std::enable_if< _D!=0 >::type _setElement( const Direction* dirs ); - template< unsigned int _D=D > typename std::enable_if< _D==0 >::type _setElement( const Direction* dirs ); - - template< unsigned int _D=D , unsigned int _K=K > typename std::enable_if< _D==_K >::type _factor( Direction& dir , unsigned int& coIndex ) const; - template< unsigned int _D=D , unsigned int _K=K > typename std::enable_if< _D!=_K && _K!=0 >::type _factor( Direction& dir , unsigned int& coIndex ) const; - template< unsigned int _D=D , unsigned int _K=K > typename std::enable_if< _D!=_K && _K==0 >::type _factor( Direction& dir , unsigned int& coIndex ) const; - - template< unsigned int _D=D , unsigned int _K=K > typename std::enable_if< (_D>_K) && _K!=0 >::type _directions( Direction* dirs ) const; - template< unsigned int _D=D , unsigned int _K=K > typename std::enable_if< (_D>_K) && _K==0 >::type _directions( Direction* dirs ) const; - template< unsigned int _D=D , unsigned int _K=K > typename std::enable_if< _D==_K >::type _directions( Direction* dirs ) const; - - template< unsigned int _D=D , unsigned int _K=K > typename std::enable_if< (_D>_K) && _K!=0 , Element >::type _antipodal( void ) const; - template< unsigned int _D=D , unsigned int _K=K > typename std::enable_if< (_D>_K) && _K==0 , Element >::type _antipodal( void ) const; - template< unsigned int _D=D , unsigned int _K=K > typename std::enable_if< _D==_K , Element >::type _antipodal( void ) const; - }; - // A way of indexing the cubes incident on an element - template< unsigned int K > using IncidentCubeIndex = typename Cube< D-K >::template Element< 0 >; - - // Number of elements of dimension K - template< unsigned int K > static constexpr unsigned int ElementNum( void ){ return HyperCube::ElementNum< D , K >::Value; } - // Number of cubes incident to an element of dimension K - template< unsigned int K > static constexpr unsigned int IncidentCubeNum( void ){ return HyperCube::ElementNum< D-K , 0 >::Value; } - // Number of overlapping elements of dimension K1 / K2 - template< unsigned int K1 , unsigned int K2 > static constexpr unsigned int OverlapElementNum( void ){ return HyperCube::OverlapElementNum< D , K1 , K2 >::Value; } - - // Is the face outward-facing - static bool IsOriented( Element< D-1 > e ); - - // Is one element contained in the other? - template< unsigned int K1 , unsigned int K2 > - static bool Overlap( Element< K1 > e1 , Element< K2 > e2 ); - - // If K1>K2: returns all elements contained in e - // Else: returns all elements containing e - template< unsigned int K1 , unsigned int K2 > - static void OverlapElements( Element< K1 > e , Element< K2 >* es ); - - // Returns the marching-cubes index for the set of values - template< typename Real > - static unsigned int MCIndex( const Real values[ Cube::ElementNum< 0 >() ] , Real iso ); - - // Extracts the marching-cubes sub-index for the associated element - template< unsigned int K > - static unsigned int ElementMCIndex( Element< K > element , unsigned int mcIndex ); - - // Does the marching cubes index have a zero-crossing - static bool HasMCRoots( unsigned int mcIndex ); - - // Sets the offset of the incident cube relative to the center cube, x[i] \in {-1,0,1} - template< unsigned int K > - static void CellOffset( Element< K > e , IncidentCubeIndex< K > d , int x[D] ); - - // Returns the linearized offset of the incident cube relative to the center cube, \in [0,3^D) - template< unsigned int K > - static unsigned int CellOffset( Element< K > e , IncidentCubeIndex< K > d ); + enum Direction{ BACK , CROSS , FRONT }; + inline Direction Opposite( Direction dir ){ return dir==BACK ? FRONT : ( dir==FRONT ? BACK : CROSS ); } + std::string DirectionName( Direction dir ) + { + if( dir==BACK ) return std::string( "back" ); + else if( dir==CROSS ) return std::string( "cross" ); + else if( dir==FRONT ) return std::string( "front" ); + else{ ERROR_OUT( "Unrecognized direction" ) ; return std::string( "" ); } + } - // Returns the index of the incident cube that is the source - template< unsigned int K > - static typename Cube< D >::template IncidentCubeIndex< K > IncidentCube( Element< K > e ); + // The number of k-dimensional elements in a d-dimensional cube is equal to + // the number of (k-1)-dimensional elements in a (d-1)-dimensional hypercube plus twice the number of k-dimensional elements in a (d-1)-dimensional hypercube + + // Number of elements of dimension K in a cube of dimension D + template< unsigned int D , unsigned int K > struct ElementNum { static const unsigned int Value = 2 * ElementNum< D-1 , K >::Value + ElementNum< D-1 , K-1 >::Value; }; + template< unsigned int D > struct ElementNum< D , 0 >{ static const unsigned int Value = 2 * ElementNum< D-1 , 0 >::Value; }; + template< unsigned int D > struct ElementNum< D , D >{ static const unsigned int Value = 1; }; + template< > struct ElementNum< 0 , 0 >{ static const unsigned int Value = 1; }; + // [WARNING] This shouldn't really happen, but we need to support the definition of OverlapElementNum + template< unsigned int K > struct ElementNum< 0 , K >{ static const unsigned int Value = K==0 ? 1 : 0; }; + + template< unsigned int D , unsigned int K1 , unsigned int K2 > struct OverlapElementNum { static const unsigned int Value = K1>=K2 ? ElementNum< K1 , K2 >::Value : OverlapElementNum< D-1 , K1 , K2 >::Value + OverlapElementNum< D-1 , K1 , K2-1 >::Value; }; + template< unsigned int D , unsigned int K > struct OverlapElementNum< D , D , K >{ static const unsigned int Value = ElementNum< D , K >::Value; }; + template< unsigned int D > struct OverlapElementNum< D , D , 0 >{ static const unsigned int Value = ElementNum< D , 0 >::Value; }; + template< unsigned int D , unsigned int K > struct OverlapElementNum< D , K , 0 >{ static const unsigned int Value = ElementNum< K , 0 >::Value; }; + template< unsigned int D , unsigned int K > struct OverlapElementNum< D , K , K >{ static const unsigned int Value = 1; }; + template< unsigned int D , unsigned int K > struct OverlapElementNum< D , K , D >{ static const unsigned int Value = 1; }; + template< unsigned int D > struct OverlapElementNum< D , D , D >{ static const unsigned int Value = 1; }; + template< unsigned int D > struct OverlapElementNum< D , 0 , 0 >{ static const unsigned int Value = 1; }; + + template< unsigned int D > + struct Cube + { + // Corner index (x,y,z,...) -> x + 2*y + 4*z + ... + // CROSS -> the D-th axis - // Returns the corresponding element in the incident cube - template< unsigned int K > - static typename Cube< D >::template Element< K > IncidentElement( Element< K > e , IncidentCubeIndex< K > d ); + // Representation of a K-dimensional element of the cube + template< unsigned int K > + struct Element + { + static_assert( D>=K , "[ERROR] Element dimension exceeds cube dimension" ); + + // The index of the element, sorted as: + // 1. All K-dimensional elements contained in the back face + // 2. All K-dimensional elements spanning the D-th axis + // 3. All K-dimensional elements contained in the front face + unsigned int index; + + // Initialize by index + Element( unsigned int idx=0 ); + + // Initialize by co-index: + // 1. A K-dimensional element in either BACK or FRONT + // 2. A (K-1)-dimensional element extruded across the D-th axis + Element( Direction dir , unsigned int coIndex ); + + // Given a K-Dimensional sub-element living inside a DK-dimensional sub-cube, get the element relative to the D-dimensional cube + template< unsigned int DK > + Element( Element< DK > subCube , typename Cube< DK >::template Element< K > subElement ); + + // Initialize by setting the directions + Element( const Direction dirs[D] ); + + // Print the element to the specified stream + void print( FILE* fp=stdout ) const; + + // Sets the direction and co-index of the element + void factor( Direction& dir , unsigned int& coIndex ) const; + + // Returns the direction along which the element lives + Direction direction( void ) const; + + // Returns the co-index of the element + unsigned int coIndex( void ) const; + + // Compute the directions of the element + void directions( Direction* dirs ) const; + + // Returns the antipodal element + typename Cube< D >::template Element< K > antipodal( void ) const; + + // Comparison operators + bool operator < ( Element e ) const { return index< e.index; } + bool operator <= ( Element e ) const { return index<=e.index; } + bool operator > ( Element e ) const { return index> e.index; } + bool operator >= ( Element e ) const { return index>=e.index; } + bool operator == ( Element e ) const { return index==e.index; } + bool operator != ( Element e ) const { return index!=e.index; } + bool operator < ( unsigned int i ) const { return index< i; } + bool operator <= ( unsigned int i ) const { return index<=i; } + bool operator > ( unsigned int i ) const { return index> i; } + bool operator >= ( unsigned int i ) const { return index>=i; } + bool operator == ( unsigned int i ) const { return index==i; } + bool operator != ( unsigned int i ) const { return index!=i; } + + // Increment operators + Element& operator ++ ( void ) { index++ ; return *this; } + Element operator ++ ( int ) { index++ ; return Element(index-1); } + protected: + template< unsigned int _D=D , unsigned int _K=K > typename std::enable_if< _D!=0 && _K!=0 >::type _setElement( Direction dir , unsigned int coIndex ); + template< unsigned int _D=D , unsigned int _K=K > typename std::enable_if< _D!=0 && _K==0 >::type _setElement( Direction dir , unsigned int coIndex ); + template< unsigned int _D=D , unsigned int _K=K > typename std::enable_if< _D==0 && _K==0 >::type _setElement( Direction dir , unsigned int coIndex ); + + template< unsigned int KD > typename std::enable_if< (D> KD) && (KD>K) && K!=0 >::type _setElement( typename Cube< D >::template Element< KD > subCube , typename Cube< KD >::template Element< K > subElement ); + template< unsigned int KD > typename std::enable_if< (D> KD) && (KD>K) && K==0 >::type _setElement( typename Cube< D >::template Element< KD > subCube , typename Cube< KD >::template Element< K > subElement ); + template< unsigned int KD > typename std::enable_if< (D==KD) && (KD>K) >::type _setElement( typename Cube< D >::template Element< KD > subCube , typename Cube< KD >::template Element< K > subElement ); + template< unsigned int KD > typename std::enable_if< (KD==K) >::type _setElement( typename Cube< D >::template Element< KD > subCube , typename Cube< KD >::template Element< K > subElement ); + + template< unsigned int _D=D > typename std::enable_if< _D!=0 >::type _setElement( const Direction* dirs ); + template< unsigned int _D=D > typename std::enable_if< _D==0 >::type _setElement( const Direction* dirs ); + + template< unsigned int _D=D , unsigned int _K=K > typename std::enable_if< _D==_K >::type _factor( Direction& dir , unsigned int& coIndex ) const; + template< unsigned int _D=D , unsigned int _K=K > typename std::enable_if< _D!=_K && _K!=0 >::type _factor( Direction& dir , unsigned int& coIndex ) const; + template< unsigned int _D=D , unsigned int _K=K > typename std::enable_if< _D!=_K && _K==0 >::type _factor( Direction& dir , unsigned int& coIndex ) const; + + template< unsigned int _D=D , unsigned int _K=K > typename std::enable_if< (_D>_K) && _K!=0 >::type _directions( Direction* dirs ) const; + template< unsigned int _D=D , unsigned int _K=K > typename std::enable_if< (_D>_K) && _K==0 >::type _directions( Direction* dirs ) const; + template< unsigned int _D=D , unsigned int _K=K > typename std::enable_if< _D==_K >::type _directions( Direction* dirs ) const; + + template< unsigned int _D=D , unsigned int _K=K > typename std::enable_if< (_D>_K) && _K!=0 , Element >::type _antipodal( void ) const; + template< unsigned int _D=D , unsigned int _K=K > typename std::enable_if< (_D>_K) && _K==0 , Element >::type _antipodal( void ) const; + template< unsigned int _D=D , unsigned int _K=K > typename std::enable_if< _D==_K , Element >::type _antipodal( void ) const; + }; + // A way of indexing the cubes incident on an element + template< unsigned int K > using IncidentCubeIndex = typename Cube< D-K >::template Element< 0 >; + + // Number of elements of dimension K + template< unsigned int K > static constexpr unsigned int ElementNum( void ){ return HyperCube::ElementNum< D , K >::Value; } + // Number of cubes incident to an element of dimension K + template< unsigned int K > static constexpr unsigned int IncidentCubeNum( void ){ return HyperCube::ElementNum< D-K , 0 >::Value; } + // Number of overlapping elements of dimension K1 / K2 + template< unsigned int K1 , unsigned int K2 > static constexpr unsigned int OverlapElementNum( void ){ return HyperCube::OverlapElementNum< D , K1 , K2 >::Value; } + + // Is the face outward-facing + static bool IsOriented( Element< D-1 > e ); + + // Is one element contained in the other? + template< unsigned int K1 , unsigned int K2 > + static bool Overlap( Element< K1 > e1 , Element< K2 > e2 ); + + // If K1>K2: returns all elements contained in e + // Else: returns all elements containing e + template< unsigned int K1 , unsigned int K2 > + static void OverlapElements( Element< K1 > e , Element< K2 >* es ); + + // Returns the marching-cubes index for the set of values + template< typename Real > + static unsigned int MCIndex( const Real values[ Cube::ElementNum< 0 >() ] , Real iso ); + + // Extracts the marching-cubes sub-index for the associated element + template< unsigned int K > + static unsigned int ElementMCIndex( Element< K > element , unsigned int mcIndex ); + + // Does the marching cubes index have a zero-crossing + static bool HasMCRoots( unsigned int mcIndex ); + + // Sets the offset of the incident cube relative to the center cube, x[i] \in {-1,0,1} + template< unsigned int K > + static void CellOffset( Element< K > e , IncidentCubeIndex< K > d , int x[D] ); + + // Returns the linearized offset of the incident cube relative to the center cube, \in [0,3^D) + template< unsigned int K > + static unsigned int CellOffset( Element< K > e , IncidentCubeIndex< K > d ); + + // Returns the index of the incident cube that is the source + template< unsigned int K > + static typename Cube< D >::template IncidentCubeIndex< K > IncidentCube( Element< K > e ); + + // Returns the corresponding element in the incident cube + template< unsigned int K > + static typename Cube< D >::template Element< K > IncidentElement( Element< K > e , IncidentCubeIndex< K > d ); - protected: - template< unsigned int K1 , unsigned int K2 > static typename std::enable_if< (K1>=K2) , bool >::type _Overlap( Element< K1 > e1 , Element< K2 > e2 ); - template< unsigned int K1 , unsigned int K2 > static typename std::enable_if< (K1< K2) , bool >::type _Overlap( Element< K1 > e1 , Element< K2 > e2 ); + protected: + template< unsigned int K1 , unsigned int K2 > static typename std::enable_if< (K1>=K2) , bool >::type _Overlap( Element< K1 > e1 , Element< K2 > e2 ); + template< unsigned int K1 , unsigned int K2 > static typename std::enable_if< (K1< K2) , bool >::type _Overlap( Element< K1 > e1 , Element< K2 > e2 ); - template< unsigned int K1 , unsigned int K2 > static typename std::enable_if< (K1>=K2) >::type _OverlapElements( Element< K1 > e , Element< K2 >* es ); - template< unsigned int K1 , unsigned int K2 > static typename std::enable_if< (K1< K2) && D==K2 >::type _OverlapElements( Element< K1 > e , Element< K2 >* es ); - template< unsigned int K1 , unsigned int K2 > static typename std::enable_if< (K1< K2) && D!=K2 && K1!=0 >::type _OverlapElements( Element< K1 > e , Element< K2 >* es ); - template< unsigned int K1 , unsigned int K2 > static typename std::enable_if< (K1< K2) && D!=K2 && K1==0 >::type _OverlapElements( Element< K1 > e , Element< K2 >* es ); + template< unsigned int K1 , unsigned int K2 > static typename std::enable_if< (K1>=K2) >::type _OverlapElements( Element< K1 > e , Element< K2 >* es ); + template< unsigned int K1 , unsigned int K2 > static typename std::enable_if< (K1< K2) && D==K2 >::type _OverlapElements( Element< K1 > e , Element< K2 >* es ); + template< unsigned int K1 , unsigned int K2 > static typename std::enable_if< (K1< K2) && D!=K2 && K1!=0 >::type _OverlapElements( Element< K1 > e , Element< K2 >* es ); + template< unsigned int K1 , unsigned int K2 > static typename std::enable_if< (K1< K2) && D!=K2 && K1==0 >::type _OverlapElements( Element< K1 > e , Element< K2 >* es ); - template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D==K , IncidentCubeIndex< K > >::type _IncidentCube( Element< K > e ); - template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D!=K && _D!=0 && K!=0 , IncidentCubeIndex< K > >::type _IncidentCube( Element< K > e ); - template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D!=K && _D!=0 && K==0 , IncidentCubeIndex< K > >::type _IncidentCube( Element< K > e ); + template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D==K , IncidentCubeIndex< K > >::type _IncidentCube( Element< K > e ); + template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D!=K && _D!=0 && K!=0 , IncidentCubeIndex< K > >::type _IncidentCube( Element< K > e ); + template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D!=K && _D!=0 && K==0 , IncidentCubeIndex< K > >::type _IncidentCube( Element< K > e ); - template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D==K >::type _CellOffset( Element< K > e , IncidentCubeIndex< K > d , int* x ); - template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D!=K && K!=0 >::type _CellOffset( Element< K > e , IncidentCubeIndex< K > d , int* x ); - template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D!=K && K==0 >::type _CellOffset( Element< K > e , IncidentCubeIndex< K > d , int* x ); + template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D==K >::type _CellOffset( Element< K > e , IncidentCubeIndex< K > d , int* x ); + template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D!=K && K!=0 >::type _CellOffset( Element< K > e , IncidentCubeIndex< K > d , int* x ); + template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D!=K && K==0 >::type _CellOffset( Element< K > e , IncidentCubeIndex< K > d , int* x ); - template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D==K && K==0 , unsigned int >::type _CellOffset( Element< K > e , IncidentCubeIndex< K > d ); - template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D==K && K!=0 , unsigned int >::type _CellOffset( Element< K > e , IncidentCubeIndex< K > d ); - template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D!=K && K!=0 , unsigned int >::type _CellOffset( Element< K > e , IncidentCubeIndex< K > d ); - template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D!=K && K==0 , unsigned int >::type _CellOffset( Element< K > e , IncidentCubeIndex< K > d ); + template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D==K && K==0 , unsigned int >::type _CellOffset( Element< K > e , IncidentCubeIndex< K > d ); + template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D==K && K!=0 , unsigned int >::type _CellOffset( Element< K > e , IncidentCubeIndex< K > d ); + template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D!=K && K!=0 , unsigned int >::type _CellOffset( Element< K > e , IncidentCubeIndex< K > d ); + template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D!=K && K==0 , unsigned int >::type _CellOffset( Element< K > e , IncidentCubeIndex< K > d ); - template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D==K , Element< K > >::type _IncidentElement( Element< K > e , IncidentCubeIndex< K > d ); - template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D!=K && _D!=0 && K!=0 , Element< K > >::type _IncidentElement( Element< K > e , IncidentCubeIndex< K > d ); - template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D!=K && _D!=0 && K==0 , Element< K > >::type _IncidentElement( Element< K > e , IncidentCubeIndex< K > d ); + template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D==K , Element< K > >::type _IncidentElement( Element< K > e , IncidentCubeIndex< K > d ); + template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D!=K && _D!=0 && K!=0 , Element< K > >::type _IncidentElement( Element< K > e , IncidentCubeIndex< K > d ); + template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D!=K && _D!=0 && K==0 , Element< K > >::type _IncidentElement( Element< K > e , IncidentCubeIndex< K > d ); - template< unsigned int _D=D > static typename std::enable_if< _D!=1 >::type _FactorOrientation( Element< D-1 > e , unsigned int& dim , Direction& dir ); - template< unsigned int _D=D > static typename std::enable_if< _D==1 >::type _FactorOrientation( Element< D-1 > e , unsigned int& dim , Direction& dir ); + template< unsigned int _D=D > static typename std::enable_if< _D!=1 >::type _FactorOrientation( Element< D-1 > e , unsigned int& dim , Direction& dir ); + template< unsigned int _D=D > static typename std::enable_if< _D==1 >::type _FactorOrientation( Element< D-1 > e , unsigned int& dim , Direction& dir ); - template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D!=K && K!=0 , unsigned int >::type _ElementMCIndex( Element< K > element , unsigned int mcIndex ); - template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D!=K && K==0 , unsigned int >::type _ElementMCIndex( Element< K > element , unsigned int mcIndex ); - template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D==K , unsigned int >::type _ElementMCIndex( Element< K > element , unsigned int mcIndex ); + template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D!=K && K!=0 , unsigned int >::type _ElementMCIndex( Element< K > element , unsigned int mcIndex ); + template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D!=K && K==0 , unsigned int >::type _ElementMCIndex( Element< K > element , unsigned int mcIndex ); + template< unsigned int K , unsigned int _D=D > static typename std::enable_if< _D==K , unsigned int >::type _ElementMCIndex( Element< K > element , unsigned int mcIndex ); - template< unsigned int DD > friend struct Cube; - }; + template< unsigned int DD > friend struct Cube; + }; - // Specialized class for extracting iso-curves from a square - struct MarchingSquares - { - const static unsigned int MAX_EDGES=2; - static const int edges[1<::ElementNum< 0 >()][2*MAX_EDGES+1]; - static int AddEdgeIndices( unsigned char mcIndex , int* edges); - }; - - /////////////////// - // Cube::Element // - /////////////////// - template< unsigned int D > template< unsigned int K > - Cube< D >::Element< K >::Element( unsigned int idx ) : index( idx ){} - template< unsigned int D > template< unsigned int K > - Cube< D >::Element< K >::Element( Direction dir , unsigned int coIndex ){ _setElement( dir , coIndex ); } - template< unsigned int D > template< unsigned int K > template< unsigned int DK > - Cube< D >::Element< K >::Element( Element< DK > subCube , typename Cube< DK >::template Element< K > subElement ) - { - static_assert( DK>=K , "[ERROR] Element::Element: sub-cube dimension cannot be smaller than the sub-element dimension" ); - static_assert( DK<=D , "[ERROR] Element::Element: sub-cube dimension cannot be larger than the cube dimension" ); - _setElement( subCube , subElement ); - } - template< unsigned int D > template< unsigned int K > - Cube< D >::Element< K >::Element( const Direction dirs[D] ){ _setElement( dirs ); } + // Specialized class for extracting iso-curves from a square + struct MarchingSquares + { + const static unsigned int MAX_EDGES=2; + static const int edges[1<::ElementNum< 0 >()][2*MAX_EDGES+1]; + static int AddEdgeIndices( unsigned char mcIndex , int* edges); + }; - template< unsigned int D > template< unsigned int K > template< unsigned int KD > - typename std::enable_if< (D>KD) && (KD>K) && K!=0 >::type Cube< D >::Element< K >::_setElement( typename Cube< D >::template Element< KD > subCube , typename Cube< KD >::template Element< K > subElement ) - { - Direction dir ; unsigned int coIndex; - subCube.factor( dir , coIndex ); - // If the sub-cube lies entirely in the back/front, we can compute the element in the smaller cube. - if( dir==BACK || dir==FRONT ) + /////////////////// + // Cube::Element // + /////////////////// + template< unsigned int D > template< unsigned int K > + Cube< D >::Element< K >::Element( unsigned int idx ) : index( idx ){} + template< unsigned int D > template< unsigned int K > + Cube< D >::Element< K >::Element( Direction dir , unsigned int coIndex ){ _setElement( dir , coIndex ); } + template< unsigned int D > template< unsigned int K > template< unsigned int DK > + Cube< D >::Element< K >::Element( Element< DK > subCube , typename Cube< DK >::template Element< K > subElement ) { - typename Cube< D-1 >::template Element< KD > _subCube( coIndex ); - typename Cube< D-1 >::template Element< K > _element( _subCube , subElement ); - *this = Element( dir , _element.index ); + static_assert( DK>=K , "[ERROR] Element::Element: sub-cube dimension cannot be smaller than the sub-element dimension" ); + static_assert( DK<=D , "[ERROR] Element::Element: sub-cube dimension cannot be larger than the cube dimension" ); + _setElement( subCube , subElement ); } - else - { - typename Cube< D-1 >::template Element< KD-1 > _subCube( coIndex ); + template< unsigned int D > template< unsigned int K > + Cube< D >::Element< K >::Element( const Direction dirs[D] ){ _setElement( dirs ); } - Direction _dir ; unsigned int _coIndex; - subElement.factor( _dir , _coIndex ); - // If the sub-element lies entirely in the back/front, we can compute the element in the smaller cube. - if( _dir==BACK || _dir==FRONT ) + template< unsigned int D > template< unsigned int K > template< unsigned int KD > + typename std::enable_if< (D>KD) && (KD>K) && K!=0 >::type Cube< D >::Element< K >::_setElement( typename Cube< D >::template Element< KD > subCube , typename Cube< KD >::template Element< K > subElement ) + { + Direction dir ; unsigned int coIndex; + subCube.factor( dir , coIndex ); + // If the sub-cube lies entirely in the back/front, we can compute the element in the smaller cube. + if( dir==BACK || dir==FRONT ) { - typename Cube< KD-1 >::template Element< K > _subElement( _coIndex ); - typename Cube< D-1 >::template Element< K > _element( _subCube , _subElement ); - *this = Element( _dir , _element.index ); + typename Cube< D-1 >::template Element< KD > _subCube( coIndex ); + typename Cube< D-1 >::template Element< K > _element( _subCube , subElement ); + *this = Element( dir , _element.index ); } - // Otherwise else { - typename Cube< KD-1 >::template Element< K-1 > _subElement( _coIndex ); - typename Cube< D-1 >::template Element< K-1 > _element( _subCube , _subElement ); - *this = Element( _dir , _element.index ); + typename Cube< D-1 >::template Element< KD-1 > _subCube( coIndex ); + + Direction _dir ; unsigned int _coIndex; + subElement.factor( _dir , _coIndex ); + // If the sub-element lies entirely in the back/front, we can compute the element in the smaller cube. + if( _dir==BACK || _dir==FRONT ) + { + typename Cube< KD-1 >::template Element< K > _subElement( _coIndex ); + typename Cube< D-1 >::template Element< K > _element( _subCube , _subElement ); + *this = Element( _dir , _element.index ); + } + // Otherwise + else + { + typename Cube< KD-1 >::template Element< K-1 > _subElement( _coIndex ); + typename Cube< D-1 >::template Element< K-1 > _element( _subCube , _subElement ); + *this = Element( _dir , _element.index ); + } } } - } - template< unsigned int D > template< unsigned int K > template< unsigned int KD > - typename std::enable_if< (D>KD) && (KD>K) && K==0 >::type Cube< D >::Element< K >::_setElement( typename Cube< D >::template Element< KD > subCube , typename Cube< KD >::template Element< K > subElement ) - { - Direction dir ; unsigned int coIndex; - subCube.factor( dir , coIndex ); - // If the sub-cube lies entirely in the back/front, we can compute the element in the smaller cube. - if( dir==BACK || dir==FRONT ) + template< unsigned int D > template< unsigned int K > template< unsigned int KD > + typename std::enable_if< (D>KD) && (KD>K) && K==0 >::type Cube< D >::Element< K >::_setElement( typename Cube< D >::template Element< KD > subCube , typename Cube< KD >::template Element< K > subElement ) { - typename Cube< D-1 >::template Element< KD > _subCube( coIndex ); - typename Cube< D-1 >::template Element< K > _element( _subCube , subElement ); - *this = Element( dir , _element.index ); - } - else - { - typename Cube< D-1 >::template Element< KD-1 > _subCube( coIndex ); - - Direction _dir ; unsigned int _coIndex; - subElement.factor( _dir , _coIndex ); - // If the sub-element lies entirely in the back/front, we can compute the element in the smaller cube. - if( _dir==BACK || _dir==FRONT ) + Direction dir ; unsigned int coIndex; + subCube.factor( dir , coIndex ); + // If the sub-cube lies entirely in the back/front, we can compute the element in the smaller cube. + if( dir==BACK || dir==FRONT ) + { + typename Cube< D-1 >::template Element< KD > _subCube( coIndex ); + typename Cube< D-1 >::template Element< K > _element( _subCube , subElement ); + *this = Element( dir , _element.index ); + } + else { - typename Cube< KD-1 >::template Element< K > _subElement( _coIndex ); - typename Cube< D-1 >::template Element< K > _element( _subCube , _subElement ); - *this = Element( _dir , _element.index ); + typename Cube< D-1 >::template Element< KD-1 > _subCube( coIndex ); + + Direction _dir ; unsigned int _coIndex; + subElement.factor( _dir , _coIndex ); + // If the sub-element lies entirely in the back/front, we can compute the element in the smaller cube. + if( _dir==BACK || _dir==FRONT ) + { + typename Cube< KD-1 >::template Element< K > _subElement( _coIndex ); + typename Cube< D-1 >::template Element< K > _element( _subCube , _subElement ); + *this = Element( _dir , _element.index ); + } } } - } - template< unsigned int D > template< unsigned int K > template< unsigned int KD > - typename std::enable_if< (D==KD) && (KD>K) >::type Cube< D >::Element< K >::_setElement( typename Cube< D >::template Element< KD > subCube , typename Cube< KD >::template Element< K > subElement ){ *this = subElement; } - template< unsigned int D > template< unsigned int K > template< unsigned int KD > - typename std::enable_if< (KD==K) >::type Cube< D >::Element< K >::_setElement( typename Cube< D >::template Element< KD > subCube , typename Cube< KD >::template Element< K > subElement ){ *this = subCube; } + template< unsigned int D > template< unsigned int K > template< unsigned int KD > + typename std::enable_if< (D==KD) && (KD>K) >::type Cube< D >::Element< K >::_setElement( typename Cube< D >::template Element< KD > subCube , typename Cube< KD >::template Element< K > subElement ){ *this = subElement; } + template< unsigned int D > template< unsigned int K > template< unsigned int KD > + typename std::enable_if< (KD==K) >::type Cube< D >::Element< K >::_setElement( typename Cube< D >::template Element< KD > subCube , typename Cube< KD >::template Element< K > subElement ){ *this = subCube; } - template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > - typename std::enable_if< _D!=0 && _K!=0 >::type Cube< D >::Element< K >::_setElement( Direction dir , unsigned int coIndex ) - { - switch( dir ) + template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > + typename std::enable_if< _D!=0 && _K!=0 >::type Cube< D >::Element< K >::_setElement( Direction dir , unsigned int coIndex ) { + switch( dir ) + { case BACK: index = coIndex ; break; case CROSS: index = coIndex + HyperCube::ElementNum< D-1 , K >::Value ; break; case FRONT: index = coIndex + HyperCube::ElementNum< D-1 , K >::Value + HyperCube::ElementNum< D-1 , K-1 >::Value ; break; default: ERROR_OUT( "Bad direction: " , dir ); + } } - } - template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > - typename std::enable_if< _D!=0 && _K==0 >::type Cube< D >::Element< K >::_setElement( Direction dir , unsigned int coIndex ) - { - switch( dir ) + template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > + typename std::enable_if< _D!=0 && _K==0 >::type Cube< D >::Element< K >::_setElement( Direction dir , unsigned int coIndex ) { + switch( dir ) + { case BACK: index = coIndex ; break; case FRONT: index = coIndex + HyperCube::ElementNum< D-1 , K >::Value ; break; default: ERROR_OUT( "Bad direction: " , dir ); + } } - } - template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > - typename std::enable_if< _D==0 && _K==0 >::type Cube< D >::Element< K >::_setElement( Direction dir , unsigned int coIndex ){ index = coIndex; } + template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > + typename std::enable_if< _D==0 && _K==0 >::type Cube< D >::Element< K >::_setElement( Direction dir , unsigned int coIndex ){ index = coIndex; } - template< unsigned int D > template< unsigned int K > template< unsigned int _D > - typename std::enable_if< _D!=0 >::type Cube< D >::Element< K>::_setElement( const Direction* dirs ) - { - if( dirs[D-1]==CROSS ) *this = Element( dirs[D-1] , typename Cube< D-1 >::template Element< K-1 >( dirs ).index ); - else *this = Element( dirs[D-1] , typename Cube< D-1 >::template Element< K >( dirs ).index ); - } - template< unsigned int D > template< unsigned int K > template< unsigned int _D > - typename std::enable_if< _D==0 >::type Cube< D >::Element< K>::_setElement( const Direction* dirs ){} + template< unsigned int D > template< unsigned int K > template< unsigned int _D > + typename std::enable_if< _D!=0 >::type Cube< D >::Element< K>::_setElement( const Direction* dirs ) + { + if( dirs[D-1]==CROSS ) *this = Element( dirs[D-1] , typename Cube< D-1 >::template Element< K-1 >( dirs ).index ); + else *this = Element( dirs[D-1] , typename Cube< D-1 >::template Element< K >( dirs ).index ); + } + template< unsigned int D > template< unsigned int K > template< unsigned int _D > + typename std::enable_if< _D==0 >::type Cube< D >::Element< K>::_setElement( const Direction* dirs ){} - template< unsigned int D > template< unsigned int K > - void Cube< D >::Element< K >::print( FILE* fp ) const - { - Direction dirs[D==0?1:D]; - directions( dirs ); - for( int d=0 ; d template< unsigned int K > + void Cube< D >::Element< K >::print( FILE* fp ) const + { + Direction dirs[D==0?1:D]; + directions( dirs ); + for( int d=0 ; d template< unsigned int K > - void Cube< D >::Element< K >::factor( Direction& dir , unsigned int& coIndex ) const { _factor( dir , coIndex ); } + template< unsigned int D > template< unsigned int K > + void Cube< D >::Element< K >::factor( Direction& dir , unsigned int& coIndex ) const { _factor( dir , coIndex ); } - template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > - typename std::enable_if< _D!=_K && _K!=0 >::type Cube< D >::Element< K >::_factor( Direction& dir , unsigned int& coIndex ) const - { - if ( index::Value ) dir = BACK , coIndex = index; - else if( index::Value + HyperCube::ElementNum< D-1 , K-1 >::Value ) dir = CROSS , coIndex = index - HyperCube::ElementNum< D-1 , K >::Value; - else dir = FRONT , coIndex = index - HyperCube::ElementNum< D-1 , K >::Value - HyperCube::ElementNum< D-1 , K-1 >::Value; - } - template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > - typename std::enable_if< _D!=_K && _K==0 >::type Cube< D >::Element< K >::_factor( Direction& dir , unsigned int& coIndex ) const - { - if ( index::Value ) dir = BACK , coIndex = index; - else dir = FRONT , coIndex = index - HyperCube::ElementNum< D-1 , K >::Value; - } - template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > - typename std::enable_if< _D==_K >::type Cube< D >::Element< K >::_factor( Direction& dir , unsigned int& coIndex ) const { dir=CROSS , coIndex=0; } + template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > + typename std::enable_if< _D!=_K && _K!=0 >::type Cube< D >::Element< K >::_factor( Direction& dir , unsigned int& coIndex ) const + { + if ( index::Value ) dir = BACK , coIndex = index; + else if( index::Value + HyperCube::ElementNum< D-1 , K-1 >::Value ) dir = CROSS , coIndex = index - HyperCube::ElementNum< D-1 , K >::Value; + else dir = FRONT , coIndex = index - HyperCube::ElementNum< D-1 , K >::Value - HyperCube::ElementNum< D-1 , K-1 >::Value; + } + template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > + typename std::enable_if< _D!=_K && _K==0 >::type Cube< D >::Element< K >::_factor( Direction& dir , unsigned int& coIndex ) const + { + if ( index::Value ) dir = BACK , coIndex = index; + else dir = FRONT , coIndex = index - HyperCube::ElementNum< D-1 , K >::Value; + } + template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > + typename std::enable_if< _D==_K >::type Cube< D >::Element< K >::_factor( Direction& dir , unsigned int& coIndex ) const { dir=CROSS , coIndex=0; } - template< unsigned int D > template< unsigned int K > - Direction Cube< D >::Element< K >::direction( void ) const - { - Direction dir ; unsigned int coIndex; - factor( dir , coIndex ); - return dir; - } - template< unsigned int D > template< unsigned int K > - unsigned int Cube< D >::Element< K >::coIndex( void ) const - { - Direction dir ; unsigned int coIndex; - factor( dir , coIndex ); - return coIndex; - } + template< unsigned int D > template< unsigned int K > + Direction Cube< D >::Element< K >::direction( void ) const + { + Direction dir ; unsigned int coIndex; + factor( dir , coIndex ); + return dir; + } + template< unsigned int D > template< unsigned int K > + unsigned int Cube< D >::Element< K >::coIndex( void ) const + { + Direction dir ; unsigned int coIndex; + factor( dir , coIndex ); + return coIndex; + } - template< unsigned int D > template< unsigned int K > - void Cube< D >::Element< K >::directions( Direction* dirs ) const { _directions( dirs ); } - template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > - typename std::enable_if< (_D>_K) && _K!=0 >::type Cube< D >::Element< K >::_directions( Direction* dirs ) const - { - unsigned int coIndex; - factor( dirs[D-1] , coIndex ); - if( dirs[D-1]==CROSS ) typename Cube< D-1 >::template Element< K-1 >( coIndex ).directions( dirs ); - else typename Cube< D-1 >::template Element< K >( coIndex ).directions( dirs ); - } - template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > - typename std::enable_if< (_D>_K) && _K==0 >::type Cube< D >::Element< K >::_directions( Direction* dirs ) const - { - unsigned int coIndex; - factor( dirs[D-1] , coIndex ); - if( dirs[D-1]==FRONT || dirs[D-1]==BACK ) typename Cube< D-1 >::template Element< K >( coIndex ).directions( dirs ); - } + template< unsigned int D > template< unsigned int K > + void Cube< D >::Element< K >::directions( Direction* dirs ) const { _directions( dirs ); } + template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > + typename std::enable_if< (_D>_K) && _K!=0 >::type Cube< D >::Element< K >::_directions( Direction* dirs ) const + { + unsigned int coIndex; + factor( dirs[D-1] , coIndex ); + if( dirs[D-1]==CROSS ) typename Cube< D-1 >::template Element< K-1 >( coIndex ).directions( dirs ); + else typename Cube< D-1 >::template Element< K >( coIndex ).directions( dirs ); + } + template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > + typename std::enable_if< (_D>_K) && _K==0 >::type Cube< D >::Element< K >::_directions( Direction* dirs ) const + { + unsigned int coIndex; + factor( dirs[D-1] , coIndex ); + if( dirs[D-1]==FRONT || dirs[D-1]==BACK ) typename Cube< D-1 >::template Element< K >( coIndex ).directions( dirs ); + } - template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > - typename std::enable_if< _D==_K >::type Cube< D >::Element< K >::_directions( Direction* dirs ) const { for( int d=0 ; d template< unsigned int K > template< unsigned int _D , unsigned int _K > + typename std::enable_if< _D==_K >::type Cube< D >::Element< K >::_directions( Direction* dirs ) const { for( int d=0 ; d template< unsigned int K > - typename Cube< D >::template Element< K > Cube< D >::Element< K >::antipodal( void ) const { return _antipodal(); } - template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > -#ifdef _MSC_VER - typename std::enable_if< (_D>_K) && _K!=0 , typename Cube< D >::Element< K > >::type Cube< D >::Element< K >::_antipodal( void ) const -#else // !_MSC_VER - typename std::enable_if< (_D>_K) && _K!=0 , typename Cube< D >::template Element< K > >::type Cube< D >::Element< K >::_antipodal( void ) const -#endif // _MSC_VER - { - Direction dir ; unsigned int coIndex; - factor( dir , coIndex ); - if ( dir==CROSS ) return Element< K >( CROSS , typename Cube< D-1 >::template Element< K-1 >( coIndex ).antipodal().index ); - else if( dir==FRONT ) return Element< K >( BACK , typename Cube< D-1 >::template Element< K >( coIndex ).antipodal().index ); - else if( dir==BACK ) return Element< K >( FRONT , typename Cube< D-1 >::template Element< K >( coIndex ).antipodal().index ); - return Element< K >(); - } - template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > + template< unsigned int D > template< unsigned int K > + typename Cube< D >::template Element< K > Cube< D >::Element< K >::antipodal( void ) const { return _antipodal(); } + template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > + typename std::enable_if< (_D>_K) && _K!=0 , typename Cube< D >::template Element< K > >::type Cube< D >::Element< K >::_antipodal( void ) const + { + Direction dir ; unsigned int coIndex; + factor( dir , coIndex ); + if ( dir==CROSS ) return Element< K >( CROSS , typename Cube< D-1 >::template Element< K-1 >( coIndex ).antipodal().index ); + else if( dir==FRONT ) return Element< K >( BACK , typename Cube< D-1 >::template Element< K >( coIndex ).antipodal().index ); + else if( dir==BACK ) return Element< K >( FRONT , typename Cube< D-1 >::template Element< K >( coIndex ).antipodal().index ); + return Element< K >(); + } + template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > #ifdef _MSC_VER - typename std::enable_if< (_D>_K) && _K==0 , typename Cube< D >::Element< K > >::type Cube< D >::Element< K >::_antipodal( void ) const + typename std::enable_if< (_D>_K) && _K==0 , typename Cube< D >::Element< K > >::type Cube< D >::Element< K >::_antipodal( void ) const #else // !_MSC_VER - typename std::enable_if< (_D>_K) && _K==0 , typename Cube< D >::template Element< K > >::type Cube< D >::Element< K >::_antipodal( void ) const + typename std::enable_if< (_D>_K) && _K==0 , typename Cube< D >::template Element< K > >::type Cube< D >::Element< K >::_antipodal( void ) const #endif // _MSC_VER - { - Direction dir ; unsigned int coIndex; - factor( dir , coIndex ); - if ( dir==FRONT ) return Element< K >( BACK , typename Cube< D-1 >::template Element< K >( coIndex ).antipodal().index ); - else if( dir==BACK ) return Element< K >( FRONT , typename Cube< D-1 >::template Element< K >( coIndex ).antipodal().index ); - return Element< K >(); - } - template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > + { + Direction dir ; unsigned int coIndex; + factor( dir , coIndex ); + if ( dir==FRONT ) return Element< K >( BACK , typename Cube< D-1 >::template Element< K >( coIndex ).antipodal().index ); + else if( dir==BACK ) return Element< K >( FRONT , typename Cube< D-1 >::template Element< K >( coIndex ).antipodal().index ); + return Element< K >(); + } + template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > #ifdef _MSC_VER - typename std::enable_if< _D==_K , typename Cube< D >::Element< K > >::type Cube< D >::Element< K >::_antipodal( void ) const { return *this; } + typename std::enable_if< _D==_K , typename Cube< D >::Element< K > >::type Cube< D >::Element< K >::_antipodal( void ) const { return *this; } #else // !_MSC_VER - typename std::enable_if< _D==_K , typename Cube< D >::template Element< K > >::type Cube< D >::Element< K >::_antipodal( void ) const { return *this; } + typename std::enable_if< _D==_K , typename Cube< D >::template Element< K > >::type Cube< D >::Element< K >::_antipodal( void ) const { return *this; } #endif // _MSC_VER - ////////// - // Cube // - ////////// - template< unsigned int D > template< unsigned int K1 , unsigned int K2 > - bool Cube< D >::Overlap( Element< K1 > e1 , Element< K2 > e2 ){ return _Overlap( e1 , e2 ); } - template< unsigned int D > template< unsigned int K1 , unsigned int K2 > - typename std::enable_if< (K1>=K2) , bool >::type Cube< D >::_Overlap( Element< K1 > e1 , Element< K2 > e2 ) - { - Direction dir1[ D ] , dir2[ D ]; - e1.directions( dir1 ) , e2.directions( dir2 ); - for( int d=0 ; d template< unsigned int K1 , unsigned int K2 > - typename std::enable_if< (K1< K2) , bool >::type Cube< D >::_Overlap( Element< K1 > e1 , Element< K2 > e2 ){ return _Overlap( e2 , e1 ); } + ////////// + // Cube // + ////////// + template< unsigned int D > template< unsigned int K1 , unsigned int K2 > + bool Cube< D >::Overlap( Element< K1 > e1 , Element< K2 > e2 ){ return _Overlap( e1 , e2 ); } + template< unsigned int D > template< unsigned int K1 , unsigned int K2 > + typename std::enable_if< (K1>=K2) , bool >::type Cube< D >::_Overlap( Element< K1 > e1 , Element< K2 > e2 ) + { + Direction dir1[ D ] , dir2[ D ]; + e1.directions( dir1 ) , e2.directions( dir2 ); + for( int d=0 ; d template< unsigned int K1 , unsigned int K2 > + typename std::enable_if< (K1< K2) , bool >::type Cube< D >::_Overlap( Element< K1 > e1 , Element< K2 > e2 ){ return _Overlap( e2 , e1 ); } - template< unsigned int D > template< unsigned int K1 , unsigned int K2 > - void Cube< D >::OverlapElements( Element< K1 > e , Element< K2 >* es ){ _OverlapElements( e , es ); } - template< unsigned int D > template< unsigned int K1 , unsigned int K2 > - typename std::enable_if< (K1>=K2) >::type Cube< D >::_OverlapElements( Element< K1 > e , Element< K2 >* es ) - { - for( typename Cube< K1 >::template Element< K2 > _e ; _e::template ElementNum< K2 >() ; _e++ ) es[_e.index] = Element< K2 >( e , _e ); - } - template< unsigned int D > template< unsigned int K1 , unsigned int K2 > - typename std::enable_if< (K1< K2) && D==K2 >::type Cube< D >::_OverlapElements( Element< K1 > e , Element< K2 >* es ) - { - es[0] = Element< D >(); - } - template< unsigned int D > template< unsigned int K1 , unsigned int K2 > - typename std::enable_if< (K1< K2) && D!=K2 && K1!=0 >::type Cube< D >::_OverlapElements( Element< K1 > e , Element< K2 >* es ) - { - Direction dir = e.direction() ; unsigned int coIndex; - e.factor( dir , coIndex ); - if( dir==FRONT || dir==BACK ) + template< unsigned int D > template< unsigned int K1 , unsigned int K2 > + void Cube< D >::OverlapElements( Element< K1 > e , Element< K2 >* es ){ _OverlapElements( e , es ); } + template< unsigned int D > template< unsigned int K1 , unsigned int K2 > + typename std::enable_if< (K1>=K2) >::type Cube< D >::_OverlapElements( Element< K1 > e , Element< K2 >* es ) { - typename Cube< D-1 >::template Element< K2 > _es1[ HyperCube::OverlapElementNum< D-1 , K1 , K2 >::Value ]; - typename Cube< D-1 >::template Element< K2-1 > _es2[ HyperCube::OverlapElementNum< D-1 , K1 , K2-1 >::Value ]; - Cube< D-1 >::OverlapElements( typename Cube< D-1 >::template Element< K1 >( coIndex ) , _es1 ); - Cube< D-1 >::OverlapElements( typename Cube< D-1 >::template Element< K1 >( coIndex ) , _es2 ); - for( unsigned int i=0 ; i::Value ; i++ ) es[i] = typename Cube< D >::template Element< K2 >( dir , _es1[i].index ); - es += HyperCube::OverlapElementNum< D-1 , K1 , K2 >::Value; - for( unsigned int i=0 ; i::Value ; i++ ) es[i] = typename Cube< D >::template Element< K2 >( CROSS , _es2[i].index ); + for( typename Cube< K1 >::template Element< K2 > _e ; _e::template ElementNum< K2 >() ; _e++ ) es[_e.index] = Element< K2 >( e , _e ); } - else if( dir==CROSS ) + template< unsigned int D > template< unsigned int K1 , unsigned int K2 > + typename std::enable_if< (K1< K2) && D==K2 >::type Cube< D >::_OverlapElements( Element< K1 > e , Element< K2 >* es ) { - typename Cube< D-1 >::template Element< K2-1 > _es1[ HyperCube::OverlapElementNum< D-1 , K1-1 , K2-1 >::Value ]; - Cube< D-1 >::OverlapElements( typename Cube< D-1 >::template Element< K1-1 >( coIndex ) , _es1 ); - for( unsigned int i=0 ; i::Value ; i++ ) es[i] = typename Cube< D >::template Element< K2 >( CROSS , _es1[i].index ); + es[0] = Element< D >(); } - } - template< unsigned int D > template< unsigned int K1 , unsigned int K2 > - typename std::enable_if< (K1< K2) && D!=K2 && K1==0 >::type Cube< D >::_OverlapElements( Element< K1 > e , Element< K2 >* es ) - { - Direction dir = e.direction() ; unsigned int coIndex; - e.factor( dir , coIndex ); - if( dir==FRONT || dir==BACK ) - { - typename Cube< D-1 >::template Element< K2 > _es1[ HyperCube::OverlapElementNum< D-1 , K1 , K2 >::Value ]; - typename Cube< D-1 >::template Element< K2-1 > _es2[ HyperCube::OverlapElementNum< D-1 , K1 , K2-1 >::Value ]; - Cube< D-1 >::OverlapElements( typename Cube< D-1 >::template Element< K1 >( coIndex ) , _es1 ); - Cube< D-1 >::OverlapElements( typename Cube< D-1 >::template Element< K1 >( coIndex ) , _es2 ); - for( unsigned int i=0 ; i::Value ; i++ ) es[i] = typename Cube< D >::template Element< K2 >( dir , _es1[i].index ); - es += HyperCube::OverlapElementNum< D-1 , K1 , K2 >::Value; - for( unsigned int i=0 ; i::Value ; i++ ) es[i] = typename Cube< D >::template Element< K2 >( CROSS , _es2[i].index ); + template< unsigned int D > template< unsigned int K1 , unsigned int K2 > + typename std::enable_if< (K1< K2) && D!=K2 && K1!=0 >::type Cube< D >::_OverlapElements( Element< K1 > e , Element< K2 >* es ) + { + Direction dir = e.direction() ; unsigned int coIndex; + e.factor( dir , coIndex ); + if( dir==FRONT || dir==BACK ) + { + typename Cube< D-1 >::template Element< K2 > _es1[ HyperCube::OverlapElementNum< D-1 , K1 , K2 >::Value ]; + typename Cube< D-1 >::template Element< K2-1 > _es2[ HyperCube::OverlapElementNum< D-1 , K1 , K2-1 >::Value ]; + Cube< D-1 >::OverlapElements( typename Cube< D-1 >::template Element< K1 >( coIndex ) , _es1 ); + Cube< D-1 >::OverlapElements( typename Cube< D-1 >::template Element< K1 >( coIndex ) , _es2 ); + for( unsigned int i=0 ; i::Value ; i++ ) es[i] = typename Cube< D >::template Element< K2 >( dir , _es1[i].index ); + es += HyperCube::OverlapElementNum< D-1 , K1 , K2 >::Value; + for( unsigned int i=0 ; i::Value ; i++ ) es[i] = typename Cube< D >::template Element< K2 >( CROSS , _es2[i].index ); + } + else if( dir==CROSS ) + { + typename Cube< D-1 >::template Element< K2-1 > _es1[ HyperCube::OverlapElementNum< D-1 , K1-1 , K2-1 >::Value ]; + Cube< D-1 >::OverlapElements( typename Cube< D-1 >::template Element< K1-1 >( coIndex ) , _es1 ); + for( unsigned int i=0 ; i::Value ; i++ ) es[i] = typename Cube< D >::template Element< K2 >( CROSS , _es1[i].index ); + } + } + template< unsigned int D > template< unsigned int K1 , unsigned int K2 > + typename std::enable_if< (K1< K2) && D!=K2 && K1==0 >::type Cube< D >::_OverlapElements( Element< K1 > e , Element< K2 >* es ) + { + Direction dir = e.direction() ; unsigned int coIndex; + e.factor( dir , coIndex ); + if( dir==FRONT || dir==BACK ) + { + typename Cube< D-1 >::template Element< K2 > _es1[ HyperCube::OverlapElementNum< D-1 , K1 , K2 >::Value ]; + typename Cube< D-1 >::template Element< K2-1 > _es2[ HyperCube::OverlapElementNum< D-1 , K1 , K2-1 >::Value ]; + Cube< D-1 >::OverlapElements( typename Cube< D-1 >::template Element< K1 >( coIndex ) , _es1 ); + Cube< D-1 >::OverlapElements( typename Cube< D-1 >::template Element< K1 >( coIndex ) , _es2 ); + for( unsigned int i=0 ; i::Value ; i++ ) es[i] = typename Cube< D >::template Element< K2 >( dir , _es1[i].index ); + es += HyperCube::OverlapElementNum< D-1 , K1 , K2 >::Value; + for( unsigned int i=0 ; i::Value ; i++ ) es[i] = typename Cube< D >::template Element< K2 >( CROSS , _es2[i].index ); + } } - } - template< unsigned int D > template< unsigned int K > - typename Cube< D >::template IncidentCubeIndex< K > Cube< D >::IncidentCube( Element< K > e ){ return _IncidentCube( e ); } - template< unsigned int D > template< unsigned int K , unsigned int _D > + template< unsigned int D > template< unsigned int K > + typename Cube< D >::template IncidentCubeIndex< K > Cube< D >::IncidentCube( Element< K > e ){ return _IncidentCube( e ); } + template< unsigned int D > template< unsigned int K , unsigned int _D > #ifdef _MSC_VER - typename std::enable_if< _D==K , typename Cube< D >::IncidentCubeIndex< K > >::type Cube< D >::_IncidentCube( Element< K > e ){ return IncidentCubeIndex< D >(); } + typename std::enable_if< _D==K , typename Cube< D >::IncidentCubeIndex< K > >::type Cube< D >::_IncidentCube( Element< K > e ){ return IncidentCubeIndex< D >(); } #else // !_MSC_VER - typename std::enable_if< _D==K , typename Cube< D >::template IncidentCubeIndex< K > >::type Cube< D >::_IncidentCube( Element< K > e ){ return IncidentCubeIndex< D >(); } + typename std::enable_if< _D==K , typename Cube< D >::template IncidentCubeIndex< K > >::type Cube< D >::_IncidentCube( Element< K > e ){ return IncidentCubeIndex< D >(); } #endif // _MSC_VER - template< unsigned int D > template< unsigned int K , unsigned int _D > + template< unsigned int D > template< unsigned int K , unsigned int _D > #ifdef _MSC_VER - typename std::enable_if< _D!=K && _D!=0 && K!=0 , typename Cube< D >::IncidentCubeIndex< K > >::type Cube< D >::_IncidentCube( Element< K > e ) + typename std::enable_if< _D!=K && _D!=0 && K!=0 , typename Cube< D >::IncidentCubeIndex< K > >::type Cube< D >::_IncidentCube( Element< K > e ) #else // !_MSC_VER - typename std::enable_if< _D!=K && _D!=0 && K!=0 , typename Cube< D >::template IncidentCubeIndex< K > >::type Cube< D >::_IncidentCube( Element< K > e ) + typename std::enable_if< _D!=K && _D!=0 && K!=0 , typename Cube< D >::template IncidentCubeIndex< K > >::type Cube< D >::_IncidentCube( Element< K > e ) #endif // _MSC_VER - { - Direction dir ; unsigned int coIndex; - e.factor( dir , coIndex ); - if ( dir==CROSS ) return Cube< D-1 >::IncidentCube( typename Cube< D-1 >::template Element< K-1 >( coIndex ) ); - else if( dir==FRONT ) return IncidentCubeIndex< K >( BACK , Cube< D-1 >::IncidentCube( typename Cube< D-1 >::template Element< K >( coIndex ) ).index ); - else return IncidentCubeIndex< K >( FRONT , Cube< D-1 >::IncidentCube( typename Cube< D-1 >::template Element< K >( coIndex ) ).index ); - } - template< unsigned int D > template< unsigned int K , unsigned int _D > + { + Direction dir ; unsigned int coIndex; + e.factor( dir , coIndex ); + if ( dir==CROSS ) return Cube< D-1 >::IncidentCube( typename Cube< D-1 >::template Element< K-1 >( coIndex ) ); + else if( dir==FRONT ) return IncidentCubeIndex< K >( BACK , Cube< D-1 >::IncidentCube( typename Cube< D-1 >::template Element< K >( coIndex ) ).index ); + else return IncidentCubeIndex< K >( FRONT , Cube< D-1 >::IncidentCube( typename Cube< D-1 >::template Element< K >( coIndex ) ).index ); + } + template< unsigned int D > template< unsigned int K , unsigned int _D > #ifdef _MSC_VER - typename std::enable_if< _D!=K && _D!=0 && K==0 , typename Cube< D >::IncidentCubeIndex< K > >::type Cube< D >::_IncidentCube( Element< K > e ) + typename std::enable_if< _D!=K && _D!=0 && K==0 , typename Cube< D >::IncidentCubeIndex< K > >::type Cube< D >::_IncidentCube( Element< K > e ) #else // !_MSC_VER - typename std::enable_if< _D!=K && _D!=0 && K==0 , typename Cube< D >::template IncidentCubeIndex< K > >::type Cube< D >::_IncidentCube( Element< K > e ) + typename std::enable_if< _D!=K && _D!=0 && K==0 , typename Cube< D >::template IncidentCubeIndex< K > >::type Cube< D >::_IncidentCube( Element< K > e ) #endif // _MSC_VER - { - Direction dir ; unsigned int coIndex; - e.factor( dir , coIndex ); - if( dir==FRONT ) return IncidentCubeIndex< K >( BACK , Cube< D-1 >::IncidentCube( typename Cube< D-1 >::template Element< K >( coIndex ) ).index ); - else return IncidentCubeIndex< K >( FRONT , Cube< D-1 >::IncidentCube( typename Cube< D-1 >::template Element< K >( coIndex ) ).index ); - } + { + Direction dir ; unsigned int coIndex; + e.factor( dir , coIndex ); + if( dir==FRONT ) return IncidentCubeIndex< K >( BACK , Cube< D-1 >::IncidentCube( typename Cube< D-1 >::template Element< K >( coIndex ) ).index ); + else return IncidentCubeIndex< K >( FRONT , Cube< D-1 >::IncidentCube( typename Cube< D-1 >::template Element< K >( coIndex ) ).index ); + } - template< unsigned int D > - bool Cube< D >::IsOriented( Element< D-1 > e ) - { - unsigned int dim ; Direction dir; - _FactorOrientation( e , dim , dir ); - return (dir==FRONT) ^ ((D-dim-1)&1); - } - template< unsigned int D > template< unsigned int _D > - typename std::enable_if< _D!=1 >::type Cube< D >::_FactorOrientation( Element< D-1 > e , unsigned int& dim , Direction& dir ) - { - unsigned int coIndex; - e.factor( dir , coIndex ); - if( dir==CROSS ) Cube< D-1 >::template _FactorOrientation( typename Cube< D-1 >::template Element< D-2 >( coIndex ) , dim , dir ); - else dim = D-1; - } - template< unsigned int D > template< unsigned int _D > - typename std::enable_if< _D==1 >::type Cube< D >::_FactorOrientation( Element< D-1 > e , unsigned int& dim , Direction& dir ) - { - unsigned int coIndex; - e.factor( dir , coIndex ); - dim = 0; - } + template< unsigned int D > + bool Cube< D >::IsOriented( Element< D-1 > e ) + { + unsigned int dim ; Direction dir; + _FactorOrientation( e , dim , dir ); + return (dir==FRONT) ^ ((D-dim-1)&1); + } + template< unsigned int D > template< unsigned int _D > + typename std::enable_if< _D!=1 >::type Cube< D >::_FactorOrientation( Element< D-1 > e , unsigned int& dim , Direction& dir ) + { + unsigned int coIndex; + e.factor( dir , coIndex ); + if( dir==CROSS ) Cube< D-1 >::template _FactorOrientation( typename Cube< D-1 >::template Element< D-2 >( coIndex ) , dim , dir ); + else dim = D-1; + } + template< unsigned int D > template< unsigned int _D > + typename std::enable_if< _D==1 >::type Cube< D >::_FactorOrientation( Element< D-1 > e , unsigned int& dim , Direction& dir ) + { + unsigned int coIndex; + e.factor( dir , coIndex ); + dim = 0; + } - template< unsigned int D > template< typename Real > - unsigned int Cube< D >::MCIndex( const Real values[ Cube< D >::ElementNum< 0 >() ] , Real iso ) - { - unsigned int mcIdx = 0; - for( unsigned int c=0 ; c() ; c++ ) if( values[c] template< typename Real > + unsigned int Cube< D >::MCIndex( const Real values[ Cube< D >::ElementNum< 0 >() ] , Real iso ) + { + unsigned int mcIdx = 0; + for( unsigned int c=0 ; c() ; c++ ) if( values[c] template< unsigned int K > - unsigned int Cube< D >::ElementMCIndex( Element< K > element , unsigned int mcIndex ){ return _ElementMCIndex( element , mcIndex ); } + template< unsigned int D > template< unsigned int K > + unsigned int Cube< D >::ElementMCIndex( Element< K > element , unsigned int mcIndex ){ return _ElementMCIndex( element , mcIndex ); } - template< unsigned int D > - bool Cube< D >::HasMCRoots( unsigned int mcIndex ) - { - static const unsigned int Mask = (1<<(1< + bool Cube< D >::HasMCRoots( unsigned int mcIndex ) + { + static const unsigned int Mask = (1<<(1< template< unsigned int K , unsigned int _D > - typename std::enable_if< _D!=K && K!=0 , unsigned int >::type Cube< D >::_ElementMCIndex( Element< K > element , unsigned int mcIndex ) - { - static const unsigned int Mask = ( 1<<( ElementNum< 0 >() / 2 ) ) - 1; - static const unsigned int Shift = ElementNum< 0 >() / 2 , _Shift = Cube< K >::template ElementNum< 0 >() / 2; - unsigned int mcIndex0 = mcIndex & Mask , mcIndex1 = ( mcIndex>>Shift ) & Mask; - Direction dir ; unsigned int coIndex; - element.factor( dir , coIndex ); - if( dir==CROSS ) return Cube< D-1 >::template ElementMCIndex< K-1 >( coIndex , mcIndex0 ) | ( Cube< D-1 >::template ElementMCIndex< K-1 >( coIndex , mcIndex1 )<<_Shift ); - else return Cube< D-1 >::template ElementMCIndex< K >( coIndex , dir==BACK ? mcIndex0 : mcIndex1 ); - } - template< unsigned int D > template< unsigned int K , unsigned int _D > - typename std::enable_if< _D!=K && K==0 , unsigned int >::type Cube< D >::_ElementMCIndex( Element< K > element , unsigned int mcIndex ) - { - static const unsigned int Mask = ( 1<<( ElementNum< 0 >() / 2 ) ) - 1; - static const unsigned int Shift = ElementNum< 0 >() / 2 , _Shift = Cube< K >::template ElementNum< 0 >() / 2; - unsigned int mcIndex0 = mcIndex & Mask , mcIndex1 = ( mcIndex>>Shift ) & Mask; - Direction dir ; unsigned int coIndex; - element.factor( dir , coIndex ); - return Cube< D-1 >::template ElementMCIndex< K >( typename Cube< D-1 >::template Element< K >( coIndex ) , dir==BACK ? mcIndex0 : mcIndex1 ); - } - template< unsigned int D > template< unsigned int K , unsigned int _D > - typename std::enable_if< _D==K , unsigned int >::type Cube< D >::_ElementMCIndex( Element< K > element , unsigned int mcIndex ){ return mcIndex; } - - template< unsigned int D > template< unsigned int K > - void Cube< D >::CellOffset( Element< K > e , IncidentCubeIndex< K > d , int x[D] ){ _CellOffset( e , d , x ); } - template< unsigned int D > template< unsigned int K , unsigned int _D > - typename std::enable_if< _D==K >::type Cube< D >::_CellOffset( Element< K > e , IncidentCubeIndex< K > d , int *x ){ for( int d=0 ; d template< unsigned int K , unsigned int _D > - typename std::enable_if< _D!=K && K!=0 >::type Cube< D >::_CellOffset( Element< K > e , IncidentCubeIndex< K > d , int *x ) - { - Direction eDir , dDir ; unsigned int eCoIndex , dCoIndex; - e.factor( eDir , eCoIndex ) , d.factor( dDir , dCoIndex ); - if ( eDir==CROSS ){ x[D-1] = 0 ; Cube< D-1 >::CellOffset( typename Cube< D-1 >::template Element< K-1 >( eCoIndex ) , d , x ); } - else if( eDir==BACK ){ x[D-1] = -1 + ( dDir==BACK ? 0 : 1 ) ; Cube< D-1 >::CellOffset( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) , x ); } - else if( eDir==FRONT ){ x[D-1] = 0 + ( dDir==BACK ? 0 : 1 ) ; Cube< D-1 >::CellOffset( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) , x ); } - } - template< unsigned int D > template< unsigned int K , unsigned int _D > - typename std::enable_if< _D!=K && K==0 >::type Cube< D >::_CellOffset( Element< K > e , IncidentCubeIndex< K > d , int *x ) - { - Direction eDir , dDir ; unsigned int eCoIndex , dCoIndex; - e.factor( eDir , eCoIndex ) , d.factor( dDir , dCoIndex ); - if ( eDir==BACK ){ x[D-1] = -1 + ( dDir==BACK ? 0 : 1 ) ; Cube< D-1 >::CellOffset( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) , x ); } - else if( eDir==FRONT ){ x[D-1] = 0 + ( dDir==BACK ? 0 : 1 ) ; Cube< D-1 >::CellOffset( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) , x ); } - } + template< unsigned int D > template< unsigned int K , unsigned int _D > + typename std::enable_if< _D!=K && K!=0 , unsigned int >::type Cube< D >::_ElementMCIndex( Element< K > element , unsigned int mcIndex ) + { + static const unsigned int Mask = ( 1<<( ElementNum< 0 >() / 2 ) ) - 1; + static const unsigned int Shift = ElementNum< 0 >() / 2 , _Shift = Cube< K >::template ElementNum< 0 >() / 2; + unsigned int mcIndex0 = mcIndex & Mask , mcIndex1 = ( mcIndex>>Shift ) & Mask; + Direction dir ; unsigned int coIndex; + element.factor( dir , coIndex ); + if( dir==CROSS ) return Cube< D-1 >::template ElementMCIndex< K-1 >( coIndex , mcIndex0 ) | ( Cube< D-1 >::template ElementMCIndex< K-1 >( coIndex , mcIndex1 )<<_Shift ); + else return Cube< D-1 >::template ElementMCIndex< K >( coIndex , dir==BACK ? mcIndex0 : mcIndex1 ); + } + template< unsigned int D > template< unsigned int K , unsigned int _D > + typename std::enable_if< _D!=K && K==0 , unsigned int >::type Cube< D >::_ElementMCIndex( Element< K > element , unsigned int mcIndex ) + { + static const unsigned int Mask = ( 1<<( ElementNum< 0 >() / 2 ) ) - 1; + static const unsigned int Shift = ElementNum< 0 >() / 2 , _Shift = Cube< K >::template ElementNum< 0 >() / 2; + unsigned int mcIndex0 = mcIndex & Mask , mcIndex1 = ( mcIndex>>Shift ) & Mask; + Direction dir ; unsigned int coIndex; + element.factor( dir , coIndex ); + return Cube< D-1 >::template ElementMCIndex< K >( typename Cube< D-1 >::template Element< K >( coIndex ) , dir==BACK ? mcIndex0 : mcIndex1 ); + } + template< unsigned int D > template< unsigned int K , unsigned int _D > + typename std::enable_if< _D==K , unsigned int >::type Cube< D >::_ElementMCIndex( Element< K > element , unsigned int mcIndex ){ return mcIndex; } + + template< unsigned int D > template< unsigned int K > + void Cube< D >::CellOffset( Element< K > e , IncidentCubeIndex< K > d , int x[D] ){ _CellOffset( e , d , x ); } + template< unsigned int D > template< unsigned int K , unsigned int _D > + typename std::enable_if< _D==K >::type Cube< D >::_CellOffset( Element< K > e , IncidentCubeIndex< K > d , int *x ){ for( int d=0 ; d template< unsigned int K , unsigned int _D > + typename std::enable_if< _D!=K && K!=0 >::type Cube< D >::_CellOffset( Element< K > e , IncidentCubeIndex< K > d , int *x ) + { + Direction eDir , dDir ; unsigned int eCoIndex , dCoIndex; + e.factor( eDir , eCoIndex ) , d.factor( dDir , dCoIndex ); + if ( eDir==CROSS ){ x[D-1] = 0 ; Cube< D-1 >::CellOffset( typename Cube< D-1 >::template Element< K-1 >( eCoIndex ) , d , x ); } + else if( eDir==BACK ){ x[D-1] = -1 + ( dDir==BACK ? 0 : 1 ) ; Cube< D-1 >::CellOffset( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) , x ); } + else if( eDir==FRONT ){ x[D-1] = 0 + ( dDir==BACK ? 0 : 1 ) ; Cube< D-1 >::CellOffset( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) , x ); } + } + template< unsigned int D > template< unsigned int K , unsigned int _D > + typename std::enable_if< _D!=K && K==0 >::type Cube< D >::_CellOffset( Element< K > e , IncidentCubeIndex< K > d , int *x ) + { + Direction eDir , dDir ; unsigned int eCoIndex , dCoIndex; + e.factor( eDir , eCoIndex ) , d.factor( dDir , dCoIndex ); + if ( eDir==BACK ){ x[D-1] = -1 + ( dDir==BACK ? 0 : 1 ) ; Cube< D-1 >::CellOffset( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) , x ); } + else if( eDir==FRONT ){ x[D-1] = 0 + ( dDir==BACK ? 0 : 1 ) ; Cube< D-1 >::CellOffset( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) , x ); } + } - template< unsigned int D > template< unsigned int K > - unsigned int Cube< D >::CellOffset( Element< K > e , IncidentCubeIndex< K > d ){ return _CellOffset( e , d ); } - template< unsigned int D > template< unsigned int K , unsigned int _D > - typename std::enable_if< _D==K && K==0 , unsigned int >::type Cube< D >::_CellOffset( Element< K > e , IncidentCubeIndex< K > d ){ return 0; } - template< unsigned int D > template< unsigned int K , unsigned int _D > - typename std::enable_if< _D==K && K!=0 , unsigned int >::type Cube< D >::_CellOffset( Element< K > e , IncidentCubeIndex< K > d ){ return WindowIndex< IsotropicUIntPack< D , 3 > , IsotropicUIntPack< D , 1 > >::Index; } - template< unsigned int D > template< unsigned int K , unsigned int _D > - typename std::enable_if< _D!=K && K!=0 , unsigned int >::type Cube< D >::_CellOffset( Element< K > e , IncidentCubeIndex< K > d ) - { - Direction eDir , dDir ; unsigned int eCoIndex , dCoIndex; - e.factor( eDir , eCoIndex ) , d.factor( dDir , dCoIndex ); - if ( eDir==CROSS ){ return 1 + Cube< D-1 >::template CellOffset( typename Cube< D-1 >::template Element< K-1 >( eCoIndex ) , d ) * 3; } - else if( eDir==BACK ){ return 0 + ( dDir==BACK ? 0 : 1 ) + Cube< D-1 >::template CellOffset( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ) * 3; } - else if( eDir==FRONT ){ return 1 + ( dDir==BACK ? 0 : 1 ) + Cube< D-1 >::template CellOffset( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ) * 3; } - return 0; - } - template< unsigned int D > template< unsigned int K , unsigned int _D > - typename std::enable_if< _D!=K && K==0 , unsigned int >::type Cube< D >::_CellOffset( Element< K > e , IncidentCubeIndex< K > d ) - { - Direction eDir , dDir ; unsigned int eCoIndex , dCoIndex; - e.factor( eDir , eCoIndex ) , d.factor( dDir , dCoIndex ); - if ( eDir==BACK ){ return 0 + ( dDir==BACK ? 0 : 1 ) + Cube< D-1 >::CellOffset( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ) * 3; } - else if( eDir==FRONT ){ return 1 + ( dDir==BACK ? 0 : 1 ) + Cube< D-1 >::CellOffset( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ) * 3; } - return 0; - } + template< unsigned int D > template< unsigned int K > + unsigned int Cube< D >::CellOffset( Element< K > e , IncidentCubeIndex< K > d ){ return _CellOffset( e , d ); } + template< unsigned int D > template< unsigned int K , unsigned int _D > + typename std::enable_if< _D==K && K==0 , unsigned int >::type Cube< D >::_CellOffset( Element< K > e , IncidentCubeIndex< K > d ){ return 0; } + template< unsigned int D > template< unsigned int K , unsigned int _D > + typename std::enable_if< _D==K && K!=0 , unsigned int >::type Cube< D >::_CellOffset( Element< K > e , IncidentCubeIndex< K > d ){ return WindowIndex< IsotropicUIntPack< D , 3 > , IsotropicUIntPack< D , 1 > >::Index; } + template< unsigned int D > template< unsigned int K , unsigned int _D > + typename std::enable_if< _D!=K && K!=0 , unsigned int >::type Cube< D >::_CellOffset( Element< K > e , IncidentCubeIndex< K > d ) + { + Direction eDir , dDir ; unsigned int eCoIndex , dCoIndex; + e.factor( eDir , eCoIndex ) , d.factor( dDir , dCoIndex ); + if ( eDir==CROSS ){ return 1 + Cube< D-1 >::template CellOffset( typename Cube< D-1 >::template Element< K-1 >( eCoIndex ) , d ) * 3; } + else if( eDir==BACK ){ return 0 + ( dDir==BACK ? 0 : 1 ) + Cube< D-1 >::template CellOffset( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ) * 3; } + else if( eDir==FRONT ){ return 1 + ( dDir==BACK ? 0 : 1 ) + Cube< D-1 >::template CellOffset( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ) * 3; } + return 0; + } + template< unsigned int D > template< unsigned int K , unsigned int _D > + typename std::enable_if< _D!=K && K==0 , unsigned int >::type Cube< D >::_CellOffset( Element< K > e , IncidentCubeIndex< K > d ) + { + Direction eDir , dDir ; unsigned int eCoIndex , dCoIndex; + e.factor( eDir , eCoIndex ) , d.factor( dDir , dCoIndex ); + if ( eDir==BACK ){ return 0 + ( dDir==BACK ? 0 : 1 ) + Cube< D-1 >::CellOffset( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ) * 3; } + else if( eDir==FRONT ){ return 1 + ( dDir==BACK ? 0 : 1 ) + Cube< D-1 >::CellOffset( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ) * 3; } + return 0; + } - template< unsigned int D > template< unsigned int K > - typename Cube< D >::template Element< K > Cube< D >::IncidentElement( Element< K > e , IncidentCubeIndex< K > d ){ return _IncidentElement( e , d ); } - template< unsigned int D > template< unsigned int K , unsigned int _D > + template< unsigned int D > template< unsigned int K > + typename Cube< D >::template Element< K > Cube< D >::IncidentElement( Element< K > e , IncidentCubeIndex< K > d ){ return _IncidentElement( e , d ); } + template< unsigned int D > template< unsigned int K , unsigned int _D > #ifdef _MSC_VER - typename std::enable_if< _D==K , typename Cube< D >::Element< K > >::type Cube< D >::_IncidentElement( Element< K > e , IncidentCubeIndex< K > d ){ return e; } + typename std::enable_if< _D==K , typename Cube< D >::Element< K > >::type Cube< D >::_IncidentElement( Element< K > e , IncidentCubeIndex< K > d ){ return e; } #else // !_MSC_VER - typename std::enable_if< _D==K , typename Cube< D >::template Element< K > >::type Cube< D >::_IncidentElement( Element< K > e , IncidentCubeIndex< K > d ){ return e; } + typename std::enable_if< _D==K , typename Cube< D >::template Element< K > >::type Cube< D >::_IncidentElement( Element< K > e , IncidentCubeIndex< K > d ){ return e; } #endif // _MSC_VER - template< unsigned int D > template< unsigned int K , unsigned int _D > + template< unsigned int D > template< unsigned int K , unsigned int _D > #ifdef _MSC_VER - typename std::enable_if< _D!=K && _D!=0 && K!=0 , typename Cube< D >::Element< K > >::type Cube< D >::_IncidentElement( Element< K > e , IncidentCubeIndex< K > d ) + typename std::enable_if< _D!=K && _D!=0 && K!=0 , typename Cube< D >::Element< K > >::type Cube< D >::_IncidentElement( Element< K > e , IncidentCubeIndex< K > d ) #else // !_MSC_VER - typename std::enable_if< _D!=K && _D!=0 && K!=0 , typename Cube< D >::template Element< K > >::type Cube< D >::_IncidentElement( Element< K > e , IncidentCubeIndex< K > d ) + typename std::enable_if< _D!=K && _D!=0 && K!=0 , typename Cube< D >::template Element< K > >::type Cube< D >::_IncidentElement( Element< K > e , IncidentCubeIndex< K > d ) #endif // _MSC_VER - { - Direction eDir , dDir ; unsigned int eCoIndex , dCoIndex; - e.factor( eDir , eCoIndex ) , d.factor( dDir , dCoIndex ); - if ( eDir==CROSS ) return Element< K >( eDir , Cube< D-1 >::template IncidentElement( typename Cube< D-1 >::template Element< K-1 >( eCoIndex ) , d ).index ); - else if( eDir==dDir ) return Element< K >( Opposite( eDir ) , Cube< D-1 >::template IncidentElement( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ).index ); - else return Element< K >( eDir , Cube< D-1 >::template IncidentElement( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ).index ); - } - template< unsigned int D > template< unsigned int K , unsigned int _D > + { + Direction eDir , dDir ; unsigned int eCoIndex , dCoIndex; + e.factor( eDir , eCoIndex ) , d.factor( dDir , dCoIndex ); + if ( eDir==CROSS ) return Element< K >( eDir , Cube< D-1 >::template IncidentElement( typename Cube< D-1 >::template Element< K-1 >( eCoIndex ) , d ).index ); + else if( eDir==dDir ) return Element< K >( Opposite( eDir ) , Cube< D-1 >::template IncidentElement( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ).index ); + else return Element< K >( eDir , Cube< D-1 >::template IncidentElement( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ).index ); + } + template< unsigned int D > template< unsigned int K , unsigned int _D > #ifdef _MSC_VER - typename std::enable_if< _D!=K && _D!=0 && K==0 , typename Cube< D >::Element< K > >::type Cube< D >::_IncidentElement( Element< K > e , IncidentCubeIndex< K > d ) + typename std::enable_if< _D!=K && _D!=0 && K==0 , typename Cube< D >::Element< K > >::type Cube< D >::_IncidentElement( Element< K > e , IncidentCubeIndex< K > d ) #else // !_MSC_VER - typename std::enable_if< _D!=K && _D!=0 && K==0 , typename Cube< D >::template Element< K > >::type Cube< D >::_IncidentElement( Element< K > e , IncidentCubeIndex< K > d ) + typename std::enable_if< _D!=K && _D!=0 && K==0 , typename Cube< D >::template Element< K > >::type Cube< D >::_IncidentElement( Element< K > e , IncidentCubeIndex< K > d ) #endif // _MSC_VER - { - Direction eDir , dDir ; unsigned int eCoIndex , dCoIndex; - e.factor( eDir , eCoIndex ) , d.factor( dDir , dCoIndex ); - if( eDir==dDir ) return Element< K >( Opposite( eDir ) , Cube< D-1 >::template IncidentElement( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ).index ); - else return Element< K >( eDir , Cube< D-1 >::template IncidentElement( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ).index ); - } - + { + Direction eDir , dDir ; unsigned int eCoIndex , dCoIndex; + e.factor( eDir , eCoIndex ) , d.factor( dDir , dCoIndex ); + if( eDir==dDir ) return Element< K >( Opposite( eDir ) , Cube< D-1 >::template IncidentElement( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ).index ); + else return Element< K >( eDir , Cube< D-1 >::template IncidentElement( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ).index ); + } - ///////////////////// - // MarchingSquares // - ///////////////////// - const int MarchingSquares::edges[][MAX_EDGES*2+1] = - { - // Positive to the right - // Positive in center - /////////////////////////////////// (0,0) (1,0) (0,1) (1,1) - { -1 , -1 , -1 , -1 , -1 } , // - - - - // - { 1 , 0 , -1 , -1 , -1 } , // + - - - // (0,0) - (0,1) | (0,0) - (1,0) - { 0 , 2 , -1 , -1 , -1 } , // - + - - // (0,0) - (1,0) | (1,0) - (1,1) - { 1 , 2 , -1 , -1 , -1 } , // + + - - // (0,0) - (0,1) | (1,0) - (1,1) - { 3 , 1 , -1 , -1 , -1 } , // - - + - // (0,1) - (1,1) | (0,0) - (0,1) - { 3 , 0 , -1 , -1 , -1 } , // + - + - // (0,1) - (1,1) | (0,0) - (1,0) - { 0 , 1 , 3 , 2 , -1 } , // - + + - // (0,0) - (1,0) | (0,0) - (0,1) & (0,1) - (1,1) | (1,0) - (1,1) - { 3 , 2 , -1 , -1 , -1 } , // + + + - // (0,1) - (1,1) | (1,0) - (1,1) - { 2 , 3 , -1 , -1 , -1 } , // - - - + // (1,0) - (1,1) | (0,1) - (1,1) - { 1 , 3 , 2 , 0 , -1 } , // + - - + // (0,0) - (0,1) | (0,1) - (1,1) & (1,0) - (1,1) | (0,0) - (1,0) - { 0 , 3 , -1 , -1 , -1 } , // - + - + // (0,0) - (1,0) | (0,1) - (1,1) - { 1 , 3 , -1 , -1 , -1 } , // + + - + // (0,0) - (0,1) | (0,1) - (1,1) - { 2 , 1 , -1 , -1 , -1 } , // - - + + // (1,0) - (1,1) | (0,0) - (0,1) - { 2 , 0 , -1 , -1 , -1 } , // + - + + // (1,0) - (1,1) | (0,0) - (1,0) - { 0 , 1 , -1 , -1 , -1 } , // - + + + // (0,0) - (1,0) | (0,0) - (0,1) - { -1 , -1 , -1 , -1 , -1 } , // + + + + // - }; - inline int MarchingSquares::AddEdgeIndices( unsigned char mcIndex , int* isoIndices ) - { - int nEdges = 0; - /* Square is entirely in/out of the surface */ - if( mcIndex==0 || mcIndex==15 ) return 0; - /* Create the edges */ - for( int i=0 ; edges[mcIndex][i]!=-1 ; i+=2 ) + ///////////////////// + // MarchingSquares // + ///////////////////// + const int MarchingSquares::edges[][MAX_EDGES*2+1] = { - for( int j=0 ; j<2 ; j++ ) isoIndices[i+j] = edges[mcIndex][i+j]; - nEdges++; + // Positive to the right + // Positive in center + /////////////////////////////////// (0,0) (1,0) (0,1) (1,1) + { -1 , -1 , -1 , -1 , -1 } , // - - - - // + { 1 , 0 , -1 , -1 , -1 } , // + - - - // (0,0) - (0,1) | (0,0) - (1,0) + { 0 , 2 , -1 , -1 , -1 } , // - + - - // (0,0) - (1,0) | (1,0) - (1,1) + { 1 , 2 , -1 , -1 , -1 } , // + + - - // (0,0) - (0,1) | (1,0) - (1,1) + { 3 , 1 , -1 , -1 , -1 } , // - - + - // (0,1) - (1,1) | (0,0) - (0,1) + { 3 , 0 , -1 , -1 , -1 } , // + - + - // (0,1) - (1,1) | (0,0) - (1,0) + { 0 , 1 , 3 , 2 , -1 } , // - + + - // (0,0) - (1,0) | (0,0) - (0,1) & (0,1) - (1,1) | (1,0) - (1,1) + { 3 , 2 , -1 , -1 , -1 } , // + + + - // (0,1) - (1,1) | (1,0) - (1,1) + { 2 , 3 , -1 , -1 , -1 } , // - - - + // (1,0) - (1,1) | (0,1) - (1,1) + { 1 , 3 , 2 , 0 , -1 } , // + - - + // (0,0) - (0,1) | (0,1) - (1,1) & (1,0) - (1,1) | (0,0) - (1,0) + { 0 , 3 , -1 , -1 , -1 } , // - + - + // (0,0) - (1,0) | (0,1) - (1,1) + { 1 , 3 , -1 , -1 , -1 } , // + + - + // (0,0) - (0,1) | (0,1) - (1,1) + { 2 , 1 , -1 , -1 , -1 } , // - - + + // (1,0) - (1,1) | (0,0) - (0,1) + { 2 , 0 , -1 , -1 , -1 } , // + - + + // (1,0) - (1,1) | (0,0) - (1,0) + { 0 , 1 , -1 , -1 , -1 } , // - + + + // (0,0) - (1,0) | (0,0) - (0,1) + { -1 , -1 , -1 , -1 , -1 } , // + + + + // + }; + inline int MarchingSquares::AddEdgeIndices( unsigned char mcIndex , int* isoIndices ) + { + int nEdges = 0; + /* Square is entirely in/out of the surface */ + if( mcIndex==0 || mcIndex==15 ) return 0; + + /* Create the edges */ + for( int i=0 ; edges[mcIndex][i]!=-1 ; i+=2 ) + { + for( int j=0 ; j<2 ; j++ ) isoIndices[i+j] = edges[mcIndex][i+j]; + nEdges++; + } + return nEdges; } - return nEdges; } } diff --git a/Src/MergePlyClientServer.h b/Src/MergePlyClientServer.h index 22b48de2..ef306ef2 100644 --- a/Src/MergePlyClientServer.h +++ b/Src/MergePlyClientServer.h @@ -35,39 +35,42 @@ DAMAGE. #include "MyMiscellany.h" #include "CmdLineParser.h" - -namespace MergePlyClientServer +namespace PoissonRecon { - struct ClientMergePlyInfo + + namespace MergePlyClientServer { - std::vector< PlyProperty > auxProperties; - size_t bufferSize; - bool keepSeparate , verbose; + struct ClientMergePlyInfo + { + std::vector< PlyProperty > auxProperties; + size_t bufferSize; + bool keepSeparate , verbose; - ClientMergePlyInfo( void ); - ClientMergePlyInfo( BinaryStream &stream ); + ClientMergePlyInfo( void ); + ClientMergePlyInfo( BinaryStream &stream ); - void write( BinaryStream &stream ) const; - }; + void write( BinaryStream &stream ) const; + }; - template< typename Real , unsigned int Dim > - void RunServer - ( - std::string inDir , - std::string tempDir , - std::string header , - std::string out , - std::vector< Socket > &clientSockets , - const std::vector< unsigned int > &sharedVertexCounts , - ClientMergePlyInfo clientMergePlyInfo , - unsigned int sampleMS , - std::function< std::vector< std::string > (unsigned int) > commentFunctor=[](unsigned int){ return std::vector< std::string >(); } - ); + template< typename Real , unsigned int Dim > + void RunServer + ( + std::string inDir , + std::string tempDir , + std::string header , + std::string out , + std::vector< Socket > &clientSockets , + const std::vector< unsigned int > &sharedVertexCounts , + ClientMergePlyInfo clientMergePlyInfo , + unsigned int sampleMS , + std::function< std::vector< std::string > (unsigned int) > commentFunctor=[](unsigned int){ return std::vector< std::string >(); } + ); - template< typename Real , unsigned int Dim > - void RunClients( std::vector< Socket > &serverSockets , unsigned int sampleMS ); + template< typename Real , unsigned int Dim > + void RunClients( std::vector< Socket > &serverSockets , unsigned int sampleMS ); #include "MergePlyClientServer.inl" + } } #endif // MERGE_PLY_CLIENT_SERVER_INCLUDED \ No newline at end of file diff --git a/Src/MyExceptions.h b/Src/MyExceptions.h new file mode 100644 index 00000000..ad5bf110 --- /dev/null +++ b/Src/MyExceptions.h @@ -0,0 +1,120 @@ +/* +Copyright (c) 2017, 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 MY_EXCEPTIONS_INCLUDED +#define MY_EXCEPTIONS_INCLUDED + +///////////////////////////////////// +// Exception, Warnings, and Errors // +///////////////////////////////////// +#include +#include +#include +#include +#include + +namespace PoissonRecon +{ + template< typename ... Arguments > void _AddToMessageStream( std::stringstream &stream , Arguments ... arguments ); + inline void _AddToMessageStream( std::stringstream &stream ){ return; } + template< typename Argument , typename ... Arguments > void _AddToMessageStream( std::stringstream &stream , Argument argument , Arguments ... arguments ) + { + stream << argument; + _AddToMessageStream( stream , arguments ... ); + } + + template< typename ... Arguments > + std::string MakeMessageString( std::string header , std::string fileName , int line , std::string functionName , Arguments ... arguments ) + { + size_t headerSize = header.size(); + std::stringstream stream; + + // The first line is the header, the file name , and the line number + stream << header << " " << fileName << " (Line " << line << ")" << std::endl; + + // Inset the second line by the size of the header and write the function name + for( size_t i=0 ; i<=headerSize ; i++ ) stream << " "; + stream << functionName << std::endl; + + // Inset the third line by the size of the header and write the rest + for( size_t i=0 ; i<=headerSize ; i++ ) stream << " "; + _AddToMessageStream( stream , arguments ... ); + + return stream.str(); + } + struct Exception : public std::exception + { + const char *what( void ) const noexcept { return _message.c_str(); } + template< typename ... Args > + Exception( const char *fileName , int line , const char *functionName , const char *format , Args ... args ) + { + _message = MakeMessageString( "[EXCEPTION]" , fileName , line , functionName , format , args ... ); + } + private: + std::string _message; + }; + + template< typename ... Args > void Throw( const char *fileName , int line , const char *functionName , const char *format , Args ... args ){ throw Exception( fileName , line , functionName , format , args ... ); } + template< typename ... Args > + void Warn( const char *fileName , int line , const char *functionName , const char *format , Args ... args ) + { + std::cerr << MakeMessageString( "[WARNING]" , fileName , line , functionName , format , args ... ) << std::endl; + } + template< typename ... Args > + void ErrorOut( const char *fileName , int line , const char *functionName , const char *format , Args ... args ) + { + std::cerr << MakeMessageString( "[ERROR]" , fileName , line , functionName , format , args ... ) << std::endl; + exit( EXIT_FAILURE ); + } +} +#ifndef WARN +#define WARN( ... ) Warn( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) +#endif // WARN +#ifndef WARN_ONCE +#define WARN_ONCE( ... ) { static bool firstTime = true ; if( firstTime ) Warn( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) ; firstTime = false; } +#endif // WARN_ONCE +#ifndef THROW +#define THROW( ... ) Throw( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) +#endif // THROW +#ifndef ERROR_OUT +#define ERROR_OUT( ... ) ErrorOut( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) +#endif // ERROR_OUT + +#ifndef PR_WARN +#define PR_WARN( ... ) PoissonRecon::Warn( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) +#endif // PR_WARN +#ifndef PR_WARN_ONCE +#define PR_WARN_ONCE( ... ) { static bool firstTime = true ; if( firstTime ) PoissonRecon::Warn( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) ; firstTime = false; } +#endif // PR_WARN_ONCE +#ifndef PR_THROW +#define PR_THROW( ... ) PoissonRecon::Throw( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) +#endif // PR_THROW +#ifndef PR_ERROR_OUT +#define PR_ERROR_OUT( ... ) PoissonRecon::ErrorOut( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) +#endif // PR_ERROR_OUT + +#endif // MY_EXCEPTIONS_INCLUDED diff --git a/Src/MyMiscellany.h b/Src/MyMiscellany.h index 90dc82d2..470d5868 100644 --- a/Src/MyMiscellany.h +++ b/Src/MyMiscellany.h @@ -32,87 +32,114 @@ DAMAGE. #include #include #include +#include +#include +#include +#include +#include +#if defined( _WIN32 ) || defined( _WIN64 ) +#include +#include +#include +#else // !_WIN32 && !_WIN64 +#include +#include +#include +#endif // _WIN32 || _WIN64 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(_WIN32) || defined( _WIN64 ) +#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) +#if defined(__APPLE__) && defined(__MACH__) +#include +#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__))) +#include +#include +#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__) +#include +#endif -////////////////// -// OpenMP Stuff // -////////////////// +#else +#error "Cannot define getPeakRSS( ) or getCurrentRSS( ) for an unknown OS." +#endif #ifdef _OPENMP #include #endif // _OPENMP +#include "Array.h" -//////////////////////////// -// Formatted float output // -//////////////////////////// -struct StreamFloatPrecision +namespace PoissonRecon { - StreamFloatPrecision( std::ostream &str , unsigned int precision , bool scientific=false ) : _str(str) - { - _defaultPrecision = (int)_str.precision(); - _str.precision( precision ); - if( scientific ) _str << std::scientific; - else _str << std::fixed; - } - ~StreamFloatPrecision( void ) + //////////////////////////// + // Formatted float output // + //////////////////////////// + struct StreamFloatPrecision { - _str << std::defaultfloat; - _str.precision( _defaultPrecision ); - } -protected: - int _defaultPrecision; - std::ostream &_str; -}; - -//////////////// -// Time Stuff // -//////////////// -#include -#include -#ifndef WIN32 -#include -#endif // WIN32 + StreamFloatPrecision( std::ostream &str , unsigned int precision , bool scientific=false ) : _str(str) + { + _defaultPrecision = (int)_str.precision(); + _str.precision( precision ); + if( scientific ) _str << std::scientific; + else _str << std::fixed; + } + ~StreamFloatPrecision( void ) + { + _str << std::defaultfloat; + _str.precision( _defaultPrecision ); + } + protected: + int _defaultPrecision; + std::ostream &_str; + }; -inline double Time( void ) -{ + //////////////// + // Time Stuff // + //////////////// + inline double Time( void ) + { #ifdef WIN32 - struct _timeb t; - _ftime( &t ); - return double( t.time ) + double( t.millitm ) / 1000.0; + 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; + struct timeval t; + gettimeofday( &t , NULL ); + return t.tv_sec + double( t.tv_usec ) / 1000000; #endif // WIN32 -} + } -#include -#include -#include -struct Timer -{ - Timer( void ){ _startCPUClock = std::clock() , _startWallClock = std::chrono::system_clock::now(); } - double cpuTime( void ) const{ return (std::clock() - _startCPUClock) / (double)CLOCKS_PER_SEC; }; - double wallTime( void ) const{ std::chrono::duration diff = (std::chrono::system_clock::now() - _startWallClock) ; return diff.count(); } - std::string operator()( bool showCpuTime , unsigned int precision=1 ) const + struct Timer { - std::stringstream ss; - StreamFloatPrecision sfp( ss , precision ); - ss << wallTime() << " (s)"; - if( showCpuTime ) ss << " / " << cpuTime() << " (s)"; - return ss.str(); - } - friend std::ostream &operator << ( std::ostream &os , const Timer &timer ){ return os << timer(false); } -protected: - std::clock_t _startCPUClock; - std::chrono::time_point< std::chrono::system_clock > _startWallClock; -}; + Timer( void ){ _startCPUClock = std::clock() , _startWallClock = std::chrono::system_clock::now(); } + double cpuTime( void ) const{ return (std::clock() - _startCPUClock) / (double)CLOCKS_PER_SEC; }; + double wallTime( void ) const{ std::chrono::duration diff = (std::chrono::system_clock::now() - _startWallClock) ; return diff.count(); } + std::string operator()( bool showCpuTime , unsigned int precision=1 ) const + { + std::stringstream ss; + StreamFloatPrecision sfp( ss , precision ); + ss << wallTime() << " (s)"; + if( showCpuTime ) ss << " / " << cpuTime() << " (s)"; + return ss.str(); + } + friend std::ostream &operator << ( std::ostream &os , const Timer &timer ){ return os << timer(false); } + protected: + std::clock_t _startCPUClock; + std::chrono::time_point< std::chrono::system_clock > _startWallClock; + }; -/////////////// -// I/O Stuff // -/////////////// + /////////////// + // I/O Stuff // + /////////////// #if defined( _WIN32 ) || defined( _WIN64 ) -const char FileSeparator = '\\'; + const char FileSeparator = '\\'; #else // !_WIN -const char FileSeparator = '/'; + const char FileSeparator = '/'; #endif // _WIN #ifndef SetTempDirectory @@ -124,905 +151,533 @@ const char FileSeparator = '/'; #endif // !SetTempDirectory #if defined( _WIN32 ) || defined( _WIN64 ) -#include -inline void FSync( FILE *fp ) -{ - // FlushFileBuffers( (HANDLE)_fileno( fp ) ); - _commit( _fileno( fp ) ); -} -#else // !_WIN32 && !_WIN64 -#include -inline void FSync( FILE *fp ) -{ - fsync( fileno( fp ) ); -} -#endif // _WIN32 || _WIN64 - -///////////////////////////////////// -// Exception, Warnings, and Errors // -///////////////////////////////////// -#include -#include -#include -#include -#include -namespace MKExceptions -{ - template< typename ... Arguments > void _AddToMessageStream( std::stringstream &stream , Arguments ... arguments ); - inline void _AddToMessageStream( std::stringstream &stream ){ return; } - template< typename Argument , typename ... Arguments > void _AddToMessageStream( std::stringstream &stream , Argument argument , Arguments ... arguments ) + inline void FSync( FILE *fp ) { - stream << argument; - _AddToMessageStream( stream , arguments ... ); + // FlushFileBuffers( (HANDLE)_fileno( fp ) ); + _commit( _fileno( fp ) ); } - - template< typename ... Arguments > - std::string MakeMessageString( std::string header , std::string fileName , int line , std::string functionName , Arguments ... arguments ) +#else // !_WIN32 && !_WIN64 + inline void FSync( FILE *fp ) { - size_t headerSize = header.size(); - std::stringstream stream; - - // The first line is the header, the file name , and the line number - stream << header << " " << fileName << " (Line " << line << ")" << std::endl; - - // Inset the second line by the size of the header and write the function name - for( size_t i=0 ; i<=headerSize ; i++ ) stream << " "; - stream << functionName << std::endl; + fsync( fileno( fp ) ); + } +#endif // _WIN32 || _WIN64 - // Inset the third line by the size of the header and write the rest - for( size_t i=0 ; i<=headerSize ; i++ ) stream << " "; - _AddToMessageStream( stream , arguments ... ); + template< typename Value > bool SetAtomic( volatile Value *value , Value newValue , Value oldValue ); + template< typename Data > void AddAtomic( Data& a , Data b ); - return stream.str(); - } - struct Exception : public std::exception + //////////////////// + // MKThread Stuff // + //////////////////// + struct ThreadPool { - const char *what( void ) const noexcept { return _message.c_str(); } - template< typename ... Args > - Exception( const char *fileName , int line , const char *functionName , const char *format , Args ... args ) + enum ParallelType { - _message = MakeMessageString( "[EXCEPTION]" , fileName , line , functionName , format , args ... ); - } - private: - std::string _message; - }; - - template< typename ... Args > void Throw( const char *fileName , int line , const char *functionName , const char *format , Args ... args ){ throw Exception( fileName , line , functionName , format , args ... ); } - template< typename ... Args > - void Warn( const char *fileName , int line , const char *functionName , const char *format , Args ... args ) - { - std::cerr << MakeMessageString( "[WARNING]" , fileName , line , functionName , format , args ... ) << std::endl; - } - template< typename ... Args > - void ErrorOut( const char *fileName , int line , const char *functionName , const char *format , Args ... args ) - { - std::cerr << MakeMessageString( "[ERROR]" , fileName , line , functionName , format , args ... ) << std::endl; - exit( EXIT_FAILURE ); - } -} -#ifndef WARN -#define WARN( ... ) MKExceptions::Warn( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) -#endif // WARN -#ifndef WARN_ONCE -#define WARN_ONCE( ... ) { static bool firstTime = true ; if( firstTime ) MKExceptions::Warn( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) ; firstTime = false; } -#endif // WARN_ONCE -#ifndef THROW -#define THROW( ... ) MKExceptions::Throw( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) -#endif // THROW -#ifndef ERROR_OUT -#define ERROR_OUT( ... ) MKExceptions::ErrorOut( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) -#endif // ERROR_OUT +#ifdef _OPENMP + OPEN_MP , +#endif // _OPENMP + THREAD_POOL , + ASYNC , + NONE + }; + static const std::vector< std::string > ParallelNames; -struct FunctionCallNotifier -{ - FunctionCallNotifier( std::string str ) : _str(str) - { - _depth = _Depth++; - for( unsigned int i=0 ; i<_depth ; i++ ) std::cout << " "; - std::cout << "[START] " << _str << std::endl; - }; - ~FunctionCallNotifier( void ) - { - for( unsigned int i=0 ; i<_depth ; i++ ) std::cout << " "; - std::cout << "[END] " << _str << std::endl; - _Depth--; - } -protected: - static unsigned int _Depth; - unsigned int _depth; - std::string _str; -}; -unsigned int FunctionCallNotifier::_Depth = 0; -#define FUNCTION_NOTIFY FunctionCallNotifier ___myFunctionCallNotifier___( __FUNCTION__ ) + enum ScheduleType + { + STATIC , + DYNAMIC + }; + static const std::vector< std::string > ScheduleNames; -#include -#if defined(_WIN32) || defined( _WIN64 ) -#else // !WINDOWS -#include -#include -#include -#include -#endif // WINDOWS -struct StackTracer -{ - static const char *exec; -#if defined(_WIN32) || defined( _WIN64 ) - static void Trace( void ) - { - } -#else // !WINDOWS - static void Trace( void ) - { - static std::mutex mutex; - std::lock_guard< std::mutex > lock(mutex); + static size_t DefaultChunkSize; + static ScheduleType DefaultSchedule; - // Code borrowed from: - // https://stackoverflow.com/questions/77005/how-to-automatically-generate-a-stacktrace-when-my-program-crashes - // and - // https://stackoverflow.com/questions/15129089/is-there-a-way-to-dump-stack-trace-with-line-number-from-a-linux-release-binary/15130037 - void * trace[128]; - int size = backtrace( trace , 128 ); + template< typename ... Functions > + static void ParallelSections( const Functions & ... functions ) + { + std::vector< std::future< void > > futures( sizeof...(Functions) ); + _ParallelSections( &futures[0] , functions ... ); + for( size_t t=0 ; t &iterationFunction , ScheduleType schedule=DefaultSchedule , size_t chunkSize=DefaultChunkSize ) { - char *mangled_name=0 , *offset_begin=0 , *offset_end=0; + if( begin>=end ) return; + size_t range = end - begin; + size_t chunks = ( range + chunkSize - 1 ) / chunkSize; + unsigned int threads = (unsigned int)NumThreads(); + std::atomic< size_t > index; + index.store( 0 ); - char syscom[1024]; - sprintf( syscom , "addr2line %p -e %s" , trace[i] , exec ); //last parameter is the name of this app - if( !system( syscom ) ){} - // find parantheses and +address offset surrounding mangled name - for( char *p=messages[i] ; *p ; ++p ) + if( range( end , _begin+chunkSize ); + for( size_t i=_begin ; i<_end ; i++ ) iterationFunction( thread , i ); + }; + auto _StaticThreadFunction = [ &_ChunkFunction , chunks , threads ]( unsigned int thread ) { - std::cerr << "\t(" << i << ") " << messages[i] << " : " << mangled_name << "+" << offset_begin << offset_end << std::endl; - std::cout << "\t(" << i << ") " << messages[i] << " : " << mangled_name << "+" << offset_begin << offset_end << std::endl; - } - free( real_name ); - } - // otherwise, print the whole line - else - { - std::cerr << "\t(" << i << ") " << messages[i] << std::endl; - std::cout << "\t(" << i << ") " << messages[i] << std::endl; - } - } - - free( messages ); - } -#endif // WINDOWS -}; -const char *StackTracer::exec; - -inline void SignalHandler( int signal ) -{ - printf( "Signal: %d\n" , signal ); - StackTracer::Trace(); - exit( EXIT_FAILURE ); -}; - - -template< typename Value > bool SetAtomic( volatile Value *value , Value newValue , Value oldValue ); -template< typename Data > void AddAtomic( Data& a , Data b ); - -////////////////////////////////// -// File-backed streaming memory // -////////////////////////////////// -#include "Array.h" -class FileBackedReadWriteStream -{ -public: - struct FileDescription - { - FILE *fp; - - FileDescription( FILE *fp ) : fp(fp) , _closeFile(false) - { - if( !this->fp ) - { - this->fp = std::tmpfile(); - _closeFile = true; - if( !this->fp ) ERROR_OUT( "Failed to open temporary file" ); - } - } - ~FileDescription( void ){ if( _closeFile ) fclose(fp); } - protected: - bool _closeFile; - }; - - FileBackedReadWriteStream( FILE *fp ) : _fd(fp) {} - bool write( ConstPointer(char) data , size_t size ){ return fwrite( data , sizeof(char) , size , _fd.fp )==size; } - bool read( Pointer(char) data , size_t size ){ return fread( data , sizeof(char) , size , _fd.fp )==size; } - void reset( void ){ fseek( _fd.fp , 0 , SEEK_SET ); } -protected: - FileDescription _fd; -}; - - - -//////////////////// -// MKThread Stuff // -//////////////////// -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -struct ThreadPool -{ - enum ParallelType - { -#ifdef _OPENMP - OPEN_MP , -#endif // _OPENMP - THREAD_POOL , - ASYNC , - NONE - }; - static const std::vector< std::string > ParallelNames; - - enum ScheduleType - { - STATIC , - DYNAMIC - }; - static const std::vector< std::string > ScheduleNames; - - static size_t DefaultChunkSize; - static ScheduleType DefaultSchedule; - - template< typename ... Functions > - static void ParallelSections( const Functions & ... functions ) - { - std::vector< std::future< void > > futures( sizeof...(Functions) ); - _ParallelSections( &futures[0] , functions ... ); - for( size_t t=0 ; t &iterationFunction , ScheduleType schedule=DefaultSchedule , size_t chunkSize=DefaultChunkSize ) - { - if( begin>=end ) return; - size_t range = end - begin; - size_t chunks = ( range + chunkSize - 1 ) / chunkSize; - unsigned int threads = (unsigned int)NumThreads(); - std::atomic< size_t > index; - index.store( 0 ); - - - if( range( end , _begin+chunkSize ); - for( size_t i=_begin ; i<_end ; i++ ) iterationFunction( thread , i ); - }; - auto _StaticThreadFunction = [ &_ChunkFunction , chunks , threads ]( unsigned int thread ) - { - for( size_t chunk=thread ; chunk > futures; - futures.resize( threads-1 ); - for( unsigned int t=1 ; t > futures; + futures.resize( threads-1 ); + for( unsigned int t=1 ; t lock( _Mutex ); - _DoneWithWork.wait( lock , [&]( void ){ return _RemainingTasks==0; } ); + WARN( "nested for loop, reverting to serial" ); + for( size_t i=begin ; i lock( _Mutex ); + _DoneWithWork.wait( lock , [&]( void ){ return _RemainingTasks==0; } ); + } } } } - } - static unsigned int NumThreads( void ){ return (unsigned int)_Threads.size()+1; } + static unsigned int NumThreads( void ){ return (unsigned int)_Threads.size()+1; } - static void Init( ParallelType parallelType , unsigned int numThreads=std::thread::hardware_concurrency() ) - { - _ParallelType = parallelType; - if( _Threads.size() && !_Close ) + static void Init( ParallelType parallelType , unsigned int numThreads=std::thread::hardware_concurrency() ) { + _ParallelType = parallelType; + if( _Threads.size() && !_Close ) + { + _Close = true; + _WaitingForWorkOrClose.notify_all(); + for( unsigned int t=0 ; t<_Threads.size() ; t++ ) _Threads[t].join(); + } _Close = true; - _WaitingForWorkOrClose.notify_all(); - for( unsigned int t=0 ; t<_Threads.size() ; t++ ) _Threads[t].join(); + numThreads--; + _Threads.resize( numThreads ); + if( _ParallelType==THREAD_POOL ) + { + _RemainingTasks = 0; + _Close = false; + for( unsigned int t=0 ; t + static void _ParallelSections( std::future< void > *futures , const Function &function ){ *futures = std::async( std::launch::async , function ); } + template< typename Function , typename ... Functions > + static void _ParallelSections( std::future< void > *futures , const Function &function , const Functions& ... functions ) { - _Close = true; - _WaitingForWorkOrClose.notify_all(); - for( unsigned int t=0 ; t<_Threads.size() ; t++ ) _Threads[t].join(); - _Threads.resize( 0 ); + *futures = std::async( std::launch::async , function ); + _ParallelSections( futures+1 , functions ... ); } - } -private: - ThreadPool( const ThreadPool & ){} - ThreadPool &operator = ( const ThreadPool & ){ return *this; } - - template< typename Function > - static void _ParallelSections( std::future< void > *futures , const Function &function ){ *futures = std::async( std::launch::async , function ); } - template< typename Function , typename ... Functions > - static void _ParallelSections( std::future< void > *futures , const Function &function , const Functions& ... functions ) - { - *futures = std::async( std::launch::async , function ); - _ParallelSections( futures+1 , functions ... ); - } - static void _ThreadInitFunction( unsigned int thread ) - { - // Wait for the first job to come in - std::unique_lock< std::mutex > lock( _Mutex ); - _WaitingForWorkOrClose.wait( lock ); - while( !_Close ) + static void _ThreadInitFunction( unsigned int thread ) { - lock.unlock(); - // do the job - _ThreadFunction( thread ); - - // Notify and wait for the next job - lock.lock(); - _RemainingTasks--; - if( !_RemainingTasks ) _DoneWithWork.notify_all(); + // Wait for the first job to come in + std::unique_lock< std::mutex > lock( _Mutex ); _WaitingForWorkOrClose.wait( lock ); + while( !_Close ) + { + lock.unlock(); + // do the job + _ThreadFunction( thread ); + + // Notify and wait for the next job + lock.lock(); + _RemainingTasks--; + if( !_RemainingTasks ) _DoneWithWork.notify_all(); + _WaitingForWorkOrClose.wait( lock ); + } } - } - static bool _Close; - static volatile unsigned int _RemainingTasks; - static std::mutex _Mutex; - static std::condition_variable _WaitingForWorkOrClose , _DoneWithWork; - static std::vector< std::thread > _Threads; - static std::function< void ( unsigned int ) > _ThreadFunction; - static ParallelType _ParallelType; -}; + static bool _Close; + static volatile unsigned int _RemainingTasks; + static std::mutex _Mutex; + static std::condition_variable _WaitingForWorkOrClose , _DoneWithWork; + static std::vector< std::thread > _Threads; + static std::function< void ( unsigned int ) > _ThreadFunction; + static ParallelType _ParallelType; + }; -size_t ThreadPool::DefaultChunkSize = 128; -ThreadPool::ScheduleType ThreadPool::DefaultSchedule = ThreadPool::DYNAMIC; -bool ThreadPool::_Close; -volatile unsigned int ThreadPool::_RemainingTasks; -std::mutex ThreadPool::_Mutex; -std::condition_variable ThreadPool::_WaitingForWorkOrClose; -std::condition_variable ThreadPool::_DoneWithWork; -std::vector< std::thread > ThreadPool::_Threads; -std::function< void ( unsigned int ) > ThreadPool::_ThreadFunction; -ThreadPool::ParallelType ThreadPool::_ParallelType; + size_t ThreadPool::DefaultChunkSize = 128; + ThreadPool::ScheduleType ThreadPool::DefaultSchedule = ThreadPool::DYNAMIC; + bool ThreadPool::_Close; + volatile unsigned int ThreadPool::_RemainingTasks; + std::mutex ThreadPool::_Mutex; + std::condition_variable ThreadPool::_WaitingForWorkOrClose; + std::condition_variable ThreadPool::_DoneWithWork; + std::vector< std::thread > ThreadPool::_Threads; + std::function< void ( unsigned int ) > ThreadPool::_ThreadFunction; + ThreadPool::ParallelType ThreadPool::_ParallelType; -const std::vector< std::string >ThreadPool::ParallelNames = -{ + const std::vector< std::string >ThreadPool::ParallelNames = + { #ifdef _OPENMP - "open mp" , + "open mp" , #endif // _OPENMP - "thread pool" , - "async" , - "none" -}; -const std::vector< std::string >ThreadPool::ScheduleNames = { "static" , "dynamic" }; - -#include + "thread pool" , + "async" , + "none" + }; + const std::vector< std::string >ThreadPool::ScheduleNames = { "static" , "dynamic" }; + template< typename Value > + bool SetAtomic32( volatile Value *value , Value newValue , Value oldValue ) + { #if defined( _WIN32 ) || defined( _WIN64 ) -#include -#endif // _WIN32 || _WIN64 -template< typename Value > -bool SetAtomic32( volatile Value *value , Value newValue , Value oldValue ) -{ -#if defined( _WIN32 ) || defined( _WIN64 ) - long *_oldValue = (long *)&oldValue; - long *_newValue = (long *)&newValue; - return InterlockedCompareExchange( (long*)value , *_newValue , *_oldValue )==*_oldValue; + long *_oldValue = (long *)&oldValue; + long *_newValue = (long *)&newValue; + return InterlockedCompareExchange( (long*)value , *_newValue , *_oldValue )==*_oldValue; #else // !_WIN32 && !_WIN64 - uint32_t *_newValue = (uint32_t *)&newValue; - return __atomic_compare_exchange_n( (uint32_t *)value , (uint32_t *)&oldValue , *_newValue , false , __ATOMIC_SEQ_CST , __ATOMIC_SEQ_CST ); + uint32_t *_newValue = (uint32_t *)&newValue; + return __atomic_compare_exchange_n( (uint32_t *)value , (uint32_t *)&oldValue , *_newValue , false , __ATOMIC_SEQ_CST , __ATOMIC_SEQ_CST ); #endif // _WIN32 || _WIN64 -} -template< typename Value > -bool SetAtomic64( volatile Value *value , Value newValue , Value oldValue ) -{ + } + template< typename Value > + bool SetAtomic64( volatile Value *value , Value newValue , Value oldValue ) + { #if defined( _WIN32 ) || defined( _WIN64 ) - __int64 *_oldValue = (__int64 *)&oldValue; - __int64 *_newValue = (__int64 *)&newValue; - return InterlockedCompareExchange64( (__int64*)value , *_newValue , *_oldValue )==*_oldValue; + __int64 *_oldValue = (__int64 *)&oldValue; + __int64 *_newValue = (__int64 *)&newValue; + return InterlockedCompareExchange64( (__int64*)value , *_newValue , *_oldValue )==*_oldValue; #else // !_WIN32 && !_WIN64 - uint64_t *_newValue = (uint64_t *)&newValue; - return __atomic_compare_exchange_n( (uint64_t *)value , (uint64_t *)&oldValue , *_newValue , false , __ATOMIC_SEQ_CST , __ATOMIC_SEQ_CST ); + uint64_t *_newValue = (uint64_t *)&newValue; + return __atomic_compare_exchange_n( (uint64_t *)value , (uint64_t *)&oldValue , *_newValue , false , __ATOMIC_SEQ_CST , __ATOMIC_SEQ_CST ); #endif // _WIN32 || _WIN64 -} + } -template< typename Number > -void AddAtomic32( volatile Number &a , Number b ) -{ + template< typename Number > + void AddAtomic32( volatile Number &a , Number b ) + { #if defined( _WIN32 ) || defined( _WIN64 ) - Number current = a; - Number sum = current+b; - long *_current = (long *)¤t; - long *_sum = (long *)∑ - while( InterlockedCompareExchange( (long*)&a , *_sum , *_current )!=*_current ) current = a , sum = a+b; + Number current = a; + Number sum = current+b; + long *_current = (long *)¤t; + long *_sum = (long *)∑ + while( InterlockedCompareExchange( (long*)&a , *_sum , *_current )!=*_current ) current = a , sum = a+b; #else // !_WIN32 && !_WIN64 - Number current = a; - Number sum = current+b; - uint32_t *_current = (uint32_t *)¤t; - uint32_t *_sum = (uint32_t *)∑ - while( __sync_val_compare_and_swap( (uint32_t *)&a , *_current , *_sum )!=*_current ) current = a , sum = a+b; + Number current = a; + Number sum = current+b; + uint32_t *_current = (uint32_t *)¤t; + uint32_t *_sum = (uint32_t *)∑ + while( __sync_val_compare_and_swap( (uint32_t *)&a , *_current , *_sum )!=*_current ) current = a , sum = a+b; #endif // _WIN32 || _WIN64 -} + } -template< typename Number > -void AddAtomic64( volatile Number &a , Number b ) -{ + template< typename Number > + void AddAtomic64( volatile Number &a , Number b ) + { #if 1 - Number current = a; - Number sum = current+b; - while( !SetAtomic64( &a , sum , current ) ) current = a , sum = a+b; + Number current = a; + Number sum = current+b; + while( !SetAtomic64( &a , sum , current ) ) current = a , sum = a+b; #else #if defined( _WIN32 ) || defined( _WIN64 ) - Number current = a; - Number sum = current+b; - __int64 *_current = (__int64 *)¤t; - __int64 *_sum = (__int64 *)∑ - while( InterlockedCompareExchange64( (__int64*)&a , *_sum , *_current )!=*_current ) current = a , sum = a+b; + Number current = a; + Number sum = current+b; + __int64 *_current = (__int64 *)¤t; + __int64 *_sum = (__int64 *)∑ + while( InterlockedCompareExchange64( (__int64*)&a , *_sum , *_current )!=*_current ) current = a , sum = a+b; #else // !_WIN32 && !_WIN64 - Number current = a; - Number sum = current+b; - uint64_t *_current = (uint64_t *)¤t; - uint64_t *_sum = (uint64_t *)∑ - while( __sync_val_compare_and_swap( (uint64_t *)&a , *_current , *_sum )!=*_current ) current = a , sum = a+b; + Number current = a; + Number sum = current+b; + uint64_t *_current = (uint64_t *)¤t; + uint64_t *_sum = (uint64_t *)∑ + while( __sync_val_compare_and_swap( (uint64_t *)&a , *_current , *_sum )!=*_current ) current = a , sum = a+b; #endif // _WIN32 || _WIN64 #endif -} - -template< typename Value > -bool SetAtomic( volatile Value *value , Value newValue , Value oldValue ) -{ - switch( sizeof(Value) ) - { - case 4: return SetAtomic32( value , newValue , oldValue ); - case 8: return SetAtomic64( value , newValue , oldValue ); - default: - WARN_ONCE( "should not use this function: " , sizeof(Value) ); - static std::mutex setAtomicMutex; - std::lock_guard< std::mutex > lock( setAtomicMutex ); - if( *value==oldValue ){ *value = newValue ; return true; } - else return false; } -} -template< typename Data > -void AddAtomic( Data& a , Data b ) -{ - switch( sizeof(Data) ) + template< typename Value > + bool SetAtomic( volatile Value *value , Value newValue , Value oldValue ) { - case 4: return AddAtomic32( a , b ); - case 8: return AddAtomic64( a , b ); - default: - WARN_ONCE( "should not use this function: " , sizeof(Data) ); - static std::mutex addAtomicMutex; - std::lock_guard< std::mutex > lock( addAtomicMutex ); - a += b; + switch( sizeof(Value) ) + { + case 4: return SetAtomic32( value , newValue , oldValue ); + case 8: return SetAtomic64( value , newValue , oldValue ); + default: + WARN_ONCE( "should not use this function: " , sizeof(Value) ); + static std::mutex setAtomicMutex; + std::lock_guard< std::mutex > lock( setAtomicMutex ); + if( *value==oldValue ){ *value = newValue ; return true; } + else return false; + } } -} -///////////////////////// -// NumberWrapper Stuff // -///////////////////////// -#include -struct EmptyNumberWrapperClass{}; - -template< typename Number , typename Type=EmptyNumberWrapperClass , size_t I=0 > -struct NumberWrapper -{ - typedef Number type; - - Number n; - - NumberWrapper( Number _n=0 ) : n(_n){} - NumberWrapper operator + ( NumberWrapper _n ) const { return NumberWrapper( n + _n.n ); } - NumberWrapper operator - ( NumberWrapper _n ) const { return NumberWrapper( n - _n.n ); } - NumberWrapper operator * ( NumberWrapper _n ) const { return NumberWrapper( n * _n.n ); } - NumberWrapper operator / ( NumberWrapper _n ) const { return NumberWrapper( n / _n.n ); } - NumberWrapper &operator += ( NumberWrapper _n ){ n += _n.n ; return *this; } - NumberWrapper &operator -= ( NumberWrapper _n ){ n -= _n.n ; return *this; } - NumberWrapper &operator *= ( NumberWrapper _n ){ n *= _n.n ; return *this; } - NumberWrapper &operator /= ( NumberWrapper _n ){ n /= _n.n ; return *this; } - bool operator == ( NumberWrapper _n ) const { return n==_n.n; } - bool operator != ( NumberWrapper _n ) const { return n!=_n.n; } - bool operator < ( NumberWrapper _n ) const { return n<_n.n; } - bool operator > ( NumberWrapper _n ) const { return n>_n.n; } - bool operator <= ( NumberWrapper _n ) const { return n<=_n.n; } - bool operator >= ( NumberWrapper _n ) const { return n>=_n.n; } - NumberWrapper operator ++ ( int ) { NumberWrapper _n(n) ; n++ ; return _n; } - NumberWrapper operator -- ( int ) { NumberWrapper _n(n) ; n-- ; return _n; } - NumberWrapper &operator ++ ( void ) { n++ ; return *this; } - NumberWrapper &operator -- ( void ) { n-- ; return *this; } - explicit operator Number () const { return n; } -}; - -#if 0 -template< typename Number , typename Type , size_t I > -struct std::atomic< NumberWrapper< Number , Type , I > > -{ - typedef Number type; - - std::atomic< Number > n; - - atomic( Number _n=0 ) : n(_n){} - atomic( const std::atomic< Number > &_n ) : n(_n){} - atomic( NumberWrapper< Number , Type , I > _n ) : n(_n.n){} - atomic &operator = ( Number _n ){ n = _n ; return *this; } -// atomic &operator = ( const atomic &a ){ n = a.n ; return *this; } -// atomic &operator = ( const NumberWrapper< Number , Type , I > &_n ){ n = _n.n ; return *this; } - atomic operator + ( atomic _n ) const { return atomic( n + _n.n ); } - atomic operator - ( atomic _n ) const { return atomic( n * _n.n ); } - atomic operator * ( atomic _n ) const { return atomic( n * _n.n ); } - atomic operator / ( atomic _n ) const { return atomic( n / _n.n ); } - atomic &operator += ( atomic _n ){ n += _n.n ; return *this; } - atomic &operator -= ( atomic _n ){ n -= _n.n ; return *this; } - atomic &operator *= ( atomic _n ){ n *= _n.n ; return *this; } - atomic &operator /= ( atomic _n ){ n /= _n.n ; return *this; } - bool operator == ( atomic _n ) const { return n==_n.n; } - bool operator != ( atomic _n ) const { return n!=_n.n; } - bool operator < ( atomic _n ) const { return n<_n.n; } - bool operator > ( atomic _n ) const { return n>_n.n; } - bool operator <= ( atomic _n ) const { return n<=_n.n; } - bool operator >= ( atomic _n ) const { return n>=_n.n; } - atomic operator ++ ( int ) { atomic _n(n) ; n++ ; return _n; } - atomic operator -- ( int ) { atomic _n(n) ; n-- ; return _n; } - atomic &operator ++ ( void ) { n++ ; return *this; } - atomic &operator -- ( void ) { n-- ; return *this; } - operator NumberWrapper< Number , Type , I >() const { return NumberWrapper< Number , Type , I >(n); } - explicit operator Number () const { return n; } -}; -#endif - - -namespace std -{ - template< typename Number , typename Type , size_t I > - struct hash< NumberWrapper< Number , Type , I > > - { - size_t operator()( NumberWrapper< Number , Type , I > n ) const { return std::hash< Number >{}( n.n ); } - }; -} - -template< typename Data , typename _NumberWrapper > -struct VectorWrapper : public std::vector< Data > -{ - VectorWrapper( void ){} - VectorWrapper( size_t sz ) : std::vector< Data >( sz ){} - VectorWrapper( size_t sz , Data d ) : std::vector< Data >( sz , d ){} - -// void resize( _NumberWrapper n ) { std::vector< Data >::resize( (size_t)(_NumberWrapper::type)n ); } -// void resize( _NumberWrapper n , Data d ){ std::vector< Data >::resize( (size_t)(_NumberWrapper::type)n , d ); } - - typename std::vector< Data >::reference operator[]( _NumberWrapper n ){ return std::vector< Data >::operator[]( n.n ); } - typename std::vector< Data >::const_reference operator[]( _NumberWrapper n ) const { return std::vector< Data >::operator[]( n.n ); } -}; - -////////////////// -// Memory Stuff // -////////////////// -size_t getPeakRSS( void ); -size_t getCurrentRSS( void ); - -struct Profiler -{ - Profiler( unsigned int ms=0 ) + template< typename Data > + void AddAtomic( Data& a , Data b ) { - _t = Time(); - _currentPeak = 0; - if( ms ) + switch( sizeof(Data) ) { - _thread = std::thread( &Profiler::_updatePeakMemoryFunction , std::ref( *this ) , ms ); - _spawnedSampler = true; + case 4: return AddAtomic32( a , b ); + case 8: return AddAtomic64( a , b ); + default: + WARN_ONCE( "should not use this function: " , sizeof(Data) ); + static std::mutex addAtomicMutex; + std::lock_guard< std::mutex > lock( addAtomicMutex ); + a += b; } - else _spawnedSampler = false; } - ~Profiler( void ) + ////////////////// + // Memory Stuff // + ////////////////// + size_t getPeakRSS( void ); + size_t getCurrentRSS( void ); + + struct Profiler { - if( _spawnedSampler ) + Profiler( unsigned int ms=0 ) { + _t = Time(); + _currentPeak = 0; + if( ms ) { - std::lock_guard< std::mutex > lock( _mutex ); - _terminate = true; + _thread = std::thread( &Profiler::_updatePeakMemoryFunction , std::ref( *this ) , ms ); + _spawnedSampler = true; } - _thread.join(); + else _spawnedSampler = false; } - } - void reset( void ) - { - _t = Time(); - if( _spawnedSampler ) + ~Profiler( void ) { - std::lock_guard< std::mutex > lock( _mutex ); - _currentPeak = 0; + if( _spawnedSampler ) + { + { + std::lock_guard< std::mutex > lock( _mutex ); + _terminate = true; + } + _thread.join(); + } } - else _currentPeak = 0; - } - void update( void ) - { - size_t currentPeak = getCurrentRSS(); - if( _spawnedSampler ) + void reset( void ) { - std::lock_guard< std::mutex > lock( _mutex ); - if( currentPeak>_currentPeak ) _currentPeak = currentPeak; + _t = Time(); + if( _spawnedSampler ) + { + std::lock_guard< std::mutex > lock( _mutex ); + _currentPeak = 0; + } + else _currentPeak = 0; } - else if( currentPeak>_currentPeak ) _currentPeak = currentPeak; - } - std::string operator()( bool showTime=true ) const - { - std::stringstream ss; - double dt = Time()-_t; - double localPeakMB = ( (double)_currentPeak )/(1<<20); - double globalPeakMB = ( (double)getPeakRSS() )/(1<<20); + void update( void ) { - StreamFloatPrecision sfp( ss , 1 ); - if( showTime ) ss << dt << " (s), "; - ss << localPeakMB << " (MB) / " << globalPeakMB << " (MB)"; + size_t currentPeak = getCurrentRSS(); + if( _spawnedSampler ) + { + std::lock_guard< std::mutex > lock( _mutex ); + if( currentPeak>_currentPeak ) _currentPeak = currentPeak; + } + else if( currentPeak>_currentPeak ) _currentPeak = currentPeak; } - return ss.str(); - } - friend std::ostream &operator << ( std::ostream &os , const Profiler &profiler ){ return os << profiler(); } + std::string operator()( bool showTime=true ) const + { + std::stringstream ss; + double dt = Time()-_t; + double localPeakMB = ( (double)_currentPeak )/(1<<20); + double globalPeakMB = ( (double)getPeakRSS() )/(1<<20); + { + StreamFloatPrecision sfp( ss , 1 ); + if( showTime ) ss << dt << " (s), "; + ss << localPeakMB << " (MB) / " << globalPeakMB << " (MB)"; + } + return ss.str(); + } -protected: - std::thread _thread; - std::mutex _mutex; - bool _spawnedSampler; - double _t; - volatile size_t _currentPeak; - volatile bool _terminate; + friend std::ostream &operator << ( std::ostream &os , const Profiler &profiler ){ return os << profiler(); } - void _updatePeakMemoryFunction( unsigned int ms ) - { - while( true ) + protected: + std::thread _thread; + std::mutex _mutex; + bool _spawnedSampler; + double _t; + volatile size_t _currentPeak; + volatile bool _terminate; + + void _updatePeakMemoryFunction( unsigned int ms ) { - std::this_thread::sleep_for( std::chrono::milliseconds( ms ) ); - update(); - if( _terminate ) return; - } + while( true ) + { + std::this_thread::sleep_for( std::chrono::milliseconds( ms ) ); + update(); + if( _terminate ) return; + } + }; }; -}; -struct MemoryInfo -{ - static size_t Usage( void ){ return getCurrentRSS(); } - static int PeakMemoryUsageMB( void ){ return (int)( getPeakRSS()>>20 ); } -}; + struct MemoryInfo + { + static size_t Usage( void ){ return getCurrentRSS(); } + static int PeakMemoryUsageMB( void ){ return (int)( getPeakRSS()>>20 ); } + }; #if defined( _WIN32 ) || defined( _WIN64 ) -#include -#include -inline void SetPeakMemoryMB( size_t sz ) -{ - sz <<= 20; - SIZE_T peakMemory = sz; - HANDLE h = CreateJobObject( NULL , NULL ); - AssignProcessToJobObject( h , GetCurrentProcess() ); + inline void SetPeakMemoryMB( size_t sz ) + { + sz <<= 20; + SIZE_T peakMemory = sz; + 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 ) ) ) WARN( "Failed to set memory limit" ); -} + JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 }; + jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_JOB_MEMORY; + jeli.JobMemoryLimit = peakMemory; + if( !SetInformationJobObject( h , JobObjectExtendedLimitInformation , &jeli , sizeof( jeli ) ) ) WARN( "Failed to set memory limit" ); + } #else // !_WIN32 && !_WIN64 -#include -#include -inline void SetPeakMemoryMB( size_t sz ) -{ - sz <<= 20; - struct rlimit rl; - getrlimit( RLIMIT_AS , &rl ); - rl.rlim_cur = sz; - setrlimit( RLIMIT_AS , &rl ); -} + inline void SetPeakMemoryMB( size_t sz ) + { + sz <<= 20; + struct rlimit rl; + getrlimit( RLIMIT_AS , &rl ); + rl.rlim_cur = sz; + setrlimit( RLIMIT_AS , &rl ); + } #endif // _WIN32 || _WIN64 -/* -* Author: David Robert Nadeau -* Site: http://NadeauSoftware.com/ -* License: Creative Commons Attribution 3.0 Unported License -* http://creativecommons.org/licenses/by/3.0/deed.en_US -*/ - -#if defined(_WIN32) || defined( _WIN64 ) -#include -#include - -#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) -#include -#include - -#if defined(__APPLE__) && defined(__MACH__) -#include + /* + * Author: David Robert Nadeau + * Site: http://NadeauSoftware.com/ + * License: Creative Commons Attribution 3.0 Unported License + * http://creativecommons.org/licenses/by/3.0/deed.en_US + */ -#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__))) -#include -#include - -#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__) -#include - -#endif - -#else -#error "Cannot define getPeakRSS( ) or getCurrentRSS( ) for an unknown OS." -#endif - - - - - -/** -* Returns the peak (maximum so far) resident set size (physical -* memory use) measured in bytes, or zero if the value cannot be -* determined on this OS. -*/ -inline size_t getPeakRSS( ) -{ + /** + * Returns the peak (maximum so far) resident set size (physical + * memory use) measured in bytes, or zero if the value cannot be + * determined on this OS. + */ + inline size_t getPeakRSS( ) + { #if defined(_WIN32) - /* Windows -------------------------------------------------- */ - PROCESS_MEMORY_COUNTERS info; - GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) ); - return (size_t)info.PeakWorkingSetSize; + /* Windows -------------------------------------------------- */ + PROCESS_MEMORY_COUNTERS info; + GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) ); + return (size_t)info.PeakWorkingSetSize; #elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__))) - /* AIX and Solaris ------------------------------------------ */ - struct psinfo psinfo; - int fd = -1; - if ( (fd = open( "/proc/self/psinfo", O_RDONLY )) == -1 ) - return (size_t)0L; /* Can't open? */ - if ( read( fd, &psinfo, sizeof(psinfo) ) != sizeof(psinfo) ) - { + /* AIX and Solaris ------------------------------------------ */ + struct psinfo psinfo; + int fd = -1; + if ( (fd = open( "/proc/self/psinfo", O_RDONLY )) == -1 ) + return (size_t)0L; /* Can't open? */ + if ( read( fd, &psinfo, sizeof(psinfo) ) != sizeof(psinfo) ) + { + close( fd ); + return (size_t)0L; /* Can't read? */ + } close( fd ); - return (size_t)0L; /* Can't read? */ - } - close( fd ); - return (size_t)(psinfo.pr_rssize * 1024L); + return (size_t)(psinfo.pr_rssize * 1024L); #elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) - /* BSD, Linux, and OSX -------------------------------------- */ - struct rusage rusage; - getrusage( RUSAGE_SELF, &rusage ); + /* BSD, Linux, and OSX -------------------------------------- */ + struct rusage rusage; + getrusage( RUSAGE_SELF, &rusage ); #if defined(__APPLE__) && defined(__MACH__) - return (size_t)rusage.ru_maxrss; + return (size_t)rusage.ru_maxrss; #else - return (size_t)(rusage.ru_maxrss * 1024L); + return (size_t)(rusage.ru_maxrss * 1024L); #endif #else - /* Unknown OS ----------------------------------------------- */ - return (size_t)0L; /* Unsupported. */ + /* Unknown OS ----------------------------------------------- */ + return (size_t)0L; /* Unsupported. */ #endif -} + } -/** -* Returns the current resident set size (physical memory use) measured -* in bytes, or zero if the value cannot be determined on this OS. -*/ -inline size_t getCurrentRSS( ) -{ + /** + * Returns the current resident set size (physical memory use) measured + * in bytes, or zero if the value cannot be determined on this OS. + */ + inline size_t getCurrentRSS( ) + { #if defined(_WIN32) || defined( _WIN64 ) - /* Windows -------------------------------------------------- */ - PROCESS_MEMORY_COUNTERS info; - GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) ); - return (size_t)info.WorkingSetSize; + /* Windows -------------------------------------------------- */ + PROCESS_MEMORY_COUNTERS info; + GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) ); + return (size_t)info.WorkingSetSize; #elif defined(__APPLE__) && defined(__MACH__) - /* OSX ------------------------------------------------------ */ - struct mach_task_basic_info info; - mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT; - if ( task_info( mach_task_self( ), MACH_TASK_BASIC_INFO, - (task_info_t)&info, &infoCount ) != KERN_SUCCESS ) - return (size_t)0L; /* Can't access? */ - return (size_t)info.resident_size; + /* OSX ------------------------------------------------------ */ + struct mach_task_basic_info info; + mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT; + if ( task_info( mach_task_self( ), MACH_TASK_BASIC_INFO, + (task_info_t)&info, &infoCount ) != KERN_SUCCESS ) + return (size_t)0L; /* Can't access? */ + return (size_t)info.resident_size; #elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__) - /* Linux ---------------------------------------------------- */ - long rss = 0L; - FILE* fp = NULL; - if ( (fp = fopen( "/proc/self/statm", "r" )) == NULL ) - return (size_t)0L; /* Can't open? */ - if ( fscanf( fp, "%*s%ld", &rss ) != 1 ) - { + /* Linux ---------------------------------------------------- */ + long rss = 0L; + FILE* fp = NULL; + if ( (fp = fopen( "/proc/self/statm", "r" )) == NULL ) + return (size_t)0L; /* Can't open? */ + if ( fscanf( fp, "%*s%ld", &rss ) != 1 ) + { + fclose( fp ); + return (size_t)0L; /* Can't read? */ + } fclose( fp ); - return (size_t)0L; /* Can't read? */ - } - fclose( fp ); - return (size_t)rss * (size_t)sysconf( _SC_PAGESIZE); + return (size_t)rss * (size_t)sysconf( _SC_PAGESIZE); #else - /* AIX, BSD, Solaris, and Unknown OS ------------------------ */ - return (size_t)0L; /* Unsupported. */ + /* AIX, BSD, Solaris, and Unknown OS ------------------------ */ + return (size_t)0L; /* Unsupported. */ #endif + } } #endif // MY_MISCELLANY_INCLUDED diff --git a/Src/PNG.h b/Src/PNG.h index 94850725..c7f82e6e 100644 --- a/Src/PNG.h +++ b/Src/PNG.h @@ -29,35 +29,42 @@ DAMAGE. #ifndef PNG_INCLUDED #define PNG_INCLUDED +#include +#include +#include "Image.h" #include "PNG/png.h" -struct PNGReader : public ImageReader +namespace PoissonRecon { - PNGReader( const char* fileName , unsigned int& width , unsigned int& height , unsigned int& channels ); - ~PNGReader( void ); - unsigned int nextRow( unsigned char* row ); - static bool GetInfo( const char* fileName , unsigned int& width , unsigned int& height , unsigned int& channels ); -protected: - png_structp _png_ptr; - png_infop _info_ptr; - png_infop _end_info ; - FILE* _fp; - unsigned char* _scratchRow; - unsigned int _currentRow; -}; - -struct PNGWriter : public ImageWriter -{ - PNGWriter( const char* fileName , unsigned int width , unsigned int height , unsigned int channels , unsigned int quality=100 ); - ~PNGWriter( void ); - unsigned int nextRow( const unsigned char* row ); - unsigned int nextRows( const unsigned char* rows , unsigned int rowNum ); -protected: - FILE* _fp; - png_structp _png_ptr; - png_infop _info_ptr; - unsigned int _currentRow; -}; + struct PNGReader : public ImageReader + { + PNGReader( const char* fileName , unsigned int& width , unsigned int& height , unsigned int& channels ); + ~PNGReader( void ); + unsigned int nextRow( unsigned char* row ); + static bool GetInfo( const char* fileName , unsigned int& width , unsigned int& height , unsigned int& channels ); + protected: + png_structp _png_ptr; + png_infop _info_ptr; + png_infop _end_info ; + FILE* _fp; + unsigned char* _scratchRow; + unsigned int _currentRow; + }; + + struct PNGWriter : public ImageWriter + { + PNGWriter( const char* fileName , unsigned int width , unsigned int height , unsigned int channels , unsigned int quality=100 ); + ~PNGWriter( void ); + unsigned int nextRow( const unsigned char* row ); + unsigned int nextRows( const unsigned char* rows , unsigned int rowNum ); + protected: + FILE* _fp; + png_structp _png_ptr; + png_infop _info_ptr; + unsigned int _currentRow; + }; #include "PNG.inl" +} + #endif //PNG_INCLUDED diff --git a/Src/PNG.inl b/Src/PNG.inl index 273f8052..bbf4d69f 100644 --- a/Src/PNG.inl +++ b/Src/PNG.inl @@ -26,9 +26,6 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ -#include -#include - inline PNGReader::PNGReader( const char* fileName , unsigned int& width , unsigned int& height , unsigned int& channels ) { _currentRow = 0; diff --git a/Src/PPolynomial.h b/Src/PPolynomial.h index 1b6b1c20..70e96158 100644 --- a/Src/PPolynomial.h +++ b/Src/PPolynomial.h @@ -31,83 +31,89 @@ DAMAGE. #include #include "Polynomial.h" #include "Array.h" +#include "Factor.h" -template< int Degree > -class StartingPolynomial +namespace PoissonRecon { -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 ); + 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& operator = ( const PPolynomial& p ); + PPolynomial( void ); + PPolynomial( const PPolynomial& p ); + ~PPolynomial( void ); - int size( void ) const; + PPolynomial& operator = ( const PPolynomial& p ); - 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. ); + 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 ); + double operator()( double t ) const; + double integral( double tMin , double tMax ) const; + double Integral( void ) const; - PPolynomial operator + ( const PPolynomial& p ) const; - PPolynomial operator - ( const PPolynomial& p ) const; + template< int Degree2 > PPolynomial< Degree >& operator = ( const PPolynomial< Degree2 >& p ); - 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 + ( 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& 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 scale( double s ) const; - PPolynomial shift( double t ) const; - PPolynomial reflect( double r=0. ) const; + PPolynomial& addScaled( const PPolynomial& poly , double scale ); - PPolynomial< Degree-1 > derivative(void) const; - PPolynomial< Degree+1 > integral(void) const; + PPolynomial scale( double s ) const; + PPolynomial shift( double t ) const; + PPolynomial reflect( double r=0. ) const; - void getSolutions( double c , std::vector< double >& roots , double EPS , double min=-DBL_MAX , double max=DBL_MAX ) const; + PPolynomial< Degree-1 > derivative(void) const; + PPolynomial< Degree+1 > integral(void) const; - void printnl( void ) const; + void getSolutions( double c , std::vector< double >& roots , double EPS , double min=-DBL_MAX , double max=DBL_MAX ) const; - PPolynomial< Degree+1 > MovingAverage( double radius ) const; - static PPolynomial BSpline( double radius=0.5 ); + void printnl( void ) const; - void write( FILE* fp , int samples , double min , double max ) 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/PPolynomial.inl b/Src/PPolynomial.inl index be25aff0..324731bb 100644 --- a/Src/PPolynomial.inl +++ b/Src/PPolynomial.inl @@ -26,8 +26,6 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ -#include "Factor.h" - //////////////////////// // StartingPolynomial // //////////////////////// diff --git a/Src/Ply.h b/Src/Ply.h index ece6acff..2f70d0c3 100644 --- a/Src/Ply.h +++ b/Src/Ply.h @@ -51,69 +51,74 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include "PlyFile.h" #include "Geometry.h" #include "DataStream.h" #include "MyMiscellany.h" #include "Array.h" -namespace PLY +namespace PoissonRecon { - // Converts from C-type to PLY type - template< class Scalar > int Type( void ); + namespace PLY + { + // Converts from C-type to PLY type + template< class Scalar > int Type( void ); - // Converts from C-type to PLY name - template< typename Integer > struct Traits{ static const std::string name; }; + // Converts from C-type to PLY name + template< typename Integer > struct Traits{ static const std::string name; }; - // A structure representing a face - template< typename Index > - struct Edge - { - Index v1 , v2; - static PlyProperty Properties[]; - }; + // A structure representing a face + template< typename Index > + struct Edge + { + Index v1 , v2; + static PlyProperty Properties[]; + }; - // A structure representing a face - template< typename Index , bool UseCharIndex=false > - struct Face - { - unsigned int nr_vertices; - Index *vertices; + // A structure representing a face + template< typename Index , bool UseCharIndex=false > + struct Face + { + unsigned int nr_vertices; + Index *vertices; - static PlyProperty Properties[]; - }; + static PlyProperty Properties[]; + }; - int DefaultFileType( void ); + int DefaultFileType( void ); - // PLY read header functionality + // PLY read header functionality - // Get the properties (and return the file type) - int ReadVertexHeader( std::string fileName , std::vector< PlyProperty > &properties ); + // Get the properties (and return the file type) + int ReadVertexHeader( std::string fileName , std::vector< PlyProperty > &properties ); - // Test which properties are represented by elements of the vertex factory (and return the file type) - template< typename VertexFactory > - int ReadVertexHeader( std::string fileName , const VertexFactory &vFactory , bool *readFlags ); + // Test which properties are represented by elements of the vertex factory (and return the file type) + template< typename VertexFactory > + int ReadVertexHeader( std::string fileName , const VertexFactory &vFactory , bool *readFlags ); - // Test which properties are represented by elements of the vertex factory and add the others to the property list (and return the file type) - template< typename VertexFactory > - int ReadVertexHeader( std::string fileName , const VertexFactory &vFactory , bool *readFlags , std::vector< PlyProperty > &unprocessedProperties ); + // Test which properties are represented by elements of the vertex factory and add the others to the property list (and return the file type) + template< typename VertexFactory > + int ReadVertexHeader( std::string fileName , const VertexFactory &vFactory , bool *readFlags , std::vector< PlyProperty > &unprocessedProperties ); - // PLY write mesh functionality - template< typename VertexFactory , typename Index , class Real , int Dim , typename OutputIndex=int , bool UseCharIndex=false > - void Write( std::string fileName , const VertexFactory &vFactory , size_t vertexNum , size_t polygonNum , InputDataStream< typename VertexFactory::VertexType > &vertexStream , InputDataStream< std::vector< Index > > &polygonStream , int file_type , const std::vector< std::string >& comments ); + // PLY write mesh functionality + template< typename VertexFactory , typename Index , class Real , int Dim , typename OutputIndex=int , bool UseCharIndex=false > + void Write( std::string fileName , const VertexFactory &vFactory , size_t vertexNum , size_t polygonNum , InputDataStream< typename VertexFactory::VertexType > &vertexStream , InputDataStream< std::vector< Index > > &polygonStream , int file_type , const std::vector< std::string >& comments ); - template< typename VertexFactory , typename Index , class Real , int Dim , typename OutputIndex=int > - void Write( std::string fileName , const VertexFactory &vFactory , size_t vertexNum , size_t edgeNum , InputDataStream< typename VertexFactory::VertexType > &vertexStream , InputDataStream< std::pair< Index , Index > > &edgeStream , int file_type , const std::vector< std::string >& comments ); + template< typename VertexFactory , typename Index , class Real , int Dim , typename OutputIndex=int > + void Write( std::string fileName , const VertexFactory &vFactory , size_t vertexNum , size_t edgeNum , InputDataStream< typename VertexFactory::VertexType > &vertexStream , InputDataStream< std::pair< Index , Index > > &edgeStream , int file_type , const std::vector< std::string >& comments ); - template< typename VertexFactory , typename Index , bool UseCharIndex=false > - void WritePolygons( std::string fileName , const VertexFactory &vFactory , const std::vector< typename VertexFactory::VertexType > &vertices , const std::vector< std::vector< Index > > &polygons , int file_type , const std::vector< std::string > &comments ); + template< typename VertexFactory , typename Index , bool UseCharIndex=false > + void WritePolygons( std::string fileName , const VertexFactory &vFactory , const std::vector< typename VertexFactory::VertexType > &vertices , const std::vector< std::vector< Index > > &polygons , int file_type , const std::vector< std::string > &comments ); - // PLY read mesh functionality - template< typename VertexFactory , typename Index > - void ReadPolygons( std::string fileName , const VertexFactory &vFactory , std::vector< typename VertexFactory::VertexType > &vertices , std::vector< std::vector< Index > >& polygons , int &file_type , std::vector< std::string > &comments , bool* readFlags=NULL ); + // PLY read mesh functionality + template< typename VertexFactory , typename Index > + void ReadPolygons( std::string fileName , const VertexFactory &vFactory , std::vector< typename VertexFactory::VertexType > &vertices , std::vector< std::vector< Index > >& polygons , int &file_type , std::vector< std::string > &comments , bool* readFlags=NULL ); - template< typename VertexFactory , typename Index > - void ReadEdges( std::string fileName , const VertexFactory &vFactory , std::vector< typename VertexFactory::VertexType > &vertices , std::vector< std::pair< Index , Index > >& edges , int &file_type , std::vector< std::string > &comments , bool* readFlags=NULL ); -} + template< typename VertexFactory , typename Index > + void ReadEdges( std::string fileName , const VertexFactory &vFactory , std::vector< typename VertexFactory::VertexType > &vertices , std::vector< std::pair< Index , Index > >& edges , int &file_type , std::vector< std::string > &comments , bool* readFlags=NULL ); + } #include "Ply.inl" +} + #endif // PLY_INCLUDED diff --git a/Src/PlyFile.h b/Src/PlyFile.h index 7a2a6e26..6f77aa9f 100644 --- a/Src/PlyFile.h +++ b/Src/PlyFile.h @@ -58,6 +58,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "MyMiscellany.h" #include "Streams.h" +namespace PoissonRecon +{ #define PLY_ASCII 1 /* ascii PLY file */ #define PLY_BINARY_BE 2 /* binary PLY file, big endian */ @@ -98,175 +100,176 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define PLY_STRIP_COMMENT_HEADER 0 -const std::string PlyTypes[] -{ - "start type" , - "char" , - "short" , - "int" , - "long long " , - "unsigned char" , - "unsigned short" , - "unsigned int" , - "unsigned long long" , - "float" , - "double" , - "int8" , - "unsigned int8" , - "int16" , - "unsigned int16" , - "int32" , - "unsigned int32" , - "int64" , - "unsigned int64" , - "float32" , - "float64" -}; - -/* description of a property */ -struct PlyProperty -{ - std::string name; /* property name */ - int external_type; /* file's data type */ - int internal_type; /* program's data type */ - int offset; /* offset bytes of prop in a struct */ - - int is_list; /* 1 = list, 0 = scalar */ - int count_external; /* file's count type */ - int count_internal; /* program's count type */ - int count_offset; /* offset byte for list count */ - - PlyProperty( const std::string &n , int et , int it , int o , int il=0 , int ce=0 , int ci=0 , int co=0 ) : name(n) , external_type(et) , internal_type(it) , offset(o) , is_list(il) , count_external(ce) , count_internal(ci) , count_offset(co){ } - PlyProperty( const std::string &n ) : PlyProperty( n , 0 , 0 , 0 , 0 , 0 , 0 , 0 ){ } - PlyProperty( void ) : external_type(0) , internal_type(0) , offset(0) , is_list(0) , count_external(0) , count_internal(0) , count_offset(0){ } - - void write( BinaryStream &stream ) const + const std::string PlyTypes[] { - stream.write( name ); - stream.write( external_type ); - stream.write( offset ); - stream.write( is_list ); - stream.write( count_external ); - stream.write( count_internal ); - stream.write( count_offset ); - } - void read( BinaryStream &stream ) + "start type" , + "char" , + "short" , + "int" , + "long long " , + "unsigned char" , + "unsigned short" , + "unsigned int" , + "unsigned long long" , + "float" , + "double" , + "int8" , + "unsigned int8" , + "int16" , + "unsigned int16" , + "int32" , + "unsigned int32" , + "int64" , + "unsigned int64" , + "float32" , + "float64" + }; + + /* description of a property */ + struct PlyProperty { - if( !stream.read( name ) ) ERROR_OUT( "Failed to read name" ); - if( !stream.read( external_type ) ) ERROR_OUT( "Failed to read external_type" ); - if( !stream.read( offset ) ) ERROR_OUT( "Failed to read offset" ); - if( !stream.read( is_list ) ) ERROR_OUT( "Failed to read is_list" ); - if( !stream.read( count_external ) ) ERROR_OUT( "Failed to read count_external" ); - if( !stream.read( count_internal ) ) ERROR_OUT( "Failed to read count_internal" ); - if( !stream.read( count_offset ) ) ERROR_OUT( "Failed to read count_offset" ); + std::string name; /* property name */ + int external_type; /* file's data type */ + int internal_type; /* program's data type */ + int offset; /* offset bytes of prop in a struct */ + + int is_list; /* 1 = list, 0 = scalar */ + int count_external; /* file's count type */ + int count_internal; /* program's count type */ + int count_offset; /* offset byte for list count */ + + PlyProperty( const std::string &n , int et , int it , int o , int il=0 , int ce=0 , int ci=0 , int co=0 ) : name(n) , external_type(et) , internal_type(it) , offset(o) , is_list(il) , count_external(ce) , count_internal(ci) , count_offset(co){ } + PlyProperty( const std::string &n ) : PlyProperty( n , 0 , 0 , 0 , 0 , 0 , 0 , 0 ){ } + PlyProperty( void ) : external_type(0) , internal_type(0) , offset(0) , is_list(0) , count_external(0) , count_internal(0) , count_offset(0){ } + + void write( BinaryStream &stream ) const + { + stream.write( name ); + stream.write( external_type ); + stream.write( offset ); + stream.write( is_list ); + stream.write( count_external ); + stream.write( count_internal ); + stream.write( count_offset ); + } + void read( BinaryStream &stream ) + { + if( !stream.read( name ) ) ERROR_OUT( "Failed to read name" ); + if( !stream.read( external_type ) ) ERROR_OUT( "Failed to read external_type" ); + if( !stream.read( offset ) ) ERROR_OUT( "Failed to read offset" ); + if( !stream.read( is_list ) ) ERROR_OUT( "Failed to read is_list" ); + if( !stream.read( count_external ) ) ERROR_OUT( "Failed to read count_external" ); + if( !stream.read( count_internal ) ) ERROR_OUT( "Failed to read count_internal" ); + if( !stream.read( count_offset ) ) ERROR_OUT( "Failed to read count_offset" ); + } + }; + + std::ostream &operator << ( std::ostream &os , PlyProperty p ) + { + if( p.is_list ) return os << "{ " << p.name << " , " << PlyTypes[ p.count_external ] << " -> " << PlyTypes[ p.count_internal ] << " , " << PlyTypes[ p.external_type ] << " -> " << PlyTypes[ p.internal_type ] << " , " << p.offset << " }"; + else return os << "{ " << p.name << " , " << PlyTypes[ p.external_type ] << " -> " << PlyTypes[ p.internal_type ] << " , " << p.offset << " }"; } -}; - -std::ostream &operator << ( std::ostream &os , PlyProperty p ) -{ - if( p.is_list ) return os << "{ " << p.name << " , " << PlyTypes[ p.count_external ] << " -> " << PlyTypes[ p.count_internal ] << " , " << PlyTypes[ p.external_type ] << " -> " << PlyTypes[ p.internal_type ] << " , " << p.offset << " }"; - else return os << "{ " << p.name << " , " << PlyTypes[ p.external_type ] << " -> " << PlyTypes[ p.internal_type ] << " , " << p.offset << " }"; -} -struct PlyStoredProperty -{ - PlyProperty prop ; char store; - PlyStoredProperty( void ){ } - PlyStoredProperty( const PlyProperty &p , char s ) : prop(p) , store(s){ } -}; + struct PlyStoredProperty + { + PlyProperty prop ; char store; + PlyStoredProperty( void ){ } + PlyStoredProperty( const PlyProperty &p , char s ) : prop(p) , store(s){ } + }; -/* description of an element */ -struct PlyElement -{ - std::string name; /* element name */ - size_t num; /* number of elements in this object */ - int size; /* size of element (bytes) or -1 if variable */ - std::vector< PlyStoredProperty > props; /* list of properties in the file */ - int other_offset; /* offset to un-asked-for props, or -1 if none*/ - int other_size; /* size of other_props structure */ - PlyProperty *find_property( const std::string &prop_name , int &index ); -}; - -/* describes other properties in an element */ -struct PlyOtherProp -{ - std::string name; /* element name */ - int size; /* size of other_props */ - std::vector< PlyProperty > props; /* list of properties in other_props */ -}; + /* description of an element */ + struct PlyElement + { + std::string name; /* element name */ + size_t num; /* number of elements in this object */ + int size; /* size of element (bytes) or -1 if variable */ + std::vector< PlyStoredProperty > props; /* list of properties in the file */ + int other_offset; /* offset to un-asked-for props, or -1 if none*/ + int other_size; /* size of other_props structure */ + PlyProperty *find_property( const std::string &prop_name , int &index ); + }; + + /* describes other properties in an element */ + struct PlyOtherProp + { + std::string name; /* element name */ + int size; /* size of other_props */ + std::vector< PlyProperty > props; /* list of properties in other_props */ + }; -/* storing other_props for an other element */ -struct OtherData -{ - void *other_props; - OtherData( void ) : other_props(NULL){ } - ~OtherData( void ){ if( other_props ) free( other_props ); } -}; + /* storing other_props for an other element */ + struct OtherData + { + void *other_props; + OtherData( void ) : other_props(NULL){ } + ~OtherData( void ){ if( other_props ) free( other_props ); } + }; -/* data for one "other" element */ -struct OtherElem -{ - std::string elem_name; /* names of other elements */ - std::vector< OtherData > other_data; /* actual property data for the elements */ - PlyOtherProp other_props; /* description of the property data */ -}; + /* data for one "other" element */ + struct OtherElem + { + std::string elem_name; /* names of other elements */ + std::vector< OtherData > other_data; /* actual property data for the elements */ + PlyOtherProp other_props; /* description of the property data */ + }; -/* "other" elements, not interpreted by user */ -struct PlyOtherElems -{ - std::vector< OtherElem > other_list; /* list of data for other elements */ -}; + /* "other" elements, not interpreted by user */ + struct PlyOtherElems + { + std::vector< OtherElem > other_list; /* list of data for other elements */ + }; -/* description of PLY file */ -struct PlyFile -{ - FILE *fp; /* file pointer */ - int file_type; /* ascii or binary */ - float version; /* version number of file */ - std::vector< PlyElement > elems; /* list of elements of object */ - std::vector< std::string > comments; /* list of comments */ - std::vector< std::string > obj_info; /* list of object info items */ - PlyElement *which_elem; /* which element we're currently writing */ - PlyOtherElems *other_elems; /* "other" elements from a PLY file */ - - static PlyFile *Write( const std::string & , const std::vector< std::string > & , int , float & ); - static PlyFile *Read ( const std::string & , std::vector< std::string > & , int & , float & ); - - PlyFile( FILE *f ) : fp(f) , other_elems(NULL) , version(1.) { } - ~PlyFile( void ){ if( fp ) fclose(fp) ; if(other_elems) delete other_elems; } - - void describe_element ( const std::string & , size_t , int , const PlyProperty * ); - void describe_property( const std::string & , const PlyProperty * ); - void describe_other_elements( PlyOtherElems * ); - PlyElement *find_element( const std::string & ); - void element_count( const std::string & , size_t ); - void header_complete( void ); - void put_element_setup( const std::string & ); - void put_element ( void * ); - void put_comment ( const std::string & ); - void put_obj_info( const std::string & ); - void put_other_elements( void ); - void add_element ( const std::vector< std::string > & ); - void add_property( const std::vector< std::string > & ); - void add_comment ( const std::string & ); - void add_obj_info( const std::string & ); - - std::vector< PlyProperty > get_element_description( const std::string & , size_t & ); - void get_element_setup( const std::string & , int , PlyProperty * ); - int get_property( const std::string & , const PlyProperty * ); - void describe_other_properties( const PlyOtherProp & , int ); - bool set_other_properties( const std::string & , int , PlyOtherProp & ); - void get_element( void * ); - std::vector< std::string > &get_comments( void ); - std::vector< std::string > &get_obj_info( void ); - void get_info( float & , int & ); - PlyOtherElems *get_other_element( std::string & , size_t ); -protected: - void _ascii_get_element ( void * ); - void _binary_get_element( void * ); - static PlyFile *_Write( FILE * , const std::vector< std::string > & , int ); - static PlyFile *_Read ( FILE * , std::vector< std::string > & ); -}; + /* description of PLY file */ + struct PlyFile + { + FILE *fp; /* file pointer */ + int file_type; /* ascii or binary */ + float version; /* version number of file */ + std::vector< PlyElement > elems; /* list of elements of object */ + std::vector< std::string > comments; /* list of comments */ + std::vector< std::string > obj_info; /* list of object info items */ + PlyElement *which_elem; /* which element we're currently writing */ + PlyOtherElems *other_elems; /* "other" elements from a PLY file */ + + static PlyFile *Write( const std::string & , const std::vector< std::string > & , int , float & ); + static PlyFile *Read ( const std::string & , std::vector< std::string > & , int & , float & ); + + PlyFile( FILE *f ) : fp(f) , other_elems(NULL) , version(1.) { } + ~PlyFile( void ){ if( fp ) fclose(fp) ; if(other_elems) delete other_elems; } + + void describe_element ( const std::string & , size_t , int , const PlyProperty * ); + void describe_property( const std::string & , const PlyProperty * ); + void describe_other_elements( PlyOtherElems * ); + PlyElement *find_element( const std::string & ); + void element_count( const std::string & , size_t ); + void header_complete( void ); + void put_element_setup( const std::string & ); + void put_element ( void * ); + void put_comment ( const std::string & ); + void put_obj_info( const std::string & ); + void put_other_elements( void ); + void add_element ( const std::vector< std::string > & ); + void add_property( const std::vector< std::string > & ); + void add_comment ( const std::string & ); + void add_obj_info( const std::string & ); + + std::vector< PlyProperty > get_element_description( const std::string & , size_t & ); + void get_element_setup( const std::string & , int , PlyProperty * ); + int get_property( const std::string & , const PlyProperty * ); + void describe_other_properties( const PlyOtherProp & , int ); + bool set_other_properties( const std::string & , int , PlyOtherProp & ); + void get_element( void * ); + std::vector< std::string > &get_comments( void ); + std::vector< std::string > &get_obj_info( void ); + void get_info( float & , int & ); + PlyOtherElems *get_other_element( std::string & , size_t ); + protected: + void _ascii_get_element ( void * ); + void _binary_get_element( void * ); + static PlyFile *_Write( FILE * , const std::vector< std::string > & , int ); + static PlyFile *_Read ( FILE * , std::vector< std::string > & ); + }; #include "PlyFile.inl" +} #endif // PLY_FILE_INCLUDED diff --git a/Src/PlyFile.inl b/Src/PlyFile.inl index a5c6f146..4d2b034f 100644 --- a/Src/PlyFile.inl +++ b/Src/PlyFile.inl @@ -47,12 +47,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include -#include -#include -#include -#include "MyMiscellany.h" - const char *type_names[] = { "invalid", @@ -114,13 +108,13 @@ typedef union static int native_binary_type = -1; static int types_checked = 0; -#define NO_OTHER_PROPS -1 +static const int no_other_props = -1; -#define DONT_STORE_PROP 0 -#define STORE_PROP 1 +static const int dont_store_prop = 0; +static const int store_prop = 1; -#define OTHER_PROP 0 -#define NAMED_PROP 1 +static const int other_prop = 0; +static const int named_prop = 1; /* write to a file the word describing a PLY file data type */ @@ -256,7 +250,7 @@ void PlyFile::describe_element( const std::string &elem_name , size_t nelems , i /* copy the list of properties */ elem->props.resize( nprops ); - for( int i=0 ; iprops[i] = PlyStoredProperty( prop_list[i] , NAMED_PROP ); + for( int i=0 ; iprops[i] = PlyStoredProperty( prop_list[i] , named_prop ); } @@ -278,7 +272,7 @@ void PlyFile::describe_property( const std::string &elem_name , const PlyPropert return; } - elem->props.push_back( PlyStoredProperty( *prop , NAMED_PROP ) ); + elem->props.push_back( PlyStoredProperty( *prop , named_prop ) ); } @@ -298,7 +292,7 @@ void PlyFile::describe_other_properties( const PlyOtherProp &other , int offset } elem->props.reserve( elem->props.size() + other.props.size() ); - for( int i=0 ; iprops.push_back( PlyStoredProperty( other.props[i] , OTHER_PROP ) ); + for( int i=0 ; iprops.push_back( PlyStoredProperty( other.props[i] , other_prop ) ); /* save other info about other properties */ elem->other_size = other.size; @@ -422,7 +416,7 @@ void PlyFile::put_element( void *elem_ptr ) /* write out each property of the element */ for( int j=0 ; jprops.size() ; j++ ) { - if( elem->props[j].store==OTHER_PROP ) elem_data = *other_ptr; + if( elem->props[j].store==other_prop ) elem_data = *other_ptr; else elem_data = (char *)elem_ptr; if( elem->props[j].prop.is_list ) { @@ -454,7 +448,7 @@ void PlyFile::put_element( void *elem_ptr ) /* write out each property of the element */ for( int j=0 ; jprops.size() ; j++ ) { - if (elem->props[j].store==OTHER_PROP ) elem_data = *other_ptr; + if (elem->props[j].store==other_prop ) elem_data = *other_ptr; else elem_data = (char *)elem_ptr; if( elem->props[j].prop.is_list ) { @@ -565,8 +559,8 @@ PlyFile *PlyFile::_Read( FILE *fp , std::vector< std::string > &elem_names ) /* later to say whether or not to store each property for the user */ for( int i=0 ; ielems.size() ; i++ ) { - for( int j=0 ; jelems[i].props.size() ; j++ ) plyfile->elems[i].props[j].store = DONT_STORE_PROP; - plyfile->elems[i].other_offset = NO_OTHER_PROPS; /* no "other" props by default */ + for( int j=0 ; jelems[i].props.size() ; j++ ) plyfile->elems[i].props[j].store = dont_store_prop; + plyfile->elems[i].other_offset = no_other_props; /* no "other" props by default */ } /* set return values about the elements */ @@ -678,7 +672,7 @@ void PlyFile::get_element_setup( const std::string &elem_name , int nprops , Ply prop->count_offset = prop_list[i].count_offset; /* specify that the user wants this property */ - elem->props[index].store = STORE_PROP; + elem->props[index].store = store_prop; } } @@ -710,7 +704,7 @@ int PlyFile::get_property( const std::string &elem_name , const PlyProperty *pro prop_ptr->count_offset = prop->count_offset; /* specify that the user wants this property */ - elem->props[index].store = STORE_PROP; + elem->props[index].store = store_prop; return 1; } @@ -853,7 +847,7 @@ bool PlyFile::set_other_properties( const std::string &elem_name , int offset , for( int i=0 ; iprops.size() ; i++ ) if( !elem->props[i].store ) other.props.push_back( elem->props[i].prop ); /* set other_offset pointer appropriately if there are NO other properties */ - if( !other.props.size() ) elem->other_offset = NO_OTHER_PROPS; + if( !other.props.size() ) elem->other_offset = no_other_props; return true; } @@ -1043,7 +1037,7 @@ void PlyFile::_ascii_get_element( void *elem_ptr ) elem = which_elem; /* do we need to setup for other_props? */ - if( elem->other_offset!=NO_OTHER_PROPS ) + if( elem->other_offset!=no_other_props ) { char **ptr; other_flag = 1; @@ -1150,7 +1144,7 @@ void PlyFile::_binary_get_element( void *elem_ptr ) elem = which_elem; /* do we need to setup for other_props? */ - if( elem->other_offset!=NO_OTHER_PROPS ) + if( elem->other_offset!=no_other_props ) { char **ptr; other_flag = 1; @@ -1323,9 +1317,9 @@ returns a list of words from the line, or NULL if end-of-file std::vector< std::string > get_words( FILE *fp , char **orig_line ) { -#define BIG_STRING 4096 - static char str[BIG_STRING]; - static char str_copy[BIG_STRING]; + static const unsigned int BigString = 4096; + static char str[BigString]; + static char str_copy[BigString]; std::vector< std::string > words; int max_words = 10; int num_words = 0; @@ -1333,7 +1327,7 @@ std::vector< std::string > get_words( FILE *fp , char **orig_line ) char *result; /* read in a line */ - result = fgets( str , BIG_STRING , fp ); + result = fgets( str , BigString , fp ); if( result==NULL ) { *orig_line = NULL; @@ -1343,8 +1337,8 @@ std::vector< std::string > get_words( FILE *fp , char **orig_line ) /* (this guarentees that there will be a space before the */ /* null character at the end of the string) */ - str[BIG_STRING-2] = ' '; - str[BIG_STRING-1] = '\0'; + str[BigString-2] = ' '; + str[BigString-1] = '\0'; for( ptr=str , ptr2=str_copy ; *ptr!='\0' ; ptr++ , ptr2++ ) { @@ -1950,7 +1944,7 @@ void PlyFile::add_property( const std::vector< std::string > &words ) } /* add this property to the list of properties of the current element */ - elems.back().props.push_back( PlyStoredProperty( prop , DONT_STORE_PROP ) ); + elems.back().props.push_back( PlyStoredProperty( prop , dont_store_prop ) ); } diff --git a/Src/PointExtent.h b/Src/PointExtent.h index be8a036a..1522c01f 100644 --- a/Src/PointExtent.h +++ b/Src/PointExtent.h @@ -32,49 +32,52 @@ DAMAGE. #include #include "Geometry.h" -namespace PointExtent +namespace PoissonRecon { - template< typename Real , unsigned int Dim , bool ExtendedAxes > - struct Frame + namespace PointExtent { - static const unsigned int DirectionN = ExtendedAxes ? ( Dim==2 ? 4 : 9 ) : Dim; - Point< Real , Dim > directions[ DirectionN ]; - unsigned int frames[DirectionN][Dim]; - Frame( void ); - }; - - template< typename Real , unsigned int Dim , bool ExtendedAxes=true > - struct Extent - { - static const unsigned int DirectionN = Frame< Real , Dim , ExtendedAxes >::DirectionN; - static Point< Real , Dim > Direction( unsigned int d ){ return _Frame.directions[d]; } - static const unsigned int *Frame( unsigned int d ){ return _Frame.frames[d]; } - - std::pair< Real , Real > extents[ DirectionN ]; - std::pair< Real , Real > &operator[]( unsigned int d ){ return extents[d]; } - const std::pair< Real , Real > &operator[]( unsigned int d ) const { return extents[d]; } - - Extent( void ); - void add( Point< Real , Dim > p ); - Extent operator + ( const Extent &e ) const; - protected: - static const PointExtent::Frame< Real , Dim , ExtendedAxes > _Frame; - - template< typename _Real , unsigned int _Dim , bool _ExtendedAxes > - friend std::ostream &operator << ( std::ostream & , const Extent< _Real , _Dim , _ExtendedAxes > & ); - }; - - template< typename Real , unsigned int Dim , bool ExtendedAxes > - const Frame< Real , Dim , ExtendedAxes > Extent< Real , Dim , ExtendedAxes >::_Frame; - - template< class Real , unsigned int Dim > - XForm< Real , Dim+1 > GetBoundingBoxXForm( Point< Real , Dim > min , Point< Real , Dim > max , Real scaleFactor , bool rotate=true ); - - template< class Real , unsigned int Dim , bool ExtendedAxes > - XForm< Real , Dim+1 > GetBoundingBoxXForm( const Extent< Real , Dim , ExtendedAxes > &extent , Real scaleFactor , unsigned int dir ); + template< typename Real , unsigned int Dim , bool ExtendedAxes > + struct Frame + { + static const unsigned int DirectionN = ExtendedAxes ? ( Dim==2 ? 4 : 9 ) : Dim; + Point< Real , Dim > directions[ DirectionN ]; + unsigned int frames[DirectionN][Dim]; + Frame( void ); + }; + + template< typename Real , unsigned int Dim , bool ExtendedAxes=true > + struct Extent + { + static const unsigned int DirectionN = Frame< Real , Dim , ExtendedAxes >::DirectionN; + static Point< Real , Dim > Direction( unsigned int d ){ return _Frame.directions[d]; } + static const unsigned int *Frame( unsigned int d ){ return _Frame.frames[d]; } + + std::pair< Real , Real > extents[ DirectionN ]; + std::pair< Real , Real > &operator[]( unsigned int d ){ return extents[d]; } + const std::pair< Real , Real > &operator[]( unsigned int d ) const { return extents[d]; } + + Extent( void ); + void add( Point< Real , Dim > p ); + Extent operator + ( const Extent &e ) const; + protected: + static const PointExtent::Frame< Real , Dim , ExtendedAxes > _Frame; + + template< typename _Real , unsigned int _Dim , bool _ExtendedAxes > + friend std::ostream &operator << ( std::ostream & , const Extent< _Real , _Dim , _ExtendedAxes > & ); + }; + + template< typename Real , unsigned int Dim , bool ExtendedAxes > + const Frame< Real , Dim , ExtendedAxes > Extent< Real , Dim , ExtendedAxes >::_Frame; + + template< class Real , unsigned int Dim > + XForm< Real , Dim+1 > GetBoundingBoxXForm( Point< Real , Dim > min , Point< Real , Dim > max , Real scaleFactor , bool rotate=true ); + + template< class Real , unsigned int Dim , bool ExtendedAxes > + XForm< Real , Dim+1 > GetBoundingBoxXForm( const Extent< Real , Dim , ExtendedAxes > &extent , Real scaleFactor , unsigned int dir ); #include "PointExtent.inl" + } } #endif // POINT_EXTENT_INCLUDED \ No newline at end of file diff --git a/Src/PointInterpolant.cpp b/Src/PointInterpolant.cpp index f696979c..25d668a6 100644 --- a/Src/PointInterpolant.cpp +++ b/Src/PointInterpolant.cpp @@ -48,8 +48,11 @@ DAMAGE. #include "Image.h" #include "RegularGrid.h" #include "DataStream.imp.h" +#include "Reconstructors.h" -cmdLineParameter< char* > +using namespace PoissonRecon; + +CmdLineParameter< char* > InValues( "inValues" ) , InGradients( "inGradients" ) , Out( "out" ) , @@ -58,7 +61,7 @@ cmdLineParameter< char* > Tree( "tree" ) , Transform( "xForm" ); -cmdLineReadable +CmdLineReadable Performance( "performance" ) , ShowResidual( "showResidual" ) , PrimalGrid( "primalGrid" ) , @@ -70,7 +73,7 @@ cmdLineReadable ASCII( "ascii" ) , Verbose( "verbose" ); -cmdLineParameter< int > +CmdLineParameter< int > #ifndef FAST_COMPILE Degree( "degree" , DEFAULT_FEM_DEGREE ) , #endif // !FAST_COMPILE @@ -94,7 +97,7 @@ cmdLineParameter< int > ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , Threads( "threads" , (int)std::thread::hardware_concurrency() ); -cmdLineParameter< float > +CmdLineParameter< float > Scale( "scale" , 1.1f ) , Width( "width" , 0.f ) , CGSolverAccuracy( "cgAccuracy" , 1e-3f ) , @@ -104,7 +107,7 @@ cmdLineParameter< float > LapWeight ( "lapWeight" , 0.f ) , BiLapWeight ( "biLapWeight" , 1.f ); -cmdLineReadable* params[] = +CmdLineReadable* params[] = { #ifndef FAST_COMPILE &Degree , &BType , &Dimension , @@ -956,7 +959,7 @@ int main( int argc , char* argv[] ) WARN( "Array debugging enabled" ); #endif // ARRAY_DEBUG - cmdLineParse( argc-1 , &argv[1] , params ); + CmdLineParse( argc-1 , &argv[1] , params ); if( MaxMemoryGB.value>0 ) SetPeakMemoryMB( MaxMemoryGB.value<<10 ); ThreadPool::DefaultChunkSize = ThreadChunkSize.value; diff --git a/Src/PointPartition.h b/Src/PointPartition.h index e0fe8c5f..43c75ba1 100644 --- a/Src/PointPartition.h +++ b/Src/PointPartition.h @@ -38,109 +38,111 @@ DAMAGE. #include "DataStream.h" #include "PointExtent.h" -#define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth -#define BUFFER_IO (1<<14) // Buffer the points before reading/writing +namespace PoissonRecon +{ + static const unsigned int BUFFER_IO = 1<<14; // Buffer the points before reading/writing -namespace PointPartition -{ - template< typename Real , unsigned int Dim > - struct PointSetInfo + namespace PointPartition { - std::string header; - unsigned filesPerDir; - XForm< Real , Dim+1 > modelToUnitCube; - std::vector< size_t > pointsPerSlab; - std::vector< PlyProperty > auxiliaryProperties; + template< typename Real , unsigned int Dim > + struct PointSetInfo + { + std::string header; + unsigned filesPerDir; + XForm< Real , Dim+1 > modelToUnitCube; + std::vector< size_t > pointsPerSlab; + std::vector< PlyProperty > auxiliaryProperties; - PointSetInfo( void ); - PointSetInfo( unsigned int slabs ); - PointSetInfo( BinaryStream &stream ); + PointSetInfo( void ); + PointSetInfo( unsigned int slabs ); + PointSetInfo( BinaryStream &stream ); - void write( BinaryStream &stream ) const; - }; + void write( BinaryStream &stream ) const; + }; - struct Partition - { - Partition( void ); - Partition( unsigned int dCount , const std::vector< size_t > &slabSizes ); + struct Partition + { + Partition( void ); + Partition( unsigned int dCount , const std::vector< size_t > &slabSizes ); #ifdef ADAPTIVE_PADDING - void optimize( bool useMax ); - std::pair< unsigned int , unsigned int > range( unsigned int i ) const; - size_t size( unsigned int i ) const; - void printDistribution( void ) const; - double l2Energy( void ) const; - double maxEnergy( void ) const; + void optimize( bool useMax ); + std::pair< unsigned int , unsigned int > range( unsigned int i ) const; + size_t size( unsigned int i ) const; + void printDistribution( void ) const; + double l2Energy( void ) const; + double maxEnergy( void ) const; #else // !ADAPTIVE_PADDING - void optimize( bool useMax , unsigned int padSize ); - std::pair< unsigned int , unsigned int > range( unsigned int i , unsigned int padSize ) const; - size_t size( unsigned int i , unsigned int padSize ) const; - void printDistribution( unsigned int padSize ) const; - double l2Energy( unsigned int padSize ) const; - double maxEnergy( unsigned int padSize ) const; + void optimize( bool useMax , unsigned int padSize ); + std::pair< unsigned int , unsigned int > range( unsigned int i , unsigned int padSize ) const; + size_t size( unsigned int i , unsigned int padSize ) const; + void printDistribution( unsigned int padSize ) const; + double l2Energy( unsigned int padSize ) const; + double maxEnergy( unsigned int padSize ) const; #endif // ADAPTIVE_PADDING - size_t size( void ) const; - unsigned int partitions( void ) const; - unsigned int slabs( void ) const; - - protected: - std::vector< unsigned int > _starts; - std::vector< size_t > _slabSizes; - }; - - long ReadPLYProperties( FILE *fp , std::vector< PlyProperty > &properties ); - long ReadPLYProperties( const char *fileName , std::vector< PlyProperty > &properties ); - long WritePLYProperties( FILE *fp , const std::vector< PlyProperty > &properties ); - long WritePLYProperties( const char *fileName , const std::vector< PlyProperty > &properties ); - - template< typename InputFactory > - struct BufferedBinaryInputDataStream : public InputDataStream< typename InputFactory::VertexType > - { - - typedef typename InputFactory::VertexType Data; - BufferedBinaryInputDataStream( const char *fileName , const InputFactory &factory , size_t bufferSize ); - ~BufferedBinaryInputDataStream( void ); - void reset( void ); - bool base_read( Data &d ); - protected: - size_t _bufferSize , _current , _inBuffer , _elementSize; - Pointer( char ) _buffer; - FILE *_fp; - const InputFactory &_factory; - long _inset; - }; - - template< typename OutputFactory > - struct BufferedBinaryOutputDataStream : public OutputDataStream< typename OutputFactory::VertexType > - { - typedef typename OutputFactory::VertexType Data; - BufferedBinaryOutputDataStream( const char *fileName , const OutputFactory &factory , size_t bufferSize ); - ~BufferedBinaryOutputDataStream( void ); - void reset( void ); - void base_write( const Data &d ); - protected: - size_t _bufferSize , _current , _elementSize; - Pointer( char ) _buffer; - FILE *_fp; - const OutputFactory &_factory; - long _inset; - }; - - void RemovePointSlabDirs( std::string dir ); - static void CreatePointSlabDirs( std::string dir , unsigned int count , unsigned int filesPerDir ); - - std::string FileDir( std::string dir , std::string header ); - std::string FileDir( std::string dir , std::string header , unsigned int clientIndex ); - - std::string FileName( std::string dir , unsigned int slab , unsigned int slabs , unsigned int filesPerDir ); - std::string FileName( std::string dir , std::string header , unsigned int slab , unsigned int slabs , unsigned int filesPerDir ); - std::string FileName( std::string dir , std::string header , unsigned int clientIndex , unsigned int slab , unsigned int slabs , unsigned int filesPerDir ); - - std::string PointSetInfoName( std::string dir , std::string header ); + size_t size( void ) const; + unsigned int partitions( void ) const; + unsigned int slabs( void ) const; + + protected: + std::vector< unsigned int > _starts; + std::vector< size_t > _slabSizes; + }; + + long ReadPLYProperties( FILE *fp , std::vector< PlyProperty > &properties ); + long ReadPLYProperties( const char *fileName , std::vector< PlyProperty > &properties ); + long WritePLYProperties( FILE *fp , const std::vector< PlyProperty > &properties ); + long WritePLYProperties( const char *fileName , const std::vector< PlyProperty > &properties ); + + template< typename InputFactory > + struct BufferedBinaryInputDataStream : public InputDataStream< typename InputFactory::VertexType > + { + + typedef typename InputFactory::VertexType Data; + BufferedBinaryInputDataStream( const char *fileName , const InputFactory &factory , size_t bufferSize ); + ~BufferedBinaryInputDataStream( void ); + void reset( void ); + bool base_read( Data &d ); + protected: + size_t _bufferSize , _current , _inBuffer , _elementSize; + Pointer( char ) _buffer; + FILE *_fp; + const InputFactory &_factory; + long _inset; + }; + + template< typename OutputFactory > + struct BufferedBinaryOutputDataStream : public OutputDataStream< typename OutputFactory::VertexType > + { + typedef typename OutputFactory::VertexType Data; + BufferedBinaryOutputDataStream( const char *fileName , const OutputFactory &factory , size_t bufferSize ); + ~BufferedBinaryOutputDataStream( void ); + void reset( void ); + void base_write( const Data &d ); + protected: + size_t _bufferSize , _current , _elementSize; + Pointer( char ) _buffer; + FILE *_fp; + const OutputFactory &_factory; + long _inset; + }; + + void RemovePointSlabDirs( std::string dir ); + static void CreatePointSlabDirs( std::string dir , unsigned int count , unsigned int filesPerDir ); + + std::string FileDir( std::string dir , std::string header ); + std::string FileDir( std::string dir , std::string header , unsigned int clientIndex ); + + std::string FileName( std::string dir , unsigned int slab , unsigned int slabs , unsigned int filesPerDir ); + std::string FileName( std::string dir , std::string header , unsigned int slab , unsigned int slabs , unsigned int filesPerDir ); + std::string FileName( std::string dir , std::string header , unsigned int clientIndex , unsigned int slab , unsigned int slabs , unsigned int filesPerDir ); + + std::string PointSetInfoName( std::string dir , std::string header ); #include "PointPartition.inl" + } } #endif // POINT_PARTITION_INCLUDED \ No newline at end of file diff --git a/Src/PointPartitionClientServer.h b/Src/PointPartitionClientServer.h index 3dd84a3d..708d5024 100644 --- a/Src/PointPartitionClientServer.h +++ b/Src/PointPartitionClientServer.h @@ -38,36 +38,39 @@ DAMAGE. #include "Reconstructors.h" #include "PointExtent.h" - -namespace PointPartitionClientServer +namespace PoissonRecon { - template< typename Real > - struct ClientPartitionInfo + namespace PointPartitionClientServer { - std::string in , tempDir , outDir , outHeader; - unsigned int slabs , filesPerDir , bufferSize , clientCount , sliceDir; - Real scale; - bool verbose; + template< typename Real > + struct ClientPartitionInfo + { + std::string in , tempDir , outDir , outHeader; + unsigned int slabs , filesPerDir , bufferSize , clientCount , sliceDir; + Real scale; + bool verbose; - ClientPartitionInfo( void ); - ClientPartitionInfo( BinaryStream &stream ); + ClientPartitionInfo( void ); + ClientPartitionInfo( BinaryStream &stream ); - void write( BinaryStream &stream ) const; - }; + void write( BinaryStream &stream ) const; + }; - template< typename Real , unsigned int Dim > - std::pair< PointPartition::PointSetInfo< Real , Dim > , PointPartition::Partition > RunServer - ( - std::vector< Socket > &clientSockets , - ClientPartitionInfo< Real > clientPartitionInfo , - bool loadBalance - ); + template< typename Real , unsigned int Dim > + std::pair< PointPartition::PointSetInfo< Real , Dim > , PointPartition::Partition > RunServer + ( + std::vector< Socket > &clientSockets , + ClientPartitionInfo< Real > clientPartitionInfo , + bool loadBalance + ); - template< typename Real , unsigned int Dim > - void RunClients( std::vector< Socket > &serverSockets ); + template< typename Real , unsigned int Dim > + void RunClients( std::vector< Socket > &serverSockets ); #include "PointPartitionClientServer.inl" + } } + #endif // POINT_PARTITION_CLIENT_SERVER_INCLUDED \ No newline at end of file diff --git a/Src/PointsToDisks.cpp b/Src/PointsToDisks.cpp index 55e919b5..463cdb5b 100644 --- a/Src/PointsToDisks.cpp +++ b/Src/PointsToDisks.cpp @@ -42,26 +42,27 @@ DAMAGE. #include "MyMiscellany.h" #include "DataStream.imp.h" +using namespace PoissonRecon; -cmdLineParameter< std::string > +CmdLineParameter< std::string > In( "in" ) , Out( "out" ); -cmdLineParameter< unsigned int > +CmdLineParameter< unsigned int > Res( "res" , 12 ) , PointsToKeep( "keep" ); -cmdLineParameter< float > +CmdLineParameter< float > Scale( "scale" , 0.005f ) , Fraction( "fraction" , 1.f ); -cmdLineReadable +CmdLineReadable Verbose( "verbose" ); -cmdLineParameter< float > +CmdLineParameter< float > LengthToRadiusExponent( "lExp" , 0.66f ); -cmdLineReadable* params[] = +CmdLineReadable* params[] = { &In , &Out , @@ -106,7 +107,7 @@ int main( int argc , char* argv[] ) return color; }; - cmdLineParse( argc-1 , &argv[1] , params ); + CmdLineParse( argc-1 , &argv[1] , params ); if( !In.set || !Out.set ) { ShowUsage( argv [0] ); @@ -186,7 +187,7 @@ int main( int argc , char* argv[] ) if( PointsToKeep.set && PointsToKeep.value>vertices.size() ) { WARN( "--" , PointsToKeep.name , " value exceeds number of points: " , PointsToKeep.value , " > " , vertices.size() ); - PointsToKeep.value = vertices.size(); + PointsToKeep.value = (unsigned int)vertices.size(); } if( !hasNormals ) ERROR_OUT( "Input is not oriented" ); diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index 262bb281..496357d2 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -45,7 +45,9 @@ DAMAGE. #define DEFAULT_DIMENSION 3 -cmdLineParameter< char* > +using namespace PoissonRecon; + +CmdLineParameter< char* > In( "in" ) , Out( "out" ) , TempDir( "tempDir" ) , @@ -54,7 +56,7 @@ cmdLineParameter< char* > Envelope( "envelope" ) , Transform( "xForm" ); -cmdLineReadable +CmdLineReadable Performance( "performance" ) , ShowResidual( "showResidual" ) , PolygonMesh( "polygonMesh" ) , @@ -70,7 +72,7 @@ cmdLineReadable Gradients( "gradients" ) , Verbose( "verbose" ); -cmdLineParameter< int > +CmdLineParameter< int > #ifndef FAST_COMPILE Degree( "degree" , Reconstructor::Poisson::DefaultFEMDegree ) , #endif // !FAST_COMPILE @@ -96,7 +98,7 @@ cmdLineParameter< int > ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , Threads( "threads" , (int)std::thread::hardware_concurrency() ); -cmdLineParameter< float > +CmdLineParameter< float > DataX( "data" , 32.f ) , SamplesPerNode( "samplesPerNode" , 1.5f ) , Scale( "scale" , 1.1f ) , @@ -108,7 +110,7 @@ cmdLineParameter< float > TargetValue( "targetValue" , 0.5f ) , PointWeight( "pointWeight" ); -cmdLineReadable* params[] = +CmdLineReadable* params[] = { #ifndef FAST_COMPILE &Degree , &BType , @@ -606,7 +608,7 @@ int main( int argc , char* argv[] ) #ifdef ARRAY_DEBUG WARN( "Array debugging enabled" ); #endif // ARRAY_DEBUG - cmdLineParse( argc-1 , &argv[1] , params ); + CmdLineParse( argc-1 , &argv[1] , params ); if( MaxMemoryGB.value>0 ) SetPeakMemoryMB( MaxMemoryGB.value<<10 ); ThreadPool::DefaultChunkSize = ThreadChunkSize.value; ThreadPool::DefaultSchedule = (ThreadPool::ScheduleType)ScheduleType.value; diff --git a/Src/PoissonRecon.server.inl b/Src/PoissonRecon.server.inl index 41abe0ca..2dca601e 100644 --- a/Src/PoissonRecon.server.inl +++ b/Src/PoissonRecon.server.inl @@ -26,8 +26,6 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ -#include "DataStream.imp.h" - template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > struct Server { diff --git a/Src/PoissonReconClient.cpp b/Src/PoissonReconClient.cpp index b10a1dc6..115a8015 100644 --- a/Src/PoissonReconClient.cpp +++ b/Src/PoissonReconClient.cpp @@ -43,10 +43,12 @@ DAMAGE. #define DEFAULT_DIMENSION 3 -cmdLineParameter< std::string > +using namespace PoissonRecon; + +CmdLineParameter< std::string > Address( "address" , "127.0.0.1" ); -cmdLineParameter< int > +CmdLineParameter< int > MaxMemoryGB( "maxMemory" , 0 ) , #ifdef _OPENMP ParallelType( "parallel" , (int)ThreadPool::OPEN_MP ) , @@ -60,11 +62,11 @@ cmdLineParameter< int > Port( "port" , 0 ) , PeakMemorySampleMS( "sampleMS" , 10 ); -cmdLineReadable +CmdLineReadable Pause( "pause" ); -cmdLineReadable* params[] = +CmdLineReadable* params[] = { &Port , &MultiClient , &Address , &MaxMemoryGB , &ParallelType , &ScheduleType , &ThreadChunkSize , &Threads , @@ -167,7 +169,7 @@ int main( int argc , char* argv[] ) static const unsigned int Dim = DEFAULT_DIMENSION; Timer timer; - cmdLineParse( argc-1 , &argv[1] , params ); + CmdLineParse( argc-1 , &argv[1] , params ); if( !Port.set ) { diff --git a/Src/PoissonReconClientServer.h b/Src/PoissonReconClientServer.h index 4100d3cb..d16fdcb9 100644 --- a/Src/PoissonReconClientServer.h +++ b/Src/PoissonReconClientServer.h @@ -39,59 +39,63 @@ DAMAGE. #include "VertexFactory.h" #include "Socket.h" #include "Reconstructors.h" +#include "DataStream.imp.h" -namespace PoissonReconClientServer +namespace PoissonRecon { - template< typename Real , unsigned int Dim > - struct ClientReconstructionInfo + namespace PoissonReconClientServer { - enum ShareType + template< typename Real , unsigned int Dim > + struct ClientReconstructionInfo { - BACK , - CENTER , - FRONT - }; - enum MergeType - { - TOPOLOGY_AND_FUNCTION , // Identical topology across slice - FUNCTION , // Identical function across slice - NONE + enum ShareType + { + BACK , + CENTER , + FRONT + }; + enum MergeType + { + TOPOLOGY_AND_FUNCTION , // Identical topology across slice + FUNCTION , // Identical function across slice + NONE + }; + + std::string header , inDir , tempDir , outDir; + unsigned int solveDepth , reconstructionDepth , sharedDepth , distributionDepth , baseDepth , kernelDepth , iters , bufferSize , filesPerDir , padSize , verbose; + Real pointWeight , confidence , confidenceBias , samplesPerNode , dataX , cgSolverAccuracy , targetValue; + MergeType mergeType; + bool density , linearFit , ouputVoxelGrid , outputSolution; + std::vector< PlyProperty > auxProperties; + + ClientReconstructionInfo( void ); + ClientReconstructionInfo( BinaryStream &stream ); + + void write( BinaryStream &stream ) const; + + std::string sharedFile( unsigned int idx , ShareType shareType=CENTER ) const; }; - std::string header , inDir , tempDir , outDir; - unsigned int solveDepth , reconstructionDepth , sharedDepth , distributionDepth , baseDepth , kernelDepth , iters , bufferSize , filesPerDir , padSize , verbose; - Real pointWeight , confidence , confidenceBias , samplesPerNode , dataX , cgSolverAccuracy , targetValue; - MergeType mergeType; - bool density , linearFit , ouputVoxelGrid , outputSolution; - std::vector< PlyProperty > auxProperties; - - ClientReconstructionInfo( void ); - ClientReconstructionInfo( BinaryStream &stream ); - - void write( BinaryStream &stream ) const; - - std::string sharedFile( unsigned int idx , ShareType shareType=CENTER ) const; - }; - - template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > - std::vector< unsigned int > RunServer - ( - PointPartition::PointSetInfo< Real , Dim > pointSetInfo , - PointPartition::Partition pointPartition , - std::vector< Socket > clientSockets , - ClientReconstructionInfo< Real , Dim > clientReconInfo , - unsigned int baseVCycles , - unsigned int sampleMS , - bool showDiscontinuity=false , - bool outputBoundarySlices=false - ); - - template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > - void RunClient( std::vector< Socket > &serverSockets , unsigned int sampleMS ); + template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > + std::vector< unsigned int > RunServer + ( + PointPartition::PointSetInfo< Real , Dim > pointSetInfo , + PointPartition::Partition pointPartition , + std::vector< Socket > clientSockets , + ClientReconstructionInfo< Real , Dim > clientReconInfo , + unsigned int baseVCycles , + unsigned int sampleMS , + bool showDiscontinuity=false , + bool outputBoundarySlices=false + ); + + template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > + void RunClient( std::vector< Socket > &serverSockets , unsigned int sampleMS ); #include "PoissonReconClientServer.inl" #include "PoissonRecon.server.inl" #include "PoissonRecon.client.inl" + } } #endif // POISSON_RECON_CLIENT_SERVER_INCLUDED \ No newline at end of file diff --git a/Src/PoissonReconServer.cpp b/Src/PoissonReconServer.cpp index 4d3d9e3d..f4f569aa 100644 --- a/Src/PoissonReconServer.cpp +++ b/Src/PoissonReconServer.cpp @@ -43,6 +43,8 @@ DAMAGE. #define DEFAULT_DIMENSION 3 +using namespace PoissonRecon; + enum MergeSlabType { NONE , @@ -54,13 +56,13 @@ enum MergeSlabType const std::string MergeSlabNames[] = { "none" , "function" , "topology" , "seamless" }; -cmdLineParameter< std::string > +CmdLineParameter< std::string > AddressPrefix( "prefix" ) , In( "in" ) , TempDir( "tempDir" ) , Out( "out" ); -cmdLineParameter< int > +CmdLineParameter< int > ClientCount( "count" ) , Port( "port" , 0 ) , Verbose( "verbose" , 0 ) , @@ -92,7 +94,7 @@ cmdLineParameter< int > AlignmentDir( "alignDir" , -1 ) , Threads( "threads" , (int)std::thread::hardware_concurrency() ) ; -cmdLineReadable +CmdLineReadable Performance( "performance" ) , NoLoadBalance( "noLoadBalance" ) , Density( "density" ) , @@ -103,7 +105,7 @@ cmdLineReadable OutputSolution( "solution" ) , ShowDiscontinuity( "showDiscontinuity" ); -cmdLineParameter< float > +CmdLineParameter< float > Scale( "scale" , 1.1f ) , Width( "width" , 0.f ) , Confidence( "confidence" , 0.f ) , @@ -114,7 +116,7 @@ cmdLineParameter< float > TargetValue( "targetValue" , 0.5f ) , CGSolverAccuracy( "cgAccuracy" , 1e-3f ); -cmdLineReadable* params[] = +CmdLineReadable* params[] = { &Port , &ClientCount , &AddressPrefix , &Performance , &Verbose , &In , @@ -383,7 +385,7 @@ int main( int argc , char* argv[] ) #endif // USE_DOUBLE static const unsigned int Dim = DEFAULT_DIMENSION; - cmdLineParse( argc-1 , &argv[1] , params ); + CmdLineParse( argc-1 , &argv[1] , params ); if( !In.set || !TempDir.set || !Out.set || !ClientCount.set ) { diff --git a/Src/Polynomial.h b/Src/Polynomial.h index 58fc3546..6621e440 100644 --- a/Src/Polynomial.h +++ b/Src/Polynomial.h @@ -29,73 +29,82 @@ DAMAGE. #ifndef POLYNOMIAL_INCLUDED #define POLYNOMIAL_INCLUDED -template< int Degree > -class Polynomial +#include +#include +#include +#include "Factor.h" + +namespace PoissonRecon { -public: - double coefficients[Degree+1]; - - Polynomial( void ); - template< int Degree2 > Polynomial( const Polynomial< Degree2 >& 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; - - template< int _Degree=Degree > - typename std::enable_if< (_Degree==0) , Polynomial< Degree > >::type derivative( void ) const { return Polynomial< Degree >(); } - template< int _Degree=Degree > - typename std::enable_if< (_Degree> 0) , Polynomial< Degree-1 > >::type derivative( void ) const + + template< int Degree > + class Polynomial { - Polynomial< Degree-1 > p; - for( int i=0 ; i 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); - - 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] ); -}; + public: + double coefficients[Degree+1]; + + Polynomial( void ); + template< int Degree2 > Polynomial( const Polynomial< Degree2 >& 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; + + template< int _Degree=Degree > + typename std::enable_if< (_Degree==0) , Polynomial< Degree > >::type derivative( void ) const { return Polynomial< Degree >(); } + template< int _Degree=Degree > + typename std::enable_if< (_Degree> 0) , Polynomial< Degree-1 > >::type derivative( void ) const + { + Polynomial< Degree-1 > p; + for( int i=0 ; i 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); + + 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/Polynomial.inl b/Src/Polynomial.inl index ebd8d3ee..88940038 100644 --- a/Src/Polynomial.inl +++ b/Src/Polynomial.inl @@ -26,11 +26,6 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ -#include -#include -#include -#include "Factor.h" - //////////////// // Polynomial // //////////////// diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 90458de0..07362197 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -45,7 +45,9 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "17.00" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "18.00" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation +#define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth + #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file diff --git a/Src/Rasterizer.h b/Src/Rasterizer.h index dd03baca..046f7816 100644 --- a/Src/Rasterizer.h +++ b/Src/Rasterizer.h @@ -35,97 +35,101 @@ DAMAGE. #include "RegularGrid.h" #include "MyMiscellany.h" -template< typename Real , unsigned int Dim > -struct Rasterizer +namespace PoissonRecon { - struct ThreadSafety + + template< typename Real , unsigned int Dim > + struct Rasterizer { - enum Type + struct ThreadSafety { - MUTEXES , - MAP_REDUCE , - SINGLE_THREADED + enum Type + { + MUTEXES , + MAP_REDUCE , + SINGLE_THREADED + }; + Type type; + unsigned int lockDepth; + ThreadSafety( Type t=MUTEXES , unsigned int ld=0 ) : type(t) , lockDepth(ld) { } }; - Type type; - unsigned int lockDepth; - ThreadSafety( Type t=MUTEXES , unsigned int ld=0 ) : type(t) , lockDepth(ld) { } - }; - template< typename IndexType , unsigned int K > using SimplexRasterizationGrid = RegularGrid< std::vector< std::pair< IndexType , Simplex< Real , Dim , K > > > , Dim >; - - // This templated function rasterizes simplices. - // It is assumed that the simplices are scaled to be contained in the cube [0,1]^3. - // Template parameters: - // IndexType: specifies the storage for vertex/simplex indices - // Input: - // vertices: the vertices of the mesh - // simplices: the connectivity of the mesh - // depth: the depth of the voxel grid, generating a grid of size (2^depth) x (2^depth) x (2^depth) - // lockDepth: the depth of the voxel grid storing the locks - // Output: - // A RegularGrid object where each cell stores the list of pairs containing the index into the original simplex list and the (clipped) simplex - template< typename IndexType , unsigned int K > - static SimplexRasterizationGrid< IndexType , K > Rasterize( const SimplicialComplex< Real , Dim , K > &simplicialComplex , unsigned int depth , ThreadSafety threadSafety ); - -protected: - struct _RegularGridIndex - { - unsigned int depth , index[Dim]; - _RegularGridIndex( void ); - _RegularGridIndex( unsigned int d , Point< Real , Dim > p ); - template< unsigned int K > _RegularGridIndex( unsigned int maxDepth , Simplex< Real , Dim , K > simplex ); + template< typename IndexType , unsigned int K > using SimplexRasterizationGrid = RegularGrid< std::vector< std::pair< IndexType , Simplex< Real , Dim , K > > > , Dim >; + + // This templated function rasterizes simplices. + // It is assumed that the simplices are scaled to be contained in the cube [0,1]^3. + // Template parameters: + // IndexType: specifies the storage for vertex/simplex indices + // Input: + // vertices: the vertices of the mesh + // simplices: the connectivity of the mesh + // depth: the depth of the voxel grid, generating a grid of size (2^depth) x (2^depth) x (2^depth) + // lockDepth: the depth of the voxel grid storing the locks + // Output: + // A RegularGrid object where each cell stores the list of pairs containing the index into the original simplex list and the (clipped) simplex + template< typename IndexType , unsigned int K > + static SimplexRasterizationGrid< IndexType , K > Rasterize( const SimplicialComplex< Real , Dim , K > &simplicialComplex , unsigned int depth , ThreadSafety threadSafety ); + + protected: + struct _RegularGridIndex + { + unsigned int depth , index[Dim]; + _RegularGridIndex( void ); + _RegularGridIndex( unsigned int d , Point< Real , Dim > p ); + template< unsigned int K > _RegularGridIndex( unsigned int maxDepth , Simplex< Real , Dim , K > simplex ); - bool operator != ( const _RegularGridIndex &idx ) const; - bool operator == ( const _RegularGridIndex &idx ) const { return !( (*this)!=idx ); } + bool operator != ( const _RegularGridIndex &idx ) const; + bool operator == ( const _RegularGridIndex &idx ) const { return !( (*this)!=idx ); } - _RegularGridIndex child( unsigned int c ) const; - }; + _RegularGridIndex child( unsigned int c ) const; + }; - struct _RegularGridMutexes - { - _RegularGridMutexes( unsigned int lockDepth , unsigned int maxDepth ) + struct _RegularGridMutexes { - if( lockDepth>maxDepth ) + _RegularGridMutexes( unsigned int lockDepth , unsigned int maxDepth ) { - WARN( "Lock depth exceeds max depth: " , lockDepth , " > " , maxDepth ); - lockDepth = maxDepth; + if( lockDepth>maxDepth ) + { + WARN( "Lock depth exceeds max depth: " , lockDepth , " > " , maxDepth ); + lockDepth = maxDepth; + } + _bitShift = maxDepth - lockDepth; + unsigned int _res = 1<> _bitShift; - return _metexes( _idx ); - } - std::mutex &operator() ( unsigned int idx[Dim] ) - { - unsigned int _idx[Dim]; - for( int d=0 ; d> _bitShift; - return _mutexes( _idx ); - } - template< typename ... UnsignedInts > - std::mutex &operator()( UnsignedInts ... idx ) - { - unsigned int _idx[] = { idx ... }; - for( int d=0 ; d> _bitShift; - return _mutexes( _idx ); - } - protected: - RegularGrid< std::mutex , Dim > _mutexes; - size_t _bitShift; - }; + std::mutex &operator() ( const unsigned int idx[Dim] ) + { + unsigned int _idx[Dim]; + for( int d=0 ; d> _bitShift; + return _metexes( _idx ); + } + std::mutex &operator() ( unsigned int idx[Dim] ) + { + unsigned int _idx[Dim]; + for( int d=0 ; d> _bitShift; + return _mutexes( _idx ); + } + template< typename ... UnsignedInts > + std::mutex &operator()( UnsignedInts ... idx ) + { + unsigned int _idx[] = { idx ... }; + for( int d=0 ; d> _bitShift; + return _mutexes( _idx ); + } - template< typename IndexType , unsigned int K > - static size_t _Rasterize( _RegularGridMutexes &mutexes , SimplexRasterizationGrid< IndexType , K > &raster , IndexType simplexIndex , Simplex< Real , Dim , K > simplex , unsigned int depth , _RegularGridIndex idx ); + protected: + RegularGrid< std::mutex , Dim > _mutexes; + size_t _bitShift; + }; + + template< typename IndexType , unsigned int K > + static size_t _Rasterize( _RegularGridMutexes &mutexes , SimplexRasterizationGrid< IndexType , K > &raster , IndexType simplexIndex , Simplex< Real , Dim , K > simplex , unsigned int depth , _RegularGridIndex idx ); - template< typename IndexType , unsigned int K > - static size_t _Rasterize( SimplexRasterizationGrid< IndexType , K > &raster , IndexType simplexIndex , Simplex< Real , Dim , K > simplex , unsigned int depth , _RegularGridIndex idx ); -}; + template< typename IndexType , unsigned int K > + static size_t _Rasterize( SimplexRasterizationGrid< IndexType , K > &raster , IndexType simplexIndex , Simplex< Real , Dim , K > simplex , unsigned int depth , _RegularGridIndex idx ); + }; #include "Rasterizer.inl" +} #endif // RASTERIZER_INCLUDED \ No newline at end of file diff --git a/Src/Reconstruction.example.cpp b/Src/Reconstruction.example.cpp index 670b4137..59b49fda 100644 --- a/Src/Reconstruction.example.cpp +++ b/Src/Reconstruction.example.cpp @@ -38,11 +38,13 @@ DAMAGE. #include "MyMiscellany.h" #include "CmdLineParser.h" -cmdLineParameter< char* > Out( "out" ); -cmdLineReadable SSDReconstruction( "ssd" ) , UseColor( "color" ) , Verbose( "verbose" ); -cmdLineParameter< int > Depth( "depth" , 8 ) , SampleNum( "samples" , 100000 ); +using namespace PoissonRecon; -cmdLineReadable* params[] = { &Out , &SSDReconstruction , &UseColor , &Verbose , &Depth , &SampleNum , nullptr }; +CmdLineParameter< char* > Out( "out" ); +CmdLineReadable SSDReconstruction( "ssd" ) , UseColor( "color" ) , Verbose( "verbose" ); +CmdLineParameter< int > Depth( "depth" , 8 ) , SampleNum( "samples" , 100000 ); + +CmdLineReadable* params[] = { &Out , &SSDReconstruction , &UseColor , &Verbose , &Depth , &SampleNum , nullptr }; void ShowUsage( char* ex ) { @@ -321,7 +323,7 @@ void Execute( void ) int main( int argc , char* argv[] ) { Timer timer; - cmdLineParse( argc-1 , &argv[1] , params ); + CmdLineParse( argc-1 , &argv[1] , params ); #ifdef _OPENMP ThreadPool::Init( ThreadPool::OPEN_MP , std::thread::hardware_concurrency() ); #else // !_OPENMP diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h index f259b064..6eed21e4 100644 --- a/Src/Reconstructors.h +++ b/Src/Reconstructors.h @@ -34,1309 +34,1307 @@ DAMAGE. #include "DataStream.imp.h" #include "FEMTree.h" #include "PointExtent.h" - -namespace Reconstructor -{ - static const unsigned int DataDegree = 0; // The order of the B-Spline used to splat in data for auxiliary data interpolation - static const unsigned int WeightDegree = 2; // The order of the B-Spline used to splat in the weights for density estimation - - // For clarity, to distinguies betwen the case that a Point is referencing a position and a normal - template< typename Real , unsigned int Dim > using Position = Point< Real , Dim >; - template< typename Real , unsigned int Dim > using Normal = Point< Real , Dim >; - template< typename Real , unsigned int Dim > using Gradient = Point< Real , Dim >; - #include "Reconstructors.streams.h" - // Declare a type for storing the solution information - template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... AuxData > struct Implicit; +namespace PoissonRecon +{ - // Parameters for mesh extraction - struct LevelSetExtractionParameters + namespace Reconstructor { - bool linearFit; - bool outputGradients; - bool forceManifold; - bool polygonMesh; - bool verbose; - LevelSetExtractionParameters( void ) : linearFit(false) , outputGradients(false) , forceManifold(true) , polygonMesh(false) , verbose(false) {} - }; - - // "Private" function for extracting meshes - template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ImplicitType , unsigned int ... FEMSigs > - void _ExtractLevelSet( UIntPack< FEMSigs ... > , const ImplicitType &implicit , OutputVertexStream &vertexStream , OutputFaceStream< Dim-1 > &faceStream , typename Implicit< Real , Dim , FEMSig >::LevelSetExtractionParameters params ); - - // Specialized solution information without auxiliary data - template< typename Real , unsigned int Dim , unsigned int FEMSig > - struct Implicit< Real , Dim , FEMSig > - { - // The signature pack - typedef IsotropicUIntPack< Dim , FEMSig > Sigs; - - // The type representing the point sampling density - typedef typename FEMTree< Dim , Real >::template DensityEstimator< Reconstructor::WeightDegree > DensityEstimator; - - // The constructor - Implicit( void ) : density(NULL) , isoValue(0) , tree(MEMORY_ALLOCATOR_BLOCK_SIZE) , unitCubeToModel( XForm< Real , Dim+1 >::Identity() ){} - - // The desctructor - ~Implicit( void ){ delete density ; density = NULL; } + static const unsigned int DataDegree = 0; // The order of the B-Spline used to splat in data for auxiliary data interpolation + static const unsigned int WeightDegree = 2; // The order of the B-Spline used to splat in the weights for density estimation - // The transformation taking points in the unit cube back to world coordinates - XForm< Real , Dim+1 > unitCubeToModel; + // Declare a type for storing the solution information + template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... AuxData > struct Implicit; - // The octree adapted to the points - FEMTree< Dim , Real > tree; + // Parameters for mesh extraction + struct LevelSetExtractionParameters + { + bool linearFit; + bool outputGradients; + bool forceManifold; + bool polygonMesh; + bool verbose; + LevelSetExtractionParameters( void ) : linearFit(false) , outputGradients(false) , forceManifold(true) , polygonMesh(false) , verbose(false) {} + }; - // The solution coefficients - DenseNodeData< Real , Sigs > solution; + // "Private" function for extracting meshes + template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ImplicitType , unsigned int ... FEMSigs > + void _ExtractLevelSet( UIntPack< FEMSigs ... > , const ImplicitType &implicit , OutputVertexStream &vertexStream , OutputFaceStream< Dim-1 > &faceStream , typename Implicit< Real , Dim , FEMSig >::LevelSetExtractionParameters params ); - // The average value at the sample positions - Real isoValue; + // Specialized solution information without auxiliary data + template< typename Real , unsigned int Dim , unsigned int FEMSig > + struct Implicit< Real , Dim , FEMSig > + { + // The signature pack + typedef IsotropicUIntPack< Dim , FEMSig > Sigs; - // The density estimator computed from the samples - DensityEstimator *density; + // The type representing the point sampling density + typedef typename FEMTree< Dim , Real >::template DensityEstimator< Reconstructor::WeightDegree > DensityEstimator; - // A method that writes the extracted mesh to the streams - void extractLevelSet( OutputVertexStream< Real , Dim > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const - { - typedef unsigned char AuxData; - _ExtractLevelSet< false , Real , Dim , FEMSig , AuxData , OutputVertexStream< Real , Dim > , Implicit< Real , Dim , FEMSig > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); - } - }; + // The constructor + Implicit( void ) : density(NULL) , isoValue(0) , tree(MEMORY_ALLOCATOR_BLOCK_SIZE) , unitCubeToModel( XForm< Real , Dim+1 >::Identity() ){} - // Specialized solution information with auxiliary data - template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > - struct Implicit< Real , Dim , FEMSig , AuxData > : public Implicit< Real , Dim , FEMSig > - { - typedef IsotropicUIntPack< Dim , FEMSig > Sigs; + // The desctructor + ~Implicit( void ){ delete density ; density = NULL; } - // The signature of the finite-element used for data extrapolation - static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; + // The transformation taking points in the unit cube back to world coordinates + XForm< Real , Dim+1 > unitCubeToModel; - // The constructor - Implicit( AuxData zeroAuxData ) : auxData(NULL) , zeroAuxData(zeroAuxData) {} + // The octree adapted to the points + FEMTree< Dim , Real > tree; - // The desctructor - ~Implicit( void ){ delete auxData ; auxData = NULL; } + // The solution coefficients + DenseNodeData< Real , Sigs > solution; - // The auxiliary information stored with the oriented vertices - SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > > *auxData; + // The average value at the sample positions + Real isoValue; - // An instance of "zero" AuxData - AuxData zeroAuxData; + // The density estimator computed from the samples + DensityEstimator *density; - // a method for rescaling the contents of the auxiliary data to give interpolation-preference to finer levels - void weightAuxDataByDepth( Real perLevelScaleFactor ) - { - auto nodeFunctor = [&]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *n ) + // A method that writes the extracted mesh to the streams + void extractLevelSet( OutputVertexStream< Real , Dim > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const { - ProjectiveData< AuxData , Real >* clr = (*auxData)( n ); - if( clr ) (*clr) *= (Real)pow( (Real)perLevelScaleFactor , Implicit< Real , Dim , FEMSig>::tree.depth( n ) ); - }; - Implicit< Real , Dim , FEMSig>::tree.tree().processNodes( nodeFunctor ); - } + typedef unsigned char AuxData; + _ExtractLevelSet< false , Real , Dim , FEMSig , AuxData , OutputVertexStream< Real , Dim > , Implicit< Real , Dim , FEMSig > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); + } + }; - // A method for writing the extracted mesh to the streams - void extractLevelSet( OutputVertexWithDataStream< Real , Dim , AuxData > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const + // Specialized solution information with auxiliary data + template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > + struct Implicit< Real , Dim , FEMSig , AuxData > : public Implicit< Real , Dim , FEMSig > { - _ExtractLevelSet< true , Real , Dim , FEMSig , AuxData , OutputVertexWithDataStream< Real , Dim , AuxData > , Implicit< Real , Dim , FEMSig , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); - } - }; + typedef IsotropicUIntPack< Dim , FEMSig > Sigs; - struct Poisson - { - static const unsigned int NormalDegree = 2; // The order of the B-Spline used to splat in the normals for constructing the Laplacian constraints - static const unsigned int DefaultFEMDegree = 1; // The default finite-element degree (has to be at least 1) - static const BoundaryType DefaultFEMBoundary = BOUNDARY_NEUMANN; // The default finite-element boundary type {BOUNDARY_FREE, BOUNDARY_DIRICHLET, BOUNDARY_NEUMANN} - inline static const float WeightMultiplier = 2.f; // The default degree-to-point-weight scaling + // The signature of the finite-element used for data extrapolation + static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; - template< unsigned int Dim , typename Real > - struct ConstraintDual - { - Real target , weight; - ConstraintDual( void ) : target(0) , weight(0) {} - ConstraintDual( Real t , Real w ) : target(t) , weight(w) {} - CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim >& p ) const { return CumulativeDerivativeValues< Real , Dim , 0 >( target*weight ); }; - }; + // The constructor + Implicit( AuxData zeroAuxData ) : auxData(NULL) , zeroAuxData(zeroAuxData) {} - template< unsigned int Dim , typename Real > - struct SystemDual - { - Real weight; - SystemDual( void ) : weight(0) {} - SystemDual( Real w ) : weight(w) {} - CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim >& p , const CumulativeDerivativeValues< Real , Dim , 0 >& dValues ) const { return dValues * weight; }; - CumulativeDerivativeValues< double , Dim , 0 > operator()( const Point< Real , Dim >& p , const CumulativeDerivativeValues< double , Dim , 0 >& dValues ) const { return dValues * weight; }; - }; + // The desctructor + ~Implicit( void ){ delete auxData ; auxData = NULL; } - template< unsigned int Dim > - struct SystemDual< Dim , double > - { - typedef double Real; - Real weight; - SystemDual( void ) : weight(0) {} - SystemDual( Real w ) : weight(w) {} - CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim >& p , const CumulativeDerivativeValues< Real , Dim , 0 >& dValues ) const { return dValues * weight; }; - }; + // The auxiliary information stored with the oriented vertices + SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > > *auxData; - template< unsigned int Dim , typename Real > - struct ValueInterpolationConstraintDual - { - typedef VectorTypeUnion< Real , Real > PointSampleData; - Real vWeight; - ValueInterpolationConstraintDual( Real v ) : vWeight(v){ } - CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim > &p , const VectorTypeUnion< Real , Real >& data ) const - { - Real value = data.template get<0>(); - CumulativeDerivativeValues< Real , Dim , 0 > cdv; - cdv[0] = value*vWeight; - return cdv; - } - }; + // An instance of "zero" AuxData + AuxData zeroAuxData; - template< unsigned int Dim , typename Real > - struct ValueInterpolationSystemDual - { - CumulativeDerivativeValues< Real , Dim , 0 > weight; - ValueInterpolationSystemDual( Real v ){ weight[0] = v; } - CumulativeDerivativeValues< Real , Dim , 0 > operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Real > &data , const CumulativeDerivativeValues< Real , Dim , 0 > &dValues ) const + // a method for rescaling the contents of the auxiliary data to give interpolation-preference to finer levels + void weightAuxDataByDepth( Real perLevelScaleFactor ) { - return dValues * weight; + auto nodeFunctor = [&]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *n ) + { + ProjectiveData< AuxData , Real >* clr = (*auxData)( n ); + if( clr ) (*clr) *= (Real)pow( (Real)perLevelScaleFactor , Implicit< Real , Dim , FEMSig>::tree.depth( n ) ); + }; + Implicit< Real , Dim , FEMSig>::tree.tree().processNodes( nodeFunctor ); } - CumulativeDerivativeValues< double , Dim , 0 > operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Real > &data , const CumulativeDerivativeValues< double , Dim , 0 > &dValues ) const + + // A method for writing the extracted mesh to the streams + void extractLevelSet( OutputVertexWithDataStream< Real , Dim , AuxData > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const { - return dValues * weight; + _ExtractLevelSet< true , Real , Dim , FEMSig , AuxData , OutputVertexWithDataStream< Real , Dim , AuxData > , Implicit< Real , Dim , FEMSig , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); } }; - template< unsigned int Dim > - struct ValueInterpolationSystemDual< Dim , double > + struct Poisson { - typedef double Real; - Real weight; - ValueInterpolationSystemDual( void ) : weight(0) {} - ValueInterpolationSystemDual( Real v ) : weight(v) {} - CumulativeDerivativeValues< Real , Dim , 0 > operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Real > &data , const CumulativeDerivativeValues< Real , Dim , 0 > &dValues ) const + static const unsigned int NormalDegree = 2; // The order of the B-Spline used to splat in the normals for constructing the Laplacian constraints + static const unsigned int DefaultFEMDegree = 1; // The default finite-element degree (has to be at least 1) + static const BoundaryType DefaultFEMBoundary = BOUNDARY_NEUMANN; // The default finite-element boundary type {BOUNDARY_FREE, BOUNDARY_DIRICHLET, BOUNDARY_NEUMANN} + inline static const float WeightMultiplier = 2.f; // The default degree-to-point-weight scaling + + template< unsigned int Dim , typename Real > + struct ConstraintDual { - return dValues * weight; - } - }; + Real target , weight; + ConstraintDual( void ) : target(0) , weight(0) {} + ConstraintDual( Real t , Real w ) : target(t) , weight(w) {} + CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim >& p ) const { return CumulativeDerivativeValues< Real , Dim , 0 >( target*weight ); }; + }; - template< typename Real > - struct SolutionParameters - { - bool verbose; - bool dirichletErode; - bool outputDensity; - bool exactInterpolation; - bool showResidual; - Real scale; - Real confidence; - Real confidenceBias; - Real lowDepthCutOff; - Real width; - Real pointWeight; - Real valueInterpolationWeight; - Real samplesPerNode; - Real cgSolverAccuracy; - Real targetValue; - unsigned int depth; - unsigned int solveDepth; - unsigned int baseDepth; - unsigned int fullDepth; - unsigned int kernelDepth; - unsigned int envelopeDepth; - unsigned int baseVCycles; - unsigned int iters; - unsigned int alignDir; - - SolutionParameters( void ) : - verbose(false) , dirichletErode(false) , outputDensity(false) , exactInterpolation(false) , showResidual(false) , - scale((Real)1.1) , confidence((Real)0.) , confidenceBias((Real)0.) , lowDepthCutOff((Real)0.) , width((Real)0.) , - pointWeight((Real)0.) , valueInterpolationWeight((Real)0.) , samplesPerNode((Real)1.5) , cgSolverAccuracy((Real)1e-3 ) , targetValue((Real)0.) , - depth((unsigned int)8) , solveDepth((unsigned int)-1) , baseDepth((unsigned int)-1) , fullDepth((unsigned int)5) , kernelDepth((unsigned int)-1) , - envelopeDepth((unsigned int)-1) , baseVCycles((unsigned int)1) , iters((unsigned int)8) , alignDir(0) - {} - }; + template< unsigned int Dim , typename Real > + struct SystemDual + { + Real weight; + SystemDual( void ) : weight(0) {} + SystemDual( Real w ) : weight(w) {} + CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim >& p , const CumulativeDerivativeValues< Real , Dim , 0 >& dValues ) const { return dValues * weight; }; + CumulativeDerivativeValues< double , Dim , 0 > operator()( const Point< Real , Dim >& p , const CumulativeDerivativeValues< double , Dim , 0 >& dValues ) const { return dValues * weight; }; + }; - template< typename Real , unsigned int Dim > - struct EnvelopeMesh - { - std::vector< Point< Real , Dim > > vertices; - std::vector< SimplexIndex< Dim-1 , node_index_type > > simplices; - }; + template< unsigned int Dim > + struct SystemDual< Dim , double > + { + typedef double Real; + Real weight; + SystemDual( void ) : weight(0) {} + SystemDual( Real w ) : weight(w) {} + CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim >& p , const CumulativeDerivativeValues< Real , Dim , 0 >& dValues ) const { return dValues * weight; }; + }; - template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct Implicit; + template< unsigned int Dim , typename Real > + struct ValueInterpolationConstraintDual + { + typedef VectorTypeUnion< Real , Real > PointSampleData; + Real vWeight; + ValueInterpolationConstraintDual( Real v ) : vWeight(v){ } + CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim > &p , const VectorTypeUnion< Real , Real >& data ) const + { + Real value = data.template get<0>(); + CumulativeDerivativeValues< Real , Dim , 0 > cdv; + cdv[0] = value*vWeight; + return cdv; + } + }; - template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > - static void _Solve( UIntPack< FEMSigs... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh , ValueInterpolationStream< Real , Dim > *valueInterpolationStream ); + template< unsigned int Dim , typename Real > + struct ValueInterpolationSystemDual + { + CumulativeDerivativeValues< Real , Dim , 0 > weight; + ValueInterpolationSystemDual( Real v ){ weight[0] = v; } + CumulativeDerivativeValues< Real , Dim , 0 > operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Real > &data , const CumulativeDerivativeValues< Real , Dim , 0 > &dValues ) const + { + return dValues * weight; + } + CumulativeDerivativeValues< double , Dim , 0 > operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Real > &data , const CumulativeDerivativeValues< double , Dim , 0 > &dValues ) const + { + return dValues * weight; + } + }; - template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct Implicit; + template< unsigned int Dim > + struct ValueInterpolationSystemDual< Dim , double > + { + typedef double Real; + Real weight; + ValueInterpolationSystemDual( void ) : weight(0) {} + ValueInterpolationSystemDual( Real v ) : weight(v) {} + CumulativeDerivativeValues< Real , Dim , 0 > operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Real > &data , const CumulativeDerivativeValues< Real , Dim , 0 > &dValues ) const + { + return dValues * weight; + } + }; - template< typename Real , unsigned int Dim , unsigned int FEMSig > - struct Implicit< Real , Dim , FEMSig > : public Reconstructor::Implicit< Real , Dim , FEMSig > - { - Implicit( InputSampleStream< Real , Dim > &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL , ValueInterpolationStream< Real , Dim > *valueInterpolationStream=NULL ) + template< typename Real > + struct SolutionParameters { - typedef unsigned char AuxData; - _Solve< false , Real , Dim , FEMSig , AuxData , InputSampleStream< Real , Dim > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params , envelopeMesh , valueInterpolationStream ); - } - }; + bool verbose; + bool dirichletErode; + bool outputDensity; + bool exactInterpolation; + bool showResidual; + Real scale; + Real confidence; + Real confidenceBias; + Real lowDepthCutOff; + Real width; + Real pointWeight; + Real valueInterpolationWeight; + Real samplesPerNode; + Real cgSolverAccuracy; + Real targetValue; + unsigned int depth; + unsigned int solveDepth; + unsigned int baseDepth; + unsigned int fullDepth; + unsigned int kernelDepth; + unsigned int envelopeDepth; + unsigned int baseVCycles; + unsigned int iters; + unsigned int alignDir; + + SolutionParameters( void ) : + verbose(false) , dirichletErode(false) , outputDensity(false) , exactInterpolation(false) , showResidual(false) , + scale((Real)1.1) , confidence((Real)0.) , confidenceBias((Real)0.) , lowDepthCutOff((Real)0.) , width((Real)0.) , + pointWeight((Real)0.) , valueInterpolationWeight((Real)0.) , samplesPerNode((Real)1.5) , cgSolverAccuracy((Real)1e-3 ) , targetValue((Real)0.) , + depth((unsigned int)8) , solveDepth((unsigned int)-1) , baseDepth((unsigned int)-1) , fullDepth((unsigned int)5) , kernelDepth((unsigned int)-1) , + envelopeDepth((unsigned int)-1) , baseVCycles((unsigned int)1) , iters((unsigned int)8) , alignDir(0) + {} + }; - template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > - struct Implicit< Real , Dim , FEMSig , AuxData > : public Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > - { - Implicit( InputSampleWithDataStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL , ValueInterpolationStream< Real , Dim > *valueInterpolationStream=NULL ) - : Reconstructor::Implicit< Real , Dim , FEMSig , AuxData >( pointStream.zero() ) + template< typename Real , unsigned int Dim > + struct EnvelopeMesh { - _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleWithDataStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params , envelopeMesh , valueInterpolationStream ); - } - }; - }; + std::vector< Point< Real , Dim > > vertices; + std::vector< SimplexIndex< Dim-1 , node_index_type > > simplices; + }; - struct SSD - { - static const unsigned int NormalDegree = 2; // The order of the B-Spline used to splat in the normals for constructing the Laplacian constraints - static const unsigned int DefaultFEMDegree = 2; // The default finite-element degree (has to be at least 2) - static const BoundaryType DefaultFEMBoundary = BOUNDARY_NEUMANN; // The default finite-element boundary type {BOUNDARY_FREE, BOUNDARY_DIRICHLET, BOUNDARY_NEUMANN} - inline static const double WeightMultipliers[] = { 5e+1f , 5e-4f , 1e-5f }; // The default weights for balancing the value, gradient, and laplacian energy terms + template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct Implicit; - template< unsigned int Dim , typename ... > struct ConstraintDual; - template< unsigned int Dim , typename ... > struct SystemDual; + template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > + static void _Solve( UIntPack< FEMSigs... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh , ValueInterpolationStream< Real , Dim > *valueInterpolationStream ); - template< unsigned int Dim , typename Real > - struct ConstraintDual< Dim , Real > - { - Real target , vWeight , gWeight; - ConstraintDual( Real t , Real v , Real g ) : target(t) , vWeight(v) , gWeight(g) { } - CumulativeDerivativeValues< Real , Dim , 1 > operator()( const Point< Real , Dim >& p , const Point< Real , Dim > &n ) const + template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct Implicit; + + template< typename Real , unsigned int Dim , unsigned int FEMSig > + struct Implicit< Real , Dim , FEMSig > : public Reconstructor::Implicit< Real , Dim , FEMSig > { - CumulativeDerivativeValues< Real , Dim , 1 > cdv; - cdv[0] = target*vWeight; - for( int d=0 ; d &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL , ValueInterpolationStream< Real , Dim > *valueInterpolationStream=NULL ) + { + typedef unsigned char AuxData; + _Solve< false , Real , Dim , FEMSig , AuxData , InputSampleStream< Real , Dim > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params , envelopeMesh , valueInterpolationStream ); + } + }; - template< unsigned int Dim , typename Real , typename AuxData > - struct ConstraintDual< Dim , Real , AuxData > - { - Real target , vWeight , gWeight; - ConstraintDual( Real t , Real v , Real g ) : target(t) , vWeight(v) , gWeight(g) { } - CumulativeDerivativeValues< Real , Dim , 1 > operator()( const Point< Real , Dim >& p , const VectorTypeUnion< Real , Point< Real , Dim > , AuxData > &normalAndAuxData ) const + template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > + struct Implicit< Real , Dim , FEMSig , AuxData > : public Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > { - Point< Real , Dim > n = normalAndAuxData.template get<0>(); - CumulativeDerivativeValues< Real , Dim , 1 > cdv; - cdv[0] = target*vWeight; - for( int d=0 ; d &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL , ValueInterpolationStream< Real , Dim > *valueInterpolationStream=NULL ) + : Reconstructor::Implicit< Real , Dim , FEMSig , AuxData >( pointStream.zero() ) + { + _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleWithDataStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params , envelopeMesh , valueInterpolationStream ); + } + }; }; - template< unsigned int Dim , typename Real > - struct SystemDual< Dim , Real > + struct SSD { - CumulativeDerivativeValues< Real , Dim , 1 > weight; - SystemDual( Real v , Real g ) - { - weight[0] = v; - for( int d=0 ; d operator()( Point< Real , Dim > p , const Point< Real , Dim > & , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const - { - return dValues * weight; - } - CumulativeDerivativeValues< double , Dim , 1 > operator()( Point< Real , Dim > p , const Point< Real , Dim > & , const CumulativeDerivativeValues< double , Dim , 1 >& dValues ) const + static const unsigned int NormalDegree = 2; // The order of the B-Spline used to splat in the normals for constructing the Laplacian constraints + static const unsigned int DefaultFEMDegree = 2; // The default finite-element degree (has to be at least 2) + static const BoundaryType DefaultFEMBoundary = BOUNDARY_NEUMANN; // The default finite-element boundary type {BOUNDARY_FREE, BOUNDARY_DIRICHLET, BOUNDARY_NEUMANN} + inline static const double WeightMultipliers[] = { 5e+1f , 5e-4f , 1e-5f }; // The default weights for balancing the value, gradient, and laplacian energy terms + + template< unsigned int Dim , typename ... > struct ConstraintDual; + template< unsigned int Dim , typename ... > struct SystemDual; + + template< unsigned int Dim , typename Real > + struct ConstraintDual< Dim , Real > { - return dValues * weight; + Real target , vWeight , gWeight; + ConstraintDual( Real t , Real v , Real g ) : target(t) , vWeight(v) , gWeight(g) { } + CumulativeDerivativeValues< Real , Dim , 1 > operator()( const Point< Real , Dim >& p , const Point< Real , Dim > &n ) const + { + CumulativeDerivativeValues< Real , Dim , 1 > cdv; + cdv[0] = target*vWeight; + for( int d=0 ; d - struct SystemDual< Dim , double > - { - typedef double Real; - CumulativeDerivativeValues< Real , Dim , 1 > weight; - SystemDual( Real v , Real g ) : weight( v , g , g , g ) { } - CumulativeDerivativeValues< Real , Dim , 1 > operator()( Point< Real , Dim > p , const Point< Real , Dim > & , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const + template< unsigned int Dim , typename Real , typename AuxData > + struct ConstraintDual< Dim , Real , AuxData > { - return dValues * weight; - } - }; + Real target , vWeight , gWeight; + ConstraintDual( Real t , Real v , Real g ) : target(t) , vWeight(v) , gWeight(g) { } + CumulativeDerivativeValues< Real , Dim , 1 > operator()( const Point< Real , Dim >& p , const VectorTypeUnion< Real , Point< Real , Dim > , AuxData > &normalAndAuxData ) const + { + Point< Real , Dim > n = normalAndAuxData.template get<0>(); + CumulativeDerivativeValues< Real , Dim , 1 > cdv; + cdv[0] = target*vWeight; + for( int d=0 ; d - struct SystemDual< Dim , Real , AuxData > - { - CumulativeDerivativeValues< Real , Dim , 1 > weight; - SystemDual( Real v , Real g ) + template< unsigned int Dim , typename Real > + struct SystemDual< Dim , Real > { - weight[0] = v; - for( int d=0 ; d operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Point< Real , Dim > , AuxData > & , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const + CumulativeDerivativeValues< Real , Dim , 1 > weight; + SystemDual( Real v , Real g ) + { + weight[0] = v; + for( int d=0 ; d operator()( Point< Real , Dim > p , const Point< Real , Dim > & , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const + { + return dValues * weight; + } + CumulativeDerivativeValues< double , Dim , 1 > operator()( Point< Real , Dim > p , const Point< Real , Dim > & , const CumulativeDerivativeValues< double , Dim , 1 >& dValues ) const + { + return dValues * weight; + }; + }; + + template< unsigned int Dim > + struct SystemDual< Dim , double > { - return dValues * weight; - } - CumulativeDerivativeValues< double , Dim , 1 > operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Point< Real , Dim > , AuxData > & , const CumulativeDerivativeValues< double , Dim , 1 >& dValues ) const + typedef double Real; + CumulativeDerivativeValues< Real , Dim , 1 > weight; + SystemDual( Real v , Real g ) : weight( v , g , g , g ) { } + CumulativeDerivativeValues< Real , Dim , 1 > operator()( Point< Real , Dim > p , const Point< Real , Dim > & , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const + { + return dValues * weight; + } + }; + + template< unsigned int Dim , typename Real , typename AuxData > + struct SystemDual< Dim , Real , AuxData > { - return dValues * weight; + CumulativeDerivativeValues< Real , Dim , 1 > weight; + SystemDual( Real v , Real g ) + { + weight[0] = v; + for( int d=0 ; d operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Point< Real , Dim > , AuxData > & , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const + { + return dValues * weight; + } + CumulativeDerivativeValues< double , Dim , 1 > operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Point< Real , Dim > , AuxData > & , const CumulativeDerivativeValues< double , Dim , 1 >& dValues ) const + { + return dValues * weight; + }; }; - }; - template< unsigned int Dim , class AuxData > - struct SystemDual< Dim , double , AuxData > - { - typedef double Real; - CumulativeDerivativeValues< Real , Dim , 1 > weight; - SystemDual( Real v , Real g ) : weight( v , g , g , g ) { } - CumulativeDerivativeValues< Real , Dim , 1 > operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Point< Real , Dim > , AuxData > & , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const + template< unsigned int Dim , class AuxData > + struct SystemDual< Dim , double , AuxData > { - return dValues * weight; - } - }; + typedef double Real; + CumulativeDerivativeValues< Real , Dim , 1 > weight; + SystemDual( Real v , Real g ) : weight( v , g , g , g ) { } + CumulativeDerivativeValues< Real , Dim , 1 > operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Point< Real , Dim > , AuxData > & , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const + { + return dValues * weight; + } + }; - template< typename Real > - struct SolutionParameters - { - bool verbose; - bool outputDensity; - bool exactInterpolation; - bool showResidual; - Real scale; - Real confidence; - Real confidenceBias; - Real lowDepthCutOff; - Real width; - Real pointWeight; - Real gradientWeight; - Real biLapWeight; - Real samplesPerNode; - Real cgSolverAccuracy; - unsigned int depth; - unsigned int solveDepth; - unsigned int baseDepth; - unsigned int fullDepth; - unsigned int kernelDepth; - unsigned int baseVCycles; - unsigned int iters; - unsigned int alignDir; - - SolutionParameters( void ) : - verbose(false) , outputDensity(false) , exactInterpolation(false) , showResidual(false) , - scale((Real)1.1) , confidence((Real)0.) , confidenceBias((Real)0.) , lowDepthCutOff((Real)0.) , width((Real)0.) , - pointWeight((Real)WeightMultipliers[0]) , gradientWeight((Real)WeightMultipliers[1]) , biLapWeight((Real)WeightMultipliers[2]) , samplesPerNode((Real)1.5) , cgSolverAccuracy((Real)1e-3 ) , - depth((unsigned int)8) , solveDepth((unsigned int)-1) , baseDepth((unsigned int)-1) , fullDepth((unsigned int)5) , kernelDepth((unsigned int)-1) , alignDir(0) , - baseVCycles((unsigned int)1) , iters((unsigned int)8) - {} + template< typename Real > + struct SolutionParameters + { + bool verbose; + bool outputDensity; + bool exactInterpolation; + bool showResidual; + Real scale; + Real confidence; + Real confidenceBias; + Real lowDepthCutOff; + Real width; + Real pointWeight; + Real gradientWeight; + Real biLapWeight; + Real samplesPerNode; + Real cgSolverAccuracy; + unsigned int depth; + unsigned int solveDepth; + unsigned int baseDepth; + unsigned int fullDepth; + unsigned int kernelDepth; + unsigned int baseVCycles; + unsigned int iters; + unsigned int alignDir; + + SolutionParameters( void ) : + verbose(false) , outputDensity(false) , exactInterpolation(false) , showResidual(false) , + scale((Real)1.1) , confidence((Real)0.) , confidenceBias((Real)0.) , lowDepthCutOff((Real)0.) , width((Real)0.) , + pointWeight((Real)WeightMultipliers[0]) , gradientWeight((Real)WeightMultipliers[1]) , biLapWeight((Real)WeightMultipliers[2]) , samplesPerNode((Real)1.5) , cgSolverAccuracy((Real)1e-3 ) , + depth((unsigned int)8) , solveDepth((unsigned int)-1) , baseDepth((unsigned int)-1) , fullDepth((unsigned int)5) , kernelDepth((unsigned int)-1) , alignDir(0) , + baseVCycles((unsigned int)1) , iters((unsigned int)8) + {} - }; + }; - template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct Implicit; + template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct Implicit; - template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > - static void _Solve( UIntPack< FEMSigs... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params ); + template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > + static void _Solve( UIntPack< FEMSigs... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params ); - template< typename Real , unsigned int Dim , unsigned int FEMSig > - struct Implicit< Real , Dim , FEMSig > : public Reconstructor::Implicit< Real , Dim , FEMSig > - { - Implicit( InputSampleStream< Real , Dim > &pointStream , SolutionParameters< Real > params ) + template< typename Real , unsigned int Dim , unsigned int FEMSig > + struct Implicit< Real , Dim , FEMSig > : public Reconstructor::Implicit< Real , Dim , FEMSig > { - typedef unsigned char AuxData; - _Solve< false , Real , Dim , FEMSig , AuxData , InputSampleStream< Real , Dim > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params ); - } - }; + Implicit( InputSampleStream< Real , Dim > &pointStream , SolutionParameters< Real > params ) + { + typedef unsigned char AuxData; + _Solve< false , Real , Dim , FEMSig , AuxData , InputSampleStream< Real , Dim > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params ); + } + }; - template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > - struct Implicit< Real , Dim , FEMSig , AuxData > : public Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > - { - Implicit( InputSampleWithDataStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params ) - : Reconstructor::Implicit< Real , Dim , FEMSig , AuxData >( pointStream.zero() ) + template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > + struct Implicit< Real , Dim , FEMSig , AuxData > : public Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > { - _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleWithDataStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params ); - } + Implicit( InputSampleWithDataStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params ) + : Reconstructor::Implicit< Real , Dim , FEMSig , AuxData >( pointStream.zero() ) + { + _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleWithDataStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params ); + } + }; }; - }; - - template< class Real , unsigned int Dim , bool ExtendedAxes > - PointExtent::Extent< Real , Dim , ExtendedAxes > GetExtent( InputDataStream< Point< Real , Dim > > &stream ) - { - Point< Real , Dim > p; - PointExtent::Extent< Real , Dim , ExtendedAxes > e; - while( stream.read( p ) ) e.add( p ); - stream.reset(); - return e; - } - - template< class Real , unsigned int Dim , bool ExtendedAxes , typename AuxData > - PointExtent::Extent< Real , Dim , ExtendedAxes > GetExtent( InputDataStream< VectorTypeUnion< Real , Point< Real , Dim > , AuxData > > &stream , AuxData d ) - { - VectorTypeUnion< Real , Point< Real , Dim > , AuxData > p( Point< Real , Dim >() , d ); - PointExtent::Extent< Real , Dim , ExtendedAxes > e; - while( stream.read( p ) ) e.add( p.template get<0>() ); - stream.reset(); - return e; - } - - template< class Real , unsigned int Dim , bool ExtendedAxes > - XForm< Real , Dim+1 > GetPointXForm( InputDataStream< Point< Real , Dim > > &stream , Real scaleFactor , unsigned int dir ) - { - PointExtent::Extent< Real , Dim , ExtendedAxes > e = GetExtent< Real , Dim , ExtendedAxes >( stream ); - return PointExtent::GetBoundingBoxXForm( e , scaleFactor , dir ); - } - - template< class Real , unsigned int Dim , bool ExtendedAxes , typename AuxData > - XForm< Real , Dim+1 > GetPointXForm( InputDataStream< VectorTypeUnion< Real , Point< Real , Dim > , AuxData > > &stream , AuxData d , Real scaleFactor , unsigned int dir ) - { - PointExtent::Extent< Real , Dim , ExtendedAxes > e = GetExtent< Real , Dim , ExtendedAxes , AuxData >( stream , d ); - return PointExtent::GetBoundingBoxXForm( e , scaleFactor , dir ); - } - - template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ImplicitType , unsigned int ... FEMSigs > - void _ExtractLevelSet( UIntPack< FEMSigs ... > , const ImplicitType &implicit , OutputVertexStream &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) - { - typedef UIntPack< FEMSigs ... > Sigs; - static_assert( std::is_same< IsotropicUIntPack< Dim , FEMSig > , UIntPack< FEMSigs ... > >::value , "[ERROR] Signatures don't match" ); - static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; - typedef typename ImplicitType::DensityEstimator DensityEstimator; - if constexpr( Dim==3 ) + template< class Real , unsigned int Dim , bool ExtendedAxes > + PointExtent::Extent< Real , Dim , ExtendedAxes > GetExtent( InputDataStream< Point< Real , Dim > > &stream ) { - Profiler profiler(20); - - std::string statsString; - - if constexpr( HasAuxData ) - { - typename LevelSetExtractor< Real , Dim , AuxData >::Stats stats; - TransformedOutputVertexWithDataStream< Real , Dim , AuxData > _vertexStream( implicit.unitCubeToModel , vertexStream ); - stats = LevelSetExtractor< Real , Dim , AuxData >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , UIntPack< DataSig >() , implicit.tree , implicit.density , implicit.auxData , implicit.solution , implicit.isoValue , _vertexStream , faceStream , implicit.zeroAuxData , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); - statsString = stats.toString(); - } - else - { - typename LevelSetExtractor< Real , Dim >::Stats stats; - TransformedOutputVertexStream< Real , Dim > _vertexStream( implicit.unitCubeToModel , vertexStream ); - stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , implicit.tree , implicit.density , implicit.solution , implicit.isoValue , _vertexStream , faceStream , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); - statsString = stats.toString(); - } - if( params.verbose ) - { - std::cout << "Vertices / Faces: " << vertexStream.size() << " / " << faceStream.size() << std::endl; - std::cout << statsString << std::endl; - std::cout << "# Got Faces: " << profiler << std::endl; - } + Point< Real , Dim > p; + PointExtent::Extent< Real , Dim , ExtendedAxes > e; + while( stream.read( p ) ) e.add( p ); + stream.reset(); + return e; } - else if constexpr( Dim==2 ) - { - Profiler profiler(20); - - std::string statsString; - if constexpr( HasAuxData ) - { - typename LevelSetExtractor< Real , Dim , AuxData >::Stats stats; - TransformedOutputVertexWithDataStream< Real , Dim , AuxData > _vertexStream( implicit.unitCubeToModel , vertexStream ); - stats = LevelSetExtractor< Real , Dim , AuxData >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , UIntPack< DataSig >() , implicit.tree , implicit.density , implicit.auxData , implicit.solution , implicit.isoValue , _vertexStream , faceStream , implicit.zeroAuxData , !params.linearFit , params.outputGradients , false ); - statsString = stats.toString(); - } - else - { - typename LevelSetExtractor< Real , Dim >::Stats stats; - TransformedOutputVertexStream< Real , Dim > _vertexStream( implicit.unitCubeToModel , vertexStream ); - stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , implicit.tree , implicit.density , implicit.solution , implicit.isoValue , _vertexStream , faceStream , !params.linearFit , params.outputGradients , false ); - statsString = stats.toString(); - } - if( params.verbose ) - { - std::cout << "Vertices / Faces: " << vertexStream.size() << " / " << faceStream.size() << std::endl; - std::cout << statsString << std::endl; - std::cout << "# Got faces: " << profiler << std::endl; - } + template< class Real , unsigned int Dim , bool ExtendedAxes , typename AuxData > + PointExtent::Extent< Real , Dim , ExtendedAxes > GetExtent( InputDataStream< VectorTypeUnion< Real , Point< Real , Dim > , AuxData > > &stream , AuxData d ) + { + VectorTypeUnion< Real , Point< Real , Dim > , AuxData > p( Point< Real , Dim >() , d ); + PointExtent::Extent< Real , Dim , ExtendedAxes > e; + while( stream.read( p ) ) e.add( p.template get<0>() ); + stream.reset(); + return e; } - else WARN( "Extraction only supported for dimensions 2 and 3" ); } - template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > - void Poisson::_Solve( UIntPack< FEMSigs ... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh , ValueInterpolationStream< Real , Dim > *valueInterpolationStream ) - { - static_assert( std::is_same< IsotropicUIntPack< Dim , FEMSig > , UIntPack< FEMSigs... > >::value , "[ERROR] Signatures don't match" ); - if( params.valueInterpolationWeight<0 ) + template< class Real , unsigned int Dim , bool ExtendedAxes > + XForm< Real , Dim+1 > GetPointXForm( InputDataStream< Point< Real , Dim > > &stream , Real scaleFactor , unsigned int dir ) { - WARN( "Negative value interpolation weight clamped to zero" ); - params.valueInterpolationWeight = 0; + PointExtent::Extent< Real , Dim , ExtendedAxes > e = GetExtent< Real , Dim , ExtendedAxes >( stream ); + return PointExtent::GetBoundingBoxXForm( e , scaleFactor , dir ); } - if( valueInterpolationStream && !params.valueInterpolationWeight ) WARN( "Value interpolation stream provided but interpolation weight is zero" ); - // The signature for the finite-elements representing the auxiliary data (if it's there) - static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; - - /////////////// - // Types --> // - // The packed finite elements signature - typedef UIntPack< FEMSigs ... > Sigs; + template< class Real , unsigned int Dim , bool ExtendedAxes , typename AuxData > + XForm< Real , Dim+1 > GetPointXForm( InputDataStream< VectorTypeUnion< Real , Point< Real , Dim > , AuxData > > &stream , AuxData d , Real scaleFactor , unsigned int dir ) + { + PointExtent::Extent< Real , Dim , ExtendedAxes > e = GetExtent< Real , Dim , ExtendedAxes , AuxData >( stream , d ); + return PointExtent::GetBoundingBoxXForm( e , scaleFactor , dir ); + } - // The degrees of the finite elements across the different axes - typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > Degrees; + template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ImplicitType , unsigned int ... FEMSigs > + void _ExtractLevelSet( UIntPack< FEMSigs ... > , const ImplicitType &implicit , OutputVertexStream &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) + { + typedef UIntPack< FEMSigs ... > Sigs; + static_assert( std::is_same< IsotropicUIntPack< Dim , FEMSig > , UIntPack< FEMSigs ... > >::value , "[ERROR] Signatures don't match" ); + static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; + typedef typename ImplicitType::DensityEstimator DensityEstimator; - // The signature describing the normals elements - typedef UIntPack< FEMDegreeAndBType< Poisson::NormalDegree , DerivativeBoundary< FEMSignature< FEMSigs >::BType , 1 >::BType >::Signature ... > NormalSigs; + if constexpr( Dim==3 ) + { + Profiler profiler(20); - // Type for tracking sample interpolation - typedef typename FEMTree< Dim , Real >::template InterpolationInfo< Real , 0 > InterpolationInfo; + std::string statsString; - // The finite-element tracking tree node - typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; + if constexpr( HasAuxData ) + { + typename LevelSetExtractor< Real , Dim , AuxData >::Stats stats; + TransformedOutputVertexWithDataStream< Real , Dim , AuxData > _vertexStream( implicit.unitCubeToModel , vertexStream ); + stats = LevelSetExtractor< Real , Dim , AuxData >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , UIntPack< DataSig >() , implicit.tree , implicit.density , implicit.auxData , implicit.solution , implicit.isoValue , _vertexStream , faceStream , implicit.zeroAuxData , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); + statsString = stats.toString(); + } + else + { + typename LevelSetExtractor< Real , Dim >::Stats stats; + TransformedOutputVertexStream< Real , Dim > _vertexStream( implicit.unitCubeToModel , vertexStream ); + stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , implicit.tree , implicit.density , implicit.solution , implicit.isoValue , _vertexStream , faceStream , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); + statsString = stats.toString(); + } + if( params.verbose ) + { + std::cout << "Vertices / Faces: " << vertexStream.size() << " / " << faceStream.size() << std::endl; + std::cout << statsString << std::endl; + std::cout << "# Got Faces: " << profiler << std::endl; + } + } + else if constexpr( Dim==2 ) + { + Profiler profiler(20); - typedef typename FEMTreeInitializer< Dim , Real >::GeometryNodeType GeometryNodeType; + std::string statsString; - // The type of the auxiliary information (including the normal) - typedef typename std::conditional< HasAuxData , VectorTypeUnion< Real , Normal< Real , Dim > , AuxData > , Normal< Real , Dim > >::type NormalAndAuxData; + if constexpr( HasAuxData ) + { + typename LevelSetExtractor< Real , Dim , AuxData >::Stats stats; + TransformedOutputVertexWithDataStream< Real , Dim , AuxData > _vertexStream( implicit.unitCubeToModel , vertexStream ); + stats = LevelSetExtractor< Real , Dim , AuxData >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , UIntPack< DataSig >() , implicit.tree , implicit.density , implicit.auxData , implicit.solution , implicit.isoValue , _vertexStream , faceStream , implicit.zeroAuxData , !params.linearFit , params.outputGradients , false ); + statsString = stats.toString(); + } + else + { + typename LevelSetExtractor< Real , Dim >::Stats stats; + TransformedOutputVertexStream< Real , Dim > _vertexStream( implicit.unitCubeToModel , vertexStream ); + stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , implicit.tree , implicit.density , implicit.solution , implicit.isoValue , _vertexStream , faceStream , !params.linearFit , params.outputGradients , false ); + statsString = stats.toString(); + } + if( params.verbose ) + { + std::cout << "Vertices / Faces: " << vertexStream.size() << " / " << faceStream.size() << std::endl; + std::cout << statsString << std::endl; + std::cout << "# Got faces: " << profiler << std::endl; + } + } + else WARN( "Extraction only supported for dimensions 2 and 3" ); } - // The type describing the sampling density - typedef typename std::conditional< HasAuxData , Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type::DensityEstimator DensityEstimator; - // <-- Types // - /////////////// + template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > + void Poisson::_Solve( UIntPack< FEMSigs ... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh , ValueInterpolationStream< Real , Dim > *valueInterpolationStream ) + { + static_assert( std::is_same< IsotropicUIntPack< Dim , FEMSig > , UIntPack< FEMSigs... > >::value , "[ERROR] Signatures don't match" ); + if( params.valueInterpolationWeight<0 ) + { + WARN( "Negative value interpolation weight clamped to zero" ); + params.valueInterpolationWeight = 0; + } + if( valueInterpolationStream && !params.valueInterpolationWeight ) WARN( "Value interpolation stream provided but interpolation weight is zero" ); - NormalAndAuxData zeroNormalAndAuxData; - if constexpr( HasAuxData ) zeroNormalAndAuxData = NormalAndAuxData( Normal< Real , Dim >() , implicit.zeroAuxData ); + // The signature for the finite-elements representing the auxiliary data (if it's there) + static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; - XForm< Real , Dim+1 > modelToUnitCube = XForm< Real , Dim+1 >::Identity(); + /////////////// + // Types --> // + // The packed finite elements signature + typedef UIntPack< FEMSigs ... > Sigs; - Profiler profiler(20); + // The degrees of the finite elements across the different axes + typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > Degrees; - size_t pointCount; + // The signature describing the normals elements + typedef UIntPack< FEMDegreeAndBType< Poisson::NormalDegree , DerivativeBoundary< FEMSignature< FEMSigs >::BType , 1 >::BType >::Signature ... > NormalSigs; - ProjectiveData< Point< Real , 2 > , Real > pointDepthAndWeight; - std::vector< typename FEMTree< Dim , Real >::PointSample > *valueInterpolationSamples = NULL; - std::vector< Real > *valueInterpolationSampleData = NULL; - DenseNodeData< GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > geometryNodeDesignators; - SparseNodeData< Point< Real , Dim > , NormalSigs > *normalInfo = NULL; - std::vector< typename FEMTree< Dim , Real >::PointSample > *samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); - std::vector< NormalAndAuxData > *sampleNormalAndAuxData = NULL; + // Type for tracking sample interpolation + typedef typename FEMTree< Dim , Real >::template InterpolationInfo< Real , 0 > InterpolationInfo; - Real targetValue = params.targetValue; + // The finite-element tracking tree node + typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; - // Read in the samples (and auxiliary data) - { - profiler.reset(); + typedef typename FEMTreeInitializer< Dim , Real >::GeometryNodeType GeometryNodeType; - pointStream.reset(); - sampleNormalAndAuxData = new std::vector< NormalAndAuxData >(); + // The type of the auxiliary information (including the normal) + typedef typename std::conditional< HasAuxData , VectorTypeUnion< Real , Normal< Real , Dim > , AuxData > , Normal< Real , Dim > >::type NormalAndAuxData; - modelToUnitCube = params.scale>0 ? GetPointXForm< Real , Dim , true >( pointStream , zeroNormalAndAuxData , params.scale , params.alignDir ) * modelToUnitCube : modelToUnitCube; + // The type describing the sampling density + typedef typename std::conditional< HasAuxData , Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type::DensityEstimator DensityEstimator; + // <-- Types // + /////////////// - if( params.width>0 ) - { - XForm< Real , Dim > unitCubeToModel = modelToUnitCube.inverse(); + NormalAndAuxData zeroNormalAndAuxData; + if constexpr( HasAuxData ) zeroNormalAndAuxData = NormalAndAuxData( Normal< Real , Dim >() , implicit.zeroAuxData ); - Real maxScale = 0; - for( unsigned int i=0 ; imaxScale ) maxScale = l2; - } - maxScale = sqrt( maxScale ); - params.depth = (unsigned int)ceil( std::max< double >( 0. , log( maxScale/params.width )/log(2.) ) ); - } - if( params.solveDepth>params.depth ) - { - if( params.solveDepth!=-1 ) WARN( "Solution depth cannot exceed system depth: " , params.solveDepth , " <= " , params.depth ); - params.solveDepth = params.depth; - } - if( params.fullDepth>params.solveDepth ) - { - if( params.fullDepth!=-1 ) WARN( "Full depth cannot exceed system depth: " , params.fullDepth , " <= " , params.solveDepth ); - params.fullDepth = params.solveDepth; - } - if( params.baseDepth>params.fullDepth ) - { - if( params.baseDepth!=-1 ) WARN( "Base depth must be smaller than full depth: " , params.baseDepth , " <= " , params.fullDepth ); - params.baseDepth = params.fullDepth; - } - if( params.kernelDepth==-1 ) params.kernelDepth = params.depth>2 ? params.depth-2 : 0; - if( params.kernelDepth>params.depth ) - { - if( params.kernelDepth!=-1 ) WARN( "Kernel depth cannot exceed system depth: " , params.kernelDepth , " <= " , params.depth ); - params.kernelDepth = params.depth; - } - if( params.envelopeDepth==-1 ) params.envelopeDepth = params.baseDepth; - if( params.envelopeDepth>params.depth ) - { - if( params.envelopeDepth!=-1 ) WARN( "Envelope dpeth cannot exceed system depth: " , params.envelopeDepth , " <= " , params.depth ); - params.envelopeDepth = params.depth; - } - if( params.envelopeDepth= " , params.baseDepth ); - params.envelopeDepth = params.baseDepth; - } + XForm< Real , Dim+1 > modelToUnitCube = XForm< Real , Dim+1 >::Identity(); - if constexpr( HasAuxData ) - { -#ifdef DE_VIRTUALIZE_OUTPUT - TransformedInputSampleWithDataStream< Real , Dim , AuxData , InputSampleStreamType > _pointStream( modelToUnitCube , pointStream ); -#else // !DE_VIRTUALIZE_OUTPUT - TransformedInputSampleWithDataStream< Real , Dim , AuxData > _pointStream( modelToUnitCube , pointStream ); -#endif // DE_VIRTUALIZE_OUTPUT - auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , NormalAndAuxData &d ) - { - Real l = (Real)Length( d.template get<0>() ); - if( !l || !std::isfinite( l ) ) return (Real)-1.; - return (Real)pow( l , params.confidence ); - }; - auto ProcessData = []( const Point< Real , Dim > &p , NormalAndAuxData &d ) - { - Real l = (Real)Length( d.template get<0>() ); - if( !l || !std::isfinite( l ) ) return (Real)-1.; - d.template get<0>() /= l; - return (Real)1.; - }; + Profiler profiler(20); - typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; - if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); - } - else - { -#ifdef DE_VIRTUALIZE_OUTPUT - TransformedInputSampleStream< Real , Dim , InputSampleStreamType > _pointStream( modelToUnitCube , pointStream ); -#else // !DE_VIRTUALIZE_OUTPUT - TransformedInputSampleStream< Real , Dim > _pointStream( modelToUnitCube , pointStream ); -#endif // DE_VIRTUALIZE_OUTPUT - auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , NormalAndAuxData &d ) - { - Real l = (Real)Length( d ); - if( !l || !std::isfinite( l ) ) return (Real)-1.; - return (Real)pow( l , params.confidence ); - }; - auto ProcessData = []( const Point< Real , Dim > &p , NormalAndAuxData &d ) - { - Real l = (Real)Length( d ); - if( !l || !std::isfinite( l ) ) return (Real)-1.; - d /= l; - return (Real)1.; - }; + size_t pointCount; - typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; - if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); - } + ProjectiveData< Point< Real , 2 > , Real > pointDepthAndWeight; + std::vector< typename FEMTree< Dim , Real >::PointSample > *valueInterpolationSamples = NULL; + std::vector< Real > *valueInterpolationSampleData = NULL; + DenseNodeData< GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > geometryNodeDesignators; + SparseNodeData< Point< Real , Dim > , NormalSigs > *normalInfo = NULL; + std::vector< typename FEMTree< Dim , Real >::PointSample > *samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); + std::vector< NormalAndAuxData > *sampleNormalAndAuxData = NULL; - implicit.unitCubeToModel = modelToUnitCube.inverse(); + Real targetValue = params.targetValue; - if( params.verbose ) + // Read in the samples (and auxiliary data) { - std::cout << "Input Points / Samples: " << pointCount << " / " << samples->size() << std::endl; - std::cout << "# Read input into tree: " << profiler << std::endl; - } - } - - if( valueInterpolationStream && params.valueInterpolationWeight ) - { - valueInterpolationSamples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); - valueInterpolationSampleData = new std::vector< Real >(); - // Wrap the point stream in a transforming stream - TransformedValueInterpolationStream< Real , Dim > _valueInterpolationStream( modelToUnitCube , *valueInterpolationStream ); - - // Assign each sample a weight of 1. - auto ProcessData = []( const Point< Real , Dim > &p , Real &d ){ return (Real)1.; }; - Real zeroValue = (Real)0.; - typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; - size_t count = FEMTreeInitializer< Dim , Real >::template Initialize< Real >( sid , implicit.tree.spaceRoot() , _valueInterpolationStream , zeroValue , params.depth , *valueInterpolationSamples , *valueInterpolationSampleData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); - if( params.verbose ) std::cout << "Input Interpolation Points / Samples: " << count << " / " << valueInterpolationSamples->size() << std::endl; - } + profiler.reset(); - { - InterpolationInfo *valueInterpolationInfo = NULL; - DenseNodeData< Real , Sigs > constraints; - InterpolationInfo *iInfo = NULL; - int solveDepth = params.depth; + pointStream.reset(); + sampleNormalAndAuxData = new std::vector< NormalAndAuxData >(); - implicit.tree.resetNodeIndices( 0 , std::make_tuple() ); + modelToUnitCube = params.scale>0 ? GetPointXForm< Real , Dim , true >( pointStream , zeroNormalAndAuxData , params.scale , params.alignDir ) * modelToUnitCube : modelToUnitCube; - // Get the kernel density estimator - { - profiler.reset(); - implicit.density = implicit.tree.template setDensityEstimator< 1 , Reconstructor::WeightDegree >( *samples , params.kernelDepth , params.samplesPerNode ); - if( params.verbose ) std::cout << "# Got kernel density: " << profiler << std::endl; - } + if( params.width>0 ) + { + XForm< Real , Dim > unitCubeToModel = modelToUnitCube.inverse(); + + Real maxScale = 0; + for( unsigned int i=0 ; imaxScale ) maxScale = l2; + } + maxScale = sqrt( maxScale ); + params.depth = (unsigned int)ceil( std::max< double >( 0. , log( maxScale/params.width )/log(2.) ) ); + } + if( params.solveDepth>params.depth ) + { + if( params.solveDepth!=-1 ) WARN( "Solution depth cannot exceed system depth: " , params.solveDepth , " <= " , params.depth ); + params.solveDepth = params.depth; + } + if( params.fullDepth>params.solveDepth ) + { + if( params.fullDepth!=-1 ) WARN( "Full depth cannot exceed system depth: " , params.fullDepth , " <= " , params.solveDepth ); + params.fullDepth = params.solveDepth; + } + if( params.baseDepth>params.fullDepth ) + { + if( params.baseDepth!=-1 ) WARN( "Base depth must be smaller than full depth: " , params.baseDepth , " <= " , params.fullDepth ); + params.baseDepth = params.fullDepth; + } + if( params.kernelDepth==-1 ) params.kernelDepth = params.depth>2 ? params.depth-2 : 0; + if( params.kernelDepth>params.depth ) + { + if( params.kernelDepth!=-1 ) WARN( "Kernel depth cannot exceed system depth: " , params.kernelDepth , " <= " , params.depth ); + params.kernelDepth = params.depth; + } + if( params.envelopeDepth==-1 ) params.envelopeDepth = params.baseDepth; + if( params.envelopeDepth>params.depth ) + { + if( params.envelopeDepth!=-1 ) WARN( "Envelope dpeth cannot exceed system depth: " , params.envelopeDepth , " <= " , params.depth ); + params.envelopeDepth = params.depth; + } + if( params.envelopeDepth= " , params.baseDepth ); + params.envelopeDepth = params.baseDepth; + } - // Transform the Hermite samples into a vector field - { - profiler.reset(); - normalInfo = new SparseNodeData< Point< Real , Dim > , NormalSigs >(); - std::function< bool ( NormalAndAuxData , Point< Real , Dim > & ) > ConversionFunction; - std::function< bool ( NormalAndAuxData , Point< Real , Dim > & , Real & ) > ConversionAndBiasFunction; if constexpr( HasAuxData ) { - ConversionFunction = []( NormalAndAuxData in , Point< Real , Dim > &out ) +#ifdef DE_VIRTUALIZE_OUTPUT + TransformedInputSampleWithDataStream< Real , Dim , AuxData , InputSampleStreamType > _pointStream( modelToUnitCube , pointStream ); +#else // !DE_VIRTUALIZE_OUTPUT + TransformedInputSampleWithDataStream< Real , Dim , AuxData > _pointStream( modelToUnitCube , pointStream ); +#endif // DE_VIRTUALIZE_OUTPUT + auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , NormalAndAuxData &d ) { - Point< Real , Dim > n = in.template get<0>(); - Real l = (Real)Length( n ); - // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... - if( !l ) return false; - out = n / l; - return true; + Real l = (Real)Length( d.template get<0>() ); + if( !l || !std::isfinite( l ) ) return (Real)-1.; + return (Real)pow( l , params.confidence ); }; - ConversionAndBiasFunction = [&]( NormalAndAuxData in , Point< Real , Dim > &out , Real &bias ) + auto ProcessData = []( const Point< Real , Dim > &p , NormalAndAuxData &d ) { - Point< Real , Dim > n = in.template get<0>(); - Real l = (Real)Length( n ); - // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... - if( !l ) return false; - out = n / l; - bias = (Real)( log( l ) * params.confidenceBias / log( 1<<(Dim-1) ) ); - return true; + Real l = (Real)Length( d.template get<0>() ); + if( !l || !std::isfinite( l ) ) return (Real)-1.; + d.template get<0>() /= l; + return (Real)1.; }; + + typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; + if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); } else { - // In this case NormalAndAuxData = Point< Real , Dim > - ConversionFunction = []( NormalAndAuxData in , Point< Real , Dim > &out ) +#ifdef DE_VIRTUALIZE_OUTPUT + TransformedInputSampleStream< Real , Dim , InputSampleStreamType > _pointStream( modelToUnitCube , pointStream ); +#else // !DE_VIRTUALIZE_OUTPUT + TransformedInputSampleStream< Real , Dim > _pointStream( modelToUnitCube , pointStream ); +#endif // DE_VIRTUALIZE_OUTPUT + auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , NormalAndAuxData &d ) { - Real l = (Real)Length( in ); - // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... - if( !l ) return false; - out = in / l; - return true; + Real l = (Real)Length( d ); + if( !l || !std::isfinite( l ) ) return (Real)-1.; + return (Real)pow( l , params.confidence ); }; - ConversionAndBiasFunction = [&]( NormalAndAuxData in , Point< Real , Dim > &out , Real &bias ) + auto ProcessData = []( const Point< Real , Dim > &p , NormalAndAuxData &d ) { - Real l = (Real)Length( in ); - // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... - if( !l ) return false; - out = in / l; - bias = (Real)( log( l ) * params.confidenceBias / log( 1<<(Dim-1) ) ); - return true; + Real l = (Real)Length( d ); + if( !l || !std::isfinite( l ) ) return (Real)-1.; + d /= l; + return (Real)1.; }; + + typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; + if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); } - if( params.confidenceBias>0 ) *normalInfo = implicit.tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , implicit.density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionAndBiasFunction ); - else *normalInfo = implicit.tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , implicit.density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionFunction ); - ThreadPool::Parallel_for( 0 , normalInfo->size() , [&]( unsigned int , size_t i ){ (*normalInfo)[i] *= (Real)-1.; } ); + + implicit.unitCubeToModel = modelToUnitCube.inverse(); + if( params.verbose ) { - std::cout << "# Got normal field: " << profiler << std::endl; - std::cout << "Point depth / Point weight / Estimated measure: " << pointDepthAndWeight.value()[0] << " / " << pointDepthAndWeight.value()[1] << " / " << pointCount*pointDepthAndWeight.value()[1] << std::endl; + std::cout << "Input Points / Samples: " << pointCount << " / " << samples->size() << std::endl; + std::cout << "# Read input into tree: " << profiler << std::endl; } } - // Get the geometry designators indicating if the space node are interior to, exterior to, or contain the envelope boundary - if( envelopeMesh ) + if( valueInterpolationStream && params.valueInterpolationWeight ) { - profiler.reset(); - { - // Make the octree complete up to the base depth - FEMTreeInitializer< Dim , Real >::Initialize( implicit.tree.spaceRoot() , params.baseDepth , []( int , int[] ){ return true; } , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() ); + valueInterpolationSamples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); + valueInterpolationSampleData = new std::vector< Real >(); + // Wrap the point stream in a transforming stream + TransformedValueInterpolationStream< Real , Dim > _valueInterpolationStream( modelToUnitCube , *valueInterpolationStream ); + + // Assign each sample a weight of 1. + auto ProcessData = []( const Point< Real , Dim > &p , Real &d ){ return (Real)1.; }; + Real zeroValue = (Real)0.; + typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; + size_t count = FEMTreeInitializer< Dim , Real >::template Initialize< Real >( sid , implicit.tree.spaceRoot() , _valueInterpolationStream , zeroValue , params.depth , *valueInterpolationSamples , *valueInterpolationSampleData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); + if( params.verbose ) std::cout << "Input Interpolation Points / Samples: " << count << " / " << valueInterpolationSamples->size() << std::endl; + } + + { + InterpolationInfo *valueInterpolationInfo = NULL; + DenseNodeData< Real , Sigs > constraints; + InterpolationInfo *iInfo = NULL; + int solveDepth = params.depth; + + implicit.tree.resetNodeIndices( 0 , std::make_tuple() ); - std::vector< Point< Real , Dim > > vertices( envelopeMesh->vertices.size() ); - for( unsigned int i=0 ; ivertices[i]; - geometryNodeDesignators = FEMTreeInitializer< Dim , Real >::template GetGeometryNodeDesignators( &implicit.tree.spaceRoot() , vertices , envelopeMesh->simplices , params.baseDepth , params.envelopeDepth , implicit.tree.nodeAllocators , implicit.tree.initializer() ); + // Get the kernel density estimator + { + profiler.reset(); + implicit.density = implicit.tree.template setDensityEstimator< 1 , Reconstructor::WeightDegree >( *samples , params.kernelDepth , params.samplesPerNode ); + if( params.verbose ) std::cout << "# Got kernel density: " << profiler << std::endl; + } - // Make nodes in the support of the vector field @{ExactDepth} interior - if( params.dirichletErode ) + // Transform the Hermite samples into a vector field + { + profiler.reset(); + normalInfo = new SparseNodeData< Point< Real , Dim > , NormalSigs >(); + std::function< bool ( NormalAndAuxData , Point< Real , Dim > & ) > ConversionFunction; + std::function< bool ( NormalAndAuxData , Point< Real , Dim > & , Real & ) > ConversionAndBiasFunction; + if constexpr( HasAuxData ) { - // What to do if we find a node in the support of the vector field - auto SetScratchFlag = [&]( FEMTreeNode *node ) + ConversionFunction = []( NormalAndAuxData in , Point< Real , Dim > &out ) { - if( node ) - { - while( node->depth()>(int)params.baseDepth ) node = node->parent; - node->nodeData.setScratchFlag( true ); - } + Point< Real , Dim > n = in.template get<0>(); + Real l = (Real)Length( n ); + // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... + if( !l ) return false; + out = n / l; + return true; }; - - std::function< void ( FEMTreeNode * ) > PropagateToLeaves = [&]( const FEMTreeNode *node ) + ConversionAndBiasFunction = [&]( NormalAndAuxData in , Point< Real , Dim > &out , Real &bias ) { - geometryNodeDesignators[ node ] = GeometryNodeType::INTERIOR; - if( node->children ) for( int c=0 ; c<(1<children+c ); + Point< Real , Dim > n = in.template get<0>(); + Real l = (Real)Length( n ); + // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... + if( !l ) return false; + out = n / l; + bias = (Real)( log( l ) * params.confidenceBias / log( 1<<(Dim-1) ) ); + return true; }; - - // Flags indicating if a node contains a non-zero vector field coefficient - std::vector< bool > isVectorFieldElement( implicit.tree.nodeCount() , false ); - - // Get the set of base nodes - std::vector< FEMTreeNode * > baseNodes; - auto nodeFunctor = [&]( FEMTreeNode *node ) + } + else + { + // In this case NormalAndAuxData = Point< Real , Dim > + ConversionFunction = []( NormalAndAuxData in , Point< Real , Dim > &out ) + { + Real l = (Real)Length( in ); + // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... + if( !l ) return false; + out = in / l; + return true; + }; + ConversionAndBiasFunction = [&]( NormalAndAuxData in , Point< Real , Dim > &out , Real &bias ) { - if( node->depth()==params.baseDepth ) baseNodes.push_back( node ); - return node->depth()<(int)params.baseDepth; + Real l = (Real)Length( in ); + // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... + if( !l ) return false; + out = in / l; + bias = (Real)( log( l ) * params.confidenceBias / log( 1<<(Dim-1) ) ); + return true; }; - implicit.tree.spaceRoot().processNodes( nodeFunctor ); + } + if( params.confidenceBias>0 ) *normalInfo = implicit.tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , implicit.density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionAndBiasFunction ); + else *normalInfo = implicit.tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , implicit.density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionFunction ); + ThreadPool::Parallel_for( 0 , normalInfo->size() , [&]( unsigned int , size_t i ){ (*normalInfo)[i] *= (Real)-1.; } ); + if( params.verbose ) + { + std::cout << "# Got normal field: " << profiler << std::endl; + std::cout << "Point depth / Point weight / Estimated measure: " << pointDepthAndWeight.value()[0] << " / " << pointDepthAndWeight.value()[1] << " / " << pointCount*pointDepthAndWeight.value()[1] << std::endl; + } + } + + // Get the geometry designators indicating if the space node are interior to, exterior to, or contain the envelope boundary + if( envelopeMesh ) + { + profiler.reset(); + { + // Make the octree complete up to the base depth + FEMTreeInitializer< Dim , Real >::Initialize( implicit.tree.spaceRoot() , params.baseDepth , []( int , int[] ){ return true; } , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() ); - std::vector< node_index_type > vectorFieldElementCounts( baseNodes.size() ); - for( int i=0 ; i > vertices( envelopeMesh->vertices.size() ); + for( unsigned int i=0 ; ivertices[i]; + geometryNodeDesignators = FEMTreeInitializer< Dim , Real >::template GetGeometryNodeDesignators( &implicit.tree.spaceRoot() , vertices , envelopeMesh->simplices , params.baseDepth , params.envelopeDepth , implicit.tree.nodeAllocators , implicit.tree.initializer() ); - // In parallel, iterate over the base nodes and mark the nodes containing non-zero vector field coefficients - ThreadPool::Parallel_for( 0 , baseNodes.size() , [&]( unsigned int t , size_t i ) - { - auto nodeFunctor = [&]( FEMTreeNode *node ) - { - Point< Real , Dim > *n = (*normalInfo)( node ); - if( n && Point< Real , Dim >::SquareNorm( *n ) ) isVectorFieldElement[ node->nodeData.nodeIndex ] = true , vectorFieldElementCounts[i]++; - }; - baseNodes[i]->processNodes( nodeFunctor ); - } ); - size_t vectorFieldElementCount = 0; - for( int i=0 ; i vectorFieldElements; - vectorFieldElements.reserve( vectorFieldElementCount ); + // Make nodes in the support of the vector field @{ExactDepth} interior + if( params.dirichletErode ) { - std::vector< std::vector< FEMTreeNode * > > _vectorFieldElements( baseNodes.size() ); - for( int i=0 ; i<_vectorFieldElements.size() ; i++ ) _vectorFieldElements[i].reserve( vectorFieldElementCounts[i] ); + // What to do if we find a node in the support of the vector field + auto SetScratchFlag = [&]( FEMTreeNode *node ) + { + if( node ) + { + while( node->depth()>(int)params.baseDepth ) node = node->parent; + node->nodeData.setScratchFlag( true ); + } + }; + + std::function< void ( FEMTreeNode * ) > PropagateToLeaves = [&]( const FEMTreeNode *node ) + { + geometryNodeDesignators[ node ] = GeometryNodeType::INTERIOR; + if( node->children ) for( int c=0 ; c<(1<children+c ); + }; + + // Flags indicating if a node contains a non-zero vector field coefficient + std::vector< bool > isVectorFieldElement( implicit.tree.nodeCount() , false ); + + // Get the set of base nodes + std::vector< FEMTreeNode * > baseNodes; + auto nodeFunctor = [&]( FEMTreeNode *node ) + { + if( node->depth()==params.baseDepth ) baseNodes.push_back( node ); + return node->depth()<(int)params.baseDepth; + }; + implicit.tree.spaceRoot().processNodes( nodeFunctor ); + + std::vector< node_index_type > vectorFieldElementCounts( baseNodes.size() ); + for( int i=0 ; inodeData.nodeIndex ] ) _vectorFieldElements[i].push_back( node ); - node->nodeData.setScratchFlag( false ); + Point< Real , Dim > *n = (*normalInfo)( node ); + if( n && Point< Real , Dim >::SquareNorm( *n ) ) isVectorFieldElement[ node->nodeData.nodeIndex ] = true , vectorFieldElementCounts[i]++; }; baseNodes[i]->processNodes( nodeFunctor ); } ); - for( int i=0 ; i<_vectorFieldElements.size() ; i++ ) vectorFieldElements.insert( vectorFieldElements.end() , _vectorFieldElements[i].begin() , _vectorFieldElements[i].end() ); - } + size_t vectorFieldElementCount = 0; + for( int i=0 ; i vectorFieldElements; + vectorFieldElements.reserve( vectorFieldElementCount ); + { + std::vector< std::vector< FEMTreeNode * > > _vectorFieldElements( baseNodes.size() ); + for( int i=0 ; i<_vectorFieldElements.size() ; i++ ) _vectorFieldElements[i].reserve( vectorFieldElementCounts[i] ); + ThreadPool::Parallel_for( 0 , baseNodes.size() , [&]( unsigned int t , size_t i ) + { + auto nodeFunctor = [&]( FEMTreeNode *node ) + { + if( isVectorFieldElement[ node->nodeData.nodeIndex ] ) _vectorFieldElements[i].push_back( node ); + node->nodeData.setScratchFlag( false ); + }; + baseNodes[i]->processNodes( nodeFunctor ); + } ); + for( int i=0 ; i<_vectorFieldElements.size() ; i++ ) vectorFieldElements.insert( vectorFieldElements.end() , _vectorFieldElements[i].begin() , _vectorFieldElements[i].end() ); + } + + // Set the scratch flag for the base nodes on which the vector field is supported #ifdef SHOW_WARNINGS #pragma message( "[WARNING] In principal, we should unlock finite elements whose support overlaps the vector field" ) #endif // SHOW_WARNINGS - implicit.tree.template processNeighboringLeaves< -BSplineSupportSizes< Poisson::NormalDegree >::SupportStart , BSplineSupportSizes< Poisson::NormalDegree >::SupportEnd >( &vectorFieldElements[0] , vectorFieldElements.size() , SetScratchFlag , false ); + implicit.tree.template processNeighboringLeaves< -BSplineSupportSizes< Poisson::NormalDegree >::SupportStart , BSplineSupportSizes< Poisson::NormalDegree >::SupportEnd >( &vectorFieldElements[0] , vectorFieldElements.size() , SetScratchFlag , false ); - // Set sub-trees rooted at interior nodes @ ExactDepth to interior - ThreadPool::Parallel_for( 0 , baseNodes.size() , [&]( unsigned int , size_t i ){ if( baseNodes[i]->nodeData.getScratchFlag() ) PropagateToLeaves( baseNodes[i] ); } ); + // Set sub-trees rooted at interior nodes @ ExactDepth to interior + ThreadPool::Parallel_for( 0 , baseNodes.size() , [&]( unsigned int , size_t i ){ if( baseNodes[i]->nodeData.getScratchFlag() ) PropagateToLeaves( baseNodes[i] ); } ); - // Adjust the coarser node designators in case exterior nodes have become boundary. - ThreadPool::Parallel_for( 0 , baseNodes.size() , [&]( unsigned int , size_t i ){ FEMTreeInitializer< Dim , Real >::PullGeometryNodeDesignatorsFromFiner( baseNodes[i] , geometryNodeDesignators ); } ); - FEMTreeInitializer< Dim , Real >::PullGeometryNodeDesignatorsFromFiner( &implicit.tree.spaceRoot() , geometryNodeDesignators , params.baseDepth ); + // Adjust the coarser node designators in case exterior nodes have become boundary. + ThreadPool::Parallel_for( 0 , baseNodes.size() , [&]( unsigned int , size_t i ){ FEMTreeInitializer< Dim , Real >::PullGeometryNodeDesignatorsFromFiner( baseNodes[i] , geometryNodeDesignators ); } ); + FEMTreeInitializer< Dim , Real >::PullGeometryNodeDesignatorsFromFiner( &implicit.tree.spaceRoot() , geometryNodeDesignators , params.baseDepth ); + } } + if( params.verbose ) std::cout << "# Initialized envelope constraints: " << profiler << std::endl; } - if( params.verbose ) std::cout << "# Initialized envelope constraints: " << profiler << std::endl; - } - - if( !params.outputDensity ){ delete implicit.density ; implicit.density = NULL; } - if constexpr( HasAuxData ) implicit.auxData = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( implicit.tree.template setExtrapolatedDataField< DataSig , false , Reconstructor::WeightDegree , AuxData >( samples->size() , [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return (*samples)[i]; } , [&]( size_t i ) -> const AuxData & { return (*sampleNormalAndAuxData)[i].template get<1>(); } , (DensityEstimator*)NULL ) ); - delete sampleNormalAndAuxData; - // Add the interpolation constraints - if( params.pointWeight>0 ) - { - profiler.reset(); - if( params.exactInterpolation ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointInterpolationInfo< Real , 0 > ( implicit.tree , *samples , Poisson::ConstraintDual< Dim , Real >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] ) , Poisson::SystemDual< Dim , Real >( params.pointWeight * pointDepthAndWeight.value()[1] ) , true , false ); - else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointInterpolationInfo< Real , 0 > ( implicit.tree , *samples , Poisson::ConstraintDual< Dim , Real >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] ) , Poisson::SystemDual< Dim , Real >( params.pointWeight * pointDepthAndWeight.value()[1] ) , true , params.depth , 1 ); - if( params.verbose ) std::cout << "#Initialized point interpolation constraints: " << profiler << std::endl; - } + if( !params.outputDensity ){ delete implicit.density ; implicit.density = NULL; } + if constexpr( HasAuxData ) implicit.auxData = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( implicit.tree.template setExtrapolatedDataField< DataSig , false , Reconstructor::WeightDegree , AuxData >( samples->size() , [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return (*samples)[i]; } , [&]( size_t i ) -> const AuxData & { return (*sampleNormalAndAuxData)[i].template get<1>(); } , (DensityEstimator*)NULL ) ); + delete sampleNormalAndAuxData; - // Trim the tree and prepare for multigrid - { - profiler.reset(); - constexpr int MaxDegree = Poisson::NormalDegree > Degrees::Max() ? Poisson::NormalDegree : Degrees::Max(); - typename FEMTree< Dim , Real >::template HasNormalDataFunctor< NormalSigs > hasNormalDataFunctor( *normalInfo ); - auto hasDataFunctor = [&]( const FEMTreeNode *node ){ return hasNormalDataFunctor( node ); }; - auto addNodeFunctor = [&]( int d , const int off[Dim] ){ return d<=(int)params.fullDepth; }; - if constexpr( HasAuxData ) - { - if( geometryNodeDesignators.size() ) implicit.tree.template finalizeForMultigridWithDirichlet< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , [&]( const FEMTreeNode *node ){ return node->nodeData.nodeIndex<(node_index_type)geometryNodeDesignators.size() && geometryNodeDesignators[node]==GeometryNodeType::EXTERIOR; } , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density , implicit.auxData , &geometryNodeDesignators ) ); - else implicit.tree.template finalizeForMultigrid < MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density , implicit.auxData ) ); - } - else + // Add the interpolation constraints + if( params.pointWeight>0 ) { - if( geometryNodeDesignators.size() ) implicit.tree.template finalizeForMultigridWithDirichlet< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , [&]( const FEMTreeNode *node ){ return node->nodeData.nodeIndex<(node_index_type)geometryNodeDesignators.size() && geometryNodeDesignators[node]==GeometryNodeType::EXTERIOR; } , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density , &geometryNodeDesignators ) ); - else implicit.tree.template finalizeForMultigrid < MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density ) ); + profiler.reset(); + if( params.exactInterpolation ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointInterpolationInfo< Real , 0 > ( implicit.tree , *samples , Poisson::ConstraintDual< Dim , Real >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] ) , Poisson::SystemDual< Dim , Real >( params.pointWeight * pointDepthAndWeight.value()[1] ) , true , false ); + else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointInterpolationInfo< Real , 0 > ( implicit.tree , *samples , Poisson::ConstraintDual< Dim , Real >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] ) , Poisson::SystemDual< Dim , Real >( params.pointWeight * pointDepthAndWeight.value()[1] ) , true , params.depth , 1 ); + if( params.verbose ) std::cout << "#Initialized point interpolation constraints: " << profiler << std::endl; } - if( params.verbose ) std::cout << "# Finalized tree: " << profiler << std::endl; - } + // Trim the tree and prepare for multigrid + { + profiler.reset(); + constexpr int MaxDegree = Poisson::NormalDegree > Degrees::Max() ? Poisson::NormalDegree : Degrees::Max(); + typename FEMTree< Dim , Real >::template HasNormalDataFunctor< NormalSigs > hasNormalDataFunctor( *normalInfo ); + auto hasDataFunctor = [&]( const FEMTreeNode *node ){ return hasNormalDataFunctor( node ); }; + auto addNodeFunctor = [&]( int d , const int off[Dim] ){ return d<=(int)params.fullDepth; }; + if constexpr( HasAuxData ) + { + if( geometryNodeDesignators.size() ) implicit.tree.template finalizeForMultigridWithDirichlet< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , [&]( const FEMTreeNode *node ){ return node->nodeData.nodeIndex<(node_index_type)geometryNodeDesignators.size() && geometryNodeDesignators[node]==GeometryNodeType::EXTERIOR; } , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density , implicit.auxData , &geometryNodeDesignators ) ); + else implicit.tree.template finalizeForMultigrid < MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density , implicit.auxData ) ); + } + else + { + if( geometryNodeDesignators.size() ) implicit.tree.template finalizeForMultigridWithDirichlet< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , [&]( const FEMTreeNode *node ){ return node->nodeData.nodeIndex<(node_index_type)geometryNodeDesignators.size() && geometryNodeDesignators[node]==GeometryNodeType::EXTERIOR; } , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density , &geometryNodeDesignators ) ); + else implicit.tree.template finalizeForMultigrid < MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density ) ); + } - // Add the FEM constraints - { - profiler.reset(); - constraints = implicit.tree.initDenseNodeData( Sigs() ); + if( params.verbose ) std::cout << "# Finalized tree: " << profiler << std::endl; + } - // Add Poisson constraints + // Add the FEM constraints { - typename FEMIntegrator::template Constraint< Sigs , IsotropicUIntPack< Dim , 1 > , NormalSigs , IsotropicUIntPack< Dim , 0 > , Dim > F; - unsigned int derivatives2[Dim]; - for( int d=0 ; d Derivatives1; - typedef IsotropicUIntPack< Dim , 0 > Derivatives2; - for( int d=0 ; d::Index( derivatives1 ) ][ TensorDerivatives< Derivatives2 >::Index( derivatives2 ) ] = 1; + typename FEMIntegrator::template Constraint< Sigs , IsotropicUIntPack< Dim , 1 > , NormalSigs , IsotropicUIntPack< Dim , 0 > , Dim > F; + unsigned int derivatives2[Dim]; + for( int d=0 ; d Derivatives1; + typedef IsotropicUIntPack< Dim , 0 > Derivatives2; + for( int d=0 ; d::Index( derivatives1 ) ][ TensorDerivatives< Derivatives2 >::Index( derivatives2 ) ] = 1; + } + implicit.tree.addFEMConstraints( F , *normalInfo , constraints , solveDepth ); } - implicit.tree.addFEMConstraints( F , *normalInfo , constraints , solveDepth ); + if( params.verbose ) std::cout << "# Set FEM constraints: " << profiler << std::endl; } - if( params.verbose ) std::cout << "# Set FEM constraints: " << profiler << std::endl; - } - // Free up the normal info - delete normalInfo , normalInfo = NULL; + // Free up the normal info + delete normalInfo , normalInfo = NULL; - if( params.pointWeight>0 ) - { - profiler.reset(); - implicit.tree.addInterpolationConstraints( constraints , solveDepth , std::make_tuple( iInfo ) ); - if( params.verbose ) std::cout << "#Set point constraints: " << profiler << std::endl; - } + if( params.pointWeight>0 ) + { + profiler.reset(); + implicit.tree.addInterpolationConstraints( constraints , solveDepth , std::make_tuple( iInfo ) ); + if( params.verbose ) std::cout << "#Set point constraints: " << profiler << std::endl; + } - if( valueInterpolationSamples && params.valueInterpolationWeight ) - { - profiler.reset(); - if( params.exactInterpolation ) valueInterpolationInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , Real , 0 > ( implicit.tree , *valueInterpolationSamples , GetPointer( *valueInterpolationSampleData ) , Poisson::ValueInterpolationConstraintDual< Dim , Real >( params.valueInterpolationWeight ) , Poisson::ValueInterpolationSystemDual< Dim , Real >( params.valueInterpolationWeight ) , true , false ); - else valueInterpolationInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , Real , 0 > ( implicit.tree , *valueInterpolationSamples , GetPointer( *valueInterpolationSampleData ) , Poisson::ValueInterpolationConstraintDual< Dim , Real >( params.valueInterpolationWeight ) , Poisson::ValueInterpolationSystemDual< Dim , Real >( params.valueInterpolationWeight ) , true , params.depth , 1 ); - delete valueInterpolationSamples , valueInterpolationSamples = NULL; - delete valueInterpolationSampleData , valueInterpolationSampleData = NULL; + if( valueInterpolationSamples && params.valueInterpolationWeight ) + { + profiler.reset(); + if( params.exactInterpolation ) valueInterpolationInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , Real , 0 > ( implicit.tree , *valueInterpolationSamples , GetPointer( *valueInterpolationSampleData ) , Poisson::ValueInterpolationConstraintDual< Dim , Real >( params.valueInterpolationWeight ) , Poisson::ValueInterpolationSystemDual< Dim , Real >( params.valueInterpolationWeight ) , true , false ); + else valueInterpolationInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , Real , 0 > ( implicit.tree , *valueInterpolationSamples , GetPointer( *valueInterpolationSampleData ) , Poisson::ValueInterpolationConstraintDual< Dim , Real >( params.valueInterpolationWeight ) , Poisson::ValueInterpolationSystemDual< Dim , Real >( params.valueInterpolationWeight ) , true , params.depth , 1 ); + delete valueInterpolationSamples , valueInterpolationSamples = NULL; + delete valueInterpolationSampleData , valueInterpolationSampleData = NULL; - implicit.tree.addInterpolationConstraints( constraints , solveDepth , std::make_tuple( valueInterpolationInfo ) ); - if( params.verbose ) std::cout << "#Set value interpolation constraints: " << profiler << std::endl; - } + implicit.tree.addInterpolationConstraints( constraints , solveDepth , std::make_tuple( valueInterpolationInfo ) ); + if( params.verbose ) std::cout << "#Set value interpolation constraints: " << profiler << std::endl; + } - if( params.verbose ) std::cout << "All Nodes / Active Nodes / Ghost Nodes / Dirichlet Supported Nodes: " << implicit.tree.allNodes() << " / " << implicit.tree.activeNodes() << " / " << implicit.tree.ghostNodes() << " / " << implicit.tree.dirichletElements() << std::endl; - if( params.verbose ) std::cout << "Memory Usage: " << float( MemoryInfo::Usage())/(1<<20) << " MB" << std::endl; + if( params.verbose ) std::cout << "All Nodes / Active Nodes / Ghost Nodes / Dirichlet Supported Nodes: " << implicit.tree.allNodes() << " / " << implicit.tree.activeNodes() << " / " << implicit.tree.ghostNodes() << " / " << implicit.tree.dirichletElements() << std::endl; + if( params.verbose ) std::cout << "Memory Usage: " << float( MemoryInfo::Usage())/(1<<20) << " MB" << std::endl; - // Solve the linear system - { - profiler.reset(); - typename FEMTree< Dim , Real >::SolverInfo _sInfo; - _sInfo.cgDepth = 0 , _sInfo.cascadic = true , _sInfo.vCycles = 1 , _sInfo.iters = params.iters , _sInfo.cgAccuracy = params.cgSolverAccuracy , _sInfo.verbose = params.verbose , _sInfo.showResidual = params.showResidual , _sInfo.showGlobalResidual = SHOW_GLOBAL_RESIDUAL_NONE , _sInfo.sliceBlockSize = 1; - _sInfo.baseVCycles = params.baseVCycles; - typename FEMIntegrator::template System< Sigs , IsotropicUIntPack< Dim , 1 > > F( { 0. , 1. } ); - if( valueInterpolationInfo ) implicit.solution = implicit.tree.solveSystem( Sigs() , F , constraints , params.baseDepth , params.solveDepth , _sInfo , std::make_tuple( iInfo , valueInterpolationInfo ) ); - else implicit.solution = implicit.tree.solveSystem( Sigs() , F , constraints , params.baseDepth , params.solveDepth , _sInfo , std::make_tuple( iInfo ) ); - if( params.verbose ) std::cout << "# Linear system solved: " << profiler << std::endl; - if( iInfo ) delete iInfo , iInfo = NULL; - if( valueInterpolationInfo ) delete valueInterpolationInfo , valueInterpolationInfo = NULL; + // Solve the linear system + { + profiler.reset(); + typename FEMTree< Dim , Real >::SolverInfo _sInfo; + _sInfo.cgDepth = 0 , _sInfo.cascadic = true , _sInfo.vCycles = 1 , _sInfo.iters = params.iters , _sInfo.cgAccuracy = params.cgSolverAccuracy , _sInfo.verbose = params.verbose , _sInfo.showResidual = params.showResidual , _sInfo.showGlobalResidual = SHOW_GLOBAL_RESIDUAL_NONE , _sInfo.sliceBlockSize = 1; + _sInfo.baseVCycles = params.baseVCycles; + typename FEMIntegrator::template System< Sigs , IsotropicUIntPack< Dim , 1 > > F( { 0. , 1. } ); + if( valueInterpolationInfo ) implicit.solution = implicit.tree.solveSystem( Sigs() , F , constraints , params.baseDepth , params.solveDepth , _sInfo , std::make_tuple( iInfo , valueInterpolationInfo ) ); + else implicit.solution = implicit.tree.solveSystem( Sigs() , F , constraints , params.baseDepth , params.solveDepth , _sInfo , std::make_tuple( iInfo ) ); + if( params.verbose ) std::cout << "# Linear system solved: " << profiler << std::endl; + if( iInfo ) delete iInfo , iInfo = NULL; + if( valueInterpolationInfo ) delete valueInterpolationInfo , valueInterpolationInfo = NULL; + } } - } - // Get the iso-value - { - profiler.reset(); - double valueSum = 0 , weightSum = 0; - typename FEMTree< Dim , Real >::template MultiThreadedEvaluator< Sigs , 0 > evaluator( &implicit.tree , implicit.solution ); - std::vector< double > valueSums( ThreadPool::NumThreads() , 0 ) , weightSums( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , samples->size() , [&]( unsigned int thread , size_t j ) - { - ProjectiveData< Point< Real , Dim > , Real >& sample = (*samples)[j].sample; - Real w = sample.weight; - if( w>0 ) weightSums[thread] += w , valueSums[thread] += evaluator.values( sample.data / sample.weight , thread , (*samples)[j].node )[0] * w; - } ); - for( size_t t=0 ; t::template MultiThreadedEvaluator< Sigs , 0 > evaluator( &implicit.tree , implicit.solution ); + std::vector< double > valueSums( ThreadPool::NumThreads() , 0 ) , weightSums( ThreadPool::NumThreads() , 0 ); + ThreadPool::Parallel_for( 0 , samples->size() , [&]( unsigned int thread , size_t j ) + { + ProjectiveData< Point< Real , Dim > , Real >& sample = (*samples)[j].sample; + Real w = sample.weight; + if( w>0 ) weightSums[thread] += w , valueSums[thread] += evaluator.values( sample.data / sample.weight , thread , (*samples)[j].node )[0] * w; + } ); + for( size_t t=0 ; t - void SSD::_Solve( UIntPack< FEMSigs ... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params ) - { - static_assert( std::is_same< IsotropicUIntPack< Dim , FEMSig > , UIntPack< FEMSigs... > >::value , "[ERROR] Signatures don't match" ); - - // The signature for the finite-elements representing the auxiliary data (if it's there) - static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; - - /////////////// - // Types --> // - // The packed finite elements signature - typedef UIntPack< FEMSigs ... > Sigs; - - // The degrees of the finite elements across the different axes - typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > Degrees; - // The signature describing the normals elements - typedef UIntPack< FEMDegreeAndBType< SSD::NormalDegree , DerivativeBoundary< FEMSignature< FEMSigs >::BType , 1 >::BType >::Signature ... > NormalSigs; - - // Type for tracking sample interpolation - typedef typename FEMTree< Dim , Real >::template InterpolationInfo< Real , 1 > InterpolationInfo; + template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > + void SSD::_Solve( UIntPack< FEMSigs ... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params ) + { + static_assert( std::is_same< IsotropicUIntPack< Dim , FEMSig > , UIntPack< FEMSigs... > >::value , "[ERROR] Signatures don't match" ); - // The finite-element tracking tree node - typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; + // The signature for the finite-elements representing the auxiliary data (if it's there) + static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; - // The type of the auxiliary information (including the normal) - typedef typename std::conditional< HasAuxData , VectorTypeUnion< Real , Normal< Real , Dim > , AuxData > , Normal< Real , Dim > >::type NormalAndAuxData; + /////////////// + // Types --> // + // The packed finite elements signature + typedef UIntPack< FEMSigs ... > Sigs; - // The type describing the sampling density - typedef typename std::conditional< HasAuxData , Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type::DensityEstimator DensityEstimator; - // <-- Types // - /////////////// + // The degrees of the finite elements across the different axes + typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > Degrees; - NormalAndAuxData zeroNormalAndAuxData; - if constexpr( HasAuxData ) zeroNormalAndAuxData = NormalAndAuxData( Normal< Real , Dim >() , implicit.zeroAuxData ); + // The signature describing the normals elements + typedef UIntPack< FEMDegreeAndBType< SSD::NormalDegree , DerivativeBoundary< FEMSignature< FEMSigs >::BType , 1 >::BType >::Signature ... > NormalSigs; - XForm< Real , Dim+1 > modelToUnitCube = XForm< Real , Dim+1 >::Identity(); + // Type for tracking sample interpolation + typedef typename FEMTree< Dim , Real >::template InterpolationInfo< Real , 1 > InterpolationInfo; - Profiler profiler(20); + // The finite-element tracking tree node + typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; - size_t pointCount; + // The type of the auxiliary information (including the normal) + typedef typename std::conditional< HasAuxData , VectorTypeUnion< Real , Normal< Real , Dim > , AuxData > , Normal< Real , Dim > >::type NormalAndAuxData; - ProjectiveData< Point< Real , 2 > , Real > pointDepthAndWeight; - SparseNodeData< Point< Real , Dim > , NormalSigs > *normalInfo = NULL; - std::vector< typename FEMTree< Dim , Real >::PointSample > *samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); - std::vector< NormalAndAuxData > *sampleNormalAndAuxData = NULL; + // The type describing the sampling density + typedef typename std::conditional< HasAuxData , Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type::DensityEstimator DensityEstimator; + // <-- Types // + /////////////// - Real targetValue = (Real)0.0; + NormalAndAuxData zeroNormalAndAuxData; + if constexpr( HasAuxData ) zeroNormalAndAuxData = NormalAndAuxData( Normal< Real , Dim >() , implicit.zeroAuxData ); - // Read in the samples (and auxiliary data) - { - profiler.reset(); + XForm< Real , Dim+1 > modelToUnitCube = XForm< Real , Dim+1 >::Identity(); - pointStream.reset(); - sampleNormalAndAuxData = new std::vector< NormalAndAuxData >(); + Profiler profiler(20); - modelToUnitCube = params.scale>0 ? GetPointXForm< Real , Dim , true >( pointStream , zeroNormalAndAuxData , params.scale , params.alignDir ) * modelToUnitCube : modelToUnitCube; + size_t pointCount; - if( params.width>0 ) - { - // Assuming the transformation is rigid so that the (max) scale can be pulled from the Frobenius norm - Real maxScale = 0; - for( unsigned int i=0 ; i( 0. , log( maxScale/params.width )/log(2.) ) ); - } - if( params.solveDepth>params.depth ) - { - if( params.solveDepth!=-1 ) WARN( "Solution depth cannot exceed system depth: " , params.solveDepth , " <= " , params.depth ); - params.solveDepth = params.depth; - } - if( params.fullDepth>params.solveDepth ) - { - if( params.fullDepth!=-1 ) WARN( "Full depth cannot exceed system depth: " , params.fullDepth , " <= " , params.solveDepth ); - params.fullDepth = params.solveDepth; - } - if( params.baseDepth>params.fullDepth ) - { - if( params.baseDepth!=-1 ) WARN( "Base depth must be smaller than full depth: " , params.baseDepth , " <= " , params.fullDepth ); - params.baseDepth = params.fullDepth; - } - if( params.kernelDepth==-1 ) params.kernelDepth = params.depth>2 ? params.depth-2 : 0; - if( params.kernelDepth>params.depth ) - { - if( params.kernelDepth!=-1 ) WARN( "Kernel depth cannot exceed system depth: " , params.kernelDepth , " <= " , params.depth ); - params.kernelDepth = params.depth; - } + ProjectiveData< Point< Real , 2 > , Real > pointDepthAndWeight; + SparseNodeData< Point< Real , Dim > , NormalSigs > *normalInfo = NULL; + std::vector< typename FEMTree< Dim , Real >::PointSample > *samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); + std::vector< NormalAndAuxData > *sampleNormalAndAuxData = NULL; - if constexpr( HasAuxData ) - { -#ifdef DE_VIRTUALIZE_OUTPUT - TransformedInputSampleWithDataStream< Real , Dim , AuxData , InputSampleStreamType > _pointStream( modelToUnitCube , pointStream ); -#else // !DE_VIRTUALIZE_OUTPUT - TransformedInputSampleWithDataStream< Real , Dim , AuxData > _pointStream( modelToUnitCube , pointStream ); -#endif // DE_VIRTUALIZE_OUTPUT - auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , NormalAndAuxData &d ) - { - Real l = (Real)Length( d.template get<0>() ); - if( !l || !std::isfinite( l ) ) return (Real)-1.; - return (Real)pow( l , params.confidence ); - }; - auto ProcessData = []( const Point< Real , Dim > &p , NormalAndAuxData &d ) - { - Real l = (Real)Length( d.template get<0>() ); - if( !l || !std::isfinite( l ) ) return (Real)-1.; - d.template get<0>() /= l; - return (Real)1.; - }; + Real targetValue = (Real)0.0; - typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; - if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); - } - else + // Read in the samples (and auxiliary data) { -#ifdef DE_VIRTUALIZE_OUTPUT - TransformedInputSampleStream< Real , Dim , InputSampleStreamType > _pointStream( modelToUnitCube , pointStream ); -#else // !DE_VIRTUALIZE_OUTPUT - TransformedInputSampleStream< Real , Dim > _pointStream( modelToUnitCube , pointStream ); -#endif // DE_VIRTUALIZE_OUTPUT - auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , NormalAndAuxData &d ) - { - Real l = (Real)Length( d ); - if( !l || !std::isfinite( l ) ) return (Real)-1.; - return (Real)pow( l , params.confidence ); - }; - auto ProcessData = []( const Point< Real , Dim > &p , NormalAndAuxData &d ) - { - Real l = (Real)Length( d ); - if( !l || !std::isfinite( l ) ) return (Real)-1.; - d /= l; - return (Real)1.; - }; - - typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; - if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); - } - - implicit.unitCubeToModel = modelToUnitCube.inverse(); + profiler.reset(); - if( params.verbose ) - { - std::cout << "Input Points / Samples: " << pointCount << " / " << samples->size() << std::endl; - std::cout << "# Read input into tree: " << profiler << std::endl; - } - } - { - DenseNodeData< Real , Sigs > constraints; - InterpolationInfo *iInfo = NULL; - int solveDepth = params.depth; + pointStream.reset(); + sampleNormalAndAuxData = new std::vector< NormalAndAuxData >(); - implicit.tree.resetNodeIndices( 0 , std::make_tuple() ); + modelToUnitCube = params.scale>0 ? GetPointXForm< Real , Dim , true >( pointStream , zeroNormalAndAuxData , params.scale , params.alignDir ) * modelToUnitCube : modelToUnitCube; - // Get the kernel density estimator - { - profiler.reset(); - implicit.density = implicit.tree.template setDensityEstimator< 1 , Reconstructor::WeightDegree >( *samples , params.kernelDepth , params.samplesPerNode ); - if( params.verbose ) std::cout << "# Got kernel density: " << profiler << std::endl; - } + if( params.width>0 ) + { + // Assuming the transformation is rigid so that the (max) scale can be pulled from the Frobenius norm + Real maxScale = 0; + for( unsigned int i=0 ; i( 0. , log( maxScale/params.width )/log(2.) ) ); + } + if( params.solveDepth>params.depth ) + { + if( params.solveDepth!=-1 ) WARN( "Solution depth cannot exceed system depth: " , params.solveDepth , " <= " , params.depth ); + params.solveDepth = params.depth; + } + if( params.fullDepth>params.solveDepth ) + { + if( params.fullDepth!=-1 ) WARN( "Full depth cannot exceed system depth: " , params.fullDepth , " <= " , params.solveDepth ); + params.fullDepth = params.solveDepth; + } + if( params.baseDepth>params.fullDepth ) + { + if( params.baseDepth!=-1 ) WARN( "Base depth must be smaller than full depth: " , params.baseDepth , " <= " , params.fullDepth ); + params.baseDepth = params.fullDepth; + } + if( params.kernelDepth==-1 ) params.kernelDepth = params.depth>2 ? params.depth-2 : 0; + if( params.kernelDepth>params.depth ) + { + if( params.kernelDepth!=-1 ) WARN( "Kernel depth cannot exceed system depth: " , params.kernelDepth , " <= " , params.depth ); + params.kernelDepth = params.depth; + } - // Transform the Hermite samples into a vector field - { - profiler.reset(); - normalInfo = new SparseNodeData< Point< Real , Dim > , NormalSigs >(); - std::function< bool ( NormalAndAuxData , Point< Real , Dim > & ) > ConversionFunction; - std::function< bool ( NormalAndAuxData , Point< Real , Dim > & , Real & ) > ConversionAndBiasFunction; if constexpr( HasAuxData ) { - ConversionFunction = []( NormalAndAuxData in , Point< Real , Dim > &out ) +#ifdef DE_VIRTUALIZE_OUTPUT + TransformedInputSampleWithDataStream< Real , Dim , AuxData , InputSampleStreamType > _pointStream( modelToUnitCube , pointStream ); +#else // !DE_VIRTUALIZE_OUTPUT + TransformedInputSampleWithDataStream< Real , Dim , AuxData > _pointStream( modelToUnitCube , pointStream ); +#endif // DE_VIRTUALIZE_OUTPUT + auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , NormalAndAuxData &d ) { - Point< Real , Dim > n = in.template get<0>(); - Real l = (Real)Length( n ); - // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... - if( !l ) return false; - out = n / l; - return true; + Real l = (Real)Length( d.template get<0>() ); + if( !l || !std::isfinite( l ) ) return (Real)-1.; + return (Real)pow( l , params.confidence ); }; - ConversionAndBiasFunction = [&]( NormalAndAuxData in , Point< Real , Dim > &out , Real &bias ) + auto ProcessData = []( const Point< Real , Dim > &p , NormalAndAuxData &d ) { - Point< Real , Dim > n = in.template get<0>(); - Real l = (Real)Length( n ); - // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... - if( !l ) return false; - out = n / l; - bias = (Real)( log( l ) * params.confidenceBias / log( 1<<(Dim-1) ) ); - return true; + Real l = (Real)Length( d.template get<0>() ); + if( !l || !std::isfinite( l ) ) return (Real)-1.; + d.template get<0>() /= l; + return (Real)1.; }; + + typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; + if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); } else { - // In this case NormalAndAuxData = Point< Real , Dim > - ConversionFunction = []( NormalAndAuxData in , Point< Real , Dim > &out ) +#ifdef DE_VIRTUALIZE_OUTPUT + TransformedInputSampleStream< Real , Dim , InputSampleStreamType > _pointStream( modelToUnitCube , pointStream ); +#else // !DE_VIRTUALIZE_OUTPUT + TransformedInputSampleStream< Real , Dim > _pointStream( modelToUnitCube , pointStream ); +#endif // DE_VIRTUALIZE_OUTPUT + auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , NormalAndAuxData &d ) { - Real l = (Real)Length( in ); - // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... - if( !l ) return false; - out = in / l; - return true; + Real l = (Real)Length( d ); + if( !l || !std::isfinite( l ) ) return (Real)-1.; + return (Real)pow( l , params.confidence ); }; - ConversionAndBiasFunction = [&]( NormalAndAuxData in , Point< Real , Dim > &out , Real &bias ) + auto ProcessData = []( const Point< Real , Dim > &p , NormalAndAuxData &d ) { - Real l = (Real)Length( in ); - // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... - if( !l ) return false; - out = in / l; - bias = (Real)( log( l ) * params.confidenceBias / log( 1<<(Dim-1) ) ); - return true; + Real l = (Real)Length( d ); + if( !l || !std::isfinite( l ) ) return (Real)-1.; + d /= l; + return (Real)1.; }; + + typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; + if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); } - if( params.confidenceBias>0 ) *normalInfo = implicit.tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , implicit.density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionAndBiasFunction ); - else *normalInfo = implicit.tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , implicit.density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionFunction ); + + implicit.unitCubeToModel = modelToUnitCube.inverse(); + if( params.verbose ) { - std::cout << "# Got normal field: " << profiler << std::endl; - std::cout << "Point depth / Point weight / Estimated measure: " << pointDepthAndWeight.value()[0] << " / " << pointDepthAndWeight.value()[1] << " / " << pointCount*pointDepthAndWeight.value()[1] << std::endl; + std::cout << "Input Points / Samples: " << pointCount << " / " << samples->size() << std::endl; + std::cout << "# Read input into tree: " << profiler << std::endl; } } + { + DenseNodeData< Real , Sigs > constraints; + InterpolationInfo *iInfo = NULL; + int solveDepth = params.depth; + + implicit.tree.resetNodeIndices( 0 , std::make_tuple() ); + + // Get the kernel density estimator + { + profiler.reset(); + implicit.density = implicit.tree.template setDensityEstimator< 1 , Reconstructor::WeightDegree >( *samples , params.kernelDepth , params.samplesPerNode ); + if( params.verbose ) std::cout << "# Got kernel density: " << profiler << std::endl; + } + + // Transform the Hermite samples into a vector field + { + profiler.reset(); + normalInfo = new SparseNodeData< Point< Real , Dim > , NormalSigs >(); + std::function< bool ( NormalAndAuxData , Point< Real , Dim > & ) > ConversionFunction; + std::function< bool ( NormalAndAuxData , Point< Real , Dim > & , Real & ) > ConversionAndBiasFunction; + if constexpr( HasAuxData ) + { + ConversionFunction = []( NormalAndAuxData in , Point< Real , Dim > &out ) + { + Point< Real , Dim > n = in.template get<0>(); + Real l = (Real)Length( n ); + // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... + if( !l ) return false; + out = n / l; + return true; + }; + ConversionAndBiasFunction = [&]( NormalAndAuxData in , Point< Real , Dim > &out , Real &bias ) + { + Point< Real , Dim > n = in.template get<0>(); + Real l = (Real)Length( n ); + // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... + if( !l ) return false; + out = n / l; + bias = (Real)( log( l ) * params.confidenceBias / log( 1<<(Dim-1) ) ); + return true; + }; + } + else + { + // In this case NormalAndAuxData = Point< Real , Dim > + ConversionFunction = []( NormalAndAuxData in , Point< Real , Dim > &out ) + { + Real l = (Real)Length( in ); + // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... + if( !l ) return false; + out = in / l; + return true; + }; + ConversionAndBiasFunction = [&]( NormalAndAuxData in , Point< Real , Dim > &out , Real &bias ) + { + Real l = (Real)Length( in ); + // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... + if( !l ) return false; + out = in / l; + bias = (Real)( log( l ) * params.confidenceBias / log( 1<<(Dim-1) ) ); + return true; + }; + } + if( params.confidenceBias>0 ) *normalInfo = implicit.tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , implicit.density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionAndBiasFunction ); + else *normalInfo = implicit.tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , implicit.density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionFunction ); + if( params.verbose ) + { + std::cout << "# Got normal field: " << profiler << std::endl; + std::cout << "Point depth / Point weight / Estimated measure: " << pointDepthAndWeight.value()[0] << " / " << pointDepthAndWeight.value()[1] << " / " << pointCount*pointDepthAndWeight.value()[1] << std::endl; + } + } - if( !params.outputDensity ){ delete implicit.density ; implicit.density = NULL; } - if constexpr( HasAuxData ) implicit.auxData = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( implicit.tree.template setExtrapolatedDataField< DataSig , false , Reconstructor::WeightDegree , AuxData >( samples->size() , [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return (*samples)[i]; } , [&]( size_t i ) -> const AuxData & { return (*sampleNormalAndAuxData)[i].template get<1>(); } , (DensityEstimator*)NULL ) ); + if( !params.outputDensity ){ delete implicit.density ; implicit.density = NULL; } + if constexpr( HasAuxData ) implicit.auxData = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( implicit.tree.template setExtrapolatedDataField< DataSig , false , Reconstructor::WeightDegree , AuxData >( samples->size() , [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return (*samples)[i]; } , [&]( size_t i ) -> const AuxData & { return (*sampleNormalAndAuxData)[i].template get<1>(); } , (DensityEstimator*)NULL ) ); // Add the interpolation constraints if( params.pointWeight>0 || params.gradientWeight>0 ) { profiler.reset(); - if constexpr( HasAuxData ) - { - if( params.exactInterpolation ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , NormalAndAuxData , 1 >( implicit.tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real , AuxData >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real , AuxData >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , false ); - else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , NormalAndAuxData , 1 >( implicit.tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real , AuxData >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real , AuxData >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , params.depth , 1 ); - } - else - { - if( params.exactInterpolation ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , Point< Real , Dim > , 1 >( implicit.tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , false ); - else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , Point< Real , Dim > , 1 >( implicit.tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , params.depth , 1 ); - } + if constexpr( HasAuxData ) + { + if( params.exactInterpolation ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , NormalAndAuxData , 1 >( implicit.tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real , AuxData >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real , AuxData >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , false ); + else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , NormalAndAuxData , 1 >( implicit.tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real , AuxData >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real , AuxData >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , params.depth , 1 ); + } + else + { + if( params.exactInterpolation ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , Point< Real , Dim > , 1 >( implicit.tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , false ); + else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , Point< Real , Dim > , 1 >( implicit.tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , params.depth , 1 ); + } if( params.verbose ) std::cout << "#Initialized point interpolation constraints: " << profiler << std::endl; } - delete sampleNormalAndAuxData; + delete sampleNormalAndAuxData; - // Trim the tree and prepare for multigrid - { - profiler.reset(); - constexpr int MaxDegree = SSD::NormalDegree > Degrees::Max() ? SSD::NormalDegree : Degrees::Max(); - typename FEMTree< Dim , Real >::template HasNormalDataFunctor< NormalSigs > hasNormalDataFunctor( *normalInfo ); - auto hasDataFunctor = [&]( const FEMTreeNode *node ){ return hasNormalDataFunctor( node ); }; - auto addNodeFunctor = [&]( int d , const int off[Dim] ){ return d<=(int)params.fullDepth; }; - if constexpr( HasAuxData ) implicit.tree.template finalizeForMultigrid< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density , implicit.auxData ) ); - else implicit.tree.template finalizeForMultigrid< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density ) ); - - if( params.verbose ) std::cout << "# Finalized tree: " << profiler << std::endl; - } + // Trim the tree and prepare for multigrid + { + profiler.reset(); + constexpr int MaxDegree = SSD::NormalDegree > Degrees::Max() ? SSD::NormalDegree : Degrees::Max(); + typename FEMTree< Dim , Real >::template HasNormalDataFunctor< NormalSigs > hasNormalDataFunctor( *normalInfo ); + auto hasDataFunctor = [&]( const FEMTreeNode *node ){ return hasNormalDataFunctor( node ); }; + auto addNodeFunctor = [&]( int d , const int off[Dim] ){ return d<=(int)params.fullDepth; }; + if constexpr( HasAuxData ) implicit.tree.template finalizeForMultigrid< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density , implicit.auxData ) ); + else implicit.tree.template finalizeForMultigrid< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density ) ); + + if( params.verbose ) std::cout << "# Finalized tree: " << profiler << std::endl; + } - // Free up the normal info - delete normalInfo , normalInfo = NULL; + // Free up the normal info + delete normalInfo , normalInfo = NULL; - if( params.pointWeight>0 || params.gradientWeight>0 ) - { - profiler.reset(); - constraints = implicit.tree.initDenseNodeData( Sigs() ); - implicit.tree.addInterpolationConstraints( constraints , solveDepth , std::make_tuple( iInfo ) ); - if( params.verbose ) std::cout << "#Set point constraints: " << profiler << std::endl; - } + if( params.pointWeight>0 || params.gradientWeight>0 ) + { + profiler.reset(); + constraints = implicit.tree.initDenseNodeData( Sigs() ); + implicit.tree.addInterpolationConstraints( constraints , solveDepth , std::make_tuple( iInfo ) ); + if( params.verbose ) std::cout << "#Set point constraints: " << profiler << std::endl; + } - if( params.verbose ) std::cout << "All Nodes / Active Nodes / Ghost Nodes: " << implicit.tree.allNodes() << " / " << implicit.tree.activeNodes() << " / " << implicit.tree.ghostNodes() << std::endl; - if( params.verbose ) std::cout << "Memory Usage: " << float( MemoryInfo::Usage())/(1<<20) << " MB" << std::endl; + if( params.verbose ) std::cout << "All Nodes / Active Nodes / Ghost Nodes: " << implicit.tree.allNodes() << " / " << implicit.tree.activeNodes() << " / " << implicit.tree.ghostNodes() << std::endl; + if( params.verbose ) std::cout << "Memory Usage: " << float( MemoryInfo::Usage())/(1<<20) << " MB" << std::endl; - // Solve the linear system - { - profiler.reset(); - typename FEMTree< Dim , Real >::SolverInfo _sInfo; - _sInfo.cgDepth = 0 , _sInfo.cascadic = true , _sInfo.vCycles = 1 , _sInfo.iters = params.iters , _sInfo.cgAccuracy = params.cgSolverAccuracy , _sInfo.verbose = params.verbose , _sInfo.showResidual = params.showResidual , _sInfo.showGlobalResidual = SHOW_GLOBAL_RESIDUAL_NONE , _sInfo.sliceBlockSize = 1; - _sInfo.baseVCycles = params.baseVCycles; - typename FEMIntegrator::template System< Sigs , IsotropicUIntPack< Dim , 2 > > F( { 0. , 0. , (double)params.biLapWeight } ); - implicit.solution = implicit.tree.solveSystem( Sigs() , F , constraints , params.baseDepth , params.solveDepth , _sInfo , std::make_tuple( iInfo ) ); - if( params.verbose ) std::cout << "# Linear system solved: " << profiler << std::endl; - if( iInfo ) delete iInfo , iInfo = NULL; + // Solve the linear system + { + profiler.reset(); + typename FEMTree< Dim , Real >::SolverInfo _sInfo; + _sInfo.cgDepth = 0 , _sInfo.cascadic = true , _sInfo.vCycles = 1 , _sInfo.iters = params.iters , _sInfo.cgAccuracy = params.cgSolverAccuracy , _sInfo.verbose = params.verbose , _sInfo.showResidual = params.showResidual , _sInfo.showGlobalResidual = SHOW_GLOBAL_RESIDUAL_NONE , _sInfo.sliceBlockSize = 1; + _sInfo.baseVCycles = params.baseVCycles; + typename FEMIntegrator::template System< Sigs , IsotropicUIntPack< Dim , 2 > > F( { 0. , 0. , (double)params.biLapWeight } ); + implicit.solution = implicit.tree.solveSystem( Sigs() , F , constraints , params.baseDepth , params.solveDepth , _sInfo , std::make_tuple( iInfo ) ); + if( params.verbose ) std::cout << "# Linear system solved: " << profiler << std::endl; + if( iInfo ) delete iInfo , iInfo = NULL; + } } - } - // Get the iso-value - { - profiler.reset(); - double valueSum = 0 , weightSum = 0; - typename FEMTree< Dim , Real >::template MultiThreadedEvaluator< Sigs , 0 > evaluator( &implicit.tree , implicit.solution ); - std::vector< double > valueSums( ThreadPool::NumThreads() , 0 ) , weightSums( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , samples->size() , [&]( unsigned int thread , size_t j ) - { - ProjectiveData< Point< Real , Dim > , Real >& sample = (*samples)[j].sample; - Real w = sample.weight; - if( w>0 ) weightSums[thread] += w , valueSums[thread] += evaluator.values( sample.data / sample.weight , thread , (*samples)[j].node )[0] * w; - } ); - for( size_t t=0 ; t::template MultiThreadedEvaluator< Sigs , 0 > evaluator( &implicit.tree , implicit.solution ); + std::vector< double > valueSums( ThreadPool::NumThreads() , 0 ) , weightSums( ThreadPool::NumThreads() , 0 ); + ThreadPool::Parallel_for( 0 , samples->size() , [&]( unsigned int thread , size_t j ) + { + ProjectiveData< Point< Real , Dim > , Real >& sample = (*samples)[j].sample; + Real w = sample.weight; + if( w>0 ) weightSums[thread] += w , valueSums[thread] += evaluator.values( sample.data / sample.weight , thread , (*samples)[j].node )[0] * w; + } ); + for( size_t t=0 ; t +#include "FEMTree.h" +#include "MyExceptions.h" +#include "Array.h" -// Basic types -template< typename Real , unsigned int Dim > -using BaseSample = VectorTypeUnion< Real , Position< Real , Dim > , Normal< Real , Dim > >; +namespace PoissonRecon +{ + namespace Reconstructor + { + template< typename Real , unsigned int Dim > using Position = Point< Real , Dim >; + template< typename Real , unsigned int Dim > using Normal = Point< Real , Dim >; + template< typename Real , unsigned int Dim > using Gradient = Point< Real , Dim >; -template< typename Real , unsigned int Dim , typename Data > -using BaseSampleWithData = VectorTypeUnion< Real , Position< Real , Dim > , VectorTypeUnion< Real , Normal< Real , Dim > , Data > >; + // Basic types + template< typename Real , unsigned int Dim > + using BaseSample = VectorTypeUnion< Real , Position< Real , Dim > , Normal< Real , Dim > >; -template< typename Real , unsigned int Dim > -using BaseVertex = VectorTypeUnion< Real , Position< Real , Dim > , Normal< Real , Dim > , Real >; + template< typename Real , unsigned int Dim , typename Data > + using BaseSampleWithData = VectorTypeUnion< Real , Position< Real , Dim > , VectorTypeUnion< Real , Normal< Real , Dim > , Data > >; -template< typename Real , unsigned int Dim , typename Data > -using BaseVertexWithData = VectorTypeUnion< Real , Position< Real , Dim > , Gradient< Real , Dim > , Real , Data >; + template< typename Real , unsigned int Dim > + using BaseVertex = VectorTypeUnion< Real , Position< Real , Dim > , Normal< Real , Dim > , Real >; -using Edge = std::pair< node_index_type , node_index_type >; -using Polygon = std::vector< node_index_type >; + template< typename Real , unsigned int Dim , typename Data > + using BaseVertexWithData = VectorTypeUnion< Real , Position< Real , Dim > , Gradient< Real , Dim > , Real , Data >; -template< unsigned int FaceDim > using Face = std::conditional_t< FaceDim==2 , Polygon , std::conditional_t< FaceDim==1 , Edge , void * > >; + template< unsigned int FaceDim , typename T=node_index_type > using Face = std::conditional_t< FaceDim==2 , std::vector< T > , std::conditional_t< FaceDim==1 , std::pair< T , T > , void * > >; -// Basic streams -template< typename Real , unsigned int Dim > using BaseInputSampleStream = InputDataStream< BaseSample < Real , Dim > >; -template< typename Real , unsigned int Dim , typename Data > using BaseInputSampleWithDataStream = InputDataStream< BaseSampleWithData< Real , Dim , Data > >; + // Basic streams + template< typename Real , unsigned int Dim > using BaseInputSampleStream = InputDataStream< BaseSample < Real , Dim > >; + template< typename Real , unsigned int Dim , typename Data > using BaseInputSampleWithDataStream = InputDataStream< BaseSampleWithData< Real , Dim , Data > >; -template< typename Real , unsigned int Dim > using BaseOutputVertexStream = OutputDataStream< BaseVertex < Real , Dim > >; -template< typename Real , unsigned int Dim , typename Data > using BaseOutputVertexWithDataStream = OutputDataStream< BaseVertexWithData< Real , Dim , Data > >; + template< typename Real , unsigned int Dim > using BaseOutputVertexStream = OutputDataStream< BaseVertex < Real , Dim > >; + template< typename Real , unsigned int Dim , typename Data > using BaseOutputVertexWithDataStream = OutputDataStream< BaseVertexWithData< Real , Dim , Data > >; -template< unsigned int FaceDim > using InputFaceStream = InputDataStream< Face< FaceDim > >; -template< unsigned int FaceDim > using OutputFaceStream = OutputDataStream< Face< FaceDim > >; + template< unsigned int FaceDim > using InputFaceStream = InputDataStream< Face< FaceDim > >; + template< unsigned int FaceDim > using OutputFaceStream = OutputDataStream< Face< FaceDim > >; -///////////////////////////////////// -// Value Interpolation Data Stream // -///////////////////////////////////// -template< typename Real , unsigned int Dim > -struct ValueInterpolationStream : public InputDataStream< VectorTypeUnion< Real , Point< Real , Dim > , Real > > -{ - // Functionality to reset the stream to the start - virtual void reset( void ) = 0; - - // Functionality to extract the next position/normal pair. - // The method returns true if there was another point in the stream to read, and false otherwise - virtual bool base_read( Position< Real , Dim > &p , Real &v ) = 0; - // Implementation of InputDataStream::read - bool base_read( VectorTypeUnion< Real , Point< Real , Dim > , Real > &s ){ return base_read( s.template get<0>() , s.template get<1>() ); } -}; - -///////////////////////////////////////////////// -// Transformed Value Interpolation Data Stream // -///////////////////////////////////////////////// -template< typename Real , unsigned int Dim > -struct TransformedValueInterpolationStream : public ValueInterpolationStream< Real , Dim > -{ - // A constructor initialized with the transformation to be applied to the samples, and a sample stream - TransformedValueInterpolationStream( XForm< Real , Dim+1 > xForm , ValueInterpolationStream< Real , Dim > &stream ) : _stream(stream) , _xForm(xForm) {} + ///////////////////////////////////// + // Value Interpolation Data Stream // + ///////////////////////////////////// + template< typename Real , unsigned int Dim > + struct ValueInterpolationStream : public InputDataStream< VectorTypeUnion< Real , Point< Real , Dim > , Real > > + { + // Functionality to reset the stream to the start + virtual void reset( void ) = 0; + + // Functionality to extract the next position/normal pair. + // The method returns true if there was another point in the stream to read, and false otherwise + virtual bool base_read( Position< Real , Dim > &p , Real &v ) = 0; + // Implementation of InputDataStream::read + bool base_read( VectorTypeUnion< Real , Point< Real , Dim > , Real > &s ){ return base_read( s.template get<0>() , s.template get<1>() ); } + }; + + ///////////////////////////////////////////////// + // Transformed Value Interpolation Data Stream // + ///////////////////////////////////////////////// + template< typename Real , unsigned int Dim > + struct TransformedValueInterpolationStream : public ValueInterpolationStream< Real , Dim > + { + // A constructor initialized with the transformation to be applied to the samples, and a sample stream + TransformedValueInterpolationStream( XForm< Real , Dim+1 > xForm , ValueInterpolationStream< Real , Dim > &stream ) : _stream(stream) , _xForm(xForm) {} - // Functionality to reset the stream to the start - void reset( void ){ _stream.reset(); } + // Functionality to reset the stream to the start + void reset( void ){ _stream.reset(); } - // Functionality to extract the next position/normal pair. - // The method returns true if there was another point in the stream to read, and false otherwise - bool base_read( Position< Real , Dim > &p , Real &v ) - { - VectorTypeUnion< Real , Point< Real , Dim > , Real > s; - bool ret = _stream.read( s ); - if( ret ) p = _xForm * s.template get<0>() , v = s.template get<1>(); - return ret; - } + // Functionality to extract the next position/normal pair. + // The method returns true if there was another point in the stream to read, and false otherwise + bool base_read( Position< Real , Dim > &p , Real &v ) + { + VectorTypeUnion< Real , Point< Real , Dim > , Real > s; + bool ret = _stream.read( s ); + if( ret ) p = _xForm * s.template get<0>() , v = s.template get<1>(); + return ret; + } -protected: - // A reference to the underlying stream - ValueInterpolationStream< Real , Dim > &_stream; + protected: + // A reference to the underlying stream + ValueInterpolationStream< Real , Dim > &_stream; - // The affine transformation to be applied to the positions - XForm< Real , Dim+1 > _xForm; -}; + // The affine transformation to be applied to the positions + XForm< Real , Dim+1 > _xForm; + }; -/////////////////////////// -// Oriented Point Stream // -/////////////////////////// -template< typename Real , unsigned int Dim > -struct InputSampleStream : public BaseInputSampleStream< Real , Dim > -{ - // Functionality to reset the stream to the start - virtual void reset( void ) = 0; - - // Functionality to extract the next position/normal pair. - // The method returns true if there was another point in the stream to read, and false otherwise - virtual bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n ) = 0; - // Implementation of InputDataStream::read - bool base_read( BaseSample< Real , Dim > &s ){ return base_read( s.template get<0>() , s.template get<1>() ); } -}; - -/////////////////////////////////// -// Oriented Point w/ Data Stream // -/////////////////////////////////// -template< typename Real , unsigned int Dim , typename Data > -struct InputSampleWithDataStream : public BaseInputSampleWithDataStream< Real , Dim , Data > -{ - // A constructor initialized with an instance of "zero" data - InputSampleWithDataStream( Data zero ) : _zero(zero) {} + /////////////////////////// + // Oriented Point Stream // + /////////////////////////// + template< typename Real , unsigned int Dim > + struct InputSampleStream : public BaseInputSampleStream< Real , Dim > + { + // Functionality to reset the stream to the start + virtual void reset( void ) = 0; + + // Functionality to extract the next position/normal pair. + // The method returns true if there was another point in the stream to read, and false otherwise + virtual bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n ) = 0; + // Implementation of InputDataStream::read + bool base_read( BaseSample< Real , Dim > &s ){ return base_read( s.template get<0>() , s.template get<1>() ); } + }; + + /////////////////////////////////// + // Oriented Point w/ Data Stream // + /////////////////////////////////// + template< typename Real , unsigned int Dim , typename Data > + struct InputSampleWithDataStream : public BaseInputSampleWithDataStream< Real , Dim , Data > + { + // A constructor initialized with an instance of "zero" data + InputSampleWithDataStream( Data zero ) : _zero(zero) {} - // Functionality to reset the stream to the start - virtual void reset( void ) = 0; + // Functionality to reset the stream to the start + virtual void reset( void ) = 0; - // Returns the zero instance - const Data &zero( void ) const{ return _zero; } + // Returns the zero instance + const Data &zero( void ) const{ return _zero; } - // Functionality to extract the next position/normal pair. - // The method returns true if there was another point in the stream to read, and false otherwise - virtual bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n , Data &d ) = 0; - bool base_read( BaseSampleWithData< Real , Dim , Data > &s ){ return base_read( s.template get<0>() , s.template get<1>().template get<0>() , s.template get<1>().template get<1>() ); } + // Functionality to extract the next position/normal pair. + // The method returns true if there was another point in the stream to read, and false otherwise + virtual bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n , Data &d ) = 0; + bool base_read( BaseSampleWithData< Real , Dim , Data > &s ){ return base_read( s.template get<0>() , s.template get<1>().template get<0>() , s.template get<1>().template get<1>() ); } - // An instance of "zero" data - Data _zero; -}; + // An instance of "zero" data + Data _zero; + }; -/////////////////////////////////////// -// Transformed Oriented Point Stream // -/////////////////////////////////////// + /////////////////////////////////////// + // Transformed Oriented Point Stream // + /////////////////////////////////////// #ifdef DE_VIRTUALIZE_INPUT -template< typename Real , unsigned int Dim , typename InputStream > + template< typename Real , unsigned int Dim , typename InputStream > #else // !DE_VIRTUALIZE_INPUT -template< typename Real , unsigned int Dim > + template< typename Real , unsigned int Dim > #endif // DE_VIRTUALIZE_INPUT -struct TransformedInputSampleStream : public InputSampleStream< Real , Dim > -{ + struct TransformedInputSampleStream : public InputSampleStream< Real , Dim > + { #ifdef DE_VIRTUALIZE_INPUT - static_assert( std::is_base_of< InputSampleStream< Real , Dim > , InputStream >::value , "[ERROR] Unexpected stream type" ); + static_assert( std::is_base_of< InputSampleStream< Real , Dim > , InputStream >::value , "[ERROR] Unexpected stream type" ); #endif // DE_VIRTUALIZE_INPUT - // A constructor initialized with the transformation to be applied to the samples, and a sample stream + // A constructor initialized with the transformation to be applied to the samples, and a sample stream #ifdef DE_VIRTUALIZE_INPUT - TransformedInputSampleStream( XForm< Real , Dim+1 > xForm , InputStream &stream ) : _stream(stream) , _positionXForm(xForm) + TransformedInputSampleStream( XForm< Real , Dim+1 > xForm , InputStream &stream ) : _stream(stream) , _positionXForm(xForm) #else // !DE_VIRTUALIZE_INPUT - TransformedInputSampleStream( XForm< Real , Dim+1 > xForm , InputSampleStream< Real , Dim > &stream ) : _stream(stream) , _positionXForm(xForm) + TransformedInputSampleStream( XForm< Real , Dim+1 > xForm , InputSampleStream< Real , Dim > &stream ) : _stream(stream) , _positionXForm(xForm) #endif // DE_VIRTUALIZE_INPUT - { - _normalXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( fabs( xForm.determinant() ) , 1./Dim ); - } + { + _normalXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( fabs( xForm.determinant() ) , 1./Dim ); + } - // Functionality to reset the stream to the start - void reset( void ){ _stream.reset(); } + // Functionality to reset the stream to the start + void reset( void ){ _stream.reset(); } - // Functionality to extract the next position/normal pair. - // The method returns true if there was another point in the stream to read, and false otherwise - bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n ) - { - BaseSample< Real , Dim > s; - bool ret = _stream.read( s ); - if( ret ) p = _positionXForm * s.template get<0>() , n = _normalXForm * s.template get<1>(); - return ret; - } + // Functionality to extract the next position/normal pair. + // The method returns true if there was another point in the stream to read, and false otherwise + bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n ) + { + BaseSample< Real , Dim > s; + bool ret = _stream.read( s ); + if( ret ) p = _positionXForm * s.template get<0>() , n = _normalXForm * s.template get<1>(); + return ret; + } -protected: - // A reference to the underlying stream + protected: + // A reference to the underlying stream #ifdef DE_VIRTUALIZE_INPUT - InputStream &_stream; + InputStream &_stream; #else // !DE_VIRTUALIZE_INPUT - InputSampleStream< Real , Dim > &_stream; + InputSampleStream< Real , Dim > &_stream; #endif // DE_VIRTUALIZE_INPUT - // The affine transformation to be applied to the positions - XForm< Real , Dim+1 > _positionXForm; + // The affine transformation to be applied to the positions + XForm< Real , Dim+1 > _positionXForm; - // The linear transformation to be applied to the normals - XForm< Real , Dim > _normalXForm; -}; + // The linear transformation to be applied to the normals + XForm< Real , Dim > _normalXForm; + }; -/////////////////////////////////////////////// -// Transformed Oriented Point w/ Data Stream // -/////////////////////////////////////////////// + /////////////////////////////////////////////// + // Transformed Oriented Point w/ Data Stream // + /////////////////////////////////////////////// #ifdef DE_VIRTUALIZE_INPUT -template< typename Real , unsigned int Dim , typename Data , typename InputStream > + template< typename Real , unsigned int Dim , typename Data , typename InputStream > #else // !DE_VIRTUALIZE_INPUT -template< typename Real , unsigned int Dim , typename Data > + template< typename Real , unsigned int Dim , typename Data > #endif // DE_VIRTUALIZE_INPUT -struct TransformedInputSampleWithDataStream : public InputSampleWithDataStream< Real , Dim , Data > -{ + struct TransformedInputSampleWithDataStream : public InputSampleWithDataStream< Real , Dim , Data > + { #ifdef DE_VIRTUALIZE_INPUT - static_assert( std::is_base_of< InputSampleWithDataStream< Real , Dim , Data > , InputStream >::value , "[ERROR] Unexpected stream type" ); + static_assert( std::is_base_of< InputSampleWithDataStream< Real , Dim , Data > , InputStream >::value , "[ERROR] Unexpected stream type" ); #endif // DE_VIRTUALIZE_INPUT - // A constructor initialized with an instance of "zero" data + // A constructor initialized with an instance of "zero" data #ifdef DE_VIRTUALIZE_INPUT - TransformedInputSampleWithDataStream( XForm< Real , Dim+1 > xForm , InputStream &stream ) : InputSampleWithDataStream< Real , Dim , Data >( stream.zero() ) , _stream(stream) , _positionXForm(xForm) + TransformedInputSampleWithDataStream( XForm< Real , Dim+1 > xForm , InputStream &stream ) : InputSampleWithDataStream< Real , Dim , Data >( stream.zero() ) , _stream(stream) , _positionXForm(xForm) #else // !DE_VIRTUALIZE_INPUT - TransformedInputSampleWithDataStream( XForm< Real , Dim+1 > xForm , InputSampleWithDataStream< Real , Dim , Data > &stream ) : InputSampleWithDataStream< Real , Dim , Data >( stream.zero() ) , _stream(stream) , _positionXForm(xForm) + TransformedInputSampleWithDataStream( XForm< Real , Dim+1 > xForm , InputSampleWithDataStream< Real , Dim , Data > &stream ) : InputSampleWithDataStream< Real , Dim , Data >( stream.zero() ) , _stream(stream) , _positionXForm(xForm) #endif // DE_VIRTUALIZE_INPUT - { - _normalXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); - } + { + _normalXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); + } - // Functionality to reset the stream to the start - void reset( void ){ _stream.reset(); } + // Functionality to reset the stream to the start + void reset( void ){ _stream.reset(); } - // Functionality to extract the next position/normal pair. - // The method returns true if there was another point in the stream to read, and false otherwise - bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n , Data &d ) - { - BaseSampleWithData< Real , Dim , Data > s( Position< Real , Dim >() , VectorTypeUnion< Real , Normal< Real , Dim > , Data >( Normal< Real , Dim >() , _stream.zero() ) ); - bool ret = _stream.read( s ); - if( ret ) p = _positionXForm * s.template get<0>() , n = _normalXForm * s.template get<1>().template get<0>() , d = s.template get<1>().template get<1>(); - return ret; - } + // Functionality to extract the next position/normal pair. + // The method returns true if there was another point in the stream to read, and false otherwise + bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n , Data &d ) + { + BaseSampleWithData< Real , Dim , Data > s( Position< Real , Dim >() , VectorTypeUnion< Real , Normal< Real , Dim > , Data >( Normal< Real , Dim >() , _stream.zero() ) ); + bool ret = _stream.read( s ); + if( ret ) p = _positionXForm * s.template get<0>() , n = _normalXForm * s.template get<1>().template get<0>() , d = s.template get<1>().template get<1>(); + return ret; + } -protected: - // A reference to the underlying stream + protected: + // A reference to the underlying stream #ifdef DE_VIRTUALIZE_INPUT - InputStream &_stream; + InputStream &_stream; #else // !DE_VIRTUALIZE_INPUT - InputSampleWithDataStream< Real , Dim , Data > &_stream; + InputSampleWithDataStream< Real , Dim , Data > &_stream; #endif // DE_VIRTUALIZE_INPUT - // The affine transformation to be applied to the positions - XForm< Real , Dim+1 > _positionXForm; - - // The linear transformation to be applied to the normals - XForm< Real , Dim > _normalXForm; -}; - + // The affine transformation to be applied to the positions + XForm< Real , Dim+1 > _positionXForm; -/////////////////// -// Vertex Stream // -/////////////////// -template< typename Real , unsigned int Dim > -struct OutputVertexStream : public BaseOutputVertexStream< Real , Dim > -{ - // Need to provide access to base write for counter support - using BaseOutputVertexStream< Real , Dim >::write; - - // Functionality to insert the next vertex - virtual void base_write( Position< Real , Dim > p , Gradient< Real , Dim > g , Real w ) = 0; - void base_write( const BaseVertex< Real , Dim > &v ){ base_write( v.template get<0>() , v.template get<1>() , v.template get<2>() ); } -}; - -/////////////////////////// -// Vertex w/ Data Stream // -/////////////////////////// -template< typename Real , unsigned int Dim , typename Data > -struct OutputVertexWithDataStream : public BaseOutputVertexWithDataStream< Real , Dim , Data > -{ - // Need to provide access to base write for counter support - using BaseOutputVertexWithDataStream< Real , Dim , Data >::write; - - // Functionality to insert the next vertex - virtual void base_write( Position< Real , Dim > p , Gradient< Real , Dim > g , Real w , Data d ) = 0; - void base_write( const BaseVertexWithData< Real , Dim , Data > &v ){ return base_write( v.template get<0>() , v.template get<1>() , v.template get<2>() , v.template get<3>() ); } -}; - -/////////////////////////////// -// Transformed Vertex Stream // -/////////////////////////////// -template< typename Real , unsigned int Dim > -struct TransformedOutputVertexStream : public OutputVertexStream< Real , Dim > -{ - // A constructor initialized with the transformation to be applied to the samples, and a sample stream - TransformedOutputVertexStream( XForm< Real , Dim+1 > xForm , OutputVertexStream< Real , Dim > &stream ) : _stream(stream) , _positionXForm(xForm) - { - _gradientXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); - } + // The linear transformation to be applied to the normals + XForm< Real , Dim > _normalXForm; + }; - // Need to write the union to ensure that the counter gets set - void base_write( Position< Real , Dim > p , Normal< Real , Dim > g , Real w ){ _stream.write( BaseVertex< Real , Dim >( _positionXForm * p , _gradientXForm * g , w ) ); } -protected: - // A reference to the underlying stream - OutputVertexStream< Real , Dim > &_stream; + /////////////////// + // Vertex Stream // + /////////////////// + template< typename Real , unsigned int Dim > + struct OutputVertexStream : public BaseOutputVertexStream< Real , Dim > + { + // Need to provide access to base write for counter support + using BaseOutputVertexStream< Real , Dim >::write; + + // Functionality to insert the next vertex + virtual void base_write( Position< Real , Dim > p , Gradient< Real , Dim > g , Real w ) = 0; + void base_write( const BaseVertex< Real , Dim > &v ){ base_write( v.template get<0>() , v.template get<1>() , v.template get<2>() ); } + }; + + /////////////////////////// + // Vertex w/ Data Stream // + /////////////////////////// + template< typename Real , unsigned int Dim , typename Data > + struct OutputVertexWithDataStream : public BaseOutputVertexWithDataStream< Real , Dim , Data > + { + // Need to provide access to base write for counter support + using BaseOutputVertexWithDataStream< Real , Dim , Data >::write; + + // Functionality to insert the next vertex + virtual void base_write( Position< Real , Dim > p , Gradient< Real , Dim > g , Real w , Data d ) = 0; + void base_write( const BaseVertexWithData< Real , Dim , Data > &v ){ return base_write( v.template get<0>() , v.template get<1>() , v.template get<2>() , v.template get<3>() ); } + }; + + /////////////////////////////// + // Transformed Vertex Stream // + /////////////////////////////// + template< typename Real , unsigned int Dim > + struct TransformedOutputVertexStream : public OutputVertexStream< Real , Dim > + { + // A constructor initialized with the transformation to be applied to the samples, and a sample stream + TransformedOutputVertexStream( XForm< Real , Dim+1 > xForm , OutputVertexStream< Real , Dim > &stream ) : _stream(stream) , _positionXForm(xForm) + { + _gradientXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); + } - // The affine transformation to be applied to the positions - XForm< Real , Dim+1 > _positionXForm; + // Need to write the union to ensure that the counter gets set + void base_write( Position< Real , Dim > p , Normal< Real , Dim > g , Real w ){ _stream.write( BaseVertex< Real , Dim >( _positionXForm * p , _gradientXForm * g , w ) ); } - // The linear transformation to be applied to the normals - XForm< Real , Dim > _gradientXForm; -}; + protected: + // A reference to the underlying stream + OutputVertexStream< Real , Dim > &_stream; + // The affine transformation to be applied to the positions + XForm< Real , Dim+1 > _positionXForm; -/////////////////////////////////////// -// Transformed Vertex w/ Data Stream // -/////////////////////////////////////// -template< typename Real , unsigned int Dim , typename Data > -struct TransformedOutputVertexWithDataStream : public OutputVertexWithDataStream< Real , Dim , Data > -{ - // A constructor initialized with the transformation to be applied to the samples, and a sample stream - TransformedOutputVertexWithDataStream( XForm< Real , Dim+1 > xForm , OutputVertexWithDataStream< Real , Dim , Data > &stream ) : _stream(stream) , _positionXForm(xForm) - { - _gradientXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); - } + // The linear transformation to be applied to the normals + XForm< Real , Dim > _gradientXForm; + }; - void base_write( Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ){ _stream.write( BaseVertexWithData< Real , Dim , Data >( _positionXForm * p , _gradientXForm * g , w , d ) ); } -protected: - // A reference to the underlying stream - OutputVertexWithDataStream< Real , Dim , Data > &_stream; + /////////////////////////////////////// + // Transformed Vertex w/ Data Stream // + /////////////////////////////////////// + template< typename Real , unsigned int Dim , typename Data > + struct TransformedOutputVertexWithDataStream : public OutputVertexWithDataStream< Real , Dim , Data > + { + // A constructor initialized with the transformation to be applied to the samples, and a sample stream + TransformedOutputVertexWithDataStream( XForm< Real , Dim+1 > xForm , OutputVertexWithDataStream< Real , Dim , Data > &stream ) : _stream(stream) , _positionXForm(xForm) + { + _gradientXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); + } - // The affine transformation to be applied to the positions - XForm< Real , Dim+1 > _positionXForm; + void base_write( Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ){ _stream.write( BaseVertexWithData< Real , Dim , Data >( _positionXForm * p , _gradientXForm * g , w , d ) ); } - // The linear transformation to be applied to the normals - XForm< Real , Dim > _gradientXForm; -}; + protected: + // A reference to the underlying stream + OutputVertexWithDataStream< Real , Dim , Data > &_stream; -/////////////////////////////////////////// -// A wrapper class to write out vertices // -/////////////////////////////////////////// -template< typename Real , unsigned int Dim , typename Vertex > -struct OutputVertexStreamWrapper : public OutputVertexStream< Real , Dim > -{ - virtual void set( Vertex &out , const BaseVertex< Real , Dim > &in ) = 0; + // The affine transformation to be applied to the positions + XForm< Real , Dim+1 > _positionXForm; - OutputVertexStreamWrapper( OutputDataStream< Vertex > &stream , Vertex out ) : _stream(stream) , _out(out) {} + // The linear transformation to be applied to the normals + XForm< Real , Dim > _gradientXForm; + }; - void base_write( Position< Real , Dim > p , Normal< Real , Dim > g , Real w ) - { - _in.template get<0>() = p; - _in.template get<1>() = g; - _in.template get<2>() = w; - set( _out , _in ); - _stream.write( _out ); - } -protected: - OutputDataStream< Vertex > &_stream; - BaseVertex< Real , Dim > _in; - Vertex _out; -}; - -template< typename Real , unsigned int Dim , typename Data , typename Vertex > -struct OutputVertexWithDataStreamWrapper : public OutputVertexWithDataStream< Real , Dim , Data > -{ - virtual void set( Vertex &out , const BaseVertexWithData< Real , Dim , Data > &in ) = 0; + /////////////////////////////////////////// + // A wrapper class to write out vertices // + /////////////////////////////////////////// + template< typename Real , unsigned int Dim , typename Vertex > + struct OutputVertexStreamWrapper : public OutputVertexStream< Real , Dim > + { + virtual void set( Vertex &out , const BaseVertex< Real , Dim > &in ) = 0; - OutputVertexWithDataStreamWrapper( OutputDataStream< Vertex > &stream , BaseVertexWithData< Real , Dim , Data > in , Vertex out ) : _stream(stream) , _in(in) , _out(out) {} + OutputVertexStreamWrapper( OutputDataStream< Vertex > &stream , Vertex out ) : _stream(stream) , _out(out) {} - void base_write( Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ) - { - _in.template get<0>() = p; - _in.template get<1>() = g; - _in.template get<2>() = w; - _in.template get<3>() = d; - set( _out , _in ); - _stream.write( _out ); - } -protected: - OutputDataStream< Vertex > &_stream; - BaseVertexWithData< Real , Dim , Data > _in; - Vertex _out; -}; + void base_write( Position< Real , Dim > p , Normal< Real , Dim > g , Real w ) + { + _in.template get<0>() = p; + _in.template get<1>() = g; + _in.template get<2>() = w; + set( _out , _in ); + _stream.write( _out ); + } + protected: + OutputDataStream< Vertex > &_stream; + BaseVertex< Real , Dim > _in; + Vertex _out; + }; + + template< typename Real , unsigned int Dim , typename Data , typename Vertex > + struct OutputVertexWithDataStreamWrapper : public OutputVertexWithDataStream< Real , Dim , Data > + { + virtual void set( Vertex &out , const BaseVertexWithData< Real , Dim , Data > &in ) = 0; + OutputVertexWithDataStreamWrapper( OutputDataStream< Vertex > &stream , BaseVertexWithData< Real , Dim , Data > in , Vertex out ) : _stream(stream) , _in(in) , _out(out) {} -////////////////////////////////////////////////////////////////////////////// -// Output and the input face stream, backed either by a file or by a vector // -////////////////////////////////////////////////////////////////////////////// -// [WARNING] These assume that the stream starts as write-only and after the reset method is invoked, the stream becomes read-only. + void base_write( Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ) + { + _in.template get<0>() = p; + _in.template get<1>() = g; + _in.template get<2>() = w; + _in.template get<3>() = d; + set( _out , _in ); + _stream.write( _out ); + } + protected: + OutputDataStream< Vertex > &_stream; + BaseVertexWithData< Real , Dim , Data > _in; + Vertex _out; + }; + + ////////////////////////////////// + // File-backed streaming memory // + ////////////////////////////////// + class FileBackedReadWriteStream + { + public: + struct FileDescription + { + FILE *fp; -template< unsigned int FaceDim > -struct OutputInputFaceStream : public OutputFaceStream< FaceDim > , public InputFaceStream< FaceDim > -{ - // The streams for communicating the information - InputFaceStream < FaceDim > * inStream; - OutputFaceStream< FaceDim > *outStream; + FileDescription( FILE *fp ) : fp(fp) , _closeFile(false) + { + if( !this->fp ) + { + this->fp = std::tmpfile(); + _closeFile = true; + if( !this->fp ) ERROR_OUT( "Failed to open temporary file" ); + } + } + ~FileDescription( void ){ if( _closeFile ) fclose(fp); } + protected: +#ifdef SHOW_WARNINGS +#pragma message( "[WARNING] Probably can let the system handle closing the file" ) +#endif // SHOW_WARNINGS + bool _closeFile; + }; + + FileBackedReadWriteStream( FILE *fp ) : _fd(fp) {} + bool write( ConstPointer(char) data , size_t size ){ return fwrite( data , sizeof(char) , size , _fd.fp )==size; } + bool read( Pointer(char) data , size_t size ){ return fread( data , sizeof(char) , size , _fd.fp )==size; } + void reset( void ){ fseek( _fd.fp , 0 , SEEK_SET ); } + protected: + FileDescription _fd; + }; + + ////////////////////////////////////////////////////////////////////////////// + // Output and the input face stream, backed either by a file or by a vector // + ////////////////////////////////////////////////////////////////////////////// + // [WARNING] These assume that the stream starts as write-only and after the reset method is invoked, the stream becomes read-only. + + template< unsigned int FaceDim > + struct OutputInputFaceStream : public OutputFaceStream< FaceDim > , public InputFaceStream< FaceDim > + { + // The streams for communicating the information + InputFaceStream < FaceDim > * inStream; + OutputFaceStream< FaceDim > *outStream; - void reset( void ){ inStream->reset(); } - bool base_read( Face< FaceDim > &f ){ return inStream->read(f); } - bool base_read( unsigned int t , Face< FaceDim > &f ){ return inStream->read(t,f); } - void base_write( const Face< FaceDim > &f ){ outStream->write(f); } - void base_write( unsigned int t , const Face< FaceDim > &f ){ outStream->write(t,f); } + void reset( void ){ inStream->reset(); } + bool base_read( Face< FaceDim > &f ){ return inStream->read(f); } + bool base_read( unsigned int t , Face< FaceDim > &f ){ return inStream->read(t,f); } + void base_write( const Face< FaceDim > &f ){ outStream->write(f); } + void base_write( unsigned int t , const Face< FaceDim > &f ){ outStream->write(t,f); } - OutputInputFaceStream( bool inCore , bool multi ) - { - size_t sz = std::thread::hardware_concurrency(); + OutputInputFaceStream( bool inCore , bool multi ) + { + size_t sz = std::thread::hardware_concurrency(); - _backingVector = NULL; - _backingVectors.resize( sz , NULL ); + _backingVector = NULL; + _backingVectors.resize( sz , NULL ); - _backingFile = NULL; - _backingFiles.resize( sz , NULL ); + _backingFile = NULL; + _backingFiles.resize( sz , NULL ); - _inStreams.resize( sz , NULL ); - _outStreams.resize( sz , NULL ); + _inStreams.resize( sz , NULL ); + _outStreams.resize( sz , NULL ); - if( inCore ) - { - if( multi ) - { - for( unsigned int i=0 ; i >(); - _inStreams[i] = new VectorBackedInputDataStream< Face< FaceDim > >( *_backingVectors[i] ); - _outStreams[i] = new VectorBackedOutputDataStream< Face< FaceDim > >( *_backingVectors[i] ); + if( multi ) + { + for( unsigned int i=0 ; i >(); + _inStreams[i] = new VectorBackedInputDataStream< Face< FaceDim > >( *_backingVectors[i] ); + _outStreams[i] = new VectorBackedOutputDataStream< Face< FaceDim > >( *_backingVectors[i] ); + } + inStream = new MultiInputDataStream< Face< FaceDim > >( _inStreams ); + outStream = new MultiOutputDataStream< Face< FaceDim > >( _outStreams ); + } + else + { + _backingVector = new std::vector< Face< FaceDim > >(); + inStream = new VectorBackedInputDataStream< Face< FaceDim > >( *_backingVector ); + outStream = new VectorBackedOutputDataStream< Face< FaceDim > >( *_backingVector ); + } } - inStream = new MultiInputDataStream< Face< FaceDim > >( _inStreams ); - outStream = new MultiOutputDataStream< Face< FaceDim > >( _outStreams ); - } - else - { - _backingVector = new std::vector< Face< FaceDim > >(); - inStream = new VectorBackedInputDataStream< Face< FaceDim > >( *_backingVector ); - outStream = new VectorBackedOutputDataStream< Face< FaceDim > >( *_backingVector ); - } - } - else - { - if( multi ) - { - for( unsigned int i=0 ; i >( _backingFiles[i]->fp ); - _outStreams[i] = new FileBackedOutputDataStream< Face< FaceDim > >( _backingFiles[i]->fp ); + if( multi ) + { + for( unsigned int i=0 ; i >( _backingFiles[i]->fp ); + _outStreams[i] = new FileBackedOutputDataStream< Face< FaceDim > >( _backingFiles[i]->fp ); + } + inStream = new MultiInputDataStream< Face< FaceDim > >( _inStreams ); + outStream = new MultiOutputDataStream< Face< FaceDim > >( _outStreams ); + } + else + { + _backingFile = new FileBackedReadWriteStream::FileDescription( NULL ); + inStream = new FileBackedInputDataStream< Face< FaceDim > >( _backingFile->fp ); + outStream = new FileBackedOutputDataStream< Face< FaceDim > >( _backingFile->fp ); + } } - inStream = new MultiInputDataStream< Face< FaceDim > >( _inStreams ); - outStream = new MultiOutputDataStream< Face< FaceDim > >( _outStreams ); } - else + + ~OutputInputFaceStream( void ) { - _backingFile = new FileBackedReadWriteStream::FileDescription( NULL ); - inStream = new FileBackedInputDataStream< Face< FaceDim > >( _backingFile->fp ); - outStream = new FileBackedOutputDataStream< Face< FaceDim > >( _backingFile->fp ); - } - } - } + size_t sz = std::thread::hardware_concurrency(); - ~OutputInputFaceStream( void ) - { - size_t sz = std::thread::hardware_concurrency(); + delete _backingVector; + delete _backingFile; - delete _backingVector; - delete _backingFile; + for( unsigned int i=0 ; i > *_backingVector; + FileBackedReadWriteStream::FileDescription *_backingFile; + std::vector< std::vector< Face< FaceDim > > * > _backingVectors; + std::vector< FileBackedReadWriteStream::FileDescription * > _backingFiles; + std::vector< InputDataStream< Face< FaceDim > > * > _inStreams; + std::vector< OutputDataStream< Face< FaceDim > > * > _outStreams; + }; + + template< typename Factory > + struct OutputInputFactoryTypeStream : public OutputDataStream< typename Factory::VertexType > , public InputDataStream< typename Factory::VertexType > { - delete _backingVectors[i]; - delete _backingFiles[i]; - delete _inStreams[i]; - delete _outStreams[i]; - } - - delete inStream; - delete outStream; - } -protected: - std::vector< Face< FaceDim > > *_backingVector; - FileBackedReadWriteStream::FileDescription *_backingFile; - std::vector< std::vector< Face< FaceDim > > * > _backingVectors; - std::vector< FileBackedReadWriteStream::FileDescription * > _backingFiles; - std::vector< InputDataStream< Face< FaceDim > > * > _inStreams; - std::vector< OutputDataStream< Face< FaceDim > > * > _outStreams; -}; - -template< typename Factory > -struct OutputInputFactoryTypeStream : public OutputDataStream< typename Factory::VertexType > , public InputDataStream< typename Factory::VertexType > -{ - typedef typename Factory::VertexType Vertex; - // The streams for communicating the information - InputDataStream < Vertex > * inStream; - OutputDataStream< Vertex > *outStream; + typedef typename Factory::VertexType Vertex; + // The streams for communicating the information + InputDataStream < Vertex > * inStream; + OutputDataStream< Vertex > *outStream; - void reset( void ){ inStream->reset(); } - void base_write( const Vertex &v ){ outStream->write( v ); } - bool base_read( Vertex &v ){ return inStream->read( v ); } + void reset( void ){ inStream->reset(); } + void base_write( const Vertex &v ){ outStream->write( v ); } + bool base_read( Vertex &v ){ return inStream->read( v ); } - OutputInputFactoryTypeStream( Factory &factory , bool inCore , bool multi ) - { - size_t sz = std::thread::hardware_concurrency(); + OutputInputFactoryTypeStream( Factory &factory , bool inCore , bool multi ) + { + size_t sz = std::thread::hardware_concurrency(); - _backingVector = NULL; - _backingVectors.resize( sz , NULL ); + _backingVector = NULL; + _backingVectors.resize( sz , NULL ); - _backingFile = NULL; - _backingFiles.resize( sz , NULL ); + _backingFile = NULL; + _backingFiles.resize( sz , NULL ); - _inStreams.resize( sz , NULL ); - _outStreams.resize( sz , NULL ); + _inStreams.resize( sz , NULL ); + _outStreams.resize( sz , NULL ); - if( inCore ) - { - if( multi ) - { - for( unsigned int i=0 ; i(); - _inStreams[i] = new VectorBackedInputDataStream< Vertex >( *_backingVectors[i] ); - _outStreams[i] = new VectorBackedOutputDataStream< Vertex >( *_backingVectors[i] ); + if( multi ) + { + for( unsigned int i=0 ; i(); + _inStreams[i] = new VectorBackedInputDataStream< Vertex >( *_backingVectors[i] ); + _outStreams[i] = new VectorBackedOutputDataStream< Vertex >( *_backingVectors[i] ); + } + inStream = new MultiInputDataStream< Vertex >( _inStreams ); + outStream = new MultiOutputDataStream< Vertex >( _outStreams ); + } + else + { + _backingVector = new std::vector< Vertex >(); + + inStream = new VectorBackedInputDataStream< Vertex >( *_backingVector ); + outStream = new VectorBackedOutputDataStream< Vertex >( *_backingVector ); + } } - inStream = new MultiInputDataStream< Vertex >( _inStreams ); - outStream = new MultiOutputDataStream< Vertex >( _outStreams ); - } - else - { - _backingVector = new std::vector< Vertex >(); - - inStream = new VectorBackedInputDataStream< Vertex >( *_backingVector ); - outStream = new VectorBackedOutputDataStream< Vertex >( *_backingVector ); - } - } - else - { - if( multi ) - { - for( unsigned int i=0 ; i( _backingFiles[i]->fp , factory ); - _outStreams[i] = new FileBackedOutputFactoryTypeStream< Factory >( _backingFiles[i]->fp , factory ); + if( multi ) + { + for( unsigned int i=0 ; i( _backingFiles[i]->fp , factory ); + _outStreams[i] = new FileBackedOutputFactoryTypeStream< Factory >( _backingFiles[i]->fp , factory ); + } + inStream = new MultiInputDataStream< Vertex >( _inStreams ); + outStream = new MultiOutputDataStream< Vertex >( _outStreams ); + } + else + { + _backingFile = new FileBackedReadWriteStream::FileDescription( NULL ); + inStream = new FileBackedInputFactoryTypeStream< Factory >( _backingFile->fp , factory ); + outStream = new FileBackedOutputFactoryTypeStream< Factory >( _backingFile->fp , factory ); + } } - inStream = new MultiInputDataStream< Vertex >( _inStreams ); - outStream = new MultiOutputDataStream< Vertex >( _outStreams ); } - else + + ~OutputInputFactoryTypeStream( void ) { - _backingFile = new FileBackedReadWriteStream::FileDescription( NULL ); - inStream = new FileBackedInputFactoryTypeStream< Factory >( _backingFile->fp , factory ); - outStream = new FileBackedOutputFactoryTypeStream< Factory >( _backingFile->fp , factory ); - } - } - } + size_t sz = std::thread::hardware_concurrency(); - ~OutputInputFactoryTypeStream( void ) - { - size_t sz = std::thread::hardware_concurrency(); + delete _backingVector; + delete _backingFile; - delete _backingVector; - delete _backingFile; + for( unsigned int i=0 ; i *_backingVector; + FileBackedReadWriteStream::FileDescription *_backingFile; + std::vector< std::vector< Vertex > * >_backingVectors; + std::vector< FileBackedReadWriteStream::FileDescription * > _backingFiles; + std::vector< InputDataStream< Vertex > * > _inStreams; + std::vector< OutputDataStream< Vertex > * > _outStreams; + }; + + template< typename Real , unsigned int Dim , bool HasGradients , bool HasDensity > + struct OutputVertexInfo { - delete _backingVectors[i]; - delete _backingFiles[i]; - delete _inStreams[i]; - delete _outStreams[i]; - } - - delete inStream; - delete outStream; - } -protected: - std::vector< Vertex > *_backingVector; - FileBackedReadWriteStream::FileDescription *_backingFile; - std::vector< std::vector< Vertex > * >_backingVectors; - std::vector< FileBackedReadWriteStream::FileDescription * > _backingFiles; - std::vector< InputDataStream< Vertex > * > _inStreams; - std::vector< OutputDataStream< Vertex > * > _outStreams; -}; - -template< typename Real , unsigned int Dim , bool HasGradients , bool HasDensity > -struct OutputVertexInfo -{ - using Factory = - typename std::conditional - < - HasGradients , - typename std::conditional - < + using Factory = + typename std::conditional + < + HasGradients , + typename std::conditional + < HasDensity , VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::NormalFactory< Real , Dim > , VertexFactory::ValueFactory< Real > > , VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::NormalFactory< Real , Dim > > - >::type , - typename std::conditional - < + >::type , + typename std::conditional + < HasDensity , VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::ValueFactory< Real > > , VertexFactory::PositionFactory< Real , Dim > - >::type - >::type; - using Vertex = typename Factory::VertexType; + >::type + >::type; + using Vertex = typename Factory::VertexType; - static Factory GetFactory( void ){ return Factory(); } + static Factory GetFactory( void ){ return Factory(); } - struct StreamWrapper : public Reconstructor::OutputVertexStreamWrapper< Real , Dim , Vertex > - { - StreamWrapper( OutputDataStream< Vertex > &stream , Vertex out ) : - Reconstructor::OutputVertexStreamWrapper< Real , Dim , Vertex >( stream , out ){} - void set( Vertex &out , const Reconstructor::BaseVertex< Real , Dim > &in ) - { - if constexpr( HasGradients || HasDensity ) + struct StreamWrapper : public Reconstructor::OutputVertexStreamWrapper< Real , Dim , Vertex > { - out.template get<0>() = in.template get<0>(); - if constexpr( HasGradients ) + StreamWrapper( OutputDataStream< Vertex > &stream , Vertex out ) : + Reconstructor::OutputVertexStreamWrapper< Real , Dim , Vertex >( stream , out ){} + void set( Vertex &out , const Reconstructor::BaseVertex< Real , Dim > &in ) { - out.template get<1>() = in.template get<1>(); - if constexpr( HasDensity ) out.template get<2>() = in.template get<2>(); + if constexpr( HasGradients || HasDensity ) + { + out.template get<0>() = in.template get<0>(); + if constexpr( HasGradients ) + { + out.template get<1>() = in.template get<1>(); + if constexpr( HasDensity ) out.template get<2>() = in.template get<2>(); + } + else + { + if constexpr( HasDensity ) out.template get<1>() = in.template get<2>(); + } + } + else out = in.template get<0>(); } - else - { - if constexpr( HasDensity ) out.template get<1>() = in.template get<2>(); - } - } - else out = in.template get<0>(); - } - }; -}; + }; + }; -template< typename Real , unsigned int Dim , typename AuxDataFactory , bool HasGradients , bool HasDensity > -struct OutputVertexWithDataInfo -{ - using Factory = - typename std::conditional - < - HasGradients , - typename std::conditional - < + template< typename Real , unsigned int Dim , typename AuxDataFactory , bool HasGradients , bool HasDensity > + struct OutputVertexWithDataInfo + { + using Factory = + typename std::conditional + < + HasGradients , + typename std::conditional + < HasDensity , VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::NormalFactory< Real , Dim > , VertexFactory::ValueFactory< Real > , AuxDataFactory > , VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::NormalFactory< Real , Dim > , AuxDataFactory > - >::type , - typename std::conditional - < + >::type , + typename std::conditional + < HasDensity , VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::ValueFactory< Real > , AuxDataFactory > , VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , AuxDataFactory > - >::type - >::type; - using AuxData = typename AuxDataFactory::VertexType; - - using _Vertex = VectorTypeUnion< Real , Point< Real , Dim > , Point< Real , Dim > , Real , typename AuxDataFactory::VertexType >; - using Vertex = typename Factory::VertexType; - - static Factory GetFactory( AuxDataFactory auxDataFactory ) - { - if constexpr( HasGradients ) - { - if constexpr( HasDensity ) return Factory( VertexFactory::PositionFactory< Real , Dim >() , VertexFactory::NormalFactory< Real , Dim >() , VertexFactory::ValueFactory< Real >() , auxDataFactory ); - else return Factory( VertexFactory::PositionFactory< Real , Dim >() , VertexFactory::NormalFactory< Real , Dim >() , auxDataFactory ); - } - else - { - if constexpr( HasDensity ) return Factory( VertexFactory::PositionFactory< Real , Dim >() , VertexFactory::ValueFactory< Real >() , auxDataFactory ); - else return Factory( VertexFactory::PositionFactory< Real , Dim >() , auxDataFactory ); - } - } + >::type + >::type; + using AuxData = typename AuxDataFactory::VertexType; - struct StreamWrapper : public Reconstructor::OutputVertexWithDataStreamWrapper< Real , Dim , AuxData , Vertex > - { - StreamWrapper( OutputDataStream< Vertex > &stream , Vertex out ) : - Reconstructor::OutputVertexWithDataStreamWrapper< Real , Dim , AuxData , Vertex >( stream , _Vertex() , out ){} + using _Vertex = VectorTypeUnion< Real , Point< Real , Dim > , Point< Real , Dim > , Real , typename AuxDataFactory::VertexType >; + using Vertex = typename Factory::VertexType; - void set( Vertex &out , const Reconstructor::BaseVertexWithData< Real , Dim , AuxData > &in ) - { - out.template get<0>() = in.template get<0>(); - if constexpr( HasGradients ) + static Factory GetFactory( AuxDataFactory auxDataFactory ) { - out.template get<1>() = in.template get<1>(); - if constexpr( HasDensity ) out.template get<2>() = in.template get<2>() , out.template get<3>() = in.template get<3>(); - else out.template get<2>() = in.template get<3>(); + if constexpr( HasGradients ) + { + if constexpr( HasDensity ) return Factory( VertexFactory::PositionFactory< Real , Dim >() , VertexFactory::NormalFactory< Real , Dim >() , VertexFactory::ValueFactory< Real >() , auxDataFactory ); + else return Factory( VertexFactory::PositionFactory< Real , Dim >() , VertexFactory::NormalFactory< Real , Dim >() , auxDataFactory ); + } + else + { + if constexpr( HasDensity ) return Factory( VertexFactory::PositionFactory< Real , Dim >() , VertexFactory::ValueFactory< Real >() , auxDataFactory ); + else return Factory( VertexFactory::PositionFactory< Real , Dim >() , auxDataFactory ); + } } - else + + struct StreamWrapper : public Reconstructor::OutputVertexWithDataStreamWrapper< Real , Dim , AuxData , Vertex > { - if constexpr( HasDensity ) out.template get<1>() = in.template get<2>() , out.template get<2>() = in.template get<3>(); - else out.template get<1>() = in.template get<3>(); - } - } - }; -}; + StreamWrapper( OutputDataStream< Vertex > &stream , Vertex out ) : + Reconstructor::OutputVertexWithDataStreamWrapper< Real , Dim , AuxData , Vertex >( stream , _Vertex() , out ){} + + void set( Vertex &out , const Reconstructor::BaseVertexWithData< Real , Dim , AuxData > &in ) + { + out.template get<0>() = in.template get<0>(); + if constexpr( HasGradients ) + { + out.template get<1>() = in.template get<1>(); + if constexpr( HasDensity ) out.template get<2>() = in.template get<2>() , out.template get<3>() = in.template get<3>(); + else out.template get<2>() = in.template get<3>(); + } + else + { + if constexpr( HasDensity ) out.template get<1>() = in.template get<2>() , out.template get<2>() = in.template get<3>(); + else out.template get<1>() = in.template get<3>(); + } + } + }; + }; + } +} #endif // RECONSTRUCTORS_STREAMS_INCLUDED \ No newline at end of file diff --git a/Src/RegularGrid.h b/Src/RegularGrid.h index 9e7c7846..ec561f1e 100644 --- a/Src/RegularGrid.h +++ b/Src/RegularGrid.h @@ -32,117 +32,123 @@ DAMAGE. #include #include "Array.h" #include "Geometry.h" +#include "MyMiscellany.h" -template< typename ... Type > struct RegularGridDataType{}; - -template<> -struct RegularGridDataType<> -{ - static void Write( FILE *fp , unsigned int dim , std::string name ); - static bool Read( FILE *fp , unsigned int dim , std::string name ); -}; - -template<> struct RegularGridDataType< char >{ static const std::string Name ; static void Write( FILE *fp ){ RegularGridDataType<>::Write( fp , 1 , Name ); } ; static bool Read( FILE *fp ){ return RegularGridDataType<>::Read( fp , 1 , Name ); } }; -const std::string RegularGridDataType< char >::Name = "CHAR"; -template<> struct RegularGridDataType< unsigned char >{ static const std::string Name ; static void Write( FILE *fp ){ RegularGridDataType<>::Write( fp , 1 , Name ); } static bool Read( FILE *fp ){ return RegularGridDataType<>::Read( fp , 1 , Name ); } }; -const std::string RegularGridDataType< unsigned char >::Name = "UNSIGNED_CHAR"; -template<> struct RegularGridDataType< int >{ static const std::string Name ; static void Write( FILE *fp ){ RegularGridDataType<>::Write( fp , 1 , Name ); } static bool Read( FILE *fp ){ return RegularGridDataType<>::Read( fp , 1 , Name ); } }; -const std::string RegularGridDataType< int >::Name = "INT"; -template<> struct RegularGridDataType< unsigned int >{ static const std::string Name ; static void Write( FILE *fp ){ RegularGridDataType<>::Write( fp , 1 , Name ); } static bool Read( FILE *fp ){ return RegularGridDataType<>::Read( fp , 1 , Name ); } }; -const std::string RegularGridDataType< unsigned int >::Name = "UNSIGNED_INT"; -template<> struct RegularGridDataType< float >{ static const std::string Name ; static void Write( FILE *fp ){ RegularGridDataType<>::Write( fp , 1 , Name ); } static bool Read( FILE *fp ){ return RegularGridDataType<>::Read( fp , 1 , Name ); } }; -const std::string RegularGridDataType< float >::Name = "FLOAT"; -template<> struct RegularGridDataType< double >{ static const std::string Name ; static void Write( FILE *fp ){ RegularGridDataType<>::Write( fp , 1 , Name ); } static bool Read( FILE *fp ){ return RegularGridDataType<>::Read( fp , 1 , Name ); } }; -const std::string RegularGridDataType< double >::Name = "DOUBLE"; - -template< typename Real , unsigned int Dim > struct RegularGridDataType< Point< Real , Dim > >{ static const std::string Name ; static void Write( FILE *fp ){ RegularGridDataType<>::Write( fp , Dim , Name ); } static bool Read( FILE *fp ){ return RegularGridDataType<>::Read( fp , Dim , Name ); } }; -template< typename Real , unsigned int Dim > const std::string RegularGridDataType< Point< Real , Dim > >::Name = RegularGridDataType< Real >::Name; - - -template< typename DataType , unsigned int Dim > -struct RegularGrid +namespace PoissonRecon { - static bool ReadHeader( std::string fileName , unsigned int &dim , std::string &type ); - - RegularGrid( void ) : _values( NullPointer( DataType ) ){ for( unsigned int d=0 ; d static void Read( std::string fileName , unsigned int res[Dim] , Pointer( DataType ) &values , XForm< Real , Dim+1 > &gridToModel ); - template< typename Real > static void Write( std::string fileName , const unsigned int res[Dim] , ConstPointer( DataType ) values , XForm< Real , Dim+1 > gridToModel ); - - template< typename Real > void read( std::string fileName , XForm< Real , Dim+1 > &gridToModel ); - template< typename Real > void write( std::string fileName , XForm< Real , Dim+1 > gridToModel ) const; - - Pointer( DataType ) operator()( void ){ return _values; } - ConstPointer( DataType ) operator()( void ) const { return _values; } - - DataType &operator[]( size_t idx ){ return _values[idx]; } - const DataType &operator[]( size_t idx ) const { return _values[idx]; } - - // Take the Dim coordinates and transform them into an index - template< typename Int > typename std::enable_if< std::is_integral< Int >::value , size_t >::type index( const Int coords[] ) const { return _index( coords , 0 ); } - template< typename Int > typename std::enable_if< std::is_integral< Int >::value , size_t >::type index( Int coords[] ) const { return _index( coords , 0 ); } - template< typename Int , typename ... Ints > typename std::enable_if< std::is_integral< Int >::value , size_t >::type index( Int coord , Ints ... coords ) const { static_assert( sizeof...(coords)+1==Dim , "[ERROR] number of coordinates does not match the number of dimensions" ) ; const Int c[] = { coord , coords ... } ; return index( c ); } - - // Take the index and transform it into the Dim coordinate - template< typename Int > typename std::enable_if< std::is_integral< Int >::value >::type setIndex( size_t idx , Int coords[] ) const { _setIndex( idx , coords ); } - - template< typename Int > typename std::enable_if< std::is_integral< Int >::value >::type resize( const Int res[] ); - template< typename Int > typename std::enable_if< std::is_integral< Int >::value >::type resize( Int res[] ); - template< typename Int , typename ... Ints > typename std::enable_if< std::is_integral< Int >::value >::type resize( Int res , Ints ... ress ); - - template< typename Int > typename std::enable_if< std::is_integral< Int >::value , DataType & >::type operator()( const Int coords[] ) { return operator[]( index( coords ) ); } - template< typename Int > typename std::enable_if< std::is_integral< Int >::value , DataType & >::type operator()( Int coords[] ) { return operator[]( index( coords ) ); } - template< typename Int > typename std::enable_if< std::is_integral< Int >::value , const DataType & >::type operator()( const Int coords[] ) const { return operator[]( index( coords ) ); } - template< typename Int > typename std::enable_if< std::is_integral< Int >::value , const DataType & >::type operator()( Int coords[] ) const { return operator[]( index( coords ) ); } - template< typename Int , typename ... Ints > typename std::enable_if< std::is_integral< Int >::value , DataType & >::type operator()( Int coord , Ints ... coords ) { static_assert( sizeof...(coords)+1==Dim , "[ERROR] number of coordinates does not match the number of dimensions" ) ; const Int c[] = { coord , coords ... } ; return operator()( c ); } - template< typename Int , typename ... Ints > typename std::enable_if< std::is_integral< Int >::value , const DataType & >::type operator()( Int coord , Ints ... coords ) const { static_assert( sizeof...(coords)+1==Dim , "[ERROR] number of coordinates does not match the number of dimensions" ) ; const Int c[] = { coord , coords ... } ; return operator()( c ); } - - template< typename Real > typename std::enable_if< !std::is_integral< Real >::value , ProjectiveData< Real , DataType > >::type operator()( Real coords[] ) { return _Sample( _res , coords , _values ); } - template< typename Real > typename std::enable_if< !std::is_integral< Real >::value , ProjectiveData< Real , DataType > >::type operator()( const Real coords[] ) { return _Sample( _res , coords , _values ); } - template< typename Real > typename std::enable_if< !std::is_integral< Real >::value , ProjectiveData< Real , DataType > >::type operator()( Real coords[] ) const { return _Sample( _res , coords , _values ); } - template< typename Real > typename std::enable_if< !std::is_integral< Real >::value , ProjectiveData< Real , DataType > >::type operator()( const Real coords[] ) const { return _Sample( _res , coords , _values ); } - template< typename Real , typename ... Reals > typename std::enable_if< !std::is_integral< Real >::value , ProjectiveData< Real , DataType > >::type operator()( Real coord , Reals ... coords ) { static_assert( sizeof...(coords)+1==Dim , "[ERROR] number of coordinates does not match the number of dimensions" ) ; const Real c[] = { coord , coords ... } ; return operator()( c ); } - template< typename Real , typename ... Reals > typename std::enable_if< !std::is_integral< Real >::value , ProjectiveData< Real , DataType > >::type operator()( Real coord , Reals ... coords ) const { static_assert( sizeof...(coords)+1==Dim , "[ERROR] number of coordinates does not match the number of dimensions" ) ; const Real c[] = { coord , coords ... } ; return operator()( c ); } - template< typename Real > ProjectiveData< Real , DataType > operator()( Point< Real , Dim > coords ) { return operator()( &coords[0] ); } - template< typename Real > ProjectiveData< Real , DataType > operator()( Point< Real , Dim > coords ) const { return operator()( &coords[0] ); } - - template< typename Int > typename std::enable_if< std::is_integral< int >::value , bool >::type inBounds( const Int coords[] ) const { return _inBounds< Dim-1 >( coords ); } - template< typename Int > typename std::enable_if< std::is_integral< int >::value , bool >::type inBounds( Int coords[] ) const { return _inBounds< Dim-1 >( coords ); } - template< typename Int , typename ... Ints > typename std::enable_if< std::is_integral< int >::value , bool >::type inBounds( Ints ... coords ) const { static_assert( sizeof...(coords)+1==Dim , "[ERROR] number of coordinates does not match the number of dimensions" ) ; const Int c[] = { coords ... } ; return inBounds( c ); } - - const unsigned int *res( void ) const { return _res; } - unsigned int res( unsigned int d ) const { return _res[d]; } - size_t resolution( void ) const { return _Resolution< Dim >( _res ); } - -protected: - template< unsigned int D=Dim > static typename std::enable_if< D==1 , size_t >::type _Resolution( const unsigned int res[] ) { return res[0]; } - template< unsigned int D=Dim > static typename std::enable_if< D!=1 , size_t >::type _Resolution( const unsigned int res[] ) { return res[D-1] * _Resolution(res); } - - template< typename Real , unsigned int D=Dim > static typename std::enable_if< D==1 , ProjectiveData< Real , DataType > >::type _Sample( const unsigned int res[] , const Real coords[] , ConstPointer( DataType ) values ); - template< typename Real , unsigned int D=Dim > static typename std::enable_if< D!=1 , ProjectiveData< Real , DataType > >::type _Sample( const unsigned int res[] , const Real coords[] , ConstPointer( DataType ) values ); - - // _index( x[0] , ... , x[D-1] ) = x[0] + ... + x[D-1] * ( res[0] * ... * res[D-1] ) - template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D==Dim-1 && D!=0 , size_t >::type _index( Int coords[] , size_t idx ) const { return _index< Int , D-1 >( coords , coords[D] ); } - template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D!=Dim-1 && D!=0 , size_t >::type _index( Int coords[] , size_t idx ) const { return _index< Int , D-1 >( coords , coords[D] + idx*_res[D] ); } - template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D!=Dim-1 && D==0 , size_t >::type _index( Int coords[] , size_t idx ) const { return coords[D] + idx*_res[D] ; } - template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D==Dim-1 && D==0 , size_t >::type _index( Int coords[] , size_t idx ) const { return coords[D] ; } - template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D==Dim-1 && D!=0 , size_t >::type _index( const Int coords[] , size_t idx ) const { return _index< Int , D-1 >( coords , coords[D] ); } - template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D!=Dim-1 && D!=0 , size_t >::type _index( const Int coords[] , size_t idx ) const { return _index< Int , D-1 >( coords , coords[D] + idx*_res[D] ); } - template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D!=Dim-1 && D==0 , size_t >::type _index( const Int coords[] , size_t idx ) const { return coords[D] + idx*_res[D] ; } - template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D==Dim-1 && D==0 , size_t >::type _index( const Int coords[] , size_t idx ) const { return coords[D] ; } - - template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D!=0 , size_t >::type _setIndex( size_t idx , Int coords[] ) const { idx = _setIndex< Int , D-1 >( idx , coords ) ; coords[D] = (Int)( idx % _res[D] ) ; return idx / _res[D]; } - template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D==0 , size_t >::type _setIndex( size_t idx , Int coords[] ) const { coords[D] = (Int)( idx % _res[D] ) ; return idx / _res[D]; } - - template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D==0 , bool >::type _inBounds( Int coords[] ) const { return coords[0]>=0 && coords[0]<_res[0]; } - template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D!=0 , bool >::type _inBounds( Int coords[] ) const { return coords[D]>=0 && coords[D]<_res[D] && _inBounds< D-1 >( coords ); } - template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D==0 , bool >::type _inBounds( const Int coords[] ) const { return coords[0]>=0 && coords[0]<_res[0]; } - template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D!=0 , bool >::type _inBounds( const Int coords[] ) const { return coords[D]>=0 && coords[D]<_res[D] && _inBounds< D-1 >( coords ); } - - - unsigned int _res[Dim]; - Pointer( DataType ) _values; -}; + + template< typename ... Type > struct RegularGridDataType{}; + + template<> + struct RegularGridDataType<> + { + static void Write( FILE *fp , unsigned int dim , std::string name ); + static bool Read( FILE *fp , unsigned int dim , std::string name ); + }; + + template<> struct RegularGridDataType< char >{ static const std::string Name ; static void Write( FILE *fp ){ RegularGridDataType<>::Write( fp , 1 , Name ); } ; static bool Read( FILE *fp ){ return RegularGridDataType<>::Read( fp , 1 , Name ); } }; + const std::string RegularGridDataType< char >::Name = "CHAR"; + template<> struct RegularGridDataType< unsigned char >{ static const std::string Name ; static void Write( FILE *fp ){ RegularGridDataType<>::Write( fp , 1 , Name ); } static bool Read( FILE *fp ){ return RegularGridDataType<>::Read( fp , 1 , Name ); } }; + const std::string RegularGridDataType< unsigned char >::Name = "UNSIGNED_CHAR"; + template<> struct RegularGridDataType< int >{ static const std::string Name ; static void Write( FILE *fp ){ RegularGridDataType<>::Write( fp , 1 , Name ); } static bool Read( FILE *fp ){ return RegularGridDataType<>::Read( fp , 1 , Name ); } }; + const std::string RegularGridDataType< int >::Name = "INT"; + template<> struct RegularGridDataType< unsigned int >{ static const std::string Name ; static void Write( FILE *fp ){ RegularGridDataType<>::Write( fp , 1 , Name ); } static bool Read( FILE *fp ){ return RegularGridDataType<>::Read( fp , 1 , Name ); } }; + const std::string RegularGridDataType< unsigned int >::Name = "UNSIGNED_INT"; + template<> struct RegularGridDataType< float >{ static const std::string Name ; static void Write( FILE *fp ){ RegularGridDataType<>::Write( fp , 1 , Name ); } static bool Read( FILE *fp ){ return RegularGridDataType<>::Read( fp , 1 , Name ); } }; + const std::string RegularGridDataType< float >::Name = "FLOAT"; + template<> struct RegularGridDataType< double >{ static const std::string Name ; static void Write( FILE *fp ){ RegularGridDataType<>::Write( fp , 1 , Name ); } static bool Read( FILE *fp ){ return RegularGridDataType<>::Read( fp , 1 , Name ); } }; + const std::string RegularGridDataType< double >::Name = "DOUBLE"; + + template< typename Real , unsigned int Dim > struct RegularGridDataType< Point< Real , Dim > >{ static const std::string Name ; static void Write( FILE *fp ){ RegularGridDataType<>::Write( fp , Dim , Name ); } static bool Read( FILE *fp ){ return RegularGridDataType<>::Read( fp , Dim , Name ); } }; + template< typename Real , unsigned int Dim > const std::string RegularGridDataType< Point< Real , Dim > >::Name = RegularGridDataType< Real >::Name; + + + template< typename DataType , unsigned int Dim > + struct RegularGrid + { + static bool ReadHeader( std::string fileName , unsigned int &dim , std::string &type ); + + RegularGrid( void ) : _values( NullPointer( DataType ) ){ for( unsigned int d=0 ; d static void Read( std::string fileName , unsigned int res[Dim] , Pointer( DataType ) &values , XForm< Real , Dim+1 > &gridToModel ); + template< typename Real > static void Write( std::string fileName , const unsigned int res[Dim] , ConstPointer( DataType ) values , XForm< Real , Dim+1 > gridToModel ); + + template< typename Real > void read( std::string fileName , XForm< Real , Dim+1 > &gridToModel ); + template< typename Real > void write( std::string fileName , XForm< Real , Dim+1 > gridToModel ) const; + + Pointer( DataType ) operator()( void ){ return _values; } + ConstPointer( DataType ) operator()( void ) const { return _values; } + + DataType &operator[]( size_t idx ){ return _values[idx]; } + const DataType &operator[]( size_t idx ) const { return _values[idx]; } + + // Take the Dim coordinates and transform them into an index + template< typename Int > typename std::enable_if< std::is_integral< Int >::value , size_t >::type index( const Int coords[] ) const { return _index( coords , 0 ); } + template< typename Int > typename std::enable_if< std::is_integral< Int >::value , size_t >::type index( Int coords[] ) const { return _index( coords , 0 ); } + template< typename Int , typename ... Ints > typename std::enable_if< std::is_integral< Int >::value , size_t >::type index( Int coord , Ints ... coords ) const { static_assert( sizeof...(coords)+1==Dim , "[ERROR] number of coordinates does not match the number of dimensions" ) ; const Int c[] = { coord , coords ... } ; return index( c ); } + + // Take the index and transform it into the Dim coordinate + template< typename Int > typename std::enable_if< std::is_integral< Int >::value >::type setIndex( size_t idx , Int coords[] ) const { _setIndex( idx , coords ); } + + template< typename Int > typename std::enable_if< std::is_integral< Int >::value >::type resize( const Int res[] ); + template< typename Int > typename std::enable_if< std::is_integral< Int >::value >::type resize( Int res[] ); + template< typename Int , typename ... Ints > typename std::enable_if< std::is_integral< Int >::value >::type resize( Int res , Ints ... ress ); + + template< typename Int > typename std::enable_if< std::is_integral< Int >::value , DataType & >::type operator()( const Int coords[] ) { return operator[]( index( coords ) ); } + template< typename Int > typename std::enable_if< std::is_integral< Int >::value , DataType & >::type operator()( Int coords[] ) { return operator[]( index( coords ) ); } + template< typename Int > typename std::enable_if< std::is_integral< Int >::value , const DataType & >::type operator()( const Int coords[] ) const { return operator[]( index( coords ) ); } + template< typename Int > typename std::enable_if< std::is_integral< Int >::value , const DataType & >::type operator()( Int coords[] ) const { return operator[]( index( coords ) ); } + template< typename Int , typename ... Ints > typename std::enable_if< std::is_integral< Int >::value , DataType & >::type operator()( Int coord , Ints ... coords ) { static_assert( sizeof...(coords)+1==Dim , "[ERROR] number of coordinates does not match the number of dimensions" ) ; const Int c[] = { coord , coords ... } ; return operator()( c ); } + template< typename Int , typename ... Ints > typename std::enable_if< std::is_integral< Int >::value , const DataType & >::type operator()( Int coord , Ints ... coords ) const { static_assert( sizeof...(coords)+1==Dim , "[ERROR] number of coordinates does not match the number of dimensions" ) ; const Int c[] = { coord , coords ... } ; return operator()( c ); } + + template< typename Real > typename std::enable_if< !std::is_integral< Real >::value , ProjectiveData< Real , DataType > >::type operator()( Real coords[] ) { return _Sample( _res , coords , _values ); } + template< typename Real > typename std::enable_if< !std::is_integral< Real >::value , ProjectiveData< Real , DataType > >::type operator()( const Real coords[] ) { return _Sample( _res , coords , _values ); } + template< typename Real > typename std::enable_if< !std::is_integral< Real >::value , ProjectiveData< Real , DataType > >::type operator()( Real coords[] ) const { return _Sample( _res , coords , _values ); } + template< typename Real > typename std::enable_if< !std::is_integral< Real >::value , ProjectiveData< Real , DataType > >::type operator()( const Real coords[] ) const { return _Sample( _res , coords , _values ); } + template< typename Real , typename ... Reals > typename std::enable_if< !std::is_integral< Real >::value , ProjectiveData< Real , DataType > >::type operator()( Real coord , Reals ... coords ) { static_assert( sizeof...(coords)+1==Dim , "[ERROR] number of coordinates does not match the number of dimensions" ) ; const Real c[] = { coord , coords ... } ; return operator()( c ); } + template< typename Real , typename ... Reals > typename std::enable_if< !std::is_integral< Real >::value , ProjectiveData< Real , DataType > >::type operator()( Real coord , Reals ... coords ) const { static_assert( sizeof...(coords)+1==Dim , "[ERROR] number of coordinates does not match the number of dimensions" ) ; const Real c[] = { coord , coords ... } ; return operator()( c ); } + template< typename Real > ProjectiveData< Real , DataType > operator()( Point< Real , Dim > coords ) { return operator()( &coords[0] ); } + template< typename Real > ProjectiveData< Real , DataType > operator()( Point< Real , Dim > coords ) const { return operator()( &coords[0] ); } + + template< typename Int > typename std::enable_if< std::is_integral< int >::value , bool >::type inBounds( const Int coords[] ) const { return _inBounds< Dim-1 >( coords ); } + template< typename Int > typename std::enable_if< std::is_integral< int >::value , bool >::type inBounds( Int coords[] ) const { return _inBounds< Dim-1 >( coords ); } + template< typename Int , typename ... Ints > typename std::enable_if< std::is_integral< int >::value , bool >::type inBounds( Ints ... coords ) const { static_assert( sizeof...(coords)+1==Dim , "[ERROR] number of coordinates does not match the number of dimensions" ) ; const Int c[] = { coords ... } ; return inBounds( c ); } + + const unsigned int *res( void ) const { return _res; } + unsigned int res( unsigned int d ) const { return _res[d]; } + size_t resolution( void ) const { return _Resolution< Dim >( _res ); } + + protected: + template< unsigned int D=Dim > static typename std::enable_if< D==1 , size_t >::type _Resolution( const unsigned int res[] ) { return res[0]; } + template< unsigned int D=Dim > static typename std::enable_if< D!=1 , size_t >::type _Resolution( const unsigned int res[] ) { return res[D-1] * _Resolution(res); } + + template< typename Real , unsigned int D=Dim > static typename std::enable_if< D==1 , ProjectiveData< Real , DataType > >::type _Sample( const unsigned int res[] , const Real coords[] , ConstPointer( DataType ) values ); + template< typename Real , unsigned int D=Dim > static typename std::enable_if< D!=1 , ProjectiveData< Real , DataType > >::type _Sample( const unsigned int res[] , const Real coords[] , ConstPointer( DataType ) values ); + + // _index( x[0] , ... , x[D-1] ) = x[0] + ... + x[D-1] * ( res[0] * ... * res[D-1] ) + template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D==Dim-1 && D!=0 , size_t >::type _index( Int coords[] , size_t idx ) const { return _index< Int , D-1 >( coords , coords[D] ); } + template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D!=Dim-1 && D!=0 , size_t >::type _index( Int coords[] , size_t idx ) const { return _index< Int , D-1 >( coords , coords[D] + idx*_res[D] ); } + template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D!=Dim-1 && D==0 , size_t >::type _index( Int coords[] , size_t idx ) const { return coords[D] + idx*_res[D] ; } + template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D==Dim-1 && D==0 , size_t >::type _index( Int coords[] , size_t idx ) const { return coords[D] ; } + template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D==Dim-1 && D!=0 , size_t >::type _index( const Int coords[] , size_t idx ) const { return _index< Int , D-1 >( coords , coords[D] ); } + template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D!=Dim-1 && D!=0 , size_t >::type _index( const Int coords[] , size_t idx ) const { return _index< Int , D-1 >( coords , coords[D] + idx*_res[D] ); } + template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D!=Dim-1 && D==0 , size_t >::type _index( const Int coords[] , size_t idx ) const { return coords[D] + idx*_res[D] ; } + template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D==Dim-1 && D==0 , size_t >::type _index( const Int coords[] , size_t idx ) const { return coords[D] ; } + + template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D!=0 , size_t >::type _setIndex( size_t idx , Int coords[] ) const { idx = _setIndex< Int , D-1 >( idx , coords ) ; coords[D] = (Int)( idx % _res[D] ) ; return idx / _res[D]; } + template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D==0 , size_t >::type _setIndex( size_t idx , Int coords[] ) const { coords[D] = (Int)( idx % _res[D] ) ; return idx / _res[D]; } + + template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D==0 , bool >::type _inBounds( Int coords[] ) const { return coords[0]>=0 && coords[0]<_res[0]; } + template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D!=0 , bool >::type _inBounds( Int coords[] ) const { return coords[D]>=0 && coords[D]<_res[D] && _inBounds< D-1 >( coords ); } + template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D==0 , bool >::type _inBounds( const Int coords[] ) const { return coords[0]>=0 && coords[0]<_res[0]; } + template< typename Int , unsigned int D=Dim-1 > typename std::enable_if< D!=0 , bool >::type _inBounds( const Int coords[] ) const { return coords[D]>=0 && coords[D]<_res[D] && _inBounds< D-1 >( coords ); } + + + unsigned int _res[Dim]; + Pointer( DataType ) _values; + }; #include "RegularGrid.inl" +} + #endif // REGULAR_GRID_INCLUDED diff --git a/Src/RegularGrid.inl b/Src/RegularGrid.inl index 4393cd92..c281ca9e 100644 --- a/Src/RegularGrid.inl +++ b/Src/RegularGrid.inl @@ -26,8 +26,6 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ -#include "MyMiscellany.h" - ///////////////////////// // RegularGridTypeData // ///////////////////////// diff --git a/Src/RegularTree.h b/Src/RegularTree.h index 55eea7ec..f2d31cf3 100644 --- a/Src/RegularTree.h +++ b/Src/RegularTree.h @@ -30,374 +30,382 @@ DAMAGE. #define REGULAR_TREE_NODE_INCLUDED #include +#include +#include +#include #include "Streams.h" #include "Allocator.h" #include "BinaryNode.h" #include "Window.h" +#include "MyMiscellany.h" -template< unsigned int Dim , class NodeData , class DepthAndOffsetType > -struct RegularTreeNode +namespace PoissonRecon { - // This struct temporarily makes a node appear to be a root node by removing the parent reference - struct SubTreeExtractor - { - SubTreeExtractor( RegularTreeNode &root ) : _root(root) - { - _rootParent = _root.parent; - _root.parent = NULL; - _root.depthAndOffset( _depth , _offset ); - int depth=0 , offset[Dim]; - for( unsigned int d=0 ; d - bool _initChildren ( Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ); - template< typename Initializer > - bool _initChildren_s( Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ); -public: - - RegularTreeNode* parent; - RegularTreeNode* children; - NodeData nodeData; - - RegularTreeNode( void ); - static RegularTreeNode* NewBrood( Allocator< RegularTreeNode >* nodeAllocator ) - { - auto initializer = []( RegularTreeNode & ){}; - return NewBrood( nodeAllocator , initializer ); - } - - template< typename Initializer > - RegularTreeNode( Initializer &initializer ); - template< typename Initializer > - static RegularTreeNode* NewBrood( Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ); - template< bool ThreadSafe > - bool initChildren( Allocator< RegularTreeNode >* nodeAllocator ) - { - auto initializer = []( RegularTreeNode & ){}; - return initChildren( nodeAllocator , initializer ); - } - template< bool ThreadSafe , typename Initializer > - bool initChildren( Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ) - { - return ThreadSafe ? _initChildren_s( nodeAllocator , initializer ) : _initChildren( nodeAllocator , initializer ); - } - void cleanChildren( bool deleteChildren ); - static void ResetDepthAndOffset( RegularTreeNode* root , int d , int off[Dim] ); - ~RegularTreeNode( void ); - - // KeepNodeFunctor looks like std::function< bool ( const RegularTreeNode * ) > - template< typename KeepNodeFunctor > - void copySubTree( RegularTreeNode &subTree , const KeepNodeFunctor &keepNodeFunctor , Allocator< RegularTreeNode > *nodeAllocator=NULL ) const; - - template< typename KeepNodeFunctor > - Pointer( RegularTreeNode ) serializeSubTree( const KeepNodeFunctor &keepNodeFunctor , size_t &nodeCount ) const; - - // The merge functor takes two objects of type NodeData and returns an object of type NodeData - // [NOTE] We are assuming that the merge functor is symmetric, f(a,b) = f(b,a), and implicity satisfies f(a) = a - template< class MergeFunctor > - void merge( RegularTreeNode* node , MergeFunctor& f ); - - void depthAndOffset( int& depth , int offset[Dim] ) const; - DepthAndOffset depthAndOffset( void ) const; - void centerIndex( int index[Dim] ) const; - int depth( void ) const; - template< class Real > void centerAndWidth( Point< Real , Dim >& center , Real& width ) const; - template< class Real > void startAndWidth( Point< Real , Dim >& start , Real& width ) const; - template< class Real > bool isInside( Point< Real , Dim > p ) const; - - size_t leaves( void ) const; - size_t maxDepthLeaves( int maxDepth ) const; - size_t nodes( void ) const; - int maxDepth( void ) const; - - const RegularTreeNode* root( void ) const; - - /* These functions apply the functor to the node and all descendents, terminating either at a leaf or when the functor returns false. */ - template< typename NodeFunctor /* = std::function< bool/void ( RegularTreeNode * ) > */ > - void processNodes( NodeFunctor nodeFunctor ); - template< typename NodeFunctor /* = std::function< bool/void ( const RegularTreeNode * ) > */ > - void processNodes( NodeFunctor nodeFunctor ) const; - template< typename NodeFunctor /* = std::function< void ( RegularTreeNode * ) > */ > - void processLeaves( NodeFunctor nodeFunctor ); - template< typename NodeFunctor /* = std::function< void ( const RegularTreeNode * ) > */ > - void processLeaves( NodeFunctor nodeFunctor ) const; -protected: - template< typename NodeFunctor /* = std::function< bool/void ( RegularTreeNode * ) > */ > - void _processChildNodes( NodeFunctor &nodeFunctor ); - template< typename NodeFunctor /* = std::function< bool/void ( const RegularTreeNode * ) > */ > - void _processChildNodes( NodeFunctor &nodeFunctor ) const; - template< typename NodeFunctor /* = std::function< bool/void ( RegularTreeNode * ) > */ > - void _processChildLeaves( NodeFunctor &nodeFunctor ); - template< typename NodeFunctor /* = std::function< bool/void ( const RegularTreeNode * ) > */ > - void _processChildLeaves( NodeFunctor &nodeFunctor ) const; -public: - - void setFullDepth( int maxDepth , Allocator< RegularTreeNode >* nodeAllocator ) - { - auto initializer = []( RegularTreeNode & ){}; - return setFulDepth( nodeAllocator , initializer ); - } - template< typename Initializer > - void setFullDepth( int maxDepth , Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ); - - template< typename PruneChildrenFunctor > - void pruneChildren( const PruneChildrenFunctor pruneFunctor , bool deleteChildren ); - void printLeaves( void ) const; - void printRange( void ) const; - - template< class Real > static int ChildIndex( const Point< Real , Dim >& center , const Point< Real , Dim > &p ); - - // WriteNodeFunctor looks like std::function< bool ( const RegularTreeNode * ) > - template< typename WriteNodeFunctor > - bool write( BinaryStream &stream , bool serialize , const WriteNodeFunctor &writeNodeFunctor ) const; - bool write( BinaryStream &stream , bool serialize ) const { return write( stream , serialize , []( const RegularTreeNode * ){ return true; } ); } - - template< typename Initializer > - bool read( BinaryStream &stream , Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ); - bool read( BinaryStream &stream , Allocator< RegularTreeNode >* nodeAllocator ) - { - auto initializer = []( RegularTreeNode & ){}; - return read( stream , nodeAllocator , initializer ); - } - - template< typename Initializer > - bool read( const char* fileName , Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ); - template< typename Initializer > - bool read( FILE* fp , Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ); - - template< typename Pack > struct Neighbors{}; - template< unsigned int ... Widths > - struct Neighbors< UIntPack< Widths ... > > - { - typedef StaticWindow< RegularTreeNode* , UIntPack< Widths ... > > Window; - Window neighbors; - Neighbors( void ); - void clear( void ); - }; - template< typename Pack > struct ConstNeighbors{}; - template< unsigned int ... Widths > - struct ConstNeighbors< UIntPack< Widths ... > > + template< unsigned int Dim , class NodeData , class DepthAndOffsetType > + struct RegularTreeNode { - typedef StaticWindow< const RegularTreeNode* , UIntPack< Widths ... > > Window; - Window neighbors; - ConstNeighbors( void ); - void clear( void ); - }; - - template< typename LeftPack , typename RightPack > struct NeighborKey{}; - template< unsigned int ... LeftRadii , unsigned int ... RightRadii > - struct NeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > > - { - protected: - static_assert( sizeof...(LeftRadii)==sizeof...(RightRadii) , "[ERROR] Left and right radii dimensions don't match" ); - static const unsigned int CenterIndex = WindowIndex< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > , UIntPack< LeftRadii ... > >::Index; - int _depth; - - template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , unsigned int ... _PLeftRadii , unsigned int ... _PRightRadii , unsigned int ... _CLeftRadii , unsigned int ... _CRightRadii > - static unsigned int _NeighborsLoop( UIntPack< _PLeftRadii ... > , UIntPack< _PRightRadii ... > , UIntPack< _CLeftRadii ... > , UIntPack< _CRightRadii ... > , ConstWindowSlice< RegularTreeNode* , UIntPack< ( _PLeftRadii+_PRightRadii+1 ) ... > > pNeighbors , WindowSlice< RegularTreeNode* , UIntPack< ( _CLeftRadii+_CRightRadii+1 ) ... > > cNeighbors , int cIdx , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ); - - template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , unsigned int ... _PLeftRadii , unsigned int ... _PRightRadii , unsigned int ... _CLeftRadii , unsigned int ... _CRightRadii > - static unsigned int _NeighborsLoop( UIntPack< _PLeftRadii ... > , UIntPack< _PRightRadii ... > , UIntPack< _CLeftRadii ... > , UIntPack< _CRightRadii ... > , WindowSlice< RegularTreeNode* , UIntPack< ( _PLeftRadii+_PRightRadii+1 ) ... > > pNeighbors , WindowSlice< RegularTreeNode* , UIntPack< ( _CLeftRadii+_CRightRadii+1 ) ... > > cNeighbors , int cIdx , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ); - - template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , typename PLeft , typename PRight , typename CLeft , typename CRight > struct _Run{}; - - template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , unsigned int _PLeftRadius , unsigned int ... _PLeftRadii , unsigned int _PRightRadius , unsigned int ... _PRightRadii , unsigned int _CLeftRadius , unsigned int ... _CLeftRadii , unsigned int _CRightRadius , unsigned int ... _CRightRadii > - struct _Run< CreateNodes , ThreadSafe , NodeInitializer , UIntPack< _PLeftRadius , _PLeftRadii ... > , UIntPack< _PRightRadius , _PRightRadii ... > , UIntPack< _CLeftRadius , _CLeftRadii ... > , UIntPack< _CRightRadius , _CRightRadii ... > > + // This struct temporarily makes a node appear to be a root node by removing the parent reference + struct SubTreeExtractor { - static unsigned int Run( ConstWindowSlice< RegularTreeNode* , UIntPack< _PLeftRadius+_PRightRadius+1 , ( _PLeftRadii+_PRightRadii+1 ) ... > > pNeighbors , WindowSlice< RegularTreeNode* , UIntPack< _CLeftRadius+_CRightRadius+1 , ( _CLeftRadii+_CRightRadii+1 ) ... > > cNeighbors , int* c , int cornerIndex , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ); + SubTreeExtractor( RegularTreeNode &root ) : _root(root) + { + _rootParent = _root.parent; + _root.parent = NULL; + _root.depthAndOffset( _depth , _offset ); + int depth=0 , offset[Dim]; + for( unsigned int d=0 ; d - struct _Run< CreateNodes , ThreadSafe , NodeInitializer , UIntPack< _PLeftRadius > , UIntPack< _PRightRadius > , UIntPack< _CLeftRadius > , UIntPack< _CRightRadius > > + struct DepthAndOffset { - static unsigned int Run( ConstWindowSlice< RegularTreeNode* , UIntPack< _PLeftRadius+_PRightRadius+1 > > pNeighbors , WindowSlice< RegularTreeNode* , UIntPack< _CLeftRadius+_CRightRadius+1 > > cNeighbors , int* c , int cornerIndex , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ); + DepthAndOffsetType depth , offset[Dim]; + DepthAndOffset( void ){ depth = 0 , memset( offset , 0 , sizeof(DepthAndOffsetType) * Dim ); } + DepthAndOffset( DepthAndOffsetType d , const DepthAndOffsetType off[] ){ depth = d , memcpy( offset , off , sizeof(DepthAndOffsetType) * Dim ); } + bool operator == ( const DepthAndOffset &doff ) const + { + if( depth!=doff.depth ) return false; + for( int d=0 ; d + bool _initChildren ( Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ); + template< typename Initializer > + bool _initChildren_s( Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ); public: - typedef Neighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > > NeighborType; - NeighborType* neighbors; - - NeighborKey( void ); - NeighborKey( const NeighborKey& key ); - ~NeighborKey( void ); - int depth( void ) const { return _depth; } + RegularTreeNode* parent; + RegularTreeNode* children; + NodeData nodeData; - void set( int depth ); - - template< bool CreateNodes , bool ThreadSafe > - typename RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::template Neighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& getNeighbors( RegularTreeNode* node , Allocator< RegularTreeNode >* nodeAllocator ) + RegularTreeNode( void ); + static RegularTreeNode* NewBrood( Allocator< RegularTreeNode >* nodeAllocator ) { auto initializer = []( RegularTreeNode & ){}; - return getNeighbors( node , nodeAllocator , initializer ); + return NewBrood( nodeAllocator , initializer ); } - template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer > - typename RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::template Neighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& getNeighbors( RegularTreeNode* node , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &nodeInitializer ); - - NeighborType& getNeighbors( const RegularTreeNode* node ) + template< typename Initializer > + RegularTreeNode( Initializer &initializer ); + template< typename Initializer > + static RegularTreeNode* NewBrood( Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ); + template< bool ThreadSafe > + bool initChildren( Allocator< RegularTreeNode >* nodeAllocator ) { auto initializer = []( RegularTreeNode & ){}; - return getNeighbors< false , false >( (RegularTreeNode*)node , NULL , initializer ); + return initChildren( nodeAllocator , initializer ); } - - template< bool CreateNodes , bool ThreadSafe , unsigned int ... _LeftRadii , unsigned int ... _RightRadii > - void getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , RegularTreeNode* node , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors , Allocator< RegularTreeNode >* nodeAllocator ) + template< bool ThreadSafe , typename Initializer > + bool initChildren( Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ) { - auto initializer = []( RegularTreeNode & ){}; - return getNeighbors( UIntPack< _LeftRadii ... >() , UIntPack< _RightRadii ... >() , node , neighbors , nodeAllocator , initializer ); + return ThreadSafe ? _initChildren_s( nodeAllocator , initializer ) : _initChildren( nodeAllocator , initializer ); } + void cleanChildren( bool deleteChildren ); + static void ResetDepthAndOffset( RegularTreeNode* root , int d , int off[Dim] ); + ~RegularTreeNode( void ); + + // KeepNodeFunctor looks like std::function< bool ( const RegularTreeNode * ) > + template< typename KeepNodeFunctor > + void copySubTree( RegularTreeNode &subTree , const KeepNodeFunctor &keepNodeFunctor , Allocator< RegularTreeNode > *nodeAllocator=NULL ) const; + + template< typename KeepNodeFunctor > + Pointer( RegularTreeNode ) serializeSubTree( const KeepNodeFunctor &keepNodeFunctor , size_t &nodeCount ) const; + + // The merge functor takes two objects of type NodeData and returns an object of type NodeData + // [NOTE] We are assuming that the merge functor is symmetric, f(a,b) = f(b,a), and implicity satisfies f(a) = a + template< class MergeFunctor > + void merge( RegularTreeNode* node , MergeFunctor& f ); + + void depthAndOffset( int& depth , int offset[Dim] ) const; + DepthAndOffset depthAndOffset( void ) const; + void centerIndex( int index[Dim] ) const; + int depth( void ) const; + template< class Real > void centerAndWidth( Point< Real , Dim >& center , Real& width ) const; + template< class Real > void startAndWidth( Point< Real , Dim >& start , Real& width ) const; + template< class Real > bool isInside( Point< Real , Dim > p ) const; + + size_t leaves( void ) const; + size_t maxDepthLeaves( int maxDepth ) const; + size_t nodes( void ) const; + int maxDepth( void ) const; + + const RegularTreeNode* root( void ) const; + + /* These functions apply the functor to the node and all descendents, terminating either at a leaf or when the functor returns false. */ + template< typename NodeFunctor /* = std::function< bool/void ( RegularTreeNode * ) > */ > + void processNodes( NodeFunctor nodeFunctor ); + template< typename NodeFunctor /* = std::function< bool/void ( const RegularTreeNode * ) > */ > + void processNodes( NodeFunctor nodeFunctor ) const; + template< typename NodeFunctor /* = std::function< void ( RegularTreeNode * ) > */ > + void processLeaves( NodeFunctor nodeFunctor ); + template< typename NodeFunctor /* = std::function< void ( const RegularTreeNode * ) > */ > + void processLeaves( NodeFunctor nodeFunctor ) const; + protected: + template< typename NodeFunctor /* = std::function< bool/void ( RegularTreeNode * ) > */ > + void _processChildNodes( NodeFunctor &nodeFunctor ); + template< typename NodeFunctor /* = std::function< bool/void ( const RegularTreeNode * ) > */ > + void _processChildNodes( NodeFunctor &nodeFunctor ) const; + template< typename NodeFunctor /* = std::function< bool/void ( RegularTreeNode * ) > */ > + void _processChildLeaves( NodeFunctor &nodeFunctor ); + template< typename NodeFunctor /* = std::function< bool/void ( const RegularTreeNode * ) > */ > + void _processChildLeaves( NodeFunctor &nodeFunctor ) const; + public: - template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , unsigned int ... _LeftRadii , unsigned int ... _RightRadii > - void getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , RegularTreeNode* node , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ); - - template< unsigned int ... _LeftRadii , unsigned int ... _RightRadii > - void getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , const RegularTreeNode* node , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors ) + void setFullDepth( int maxDepth , Allocator< RegularTreeNode >* nodeAllocator ) { auto initializer = []( RegularTreeNode & ){}; - return getNeighbors< false , false >( UIntPack< _LeftRadii ... >() , UIntPack< _RightRadii ... >() , (RegularTreeNode*)node , NULL , initializer ); + return setFulDepth( nodeAllocator , initializer ); } + template< typename Initializer > + void setFullDepth( int maxDepth , Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ); - template< bool CreateNodes , bool ThreadSafe , unsigned int ... _LeftRadii , unsigned int ... _RightRadii > - void getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , RegularTreeNode* node , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& pNeighbors , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors , Allocator< RegularTreeNode >* nodeAllocator ) - { - auto initializer = []( RegularTreeNode & ){}; - return getNeighbors( UIntPack< _LeftRadii ... >() , UIntPack< _RightRadii ... >() , node , pNeighbors , neighbors , nodeAllocator , initializer ); - } + template< typename PruneChildrenFunctor > + void pruneChildren( const PruneChildrenFunctor pruneFunctor , bool deleteChildren ); - template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , unsigned int ... _LeftRadii , unsigned int ... _RightRadii > - void getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , RegularTreeNode* node , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& pNeighbors , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ); + void printLeaves( void ) const; + void printRange( void ) const; - template< unsigned int ... _LeftRadii , unsigned int ... _RightRadii > - void getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , const RegularTreeNode* node , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& pNeighbors , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors ) - { - auto initializer = []( RegularTreeNode & ){}; - return getNeighbors< false , false >( UIntPack< _LeftRadii ... >() , UIntPack< _RightRadii ... >() , (RegularTreeNode*)node , NULL , initializer ); - } + template< class Real > static int ChildIndex( const Point< Real , Dim >& center , const Point< Real , Dim > &p ); - template< bool CreateNodes , bool ThreadSafe > - unsigned int getChildNeighbors( int cIdx , int d , NeighborType& childNeighbors , Allocator< RegularTreeNode >* nodeAllocator ) const - { - auto initializer = []( RegularTreeNode & ){}; - return getChildNeighbors( cIdx , d , childNeighbors , nodeAllocator , initializer ); - } - - template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer > - unsigned int getChildNeighbors( int cIdx , int d , NeighborType& childNeighbors , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ) const; + // WriteNodeFunctor looks like std::function< bool ( const RegularTreeNode * ) > + template< typename WriteNodeFunctor > + bool write( BinaryStream &stream , bool serialize , const WriteNodeFunctor &writeNodeFunctor ) const; + bool write( BinaryStream &stream , bool serialize ) const { return write( stream , serialize , []( const RegularTreeNode * ){ return true; } ); } - unsigned int getChildNeighbors( int cIdx , int d , NeighborType& childNeighbors ) const + template< typename Initializer > + bool read( BinaryStream &stream , Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ); + bool read( BinaryStream &stream , Allocator< RegularTreeNode >* nodeAllocator ) { auto initializer = []( RegularTreeNode & ){}; - return getChildNeighbors< false , false >( cIdx , d , childNeighbors , NULL , initializer ); + return read( stream , nodeAllocator , initializer ); } - template< bool CreateNodes , bool ThreadSafe , class Real > - unsigned int getChildNeighbors( Point< Real , Dim > p , int d , NeighborType& childNeighbors , Allocator< RegularTreeNode >* nodeAllocator ) const - { - auto initializer = []( RegularTreeNode & ){}; - return getChildNeighbors( p , d , childNeighbors , nodeAllocator , initializer ); - } - - template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , class Real > - unsigned int getChildNeighbors( Point< Real , Dim > p , int d , NeighborType& childNeighbors , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ) const; + template< typename Initializer > + bool read( const char* fileName , Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ); + template< typename Initializer > + bool read( FILE* fp , Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ); - template< class Real > - unsigned int getChildNeighbors( Point< Real , Dim > p , int d , NeighborType& childNeighbors ) const + template< typename Pack > struct Neighbors{}; + template< unsigned int ... Widths > + struct Neighbors< UIntPack< Widths ... > > { - auto initializer = []( RegularTreeNode & ){}; - return getChildNeighbors< false , false , Real >( p , d , childNeighbors , NULL , initializer ); - } - - void setLeafNeighbors( RegularTreeNode *node , StaticWindow< RegularTreeNode * , UIntPack< ( LeftRadii + RightRadii + 1 ) ... > > &leaves ); - }; - - template< typename LeftPack , typename RightPack > struct ConstNeighborKey{}; - - template< unsigned int ... LeftRadii , unsigned int ... RightRadii > - struct ConstNeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > > - { - protected: - static_assert( sizeof...(LeftRadii)==sizeof...(RightRadii) , "[ERROR] Left and right radii dimensions don't match" ); - static const unsigned int CenterIndex = WindowIndex< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > , UIntPack< LeftRadii ... > >::Index; - int _depth; - - template< unsigned int ... _PLeftRadii , unsigned int ... _PRightRadii , unsigned int ... _CLeftRadii , unsigned int ... _CRightRadii > - static unsigned int _NeighborsLoop( UIntPack< _PLeftRadii ... > , UIntPack< _PRightRadii ... > , UIntPack< _CLeftRadii ... > , UIntPack< _CRightRadii ... > , ConstWindowSlice< const RegularTreeNode* , UIntPack< ( _PLeftRadii+_PRightRadii+1 ) ... > > pNeighbors , WindowSlice< const RegularTreeNode* , UIntPack< ( _CLeftRadii+_CRightRadii+1 ) ... > > cNeighbors , int cIdx ); - template< unsigned int ... _PLeftRadii , unsigned int ... _PRightRadii , unsigned int ... _CLeftRadii , unsigned int ... _CRightRadii > - static unsigned int _NeighborsLoop( UIntPack< _PLeftRadii ... > , UIntPack< _PRightRadii ... > , UIntPack< _CLeftRadii ... > , UIntPack< _CRightRadii ... > , WindowSlice< const RegularTreeNode* , UIntPack< ( _PLeftRadii+_PRightRadii+1 ) ... > > pNeighbors , WindowSlice< const RegularTreeNode* , UIntPack< ( _CLeftRadii+_CRightRadii+1 ) ... > > cNeighbors , int cIdx ); - - template< typename PLeft , typename PRight , typename CLeft , typename CRight > struct _Run{}; - - template< unsigned int _PLeftRadius , unsigned int ... _PLeftRadii , unsigned int _PRightRadius , unsigned int ... _PRightRadii , unsigned int _CLeftRadius , unsigned int ... _CLeftRadii , unsigned int _CRightRadius , unsigned int ... _CRightRadii > - struct _Run< UIntPack< _PLeftRadius , _PLeftRadii ... > , UIntPack< _PRightRadius , _PRightRadii ... > , UIntPack< _CLeftRadius , _CLeftRadii ... > , UIntPack< _CRightRadius , _CRightRadii ... > > - { - static unsigned int Run( ConstWindowSlice< const RegularTreeNode* , UIntPack< _PLeftRadius + _PRightRadius + 1 , ( _PLeftRadii+_PRightRadii+1 ) ... > > pNeighbors , WindowSlice< const RegularTreeNode* , UIntPack< _CLeftRadius + _CRightRadius + 1 , ( _CLeftRadii+_CRightRadii+1 ) ... > > cNeighbors , int* c , int cornerIndex ); + typedef StaticWindow< RegularTreeNode* , UIntPack< Widths ... > > Window; + Window neighbors; + Neighbors( void ); + void clear( void ); }; - template< unsigned int _PLeftRadius , unsigned int _PRightRadius , unsigned int _CLeftRadius , unsigned int _CRightRadius > - struct _Run< UIntPack< _PLeftRadius > , UIntPack< _PRightRadius > , UIntPack< _CLeftRadius > , UIntPack< _CRightRadius > > + template< typename Pack > struct ConstNeighbors{}; + template< unsigned int ... Widths > + struct ConstNeighbors< UIntPack< Widths ... > > { - static unsigned int Run( ConstWindowSlice< const RegularTreeNode* , UIntPack< _PLeftRadius+_PRightRadius+1 > > pNeighbors , WindowSlice< const RegularTreeNode* , UIntPack< _CLeftRadius+_CRightRadius+1 > > cNeighbors , int* c , int cornerIndex ); + typedef StaticWindow< const RegularTreeNode* , UIntPack< Widths ... > > Window; + Window neighbors; + ConstNeighbors( void ); + void clear( void ); }; - public: - - typedef ConstNeighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > > NeighborType; - NeighborType* neighbors; - - ConstNeighborKey( void ); - ConstNeighborKey( const ConstNeighborKey& key ); - ~ConstNeighborKey( void ); - ConstNeighborKey& operator = ( const ConstNeighborKey& key ); + template< typename LeftPack , typename RightPack > struct NeighborKey{}; + template< unsigned int ... LeftRadii , unsigned int ... RightRadii > + struct NeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > > + { + protected: + static_assert( sizeof...(LeftRadii)==sizeof...(RightRadii) , "[ERROR] Left and right radii dimensions don't match" ); + static const unsigned int CenterIndex = WindowIndex< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > , UIntPack< LeftRadii ... > >::Index; + int _depth; + + template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , unsigned int ... _PLeftRadii , unsigned int ... _PRightRadii , unsigned int ... _CLeftRadii , unsigned int ... _CRightRadii > + static unsigned int _NeighborsLoop( UIntPack< _PLeftRadii ... > , UIntPack< _PRightRadii ... > , UIntPack< _CLeftRadii ... > , UIntPack< _CRightRadii ... > , ConstWindowSlice< RegularTreeNode* , UIntPack< ( _PLeftRadii+_PRightRadii+1 ) ... > > pNeighbors , WindowSlice< RegularTreeNode* , UIntPack< ( _CLeftRadii+_CRightRadii+1 ) ... > > cNeighbors , int cIdx , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ); + + template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , unsigned int ... _PLeftRadii , unsigned int ... _PRightRadii , unsigned int ... _CLeftRadii , unsigned int ... _CRightRadii > + static unsigned int _NeighborsLoop( UIntPack< _PLeftRadii ... > , UIntPack< _PRightRadii ... > , UIntPack< _CLeftRadii ... > , UIntPack< _CRightRadii ... > , WindowSlice< RegularTreeNode* , UIntPack< ( _PLeftRadii+_PRightRadii+1 ) ... > > pNeighbors , WindowSlice< RegularTreeNode* , UIntPack< ( _CLeftRadii+_CRightRadii+1 ) ... > > cNeighbors , int cIdx , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ); + + template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , typename PLeft , typename PRight , typename CLeft , typename CRight > struct _Run{}; + + template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , unsigned int _PLeftRadius , unsigned int ... _PLeftRadii , unsigned int _PRightRadius , unsigned int ... _PRightRadii , unsigned int _CLeftRadius , unsigned int ... _CLeftRadii , unsigned int _CRightRadius , unsigned int ... _CRightRadii > + struct _Run< CreateNodes , ThreadSafe , NodeInitializer , UIntPack< _PLeftRadius , _PLeftRadii ... > , UIntPack< _PRightRadius , _PRightRadii ... > , UIntPack< _CLeftRadius , _CLeftRadii ... > , UIntPack< _CRightRadius , _CRightRadii ... > > + { + static unsigned int Run( ConstWindowSlice< RegularTreeNode* , UIntPack< _PLeftRadius+_PRightRadius+1 , ( _PLeftRadii+_PRightRadii+1 ) ... > > pNeighbors , WindowSlice< RegularTreeNode* , UIntPack< _CLeftRadius+_CRightRadius+1 , ( _CLeftRadii+_CRightRadii+1 ) ... > > cNeighbors , int* c , int cornerIndex , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ); + }; + template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , unsigned int _PLeftRadius , unsigned int _PRightRadius , unsigned int _CLeftRadius , unsigned int _CRightRadius > + struct _Run< CreateNodes , ThreadSafe , NodeInitializer , UIntPack< _PLeftRadius > , UIntPack< _PRightRadius > , UIntPack< _CLeftRadius > , UIntPack< _CRightRadius > > + { + static unsigned int Run( ConstWindowSlice< RegularTreeNode* , UIntPack< _PLeftRadius+_PRightRadius+1 > > pNeighbors , WindowSlice< RegularTreeNode* , UIntPack< _CLeftRadius+_CRightRadius+1 > > cNeighbors , int* c , int cornerIndex , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ); + }; + public: + typedef Neighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > > NeighborType; + NeighborType* neighbors; + + + NeighborKey( void ); + NeighborKey( const NeighborKey& key ); + ~NeighborKey( void ); + int depth( void ) const { return _depth; } + + void set( int depth ); + + template< bool CreateNodes , bool ThreadSafe > + typename RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::template Neighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& getNeighbors( RegularTreeNode* node , Allocator< RegularTreeNode >* nodeAllocator ) + { + auto initializer = []( RegularTreeNode & ){}; + return getNeighbors( node , nodeAllocator , initializer ); + } + + template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer > + typename RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::template Neighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& getNeighbors( RegularTreeNode* node , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &nodeInitializer ); + + NeighborType& getNeighbors( const RegularTreeNode* node ) + { + auto initializer = []( RegularTreeNode & ){}; + return getNeighbors< false , false >( (RegularTreeNode*)node , NULL , initializer ); + } + + template< bool CreateNodes , bool ThreadSafe , unsigned int ... _LeftRadii , unsigned int ... _RightRadii > + void getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , RegularTreeNode* node , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors , Allocator< RegularTreeNode >* nodeAllocator ) + { + auto initializer = []( RegularTreeNode & ){}; + return getNeighbors( UIntPack< _LeftRadii ... >() , UIntPack< _RightRadii ... >() , node , neighbors , nodeAllocator , initializer ); + } + + template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , unsigned int ... _LeftRadii , unsigned int ... _RightRadii > + void getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , RegularTreeNode* node , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ); + + template< unsigned int ... _LeftRadii , unsigned int ... _RightRadii > + void getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , const RegularTreeNode* node , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors ) + { + auto initializer = []( RegularTreeNode & ){}; + return getNeighbors< false , false >( UIntPack< _LeftRadii ... >() , UIntPack< _RightRadii ... >() , (RegularTreeNode*)node , NULL , initializer ); + } + + template< bool CreateNodes , bool ThreadSafe , unsigned int ... _LeftRadii , unsigned int ... _RightRadii > + void getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , RegularTreeNode* node , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& pNeighbors , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors , Allocator< RegularTreeNode >* nodeAllocator ) + { + auto initializer = []( RegularTreeNode & ){}; + return getNeighbors( UIntPack< _LeftRadii ... >() , UIntPack< _RightRadii ... >() , node , pNeighbors , neighbors , nodeAllocator , initializer ); + } + + template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , unsigned int ... _LeftRadii , unsigned int ... _RightRadii > + void getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , RegularTreeNode* node , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& pNeighbors , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ); + + template< unsigned int ... _LeftRadii , unsigned int ... _RightRadii > + void getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , const RegularTreeNode* node , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& pNeighbors , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors ) + { + auto initializer = []( RegularTreeNode & ){}; + return getNeighbors< false , false >( UIntPack< _LeftRadii ... >() , UIntPack< _RightRadii ... >() , (RegularTreeNode*)node , NULL , initializer ); + } + + template< bool CreateNodes , bool ThreadSafe > + unsigned int getChildNeighbors( int cIdx , int d , NeighborType& childNeighbors , Allocator< RegularTreeNode >* nodeAllocator ) const + { + auto initializer = []( RegularTreeNode & ){}; + return getChildNeighbors( cIdx , d , childNeighbors , nodeAllocator , initializer ); + } + + template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer > + unsigned int getChildNeighbors( int cIdx , int d , NeighborType& childNeighbors , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ) const; + + unsigned int getChildNeighbors( int cIdx , int d , NeighborType& childNeighbors ) const + { + auto initializer = []( RegularTreeNode & ){}; + return getChildNeighbors< false , false >( cIdx , d , childNeighbors , NULL , initializer ); + } + + template< bool CreateNodes , bool ThreadSafe , class Real > + unsigned int getChildNeighbors( Point< Real , Dim > p , int d , NeighborType& childNeighbors , Allocator< RegularTreeNode >* nodeAllocator ) const + { + auto initializer = []( RegularTreeNode & ){}; + return getChildNeighbors( p , d , childNeighbors , nodeAllocator , initializer ); + } + + template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , class Real > + unsigned int getChildNeighbors( Point< Real , Dim > p , int d , NeighborType& childNeighbors , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ) const; + + template< class Real > + unsigned int getChildNeighbors( Point< Real , Dim > p , int d , NeighborType& childNeighbors ) const + { + auto initializer = []( RegularTreeNode & ){}; + return getChildNeighbors< false , false , Real >( p , d , childNeighbors , NULL , initializer ); + } + + void setLeafNeighbors( RegularTreeNode *node , StaticWindow< RegularTreeNode * , UIntPack< ( LeftRadii + RightRadii + 1 ) ... > > &leaves ); + }; - int depth( void ) const { return _depth; } - void set( int depth ); + template< typename LeftPack , typename RightPack > struct ConstNeighborKey{}; - typename RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::template ConstNeighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& getNeighbors( const RegularTreeNode* node ); - template< unsigned int ... _LeftRadii , unsigned int ... _RightRadii > - void getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , const RegularTreeNode* node , ConstNeighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors ); - template< unsigned int ... _LeftRadii , unsigned int ... _RightRadii > - void getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , const RegularTreeNode* node , ConstNeighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& pNeighbors , ConstNeighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors ); - unsigned int getChildNeighbors( int cIdx , int d , NeighborType& childNeighbors ) const; - template< class Real > - unsigned int getChildNeighbors( Point< Real , Dim > p , int d , ConstNeighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& childNeighbors ) const; + template< unsigned int ... LeftRadii , unsigned int ... RightRadii > + struct ConstNeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > > + { + protected: + static_assert( sizeof...(LeftRadii)==sizeof...(RightRadii) , "[ERROR] Left and right radii dimensions don't match" ); + static const unsigned int CenterIndex = WindowIndex< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > , UIntPack< LeftRadii ... > >::Index; + int _depth; + + template< unsigned int ... _PLeftRadii , unsigned int ... _PRightRadii , unsigned int ... _CLeftRadii , unsigned int ... _CRightRadii > + static unsigned int _NeighborsLoop( UIntPack< _PLeftRadii ... > , UIntPack< _PRightRadii ... > , UIntPack< _CLeftRadii ... > , UIntPack< _CRightRadii ... > , ConstWindowSlice< const RegularTreeNode* , UIntPack< ( _PLeftRadii+_PRightRadii+1 ) ... > > pNeighbors , WindowSlice< const RegularTreeNode* , UIntPack< ( _CLeftRadii+_CRightRadii+1 ) ... > > cNeighbors , int cIdx ); + template< unsigned int ... _PLeftRadii , unsigned int ... _PRightRadii , unsigned int ... _CLeftRadii , unsigned int ... _CRightRadii > + static unsigned int _NeighborsLoop( UIntPack< _PLeftRadii ... > , UIntPack< _PRightRadii ... > , UIntPack< _CLeftRadii ... > , UIntPack< _CRightRadii ... > , WindowSlice< const RegularTreeNode* , UIntPack< ( _PLeftRadii+_PRightRadii+1 ) ... > > pNeighbors , WindowSlice< const RegularTreeNode* , UIntPack< ( _CLeftRadii+_CRightRadii+1 ) ... > > cNeighbors , int cIdx ); + + template< typename PLeft , typename PRight , typename CLeft , typename CRight > struct _Run{}; + + template< unsigned int _PLeftRadius , unsigned int ... _PLeftRadii , unsigned int _PRightRadius , unsigned int ... _PRightRadii , unsigned int _CLeftRadius , unsigned int ... _CLeftRadii , unsigned int _CRightRadius , unsigned int ... _CRightRadii > + struct _Run< UIntPack< _PLeftRadius , _PLeftRadii ... > , UIntPack< _PRightRadius , _PRightRadii ... > , UIntPack< _CLeftRadius , _CLeftRadii ... > , UIntPack< _CRightRadius , _CRightRadii ... > > + { + static unsigned int Run( ConstWindowSlice< const RegularTreeNode* , UIntPack< _PLeftRadius + _PRightRadius + 1 , ( _PLeftRadii+_PRightRadii+1 ) ... > > pNeighbors , WindowSlice< const RegularTreeNode* , UIntPack< _CLeftRadius + _CRightRadius + 1 , ( _CLeftRadii+_CRightRadii+1 ) ... > > cNeighbors , int* c , int cornerIndex ); + }; + template< unsigned int _PLeftRadius , unsigned int _PRightRadius , unsigned int _CLeftRadius , unsigned int _CRightRadius > + struct _Run< UIntPack< _PLeftRadius > , UIntPack< _PRightRadius > , UIntPack< _CLeftRadius > , UIntPack< _CRightRadius > > + { + static unsigned int Run( ConstWindowSlice< const RegularTreeNode* , UIntPack< _PLeftRadius+_PRightRadius+1 > > pNeighbors , WindowSlice< const RegularTreeNode* , UIntPack< _CLeftRadius+_CRightRadius+1 > > cNeighbors , int* c , int cornerIndex ); + }; + + public: + + typedef ConstNeighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > > NeighborType; + NeighborType* neighbors; + + ConstNeighborKey( void ); + ConstNeighborKey( const ConstNeighborKey& key ); + ~ConstNeighborKey( void ); + ConstNeighborKey& operator = ( const ConstNeighborKey& key ); + + int depth( void ) const { return _depth; } + void set( int depth ); + + typename RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::template ConstNeighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& getNeighbors( const RegularTreeNode* node ); + template< unsigned int ... _LeftRadii , unsigned int ... _RightRadii > + void getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , const RegularTreeNode* node , ConstNeighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors ); + template< unsigned int ... _LeftRadii , unsigned int ... _RightRadii > + void getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , const RegularTreeNode* node , ConstNeighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& pNeighbors , ConstNeighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors ); + unsigned int getChildNeighbors( int cIdx , int d , NeighborType& childNeighbors ) const; + template< class Real > + unsigned int getChildNeighbors( Point< Real , Dim > p , int d , ConstNeighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& childNeighbors ) const; + + void setLeafNeighbors( const RegularTreeNode *node , StaticWindow< RegularTreeNode * , UIntPack< ( LeftRadii + RightRadii + 1 ) ... > > &leaves ); + }; - void setLeafNeighbors( const RegularTreeNode *node , StaticWindow< RegularTreeNode * , UIntPack< ( LeftRadii + RightRadii + 1 ) ... > > &leaves ); + int width( int maxDepth ) const; }; - int width( int maxDepth ) const; -}; - #include "RegularTree.inl" +} #endif // REGULAR_TREE_NODE_INCLUDED diff --git a/Src/RegularTree.inl b/Src/RegularTree.inl index d6337c4e..8ddfa3dc 100644 --- a/Src/RegularTree.inl +++ b/Src/RegularTree.inl @@ -26,11 +26,6 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ -#include -#include -#include -#include "MyMiscellany.h" - ///////////////////// // RegularTreeNode // ///////////////////// diff --git a/Src/SSDRecon.cpp b/Src/SSDRecon.cpp index 1a04a9fd..35e78f77 100644 --- a/Src/SSDRecon.cpp +++ b/Src/SSDRecon.cpp @@ -45,7 +45,9 @@ DAMAGE. #define DEFAULT_DIMENSION 3 -cmdLineParameter< char* > +using namespace PoissonRecon; + +CmdLineParameter< char* > In( "in" ) , Out( "out" ) , TempDir( "tempDir" ) , @@ -53,7 +55,7 @@ cmdLineParameter< char* > Tree( "tree" ) , Transform( "xForm" ); -cmdLineReadable +CmdLineReadable Performance( "performance" ) , ShowResidual( "showResidual" ) , PolygonMesh( "polygonMesh" ) , @@ -68,7 +70,7 @@ cmdLineReadable Gradients( "gradients" ) , Verbose( "verbose" ); -cmdLineParameter< int > +CmdLineParameter< int > #ifndef FAST_COMPILE Degree( "degree" , Reconstructor::SSD::DefaultFEMDegree ) , #endif // !FAST_COMPILE @@ -93,7 +95,7 @@ cmdLineParameter< int > ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , Threads( "threads" , (int)std::thread::hardware_concurrency() ); -cmdLineParameter< float > +CmdLineParameter< float > DataX( "data" , 32.f ) , SamplesPerNode( "samplesPerNode" , 1.5f ) , Scale( "scale" , 1.1f ) , @@ -107,7 +109,7 @@ cmdLineParameter< float > BiLapWeight ( "biLapWeight" , 1.f ); -cmdLineReadable* params[] = +CmdLineReadable* params[] = { #ifndef FAST_COMPILE &Degree , &BType , @@ -580,7 +582,7 @@ int main( int argc , char* argv[] ) WARN( "Array debugging enabled" ); #endif // ARRAY_DEBUG - cmdLineParse( argc-1 , &argv[1] , params ); + CmdLineParse( argc-1 , &argv[1] , params ); if( MaxMemoryGB.value>0 ) SetPeakMemoryMB( MaxMemoryGB.value<<10 ); ThreadPool::DefaultChunkSize = ThreadChunkSize.value; ThreadPool::DefaultSchedule = (ThreadPool::ScheduleType)ScheduleType.value; diff --git a/Src/Socket.h b/Src/Socket.h index 0b25b671..667c0af5 100644 --- a/Src/Socket.h +++ b/Src/Socket.h @@ -43,101 +43,105 @@ DAMAGE. #include "MyMiscellany.h" #include "Streams.h" -static const unsigned int SOCKET_CONNECT_WAIT = 500; // Default time to wait on a socket (in ms) +namespace PoissonRecon +{ -typedef boost::asio::ip::tcp::socket *Socket; -typedef boost::asio::ip::tcp::acceptor *AcceptorSocket; -typedef boost::asio::ip::address EndpointAddress; -const Socket _INVALID_SOCKET_ = (Socket)NULL; -const AcceptorSocket _INVALID_ACCEPTOR_SOCKET_ = (AcceptorSocket)NULL; -static boost::asio::io_service io_service; + static const unsigned int SOCKET_CONNECT_WAIT = 500; // Default time to wait on a socket (in ms) -template< class C > int socket_receive( Socket &s , C *destination , size_t len ) -{ - boost::system::error_code ec; - int ret = (int)( boost::asio::read( *s , boost::asio::buffer( destination , len ) , ec ) ); - if( ec ) ERROR_OUT( "Failed to read from socket" ); - return ret; -} + typedef boost::asio::ip::tcp::socket *Socket; + typedef boost::asio::ip::tcp::acceptor *AcceptorSocket; + typedef boost::asio::ip::address EndpointAddress; + const Socket _INVALID_SOCKET_ = (Socket)NULL; + const AcceptorSocket _INVALID_ACCEPTOR_SOCKET_ = (AcceptorSocket)NULL; + static boost::asio::io_service io_service; -template< class C > int socket_send( Socket& s , const C* source , size_t len ) -{ - boost::system::error_code ec; - int ret = (int)( boost::asio::write( *s , boost::asio::buffer( source , len ) , ec ) ); - if( ec ) ERROR_OUT( "Failed to write to socket" ); - return ret; -} + template< class C > int socket_receive( Socket &s , C *destination , size_t len ) + { + boost::system::error_code ec; + int ret = (int)( boost::asio::read( *s , boost::asio::buffer( destination , len ) , ec ) ); + if( ec ) ERROR_OUT( "Failed to read from socket" ); + return ret; + } -inline bool AddressesEqual( const EndpointAddress& a1 , const EndpointAddress& a2 ){ return a1.to_string()==a2.to_string(); } -inline const char *LastSocketError( void ){ return ""; } -inline void PrintHostAddresses( FILE* fp ) -{ - boost::asio::ip::tcp::resolver resolver( io_service ); - boost::asio::ip::tcp::resolver::query query( boost::asio::ip::host_name() , std::string( "" ) , boost::asio::ip::resolver_query_base::numeric_service ); - boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve( query ) , end; - for( int count=0 ; iterator!=end ; ) + template< class C > int socket_send( Socket& s , const C* source , size_t len ) { - if( (*iterator).endpoint().address().is_v4() ) fprintf( fp , "%d] %s\n" , count++ , (*iterator).endpoint().address().to_string().c_str() ); - // else fprintf( fp , "%d]* %s\n" , count++ , (*iterator).endpoint().address().to_string().c_str() ); - iterator++; + boost::system::error_code ec; + int ret = (int)( boost::asio::write( *s , boost::asio::buffer( source , len ) , ec ) ); + if( ec ) ERROR_OUT( "Failed to write to socket" ); + return ret; + } + + inline bool AddressesEqual( const EndpointAddress& a1 , const EndpointAddress& a2 ){ return a1.to_string()==a2.to_string(); } + inline const char *LastSocketError( void ){ return ""; } + inline void PrintHostAddresses( FILE* fp ) + { + boost::asio::ip::tcp::resolver resolver( io_service ); + boost::asio::ip::tcp::resolver::query query( boost::asio::ip::host_name() , std::string( "" ) , boost::asio::ip::resolver_query_base::numeric_service ); + boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve( query ) , end; + for( int count=0 ; iterator!=end ; ) + { + if( (*iterator).endpoint().address().is_v4() ) fprintf( fp , "%d] %s\n" , count++ , (*iterator).endpoint().address().to_string().c_str() ); + // else fprintf( fp , "%d]* %s\n" , count++ , (*iterator).endpoint().address().to_string().c_str() ); + iterator++; + } } -} #ifdef ARRAY_DEBUG -template< class C > -int socket_receive( Socket& s , Array< C > destination , size_t len ) -{ - if( len>destination.maximum()*sizeof( C ) ) - ERROR_OUT( "Size of socket_receive exceeds destination maximum: " , len , " > " , destination.maximum()*sizeof( C ) ); - return socket_receive( s , (char*)&destination[0] , len ); -} -template< class C > -int socket_send( Socket s , ConstArray< C > source , size_t len ) -{ - if( len>source.maximum()*sizeof( C ) ) - ERROR_OUT( "Size of socket_send exceeds source maximum: " , len , " > " , source.maximum()*sizeof( C ) ); - return socket_send( s , (char*)&source[0] , len ); -} + template< class C > + int socket_receive( Socket& s , Array< C > destination , size_t len ) + { + if( len>destination.maximum()*sizeof( C ) ) + ERROR_OUT( "Size of socket_receive exceeds destination maximum: " , len , " > " , destination.maximum()*sizeof( C ) ); + return socket_receive( s , (char*)&destination[0] , len ); + } + template< class C > + int socket_send( Socket s , ConstArray< C > source , size_t len ) + { + if( len>source.maximum()*sizeof( C ) ) + ERROR_OUT( "Size of socket_send exceeds source maximum: " , len , " > " , source.maximum()*sizeof( C ) ); + return socket_send( s , (char*)&source[0] , len ); + } #endif // ARRAY_DEBUG -class ConnectionData -{ -public: - EndpointAddress localAddr , peerAddr; - int localPort , peerPort; -}; - - -template< class C > bool ReceiveOnSocket( Socket &s , Pointer( C ) data , size_t dataSize ); -template< class C > bool SendOnSocket ( Socket &s , ConstPointer( C ) data , size_t dataSize ); -template< class C > bool SendOnSocket ( Socket &s , Pointer( C ) data , size_t dataSize ); -template< class C > void ReceiveOnSocket( Socket &s , Pointer( C ) data , size_t dataSize , const char *errorMessage , ... ); -template< class C > void SendOnSocket ( Socket &s , ConstPointer( C ) data , size_t dataSize , const char *errorMessage , ... ); -template< class C > void SendOnSocket ( Socket &s , Pointer( C ) data , size_t dataSize , const char *errorMessage , ... ); - -AcceptorSocket GetListenSocket( int& port ); -Socket AcceptSocket( AcceptorSocket listen ); -Socket GetConnectSocket( const char* address , int port , int ms=5 , bool progress=false ); -Socket GetConnectSocket( EndpointAddress , int port , int ms=5 , bool progress=false ); -void CloseSocket( Socket& s ); -void CloseAcceptorSocket( AcceptorSocket& s ); -EndpointAddress GetLocalSocketEndpointAddress( Socket& s ); -int GetLocalSocketPort ( Socket& s ); -EndpointAddress GetLocalSocketEndpointAddress( Socket& s ); -int GetPeerSocketPort ( Socket& s ); -bool GetHostAddress( char* address , const char* prefix = NULL ); -bool GetHostEndpointAddress( EndpointAddress* address , const char* prefix=NULL ); -void PrintHostAddress( void ); - -struct SocketStream : public BinaryStream -{ - SocketStream( Socket socket=_INVALID_SOCKET_ ) : _socket(socket){} -protected: - Socket _socket; - bool _read( Pointer( unsigned char ) ptr , size_t sz ){ return socket_receive( _socket , ptr , sizeof(unsigned char)*sz )==sz; } - bool _write( ConstPointer( unsigned char ) ptr , size_t sz ){ return socket_send ( _socket , ptr , sizeof(unsigned char)*sz )==sz; } -}; + class ConnectionData + { + public: + EndpointAddress localAddr , peerAddr; + int localPort , peerPort; + }; + + + template< class C > bool ReceiveOnSocket( Socket &s , Pointer( C ) data , size_t dataSize ); + template< class C > bool SendOnSocket ( Socket &s , ConstPointer( C ) data , size_t dataSize ); + template< class C > bool SendOnSocket ( Socket &s , Pointer( C ) data , size_t dataSize ); + template< class C > void ReceiveOnSocket( Socket &s , Pointer( C ) data , size_t dataSize , const char *errorMessage , ... ); + template< class C > void SendOnSocket ( Socket &s , ConstPointer( C ) data , size_t dataSize , const char *errorMessage , ... ); + template< class C > void SendOnSocket ( Socket &s , Pointer( C ) data , size_t dataSize , const char *errorMessage , ... ); + + AcceptorSocket GetListenSocket( int& port ); + Socket AcceptSocket( AcceptorSocket listen ); + Socket GetConnectSocket( const char* address , int port , int ms=5 , bool progress=false ); + Socket GetConnectSocket( EndpointAddress , int port , int ms=5 , bool progress=false ); + void CloseSocket( Socket& s ); + void CloseAcceptorSocket( AcceptorSocket& s ); + EndpointAddress GetLocalSocketEndpointAddress( Socket& s ); + int GetLocalSocketPort ( Socket& s ); + EndpointAddress GetLocalSocketEndpointAddress( Socket& s ); + int GetPeerSocketPort ( Socket& s ); + bool GetHostAddress( char* address , const char* prefix = NULL ); + bool GetHostEndpointAddress( EndpointAddress* address , const char* prefix=NULL ); + void PrintHostAddress( void ); + + struct SocketStream : public BinaryStream + { + SocketStream( Socket socket=_INVALID_SOCKET_ ) : _socket(socket){} + protected: + Socket _socket; + bool _read( Pointer( unsigned char ) ptr , size_t sz ){ return socket_receive( _socket , ptr , sizeof(unsigned char)*sz )==sz; } + bool _write( ConstPointer( unsigned char ) ptr , size_t sz ){ return socket_send ( _socket , ptr , sizeof(unsigned char)*sz )==sz; } + }; #include "Socket.inl" +} #endif // SOCKET_INCLUDED diff --git a/Src/SparseMatrix.h b/Src/SparseMatrix.h index ee2487c1..19867187 100644 --- a/Src/SparseMatrix.h +++ b/Src/SparseMatrix.h @@ -28,127 +28,135 @@ DAMAGE. #ifndef SPARSE_MATRIX_INCLUDED #define SPARSE_MATRIX_INCLUDED +#include +#include +#include #include "SparseMatrixInterface.h" #include "Array.h" -template< class T , class IndexType , size_t MaxRowSize=0 > class SparseMatrix; - -template< class T , class IndexType > class SparseMatrix< T , IndexType , 0 > : public SparseMatrixInterface< T , ConstPointer( MatrixEntry< T , IndexType > ) > +namespace PoissonRecon { - template< class T2 , class IndexType2 , size_t MaxRowSize2 > friend class SparseMatrix; - Pointer( Pointer( MatrixEntry< T , IndexType > ) ) _entries; -public: - static void Swap( SparseMatrix& M1 , SparseMatrix& M2 ) + + template< class T , class IndexType , size_t MaxRowSize=0 > class SparseMatrix; + + template< class T , class IndexType > class SparseMatrix< T , IndexType , 0 > : public SparseMatrixInterface< T , ConstPointer( MatrixEntry< T , IndexType > ) > { - std::swap( M1.rowNum , M2.rowNum ); - std::swap( M1.rowSizes , M2.rowSizes ); - std::swap( M1._entries , M2._entries ); - } - typedef SparseMatrixInterface< T , ConstPointer( MatrixEntry< T , IndexType > ) > Interface; - typedef ConstPointer( MatrixEntry< T , IndexType > ) RowIterator; - - size_t rowNum; - Pointer( size_t ) rowSizes; - - SparseMatrix( void ); - SparseMatrix( const SparseMatrix& M ); - SparseMatrix( SparseMatrix&& M ); - template< class T2 , class IndexType2 > - SparseMatrix( const SparseMatrix< T2 , IndexType2 , 0 >& M ); - ~SparseMatrix(); - SparseMatrix& operator = ( SparseMatrix&& M ); - SparseMatrix< T , IndexType >& operator = ( const SparseMatrix< T , IndexType >& M ); - template< class T2 , class IndexType2 > - SparseMatrix< T , IndexType , 0 >& operator = ( const SparseMatrix< T2 , IndexType2 , 0 >& M ); - - template< class T2 > void operator()( const T2* in , T2* out ) const; - - template< class T2 , class IndexType2 > - SparseMatrix< T , IndexType , 0 >& copy( const SparseMatrix< T2 , IndexType2 , 0 >& M ); - - inline ConstPointer( MatrixEntry< T , IndexType > ) begin( size_t row ) const { return _entries[row]; } - inline ConstPointer( MatrixEntry< T , IndexType > ) end ( size_t row ) const { return _entries[row] + (unsigned long long)rowSizes[row]; } - inline size_t rows ( void ) const { return rowNum; } - inline size_t rowSize ( size_t idx ) const { return rowSizes[idx]; } - - SparseMatrix( size_t rowNum ); - void resize ( size_t rowNum ); - void setRowSize( size_t row , size_t count ); - void resetRowSize( size_t row , size_t count ); - inline Pointer( MatrixEntry< T , IndexType > ) operator[] ( size_t idx ) { return _entries[idx]; } - inline ConstPointer( MatrixEntry< T , IndexType > ) operator[] ( size_t idx ) const { return _entries[idx]; } - - // With copy move, these should be well-behaved from a memory perspective - static SparseMatrix Identity( size_t dim ); - SparseMatrix transpose( T (*TransposeFunction)( const T& )=NULL ) const; - SparseMatrix transpose( size_t outRows , T (*TransposeFunction)( const T& )=NULL ) const; - SparseMatrix operator * ( T s ) const; - SparseMatrix operator / ( T s ) const; - SparseMatrix operator * ( const SparseMatrix& M ) const; - SparseMatrix operator + ( const SparseMatrix& M ) const; - SparseMatrix operator - ( const SparseMatrix& M ) const; - SparseMatrix& operator *= ( T s ); - SparseMatrix& operator /= ( T s ); - SparseMatrix& operator *= ( const SparseMatrix& M ); - SparseMatrix& operator += ( const SparseMatrix& M ); - SparseMatrix& operator -= ( const SparseMatrix& M ); - - template< class A_const_iterator , class B_const_iterator > - static SparseMatrix Multiply( const SparseMatrixInterface< T , A_const_iterator >& A , const SparseMatrixInterface< T , B_const_iterator >& B ); - template< class const_iterator > - static SparseMatrix Transpose( const SparseMatrixInterface< T , const_iterator >& At , T (*TransposeFunction)( const T& )=NULL ); - template< class const_iterator > - static SparseMatrix Transpose( const SparseMatrixInterface< T , const_iterator >& At , size_t outRows , T (*TransposeFunction)( const T& )=NULL ); -}; - -template< class T , class IndexType , size_t MaxRowSize > class SparseMatrix : public SparseMatrixInterface< T , ConstPointer( MatrixEntry< T , IndexType > ) > -{ - template< class T2 , class IndexType2 > friend class _SparseMatrix; - Pointer( MatrixEntry< T , IndexType > ) _entries; - size_t _rowNum; - Pointer( size_t ) _rowSizes; - size_t _maxRows; -public: - static void Swap( SparseMatrix& M1 , SparseMatrix& M2 ) + template< class T2 , class IndexType2 , size_t MaxRowSize2 > friend class SparseMatrix; + Pointer( Pointer( MatrixEntry< T , IndexType > ) ) _entries; + public: + static void Swap( SparseMatrix& M1 , SparseMatrix& M2 ) + { + std::swap( M1.rowNum , M2.rowNum ); + std::swap( M1.rowSizes , M2.rowSizes ); + std::swap( M1._entries , M2._entries ); + } + typedef SparseMatrixInterface< T , ConstPointer( MatrixEntry< T , IndexType > ) > Interface; + typedef ConstPointer( MatrixEntry< T , IndexType > ) RowIterator; + + size_t rowNum; + Pointer( size_t ) rowSizes; + + SparseMatrix( void ); + SparseMatrix( const SparseMatrix& M ); + SparseMatrix( SparseMatrix&& M ); + template< class T2 , class IndexType2 > + SparseMatrix( const SparseMatrix< T2 , IndexType2 , 0 >& M ); + ~SparseMatrix(); + SparseMatrix& operator = ( SparseMatrix&& M ); + SparseMatrix< T , IndexType >& operator = ( const SparseMatrix< T , IndexType >& M ); + template< class T2 , class IndexType2 > + SparseMatrix< T , IndexType , 0 >& operator = ( const SparseMatrix< T2 , IndexType2 , 0 >& M ); + + template< class T2 > void operator()( const T2* in , T2* out ) const; + + template< class T2 , class IndexType2 > + SparseMatrix< T , IndexType , 0 >& copy( const SparseMatrix< T2 , IndexType2 , 0 >& M ); + + inline ConstPointer( MatrixEntry< T , IndexType > ) begin( size_t row ) const { return _entries[row]; } + inline ConstPointer( MatrixEntry< T , IndexType > ) end ( size_t row ) const { return _entries[row] + (unsigned long long)rowSizes[row]; } + inline size_t rows ( void ) const { return rowNum; } + inline size_t rowSize ( size_t idx ) const { return rowSizes[idx]; } + + SparseMatrix( size_t rowNum ); + void resize ( size_t rowNum ); + void setRowSize( size_t row , size_t count ); + void resetRowSize( size_t row , size_t count ); + inline Pointer( MatrixEntry< T , IndexType > ) operator[] ( size_t idx ) { return _entries[idx]; } + inline ConstPointer( MatrixEntry< T , IndexType > ) operator[] ( size_t idx ) const { return _entries[idx]; } + + // With copy move, these should be well-behaved from a memory perspective + static SparseMatrix Identity( size_t dim ); + SparseMatrix transpose( T (*TransposeFunction)( const T& )=NULL ) const; + SparseMatrix transpose( size_t outRows , T (*TransposeFunction)( const T& )=NULL ) const; + SparseMatrix operator * ( T s ) const; + SparseMatrix operator / ( T s ) const; + SparseMatrix operator * ( const SparseMatrix& M ) const; + SparseMatrix operator + ( const SparseMatrix& M ) const; + SparseMatrix operator - ( const SparseMatrix& M ) const; + SparseMatrix& operator *= ( T s ); + SparseMatrix& operator /= ( T s ); + SparseMatrix& operator *= ( const SparseMatrix& M ); + SparseMatrix& operator += ( const SparseMatrix& M ); + SparseMatrix& operator -= ( const SparseMatrix& M ); + + template< class A_const_iterator , class B_const_iterator > + static SparseMatrix Multiply( const SparseMatrixInterface< T , A_const_iterator >& A , const SparseMatrixInterface< T , B_const_iterator >& B ); + template< class const_iterator > + static SparseMatrix Transpose( const SparseMatrixInterface< T , const_iterator >& At , T (*TransposeFunction)( const T& )=NULL ); + template< class const_iterator > + static SparseMatrix Transpose( const SparseMatrixInterface< T , const_iterator >& At , size_t outRows , T (*TransposeFunction)( const T& )=NULL ); + }; + + template< class T , class IndexType , size_t MaxRowSize > class SparseMatrix : public SparseMatrixInterface< T , ConstPointer( MatrixEntry< T , IndexType > ) > { - std::swap( M1._rowNum , M2._rowNum ); - std::swap( M1._rowSizes , M2._rowSizes ); - std::swap( M1._entries , M2._entries ); - } - typedef SparseMatrixInterface< T , ConstPointer( MatrixEntry< T , IndexType > ) > Interface; - typedef ConstPointer( MatrixEntry< T , IndexType > ) RowIterator; - - SparseMatrix( void ); - SparseMatrix( const SparseMatrix& M ); - SparseMatrix( SparseMatrix&& M ); - template< class T2 , class IndexType2 > - SparseMatrix( const SparseMatrix< T2 , IndexType2 , MaxRowSize >& M ); - SparseMatrix& operator = ( SparseMatrix&& M ); - SparseMatrix< T , IndexType , MaxRowSize >& operator = ( const SparseMatrix< T , IndexType , MaxRowSize >& M ); - template< class T2 , class IndexType2 > - SparseMatrix< T , IndexType , MaxRowSize >& operator = ( const SparseMatrix< T2 , IndexType2 , MaxRowSize >& M ); - ~SparseMatrix( void ); - - template< class T2 > void operator()( const T2* in , T2* out ) const; - - inline ConstPointer( MatrixEntry< T , IndexType > ) begin( size_t row ) const { return _entries + MaxRowSize * row; } - inline ConstPointer( MatrixEntry< T , IndexType > ) end ( size_t row ) const { return _entries + MaxRowSize * row + (unsigned long long)_rowSizes[row]; } - inline size_t rows ( void ) const { return _rowNum; } - inline size_t rowSize ( size_t idx ) const { return _rowSizes[idx]; } - - SparseMatrix( size_t rowNum ); - void resize ( size_t rowNum ); - void setRowSize( size_t row , size_t rowSize ); - void resetRowSize( size_t row , size_t rowSize ); - inline Pointer( MatrixEntry< T , IndexType > ) operator[] ( size_t idx ) { return _entries + MaxRowSize * idx; } - inline ConstPointer( MatrixEntry< T , IndexType > ) operator[] ( size_t idx ) const { return _entries + MaxRowSize * idx; } - - // With copy move, these should be well-behaved from a memory perspective - SparseMatrix operator * ( T s ) const; - SparseMatrix operator / ( T s ) const; - SparseMatrix& operator *= ( T s ); - SparseMatrix& operator /= ( T s ); -}; + template< class T2 , class IndexType2 > friend class _SparseMatrix; + Pointer( MatrixEntry< T , IndexType > ) _entries; + size_t _rowNum; + Pointer( size_t ) _rowSizes; + size_t _maxRows; + public: + static void Swap( SparseMatrix& M1 , SparseMatrix& M2 ) + { + std::swap( M1._rowNum , M2._rowNum ); + std::swap( M1._rowSizes , M2._rowSizes ); + std::swap( M1._entries , M2._entries ); + } + typedef SparseMatrixInterface< T , ConstPointer( MatrixEntry< T , IndexType > ) > Interface; + typedef ConstPointer( MatrixEntry< T , IndexType > ) RowIterator; + + SparseMatrix( void ); + SparseMatrix( const SparseMatrix& M ); + SparseMatrix( SparseMatrix&& M ); + template< class T2 , class IndexType2 > + SparseMatrix( const SparseMatrix< T2 , IndexType2 , MaxRowSize >& M ); + SparseMatrix& operator = ( SparseMatrix&& M ); + SparseMatrix< T , IndexType , MaxRowSize >& operator = ( const SparseMatrix< T , IndexType , MaxRowSize >& M ); + template< class T2 , class IndexType2 > + SparseMatrix< T , IndexType , MaxRowSize >& operator = ( const SparseMatrix< T2 , IndexType2 , MaxRowSize >& M ); + ~SparseMatrix( void ); + + template< class T2 > void operator()( const T2* in , T2* out ) const; + + inline ConstPointer( MatrixEntry< T , IndexType > ) begin( size_t row ) const { return _entries + MaxRowSize * row; } + inline ConstPointer( MatrixEntry< T , IndexType > ) end ( size_t row ) const { return _entries + MaxRowSize * row + (unsigned long long)_rowSizes[row]; } + inline size_t rows ( void ) const { return _rowNum; } + inline size_t rowSize ( size_t idx ) const { return _rowSizes[idx]; } + + SparseMatrix( size_t rowNum ); + void resize ( size_t rowNum ); + void setRowSize( size_t row , size_t rowSize ); + void resetRowSize( size_t row , size_t rowSize ); + inline Pointer( MatrixEntry< T , IndexType > ) operator[] ( size_t idx ) { return _entries + MaxRowSize * idx; } + inline ConstPointer( MatrixEntry< T , IndexType > ) operator[] ( size_t idx ) const { return _entries + MaxRowSize * idx; } + + // With copy move, these should be well-behaved from a memory perspective + SparseMatrix operator * ( T s ) const; + SparseMatrix operator / ( T s ) const; + SparseMatrix& operator *= ( T s ); + SparseMatrix& operator /= ( T s ); + }; #include "SparseMatrix.inl" +} + #endif // SPARSE_MATRIX_INCLUDED diff --git a/Src/SparseMatrix.inl b/Src/SparseMatrix.inl index 5cb16579..b955538f 100644 --- a/Src/SparseMatrix.inl +++ b/Src/SparseMatrix.inl @@ -26,10 +26,6 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ -#include -#include -#include - /////////////////////////////////////////////////////////////// // SparseMatrix (unconstrained max row size specialization) // /////////////////////////////////////////////////////////////// diff --git a/Src/SparseMatrixInterface.h b/Src/SparseMatrixInterface.h index dd4bce19..20f813e2 100644 --- a/Src/SparseMatrixInterface.h +++ b/Src/SparseMatrixInterface.h @@ -29,129 +29,134 @@ DAMAGE. #ifndef SPARSE_MATRIX_INTERFACE_INCLUDED #define SPARSE_MATRIX_INTERFACE_INCLUDED -#define FORCE_TWO_BYTE_ALIGNMENT 1 +#define FORCE_TWO_BYTE_ALIGNMENT #include "MyMiscellany.h" #include "Array.h" -#if FORCE_TWO_BYTE_ALIGNMENT +namespace PoissonRecon +{ + +#ifdef FORCE_TWO_BYTE_ALIGNMENT #pragma pack(push) #pragma pack(2) #endif // FORCE_TWO_BYTE_ALIGNMENT -template< class T , class IndexType > -struct MatrixEntry -{ - MatrixEntry( void ) { N =-1 , Value = 0; } - MatrixEntry( IndexType i ) { N = i , Value = 0; } - MatrixEntry( IndexType n , T v ){ N = n , Value = v; } - IndexType N; - T Value; -}; - -#if FORCE_TWO_BYTE_ALIGNMENT + template< class T , class IndexType > + struct MatrixEntry + { + MatrixEntry( void ) { N =-1 , Value = 0; } + MatrixEntry( IndexType i ) { N = i , Value = 0; } + MatrixEntry( IndexType n , T v ){ N = n , Value = v; } + IndexType N; + T Value; + }; + +#ifdef FORCE_TWO_BYTE_ALIGNMENT #pragma pack(pop) #endif // FORCE_TWO_BYTE_ALIGNMENT -enum -{ - MULTIPLY_ADD = 1 , - MULTIPLY_NEGATE = 2 -}; + enum + { + MULTIPLY_ADD = 1 , + MULTIPLY_NEGATE = 2 + }; -//#pragma message( "[WARNING] make me templated off of IndexType as well" ) -template< class T , class const_iterator > class SparseMatrixInterface -{ -public: - virtual const_iterator begin( size_t row ) const = 0; - virtual const_iterator end ( size_t row ) const = 0; - virtual size_t rows ( void ) const = 0; - virtual size_t rowSize( size_t idx ) const = 0; - - size_t entries( void ) const; - - double squareNorm( void ) const; - double squareASymmetricNorm( void ) const; - double squareASymmetricNorm( size_t &idx1 , size_t &idx2 ) const; - - template< class T2 > void multiply ( ConstPointer( T2 ) In , Pointer( T2 ) Out , char multiplyFlag=0 ) const; - template< class T2 > void multiplyScaled( T scale , ConstPointer( T2 ) In , Pointer( T2 ) Out , char multiplyFlag=0 ) const; - template< class T2 > void multiply ( Pointer( T2 ) In , Pointer( T2 ) Out , char multiplyFlag=0 ) const { multiply ( ( ConstPointer(T2) )( In ) , Out , multiplyFlag ); } - template< class T2 > void multiplyScaled( T scale , Pointer( T2 ) In , Pointer( T2 ) Out , char multiplyFlag=0 ) const { multiplyScaled( scale , ( ConstPointer(T2) )( In ) , Out , multiplyFlag ); } - - void setDiagonal( Pointer( T ) diagonal ) const; - void setDiagonalR( Pointer( T ) diagonal ) const; - template< class T2 > void jacobiIteration( ConstPointer( T ) diagonal , ConstPointer( T2 ) b , ConstPointer( T2 ) in , Pointer( T2 ) out , bool dReciprocal ) const; - template< class T2 > void gsIteration( const std::vector< size_t > & multiColorIndices , ConstPointer( T ) diagonal , ConstPointer( T2 ) b , Pointer( T2 ) x , bool dReciprocal ) const; - template< class T2 > void gsIteration( const std::vector< std::vector< size_t > >& multiColorIndices , ConstPointer( T ) diagonal , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward , bool dReciprocal ) const; - template< class T2 > void gsIteration( ConstPointer( T ) diagonal , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward , bool dReciprocal ) const; -}; - -// Assuming that the SPDOperator class defines: -// auto SPDOperator::()( ConstPointer( T ) , Pointer( T ) ) const -template< class SPDFunctor , class T , typename Real , class TDotTFunctor > size_t SolveCG( const SPDFunctor& M , size_t dim , ConstPointer( T ) b , size_t iters , Pointer( T ) x , double eps , TDotTFunctor Dot ); -template< class SPDFunctor , class Preconditioner , class T , typename Real , class TDotTFunctor > size_t SolveCG( const SPDFunctor& M , const Preconditioner& P , size_t dim , ConstPointer( T ) b , size_t iters , Pointer( T ) x , double eps , TDotTFunctor Dot ); - -template< typename T > -struct AbstractArrayWrapper -{ - virtual T operator[]( size_t i ) const = 0; -}; -template< typename T , typename AbstractArrayWrapper1 , typename AbstractArrayWrapper2 > struct _VectorSum; -template< typename T , typename AbstractArrayWrapper1 , typename AbstractArrayWrapper2 > struct _VectorDifference; -template< typename T , typename Real , typename const_iterator , typename _AbstractArrayWrapper > struct _VectorProduct; - -template< typename T , typename AbstractArrayWrapper1 , typename AbstractArrayWrapper2 > -struct _VectorSum : public AbstractArrayWrapper< T > -{ - _VectorSum( const AbstractArrayWrapper1 &v1 , const AbstractArrayWrapper2 &v2 ) : _v1(v1) , _v2(v2) + //#pragma message( "[WARNING] make me templated off of IndexType as well" ) + template< class T , class const_iterator > class SparseMatrixInterface { - // static_assert( std::is_convertible< AbstractArrayWrapper1 , AbstractArrayWrapper< T > >::value || std::is_convertible< AbstractArrayWrapper1 , ConstPointer(T) >::value , "[ERROR] Bad AbstractArrayWrapper1" ); - // static_assert( std::is_convertible< AbstractArrayWrapper2 , AbstractArrayWrapper< T > >::value || std::is_convertible< AbstractArrayWrapper2 , ConstPointer(T) >::value , "[ERROR] Bad AbstractArrayWrapper2" ); - } - T operator[] ( size_t i ) const { return _v1[i] + _v2[i]; } -protected: - const AbstractArrayWrapper1 &_v1; - const AbstractArrayWrapper2 &_v2; -}; - -template< typename T , typename AbstractArrayWrapper1 , typename AbstractArrayWrapper2 > -struct _VectorDifference : public AbstractArrayWrapper< T > -{ - _VectorDifference( const AbstractArrayWrapper1 &v1 , const AbstractArrayWrapper2 &v2 ) : _v1(v1) , _v2(v2) + public: + virtual const_iterator begin( size_t row ) const = 0; + virtual const_iterator end ( size_t row ) const = 0; + virtual size_t rows ( void ) const = 0; + virtual size_t rowSize( size_t idx ) const = 0; + + size_t entries( void ) const; + + double squareNorm( void ) const; + double squareASymmetricNorm( void ) const; + double squareASymmetricNorm( size_t &idx1 , size_t &idx2 ) const; + + template< class T2 > void multiply ( ConstPointer( T2 ) In , Pointer( T2 ) Out , char multiplyFlag=0 ) const; + template< class T2 > void multiplyScaled( T scale , ConstPointer( T2 ) In , Pointer( T2 ) Out , char multiplyFlag=0 ) const; + template< class T2 > void multiply ( Pointer( T2 ) In , Pointer( T2 ) Out , char multiplyFlag=0 ) const { multiply ( ( ConstPointer(T2) )( In ) , Out , multiplyFlag ); } + template< class T2 > void multiplyScaled( T scale , Pointer( T2 ) In , Pointer( T2 ) Out , char multiplyFlag=0 ) const { multiplyScaled( scale , ( ConstPointer(T2) )( In ) , Out , multiplyFlag ); } + + void setDiagonal( Pointer( T ) diagonal ) const; + void setDiagonalR( Pointer( T ) diagonal ) const; + template< class T2 > void jacobiIteration( ConstPointer( T ) diagonal , ConstPointer( T2 ) b , ConstPointer( T2 ) in , Pointer( T2 ) out , bool dReciprocal ) const; + template< class T2 > void gsIteration( const std::vector< size_t > & multiColorIndices , ConstPointer( T ) diagonal , ConstPointer( T2 ) b , Pointer( T2 ) x , bool dReciprocal ) const; + template< class T2 > void gsIteration( const std::vector< std::vector< size_t > >& multiColorIndices , ConstPointer( T ) diagonal , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward , bool dReciprocal ) const; + template< class T2 > void gsIteration( ConstPointer( T ) diagonal , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward , bool dReciprocal ) const; + }; + + // Assuming that the SPDOperator class defines: + // auto SPDOperator::()( ConstPointer( T ) , Pointer( T ) ) const + template< class SPDFunctor , class T , typename Real , class TDotTFunctor > size_t SolveCG( const SPDFunctor& M , size_t dim , ConstPointer( T ) b , size_t iters , Pointer( T ) x , double eps , TDotTFunctor Dot ); + template< class SPDFunctor , class Preconditioner , class T , typename Real , class TDotTFunctor > size_t SolveCG( const SPDFunctor& M , const Preconditioner& P , size_t dim , ConstPointer( T ) b , size_t iters , Pointer( T ) x , double eps , TDotTFunctor Dot ); + + template< typename T > + struct AbstractArrayWrapper { - // static_assert( std::is_convertible< AbstractArrayWrapper1 , AbstractArrayWrapper< T > >::value || std::is_convertible< AbstractArrayWrapper1 , ConstPointer(T) >::value , "[ERROR] Bad AbstractArrayWrapper1" ); - // static_assert( std::is_convertible< AbstractArrayWrapper2 , AbstractArrayWrapper< T > >::value || std::is_convertible< AbstractArrayWrapper2 , ConstPointer(T) >::value , "[ERROR] Bad AbstractArrayWrapper2" ); - } - T operator[] ( size_t i ) const { return _v1[i] - _v2[i]; } -protected: - const AbstractArrayWrapper1 &_v1; - const AbstractArrayWrapper2 &_v2; -}; - -template< typename T , typename Real , typename const_iterator , typename _AbstractArrayWrapper > -struct _VectorProduct : public AbstractArrayWrapper< T > -{ - _VectorProduct( const SparseMatrixInterface< Real , const_iterator > &M , const _AbstractArrayWrapper &v ) : _M(M) , _v(v) + virtual T operator[]( size_t i ) const = 0; + }; + template< typename T , typename AbstractArrayWrapper1 , typename AbstractArrayWrapper2 > struct _VectorSum; + template< typename T , typename AbstractArrayWrapper1 , typename AbstractArrayWrapper2 > struct _VectorDifference; + template< typename T , typename Real , typename const_iterator , typename _AbstractArrayWrapper > struct _VectorProduct; + + template< typename T , typename AbstractArrayWrapper1 , typename AbstractArrayWrapper2 > + struct _VectorSum : public AbstractArrayWrapper< T > + { + _VectorSum( const AbstractArrayWrapper1 &v1 , const AbstractArrayWrapper2 &v2 ) : _v1(v1) , _v2(v2) + { + // static_assert( std::is_convertible< AbstractArrayWrapper1 , AbstractArrayWrapper< T > >::value || std::is_convertible< AbstractArrayWrapper1 , ConstPointer(T) >::value , "[ERROR] Bad AbstractArrayWrapper1" ); + // static_assert( std::is_convertible< AbstractArrayWrapper2 , AbstractArrayWrapper< T > >::value || std::is_convertible< AbstractArrayWrapper2 , ConstPointer(T) >::value , "[ERROR] Bad AbstractArrayWrapper2" ); + } + T operator[] ( size_t i ) const { return _v1[i] + _v2[i]; } + protected: + const AbstractArrayWrapper1 &_v1; + const AbstractArrayWrapper2 &_v2; + }; + + template< typename T , typename AbstractArrayWrapper1 , typename AbstractArrayWrapper2 > + struct _VectorDifference : public AbstractArrayWrapper< T > { - // static_assert( std::is_convertible< _AbstractArrayWrapper , AbstractArrayWrapper< T > >::value || std::is_convertible< _AbstractArrayWrapper , ConstPointer(T) >::value , "[ERROR] Bad _AbstractArrayWrapper" ); - } - T operator[] ( size_t i ) const + _VectorDifference( const AbstractArrayWrapper1 &v1 , const AbstractArrayWrapper2 &v2 ) : _v1(v1) , _v2(v2) + { + // static_assert( std::is_convertible< AbstractArrayWrapper1 , AbstractArrayWrapper< T > >::value || std::is_convertible< AbstractArrayWrapper1 , ConstPointer(T) >::value , "[ERROR] Bad AbstractArrayWrapper1" ); + // static_assert( std::is_convertible< AbstractArrayWrapper2 , AbstractArrayWrapper< T > >::value || std::is_convertible< AbstractArrayWrapper2 , ConstPointer(T) >::value , "[ERROR] Bad AbstractArrayWrapper2" ); + } + T operator[] ( size_t i ) const { return _v1[i] - _v2[i]; } + protected: + const AbstractArrayWrapper1 &_v1; + const AbstractArrayWrapper2 &_v2; + }; + + template< typename T , typename Real , typename const_iterator , typename _AbstractArrayWrapper > + struct _VectorProduct : public AbstractArrayWrapper< T > { - T t = {}; - const_iterator e = _M.end( i ); - for( const_iterator iter = _M.begin( i ) ; iter!=e ; iter++ ) t += _v[ iter->N ] * iter->Value; - return t; - } -protected: - const SparseMatrixInterface< Real , const_iterator > &_M; - const _AbstractArrayWrapper &_v; -}; - -template< typename T , typename AbstractArrayWrapper1 , typename AbstractArrayWrapper2 > -_VectorSum< T , AbstractArrayWrapper1 , AbstractArrayWrapper2 > VectorSum( const AbstractArrayWrapper1 &v1 , const AbstractArrayWrapper2 &v2 ){ return _VectorSum< T , AbstractArrayWrapper1 , AbstractArrayWrapper2 >( v1 , v2 ); } -template< typename T , typename AbstractArrayWrapper1 , typename AbstractArrayWrapper2 > -_VectorDifference< T , AbstractArrayWrapper1 , AbstractArrayWrapper2 > VectorDifference( const AbstractArrayWrapper1 &v1 , const AbstractArrayWrapper2 &v2 ){ return _VectorDifference< T , AbstractArrayWrapper1 , AbstractArrayWrapper2 >( v1 , v2 ); } -template< typename T , typename Real , typename const_iterator , typename _AbstractArrayWrapper > -_VectorProduct< T , Real , const_iterator , _AbstractArrayWrapper > VectorProduct( const SparseMatrixInterface< Real , const_iterator > &M , const _AbstractArrayWrapper &v ){ return _VectorProduct< T , Real , const_iterator , _AbstractArrayWrapper >( M , v ); } + _VectorProduct( const SparseMatrixInterface< Real , const_iterator > &M , const _AbstractArrayWrapper &v ) : _M(M) , _v(v) + { + // static_assert( std::is_convertible< _AbstractArrayWrapper , AbstractArrayWrapper< T > >::value || std::is_convertible< _AbstractArrayWrapper , ConstPointer(T) >::value , "[ERROR] Bad _AbstractArrayWrapper" ); + } + T operator[] ( size_t i ) const + { + T t = {}; + const_iterator e = _M.end( i ); + for( const_iterator iter = _M.begin( i ) ; iter!=e ; iter++ ) t += _v[ iter->N ] * iter->Value; + return t; + } + protected: + const SparseMatrixInterface< Real , const_iterator > &_M; + const _AbstractArrayWrapper &_v; + }; + + template< typename T , typename AbstractArrayWrapper1 , typename AbstractArrayWrapper2 > + _VectorSum< T , AbstractArrayWrapper1 , AbstractArrayWrapper2 > VectorSum( const AbstractArrayWrapper1 &v1 , const AbstractArrayWrapper2 &v2 ){ return _VectorSum< T , AbstractArrayWrapper1 , AbstractArrayWrapper2 >( v1 , v2 ); } + template< typename T , typename AbstractArrayWrapper1 , typename AbstractArrayWrapper2 > + _VectorDifference< T , AbstractArrayWrapper1 , AbstractArrayWrapper2 > VectorDifference( const AbstractArrayWrapper1 &v1 , const AbstractArrayWrapper2 &v2 ){ return _VectorDifference< T , AbstractArrayWrapper1 , AbstractArrayWrapper2 >( v1 , v2 ); } + template< typename T , typename Real , typename const_iterator , typename _AbstractArrayWrapper > + _VectorProduct< T , Real , const_iterator , _AbstractArrayWrapper > VectorProduct( const SparseMatrixInterface< Real , const_iterator > &M , const _AbstractArrayWrapper &v ){ return _VectorProduct< T , Real , const_iterator , _AbstractArrayWrapper >( M , v ); } #include "SparseMatrixInterface.inl" +} + #endif // SPARSE_MATRIX_INTERFACE_INCLUDED diff --git a/Src/SparseMatrixInterface.inl b/Src/SparseMatrixInterface.inl index b88f47bd..27634d8f 100644 --- a/Src/SparseMatrixInterface.inl +++ b/Src/SparseMatrixInterface.inl @@ -167,30 +167,27 @@ void SparseMatrixInterface< T , const_iterator >::gsIteration( ConstPointer( T ) { if( dReciprocal ) { -#define ITERATE( j ) \ - { \ - T2 _b = b[j]; \ - const_iterator e = end( j ); \ - for( const_iterator iter = begin( j ) ; iter!=e ; iter++ ) _b -= x[iter->N] * iter->Value; \ - x[j] += _b * diagonal[j]; \ - } - if( forward ) for( long long j=0 ; j<(long long)rows() ; j++ ){ ITERATE( j ); } - else for( long long j=(long long)rows()-1 ; j>=0 ; j-- ){ ITERATE( j ); } -#undef ITERATE + auto Iterate = [&]( long long j ) + { + T2 _b = b[j]; + const_iterator e = end( j ); + for( const_iterator iter = begin( j ) ; iter!=e ; iter++ ) _b -= x[iter->N] * iter->Value; + x[j] += _b * diagonal[j]; + }; + if( forward ) for( long long j=0 ; j<(long long)rows() ; j++ ){ Iterate( j ); } + else for( long long j=(long long)rows()-1 ; j>=0 ; j-- ){ Iterate( j ); } } else { -#define ITERATE( j ) \ - { \ - T2 _b = b[j]; \ - const_iterator e = end( j ); \ - for( const_iterator iter = begin( j ) ; iter!=e ; iter++ ) _b -= x[iter->N] * iter->Value; \ - x[j] += _b / diagonal[j]; \ - } - - if( forward ) for( long long j=0 ; j<(long long)rows() ; j++ ){ ITERATE( j ); } - else for( long long j=(long long)rows()-1 ; j>=0 ; j-- ){ ITERATE( j ); } -#undef ITERATE + auto Iterate = [&]( long long j ) + { + T2 _b = b[j]; + const_iterator e = end( j ); + for( const_iterator iter = begin( j ) ; iter!=e ; iter++ ) _b -= x[iter->N] * iter->Value; + x[j] += _b / diagonal[j]; + }; + if( forward ) for( long long j=0 ; j<(long long)rows() ; j++ ){ Iterate( j ); } + else for( long long j=(long long)rows()-1 ; j>=0 ; j-- ){ Iterate( j ); } } } template< class T , class const_iterator > @@ -225,39 +222,37 @@ void SparseMatrixInterface< T , const_iterator >::gsIteration( const std::vector { if( dReciprocal ) { -#define ITERATE( indices ) \ - { \ - ThreadPool::Parallel_for( 0 , indices.size() , [&]( unsigned int , size_t k ) \ - { \ - size_t jj = indices[k]; \ - T2 _b = b[jj]; \ - const_iterator e = end( jj ); \ - for( const_iterator iter = begin( jj ) ; iter!=e ; iter++ ) _b -= x[iter->N] * iter->Value; \ - x[jj] += _b * diagonal[jj]; \ - } \ - ); \ - } - if( forward ) for( size_t j=0 ; j=0 ; j-- ){ ITERATE( multiColorIndices[j] ); } -#undef ITERATE + auto Iterate = [&]( const std::vector< size_t > &indices ) + { + ThreadPool::Parallel_for( 0 , indices.size() , [&]( unsigned int , size_t k ) + { + size_t jj = indices[k]; + T2 _b = b[jj]; + const_iterator e = end( jj ); + for( const_iterator iter = begin( jj ) ; iter!=e ; iter++ ) _b -= x[iter->N] * iter->Value; + x[jj] += _b * diagonal[jj]; + } + ); + }; + if( forward ) for( size_t j=0 ; j=0 ; j-- ){ Iterate( multiColorIndices[j] ); } } else { -#define ITERATE( indices ) \ - { \ - ThreadPool::Parallel_for( 0 , indices.size() , [&]( unsigned int , size_t k ) \ - { \ - size_t jj = indices[k]; \ - T2 _b = b[jj]; \ - const_iterator e = end( jj ); \ - for( const_iterator iter = begin( jj ) ; iter!=e ; iter++ ) _b -= x[iter->N] * iter->Value; \ - x[jj] += _b / diagonal[jj]; \ - } \ - ); \ - } - if( forward ) for( size_t j=0 ; j=0 ; j-- ){ ITERATE( multiColorIndices[j] ); } -#undef ITERATE + auto Iterate = [&]( const std::vector< size_t > &indices ) + { + ThreadPool::Parallel_for( 0 , indices.size() , [&]( unsigned int , size_t k ) + { + size_t jj = indices[k]; + T2 _b = b[jj]; + const_iterator e = end( jj ); + for( const_iterator iter = begin( jj ) ; iter!=e ; iter++ ) _b -= x[iter->N] * iter->Value; + x[jj] += _b / diagonal[jj]; + } + ); + }; + if( forward ) for( size_t j=0 ; j=0 ; j-- ){ Iterate( multiColorIndices[j] ); } } } template< class SPDFunctor , class T , typename Real , class TDotTFunctor > size_t SolveCG( const SPDFunctor& M , size_t dim , ConstPointer( T ) b , size_t iters , Pointer( T ) x , double eps , TDotTFunctor Dot ) diff --git a/Src/Streams.h b/Src/Streams.h index ada40c9c..4aa5ae79 100644 --- a/Src/Streams.h +++ b/Src/Streams.h @@ -30,129 +30,132 @@ DAMAGE. #include "Array.h" -////////////////// -// BinaryStream // -////////////////// -struct BinaryStream +namespace PoissonRecon { - size_t ioBytes; - BinaryStream( void ) : ioBytes(0) {} - - template< typename C > bool read( C &c ){ return __read( ( Pointer( unsigned char ) )GetPointer( c ) , sizeof(C) ); } - template< typename C > bool write( const C &c ){ return __write( ( ConstPointer( unsigned char ) )GetPointer( c ) , sizeof(C) ); } - template< typename C > bool write( C &c ){ return __write( ( ConstPointer( unsigned char ) )GetPointer( c ) , sizeof(C) ); } - template< typename C > bool read( Pointer( C ) c , size_t sz ){ return __read( ( Pointer( unsigned char ) )c , sizeof(C)*sz ); } - template< typename C > bool write( ConstPointer( C ) c , size_t sz ){ return __write( ( ConstPointer( unsigned char ) )c , sizeof(C)*sz ); } - template< typename C > bool write( Pointer( C ) c , size_t sz ){ return __write( ( ConstPointer( unsigned char ) )c , sizeof(C)*sz ); } - - template< typename C > - bool read( std::vector< std::vector< C > > &c ) - { - size_t sz; - if( !read( sz ) ) return false; - c.resize( sz ); - bool ret = true; - for( size_t i=0 ; i - bool read( std::vector< C > &c ) + ////////////////// + // BinaryStream // + ////////////////// + struct BinaryStream { - size_t sz; - if( !read( sz ) ) return false; - c.resize( sz ); - if( sz ) return read( GetPointer( c ) , sz ); - else return true; - } - - template< typename C > - bool write( const std::vector< std::vector< C > > &c ) - { - size_t sz = c.size(); - if( !write( sz ) ) return false; - bool ret = true; - for( size_t i=0 ; i - bool write( const std::vector< C > &c ) + size_t ioBytes; + BinaryStream( void ) : ioBytes(0) {} + + template< typename C > bool read( C &c ){ return __read( ( Pointer( unsigned char ) )GetPointer( c ) , sizeof(C) ); } + template< typename C > bool write( const C &c ){ return __write( ( ConstPointer( unsigned char ) )GetPointer( c ) , sizeof(C) ); } + template< typename C > bool write( C &c ){ return __write( ( ConstPointer( unsigned char ) )GetPointer( c ) , sizeof(C) ); } + template< typename C > bool read( Pointer( C ) c , size_t sz ){ return __read( ( Pointer( unsigned char ) )c , sizeof(C)*sz ); } + template< typename C > bool write( ConstPointer( C ) c , size_t sz ){ return __write( ( ConstPointer( unsigned char ) )c , sizeof(C)*sz ); } + template< typename C > bool write( Pointer( C ) c , size_t sz ){ return __write( ( ConstPointer( unsigned char ) )c , sizeof(C)*sz ); } + + template< typename C > + bool read( std::vector< std::vector< C > > &c ) + { + size_t sz; + if( !read( sz ) ) return false; + c.resize( sz ); + bool ret = true; + for( size_t i=0 ; i + bool read( std::vector< C > &c ) + { + size_t sz; + if( !read( sz ) ) return false; + c.resize( sz ); + if( sz ) return read( GetPointer( c ) , sz ); + else return true; + } + + template< typename C > + bool write( const std::vector< std::vector< C > > &c ) + { + size_t sz = c.size(); + if( !write( sz ) ) return false; + bool ret = true; + for( size_t i=0 ; i + bool write( const std::vector< C > &c ) + { + size_t sz = c.size(); + if( !write( sz ) ) return false; + if( sz ) return write( GetPointer( c ) , sz ); + else return true; + } + + template< typename C > + bool write( std::vector< std::vector< C > > &c ) + { + size_t sz = c.size(); + if( !write( sz ) ) return false; + bool ret = true; + for( size_t i=0 ; i + bool write( std::vector< C > &c ) + { + size_t sz = c.size(); + if( !write( sz ) ) return false; + if( sz ) return write( GetPointer( c ) , sz ); + else return true; + } + + bool read( std::string &str ) + { + size_t sz; + if( !read( sz ) ) return false; + char *_str = new char[sz+1]; + bool ret = read( GetPointer( _str , sz+1 ) , sz+1 ); + if( ret ) str = std::string( _str ); + delete[] _str; + return ret; + } + + bool write( const std::string &str ) + { + size_t sz = strlen( str.c_str() ); + if( !write( sz ) ) return false; + return write( GetPointer( str.c_str() , sz+1 ) , sz+1 ); + } + + bool write( std::string &str ) + { + size_t sz = strlen( str.c_str() ); + if( !write( sz ) ) return false; + return write( GetPointer( str.c_str() , sz+1 ) , sz+1 ); + } + protected: + virtual bool _read( Pointer( unsigned char ) ptr , size_t sz ) = 0; + virtual bool _write( ConstPointer( unsigned char ) ptr , size_t sz ) = 0; + bool _write( Pointer( unsigned char ) ptr , size_t sz ){ return _write( ( ConstPointer( unsigned char ) )ptr , sz ); } + bool __read( Pointer( unsigned char ) ptr , size_t sz ){ ioBytes += sz ; return _read( ptr , sz ); } + bool __write( ConstPointer( unsigned char ) ptr , size_t sz ){ ioBytes += sz ; return _write( ptr , sz ); } + bool __write( Pointer( unsigned char ) ptr , size_t sz ){ ioBytes += sz ; return _write( ( ConstPointer( unsigned char ) )ptr , sz ); } + }; + + struct FileStream : public BinaryStream { - size_t sz = c.size(); - if( !write( sz ) ) return false; - if( sz ) return write( GetPointer( c ) , sz ); - else return true; - } + FileStream( FILE *fp ) : _fp(fp){} + void reset( void ){ std::rewind( _fp ); } + protected: + FILE *_fp; + bool _read( Pointer( unsigned char ) ptr , size_t sz ){ return fread( ptr , sizeof(unsigned char) , sz , _fp )==sz; } + bool _write( ConstPointer( unsigned char ) ptr , size_t sz ){ return fwrite( ptr , sizeof(unsigned char) , sz , _fp )==sz; } + }; template< typename C > - bool write( std::vector< std::vector< C > > &c ) + struct Serializer { - size_t sz = c.size(); - if( !write( sz ) ) return false; - bool ret = true; - for( size_t i=0 ; i - bool write( std::vector< C > &c ) - { - size_t sz = c.size(); - if( !write( sz ) ) return false; - if( sz ) return write( GetPointer( c ) , sz ); - else return true; - } - - bool read( std::string &str ) - { - size_t sz; - if( !read( sz ) ) return false; - char *_str = new char[sz+1]; - bool ret = read( GetPointer( _str , sz+1 ) , sz+1 ); - if( ret ) str = std::string( _str ); - delete[] _str; - return ret; - } - - bool write( const std::string &str ) - { - size_t sz = strlen( str.c_str() ); - if( !write( sz ) ) return false; - return write( GetPointer( str.c_str() , sz+1 ) , sz+1 ); - } - - bool write( std::string &str ) - { - size_t sz = strlen( str.c_str() ); - if( !write( sz ) ) return false; - return write( GetPointer( str.c_str() , sz+1 ) , sz+1 ); - } -protected: - virtual bool _read( Pointer( unsigned char ) ptr , size_t sz ) = 0; - virtual bool _write( ConstPointer( unsigned char ) ptr , size_t sz ) = 0; - bool _write( Pointer( unsigned char ) ptr , size_t sz ){ return _write( ( ConstPointer( unsigned char ) )ptr , sz ); } - bool __read( Pointer( unsigned char ) ptr , size_t sz ){ ioBytes += sz ; return _read( ptr , sz ); } - bool __write( ConstPointer( unsigned char ) ptr , size_t sz ){ ioBytes += sz ; return _write( ptr , sz ); } - bool __write( Pointer( unsigned char ) ptr , size_t sz ){ ioBytes += sz ; return _write( ( ConstPointer( unsigned char ) )ptr , sz ); } -}; - -struct FileStream : public BinaryStream -{ - FileStream( FILE *fp ) : _fp(fp){} - void reset( void ){ std::rewind( _fp ); } -protected: - FILE *_fp; - bool _read( Pointer( unsigned char ) ptr , size_t sz ){ return fread( ptr , sizeof(unsigned char) , sz , _fp )==sz; } - bool _write( ConstPointer( unsigned char ) ptr , size_t sz ){ return fwrite( ptr , sizeof(unsigned char) , sz , _fp )==sz; } -}; - -template< typename C > -struct Serializer -{ - virtual size_t size( void ) const = 0; - virtual void serialize( const C & , Pointer( char ) buffer ) const = 0; - virtual void deserialize( ConstPointer( char ) buffer , C & ) const = 0; -}; + virtual size_t size( void ) const = 0; + virtual void serialize( const C & , Pointer( char ) buffer ) const = 0; + virtual void deserialize( ConstPointer( char ) buffer , C & ) const = 0; + }; +} #endif // STREAMS_INCLUDED diff --git a/Src/SurfaceTrimmer.cpp b/Src/SurfaceTrimmer.cpp index 91e6f534..754c6eba 100644 --- a/Src/SurfaceTrimmer.cpp +++ b/Src/SurfaceTrimmer.cpp @@ -44,15 +44,17 @@ DAMAGE. #include "Ply.h" #include "VertexFactory.h" -cmdLineParameter< char* > +using namespace PoissonRecon; + +CmdLineParameter< char* > In( "in" ) , Out( "out" ); -cmdLineParameter< int > +CmdLineParameter< int > Smooth( "smooth" , 5 ); -cmdLineParameter< float > +CmdLineParameter< float > Trim( "trim" ) , IslandAreaRatio( "aRatio" , 0.001f ); -cmdLineReadable +CmdLineReadable PolygonMesh( "polygonMesh" ) , Long( "long" ) , ASCII( "ascii" ) , @@ -61,7 +63,7 @@ cmdLineReadable Verbose( "verbose" ); -cmdLineReadable* params[] = +CmdLineReadable* params[] = { &In , &Out , &Trim , &PolygonMesh , &Smooth , &IslandAreaRatio , &Verbose , &Long , &ASCII , &RemoveIslands , &Debug , NULL @@ -585,7 +587,7 @@ int Execute( AuxDataFactories ... auxDataFactories ) } int main( int argc , char* argv[] ) { - cmdLineParse( argc-1 , &argv[1] , params ); + CmdLineParse( argc-1 , &argv[1] , params ); if( !In.set || !Trim.set ) { diff --git a/Src/VertexFactory.h b/Src/VertexFactory.h index 09e19523..7571b51e 100644 --- a/Src/VertexFactory.h +++ b/Src/VertexFactory.h @@ -32,581 +32,584 @@ DAMAGE. #include "Ply.h" #include "Array.h" -namespace VertexFactory +namespace PoissonRecon { - // Mimicking the scalar types in Ply.inl - // Assuming Real is something that is castable to/from a double - enum TypeOnDisk + namespace VertexFactory { - CHAR , - UCHAR , - INT , - UINT , - FLOAT , - DOUBLE , - INT_8 , - UINT_8 , - INT_16 , - UINT_16 , - INT_32 , - UINT_32 , - INT_64 , - UINT_64 , - UNKNOWN - }; - - int ToPlyType( TypeOnDisk typeOnDisk ); - TypeOnDisk FromPlyType( int plyType ); - template< typename Real > TypeOnDisk GetTypeOnDisk( void ); - - template< typename Real > - struct VertexIO - { - static bool ReadASCII ( FILE *fp , TypeOnDisk typeOnDisk , Real &s ); - static bool ReadBinary ( FILE *fp , TypeOnDisk typeOnDisk , Real &s ); - static void WriteASCII ( FILE *fp , TypeOnDisk typeOnDisk , const Real &s ); - static void WriteBinary( FILE *fp , TypeOnDisk typeOnDisk , const Real &s ); - - static bool ReadASCII ( FILE *fp , TypeOnDisk typeOnDisk , size_t sz , Real *s ); - static bool ReadBinary ( FILE *fp , TypeOnDisk typeOnDisk , size_t sz , Real *s ); - static void WriteASCII ( FILE *fp , TypeOnDisk typeOnDisk , size_t sz , const Real *s ); - static void WriteBinary( FILE *fp , TypeOnDisk typeOnDisk , size_t sz , const Real *s ); - - protected: - template< typename Type > static bool _ReadBinary( FILE *fp , Real &s ); - template< typename Type > static void _WriteBinary( FILE *fp , Real s ); - }; - - template< typename _VertexType , typename FactoryType > - struct _Factory - { - typedef _VertexType VertexType; - virtual VertexType operator()( void ) const = 0; - - // Reading/writing methods for PLY format - virtual unsigned int plyReadNum( void ) const = 0; - virtual unsigned int plyWriteNum( void ) const = 0; - virtual bool plyValidReadProperties( const bool *flags ) const = 0; - - virtual PlyProperty plyReadProperty( unsigned int idx ) const = 0; - virtual PlyProperty plyWriteProperty( unsigned int idx ) const = 0; - - // Reading/writing methods for ASCII/Binary files - virtual bool readASCII( FILE *fp , VertexType &dt ) const = 0; - virtual bool readBinary( FILE *fp , VertexType &dt ) const = 0; - virtual void writeASCII( FILE *fp , const VertexType &dt ) const = 0; - virtual void writeBinary( FILE *fp , const VertexType &dt ) const = 0; - - virtual size_t bufferSize( void ) const = 0; - virtual void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const = 0; - virtual void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const = 0; - - virtual bool isStaticallyAllocated( void ) const = 0; - virtual PlyProperty plyStaticReadProperty( unsigned int idx ) const = 0; - virtual PlyProperty plyStaticWriteProperty( unsigned int idx ) const = 0; - - virtual bool operator == ( const FactoryType &factory ) const = 0; - bool operator != ( const FactoryType &factory ) const { return !( (*this)==factory ); } - }; - - // An empty factory - template< typename Real > - struct EmptyFactory : _Factory< EmptyVectorType< Real > , EmptyFactory< Real > > - { - typedef typename _Factory< EmptyVectorType< Real > , EmptyFactory< Real > >::VertexType VertexType; + // Mimicking the scalar types in Ply.inl + // Assuming Real is something that is castable to/from a double + enum TypeOnDisk + { + CHAR , + UCHAR , + INT , + UINT , + FLOAT , + DOUBLE , + INT_8 , + UINT_8 , + INT_16 , + UINT_16 , + INT_32 , + UINT_32 , + INT_64 , + UINT_64 , + UNKNOWN + }; + + int ToPlyType( TypeOnDisk typeOnDisk ); + TypeOnDisk FromPlyType( int plyType ); + template< typename Real > TypeOnDisk GetTypeOnDisk( void ); - struct Transform + template< typename Real > + struct VertexIO { - Transform( void ){} - template< typename X > Transform( X ){} - void inPlace( VertexType &dt ) const {} + static bool ReadASCII ( FILE *fp , TypeOnDisk typeOnDisk , Real &s ); + static bool ReadBinary ( FILE *fp , TypeOnDisk typeOnDisk , Real &s ); + static void WriteASCII ( FILE *fp , TypeOnDisk typeOnDisk , const Real &s ); + static void WriteBinary( FILE *fp , TypeOnDisk typeOnDisk , const Real &s ); + + static bool ReadASCII ( FILE *fp , TypeOnDisk typeOnDisk , size_t sz , Real *s ); + static bool ReadBinary ( FILE *fp , TypeOnDisk typeOnDisk , size_t sz , Real *s ); + static void WriteASCII ( FILE *fp , TypeOnDisk typeOnDisk , size_t sz , const Real *s ); + static void WriteBinary( FILE *fp , TypeOnDisk typeOnDisk , size_t sz , const Real *s ); + + protected: + template< typename Type > static bool _ReadBinary( FILE *fp , Real &s ); + template< typename Type > static void _WriteBinary( FILE *fp , Real s ); }; - VertexType operator()( void ) const { return VertexType(); } + template< typename _VertexType , typename FactoryType > + struct _Factory + { + typedef _VertexType VertexType; + virtual VertexType operator()( void ) const = 0; - unsigned int plyReadNum( void ) const { return 0; } - unsigned int plyWriteNum( void ) const { return 0; } - bool plyValidReadProperties( const bool *flags ) const { return true ; } - PlyProperty plyReadProperty( unsigned int idx ) const { if( idx>= plyReadNum() ) ERROR_OUT( "read property out of bounds" ) ; return PlyProperty(); } - PlyProperty plyWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ) ; return PlyProperty(); } - bool readASCII( FILE *fp , VertexType &dt ) const { return true; } - bool readBinary( FILE *fp , VertexType &dt ) const { return true; } - void writeASCII( FILE *fp , const VertexType &dt ) const {} - void writeBinary( FILE *fp , const VertexType &dt ) const {}; + // Reading/writing methods for PLY format + virtual unsigned int plyReadNum( void ) const = 0; + virtual unsigned int plyWriteNum( void ) const = 0; + virtual bool plyValidReadProperties( const bool *flags ) const = 0; - bool isStaticallyAllocated( void ) const{ return true; } - PlyProperty plyStaticReadProperty( unsigned int idx ) const { if( idx>= plyReadNum() ) ERROR_OUT( "read property out of bounds" ) ; return PlyProperty(); } - PlyProperty plyStaticWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ) ; return PlyProperty(); } + virtual PlyProperty plyReadProperty( unsigned int idx ) const = 0; + virtual PlyProperty plyWriteProperty( unsigned int idx ) const = 0; - size_t bufferSize( void ) const { return 0; } - void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const {} - void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const {} + // Reading/writing methods for ASCII/Binary files + virtual bool readASCII( FILE *fp , VertexType &dt ) const = 0; + virtual bool readBinary( FILE *fp , VertexType &dt ) const = 0; + virtual void writeASCII( FILE *fp , const VertexType &dt ) const = 0; + virtual void writeBinary( FILE *fp , const VertexType &dt ) const = 0; - bool operator == ( const EmptyFactory &factory ) const { return true; } + virtual size_t bufferSize( void ) const = 0; + virtual void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const = 0; + virtual void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const = 0; - }; + virtual bool isStaticallyAllocated( void ) const = 0; + virtual PlyProperty plyStaticReadProperty( unsigned int idx ) const = 0; + virtual PlyProperty plyStaticWriteProperty( unsigned int idx ) const = 0; - // The position factory - template< typename Real , unsigned int Dim > - struct PositionFactory : _Factory< Point< Real , Dim > , PositionFactory< Real , Dim > > - { - typedef typename _Factory< Point< Real , Dim > , PositionFactory< Real , Dim > >::VertexType VertexType; + virtual bool operator == ( const FactoryType &factory ) const = 0; + bool operator != ( const FactoryType &factory ) const { return !( (*this)==factory ); } + }; - struct Transform + // An empty factory + template< typename Real > + struct EmptyFactory : _Factory< EmptyVectorType< Real > , EmptyFactory< Real > > { - Transform( void ){ _xForm = XForm< Real , Dim+1 >::Identity(); } - Transform( XForm< Real , Dim > xForm ){ _xForm = XForm< Real , Dim+1 >::Identity() ; for( int i=0 ; i xForm ) : _xForm(xForm) {} - void inPlace( VertexType &dt ) const { dt = _xForm * dt; } - protected: - XForm< Real , Dim+1 > _xForm; - }; + typedef typename _Factory< EmptyVectorType< Real > , EmptyFactory< Real > >::VertexType VertexType; - VertexType operator()( void ) const { return VertexType(); } + struct Transform + { + Transform( void ){} + template< typename X > Transform( X ){} + void inPlace( VertexType &dt ) const {} + }; - unsigned int plyReadNum( void ) const { return Dim; } - unsigned int plyWriteNum( void ) const { return Dim; } - bool plyValidReadProperties( const bool *flags ) const { for( int d=0 ; d:: ReadASCII( fp , _typeOnDisk , Dim , &dt[0] ); } - void writeASCII( FILE *fp , const VertexType &dt ) const { VertexIO< Real >:: WriteASCII( fp , _typeOnDisk , Dim , &dt[0] ); } - bool readBinary( FILE *fp , VertexType &dt ) const - { - if( _realTypeOnDisk ) return fread( &dt[0] , sizeof(Real) , Dim , fp )==Dim; - else return VertexIO< Real >::ReadBinary( fp , _typeOnDisk , Dim , &dt[0] ); - } - void writeBinary( FILE *fp , const VertexType &dt ) const - { - if( _realTypeOnDisk ) fwrite( &dt[0] , sizeof(Real) , Dim , fp ); - else VertexIO< Real >::WriteBinary( fp , _typeOnDisk , Dim , &dt[0] ); - } - bool isStaticallyAllocated( void ) const{ return true; } - - PlyProperty plyStaticReadProperty( unsigned int idx ) const; - PlyProperty plyStaticWriteProperty( unsigned int idx ) const; - - PositionFactory( TypeOnDisk typeOnDisk=GetTypeOnDisk< Real >() ) : _typeOnDisk( typeOnDisk ) { _realTypeOnDisk = GetTypeOnDisk< Real >()==_typeOnDisk; } - - size_t bufferSize( void ) const { return sizeof( VertexType ); } - void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { memcpy( buffer , &dt , sizeof( VertexType ) ); } - void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const { memcpy( &dt , buffer , sizeof( VertexType ) ); } - - bool operator == ( const PositionFactory &factory ) const { return _typeOnDisk==factory._typeOnDisk; } - protected: - TypeOnDisk _typeOnDisk; - bool _realTypeOnDisk; - static const std::string _PlyNames[]; - }; - - // The vertex factory - template< typename Real , unsigned int Dim > - struct NormalFactory : public _Factory< Point< Real , Dim > , NormalFactory< Real , Dim > > - { - typedef typename _Factory< Point< Real , Dim > , NormalFactory< Real , Dim > >::VertexType VertexType; + VertexType operator()( void ) const { return VertexType(); } + + unsigned int plyReadNum( void ) const { return 0; } + unsigned int plyWriteNum( void ) const { return 0; } + bool plyValidReadProperties( const bool *flags ) const { return true ; } + PlyProperty plyReadProperty( unsigned int idx ) const { if( idx>= plyReadNum() ) ERROR_OUT( "read property out of bounds" ) ; return PlyProperty(); } + PlyProperty plyWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ) ; return PlyProperty(); } + bool readASCII( FILE *fp , VertexType &dt ) const { return true; } + bool readBinary( FILE *fp , VertexType &dt ) const { return true; } + void writeASCII( FILE *fp , const VertexType &dt ) const {} + void writeBinary( FILE *fp , const VertexType &dt ) const {}; + + bool isStaticallyAllocated( void ) const{ return true; } + PlyProperty plyStaticReadProperty( unsigned int idx ) const { if( idx>= plyReadNum() ) ERROR_OUT( "read property out of bounds" ) ; return PlyProperty(); } + PlyProperty plyStaticWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ) ; return PlyProperty(); } + + size_t bufferSize( void ) const { return 0; } + void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const {} + void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const {} - struct Transform + bool operator == ( const EmptyFactory &factory ) const { return true; } + + }; + + // The position factory + template< typename Real , unsigned int Dim > + struct PositionFactory : _Factory< Point< Real , Dim > , PositionFactory< Real , Dim > > { - Transform( void ){ _xForm = XForm< Real , Dim >::Identity(); } - Transform( XForm< Real , Dim > xForm ){ _xForm = xForm.inverse().transpose(); } - Transform( XForm< Real , Dim+1 > xForm ) + typedef typename _Factory< Point< Real , Dim > , PositionFactory< Real , Dim > >::VertexType VertexType; + + struct Transform + { + Transform( void ){ _xForm = XForm< Real , Dim+1 >::Identity(); } + Transform( XForm< Real , Dim > xForm ){ _xForm = XForm< Real , Dim+1 >::Identity() ; for( int i=0 ; i xForm ) : _xForm(xForm) {} + void inPlace( VertexType &dt ) const { dt = _xForm * dt; } + protected: + XForm< Real , Dim+1 > _xForm; + }; + + VertexType operator()( void ) const { return VertexType(); } + + unsigned int plyReadNum( void ) const { return Dim; } + unsigned int plyWriteNum( void ) const { return Dim; } + bool plyValidReadProperties( const bool *flags ) const { for( int d=0 ; d:: ReadASCII( fp , _typeOnDisk , Dim , &dt[0] ); } + void writeASCII( FILE *fp , const VertexType &dt ) const { VertexIO< Real >:: WriteASCII( fp , _typeOnDisk , Dim , &dt[0] ); } + bool readBinary( FILE *fp , VertexType &dt ) const { - for( int i=0 ; i::ReadBinary( fp , _typeOnDisk , Dim , &dt[0] ); } - void inPlace( VertexType &dt ) const { dt = _xForm * dt; } + void writeBinary( FILE *fp , const VertexType &dt ) const + { + if( _realTypeOnDisk ) fwrite( &dt[0] , sizeof(Real) , Dim , fp ); + else VertexIO< Real >::WriteBinary( fp , _typeOnDisk , Dim , &dt[0] ); + } + bool isStaticallyAllocated( void ) const{ return true; } + + PlyProperty plyStaticReadProperty( unsigned int idx ) const; + PlyProperty plyStaticWriteProperty( unsigned int idx ) const; + + PositionFactory( TypeOnDisk typeOnDisk=GetTypeOnDisk< Real >() ) : _typeOnDisk( typeOnDisk ) { _realTypeOnDisk = GetTypeOnDisk< Real >()==_typeOnDisk; } + + size_t bufferSize( void ) const { return sizeof( VertexType ); } + void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { memcpy( buffer , &dt , sizeof( VertexType ) ); } + void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const { memcpy( &dt , buffer , sizeof( VertexType ) ); } + + bool operator == ( const PositionFactory &factory ) const { return _typeOnDisk==factory._typeOnDisk; } protected: - XForm< Real , Dim > _xForm; + TypeOnDisk _typeOnDisk; + bool _realTypeOnDisk; + static const std::string _PlyNames[]; }; - VertexType operator()( void ) const { return VertexType(); } - - unsigned int plyReadNum( void ) const { return Dim; } - unsigned int plyWriteNum( void ) const { return Dim; } - bool plyValidReadProperties( const bool *flags ) const { for( int d=0 ; d:: ReadASCII( fp , _typeOnDisk , Dim , &dt[0] ); } - void writeASCII( FILE *fp , const VertexType &dt ) const { VertexIO< Real >:: WriteASCII( fp , _typeOnDisk , Dim , &dt[0] ); } - bool readBinary( FILE *fp , VertexType &dt ) const - { - if( _realTypeOnDisk ) return fread( &dt[0] , sizeof(Real) , Dim , fp )==Dim; - else return VertexIO< Real >::ReadBinary( fp , _typeOnDisk , Dim , &dt[0] ); - } - void writeBinary( FILE *fp , const VertexType &dt ) const + // The vertex factory + template< typename Real , unsigned int Dim > + struct NormalFactory : public _Factory< Point< Real , Dim > , NormalFactory< Real , Dim > > { - if( _realTypeOnDisk ) fwrite( &dt[0] , sizeof(Real) , Dim , fp ); - else VertexIO< Real >::WriteBinary( fp , _typeOnDisk , Dim , &dt[0] ); - } - - bool isStaticallyAllocated( void ) const{ return true; } - PlyProperty plyStaticReadProperty( unsigned int idx ) const; - PlyProperty plyStaticWriteProperty( unsigned int idx ) const; - - NormalFactory( TypeOnDisk typeOnDisk=GetTypeOnDisk< Real >() ) : _typeOnDisk( typeOnDisk ) { _realTypeOnDisk = GetTypeOnDisk< Real >()==_typeOnDisk; } - - size_t bufferSize( void ) const { return sizeof( VertexType ); } - void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { memcpy( buffer , &dt , sizeof( VertexType ) ); } - void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const { memcpy( &dt , buffer , sizeof( VertexType ) ); } - - bool operator == ( const NormalFactory &factory ) const { return _typeOnDisk==factory._typeOnDisk; } - protected: - TypeOnDisk _typeOnDisk; - bool _realTypeOnDisk; - static const std::string _PlyNames[]; - }; - - // The texture factory - template< typename Real , unsigned int Dim > - struct TextureFactory : public _Factory< Point< Real , Dim > , TextureFactory< Real , Dim > > - { - typedef typename _Factory< Point< Real , Dim > , TextureFactory< Real , Dim > >::VertexType VertexType; + typedef typename _Factory< Point< Real , Dim > , NormalFactory< Real , Dim > >::VertexType VertexType; - struct Transform - { - Transform( void ){} - template< typename XForm > Transform( XForm xForm ){} - void inPlace( VertexType &dt ) const {} - }; + struct Transform + { + Transform( void ){ _xForm = XForm< Real , Dim >::Identity(); } + Transform( XForm< Real , Dim > xForm ){ _xForm = xForm.inverse().transpose(); } + Transform( XForm< Real , Dim+1 > xForm ) + { + for( int i=0 ; i _xForm; + }; + + VertexType operator()( void ) const { return VertexType(); } + + unsigned int plyReadNum( void ) const { return Dim; } + unsigned int plyWriteNum( void ) const { return Dim; } + bool plyValidReadProperties( const bool *flags ) const { for( int d=0 ; d:: ReadASCII( fp , _typeOnDisk , Dim , &dt[0] ); } + void writeASCII( FILE *fp , const VertexType &dt ) const { VertexIO< Real >:: WriteASCII( fp , _typeOnDisk , Dim , &dt[0] ); } + bool readBinary( FILE *fp , VertexType &dt ) const + { + if( _realTypeOnDisk ) return fread( &dt[0] , sizeof(Real) , Dim , fp )==Dim; + else return VertexIO< Real >::ReadBinary( fp , _typeOnDisk , Dim , &dt[0] ); + } + void writeBinary( FILE *fp , const VertexType &dt ) const + { + if( _realTypeOnDisk ) fwrite( &dt[0] , sizeof(Real) , Dim , fp ); + else VertexIO< Real >::WriteBinary( fp , _typeOnDisk , Dim , &dt[0] ); + } - VertexType operator()( void ) const { return VertexType(); } + bool isStaticallyAllocated( void ) const{ return true; } + PlyProperty plyStaticReadProperty( unsigned int idx ) const; + PlyProperty plyStaticWriteProperty( unsigned int idx ) const; - unsigned int plyReadNum( void ) const { return Dim; } - unsigned int plyWriteNum( void ) const { return Dim; } - bool plyValidReadProperties( const bool *flags ) const { for( int d=0 ; d:: ReadASCII( fp , _typeOnDisk , Dim , &dt[0] ); } - void writeASCII( FILE *fp , const VertexType &dt ) const { VertexIO< Real >:: WriteASCII( fp , _typeOnDisk , Dim , &dt[0] ); } - bool readBinary( FILE *fp , VertexType &dt ) const - { - if( _realTypeOnDisk ) return fread( &dt[0] , sizeof(Real) , Dim , fp )==Dim; - else return VertexIO< Real >::ReadBinary( fp , _typeOnDisk , Dim , &dt[0] ); - } - void writeBinary( FILE *fp , const VertexType &dt ) const + NormalFactory( TypeOnDisk typeOnDisk=GetTypeOnDisk< Real >() ) : _typeOnDisk( typeOnDisk ) { _realTypeOnDisk = GetTypeOnDisk< Real >()==_typeOnDisk; } + + size_t bufferSize( void ) const { return sizeof( VertexType ); } + void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { memcpy( buffer , &dt , sizeof( VertexType ) ); } + void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const { memcpy( &dt , buffer , sizeof( VertexType ) ); } + + bool operator == ( const NormalFactory &factory ) const { return _typeOnDisk==factory._typeOnDisk; } + protected: + TypeOnDisk _typeOnDisk; + bool _realTypeOnDisk; + static const std::string _PlyNames[]; + }; + + // The texture factory + template< typename Real , unsigned int Dim > + struct TextureFactory : public _Factory< Point< Real , Dim > , TextureFactory< Real , Dim > > { - if( _realTypeOnDisk ) fwrite( &dt[0] , sizeof(Real) , Dim , fp ); - VertexIO< Real >::WriteBinary( fp , _typeOnDisk , Dim , &dt[0] ); - } + typedef typename _Factory< Point< Real , Dim > , TextureFactory< Real , Dim > >::VertexType VertexType; - bool isStaticallyAllocated( void ) const{ return true; } - PlyProperty plyStaticReadProperty( unsigned int idx ) const; - PlyProperty plyStaticWriteProperty( unsigned int idx ) const; + struct Transform + { + Transform( void ){} + template< typename XForm > Transform( XForm xForm ){} + void inPlace( VertexType &dt ) const {} + }; + + VertexType operator()( void ) const { return VertexType(); } + + unsigned int plyReadNum( void ) const { return Dim; } + unsigned int plyWriteNum( void ) const { return Dim; } + bool plyValidReadProperties( const bool *flags ) const { for( int d=0 ; d:: ReadASCII( fp , _typeOnDisk , Dim , &dt[0] ); } + void writeASCII( FILE *fp , const VertexType &dt ) const { VertexIO< Real >:: WriteASCII( fp , _typeOnDisk , Dim , &dt[0] ); } + bool readBinary( FILE *fp , VertexType &dt ) const + { + if( _realTypeOnDisk ) return fread( &dt[0] , sizeof(Real) , Dim , fp )==Dim; + else return VertexIO< Real >::ReadBinary( fp , _typeOnDisk , Dim , &dt[0] ); + } + void writeBinary( FILE *fp , const VertexType &dt ) const + { + if( _realTypeOnDisk ) fwrite( &dt[0] , sizeof(Real) , Dim , fp ); + VertexIO< Real >::WriteBinary( fp , _typeOnDisk , Dim , &dt[0] ); + } - TextureFactory( TypeOnDisk typeOnDisk=GetTypeOnDisk< Real >() ) : _typeOnDisk( typeOnDisk ) { _realTypeOnDisk = GetTypeOnDisk< Real >()==_typeOnDisk; } + bool isStaticallyAllocated( void ) const{ return true; } + PlyProperty plyStaticReadProperty( unsigned int idx ) const; + PlyProperty plyStaticWriteProperty( unsigned int idx ) const; - size_t bufferSize( void ) const { return sizeof( VertexType ); } - void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { memcpy( buffer , &dt , sizeof( VertexType ) ); } - void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const { memcpy( &dt , buffer , sizeof( VertexType ) ); } + TextureFactory( TypeOnDisk typeOnDisk=GetTypeOnDisk< Real >() ) : _typeOnDisk( typeOnDisk ) { _realTypeOnDisk = GetTypeOnDisk< Real >()==_typeOnDisk; } - bool operator == ( const TextureFactory &factory ) const { return _typeOnDisk==factory._typeOnDisk; } + size_t bufferSize( void ) const { return sizeof( VertexType ); } + void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { memcpy( buffer , &dt , sizeof( VertexType ) ); } + void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const { memcpy( &dt , buffer , sizeof( VertexType ) ); } - protected: - TypeOnDisk _typeOnDisk; - bool _realTypeOnDisk; - static const std::string _PlyNames[]; - }; + bool operator == ( const TextureFactory &factory ) const { return _typeOnDisk==factory._typeOnDisk; } - // The rgb color factory - template< typename Real > - struct RGBColorFactory : public _Factory< Point< Real , 3 > , RGBColorFactory< Real > > - { - typedef typename _Factory< Point< Real , 3 > , RGBColorFactory< Real > >::VertexType VertexType; + protected: + TypeOnDisk _typeOnDisk; + bool _realTypeOnDisk; + static const std::string _PlyNames[]; + }; - struct Transform + // The rgb color factory + template< typename Real > + struct RGBColorFactory : public _Factory< Point< Real , 3 > , RGBColorFactory< Real > > { - Transform( void ){} - template< typename XForm > Transform( XForm xForm ){} - void inPlace( VertexType &dt ) const {} - }; + typedef typename _Factory< Point< Real , 3 > , RGBColorFactory< Real > >::VertexType VertexType; - VertexType operator()( void ) const { return VertexType(); } + struct Transform + { + Transform( void ){} + template< typename XForm > Transform( XForm xForm ){} + void inPlace( VertexType &dt ) const {} + }; + + VertexType operator()( void ) const { return VertexType(); } + + unsigned int plyReadNum( void ) const { return 6; } + unsigned int plyWriteNum( void ) const { return 3; } + bool plyValidReadProperties( const bool *flags ) const { for( int d=0 ; d<3 ; d++ ) if( !flags[d] && !flags[d+3] ) return false ; return true ; } + PlyProperty plyReadProperty( unsigned int idx ) const; + PlyProperty plyWriteProperty( unsigned int idx ) const; + bool readASCII( FILE *fp , VertexType &dt ) const { return VertexIO< Real >:: ReadASCII( fp , _typeOnDisk , 3 , &dt[0] ); } + void writeASCII( FILE *fp , const VertexType &dt ) const { VertexIO< Real >:: WriteASCII( fp , _typeOnDisk , 3 , &dt[0] ); } + bool readBinary( FILE *fp , VertexType &dt ) const + { + if( _realTypeOnDisk ) return fread( &dt[0] , sizeof(Real) , 3 , fp )==3; + else return VertexIO< Real >::ReadBinary( fp , _typeOnDisk , 3 , &dt[0] ); + } + void writeBinary( FILE *fp , const VertexType &dt ) const + { + if( _realTypeOnDisk ) fwrite( &dt[0] , sizeof(Real) , 3 , fp ); + VertexIO< Real >::WriteBinary( fp , _typeOnDisk , 3 , &dt[0] ); + } - unsigned int plyReadNum( void ) const { return 6; } - unsigned int plyWriteNum( void ) const { return 3; } - bool plyValidReadProperties( const bool *flags ) const { for( int d=0 ; d<3 ; d++ ) if( !flags[d] && !flags[d+3] ) return false ; return true ; } - PlyProperty plyReadProperty( unsigned int idx ) const; - PlyProperty plyWriteProperty( unsigned int idx ) const; - bool readASCII( FILE *fp , VertexType &dt ) const { return VertexIO< Real >:: ReadASCII( fp , _typeOnDisk , 3 , &dt[0] ); } - void writeASCII( FILE *fp , const VertexType &dt ) const { VertexIO< Real >:: WriteASCII( fp , _typeOnDisk , 3 , &dt[0] ); } - bool readBinary( FILE *fp , VertexType &dt ) const - { - if( _realTypeOnDisk ) return fread( &dt[0] , sizeof(Real) , 3 , fp )==3; - else return VertexIO< Real >::ReadBinary( fp , _typeOnDisk , 3 , &dt[0] ); - } - void writeBinary( FILE *fp , const VertexType &dt ) const - { - if( _realTypeOnDisk ) fwrite( &dt[0] , sizeof(Real) , 3 , fp ); - VertexIO< Real >::WriteBinary( fp , _typeOnDisk , 3 , &dt[0] ); - } - - bool isStaticallyAllocated( void ) const{ return true; } - PlyProperty plyStaticReadProperty( unsigned int idx ) const; - PlyProperty plyStaticWriteProperty( unsigned int idx ) const; - - RGBColorFactory( TypeOnDisk typeOnDisk=GetTypeOnDisk< unsigned char >() ) : _typeOnDisk( typeOnDisk ) { _realTypeOnDisk = GetTypeOnDisk< Real >()==_typeOnDisk; } - - size_t bufferSize( void ) const { return sizeof( VertexType ); } - void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { memcpy( buffer , &dt , sizeof( VertexType ) ); } - void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const { memcpy( &dt , buffer , sizeof( VertexType ) ); } - - bool operator == ( const RGBColorFactory &factory ) const { return _typeOnDisk==factory._typeOnDisk; } - protected: - TypeOnDisk _typeOnDisk; - bool _realTypeOnDisk; - static const std::string _PlyNames[]; - }; - - // The rgba color factory - template< typename Real > - struct RGBAColorFactory : public _Factory< Point< Real , 4 > , RGBAColorFactory< Real > > - { - typedef typename _Factory< Point< Real , 4 > , RGBAColorFactory< Real > >::VertexType VertexType; + bool isStaticallyAllocated( void ) const{ return true; } + PlyProperty plyStaticReadProperty( unsigned int idx ) const; + PlyProperty plyStaticWriteProperty( unsigned int idx ) const; - struct Transform - { - Transform( void ){} - template< typename XForm > Transform( XForm xForm ){} - void inPlace( VertexType &dt ) const {} - }; + RGBColorFactory( TypeOnDisk typeOnDisk=GetTypeOnDisk< unsigned char >() ) : _typeOnDisk( typeOnDisk ) { _realTypeOnDisk = GetTypeOnDisk< Real >()==_typeOnDisk; } - VertexType operator()( void ) const { return VertexType(); } + size_t bufferSize( void ) const { return sizeof( VertexType ); } + void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { memcpy( buffer , &dt , sizeof( VertexType ) ); } + void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const { memcpy( &dt , buffer , sizeof( VertexType ) ); } - unsigned int plyReadNum( void ) const { return 8; } - unsigned int plyWriteNum( void ) const { return 4; } - bool plyValidReadProperties( const bool *flags ) const { for( int d=0 ; d<4 ; d++ ) if( !flags[d] && !flags[d+4] ) return false ; return true ; } - PlyProperty plyReadProperty( unsigned int idx ) const; - PlyProperty plyWriteProperty( unsigned int idx ) const; - bool readASCII( FILE *fp , VertexType &dt ) const { return VertexIO< Real >:: ReadASCII( fp , _typeOnDisk , 4 , &dt[0] ); } - void writeASCII( FILE *fp , const VertexType &dt ) const { VertexIO< Real >:: WriteASCII( fp , _typeOnDisk , 4 , &dt[0] ); } - bool readBinary( FILE *fp , VertexType &dt ) const - { - if( _realTypeOnDisk ) return fread( &dt[0] , sizeof(Real) , 4 , fp )==4; - else return VertexIO< Real >::ReadBinary( fp , _typeOnDisk , 4 , &dt[0] ); - } - void writeBinary( FILE *fp , const VertexType &dt ) const - { - if( _realTypeOnDisk ) fwrite( &dt[0] , sizeof(Real) , 4 , fp ); - VertexIO< Real >::WriteBinary( fp , _typeOnDisk , 4 , &dt[0] ); - } - - bool isStaticallyAllocated( void ) const{ return true; } - PlyProperty plyStaticReadProperty( unsigned int idx ) const; - PlyProperty plyStaticWriteProperty( unsigned int idx ) const; - - RGBAColorFactory( TypeOnDisk typeOnDisk=GetTypeOnDisk< unsigned char >() ) : _typeOnDisk( typeOnDisk ) { _realTypeOnDisk = GetTypeOnDisk< Real >()==_typeOnDisk; } - size_t bufferSize( void ) const { return sizeof( VertexType ); } - void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { memcpy( buffer , &dt , sizeof( VertexType ) ); } - void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const { memcpy( &dt , buffer , sizeof( VertexType ) ); } - - bool operator == ( const RGBAColorFactory &factory ) const { return _typeOnDisk==factory._typeOnDisk; } - protected: - TypeOnDisk _typeOnDisk; - bool _realTypeOnDisk; - static const std::string _PlyNames[]; - }; - - // The value factory - template< typename Real > - struct ValueFactory : public _Factory< Real , ValueFactory< Real > > - { - typedef typename _Factory< Real , ValueFactory< Real > >::VertexType VertexType; + bool operator == ( const RGBColorFactory &factory ) const { return _typeOnDisk==factory._typeOnDisk; } + protected: + TypeOnDisk _typeOnDisk; + bool _realTypeOnDisk; + static const std::string _PlyNames[]; + }; - struct Transform + // The rgba color factory + template< typename Real > + struct RGBAColorFactory : public _Factory< Point< Real , 4 > , RGBAColorFactory< Real > > { - Transform( void ){} - template< typename XForm > Transform( XForm xForm ){} - void inPlace( VertexType &dt ) const {} - }; + typedef typename _Factory< Point< Real , 4 > , RGBAColorFactory< Real > >::VertexType VertexType; - VertexType operator()( void ) const { return (Real)0; } + struct Transform + { + Transform( void ){} + template< typename XForm > Transform( XForm xForm ){} + void inPlace( VertexType &dt ) const {} + }; + + VertexType operator()( void ) const { return VertexType(); } + + unsigned int plyReadNum( void ) const { return 8; } + unsigned int plyWriteNum( void ) const { return 4; } + bool plyValidReadProperties( const bool *flags ) const { for( int d=0 ; d<4 ; d++ ) if( !flags[d] && !flags[d+4] ) return false ; return true ; } + PlyProperty plyReadProperty( unsigned int idx ) const; + PlyProperty plyWriteProperty( unsigned int idx ) const; + bool readASCII( FILE *fp , VertexType &dt ) const { return VertexIO< Real >:: ReadASCII( fp , _typeOnDisk , 4 , &dt[0] ); } + void writeASCII( FILE *fp , const VertexType &dt ) const { VertexIO< Real >:: WriteASCII( fp , _typeOnDisk , 4 , &dt[0] ); } + bool readBinary( FILE *fp , VertexType &dt ) const + { + if( _realTypeOnDisk ) return fread( &dt[0] , sizeof(Real) , 4 , fp )==4; + else return VertexIO< Real >::ReadBinary( fp , _typeOnDisk , 4 , &dt[0] ); + } + void writeBinary( FILE *fp , const VertexType &dt ) const + { + if( _realTypeOnDisk ) fwrite( &dt[0] , sizeof(Real) , 4 , fp ); + VertexIO< Real >::WriteBinary( fp , _typeOnDisk , 4 , &dt[0] ); + } - unsigned int plyReadNum( void ) const { return 1; } - unsigned int plyWriteNum( void ) const { return 1; } - bool plyValidReadProperties( const bool *flags ) const { if( !flags[0] ) return false ; return true ; } - PlyProperty plyReadProperty( unsigned int idx ) const; - PlyProperty plyWriteProperty( unsigned int idx ) const; - bool readASCII( FILE *fp , VertexType &dt ) const { return VertexIO< Real >:: ReadASCII( fp , _typeOnDisk , 1 , &dt ); } - void writeASCII( FILE *fp , const VertexType &dt ) const { VertexIO< Real >:: WriteASCII( fp , _typeOnDisk , 1 , &dt ); } - bool readBinary( FILE *fp , VertexType &dt ) const - { - if( _realTypeOnDisk ) return fread( &dt , sizeof(Real) , 1 , fp )==1; - else return VertexIO< Real >::ReadBinary( fp , _typeOnDisk , 1 , &dt ); - } - void writeBinary( FILE *fp , const VertexType &dt ) const + bool isStaticallyAllocated( void ) const{ return true; } + PlyProperty plyStaticReadProperty( unsigned int idx ) const; + PlyProperty plyStaticWriteProperty( unsigned int idx ) const; + + RGBAColorFactory( TypeOnDisk typeOnDisk=GetTypeOnDisk< unsigned char >() ) : _typeOnDisk( typeOnDisk ) { _realTypeOnDisk = GetTypeOnDisk< Real >()==_typeOnDisk; } + size_t bufferSize( void ) const { return sizeof( VertexType ); } + void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { memcpy( buffer , &dt , sizeof( VertexType ) ); } + void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const { memcpy( &dt , buffer , sizeof( VertexType ) ); } + + bool operator == ( const RGBAColorFactory &factory ) const { return _typeOnDisk==factory._typeOnDisk; } + protected: + TypeOnDisk _typeOnDisk; + bool _realTypeOnDisk; + static const std::string _PlyNames[]; + }; + + // The value factory + template< typename Real > + struct ValueFactory : public _Factory< Real , ValueFactory< Real > > { - if( _realTypeOnDisk ) fwrite( &dt , sizeof(Real) , 1 , fp ); - else VertexIO< Real >::WriteBinary( fp , _typeOnDisk , 1 , &dt ); - } - - bool isStaticallyAllocated( void ) const{ return true; } - PlyProperty plyStaticReadProperty( unsigned int idx ) const; - PlyProperty plyStaticWriteProperty( unsigned int idx ) const; - - ValueFactory( TypeOnDisk typeOnDisk=GetTypeOnDisk< Real >() ) : _typeOnDisk( typeOnDisk ) { _realTypeOnDisk = GetTypeOnDisk< Real >()==_typeOnDisk; } - - size_t bufferSize( void ) const { return sizeof( VertexType ); } - void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { memcpy( buffer , &dt , sizeof( VertexType ) ); } - void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const { memcpy( &dt , buffer , sizeof( VertexType ) ); } - - bool operator == ( const ValueFactory &factory ) const { return _typeOnDisk==factory._typeOnDisk; } - protected: - TypeOnDisk _typeOnDisk; - bool _realTypeOnDisk; - static const std::string _PlyNames[]; - }; - - // The named array factory - template< typename Real > - struct DynamicFactory : public _Factory< Point< Real > , DynamicFactory< Real > > - { - typedef typename _Factory< Point< Real > , DynamicFactory< Real > >::VertexType VertexType; + typedef typename _Factory< Real , ValueFactory< Real > >::VertexType VertexType; + + struct Transform + { + Transform( void ){} + template< typename XForm > Transform( XForm xForm ){} + void inPlace( VertexType &dt ) const {} + }; + + VertexType operator()( void ) const { return (Real)0; } + + unsigned int plyReadNum( void ) const { return 1; } + unsigned int plyWriteNum( void ) const { return 1; } + bool plyValidReadProperties( const bool *flags ) const { if( !flags[0] ) return false ; return true ; } + PlyProperty plyReadProperty( unsigned int idx ) const; + PlyProperty plyWriteProperty( unsigned int idx ) const; + bool readASCII( FILE *fp , VertexType &dt ) const { return VertexIO< Real >:: ReadASCII( fp , _typeOnDisk , 1 , &dt ); } + void writeASCII( FILE *fp , const VertexType &dt ) const { VertexIO< Real >:: WriteASCII( fp , _typeOnDisk , 1 , &dt ); } + bool readBinary( FILE *fp , VertexType &dt ) const + { + if( _realTypeOnDisk ) return fread( &dt , sizeof(Real) , 1 , fp )==1; + else return VertexIO< Real >::ReadBinary( fp , _typeOnDisk , 1 , &dt ); + } + void writeBinary( FILE *fp , const VertexType &dt ) const + { + if( _realTypeOnDisk ) fwrite( &dt , sizeof(Real) , 1 , fp ); + else VertexIO< Real >::WriteBinary( fp , _typeOnDisk , 1 , &dt ); + } + + bool isStaticallyAllocated( void ) const{ return true; } + PlyProperty plyStaticReadProperty( unsigned int idx ) const; + PlyProperty plyStaticWriteProperty( unsigned int idx ) const; + + ValueFactory( TypeOnDisk typeOnDisk=GetTypeOnDisk< Real >() ) : _typeOnDisk( typeOnDisk ) { _realTypeOnDisk = GetTypeOnDisk< Real >()==_typeOnDisk; } - struct Transform + size_t bufferSize( void ) const { return sizeof( VertexType ); } + void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { memcpy( buffer , &dt , sizeof( VertexType ) ); } + void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const { memcpy( &dt , buffer , sizeof( VertexType ) ); } + + bool operator == ( const ValueFactory &factory ) const { return _typeOnDisk==factory._typeOnDisk; } + protected: + TypeOnDisk _typeOnDisk; + bool _realTypeOnDisk; + static const std::string _PlyNames[]; + }; + + // The named array factory + template< typename Real > + struct DynamicFactory : public _Factory< Point< Real > , DynamicFactory< Real > > { - Transform( void ){} - template< typename XForm > Transform( XForm xForm ){} - void inPlace( VertexType &dt ) const {} + typedef typename _Factory< Point< Real > , DynamicFactory< Real > >::VertexType VertexType; + + struct Transform + { + Transform( void ){} + template< typename XForm > Transform( XForm xForm ){} + void inPlace( VertexType &dt ) const {} + }; + + VertexType operator()( void ) const { return Point< Real >( _namesAndTypesOnDisk.size() ); } + unsigned int plyReadNum( void ) const { return (unsigned int )_namesAndTypesOnDisk.size(); } + unsigned int plyWriteNum( void ) const { return (unsigned int )_namesAndTypesOnDisk.size(); } + bool plyValidReadProperties( const bool *flags ) const { for( int d=0 ; d<_namesAndTypesOnDisk.size() ; d++ ) if( !flags[d] ) return false ; return true ; } + PlyProperty plyReadProperty( unsigned int idx ) const; + PlyProperty plyWriteProperty( unsigned int idx ) const; + + bool readASCII( FILE *fp , VertexType &dt ) const; + bool readBinary( FILE *fp , VertexType &dt ) const; + void writeASCII( FILE *fp , const VertexType &dt ) const; + void writeBinary( FILE *fp , const VertexType &dt ) const; + + bool isStaticallyAllocated( void ) const{ return false; } + PlyProperty plyStaticReadProperty( unsigned int idx ) const { ERROR_OUT( "does not support static allocation" ) ; return PlyProperty(); } + PlyProperty plyStaticWriteProperty( unsigned int idx ) const { ERROR_OUT( "does not support static allocation" ) ; return PlyProperty(); } + + size_t size( void ) const { return _namesAndTypesOnDisk.size(); } + + DynamicFactory( const std::vector< std::pair< std::string , TypeOnDisk > > &namesAndTypesOnDisk ); + DynamicFactory( const std::vector< PlyProperty > &plyProperties ); + size_t bufferSize( void ) const { return sizeof(Real) * _namesAndTypesOnDisk.size(); } + void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { for( size_t i=0 ; i<_namesAndTypesOnDisk.size() ; i++ ) ( ( Pointer(Real) )(buffer) )[i] = dt[i]; } + void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const { for( size_t i=0 ; i<_namesAndTypesOnDisk.size() ; i++ ) dt[i] = ( ( ConstPointer( Real ) )(buffer) )[i]; } + + bool operator == ( const DynamicFactory &factory ) const; + protected: + bool _realTypeOnDisk; + std::vector< std::pair< std::string , TypeOnDisk > > _namesAndTypesOnDisk; }; - VertexType operator()( void ) const { return Point< Real >( _namesAndTypesOnDisk.size() ); } - unsigned int plyReadNum( void ) const { return (unsigned int )_namesAndTypesOnDisk.size(); } - unsigned int plyWriteNum( void ) const { return (unsigned int )_namesAndTypesOnDisk.size(); } - bool plyValidReadProperties( const bool *flags ) const { for( int d=0 ; d<_namesAndTypesOnDisk.size() ; d++ ) if( !flags[d] ) return false ; return true ; } - PlyProperty plyReadProperty( unsigned int idx ) const; - PlyProperty plyWriteProperty( unsigned int idx ) const; - - bool readASCII( FILE *fp , VertexType &dt ) const; - bool readBinary( FILE *fp , VertexType &dt ) const; - void writeASCII( FILE *fp , const VertexType &dt ) const; - void writeBinary( FILE *fp , const VertexType &dt ) const; - - bool isStaticallyAllocated( void ) const{ return false; } - PlyProperty plyStaticReadProperty( unsigned int idx ) const { ERROR_OUT( "does not support static allocation" ) ; return PlyProperty(); } - PlyProperty plyStaticWriteProperty( unsigned int idx ) const { ERROR_OUT( "does not support static allocation" ) ; return PlyProperty(); } - - size_t size( void ) const { return _namesAndTypesOnDisk.size(); } - - DynamicFactory( const std::vector< std::pair< std::string , TypeOnDisk > > &namesAndTypesOnDisk ); - DynamicFactory( const std::vector< PlyProperty > &plyProperties ); - size_t bufferSize( void ) const { return sizeof(Real) * _namesAndTypesOnDisk.size(); } - void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { for( size_t i=0 ; i<_namesAndTypesOnDisk.size() ; i++ ) ( ( Pointer(Real) )(buffer) )[i] = dt[i]; } - void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const { for( size_t i=0 ; i<_namesAndTypesOnDisk.size() ; i++ ) dt[i] = ( ( ConstPointer( Real ) )(buffer) )[i]; } - - bool operator == ( const DynamicFactory &factory ) const; - protected: - bool _realTypeOnDisk; - std::vector< std::pair< std::string , TypeOnDisk > > _namesAndTypesOnDisk; - }; - - // A factory for building the union of multiple components - template< typename Real , typename ... Factories > - struct Factory : public _Factory< VectorTypeUnion< Real , typename Factories::VertexType ... > , Factory< Real , Factories ... > > - { - protected: - typedef std::tuple< Factories ... > _FactoryTuple; - public: - typedef typename _Factory< VectorTypeUnion< Real , typename Factories::VertexType ... > , Factory< Real , Factories ... > >::VertexType VertexType; - template< unsigned int I > using FactoryType = typename std::tuple_element< I , _FactoryTuple >::type; - template< unsigned int I > FactoryType< I >& get( void ) { return std::get< I >( _factoryTuple ); } - template< unsigned int I > const FactoryType< I >& get( void ) const { return std::get< I >( _factoryTuple ); } - - struct Transform + // A factory for building the union of multiple components + template< typename Real , typename ... Factories > + struct Factory : public _Factory< VectorTypeUnion< Real , typename Factories::VertexType ... > , Factory< Real , Factories ... > > { protected: - typedef std::tuple< typename Factories::Transform ... > _TransformTuple; + typedef std::tuple< Factories ... > _FactoryTuple; public: - Transform( void ){} - template< typename XForm > - Transform( XForm xForm ){ _set<0>( xForm ); } - void inPlace( VertexType &dt ) const { _inPlace< 0 >( dt ); } - - template< unsigned int I > using TransformType = typename std::tuple_element< I , _TransformTuple >::type; - template< unsigned int I > TransformType< I >& get( void ) { return std::get< I >( _transformTuple ); } - template< unsigned int I > const TransformType< I >& get( void ) const { return std::get< I >( _transformTuple ); } + typedef typename _Factory< VectorTypeUnion< Real , typename Factories::VertexType ... > , Factory< Real , Factories ... > >::VertexType VertexType; + template< unsigned int I > using FactoryType = typename std::tuple_element< I , _FactoryTuple >::type; + template< unsigned int I > FactoryType< I >& get( void ) { return std::get< I >( _factoryTuple ); } + template< unsigned int I > const FactoryType< I >& get( void ) const { return std::get< I >( _factoryTuple ); } + + struct Transform + { + protected: + typedef std::tuple< typename Factories::Transform ... > _TransformTuple; + public: + Transform( void ){} + template< typename XForm > + Transform( XForm xForm ){ _set<0>( xForm ); } + void inPlace( VertexType &dt ) const { _inPlace< 0 >( dt ); } + + template< unsigned int I > using TransformType = typename std::tuple_element< I , _TransformTuple >::type; + template< unsigned int I > TransformType< I >& get( void ) { return std::get< I >( _transformTuple ); } + template< unsigned int I > const TransformType< I >& get( void ) const { return std::get< I >( _transformTuple ); } + protected: + _TransformTuple _transformTuple; + template< unsigned int I , typename XForm > typename std::enable_if< I!=sizeof...(Factories) >::type _set( XForm xForm ){ this->template get() = xForm ; _set< I+1 >( xForm ); } + template< unsigned int I , typename XForm > typename std::enable_if< I==sizeof...(Factories) >::type _set( XForm xForm ){} + template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) >::type _inPlace( VertexType &dt ) const { this->template get().inPlace( dt.template get() ) ; _inPlace< I+1 >( dt ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) >::type _inPlace( VertexType &dt ) const {} + }; + + Factory( void ){} + Factory( Factories ... factories ) : _factoryTuple( factories ... ){ } + + VertexType operator()( void ) const{ return _VertexType( std::make_index_sequence< sizeof...(Factories) >() ); } + + unsigned int plyReadNum( void ) const { return _plyReadNum<0>(); } + unsigned int plyWriteNum( void ) const { return _plyWriteNum<0>(); } + bool plyValidReadProperties( const bool *flags ) const { return _plyValidReadProperties<0>( flags ) ; } + template< unsigned int I > bool plyValidReadProperties( const bool* flags ) const { return get< I >().plyValidReadProperties( flags + _readOffset< I >() ) ; } + PlyProperty plyReadProperty( unsigned int idx ) const { return _plyReadProperty<0>( idx , 0 ); } + PlyProperty plyWriteProperty( unsigned int idx ) const { return _plyWriteProperty<0>( idx , 0 ); } + bool readASCII( FILE *fp , VertexType &dt ) const { return _readASCII<0>( fp , dt ); } + bool readBinary( FILE *fp , VertexType &dt ) const { return _readBinary<0>( fp , dt ); } + void writeASCII( FILE *fp , const VertexType &dt ) const { _writeASCII<0>( fp , dt ); } + void writeBinary( FILE *fp , const VertexType &dt ) const { _writeBinary<0>( fp , dt ); } + + bool isStaticallyAllocated( void ) const { return _isStaticallyAllocated<0>(); } + PlyProperty plyStaticReadProperty( unsigned int idx ) const { return _plyStaticReadProperty<0>( idx ); } + PlyProperty plyStaticWriteProperty( unsigned int idx ) const { return _plyStaticWriteProperty<0>( idx ); } + + size_t bufferSize( void ) const { return _bufferSize<0>(); } + void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { _toBuffer<0>( dt , buffer ); } + void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const { _fromBuffer<0>( buffer , dt ); } + + bool operator == ( const Factory &factory ) const { return _equal<0>( factory ); } protected: - _TransformTuple _transformTuple; - template< unsigned int I , typename XForm > typename std::enable_if< I!=sizeof...(Factories) >::type _set( XForm xForm ){ this->template get() = xForm ; _set< I+1 >( xForm ); } - template< unsigned int I , typename XForm > typename std::enable_if< I==sizeof...(Factories) >::type _set( XForm xForm ){} - template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) >::type _inPlace( VertexType &dt ) const { this->template get().inPlace( dt.template get() ) ; _inPlace< I+1 >( dt ); } - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) >::type _inPlace( VertexType &dt ) const {} + _FactoryTuple _factoryTuple; + template< size_t ... Is > VertexType _VertexType( std::index_sequence< Is ... > ) const{ return VertexType( get().operator()() ... ); } + + template< typename Factory1 , typename Factory2 > + static typename std::enable_if< !std::is_same< Factory1 , Factory1 >::value , bool >::type _EqualFactories( const Factory1 &f1 , const Factory1 &f2 ){ return false; } + template< typename Factory1 , typename Factory2 > + static typename std::enable_if< std::is_same< Factory1 , Factory1 >::value , bool >::type _EqualFactories( const Factory1 &f1 , const Factory1 &f2 ){ return f1==f2; } + + + template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , unsigned int >::type _plyReadNum( void ) const { return get().plyReadNum() + _plyReadNum< I+1 >(); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , unsigned int >::type _plyReadNum( void ) const { return 0; } + template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , unsigned int >::type _plyWriteNum( void ) const { return get().plyWriteNum() + _plyWriteNum< I+1 >(); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , unsigned int >::type _plyWriteNum( void ) const { return 0; } + template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , bool >::type _plyValidReadProperties( const bool *flags ) const { return get< I >().plyValidReadProperties( flags ) && _plyValidReadProperties< I+1 >( flags + get< I >().plyReadNum() ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , bool >::type _plyValidReadProperties( const bool *flags ) const { return true; } + template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , PlyProperty >::type _plyReadProperty( unsigned int idx , size_t offset ) const; + template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , PlyProperty >::type _plyWriteProperty( unsigned int idx , size_t offset ) const; + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyReadProperty( unsigned int idx , size_t offset ) const { ERROR_OUT( "read property out of bounds" ) ; return PlyProperty(); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyWriteProperty( unsigned int idx , size_t offset ) const { ERROR_OUT( "write property out of bounds" ) ; return PlyProperty(); } + template< unsigned int I > typename std::enable_if< I==0 , unsigned int >::type _readOffset( void ) const { return 0; } + template< unsigned int I > typename std::enable_if< I!=0 , unsigned int >::type _readOffset( void ) const { return _readOffset< I-1 >() + get< I-1 >().plyReadNum(); } + template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , bool >::type _readASCII( FILE *fp , VertexType &dt ) const { return this->template get().readASCII( fp , dt.template get() ) && _readASCII< I+1 >( fp , dt ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , bool >::type _readASCII( FILE *fp , VertexType &dt ) const { return true; } + template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , bool >::type _readBinary( FILE *fp , VertexType &dt ) const { return this->template get().readBinary( fp , dt.template get() ) && _readBinary< I+1 >( fp , dt ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , bool >::type _readBinary( FILE *fp , VertexType &dt ) const { return true; } + template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) >::type _writeASCII( FILE *fp , const VertexType &dt ) const { this->template get().writeASCII( fp , dt.template get() ) ; _writeASCII< I+1 >( fp , dt ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) >::type _writeASCII( FILE *fp , const VertexType &dt ) const {} + template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) >::type _writeBinary( FILE *fp , const VertexType &dt ) const { this->template get().writeBinary( fp , dt.template get() ) ; _writeBinary< I+1 >( fp , dt ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) >::type _writeBinary( FILE *fp , const VertexType &dt ) const {} + + template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , bool >::type _isStaticallyAllocated( void ) const { return this->template get< I >().isStaticallyAllocated() && _isStaticallyAllocated< I+1 >(); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , bool >::type _isStaticallyAllocated( void ) const { return true; } + template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , PlyProperty >::type _plyStaticReadProperty ( unsigned int idx ) const; + template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , PlyProperty >::type _plyStaticWriteProperty( unsigned int idx ) const; + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyStaticReadProperty ( unsigned int idx ) const { ERROR_OUT( "read property out of bounds" ) ; return PlyProperty(); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyStaticWriteProperty( unsigned int idx ) const { ERROR_OUT( "write property out of bounds" ) ; return PlyProperty(); } + + template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , size_t >::type _bufferSize( void ) const { return this->template get().bufferSize() + _bufferSize< I+1 >(); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , size_t >::type _bufferSize( void ) const { return 0; } + template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) >::type _toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { this->template get().toBuffer( dt.template get() , buffer ) ; _toBuffer< I+1 >( dt , buffer + this->template get().bufferSize() ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) >::type _toBuffer( const VertexType &dt , Pointer( char ) buffer ) const {} + template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) >::type _fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const {this->template get().fromBuffer( buffer , dt.template get() ) ; _fromBuffer< I+1 >( buffer + this->template get().bufferSize() , dt ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) >::type _fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const {} + + template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , bool >::type _equal( const Factory &factory ) const { return _EqualFactories< FactoryType , Factory >( this->template get< I >() , factory.template get() ) && _equal< I+1 >( factory ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , bool >::type _equal( const Factory &factory ) const { return true; } }; - - Factory( void ){} - Factory( Factories ... factories ) : _factoryTuple( factories ... ){ } - - VertexType operator()( void ) const{ return _VertexType( std::make_index_sequence< sizeof...(Factories) >() ); } - - unsigned int plyReadNum( void ) const { return _plyReadNum<0>(); } - unsigned int plyWriteNum( void ) const { return _plyWriteNum<0>(); } - bool plyValidReadProperties( const bool *flags ) const { return _plyValidReadProperties<0>( flags ) ; } - template< unsigned int I > bool plyValidReadProperties( const bool* flags ) const { return get< I >().plyValidReadProperties( flags + _readOffset< I >() ) ; } - PlyProperty plyReadProperty( unsigned int idx ) const { return _plyReadProperty<0>( idx , 0 ); } - PlyProperty plyWriteProperty( unsigned int idx ) const { return _plyWriteProperty<0>( idx , 0 ); } - bool readASCII( FILE *fp , VertexType &dt ) const { return _readASCII<0>( fp , dt ); } - bool readBinary( FILE *fp , VertexType &dt ) const { return _readBinary<0>( fp , dt ); } - void writeASCII( FILE *fp , const VertexType &dt ) const { _writeASCII<0>( fp , dt ); } - void writeBinary( FILE *fp , const VertexType &dt ) const { _writeBinary<0>( fp , dt ); } - - bool isStaticallyAllocated( void ) const { return _isStaticallyAllocated<0>(); } - PlyProperty plyStaticReadProperty( unsigned int idx ) const { return _plyStaticReadProperty<0>( idx ); } - PlyProperty plyStaticWriteProperty( unsigned int idx ) const { return _plyStaticWriteProperty<0>( idx ); } - - size_t bufferSize( void ) const { return _bufferSize<0>(); } - void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { _toBuffer<0>( dt , buffer ); } - void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const { _fromBuffer<0>( buffer , dt ); } - - bool operator == ( const Factory &factory ) const { return _equal<0>( factory ); } - protected: - _FactoryTuple _factoryTuple; - template< size_t ... Is > VertexType _VertexType( std::index_sequence< Is ... > ) const{ return VertexType( get().operator()() ... ); } - - template< typename Factory1 , typename Factory2 > - static typename std::enable_if< !std::is_same< Factory1 , Factory1 >::value , bool >::type _EqualFactories( const Factory1 &f1 , const Factory1 &f2 ){ return false; } - template< typename Factory1 , typename Factory2 > - static typename std::enable_if< std::is_same< Factory1 , Factory1 >::value , bool >::type _EqualFactories( const Factory1 &f1 , const Factory1 &f2 ){ return f1==f2; } - - - template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , unsigned int >::type _plyReadNum( void ) const { return get().plyReadNum() + _plyReadNum< I+1 >(); } - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , unsigned int >::type _plyReadNum( void ) const { return 0; } - template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , unsigned int >::type _plyWriteNum( void ) const { return get().plyWriteNum() + _plyWriteNum< I+1 >(); } - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , unsigned int >::type _plyWriteNum( void ) const { return 0; } - template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , bool >::type _plyValidReadProperties( const bool *flags ) const { return get< I >().plyValidReadProperties( flags ) && _plyValidReadProperties< I+1 >( flags + get< I >().plyReadNum() ); } - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , bool >::type _plyValidReadProperties( const bool *flags ) const { return true; } - template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , PlyProperty >::type _plyReadProperty( unsigned int idx , size_t offset ) const; - template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , PlyProperty >::type _plyWriteProperty( unsigned int idx , size_t offset ) const; - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyReadProperty( unsigned int idx , size_t offset ) const { ERROR_OUT( "read property out of bounds" ) ; return PlyProperty(); } - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyWriteProperty( unsigned int idx , size_t offset ) const { ERROR_OUT( "write property out of bounds" ) ; return PlyProperty(); } - template< unsigned int I > typename std::enable_if< I==0 , unsigned int >::type _readOffset( void ) const { return 0; } - template< unsigned int I > typename std::enable_if< I!=0 , unsigned int >::type _readOffset( void ) const { return _readOffset< I-1 >() + get< I-1 >().plyReadNum(); } - template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , bool >::type _readASCII( FILE *fp , VertexType &dt ) const { return this->template get().readASCII( fp , dt.template get() ) && _readASCII< I+1 >( fp , dt ); } - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , bool >::type _readASCII( FILE *fp , VertexType &dt ) const { return true; } - template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , bool >::type _readBinary( FILE *fp , VertexType &dt ) const { return this->template get().readBinary( fp , dt.template get() ) && _readBinary< I+1 >( fp , dt ); } - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , bool >::type _readBinary( FILE *fp , VertexType &dt ) const { return true; } - template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) >::type _writeASCII( FILE *fp , const VertexType &dt ) const { this->template get().writeASCII( fp , dt.template get() ) ; _writeASCII< I+1 >( fp , dt ); } - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) >::type _writeASCII( FILE *fp , const VertexType &dt ) const {} - template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) >::type _writeBinary( FILE *fp , const VertexType &dt ) const { this->template get().writeBinary( fp , dt.template get() ) ; _writeBinary< I+1 >( fp , dt ); } - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) >::type _writeBinary( FILE *fp , const VertexType &dt ) const {} - - template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , bool >::type _isStaticallyAllocated( void ) const { return this->template get< I >().isStaticallyAllocated() && _isStaticallyAllocated< I+1 >(); } - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , bool >::type _isStaticallyAllocated( void ) const { return true; } - template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , PlyProperty >::type _plyStaticReadProperty ( unsigned int idx ) const; - template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , PlyProperty >::type _plyStaticWriteProperty( unsigned int idx ) const; - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyStaticReadProperty ( unsigned int idx ) const { ERROR_OUT( "read property out of bounds" ) ; return PlyProperty(); } - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyStaticWriteProperty( unsigned int idx ) const { ERROR_OUT( "write property out of bounds" ) ; return PlyProperty(); } - - template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , size_t >::type _bufferSize( void ) const { return this->template get().bufferSize() + _bufferSize< I+1 >(); } - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , size_t >::type _bufferSize( void ) const { return 0; } - template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) >::type _toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { this->template get().toBuffer( dt.template get() , buffer ) ; _toBuffer< I+1 >( dt , buffer + this->template get().bufferSize() ); } - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) >::type _toBuffer( const VertexType &dt , Pointer( char ) buffer ) const {} - template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) >::type _fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const {this->template get().fromBuffer( buffer , dt.template get() ) ; _fromBuffer< I+1 >( buffer + this->template get().bufferSize() , dt ); } - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) >::type _fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const {} - - template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , bool >::type _equal( const Factory &factory ) const { return _EqualFactories< FactoryType , Factory >( this->template get< I >() , factory.template get() ) && _equal< I+1 >( factory ); } - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , bool >::type _equal( const Factory &factory ) const { return true; } - }; -} + } #include "VertexFactory.inl" +} #endif // VERTEX_FACTORY_INCLUDED \ No newline at end of file diff --git a/Src/Window.h b/Src/Window.h index e936e42a..0b4452c2 100644 --- a/Src/Window.h +++ b/Src/Window.h @@ -34,416 +34,420 @@ DAMAGE. #include "Allocator.h" #include "Array.h" -////////////////////////////////////////////////////////// -// Some basic functionality for integer parameter packs // -////////////////////////////////////////////////////////// - -// A wrapper class for passing unsigned integer parameter packs -template< unsigned int ... Values > struct UIntPack{}; -template< unsigned int _Value , unsigned int ... _Values > struct UIntPack< _Value , _Values ... > +namespace PoissonRecon { - static const unsigned int First = _Value; - typedef UIntPack< _Values ... > Rest; - - static const unsigned int Size = 1 + sizeof ... ( _Values ); - template< unsigned int __Value > using Append = UIntPack< _Value , _Values ... , __Value >; - template< unsigned int __Value > using Prepend = UIntPack< __Value , _Value , _Values ... >; - static const unsigned int Values[]; - static constexpr unsigned int Min( void ){ return _Value < Rest::Min() ? _Value : Rest::Min(); } - static constexpr unsigned int Max( void ){ return _Value > Rest::Max() ? _Value : Rest::Max(); } - - using Reverse = typename Rest::Reverse::template Append< First >; - - template< typename T > struct Plus{}; - template< typename T > struct Minus{}; - template< typename T > struct Compare{}; - template< unsigned int __Value , unsigned int ... __Values > struct Plus < UIntPack< __Value , __Values ... > >{ typedef typename Rest::template Plus < UIntPack< __Values ... > >::type::template Prepend< _Value + __Value > type; }; - template< unsigned int __Value , unsigned int ... __Values > struct Minus< UIntPack< __Value , __Values ... > >{ typedef typename Rest::template Minus< UIntPack< __Values ... > >::type::template Prepend< _Value - __Value > type; }; - template< unsigned int __Value , unsigned int ... __Values > struct Compare< UIntPack< __Value , __Values ... > > - { - static const bool Equal = _Value==__Value && Rest::template Compare< UIntPack< __Values ... > >:: Equal; - static const bool NotEqual = _Value!=__Value || Rest::template Compare< UIntPack< __Values ... > >:: NotEqual; - static const bool LessThan = _Value< __Value && Rest::template Compare< UIntPack< __Values ... > >:: LessThan ; - static const bool LessThanOrEqual = _Value<=__Value && Rest::template Compare< UIntPack< __Values ... > >:: LessThanOrEqual; - static const bool GreaterThan = _Value> __Value && Rest::template Compare< UIntPack< __Values ... > >::GreaterThan ; - static const bool GreaterThanOrEqual = _Value>=__Value && Rest::template Compare< UIntPack< __Values ... > >::GreaterThanOrEqual; - }; - - static void Print( FILE* fp=stdout , bool leadingSpace=false ){ if( leadingSpace ) fprintf( fp , " " ) ; fprintf( fp , "%d" , _Value ) ; Rest::Print( fp , true ); } - - template< unsigned int I > constexpr static typename std::enable_if< I==0 , unsigned int >::type Get( void ){ return _Value; } - template< unsigned int I > constexpr static typename std::enable_if< I!=0 , unsigned int >::type Get( void ){ return Rest::template Get< I-1 >(); } - template< unsigned int __Value , unsigned int ... __Values > constexpr bool operator < ( UIntPack< __Value , __Values ... > ) const { return _Value< __Value && Rest()< UIntPack< __Values ... >(); } - template< unsigned int __Value , unsigned int ... __Values > constexpr bool operator <= ( UIntPack< __Value , __Values ... > ) const { return _Value<=__Value && Rest()<=UIntPack< __Values ... >(); } - template< unsigned int __Value , unsigned int ... __Values > constexpr bool operator > ( UIntPack< __Value , __Values ... > ) const { return _Value> __Value && Rest()> UIntPack< __Values ... >(); } - template< unsigned int __Value , unsigned int ... __Values > constexpr bool operator >= ( UIntPack< __Value , __Values ... > ) const { return _Value>=__Value && Rest()>=UIntPack< __Values ... >(); } - template< unsigned int __Value , unsigned int ... __Values > constexpr bool operator == ( UIntPack< __Value , __Values ... > ) const { return _Value==__Value && Rest()==UIntPack< __Values ... >(); } - template< unsigned int __Value , unsigned int ... __Values > constexpr bool operator != ( UIntPack< __Value , __Values ... > ) const { return _Value!=__Value && Rest()!=UIntPack< __Values ... >(); } -}; + ////////////////////////////////////////////////////////// + // Some basic functionality for integer parameter packs // + ////////////////////////////////////////////////////////// -template< unsigned int _Value > struct UIntPack< _Value > -{ - static const unsigned int First = _Value; - - static const unsigned int Size = 1; - template< unsigned int __Value > using Append = UIntPack< _Value , __Value >; - template< unsigned int __Value > using Prepend = UIntPack< __Value , _Value >; - static const unsigned int Values[]; - static constexpr unsigned int Min( void ){ return _Value; } - static constexpr unsigned int Max( void ){ return _Value; } - - using Reverse = UIntPack< _Value >; - - template< typename T > struct Plus{}; - template< typename T > struct Minus{}; - template< typename T > struct Compare{}; - template< unsigned int __Value > struct Plus < UIntPack< __Value > >{ typedef UIntPack< _Value + __Value > type; }; - template< unsigned int __Value > struct Minus< UIntPack< __Value > >{ typedef UIntPack< _Value - __Value > type; }; - template< unsigned int __Value > struct Compare< UIntPack< __Value > > + // A wrapper class for passing unsigned integer parameter packs + template< unsigned int ... Values > struct UIntPack{}; + template< unsigned int _Value , unsigned int ... _Values > struct UIntPack< _Value , _Values ... > { - static const bool Equal = _Value==__Value; - static const bool NotEqual = _Value!=__Value; - static const bool LessThan = _Value< __Value; - static const bool LessThanOrEqual = _Value<=__Value; - static const bool GreaterThan = _Value> __Value; - static const bool GreaterThanOrEqual = _Value>=__Value; + static const unsigned int First = _Value; + typedef UIntPack< _Values ... > Rest; + + static const unsigned int Size = 1 + sizeof ... ( _Values ); + template< unsigned int __Value > using Append = UIntPack< _Value , _Values ... , __Value >; + template< unsigned int __Value > using Prepend = UIntPack< __Value , _Value , _Values ... >; + static const unsigned int Values[]; + static constexpr unsigned int Min( void ){ return _Value < Rest::Min() ? _Value : Rest::Min(); } + static constexpr unsigned int Max( void ){ return _Value > Rest::Max() ? _Value : Rest::Max(); } + + using Reverse = typename Rest::Reverse::template Append< First >; + + template< typename T > struct Plus{}; + template< typename T > struct Minus{}; + template< typename T > struct Compare{}; + template< unsigned int __Value , unsigned int ... __Values > struct Plus < UIntPack< __Value , __Values ... > >{ typedef typename Rest::template Plus < UIntPack< __Values ... > >::type::template Prepend< _Value + __Value > type; }; + template< unsigned int __Value , unsigned int ... __Values > struct Minus< UIntPack< __Value , __Values ... > >{ typedef typename Rest::template Minus< UIntPack< __Values ... > >::type::template Prepend< _Value - __Value > type; }; + template< unsigned int __Value , unsigned int ... __Values > struct Compare< UIntPack< __Value , __Values ... > > + { + static const bool Equal = _Value==__Value && Rest::template Compare< UIntPack< __Values ... > >:: Equal; + static const bool NotEqual = _Value!=__Value || Rest::template Compare< UIntPack< __Values ... > >:: NotEqual; + static const bool LessThan = _Value< __Value && Rest::template Compare< UIntPack< __Values ... > >:: LessThan ; + static const bool LessThanOrEqual = _Value<=__Value && Rest::template Compare< UIntPack< __Values ... > >:: LessThanOrEqual; + static const bool GreaterThan = _Value> __Value && Rest::template Compare< UIntPack< __Values ... > >::GreaterThan ; + static const bool GreaterThanOrEqual = _Value>=__Value && Rest::template Compare< UIntPack< __Values ... > >::GreaterThanOrEqual; + }; + + static void Print( FILE* fp=stdout , bool leadingSpace=false ){ if( leadingSpace ) fprintf( fp , " " ) ; fprintf( fp , "%d" , _Value ) ; Rest::Print( fp , true ); } + + template< unsigned int I > constexpr static typename std::enable_if< I==0 , unsigned int >::type Get( void ){ return _Value; } + template< unsigned int I > constexpr static typename std::enable_if< I!=0 , unsigned int >::type Get( void ){ return Rest::template Get< I-1 >(); } + + template< unsigned int __Value , unsigned int ... __Values > constexpr bool operator < ( UIntPack< __Value , __Values ... > ) const { return _Value< __Value && Rest()< UIntPack< __Values ... >(); } + template< unsigned int __Value , unsigned int ... __Values > constexpr bool operator <= ( UIntPack< __Value , __Values ... > ) const { return _Value<=__Value && Rest()<=UIntPack< __Values ... >(); } + template< unsigned int __Value , unsigned int ... __Values > constexpr bool operator > ( UIntPack< __Value , __Values ... > ) const { return _Value> __Value && Rest()> UIntPack< __Values ... >(); } + template< unsigned int __Value , unsigned int ... __Values > constexpr bool operator >= ( UIntPack< __Value , __Values ... > ) const { return _Value>=__Value && Rest()>=UIntPack< __Values ... >(); } + template< unsigned int __Value , unsigned int ... __Values > constexpr bool operator == ( UIntPack< __Value , __Values ... > ) const { return _Value==__Value && Rest()==UIntPack< __Values ... >(); } + template< unsigned int __Value , unsigned int ... __Values > constexpr bool operator != ( UIntPack< __Value , __Values ... > ) const { return _Value!=__Value && Rest()!=UIntPack< __Values ... >(); } }; - static void Print( FILE* fp=stdout , bool leadingSpace=false ){ if( leadingSpace ) fprintf( fp , " " ) ; fprintf( fp , "%d" , _Value ); } - template< unsigned int I > constexpr static unsigned int Get( void ){ static_assert( I==0 , "[ERROR] UIntPack< Value >::Get called with non-zero index" ) ; return _Value; } - - template< unsigned int __Value > constexpr bool operator < ( UIntPack< __Value > ) const { return _Value< __Value; } - template< unsigned int __Value > constexpr bool operator <= ( UIntPack< __Value > ) const { return _Value<=__Value; } - template< unsigned int __Value > constexpr bool operator > ( UIntPack< __Value > ) const { return _Value> __Value; } - template< unsigned int __Value > constexpr bool operator >= ( UIntPack< __Value > ) const { return _Value>=__Value; } - template< unsigned int __Value > constexpr bool operator == ( UIntPack< __Value > ) const { return _Value==__Value; } - template< unsigned int __Value > constexpr bool operator != ( UIntPack< __Value > ) const { return _Value!=__Value; } -}; -template< unsigned int _Value , unsigned int ... _Values > const unsigned int UIntPack< _Value , _Values ... >::Values[] = { _Value , _Values ... }; -template< unsigned int _Value > const unsigned int UIntPack< _Value >::Values[] = { _Value }; -template< unsigned int ... V1 , unsigned int ... V2 > typename UIntPack< V1 ... >::template Plus < UIntPack< V2 ... > >::type operator + ( UIntPack< V1 ... > , UIntPack< V2 ... > ){ return typename UIntPack< V1 ... >::template Plus < UIntPack< V2 ... > >::type(); } -template< unsigned int ... V1 , unsigned int ... V2 > typename UIntPack< V1 ... >::template Minus< UIntPack< V2 ... > >::type operator - ( UIntPack< V1 ... > , UIntPack< V2 ... > ){ return typename UIntPack< V1 ... >::template Minus< UIntPack< V2 ... > >::type(); } - -template< int ... Values > struct IntPack{}; -template< int _Value , int ... _Values > struct IntPack< _Value , _Values ... > -{ - static const int First = _Value; - typedef IntPack< _Values ... > Rest; - - static const unsigned int Size = 1 + sizeof ... ( _Values ); - template< int __Value > using Append = IntPack< _Value , _Values ... , __Value >; - template< int __Value > using Prepend = IntPack< __Value , _Value , _Values ... >; - static const int Values[]; - static constexpr int Min( void ){ return _Value < Rest::Min ? _Value : Rest::Min; } - static constexpr int Max( void ){ return _Value > Rest::Max ? _Value : Rest::Max; } - - using Reverse = typename Rest::Reverse::template Append< First >; - - template< typename T > struct Plus{}; - template< typename T > struct Minus{}; - template< typename T > struct Compare{}; - template< int __Value , int ... __Values > struct Plus < IntPack< __Value , __Values ... > >{ typedef typename Rest::template Plus < IntPack< __Values ... > >::type::template Prepend< _Value + __Value > type; }; - template< int __Value , int ... __Values > struct Minus< IntPack< __Value , __Values ... > >{ typedef typename Rest::template Minus< IntPack< __Values ... > >::type::template Prepend< _Value - __Value > type; }; - template< int __Value , int ... __Values > struct Compare< IntPack< __Value , __Values ... > > + template< unsigned int _Value > struct UIntPack< _Value > { - static const bool Equal = _Value==__Value && Rest::template Compare< IntPack< __Values ... > >:: Equal; - static const bool NotEqual = _Value!=__Value || Rest::template Compare< IntPack< __Values ... > >:: NotEqual; - static const bool LessThan = _Value< __Value && Rest::template Compare< IntPack< __Values ... > >:: LessThan ; - static const bool LessThanOrEqual = _Value<=__Value && Rest::template Compare< IntPack< __Values ... > >:: LessThanOrEqual; - static const bool GreaterThan = _Value> __Value && Rest::template Compare< IntPack< __Values ... > >::GreaterThan ; - static const bool GreaterThanOrEqual = _Value>=__Value && Rest::template Compare< IntPack< __Values ... > >::GreaterThanOrEqual; + static const unsigned int First = _Value; + + static const unsigned int Size = 1; + template< unsigned int __Value > using Append = UIntPack< _Value , __Value >; + template< unsigned int __Value > using Prepend = UIntPack< __Value , _Value >; + static const unsigned int Values[]; + static constexpr unsigned int Min( void ){ return _Value; } + static constexpr unsigned int Max( void ){ return _Value; } + + using Reverse = UIntPack< _Value >; + + template< typename T > struct Plus{}; + template< typename T > struct Minus{}; + template< typename T > struct Compare{}; + template< unsigned int __Value > struct Plus < UIntPack< __Value > >{ typedef UIntPack< _Value + __Value > type; }; + template< unsigned int __Value > struct Minus< UIntPack< __Value > >{ typedef UIntPack< _Value - __Value > type; }; + template< unsigned int __Value > struct Compare< UIntPack< __Value > > + { + static const bool Equal = _Value==__Value; + static const bool NotEqual = _Value!=__Value; + static const bool LessThan = _Value< __Value; + static const bool LessThanOrEqual = _Value<=__Value; + static const bool GreaterThan = _Value> __Value; + static const bool GreaterThanOrEqual = _Value>=__Value; + }; + + static void Print( FILE* fp=stdout , bool leadingSpace=false ){ if( leadingSpace ) fprintf( fp , " " ) ; fprintf( fp , "%d" , _Value ); } + template< unsigned int I > constexpr static unsigned int Get( void ){ static_assert( I==0 , "[ERROR] UIntPack< Value >::Get called with non-zero index" ) ; return _Value; } + + template< unsigned int __Value > constexpr bool operator < ( UIntPack< __Value > ) const { return _Value< __Value; } + template< unsigned int __Value > constexpr bool operator <= ( UIntPack< __Value > ) const { return _Value<=__Value; } + template< unsigned int __Value > constexpr bool operator > ( UIntPack< __Value > ) const { return _Value> __Value; } + template< unsigned int __Value > constexpr bool operator >= ( UIntPack< __Value > ) const { return _Value>=__Value; } + template< unsigned int __Value > constexpr bool operator == ( UIntPack< __Value > ) const { return _Value==__Value; } + template< unsigned int __Value > constexpr bool operator != ( UIntPack< __Value > ) const { return _Value!=__Value; } }; + template< unsigned int _Value , unsigned int ... _Values > const unsigned int UIntPack< _Value , _Values ... >::Values[] = { _Value , _Values ... }; + template< unsigned int _Value > const unsigned int UIntPack< _Value >::Values[] = { _Value }; + template< unsigned int ... V1 , unsigned int ... V2 > typename UIntPack< V1 ... >::template Plus < UIntPack< V2 ... > >::type operator + ( UIntPack< V1 ... > , UIntPack< V2 ... > ){ return typename UIntPack< V1 ... >::template Plus < UIntPack< V2 ... > >::type(); } + template< unsigned int ... V1 , unsigned int ... V2 > typename UIntPack< V1 ... >::template Minus< UIntPack< V2 ... > >::type operator - ( UIntPack< V1 ... > , UIntPack< V2 ... > ){ return typename UIntPack< V1 ... >::template Minus< UIntPack< V2 ... > >::type(); } - static void Print( FILE* fp=stdout , bool leadingSpace=false ){ if( leadingSpace ) fprintf( fp , " " ) ; fprintf( fp , "%d" , _Value ) ; Rest::Print( fp , true ); } - - template< unsigned int I > constexpr static typename std::enable_if< I==0 , unsigned int >::type Get( void ){ return _Value; } - template< unsigned int I > constexpr static typename std::enable_if< I!=0 , unsigned int >::type Get( void ){ return Rest::template Get< I-1 >(); } - - template< int __Value , int ... __Values > constexpr bool operator < ( IntPack< __Value , __Values ... > ) const { return _Value< __Value && Rest()< IntPack< __Values ... >(); } - template< int __Value , int ... __Values > constexpr bool operator <= ( IntPack< __Value , __Values ... > ) const { return _Value<=__Value && Rest()<=IntPack< __Values ... >(); } - template< int __Value , int ... __Values > constexpr bool operator > ( IntPack< __Value , __Values ... > ) const { return _Value> __Value && Rest()> IntPack< __Values ... >(); } - template< int __Value , int ... __Values > constexpr bool operator >= ( IntPack< __Value , __Values ... > ) const { return _Value>=__Value && Rest()>=IntPack< __Values ... >(); } - template< int __Value , int ... __Values > constexpr bool operator == ( IntPack< __Value , __Values ... > ) const { return _Value==__Value && Rest()==IntPack< __Values ... >(); } - template< int __Value , int ... __Values > constexpr bool operator != ( IntPack< __Value , __Values ... > ) const { return _Value!=__Value && Rest()!=IntPack< __Values ... >(); } -}; -template< int _Value > struct IntPack< _Value > -{ - static const int First = _Value; - - static const unsigned int Size = 1; - template< int __Value > using Append = IntPack< _Value , __Value >; - template< int __Value > using Prepend = IntPack< __Value , _Value >; - static const int Values[]; - static constexpr int Min( void ){ return _Value; } - static constexpr int Max( void ){ return _Value; } - - using Reverse = IntPack< _Value >; - - template< typename T > struct Plus{}; - template< typename T > struct Minus{}; - template< typename T > struct Compare{}; - template< int __Value > struct Plus < IntPack< __Value > >{ typedef IntPack< _Value + __Value > type; }; - template< int __Value > struct Minus< IntPack< __Value > >{ typedef IntPack< _Value - __Value > type; }; - template< int __Value > struct Compare< IntPack< __Value > > + template< int ... Values > struct IntPack{}; + template< int _Value , int ... _Values > struct IntPack< _Value , _Values ... > + { + static const int First = _Value; + typedef IntPack< _Values ... > Rest; + + static const unsigned int Size = 1 + sizeof ... ( _Values ); + template< int __Value > using Append = IntPack< _Value , _Values ... , __Value >; + template< int __Value > using Prepend = IntPack< __Value , _Value , _Values ... >; + static const int Values[]; + static constexpr int Min( void ){ return _Value < Rest::Min ? _Value : Rest::Min; } + static constexpr int Max( void ){ return _Value > Rest::Max ? _Value : Rest::Max; } + + using Reverse = typename Rest::Reverse::template Append< First >; + + template< typename T > struct Plus{}; + template< typename T > struct Minus{}; + template< typename T > struct Compare{}; + template< int __Value , int ... __Values > struct Plus < IntPack< __Value , __Values ... > >{ typedef typename Rest::template Plus < IntPack< __Values ... > >::type::template Prepend< _Value + __Value > type; }; + template< int __Value , int ... __Values > struct Minus< IntPack< __Value , __Values ... > >{ typedef typename Rest::template Minus< IntPack< __Values ... > >::type::template Prepend< _Value - __Value > type; }; + template< int __Value , int ... __Values > struct Compare< IntPack< __Value , __Values ... > > + { + static const bool Equal = _Value==__Value && Rest::template Compare< IntPack< __Values ... > >:: Equal; + static const bool NotEqual = _Value!=__Value || Rest::template Compare< IntPack< __Values ... > >:: NotEqual; + static const bool LessThan = _Value< __Value && Rest::template Compare< IntPack< __Values ... > >:: LessThan ; + static const bool LessThanOrEqual = _Value<=__Value && Rest::template Compare< IntPack< __Values ... > >:: LessThanOrEqual; + static const bool GreaterThan = _Value> __Value && Rest::template Compare< IntPack< __Values ... > >::GreaterThan ; + static const bool GreaterThanOrEqual = _Value>=__Value && Rest::template Compare< IntPack< __Values ... > >::GreaterThanOrEqual; + }; + + static void Print( FILE* fp=stdout , bool leadingSpace=false ){ if( leadingSpace ) fprintf( fp , " " ) ; fprintf( fp , "%d" , _Value ) ; Rest::Print( fp , true ); } + + template< unsigned int I > constexpr static typename std::enable_if< I==0 , unsigned int >::type Get( void ){ return _Value; } + template< unsigned int I > constexpr static typename std::enable_if< I!=0 , unsigned int >::type Get( void ){ return Rest::template Get< I-1 >(); } + + template< int __Value , int ... __Values > constexpr bool operator < ( IntPack< __Value , __Values ... > ) const { return _Value< __Value && Rest()< IntPack< __Values ... >(); } + template< int __Value , int ... __Values > constexpr bool operator <= ( IntPack< __Value , __Values ... > ) const { return _Value<=__Value && Rest()<=IntPack< __Values ... >(); } + template< int __Value , int ... __Values > constexpr bool operator > ( IntPack< __Value , __Values ... > ) const { return _Value> __Value && Rest()> IntPack< __Values ... >(); } + template< int __Value , int ... __Values > constexpr bool operator >= ( IntPack< __Value , __Values ... > ) const { return _Value>=__Value && Rest()>=IntPack< __Values ... >(); } + template< int __Value , int ... __Values > constexpr bool operator == ( IntPack< __Value , __Values ... > ) const { return _Value==__Value && Rest()==IntPack< __Values ... >(); } + template< int __Value , int ... __Values > constexpr bool operator != ( IntPack< __Value , __Values ... > ) const { return _Value!=__Value && Rest()!=IntPack< __Values ... >(); } + }; + template< int _Value > struct IntPack< _Value > + { + static const int First = _Value; + + static const unsigned int Size = 1; + template< int __Value > using Append = IntPack< _Value , __Value >; + template< int __Value > using Prepend = IntPack< __Value , _Value >; + static const int Values[]; + static constexpr int Min( void ){ return _Value; } + static constexpr int Max( void ){ return _Value; } + + using Reverse = IntPack< _Value >; + + template< typename T > struct Plus{}; + template< typename T > struct Minus{}; + template< typename T > struct Compare{}; + template< int __Value > struct Plus < IntPack< __Value > >{ typedef IntPack< _Value + __Value > type; }; + template< int __Value > struct Minus< IntPack< __Value > >{ typedef IntPack< _Value - __Value > type; }; + template< int __Value > struct Compare< IntPack< __Value > > + { + static const bool Equal = _Value==__Value; + static const bool NotEqual = _Value!=__Value; + static const bool LessThan = _Value< __Value; + static const bool LessThanOrEqual = _Value<=__Value; + static const bool GreaterThan = _Value> __Value; + static const bool GreaterThanOrEqual = _Value>=__Value; + }; + + static void Print( FILE* fp=stdout , bool leadingSpace=false ){ if( leadingSpace ) fprintf( fp , " " ) ; fprintf( fp , "%d" , _Value ); } + template< unsigned int I > constexpr static unsigned int Get( void ){ static_assert( I==0 , "[ERROR] IntPack< Value >::Get called with non-zero index" ) ; return _Value; } + + template< int __Value > constexpr bool operator < ( IntPack< __Value > ) const { return _Value< __Value; } + template< int __Value > constexpr bool operator <= ( IntPack< __Value > ) const { return _Value<=__Value; } + template< int __Value > constexpr bool operator > ( IntPack< __Value > ) const { return _Value> __Value; } + template< int __Value > constexpr bool operator >= ( IntPack< __Value > ) const { return _Value>=__Value; } + template< int __Value > constexpr bool operator == ( IntPack< __Value > ) const { return _Value==__Value; } + template< int __Value > constexpr bool operator != ( IntPack< __Value > ) const { return _Value!=__Value; } + }; + template< int _Value , int ... _Values > const int IntPack< _Value , _Values ... >::Values[] = { _Value , _Values ... }; + template< int _Value > const int IntPack< _Value >::Values[] = { _Value }; + template< int ... V1 , int ... V2 > typename IntPack< V1 ... >::template Plus < IntPack< V2 ... > >::type operator + ( IntPack< V1 ... > , IntPack< V2 ... > ){ return typename IntPack< V1 ... >::template Plus < IntPack< V2 ... > >::type(); } + template< int ... V1 , int ... V2 > typename IntPack< V1 ... >::template Minus< IntPack< V2 ... > >::type operator - ( IntPack< V1 ... > , IntPack< V2 ... > ){ return typename IntPack< V1 ... >::template Minus< IntPack< V2 ... > >::type(); } + + /////////////////////////// + // The isotropic variant // + /////////////////////////// + template< unsigned int Dim , unsigned int Value > struct _IsotropicUIntPack { typedef typename _IsotropicUIntPack< Dim-1 , Value >::type::template Append< Value > type; }; + template< unsigned int Value > struct _IsotropicUIntPack< 1 , Value >{ typedef UIntPack< Value > type; }; + template< unsigned int Value > struct _IsotropicUIntPack< 0 , Value >{ typedef UIntPack< > type; }; + template< unsigned int Dim , unsigned int Value > using IsotropicUIntPack = typename _IsotropicUIntPack< Dim , Value >::type; + template< unsigned int Dim > using ZeroUIntPack = IsotropicUIntPack< Dim , 0 >; + + template< int Dim , int Value > struct _IsotropicIntPack { typedef typename _IsotropicUIntPack< Dim-1 , Value >::type::template Append< Value > type; }; + template< int Value > struct _IsotropicIntPack< 1 , Value >{ typedef IntPack< Value > type; }; + template< int Value > struct _IsotropicIntPack< 0 , Value >{ typedef IntPack< > type; }; + template< int Dim , int Value > using IsotropicIntPack = typename _IsotropicIntPack< Dim , Value >::type; + template< int Dim > using ZeroIntPack = IsotropicIntPack< Dim , 0 >; + ///////////////////////////// + // And now for the windows // + ///////////////////////////// + template< typename T > struct WindowSize{}; + template< typename T1 , typename T2 > struct WindowIndex{}; + + template< unsigned int Res , unsigned int ... Ress > struct WindowSize< UIntPack< Res , Ress ... > >{ static const unsigned int Size = WindowSize< UIntPack< Ress ... > >::Size * Res; }; + template< unsigned int Res > struct WindowSize< UIntPack< Res > >{ static const unsigned int Size = Res; }; + + template< unsigned int Res , unsigned int ... Ress , unsigned int Idx , unsigned int ... Idxs > struct WindowIndex< UIntPack< Res , Ress ... > , UIntPack< Idx , Idxs ... > >{ static const unsigned int Index = Idx * WindowSize< UIntPack< Ress ... > >::Size + WindowIndex< UIntPack< Ress ... > , UIntPack< Idxs ... > >::Index; }; + template< unsigned int Res , unsigned int Idx > struct WindowIndex< UIntPack< Res > , UIntPack< Idx > >{ static const unsigned int Index = Idx; }; + + template< unsigned int Res , unsigned int ... Ress > typename std::enable_if< (sizeof...(Ress)!=0) , unsigned int >::type GetWindowIndex( UIntPack< Res , Ress ... > , const unsigned int idx[] ){ return idx[0] * WindowSize< UIntPack< Ress ... > >::Size + GetWindowIndex( UIntPack< Ress ... >() , idx+1 ); }; + template< unsigned int Res > unsigned int GetWindowIndex( UIntPack< Res > , const unsigned int idx[] ){ return idx[0]; } + + template< unsigned int Res , unsigned int ... Ress > typename std::enable_if< (sizeof...(Ress)!=0) , unsigned int >::type GetWindowIndex( UIntPack< Res , Ress ... > , const int idx[] ){ return idx[0] * WindowSize< UIntPack< Ress ... > >::Size + GetWindowIndex( UIntPack< Ress ... >() , idx+1 ); }; + template< unsigned int Res > unsigned int GetWindowIndex( UIntPack< Res > , const int idx[] ){ return idx[0]; } + + template< typename Data , typename Pack > struct ConstWindowSlice{}; + template< typename Data , typename Pack > struct WindowSlice{}; + template< typename Data , typename Pack > struct StaticWindow {}; + template< typename Data , typename Pack > struct DynamicWindow {}; + + + template< class Data , unsigned int ... Ress > + struct ConstWindowSlice< Data , UIntPack< Ress ... > > + { + typedef UIntPack< Ress ... > Pack; + static const unsigned int Size = WindowSize< Pack >::Size; + typedef Data data_type; + typedef const Data& data_reference_type; + typedef const Data& const_data_reference_type; + ConstWindowSlice( Pointer( Data ) d ) : data(d) { ; } + ConstWindowSlice( ConstPointer( Data ) d ) : data(d) { ; } + ConstWindowSlice< Data , typename Pack::Rest > operator[]( int idx ) const { return ConstWindowSlice< Data , typename Pack::Rest >( data + WindowSize< typename Pack::Rest >::Size * idx ); } + data_reference_type operator()( const int idx[sizeof...(Ress)] ) const { return data[ GetWindowIndex( UIntPack< Ress ... >() , idx ) ]; } + data_reference_type operator()( const unsigned int idx[sizeof...(Ress)] ) const { return data[ GetWindowIndex( UIntPack< Ress ... >() , idx ) ]; } + ConstPointer( Data ) data; + }; + template< class Data , unsigned int Res > + struct ConstWindowSlice< Data , UIntPack< Res > > + { + typedef UIntPack< Res > Pack; + static const unsigned int Size = Res; + typedef Data data_type; + typedef const Data& data_reference_type; + typedef const Data& const_data_reference_type; + ConstWindowSlice( Pointer( Data ) d ) : data(d) { ; } + ConstWindowSlice( ConstPointer( Data ) d ) : data(d) { ; } + inline data_reference_type operator[]( int idx ) const { return data[idx]; } + data_reference_type operator()( const int idx[1] ) const { return data[ idx[0] ]; } + data_reference_type operator()( const unsigned int idx[1] ) const { return data[ idx[0] ]; } + ConstPointer( Data ) data; + }; + template< class Data , unsigned int ... Ress > + struct WindowSlice< Data , UIntPack< Ress ... > > + { + typedef UIntPack< Ress ... > Pack; + static const unsigned int Size = WindowSize< Pack >::Size; + typedef Data data_type; + typedef Data& data_reference_type; + typedef const Data& const_data_reference_type; + WindowSlice( Pointer( Data ) d ) : data(d) { ; } + WindowSlice< Data , typename Pack::Rest > operator[]( int idx ){ return WindowSlice< Data , typename Pack::Rest >( data + WindowSize< typename Pack::Rest >::Size * idx ); } + inline data_reference_type operator()( const int idx[sizeof...(Ress)] ){ return (*this)[ idx[0] ]( idx+1 ); } + const_data_reference_type operator()( const int idx[sizeof...(Ress)] ) const { return (*this)[ idx[0] ]( idx+1 ); } + operator ConstWindowSlice< Data , Pack >() const { return ConstWindowSlice< Data , Pack >( ( ConstPointer( Data ) )data ); } + Pointer( Data ) data; + }; + template< class Data , unsigned int Res > + struct WindowSlice< Data , UIntPack< Res > > { - static const bool Equal = _Value==__Value; - static const bool NotEqual = _Value!=__Value; - static const bool LessThan = _Value< __Value; - static const bool LessThanOrEqual = _Value<=__Value; - static const bool GreaterThan = _Value> __Value; - static const bool GreaterThanOrEqual = _Value>=__Value; + typedef UIntPack< Res > Pack; + static const unsigned int Size = Res; + typedef Data data_type; + typedef Data& data_reference_type; + typedef const Data& const_data_reference_type; + WindowSlice( Pointer( Data ) d ) : data(d) { ; } + inline data_reference_type operator[]( int idx ){ return data[idx]; } + inline const_data_reference_type operator[]( int idx ) const { return data[idx]; } + data_reference_type operator()( const int idx[1] ){ return (*this)[ idx[0] ]; } + const_data_reference_type operator()( const int idx[1] ) const { return (*this)[ idx[0] ]; } + operator ConstWindowSlice< Data , Pack >() const { return ConstWindowSlice< Data , Pack >( ( ConstPointer( Data ) )data ); } + Pointer( Data ) data; }; - static void Print( FILE* fp=stdout , bool leadingSpace=false ){ if( leadingSpace ) fprintf( fp , " " ) ; fprintf( fp , "%d" , _Value ); } - template< unsigned int I > constexpr static unsigned int Get( void ){ static_assert( I==0 , "[ERROR] IntPack< Value >::Get called with non-zero index" ) ; return _Value; } - - template< int __Value > constexpr bool operator < ( IntPack< __Value > ) const { return _Value< __Value; } - template< int __Value > constexpr bool operator <= ( IntPack< __Value > ) const { return _Value<=__Value; } - template< int __Value > constexpr bool operator > ( IntPack< __Value > ) const { return _Value> __Value; } - template< int __Value > constexpr bool operator >= ( IntPack< __Value > ) const { return _Value>=__Value; } - template< int __Value > constexpr bool operator == ( IntPack< __Value > ) const { return _Value==__Value; } - template< int __Value > constexpr bool operator != ( IntPack< __Value > ) const { return _Value!=__Value; } -}; -template< int _Value , int ... _Values > const int IntPack< _Value , _Values ... >::Values[] = { _Value , _Values ... }; -template< int _Value > const int IntPack< _Value >::Values[] = { _Value }; -template< int ... V1 , int ... V2 > typename IntPack< V1 ... >::template Plus < IntPack< V2 ... > >::type operator + ( IntPack< V1 ... > , IntPack< V2 ... > ){ return typename IntPack< V1 ... >::template Plus < IntPack< V2 ... > >::type(); } -template< int ... V1 , int ... V2 > typename IntPack< V1 ... >::template Minus< IntPack< V2 ... > >::type operator - ( IntPack< V1 ... > , IntPack< V2 ... > ){ return typename IntPack< V1 ... >::template Minus< IntPack< V2 ... > >::type(); } - -/////////////////////////// -// The isotropic variant // -/////////////////////////// -template< unsigned int Dim , unsigned int Value > struct _IsotropicUIntPack { typedef typename _IsotropicUIntPack< Dim-1 , Value >::type::template Append< Value > type; }; -template< unsigned int Value > struct _IsotropicUIntPack< 1 , Value >{ typedef UIntPack< Value > type; }; -template< unsigned int Value > struct _IsotropicUIntPack< 0 , Value >{ typedef UIntPack< > type; }; -template< unsigned int Dim , unsigned int Value > using IsotropicUIntPack = typename _IsotropicUIntPack< Dim , Value >::type; -template< unsigned int Dim > using ZeroUIntPack = IsotropicUIntPack< Dim , 0 >; - -template< int Dim , int Value > struct _IsotropicIntPack { typedef typename _IsotropicUIntPack< Dim-1 , Value >::type::template Append< Value > type; }; -template< int Value > struct _IsotropicIntPack< 1 , Value >{ typedef IntPack< Value > type; }; -template< int Value > struct _IsotropicIntPack< 0 , Value >{ typedef IntPack< > type; }; -template< int Dim , int Value > using IsotropicIntPack = typename _IsotropicIntPack< Dim , Value >::type; -template< int Dim > using ZeroIntPack = IsotropicIntPack< Dim , 0 >; -///////////////////////////// -// And now for the windows // -///////////////////////////// -template< typename T > struct WindowSize{}; -template< typename T1 , typename T2 > struct WindowIndex{}; - -template< unsigned int Res , unsigned int ... Ress > struct WindowSize< UIntPack< Res , Ress ... > >{ static const unsigned int Size = WindowSize< UIntPack< Ress ... > >::Size * Res; }; -template< unsigned int Res > struct WindowSize< UIntPack< Res > >{ static const unsigned int Size = Res; }; - -template< unsigned int Res , unsigned int ... Ress , unsigned int Idx , unsigned int ... Idxs > struct WindowIndex< UIntPack< Res , Ress ... > , UIntPack< Idx , Idxs ... > >{ static const unsigned int Index = Idx * WindowSize< UIntPack< Ress ... > >::Size + WindowIndex< UIntPack< Ress ... > , UIntPack< Idxs ... > >::Index; }; -template< unsigned int Res , unsigned int Idx > struct WindowIndex< UIntPack< Res > , UIntPack< Idx > >{ static const unsigned int Index = Idx; }; - -template< unsigned int Res , unsigned int ... Ress > typename std::enable_if< (sizeof...(Ress)!=0) , unsigned int >::type GetWindowIndex( UIntPack< Res , Ress ... > , const unsigned int idx[] ){ return idx[0] * WindowSize< UIntPack< Ress ... > >::Size + GetWindowIndex( UIntPack< Ress ... >() , idx+1 ); }; -template< unsigned int Res > unsigned int GetWindowIndex( UIntPack< Res > , const unsigned int idx[] ){ return idx[0]; } - -template< unsigned int Res , unsigned int ... Ress > typename std::enable_if< (sizeof...(Ress)!=0) , unsigned int >::type GetWindowIndex( UIntPack< Res , Ress ... > , const int idx[] ){ return idx[0] * WindowSize< UIntPack< Ress ... > >::Size + GetWindowIndex( UIntPack< Ress ... >() , idx+1 ); }; -template< unsigned int Res > unsigned int GetWindowIndex( UIntPack< Res > , const int idx[] ){ return idx[0]; } - -template< typename Data , typename Pack > struct ConstWindowSlice{}; -template< typename Data , typename Pack > struct WindowSlice{}; -template< typename Data , typename Pack > struct StaticWindow {}; -template< typename Data , typename Pack > struct DynamicWindow {}; - - -template< class Data , unsigned int ... Ress > -struct ConstWindowSlice< Data , UIntPack< Ress ... > > -{ - typedef UIntPack< Ress ... > Pack; - static const unsigned int Size = WindowSize< Pack >::Size; - typedef Data data_type; - typedef const Data& data_reference_type; - typedef const Data& const_data_reference_type; - ConstWindowSlice( Pointer( Data ) d ) : data(d) { ; } - ConstWindowSlice( ConstPointer( Data ) d ) : data(d) { ; } - ConstWindowSlice< Data , typename Pack::Rest > operator[]( int idx ) const { return ConstWindowSlice< Data , typename Pack::Rest >( data + WindowSize< typename Pack::Rest >::Size * idx ); } - data_reference_type operator()( const int idx[sizeof...(Ress)] ) const { return data[ GetWindowIndex( UIntPack< Ress ... >() , idx ) ]; } - data_reference_type operator()( const unsigned int idx[sizeof...(Ress)] ) const { return data[ GetWindowIndex( UIntPack< Ress ... >() , idx ) ]; } - ConstPointer( Data ) data; -}; -template< class Data , unsigned int Res > -struct ConstWindowSlice< Data , UIntPack< Res > > -{ - typedef UIntPack< Res > Pack; - static const unsigned int Size = Res; - typedef Data data_type; - typedef const Data& data_reference_type; - typedef const Data& const_data_reference_type; - ConstWindowSlice( Pointer( Data ) d ) : data(d) { ; } - ConstWindowSlice( ConstPointer( Data ) d ) : data(d) { ; } - inline data_reference_type operator[]( int idx ) const { return data[idx]; } - data_reference_type operator()( const int idx[1] ) const { return data[ idx[0] ]; } - data_reference_type operator()( const unsigned int idx[1] ) const { return data[ idx[0] ]; } - ConstPointer( Data ) data; -}; -template< class Data , unsigned int ... Ress > -struct WindowSlice< Data , UIntPack< Ress ... > > -{ - typedef UIntPack< Ress ... > Pack; - static const unsigned int Size = WindowSize< Pack >::Size; - typedef Data data_type; - typedef Data& data_reference_type; - typedef const Data& const_data_reference_type; - WindowSlice( Pointer( Data ) d ) : data(d) { ; } - WindowSlice< Data , typename Pack::Rest > operator[]( int idx ){ return WindowSlice< Data , typename Pack::Rest >( data + WindowSize< typename Pack::Rest >::Size * idx ); } - inline data_reference_type operator()( const int idx[sizeof...(Ress)] ){ return (*this)[ idx[0] ]( idx+1 ); } - const_data_reference_type operator()( const int idx[sizeof...(Ress)] ) const { return (*this)[ idx[0] ]( idx+1 ); } - operator ConstWindowSlice< Data , Pack >() const { return ConstWindowSlice< Data , Pack >( ( ConstPointer( Data ) )data ); } - Pointer( Data ) data; -}; -template< class Data , unsigned int Res > -struct WindowSlice< Data , UIntPack< Res > > -{ - typedef UIntPack< Res > Pack; - static const unsigned int Size = Res; - typedef Data data_type; - typedef Data& data_reference_type; - typedef const Data& const_data_reference_type; - WindowSlice( Pointer( Data ) d ) : data(d) { ; } - inline data_reference_type operator[]( int idx ){ return data[idx]; } - inline const_data_reference_type operator[]( int idx ) const { return data[idx]; } - data_reference_type operator()( const int idx[1] ){ return (*this)[ idx[0] ]; } - const_data_reference_type operator()( const int idx[1] ) const { return (*this)[ idx[0] ]; } - operator ConstWindowSlice< Data , Pack >() const { return ConstWindowSlice< Data , Pack >( ( ConstPointer( Data ) )data ); } - Pointer( Data ) data; -}; - -template< class Data , unsigned int ... Ress > -struct StaticWindow< Data , UIntPack< Ress ... > > -{ - typedef UIntPack< Ress ... > Pack; + template< class Data , unsigned int ... Ress > + struct StaticWindow< Data , UIntPack< Ress ... > > + { + typedef UIntPack< Ress ... > Pack; #if defined( __GNUC__ ) && defined( DEBUG ) #ifdef SHOW_WARNINGS -#warning "you've got me gcc" + #warning "you've got me gcc" #endif // SHOW_WARNINGS - static const unsigned int Size; + static const unsigned int Size; #else // !( __GNUC__ && DEBUG ) - static const unsigned int Size = WindowSize< Pack >::Size; + static const unsigned int Size = WindowSize< Pack >::Size; #endif // ( __GNUC__ && DEBUG ) - typedef ConstWindowSlice< Data , Pack > const_window_slice_type; - typedef WindowSlice< Data , Pack > window_slice_type; - typedef Data data_type; - WindowSlice< Data , typename Pack::Rest > operator[]( int idx ){ return WindowSlice< Data , typename Pack::Rest >( GetPointer( data , WindowSize< Pack >::Size ) + WindowSize< typename Pack::Rest >::Size * idx ); } - ConstWindowSlice< Data , typename Pack::Rest > operator[]( int idx ) const { return ConstWindowSlice< Data , typename Pack::Rest >( ( ConstPointer( Data ) )GetPointer( data , WindowSize< Pack >::Size ) + WindowSize< typename Pack::Rest >::Size * idx ); } - WindowSlice< Data , Pack > operator()( void ){ return WindowSlice< Data , Pack >( GetPointer( data , WindowSize< Pack >::Size ) ); } - ConstWindowSlice< Data , Pack > operator()( void ) const { return ConstWindowSlice< Data , Pack >( ( ConstPointer( Data ) )GetPointer( data , WindowSize< Pack >::Size ) ); } - Data& operator()( const int idx[sizeof...(Ress)] ){ return (*this)()( idx ); } - const Data& operator()( const unsigned int idx[sizeof...(Ress)] ) const { return data[ GetWindowIndex( UIntPack< Ress ... >() , idx ) ]; } - const Data& operator()( const int idx[sizeof...(Ress)] ) const { return data[ GetWindowIndex( UIntPack< Ress ... >() , idx ) ]; } - Data data[ WindowSize< Pack >::Size ]; -}; + typedef ConstWindowSlice< Data , Pack > const_window_slice_type; + typedef WindowSlice< Data , Pack > window_slice_type; + typedef Data data_type; + WindowSlice< Data , typename Pack::Rest > operator[]( int idx ){ return WindowSlice< Data , typename Pack::Rest >( GetPointer( data , WindowSize< Pack >::Size ) + WindowSize< typename Pack::Rest >::Size * idx ); } + ConstWindowSlice< Data , typename Pack::Rest > operator[]( int idx ) const { return ConstWindowSlice< Data , typename Pack::Rest >( ( ConstPointer( Data ) )GetPointer( data , WindowSize< Pack >::Size ) + WindowSize< typename Pack::Rest >::Size * idx ); } + WindowSlice< Data , Pack > operator()( void ){ return WindowSlice< Data , Pack >( GetPointer( data , WindowSize< Pack >::Size ) ); } + ConstWindowSlice< Data , Pack > operator()( void ) const { return ConstWindowSlice< Data , Pack >( ( ConstPointer( Data ) )GetPointer( data , WindowSize< Pack >::Size ) ); } + Data& operator()( const int idx[sizeof...(Ress)] ){ return (*this)()( idx ); } + const Data& operator()( const unsigned int idx[sizeof...(Ress)] ) const { return data[ GetWindowIndex( UIntPack< Ress ... >() , idx ) ]; } + const Data& operator()( const int idx[sizeof...(Ress)] ) const { return data[ GetWindowIndex( UIntPack< Ress ... >() , idx ) ]; } + Data data[ WindowSize< Pack >::Size ]; + }; #if defined( __GNUC__ ) && defined( DEBUG ) -template< class Data , unsigned int ... Ress > -const unsigned int StaticWindow< Data , UIntPack< Ress ... > >::Size = WindowSize< UIntPack< Ress ... > >::Size; + template< class Data , unsigned int ... Ress > + const unsigned int StaticWindow< Data , UIntPack< Ress ... > >::Size = WindowSize< UIntPack< Ress ... > >::Size; #endif // ( __GNUC__ && DEBUG ) -template< class Data , unsigned int Res > -struct StaticWindow< Data , UIntPack< Res > > -{ - typedef UIntPack< Res > Pack; + template< class Data , unsigned int Res > + struct StaticWindow< Data , UIntPack< Res > > + { + typedef UIntPack< Res > Pack; #if defined( __GNUC__ ) && defined( DEBUG ) #ifdef SHOW_WARNINGS -#warning "you've got me gcc" + #warning "you've got me gcc" #endif // SHOW_WARNINGS - static const unsigned int Size; + static const unsigned int Size; #else // !( __GNUC__ && DEBUG ) - static const unsigned int Size = Res; + static const unsigned int Size = Res; #endif // ( __GNUC__ && DEBUG ) - typedef Data data_type; - Data& operator[]( int idx ){ return data[idx]; }; - const Data& operator[]( int idx ) const { return data[idx]; }; - WindowSlice< Data , Pack > operator()( void ){ return WindowSlice< Data , Pack >( GetPointer( data , WindowSize< Pack >::Size ) ); } - ConstWindowSlice< Data , Pack > operator()( void ) const { return ConstWindowSlice< Data , Pack >( ( ConstPointer( Data ) )GetPointer( data , WindowSize< Pack >::Size ) ); } - Data& operator()( const int idx[1] ){ return (*this)()( idx ); } - const Data& operator()( const unsigned int idx[1] ) const { return data[ idx[0] ]; } - const Data& operator()( const int idx[1] ) const { return data[ idx[0] ]; } - Data data[ Res ]; -}; + typedef Data data_type; + Data& operator[]( int idx ){ return data[idx]; }; + const Data& operator[]( int idx ) const { return data[idx]; }; + WindowSlice< Data , Pack > operator()( void ){ return WindowSlice< Data , Pack >( GetPointer( data , WindowSize< Pack >::Size ) ); } + ConstWindowSlice< Data , Pack > operator()( void ) const { return ConstWindowSlice< Data , Pack >( ( ConstPointer( Data ) )GetPointer( data , WindowSize< Pack >::Size ) ); } + Data& operator()( const int idx[1] ){ return (*this)()( idx ); } + const Data& operator()( const unsigned int idx[1] ) const { return data[ idx[0] ]; } + const Data& operator()( const int idx[1] ) const { return data[ idx[0] ]; } + Data data[ Res ]; + }; #if defined( __GNUC__ ) && defined( DEBUG ) -template< class Data , unsigned int Res > -const unsigned int StaticWindow< Data , UIntPack< Res > >::Size = Res; + template< class Data , unsigned int Res > + const unsigned int StaticWindow< Data , UIntPack< Res > >::Size = Res; #endif // ( __GNUC__ && DEBUG ) -template< class Data , unsigned int ... Ress > -struct DynamicWindow< Data , UIntPack< Ress ... > > -{ - typedef UIntPack< Ress ... > Pack; - static const unsigned int Size = WindowSize< Pack >::Size; - typedef ConstWindowSlice< Data , Pack > const_window_slice_type; - typedef WindowSlice< Data , Pack > window_slice_type; - typedef Data data_type; - WindowSlice< Data , typename Pack::Rest > operator[]( int idx ){ return WindowSlice< Data , typename Pack::Rest >( data + WindowSize< typename Pack::Rest >::Size * idx ); } - ConstWindowSlice< Data , typename Pack::Rest > operator[]( int idx ) const { return ConstWindowSlice< Data , typename Pack::Rest >( ( ConstPointer( Data ) )( data + WindowSize< typename Pack::Rest >::Size * idx ) ); } - WindowSlice< Data , Pack > operator()( void ){ return WindowSlice< Data , Pack >( data ); } - ConstWindowSlice< Data , Pack > operator()( void ) const { return ConstWindowSlice< Data , Pack >( ( ConstPointer( Data ) )data ); } - Data& operator()( const int idx[sizeof...(Ress)+1] ){ return (*this)()( idx ); } - const Data& operator()( const int idx[sizeof...(Ress)+1] ) const { return (*this)()( idx ); } - - DynamicWindow( void ){ data = NewPointer< Data >( WindowSize< Pack >::Size ); } - ~DynamicWindow( void ){ DeletePointer( data ); } - Pointer( Data ) data; -}; -template< class Data , unsigned int Res > -struct DynamicWindow< Data , UIntPack< Res > > -{ - typedef UIntPack< Res > Pack; - static const unsigned int Size = Res; - typedef Data data_type; - Data& operator[]( int idx ){ return data[idx]; }; - const Data& operator[]( int idx ) const { return data[idx]; }; - WindowSlice< Data , Pack > operator()( void ) { return WindowSlice< Data , Pack >( data ); } - ConstWindowSlice< Data , Pack > operator()( void ) const { return ConstWindowSlice< Data , Pack >( ( ConstPointer( Data ) )data ); } - Data& operator()( const int idx[1] ){ return (*this)()( idx ); } - const Data& operator()( const int idx[1] ) const { return (*this)()( idx ); } - - DynamicWindow( void ){ data = NewPointer< Data >( Res ); } - ~DynamicWindow( void ){ DeletePointer( data ); } - Pointer( Data ) data; -}; - -// Recursive loop iterations for processing window slices -// WindowDimension: the the window slice -// IterationDimensions: the number of dimensions to process -// Res: the resolution of the window - -template< unsigned int WindowDimension , unsigned int IterationDimensions , unsigned int CurrentIteration > struct _WindowLoop; -template< unsigned int WindowDimension , unsigned int IterationDimensions=WindowDimension > -struct WindowLoop -{ - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void Run( int begin , int end , UpdateFunction updateState , ProcessFunction function , Windows ... w ) + template< class Data , unsigned int ... Ress > + struct DynamicWindow< Data , UIntPack< Ress ... > > { - _WindowLoop< WindowDimension , IterationDimensions , IterationDimensions >::Run( begin , end , updateState , function , w ... ); - } - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void Run( const int* begin , const int* end , UpdateFunction updateState , ProcessFunction function , Windows ... w ) - { - _WindowLoop< WindowDimension , IterationDimensions , IterationDimensions >::Run( begin , end , updateState , function , w ... ); - } - template< unsigned int ... Begin , unsigned int ... End , typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void Run( UIntPack< Begin ... > begin , UIntPack< End ... > end , UpdateFunction updateState , ProcessFunction function , Windows ... w ) + typedef UIntPack< Ress ... > Pack; + static const unsigned int Size = WindowSize< Pack >::Size; + typedef ConstWindowSlice< Data , Pack > const_window_slice_type; + typedef WindowSlice< Data , Pack > window_slice_type; + typedef Data data_type; + WindowSlice< Data , typename Pack::Rest > operator[]( int idx ){ return WindowSlice< Data , typename Pack::Rest >( data + WindowSize< typename Pack::Rest >::Size * idx ); } + ConstWindowSlice< Data , typename Pack::Rest > operator[]( int idx ) const { return ConstWindowSlice< Data , typename Pack::Rest >( ( ConstPointer( Data ) )( data + WindowSize< typename Pack::Rest >::Size * idx ) ); } + WindowSlice< Data , Pack > operator()( void ){ return WindowSlice< Data , Pack >( data ); } + ConstWindowSlice< Data , Pack > operator()( void ) const { return ConstWindowSlice< Data , Pack >( ( ConstPointer( Data ) )data ); } + Data& operator()( const int idx[sizeof...(Ress)+1] ){ return (*this)()( idx ); } + const Data& operator()( const int idx[sizeof...(Ress)+1] ) const { return (*this)()( idx ); } + + DynamicWindow( void ){ data = NewPointer< Data >( WindowSize< Pack >::Size ); } + ~DynamicWindow( void ){ DeletePointer( data ); } + Pointer( Data ) data; + }; + template< class Data , unsigned int Res > + struct DynamicWindow< Data , UIntPack< Res > > { - _WindowLoop< WindowDimension , IterationDimensions , IterationDimensions >::Run( begin , end , updateState , function , w ... ); - } + typedef UIntPack< Res > Pack; + static const unsigned int Size = Res; + typedef Data data_type; + Data& operator[]( int idx ){ return data[idx]; }; + const Data& operator[]( int idx ) const { return data[idx]; }; + WindowSlice< Data , Pack > operator()( void ) { return WindowSlice< Data , Pack >( data ); } + ConstWindowSlice< Data , Pack > operator()( void ) const { return ConstWindowSlice< Data , Pack >( ( ConstPointer( Data ) )data ); } + Data& operator()( const int idx[1] ){ return (*this)()( idx ); } + const Data& operator()( const int idx[1] ) const { return (*this)()( idx ); } + + DynamicWindow( void ){ data = NewPointer< Data >( Res ); } + ~DynamicWindow( void ){ DeletePointer( data ); } + Pointer( Data ) data; + }; - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunParallel( int begin , int end , UpdateFunction updateState , ProcessFunction function , Windows ... w ) - { - _WindowLoop< WindowDimension , IterationDimensions , IterationDimensions >::RunParallel( begin , end , updateState , function , w ... ); - } - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunParallel( const int* begin , const int* end , UpdateFunction updateState , ProcessFunction function , Windows ... w ) - { - _WindowLoop< WindowDimension , IterationDimensions , IterationDimensions >::RunParallel( begin , end , updateState , function , w ... ); - } - template< unsigned int ... Begin , unsigned int ... End , typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunParallel( UIntPack< Begin ... > begin , UIntPack< End ... > end , UpdateFunction updateState , ProcessFunction function , Windows ... w ) + // Recursive loop iterations for processing window slices + // WindowDimension: the the window slice + // IterationDimensions: the number of dimensions to process + // Res: the resolution of the window + + template< unsigned int WindowDimension , unsigned int IterationDimensions , unsigned int CurrentIteration > struct _WindowLoop; + template< unsigned int WindowDimension , unsigned int IterationDimensions=WindowDimension > + struct WindowLoop { - _WindowLoop< WindowDimension , IterationDimensions , IterationDimensions >::RunParallel( begin , end , updateState , function , w ... ); - } -}; + template< typename UpdateFunction , typename ProcessFunction , class ... Windows > + static void Run( int begin , int end , UpdateFunction updateState , ProcessFunction function , Windows ... w ) + { + _WindowLoop< WindowDimension , IterationDimensions , IterationDimensions >::Run( begin , end , updateState , function , w ... ); + } + template< typename UpdateFunction , typename ProcessFunction , class ... Windows > + static void Run( const int* begin , const int* end , UpdateFunction updateState , ProcessFunction function , Windows ... w ) + { + _WindowLoop< WindowDimension , IterationDimensions , IterationDimensions >::Run( begin , end , updateState , function , w ... ); + } + template< unsigned int ... Begin , unsigned int ... End , typename UpdateFunction , typename ProcessFunction , class ... Windows > + static void Run( UIntPack< Begin ... > begin , UIntPack< End ... > end , UpdateFunction updateState , ProcessFunction function , Windows ... w ) + { + _WindowLoop< WindowDimension , IterationDimensions , IterationDimensions >::Run( begin , end , updateState , function , w ... ); + } + + template< typename UpdateFunction , typename ProcessFunction , class ... Windows > + static void RunParallel( int begin , int end , UpdateFunction updateState , ProcessFunction function , Windows ... w ) + { + _WindowLoop< WindowDimension , IterationDimensions , IterationDimensions >::RunParallel( begin , end , updateState , function , w ... ); + } + template< typename UpdateFunction , typename ProcessFunction , class ... Windows > + static void RunParallel( const int* begin , const int* end , UpdateFunction updateState , ProcessFunction function , Windows ... w ) + { + _WindowLoop< WindowDimension , IterationDimensions , IterationDimensions >::RunParallel( begin , end , updateState , function , w ... ); + } + template< unsigned int ... Begin , unsigned int ... End , typename UpdateFunction , typename ProcessFunction , class ... Windows > + static void RunParallel( UIntPack< Begin ... > begin , UIntPack< End ... > end , UpdateFunction updateState , ProcessFunction function , Windows ... w ) + { + _WindowLoop< WindowDimension , IterationDimensions , IterationDimensions >::RunParallel( begin , end , updateState , function , w ... ); + } + }; #include "Window.inl" +} #endif // WINDOW_INCLUDED From 5960db7a3ba4f398dfa9f740c0a4fce9a66e2989 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Wed, 11 Sep 2024 20:32:25 -0400 Subject: [PATCH 37/86] Added sanitization support --- README.md | 13 ++- Src/AdaptiveTreeVisualization.cpp | 6 +- Src/BlockedVector.h | 21 +++++ Src/EDTInHeat.cpp | 6 +- Src/FEMTree.LevelSet.inl | 3 +- Src/FEMTree.h | 67 ++++++++++++++-- Src/FEMTree.inl | 29 ++++++- Src/ImageStitching.cpp | 6 +- Src/MarchingCubes.h | 18 ++--- Src/MyMiscellany.h | 129 +++++++++++++++++++++++++++--- Src/PointInterpolant.cpp | 6 +- Src/PoissonRecon.cpp | 6 +- Src/PoissonReconClient.cpp | 6 +- Src/PoissonReconServer.cpp | 6 +- Src/PreProcessor.h | 3 +- Src/Reconstruction.example.cpp | 6 +- Src/Reconstructors.h | 2 +- Src/RegularTree.inl | 10 +++ Src/SparseMatrix.inl | 4 +- 19 files changed, 266 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index dda1d27c..333f7538 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

      Adaptive Multigrid Solvers (Version 18.00)

      +

      Adaptive Multigrid Solvers (Version 18.01)

      links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
      Executables: -Win64
      +Win64
      Source Code: -ZIP GitHub
      +ZIP GitHub
      Older Versions: +V18.00, V17.00, V16.10, V16.09, @@ -1564,6 +1565,12 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
      1. Encapsulated the code within the PoissonRecon namespace.
      + +Version 18.01: +
        +
      1. Introduced compiler support for CLANG-sanitized code via the pre-processor flag SANITIZED_PR. +
      +
      diff --git a/Src/AdaptiveTreeVisualization.cpp b/Src/AdaptiveTreeVisualization.cpp index 7b0de9bc..f5cdf131 100644 --- a/Src/AdaptiveTreeVisualization.cpp +++ b/Src/AdaptiveTreeVisualization.cpp @@ -63,11 +63,7 @@ CmdLineReadable Verbose( "verbose" ); CmdLineParameter< int > -#ifdef _OPENMP - ParallelType( "parallel" , (int)ThreadPool::OPEN_MP ) , -#else // !_OPENMP - ParallelType( "parallel" , (int)ThreadPool::THREAD_POOL ) , -#endif // _OPENMP + ParallelType( "parallel" , 0 ) , ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , Threads( "threads" , (int)std::thread::hardware_concurrency() ) , diff --git a/Src/BlockedVector.h b/Src/BlockedVector.h index 1393156a..225be466 100644 --- a/Src/BlockedVector.h +++ b/Src/BlockedVector.h @@ -56,7 +56,11 @@ namespace PoissonRecon BlockedVector( const BlockedVector& v ) { +#ifdef SANITIZED_PR + _reservedBlocks = v._reservedBlocks , _allocatedBlocks = v._allocatedBlocks , _size = v._size.load() , _defaultValue = v._defaultValue; +#else // !SANITIZED_PR _reservedBlocks = v._reservedBlocks , _allocatedBlocks = v._allocatedBlocks , _size = v._size , _defaultValue = v._defaultValue; +#endif // SANITIZED_PR _blocks = NewPointer< Pointer( T ) >( _reservedBlocks ); for( size_t i=0 ; i<_allocatedBlocks ; i++ ) { @@ -70,7 +74,11 @@ namespace PoissonRecon { for( size_t i=0 ; i<_allocatedBlocks ; i++ ) DeletePointer( _blocks[i] ); DeletePointer( _blocks ); +#ifdef SANITIZED_PR + _reservedBlocks = v._reservedBlocks , _blocks = v._blocks.load() , _allocatedBlocks = v._allocatedBlocks , _size = v._size.load() , _defaultValue = v._defaultValue; +#else // !SANITIZED_PR _reservedBlocks = v._reservedBlocks , _blocks = v._blocks , _allocatedBlocks = v._allocatedBlocks , _size = v._size , _defaultValue = v._defaultValue; +#endif // SANITIZED_PR _blocks = NewPointer< Pointer( T ) >( _reservedBlocks ); for( size_t i=0 ; i<_allocatedBlocks ; i++ ) { @@ -83,7 +91,11 @@ namespace PoissonRecon BlockedVector( BlockedVector&& v ) { +#ifdef SANITIZED_PR + _reservedBlocks = v._reservedBlocks , _allocatedBlocks = v._allocatedBlocks , _size = v._size.load() , _defaultValue = v._defaultValue , _blocks = v._blocks.load(); +#else // !SANITIZED_PR _reservedBlocks = v._reservedBlocks , _allocatedBlocks = v._allocatedBlocks , _size = v._size , _defaultValue = v._defaultValue , _blocks = v._blocks; +#endif // SANITIZED_PR v._reservedBlocks = v._allocatedBlocks = v._size = 0 , v._blocks = NullPointer( Pointer( T ) ); } @@ -91,7 +103,11 @@ namespace PoissonRecon { for( size_t i=0 ; i<_allocatedBlocks ; i++ ) DeletePointer( _blocks[i] ); DeletePointer( _blocks ); +#ifdef SANITIZED_PR + _reservedBlocks = v._reservedBlocks , _allocatedBlocks = v._allocatedBlocks , _size = v._size.load() , _defaultValue = v._defaultValue , _blocks = v._blocks.load(); +#else // !SANITIZED_PR _reservedBlocks = v._reservedBlocks , _allocatedBlocks = v._allocatedBlocks , _size = v._size , _defaultValue = v._defaultValue , _blocks = v._blocks; +#endif // SANITIZED_PR v._reservedBlocks = v._allocatedBlocks = v._size = 0 , v._blocks = NullPointer( Pointer( T ) ); return *this; } @@ -241,8 +257,13 @@ namespace PoissonRecon T _defaultValue; size_t _allocatedBlocks , _reservedBlocks; +#ifdef SANITIZED_PR + std::atomic< size_t > _size; + std::atomic< Pointer( Pointer( T ) ) > _blocks; +#else // !SANITIZED_PR size_t _size; Pointer( Pointer( T ) ) _blocks; +#endif // SANITIZED_PR }; } #endif // BLOCKED_VECTOR_INCLUDED diff --git a/Src/EDTInHeat.cpp b/Src/EDTInHeat.cpp index a82153f1..99f5b8b7 100644 --- a/Src/EDTInHeat.cpp +++ b/Src/EDTInHeat.cpp @@ -68,11 +68,7 @@ CmdLineParameter< int > BaseDepth( "baseDepth" ) , BaseVCycles( "baseVCycles" , 1 ) , MaxMemoryGB( "maxMemory" , 0 ) , -#ifdef _OPENMP - ParallelType( "parallel" , (int)ThreadPool::OPEN_MP ) , -#else // !_OPENMP - ParallelType( "parallel" , (int)ThreadPool::THREAD_POOL ) , -#endif // _OPENMP + ParallelType( "parallel" , 0 ) , ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , Threads( "threads" , (int)std::thread::hardware_concurrency() ); diff --git a/Src/FEMTree.LevelSet.inl b/Src/FEMTree.LevelSet.inl index 446de46e..71381547 100644 --- a/Src/FEMTree.LevelSet.inl +++ b/Src/FEMTree.LevelSet.inl @@ -233,7 +233,8 @@ namespace LevelSetExtraction template< unsigned int CellDim > void _zeroOut( size_t sz ) { - memset( maps[CellDim] , 0 , sizeof(node_index_type) * sz * HyperCube::Cube< Dim >::template ElementNum< CellDim >() ); + if( sz && maps[CellDim] ) memset( maps[CellDim] , 0 , sizeof(node_index_type) * sz * HyperCube::Cube< Dim >::template ElementNum< CellDim >() ); + else if( sz ) ERROR_OUT( "Traying to zero out null pointer" ); if constexpr( CellDim==MaxCellDim ) return; else _zeroOut< CellDim+1 >( sz ); diff --git a/Src/FEMTree.h b/Src/FEMTree.h index 63508bb8..485e7913 100644 --- a/Src/FEMTree.h +++ b/Src/FEMTree.h @@ -46,6 +46,9 @@ DAMAGE. #define FEM_TREE_INCLUDED #include +#ifdef SANITIZED_PR +#include +#endif // SANITIZED_PR #include "MyMiscellany.h" #include "BSplineData.h" #include "Geometry.h" @@ -113,17 +116,24 @@ namespace PoissonRecon SCRATCH_FLAG = 1 << 7 , }; node_index_type nodeIndex; +#ifdef SANITIZED_PR + mutable std::atomic< unsigned char > flags; +#else // !SANITIZED_PR mutable char flags; +#endif // SANITIZED_PR void setGhostFlag( bool f ) const { if( f ) flags |= GHOST_FLAG ; else flags &= ~GHOST_FLAG; } bool getGhostFlag( void ) const { return ( flags & GHOST_FLAG )!=0; } void setDirichletNodeFlag( bool f ) const { if( f ) flags |= DIRICHLET_NODE_FLAG ; else flags &= ~DIRICHLET_NODE_FLAG; } bool getDirichletNodeFlag( void ) const { return ( flags & DIRICHLET_NODE_FLAG )!=0; } void setDirichletElementFlag( bool f ) const { if( f ) flags |= DIRICHLET_ELEMENT_FLAG ; else flags &= ~DIRICHLET_ELEMENT_FLAG; } bool getDirichletElementFlag( void ) const { return ( flags & DIRICHLET_ELEMENT_FLAG )!=0; } - void setScratchFlag( bool f ) const { if( f ) flags |= SCRATCH_FLAG ; else flags &= ~SCRATCH_FLAG; } + void setScratchFlag( bool f ) const { if( f ) flags |= SCRATCH_FLAG ; else flags &= (unsigned char)~SCRATCH_FLAG; } bool getScratchFlag( void ) const { return ( flags & SCRATCH_FLAG )!=0; } FEMTreeNodeData( void ); ~FEMTreeNodeData( void ); +#ifdef SANITIZED_PR + FEMTreeNodeData &operator = ( const FEMTreeNodeData &data ); +#endif // SANITIZED_PR }; template< unsigned int Dim > @@ -320,25 +330,53 @@ namespace PoissonRecon const Data* operator()( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ) const { return ( node->nodeData.nodeIndex<0 || node->nodeData.nodeIndex>=(node_index_type)_indices.size() || _indices[ node->nodeData.nodeIndex ]==-1 ) ? NULL : &_data[ _indices[ node->nodeData.nodeIndex ] ]; } Data& operator[]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ) { +#ifdef SANITIZED_PR + static std::shared_mutex _insertionMutex; +#else // !SANITIZED_PR static std::mutex _insertionMutex; +#endif // SANITIZED_PR // If the node hasn't been indexed yet if( node->nodeData.nodeIndex>=(node_index_type)_indices.size() ) { +#ifdef SANITIZED_PR + std::unique_lock lock( _insertionMutex ); +#else // !SANITIZED_PR std::lock_guard< std::mutex > lock( _insertionMutex ); +#endif // SANITIZED_PR if( node->nodeData.nodeIndex>=(node_index_type)_indices.size() ) _indices.resize( node->nodeData.nodeIndex+1 , -1 ); } // If the node hasn't been allocated yet +#ifdef SANITIZED_PR + volatile node_index_type * indexPtr; + { + std::shared_lock lock( _insertionMutex ); + indexPtr = &_indices[ node->nodeData.nodeIndex ]; + } + node_index_type _index = ReadAtomic( indexPtr ); +#else // !SANITIZED_PR volatile node_index_type &_index = _indices[ node->nodeData.nodeIndex ]; - if( _index==-1 ) +#endif // SANITIZED_PR if( _index==-1 ) { +#ifdef SANITIZED_PR + std::unique_lock lock( _insertionMutex ); + _index = ReadAtomic( indexPtr ); +#else // !SANITIZED_PR std::lock_guard< std::mutex > lock( _insertionMutex ); +#endif // SANITIZED_PR if( _index==-1 ) { size_t sz = _data.size(); _data.resize( sz + 1 ); _index = (node_index_type)sz; +#ifdef SANITIZED_PR + // [WARNING] Why is this necessary, given that we are within a critical section? + SetAtomic( indexPtr , _index , (node_index_type)-1 ); +#endif // SANITIZED_PR } } +#ifdef SANITIZED_PR + std::shared_lock lock( _insertionMutex ); +#endif // SANITIZED_PR return _data[ _index ]; } node_index_type index( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *node ) const @@ -1398,6 +1436,16 @@ namespace PoissonRecon for( int d=0 ; d + Point< Real , Dim > ReadAtomic( const volatile Point< Real , Dim > * a ) + { + Point< Real , Dim > p; + for( int d=0 ; d bool IsZero( const Data& data ){ return false; } template< class Real , unsigned int Dim > @@ -1930,9 +1978,14 @@ namespace PoissonRecon int _localInset( LocalDepth d ) const { return _depthOffset==0 ? 0 : 1<<( d + _depthOffset - 1 ); } void _localDepthAndOffset( const FEMTreeNode* node , LocalDepth& d , LocalOffset& off ) const { - node->depthAndOffset( d , off ) ; d -= _depthOffset; - int inset = _localInset( d ); - for( int d=0 ; ddepthAndOffset( d , off ); + d -= _depthOffset; + if( d<0 ) for( int d=0 ; d static int _BSplineBegin( LocalDepth depth ){ return BSplineEvaluationData< FEMSig >::Begin( depth ); } template< unsigned int FEMSig > static int _BSplineEnd ( LocalDepth depth ){ return BSplineEvaluationData< FEMSig >::End ( depth ); } @@ -2151,12 +2204,12 @@ namespace PoissonRecon if( node ) { int d , off[Dim] ; node->depthAndOffset( d , off ); - BaseFEMIntegrator::template ParentOverlapBounds( UIntPack< FEMDegrees1 ... >() , UIntPack< FEMDegrees2 ... >() , d , off , start , end ); + BaseFEMIntegrator::ParentOverlapBounds( UIntPack< FEMDegrees1 ... >() , UIntPack< FEMDegrees2 ... >() , d , off , start , end ); } } template< unsigned int ... FEMDegrees1 , unsigned int ... FEMDegrees2 > static void _SetParentOverlapBounds( UIntPack< FEMDegrees1 ... > , UIntPack< FEMDegrees2 ... > , int cIdx , int start[Dim] , int end[Dim] ) { - BaseFEMIntegrator::template ParentOverlapBounds( UIntPack< FEMDegrees1 ... >() , UIntPack< FEMDegrees2 ... >() , cIdx , start , end ); + BaseFEMIntegrator::ParentOverlapBounds( UIntPack< FEMDegrees1 ... >() , UIntPack< FEMDegrees2 ... >() , cIdx , start , end ); } template< unsigned int ... FEMSigs > diff --git a/Src/FEMTree.inl b/Src/FEMTree.inl index 5a31b478..fb04f6ae 100644 --- a/Src/FEMTree.inl +++ b/Src/FEMTree.inl @@ -29,7 +29,17 @@ DAMAGE. ///////////////////// // FEMTreeNodeData // ///////////////////// +#ifdef SANITIZED_PR +FEMTreeNodeData::FEMTreeNodeData( void ) : flags(0){} +FEMTreeNodeData &FEMTreeNodeData::operator = ( const FEMTreeNodeData &data ) +{ + nodeIndex = data.nodeIndex; + flags = data.flags.load(); + return *this; +} +#else // !SANITIZED_PR FEMTreeNodeData::FEMTreeNodeData( void ){ flags = 0; } +#endif // SANITIZED_PR FEMTreeNodeData::~FEMTreeNodeData( void ) { } @@ -475,8 +485,8 @@ void FEMTree< Dim , Real >::_refine( UIntPack< Degrees ... > , Allocator< FEMTre for( int c=0 ; c<(1<::Signature ... >() , _d , _off ) && addNodeFunctor( _d , _off ); } if( refine ) @@ -554,11 +564,12 @@ typename FEMTree< Dim , Real >::LocalDepth FEMTree< Dim , Real >::_getFullDepth( auto IsSupported = [&]( LocalDepth d , LocalOffset off ) { + if( d>depth ) return false; LocalOffset supportStart , supportEnd; for( unsigned int dim=0 ; dim=0 ) for( unsigned int dim=0 ; dim=end[dim] || supportEnd[dim]<=begin[dim] ) return false; return true; @@ -573,8 +584,13 @@ typename FEMTree< Dim , Real >::LocalDepth FEMTree< Dim , Real >::_getFullDepth( for( unsigned int c=0 ; c<(1<::updateDensityEstimator( typename FEMTree< Dim , Real PointSupportKey< IsotropicUIntPack< Dim , DensityDegree > > densityKey; densityKey.set( maxSplatDepth ); +#ifdef SANITIZED_PR + std::vector< std::atomic< node_index_type > > sampleMap( nodeCount() ); + ThreadPool::Parallel_for( 0 , sampleMap.size() , [&]( unsigned int , size_t i ){ sampleMap[i] = (node_index_type)-1; } ); +#else // !SANITIZED_PR std::vector< node_index_type > sampleMap( nodeCount() , -1 ); +#endif // SANITIZED_PR // Initialize the map from node indices to samples ThreadPool::Parallel_for( 0 , samples.size() , [&]( unsigned int , size_t i ){ if( samples[i].sample.weight>0 ) sampleMap[ samples[i].node->nodeData.nodeIndex ] = (node_index_type)i; } ); diff --git a/Src/ImageStitching.cpp b/Src/ImageStitching.cpp index 52c2c2ed..fc907044 100644 --- a/Src/ImageStitching.cpp +++ b/Src/ImageStitching.cpp @@ -60,11 +60,7 @@ CmdLineParameter< int > #else // !FAST_COMPILE Degree( "degree" , DEFAULT_FEM_DEGREE ) , #endif // FAST_COMPILE -#ifdef _OPENMP - ParallelType( "parallel" , (int)ThreadPool::OPEN_MP ) , -#else // !_OPENMP - ParallelType( "parallel" , (int)ThreadPool::THREAD_POOL ) , -#endif // _OPENMP + ParallelType( "parallel" , 0 ) , ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , Threads( "threads" , (int)std::thread::hardware_concurrency() ) , diff --git a/Src/MarchingCubes.h b/Src/MarchingCubes.h index 2ab88c48..ea5ff8f0 100644 --- a/Src/MarchingCubes.h +++ b/Src/MarchingCubes.h @@ -579,7 +579,7 @@ namespace PoissonRecon { unsigned int coIndex; e.factor( dir , coIndex ); - if( dir==CROSS ) Cube< D-1 >::template _FactorOrientation( typename Cube< D-1 >::template Element< D-2 >( coIndex ) , dim , dir ); + if( dir==CROSS ) Cube< D-1 >::_FactorOrientation( typename Cube< D-1 >::template Element< D-2 >( coIndex ) , dim , dir ); else dim = D-1; } template< unsigned int D > template< unsigned int _D > @@ -665,9 +665,9 @@ namespace PoissonRecon { Direction eDir , dDir ; unsigned int eCoIndex , dCoIndex; e.factor( eDir , eCoIndex ) , d.factor( dDir , dCoIndex ); - if ( eDir==CROSS ){ return 1 + Cube< D-1 >::template CellOffset( typename Cube< D-1 >::template Element< K-1 >( eCoIndex ) , d ) * 3; } - else if( eDir==BACK ){ return 0 + ( dDir==BACK ? 0 : 1 ) + Cube< D-1 >::template CellOffset( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ) * 3; } - else if( eDir==FRONT ){ return 1 + ( dDir==BACK ? 0 : 1 ) + Cube< D-1 >::template CellOffset( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ) * 3; } + if ( eDir==CROSS ){ return 1 + Cube< D-1 >::CellOffset( typename Cube< D-1 >::template Element< K-1 >( eCoIndex ) , d ) * 3; } + else if( eDir==BACK ){ return 0 + ( dDir==BACK ? 0 : 1 ) + Cube< D-1 >::CellOffset( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ) * 3; } + else if( eDir==FRONT ){ return 1 + ( dDir==BACK ? 0 : 1 ) + Cube< D-1 >::CellOffset( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ) * 3; } return 0; } template< unsigned int D > template< unsigned int K , unsigned int _D > @@ -698,9 +698,9 @@ namespace PoissonRecon { Direction eDir , dDir ; unsigned int eCoIndex , dCoIndex; e.factor( eDir , eCoIndex ) , d.factor( dDir , dCoIndex ); - if ( eDir==CROSS ) return Element< K >( eDir , Cube< D-1 >::template IncidentElement( typename Cube< D-1 >::template Element< K-1 >( eCoIndex ) , d ).index ); - else if( eDir==dDir ) return Element< K >( Opposite( eDir ) , Cube< D-1 >::template IncidentElement( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ).index ); - else return Element< K >( eDir , Cube< D-1 >::template IncidentElement( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ).index ); + if ( eDir==CROSS ) return Element< K >( eDir , Cube< D-1 >::IncidentElement( typename Cube< D-1 >::template Element< K-1 >( eCoIndex ) , d ).index ); + else if( eDir==dDir ) return Element< K >( Opposite( eDir ) , Cube< D-1 >::IncidentElement( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ).index ); + else return Element< K >( eDir , Cube< D-1 >::IncidentElement( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ).index ); } template< unsigned int D > template< unsigned int K , unsigned int _D > #ifdef _MSC_VER @@ -711,8 +711,8 @@ namespace PoissonRecon { Direction eDir , dDir ; unsigned int eCoIndex , dCoIndex; e.factor( eDir , eCoIndex ) , d.factor( dDir , dCoIndex ); - if( eDir==dDir ) return Element< K >( Opposite( eDir ) , Cube< D-1 >::template IncidentElement( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ).index ); - else return Element< K >( eDir , Cube< D-1 >::template IncidentElement( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ).index ); + if( eDir==dDir ) return Element< K >( Opposite( eDir ) , Cube< D-1 >::IncidentElement( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ).index ); + else return Element< K >( eDir , Cube< D-1 >::IncidentElement( typename Cube< D-1 >::template Element< K >( eCoIndex ) , typename Cube< D-1 >::template IncidentCubeIndex< K >( dCoIndex ) ).index ); } diff --git a/Src/MyMiscellany.h b/Src/MyMiscellany.h index 470d5868..bf51921d 100644 --- a/Src/MyMiscellany.h +++ b/Src/MyMiscellany.h @@ -176,7 +176,10 @@ namespace PoissonRecon #ifdef _OPENMP OPEN_MP , #endif // _OPENMP +#ifdef SANITIZED_PR +#else // !SANITIZED_PR THREAD_POOL , +#endif // SANITIZED_PR ASYNC , NONE }; @@ -255,6 +258,8 @@ namespace PoissonRecon _ThreadFunction( 0 ); for( unsigned int t=1 ; t _Close; + static std::atomic< unsigned int > _RemainingTasks; +#else // !SANITIZED_PR static bool _Close; static volatile unsigned int _RemainingTasks; +#endif // SANITIZED_PR static std::mutex _Mutex; static std::condition_variable _WaitingForWorkOrClose , _DoneWithWork; static std::vector< std::thread > _Threads; @@ -347,8 +361,13 @@ namespace PoissonRecon size_t ThreadPool::DefaultChunkSize = 128; ThreadPool::ScheduleType ThreadPool::DefaultSchedule = ThreadPool::DYNAMIC; +#ifdef SANITIZED_PR + std::atomic< bool > ThreadPool::_Close; + std::atomic< unsigned int > ThreadPool::_RemainingTasks; +#else // !SANITIZED_PR bool ThreadPool::_Close; volatile unsigned int ThreadPool::_RemainingTasks; +#endif // SANITIZED_PR std::mutex ThreadPool::_Mutex; std::condition_variable ThreadPool::_WaitingForWorkOrClose; std::condition_variable ThreadPool::_DoneWithWork; @@ -361,12 +380,38 @@ namespace PoissonRecon #ifdef _OPENMP "open mp" , #endif // _OPENMP +#ifdef SANITIZED_PR +#else // !SANITIZED_PR "thread pool" , +#endif // SANITIZED_PR "async" , "none" }; const std::vector< std::string >ThreadPool::ScheduleNames = { "static" , "dynamic" }; + template< typename Value > + Value ReadAtomic32( const volatile Value * value ) + { +#if defined( _WIN32 ) || defined( _WIN64 ) + long _value = InterlockedExchangeAdd( (long*)value , 0 ); + return *(Value*)(&_value); +#else // !_WIN32 && !_WIN64 + uint32_t _value = __atomic_load_n( (uint32_t *)value , __ATOMIC_SEQ_CST ); +#endif // _WIN32 || _WIN64 + return *(Value*)(&_value); + } + + template< typename Value > + Value ReadAtomic64( const volatile Value * value ) + { +#if defined( _WIN32 ) || defined( _WIN64 ) + __int64 _value = InterlockedExchangeAdd64( (__int64*)value , 0 ); +#else // !_WIN32 && !_WIN64 + uint64_t _value = __atomic_load_n( (uint64_t *)value , __ATOMIC_SEQ_CST ); +#endif // _WIN32 || _WIN64 + return *(Value*)(&_value); + } + template< typename Value > bool SetAtomic32( volatile Value *value , Value newValue , Value oldValue ) { @@ -395,18 +440,36 @@ namespace PoissonRecon template< typename Number > void AddAtomic32( volatile Number &a , Number b ) { -#if defined( _WIN32 ) || defined( _WIN64 ) +#ifdef SANITIZED_PR + Number current = ReadAtomic32( &a ); +#else // !SANITIZED_PR Number current = a; +#endif // SANITIZED_PR Number sum = current+b; +#if defined( _WIN32 ) || defined( _WIN64 ) long *_current = (long *)¤t; long *_sum = (long *)∑ +#ifdef SANITIZED_PR + while( InterlockedCompareExchange( (long*)&a , *_sum , *_current )!=*_current ) + { + current = ReadAtomic32( &a ); + sum = current + b; + } +#else // !SANITIZED_PR while( InterlockedCompareExchange( (long*)&a , *_sum , *_current )!=*_current ) current = a , sum = a+b; +#endif // SANITIZED_PR #else // !_WIN32 && !_WIN64 - Number current = a; - Number sum = current+b; uint32_t *_current = (uint32_t *)¤t; uint32_t *_sum = (uint32_t *)∑ +#ifdef SANITIZED_PR + while( __sync_val_compare_and_swap( (uint32_t *)&a , *_current , *_sum )!=*_current ) + { + current = ReadAtomic32( &a ); + sum = current+b; + } +#else // !SANITIZED_PR while( __sync_val_compare_and_swap( (uint32_t *)&a , *_current , *_sum )!=*_current ) current = a , sum = a+b; +#endif // SANITIZED_PR #endif // _WIN32 || _WIN64 } @@ -414,22 +477,50 @@ namespace PoissonRecon void AddAtomic64( volatile Number &a , Number b ) { #if 1 +#ifdef SANITIZED_PR + Number current = ReadAtomic64( &a ); + Number sum = current+b; + while( !SetAtomic64( &a , sum , current ) ) + { + current = ReadAtomic64( &a ); + sum = current+b; + } +#else // !SANITIZED_PR Number current = a; Number sum = current+b; while( !SetAtomic64( &a , sum , current ) ) current = a , sum = a+b; +#endif // SANITIZED_PR #else -#if defined( _WIN32 ) || defined( _WIN64 ) +#ifdef SANITIZED_PR + Number current = ReadAtomic64( &a ); +#else // !SANITIZED_PR Number current = a; +#endif // SANITIZED_PR Number sum = current+b; +#if defined( _WIN32 ) || defined( _WIN64 ) __int64 *_current = (__int64 *)¤t; __int64 *_sum = (__int64 *)∑ +#ifdef SANITIZED_PR + while( InterlockedCompareExchange64( (__int64*)&a , *_sum , *_current )!=*_current ) + { + current = ReadAtomic64( &a ); + sum = current+b; + } +#else // !SANITIZED_PR while( InterlockedCompareExchange64( (__int64*)&a , *_sum , *_current )!=*_current ) current = a , sum = a+b; +#endif // SANITIZED_PR #else // !_WIN32 && !_WIN64 - Number current = a; - Number sum = current+b; uint64_t *_current = (uint64_t *)¤t; uint64_t *_sum = (uint64_t *)∑ +#ifdef SANITIZED_PR + while( __sync_val_compare_and_swap( (uint64_t *)&a , *_current , *_sum )!=*_current ) + { + current = ReadAtomic64( &a); + sum = current+b; + } +#else // !SANITIZED_PR while( __sync_val_compare_and_swap( (uint64_t *)&a , *_current , *_sum )!=*_current ) current = a , sum = a+b; +#endif // SANITIZED_PR #endif // _WIN32 || _WIN64 #endif } @@ -465,6 +556,20 @@ namespace PoissonRecon } } + template< typename Value > + Value ReadAtomic( const volatile Value * value ) + { + if constexpr( sizeof(Value)==4 ) return ReadAtomic32( value ); + else if constexpr( sizeof(Value)==8 ) return ReadAtomic64( value ); + else + { + WARN_ONCE( "should not use this function: " , sizeof(Value) ); + static std::mutex readAtomicMutex; + std::lock_guard< std::mutex > lock( readAtomicMutex ); + return *value; + } + } + ////////////////// // Memory Stuff // ////////////////// @@ -477,6 +582,7 @@ namespace PoissonRecon { _t = Time(); _currentPeak = 0; + _terminate = false; if( ms ) { _thread = std::thread( &Profiler::_updatePeakMemoryFunction , std::ref( *this ) , ms ); @@ -489,10 +595,7 @@ namespace PoissonRecon { if( _spawnedSampler ) { - { - std::lock_guard< std::mutex > lock( _mutex ); - _terminate = true; - } + _terminate = true; _thread.join(); } } @@ -538,10 +641,10 @@ namespace PoissonRecon protected: std::thread _thread; std::mutex _mutex; - bool _spawnedSampler; double _t; - volatile size_t _currentPeak; - volatile bool _terminate; + std::atomic< bool > _spawnedSampler; + std::atomic< size_t > _currentPeak; + std::atomic< bool > _terminate; void _updatePeakMemoryFunction( unsigned int ms ) { diff --git a/Src/PointInterpolant.cpp b/Src/PointInterpolant.cpp index 25d668a6..e56acbcf 100644 --- a/Src/PointInterpolant.cpp +++ b/Src/PointInterpolant.cpp @@ -88,11 +88,7 @@ CmdLineParameter< int > Dimension( "dim" , DEFAULT_DIMENSION ) , #endif // !FAST_COMPILE MaxMemoryGB( "maxMemory" , 0 ) , -#ifdef _OPENMP - ParallelType( "parallel" , (int)ThreadPool::OPEN_MP ) , -#else // !_OPENMP - ParallelType( "parallel" , (int)ThreadPool::THREAD_POOL ) , -#endif // _OPENMP + ParallelType( "parallel" , 0 ) , ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , Threads( "threads" , (int)std::thread::hardware_concurrency() ); diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index 496357d2..48c703b7 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -88,11 +88,7 @@ CmdLineParameter< int > BType( "bType" , Reconstructor::Poisson::DefaultFEMBoundary+1 ) , #endif // !FAST_COMPILE MaxMemoryGB( "maxMemory" , 0 ) , -#ifdef _OPENMP - ParallelType( "parallel" , (int)ThreadPool::OPEN_MP ) , -#else // !_OPENMP - ParallelType( "parallel" , (int)ThreadPool::THREAD_POOL ) , -#endif // _OPENMP + ParallelType( "parallel" , 0 ) , AlignmentDir( "alignDir" , DEFAULT_DIMENSION-1 ) , ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , diff --git a/Src/PoissonReconClient.cpp b/Src/PoissonReconClient.cpp index 115a8015..2ad9dad0 100644 --- a/Src/PoissonReconClient.cpp +++ b/Src/PoissonReconClient.cpp @@ -50,11 +50,7 @@ CmdLineParameter< std::string > CmdLineParameter< int > MaxMemoryGB( "maxMemory" , 0 ) , -#ifdef _OPENMP - ParallelType( "parallel" , (int)ThreadPool::OPEN_MP ) , -#else // !_OPENMP - ParallelType( "parallel" , (int)ThreadPool::THREAD_POOL ) , -#endif // _OPENMP + ParallelType( "parallel" , 0 ) , ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , Threads( "threads" , (int)std::thread::hardware_concurrency() ) , diff --git a/Src/PoissonReconServer.cpp b/Src/PoissonReconServer.cpp index f4f569aa..e926ad4a 100644 --- a/Src/PoissonReconServer.cpp +++ b/Src/PoissonReconServer.cpp @@ -83,11 +83,7 @@ CmdLineParameter< int > FilesPerDir( "filesPerDir" , -1 ) , MaxMemoryGB( "maxMemory" , 0 ) , PeakMemorySampleMS( "sampleMS" , 10 ) , -#ifdef _OPENMP - ParallelType( "parallel" , (int)ThreadPool::OPEN_MP ) , -#else // !_OPENMP - ParallelType( "parallel" , (int)ThreadPool::THREAD_POOL ) , -#endif // _OPENMP + ParallelType( "parallel" , 0 ) , ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , MergeSlabs( "merge" , MergeSlabType::SEAMLESS ) , diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 07362197..b6ab3582 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -37,6 +37,7 @@ DAMAGE. // (each of which is small enough to be represented using 32-bit indexing.) #endif // BIG_DATA +//#define SANITIZED_PR // If enabled, produces CLANG-sanitized code [thread/undefined/address] //#define FAST_COMPILE // If enabled, only a single version of the code is compiled #undef SHOW_WARNINGS // Display compilation warnings #undef ARRAY_DEBUG // If enabled, array access is tested for validity @@ -45,7 +46,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "18.00" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "18.01" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth diff --git a/Src/Reconstruction.example.cpp b/Src/Reconstruction.example.cpp index 59b49fda..14a1c976 100644 --- a/Src/Reconstruction.example.cpp +++ b/Src/Reconstruction.example.cpp @@ -324,11 +324,7 @@ int main( int argc , char* argv[] ) { Timer timer; CmdLineParse( argc-1 , &argv[1] , params ); -#ifdef _OPENMP - ThreadPool::Init( ThreadPool::OPEN_MP , std::thread::hardware_concurrency() ); -#else // !_OPENMP - ThreadPool::Init( ThreadPool::THREAD_POOL , std::thread::hardware_concurrency() ); -#endif // _OPENMP + ThreadPool::Init( (ThreadPool::ParallelType)0 , std::thread::hardware_concurrency() ); if( !SampleNum.set ) { diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h index 6eed21e4..30972313 100644 --- a/Src/Reconstructors.h +++ b/Src/Reconstructors.h @@ -827,7 +827,7 @@ namespace PoissonRecon std::vector< Point< Real , Dim > > vertices( envelopeMesh->vertices.size() ); for( unsigned int i=0 ; ivertices[i]; - geometryNodeDesignators = FEMTreeInitializer< Dim , Real >::template GetGeometryNodeDesignators( &implicit.tree.spaceRoot() , vertices , envelopeMesh->simplices , params.baseDepth , params.envelopeDepth , implicit.tree.nodeAllocators , implicit.tree.initializer() ); + geometryNodeDesignators = FEMTreeInitializer< Dim , Real >::GetGeometryNodeDesignators( &implicit.tree.spaceRoot() , vertices , envelopeMesh->simplices , params.baseDepth , params.envelopeDepth , implicit.tree.nodeAllocators , implicit.tree.initializer() ); // Make nodes in the support of the vector field @{ExactDepth} interior if( params.dirichletErode ) diff --git a/Src/RegularTree.inl b/Src/RegularTree.inl index 8ddfa3dc..c85bb4eb 100644 --- a/Src/RegularTree.inl +++ b/Src/RegularTree.inl @@ -663,8 +663,18 @@ unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey { if( pNeighbors[pi] ) { +#ifdef SANITIZED_PR + RegularTreeNode * children = ReadAtomic( &(pNeighbors[pi]->children) ); + if( !children ) + { + pNeighbors[pi]->template initChildren< ThreadSafe >( nodeAllocator , initializer ); + children = ReadAtomic( &(pNeighbors[pi]->children) ); + } + cNeighbors[ci] = children + ( cornerIndex | ( ( _i&1)<<(Dim-1) ) ); +#else // !SANITIZED_PR if( !pNeighbors[pi]->children ) pNeighbors[pi]->template initChildren< ThreadSafe >( nodeAllocator , initializer ); cNeighbors[ci] = pNeighbors[pi]->children + ( cornerIndex | ( ( _i&1)<<(Dim-1) ) ); +#endif // SANITIZED_PR count++; } else cNeighbors[ci] = NULL; diff --git a/Src/SparseMatrix.inl b/Src/SparseMatrix.inl index b955538f..52a6eac1 100644 --- a/Src/SparseMatrix.inl +++ b/Src/SparseMatrix.inl @@ -460,7 +460,7 @@ SparseMatrix< T , IndexType , 0 > SparseMatrix< T , IndexType , 0 >::Transpose( A.resize( aRows ); for( size_t i=0 ; iN ]++; - for( size_t i=0 ; i SparseMatrix< T , IndexType , 0 >::Transpose( A.resize( aRows ); for( size_t i=0 ; iN ]++; - for( size_t i=0 ; i Date: Thu, 12 Sep 2024 13:54:20 -0400 Subject: [PATCH 38/86] Version 18.02 --- README.md | 14 ++++++++++---- Src/PointsToDisks.cpp | 2 -- Src/PreProcessor.h | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 333f7538..ef1b8345 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

      Adaptive Multigrid Solvers (Version 18.01)

      +

      Adaptive Multigrid Solvers (Version 18.02)

      links compilation @@ -29,11 +29,12 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
      Executables: -Win64
      +Win64
      Source Code: -ZIP GitHub
      +ZIP GitHub
      Older Versions: -V18.00, +V18.01, +V18.00, V17.00, V16.10, V16.09, @@ -1571,6 +1572,11 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
    • Introduced compiler support for CLANG-sanitized code via the pre-processor flag SANITIZED_PR. +Version 18.02: +
        +
      1. Cleaned up bug in PointsToDisks executable. +
      +
      diff --git a/Src/PointsToDisks.cpp b/Src/PointsToDisks.cpp index 463cdb5b..4a0af0fe 100644 --- a/Src/PointsToDisks.cpp +++ b/Src/PointsToDisks.cpp @@ -234,8 +234,6 @@ int main( int argc , char* argv[] ) if( !l ) return; n /= (float)l; - p += n; - float radiusScale = (float)pow( l , LengthToRadiusExponent.value ); v1 = Point< float , 3 >( -n[2] , 0 , n[0] ); if( Point< float , 3 >::SquareNorm( v1 )<0.0000001 ) v1 = Point< float , 3 >( 1 , 0 , 0 ); diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index b6ab3582..e17f6f97 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -46,7 +46,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "18.01" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "18.02" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth From 0794484bc3203cec00acc378a50931745ea0c685 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Thu, 12 Sep 2024 21:42:52 -0400 Subject: [PATCH 39/86] Version 18.03 --- README.md | 12 +++++++++--- Src/FEMTree.inl | 3 ++- Src/PreProcessor.h | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ef1b8345..9637a950 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

      Adaptive Multigrid Solvers (Version 18.02)

      +

      Adaptive Multigrid Solvers (Version 18.03)

      links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
      Executables: -Win64
      +Win64
      Source Code: -ZIP GitHub
      +ZIP GitHub
      Older Versions: +V18.02, V18.01, V18.00, V17.00, @@ -1577,6 +1578,11 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
    • Cleaned up bug in PointsToDisks executable. +Version 18.03: +
        +
      1. Fixed bug occuring when the octree was complete.. +
      +
      diff --git a/Src/FEMTree.inl b/Src/FEMTree.inl index fb04f6ae..61e9b6e8 100644 --- a/Src/FEMTree.inl +++ b/Src/FEMTree.inl @@ -627,7 +627,8 @@ template< unsigned int Dim , class Real > template< unsigned int ... Degrees > typename FEMTree< Dim , Real >::LocalDepth FEMTree< Dim , Real >::getFullDepth( UIntPack< Degrees ... > , const LocalDepth depth , const LocalOffset begin , const LocalOffset end ) const { - LocalDepth maxDepth = this->maxDepth(); + // [NOTE] Need "+1" because _getFullDepth will test children of leaves + LocalDepth maxDepth = this->maxDepth() + 1; LocalDepth _depth ; LocalOffset _begin , _end; for( unsigned int d=0 ; d15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "18.02" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "18.03" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth From 7befcbcd2fa7d43b16ff953e37a47a8f80c32741 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Sun, 15 Sep 2024 17:13:45 -0400 Subject: [PATCH 40/86] Version 18.04 --- AdaptiveSolvers.sln | 1 + README.md | 14 +- Src/FEMTree.LevelSet.2D.inl | 46 ++++++ Src/FEMTree.LevelSet.3D.inl | 121 ++++++++++++++++ Src/FEMTree.LevelSet.inl | 15 ++ Src/FEMTree.System.inl | 2 +- Src/FEMTree.h | 27 ++-- Src/FEMTree.inl | 5 - Src/MyAtomic.h | 281 ++++++++++++++++++++++++++++++++++++ Src/MyMiscellany.h | 221 +++------------------------- Src/PreProcessor.h | 2 +- Src/RegularTree.inl | 6 +- 12 files changed, 514 insertions(+), 227 deletions(-) create mode 100644 Src/MyAtomic.h diff --git a/AdaptiveSolvers.sln b/AdaptiveSolvers.sln index 02fbc9b9..1247503d 100644 --- a/AdaptiveSolvers.sln +++ b/AdaptiveSolvers.sln @@ -59,6 +59,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Header Files", "Header File Src\MarchingCubes.h = Src\MarchingCubes.h Src\MAT.h = Src\MAT.h Src\MergePlyClientServer.h = Src\MergePlyClientServer.h + Src\MyAtomic.h = Src\MyAtomic.h Src\MyExceptions.h = Src\MyExceptions.h Src\MyMiscellany.h = Src\MyMiscellany.h Src\Ply.h = Src\Ply.h diff --git a/README.md b/README.md index 9637a950..b4cb4f33 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

      Adaptive Multigrid Solvers (Version 18.03)

      +

      Adaptive Multigrid Solvers (Version 18.04)

      links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
      Executables: -Win64
      +Win64
      Source Code: -ZIP GitHub
      +ZIP GitHub
      Older Versions: +V18.03, V18.02, V18.01, V18.00, @@ -1580,7 +1581,12 @@ Similarly, to reduce compilation times, support for specific degrees can be remo Version 18.03:
        -
      1. Fixed bug occuring when the octree was complete.. +
      2. Fixed bug occurring when the octree was complete. +
      + +Version 18.04: +
        +
      1. Further sanitized multi-threading code.
      diff --git a/Src/FEMTree.LevelSet.2D.inl b/Src/FEMTree.LevelSet.2D.inl index f4723244..a5a50dfd 100644 --- a/Src/FEMTree.LevelSet.2D.inl +++ b/Src/FEMTree.LevelSet.2D.inl @@ -81,22 +81,37 @@ public: EKeyValues eKeyValues; VKeyValues vKeyValues; +#ifdef SANITIZED_PR + Pointer( std::atomic< char > ) cSet; + Pointer( std::atomic< char > ) eSet; +#else // !SANITIZED_PR Pointer( char ) cSet; Pointer( char ) eSet; +#endif // SANITIZED_PR Scratch( void ) { vKeyValues.resize( ThreadPool::NumThreads() ); eKeyValues.resize( ThreadPool::NumThreads() ); fKeyValues.resize( ThreadPool::NumThreads() ); +#ifdef SANITIZED_PR + cSet = NullPointer( std::atomic< char > ); + eSet = NullPointer( std::atomic< char > ); +#else // !SANITIZED_PR cSet = NullPointer( char ); eSet = NullPointer( char ); +#endif // SANITIZED_PR } ~Scratch( void ) { +#ifdef SANITIZED_PR + DeletePointer( cSet ); + DeletePointer( eSet ); +#else // !SANITIZED_PR FreePointer( cSet ); FreePointer( eSet ); +#endif // SANITIZED_PR } void reset( const LevelSetExtraction::FullCellIndexData< Dim > &cellIndices ) @@ -104,6 +119,20 @@ public: for( size_t i=0 ; i >( cellIndices.counts[0] ); + for( unsigned int i=0 ; i >( cellIndices.counts[1] ); + for( unsigned int i=0 ; i( cellIndices.counts[1] ); memset( eSet , 0 , sizeof( char ) * cellIndices.counts[1] ); } +#endif // SANITIZED_PR } }; @@ -487,7 +517,11 @@ public: { static const unsigned int FEMDegrees[] = { FEMSignature< FEMSigs >::Degree ... }; SliceValues& sValues = sliceValues[depth]; +#ifdef SANITIZED_PR + Pointer( std::atomic< char > ) cornerSet = scratchValues[depth].cSet; +#else // !SANITIZED_PR Pointer( char ) cornerSet = scratchValues[depth].cSet; +#endif // SANITIZED_PR bool useBoundaryEvaluation = false; for( int d=0 ; d::Degree ... > > > neighborKeys( ThreadPool::NumThreads() ); @@ -542,7 +576,11 @@ public: { node = node->parent , _depth--; SliceValues& _sValues = sliceValues[_depth]; +#ifdef SANITIZED_PR + Pointer( std::atomic< char > ) _cornerSet = scratchValues[_depth].cSet; +#else // !SANITIZED_PR Pointer( char ) _cornerSet = scratchValues[_depth].cSet; +#endif // SANITIZED_PR const typename LevelSetExtraction::FullCellIndexData< Dim >::template CellIndices<0> &_cIndices = _sValues.cellIndices.template indices<0>( node ); node_index_type _vIndex = _cIndices[c.index]; _sValues.cornerValues[_vIndex] = sValues.cornerValues[vIndex]; @@ -606,7 +644,11 @@ public: if( HyperCube::Cube< 1 >::HasMCRoots( HyperCube::Cube< Dim >::ElementMCIndex( e , sValues.mcIndices[idx] ) ) ) { node_index_type vIndex = eIndices[e.index]; +#ifdef SANITIZED_PR + std::atomic< char > &edgeSet = scValues.eSet[vIndex]; +#else // !SANITIZED_PR volatile char &edgeSet = scValues.eSet[vIndex]; +#endif // SANITIZED_PR // If the edge hasn't been set already (e.g. either by another thread or from a finer resolution) if( !edgeSet ) { @@ -732,7 +774,11 @@ public: }; SliceValues& sValues = sliceValues[depth]; +#ifdef SANITIZED_PR + Pointer( std::atomic< char > ) edgeSet = scratchValues[depth].eSet; +#else // !SANITIZED_PR Pointer( char ) edgeSet = scratchValues[depth].eSet; +#endif // SANITIZED_PR std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); for( size_t i=0 ; i ) cSet; + Pointer( std::atomic< char > ) eSet; + Pointer( std::atomic< char > ) fSet; +#else // !SANITIZED_PR Pointer( char ) cSet; Pointer( char ) eSet; Pointer( char ) fSet; +#endif // SANITIZED_PR Scratch( void ) { vKeyValues.resize( ThreadPool::NumThreads() ); eKeyValues.resize( ThreadPool::NumThreads() ); fKeyValues.resize( ThreadPool::NumThreads() ); +#ifdef SANITIZED_PR + cSet = NullPointer( std::atomic< char > ); + eSet = NullPointer( std::atomic< char > ); + fSet = NullPointer( std::atomic< char > ); +#else // !SANITIZED_PR cSet = NullPointer( char ); eSet = NullPointer( char ); fSet = NullPointer( char ); +#endif // SANITIZED_PR } ~Scratch( void ) { +#ifdef SANITIZED_PR + DeletePointer( cSet ); + DeletePointer( eSet ); + DeletePointer( fSet ); +#else // !SANITIZED_PR FreePointer( cSet ); FreePointer( eSet ); FreePointer( fSet ); +#endif // SANITIZED_PR } void reset( const LevelSetExtraction::SliceCellIndexData< Dim > &cellIndices ) @@ -130,6 +157,26 @@ public: for( size_t i=0 ; i >( cellIndices.counts[0] ); + for( unsigned int i=0 ; i >( cellIndices.counts[1] ); + for( unsigned int i=0 ; i >( cellIndices.counts[2] ); + for( unsigned int i=0 ; i( cellIndices.counts[2] ); memset( fSet , 0 , sizeof( char ) * cellIndices.counts[2] ); } +#endif // SANITIZED_PR } }; @@ -335,22 +383,37 @@ public: EKeyValues eKeyValues; VKeyValues vKeyValues; +#ifdef SANITIZED_PR + Pointer( std::atomic< char > ) eSet; + Pointer( std::atomic< char > ) fSet; +#else // !SANITIZED_PR Pointer( char ) eSet; Pointer( char ) fSet; +#endif // SANITIZED_PR Scratch( void ) { vKeyValues.resize( ThreadPool::NumThreads() ); eKeyValues.resize( ThreadPool::NumThreads() ); fKeyValues.resize( ThreadPool::NumThreads() ); +#ifdef SANITIZED_PR + eSet = NullPointer( std::atomic< char > ); + fSet = NullPointer( std::atomic< char > ); +#else // !SANITIZED_PR eSet = NullPointer( char ); fSet = NullPointer( char ); +#endif // SANITIZED_PR } ~Scratch( void ) { +#ifdef SANITIZED_PR + DeletePointer( eSet ); + DeletePointer( fSet ); +#else // !SANITIZED_PR FreePointer( eSet ); FreePointer( fSet ); +#endif // SANITIZED_PR } void reset( const LevelSetExtraction::SlabCellIndexData< Dim > &cellIndices ) @@ -358,6 +421,20 @@ public: for( size_t i=0 ; i >( cellIndices.counts[0] ); + for( unsigned int i=0 ; i >( cellIndices.counts[1] ); + for( unsigned int i=0 ; i( cellIndices.counts[1] ); memset( fSet , 0 , sizeof( char ) * cellIndices.counts[1] ); } +#endif // SANITIZED_PR } }; @@ -820,7 +898,11 @@ public: for( typename HyperCube::Cube< Dim-1 >::template Element< 0 > _c ; _c::template ElementNum< 0 >() ; _c++ ) { typename HyperCube::Cube< Dim >::template Element< 0 > c( zDir , _c.index ); +#ifdef SANITIZED_PR + node_index_type vIndex = ReadAtomic( cIndices[_c.index] ); +#else // !SANITIZED_PR node_index_type vIndex = cIndices[_c.index]; +#endif // SANITIZED_PR if( !sScratch.cSet[vIndex] ) { if( sValues.cornerGradients ) @@ -828,16 +910,30 @@ public: CumulativeDerivativeValues< Real , Dim , 1 > p; if( useBoundaryEvaluation ) p = tree.template _getCornerValues< Real , 1 >( bNeighborKey , leaf , c.index , coefficients , coarseCoefficients , evaluator , tree._maxDepth , isInterior ); else p = tree.template _getCornerValues< Real , 1 >( neighborKey , leaf , c.index , coefficients , coarseCoefficients , evaluator , tree._maxDepth , isInterior ); +#ifdef SANITIZED_PR + SetAtomic( sValues.cornerValues[vIndex] , p[0] ); + SetAtomic( sValues.cornerGradients[vIndex] , Point< Real , Dim >( p[1] , p[2] , p[3] ) ); +#else // !SANITIZED_PR sValues.cornerValues[vIndex] = p[0] , sValues.cornerGradients[vIndex] = Point< Real , Dim >( p[1] , p[2] , p[3] ); +#endif // SANITIZED_PR } else { +#ifdef SANITIZED_PR + if( useBoundaryEvaluation ) SetAtomic( sValues.cornerValues[vIndex] , tree.template _getCornerValues< Real , 0 >( bNeighborKey , leaf , c.index , coefficients , coarseCoefficients , evaluator , tree._maxDepth , isInterior )[0] ); + else SetAtomic( sValues.cornerValues[vIndex] , tree.template _getCornerValues< Real , 0 >( neighborKey , leaf , c.index , coefficients , coarseCoefficients , evaluator , tree._maxDepth , isInterior )[0] ); +#else // !SANITIZED_PR if( useBoundaryEvaluation ) sValues.cornerValues[vIndex] = tree.template _getCornerValues< Real , 0 >( bNeighborKey , leaf , c.index , coefficients , coarseCoefficients , evaluator , tree._maxDepth , isInterior )[0]; else sValues.cornerValues[vIndex] = tree.template _getCornerValues< Real , 0 >( neighborKey , leaf , c.index , coefficients , coarseCoefficients , evaluator , tree._maxDepth , isInterior )[0]; +#endif // SANITIZED_PR } sScratch.cSet[vIndex] = 1; } +#ifdef SANITIZED_PR + squareValues[_c.index] = ReadAtomic( sValues.cornerValues[ vIndex ] ); +#else // !SANITIZED_PR squareValues[_c.index] = sValues.cornerValues[ vIndex ]; +#endif // SANITIZED_PR TreeNode* node = leaf; LocalDepth _depth = depth; int _slice = slice; @@ -848,8 +944,13 @@ public: typename SliceValues::Scratch &_sScratch = slabValues[_depth].sliceScratch( _slice ); const typename LevelSetExtraction::SliceCellIndexData< Dim >::template CellIndices<0> &_cIndices = _sValues.cellIndices.template indices<0>( node ); node_index_type _vIndex = _cIndices[_c.index]; +#ifdef SANITIZED_PR + SetAtomic( _sValues.cornerValues[_vIndex] , ReadAtomic( sValues.cornerValues[vIndex] ) ); + if( _sValues.cornerGradients ) SetAtomic( _sValues.cornerGradients[_vIndex] , ReadAtomic( sValues.cornerGradients[vIndex] ) ); +#else // !SANITIZED_PR _sValues.cornerValues[_vIndex] = sValues.cornerValues[vIndex]; if( _sValues.cornerGradients ) _sValues.cornerGradients[_vIndex] = sValues.cornerGradients[vIndex]; +#endif // SANITIZED_PR _sScratch.cSet[_vIndex] = 1; } } @@ -939,7 +1040,11 @@ public: { typename HyperCube::Cube< Dim >::template Element< 1 > e( zDir , _e.index ); node_index_type vIndex = eIndices[_e.index]; +#ifdef SANITIZED_PR + std::atomic< char > &edgeSet = sScratch.eSet[vIndex]; +#else // !SANITIZED_PR volatile char &edgeSet = sScratch.eSet[vIndex]; +#endif // SANITIZED_PR if( !edgeSet ) { Vertex vertex; @@ -1073,7 +1178,11 @@ public: if( HyperCube::Cube< 1 >::HasMCRoots( _mcIndex ) ) { node_index_type vIndex = eIndices[_c.index]; +#ifdef SANITIZED_PR + std::atomic< char > &edgeSet = xScratch.eSet[vIndex]; +#else // !SANITIZED_PR volatile char &edgeSet = xScratch.eSet[vIndex]; +#endif // SANITIZED_PR if( !edgeSet ) { Vertex vertex; @@ -1185,7 +1294,11 @@ public: Key key; if( cSliceScratch.eSet[cIndex1] ) key = cSliceValues.edgeKeys[cIndex1]; else key = cSliceValues.edgeKeys[cIndex2]; +#ifdef SANITIZED_PR + SetAtomic( pSliceValues.edgeKeys[pIndex] , key ); +#else // !SANITIZED_PR pSliceValues.edgeKeys[pIndex] = key; +#endif // SANITIZED_PR pSliceScratch.eSet[pIndex] = 1; } else if( cSliceScratch.eSet[cIndex1] && cSliceScratch.eSet[cIndex2] ) @@ -1257,7 +1370,11 @@ public: Key key; if( eSet0 ) key = cSliceValues0.edgeKeys[cIndex0]; //, vPair = cSliceValues0.edgeVertexMap.find( key )->second; else key = cSliceValues1.edgeKeys[cIndex1]; //, vPair = cSliceValues1.edgeVertexMap.find( key )->second; +#ifdef SANITIZED_PR + SetAtomic( pSliceValues.edgeKeys[ pIndex ] , key ); +#else // !SANITIZED_PR pSliceValues.edgeKeys[ pIndex ] = key; +#endif // SANITIZED_PR pSliceScratch.eSet[ pIndex ] = 1; } // If there's are two zero-crossings along the edge @@ -1419,7 +1536,11 @@ public: } } xScratch.fSet[ eIndices[_e.index] ] = 1; +#ifdef SANITIZED_PR + SetAtomic( xValues.faceEdges[ eIndices[_e.index] ] , fe ); +#else // !SANITIZED_PR xValues.faceEdges[ eIndices[_e.index] ] = fe; +#endif // SANITIZED_PR TreeNode* node = leaf; LocalDepth _depth = depth; diff --git a/Src/FEMTree.LevelSet.inl b/Src/FEMTree.LevelSet.inl index 71381547..2d18b251 100644 --- a/Src/FEMTree.LevelSet.inl +++ b/Src/FEMTree.LevelSet.inl @@ -67,6 +67,13 @@ namespace LevelSetExtraction friend std::ostream &operator << ( std::ostream &os , const Key &key ){ return os << key.to_string(); } + friend Key SetAtomic( volatile Key & value , Key newValue ) + { + Key oldValue; + for( unsigned int d=0 ; d v1 , Key< Dim > v2 ){ vertices[0] = v1 , vertices[1] = v2; } Key< Dim > &operator[]( int idx ){ return vertices[idx]; } const Key< Dim > &operator[]( int idx ) const { return vertices[idx]; } + + friend IsoEdge SetAtomic( volatile IsoEdge & value , IsoEdge newValue ) + { + IsoEdge oldValue; + oldValue.vertices[0] = SetAtomic( value.vertices[0] , newValue.vertices[0] ); + oldValue.vertices[1] = SetAtomic( value.vertices[1] , newValue.vertices[1] ); + return oldValue; + } }; ///////////////////// diff --git a/Src/FEMTree.System.inl b/Src/FEMTree.System.inl index a8d923af..7581419b 100644 --- a/Src/FEMTree.System.inl +++ b/Src/FEMTree.System.inl @@ -2938,7 +2938,7 @@ void FEMTree< Dim , Real >::_addFEMConstraints( UIntPack< FEMSigs ... > , UIntPa static const WindowLoopData< UIntPack< BSplineOverlapSizes< CDegrees , FEMDegrees >::OverlapSize ... > > cfemLoopData( []( int c , int* start , int* end ){ BaseFEMIntegrator::ParentOverlapBounds( UIntPack< CDegrees ... >() , UIntPack< FEMDegrees ... >() , c , start , end ); } ); static const WindowLoopData< UIntPack< BSplineOverlapSizes< FEMDegrees , CDegrees >::OverlapSize ... > > femcLoopData( []( int c , int* start , int* end ){ BaseFEMIntegrator::ParentOverlapBounds( UIntPack< FEMDegrees ... >() , UIntPack< CDegrees ... >() , c , start , end ); } ); - bool hasCoarserCoefficients = false; + std::atomic< bool > hasCoarserCoefficients = true; // Iterate from fine to coarse, setting the constraints @(depth) and the cumulative constraints @(depth-1) for( LocalDepth d=maxDepth ; d>=0 ; d-- ) { diff --git a/Src/FEMTree.h b/Src/FEMTree.h index 485e7913..10d05d39 100644 --- a/Src/FEMTree.h +++ b/Src/FEMTree.h @@ -352,14 +352,15 @@ namespace PoissonRecon std::shared_lock lock( _insertionMutex ); indexPtr = &_indices[ node->nodeData.nodeIndex ]; } - node_index_type _index = ReadAtomic( indexPtr ); + node_index_type _index = ReadAtomic( *indexPtr ); #else // !SANITIZED_PR volatile node_index_type &_index = _indices[ node->nodeData.nodeIndex ]; -#endif // SANITIZED_PR if( _index==-1 ) +#endif // SANITIZED_PR + if( _index==-1 ) { #ifdef SANITIZED_PR std::unique_lock lock( _insertionMutex ); - _index = ReadAtomic( indexPtr ); + _index = ReadAtomic( *indexPtr ); #else // !SANITIZED_PR std::lock_guard< std::mutex > lock( _insertionMutex ); #endif // SANITIZED_PR @@ -370,7 +371,7 @@ namespace PoissonRecon _index = (node_index_type)sz; #ifdef SANITIZED_PR // [WARNING] Why is this necessary, given that we are within a critical section? - SetAtomic( indexPtr , _index , (node_index_type)-1 ); + SetAtomic( *indexPtr , _index , (node_index_type)-1 ); #endif // SANITIZED_PR } } @@ -1431,20 +1432,26 @@ namespace PoissonRecon }; template< class Real , unsigned int Dim > - void AddAtomic( Point< Real , Dim >& a , const Point< Real , Dim >& b ) + void AddAtomic( volatile Point< Real , Dim > & a , const Point< Real , Dim >& b ) { - for( int d=0 ; d - Point< Real , Dim > ReadAtomic( const volatile Point< Real , Dim > * a ) + Point< Real , Dim > ReadAtomic( const volatile Point< Real , Dim > & a ) { Point< Real , Dim > p; - for( int d=0 ; d + Point< Real , Dim > SetAtomic( volatile Point< Real , Dim > & p , Point< Real , Dim > newP ) + { + Point< Real , Dim > oldP; + for( int d=0 ; d bool IsZero( const Data& data ){ return false; } diff --git a/Src/FEMTree.inl b/Src/FEMTree.inl index 61e9b6e8..2459522d 100644 --- a/Src/FEMTree.inl +++ b/Src/FEMTree.inl @@ -802,12 +802,7 @@ void FEMTree< Dim , Real >::updateDensityEstimator( typename FEMTree< Dim , Real PointSupportKey< IsotropicUIntPack< Dim , DensityDegree > > densityKey; densityKey.set( maxSplatDepth ); -#ifdef SANITIZED_PR - std::vector< std::atomic< node_index_type > > sampleMap( nodeCount() ); - ThreadPool::Parallel_for( 0 , sampleMap.size() , [&]( unsigned int , size_t i ){ sampleMap[i] = (node_index_type)-1; } ); -#else // !SANITIZED_PR std::vector< node_index_type > sampleMap( nodeCount() , -1 ); -#endif // SANITIZED_PR // Initialize the map from node indices to samples ThreadPool::Parallel_for( 0 , samples.size() , [&]( unsigned int , size_t i ){ if( samples[i].sample.weight>0 ) sampleMap[ samples[i].node->nodeData.nodeIndex ] = (node_index_type)i; } ); diff --git a/Src/MyAtomic.h b/Src/MyAtomic.h new file mode 100644 index 00000000..440a84ad --- /dev/null +++ b/Src/MyAtomic.h @@ -0,0 +1,281 @@ +/* +Copyright (c) 2017, 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 MY_ATOMIC_INCLUDED +#define MY_ATOMIC_INCLUDED + +#if defined( _WIN32 ) || defined( _WIN64 ) +#include +#include +#include +#else // !_WIN32 && !_WIN64 +#include +#include +#include +#endif // _WIN32 || _WIN64 + +namespace PoissonRecon +{ + template< typename Value > Value ReadAtomic32_( const volatile Value * value ); + template< typename Value > Value ReadAtomic64_( const volatile Value * value ); + + template< typename Value > Value SetAtomic32_( volatile Value * value , Value newValue ); + template< typename Value > Value SetAtomic64_( volatile Value * value , Value newValue ); + + template< typename Value > bool SetAtomic32_( volatile Value * value , Value newValue , Value oldValue ); + template< typename Value > bool SetAtomic64_( volatile Value * value , Value newValue , Value oldValue ); + + template< typename Value > void AddAtomic32_( volatile Value * a , Value b ); + template< typename Value > void AddAtomic64_( volatile Value * a , Value b ); + + template< typename Value > + Value SetAtomic( volatile Value & value , Value newValue ) + { + if constexpr( sizeof(Value)==4 ) return SetAtomic32_( &value , newValue ); + else if constexpr( sizeof(Value)==8 ) return SetAtomic64_( &value , newValue ); + else + { + WARN_ONCE( "should not use this function: " , sizeof(Value) ); + static std::mutex setAtomicMutex; + std::lock_guard< std::mutex > lock( setAtomicMutex ); + Value oldValue = *(Value*)&value; + *(Value*)&value = newValue; + return oldValue; + } + } + + template< typename Value > + bool SetAtomic( volatile Value & value , Value newValue , Value oldValue ) + { + if constexpr( sizeof(Value)==4 ) return SetAtomic32_( &value , newValue , oldValue ); + else if constexpr( sizeof(Value)==8 ) return SetAtomic64_( &value , newValue , oldValue ); + else + { + WARN_ONCE( "should not use this function: " , sizeof(Value) ); + static std::mutex setAtomicMutex; + std::lock_guard< std::mutex > lock( setAtomicMutex ); + if( value==oldValue ){ value = newValue ; return true; } + else return false; + } + } + + template< typename Value > + void AddAtomic( volatile Value & a , Value b ) + { + if constexpr( sizeof(Value)==4 ) return AddAtomic32_( &a , b ); + else if constexpr( sizeof(Value)==8 ) return AddAtomic64_( &a , b ); + else + { + WARN_ONCE( "should not use this function: " , sizeof(Value) ); + static std::mutex addAtomicMutex; + std::lock_guard< std::mutex > lock( addAtomicMutex ); + *(Value*)&a += b; + } + } + + template< typename Value > + Value ReadAtomic( const volatile Value & value ) + { + if constexpr( sizeof(Value)==4 ) return ReadAtomic32_( &value ); + else if constexpr( sizeof(Value)==8 ) return ReadAtomic64_( &value ); + else + { + WARN_ONCE( "should not use this function: " , sizeof(Value) ); + static std::mutex readAtomicMutex; + std::lock_guard< std::mutex > lock( readAtomicMutex ); + return *(Value*)&value; + } + } + + /////////////////////////////////////////////// + /////////////////////////////////////////////// + /////////////////////////////////////////////// + + template< typename Value > + Value ReadAtomic32_( const volatile Value * value ) + { +#if defined( _WIN32 ) || defined( _WIN64 ) + long _value = InterlockedExchangeAdd( (long*)value , 0 ); + return *(Value*)(&_value); +#else // !_WIN32 && !_WIN64 + uint32_t _value = __atomic_load_n( (uint32_t *)value , __ATOMIC_SEQ_CST ); +#endif // _WIN32 || _WIN64 + return *(Value*)(&_value); + } + + template< typename Value > + Value ReadAtomic64_( const volatile Value * value ) + { +#if defined( _WIN32 ) || defined( _WIN64 ) + __int64 _value = InterlockedExchangeAdd64( (__int64*)value , 0 ); +#else // !_WIN32 && !_WIN64 + uint64_t _value = __atomic_load_n( (uint64_t *)value , __ATOMIC_SEQ_CST ); +#endif // _WIN32 || _WIN64 + return *(Value*)(&_value); + } + + template< typename Value > + Value SetAtomic32_( volatile Value *value , Value newValue ) + { +#if defined( _WIN32 ) || defined( _WIN64 ) + long *_newValue = (long *)&newValue; + long oldValue = InterlockedExchange( (long*)value , *_newValue ); +#else // !_WIN32 && !_WIN64 + uint32_t *_newValue = (uint32_t *)&newValue; + long oldValue = __atomic_exchange_n( (uint32_t *)value , *_newValue , __ATOMIC_SEQ_CST ); +#endif // _WIN32 || _WIN64 + return *(Value*)&oldValue; + } + + template< typename Value > + Value SetAtomic64_( volatile Value * value , Value newValue ) + { +#if defined( _WIN32 ) || defined( _WIN64 ) + __int64 *_newValue = (__int64 *)&newValue; + __int64 oldValue = InterlockedExchange64( (__int64*)value , *_newValue ); +#else // !_WIN32 && !_WIN64 + uint64_t *_newValue = (uint64_t *)&newValue; + uint64_t oldValue = __atomic_exchange_n( (uint64_t *)value , *_newValue , __ATOMIC_SEQ_CST );; +#endif // _WIN32 || _WIN64 + return *(Value*)&oldValue; + } + + template< typename Value > + bool SetAtomic32_( volatile Value *value , Value newValue , Value oldValue ) + { +#if defined( _WIN32 ) || defined( _WIN64 ) + long *_oldValue = (long *)&oldValue; + long *_newValue = (long *)&newValue; + return InterlockedCompareExchange( (long*)value , *_newValue , *_oldValue )==*_oldValue; +#else // !_WIN32 && !_WIN64 + uint32_t *_newValue = (uint32_t *)&newValue; + return __atomic_compare_exchange_n( (uint32_t *)value , (uint32_t *)&oldValue , *_newValue , false , __ATOMIC_SEQ_CST , __ATOMIC_SEQ_CST ); +#endif // _WIN32 || _WIN64 + } + + template< typename Value > + bool SetAtomic64_( volatile Value * value , Value newValue , Value oldValue ) + { +#if defined( _WIN32 ) || defined( _WIN64 ) + __int64 *_oldValue = (__int64 *)&oldValue; + __int64 *_newValue = (__int64 *)&newValue; + return InterlockedCompareExchange64( (__int64*)value , *_newValue , *_oldValue )==*_oldValue; +#else // !_WIN32 && !_WIN64 + uint64_t *_newValue = (uint64_t *)&newValue; + return __atomic_compare_exchange_n( (uint64_t *)value , (uint64_t *)&oldValue , *_newValue , false , __ATOMIC_SEQ_CST , __ATOMIC_SEQ_CST ); +#endif // _WIN32 || _WIN64 + } + + template< typename Value > + void AddAtomic32_( volatile Value *a , Value b ) + { +#ifdef SANITIZED_PR + Value current = ReadAtomic32_( a ); +#else // !SANITIZED_PR + Value current = *a; +#endif // SANITIZED_PR + Value sum = current+b; +#if defined( _WIN32 ) || defined( _WIN64 ) + long *_current = (long *)¤t; + long *_sum = (long *)∑ +#ifdef SANITIZED_PR + while( InterlockedCompareExchange( (long*)a , *_sum , *_current )!=*_current ) + { + current = ReadAtomic32_( a ); + sum = current + b; + } +#else // !SANITIZED_PR + while( InterlockedCompareExchange( (long*)a , *_sum , *_current )!=*_current ) current = *(Value*)a , sum = *(Value*)a+b; +#endif // SANITIZED_PR +#else // !_WIN32 && !_WIN64 + uint32_t *_current = (uint32_t *)¤t; + uint32_t *_sum = (uint32_t *)∑ +#ifdef SANITIZED_PR + while( __sync_val_compare_and_swap( (uint32_t *)a , *_current , *_sum )!=*_current ) + { + current = ReadAtomic32_( a ); + sum = current+b; + } +#else // !SANITIZED_PR + while( __sync_val_compare_and_swap( (uint32_t *)a , *_current , *_sum )!=*_current ) current = *(Value*)a , sum = *(Value*)a+b; +#endif // SANITIZED_PR +#endif // _WIN32 || _WIN64 + } + + template< typename Value > + void AddAtomic64_( volatile Value * a , Value b ) + { +#if 1 +#ifdef SANITIZED_PR + Value current = ReadAtomic64_( a ); + Value sum = current+b; + while( !SetAtomic64_( a , sum , current ) ) + { + current = ReadAtomic64_( a ); + sum = current+b; + } +#else // !SANITIZED_PR + Value current = *a; + Value sum = current+b; + while( !SetAtomic64_( a , sum , current ) ) current = *(Value*)a , sum = *(Value*)a+b; +#endif // SANITIZED_PR +#else +#ifdef SANITIZED_PR + Value current = ReadAtomic64_( a ); +#else // !SANITIZED_PR + Value current = a; +#endif // SANITIZED_PR + Value sum = current+b; +#if defined( _WIN32 ) || defined( _WIN64 ) + __int64 *_current = (__int64 *)¤t; + __int64 *_sum = (__int64 *)∑ +#ifdef SANITIZED_PR + while( InterlockedCompareExchange64( (__int64*)a , *_sum , *_current )!=*_current ) + { + current = ReadAtomic64_( a ); + sum = current+b; + } +#else // !SANITIZED_PR + while( InterlockedCompareExchange64( (__int64*)a , *_sum , *_current )!=*_current ) current = *(Value*)a , sum = a+b; +#endif // SANITIZED_PR +#else // !_WIN32 && !_WIN64 + uint64_t *_current = (uint64_t *)¤t; + uint64_t *_sum = (uint64_t *)∑ +#ifdef SANITIZED_PR + while( __sync_val_compare_and_swap( (uint64_t *)a , *_current , *_sum )!=*_current ) + { + current = ReadAtomic64_( a); + sum = current+b; + } +#else // !SANITIZED_PR + while( __sync_val_compare_and_swap( (uint64_t *)a , *_current , *_sum )!=*_current ) current = *(Value*)a , sum = a+b; +#endif // SANITIZED_PR +#endif // _WIN32 || _WIN64 +#endif + } +} +#endif // MY_ATOMIC_INCLUDED diff --git a/Src/MyMiscellany.h b/Src/MyMiscellany.h index bf51921d..2bd92c0f 100644 --- a/Src/MyMiscellany.h +++ b/Src/MyMiscellany.h @@ -73,6 +73,7 @@ DAMAGE. #include #endif // _OPENMP #include "Array.h" +#include "MyAtomic.h" namespace PoissonRecon { @@ -163,9 +164,6 @@ namespace PoissonRecon } #endif // _WIN32 || _WIN64 - template< typename Value > bool SetAtomic( volatile Value *value , Value newValue , Value oldValue ); - template< typename Data > void AddAtomic( Data& a , Data b ); - //////////////////// // MKThread Stuff // //////////////////// @@ -176,10 +174,7 @@ namespace PoissonRecon #ifdef _OPENMP OPEN_MP , #endif // _OPENMP -#ifdef SANITIZED_PR -#else // !SANITIZED_PR THREAD_POOL , -#endif // SANITIZED_PR ASYNC , NONE }; @@ -219,24 +214,28 @@ namespace PoissonRecon return; } - auto _ChunkFunction = [ &iterationFunction , begin , end , chunkSize ]( unsigned int thread , size_t chunk ) + std::function< void (unsigned int , size_t ) > _ChunkFunction = [ &iterationFunction , begin , end , chunkSize ]( unsigned int thread , size_t chunk ) { const size_t _begin = begin + chunkSize*chunk; const size_t _end = std::min< size_t >( end , _begin+chunkSize ); for( size_t i=_begin ; i<_end ; i++ ) iterationFunction( thread , i ); }; - auto _StaticThreadFunction = [ &_ChunkFunction , chunks , threads ]( unsigned int thread ) + std::function< void (unsigned int ) > _StaticThreadFunction = [ &_ChunkFunction , chunks , threads ]( unsigned int thread ) { for( size_t chunk=thread ; chunk _DynamicThreadFunction = [ &_ChunkFunction , chunks , &index ]( unsigned int thread ) { size_t chunk; while( ( chunk=index.fetch_add(1) ) lock( _Mutex ); + + if ( schedule==STATIC ) _ThreadFunction = _StaticThreadFunction; + else if( schedule==DYNAMIC ) _ThreadFunction = _DynamicThreadFunction; + } if( false ){} #ifdef _OPENMP @@ -258,18 +257,23 @@ namespace PoissonRecon _ThreadFunction( 0 ); for( unsigned int t=1 ; t lock( _Mutex ); @@ -277,7 +281,6 @@ namespace PoissonRecon } } } -#endif // SANITIZED_PR } static unsigned int NumThreads( void ){ return (unsigned int)_Threads.size()+1; } @@ -294,15 +297,12 @@ namespace PoissonRecon _Close = true; numThreads--; _Threads.resize( numThreads ); -#ifdef SANITIZED_PR -#else // !SANITIZED_PR if( _ParallelType==THREAD_POOL ) { _RemainingTasks = 0; _Close = false; for( unsigned int t=0 ; tThreadPool::ScheduleNames = { "static" , "dynamic" }; - template< typename Value > - Value ReadAtomic32( const volatile Value * value ) - { -#if defined( _WIN32 ) || defined( _WIN64 ) - long _value = InterlockedExchangeAdd( (long*)value , 0 ); - return *(Value*)(&_value); -#else // !_WIN32 && !_WIN64 - uint32_t _value = __atomic_load_n( (uint32_t *)value , __ATOMIC_SEQ_CST ); -#endif // _WIN32 || _WIN64 - return *(Value*)(&_value); - } - - template< typename Value > - Value ReadAtomic64( const volatile Value * value ) - { -#if defined( _WIN32 ) || defined( _WIN64 ) - __int64 _value = InterlockedExchangeAdd64( (__int64*)value , 0 ); -#else // !_WIN32 && !_WIN64 - uint64_t _value = __atomic_load_n( (uint64_t *)value , __ATOMIC_SEQ_CST ); -#endif // _WIN32 || _WIN64 - return *(Value*)(&_value); - } - - template< typename Value > - bool SetAtomic32( volatile Value *value , Value newValue , Value oldValue ) - { -#if defined( _WIN32 ) || defined( _WIN64 ) - long *_oldValue = (long *)&oldValue; - long *_newValue = (long *)&newValue; - return InterlockedCompareExchange( (long*)value , *_newValue , *_oldValue )==*_oldValue; -#else // !_WIN32 && !_WIN64 - uint32_t *_newValue = (uint32_t *)&newValue; - return __atomic_compare_exchange_n( (uint32_t *)value , (uint32_t *)&oldValue , *_newValue , false , __ATOMIC_SEQ_CST , __ATOMIC_SEQ_CST ); -#endif // _WIN32 || _WIN64 - } - template< typename Value > - bool SetAtomic64( volatile Value *value , Value newValue , Value oldValue ) - { -#if defined( _WIN32 ) || defined( _WIN64 ) - __int64 *_oldValue = (__int64 *)&oldValue; - __int64 *_newValue = (__int64 *)&newValue; - return InterlockedCompareExchange64( (__int64*)value , *_newValue , *_oldValue )==*_oldValue; -#else // !_WIN32 && !_WIN64 - uint64_t *_newValue = (uint64_t *)&newValue; - return __atomic_compare_exchange_n( (uint64_t *)value , (uint64_t *)&oldValue , *_newValue , false , __ATOMIC_SEQ_CST , __ATOMIC_SEQ_CST ); -#endif // _WIN32 || _WIN64 - } - - template< typename Number > - void AddAtomic32( volatile Number &a , Number b ) - { -#ifdef SANITIZED_PR - Number current = ReadAtomic32( &a ); -#else // !SANITIZED_PR - Number current = a; -#endif // SANITIZED_PR - Number sum = current+b; -#if defined( _WIN32 ) || defined( _WIN64 ) - long *_current = (long *)¤t; - long *_sum = (long *)∑ -#ifdef SANITIZED_PR - while( InterlockedCompareExchange( (long*)&a , *_sum , *_current )!=*_current ) - { - current = ReadAtomic32( &a ); - sum = current + b; - } -#else // !SANITIZED_PR - while( InterlockedCompareExchange( (long*)&a , *_sum , *_current )!=*_current ) current = a , sum = a+b; -#endif // SANITIZED_PR -#else // !_WIN32 && !_WIN64 - uint32_t *_current = (uint32_t *)¤t; - uint32_t *_sum = (uint32_t *)∑ -#ifdef SANITIZED_PR - while( __sync_val_compare_and_swap( (uint32_t *)&a , *_current , *_sum )!=*_current ) - { - current = ReadAtomic32( &a ); - sum = current+b; - } -#else // !SANITIZED_PR - while( __sync_val_compare_and_swap( (uint32_t *)&a , *_current , *_sum )!=*_current ) current = a , sum = a+b; -#endif // SANITIZED_PR -#endif // _WIN32 || _WIN64 - } - - template< typename Number > - void AddAtomic64( volatile Number &a , Number b ) - { -#if 1 -#ifdef SANITIZED_PR - Number current = ReadAtomic64( &a ); - Number sum = current+b; - while( !SetAtomic64( &a , sum , current ) ) - { - current = ReadAtomic64( &a ); - sum = current+b; - } -#else // !SANITIZED_PR - Number current = a; - Number sum = current+b; - while( !SetAtomic64( &a , sum , current ) ) current = a , sum = a+b; -#endif // SANITIZED_PR -#else -#ifdef SANITIZED_PR - Number current = ReadAtomic64( &a ); -#else // !SANITIZED_PR - Number current = a; -#endif // SANITIZED_PR - Number sum = current+b; -#if defined( _WIN32 ) || defined( _WIN64 ) - __int64 *_current = (__int64 *)¤t; - __int64 *_sum = (__int64 *)∑ -#ifdef SANITIZED_PR - while( InterlockedCompareExchange64( (__int64*)&a , *_sum , *_current )!=*_current ) - { - current = ReadAtomic64( &a ); - sum = current+b; - } -#else // !SANITIZED_PR - while( InterlockedCompareExchange64( (__int64*)&a , *_sum , *_current )!=*_current ) current = a , sum = a+b; -#endif // SANITIZED_PR -#else // !_WIN32 && !_WIN64 - uint64_t *_current = (uint64_t *)¤t; - uint64_t *_sum = (uint64_t *)∑ -#ifdef SANITIZED_PR - while( __sync_val_compare_and_swap( (uint64_t *)&a , *_current , *_sum )!=*_current ) - { - current = ReadAtomic64( &a); - sum = current+b; - } -#else // !SANITIZED_PR - while( __sync_val_compare_and_swap( (uint64_t *)&a , *_current , *_sum )!=*_current ) current = a , sum = a+b; -#endif // SANITIZED_PR -#endif // _WIN32 || _WIN64 -#endif - } - - template< typename Value > - bool SetAtomic( volatile Value *value , Value newValue , Value oldValue ) - { - switch( sizeof(Value) ) - { - case 4: return SetAtomic32( value , newValue , oldValue ); - case 8: return SetAtomic64( value , newValue , oldValue ); - default: - WARN_ONCE( "should not use this function: " , sizeof(Value) ); - static std::mutex setAtomicMutex; - std::lock_guard< std::mutex > lock( setAtomicMutex ); - if( *value==oldValue ){ *value = newValue ; return true; } - else return false; - } - } - - template< typename Data > - void AddAtomic( Data& a , Data b ) - { - switch( sizeof(Data) ) - { - case 4: return AddAtomic32( a , b ); - case 8: return AddAtomic64( a , b ); - default: - WARN_ONCE( "should not use this function: " , sizeof(Data) ); - static std::mutex addAtomicMutex; - std::lock_guard< std::mutex > lock( addAtomicMutex ); - a += b; - } - } - - template< typename Value > - Value ReadAtomic( const volatile Value * value ) - { - if constexpr( sizeof(Value)==4 ) return ReadAtomic32( value ); - else if constexpr( sizeof(Value)==8 ) return ReadAtomic64( value ); - else - { - WARN_ONCE( "should not use this function: " , sizeof(Value) ); - static std::mutex readAtomicMutex; - std::lock_guard< std::mutex > lock( readAtomicMutex ); - return *value; - } - } ////////////////// // Memory Stuff // diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 7bd43f9d..9d0e6e96 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -46,7 +46,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "18.03" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "18.04" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth diff --git a/Src/RegularTree.inl b/Src/RegularTree.inl index c85bb4eb..ba002492 100644 --- a/Src/RegularTree.inl +++ b/Src/RegularTree.inl @@ -155,7 +155,7 @@ bool RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::_initChildren_s( Al } // If we are the first to set the child, initialize - if( SetAtomic( &children , _children , (RegularTreeNode *)NULL ) ) return true; + if( SetAtomic( children , _children , (RegularTreeNode *)NULL ) ) return true; // Otherwise clean up else { @@ -664,11 +664,11 @@ unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey if( pNeighbors[pi] ) { #ifdef SANITIZED_PR - RegularTreeNode * children = ReadAtomic( &(pNeighbors[pi]->children) ); + RegularTreeNode * children = ReadAtomic( pNeighbors[pi]->children ); if( !children ) { pNeighbors[pi]->template initChildren< ThreadSafe >( nodeAllocator , initializer ); - children = ReadAtomic( &(pNeighbors[pi]->children) ); + children = ReadAtomic( pNeighbors[pi]->children ); } cNeighbors[ci] = children + ( cornerIndex | ( ( _i&1)<<(Dim-1) ) ); #else // !SANITIZED_PR From 4c8686344378f4870aba7fe697619f99908f5e4b Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Sun, 15 Sep 2024 22:39:44 -0400 Subject: [PATCH 41/86] Version18.04 --- AdaptiveSolvers.sln | 1 + Src/MultiThreading.h | 387 +++++++++++++++++++++++++++++++++++++++++++ Src/MyAtomic.h | 1 + Src/MyMiscellany.h | 234 +------------------------- Src/Reconstructors.h | 9 +- 5 files changed, 395 insertions(+), 237 deletions(-) create mode 100644 Src/MultiThreading.h diff --git a/AdaptiveSolvers.sln b/AdaptiveSolvers.sln index 1247503d..db281a22 100644 --- a/AdaptiveSolvers.sln +++ b/AdaptiveSolvers.sln @@ -59,6 +59,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Header Files", "Header File Src\MarchingCubes.h = Src\MarchingCubes.h Src\MAT.h = Src\MAT.h Src\MergePlyClientServer.h = Src\MergePlyClientServer.h + Src\MultiThreading.h = Src\MultiThreading.h Src\MyAtomic.h = Src\MyAtomic.h Src\MyExceptions.h = Src\MyExceptions.h Src\MyMiscellany.h = Src\MyMiscellany.h diff --git a/Src/MultiThreading.h b/Src/MultiThreading.h new file mode 100644 index 00000000..90575a2e --- /dev/null +++ b/Src/MultiThreading.h @@ -0,0 +1,387 @@ +/* +Copyright (c) 2017, 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 MULTI_THREADING_INCLUDED +#define MULTI_THREADING_INCLUDED + +#include +#include +#if defined( _WIN32 ) || defined( _WIN64 ) +#include +#include +#include +#else // !_WIN32 && !_WIN64 +#include +#include +#include +#endif // _WIN32 || _WIN64 +#include +#include +#include +#include +#include +#include +#ifdef _OPENMP +#include +#endif // _OPENMP +#include "Array.h" +#include "MyAtomic.h" + +namespace PoissonRecon +{ +#ifdef USE_HH_THREADS + namespace hh + { + inline int get_max_threads( void ) { return std::max< int >( (int)std::thread::hardware_concurrency() , 1 ); } + + class ThreadPoolIndexedTask + { + public: + using Task = std::function< void (int) >; + ThreadPoolIndexedTask( void ) + { + const int num_threads = get_max_threads()-1; + _threads.reserve( num_threads ); + for( int i=0 ; i lock( _mutex ); + if( !_running ) ERROR_OUT( "not running" ); + if( _num_remaining_tasks ) ERROR_OUT( "tasks remaining" ); + if( _task_index!=_num_tasks ) ERROR_OUT( "task index and num tasks don't match" ); + _running = false; + _task_index = 0; + _num_tasks = 1; + _condition_variable_worker.notify_all(); + } + for( int i=0 ; i<_threads.size() ; i++ ) _threads[i].join(); + } + int num_threads( void ) const { return (int)_threads.size()+1; } + bool already_active( void ) const { return _num_remaining_tasks!=0; } // detect nested execution + void execute( int num_tasks , const Task& task_function ) + { + if( already_active() ) + { + WARN( "Nested execution of ThreadPoolIndexedTask is run serially" ); + for( int i=0 ; i lock( _mutex ); + _task_function = task_function; + _num_tasks = num_tasks; + _num_remaining_tasks = num_tasks; + _task_index = 0; + _condition_variable_worker.notify_all(); + _condition_variable_master.wait( lock , [this]{ return !_num_remaining_tasks; } ); + } + } + static ThreadPoolIndexedTask& default_threadpool( void ) + { + static std::unique_ptr< ThreadPoolIndexedTask > thread_pool; + // This is safe because thread_pool is nullptr only in the main thread before any other thread is launched. + if( !thread_pool ) thread_pool = std::unique_ptr< ThreadPoolIndexedTask >( new ThreadPoolIndexedTask() ); + return *thread_pool; + } + + private: + std::mutex _mutex; + bool _running = true; + std::vector< std::thread > _threads; + Task _task_function; + int _num_tasks = 0; + int _num_remaining_tasks = 0; + int _task_index = 0; + std::condition_variable _condition_variable_worker; + std::condition_variable _condition_variable_master; + + void worker_main( void ) + { + std::unique_lock< std::mutex > lock( _mutex ); + // Consider: https://stackoverflow.com/questions/233127/how-can-i-propagate-exceptions-between-threads + // However, rethrowing the exception in the main thread loses the stack state, so not useful for debugging. + for (;;) + { + _condition_variable_worker.wait( lock , [this]{ return _task_index < _num_tasks; } ); + if( !_running ) break; + while( _task_index<_num_tasks ) + { + int i = _task_index++; + lock.unlock(); + _task_function(i); + lock.lock(); + if( _num_remaining_tasks<=0 ) ERROR_OUT( "num remaining tasks not greater than zero" ); + if (!--_num_remaining_tasks) _condition_variable_master.notify_all(); + } + } + } + }; + } +#endif // USE_HH_THREADS + + struct ThreadPool + { + enum ParallelType + { +#ifdef _OPENMP + OPEN_MP , +#endif // _OPENMP + THREAD_POOL , +#ifdef USE_HH_THREADS + THREAD_POOL_HH , +#endif // USE_HH_THREADS + ASYNC , + NONE + }; + static const std::vector< std::string > ParallelNames; + + enum ScheduleType + { + STATIC , + DYNAMIC + }; + static const std::vector< std::string > ScheduleNames; + + static size_t DefaultChunkSize; + static ScheduleType DefaultSchedule; + + template< typename ... Functions > + static void ParallelSections( const Functions & ... functions ) + { + std::vector< std::future< void > > futures( sizeof...(Functions) ); + _ParallelSections( &futures[0] , functions ... ); + for( size_t t=0 ; t &iterationFunction , ScheduleType schedule=DefaultSchedule , size_t chunkSize=DefaultChunkSize ) + { + if( begin>=end ) return; + size_t range = end - begin; + size_t chunks = ( range + chunkSize - 1 ) / chunkSize; + unsigned int threads = (unsigned int)NumThreads(); + std::atomic< size_t > index; + index.store( 0 ); + + + if( range _ChunkFunction = [ &iterationFunction , begin , end , chunkSize ]( unsigned int thread , size_t chunk ) + { + const size_t _begin = begin + chunkSize*chunk; + const size_t _end = std::min< size_t >( end , _begin+chunkSize ); + for( size_t i=_begin ; i<_end ; i++ ) iterationFunction( thread , i ); + }; + std::function< void (unsigned int ) > _StaticThreadFunction = [ &_ChunkFunction , chunks , threads ]( unsigned int thread ) + { + for( size_t chunk=thread ; chunk _DynamicThreadFunction = [ &_ChunkFunction , chunks , &index ]( unsigned int thread ) + { + size_t chunk; + while( ( chunk=index.fetch_add(1) ) lock( _Mutex ); + + if ( schedule==STATIC ) _ThreadFunction = _StaticThreadFunction; + else if( schedule==DYNAMIC ) _ThreadFunction = _DynamicThreadFunction; + } + + if( false ){} +#ifdef _OPENMP + else if( _ParallelType==OPEN_MP ) + { + if( schedule==STATIC ) +#pragma omp parallel for num_threads( threads ) schedule( static , 1 ) + for( int c=0 ; c( threads , range ); + hh::ThreadPoolIndexedTask* const thread_pool = &hh::ThreadPoolIndexedTask::default_threadpool(); + if( !thread_pool || thread_pool->already_active() ) + { + // Traverse the range elements sequentially. + for( size_t index=begin ; indexexecute( num_threads , _ThreadFunction ); + } +#endif // USE_HH_THREADS + else if( _ParallelType==ASYNC ) + { + static std::vector< std::future< void > > futures; + futures.resize( threads-1 ); + for( unsigned int t=1 ; t lock( _Mutex ); + _DoneWithWork.wait( lock , [&]( void ){ return _RemainingTasks==0; } ); + } + } + } + } + + static unsigned int NumThreads( void ){ return (unsigned int)_Threads.size()+1; } + + static void Init( ParallelType parallelType , unsigned int numThreads=std::thread::hardware_concurrency() ) + { + _ParallelType = parallelType; + if( _Threads.size() && !_Close ) + { + _Close = true; + _WaitingForWorkOrClose.notify_all(); + for( unsigned int t=0 ; t<_Threads.size() ; t++ ) _Threads[t].join(); + } + _Close = true; + numThreads--; + _Threads.resize( numThreads ); + if( _ParallelType==THREAD_POOL ) + { + _RemainingTasks = 0; + _Close = false; + for( unsigned int t=0 ; t + static void _ParallelSections( std::future< void > *futures , const Function &function ){ *futures = std::async( std::launch::async , function ); } + template< typename Function , typename ... Functions > + static void _ParallelSections( std::future< void > *futures , const Function &function , const Functions& ... functions ) + { + *futures = std::async( std::launch::async , function ); + _ParallelSections( futures+1 , functions ... ); + } + static void _ThreadInitFunction( unsigned int thread ) + { + // Wait for the first job to come in + std::unique_lock< std::mutex > lock( _Mutex ); + _WaitingForWorkOrClose.wait( lock ); + + while( !_Close ) + { + // do the job + _ThreadFunction( thread ); + + // Notify and wait for the next job + _RemainingTasks--; + if( !_RemainingTasks ) _DoneWithWork.notify_all(); + _WaitingForWorkOrClose.wait( lock ); + } + } + +#ifdef SANITIZED_PR + static std::atomic< bool > _Close; + static std::atomic< unsigned int > _RemainingTasks; +#else // !SANITIZED_PR + static bool _Close; + static volatile unsigned int _RemainingTasks; +#endif // SANITIZED_PR + static std::mutex _Mutex; + static std::condition_variable _WaitingForWorkOrClose , _DoneWithWork; + static std::vector< std::thread > _Threads; + static std::function< void ( unsigned int ) > _ThreadFunction; + static ParallelType _ParallelType; + }; + + size_t ThreadPool::DefaultChunkSize = 128; + ThreadPool::ScheduleType ThreadPool::DefaultSchedule = ThreadPool::DYNAMIC; +#ifdef SANITIZED_PR + std::atomic< bool > ThreadPool::_Close; + std::atomic< unsigned int > ThreadPool::_RemainingTasks; +#else // !SANITIZED_PR + bool ThreadPool::_Close; + volatile unsigned int ThreadPool::_RemainingTasks; +#endif // SANITIZED_PR + std::mutex ThreadPool::_Mutex; + std::condition_variable ThreadPool::_WaitingForWorkOrClose; + std::condition_variable ThreadPool::_DoneWithWork; + std::vector< std::thread > ThreadPool::_Threads; + std::function< void ( unsigned int ) > ThreadPool::_ThreadFunction; + ThreadPool::ParallelType ThreadPool::_ParallelType; + + const std::vector< std::string > ThreadPool::ParallelNames = + { +#ifdef _OPENMP + "open mp" , +#endif // _OPENMP + "thread pool" , +#ifdef USE_HH_THREADS + "thread pool (hh)" , +#endif // USE_HH_THREADS + "async" , + "none" + }; + const std::vector< std::string > ThreadPool::ScheduleNames = { "static" , "dynamic" }; +} +#endif // MULTI_THREADING_INCLUDED diff --git a/Src/MyAtomic.h b/Src/MyAtomic.h index 440a84ad..578c540f 100644 --- a/Src/MyAtomic.h +++ b/Src/MyAtomic.h @@ -37,6 +37,7 @@ DAMAGE. #include #include #endif // _WIN32 || _WIN64 +#include namespace PoissonRecon { diff --git a/Src/MyMiscellany.h b/Src/MyMiscellany.h index 2bd92c0f..007285b8 100644 --- a/Src/MyMiscellany.h +++ b/Src/MyMiscellany.h @@ -31,7 +31,6 @@ DAMAGE. #include #include #include -#include #include #include #include @@ -46,15 +45,7 @@ DAMAGE. #include #include #endif // _WIN32 || _WIN64 -#include -#include -#include -#include -#include -#include -#include #include -#include #if defined(_WIN32) || defined( _WIN64 ) #elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) #if defined(__APPLE__) && defined(__MACH__) @@ -69,11 +60,9 @@ DAMAGE. #else #error "Cannot define getPeakRSS( ) or getCurrentRSS( ) for an unknown OS." #endif -#ifdef _OPENMP -#include -#endif // _OPENMP #include "Array.h" #include "MyAtomic.h" +#include "MultiThreading.h" namespace PoissonRecon { @@ -164,227 +153,6 @@ namespace PoissonRecon } #endif // _WIN32 || _WIN64 - //////////////////// - // MKThread Stuff // - //////////////////// - struct ThreadPool - { - enum ParallelType - { -#ifdef _OPENMP - OPEN_MP , -#endif // _OPENMP - THREAD_POOL , - ASYNC , - NONE - }; - static const std::vector< std::string > ParallelNames; - - enum ScheduleType - { - STATIC , - DYNAMIC - }; - static const std::vector< std::string > ScheduleNames; - - static size_t DefaultChunkSize; - static ScheduleType DefaultSchedule; - - template< typename ... Functions > - static void ParallelSections( const Functions & ... functions ) - { - std::vector< std::future< void > > futures( sizeof...(Functions) ); - _ParallelSections( &futures[0] , functions ... ); - for( size_t t=0 ; t &iterationFunction , ScheduleType schedule=DefaultSchedule , size_t chunkSize=DefaultChunkSize ) - { - if( begin>=end ) return; - size_t range = end - begin; - size_t chunks = ( range + chunkSize - 1 ) / chunkSize; - unsigned int threads = (unsigned int)NumThreads(); - std::atomic< size_t > index; - index.store( 0 ); - - - if( range _ChunkFunction = [ &iterationFunction , begin , end , chunkSize ]( unsigned int thread , size_t chunk ) - { - const size_t _begin = begin + chunkSize*chunk; - const size_t _end = std::min< size_t >( end , _begin+chunkSize ); - for( size_t i=_begin ; i<_end ; i++ ) iterationFunction( thread , i ); - }; - std::function< void (unsigned int ) > _StaticThreadFunction = [ &_ChunkFunction , chunks , threads ]( unsigned int thread ) - { - for( size_t chunk=thread ; chunk _DynamicThreadFunction = [ &_ChunkFunction , chunks , &index ]( unsigned int thread ) - { - size_t chunk; - while( ( chunk=index.fetch_add(1) ) lock( _Mutex ); - - if ( schedule==STATIC ) _ThreadFunction = _StaticThreadFunction; - else if( schedule==DYNAMIC ) _ThreadFunction = _DynamicThreadFunction; - } - - if( false ){} -#ifdef _OPENMP - else if( _ParallelType==OPEN_MP ) - { - if( schedule==STATIC ) -#pragma omp parallel for num_threads( threads ) schedule( static , 1 ) - for( int c=0 ; c > futures; - futures.resize( threads-1 ); - for( unsigned int t=1 ; t lock( _Mutex ); - _DoneWithWork.wait( lock , [&]( void ){ return _RemainingTasks==0; } ); - } - } - } - } - - static unsigned int NumThreads( void ){ return (unsigned int)_Threads.size()+1; } - - static void Init( ParallelType parallelType , unsigned int numThreads=std::thread::hardware_concurrency() ) - { - _ParallelType = parallelType; - if( _Threads.size() && !_Close ) - { - _Close = true; - _WaitingForWorkOrClose.notify_all(); - for( unsigned int t=0 ; t<_Threads.size() ; t++ ) _Threads[t].join(); - } - _Close = true; - numThreads--; - _Threads.resize( numThreads ); - if( _ParallelType==THREAD_POOL ) - { - _RemainingTasks = 0; - _Close = false; - for( unsigned int t=0 ; t - static void _ParallelSections( std::future< void > *futures , const Function &function ){ *futures = std::async( std::launch::async , function ); } - template< typename Function , typename ... Functions > - static void _ParallelSections( std::future< void > *futures , const Function &function , const Functions& ... functions ) - { - *futures = std::async( std::launch::async , function ); - _ParallelSections( futures+1 , functions ... ); - } - static void _ThreadInitFunction( unsigned int thread ) - { - // Wait for the first job to come in - std::unique_lock< std::mutex > lock( _Mutex ); - _WaitingForWorkOrClose.wait( lock ); - while( !_Close ) - { - // do the job - _ThreadFunction( thread ); - - // Notify and wait for the next job - _RemainingTasks--; - if( !_RemainingTasks ) _DoneWithWork.notify_all(); - _WaitingForWorkOrClose.wait( lock ); - } - } - -#ifdef SANITIZED_PR - static std::atomic< bool > _Close; - static std::atomic< unsigned int > _RemainingTasks; -#else // !SANITIZED_PR - static bool _Close; - static volatile unsigned int _RemainingTasks; -#endif // SANITIZED_PR - static std::mutex _Mutex; - static std::condition_variable _WaitingForWorkOrClose , _DoneWithWork; - static std::vector< std::thread > _Threads; - static std::function< void ( unsigned int ) > _ThreadFunction; - static ParallelType _ParallelType; - }; - - size_t ThreadPool::DefaultChunkSize = 128; - ThreadPool::ScheduleType ThreadPool::DefaultSchedule = ThreadPool::DYNAMIC; -#ifdef SANITIZED_PR - std::atomic< bool > ThreadPool::_Close; - std::atomic< unsigned int > ThreadPool::_RemainingTasks; -#else // !SANITIZED_PR - bool ThreadPool::_Close; - volatile unsigned int ThreadPool::_RemainingTasks; -#endif // SANITIZED_PR - std::mutex ThreadPool::_Mutex; - std::condition_variable ThreadPool::_WaitingForWorkOrClose; - std::condition_variable ThreadPool::_DoneWithWork; - std::vector< std::thread > ThreadPool::_Threads; - std::function< void ( unsigned int ) > ThreadPool::_ThreadFunction; - ThreadPool::ParallelType ThreadPool::_ParallelType; - - const std::vector< std::string >ThreadPool::ParallelNames = - { -#ifdef _OPENMP - "open mp" , -#endif // _OPENMP - "thread pool" , - "async" , - "none" - }; - const std::vector< std::string >ThreadPool::ScheduleNames = { "static" , "dynamic" }; - - ////////////////// // Memory Stuff // ////////////////// diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h index 30972313..a4bc1e72 100644 --- a/Src/Reconstructors.h +++ b/Src/Reconstructors.h @@ -41,6 +41,7 @@ namespace PoissonRecon namespace Reconstructor { + unsigned int ProfilerMS = 20; // The number of ms at which to poll the performance (set to zero for no polling) static const unsigned int DataDegree = 0; // The order of the B-Spline used to splat in data for auxiliary data interpolation static const unsigned int WeightDegree = 2; // The order of the B-Spline used to splat in the weights for density estimation @@ -498,7 +499,7 @@ namespace PoissonRecon if constexpr( Dim==3 ) { - Profiler profiler(20); + Profiler profiler( ProfilerMS ); std::string statsString; @@ -525,7 +526,7 @@ namespace PoissonRecon } else if constexpr( Dim==2 ) { - Profiler profiler(20); + Profiler profiler( ProfilerMS ); std::string statsString; @@ -598,7 +599,7 @@ namespace PoissonRecon XForm< Real , Dim+1 > modelToUnitCube = XForm< Real , Dim+1 >::Identity(); - Profiler profiler(20); + Profiler profiler( ProfilerMS ); size_t pointCount; @@ -1069,7 +1070,7 @@ namespace PoissonRecon XForm< Real , Dim+1 > modelToUnitCube = XForm< Real , Dim+1 >::Identity(); - Profiler profiler(20); + Profiler profiler( ProfilerMS ); size_t pointCount; From 8412fd4808d834a239e2522a1962e7de1932a6e1 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Sun, 15 Sep 2024 23:20:01 -0400 Subject: [PATCH 42/86] Update MultiThreading.h --- Src/MultiThreading.h | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/Src/MultiThreading.h b/Src/MultiThreading.h index 90575a2e..6a33ec21 100644 --- a/Src/MultiThreading.h +++ b/Src/MultiThreading.h @@ -172,12 +172,17 @@ namespace PoissonRecon static size_t DefaultChunkSize; static ScheduleType DefaultSchedule; - template< typename ... Functions > - static void ParallelSections( const Functions & ... functions ) + template< typename Function , typename ... Functions > + static void ParallelSections( const Function &function , const Functions & ... functions ) { - std::vector< std::future< void > > futures( sizeof...(Functions) ); - _ParallelSections( &futures[0] , functions ... ); - for( size_t t=0 ; t > futures; + if constexpr( sizeof ... (Functions) ) + { + futures.reserve( sizeof...(Functions) ); + _ParallelSections( futures , functions... ); + } + function(); + for( unsigned int i=0 ; i &iterationFunction , ScheduleType schedule=DefaultSchedule , size_t chunkSize=DefaultChunkSize ) @@ -189,7 +194,6 @@ namespace PoissonRecon std::atomic< size_t > index; index.store( 0 ); - if( range - static void _ParallelSections( std::future< void > *futures , const Function &function ){ *futures = std::async( std::launch::async , function ); } template< typename Function , typename ... Functions > - static void _ParallelSections( std::future< void > *futures , const Function &function , const Functions& ... functions ) + static void _ParallelSections( std::vector< std::future< void > > &futures , const Function &function , const Functions & ... functions ) { - *futures = std::async( std::launch::async , function ); - _ParallelSections( futures+1 , functions ... ); + futures.push_back( std::async( std::launch::async , function ) ); + if constexpr( sizeof...(Functions) ) _ParallelSections( futures , functions... ); } + static void _ThreadInitFunction( unsigned int thread ) { // Wait for the first job to come in From eaff5e54d63ba9833d1118abdacd7e35b7693f54 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Mon, 16 Sep 2024 12:59:58 -0400 Subject: [PATCH 43/86] Version 18.04 --- Makefile | 1 + Src/AdaptiveTreeVisualization.cpp | 28 ++- Src/EDTInHeat.cpp | 26 ++- Src/FEMTree.Evaluation.inl | 16 +- Src/FEMTree.Initialize.inl | 18 +- Src/FEMTree.LevelSet.2D.inl | 12 +- Src/FEMTree.LevelSet.3D.inl | 20 +-- Src/FEMTree.LevelSet.inl | 12 +- Src/FEMTree.System.inl | 98 +++++------ Src/FEMTree.inl | 44 ++--- Src/ImageStitching.cpp | 21 +-- Src/MultiThreading.h | 282 +++--------------------------- Src/PointInterpolant.cpp | 25 ++- Src/PoissonRecon.client.inl | 6 +- Src/PoissonRecon.cpp | 16 +- Src/PoissonReconClient.cpp | 16 +- Src/PoissonReconServer.cpp | 19 +- Src/Rasterizer.inl | 6 +- Src/Reconstruction.example.cpp | 3 +- Src/Reconstructors.h | 14 +- Src/SSDRecon.cpp | 22 +-- Src/SparseMatrix.inl | 20 +-- Src/SparseMatrixInterface.inl | 44 ++--- Src/Window.inl | 30 ++-- 24 files changed, 268 insertions(+), 531 deletions(-) diff --git a/Makefile b/Makefile index 22458b08..5758d413 100644 --- a/Makefile +++ b/Makefile @@ -37,6 +37,7 @@ else # CFLAGS += -fopenmp=libiomp5 -Wno-deprecated -Wno-write-strings -std=c++17 -Wno-invalid-offsetof # LFLAGS += -liomp5 -lstdc++ CFLAGS += -Wno-deprecated -std=c++17 -pthread -Wno-invalid-offsetof -Wno-dangling-else + CFLAGS += -Wno-nan-infinity-disabled LFLAGS += -lstdc++ endif LFLAGS_IMG += -lz -lpng -ljpeg diff --git a/Src/AdaptiveTreeVisualization.cpp b/Src/AdaptiveTreeVisualization.cpp index f5cdf131..3713ed59 100644 --- a/Src/AdaptiveTreeVisualization.cpp +++ b/Src/AdaptiveTreeVisualization.cpp @@ -64,9 +64,8 @@ CmdLineReadable CmdLineParameter< int > ParallelType( "parallel" , 0 ) , - ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , - ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , - Threads( "threads" , (int)std::thread::hardware_concurrency() ) , + ScheduleType( "schedule" , (int)ThreadPool::Schedule ) , + ThreadChunkSize( "chunkSize" , (int)ThreadPool::ChunkSize ) , IsoSlabDepth( "sDepth" , 0 ) , IsoSlabStart( "sStart" , 0 ) , IsoSlabEnd ( "sEnd" , 1 ) , @@ -86,7 +85,6 @@ CmdLineReadable* params[] = &OutMesh , &NonManifold , &PolygonMesh , &FlipOrientation , &ASCII , &NonLinearFit , &IsoValue , &OutGrid , &PrimalGrid , &OutTree , &TreeScale , &TreeDepth , - &Threads , &Verbose , &ParallelType , &ScheduleType , @@ -106,7 +104,6 @@ void ShowUsage( char* ex ) printf( "\t[--%s ]\n" , OutTree.name ); printf( "\t[--%s =%d]\n" , TreeScale.name , TreeScale.value ); printf( "\t[--%s =%d]\n" , TreeDepth.name , TreeDepth.value ); - printf( "\t[--%s =%d]\n" , Threads.name , Threads.value ); printf( "\t[--%s =%d]\n" , ParallelType.name , ParallelType.value ); for( size_t i=0 ; i=%d]\n" , ScheduleType.name , ScheduleType.value ); @@ -141,14 +138,14 @@ void WriteGrid( const char *fileName , ConstPointer( Real ) values , unsigned in // Compute average Real avg = 0; std::vector< Real > avgs( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , totalResolution , [&]( unsigned int thread , size_t i ){ avgs[thread] += values[i]; } ); + ThreadPool::ParallelFor( 0 , totalResolution , [&]( unsigned int thread , size_t i ){ avgs[thread] += values[i]; } ); for( unsigned int t=0 ; t stds( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , totalResolution , [&]( unsigned int thread , size_t i ){ stds[thread] += ( values[i] - avg ) * ( values[i] - avg ); } ); + ThreadPool::ParallelFor( 0 , totalResolution , [&]( unsigned int thread , size_t i ){ stds[thread] += ( values[i] - avg ) * ( values[i] - avg ); } ); for( unsigned int t=0 ; t( (Real)1. , std::max< Real >( (Real)-1. , ( values[i] - avg ) / (2*std ) ) ); v = (Real)( ( v + 1. ) / 2. * 256. ); @@ -198,7 +195,7 @@ void WriteGrid( const char *fileName , ConstPointer( Real ) values , unsigned in template< unsigned int Dim , class Real , unsigned int FEMSig > void _Execute( const FEMTree< Dim , Real > *tree , XForm< Real , Dim+1 > modelToUnitCube , BinaryStream &stream ) { - ThreadPool::Init( (ThreadPool::ParallelType)ParallelType.value , Threads.value ); + ThreadPool::ParallelizationType= (ThreadPool::ParallelType)ParallelType.value; static const unsigned int Degree = FEMSignature< FEMSig >::Degree; DenseNodeData< Real , IsotropicUIntPack< Dim , FEMSig > > coefficients; @@ -227,7 +224,7 @@ void _Execute( const FEMTree< Dim , Real > *tree , XForm< Real , Dim+1 > modelTo }; while( ( pointsRead=ReadBatch() ) ) { - ThreadPool::Parallel_for( 0 , pointsRead , [&]( unsigned int thread , size_t j ) + ThreadPool::ParallelFor( 0 , pointsRead , [&]( unsigned int thread , size_t j ) { Point< Real , Dim > p = modelToUnitCube * points[j]; bool inBounds = true; @@ -260,11 +257,11 @@ void _Execute( const FEMTree< Dim , Real > *tree , XForm< Real , Dim+1 > modelTo if( OutTree.set ) { DenseNodeData< Real , IsotropicUIntPack< Dim , FEMTrivialSignature > > _coefficients = tree->initDenseNodeData( IsotropicUIntPack< Dim , FEMTrivialSignature >() ); - ThreadPool::Parallel_for( 0 , _coefficients.size() , [&]( unsigned int , size_t i ){ _coefficients[i] = 0; } ); + ThreadPool::ParallelFor( 0 , _coefficients.size() , [&]( unsigned int , size_t i ){ _coefficients[i] = 0; } ); if( TreeDepth.value!=-1 ) { - ThreadPool::Parallel_for + ThreadPool::ParallelFor ( tree->nodesBegin(TreeDepth.value) , tree->nodesEnd(TreeDepth.value) , [&]( unsigned int , size_t i ) @@ -276,7 +273,7 @@ void _Execute( const FEMTree< Dim , Real > *tree , XForm< Real , Dim+1 > modelTo } else { - ThreadPool::Parallel_for + ThreadPool::ParallelFor ( tree->nodesBegin(0) , tree->nodesEnd( tree->depth() ) , [&]( unsigned int , size_t i ) @@ -466,8 +463,8 @@ int main( int argc , char* argv[] ) WARN( "Array debugging enabled" ); #endif // ARRAY_DEBUG CmdLineParse( argc-1 , &argv[1] , params ); - ThreadPool::DefaultChunkSize = ThreadChunkSize.value; - ThreadPool::DefaultSchedule = (ThreadPool::ScheduleType)ScheduleType.value; + ThreadPool::ChunkSize = ThreadChunkSize.value; + ThreadPool::Schedule = (ThreadPool::ScheduleType)ScheduleType.value; if( Verbose.set ) { printf( "**************************************************\n" ); @@ -475,7 +472,6 @@ int main( int argc , char* argv[] ) printf( "** Running Octree Visualization (Version %s) **\n" , ADAPTIVE_SOLVERS_VERSION ); printf( "**************************************************\n" ); printf( "**************************************************\n" ); - if( !Threads.set ) printf( "Running with %d threads\n" , Threads.value ); } if( !In.set ) diff --git a/Src/EDTInHeat.cpp b/Src/EDTInHeat.cpp index 99f5b8b7..e6d9cc4d 100644 --- a/Src/EDTInHeat.cpp +++ b/Src/EDTInHeat.cpp @@ -69,9 +69,8 @@ CmdLineParameter< int > BaseVCycles( "baseVCycles" , 1 ) , MaxMemoryGB( "maxMemory" , 0 ) , ParallelType( "parallel" , 0 ) , - ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , - ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , - Threads( "threads" , (int)std::thread::hardware_concurrency() ); + ScheduleType( "schedule" , (int)ThreadPool::Schedule ) , + ThreadChunkSize( "chunkSize" , (int)ThreadPool::ChunkSize ); CmdLineParameter< float > Scale( "scale" , 2.f ) , @@ -90,7 +89,6 @@ CmdLineReadable* params[] = &Scale , &Verbose , &CGSolverAccuracy , &ShowResidual , &ValueWeight , &DiffusionTime , - &Threads , &FullDepth , &GSIterations , &WeightScale , &WeightExponent , @@ -122,9 +120,6 @@ void ShowUsage( char* ex ) printf( "\t[--%s =%.3e]\n" , ValueWeight.name , ValueWeight.value ); printf( "\t[--%s =%d]\n" , GSIterations.name , GSIterations.value ); printf( "\t[--%s]\n" , ExactInterpolation.name ); -#ifdef _OPENMP - printf( "\t[--%s =%d]\n" , Threads.name , Threads.value ); -#endif // _OPENMP printf( "\t[--%s =%g]\n" , CGSolverAccuracy.name , CGSolverAccuracy.value ); printf( "\t[--%s =%f]\n" , WeightScale.name , WeightScale.value ); printf( "\t[--%s =%f]\n" , WeightExponent.name , WeightExponent.value ); @@ -185,7 +180,7 @@ struct SystemDual< Dim , double > template< unsigned int Dim , class Real , unsigned int FEMSig > void _Execute( int argc , char* argv[] ) { - ThreadPool::Init( (ThreadPool::ParallelType)ParallelType.value , Threads.value ); + ThreadPool::ParallelizationType= (ThreadPool::ParallelType)ParallelType.value; static const unsigned int Degree = FEMSignature< FEMSig >::Degree; typedef typename FEMTree< Dim , Real >::template InterpolationInfo< Real , 0 > InterpolationInfo; typedef typename FEMTree< Dim , Real >::FEMTreeNode FEMTreeNode; @@ -197,7 +192,6 @@ void _Execute( int argc , char* argv[] ) std::cout << "** Running EDT in Heat (Version " << ADAPTIVE_SOLVERS_VERSION ") **" << std::endl; std::cout << "*****************************************" << std::endl; std::cout << "*****************************************" << std::endl; - if( !Threads.set ) std::cout << "Running with " << Threads.value << " threads" << std::endl; } XForm< Real , Dim+1 > modelToUnitCube , unitCubeToModel; @@ -285,7 +279,7 @@ void _Execute( int argc , char* argv[] ) double area = 0; std::vector< double > areas( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , triangles.size() , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( 0 , triangles.size() , [&]( unsigned int thread , size_t i ) { Simplex< Real , Dim , Dim-1 > s; for( int k=0 ; k > leafCenterValues = tree.initDenseNodeData( IsotropicUIntPack< Dim , FEMTrivialSignature >() ); - ThreadPool::Parallel_for( tree.nodesBegin(0) , tree.nodesEnd(Depth.value) , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( tree.nodesBegin(0) , tree.nodesEnd(Depth.value) , [&]( unsigned int thread , size_t i ) { if( tree.isValidSpaceNode( tree.node((node_index_type)i) ) ) { @@ -437,7 +431,7 @@ void _Execute( int argc , char* argv[] ) leafValues[leaf] *= 0; } - ThreadPool::Parallel_for( tree.nodesBegin(0) , tree.nodesEnd(Depth.value) , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( tree.nodesBegin(0) , tree.nodesEnd(Depth.value) , [&]( unsigned int thread , size_t i ) { if( tree.isValidSpaceNode( tree.node((node_index_type)i) ) && !tree.isValidSpaceNode( tree.node((node_index_type)i)->children ) ) { @@ -507,7 +501,7 @@ void _Execute( int argc , char* argv[] ) double errorSum = 0 , valueSum = 0 , weightSum = 0; typename FEMTree< Dim , Real >::template MultiThreadedEvaluator< IsotropicUIntPack< Dim , FEMSig > , 0 > evaluator( tree , coefficients ); std::vector< double > errorSums( ThreadPool::NumThreads() , 0 ) , valueSums( ThreadPool::NumThreads() , 0 ) , weightSums( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , geometrySamples.size() , [&]( unsigned int thread , size_t j ) + ThreadPool::ParallelFor( 0 , geometrySamples.size() , [&]( unsigned int thread , size_t j ) { ProjectiveData< Point< Real , Dim > , Real >& sample = geometrySamples[j].sample; Real w = sample.weight; @@ -523,7 +517,7 @@ void _Execute( int argc , char* argv[] ) double average , error; GetAverageValueAndError( &tree , edtSolution , average , error ); if( Verbose.set ) printf( "Interpolation average / error: %g / %g\n" , average , error ); - ThreadPool::Parallel_for( tree.nodesBegin(0) , tree.nodesEnd(0) , [&]( unsigned int , size_t i ){ edtSolution[i] -= (Real)average; } ); + ThreadPool::ParallelFor( tree.nodesBegin(0) , tree.nodesEnd(0) , [&]( unsigned int , size_t i ){ edtSolution[i] -= (Real)average; } ); } if( Out.set ) @@ -562,8 +556,8 @@ int main( int argc , char* argv[] ) WARN( "Array debugging enabled" ); #endif // ARRAY_DEBUG CmdLineParse( argc-1 , &argv[1] , params ); - ThreadPool::DefaultChunkSize = ThreadChunkSize.value; - ThreadPool::DefaultSchedule = (ThreadPool::ScheduleType)ScheduleType.value; + ThreadPool::ChunkSize = ThreadChunkSize.value; + ThreadPool::Schedule = (ThreadPool::ScheduleType)ScheduleType.value; if( MaxMemoryGB.value>0 ) SetPeakMemoryMB( MaxMemoryGB.value<<10 ); #ifdef USE_DOUBLE diff --git a/Src/FEMTree.Evaluation.inl b/Src/FEMTree.Evaluation.inl index 8c0ff73f..682ebd2c 100644 --- a/Src/FEMTree.Evaluation.inl +++ b/Src/FEMTree.Evaluation.inl @@ -641,7 +641,7 @@ Pointer( V ) FEMTree< Dim , Real >::regularGridEvaluate( const DenseNodeData< V offsets() , cornerValues() ); } - ThreadPool::Parallel_for( 0 , cellCount , [&]( unsigned int , size_t c ) + ThreadPool::ParallelFor( 0 , cellCount , [&]( unsigned int , size_t c ) { V& value = values[c]; int idx[Dim]; @@ -726,7 +726,7 @@ Pointer( V ) FEMTree< Dim , Real >::regularGridEvaluate( const DenseNodeData< V offsets() , centerValues() ); } - ThreadPool::Parallel_for( 0 , cellCount , [&]( unsigned int , size_t c ) + ThreadPool::ParallelFor( 0 , cellCount , [&]( unsigned int , size_t c ) { V& value = values[c]; int idx[Dim]; @@ -830,7 +830,7 @@ Pointer( V ) FEMTree< Dim , Real >::regularGridEvaluate( const DenseNodeData< V offsets() , cornerValues() ); } - ThreadPool::Parallel_for( 0 , cellCount , [&]( unsigned int , size_t c ) + ThreadPool::ParallelFor( 0 , cellCount , [&]( unsigned int , size_t c ) { V &value = values[c]; int idx[Dim]; @@ -915,7 +915,7 @@ Pointer( V ) FEMTree< Dim , Real >::regularGridEvaluate( const DenseNodeData< V offsets() , centerValues() ); } - ThreadPool::Parallel_for( 0 , cellCount , [&]( unsigned int , size_t c ) + ThreadPool::ParallelFor( 0 , cellCount , [&]( unsigned int , size_t c ) { V &value = values[c]; int idx[Dim]; @@ -1048,7 +1048,7 @@ Pointer( V ) FEMTree< Dim , Real >::regularGridUpSample( const DenseNodeData< V for( int dd=0 ; dd( count ); memset( upSampledCoefficients , 0 , sizeof( V ) * count ); - ThreadPool::Parallel_for( _sNodesBegin(_depth) , _sNodesEnd(_depth) , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( _sNodesBegin(_depth) , _sNodesEnd(_depth) , [&]( unsigned int , size_t i ) { if( !_outOfBounds( UIntPack< DataSigs ... >() , _sNodes.treeNodes[i] ) ) { @@ -1072,7 +1072,7 @@ Pointer( V ) FEMTree< Dim , Real >::regularGridUpSample( const DenseNodeData< V Pointer( V ) _coefficients = NewPointer< V >( count ); memset( _coefficients , 0 , sizeof( V ) * count ); if( _depth<=_maxDepth ) - ThreadPool::Parallel_for( _sNodesBegin(_depth) , _sNodesEnd(_depth) , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( _sNodesBegin(_depth) , _sNodesEnd(_depth) , [&]( unsigned int , size_t i ) { if( !_outOfBounds( UIntPack< DataSigs ... >() , _sNodes.treeNodes[i] ) ) { @@ -1117,7 +1117,7 @@ V FEMTree< Dim , Real >::average( const DenseNodeData< V , UIntPack< DataSigs .. double __begin[Dim] , __end[Dim]; for( int dd=0 ; dd() , d , off , __begin , __end ); - ThreadPool::Parallel_for( _sNodesBegin(d) , _sNodesEnd(d) , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( _sNodesBegin(d) , _sNodesEnd(d) , [&]( unsigned int thread , size_t i ) { if( _isValidFEM1Node( _sNodes.treeNodes[i] ) ) { @@ -1149,7 +1149,7 @@ SparseNodeData< CumulativeDerivativeValues< Real , Dim , PointD > , IsotropicUIn { std::vector< ConstPointSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > > > neighborKeys( ThreadPool::NumThreads() ); for( size_t i=0 ; i::Initialize( FEMTreeNode& root , const std typename FEMTreeNode::SubTreeExtractor subtreeExtractor( root ); std::vector< node_index_type > nodeToIndexMap; - ThreadPool::Parallel_for( 0 , simplices.size() , [&]( unsigned int t , size_t i ) + ThreadPool::ParallelFor( 0 , simplices.size() , [&]( unsigned int t , size_t i ) { Simplex< Real , Dim , Dim-1 > s; for( int k=0 ; k::Initialize( FEMTreeNode &root , const std typename FEMTreeNode::SubTreeExtractor subtreeExtractor( root ); std::vector< node_index_type > nodeToIndexMap; - ThreadPool::Parallel_for( 0 , points.size() , [&]( unsigned int t , size_t i ) + ThreadPool::ParallelFor( 0 , points.size() , [&]( unsigned int t , size_t i ) { _AddSample< true >( root , points[i] , maxDepth , samples , mergeNodeSamples ? &nodeToIndexMap :NULL , nodeAllocators.size() ? nodeAllocators[t] : NULL , NodeInitializer ); } ); @@ -173,7 +173,7 @@ void FEMTreeInitializer< Dim , Real >::Initialize( FEMTreeNode &root , const std typename FEMTreeNode::SubTreeExtractor subtreeExtractor( root ); std::vector< node_index_type > nodeToIndexMap; - ThreadPool::Parallel_for( 0 , points.size() , [&]( unsigned int t , size_t i ) + ThreadPool::ParallelFor( 0 , points.size() , [&]( unsigned int t , size_t i ) { _AddSample( root , points[i] , maxDepth , samples , mergeNodeSamples ? &nodeToIndexMap : NULL ); } ); @@ -500,7 +500,7 @@ void FEMTreeInitializer< Dim , Real >::Initialize( FEMTreeNode& root , const std std::vector< Allocator< FEMTreeNode > * > _nodeAllocators( ThreadPool::NumThreads() ); for( int i=0 ; i<_nodeAllocators.size() ; i++ ) _nodeAllocators[i] = nodeAllocators.size() ? nodeAllocators[i] : NULL; - ThreadPool::Parallel_for( 0 , geometricCellCount , [&]( unsigned int t , size_t i ) + ThreadPool::ParallelFor( 0 , geometricCellCount , [&]( unsigned int t , size_t i ) { auto &cellSimplices = raster[ cellIndices[i] ]; for( int j=0 ; j( *roots[i] , cellSimplices[j].first , cellSimplices[j].second , maxDepth , nodeSimplices , nodeToIndexMap , _nodeAllocators[t] , NodeInitializer ); @@ -745,7 +745,7 @@ typename std::enable_if< _Dim!=1 , DenseNodeData< typename FEMTreeInitializer< D { static_assert( Dim==_Dim , "[ERROR] Dimensions don't match" ); std::vector< Point< Real , Dim > > normals( simplices.size() ); - ThreadPool::Parallel_for + ThreadPool::ParallelFor ( 0 , simplices.size() , [&]( unsigned int , size_t i ) @@ -796,7 +796,7 @@ DenseNodeData< typename FEMTreeInitializer< Dim , Real >::GeometryNodeType , Iso geometryNodeDesignators.resize( nodeCount ); - ThreadPool::Parallel_for( 0 , nodeSimplices.size() , [&]( unsigned int , size_t i ){ for( FEMTreeNode *node=nodeSimplices[i].node ; node ; node=node->parent ) geometryNodeDesignators[node] = GeometryNodeType::BOUNDARY; } ); + ThreadPool::ParallelFor( 0 , nodeSimplices.size() , [&]( unsigned int , size_t i ){ for( FEMTreeNode *node=nodeSimplices[i].node ; node ; node=node->parent ) geometryNodeDesignators[node] = GeometryNodeType::BOUNDARY; } ); // Propagate out from the boundary nodes std::vector< const FEMTreeNode * > interiorNodes , exteriorNodes; @@ -806,7 +806,7 @@ DenseNodeData< typename FEMTreeInitializer< Dim , Real >::GeometryNodeType , Iso for( int i=0 ; i &interiorNodes = _interiorNodes[thread]; std::vector< const FEMTreeNode * > &exteriorNodes = _exteriorNodes[thread]; @@ -901,7 +901,7 @@ DenseNodeData< typename FEMTreeInitializer< Dim , Real >::GeometryNodeType , Iso for( int i=0 ; i<_interiorNodes.size() ; i++ ) _interiorNodes[i].resize( 0 ); for( int i=0 ; i<_exteriorNodes.size() ; i++ ) _exteriorNodes[i].resize( 0 ); - ThreadPool::Parallel_for( 0 , interiorNodes.size() , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( 0 , interiorNodes.size() , [&]( unsigned int thread , size_t i ) { std::vector< const FEMTreeNode * > &__interiorNodes = _interiorNodes[thread]; NeighborKey &neighborKey = neighborKeys[thread]; @@ -926,7 +926,7 @@ DenseNodeData< typename FEMTreeInitializer< Dim , Real >::GeometryNodeType , Iso } } ); - ThreadPool::Parallel_for( 0 , exteriorNodes.size() , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( 0 , exteriorNodes.size() , [&]( unsigned int thread , size_t i ) { std::vector< const FEMTreeNode * > &__exteriorNodes = _exteriorNodes[thread]; NeighborKey &neighborKey = neighborKeys[thread]; diff --git a/Src/FEMTree.LevelSet.2D.inl b/Src/FEMTree.LevelSet.2D.inl index a5a50dfd..56074397 100644 --- a/Src/FEMTree.LevelSet.2D.inl +++ b/Src/FEMTree.LevelSet.2D.inl @@ -528,7 +528,7 @@ public: std::vector< ConstCornerSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > > > bNeighborKeys( ThreadPool::NumThreads() ); if( useBoundaryEvaluation ) for( size_t i=0 ; i > > dataKeys( ThreadPool::NumThreads() ); for( size_t i=0 ; i &pCellIndices = pSliceValues.cellIndices; LevelSetExtraction::FullCellIndexData< Dim > &cCellIndices = cSliceValues.cellIndices; - ThreadPool::Parallel_for( tree._sNodesBegin(depth) , tree._sNodesEnd(depth) , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( tree._sNodesBegin(depth) , tree._sNodesEnd(depth) , [&]( unsigned int thread , size_t i ) { if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i] ) ) if( IsActiveNode< Dim >( tree._sNodes.treeNodes[i]->children ) ) { @@ -781,7 +781,7 @@ public: #endif // SANITIZED_PR std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); for( size_t i=0 ; i , ZeroUIntPack< Dim > >( tree._maxDepth ); DenseNodeData< Real , UIntPack< FEMSigs ... > > coarseCoefficients( tree._sNodesEnd( tree._maxDepth-1 ) ); memset( coarseCoefficients() , 0 , sizeof(Real)*tree._sNodesEnd( tree._maxDepth-1 ) ); - ThreadPool::Parallel_for( tree._sNodesBegin(0) , tree._sNodesEnd( tree._maxDepth-1 ) , [&]( unsigned int, size_t i ){ coarseCoefficients[i] = coefficients[i]; } ); + ThreadPool::ParallelFor( tree._sNodesBegin(0) , tree._sNodesEnd( tree._maxDepth-1 ) , [&]( unsigned int, size_t i ){ coarseCoefficients[i] = coefficients[i]; } ); typename FEMIntegrator::template RestrictionProlongation< UIntPack< FEMSigs ... > > rp; for( LocalDepth d=1 ; d() , rp , d , ( ConstPointer(Real) )coarseCoefficients()+tree._sNodesBegin(d-1) , coarseCoefficients()+tree._sNodesBegin(d) ); diff --git a/Src/FEMTree.LevelSet.3D.inl b/Src/FEMTree.LevelSet.3D.inl index 57a6ebbb..72e39328 100644 --- a/Src/FEMTree.LevelSet.3D.inl +++ b/Src/FEMTree.LevelSet.3D.inl @@ -879,7 +879,7 @@ public: std::vector< ConstCornerSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > > > bNeighborKeys( ThreadPool::NumThreads() ); if( useBoundaryEvaluation ) for( size_t i=0 ; i::template ElementNum< 0 >() ]; TreeNode* leaf = tree._sNodes.treeNodes[i]; @@ -1017,7 +1017,7 @@ public: std::vector< ConstPointSupportKey< IsotropicUIntPack< Dim , WeightDegree > > > weightKeys( ThreadPool::NumThreads() ); std::vector< ConstPointSupportKey< IsotropicUIntPack< Dim , DataDegree > > > dataKeys( ThreadPool::NumThreads() ); for( size_t i=0 ; i > > weightKeys( ThreadPool::NumThreads() ); std::vector< ConstPointSupportKey< IsotropicUIntPack< Dim , DataDegree > > > dataKeys( ThreadPool::NumThreads() ); for( size_t i=0 ; i &pCellIndices = pSliceValues.cellIndices; LevelSetExtraction::SliceCellIndexData< Dim > &cCellIndices = cSliceValues.cellIndices; - ThreadPool::Parallel_for( tree._sNodesBegin(depth,slice-(zDir==HyperCube::BACK ? 0 : 1)) , tree._sNodesEnd(depth,slice-(zDir==HyperCube::BACK ? 0 : 1)) , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( tree._sNodesBegin(depth,slice-(zDir==HyperCube::BACK ? 0 : 1)) , tree._sNodesEnd(depth,slice-(zDir==HyperCube::BACK ? 0 : 1)) , [&]( unsigned int thread , size_t i ) { if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i] ) ) if( IsActiveNode< Dim >( tree._sNodes.treeNodes[i]->children ) ) { @@ -1339,7 +1339,7 @@ public: bool has0 = cSliceValues0.slab()==((slab<<1)|0); bool has1 = cSliceValues1.slab()==((slab<<1)|1); - ThreadPool::Parallel_for( tree._sNodesBegin(depth,slab) , tree._sNodesEnd(depth,slab) , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( tree._sNodesBegin(depth,slab) , tree._sNodesEnd(depth,slab) , [&]( unsigned int thread , size_t i ) { // If the node is not a leaf, inherit iso-edges from children if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i] ) && IsActiveNode< Dim >( tree._sNodes.treeNodes[i]->children ) ) @@ -1419,7 +1419,7 @@ public: typename SliceValues::Scratch &sScratch = slabValues[depth].sliceScratch( slice ); std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); for( size_t i=0 ; i neighborKeys( ThreadPool::NumThreads() ); for( size_t i=0 ; i > polygon; std::vector< std::vector< IsoEdge > > edgess( ThreadPool::NumThreads() ); - ThreadPool::Parallel_for( tree._sNodesBegin(depth,offset) , tree._sNodesEnd(depth,offset) , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( tree._sNodesBegin(depth,offset) , tree._sNodesEnd(depth,offset) , [&]( unsigned int thread , size_t i ) { if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i] ) ) { @@ -2034,7 +2034,7 @@ public: if constexpr( HasData ) if( data ) pointEvaluator = new typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >( tree._maxDepth ); DenseNodeData< Real , UIntPack< FEMSigs ... > > coarseCoefficients( tree._sNodesEnd( tree._maxDepth-1 ) ); memset( coarseCoefficients() , 0 , sizeof(Real)*tree._sNodesEnd( tree._maxDepth-1 ) ); - ThreadPool::Parallel_for( tree._sNodesBegin(0) , tree._sNodesEnd( tree._maxDepth-1 ) , [&]( unsigned int, size_t i ){ coarseCoefficients[i] = coefficients[i]; } ); + ThreadPool::ParallelFor( tree._sNodesBegin(0) , tree._sNodesEnd( tree._maxDepth-1 ) , [&]( unsigned int, size_t i ){ coarseCoefficients[i] = coefficients[i]; } ); typename FEMIntegrator::template RestrictionProlongation< UIntPack< FEMSigs ... > > rp; for( LocalDepth d=1 ; d() , rp , d , ( ConstPointer(Real) )coarseCoefficients()+tree._sNodesBegin(d-1) , coarseCoefficients()+tree._sNodesBegin(d) ); diff --git a/Src/FEMTree.LevelSet.inl b/Src/FEMTree.LevelSet.inl index 2d18b251..e4b509ab 100644 --- a/Src/FEMTree.LevelSet.inl +++ b/Src/FEMTree.LevelSet.inl @@ -407,7 +407,7 @@ namespace LevelSetExtraction for( size_t i=0 ; i( _scratch.maps ); - ThreadPool::Parallel_for( 0 , size() , [&]( unsigned int , size_t i ){ _setTables<0>( (unsigned int)i , _scratch.maps ); } ); + ThreadPool::ParallelFor( 0 , size() , [&]( unsigned int , size_t i ){ _setTables<0>( (unsigned int)i , _scratch.maps ); } ); } // Maps from tree nodes (and their associated indices) to the associated indices for the cell indices @@ -537,7 +537,7 @@ namespace LevelSetExtraction for( size_t i=0 ; i( _scratch.maps ); - ThreadPool::Parallel_for( 0 , size() , [&]( unsigned int , size_t i ){ _setTables<0>( (unsigned int)i , _scratch.maps ); } ); + ThreadPool::ParallelFor( 0 , size() , [&]( unsigned int , size_t i ){ _setTables<0>( (unsigned int)i , _scratch.maps ); } ); } // Maps from tree nodes (and their associated indices) to the associated indices for the cell indices @@ -671,7 +671,7 @@ namespace LevelSetExtraction for( size_t i=0 ; i( _scratch.maps ); - ThreadPool::Parallel_for( 0 , size() , [&]( unsigned int , size_t i ){ _setTables<0>( (unsigned int)i , _scratch.maps ); } ); + ThreadPool::ParallelFor( 0 , size() , [&]( unsigned int , size_t i ){ _setTables<0>( (unsigned int)i , _scratch.maps ); } ); } // Maps from tree nodes (and their associated indices) to the associated indices for the cell indices diff --git a/Src/FEMTree.System.inl b/Src/FEMTree.System.inl index 7581419b..8eb50f62 100644 --- a/Src/FEMTree.System.inl +++ b/Src/FEMTree.System.inl @@ -216,7 +216,7 @@ void FEMTree< Dim , Real >::_setMultiColorIndices( UIntPack< FEMSigs ... > , nod for( int dd=0 ; dd::_solveFullSystemGS( UIntPack< FEMSigs ... > , const t Pointer( Real ) D = AllocPointer< Real >( _sNodesEnd( depth ) - _sNodesBegin( depth ) ); Pointer( T ) _constraints = AllocPointer< T >( _sNodesSize( depth ) ); _getSliceMatrixAndProlongationConstraints( UIntPack< FEMSigs ... >() , F , M , D , bsData , depth , _sNodesBegin( depth ) , _sNodesEnd( depth ) , prolongedSolution , _constraints , ccStencil , pcStencils , interpolationInfos ); - ThreadPool::Parallel_for( _sNodesBegin(depth) , _sNodesEnd(depth) , [&]( unsigned int , size_t i ){ _constraints[ i - _sNodesBegin(depth) ] = constraints[ _sNodes.treeNodes[i]->nodeData.nodeIndex ] - _constraints[ i - _sNodesBegin(depth) ]; } ); + ThreadPool::ParallelFor( _sNodesBegin(depth) , _sNodesEnd(depth) , [&]( unsigned int , size_t i ){ _constraints[ i - _sNodesBegin(depth) ] = constraints[ _sNodes.treeNodes[i]->nodeData.nodeIndex ] - _constraints[ i - _sNodesBegin(depth) ]; } ); { node_index_type begin = _sNodesBegin( depth ) , end = _sNodesEnd( depth ); for( node_index_type i=begin ; i::_solveFullSystemGS( UIntPack< FEMSigs ... > , const t if( computeNorms ) { std::vector< double > bNorms( ThreadPool::NumThreads() , 0 ) , inRNorms( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , M.rows() , [&]( unsigned int thread , size_t j ) + ThreadPool::ParallelFor( 0 , M.rows() , [&]( unsigned int thread , size_t j ) { T temp = {}; ConstPointer( MatrixEntry< Real , matrix_index_type > ) start = M[j]; @@ -294,7 +294,7 @@ int FEMTree< Dim , Real >::_solveFullSystemGS( UIntPack< FEMSigs ... > , const t if( computeNorms ) { std::vector< double > outRNorms( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , M.rows() , [&]( unsigned int thread , size_t j ) + ThreadPool::ParallelFor( 0 , M.rows() , [&]( unsigned int thread , size_t j ) { T temp = {}; ConstPointer( MatrixEntry< Real , matrix_index_type > ) start = M[j]; @@ -461,7 +461,7 @@ int FEMTree< Dim , Real >::_solveSlicedSystemGS( UIntPack< FEMSigs ... > , const t = Time(); _getSliceMatrixAndProlongationConstraints( UIntPack< FEMSigs ... >() , F , _M[_b] , _D[_b] , bsData , depth , _sNodesBegin( depth , BlockFirst( b ) ) , _sNodesEnd( depth , BlockLast( b ) ) , prolongedSolution , _constraints[_b] , ccStencil , pcStencils , interpolationInfos ); size_t begin = _sNodesBegin( depth , BlockFirst( b ) ) , end = _sNodesEnd( depth , BlockLast( b ) ); - ThreadPool::Parallel_for( begin , end , [&]( unsigned int , size_t i ){ _constraints[_b][ i-begin ] = constraints[i] - _constraints[_b][ i-begin ]; } ); + ThreadPool::ParallelFor( begin , end , [&]( unsigned int , size_t i ){ _constraints[_b][ i-begin ] = constraints[i] - _constraints[_b][ i-begin ]; } ); { node_index_type begin = _sNodesBegin( depth , BlockFirst( b ) ) , end = _sNodesEnd( depth , BlockLast( b ) ); for( node_index_type i=begin ; i::_solveSlicedSystemGS( UIntPack< FEMSigs ... > , const ConstPointer( T ) B = _constraints[_b]; ConstPointer( T ) X = XBlocks( depth , b , solution ); std::vector< double > bNorms( ThreadPool::NumThreads() , 0 ) , inRNorms( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , _M[_b].rows() , [&]( unsigned int thread , size_t j ) + ThreadPool::ParallelFor( 0 , _M[_b].rows() , [&]( unsigned int thread , size_t j ) { T temp = {}; ConstPointer( MatrixEntry< Real , matrix_index_type > ) start = _M[_b][j]; @@ -515,7 +515,7 @@ int FEMTree< Dim , Real >::_solveSlicedSystemGS( UIntPack< FEMSigs ... > , const ConstPointer( T ) B = _constraints[_b]; ConstPointer( T ) X = XBlocks( depth , b , solution ); std::vector< double > outRNorms( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , _M[_b].rows() , [&]( unsigned int thread , size_t j ) + ThreadPool::ParallelFor( 0 , _M[_b].rows() , [&]( unsigned int thread , size_t j ) { T temp = {}; ConstPointer( MatrixEntry< Real , matrix_index_type > ) start = _M[_b][j]; @@ -562,7 +562,7 @@ int FEMTree< Dim , Real >::_solveSystemCG( UIntPack< FEMSigs ... > , const typen F.template setStencil< false >( ccStencil ); F.template setStencils< true >( pcStencils ); _getSliceMatrixAndProlongationConstraints( UIntPack< FEMSigs ... >() , F , M , NullPointer( Real ) , bsData , depth , _sNodesBegin( depth ) , _sNodesEnd( depth ) , prolongedSolution , _constraints , ccStencil , pcStencils , interpolationInfos ); - ThreadPool::Parallel_for( _sNodesBegin(depth) , _sNodesEnd(depth) , [&]( unsigned int , size_t i ){ _constraints[ i - _sNodesBegin(depth) ] = constraints[i] - _constraints[ i - _sNodesBegin(depth) ]; } ); + ThreadPool::ParallelFor( _sNodesBegin(depth) , _sNodesEnd(depth) , [&]( unsigned int , size_t i ){ _constraints[ i - _sNodesBegin(depth) ] = constraints[i] - _constraints[ i - _sNodesBegin(depth) ]; } ); systemTime = Time()-systemTime; solveTime = Time(); // Solve the linear system @@ -580,7 +580,7 @@ int FEMTree< Dim , Real >::_solveSystemCG( UIntPack< FEMSigs ... > , const typen if( computeNorms ) { std::vector< double > bNorms( ThreadPool::NumThreads() , 0 ) , inRNorms( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , M.rows() , [&]( unsigned int thread , size_t j ) + ThreadPool::ParallelFor( 0 , M.rows() , [&]( unsigned int thread , size_t j ) { T temp = {}; ConstPointer( MatrixEntry< Real , matrix_index_type > ) start = M[j]; @@ -620,7 +620,7 @@ int FEMTree< Dim , Real >::_solveSystemCG( UIntPack< FEMSigs ... > , const typen if( computeNorms ) { std::vector< double > outRNorms( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , M.rows() , [&]( unsigned int thread , size_t j ) + ThreadPool::ParallelFor( 0 , M.rows() , [&]( unsigned int thread , size_t j ) { T temp = {}; ConstPointer( MatrixEntry< Real , matrix_index_type > ) start = M[j]; @@ -700,7 +700,7 @@ void FEMTree< Dim , Real >::_solveRegularMG( UIntPack< FEMSigs ... > , typename const SparseMatrix< Real , matrix_index_type >& _M = M.back(); ConstPointer( T ) _X = X.back(); std::vector< double > bNorms( ThreadPool::NumThreads() , 0 ) , inRNorms( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , _M.rows() , [&]( unsigned int thread , size_t j ) + ThreadPool::ParallelFor( 0 , _M.rows() , [&]( unsigned int thread , size_t j ) { T temp = {}; ConstPointer( MatrixEntry< Real , matrix_index_type > ) start = _M[j]; @@ -777,7 +777,7 @@ void FEMTree< Dim , Real >::_solveRegularMG( UIntPack< FEMSigs ... > , typename const SparseMatrix< Real , matrix_index_type >& _M = M.back(); ConstPointer( T ) _X = X.back(); std::vector< double > outRNorms( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , _M.rows() , [&]( unsigned int thread , size_t j ) + ThreadPool::ParallelFor( 0 , _M.rows() , [&]( unsigned int thread , size_t j ) { T temp = {}; ConstPointer( MatrixEntry< Real , matrix_index_type > ) start = _M[j]; @@ -1308,7 +1308,7 @@ void FEMTree< Dim , Real >::_updateRestrictedIntegralConstraints( UIntPack< FEMS // Iterate over the nodes @(highDepth) std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); for( size_t i=0 ; i::_setPointValuesFromProlongedSolution( LocalDepth hig std::vector< ConstPointSupportKey< FEMDegrees > > neighborKeys( ThreadPool::NumThreads() ); for( size_t i=0 ; i::_updateRestrictedInterpolationConstraints( const Poi node_index_type start = _sNodesBegin(lowDepth) , end = _sNodesEnd(lowDepth); std::vector< ConstPointSupportKey< FEMDegrees > > neighborKeys( ThreadPool::NumThreads() ); for( size_t i=0 ; i > FEMTree< Dim , Real >::coarseCoeffi { DenseNodeData< C , UIntPack< FEMSigs ... > > coarseCoefficients( _sNodesEnd(_maxDepth-1) ); memset( coarseCoefficients() , 0 , sizeof(Real)*_sNodesEnd(_maxDepth-1) ); - ThreadPool::Parallel_for( _sNodesBegin(0) , _sNodesEnd(_maxDepth-1) , [&]( unsigned int , size_t i ){ coarseCoefficients[i] = coefficients[i]; } ); + ThreadPool::ParallelFor( _sNodesBegin(0) , _sNodesEnd(_maxDepth-1) , [&]( unsigned int , size_t i ){ coarseCoefficients[i] = coefficients[i]; } ); typename FEMIntegrator::template RestrictionProlongation< UIntPack< FEMSigs ... > > rp; for( LocalDepth d=1 ; d<_maxDepth ; d++ ) _upSample( UIntPack< FEMSigs ... >() , rp , d , ( ConstPointer(C) )coarseCoefficients()+_sNodesBegin(d-1) , coarseCoefficients()+_sNodesBegin(d) ); return coarseCoefficients; @@ -1481,7 +1481,7 @@ DenseNodeData< C , UIntPack< FEMSigs ... > > FEMTree< Dim , Real >::coarseCoeffi { DenseNodeData< C , UIntPack< FEMSigs ... > > coarseCoefficients( _sNodesEnd(_maxDepth-1) ); memset( coarseCoefficients() , 0 , sizeof(C)*_sNodesEnd(_maxDepth-1) ); - ThreadPool::Parallel_for( _sNodesBegin(0) , _sNodesEnd(_maxDepth-1) , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( _sNodesBegin(0) , _sNodesEnd(_maxDepth-1) , [&]( unsigned int , size_t i ) { const C* c = coefficients( _sNodes.treeNodes[i] ); if( c ) coarseCoefficients[i] = *c; @@ -1498,7 +1498,7 @@ DenseNodeData< C , UIntPack< FEMSigs ... > > FEMTree< Dim , Real >::denseCoeffic { DenseNodeData< C , UIntPack< FEMSigs ... > > denseCoefficients( _sNodesEnd(_maxDepth) ); memset( denseCoefficients() , 0 , sizeof(C)*_sNodesEnd(_maxDepth) ); - ThreadPool::Parallel_for( _sNodesBegin(0) , _sNodesEnd(_maxDepth) , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( _sNodesBegin(0) , _sNodesEnd(_maxDepth) , [&]( unsigned int , size_t i ) { const C* c = coefficients( _sNodes.treeNodes[i] ); if( c ) denseCoefficients[i] = *c; @@ -1587,7 +1587,7 @@ int FEMTree< Dim , Real >::_getSliceMatrixAndProlongationConstraints( UIntPack< matrix.resize( range ); std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); for( size_t i=0 ; i FEMTree< Dim , Real >::systemMatrix( UI matrix.resize( _sNodesSize(depth) ); std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); for( size_t i=0 ; i FEMTree< Dim , Real >::prolongedSystemM matrix.resize( _sNodesSize(highDepth) ); std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); for( size_t i=0 ; i FEMTree< Dim , Real >::_downSampleMatri upSampleStencil() ); - ThreadPool::Parallel_for( _sNodesBegin(lowDepth) , _sNodesEnd(lowDepth) , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( _sNodesBegin(lowDepth) , _sNodesEnd(lowDepth) , [&]( unsigned int thread , size_t i ) { if( validNodeFunctor( _sNodes.treeNodes[i] ) ) { @@ -1819,7 +1819,7 @@ SparseMatrix< Real , matrix_index_type > FEMTree< Dim , Real >::_upSampleMatrix( ); // For Dirichlet constraints, can't get to all children from parents because boundary nodes are invalid - ThreadPool::Parallel_for( _sNodesBegin(highDepth) , _sNodesEnd(highDepth) , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( _sNodesBegin(highDepth) , _sNodesEnd(highDepth) , [&]( unsigned int thread , size_t i ) { if( validNodeFunctor( _sNodes.treeNodes[i] ) ) { @@ -1902,7 +1902,7 @@ SparseMatrix< Real , matrix_index_type > FEMTree< Dim , Real >::_restrictSystemM // Compute the window indices of all nodes at the coarser resolution static const unsigned int StartOffsetIndex = GetWindowIndex( UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... >() , StartOffset ); std::vector< unsigned int > windowIndices( _sNodesSize(lowDepth) ); - ThreadPool::Parallel_for( _sNodesBegin(lowDepth) , _sNodesEnd(lowDepth) , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( _sNodesBegin(lowDepth) , _sNodesEnd(lowDepth) , [&]( unsigned int thread , size_t i ) { node_index_type _i = (node_index_type)i - _sNodesBegin(lowDepth); LocalDepth d ; LocalOffset off; @@ -1911,7 +1911,7 @@ SparseMatrix< Real , matrix_index_type > FEMTree< Dim , Real >::_restrictSystemM } ); // Iterate over all low-depth nodes - ThreadPool::Parallel_for( _sNodesBegin(lowDepth) , _sNodesEnd(lowDepth) , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( _sNodesBegin(lowDepth) , _sNodesEnd(lowDepth) , [&]( unsigned int thread , size_t i ) { if( validNodeFunctor( _sNodes.treeNodes[i] ) ) { @@ -1987,7 +1987,7 @@ SparseMatrix< Real , matrix_index_type > FEMTree< Dim , Real >::fullSystemMatrix SparseMatrix< Real , matrix_index_type >& M = systemMatrices[d]; M.resize( size ); SparseMatrix< Real , matrix_index_type > _M = systemMatrix< Real >( UIntPack< FEMSigs ... >() , F , d , interpolationInfos ); - ThreadPool::Parallel_for( 0 , _M.rows() , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( 0 , _M.rows() , [&]( unsigned int , size_t i ) { M.setRowSize( (matrix_index_type)( i + _sNodesBegin(d) ) , _M.rowSize(i) ); for( int j=0 ; j<_M.rowSize(i) ; j++ ) M[i+_sNodesBegin(d)][j] = MatrixEntry< Real , matrix_index_type >( _M[i][j].N + (matrix_index_type)_sNodesBegin(d) , _M[i][j].Value ); @@ -1999,7 +1999,7 @@ SparseMatrix< Real , matrix_index_type > FEMTree< Dim , Real >::fullSystemMatrix SparseMatrix< Real , matrix_index_type >& M = prolongedSystemMatrices[d]; M.resize( size ); SparseMatrix< Real , matrix_index_type > _M = prolongedSystemMatrix< Real >( UIntPack< FEMSigs ... >() , F , d+1 , interpolationInfos ); - ThreadPool::Parallel_for( 0 , _M.rows() , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( 0 , _M.rows() , [&]( unsigned int , size_t i ) { M.setRowSize( i + (matrix_index_type)_sNodesBegin(d+1) , _M.rowSize(i) ); for( int j=0 ; j<_M.rowSize(i) ; j++ ) M[i+_sNodesBegin(d+1)][j] = MatrixEntry< Real , matrix_index_type >( _M[i][j].N + (matrix_index_type)_sNodesBegin(d) , _M[i][j].Value ); @@ -2011,7 +2011,7 @@ SparseMatrix< Real , matrix_index_type > FEMTree< Dim , Real >::fullSystemMatrix SparseMatrix< Real , matrix_index_type >& M = upSampleMatrices[d][d+1]; M.resize( size ); SparseMatrix< Real , matrix_index_type > _M = downSampleMatrix( UIntPack< FEMSigs ... >() , d+1 ).transpose( _sNodesSize( d+1 ) ); - ThreadPool::Parallel_for( 0 , _M.rows() , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( 0 , _M.rows() , [&]( unsigned int , size_t i ) { M.setRowSize( i + (matrix_index_type)_sNodesBegin(d+1) , _M.rowSize(i) ); for( int j=0 ; j<_M.rowSize(i) ; j++ ) M[i+_sNodesBegin(d+1)][j] = MatrixEntry< Real , matrix_index_type >( _M[i][j].N + (matrix_index_type)_sNodesBegin(d) , _M[i][j].Value ); @@ -2037,7 +2037,7 @@ SparseMatrix< Real , matrix_index_type > FEMTree< Dim , Real >::fullSystemMatrix for( int d2=0 ; d2<=depth ; d2++ ) if( d1!=d2 ) { SparseMatrix< Real , matrix_index_type > _M = Matrix( d1 , d2 ); - ThreadPool::Parallel_for( 0 , _M.rows() , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( 0 , _M.rows() , [&]( unsigned int , size_t i ) { if( _M.rowSize(i) ) { @@ -2071,7 +2071,7 @@ void FEMTree< Dim , Real >::_downSample( UIntPack< FEMSigs ... > , typename Base typename BaseRestrictionProlongation::UpSampleStencil upSampleStencil; rp.setStencil( upSampleStencil ); - ThreadPool::Parallel_for( _sNodesBegin(lowDepth) , _sNodesEnd(lowDepth) , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( _sNodesBegin(lowDepth) , _sNodesEnd(lowDepth) , [&]( unsigned int thread , size_t i ) { if( _isValidFEM1Node( _sNodes.treeNodes[i] ) ) { @@ -2130,7 +2130,7 @@ DenseNodeData< Real , UIntPack< FEMSigs ... > > FEMTree< Dim , Real >::supportWe for( size_t i=0 ; i( stencil ); - ThreadPool::Parallel_for( _sNodesBegin(d) , _sNodesEnd(d) , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( _sNodesBegin(d) , _sNodesEnd(d) , [&]( unsigned int thread , size_t i ) { if( _isValidFEM1Node( _sNodes.treeNodes[i] ) ) { @@ -2204,7 +2204,7 @@ DenseNodeData< Real , UIntPack< FEMSigs ... > > FEMTree< Dim , Real >::prolongat std::vector< UpSampleKey > neighborKeys( ThreadPool::NumThreads() ); for( size_t i=0 ; i > FEMTree< Dim , Real >::prolongat typename BaseRestrictionProlongation::UpSampleStencil upSampleStencil; rp.setStencil( upSampleStencil ); - ThreadPool::Parallel_for( _sNodesBegin(lowDepth) , _sNodesEnd(lowDepth) , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( _sNodesBegin(lowDepth) , _sNodesEnd(lowDepth) , [&]( unsigned int thread , size_t i ) { if( _isValidFEM1Node( _sNodes.treeNodes[i] ) ) { @@ -2283,7 +2283,7 @@ DenseNodeData< Real , UIntPack< FEMSigs ... > > FEMTree< Dim , Real >::prolongat typename BaseRestrictionProlongation::DownSampleStencils downSampleStencils; rp.setStencils( downSampleStencils ); - ThreadPool::Parallel_for( _sNodesBegin(lowDepth+1) , _sNodesEnd(lowDepth+1) , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( _sNodesBegin(lowDepth+1) , _sNodesEnd(lowDepth+1) , [&]( unsigned int thread , size_t i ) { if( _isValidFEM1Node( _sNodes.treeNodes[i] ) ) { @@ -2376,7 +2376,7 @@ void FEMTree< Dim , Real >::_upSample( UIntPack< FEMSigs ... > , typename BaseFE } ); // For Dirichlet constraints, can't get to all children from parents because boundary nodes are invalid - ThreadPool::Parallel_for( _sNodesBegin(highDepth) , _sNodesEnd(highDepth) , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( _sNodesBegin(highDepth) , _sNodesEnd(highDepth) , [&]( unsigned int thread , size_t i ) { if( _isValidFEM1Node( _sNodes.treeNodes[i] ) ) { @@ -2687,7 +2687,7 @@ void FEMTree< Dim , Real >::solveSystem( UIntPack< FEMSigs ... > , typename Base if( depth==_maxDepth ) return; if ( depth< _baseDepth ){} - else if( depth==_baseDepth ) ThreadPool::Parallel_for( _sNodesBegin(depth) , _sNodesEnd(depth) , [&]( unsigned int , size_t i ){ _prolongedSolution[i] = solution[i]; } ); + else if( depth==_baseDepth ) ThreadPool::ParallelFor( _sNodesBegin(depth) , _sNodesEnd(depth) , [&]( unsigned int , size_t i ){ _prolongedSolution[i] = solution[i]; } ); else if( depth< _maxDepth ) { // Clear the prolonged solution @(depth) @@ -2698,7 +2698,7 @@ void FEMTree< Dim , Real >::solveSystem( UIntPack< FEMSigs ... > , typename Base _upSample( UIntPack< FEMSigs ... >() , F.restrictionProlongation() , depth , ( ConstPointer(T) )_prolongedSolution+_sNodesBegin(depth-1) , _prolongedSolution+_sNodesBegin(depth) ); // Add in the solution @(depth) to the prolonged solution - ThreadPool::Parallel_for( _sNodesBegin(depth) , _sNodesEnd(depth) , [&]( unsigned int , size_t i ){ _prolongedSolution[i] += solution[i]; } ); + ThreadPool::ParallelFor( _sNodesBegin(depth) , _sNodesEnd(depth) , [&]( unsigned int , size_t i ){ _prolongedSolution[i] += solution[i]; } ); } #ifdef SHOW_WARNINGS #pragma message( "[WARNING] Should this be here or in SetResidualConstraints" ) @@ -2725,7 +2725,7 @@ void FEMTree< Dim , Real >::solveSystem( UIntPack< FEMSigs ... > , typename Base // Update the constraints @(depth) using the restriced residual @(depth) if( depth<_maxDepth && _restrictedConstraints ) - ThreadPool::Parallel_for( _sNodesBegin(depth) , _sNodesEnd(depth) , [&]( unsigned int , size_t i ){ _residualConstraints[i] -= _restrictedConstraints[i]; } ); + ThreadPool::ParallelFor( _sNodesBegin(depth) , _sNodesEnd(depth) , [&]( unsigned int , size_t i ){ _residualConstraints[i] -= _restrictedConstraints[i]; } ); }; auto OutputSolverStats = [&] ( int cycle , int depth , const _SolverStats& sStats , bool showResidual , int actualIters ) { @@ -2949,7 +2949,7 @@ void FEMTree< Dim , Real >::_addFEMConstraints( UIntPack< FEMSigs ... > , UIntPa F.template setStencils< true >( stencils ); std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); for( size_t i=0 ; i::_addFEMConstraints( UIntPack< FEMSigs ... > , UIntPa memset( _coefficients , 0 , sizeof(D) * _sNodesEnd(maxDepth-1) ); for( LocalDepth d=maxDepth-1 ; d>=0 ; d-- ) { - ThreadPool::Parallel_for( _sNodesBegin(d) , _sNodesEnd(d) , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( _sNodesBegin(d) , _sNodesEnd(d) , [&]( unsigned int , size_t i ) { const D* d = coefficients( _sNodes.treeNodes[i] ); if( d ) _coefficients[i] += *d; @@ -3082,7 +3082,7 @@ void FEMTree< Dim , Real >::_addFEMConstraints( UIntPack< FEMSigs ... > , UIntPa std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); for( size_t i=0 ; i::_addFEMConstraints( UIntPack< FEMSigs ... > , UIntPa FreePointer( _coefficients ); } - ThreadPool::Parallel_for( _sNodesBegin(0) , _sNodesEnd(_maxDepth) , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( _sNodesBegin(0) , _sNodesEnd(_maxDepth) , [&]( unsigned int , size_t i ) { if( _isValidFEM1Node( _sNodes.treeNodes[i] ) && _sNodes.treeNodes[i]->nodeData.getDirichletElementFlag() ) constraints[i] *= (Real)0; } ); @@ -3170,7 +3170,7 @@ void FEMTree< Dim , Real >::_addInterpolationConstraints( DenseNodeData< T , UIn { return eState.template dValues< Real , CumulativeDerivatives< Dim , PointD > >( off ); }; - ThreadPool::Parallel_for( _sNodesBegin(d) , _sNodesEnd(d) , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( _sNodesBegin(d) , _sNodesEnd(d) , [&]( unsigned int thread , size_t i ) { if( _isValidSpaceNode( _sNodes.treeNodes[i] ) ) { @@ -3234,7 +3234,7 @@ double FEMTree< Dim , Real >::_interpolationDot( UIntPack< FEMSigs1 ... > , UInt size_t begin , end; iInfo->range( _spaceRoot , begin , end ); std::vector< double > dots( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( begin , end , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( begin , end , [&]( unsigned int thread , size_t i ) { Point< Real , Dim > p = (*iInfo)[i].position; Real w = (*iInfo)[i].weight; @@ -3272,7 +3272,7 @@ double FEMTree< Dim , Real >::_dot( UIntPack< FEMSigs1 ... > , UIntPack< FEMSigs for( size_t i=0 ; i dots( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( _sNodesBegin(d) , _sNodesEnd(d) , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( _sNodesBegin(d) , _sNodesEnd(d) , [&]( unsigned int thread , size_t i ) { double &dot = dots[thread]; const FEMTreeNode* node = _sNodes.treeNodes[i]; @@ -3326,7 +3326,7 @@ double FEMTree< Dim , Real >::_dot( UIntPack< FEMSigs1 ... > , UIntPack< FEMSigs for( LocalDepth d=1 ; d<=_maxDepth ; d++ ) { // Update the cumulative coefficients with the coefficients @(depth-1) - ThreadPool::Parallel_for( _sNodesBegin(d-1) , _sNodesEnd(d-1) , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( _sNodesBegin(d-1) , _sNodesEnd(d-1) , [&]( unsigned int , size_t i ) { const T* _data1 = coefficients1( _sNodes.treeNodes[i] ); if( _data1 ) cumulative1[i] += *_data1; @@ -3341,7 +3341,7 @@ double FEMTree< Dim , Real >::_dot( UIntPack< FEMSigs1 ... > , UIntPack< FEMSigs for( size_t i=0 ; i dots( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( _sNodesBegin(d) , _sNodesEnd(d) , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( _sNodesBegin(d) , _sNodesEnd(d) , [&]( unsigned int thread , size_t i ) { double &dot = dots[thread]; const FEMTreeNode* node = _sNodes.treeNodes[i]; @@ -3409,7 +3409,7 @@ double FEMTree< Dim , Real >::_dot( UIntPack< FEMSigs1 ... > , UIntPack< FEMSigs // Update the cumulative constraints @(depth-1) from @(depth) std::vector< double > dots( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( _sNodesBegin(d) , _sNodesEnd(d) , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( _sNodesBegin(d) , _sNodesEnd(d) , [&]( unsigned int thread , size_t i ) { double &dot = dots[thread]; const FEMTreeNode* node = _sNodes.treeNodes[i]; @@ -3467,7 +3467,7 @@ double FEMTree< Dim , Real >::_dot( UIntPack< FEMSigs1 ... > , UIntPack< FEMSigs for( unsigned int t=0 ; t::processNeighboringLeaves( FEMTreeNode **nodes , size std::vector< NeighborKey > neighborKeys( ThreadPool::NumThreads() ); for( int i=0 ; i > NeighborLeafNodes; NeighborLeafNodes neighborLeafNodes; @@ -805,7 +805,7 @@ void FEMTree< Dim , Real >::updateDensityEstimator( typename FEMTree< Dim , Real std::vector< node_index_type > sampleMap( nodeCount() , -1 ); // Initialize the map from node indices to samples - ThreadPool::Parallel_for( 0 , samples.size() , [&]( unsigned int , size_t i ){ if( samples[i].sample.weight>0 ) sampleMap[ samples[i].node->nodeData.nodeIndex ] = (node_index_type)i; } ); + ThreadPool::ParallelFor( 0 , samples.size() , [&]( unsigned int , size_t i ){ if( samples[i].sample.weight>0 ) sampleMap[ samples[i].node->nodeData.nodeIndex ] = (node_index_type)i; } ); std::function< ProjectiveData< Point< Real , Dim > , Real > ( FEMTreeNode* ) > SetDensity = [&] ( FEMTreeNode* node ) { @@ -837,7 +837,7 @@ void FEMTree< Dim , Real >::updateDensityEstimator( typename FEMTree< Dim , Real std::vector< node_index_type > sampleMap( nodeCount() , -1 ); // Initialize the map from node indices to samples - ThreadPool::Parallel_for( 0 , samples.size() , [&]( unsigned int , size_t i ){ if( samples[i].sample.weight>0 ) sampleMap[ samples[i].node->nodeData.nodeIndex ] = (node_index_type)i; } ); + ThreadPool::ParallelFor( 0 , samples.size() , [&]( unsigned int , size_t i ){ if( samples[i].sample.weight>0 ) sampleMap[ samples[i].node->nodeData.nodeIndex ] = (node_index_type)i; } ); std::function< ProjectiveData< Point< Real , Dim > , Real > ( FEMTreeNode* ) > SetDensity = [&] ( FEMTreeNode* node ) { @@ -918,7 +918,7 @@ SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setI pointDepthAndWeight.weight = 0; SparseNodeData< OutData , UIntPack< DataSigs ... > > dataField; std::vector< Point< Real , 2 > > pointDepthAndWeightSums( ThreadPool::NumThreads() , Point< Real , 2 >() ); - ThreadPool::Parallel_for( 0 , samples.size() , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( 0 , samples.size() , [&]( unsigned int thread , size_t i ) { DensityKey& densityKey = densityKeys[ thread ]; DataKey& dataKey = dataKeys[ thread ]; @@ -1007,7 +1007,7 @@ SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setI pointDepthAndWeight.weight = 0; SparseNodeData< OutData , UIntPack< DataSigs ... > > dataField; std::vector< Point< Real , 2 > > pointDepthAndWeightSums( ThreadPool::NumThreads() , Point< Real , 2 >() ); - ThreadPool::Parallel_for( 0 , samples.size() , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( 0 , samples.size() , [&]( unsigned int thread , size_t i ) { DensityKey& densityKey = densityKeys[ thread ]; DataKey& dataKey = dataKeys[ thread ]; @@ -1130,7 +1130,7 @@ void FEMTree< Dim , Real >::_supportApproximateProlongation( void ) #ifdef SHOW_WARNINGS #pragma message( "[WARNING] This may be overkill as we only need to check if the support overlaps the support of the children" ) #endif // SHOW_WARNINGS - ThreadPool::Parallel_for( 0 , nodes.size() , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( 0 , nodes.size() , [&]( unsigned int thread , size_t i ) { NeighborKey& neighborKey = neighborKeys[ thread ]; FEMTreeNode *node = nodes[i]; @@ -1180,7 +1180,7 @@ void FEMTree< Dim , Real >::_markNonBaseDirichletElements( void ) } }; - ThreadPool::Parallel_for( 0 , baseNodes.size() , [&]( unsigned int t , size_t i ){ ProcessSubTree( baseNodes[i] , supportKeys[t] , neighborLeaves[t] ); } ); + ThreadPool::ParallelFor( 0 , baseNodes.size() , [&]( unsigned int t , size_t i ){ ProcessSubTree( baseNodes[i] , supportKeys[t] , neighborLeaves[t] ); } ); } template< unsigned int Dim , typename Real > @@ -1197,7 +1197,7 @@ void FEMTree< Dim , Real >::_markBaseDirichletElements( void ) std::vector< FEMTreeNode* > nodes; _tree.processNodes( [&]( FEMTreeNode *node ){ if( _localDepth( node )==_baseDepth && node->nodeData.getDirichletNodeFlag() ) nodes.push_back( node ) ; return _localDepth(node)<_baseDepth; } ); - ThreadPool::Parallel_for( 0 , nodes.size() , [&]( unsigned int thread , size_t i ) + ThreadPool::ParallelFor( 0 , nodes.size() , [&]( unsigned int thread , size_t i ) { SupportKey &supportKey = supportKeys[ thread ]; FEMTreeNode *node = nodes[i]; @@ -1416,7 +1416,7 @@ template< unsigned int Dim , class Real > void FEMTree< Dim , Real >::_setSpaceValidityFlags( void ) const { const unsigned char MASK = ~( FEMTreeNodeData::SPACE_FLAG ); - ThreadPool::Parallel_for( 0 , _sNodes.size() , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( 0 , _sNodes.size() , [&]( unsigned int , size_t i ) { _sNodes.treeNodes[i]->nodeData.flags &= MASK; if( isValidSpaceNode( _sNodes.treeNodes[i] ) ) _sNodes.treeNodes[i]->nodeData.flags |= FEMTreeNodeData::SPACE_FLAG; @@ -1477,7 +1477,7 @@ void FEMTree< Dim , Real >::_clipTree( const HasDataFunctor& f , LocalDepth full node_index_type sz = nodeCount(); Pointer( char ) nodeHasData = NewPointer< char >( sz ); for( node_index_type i=0 ; iprocessNodes( [&]( FEMTreeNode *node ){ if( node->nodeData.nodeIndex!=-1 ) nodeHasData[node->nodeData.nodeIndex] = f( node ) ? 1 : 0; } ); } ); @@ -1492,10 +1492,10 @@ void FEMTree< Dim , Real >::_clipTree( const HasDataFunctor& f , LocalDepth full return hasData; }; - ThreadPool::Parallel_for( 0 , regularNodes.size() , [&]( unsigned int , size_t i ){ PullHasDataFromChildren( regularNodes[i] ); } ); + ThreadPool::ParallelFor( 0 , regularNodes.size() , [&]( unsigned int , size_t i ){ PullHasDataFromChildren( regularNodes[i] ); } ); // Mark all children of a node as ghost if none of them have data - ThreadPool::Parallel_for( 0 , regularNodes.size() , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( 0 , regularNodes.size() , [&]( unsigned int , size_t i ) { auto nodeFunctor = [&]( FEMTreeNode *node ) { @@ -1516,7 +1516,7 @@ template< typename T , typename Data , unsigned int PointD , typename Constraint void FEMTree< Dim , Real >::_ExactPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >::_init( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , ConstPointer( Data ) sampleData , bool noRescale ) { _sampleSpan.resize( tree.nodesSize() ); - ThreadPool::Parallel_for( 0 , tree.nodesSize() , [&]( unsigned int , size_t i ){ _sampleSpan[i] = std::pair< node_index_type , node_index_type >( 0 , 0 ); } ); + ThreadPool::ParallelFor( 0 , tree.nodesSize() , [&]( unsigned int , size_t i ){ _sampleSpan[i] = std::pair< node_index_type , node_index_type >( 0 , 0 ); } ); for( node_index_type i=0 ; i<(node_index_type)samples.size() ; i++ ) { const FEMTreeNode* leaf = samples[i].node; @@ -1565,7 +1565,7 @@ void FEMTree< Dim , Real >::_ExactPointAndDataInterpolationInfo< T , Data , Poin } } - ThreadPool::Parallel_for( 0 , _iData.size() , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( 0 , _iData.size() , [&]( unsigned int , size_t i ) { Real w = _iData[i].pointInfo.weight; _iData[i] /= w; @@ -1580,7 +1580,7 @@ template< typename T , unsigned int PointD , typename ConstraintDual , typename void FEMTree< Dim , Real >::ExactPointInterpolationInfo< T , PointD , ConstraintDual , SystemDual >::_init( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , bool noRescale ) { _sampleSpan.resize( tree._nodeCount ); - ThreadPool::Parallel_for( 0 , tree.nodesSize() , [&]( unsigned int , size_t i ){ _sampleSpan[i] = std::pair< node_index_type , node_index_type >( 0 , 0 ); } ); + ThreadPool::ParallelFor( 0 , tree.nodesSize() , [&]( unsigned int , size_t i ){ _sampleSpan[i] = std::pair< node_index_type , node_index_type >( 0 , 0 ); } ); for( node_index_type i=0 ; i<(node_index_type)samples.size() ; i++ ) { const FEMTreeNode* leaf = samples[i].node; @@ -1629,7 +1629,7 @@ void FEMTree< Dim , Real >::ExactPointInterpolationInfo< T , PointD , Constraint } } - ThreadPool::Parallel_for( 0 , _iData.size() , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( 0 , _iData.size() , [&]( unsigned int , size_t i ) { Real w = _iData[i].weight; _iData[i] /= w; @@ -1644,7 +1644,7 @@ template< unsigned int PointD , typename ConstraintDual , typename SystemDual > void FEMTree< Dim , Real >::ExactPointInterpolationInfo< double , PointD , ConstraintDual , SystemDual >::_init( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , bool noRescale ) { _sampleSpan.resize( tree._nodeCount ); - ThreadPool::Parallel_for( 0 , tree.nodesSize() , [&]( unsigned int , size_t i ){ _sampleSpan[i] = std::pair< node_index_type , node_index_type >( 0 , 0 ); } ); + ThreadPool::ParallelFor( 0 , tree.nodesSize() , [&]( unsigned int , size_t i ){ _sampleSpan[i] = std::pair< node_index_type , node_index_type >( 0 , 0 ); } ); for( node_index_type i=0 ; i<(node_index_type)samples.size() ; i++ ) { const FEMTreeNode* leaf = samples[i].node; @@ -1692,7 +1692,7 @@ void FEMTree< Dim , Real >::ExactPointInterpolationInfo< double , PointD , Const } } - ThreadPool::Parallel_for( 0 , _iData.size() , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( 0 , _iData.size() , [&]( unsigned int , size_t i ) { Real w = _iData[i].weight; _iData[i] /= w; @@ -1744,7 +1744,7 @@ void FEMTree< Dim , Real >::_densifyInterpolationInfoAndSetDualConstraints( Spar // Set the interior values _setInterpolationInfoFromChildren( _spaceRoot , iInfo ); - ThreadPool::Parallel_for( 0 , iInfo.size() , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( 0 , iInfo.size() , [&]( unsigned int , size_t i ) { Real w = iInfo[i].weight; iInfo[i] /= w ; iInfo[i].weight = w; @@ -1789,7 +1789,7 @@ void FEMTree< Dim , Real >::_densifyInterpolationInfoAndSetDualConstraints( Spar // Set the interior values _setInterpolationInfoFromChildren( _spaceRoot , iInfo ); - ThreadPool::Parallel_for( 0 , iInfo.size() , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( 0 , iInfo.size() , [&]( unsigned int , size_t i ) { Real w = iInfo[i].pointInfo.weight; iInfo[i] /= w ; iInfo[i].pointInfo.weight = w; @@ -1855,7 +1855,7 @@ SparseNodeData< DualPointInfoBrood< Dim , Real , T , PointD > , IsotropicUIntPac // Set the interior values _setInterpolationInfoFromChildren( _spaceRoot , iInfo ); - ThreadPool::Parallel_for( 0 , iInfo.size() , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( 0 , iInfo.size() , [&]( unsigned int , size_t i ) { iInfo[i].finalize(); for( size_t c=0 ; c , Is // Set the interior values _setInterpolationInfoFromChildren( _spaceRoot , iInfo ); - ThreadPool::Parallel_for( 0 , iInfo.size() , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( 0 , iInfo.size() , [&]( unsigned int , size_t i ) { iInfo[i].finalize(); for( size_t c=0 ; c Degree( "degree" , DEFAULT_FEM_DEGREE ) , #endif // FAST_COMPILE ParallelType( "parallel" , 0 ) , - ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , - ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , - Threads( "threads" , (int)std::thread::hardware_concurrency() ) , + ScheduleType( "schedule" , (int)ThreadPool::Schedule ) , + ThreadChunkSize( "chunkSize" , (int)ThreadPool::ChunkSize ) , MaxMemoryGB( "maxMemory" , 0 ) , GSIterations( "iters" , 8 ) , FullDepth( "fullDepth" , 6 ) , @@ -79,7 +78,7 @@ CmdLineParameter< float > CmdLineReadable* params[] = { - &In , &Out , &Threads , &Verbose , &ShowResidual , &GSIterations , &FullDepth , + &In , &Out , &Verbose , &ShowResidual , &GSIterations , &FullDepth , &BaseDepth , &BaseVCycles , &WeightScale , &WeightExponent , &Performance , @@ -103,7 +102,6 @@ void ShowUsage( char* ex ) #endif // !FAST_COMPILE printf( "\t[--%s =%d]\n" , GSIterations.name , GSIterations.value ); printf( "\t[--%s =%d]\n" , FullDepth.name , FullDepth.value ); - printf( "\t[--%s =%d]\n" , Threads.name , Threads.value ); printf( "\t[--%s =%d]\n" , ParallelType.name , ParallelType.value ); for( size_t i=0 ; i=%d]\n" , ScheduleType.name , ScheduleType.value ); @@ -224,7 +222,7 @@ struct BufferedImageDerivativeStream : public FEMTreeInitializer< DEFAULT_DIMENS _labels->nextRow( __labelRow ); for( int i=0 ; i<(int)_resolution[0] ; i++ ) labelRow[i][0] = labelRow[i][1] = labelRow[i][2] = __labelRow[i]; } - ThreadPool::Parallel_for( 0 , _resolution[0] , [&]( unsigned int , size_t i ){ maskRow[i] = labelRow[i].mask(); } ); + ThreadPool::ParallelFor( 0 , _resolution[0] , [&]( unsigned int , size_t i ){ maskRow[i] = labelRow[i].mask(); } ); } } @@ -276,7 +274,7 @@ struct BufferedImageDerivativeStream : public FEMTreeInitializer< DEFAULT_DIMENS template< typename Real , unsigned int Degree > void _Execute( void ) { - ThreadPool::Init( (ThreadPool::ParallelType)ParallelType.value , Threads.value ); + ThreadPool::ParallelizationType= (ThreadPool::ParallelType)ParallelType.value; int w , h; { unsigned int _w , _h , _c; @@ -429,7 +427,7 @@ void _Execute( void ) { in->nextRow( inRow ); RGBPixel *_inRow = inRows[block&1] + rr*w; - ThreadPool::Parallel_for( 0 , w , [&]( unsigned int , size_t i ){ _inRow[i][0] = _inRow[i][1] = _inRow[i][2] = inRow[i]; } ); + ThreadPool::ParallelFor( 0 , w , [&]( unsigned int , size_t i ){ _inRow[i][0] = _inRow[i][1] = _inRow[i][2] = inRow[i]; } ); } } }; @@ -458,7 +456,7 @@ void _Execute( void ) begin[0] = 0 , begin[1] = rStart , end[0] = w , end[1] = rEnd; Pointer( Point< Real , Colors > ) outBlock = tree.template regularGridUpSample< true >( solution , begin , end ); int size = (rEnd-rStart)*w; - ThreadPool::Parallel_for( 0 , size , [&]( unsigned int , size_t ii ) + ThreadPool::ParallelFor( 0 , size , [&]( unsigned int , size_t ii ) { Point< Real , Colors > c = Point< Real , Colors >( _inRows[ii][0] , _inRows[ii][1] , _inRows[ii][2] ) / 255; c += outBlock[ii] - average; @@ -510,8 +508,8 @@ int main( int argc , char* argv[] ) #endif // ARRAY_DEBUG CmdLineParse( argc-1 , &argv[1] , params ); if( MaxMemoryGB.value>0 ) SetPeakMemoryMB( MaxMemoryGB.value<<10 ); - ThreadPool::DefaultChunkSize = ThreadChunkSize.value; - ThreadPool::DefaultSchedule = (ThreadPool::ScheduleType)ScheduleType.value; + ThreadPool::ChunkSize = ThreadChunkSize.value; + ThreadPool::Schedule = (ThreadPool::ScheduleType)ScheduleType.value; if( Verbose.set ) { printf( "*********************************************\n" ); @@ -519,7 +517,6 @@ int main( int argc , char* argv[] ) printf( "** Running Image Stitching (Version %s) **\n" , ADAPTIVE_SOLVERS_VERSION ); printf( "*********************************************\n" ); printf( "*********************************************\n" ); - if( !Threads.set ) printf( "Running with %d threads\n" , Threads.value ); } if( !In.set ) diff --git a/Src/MultiThreading.h b/Src/MultiThreading.h index 6a33ec21..f71e5005 100644 --- a/Src/MultiThreading.h +++ b/Src/MultiThreading.h @@ -29,123 +29,16 @@ DAMAGE. #define MULTI_THREADING_INCLUDED #include -#include -#if defined( _WIN32 ) || defined( _WIN64 ) -#include -#include -#include -#else // !_WIN32 && !_WIN64 -#include -#include -#include -#endif // _WIN32 || _WIN64 -#include #include #include -#include #include #include #ifdef _OPENMP #include #endif // _OPENMP -#include "Array.h" -#include "MyAtomic.h" namespace PoissonRecon { -#ifdef USE_HH_THREADS - namespace hh - { - inline int get_max_threads( void ) { return std::max< int >( (int)std::thread::hardware_concurrency() , 1 ); } - - class ThreadPoolIndexedTask - { - public: - using Task = std::function< void (int) >; - ThreadPoolIndexedTask( void ) - { - const int num_threads = get_max_threads()-1; - _threads.reserve( num_threads ); - for( int i=0 ; i lock( _mutex ); - if( !_running ) ERROR_OUT( "not running" ); - if( _num_remaining_tasks ) ERROR_OUT( "tasks remaining" ); - if( _task_index!=_num_tasks ) ERROR_OUT( "task index and num tasks don't match" ); - _running = false; - _task_index = 0; - _num_tasks = 1; - _condition_variable_worker.notify_all(); - } - for( int i=0 ; i<_threads.size() ; i++ ) _threads[i].join(); - } - int num_threads( void ) const { return (int)_threads.size()+1; } - bool already_active( void ) const { return _num_remaining_tasks!=0; } // detect nested execution - void execute( int num_tasks , const Task& task_function ) - { - if( already_active() ) - { - WARN( "Nested execution of ThreadPoolIndexedTask is run serially" ); - for( int i=0 ; i lock( _mutex ); - _task_function = task_function; - _num_tasks = num_tasks; - _num_remaining_tasks = num_tasks; - _task_index = 0; - _condition_variable_worker.notify_all(); - _condition_variable_master.wait( lock , [this]{ return !_num_remaining_tasks; } ); - } - } - static ThreadPoolIndexedTask& default_threadpool( void ) - { - static std::unique_ptr< ThreadPoolIndexedTask > thread_pool; - // This is safe because thread_pool is nullptr only in the main thread before any other thread is launched. - if( !thread_pool ) thread_pool = std::unique_ptr< ThreadPoolIndexedTask >( new ThreadPoolIndexedTask() ); - return *thread_pool; - } - - private: - std::mutex _mutex; - bool _running = true; - std::vector< std::thread > _threads; - Task _task_function; - int _num_tasks = 0; - int _num_remaining_tasks = 0; - int _task_index = 0; - std::condition_variable _condition_variable_worker; - std::condition_variable _condition_variable_master; - - void worker_main( void ) - { - std::unique_lock< std::mutex > lock( _mutex ); - // Consider: https://stackoverflow.com/questions/233127/how-can-i-propagate-exceptions-between-threads - // However, rethrowing the exception in the main thread loses the stack state, so not useful for debugging. - for (;;) - { - _condition_variable_worker.wait( lock , [this]{ return _task_index < _num_tasks; } ); - if( !_running ) break; - while( _task_index<_num_tasks ) - { - int i = _task_index++; - lock.unlock(); - _task_function(i); - lock.lock(); - if( _num_remaining_tasks<=0 ) ERROR_OUT( "num remaining tasks not greater than zero" ); - if (!--_num_remaining_tasks) _condition_variable_master.notify_all(); - } - } - } - }; - } -#endif // USE_HH_THREADS - struct ThreadPool { enum ParallelType @@ -153,10 +46,6 @@ namespace PoissonRecon #ifdef _OPENMP OPEN_MP , #endif // _OPENMP - THREAD_POOL , -#ifdef USE_HH_THREADS - THREAD_POOL_HH , -#endif // USE_HH_THREADS ASYNC , NONE }; @@ -169,8 +58,10 @@ namespace PoissonRecon }; static const std::vector< std::string > ScheduleNames; - static size_t DefaultChunkSize; - static ScheduleType DefaultSchedule; + static unsigned int NumThreads( void ){ return _NumThreads; } + static ParallelType ParallelizationType; + static size_t ChunkSize; + static ScheduleType Schedule; template< typename Function , typename ... Functions > static void ParallelSections( const Function &function , const Functions & ... functions ) @@ -185,16 +76,15 @@ namespace PoissonRecon for( unsigned int i=0 ; i &iterationFunction , ScheduleType schedule=DefaultSchedule , size_t chunkSize=DefaultChunkSize ) + static void ParallelFor( size_t begin , size_t end , const std::function< void ( unsigned int , size_t ) > &iterationFunction , unsigned int numThreads=_NumThreads , ParallelType pType=ParallelizationType , ScheduleType schedule=Schedule , size_t chunkSize=ChunkSize ) { if( begin>=end ) return; size_t range = end - begin; size_t chunks = ( range + chunkSize - 1 ) / chunkSize; - unsigned int threads = (unsigned int)NumThreads(); std::atomic< size_t > index; index.store( 0 ); - if( range( end , _begin+chunkSize ); for( size_t i=_begin ; i<_end ; i++ ) iterationFunction( thread , i ); }; - std::function< void (unsigned int ) > _StaticThreadFunction = [ &_ChunkFunction , chunks , threads ]( unsigned int thread ) + std::function< void (unsigned int ) > _StaticThreadFunction = [ &_ChunkFunction , chunks , numThreads ]( unsigned int thread ) { - for( size_t chunk=thread ; chunk _DynamicThreadFunction = [ &_ChunkFunction , chunks , &index ]( unsigned int thread ) { size_t chunk; while( ( chunk=index.fetch_add(1) ) lock( _Mutex ); - - if ( schedule==STATIC ) _ThreadFunction = _StaticThreadFunction; - else if( schedule==DYNAMIC ) _ThreadFunction = _DynamicThreadFunction; - } + std::function< void (unsigned int ) > ThreadFunction; + if ( schedule==ScheduleType::STATIC ) ThreadFunction = _StaticThreadFunction; + else if( schedule==ScheduleType::DYNAMIC ) ThreadFunction = _DynamicThreadFunction; if( false ){} #ifdef _OPENMP - else if( _ParallelType==OPEN_MP ) + else if( pType==ParallelType::OPEN_MP ) { - if( schedule==STATIC ) -#pragma omp parallel for num_threads( threads ) schedule( static , 1 ) + if( schedule==ScheduleType::STATIC ) +#pragma omp parallel for num_threads( numThreads ) schedule( static , 1 ) for( int c=0 ; c( threads , range ); - hh::ThreadPoolIndexedTask* const thread_pool = &hh::ThreadPoolIndexedTask::default_threadpool(); - if( !thread_pool || thread_pool->already_active() ) - { - // Traverse the range elements sequentially. - for( size_t index=begin ; indexexecute( num_threads , _ThreadFunction ); - } -#endif // USE_HH_THREADS - else if( _ParallelType==ASYNC ) + else if( pType==ParallelType::ASYNC ) { static std::vector< std::future< void > > futures; - futures.resize( threads-1 ); - for( unsigned int t=1 ; t lock( _Mutex ); - _DoneWithWork.wait( lock , [&]( void ){ return _RemainingTasks==0; } ); - } - } + futures.resize( numThreads-1 ); + for( unsigned int t=1 ; t static void _ParallelSections( std::vector< std::future< void > > &futures , const Function &function , const Functions & ... functions ) @@ -324,64 +142,18 @@ namespace PoissonRecon futures.push_back( std::async( std::launch::async , function ) ); if constexpr( sizeof...(Functions) ) _ParallelSections( futures , functions... ); } - - static void _ThreadInitFunction( unsigned int thread ) - { - // Wait for the first job to come in - std::unique_lock< std::mutex > lock( _Mutex ); - _WaitingForWorkOrClose.wait( lock ); - - while( !_Close ) - { - // do the job - _ThreadFunction( thread ); - - // Notify and wait for the next job - _RemainingTasks--; - if( !_RemainingTasks ) _DoneWithWork.notify_all(); - _WaitingForWorkOrClose.wait( lock ); - } - } - -#ifdef SANITIZED_PR - static std::atomic< bool > _Close; - static std::atomic< unsigned int > _RemainingTasks; -#else // !SANITIZED_PR - static bool _Close; - static volatile unsigned int _RemainingTasks; -#endif // SANITIZED_PR - static std::mutex _Mutex; - static std::condition_variable _WaitingForWorkOrClose , _DoneWithWork; - static std::vector< std::thread > _Threads; - static std::function< void ( unsigned int ) > _ThreadFunction; - static ParallelType _ParallelType; }; - size_t ThreadPool::DefaultChunkSize = 128; - ThreadPool::ScheduleType ThreadPool::DefaultSchedule = ThreadPool::DYNAMIC; -#ifdef SANITIZED_PR - std::atomic< bool > ThreadPool::_Close; - std::atomic< unsigned int > ThreadPool::_RemainingTasks; -#else // !SANITIZED_PR - bool ThreadPool::_Close; - volatile unsigned int ThreadPool::_RemainingTasks; -#endif // SANITIZED_PR - std::mutex ThreadPool::_Mutex; - std::condition_variable ThreadPool::_WaitingForWorkOrClose; - std::condition_variable ThreadPool::_DoneWithWork; - std::vector< std::thread > ThreadPool::_Threads; - std::function< void ( unsigned int ) > ThreadPool::_ThreadFunction; - ThreadPool::ParallelType ThreadPool::_ParallelType; + unsigned int ThreadPool::_NumThreads = std::thread::hardware_concurrency(); + ThreadPool::ParallelType ThreadPool::ParallelizationType = ThreadPool::ParallelType::NONE; + ThreadPool::ScheduleType ThreadPool::Schedule = ThreadPool::DYNAMIC; + size_t ThreadPool::ChunkSize = 128; const std::vector< std::string > ThreadPool::ParallelNames = { #ifdef _OPENMP "open mp" , #endif // _OPENMP - "thread pool" , -#ifdef USE_HH_THREADS - "thread pool (hh)" , -#endif // USE_HH_THREADS "async" , "none" }; diff --git a/Src/PointInterpolant.cpp b/Src/PointInterpolant.cpp index e56acbcf..701688cc 100644 --- a/Src/PointInterpolant.cpp +++ b/Src/PointInterpolant.cpp @@ -89,9 +89,8 @@ CmdLineParameter< int > #endif // !FAST_COMPILE MaxMemoryGB( "maxMemory" , 0 ) , ParallelType( "parallel" , 0 ) , - ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , - ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , - Threads( "threads" , (int)std::thread::hardware_concurrency() ); + ScheduleType( "schedule" , (int)ThreadPool::Schedule ) , + ThreadChunkSize( "chunkSize" , (int)ThreadPool::ChunkSize ); CmdLineParameter< float > Scale( "scale" , 1.1f ) , @@ -116,7 +115,7 @@ CmdLineReadable* params[] = &NonManifold , &PolygonMesh , &ASCII , &ShowResidual , &ValueWeight , &GradientWeight , &LapWeight , &BiLapWeight , - &Grid , &Threads , + &Grid , &Tree , &FullDepth , &BaseDepth , &BaseVCycles , @@ -161,7 +160,6 @@ void ShowUsage(char* ex) printf( "\t[--%s =%.3e]\n" , BiLapWeight.name , BiLapWeight.value ); printf( "\t[--%s =%d]\n" , Iters.name , Iters.value ); printf( "\t[--%s]\n" , ExactInterpolation.name ); - printf( "\t[--%s =%d]\n" , Threads.name , Threads.value ); printf( "\t[--%s =%d]\n" , ParallelType.name , ParallelType.value ); for( size_t i=0 ; i=%d]\n" , ScheduleType.name , ScheduleType.value ); @@ -400,14 +398,14 @@ void WriteGrid( const char *fileName , ConstPointer( Real ) values , unsigned in // Compute average Real avg = 0; std::vector< Real > avgs( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , totalResolution , [&]( unsigned int thread , size_t i ){ avgs[thread] += values[i]; } ); + ThreadPool::ParallelFor( 0 , totalResolution , [&]( unsigned int thread , size_t i ){ avgs[thread] += values[i]; } ); for( unsigned int t=0 ; t stds( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , totalResolution , [&]( unsigned int thread , size_t i ){ stds[thread] += ( values[i] - avg ) * ( values[i] - avg ); } ); + ThreadPool::ParallelFor( 0 , totalResolution , [&]( unsigned int thread , size_t i ){ stds[thread] += ( values[i] - avg ) * ( values[i] - avg ); } ); for( unsigned int t=0 ; t( (Real)1. , std::max< Real >( (Real)-1. , ( values[i] - avg ) / (2*std ) ) ); v = (Real)( ( v + 1. ) / 2. * 256. ); @@ -545,10 +543,9 @@ void Execute( UIntPack< FEMSigs ... > ) std::cout << "** Running Point Interpolant (Version " << ADAPTIVE_SOLVERS_VERSION << ") **" << std::endl; std::cout << "***********************************************" << std::endl; std::cout << "***********************************************" << std::endl; - if( !Threads.set ) std::cout << "Running with " << Threads.value << " threads" << std::endl; } - ThreadPool::Init( (ThreadPool::ParallelType)ParallelType.value , Threads.value ); + ThreadPool::ParallelizationType= (ThreadPool::ParallelType)ParallelType.value; XForm< Real , Dim+1 > modelToUnitCube , unitCubeToModel; if( Transform.set ) @@ -805,7 +802,7 @@ void Execute( UIntPack< FEMSigs ... > ) typename FEMTree< Dim , Real >::template MultiThreadedEvaluator< Sigs , 0 > evaluator( &tree , solution ); std::pair< double , double > valueStat(0,0); std::vector< std::pair< double , double > > valueStats( ThreadPool::NumThreads() , std::pair< double , double >(0,0) ); - ThreadPool::Parallel_for( 0 , valueSamples->size() , [&]( unsigned int thread , size_t j ) + ThreadPool::ParallelFor( 0 , valueSamples->size() , [&]( unsigned int thread , size_t j ) { ProjectiveData< Point< Real , Dim > , Real >& sample = (*valueSamples)[j].sample; Real w = sample.weight; @@ -827,7 +824,7 @@ void Execute( UIntPack< FEMSigs ... > ) typename FEMTree< Dim , Real >::template MultiThreadedEvaluator< Sigs , 1 > evaluator( &tree , solution ); std::pair< double , double > gradientStat(0,0); std::vector< std::pair< double , double > > gradientStats( ThreadPool::NumThreads() , std::pair< double , double >(0,0) ); - ThreadPool::Parallel_for( 0 , gradientSamples->size() , [&]( unsigned int thread , size_t j ) + ThreadPool::ParallelFor( 0 , gradientSamples->size() , [&]( unsigned int thread , size_t j ) { ProjectiveData< Point< Real , Dim > , Real >& sample = (*gradientSamples)[j].sample; Real w = sample.weight; @@ -958,8 +955,8 @@ int main( int argc , char* argv[] ) CmdLineParse( argc-1 , &argv[1] , params ); if( MaxMemoryGB.value>0 ) SetPeakMemoryMB( MaxMemoryGB.value<<10 ); - ThreadPool::DefaultChunkSize = ThreadChunkSize.value; - ThreadPool::DefaultSchedule = (ThreadPool::ScheduleType)ScheduleType.value; + ThreadPool::ChunkSize = ThreadChunkSize.value; + ThreadPool::Schedule = (ThreadPool::ScheduleType)ScheduleType.value; if( !InValues.set && !InGradients.set ) { diff --git a/Src/PoissonRecon.client.inl b/Src/PoissonRecon.client.inl index 8cfc1e42..2f616dad 100644 --- a/Src/PoissonRecon.client.inl +++ b/Src/PoissonRecon.client.inl @@ -652,8 +652,8 @@ void Client< Real , Dim , BType , Degree >::_process1( const ClientReconstructio #endif // ADAPTIVE_PADDING } - ThreadPool::Parallel_for( 0 , _normalInfo->size() , [&]( unsigned int , size_t i ){ (*_normalInfo)[i] *= (Real)-1.; } ); - ThreadPool::Parallel_for( 0 , _paddedNormalInfo->size() , [&]( unsigned int , size_t i ){ (*_paddedNormalInfo)[i] *= (Real)-1.; } ); + ThreadPool::ParallelFor( 0 , _normalInfo->size() , [&]( unsigned int , size_t i ){ (*_normalInfo)[i] *= (Real)-1.; } ); + ThreadPool::ParallelFor( 0 , _paddedNormalInfo->size() , [&]( unsigned int , size_t i ){ (*_paddedNormalInfo)[i] *= (Real)-1.; } ); profiler.update(); if( clientReconInfo.verbose>1 ) { @@ -1122,7 +1122,7 @@ std::pair< double , double > Client< Real , Dim , BType , Degree >::_process5( c Timer timer; typename FEMTree< Dim , Real >::template MultiThreadedEvaluator< Sigs , 0 > evaluator( &_tree , _solution ); std::vector< double > valueSums( ThreadPool::NumThreads() , 0 ) , weightSums( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , _samples.size() , [&]( unsigned int thread , size_t j ) + ThreadPool::ParallelFor( 0 , _samples.size() , [&]( unsigned int thread , size_t j ) { ProjectiveData< Point< Real , Dim > , Real > &sample = _samples[j].sample; Real w = sample.weight; diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index 48c703b7..6080f08b 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -90,9 +90,8 @@ CmdLineParameter< int > MaxMemoryGB( "maxMemory" , 0 ) , ParallelType( "parallel" , 0 ) , AlignmentDir( "alignDir" , DEFAULT_DIMENSION-1 ) , - ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , - ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , - Threads( "threads" , (int)std::thread::hardware_concurrency() ); + ScheduleType( "schedule" , (int)ThreadPool::Schedule ) , + ThreadChunkSize( "chunkSize" , (int)ThreadPool::ChunkSize ); CmdLineParameter< float > DataX( "data" , 32.f ) , @@ -122,7 +121,7 @@ CmdLineReadable* params[] = &ConfidenceBias , &BaseDepth , &BaseVCycles , &PointWeight , - &Grid , &Threads , + &Grid , &Tree , &Density , &FullDepth , @@ -175,7 +174,6 @@ void ShowUsage(char* ex) printf( "\t[--%s =%f]\n" , DataX.name , DataX.value ); printf( "\t[--%s]\n" , Colors.name ); printf( "\t[--%s]\n" , Gradients.name ); - printf( "\t[--%s =%d]\n" , Threads.name , Threads.value ); printf( "\t[--%s =%d]\n" , ParallelType.name , ParallelType.value ); for( size_t i=0 ; i=%d]\n" , ScheduleType.name , ScheduleType.value ); @@ -299,7 +297,6 @@ void Execute( const AuxDataFactory &auxDataFactory ) std::cout << "** Running Screened Poisson Reconstruction (Version " << ADAPTIVE_SOLVERS_VERSION << ") **" << std::endl; std::cout << "*************************************************************" << std::endl; std::cout << "*************************************************************" << std::endl; - if( !Threads.set ) std::cout << "Running with " << Threads.value << " threads" << std::endl; char str[1024]; for( int i=0 ; params[i] ; i++ ) if( params[i]->set ) @@ -606,9 +603,9 @@ int main( int argc , char* argv[] ) #endif // ARRAY_DEBUG CmdLineParse( argc-1 , &argv[1] , params ); if( MaxMemoryGB.value>0 ) SetPeakMemoryMB( MaxMemoryGB.value<<10 ); - ThreadPool::DefaultChunkSize = ThreadChunkSize.value; - ThreadPool::DefaultSchedule = (ThreadPool::ScheduleType)ScheduleType.value; - ThreadPool::Init( (ThreadPool::ParallelType)ParallelType.value , Threads.value ); + ThreadPool::ChunkSize = ThreadChunkSize.value; + ThreadPool::Schedule = (ThreadPool::ScheduleType)ScheduleType.value; + ThreadPool::ParallelizationType= (ThreadPool::ParallelType)ParallelType.value; if( !In.set ) { @@ -680,6 +677,5 @@ int main( int argc , char* argv[] ) printf( "Peak Memory (MB): %d\n" , MemoryInfo::PeakMemoryUsageMB() ); } - ThreadPool::Terminate(); return EXIT_SUCCESS; } diff --git a/Src/PoissonReconClient.cpp b/Src/PoissonReconClient.cpp index 2ad9dad0..329ea045 100644 --- a/Src/PoissonReconClient.cpp +++ b/Src/PoissonReconClient.cpp @@ -51,9 +51,8 @@ CmdLineParameter< std::string > CmdLineParameter< int > MaxMemoryGB( "maxMemory" , 0 ) , ParallelType( "parallel" , 0 ) , - ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , - ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , - Threads( "threads" , (int)std::thread::hardware_concurrency() ) , + ScheduleType( "schedule" , (int)ThreadPool::Schedule ) , + ThreadChunkSize( "chunkSize" , (int)ThreadPool::ChunkSize ) , MultiClient( "multi" , 1 ) , Port( "port" , 0 ) , PeakMemorySampleMS( "sampleMS" , 10 ); @@ -65,7 +64,7 @@ CmdLineReadable CmdLineReadable* params[] = { &Port , &MultiClient , &Address , - &MaxMemoryGB , &ParallelType , &ScheduleType , &ThreadChunkSize , &Threads , + &MaxMemoryGB , &ParallelType , &ScheduleType , &ThreadChunkSize , &Pause , &PeakMemorySampleMS , NULL @@ -77,7 +76,6 @@ void ShowUsage( char* ex ) printf( "\t --%s \n" , Port.name ); printf( "\t[--%s =%d]\n" , MultiClient.name , MultiClient.value ); printf( "\t[--%s =%s]\n" , Address.name , Address.value.c_str() ); - printf( "\t[--%s =%d]\n" , Threads.name , Threads.value ); printf( "\t[--%s =%d]\n" , ParallelType.name , ParallelType.value ); for( size_t i=0 ; i=%d]\n" , ScheduleType.name , ScheduleType.value ); @@ -174,9 +172,9 @@ int main( int argc , char* argv[] ) } if( MaxMemoryGB.value>0 ) SetPeakMemoryMB( MaxMemoryGB.value<<10 ); - ThreadPool::DefaultChunkSize = ThreadChunkSize.value; - ThreadPool::DefaultSchedule = (ThreadPool::ScheduleType)ScheduleType.value; - ThreadPool::Init( (ThreadPool::ParallelType)ParallelType.value , Threads.value ); + ThreadPool::ChunkSize = ThreadChunkSize.value; + ThreadPool::Schedule = (ThreadPool::ScheduleType)ScheduleType.value; + ThreadPool::ParallelizationType= (ThreadPool::ParallelType)ParallelType.value; std::vector< Socket > serverSockets( MultiClient.value , NULL ); for( unsigned int i=0 ; i<(unsigned int)MultiClient.value ; i++ ) serverSockets[i] = GetConnectSocket( Address.value.c_str() , Port.value , SOCKET_CONNECT_WAIT , false ); @@ -195,8 +193,6 @@ int main( int argc , char* argv[] ) for( unsigned int i=0 ; i MaxMemoryGB( "maxMemory" , 0 ) , PeakMemorySampleMS( "sampleMS" , 10 ) , ParallelType( "parallel" , 0 ) , - ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , - ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , + ScheduleType( "schedule" , (int)ThreadPool::Schedule ) , + ThreadChunkSize( "chunkSize" , (int)ThreadPool::ChunkSize ) , MergeSlabs( "merge" , MergeSlabType::SEAMLESS ) , - AlignmentDir( "alignDir" , -1 ) , - Threads( "threads" , (int)std::thread::hardware_concurrency() ) ; + AlignmentDir( "alignDir" , -1 ); CmdLineReadable Performance( "performance" ) , @@ -132,7 +131,7 @@ CmdLineReadable* params[] = &MergeSlabs , &Width , &Confidence , &ConfidenceBias , &SamplesPerNode , &DataX , &PointWeight , &CGSolverAccuracy , &TargetValue , - &MaxMemoryGB , &ParallelType , &ScheduleType , &ThreadChunkSize , &Threads , + &MaxMemoryGB , &ParallelType , &ScheduleType , &ThreadChunkSize , &PeakMemorySampleMS , &OutputVoxelGrid , &OutputBoundarySlices , @@ -177,7 +176,6 @@ void ShowUsage( char* ex ) printf( "\t[--%s =%f]\n" , DataX.name , DataX.value ); printf( "\t[--%s =%d]\n" , PadSize.name , PadSize.value ); printf( "\t[--%s =%d]\n" , BufferSize.name , BufferSize.value ); - printf( "\t[--%s =%d]\n" , Threads.name , Threads.value ); printf( "\t[--%s =%d]\n" , ParallelType.name , ParallelType.value ); for( size_t i=0 ; i=%d]\n" , ScheduleType.name , ScheduleType.value ); @@ -412,10 +410,9 @@ int main( int argc , char* argv[] ) } if( MaxMemoryGB.value>0 ) SetPeakMemoryMB( MaxMemoryGB.value<<10 ); - ThreadPool::DefaultChunkSize = ThreadChunkSize.value; - ThreadPool::DefaultSchedule = (ThreadPool::ScheduleType)ScheduleType.value; - ThreadPool::Init( (ThreadPool::ParallelType)ParallelType.value , Threads.value ); - if( !Threads.set && Verbose.value>1 ) std::cout << "Running with " << Threads.value << " threads" << std::endl; + ThreadPool::ChunkSize = ThreadChunkSize.value; + ThreadPool::Schedule = (ThreadPool::ScheduleType)ScheduleType.value; + ThreadPool::ParallelizationType= (ThreadPool::ParallelType)ParallelType.value; std::string header; // Create the connections to the clients @@ -617,7 +614,5 @@ int main( int argc , char* argv[] ) } } - ThreadPool::Terminate(); - return EXIT_SUCCESS; } diff --git a/Src/Rasterizer.inl b/Src/Rasterizer.inl index 6b4c2147..5fe3374b 100644 --- a/Src/Rasterizer.inl +++ b/Src/Rasterizer.inl @@ -169,7 +169,7 @@ typename Rasterizer< Real , Dim >::template SimplexRasterizationGrid< IndexType if( threadSafety.lockDepth>depth ) ERROR_OUT( "Lock depth cannot excceed depth: " , threadSafety.lockDepth , " <= " , depth ); _RegularGridMutexes mutexes( threadSafety.lockDepth , depth ); - ThreadPool::Parallel_for( 0 , simplicialComplex.size() , [&]( unsigned int t , size_t i ) + ThreadPool::ParallelFor( 0 , simplicialComplex.size() , [&]( unsigned int t , size_t i ) { std::vector< Simplex< Real , Dim , K > > subSimplices; subSimplices.push_back( simplicialComplex[i] ); @@ -234,7 +234,7 @@ typename Rasterizer< Real , Dim >::template SimplexRasterizationGrid< IndexType } // Map - ThreadPool::Parallel_for( 0 , simplicialComplex.size() , [&]( unsigned int t , size_t i ) + ThreadPool::ParallelFor( 0 , simplicialComplex.size() , [&]( unsigned int t , size_t i ) { std::vector< Simplex< Real , Dim , K > > subSimplices; subSimplices.push_back( simplicialComplex[i] ); @@ -261,7 +261,7 @@ typename Rasterizer< Real , Dim >::template SimplexRasterizationGrid< IndexType } ); // Reduce - ThreadPool::Parallel_for( 0 , raster.resolution() , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( 0 , raster.resolution() , [&]( unsigned int , size_t i ) { size_t count = 0; for( int t=0 ; t0 ) *normalInfo = implicit.tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , implicit.density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionAndBiasFunction ); else *normalInfo = implicit.tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , implicit.density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionFunction ); - ThreadPool::Parallel_for( 0 , normalInfo->size() , [&]( unsigned int , size_t i ){ (*normalInfo)[i] *= (Real)-1.; } ); + ThreadPool::ParallelFor( 0 , normalInfo->size() , [&]( unsigned int , size_t i ){ (*normalInfo)[i] *= (Real)-1.; } ); if( params.verbose ) { std::cout << "# Got normal field: " << profiler << std::endl; @@ -865,7 +865,7 @@ namespace PoissonRecon for( int i=0 ; i > _vectorFieldElements( baseNodes.size() ); for( int i=0 ; i<_vectorFieldElements.size() ; i++ ) _vectorFieldElements[i].reserve( vectorFieldElementCounts[i] ); - ThreadPool::Parallel_for( 0 , baseNodes.size() , [&]( unsigned int t , size_t i ) + ThreadPool::ParallelFor( 0 , baseNodes.size() , [&]( unsigned int t , size_t i ) { auto nodeFunctor = [&]( FEMTreeNode *node ) { @@ -902,10 +902,10 @@ namespace PoissonRecon implicit.tree.template processNeighboringLeaves< -BSplineSupportSizes< Poisson::NormalDegree >::SupportStart , BSplineSupportSizes< Poisson::NormalDegree >::SupportEnd >( &vectorFieldElements[0] , vectorFieldElements.size() , SetScratchFlag , false ); // Set sub-trees rooted at interior nodes @ ExactDepth to interior - ThreadPool::Parallel_for( 0 , baseNodes.size() , [&]( unsigned int , size_t i ){ if( baseNodes[i]->nodeData.getScratchFlag() ) PropagateToLeaves( baseNodes[i] ); } ); + ThreadPool::ParallelFor( 0 , baseNodes.size() , [&]( unsigned int , size_t i ){ if( baseNodes[i]->nodeData.getScratchFlag() ) PropagateToLeaves( baseNodes[i] ); } ); // Adjust the coarser node designators in case exterior nodes have become boundary. - ThreadPool::Parallel_for( 0 , baseNodes.size() , [&]( unsigned int , size_t i ){ FEMTreeInitializer< Dim , Real >::PullGeometryNodeDesignatorsFromFiner( baseNodes[i] , geometryNodeDesignators ); } ); + ThreadPool::ParallelFor( 0 , baseNodes.size() , [&]( unsigned int , size_t i ){ FEMTreeInitializer< Dim , Real >::PullGeometryNodeDesignatorsFromFiner( baseNodes[i] , geometryNodeDesignators ); } ); FEMTreeInitializer< Dim , Real >::PullGeometryNodeDesignatorsFromFiner( &implicit.tree.spaceRoot() , geometryNodeDesignators , params.baseDepth ); } } @@ -1015,7 +1015,7 @@ namespace PoissonRecon double valueSum = 0 , weightSum = 0; typename FEMTree< Dim , Real >::template MultiThreadedEvaluator< Sigs , 0 > evaluator( &implicit.tree , implicit.solution ); std::vector< double > valueSums( ThreadPool::NumThreads() , 0 ) , weightSums( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , samples->size() , [&]( unsigned int thread , size_t j ) + ThreadPool::ParallelFor( 0 , samples->size() , [&]( unsigned int thread , size_t j ) { ProjectiveData< Point< Real , Dim > , Real >& sample = (*samples)[j].sample; Real w = sample.weight; @@ -1320,7 +1320,7 @@ namespace PoissonRecon double valueSum = 0 , weightSum = 0; typename FEMTree< Dim , Real >::template MultiThreadedEvaluator< Sigs , 0 > evaluator( &implicit.tree , implicit.solution ); std::vector< double > valueSums( ThreadPool::NumThreads() , 0 ) , weightSums( ThreadPool::NumThreads() , 0 ); - ThreadPool::Parallel_for( 0 , samples->size() , [&]( unsigned int thread , size_t j ) + ThreadPool::ParallelFor( 0 , samples->size() , [&]( unsigned int thread , size_t j ) { ProjectiveData< Point< Real , Dim > , Real >& sample = (*samples)[j].sample; Real w = sample.weight; diff --git a/Src/SSDRecon.cpp b/Src/SSDRecon.cpp index 35e78f77..5cea7672 100644 --- a/Src/SSDRecon.cpp +++ b/Src/SSDRecon.cpp @@ -85,15 +85,10 @@ CmdLineParameter< int > BType( "bType" , Reconstructor::SSD::DefaultFEMBoundary+1 ) , #endif // !FAST_COMPILE MaxMemoryGB( "maxMemory" , 0 ) , -#ifdef _OPENMP - ParallelType( "parallel" , (int)ThreadPool::OPEN_MP ) , -#else // !_OPENMP - ParallelType( "parallel" , (int)ThreadPool::THREAD_POOL ) , -#endif // _OPENMP + ParallelType( "parallel" , 0 ) , AlignmentDir( "alignDir" , DEFAULT_DIMENSION-1 ) , - ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , - ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , - Threads( "threads" , (int)std::thread::hardware_concurrency() ); + ScheduleType( "schedule" , (int)ThreadPool::Schedule ) , + ThreadChunkSize( "chunkSize" , (int)ThreadPool::ChunkSize ); CmdLineParameter< float > DataX( "data" , 32.f ) , @@ -121,7 +116,7 @@ CmdLineReadable* params[] = &KernelDepth , &SamplesPerNode , &Confidence , &NonManifold , &PolygonMesh , &ASCII , &ShowResidual , &ConfidenceBias , &ValueWeight , &GradientWeight , &BiLapWeight , - &Grid , &Threads , + &Grid , &Tree , &Density , &FullDepth , @@ -173,7 +168,6 @@ void ShowUsage(char* ex) printf( "\t[--%s =%f]\n" , DataX.name , DataX.value ); printf( "\t[--%s]\n" , Colors.name ); printf( "\t[--%s]\n" , Gradients.name ); - printf( "\t[--%s =%d]\n" , Threads.name , Threads.value ); printf( "\t[--%s =%d]\n" , ParallelType.name , ParallelType.value ); for( size_t i=0 ; i=%d]\n" , ScheduleType.name , ScheduleType.value ); @@ -296,7 +290,6 @@ void Execute( const AuxDataFactory &auxDataFactory ) std::cout << "** Running SSD Reconstruction (Version " << ADAPTIVE_SOLVERS_VERSION << ") **" << std::endl; std::cout << "************************************************" << std::endl; std::cout << "************************************************" << std::endl; - if( !Threads.set ) std::cout << "Running with " << Threads.value << " threads" << std::endl; char str[1024]; for( int i=0 ; params[i] ; i++ ) if( params[i]->set ) @@ -584,9 +577,9 @@ int main( int argc , char* argv[] ) CmdLineParse( argc-1 , &argv[1] , params ); if( MaxMemoryGB.value>0 ) SetPeakMemoryMB( MaxMemoryGB.value<<10 ); - ThreadPool::DefaultChunkSize = ThreadChunkSize.value; - ThreadPool::DefaultSchedule = (ThreadPool::ScheduleType)ScheduleType.value; - ThreadPool::Init( (ThreadPool::ParallelType)ParallelType.value , Threads.value ); + ThreadPool::ChunkSize = ThreadChunkSize.value; + ThreadPool::Schedule = (ThreadPool::ScheduleType)ScheduleType.value; + ThreadPool::ParallelizationType= (ThreadPool::ParallelType)ParallelType.value; if( !In.set ) { @@ -657,6 +650,7 @@ int main( int argc , char* argv[] ) } delete[] ext; #endif // FAST_COMPILE + if( Performance.set ) { printf( "Time (Wall/CPU): %.2f / %.2f\n" , timer.wallTime() , timer.cpuTime() ); diff --git a/Src/SparseMatrix.inl b/Src/SparseMatrix.inl index 52a6eac1..8b897a22 100644 --- a/Src/SparseMatrix.inl +++ b/Src/SparseMatrix.inl @@ -192,7 +192,7 @@ SparseMatrix< T , IndexType , 0 > SparseMatrix< T , IndexType , 0 >::Identity( s template< class T , class IndexType > SparseMatrix< T , IndexType , 0 >& SparseMatrix< T , IndexType , 0 >::operator *= ( T s ) { - ThreadPool::Parallel_for( 0 , rowNum , [&]( unsigned int , size_t i ){ for( size_t j=0 ; j @@ -238,7 +238,7 @@ SparseMatrix< T , IndexType , 0 > SparseMatrix< T , IndexType , 0 >::operator * if( bRows row; for( size_t j=0 ; j SparseMatrix< T , IndexType , 0 >::operator + SparseMatrix out; out.resize( rowNum ); - ThreadPool::Parallel_for( 0 , rowNum , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( 0 , rowNum , [&]( unsigned int , size_t i ) { std::unordered_map< IndexType , T > row; if( i SparseMatrix< T , IndexType , 0 >::operator - SparseMatrix out; out.resize( rowNum ); - ThreadPool::Parallel_for( 0 , rowNum , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( 0 , rowNum , [&]( unsigned int , size_t i ) { std::unordered_map< IndexType , T > row; if( i SparseMatrix< T , IndexType , 0 >::transpose( A.resize( aRows ); const size_t One = 1; for( size_t i=0 ; i SparseMatrix< T , IndexType , 0 >::transpose( } ); - ThreadPool::Parallel_for( 0 , A.rowNum , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( 0 , A.rowNum , [&]( unsigned int , size_t i ) { size_t t = A.rowSizes[i]; A.rowSizes[i] = 0; @@ -382,13 +382,13 @@ SparseMatrix< T , IndexType , 0 > SparseMatrix< T , IndexType , 0 >::transpose( A.resize( aRows ); for( size_t i=0 ; i SparseMatrix< T , IndexType , 0 >::Multiply( c M.resize( aRows ); - ThreadPool::Parallel_for( 0 , aRows , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( 0 , aRows , [&]( unsigned int , size_t i ) { std::unordered_map< IndexType , T > row; for( A_const_iterator iterA=A.begin(i) ; iterA!=A.end(i) ; iterA++ ) @@ -640,7 +640,7 @@ void SparseMatrix< T , IndexType , MaxRowSize >::resetRowSize( size_t row , size template< class T , class IndexType , size_t MaxRowSize > SparseMatrix< T , IndexType , MaxRowSize >& SparseMatrix< T , IndexType , MaxRowSize >::operator *= ( T s ) { - ThreadPool::Parallel_for( 0 , _rowNum*MaxRowSize , [&]( unsigned int , size_t i ){ _entries[i].Value *= s; } ); + ThreadPool::ParallelFor( 0 , _rowNum*MaxRowSize , [&]( unsigned int , size_t i ){ _entries[i].Value *= s; } ); return *this; } diff --git a/Src/SparseMatrixInterface.inl b/Src/SparseMatrixInterface.inl index 27634d8f..d1685ac3 100644 --- a/Src/SparseMatrixInterface.inl +++ b/Src/SparseMatrixInterface.inl @@ -93,7 +93,7 @@ template< class T2 > void SparseMatrixInterface< T , const_iterator >::multiply( ConstPointer( T2 ) In , Pointer( T2 ) Out , char multiplyFlag ) const { ConstPointer( T2 ) in = In; - ThreadPool::Parallel_for( 0 , rows() , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( 0 , rows() , [&]( unsigned int , size_t i ) { T2 temp; memset( &temp , 0 , sizeof(T2) ); @@ -111,7 +111,7 @@ template< class T2 > void SparseMatrixInterface< T , const_iterator >::multiplyScaled( T scale , ConstPointer( T2 ) In , Pointer( T2 ) Out , char multiplyFlag ) const { ConstPointer( T2 ) in = In; - ThreadPool::Parallel_for( 0 , rows() , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( 0 , rows() , [&]( unsigned int , size_t i ) { T2 temp; memset( &temp , 0 , sizeof(T2) ); @@ -129,7 +129,7 @@ void SparseMatrixInterface< T , const_iterator >::multiplyScaled( T scale , Cons template< class T , class const_iterator > void SparseMatrixInterface< T , const_iterator >::setDiagonal( Pointer( T ) diagonal ) const { - ThreadPool::Parallel_for( 0 , rows() , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( 0 , rows() , [&]( unsigned int , size_t i ) { diagonal[i] = (T)0; const_iterator e = end( i ); @@ -141,7 +141,7 @@ void SparseMatrixInterface< T , const_iterator >::setDiagonal( Pointer( T ) diag template< class T , class const_iterator > void SparseMatrixInterface< T , const_iterator >::setDiagonalR( Pointer( T ) diagonal ) const { - ThreadPool::Parallel_for( 0 , rows() , [&]( unsigned int , size_t i ) + ThreadPool::ParallelFor( 0 , rows() , [&]( unsigned int , size_t i ) { diagonal[i] = (T)0; const_iterator e = end( i ); @@ -157,9 +157,9 @@ void SparseMatrixInterface< T , const_iterator >::jacobiIteration( ConstPointer( { multiply( in , out ); if( dReciprocal ) - ThreadPool::Parallel_for( 0 , rows() , [&]( unsigned int , size_t i ){ out[i] = in[i] + ( b[i] - out[i] ) * diagonal[i]; } ); + ThreadPool::ParallelFor( 0 , rows() , [&]( unsigned int , size_t i ){ out[i] = in[i] + ( b[i] - out[i] ) * diagonal[i]; } ); else - ThreadPool::Parallel_for( 0 , rows() , [&]( unsigned int , size_t i ){ out[i] = in[i] + ( b[i] - out[i] ) / diagonal[i]; } ); + ThreadPool::ParallelFor( 0 , rows() , [&]( unsigned int , size_t i ){ out[i] = in[i] + ( b[i] - out[i] ) / diagonal[i]; } ); } template< class T , class const_iterator > template< class T2 > @@ -195,7 +195,7 @@ template< class T2 > void SparseMatrixInterface< T , const_iterator >::gsIteration( const std::vector< size_t >& multiColorIndices , ConstPointer( T ) diagonal , ConstPointer( T2 ) b , Pointer( T2 ) x , bool dReciprocal ) const { if( dReciprocal ) - ThreadPool::Parallel_for( 0 , multiColorIndices.size() , [&]( unsigned int , size_t j ) + ThreadPool::ParallelFor( 0 , multiColorIndices.size() , [&]( unsigned int , size_t j ) { size_t jj = multiColorIndices[j]; T2 _b = b[jj]; @@ -205,7 +205,7 @@ void SparseMatrixInterface< T , const_iterator >::gsIteration( const std::vector } ); else - ThreadPool::Parallel_for( 0 , multiColorIndices.size() , [&]( unsigned int , size_t j ) + ThreadPool::ParallelFor( 0 , multiColorIndices.size() , [&]( unsigned int , size_t j ) { size_t jj = multiColorIndices[j]; T2 _b = b[jj]; @@ -224,7 +224,7 @@ void SparseMatrixInterface< T , const_iterator >::gsIteration( const std::vector { auto Iterate = [&]( const std::vector< size_t > &indices ) { - ThreadPool::Parallel_for( 0 , indices.size() , [&]( unsigned int , size_t k ) + ThreadPool::ParallelFor( 0 , indices.size() , [&]( unsigned int , size_t k ) { size_t jj = indices[k]; T2 _b = b[jj]; @@ -241,7 +241,7 @@ void SparseMatrixInterface< T , const_iterator >::gsIteration( const std::vector { auto Iterate = [&]( const std::vector< size_t > &indices ) { - ThreadPool::Parallel_for( 0 , indices.size() , [&]( unsigned int , size_t k ) + ThreadPool::ParallelFor( 0 , indices.size() , [&]( unsigned int , size_t k ) { size_t jj = indices[k]; T2 _b = b[jj]; @@ -265,7 +265,7 @@ template< class SPDFunctor , class T , typename Real , class TDotTFunctor > size Real delta_new = 0 , delta_0; M( ( ConstPointer( T ) )x , r ); - ThreadPool::Parallel_for( 0 , dim , [&]( unsigned int thread , size_t i ){ d[i] = r[i] = b[i] - r[i] , scratch[thread] += Dot( r[i] , r[i] ); } ); + ThreadPool::ParallelFor( 0 , dim , [&]( unsigned int thread , size_t i ){ d[i] = r[i] = b[i] - r[i] , scratch[thread] += Dot( r[i] , r[i] ); } ); for( unsigned int t=0 ; t size { M( ( ConstPointer( T ) )d , q ); Real dDotQ = 0; - ThreadPool::Parallel_for( 0 , dim , [&]( unsigned int thread , size_t i ){ scratch[thread] += Dot( d[i] , q[i] ); } ); + ThreadPool::ParallelFor( 0 , dim , [&]( unsigned int thread , size_t i ){ scratch[thread] += Dot( d[i] , q[i] ); } ); for( unsigned int t=0 ; t size delta_new = 0; if( (ii%50)==(50-1) ) { - ThreadPool::Parallel_for( 0 , dim , [&]( unsigned int , size_t i ){ x[i] += (T)( d[i] * alpha ); } ); + ThreadPool::ParallelFor( 0 , dim , [&]( unsigned int , size_t i ){ x[i] += (T)( d[i] * alpha ); } ); M( ( ConstPointer( T ) )x , r ); - ThreadPool::Parallel_for( 0 , dim , [&]( unsigned int thread , size_t i ){ r[i] = b[i] - r[i] , scratch[thread] += Dot( r[i] , r[i] ) , x[i] += (T)( d[i] * alpha ); } ); + ThreadPool::ParallelFor( 0 , dim , [&]( unsigned int thread , size_t i ){ r[i] = b[i] - r[i] , scratch[thread] += Dot( r[i] , r[i] ) , x[i] += (T)( d[i] * alpha ); } ); for( unsigned int t=0 ; t static void RunParallel( int begin , int end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) { - ThreadPool::Parallel_for( begin , end , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration-1 >::RunThread( begin , end , thread , updateState , function , w[i] ... ); } ); + ThreadPool::ParallelFor( begin , end , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration-1 >::RunThread( begin , end , thread , updateState , function , w[i] ... ); } ); } template< typename UpdateFunction , typename ProcessFunction , class ... Windows > static void RunParallel( const int* begin , const int* end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) { - ThreadPool::Parallel_for( begin[0] , end[0] , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration-1 >::RunThread( begin+1 , end+1 , thread , updateState , function , w[i] ... ); } ); + ThreadPool::ParallelFor( begin[0] , end[0] , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration-1 >::RunThread( begin+1 , end+1 , thread , updateState , function , w[i] ... ); } ); } template< unsigned int ... Begin , unsigned int ... End , typename UpdateFunction , typename ProcessFunction , class ... Windows > static void RunParallel( UIntPack< Begin ... > begin , UIntPack< End ... > end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) { - ThreadPool::Parallel_for( UIntPack< Begin ... >::First , UIntPack< End ... >::First , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration-1 >::RunThread( typename UIntPack< Begin ... >::Rest() , typename UIntPack< End ... >::Rest() , thread , updateState , function , w[i] ... ); } ); + ThreadPool::ParallelFor( UIntPack< Begin ... >::First , UIntPack< End ... >::First , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration-1 >::RunThread( typename UIntPack< Begin ... >::Rest() , typename UIntPack< End ... >::Rest() , thread , updateState , function , w[i] ... ); } ); } template< typename UpdateFunction , typename ProcessFunction , class ... Windows > @@ -116,17 +116,17 @@ protected: template< typename UpdateFunction , typename ProcessFunction , class ... Windows > static void RunParallel( int begin , int end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) { - ThreadPool::Parallel_for( begin , end , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration-1 >::RunThread( begin , end , thread , updateState , function , w[i] ... ); } ); + ThreadPool::ParallelFor( begin , end , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration-1 >::RunThread( begin , end , thread , updateState , function , w[i] ... ); } ); } template< typename UpdateFunction , typename ProcessFunction , class ... Windows > static void RunParallel( const int* begin , const int* end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) { - ThreadPool::Parallel_for( begin[0] , end[0] , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration-1 >::RunThread( begin+1 , end+1 , thread , updateState , function , w[i] ... ); } ); + ThreadPool::ParallelFor( begin[0] , end[0] , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration-1 >::RunThread( begin+1 , end+1 , thread , updateState , function , w[i] ... ); } ); } template< unsigned int ... Begin , unsigned int ... End , typename UpdateFunction , typename ProcessFunction , class ... Windows > static void RunParallel( UIntPack< Begin ... > begin , UIntPack< End ... > end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) { - ThreadPool::Parallel_for( UIntPack< Begin ... >::First , UIntPack< End ... >::First , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration-1 >::RunThread( typename UIntPack< Begin ... >::Rest() , typename UIntPack< End ... >::Rest() , thread , updateState , function , w[i] ... ); } ); + ThreadPool::ParallelFor( UIntPack< Begin ... >::First , UIntPack< End ... >::First , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration-1 >::RunThread( typename UIntPack< Begin ... >::Rest() , typename UIntPack< End ... >::Rest() , thread , updateState , function , w[i] ... ); } ); } template< typename UpdateFunction , typename ProcessFunction , class ... Windows > @@ -176,17 +176,17 @@ protected: template< typename UpdateFunction , typename ProcessFunction , class ... Windows > static void RunParallel( int begin , int end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) { - ThreadPool::Parallel_for( begin , end , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); + ThreadPool::ParallelFor( begin , end , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); } template< typename UpdateFunction , typename ProcessFunction , class ... Windows > static void RunParallel( const int* begin , const int* end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) { - ThreadPool::Parallel_for( begin[0] , end[0] , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); + ThreadPool::ParallelFor( begin[0] , end[0] , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); } template< unsigned int ... Begin , unsigned int ... End , typename UpdateFunction , typename ProcessFunction , class ... Windows > static void RunParallel( UIntPack< Begin ... > begin , UIntPack< End ... > end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) { - ThreadPool::Parallel_for( UIntPack< Begin ... >::First , UIntPack< End ... >::First , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); + ThreadPool::ParallelFor( UIntPack< Begin ... >::First , UIntPack< End ... >::First , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); } template< typename UpdateFunction , typename ProcessFunction , class ... Windows > @@ -237,17 +237,17 @@ protected: template< typename UpdateFunction , typename ProcessFunction , class ... Windows > static void RunParallel( int begin , int end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) { - ThreadPool::Parallel_for( begin , end , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); + ThreadPool::ParallelFor( begin , end , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); } template< typename UpdateFunction , typename ProcessFunction , class ... Windows > static void RunParallel( const int* begin , const int* end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) { - ThreadPool::Parallel_for( begin[0] , end[0] , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); + ThreadPool::ParallelFor( begin[0] , end[0] , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); } template< unsigned int ... Begin , unsigned int ... End , typename UpdateFunction , typename ProcessFunction , class ... Windows > static void RunParallel( UIntPack< Begin ... > begin , UIntPack< End ... > end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) { - ThreadPool::Parallel_for( UIntPack< Begin ... >::First , UIntPack< End ... >::First , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); + ThreadPool::ParallelFor( UIntPack< Begin ... >::First , UIntPack< End ... >::First , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); } template< typename UpdateFunction , typename ProcessFunction , class ... Windows > @@ -299,17 +299,17 @@ protected: template< typename UpdateFunction , typename ProcessFunction , class ... Windows > static void RunParallel( int begin , int end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) { - ThreadPool::Parallel_for( begin , end , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); + ThreadPool::ParallelFor( begin , end , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); } template< typename UpdateFunction , typename ProcessFunction , class ... Windows > static void RunParallel( const int* begin , const int* end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) { - ThreadPool::Parallel_for( begin[0] , end[0] , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); + ThreadPool::ParallelFor( begin[0] , end[0] , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); } template< unsigned int ... Begin , unsigned int ... End , typename UpdateFunction , typename ProcessFunction , class ... Windows > static void RunParallel( UIntPack< Begin ... > begin , UIntPack< End ... > end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) { - ThreadPool::Parallel_for( UIntPack< Begin ... >::First , UIntPack< End ... >::First , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); + ThreadPool::ParallelFor( UIntPack< Begin ... >::First , UIntPack< End ... >::First , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); } template< typename UpdateFunction , typename ProcessFunction , class ... Windows > From d16bc417981d0d55a6300baccbd7019da17a4cfc Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Tue, 17 Sep 2024 12:24:10 -0400 Subject: [PATCH 44/86] Version 18.05 --- AdaptiveSolvers.sln | 1 + README.md | 14 +- Src/FEMTree.h | 48 ++----- Src/NestedVector.h | 343 ++++++++++++++++++++++++++++++++++++++++++++ Src/Ply.inl | 4 +- Src/PreProcessor.h | 4 +- 6 files changed, 373 insertions(+), 41 deletions(-) create mode 100644 Src/NestedVector.h diff --git a/AdaptiveSolvers.sln b/AdaptiveSolvers.sln index db281a22..d6db1f3c 100644 --- a/AdaptiveSolvers.sln +++ b/AdaptiveSolvers.sln @@ -63,6 +63,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Header Files", "Header File Src\MyAtomic.h = Src\MyAtomic.h Src\MyExceptions.h = Src\MyExceptions.h Src\MyMiscellany.h = Src\MyMiscellany.h + Src\NestedVector.h = Src\NestedVector.h Src\Ply.h = Src\Ply.h Src\PlyFile.h = Src\PlyFile.h Src\PNG.h = Src\PNG.h diff --git a/README.md b/README.md index b4cb4f33..2d842d3e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

      Adaptive Multigrid Solvers (Version 18.04)

      +

      Adaptive Multigrid Solvers (Version 18.05)

      links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
      Executables: -Win64
      +Win64
      Source Code: -ZIP GitHub
      +ZIP GitHub
      Older Versions: +V18.04, V18.03, V18.02, V18.01, @@ -1584,11 +1585,16 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
    • Fixed bug occurring when the octree was complete. -Version 18.04: +Version 18.04:
      1. Further sanitized multi-threading code.
      +Version 18.05: +
        +
      1. Replaced BlockedVector with NestedVector to reduce synchronization. +
      +
      diff --git a/Src/FEMTree.h b/Src/FEMTree.h index 10d05d39..7fcf8818 100644 --- a/Src/FEMTree.h +++ b/Src/FEMTree.h @@ -55,7 +55,7 @@ DAMAGE. #include "DataStream.h" #include "RegularTree.h" #include "SparseMatrix.h" -#include "BlockedVector.h" +#include "NestedVector.h" #include "Rasterizer.h" #include #include @@ -330,54 +330,34 @@ namespace PoissonRecon const Data* operator()( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ) const { return ( node->nodeData.nodeIndex<0 || node->nodeData.nodeIndex>=(node_index_type)_indices.size() || _indices[ node->nodeData.nodeIndex ]==-1 ) ? NULL : &_data[ _indices[ node->nodeData.nodeIndex ] ]; } Data& operator[]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ) { -#ifdef SANITIZED_PR - static std::shared_mutex _insertionMutex; -#else // !SANITIZED_PR - static std::mutex _insertionMutex; -#endif // SANITIZED_PR - // If the node hasn't been indexed yet - if( node->nodeData.nodeIndex>=(node_index_type)_indices.size() ) - { -#ifdef SANITIZED_PR - std::unique_lock lock( _insertionMutex ); -#else // !SANITIZED_PR - std::lock_guard< std::mutex > lock( _insertionMutex ); -#endif // SANITIZED_PR - if( node->nodeData.nodeIndex>=(node_index_type)_indices.size() ) _indices.resize( node->nodeData.nodeIndex+1 , -1 ); - } + _indices.resize( node->nodeData.nodeIndex+1 , -1 ); + // If the node hasn't been allocated yet #ifdef SANITIZED_PR - volatile node_index_type * indexPtr; - { - std::shared_lock lock( _insertionMutex ); - indexPtr = &_indices[ node->nodeData.nodeIndex ]; - } + volatile node_index_type *indexPtr = &_indices[ node->nodeData.nodeIndex ]; node_index_type _index = ReadAtomic( *indexPtr ); #else // !SANITIZED_PR volatile node_index_type &_index = _indices[ node->nodeData.nodeIndex ]; #endif // SANITIZED_PR if( _index==-1 ) { + static std::mutex _updateMutex; + std::lock_guard< std::mutex > lock( _updateMutex ); #ifdef SANITIZED_PR - std::unique_lock lock( _insertionMutex ); _index = ReadAtomic( *indexPtr ); -#else // !SANITIZED_PR - std::lock_guard< std::mutex > lock( _insertionMutex ); #endif // SANITIZED_PR if( _index==-1 ) { size_t sz = _data.size(); _data.resize( sz + 1 ); - _index = (node_index_type)sz; #ifdef SANITIZED_PR - // [WARNING] Why is this necessary, given that we are within a critical section? - SetAtomic( *indexPtr , _index , (node_index_type)-1 ); + _index = (node_index_type)sz; + SetAtomic( *indexPtr , _index ); +#else // !SANITIZED_PR + *(node_index_type*)&_index = (node_index_type)sz; #endif // SANITIZED_PR } } -#ifdef SANITIZED_PR - std::shared_lock lock( _insertionMutex ); -#endif // SANITIZED_PR return _data[ _index ]; } node_index_type index( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *node ) const @@ -474,14 +454,14 @@ namespace PoissonRecon // Map should be the size of the new number of entries and map[i] should give the old index of the i-th node void _remapIndices( ConstPointer( node_index_type )oldNodeIndices , size_t newNodeCount ) { - BlockedVector< node_index_type > newIndices; + NestedVector< node_index_type , NESTED_VECTOR_LEVELS > newIndices; newIndices.resize( newNodeCount ); for( node_index_type i=0 ; i<(node_index_type)newNodeCount ; i++ ) { newIndices[i] = -1; if( oldNodeIndices[i]!=-1 && oldNodeIndices[i]<(node_index_type)_indices.size() ) newIndices[i] = _indices[ oldNodeIndices[i] ]; } - _indices = newIndices; + std::swap( _indices , newIndices ); } SparseNodeData _trim( node_index_type endIndex ) const @@ -503,8 +483,8 @@ namespace PoissonRecon return sparseNodeData; } - BlockedVector< node_index_type > _indices; - BlockedVector< Data > _data; + NestedVector< node_index_type , NESTED_VECTOR_LEVELS > _indices; + NestedVector< Data , NESTED_VECTOR_LEVELS > _data; }; template< class Data , typename Pack > struct DenseNodeData{}; diff --git a/Src/NestedVector.h b/Src/NestedVector.h new file mode 100644 index 00000000..d3d1cc82 --- /dev/null +++ b/Src/NestedVector.h @@ -0,0 +1,343 @@ +/* +Copyright (c) 2024, 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 NESTED_VECTOR_INCLUDED +#define NESTED_VECTOR_INCLUDED + +#include +#include "MyAtomic.h" +#include "MyMiscellany.h" + +namespace PoissonRecon +{ + // This represents a vector that can only grow in size. + // It has the property that once a reference to an element is returned, that reference remains valid until the vector is destroyed. + template< typename T , unsigned int Depth , unsigned int LogSize=20 > + struct NestedVector; + + // The base case, an array with a maximum of 1< + struct NestedVector< T , 0 , LogSize > + { + static const unsigned int Depth = 0; + NestedVector( void ) : _size(0) { _data = new _DataType[ _Size ]; } + + ~NestedVector( void ){ delete[] _data; } + + NestedVector( const NestedVector &nv ) : NestedVector() + { + _size = nv._size.load(); + for( size_t i=0 ; i<_size ; i++ ) operator[](i) = nv[i]; + } + + NestedVector &operator = ( const NestedVector & nv ) + { + _size = nv._size.load(); + for( size_t i=0 ; i<_size ; i++ ) operator[](i) = nv[i]; + return *this; + } + + NestedVector( NestedVector &&nv ) + { + _data = nv._data; + _size = nv._size.load(); + nv._size = 0; + nv._data = nullptr; + } + + NestedVector& operator = ( NestedVector &&nv ) + { + size_t foo = _size; + _size = nv._size.load(); + nv._size = foo; + std::swap( _data , nv._data ); + return *this; + } + + // This function is guaranteed to return a lower-bound on the actual size + size_t size( void ) const { return _size; } + + const T& operator[]( size_t idx ) const { return _data[idx]; } + T& operator[]( size_t idx ){ return _data[idx]; } + + size_t resize( size_t sz ) + { + if( sz>_MaxSize ) ERROR_OUT( "Resize size exceeds max size, considering increasing nesting: " , sz , " > " , _MaxSize ); + + // Quick check to see if anything needs doing + if( sz<_size ) return size(); + + // Otherwise lock it down and get to work + std::lock_guard lock( _mutex ); + + // Check if the size got changed + if( sz>_size ) _size = sz; + return size(); + } + + size_t resize( size_t sz , const T &defaultValue ) + { + if( sz>_MaxSize ) ERROR_OUT( "Resize size exceeds max size, considering increasing nesting: " , sz , " > " , _MaxSize ); + + // Quick check to see if anything needs doing + if( sz<_size ) return size(); + + // Otherwise lock it down and get to work + std::lock_guard lock( _mutex ); + + // Check if the size got changed + if( sz>_size ) + { + for( size_t i=_size ; i &serializer ) const + { + const size_t serializedSize = serializer.size(); + + stream.write( _size ); + if( _size ) + { + char *buffer = new char[ _size * serializedSize ]; + for( size_t i=0 ; i<_size ; i++ ) serializer.serialize( operator[]( i ) , buffer+i*serializedSize ); + stream.write( buffer , serializedSize*_size ); + delete[] buffer ; + } + } + void read( BinaryStream &stream , const Serializer< T > &serializer ) + { + const size_t serializedSize = serializer.size(); + + if( !stream.read( _size ) ) ERROR_OUT( "Failed to read _size" ); + if( _size ) + { + char *buffer = new char[ _size * serializedSize ]; + if( !stream.read( buffer , serializedSize*_size ) ) ERROR_OUT( "Failed tor read in data" ); + for( size_t i=0 ; i<_size ; i++ ) serializer.deserialize( buffer+i*serializedSize , operator[]( i ) ); + delete[] buffer; + } + } + + protected: + template< typename _T , unsigned int _Depth , unsigned int _LogSize > friend struct NestedVector; + + using _DataType = T; + static const size_t _MaxSize = ((size_t)1)< _size; + _DataType *_data; + }; + + // The derived case, an array a maximum of 1< + struct NestedVector + { + NestedVector( void ) : _size(0) + { + _data = new _DataType*[ _Size ]; + for( size_t i=0 ; i<_Size ; i++ ) _data[i] = nullptr; + } + + ~NestedVector( void ) + { + for( size_t i=0 ; i<_size ; i++ ) delete _data[i]; + delete[] _data; + } + + NestedVector( const NestedVector &nv ) : NestedVector() + { + _size = nv._size.load(); + for( size_t i=0 ; i<_size ; i++ ) _data[i] = new _DataType( *nv._data[i] ); + } + + NestedVector &operator = ( const NestedVector &nv ) + { + for( size_t i=0 ; i<_size ; i++ ){ delete _data[i] ; _data[i] = nullptr; } + _size = nv._size.load(); + for( size_t i=0 ; i<_size ; i++ ) _data[i] = new _DataType( *nv._data[i] ); + return *this; + } + + NestedVector( NestedVector &&nv ) + { + _size = nv._size.load(); + _data = nv._data; + nv._size = 0; + nv._data = nullptr; + } + + NestedVector& operator = ( NestedVector &&nv ) + { + size_t foo = _size; + _size = nv._size.load(); + nv._size = foo; + std::swap( _data , nv._data ); + return *this; + } + + // This function is guaranteed to return a lower-bound on the actual size + size_t size( void ) const + { + if( !_size ) return 0; + else return ( (_size-1)<<(Depth*LogSize) ) + _data[_size-1]->size(); + } + + const T& operator[]( size_t idx ) const { return ( *_data[ idx>>(LogSize*Depth) ] )[ idx & NestedVector< T , Depth-1 , LogSize >::_Mask ] ; } + T& operator[]( size_t idx ){ return ( *( _data[ idx>>(LogSize*Depth) ] ) )[ idx & NestedVector< T , Depth-1 , LogSize >::_Mask ] ; } + + size_t resize( size_t sz ) + { + if( sz>_MaxSize ) ERROR_OUT( "Resize size exceeds max size, considering increasing nesting: " , sz , " > " , _MaxSize ); + + size_t _sz = (sz+NestedVector< T , Depth-1 , LogSize >::_Mask)>>(LogSize*Depth); + + // Quick check to see if anything needs doing + if( !_sz || _sz<_size ) return size(); + + // Otherwise lock it down and get to work + std::lock_guard lock( _mutex ); + + // Check if the size got changed + if( _sz>_size ) + { + for( size_t i=_size ; i<_sz ; i++ ) + { + _data[i] = new _DataType(); + size_t __sz = (_sz==i+1) ? ( sz - NestedVector< T , Depth-1 , LogSize >::_MaxSize * i ) : ( NestedVector< T , Depth-1 , LogSize >::_MaxSize ); + _data[i]->resize( __sz ); + } + _size = _sz; + } + else if( _sz==_size ) + { + size_t i = _sz-1; + size_t __sz = _sz==(i+1) ? ( sz - NestedVector< T , Depth-1 , LogSize >::_MaxSize * i ) : ( NestedVector< T , Depth-1 , LogSize >::_MaxSize ); + _data[i]->resize( __sz ); + } + return size(); + } + + size_t resize( size_t sz , const T &defaultValue ) + { + if( sz>_MaxSize ) ERROR_OUT( "Resize size exceeds max size, considering increasing nesting: " , sz , " > " , _MaxSize ); + + size_t _sz = (sz+NestedVector< T , Depth-1 , LogSize >::_Mask)>>(LogSize*Depth); + + // Quick check to see if anything needs doing + if( !_sz || _sz<_size ) return size(); + + // Otherwise lock it down and get to work + std::lock_guard lock( _mutex ); + + // Check if the size got changed + if( _sz>_size ) + { + // Complete the initialization for the last existing + if( _size ) + { + size_t i = _size-1; + size_t __sz = _sz==(i+1) ? ( sz - NestedVector< T , Depth-1 , LogSize >::_MaxSize * i ) : ( NestedVector< T , Depth-1 , LogSize >::_MaxSize ); + _data[i]->resize( __sz , defaultValue ); + } + for( size_t i=_size ; i<_sz ; i++ ) + { + _data[i] = new _DataType(); + size_t __sz = _sz==(i+1) ? ( sz - NestedVector< T , Depth-1 , LogSize >::_MaxSize * i ) : ( NestedVector< T , Depth-1 , LogSize >::_MaxSize ); + _data[i]->resize( __sz , defaultValue ); + } + _size = _sz; + } + else if( _sz==_size ) + { + size_t i = _sz-1; + size_t __sz = _sz==(i+1) ? ( sz - NestedVector< T , Depth-1 , LogSize >::_MaxSize * i ) : ( NestedVector< T , Depth-1 , LogSize >::_MaxSize ); + _data[i]->resize( __sz , defaultValue ); + } + return size(); + } + + void write( BinaryStream &stream ) const + { + stream.write( _size ); + for( size_t i=0 ; i<_size ; i++ ) _data[i]->write( stream ); + } + + void read( BinaryStream &stream ) + { + if( !stream.read( _size ) ) ERROR_OUT( "Failed to read _size" ); + for( size_t i=0 ; i<_size ; i++ ) _data[i]->read(stream); + } + + void write( BinaryStream &stream , const Serializer< T > &serializer ) const + { + const size_t serializedSize = serializer.size(); + + stream.write( _size ); + for( size_t i=0 ; i<_size ; i++ ) _data[i]->write( stream , serializer ); + } + void read( BinaryStream &stream , const Serializer< T > &serializer ) + { + const size_t serializedSize = serializer.size(); + + if( !stream.read( _size ) ) ERROR_OUT( "Failed to read _size" ); + for( size_t i=0 ; i<_size ; i++ ) _data[i]->read( stream , serializer ); + } + + protected: + template< typename _T , unsigned int _Depth , unsigned int _LogSize > friend struct NestedVector; + + using _DataType = NestedVector< T , Depth-1 , LogSize >; + static const size_t _MaxSize = ((size_t)1)<<(LogSize*(Depth+1)); + static const size_t _Size = ((size_t)1)< _size; + _DataType **_data; + }; +} +#endif // NESTED_VECTOR_INCLUDED diff --git a/Src/Ply.inl b/Src/Ply.inl index efcb5295..71de1414 100644 --- a/Src/Ply.inl +++ b/Src/Ply.inl @@ -522,8 +522,8 @@ namespace PLY // Edge< OutputIndex > ply_edge; if( !edgeStream.read( edge ) ) ERROR_OUT( "Failed to read edge " , i , " / " , edgeNum ); - ply_edge.v1 = (Index)edge.first; - ply_edge.v2 = (Index)edge.second; + ply_edge.v1 = (OutputIndex)edge.first; + ply_edge.v2 = (OutputIndex)edge.second; ply->put_element( (void *)&ply_edge ); } // for, write edges diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 9d0e6e96..857e4bba 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -46,9 +46,11 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "18.04" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "18.05" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth +#define NESTED_VECTOR_LEVELS 1 // The number of nesting levels for the nested-vector + #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file From 21ad02c3e877fb29dd163b65761b5add04c811e2 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Wed, 18 Sep 2024 17:32:49 -0400 Subject: [PATCH 45/86] Version 18.05 --- Src/NestedVector.h | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/Src/NestedVector.h b/Src/NestedVector.h index d3d1cc82..c69f5710 100644 --- a/Src/NestedVector.h +++ b/Src/NestedVector.h @@ -122,21 +122,25 @@ namespace PoissonRecon void write( BinaryStream &stream ) const { - stream.write( _size ); - stream.write( _data , _size ); + size_t sz = _size; + stream.write( sz ); + stream.write( GetPointer( _data , _Size ) , sz ); } void read( BinaryStream &stream ) { - if( !stream.read( _size ) ) ERROR_OUT( "Failed to read _size" ); - if( !stream.read( _data , _size ) ) ERROR_OUT( "Failed to read _data" ); + size_t sz; + if( !stream.read( sz ) ) ERROR_OUT( "Failed to read _size" ); + resize( sz ); + if( !stream.read( GetPointer( _data , _Size ) , _size ) ) ERROR_OUT( "Failed to read _data" ); } void write( BinaryStream &stream , const Serializer< T > &serializer ) const { const size_t serializedSize = serializer.size(); - stream.write( _size ); + size_t sz = _size; + stream.write( sz ); if( _size ) { char *buffer = new char[ _size * serializedSize ]; @@ -149,9 +153,11 @@ namespace PoissonRecon { const size_t serializedSize = serializer.size(); - if( !stream.read( _size ) ) ERROR_OUT( "Failed to read _size" ); + size_t sz; + if( !stream.read( sz ) ) ERROR_OUT( "Failed to read _size" ); if( _size ) { + resize( sz ); char *buffer = new char[ _size * serializedSize ]; if( !stream.read( buffer , serializedSize*_size ) ) ERROR_OUT( "Failed tor read in data" ); for( size_t i=0 ; i<_size ; i++ ) serializer.deserialize( buffer+i*serializedSize , operator[]( i ) ); @@ -302,13 +308,16 @@ namespace PoissonRecon void write( BinaryStream &stream ) const { - stream.write( _size ); + size_t sz = _size; + stream.write( sz ); for( size_t i=0 ; i<_size ; i++ ) _data[i]->write( stream ); } void read( BinaryStream &stream ) { - if( !stream.read( _size ) ) ERROR_OUT( "Failed to read _size" ); + size_t sz; + if( !stream.read( sz ) ) ERROR_OUT( "Failed to read _size" ); + resize( sz ); for( size_t i=0 ; i<_size ; i++ ) _data[i]->read(stream); } @@ -316,14 +325,17 @@ namespace PoissonRecon { const size_t serializedSize = serializer.size(); - stream.write( _size ); + size_t sz = _size; + stream.write( sz ); for( size_t i=0 ; i<_size ; i++ ) _data[i]->write( stream , serializer ); } void read( BinaryStream &stream , const Serializer< T > &serializer ) { const size_t serializedSize = serializer.size(); - if( !stream.read( _size ) ) ERROR_OUT( "Failed to read _size" ); + size_t sz; + if( !stream.read( sz ) ) ERROR_OUT( "Failed to read _size" ); + resize( sz ); for( size_t i=0 ; i<_size ; i++ ) _data[i]->read( stream , serializer ); } From 2e14a086b7a6561141dd7894679d133ec5c2896e Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Thu, 19 Sep 2024 19:21:32 -0400 Subject: [PATCH 46/86] Version 18..05 --- Src/Array.h | 6 ++++- Src/Array.inl | 38 ++++++++++++++---------------- Src/BSplineData.inl | 14 ++++++++++- Src/DataStream.h | 6 ++--- Src/FEMTree.LevelSet.3D.inl | 3 ++- Src/MultiThreading.h | 10 +++++++- Src/NestedVector.h | 47 ++----------------------------------- 7 files changed, 51 insertions(+), 73 deletions(-) diff --git a/Src/Array.h b/Src/Array.h index 234ff893..bf02cf10 100644 --- a/Src/Array.h +++ b/Src/Array.h @@ -32,8 +32,12 @@ DAMAGE. #include #include "MyExceptions.h" +#ifdef ARRAY_DEBUG +#else // !ARRAY_DEBUG namespace PoissonRecon { +#endif // ARRAY_DEBUG + // Code from http://stackoverflow.com inline void* aligned_malloc( size_t size , size_t align ) { @@ -109,6 +113,6 @@ namespace PoissonRecon template< class C > const C* GetPointer( const C* c , size_t sz ) { return c; } template< class C > C* GetPointer( C* c , std::ptrdiff_t start , std::ptrdiff_t end ) { return c; } template< class C > const C* GetPointer( const C* c , std::ptrdiff_t start , std::ptrdiff_t end ) { return c; } -#endif // ARRAY_DEBUG } +#endif // ARRAY_DEBUG #endif // ARRAY_INCLUDED diff --git a/Src/Array.inl b/Src/Array.inl index 0d634f78..16cbc1f4 100644 --- a/Src/Array.inl +++ b/Src/Array.inl @@ -35,11 +35,7 @@ class Array friend class ConstArray< C >; void _assertBounds( std::ptrdiff_t idx ) const { - if( idx=max ) - { - StackTracer::Trace(); - ERROR_OUT( "Array index out-of-bounds: " , min , " <= " , idx , " < " , max ); - } + if( idx=max ) PoissonRecon::ERROR_OUT( "Array index out-of-bounds: " , min , " <= " , idx , " < " , max ); } protected: C *data , *_data; @@ -123,7 +119,7 @@ public: 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 ) ERROR_OUT( "Could not convert array [ " , a.minimum() , " , " , a.maximum() , " ] * " , szD , " => [ " , min , " , " , max , " ] * " , szC ); + if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD ) PoissonRecon::ERROR_OUT( "Could not convert array [ " , a.minimum() , " , " , a.maximum() , " ] * " , szD , " => [ " , min , " , " , max , " ] * " , szC ); } } static Array FromPointer( C* data , std::ptrdiff_t max ) @@ -240,7 +236,7 @@ class ConstArray template< class D > friend class ConstArray; void _assertBounds( std::ptrdiff_t idx ) const { - if( idx=max ) ERROR_OUT( "ConstArray index out-of-bounds: " , min , " <= " , idx , " < " , max ); + if( idx=max ) PoissonRecon::ERROR_OUT( "ConstArray index out-of-bounds: " , min , " <= " , idx , " < " , max ); } protected: const C *data; @@ -270,7 +266,7 @@ public: 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 ) ERROR_OUT( "Could not convert const array [ " , a.minimum() , " , " , a.maximum() , " ] * " , szD , " => [ " , min , " , " , max , " ] * " , szC ); + if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD ) PoissonRecon::ERROR_OUT( "Could not convert const array [ " , a.minimum() , " , " , a.maximum() , " ] * " , szD , " => [ " , min , " , " , max , " ] * " , szC ); } template< class D > inline ConstArray( ConstArray< D > a ) @@ -281,7 +277,7 @@ public: 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 ) ERROR_OUT( "Could not convert array [ " , a.minimum() , " , " , a.maximum() , " ] * " , szD , " => [ " , min , " , " , max , " ] * " , szC ); + if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD ) PoissonRecon::ERROR_OUT( "Could not convert array [ " , a.minimum() , " , " , a.maximum() , " ] * " , szD , " => [ " , min , " , " , max , " ] * " , szC ); } explicit operator Array< C >() const { @@ -365,44 +361,44 @@ public: template< class C > Array< C > memcpy( Array< C > destination , const void* source , size_t size ) { - if( size>destination.maximum()*sizeof(C) ) ERROR_OUT( "Size of copy exceeds destination maximum: " , size , " > " , destination.maximum()*sizeof( C ) ); + if( size>destination.maximum()*sizeof(C) ) PoissonRecon::ERROR_OUT( "Size of copy exceeds destination maximum: " , size , " > " , destination.maximum()*sizeof( C ) ); 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 ) ) ERROR_OUT( "Size of copy exceeds destination maximum: " , size , " > " , destination.maximum()*sizeof( C ) ); - if( size>source.maximum()*sizeof( D ) ) ERROR_OUT( "Size of copy exceeds source maximum: " , size , " > " , source.maximum()*sizeof( D ) ); + if( size>destination.maximum()*sizeof( C ) ) PoissonRecon::ERROR_OUT( "Size of copy exceeds destination maximum: " , size , " > " , destination.maximum()*sizeof( C ) ); + if( size>source.maximum()*sizeof( D ) ) PoissonRecon::ERROR_OUT( "Size of copy exceeds source maximum: " , size , " > " , source.maximum()*sizeof( D ) ); 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 ) ) ERROR_OUT( "Size of copy exceeds destination maximum: " , size , " > " , destination.maximum()*sizeof( C ) ); - if( size>source.maximum()*sizeof( D ) ) ERROR_OUT( "Size of copy exceeds source maximum: " , size , " > " , source.maximum()*sizeof( D ) ); + if( size>destination.maximum()*sizeof( C ) ) PoissonRecon::ERROR_OUT( "Size of copy exceeds destination maximum: " , size , " > " , destination.maximum()*sizeof( C ) ); + if( size>source.maximum()*sizeof( D ) ) PoissonRecon::ERROR_OUT( "Size of copy exceeds source maximum: " , size , " > " , source.maximum()*sizeof( D ) ); 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 ) ) ERROR_OUT( "Size of copy exceeds source maximum: " , size , " > " , source.maximum()*sizeof( D ) ); + if( size>source.maximum()*sizeof( D ) ) PoissonRecon::ERROR_OUT( "Size of copy exceeds source maximum: " , size , " > " , source.maximum()*sizeof( D ) ); 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 ) ) ERROR_OUT( "Size of copy exceeds source maximum: " , size , " > " , source.maximum()*sizeof( D ) ); + if( size>source.maximum()*sizeof( D ) ) PoissonRecon::ERROR_OUT( "Size of copy exceeds source maximum: " , size , " > " , source.maximum()*sizeof( D ) ); 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 ) ) ERROR_OUT( "Size of set exceeds destination maximum: " , size , " > " , destination.maximum()*sizeof( C ) ); + if( size>destination.maximum()*sizeof( C ) ) PoissonRecon::ERROR_OUT( "Size of set exceeds destination maximum: " , size , " > " , destination.maximum()*sizeof( C ) ); if( size ) memset( &destination[0] , value , size ); return destination; } @@ -410,28 +406,28 @@ Array< C > memset( Array< C > destination , int value , size_t size ) template< class C > size_t fread( Array< C > destination , size_t eSize , size_t count , FILE* fp ) { - if( count*eSize>destination.maximum()*sizeof( C ) ) ERROR_OUT( "Size of read exceeds source maximum: " , count*eSize , " > " , destination.maximum()*sizeof( C ) ); + if( count*eSize>destination.maximum()*sizeof( C ) ) PoissonRecon::ERROR_OUT( "Size of read exceeds source maximum: " , count*eSize , " > " , destination.maximum()*sizeof( C ) ); if( count ) return fread( &destination[0] , eSize , count , fp ); else return 0; } template< class C > size_t fwrite( Array< C > source , size_t eSize , size_t count , FILE* fp ) { - if( count*eSize>source.maximum()*sizeof( C ) ) ERROR_OUT( "Size of write exceeds source maximum: " , count*eSize , " > " , source.maximum()*sizeof( C ) ); + if( count*eSize>source.maximum()*sizeof( C ) ) PoissonRecon::ERROR_OUT( "Size of write exceeds source maximum: " , count*eSize , " > " , source.maximum()*sizeof( C ) ); if( count ) return fwrite( &source[0] , eSize , count , fp ); else return 0; } template< class C > size_t fwrite( ConstArray< C > source , size_t eSize , size_t count , FILE* fp ) { - if( count*eSize>source.maximum()*sizeof( C ) ) ERROR_OUT( "Size of write exceeds source maximum: " , count*eSize , " > " , source.maximum()*sizeof( C ) ); + if( count*eSize>source.maximum()*sizeof( C ) ) PoissonRecon::ERROR_OUT( "Size of write exceeds source maximum: " , count*eSize , " > " , source.maximum()*sizeof( C ) ); if( count ) return fwrite( &source[0] , eSize , count , fp ); else return 0; } template< class C > void qsort( Array< C > base , size_t numElements , size_t elementSize , int (*compareFunction)( const void* , const void* ) ) { - if( sizeof(C)!=elementSize ) ERROR_OUT( "Element sizes differ: " , sizeof(C) , " != " , elementSize ); + if( sizeof(C)!=elementSize ) PoissonRecon::ERROR_OUT( "Element sizes differ: " , sizeof(C) , " != " , elementSize ); if( base.minimum()>0 || base.maximum() " , _MaxSize ); - - // Quick check to see if anything needs doing - if( sz<_size ) return size(); - - // Otherwise lock it down and get to work - std::lock_guard lock( _mutex ); - - // Check if the size got changed - if( sz>_size ) _size = sz; - return size(); - } + size_t resize( size_t sz ){ return resize( sz , T{} ); } size_t resize( size_t sz , const T &defaultValue ) { @@ -235,37 +222,7 @@ namespace PoissonRecon const T& operator[]( size_t idx ) const { return ( *_data[ idx>>(LogSize*Depth) ] )[ idx & NestedVector< T , Depth-1 , LogSize >::_Mask ] ; } T& operator[]( size_t idx ){ return ( *( _data[ idx>>(LogSize*Depth) ] ) )[ idx & NestedVector< T , Depth-1 , LogSize >::_Mask ] ; } - size_t resize( size_t sz ) - { - if( sz>_MaxSize ) ERROR_OUT( "Resize size exceeds max size, considering increasing nesting: " , sz , " > " , _MaxSize ); - - size_t _sz = (sz+NestedVector< T , Depth-1 , LogSize >::_Mask)>>(LogSize*Depth); - - // Quick check to see if anything needs doing - if( !_sz || _sz<_size ) return size(); - - // Otherwise lock it down and get to work - std::lock_guard lock( _mutex ); - - // Check if the size got changed - if( _sz>_size ) - { - for( size_t i=_size ; i<_sz ; i++ ) - { - _data[i] = new _DataType(); - size_t __sz = (_sz==i+1) ? ( sz - NestedVector< T , Depth-1 , LogSize >::_MaxSize * i ) : ( NestedVector< T , Depth-1 , LogSize >::_MaxSize ); - _data[i]->resize( __sz ); - } - _size = _sz; - } - else if( _sz==_size ) - { - size_t i = _sz-1; - size_t __sz = _sz==(i+1) ? ( sz - NestedVector< T , Depth-1 , LogSize >::_MaxSize * i ) : ( NestedVector< T , Depth-1 , LogSize >::_MaxSize ); - _data[i]->resize( __sz ); - } - return size(); - } + size_t resize( size_t sz ){ return resize( sz , T{} ); } size_t resize( size_t sz , const T &defaultValue ) { From daa490aa44d9e47543dde741567885c6a4dd996b Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Sun, 22 Sep 2024 13:48:04 -0400 Subject: [PATCH 47/86] Version 18.10 --- README.md | 12 +- Src/AdaptiveTreeVisualization.cpp | 4 +- Src/DataStream.h | 80 +++- Src/DataStream.imp.h | 50 ++- Src/FEMTree.Initialize.inl | 23 +- Src/FEMTree.LevelSet.2D.inl | 119 ++++-- Src/FEMTree.LevelSet.3D.inl | 147 ++++++-- Src/FEMTree.h | 16 +- Src/MyAtomic.h | 90 ++++- Src/PointInterpolant.cpp | 4 +- Src/PoissonRecon.client.inl | 20 +- Src/PoissonRecon.cpp | 96 ++--- Src/PoissonRecon.server.inl | 9 +- Src/PoissonReconClientServer.h | 2 +- Src/PoissonReconClientServer.inl | 3 + Src/PoissonReconServer.cpp | 4 + Src/PreProcessor.h | 2 +- Src/Reconstruction.example.cpp | 16 +- Src/Reconstructors.h | 105 +++--- Src/Reconstructors.streams.h | 590 +++++++++++++++++++++++------- Src/SSDRecon.cpp | 88 ++--- 21 files changed, 1083 insertions(+), 397 deletions(-) diff --git a/README.md b/README.md index 2d842d3e..cb331ed7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

      Adaptive Multigrid Solvers (Version 18.05)

      +

      Adaptive Multigrid Solvers (Version 18.10)

      links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
      Executables: -Win64
      +Win64
      Source Code: -ZIP GitHub
      +ZIP GitHub
      Older Versions: +V18.05, V18.04, V18.03, V18.02, @@ -1595,6 +1596,11 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
    • Replaced BlockedVector with NestedVector to reduce synchronization. +Version 18.10: +
        +
      1. Removed mutual exclusion in the iso-surfacing phase. +
      +
      diff --git a/Src/AdaptiveTreeVisualization.cpp b/Src/AdaptiveTreeVisualization.cpp index 3713ed59..a9e6fa2d 100644 --- a/Src/AdaptiveTreeVisualization.cpp +++ b/Src/AdaptiveTreeVisualization.cpp @@ -405,12 +405,12 @@ void _Execute( const FEMTree< Dim , Real > *tree , XForm< Real , Dim+1 > modelTo Factory factory = VInfo::GetFactory(); // A backing stream for the vertices - Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , false , false ); + Reconstructor::OutputInputFactoryTypeStream< Factory , false > vertexStream( factory , false ); Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( false , true ); { // The wrapper converting native to output types - typename VInfo::StreamWrapper _vertexStream( vertexStream , factory() ); + typename VInfo::StreamWrapper _vertexStream( vertexStream ); Reconstructor::TransformedOutputVertexStream< Real , Dim > __vertexStream( modelToUnitCube.inverse() , _vertexStream ); // Extract the mesh diff --git a/Src/DataStream.h b/Src/DataStream.h index 9634d8bb..31730f23 100644 --- a/Src/DataStream.h +++ b/Src/DataStream.h @@ -117,14 +117,21 @@ namespace PoissonRecon MultiInputDataStream( InputDataStream< Data > **streams , size_t N ) : _current(0) , _streams( streams , streams+N ) {} MultiInputDataStream( const std::vector< InputDataStream< Data > * > &streams ) : _current(0) , _streams( streams ) {} void reset( void ){ for( unsigned int i=0 ; i<_streams.size() ; i++ ) _streams[i]->reset(); } - unsigned int numStreams( void ) const { return _streams.size(); } + unsigned int numStreams( void ) const { return (unsigned int)_streams.size(); } protected: std::vector< InputDataStream< Data > * > _streams; unsigned int _current; + MultiInputDataStream( void ) {} + void _init( InputDataStream< Data > **streams , size_t N ) + { + _streams.resize( N ); + for( unsigned int i=0 ; i * > &streams ){ _streams = streams; } bool base_read( unsigned int t , Data &d ){ return _streams[t]->base_read(d); } - bool base_read( Data &d ) + bool base_read( Data &d ) { while( _current<_streams.size() ) { @@ -140,13 +147,80 @@ namespace PoissonRecon { MultiOutputDataStream( OutputDataStream< Data > **streams , size_t N ) : _streams( streams , streams+N ) {} MultiOutputDataStream( const std::vector< OutputDataStream< Data > * > &streams ) : _streams( streams ) {} + unsigned int numStreams( void ) const { return (unsigned int)_streams.size(); } protected: std::vector< OutputDataStream< Data > * > _streams; - void base_write( const Data &d ){ _streams[0]->base_write(d); } + MultiOutputDataStream( void ) {} + void _init( OutputDataStream< Data > **streams , size_t N ) + { + _streams.resize( N ); + for( unsigned int i=0 ; i * > &streams ){ _streams = streams; } + void base_write( const Data &d ){ _streams[0]->base_write(d); } void base_write( unsigned int t , const Data &d ){ _streams[t]->base_write(d); } }; + + template< typename Index , typename Data > + struct IndexedInputDataStream : public InputDataStream< Data > + { + IndexedInputDataStream( MultiInputDataStream< std::pair< Index , Data > > &multiStream , Data data ) : _multiStream( multiStream ) + { + _nextValues.resize( multiStream.numStreams() ); + for( unsigned int i=0 ; i<_nextValues.size() ; i++ ) _nextValues[i].data.second = data; + for( unsigned int i=0 ; i<_nextValues.size() ; i++ ) + { + _nextValues[i].validData = _multiStream.read( i , _nextValues[i].data ); + _nextValues[i].streamIndex = i; + } + std::make_heap( _nextValues.begin() , _nextValues.end() , _NextValue::Compare ); + } + void reset( void ) + { + _multiStream.reset(); + for( unsigned int i=0 ; i<_nextValues.size() ; i++ ) + { + _nextValues[i].validData = _multiStream.read( i , _nextValues[i].data ); + _nextValues[i].streamIndex = i; + } + std::make_heap( _nextValues.begin() , _nextValues.end() , _NextValue::Compare ); + } + + + protected: + struct _NextValue + { + std::pair< Index , Data > data; + unsigned int streamIndex; + bool validData; + + // Returns true if v1>v2 so that it's a min-heap + static bool Compare( const _NextValue &v1 , const _NextValue &v2 ) + { + if( !v2.validData ) return false; + else if( !v1.validData && v2.validData ) return true; + else return v1.data.first>v2.data.first; + }; + }; + + MultiInputDataStream< std::pair< Index , Data > > &_multiStream; + std::vector< _NextValue > _nextValues; + + bool base_read( unsigned int t , Data &d ){ return base_read(d); } + bool base_read( Data &d ) + { + std::pop_heap( _nextValues.begin() , _nextValues.end() , _NextValue::Compare ); + _NextValue &next = _nextValues.back(); + if( !next.validData ) return false; + d = next.data.second; + next.validData = _multiStream.read( next.streamIndex , next.data ); + + std::push_heap( _nextValues.begin() , _nextValues.end() , _NextValue::Compare ); + return true; + } + }; } #endif // DATA_STREAM_INCLUDED diff --git a/Src/DataStream.imp.h b/Src/DataStream.imp.h index bb25d2bb..3e209077 100644 --- a/Src/DataStream.imp.h +++ b/Src/DataStream.imp.h @@ -139,10 +139,10 @@ namespace PoissonRecon //////////////////////////////////////////////////////// // File-backed stream with data desribed by a factory // //////////////////////////////////////////////////////// - template< typename Factory > - struct FileBackedInputFactoryTypeStream : public InputDataStream< typename Factory::VertexType > + template< typename Factory , bool ParallelStream , typename Index=size_t > + struct FileBackedInputFactoryTypeStream : public InputDataStream< std::conditional_t< ParallelStream , std::pair< Index , typename Factory::VertexType > , typename Factory::VertexType > > { - typedef typename Factory::VertexType Data; + using Data = std::conditional_t< ParallelStream , std::pair< Index , typename Factory::VertexType > , typename Factory::VertexType >; // It is assumed that the file pointer was open for binary reading FileBackedInputFactoryTypeStream( FILE *fp , const Factory &factory ) : _fp(fp) , _factory(factory) , _buffer( NewPointer< char >( _factory.bufferSize() ) ) , _bufferSize( _factory.bufferSize() ) {} ~FileBackedInputFactoryTypeStream( void ){ DeletePointer( _buffer ); } @@ -154,13 +154,34 @@ namespace PoissonRecon Pointer( char ) _buffer; const size_t _bufferSize; - bool base_read( Data &d ){ if( fread( _buffer , sizeof(unsigned char) , _bufferSize , _fp )==_bufferSize ){ _factory.fromBuffer( _buffer , d ) ; return true; } else return false; } + bool base_read( Data &d ) + { + if constexpr( ParallelStream ) + { + if( fread( &d.first , sizeof(Index) , 1 , _fp )!=1 ) return false; + if( fread( _buffer , sizeof(unsigned char) , _bufferSize , _fp )==_bufferSize ) + { + _factory.fromBuffer( _buffer , d.second ); + return true; + } + else return false; + } + else + { + if( fread( _buffer , sizeof(unsigned char) , _bufferSize , _fp )==_bufferSize ) + { + _factory.fromBuffer( _buffer , d ); + return true; + } + else return false; + } + } }; - template< typename Factory > - struct FileBackedOutputFactoryTypeStream : public OutputDataStream< typename Factory::VertexType > + template< typename Factory , bool ParallelStream , typename Index=size_t > + struct FileBackedOutputFactoryTypeStream : public OutputDataStream< std::conditional_t< ParallelStream , std::pair< Index , typename Factory::VertexType > , typename Factory::VertexType > > { - typedef typename Factory::VertexType Data; + using Data = std::conditional_t< ParallelStream , std::pair< Index , typename Factory::VertexType > , typename Factory::VertexType >; // It is assumed that the file pointer was open for binary reading FileBackedOutputFactoryTypeStream( FILE *fp , const Factory &factory ) : _fp(fp) , _factory(factory) , _buffer( NewPointer< char >( _factory.bufferSize() ) ) , _bufferSize( _factory.bufferSize() ) {} @@ -172,7 +193,20 @@ namespace PoissonRecon Pointer( char ) _buffer; const size_t _bufferSize; - void base_write( const Data &d ){ _factory.toBuffer( d , _buffer ) ; fwrite( _buffer , sizeof(unsigned char) , _bufferSize , _fp ); } + void base_write( const Data &d ) + { + if constexpr( ParallelStream ) + { + fwrite( &d.first , sizeof(Index) , 1 , _fp ); + _factory.toBuffer( d.second , _buffer ); + fwrite( _buffer , sizeof(unsigned char) , _bufferSize , _fp ); + } + else + { + _factory.toBuffer( d , _buffer ); + fwrite( _buffer , sizeof(unsigned char) , _bufferSize , _fp ); + } + } }; diff --git a/Src/FEMTree.Initialize.inl b/Src/FEMTree.Initialize.inl index fa0a74c5..1f1ecd61 100644 --- a/Src/FEMTree.Initialize.inl +++ b/Src/FEMTree.Initialize.inl @@ -51,16 +51,18 @@ size_t FEMTreeInitializer< Dim , Real >::_Initialize( FEMTreeNode &node , int ma } template< unsigned int Dim , class Real > -template< typename AuxData > -size_t FEMTreeInitializer< Dim , Real >::Initialize( StreamInitializationData &sid , FEMTreeNode &root , typename InputPointStream< AuxData >::StreamType &pointStream , AuxData zeroData , int maxDepth , std::vector< PointSample >& samplePoints , std::vector< typename InputPointStream< AuxData >::DataType > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , typename InputPointStream< AuxData >::DataType & ) > ProcessData ) +template< typename AuxData , typename PointStream > +size_t FEMTreeInitializer< Dim , Real >::Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , PointStream &pointStream , AuxData zeroData , int maxDepth , std::vector< PointSample >& samplePoints , std::vector< AuxData > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , AuxData & ) > ProcessData ) { - return Initialize< AuxData >( sid , root , pointStream , zeroData , maxDepth , [&]( Point< Real , Dim > ){ return maxDepth; } , samplePoints , sampleData , mergeNodeSamples , nodeAllocator , NodeInitializer , ProcessData ); + return Initialize< AuxData , PointStream >( sid , root , pointStream , zeroData , maxDepth , [&]( Point< Real , Dim > ){ return maxDepth; } , samplePoints , sampleData , mergeNodeSamples , nodeAllocator , NodeInitializer , ProcessData ); } template< unsigned int Dim , class Real > -template< typename AuxData > -size_t FEMTreeInitializer< Dim , Real >::Initialize( StreamInitializationData &sid , FEMTreeNode& root , typename InputPointStream< AuxData >::StreamType &pointStream , AuxData zeroData , int maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , std::vector< PointSample >& samplePoints , std::vector< typename InputPointStream< AuxData >::DataType > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , typename InputPointStream< AuxData >::DataType & ) > ProcessData ) +template< typename AuxData , typename PointStream > +size_t FEMTreeInitializer< Dim , Real >::Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , PointStream &pointStream , AuxData zeroData , int maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , std::vector< PointSample >& samplePoints , std::vector< AuxData > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , AuxData & ) > ProcessData ) { + using Sample = VectorTypeUnion< Real , Point< Real , Dim > , AuxData >; + static_assert( std::is_base_of< InputDataStream< Sample > , PointStream >::value , "[ERROR] Unexpected point stream type" ); typename FEMTreeNode::SubTreeExtractor subtreeExtractor( root ); @@ -94,12 +96,13 @@ size_t FEMTreeInitializer< Dim , Real >::Initialize( StreamInitializationData &s size_t outOfBoundPoints = 0 , badData = 0 , pointCount = 0; { std::vector< node_index_type > &nodeToIndexMap = sid._nodeToIndexMap; - typename InputPointStream< AuxData >::PointAndDataType pd; - pd.template get<1>() = zeroData; - while( pointStream.read( pd ) ) + + Sample s; + s.template get<1>() = zeroData; + while( pointStream.read( s ) ) { - Point< Real , Dim > p = pd.template get<0>(); - typename InputPointStream< AuxData >::DataType d = InputPointStream< AuxData >::GetData( pd ); + Point< Real , Dim > p = s.template get<0>(); + AuxData d = s.template get<1>(); Real weight = ProcessData( p , d ); if( weight<=0 ){ badData++ ; continue; } FEMTreeNode *temp = Leaf( root , p , pointDepthFunctor(p) ); diff --git a/Src/FEMTree.LevelSet.2D.inl b/Src/FEMTree.LevelSet.2D.inl index 56074397..8f5d9f41 100644 --- a/Src/FEMTree.LevelSet.2D.inl +++ b/Src/FEMTree.LevelSet.2D.inl @@ -598,8 +598,25 @@ public: } - template< unsigned int WeightDegree , unsigned int DataSig > - static void SetIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool outputGradients , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > > *pointEvaluator , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , node_index_type &vOffset , OutputDataStream< Vertex > &vertexStream , std::vector< SliceValues > &sliceValues , std::vector< typename SliceValues::Scratch > &scratchValues , const Data &zeroData ) + template< unsigned int WeightDegree , unsigned int DataSig , typename OutputVertexStream > + static void SetIsoVertices + ( + const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , + const FEMTree< Dim , Real >& tree , + bool nonLinearFit , + bool outputGradients , + typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > > *pointEvaluator , + const DensityEstimator< WeightDegree > *densityWeights , + const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , + Real isoValue , + LocalDepth depth , + LocalDepth fullDepth , + std::atomic< node_index_type > &vOffset , + OutputVertexStream &vertexStream , + std::vector< SliceValues > &sliceValues , + std::vector< typename SliceValues::Scratch > &scratchValues , + const Data &zeroData + ) { auto _EdgeIndex = [&]( const TreeNode *node , typename HyperCube::Cube< Dim >::template Element< 1 > e ) { @@ -656,37 +673,51 @@ public: Key key = _EdgeIndex( leaf , e ); GetIsoVertex< WeightDegree , DataSig >( tree , nonLinearFit , outputGradients , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , e , sValues , vertex , zeroData ); bool stillOwner = false; - node_index_type hashed_vertex; + std::pair< node_index_type , Vertex > hashed_vertex; + if constexpr( std::is_base_of_v< OutputDataStream< std::pair< node_index_type , Vertex > > , OutputVertexStream > ) + { + char desired = 1 , expected = 0; +#ifdef SANITIZED_PR + if( edgeSet.compare_exchange_weak( expected , desired ) ) +#else // !SANITIZED_PR + if( SetAtomic( edgeSet , desired , expected ) ) +#endif // SANITIZED_PR + { + hashed_vertex = std::pair< node_index_type , Vertex >( vOffset++ , vertex ); + vertexStream.write( thread , hashed_vertex ); + stillOwner = true; + } + } + else if constexpr( std::is_base_of_v< OutputDataStream< Vertex > , OutputVertexStream > ) { std::lock_guard< std::mutex > lock( _pointInsertionMutex ); if( !edgeSet ) { + hashed_vertex = std::pair< node_index_type , Vertex >( vOffset++ , vertex ); vertexStream.write( vertex ); edgeSet = 1; - hashed_vertex = vOffset; - sValues.edgeKeys[ vIndex ] = key; - vOffset++; stillOwner = true; } } + else ERROR_OUT( "Bad stream type: " , typeid(OutputVertexStream).name() ); + if( stillOwner ) // If this edge is the one generating the iso-vertex { - scValues.eKeyValues[ thread ].push_back( std::pair< Key , node_index_type >( key , hashed_vertex ) ); - // We only need to pass the iso-vertex down if the edge it lies on is adjacent to a coarser leaf + sValues.edgeKeys[ vIndex ] = key; + scValues.eKeyValues[ thread ].push_back( std::pair< Key , node_index_type >( key , hashed_vertex.first ) ); + // We only need to pass the iso-vertex down if the edge it lies on is adjacent to a coarser leaf + const typename HyperCube::Cube< Dim >::template Element< Dim > *f = HyperCubeTables< Dim , 1 , Dim >::OverlapElements[e.index]; + // Note that this is a trivial loop of size 1 + for( int k=0 ; k::OverlapElementNum ; k++ ) { - const typename HyperCube::Cube< Dim >::template Element< Dim > *f = HyperCubeTables< Dim , 1 , Dim >::OverlapElements[e.index]; - // Note that this is a trivial loop of size 1 - for( int k=0 ; k::OverlapElementNum ; k++ ) + TreeNode *node = leaf; + LocalDepth _depth = depth; + while( _depth>fullDepth && tree._isValidSpaceNode( node->parent ) && HyperCubeTables< Dim , Dim , 0 >::Overlap[f[k].index][(unsigned int)(node-node->parent->children) ] ) { - TreeNode *node = leaf; - LocalDepth _depth = depth; - while( _depth>fullDepth && tree._isValidSpaceNode( node->parent ) && HyperCubeTables< Dim , Dim , 0 >::Overlap[f[k].index][(unsigned int)(node-node->parent->children) ] ) - { - node = node->parent , _depth--; - typename SliceValues::Scratch &_scValues = scratchValues[_depth]; - _scValues.eKeyValues[ thread ].push_back( std::pair< Key , node_index_type >( key , hashed_vertex ) ); - } + node = node->parent , _depth--; + typename SliceValues::Scratch &_scValues = scratchValues[_depth]; + _scValues.eKeyValues[ thread ].push_back( std::pair< Key , node_index_type >( key , hashed_vertex.first ) ); } } } @@ -1004,8 +1035,8 @@ public: static int SetIsoEdgesFlag ( void ){ return _SetFlag::CORNER_VALUES | _SetFlag::ISO_VERTICES | _SetFlag::ISO_EDGES; } - template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > - static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputDataStream< Vertex > &vertexStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , std::vector< SliceValues > &sliceValues , int setFlag ) + template< unsigned int WeightDegree , unsigned int DataSig , typename OutputVertexStream , unsigned int ... FEMSigs > + static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputVertexStream &vertexStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , std::vector< SliceValues > &sliceValues , int setFlag ) { if( maxKeyDepth(); - node_index_type vOffset = 0; + std::atomic< node_index_type > vOffset = 0; typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator = NULL; if constexpr( HasData ) if( data ) pointEvaluator = new typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >( tree._maxDepth ); @@ -1101,8 +1132,8 @@ public: } - template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , OutputDataStream< Vertex > &vertexStream , OutputDataStream< std::pair< node_index_type , node_index_type > > &edgeStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool flipOrientation ) + template< unsigned int WeightDegree , unsigned int DataSig , typename OutputVertexStream , unsigned int ... FEMSigs > + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , OutputVertexStream &vertexStream , OutputDataStream< std::pair< node_index_type , node_index_type > > &edgeStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool flipOrientation ) { std::vector< SliceValues > sliceValues; @@ -1131,6 +1162,7 @@ struct LevelSetExtractor< Real , 2 > typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::SliceValues SliceValues; typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::TreeSliceValuesAndVertexPositions TreeSliceValuesAndVertexPositions; typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::TreeNode TreeNode; + using IndexedVertex = std::pair< node_index_type , Vertex >; template< unsigned int WeightDegree > using DensityEstimator = typename _LevelSetExtractor< HasData , Real , Dim , Data >::template DensityEstimator< WeightDegree >; static int SetCornerValuesFlag( void ){ return _LevelSetExtractor< HasData , Real , Dim , Data >::SetCornerValuesFlag(); } static int SetIsoVerticesFlag ( void ){ return _LevelSetExtractor< HasData , Real , Dim , Data >::SetIsoVerticesFlag (); } @@ -1143,7 +1175,17 @@ struct LevelSetExtractor< Real , 2 > Data zeroData = 0; static const unsigned int DataSig = FEMDegreeAndBType< 0 , BOUNDARY_FREE >::Signature; const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data = NULL; - return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , vertexStream , edgeStream , zeroData , nonLinearFit , outputGradients , flipOrientation ); + return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputDataStream< Vertex > , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , vertexStream , edgeStream , zeroData , nonLinearFit , outputGradients , flipOrientation ); + } + + template< unsigned int WeightDegree , unsigned int ... FEMSigs > + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , OutputDataStream< IndexedVertex > &vertexStream , OutputDataStream< std::pair< node_index_type , node_index_type > > &edgeStream , bool nonLinearFit , bool outputGradients , bool flipOrientation ) + { + typedef unsigned char Data; + Data zeroData = 0; + static const unsigned int DataSig = FEMDegreeAndBType< 0 , BOUNDARY_FREE >::Signature; + const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data = NULL; + return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputDataStream< IndexedVertex > , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , vertexStream , edgeStream , zeroData , nonLinearFit , outputGradients , flipOrientation ); } template< unsigned int WeightDegree , unsigned int ... FEMSigs > @@ -1153,7 +1195,17 @@ struct LevelSetExtractor< Real , 2 > Data zeroData = 0; static const unsigned int DataSig = FEMDegreeAndBType< 0 , BOUNDARY_FREE >::Signature; const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data = NULL; - return _LevelSetExtractor< HasData , Real , Dim , Data >::template SetSliceValues< WeightDegree , DataSig , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , vertexStream , zeroData , nonLinearFit , outputGradients , sliceValues , setFlag ); + return _LevelSetExtractor< HasData , Real , Dim , Data >::template SetSliceValues< WeightDegree , DataSig , OutputDataStream< Vertex > , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , vertexStream , zeroData , nonLinearFit , outputGradients , sliceValues , setFlag ); + } + + template< unsigned int WeightDegree , unsigned int ... FEMSigs > + static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputDataStream< IndexedVertex > &vertexStream , bool nonLinearFit , bool outputGradients , std::vector< SliceValues > &sliceValues , int setFlag ) + { + typedef unsigned char Data; + Data zeroData = 0; + static const unsigned int DataSig = FEMDegreeAndBType< 0 , BOUNDARY_FREE >::Signature; + const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data = NULL; + return _LevelSetExtractor< HasData , Real , Dim , Data >::template SetSliceValues< WeightDegree , DataSig , OutputDataStream< IndexedVertex > , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , vertexStream , zeroData , nonLinearFit , outputGradients , sliceValues , setFlag ); } }; @@ -1167,6 +1219,7 @@ struct LevelSetExtractor< Real , 2 , Data > typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::SliceValues SliceValues; typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::TreeSliceValuesAndVertexPositions TreeSliceValuesAndVertexPositions; typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::TreeNode TreeNode; + using IndexedVertex = std::pair< node_index_type , Vertex >; template< unsigned int WeightDegree > using DensityEstimator = typename _LevelSetExtractor< HasData , Real , Dim , Data >::template DensityEstimator< WeightDegree >; static int SetCornerValuesFlag( void ){ return _LevelSetExtractor< HasData , Real , Dim , Data >::SetCornerValuesFlag(); } static int SetIsoVerticesFlag ( void ){ return _LevelSetExtractor< HasData , Real , Dim , Data >::SetIsoVerticesFlag (); } @@ -1175,12 +1228,22 @@ struct LevelSetExtractor< Real , 2 , Data > template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputDataStream< Vertex > &vertexStream , OutputDataStream< std::pair< node_index_type , node_index_type > > &edgeStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool flipOrientation ) { - return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , vertexStream , edgeStream , zeroData , nonLinearFit , outputGradients , flipOrientation ); + return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputDataStream< Vertex > , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , vertexStream , edgeStream , zeroData , nonLinearFit , outputGradients , flipOrientation ); + } + template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputDataStream< IndexedVertex > &vertexStream , OutputDataStream< std::pair< node_index_type , node_index_type > > &edgeStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool flipOrientation ) + { + return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputDataStream< IndexedVertex > , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , vertexStream , edgeStream , zeroData , nonLinearFit , outputGradients , flipOrientation ); } template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputDataStream< Vertex > &vertexStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , std::vector< SliceValues > &sliceValues , int setFlag ) { - return _LevelSetExtractor< HasData , Real , Dim , Data >::template SetSliceValues< WeightDegree , DataSig , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , vertexStream , zeroData , nonLinearFit , outputGradients , sliceValues , setFlag ); + return _LevelSetExtractor< HasData , Real , Dim , Data >::template SetSliceValues< WeightDegree , DataSig , OutputDataStream< Vertex > , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , vertexStream , zeroData , nonLinearFit , outputGradients , sliceValues , setFlag ); + } + template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > + static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputDataStream< IndexedVertex > &vertexStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , std::vector< SliceValues > &sliceValues , int setFlag ) + { + return _LevelSetExtractor< HasData , Real , Dim , Data >::template SetSliceValues< WeightDegree , DataSig , OutputDataStream< IndexedVertex > , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , vertexStream , zeroData , nonLinearFit , outputGradients , sliceValues , setFlag ); } }; diff --git a/Src/FEMTree.LevelSet.3D.inl b/Src/FEMTree.LevelSet.3D.inl index bfdc5b96..df12f23d 100644 --- a/Src/FEMTree.LevelSet.3D.inl +++ b/Src/FEMTree.LevelSet.3D.inl @@ -617,7 +617,7 @@ public: return incidence; } - template< unsigned int WeightDegree , unsigned int DataSig , typename SliceFunctor /* = std::function< SliceValues & ( unsigned int ) > */ , typename ScratchFunctor /* = std::function< typename SliceValues::Scratch & ( unsigned int ) */ > + template< unsigned int WeightDegree , unsigned int DataSig , typename OutputVertexStream , typename SliceFunctor /* = std::function< SliceValues & ( unsigned int ) > */ , typename ScratchFunctor /* = std::function< typename SliceValues::Scratch & ( unsigned int ) */ > static void CopyIsoStructure ( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , @@ -629,12 +629,12 @@ public: SliceFunctor sliceFunctor , ScratchFunctor scratchFunctor , const std::vector< std::pair< node_index_type , node_index_type > > &incidence , - OutputDataStream< Vertex > &vertexStream , + OutputVertexStream &vertexStream , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > > *pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , - node_index_type& vOffset , + std::atomic< node_index_type > &vOffset , const Data &zeroData ) { @@ -703,7 +703,6 @@ public: { ConstPointSupportKey< IsotropicUIntPack< Dim , WeightDegree > > weightKey; ConstPointSupportKey< IsotropicUIntPack< Dim , DataDegree > > dataKey; - vertexIndices[i] = vOffset++; Point< Real , Dim > p; for( unsigned int d=0 ; d() = Point< Real , Dim >(); vertices[i].template get<2>() = depth; if constexpr( HasData ) vertices[i].template get<3>() = dataValue; - vertexStream.write( vertices[i] ); + vertexIndices[i] = vOffset++; + if constexpr( std::is_base_of_v< OutputDataStream< std::pair< node_index_type , Vertex > > , OutputVertexStream > ) + vertexStream.write( 0 , std::pair< node_index_type , Vertex >( vertexIndices[i] , vertices[i] ) ); + else if constexpr( std::is_base_of_v< OutputDataStream< Vertex > , OutputVertexStream > ) + vertexStream.write( vertices[i] ); + else ERROR_OUT( "Bad stream type: " , typeid(OutputVertexStream).name() ); } } @@ -992,15 +996,15 @@ public: ); } - template< unsigned int WeightDegree , unsigned int DataSig > - static void SetSliceIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slice , node_index_type& vOffset , OutputDataStream< Vertex >& vertices , std::vector< SlabValues >& slabValues , const Data &zeroData ) + template< unsigned int WeightDegree , unsigned int DataSig , typename OutputVertexStream > + static void SetSliceIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slice , std::atomic< node_index_type > &vOffset , OutputVertexStream &vertexStream , std::vector< SlabValues >& slabValues , const Data &zeroData ) { - if( slice>0 ) SetSliceIsoVertices< WeightDegree , DataSig >( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , depth , fullDepth , slice , HyperCube::FRONT , vOffset , vertices , slabValues , zeroData ); - if( slice<(1<( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , depth , fullDepth , slice , HyperCube::BACK , vOffset , vertices , slabValues , zeroData ); + if( slice>0 ) SetSliceIsoVertices< WeightDegree , DataSig >( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , depth , fullDepth , slice , HyperCube::FRONT , vOffset , vertexStream , slabValues , zeroData ); + if( slice<(1<( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , depth , fullDepth , slice , HyperCube::BACK , vOffset , vertexStream , slabValues , zeroData ); } - template< unsigned int WeightDegree , unsigned int DataSig > - static void SetSliceIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slice , HyperCube::Direction zDir , node_index_type& vOffset , OutputDataStream< Vertex >& vertices , std::vector< SlabValues >& slabValues , const Data &zeroData ) + template< unsigned int WeightDegree , unsigned int DataSig , typename OutputVertexStream > + static void SetSliceIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slice , HyperCube::Direction zDir , std::atomic< node_index_type > &vOffset , OutputVertexStream &vertexStream , std::vector< SlabValues >& slabValues , const Data &zeroData ) { auto _EdgeIndex = [&]( const TreeNode *node , typename HyperCube::Cube< Dim >::template Element< 1 > e ) { @@ -1052,18 +1056,33 @@ public: GetIsoVertex< WeightDegree , DataSig >( tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , _e , zDir , sValues , vertex , zeroData ); bool stillOwner = false; std::pair< node_index_type , Vertex > hashed_vertex; + if constexpr( std::is_base_of_v< OutputDataStream< std::pair< node_index_type , Vertex > > , OutputVertexStream > ) + { + char desired = 1 , expected = 0; +#ifdef SANITIZED_PR + if( edgeSet.compare_exchange_weak( expected , desired ) ) +#else // !SANITIZED_PR + if( SetAtomic( edgeSet , desired , expected ) ) +#endif // SANITIZED_PR + { + hashed_vertex = std::pair< node_index_type , Vertex >( vOffset++ , vertex ); + vertexStream.write( thread , hashed_vertex ); + stillOwner = true; + } + } + else if constexpr( std::is_base_of_v< OutputDataStream< Vertex > , OutputVertexStream > ) { std::lock_guard< std::mutex > lock( _pointInsertionMutex ); if( !edgeSet ) { - vertices.write( vertex ); + hashed_vertex = std::pair< node_index_type , Vertex >( vOffset++ , vertex ); + vertexStream.write( vertex ); edgeSet = 1; - hashed_vertex = std::pair< node_index_type , Vertex >( vOffset , vertex ); - sValues.edgeKeys[ vIndex ] = key; - vOffset++; stillOwner = true; } } + else ERROR_OUT( "Bad stream type: " , typeid(OutputVertexStream).name() ); + if( stillOwner ) { sValues.edgeKeys[ vIndex ] = key; @@ -1132,8 +1151,8 @@ public: //////////////////// // Iso-Extraction // //////////////////// - template< unsigned int WeightDegree , unsigned int DataSig > - static void SetXSliceIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slab , Real bCoordinate , Real fCoordinate , node_index_type &vOffset , OutputDataStream< Vertex > &vertices , std::vector< SlabValues >& slabValues , const Data &zeroData ) + template< unsigned int WeightDegree , unsigned int DataSig , typename OutputVertexStream > + static void SetXSliceIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slab , Real bCoordinate , Real fCoordinate , std::atomic< node_index_type > &vOffset , OutputVertexStream &vertexStream , std::vector< SlabValues >& slabValues , const Data &zeroData ) { auto _EdgeIndex = [&]( const TreeNode *node , typename HyperCube::Cube< Dim >::template Element< 1 > e ) { @@ -1191,18 +1210,33 @@ public: GetIsoVertex< WeightDegree , DataSig >( tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , _c , bCoordinate , fCoordinate , bValues , fValues , vertex , zeroData ); bool stillOwner = false; std::pair< node_index_type , Vertex > hashed_vertex; + if constexpr( std::is_base_of_v< OutputDataStream< std::pair< node_index_type , Vertex > > , OutputVertexStream > ) + { + char desired = 1 , expected = 0; +#ifdef SANITIZED_PR + if( edgeSet.compare_exchange_weak( expected , desired ) ) +#else // !SANITIZED_PR + if( SetAtomic( edgeSet , desired , expected ) ) +#endif // SANITIZED_PR + { + hashed_vertex = std::pair< node_index_type , Vertex >( vOffset++ , vertex ); + vertexStream.write( thread , hashed_vertex ); + stillOwner = true; + } + } + else if constexpr( std::is_base_of_v< OutputDataStream< Vertex > , OutputVertexStream > ) { std::lock_guard< std::mutex > lock( _pointInsertionMutex ); if( !edgeSet ) { - vertices.write( vertex ); + hashed_vertex = std::pair< node_index_type , Vertex >( vOffset++ , vertex ); + vertexStream.write( vertex ); edgeSet = 1; - hashed_vertex = std::pair< node_index_type , Vertex >( vOffset , vertex ); - xValues.edgeKeys[ vIndex ] = key; - vOffset++; stillOwner = true; } } + else ERROR_OUT( "Bad stream type: " , typeid(OutputVertexStream).name() ); + if( stillOwner ) { xValues.edgeKeys[ vIndex ] = key; @@ -1567,8 +1601,8 @@ public: ); } - template< typename FaceIndexFunctor /* = std::function< LevelSetExtraction::Key< Dim > ( const TreeNode * , typename HyperCube::Cube< Dim >::template Element< 2 > ) */ > - static void SetLevelSet( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , FaceIndexFunctor faceIndexFunctor , const FEMTree< Dim , Real >& tree , LocalDepth depth , int offset , const SliceValues& bValues , const SliceValues& fValues , const XSliceValues& xValues , const typename SliceValues::Scratch &bScratch , const typename SliceValues::Scratch &fScratch , const typename XSliceValues::Scratch &xScratch , OutputDataStream< Vertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool polygonMesh , bool addBarycenter , node_index_type& vOffset , bool flipOrientation ) + template< typename OutputVertexStream , typename FaceIndexFunctor /* = std::function< LevelSetExtraction::Key< Dim > ( const TreeNode * , typename HyperCube::Cube< Dim >::template Element< 2 > ) */ > + static void SetLevelSet( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , FaceIndexFunctor faceIndexFunctor , const FEMTree< Dim , Real >& tree , LocalDepth depth , int offset , const SliceValues& bValues , const SliceValues& fValues , const XSliceValues& xValues , const typename SliceValues::Scratch &bScratch , const typename SliceValues::Scratch &fScratch , const typename XSliceValues::Scratch &xScratch , OutputVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool polygonMesh , bool addBarycenter , std::atomic< node_index_type > &vOffset , bool flipOrientation ) { std::vector< std::pair< node_index_type , Vertex > > polygon; std::vector< std::vector< IsoEdge > > edgess( ThreadPool::NumThreads() ); @@ -1894,7 +1928,8 @@ public: return true; } - static unsigned int AddIsoPolygons( unsigned int thread , OutputDataStream< Vertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , std::vector< std::pair< node_index_type , Vertex > >& polygon , bool polygonMesh , bool addBarycenter , node_index_type &vOffset ) + template< typename OutputVertexStream > + static unsigned int AddIsoPolygons( unsigned int thread , OutputVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , std::vector< std::pair< node_index_type , Vertex > >& polygon , bool polygonMesh , bool addBarycenter , std::atomic< node_index_type > &vOffset ) { if( polygonMesh ) { @@ -1921,12 +1956,21 @@ public: c *= 0; for( unsigned int i=0 ; i > , OutputVertexStream > ) + { + cIdx = vOffset++; + vertexStream.write( thread , std::pair< node_index_type , Vertex >(cIdx,c) ); + } + else if constexpr( std::is_base_of_v< OutputDataStream< Vertex > , OutputVertexStream > ) { std::lock_guard< std::mutex > lock( _pointInsertionMutex ); - vertexStream.write( c ); cIdx = vOffset++; + vertexStream.write( c ); } + else ERROR_OUT( "Bad stream type: " , typeid(OutputVertexStream).name() ); + for( unsigned i=0 ; i + template< unsigned int WeightDegree , unsigned int DataSig , typename OutputVertexStream , unsigned int ... FEMSigs > static Stats Extract ( UIntPack< FEMSigs ... > , @@ -1989,7 +2033,7 @@ public: unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , - OutputDataStream< Vertex > &vertexStream , + OutputVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , const Data &zeroData , bool nonLinearFit , @@ -2042,7 +2086,7 @@ public: std::vector< _Evaluator< UIntPack< FEMSigs ... > , 1 > > evaluators( tree._maxDepth+1 ); for( LocalDepth d=0 ; d<=tree._maxDepth ; d++ ) evaluators[d].set( tree._maxDepth ); - node_index_type vertexOffset = 0; + std::atomic< node_index_type > vertexOffset = 0; std::vector< SlabValues > slabValues( tree._maxDepth+1 ); std::vector< std::pair< node_index_type , node_index_type > > backIncidence , frontIncidence; @@ -2410,6 +2454,7 @@ struct LevelSetExtractor< Real , 3 > typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::Stats Stats; typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::Vertex Vertex; typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::TreeNode TreeNode; + using IndexedVertex = std::pair< node_index_type , Vertex >; template< unsigned int WeightDegree > using DensityEstimator = typename _LevelSetExtractor< HasData , Real , Dim , Data >::template DensityEstimator< WeightDegree >; template< unsigned int WeightDegree , unsigned int ... FEMSigs > @@ -2431,7 +2476,29 @@ struct LevelSetExtractor< Real , 3 > static const unsigned int DataSig = FEMDegreeAndBType< 0 , BOUNDARY_FREE >::Signature; const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data = NULL; Data zeroData = 0; - return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , backBoundary , frontBoundary , backDValues , frontDValues , copyTopology ); + return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputDataStream< Vertex > , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , backBoundary , frontBoundary , backDValues , frontDValues , copyTopology ); + } + + template< unsigned int WeightDegree , unsigned int ... FEMSigs > + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree > *densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputDataStream< IndexedVertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) + { + return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , tree , densityWeights , coefficients , isoValue , 0 , 0 , 1 , vertexStream , polygonStream , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation ); + } + + template< unsigned int WeightDegree , unsigned int ... FEMSigs > + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputDataStream< IndexedVertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) + { + std::vector< std::vector< Real > > dValues; + return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , tree , tree._maxDepth , densityWeights , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , NULL , NULL , dValues , dValues , false ); + } + + template< unsigned int WeightDegree , unsigned int ... FEMSigs > + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , int maxKeyDepth , const DensityEstimator< WeightDegree >* densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputDataStream< IndexedVertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *backBoundary , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *frontBoundary , const std::vector< std::vector< Real > > &backDValues , const std::vector< std::vector< Real > > &frontDValues , bool copyTopology ) + { + static const unsigned int DataSig = FEMDegreeAndBType< 0 , BOUNDARY_FREE >::Signature; + const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data = NULL; + Data zeroData = 0; + return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputDataStream< IndexedVertex > , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , backBoundary , frontBoundary , backDValues , frontDValues , copyTopology ); } }; @@ -2443,6 +2510,7 @@ struct LevelSetExtractor< Real , 3 , Data > typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::Stats Stats; typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::Vertex Vertex; typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::TreeNode TreeNode; + using IndexedVertex = std::pair< node_index_type , Vertex >; template< unsigned int WeightDegree > using DensityEstimator = typename _LevelSetExtractor< HasData , Real , Dim , Data >::template DensityEstimator< WeightDegree >; template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > @@ -2461,6 +2529,25 @@ struct LevelSetExtractor< Real , 3 , Data > template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , int maxKeyDepth , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputDataStream< Vertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *backBoundary , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *frontBoundary , const std::vector< std::vector< Real > > &backDValues , const std::vector< std::vector< Real > > &frontDValues , bool copyTopology ) { - return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , backBoundary , frontBoundary , backDValues , frontDValues , copyTopology ); + return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputDataStream< Vertex > , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , backBoundary , frontBoundary , backDValues , frontDValues , copyTopology ); + } + + template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputDataStream< IndexedVertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) + { + return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , 0 , 0 , 1 , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation ); + } + + template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputDataStream< IndexedVertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) + { + std::vector< std::vector< Real > > dValues; + return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , tree._maxDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , NULL , NULL , dValues , dValues , false ); + } + + template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , int maxKeyDepth , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputDataStream< IndexedVertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *backBoundary , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *frontBoundary , const std::vector< std::vector< Real > > &backDValues , const std::vector< std::vector< Real > > &frontDValues , bool copyTopology ) + { + return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputDataStream< IndexedVertex > , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , backBoundary , frontBoundary , backDValues , frontDValues , copyTopology ); } }; diff --git a/Src/FEMTree.h b/Src/FEMTree.h index 7fcf8818..58d20cb7 100644 --- a/Src/FEMTree.h +++ b/Src/FEMTree.h @@ -319,6 +319,12 @@ namespace PoissonRecon SparseNodeData( void ){} SparseNodeData( BinaryStream &stream ){ read(stream); } SparseNodeData( BinaryStream &stream , const Serializer< Data > &serializer ){ read(stream,serializer); } + // [WARNING] Default constructing the mutex + SparseNodeData( const SparseNodeData &d ) : _indices(d._indices) , _data(d._data){}; + SparseNodeData( SparseNodeData &&d ) : _indices(d._indices) , _data(d._data){}; + // [WARNING] Not copying the mutex + SparseNodeData &operator = ( const SparseNodeData &d ){ _indices = d._indices , _data = d._data ; return *this; } + SparseNodeData &operator = ( SparseNodeData &&d ){ std::swap( _indices , d._indices ) , std::swap( _data , d._data ); return *this; } size_t size( void ) const { return _data.size(); } const Data& operator[] ( size_t idx ) const { return _data[idx]; } @@ -341,7 +347,6 @@ namespace PoissonRecon #endif // SANITIZED_PR if( _index==-1 ) { - static std::mutex _updateMutex; std::lock_guard< std::mutex > lock( _updateMutex ); #ifdef SANITIZED_PR _index = ReadAtomic( *indexPtr ); @@ -483,6 +488,7 @@ namespace PoissonRecon return sparseNodeData; } + std::mutex _updateMutex; NestedVector< node_index_type , NESTED_VECTOR_LEVELS > _indices; NestedVector< Data , NESTED_VECTOR_LEVELS > _data; }; @@ -3028,10 +3034,10 @@ namespace PoissonRecon std::vector< node_index_type > _nodeToIndexMap; }; - template< typename Data > - static size_t Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , typename InputPointStream< Data >::StreamType &pointStream , Data zeroData , int maxDepth , std::vector< PointSample >& samplePoints , std::vector< typename InputPointStream< Data >::DataType > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , typename InputPointStream< Data >::DataType & ) > ProcessData = []( const Point< Real , Dim > & , typename InputPointStream< Data >::DataType & ){ return (Real)1.; } ); - template< typename Data > - static size_t Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , typename InputPointStream< Data >::StreamType &pointStream , Data zeroData , int maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , std::vector< PointSample >& samplePoints , std::vector< typename InputPointStream< Data >::DataType > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , typename InputPointStream< Data >::DataType & ) > ProcessData = []( const Point< Real , Dim > & , typename InputPointStream< Data >::DataType & ){ return (Real)1.; } ); + template< typename AuxData , typename PointStream > + static size_t Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , PointStream &pointStream , AuxData zeroData , int maxDepth , std::vector< PointSample >& samplePoints , std::vector< AuxData > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , AuxData & ) > ProcessData = []( const Point< Real , Dim > & , AuxData & ){ return (Real)1.; } ); + template< typename AuxData , typename PointStream > + static size_t Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , PointStream &pointStream , AuxData zeroData , int maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , std::vector< PointSample >& samplePoints , std::vector< AuxData > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , AuxData & ) > ProcessData = []( const Point< Real , Dim > & , AuxData & ){ return (Real)1.; } ); // Initialize the tree using simplices static void Initialize( FEMTreeNode& root , const std::vector< Point< Real , Dim > >& vertices , const std::vector< SimplexIndex< Dim-1 , node_index_type > >& simplices , int maxDepth , std::vector< PointSample >& samples , bool mergeNodeSamples , std::vector< Allocator< FEMTreeNode > * > &nodeAllocators , std::function< void ( FEMTreeNode& ) > NodeInitializer ); diff --git a/Src/MyAtomic.h b/Src/MyAtomic.h index 578c540f..49036ce1 100644 --- a/Src/MyAtomic.h +++ b/Src/MyAtomic.h @@ -41,22 +41,27 @@ DAMAGE. namespace PoissonRecon { + template< typename Value > Value ReadAtomic8_( const volatile Value * value ); template< typename Value > Value ReadAtomic32_( const volatile Value * value ); template< typename Value > Value ReadAtomic64_( const volatile Value * value ); + template< typename Value > Value SetAtomic8_ ( volatile Value * value , Value newValue ); template< typename Value > Value SetAtomic32_( volatile Value * value , Value newValue ); template< typename Value > Value SetAtomic64_( volatile Value * value , Value newValue ); + template< typename Value > bool SetAtomic8_ ( volatile Value * value , Value newValue , Value oldValue ); template< typename Value > bool SetAtomic32_( volatile Value * value , Value newValue , Value oldValue ); template< typename Value > bool SetAtomic64_( volatile Value * value , Value newValue , Value oldValue ); + template< typename Value > void AddAtomic8_( volatile Value * a , Value b ); template< typename Value > void AddAtomic32_( volatile Value * a , Value b ); template< typename Value > void AddAtomic64_( volatile Value * a , Value b ); template< typename Value > Value SetAtomic( volatile Value & value , Value newValue ) { - if constexpr( sizeof(Value)==4 ) return SetAtomic32_( &value , newValue ); + if constexpr( sizeof(Value)==1 ) return SetAtomic8_ ( &value , newValue ); + else if constexpr( sizeof(Value)==4 ) return SetAtomic32_( &value , newValue ); else if constexpr( sizeof(Value)==8 ) return SetAtomic64_( &value , newValue ); else { @@ -72,7 +77,8 @@ namespace PoissonRecon template< typename Value > bool SetAtomic( volatile Value & value , Value newValue , Value oldValue ) { - if constexpr( sizeof(Value)==4 ) return SetAtomic32_( &value , newValue , oldValue ); + if constexpr( sizeof(Value)==1 ) return SetAtomic8_ ( &value , newValue , oldValue ); + else if constexpr( sizeof(Value)==4 ) return SetAtomic32_( &value , newValue , oldValue ); else if constexpr( sizeof(Value)==8 ) return SetAtomic64_( &value , newValue , oldValue ); else { @@ -87,7 +93,8 @@ namespace PoissonRecon template< typename Value > void AddAtomic( volatile Value & a , Value b ) { - if constexpr( sizeof(Value)==4 ) return AddAtomic32_( &a , b ); + if constexpr( sizeof(Value)==1 ) return AddAtomic8_ ( &a , b ); + else if constexpr( sizeof(Value)==4 ) return AddAtomic32_( &a , b ); else if constexpr( sizeof(Value)==8 ) return AddAtomic64_( &a , b ); else { @@ -101,7 +108,8 @@ namespace PoissonRecon template< typename Value > Value ReadAtomic( const volatile Value & value ) { - if constexpr( sizeof(Value)==4 ) return ReadAtomic32_( &value ); + if constexpr( sizeof(Value)==1 ) return ReadAtomic8_( &value ); + else if constexpr( sizeof(Value)==4 ) return ReadAtomic32_( &value ); else if constexpr( sizeof(Value)==8 ) return ReadAtomic64_( &value ); else { @@ -116,6 +124,18 @@ namespace PoissonRecon /////////////////////////////////////////////// /////////////////////////////////////////////// + template< typename Value > + Value ReadAtomic8_( const volatile Value * value ) + { +#if defined( _WIN32 ) || defined( _WIN64 ) + char _value = InterlockedExchangeAdd8( (char*)value , 0 ); + return *(Value*)(&_value); +#else // !_WIN32 && !_WIN64 + uint8_t _value = __atomic_load_n( (uint8_t *)value , __ATOMIC_SEQ_CST ); +#endif // _WIN32 || _WIN64 + return *(Value*)(&_value); + } + template< typename Value > Value ReadAtomic32_( const volatile Value * value ) { @@ -139,6 +159,19 @@ namespace PoissonRecon return *(Value*)(&_value); } + template< typename Value > + Value SetAtomic8_( volatile Value *value , Value newValue ) + { +#if defined( _WIN32 ) || defined( _WIN64 ) + char *_newValue = (char *)&newValue; + char oldValue = InterlockedExchange( (char*)value , *_newValue ); +#else // !_WIN32 && !_WIN64 + uint8_t *_newValue = (uint8_t *)&newValue; + uint8_t oldValue = __atomic_exchange_n( (uint8_t *)value , *_newValue , __ATOMIC_SEQ_CST ); +#endif // _WIN32 || _WIN64 + return *(Value*)&oldValue; + } + template< typename Value > Value SetAtomic32_( volatile Value *value , Value newValue ) { @@ -165,6 +198,19 @@ namespace PoissonRecon return *(Value*)&oldValue; } + template< typename Value > + bool SetAtomic8_( volatile Value *value , Value newValue , Value oldValue ) + { +#if defined( _WIN32 ) || defined( _WIN64 ) + char *_oldValue = (char *)&oldValue; + char *_newValue = (char *)&newValue; + return _InterlockedCompareExchange8( (char*)value , *_newValue , *_oldValue )==*_oldValue; +#else // !_WIN32 && !_WIN64 + uint8_t *_newValue = (uint8_t *)&newValue; + return __atomic_compare_exchange_n( (uint8_t *)value , (uint8_t *)&oldValue , *_newValue , false , __ATOMIC_SEQ_CST , __ATOMIC_SEQ_CST ); +#endif // _WIN32 || _WIN64 + } + template< typename Value > bool SetAtomic32_( volatile Value *value , Value newValue , Value oldValue ) { @@ -191,6 +237,42 @@ namespace PoissonRecon #endif // _WIN32 || _WIN64 } + template< typename Value > + void AddAtomic8_( volatile Value *a , Value b ) + { +#ifdef SANITIZED_PR + Value current = ReadAtomic8_( a ); +#else // !SANITIZED_PR + Value current = *a; +#endif // SANITIZED_PR + Value sum = current+b; +#if defined( _WIN32 ) || defined( _WIN64 ) + char *_current = (char *)¤t; + char *_sum = (char *)∑ +#ifdef SANITIZED_PR + while( InterlockedCompareExchange( (char*)a , *_sum , *_current )!=*_current ) + { + current = ReadAtomic8_( a ); + sum = current + b; + } +#else // !SANITIZED_PR + while( InterlockedCompareExchange( (char*)a , *_sum , *_current )!=*_current ) current = *(Value*)a , sum = *(Value*)a+b; +#endif // SANITIZED_PR +#else // !_WIN32 && !_WIN64 + uint8_t *_current = (uint8_t *)¤t; + uint8_t *_sum = (uint8_t *)∑ +#ifdef SANITIZED_PR + while( __sync_val_compare_and_swap( (uint8_t *)a , *_current , *_sum )!=*_current ) + { + current = ReadAtomic8_( a ); + sum = current+b; + } +#else // !SANITIZED_PR + while( __sync_val_compare_and_swap( (uint8_t *)a , *_current , *_sum )!=*_current ) current = *(Value*)a , sum = *(Value*)a+b; +#endif // SANITIZED_PR +#endif // _WIN32 || _WIN64 + } + template< typename Value > void AddAtomic32_( volatile Value *a , Value b ) { diff --git a/Src/PointInterpolant.cpp b/Src/PointInterpolant.cpp index 701688cc..25aecc10 100644 --- a/Src/PointInterpolant.cpp +++ b/Src/PointInterpolant.cpp @@ -360,13 +360,13 @@ void ExtractLevelSet Factory factory = VInfo::GetFactory(); // A backing stream for the vertices - Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , false , false ); + Reconstructor::OutputInputFactoryTypeStream< Factory , false > vertexStream( factory , false ); Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( false , true ); typename LevelSetExtractor< Real , Dim >::Stats stats; { // The wrapper converting native to output types - typename VInfo::StreamWrapper _vertexStream( vertexStream , factory() ); + typename VInfo::StreamWrapper _vertexStream( vertexStream ); Reconstructor::TransformedOutputVertexStream< Real , Dim > __vertexStream( unitCubeToModel , _vertexStream ); // Extract the mesh diff --git a/Src/PoissonRecon.client.inl b/Src/PoissonRecon.client.inl index 2f616dad..8bde2c3b 100644 --- a/Src/PoissonRecon.client.inl +++ b/Src/PoissonRecon.client.inl @@ -1251,24 +1251,24 @@ void Client< Real , Dim , BType , Degree >::_writeMeshWithData( const ClientReco // A description of the output vertex information - using VInfo = Reconstructor::OutputVertexWithDataInfo< Real , Dim , AuxDataFactory , HasGradients , HasDensity >; + using VInfo = Reconstructor::OutputVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactory >; // A factory generating the output vertices using Factory = typename VInfo::Factory; Factory factory = VInfo::GetFactory( auxDataFactory ); // A backing stream for the vertices - Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , false , false ); + Reconstructor::OutputInputFactoryTypeStream< Factory , false > vertexStream( factory , false ); Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( false , true ); typename LevelSetExtractor< Real , Dim , AuxData >::Stats stats; { // The wrapper converting native to output types - typename VInfo::StreamWrapper _vertexStream( vertexStream , factory() ); + typename VInfo::StreamWrapper _vertexStream( vertexStream ); // The transformed stream - Reconstructor::TransformedOutputVertexWithDataStream< Real , Dim , AuxData > __vertexStream( unitCubeToModel , _vertexStream ); + Reconstructor::TransformedOutputVertexStream< Real , Dim , AuxData > __vertexStream( unitCubeToModel , _vertexStream ); // Extract the mesh stats = LevelSetExtractor< Real , Dim , AuxData >::template Extract< Reconstructor::WeightDegree , DataSig > @@ -1319,8 +1319,16 @@ void Client< Real , Dim , BType , Degree >::_process7( const ClientReconstructio // Extract the mesh if constexpr( Dim==3 ) { - if( clientReconInfo.density ) _writeMeshWithData< false , true >( clientReconInfo , state7 , _modelToUnitCube.inverse() ); - else _writeMeshWithData< false , false >( clientReconInfo , state7 , _modelToUnitCube.inverse() ); + XForm< Real , Dim+1 > unitCubeToModel; + if( clientReconInfo.gridCoordinates ) + { + unitCubeToModel = XForm< Real , Dim+1 >::Identity(); + unsigned int res = 1<( clientReconInfo , state7 , unitCubeToModel ); + else _writeMeshWithData< false , false >( clientReconInfo , state7 , unitCubeToModel ); } if( clientReconInfo.ouputVoxelGrid ) diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index 6080f08b..00d92b41 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -70,6 +70,7 @@ CmdLineReadable InCore( "inCore" ) , NoDirichletErode( "noErode" ) , Gradients( "gradients" ) , + GridCoordinates( "gridCoordinates" ) , Verbose( "verbose" ); CmdLineParameter< int > @@ -142,6 +143,7 @@ CmdLineReadable* params[] = &LowDepthCutOff , &AlignmentDir , &TargetValue , + &GridCoordinates , NULL }; @@ -188,6 +190,7 @@ void ShowUsage(char* ex) printf( "\t[--%s =%g]\n" , CGSolverAccuracy.name , CGSolverAccuracy.value ); printf( "\t[--%s =%d]\n" , MaxMemoryGB.name , MaxMemoryGB.value ); printf( "\t[--%s]\n" , NoDirichletErode.name ); + printf( "\t[--%s]\n" , GridCoordinates.name ); printf( "\t[--%s]\n" , Performance.name ); printf( "\t[--%s]\n" , Density.name ); printf( "\t[--%s]\n" , LinearFit.name ); @@ -198,30 +201,31 @@ void ShowUsage(char* ex) printf( "\t[--%s]\n" , Verbose.name ); } -template< typename Real , unsigned int Dim , unsigned int FEMSig , bool HasGradients , bool HasDensity > +template< typename Real , unsigned int Dim , unsigned int FEMSig , bool HasGradients , bool HasDensity , typename ... AuxDataFactories > void WriteMesh ( bool inCore , - Reconstructor::Implicit< Real , Dim , FEMSig > &implicit , + Reconstructor::Implicit< Real , Dim , FEMSig , typename AuxDataFactories::VertexType ... > &implicit , const Reconstructor::LevelSetExtractionParameters &meParams , std::string fileName , - bool ascii + bool ascii , + const AuxDataFactories& ... factories ) { // A description of the output vertex information - using VInfo = Reconstructor::OutputVertexInfo< Real , Dim , HasGradients , HasDensity >; + using VInfo = Reconstructor::OutputIndexedVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactories ... >; // A factory generating the output vertices using Factory = typename VInfo::Factory; - Factory factory = VInfo::GetFactory(); + Factory factory = VInfo::GetFactory( factories... ); // A backing stream for the vertices - Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , inCore , false ); + Reconstructor::OutputInputFactoryTypeStream< Factory , true > vertexStream( factory , inCore ); Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( inCore , true ); { // The wrapper converting native to output types - typename VInfo::StreamWrapper _vertexStream( vertexStream , factory() ); + typename VInfo::StreamWrapper _vertexStream( vertexStream ); // Extract the level set implicit.extractLevelSet( _vertexStream , faceStream , meParams ); @@ -229,42 +233,9 @@ void WriteMesh // Write the mesh to a .ply file std::vector< std::string > noComments; - PLY::Write< Factory , node_index_type , Real , Dim >( fileName , factory , vertexStream.size() , faceStream.size() , vertexStream , faceStream , ascii ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); -} - -template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxDataFactory , bool HasGradients , bool HasDensity > -void WriteMeshWithData -( - const AuxDataFactory &auxDataFactory , - bool inCore , - Reconstructor::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType > &implicit , - const Reconstructor::LevelSetExtractionParameters &meParams , - std::string fileName , - bool ascii -) -{ - // A description of the output vertex information - using VInfo = Reconstructor::OutputVertexWithDataInfo< Real , Dim , AuxDataFactory , HasGradients , HasDensity >; - - // A factory generating the output vertices - using Factory = typename VInfo::Factory; - Factory factory = VInfo::GetFactory( auxDataFactory ); - - // A backing stream for the vertices - Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , inCore , false ); - Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( inCore , true ); - - { - // The wrapper converting native to output types - typename VInfo::StreamWrapper _vertexStream( vertexStream , factory() ); - - // Extract the level set - implicit.extractLevelSet( _vertexStream , faceStream , meParams ); - } - - // Write the mesh to a .ply file - std::vector< std::string > noComments; - PLY::Write< Factory , node_index_type , Real , Dim >( fileName , factory , vertexStream.size() , faceStream.size() , vertexStream , faceStream , ascii ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); + vertexStream.reset(); + IndexedInputDataStream< node_index_type , typename Factory::VertexType > vStream( vertexStream , factory() ); + PLY::Write< Factory , node_index_type , Real , Dim >( fileName , factory , vertexStream.size() , faceStream.size() , vStream , faceStream , ascii ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); } template< class Real , unsigned int Dim , unsigned int FEMSig , typename AuxDataFactory > @@ -340,6 +311,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) meParams.outputGradients = Gradients.set; meParams.forceManifold = !NonManifold.set; meParams.polygonMesh = PolygonMesh.set; + meParams.gridCoordinates = GridCoordinates.set; meParams.verbose = Verbose.set; double startTime = Time(); @@ -430,17 +402,23 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( ret ) p = scratch.template get<0>() , n = scratch.template get<1>(); return ret; } + bool base_read( unsigned int thread , Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n ) + { + bool ret = pointStream.read( thread , scratch ); + if( ret ) p = scratch.template get<0>() , n = scratch.template get<1>(); + return ret; + } }; // A wrapper class to realize InputDataStream< SampleType > as an InputSampleWithDataStream - struct _InputSampleWithDataStream : public Reconstructor::InputSampleWithDataStream< Real , Dim , typename AuxDataFactory::VertexType > + struct _InputSampleWithDataStream : public Reconstructor::InputSampleStream< Real , Dim , typename AuxDataFactory::VertexType > { typedef VectorTypeUnion< Real , Reconstructor::Normal< Real , Dim > , typename AuxDataFactory::VertexType > DataType; typedef VectorTypeUnion< Real , Reconstructor::Position< Real , Dim > , DataType > SampleType; typedef InputDataStream< SampleType > _InputPointStream; _InputPointStream &pointStream; SampleType scratch; - _InputSampleWithDataStream( _InputPointStream &pointStream , typename AuxDataFactory::VertexType zero ) : Reconstructor::InputSampleWithDataStream< Real , Dim , typename AuxDataFactory::VertexType >( zero ) , pointStream( pointStream ) + _InputSampleWithDataStream( _InputPointStream &pointStream , typename AuxDataFactory::VertexType zero ) : Reconstructor::InputSampleStream< Real , Dim , typename AuxDataFactory::VertexType >( zero ) , pointStream( pointStream ) { scratch = SampleType( Reconstructor::Position< Real , Dim >() , DataType( Reconstructor::Normal< Real , Dim >() , zero ) ); } @@ -451,16 +429,22 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( ret ) p = scratch.template get<0>() , n = scratch.template get<1>().template get<0>() , d = scratch.template get<1>().template get<1>(); return ret; } + bool base_read( unsigned int thread , Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n , typename AuxDataFactory::VertexType &d ) + { + bool ret = pointStream.read( thread , scratch ); + if( ret ) p = scratch.template get<0>() , n = scratch.template get<1>().template get<0>() , d = scratch.template get<1>().template get<1>(); + return ret; + } }; - if( Transform.set and envelopeMesh ) for( unsigned int i=0 ; ivertices.size() ; i++ ) envelopeMesh->vertices[i] = toModel * envelopeMesh->vertices[i]; + if( Transform.set && envelopeMesh ) for( unsigned int i=0 ; ivertices.size() ; i++ ) envelopeMesh->vertices[i] = toModel * envelopeMesh->vertices[i]; if constexpr( HasAuxData ) { _InputSampleWithDataStream sampleStream( *pointStream , auxDataFactory() ); if( Transform.set ) { - Reconstructor::TransformedInputSampleWithDataStream< Real , Dim , typename AuxDataFactory::VertexType > _sampleStream( toModel , sampleStream ); + Reconstructor::TransformedInputSampleStream< Real , Dim , _InputSampleWithDataStream , typename AuxDataFactory::VertexType > _sampleStream( toModel , sampleStream ); implicit = new typename Reconstructor::Poisson::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( _sampleStream , sParams , envelopeMesh ); implicit->unitCubeToModel = toModel.inverse() * implicit->unitCubeToModel; } @@ -472,7 +456,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( Transform.set ) { - Reconstructor::TransformedInputSampleStream< Real , Dim > _sampleStream( toModel , sampleStream ); + Reconstructor::TransformedInputSampleStream< Real , Dim , _InputSampleStream > _sampleStream( toModel , sampleStream ); implicit = new typename Reconstructor::Poisson::Implicit< Real , Dim , FEMSig >( _sampleStream , sParams , envelopeMesh ); implicit->unitCubeToModel = toModel.inverse() * implicit->unitCubeToModel; } @@ -539,26 +523,26 @@ void Execute( const AuxDataFactory &auxDataFactory ) { if( Density.set ) { - if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , true , true >( auxDataFactory , InCore.set , *implicit , meParams , Out.value , ASCII.set ); - else WriteMesh < Real , Dim , FEMSig , true , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); + if constexpr( HasAuxData ) WriteMesh< Real , Dim , FEMSig , true , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set , auxDataFactory ); + else WriteMesh< Real , Dim , FEMSig , true , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); } else { - if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , true , false >( auxDataFactory , InCore.set , *implicit , meParams , Out.value , ASCII.set ); - else WriteMesh < Real , Dim , FEMSig , true , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); + if constexpr( HasAuxData ) WriteMesh< Real , Dim , FEMSig , true , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set , auxDataFactory ); + else WriteMesh< Real , Dim , FEMSig , true , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); } } else { if( Density.set ) { - if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , false , true >( auxDataFactory , InCore.set , *implicit , meParams , Out.value , ASCII.set ); - else WriteMesh < Real , Dim , FEMSig , false , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); + if constexpr( HasAuxData ) WriteMesh< Real , Dim , FEMSig , false , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set , auxDataFactory ); + else WriteMesh< Real , Dim , FEMSig , false , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); } else { - if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , false , false >( auxDataFactory , InCore.set , *implicit , meParams , Out.value , ASCII.set ); - else WriteMesh < Real , Dim , FEMSig , false , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); + if constexpr( HasAuxData ) WriteMesh< Real , Dim , FEMSig , false , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set , auxDataFactory ); + else WriteMesh< Real , Dim , FEMSig , false , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); } } } diff --git a/Src/PoissonRecon.server.inl b/Src/PoissonRecon.server.inl index 2dca601e..53edc5af 100644 --- a/Src/PoissonRecon.server.inl +++ b/Src/PoissonRecon.server.inl @@ -710,14 +710,13 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase6( const ClientReconstruc const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim-1 , DataSig > > *data=NULL; { VectorBackedOutputDataStream< Point< Real , Dim-1 > > _vertices( state6.vertices ); - struct VertexStreamWrapper : public Reconstructor::OutputVertexStreamWrapper< Real , Dim-1 , Point< Real , Dim-1 > > + struct VertexStreamWrapper : public Reconstructor::OutputVertexStreamWrapper< Point< Real , Dim-1 > , Real , Dim-1 > { typedef Point< Real , Dim-1 > Vertex; - VertexStreamWrapper( OutputDataStream< Vertex > &stream , Vertex out ) : - Reconstructor::OutputVertexStreamWrapper< Real , Dim-1 , Point< Real , Dim-1 > >( stream , out ) {} - void set( Vertex &out , const Reconstructor::BaseVertex< Real , Dim-1 > &in ){ out = in.template get<0>(); } + VertexStreamWrapper( OutputDataStream< Vertex > &stream ) : Reconstructor::OutputVertexStreamWrapper< Point< Real , Dim-1 > , Real , Dim-1 >( stream ) {} + Vertex toOutputVertex(const Reconstructor::LevelSetVertex< Real , Dim-1 > &in ){ return in.template get<0>(); } }; - VertexStreamWrapper __vertexStream( _vertices , Point< Real , Dim-1 >() ); + VertexStreamWrapper __vertexStream( _vertices ); LevelSetExtractor< Real , Dim-1 >::SetSliceValues( SliceSigs() , UIntPack< Reconstructor::WeightDegree >() , *state6.sliceTree , clientReconInfo.reconstructionDepth , density , state6.solution , isoValue , __vertexStream , !clientReconInfo.linearFit , false , state6.sliceValues , LevelSetExtractor< Real , Dim-1 , Vertex >::SetIsoEdgesFlag() ); if( !clientReconInfo.linearFit ) LevelSetExtractor< Real , Dim-1 >::SetSliceValues( SliceSigs() , UIntPack< Reconstructor::WeightDegree >() , *state6.sliceTree , clientReconInfo.reconstructionDepth , density , state6.dSolution , isoValue , __vertexStream , false , false , state6.dSliceValues , LevelSetExtractor< Real , Dim-1 , Vertex >::SetCornerValuesFlag() ); diff --git a/Src/PoissonReconClientServer.h b/Src/PoissonReconClientServer.h index d16fdcb9..56624959 100644 --- a/Src/PoissonReconClientServer.h +++ b/Src/PoissonReconClientServer.h @@ -65,7 +65,7 @@ namespace PoissonRecon unsigned int solveDepth , reconstructionDepth , sharedDepth , distributionDepth , baseDepth , kernelDepth , iters , bufferSize , filesPerDir , padSize , verbose; Real pointWeight , confidence , confidenceBias , samplesPerNode , dataX , cgSolverAccuracy , targetValue; MergeType mergeType; - bool density , linearFit , ouputVoxelGrid , outputSolution; + bool density , linearFit , ouputVoxelGrid , outputSolution , gridCoordinates; std::vector< PlyProperty > auxProperties; ClientReconstructionInfo( void ); diff --git a/Src/PoissonReconClientServer.inl b/Src/PoissonReconClientServer.inl index b911a133..97819b4f 100644 --- a/Src/PoissonReconClientServer.inl +++ b/Src/PoissonReconClientServer.inl @@ -333,6 +333,7 @@ ClientReconstructionInfo< Real , Dim >::ClientReconstructionInfo( void ) filesPerDir = -1; outputSolution = false; targetValue = (Real)0.5; + gridCoordinates = false; } template< typename Real , unsigned int Dim > @@ -371,6 +372,7 @@ ClientReconstructionInfo< Real , Dim >::ClientReconstructionInfo( BinaryStream & if( !ReadBool( density ) ) ERROR_OUT( "Failed to read density flag" ); if( !ReadBool( linearFit ) ) ERROR_OUT( "Failed to read linear-fit flag" ); if( !ReadBool( outputSolution ) ) ERROR_OUT( "Failed to read output-solution flag" ); + if( !ReadBool( gridCoordinates ) ) ERROR_OUT( "Failed to read grid-coordinates flag" ); if( !ReadBool( ouputVoxelGrid ) ) ERROR_OUT( "Failed to read output-voxel-grid flag" ); { size_t sz; @@ -414,6 +416,7 @@ void ClientReconstructionInfo< Real , Dim >::write( BinaryStream &stream ) const WriteBool( density ); WriteBool( linearFit ); WriteBool( outputSolution ); + WriteBool( gridCoordinates ); WriteBool( ouputVoxelGrid ); { size_t sz = auxProperties.size(); diff --git a/Src/PoissonReconServer.cpp b/Src/PoissonReconServer.cpp index 791cd39c..de5d7970 100644 --- a/Src/PoissonReconServer.cpp +++ b/Src/PoissonReconServer.cpp @@ -96,6 +96,7 @@ CmdLineReadable LinearFit( "linearFit" ) , OutputVoxelGrid( "grid" ) , OutputBoundarySlices( "boundary" ) , + GridCoordinates( "gridCoordinates" ) , KeepSeparate( "keepSeparate" ) , OutputSolution( "solution" ) , ShowDiscontinuity( "showDiscontinuity" ); @@ -135,6 +136,7 @@ CmdLineReadable* params[] = &PeakMemorySampleMS , &OutputVoxelGrid , &OutputBoundarySlices , + &GridCoordinates , &OutputSolution , &AlignmentDir , &ShowDiscontinuity , @@ -193,6 +195,7 @@ void ShowUsage( char* ex ) printf( "\t[--%s]\n" , LinearFit.name ); printf( "\t[--%s]\n" , OutputVoxelGrid.name ); printf( "\t[--%s]\n" , OutputBoundarySlices.name ); + printf( "\t[--%s]\n" , GridCoordinates.name ); printf( "\t[--%s]\n" , OutputSolution.name ); printf( "\t[--%s]\n" , ShowDiscontinuity.name ); printf( "\t[--%s]\n" , KeepSeparate.name ); @@ -503,6 +506,7 @@ int main( int argc , char* argv[] ) clientReconInfo.ouputVoxelGrid = OutputVoxelGrid.set; clientReconInfo.targetValue = TargetValue.value; clientReconInfo.outputSolution = OutputSolution.set; + clientReconInfo.gridCoordinates = GridCoordinates.set; clientReconInfo.verbose = Verbose.value; clientReconInfo.filesPerDir = FilesPerDir.value; clientReconInfo.padSize = PadSize.value; diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 857e4bba..4f1d7c52 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -46,7 +46,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "18.05" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "18.10" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth diff --git a/Src/Reconstruction.example.cpp b/Src/Reconstruction.example.cpp index 720ea777..4e2ef035 100644 --- a/Src/Reconstruction.example.cpp +++ b/Src/Reconstruction.example.cpp @@ -102,6 +102,7 @@ struct SphereSampleStream : public Reconstructor::InputSampleStream< Real , Dim } else return false; } + bool base_read( unsigned int , Point< Real , Dim > &p , Point< Real , Dim > &n ){ return base_read( p , n ); } static Point< Real , Dim > RandomSpherePoint( std::default_random_engine &generator , std::uniform_real_distribution< Real > &distribution ) { @@ -118,7 +119,7 @@ struct SphereSampleStream : public Reconstructor::InputSampleStream< Real , Dim // A stream for generating random samples with color on the sphere template< typename Real , unsigned int Dim > -struct SphereSampleWithColorStream : public Reconstructor::InputSampleWithDataStream< Real , Dim , RGBColor< Real > > +struct SphereSampleWithColorStream : public Reconstructor::InputSampleStream< Real , Dim , RGBColor< Real > > { // from https://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution std::random_device randomDevice; @@ -128,12 +129,12 @@ struct SphereSampleWithColorStream : public Reconstructor::InputSampleWithDataSt // Constructs a stream that contains the specified number of samples SphereSampleWithColorStream( unsigned int sz ) : _size(sz) , _current(0) , generator(0) , distribution((Real)-1.0,(Real)1.0) , - Reconstructor::InputSampleWithDataStream< Real , Dim , RGBColor< Real > >( RGBColor< Real >() ) {} + Reconstructor::InputSampleStream< Real , Dim , RGBColor< Real > >( RGBColor< Real >() ) {} - // Overrides the pure abstract method from InputSampleWithDataStream< Real , Dim , RGBColor< Real > > + // Overrides the pure abstract method from InputSampleStream< Real , Dim , RGBColor< Real > > void reset( void ){ generator.seed(0) ; _current = 0; } - // Overrides the pure abstract method from InputSampleWithDataStream< Real , Dim , RGBColor< Real > > + // Overrides the pure abstract method from InputSampleStream< Real , Dim , RGBColor< Real > > bool base_read( Point< Real , Dim > &p , Point< Real , Dim > &n , RGBColor< Real > &c ) { if( _current<_size ) @@ -148,6 +149,7 @@ struct SphereSampleWithColorStream : public Reconstructor::InputSampleWithDataSt } else return false; } + bool base_read( unsigned int , Point< Real , Dim > &p , Point< Real , Dim > &n , RGBColor< Real > &c ){ return base_read( p , n ,c ); } static Point< Real , Dim > RandomSpherePoint( std::default_random_engine &generator , std::uniform_real_distribution< Real > &distribution ) { @@ -188,14 +190,15 @@ struct VertexStream : public Reconstructor::OutputVertexStream< Real , Dim > VertexStream( std::vector< Real > &vCoordinates ) : _vCoordinates( vCoordinates ) {} // Override the pure abstract method from Reconstructor::OutputVertexStream< Real , Dim > - void base_write( Point< Real , Dim > p , Point< Real , Dim > , Real ){ for( unsigned int d=0 ; d p , Point< Real , Dim > , Real ){ for( unsigned int d=0 ; d p , Point< Real , Dim > g , Real r ){ return base_write( p , g , r ); } protected: std::vector< Real > &_vCoordinates; }; // A stream into which we can write the output vertices and colors of the extracted mesh template< typename Real , unsigned int Dim > -struct VertexWithColorStream : public Reconstructor::OutputVertexWithDataStream< Real , Dim , RGBColor< Real > > +struct VertexWithColorStream : public Reconstructor::OutputVertexStream< Real , Dim , RGBColor< Real > > { // Construct a stream that adds vertices into the coordinates VertexWithColorStream( std::vector< Real > &vCoordinates , std::vector< Real > &rgbCoordinates ) : @@ -209,6 +212,7 @@ struct VertexWithColorStream : public Reconstructor::OutputVertexWithDataStream< _rgbCoordinates.push_back( c.g ); _rgbCoordinates.push_back( c.b ); } + void base_write( unsigned int , Point< Real , Dim > p , Point< Real , Dim > g , Real r , RGBColor< Real > c ){ return base_write( p , g , r , c ); } protected: std::vector< Real > &_vCoordinates; std::vector< Real > &_rgbCoordinates; diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h index be570de1..89b2941c 100644 --- a/Src/Reconstructors.h +++ b/Src/Reconstructors.h @@ -55,12 +55,13 @@ namespace PoissonRecon bool outputGradients; bool forceManifold; bool polygonMesh; + bool gridCoordinates; bool verbose; - LevelSetExtractionParameters( void ) : linearFit(false) , outputGradients(false) , forceManifold(true) , polygonMesh(false) , verbose(false) {} + LevelSetExtractionParameters( void ) : linearFit(false) , outputGradients(false) , forceManifold(true) , polygonMesh(false) , gridCoordinates(false) , verbose(false) {} }; // "Private" function for extracting meshes - template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ImplicitType , unsigned int ... FEMSigs > + template< bool HasAuxData , bool IndexedVertexStream , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ImplicitType , unsigned int ... FEMSigs > void _ExtractLevelSet( UIntPack< FEMSigs ... > , const ImplicitType &implicit , OutputVertexStream &vertexStream , OutputFaceStream< Dim-1 > &faceStream , typename Implicit< Real , Dim , FEMSig >::LevelSetExtractionParameters params ); // Specialized solution information without auxiliary data @@ -98,7 +99,12 @@ namespace PoissonRecon void extractLevelSet( OutputVertexStream< Real , Dim > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const { typedef unsigned char AuxData; - _ExtractLevelSet< false , Real , Dim , FEMSig , AuxData , OutputVertexStream< Real , Dim > , Implicit< Real , Dim , FEMSig > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); + _ExtractLevelSet< false , false , Real , Dim , FEMSig , AuxData , OutputVertexStream< Real , Dim > , Implicit< Real , Dim , FEMSig > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); + } + void extractLevelSet( OutputIndexedVertexStream< Real , Dim > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const + { + typedef unsigned char AuxData; + _ExtractLevelSet< false , true , Real , Dim , FEMSig , AuxData , OutputIndexedVertexStream< Real , Dim > , Implicit< Real , Dim , FEMSig > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); } }; @@ -135,9 +141,13 @@ namespace PoissonRecon } // A method for writing the extracted mesh to the streams - void extractLevelSet( OutputVertexWithDataStream< Real , Dim , AuxData > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const + void extractLevelSet( OutputVertexStream< Real , Dim , AuxData > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const + { + _ExtractLevelSet< true , false , Real , Dim , FEMSig , AuxData , OutputVertexStream< Real , Dim , AuxData > , Implicit< Real , Dim , FEMSig , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); + } + void extractLevelSet( OutputIndexedVertexStream< Real , Dim , AuxData > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const { - _ExtractLevelSet< true , Real , Dim , FEMSig , AuxData , OutputVertexWithDataStream< Real , Dim , AuxData > , Implicit< Real , Dim , FEMSig , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); + _ExtractLevelSet< true , true , Real , Dim , FEMSig , AuxData , OutputIndexedVertexStream< Real , Dim , AuxData > , Implicit< Real , Dim , FEMSig , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); } }; @@ -284,10 +294,10 @@ namespace PoissonRecon template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > struct Implicit< Real , Dim , FEMSig , AuxData > : public Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > { - Implicit( InputSampleWithDataStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL , ValueInterpolationStream< Real , Dim > *valueInterpolationStream=NULL ) + Implicit( InputSampleStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL , ValueInterpolationStream< Real , Dim > *valueInterpolationStream=NULL ) : Reconstructor::Implicit< Real , Dim , FEMSig , AuxData >( pointStream.zero() ) { - _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleWithDataStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params , envelopeMesh , valueInterpolationStream ); + _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params , envelopeMesh , valueInterpolationStream ); } }; }; @@ -447,49 +457,57 @@ namespace PoissonRecon template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > struct Implicit< Real , Dim , FEMSig , AuxData > : public Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > { - Implicit( InputSampleWithDataStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params ) + Implicit( InputSampleStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params ) : Reconstructor::Implicit< Real , Dim , FEMSig , AuxData >( pointStream.zero() ) { - _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleWithDataStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params ); + _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params ); } }; }; - template< class Real , unsigned int Dim , bool ExtendedAxes > - PointExtent::Extent< Real , Dim , ExtendedAxes > GetExtent( InputDataStream< Point< Real , Dim > > &stream ) + template< class Real , unsigned int Dim , bool ExtendedAxes , typename SampleStream > + PointExtent::Extent< Real , Dim , ExtendedAxes > GetExtent( SampleStream &stream ) { - Point< Real , Dim > p; + using Sample = Point< Real , Dim >; + static_assert( std::is_base_of< InputDataStream< Sample > , SampleStream >::value , "[ERROR] Unexpected sample stream type" ); + Sample s; PointExtent::Extent< Real , Dim , ExtendedAxes > e; - while( stream.read( p ) ) e.add( p ); + while( stream.read( s ) ) e.add(s); stream.reset(); return e; } - template< class Real , unsigned int Dim , bool ExtendedAxes , typename AuxData > - PointExtent::Extent< Real , Dim , ExtendedAxes > GetExtent( InputDataStream< VectorTypeUnion< Real , Point< Real , Dim > , AuxData > > &stream , AuxData d ) + template< class Real , unsigned int Dim , bool ExtendedAxes , typename AuxData , typename SampleStream > + PointExtent::Extent< Real , Dim , ExtendedAxes > GetExtent( SampleStream &stream , AuxData d ) { - VectorTypeUnion< Real , Point< Real , Dim > , AuxData > p( Point< Real , Dim >() , d ); + using Sample = VectorTypeUnion< Real , Point< Real , Dim > , AuxData >; + static_assert( std::is_base_of< InputDataStream< Sample > , SampleStream >::value , "[ERROR] Unexpected sample stream type" ); + Sample s( Point< Real , Dim >() , d ); PointExtent::Extent< Real , Dim , ExtendedAxes > e; - while( stream.read( p ) ) e.add( p.template get<0>() ); + while( stream.read( s ) ) e.add( s.template get<0>() ); stream.reset(); return e; } - template< class Real , unsigned int Dim , bool ExtendedAxes > - XForm< Real , Dim+1 > GetPointXForm( InputDataStream< Point< Real , Dim > > &stream , Real scaleFactor , unsigned int dir ) + template< class Real , unsigned int Dim , bool ExtendedAxes , typename SampleStream > + XForm< Real , Dim+1 > GetPointXForm( SampleStream &stream , Real scaleFactor , unsigned int dir ) { - PointExtent::Extent< Real , Dim , ExtendedAxes > e = GetExtent< Real , Dim , ExtendedAxes >( stream ); + using Sample = Point< Real , Dim >; + static_assert( std::is_base_of< InputDataStream< Sample > , SampleStream >::value , "[ERROR] Unexpected sample stream type" ); + PointExtent::Extent< Real , Dim , ExtendedAxes > e = GetExtent< Real , Dim , ExtendedAxes , SampleStream >( stream ); return PointExtent::GetBoundingBoxXForm( e , scaleFactor , dir ); } - template< class Real , unsigned int Dim , bool ExtendedAxes , typename AuxData > - XForm< Real , Dim+1 > GetPointXForm( InputDataStream< VectorTypeUnion< Real , Point< Real , Dim > , AuxData > > &stream , AuxData d , Real scaleFactor , unsigned int dir ) + template< class Real , unsigned int Dim , bool ExtendedAxes , typename AuxData , typename SampleStream > + XForm< Real , Dim+1 > GetPointXForm( SampleStream &stream , AuxData d , Real scaleFactor , unsigned int dir ) { - PointExtent::Extent< Real , Dim , ExtendedAxes > e = GetExtent< Real , Dim , ExtendedAxes , AuxData >( stream , d ); + using Sample = VectorTypeUnion< Real , Point< Real , Dim > , AuxData >; + static_assert( std::is_base_of< InputDataStream< Sample > , SampleStream >::value , "[ERROR] Unexpected sample stream type" ); + PointExtent::Extent< Real , Dim , ExtendedAxes > e = GetExtent< Real , Dim , ExtendedAxes , AuxData , SampleStream >( stream , d ); return PointExtent::GetBoundingBoxXForm( e , scaleFactor , dir ); } - template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ImplicitType , unsigned int ... FEMSigs > + template< bool HasAuxData , bool IndexedVertexStream , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ImplicitType , unsigned int ... FEMSigs > void _ExtractLevelSet( UIntPack< FEMSigs ... > , const ImplicitType &implicit , OutputVertexStream &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) { typedef UIntPack< FEMSigs ... > Sigs; @@ -497,6 +515,15 @@ namespace PoissonRecon static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; typedef typename ImplicitType::DensityEstimator DensityEstimator; + XForm< Real , Dim+1 > unitCubeToModel; + if( params.gridCoordinates ) + { + unitCubeToModel = XForm< Real , Dim+1 >::Identity(); + unsigned int res = 1<::Stats stats; - TransformedOutputVertexWithDataStream< Real , Dim , AuxData > _vertexStream( implicit.unitCubeToModel , vertexStream ); + std::conditional_t< IndexedVertexStream , TransformedOutputIndexedVertexStream< Real , Dim , AuxData > , TransformedOutputVertexStream< Real , Dim , AuxData > > _vertexStream( unitCubeToModel , vertexStream ); stats = LevelSetExtractor< Real , Dim , AuxData >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , UIntPack< DataSig >() , implicit.tree , implicit.density , implicit.auxData , implicit.solution , implicit.isoValue , _vertexStream , faceStream , implicit.zeroAuxData , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); statsString = stats.toString(); } else { typename LevelSetExtractor< Real , Dim >::Stats stats; - TransformedOutputVertexStream< Real , Dim > _vertexStream( implicit.unitCubeToModel , vertexStream ); + std::conditional_t< IndexedVertexStream , TransformedOutputIndexedVertexStream< Real , Dim > , TransformedOutputVertexStream< Real , Dim > > _vertexStream( unitCubeToModel , vertexStream ); stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , implicit.tree , implicit.density , implicit.solution , implicit.isoValue , _vertexStream , faceStream , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); statsString = stats.toString(); } @@ -533,14 +560,14 @@ namespace PoissonRecon if constexpr( HasAuxData ) { typename LevelSetExtractor< Real , Dim , AuxData >::Stats stats; - TransformedOutputVertexWithDataStream< Real , Dim , AuxData > _vertexStream( implicit.unitCubeToModel , vertexStream ); + std::conditional_t< IndexedVertexStream , TransformedOutputIndexedVertexStream< Real , Dim , AuxData > , TransformedOutputVertexStream< Real , Dim , AuxData > > _vertexStream( unitCubeToModel , vertexStream ); stats = LevelSetExtractor< Real , Dim , AuxData >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , UIntPack< DataSig >() , implicit.tree , implicit.density , implicit.auxData , implicit.solution , implicit.isoValue , _vertexStream , faceStream , implicit.zeroAuxData , !params.linearFit , params.outputGradients , false ); statsString = stats.toString(); } else { typename LevelSetExtractor< Real , Dim >::Stats stats; - TransformedOutputVertexStream< Real , Dim > _vertexStream( implicit.unitCubeToModel , vertexStream ); + std::conditional_t< IndexedVertexStream , TransformedOutputIndexedVertexStream< Real , Dim > , TransformedOutputVertexStream< Real , Dim > > _vertexStream( unitCubeToModel , vertexStream ); stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , implicit.tree , implicit.density , implicit.solution , implicit.isoValue , _vertexStream , faceStream , !params.linearFit , params.outputGradients , false ); statsString = stats.toString(); } @@ -671,11 +698,7 @@ namespace PoissonRecon if constexpr( HasAuxData ) { -#ifdef DE_VIRTUALIZE_OUTPUT - TransformedInputSampleWithDataStream< Real , Dim , AuxData , InputSampleStreamType > _pointStream( modelToUnitCube , pointStream ); -#else // !DE_VIRTUALIZE_OUTPUT - TransformedInputSampleWithDataStream< Real , Dim , AuxData > _pointStream( modelToUnitCube , pointStream ); -#endif // DE_VIRTUALIZE_OUTPUT + TransformedInputSampleStream< Real , Dim , InputSampleStreamType , AuxData > _pointStream( modelToUnitCube , pointStream ); auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , NormalAndAuxData &d ) { Real l = (Real)Length( d.template get<0>() ); @@ -696,11 +719,7 @@ namespace PoissonRecon } else { -#ifdef DE_VIRTUALIZE_OUTPUT TransformedInputSampleStream< Real , Dim , InputSampleStreamType > _pointStream( modelToUnitCube , pointStream ); -#else // !DE_VIRTUALIZE_OUTPUT - TransformedInputSampleStream< Real , Dim > _pointStream( modelToUnitCube , pointStream ); -#endif // DE_VIRTUALIZE_OUTPUT auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , NormalAndAuxData &d ) { Real l = (Real)Length( d ); @@ -734,7 +753,7 @@ namespace PoissonRecon valueInterpolationSamples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); valueInterpolationSampleData = new std::vector< Real >(); // Wrap the point stream in a transforming stream - TransformedValueInterpolationStream< Real , Dim > _valueInterpolationStream( modelToUnitCube , *valueInterpolationStream ); + TransformedValueInterpolationStream< Real , Dim , ValueInterpolationStream< Real , Dim > > _valueInterpolationStream( modelToUnitCube , *valueInterpolationStream ); // Assign each sample a weight of 1. auto ProcessData = []( const Point< Real , Dim > &p , Real &d ){ return (Real)1.; }; @@ -1122,11 +1141,7 @@ namespace PoissonRecon if constexpr( HasAuxData ) { -#ifdef DE_VIRTUALIZE_OUTPUT - TransformedInputSampleWithDataStream< Real , Dim , AuxData , InputSampleStreamType > _pointStream( modelToUnitCube , pointStream ); -#else // !DE_VIRTUALIZE_OUTPUT - TransformedInputSampleWithDataStream< Real , Dim , AuxData > _pointStream( modelToUnitCube , pointStream ); -#endif // DE_VIRTUALIZE_OUTPUT + TransformedInputSampleStream< Real , Dim , InputSampleStreamType , AuxData > _pointStream( modelToUnitCube , pointStream ); auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , NormalAndAuxData &d ) { Real l = (Real)Length( d.template get<0>() ); @@ -1147,11 +1162,7 @@ namespace PoissonRecon } else { -#ifdef DE_VIRTUALIZE_OUTPUT TransformedInputSampleStream< Real , Dim , InputSampleStreamType > _pointStream( modelToUnitCube , pointStream ); -#else // !DE_VIRTUALIZE_OUTPUT - TransformedInputSampleStream< Real , Dim > _pointStream( modelToUnitCube , pointStream ); -#endif // DE_VIRTUALIZE_OUTPUT auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , NormalAndAuxData &d ) { Real l = (Real)Length( d ); diff --git a/Src/Reconstructors.streams.h b/Src/Reconstructors.streams.h index 5fa25c1f..7a7e7f72 100644 --- a/Src/Reconstructors.streams.h +++ b/Src/Reconstructors.streams.h @@ -43,26 +43,34 @@ namespace PoissonRecon template< typename Real , unsigned int Dim > using Gradient = Point< Real , Dim >; // Basic types - template< typename Real , unsigned int Dim > - using BaseSample = VectorTypeUnion< Real , Position< Real , Dim > , Normal< Real , Dim > >; + template< typename Real , unsigned int Dim , typename ... Other > + using BaseSample = std::conditional_t< sizeof...(Other)==0 , VectorTypeUnion< Real , Position< Real , Dim > , Normal< Real , Dim > > , VectorTypeUnion< Real , Position< Real , Dim > , VectorTypeUnion< Real , Normal< Real , Dim > , Other... > > >; - template< typename Real , unsigned int Dim , typename Data > - using BaseSampleWithData = VectorTypeUnion< Real , Position< Real , Dim > , VectorTypeUnion< Real , Normal< Real , Dim > , Data > >; + // The types output by the extractor + template< typename Real , unsigned int Dim , typename ... Other > + using LevelSetVertex = typename LevelSetExtractor< Real , Dim , Other... >::Vertex; - template< typename Real , unsigned int Dim > - using BaseVertex = VectorTypeUnion< Real , Position< Real , Dim > , Normal< Real , Dim > , Real >; + template< typename Real , unsigned int Dim , typename ... Other > + using LevelSetIndexedVertex = typename LevelSetExtractor< Real , Dim , Other... >::IndexedVertex; - template< typename Real , unsigned int Dim , typename Data > - using BaseVertexWithData = VectorTypeUnion< Real , Position< Real , Dim > , Gradient< Real , Dim > , Real , Data >; + template< typename Real , unsigned int Dim , typename ... Other > using BaseInputSampleStream = InputDataStream< BaseSample< Real , Dim , Other... > >; + template< typename Real , unsigned int Dim , typename ... Other > using LevelSetVertexStream = OutputDataStream< LevelSetVertex< Real , Dim , Other... > >; + template< typename Real , unsigned int Dim , typename ... Other > using LevelSetIndexedVertexStream = OutputDataStream< LevelSetIndexedVertex< Real , Dim , Other... > >; - template< unsigned int FaceDim , typename T=node_index_type > using Face = std::conditional_t< FaceDim==2 , std::vector< T > , std::conditional_t< FaceDim==1 , std::pair< T , T > , void * > >; + // Stream types + template< typename Real , unsigned int Dim , typename ... Other > struct InputSampleStream; - // Basic streams - template< typename Real , unsigned int Dim > using BaseInputSampleStream = InputDataStream< BaseSample < Real , Dim > >; - template< typename Real , unsigned int Dim , typename Data > using BaseInputSampleWithDataStream = InputDataStream< BaseSampleWithData< Real , Dim , Data > >; + template< typename Real , unsigned int Dim , typename InputStream , typename ... Other > struct TransformedInputSampleStream; + template< typename Real , unsigned int Dim , typename ... Other > struct OutputVertexStream; + template< typename Real , unsigned int Dim , typename ... Other > struct OutputIndexedVertexStream; + template< typename Real , unsigned int Dim , typename ... Other > struct TransformedOutputVertexStream; + template< typename Real , unsigned int Dim , typename ... Other > struct TransformedOutputIndexedVertexStream; + template< typename Vertex , typename Real , unsigned int Dim , typename ... Other > struct OutputVertexStreamWrapper; + template< typename Vertex , typename Real , unsigned int Dim , typename ... Other > struct OutputIndexedVertexStreamWrapper; + template< typename Real , unsigned int Dim , bool HasGradients , bool HasDensity , typename ... Other > struct OutputVertexInfo; + template< typename Real , unsigned int Dim , bool HasGradients , bool HasDensity , typename ... Other > struct OutputIndexedVertexInfo; - template< typename Real , unsigned int Dim > using BaseOutputVertexStream = OutputDataStream< BaseVertex < Real , Dim > >; - template< typename Real , unsigned int Dim , typename Data > using BaseOutputVertexWithDataStream = OutputDataStream< BaseVertexWithData< Real , Dim , Data > >; + template< unsigned int FaceDim , typename T=node_index_type > using Face = std::conditional_t< FaceDim==2 , std::vector< T > , std::conditional_t< FaceDim==1 , std::pair< T , T > , void * > >; template< unsigned int FaceDim > using InputFaceStream = InputDataStream< Face< FaceDim > >; template< unsigned int FaceDim > using OutputFaceStream = OutputDataStream< Face< FaceDim > >; @@ -78,19 +86,23 @@ namespace PoissonRecon // Functionality to extract the next position/normal pair. // The method returns true if there was another point in the stream to read, and false otherwise - virtual bool base_read( Position< Real , Dim > &p , Real &v ) = 0; + virtual bool base_read( Position< Real , Dim > &p , Real &v ) = 0; + virtual bool base_read( unsigned int thread , Position< Real , Dim > &p , Real &v ) = 0; // Implementation of InputDataStream::read - bool base_read( VectorTypeUnion< Real , Point< Real , Dim > , Real > &s ){ return base_read( s.template get<0>() , s.template get<1>() ); } + bool base_read( VectorTypeUnion< Real , Point< Real , Dim > , Real > &s ){ return base_read( s.template get<0>() , s.template get<1>() ); } + bool base_read( unsigned int thread , VectorTypeUnion< Real , Point< Real , Dim > , Real > &s ){ return base_read( thread , s.template get<0>() , s.template get<1>() ); } }; ///////////////////////////////////////////////// // Transformed Value Interpolation Data Stream // ///////////////////////////////////////////////// - template< typename Real , unsigned int Dim > + template< typename Real , unsigned int Dim , typename InputStream > struct TransformedValueInterpolationStream : public ValueInterpolationStream< Real , Dim > { + static_assert( std::is_base_of< ValueInterpolationStream< Real , Dim > , InputStream >::value , "[ERROR] Unexpected stream type" ); + // A constructor initialized with the transformation to be applied to the samples, and a sample stream - TransformedValueInterpolationStream( XForm< Real , Dim+1 > xForm , ValueInterpolationStream< Real , Dim > &stream ) : _stream(stream) , _xForm(xForm) {} + TransformedValueInterpolationStream( XForm< Real , Dim+1 > xForm , InputStream &stream ) : _stream(stream) , _xForm(xForm) {} // Functionality to reset the stream to the start void reset( void ){ _stream.reset(); } @@ -104,10 +116,17 @@ namespace PoissonRecon if( ret ) p = _xForm * s.template get<0>() , v = s.template get<1>(); return ret; } + bool base_read( unsigned int thread , Position< Real , Dim > &p , Real &v ) + { + VectorTypeUnion< Real , Point< Real , Dim > , Real > s; + bool ret = _stream.read( thread , s ); + if( ret ) p = _xForm * s.template get<0>() , v = s.template get<1>(); + return ret; + } protected: // A reference to the underlying stream - ValueInterpolationStream< Real , Dim > &_stream; + InputStream &_stream; // The affine transformation to be applied to the positions XForm< Real , Dim+1 > _xForm; @@ -117,26 +136,28 @@ namespace PoissonRecon // Oriented Point Stream // /////////////////////////// template< typename Real , unsigned int Dim > - struct InputSampleStream : public BaseInputSampleStream< Real , Dim > + struct InputSampleStream< Real , Dim > : public BaseInputSampleStream< Real , Dim > { // Functionality to reset the stream to the start virtual void reset( void ) = 0; // Functionality to extract the next position/normal pair. // The method returns true if there was another point in the stream to read, and false otherwise - virtual bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n ) = 0; + virtual bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n ) = 0; + virtual bool base_read( unsigned int thread , Position< Real , Dim > &p , Normal< Real , Dim > &n ) = 0; // Implementation of InputDataStream::read - bool base_read( BaseSample< Real , Dim > &s ){ return base_read( s.template get<0>() , s.template get<1>() ); } + bool base_read( BaseSample< Real , Dim > &s ){ return base_read( s.template get<0>() , s.template get<1>() ); } + bool base_read( unsigned int thread , BaseSample< Real , Dim > &s ){ return base_read( thread , s.template get<0>() , s.template get<1>() ); } }; /////////////////////////////////// // Oriented Point w/ Data Stream // /////////////////////////////////// template< typename Real , unsigned int Dim , typename Data > - struct InputSampleWithDataStream : public BaseInputSampleWithDataStream< Real , Dim , Data > + struct InputSampleStream< Real , Dim , Data > : public BaseInputSampleStream< Real , Dim , Data > { // A constructor initialized with an instance of "zero" data - InputSampleWithDataStream( Data zero ) : _zero(zero) {} + InputSampleStream( Data zero ) : _zero(zero) {} // Functionality to reset the stream to the start virtual void reset( void ) = 0; @@ -146,8 +167,10 @@ namespace PoissonRecon // Functionality to extract the next position/normal pair. // The method returns true if there was another point in the stream to read, and false otherwise - virtual bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n , Data &d ) = 0; - bool base_read( BaseSampleWithData< Real , Dim , Data > &s ){ return base_read( s.template get<0>() , s.template get<1>().template get<0>() , s.template get<1>().template get<1>() ); } + virtual bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n , Data &d ) = 0; + virtual bool base_read( unsigned int thread , Position< Real , Dim > &p , Normal< Real , Dim > &n , Data &d ) = 0; + bool base_read( BaseSample< Real , Dim , Data > &s ){ return base_read( s.template get<0>() , s.template get<1>().template get<0>() , s.template get<1>().template get<1>() ); } + bool base_read( unsigned int thread , BaseSample< Real , Dim , Data > &s ){ return base_read( thread , s.template get<0>() , s.template get<1>().template get<0>() , s.template get<1>().template get<1>() ); } // An instance of "zero" data Data _zero; @@ -157,22 +180,12 @@ namespace PoissonRecon /////////////////////////////////////// // Transformed Oriented Point Stream // /////////////////////////////////////// -#ifdef DE_VIRTUALIZE_INPUT template< typename Real , unsigned int Dim , typename InputStream > -#else // !DE_VIRTUALIZE_INPUT - template< typename Real , unsigned int Dim > -#endif // DE_VIRTUALIZE_INPUT - struct TransformedInputSampleStream : public InputSampleStream< Real , Dim > + struct TransformedInputSampleStream< Real , Dim , InputStream > : public InputSampleStream< Real , Dim > { -#ifdef DE_VIRTUALIZE_INPUT static_assert( std::is_base_of< InputSampleStream< Real , Dim > , InputStream >::value , "[ERROR] Unexpected stream type" ); -#endif // DE_VIRTUALIZE_INPUT // A constructor initialized with the transformation to be applied to the samples, and a sample stream -#ifdef DE_VIRTUALIZE_INPUT TransformedInputSampleStream( XForm< Real , Dim+1 > xForm , InputStream &stream ) : _stream(stream) , _positionXForm(xForm) -#else // !DE_VIRTUALIZE_INPUT - TransformedInputSampleStream( XForm< Real , Dim+1 > xForm , InputSampleStream< Real , Dim > &stream ) : _stream(stream) , _positionXForm(xForm) -#endif // DE_VIRTUALIZE_INPUT { _normalXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( fabs( xForm.determinant() ) , 1./Dim ); } @@ -189,14 +202,17 @@ namespace PoissonRecon if( ret ) p = _positionXForm * s.template get<0>() , n = _normalXForm * s.template get<1>(); return ret; } + bool base_read( unsigned int thread , Position< Real , Dim > &p , Normal< Real , Dim > &n ) + { + BaseSample< Real , Dim > s; + bool ret = _stream.read( thread , s ); + if( ret ) p = _positionXForm * s.template get<0>() , n = _normalXForm * s.template get<1>(); + return ret; + } protected: // A reference to the underlying stream -#ifdef DE_VIRTUALIZE_INPUT InputStream &_stream; -#else // !DE_VIRTUALIZE_INPUT - InputSampleStream< Real , Dim > &_stream; -#endif // DE_VIRTUALIZE_INPUT // The affine transformation to be applied to the positions XForm< Real , Dim+1 > _positionXForm; @@ -208,22 +224,13 @@ namespace PoissonRecon /////////////////////////////////////////////// // Transformed Oriented Point w/ Data Stream // /////////////////////////////////////////////// -#ifdef DE_VIRTUALIZE_INPUT - template< typename Real , unsigned int Dim , typename Data , typename InputStream > -#else // !DE_VIRTUALIZE_INPUT - template< typename Real , unsigned int Dim , typename Data > -#endif // DE_VIRTUALIZE_INPUT - struct TransformedInputSampleWithDataStream : public InputSampleWithDataStream< Real , Dim , Data > + template< typename Real , unsigned int Dim , typename InputStream , typename Data > + struct TransformedInputSampleStream< Real , Dim , InputStream , Data > : public InputSampleStream< Real , Dim , Data > { -#ifdef DE_VIRTUALIZE_INPUT - static_assert( std::is_base_of< InputSampleWithDataStream< Real , Dim , Data > , InputStream >::value , "[ERROR] Unexpected stream type" ); -#endif // DE_VIRTUALIZE_INPUT + static_assert( std::is_base_of< InputSampleStream< Real , Dim , Data > , InputStream >::value , "[ERROR] Unexpected stream type" ); + // A constructor initialized with an instance of "zero" data -#ifdef DE_VIRTUALIZE_INPUT - TransformedInputSampleWithDataStream( XForm< Real , Dim+1 > xForm , InputStream &stream ) : InputSampleWithDataStream< Real , Dim , Data >( stream.zero() ) , _stream(stream) , _positionXForm(xForm) -#else // !DE_VIRTUALIZE_INPUT - TransformedInputSampleWithDataStream( XForm< Real , Dim+1 > xForm , InputSampleWithDataStream< Real , Dim , Data > &stream ) : InputSampleWithDataStream< Real , Dim , Data >( stream.zero() ) , _stream(stream) , _positionXForm(xForm) -#endif // DE_VIRTUALIZE_INPUT + TransformedInputSampleStream( XForm< Real , Dim+1 > xForm , InputStream &stream ) : InputSampleStream< Real , Dim , Data >( stream.zero() ) , _stream(stream) , _positionXForm(xForm) { _normalXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); } @@ -235,19 +242,22 @@ namespace PoissonRecon // The method returns true if there was another point in the stream to read, and false otherwise bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n , Data &d ) { - BaseSampleWithData< Real , Dim , Data > s( Position< Real , Dim >() , VectorTypeUnion< Real , Normal< Real , Dim > , Data >( Normal< Real , Dim >() , _stream.zero() ) ); + BaseSample< Real , Dim , Data > s( Position< Real , Dim >() , VectorTypeUnion< Real , Normal< Real , Dim > , Data >( Normal< Real , Dim >() , _stream.zero() ) ); bool ret = _stream.read( s ); if( ret ) p = _positionXForm * s.template get<0>() , n = _normalXForm * s.template get<1>().template get<0>() , d = s.template get<1>().template get<1>(); return ret; } + bool base_read( unsigned int thread , Position< Real , Dim > &p , Normal< Real , Dim > &n , Data &d ) + { + BaseSample< Real , Dim , Data > s( Position< Real , Dim >() , VectorTypeUnion< Real , Normal< Real , Dim > , Data >( Normal< Real , Dim >() , _stream.zero() ) ); + bool ret = _stream.read( thread , s ); + if( ret ) p = _positionXForm * s.template get<0>() , n = _normalXForm * s.template get<1>().template get<0>() , d = s.template get<1>().template get<1>(); + return ret; + } protected: // A reference to the underlying stream -#ifdef DE_VIRTUALIZE_INPUT InputStream &_stream; -#else // !DE_VIRTUALIZE_INPUT - InputSampleWithDataStream< Real , Dim , Data > &_stream; -#endif // DE_VIRTUALIZE_INPUT // The affine transformation to be applied to the positions XForm< Real , Dim+1 > _positionXForm; @@ -257,39 +267,82 @@ namespace PoissonRecon }; - /////////////////// - // Vertex Stream // - /////////////////// + ////////////////////////////////////////////////////////////////////////////// + // Vertex Stream: // + // Looks like a LevelSetVertexStream, but supports component-wise insertion // + ////////////////////////////////////////////////////////////////////////////// + template< typename Real , unsigned int Dim > + struct OutputVertexStream< Real , Dim > : public LevelSetVertexStream< Real , Dim > + { + // Need to provide access to base write for counter support + using LevelSetVertexStream< Real , Dim >::write; + + // Functionality to insert the next vertex + virtual void base_write( Position< Real , Dim > p , Gradient< Real , Dim > g , Real w ) = 0; + virtual void base_write( unsigned int thread , Position< Real , Dim > p , Gradient< Real , Dim > g , Real w ) = 0; + void base_write( const LevelSetVertex< Real , Dim > &v ){ base_write( v.template get<0>() , v.template get<1>() , v.template get<2>() ); } + void base_write( unsigned int thread , const LevelSetVertex< Real , Dim > &v ){ base_write( thread , v.template get<0>() , v.template get<1>() , v.template get<2>() ); } + }; + + /////////////////////////// + // Indexed Vertex Stream // + /////////////////////////// template< typename Real , unsigned int Dim > - struct OutputVertexStream : public BaseOutputVertexStream< Real , Dim > + struct OutputIndexedVertexStream< Real , Dim > : public LevelSetIndexedVertexStream< Real , Dim > { // Need to provide access to base write for counter support - using BaseOutputVertexStream< Real , Dim >::write; + using LevelSetIndexedVertexStream< Real , Dim >::write; // Functionality to insert the next vertex - virtual void base_write( Position< Real , Dim > p , Gradient< Real , Dim > g , Real w ) = 0; - void base_write( const BaseVertex< Real , Dim > &v ){ base_write( v.template get<0>() , v.template get<1>() , v.template get<2>() ); } + virtual void base_write( node_index_type idx , Position< Real , Dim > p , Gradient< Real , Dim > g , Real w ) = 0; + virtual void base_write( unsigned int thread , node_index_type idx , Position< Real , Dim > p , Gradient< Real , Dim > g , Real w ) = 0; + void base_write( const LevelSetIndexedVertex< Real , Dim > &v ) + { + base_write( v.first , v.second.template get<0>() , v.second.template get<1>() , v.second.template get<2>() ); + } + void base_write( unsigned int thread , const LevelSetIndexedVertex< Real , Dim > &v ) + { + base_write( thread , v.first , v.second.template get<0>() , v.second.template get<1>() , v.second.template get<2>() ); + } }; /////////////////////////// // Vertex w/ Data Stream // /////////////////////////// template< typename Real , unsigned int Dim , typename Data > - struct OutputVertexWithDataStream : public BaseOutputVertexWithDataStream< Real , Dim , Data > + struct OutputVertexStream< Real , Dim , Data > : public LevelSetVertexStream< Real , Dim , Data > { // Need to provide access to base write for counter support - using BaseOutputVertexWithDataStream< Real , Dim , Data >::write; + using LevelSetVertexStream< Real , Dim , Data >::write; // Functionality to insert the next vertex - virtual void base_write( Position< Real , Dim > p , Gradient< Real , Dim > g , Real w , Data d ) = 0; - void base_write( const BaseVertexWithData< Real , Dim , Data > &v ){ return base_write( v.template get<0>() , v.template get<1>() , v.template get<2>() , v.template get<3>() ); } + virtual void base_write( Position< Real , Dim > p , Gradient< Real , Dim > g , Real w , Data d ) = 0; + virtual void base_write( unsigned int thread , Position< Real , Dim > p , Gradient< Real , Dim > g , Real w , Data d ) = 0; + void base_write( const LevelSetVertex< Real , Dim , Data > &v ){ return base_write( v.template get<0>() , v.template get<1>() , v.template get<2>() , v.template get<3>() ); } + void base_write( unsigned int thread , const LevelSetVertex< Real , Dim , Data > &v ){ return base_write( thread , v.template get<0>() , v.template get<1>() , v.template get<2>() , v.template get<3>() ); } + }; + + /////////////////////////////////// + // Indexed vertex w/ Data Stream // + /////////////////////////////////// + template< typename Real , unsigned int Dim , typename Data > + struct OutputIndexedVertexStream< Real , Dim , Data > : public LevelSetIndexedVertexStream< Real , Dim , Data > + { + // Need to provide access to base write for counter support + using LevelSetIndexedVertexStream< Real , Dim , Data >::write; + + // Functionality to insert the next vertex + virtual void base_write( node_index_type idx , Position< Real , Dim > p , Gradient< Real , Dim > g , Real w , Data d ) = 0; + virtual void base_write( unsigned int thread , node_index_type idx , Position< Real , Dim > p , Gradient< Real , Dim > g , Real w , Data d ) = 0; + void base_write( const LevelSetIndexedVertex< Real , Dim , Data > &v ){ return base_write( v.first , v.second.template get<0>() , v.second.template get<1>() , v.second.template get<2>() , v.second.template get<3>() ); } + void base_write( unsigned int thread , const LevelSetIndexedVertex< Real , Dim , Data > &v ){ return base_write( thread , v.first , v.second.template get<0>() , v.second.template get<1>() , v.second.template get<2>() , v.second.template get<3>() ); } }; /////////////////////////////// // Transformed Vertex Stream // /////////////////////////////// template< typename Real , unsigned int Dim > - struct TransformedOutputVertexStream : public OutputVertexStream< Real , Dim > + struct TransformedOutputVertexStream< Real , Dim > : public OutputVertexStream< Real , Dim > { // A constructor initialized with the transformation to be applied to the samples, and a sample stream TransformedOutputVertexStream( XForm< Real , Dim+1 > xForm , OutputVertexStream< Real , Dim > &stream ) : _stream(stream) , _positionXForm(xForm) @@ -298,7 +351,8 @@ namespace PoissonRecon } // Need to write the union to ensure that the counter gets set - void base_write( Position< Real , Dim > p , Normal< Real , Dim > g , Real w ){ _stream.write( BaseVertex< Real , Dim >( _positionXForm * p , _gradientXForm * g , w ) ); } + void base_write( Position< Real , Dim > p , Normal< Real , Dim > g , Real w ){ _stream.write( LevelSetVertex< Real , Dim >( _positionXForm * p , _gradientXForm * g , w ) ); } + void base_write( unsigned int thread , Position< Real , Dim > p , Normal< Real , Dim > g , Real w ){ _stream.write( thread , LevelSetVertex< Real , Dim >( _positionXForm * p , _gradientXForm * g , w ) ); } protected: // A reference to the underlying stream @@ -316,19 +370,86 @@ namespace PoissonRecon // Transformed Vertex w/ Data Stream // /////////////////////////////////////// template< typename Real , unsigned int Dim , typename Data > - struct TransformedOutputVertexWithDataStream : public OutputVertexWithDataStream< Real , Dim , Data > + struct TransformedOutputVertexStream< Real , Dim , Data > : public OutputVertexStream< Real , Dim , Data > + { + // A constructor initialized with the transformation to be applied to the samples, and a sample stream + TransformedOutputVertexStream( XForm< Real , Dim+1 > xForm , OutputVertexStream< Real , Dim , Data > &stream ) : _stream(stream) , _positionXForm(xForm) + { + _gradientXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); + } + + void base_write( Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ){ _stream.write( LevelSetVertex< Real , Dim , Data >( _positionXForm * p , _gradientXForm * g , w , d ) ); } + void base_write( unsigned int thread , Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ){ _stream.write( thread , LevelSetVertex< Real , Dim , Data >( _positionXForm * p , _gradientXForm * g , w , d ) ); } + + protected: + // A reference to the underlying stream + OutputVertexStream< Real , Dim , Data > &_stream; + + // The affine transformation to be applied to the positions + XForm< Real , Dim+1 > _positionXForm; + + // The linear transformation to be applied to the normals + XForm< Real , Dim > _gradientXForm; + }; + + /////////////////////////////////////// + // Transformed Indexed Vertex Stream // + /////////////////////////////////////// + template< typename Real , unsigned int Dim > + struct TransformedOutputIndexedVertexStream< Real , Dim > : public OutputIndexedVertexStream< Real , Dim > + { + // A constructor initialized with the transformation to be applied to the samples, and a sample stream + TransformedOutputIndexedVertexStream( XForm< Real , Dim+1 > xForm , OutputIndexedVertexStream< Real , Dim > &stream ) : _stream(stream) , _positionXForm(xForm) + { + _gradientXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); + } + + // Need to write the union to ensure that the counter gets set + void base_write( node_index_type idx , Position< Real , Dim > p , Normal< Real , Dim > g , Real w ) + { + _stream.write( std::pair< node_index_type , LevelSetVertex< Real , Dim > >( idx , LevelSetVertex< Real , Dim > (_positionXForm * p , _gradientXForm * g , w ) ) ); + } + void base_write( unsigned int thread , node_index_type idx , Position< Real , Dim > p , Normal< Real , Dim > g , Real w ) + { + _stream.write( thread , std::pair< node_index_type , LevelSetVertex< Real , Dim > >( idx , LevelSetVertex< Real , Dim > (_positionXForm * p , _gradientXForm * g , w ) ) ); + } + + protected: + // A reference to the underlying stream + OutputIndexedVertexStream< Real , Dim > &_stream; + + // The affine transformation to be applied to the positions + XForm< Real , Dim+1 > _positionXForm; + + // The linear transformation to be applied to the normals + XForm< Real , Dim > _gradientXForm; + }; + + + /////////////////////////////////////////////// + // Transformed Indexed Vertex w/ Data Stream // + /////////////////////////////////////////////// + template< typename Real , unsigned int Dim , typename Data > + struct TransformedOutputIndexedVertexStream< Real , Dim , Data > : public OutputIndexedVertexStream< Real , Dim , Data > { // A constructor initialized with the transformation to be applied to the samples, and a sample stream - TransformedOutputVertexWithDataStream( XForm< Real , Dim+1 > xForm , OutputVertexWithDataStream< Real , Dim , Data > &stream ) : _stream(stream) , _positionXForm(xForm) + TransformedOutputIndexedVertexStream( XForm< Real , Dim+1 > xForm , OutputIndexedVertexStream< Real , Dim , Data > &stream ) : _stream(stream) , _positionXForm(xForm) { _gradientXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); } - void base_write( Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ){ _stream.write( BaseVertexWithData< Real , Dim , Data >( _positionXForm * p , _gradientXForm * g , w , d ) ); } + void base_write( node_index_type idx , Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ) + { + _stream.write( std::pair< node_index_type , LevelSetVertex< Real , Dim , Data > >( idx , LevelSetVertex< Real , Dim , Data >( _positionXForm * p , _gradientXForm * g , w , d ) ) ); + } + void base_write( unsigned int thread , node_index_type idx , Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ) + { + _stream.write( thread , std::pair< node_index_type , LevelSetVertex< Real , Dim , Data > >( idx , LevelSetVertex< Real , Dim , Data >( _positionXForm * p , _gradientXForm * g , w , d ) ) ); + } protected: // A reference to the underlying stream - OutputVertexWithDataStream< Real , Dim , Data > &_stream; + OutputIndexedVertexStream< Real , Dim , Data > &_stream; // The affine transformation to be applied to the positions XForm< Real , Dim+1 > _positionXForm; @@ -340,49 +461,136 @@ namespace PoissonRecon /////////////////////////////////////////// // A wrapper class to write out vertices // /////////////////////////////////////////// - template< typename Real , unsigned int Dim , typename Vertex > - struct OutputVertexStreamWrapper : public OutputVertexStream< Real , Dim > + template< typename Vertex , typename Real , unsigned int Dim > + struct OutputVertexStreamWrapper< Vertex , Real , Dim > : public OutputVertexStream< Real , Dim > { - virtual void set( Vertex &out , const BaseVertex< Real , Dim > &in ) = 0; + virtual Vertex toOutputVertex( const LevelSetVertex< Real , Dim > &in ) = 0; - OutputVertexStreamWrapper( OutputDataStream< Vertex > &stream , Vertex out ) : _stream(stream) , _out(out) {} + OutputVertexStreamWrapper( OutputDataStream< Vertex > &stream ) : _stream(stream){} void base_write( Position< Real , Dim > p , Normal< Real , Dim > g , Real w ) { - _in.template get<0>() = p; - _in.template get<1>() = g; - _in.template get<2>() = w; - set( _out , _in ); - _stream.write( _out ); + LevelSetVertex< Real , Dim > in; + in.template get<0>() = p; + in.template get<1>() = g; + in.template get<2>() = w; + + Vertex out = toOutputVertex( in ); + _stream.write( out ); + } + void base_write( unsigned int thread , Position< Real , Dim > p , Normal< Real , Dim > g , Real w ) + { + LevelSetVertex< Real , Dim > in; + in.template get<0>() = p; + in.template get<1>() = g; + in.template get<2>() = w; + + Vertex out = toOutputVertex( in ); + _stream.write( thread , out ); } protected: OutputDataStream< Vertex > &_stream; - BaseVertex< Real , Dim > _in; - Vertex _out; }; - template< typename Real , unsigned int Dim , typename Data , typename Vertex > - struct OutputVertexWithDataStreamWrapper : public OutputVertexWithDataStream< Real , Dim , Data > + template< typename Vertex , typename Real , unsigned int Dim , typename Data > + struct OutputVertexStreamWrapper< Vertex , Real , Dim , Data > : public OutputVertexStream< Real , Dim , Data > { - virtual void set( Vertex &out , const BaseVertexWithData< Real , Dim , Data > &in ) = 0; + virtual Vertex toOutputVertex( const LevelSetVertex< Real , Dim , Data > &in ) = 0; - OutputVertexWithDataStreamWrapper( OutputDataStream< Vertex > &stream , BaseVertexWithData< Real , Dim , Data > in , Vertex out ) : _stream(stream) , _in(in) , _out(out) {} + OutputVertexStreamWrapper( OutputDataStream< Vertex > &stream ) : _stream(stream){} void base_write( Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ) { - _in.template get<0>() = p; - _in.template get<1>() = g; - _in.template get<2>() = w; - _in.template get<3>() = d; - set( _out , _in ); - _stream.write( _out ); + LevelSetVertex< Real , Dim , Data > in; + in.template get<0>() = p; + in.template get<1>() = g; + in.template get<2>() = w; + in.template get<3>() = d; + + Vertex out = toOutputVertex( in ); + _stream.write( out ); + } + void base_write( unsigned int thread , Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ) + { + LevelSetVertex< Real , Dim , Data > in; + in.template get<0>() = p; + in.template get<1>() = g; + in.template get<2>() = w; + in.template get<3>() = d; + + Vertex out = toOutputVertex( in ); + _stream.write( thread , out ); } protected: OutputDataStream< Vertex > &_stream; - BaseVertexWithData< Real , Dim , Data > _in; - Vertex _out; }; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // A wrapper class to write out indexed vertices: OutputDataStream< IndexedVertex > -> OutputIndexedVertexStream< Real , Dim > // + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + template< typename Vertex , typename Real , unsigned int Dim > + struct OutputIndexedVertexStreamWrapper< Vertex , Real , Dim > : public OutputIndexedVertexStream< Real , Dim > + { + virtual Vertex toOutputVertex( const LevelSetVertex< Real , Dim > &in ) = 0; + + OutputIndexedVertexStreamWrapper( OutputDataStream< std::pair< node_index_type , Vertex > > &stream ) : _stream(stream){} + + void base_write( node_index_type idx , Position< Real , Dim > p , Normal< Real , Dim > g , Real w ) + { + LevelSetVertex< Real , Dim > in; + in.template get<0>() = p; + in.template get<1>() = g; + in.template get<2>() = w; + + std::pair< node_index_type , Vertex > out( idx , toOutputVertex(in) ); + _stream.write( out ); + } + void base_write( unsigned int thread , node_index_type idx , Position< Real , Dim > p , Normal< Real , Dim > g , Real w ) + { + LevelSetVertex< Real , Dim > in; + in.template get<0>() = p; + in.template get<1>() = g; + in.template get<2>() = w; + + std::pair< node_index_type , Vertex > out( idx , toOutputVertex(in) ); + _stream.write( thread , out ); + } + protected: + OutputDataStream< std::pair< node_index_type , Vertex > > &_stream; + }; + + template< typename Vertex , typename Real , unsigned int Dim , typename Data > + struct OutputIndexedVertexStreamWrapper< Vertex , Real , Dim , Data > : public OutputIndexedVertexStream< Real , Dim , Data > + { + virtual Vertex toOutputVertex( const LevelSetVertex< Real , Dim , Data > &in ) = 0; + + OutputIndexedVertexStreamWrapper( OutputDataStream< std::pair< node_index_type , Vertex > > &stream ) : _stream(stream){} + + void base_write( node_index_type idx , Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ) + { + LevelSetVertex< Real , Dim , Data > in; + in.template get<0>() = p; + in.template get<1>() = g; + in.template get<2>() = w; + in.template get<3>() = d; + + std::pair< node_index_type , Vertex > out( idx , toOutputVertex(in) ); + _stream.write( out ); + } + void base_write( unsigned int thread , node_index_type idx , Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ) + { + LevelSetVertex< Real , Dim , Data > in; + in.template get<0>() = p; + in.template get<1>() = g; + in.template get<2>() = w; + in.template get<3>() = d; + + std::pair< node_index_type , Vertex > out( idx , toOutputVertex(in) ); + _stream.write( thread , out ); + } + protected: + OutputDataStream< std::pair< node_index_type , Vertex > > &_stream; + }; ////////////////////////////////// // File-backed streaming memory // ////////////////////////////////// @@ -518,19 +726,25 @@ namespace PoissonRecon std::vector< OutputDataStream< Face< FaceDim > > * > _outStreams; }; - template< typename Factory > - struct OutputInputFactoryTypeStream : public OutputDataStream< typename Factory::VertexType > , public InputDataStream< typename Factory::VertexType > + template< typename Factory , bool Parallel > + struct OutputInputFactoryTypeStream : + public std::conditional_t< Parallel , MultiOutputDataStream< std::pair< node_index_type , typename Factory::VertexType > > , OutputDataStream< typename Factory::VertexType > > , + public std::conditional_t< Parallel , MultiInputDataStream< std::pair< node_index_type , typename Factory::VertexType > > , InputDataStream< typename Factory::VertexType > > { - typedef typename Factory::VertexType Vertex; + using Vertex = std::conditional_t< Parallel , std::pair< node_index_type , typename Factory::VertexType > , typename Factory::VertexType >; // The streams for communicating the information - InputDataStream < Vertex > * inStream; - OutputDataStream< Vertex > *outStream; + using InputStreamType = std::conditional_t< Parallel , MultiInputDataStream< Vertex > , InputDataStream< Vertex > >; + using OutputStreamType = std::conditional_t< Parallel , MultiOutputDataStream< Vertex > , OutputDataStream< Vertex > >; + InputStreamType * inStream; + OutputStreamType *outStream; void reset( void ){ inStream->reset(); } - void base_write( const Vertex &v ){ outStream->write( v ); } - bool base_read( Vertex &v ){ return inStream->read( v ); } + void base_write( const Vertex &v ){ outStream->write( v ); } + void base_write( unsigned int thread , const Vertex &v ){ outStream->write( thread , v ); } + bool base_read( Vertex &v ){ return inStream->read( v ); } + bool base_read( unsigned int thread , Vertex &v ){ return inStream->read( thread , v ); } - OutputInputFactoryTypeStream( Factory &factory , bool inCore , bool multi ) + OutputInputFactoryTypeStream( Factory &factory , bool inCore ) { size_t sz = std::thread::hardware_concurrency(); @@ -545,7 +759,7 @@ namespace PoissonRecon if( inCore ) { - if( multi ) + if constexpr( Parallel ) { for( unsigned int i=0 ; i( _backingFiles[i]->fp , factory ); - _outStreams[i] = new FileBackedOutputFactoryTypeStream< Factory >( _backingFiles[i]->fp , factory ); + _inStreams[i] = new FileBackedInputFactoryTypeStream< Factory , Parallel , node_index_type >( _backingFiles[i]->fp , factory ); + _outStreams[i] = new FileBackedOutputFactoryTypeStream< Factory , Parallel , node_index_type >( _backingFiles[i]->fp , factory ); } inStream = new MultiInputDataStream< Vertex >( _inStreams ); outStream = new MultiOutputDataStream< Vertex >( _outStreams ); @@ -580,10 +794,15 @@ namespace PoissonRecon else { _backingFile = new FileBackedReadWriteStream::FileDescription( NULL ); - inStream = new FileBackedInputFactoryTypeStream< Factory >( _backingFile->fp , factory ); - outStream = new FileBackedOutputFactoryTypeStream< Factory >( _backingFile->fp , factory ); + inStream = new FileBackedInputFactoryTypeStream< Factory , Parallel , node_index_type >( _backingFile->fp , factory ); + outStream = new FileBackedOutputFactoryTypeStream< Factory , Parallel , node_index_type >( _backingFile->fp , factory ); } } + if constexpr( Parallel ) + { + MultiOutputDataStream< std::pair< node_index_type , typename Factory::VertexType > >::_init( _outStreams ); + MultiInputDataStream< std::pair< node_index_type , typename Factory::VertexType > >::_init( _inStreams ); + } } ~OutputInputFactoryTypeStream( void ) @@ -614,7 +833,121 @@ namespace PoissonRecon }; template< typename Real , unsigned int Dim , bool HasGradients , bool HasDensity > - struct OutputVertexInfo + struct OutputVertexInfo< Real , Dim , HasGradients , HasDensity > + { + using Factory = + typename std::conditional + < + HasGradients , + typename std::conditional + < + HasDensity , + VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::NormalFactory< Real , Dim > , VertexFactory::ValueFactory< Real > > , + VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::NormalFactory< Real , Dim > > + >::type , + typename std::conditional + < + HasDensity , + VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::ValueFactory< Real > > , + VertexFactory::PositionFactory< Real , Dim > + >::type + >::type; + using Vertex = typename Factory::VertexType; + + static Factory GetFactory( void ){ return Factory(); } + + struct StreamWrapper : public Reconstructor::OutputVertexStreamWrapper< Vertex , Real , Dim > + { + StreamWrapper( OutputDataStream< Vertex > &stream ) : + Reconstructor::OutputVertexStreamWrapper< Vertex , Real , Dim >( stream ){} + + Vertex toOutputVertex( const Reconstructor::LevelSetVertex< Real , Dim > &in ) + { + Vertex out; + if constexpr( HasGradients || HasDensity ) + { + out.template get<0>() = in.template get<0>(); + if constexpr( HasGradients ) + { + out.template get<1>() = in.template get<1>(); + if constexpr( HasDensity ) out.template get<2>() = in.template get<2>(); + } + else + { + if constexpr( HasDensity ) out.template get<1>() = in.template get<2>(); + } + } + else out = in.template get<0>(); + return out; + } + }; + }; + + template< typename Real , unsigned int Dim , bool HasGradients , bool HasDensity , typename AuxDataFactory > + struct OutputVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactory > + { + using Factory = + typename std::conditional + < + HasGradients , + typename std::conditional + < + HasDensity , + VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::NormalFactory< Real , Dim > , VertexFactory::ValueFactory< Real > , AuxDataFactory > , + VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::NormalFactory< Real , Dim > , AuxDataFactory > + >::type , + typename std::conditional + < + HasDensity , + VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::ValueFactory< Real > , AuxDataFactory > , + VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , AuxDataFactory > + >::type + >::type; + using AuxData = typename AuxDataFactory::VertexType; + + using _Vertex = VectorTypeUnion< Real , Point< Real , Dim > , Point< Real , Dim > , Real , typename AuxDataFactory::VertexType >; + using Vertex = typename Factory::VertexType; + + static Factory GetFactory( AuxDataFactory auxDataFactory ) + { + if constexpr( HasGradients ) + { + if constexpr( HasDensity ) return Factory( VertexFactory::PositionFactory< Real , Dim >() , VertexFactory::NormalFactory< Real , Dim >() , VertexFactory::ValueFactory< Real >() , auxDataFactory ); + else return Factory( VertexFactory::PositionFactory< Real , Dim >() , VertexFactory::NormalFactory< Real , Dim >() , auxDataFactory ); + } + else + { + if constexpr( HasDensity ) return Factory( VertexFactory::PositionFactory< Real , Dim >() , VertexFactory::ValueFactory< Real >() , auxDataFactory ); + else return Factory( VertexFactory::PositionFactory< Real , Dim >() , auxDataFactory ); + } + } + + struct StreamWrapper : public Reconstructor::OutputVertexStreamWrapper< Vertex , Real , Dim , AuxData > + { + StreamWrapper( OutputDataStream< Vertex > &stream ) : + Reconstructor::OutputVertexStreamWrapper< Vertex , Real , Dim , AuxData >( stream ){} + + Vertex toOutputVertex( const Reconstructor::LevelSetVertex< Real , Dim , AuxData > &in ) + { + Vertex out; + out.template get<0>() = in.template get<0>(); + if constexpr( HasGradients ) + { + out.template get<1>() = in.template get<1>(); + if constexpr( HasDensity ) out.template get<2>() = in.template get<2>() , out.template get<3>() = in.template get<3>(); + else out.template get<2>() = in.template get<3>(); + } + else + { + if constexpr( HasDensity ) out.template get<1>() = in.template get<2>() , out.template get<2>() = in.template get<3>(); + else out.template get<1>() = in.template get<3>(); + } + return out; + } + }; + }; + template< typename Real , unsigned int Dim , bool HasGradients , bool HasDensity > + struct OutputIndexedVertexInfo< Real , Dim , HasGradients , HasDensity > { using Factory = typename std::conditional @@ -634,15 +967,18 @@ namespace PoissonRecon >::type >::type; using Vertex = typename Factory::VertexType; + using IndexedVertex = std::pair< node_index_type , Vertex >; static Factory GetFactory( void ){ return Factory(); } - struct StreamWrapper : public Reconstructor::OutputVertexStreamWrapper< Real , Dim , Vertex > + struct StreamWrapper : public Reconstructor::OutputIndexedVertexStreamWrapper< Vertex , Real , Dim > { - StreamWrapper( OutputDataStream< Vertex > &stream , Vertex out ) : - Reconstructor::OutputVertexStreamWrapper< Real , Dim , Vertex >( stream , out ){} - void set( Vertex &out , const Reconstructor::BaseVertex< Real , Dim > &in ) + StreamWrapper( OutputDataStream< IndexedVertex > &stream ) : + Reconstructor::OutputIndexedVertexStreamWrapper< Vertex , Real , Dim >( stream ){} + + Vertex toOutputVertex( const Reconstructor::LevelSetVertex< Real , Dim > &in ) { + Vertex out; if constexpr( HasGradients || HasDensity ) { out.template get<0>() = in.template get<0>(); @@ -657,12 +993,13 @@ namespace PoissonRecon } } else out = in.template get<0>(); + return out; } }; }; - template< typename Real , unsigned int Dim , typename AuxDataFactory , bool HasGradients , bool HasDensity > - struct OutputVertexWithDataInfo + template< typename Real , unsigned int Dim , bool HasGradients , bool HasDensity , typename AuxDataFactory > + struct OutputIndexedVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactory > { using Factory = typename std::conditional @@ -685,6 +1022,7 @@ namespace PoissonRecon using _Vertex = VectorTypeUnion< Real , Point< Real , Dim > , Point< Real , Dim > , Real , typename AuxDataFactory::VertexType >; using Vertex = typename Factory::VertexType; + using IndexedVertex = std::pair< node_index_type , Vertex >; static Factory GetFactory( AuxDataFactory auxDataFactory ) { @@ -700,13 +1038,14 @@ namespace PoissonRecon } } - struct StreamWrapper : public Reconstructor::OutputVertexWithDataStreamWrapper< Real , Dim , AuxData , Vertex > + struct StreamWrapper : public Reconstructor::OutputIndexedVertexStreamWrapper< Vertex , Real , Dim , AuxData > { - StreamWrapper( OutputDataStream< Vertex > &stream , Vertex out ) : - Reconstructor::OutputVertexWithDataStreamWrapper< Real , Dim , AuxData , Vertex >( stream , _Vertex() , out ){} + StreamWrapper( OutputDataStream< IndexedVertex > &stream ) : + Reconstructor::OutputIndexedVertexStreamWrapper< Vertex , Real , Dim , AuxData >( stream ){} - void set( Vertex &out , const Reconstructor::BaseVertexWithData< Real , Dim , AuxData > &in ) + Vertex toOutputVertex( const Reconstructor::LevelSetVertex< Real , Dim , AuxData > &in ) { + Vertex out; out.template get<0>() = in.template get<0>(); if constexpr( HasGradients ) { @@ -719,6 +1058,7 @@ namespace PoissonRecon if constexpr( HasDensity ) out.template get<1>() = in.template get<2>() , out.template get<2>() = in.template get<3>(); else out.template get<1>() = in.template get<3>(); } + return out; } }; }; diff --git a/Src/SSDRecon.cpp b/Src/SSDRecon.cpp index 5cea7672..e21c17ca 100644 --- a/Src/SSDRecon.cpp +++ b/Src/SSDRecon.cpp @@ -68,6 +68,7 @@ CmdLineReadable Colors( "colors" ) , InCore( "inCore" ) , Gradients( "gradients" ) , + GridCoordinates( "gridCoordinates" ) , Verbose( "verbose" ); CmdLineParameter< int > @@ -137,6 +138,7 @@ CmdLineReadable* params[] = &ThreadChunkSize , &LowDepthCutOff , &AlignmentDir , + &GridCoordinates , NULL }; @@ -181,6 +183,7 @@ void ShowUsage(char* ex) printf( "\t[--%s]\n" , PolygonMesh.name ); printf( "\t[--%s =%g]\n" , CGSolverAccuracy.name , CGSolverAccuracy.value ); printf( "\t[--%s =%d]\n" , MaxMemoryGB.name , MaxMemoryGB.value ); + printf( "\t[--%s]\n" , GridCoordinates.name ); printf( "\t[--%s]\n" , Performance.name ); printf( "\t[--%s]\n" , Density.name ); printf( "\t[--%s]\n" , NonLinearFit.name ); @@ -191,30 +194,31 @@ void ShowUsage(char* ex) printf( "\t[--%s]\n" , Verbose.name ); } -template< typename Real , unsigned int Dim , unsigned int FEMSig , bool HasGradients , bool HasDensity > +template< typename Real , unsigned int Dim , unsigned int FEMSig , bool HasGradients , bool HasDensity , typename ... AuxDataFactories > void WriteMesh ( bool inCore , - Reconstructor::Implicit< Real , Dim , FEMSig > &implicit , + Reconstructor::Implicit< Real , Dim , FEMSig , typename AuxDataFactories::VertexType ... > &implicit , const Reconstructor::LevelSetExtractionParameters &meParams , std::string fileName , - bool ascii + bool ascii , + const AuxDataFactories& ... factories ) { // A description of the output vertex information - using VInfo = Reconstructor::OutputVertexInfo< Real , Dim , HasGradients , HasDensity >; + using VInfo = Reconstructor::OutputIndexedVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactories ... >; // A factory generating the output vertices using Factory = typename VInfo::Factory; - Factory factory = VInfo::GetFactory(); + Factory factory = VInfo::GetFactory( factories... ); // A backing stream for the vertices - Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , inCore , false ); + Reconstructor::OutputInputFactoryTypeStream< Factory , true > vertexStream( factory , inCore ); Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( inCore , true ); { // The wrapper converting native to output types - typename VInfo::StreamWrapper _vertexStream( vertexStream , factory() ); + typename VInfo::StreamWrapper _vertexStream( vertexStream ); // Extract the level set implicit.extractLevelSet( _vertexStream , faceStream , meParams ); @@ -222,42 +226,9 @@ void WriteMesh // Write the mesh to a .ply file std::vector< std::string > noComments; - PLY::Write< Factory , node_index_type , Real , Dim >( fileName , factory , vertexStream.size() , faceStream.size() , vertexStream , faceStream , ascii ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); -} - -template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxDataFactory , bool HasGradients , bool HasDensity > -void WriteMeshWithData -( - const AuxDataFactory &auxDataFactory , - bool inCore , - Reconstructor::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType > &implicit , - const Reconstructor::LevelSetExtractionParameters &meParams , - std::string fileName , - bool ascii -) -{ - // A description of the output vertex information - using VInfo = Reconstructor::OutputVertexWithDataInfo< Real , Dim , AuxDataFactory , HasGradients , HasDensity >; - - // A factory generating the output vertices - using Factory = typename VInfo::Factory; - Factory factory = VInfo::GetFactory( auxDataFactory ); - - // A backing stream for the vertices - Reconstructor::OutputInputFactoryTypeStream< Factory > vertexStream( factory , inCore , false ); - Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( inCore , true ); - - { - // The wrapper converting native to output types - typename VInfo::StreamWrapper _vertexStream( vertexStream , factory() ); - - // Extract the level set - implicit.extractLevelSet( _vertexStream , faceStream , meParams ); - } - - // Write the mesh to a .ply file - std::vector< std::string > noComments; - PLY::Write< Factory , node_index_type , Real , Dim >( fileName , factory , vertexStream.size() , faceStream.size() , vertexStream , faceStream , ascii ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); + vertexStream.reset(); + IndexedInputDataStream< node_index_type , typename Factory::VertexType > vStream( vertexStream , factory() ); + PLY::Write< Factory , node_index_type , Real , Dim >( fileName , factory , vertexStream.size() , faceStream.size() , vStream , faceStream , ascii ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); } template< class Real , unsigned int Dim , unsigned int FEMSig , typename AuxDataFactory > @@ -332,6 +303,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) meParams.outputGradients = Gradients.set; meParams.forceManifold = !NonManifold.set; meParams.polygonMesh = PolygonMesh.set; + meParams.gridCoordinates = GridCoordinates.set; meParams.verbose = Verbose.set; double startTime = Time(); @@ -406,17 +378,19 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( ret ) p = scratch.template get<0>() , n = scratch.template get<1>(); return ret; } + bool base_read( unsigned int , Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n ){ return base_read( p , n ); } }; // A wrapper class to realize InputPointStream as an InputSampleWithDataStream - struct _InputSampleWithDataStream : public Reconstructor::InputSampleWithDataStream< Real , Dim , typename AuxDataFactory::VertexType > + struct _InputSampleWithDataStream : public Reconstructor::InputSampleStream< Real , Dim , typename AuxDataFactory::VertexType > { typedef VectorTypeUnion< Real , Reconstructor::Normal< Real , Dim > , typename AuxDataFactory::VertexType > DataType; typedef VectorTypeUnion< Real , Reconstructor::Position< Real , Dim > , DataType > SampleType; typedef InputDataStream< SampleType > _InputPointStream; _InputPointStream &pointStream; SampleType scratch; - _InputSampleWithDataStream( _InputPointStream &pointStream , typename AuxDataFactory::VertexType zero ) : Reconstructor::InputSampleWithDataStream< Real , Dim , typename AuxDataFactory::VertexType >( zero ) , pointStream( pointStream ) + _InputSampleWithDataStream( _InputPointStream &pointStream , typename AuxDataFactory::VertexType zero ) + : Reconstructor::InputSampleStream< Real , Dim , typename AuxDataFactory::VertexType >( zero ) , pointStream( pointStream ) { scratch = SampleType( Reconstructor::Position< Real , Dim >() , DataType( Reconstructor::Normal< Real , Dim >() , zero ) ); } @@ -427,6 +401,10 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( ret ) p = scratch.template get<0>() , n = scratch.template get<1>().template get<0>() , d = scratch.template get<1>().template get<1>(); return ret; } + bool base_read( unsigned int , Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n , typename AuxDataFactory::VertexType &d ) + { + return base_read( p , n , d ); + } }; if constexpr( HasAuxData ) @@ -435,7 +413,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( Transform.set ) { - Reconstructor::TransformedInputSampleWithDataStream< Real , Dim , typename AuxDataFactory::VertexType > _sampleStream( toModel , sampleStream ); + Reconstructor::TransformedInputSampleStream< Real , Dim , _InputSampleWithDataStream , typename AuxDataFactory::VertexType > _sampleStream( toModel , sampleStream ); implicit = new Reconstructor::SSD::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( _sampleStream , sParams ); implicit->unitCubeToModel = toModel.inverse() * implicit->unitCubeToModel; } @@ -447,7 +425,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( Transform.set ) { - Reconstructor::TransformedInputSampleStream< Real , Dim > _sampleStream( toModel , sampleStream ); + Reconstructor::TransformedInputSampleStream< Real , Dim , _InputSampleStream > _sampleStream( toModel , sampleStream ); implicit = new Reconstructor::SSD::Implicit< Real , Dim , FEMSig >( _sampleStream , sParams ); implicit->unitCubeToModel = toModel.inverse() * implicit->unitCubeToModel; } @@ -513,26 +491,26 @@ void Execute( const AuxDataFactory &auxDataFactory ) { if( Density.set ) { - if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , true , true >( auxDataFactory , InCore.set , *implicit , meParams , Out.value , ASCII.set ); - else WriteMesh < Real , Dim , FEMSig , true , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); + if constexpr( HasAuxData ) WriteMesh< Real , Dim , FEMSig , true , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set , auxDataFactory ); + else WriteMesh< Real , Dim , FEMSig , true , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); } else { - if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , true , false >( auxDataFactory , InCore.set , *implicit , meParams , Out.value , ASCII.set ); - else WriteMesh < Real , Dim , FEMSig , true , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); + if constexpr( HasAuxData ) WriteMesh< Real , Dim , FEMSig , true , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set , auxDataFactory ); + else WriteMesh< Real , Dim , FEMSig , true , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); } } else { if( Density.set ) { - if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , false , true >( auxDataFactory , InCore.set , *implicit , meParams , Out.value , ASCII.set ); - else WriteMesh < Real , Dim , FEMSig , false , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); + if constexpr( HasAuxData ) WriteMesh< Real , Dim , FEMSig , false , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set , auxDataFactory ); + else WriteMesh< Real , Dim , FEMSig , false , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); } else { - if constexpr( HasAuxData ) WriteMeshWithData< Real , Dim , FEMSig , AuxDataFactory , false , false >( auxDataFactory , InCore.set , *implicit , meParams , Out.value , ASCII.set ); - else WriteMesh < Real , Dim , FEMSig , false , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); + if constexpr( HasAuxData ) WriteMesh< Real , Dim , FEMSig , false , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set , auxDataFactory ); + else WriteMesh< Real , Dim , FEMSig , false , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); } } } From dae2ffb2d2f89098465c1662112c3ace82d10836 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Sun, 22 Sep 2024 20:43:53 -0400 Subject: [PATCH 48/86] Version 18.10 --- Src/AdaptiveTreeVisualization.cpp | 4 +- Src/PointInterpolant.cpp | 4 +- Src/PoissonRecon.client.inl | 4 +- Src/PoissonRecon.cpp | 8 +- Src/PoissonRecon.server.inl | 4 +- Src/Reconstruction.example.cpp | 12 ++- Src/Reconstructors.h | 32 +++---- Src/Reconstructors.streams.h | 144 ++++++++++++++---------------- Src/SSDRecon.cpp | 9 +- 9 files changed, 102 insertions(+), 119 deletions(-) diff --git a/Src/AdaptiveTreeVisualization.cpp b/Src/AdaptiveTreeVisualization.cpp index a9e6fa2d..92653cc4 100644 --- a/Src/AdaptiveTreeVisualization.cpp +++ b/Src/AdaptiveTreeVisualization.cpp @@ -398,7 +398,7 @@ void _Execute( const FEMTree< Dim , Real > *tree , XForm< Real , Dim+1 > modelTo double t = Time(); // A description of the output vertex information - using VInfo = Reconstructor::OutputVertexInfo< Real , Dim , false , false >; + using VInfo = Reconstructor::OutputLevelSetVertexInfo< Real , Dim , false , false >; // A factory generating the output vertices using Factory = typename VInfo::Factory; @@ -411,7 +411,7 @@ void _Execute( const FEMTree< Dim , Real > *tree , XForm< Real , Dim+1 > modelTo { // The wrapper converting native to output types typename VInfo::StreamWrapper _vertexStream( vertexStream ); - Reconstructor::TransformedOutputVertexStream< Real , Dim > __vertexStream( modelToUnitCube.inverse() , _vertexStream ); + Reconstructor::TransformedOutputLevelSetVertexStream< Real , Dim > __vertexStream( modelToUnitCube.inverse() , _vertexStream ); // Extract the mesh if constexpr( Dim==3 ) LevelSetExtractor< Real , Dim >::Extract( IsotropicUIntPack< Dim , FEMSig >() , UIntPack< 0 >() , *tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , coefficients , IsoValue.value , IsoSlabDepth.value , IsoSlabStart.value , IsoSlabEnd.value , __vertexStream , faceStream , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , FlipOrientation.set ); diff --git a/Src/PointInterpolant.cpp b/Src/PointInterpolant.cpp index 25aecc10..3e1064fb 100644 --- a/Src/PointInterpolant.cpp +++ b/Src/PointInterpolant.cpp @@ -353,7 +353,7 @@ void ExtractLevelSet } // A description of the output vertex information - using VInfo = Reconstructor::OutputVertexInfo< Real , Dim , false , false >; + using VInfo = Reconstructor::OutputLevelSetVertexInfo< Real , Dim , false , false >; // A factory generating the output vertices using Factory = typename VInfo::Factory; @@ -367,7 +367,7 @@ void ExtractLevelSet { // The wrapper converting native to output types typename VInfo::StreamWrapper _vertexStream( vertexStream ); - Reconstructor::TransformedOutputVertexStream< Real , Dim > __vertexStream( unitCubeToModel , _vertexStream ); + Reconstructor::TransformedOutputLevelSetVertexStream< Real , Dim > __vertexStream( unitCubeToModel , _vertexStream ); // Extract the mesh stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< 0 >() , tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , solution , isoValue , __vertexStream , faceStream , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , false ); diff --git a/Src/PoissonRecon.client.inl b/Src/PoissonRecon.client.inl index 8bde2c3b..e2e4362e 100644 --- a/Src/PoissonRecon.client.inl +++ b/Src/PoissonRecon.client.inl @@ -1251,7 +1251,7 @@ void Client< Real , Dim , BType , Degree >::_writeMeshWithData( const ClientReco // A description of the output vertex information - using VInfo = Reconstructor::OutputVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactory >; + using VInfo = Reconstructor::OutputLevelSetVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactory >; // A factory generating the output vertices using Factory = typename VInfo::Factory; @@ -1268,7 +1268,7 @@ void Client< Real , Dim , BType , Degree >::_writeMeshWithData( const ClientReco typename VInfo::StreamWrapper _vertexStream( vertexStream ); // The transformed stream - Reconstructor::TransformedOutputVertexStream< Real , Dim , AuxData > __vertexStream( unitCubeToModel , _vertexStream ); + Reconstructor::TransformedOutputLevelSetVertexStream< Real , Dim , AuxData > __vertexStream( unitCubeToModel , _vertexStream ); // Extract the mesh stats = LevelSetExtractor< Real , Dim , AuxData >::template Extract< Reconstructor::WeightDegree , DataSig > diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index 00d92b41..df424d56 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -213,7 +213,7 @@ void WriteMesh ) { // A description of the output vertex information - using VInfo = Reconstructor::OutputIndexedVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactories ... >; + using VInfo = Reconstructor::OutputIndexedLevelSetVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactories ... >; // A factory generating the output vertices using Factory = typename VInfo::Factory; @@ -418,7 +418,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) typedef InputDataStream< SampleType > _InputPointStream; _InputPointStream &pointStream; SampleType scratch; - _InputSampleWithDataStream( _InputPointStream &pointStream , typename AuxDataFactory::VertexType zero ) : Reconstructor::InputSampleStream< Real , Dim , typename AuxDataFactory::VertexType >( zero ) , pointStream( pointStream ) + _InputSampleWithDataStream( _InputPointStream &pointStream , typename AuxDataFactory::VertexType zero ) : pointStream( pointStream ) { scratch = SampleType( Reconstructor::Position< Real , Dim >() , DataType( Reconstructor::Normal< Real , Dim >() , zero ) ); } @@ -445,10 +445,10 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( Transform.set ) { Reconstructor::TransformedInputSampleStream< Real , Dim , _InputSampleWithDataStream , typename AuxDataFactory::VertexType > _sampleStream( toModel , sampleStream ); - implicit = new typename Reconstructor::Poisson::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( _sampleStream , sParams , envelopeMesh ); + implicit = new typename Reconstructor::Poisson::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( _sampleStream , sParams , auxDataFactory() , envelopeMesh ); implicit->unitCubeToModel = toModel.inverse() * implicit->unitCubeToModel; } - else implicit = new typename Reconstructor::Poisson::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( sampleStream , sParams , envelopeMesh ); + else implicit = new typename Reconstructor::Poisson::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( sampleStream , sParams , auxDataFactory() , envelopeMesh ); } else { diff --git a/Src/PoissonRecon.server.inl b/Src/PoissonRecon.server.inl index 53edc5af..42909d5f 100644 --- a/Src/PoissonRecon.server.inl +++ b/Src/PoissonRecon.server.inl @@ -710,10 +710,10 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase6( const ClientReconstruc const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim-1 , DataSig > > *data=NULL; { VectorBackedOutputDataStream< Point< Real , Dim-1 > > _vertices( state6.vertices ); - struct VertexStreamWrapper : public Reconstructor::OutputVertexStreamWrapper< Point< Real , Dim-1 > , Real , Dim-1 > + struct VertexStreamWrapper : public Reconstructor::OutputLevelSetVertexStreamWrapper< Point< Real , Dim-1 > , Real , Dim-1 > { typedef Point< Real , Dim-1 > Vertex; - VertexStreamWrapper( OutputDataStream< Vertex > &stream ) : Reconstructor::OutputVertexStreamWrapper< Point< Real , Dim-1 > , Real , Dim-1 >( stream ) {} + VertexStreamWrapper( OutputDataStream< Vertex > &stream ) : Reconstructor::OutputLevelSetVertexStreamWrapper< Point< Real , Dim-1 > , Real , Dim-1 >( stream ) {} Vertex toOutputVertex(const Reconstructor::LevelSetVertex< Real , Dim-1 > &in ){ return in.template get<0>(); } }; VertexStreamWrapper __vertexStream( _vertices ); diff --git a/Src/Reconstruction.example.cpp b/Src/Reconstruction.example.cpp index 4e2ef035..d489071b 100644 --- a/Src/Reconstruction.example.cpp +++ b/Src/Reconstruction.example.cpp @@ -127,9 +127,7 @@ struct SphereSampleWithColorStream : public Reconstructor::InputSampleStream< Re std::uniform_real_distribution< Real > distribution; // Constructs a stream that contains the specified number of samples - SphereSampleWithColorStream( unsigned int sz ) : - _size(sz) , _current(0) , generator(0) , distribution((Real)-1.0,(Real)1.0) , - Reconstructor::InputSampleStream< Real , Dim , RGBColor< Real > >( RGBColor< Real >() ) {} + SphereSampleWithColorStream( unsigned int sz ) :_size(sz) , _current(0) , generator(0) , distribution((Real)-1.0,(Real)1.0) {} // Overrides the pure abstract method from InputSampleStream< Real , Dim , RGBColor< Real > > void reset( void ){ generator.seed(0) ; _current = 0; } @@ -184,12 +182,12 @@ struct PolygonStream : public Reconstructor::OutputFaceStream< 2 > // A stream into which we can write the output vertices of the extracted mesh template< typename Real , unsigned int Dim > -struct VertexStream : public Reconstructor::OutputVertexStream< Real , Dim > +struct VertexStream : public Reconstructor::OutputLevelSetVertexStream< Real , Dim > { // Construct a stream that adds vertices into the coordinates VertexStream( std::vector< Real > &vCoordinates ) : _vCoordinates( vCoordinates ) {} - // Override the pure abstract method from Reconstructor::OutputVertexStream< Real , Dim > + // Override the pure abstract method from Reconstructor::OutputLevelSetVertexStream< Real , Dim > void base_write( Point< Real , Dim > p , Point< Real , Dim > , Real ){ for( unsigned int d=0 ; d p , Point< Real , Dim > g , Real r ){ return base_write( p , g , r ); } protected: @@ -198,7 +196,7 @@ struct VertexStream : public Reconstructor::OutputVertexStream< Real , Dim > // A stream into which we can write the output vertices and colors of the extracted mesh template< typename Real , unsigned int Dim > -struct VertexWithColorStream : public Reconstructor::OutputVertexStream< Real , Dim , RGBColor< Real > > +struct VertexWithColorStream : public Reconstructor::OutputLevelSetVertexStream< Real , Dim , RGBColor< Real > > { // Construct a stream that adds vertices into the coordinates VertexWithColorStream( std::vector< Real > &vCoordinates , std::vector< Real > &rgbCoordinates ) : @@ -279,7 +277,7 @@ void Execute( void ) SphereSampleWithColorStream< Real , Dim > sampleStream( SampleNum.value ); // Construct the implicit representation - Implicit implicit( sampleStream , solverParams ); + Implicit implicit( sampleStream , solverParams , RGBColor< Real >() ); // Scale the color information to give extrapolation preference to data at finer depths implicit.weightAuxDataByDepth( (Real)32. ); diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h index 89b2941c..8eb833bb 100644 --- a/Src/Reconstructors.h +++ b/Src/Reconstructors.h @@ -96,15 +96,15 @@ namespace PoissonRecon DensityEstimator *density; // A method that writes the extracted mesh to the streams - void extractLevelSet( OutputVertexStream< Real , Dim > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const + void extractLevelSet( OutputLevelSetVertexStream< Real , Dim > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const { typedef unsigned char AuxData; - _ExtractLevelSet< false , false , Real , Dim , FEMSig , AuxData , OutputVertexStream< Real , Dim > , Implicit< Real , Dim , FEMSig > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); + _ExtractLevelSet< false , false , Real , Dim , FEMSig , AuxData , OutputLevelSetVertexStream< Real , Dim > , Implicit< Real , Dim , FEMSig > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); } - void extractLevelSet( OutputIndexedVertexStream< Real , Dim > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const + void extractLevelSet( OutputIndexedLevelSetVertexStream< Real , Dim > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const { typedef unsigned char AuxData; - _ExtractLevelSet< false , true , Real , Dim , FEMSig , AuxData , OutputIndexedVertexStream< Real , Dim > , Implicit< Real , Dim , FEMSig > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); + _ExtractLevelSet< false , true , Real , Dim , FEMSig , AuxData , OutputIndexedLevelSetVertexStream< Real , Dim > , Implicit< Real , Dim , FEMSig > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); } }; @@ -141,13 +141,13 @@ namespace PoissonRecon } // A method for writing the extracted mesh to the streams - void extractLevelSet( OutputVertexStream< Real , Dim , AuxData > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const + void extractLevelSet( OutputLevelSetVertexStream< Real , Dim , AuxData > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const { - _ExtractLevelSet< true , false , Real , Dim , FEMSig , AuxData , OutputVertexStream< Real , Dim , AuxData > , Implicit< Real , Dim , FEMSig , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); + _ExtractLevelSet< true , false , Real , Dim , FEMSig , AuxData , OutputLevelSetVertexStream< Real , Dim , AuxData > , Implicit< Real , Dim , FEMSig , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); } - void extractLevelSet( OutputIndexedVertexStream< Real , Dim , AuxData > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const + void extractLevelSet( OutputIndexedLevelSetVertexStream< Real , Dim , AuxData > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const { - _ExtractLevelSet< true , true , Real , Dim , FEMSig , AuxData , OutputIndexedVertexStream< Real , Dim , AuxData > , Implicit< Real , Dim , FEMSig , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); + _ExtractLevelSet< true , true , Real , Dim , FEMSig , AuxData , OutputIndexedLevelSetVertexStream< Real , Dim , AuxData > , Implicit< Real , Dim , FEMSig , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); } }; @@ -294,8 +294,8 @@ namespace PoissonRecon template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > struct Implicit< Real , Dim , FEMSig , AuxData > : public Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > { - Implicit( InputSampleStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL , ValueInterpolationStream< Real , Dim > *valueInterpolationStream=NULL ) - : Reconstructor::Implicit< Real , Dim , FEMSig , AuxData >( pointStream.zero() ) + Implicit( InputSampleStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params , AuxData zero , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL , ValueInterpolationStream< Real , Dim > *valueInterpolationStream=NULL ) + : Reconstructor::Implicit< Real , Dim , FEMSig , AuxData >( zero ) { _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params , envelopeMesh , valueInterpolationStream ); } @@ -457,8 +457,8 @@ namespace PoissonRecon template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > struct Implicit< Real , Dim , FEMSig , AuxData > : public Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > { - Implicit( InputSampleStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params ) - : Reconstructor::Implicit< Real , Dim , FEMSig , AuxData >( pointStream.zero() ) + Implicit( InputSampleStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params , AuxData zero ) + : Reconstructor::Implicit< Real , Dim , FEMSig , AuxData >( zero ) { _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params ); } @@ -533,14 +533,14 @@ namespace PoissonRecon if constexpr( HasAuxData ) { typename LevelSetExtractor< Real , Dim , AuxData >::Stats stats; - std::conditional_t< IndexedVertexStream , TransformedOutputIndexedVertexStream< Real , Dim , AuxData > , TransformedOutputVertexStream< Real , Dim , AuxData > > _vertexStream( unitCubeToModel , vertexStream ); + std::conditional_t< IndexedVertexStream , TransformedOutputIndexedLevelSetVertexStream< Real , Dim , AuxData > , TransformedOutputLevelSetVertexStream< Real , Dim , AuxData > > _vertexStream( unitCubeToModel , vertexStream ); stats = LevelSetExtractor< Real , Dim , AuxData >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , UIntPack< DataSig >() , implicit.tree , implicit.density , implicit.auxData , implicit.solution , implicit.isoValue , _vertexStream , faceStream , implicit.zeroAuxData , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); statsString = stats.toString(); } else { typename LevelSetExtractor< Real , Dim >::Stats stats; - std::conditional_t< IndexedVertexStream , TransformedOutputIndexedVertexStream< Real , Dim > , TransformedOutputVertexStream< Real , Dim > > _vertexStream( unitCubeToModel , vertexStream ); + std::conditional_t< IndexedVertexStream , TransformedOutputIndexedLevelSetVertexStream< Real , Dim > , TransformedOutputLevelSetVertexStream< Real , Dim > > _vertexStream( unitCubeToModel , vertexStream ); stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , implicit.tree , implicit.density , implicit.solution , implicit.isoValue , _vertexStream , faceStream , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); statsString = stats.toString(); } @@ -560,14 +560,14 @@ namespace PoissonRecon if constexpr( HasAuxData ) { typename LevelSetExtractor< Real , Dim , AuxData >::Stats stats; - std::conditional_t< IndexedVertexStream , TransformedOutputIndexedVertexStream< Real , Dim , AuxData > , TransformedOutputVertexStream< Real , Dim , AuxData > > _vertexStream( unitCubeToModel , vertexStream ); + std::conditional_t< IndexedVertexStream , TransformedOutputIndexedLevelSetVertexStream< Real , Dim , AuxData > , TransformedOutputLevelSetVertexStream< Real , Dim , AuxData > > _vertexStream( unitCubeToModel , vertexStream ); stats = LevelSetExtractor< Real , Dim , AuxData >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , UIntPack< DataSig >() , implicit.tree , implicit.density , implicit.auxData , implicit.solution , implicit.isoValue , _vertexStream , faceStream , implicit.zeroAuxData , !params.linearFit , params.outputGradients , false ); statsString = stats.toString(); } else { typename LevelSetExtractor< Real , Dim >::Stats stats; - std::conditional_t< IndexedVertexStream , TransformedOutputIndexedVertexStream< Real , Dim > , TransformedOutputVertexStream< Real , Dim > > _vertexStream( unitCubeToModel , vertexStream ); + std::conditional_t< IndexedVertexStream , TransformedOutputIndexedLevelSetVertexStream< Real , Dim > , TransformedOutputLevelSetVertexStream< Real , Dim > > _vertexStream( unitCubeToModel , vertexStream ); stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , implicit.tree , implicit.density , implicit.solution , implicit.isoValue , _vertexStream , faceStream , !params.linearFit , params.outputGradients , false ); statsString = stats.toString(); } diff --git a/Src/Reconstructors.streams.h b/Src/Reconstructors.streams.h index 7a7e7f72..541650ce 100644 --- a/Src/Reconstructors.streams.h +++ b/Src/Reconstructors.streams.h @@ -44,34 +44,29 @@ namespace PoissonRecon // Basic types template< typename Real , unsigned int Dim , typename ... Other > - using BaseSample = std::conditional_t< sizeof...(Other)==0 , VectorTypeUnion< Real , Position< Real , Dim > , Normal< Real , Dim > > , VectorTypeUnion< Real , Position< Real , Dim > , VectorTypeUnion< Real , Normal< Real , Dim > , Other... > > >; + using Sample = std::conditional_t< sizeof...(Other)==0 , VectorTypeUnion< Real , Position< Real , Dim > , Normal< Real , Dim > > , VectorTypeUnion< Real , Position< Real , Dim > , VectorTypeUnion< Real , Normal< Real , Dim > , Other... > > >; // The types output by the extractor template< typename Real , unsigned int Dim , typename ... Other > using LevelSetVertex = typename LevelSetExtractor< Real , Dim , Other... >::Vertex; - template< typename Real , unsigned int Dim , typename ... Other > using LevelSetIndexedVertex = typename LevelSetExtractor< Real , Dim , Other... >::IndexedVertex; - template< typename Real , unsigned int Dim , typename ... Other > using BaseInputSampleStream = InputDataStream< BaseSample< Real , Dim , Other... > >; - template< typename Real , unsigned int Dim , typename ... Other > using LevelSetVertexStream = OutputDataStream< LevelSetVertex< Real , Dim , Other... > >; - template< typename Real , unsigned int Dim , typename ... Other > using LevelSetIndexedVertexStream = OutputDataStream< LevelSetIndexedVertex< Real , Dim , Other... > >; - // Stream types template< typename Real , unsigned int Dim , typename ... Other > struct InputSampleStream; - template< typename Real , unsigned int Dim , typename InputStream , typename ... Other > struct TransformedInputSampleStream; - template< typename Real , unsigned int Dim , typename ... Other > struct OutputVertexStream; - template< typename Real , unsigned int Dim , typename ... Other > struct OutputIndexedVertexStream; - template< typename Real , unsigned int Dim , typename ... Other > struct TransformedOutputVertexStream; - template< typename Real , unsigned int Dim , typename ... Other > struct TransformedOutputIndexedVertexStream; - template< typename Vertex , typename Real , unsigned int Dim , typename ... Other > struct OutputVertexStreamWrapper; - template< typename Vertex , typename Real , unsigned int Dim , typename ... Other > struct OutputIndexedVertexStreamWrapper; - template< typename Real , unsigned int Dim , bool HasGradients , bool HasDensity , typename ... Other > struct OutputVertexInfo; - template< typename Real , unsigned int Dim , bool HasGradients , bool HasDensity , typename ... Other > struct OutputIndexedVertexInfo; - template< unsigned int FaceDim , typename T=node_index_type > using Face = std::conditional_t< FaceDim==2 , std::vector< T > , std::conditional_t< FaceDim==1 , std::pair< T , T > , void * > >; + template< typename Real , unsigned int Dim , typename ... Other > struct OutputLevelSetVertexStream; + template< typename Real , unsigned int Dim , typename ... Other > struct OutputIndexedLevelSetVertexStream; + template< typename Real , unsigned int Dim , typename ... Other > struct TransformedOutputLevelSetVertexStream; + template< typename Real , unsigned int Dim , typename ... Other > struct TransformedOutputIndexedLevelSetVertexStream; + template< typename Vertex , typename Real , unsigned int Dim , typename ... Other > struct OutputLevelSetVertexStreamWrapper; + template< typename Vertex , typename Real , unsigned int Dim , typename ... Other > struct OutputIndexedLevelSetVertexStreamWrapper; + + template< typename Real , unsigned int Dim , bool HasGradients , bool HasDensity , typename ... Other > struct OutputLevelSetVertexInfo; + template< typename Real , unsigned int Dim , bool HasGradients , bool HasDensity , typename ... Other > struct OutputIndexedLevelSetVertexInfo; + template< unsigned int FaceDim , typename T=node_index_type > using Face = std::conditional_t< FaceDim==2 , std::vector< T > , std::conditional_t< FaceDim==1 , std::pair< T , T > , void * > >; template< unsigned int FaceDim > using InputFaceStream = InputDataStream< Face< FaceDim > >; template< unsigned int FaceDim > using OutputFaceStream = OutputDataStream< Face< FaceDim > >; @@ -136,7 +131,7 @@ namespace PoissonRecon // Oriented Point Stream // /////////////////////////// template< typename Real , unsigned int Dim > - struct InputSampleStream< Real , Dim > : public BaseInputSampleStream< Real , Dim > + struct InputSampleStream< Real , Dim > : public InputDataStream< Sample< Real , Dim > > { // Functionality to reset the stream to the start virtual void reset( void ) = 0; @@ -146,34 +141,25 @@ namespace PoissonRecon virtual bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n ) = 0; virtual bool base_read( unsigned int thread , Position< Real , Dim > &p , Normal< Real , Dim > &n ) = 0; // Implementation of InputDataStream::read - bool base_read( BaseSample< Real , Dim > &s ){ return base_read( s.template get<0>() , s.template get<1>() ); } - bool base_read( unsigned int thread , BaseSample< Real , Dim > &s ){ return base_read( thread , s.template get<0>() , s.template get<1>() ); } + bool base_read( Sample< Real , Dim > &s ){ return base_read( s.template get<0>() , s.template get<1>() ); } + bool base_read( unsigned int thread , Sample< Real , Dim > &s ){ return base_read( thread , s.template get<0>() , s.template get<1>() ); } }; /////////////////////////////////// // Oriented Point w/ Data Stream // /////////////////////////////////// template< typename Real , unsigned int Dim , typename Data > - struct InputSampleStream< Real , Dim , Data > : public BaseInputSampleStream< Real , Dim , Data > + struct InputSampleStream< Real , Dim , Data > : public InputDataStream< Sample< Real , Dim , Data > > { - // A constructor initialized with an instance of "zero" data - InputSampleStream( Data zero ) : _zero(zero) {} - // Functionality to reset the stream to the start virtual void reset( void ) = 0; - // Returns the zero instance - const Data &zero( void ) const{ return _zero; } - // Functionality to extract the next position/normal pair. // The method returns true if there was another point in the stream to read, and false otherwise virtual bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n , Data &d ) = 0; virtual bool base_read( unsigned int thread , Position< Real , Dim > &p , Normal< Real , Dim > &n , Data &d ) = 0; - bool base_read( BaseSample< Real , Dim , Data > &s ){ return base_read( s.template get<0>() , s.template get<1>().template get<0>() , s.template get<1>().template get<1>() ); } - bool base_read( unsigned int thread , BaseSample< Real , Dim , Data > &s ){ return base_read( thread , s.template get<0>() , s.template get<1>().template get<0>() , s.template get<1>().template get<1>() ); } - - // An instance of "zero" data - Data _zero; + bool base_read( Sample< Real , Dim , Data > &s ){ return base_read( s.template get<0>() , s.template get<1>().template get<0>() , s.template get<1>().template get<1>() ); } + bool base_read( unsigned int thread , Sample< Real , Dim , Data > &s ){ return base_read( thread , s.template get<0>() , s.template get<1>().template get<0>() , s.template get<1>().template get<1>() ); } }; @@ -197,14 +183,14 @@ namespace PoissonRecon // The method returns true if there was another point in the stream to read, and false otherwise bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n ) { - BaseSample< Real , Dim > s; + Sample< Real , Dim > s; bool ret = _stream.read( s ); if( ret ) p = _positionXForm * s.template get<0>() , n = _normalXForm * s.template get<1>(); return ret; } bool base_read( unsigned int thread , Position< Real , Dim > &p , Normal< Real , Dim > &n ) { - BaseSample< Real , Dim > s; + Sample< Real , Dim > s; bool ret = _stream.read( thread , s ); if( ret ) p = _positionXForm * s.template get<0>() , n = _normalXForm * s.template get<1>(); return ret; @@ -230,7 +216,7 @@ namespace PoissonRecon static_assert( std::is_base_of< InputSampleStream< Real , Dim , Data > , InputStream >::value , "[ERROR] Unexpected stream type" ); // A constructor initialized with an instance of "zero" data - TransformedInputSampleStream( XForm< Real , Dim+1 > xForm , InputStream &stream ) : InputSampleStream< Real , Dim , Data >( stream.zero() ) , _stream(stream) , _positionXForm(xForm) + TransformedInputSampleStream( XForm< Real , Dim+1 > xForm , InputStream &stream ) : _stream(stream) , _positionXForm(xForm) { _normalXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); } @@ -242,14 +228,14 @@ namespace PoissonRecon // The method returns true if there was another point in the stream to read, and false otherwise bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n , Data &d ) { - BaseSample< Real , Dim , Data > s( Position< Real , Dim >() , VectorTypeUnion< Real , Normal< Real , Dim > , Data >( Normal< Real , Dim >() , _stream.zero() ) ); + Sample< Real , Dim , Data > s( Position< Real , Dim >() , VectorTypeUnion< Real , Normal< Real , Dim > , Data >( Normal< Real , Dim >() , d ) ); bool ret = _stream.read( s ); if( ret ) p = _positionXForm * s.template get<0>() , n = _normalXForm * s.template get<1>().template get<0>() , d = s.template get<1>().template get<1>(); return ret; } bool base_read( unsigned int thread , Position< Real , Dim > &p , Normal< Real , Dim > &n , Data &d ) { - BaseSample< Real , Dim , Data > s( Position< Real , Dim >() , VectorTypeUnion< Real , Normal< Real , Dim > , Data >( Normal< Real , Dim >() , _stream.zero() ) ); + Sample< Real , Dim , Data > s( Position< Real , Dim >() , VectorTypeUnion< Real , Normal< Real , Dim > , Data >( Normal< Real , Dim >() , d ) ); bool ret = _stream.read( thread , s ); if( ret ) p = _positionXForm * s.template get<0>() , n = _normalXForm * s.template get<1>().template get<0>() , d = s.template get<1>().template get<1>(); return ret; @@ -272,10 +258,10 @@ namespace PoissonRecon // Looks like a LevelSetVertexStream, but supports component-wise insertion // ////////////////////////////////////////////////////////////////////////////// template< typename Real , unsigned int Dim > - struct OutputVertexStream< Real , Dim > : public LevelSetVertexStream< Real , Dim > + struct OutputLevelSetVertexStream< Real , Dim > : public OutputDataStream< LevelSetVertex< Real , Dim > > { // Need to provide access to base write for counter support - using LevelSetVertexStream< Real , Dim >::write; + using OutputDataStream< LevelSetVertex< Real , Dim > >::write; // Functionality to insert the next vertex virtual void base_write( Position< Real , Dim > p , Gradient< Real , Dim > g , Real w ) = 0; @@ -288,10 +274,10 @@ namespace PoissonRecon // Indexed Vertex Stream // /////////////////////////// template< typename Real , unsigned int Dim > - struct OutputIndexedVertexStream< Real , Dim > : public LevelSetIndexedVertexStream< Real , Dim > + struct OutputIndexedLevelSetVertexStream< Real , Dim > : public OutputDataStream< LevelSetIndexedVertex< Real , Dim > > { // Need to provide access to base write for counter support - using LevelSetIndexedVertexStream< Real , Dim >::write; + using OutputDataStream< LevelSetIndexedVertex< Real , Dim > >::write; // Functionality to insert the next vertex virtual void base_write( node_index_type idx , Position< Real , Dim > p , Gradient< Real , Dim > g , Real w ) = 0; @@ -310,10 +296,10 @@ namespace PoissonRecon // Vertex w/ Data Stream // /////////////////////////// template< typename Real , unsigned int Dim , typename Data > - struct OutputVertexStream< Real , Dim , Data > : public LevelSetVertexStream< Real , Dim , Data > + struct OutputLevelSetVertexStream< Real , Dim , Data > : public OutputDataStream< LevelSetVertex< Real , Dim , Data > > { // Need to provide access to base write for counter support - using LevelSetVertexStream< Real , Dim , Data >::write; + using OutputDataStream< LevelSetVertex< Real , Dim , Data > >::write; // Functionality to insert the next vertex virtual void base_write( Position< Real , Dim > p , Gradient< Real , Dim > g , Real w , Data d ) = 0; @@ -326,10 +312,10 @@ namespace PoissonRecon // Indexed vertex w/ Data Stream // /////////////////////////////////// template< typename Real , unsigned int Dim , typename Data > - struct OutputIndexedVertexStream< Real , Dim , Data > : public LevelSetIndexedVertexStream< Real , Dim , Data > + struct OutputIndexedLevelSetVertexStream< Real , Dim , Data > : public OutputDataStream< LevelSetIndexedVertex< Real , Dim , Data > > { // Need to provide access to base write for counter support - using LevelSetIndexedVertexStream< Real , Dim , Data >::write; + using OutputDataStream< LevelSetIndexedVertex< Real , Dim , Data > >::write; // Functionality to insert the next vertex virtual void base_write( node_index_type idx , Position< Real , Dim > p , Gradient< Real , Dim > g , Real w , Data d ) = 0; @@ -342,10 +328,10 @@ namespace PoissonRecon // Transformed Vertex Stream // /////////////////////////////// template< typename Real , unsigned int Dim > - struct TransformedOutputVertexStream< Real , Dim > : public OutputVertexStream< Real , Dim > + struct TransformedOutputLevelSetVertexStream< Real , Dim > : public OutputLevelSetVertexStream< Real , Dim > { // A constructor initialized with the transformation to be applied to the samples, and a sample stream - TransformedOutputVertexStream( XForm< Real , Dim+1 > xForm , OutputVertexStream< Real , Dim > &stream ) : _stream(stream) , _positionXForm(xForm) + TransformedOutputLevelSetVertexStream( XForm< Real , Dim+1 > xForm , OutputLevelSetVertexStream< Real , Dim > &stream ) : _stream(stream) , _positionXForm(xForm) { _gradientXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); } @@ -356,7 +342,7 @@ namespace PoissonRecon protected: // A reference to the underlying stream - OutputVertexStream< Real , Dim > &_stream; + OutputLevelSetVertexStream< Real , Dim > &_stream; // The affine transformation to be applied to the positions XForm< Real , Dim+1 > _positionXForm; @@ -370,10 +356,10 @@ namespace PoissonRecon // Transformed Vertex w/ Data Stream // /////////////////////////////////////// template< typename Real , unsigned int Dim , typename Data > - struct TransformedOutputVertexStream< Real , Dim , Data > : public OutputVertexStream< Real , Dim , Data > + struct TransformedOutputLevelSetVertexStream< Real , Dim , Data > : public OutputLevelSetVertexStream< Real , Dim , Data > { // A constructor initialized with the transformation to be applied to the samples, and a sample stream - TransformedOutputVertexStream( XForm< Real , Dim+1 > xForm , OutputVertexStream< Real , Dim , Data > &stream ) : _stream(stream) , _positionXForm(xForm) + TransformedOutputLevelSetVertexStream( XForm< Real , Dim+1 > xForm , OutputLevelSetVertexStream< Real , Dim , Data > &stream ) : _stream(stream) , _positionXForm(xForm) { _gradientXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); } @@ -383,7 +369,7 @@ namespace PoissonRecon protected: // A reference to the underlying stream - OutputVertexStream< Real , Dim , Data > &_stream; + OutputLevelSetVertexStream< Real , Dim , Data > &_stream; // The affine transformation to be applied to the positions XForm< Real , Dim+1 > _positionXForm; @@ -396,10 +382,10 @@ namespace PoissonRecon // Transformed Indexed Vertex Stream // /////////////////////////////////////// template< typename Real , unsigned int Dim > - struct TransformedOutputIndexedVertexStream< Real , Dim > : public OutputIndexedVertexStream< Real , Dim > + struct TransformedOutputIndexedLevelSetVertexStream< Real , Dim > : public OutputIndexedLevelSetVertexStream< Real , Dim > { // A constructor initialized with the transformation to be applied to the samples, and a sample stream - TransformedOutputIndexedVertexStream( XForm< Real , Dim+1 > xForm , OutputIndexedVertexStream< Real , Dim > &stream ) : _stream(stream) , _positionXForm(xForm) + TransformedOutputIndexedLevelSetVertexStream( XForm< Real , Dim+1 > xForm , OutputIndexedLevelSetVertexStream< Real , Dim > &stream ) : _stream(stream) , _positionXForm(xForm) { _gradientXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); } @@ -416,7 +402,7 @@ namespace PoissonRecon protected: // A reference to the underlying stream - OutputIndexedVertexStream< Real , Dim > &_stream; + OutputIndexedLevelSetVertexStream< Real , Dim > &_stream; // The affine transformation to be applied to the positions XForm< Real , Dim+1 > _positionXForm; @@ -430,10 +416,10 @@ namespace PoissonRecon // Transformed Indexed Vertex w/ Data Stream // /////////////////////////////////////////////// template< typename Real , unsigned int Dim , typename Data > - struct TransformedOutputIndexedVertexStream< Real , Dim , Data > : public OutputIndexedVertexStream< Real , Dim , Data > + struct TransformedOutputIndexedLevelSetVertexStream< Real , Dim , Data > : public OutputIndexedLevelSetVertexStream< Real , Dim , Data > { // A constructor initialized with the transformation to be applied to the samples, and a sample stream - TransformedOutputIndexedVertexStream( XForm< Real , Dim+1 > xForm , OutputIndexedVertexStream< Real , Dim , Data > &stream ) : _stream(stream) , _positionXForm(xForm) + TransformedOutputIndexedLevelSetVertexStream( XForm< Real , Dim+1 > xForm , OutputIndexedLevelSetVertexStream< Real , Dim , Data > &stream ) : _stream(stream) , _positionXForm(xForm) { _gradientXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); } @@ -449,7 +435,7 @@ namespace PoissonRecon protected: // A reference to the underlying stream - OutputIndexedVertexStream< Real , Dim , Data > &_stream; + OutputIndexedLevelSetVertexStream< Real , Dim , Data > &_stream; // The affine transformation to be applied to the positions XForm< Real , Dim+1 > _positionXForm; @@ -462,11 +448,11 @@ namespace PoissonRecon // A wrapper class to write out vertices // /////////////////////////////////////////// template< typename Vertex , typename Real , unsigned int Dim > - struct OutputVertexStreamWrapper< Vertex , Real , Dim > : public OutputVertexStream< Real , Dim > + struct OutputLevelSetVertexStreamWrapper< Vertex , Real , Dim > : public OutputLevelSetVertexStream< Real , Dim > { virtual Vertex toOutputVertex( const LevelSetVertex< Real , Dim > &in ) = 0; - OutputVertexStreamWrapper( OutputDataStream< Vertex > &stream ) : _stream(stream){} + OutputLevelSetVertexStreamWrapper( OutputDataStream< Vertex > &stream ) : _stream(stream){} void base_write( Position< Real , Dim > p , Normal< Real , Dim > g , Real w ) { @@ -493,11 +479,11 @@ namespace PoissonRecon }; template< typename Vertex , typename Real , unsigned int Dim , typename Data > - struct OutputVertexStreamWrapper< Vertex , Real , Dim , Data > : public OutputVertexStream< Real , Dim , Data > + struct OutputLevelSetVertexStreamWrapper< Vertex , Real , Dim , Data > : public OutputLevelSetVertexStream< Real , Dim , Data > { virtual Vertex toOutputVertex( const LevelSetVertex< Real , Dim , Data > &in ) = 0; - OutputVertexStreamWrapper( OutputDataStream< Vertex > &stream ) : _stream(stream){} + OutputLevelSetVertexStreamWrapper( OutputDataStream< Vertex > &stream ) : _stream(stream){} void base_write( Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ) { @@ -525,15 +511,15 @@ namespace PoissonRecon OutputDataStream< Vertex > &_stream; }; - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // A wrapper class to write out indexed vertices: OutputDataStream< IndexedVertex > -> OutputIndexedVertexStream< Real , Dim > // - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // A wrapper class to write out indexed vertices: OutputDataStream< IndexedVertex > -> OutputIndexedLevelSetVertexStream< Real , Dim > // + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template< typename Vertex , typename Real , unsigned int Dim > - struct OutputIndexedVertexStreamWrapper< Vertex , Real , Dim > : public OutputIndexedVertexStream< Real , Dim > + struct OutputIndexedLevelSetVertexStreamWrapper< Vertex , Real , Dim > : public OutputIndexedLevelSetVertexStream< Real , Dim > { virtual Vertex toOutputVertex( const LevelSetVertex< Real , Dim > &in ) = 0; - OutputIndexedVertexStreamWrapper( OutputDataStream< std::pair< node_index_type , Vertex > > &stream ) : _stream(stream){} + OutputIndexedLevelSetVertexStreamWrapper( OutputDataStream< std::pair< node_index_type , Vertex > > &stream ) : _stream(stream){} void base_write( node_index_type idx , Position< Real , Dim > p , Normal< Real , Dim > g , Real w ) { @@ -560,11 +546,11 @@ namespace PoissonRecon }; template< typename Vertex , typename Real , unsigned int Dim , typename Data > - struct OutputIndexedVertexStreamWrapper< Vertex , Real , Dim , Data > : public OutputIndexedVertexStream< Real , Dim , Data > + struct OutputIndexedLevelSetVertexStreamWrapper< Vertex , Real , Dim , Data > : public OutputIndexedLevelSetVertexStream< Real , Dim , Data > { virtual Vertex toOutputVertex( const LevelSetVertex< Real , Dim , Data > &in ) = 0; - OutputIndexedVertexStreamWrapper( OutputDataStream< std::pair< node_index_type , Vertex > > &stream ) : _stream(stream){} + OutputIndexedLevelSetVertexStreamWrapper( OutputDataStream< std::pair< node_index_type , Vertex > > &stream ) : _stream(stream){} void base_write( node_index_type idx , Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ) { @@ -833,7 +819,7 @@ namespace PoissonRecon }; template< typename Real , unsigned int Dim , bool HasGradients , bool HasDensity > - struct OutputVertexInfo< Real , Dim , HasGradients , HasDensity > + struct OutputLevelSetVertexInfo< Real , Dim , HasGradients , HasDensity > { using Factory = typename std::conditional @@ -856,10 +842,10 @@ namespace PoissonRecon static Factory GetFactory( void ){ return Factory(); } - struct StreamWrapper : public Reconstructor::OutputVertexStreamWrapper< Vertex , Real , Dim > + struct StreamWrapper : public Reconstructor::OutputLevelSetVertexStreamWrapper< Vertex , Real , Dim > { StreamWrapper( OutputDataStream< Vertex > &stream ) : - Reconstructor::OutputVertexStreamWrapper< Vertex , Real , Dim >( stream ){} + Reconstructor::OutputLevelSetVertexStreamWrapper< Vertex , Real , Dim >( stream ){} Vertex toOutputVertex( const Reconstructor::LevelSetVertex< Real , Dim > &in ) { @@ -884,7 +870,7 @@ namespace PoissonRecon }; template< typename Real , unsigned int Dim , bool HasGradients , bool HasDensity , typename AuxDataFactory > - struct OutputVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactory > + struct OutputLevelSetVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactory > { using Factory = typename std::conditional @@ -922,10 +908,10 @@ namespace PoissonRecon } } - struct StreamWrapper : public Reconstructor::OutputVertexStreamWrapper< Vertex , Real , Dim , AuxData > + struct StreamWrapper : public Reconstructor::OutputLevelSetVertexStreamWrapper< Vertex , Real , Dim , AuxData > { StreamWrapper( OutputDataStream< Vertex > &stream ) : - Reconstructor::OutputVertexStreamWrapper< Vertex , Real , Dim , AuxData >( stream ){} + Reconstructor::OutputLevelSetVertexStreamWrapper< Vertex , Real , Dim , AuxData >( stream ){} Vertex toOutputVertex( const Reconstructor::LevelSetVertex< Real , Dim , AuxData > &in ) { @@ -947,7 +933,7 @@ namespace PoissonRecon }; }; template< typename Real , unsigned int Dim , bool HasGradients , bool HasDensity > - struct OutputIndexedVertexInfo< Real , Dim , HasGradients , HasDensity > + struct OutputIndexedLevelSetVertexInfo< Real , Dim , HasGradients , HasDensity > { using Factory = typename std::conditional @@ -971,10 +957,10 @@ namespace PoissonRecon static Factory GetFactory( void ){ return Factory(); } - struct StreamWrapper : public Reconstructor::OutputIndexedVertexStreamWrapper< Vertex , Real , Dim > + struct StreamWrapper : public Reconstructor::OutputIndexedLevelSetVertexStreamWrapper< Vertex , Real , Dim > { StreamWrapper( OutputDataStream< IndexedVertex > &stream ) : - Reconstructor::OutputIndexedVertexStreamWrapper< Vertex , Real , Dim >( stream ){} + Reconstructor::OutputIndexedLevelSetVertexStreamWrapper< Vertex , Real , Dim >( stream ){} Vertex toOutputVertex( const Reconstructor::LevelSetVertex< Real , Dim > &in ) { @@ -999,7 +985,7 @@ namespace PoissonRecon }; template< typename Real , unsigned int Dim , bool HasGradients , bool HasDensity , typename AuxDataFactory > - struct OutputIndexedVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactory > + struct OutputIndexedLevelSetVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactory > { using Factory = typename std::conditional @@ -1038,10 +1024,10 @@ namespace PoissonRecon } } - struct StreamWrapper : public Reconstructor::OutputIndexedVertexStreamWrapper< Vertex , Real , Dim , AuxData > + struct StreamWrapper : public Reconstructor::OutputIndexedLevelSetVertexStreamWrapper< Vertex , Real , Dim , AuxData > { StreamWrapper( OutputDataStream< IndexedVertex > &stream ) : - Reconstructor::OutputIndexedVertexStreamWrapper< Vertex , Real , Dim , AuxData >( stream ){} + Reconstructor::OutputIndexedLevelSetVertexStreamWrapper< Vertex , Real , Dim , AuxData >( stream ){} Vertex toOutputVertex( const Reconstructor::LevelSetVertex< Real , Dim , AuxData > &in ) { diff --git a/Src/SSDRecon.cpp b/Src/SSDRecon.cpp index e21c17ca..baeb97f8 100644 --- a/Src/SSDRecon.cpp +++ b/Src/SSDRecon.cpp @@ -206,7 +206,7 @@ void WriteMesh ) { // A description of the output vertex information - using VInfo = Reconstructor::OutputIndexedVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactories ... >; + using VInfo = Reconstructor::OutputIndexedLevelSetVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactories ... >; // A factory generating the output vertices using Factory = typename VInfo::Factory; @@ -389,8 +389,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) typedef InputDataStream< SampleType > _InputPointStream; _InputPointStream &pointStream; SampleType scratch; - _InputSampleWithDataStream( _InputPointStream &pointStream , typename AuxDataFactory::VertexType zero ) - : Reconstructor::InputSampleStream< Real , Dim , typename AuxDataFactory::VertexType >( zero ) , pointStream( pointStream ) + _InputSampleWithDataStream( _InputPointStream &pointStream , typename AuxDataFactory::VertexType zero ) : pointStream( pointStream ) { scratch = SampleType( Reconstructor::Position< Real , Dim >() , DataType( Reconstructor::Normal< Real , Dim >() , zero ) ); } @@ -414,10 +413,10 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( Transform.set ) { Reconstructor::TransformedInputSampleStream< Real , Dim , _InputSampleWithDataStream , typename AuxDataFactory::VertexType > _sampleStream( toModel , sampleStream ); - implicit = new Reconstructor::SSD::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( _sampleStream , sParams ); + implicit = new Reconstructor::SSD::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( _sampleStream , sParams , auxDataFactory() ); implicit->unitCubeToModel = toModel.inverse() * implicit->unitCubeToModel; } - else implicit = new Reconstructor::SSD::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( sampleStream , sParams ); + else implicit = new Reconstructor::SSD::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( sampleStream , sParams , auxDataFactory() ); } else { From 88c61cbf771f4dc628999b18dbfd0214a95d6e42 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Tue, 24 Sep 2024 00:50:25 -0400 Subject: [PATCH 49/86] Version 18.10 --- Src/DataStream.h | 42 ++++++++++++++++++------------------- Src/NestedVector.h | 6 ++---- Src/PoissonRecon.client.inl | 10 +++++---- Src/PoissonRecon.cpp | 2 +- Src/SSDRecon.cpp | 2 +- 5 files changed, 31 insertions(+), 31 deletions(-) diff --git a/Src/DataStream.h b/Src/DataStream.h index 31730f23..3b52f092 100644 --- a/Src/DataStream.h +++ b/Src/DataStream.h @@ -166,28 +166,11 @@ namespace PoissonRecon template< typename Index , typename Data > struct IndexedInputDataStream : public InputDataStream< Data > { - IndexedInputDataStream( MultiInputDataStream< std::pair< Index , Data > > &multiStream , Data data ) : _multiStream( multiStream ) + IndexedInputDataStream( MultiInputDataStream< std::pair< Index , Data > > &multiStream ) : _multiStream( multiStream ) , _firstTime(true) { _nextValues.resize( multiStream.numStreams() ); - for( unsigned int i=0 ; i<_nextValues.size() ; i++ ) _nextValues[i].data.second = data; - for( unsigned int i=0 ; i<_nextValues.size() ; i++ ) - { - _nextValues[i].validData = _multiStream.read( i , _nextValues[i].data ); - _nextValues[i].streamIndex = i; - } - std::make_heap( _nextValues.begin() , _nextValues.end() , _NextValue::Compare ); - } - void reset( void ) - { - _multiStream.reset(); - for( unsigned int i=0 ; i<_nextValues.size() ; i++ ) - { - _nextValues[i].validData = _multiStream.read( i , _nextValues[i].data ); - _nextValues[i].streamIndex = i; - } - std::make_heap( _nextValues.begin() , _nextValues.end() , _NextValue::Compare ); } - + void reset( void ){ _multiStream.reset() , _firstTime = true; } protected: struct _NextValue @@ -207,10 +190,27 @@ namespace PoissonRecon MultiInputDataStream< std::pair< Index , Data > > &_multiStream; std::vector< _NextValue > _nextValues; + bool _firstTime; - bool base_read( unsigned int t , Data &d ){ return base_read(d); } - bool base_read( Data &d ) + void _init( const Data &data ) + { + for( unsigned int i=0 ; i<_nextValues.size() ; i++ ) _nextValues[i].data.second = data; + for( unsigned int i=0 ; i<_nextValues.size() ; i++ ) + { + _nextValues[i].validData = _multiStream.read( i , _nextValues[i].data ); + _nextValues[i].streamIndex = i; + } + std::make_heap( _nextValues.begin() , _nextValues.end() , _NextValue::Compare ); + } + + bool base_read( unsigned int t , Data &d ) + { + ERROR_OUT( "Multi-threaded read not supported" ); + return false; + } + bool base_read( Data &d ) { + if( _firstTime ) _init(d) , _firstTime = false; std::pop_heap( _nextValues.begin() , _nextValues.end() , _NextValue::Compare ); _NextValue &next = _nextValues.back(); if( !next.validData ) return false; diff --git a/Src/NestedVector.h b/Src/NestedVector.h index 0e72a5f2..7022a80a 100644 --- a/Src/NestedVector.h +++ b/Src/NestedVector.h @@ -265,8 +265,7 @@ namespace PoissonRecon void write( BinaryStream &stream ) const { - size_t sz = _size; - stream.write( sz ); + stream.write( size() ); for( size_t i=0 ; i<_size ; i++ ) _data[i]->write( stream ); } @@ -282,8 +281,7 @@ namespace PoissonRecon { const size_t serializedSize = serializer.size(); - size_t sz = _size; - stream.write( sz ); + stream.write( size() ); for( size_t i=0 ; i<_size ; i++ ) _data[i]->write( stream , serializer ); } void read( BinaryStream &stream , const Serializer< T > &serializer ) diff --git a/Src/PoissonRecon.client.inl b/Src/PoissonRecon.client.inl index e2e4362e..7eb8520f 100644 --- a/Src/PoissonRecon.client.inl +++ b/Src/PoissonRecon.client.inl @@ -1251,14 +1251,14 @@ void Client< Real , Dim , BType , Degree >::_writeMeshWithData( const ClientReco // A description of the output vertex information - using VInfo = Reconstructor::OutputLevelSetVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactory >; + using VInfo = Reconstructor::OutputIndexedLevelSetVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactory >; // A factory generating the output vertices using Factory = typename VInfo::Factory; Factory factory = VInfo::GetFactory( auxDataFactory ); // A backing stream for the vertices - Reconstructor::OutputInputFactoryTypeStream< Factory , false > vertexStream( factory , false ); + Reconstructor::OutputInputFactoryTypeStream< Factory , true > vertexStream( factory , false ); Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( false , true ); typename LevelSetExtractor< Real , Dim , AuxData >::Stats stats; @@ -1268,7 +1268,7 @@ void Client< Real , Dim , BType , Degree >::_writeMeshWithData( const ClientReco typename VInfo::StreamWrapper _vertexStream( vertexStream ); // The transformed stream - Reconstructor::TransformedOutputLevelSetVertexStream< Real , Dim , AuxData > __vertexStream( unitCubeToModel , _vertexStream ); + Reconstructor::TransformedOutputIndexedLevelSetVertexStream< Real , Dim , AuxData > __vertexStream( unitCubeToModel , _vertexStream ); // Extract the mesh stats = LevelSetExtractor< Real , Dim , AuxData >::template Extract< Reconstructor::WeightDegree , DataSig > @@ -1307,7 +1307,9 @@ void Client< Real , Dim , BType , Degree >::_writeMeshWithData( const ClientReco // Write the mesh to a .ply file std::vector< std::string > noComments; - PLY::Write< Factory , node_index_type , Real , Dim >( outFileName.c_str() , factory , vertexStream.size() , faceStream.size() , vertexStream , faceStream , PLY_BINARY_NATIVE , noComments ); + vertexStream.reset(); + IndexedInputDataStream< node_index_type , typename Factory::VertexType > vStream( vertexStream ); + PLY::Write< Factory , node_index_type , Real , Dim >( outFileName.c_str() , factory , vertexStream.size() , faceStream.size() , vStream , faceStream , PLY_BINARY_NATIVE , noComments ); } template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index df424d56..32629c0b 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -234,7 +234,7 @@ void WriteMesh // Write the mesh to a .ply file std::vector< std::string > noComments; vertexStream.reset(); - IndexedInputDataStream< node_index_type , typename Factory::VertexType > vStream( vertexStream , factory() ); + IndexedInputDataStream< node_index_type , typename Factory::VertexType > vStream( vertexStream ); PLY::Write< Factory , node_index_type , Real , Dim >( fileName , factory , vertexStream.size() , faceStream.size() , vStream , faceStream , ascii ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); } diff --git a/Src/SSDRecon.cpp b/Src/SSDRecon.cpp index baeb97f8..be55e4bb 100644 --- a/Src/SSDRecon.cpp +++ b/Src/SSDRecon.cpp @@ -227,7 +227,7 @@ void WriteMesh // Write the mesh to a .ply file std::vector< std::string > noComments; vertexStream.reset(); - IndexedInputDataStream< node_index_type , typename Factory::VertexType > vStream( vertexStream , factory() ); + IndexedInputDataStream< node_index_type , typename Factory::VertexType > vStream( vertexStream ); PLY::Write< Factory , node_index_type , Real , Dim >( fileName , factory , vertexStream.size() , faceStream.size() , vStream , faceStream , ascii ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); } From 56b05b5d2fbaa94d963b2d26e4d300139539bfd7 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Wed, 25 Sep 2024 00:16:27 -0400 Subject: [PATCH 50/86] Version 18.20 --- Src/MyAtomic.h | 42 ------------------------------- Src/Reconstruction.example.cpp | 46 +++++++++++++++++++++++++--------- Src/Reconstructors.h | 45 ++++++++++++++++++++++++++++++++- Src/Reconstructors.streams.h | 32 ++++++++++++++++++++--- 4 files changed, 106 insertions(+), 59 deletions(-) diff --git a/Src/MyAtomic.h b/Src/MyAtomic.h index 49036ce1..070c7916 100644 --- a/Src/MyAtomic.h +++ b/Src/MyAtomic.h @@ -240,72 +240,48 @@ namespace PoissonRecon template< typename Value > void AddAtomic8_( volatile Value *a , Value b ) { -#ifdef SANITIZED_PR Value current = ReadAtomic8_( a ); -#else // !SANITIZED_PR - Value current = *a; -#endif // SANITIZED_PR Value sum = current+b; #if defined( _WIN32 ) || defined( _WIN64 ) char *_current = (char *)¤t; char *_sum = (char *)∑ -#ifdef SANITIZED_PR while( InterlockedCompareExchange( (char*)a , *_sum , *_current )!=*_current ) { current = ReadAtomic8_( a ); sum = current + b; } -#else // !SANITIZED_PR - while( InterlockedCompareExchange( (char*)a , *_sum , *_current )!=*_current ) current = *(Value*)a , sum = *(Value*)a+b; -#endif // SANITIZED_PR #else // !_WIN32 && !_WIN64 uint8_t *_current = (uint8_t *)¤t; uint8_t *_sum = (uint8_t *)∑ -#ifdef SANITIZED_PR while( __sync_val_compare_and_swap( (uint8_t *)a , *_current , *_sum )!=*_current ) { current = ReadAtomic8_( a ); sum = current+b; } -#else // !SANITIZED_PR - while( __sync_val_compare_and_swap( (uint8_t *)a , *_current , *_sum )!=*_current ) current = *(Value*)a , sum = *(Value*)a+b; -#endif // SANITIZED_PR #endif // _WIN32 || _WIN64 } template< typename Value > void AddAtomic32_( volatile Value *a , Value b ) { -#ifdef SANITIZED_PR Value current = ReadAtomic32_( a ); -#else // !SANITIZED_PR - Value current = *a; -#endif // SANITIZED_PR Value sum = current+b; #if defined( _WIN32 ) || defined( _WIN64 ) long *_current = (long *)¤t; long *_sum = (long *)∑ -#ifdef SANITIZED_PR while( InterlockedCompareExchange( (long*)a , *_sum , *_current )!=*_current ) { current = ReadAtomic32_( a ); sum = current + b; } -#else // !SANITIZED_PR - while( InterlockedCompareExchange( (long*)a , *_sum , *_current )!=*_current ) current = *(Value*)a , sum = *(Value*)a+b; -#endif // SANITIZED_PR #else // !_WIN32 && !_WIN64 uint32_t *_current = (uint32_t *)¤t; uint32_t *_sum = (uint32_t *)∑ -#ifdef SANITIZED_PR while( __sync_val_compare_and_swap( (uint32_t *)a , *_current , *_sum )!=*_current ) { current = ReadAtomic32_( a ); sum = current+b; } -#else // !SANITIZED_PR - while( __sync_val_compare_and_swap( (uint32_t *)a , *_current , *_sum )!=*_current ) current = *(Value*)a , sum = *(Value*)a+b; -#endif // SANITIZED_PR #endif // _WIN32 || _WIN64 } @@ -313,7 +289,6 @@ namespace PoissonRecon void AddAtomic64_( volatile Value * a , Value b ) { #if 1 -#ifdef SANITIZED_PR Value current = ReadAtomic64_( a ); Value sum = current+b; while( !SetAtomic64_( a , sum , current ) ) @@ -321,42 +296,25 @@ namespace PoissonRecon current = ReadAtomic64_( a ); sum = current+b; } -#else // !SANITIZED_PR - Value current = *a; - Value sum = current+b; - while( !SetAtomic64_( a , sum , current ) ) current = *(Value*)a , sum = *(Value*)a+b; -#endif // SANITIZED_PR #else -#ifdef SANITIZED_PR Value current = ReadAtomic64_( a ); -#else // !SANITIZED_PR - Value current = a; -#endif // SANITIZED_PR Value sum = current+b; #if defined( _WIN32 ) || defined( _WIN64 ) __int64 *_current = (__int64 *)¤t; __int64 *_sum = (__int64 *)∑ -#ifdef SANITIZED_PR while( InterlockedCompareExchange64( (__int64*)a , *_sum , *_current )!=*_current ) { current = ReadAtomic64_( a ); sum = current+b; } -#else // !SANITIZED_PR - while( InterlockedCompareExchange64( (__int64*)a , *_sum , *_current )!=*_current ) current = *(Value*)a , sum = a+b; -#endif // SANITIZED_PR #else // !_WIN32 && !_WIN64 uint64_t *_current = (uint64_t *)¤t; uint64_t *_sum = (uint64_t *)∑ -#ifdef SANITIZED_PR while( __sync_val_compare_and_swap( (uint64_t *)a , *_current , *_sum )!=*_current ) { current = ReadAtomic64_( a); sum = current+b; } -#else // !SANITIZED_PR - while( __sync_val_compare_and_swap( (uint64_t *)a , *_current , *_sum )!=*_current ) current = *(Value*)a , sum = a+b; -#endif // SANITIZED_PR #endif // _WIN32 || _WIN64 #endif } diff --git a/Src/Reconstruction.example.cpp b/Src/Reconstruction.example.cpp index d489071b..626e27f5 100644 --- a/Src/Reconstruction.example.cpp +++ b/Src/Reconstruction.example.cpp @@ -41,10 +41,10 @@ DAMAGE. using namespace PoissonRecon; CmdLineParameter< char* > Out( "out" ); -CmdLineReadable SSDReconstruction( "ssd" ) , UseColor( "color" ) , Verbose( "verbose" ); +CmdLineReadable SSDReconstruction( "ssd" ) , UseColor( "color" ) , EvaluateImplicit( "evaluate" ) , Verbose( "verbose" ); CmdLineParameter< int > Depth( "depth" , 8 ) , SampleNum( "samples" , 100000 ); -CmdLineReadable* params[] = { &Out , &SSDReconstruction , &UseColor , &Verbose , &Depth , &SampleNum , nullptr }; +CmdLineReadable* params[] = { &Out , &SSDReconstruction , &UseColor , &Verbose , &Depth , &SampleNum , &EvaluateImplicit , nullptr }; void ShowUsage( char* ex ) { @@ -54,6 +54,7 @@ void ShowUsage( char* ex ) printf( "\t[--%s =%d]\n" , Depth.name , Depth.value ); printf( "\t[--%s]\n" , UseColor.name ); printf( "\t[--%s]\n" , SSDReconstruction.name ); + printf( "\t[--%s]\n" , EvaluateImplicit.name ); printf( "\t[--%s]\n" , Verbose.name ); } @@ -188,8 +189,7 @@ struct VertexStream : public Reconstructor::OutputLevelSetVertexStream< Real , D VertexStream( std::vector< Real > &vCoordinates ) : _vCoordinates( vCoordinates ) {} // Override the pure abstract method from Reconstructor::OutputLevelSetVertexStream< Real , Dim > - void base_write( Point< Real , Dim > p , Point< Real , Dim > , Real ){ for( unsigned int d=0 ; d p , Point< Real , Dim > g , Real r ){ return base_write( p , g , r ); } + void base_write( Point< Real , Dim > p , Point< Real , Dim > , Real ){ for( unsigned int d=0 ; d &_vCoordinates; }; @@ -210,7 +210,6 @@ struct VertexWithColorStream : public Reconstructor::OutputLevelSetVertexStream< _rgbCoordinates.push_back( c.g ); _rgbCoordinates.push_back( c.b ); } - void base_write( unsigned int , Point< Real , Dim > p , Point< Real , Dim > g , Real r , RGBColor< Real > c ){ return base_write( p , g , r , c ); } protected: std::vector< Real > &_vCoordinates; std::vector< Real > &_rgbCoordinates; @@ -268,11 +267,30 @@ void Execute( void ) extractionParams.linearFit = SSDReconstruction.set; // Since the SSD solution approximates a TSDF, linear fitting works well extractionParams.verbose = Verbose.set; + // The type of the reconstructor + using Implicit = std::conditional_t< UseColor , typename ReconType::template Implicit< Real , Dim , FEMSig , RGBColor< Real > > , typename ReconType::template Implicit< Real , Dim , FEMSig > >; + + // Functionality for evaluating at a single point + auto _Evaluate = []( typename Implicit::Evaluator &evaluator , Point< double , Dim > p ) + { + try{ std::cout << "\tValue/Gradient @ " << p << ": " << evaluator(p) << " / " << evaluator.grad(p) << std::endl; } + catch( typename Implicit::Evaluator::OutOfUnitCubeException &e ){ std::cout << e.what() << std::endl; } + }; + + // Functionality for evaluating at interior/exterior/boundary points + auto Evaluate = [&_Evaluate]( const Implicit &implicit ) + { + typename Implicit::Evaluator evaluator = implicit.evaluator(); + std::cout << "Evaluating interior:" << std::endl; + _Evaluate( evaluator , Point< Real , Dim >( (Real)0.0 , (Real)0.0 , (Real)0.0 ) ); + std::cout << "Evaluating exterior: " << std::endl; + _Evaluate( evaluator , Point< Real , Dim >( (Real)1.0 , (Real)1.0 , (Real)1.0 ) ); + std::cout << "Evaluating boundary: " << std::endl; + _Evaluate( evaluator , Point< Real , Dim >( (Real)1.0 , (Real)1.0 , (Real)1.0 )/(Real)sqrt(3.) ); + }; + if constexpr( UseColor ) { - // The type of the reconstructor - using Implicit = typename ReconType::template Implicit< Real , Dim , FEMSig , RGBColor< Real > >; - // A stream generating random points on the sphere with color SphereSampleWithColorStream< Real , Dim > sampleStream( SampleNum.value ); @@ -282,7 +300,6 @@ void Execute( void ) // Scale the color information to give extrapolation preference to data at finer depths implicit.weightAuxDataByDepth( (Real)32. ); - // vectors for storing the polygons (specifically, triangles), the coordinates of the vertices, and the colors at the vertices std::vector< std::vector< int > > polygons; std::vector< Real > vCoordinates , rgbCoordinates; @@ -294,13 +311,14 @@ void Execute( void ) // Extract the iso-surface implicit.extractLevelSet( vStream , pStream , extractionParams ); + // Write out the level-set if( Out.set ) WritePly( Out.value , vStream.size() , vCoordinates.data() , rgbCoordinates.data() , polygons ); + + // Evaluate the implicit function + if( EvaluateImplicit.set ) Evaluate(implicit); } else { - // The type of the reconstructor - using Implicit = typename ReconType::template Implicit< Real , Dim , FEMSig >; - // A stream generating random points on the sphere SphereSampleStream< Real , Dim > sampleStream( SampleNum.value ); @@ -318,7 +336,11 @@ void Execute( void ) // Extract the iso-surface implicit.extractLevelSet( vStream , pStream , extractionParams ); + // Write out the level-set if( Out.set ) WritePly( Out.value , vStream.size() , vCoordinates.data() , (Real*)nullptr , polygons ); + + // Evaluate the implicit function + if( EvaluateImplicit.set ) Evaluate(implicit); } } diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h index 8eb833bb..9ea4cf42 100644 --- a/Src/Reconstructors.h +++ b/Src/Reconstructors.h @@ -106,6 +106,49 @@ namespace PoissonRecon typedef unsigned char AuxData; _ExtractLevelSet< false , true , Real , Dim , FEMSig , AuxData , OutputIndexedLevelSetVertexStream< Real , Dim > , Implicit< Real , Dim , FEMSig > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); } + + struct Evaluator + { + struct OutOfUnitCubeException : public std::exception + { + OutOfUnitCubeException( Point< Real , Dim > world , Point< Real , Dim > cube ) + { + std::stringstream sStream; + sStream << "Out-of-unit-cube input: " << world << " -> " << cube; + _message = sStream.str(); + } + const char * what( void ) const noexcept { return _message.c_str(); } + protected: + std::string _message; + }; + + Evaluator( const FEMTree< Dim , Real > *tree , const DenseNodeData< Real , Sigs > &coefficients , XForm< Real , Dim+1 > worldToUnitCube ) + : _evaluator( tree , coefficients , ThreadPool::NumThreads() ) , _xForm(worldToUnitCube) { _gxForm = XForm< Real , Dim >(_xForm).transpose(); } + + Point< Real , Dim > grad( unsigned int t , Point< Real , Dim > p ) + { + CumulativeDerivativeValues< Real , Dim , 1 > v = _values( t , p ); + Point< Real , Dim > g; + for( unsigned int d=0 ; d p ){ return _values(t,p)[0]; } + + Real operator()( Point< Real , Dim > p ){ return operator()( 0 , p ); } + Point< Real , Dim > grad( Point< Real , Dim > p ){ return grad( 0 , p ); } + protected: + CumulativeDerivativeValues< Real , Dim , 1 > _values( unsigned int t , Point< Real , Dim > p ) + { + Point< Real , Dim > q = _xForm * p; + for( unsigned int d=0 ; d1 ) throw OutOfUnitCubeException(p,q); + return _evaluator.values( q , t ); + } + + typename FEMTree< Dim , Real >::template MultiThreadedEvaluator< Sigs , 1 > _evaluator; + XForm< Real , Dim+1 > _xForm; + XForm< Real , Dim > _gxForm; + }; + Evaluator evaluator( void ) const { return Evaluator( &tree , solution , unitCubeToModel.inverse() ); } }; // Specialized solution information with auxiliary data @@ -261,7 +304,7 @@ namespace PoissonRecon SolutionParameters( void ) : verbose(false) , dirichletErode(false) , outputDensity(false) , exactInterpolation(false) , showResidual(false) , scale((Real)1.1) , confidence((Real)0.) , confidenceBias((Real)0.) , lowDepthCutOff((Real)0.) , width((Real)0.) , - pointWeight((Real)0.) , valueInterpolationWeight((Real)0.) , samplesPerNode((Real)1.5) , cgSolverAccuracy((Real)1e-3 ) , targetValue((Real)0.) , + pointWeight((Real)( WeightMultiplier * DefaultFEMDegree ) ) , valueInterpolationWeight((Real)0.) , samplesPerNode((Real)1.5) , cgSolverAccuracy((Real)1e-3 ) , targetValue((Real)0.5) , depth((unsigned int)8) , solveDepth((unsigned int)-1) , baseDepth((unsigned int)-1) , fullDepth((unsigned int)5) , kernelDepth((unsigned int)-1) , envelopeDepth((unsigned int)-1) , baseVCycles((unsigned int)1) , iters((unsigned int)8) , alignDir(0) {} diff --git a/Src/Reconstructors.streams.h b/Src/Reconstructors.streams.h index 541650ce..a1bde6bc 100644 --- a/Src/Reconstructors.streams.h +++ b/Src/Reconstructors.streams.h @@ -265,9 +265,15 @@ namespace PoissonRecon // Functionality to insert the next vertex virtual void base_write( Position< Real , Dim > p , Gradient< Real , Dim > g , Real w ) = 0; - virtual void base_write( unsigned int thread , Position< Real , Dim > p , Gradient< Real , Dim > g , Real w ) = 0; + virtual void base_write( unsigned int thread , Position< Real , Dim > p , Gradient< Real , Dim > g , Real w ) + { + std::lock_guard< std::mutex > guard(_insertionMutex); + base_write( p , g , w ); + } void base_write( const LevelSetVertex< Real , Dim > &v ){ base_write( v.template get<0>() , v.template get<1>() , v.template get<2>() ); } void base_write( unsigned int thread , const LevelSetVertex< Real , Dim > &v ){ base_write( thread , v.template get<0>() , v.template get<1>() , v.template get<2>() ); } + protected: + std::mutex _insertionMutex; }; /////////////////////////// @@ -281,7 +287,11 @@ namespace PoissonRecon // Functionality to insert the next vertex virtual void base_write( node_index_type idx , Position< Real , Dim > p , Gradient< Real , Dim > g , Real w ) = 0; - virtual void base_write( unsigned int thread , node_index_type idx , Position< Real , Dim > p , Gradient< Real , Dim > g , Real w ) = 0; + virtual void base_write( unsigned int thread , node_index_type idx , Position< Real , Dim > p , Gradient< Real , Dim > g , Real w ) + { + std::lock_guard< std::mutex > guard(_insertionMutex); + base_write( idx , p , g , w ); + } void base_write( const LevelSetIndexedVertex< Real , Dim > &v ) { base_write( v.first , v.second.template get<0>() , v.second.template get<1>() , v.second.template get<2>() ); @@ -290,6 +300,8 @@ namespace PoissonRecon { base_write( thread , v.first , v.second.template get<0>() , v.second.template get<1>() , v.second.template get<2>() ); } + protected: + std::mutex _insertionMutex; }; /////////////////////////// @@ -303,9 +315,15 @@ namespace PoissonRecon // Functionality to insert the next vertex virtual void base_write( Position< Real , Dim > p , Gradient< Real , Dim > g , Real w , Data d ) = 0; - virtual void base_write( unsigned int thread , Position< Real , Dim > p , Gradient< Real , Dim > g , Real w , Data d ) = 0; + virtual void base_write( unsigned int thread , Position< Real , Dim > p , Gradient< Real , Dim > g , Real w , Data d ) + { + std::lock_guard< std::mutex > guard( _insertionMutex ); + base_write( p , g , w , d ); + } void base_write( const LevelSetVertex< Real , Dim , Data > &v ){ return base_write( v.template get<0>() , v.template get<1>() , v.template get<2>() , v.template get<3>() ); } void base_write( unsigned int thread , const LevelSetVertex< Real , Dim , Data > &v ){ return base_write( thread , v.template get<0>() , v.template get<1>() , v.template get<2>() , v.template get<3>() ); } + protected: + std::mutex _insertionMutex; }; /////////////////////////////////// @@ -319,9 +337,15 @@ namespace PoissonRecon // Functionality to insert the next vertex virtual void base_write( node_index_type idx , Position< Real , Dim > p , Gradient< Real , Dim > g , Real w , Data d ) = 0; - virtual void base_write( unsigned int thread , node_index_type idx , Position< Real , Dim > p , Gradient< Real , Dim > g , Real w , Data d ) = 0; + virtual void base_write( unsigned int thread , node_index_type idx , Position< Real , Dim > p , Gradient< Real , Dim > g , Real w , Data d ) + { + std::lock_guard< std::mutex > guard( _insertionMutex ); + base_write( idx , p , g , w , d ); + } void base_write( const LevelSetIndexedVertex< Real , Dim , Data > &v ){ return base_write( v.first , v.second.template get<0>() , v.second.template get<1>() , v.second.template get<2>() , v.second.template get<3>() ); } void base_write( unsigned int thread , const LevelSetIndexedVertex< Real , Dim , Data > &v ){ return base_write( thread , v.first , v.second.template get<0>() , v.second.template get<1>() , v.second.template get<2>() , v.second.template get<3>() ); } + protected: + std::mutex _insertionMutex; }; /////////////////////////////// From 5b774d26a1fa38c0bfc70f4bb7ac972088e3567a Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Wed, 25 Sep 2024 00:22:54 -0400 Subject: [PATCH 51/86] Version 18.20 --- README.md | 43 +++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index cb331ed7..8b7e987b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

      Adaptive Multigrid Solvers (Version 18.10)

      +

      Adaptive Multigrid Solvers (Version 18.20)

      links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
      Executables: -Win64
      +Win64
      Source Code: -ZIP GitHub
      +ZIP GitHub
      Older Versions: +V18.10, V18.05, V18.04, V18.03, @@ -1030,22 +1031,33 @@ This method writes the information for the next vertx into the stream. The data The reconstructed surface is then computed in two steps:
      • Poisson::Implicit< Real , Dim , FEMSig >::Implicit( InputSampleStream< Real , Dim > &sStream , SolutionParameters< Real > sParams ):
        -This constructor creates a Poisson reconstruction object from an input sample stream (sStream) and a description of the reconstruction parameters (sParams) desribing the depth, number of samples per node, etc. (Reconstructors.h, line 229). This object derives from Implicit< Real , Dim , FEMSig >. +This constructor creates a Poisson reconstruction object from an input sample stream (sStream) and a description of the reconstruction parameters (sParams) desribing the depth, number of samples per node, etc. (Reconstructors.h, line 340). This object derives from Implicit< Real , Dim , FEMSig >.
      • void Implicit< Real , Dim , FEMSig >::extractLevelSet( OutputVertexStream< Real , Dim > &vStream , &pStream , LevelSetExtractionParameters meParams ):
        -This member function takes references to the output vertex and polygon streams (vStream and pStream) and parameters for level-set extraction (meParams) and computes the extracted triangle/polygon mesh, writing its vertices and faces into the corresponding output streams as they are generated (Reconstructors.h, line 98). +This member function takes references to the output vertex and polygon streams (vStream and pStream) and parameters for level-set extraction (meParams) and computes the extracted triangle/polygon mesh, writing its vertices and faces into the corresponding output streams as they are generated (Reconstructors.h, line 99). +
      +In Addition, the code supports evaluation of the implicit function at points within the bounding cube: +
        +
      • Poisson::Implicit::evaluator( void ):
        +This member function returns an object of type Implicit::Evaluator. (Note that as the Implicit::Evaluator object stores const references to the state in the Poisson::Implicit object, it will not be valid once the defining Poisson::Implicit object goes out of scope.) +
      • Real Implicit::Evaluator::operator()( Point< Real , Dim > ):
        +This member function returns the value of the implicit function at the prescribed point. The point is assumed to be given in world coordinates, and a Implicit::Evaluator::OutOfUnitCubeException is thrown if it is outside of the unit-cube containing the input samples. +
      • Point< Real , Dim > Implicit::Evaluator::grad( Point< Real , Dim > ):
        +This member function returns the gradient of the implicit function at the prescribed point. The point is assumed to be given in world coordinates, and a Implicit::Evaluator::OutOfUnitCubeException is thrown if it is outside of the unit-cube containing the input samples.
      Code walk-through:
        These steps can be found in the Reconstruction.example.cpp code.
          -
        • The finite-elements signature is created in line 254. -
        • An input sample stream generating a specified number of random points on the surface of the sphere is defined in lines 78-115 and constructed in line 301. -
        • An output polygon stream that pushes the polygon to an std::vector of std::vector< int >s is defined in lines 164-179 and constructed in line 311. -
        • An output vertex stream that pushes just the position information to an std::vector of Reals is desfined in lines 182-192 and constructed in line 312. -
        • The reconstructor is constructed in line 304. -
        • The level-set extraction is performed on line 315. +
        • The finite-elements signature is created in line 257. +
        • An input sample stream generating a specified number of random points on the surface of the sphere is defined in lines 81-119 and constructed in line 324. +
        • An output polygon stream that pushes the polygon to an std::vector of std::vector< int >s is defined in lines 167-182 and constructed in line 333. +
        • An output vertex stream that pushes just the position information to an std::vector of Reals is desfined in lines 185-195 and constructed in line 334. +
        • The reconstructor is constructed in line 326. +
        • The level-set extraction is performed on line 337. +
        • The evaluator is created on line 283. +
        • The evaluator is used to query the values and gradients of the implicit function in line 276.
        -Note that a similar approach can be used to perform the Smoothed Signed Distance reconstruction (line 302). The approach also supports reconstruction of meshes with auxiliary information like color (lines 263-295), with the only constraint that the auxiliary data type supports the computation affine combinations (e.g. the RGBColor type defined in lines 60-75). +Note that a similar approach can be used to perform the Smoothed Signed Distance reconstruction (lines 370 and 371). The approach also supports reconstruction of meshes with auxiliary information like color (lines 292-319), with the only constraint that the auxiliary data type supports the computation affine combinations (e.g. the RGBColor type defined in lines 63-78).
    @@ -1601,6 +1613,13 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • Removed mutual exclusion in the iso-surfacing phase. +Version 18.20: +
      +
    1. Added an interface for evaluating the implicit function's values and gradients at points inside the bounding cube. +
    2. Added a --evaluate flag to the Reconstructor.example executable that evaluates the implicit function at an interior/exterior/boundary point on the sphere. +
    3. Changed defaults for PoissonReconstruction to use value interpolation and to evaluate to 0.5 at the input samples. +
    +
    From 19a8cbd3db47a9a62e248f14f9e35b952083487d Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Sat, 5 Oct 2024 23:55:20 -0400 Subject: [PATCH 52/86] Version 18.20 --- AdaptiveSolvers.sln | 2 + PoissonReconClient.vcxproj | 2 +- PoissonReconServer.vcxproj | 2 +- Src/AdaptiveTreeVisualization.cpp | 18 +- Src/DataStream.h | 342 +++++++---- Src/DataStream.imp.h | 203 ++++--- Src/DataStream.imp.inl | 14 +- Src/DataStream.inl | 433 ++++++++++++++ Src/Extrapolator.h | 227 ++++++++ Src/FEMTree.Initialize.inl | 21 +- Src/FEMTree.LevelSet.2D.inl | 91 +-- Src/FEMTree.LevelSet.3D.inl | 153 +++-- Src/FEMTree.h | 12 +- Src/FEMTree.inl | 52 +- Src/Geometry.h | 34 +- Src/PointExtent.h | 10 +- Src/PointExtent.inl | 22 +- Src/PointInterpolant.cpp | 76 ++- Src/PointPartition.h | 5 +- Src/PointPartition.inl | 9 +- Src/PointPartitionClientServer.inl | 2 +- Src/PoissonRecon.client.inl | 57 +- Src/PoissonRecon.cpp | 124 ++-- Src/PoissonRecon.server.inl | 22 +- Src/PoissonReconClientServer.inl | 6 +- Src/PreProcessor.h | 2 +- Src/Reconstruction.example.cpp | 142 ++++- Src/Reconstructors.h | 177 +++--- Src/Reconstructors.streams.h | 884 ++++++----------------------- Src/SSDRecon.cpp | 133 +++-- Src/SurfaceTrimmer.cpp | 2 +- Src/VertexFactory.h | 4 +- 32 files changed, 1907 insertions(+), 1376 deletions(-) create mode 100644 Src/DataStream.inl create mode 100644 Src/Extrapolator.h diff --git a/AdaptiveSolvers.sln b/AdaptiveSolvers.sln index d6db1f3c..4fafb677 100644 --- a/AdaptiveSolvers.sln +++ b/AdaptiveSolvers.sln @@ -51,6 +51,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Header Files", "Header File Src\CmdLineParser.h = Src\CmdLineParser.h Src\DataStream.h = Src\DataStream.h Src\DataStream.imp.h = Src\DataStream.imp.h + Src\Extrapolator.h = Src\Extrapolator.h Src\Factor.h = Src\Factor.h Src\FEMTree.h = Src\FEMTree.h Src\Geometry.h = Src\Geometry.h @@ -93,6 +94,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Inline Files", "Inline File Src\BSplineData.inl = Src\BSplineData.inl Src\CmdLineParser.inl = Src\CmdLineParser.inl Src\DataStream.imp.inl = Src\DataStream.imp.inl + Src\DataStream.inl = Src\DataStream.inl Src\FEMTree.Evaluation.inl = Src\FEMTree.Evaluation.inl Src\FEMTree.Initialize.inl = Src\FEMTree.Initialize.inl Src\FEMTree.inl = Src\FEMTree.inl diff --git a/PoissonReconClient.vcxproj b/PoissonReconClient.vcxproj index c6d784d7..889821a3 100644 --- a/PoissonReconClient.vcxproj +++ b/PoissonReconClient.vcxproj @@ -96,7 +96,7 @@ true true NOMINMAX;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - false + true pch.h AdvancedVectorExtensions2 true diff --git a/PoissonReconServer.vcxproj b/PoissonReconServer.vcxproj index 6a704575..8a152146 100644 --- a/PoissonReconServer.vcxproj +++ b/PoissonReconServer.vcxproj @@ -96,7 +96,7 @@ true true NOMINMAX;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - false + true pch.h AdvancedVectorExtensions2 true diff --git a/Src/AdaptiveTreeVisualization.cpp b/Src/AdaptiveTreeVisualization.cpp index 92653cc4..f37a7f63 100644 --- a/Src/AdaptiveTreeVisualization.cpp +++ b/Src/AdaptiveTreeVisualization.cpp @@ -398,25 +398,19 @@ void _Execute( const FEMTree< Dim , Real > *tree , XForm< Real , Dim+1 > modelTo double t = Time(); // A description of the output vertex information - using VInfo = Reconstructor::OutputLevelSetVertexInfo< Real , Dim , false , false >; + using VInfo = Reconstructor::OutputVertexInfo< Real , Dim , false , false >; // A factory generating the output vertices using Factory = typename VInfo::Factory; Factory factory = VInfo::GetFactory(); // A backing stream for the vertices - Reconstructor::OutputInputFactoryTypeStream< Factory , false > vertexStream( factory , false ); - Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( false , true ); + Reconstructor::OutputInputFactoryTypeStream< Real , Dim , Factory , false , true > vertexStream( factory , VInfo::Convert ); + Reconstructor::OutputInputFaceStream< Dim-1 , false , true > faceStream; - { - // The wrapper converting native to output types - typename VInfo::StreamWrapper _vertexStream( vertexStream ); - Reconstructor::TransformedOutputLevelSetVertexStream< Real , Dim > __vertexStream( modelToUnitCube.inverse() , _vertexStream ); - - // Extract the mesh - if constexpr( Dim==3 ) LevelSetExtractor< Real , Dim >::Extract( IsotropicUIntPack< Dim , FEMSig >() , UIntPack< 0 >() , *tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , coefficients , IsoValue.value , IsoSlabDepth.value , IsoSlabStart.value , IsoSlabEnd.value , __vertexStream , faceStream , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , FlipOrientation.set ); - else if constexpr( Dim==2 ) LevelSetExtractor< Real , Dim >::Extract( IsotropicUIntPack< Dim , FEMSig >() , UIntPack< 0 >() , *tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , coefficients , IsoValue.value , __vertexStream , faceStream , NonLinearFit.set , false , FlipOrientation.set ); - } + // Extract the mesh + if constexpr( Dim==3 ) LevelSetExtractor< Real , Dim >::Extract( IsotropicUIntPack< Dim , FEMSig >() , UIntPack< 0 >() , *tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , coefficients , IsoValue.value , IsoSlabDepth.value , IsoSlabStart.value , IsoSlabEnd.value , vertexStream , faceStream , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , FlipOrientation.set ); + else if constexpr( Dim==2 ) LevelSetExtractor< Real , Dim >::Extract( IsotropicUIntPack< Dim , FEMSig >() , UIntPack< 0 >() , *tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , coefficients , IsoValue.value , vertexStream , faceStream , NonLinearFit.set , false , FlipOrientation.set ); if( Verbose.set ) printf( "Got level-set: %.2f(s)\n" , Time()-t ); if( Verbose.set ) printf( "Vertices / Faces: %llu / %llu\n" , (unsigned long long)vertexStream.size() , (unsigned long long)faceStream.size() ); diff --git a/Src/DataStream.h b/Src/DataStream.h index 3b52f092..8506a7ea 100644 --- a/Src/DataStream.h +++ b/Src/DataStream.h @@ -32,195 +32,295 @@ DAMAGE. #include #include #include +#include "Geometry.h" namespace PoissonRecon { + // The input/output stream types + template< typename ... Data > struct InputDataStream; + template< typename ... Data > struct OutputDataStream; + + // Input/output streams, internally represented by an std::vector< Input/OutputDataStream< Data ... > > + template< typename ... Data > struct MultiInputDataStream; + template< typename ... Data > struct MultiOutputDataStream; + + // Class for de-interleaving output + template< typename ... Data > using OutputIndexedDataStream = OutputDataStream< size_t , Data ... >; + template< typename ... Data > using MultiOutputIndexedDataStream = MultiOutputDataStream< size_t , Data ... >; + template< typename ... Data > struct DeInterleavedMultiOutputIndexedDataStream; + + // Classes for re-interleaving input + template< typename ... Data > using InputIndexedDataStream = InputDataStream< size_t , Data ... >; + template< typename ... Data > using MultiInputIndexedDataStream = MultiInputDataStream< size_t , Data ... >; + template< typename ... Data > struct InterleavedMultiInputIndexedDataStream; + + // Classes for converting one stream type to another + template< typename IDataTuple , typename XDataTuple > struct InputDataStreamConverter; + template< typename IDataTuple , typename XDataTuple > struct OutputDataStreamConverter; + + template< typename ... Data > + struct TupleConverter + { + static void FromTuple( const std::tuple< Data ... > &dTuple , Data& ... d ); + static void ToTuple( std::tuple< Data ... > &dTuple , const Data& ... d ); + protected: + template< unsigned int I , typename _Data , typename ... _Datas > + static void _FromTuple( const std::tuple< Data ... > &dTuple , _Data &d , _Datas& ... ds ); + template< unsigned int I , typename _Data , typename ... _Datas > + static void _ToTuple( std::tuple< Data ... > &dTuple , const _Data &d , const _Datas& ... ds ); + }; - // Pre-declare so we can make friends - template< typename Data > struct MultiInputDataStream; - template< typename Data > struct MultiOutputDataStream; + template< typename Real , typename ... Data > + struct DirectSumConverter + { + static void FromDirectSum( const DirectSum< Real , Data ... > &dSum , Data& ... d ); + static void ToDirectSum( DirectSum< Real , Data ... > &dSum , const Data& ... d ); + protected: + template< unsigned int I , typename _Data , typename ... _Datas > + static void _FromDirectSum( const DirectSum &dSum , _Data &d , _Datas& ... ds ); + template< unsigned int I , typename _Data , typename ... _Datas > + static void _ToDirectSum( DirectSum< Real , Data ... > &dSum , const _Data &d , const _Datas& ... ds ); + }; - //////////////////////////////////////// - // Abstract input/output data streams // - //////////////////////////////////////// + //////////////////////// + // Input data streams // + //////////////////////// // An input stream containing "Data" types // Supporting: // -- Resetting the stream to the start // -- Trying to read the next element from the stream - template< typename Data > + template< typename ... Data > struct InputDataStream { - friend struct MultiInputDataStream< Data >; + friend struct MultiInputDataStream< Data... >; virtual ~InputDataStream( void ){} // Reset to the start of the stream virtual void reset( void ) = 0; - bool read( Data &d ){ return base_read(d); } - bool read( unsigned int thread , Data &d ){ return base_read(thread,d); } + // Read the next datum from the stream + virtual bool read( Data& ... d ) = 0; + virtual bool read( unsigned int thread , Data& ... d ); + + bool read( std::tuple< Data ... > &data ); + bool read( unsigned int thread , std::tuple< Data ... > &data ); + + template< typename Real > + bool read( DirectSum< Real , Data ... > &data ); + template< typename Real > + bool read( unsigned int thread , DirectSum< Real , Data ... > &data ); protected: std::mutex _insertionMutex; - // Read in data in a single-threaded context - virtual bool base_read( Data &d ) = 0; - - // Read in data in a multi-threaded context - virtual bool base_read( unsigned int thread , Data &d ) - { - std::lock_guard< std::mutex > lock( _insertionMutex ); - return base_read(d); - } + template< typename ... _Data > + bool _read( std::tuple< Data ... > &data , _Data& ... _data ); + template< typename ... _Data > + bool _read( unsigned int thread , std::tuple< Data ... > &data , _Data& ... _data ); + template< typename Real , typename ... _Data > + bool _read( DirectSum< Real , Data ... > &data , _Data& ... _data ); + template< typename Real , typename ... _Data > + bool _read( unsigned int thread , DirectSum< Real , Data ... > &data , _Data& ... _data ); }; + + ///////////////////////// + // Output data streams // + ///////////////////////// + // // An output stream containing "Data" types // Supporting: // -- Writing the next element to the stream - // -- Writing the next element to the stream by a particular thread - template< typename Data > + // -- Pushing the next element to the stream (and getting the count of elements pushed so far) + template< typename ... Data > struct OutputDataStream { - friend struct MultiOutputDataStream< Data >; + friend struct MultiOutputDataStream< Data ... >; - OutputDataStream( void ) : _size(0) {} + OutputDataStream( void ){} virtual ~OutputDataStream( void ){} - // Returns the number of items written to the stream - size_t size( void ) const { return _size; } + virtual size_t size( void ) const = 0; - void write( const Data &d ){ base_write(d) ; _size++; } - void write( unsigned int thread , const Data &d ){ base_write( thread , d ) ; _size++; } + virtual size_t write( const Data& ... d ) = 0; + virtual size_t write( unsigned int thread , const Data& ... d ); + + size_t write( const std::tuple< Data ... > &data ); + size_t write( unsigned int thread , const std::tuple< Data ... > &data ); + + template< typename Real > size_t write( const DirectSum< Real , Data ... > &data ); + template< typename Real > size_t write( unsigned int thread , const DirectSum< Real , Data ... > &data ); protected: std::mutex _insertionMutex; - std::atomic< size_t > _size; - // Write out data in a single-threaded context - virtual void base_write( const Data &d ) = 0; - // Write out data in a multi-threaded context - virtual void base_write( unsigned int thread , const Data &d ) - { - std::lock_guard< std::mutex > lock( _insertionMutex ); - return base_write(d); - } + template< typename ... _Data > size_t _write( const std::tuple< Data ... > &data , const _Data& ... _data ); + template< typename ... _Data > size_t _write( unsigned int thread , const std::tuple< Data ... > &data , const _Data& ... _data ); + template< typename Real , typename ... _Data > size_t _write( const DirectSum< Real , Data ... > &data , const _Data& ... _data ); + template< typename Real , typename ... _Data > size_t _write( unsigned int thread , const DirectSum< Real , Data ... > &data , const _Data& ... _data ); }; - ////////////////////////////////////////// - // Multi-streams for multi-threaded I/O // - ////////////////////////////////////////// - template< typename Data > - struct MultiInputDataStream : public InputDataStream< Data > + //////////////////////////////// + // Multiple input data stream // + //////////////////////////////// + template< typename ...Data > + struct MultiInputDataStream : public InputDataStream< Data ... > { - MultiInputDataStream( InputDataStream< Data > **streams , size_t N ) : _current(0) , _streams( streams , streams+N ) {} - MultiInputDataStream( const std::vector< InputDataStream< Data > * > &streams ) : _current(0) , _streams( streams ) {} - void reset( void ){ for( unsigned int i=0 ; i<_streams.size() ; i++ ) _streams[i]->reset(); } - unsigned int numStreams( void ) const { return (unsigned int)_streams.size(); } + using InputDataStream< Data ... >::read; + + MultiInputDataStream( InputDataStream< Data ... > **streams , size_t N ); + MultiInputDataStream( const std::vector< InputDataStream< Data ... > * > &streams ); + + void reset( void ); + + unsigned int numStreams( void ) const; + + bool read( unsigned int t , Data& ... d ); + bool read( Data& ... d ); protected: - std::vector< InputDataStream< Data > * > _streams; + std::vector< InputDataStream< Data ... > * > _streams; unsigned int _current; - MultiInputDataStream( void ) {} - void _init( InputDataStream< Data > **streams , size_t N ) - { - _streams.resize( N ); - for( unsigned int i=0 ; i * > &streams ){ _streams = streams; } - bool base_read( unsigned int t , Data &d ){ return _streams[t]->base_read(d); } - bool base_read( Data &d ) - { - while( _current<_streams.size() ) - { - if( _streams[_current]->read( d ) ) return true; - else _current++; - } - return false; - } + MultiInputDataStream( void ); + void _init( InputDataStream< Data ... > **streams , size_t N ); + void _init( const std::vector< InputDataStream< Data ... > * > &streams ); }; - template< typename Data > - struct MultiOutputDataStream : public OutputDataStream< Data > + + ///////////////////////////////// + // Multiple output data stream // + ///////////////////////////////// + template< typename ... Data > + struct MultiOutputDataStream : public OutputDataStream< Data ... > { - MultiOutputDataStream( OutputDataStream< Data > **streams , size_t N ) : _streams( streams , streams+N ) {} - MultiOutputDataStream( const std::vector< OutputDataStream< Data > * > &streams ) : _streams( streams ) {} - unsigned int numStreams( void ) const { return (unsigned int)_streams.size(); } + using OutputDataStream< Data ... >::write; + + MultiOutputDataStream( OutputDataStream< Data ... > **streams , size_t N ); + MultiOutputDataStream( const std::vector< OutputDataStream< Data ... > * > &streams ); + + unsigned int numStreams( void ) const; + + size_t size( void ) const { return _size; } + + size_t write( const Data& ... d ); + size_t write( unsigned int t , const Data& ... d ); protected: - std::vector< OutputDataStream< Data > * > _streams; + std::vector< OutputDataStream< Data ... > * > _streams; + std::atomic< size_t > _size; - MultiOutputDataStream( void ) {} - void _init( OutputDataStream< Data > **streams , size_t N ) - { - _streams.resize( N ); - for( unsigned int i=0 ; i * > &streams ){ _streams = streams; } - void base_write( const Data &d ){ _streams[0]->base_write(d); } - void base_write( unsigned int t , const Data &d ){ _streams[t]->base_write(d); } + MultiOutputDataStream( void ); + void _init( OutputDataStream< Data ... > **streams , size_t N ); + void _init( const std::vector< OutputDataStream< Data ... > * > &streams ); }; - template< typename Index , typename Data > - struct IndexedInputDataStream : public InputDataStream< Data > + ///////////////////////////////// + // Input data stream converter // + ///////////////////////////////// + template< typename ... IData , typename ... XData > + struct InputDataStreamConverter< std::tuple< IData ... > , std::tuple< XData ... > > : public InputDataStream< XData ... > { - IndexedInputDataStream( MultiInputDataStream< std::pair< Index , Data > > &multiStream ) : _multiStream( multiStream ) , _firstTime(true) - { - _nextValues.resize( multiStream.numStreams() ); - } - void reset( void ){ _multiStream.reset() , _firstTime = true; } + using InputDataStream< XData ... >::read; + + InputDataStreamConverter( InputDataStream< IData ... > &stream , std::function< std::tuple< XData ... > ( const std::tuple< IData ... >& ) > converter , IData ... zero ); + void reset( void ); + bool read( XData& ... xData ); + bool read( unsigned int thread , XData& ... xData ); protected: + InputDataStream< IData ... > &_stream; + std::function< std::tuple< XData ... > ( const std::tuple< IData ... >& ) > _converter; + std::tuple< IData ... > _iZero; + }; + + ////////////////////////////////// + // Output data stream converter // + ////////////////////////////////// + template< typename ... IData , typename ... XData > + struct OutputDataStreamConverter< std::tuple< IData ... > , std::tuple< XData ... > > : public OutputDataStream< XData ... > + { + using OutputDataStream< XData ... >::write; + + OutputDataStreamConverter( OutputDataStream< IData ... > &stream , std::function< std::tuple< IData ... > ( const std::tuple< XData ... >& ) > converter ); + + size_t size( void ) const { return _stream.size(); } + + size_t write( const XData& ... xData ); + size_t write( unsigned int thread , const XData& ... xData ); + protected: + OutputDataStream< IData ... > &_stream; + std::function< std::tuple< IData ... > ( const std::tuple< XData ... >& ) > _converter; + }; + + + //////////////////////////////////////////////// + // De-interleaved multiple output data stream // + //////////////////////////////////////////////// + template< typename ... Data > + struct DeInterleavedMultiOutputIndexedDataStream : public OutputDataStream< Data ... > + { + using OutputDataStream< Data ... >::write; + + DeInterleavedMultiOutputIndexedDataStream( OutputIndexedDataStream< Data ... > **streams , size_t N ); + DeInterleavedMultiOutputIndexedDataStream( const std::vector< OutputIndexedDataStream< Data ... > * > &streams ); + + unsigned int numStreams( void ) const; + + size_t size( void ) const { return _size; } + + size_t write( const Data& ... d ); + size_t write( unsigned int thread , const Data& ... d ); + + protected: + MultiOutputIndexedDataStream< Data ... > _multiStream; + std::atomic< size_t > _size; + + DeInterleavedMultiOutputIndexedDataStream( void ); + void _init( OutputIndexedDataStream< Data ... > **streams , size_t N ); + void _init( const std::vector< OutputIndexedDataStream< Data ... > * > &streams ); + }; + + + //////////////////////////////////////////// + // Interleaved multiple input data stream // + //////////////////////////////////////////// + + template< typename ... Data > + struct InterleavedMultiInputIndexedDataStream : public InputDataStream< Data ... > + { + using InputDataStream< Data... >::read; + + InterleavedMultiInputIndexedDataStream( InputIndexedDataStream< Data ... > **streams , size_t N ); + InterleavedMultiInputIndexedDataStream( const std::vector< InputIndexedDataStream< Data ... > * > &streams ); + void reset( void ); + bool read( Data& ... d ); + + protected: + +#ifdef DEBUG_STREAM + size_t _current = 0; +#endif // DEBUG_STREAM struct _NextValue { - std::pair< Index , Data > data; + std::tuple< size_t , Data ... > data; unsigned int streamIndex; bool validData; // Returns true if v1>v2 so that it's a min-heap - static bool Compare( const _NextValue &v1 , const _NextValue &v2 ) - { - if( !v2.validData ) return false; - else if( !v1.validData && v2.validData ) return true; - else return v1.data.first>v2.data.first; - }; + static bool Compare( const _NextValue &v1 , const _NextValue &v2 ); }; - MultiInputDataStream< std::pair< Index , Data > > &_multiStream; + MultiInputIndexedDataStream< Data... > _multiStream; std::vector< _NextValue > _nextValues; bool _firstTime; - void _init( const Data &data ) - { - for( unsigned int i=0 ; i<_nextValues.size() ; i++ ) _nextValues[i].data.second = data; - for( unsigned int i=0 ; i<_nextValues.size() ; i++ ) - { - _nextValues[i].validData = _multiStream.read( i , _nextValues[i].data ); - _nextValues[i].streamIndex = i; - } - std::make_heap( _nextValues.begin() , _nextValues.end() , _NextValue::Compare ); - } - - bool base_read( unsigned int t , Data &d ) - { - ERROR_OUT( "Multi-threaded read not supported" ); - return false; - } - bool base_read( Data &d ) - { - if( _firstTime ) _init(d) , _firstTime = false; - std::pop_heap( _nextValues.begin() , _nextValues.end() , _NextValue::Compare ); - _NextValue &next = _nextValues.back(); - if( !next.validData ) return false; - d = next.data.second; - next.validData = _multiStream.read( next.streamIndex , next.data ); - - std::push_heap( _nextValues.begin() , _nextValues.end() , _NextValue::Compare ); - return true; - } + void _init( const std::tuple< Data ... > &data ); }; +#include "DataStream.inl" } #endif // DATA_STREAM_INCLUDED diff --git a/Src/DataStream.imp.h b/Src/DataStream.imp.h index 3e209077..4279758c 100644 --- a/Src/DataStream.imp.h +++ b/Src/DataStream.imp.h @@ -45,24 +45,62 @@ namespace PoissonRecon VectorBackedInputDataStream( const std::vector< Data > &data ) : _data(data) , _current(0) {} void reset( void ) { _current = 0; } + bool read( Data &d ){ if( _current<_data.size() ){ d = _data[_current++] ; return true; } else return false; } + protected: const std::vector< Data > &_data; size_t _current; + }; + + template< typename Data > + struct VectorBackedInputIndexedDataStream : public InputIndexedDataStream< Data > + { + VectorBackedInputIndexedDataStream( const std::vector< std::pair< size_t , Data > > &data ) : _data(data) , _current(0) {} + void reset( void ) { _current = 0; } + + bool read( size_t &idx , Data &d ) + { + if( _current<_data.size() ) + { + idx = _data[_current].first; + d = _data[_current].second; + _current++; + return true; + } + else return false; + } - bool base_read( Data &d ){ if( _current<_data.size() ){ d = _data[_current++] ; return true; } else return false; } + protected: + const std::vector< std::pair< size_t , Data > > &_data; + size_t _current; }; template< typename Data > struct VectorBackedOutputDataStream : public OutputDataStream< Data > { VectorBackedOutputDataStream( std::vector< Data > &data ) : _data(data) {} - + size_t write( const Data &d ){ size_t idx = _data.size() ; _data.push_back(d) ; return idx; } + size_t size( void ) const { return _data.size(); } protected: std::vector< Data > &_data; + }; - void base_write( const Data &d ){ _data.push_back(d); } + template< typename Data > + struct VectorBackedOutputIndexedDataStream : public OutputIndexedDataStream< Data > + { + VectorBackedOutputIndexedDataStream( std::vector< std::pair< size_t , Data > > &data ) : _data(data) {} + size_t write( const size_t &idx , const Data &d ) + { + size_t sz = _data.size(); + _data.push_back( std::make_pair( idx , d ) ); + return idx; + } + size_t size( void ) const { return _data.size(); } + protected: + std::vector< std::pair< size_t , Data > > &_data; }; + //////////////////////////////////////////////////////////////////// // File-backed data stream (assumes Data is statically allocated) // //////////////////////////////////////////////////////////////////// @@ -72,11 +110,10 @@ namespace PoissonRecon // It is assumed that the file pointer was open for binary reading FileBackedInputDataStream( FILE *fp ) : _fp(fp) {} void reset( void ){ fseek( _fp , 0 , SEEK_SET ); } + bool read( Data &d ){ return fread( &d , sizeof(Data) , 1 , _fp )==1; } protected: FILE *_fp; - - bool base_read( Data &d ){ return fread( &d , sizeof(Data) , 1 , _fp )==1; } }; template< typename Data > @@ -84,11 +121,12 @@ namespace PoissonRecon { // It is assumed that the file pointer was open for binary writing FileBackedOutputDataStream( FILE *fp ) : _fp(fp) {} + size_t write( const Data &d ){ fwrite( &d , sizeof(Data) , 1 , _fp ) ; return _sz++; } + size_t size( void ) const { return _sz; } protected: + size_t _sz = 0; FILE *_fp; - - void base_write( const Data &d ){ fwrite( &d , sizeof(Data) , 1 , _fp ); } }; ///////////////////////////////////////////////////////////////////////////////////////////// @@ -100,11 +138,7 @@ namespace PoissonRecon // It is assumed that the file pointer was open for binary reading FileBackedInputDataStream( FILE *fp ) : _fp(fp) {} void reset( void ){ fseek( _fp , 0 , SEEK_SET ); } - - protected: - FILE *_fp; - - bool base_read( std::vector< Data > &d ) + bool read( std::vector< Data > &d ) { unsigned int pSize; if( fread( &pSize , sizeof(unsigned int) , 1 , _fp )==1 ) @@ -116,6 +150,9 @@ namespace PoissonRecon } else return false; } + + protected: + FILE *_fp; }; template< typename Data > @@ -123,93 +160,123 @@ namespace PoissonRecon { // It is assumed that the file pointer was open for binary writing FileBackedOutputDataStream( FILE *fp ) : _fp(fp) {} - - - protected: - FILE *_fp; - - void base_write( const std::vector< Data > &d ) + size_t write( const std::vector< Data > &d ) { unsigned int pSize = (unsigned int)d.size(); fwrite( &pSize , sizeof(unsigned int) , 1 , _fp ); fwrite( &d[0] , sizeof(Data) , pSize , _fp ); + return _sz++; } + size_t size( void ) const { return _sz; } + + protected: + size_t _sz = 0; + FILE *_fp; }; //////////////////////////////////////////////////////// // File-backed stream with data desribed by a factory // //////////////////////////////////////////////////////// - template< typename Factory , bool ParallelStream , typename Index=size_t > - struct FileBackedInputFactoryTypeStream : public InputDataStream< std::conditional_t< ParallelStream , std::pair< Index , typename Factory::VertexType > , typename Factory::VertexType > > + template< typename Factory > + struct FileBackedInputFactoryTypeStream : public InputDataStream< typename Factory::VertexType > { - using Data = std::conditional_t< ParallelStream , std::pair< Index , typename Factory::VertexType > , typename Factory::VertexType >; + using Data = typename Factory::VertexType; // It is assumed that the file pointer was open for binary reading FileBackedInputFactoryTypeStream( FILE *fp , const Factory &factory ) : _fp(fp) , _factory(factory) , _buffer( NewPointer< char >( _factory.bufferSize() ) ) , _bufferSize( _factory.bufferSize() ) {} ~FileBackedInputFactoryTypeStream( void ){ DeletePointer( _buffer ); } void reset( void ){ fseek( _fp , 0 , SEEK_SET ); } + bool read( Data &d ) + { + if( fread( _buffer , sizeof(unsigned char) , _bufferSize , _fp )==_bufferSize ) + { + _factory.fromBuffer( _buffer , d ); + return true; + } + else return false; + return _sz++; + } protected: + size_t _sz = 0; FILE *_fp; const Factory _factory; Pointer( char ) _buffer; const size_t _bufferSize; + }; - bool base_read( Data &d ) + template< typename Factory > + struct FileBackedInputIndexedFactoryTypeStream : public InputIndexedDataStream< typename Factory::VertexType > + { + using Data = typename Factory::VertexType; + // It is assumed that the file pointer was open for binary reading + FileBackedInputIndexedFactoryTypeStream( FILE *fp , const Factory &factory ) : _fp(fp) , _factory(factory) , _buffer( NewPointer< char >( _factory.bufferSize() ) ) , _bufferSize( _factory.bufferSize() ) {} + ~FileBackedInputIndexedFactoryTypeStream( void ){ DeletePointer( _buffer ); } + void reset( void ){ fseek( _fp , 0 , SEEK_SET ); } + bool read( size_t &idx , Data &d ) { - if constexpr( ParallelStream ) - { - if( fread( &d.first , sizeof(Index) , 1 , _fp )!=1 ) return false; - if( fread( _buffer , sizeof(unsigned char) , _bufferSize , _fp )==_bufferSize ) - { - _factory.fromBuffer( _buffer , d.second ); - return true; - } - else return false; - } - else + if( fread( &idx , sizeof(size_t) , 1 , _fp )!=1 ) return false; + if( fread( _buffer , sizeof(unsigned char) , _bufferSize , _fp )==_bufferSize ) { - if( fread( _buffer , sizeof(unsigned char) , _bufferSize , _fp )==_bufferSize ) - { - _factory.fromBuffer( _buffer , d ); - return true; - } - else return false; + _factory.fromBuffer( _buffer , d ); + return true; } + else return false; + return _sz++; } + + protected: + size_t _sz = 0; + FILE *_fp; + const Factory _factory; + Pointer( char ) _buffer; + const size_t _bufferSize; }; - template< typename Factory , bool ParallelStream , typename Index=size_t > - struct FileBackedOutputFactoryTypeStream : public OutputDataStream< std::conditional_t< ParallelStream , std::pair< Index , typename Factory::VertexType > , typename Factory::VertexType > > + template< typename Factory > + struct FileBackedOutputFactoryTypeStream : public OutputDataStream< typename Factory::VertexType > { - using Data = std::conditional_t< ParallelStream , std::pair< Index , typename Factory::VertexType > , typename Factory::VertexType >; - + using Data = typename Factory::VertexType; // It is assumed that the file pointer was open for binary reading FileBackedOutputFactoryTypeStream( FILE *fp , const Factory &factory ) : _fp(fp) , _factory(factory) , _buffer( NewPointer< char >( _factory.bufferSize() ) ) , _bufferSize( _factory.bufferSize() ) {} ~FileBackedOutputFactoryTypeStream( void ){ DeletePointer( _buffer ); } - + size_t write( const Data &d ) + { + _factory.toBuffer( d , _buffer ); + fwrite( _buffer , sizeof(unsigned char) , _bufferSize , _fp ); + return _sz++; + } + size_t size( void ) const { return _sz; } protected: + size_t _sz = 0; FILE *_fp; const Factory _factory; Pointer( char ) _buffer; const size_t _bufferSize; + }; - void base_write( const Data &d ) + template< typename Factory > + struct FileBackedOutputIndexedFactoryTypeStream : public OutputIndexedDataStream< typename Factory::VertexType > + { + using Data = typename Factory::VertexType; + // It is assumed that the file pointer was open for binary reading + FileBackedOutputIndexedFactoryTypeStream( FILE *fp , const Factory &factory ) : _fp(fp) , _factory(factory) , _buffer( NewPointer< char >( _factory.bufferSize() ) ) , _bufferSize( _factory.bufferSize() ) {} + ~FileBackedOutputIndexedFactoryTypeStream( void ){ DeletePointer( _buffer ); } + size_t write( const size_t &idx , const Data &d ) { - if constexpr( ParallelStream ) - { - fwrite( &d.first , sizeof(Index) , 1 , _fp ); - _factory.toBuffer( d.second , _buffer ); - fwrite( _buffer , sizeof(unsigned char) , _bufferSize , _fp ); - } - else - { - _factory.toBuffer( d , _buffer ); - fwrite( _buffer , sizeof(unsigned char) , _bufferSize , _fp ); - } + fwrite( &idx , sizeof(size_t) , 1 , _fp ); + _factory.toBuffer( d , _buffer ); + fwrite( _buffer , sizeof(unsigned char) , _bufferSize , _fp ); + return _sz++; } + size_t size( void ) const { return _sz; } + protected: + size_t _sz = 0; + FILE *_fp; + const Factory _factory; + Pointer( char ) _buffer; + const size_t _bufferSize; }; - /////////////////////////////////////////////////////////////////////////////////// // File-backed data streams, with functionality for reading/writing from/to disk // /////////////////////////////////////////////////////////////////////////////////// @@ -222,12 +289,11 @@ namespace PoissonRecon ASCIIInputDataStream( const char* fileName , const Factory &factory ); ~ASCIIInputDataStream( void ); void reset( void ); + bool read( Data &d ); protected: const Factory _factory; FILE *_fp; - - bool base_read( Data &d ); }; template< typename Factory > @@ -237,12 +303,13 @@ namespace PoissonRecon ASCIIOutputDataStream( const char* fileName , const Factory &factory ); ~ASCIIOutputDataStream( void ); + size_t write( const Data &d ); + size_t size( void ) const { return _sz; } protected: + size_t _sz = 0; const Factory _factory; FILE *_fp; - - void base_write( const Data &d ); }; template< typename Factory > @@ -253,12 +320,11 @@ namespace PoissonRecon BinaryInputDataStream( const char* filename , const Factory &factory ); ~BinaryInputDataStream( void ){ fclose( _fp ) , _fp=NULL; } void reset( void ); + bool read( Data &d ); protected: const Factory _factory; FILE* _fp; - - bool base_read( Data &d ); }; template< typename Factory > @@ -269,12 +335,13 @@ namespace PoissonRecon BinaryOutputDataStream( const char* filename , const Factory &factory ); ~BinaryOutputDataStream( void ){ fclose( _fp ) , _fp=NULL; } void reset( void ){ fseek( _fp , 0 , SEEK_SET ); } + size_t write( const Data &d ); + size_t size( void ) const { return _sz; } protected: + size_t _sz = 0; const Factory _factory; FILE* _fp; - - void base_write( const Data &d ); }; //////////////////////////////////////////// @@ -290,6 +357,7 @@ namespace PoissonRecon PLYInputDataStream( const char* fileName , const Factory &factory , size_t &count ); ~PLYInputDataStream( void ); void reset( void ); + bool read( Data &d ); protected: const Factory _factory; @@ -300,7 +368,6 @@ namespace PoissonRecon size_t _pCount , _pIdx; void _free( void ); - bool base_read( Data &d ); }; template< typename Factory > @@ -310,14 +377,14 @@ namespace PoissonRecon PLYOutputDataStream( const char* fileName , const Factory &factory , size_t count , int fileType=PLY_BINARY_NATIVE ); ~PLYOutputDataStream( void ); + size_t write( const Data &d ); + size_t size( void ) const { return _pIdx; } protected: const Factory _factory; PlyFile *_ply; size_t _pCount , _pIdx; Pointer( char ) _buffer; - - void base_write( const Data &d ); }; #include "DataStream.imp.inl" diff --git a/Src/DataStream.imp.inl b/Src/DataStream.imp.inl index e4fc1d14..080affa0 100644 --- a/Src/DataStream.imp.inl +++ b/Src/DataStream.imp.inl @@ -47,7 +47,7 @@ template< typename Factory > void ASCIIInputDataStream< Factory >::reset( void ) { fseek( _fp , 0 , SEEK_SET ); } template< typename Factory > -bool ASCIIInputDataStream< Factory >::base_read( Data &d ){ return _factory.readASCII( _fp , d ); } +bool ASCIIInputDataStream< Factory >::read( Data &d ){ return _factory.readASCII( _fp , d ); } /////////////////////////// // ASCIIOutputDataStream // @@ -67,7 +67,7 @@ ASCIIOutputDataStream< Factory >::~ASCIIOutputDataStream( void ) } template< typename Factory > -void ASCIIOutputDataStream< Factory >::base_write( const Data &d ){ _factory.writeASCII( _fp , d ); } +size_t ASCIIOutputDataStream< Factory >::write( const Data &d ){ _factory.writeASCII( _fp , d ) ; return _sz++; } /////////////////////////// // BinaryInputDataStream // @@ -83,7 +83,7 @@ template< typename Factory > void BinaryInputDataStream< Factory >::reset( void ) { fseek( _fp , 0 , SEEK_SET ); } template< typename Factory > -bool BinaryInputDataStream< Factory >::base_read( Data &d ){ return _factory.readBinary( _fp , d ); } +bool BinaryInputDataStream< Factory >::read( Data &d ){ return _factory.readBinary( _fp , d ); } //////////////////////////// // BinaryOutputDataStream // @@ -96,7 +96,7 @@ BinaryOutputDataStream< Factory >::BinaryOutputDataStream( const char* fileName } template< typename Factory > -void BinaryOutputDataStream< Factory >::base_write( const Data &d ){ return _factory.writeBinary( _fp , d ); } +size_t BinaryOutputDataStream< Factory >::write( const Data &d ){ _factory.writeBinary( _fp , d ); return _sz++; } //////////////////////// // PLYInputDataStream // @@ -174,7 +174,7 @@ PLYInputDataStream< Factory >::~PLYInputDataStream( void ) } template< typename Factory > -bool PLYInputDataStream< Factory >::base_read( Data &d ) +bool PLYInputDataStream< Factory >::read( Data &d ) { if( _pIdx<_pCount ) { @@ -224,7 +224,7 @@ PLYOutputDataStream< Factory >::~PLYOutputDataStream( void ) } template< typename Factory > -void PLYOutputDataStream< Factory >::base_write( const Data &d ) +size_t PLYOutputDataStream< Factory >::write( const Data &d ) { if( _pIdx==_pCount ) ERROR_OUT( "Trying to add more points than total: " , _pIdx , " < " , _pCount ); if( _factory.isStaticallyAllocated() ) _ply->put_element( (void *)&d ); @@ -233,6 +233,6 @@ void PLYOutputDataStream< Factory >::base_write( const Data &d ) _factory.toBuffer( d , _buffer ); _ply->put_element( PointerAddress( _buffer ) ); } - _pIdx++; + return _pIdx++; } diff --git a/Src/DataStream.inl b/Src/DataStream.inl new file mode 100644 index 00000000..b4a042f2 --- /dev/null +++ b/Src/DataStream.inl @@ -0,0 +1,433 @@ +/* +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. +*/ + +///////////////////////////// +// Variadic <-> std::tuple // +///////////////////////////// +template< typename ... Data > +void TupleConverter< Data ... >::FromTuple( const std::tuple< Data ... > &dTuple , Data& ... d ){ return _FromTuple< 0 >( dTuple , d... ); } +template< typename ... Data > +void TupleConverter< Data ... >::ToTuple( std::tuple< Data ... > &dTuple , const Data& ... d ){ return _ToTuple< 0 >( dTuple , d... ); } + +template< typename ... Data > +template< unsigned int I , typename _Data , typename ... _Datas > +void TupleConverter< Data ... >::_FromTuple( const std::tuple< Data ... > &dTuple , _Data &d , _Datas& ... ds ) +{ + d = std::get< I >( dTuple ); + if constexpr( sizeof...(_Datas) ) _FromTuple< I+1 >( dTuple , ds... ); +} + +template< typename ... Data > +template< unsigned int I , typename _Data , typename ... _Datas > +void TupleConverter< Data ... >::_ToTuple( std::tuple< Data ... > &dTuple , const _Data &d , const _Datas& ... ds ) +{ + std::get< I >( dTuple ) = d; + if constexpr( sizeof...(_Datas) ) _ToTuple< I+1 >( dTuple , ds... ); +} + +//////////////////////////// +// Variadic <-> DirectSum // +//////////////////////////// +template< typename Real , typename ... Data > +void DirectSumConverter< Real , Data ... >::FromDirectSum( const DirectSum< Real , Data ... > &dSum , Data& ... d ){ return _FromDirectSum< 0 >( dSum , d... ); } + +template< typename Real , typename ... Data > +void DirectSumConverter< Real , Data ... >::ToDirectSum( DirectSum< Real , Data ... > &dSum , const Data& ... d ){ return _ToDirectSum< 0 >( dSum , d... ); } + +template< typename Real , typename ... Data > +template< unsigned int I , typename _Data , typename ... _Datas > +void DirectSumConverter< Real , Data ... >::_FromDirectSum( const DirectSum< Real , Data ... > &dSum , _Data &d , _Datas& ... ds ) +{ + d = dSum.template get(); + if constexpr( sizeof...(_Datas) ) _FromDirectSum< I+1 >( dSum , ds... ); +} + +template< typename Real , typename ... Data > +template< unsigned int I , typename _Data , typename ... _Datas > +void DirectSumConverter< Real , Data ... >::_ToDirectSum( DirectSum< Real , Data ... > &dSum , const _Data &d , const _Datas& ... ds ) +{ + dSum.template get() + d; + if constexpr( sizeof...(_Datas) ) _ToDirectSum< I+1 >( dSum , ds... ); +} + +//////////////////////// +// Input data streams // +//////////////////////// +template< typename ... Data > +bool InputDataStream< Data ... >::read( unsigned int thread , Data& ... d ) +{ +#ifdef SHOW_WARNINGS + WARN_ONCE( "Serializing read: " , typeid(*this).name() ); +#endif // SHOW_WARNINGS + std::lock_guard< std::mutex > lock( _insertionMutex ); + return read(d...); +} + +template< typename ... Data > +bool InputDataStream< Data ... >::read( std::tuple< Data ... > &data ){ return _read( data ); } + +template< typename ... Data > +bool InputDataStream< Data ... >::read( unsigned int thread , std::tuple< Data ... > &data ){ return _read( thread , data ); } + +template< typename ... Data > +template< typename Real > +bool InputDataStream< Data ... >::read( DirectSum< Real , Data ... > &data ){ return _read( data ); } + +template< typename ... Data > +template< typename Real > +bool InputDataStream< Data ... >::read( unsigned int thread , DirectSum< Real , Data ... > &data ){ return _read( thread , data ); } + +template< typename ... Data > +template< typename ... _Data > +bool InputDataStream< Data ... >::_read( std::tuple< Data ... > &data , _Data& ... _data ) +{ + if constexpr( sizeof...(_Data)==sizeof...(Data) ) return read( _data... ); + else return _read( data , _data... , std::get< sizeof...(_Data) >( data ) ); +} + +template< typename ... Data > +template< typename ... _Data > +bool InputDataStream< Data ... >::_read( unsigned int thread , std::tuple< Data ... > &data , _Data& ... _data ) +{ + if constexpr( sizeof...(_Data)==sizeof...(Data) ) return read( thread , _data... ); + else return _read( thread , data , _data... , std::get< sizeof...(_Data) >( data ) ); +} + +template< typename ... Data > +template< typename Real , typename ... _Data > +bool InputDataStream< Data ... >::_read( DirectSum< Real , Data ... > &data , _Data& ... _data ) +{ + if constexpr( sizeof...(_Data)==sizeof...(Data) ) return read( _data... ); + else return _read( data , _data... , data.template get< sizeof...(_Data) >() ); +} + +template< typename ... Data > +template< typename Real , typename ... _Data > +bool InputDataStream< Data ... >::_read( unsigned int thread , DirectSum< Real , Data ... > &data , _Data& ... _data ) +{ + if constexpr( sizeof...(_Data)==sizeof...(Data) ) return read( thread , _data... ); + else return _read( thread , data , _data... , data.template get< sizeof...(_Data) >() ); +} + + +///////////////////////// +// Output data streams // +///////////////////////// +template< typename ... Data > +size_t OutputDataStream< Data ... >::write( unsigned int thread , const Data& ... d ) +{ +#ifdef SHOW_WARNINGS + WARN_ONCE( "Serializing write: " , typeid(*this).name() ); +#endif // SHOW_WARNINGS + std::lock_guard< std::mutex > lock( _insertionMutex ); + return write(d...); +} + +template< typename ... Data > +size_t OutputDataStream< Data ... >::write( const std::tuple< Data ... > &data ){ return _write( data ); } + +template< typename ... Data > +size_t OutputDataStream< Data ... >::write( unsigned int thread , const std::tuple< Data ... > &data ){ return _write( thread , data ); } + +template< typename ... Data > +template< typename Real > +size_t OutputDataStream< Data ... >::write( const DirectSum< Real , Data ... > &data ){ return _write( data ); } + +template< typename ... Data > +template< typename Real > +size_t OutputDataStream< Data ... >::write( unsigned int thread , const DirectSum< Real , Data ... > &data ){ return _write( thread , data ); } + +template< typename ... Data > +template< typename ... _Data > +size_t OutputDataStream< Data ... >::_write( const std::tuple< Data ... > &data , const _Data& ... _data ) +{ + if constexpr( sizeof...(_Data)==sizeof...(Data) ) return write( _data... ); + else return _write( data , _data... , std::get< sizeof...(_Data) >( data ) ); +} + +template< typename ... Data > +template< typename ... _Data > +size_t OutputDataStream< Data ... >::_write( unsigned int thread , const std::tuple< Data ... > &data , const _Data& ... _data ) +{ + if constexpr( sizeof...(_Data)==sizeof...(Data) ) return write( thread , _data... ); + else return _write( thread , data , _data... , std::get< sizeof...(_Data) >( data ) ); +} + +template< typename ... Data > +template< typename Real , typename ... _Data > +size_t OutputDataStream< Data ... >::_write( const DirectSum< Real , Data ... > &data , const _Data& ... _data ) +{ + if constexpr( sizeof...(_Data)==sizeof...(Data) ) return write( _data... ); + else return _write( data , _data... , data.template get< sizeof...(_Data) >() ); +} + +template< typename ... Data > +template< typename Real , typename ... _Data > +size_t OutputDataStream< Data ... >::_write( unsigned int thread , const DirectSum< Real , Data ... > &data , const _Data& ... _data ) +{ + if constexpr( sizeof...(_Data)==sizeof...(Data) ) return write( thread , _data... ); + else return _write( thread , data , _data... , data.template get< sizeof...(_Data) >() ); +} + +//////////////////////////////// +// Multiple input data stream // +//////////////////////////////// +template< typename ...Data > +MultiInputDataStream< Data ... >::MultiInputDataStream( InputDataStream< Data ... > **streams , size_t N ) : _current(0) , _streams( streams , streams+N ) {} + +template< typename ...Data > +MultiInputDataStream< Data ... >::MultiInputDataStream( const std::vector< InputDataStream< Data ... > * > &streams ) : _current(0) , _streams( streams ) {} + +template< typename ...Data > +void MultiInputDataStream< Data ... >::reset( void ){ for( unsigned int i=0 ; i<_streams.size() ; i++ ) _streams[i]->reset(); } + +template< typename ...Data > +unsigned int MultiInputDataStream< Data ... >::numStreams( void ) const { return (unsigned int)_streams.size(); } + +template< typename ...Data > +bool MultiInputDataStream< Data ... >::read( unsigned int t , Data& ... d ){ return _streams[t]->read(d...); } + +template< typename ...Data > +bool MultiInputDataStream< Data ... >::read( Data& ... d ) +{ + while( _current<_streams.size() ) + { + if( _streams[_current]->read( d... ) ) return true; + else _current++; + } + return false; +} + +template< typename ...Data > +MultiInputDataStream< Data ... >::MultiInputDataStream( void ) {} + +template< typename ...Data > +void MultiInputDataStream< Data ... >::_init( InputDataStream< Data ... > **streams , size_t N ) +{ + _streams.resize( N ); + for( unsigned int i=0 ; i +void MultiInputDataStream< Data ... >::_init( const std::vector< InputDataStream< Data ... > * > &streams ){ _streams = streams; } + +///////////////////////////////// +// Multiple output data stream // +///////////////////////////////// + +template< typename ... Data > +MultiOutputDataStream< Data ... >::MultiOutputDataStream( OutputDataStream< Data ... > **streams , size_t N ) : _size(0) , _streams( streams , streams+N ) {} + +template< typename ... Data > +MultiOutputDataStream< Data ... >::MultiOutputDataStream( const std::vector< OutputDataStream< Data ... > * > &streams ) : _size(0) , _streams( streams ) {} + +template< typename ... Data > +unsigned int MultiOutputDataStream< Data ... >::numStreams( void ) const { return (unsigned int)_streams.size(); } + +template< typename ... Data > +size_t MultiOutputDataStream< Data ... >::write( const Data& ... d ){ size_t idx = _size++ ; _streams[0]->write(d...) ; return idx; } + +template< typename ... Data > +size_t MultiOutputDataStream< Data ... >::write( unsigned int t , const Data& ... d ){ size_t idx = _size++ ; _streams[t]->write(d...) ; return idx; } + +template< typename ... Data > +MultiOutputDataStream< Data ... >::MultiOutputDataStream( void ) {} + +#if 0 +template< typename ... Data > +void MultiOutputDataStream< Data ... >::_init( OutputDataStream< Data ... > **streams , size_t N ) +{ + _size = 0; + _streams.resize( N ); + for( unsigned int i=0 ; i +void MultiOutputDataStream< Data ... >::_init( const std::vector< OutputDataStream< Data ... > * > &streams ){ _streams = streams; } + +//////////////////////////////////////////////// +// De-interleaved multiple output data stream // +//////////////////////////////////////////////// + +template< typename ... Data > +DeInterleavedMultiOutputIndexedDataStream< Data ... >::DeInterleavedMultiOutputIndexedDataStream( OutputIndexedDataStream< Data ... > **streams , size_t N ) : _size(0) , _multiStream( streams , streams+N ) {} + +template< typename ... Data > +DeInterleavedMultiOutputIndexedDataStream< Data ... >::DeInterleavedMultiOutputIndexedDataStream( const std::vector< OutputIndexedDataStream< Data ... > * > &streams ) : _size(0) , _multiStream( streams ) {} + +template< typename ... Data > +unsigned int DeInterleavedMultiOutputIndexedDataStream< Data ... >::numStreams( void ) const { return _multiStream.numStreams(); } + +template< typename ... Data > +size_t DeInterleavedMultiOutputIndexedDataStream< Data ... >::write( const Data& ... d ){ size_t idx = _size++ ; _multiStream.write( idx , d... ) ; return idx; } + +template< typename ... Data > +size_t DeInterleavedMultiOutputIndexedDataStream< Data ... >::write( unsigned int thread , const Data& ... d ){ size_t idx = _size++ ; _multiStream.write( thread , idx , d... ) ; return idx; } + +template< typename ... Data > +DeInterleavedMultiOutputIndexedDataStream< Data ... >::DeInterleavedMultiOutputIndexedDataStream( void ) {} + +template< typename ... Data > +void DeInterleavedMultiOutputIndexedDataStream< Data ... >::_init( OutputIndexedDataStream< Data ... > **streams , size_t N ){ _multiStream._init( streams , N ); } + +template< typename ... Data > +void DeInterleavedMultiOutputIndexedDataStream< Data ... >::_init( const std::vector< OutputIndexedDataStream< Data ... > * > &streams ){ _multiStream.init( streams ); } + +///////////////////////////////// +// Input data stream converter // +///////////////////////////////// +template< typename ... IData , typename ... XData > +InputDataStreamConverter< std::tuple< IData ... > , std::tuple< XData ... > >::InputDataStreamConverter( InputDataStream< IData ... > &stream , std::function< std::tuple< XData ... > ( const std::tuple< IData ... >& ) > converter , IData ... zero ) + : _stream(stream) , _converter(converter) , _iZero( std::make_tuple( zero... ) ) {} + +template< typename ... IData , typename ... XData > +void InputDataStreamConverter< std::tuple< IData ... > , std::tuple< XData ... > >::reset( void ){ _stream.reset(); } + +template< typename ... IData , typename ... XData > +bool InputDataStreamConverter< std::tuple< IData ... > , std::tuple< XData ... > >::read( XData& ... xData ) +{ + std::tuple< IData ... > _iData = _iZero; + if( !_stream.read( _iData ) ) return false; + std::tuple< XData ... > _xData = _converter( _iData ); + TupleConverter< XData ... >::FromTuple( _xData , xData ... ); + return true; +} + +template< typename ... IData , typename ... XData > +bool InputDataStreamConverter< std::tuple< IData ... > , std::tuple< XData ... > >::read( unsigned int thread , XData& ... xData ) +{ + std::tuple< IData ... > _iData = _iZero; + if( !_stream.read( thread , _iData ) ) return false; + std::tuple< XData ... > _xData = _converter( _iData ); + TupleConverter< XData ... >::FromTuple( _xData , xData ... ); + return true; +} + +////////////////////////////////// +// Output data stream converter // +////////////////////////////////// +template< typename ... IData , typename ... XData > +OutputDataStreamConverter< std::tuple< IData ... > , std::tuple< XData ... > >::OutputDataStreamConverter( OutputDataStream< IData ... > &stream , std::function< std::tuple< IData ... > ( const std::tuple< XData ... >& ) > converter ) + : _stream(stream) , _converter(converter) {} + +template< typename ... IData , typename ... XData > +size_t OutputDataStreamConverter< std::tuple< IData ... > , std::tuple< XData ... > >::write( const XData& ... xData ) +{ + std::tuple< XData ... > _xData; + TupleConverter< XData ... >::ToTuple( _xData , xData ... ); + std::tuple< IData ... > _iData = _converter( _xData ); + return _stream.write( _iData ); +} + +template< typename ... IData , typename ... XData > +size_t OutputDataStreamConverter< std::tuple< IData ... > , std::tuple< XData ... > >::write( unsigned int thread , const XData& ... xData ) +{ + std::tuple< XData ... > _xData; + TupleConverter< XData ... >::ToTuple( _xData , xData ... ); + std::tuple< IData ... > _iData = _converter( _xData ); + return _stream.write( thread , _iData ); +} + + +//////////////////////////////////////////// +// Interleaved multiple input data stream // +//////////////////////////////////////////// + +template< typename ... Data > +InterleavedMultiInputIndexedDataStream< Data ... >::InterleavedMultiInputIndexedDataStream( InputIndexedDataStream< Data ... > **streams , size_t N ) + : _multiStream( streams , N ) + , _firstTime(true) +{ + _nextValues.resize( _multiStream.numStreams() ); +} + +template< typename ... Data > +InterleavedMultiInputIndexedDataStream< Data ... >::InterleavedMultiInputIndexedDataStream( const std::vector< InputIndexedDataStream< Data ... > * > &streams ) + : _multiStream( streams ) + , _firstTime(true) +{ + _nextValues.resize( _multiStream.numStreams() ); +} + +template< typename ... Data > +void InterleavedMultiInputIndexedDataStream< Data ... >::reset( void ){ _multiStream.reset() , _firstTime = true; } + +template< typename ... Data > +bool InterleavedMultiInputIndexedDataStream< Data ... >::_NextValue::Compare( const _NextValue &v1 , const _NextValue &v2 ) +{ + if( !v2.validData ) return false; + else if( !v1.validData && v2.validData ) return true; + else return std::get<0>( v1.data ) > std::get<0>( v2.data ); +} + +template< typename ... Data > +void InterleavedMultiInputIndexedDataStream< Data ... >::_init( const std::tuple< Data ... > &data ) +{ + std::tuple< size_t , Data ... > _data = std::tuple_cat( std::make_tuple( (size_t)0 ) , data ); + for( unsigned int i=0 ; i<_nextValues.size() ; i++ ) _nextValues[i].data = _data; + for( unsigned int i=0 ; i<_nextValues.size() ; i++ ) + { + _nextValues[i].validData = _multiStream.read( i , _nextValues[i].data ); + _nextValues[i].streamIndex = i; + } + std::make_heap( _nextValues.begin() , _nextValues.end() , _NextValue::Compare ); +} + +template< typename ... Data > +bool InterleavedMultiInputIndexedDataStream< Data ... >::read( Data& ... d ) +{ + if( _firstTime ) _init(d...) , _firstTime = false; + std::pop_heap( _nextValues.begin() , _nextValues.end() , _NextValue::Compare ); +#ifdef DEBUG_STREAM +#if 0 + static unsigned int count = 0; + if( count<10 ) + { + std::vector< _NextValue > foo = _nextValues; + std::sort( foo.begin() , foo.end() , []( const _NextValue &v1 , const _NextValue &v2 ){ return v1.streamIndex::FromTuple( next.data , sz , d... ); +#ifdef DEBUG_STREAM + if( next.data.idx!=_current ) ERROR_OUT( "out of order: Expected = " , _current , ", Found = " , next.data.idx ); + _current++; +#endif // DEBUG_STREAM + + next.validData = _multiStream.read( next.streamIndex , next.data ); + + std::push_heap( _nextValues.begin() , _nextValues.end() , _NextValue::Compare ); + return true; +} \ No newline at end of file diff --git a/Src/Extrapolator.h b/Src/Extrapolator.h new file mode 100644 index 00000000..abf420ca --- /dev/null +++ b/Src/Extrapolator.h @@ -0,0 +1,227 @@ +/* +Copyright (c) 2024, 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 EXTRAPOLATOR_INCLUDED +#define EXTRAPOLATOR_INCLUDED + +#include "PreProcessor.h" +#include "MyMiscellany.h" +#include "FEMTree.h" +#include "PointExtent.h" +#include "Reconstructors.streams.h" + +namespace PoissonRecon +{ + namespace Extrapolator + { + unsigned int ProfilerMS = 20; // The number of ms at which to poll the performance (set to zero for no polling) + + template< typename Real , unsigned int Dim , typename AuxData > + using InputStream = Reconstructor::InputSampleStream< Real , Dim , AuxData >; + + // Specialized solution information without auxiliary data + template< typename Real , unsigned int Dim , typename AuxData , unsigned int DataDegree=1 > + struct Implicit + { + struct Parameters + { + bool verbose = false; + Real scale = (Real)1.1; + Real width = (Real)0.; + Real samplesPerNode = (Real)1.5; + Real perLevelScaleFactor = (Real)32; + unsigned int baseDepth = -1; + unsigned int depth = 8; + unsigned int fullDepth = 5; + unsigned int alignDir = 0; + }; + + // The constructor + Implicit( InputStream< Real , Dim , AuxData > &pointStream , Parameters params , AuxData zero ); + + // The desctructor + ~Implicit( void ){ delete auxData ; auxData = nullptr ; delete _auxEvaluator ; _auxEvaluator = nullptr; } + + // The transformation taking points in the unit cube back to world coordinates + XForm< Real , Dim+1 > unitCubeToModel; + + // The octree adapted to the points + FEMTree< Dim , Real > tree; + + // The signature of the finite-element used for data extrapolation + static const unsigned int DataSig = FEMDegreeAndBType< DataDegree , BOUNDARY_FREE >::Signature; + + // The auxiliary information stored with the oriented vertices + SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > > *auxData; + + // An instance of "zero" AuxData + AuxData zeroAuxData; + + struct OutOfUnitCubeException : public std::exception + { + OutOfUnitCubeException( Point< Real , Dim > world , Point< Real , Dim > cube ) + { + std::stringstream sStream; + sStream << "Out-of-unit-cube input: " << world << " -> " << cube; + _message = sStream.str(); + } + const char * what( void ) const noexcept { return _message.c_str(); } + protected: + std::string _message; + }; + + XForm< Real , Dim+1 > worldToUnitCubeTransform( void ) const { return _worldToUnitCube; } + + AuxData operator()( unsigned int t , Point< Real , Dim > p ){ return _value(t,p); } + + AuxData operator()( Point< Real , Dim > p ){ return operator()( 0 , p ); } + + protected: + typename FEMTree< Dim , Real >::template MultiThreadedSparseEvaluator< IsotropicUIntPack< Dim , DataSig > , ProjectiveData< AuxData , Real > > *_auxEvaluator = nullptr; + XForm< Real , Dim+1 > _worldToUnitCube; + + AuxData _value( unsigned int t , Point< Real , Dim > p ) + { + Point< Real , Dim > q = _worldToUnitCube * p; + for( unsigned int d=0 ; d1 ) throw OutOfUnitCubeException(p,q); + ProjectiveData< AuxData , Real > pData( zeroAuxData ); + _auxEvaluator->addValue( q , pData ); + return pData.value(); + } + }; + + template< typename Real , unsigned int Dim , typename AuxData , unsigned int DataDegree > + Implicit< Real , Dim , AuxData , DataDegree >::Implicit( InputStream< Real , Dim , AuxData > &pointStream , Parameters params , AuxData zeroAuxData ) + : tree(MEMORY_ALLOCATOR_BLOCK_SIZE) , unitCubeToModel( XForm< Real , Dim+1 >::Identity() ) , zeroAuxData(zeroAuxData) + { + // The finite-element tracking tree node + using FEMTreeNode = RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >; + + // The type describing the sampling density + using DensityEstimator = typename FEMTree< Dim , Real >::template DensityEstimator< 0 >; + + // The signature for the finite-elements representing the auxiliary data (if it's there) + static const unsigned int DataSig = FEMDegreeAndBType< DataDegree , BOUNDARY_FREE >::Signature; + + XForm< Real , Dim+1 > modelToUnitCube = XForm< Real , Dim+1 >::Identity(); + + Profiler profiler( ProfilerMS ); + + size_t pointCount; + + ProjectiveData< Point< Real , 2 > , Real > pointDepthAndWeight; + std::vector< typename FEMTree< Dim , Real >::PointSample > *samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); + std::vector< AuxData > *sampleAuxData = nullptr; + + // Read in the samples (and auxiliary data) + { + profiler.reset(); + + pointStream.reset(); + sampleAuxData = new std::vector< AuxData >(); + + modelToUnitCube = params.scale>0 ? PointExtent::GetXForm< Real , Dim , true , AuxData >( pointStream , zeroAuxData , params.scale , params.alignDir ) * modelToUnitCube : modelToUnitCube; + pointStream.reset(); + + if( params.width>0 ) + { + // Assuming the transformation is rigid so that the (max) scale can be pulled from the Frobenius norm + Real maxScale = 0; + for( unsigned int i=0 ; i( 0. , log( maxScale/params.width )/log(2.) ) ); + } + + { + Reconstructor::TransformedInputSampleStream< Real , Dim , AuxData > _pointStream( modelToUnitCube , pointStream ); + auto ProcessData = []( const Point< Real , Dim > &p , AuxData &d ){ return (Real)1.; }; + typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; + pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< AuxData >( sid , tree.spaceRoot() , _pointStream , zeroAuxData , params.depth , *samples , *sampleAuxData , true , tree.nodeAllocators.size() ? tree.nodeAllocators[0] : nullptr , tree.initializer() , ProcessData ); + } + + if( params.fullDepth>params.depth ) + { + if( params.fullDepth!=-1 ) WARN( "Full depth cannot exceed depth: " , params.fullDepth , " <= " , params.depth ); + params.fullDepth = params.depth; + } + if( params.baseDepth>params.fullDepth ) + { + if( params.baseDepth!=-1 ) WARN( "Base depth must be smaller than full depth: " , params.baseDepth , " <= " , params.fullDepth ); + params.baseDepth = params.fullDepth; + } + + + unitCubeToModel = modelToUnitCube.inverse(); + + if( params.verbose ) + { + std::cout << "Input Points / Samples: " << pointCount << " / " << samples->size() << std::endl; + std::cout << "# Read input into tree: " << profiler << std::endl; + } + } + tree.resetNodeIndices( 0 , std::make_tuple() ); + { + profiler.reset(); + auto SampleFunctor = [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return (*samples)[i]; }; + auto SampleDataFunctor = [&]( size_t i ) -> const AuxData & { return (*sampleAuxData)[i]; }; + auxData = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( tree.template setExtrapolatedDataField< DataSig , false , 0 , AuxData >( samples->size() , SampleFunctor , SampleDataFunctor , (DensityEstimator*)nullptr ) ); + delete sampleAuxData; + if( params.verbose ) std::cout << "# Got aux data: " << profiler << std::endl; + } + + { + profiler.reset(); + auto hasDataFunctor = [&]( const FEMTreeNode *node ) + { + ProjectiveData< AuxData , Real > *data = auxData->operator()( node ); + return data && data->weight; + }; + auto addNodeFunctor = [&]( int d , const int off[Dim] ){ return d<=(int)params.fullDepth; }; + tree.template finalizeForMultigrid< 0 , 0 >( 0 , addNodeFunctor , hasDataFunctor , std::make_tuple() , std::make_tuple( auxData ) ); + } + + if( params.verbose ) std::cout << "# Finalized tree: " << profiler << std::endl; + if( params.verbose ) std::cout << "All Nodes / Active Nodes / Ghost Nodes: " << tree.allNodes() << " / " << tree.activeNodes() << " / " << tree.ghostNodes() << std::endl; + if( params.verbose ) std::cout << "Memory Usage: " << float( MemoryInfo::Usage())/(1<<20) << " MB" << std::endl; + delete samples; + + auto nodeFunctor = [&]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *n ) + { + ProjectiveData< AuxData , Real >* clr = (*auxData)( n ); + if( clr ) (*clr) *= (Real)pow( params.perLevelScaleFactor , tree.depth( n ) ); + }; + tree.tree().processNodes( nodeFunctor ); + + _worldToUnitCube = unitCubeToModel.inverse(); + _auxEvaluator = new typename FEMTree< Dim , Real >::template MultiThreadedSparseEvaluator< IsotropicUIntPack< Dim , DataSig > , ProjectiveData< AuxData , Real > >( &tree , *auxData , ThreadPool::NumThreads() ); + + } + } +} + +#endif // EXTRAPOLATOR_INCLUDED \ No newline at end of file diff --git a/Src/FEMTree.Initialize.inl b/Src/FEMTree.Initialize.inl index 1f1ecd61..1e0eae51 100644 --- a/Src/FEMTree.Initialize.inl +++ b/Src/FEMTree.Initialize.inl @@ -51,21 +51,18 @@ size_t FEMTreeInitializer< Dim , Real >::_Initialize( FEMTreeNode &node , int ma } template< unsigned int Dim , class Real > -template< typename AuxData , typename PointStream > -size_t FEMTreeInitializer< Dim , Real >::Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , PointStream &pointStream , AuxData zeroData , int maxDepth , std::vector< PointSample >& samplePoints , std::vector< AuxData > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , AuxData & ) > ProcessData ) +template< typename AuxData > +size_t FEMTreeInitializer< Dim , Real >::Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , InputDataStream< Point< Real , Dim > , AuxData > &pointStream , AuxData zeroData , int maxDepth , std::vector< PointSample >& samplePoints , std::vector< AuxData > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , AuxData & ) > ProcessData ) { - return Initialize< AuxData , PointStream >( sid , root , pointStream , zeroData , maxDepth , [&]( Point< Real , Dim > ){ return maxDepth; } , samplePoints , sampleData , mergeNodeSamples , nodeAllocator , NodeInitializer , ProcessData ); + return Initialize< AuxData >( sid , root , pointStream , zeroData , maxDepth , [&]( Point< Real , Dim > ){ return maxDepth; } , samplePoints , sampleData , mergeNodeSamples , nodeAllocator , NodeInitializer , ProcessData ); } template< unsigned int Dim , class Real > -template< typename AuxData , typename PointStream > -size_t FEMTreeInitializer< Dim , Real >::Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , PointStream &pointStream , AuxData zeroData , int maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , std::vector< PointSample >& samplePoints , std::vector< AuxData > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , AuxData & ) > ProcessData ) +template< typename AuxData > +size_t FEMTreeInitializer< Dim , Real >::Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , InputDataStream< Point< Real , Dim > , AuxData > &pointStream , AuxData zeroData , int maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , std::vector< PointSample >& samplePoints , std::vector< AuxData > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , AuxData & ) > ProcessData ) { - using Sample = VectorTypeUnion< Real , Point< Real , Dim > , AuxData >; - static_assert( std::is_base_of< InputDataStream< Sample > , PointStream >::value , "[ERROR] Unexpected point stream type" ); typename FEMTreeNode::SubTreeExtractor subtreeExtractor( root ); - auto Leaf = [&]( FEMTreeNode& root , Point< Real , Dim > p , unsigned int maxDepth ) { for( int d=0 ; d1 ) return (FEMTreeNode*)NULL; @@ -97,12 +94,10 @@ size_t FEMTreeInitializer< Dim , Real >::Initialize( struct StreamInitialization { std::vector< node_index_type > &nodeToIndexMap = sid._nodeToIndexMap; - Sample s; - s.template get<1>() = zeroData; - while( pointStream.read( s ) ) + Point< Real , Dim > p; + AuxData d = zeroData; + while( pointStream.read( p , d ) ) { - Point< Real , Dim > p = s.template get<0>(); - AuxData d = s.template get<1>(); Real weight = ProcessData( p , d ); if( weight<=0 ){ badData++ ; continue; } FEMTreeNode *temp = Leaf( root , p , pointDepthFunctor(p) ); diff --git a/Src/FEMTree.LevelSet.2D.inl b/Src/FEMTree.LevelSet.2D.inl index 8f5d9f41..6b0e8093 100644 --- a/Src/FEMTree.LevelSet.2D.inl +++ b/Src/FEMTree.LevelSet.2D.inl @@ -32,12 +32,27 @@ struct _LevelSetExtractor< HasData , Real , 2 , Data > { static const unsigned int Dim = 2; // Store the position, the (interpolated) gradient, the weight, and possibly data - typedef typename std::conditional + typedef std::conditional_t < HasData , - VectorTypeUnion< Real , Point< Real , Dim > , Point< Real , Dim > , Real , Data > , - VectorTypeUnion< Real , Point< Real , Dim > , Point< Real , Dim > , Real > - >::type Vertex; + DirectSum< Real , Point< Real , Dim > , Point< Real , Dim > , Real , Data > , + DirectSum< Real , Point< Real , Dim > , Point< Real , Dim > , Real > + > Vertex; + + using OutputVertexStream = std::conditional_t + < + HasData , + OutputDataStream< Point< Real , Dim > , Point< Real , Dim > , Real , Data > , + OutputDataStream< Point< Real , Dim > , Point< Real , Dim > , Real > + >; + + using OutputIndexedVertexStream = std::conditional_t + < + HasData , + OutputIndexedDataStream< Point< Real , Dim > , Point< Real , Dim > , Real , Data > , + OutputIndexedDataStream< Point< Real , Dim > , Point< Real , Dim > , Real > + >; + protected: static std::mutex _pointInsertionMutex; static std::atomic< size_t > _BadRootCount; @@ -598,7 +613,7 @@ public: } - template< unsigned int WeightDegree , unsigned int DataSig , typename OutputVertexStream > + template< unsigned int WeightDegree , unsigned int DataSig , typename VertexStream > static void SetIsoVertices ( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , @@ -611,8 +626,7 @@ public: Real isoValue , LocalDepth depth , LocalDepth fullDepth , - std::atomic< node_index_type > &vOffset , - OutputVertexStream &vertexStream , + VertexStream &vertexStream , std::vector< SliceValues > &sliceValues , std::vector< typename SliceValues::Scratch > &scratchValues , const Data &zeroData @@ -674,7 +688,7 @@ public: GetIsoVertex< WeightDegree , DataSig >( tree , nonLinearFit , outputGradients , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , e , sValues , vertex , zeroData ); bool stillOwner = false; std::pair< node_index_type , Vertex > hashed_vertex; - if constexpr( std::is_base_of_v< OutputDataStream< std::pair< node_index_type , Vertex > > , OutputVertexStream > ) + if constexpr( std::is_base_of_v< OutputIndexedVertexStream , VertexStream > ) { char desired = 1 , expected = 0; #ifdef SANITIZED_PR @@ -683,23 +697,21 @@ public: if( SetAtomic( edgeSet , desired , expected ) ) #endif // SANITIZED_PR { - hashed_vertex = std::pair< node_index_type , Vertex >( vOffset++ , vertex ); - vertexStream.write( thread , hashed_vertex ); + hashed_vertex = std::pair< node_index_type , Vertex >( (node_index_type)vertexStream.write( thread , vertex ) , vertex ); stillOwner = true; } } - else if constexpr( std::is_base_of_v< OutputDataStream< Vertex > , OutputVertexStream > ) + else if constexpr( std::is_base_of_v< OutputVertexStream , VertexStream > ) { std::lock_guard< std::mutex > lock( _pointInsertionMutex ); if( !edgeSet ) { - hashed_vertex = std::pair< node_index_type , Vertex >( vOffset++ , vertex ); - vertexStream.write( vertex ); + hashed_vertex = std::pair< node_index_type , Vertex >( (node_index_type)vertexStream.write( thread , vertex ) , vertex ); edgeSet = 1; stillOwner = true; } } - else ERROR_OUT( "Bad stream type: " , typeid(OutputVertexStream).name() ); + else ERROR_OUT( "Bad stream type: " , typeid(VertexStream).name() ); if( stillOwner ) // If this edge is the one generating the iso-vertex { @@ -1034,9 +1046,8 @@ public: static int SetIsoVerticesFlag ( void ){ return _SetFlag::CORNER_VALUES | _SetFlag::ISO_VERTICES; } static int SetIsoEdgesFlag ( void ){ return _SetFlag::CORNER_VALUES | _SetFlag::ISO_VERTICES | _SetFlag::ISO_EDGES; } - - template< unsigned int WeightDegree , unsigned int DataSig , typename OutputVertexStream , unsigned int ... FEMSigs > - static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputVertexStream &vertexStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , std::vector< SliceValues > &sliceValues , int setFlag ) + template< unsigned int WeightDegree , unsigned int DataSig , typename VertexStream , unsigned int ... FEMSigs > + static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , VertexStream &vertexStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , std::vector< SliceValues > &sliceValues , int setFlag ) { if( maxKeyDepth(); - std::atomic< node_index_type > vOffset = 0; typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator = NULL; if constexpr( HasData ) if( data ) pointEvaluator = new typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >( tree._maxDepth ); @@ -1098,7 +1108,7 @@ public: if( setFlag & _SetFlag::ISO_VERTICES ) { double t = Time(); - SetIsoVertices< WeightDegree , DataSig >( keyGenerator , tree , nonLinearFit , outputGradients , pointEvaluator , densityWeights , data , isoValue , d , fullDepth , vOffset , vertexStream , sliceValues , scratchValues , zeroData ); + SetIsoVertices< WeightDegree , DataSig >( keyGenerator , tree , nonLinearFit , outputGradients , pointEvaluator , densityWeights , data , isoValue , d , fullDepth , vertexStream , sliceValues , scratchValues , zeroData ); stats.verticesTime += Time()-t; } @@ -1131,9 +1141,8 @@ public: for( LocalDepth d=tree._maxDepth ; d>=fullDepth ; d-- ) SetLevelSet( keyGenerator , tree , d , sliceValues[d] , edgeStream , flipOrientation ); } - - template< unsigned int WeightDegree , unsigned int DataSig , typename OutputVertexStream , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , OutputVertexStream &vertexStream , OutputDataStream< std::pair< node_index_type , node_index_type > > &edgeStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool flipOrientation ) + template< unsigned int WeightDegree , unsigned int DataSig , typename VertexStream , unsigned int ... FEMSigs > + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , VertexStream &vertexStream , OutputDataStream< std::pair< node_index_type , node_index_type > > &edgeStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool flipOrientation ) { std::vector< SliceValues > sliceValues; @@ -1162,50 +1171,51 @@ struct LevelSetExtractor< Real , 2 > typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::SliceValues SliceValues; typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::TreeSliceValuesAndVertexPositions TreeSliceValuesAndVertexPositions; typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::TreeNode TreeNode; - using IndexedVertex = std::pair< node_index_type , Vertex >; + using OutputVertexStream = typename _LevelSetExtractor< HasData , Real , Dim , Data >::OutputVertexStream; + using OutputIndexedVertexStream = typename _LevelSetExtractor< HasData , Real , Dim , Data >::OutputIndexedVertexStream; template< unsigned int WeightDegree > using DensityEstimator = typename _LevelSetExtractor< HasData , Real , Dim , Data >::template DensityEstimator< WeightDegree >; static int SetCornerValuesFlag( void ){ return _LevelSetExtractor< HasData , Real , Dim , Data >::SetCornerValuesFlag(); } static int SetIsoVerticesFlag ( void ){ return _LevelSetExtractor< HasData , Real , Dim , Data >::SetIsoVerticesFlag (); } static int SetIsoEdgesFlag ( void ){ return _LevelSetExtractor< HasData , Real , Dim , Data >::SetIsoEdgesFlag (); } template< unsigned int WeightDegree , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , OutputDataStream< Vertex > &vertexStream , OutputDataStream< std::pair< node_index_type , node_index_type > > &edgeStream , bool nonLinearFit , bool outputGradients , bool flipOrientation ) + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , OutputVertexStream &vertexStream , OutputDataStream< std::pair< node_index_type , node_index_type > > &edgeStream , bool nonLinearFit , bool outputGradients , bool flipOrientation ) { typedef unsigned char Data; Data zeroData = 0; static const unsigned int DataSig = FEMDegreeAndBType< 0 , BOUNDARY_FREE >::Signature; const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data = NULL; - return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputDataStream< Vertex > , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , vertexStream , edgeStream , zeroData , nonLinearFit , outputGradients , flipOrientation ); + return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputVertexStream , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , vertexStream , edgeStream , zeroData , nonLinearFit , outputGradients , flipOrientation ); } template< unsigned int WeightDegree , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , OutputDataStream< IndexedVertex > &vertexStream , OutputDataStream< std::pair< node_index_type , node_index_type > > &edgeStream , bool nonLinearFit , bool outputGradients , bool flipOrientation ) + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , OutputIndexedVertexStream &vertexStream , OutputDataStream< std::pair< node_index_type , node_index_type > > &edgeStream , bool nonLinearFit , bool outputGradients , bool flipOrientation ) { typedef unsigned char Data; Data zeroData = 0; static const unsigned int DataSig = FEMDegreeAndBType< 0 , BOUNDARY_FREE >::Signature; const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data = NULL; - return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputDataStream< IndexedVertex > , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , vertexStream , edgeStream , zeroData , nonLinearFit , outputGradients , flipOrientation ); + return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputIndexedVertexStream , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , vertexStream , edgeStream , zeroData , nonLinearFit , outputGradients , flipOrientation ); } template< unsigned int WeightDegree , unsigned int ... FEMSigs > - static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputDataStream< Vertex > &vertexStream , bool nonLinearFit , bool outputGradients , std::vector< SliceValues > &sliceValues , int setFlag ) + static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputVertexStream &vertexStream , bool nonLinearFit , bool outputGradients , std::vector< SliceValues > &sliceValues , int setFlag ) { typedef unsigned char Data; Data zeroData = 0; static const unsigned int DataSig = FEMDegreeAndBType< 0 , BOUNDARY_FREE >::Signature; const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data = NULL; - return _LevelSetExtractor< HasData , Real , Dim , Data >::template SetSliceValues< WeightDegree , DataSig , OutputDataStream< Vertex > , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , vertexStream , zeroData , nonLinearFit , outputGradients , sliceValues , setFlag ); + return _LevelSetExtractor< HasData , Real , Dim , Data >::template SetSliceValues< WeightDegree , DataSig , OutputVertexStream , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , vertexStream , zeroData , nonLinearFit , outputGradients , sliceValues , setFlag ); } template< unsigned int WeightDegree , unsigned int ... FEMSigs > - static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputDataStream< IndexedVertex > &vertexStream , bool nonLinearFit , bool outputGradients , std::vector< SliceValues > &sliceValues , int setFlag ) + static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputIndexedVertexStream &vertexStream , bool nonLinearFit , bool outputGradients , std::vector< SliceValues > &sliceValues , int setFlag ) { typedef unsigned char Data; Data zeroData = 0; static const unsigned int DataSig = FEMDegreeAndBType< 0 , BOUNDARY_FREE >::Signature; const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data = NULL; - return _LevelSetExtractor< HasData , Real , Dim , Data >::template SetSliceValues< WeightDegree , DataSig , OutputDataStream< IndexedVertex > , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , vertexStream , zeroData , nonLinearFit , outputGradients , sliceValues , setFlag ); + return _LevelSetExtractor< HasData , Real , Dim , Data >::template SetSliceValues< WeightDegree , DataSig , OutputIndexedVertexStream , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , vertexStream , zeroData , nonLinearFit , outputGradients , sliceValues , setFlag ); } }; @@ -1219,31 +1229,32 @@ struct LevelSetExtractor< Real , 2 , Data > typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::SliceValues SliceValues; typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::TreeSliceValuesAndVertexPositions TreeSliceValuesAndVertexPositions; typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::TreeNode TreeNode; - using IndexedVertex = std::pair< node_index_type , Vertex >; + using OutputVertexStream = typename _LevelSetExtractor< HasData , Real , Dim , Data >::OutputVertexStream; + using OutputIndexedVertexStream = typename _LevelSetExtractor< HasData , Real , Dim , Data >::OutputIndexedVertexStream; template< unsigned int WeightDegree > using DensityEstimator = typename _LevelSetExtractor< HasData , Real , Dim , Data >::template DensityEstimator< WeightDegree >; static int SetCornerValuesFlag( void ){ return _LevelSetExtractor< HasData , Real , Dim , Data >::SetCornerValuesFlag(); } static int SetIsoVerticesFlag ( void ){ return _LevelSetExtractor< HasData , Real , Dim , Data >::SetIsoVerticesFlag (); } static int SetIsoEdgesFlag ( void ){ return _LevelSetExtractor< HasData , Real , Dim , Data >::SetIsoEdgesFlag (); } template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputDataStream< Vertex > &vertexStream , OutputDataStream< std::pair< node_index_type , node_index_type > > &edgeStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool flipOrientation ) + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputVertexStream &vertexStream , OutputDataStream< std::pair< node_index_type , node_index_type > > &edgeStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool flipOrientation ) { - return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputDataStream< Vertex > , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , vertexStream , edgeStream , zeroData , nonLinearFit , outputGradients , flipOrientation ); + return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputVertexStream , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , vertexStream , edgeStream , zeroData , nonLinearFit , outputGradients , flipOrientation ); } template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputDataStream< IndexedVertex > &vertexStream , OutputDataStream< std::pair< node_index_type , node_index_type > > &edgeStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool flipOrientation ) + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputIndexedVertexStream &vertexStream , OutputDataStream< std::pair< node_index_type , node_index_type > > &edgeStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool flipOrientation ) { - return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputDataStream< IndexedVertex > , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , vertexStream , edgeStream , zeroData , nonLinearFit , outputGradients , flipOrientation ); + return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputIndexedVertexStream , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , vertexStream , edgeStream , zeroData , nonLinearFit , outputGradients , flipOrientation ); } template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > - static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputDataStream< Vertex > &vertexStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , std::vector< SliceValues > &sliceValues , int setFlag ) + static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputVertexStream &vertexStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , std::vector< SliceValues > &sliceValues , int setFlag ) { - return _LevelSetExtractor< HasData , Real , Dim , Data >::template SetSliceValues< WeightDegree , DataSig , OutputDataStream< Vertex > , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , vertexStream , zeroData , nonLinearFit , outputGradients , sliceValues , setFlag ); + return _LevelSetExtractor< HasData , Real , Dim , Data >::template SetSliceValues< WeightDegree , DataSig , OutputVertexStream , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , vertexStream , zeroData , nonLinearFit , outputGradients , sliceValues , setFlag ); } template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > - static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputDataStream< IndexedVertex > &vertexStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , std::vector< SliceValues > &sliceValues , int setFlag ) + static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputIndexedVertexStream &vertexStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , std::vector< SliceValues > &sliceValues , int setFlag ) { - return _LevelSetExtractor< HasData , Real , Dim , Data >::template SetSliceValues< WeightDegree , DataSig , OutputDataStream< IndexedVertex > , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , vertexStream , zeroData , nonLinearFit , outputGradients , sliceValues , setFlag ); + return _LevelSetExtractor< HasData , Real , Dim , Data >::template SetSliceValues< WeightDegree , DataSig , OutputIndexedVertexStream , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , vertexStream , zeroData , nonLinearFit , outputGradients , sliceValues , setFlag ); } }; diff --git a/Src/FEMTree.LevelSet.3D.inl b/Src/FEMTree.LevelSet.3D.inl index df12f23d..d64c950f 100644 --- a/Src/FEMTree.LevelSet.3D.inl +++ b/Src/FEMTree.LevelSet.3D.inl @@ -32,12 +32,26 @@ struct _LevelSetExtractor< HasData , Real , 3 , Data > { static const unsigned int Dim = 3; // Store the position, the (interpolated) gradient, the weight, and possibly data - typedef typename std::conditional + typedef std::conditional_t < HasData , - VectorTypeUnion< Real , Point< Real , Dim > , Point< Real , Dim > , Real , Data > , - VectorTypeUnion< Real , Point< Real , Dim > , Point< Real , Dim > , Real > - >::type Vertex; + DirectSum< Real , Point< Real , Dim > , Point< Real , Dim > , Real , Data > , + DirectSum< Real , Point< Real , Dim > , Point< Real , Dim > , Real > + > Vertex; + + using OutputVertexStream = std::conditional_t + < + HasData , + OutputDataStream< Point< Real , Dim > , Point< Real , Dim > , Real , Data > , + OutputDataStream< Point< Real , Dim > , Point< Real , Dim > , Real > + >; + + using OutputIndexedVertexStream = std::conditional_t + < + HasData , + OutputIndexedDataStream< Point< Real , Dim > , Point< Real , Dim > , Real , Data > , + OutputIndexedDataStream< Point< Real , Dim > , Point< Real , Dim > , Real > + >; protected: static std::mutex _pointInsertionMutex; @@ -617,7 +631,7 @@ public: return incidence; } - template< unsigned int WeightDegree , unsigned int DataSig , typename OutputVertexStream , typename SliceFunctor /* = std::function< SliceValues & ( unsigned int ) > */ , typename ScratchFunctor /* = std::function< typename SliceValues::Scratch & ( unsigned int ) */ > + template< unsigned int WeightDegree , unsigned int DataSig , typename VertexStream , typename SliceFunctor /* = std::function< SliceValues & ( unsigned int ) > */ , typename ScratchFunctor /* = std::function< typename SliceValues::Scratch & ( unsigned int ) */ > static void CopyIsoStructure ( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , @@ -629,12 +643,11 @@ public: SliceFunctor sliceFunctor , ScratchFunctor scratchFunctor , const std::vector< std::pair< node_index_type , node_index_type > > &incidence , - OutputVertexStream &vertexStream , + VertexStream &vertexStream , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > > *pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , - std::atomic< node_index_type > &vOffset , const Data &zeroData ) { @@ -745,12 +758,9 @@ public: vertices[i].template get<1>() = Point< Real , Dim >(); vertices[i].template get<2>() = depth; if constexpr( HasData ) vertices[i].template get<3>() = dataValue; - vertexIndices[i] = vOffset++; - if constexpr( std::is_base_of_v< OutputDataStream< std::pair< node_index_type , Vertex > > , OutputVertexStream > ) - vertexStream.write( 0 , std::pair< node_index_type , Vertex >( vertexIndices[i] , vertices[i] ) ); - else if constexpr( std::is_base_of_v< OutputDataStream< Vertex > , OutputVertexStream > ) - vertexStream.write( vertices[i] ); - else ERROR_OUT( "Bad stream type: " , typeid(OutputVertexStream).name() ); + if constexpr( std::is_base_of_v< OutputIndexedVertexStream , VertexStream > ) vertexIndices[i] = (node_index_type)vertexStream.write( 0 , vertices[i] ); + else if constexpr( std::is_base_of_v< OutputVertexStream , VertexStream > ) vertexIndices[i] = (node_index_type)vertexStream.write( vertices[i] ); + else ERROR_OUT( "Bad stream type: " , typeid(VertexStream).name() ); } } @@ -996,15 +1006,15 @@ public: ); } - template< unsigned int WeightDegree , unsigned int DataSig , typename OutputVertexStream > - static void SetSliceIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slice , std::atomic< node_index_type > &vOffset , OutputVertexStream &vertexStream , std::vector< SlabValues >& slabValues , const Data &zeroData ) + template< unsigned int WeightDegree , unsigned int DataSig , typename VertexStream > + static void SetSliceIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slice , VertexStream &vertexStream , std::vector< SlabValues >& slabValues , const Data &zeroData ) { - if( slice>0 ) SetSliceIsoVertices< WeightDegree , DataSig >( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , depth , fullDepth , slice , HyperCube::FRONT , vOffset , vertexStream , slabValues , zeroData ); - if( slice<(1<( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , depth , fullDepth , slice , HyperCube::BACK , vOffset , vertexStream , slabValues , zeroData ); + if( slice>0 ) SetSliceIsoVertices< WeightDegree , DataSig >( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , depth , fullDepth , slice , HyperCube::FRONT , vertexStream , slabValues , zeroData ); + if( slice<(1<( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , depth , fullDepth , slice , HyperCube::BACK , vertexStream , slabValues , zeroData ); } - template< unsigned int WeightDegree , unsigned int DataSig , typename OutputVertexStream > - static void SetSliceIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slice , HyperCube::Direction zDir , std::atomic< node_index_type > &vOffset , OutputVertexStream &vertexStream , std::vector< SlabValues >& slabValues , const Data &zeroData ) + template< unsigned int WeightDegree , unsigned int DataSig , typename VertexStream > + static void SetSliceIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slice , HyperCube::Direction zDir , VertexStream &vertexStream , std::vector< SlabValues >& slabValues , const Data &zeroData ) { auto _EdgeIndex = [&]( const TreeNode *node , typename HyperCube::Cube< Dim >::template Element< 1 > e ) { @@ -1056,7 +1066,7 @@ public: GetIsoVertex< WeightDegree , DataSig >( tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , _e , zDir , sValues , vertex , zeroData ); bool stillOwner = false; std::pair< node_index_type , Vertex > hashed_vertex; - if constexpr( std::is_base_of_v< OutputDataStream< std::pair< node_index_type , Vertex > > , OutputVertexStream > ) + if constexpr( std::is_base_of_v< OutputIndexedVertexStream , VertexStream > ) { char desired = 1 , expected = 0; #ifdef SANITIZED_PR @@ -1065,23 +1075,21 @@ public: if( SetAtomic( edgeSet , desired , expected ) ) #endif // SANITIZED_PR { - hashed_vertex = std::pair< node_index_type , Vertex >( vOffset++ , vertex ); - vertexStream.write( thread , hashed_vertex ); + hashed_vertex = std::pair< node_index_type , Vertex >( (node_index_type)vertexStream.write( thread , vertex ) , vertex ); stillOwner = true; } } - else if constexpr( std::is_base_of_v< OutputDataStream< Vertex > , OutputVertexStream > ) + else if constexpr( std::is_base_of_v< OutputVertexStream , VertexStream > ) { std::lock_guard< std::mutex > lock( _pointInsertionMutex ); if( !edgeSet ) { - hashed_vertex = std::pair< node_index_type , Vertex >( vOffset++ , vertex ); - vertexStream.write( vertex ); + hashed_vertex = std::pair< node_index_type , Vertex >( (node_index_type)vertexStream.write( vertex ) , vertex ); edgeSet = 1; stillOwner = true; } } - else ERROR_OUT( "Bad stream type: " , typeid(OutputVertexStream).name() ); + else ERROR_OUT( "Bad stream type: " , typeid(VertexStream).name() ); if( stillOwner ) { @@ -1151,8 +1159,8 @@ public: //////////////////// // Iso-Extraction // //////////////////// - template< unsigned int WeightDegree , unsigned int DataSig , typename OutputVertexStream > - static void SetXSliceIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slab , Real bCoordinate , Real fCoordinate , std::atomic< node_index_type > &vOffset , OutputVertexStream &vertexStream , std::vector< SlabValues >& slabValues , const Data &zeroData ) + template< unsigned int WeightDegree , unsigned int DataSig , typename VertexStream > + static void SetXSliceIsoVertices( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , const FEMTree< Dim , Real >& tree , bool nonLinearFit , bool gradientNormals , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , LocalDepth fullDepth , int slab , Real bCoordinate , Real fCoordinate , VertexStream &vertexStream , std::vector< SlabValues >& slabValues , const Data &zeroData ) { auto _EdgeIndex = [&]( const TreeNode *node , typename HyperCube::Cube< Dim >::template Element< 1 > e ) { @@ -1210,7 +1218,7 @@ public: GetIsoVertex< WeightDegree , DataSig >( tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , _c , bCoordinate , fCoordinate , bValues , fValues , vertex , zeroData ); bool stillOwner = false; std::pair< node_index_type , Vertex > hashed_vertex; - if constexpr( std::is_base_of_v< OutputDataStream< std::pair< node_index_type , Vertex > > , OutputVertexStream > ) + if constexpr( std::is_base_of_v< OutputIndexedVertexStream , VertexStream > ) { char desired = 1 , expected = 0; #ifdef SANITIZED_PR @@ -1219,23 +1227,21 @@ public: if( SetAtomic( edgeSet , desired , expected ) ) #endif // SANITIZED_PR { - hashed_vertex = std::pair< node_index_type , Vertex >( vOffset++ , vertex ); - vertexStream.write( thread , hashed_vertex ); + hashed_vertex = std::pair< node_index_type , Vertex >( (node_index_type)vertexStream.write( thread , vertex ) , vertex ); stillOwner = true; } } - else if constexpr( std::is_base_of_v< OutputDataStream< Vertex > , OutputVertexStream > ) + else if constexpr( std::is_base_of_v< OutputVertexStream , VertexStream > ) { std::lock_guard< std::mutex > lock( _pointInsertionMutex ); if( !edgeSet ) { - hashed_vertex = std::pair< node_index_type , Vertex >( vOffset++ , vertex ); - vertexStream.write( vertex ); + hashed_vertex = std::pair< node_index_type , Vertex >( (node_index_type)vertexStream.write( vertex ) , vertex ); edgeSet = 1; stillOwner = true; } } - else ERROR_OUT( "Bad stream type: " , typeid(OutputVertexStream).name() ); + else ERROR_OUT( "Bad stream type: " , typeid(VertexStream).name() ); if( stillOwner ) { @@ -1597,12 +1603,11 @@ public: } } } - } - ); + } ); } - template< typename OutputVertexStream , typename FaceIndexFunctor /* = std::function< LevelSetExtraction::Key< Dim > ( const TreeNode * , typename HyperCube::Cube< Dim >::template Element< 2 > ) */ > - static void SetLevelSet( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , FaceIndexFunctor faceIndexFunctor , const FEMTree< Dim , Real >& tree , LocalDepth depth , int offset , const SliceValues& bValues , const SliceValues& fValues , const XSliceValues& xValues , const typename SliceValues::Scratch &bScratch , const typename SliceValues::Scratch &fScratch , const typename XSliceValues::Scratch &xScratch , OutputVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool polygonMesh , bool addBarycenter , std::atomic< node_index_type > &vOffset , bool flipOrientation ) + template< typename VertexStream , typename FaceIndexFunctor /* = std::function< LevelSetExtraction::Key< Dim > ( const TreeNode * , typename HyperCube::Cube< Dim >::template Element< 2 > ) */ > + static void SetLevelSet( const LevelSetExtraction::KeyGenerator< Dim > &keyGenerator , FaceIndexFunctor faceIndexFunctor , const FEMTree< Dim , Real >& tree , LocalDepth depth , int offset , const SliceValues& bValues , const SliceValues& fValues , const XSliceValues& xValues , const typename SliceValues::Scratch &bScratch , const typename SliceValues::Scratch &fScratch , const typename XSliceValues::Scratch &xScratch , VertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool polygonMesh , bool addBarycenter , bool flipOrientation ) { std::vector< std::pair< node_index_type , Vertex > > polygon; std::vector< std::vector< IsoEdge > > edgess( ThreadPool::NumThreads() ); @@ -1694,13 +1699,12 @@ public: else if( ( iter=xValues.edgeVertexMap.find( key ) )!=xValues.edgeVertexMap.end() ) polygon[kk] = iter->second; else ERROR_OUT( "Couldn't find vertex in edge map: " , off[0] , " , " , off[1] , " , " , off[2] , " @ " , depth , " : " , keyGenerator.to_string( key ) , " | " , key.to_string() ); } - AddIsoPolygons( thread , vertexStream , polygonStream , polygon , polygonMesh , addBarycenter , vOffset ); + AddIsoPolygons( thread , vertexStream , polygonStream , polygon , polygonMesh , addBarycenter ); } } } } - } - ); + } ); } template< unsigned int WeightDegree , unsigned int DataSig > @@ -1928,8 +1932,8 @@ public: return true; } - template< typename OutputVertexStream > - static unsigned int AddIsoPolygons( unsigned int thread , OutputVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , std::vector< std::pair< node_index_type , Vertex > >& polygon , bool polygonMesh , bool addBarycenter , std::atomic< node_index_type > &vOffset ) + template< typename VertexStream > + static unsigned int AddIsoPolygons( unsigned int thread , VertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , std::vector< std::pair< node_index_type , Vertex > >& polygon , bool polygonMesh , bool addBarycenter ) { if( polygonMesh ) { @@ -1958,18 +1962,13 @@ public: c /= ( typename Vertex::Real )polygon.size(); node_index_type cIdx; - if constexpr( std::is_base_of_v< OutputDataStream< std::pair< node_index_type , Vertex > > , OutputVertexStream > ) - { - cIdx = vOffset++; - vertexStream.write( thread , std::pair< node_index_type , Vertex >(cIdx,c) ); - } - else if constexpr( std::is_base_of_v< OutputDataStream< Vertex > , OutputVertexStream > ) + if constexpr( std::is_base_of_v< OutputIndexedVertexStream , VertexStream > ) cIdx = (node_index_type)vertexStream.write( thread , c ); + else if constexpr( std::is_base_of_v< OutputVertexStream , VertexStream > ) { std::lock_guard< std::mutex > lock( _pointInsertionMutex ); - cIdx = vOffset++; - vertexStream.write( c ); + cIdx = (node_index_type)vertexStream.write( c ); } - else ERROR_OUT( "Bad stream type: " , typeid(OutputVertexStream).name() ); + else ERROR_OUT( "Bad stream type: " , typeid(VertexStream).name() ); for( unsigned i=0 ; i , 1 > > evaluators( tree._maxDepth+1 ); for( LocalDepth d=0 ; d<=tree._maxDepth ; d++ ) evaluators[d].set( tree._maxDepth ); - std::atomic< node_index_type > vertexOffset = 0; - std::vector< SlabValues > slabValues( tree._maxDepth+1 ); std::vector< std::pair< node_index_type , node_index_type > > backIncidence , frontIncidence; if( backBoundary ) backIncidence = SetIncidence( tree , backBoundary->sliceTree , fullDepth , slabStartAtMaxDepth , maxDepth ); @@ -2291,7 +2288,7 @@ public: if( !SetCoarseSlice( sliceAtMaxDepth , depth , slice ) ) ERROR_OUT( "Could not set coarse slice" ); return slabValues[depth].sliceScratch( slice ); }; - CopyIsoStructure< WeightDegree , DataSig >( keyGenerator , *boundary , tree , fullDepth , sliceAtMaxDepth , maxDepth , sliceFunctor , scratchFunctor , *incidence , vertexStream , gradientNormals , pointEvaluator , densityWeights , data , vertexOffset , zeroData ); + CopyIsoStructure< WeightDegree , DataSig >( keyGenerator , *boundary , tree , fullDepth , sliceAtMaxDepth , maxDepth , sliceFunctor , scratchFunctor , *incidence , vertexStream , gradientNormals , pointEvaluator , densityWeights , data , zeroData ); } else { @@ -2302,7 +2299,7 @@ public: { if( d<=tree._maxDepth ) { - SetSliceIsoVertices< WeightDegree , DataSig >( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , d , fullDepth , o , vertexOffset , vertexStream , slabValues , zeroData ); + SetSliceIsoVertices< WeightDegree , DataSig >( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , d , fullDepth , o , vertexStream , slabValues , zeroData ); } if( o&1 ) break; } @@ -2341,7 +2338,7 @@ public: // Set the iso-vertices Real bCoordinate , fCoordinate; SetSlabBounds( d , o , bCoordinate , fCoordinate ); - SetXSliceIsoVertices< WeightDegree , DataSig >( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , d , std::max< unsigned int >( slabDepth , fullDepth ) , o , bCoordinate , fCoordinate , vertexOffset , vertexStream , slabValues , zeroData ); + SetXSliceIsoVertices< WeightDegree , DataSig >( keyGenerator , tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , d , std::max< unsigned int >( slabDepth , fullDepth ) , o , bCoordinate , fCoordinate , vertexStream , slabValues , zeroData ); } } @@ -2399,7 +2396,7 @@ public: else if( dir==HyperCube::FRONT && ( (((unsigned int)offset[Dim-1]+1)<<(maxDepth-depth))> slabEndAtMaxDepth ) ) key[Dim-1] = keyGenerator.cornerIndex( maxDepth , slabEndAtMaxDepth ); return key; }; - if( InteriorSlab( d , o ) ) SetLevelSet( keyGenerator , faceIndexFunctor , tree , d , o , slabValues[d].sliceValues(o) , slabValues[d].sliceValues(o+1) , slabValues[d].xSliceValues(o) , slabValues[d].sliceScratch(o) , slabValues[d].sliceScratch(o+1) , slabValues[d].xSliceScratch(o) , vertexStream , polygonStream , polygonMesh , addBarycenter , vertexOffset , flipOrientation ); + if( InteriorSlab( d , o ) ) SetLevelSet( keyGenerator , faceIndexFunctor , tree , d , o , slabValues[d].sliceValues(o) , slabValues[d].sliceValues(o+1) , slabValues[d].xSliceValues(o) , slabValues[d].sliceScratch(o) , slabValues[d].sliceScratch(o+1) , slabValues[d].xSliceScratch(o) , vertexStream , polygonStream , polygonMesh , addBarycenter , flipOrientation ); } if( !(o&1) && !boundary ) break; } @@ -2454,51 +2451,52 @@ struct LevelSetExtractor< Real , 3 > typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::Stats Stats; typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::Vertex Vertex; typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::TreeNode TreeNode; - using IndexedVertex = std::pair< node_index_type , Vertex >; + using OutputVertexStream = typename _LevelSetExtractor< HasData , Real , Dim , Data >::OutputVertexStream; + using OutputIndexedVertexStream = typename _LevelSetExtractor< HasData , Real , Dim , Data >::OutputIndexedVertexStream; template< unsigned int WeightDegree > using DensityEstimator = typename _LevelSetExtractor< HasData , Real , Dim , Data >::template DensityEstimator< WeightDegree >; template< unsigned int WeightDegree , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree > *densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputDataStream< Vertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree > *densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) { return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , tree , densityWeights , coefficients , isoValue , 0 , 0 , 1 , vertexStream , polygonStream , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation ); } template< unsigned int WeightDegree , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputDataStream< Vertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) { std::vector< std::vector< Real > > dValues; return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , tree , tree._maxDepth , densityWeights , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , NULL , NULL , dValues , dValues , false ); } template< unsigned int WeightDegree , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , int maxKeyDepth , const DensityEstimator< WeightDegree >* densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputDataStream< Vertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *backBoundary , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *frontBoundary , const std::vector< std::vector< Real > > &backDValues , const std::vector< std::vector< Real > > &frontDValues , bool copyTopology ) + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , int maxKeyDepth , const DensityEstimator< WeightDegree >* densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *backBoundary , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *frontBoundary , const std::vector< std::vector< Real > > &backDValues , const std::vector< std::vector< Real > > &frontDValues , bool copyTopology ) { static const unsigned int DataSig = FEMDegreeAndBType< 0 , BOUNDARY_FREE >::Signature; const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data = NULL; Data zeroData = 0; - return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputDataStream< Vertex > , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , backBoundary , frontBoundary , backDValues , frontDValues , copyTopology ); + return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputVertexStream , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , backBoundary , frontBoundary , backDValues , frontDValues , copyTopology ); } template< unsigned int WeightDegree , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree > *densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputDataStream< IndexedVertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree > *densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputIndexedVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) { return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , tree , densityWeights , coefficients , isoValue , 0 , 0 , 1 , vertexStream , polygonStream , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation ); } template< unsigned int WeightDegree , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputDataStream< IndexedVertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputIndexedVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) { std::vector< std::vector< Real > > dValues; return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , tree , tree._maxDepth , densityWeights , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , NULL , NULL , dValues , dValues , false ); } template< unsigned int WeightDegree , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , int maxKeyDepth , const DensityEstimator< WeightDegree >* densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputDataStream< IndexedVertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *backBoundary , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *frontBoundary , const std::vector< std::vector< Real > > &backDValues , const std::vector< std::vector< Real > > &frontDValues , bool copyTopology ) + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , int maxKeyDepth , const DensityEstimator< WeightDegree >* densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputIndexedVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *backBoundary , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *frontBoundary , const std::vector< std::vector< Real > > &backDValues , const std::vector< std::vector< Real > > &frontDValues , bool copyTopology ) { static const unsigned int DataSig = FEMDegreeAndBType< 0 , BOUNDARY_FREE >::Signature; const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data = NULL; Data zeroData = 0; - return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputDataStream< IndexedVertex > , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , backBoundary , frontBoundary , backDValues , frontDValues , copyTopology ); + return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputIndexedVertexStream , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , backBoundary , frontBoundary , backDValues , frontDValues , copyTopology ); } }; @@ -2510,44 +2508,45 @@ struct LevelSetExtractor< Real , 3 , Data > typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::Stats Stats; typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::Vertex Vertex; typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::TreeNode TreeNode; - using IndexedVertex = std::pair< node_index_type , Vertex >; + using OutputVertexStream = typename _LevelSetExtractor< HasData , Real , Dim , Data >::OutputVertexStream; + using OutputIndexedVertexStream = typename _LevelSetExtractor< HasData , Real , Dim , Data >::OutputIndexedVertexStream; template< unsigned int WeightDegree > using DensityEstimator = typename _LevelSetExtractor< HasData , Real , Dim , Data >::template DensityEstimator< WeightDegree >; template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputDataStream< Vertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) { return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , 0 , 0 , 1 , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation ); } template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputDataStream< Vertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) { std::vector< std::vector< Real > > dValues; return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , tree._maxDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , NULL , NULL , dValues , dValues , false ); } template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , int maxKeyDepth , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputDataStream< Vertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *backBoundary , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *frontBoundary , const std::vector< std::vector< Real > > &backDValues , const std::vector< std::vector< Real > > &frontDValues , bool copyTopology ) + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , int maxKeyDepth , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *backBoundary , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *frontBoundary , const std::vector< std::vector< Real > > &backDValues , const std::vector< std::vector< Real > > &frontDValues , bool copyTopology ) { - return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputDataStream< Vertex > , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , backBoundary , frontBoundary , backDValues , frontDValues , copyTopology ); + return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputVertexStream , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , backBoundary , frontBoundary , backDValues , frontDValues , copyTopology ); } template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputDataStream< IndexedVertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputIndexedVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) { return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , 0 , 0 , 1 , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation ); } template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputDataStream< IndexedVertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputIndexedVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) { std::vector< std::vector< Real > > dValues; return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , tree._maxDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , NULL , NULL , dValues , dValues , false ); } template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , int maxKeyDepth , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputDataStream< IndexedVertex > &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *backBoundary , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *frontBoundary , const std::vector< std::vector< Real > > &backDValues , const std::vector< std::vector< Real > > &frontDValues , bool copyTopology ) + static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , int maxKeyDepth , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputIndexedVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *backBoundary , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *frontBoundary , const std::vector< std::vector< Real > > &backDValues , const std::vector< std::vector< Real > > &frontDValues , bool copyTopology ) { - return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputDataStream< IndexedVertex > , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , backBoundary , frontBoundary , backDValues , frontDValues , copyTopology ); + return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputIndexedVertexStream , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , backBoundary , frontBoundary , backDValues , frontDValues , copyTopology ); } }; diff --git a/Src/FEMTree.h b/Src/FEMTree.h index 58d20cb7..7861c530 100644 --- a/Src/FEMTree.h +++ b/Src/FEMTree.h @@ -2998,7 +2998,7 @@ namespace PoissonRecon struct InputPointStream { typedef Data DataType; - typedef VectorTypeUnion< Real , Point< Real , Dim > , Data > PointAndDataType; + typedef DirectSum< Real , Point< Real , Dim > , Data > PointAndDataType; typedef InputDataStream< PointAndDataType > StreamType; static Point< Real , Dim > &GetPoint( PointAndDataType &pd ){ return pd.template get<0>(); } static const Point< Real , Dim > &GetPoint( const PointAndDataType &pd ){ return pd.template get<0>(); } @@ -3019,7 +3019,7 @@ namespace PoissonRecon struct OutputPointStream { typedef Data DataType; - typedef VectorTypeUnion< Real , Point< Real , Dim > , Data > PointAndDataType; + typedef DirectSum< Real , Point< Real , Dim > , Data > PointAndDataType; typedef OutputDataStream< PointAndDataType > StreamType; static Point< Real , Dim > &GetPoint( PointAndDataType &pd ){ return pd.template get<0>(); } static const Point< Real , Dim > &GetPoint( const PointAndDataType &pd ){ return pd.template get<0>(); } @@ -3034,10 +3034,10 @@ namespace PoissonRecon std::vector< node_index_type > _nodeToIndexMap; }; - template< typename AuxData , typename PointStream > - static size_t Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , PointStream &pointStream , AuxData zeroData , int maxDepth , std::vector< PointSample >& samplePoints , std::vector< AuxData > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , AuxData & ) > ProcessData = []( const Point< Real , Dim > & , AuxData & ){ return (Real)1.; } ); - template< typename AuxData , typename PointStream > - static size_t Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , PointStream &pointStream , AuxData zeroData , int maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , std::vector< PointSample >& samplePoints , std::vector< AuxData > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , AuxData & ) > ProcessData = []( const Point< Real , Dim > & , AuxData & ){ return (Real)1.; } ); + template< typename AuxData > + static size_t Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , InputDataStream< Point< Real , Dim > , AuxData > &pointStream , AuxData zeroData , int maxDepth , std::vector< PointSample >& samplePoints , std::vector< AuxData > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , AuxData & ) > ProcessData = []( const Point< Real , Dim > & , AuxData & ){ return (Real)1.; } ); + template< typename AuxData > + static size_t Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , InputDataStream< Point< Real , Dim > , AuxData > &pointStream , AuxData zeroData , int maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , std::vector< PointSample >& samplePoints , std::vector< AuxData > &sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , AuxData & ) > ProcessData = []( const Point< Real , Dim > & , AuxData & ){ return (Real)1.; } ); // Initialize the tree using simplices static void Initialize( FEMTreeNode& root , const std::vector< Point< Real , Dim > >& vertices , const std::vector< SimplexIndex< Dim-1 , node_index_type > >& simplices , int maxDepth , std::vector< PointSample >& samples , bool mergeNodeSamples , std::vector< Allocator< FEMTreeNode > * > &nodeAllocators , std::function< void ( FEMTreeNode& ) > NodeInitializer ); diff --git a/Src/FEMTree.inl b/Src/FEMTree.inl index 5453be22..0ae77e94 100644 --- a/Src/FEMTree.inl +++ b/Src/FEMTree.inl @@ -1089,25 +1089,49 @@ void FEMTree< Dim , Real >::updateExtrapolatedDataField( SparseNodeData< Project { Allocator< FEMTreeNode > *nodeAllocator = nodeAllocators.size() ? nodeAllocators[0] : NULL; LocalDepth maxDepth = _spaceRoot->maxDepth(); - PointSupportKey< IsotropicUIntPack< Dim , DensityDegree > > densityKey; - PointSupportKey< IsotropicUIntPack< Dim , FEMSignature< DataSig >::Degree > > dataKey; - densityKey.set( _localToGlobal( maxDepth ) ) , dataKey.set( _localToGlobal( maxDepth ) ); - for( node_index_type i=0 ; i<(node_index_type)sampleNum ; i++ ) + if constexpr( CreateNodes ) { - const PointSample &sampleAndNode = sampleFunctor(i); - const ProjectiveData< Point< Real , Dim > , Real >& sample = sampleAndNode.sample; - const Data& data = sampleDataFunctor(i); - Point< Real , Dim > p = sample.weight==0 ? sample.data : sample.data / sample.weight; - if( !_InBounds(p) ) + PointSupportKey< IsotropicUIntPack< Dim , DensityDegree > > densityKey; + PointSupportKey< IsotropicUIntPack< Dim , FEMSignature< DataSig >::Degree > > dataKey; + densityKey.set( _localToGlobal( maxDepth ) ) , dataKey.set( _localToGlobal( maxDepth ) ); + for( node_index_type i=0 ; i<(node_index_type)sampleNum ; i++ ) { - WARN( "Point is out of bounds" ); - continue; + const PointSample &sampleAndNode = sampleFunctor(i); + const ProjectiveData< Point< Real , Dim > , Real >& sample = sampleAndNode.sample; + const Data& data = sampleDataFunctor(i); + Point< Real , Dim > p = sample.weight==0 ? sample.data : sample.data / sample.weight; + if( !_InBounds(p) ) + { + WARN( "Point is out of bounds" ); + continue; + } + if( nearest ) _nearestMultiSplatPointData< DensityDegree >( density , (FEMTreeNode*)sampleAndNode.node , p , ProjectiveData< Data , Real >( data , sample.weight ) , dataField , densityKey , 2 ); + else _multiSplatPointData< CreateNodes , false , DensityDegree >( nodeAllocator , density , (FEMTreeNode*)sampleAndNode.node , p , ProjectiveData< Data , Real >( data , sample.weight ) , dataField , densityKey , dataKey , 2 ); } - if( nearest ) _nearestMultiSplatPointData< DensityDegree >( density , (FEMTreeNode*)sampleAndNode.node , p , ProjectiveData< Data , Real >( data , sample.weight ) , dataField , densityKey , 2 ); - else _multiSplatPointData< CreateNodes , false , DensityDegree >( nodeAllocator , density , (FEMTreeNode*)sampleAndNode.node , p , ProjectiveData< Data , Real >( data , sample.weight ) , dataField , densityKey , dataKey , 2 ); } -} + else + { + std::vector< PointSupportKey< IsotropicUIntPack< Dim , DensityDegree > > > densityKeys( ThreadPool::NumThreads() ); + std::vector< PointSupportKey< IsotropicUIntPack< Dim , FEMSignature< DataSig >::Degree > > > dataKeys( ThreadPool::NumThreads() ); + for( unsigned int i=0 ; i > &densityKey = densityKeys[thread]; + PointSupportKey< IsotropicUIntPack< Dim , FEMSignature< DataSig >::Degree > > &dataKey = dataKeys[thread]; + + const PointSample &sampleAndNode = sampleFunctor(i); + const ProjectiveData< Point< Real , Dim > , Real >& sample = sampleAndNode.sample; + const Data& data = sampleDataFunctor(i); + Point< Real , Dim > p = sample.weight==0 ? sample.data : sample.data / sample.weight; + if( !_InBounds(p) ) WARN( "Point is out of bounds" ); + else + { + if( nearest ) _nearestMultiSplatPointData< DensityDegree >( density , (FEMTreeNode*)sampleAndNode.node , p , ProjectiveData< Data , Real >( data , sample.weight ) , dataField , densityKey , 2 ); + else _multiSplatPointData< CreateNodes , false , DensityDegree >( nodeAllocator , density , (FEMTreeNode*)sampleAndNode.node , p , ProjectiveData< Data , Real >( data , sample.weight ) , dataField , densityKey , dataKey , 2 ); + } + } ); + }} template< unsigned int Dim , class Real > template< unsigned int MaxDegree > diff --git a/Src/Geometry.h b/Src/Geometry.h index 5cb2f81f..dbdb5fb1 100644 --- a/Src/Geometry.h +++ b/Src/Geometry.h @@ -62,7 +62,7 @@ namespace PoissonRecon template< typename Real > EmptyVectorType< Real > operator * ( Real s , EmptyVectorType< Real > v ){ return v*s; } template< typename _Real , typename ... VectorTypes > - struct VectorTypeUnion + struct DirectSum { protected: typedef std::tuple< VectorTypes ... > _VectorTuple; @@ -72,19 +72,19 @@ namespace PoissonRecon template< unsigned int I > VectorType< I >& get( void ) { return std::get< I >( _vectorTypeTuple ); } template< unsigned int I > const VectorType< I >& get( void ) const { return std::get< I >( _vectorTypeTuple ); } - VectorTypeUnion& operator += ( const VectorTypeUnion& p ){ _add<0>( p ) ; return *this; } - VectorTypeUnion& operator -= ( const VectorTypeUnion& p ){ _sub<0>( p ) ; return *this; } - VectorTypeUnion& operator *= ( Real s ) { _mul<0>( s ) ; return *this; } - VectorTypeUnion& operator /= ( Real s ) { _div<0>( s ) ; return *this; } - VectorTypeUnion operator + ( const VectorTypeUnion& p ) const { VectorTypeUnion _p = *this ; _p += p ; return _p; } - VectorTypeUnion operator - ( const VectorTypeUnion& p ) const { VectorTypeUnion _p = *this ; _p -= p ; return _p; } - VectorTypeUnion operator * ( Real s ) const { VectorTypeUnion _p = *this ; _p *= s ; return _p; } - VectorTypeUnion operator / ( Real s ) const { VectorTypeUnion _p = *this ; _p /= s ; return _p; } + DirectSum& operator += ( const DirectSum& p ){ _add<0>( p ) ; return *this; } + DirectSum& operator -= ( const DirectSum& p ){ _sub<0>( p ) ; return *this; } + DirectSum& operator *= ( Real s ) { _mul<0>( s ) ; return *this; } + DirectSum& operator /= ( Real s ) { _div<0>( s ) ; return *this; } + DirectSum operator + ( const DirectSum& p ) const { DirectSum _p = *this ; _p += p ; return _p; } + DirectSum operator - ( const DirectSum& p ) const { DirectSum _p = *this ; _p -= p ; return _p; } + DirectSum operator * ( Real s ) const { DirectSum _p = *this ; _p *= s ; return _p; } + DirectSum operator / ( Real s ) const { DirectSum _p = *this ; _p /= s ; return _p; } - VectorTypeUnion( void ){} - VectorTypeUnion( const VectorTypes & ... vectors ){ _set< 0 >( vectors ... ); } + DirectSum( void ){} + DirectSum( const VectorTypes & ... vectors ){ _set< 0 >( vectors ... ); } - friend std::ostream &operator << ( std::ostream &os , const VectorTypeUnion &v ) + friend std::ostream &operator << ( std::ostream &os , const DirectSum &v ) { os << "{ "; v._streamOut< 0 >( os ); @@ -95,10 +95,10 @@ namespace PoissonRecon std::tuple< VectorTypes ... > _vectorTypeTuple; template< unsigned int I , typename _Vector , typename ... _Vectors > void _set( const _Vector &vector , const _Vectors & ... vectors ){ get< I >() = vector ; _set< I+1 >( vectors ... ); } template< unsigned int I , typename _Vector > void _set( const _Vector &vector ){ get< I >() = vector ; } - template< unsigned int I > typename std::enable_if< I!=sizeof...(VectorTypes) >::type _add( const VectorTypeUnion& p ){ get() += p.get() ; _add< I+1 >( p ); } - template< unsigned int I > typename std::enable_if< I==sizeof...(VectorTypes) >::type _add( const VectorTypeUnion& p ){ } - template< unsigned int I > typename std::enable_if< I!=sizeof...(VectorTypes) >::type _sub( const VectorTypeUnion& p ){ get() -= p.get() ; _sub< I+1 >( p ); } - template< unsigned int I > typename std::enable_if< I==sizeof...(VectorTypes) >::type _sub( const VectorTypeUnion& p ){ } + template< unsigned int I > typename std::enable_if< I!=sizeof...(VectorTypes) >::type _add( const DirectSum& p ){ get() += p.get() ; _add< I+1 >( p ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(VectorTypes) >::type _add( const DirectSum& p ){ } + template< unsigned int I > typename std::enable_if< I!=sizeof...(VectorTypes) >::type _sub( const DirectSum& p ){ get() -= p.get() ; _sub< I+1 >( p ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(VectorTypes) >::type _sub( const DirectSum& p ){ } template< unsigned int I > typename std::enable_if< I!=sizeof...(VectorTypes) >::type _mul( Real s ){ get() *= s ; _mul< I+1 >( s ); } template< unsigned int I > typename std::enable_if< I==sizeof...(VectorTypes) >::type _mul( Real s ){ } template< unsigned int I > typename std::enable_if< I!=sizeof...(VectorTypes) >::type _div( Real s ){ get() /= s ; _div< I+1 >( s ); } @@ -107,7 +107,7 @@ namespace PoissonRecon template< unsigned int I > typename std::enable_if< I==sizeof...(VectorTypes) >::type _streamOut( std::ostream &os ) const { } }; template< typename Real , typename ... Vectors > - VectorTypeUnion< Real , Vectors ... > operator * ( Real s , VectorTypeUnion< Real , Vectors ... > vu ){ return vu * s; } + DirectSum< Real , Vectors ... > operator * ( Real s , DirectSum< Real , Vectors ... > vu ){ return vu * s; } template< class Real > Real Random( void ); diff --git a/Src/PointExtent.h b/Src/PointExtent.h index 1522c01f..d131ac90 100644 --- a/Src/PointExtent.h +++ b/Src/PointExtent.h @@ -31,6 +31,7 @@ DAMAGE. #include #include "Geometry.h" +#include "DataStream.h" namespace PoissonRecon { @@ -69,12 +70,17 @@ namespace PoissonRecon template< typename Real , unsigned int Dim , bool ExtendedAxes > const Frame< Real , Dim , ExtendedAxes > Extent< Real , Dim , ExtendedAxes >::_Frame; + template< class Real , unsigned int Dim , bool ExtendedAxes , typename ... Data > + Extent< Real , Dim , ExtendedAxes > GetExtent( InputDataStream< Point< Real , Dim > , Data ... > &stream , Data ... data ); + template< class Real , unsigned int Dim > - XForm< Real , Dim+1 > GetBoundingBoxXForm( Point< Real , Dim > min , Point< Real , Dim > max , Real scaleFactor , bool rotate=true ); + XForm< Real , Dim+1 > GetXForm( Point< Real , Dim > min , Point< Real , Dim > max , Real scaleFactor , bool rotate=true ); template< class Real , unsigned int Dim , bool ExtendedAxes > - XForm< Real , Dim+1 > GetBoundingBoxXForm( const Extent< Real , Dim , ExtendedAxes > &extent , Real scaleFactor , unsigned int dir ); + XForm< Real , Dim+1 > GetXForm( const Extent< Real , Dim , ExtendedAxes > &extent , Real scaleFactor , unsigned int dir ); + template< class Real , unsigned int Dim , bool ExtendedAxes , typename ... Data > + XForm< Real , Dim+1 > GetXForm( InputDataStream< Point< Real , Dim > , Data ... > &stream , Data ... data , Real scaleFactor , unsigned int dir ); #include "PointExtent.inl" } diff --git a/Src/PointExtent.inl b/Src/PointExtent.inl index f06c6c98..3d4fc2d7 100644 --- a/Src/PointExtent.inl +++ b/Src/PointExtent.inl @@ -31,7 +31,7 @@ DAMAGE. // GetBoundingBox // //////////////////// template< class Real , unsigned int Dim > -XForm< Real , Dim+1 > GetBoundingBoxXForm( Point< Real , Dim > min , Point< Real , Dim > max , Real scaleFactor , bool rotate ) +XForm< Real , Dim+1 > GetXForm( Point< Real , Dim > min , Point< Real , Dim > max , Real scaleFactor , bool rotate ) { Point< Real , Dim > center = ( max + min ) / 2; Real scale = max[0] - min[0]; @@ -51,7 +51,7 @@ XForm< Real , Dim+1 > GetBoundingBoxXForm( Point< Real , Dim > min , Point< Real } template< class Real , unsigned int Dim , bool ExtendedAxes > -XForm< Real , Dim+1 > GetBoundingBoxXForm( const Extent< Real , Dim , ExtendedAxes > &extent , Real scaleFactor , unsigned int dir ) +XForm< Real , Dim+1 > GetXForm( const Extent< Real , Dim , ExtendedAxes > &extent , Real scaleFactor , unsigned int dir ) { using _Extent = Extent< Real , Dim , ExtendedAxes >; bool rotate = ( dir >= _Extent::DirectionN ); @@ -75,8 +75,7 @@ XForm< Real , Dim+1 > GetBoundingBoxXForm( const Extent< Real , Dim , ExtendedAx bBox[0][d] = extent[ frame[d] ].first; bBox[1][d] = extent[ frame[d] ].second; } - - return GetBoundingBoxXForm( bBox[0] , bBox[1] , scaleFactor , rotate ) * R; + return GetXForm( bBox[0] , bBox[1] , scaleFactor , rotate ) * R; } /////////// @@ -161,3 +160,18 @@ std::ostream &operator << ( std::ostream &os , const Extent< Real , Dim , Extend } return os; } + +template< class Real , unsigned int Dim , bool ExtendedAxes , typename ... Data > +Extent< Real , Dim , ExtendedAxes > GetExtent( InputDataStream< Point< Real , Dim > , Data ... > &stream , Data ... data ) +{ + Point< Real, Dim > p; + Extent< Real , Dim , ExtendedAxes > e; + while( stream.read( p , data... ) ) e.add(p); + return e; +} + +template< class Real , unsigned int Dim , bool ExtendedAxes , typename ... Data > +XForm< Real , Dim+1 > GetXForm( InputDataStream< Point< Real , Dim > , Data ... > &stream , Data ... data , Real scaleFactor , unsigned int dir ) +{ + return GetXForm( GetExtent< Real , Dim , ExtendedAxes >( stream , data... ) , scaleFactor , dir ); +} diff --git a/Src/PointInterpolant.cpp b/Src/PointInterpolant.cpp index 3e1064fb..2a90c2ee 100644 --- a/Src/PointInterpolant.cpp +++ b/Src/PointInterpolant.cpp @@ -233,9 +233,9 @@ XForm< Real , Dim+1 > GetPointXForm( InputPointStream< Real , Dim , FunctionValu template< unsigned int Dim , typename Real , typename PointSampleData > struct ConstraintDual; template< unsigned int Dim , typename Real > -struct ConstraintDual< Dim , Real , VectorTypeUnion< Real , Real > > +struct ConstraintDual< Dim , Real , DirectSum< Real , Real > > { - typedef VectorTypeUnion< Real , Real > PointSampleData; + typedef DirectSum< Real , Real > PointSampleData; Real vWeight; ConstraintDual( Real v) : vWeight(v){ } CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim > &p , const PointSampleData& data ) const @@ -248,9 +248,9 @@ struct ConstraintDual< Dim , Real , VectorTypeUnion< Real , Real > > }; template< unsigned int Dim , typename Real > -struct ConstraintDual< Dim , Real , VectorTypeUnion< Real , Point< Real , Dim > > > +struct ConstraintDual< Dim , Real , DirectSum< Real , Point< Real , Dim > > > { - typedef VectorTypeUnion< Real , Point< Real , Dim > > PointSampleData; + typedef DirectSum< Real , Point< Real , Dim > > PointSampleData; Real gWeight; ConstraintDual( Real g ) : gWeight(g) { } CumulativeDerivativeValues< Real , Dim , 1 > operator()( const Point< Real , Dim >& p , const PointSampleData& data ) const @@ -265,33 +265,33 @@ struct ConstraintDual< Dim , Real , VectorTypeUnion< Real , Point< Real , Dim > template< unsigned int Dim , typename Real , typename TotalPointSampleData > struct SystemDual; template< unsigned int Dim , typename Real > -struct SystemDual< Dim , Real , VectorTypeUnion< Real , Real > > +struct SystemDual< Dim , Real , DirectSum< Real , Real > > { CumulativeDerivativeValues< Real , Dim , 0 > weight; SystemDual( Real v ){ weight[0] = v; } - CumulativeDerivativeValues< Real , Dim , 0 > operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Real > &data , const CumulativeDerivativeValues< Real , Dim , 0 > &dValues ) const + CumulativeDerivativeValues< Real , Dim , 0 > operator()( Point< Real , Dim > p , const DirectSum< Real , Real > &data , const CumulativeDerivativeValues< Real , Dim , 0 > &dValues ) const { return dValues * weight; } - CumulativeDerivativeValues< double , Dim , 0 > operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Real > &data , const CumulativeDerivativeValues< double , Dim , 0 > &dValues ) const + CumulativeDerivativeValues< double , Dim , 0 > operator()( Point< Real , Dim > p , const DirectSum< Real , Real > &data , const CumulativeDerivativeValues< double , Dim , 0 > &dValues ) const { return dValues * weight; }; }; template< unsigned int Dim > -struct SystemDual< Dim , double , VectorTypeUnion< double , double > > +struct SystemDual< Dim , double , DirectSum< double , double > > { typedef double Real; CumulativeDerivativeValues< Real , Dim , 0 > weight; SystemDual( Real v ){ weight[0] = v; } - CumulativeDerivativeValues< Real , Dim , 0 > operator()( Point< Real , Dim > p , const VectorTypeUnion< double , double > &data , const CumulativeDerivativeValues< Real , Dim , 0 > &dValues ) const + CumulativeDerivativeValues< Real , Dim , 0 > operator()( Point< Real , Dim > p , const DirectSum< double , double > &data , const CumulativeDerivativeValues< Real , Dim , 0 > &dValues ) const { return dValues * weight; } }; template< unsigned int Dim , typename Real > -struct SystemDual< Dim , Real , VectorTypeUnion< Real , Point< Real , Dim > > > +struct SystemDual< Dim , Real , DirectSum< Real , Point< Real , Dim > > > { CumulativeDerivativeValues< Real , Dim , 1 > weight; SystemDual( Real g ) @@ -299,17 +299,17 @@ struct SystemDual< Dim , Real , VectorTypeUnion< Real , Point< Real , Dim > > > weight[0] = 0; for( int d=0 ; d operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Point< Real , Dim > > &data , const CumulativeDerivativeValues< Real , Dim , 1 > &dValues ) const + CumulativeDerivativeValues< Real , Dim , 1 > operator()( Point< Real , Dim > p , const DirectSum< Real , Point< Real , Dim > > &data , const CumulativeDerivativeValues< Real , Dim , 1 > &dValues ) const { return dValues * weight; } - CumulativeDerivativeValues< double , Dim , 1 > operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Point< Real , Dim > > &data , const CumulativeDerivativeValues< double , Dim , 1 > &dValues ) const + CumulativeDerivativeValues< double , Dim , 1 > operator()( Point< Real , Dim > p , const DirectSum< Real , Point< Real , Dim > > &data , const CumulativeDerivativeValues< double , Dim , 1 > &dValues ) const { return dValues * weight; }; }; template< unsigned int Dim > -struct SystemDual< Dim , double , VectorTypeUnion< double , Point< double , Dim > > > +struct SystemDual< Dim , double , DirectSum< double , Point< double , Dim > > > { typedef double Real; CumulativeDerivativeValues< Real , Dim , 1 > weight; @@ -318,7 +318,7 @@ struct SystemDual< Dim , double , VectorTypeUnion< double , Point< double , Dim weight[0] = 0; for( int d=0 ; d operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Point< Real , Dim > > &data , const CumulativeDerivativeValues< Real , Dim , 1 > &dValues ) const + CumulativeDerivativeValues< Real , Dim , 1 > operator()( Point< Real , Dim > p , const DirectSum< Real , Point< Real , Dim > > &data , const CumulativeDerivativeValues< Real , Dim , 1 > &dValues ) const { return dValues * weight; } @@ -353,25 +353,21 @@ void ExtractLevelSet } // A description of the output vertex information - using VInfo = Reconstructor::OutputLevelSetVertexInfo< Real , Dim , false , false >; + using VInfo = Reconstructor::OutputVertexInfo< Real , Dim , false , false >; // A factory generating the output vertices using Factory = typename VInfo::Factory; Factory factory = VInfo::GetFactory(); // A backing stream for the vertices - Reconstructor::OutputInputFactoryTypeStream< Factory , false > vertexStream( factory , false ); - Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( false , true ); + Reconstructor::OutputInputFactoryTypeStream< Real , Dim , Factory , false , true > vertexStream( factory , VInfo::Convert ); + Reconstructor::OutputInputFaceStream< Dim-1 , false , true > faceStream; typename LevelSetExtractor< Real , Dim >::Stats stats; - { - // The wrapper converting native to output types - typename VInfo::StreamWrapper _vertexStream( vertexStream ); - Reconstructor::TransformedOutputLevelSetVertexStream< Real , Dim > __vertexStream( unitCubeToModel , _vertexStream ); + Reconstructor::TransformedOutputLevelSetVertexStream< Real , Dim > _vertexStream( unitCubeToModel , vertexStream ); - // Extract the mesh - stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< 0 >() , tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , solution , isoValue , __vertexStream , faceStream , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , false ); - } + // Extract the mesh + stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< 0 >() , tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , solution , isoValue , _vertexStream , faceStream , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , false ); if( Verbose.set ) { @@ -493,7 +489,7 @@ void Execute( UIntPack< FEMSigs ... > ) InputDataStream< InputSampleValueType > &stream; XForm< Real , Dim+1 > pointTransform; XInputPointValueStream( InputDataStream< InputSampleValueType > &stream , XForm< Real , Dim+1 > modelToUnitCube ) : stream(stream) , pointTransform( modelToUnitCube ){} - bool base_read( InputSampleValueType &s ) + bool read( InputSampleValueType &s ) { if( stream.read( s ) ){ s.template get<0>() = pointTransform * s.template get<0>() ; return true; } else return false; @@ -516,7 +512,7 @@ void Execute( UIntPack< FEMSigs ... > ) pointTransform = modelToUnitCube; gradientTransform = XForm< Real , Dim >( pointTransform ).inverse().transpose(); } - bool base_read( InputSampleGradientType &s ) + bool read( InputSampleGradientType &s ) { if( stream.read( s ) ) { @@ -701,7 +697,19 @@ void Execute( UIntPack< FEMSigs ... > ) auto ProcessData = []( const Point< Real , Dim > &p , FunctionValueType &d ){ return (Real)1.; }; FunctionValueType zeroValue = functionValueFactory(); typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; - pointValueCount = FEMTreeInitializer< Dim , Real >::template Initialize< FunctionValueType >( sid , tree.spaceRoot() , _pointStream , zeroValue , Depth.value , *valueSamples , *valueSampleData , true , tree.nodeAllocators.size() ? tree.nodeAllocators[0] : NULL , tree.initializer() , ProcessData ); + { + using ExternalType = std::tuple< Point< Real , Dim > , FunctionValueType >; + using InternalType = std::tuple< InputSampleValueType >; + auto converter = []( const InternalType &iType ) + { + ExternalType xType; + std::get< 0 >( xType ) = std::get< 0 >( iType ).template get<0>(); + std::get< 1 >( xType ) = std::get< 0 >( iType ).template get<1>(); + return xType; + }; + InputDataStreamConverter< InternalType , ExternalType > __pointStream( _pointStream , converter , InputSampleValueType( Point< Real , Dim >() , zeroValue ) ); + pointValueCount = FEMTreeInitializer< Dim , Real >::template Initialize< FunctionValueType >( sid , tree.spaceRoot() , __pointStream , zeroValue , Depth.value , *valueSamples , *valueSampleData , true , tree.nodeAllocators.size() ? tree.nodeAllocators[0] : NULL , tree.initializer() , ProcessData ); + } delete pointValueStream; } else pointValueCount = 0; @@ -713,7 +721,19 @@ void Execute( UIntPack< FEMSigs ... > ) auto ProcessData = []( const Point< Real , Dim > &p , FunctionGradientType &d ){ return (Real)1.; }; FunctionGradientType zeroGradient = functionGradientFactory(); typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; - pointGradientCount = FEMTreeInitializer< Dim , Real >::template Initialize< FunctionGradientType >( sid , tree.spaceRoot() , _pointStream , zeroGradient , Depth.value , *gradientSamples , *gradientSampleData , true , tree.nodeAllocators.size() ? tree.nodeAllocators[0] : NULL , tree.initializer() , ProcessData ); + { + using ExternalType = std::tuple< Point< Real , Dim > , FunctionGradientType >; + using InternalType = std::tuple< InputSampleGradientType >; + auto converter = []( const InternalType &iType ) + { + ExternalType xType; + std::get< 0 >( xType ) = std::get< 0 >( iType ).template get<0>(); + std::get< 1 >( xType ) = std::get< 0 >( iType ).template get<1>(); + return xType; + }; + InputDataStreamConverter< InternalType , ExternalType > __pointGradientStream( _pointStream , converter , InputSampleGradientType( Point< Real , Dim >() , zeroGradient ) ); + pointGradientCount = FEMTreeInitializer< Dim , Real >::template Initialize< FunctionGradientType >( sid , tree.spaceRoot() , __pointGradientStream , zeroGradient , Depth.value , *gradientSamples , *gradientSampleData , true , tree.nodeAllocators.size() ? tree.nodeAllocators[0] : NULL , tree.initializer() , ProcessData ); + } delete pointGradientStream; } else pointGradientCount = 0; diff --git a/Src/PointPartition.h b/Src/PointPartition.h index 43c75ba1..c441d76a 100644 --- a/Src/PointPartition.h +++ b/Src/PointPartition.h @@ -104,7 +104,7 @@ namespace PoissonRecon BufferedBinaryInputDataStream( const char *fileName , const InputFactory &factory , size_t bufferSize ); ~BufferedBinaryInputDataStream( void ); void reset( void ); - bool base_read( Data &d ); + bool read( Data &d ); protected: size_t _bufferSize , _current , _inBuffer , _elementSize; Pointer( char ) _buffer; @@ -120,7 +120,8 @@ namespace PoissonRecon BufferedBinaryOutputDataStream( const char *fileName , const OutputFactory &factory , size_t bufferSize ); ~BufferedBinaryOutputDataStream( void ); void reset( void ); - void base_write( const Data &d ); + size_t write( const Data &d ); + size_t size( void ) const; protected: size_t _bufferSize , _current , _elementSize; Pointer( char ) _buffer; diff --git a/Src/PointPartition.inl b/Src/PointPartition.inl index a36f00f6..cab02b5b 100644 --- a/Src/PointPartition.inl +++ b/Src/PointPartition.inl @@ -518,7 +518,7 @@ void BufferedBinaryInputDataStream< InputFactory >::reset( void ) } template< typename InputFactory > -bool BufferedBinaryInputDataStream< InputFactory >::base_read( Data &d ) +bool BufferedBinaryInputDataStream< InputFactory >::read( Data &d ) { if( _current==_inBuffer ) { @@ -570,7 +570,7 @@ void BufferedBinaryOutputDataStream< OutputFactory >::reset( void ) } template< typename OutputFactory > -void BufferedBinaryOutputDataStream< OutputFactory >::base_write( const Data &d ) +size_t BufferedBinaryOutputDataStream< OutputFactory >::write( const Data &d ) { if( _current==_bufferSize ) { @@ -578,5 +578,8 @@ void BufferedBinaryOutputDataStream< OutputFactory >::base_write( const Data &d _current = 0; } _factory.toBuffer( d , _buffer + _elementSize*_current ); - _current++; + return _current++; } + +template< typename OutputFactory > +size_t BufferedBinaryOutputDataStream< OutputFactory >::size( void ) const { return _current; } diff --git a/Src/PointPartitionClientServer.inl b/Src/PointPartitionClientServer.inl index 27d25457..5ef49a54 100644 --- a/Src/PointPartitionClientServer.inl +++ b/Src/PointPartitionClientServer.inl @@ -245,7 +245,7 @@ std::pair< PointPartition::PointSetInfo< Real , Dim > , PointPartition::Partitio SocketStream( clientSockets[c] ).read( _e ); e = e + _e; } - pointSetInfo.modelToUnitCube = PointExtent::GetBoundingBoxXForm( e , clientPartitionInfo.scale , clientPartitionInfo.sliceDir ); + pointSetInfo.modelToUnitCube = PointExtent::GetXForm( e , clientPartitionInfo.scale , clientPartitionInfo.sliceDir ); // Send the transformation to the clients for( unsigned int c=0 ; c , VertexFactory::Factory< Real , VertexFactory::NormalFactory< Real , Dim > , AuxDataFactory > > InputSampleFactory; typedef VertexFactory::Factory< Real , VertexFactory::NormalFactory< Real , Dim > , AuxDataFactory > InputSampleDataFactory; - typedef VectorTypeUnion< Real , Point< Real , Dim > , typename AuxDataFactory::VertexType > InputSampleDataType; - typedef VectorTypeUnion< Real , Point< Real , Dim > , InputSampleDataType > InputSampleType; + typedef DirectSum< Real , Point< Real , Dim > , typename AuxDataFactory::VertexType > InputSampleDataType; + typedef DirectSum< Real , Point< Real , Dim > , InputSampleDataType > InputSampleType; typedef InputDataStream< InputSampleType > InputPointStream; typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; using BoundaryData = std::conditional_t< Dim==3 , typename LevelSetExtractor< Real , 2 , Point< Real , 2 > >::TreeSliceValuesAndVertexPositions , char >; @@ -518,13 +518,25 @@ void Client< Real , Dim , BType , Degree >::_process1( const ClientReconstructio using MultiPointStream = MultiInputDataStream< typename InputSampleFactory::VertexType >; + using ExternalType = std::tuple< Point< Real , Dim > , InputSampleDataType >; + using InternalType = std::tuple< typename InputSampleFactory::VertexType >; + auto converter = []( const InternalType &iType ) + { + ExternalType xType; + std::get< 0 >( xType ) = std::get< 0 >( iType ).template get<0>(); + std::get< 1 >( xType ).template get<0>() = std::get< 0 >( iType ).template get<1>().template get<0>(); + std::get< 1 >( xType ).template get<1>() = std::get< 0 >( iType ).template get<1>().template get<1>(); + return xType; + }; + auto ProcessInteriorPointSlabs = [&]( typename FEMTreeInitializer< Dim , Real >::StreamInitializationData &sid , unsigned int start , unsigned int end ) { if( start==end ) return; MultiPointStream pointStream( &pointStreams[start-beginPaddedIndex] , end - start ); typename InputSampleDataFactory::VertexType zeroData = inputSampleDataFactory(); - if( clientReconInfo.confidence>0 ) pointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , pointStream , zeroData , clientReconInfo.reconstructionDepth , _samples , _sampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessDataWithConfidence ); - else pointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , pointStream , zeroData , clientReconInfo.reconstructionDepth , _samples , _sampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); + InputDataStreamConverter< InternalType , ExternalType > _pointStream( pointStream , converter , inputSampleFactory() ); + if( clientReconInfo.confidence>0 ) pointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , _samples , _sampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessDataWithConfidence ); + else pointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , _samples , _sampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); profiler.update(); }; auto ProcessPadPointSlabs = [&]( typename FEMTreeInitializer< Dim , Real >::StreamInitializationData &sid , unsigned int start , unsigned int end ) @@ -532,12 +544,13 @@ void Client< Real , Dim , BType , Degree >::_process1( const ClientReconstructio if( start==end ) return; MultiPointStream pointStream( &pointStreams[start-beginPaddedIndex] , end - start ); typename InputSampleDataFactory::VertexType zeroData = inputSampleDataFactory(); + InputDataStreamConverter< InternalType , ExternalType > _pointStream( pointStream , converter , inputSampleFactory() ); #ifdef ADAPTIVE_PADDING - if( clientReconInfo.confidence>0 ) paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , pointStream , zeroData , clientReconInfo.reconstructionDepth , pointDepthFunctor , _paddedSamples , _paddedSampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessDataWithConfidence ); - else paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , pointStream , zeroData , clientReconInfo.reconstructionDepth , pointDepthFunctor , _paddedSamples , _paddedSampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); + if( clientReconInfo.confidence>0 ) paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , pointDepthFunctor , _paddedSamples , _paddedSampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessDataWithConfidence ); + else paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , pointDepthFunctor , _paddedSamples , _paddedSampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); #else // !ADAPTIVE_PADDING - if( clientReconInfo.confidence>0 ) paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , pointStream , zeroData , clientReconInfo.reconstructionDepth , _paddedSamples , _paddedSampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessDataWithConfidence ); - else paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , pointStream , zeroData , clientReconInfo.reconstructionDepth , _paddedSamples , _paddedSampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); + if( clientReconInfo.confidence>0 ) paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , _paddedSamples , _paddedSampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessDataWithConfidence ); + else paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , _paddedSamples , _paddedSampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); #endif // ADAPTIVE_PADDING profiler.update(); }; @@ -549,18 +562,20 @@ void Client< Real , Dim , BType , Degree >::_process1( const ClientReconstructio if( idx>=beginIndex && idx0 ) pointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , pointStream , zeroData , clientReconInfo.reconstructionDepth , _samples , _sampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessDataWithConfidence ); - else pointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , pointStream , zeroData , clientReconInfo.reconstructionDepth , _samples , _sampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); + InputDataStreamConverter< InternalType , ExternalType > _pointStream( pointStream , converter , inputSampleFactory() ); + if( clientReconInfo.confidence>0 ) pointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , _samples , _sampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessDataWithConfidence ); + else pointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , _samples , _sampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); } else { typename InputSampleDataFactory::VertexType zeroData = inputSampleDataFactory(); + InputDataStreamConverter< InternalType , ExternalType > _pointStream( pointStream , converter , inputSampleFactory() ); #ifdef ADAPTIVE_PADDING - if( clientReconInfo.confidence>0 ) paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , pointStream , zeroData , clientReconInfo.reconstructionDepth , pointDepthFunctor , _paddedSamples , _paddedSampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessDataWithConfidence ); - else paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , pointStream , zeroData , clientReconInfo.reconstructionDepth , pointDepthFunctor , _paddedSamples , _paddedSampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); + if( clientReconInfo.confidence>0 ) paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , pointDepthFunctor , _paddedSamples , _paddedSampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessDataWithConfidence ); + else paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , pointDepthFunctor , _paddedSamples , _paddedSampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); #else // !ADAPTIVE_PADDING - if( clientReconInfo.confidence>0 ) paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( _tree.spaceRoot() , pointStream , zeroData , clientReconInfo.reconstructionDepth , _paddedSamples , _paddedSampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessDataWithConfidence ); - else paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( _tree.spaceRoot() , pointStream , zeroData , clientReconInfo.reconstructionDepth , _paddedSamples , _paddedSampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); + if( clientReconInfo.confidence>0 ) paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , _paddedSamples , _paddedSampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessDataWithConfidence ); + else paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , _paddedSamples , _paddedSampleData , true , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); #endif // ADAPTIVE_PADDING } profiler.update(); @@ -1251,24 +1266,21 @@ void Client< Real , Dim , BType , Degree >::_writeMeshWithData( const ClientReco // A description of the output vertex information - using VInfo = Reconstructor::OutputIndexedLevelSetVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactory >; + using VInfo = Reconstructor::OutputVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactory >; // A factory generating the output vertices using Factory = typename VInfo::Factory; Factory factory = VInfo::GetFactory( auxDataFactory ); // A backing stream for the vertices - Reconstructor::OutputInputFactoryTypeStream< Factory , true > vertexStream( factory , false ); - Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( false , true ); + Reconstructor::OutputInputFactoryTypeStream< Real , Dim , Factory , false , true , AuxData > vertexStream( factory , VInfo::Convert ); + Reconstructor::OutputInputFaceStream< Dim-1 , false , true > faceStream; typename LevelSetExtractor< Real , Dim , AuxData >::Stats stats; { - // The wrapper converting native to output types - typename VInfo::StreamWrapper _vertexStream( vertexStream ); - // The transformed stream - Reconstructor::TransformedOutputIndexedLevelSetVertexStream< Real , Dim , AuxData > __vertexStream( unitCubeToModel , _vertexStream ); + Reconstructor::TransformedOutputLevelSetVertexStream< Real , Dim , AuxData > __vertexStream( unitCubeToModel , vertexStream ); // Extract the mesh stats = LevelSetExtractor< Real , Dim , AuxData >::template Extract< Reconstructor::WeightDegree , DataSig > @@ -1308,8 +1320,7 @@ void Client< Real , Dim , BType , Degree >::_writeMeshWithData( const ClientReco // Write the mesh to a .ply file std::vector< std::string > noComments; vertexStream.reset(); - IndexedInputDataStream< node_index_type , typename Factory::VertexType > vStream( vertexStream ); - PLY::Write< Factory , node_index_type , Real , Dim >( outFileName.c_str() , factory , vertexStream.size() , faceStream.size() , vStream , faceStream , PLY_BINARY_NATIVE , noComments ); + PLY::Write< Factory , node_index_type , Real , Dim >( outFileName.c_str() , factory , vertexStream.size() , faceStream.size() , vertexStream , faceStream , PLY_BINARY_NATIVE , noComments ); } template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index 32629c0b..92aafb45 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -201,10 +201,9 @@ void ShowUsage(char* ex) printf( "\t[--%s]\n" , Verbose.name ); } -template< typename Real , unsigned int Dim , unsigned int FEMSig , bool HasGradients , bool HasDensity , typename ... AuxDataFactories > +template< typename Real , unsigned int Dim , unsigned int FEMSig , bool HasGradients , bool HasDensity , bool InCore , typename ... AuxDataFactories > void WriteMesh ( - bool inCore , Reconstructor::Implicit< Real , Dim , FEMSig , typename AuxDataFactories::VertexType ... > &implicit , const Reconstructor::LevelSetExtractionParameters &meParams , std::string fileName , @@ -213,29 +212,66 @@ void WriteMesh ) { // A description of the output vertex information - using VInfo = Reconstructor::OutputIndexedLevelSetVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactories ... >; + using VInfo = Reconstructor::OutputVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactories ... >; // A factory generating the output vertices using Factory = typename VInfo::Factory; Factory factory = VInfo::GetFactory( factories... ); - // A backing stream for the vertices - Reconstructor::OutputInputFactoryTypeStream< Factory , true > vertexStream( factory , inCore ); - Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( inCore , true ); + Reconstructor::OutputInputFactoryTypeStream< Real , Dim , Factory , InCore , true , typename AuxDataFactories::VertexType... > vertexStream( factory , VInfo::Convert ); + Reconstructor::OutputInputFaceStream< Dim-1 , InCore , true > faceStream; - { - // The wrapper converting native to output types - typename VInfo::StreamWrapper _vertexStream( vertexStream ); - - // Extract the level set - implicit.extractLevelSet( _vertexStream , faceStream , meParams ); - } + implicit.extractLevelSet( vertexStream , faceStream , meParams ); // Write the mesh to a .ply file std::vector< std::string > noComments; vertexStream.reset(); - IndexedInputDataStream< node_index_type , typename Factory::VertexType > vStream( vertexStream ); - PLY::Write< Factory , node_index_type , Real , Dim >( fileName , factory , vertexStream.size() , faceStream.size() , vStream , faceStream , ascii ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); + PLY::Write< Factory , node_index_type , Real , Dim >( fileName , factory , vertexStream.size() , faceStream.size() , vertexStream , faceStream , ascii ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); +} + +template< typename Real , unsigned int Dim , unsigned int FEMSig , bool HasDensity , bool InCore , typename ... AuxDataFactories > +void WriteMesh +( + bool hasGradients , + Reconstructor::Implicit< Real , Dim , FEMSig , typename AuxDataFactories::VertexType ... > &implicit , + const Reconstructor::LevelSetExtractionParameters &meParams , + std::string fileName , + bool ascii , + const AuxDataFactories& ... factories +) +{ + if( hasGradients ) return WriteMesh< Real , Dim, FEMSig , true , HasDensity , InCore , AuxDataFactories ... >( implicit , meParams , fileName , ascii , factories... ); + else return WriteMesh< Real , Dim, FEMSig , false , HasDensity , InCore , AuxDataFactories ... >( implicit , meParams , fileName , ascii , factories... ); +} + +template< typename Real , unsigned int Dim , unsigned int FEMSig , bool InCore , typename ... AuxDataFactories > +void WriteMesh +( + bool hasGradients , bool hasDensity , + Reconstructor::Implicit< Real , Dim , FEMSig , typename AuxDataFactories::VertexType ... > &implicit , + const Reconstructor::LevelSetExtractionParameters &meParams , + std::string fileName , + bool ascii , + const AuxDataFactories& ... factories +) +{ + if( hasDensity ) return WriteMesh< Real , Dim, FEMSig , true , InCore , AuxDataFactories ... >( hasGradients , implicit , meParams , fileName , ascii , factories... ); + else return WriteMesh< Real , Dim, FEMSig , false , InCore , AuxDataFactories ... >( hasGradients , implicit , meParams , fileName , ascii , factories... ); +} + +template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... AuxDataFactories > +void WriteMesh +( + bool hasGradients , bool hasDensity , bool inCore , + Reconstructor::Implicit< Real , Dim , FEMSig , typename AuxDataFactories::VertexType ... > &implicit , + const Reconstructor::LevelSetExtractionParameters &meParams , + std::string fileName , + bool ascii , + const AuxDataFactories& ... factories +) +{ + if( inCore ) return WriteMesh< Real , Dim, FEMSig , true , AuxDataFactories ... >( hasGradients , hasDensity , implicit , meParams , fileName , ascii , factories... ); + else return WriteMesh< Real , Dim, FEMSig , false , AuxDataFactories ... >( hasGradients , hasDensity , implicit , meParams , fileName , ascii , factories... ); } template< class Real , unsigned int Dim , unsigned int FEMSig , typename AuxDataFactory > @@ -384,25 +420,25 @@ void Execute( const AuxDataFactory &auxDataFactory ) } // A wrapper class to realize InputDataStream< SampleType > as an InputSampleStream - struct _InputSampleStream : public Reconstructor::InputSampleStream< Real , Dim > + struct _InputOrientedSampleStream : public Reconstructor::InputOrientedSampleStream< Real , Dim > { typedef Reconstructor::Normal< Real , Dim > DataType; - typedef VectorTypeUnion< Real , Reconstructor::Position< Real , Dim > , DataType > SampleType; + typedef DirectSum< Real , Reconstructor::Position< Real , Dim > , DataType > SampleType; typedef InputDataStream< SampleType > _InputPointStream; _InputPointStream &pointStream; SampleType scratch; - _InputSampleStream( _InputPointStream &pointStream ) : pointStream( pointStream ) + _InputOrientedSampleStream( _InputPointStream &pointStream ) : pointStream( pointStream ) { scratch = SampleType( Reconstructor::Position< Real , Dim >() , Reconstructor::Normal< Real , Dim >() ); } void reset( void ){ pointStream.reset(); } - bool base_read( Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n ) + bool read( Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n ) { bool ret = pointStream.read( scratch ); if( ret ) p = scratch.template get<0>() , n = scratch.template get<1>(); return ret; } - bool base_read( unsigned int thread , Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n ) + bool read( unsigned int thread , Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n ) { bool ret = pointStream.read( thread , scratch ); if( ret ) p = scratch.template get<0>() , n = scratch.template get<1>(); @@ -411,25 +447,25 @@ void Execute( const AuxDataFactory &auxDataFactory ) }; // A wrapper class to realize InputDataStream< SampleType > as an InputSampleWithDataStream - struct _InputSampleWithDataStream : public Reconstructor::InputSampleStream< Real , Dim , typename AuxDataFactory::VertexType > + struct _InputOrientedSampleWithDataStream : public Reconstructor::InputOrientedSampleStream< Real , Dim , typename AuxDataFactory::VertexType > { - typedef VectorTypeUnion< Real , Reconstructor::Normal< Real , Dim > , typename AuxDataFactory::VertexType > DataType; - typedef VectorTypeUnion< Real , Reconstructor::Position< Real , Dim > , DataType > SampleType; + typedef DirectSum< Real , Reconstructor::Normal< Real , Dim > , typename AuxDataFactory::VertexType > DataType; + typedef DirectSum< Real , Reconstructor::Position< Real , Dim > , DataType > SampleType; typedef InputDataStream< SampleType > _InputPointStream; _InputPointStream &pointStream; SampleType scratch; - _InputSampleWithDataStream( _InputPointStream &pointStream , typename AuxDataFactory::VertexType zero ) : pointStream( pointStream ) + _InputOrientedSampleWithDataStream( _InputPointStream &pointStream , typename AuxDataFactory::VertexType zero ) : pointStream( pointStream ) { scratch = SampleType( Reconstructor::Position< Real , Dim >() , DataType( Reconstructor::Normal< Real , Dim >() , zero ) ); } void reset( void ){ pointStream.reset(); } - bool base_read( Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n , typename AuxDataFactory::VertexType &d ) + bool read( Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n , typename AuxDataFactory::VertexType &d ) { bool ret = pointStream.read( scratch ); if( ret ) p = scratch.template get<0>() , n = scratch.template get<1>().template get<0>() , d = scratch.template get<1>().template get<1>(); return ret; } - bool base_read( unsigned int thread , Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n , typename AuxDataFactory::VertexType &d ) + bool read( unsigned int thread , Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n , typename AuxDataFactory::VertexType &d ) { bool ret = pointStream.read( thread , scratch ); if( ret ) p = scratch.template get<0>() , n = scratch.template get<1>().template get<0>() , d = scratch.template get<1>().template get<1>(); @@ -440,11 +476,11 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( Transform.set && envelopeMesh ) for( unsigned int i=0 ; ivertices.size() ; i++ ) envelopeMesh->vertices[i] = toModel * envelopeMesh->vertices[i]; if constexpr( HasAuxData ) { - _InputSampleWithDataStream sampleStream( *pointStream , auxDataFactory() ); + _InputOrientedSampleWithDataStream sampleStream( *pointStream , auxDataFactory() ); if( Transform.set ) { - Reconstructor::TransformedInputSampleStream< Real , Dim , _InputSampleWithDataStream , typename AuxDataFactory::VertexType > _sampleStream( toModel , sampleStream ); + Reconstructor::TransformedInputOrientedSampleStream< Real , Dim , typename AuxDataFactory::VertexType > _sampleStream( toModel , sampleStream ); implicit = new typename Reconstructor::Poisson::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( _sampleStream , sParams , auxDataFactory() , envelopeMesh ); implicit->unitCubeToModel = toModel.inverse() * implicit->unitCubeToModel; } @@ -452,11 +488,11 @@ void Execute( const AuxDataFactory &auxDataFactory ) } else { - _InputSampleStream sampleStream( *pointStream ); + _InputOrientedSampleStream sampleStream( *pointStream ); if( Transform.set ) { - Reconstructor::TransformedInputSampleStream< Real , Dim , _InputSampleStream > _sampleStream( toModel , sampleStream ); + Reconstructor::TransformedInputOrientedSampleStream< Real , Dim > _sampleStream( toModel , sampleStream ); implicit = new typename Reconstructor::Poisson::Implicit< Real , Dim , FEMSig >( _sampleStream , sParams , envelopeMesh ); implicit->unitCubeToModel = toModel.inverse() * implicit->unitCubeToModel; } @@ -519,32 +555,8 @@ void Execute( const AuxDataFactory &auxDataFactory ) XForm< Real , Dim+1 > pXForm = implicit->unitCubeToModel; XForm< Real , Dim > nXForm = XForm< Real , Dim >( pXForm ).inverse().transpose(); - if( Gradients.set ) - { - if( Density.set ) - { - if constexpr( HasAuxData ) WriteMesh< Real , Dim , FEMSig , true , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set , auxDataFactory ); - else WriteMesh< Real , Dim , FEMSig , true , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); - } - else - { - if constexpr( HasAuxData ) WriteMesh< Real , Dim , FEMSig , true , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set , auxDataFactory ); - else WriteMesh< Real , Dim , FEMSig , true , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); - } - } - else - { - if( Density.set ) - { - if constexpr( HasAuxData ) WriteMesh< Real , Dim , FEMSig , false , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set , auxDataFactory ); - else WriteMesh< Real , Dim , FEMSig , false , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); - } - else - { - if constexpr( HasAuxData ) WriteMesh< Real , Dim , FEMSig , false , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set , auxDataFactory ); - else WriteMesh< Real , Dim , FEMSig , false , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); - } - } + if constexpr( HasAuxData ) WriteMesh< Real , Dim , FEMSig >( Gradients.set , Density.set , InCore.set , *implicit , meParams , Out.value , ASCII.set , auxDataFactory ); + else WriteMesh< Real , Dim , FEMSig >( Gradients.set , Density.set , InCore.set , *implicit , meParams , Out.value , ASCII.set ); } else WARN( "Mesh extraction is only supported in dimensions 2 and 3" ); diff --git a/Src/PoissonRecon.server.inl b/Src/PoissonRecon.server.inl index 42909d5f..cc87ac07 100644 --- a/Src/PoissonRecon.server.inl +++ b/Src/PoissonRecon.server.inl @@ -39,8 +39,8 @@ struct Server typedef typename AuxDataFactory::VertexType AuxData; typedef VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::Factory< Real , VertexFactory::NormalFactory< Real , Dim > , AuxDataFactory > > InputSampleFactory; typedef VertexFactory::Factory< Real , VertexFactory::NormalFactory< Real , Dim > , AuxDataFactory > InputSampleDataFactory; - typedef VectorTypeUnion< Real , Point< Real , Dim > , typename AuxDataFactory::VertexType > InputSampleDataType; - typedef VectorTypeUnion< Real , Point< Real , Dim > , InputSampleDataType > InputSampleType; + typedef DirectSum< Real , Point< Real , Dim > , typename AuxDataFactory::VertexType > InputSampleDataType; + typedef DirectSum< Real , Point< Real , Dim > , InputSampleDataType > InputSampleType; typedef InputDataStream< InputSampleType > InputPointStream; typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; @@ -709,14 +709,16 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase6( const ClientReconstruc const typename FEMTree< Dim-1 , Real >::template DensityEstimator< Reconstructor::WeightDegree > *density=NULL; const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim-1 , DataSig > > *data=NULL; { - VectorBackedOutputDataStream< Point< Real , Dim-1 > > _vertices( state6.vertices ); - struct VertexStreamWrapper : public Reconstructor::OutputLevelSetVertexStreamWrapper< Point< Real , Dim-1 > , Real , Dim-1 > - { - typedef Point< Real , Dim-1 > Vertex; - VertexStreamWrapper( OutputDataStream< Vertex > &stream ) : Reconstructor::OutputLevelSetVertexStreamWrapper< Point< Real , Dim-1 > , Real , Dim-1 >( stream ) {} - Vertex toOutputVertex(const Reconstructor::LevelSetVertex< Real , Dim-1 > &in ){ return in.template get<0>(); } - }; - VertexStreamWrapper __vertexStream( _vertices ); + VectorBackedOutputDataStream< Point< Real , Dim-1 > > _vertexStream( state6.vertices ); + using ExternalType = std::tuple< Point< Real , Dim-1 > , Point< Real , Dim-1 > , Real >; + using InternalType = std::tuple< Point< Real , Dim-1 > >; + auto converter = []( const ExternalType &xType ) + { + InternalType iType; + std::get< 0 >( iType ) = std::get< 0 >( xType ); + return iType; + }; + OutputDataStreamConverter< InternalType , ExternalType > __vertexStream( _vertexStream , converter ); LevelSetExtractor< Real , Dim-1 >::SetSliceValues( SliceSigs() , UIntPack< Reconstructor::WeightDegree >() , *state6.sliceTree , clientReconInfo.reconstructionDepth , density , state6.solution , isoValue , __vertexStream , !clientReconInfo.linearFit , false , state6.sliceValues , LevelSetExtractor< Real , Dim-1 , Vertex >::SetIsoEdgesFlag() ); if( !clientReconInfo.linearFit ) LevelSetExtractor< Real , Dim-1 >::SetSliceValues( SliceSigs() , UIntPack< Reconstructor::WeightDegree >() , *state6.sliceTree , clientReconInfo.reconstructionDepth , density , state6.dSolution , isoValue , __vertexStream , false , false , state6.dSliceValues , LevelSetExtractor< Real , Dim-1 , Vertex >::SetCornerValuesFlag() ); diff --git a/Src/PoissonReconClientServer.inl b/Src/PoissonReconClientServer.inl index 97819b4f..9582d532 100644 --- a/Src/PoissonReconClientServer.inl +++ b/Src/PoissonReconClientServer.inl @@ -74,14 +74,14 @@ protected: }; template< typename Real , unsigned int Dim > -using SampleDataType = VectorTypeUnion< Real , typename VertexFactory::NormalFactory< Real , Dim >::VertexType , typename VertexFactory::DynamicFactory< Real >::VertexType >; +using SampleDataType = DirectSum< Real , typename VertexFactory::NormalFactory< Real , Dim >::VertexType , typename VertexFactory::DynamicFactory< Real >::VertexType >; template< typename Real , unsigned int Dim > struct SampleDataTypeSerializer : public Serializer< SampleDataType< Real , Dim > > { using Normal = typename VertexFactory::NormalFactory< Real , Dim >::VertexType; using AuxData = typename VertexFactory::DynamicFactory< Real >::VertexType; - using Data = VectorTypeUnion< Real , Normal , AuxData >; + using Data = DirectSum< Real , Normal , AuxData >; SampleDataTypeSerializer( const std::vector< PlyProperty > &properties ) : _factory( properties ){} @@ -108,7 +108,7 @@ struct ProjectiveSampleDataTypeSerializer : public Serializer< ProjectiveData< S { using Normal = typename VertexFactory::NormalFactory< Real , Dim >::VertexType; using AuxData = typename VertexFactory::DynamicFactory< Real >::VertexType; - using Data = ProjectiveData< VectorTypeUnion< Real , Normal , AuxData > , Real >; + using Data = ProjectiveData< DirectSum< Real , Normal , AuxData > , Real >; ProjectiveSampleDataTypeSerializer( const std::vector< PlyProperty > &properties ) : _factory( properties ){} diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 4f1d7c52..d41e1dfd 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -46,7 +46,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "18.10" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "18.20" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth diff --git a/Src/Reconstruction.example.cpp b/Src/Reconstruction.example.cpp index 626e27f5..80d28bbe 100644 --- a/Src/Reconstruction.example.cpp +++ b/Src/Reconstruction.example.cpp @@ -28,6 +28,7 @@ DAMAGE. #include "PreProcessor.h" #include "Reconstructors.h" +#include "Extrapolator.h" #include #include @@ -41,10 +42,10 @@ DAMAGE. using namespace PoissonRecon; CmdLineParameter< char* > Out( "out" ); -CmdLineReadable SSDReconstruction( "ssd" ) , UseColor( "color" ) , EvaluateImplicit( "evaluate" ) , Verbose( "verbose" ); -CmdLineParameter< int > Depth( "depth" , 8 ) , SampleNum( "samples" , 100000 ); +CmdLineReadable SSDReconstruction( "ssd" ) , EvaluateImplicit( "evaluate" ) , Verbose( "verbose" ); +CmdLineParameter< int > Depth( "depth" , 8 ) , SampleNum( "samples" , 100000 ) , ColorMode( "color" , 0 ); -CmdLineReadable* params[] = { &Out , &SSDReconstruction , &UseColor , &Verbose , &Depth , &SampleNum , &EvaluateImplicit , nullptr }; +CmdLineReadable* params[] = { &Out , &SSDReconstruction , &ColorMode , &Verbose , &Depth , &SampleNum , &EvaluateImplicit , nullptr }; void ShowUsage( char* ex ) { @@ -52,7 +53,10 @@ void ShowUsage( char* ex ) printf( "\t --%s \n" , SampleNum.name ); printf( "\t[--%s ]\n" , Out.name ); printf( "\t[--%s =%d]\n" , Depth.name , Depth.value ); - printf( "\t[--%s]\n" , UseColor.name ); + printf( "\t[--%s =%d]\n" , ColorMode.name , ColorMode.value ); + printf( "\t\t0] No color\n" ); + printf( "\t\t1] Jointly extrapolated color\n" ); + printf( "\t\t2] Independently extrapolated color\n" ); printf( "\t[--%s]\n" , SSDReconstruction.name ); printf( "\t[--%s]\n" , EvaluateImplicit.name ); printf( "\t[--%s]\n" , Verbose.name ); @@ -77,9 +81,9 @@ struct RGBColor RGBColor operator / ( Real s ) const { return operator * (1/s); } }; -// A stream for generating random samples on the sphere +// A stream for generating random oriented samples on the sphere template< typename Real , unsigned int Dim > -struct SphereSampleStream : public Reconstructor::InputSampleStream< Real , Dim > +struct SphereOrientedSampleStream : public Reconstructor::InputOrientedSampleStream< Real , Dim > { // from https://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution std::random_device randomDevice; @@ -87,13 +91,13 @@ struct SphereSampleStream : public Reconstructor::InputSampleStream< Real , Dim std::uniform_real_distribution< Real > distribution; // Constructs a stream that contains the specified number of samples - SphereSampleStream( unsigned int sz ) : _size(sz) , _current(0) , generator(0) , distribution((Real)-1.0,(Real)1.0) {} + SphereOrientedSampleStream( unsigned int sz ) : _size(sz) , _current(0) , generator(0) , distribution((Real)-1.0,(Real)1.0) {} - // Overrides the pure abstract method from InputSampleStream< Real , Dim > + // Overrides the pure abstract method from InputOrientedSampleStream< Real , Dim > void reset( void ){ generator.seed(0) ; _current = 0; } - // Overrides the pure abstract method from InputSampleStream< Real , Dim > - bool base_read( Point< Real , Dim > &p , Point< Real , Dim > &n ) + // Overrides the pure abstract method from InputOrientedSampleStream< Real , Dim > + bool read( Point< Real , Dim > &p , Point< Real , Dim > &n ) { if( _current<_size ) { @@ -103,7 +107,50 @@ struct SphereSampleStream : public Reconstructor::InputSampleStream< Real , Dim } else return false; } - bool base_read( unsigned int , Point< Real , Dim > &p , Point< Real , Dim > &n ){ return base_read( p , n ); } + + static Point< Real , Dim > RandomSpherePoint( std::default_random_engine &generator , std::uniform_real_distribution< Real > &distribution ) + { + while( true ) + { + Point< Real , Dim > p; + for( unsigned int d=0 ; d::SquareNorm( p )<1 ) return p / (Real)sqrt( Point< Real , Dim >::SquareNorm(p) ); + } + } +protected: + unsigned int _size , _current; +}; + +// A stream for generating random oriented samples with color on the sphere +template< typename Real , unsigned int Dim > +struct SphereOrientedSampleWithColorStream : public Reconstructor::InputOrientedSampleStream< Real , Dim , RGBColor< Real > > +{ + // from https://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution + std::random_device randomDevice; + std::default_random_engine generator; + std::uniform_real_distribution< Real > distribution; + + // Constructs a stream that contains the specified number of samples + SphereOrientedSampleWithColorStream( unsigned int sz ) : _size(sz) , _current(0) , generator(0) , distribution((Real)-1.0,(Real)1.0) {} + + // Overrides the pure abstract method from InputOrientedSampleStream< Real , Dim , RGBColor< Real > > + void reset( void ){ generator.seed(0) ; _current = 0; } + + // Overrides the pure abstract method from InputOrientedSampleStream< Real , Dim , RGBColor< Real > > + bool read( Point< Real , Dim > &p , Point< Real , Dim > &n , RGBColor< Real > &c ) + { + if( _current<_size ) + { + p = n = RandomSpherePoint( generator , distribution ); + _current++; + c.r = c.g = c.b = 0; + if ( p[0]<-1.f/3 ) c.r = 1.f; + else if( p[0]< 1.f/3 ) c.g = 1.f; + else c.b = 1.f; + return true; + } + else return false; + } static Point< Real , Dim > RandomSpherePoint( std::default_random_engine &generator , std::uniform_real_distribution< Real > &distribution ) { @@ -128,17 +175,17 @@ struct SphereSampleWithColorStream : public Reconstructor::InputSampleStream< Re std::uniform_real_distribution< Real > distribution; // Constructs a stream that contains the specified number of samples - SphereSampleWithColorStream( unsigned int sz ) :_size(sz) , _current(0) , generator(0) , distribution((Real)-1.0,(Real)1.0) {} + SphereSampleWithColorStream( unsigned int sz ) : _size(sz) , _current(0) , generator(0) , distribution((Real)-1.0,(Real)1.0) {} // Overrides the pure abstract method from InputSampleStream< Real , Dim , RGBColor< Real > > void reset( void ){ generator.seed(0) ; _current = 0; } // Overrides the pure abstract method from InputSampleStream< Real , Dim , RGBColor< Real > > - bool base_read( Point< Real , Dim > &p , Point< Real , Dim > &n , RGBColor< Real > &c ) + bool read( Point< Real , Dim > &p , RGBColor< Real > &c ) { if( _current<_size ) { - p = n = RandomSpherePoint( generator , distribution ); + p = RandomSpherePoint( generator , distribution ); _current++; c.r = c.g = c.b = 0; if ( p[0]<-1.f/3 ) c.r = 1.f; @@ -148,7 +195,6 @@ struct SphereSampleWithColorStream : public Reconstructor::InputSampleStream< Re } else return false; } - bool base_read( unsigned int , Point< Real , Dim > &p , Point< Real , Dim > &n , RGBColor< Real > &c ){ return base_read( p , n ,c ); } static Point< Real , Dim > RandomSpherePoint( std::default_random_engine &generator , std::uniform_real_distribution< Real > &distribution ) { @@ -171,11 +217,13 @@ struct PolygonStream : public Reconstructor::OutputFaceStream< 2 > PolygonStream( std::vector< std::vector< Index > > &polygonStream ) : _polygons( polygonStream ) {} // Override the pure abstract method from OutputPolygonStream - void base_write( const std::vector< node_index_type > &polygon ) + size_t size( void ) const { return _polygons.size(); } + size_t write( const std::vector< node_index_type > &polygon ) { std::vector< Index > poly( polygon.size() ); for( unsigned int i=0 ; i > &_polygons; @@ -188,8 +236,9 @@ struct VertexStream : public Reconstructor::OutputLevelSetVertexStream< Real , D // Construct a stream that adds vertices into the coordinates VertexStream( std::vector< Real > &vCoordinates ) : _vCoordinates( vCoordinates ) {} - // Override the pure abstract method from Reconstructor::OutputLevelSetVertexStream< Real , Dim > - void base_write( Point< Real , Dim > p , Point< Real , Dim > , Real ){ for( unsigned int d=0 ; d + size_t size( void ) const { return _vCoordinates.size()/3; } + size_t write( const Point< Real , Dim > &p , const Point< Real , Dim > & , const Real & ){ for( unsigned int d=0 ; d &_vCoordinates; }; @@ -202,13 +251,15 @@ struct VertexWithColorStream : public Reconstructor::OutputLevelSetVertexStream< VertexWithColorStream( std::vector< Real > &vCoordinates , std::vector< Real > &rgbCoordinates ) : _vCoordinates( vCoordinates ) , _rgbCoordinates( rgbCoordinates ) {} - // Override the pure abstract methodfrom Reconstructor::OutputVertexWithColorStream< Real , Dim > - void base_write( Point< Real , Dim > p , Point< Real , Dim > , Real , RGBColor< Real > c ) + // Override the pure abstract methods from Reconstructor::OutputLevelSetVertexStream< Real , Dim > + size_t size( void ) const { return _vCoordinates.size()/3; } + size_t write( const Point< Real , Dim > &p , const Point< Real , Dim > & , const Real & , const RGBColor< Real > &c ) { for( unsigned int d=0 ; d &_vCoordinates; @@ -291,8 +342,8 @@ void Execute( void ) if constexpr( UseColor ) { - // A stream generating random points on the sphere with color - SphereSampleWithColorStream< Real , Dim > sampleStream( SampleNum.value ); + // A stream generating random oriented points on the sphere with color + SphereOrientedSampleWithColorStream< Real , Dim > sampleStream( SampleNum.value ); // Construct the implicit representation Implicit implicit( sampleStream , solverParams , RGBColor< Real >() ); @@ -319,8 +370,8 @@ void Execute( void ) } else { - // A stream generating random points on the sphere - SphereSampleStream< Real , Dim > sampleStream( SampleNum.value ); + // A stream generating random oriented points on the sphere + SphereOrientedSampleStream< Real , Dim > sampleStream( SampleNum.value ); // Construct the implicit representation Implicit implicit( sampleStream , solverParams ); @@ -336,8 +387,39 @@ void Execute( void ) // Extract the iso-surface implicit.extractLevelSet( vStream , pStream , extractionParams ); - // Write out the level-set - if( Out.set ) WritePly( Out.value , vStream.size() , vCoordinates.data() , (Real*)nullptr , polygons ); + if( ColorMode.value==0 ) + { + // Write out the level-set + if( Out.set ) WritePly( Out.value , vStream.size() , vCoordinates.data() , (Real*)nullptr , polygons ); + } + else + { + // A stream generating random points on the sphere with color + SphereSampleWithColorStream< Real , Dim > sampleStream( SampleNum.value ); + + // Parameters for performing the extrapolation + typename Extrapolator::Implicit< Real , Dim , RGBColor< Real > >::Parameters eParams; + eParams.verbose = Verbose.set; + eParams.depth = Depth.value+1; + + // The extrapolated color field + Extrapolator::Implicit< Real , Dim , RGBColor< Real > > extrapolator( sampleStream , eParams , RGBColor< Real >() ); + + // The sampled colors + std::vector< Real > rgbCoordinates( vCoordinates.size()/Dim*3 ); + + // Iterate over the vertices and evaluate the extrapolate to get the color values + for( unsigned int i=0 ; i p; + for( unsigned int d=0 ; d c = extrapolator( p ); + rgbCoordinates[i*3+0] = c.r , rgbCoordinates[i*3+1] = c.g , rgbCoordinates[i*3+2] = c.b; + } + + // Write out the level-set with sampled colors + if( Out.set ) WritePly( Out.value , vStream.size() , vCoordinates.data() , rgbCoordinates.data() , polygons ); + } // Evaluate the implicit function if( EvaluateImplicit.set ) Evaluate(implicit); @@ -367,11 +449,11 @@ int main( int argc , char* argv[] ) // Solve using single float precision, in dimension 3, w/ finite-elements of degree 2 for SSD and degree 1 for Poisson, and using Neumann boundaries if( SSDReconstruction.set ) - if( UseColor.set ) Execute< float , 3 , Reconstructor:: SSD , true >(); - else Execute< float , 3 , Reconstructor:: SSD , false >(); + if( ColorMode.value==1 ) Execute< float , 3 , Reconstructor::SSD , true >(); + else Execute< float , 3 , Reconstructor::SSD , false >(); else - if( UseColor.set ) Execute< float , 3 , Reconstructor::Poisson , true >(); - else Execute< float , 3 , Reconstructor::Poisson , false >(); + if( ColorMode.value==1 ) Execute< float , 3 , Reconstructor::Poisson , true >(); + else Execute< float , 3 , Reconstructor::Poisson , false >(); if( Verbose.set ) { diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h index 9ea4cf42..97ff29aa 100644 --- a/Src/Reconstructors.h +++ b/Src/Reconstructors.h @@ -233,10 +233,10 @@ namespace PoissonRecon template< unsigned int Dim , typename Real > struct ValueInterpolationConstraintDual { - typedef VectorTypeUnion< Real , Real > PointSampleData; + typedef DirectSum< Real , Real > PointSampleData; Real vWeight; ValueInterpolationConstraintDual( Real v ) : vWeight(v){ } - CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim > &p , const VectorTypeUnion< Real , Real >& data ) const + CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim > &p , const DirectSum< Real , Real >& data ) const { Real value = data.template get<0>(); CumulativeDerivativeValues< Real , Dim , 0 > cdv; @@ -250,11 +250,11 @@ namespace PoissonRecon { CumulativeDerivativeValues< Real , Dim , 0 > weight; ValueInterpolationSystemDual( Real v ){ weight[0] = v; } - CumulativeDerivativeValues< Real , Dim , 0 > operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Real > &data , const CumulativeDerivativeValues< Real , Dim , 0 > &dValues ) const + CumulativeDerivativeValues< Real , Dim , 0 > operator()( Point< Real , Dim > p , const DirectSum< Real , Real > &data , const CumulativeDerivativeValues< Real , Dim , 0 > &dValues ) const { return dValues * weight; } - CumulativeDerivativeValues< double , Dim , 0 > operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Real > &data , const CumulativeDerivativeValues< double , Dim , 0 > &dValues ) const + CumulativeDerivativeValues< double , Dim , 0 > operator()( Point< Real , Dim > p , const DirectSum< Real , Real > &data , const CumulativeDerivativeValues< double , Dim , 0 > &dValues ) const { return dValues * weight; } @@ -267,7 +267,7 @@ namespace PoissonRecon Real weight; ValueInterpolationSystemDual( void ) : weight(0) {} ValueInterpolationSystemDual( Real v ) : weight(v) {} - CumulativeDerivativeValues< Real , Dim , 0 > operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Real > &data , const CumulativeDerivativeValues< Real , Dim , 0 > &dValues ) const + CumulativeDerivativeValues< Real , Dim , 0 > operator()( Point< Real , Dim > p , const DirectSum< Real , Real > &data , const CumulativeDerivativeValues< Real , Dim , 0 > &dValues ) const { return dValues * weight; } @@ -319,28 +319,28 @@ namespace PoissonRecon template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct Implicit; - template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > - static void _Solve( UIntPack< FEMSigs... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh , ValueInterpolationStream< Real , Dim > *valueInterpolationStream ); + template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputOrientedSampleStreamType , unsigned int ... FEMSigs > + static void _Solve( UIntPack< FEMSigs... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputOrientedSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh , InputValuedSampleStream< Real , Dim > *valueInterpolationStream ); template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct Implicit; template< typename Real , unsigned int Dim , unsigned int FEMSig > struct Implicit< Real , Dim , FEMSig > : public Reconstructor::Implicit< Real , Dim , FEMSig > { - Implicit( InputSampleStream< Real , Dim > &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL , ValueInterpolationStream< Real , Dim > *valueInterpolationStream=NULL ) + Implicit( InputOrientedSampleStream< Real , Dim > &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL , InputValuedSampleStream< Real , Dim > *valueInterpolationStream=NULL ) { typedef unsigned char AuxData; - _Solve< false , Real , Dim , FEMSig , AuxData , InputSampleStream< Real , Dim > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params , envelopeMesh , valueInterpolationStream ); + _Solve< false , Real , Dim , FEMSig , AuxData , InputOrientedSampleStream< Real , Dim > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params , envelopeMesh , valueInterpolationStream ); } }; template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > struct Implicit< Real , Dim , FEMSig , AuxData > : public Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > { - Implicit( InputSampleStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params , AuxData zero , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL , ValueInterpolationStream< Real , Dim > *valueInterpolationStream=NULL ) + Implicit( InputOrientedSampleStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params , AuxData zero , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL , InputValuedSampleStream< Real , Dim > *valueInterpolationStream=NULL ) : Reconstructor::Implicit< Real , Dim , FEMSig , AuxData >( zero ) { - _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params , envelopeMesh , valueInterpolationStream ); + _Solve< true , Real , Dim , FEMSig , AuxData , InputOrientedSampleStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params , envelopeMesh , valueInterpolationStream ); } }; }; @@ -374,7 +374,7 @@ namespace PoissonRecon { Real target , vWeight , gWeight; ConstraintDual( Real t , Real v , Real g ) : target(t) , vWeight(v) , gWeight(g) { } - CumulativeDerivativeValues< Real , Dim , 1 > operator()( const Point< Real , Dim >& p , const VectorTypeUnion< Real , Point< Real , Dim > , AuxData > &normalAndAuxData ) const + CumulativeDerivativeValues< Real , Dim , 1 > operator()( const Point< Real , Dim >& p , const DirectSum< Real , Point< Real , Dim > , AuxData > &normalAndAuxData ) const { Point< Real , Dim > n = normalAndAuxData.template get<0>(); CumulativeDerivativeValues< Real , Dim , 1 > cdv; @@ -424,11 +424,11 @@ namespace PoissonRecon weight[0] = v; for( int d=0 ; d operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Point< Real , Dim > , AuxData > & , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const + CumulativeDerivativeValues< Real , Dim , 1 > operator()( Point< Real , Dim > p , const DirectSum< Real , Point< Real , Dim > , AuxData > & , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const { return dValues * weight; } - CumulativeDerivativeValues< double , Dim , 1 > operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Point< Real , Dim > , AuxData > & , const CumulativeDerivativeValues< double , Dim , 1 >& dValues ) const + CumulativeDerivativeValues< double , Dim , 1 > operator()( Point< Real , Dim > p , const DirectSum< Real , Point< Real , Dim > , AuxData > & , const CumulativeDerivativeValues< double , Dim , 1 >& dValues ) const { return dValues * weight; }; @@ -440,7 +440,7 @@ namespace PoissonRecon typedef double Real; CumulativeDerivativeValues< Real , Dim , 1 > weight; SystemDual( Real v , Real g ) : weight( v , g , g , g ) { } - CumulativeDerivativeValues< Real , Dim , 1 > operator()( Point< Real , Dim > p , const VectorTypeUnion< Real , Point< Real , Dim > , AuxData > & , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const + CumulativeDerivativeValues< Real , Dim , 1 > operator()( Point< Real , Dim > p , const DirectSum< Real , Point< Real , Dim > , AuxData > & , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const { return dValues * weight; } @@ -484,71 +484,31 @@ namespace PoissonRecon template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct Implicit; - template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > - static void _Solve( UIntPack< FEMSigs... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params ); + template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputOrientedSampleStreamType , unsigned int ... FEMSigs > + static void _Solve( UIntPack< FEMSigs... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputOrientedSampleStreamType &pointStream , SolutionParameters< Real > params ); template< typename Real , unsigned int Dim , unsigned int FEMSig > struct Implicit< Real , Dim , FEMSig > : public Reconstructor::Implicit< Real , Dim , FEMSig > { - Implicit( InputSampleStream< Real , Dim > &pointStream , SolutionParameters< Real > params ) + Implicit( InputOrientedSampleStream< Real , Dim > &pointStream , SolutionParameters< Real > params ) { typedef unsigned char AuxData; - _Solve< false , Real , Dim , FEMSig , AuxData , InputSampleStream< Real , Dim > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params ); + _Solve< false , Real , Dim , FEMSig , AuxData , InputOrientedSampleStream< Real , Dim > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params ); } }; template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > struct Implicit< Real , Dim , FEMSig , AuxData > : public Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > { - Implicit( InputSampleStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params , AuxData zero ) + Implicit( InputOrientedSampleStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params , AuxData zero ) : Reconstructor::Implicit< Real , Dim , FEMSig , AuxData >( zero ) { - _Solve< true , Real , Dim , FEMSig , AuxData , InputSampleStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params ); + _Solve< true , Real , Dim , FEMSig , AuxData , InputOrientedSampleStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params ); } }; }; - template< class Real , unsigned int Dim , bool ExtendedAxes , typename SampleStream > - PointExtent::Extent< Real , Dim , ExtendedAxes > GetExtent( SampleStream &stream ) - { - using Sample = Point< Real , Dim >; - static_assert( std::is_base_of< InputDataStream< Sample > , SampleStream >::value , "[ERROR] Unexpected sample stream type" ); - Sample s; - PointExtent::Extent< Real , Dim , ExtendedAxes > e; - while( stream.read( s ) ) e.add(s); - stream.reset(); - return e; - } - - template< class Real , unsigned int Dim , bool ExtendedAxes , typename AuxData , typename SampleStream > - PointExtent::Extent< Real , Dim , ExtendedAxes > GetExtent( SampleStream &stream , AuxData d ) - { - using Sample = VectorTypeUnion< Real , Point< Real , Dim > , AuxData >; - static_assert( std::is_base_of< InputDataStream< Sample > , SampleStream >::value , "[ERROR] Unexpected sample stream type" ); - Sample s( Point< Real , Dim >() , d ); - PointExtent::Extent< Real , Dim , ExtendedAxes > e; - while( stream.read( s ) ) e.add( s.template get<0>() ); - stream.reset(); - return e; - } - template< class Real , unsigned int Dim , bool ExtendedAxes , typename SampleStream > - XForm< Real , Dim+1 > GetPointXForm( SampleStream &stream , Real scaleFactor , unsigned int dir ) - { - using Sample = Point< Real , Dim >; - static_assert( std::is_base_of< InputDataStream< Sample > , SampleStream >::value , "[ERROR] Unexpected sample stream type" ); - PointExtent::Extent< Real , Dim , ExtendedAxes > e = GetExtent< Real , Dim , ExtendedAxes , SampleStream >( stream ); - return PointExtent::GetBoundingBoxXForm( e , scaleFactor , dir ); - } - - template< class Real , unsigned int Dim , bool ExtendedAxes , typename AuxData , typename SampleStream > - XForm< Real , Dim+1 > GetPointXForm( SampleStream &stream , AuxData d , Real scaleFactor , unsigned int dir ) - { - using Sample = VectorTypeUnion< Real , Point< Real , Dim > , AuxData >; - static_assert( std::is_base_of< InputDataStream< Sample > , SampleStream >::value , "[ERROR] Unexpected sample stream type" ); - PointExtent::Extent< Real , Dim , ExtendedAxes > e = GetExtent< Real , Dim , ExtendedAxes , AuxData , SampleStream >( stream , d ); - return PointExtent::GetBoundingBoxXForm( e , scaleFactor , dir ); - } template< bool HasAuxData , bool IndexedVertexStream , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ImplicitType , unsigned int ... FEMSigs > void _ExtractLevelSet( UIntPack< FEMSigs ... > , const ImplicitType &implicit , OutputVertexStream &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) @@ -623,8 +583,8 @@ namespace PoissonRecon } else WARN( "Extraction only supported for dimensions 2 and 3" ); } - template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > - void Poisson::_Solve( UIntPack< FEMSigs ... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh , ValueInterpolationStream< Real , Dim > *valueInterpolationStream ) + template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputOrientedSampleStreamType , unsigned int ... FEMSigs > + void Poisson::_Solve( UIntPack< FEMSigs ... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputOrientedSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh , InputValuedSampleStream< Real , Dim > *valueInterpolationStream ) { static_assert( std::is_same< IsotropicUIntPack< Dim , FEMSig > , UIntPack< FEMSigs... > >::value , "[ERROR] Signatures don't match" ); if( params.valueInterpolationWeight<0 ) @@ -657,7 +617,7 @@ namespace PoissonRecon typedef typename FEMTreeInitializer< Dim , Real >::GeometryNodeType GeometryNodeType; // The type of the auxiliary information (including the normal) - typedef typename std::conditional< HasAuxData , VectorTypeUnion< Real , Normal< Real , Dim > , AuxData > , Normal< Real , Dim > >::type NormalAndAuxData; + typedef typename std::conditional< HasAuxData , DirectSum< Real , Normal< Real , Dim > , AuxData > , Normal< Real , Dim > >::type NormalAndAuxData; // The type describing the sampling density typedef typename std::conditional< HasAuxData , Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type::DensityEstimator DensityEstimator; @@ -690,7 +650,9 @@ namespace PoissonRecon pointStream.reset(); sampleNormalAndAuxData = new std::vector< NormalAndAuxData >(); - modelToUnitCube = params.scale>0 ? GetPointXForm< Real , Dim , true >( pointStream , zeroNormalAndAuxData , params.scale , params.alignDir ) * modelToUnitCube : modelToUnitCube; + if constexpr( HasAuxData ) modelToUnitCube = params.scale>0 ? PointExtent::GetXForm< Real , Dim , true , Point< Real , Dim > , AuxData >( pointStream , Point< Real , Dim >() , implicit.zeroAuxData , params.scale , params.alignDir ) * modelToUnitCube : modelToUnitCube; + else modelToUnitCube = params.scale>0 ? PointExtent::GetXForm< Real , Dim , true , Point< Real , Dim > >( pointStream , Point< Real , Dim >() , params.scale , params.alignDir ) * modelToUnitCube : modelToUnitCube; + pointStream.reset(); if( params.width>0 ) { @@ -741,7 +703,7 @@ namespace PoissonRecon if constexpr( HasAuxData ) { - TransformedInputSampleStream< Real , Dim , InputSampleStreamType , AuxData > _pointStream( modelToUnitCube , pointStream ); + TransformedInputOrientedSampleStream< Real , Dim , AuxData > _pointStream( modelToUnitCube , pointStream ); auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , NormalAndAuxData &d ) { Real l = (Real)Length( d.template get<0>() ); @@ -757,12 +719,33 @@ namespace PoissonRecon }; typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; - if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); + { + using ExternalType = std::tuple< Point< Real , Dim > , NormalAndAuxData >; + if constexpr( HasAuxData ) + { + using InternalType = std::tuple< Point< Real , Dim > , Point< Real , Dim > , AuxData >; + auto converter = []( const InternalType &iType ) + { + ExternalType xType; + std::get< 0 >( xType ) = std::get< 0 >( iType ); + std::get< 1 >( xType ).template get<0>() = std::get< 1 >( iType ); + std::get< 1 >( xType ).template get<1>() = std::get< 2 >( iType ); + return xType; + }; + InputDataStreamConverter< InternalType , ExternalType > __pointStream( _pointStream , converter , Point< Real , Dim >() , Point< Real , Dim >() , implicit.zeroAuxData ); + if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , __pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , __pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); + } + else + { + if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); + } + } } else { - TransformedInputSampleStream< Real , Dim , InputSampleStreamType > _pointStream( modelToUnitCube , pointStream ); + TransformedInputOrientedSampleStream< Real , Dim > _pointStream( modelToUnitCube , pointStream ); auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , NormalAndAuxData &d ) { Real l = (Real)Length( d ); @@ -796,7 +779,7 @@ namespace PoissonRecon valueInterpolationSamples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); valueInterpolationSampleData = new std::vector< Real >(); // Wrap the point stream in a transforming stream - TransformedValueInterpolationStream< Real , Dim , ValueInterpolationStream< Real , Dim > > _valueInterpolationStream( modelToUnitCube , *valueInterpolationStream ); + TransformedInputValuedSampleStream< Real , Dim > _valueInterpolationStream( modelToUnitCube , *valueInterpolationStream ); // Assign each sample a weight of 1. auto ProcessData = []( const Point< Real , Dim > &p , Real &d ){ return (Real)1.; }; @@ -975,7 +958,12 @@ namespace PoissonRecon } if( !params.outputDensity ){ delete implicit.density ; implicit.density = NULL; } - if constexpr( HasAuxData ) implicit.auxData = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( implicit.tree.template setExtrapolatedDataField< DataSig , false , Reconstructor::WeightDegree , AuxData >( samples->size() , [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return (*samples)[i]; } , [&]( size_t i ) -> const AuxData & { return (*sampleNormalAndAuxData)[i].template get<1>(); } , (DensityEstimator*)NULL ) ); + if constexpr( HasAuxData ) + { + profiler.reset(); + implicit.auxData = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( implicit.tree.template setExtrapolatedDataField< DataSig , false , Reconstructor::WeightDegree , AuxData >( samples->size() , [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return (*samples)[i]; } , [&]( size_t i ) -> const AuxData & { return (*sampleNormalAndAuxData)[i].template get<1>(); } , (DensityEstimator*)NULL ) ); + if( params.verbose ) std::cout << "# Got aux data: " << profiler << std::endl; + } delete sampleNormalAndAuxData; // Add the interpolation constraints @@ -1094,8 +1082,8 @@ namespace PoissonRecon delete samples; } - template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputSampleStreamType , unsigned int ... FEMSigs > - void SSD::_Solve( UIntPack< FEMSigs ... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputSampleStreamType &pointStream , SolutionParameters< Real > params ) + template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputOrientedSampleStreamType , unsigned int ... FEMSigs > + void SSD::_Solve( UIntPack< FEMSigs ... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputOrientedSampleStreamType &pointStream , SolutionParameters< Real > params ) { static_assert( std::is_same< IsotropicUIntPack< Dim , FEMSig > , UIntPack< FEMSigs... > >::value , "[ERROR] Signatures don't match" ); @@ -1120,7 +1108,7 @@ namespace PoissonRecon typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; // The type of the auxiliary information (including the normal) - typedef typename std::conditional< HasAuxData , VectorTypeUnion< Real , Normal< Real , Dim > , AuxData > , Normal< Real , Dim > >::type NormalAndAuxData; + typedef typename std::conditional< HasAuxData , DirectSum< Real , Normal< Real , Dim > , AuxData > , Normal< Real , Dim > >::type NormalAndAuxData; // The type describing the sampling density typedef typename std::conditional< HasAuxData , Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type::DensityEstimator DensityEstimator; @@ -1150,7 +1138,9 @@ namespace PoissonRecon pointStream.reset(); sampleNormalAndAuxData = new std::vector< NormalAndAuxData >(); - modelToUnitCube = params.scale>0 ? GetPointXForm< Real , Dim , true >( pointStream , zeroNormalAndAuxData , params.scale , params.alignDir ) * modelToUnitCube : modelToUnitCube; + if constexpr( HasAuxData ) modelToUnitCube = params.scale>0 ? PointExtent::GetXForm< Real , Dim , true , Point< Real , Dim > , AuxData >( pointStream , Point< Real , Dim >() , implicit.zeroAuxData , params.scale , params.alignDir ) * modelToUnitCube : modelToUnitCube; + else modelToUnitCube = params.scale>0 ? PointExtent::GetXForm< Real , Dim , true , Point< Real , Dim > >( pointStream , Point< Real , Dim >() , params.scale , params.alignDir ) * modelToUnitCube : modelToUnitCube; + pointStream.reset(); if( params.width>0 ) { @@ -1184,7 +1174,7 @@ namespace PoissonRecon if constexpr( HasAuxData ) { - TransformedInputSampleStream< Real , Dim , InputSampleStreamType , AuxData > _pointStream( modelToUnitCube , pointStream ); + TransformedInputOrientedSampleStream< Real , Dim , AuxData > _pointStream( modelToUnitCube , pointStream ); auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , NormalAndAuxData &d ) { Real l = (Real)Length( d.template get<0>() ); @@ -1200,12 +1190,32 @@ namespace PoissonRecon }; typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; - if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); - } + { + using ExternalType = std::tuple< Point< Real , Dim > , NormalAndAuxData >; + if constexpr( HasAuxData ) + { + using InternalType = std::tuple< Point< Real , Dim > , Point< Real , Dim > , AuxData >; + auto converter = []( const InternalType &iType ) + { + ExternalType xType; + std::get< 0 >( xType ) = std::get< 0 >( iType ); + std::get< 1 >( xType ).template get<0>() = std::get< 1 >( iType ); + std::get< 1 >( xType ).template get<1>() = std::get< 2 >( iType ); + return xType; + }; + InputDataStreamConverter< InternalType , ExternalType > __pointStream( _pointStream , converter , Point< Real , Dim >() , Point< Real , Dim >() , implicit.zeroAuxData ); + if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , __pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , __pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); + } + else + { + if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); + } + } } else { - TransformedInputSampleStream< Real , Dim , InputSampleStreamType > _pointStream( modelToUnitCube , pointStream ); + TransformedInputOrientedSampleStream< Real , Dim > _pointStream( modelToUnitCube , pointStream ); auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , NormalAndAuxData &d ) { Real l = (Real)Length( d ); @@ -1306,7 +1316,12 @@ namespace PoissonRecon } if( !params.outputDensity ){ delete implicit.density ; implicit.density = NULL; } - if constexpr( HasAuxData ) implicit.auxData = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( implicit.tree.template setExtrapolatedDataField< DataSig , false , Reconstructor::WeightDegree , AuxData >( samples->size() , [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return (*samples)[i]; } , [&]( size_t i ) -> const AuxData & { return (*sampleNormalAndAuxData)[i].template get<1>(); } , (DensityEstimator*)NULL ) ); + if constexpr( HasAuxData ) + { + profiler.reset(); + implicit.auxData = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( implicit.tree.template setExtrapolatedDataField< DataSig , false , Reconstructor::WeightDegree , AuxData >( samples->size() , [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return (*samples)[i]; } , [&]( size_t i ) -> const AuxData & { return (*sampleNormalAndAuxData)[i].template get<1>(); } , (DensityEstimator*)NULL ) ); + if( params.verbose ) std::cout << "# Got aux data: " << profiler << std::endl; + } // Add the interpolation constraints if( params.pointWeight>0 || params.gradientWeight>0 ) diff --git a/Src/Reconstructors.streams.h b/Src/Reconstructors.streams.h index a1bde6bc..0f879b92 100644 --- a/Src/Reconstructors.streams.h +++ b/Src/Reconstructors.streams.h @@ -41,137 +41,88 @@ namespace PoissonRecon template< typename Real , unsigned int Dim > using Position = Point< Real , Dim >; template< typename Real , unsigned int Dim > using Normal = Point< Real , Dim >; template< typename Real , unsigned int Dim > using Gradient = Point< Real , Dim >; + template< typename Real > using Weight = Real; + template< typename Real > using Value = Real; - // Basic types - template< typename Real , unsigned int Dim , typename ... Other > - using Sample = std::conditional_t< sizeof...(Other)==0 , VectorTypeUnion< Real , Position< Real , Dim > , Normal< Real , Dim > > , VectorTypeUnion< Real , Position< Real , Dim > , VectorTypeUnion< Real , Normal< Real , Dim > , Other... > > >; + //////////////////////// + // Input stream types // + //////////////////////// - // The types output by the extractor - template< typename Real , unsigned int Dim , typename ... Other > - using LevelSetVertex = typename LevelSetExtractor< Real , Dim , Other... >::Vertex; - template< typename Real , unsigned int Dim , typename ... Other > - using LevelSetIndexedVertex = typename LevelSetExtractor< Real , Dim , Other... >::IndexedVertex; + template< typename Real , unsigned int Dim , typename ... Data > using InputSampleStream = InputDataStream< Point< Real , Dim > , Data ... >; + template< typename Real , unsigned int Dim , typename ... Data > struct TransformedInputSampleStream; - // Stream types - template< typename Real , unsigned int Dim , typename ... Other > struct InputSampleStream; - template< typename Real , unsigned int Dim , typename InputStream , typename ... Other > struct TransformedInputSampleStream; + template< typename Real , unsigned int Dim , typename ... Data > using InputOrientedSampleStream = InputDataStream< Position< Real , Dim > , Normal< Real , Dim > , Data ... >; + template< typename Real , unsigned int Dim , typename ... Data > struct TransformedInputOrientedSampleStream; - template< typename Real , unsigned int Dim , typename ... Other > struct OutputLevelSetVertexStream; - template< typename Real , unsigned int Dim , typename ... Other > struct OutputIndexedLevelSetVertexStream; - template< typename Real , unsigned int Dim , typename ... Other > struct TransformedOutputLevelSetVertexStream; - template< typename Real , unsigned int Dim , typename ... Other > struct TransformedOutputIndexedLevelSetVertexStream; - template< typename Vertex , typename Real , unsigned int Dim , typename ... Other > struct OutputLevelSetVertexStreamWrapper; - template< typename Vertex , typename Real , unsigned int Dim , typename ... Other > struct OutputIndexedLevelSetVertexStreamWrapper; + template< typename Real , unsigned int Dim , typename ... Data > using InputValuedSampleStream = InputSampleStream< Real , Dim , Value< Real > , Data ... >; + template< typename Real , unsigned int Dim , typename ... Data > using TransformedInputValuedSampleStream = TransformedInputSampleStream< Real , Dim , Value< Real > , Data ... >; - template< typename Real , unsigned int Dim , bool HasGradients , bool HasDensity , typename ... Other > struct OutputLevelSetVertexInfo; - template< typename Real , unsigned int Dim , bool HasGradients , bool HasDensity , typename ... Other > struct OutputIndexedLevelSetVertexInfo; + ///////////////////////// + // Output stream types // + ///////////////////////// + + template< typename Real , unsigned int Dim , typename ... Data > using OutputLevelSetVertexStream = OutputDataStream< Position< Real , Dim > , Gradient< Real , Dim > , Weight< Real > , Data ... >; + template< typename Real , unsigned int Dim , typename ... Data > struct TransformedOutputLevelSetVertexStream; + + template< typename Real , unsigned int Dim , typename ... Data > using OutputIndexedLevelSetVertexStream = OutputDataStream< size_t , Position< Real , Dim > , Gradient< Real , Dim > , Weight< Real > , Data ... >; + template< typename Real , unsigned int Dim , typename ... Data > struct TransformedOutputIndexedLevelSetVertexStream; + + ////////////////// + // Face streams // + ////////////////// template< unsigned int FaceDim , typename T=node_index_type > using Face = std::conditional_t< FaceDim==2 , std::vector< T > , std::conditional_t< FaceDim==1 , std::pair< T , T > , void * > >; template< unsigned int FaceDim > using InputFaceStream = InputDataStream< Face< FaceDim > >; template< unsigned int FaceDim > using OutputFaceStream = OutputDataStream< Face< FaceDim > >; - ///////////////////////////////////// - // Value Interpolation Data Stream // - ///////////////////////////////////// - template< typename Real , unsigned int Dim > - struct ValueInterpolationStream : public InputDataStream< VectorTypeUnion< Real , Point< Real , Dim > , Real > > - { - // Functionality to reset the stream to the start - virtual void reset( void ) = 0; - - // Functionality to extract the next position/normal pair. - // The method returns true if there was another point in the stream to read, and false otherwise - virtual bool base_read( Position< Real , Dim > &p , Real &v ) = 0; - virtual bool base_read( unsigned int thread , Position< Real , Dim > &p , Real &v ) = 0; - // Implementation of InputDataStream::read - bool base_read( VectorTypeUnion< Real , Point< Real , Dim > , Real > &s ){ return base_read( s.template get<0>() , s.template get<1>() ); } - bool base_read( unsigned int thread , VectorTypeUnion< Real , Point< Real , Dim > , Real > &s ){ return base_read( thread , s.template get<0>() , s.template get<1>() ); } - }; + ////////////////////////////////////////////// + // Information about the output vertex type // + ////////////////////////////////////////////// + template< typename Real , unsigned int Dim , bool HasGradients , bool HasDensity , typename ... AxuDataFactories > struct OutputVertexInfo; - ///////////////////////////////////////////////// - // Transformed Value Interpolation Data Stream // - ///////////////////////////////////////////////// - template< typename Real , unsigned int Dim , typename InputStream > - struct TransformedValueInterpolationStream : public ValueInterpolationStream< Real , Dim > + ////////////////////////////////////////// + // Transformed Input Sample Data Stream // + ////////////////////////////////////////// + template< typename Real , unsigned int Dim , typename ... Data > + struct TransformedInputSampleStream : public InputSampleStream< Real , Dim , Data ... > { - static_assert( std::is_base_of< ValueInterpolationStream< Real , Dim > , InputStream >::value , "[ERROR] Unexpected stream type" ); - // A constructor initialized with the transformation to be applied to the samples, and a sample stream - TransformedValueInterpolationStream( XForm< Real , Dim+1 > xForm , InputStream &stream ) : _stream(stream) , _xForm(xForm) {} + TransformedInputSampleStream( XForm< Real , Dim+1 > xForm , InputSampleStream< Real , Dim , Data ... > &stream ) : _stream(stream) , _xForm(xForm) {} // Functionality to reset the stream to the start void reset( void ){ _stream.reset(); } // Functionality to extract the next position/normal pair. // The method returns true if there was another point in the stream to read, and false otherwise - bool base_read( Position< Real , Dim > &p , Real &v ) + bool read( Position< Real , Dim > &p , Data& ... d ) { - VectorTypeUnion< Real , Point< Real , Dim > , Real > s; - bool ret = _stream.read( s ); - if( ret ) p = _xForm * s.template get<0>() , v = s.template get<1>(); - return ret; + if( !_stream.read( p , d... ) ) return false; + p = _xForm * p; + return true; } - bool base_read( unsigned int thread , Position< Real , Dim > &p , Real &v ) + bool read( unsigned int thread , Position< Real , Dim > &p , Data& ... d ) { - VectorTypeUnion< Real , Point< Real , Dim > , Real > s; - bool ret = _stream.read( thread , s ); - if( ret ) p = _xForm * s.template get<0>() , v = s.template get<1>(); - return ret; + if( !_stream.read( thread , p , d... ) ) return false; + p = _xForm * p; + return true; } protected: // A reference to the underlying stream - InputStream &_stream; + InputSampleStream< Real , Dim , Data ... > &_stream; // The affine transformation to be applied to the positions XForm< Real , Dim+1 > _xForm; }; - /////////////////////////// - // Oriented Point Stream // - /////////////////////////// - template< typename Real , unsigned int Dim > - struct InputSampleStream< Real , Dim > : public InputDataStream< Sample< Real , Dim > > + ////////////////////////////////////////////////// + // Transformed Input Oriente Sample Data Stream // + ////////////////////////////////////////////////// + template< typename Real , unsigned int Dim , typename ... Data > + struct TransformedInputOrientedSampleStream : public InputOrientedSampleStream< Real , Dim , Data ... > { - // Functionality to reset the stream to the start - virtual void reset( void ) = 0; - - // Functionality to extract the next position/normal pair. - // The method returns true if there was another point in the stream to read, and false otherwise - virtual bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n ) = 0; - virtual bool base_read( unsigned int thread , Position< Real , Dim > &p , Normal< Real , Dim > &n ) = 0; - // Implementation of InputDataStream::read - bool base_read( Sample< Real , Dim > &s ){ return base_read( s.template get<0>() , s.template get<1>() ); } - bool base_read( unsigned int thread , Sample< Real , Dim > &s ){ return base_read( thread , s.template get<0>() , s.template get<1>() ); } - }; - - /////////////////////////////////// - // Oriented Point w/ Data Stream // - /////////////////////////////////// - template< typename Real , unsigned int Dim , typename Data > - struct InputSampleStream< Real , Dim , Data > : public InputDataStream< Sample< Real , Dim , Data > > - { - // Functionality to reset the stream to the start - virtual void reset( void ) = 0; - - // Functionality to extract the next position/normal pair. - // The method returns true if there was another point in the stream to read, and false otherwise - virtual bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n , Data &d ) = 0; - virtual bool base_read( unsigned int thread , Position< Real , Dim > &p , Normal< Real , Dim > &n , Data &d ) = 0; - bool base_read( Sample< Real , Dim , Data > &s ){ return base_read( s.template get<0>() , s.template get<1>().template get<0>() , s.template get<1>().template get<1>() ); } - bool base_read( unsigned int thread , Sample< Real , Dim , Data > &s ){ return base_read( thread , s.template get<0>() , s.template get<1>().template get<0>() , s.template get<1>().template get<1>() ); } - }; - - - /////////////////////////////////////// - // Transformed Oriented Point Stream // - /////////////////////////////////////// - template< typename Real , unsigned int Dim , typename InputStream > - struct TransformedInputSampleStream< Real , Dim , InputStream > : public InputSampleStream< Real , Dim > - { - static_assert( std::is_base_of< InputSampleStream< Real , Dim > , InputStream >::value , "[ERROR] Unexpected stream type" ); // A constructor initialized with the transformation to be applied to the samples, and a sample stream - TransformedInputSampleStream( XForm< Real , Dim+1 > xForm , InputStream &stream ) : _stream(stream) , _positionXForm(xForm) + TransformedInputOrientedSampleStream( XForm< Real , Dim+1 > xForm , InputOrientedSampleStream< Real , Dim , Data ... > &stream ) : _stream(stream) , _positionXForm(xForm) { _normalXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( fabs( xForm.determinant() ) , 1./Dim ); } @@ -181,69 +132,22 @@ namespace PoissonRecon // Functionality to extract the next position/normal pair. // The method returns true if there was another point in the stream to read, and false otherwise - bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n ) - { - Sample< Real , Dim > s; - bool ret = _stream.read( s ); - if( ret ) p = _positionXForm * s.template get<0>() , n = _normalXForm * s.template get<1>(); - return ret; - } - bool base_read( unsigned int thread , Position< Real , Dim > &p , Normal< Real , Dim > &n ) - { - Sample< Real , Dim > s; - bool ret = _stream.read( thread , s ); - if( ret ) p = _positionXForm * s.template get<0>() , n = _normalXForm * s.template get<1>(); - return ret; - } - - protected: - // A reference to the underlying stream - InputStream &_stream; - - // The affine transformation to be applied to the positions - XForm< Real , Dim+1 > _positionXForm; - - // The linear transformation to be applied to the normals - XForm< Real , Dim > _normalXForm; - }; - - /////////////////////////////////////////////// - // Transformed Oriented Point w/ Data Stream // - /////////////////////////////////////////////// - template< typename Real , unsigned int Dim , typename InputStream , typename Data > - struct TransformedInputSampleStream< Real , Dim , InputStream , Data > : public InputSampleStream< Real , Dim , Data > - { - static_assert( std::is_base_of< InputSampleStream< Real , Dim , Data > , InputStream >::value , "[ERROR] Unexpected stream type" ); - - // A constructor initialized with an instance of "zero" data - TransformedInputSampleStream( XForm< Real , Dim+1 > xForm , InputStream &stream ) : _stream(stream) , _positionXForm(xForm) - { - _normalXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); - } - - // Functionality to reset the stream to the start - void reset( void ){ _stream.reset(); } - - // Functionality to extract the next position/normal pair. - // The method returns true if there was another point in the stream to read, and false otherwise - bool base_read( Position< Real , Dim > &p , Normal< Real , Dim > &n , Data &d ) + bool read( Position< Real , Dim > &p , Normal< Real , Dim > &n , Data& ... d ) { - Sample< Real , Dim , Data > s( Position< Real , Dim >() , VectorTypeUnion< Real , Normal< Real , Dim > , Data >( Normal< Real , Dim >() , d ) ); - bool ret = _stream.read( s ); - if( ret ) p = _positionXForm * s.template get<0>() , n = _normalXForm * s.template get<1>().template get<0>() , d = s.template get<1>().template get<1>(); - return ret; + if( !_stream.read( p , n , d... ) ) return false; + p = _positionXForm * p , n = _normalXForm * n; + return true; } - bool base_read( unsigned int thread , Position< Real , Dim > &p , Normal< Real , Dim > &n , Data &d ) + bool read( unsigned int thread , Position< Real , Dim > &p , Normal< Real , Dim > &n , Data& ... d ) { - Sample< Real , Dim , Data > s( Position< Real , Dim >() , VectorTypeUnion< Real , Normal< Real , Dim > , Data >( Normal< Real , Dim >() , d ) ); - bool ret = _stream.read( thread , s ); - if( ret ) p = _positionXForm * s.template get<0>() , n = _normalXForm * s.template get<1>().template get<0>() , d = s.template get<1>().template get<1>(); - return ret; + if( !_stream.read( thread , p , n , d... ) ) return false; + p = _positionXForm * p , n = _normalXForm * n; + return true; } protected: // A reference to the underlying stream - InputStream &_stream; + InputOrientedSampleStream< Real , Dim , Data ... > &_stream; // The affine transformation to be applied to the positions XForm< Real , Dim+1 > _positionXForm; @@ -252,121 +156,26 @@ namespace PoissonRecon XForm< Real , Dim > _normalXForm; }; - - ////////////////////////////////////////////////////////////////////////////// - // Vertex Stream: // - // Looks like a LevelSetVertexStream, but supports component-wise insertion // - ////////////////////////////////////////////////////////////////////////////// - template< typename Real , unsigned int Dim > - struct OutputLevelSetVertexStream< Real , Dim > : public OutputDataStream< LevelSetVertex< Real , Dim > > - { - // Need to provide access to base write for counter support - using OutputDataStream< LevelSetVertex< Real , Dim > >::write; - - // Functionality to insert the next vertex - virtual void base_write( Position< Real , Dim > p , Gradient< Real , Dim > g , Real w ) = 0; - virtual void base_write( unsigned int thread , Position< Real , Dim > p , Gradient< Real , Dim > g , Real w ) - { - std::lock_guard< std::mutex > guard(_insertionMutex); - base_write( p , g , w ); - } - void base_write( const LevelSetVertex< Real , Dim > &v ){ base_write( v.template get<0>() , v.template get<1>() , v.template get<2>() ); } - void base_write( unsigned int thread , const LevelSetVertex< Real , Dim > &v ){ base_write( thread , v.template get<0>() , v.template get<1>() , v.template get<2>() ); } - protected: - std::mutex _insertionMutex; - }; - - /////////////////////////// - // Indexed Vertex Stream // - /////////////////////////// - template< typename Real , unsigned int Dim > - struct OutputIndexedLevelSetVertexStream< Real , Dim > : public OutputDataStream< LevelSetIndexedVertex< Real , Dim > > - { - // Need to provide access to base write for counter support - using OutputDataStream< LevelSetIndexedVertex< Real , Dim > >::write; - - // Functionality to insert the next vertex - virtual void base_write( node_index_type idx , Position< Real , Dim > p , Gradient< Real , Dim > g , Real w ) = 0; - virtual void base_write( unsigned int thread , node_index_type idx , Position< Real , Dim > p , Gradient< Real , Dim > g , Real w ) - { - std::lock_guard< std::mutex > guard(_insertionMutex); - base_write( idx , p , g , w ); - } - void base_write( const LevelSetIndexedVertex< Real , Dim > &v ) - { - base_write( v.first , v.second.template get<0>() , v.second.template get<1>() , v.second.template get<2>() ); - } - void base_write( unsigned int thread , const LevelSetIndexedVertex< Real , Dim > &v ) - { - base_write( thread , v.first , v.second.template get<0>() , v.second.template get<1>() , v.second.template get<2>() ); - } - protected: - std::mutex _insertionMutex; - }; - - /////////////////////////// - // Vertex w/ Data Stream // - /////////////////////////// - template< typename Real , unsigned int Dim , typename Data > - struct OutputLevelSetVertexStream< Real , Dim , Data > : public OutputDataStream< LevelSetVertex< Real , Dim , Data > > - { - // Need to provide access to base write for counter support - using OutputDataStream< LevelSetVertex< Real , Dim , Data > >::write; - - // Functionality to insert the next vertex - virtual void base_write( Position< Real , Dim > p , Gradient< Real , Dim > g , Real w , Data d ) = 0; - virtual void base_write( unsigned int thread , Position< Real , Dim > p , Gradient< Real , Dim > g , Real w , Data d ) - { - std::lock_guard< std::mutex > guard( _insertionMutex ); - base_write( p , g , w , d ); - } - void base_write( const LevelSetVertex< Real , Dim , Data > &v ){ return base_write( v.template get<0>() , v.template get<1>() , v.template get<2>() , v.template get<3>() ); } - void base_write( unsigned int thread , const LevelSetVertex< Real , Dim , Data > &v ){ return base_write( thread , v.template get<0>() , v.template get<1>() , v.template get<2>() , v.template get<3>() ); } - protected: - std::mutex _insertionMutex; - }; - - /////////////////////////////////// - // Indexed vertex w/ Data Stream // - /////////////////////////////////// - template< typename Real , unsigned int Dim , typename Data > - struct OutputIndexedLevelSetVertexStream< Real , Dim , Data > : public OutputDataStream< LevelSetIndexedVertex< Real , Dim , Data > > - { - // Need to provide access to base write for counter support - using OutputDataStream< LevelSetIndexedVertex< Real , Dim , Data > >::write; - - // Functionality to insert the next vertex - virtual void base_write( node_index_type idx , Position< Real , Dim > p , Gradient< Real , Dim > g , Real w , Data d ) = 0; - virtual void base_write( unsigned int thread , node_index_type idx , Position< Real , Dim > p , Gradient< Real , Dim > g , Real w , Data d ) - { - std::lock_guard< std::mutex > guard( _insertionMutex ); - base_write( idx , p , g , w , d ); - } - void base_write( const LevelSetIndexedVertex< Real , Dim , Data > &v ){ return base_write( v.first , v.second.template get<0>() , v.second.template get<1>() , v.second.template get<2>() , v.second.template get<3>() ); } - void base_write( unsigned int thread , const LevelSetIndexedVertex< Real , Dim , Data > &v ){ return base_write( thread , v.first , v.second.template get<0>() , v.second.template get<1>() , v.second.template get<2>() , v.second.template get<3>() ); } - protected: - std::mutex _insertionMutex; - }; - - /////////////////////////////// - // Transformed Vertex Stream // - /////////////////////////////// - template< typename Real , unsigned int Dim > - struct TransformedOutputLevelSetVertexStream< Real , Dim > : public OutputLevelSetVertexStream< Real , Dim > + ////////////////////////////////////// + // Transformed Output Vertex Stream // + ////////////////////////////////////// + template< typename Real , unsigned int Dim , typename ... Data > + struct TransformedOutputLevelSetVertexStream : public OutputLevelSetVertexStream< Real , Dim , Data ... > { // A constructor initialized with the transformation to be applied to the samples, and a sample stream - TransformedOutputLevelSetVertexStream( XForm< Real , Dim+1 > xForm , OutputLevelSetVertexStream< Real , Dim > &stream ) : _stream(stream) , _positionXForm(xForm) + TransformedOutputLevelSetVertexStream( XForm< Real , Dim+1 > xForm , OutputLevelSetVertexStream< Real , Dim , Data ... > &stream ) : _stream(stream) , _positionXForm(xForm) { _gradientXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); } // Need to write the union to ensure that the counter gets set - void base_write( Position< Real , Dim > p , Normal< Real , Dim > g , Real w ){ _stream.write( LevelSetVertex< Real , Dim >( _positionXForm * p , _gradientXForm * g , w ) ); } - void base_write( unsigned int thread , Position< Real , Dim > p , Normal< Real , Dim > g , Real w ){ _stream.write( thread , LevelSetVertex< Real , Dim >( _positionXForm * p , _gradientXForm * g , w ) ); } + size_t write( const Position< Real , Dim > &p , const Gradient< Real , Dim > &g , const Weight< Real > &w , const Data& ... d ){ return _stream.write( _positionXForm * p , _gradientXForm * g , w , d... ); } + size_t write( unsigned int thread , const Position< Real , Dim > &p , const Gradient< Real , Dim > &g , const Weight< Real > &w , const Data& ... d ){ return _stream.write( thread , _positionXForm * p , _gradientXForm * g , w , d... ); } + size_t size( void ) const { return _stream.size(); } protected: // A reference to the underlying stream - OutputLevelSetVertexStream< Real , Dim > &_stream; + OutputLevelSetVertexStream< Real , Dim , Data ... > &_stream; // The affine transformation to be applied to the positions XForm< Real , Dim+1 > _positionXForm; @@ -376,90 +185,31 @@ namespace PoissonRecon }; - /////////////////////////////////////// - // Transformed Vertex w/ Data Stream // - /////////////////////////////////////// - template< typename Real , unsigned int Dim , typename Data > - struct TransformedOutputLevelSetVertexStream< Real , Dim , Data > : public OutputLevelSetVertexStream< Real , Dim , Data > + ////////////////////////////////////////////// + // Transformed Output Indexed Vertex Stream // + ////////////////////////////////////////////// + template< typename Real , unsigned int Dim , typename ... Data > + struct TransformedOutputIndexedLevelSetVertexStream : public OutputIndexedLevelSetVertexStream< Real , Dim , Data ... > { // A constructor initialized with the transformation to be applied to the samples, and a sample stream - TransformedOutputLevelSetVertexStream( XForm< Real , Dim+1 > xForm , OutputLevelSetVertexStream< Real , Dim , Data > &stream ) : _stream(stream) , _positionXForm(xForm) - { - _gradientXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); - } - - void base_write( Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ){ _stream.write( LevelSetVertex< Real , Dim , Data >( _positionXForm * p , _gradientXForm * g , w , d ) ); } - void base_write( unsigned int thread , Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ){ _stream.write( thread , LevelSetVertex< Real , Dim , Data >( _positionXForm * p , _gradientXForm * g , w , d ) ); } - - protected: - // A reference to the underlying stream - OutputLevelSetVertexStream< Real , Dim , Data > &_stream; - - // The affine transformation to be applied to the positions - XForm< Real , Dim+1 > _positionXForm; - - // The linear transformation to be applied to the normals - XForm< Real , Dim > _gradientXForm; - }; - - /////////////////////////////////////// - // Transformed Indexed Vertex Stream // - /////////////////////////////////////// - template< typename Real , unsigned int Dim > - struct TransformedOutputIndexedLevelSetVertexStream< Real , Dim > : public OutputIndexedLevelSetVertexStream< Real , Dim > - { - // A constructor initialized with the transformation to be applied to the samples, and a sample stream - TransformedOutputIndexedLevelSetVertexStream( XForm< Real , Dim+1 > xForm , OutputIndexedLevelSetVertexStream< Real , Dim > &stream ) : _stream(stream) , _positionXForm(xForm) + TransformedOutputIndexedLevelSetVertexStream( XForm< Real , Dim+1 > xForm , OutputIndexedLevelSetVertexStream< Real , Dim , Data ... > &stream ) : _stream(stream) , _positionXForm(xForm) { _gradientXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); } // Need to write the union to ensure that the counter gets set - void base_write( node_index_type idx , Position< Real , Dim > p , Normal< Real , Dim > g , Real w ) - { - _stream.write( std::pair< node_index_type , LevelSetVertex< Real , Dim > >( idx , LevelSetVertex< Real , Dim > (_positionXForm * p , _gradientXForm * g , w ) ) ); - } - void base_write( unsigned int thread , node_index_type idx , Position< Real , Dim > p , Normal< Real , Dim > g , Real w ) - { - _stream.write( thread , std::pair< node_index_type , LevelSetVertex< Real , Dim > >( idx , LevelSetVertex< Real , Dim > (_positionXForm * p , _gradientXForm * g , w ) ) ); - } - - protected: - // A reference to the underlying stream - OutputIndexedLevelSetVertexStream< Real , Dim > &_stream; - - // The affine transformation to be applied to the positions - XForm< Real , Dim+1 > _positionXForm; - - // The linear transformation to be applied to the normals - XForm< Real , Dim > _gradientXForm; - }; - - - /////////////////////////////////////////////// - // Transformed Indexed Vertex w/ Data Stream // - /////////////////////////////////////////////// - template< typename Real , unsigned int Dim , typename Data > - struct TransformedOutputIndexedLevelSetVertexStream< Real , Dim , Data > : public OutputIndexedLevelSetVertexStream< Real , Dim , Data > - { - // A constructor initialized with the transformation to be applied to the samples, and a sample stream - TransformedOutputIndexedLevelSetVertexStream( XForm< Real , Dim+1 > xForm , OutputIndexedLevelSetVertexStream< Real , Dim , Data > &stream ) : _stream(stream) , _positionXForm(xForm) - { - _gradientXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); - } - - void base_write( node_index_type idx , Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ) + size_t write( const size_t &idx , const Position< Real , Dim > &p , const Gradient< Real , Dim > &g , const Data& ... d ) { - _stream.write( std::pair< node_index_type , LevelSetVertex< Real , Dim , Data > >( idx , LevelSetVertex< Real , Dim , Data >( _positionXForm * p , _gradientXForm * g , w , d ) ) ); + return _stream.write( idx , _positionXForm * p , _gradientXForm * g , d... ); } - void base_write( unsigned int thread , node_index_type idx , Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ) + size_t write( unsigned int thread , const size_t &idx , const Position< Real , Dim > &p , const Gradient< Real , Dim > &g , const Data& ... d ) { - _stream.write( thread , std::pair< node_index_type , LevelSetVertex< Real , Dim , Data > >( idx , LevelSetVertex< Real , Dim , Data >( _positionXForm * p , _gradientXForm * g , w , d ) ) ); + return _stream.write( thread , idx , _positionXForm * p , _gradientXForm * g , d... ); } - + size_t size( void ) const { return _stream.size(); } protected: // A reference to the underlying stream - OutputIndexedLevelSetVertexStream< Real , Dim , Data > &_stream; + OutputIndexedLevelSetVertexStream< Real , Dim , Data ... > &_stream; // The affine transformation to be applied to the positions XForm< Real , Dim+1 > _positionXForm; @@ -468,139 +218,7 @@ namespace PoissonRecon XForm< Real , Dim > _gradientXForm; }; - /////////////////////////////////////////// - // A wrapper class to write out vertices // - /////////////////////////////////////////// - template< typename Vertex , typename Real , unsigned int Dim > - struct OutputLevelSetVertexStreamWrapper< Vertex , Real , Dim > : public OutputLevelSetVertexStream< Real , Dim > - { - virtual Vertex toOutputVertex( const LevelSetVertex< Real , Dim > &in ) = 0; - - OutputLevelSetVertexStreamWrapper( OutputDataStream< Vertex > &stream ) : _stream(stream){} - void base_write( Position< Real , Dim > p , Normal< Real , Dim > g , Real w ) - { - LevelSetVertex< Real , Dim > in; - in.template get<0>() = p; - in.template get<1>() = g; - in.template get<2>() = w; - - Vertex out = toOutputVertex( in ); - _stream.write( out ); - } - void base_write( unsigned int thread , Position< Real , Dim > p , Normal< Real , Dim > g , Real w ) - { - LevelSetVertex< Real , Dim > in; - in.template get<0>() = p; - in.template get<1>() = g; - in.template get<2>() = w; - - Vertex out = toOutputVertex( in ); - _stream.write( thread , out ); - } - protected: - OutputDataStream< Vertex > &_stream; - }; - - template< typename Vertex , typename Real , unsigned int Dim , typename Data > - struct OutputLevelSetVertexStreamWrapper< Vertex , Real , Dim , Data > : public OutputLevelSetVertexStream< Real , Dim , Data > - { - virtual Vertex toOutputVertex( const LevelSetVertex< Real , Dim , Data > &in ) = 0; - - OutputLevelSetVertexStreamWrapper( OutputDataStream< Vertex > &stream ) : _stream(stream){} - - void base_write( Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ) - { - LevelSetVertex< Real , Dim , Data > in; - in.template get<0>() = p; - in.template get<1>() = g; - in.template get<2>() = w; - in.template get<3>() = d; - - Vertex out = toOutputVertex( in ); - _stream.write( out ); - } - void base_write( unsigned int thread , Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ) - { - LevelSetVertex< Real , Dim , Data > in; - in.template get<0>() = p; - in.template get<1>() = g; - in.template get<2>() = w; - in.template get<3>() = d; - - Vertex out = toOutputVertex( in ); - _stream.write( thread , out ); - } - protected: - OutputDataStream< Vertex > &_stream; - }; - - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // A wrapper class to write out indexed vertices: OutputDataStream< IndexedVertex > -> OutputIndexedLevelSetVertexStream< Real , Dim > // - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - template< typename Vertex , typename Real , unsigned int Dim > - struct OutputIndexedLevelSetVertexStreamWrapper< Vertex , Real , Dim > : public OutputIndexedLevelSetVertexStream< Real , Dim > - { - virtual Vertex toOutputVertex( const LevelSetVertex< Real , Dim > &in ) = 0; - - OutputIndexedLevelSetVertexStreamWrapper( OutputDataStream< std::pair< node_index_type , Vertex > > &stream ) : _stream(stream){} - - void base_write( node_index_type idx , Position< Real , Dim > p , Normal< Real , Dim > g , Real w ) - { - LevelSetVertex< Real , Dim > in; - in.template get<0>() = p; - in.template get<1>() = g; - in.template get<2>() = w; - - std::pair< node_index_type , Vertex > out( idx , toOutputVertex(in) ); - _stream.write( out ); - } - void base_write( unsigned int thread , node_index_type idx , Position< Real , Dim > p , Normal< Real , Dim > g , Real w ) - { - LevelSetVertex< Real , Dim > in; - in.template get<0>() = p; - in.template get<1>() = g; - in.template get<2>() = w; - - std::pair< node_index_type , Vertex > out( idx , toOutputVertex(in) ); - _stream.write( thread , out ); - } - protected: - OutputDataStream< std::pair< node_index_type , Vertex > > &_stream; - }; - - template< typename Vertex , typename Real , unsigned int Dim , typename Data > - struct OutputIndexedLevelSetVertexStreamWrapper< Vertex , Real , Dim , Data > : public OutputIndexedLevelSetVertexStream< Real , Dim , Data > - { - virtual Vertex toOutputVertex( const LevelSetVertex< Real , Dim , Data > &in ) = 0; - - OutputIndexedLevelSetVertexStreamWrapper( OutputDataStream< std::pair< node_index_type , Vertex > > &stream ) : _stream(stream){} - - void base_write( node_index_type idx , Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ) - { - LevelSetVertex< Real , Dim , Data > in; - in.template get<0>() = p; - in.template get<1>() = g; - in.template get<2>() = w; - in.template get<3>() = d; - - std::pair< node_index_type , Vertex > out( idx , toOutputVertex(in) ); - _stream.write( out ); - } - void base_write( unsigned int thread , node_index_type idx , Position< Real , Dim > p , Normal< Real , Dim > g , Real w , Data d ) - { - LevelSetVertex< Real , Dim , Data > in; - in.template get<0>() = p; - in.template get<1>() = g; - in.template get<2>() = w; - in.template get<3>() = d; - - std::pair< node_index_type , Vertex > out( idx , toOutputVertex(in) ); - _stream.write( thread , out ); - } - protected: - OutputDataStream< std::pair< node_index_type , Vertex > > &_stream; - }; ////////////////////////////////// // File-backed streaming memory // ////////////////////////////////// @@ -636,40 +254,42 @@ namespace PoissonRecon FileDescription _fd; }; + ////////////////////////////////////////////////////////////////////////////// // Output and the input face stream, backed either by a file or by a vector // ////////////////////////////////////////////////////////////////////////////// // [WARNING] These assume that the stream starts as write-only and after the reset method is invoked, the stream becomes read-only. - template< unsigned int FaceDim > - struct OutputInputFaceStream : public OutputFaceStream< FaceDim > , public InputFaceStream< FaceDim > + template< unsigned int FaceDim , bool InCore , bool Parallel > + struct OutputInputFaceStream + : public OutputFaceStream< FaceDim > + , public InputFaceStream< FaceDim > { // The streams for communicating the information InputFaceStream < FaceDim > * inStream; OutputFaceStream< FaceDim > *outStream; void reset( void ){ inStream->reset(); } - bool base_read( Face< FaceDim > &f ){ return inStream->read(f); } - bool base_read( unsigned int t , Face< FaceDim > &f ){ return inStream->read(t,f); } - void base_write( const Face< FaceDim > &f ){ outStream->write(f); } - void base_write( unsigned int t , const Face< FaceDim > &f ){ outStream->write(t,f); } + bool read( Face< FaceDim > &f ){ return inStream->read( f); } + bool read( unsigned int t , Face< FaceDim > &f ){ return inStream->read(t,f); } + size_t write( const Face< FaceDim > &f ){ return outStream->write( f); } + size_t write( unsigned int t , const Face< FaceDim > &f ){ return outStream->write(t,f); } + size_t size( void ) const { return outStream->size(); } - OutputInputFaceStream( bool inCore , bool multi ) + OutputInputFaceStream( void ) { size_t sz = std::thread::hardware_concurrency(); - _backingVector = NULL; - _backingVectors.resize( sz , NULL ); + _backingVectors.resize( sz , nullptr ); - _backingFile = NULL; - _backingFiles.resize( sz , NULL ); + _backingFiles.resize( sz , nullptr ); - _inStreams.resize( sz , NULL ); - _outStreams.resize( sz , NULL ); + _inStreams.resize( sz , nullptr ); + _outStreams.resize( sz , nullptr ); - if( inCore ) + if constexpr( InCore ) { - if( multi ) + if constexpr( Parallel ) { for( unsigned int i=0 ; i > *_backingVector; - FileBackedReadWriteStream::FileDescription *_backingFile; + std::vector< Face< FaceDim > > *_backingVector = nullptr; + FileBackedReadWriteStream::FileDescription *_backingFile = nullptr; std::vector< std::vector< Face< FaceDim > > * > _backingVectors; std::vector< FileBackedReadWriteStream::FileDescription * > _backingFiles; std::vector< InputDataStream< Face< FaceDim > > * > _inStreams; std::vector< OutputDataStream< Face< FaceDim > > * > _outStreams; }; - template< typename Factory , bool Parallel > - struct OutputInputFactoryTypeStream : - public std::conditional_t< Parallel , MultiOutputDataStream< std::pair< node_index_type , typename Factory::VertexType > > , OutputDataStream< typename Factory::VertexType > > , - public std::conditional_t< Parallel , MultiInputDataStream< std::pair< node_index_type , typename Factory::VertexType > > , InputDataStream< typename Factory::VertexType > > + + template< typename Real , unsigned int Dim , typename Factory , bool InCore , bool Parallel , typename ... Data > + struct OutputInputFactoryTypeStream + : public OutputDataStream< Position< Real , Dim > , Gradient< Real , Dim > , Weight< Real > , Data ... > + , public InputDataStream< typename Factory::VertexType > { - using Vertex = std::conditional_t< Parallel , std::pair< node_index_type , typename Factory::VertexType > , typename Factory::VertexType >; + using Vertex = typename Factory::VertexType; + // The streams for communicating the information - using InputStreamType = std::conditional_t< Parallel , MultiInputDataStream< Vertex > , InputDataStream< Vertex > >; - using OutputStreamType = std::conditional_t< Parallel , MultiOutputDataStream< Vertex > , OutputDataStream< Vertex > >; - InputStreamType * inStream; + using OutputStreamType = OutputDataStream< Vertex >; + using InputStreamType = InputDataStream< Vertex >; OutputStreamType *outStream; + InputStreamType * inStream; void reset( void ){ inStream->reset(); } - void base_write( const Vertex &v ){ outStream->write( v ); } - void base_write( unsigned int thread , const Vertex &v ){ outStream->write( thread , v ); } - bool base_read( Vertex &v ){ return inStream->read( v ); } - bool base_read( unsigned int thread , Vertex &v ){ return inStream->read( thread , v ); } + size_t write( const Position< Real , Dim > &p , const Gradient< Real , Dim > &g , const Weight< Real > &w , const Data& ... d ) + { + Vertex v = _converter( p , g , w , d... ); + return outStream->write( v ); + } + size_t write( unsigned int thread , const Position< Real , Dim > &p , const Gradient< Real , Dim > &g , const Weight< Real > &w , const Data& ... d ) + { + Vertex v = _converter( p , g , w , d... ); + return outStream->write( thread , v ); + } + bool read( Vertex &v ){ return inStream->read( v ); } + bool read( unsigned int thread , Vertex &v ){ return inStream->read( thread , v ); } + + size_t size( void ) const { return outStream->size(); } - OutputInputFactoryTypeStream( Factory &factory , bool inCore ) + OutputInputFactoryTypeStream( Factory &factory , std::function< Vertex ( const Position< Real , Dim > & , const Gradient< Real , Dim > & , const Weight< Real > & , const Data & ... ) > converter ) + : _converter( converter ) { size_t sz = std::thread::hardware_concurrency(); - _backingVector = NULL; - _backingVectors.resize( sz , NULL ); + _backingVectors.resize( sz , nullptr ); - _backingFile = NULL; - _backingFiles.resize( sz , NULL ); + _backingFiles.resize( sz , nullptr ); - _inStreams.resize( sz , NULL ); - _outStreams.resize( sz , NULL ); + _inStreams.resize( sz , nullptr ); + _outStreams.resize( sz , nullptr ); - if( inCore ) + if constexpr( Parallel ) { - if constexpr( Parallel ) + for( unsigned int i=0 ; i(); - _inStreams[i] = new VectorBackedInputDataStream< Vertex >( *_backingVectors[i] ); - _outStreams[i] = new VectorBackedOutputDataStream< Vertex >( *_backingVectors[i] ); + _backingVectors[i] = new std::vector< std::pair< size_t , Vertex > >(); + _outStreams[i] = new VectorBackedOutputIndexedDataStream< Vertex >( *_backingVectors[i] ); + _inStreams[i] = new VectorBackedInputIndexedDataStream< Vertex >( *_backingVectors[i] ); + } + else + { + _backingFiles[i] = new FileBackedReadWriteStream::FileDescription( NULL ); + _outStreams[i] = new FileBackedOutputIndexedFactoryTypeStream< Factory >( _backingFiles[i]->fp , factory ); + _inStreams[i] = new FileBackedInputIndexedFactoryTypeStream< Factory >( _backingFiles[i]->fp , factory ); } - inStream = new MultiInputDataStream< Vertex >( _inStreams ); - outStream = new MultiOutputDataStream< Vertex >( _outStreams ); - } - else - { - _backingVector = new std::vector< Vertex >(); - - inStream = new VectorBackedInputDataStream< Vertex >( *_backingVector ); - outStream = new VectorBackedOutputDataStream< Vertex >( *_backingVector ); } + outStream = new DeInterleavedMultiOutputIndexedDataStream< Vertex >( _outStreams ); + inStream = new InterleavedMultiInputIndexedDataStream< Vertex >( _inStreams ); } else { - if constexpr( Parallel ) + if constexpr( InCore ) { - for( unsigned int i=0 ; i( _backingFiles[i]->fp , factory ); - _outStreams[i] = new FileBackedOutputFactoryTypeStream< Factory , Parallel , node_index_type >( _backingFiles[i]->fp , factory ); - } - inStream = new MultiInputDataStream< Vertex >( _inStreams ); - outStream = new MultiOutputDataStream< Vertex >( _outStreams ); + _backingVector = new std::vector< Vertex >(); + outStream = new VectorBackedOutputDataStream< Vertex >( *_backingVector ); + inStream = new VectorBackedInputDataStream< Vertex >( *_backingVector ); } else { _backingFile = new FileBackedReadWriteStream::FileDescription( NULL ); - inStream = new FileBackedInputFactoryTypeStream< Factory , Parallel , node_index_type >( _backingFile->fp , factory ); - outStream = new FileBackedOutputFactoryTypeStream< Factory , Parallel , node_index_type >( _backingFile->fp , factory ); + outStream = new FileBackedOutputFactoryTypeStream< Factory >( _backingFile->fp , factory ); + inStream = new FileBackedInputFactoryTypeStream< Factory >( _backingFile->fp , factory ); } } - if constexpr( Parallel ) - { - MultiOutputDataStream< std::pair< node_index_type , typename Factory::VertexType > >::_init( _outStreams ); - MultiInputDataStream< std::pair< node_index_type , typename Factory::VertexType > >::_init( _inStreams ); - } } ~OutputInputFactoryTypeStream( void ) @@ -832,184 +452,66 @@ namespace PoissonRecon delete inStream; delete outStream; + delete _inMultiStream; } protected: - std::vector< Vertex > *_backingVector; - FileBackedReadWriteStream::FileDescription *_backingFile; - std::vector< std::vector< Vertex > * >_backingVectors; + std::function< Vertex ( const Position< Real , Dim > & , const Gradient< Real , Dim > & , const Weight< Real > & , const Data & ... ) > _converter; + std::vector< Vertex > *_backingVector = nullptr; + FileBackedReadWriteStream::FileDescription *_backingFile = nullptr; + std::vector< std::vector< std::conditional_t< Parallel , std::pair< size_t , Vertex > , Vertex > > * >_backingVectors; std::vector< FileBackedReadWriteStream::FileDescription * > _backingFiles; - std::vector< InputDataStream< Vertex > * > _inStreams; - std::vector< OutputDataStream< Vertex > * > _outStreams; + std::vector< OutputIndexedDataStream< Vertex > * > _outStreams; + std::vector< InputIndexedDataStream< Vertex > * > _inStreams; + MultiInputIndexedDataStream< Vertex > *_inMultiStream = nullptr; }; template< typename Real , unsigned int Dim , bool HasGradients , bool HasDensity > - struct OutputLevelSetVertexInfo< Real , Dim , HasGradients , HasDensity > + struct OutputVertexInfo< Real , Dim , HasGradients , HasDensity > { using Factory = - typename std::conditional + typename std::conditional_t < HasGradients , - typename std::conditional + typename std::conditional_t < HasDensity , VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::NormalFactory< Real , Dim > , VertexFactory::ValueFactory< Real > > , VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::NormalFactory< Real , Dim > > - >::type , - typename std::conditional + > , + typename std::conditional_t < HasDensity , VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::ValueFactory< Real > > , VertexFactory::PositionFactory< Real , Dim > - >::type - >::type; + > + >; using Vertex = typename Factory::VertexType; static Factory GetFactory( void ){ return Factory(); } - struct StreamWrapper : public Reconstructor::OutputLevelSetVertexStreamWrapper< Vertex , Real , Dim > + static Vertex Convert( const Position< Real , Dim > &p , const Gradient< Real , Dim > &g , const Weight< Real > & w ) { - StreamWrapper( OutputDataStream< Vertex > &stream ) : - Reconstructor::OutputLevelSetVertexStreamWrapper< Vertex , Real , Dim >( stream ){} - - Vertex toOutputVertex( const Reconstructor::LevelSetVertex< Real , Dim > &in ) - { - Vertex out; - if constexpr( HasGradients || HasDensity ) - { - out.template get<0>() = in.template get<0>(); - if constexpr( HasGradients ) - { - out.template get<1>() = in.template get<1>(); - if constexpr( HasDensity ) out.template get<2>() = in.template get<2>(); - } - else - { - if constexpr( HasDensity ) out.template get<1>() = in.template get<2>(); - } - } - else out = in.template get<0>(); - return out; - } - }; - }; - - template< typename Real , unsigned int Dim , bool HasGradients , bool HasDensity , typename AuxDataFactory > - struct OutputLevelSetVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactory > - { - using Factory = - typename std::conditional - < - HasGradients , - typename std::conditional - < - HasDensity , - VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::NormalFactory< Real , Dim > , VertexFactory::ValueFactory< Real > , AuxDataFactory > , - VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::NormalFactory< Real , Dim > , AuxDataFactory > - >::type , - typename std::conditional - < - HasDensity , - VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::ValueFactory< Real > , AuxDataFactory > , - VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , AuxDataFactory > - >::type - >::type; - using AuxData = typename AuxDataFactory::VertexType; - - using _Vertex = VectorTypeUnion< Real , Point< Real , Dim > , Point< Real , Dim > , Real , typename AuxDataFactory::VertexType >; - using Vertex = typename Factory::VertexType; - - static Factory GetFactory( AuxDataFactory auxDataFactory ) - { - if constexpr( HasGradients ) - { - if constexpr( HasDensity ) return Factory( VertexFactory::PositionFactory< Real , Dim >() , VertexFactory::NormalFactory< Real , Dim >() , VertexFactory::ValueFactory< Real >() , auxDataFactory ); - else return Factory( VertexFactory::PositionFactory< Real , Dim >() , VertexFactory::NormalFactory< Real , Dim >() , auxDataFactory ); - } + Vertex v; + if constexpr( !HasGradients && !HasDensity ) v = p; else { - if constexpr( HasDensity ) return Factory( VertexFactory::PositionFactory< Real , Dim >() , VertexFactory::ValueFactory< Real >() , auxDataFactory ); - else return Factory( VertexFactory::PositionFactory< Real , Dim >() , auxDataFactory ); - } - } - - struct StreamWrapper : public Reconstructor::OutputLevelSetVertexStreamWrapper< Vertex , Real , Dim , AuxData > - { - StreamWrapper( OutputDataStream< Vertex > &stream ) : - Reconstructor::OutputLevelSetVertexStreamWrapper< Vertex , Real , Dim , AuxData >( stream ){} - - Vertex toOutputVertex( const Reconstructor::LevelSetVertex< Real , Dim , AuxData > &in ) - { - Vertex out; - out.template get<0>() = in.template get<0>(); + v.template get<0>() = p; if constexpr( HasGradients ) { - out.template get<1>() = in.template get<1>(); - if constexpr( HasDensity ) out.template get<2>() = in.template get<2>() , out.template get<3>() = in.template get<3>(); - else out.template get<2>() = in.template get<3>(); + if constexpr( HasDensity ) v.template get<1>() = g , v.template get<2>() = w; + else v.template get<1>() = g; } else { - if constexpr( HasDensity ) out.template get<1>() = in.template get<2>() , out.template get<2>() = in.template get<3>(); - else out.template get<1>() = in.template get<3>(); + if constexpr( HasDensity ) v.template get<1>() = w; } - return out; } - }; - }; - template< typename Real , unsigned int Dim , bool HasGradients , bool HasDensity > - struct OutputIndexedLevelSetVertexInfo< Real , Dim , HasGradients , HasDensity > - { - using Factory = - typename std::conditional - < - HasGradients , - typename std::conditional - < - HasDensity , - VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::NormalFactory< Real , Dim > , VertexFactory::ValueFactory< Real > > , - VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::NormalFactory< Real , Dim > > - >::type , - typename std::conditional - < - HasDensity , - VertexFactory::Factory< Real , VertexFactory::PositionFactory< Real , Dim > , VertexFactory::ValueFactory< Real > > , - VertexFactory::PositionFactory< Real , Dim > - >::type - >::type; - using Vertex = typename Factory::VertexType; - using IndexedVertex = std::pair< node_index_type , Vertex >; - - static Factory GetFactory( void ){ return Factory(); } - - struct StreamWrapper : public Reconstructor::OutputIndexedLevelSetVertexStreamWrapper< Vertex , Real , Dim > - { - StreamWrapper( OutputDataStream< IndexedVertex > &stream ) : - Reconstructor::OutputIndexedLevelSetVertexStreamWrapper< Vertex , Real , Dim >( stream ){} - - Vertex toOutputVertex( const Reconstructor::LevelSetVertex< Real , Dim > &in ) - { - Vertex out; - if constexpr( HasGradients || HasDensity ) - { - out.template get<0>() = in.template get<0>(); - if constexpr( HasGradients ) - { - out.template get<1>() = in.template get<1>(); - if constexpr( HasDensity ) out.template get<2>() = in.template get<2>(); - } - else - { - if constexpr( HasDensity ) out.template get<1>() = in.template get<2>(); - } - } - else out = in.template get<0>(); - return out; - } - }; + return v; + } }; template< typename Real , unsigned int Dim , bool HasGradients , bool HasDensity , typename AuxDataFactory > - struct OutputIndexedLevelSetVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactory > + struct OutputVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactory > { using Factory = typename std::conditional @@ -1030,9 +532,8 @@ namespace PoissonRecon >::type; using AuxData = typename AuxDataFactory::VertexType; - using _Vertex = VectorTypeUnion< Real , Point< Real , Dim > , Point< Real , Dim > , Real , typename AuxDataFactory::VertexType >; + using _Vertex = DirectSum< Real , Point< Real , Dim > , Point< Real , Dim > , Real , typename AuxDataFactory::VertexType >; using Vertex = typename Factory::VertexType; - using IndexedVertex = std::pair< node_index_type , Vertex >; static Factory GetFactory( AuxDataFactory auxDataFactory ) { @@ -1048,29 +549,22 @@ namespace PoissonRecon } } - struct StreamWrapper : public Reconstructor::OutputIndexedLevelSetVertexStreamWrapper< Vertex , Real , Dim , AuxData > + static Vertex Convert( const Position< Real , Dim > &p , const Gradient< Real , Dim > &g , const Weight< Real > & w , const AuxData &data ) { - StreamWrapper( OutputDataStream< IndexedVertex > &stream ) : - Reconstructor::OutputIndexedLevelSetVertexStreamWrapper< Vertex , Real , Dim , AuxData >( stream ){} - - Vertex toOutputVertex( const Reconstructor::LevelSetVertex< Real , Dim , AuxData > &in ) + Vertex v; + v.template get<0>() = p; + if constexpr( HasGradients ) { - Vertex out; - out.template get<0>() = in.template get<0>(); - if constexpr( HasGradients ) - { - out.template get<1>() = in.template get<1>(); - if constexpr( HasDensity ) out.template get<2>() = in.template get<2>() , out.template get<3>() = in.template get<3>(); - else out.template get<2>() = in.template get<3>(); - } - else - { - if constexpr( HasDensity ) out.template get<1>() = in.template get<2>() , out.template get<2>() = in.template get<3>(); - else out.template get<1>() = in.template get<3>(); - } - return out; + if constexpr( HasDensity ) v.template get<1>() = g , v.template get<2>() = w , v.template get<3>() = data; + else v.template get<1>() = g , v.template get<2>() = data; } - }; + else + { + if constexpr( HasDensity ) v.template get<1>() = w , v.template get<2>() = data; + else v.template get<1>() = data; + } + return v; + } }; } } diff --git a/Src/SSDRecon.cpp b/Src/SSDRecon.cpp index be55e4bb..a1c107aa 100644 --- a/Src/SSDRecon.cpp +++ b/Src/SSDRecon.cpp @@ -194,10 +194,9 @@ void ShowUsage(char* ex) printf( "\t[--%s]\n" , Verbose.name ); } -template< typename Real , unsigned int Dim , unsigned int FEMSig , bool HasGradients , bool HasDensity , typename ... AuxDataFactories > +template< typename Real , unsigned int Dim , unsigned int FEMSig , bool HasGradients , bool HasDensity , bool InCore , typename ... AuxDataFactories > void WriteMesh ( - bool inCore , Reconstructor::Implicit< Real , Dim , FEMSig , typename AuxDataFactories::VertexType ... > &implicit , const Reconstructor::LevelSetExtractionParameters &meParams , std::string fileName , @@ -206,29 +205,66 @@ void WriteMesh ) { // A description of the output vertex information - using VInfo = Reconstructor::OutputIndexedLevelSetVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactories ... >; + using VInfo = Reconstructor::OutputVertexInfo< Real , Dim , HasGradients , HasDensity , AuxDataFactories ... >; // A factory generating the output vertices using Factory = typename VInfo::Factory; Factory factory = VInfo::GetFactory( factories... ); - // A backing stream for the vertices - Reconstructor::OutputInputFactoryTypeStream< Factory , true > vertexStream( factory , inCore ); - Reconstructor::OutputInputFaceStream< Dim-1 > faceStream( inCore , true ); + Reconstructor::OutputInputFactoryTypeStream< Real , Dim , Factory , InCore , true , typename AuxDataFactories::VertexType... > vertexStream( factory , VInfo::Convert ); + Reconstructor::OutputInputFaceStream< Dim-1 , InCore , true > faceStream; - { - // The wrapper converting native to output types - typename VInfo::StreamWrapper _vertexStream( vertexStream ); - - // Extract the level set - implicit.extractLevelSet( _vertexStream , faceStream , meParams ); - } + implicit.extractLevelSet( vertexStream , faceStream , meParams ); // Write the mesh to a .ply file std::vector< std::string > noComments; vertexStream.reset(); - IndexedInputDataStream< node_index_type , typename Factory::VertexType > vStream( vertexStream ); - PLY::Write< Factory , node_index_type , Real , Dim >( fileName , factory , vertexStream.size() , faceStream.size() , vStream , faceStream , ascii ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); + PLY::Write< Factory , node_index_type , Real , Dim >( fileName , factory , vertexStream.size() , faceStream.size() , vertexStream , faceStream , ascii ? PLY_ASCII : PLY_BINARY_NATIVE , noComments ); +} + +template< typename Real , unsigned int Dim , unsigned int FEMSig , bool HasDensity , bool InCore , typename ... AuxDataFactories > +void WriteMesh +( + bool hasGradients , + Reconstructor::Implicit< Real , Dim , FEMSig , typename AuxDataFactories::VertexType ... > &implicit , + const Reconstructor::LevelSetExtractionParameters &meParams , + std::string fileName , + bool ascii , + const AuxDataFactories& ... factories +) +{ + if( hasGradients ) return WriteMesh< Real , Dim, FEMSig , true , HasDensity , InCore , AuxDataFactories ... >( implicit , meParams , fileName , ascii , factories... ); + else return WriteMesh< Real , Dim, FEMSig , false , HasDensity , InCore , AuxDataFactories ... >( implicit , meParams , fileName , ascii , factories... ); +} + +template< typename Real , unsigned int Dim , unsigned int FEMSig , bool InCore , typename ... AuxDataFactories > +void WriteMesh +( + bool hasGradients , bool hasDensity , + Reconstructor::Implicit< Real , Dim , FEMSig , typename AuxDataFactories::VertexType ... > &implicit , + const Reconstructor::LevelSetExtractionParameters &meParams , + std::string fileName , + bool ascii , + const AuxDataFactories& ... factories +) +{ + if( hasDensity ) return WriteMesh< Real , Dim, FEMSig , true , InCore , AuxDataFactories ... >( hasGradients , implicit , meParams , fileName , ascii , factories... ); + else return WriteMesh< Real , Dim, FEMSig , false , InCore , AuxDataFactories ... >( hasGradients , implicit , meParams , fileName , ascii , factories... ); +} + +template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... AuxDataFactories > +void WriteMesh +( + bool hasGradients , bool hasDensity , bool inCore , + Reconstructor::Implicit< Real , Dim , FEMSig , typename AuxDataFactories::VertexType ... > &implicit , + const Reconstructor::LevelSetExtractionParameters &meParams , + std::string fileName , + bool ascii , + const AuxDataFactories& ... factories +) +{ + if( inCore ) return WriteMesh< Real , Dim, FEMSig , true , AuxDataFactories ... >( hasGradients , hasDensity , implicit , meParams , fileName , ascii , factories... ); + else return WriteMesh< Real , Dim, FEMSig , false , AuxDataFactories ... >( hasGradients , hasDensity , implicit , meParams , fileName , ascii , factories... ); } template< class Real , unsigned int Dim , unsigned int FEMSig , typename AuxDataFactory > @@ -360,59 +396,66 @@ void Execute( const AuxDataFactory &auxDataFactory ) } // A wrapper class to realize InputPointStream as an InputSampleWithDataStream - struct _InputSampleStream : public Reconstructor::InputSampleStream< Real , Dim > + struct _InputOrientedSampleStream : public Reconstructor::InputOrientedSampleStream< Real , Dim > { typedef Reconstructor::Normal< Real , Dim > DataType; - typedef VectorTypeUnion< Real , Reconstructor::Position< Real , Dim > , DataType > SampleType; + typedef DirectSum< Real , Reconstructor::Position< Real , Dim > , DataType > SampleType; typedef InputDataStream< SampleType > _InputPointStream; _InputPointStream &pointStream; SampleType scratch; - _InputSampleStream( _InputPointStream &pointStream ) : pointStream( pointStream ) + _InputOrientedSampleStream( _InputPointStream &pointStream ) : pointStream( pointStream ) { scratch = SampleType( Reconstructor::Position< Real , Dim >() , Reconstructor::Normal< Real , Dim >() ); } void reset( void ){ pointStream.reset(); } - bool base_read( Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n ) + bool read( Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n ) { bool ret = pointStream.read( scratch ); if( ret ) p = scratch.template get<0>() , n = scratch.template get<1>(); return ret; } - bool base_read( unsigned int , Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n ){ return base_read( p , n ); } + bool read( unsigned int thread , Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n ) + { + bool ret = pointStream.read( thread , scratch ); + if( ret ) p = scratch.template get<0>() , n = scratch.template get<1>(); + return ret; + } }; // A wrapper class to realize InputPointStream as an InputSampleWithDataStream - struct _InputSampleWithDataStream : public Reconstructor::InputSampleStream< Real , Dim , typename AuxDataFactory::VertexType > + struct _InputOrientedSampleWithDataStream : public Reconstructor::InputOrientedSampleStream< Real , Dim , typename AuxDataFactory::VertexType > { - typedef VectorTypeUnion< Real , Reconstructor::Normal< Real , Dim > , typename AuxDataFactory::VertexType > DataType; - typedef VectorTypeUnion< Real , Reconstructor::Position< Real , Dim > , DataType > SampleType; + typedef DirectSum< Real , Reconstructor::Normal< Real , Dim > , typename AuxDataFactory::VertexType > DataType; + typedef DirectSum< Real , Reconstructor::Position< Real , Dim > , DataType > SampleType; typedef InputDataStream< SampleType > _InputPointStream; _InputPointStream &pointStream; SampleType scratch; - _InputSampleWithDataStream( _InputPointStream &pointStream , typename AuxDataFactory::VertexType zero ) : pointStream( pointStream ) + _InputOrientedSampleWithDataStream( _InputPointStream &pointStream , typename AuxDataFactory::VertexType zero ) : pointStream( pointStream ) { scratch = SampleType( Reconstructor::Position< Real , Dim >() , DataType( Reconstructor::Normal< Real , Dim >() , zero ) ); } void reset( void ){ pointStream.reset(); } - bool base_read( Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n , typename AuxDataFactory::VertexType &d ) + bool read( Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n , typename AuxDataFactory::VertexType &d ) { bool ret = pointStream.read( scratch ); if( ret ) p = scratch.template get<0>() , n = scratch.template get<1>().template get<0>() , d = scratch.template get<1>().template get<1>(); return ret; } - bool base_read( unsigned int , Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n , typename AuxDataFactory::VertexType &d ) + bool read( unsigned int thread , Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n , typename AuxDataFactory::VertexType &d ) { - return base_read( p , n , d ); + bool ret = pointStream.read( thread , scratch ); + if( ret ) p = scratch.template get<0>() , n = scratch.template get<1>().template get<0>() , d = scratch.template get<1>().template get<1>(); + return ret; } }; if constexpr( HasAuxData ) { - _InputSampleWithDataStream sampleStream( *pointStream , auxDataFactory() ); + _InputOrientedSampleWithDataStream sampleStream( *pointStream , auxDataFactory() ); if( Transform.set ) { - Reconstructor::TransformedInputSampleStream< Real , Dim , _InputSampleWithDataStream , typename AuxDataFactory::VertexType > _sampleStream( toModel , sampleStream ); + Reconstructor::TransformedInputOrientedSampleStream< Real , Dim , typename AuxDataFactory::VertexType > _sampleStream( toModel , sampleStream ); implicit = new Reconstructor::SSD::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( _sampleStream , sParams , auxDataFactory() ); implicit->unitCubeToModel = toModel.inverse() * implicit->unitCubeToModel; } @@ -420,11 +463,11 @@ void Execute( const AuxDataFactory &auxDataFactory ) } else { - _InputSampleStream sampleStream( *pointStream ); + _InputOrientedSampleStream sampleStream( *pointStream ); if( Transform.set ) { - Reconstructor::TransformedInputSampleStream< Real , Dim , _InputSampleStream > _sampleStream( toModel , sampleStream ); + Reconstructor::TransformedInputOrientedSampleStream< Real , Dim > _sampleStream( toModel , sampleStream ); implicit = new Reconstructor::SSD::Implicit< Real , Dim , FEMSig >( _sampleStream , sParams ); implicit->unitCubeToModel = toModel.inverse() * implicit->unitCubeToModel; } @@ -486,32 +529,8 @@ void Execute( const AuxDataFactory &auxDataFactory ) XForm< Real , Dim+1 > pXForm = implicit->unitCubeToModel; XForm< Real , Dim > nXForm = XForm< Real , Dim >( pXForm ).inverse().transpose(); - if( Gradients.set ) - { - if( Density.set ) - { - if constexpr( HasAuxData ) WriteMesh< Real , Dim , FEMSig , true , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set , auxDataFactory ); - else WriteMesh< Real , Dim , FEMSig , true , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); - } - else - { - if constexpr( HasAuxData ) WriteMesh< Real , Dim , FEMSig , true , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set , auxDataFactory ); - else WriteMesh< Real , Dim , FEMSig , true , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); - } - } - else - { - if( Density.set ) - { - if constexpr( HasAuxData ) WriteMesh< Real , Dim , FEMSig , false , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set , auxDataFactory ); - else WriteMesh< Real , Dim , FEMSig , false , true >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); - } - else - { - if constexpr( HasAuxData ) WriteMesh< Real , Dim , FEMSig , false , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set , auxDataFactory ); - else WriteMesh< Real , Dim , FEMSig , false , false >( InCore.set , *implicit , meParams , Out.value , ASCII.set ); - } - } + if constexpr( HasAuxData ) WriteMesh< Real , Dim , FEMSig >( Gradients.set , Density.set , InCore.set , *implicit , meParams , Out.value , ASCII.set , auxDataFactory ); + else WriteMesh< Real , Dim , FEMSig >( Gradients.set , Density.set , InCore.set , *implicit , meParams , Out.value , ASCII.set ); } else WARN( "Mesh extraction is only supported in dimensions 2 and 3" ); diff --git a/Src/SurfaceTrimmer.cpp b/Src/SurfaceTrimmer.cpp index 754c6eba..50c22a09 100644 --- a/Src/SurfaceTrimmer.cpp +++ b/Src/SurfaceTrimmer.cpp @@ -173,7 +173,7 @@ struct ComponentGraph }; template< typename Real , unsigned int Dim , typename ... AuxData > -using ValuedPointData = VectorTypeUnion< Real , Point< Real , Dim > , Real , AuxData ... >; +using ValuedPointData = DirectSum< Real , Point< Real , Dim > , Real , AuxData ... >; template< typename Index > size_t BoostHash( Index i1 , Index i2 ) diff --git a/Src/VertexFactory.h b/Src/VertexFactory.h index 7571b51e..2049eefb 100644 --- a/Src/VertexFactory.h +++ b/Src/VertexFactory.h @@ -503,12 +503,12 @@ namespace PoissonRecon // A factory for building the union of multiple components template< typename Real , typename ... Factories > - struct Factory : public _Factory< VectorTypeUnion< Real , typename Factories::VertexType ... > , Factory< Real , Factories ... > > + struct Factory : public _Factory< DirectSum< Real , typename Factories::VertexType ... > , Factory< Real , Factories ... > > { protected: typedef std::tuple< Factories ... > _FactoryTuple; public: - typedef typename _Factory< VectorTypeUnion< Real , typename Factories::VertexType ... > , Factory< Real , Factories ... > >::VertexType VertexType; + typedef typename _Factory< DirectSum< Real , typename Factories::VertexType ... > , Factory< Real , Factories ... > >::VertexType VertexType; template< unsigned int I > using FactoryType = typename std::tuple_element< I , _FactoryTuple >::type; template< unsigned int I > FactoryType< I >& get( void ) { return std::get< I >( _factoryTuple ); } template< unsigned int I > const FactoryType< I >& get( void ) const { return std::get< I >( _factoryTuple ); } From edf3671f0c1075079db6b3e453d6806e8b0f112b Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Sun, 6 Oct 2024 00:18:44 -0400 Subject: [PATCH 53/86] Version 18.30 --- Src/PreProcessor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index d41e1dfd..6803d804 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -46,7 +46,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "18.20" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "18.30" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth From 67ba415c54c959ddec9881b1d25a1d520761b206 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Sun, 6 Oct 2024 00:53:30 -0400 Subject: [PATCH 54/86] Version 18.30 --- README.md | 73 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 8b7e987b..2a43d495 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 18.20)

    +

    Adaptive Multigrid Solvers (Version 18.30)

    links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
    Executables: -Win64
    +Win64
    Source Code: -ZIP GitHub
    +ZIP GitHub
    Older Versions: +V18.20, V18.10, V18.05, V18.04, @@ -997,7 +998,7 @@ If both the --keep flag and the --fraction flag are set, the -- Reconstruction.example.cpp -In addition to executables, the reconstruction code can be interfaced into through the functionality implemented in Reconstructors.h. +In addition to executables, the reconstruction code can be interfaced into through the functionality implemented in Reconstructors.h and Extrapolator.h Using the functionality requires requires choosing a finite element type, FEMSig and defining one input stream and two output streams.
    • The template parameter FEMSig describes the finite element type, which is a composite of the degree of the finite element and the boundary conditions it satisfies. Given an integer valued Degree and boundary type BType (one of BOUNDARY_FREE, BOUNDARY_DIRICHLET, and BOUNDARY_NEUMANN defined in BSplineData.h), the signature is defined by setting: @@ -1012,25 +1013,29 @@ The base class has two pure virtual methods that need to be over-ridden:
      • void reset( void ):
        This method resets the stream to the start (necessary because the reconstruction code performs two passes over the input samples). -
      • bool base_read( Point< Real , Dim > &p , Point< Real , Dim > &n ):
        +
      • bool read( Point< Real , Dim > &p , Point< Real , Dim > &n ):
        This method tries to read the next pair of positions/normals from the stream, returning true if the read was successful and false if the read failed (i.e. the end of the stream was reached). The class Point< Real , Dim > represents a point in Dim-dimensional space, can be accessed like an array (i.e. overloads the bracked operator) and supports algebraic manipulation like addition and scalar multiplication.
    • Output polygon stream: This class derives from the OutputPolygonStream class. -The base class has one pure virtual method that needs to be over-ridden: +The base class has two pure virtual methods that needs to be over-ridden:
        -
      • void base_write( const std::vector< node_index_type > &polygon ):
        -This method writes the information for the next polygon into the stream, with the polygon represented as a std::vector of integral indices. (The type node_index_type is an unsigned int if the BIG_DATA macro is not defined an unsigned long long if it is.) +
      • size_t size( void ):
        +This method returns the number of polygons written. +
      • size_t write( const std::vector< node_index_type > &polygon ):
        +This method writes the information for the next polygon into the stream, with the polygon represented as a std::vector of integral indices. (The type node_index_type is an unsigned int if the BIG_DATA macro is not defined an unsigned long long if it is.) The function returns the index of the written polygon.
    • Output vertex stream: This class derives from the OutputVertexStream< Real , Dim > class. -The base class has one pure virtual method that needs to be over-ridden: +The base class has two pure virtual methods that needs to be over-ridden:
        -
      • void base_write( Point< Real , Dim > p , Point< Real , Dim > g , Real w ):
        -This method writes the information for the next vertx into the stream. The data includes the position of the vertex, p, as well as the gradient, g, and density weight, w if the extraction code is asked to compute those. +
      • size_t size( void ):
        +This method returns the number of vertices written. +
      • size_t write( Point< Real , Dim > p , Point< Real , Dim > g , Real w ):
        +This method writes the information for the next vertx into the stream. The data includes the position of the vertex, p, as well as the gradient, g, and density weight, w if the extraction code is asked to compute those. The function returns the index of the written vertex.
    The reconstructed surface is then computed in two steps:
      -
    • Poisson::Implicit< Real , Dim , FEMSig >::Implicit( InputSampleStream< Real , Dim > &sStream , SolutionParameters< Real > sParams ):
      +
    • Poisson::Implicit< Real , Dim , FEMSig >::Implicit( InputOrientedSampleStream< Real , Dim > &sStream , SolutionParameters< Real > sParams ):
      This constructor creates a Poisson reconstruction object from an input sample stream (sStream) and a description of the reconstruction parameters (sParams) desribing the depth, number of samples per node, etc. (Reconstructors.h, line 340). This object derives from Implicit< Real , Dim , FEMSig >.
    • void Implicit< Real , Dim , FEMSig >::extractLevelSet( OutputVertexStream< Real , Dim > &vStream , &pStream , LevelSetExtractionParameters meParams ):
      This member function takes references to the output vertex and polygon streams (vStream and pStream) and parameters for level-set extraction (meParams) and computes the extracted triangle/polygon mesh, writing its vertices and faces into the corresponding output streams as they are generated (Reconstructors.h, line 99). @@ -1044,20 +1049,34 @@ This member function returns the value of the implicit function at the prescribe
    • Point< Real , Dim > Implicit::Evaluator::grad( Point< Real , Dim > ):
      This member function returns the gradient of the implicit function at the prescribed point. The point is assumed to be given in world coordinates, and a Implicit::Evaluator::OutOfUnitCubeException is thrown if it is outside of the unit-cube containing the input samples.
    +And, for samples with auxiliary data, the code supports construction of an extrapolating auxiliary data field that can be queried within the bounding cube: +
      +
    • Extrapolator::Implicit< Real , Dim , AuxData , DataDegree >::Implicit( InputStream< Real , Dim , AuxData > &pointStream , Parameters params , AuxData zeroAuxData ):
      +This constructor creates an extrapolating field from the samples with auxiliary data, using the prescribed parameters. The final parameter, zeroAuxData is an object representing the zero-element of the auxiliary data. +
    • AuxData Extrapolator::Implicit< Real , Dim , AuxData , DataDegree >::operator()( Point< Real , Dim > p ):
      +This method returns the extrapolated value at the prescribed position. +
    Code walk-through:
      These steps can be found in the Reconstruction.example.cpp code.
        -
      • The finite-elements signature is created in line 257. -
      • An input sample stream generating a specified number of random points on the surface of the sphere is defined in lines 81-119 and constructed in line 324. -
      • An output polygon stream that pushes the polygon to an std::vector of std::vector< int >s is defined in lines 167-182 and constructed in line 333. -
      • An output vertex stream that pushes just the position information to an std::vector of Reals is desfined in lines 185-195 and constructed in line 334. -
      • The reconstructor is constructed in line 326. -
      • The level-set extraction is performed on line 337. -
      • The evaluator is created on line 283. -
      • The evaluator is used to query the values and gradients of the implicit function in line 276. +
      • The finite-elements signature is created in line 308. +
      • An input sample stream generating a specified number of random points on the surface of the sphere is defined in lines 85-122 and constructed in line 374. +
      • An output polygon stream that pushes the polygon to an std::vector of std::vector< int >s is defined in lines 213-230 and constructed in line 384. +
      • An output vertex stream that pushes just the position information to an std::vector of Reals is desfined in lines 223-244 and constructed in line 385. +
      • The reconstructor is constructed in line 377. +
      • The level-set extraction is performed on line 388. +
      • The evaluator is created on line 334. +
      • The evaluator is used to query the values and gradients of the implicit function in line 327. +
      • The extrapolator is constructed on line 406. +
      • The extrapolator is evaluated at the vertex positions at line 416.
      -Note that a similar approach can be used to perform the Smoothed Signed Distance reconstruction (lines 370 and 371). The approach also supports reconstruction of meshes with auxiliary information like color (lines 292-319), with the only constraint that the auxiliary data type supports the computation affine combinations (e.g. the RGBColor type defined in lines 63-78). +Note that a similar approach can be used to perform the Smoothed Signed Distance reconstruction (lines 452 and 453).
      +The approach also supports reconstruction of meshes with auxiliary information like color, with the only constraint that the auxiliary data type supports the computation affine combinations (e.g. the RGBColor type defined in lines 67-82). The auxiliary inform is derived in one of two ways: +
        +
      1. As part of the reconstruction process, so that the level-set extraction phase also sets the auxiliary information. (Lines 343-470) +
      2. Independently by constructing the extrapolation field from the samples and then evaluating at the positions of the level-set vertices. (Lines 397-418) +
    @@ -1608,18 +1627,24 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • Replaced BlockedVector with NestedVector to reduce synchronization. -Version 18.10: +Version 18.10:
    1. Removed mutual exclusion in the iso-surfacing phase.
    -Version 18.20: +Version 18.20:
    1. Added an interface for evaluating the implicit function's values and gradients at points inside the bounding cube. -
    2. Added a --evaluate flag to the Reconstructor.example executable that evaluates the implicit function at an interior/exterior/boundary point on the sphere. +
    3. Added a --evaluate flag to the Reconstruction.example executable that evaluates the implicit function at an interior/exterior/boundary point on the sphere.
    4. Changed defaults for PoissonReconstruction to use value interpolation and to evaluate to 0.5 at the input samples.
    +Version 18.30: +
      +
    1. Added an interface for evaluating the implicit data (e.g. color) field extrapolated from the samples. +
    2. Modified the --color flag of the Reconstruction.example executable to support evaluation of colors from the extrapolated field. +
    +
    From 7853528dabb09ca71866f3c111f74e19a2024fc0 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Sun, 6 Oct 2024 22:25:04 -0400 Subject: [PATCH 55/86] Version 18.30 --- Src/Reconstructors.streams.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Src/Reconstructors.streams.h b/Src/Reconstructors.streams.h index 0f879b92..8788788c 100644 --- a/Src/Reconstructors.streams.h +++ b/Src/Reconstructors.streams.h @@ -198,13 +198,13 @@ namespace PoissonRecon } // Need to write the union to ensure that the counter gets set - size_t write( const size_t &idx , const Position< Real , Dim > &p , const Gradient< Real , Dim > &g , const Data& ... d ) + size_t write( const size_t &idx , const Position< Real , Dim > &p , const Gradient< Real , Dim > &g , const Weight< Real > &w , const Data& ... d ) { - return _stream.write( idx , _positionXForm * p , _gradientXForm * g , d... ); + return _stream.write( idx , _positionXForm * p , _gradientXForm * g , w , d... ); } - size_t write( unsigned int thread , const size_t &idx , const Position< Real , Dim > &p , const Gradient< Real , Dim > &g , const Data& ... d ) + size_t write( unsigned int thread , const size_t &idx , const Position< Real , Dim > &p , const Gradient< Real , Dim > &g , const Weight< Real > &w , const Data& ... d ) { - return _stream.write( thread , idx , _positionXForm * p , _gradientXForm * g , d... ); + return _stream.write( thread , idx , _positionXForm * p , _gradientXForm * g , w , d... ); } size_t size( void ) const { return _stream.size(); } protected: From 2de05d2eb0591947b26470a81924dd9bde352737 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Sun, 6 Oct 2024 23:27:10 -0400 Subject: [PATCH 56/86] Version 18.30 --- Src/DataStream.h | 3 --- Src/DataStream.inl | 17 ---------------- Src/FEMTree.LevelSet.2D.inl | 13 +----------- Src/FEMTree.LevelSet.3D.inl | 39 ++++-------------------------------- Src/Reconstructors.h | 25 ++++++++--------------- Src/Reconstructors.streams.h | 37 ---------------------------------- 6 files changed, 13 insertions(+), 121 deletions(-) diff --git a/Src/DataStream.h b/Src/DataStream.h index 8506a7ea..bf58a602 100644 --- a/Src/DataStream.h +++ b/Src/DataStream.h @@ -301,9 +301,6 @@ namespace PoissonRecon protected: -#ifdef DEBUG_STREAM - size_t _current = 0; -#endif // DEBUG_STREAM struct _NextValue { std::tuple< size_t , Data ... > data; diff --git a/Src/DataStream.inl b/Src/DataStream.inl index b4a042f2..a880c7fe 100644 --- a/Src/DataStream.inl +++ b/Src/DataStream.inl @@ -404,27 +404,10 @@ bool InterleavedMultiInputIndexedDataStream< Data ... >::read( Data& ... d ) { if( _firstTime ) _init(d...) , _firstTime = false; std::pop_heap( _nextValues.begin() , _nextValues.end() , _NextValue::Compare ); -#ifdef DEBUG_STREAM -#if 0 - static unsigned int count = 0; - if( count<10 ) - { - std::vector< _NextValue > foo = _nextValues; - std::sort( foo.begin() , foo.end() , []( const _NextValue &v1 , const _NextValue &v2 ){ return v1.streamIndex::FromTuple( next.data , sz , d... ); -#ifdef DEBUG_STREAM - if( next.data.idx!=_current ) ERROR_OUT( "out of order: Expected = " , _current , ", Found = " , next.data.idx ); - _current++; -#endif // DEBUG_STREAM next.validData = _multiStream.read( next.streamIndex , next.data ); diff --git a/Src/FEMTree.LevelSet.2D.inl b/Src/FEMTree.LevelSet.2D.inl index 6b0e8093..7fa37bc7 100644 --- a/Src/FEMTree.LevelSet.2D.inl +++ b/Src/FEMTree.LevelSet.2D.inl @@ -688,7 +688,7 @@ public: GetIsoVertex< WeightDegree , DataSig >( tree , nonLinearFit , outputGradients , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , e , sValues , vertex , zeroData ); bool stillOwner = false; std::pair< node_index_type , Vertex > hashed_vertex; - if constexpr( std::is_base_of_v< OutputIndexedVertexStream , VertexStream > ) + { char desired = 1 , expected = 0; #ifdef SANITIZED_PR @@ -701,17 +701,6 @@ public: stillOwner = true; } } - else if constexpr( std::is_base_of_v< OutputVertexStream , VertexStream > ) - { - std::lock_guard< std::mutex > lock( _pointInsertionMutex ); - if( !edgeSet ) - { - hashed_vertex = std::pair< node_index_type , Vertex >( (node_index_type)vertexStream.write( thread , vertex ) , vertex ); - edgeSet = 1; - stillOwner = true; - } - } - else ERROR_OUT( "Bad stream type: " , typeid(VertexStream).name() ); if( stillOwner ) // If this edge is the one generating the iso-vertex { diff --git a/Src/FEMTree.LevelSet.3D.inl b/Src/FEMTree.LevelSet.3D.inl index d64c950f..92fddb83 100644 --- a/Src/FEMTree.LevelSet.3D.inl +++ b/Src/FEMTree.LevelSet.3D.inl @@ -758,9 +758,7 @@ public: vertices[i].template get<1>() = Point< Real , Dim >(); vertices[i].template get<2>() = depth; if constexpr( HasData ) vertices[i].template get<3>() = dataValue; - if constexpr( std::is_base_of_v< OutputIndexedVertexStream , VertexStream > ) vertexIndices[i] = (node_index_type)vertexStream.write( 0 , vertices[i] ); - else if constexpr( std::is_base_of_v< OutputVertexStream , VertexStream > ) vertexIndices[i] = (node_index_type)vertexStream.write( vertices[i] ); - else ERROR_OUT( "Bad stream type: " , typeid(VertexStream).name() ); + vertexIndices[i] = (node_index_type)vertexStream.write( 0 , vertices[i] ); } } @@ -1066,7 +1064,7 @@ public: GetIsoVertex< WeightDegree , DataSig >( tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , _e , zDir , sValues , vertex , zeroData ); bool stillOwner = false; std::pair< node_index_type , Vertex > hashed_vertex; - if constexpr( std::is_base_of_v< OutputIndexedVertexStream , VertexStream > ) + { char desired = 1 , expected = 0; #ifdef SANITIZED_PR @@ -1079,17 +1077,6 @@ public: stillOwner = true; } } - else if constexpr( std::is_base_of_v< OutputVertexStream , VertexStream > ) - { - std::lock_guard< std::mutex > lock( _pointInsertionMutex ); - if( !edgeSet ) - { - hashed_vertex = std::pair< node_index_type , Vertex >( (node_index_type)vertexStream.write( vertex ) , vertex ); - edgeSet = 1; - stillOwner = true; - } - } - else ERROR_OUT( "Bad stream type: " , typeid(VertexStream).name() ); if( stillOwner ) { @@ -1218,7 +1205,7 @@ public: GetIsoVertex< WeightDegree , DataSig >( tree , nonLinearFit , gradientNormals , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , _c , bCoordinate , fCoordinate , bValues , fValues , vertex , zeroData ); bool stillOwner = false; std::pair< node_index_type , Vertex > hashed_vertex; - if constexpr( std::is_base_of_v< OutputIndexedVertexStream , VertexStream > ) + { char desired = 1 , expected = 0; #ifdef SANITIZED_PR @@ -1231,17 +1218,6 @@ public: stillOwner = true; } } - else if constexpr( std::is_base_of_v< OutputVertexStream , VertexStream > ) - { - std::lock_guard< std::mutex > lock( _pointInsertionMutex ); - if( !edgeSet ) - { - hashed_vertex = std::pair< node_index_type , Vertex >( (node_index_type)vertexStream.write( vertex ) , vertex ); - edgeSet = 1; - stillOwner = true; - } - } - else ERROR_OUT( "Bad stream type: " , typeid(VertexStream).name() ); if( stillOwner ) { @@ -1961,14 +1937,7 @@ public: for( unsigned int i=0 ; i ) cIdx = (node_index_type)vertexStream.write( thread , c ); - else if constexpr( std::is_base_of_v< OutputVertexStream , VertexStream > ) - { - std::lock_guard< std::mutex > lock( _pointInsertionMutex ); - cIdx = (node_index_type)vertexStream.write( c ); - } - else ERROR_OUT( "Bad stream type: " , typeid(VertexStream).name() ); + node_index_type cIdx = (node_index_type)vertexStream.write( thread , c ); for( unsigned i=0 ; i + template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ImplicitType , unsigned int ... FEMSigs > void _ExtractLevelSet( UIntPack< FEMSigs ... > , const ImplicitType &implicit , OutputVertexStream &vertexStream , OutputFaceStream< Dim-1 > &faceStream , typename Implicit< Real , Dim , FEMSig >::LevelSetExtractionParameters params ); // Specialized solution information without auxiliary data @@ -99,12 +99,7 @@ namespace PoissonRecon void extractLevelSet( OutputLevelSetVertexStream< Real , Dim > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const { typedef unsigned char AuxData; - _ExtractLevelSet< false , false , Real , Dim , FEMSig , AuxData , OutputLevelSetVertexStream< Real , Dim > , Implicit< Real , Dim , FEMSig > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); - } - void extractLevelSet( OutputIndexedLevelSetVertexStream< Real , Dim > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const - { - typedef unsigned char AuxData; - _ExtractLevelSet< false , true , Real , Dim , FEMSig , AuxData , OutputIndexedLevelSetVertexStream< Real , Dim > , Implicit< Real , Dim , FEMSig > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); + _ExtractLevelSet< false , Real , Dim , FEMSig , AuxData , OutputLevelSetVertexStream< Real , Dim > , Implicit< Real , Dim , FEMSig > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); } struct Evaluator @@ -186,11 +181,7 @@ namespace PoissonRecon // A method for writing the extracted mesh to the streams void extractLevelSet( OutputLevelSetVertexStream< Real , Dim , AuxData > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const { - _ExtractLevelSet< true , false , Real , Dim , FEMSig , AuxData , OutputLevelSetVertexStream< Real , Dim , AuxData > , Implicit< Real , Dim , FEMSig , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); - } - void extractLevelSet( OutputIndexedLevelSetVertexStream< Real , Dim , AuxData > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const - { - _ExtractLevelSet< true , true , Real , Dim , FEMSig , AuxData , OutputIndexedLevelSetVertexStream< Real , Dim , AuxData > , Implicit< Real , Dim , FEMSig , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); + _ExtractLevelSet< true , Real , Dim , FEMSig , AuxData , OutputLevelSetVertexStream< Real , Dim , AuxData > , Implicit< Real , Dim , FEMSig , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); } }; @@ -510,7 +501,7 @@ namespace PoissonRecon - template< bool HasAuxData , bool IndexedVertexStream , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ImplicitType , unsigned int ... FEMSigs > + template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ImplicitType , unsigned int ... FEMSigs > void _ExtractLevelSet( UIntPack< FEMSigs ... > , const ImplicitType &implicit , OutputVertexStream &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) { typedef UIntPack< FEMSigs ... > Sigs; @@ -536,14 +527,14 @@ namespace PoissonRecon if constexpr( HasAuxData ) { typename LevelSetExtractor< Real , Dim , AuxData >::Stats stats; - std::conditional_t< IndexedVertexStream , TransformedOutputIndexedLevelSetVertexStream< Real , Dim , AuxData > , TransformedOutputLevelSetVertexStream< Real , Dim , AuxData > > _vertexStream( unitCubeToModel , vertexStream ); + TransformedOutputLevelSetVertexStream< Real , Dim , AuxData > _vertexStream( unitCubeToModel , vertexStream ); stats = LevelSetExtractor< Real , Dim , AuxData >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , UIntPack< DataSig >() , implicit.tree , implicit.density , implicit.auxData , implicit.solution , implicit.isoValue , _vertexStream , faceStream , implicit.zeroAuxData , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); statsString = stats.toString(); } else { typename LevelSetExtractor< Real , Dim >::Stats stats; - std::conditional_t< IndexedVertexStream , TransformedOutputIndexedLevelSetVertexStream< Real , Dim > , TransformedOutputLevelSetVertexStream< Real , Dim > > _vertexStream( unitCubeToModel , vertexStream ); + TransformedOutputLevelSetVertexStream< Real , Dim > _vertexStream( unitCubeToModel , vertexStream ); stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , implicit.tree , implicit.density , implicit.solution , implicit.isoValue , _vertexStream , faceStream , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); statsString = stats.toString(); } @@ -563,14 +554,14 @@ namespace PoissonRecon if constexpr( HasAuxData ) { typename LevelSetExtractor< Real , Dim , AuxData >::Stats stats; - std::conditional_t< IndexedVertexStream , TransformedOutputIndexedLevelSetVertexStream< Real , Dim , AuxData > , TransformedOutputLevelSetVertexStream< Real , Dim , AuxData > > _vertexStream( unitCubeToModel , vertexStream ); + TransformedOutputLevelSetVertexStream< Real , Dim , AuxData > _vertexStream( unitCubeToModel , vertexStream ); stats = LevelSetExtractor< Real , Dim , AuxData >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , UIntPack< DataSig >() , implicit.tree , implicit.density , implicit.auxData , implicit.solution , implicit.isoValue , _vertexStream , faceStream , implicit.zeroAuxData , !params.linearFit , params.outputGradients , false ); statsString = stats.toString(); } else { typename LevelSetExtractor< Real , Dim >::Stats stats; - std::conditional_t< IndexedVertexStream , TransformedOutputIndexedLevelSetVertexStream< Real , Dim > , TransformedOutputLevelSetVertexStream< Real , Dim > > _vertexStream( unitCubeToModel , vertexStream ); + TransformedOutputLevelSetVertexStream< Real , Dim > _vertexStream( unitCubeToModel , vertexStream ); stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , implicit.tree , implicit.density , implicit.solution , implicit.isoValue , _vertexStream , faceStream , !params.linearFit , params.outputGradients , false ); statsString = stats.toString(); } diff --git a/Src/Reconstructors.streams.h b/Src/Reconstructors.streams.h index 8788788c..2fd19fa5 100644 --- a/Src/Reconstructors.streams.h +++ b/Src/Reconstructors.streams.h @@ -65,9 +65,6 @@ namespace PoissonRecon template< typename Real , unsigned int Dim , typename ... Data > using OutputLevelSetVertexStream = OutputDataStream< Position< Real , Dim > , Gradient< Real , Dim > , Weight< Real > , Data ... >; template< typename Real , unsigned int Dim , typename ... Data > struct TransformedOutputLevelSetVertexStream; - template< typename Real , unsigned int Dim , typename ... Data > using OutputIndexedLevelSetVertexStream = OutputDataStream< size_t , Position< Real , Dim > , Gradient< Real , Dim > , Weight< Real > , Data ... >; - template< typename Real , unsigned int Dim , typename ... Data > struct TransformedOutputIndexedLevelSetVertexStream; - ////////////////// // Face streams // ////////////////// @@ -185,40 +182,6 @@ namespace PoissonRecon }; - ////////////////////////////////////////////// - // Transformed Output Indexed Vertex Stream // - ////////////////////////////////////////////// - template< typename Real , unsigned int Dim , typename ... Data > - struct TransformedOutputIndexedLevelSetVertexStream : public OutputIndexedLevelSetVertexStream< Real , Dim , Data ... > - { - // A constructor initialized with the transformation to be applied to the samples, and a sample stream - TransformedOutputIndexedLevelSetVertexStream( XForm< Real , Dim+1 > xForm , OutputIndexedLevelSetVertexStream< Real , Dim , Data ... > &stream ) : _stream(stream) , _positionXForm(xForm) - { - _gradientXForm = XForm< Real , Dim > ( xForm ).inverse().transpose() * (Real)pow( xForm.determinant() , 1./Dim ); - } - - // Need to write the union to ensure that the counter gets set - size_t write( const size_t &idx , const Position< Real , Dim > &p , const Gradient< Real , Dim > &g , const Weight< Real > &w , const Data& ... d ) - { - return _stream.write( idx , _positionXForm * p , _gradientXForm * g , w , d... ); - } - size_t write( unsigned int thread , const size_t &idx , const Position< Real , Dim > &p , const Gradient< Real , Dim > &g , const Weight< Real > &w , const Data& ... d ) - { - return _stream.write( thread , idx , _positionXForm * p , _gradientXForm * g , w , d... ); - } - size_t size( void ) const { return _stream.size(); } - protected: - // A reference to the underlying stream - OutputIndexedLevelSetVertexStream< Real , Dim , Data ... > &_stream; - - // The affine transformation to be applied to the positions - XForm< Real , Dim+1 > _positionXForm; - - // The linear transformation to be applied to the normals - XForm< Real , Dim > _gradientXForm; - }; - - ////////////////////////////////// // File-backed streaming memory // ////////////////////////////////// From ed2934c2d629694e4b5b8ec46c55cf3ee1642192 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Tue, 8 Oct 2024 11:06:43 -0400 Subject: [PATCH 57/86] Version 18.30 --- Src/DataStream.h | 12 ------------ Src/DataStream.inl | 35 ----------------------------------- Src/FEMTree.LevelSet.2D.inl | 2 -- Src/FEMTree.LevelSet.3D.inl | 2 -- Src/Reconstructors.streams.h | 1 - 5 files changed, 52 deletions(-) diff --git a/Src/DataStream.h b/Src/DataStream.h index bf58a602..38348b1c 100644 --- a/Src/DataStream.h +++ b/Src/DataStream.h @@ -184,10 +184,6 @@ namespace PoissonRecon protected: std::vector< InputDataStream< Data ... > * > _streams; unsigned int _current; - - MultiInputDataStream( void ); - void _init( InputDataStream< Data ... > **streams , size_t N ); - void _init( const std::vector< InputDataStream< Data ... > * > &streams ); }; @@ -212,10 +208,6 @@ namespace PoissonRecon protected: std::vector< OutputDataStream< Data ... > * > _streams; std::atomic< size_t > _size; - - MultiOutputDataStream( void ); - void _init( OutputDataStream< Data ... > **streams , size_t N ); - void _init( const std::vector< OutputDataStream< Data ... > * > &streams ); }; ///////////////////////////////// @@ -278,10 +270,6 @@ namespace PoissonRecon protected: MultiOutputIndexedDataStream< Data ... > _multiStream; std::atomic< size_t > _size; - - DeInterleavedMultiOutputIndexedDataStream( void ); - void _init( OutputIndexedDataStream< Data ... > **streams , size_t N ); - void _init( const std::vector< OutputIndexedDataStream< Data ... > * > &streams ); }; diff --git a/Src/DataStream.inl b/Src/DataStream.inl index a880c7fe..547a31b4 100644 --- a/Src/DataStream.inl +++ b/Src/DataStream.inl @@ -223,19 +223,6 @@ bool MultiInputDataStream< Data ... >::read( Data& ... d ) return false; } -template< typename ...Data > -MultiInputDataStream< Data ... >::MultiInputDataStream( void ) {} - -template< typename ...Data > -void MultiInputDataStream< Data ... >::_init( InputDataStream< Data ... > **streams , size_t N ) -{ - _streams.resize( N ); - for( unsigned int i=0 ; i -void MultiInputDataStream< Data ... >::_init( const std::vector< InputDataStream< Data ... > * > &streams ){ _streams = streams; } - ///////////////////////////////// // Multiple output data stream // ///////////////////////////////// @@ -258,19 +245,6 @@ size_t MultiOutputDataStream< Data ... >::write( unsigned int t , const Data& .. template< typename ... Data > MultiOutputDataStream< Data ... >::MultiOutputDataStream( void ) {} -#if 0 -template< typename ... Data > -void MultiOutputDataStream< Data ... >::_init( OutputDataStream< Data ... > **streams , size_t N ) -{ - _size = 0; - _streams.resize( N ); - for( unsigned int i=0 ; i -void MultiOutputDataStream< Data ... >::_init( const std::vector< OutputDataStream< Data ... > * > &streams ){ _streams = streams; } - //////////////////////////////////////////////// // De-interleaved multiple output data stream // //////////////////////////////////////////////// @@ -290,15 +264,6 @@ size_t DeInterleavedMultiOutputIndexedDataStream< Data ... >::write( template< typename ... Data > size_t DeInterleavedMultiOutputIndexedDataStream< Data ... >::write( unsigned int thread , const Data& ... d ){ size_t idx = _size++ ; _multiStream.write( thread , idx , d... ) ; return idx; } -template< typename ... Data > -DeInterleavedMultiOutputIndexedDataStream< Data ... >::DeInterleavedMultiOutputIndexedDataStream( void ) {} - -template< typename ... Data > -void DeInterleavedMultiOutputIndexedDataStream< Data ... >::_init( OutputIndexedDataStream< Data ... > **streams , size_t N ){ _multiStream._init( streams , N ); } - -template< typename ... Data > -void DeInterleavedMultiOutputIndexedDataStream< Data ... >::_init( const std::vector< OutputIndexedDataStream< Data ... > * > &streams ){ _multiStream.init( streams ); } - ///////////////////////////////// // Input data stream converter // ///////////////////////////////// diff --git a/Src/FEMTree.LevelSet.2D.inl b/Src/FEMTree.LevelSet.2D.inl index 7fa37bc7..2479f90a 100644 --- a/Src/FEMTree.LevelSet.2D.inl +++ b/Src/FEMTree.LevelSet.2D.inl @@ -54,7 +54,6 @@ struct _LevelSetExtractor< HasData , Real , 2 , Data > >; protected: - static std::mutex _pointInsertionMutex; static std::atomic< size_t > _BadRootCount; public: @@ -1146,7 +1145,6 @@ public: } }; -template< bool HasData , typename Real , typename Data > std::mutex _LevelSetExtractor< HasData , Real , 2 , Data >::_pointInsertionMutex; template< bool HasData , typename Real , typename Data > std::atomic< size_t > _LevelSetExtractor< HasData , Real , 2 , Data >::_BadRootCount; template< typename Real > diff --git a/Src/FEMTree.LevelSet.3D.inl b/Src/FEMTree.LevelSet.3D.inl index 92fddb83..81e15835 100644 --- a/Src/FEMTree.LevelSet.3D.inl +++ b/Src/FEMTree.LevelSet.3D.inl @@ -54,7 +54,6 @@ struct _LevelSetExtractor< HasData , Real , 3 , Data > >; protected: - static std::mutex _pointInsertionMutex; static std::atomic< size_t > _BadRootCount; public: @@ -2408,7 +2407,6 @@ public: } }; -template< bool HasData , typename Real , typename Data > std::mutex _LevelSetExtractor< HasData , Real , 3 , Data >::_pointInsertionMutex; template< bool HasData , typename Real , typename Data > std::atomic< size_t > _LevelSetExtractor< HasData , Real , 3 , Data >::_BadRootCount; template< typename Real > diff --git a/Src/Reconstructors.streams.h b/Src/Reconstructors.streams.h index 2fd19fa5..fd787901 100644 --- a/Src/Reconstructors.streams.h +++ b/Src/Reconstructors.streams.h @@ -29,7 +29,6 @@ DAMAGE. #ifndef RECONSTRUCTORS_STREAMS_INCLUDED #define RECONSTRUCTORS_STREAMS_INCLUDED -#include #include "FEMTree.h" #include "MyExceptions.h" #include "Array.h" From e2edd3d656a7a73d82735d4d5af49b0f974c8d26 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Wed, 9 Oct 2024 12:02:42 -0400 Subject: [PATCH 58/86] Version 18.30 --- Src/DataStream.inl | 3 -- Src/Reconstructors.h | 71 +++++++++++++++++--------------------------- 2 files changed, 28 insertions(+), 46 deletions(-) diff --git a/Src/DataStream.inl b/Src/DataStream.inl index 547a31b4..0587c2ac 100644 --- a/Src/DataStream.inl +++ b/Src/DataStream.inl @@ -242,9 +242,6 @@ size_t MultiOutputDataStream< Data ... >::write( const Data& .. template< typename ... Data > size_t MultiOutputDataStream< Data ... >::write( unsigned int t , const Data& ... d ){ size_t idx = _size++ ; _streams[t]->write(d...) ; return idx; } -template< typename ... Data > -MultiOutputDataStream< Data ... >::MultiOutputDataStream( void ) {} - //////////////////////////////////////////////// // De-interleaved multiple output data stream // //////////////////////////////////////////////// diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h index 80e00273..735a6a0d 100644 --- a/Src/Reconstructors.h +++ b/Src/Reconstructors.h @@ -712,26 +712,18 @@ namespace PoissonRecon typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; { using ExternalType = std::tuple< Point< Real , Dim > , NormalAndAuxData >; - if constexpr( HasAuxData ) - { - using InternalType = std::tuple< Point< Real , Dim > , Point< Real , Dim > , AuxData >; - auto converter = []( const InternalType &iType ) - { - ExternalType xType; - std::get< 0 >( xType ) = std::get< 0 >( iType ); - std::get< 1 >( xType ).template get<0>() = std::get< 1 >( iType ); - std::get< 1 >( xType ).template get<1>() = std::get< 2 >( iType ); - return xType; - }; - InputDataStreamConverter< InternalType , ExternalType > __pointStream( _pointStream , converter , Point< Real , Dim >() , Point< Real , Dim >() , implicit.zeroAuxData ); - if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , __pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , __pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); - } - else - { - if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); - } + using InternalType = std::tuple< Point< Real , Dim > , Point< Real , Dim > , AuxData >; + auto converter = []( const InternalType &iType ) + { + ExternalType xType; + std::get< 0 >( xType ) = std::get< 0 >( iType ); + std::get< 1 >( xType ).template get<0>() = std::get< 1 >( iType ); + std::get< 1 >( xType ).template get<1>() = std::get< 2 >( iType ); + return xType; + }; + InputDataStreamConverter< InternalType , ExternalType > __pointStream( _pointStream , converter , Point< Real , Dim >() , Point< Real , Dim >() , implicit.zeroAuxData ); + if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , __pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , __pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); } } else @@ -753,7 +745,7 @@ namespace PoissonRecon typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); } implicit.unitCubeToModel = modelToUnitCube.inverse(); @@ -1183,27 +1175,20 @@ namespace PoissonRecon typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; { using ExternalType = std::tuple< Point< Real , Dim > , NormalAndAuxData >; - if constexpr( HasAuxData ) - { - using InternalType = std::tuple< Point< Real , Dim > , Point< Real , Dim > , AuxData >; - auto converter = []( const InternalType &iType ) - { - ExternalType xType; - std::get< 0 >( xType ) = std::get< 0 >( iType ); - std::get< 1 >( xType ).template get<0>() = std::get< 1 >( iType ); - std::get< 1 >( xType ).template get<1>() = std::get< 2 >( iType ); - return xType; - }; - InputDataStreamConverter< InternalType , ExternalType > __pointStream( _pointStream , converter , Point< Real , Dim >() , Point< Real , Dim >() , implicit.zeroAuxData ); - if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , __pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , __pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); - } - else - { - if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); - } - } } + using InternalType = std::tuple< Point< Real , Dim > , Point< Real , Dim > , AuxData >; + auto converter = []( const InternalType &iType ) + { + ExternalType xType; + std::get< 0 >( xType ) = std::get< 0 >( iType ); + std::get< 1 >( xType ).template get<0>() = std::get< 1 >( iType ); + std::get< 1 >( xType ).template get<1>() = std::get< 2 >( iType ); + return xType; + }; + InputDataStreamConverter< InternalType , ExternalType > __pointStream( _pointStream , converter , Point< Real , Dim >() , Point< Real , Dim >() , implicit.zeroAuxData ); + if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , __pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , __pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); + } + } else { TransformedInputOrientedSampleStream< Real , Dim > _pointStream( modelToUnitCube , pointStream ); @@ -1223,7 +1208,7 @@ namespace PoissonRecon typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); } implicit.unitCubeToModel = modelToUnitCube.inverse(); From b81dcedaa0a547bee357f5e03ac47d891205b513 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Wed, 9 Oct 2024 12:10:18 -0400 Subject: [PATCH 59/86] Version 18.31 --- README.md | 16 +++++++++------- Src/SurfaceTrimmer.cpp | 25 +------------------------ 2 files changed, 10 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 2a43d495..dbcc0a65 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 18.30)

    +

    Adaptive Multigrid Solvers (Version 18.31)

    links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
    Executables: -Win64
    +Win64
    Source Code: -ZIP GitHub
    +ZIP GitHub
    Older Versions: +V18.30, V18.20, V18.10, V18.05, @@ -708,10 +709,6 @@ The file is read in PLY format. -
    [--smooth <smoothing iterations>] -
    This integer values the number of umbrella smoothing operations to perform on the signal before trimming.
    -The default value is 5. -
    [--aRatio <island area ratio>]
    This floating point value specifies the area ratio that defines a disconnected component as an "island". Connected components whose area, relative to the total area of the mesh, are smaller than this value will be merged into the output surface to close small holes.
    The default value 0.001. @@ -1645,6 +1642,11 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • Modified the --color flag of the Reconstruction.example executable to support evaluation of colors from the extrapolated field. +Version 18.31: +
      +
    1. Removed the smoothing option in the SufaceTrimmer executable. +
    +
    diff --git a/Src/SurfaceTrimmer.cpp b/Src/SurfaceTrimmer.cpp index 50c22a09..668d5e6f 100644 --- a/Src/SurfaceTrimmer.cpp +++ b/Src/SurfaceTrimmer.cpp @@ -49,8 +49,6 @@ using namespace PoissonRecon; CmdLineParameter< char* > In( "in" ) , Out( "out" ); -CmdLineParameter< int > - Smooth( "smooth" , 5 ); CmdLineParameter< float > Trim( "trim" ) , IslandAreaRatio( "aRatio" , 0.001f ); @@ -65,7 +63,7 @@ CmdLineReadable CmdLineReadable* params[] = { - &In , &Out , &Trim , &PolygonMesh , &Smooth , &IslandAreaRatio , &Verbose , &Long , &ASCII , &RemoveIslands , &Debug , + &In , &Out , &Trim , &PolygonMesh , &IslandAreaRatio , &Verbose , &Long , &ASCII , &RemoveIslands , &Debug , NULL }; @@ -75,7 +73,6 @@ void ShowUsage( char* 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" , RemoveIslands.name ); printf( "\t[--%s]\n" , Debug.name ); @@ -214,25 +211,6 @@ ValuedPointData< Real , Dim , AuxData ... > InterpolateVertices( const ValuedPoi return v1 * (Real)(1.-dx) + v2*dx; } -template< typename Real , unsigned int Dim , typename Index , typename ... AuxData > -void SmoothValues( std::vector< ValuedPointData< Real , Dim , AuxData ... > >& vertices , const std::vector< std::vector< Index > >& polygons ) -{ - std::vector< int > count( vertices.size() ); - std::vector< Real > sums( vertices.size() , 0 ); - for( size_t i=0 ; i() , sums[v2] += vertices[v1].template get<1>(); - } - } - for( size_t i=0 ; i() = ( sums[i] + vertices[i].template get<1>() ) / ( count[i] + 1 ); -} - template< typename Real , unsigned int Dim , typename Index , typename ... AuxData > void SplitPolygon ( @@ -431,7 +409,6 @@ int Execute( AuxDataFactories ... auxDataFactories ) std::vector< std::string > comments; PLY::ReadPolygons< Factory , Index >( In.value , factory , vertices , polygons , ft , comments ); - for( int i=0 ; i( vertices , polygons ); min = max = vertices[0].template get<1>(); for( size_t i=0 ; i( min , vertices[i].template get<1>() ) , max = std::max< Real >( max , vertices[i].template get<1>() ); From b9d0f060badd8351127c67e96dafab97e8796696 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Sun, 13 Oct 2024 09:17:07 -0400 Subject: [PATCH 60/86] Version 18.31 --- README.md | 19 ++++++++-- Src/EDTInHeat.cpp | 2 +- Src/Extrapolator.h | 3 +- Src/FEMTree.Initialize.inl | 71 +++++++++++++++++++------------------ Src/FEMTree.h | 16 +++++---- Src/PointInterpolant.cpp | 4 +-- Src/PoissonRecon.client.inl | 24 ++++++------- Src/Reconstructors.h | 22 +++++------- 8 files changed, 89 insertions(+), 72 deletions(-) diff --git a/README.md b/README.md index dbcc0a65..22e3f823 100644 --- a/README.md +++ b/README.md @@ -161,10 +161,25 @@ The file is written in size() << std::endl; } @@ -1172,7 +1169,6 @@ namespace PoissonRecon return (Real)1.; }; - typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; { using ExternalType = std::tuple< Point< Real , Dim > , NormalAndAuxData >; using InternalType = std::tuple< Point< Real , Dim > , Point< Real , Dim > , AuxData >; @@ -1185,8 +1181,8 @@ namespace PoissonRecon return xType; }; InputDataStreamConverter< InternalType , ExternalType > __pointStream( _pointStream , converter , Point< Real , Dim >() , Point< Real , Dim >() , implicit.zeroAuxData ); - if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , __pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , __pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); + if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( implicit.tree.spaceRoot() , __pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( implicit.tree.spaceRoot() , __pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); } } else @@ -1207,8 +1203,8 @@ namespace PoissonRecon }; typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; - if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( sid , implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , true , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); + if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); } implicit.unitCubeToModel = modelToUnitCube.inverse(); From 387fa8acc7871133efbe1fe20083bd57899ef018 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Tue, 15 Oct 2024 19:08:23 -0400 Subject: [PATCH 61/86] Version 18.35 --- README.md | 102 +++- Src/AdaptiveTreeVisualization.cpp | 11 +- Src/EDTInHeat.cpp | 3 +- Src/FEMTree.Initialize.inl | 117 +++-- Src/FEMTree.LevelSet.2D.inl | 46 +- Src/FEMTree.LevelSet.3D.inl | 50 -- Src/FEMTree.h | 9 +- Src/FEMTree.inl | 6 +- Src/Geometry.h | 28 +- Src/PointInterpolant.cpp | 3 +- Src/PoissonRecon.client.inl | 73 +-- Src/PoissonRecon.cpp | 36 +- Src/PoissonRecon.server.inl | 9 +- Src/PoissonReconClientServer.h | 2 +- Src/PoissonReconClientServer.inl | 5 +- Src/PoissonReconServer.cpp | 5 +- Src/PreProcessor.h | 2 +- Src/Reconstruction.example.cpp | 29 +- Src/Reconstructors.h | 815 +++++++++++++++--------------- Src/SSDRecon.cpp | 35 +- 20 files changed, 676 insertions(+), 710 deletions(-) diff --git a/README.md b/README.md index 22e3f823..46e304f3 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 18.31)

    +

    Adaptive Multigrid Solvers (Version 18.35)

    links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
    Executables: -Win64
    +Win64
    Source Code: -ZIP GitHub
    +ZIP GitHub
    Older Versions: +V18.31, V18.30, V18.20, V18.10, @@ -501,8 +502,21 @@ The file is written in Reconstruction.example.cpp In addition to executables, the reconstruction code can be interfaced into through the functionality implemented in Reconstructors.h and Extrapolator.h -Using the functionality requires requires choosing a finite element type, FEMSig and defining one input stream and two output streams. +Using the functionality requires requires choosing a finite element type and defining input oriented-point stream and output vertex and face streams. In the descriptions below, the template parameter Real is the floating point type used to represent data (typically float) and Dim is the integer dimension of the space (fixed at Dim=3).
      -
    • The template parameter FEMSig describes the finite element type, which is a composite of the degree of the finite element and the boundary conditions it satisfies. Given an integer valued Degree and boundary type BType (one of BOUNDARY_FREE, BOUNDARY_DIRICHLET, and BOUNDARY_NEUMANN defined in BSplineData.h), the signature is defined by setting: +
    • The template parameter FEMSig describes the 1D finite element type, which is a composite of the degree of the finite element and the boundary conditions it satisfies. Given an integer valued Degree and boundary type BType (one of BOUNDARY_FREE, BOUNDARY_DIRICHLET, and BOUNDARY_NEUMANN defined in BSplineData.h), the signature is defined as (Reconstruction.example.cppy line 308):
       static const unsigned int FEMSig = FEMDegreeAndBType< Degree , BoundaryType >::Signature;
       
      +
    • The template parameter FEMSIgs describes the tensor-product finite element type, typically defined as an "isotropic" element with the same 1D finite element type across all Dim dimensions. It is defined as (Reconstruction.example.cppy line 314): +
      +using FEMSigs = IsotropicUIntPack< Dim , FEMSig >;
      +
    -The three streams are defined by overriding virtual stream classes. In the descriptions below, the template parameter Real is the floating point type used to represent data (typically float) and Dim is the integer dimension of the space (fixed at Dim=3). The namespace Reconstructor is omitted for brevity. +The three streams are defined by overriding virtual stream classes. The namespace PoissonRecon::Reconstructor is omitted for brevity.
    • Input sample stream: This class derives from the InputSampleStream< Real , Dim > class. The base class has two pure virtual methods that need to be over-ridden: @@ -1045,21 +1090,21 @@ This method returns the number of vertices written. This method writes the information for the next vertx into the stream. The data includes the position of the vertex, p, as well as the gradient, g, and density weight, w if the extraction code is asked to compute those. The function returns the index of the written vertex.
    -The reconstructed surface is then computed in two steps: +The reconstructed surface is then computed in two steps. First, an Implict< Real , Dim , FEMSigs > object is created, encoding the implicit function describing the geometry, as well as a density function describing the distribution of points in space and (possibly) a function extrapolating per-sample information into a volumetric function. Then, the implicit function is iso-surfaced, (possibly) with auxialiary density and color information evaluated at the vertex positions.
      -
    • Poisson::Implicit< Real , Dim , FEMSig >::Implicit( InputOrientedSampleStream< Real , Dim > &sStream , SolutionParameters< Real > sParams ):
      -This constructor creates a Poisson reconstruction object from an input sample stream (sStream) and a description of the reconstruction parameters (sParams) desribing the depth, number of samples per node, etc. (Reconstructors.h, line 340). This object derives from Implicit< Real , Dim , FEMSig >. -
    • void Implicit< Real , Dim , FEMSig >::extractLevelSet( OutputVertexStream< Real , Dim > &vStream , &pStream , LevelSetExtractionParameters meParams ):
      -This member function takes references to the output vertex and polygon streams (vStream and pStream) and parameters for level-set extraction (meParams) and computes the extracted triangle/polygon mesh, writing its vertices and faces into the corresponding output streams as they are generated (Reconstructors.h, line 99). +
    • Implict< Real , Dim , FEMSigs > *Poisson::Solver< Real , Dim , FEMSigs >::Solve( InputOrientedSampleStream< Real , Dim > &pointStream , SolutionParameters< Real > params ):
      +This function takes in an input oriented sample stream (pointStream) and a description of the reconstruction parameters (params) desribing the depth, number of samples per node, etc., and returns a pointer to the (dynamically allocated) implicit represetation (Reconstructors.h, line 622). +
    • void Implicit< Real , Dim , FEMSigs >::extractLevelSet( OutputVertexStream< Real , Dim > &vStream , OutputFaceStream< Dim-1 > &pStream , LevelSetExtractionParameters meParams ):
      +This member function takes references to the output vertex (vStream) and polygon (pStream) streams and parameters for level-set extraction (meParams) and computes the extracted mesh, writing its vertices and faces into the corresponding output streams as they are generated (Reconstructors.h, line 548).
    In Addition, the code supports evaluation of the implicit function at points within the bounding cube:
      -
    • Poisson::Implicit::evaluator( void ):
      -This member function returns an object of type Implicit::Evaluator. (Note that as the Implicit::Evaluator object stores const references to the state in the Poisson::Implicit object, it will not be valid once the defining Poisson::Implicit object goes out of scope.) -
    • Real Implicit::Evaluator::operator()( Point< Real , Dim > ):
      -This member function returns the value of the implicit function at the prescribed point. The point is assumed to be given in world coordinates, and a Implicit::Evaluator::OutOfUnitCubeException is thrown if it is outside of the unit-cube containing the input samples. -
    • Point< Real , Dim > Implicit::Evaluator::grad( Point< Real , Dim > ):
      -This member function returns the gradient of the implicit function at the prescribed point. The point is assumed to be given in world coordinates, and a Implicit::Evaluator::OutOfUnitCubeException is thrown if it is outside of the unit-cube containing the input samples. +
    • Implicit< Real , Dim , FEMSigs >::evaluator( void ):
      +This member function returns an object of type Implicit< Real , Dim , FEMSigs >::Evaluator. (Note that as the Implicit< Real , Dim , FEMSigs >::Evaluator object stores const references to the state in the Implicit< Real , Dim , FEMSigs > object, it will not be valid once the defining Implicit< Real , Dim , FEMSigs > object goes out of scope.) +
    • Real Implicit< Real , Dim , FEMSigs >::Evaluator::operator()( Point< Real , Dim > ):
      +This member function returns the value of the implicit function at the prescribed point. The point is assumed to be given in world coordinates, and a Implicit< Real , Dim , FEMSigs >::Evaluator::OutOfUnitCubeException is thrown if it is outside of the unit-cube containing the input samples. +
    • Point< Real , Dim > Implicit< Real , Dim , FEMSigs >::Evaluator::grad( Point< Real , Dim > ):
      +This member function returns the gradient of the implicit function at the prescribed point. The point is assumed to be given in world coordinates, and a Implicit< Real , Dim , FEMSigs >::Evaluator::OutOfUnitCubeException is thrown if it is outside of the unit-cube containing the input samples.
    And, for samples with auxiliary data, the code supports construction of an extrapolating auxiliary data field that can be queried within the bounding cube:
      @@ -1662,6 +1707,11 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
    • Removed the smoothing option in the SufaceTrimmer executable. +Version 18.35: +
        +
      1. Removed the confidence bias option. +
      +
      diff --git a/Src/AdaptiveTreeVisualization.cpp b/Src/AdaptiveTreeVisualization.cpp index f37a7f63..392ce04a 100644 --- a/Src/AdaptiveTreeVisualization.cpp +++ b/Src/AdaptiveTreeVisualization.cpp @@ -385,7 +385,8 @@ void _Execute( const FEMTree< Dim , Real > *tree , XForm< Real , Dim+1 > modelTo FileStream fs(fp); FEMTree< Dim-1 , Real >::WriteParameter( fs ); DenseNodeData< Real , IsotropicUIntPack< Dim-1 , FEMSig > >::WriteSignatures( fs ); - sliceTree->write( fs , sliceModelToUnitCube , false ); + sliceTree->write( fs , false ); + fs.write( sliceModelToUnitCube ); sliceCoefficients.write( fs ); fclose( fp ); @@ -409,8 +410,9 @@ void _Execute( const FEMTree< Dim , Real > *tree , XForm< Real , Dim+1 > modelTo Reconstructor::OutputInputFaceStream< Dim-1 , false , true > faceStream; // Extract the mesh - if constexpr( Dim==3 ) LevelSetExtractor< Real , Dim >::Extract( IsotropicUIntPack< Dim , FEMSig >() , UIntPack< 0 >() , *tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , coefficients , IsoValue.value , IsoSlabDepth.value , IsoSlabStart.value , IsoSlabEnd.value , vertexStream , faceStream , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , FlipOrientation.set ); - else if constexpr( Dim==2 ) LevelSetExtractor< Real , Dim >::Extract( IsotropicUIntPack< Dim , FEMSig >() , UIntPack< 0 >() , *tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , coefficients , IsoValue.value , vertexStream , faceStream , NonLinearFit.set , false , FlipOrientation.set ); + Reconstructor::TransformedOutputLevelSetVertexStream< Real , Dim > _vertexStream( modelToUnitCube.inverse() , vertexStream ); + if constexpr( Dim==3 ) LevelSetExtractor< Real , Dim >::Extract( IsotropicUIntPack< Dim , FEMSig >() , UIntPack< 0 >() , *tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , coefficients , IsoValue.value , IsoSlabDepth.value , IsoSlabStart.value , IsoSlabEnd.value , _vertexStream , faceStream , NonLinearFit.set , false , !NonManifold.set , PolygonMesh.set , FlipOrientation.set ); + else if constexpr( Dim==2 ) LevelSetExtractor< Real , Dim >::Extract( IsotropicUIntPack< Dim , FEMSig >() , UIntPack< 0 >() , *tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , coefficients , IsoValue.value , _vertexStream , faceStream , NonLinearFit.set , false , FlipOrientation.set ); if( Verbose.set ) printf( "Got level-set: %.2f(s)\n" , Time()-t ); if( Verbose.set ) printf( "Vertices / Faces: %llu / %llu\n" , (unsigned long long)vertexStream.size() , (unsigned long long)faceStream.size() ); @@ -438,7 +440,8 @@ template< unsigned int Dim , class Real > void Execute( BinaryStream &stream , int degree , BoundaryType bType ) { XForm< Real , Dim+1 > modelToUnitCube; - FEMTree< Dim , Real > tree( stream , modelToUnitCube , MEMORY_ALLOCATOR_BLOCK_SIZE ); + FEMTree< Dim , Real > tree( stream , MEMORY_ALLOCATOR_BLOCK_SIZE ); + stream.read( modelToUnitCube ); if( Verbose.set ) printf( "All Nodes / Active Nodes / Ghost Nodes: %llu / %llu / %llu\n" , (unsigned long long)tree.allNodes() , (unsigned long long)tree.activeNodes() , (unsigned long long)tree.ghostNodes() ); diff --git a/Src/EDTInHeat.cpp b/Src/EDTInHeat.cpp index 7687bde3..b7c5b3d7 100644 --- a/Src/EDTInHeat.cpp +++ b/Src/EDTInHeat.cpp @@ -527,7 +527,8 @@ void _Execute( int argc , char* argv[] ) FileStream fs(fp); FEMTree< Dim , Real >::WriteParameter( fs ); DenseNodeData< Real , IsotropicUIntPack< Dim , FEMSig > >::WriteSignatures( fs ); - tree.write( fs , modelToUnitCube , false ); + tree.write( fs , false ); + fs.write( modelToUnitCube ); edtSolution.write( fs ); fclose( fp ); } diff --git a/Src/FEMTree.Initialize.inl b/Src/FEMTree.Initialize.inl index cdc1330e..81f3904d 100644 --- a/Src/FEMTree.Initialize.inl +++ b/Src/FEMTree.Initialize.inl @@ -50,6 +50,64 @@ size_t FEMTreeInitializer< Dim , Real >::_Initialize( FEMTreeNode &node , int ma return count; } +template< unsigned int Dim , class Real > +template< typename IsValidFunctor /*=std::function< bool ( const Point< Real , Dim > & , const AuxData &... ) >*/ , typename ProcessFunctor/*=std::function< bool ( FEMTreeNode & , const Point< Real , Dim > & , const AuxData &... ) >*/ , typename ... AuxData > +size_t FEMTreeInitializer< Dim , Real >::Initialize( FEMTreeNode &root , InputDataStream< Point< Real , Dim > , AuxData ... > &pointStream , AuxData ... d , int maxDepth , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , IsValidFunctor IsValid , ProcessFunctor Process ) +{ + return Initialize< IsValidFunctor , ProcessFunctor , AuxData ... >( root , pointStream , d... , maxDepth , [&]( Point< Real , Dim > ){ return maxDepth; } , nodeAllocator , NodeInitializer , IsValid , Process ); +} + +template< unsigned int Dim , class Real > +template< typename IsValidFunctor/*=std::function< bool ( const Point< Real , Dim > & , const AuxData &... ) >*/ , typename ProcessFunctor/*=std::function< bool ( FEMTreeNode & , const Point< Real , Dim > & , const AuxData &... ) >*/ , typename ... AuxData > +size_t FEMTreeInitializer< Dim , Real >::Initialize( FEMTreeNode &root , InputDataStream< Point< Real , Dim > , AuxData ... > &pointStream , AuxData ... d , int maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , IsValidFunctor IsValid , ProcessFunctor Process ) +{ + typename FEMTreeNode::SubTreeExtractor subtreeExtractor( root ); + auto Leaf = [&]( FEMTreeNode& root , Point< Real , Dim > p , unsigned int maxDepth ) + { + for( int d=0 ; d1 ) return (FEMTreeNode*)NULL; + Point< Real , Dim > center; + Real width; + typename FEMTree< Dim , Real >::LocalDepth depth; + typename FEMTree< Dim , Real >::LocalOffset offset; + root.centerAndWidth( center , width ); + root.depthAndOffset( depth , offset ); + + FEMTreeNode* node = &root; + + while( depth<(int)maxDepth ) + { + if( !node->children ) node->template initChildren< false >( nodeAllocator , NodeInitializer ); + int cIndex = FEMTreeNode::ChildIndex( center , p ); + node = node->children + cIndex; + width /= 2; + + depth++; + for( int dd=0 ; dd>dd) & 1 ) center[dd] += width/2 , offset[dd] = (offset[dd]<<1) | 1; + else center[dd] -= width/2 , offset[dd] = (offset[dd]<<1) | 0; + } + return node; + }; + + // Add the point data + size_t outOfBoundPoints = 0 , badDataCount = 0 , pointCount = 0; + Point< Real , Dim > p; + while( pointStream.read( p , d... ) ) + { + // Check if the data is good + if( !IsValid( p , d... ) ){ badDataCount++ ; continue; } + + // Check that the position is in-range + FEMTreeNode *leaf = Leaf( root , p , pointDepthFunctor(p) ); + if( !leaf ){ outOfBoundPoints++ ; continue; } + + // Process the data + if( Process( *leaf , p , d ... ) ) pointCount++; + } + pointStream.reset(); + return pointCount; +} + template< unsigned int Dim , class Real > template< typename AuxData > size_t FEMTreeInitializer< Dim , Real >::Initialize( FEMTreeNode &root , InputDataStream< Point< Real , Dim > , AuxData > &pointStream , AuxData zeroData , int maxDepth , std::vector< PointSample >& samplePoints , std::vector< AuxData > &sampleData , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , AuxData & ) > ProcessData ) @@ -77,55 +135,26 @@ template< unsigned int Dim , class Real > template< typename AuxData > size_t FEMTreeInitializer< Dim , Real >::Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , InputDataStream< Point< Real , Dim > , AuxData > &pointStream , AuxData zeroData , int maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , std::vector< PointSample >& samplePoints , std::vector< AuxData > &sampleData , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , AuxData & ) > ProcessData ) { - typename FEMTreeNode::SubTreeExtractor subtreeExtractor( root ); + Real weight; + std::vector< node_index_type > &nodeToIndexMap = sid._nodeToIndexMap; - auto Leaf = [&]( FEMTreeNode& root , Point< Real , Dim > p , unsigned int maxDepth ) - { - for( int d=0 ; d1 ) return (FEMTreeNode*)NULL; - Point< Real , Dim > center; - Real width; - typename FEMTree< Dim , Real >::LocalDepth depth; - typename FEMTree< Dim , Real >::LocalOffset offset; - root.centerAndWidth( center , width ); - root.depthAndOffset( depth , offset ); - - FEMTreeNode* node = &root; - while( depth<(int)maxDepth ) + auto IsValid = [&]( const Point< Real , Dim > &p , AuxData & d ) { - if( !node->children ) node->template initChildren< false >( nodeAllocator , NodeInitializer ); - int cIndex = FEMTreeNode::ChildIndex( center , p ); - node = node->children + cIndex; - width /= 2; - - depth++; - for( int dd=0 ; dd>dd) & 1 ) center[dd] += width/2 , offset[dd] = (offset[dd]<<1) | 1; - else center[dd] -= width/2 , offset[dd] = (offset[dd]<<1) | 0; - } - return node; - }; - - // Add the point data - size_t outOfBoundPoints = 0 , badData = 0 , pointCount = 0; - { - std::vector< node_index_type > &nodeToIndexMap = sid._nodeToIndexMap; - - Point< Real , Dim > p; - AuxData d = zeroData; - while( pointStream.read( p , d ) ) + weight = ProcessData( p , d ); + return weight>0; + }; + auto Process = [&]( FEMTreeNode &node , const Point< Real , Dim > &p , AuxData &d ) { - Real weight = ProcessData( p , d ); - if( weight<=0 ){ badData++ ; continue; } - FEMTreeNode *temp = Leaf( root , p , pointDepthFunctor(p) ); - if( !temp ){ outOfBoundPoints++ ; continue; } - node_index_type nodeIndex = temp->nodeData.nodeIndex; + node_index_type nodeIndex = node.nodeData.nodeIndex; + // If the node's index exceeds what's stored in the node-to-index map, grow the node-to-index map if( nodeIndex>=(node_index_type)nodeToIndexMap.size() ) nodeToIndexMap.resize( nodeIndex+1 , -1 ); + node_index_type idx = nodeToIndexMap[ nodeIndex ]; if( idx==-1 ) { idx = (node_index_type)samplePoints.size(); nodeToIndexMap[ nodeIndex ] = idx; - samplePoints.resize( idx+1 ) , samplePoints[idx].node = temp; + samplePoints.resize( idx+1 ) , samplePoints[idx].node = &node; sampleData.resize( idx+1 ); samplePoints[idx].sample = ProjectiveData< Point< Real , Dim > , Real >( p*weight , weight ); sampleData[idx] = d*weight; @@ -135,11 +164,9 @@ size_t FEMTreeInitializer< Dim , Real >::Initialize( struct StreamInitialization samplePoints[idx].sample += ProjectiveData< Point< Real , Dim > , Real >( p*weight , weight ); sampleData[ idx ] += d*weight; } - pointCount++; - } - pointStream.reset(); - } - return pointCount; + return true; + }; + return Initialize< decltype(IsValid) , decltype(Process) , AuxData >( root , pointStream , zeroData , maxDepth , pointDepthFunctor , nodeAllocator , NodeInitializer , IsValid , Process ); } template< unsigned int Dim , class Real > diff --git a/Src/FEMTree.LevelSet.2D.inl b/Src/FEMTree.LevelSet.2D.inl index 2479f90a..a8dcf992 100644 --- a/Src/FEMTree.LevelSet.2D.inl +++ b/Src/FEMTree.LevelSet.2D.inl @@ -46,13 +46,6 @@ struct _LevelSetExtractor< HasData , Real , 2 , Data > OutputDataStream< Point< Real , Dim > , Point< Real , Dim > , Real > >; - using OutputIndexedVertexStream = std::conditional_t - < - HasData , - OutputIndexedDataStream< Point< Real , Dim > , Point< Real , Dim > , Real , Data > , - OutputIndexedDataStream< Point< Real , Dim > , Point< Real , Dim > , Real > - >; - protected: static std::atomic< size_t > _BadRootCount; public: @@ -482,8 +475,10 @@ public: std::vector< Point< Real , Dim > > vertexPositions; TreeSliceValuesAndVertexPositions( void ) : sliceTree(NULL){} - TreeSliceValuesAndVertexPositions( BinaryStream &stream , XForm< Real , Dim+1 > &xForm , size_t blockSize ) : sliceTree( stream , xForm , blockSize ) + TreeSliceValuesAndVertexPositions( BinaryStream &stream , XForm< Real , Dim+1 > &xForm , size_t blockSize ) : sliceTree( stream , blockSize ) { + stream.read( xForm ); + size_t sz; if( !stream.read( sz ) ) ERROR_OUT( "Could not read slice count" ); sliceValues.resize( sz ); @@ -510,7 +505,8 @@ public: static void Write( BinaryStream &stream , const FEMTree< Dim , Real > *sliceTree , XForm< Real , Dim+1 > xForm , const std::vector< SliceValues > &sliceValues , const std::vector< Point< Real , Dim > > &vertices , bool serialize ) { - sliceTree->write( stream , xForm , serialize ); + sliceTree->write( stream , serialize ); + stream.write( xForm ); size_t sz = sliceValues.size(); stream.write( sz ); @@ -1159,7 +1155,6 @@ struct LevelSetExtractor< Real , 2 > typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::TreeSliceValuesAndVertexPositions TreeSliceValuesAndVertexPositions; typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::TreeNode TreeNode; using OutputVertexStream = typename _LevelSetExtractor< HasData , Real , Dim , Data >::OutputVertexStream; - using OutputIndexedVertexStream = typename _LevelSetExtractor< HasData , Real , Dim , Data >::OutputIndexedVertexStream; template< unsigned int WeightDegree > using DensityEstimator = typename _LevelSetExtractor< HasData , Real , Dim , Data >::template DensityEstimator< WeightDegree >; static int SetCornerValuesFlag( void ){ return _LevelSetExtractor< HasData , Real , Dim , Data >::SetCornerValuesFlag(); } static int SetIsoVerticesFlag ( void ){ return _LevelSetExtractor< HasData , Real , Dim , Data >::SetIsoVerticesFlag (); } @@ -1175,16 +1170,6 @@ struct LevelSetExtractor< Real , 2 > return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputVertexStream , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , vertexStream , edgeStream , zeroData , nonLinearFit , outputGradients , flipOrientation ); } - template< unsigned int WeightDegree , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , OutputIndexedVertexStream &vertexStream , OutputDataStream< std::pair< node_index_type , node_index_type > > &edgeStream , bool nonLinearFit , bool outputGradients , bool flipOrientation ) - { - typedef unsigned char Data; - Data zeroData = 0; - static const unsigned int DataSig = FEMDegreeAndBType< 0 , BOUNDARY_FREE >::Signature; - const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data = NULL; - return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputIndexedVertexStream , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , vertexStream , edgeStream , zeroData , nonLinearFit , outputGradients , flipOrientation ); - } - template< unsigned int WeightDegree , unsigned int ... FEMSigs > static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputVertexStream &vertexStream , bool nonLinearFit , bool outputGradients , std::vector< SliceValues > &sliceValues , int setFlag ) { @@ -1194,16 +1179,6 @@ struct LevelSetExtractor< Real , 2 > const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data = NULL; return _LevelSetExtractor< HasData , Real , Dim , Data >::template SetSliceValues< WeightDegree , DataSig , OutputVertexStream , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , vertexStream , zeroData , nonLinearFit , outputGradients , sliceValues , setFlag ); } - - template< unsigned int WeightDegree , unsigned int ... FEMSigs > - static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputIndexedVertexStream &vertexStream , bool nonLinearFit , bool outputGradients , std::vector< SliceValues > &sliceValues , int setFlag ) - { - typedef unsigned char Data; - Data zeroData = 0; - static const unsigned int DataSig = FEMDegreeAndBType< 0 , BOUNDARY_FREE >::Signature; - const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data = NULL; - return _LevelSetExtractor< HasData , Real , Dim , Data >::template SetSliceValues< WeightDegree , DataSig , OutputIndexedVertexStream , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , vertexStream , zeroData , nonLinearFit , outputGradients , sliceValues , setFlag ); - } }; template< typename Real , typename Data > @@ -1217,7 +1192,6 @@ struct LevelSetExtractor< Real , 2 , Data > typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::TreeSliceValuesAndVertexPositions TreeSliceValuesAndVertexPositions; typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::TreeNode TreeNode; using OutputVertexStream = typename _LevelSetExtractor< HasData , Real , Dim , Data >::OutputVertexStream; - using OutputIndexedVertexStream = typename _LevelSetExtractor< HasData , Real , Dim , Data >::OutputIndexedVertexStream; template< unsigned int WeightDegree > using DensityEstimator = typename _LevelSetExtractor< HasData , Real , Dim , Data >::template DensityEstimator< WeightDegree >; static int SetCornerValuesFlag( void ){ return _LevelSetExtractor< HasData , Real , Dim , Data >::SetCornerValuesFlag(); } static int SetIsoVerticesFlag ( void ){ return _LevelSetExtractor< HasData , Real , Dim , Data >::SetIsoVerticesFlag (); } @@ -1228,20 +1202,10 @@ struct LevelSetExtractor< Real , 2 , Data > { return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputVertexStream , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , vertexStream , edgeStream , zeroData , nonLinearFit , outputGradients , flipOrientation ); } - template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputIndexedVertexStream &vertexStream , OutputDataStream< std::pair< node_index_type , node_index_type > > &edgeStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool flipOrientation ) - { - return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputIndexedVertexStream , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , vertexStream , edgeStream , zeroData , nonLinearFit , outputGradients , flipOrientation ); - } template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputVertexStream &vertexStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , std::vector< SliceValues > &sliceValues , int setFlag ) { return _LevelSetExtractor< HasData , Real , Dim , Data >::template SetSliceValues< WeightDegree , DataSig , OutputVertexStream , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , vertexStream , zeroData , nonLinearFit , outputGradients , sliceValues , setFlag ); } - template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > - static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputIndexedVertexStream &vertexStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , std::vector< SliceValues > &sliceValues , int setFlag ) - { - return _LevelSetExtractor< HasData , Real , Dim , Data >::template SetSliceValues< WeightDegree , DataSig , OutputIndexedVertexStream , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , vertexStream , zeroData , nonLinearFit , outputGradients , sliceValues , setFlag ); - } }; diff --git a/Src/FEMTree.LevelSet.3D.inl b/Src/FEMTree.LevelSet.3D.inl index 81e15835..35a130ce 100644 --- a/Src/FEMTree.LevelSet.3D.inl +++ b/Src/FEMTree.LevelSet.3D.inl @@ -46,13 +46,6 @@ struct _LevelSetExtractor< HasData , Real , 3 , Data > OutputDataStream< Point< Real , Dim > , Point< Real , Dim > , Real > >; - using OutputIndexedVertexStream = std::conditional_t - < - HasData , - OutputIndexedDataStream< Point< Real , Dim > , Point< Real , Dim > , Real , Data > , - OutputIndexedDataStream< Point< Real , Dim > , Point< Real , Dim > , Real > - >; - protected: static std::atomic< size_t > _BadRootCount; @@ -2419,7 +2412,6 @@ struct LevelSetExtractor< Real , 3 > typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::Vertex Vertex; typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::TreeNode TreeNode; using OutputVertexStream = typename _LevelSetExtractor< HasData , Real , Dim , Data >::OutputVertexStream; - using OutputIndexedVertexStream = typename _LevelSetExtractor< HasData , Real , Dim , Data >::OutputIndexedVertexStream; template< unsigned int WeightDegree > using DensityEstimator = typename _LevelSetExtractor< HasData , Real , Dim , Data >::template DensityEstimator< WeightDegree >; template< unsigned int WeightDegree , unsigned int ... FEMSigs > @@ -2443,28 +2435,6 @@ struct LevelSetExtractor< Real , 3 > Data zeroData = 0; return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputVertexStream , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , backBoundary , frontBoundary , backDValues , frontDValues , copyTopology ); } - - template< unsigned int WeightDegree , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree > *densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputIndexedVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) - { - return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , tree , densityWeights , coefficients , isoValue , 0 , 0 , 1 , vertexStream , polygonStream , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation ); - } - - template< unsigned int WeightDegree , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputIndexedVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) - { - std::vector< std::vector< Real > > dValues; - return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , tree , tree._maxDepth , densityWeights , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , NULL , NULL , dValues , dValues , false ); - } - - template< unsigned int WeightDegree , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , int maxKeyDepth , const DensityEstimator< WeightDegree >* densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputIndexedVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *backBoundary , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *frontBoundary , const std::vector< std::vector< Real > > &backDValues , const std::vector< std::vector< Real > > &frontDValues , bool copyTopology ) - { - static const unsigned int DataSig = FEMDegreeAndBType< 0 , BOUNDARY_FREE >::Signature; - const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data = NULL; - Data zeroData = 0; - return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputIndexedVertexStream , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , backBoundary , frontBoundary , backDValues , frontDValues , copyTopology ); - } }; template< typename Real , typename Data > @@ -2476,7 +2446,6 @@ struct LevelSetExtractor< Real , 3 , Data > typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::Vertex Vertex; typedef typename _LevelSetExtractor< HasData , Real , Dim , Data >::TreeNode TreeNode; using OutputVertexStream = typename _LevelSetExtractor< HasData , Real , Dim , Data >::OutputVertexStream; - using OutputIndexedVertexStream = typename _LevelSetExtractor< HasData , Real , Dim , Data >::OutputIndexedVertexStream; template< unsigned int WeightDegree > using DensityEstimator = typename _LevelSetExtractor< HasData , Real , Dim , Data >::template DensityEstimator< WeightDegree >; template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > @@ -2497,23 +2466,4 @@ struct LevelSetExtractor< Real , 3 , Data > { return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputVertexStream , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , backBoundary , frontBoundary , backDValues , frontDValues , copyTopology ); } - - template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputIndexedVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) - { - return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , densityWeights , data , coefficients , isoValue , 0 , 0 , 1 , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation ); - } - - template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputIndexedVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation ) - { - std::vector< std::vector< Real > > dValues; - return Extract( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , tree._maxDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , NULL , NULL , dValues , dValues , false ); - } - - template< unsigned int WeightDegree , unsigned int DataSig , unsigned int ... FEMSigs > - static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real >& tree , int maxKeyDepth , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , unsigned int slabDepth , unsigned int slabStart , unsigned int slabEnd , OutputIndexedVertexStream &vertexStream , OutputDataStream< std::vector< node_index_type > > &polygonStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , bool addBarycenter , bool polygonMesh , bool flipOrientation , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *backBoundary , const typename LevelSetExtractor< Real , Dim-1 , Point< Real , Dim-1 > >::TreeSliceValuesAndVertexPositions *frontBoundary , const std::vector< std::vector< Real > > &backDValues , const std::vector< std::vector< Real > > &frontDValues , bool copyTopology ) - { - return _LevelSetExtractor< HasData , Real , Dim , Data >::template Extract< WeightDegree , DataSig , OutputIndexedVertexStream , FEMSigs ... >( UIntPack< FEMSigs ... >() , UIntPack< WeightDegree >() , UIntPack< DataSig >() , tree , maxKeyDepth , densityWeights , data , coefficients , isoValue , slabDepth , slabStart , slabEnd , vertexStream , polygonStream , zeroData , nonLinearFit , outputGradients , addBarycenter , polygonMesh , flipOrientation , backBoundary , frontBoundary , backDValues , frontDValues , copyTopology ); - } }; diff --git a/Src/FEMTree.h b/Src/FEMTree.h index c6721929..129c192c 100644 --- a/Src/FEMTree.h +++ b/Src/FEMTree.h @@ -2538,7 +2538,7 @@ namespace PoissonRecon public: FEMTree( size_t blockSize ); - FEMTree( BinaryStream &stream , XForm< Real , Dim+1 > &xForm , size_t blockSize ); + FEMTree( BinaryStream &stream , size_t blockSize ); template< unsigned int CrossDegree , unsigned int Pad > static FEMTree< Dim , Real > *Slice( const FEMTree< Dim+1 , Real > &tree , unsigned int sliceDepth , unsigned int sliceIndex , bool includeBounds , size_t blockSize ); @@ -2548,7 +2548,7 @@ namespace PoissonRecon _tree.cleanChildren( !nodeAllocators.size() ); for( size_t i=0 ; i xForm , bool serialize ) const; + void write( BinaryStream &stream , bool serialize ) const; static void WriteParameter( BinaryStream &stream ) { FEMTreeRealType realType; @@ -3034,6 +3034,11 @@ namespace PoissonRecon std::vector< node_index_type > _nodeToIndexMap; }; + template< typename IsValidFunctor/*=std::function< bool ( const Point< Real , Dim > & , AuxData &... ) >*/ , typename ProcessFunctor/*=std::function< bool ( FEMTreeNode & , const Point< Real , Dim > & , AuxData &... ) >*/ , typename ... AuxData > + static size_t Initialize( FEMTreeNode &root , InputDataStream< Point< Real , Dim > , AuxData ... > &pointStream , AuxData ... zeroData , int maxDepth , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , IsValidFunctor IsValid , ProcessFunctor Process ); + template< typename IsValidFunctor/*=std::function< bool ( const Point< Real , Dim > & , AuxData &... ) >*/ , typename ProcessFunctor/*=std::function< bool ( FEMTreeNode & , const Point< Real , Dim > & , AuxData &... ) >*/ , typename ... AuxData > + static size_t Initialize( FEMTreeNode &root , InputDataStream< Point< Real , Dim > , AuxData ... > &pointStream , AuxData ... zeroData , int maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , IsValidFunctor IsValid , ProcessFunctor Process ); + template< typename AuxData > static size_t Initialize( struct StreamInitializationData &sid , FEMTreeNode &root , InputDataStream< Point< Real , Dim > , AuxData > &pointStream , AuxData zeroData , int maxDepth , std::vector< PointSample >& samplePoints , std::vector< AuxData > &sampleData , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim > & , AuxData & ) > ProcessData = []( const Point< Real , Dim > & , AuxData & ){ return (Real)1.; } ); template< typename AuxData > diff --git a/Src/FEMTree.inl b/Src/FEMTree.inl index 0ae77e94..69da9217 100644 --- a/Src/FEMTree.inl +++ b/Src/FEMTree.inl @@ -354,10 +354,9 @@ FEMTree< Dim , Real >::FEMTree( size_t blockSize ) : _nodeInitializer( *this ) , } template< unsigned int Dim , class Real > -FEMTree< Dim , Real >::FEMTree( BinaryStream &stream , XForm< Real , Dim+1 > &xForm , size_t blockSize ) : FEMTree( blockSize ) +FEMTree< Dim , Real >::FEMTree( BinaryStream &stream , size_t blockSize ) : FEMTree( blockSize ) { Allocator< FEMTreeNode > *nodeAllocator = nodeAllocators.size() ? nodeAllocators[0] : NULL; - if( !stream.read( xForm.coords ) ) ERROR_OUT( "Failed to read transform" ); node_index_type nodeCount; if( !stream.read( nodeCount ) ) ERROR_OUT( "Failed to read nodeCount" ); _nodeCount = nodeCount; @@ -369,9 +368,8 @@ FEMTree< Dim , Real >::FEMTree( BinaryStream &stream , XForm< Real , Dim+1 > &xF _sNodes.read( stream , _tree ); } -template< unsigned int Dim , class Real > void FEMTree< Dim , Real >::write( BinaryStream &stream , XForm< Real , Dim+1 > xForm , bool serialize ) const +template< unsigned int Dim , class Real > void FEMTree< Dim , Real >::write( BinaryStream &stream , bool serialize ) const { - stream.write( xForm ); node_index_type nodeCount = _nodeCount; stream.write( nodeCount ); stream.write( _maxDepth ); diff --git a/Src/Geometry.h b/Src/Geometry.h index dbdb5fb1..762f1136 100644 --- a/Src/Geometry.h +++ b/Src/Geometry.h @@ -81,8 +81,19 @@ namespace PoissonRecon DirectSum operator * ( Real s ) const { DirectSum _p = *this ; _p *= s ; return _p; } DirectSum operator / ( Real s ) const { DirectSum _p = *this ; _p /= s ; return _p; } - DirectSum( void ){} - DirectSum( const VectorTypes & ... vectors ){ _set< 0 >( vectors ... ); } + template< typename ... _VectorTypes > + DirectSum( const _VectorTypes & ... vectors ) + { + if constexpr( sizeof...(_VectorTypes)==0 ) ; + else if constexpr( sizeof...(_VectorTypes)==sizeof...(VectorTypes) ) _set<0>( vectors... ); + else ERROR_OUT( "Invalid number of arguments" ); + } + + template< typename ComponentFunctor /*=std::function< void (VectorTypes&...)>*/ > + void process( ComponentFunctor f ){ _process( f ); } + + template< typename ComponentFunctor /*=std::function< void (const VectorTypes&...)>*/ > + void process( ComponentFunctor f ) const { _process( f ); } friend std::ostream &operator << ( std::ostream &os , const DirectSum &v ) { @@ -105,6 +116,19 @@ namespace PoissonRecon template< unsigned int I > typename std::enable_if< I==sizeof...(VectorTypes) >::type _div( Real s ){ } template< unsigned int I > typename std::enable_if< I!=sizeof...(VectorTypes) >::type _streamOut( std::ostream &os ) const { os << get() ; if( I!=sizeof...(VectorTypes)-1 ) os << " , "; _streamOut< I+1 >( os ); } template< unsigned int I > typename std::enable_if< I==sizeof...(VectorTypes) >::type _streamOut( std::ostream &os ) const { } + + template< typename ComponentFunctor /*=std::function< void (VectorTypes&...)>*/ , typename ... Components > + void _process( ComponentFunctor &f , Components ... c ) + { + if constexpr( sizeof...(Components)==sizeof...(VectorTypes) ) f( c... ); + else _process( f , c... , this->template get< sizeof...(Components) >() ); + } + template< typename ComponentFunctor /*=std::function< void (const VectorTypes&...)>*/ , typename ... Components > + void _process( ComponentFunctor &f , Components ... c ) const + { + if constexpr( sizeof...(Components)==sizeof...(VectorTypes) ) f( c... ); + else _process( f , c... , this->template get< sizeof...(Components) >() ); + } }; template< typename Real , typename ... Vectors > DirectSum< Real , Vectors ... > operator * ( Real s , DirectSum< Real , Vectors ... > vu ){ return vu * s; } diff --git a/Src/PointInterpolant.cpp b/Src/PointInterpolant.cpp index 316f3576..060536f0 100644 --- a/Src/PointInterpolant.cpp +++ b/Src/PointInterpolant.cpp @@ -876,7 +876,8 @@ void Execute( UIntPack< FEMSigs ... > ) FileStream fs( fp ); FEMTree< Dim , Real >::WriteParameter( fs ); DenseNodeData< Real , Sigs >::WriteSignatures( fs ); - tree.write( fs , modelToUnitCube , false ); + tree.write( fs , false ); + fs.write( modelToUnitCube ); solution.write( fs ); fclose( fp ); } diff --git a/Src/PoissonRecon.client.inl b/Src/PoissonRecon.client.inl index 5ba24aba..bff01583 100644 --- a/Src/PoissonRecon.client.inl +++ b/Src/PoissonRecon.client.inl @@ -487,19 +487,13 @@ void Client< Real , Dim , BType , Degree >::_process1( const ClientReconstructio // Read in the samples (and color data) { Timer timer; - auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , InputSampleDataType &d ) - { - Real l = (Real)Length( d.template get<0>() ); - if( !l || !std::isfinite( l ) ) return (Real)-1.; - return (Real)pow( l , clientReconInfo.confidence ); - }; - auto ProcessData = []( const Point< Real , Dim > &p , InputSampleDataType &d ) - { - Real l = (Real)Length( d.template get<0>() ); - if( !l || !std::isfinite( l ) ) return (Real)-1.; - d.template get<0>() /= l; - return (Real)1.; - }; + auto ProcessData = [&]( const Point< Real , Dim > &p , InputSampleDataType &d ) + { + Real l = (Real)Length( d.template get<0>() ); + if( !l || !std::isfinite( l ) ) return (Real)-1.; + d.template get<0>() /= l; + return clientReconInfo.confidence>0 ? (Real)pow( l , clientReconInfo.confidence ) : (Real)1.; + }; std::vector< InputDataStream< typename InputSampleFactory::VertexType > * > pointStreams( endPaddedIndex - beginPaddedIndex , NULL ); auto PointStreamFunctor = [&]( unsigned int idx ) @@ -535,8 +529,7 @@ void Client< Real , Dim , BType , Degree >::_process1( const ClientReconstructio MultiPointStream pointStream( &pointStreams[start-beginPaddedIndex] , end - start ); typename InputSampleDataFactory::VertexType zeroData = inputSampleDataFactory(); InputDataStreamConverter< InternalType , ExternalType > _pointStream( pointStream , converter , inputSampleFactory() ); - if( clientReconInfo.confidence>0 ) pointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , _samples , _sampleData , _tree.nodeAllocators[0] , _tree.initializer() , ProcessDataWithConfidence ); - else pointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , _samples , _sampleData , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); + pointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , _samples , _sampleData , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); profiler.update(); }; auto ProcessPadPointSlabs = [&]( typename FEMTreeInitializer< Dim , Real >::StreamInitializationData &sid , unsigned int start , unsigned int end ) @@ -546,11 +539,9 @@ void Client< Real , Dim , BType , Degree >::_process1( const ClientReconstructio typename InputSampleDataFactory::VertexType zeroData = inputSampleDataFactory(); InputDataStreamConverter< InternalType , ExternalType > _pointStream( pointStream , converter , inputSampleFactory() ); #ifdef ADAPTIVE_PADDING - if( clientReconInfo.confidence>0 ) paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , pointDepthFunctor , _paddedSamples , _paddedSampleData , _tree.nodeAllocators[0] , _tree.initializer() , ProcessDataWithConfidence ); - else paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , pointDepthFunctor , _paddedSamples , _paddedSampleData , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); + paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , pointDepthFunctor , _paddedSamples , _paddedSampleData , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); #else // !ADAPTIVE_PADDING - if( clientReconInfo.confidence>0 ) paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , _paddedSamples , _paddedSampleData , _tree.nodeAllocators[0] , _tree.initializer() , ProcessDataWithConfidence ); - else paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , _paddedSamples , _paddedSampleData , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); + paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , _paddedSamples , _paddedSampleData , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); #endif // ADAPTIVE_PADDING profiler.update(); }; @@ -563,19 +554,16 @@ void Client< Real , Dim , BType , Degree >::_process1( const ClientReconstructio { typename InputSampleDataFactory::VertexType zeroData = inputSampleDataFactory(); InputDataStreamConverter< InternalType , ExternalType > _pointStream( pointStream , converter , inputSampleFactory() ); - if( clientReconInfo.confidence>0 ) pointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , _samples , _sampleData , _tree.nodeAllocators[0] , _tree.initializer() , ProcessDataWithConfidence ); - else pointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , _samples , _sampleData , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); + pointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , _samples , _sampleData , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); } else { typename InputSampleDataFactory::VertexType zeroData = inputSampleDataFactory(); InputDataStreamConverter< InternalType , ExternalType > _pointStream( pointStream , converter , inputSampleFactory() ); #ifdef ADAPTIVE_PADDING - if( clientReconInfo.confidence>0 ) paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , pointDepthFunctor , _paddedSamples , _paddedSampleData , _tree.nodeAllocators[0] , _tree.initializer() , ProcessDataWithConfidence ); - else paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , pointDepthFunctor , _paddedSamples , _paddedSampleData , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); + paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , pointDepthFunctor , _paddedSamples , _paddedSampleData , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); #else // !ADAPTIVE_PADDING - if( clientReconInfo.confidence>0 ) paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , _paddedSamples , _paddedSampleData , _tree.nodeAllocators[0] , _tree.initializer() , ProcessDataWithConfidence ); - else paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , _paddedSamples , _paddedSampleData , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); + paddedPointCount += FEMTreeInitializer< Dim , Real >::template Initialize< InputSampleDataType >( sid , _tree.spaceRoot() , _pointStream , zeroData , clientReconInfo.reconstructionDepth , _paddedSamples , _paddedSampleData , _tree.nodeAllocators[0] , _tree.initializer() , ProcessData ); #endif // ADAPTIVE_PADDING } profiler.update(); @@ -635,28 +623,6 @@ void Client< Real , Dim , BType , Degree >::_process1( const ClientReconstructio return true; }; - std::function< bool ( InputSampleDataType , Point< Real , Dim >& , Real & ) > ConversionAndBiasFunction = [&]( InputSampleDataType in , Point< Real , Dim > &out , Real &bias ) - { - Point< Real , Dim > n = in.template get<0>(); - Real l = (Real)Length( n ); - // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... - if( !l ) return false; - out = n / l; - bias = (Real)( log( l ) * clientReconInfo.confidenceBias / log( 1<<(Dim-1) ) ); - return true; - }; - - if( clientReconInfo.confidenceBias>0 ) - { - *_normalInfo = _tree.setInterpolatedDataField( NormalSigs() , _samples , _sampleData , _density , clientReconInfo.sharedDepth , clientReconInfo.reconstructionDepth , (Real)0 , pointDepthAndWeight , ConversionAndBiasFunction ); - if( clientReconInfo.verbose>1 ) std::cout << "Nodes [Interior Data Field " << _normalInfo->size() << " / " << _normalInfo->reserved() << "]: " << _tree.allNodes() << std::endl; -#ifdef ADAPTIVE_PADDING - *_paddedNormalInfo = _tree.setInterpolatedDataField( NormalSigs() , _paddedSamples , _paddedSampleData , _density , clientReconInfo.sharedDepth , clientReconInfo.reconstructionDepth , pointDepthFunctor , (Real)0 , paddedPointDepthAndWeight , ConversionAndBiasFunction ); -#else // !ADAPTIVE_PADDING - *_paddedNormalInfo = _tree.setInterpolatedDataField( NormalSigs() , _paddedSamples , _paddedSampleData , _density , clientReconInfo.sharedDepth , clientReconInfo.reconstructionDepth , (Real)0 , paddedPointDepthAndWeight , ConversionAndBiasFunction ); -#endif // ADAPTIVE_PADDING - } - else { *_normalInfo = _tree.setInterpolatedDataField( NormalSigs() , _samples , _sampleData , _density , clientReconInfo.sharedDepth , clientReconInfo.reconstructionDepth , (Real)0 , pointDepthAndWeight , ConversionFunction ); if( clientReconInfo.verbose>1 ) std::cout << "Nodes [Interior Data Field " << _normalInfo->size() << " / " << _normalInfo->reserved() << "]: " << _tree.allNodes() << std::endl; @@ -1020,7 +986,8 @@ size_t Client< Real , Dim , BType , Degree >::_send5( const ClientReconstruction if( bInfo.tree ) { - bInfo.tree->write( serverStream , sliceModelToUnitCube , true ); + bInfo.tree->write( serverStream , true ); + serverStream.write( sliceModelToUnitCube ); bInfo.solution.write( serverStream ); bInfo.dSolution.write( serverStream ); } @@ -1184,7 +1151,8 @@ std::pair< double , double > Client< Real , Dim , BType , Degree >::_process5( c FEMTree< Dim , Real >::WriteParameter( fs ); DenseNodeData< Real , Sigs >::WriteSignatures( fs ); XForm< Real , Dim+1 > voxelToUnitCube = XForm< Real , Dim+1 >::Identity(); - _tree.write( fs , voxelToUnitCube , false ); + _tree.write( fs , false ); + fs.write( voxelToUnitCube ); _solution.write( fs ); fclose( fp ); } @@ -1375,8 +1343,10 @@ void Client< Real , Dim , BType , Degree >::_process7( const ClientReconstructio template< typename Real , unsigned int Dim , BoundaryType BType , unsigned int Degree > Client< Real , Dim , BType , Degree >::Client( const ClientReconstructionInfo< Real , Dim > &clientReconInfo , BinaryStream &stream , unsigned int phase ) - : _serverSocket( _INVALID_SOCKET_ ) , _tree( stream , _modelToUnitCube , MEMORY_ALLOCATOR_BLOCK_SIZE ) , _density(NULL) , _normalInfo(NULL) , _paddedNormalInfo(NULL) , _iInfo(NULL) , _index(-1) + : _serverSocket( _INVALID_SOCKET_ ) , _tree( stream , MEMORY_ALLOCATOR_BLOCK_SIZE ) , _density(NULL) , _normalInfo(NULL) , _paddedNormalInfo(NULL) , _iInfo(NULL) , _index(-1) { + stream.read( _modelToUnitCube ); + AuxDataFactory auxDataFactory( clientReconInfo.auxProperties ); bool needAuxData = clientReconInfo.dataX>0 && auxDataFactory.bufferSize(); @@ -1491,7 +1461,8 @@ void Client< Real , Dim , BType , Degree >::_write( const ClientReconstructionIn if( phase!=1 && phase!=3 && phase!=5 ) ERROR_OUT( "Only phases 1, 3, and 5 supported: " , phase ); - _tree.write( stream , _modelToUnitCube , false ); + _tree.write( stream , false ); + stream.write( _modelToUnitCube ); stream.write( _index ); stream.write( _range ); diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index 92aafb45..5dbd9058 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -100,7 +100,6 @@ CmdLineParameter< float > Scale( "scale" , 1.1f ) , Width( "width" , 0.f ) , Confidence( "confidence" , 0.f ) , - ConfidenceBias( "confidenceBias" , 0.f ) , CGSolverAccuracy( "cgAccuracy" , 1e-3f ) , LowDepthCutOff( "lowDepthCutOff" , 0.f ) , TargetValue( "targetValue" , 0.5f ) , @@ -119,7 +118,6 @@ CmdLineReadable* params[] = &KernelDepth , &SamplesPerNode , &Confidence , &NonManifold , &PolygonMesh , &ASCII , &ShowResidual , &EnvelopeDepth , &NoDirichletErode , - &ConfidenceBias , &BaseDepth , &BaseVCycles , &PointWeight , &Grid , @@ -183,7 +181,6 @@ void ShowUsage(char* ex) printf( "\t[--%s =%d]\n" , ThreadChunkSize.name , ThreadChunkSize.value ); printf( "\t[--%s =%f]\n" , LowDepthCutOff.name , LowDepthCutOff.value ); printf( "\t[--%s =%f]\n" , Confidence.name , Confidence.value ); - printf( "\t[--%s =%f]\n" , ConfidenceBias.name , ConfidenceBias.value ); printf( "\t[--%s =%d]\n" , AlignmentDir.name , AlignmentDir.value ); printf( "\t[--%s]\n" , NonManifold.name ); printf( "\t[--%s]\n" , PolygonMesh.name ); @@ -204,7 +201,7 @@ void ShowUsage(char* ex) template< typename Real , unsigned int Dim , unsigned int FEMSig , bool HasGradients , bool HasDensity , bool InCore , typename ... AuxDataFactories > void WriteMesh ( - Reconstructor::Implicit< Real , Dim , FEMSig , typename AuxDataFactories::VertexType ... > &implicit , + Reconstructor::Implicit< Real , Dim , IsotropicUIntPack< Dim , FEMSig > , typename AuxDataFactories::VertexType ... > &implicit , const Reconstructor::LevelSetExtractionParameters &meParams , std::string fileName , bool ascii , @@ -233,7 +230,7 @@ template< typename Real , unsigned int Dim , unsigned int FEMSig , bool HasDensi void WriteMesh ( bool hasGradients , - Reconstructor::Implicit< Real , Dim , FEMSig , typename AuxDataFactories::VertexType ... > &implicit , + Reconstructor::Implicit< Real , Dim , IsotropicUIntPack< Dim , FEMSig > , typename AuxDataFactories::VertexType ... > &implicit , const Reconstructor::LevelSetExtractionParameters &meParams , std::string fileName , bool ascii , @@ -248,7 +245,7 @@ template< typename Real , unsigned int Dim , unsigned int FEMSig , bool InCore , void WriteMesh ( bool hasGradients , bool hasDensity , - Reconstructor::Implicit< Real , Dim , FEMSig , typename AuxDataFactories::VertexType ... > &implicit , + Reconstructor::Implicit< Real , Dim , IsotropicUIntPack< Dim , FEMSig > , typename AuxDataFactories::VertexType ... > &implicit , const Reconstructor::LevelSetExtractionParameters &meParams , std::string fileName , bool ascii , @@ -263,7 +260,7 @@ template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... void WriteMesh ( bool hasGradients , bool hasDensity , bool inCore , - Reconstructor::Implicit< Real , Dim , FEMSig , typename AuxDataFactories::VertexType ... > &implicit , + Reconstructor::Implicit< Real , Dim , IsotropicUIntPack< Dim , FEMSig > , typename AuxDataFactories::VertexType ... > &implicit , const Reconstructor::LevelSetExtractionParameters &meParams , std::string fileName , bool ascii , @@ -285,15 +282,15 @@ void Execute( const AuxDataFactory &auxDataFactory ) using namespace VertexFactory; // The factory for constructing an input sample's data - typedef typename std::conditional< HasAuxData , Factory< Real , NormalFactory< Real , Dim > , AuxDataFactory > , NormalFactory< Real , Dim > >::type InputSampleDataFactory; + typedef std::conditional_t< HasAuxData , Factory< Real , NormalFactory< Real , Dim > , AuxDataFactory > , NormalFactory< Real , Dim > > InputSampleDataFactory; // The factory for constructing an input sample typedef Factory< Real , PositionFactory< Real , Dim > , InputSampleDataFactory > InputSampleFactory; typedef InputDataStream< typename InputSampleFactory::VertexType > InputPointStream; - // The type storing the reconstruction solution (depending on whether auxiliary data is provided or not) - using Implicit = typename std::conditional< HasAuxData , Reconstructor::Poisson::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType > , Reconstructor::Poisson::Implicit< Real , Dim , FEMSig > >::type; + using Implicit = std::conditional_t< HasAuxData , Reconstructor::Implicit< Real , Dim , IsotropicUIntPack< Dim , FEMSig > , typename AuxDataFactory::VertexType > , Reconstructor::Implicit< Real , Dim , IsotropicUIntPack< Dim , FEMSig > > >; + using Solver = std::conditional_t< HasAuxData , Reconstructor::Poisson::Solver< Real , Dim , IsotropicUIntPack< Dim , FEMSig > , typename AuxDataFactory::VertexType > , Reconstructor::Poisson::Solver< Real , Dim , IsotropicUIntPack< Dim , FEMSig > > >; // <-- Types // /////////////// @@ -321,18 +318,17 @@ void Execute( const AuxDataFactory &auxDataFactory ) sParams.verbose = Verbose.set; sParams.dirichletErode = !NoDirichletErode.set; - sParams.outputDensity = Density.set; sParams.exactInterpolation = ExactInterpolation.set; sParams.showResidual = ShowResidual.set; sParams.scale = (Real)Scale.value; sParams.confidence = (Real)Confidence.value; - sParams.confidenceBias = (Real)ConfidenceBias.value; sParams.lowDepthCutOff = (Real)LowDepthCutOff.value; sParams.width = (Real)Width.value; sParams.pointWeight = (Real)PointWeight.value; sParams.samplesPerNode = (Real)SamplesPerNode.value; sParams.cgSolverAccuracy = (Real)CGSolverAccuracy.value; sParams.targetValue = (Real)TargetValue.value; + sParams.perLevelDataScaleFactor = (Real)DataX.value; sParams.depth = (unsigned int)Depth.value; sParams.baseDepth = (unsigned int)BaseDepth.value; sParams.solveDepth = (unsigned int)SolveDepth.value; @@ -348,6 +344,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) meParams.forceManifold = !NonManifold.set; meParams.polygonMesh = PolygonMesh.set; meParams.gridCoordinates = GridCoordinates.set; + meParams.outputDensity = Density.set; meParams.verbose = Verbose.set; double startTime = Time(); @@ -481,10 +478,10 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( Transform.set ) { Reconstructor::TransformedInputOrientedSampleStream< Real , Dim , typename AuxDataFactory::VertexType > _sampleStream( toModel , sampleStream ); - implicit = new typename Reconstructor::Poisson::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( _sampleStream , sParams , auxDataFactory() , envelopeMesh ); + implicit = Solver::Solve( _sampleStream , sParams , auxDataFactory() , envelopeMesh ); implicit->unitCubeToModel = toModel.inverse() * implicit->unitCubeToModel; } - else implicit = new typename Reconstructor::Poisson::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( sampleStream , sParams , auxDataFactory() , envelopeMesh ); + else implicit = Solver::Solve( sampleStream , sParams , auxDataFactory() , envelopeMesh ); } else { @@ -493,18 +490,16 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( Transform.set ) { Reconstructor::TransformedInputOrientedSampleStream< Real , Dim > _sampleStream( toModel , sampleStream ); - implicit = new typename Reconstructor::Poisson::Implicit< Real , Dim , FEMSig >( _sampleStream , sParams , envelopeMesh ); + implicit = Solver::Solve( _sampleStream , sParams , envelopeMesh ); implicit->unitCubeToModel = toModel.inverse() * implicit->unitCubeToModel; } - else implicit = new typename Reconstructor::Poisson::Implicit< Real , Dim , FEMSig >( sampleStream , sParams , envelopeMesh ); + else implicit = Solver::Solve( sampleStream , sParams , envelopeMesh ); } delete pointStream; delete _inputSampleFactory; delete envelopeMesh; - if constexpr( HasAuxData ) if( implicit->auxData ) implicit->weightAuxDataByDepth( (Real)DataX.value ); - if( Tree.set ) { FILE* fp = fopen( Tree.value , "wb" ); @@ -512,10 +507,9 @@ void Execute( const AuxDataFactory &auxDataFactory ) FileStream fs(fp); FEMTree< Dim , Real >::WriteParameter( fs ); DenseNodeData< Real , Sigs >::WriteSignatures( fs ); - implicit->tree.write( fs , implicit->unitCubeToModel.inverse() , false ); + implicit->tree.write( fs , false ); + fs.write( implicit->unitCubeToModel.inverse() ); implicit->solution.write( fs ); - if constexpr( HasAuxData ) if( implicit->auxData ) implicit->auxData->write( fs ); - if( implicit->density ) implicit->density->write( fs ); fclose( fp ); } diff --git a/Src/PoissonRecon.server.inl b/Src/PoissonRecon.server.inl index cc87ac07..5d7ff384 100644 --- a/Src/PoissonRecon.server.inl +++ b/Src/PoissonRecon.server.inl @@ -575,7 +575,8 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase4( const ClientReconstruc FEMTree< Dim , Real >::WriteParameter( fs ); DenseNodeData< Real , Sigs >::WriteSignatures( fs ); XForm< Real , Dim+1 > voxelToUnitCube = XForm< Real , Dim+1 >::Identity(); - state4.tree.write( fs , voxelToUnitCube , false ); + state4.tree.write( fs , false ); + fs.write( voxelToUnitCube ); state4.solution.write( fs ); fclose( fp ); } @@ -598,7 +599,8 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase6( const ClientReconstruc auto ReadSlice = [&]( BinaryStream &clientStream , DenseNodeData< Real , SliceSigs > &solution , DenseNodeData< Real , SliceSigs > &dSolution , XForm< Real , Dim > &modelToUnitCube ) { - FEMTree< Dim-1 , Real > *sliceTree = new FEMTree< Dim-1 , Real >( clientStream , modelToUnitCube , MEMORY_ALLOCATOR_BLOCK_SIZE ); + FEMTree< Dim-1 , Real > *sliceTree = new FEMTree< Dim-1 , Real >( clientStream , MEMORY_ALLOCATOR_BLOCK_SIZE ); + clientStream.read( modelToUnitCube ); solution.read( clientStream ); if( !clientReconInfo.linearFit ) dSolution.read( clientStream ); return sliceTree; @@ -675,7 +677,8 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase6( const ClientReconstruc FileStream fs(fp); FEMTree< Dim-1 , Real >::WriteParameter( fs ); DenseNodeData< Real , SliceSigs >::WriteSignatures( fs ); - sliceTree->write( fs , state6.xForm , false ); + sliceTree->write( fs , false ); + fs.write( state6.xForm ); solution.write( fs ); fclose( fp ); }; diff --git a/Src/PoissonReconClientServer.h b/Src/PoissonReconClientServer.h index 56624959..dde81632 100644 --- a/Src/PoissonReconClientServer.h +++ b/Src/PoissonReconClientServer.h @@ -63,7 +63,7 @@ namespace PoissonRecon std::string header , inDir , tempDir , outDir; unsigned int solveDepth , reconstructionDepth , sharedDepth , distributionDepth , baseDepth , kernelDepth , iters , bufferSize , filesPerDir , padSize , verbose; - Real pointWeight , confidence , confidenceBias , samplesPerNode , dataX , cgSolverAccuracy , targetValue; + Real pointWeight , confidence , samplesPerNode , dataX , cgSolverAccuracy , targetValue; MergeType mergeType; bool density , linearFit , ouputVoxelGrid , outputSolution , gridCoordinates; std::vector< PlyProperty > auxProperties; diff --git a/Src/PoissonReconClientServer.inl b/Src/PoissonReconClientServer.inl index 9582d532..aaaf3a42 100644 --- a/Src/PoissonReconClientServer.inl +++ b/Src/PoissonReconClientServer.inl @@ -280,7 +280,7 @@ struct ClientServerStream : BinaryStream } protected: - typename std::conditional< ReadFromFile , std::ifstream , std::ofstream >::type _fs; + std::conditional_t< ReadFromFile , std::ifstream , std::ofstream > _fs; SocketStream &_socket; std::string _fileName; @@ -323,7 +323,6 @@ ClientReconstructionInfo< Real , Dim >::ClientReconstructionInfo( void ) baseDepth = 5; iters = 8; confidence = (Real)0.; - confidenceBias = (Real)0.; samplesPerNode = (Real)1.5; dataX = (Real)32.; density = false; @@ -363,7 +362,6 @@ ClientReconstructionInfo< Real , Dim >::ClientReconstructionInfo( BinaryStream & if( !stream.read( targetValue ) ) ERROR_OUT( "Failed to read target-value" ); if( !stream.read( pointWeight ) ) ERROR_OUT( "Failed to read point-weight" ); if( !stream.read( confidence ) ) ERROR_OUT( "Failed to read confidence" ); - if( !stream.read( confidenceBias ) ) ERROR_OUT( "Failed to read confidence-bias" ); if( !stream.read( samplesPerNode ) ) ERROR_OUT( "Failed to read samples-per-node" ); if( !stream.read( dataX ) ) ERROR_OUT( "Failed to read data-multiplier" ); if( !stream.read( padSize ) ) ERROR_OUT( "Failed to read padSize" ); @@ -407,7 +405,6 @@ void ClientReconstructionInfo< Real , Dim >::write( BinaryStream &stream ) const stream.write( targetValue ); stream.write( pointWeight ); stream.write( confidence ); - stream.write( confidenceBias ); stream.write( samplesPerNode ); stream.write( dataX ); stream.write( padSize ); diff --git a/Src/PoissonReconServer.cpp b/Src/PoissonReconServer.cpp index de5d7970..a68fe89d 100644 --- a/Src/PoissonReconServer.cpp +++ b/Src/PoissonReconServer.cpp @@ -105,7 +105,6 @@ CmdLineParameter< float > Scale( "scale" , 1.1f ) , Width( "width" , 0.f ) , Confidence( "confidence" , 0.f ) , - ConfidenceBias( "confidenceBias" , 0.f ) , SamplesPerNode( "samplesPerNode" , 1.5f ) , DataX( "data" , 32.f ) , PointWeight( "pointWeight" ) , @@ -130,7 +129,7 @@ CmdLineReadable* params[] = &SolveDepth , &NoLoadBalance , &Density , &LinearFit , &MergeSlabs , - &Width , &Confidence , &ConfidenceBias , &SamplesPerNode , &DataX , &PointWeight , &CGSolverAccuracy , + &Width , &Confidence , &SamplesPerNode , &DataX , &PointWeight , &CGSolverAccuracy , &TargetValue , &MaxMemoryGB , &ParallelType , &ScheduleType , &ThreadChunkSize , &PeakMemorySampleMS , @@ -174,7 +173,6 @@ void ShowUsage( char* ex ) printf( "\t[--%s =%f]\n" , TargetValue.name , TargetValue.value ); printf( "\t[--%s =%.3e * ]\n" , PointWeight.name , Reconstructor::Poisson::WeightMultiplier ); printf( "\t[--%s =%f]\n" , Confidence.name , Confidence.value ); - printf( "\t[--%s =%f]\n" , ConfidenceBias.name , ConfidenceBias.value ); printf( "\t[--%s =%f]\n" , DataX.name , DataX.value ); printf( "\t[--%s =%d]\n" , PadSize.name , PadSize.value ); printf( "\t[--%s =%d]\n" , BufferSize.name , BufferSize.value ); @@ -491,7 +489,6 @@ int main( int argc , char* argv[] ) clientReconInfo.iters = Iters.value; clientReconInfo.pointWeight = PointWeight.value; clientReconInfo.confidence = Confidence.value; - clientReconInfo.confidenceBias = ConfidenceBias.value; clientReconInfo.kernelDepth = KernelDepth.value; clientReconInfo.samplesPerNode = SamplesPerNode.value; clientReconInfo.dataX = DataX.value; diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 6803d804..e5bed381 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -46,7 +46,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "18.30" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "18.35" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth diff --git a/Src/Reconstruction.example.cpp b/Src/Reconstruction.example.cpp index 80d28bbe..02ba63e9 100644 --- a/Src/Reconstruction.example.cpp +++ b/Src/Reconstruction.example.cpp @@ -304,9 +304,12 @@ template > void Execute( void ) { - // Finite-elements signature + // The 1D finite-elements signature static const unsigned int FEMSig = FEMDegreeAndBType< ReconType::DefaultFEMDegree , ReconType::DefaultFEMBoundary >::Signature; + // The tensor-product finite-elements signatures + using FEMSigs = IsotropicUIntPack< Dim , FEMSig >; + // Parameters for performing the reconstruction typename ReconType::template SolutionParameters< Real > solverParams; @@ -319,7 +322,10 @@ void Execute( void ) extractionParams.verbose = Verbose.set; // The type of the reconstructor - using Implicit = std::conditional_t< UseColor , typename ReconType::template Implicit< Real , Dim , FEMSig , RGBColor< Real > > , typename ReconType::template Implicit< Real , Dim , FEMSig > >; + using Implicit = std::conditional_t< UseColor , typename Reconstructor::template Implicit< Real , Dim , FEMSigs , RGBColor< Real > > , typename Reconstructor::template Implicit< Real , Dim , FEMSigs > >; + + // The solver type + using Solver = std::conditional_t< UseColor , typename ReconType::template Solver < Real , Dim , FEMSigs , RGBColor< Real > > , typename ReconType::template Solver < Real , Dim , FEMSigs > >; // Functionality for evaluating at a single point auto _Evaluate = []( typename Implicit::Evaluator &evaluator , Point< double , Dim > p ) @@ -346,10 +352,7 @@ void Execute( void ) SphereOrientedSampleWithColorStream< Real , Dim > sampleStream( SampleNum.value ); // Construct the implicit representation - Implicit implicit( sampleStream , solverParams , RGBColor< Real >() ); - - // Scale the color information to give extrapolation preference to data at finer depths - implicit.weightAuxDataByDepth( (Real)32. ); + Implicit *implicit = Solver::Solve( sampleStream , solverParams , RGBColor< Real >() ); // vectors for storing the polygons (specifically, triangles), the coordinates of the vertices, and the colors at the vertices std::vector< std::vector< int > > polygons; @@ -360,13 +363,15 @@ void Execute( void ) PolygonStream< int > pStream( polygons ); // Extract the iso-surface - implicit.extractLevelSet( vStream , pStream , extractionParams ); + implicit->extractLevelSet( vStream , pStream , extractionParams ); // Write out the level-set if( Out.set ) WritePly( Out.value , vStream.size() , vCoordinates.data() , rgbCoordinates.data() , polygons ); // Evaluate the implicit function - if( EvaluateImplicit.set ) Evaluate(implicit); + if( EvaluateImplicit.set ) Evaluate(*implicit); + + delete implicit; } else { @@ -374,7 +379,7 @@ void Execute( void ) SphereOrientedSampleStream< Real , Dim > sampleStream( SampleNum.value ); // Construct the implicit representation - Implicit implicit( sampleStream , solverParams ); + Implicit *implicit = Solver::Solve( sampleStream , solverParams ); // vectors for storing the polygons (specifically, triangles) and the coordinates of the vertices std::vector< std::vector< int > > polygons; @@ -385,7 +390,7 @@ void Execute( void ) VertexStream< Real , Dim > vStream( vCoordinates ); // Extract the iso-surface - implicit.extractLevelSet( vStream , pStream , extractionParams ); + implicit->extractLevelSet( vStream , pStream , extractionParams ); if( ColorMode.value==0 ) { @@ -422,7 +427,9 @@ void Execute( void ) } // Evaluate the implicit function - if( EvaluateImplicit.set ) Evaluate(implicit); + if( EvaluateImplicit.set ) Evaluate(*implicit); + + delete implicit; } } diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h index cd5ae205..295af8b3 100644 --- a/Src/Reconstructors.h +++ b/Src/Reconstructors.h @@ -46,7 +46,7 @@ namespace PoissonRecon static const unsigned int WeightDegree = 2; // The order of the B-Spline used to splat in the weights for density estimation // Declare a type for storing the solution information - template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... AuxData > struct Implicit; + template< typename Real , unsigned int Dim , typename FEMSigPack /* = UIntPack< FEMSigs... >*/ , typename ... AuxData > struct Implicit; // Parameters for mesh extraction struct LevelSetExtractionParameters @@ -56,29 +56,51 @@ namespace PoissonRecon bool forceManifold; bool polygonMesh; bool gridCoordinates; + bool outputDensity; bool verbose; - LevelSetExtractionParameters( void ) : linearFit(false) , outputGradients(false) , forceManifold(true) , polygonMesh(false) , gridCoordinates(false) , verbose(false) {} + LevelSetExtractionParameters( void ) : linearFit(false) , outputGradients(false) , forceManifold(true) , polygonMesh(false) , gridCoordinates(false) , verbose(false) , outputDensity(false) {} }; - // "Private" function for extracting meshes - template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ImplicitType , unsigned int ... FEMSigs > - void _ExtractLevelSet( UIntPack< FEMSigs ... > , const ImplicitType &implicit , OutputVertexStream &vertexStream , OutputFaceStream< Dim-1 > &faceStream , typename Implicit< Real , Dim , FEMSig >::LevelSetExtractionParameters params ); + struct Poisson; + struct SSD; // Specialized solution information without auxiliary data - template< typename Real , unsigned int Dim , unsigned int FEMSig > - struct Implicit< Real , Dim , FEMSig > + template< typename Real , unsigned int Dim , unsigned int ... FEMSigs , typename ... AuxData > + struct Implicit< Real , Dim , UIntPack< FEMSigs ... > , AuxData ... > { + static_assert( sizeof...(FEMSigs)==Dim , "[ERROR] Number of FEM signatures doesn't match dimension" ); + + // The internal type representing the auxiliary data + using InternalAuxData = DirectSum< Real , AuxData... >; + + // The internal type representing the normal and auxiliary data + using InternalNormalAndAuxData = DirectSum< Real , Normal< Real , Dim > , InternalAuxData >; + // The signature pack - typedef IsotropicUIntPack< Dim , FEMSig > Sigs; + using Sigs = UIntPack< FEMSigs ... >; // The type representing the point sampling density typedef typename FEMTree< Dim , Real >::template DensityEstimator< Reconstructor::WeightDegree > DensityEstimator; + // The signature of the finite-element used for data extrapolation + static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; + // The constructor - Implicit( void ) : density(NULL) , isoValue(0) , tree(MEMORY_ALLOCATOR_BLOCK_SIZE) , unitCubeToModel( XForm< Real , Dim+1 >::Identity() ){} + Implicit( AuxData ... zeroAuxData ) : density(nullptr) , isoValue(0) , tree(MEMORY_ALLOCATOR_BLOCK_SIZE) , unitCubeToModel( XForm< Real , Dim+1 >::Identity() ) , _auxData(nullptr) , _zeroAuxData(zeroAuxData...) { _zeroNormalAndAuxData = InternalNormalAndAuxData( Normal< Real , Dim >() , _zeroAuxData ); } // The desctructor - ~Implicit( void ){ delete density ; density = NULL; } + ~Implicit( void ){ delete density ; density = nullptr ; delete _auxData ; _auxData = nullptr; } + + // Write out to file + void write( BinaryStream &stream ) const + { + tree.write( stream , false ); + stream.write( isoValue ); + stream.write( unitCubeToModel ); + solution.write( stream ); + density->write( stream ); + if constexpr( sizeof...(AuxData) ) _auxData->write( stream ); + } // The transformation taking points in the unit cube back to world coordinates XForm< Real , Dim+1 > unitCubeToModel; @@ -96,11 +118,7 @@ namespace PoissonRecon DensityEstimator *density; // A method that writes the extracted mesh to the streams - void extractLevelSet( OutputLevelSetVertexStream< Real , Dim > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const - { - typedef unsigned char AuxData; - _ExtractLevelSet< false , Real , Dim , FEMSig , AuxData , OutputLevelSetVertexStream< Real , Dim > , Implicit< Real , Dim , FEMSig > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); - } + void extractLevelSet( OutputLevelSetVertexStream< Real , Dim , AuxData... > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const; struct Evaluator { @@ -144,47 +162,156 @@ namespace PoissonRecon XForm< Real , Dim > _gxForm; }; Evaluator evaluator( void ) const { return Evaluator( &tree , solution , unitCubeToModel.inverse() ); } - }; - // Specialized solution information with auxiliary data - template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > - struct Implicit< Real , Dim , FEMSig , AuxData > : public Implicit< Real , Dim , FEMSig > - { - typedef IsotropicUIntPack< Dim , FEMSig > Sigs; + struct AuxEvaluator + { + struct OutOfUnitCubeException : public std::exception + { + OutOfUnitCubeException( Point< Real , Dim > world , Point< Real , Dim > cube ) + { + std::stringstream sStream; + sStream << "Out-of-unit-cube input: " << world << " -> " << cube; + _message = sStream.str(); + } + const char * what( void ) const noexcept { return _message.c_str(); } + protected: + std::string _message; + }; - // The signature of the finite-element used for data extrapolation - static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; + AuxEvaluator( const FEMTree< Dim , Real > *tree , const SparseNodeData< ProjectiveData< InternalAuxData , Real > , IsotropicUIntPack< Dim , DataSig > > &coefficients , XForm< Real , Dim+1 > worldToUnitCube , InternalAuxData zero ) + : _auxEvaluator( tree , coefficients , ThreadPool::NumThreads() ) , _xForm(worldToUnitCube) , _zero(zero) {} - // The constructor - Implicit( AuxData zeroAuxData ) : auxData(NULL) , zeroAuxData(zeroAuxData) {} + void set( unsigned int t , Point< Real , Dim > p , AuxData&...d ){ _SetFromInternal( _value(t,p) , d... ); } - // The desctructor - ~Implicit( void ){ delete auxData ; auxData = NULL; } + void set( Point< Real , Dim > p , AuxData&...d ){ return operator()( 0 , p , d... ); } + + XForm< Real , Dim+1 > worldToUnitCubeTransform( void ) const { return worldToUnitCubeTransform(); } + protected: + InternalAuxData _value( unsigned int t , Point< Real , Dim > p ) + { + Point< Real , Dim > q = _xForm * p; + for( unsigned int d=0 ; d1 ) throw OutOfUnitCubeException(p,q); + ProjectiveData< InternalAuxData , Real > pData( _zero ); + _auxEvaluator.addValue( q , pData ); + return pData.value(); + } + + template< typename D , typename ... Ds > + static void _SetFromInternal( InternalAuxData iData , D &d , Ds&... ds ) + { + d = iData.template get< sizeof...(AuxData) - sizeof...(Ds) - 1 >(); + if constexpr( sizeof...(Ds) ) _SetFromInternal( iData , ds... ); + } + + typename FEMTree< Dim , Real >::template MultiThreadedSparseEvaluator< IsotropicUIntPack< Dim , DataSig > , ProjectiveData< InternalAuxData , Real > > _auxEvaluator; + XForm< Real , Dim+1 > _xForm; + InternalAuxData _zero; + }; + AuxEvaluator auxEvaluator( void ) const + { + static_assert( sizeof...(AuxData) , "No auxiliary data" ); + return AuxEvaluator( &tree , *_auxData , unitCubeToModel.inverse() , _zeroAuxData ); + } + + protected: // The auxiliary information stored with the oriented vertices - SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > > *auxData; + SparseNodeData< ProjectiveData< InternalAuxData , Real > , IsotropicUIntPack< Dim , DataSig > > *_auxData; // An instance of "zero" AuxData - AuxData zeroAuxData; + InternalAuxData _zeroAuxData; + + InternalNormalAndAuxData _zeroNormalAndAuxData; - // a method for rescaling the contents of the auxiliary data to give interpolation-preference to finer levels - void weightAuxDataByDepth( Real perLevelScaleFactor ) + struct _VertexTypeConverter { - auto nodeFunctor = [&]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *n ) - { - ProjectiveData< AuxData , Real >* clr = (*auxData)( n ); - if( clr ) (*clr) *= (Real)pow( (Real)perLevelScaleFactor , Implicit< Real , Dim , FEMSig>::tree.depth( n ) ); - }; - Implicit< Real , Dim , FEMSig>::tree.tree().processNodes( nodeFunctor ); - } + using ExternalVertexType = std::tuple< Position< Real , Dim > , Gradient< Real , Dim > , Weight< Real > , InternalAuxData >; + using InternalVertexType = std::tuple< Position< Real , Dim > , Gradient< Real , Dim > , Weight< Real > , AuxData... >; + + static ExternalVertexType ConvertI2X( const InternalVertexType &iType ) + { + ExternalVertexType xType; + + // Copy the position information + std::get< 0 >( xType ) = std::get< 0 >( iType ); + std::get< 1 >( xType ) = std::get< 1 >( iType ); + std::get< 2 >( xType ) = std::get< 2 >( iType ); + // Copy the remainder of the information + _SetAuxData< 0 >( iType , xType ); + return xType; + } + static InternalVertexType ConvertX2I( const ExternalVertexType &xType ) + { + InternalVertexType iType; + + // Copy the position information + std::get< 0 >( iType ) = std::get< 0 >( xType ); + std::get< 1 >( iType ) = std::get< 1 >( xType ); + std::get< 2 >( iType ) = std::get< 2 >( xType ); + // Copy the remainder of the information + _SetAuxData< 0 >( xType , iType ); + return iType; + } + protected: + template< unsigned int I > + static void _SetAuxData( const InternalVertexType &iType , ExternalVertexType &xType ) + { + std::get< 3 >( xType ).template get< I >() = std::get< I+3 >( iType ); + if constexpr( I+1( iType , xType ); + } + template< unsigned int I > + static void _SetAuxData( const ExternalVertexType &xType , InternalVertexType &iType ) + { + std::get< I+3 >( iType ) = std::get< 3 >( xType ).template get< I >(); + if constexpr( I+1( xType , iType ); + } + }; - // A method for writing the extracted mesh to the streams - void extractLevelSet( OutputLevelSetVertexStream< Real , Dim , AuxData > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const + struct _SampleTypeConverter { - _ExtractLevelSet< true , Real , Dim , FEMSig , AuxData , OutputLevelSetVertexStream< Real , Dim , AuxData > , Implicit< Real , Dim , FEMSig , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , vertexStream , faceStream , params ); - } + using ExternalSampleType = std::tuple< Position< Real , Dim > , InternalNormalAndAuxData >; + using InternalSampleType = std::tuple< Position< Real , Dim > , Normal< Real , Dim > , AuxData... >; + + static ExternalSampleType ConvertI2X( const InternalSampleType &iType ) + { + ExternalSampleType xType; + + // Copy the position information + std::get< 0 >( xType ) = std::get< 0 >( iType ); + // Copy the remainder of the information + _SetNormalAndAuxData< 0 >( iType , xType ); + return xType; + } + static InternalSampleType ConvertX2I( const ExternalSampleType &xType ) + { + InternalSampleType iType; + + // Copy the position information + std::get< 0 >( iType ) = std::get< 0 >( xType ); + // Copy the remainder of the information + _SetNormalAndAuxData< 0 >( xType , iType ); + return iType; + } + protected: + template< unsigned int I > + static void _SetNormalAndAuxData( const InternalSampleType &iType , ExternalSampleType &xType ) + { + std::get< 1 >( xType ).template get< I >() = std::get< I+1 >( iType ); + if constexpr( I( iType , xType ); + } + template< unsigned int I > + static void _SetNormalAndAuxData( const ExternalSampleType &xType , InternalSampleType &iType ) + { + std::get< I+1 >( iType ) = std::get< 1 >( xType ).template get< I >(); + if constexpr( I( xType , iType ); + } + }; + + friend Poisson; + friend SSD; }; + struct Poisson { static const unsigned int NormalDegree = 2; // The order of the B-Spline used to splat in the normals for constructing the Laplacian constraints @@ -269,12 +396,10 @@ namespace PoissonRecon { bool verbose; bool dirichletErode; - bool outputDensity; bool exactInterpolation; bool showResidual; Real scale; Real confidence; - Real confidenceBias; Real lowDepthCutOff; Real width; Real pointWeight; @@ -282,6 +407,7 @@ namespace PoissonRecon Real samplesPerNode; Real cgSolverAccuracy; Real targetValue; + Real perLevelDataScaleFactor; unsigned int depth; unsigned int solveDepth; unsigned int baseDepth; @@ -293,9 +419,9 @@ namespace PoissonRecon unsigned int alignDir; SolutionParameters( void ) : - verbose(false) , dirichletErode(false) , outputDensity(false) , exactInterpolation(false) , showResidual(false) , - scale((Real)1.1) , confidence((Real)0.) , confidenceBias((Real)0.) , lowDepthCutOff((Real)0.) , width((Real)0.) , - pointWeight((Real)( WeightMultiplier * DefaultFEMDegree ) ) , valueInterpolationWeight((Real)0.) , samplesPerNode((Real)1.5) , cgSolverAccuracy((Real)1e-3 ) , targetValue((Real)0.5) , + verbose(false) , dirichletErode(false) , exactInterpolation(false) , showResidual(false) , + scale((Real)1.1) , confidence((Real)0.) , lowDepthCutOff((Real)0.) , width((Real)0.) , + pointWeight((Real)( WeightMultiplier * DefaultFEMDegree ) ) , valueInterpolationWeight((Real)0.) , samplesPerNode((Real)1.5) , cgSolverAccuracy((Real)1e-3 ) , targetValue((Real)0.5) , perLevelDataScaleFactor((Real)32.) , depth((unsigned int)8) , solveDepth((unsigned int)-1) , baseDepth((unsigned int)-1) , fullDepth((unsigned int)5) , kernelDepth((unsigned int)-1) , envelopeDepth((unsigned int)-1) , baseVCycles((unsigned int)1) , iters((unsigned int)8) , alignDir(0) {} @@ -308,31 +434,12 @@ namespace PoissonRecon std::vector< SimplexIndex< Dim-1 , node_index_type > > simplices; }; - template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct Implicit; - - template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputOrientedSampleStreamType , unsigned int ... FEMSigs > - static void _Solve( UIntPack< FEMSigs... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputOrientedSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh , InputValuedSampleStream< Real , Dim > *valueInterpolationStream ); + template< typename Real , unsigned int Dim , typename FEMSigPack , typename ... AuxData > struct Solver; - template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct Implicit; - - template< typename Real , unsigned int Dim , unsigned int FEMSig > - struct Implicit< Real , Dim , FEMSig > : public Reconstructor::Implicit< Real , Dim , FEMSig > + template< typename Real , unsigned int Dim , unsigned int ... FEMSigs , typename ... AuxData > + struct Solver< Real , Dim , UIntPack< FEMSigs... > , AuxData... > { - Implicit( InputOrientedSampleStream< Real , Dim > &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL , InputValuedSampleStream< Real , Dim > *valueInterpolationStream=NULL ) - { - typedef unsigned char AuxData; - _Solve< false , Real , Dim , FEMSig , AuxData , InputOrientedSampleStream< Real , Dim > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params , envelopeMesh , valueInterpolationStream ); - } - }; - - template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > - struct Implicit< Real , Dim , FEMSig , AuxData > : public Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > - { - Implicit( InputOrientedSampleStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params , AuxData zero , const EnvelopeMesh< Real , Dim > *envelopeMesh=NULL , InputValuedSampleStream< Real , Dim > *valueInterpolationStream=NULL ) - : Reconstructor::Implicit< Real , Dim , FEMSig , AuxData >( zero ) - { - _Solve< true , Real , Dim , FEMSig , AuxData , InputOrientedSampleStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params , envelopeMesh , valueInterpolationStream ); - } + static Implicit< Real , Dim , UIntPack< FEMSigs... > , AuxData... > *Solve( InputOrientedSampleStream< Real , Dim , AuxData... > &pointStream , SolutionParameters< Real > params , AuxData ... zero , const EnvelopeMesh< Real , Dim > *envelopeMesh=nullptr , InputValuedSampleStream< Real , Dim > *valueInterpolationStream=nullptr ); }; }; @@ -343,29 +450,15 @@ namespace PoissonRecon static const BoundaryType DefaultFEMBoundary = BOUNDARY_NEUMANN; // The default finite-element boundary type {BOUNDARY_FREE, BOUNDARY_DIRICHLET, BOUNDARY_NEUMANN} inline static const double WeightMultipliers[] = { 5e+1f , 5e-4f , 1e-5f }; // The default weights for balancing the value, gradient, and laplacian energy terms - template< unsigned int Dim , typename ... > struct ConstraintDual; - template< unsigned int Dim , typename ... > struct SystemDual; + template< typename Real , unsigned int Dim , typename ... AuxData > + using NormalAndAuxData = DirectSum< Real , Normal< Real , Dim > , DirectSum< Real , AuxData... > >; - template< unsigned int Dim , typename Real > - struct ConstraintDual< Dim , Real > - { - Real target , vWeight , gWeight; - ConstraintDual( Real t , Real v , Real g ) : target(t) , vWeight(v) , gWeight(g) { } - CumulativeDerivativeValues< Real , Dim , 1 > operator()( const Point< Real , Dim >& p , const Point< Real , Dim > &n ) const - { - CumulativeDerivativeValues< Real , Dim , 1 > cdv; - cdv[0] = target*vWeight; - for( int d=0 ; d - struct ConstraintDual< Dim , Real , AuxData > + template< unsigned int Dim , typename Real , typename ... AuxData > + struct ConstraintDual { Real target , vWeight , gWeight; ConstraintDual( Real t , Real v , Real g ) : target(t) , vWeight(v) , gWeight(g) { } - CumulativeDerivativeValues< Real , Dim , 1 > operator()( const Point< Real , Dim >& p , const DirectSum< Real , Point< Real , Dim > , AuxData > &normalAndAuxData ) const + CumulativeDerivativeValues< Real , Dim , 1 > operator()( const Point< Real , Dim >& p , const NormalAndAuxData< Real , Dim , AuxData... > &normalAndAuxData ) const { Point< Real , Dim > n = normalAndAuxData.template get<0>(); CumulativeDerivativeValues< Real , Dim , 1 > cdv; @@ -375,39 +468,8 @@ namespace PoissonRecon } }; - template< unsigned int Dim , typename Real > - struct SystemDual< Dim , Real > - { - CumulativeDerivativeValues< Real , Dim , 1 > weight; - SystemDual( Real v , Real g ) - { - weight[0] = v; - for( int d=0 ; d operator()( Point< Real , Dim > p , const Point< Real , Dim > & , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const - { - return dValues * weight; - } - CumulativeDerivativeValues< double , Dim , 1 > operator()( Point< Real , Dim > p , const Point< Real , Dim > & , const CumulativeDerivativeValues< double , Dim , 1 >& dValues ) const - { - return dValues * weight; - }; - }; - - template< unsigned int Dim > - struct SystemDual< Dim , double > - { - typedef double Real; - CumulativeDerivativeValues< Real , Dim , 1 > weight; - SystemDual( Real v , Real g ) : weight( v , g , g , g ) { } - CumulativeDerivativeValues< Real , Dim , 1 > operator()( Point< Real , Dim > p , const Point< Real , Dim > & , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const - { - return dValues * weight; - } - }; - - template< unsigned int Dim , typename Real , typename AuxData > - struct SystemDual< Dim , Real , AuxData > + template< unsigned int Dim , typename Real , typename ... AuxData > + struct SystemDual { CumulativeDerivativeValues< Real , Dim , 1 > weight; SystemDual( Real v , Real g ) @@ -415,23 +477,23 @@ namespace PoissonRecon weight[0] = v; for( int d=0 ; d operator()( Point< Real , Dim > p , const DirectSum< Real , Point< Real , Dim > , AuxData > & , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const + CumulativeDerivativeValues< Real , Dim , 1 > operator()( Point< Real , Dim > p , const NormalAndAuxData< Real , Dim , AuxData... > & , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const { return dValues * weight; } - CumulativeDerivativeValues< double , Dim , 1 > operator()( Point< Real , Dim > p , const DirectSum< Real , Point< Real , Dim > , AuxData > & , const CumulativeDerivativeValues< double , Dim , 1 >& dValues ) const + CumulativeDerivativeValues< double , Dim , 1 > operator()( Point< Real , Dim > p , const NormalAndAuxData< Real , Dim , AuxData... > & , const CumulativeDerivativeValues< double , Dim , 1 >& dValues ) const { return dValues * weight; }; }; - template< unsigned int Dim , class AuxData > - struct SystemDual< Dim , double , AuxData > + template< unsigned int Dim , typename ... AuxData > + struct SystemDual< Dim , double , AuxData... > { typedef double Real; CumulativeDerivativeValues< Real , Dim , 1 > weight; SystemDual( Real v , Real g ) : weight( v , g , g , g ) { } - CumulativeDerivativeValues< Real , Dim , 1 > operator()( Point< Real , Dim > p , const DirectSum< Real , Point< Real , Dim > , AuxData > & , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const + CumulativeDerivativeValues< Real , Dim , 1 > operator()( Point< Real , Dim > p , const NormalAndAuxData< Real , Dim , AuxData... > & , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const { return dValues * weight; } @@ -441,12 +503,10 @@ namespace PoissonRecon struct SolutionParameters { bool verbose; - bool outputDensity; bool exactInterpolation; bool showResidual; Real scale; Real confidence; - Real confidenceBias; Real lowDepthCutOff; Real width; Real pointWeight; @@ -454,6 +514,7 @@ namespace PoissonRecon Real biLapWeight; Real samplesPerNode; Real cgSolverAccuracy; + Real perLevelDataScaleFactor; unsigned int depth; unsigned int solveDepth; unsigned int baseDepth; @@ -464,59 +525,38 @@ namespace PoissonRecon unsigned int alignDir; SolutionParameters( void ) : - verbose(false) , outputDensity(false) , exactInterpolation(false) , showResidual(false) , - scale((Real)1.1) , confidence((Real)0.) , confidenceBias((Real)0.) , lowDepthCutOff((Real)0.) , width((Real)0.) , - pointWeight((Real)WeightMultipliers[0]) , gradientWeight((Real)WeightMultipliers[1]) , biLapWeight((Real)WeightMultipliers[2]) , samplesPerNode((Real)1.5) , cgSolverAccuracy((Real)1e-3 ) , + verbose(false) , exactInterpolation(false) , showResidual(false) , + scale((Real)1.1) , confidence((Real)0.) , lowDepthCutOff((Real)0.) , width((Real)0.) , + pointWeight((Real)WeightMultipliers[0]) , gradientWeight((Real)WeightMultipliers[1]) , biLapWeight((Real)WeightMultipliers[2]) , samplesPerNode((Real)1.5) , cgSolverAccuracy((Real)1e-3 ) , perLevelDataScaleFactor((Real)32.) , depth((unsigned int)8) , solveDepth((unsigned int)-1) , baseDepth((unsigned int)-1) , fullDepth((unsigned int)5) , kernelDepth((unsigned int)-1) , alignDir(0) , baseVCycles((unsigned int)1) , iters((unsigned int)8) {} }; - template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... Other > struct Implicit; - - template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputOrientedSampleStreamType , unsigned int ... FEMSigs > - static void _Solve( UIntPack< FEMSigs... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputOrientedSampleStreamType &pointStream , SolutionParameters< Real > params ); - - template< typename Real , unsigned int Dim , unsigned int FEMSig > - struct Implicit< Real , Dim , FEMSig > : public Reconstructor::Implicit< Real , Dim , FEMSig > - { - Implicit( InputOrientedSampleStream< Real , Dim > &pointStream , SolutionParameters< Real > params ) - { - typedef unsigned char AuxData; - _Solve< false , Real , Dim , FEMSig , AuxData , InputOrientedSampleStream< Real , Dim > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params ); - } - }; + template< typename Real , unsigned int Dim , typename FEMSigPack , typename ... AuxData > struct Solver; - template< typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData > - struct Implicit< Real , Dim , FEMSig , AuxData > : public Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > + template< typename Real , unsigned int Dim , unsigned int ... FEMSigs , typename ... AuxData > + struct Solver< Real , Dim , UIntPack< FEMSigs... > , AuxData... > { - Implicit( InputOrientedSampleStream< Real , Dim , AuxData > &pointStream , SolutionParameters< Real > params , AuxData zero ) - : Reconstructor::Implicit< Real , Dim , FEMSig , AuxData >( zero ) - { - _Solve< true , Real , Dim , FEMSig , AuxData , InputOrientedSampleStream< Real , Dim , AuxData > >( IsotropicUIntPack< Dim , FEMSig >() , *this , pointStream , params ); - } + static Implicit< Real , Dim , UIntPack< FEMSigs... > , AuxData... > *Solve( InputOrientedSampleStream< Real , Dim , AuxData... > &pointStream , SolutionParameters< Real > params , AuxData ... zero ); }; }; - - - template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename OutputVertexStream , typename ImplicitType , unsigned int ... FEMSigs > - void _ExtractLevelSet( UIntPack< FEMSigs ... > , const ImplicitType &implicit , OutputVertexStream &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) + // Implementation of the base Implicit class's level-set extraction + template< typename Real , unsigned int Dim , unsigned int ... FEMSigs , typename ... AuxData > + void Implicit< Real , Dim , UIntPack< FEMSigs ... > , AuxData ... >::extractLevelSet( OutputLevelSetVertexStream< Real , Dim , AuxData... > &vertexStream , OutputFaceStream< Dim-1 > &faceStream , LevelSetExtractionParameters params ) const { - typedef UIntPack< FEMSigs ... > Sigs; - static_assert( std::is_same< IsotropicUIntPack< Dim , FEMSig > , UIntPack< FEMSigs ... > >::value , "[ERROR] Signatures don't match" ); - static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; - typedef typename ImplicitType::DensityEstimator DensityEstimator; - XForm< Real , Dim+1 > unitCubeToModel; if( params.gridCoordinates ) { unitCubeToModel = XForm< Real , Dim+1 >::Identity(); - unsigned int res = 1<unitCubeToModel; + + DensityEstimator *density = params.outputDensity ? this->density : nullptr; if constexpr( Dim==3 ) { @@ -524,18 +564,19 @@ namespace PoissonRecon std::string statsString; - if constexpr( HasAuxData ) + TransformedOutputLevelSetVertexStream< Real , Dim , AuxData... > _vertexStream( unitCubeToModel , vertexStream ); + if constexpr( sizeof...(AuxData) ) { - typename LevelSetExtractor< Real , Dim , AuxData >::Stats stats; - TransformedOutputLevelSetVertexStream< Real , Dim , AuxData > _vertexStream( unitCubeToModel , vertexStream ); - stats = LevelSetExtractor< Real , Dim , AuxData >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , UIntPack< DataSig >() , implicit.tree , implicit.density , implicit.auxData , implicit.solution , implicit.isoValue , _vertexStream , faceStream , implicit.zeroAuxData , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); + // Convert stream: + // OutputDataStream< Position< Real , Dim > , Gradient< Real , Dim > , Weight< Real > , AuxData... > + // -> OutputDataStream< Position< Real , Dim > , Gradient< Real , Dim > , Weight< Real > , InternalAuxData > + OutputDataStreamConverter< typename _VertexTypeConverter::InternalVertexType , typename _VertexTypeConverter::ExternalVertexType > __vertexStream( _vertexStream , _VertexTypeConverter::ConvertX2I ); + typename LevelSetExtractor< Real , Dim , InternalAuxData >::Stats stats = LevelSetExtractor< Real , Dim , InternalAuxData >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , UIntPack< DataSig >() , tree , density , _auxData , solution , isoValue , __vertexStream , faceStream , _zeroAuxData , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); statsString = stats.toString(); } else { - typename LevelSetExtractor< Real , Dim >::Stats stats; - TransformedOutputLevelSetVertexStream< Real , Dim > _vertexStream( unitCubeToModel , vertexStream ); - stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , implicit.tree , implicit.density , implicit.solution , implicit.isoValue , _vertexStream , faceStream , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); + typename LevelSetExtractor< Real , Dim >::Stats stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , tree , density , solution , isoValue , _vertexStream , faceStream , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); statsString = stats.toString(); } if( params.verbose ) @@ -551,20 +592,22 @@ namespace PoissonRecon std::string statsString; - if constexpr( HasAuxData ) + TransformedOutputLevelSetVertexStream< Real , Dim , InternalAuxData > _vertexStream( unitCubeToModel , vertexStream ); + if constexpr( sizeof...(AuxData) ) { - typename LevelSetExtractor< Real , Dim , AuxData >::Stats stats; - TransformedOutputLevelSetVertexStream< Real , Dim , AuxData > _vertexStream( unitCubeToModel , vertexStream ); - stats = LevelSetExtractor< Real , Dim , AuxData >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , UIntPack< DataSig >() , implicit.tree , implicit.density , implicit.auxData , implicit.solution , implicit.isoValue , _vertexStream , faceStream , implicit.zeroAuxData , !params.linearFit , params.outputGradients , false ); + // Convert stream: + // OutputDataStream< Position< Real , Dim > , Gradient< Real , Dim > , Weight< Real > , AuxData... > + // -> OutputDataStream< Position< Real , Dim > , Gradient< Real , Dim > , Weight< Real > , InternalAuxData > + OutputDataStreamConverter< typename _VertexTypeConverter::InternalVertexType , typename _VertexTypeConverter::ExternalVertexType > __vertexStream( _vertexStream , _VertexTypeConverter::ConvertX2I ); + typename LevelSetExtractor< Real , Dim , InternalAuxData >::Stats stats = LevelSetExtractor< Real , Dim , InternalAuxData >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , UIntPack< DataSig >() , tree , density , _auxData , solution , isoValue , __vertexStream , faceStream , _zeroAuxData , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); statsString = stats.toString(); } else { - typename LevelSetExtractor< Real , Dim >::Stats stats; - TransformedOutputLevelSetVertexStream< Real , Dim > _vertexStream( unitCubeToModel , vertexStream ); - stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , implicit.tree , implicit.density , implicit.solution , implicit.isoValue , _vertexStream , faceStream , !params.linearFit , params.outputGradients , false ); + typename LevelSetExtractor< Real , Dim >::Stats stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , tree , density , solution , isoValue , _vertexStream , faceStream , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); statsString = stats.toString(); } + if( params.verbose ) { std::cout << "Vertices / Faces: " << vertexStream.size() << " / " << faceStream.size() << std::endl; @@ -574,10 +617,13 @@ namespace PoissonRecon } else WARN( "Extraction only supported for dimensions 2 and 3" ); } - template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputOrientedSampleStreamType , unsigned int ... FEMSigs > - void Poisson::_Solve( UIntPack< FEMSigs ... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputOrientedSampleStreamType &pointStream , SolutionParameters< Real > params , const EnvelopeMesh< Real , Dim > *envelopeMesh , InputValuedSampleStream< Real , Dim > *valueInterpolationStream ) + // Implementation of the derived Poisson::Implicit's constructor + template< typename Real , unsigned int Dim , unsigned int ... FEMSigs , typename ... AuxData > + Implicit< Real , Dim , UIntPack< FEMSigs... > , AuxData... > *Poisson::Solver< Real , Dim , UIntPack< FEMSigs... > , AuxData... >::Solve( InputOrientedSampleStream< Real , Dim , AuxData... > &pointStream , SolutionParameters< Real > params , AuxData ... zero , const EnvelopeMesh< Real , Dim > *envelopeMesh , InputValuedSampleStream< Real , Dim > *valueInterpolationStream ) { - static_assert( std::is_same< IsotropicUIntPack< Dim , FEMSig > , UIntPack< FEMSigs... > >::value , "[ERROR] Signatures don't match" ); + Implicit< Real , Dim , UIntPack< FEMSigs... > , AuxData... > *implicitPtr = new Implicit< Real , Dim , UIntPack< FEMSigs... > , AuxData... >( zero... ); + Implicit< Real , Dim , UIntPack< FEMSigs... > , AuxData... > &implicit = *implicitPtr; + if( params.valueInterpolationWeight<0 ) { WARN( "Negative value interpolation weight clamped to zero" ); @@ -590,8 +636,10 @@ namespace PoissonRecon /////////////// // Types --> // - // The packed finite elements signature - typedef UIntPack< FEMSigs ... > Sigs; + using InternalAuxData = typename Reconstructor::Implicit< Real , Dim , UIntPack< FEMSigs... > , AuxData... >::InternalAuxData; + using InternalNormalAndAuxData = typename Reconstructor::Implicit< Real , Dim , UIntPack< FEMSigs... > , AuxData... >::InternalNormalAndAuxData; + using _SampleTypeConverter = typename Reconstructor::Implicit< Real , Dim , UIntPack< FEMSigs... > , AuxData... >::_SampleTypeConverter; + using Sigs = typename Reconstructor::Implicit< Real , Dim , UIntPack< FEMSigs... > , AuxData... >::Sigs; // The degrees of the finite elements across the different axes typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > Degrees; @@ -606,18 +654,9 @@ namespace PoissonRecon typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; typedef typename FEMTreeInitializer< Dim , Real >::GeometryNodeType GeometryNodeType; - - // The type of the auxiliary information (including the normal) - typedef typename std::conditional< HasAuxData , DirectSum< Real , Normal< Real , Dim > , AuxData > , Normal< Real , Dim > >::type NormalAndAuxData; - - // The type describing the sampling density - typedef typename std::conditional< HasAuxData , Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type::DensityEstimator DensityEstimator; // <-- Types // /////////////// - NormalAndAuxData zeroNormalAndAuxData; - if constexpr( HasAuxData ) zeroNormalAndAuxData = NormalAndAuxData( Normal< Real , Dim >() , implicit.zeroAuxData ); - XForm< Real , Dim+1 > modelToUnitCube = XForm< Real , Dim+1 >::Identity(); Profiler profiler( ProfilerMS ); @@ -630,7 +669,7 @@ namespace PoissonRecon DenseNodeData< GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > geometryNodeDesignators; SparseNodeData< Point< Real , Dim > , NormalSigs > *normalInfo = NULL; std::vector< typename FEMTree< Dim , Real >::PointSample > *samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); - std::vector< NormalAndAuxData > *sampleNormalAndAuxData = NULL; + std::vector< InternalNormalAndAuxData > *sampleNormalAndAuxData = nullptr; Real targetValue = params.targetValue; @@ -639,10 +678,8 @@ namespace PoissonRecon profiler.reset(); pointStream.reset(); - sampleNormalAndAuxData = new std::vector< NormalAndAuxData >(); - - if constexpr( HasAuxData ) modelToUnitCube = params.scale>0 ? PointExtent::GetXForm< Real , Dim , true , Point< Real , Dim > , AuxData >( pointStream , Point< Real , Dim >() , implicit.zeroAuxData , params.scale , params.alignDir ) * modelToUnitCube : modelToUnitCube; - else modelToUnitCube = params.scale>0 ? PointExtent::GetXForm< Real , Dim , true , Point< Real , Dim > >( pointStream , Point< Real , Dim >() , params.scale , params.alignDir ) * modelToUnitCube : modelToUnitCube; + sampleNormalAndAuxData = new std::vector< InternalNormalAndAuxData >(); + modelToUnitCube = params.scale>0 ? PointExtent::GetXForm< Real , Dim , true , Normal< Real , Dim > , AuxData... >( pointStream , Normal< Real , Dim >() , zero... , params.scale , params.alignDir ) * modelToUnitCube : modelToUnitCube; pointStream.reset(); if( params.width>0 ) @@ -692,58 +729,51 @@ namespace PoissonRecon params.envelopeDepth = params.baseDepth; } - if constexpr( HasAuxData ) { - TransformedInputOrientedSampleStream< Real , Dim , AuxData > _pointStream( modelToUnitCube , pointStream ); - auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , NormalAndAuxData &d ) + // Apply the transformation + TransformedInputOrientedSampleStream< Real , Dim , AuxData... > _pointStream( modelToUnitCube , pointStream ); + + std::vector< node_index_type > nodeToIndexMap; + + auto IsValid = [&]( const Point< Real , Dim > &p , const Normal< Real , Dim > &n , AuxData ... d ) { - Real l = (Real)Length( d.template get<0>() ); - if( !l || !std::isfinite( l ) ) return (Real)-1.; - return (Real)pow( l , params.confidence ); + Real l = Point< Real , Dim >::SquareNorm( n ); + return l>0 && std::isfinite(l); }; - auto ProcessData = []( const Point< Real , Dim > &p , NormalAndAuxData &d ) + + auto Process = [&]( FEMTreeNode &node , const Point< Real , Dim > &p , Normal< Real , Dim > &n , AuxData ... d ) { - Real l = (Real)Length( d.template get<0>() ); - if( !l || !std::isfinite( l ) ) return (Real)-1.; - d.template get<0>() /= l; - return (Real)1.; - }; + Real l = (Real)Length( n ); + Real weight = params.confidence>0 ? pow( l , params.confidence ) : (Real)1.; + n /= l; - { - using ExternalType = std::tuple< Point< Real , Dim > , NormalAndAuxData >; - using InternalType = std::tuple< Point< Real , Dim > , Point< Real , Dim > , AuxData >; - auto converter = []( const InternalType &iType ) + node_index_type nodeIndex = node.nodeData.nodeIndex; + // If the node's index exceeds what's stored in the node-to-index map, grow the node-to-index map + if( nodeIndex>=(node_index_type)nodeToIndexMap.size() ) nodeToIndexMap.resize( nodeIndex+1 , -1 ); + + node_index_type idx = nodeToIndexMap[ nodeIndex ]; + if( idx==-1 ) { - ExternalType xType; - std::get< 0 >( xType ) = std::get< 0 >( iType ); - std::get< 1 >( xType ).template get<0>() = std::get< 1 >( iType ); - std::get< 1 >( xType ).template get<1>() = std::get< 2 >( iType ); - return xType; - }; - InputDataStreamConverter< InternalType , ExternalType > __pointStream( _pointStream , converter , Point< Real , Dim >() , Point< Real , Dim >() , implicit.zeroAuxData ); - if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( implicit.tree.spaceRoot() , __pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( implicit.tree.spaceRoot() , __pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); - } - } - else - { - TransformedInputOrientedSampleStream< Real , Dim > _pointStream( modelToUnitCube , pointStream ); - auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , NormalAndAuxData &d ) - { - Real l = (Real)Length( d ); - if( !l || !std::isfinite( l ) ) return (Real)-1.; - return (Real)pow( l , params.confidence ); + idx = (node_index_type)samples->size(); + nodeToIndexMap[ nodeIndex ] = idx; + samples->resize( idx+1 ) , (*samples)[idx].node = &node; + sampleNormalAndAuxData->resize( idx+1 ); + (*samples)[idx].sample = ProjectiveData< Point< Real , Dim > , Real >( p*weight , weight ); + (*sampleNormalAndAuxData)[idx] = InternalNormalAndAuxData( n , DirectSum< Real , AuxData... >( d... ) ) * weight; + } + else + { + (*samples)[idx].sample += ProjectiveData< Point< Real , Dim > , Real >( p*weight , weight ); + (*sampleNormalAndAuxData)[idx] += InternalNormalAndAuxData( n , DirectSum< Real , AuxData... >( d... ) ) * weight; + } + return true; }; - auto ProcessData = []( const Point< Real , Dim > &p , NormalAndAuxData &d ) + + auto F = [&]( AuxData ... zeroAuxData ) { - Real l = (Real)Length( d ); - if( !l || !std::isfinite( l ) ) return (Real)-1.; - d /= l; - return (Real)1.; + pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< decltype(IsValid) , decltype(Process) , Normal< Real , Dim > , AuxData... >( implicit.tree.spaceRoot() , _pointStream , Normal< Real , Dim >() , zeroAuxData... , params.depth , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : nullptr , implicit.tree.initializer() , IsValid , Process ); }; - - if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); + implicit._zeroAuxData.process( F ); } implicit.unitCubeToModel = modelToUnitCube.inverse(); @@ -788,53 +818,20 @@ namespace PoissonRecon { profiler.reset(); normalInfo = new SparseNodeData< Point< Real , Dim > , NormalSigs >(); - std::function< bool ( NormalAndAuxData , Point< Real , Dim > & ) > ConversionFunction; - std::function< bool ( NormalAndAuxData , Point< Real , Dim > & , Real & ) > ConversionAndBiasFunction; - if constexpr( HasAuxData ) - { - ConversionFunction = []( NormalAndAuxData in , Point< Real , Dim > &out ) - { - Point< Real , Dim > n = in.template get<0>(); - Real l = (Real)Length( n ); - // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... - if( !l ) return false; - out = n / l; - return true; - }; - ConversionAndBiasFunction = [&]( NormalAndAuxData in , Point< Real , Dim > &out , Real &bias ) - { - Point< Real , Dim > n = in.template get<0>(); - Real l = (Real)Length( n ); - // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... - if( !l ) return false; - out = n / l; - bias = (Real)( log( l ) * params.confidenceBias / log( 1<<(Dim-1) ) ); - return true; - }; - } - else - { - // In this case NormalAndAuxData = Point< Real , Dim > - ConversionFunction = []( NormalAndAuxData in , Point< Real , Dim > &out ) - { - Real l = (Real)Length( in ); - // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... - if( !l ) return false; - out = in / l; - return true; - }; - ConversionAndBiasFunction = [&]( NormalAndAuxData in , Point< Real , Dim > &out , Real &bias ) - { - Real l = (Real)Length( in ); - // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... - if( !l ) return false; - out = in / l; - bias = (Real)( log( l ) * params.confidenceBias / log( 1<<(Dim-1) ) ); - return true; - }; - } - if( params.confidenceBias>0 ) *normalInfo = implicit.tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , implicit.density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionAndBiasFunction ); - else *normalInfo = implicit.tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , implicit.density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionFunction ); + + std::function< bool ( InternalNormalAndAuxData , Point< Real , Dim > & ) > ConversionFunction; + std::function< bool ( InternalNormalAndAuxData , Point< Real , Dim > & , Real & ) > ConversionAndBiasFunction; + ConversionFunction = []( InternalNormalAndAuxData in , Normal< Real , Dim > &out ) + { + Normal< Real , Dim > n = in.template get<0>(); + Real l = (Real)Length( n ); + // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... + if( !l ) return false; + out = n / l; + return true; + }; + *normalInfo = implicit.tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , implicit.density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionFunction ); + ThreadPool::ParallelFor( 0 , normalInfo->size() , [&]( unsigned int , size_t i ){ (*normalInfo)[i] *= (Real)-1.; } ); if( params.verbose ) { @@ -937,13 +934,30 @@ namespace PoissonRecon if( params.verbose ) std::cout << "# Initialized envelope constraints: " << profiler << std::endl; } - if( !params.outputDensity ){ delete implicit.density ; implicit.density = NULL; } - if constexpr( HasAuxData ) + if constexpr( sizeof...(AuxData) ) { profiler.reset(); - implicit.auxData = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( implicit.tree.template setExtrapolatedDataField< DataSig , false , Reconstructor::WeightDegree , AuxData >( samples->size() , [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return (*samples)[i]; } , [&]( size_t i ) -> const AuxData & { return (*sampleNormalAndAuxData)[i].template get<1>(); } , (DensityEstimator*)NULL ) ); + auto PointSampleFunctor = [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return (*samples)[i]; }; + auto AuxDataSampleFunctor = [&]( size_t i ) -> const typename Reconstructor::Implicit< Real , Dim , UIntPack< FEMSigs... > , AuxData... >::InternalAuxData & { return (*sampleNormalAndAuxData)[i].template get<1>(); }; + implicit._auxData = new SparseNodeData< ProjectiveData< InternalAuxData , Real > , IsotropicUIntPack< Dim , DataSig > > + ( + implicit.tree.template setExtrapolatedDataField< DataSig , false , Reconstructor::WeightDegree , InternalAuxData > + ( + samples->size() , + PointSampleFunctor , + AuxDataSampleFunctor , + (typename Reconstructor::Implicit< Real , Dim , UIntPack< FEMSigs... > , AuxData... >::DensityEstimator*)nullptr + ) + ); + auto nodeFunctor = [&]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *n ) + { + ProjectiveData< InternalAuxData , Real >* clr = (*implicit._auxData)( n ); + if( clr ) (*clr) *= (Real)pow( (Real)params.perLevelDataScaleFactor , implicit.tree.depth( n ) ); + }; + implicit.tree.tree().processNodes( nodeFunctor ); if( params.verbose ) std::cout << "# Got aux data: " << profiler << std::endl; } + delete sampleNormalAndAuxData; // Add the interpolation constraints @@ -962,10 +976,10 @@ namespace PoissonRecon typename FEMTree< Dim , Real >::template HasNormalDataFunctor< NormalSigs > hasNormalDataFunctor( *normalInfo ); auto hasDataFunctor = [&]( const FEMTreeNode *node ){ return hasNormalDataFunctor( node ); }; auto addNodeFunctor = [&]( int d , const int off[Dim] ){ return d<=(int)params.fullDepth; }; - if constexpr( HasAuxData ) + if constexpr( sizeof...(AuxData) ) { - if( geometryNodeDesignators.size() ) implicit.tree.template finalizeForMultigridWithDirichlet< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , [&]( const FEMTreeNode *node ){ return node->nodeData.nodeIndex<(node_index_type)geometryNodeDesignators.size() && geometryNodeDesignators[node]==GeometryNodeType::EXTERIOR; } , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density , implicit.auxData , &geometryNodeDesignators ) ); - else implicit.tree.template finalizeForMultigrid < MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density , implicit.auxData ) ); + if( geometryNodeDesignators.size() ) implicit.tree.template finalizeForMultigridWithDirichlet< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , [&]( const FEMTreeNode *node ){ return node->nodeData.nodeIndex<(node_index_type)geometryNodeDesignators.size() && geometryNodeDesignators[node]==GeometryNodeType::EXTERIOR; } , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density , implicit._auxData , &geometryNodeDesignators ) ); + else implicit.tree.template finalizeForMultigrid < MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density , implicit._auxData ) ); } else { @@ -1060,20 +1074,25 @@ namespace PoissonRecon } } delete samples; + return implicitPtr; } - template< bool HasAuxData , typename Real , unsigned int Dim , unsigned int FEMSig , typename AuxData , typename InputOrientedSampleStreamType , unsigned int ... FEMSigs > - void SSD::_Solve( UIntPack< FEMSigs ... > , typename std::conditional< HasAuxData , Reconstructor::Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type &implicit , InputOrientedSampleStreamType &pointStream , SolutionParameters< Real > params ) + // Implementation of the derived Poisson::Implicit's constructor + template< typename Real , unsigned int Dim , unsigned int ... FEMSigs , typename ... AuxData > + Implicit< Real , Dim , UIntPack< FEMSigs... > , AuxData... > *SSD::Solver< Real , Dim , UIntPack< FEMSigs... > , AuxData... >::Solve( InputOrientedSampleStream< Real , Dim , AuxData... > &pointStream , SolutionParameters< Real > params , AuxData ... zero ) { - static_assert( std::is_same< IsotropicUIntPack< Dim , FEMSig > , UIntPack< FEMSigs... > >::value , "[ERROR] Signatures don't match" ); + Implicit< Real , Dim , UIntPack< FEMSigs... > , AuxData... > *implicitPtr = new Implicit< Real , Dim , UIntPack< FEMSigs... > , AuxData... >( zero... ); + Implicit< Real , Dim , UIntPack< FEMSigs... > , AuxData... > &implicit = *implicitPtr; // The signature for the finite-elements representing the auxiliary data (if it's there) static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; /////////////// // Types --> // - // The packed finite elements signature - typedef UIntPack< FEMSigs ... > Sigs; + using InternalAuxData = typename Reconstructor::Implicit< Real , Dim , UIntPack< FEMSigs... > , AuxData... >::InternalAuxData; + using InternalNormalAndAuxData = typename Reconstructor::Implicit< Real , Dim , UIntPack< FEMSigs... > , AuxData... >::InternalNormalAndAuxData; + using _SampleTypeConverter = typename Reconstructor::Implicit< Real , Dim , UIntPack< FEMSigs... > , AuxData... >::_SampleTypeConverter; + using Sigs = typename Reconstructor::Implicit< Real , Dim , UIntPack< FEMSigs... > , AuxData... >::Sigs; // The degrees of the finite elements across the different axes typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > Degrees; @@ -1086,18 +1105,9 @@ namespace PoissonRecon // The finite-element tracking tree node typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; - - // The type of the auxiliary information (including the normal) - typedef typename std::conditional< HasAuxData , DirectSum< Real , Normal< Real , Dim > , AuxData > , Normal< Real , Dim > >::type NormalAndAuxData; - - // The type describing the sampling density - typedef typename std::conditional< HasAuxData , Implicit< Real , Dim , FEMSig , AuxData > , Implicit< Real , Dim , FEMSig > >::type::DensityEstimator DensityEstimator; // <-- Types // /////////////// - NormalAndAuxData zeroNormalAndAuxData; - if constexpr( HasAuxData ) zeroNormalAndAuxData = NormalAndAuxData( Normal< Real , Dim >() , implicit.zeroAuxData ); - XForm< Real , Dim+1 > modelToUnitCube = XForm< Real , Dim+1 >::Identity(); Profiler profiler( ProfilerMS ); @@ -1107,7 +1117,7 @@ namespace PoissonRecon ProjectiveData< Point< Real , 2 > , Real > pointDepthAndWeight; SparseNodeData< Point< Real , Dim > , NormalSigs > *normalInfo = NULL; std::vector< typename FEMTree< Dim , Real >::PointSample > *samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); - std::vector< NormalAndAuxData > *sampleNormalAndAuxData = NULL; + std::vector< InternalNormalAndAuxData > *sampleNormalAndAuxData = nullptr; Real targetValue = (Real)0.0; @@ -1116,10 +1126,8 @@ namespace PoissonRecon profiler.reset(); pointStream.reset(); - sampleNormalAndAuxData = new std::vector< NormalAndAuxData >(); - - if constexpr( HasAuxData ) modelToUnitCube = params.scale>0 ? PointExtent::GetXForm< Real , Dim , true , Point< Real , Dim > , AuxData >( pointStream , Point< Real , Dim >() , implicit.zeroAuxData , params.scale , params.alignDir ) * modelToUnitCube : modelToUnitCube; - else modelToUnitCube = params.scale>0 ? PointExtent::GetXForm< Real , Dim , true , Point< Real , Dim > >( pointStream , Point< Real , Dim >() , params.scale , params.alignDir ) * modelToUnitCube : modelToUnitCube; + sampleNormalAndAuxData = new std::vector< InternalNormalAndAuxData >(); + modelToUnitCube = params.scale>0 ? PointExtent::GetXForm< Real , Dim , true , Normal< Real , Dim > , AuxData... >( pointStream , Normal< Real , Dim >() , zero... , params.scale , params.alignDir ) * modelToUnitCube : modelToUnitCube; pointStream.reset(); if( params.width>0 ) @@ -1152,59 +1160,55 @@ namespace PoissonRecon params.kernelDepth = params.depth; } - if constexpr( HasAuxData ) { - TransformedInputOrientedSampleStream< Real , Dim , AuxData > _pointStream( modelToUnitCube , pointStream ); - auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , NormalAndAuxData &d ) + // Apply the transformation + TransformedInputOrientedSampleStream< Real , Dim , AuxData... > _pointStream( modelToUnitCube , pointStream ); + + // Convert: + // InputDataStream< Position< Real , Dim > , Normal< Real , Dim > , AuxData ... > + // -> InputDataStream< Position< Real , Dim > , InternalNormalAndAuxData > + InputDataStreamConverter< typename _SampleTypeConverter::InternalSampleType , typename _SampleTypeConverter::ExternalSampleType > __pointStream( _pointStream , _SampleTypeConverter::ConvertI2X , Position< Real , Dim >() , Normal< Real , Dim >() , zero... ); + + std::vector< node_index_type > nodeToIndexMap; + + auto IsValid = [&]( const Point< Real , Dim > &p , const Normal< Real , Dim > &n , AuxData ... d ) { - Real l = (Real)Length( d.template get<0>() ); - if( !l || !std::isfinite( l ) ) return (Real)-1.; - return (Real)pow( l , params.confidence ); + Real l = Point< Real , Dim >::SquareNorm( n ); + return l>0 && std::isfinite(l); }; - auto ProcessData = []( const Point< Real , Dim > &p , NormalAndAuxData &d ) + + auto Process = [&]( FEMTreeNode &node , const Point< Real , Dim > &p , Normal< Real , Dim > &n , AuxData ... d ) { - Real l = (Real)Length( d.template get<0>() ); - if( !l || !std::isfinite( l ) ) return (Real)-1.; - d.template get<0>() /= l; - return (Real)1.; - }; + Real l = (Real)Length( n ); + Real weight = params.confidence>0 ? pow( l , params.confidence ) : (Real)1.; + n /= l; - { - using ExternalType = std::tuple< Point< Real , Dim > , NormalAndAuxData >; - using InternalType = std::tuple< Point< Real , Dim > , Point< Real , Dim > , AuxData >; - auto converter = []( const InternalType &iType ) + node_index_type nodeIndex = node.nodeData.nodeIndex; + // If the node's index exceeds what's stored in the node-to-index map, grow the node-to-index map + if( nodeIndex>=(node_index_type)nodeToIndexMap.size() ) nodeToIndexMap.resize( nodeIndex+1 , -1 ); + + node_index_type idx = nodeToIndexMap[ nodeIndex ]; + if( idx==-1 ) { - ExternalType xType; - std::get< 0 >( xType ) = std::get< 0 >( iType ); - std::get< 1 >( xType ).template get<0>() = std::get< 1 >( iType ); - std::get< 1 >( xType ).template get<1>() = std::get< 2 >( iType ); - return xType; - }; - InputDataStreamConverter< InternalType , ExternalType > __pointStream( _pointStream , converter , Point< Real , Dim >() , Point< Real , Dim >() , implicit.zeroAuxData ); - if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( implicit.tree.spaceRoot() , __pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( implicit.tree.spaceRoot() , __pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); - } - } - else - { - TransformedInputOrientedSampleStream< Real , Dim > _pointStream( modelToUnitCube , pointStream ); - auto ProcessDataWithConfidence = [&]( const Point< Real , Dim > &p , NormalAndAuxData &d ) - { - Real l = (Real)Length( d ); - if( !l || !std::isfinite( l ) ) return (Real)-1.; - return (Real)pow( l , params.confidence ); + idx = (node_index_type)samples->size(); + nodeToIndexMap[ nodeIndex ] = idx; + samples->resize( idx+1 ) , (*samples)[idx].node = &node; + sampleNormalAndAuxData->resize( idx+1 ); + (*samples)[idx].sample = ProjectiveData< Point< Real , Dim > , Real >( p*weight , weight ); + (*sampleNormalAndAuxData)[idx] = InternalNormalAndAuxData( n , DirectSum< Real , AuxData... >( d... ) ) * weight; + } + else + { + (*samples)[idx].sample += ProjectiveData< Point< Real , Dim > , Real >( p*weight , weight ); + (*sampleNormalAndAuxData)[idx] += InternalNormalAndAuxData( n , DirectSum< Real , AuxData... >( d... ) ) * weight; + } + return true; }; - auto ProcessData = []( const Point< Real , Dim > &p , NormalAndAuxData &d ) + auto F = [&]( AuxData ... zeroAuxData ) { - Real l = (Real)Length( d ); - if( !l || !std::isfinite( l ) ) return (Real)-1.; - d /= l; - return (Real)1.; + pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< decltype(IsValid) , decltype(Process) , Normal< Real , Dim > , AuxData... >( implicit.tree.spaceRoot() , _pointStream , Normal< Real , Dim >() , zeroAuxData... , params.depth , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : nullptr , implicit.tree.initializer() , IsValid , Process ); }; - - typename FEMTreeInitializer< Dim , Real >::StreamInitializationData sid; - if( params.confidence>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessDataWithConfidence ); - else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< NormalAndAuxData >( implicit.tree.spaceRoot() , _pointStream , zeroNormalAndAuxData , params.depth , *samples , *sampleNormalAndAuxData , implicit.tree.nodeAllocators.size() ? implicit.tree.nodeAllocators[0] : NULL , implicit.tree.initializer() , ProcessData ); + implicit._zeroAuxData.process( F ); } implicit.unitCubeToModel = modelToUnitCube.inverse(); @@ -1233,53 +1237,20 @@ namespace PoissonRecon { profiler.reset(); normalInfo = new SparseNodeData< Point< Real , Dim > , NormalSigs >(); - std::function< bool ( NormalAndAuxData , Point< Real , Dim > & ) > ConversionFunction; - std::function< bool ( NormalAndAuxData , Point< Real , Dim > & , Real & ) > ConversionAndBiasFunction; - if constexpr( HasAuxData ) - { - ConversionFunction = []( NormalAndAuxData in , Point< Real , Dim > &out ) - { - Point< Real , Dim > n = in.template get<0>(); - Real l = (Real)Length( n ); - // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... - if( !l ) return false; - out = n / l; - return true; - }; - ConversionAndBiasFunction = [&]( NormalAndAuxData in , Point< Real , Dim > &out , Real &bias ) - { - Point< Real , Dim > n = in.template get<0>(); - Real l = (Real)Length( n ); - // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... - if( !l ) return false; - out = n / l; - bias = (Real)( log( l ) * params.confidenceBias / log( 1<<(Dim-1) ) ); - return true; - }; - } - else - { - // In this case NormalAndAuxData = Point< Real , Dim > - ConversionFunction = []( NormalAndAuxData in , Point< Real , Dim > &out ) - { - Real l = (Real)Length( in ); - // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... - if( !l ) return false; - out = in / l; - return true; - }; - ConversionAndBiasFunction = [&]( NormalAndAuxData in , Point< Real , Dim > &out , Real &bias ) - { - Real l = (Real)Length( in ); - // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... - if( !l ) return false; - out = in / l; - bias = (Real)( log( l ) * params.confidenceBias / log( 1<<(Dim-1) ) ); - return true; - }; - } - if( params.confidenceBias>0 ) *normalInfo = implicit.tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , implicit.density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionAndBiasFunction ); - else *normalInfo = implicit.tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , implicit.density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionFunction ); + + std::function< bool ( InternalNormalAndAuxData , Point< Real , Dim > & ) > ConversionFunction; + std::function< bool ( InternalNormalAndAuxData , Point< Real , Dim > & , Real & ) > ConversionAndBiasFunction; + ConversionFunction = []( InternalNormalAndAuxData in , Normal< Real , Dim > &out ) + { + Normal< Real , Dim > n = in.template get<0>(); + Real l = (Real)Length( n ); + // It is possible that the samples have non-zero normals but there are two co-located samples with negative normals... + if( !l ) return false; + out = n / l; + return true; + }; + *normalInfo = implicit.tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , implicit.density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionFunction ); + if( params.verbose ) { std::cout << "# Got normal field: " << profiler << std::endl; @@ -1287,28 +1258,35 @@ namespace PoissonRecon } } - if( !params.outputDensity ){ delete implicit.density ; implicit.density = NULL; } - if constexpr( HasAuxData ) + if constexpr( sizeof...(AuxData) ) { profiler.reset(); - implicit.auxData = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( implicit.tree.template setExtrapolatedDataField< DataSig , false , Reconstructor::WeightDegree , AuxData >( samples->size() , [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return (*samples)[i]; } , [&]( size_t i ) -> const AuxData & { return (*sampleNormalAndAuxData)[i].template get<1>(); } , (DensityEstimator*)NULL ) ); + auto PointSampleFunctor = [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return (*samples)[i]; }; + auto AuxDataSampleFunctor = [&]( size_t i ) -> const typename Reconstructor::Implicit< Real , Dim , UIntPack< FEMSigs... > , AuxData... >::InternalAuxData & { return (*sampleNormalAndAuxData)[i].template get<1>(); }; + implicit._auxData = new SparseNodeData< ProjectiveData< InternalAuxData , Real > , IsotropicUIntPack< Dim , DataSig > > + ( + implicit.tree.template setExtrapolatedDataField< DataSig , false , Reconstructor::WeightDegree , InternalAuxData > + ( + samples->size() , + PointSampleFunctor , + AuxDataSampleFunctor , + (typename Reconstructor::Implicit< Real , Dim , UIntPack< FEMSigs... > , AuxData... >::DensityEstimator*)nullptr + ) + ); + auto nodeFunctor = [&]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *n ) + { + ProjectiveData< InternalAuxData , Real >* clr = (*implicit._auxData)( n ); + if( clr ) (*clr) *= (Real)pow( (Real)params.perLevelDataScaleFactor , implicit.tree.depth( n ) ); + }; + implicit.tree.tree().processNodes( nodeFunctor ); if( params.verbose ) std::cout << "# Got aux data: " << profiler << std::endl; } - // Add the interpolation constraints if( params.pointWeight>0 || params.gradientWeight>0 ) { profiler.reset(); - if constexpr( HasAuxData ) - { - if( params.exactInterpolation ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , NormalAndAuxData , 1 >( implicit.tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real , AuxData >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real , AuxData >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , false ); - else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , NormalAndAuxData , 1 >( implicit.tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real , AuxData >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real , AuxData >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , params.depth , 1 ); - } - else - { - if( params.exactInterpolation ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , Point< Real , Dim > , 1 >( implicit.tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , false ); - else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , Point< Real , Dim > , 1 >( implicit.tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , params.depth , 1 ); - } + if( params.exactInterpolation ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , InternalNormalAndAuxData , 1 >( implicit.tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real , AuxData... >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real , AuxData... >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , false ); + else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , InternalNormalAndAuxData , 1 >( implicit.tree , *samples , GetPointer( *sampleNormalAndAuxData ) , SSD::ConstraintDual< Dim , Real , AuxData... >( targetValue , params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , SSD::SystemDual< Dim , Real , AuxData... >( params.pointWeight * pointDepthAndWeight.value()[1] , params.gradientWeight * pointDepthAndWeight.value()[1] ) , true , params.depth , 1 ); if( params.verbose ) std::cout << "#Initialized point interpolation constraints: " << profiler << std::endl; } @@ -1322,7 +1300,7 @@ namespace PoissonRecon typename FEMTree< Dim , Real >::template HasNormalDataFunctor< NormalSigs > hasNormalDataFunctor( *normalInfo ); auto hasDataFunctor = [&]( const FEMTreeNode *node ){ return hasNormalDataFunctor( node ); }; auto addNodeFunctor = [&]( int d , const int off[Dim] ){ return d<=(int)params.fullDepth; }; - if constexpr( HasAuxData ) implicit.tree.template finalizeForMultigrid< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density , implicit.auxData ) ); + if constexpr( sizeof...(AuxData) ) implicit.tree.template finalizeForMultigrid< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density , implicit._auxData ) ); else implicit.tree.template finalizeForMultigrid< MaxDegree , Degrees::Max() >( params.baseDepth , addNodeFunctor , hasDataFunctor , std::make_tuple( iInfo ) , std::make_tuple( normalInfo , implicit.density ) ); if( params.verbose ) std::cout << "# Finalized tree: " << profiler << std::endl; @@ -1376,6 +1354,7 @@ namespace PoissonRecon } } delete samples; + return implicitPtr; } } } diff --git a/Src/SSDRecon.cpp b/Src/SSDRecon.cpp index a1c107aa..bd96ec75 100644 --- a/Src/SSDRecon.cpp +++ b/Src/SSDRecon.cpp @@ -97,7 +97,6 @@ CmdLineParameter< float > Scale( "scale" , 1.1f ) , Width( "width" , 0.f ) , Confidence( "confidence" , 0.f ) , - ConfidenceBias( "confidenceBias" , 0.f ) , LowDepthCutOff( "lowDepthCutOff" , 0.f ) , CGSolverAccuracy( "cgAccuracy" , 1e-3f ) , ValueWeight ( "valueWeight" , 1.f ) , @@ -115,7 +114,6 @@ CmdLineReadable* params[] = &Width , &Scale , &Verbose , &CGSolverAccuracy , &KernelDepth , &SamplesPerNode , &Confidence , &NonManifold , &PolygonMesh , &ASCII , &ShowResidual , - &ConfidenceBias , &ValueWeight , &GradientWeight , &BiLapWeight , &Grid , &Tree , @@ -176,7 +174,6 @@ void ShowUsage(char* ex) for( size_t i=0 ; i=%d]\n" , ThreadChunkSize.name , ThreadChunkSize.value ); printf( "\t[--%s =%f]\n" , Confidence.name , Confidence.value ); - printf( "\t[--%s =%f]\n" , ConfidenceBias.name , ConfidenceBias.value ); printf( "\t[--%s =%f]\n" , LowDepthCutOff.name , LowDepthCutOff.value ); printf( "\t[--%s =%d]\n" , AlignmentDir.name , AlignmentDir.value ); printf( "\t[--%s]\n" , NonManifold.name ); @@ -197,7 +194,7 @@ void ShowUsage(char* ex) template< typename Real , unsigned int Dim , unsigned int FEMSig , bool HasGradients , bool HasDensity , bool InCore , typename ... AuxDataFactories > void WriteMesh ( - Reconstructor::Implicit< Real , Dim , FEMSig , typename AuxDataFactories::VertexType ... > &implicit , + Reconstructor::Implicit< Real , Dim , IsotropicUIntPack< Dim , FEMSig > , typename AuxDataFactories::VertexType ... > &implicit , const Reconstructor::LevelSetExtractionParameters &meParams , std::string fileName , bool ascii , @@ -226,7 +223,7 @@ template< typename Real , unsigned int Dim , unsigned int FEMSig , bool HasDensi void WriteMesh ( bool hasGradients , - Reconstructor::Implicit< Real , Dim , FEMSig , typename AuxDataFactories::VertexType ... > &implicit , + Reconstructor::Implicit< Real , Dim , IsotropicUIntPack< Dim , FEMSig > , typename AuxDataFactories::VertexType ... > &implicit , const Reconstructor::LevelSetExtractionParameters &meParams , std::string fileName , bool ascii , @@ -241,7 +238,7 @@ template< typename Real , unsigned int Dim , unsigned int FEMSig , bool InCore , void WriteMesh ( bool hasGradients , bool hasDensity , - Reconstructor::Implicit< Real , Dim , FEMSig , typename AuxDataFactories::VertexType ... > &implicit , + Reconstructor::Implicit< Real , Dim , IsotropicUIntPack< Dim , FEMSig > , typename AuxDataFactories::VertexType ... > &implicit , const Reconstructor::LevelSetExtractionParameters &meParams , std::string fileName , bool ascii , @@ -256,7 +253,7 @@ template< typename Real , unsigned int Dim , unsigned int FEMSig , typename ... void WriteMesh ( bool hasGradients , bool hasDensity , bool inCore , - Reconstructor::Implicit< Real , Dim , FEMSig , typename AuxDataFactories::VertexType ... > &implicit , + Reconstructor::Implicit< Real , Dim , IsotropicUIntPack< Dim , FEMSig > , typename AuxDataFactories::VertexType ... > &implicit , const Reconstructor::LevelSetExtractionParameters &meParams , std::string fileName , bool ascii , @@ -278,7 +275,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) using namespace VertexFactory; // The factory for constructing an input sample's data - typedef typename std::conditional< HasAuxData , Factory< Real , NormalFactory< Real , Dim > , AuxDataFactory > , NormalFactory< Real , Dim > >::type InputSampleDataFactory; + typedef std::conditional_t< HasAuxData , Factory< Real , NormalFactory< Real , Dim > , AuxDataFactory > , NormalFactory< Real , Dim > > InputSampleDataFactory; // The factory for constructing an input sample typedef Factory< Real , PositionFactory< Real , Dim > , InputSampleDataFactory > InputSampleFactory; @@ -286,7 +283,8 @@ void Execute( const AuxDataFactory &auxDataFactory ) typedef InputDataStream< typename InputSampleFactory::VertexType > InputPointStream; // The type storing the reconstruction solution (depending on whether auxiliary data is provided or not) - using Implicit = typename std::conditional< HasAuxData , Reconstructor::SSD::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType > , Reconstructor::SSD::Implicit< Real , Dim , FEMSig > >::type; + using Implicit = std::conditional_t< HasAuxData , Reconstructor::Implicit< Real , Dim , IsotropicUIntPack< Dim , FEMSig > , typename AuxDataFactory::VertexType > , Reconstructor::Implicit< Real , Dim , IsotropicUIntPack< Dim , FEMSig > > >; + using Solver = std::conditional_t< HasAuxData , Reconstructor::SSD::Solver< Real , Dim , IsotropicUIntPack< Dim , FEMSig > , typename AuxDataFactory::VertexType > , Reconstructor::SSD::Solver< Real , Dim , IsotropicUIntPack< Dim , FEMSig > > >; // <-- Types // /////////////// @@ -313,12 +311,10 @@ void Execute( const AuxDataFactory &auxDataFactory ) Reconstructor::LevelSetExtractionParameters meParams; sParams.verbose = Verbose.set; - sParams.outputDensity = Density.set; sParams.exactInterpolation = ExactInterpolation.set; sParams.showResidual = ShowResidual.set; sParams.scale = (Real)Scale.value; sParams.confidence = (Real)Confidence.value; - sParams.confidenceBias = (Real)ConfidenceBias.value; sParams.lowDepthCutOff = (Real)LowDepthCutOff.value; sParams.width = (Real)Width.value; sParams.pointWeight = (Real)ValueWeight.value; @@ -326,6 +322,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) sParams.biLapWeight = (Real)BiLapWeight.value; sParams.samplesPerNode = (Real)SamplesPerNode.value; sParams.cgSolverAccuracy = (Real)CGSolverAccuracy.value; + sParams.perLevelDataScaleFactor = (Real)DataX.value; sParams.depth = (unsigned int)Depth.value; sParams.baseDepth = (unsigned int)BaseDepth.value; sParams.solveDepth = (unsigned int)SolveDepth.value; @@ -340,6 +337,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) meParams.forceManifold = !NonManifold.set; meParams.polygonMesh = PolygonMesh.set; meParams.gridCoordinates = GridCoordinates.set; + meParams.outputDensity = Density.set; meParams.verbose = Verbose.set; double startTime = Time(); @@ -456,10 +454,10 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( Transform.set ) { Reconstructor::TransformedInputOrientedSampleStream< Real , Dim , typename AuxDataFactory::VertexType > _sampleStream( toModel , sampleStream ); - implicit = new Reconstructor::SSD::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( _sampleStream , sParams , auxDataFactory() ); + implicit = Solver::Solve( _sampleStream , sParams , auxDataFactory() ); implicit->unitCubeToModel = toModel.inverse() * implicit->unitCubeToModel; } - else implicit = new Reconstructor::SSD::Implicit< Real , Dim , FEMSig , typename AuxDataFactory::VertexType >( sampleStream , sParams , auxDataFactory() ); + else implicit = Solver::Solve( sampleStream , sParams , auxDataFactory() ); } else { @@ -468,17 +466,15 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( Transform.set ) { Reconstructor::TransformedInputOrientedSampleStream< Real , Dim > _sampleStream( toModel , sampleStream ); - implicit = new Reconstructor::SSD::Implicit< Real , Dim , FEMSig >( _sampleStream , sParams ); + implicit = Solver::Solve( _sampleStream , sParams ); implicit->unitCubeToModel = toModel.inverse() * implicit->unitCubeToModel; } - else implicit = new Reconstructor::SSD::Implicit< Real , Dim , FEMSig >( sampleStream , sParams ); + else implicit = Solver::Solve( sampleStream , sParams ); } delete pointStream; delete _inputSampleFactory; - if constexpr( HasAuxData ) if( implicit->auxData ) implicit->weightAuxDataByDepth( (Real)DataX.value ); - if( Tree.set ) { FILE* fp = fopen( Tree.value , "wb" ); @@ -486,10 +482,9 @@ void Execute( const AuxDataFactory &auxDataFactory ) FileStream fs(fp); FEMTree< Dim , Real >::WriteParameter( fs ); DenseNodeData< Real , Sigs >::WriteSignatures( fs ); - implicit->tree.write( fs , implicit->unitCubeToModel.inverse() , false ); + implicit->tree.write( fs , false ); + fs.write( implicit->unitCubeToModel.inverse() ); implicit->solution.write( fs ); - if constexpr( HasAuxData ) if( implicit->auxData ) implicit->auxData->write( fs ); - if( implicit->density ) implicit->density->write( fs ); fclose( fp ); } From 913f13b9051740daf392942fecafbd98ef64d80f Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Wed, 30 Oct 2024 12:14:32 -0400 Subject: [PATCH 62/86] Version 18.40 --- README.md | 42 ++++++++++++++++++++++---------------- Src/Extrapolator.h | 21 ++++++++++++++++++- Src/FEMTree.Evaluation.inl | 32 +++++++++++++++++++++++++++-- Src/FEMTree.h | 12 +++++++++-- Src/PoissonRecon.cpp | 4 ---- Src/PreProcessor.h | 2 +- Src/Reconstructors.h | 35 ++++--------------------------- 7 files changed, 89 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 46e304f3..eac98d5f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

      Adaptive Multigrid Solvers (Version 18.35)

      +

      Adaptive Multigrid Solvers (Version 18.40)

      links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
      Executables: -Win64
      +Win64
      Source Code: -ZIP GitHub
      +ZIP GitHub
      Older Versions: +V18.35, V18.31, V18.30, V18.20, @@ -1054,11 +1055,11 @@ If both the --keep flag and the --fraction flag are set, the -- In addition to executables, the reconstruction code can be interfaced into through the functionality implemented in Reconstructors.h and Extrapolator.h Using the functionality requires requires choosing a finite element type and defining input oriented-point stream and output vertex and face streams. In the descriptions below, the template parameter Real is the floating point type used to represent data (typically float) and Dim is the integer dimension of the space (fixed at Dim=3).
        -
      • The template parameter FEMSig describes the 1D finite element type, which is a composite of the degree of the finite element and the boundary conditions it satisfies. Given an integer valued Degree and boundary type BType (one of BOUNDARY_FREE, BOUNDARY_DIRICHLET, and BOUNDARY_NEUMANN defined in BSplineData.h), the signature is defined as (Reconstruction.example.cppy line 308): +
      • The template parameter FEMSig describes the 1D finite element type, which is a composite of the degree of the finite element and the boundary conditions it satisfies. Given an integer valued Degree and boundary type BType (one of BOUNDARY_FREE, BOUNDARY_DIRICHLET, and BOUNDARY_NEUMANN defined in BSplineData.h), the signature is defined as:
         static const unsigned int FEMSig = FEMDegreeAndBType< Degree , BoundaryType >::Signature;
         
        -
      • The template parameter FEMSIgs describes the tensor-product finite element type, typically defined as an "isotropic" element with the same 1D finite element type across all Dim dimensions. It is defined as (Reconstruction.example.cppy line 314): +
      • The template parameter FEMSIgs describes the tensor-product finite element type, typically defined as an "isotropic" element with the same 1D finite element type across all Dim dimensions. It is defined as:
         using FEMSigs = IsotropicUIntPack< Dim , FEMSig >;
         
        @@ -1117,22 +1118,22 @@ This method returns the extrapolated value at the prescribed position.
          These steps can be found in the Reconstruction.example.cpp code.
            -
          • The finite-elements signature is created in line 308. -
          • An input sample stream generating a specified number of random points on the surface of the sphere is defined in lines 85-122 and constructed in line 374. -
          • An output polygon stream that pushes the polygon to an std::vector of std::vector< int >s is defined in lines 213-230 and constructed in line 384. -
          • An output vertex stream that pushes just the position information to an std::vector of Reals is desfined in lines 223-244 and constructed in line 385. -
          • The reconstructor is constructed in line 377. -
          • The level-set extraction is performed on line 388. -
          • The evaluator is created on line 334. -
          • The evaluator is used to query the values and gradients of the implicit function in line 327. -
          • The extrapolator is constructed on line 406. -
          • The extrapolator is evaluated at the vertex positions at line 416. +
          • The finite-elements signatures are created in lines 308 and 311. +
          • An input sample stream generating a specified number of random points on the surface of the sphere is defined in lines 85-122 and constructed in line 379. +
          • An output polygon stream that pushes the polygon to an std::vector of std::vector< int >s is defined in lines 213-230 and constructed in line 389. +
          • An output vertex stream that pushes just the position information to an std::vector of Reals is desfined in lines 223-244 and constructed in line 390. +
          • The implicit representation is computed in line 382. +
          • The level-set extraction is performed on line 393. +
          • The evaluator is created on line 340. +
          • The evaluator is used to query the values and gradients of the implicit function in line 333. +
          • The extrapolator is constructed on line 411. +
          • The extrapolator is evaluated at the vertex positions at line 421.
          -Note that a similar approach can be used to perform the Smoothed Signed Distance reconstruction (lines 452 and 453).
          +Note that a similar approach can be used to perform the Smoothed Signed Distance reconstruction (lines 459 and 460).
          The approach also supports reconstruction of meshes with auxiliary information like color, with the only constraint that the auxiliary data type supports the computation affine combinations (e.g. the RGBColor type defined in lines 67-82). The auxiliary inform is derived in one of two ways:
            -
          1. As part of the reconstruction process, so that the level-set extraction phase also sets the auxiliary information. (Lines 343-470) -
          2. Independently by constructing the extrapolation field from the samples and then evaluating at the positions of the level-set vertices. (Lines 397-418) +
          3. As part of the reconstruction process, so that the level-set extraction phase also sets the auxiliary information. (Lines 349-375) +
          4. Independently by constructing the extrapolation field from the samples and then evaluating at the positions of the level-set vertices. (Lines 400-427)
        @@ -1712,6 +1713,11 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
      • Removed the confidence bias option. +Version 18.40: +
          +
        1. Added support for extrapolator accumulation. +
        +
        diff --git a/Src/Extrapolator.h b/Src/Extrapolator.h index 4b541644..0ba3871c 100644 --- a/Src/Extrapolator.h +++ b/Src/Extrapolator.h @@ -98,8 +98,10 @@ namespace PoissonRecon XForm< Real , Dim+1 > worldToUnitCubeTransform( void ) const { return _worldToUnitCube; } AuxData operator()( unsigned int t , Point< Real , Dim > p ){ return _value(t,p); } + AuxData operator()( Point< Real , Dim > p ){ return _value(0,p); } - AuxData operator()( Point< Real , Dim > p ){ return operator()( 0 , p ); } + void evaluate( unsigned int t , Point< Real , Dim > p , AuxData &data ){ return _evaluate( t , p , data ); } + void evaluate( Point< Real , Dim > p , AuxData &data ){ return _evaluate( 0 , p , data ); } protected: typename FEMTree< Dim , Real >::template MultiThreadedSparseEvaluator< IsotropicUIntPack< Dim , DataSig > , ProjectiveData< AuxData , Real > > *_auxEvaluator = nullptr; @@ -113,6 +115,23 @@ namespace PoissonRecon _auxEvaluator->addValue( q , pData ); return pData.value(); } + + void _evaluate( unsigned int t , Point< Real , Dim > p , AuxData &data ) + { + Point< Real , Dim > q = _worldToUnitCube * p; + for( unsigned int d=0 ; d1 ) throw OutOfUnitCubeException(p,q); + + Real weight = (Real)0.; + data *= 0; + + auto Accumulation = [&weight,&data]( const ProjectiveData< AuxData , Real > &pData , Real scale ) + { + weight += pData.weight * scale; + data += pData.data * scale; + }; + _auxEvaluator->accumulate( q , Accumulation ); + if( weight ) data /= weight; + } }; template< typename Real , unsigned int Dim , typename AuxData , unsigned int DataDegree > diff --git a/Src/FEMTree.Evaluation.inl b/Src/FEMTree.Evaluation.inl index 682ebd2c..69e47212 100644 --- a/Src/FEMTree.Evaluation.inl +++ b/Src/FEMTree.Evaluation.inl @@ -550,15 +550,43 @@ void FEMTree< Dim , Real >::MultiThreadedSparseEvaluator< UIntPack< FEMSigs ... _tree->template _addEvaluation< T , SparseNodeData< T , FEMSignatures > , 0 >( _coefficients , p , _tree->_globalToLocal( node->depth() ) , *_pointEvaluator , nKey , t ); } +template< unsigned int Dim , class Real > +template< unsigned int ... FEMSigs , typename T > +template< typename AccumulationFunctor/*=std::function< void ( const T & , Real s ) > */ > +void FEMTree< Dim , Real >::MultiThreadedSparseEvaluator< UIntPack< FEMSigs ... > , T >::accumulate( Point< Real , Dim > p , AccumulationFunctor &Accumulate , int thread , const FEMTreeNode *node ) +{ + if( !node ) node = _tree->leaf( p ); + ConstPointSupportKey< FEMDegrees >& nKey = _pointNeighborKeys[thread]; + nKey.getNeighbors( node ); + _tree->template _accumulate< T , SparseNodeData< T , FEMSignatures > , 0 , AccumulationFunctor >( _coefficients , p , _tree->_globalToLocal( node->depth() ) , *_pointEvaluator , nKey , Accumulate ); +} + template< unsigned int Dim , class Real > template< class V , class Coefficients , unsigned int D , unsigned int ... DataSigs > void FEMTree< Dim , Real >::_addEvaluation( const Coefficients& coefficients , Point< Real , Dim > p , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , V &value ) const { - _addEvaluation< V , Coefficients , D , DataSigs ... >( coefficients , p , _globalToLocal( dataKey.depth() ) , pointEvaluator , dataKey , value ); + auto AF = [&value]( const V &w , Real s ){ value += w * s; }; + _accumulate< V , Coefficients , D , decltype(AF) , DataSigs ... >( coefficients , p , pointEvaluator , dataKey , AF ); } + template< unsigned int Dim , class Real > template< class V , class Coefficients , unsigned int D , unsigned int ... DataSigs > void FEMTree< Dim , Real >::_addEvaluation( const Coefficients& coefficients , Point< Real , Dim > p , LocalDepth pointDepth , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , V &value ) const +{ + auto AF = [&value]( const V &w , Real s ){ value += w * s; }; + _accumulate< V , Coefficients , D , decltype(AF) , DataSigs... >( coefficients , p , pointDepth , pointEvaluator , dataKey , AF ); +} + +template< unsigned int Dim , class Real > +template< typename V , typename Coefficients , unsigned int D , typename AccumulationFunctor , unsigned int ... DataSigs > +void FEMTree< Dim , Real >::_accumulate( const Coefficients& coefficients , Point< Real , Dim > p , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , AccumulationFunctor &Accumulate ) const +{ + _accumulate< V , Coefficients , D , AccumulationFunctor , DataSigs ... >( coefficients , p , _globalToLocal( dataKey.depth() ) , pointEvaluator , dataKey , Accumulate ); +} + +template< unsigned int Dim , class Real > +template< typename V , typename Coefficients , unsigned int D , typename AccumulationFunctor , unsigned int ... DataSigs > +void FEMTree< Dim , Real >::_accumulate( const Coefficients& coefficients , Point< Real , Dim > p , LocalDepth pointDepth , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , AccumulationFunctor &Accumulate ) const { typedef UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportSize ... > SupportSizes; PointEvaluatorState< UIntPack< DataSigs ... > , ZeroUIntPack< Dim > > state; @@ -582,7 +610,7 @@ void FEMTree< Dim , Real >::_addEvaluation( const Coefficients& coefficients , P if( v ) { LocalDepth d ; LocalOffset off ; _localDepthAndOffset( nodes[i] , d , off ); - value += (*v) * (Real)state.value( off , derivatives ); + Accumulate( *v , (Real)state.value( off , derivatives ) ); } } } diff --git a/Src/FEMTree.h b/Src/FEMTree.h index 129c192c..42d9b1bf 100644 --- a/Src/FEMTree.h +++ b/Src/FEMTree.h @@ -2302,8 +2302,14 @@ namespace PoissonRecon template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > Point< Real , 2 > _splatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >& densityWeights , Real minDepthCutoff , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , LocalDepth minDepth , std::function< int ( Point< Real , Dim > ) > &pointDepthFunctor , int dim , Real depthBias ); template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > Point< Real , 2 > _multiSplatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >* densityWeights , FEMTreeNode* node , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , int dim ); template< unsigned int WeightDegree , class V , unsigned int ... DataSigs > Real _nearestMultiSplatPointData( const DensityEstimator< WeightDegree >* densityWeights , FEMTreeNode* node , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , int dim=Dim ); - template< class V , class Coefficients , unsigned int D , unsigned int ... DataSigs > void _addEvaluation( const Coefficients& coefficients , Point< Real , Dim > p , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , V &value ) const; - template< class V , class Coefficients , unsigned int D , unsigned int ... DataSigs > void _addEvaluation( const Coefficients& coefficients , Point< Real , Dim > p , LocalDepth pointDepth , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , V &value ) const; + template< class V , class Coefficients , unsigned int D , unsigned int ... DataSigs > + void _addEvaluation( const Coefficients& coefficients , Point< Real , Dim > p , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , V &value ) const; + template< class V , class Coefficients , unsigned int D , unsigned int ... DataSigs > + void _addEvaluation( const Coefficients& coefficients , Point< Real , Dim > p , LocalDepth pointDepth , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , V &value ) const; + template< typename V , typename Coefficients , unsigned int D , typename AccumulationFunctor /*=std::function< void ( const V & , Real s ) > */ , unsigned int ... DataSigs > + void _accumulate( const Coefficients& coefficients , Point< Real , Dim > p , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , AccumulationFunctor &AF ) const; + template< typename V , typename Coefficients , unsigned int D , typename AccumulationFunctor /*=std::function< void ( const V & , Real s ) > */ , unsigned int ... DataSigs > + void _accumulate( const Coefficients& coefficients , Point< Real , Dim > p , LocalDepth pointDepth , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , AccumulationFunctor &AF ) const; public: @@ -2513,6 +2519,8 @@ namespace PoissonRecon MultiThreadedSparseEvaluator( const FEMTree* tree , const SparseNodeData< T , FEMSignatures >& coefficients , int threads=std::thread::hardware_concurrency() ); ~MultiThreadedSparseEvaluator( void ){ if( _pointEvaluator ) delete _pointEvaluator; } void addValue( Point< Real , Dim > p , T &t , int thread=0 , const FEMTreeNode* node=NULL ); + template< typename AccumulationFunctor/*=std::function< void ( const T & , Real s ) > */ > + void accumulate( Point< Real , Dim > p , AccumulationFunctor &Accumulate , int thread=0 , const FEMTreeNode* node=NULL ); }; protected: diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index 5dbd9058..8f2ec190 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -102,7 +102,6 @@ CmdLineParameter< float > Confidence( "confidence" , 0.f ) , CGSolverAccuracy( "cgAccuracy" , 1e-3f ) , LowDepthCutOff( "lowDepthCutOff" , 0.f ) , - TargetValue( "targetValue" , 0.5f ) , PointWeight( "pointWeight" ); CmdLineReadable* params[] = @@ -140,7 +139,6 @@ CmdLineReadable* params[] = &ThreadChunkSize , &LowDepthCutOff , &AlignmentDir , - &TargetValue , &GridCoordinates , NULL }; @@ -168,7 +166,6 @@ void ShowUsage(char* ex) 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 , Reconstructor::Poisson::WeightMultiplier * Reconstructor::Poisson::DefaultFEMDegree ); - printf( "\t[--%s =%f]\n" , TargetValue.name , TargetValue.value ); printf( "\t[--%s =%d]\n" , Iters.name , Iters.value ); printf( "\t[--%s]\n" , ExactInterpolation.name ); printf( "\t[--%s =%f]\n" , DataX.name , DataX.value ); @@ -327,7 +324,6 @@ void Execute( const AuxDataFactory &auxDataFactory ) sParams.pointWeight = (Real)PointWeight.value; sParams.samplesPerNode = (Real)SamplesPerNode.value; sParams.cgSolverAccuracy = (Real)CGSolverAccuracy.value; - sParams.targetValue = (Real)TargetValue.value; sParams.perLevelDataScaleFactor = (Real)DataX.value; sParams.depth = (unsigned int)Depth.value; sParams.baseDepth = (unsigned int)BaseDepth.value; diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index e5bed381..cb3a233e 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -46,7 +46,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "18.35" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "18.40" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h index 295af8b3..f298d903 100644 --- a/Src/Reconstructors.h +++ b/Src/Reconstructors.h @@ -558,7 +558,7 @@ namespace PoissonRecon DensityEstimator *density = params.outputDensity ? this->density : nullptr; - if constexpr( Dim==3 ) + if constexpr( Dim==2 || Dim==3 ) { Profiler profiler( ProfilerMS ); @@ -579,43 +579,16 @@ namespace PoissonRecon typename LevelSetExtractor< Real , Dim >::Stats stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , tree , density , solution , isoValue , _vertexStream , faceStream , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); statsString = stats.toString(); } - if( params.verbose ) - { - std::cout << "Vertices / Faces: " << vertexStream.size() << " / " << faceStream.size() << std::endl; - std::cout << statsString << std::endl; - std::cout << "# Got Faces: " << profiler << std::endl; - } - } - else if constexpr( Dim==2 ) - { - Profiler profiler( ProfilerMS ); - - std::string statsString; - - TransformedOutputLevelSetVertexStream< Real , Dim , InternalAuxData > _vertexStream( unitCubeToModel , vertexStream ); - if constexpr( sizeof...(AuxData) ) - { - // Convert stream: - // OutputDataStream< Position< Real , Dim > , Gradient< Real , Dim > , Weight< Real > , AuxData... > - // -> OutputDataStream< Position< Real , Dim > , Gradient< Real , Dim > , Weight< Real > , InternalAuxData > - OutputDataStreamConverter< typename _VertexTypeConverter::InternalVertexType , typename _VertexTypeConverter::ExternalVertexType > __vertexStream( _vertexStream , _VertexTypeConverter::ConvertX2I ); - typename LevelSetExtractor< Real , Dim , InternalAuxData >::Stats stats = LevelSetExtractor< Real , Dim , InternalAuxData >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , UIntPack< DataSig >() , tree , density , _auxData , solution , isoValue , __vertexStream , faceStream , _zeroAuxData , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); - statsString = stats.toString(); - } - else - { - typename LevelSetExtractor< Real , Dim >::Stats stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , tree , density , solution , isoValue , _vertexStream , faceStream , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); - statsString = stats.toString(); - } if( params.verbose ) { std::cout << "Vertices / Faces: " << vertexStream.size() << " / " << faceStream.size() << std::endl; std::cout << statsString << std::endl; - std::cout << "# Got faces: " << profiler << std::endl; + std::cout << "# Got Faces: " << profiler << std::endl; } } - else WARN( "Extraction only supported for dimensions 2 and 3" ); } + else WARN( "Extraction only supported for dimensions 2 and 3" ); + } // Implementation of the derived Poisson::Implicit's constructor template< typename Real , unsigned int Dim , unsigned int ... FEMSigs , typename ... AuxData > From b80aa2cfbf4359a0f8c7563e99678f00339eed2a Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Thu, 31 Oct 2024 19:45:02 -0400 Subject: [PATCH 63/86] Version 18.41 --- Src/PreProcessor.h | 2 +- Src/Reconstructors.h | 234 ++++++++++++++++++------------------------ Src/VertexFactory.h | 12 +-- Src/VertexFactory.inl | 109 ++++++++++++-------- 4 files changed, 172 insertions(+), 185 deletions(-) diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index cb3a233e..01dd3cd8 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -46,7 +46,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "18.40" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "18.41" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h index f298d903..5cf556da 100644 --- a/Src/Reconstructors.h +++ b/Src/Reconstructors.h @@ -61,6 +61,77 @@ namespace PoissonRecon LevelSetExtractionParameters( void ) : linearFit(false) , outputGradients(false) , forceManifold(true) , polygonMesh(false) , gridCoordinates(false) , verbose(false) , outputDensity(false) {} }; + // General solver parameters + template< typename Real > + struct SolutionParameters + { + bool verbose; + bool exactInterpolation; + bool showResidual; + Real scale; + Real confidence; + Real lowDepthCutOff; + Real width; + Real samplesPerNode; + Real cgSolverAccuracy; + Real perLevelDataScaleFactor; + unsigned int depth; + unsigned int solveDepth; + unsigned int baseDepth; + unsigned int fullDepth; + unsigned int kernelDepth; + unsigned int baseVCycles; + unsigned int iters; + unsigned int alignDir; + + SolutionParameters( void ) : + verbose(false) , exactInterpolation(false) , showResidual(false) , + scale((Real)1.1) ,confidence((Real)0.) , + lowDepthCutOff((Real)0.) , width((Real)0.) , + samplesPerNode((Real)1.5) , cgSolverAccuracy((Real)1e-3 ) , perLevelDataScaleFactor((Real)32.) , + depth((unsigned int)8) , solveDepth((unsigned int)-1) , baseDepth((unsigned int)-1) , fullDepth((unsigned int)5) , kernelDepth((unsigned int)-1) , + baseVCycles((unsigned int)1) , iters((unsigned int)8) , alignDir(0) + {} + + template< unsigned int Dim > + void testAndSet( XForm< Real , Dim > unitCubeToModel ) + { + if( width>0 ) + { + Real maxScale = 0; + for( unsigned int i=0 ; imaxScale ) maxScale = l2; + } + maxScale = sqrt( maxScale ); + depth = (unsigned int)ceil( std::max< double >( 0. , log( maxScale/width )/log(2.) ) ); + } + + if( solveDepth>depth ) + { + if( solveDepth!=-1 ) WARN( "Solution depth cannot exceed system depth: " , solveDepth , " <= " , depth ); + solveDepth = depth; + } + if( fullDepth>solveDepth ) + { + if( fullDepth!=-1 ) WARN( "Full depth cannot exceed system depth: " , fullDepth , " <= " , solveDepth ); + fullDepth = solveDepth; + } + if( baseDepth>fullDepth ) + { + if( baseDepth!=-1 ) WARN( "Base depth must be smaller than full depth: " , baseDepth , " <= " , fullDepth ); + baseDepth = fullDepth; + } + if( kernelDepth==-1 ) kernelDepth = depth>2 ? depth-2 : 0; + if( kernelDepth>depth ) + { + if( kernelDepth!=-1 ) WARN( "Kernel depth cannot exceed system depth: " , kernelDepth , " <= " , depth ); + kernelDepth = depth; + } + } + }; struct Poisson; struct SSD; @@ -392,39 +463,35 @@ namespace PoissonRecon }; template< typename Real > - struct SolutionParameters + struct SolutionParameters : public Reconstructor::SolutionParameters< Real > { - bool verbose; bool dirichletErode; - bool exactInterpolation; - bool showResidual; - Real scale; - Real confidence; - Real lowDepthCutOff; - Real width; Real pointWeight; Real valueInterpolationWeight; - Real samplesPerNode; - Real cgSolverAccuracy; - Real targetValue; - Real perLevelDataScaleFactor; - unsigned int depth; - unsigned int solveDepth; - unsigned int baseDepth; - unsigned int fullDepth; - unsigned int kernelDepth; unsigned int envelopeDepth; - unsigned int baseVCycles; - unsigned int iters; - unsigned int alignDir; SolutionParameters( void ) : - verbose(false) , dirichletErode(false) , exactInterpolation(false) , showResidual(false) , - scale((Real)1.1) , confidence((Real)0.) , lowDepthCutOff((Real)0.) , width((Real)0.) , - pointWeight((Real)( WeightMultiplier * DefaultFEMDegree ) ) , valueInterpolationWeight((Real)0.) , samplesPerNode((Real)1.5) , cgSolverAccuracy((Real)1e-3 ) , targetValue((Real)0.5) , perLevelDataScaleFactor((Real)32.) , - depth((unsigned int)8) , solveDepth((unsigned int)-1) , baseDepth((unsigned int)-1) , fullDepth((unsigned int)5) , kernelDepth((unsigned int)-1) , - envelopeDepth((unsigned int)-1) , baseVCycles((unsigned int)1) , iters((unsigned int)8) , alignDir(0) + dirichletErode(false) , + pointWeight((Real)( WeightMultiplier * DefaultFEMDegree ) ) , valueInterpolationWeight((Real)0.) , + envelopeDepth((unsigned int)-1) {} + + template< unsigned int Dim > + void testAndSet( XForm< Real , Dim > unitCubeToModel ) + { + Reconstructor::SolutionParameters< Real >::testAndSet( unitCubeToModel ); + if( envelopeDepth==-1 ) envelopeDepth = Reconstructor::SolutionParameters< Real >::baseDepth; + if( envelopeDepth>Reconstructor::SolutionParameters< Real >::depth ) + { + if( envelopeDepth!=-1 ) WARN( "Envelope depth cannot exceed system depth: " , envelopeDepth , " <= " , Reconstructor::SolutionParameters< Real >::depth ); + envelopeDepth = Reconstructor::SolutionParameters< Real >::depth; + } + if( envelopeDepth::baseDepth ) + { + WARN( "Envelope depth cannot be less than base depth: " , envelopeDepth , " >= " , Reconstructor::SolutionParameters< Real >::baseDepth ); + envelopeDepth = Reconstructor::SolutionParameters< Real >::baseDepth; + } + } }; template< typename Real , unsigned int Dim > @@ -500,38 +567,15 @@ namespace PoissonRecon }; template< typename Real > - struct SolutionParameters + struct SolutionParameters : public Reconstructor::SolutionParameters< Real > { - bool verbose; - bool exactInterpolation; - bool showResidual; - Real scale; - Real confidence; - Real lowDepthCutOff; - Real width; Real pointWeight; Real gradientWeight; Real biLapWeight; - Real samplesPerNode; - Real cgSolverAccuracy; - Real perLevelDataScaleFactor; - unsigned int depth; - unsigned int solveDepth; - unsigned int baseDepth; - unsigned int fullDepth; - unsigned int kernelDepth; - unsigned int baseVCycles; - unsigned int iters; - unsigned int alignDir; SolutionParameters( void ) : - verbose(false) , exactInterpolation(false) , showResidual(false) , - scale((Real)1.1) , confidence((Real)0.) , lowDepthCutOff((Real)0.) , width((Real)0.) , - pointWeight((Real)WeightMultipliers[0]) , gradientWeight((Real)WeightMultipliers[1]) , biLapWeight((Real)WeightMultipliers[2]) , samplesPerNode((Real)1.5) , cgSolverAccuracy((Real)1e-3 ) , perLevelDataScaleFactor((Real)32.) , - depth((unsigned int)8) , solveDepth((unsigned int)-1) , baseDepth((unsigned int)-1) , fullDepth((unsigned int)5) , kernelDepth((unsigned int)-1) , alignDir(0) , - baseVCycles((unsigned int)1) , iters((unsigned int)8) + pointWeight((Real)WeightMultipliers[0]) , gradientWeight((Real)WeightMultipliers[1]) , biLapWeight((Real)WeightMultipliers[2]) {} - }; template< typename Real , unsigned int Dim , typename FEMSigPack , typename ... AuxData > struct Solver; @@ -642,65 +686,20 @@ namespace PoissonRecon DenseNodeData< GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > geometryNodeDesignators; SparseNodeData< Point< Real , Dim > , NormalSigs > *normalInfo = NULL; std::vector< typename FEMTree< Dim , Real >::PointSample > *samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); - std::vector< InternalNormalAndAuxData > *sampleNormalAndAuxData = nullptr; + std::vector< InternalNormalAndAuxData > *sampleNormalAndAuxData = new std::vector< InternalNormalAndAuxData >(); - Real targetValue = params.targetValue; + Real targetValue = (Real)0.5; // Read in the samples (and auxiliary data) { profiler.reset(); pointStream.reset(); - sampleNormalAndAuxData = new std::vector< InternalNormalAndAuxData >(); modelToUnitCube = params.scale>0 ? PointExtent::GetXForm< Real , Dim , true , Normal< Real , Dim > , AuxData... >( pointStream , Normal< Real , Dim >() , zero... , params.scale , params.alignDir ) * modelToUnitCube : modelToUnitCube; + implicit.unitCubeToModel = modelToUnitCube.inverse(); pointStream.reset(); - if( params.width>0 ) - { - XForm< Real , Dim > unitCubeToModel = modelToUnitCube.inverse(); - - Real maxScale = 0; - for( unsigned int i=0 ; imaxScale ) maxScale = l2; - } - maxScale = sqrt( maxScale ); - params.depth = (unsigned int)ceil( std::max< double >( 0. , log( maxScale/params.width )/log(2.) ) ); - } - if( params.solveDepth>params.depth ) - { - if( params.solveDepth!=-1 ) WARN( "Solution depth cannot exceed system depth: " , params.solveDepth , " <= " , params.depth ); - params.solveDepth = params.depth; - } - if( params.fullDepth>params.solveDepth ) - { - if( params.fullDepth!=-1 ) WARN( "Full depth cannot exceed system depth: " , params.fullDepth , " <= " , params.solveDepth ); - params.fullDepth = params.solveDepth; - } - if( params.baseDepth>params.fullDepth ) - { - if( params.baseDepth!=-1 ) WARN( "Base depth must be smaller than full depth: " , params.baseDepth , " <= " , params.fullDepth ); - params.baseDepth = params.fullDepth; - } - if( params.kernelDepth==-1 ) params.kernelDepth = params.depth>2 ? params.depth-2 : 0; - if( params.kernelDepth>params.depth ) - { - if( params.kernelDepth!=-1 ) WARN( "Kernel depth cannot exceed system depth: " , params.kernelDepth , " <= " , params.depth ); - params.kernelDepth = params.depth; - } - if( params.envelopeDepth==-1 ) params.envelopeDepth = params.baseDepth; - if( params.envelopeDepth>params.depth ) - { - if( params.envelopeDepth!=-1 ) WARN( "Envelope dpeth cannot exceed system depth: " , params.envelopeDepth , " <= " , params.depth ); - params.envelopeDepth = params.depth; - } - if( params.envelopeDepth= " , params.baseDepth ); - params.envelopeDepth = params.baseDepth; - } + params.testAndSet( implicit.unitCubeToModel ); { // Apply the transformation @@ -749,7 +748,6 @@ namespace PoissonRecon implicit._zeroAuxData.process( F ); } - implicit.unitCubeToModel = modelToUnitCube.inverse(); if( params.verbose ) { @@ -1090,7 +1088,7 @@ namespace PoissonRecon ProjectiveData< Point< Real , 2 > , Real > pointDepthAndWeight; SparseNodeData< Point< Real , Dim > , NormalSigs > *normalInfo = NULL; std::vector< typename FEMTree< Dim , Real >::PointSample > *samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); - std::vector< InternalNormalAndAuxData > *sampleNormalAndAuxData = nullptr; + std::vector< InternalNormalAndAuxData > *sampleNormalAndAuxData = new std::vector< InternalNormalAndAuxData >();; Real targetValue = (Real)0.0; @@ -1099,39 +1097,11 @@ namespace PoissonRecon profiler.reset(); pointStream.reset(); - sampleNormalAndAuxData = new std::vector< InternalNormalAndAuxData >(); modelToUnitCube = params.scale>0 ? PointExtent::GetXForm< Real , Dim , true , Normal< Real , Dim > , AuxData... >( pointStream , Normal< Real , Dim >() , zero... , params.scale , params.alignDir ) * modelToUnitCube : modelToUnitCube; + implicit.unitCubeToModel = modelToUnitCube.inverse(); pointStream.reset(); - if( params.width>0 ) - { - // Assuming the transformation is rigid so that the (max) scale can be pulled from the Frobenius norm - Real maxScale = 0; - for( unsigned int i=0 ; i( 0. , log( maxScale/params.width )/log(2.) ) ); - } - if( params.solveDepth>params.depth ) - { - if( params.solveDepth!=-1 ) WARN( "Solution depth cannot exceed system depth: " , params.solveDepth , " <= " , params.depth ); - params.solveDepth = params.depth; - } - if( params.fullDepth>params.solveDepth ) - { - if( params.fullDepth!=-1 ) WARN( "Full depth cannot exceed system depth: " , params.fullDepth , " <= " , params.solveDepth ); - params.fullDepth = params.solveDepth; - } - if( params.baseDepth>params.fullDepth ) - { - if( params.baseDepth!=-1 ) WARN( "Base depth must be smaller than full depth: " , params.baseDepth , " <= " , params.fullDepth ); - params.baseDepth = params.fullDepth; - } - if( params.kernelDepth==-1 ) params.kernelDepth = params.depth>2 ? params.depth-2 : 0; - if( params.kernelDepth>params.depth ) - { - if( params.kernelDepth!=-1 ) WARN( "Kernel depth cannot exceed system depth: " , params.kernelDepth , " <= " , params.depth ); - params.kernelDepth = params.depth; - } + params.testAndSet( implicit.unitCubeToModel ); { // Apply the transformation @@ -1184,8 +1154,6 @@ namespace PoissonRecon implicit._zeroAuxData.process( F ); } - implicit.unitCubeToModel = modelToUnitCube.inverse(); - if( params.verbose ) { std::cout << "Input Points / Samples: " << pointCount << " / " << samples->size() << std::endl; diff --git a/Src/VertexFactory.h b/Src/VertexFactory.h index 2049eefb..d481e63b 100644 --- a/Src/VertexFactory.h +++ b/Src/VertexFactory.h @@ -198,7 +198,7 @@ namespace PoissonRecon protected: TypeOnDisk _typeOnDisk; bool _realTypeOnDisk; - static const std::string _PlyNames[]; + static std::string _PlyName( unsigned int idx ); }; // The vertex factory @@ -255,7 +255,7 @@ namespace PoissonRecon protected: TypeOnDisk _typeOnDisk; bool _realTypeOnDisk; - static const std::string _PlyNames[]; + static std::string _PlyName( unsigned int idx ); }; // The texture factory @@ -306,7 +306,7 @@ namespace PoissonRecon protected: TypeOnDisk _typeOnDisk; bool _realTypeOnDisk; - static const std::string _PlyNames[]; + static std::string _PlyName( unsigned int idx ); }; // The rgb color factory @@ -356,7 +356,7 @@ namespace PoissonRecon protected: TypeOnDisk _typeOnDisk; bool _realTypeOnDisk; - static const std::string _PlyNames[]; + static std::string _PlyName( unsigned int idx ); }; // The rgba color factory @@ -405,7 +405,7 @@ namespace PoissonRecon protected: TypeOnDisk _typeOnDisk; bool _realTypeOnDisk; - static const std::string _PlyNames[]; + static std::string _PlyName( unsigned int idx ); }; // The value factory @@ -455,7 +455,7 @@ namespace PoissonRecon protected: TypeOnDisk _typeOnDisk; bool _realTypeOnDisk; - static const std::string _PlyNames[]; + static std::string _PlyName( unsigned int idx ); }; // The named array factory diff --git a/Src/VertexFactory.inl b/Src/VertexFactory.inl index 3a4c6150..92ea6439 100644 --- a/Src/VertexFactory.inl +++ b/Src/VertexFactory.inl @@ -224,34 +224,34 @@ namespace VertexFactory PlyProperty PositionFactory< Real , Dim >::plyReadProperty( unsigned int idx ) const { if( idx>= plyReadNum() ) ERROR_OUT( "read property out of bounds" ); - return PlyProperty( _PlyNames[idx] , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); + return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real , unsigned int Dim > PlyProperty PositionFactory< Real , Dim >::plyWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); - return PlyProperty( _PlyNames[idx] , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); + return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real , unsigned int Dim > PlyProperty PositionFactory< Real , Dim >::plyStaticReadProperty( unsigned int idx ) const { if( idx>=plyReadNum() ) ERROR_OUT( "read property out of bounds" ); - return PlyProperty( _PlyNames[idx] , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); + return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); } template< typename Real , unsigned int Dim > PlyProperty PositionFactory< Real , Dim >::plyStaticWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); - return PlyProperty( _PlyNames[idx] , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); + return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); } - template<> const std::string PositionFactory< float , 1 >::_PlyNames[] = { "x" }; - template<> const std::string PositionFactory< double , 1 >::_PlyNames[] = { "x" }; - template<> const std::string PositionFactory< float , 2 >::_PlyNames[] = { "x" , "y" }; - template<> const std::string PositionFactory< double , 2 >::_PlyNames[] = { "x" , "y" }; - template<> const std::string PositionFactory< float , 3 >::_PlyNames[] = { "x" , "y" , "z" }; - template<> const std::string PositionFactory< double , 3 >::_PlyNames[] = { "x" , "y" , "z" }; + template< typename Real , unsigned int Dim > + std::string PositionFactory< Real , Dim >::_PlyName( unsigned int idx ) + { + static const std::string names[] = { "x" , "y" , "z" }; + return names[idx]; + } /////////////////// // NormalFactory // @@ -260,34 +260,34 @@ namespace VertexFactory PlyProperty NormalFactory< Real , Dim >::plyReadProperty( unsigned int idx ) const { if( idx>= plyReadNum() ) ERROR_OUT( "read property out of bounds" ); - return PlyProperty( _PlyNames[idx] , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); + return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real , unsigned int Dim > PlyProperty NormalFactory< Real , Dim >::plyWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); - return PlyProperty( _PlyNames[idx] , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); + return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real , unsigned int Dim > PlyProperty NormalFactory< Real , Dim >::plyStaticReadProperty( unsigned int idx ) const { if( idx>=plyReadNum() ) ERROR_OUT( "read property out of bounds" ); - return PlyProperty( _PlyNames[idx] , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); + return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); } template< typename Real , unsigned int Dim > PlyProperty NormalFactory< Real , Dim >::plyStaticWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); - return PlyProperty( _PlyNames[idx] , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); + return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); } - template<> const std::string NormalFactory< float , 1 >::_PlyNames[] = { "nx" }; - template<> const std::string NormalFactory< double , 1 >::_PlyNames[] = { "nx" }; - template<> const std::string NormalFactory< float , 2 >::_PlyNames[] = { "nx" , "ny" }; - template<> const std::string NormalFactory< double , 2 >::_PlyNames[] = { "nx" , "ny" }; - template<> const std::string NormalFactory< float , 3 >::_PlyNames[] = { "nx" , "ny" , "nz" }; - template<> const std::string NormalFactory< double , 3 >::_PlyNames[] = { "nx" , "ny" , "nz" }; + template< typename Real , unsigned int Dim > + std::string NormalFactory< Real , Dim >::_PlyName( unsigned int idx ) + { + static const std::string names[] = { "nx" , "ny" , "nz" }; + return names[idx]; + } //////////////////// // TextureFactory // @@ -296,34 +296,34 @@ namespace VertexFactory PlyProperty TextureFactory< Real , Dim >::plyReadProperty( unsigned int idx ) const { if( idx>= plyReadNum() ) ERROR_OUT( "read property out of bounds" ); - return PlyProperty( _PlyNames[idx] , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); + return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real , unsigned int Dim > PlyProperty TextureFactory< Real , Dim >::plyWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); - return PlyProperty( _PlyNames[idx] , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); + return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real , unsigned int Dim > PlyProperty TextureFactory< Real , Dim >::plyStaticReadProperty( unsigned int idx ) const { if( idx>=plyReadNum() ) ERROR_OUT( "read property out of bounds" ); - return PlyProperty( _PlyNames[idx] , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); + return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); } template< typename Real , unsigned int Dim > PlyProperty TextureFactory< Real , Dim >::plyStaticWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); - return PlyProperty( _PlyNames[idx] , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); + return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); } - template<> const std::string TextureFactory< float , 1 >::_PlyNames[] = { "u" }; - template<> const std::string TextureFactory< double , 1 >::_PlyNames[] = { "u" }; - template<> const std::string TextureFactory< float , 2 >::_PlyNames[] = { "u" , "v" }; - template<> const std::string TextureFactory< double , 2 >::_PlyNames[] = { "u" , "v" }; - template<> const std::string TextureFactory< float , 3 >::_PlyNames[] = { "u" , "v" , "w" }; - template<> const std::string TextureFactory< double , 3 >::_PlyNames[] = { "u" , "v" , "w" }; + template< typename Real , unsigned int Dim > + std::string TextureFactory< Real , Dim >::_PlyName( unsigned int idx ) + { + static const std::string names[] = { "u" , "v" , "w" }; + return names[idx]; + } ///////////////////// // RGBColorFactory // @@ -332,29 +332,34 @@ namespace VertexFactory PlyProperty RGBColorFactory< Real >::plyReadProperty( unsigned int idx ) const { if( idx>= plyReadNum() ) ERROR_OUT( "read property out of bounds" ); - return PlyProperty( _PlyNames[idx] , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); + return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real > PlyProperty RGBColorFactory< Real >::plyWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); - return PlyProperty( _PlyNames[idx] , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); + return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real > PlyProperty RGBColorFactory< Real >::plyStaticReadProperty( unsigned int idx ) const { if( idx>=plyReadNum() ) ERROR_OUT( "read property out of bounds" ); - return PlyProperty( _PlyNames[idx] , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + (idx%3)*sizeof(Real) ) ); + return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + (idx%3)*sizeof(Real) ) ); } template< typename Real > PlyProperty RGBColorFactory< Real >::plyStaticWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); - return PlyProperty( _PlyNames[idx] , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); + return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); } - template< typename Real > const std::string RGBColorFactory< Real >::_PlyNames[] = { "red" , "green" , "blue" , "r" , "g" , "b" }; + template< typename Real > + std::string RGBColorFactory< Real >::_PlyName( unsigned int idx ) + { + static const std::string names[] = { "red" , "green" , "blue" , "r" , "g" , "b" }; + return names[idx]; + } ////////////////////// // RGBAColorFactory // @@ -363,29 +368,36 @@ namespace VertexFactory PlyProperty RGBAColorFactory< Real >::plyReadProperty( unsigned int idx ) const { if( idx>= plyReadNum() ) ERROR_OUT( "read property out of bounds" ); - return PlyProperty( _PlyNames[idx] , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); + return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } + template< typename Real > PlyProperty RGBAColorFactory< Real >::plyWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); - return PlyProperty( _PlyNames[idx] , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); + return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real > PlyProperty RGBAColorFactory< Real >::plyStaticReadProperty( unsigned int idx ) const { if( idx>=plyReadNum() ) ERROR_OUT( "read property out of bounds" ); - return PlyProperty( _PlyNames[idx] , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + (idx%4)*sizeof(Real) ) ); + return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + (idx%4)*sizeof(Real) ) ); } + template< typename Real > PlyProperty RGBAColorFactory< Real >::plyStaticWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); - return PlyProperty( _PlyNames[idx] , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); + return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); } - template< typename Real > const std::string RGBAColorFactory< Real >::_PlyNames[] = { "red" , "green" , "blue" , "alpha" , "r" , "g" , "b" , "a" }; + template< typename Real > + std::string RGBAColorFactory< Real >::_PlyName( unsigned int idx ) + { + static const std::string names[] = { "red" , "green" , "blue" , "alpha" , "r" , "g" , "b" , "a" }; + return names[idx]; + } ////////////////// // ValueFactory // @@ -394,29 +406,36 @@ namespace VertexFactory PlyProperty ValueFactory< Real >::plyReadProperty( unsigned int idx ) const { if( idx>= plyReadNum() ) ERROR_OUT( "read property out of bounds" ); - return PlyProperty( _PlyNames[idx] , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); + return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } + template< typename Real > PlyProperty ValueFactory< Real >::plyWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); - return PlyProperty( _PlyNames[idx] , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); + return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real > PlyProperty ValueFactory< Real >::plyStaticReadProperty( unsigned int idx ) const { if( idx>=plyReadNum() ) ERROR_OUT( "read property out of bounds" ); - return PlyProperty( _PlyNames[idx] , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , 0 ); + return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , 0 ); } + template< typename Real > PlyProperty ValueFactory< Real >::plyStaticWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); - return PlyProperty( _PlyNames[idx] , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , 0 ); + return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , 0 ); } - template< typename Real > const std::string ValueFactory< Real >::_PlyNames[] = { "value" }; + template< typename Real > + std::string ValueFactory< Real >::_PlyName( unsigned int idx ) + { + static const std::string names[] = { "value" }; + return names[idx]; + } //////////////////// // DynamicFactory // From c2c85e434843f7777d719b17e42d4a0d8f5ac8ea Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Thu, 31 Oct 2024 19:45:50 -0400 Subject: [PATCH 64/86] Version 18.41 --- README.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index eac98d5f..3c20883e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

        Adaptive Multigrid Solvers (Version 18.40)

        +

        Adaptive Multigrid Solvers (Version 18.41)

        links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
        Executables: -Win64
        +Win64
        Source Code: -ZIP GitHub
        +ZIP GitHub
        Older Versions: +V18.40, V18.35, V18.31, V18.30, @@ -1708,16 +1709,21 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
      • Removed the smoothing option in the SufaceTrimmer executable. -Version 18.35: +Version 18.35:
        1. Removed the confidence bias option.
        -Version 18.40: +Version 18.40:
        1. Added support for extrapolator accumulation.
        +Version 18.41: +
          +
        1. Removed explicitly instantiated static variables. +
        +
        From 2bfc2c5ac9d1aabdf5ec1bde0b40fbc25fad16f2 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Fri, 1 Nov 2024 08:20:11 -0400 Subject: [PATCH 65/86] Version 18.41 --- README.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/README.md b/README.md index 3c20883e..794fa740 100644 --- a/README.md +++ b/README.md @@ -233,9 +233,6 @@ The default value for this parameter is 8.
  • [--density]
    Enabling this flag tells the reconstructor to output the estimated depth values of the iso-surface vertices. -
    [--normals] -
    Enabling this flag tells the reconstructor to output vertex normals, computed from the gradients of the implicit function. -
    [--colors]
    If the input points are in ASCII/binary format and contain color values, this flag lets the reconstruction code know that (1) each sample is represented by nine floating point values instead of the expected six, and that (2) color values should be output with the vertices of the reconstructed surface. (For input samples in the .ply format, the presence of color information, as well as any other additional per-sample data, is automatically determined from the file header.) @@ -571,9 +568,6 @@ The default value for this parameter is 8.
    [--density]
    Enabling this flag tells the reconstructor to output the estimated depth values of the iso-surface vertices. -
    [--normals] -
    Enabling this flag tells the reconstructor to output vertex normals, computed from the gradients of the implicit function. -
    [--colors]
    If the input points are in ASCII/binary format and contain color values, this flag lets the reconstruction code know that (1) each sample is represented by nine floating point values instead of the expected six, and that (2) color values should be output with the vertices of the reconstructed surface. (For input samples in the .ply format, the presence of color information, as well as any other additional per-sample data, is automatically determined from the file header.) From 0af1cf3360a44f6d6a15e05cb4415836330bc6fe Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Fri, 8 Nov 2024 12:32:33 -0500 Subject: [PATCH 66/86] Version 18.41 --- PNG.vcxproj | 2 +- PoissonReconClient.vcxproj | 2 +- PoissonReconServer.vcxproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/PNG.vcxproj b/PNG.vcxproj index 203fca53..310c88f9 100644 --- a/PNG.vcxproj +++ b/PNG.vcxproj @@ -159,7 +159,7 @@ X64 - ..;%(AdditionalIncludeDirectories) + .;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) MultiThreadedDLL diff --git a/PoissonReconClient.vcxproj b/PoissonReconClient.vcxproj index 889821a3..3495e95b 100644 --- a/PoissonReconClient.vcxproj +++ b/PoissonReconClient.vcxproj @@ -101,7 +101,7 @@ AdvancedVectorExtensions2 true stdcpp17 - C:\Research\Libraries\ + C:\Research\Libraries\;. Console diff --git a/PoissonReconServer.vcxproj b/PoissonReconServer.vcxproj index 8a152146..6301aaa6 100644 --- a/PoissonReconServer.vcxproj +++ b/PoissonReconServer.vcxproj @@ -101,7 +101,7 @@ AdvancedVectorExtensions2 true stdcpp17 - C:\Research\Libraries\ + C:\Research\Libraries\;. Console From d5cd487a522146115784b1173a4b9ba466610644 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Mon, 18 Nov 2024 06:33:56 -0500 Subject: [PATCH 67/86] Version 18.42 --- README.md | 13 ++++++++++--- Src/Extrapolator.h | 4 ++-- Src/MultiThreading.h | 20 ++++++++++++++++++++ Src/PreProcessor.h | 2 +- Src/Reconstruction.example.cpp | 14 +++++++------- 5 files changed, 40 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 794fa740..9c986532 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 18.41)

    +

    Adaptive Multigrid Solvers (Version 18.42)

    links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
    Executables: -Win64
    +Win64
    Source Code: -ZIP GitHub
    +ZIP GitHub
    Older Versions: +V18.41, V18.40, V18.35, V18.31, @@ -1718,6 +1719,12 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • Removed explicitly instantiated static variables. +Version 18.42: +
      +
    1. Fixed parallelization bugy in Extrapolator. +
    2. Moified Reconstruction.example to use parallelized extrapolation. +
    +
    diff --git a/Src/Extrapolator.h b/Src/Extrapolator.h index 0ba3871c..80393a0d 100644 --- a/Src/Extrapolator.h +++ b/Src/Extrapolator.h @@ -112,7 +112,7 @@ namespace PoissonRecon Point< Real , Dim > q = _worldToUnitCube * p; for( unsigned int d=0 ; d1 ) throw OutOfUnitCubeException(p,q); ProjectiveData< AuxData , Real > pData( zeroAuxData ); - _auxEvaluator->addValue( q , pData ); + _auxEvaluator->addValue( q , pData , t ); return pData.value(); } @@ -129,7 +129,7 @@ namespace PoissonRecon weight += pData.weight * scale; data += pData.data * scale; }; - _auxEvaluator->accumulate( q , Accumulation ); + _auxEvaluator->accumulate( q , Accumulation , t ); if( weight ) data /= weight; } }; diff --git a/Src/MultiThreading.h b/Src/MultiThreading.h index eb8ac1c4..5d303c08 100644 --- a/Src/MultiThreading.h +++ b/Src/MultiThreading.h @@ -76,6 +76,19 @@ namespace PoissonRecon for( unsigned int i=0 ; i + static void ParallelSections( const Function &&function , const Functions && ... functions ) + { + std::vector< std::future< void > > futures; + if constexpr( sizeof ... (Functions) ) + { + futures.reserve( sizeof...(Functions) ); + _ParallelSections( futures , std::move(functions)... ); + } + function(); + for( unsigned int i=0 ; i &iterationFunction , unsigned int numThreads=_NumThreads , ParallelType pType=ParallelizationType , ScheduleType schedule=Schedule , size_t chunkSize=ChunkSize ) { if( begin>=end ) return; @@ -150,6 +163,13 @@ namespace PoissonRecon futures.push_back( std::async( std::launch::async , function ) ); if constexpr( sizeof...(Functions) ) _ParallelSections( futures , functions... ); } + + template< typename Function , typename ... Functions > + static void _ParallelSections( std::vector< std::future< void > > &futures , const Function &&function , const Functions && ... functions ) + { + futures.push_back( std::async( std::launch::async , function ) ); + if constexpr( sizeof...(Functions) ) _ParallelSections( futures , std::move(functions)... ); + } }; unsigned int ThreadPool::_NumThreads = std::thread::hardware_concurrency(); diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 01dd3cd8..b2a629b5 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -46,7 +46,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "18.41" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "18.42" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth diff --git a/Src/Reconstruction.example.cpp b/Src/Reconstruction.example.cpp index 02ba63e9..3f3b99e4 100644 --- a/Src/Reconstruction.example.cpp +++ b/Src/Reconstruction.example.cpp @@ -414,13 +414,13 @@ void Execute( void ) std::vector< Real > rgbCoordinates( vCoordinates.size()/Dim*3 ); // Iterate over the vertices and evaluate the extrapolate to get the color values - for( unsigned int i=0 ; i p; - for( unsigned int d=0 ; d c = extrapolator( p ); - rgbCoordinates[i*3+0] = c.r , rgbCoordinates[i*3+1] = c.g , rgbCoordinates[i*3+2] = c.b; - } + ThreadPool::ParallelFor( 0 , vCoordinates.size()/Dim , [&]( unsigned int thread , size_t i ) + { + Point< Real , Dim > p; + for( unsigned int d=0 ; d c = extrapolator( thread , p ); + rgbCoordinates[i*3+0] = c.r , rgbCoordinates[i*3+1] = c.g , rgbCoordinates[i*3+2] = c.b; + } ); // Write out the level-set with sampled colors if( Out.set ) WritePly( Out.value , vStream.size() , vCoordinates.data() , rgbCoordinates.data() , polygons ); From f3da061d268e57638ebadc410f26080ace547611 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Tue, 19 Nov 2024 11:44:38 -0500 Subject: [PATCH 68/86] Version 18.42 --- Src/PlyFile.h | 67 ++++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/Src/PlyFile.h b/Src/PlyFile.h index 6f77aa9f..d4fc0c29 100644 --- a/Src/PlyFile.h +++ b/Src/PlyFile.h @@ -55,6 +55,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include "MyMiscellany.h" #include "Streams.h" @@ -186,7 +187,7 @@ namespace PoissonRecon std::vector< PlyStoredProperty > props; /* list of properties in the file */ int other_offset; /* offset to un-asked-for props, or -1 if none*/ int other_size; /* size of other_props structure */ - PlyProperty *find_property( const std::string &prop_name , int &index ); + inline PlyProperty *find_property( const std::string &prop_name , int &index ); }; /* describes other properties in an element */ @@ -231,43 +232,43 @@ namespace PoissonRecon PlyElement *which_elem; /* which element we're currently writing */ PlyOtherElems *other_elems; /* "other" elements from a PLY file */ - static PlyFile *Write( const std::string & , const std::vector< std::string > & , int , float & ); - static PlyFile *Read ( const std::string & , std::vector< std::string > & , int & , float & ); + static inline PlyFile *Write( const std::string & , const std::vector< std::string > & , int , float & ); + static inline PlyFile *Read ( const std::string & , std::vector< std::string > & , int & , float & ); PlyFile( FILE *f ) : fp(f) , other_elems(NULL) , version(1.) { } ~PlyFile( void ){ if( fp ) fclose(fp) ; if(other_elems) delete other_elems; } - void describe_element ( const std::string & , size_t , int , const PlyProperty * ); - void describe_property( const std::string & , const PlyProperty * ); - void describe_other_elements( PlyOtherElems * ); - PlyElement *find_element( const std::string & ); - void element_count( const std::string & , size_t ); - void header_complete( void ); - void put_element_setup( const std::string & ); - void put_element ( void * ); - void put_comment ( const std::string & ); - void put_obj_info( const std::string & ); - void put_other_elements( void ); - void add_element ( const std::vector< std::string > & ); - void add_property( const std::vector< std::string > & ); - void add_comment ( const std::string & ); - void add_obj_info( const std::string & ); - - std::vector< PlyProperty > get_element_description( const std::string & , size_t & ); - void get_element_setup( const std::string & , int , PlyProperty * ); - int get_property( const std::string & , const PlyProperty * ); - void describe_other_properties( const PlyOtherProp & , int ); - bool set_other_properties( const std::string & , int , PlyOtherProp & ); - void get_element( void * ); - std::vector< std::string > &get_comments( void ); - std::vector< std::string > &get_obj_info( void ); - void get_info( float & , int & ); - PlyOtherElems *get_other_element( std::string & , size_t ); + inline void describe_element ( const std::string & , size_t , int , const PlyProperty * ); + inline void describe_property( const std::string & , const PlyProperty * ); + inline void describe_other_elements( PlyOtherElems * ); + inline PlyElement *find_element( const std::string & ); + inline void element_count( const std::string & , size_t ); + inline void header_complete( void ); + inline void put_element_setup( const std::string & ); + inline void put_element ( void * ); + inline void put_comment ( const std::string & ); + inline void put_obj_info( const std::string & ); + inline void put_other_elements( void ); + inline void add_element ( const std::vector< std::string > & ); + inline void add_property( const std::vector< std::string > & ); + inline void add_comment ( const std::string & ); + inline void add_obj_info( const std::string & ); + + inline std::vector< PlyProperty > get_element_description( const std::string & , size_t & ); + inline void get_element_setup( const std::string & , int , PlyProperty * ); + inline int get_property( const std::string & , const PlyProperty * ); + inline void describe_other_properties( const PlyOtherProp & , int ); + inline bool set_other_properties( const std::string & , int , PlyOtherProp & ); + inline void get_element( void * ); + inline std::vector< std::string > &get_comments( void ); + inline std::vector< std::string > &get_obj_info( void ); + inline void get_info( float & , int & ); + inline PlyOtherElems *get_other_element( std::string & , size_t ); protected: - void _ascii_get_element ( void * ); - void _binary_get_element( void * ); - static PlyFile *_Write( FILE * , const std::vector< std::string > & , int ); - static PlyFile *_Read ( FILE * , std::vector< std::string > & ); + inline void _ascii_get_element ( void * ); + inline void _binary_get_element( void * ); + static inline PlyFile *_Write( FILE * , const std::vector< std::string > & , int ); + static inline PlyFile *_Read ( FILE * , std::vector< std::string > & ); }; #include "PlyFile.inl" From 83005ca4ff42436eee540874d592d20e5adc5b29 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Tue, 19 Nov 2024 14:09:02 -0500 Subject: [PATCH 69/86] Version 18.42 --- Src/BSplineData.h | 6 +++--- Src/CmdLineParser.inl | 46 +++++++++++++++++++++---------------------- Src/Extrapolator.h | 2 +- Src/FEMTree.h | 18 ++++++++--------- Src/MarchingCubes.h | 6 +++--- Src/MultiThreading.h | 12 +++++------ Src/PPolynomial.inl | 2 +- Src/Ply.h | 8 ++++---- Src/Ply.inl | 40 ++++++++++++++++++------------------- Src/PlyFile.h | 2 +- Src/PlyFile.inl | 36 +++++++++++++++++---------------- Src/Polynomial.inl | 30 +++++++++++++++------------- Src/Reconstructors.h | 2 +- Src/RegularGrid.h | 16 +++++++-------- Src/VertexFactory.h | 4 ++-- 15 files changed, 117 insertions(+), 113 deletions(-) diff --git a/Src/BSplineData.h b/Src/BSplineData.h index 5aae800a..9f230bb2 100644 --- a/Src/BSplineData.h +++ b/Src/BSplineData.h @@ -44,7 +44,7 @@ namespace PoissonRecon BOUNDARY_NEUMANN , BOUNDARY_COUNT }; - const char* BoundaryNames[] = { "free" , "Dirichlet" , "Neumann" }; + static const char* BoundaryNames[] = { "free" , "Dirichlet" , "Neumann" }; template< BoundaryType BType > inline bool HasPartitionOfUnity( void ){ return BType!=BOUNDARY_DIRICHLET; } inline bool HasPartitionOfUnity( BoundaryType bType ){ return bType!=BOUNDARY_DIRICHLET; } template< BoundaryType BType , unsigned int D > struct DerivativeBoundary{}; @@ -68,8 +68,8 @@ namespace PoissonRecon static constexpr typename std::enable_if< (Degree>=D) , unsigned int >::type DSignature( void ){ return FEMDegreeAndBType< Degree-D , DerivativeBoundary< BType , D >::BType >::Signature; } }; - unsigned int FEMSignatureDegree( unsigned int signature ){ return signature / BOUNDARY_COUNT; } - BoundaryType FEMSignatureBType ( unsigned int signature ){ return (BoundaryType)( signature % BOUNDARY_COUNT ); } + inline unsigned int FEMSignatureDegree( unsigned int signature ){ return signature / BOUNDARY_COUNT; } + inline BoundaryType FEMSignatureBType ( unsigned int signature ){ return (BoundaryType)( signature % BOUNDARY_COUNT ); } static const unsigned int FEMTrivialSignature = FEMDegreeAndBType< 0 , BOUNDARY_FREE >::Signature; diff --git a/Src/CmdLineParser.inl b/Src/CmdLineParser.inl index 8d5d195b..b4ce704e 100644 --- a/Src/CmdLineParser.inl +++ b/Src/CmdLineParser.inl @@ -30,20 +30,20 @@ DAMAGE. inline int strcasecmp( const char* c1 , const char* c2 ){ return _stricmp( c1 , c2 ); } #endif // WIN32 || _WIN64 -template< > void CmdLineType< char* >::CleanUp( char** t ){ if( *t ) free( *t ) ; *t = NULL; } - -template< > int CmdLineType< int >::Initialize( void ){ return 0; } -template< > unsigned int CmdLineType< unsigned int >::Initialize( void ){ return 0u; } -template< > float CmdLineType< float >::Initialize( void ){ return 0.f; } -template< > double CmdLineType< double >::Initialize( void ){ return 0.; } -template< > char * CmdLineType< char * >::Initialize( void ){ return NULL; } - -template< > void CmdLineType< int >::WriteValue( int t , char* str ){ sprintf( str , "%d" , t ); } -template< > void CmdLineType< unsigned int >::WriteValue( unsigned int t , char* str ){ sprintf( str , "%u" , t ); } -template< > void CmdLineType< float >::WriteValue( float t , char* str ){ sprintf( str , "%f" , t ); } -template< > void CmdLineType< double >::WriteValue( double t , char* str ){ sprintf( str , "%f" , t ); } -template< > void CmdLineType< char * >::WriteValue( char *t , char* str ){ if( t ) sprintf( str , "%s" , t ) ; else str[0]=0; } -template< > void CmdLineType< std::string >::WriteValue( std::string t , char* str ){ sprintf( str , "%s" , t.c_str() ); } +template< > inline void CmdLineType< char* >::CleanUp( char** t ){ if( *t ) free( *t ) ; *t = NULL; } + +template< > inline int CmdLineType< int >::Initialize( void ){ return 0; } +template< > inline unsigned int CmdLineType< unsigned int >::Initialize( void ){ return 0u; } +template< > inline float CmdLineType< float >::Initialize( void ){ return 0.f; } +template< > inline double CmdLineType< double >::Initialize( void ){ return 0.; } +template< > inline char * CmdLineType< char * >::Initialize( void ){ return NULL; } + +template< > inline void CmdLineType< int >::WriteValue( int t , char* str ){ sprintf( str , "%d" , t ); } +template< > inline void CmdLineType< unsigned int >::WriteValue( unsigned int t , char* str ){ sprintf( str , "%u" , t ); } +template< > inline void CmdLineType< float >::WriteValue( float t , char* str ){ sprintf( str , "%f" , t ); } +template< > inline void CmdLineType< double >::WriteValue( double t , char* str ){ sprintf( str , "%f" , t ); } +template< > inline void CmdLineType< char * >::WriteValue( char *t , char* str ){ if( t ) sprintf( str , "%s" , t ) ; else str[0]=0; } +template< > inline void CmdLineType< std::string >::WriteValue( std::string t , char* str ){ sprintf( str , "%s" , t.c_str() ); } template< typename Real , unsigned int Dim > void CmdLineType< Point< Real , Dim > >::WriteValue( Point< Real , Dim > t , char *str ) { @@ -60,21 +60,21 @@ void CmdLineType< Point< Real , Dim > >::WriteValue( Point< Real , Dim > t , cha } #if defined( WIN32 ) || defined( _WIN64 ) -template< > char* CmdLineType< char* >::Copy( char* t ){ return _strdup( t ); } +template< > inline char* CmdLineType< char* >::Copy( char* t ){ return _strdup( t ); } #else // !WIN32 && !_WIN64 -template< > char* CmdLineType< char* >::Copy( char* t ){ return strdup( t ); } +template< > inline char* CmdLineType< char* >::Copy( char* t ){ return strdup( t ); } #endif // WIN32 || _WIN64 -template< > int CmdLineType< int >::StringToType( const char* str ){ return atoi( str ); } -template< > unsigned int CmdLineType< unsigned int >::StringToType( const char* str ){ return (unsigned int)atoll( str ); } -template< > float CmdLineType< float >::StringToType( const char* str ){ return float( atof( str ) ); } -template< > double CmdLineType< double >::StringToType( const char* str ){ return double( atof( str ) ); } +template< > inline int CmdLineType< int >::StringToType( const char* str ){ return atoi( str ); } +template< > inline unsigned int CmdLineType< unsigned int >::StringToType( const char* str ){ return (unsigned int)atoll( str ); } +template< > inline float CmdLineType< float >::StringToType( const char* str ){ return float( atof( str ) ); } +template< > inline double CmdLineType< double >::StringToType( const char* str ){ return double( atof( str ) ); } #if defined( WIN32 ) || defined( _WIN64 ) -template< > char * CmdLineType< char* >::StringToType( const char* str ){ return _strdup( str ); } +template< > inline char * CmdLineType< char* >::StringToType( const char* str ){ return _strdup( str ); } #else // !WIN32 && !_WIN64 -template< > char * CmdLineType< char* >::StringToType( const char* str ){ return strdup( str ); } +template< > inline char * CmdLineType< char* >::StringToType( const char* str ){ return strdup( str ); } #endif // WIN32 || _WIN64 -template< > std::string CmdLineType< std::string >::StringToType( const char* str ){ return std::string( str ); } +template< > inline std::string CmdLineType< std::string >::StringToType( const char* str ){ return std::string( str ); } template< typename Real , unsigned int Dim > Point< Real , Dim > CmdLineType< Point< Real , Dim > >::StringToType( const char *str ) diff --git a/Src/Extrapolator.h b/Src/Extrapolator.h index 80393a0d..87f73d15 100644 --- a/Src/Extrapolator.h +++ b/Src/Extrapolator.h @@ -39,7 +39,7 @@ namespace PoissonRecon { namespace Extrapolator { - unsigned int ProfilerMS = 20; // The number of ms at which to poll the performance (set to zero for no polling) + static unsigned int ProfilerMS = 20; // The number of ms at which to poll the performance (set to zero for no polling) template< typename Real , unsigned int Dim , typename AuxData > using InputStream = Reconstructor::InputSampleStream< Real , Dim , AuxData >; diff --git a/Src/FEMTree.h b/Src/FEMTree.h index 42d9b1bf..3bdd7071 100644 --- a/Src/FEMTree.h +++ b/Src/FEMTree.h @@ -99,7 +99,7 @@ namespace PoissonRecon SHOW_GLOBAL_RESIDUAL_ALL , SHOW_GLOBAL_RESIDUAL_COUNT }; - const char* ShowGlobalResidualNames[] = { "show none" , "show last" , "show all" }; + static const char* ShowGlobalResidualNames[] = { "show none" , "show last" , "show all" }; class FEMTreeNodeData { @@ -129,10 +129,10 @@ namespace PoissonRecon bool getDirichletElementFlag( void ) const { return ( flags & DIRICHLET_ELEMENT_FLAG )!=0; } void setScratchFlag( bool f ) const { if( f ) flags |= SCRATCH_FLAG ; else flags &= (unsigned char)~SCRATCH_FLAG; } bool getScratchFlag( void ) const { return ( flags & SCRATCH_FLAG )!=0; } - FEMTreeNodeData( void ); - ~FEMTreeNodeData( void ); + inline FEMTreeNodeData( void ); + inline ~FEMTreeNodeData( void ); #ifdef SANITIZED_PR - FEMTreeNodeData &operator = ( const FEMTreeNodeData &data ); + inline FEMTreeNodeData &operator = ( const FEMTreeNodeData &data ); #endif // SANITIZED_PR }; @@ -569,15 +569,15 @@ namespace PoissonRecon FEM_TREE_REAL_DOUBLE , FEM_TREE_REAL_COUNT }; - const char* FEMTreeRealNames[] = { "float" , "double" }; + static const char *FEMTreeRealNames[] = { "float" , "double" }; - void ReadFEMTreeParameter( BinaryStream &stream , FEMTreeRealType& realType , unsigned int &dimension ) + inline void ReadFEMTreeParameter( BinaryStream &stream , FEMTreeRealType& realType , unsigned int &dimension ) { if( !stream.read( realType ) ) ERROR_OUT( "Failed to read real type" ); if( !stream.read( dimension ) ) ERROR_OUT( "Failed to read dimension" ); } - unsigned int* ReadDenseNodeDataSignatures( BinaryStream &stream , unsigned int &dim ) + inline unsigned int* ReadDenseNodeDataSignatures( BinaryStream &stream , unsigned int &dim ) { if( !stream.read( dim ) ) ERROR_OUT( "Failed to read dimension" ); unsigned int* femSigs = new unsigned int[dim]; @@ -1448,8 +1448,8 @@ namespace PoissonRecon for( int i=0 ; i class FEMTree diff --git a/Src/MarchingCubes.h b/Src/MarchingCubes.h index ea5ff8f0..2e7b6df7 100644 --- a/Src/MarchingCubes.h +++ b/Src/MarchingCubes.h @@ -41,7 +41,7 @@ namespace PoissonRecon { enum Direction{ BACK , CROSS , FRONT }; inline Direction Opposite( Direction dir ){ return dir==BACK ? FRONT : ( dir==FRONT ? BACK : CROSS ); } - std::string DirectionName( Direction dir ) + inline std::string DirectionName( Direction dir ) { if( dir==BACK ) return std::string( "back" ); else if( dir==CROSS ) return std::string( "cross" ); @@ -252,7 +252,7 @@ namespace PoissonRecon { const static unsigned int MAX_EDGES=2; static const int edges[1<::ElementNum< 0 >()][2*MAX_EDGES+1]; - static int AddEdgeIndices( unsigned char mcIndex , int* edges); + static inline int AddEdgeIndices( unsigned char mcIndex , int* edges); }; /////////////////// @@ -719,7 +719,7 @@ namespace PoissonRecon ///////////////////// // MarchingSquares // ///////////////////// - const int MarchingSquares::edges[][MAX_EDGES*2+1] = + const inline int MarchingSquares::edges[][MAX_EDGES*2+1] = { // Positive to the right // Positive in center diff --git a/Src/MultiThreading.h b/Src/MultiThreading.h index 5d303c08..0f81f3ce 100644 --- a/Src/MultiThreading.h +++ b/Src/MultiThreading.h @@ -172,12 +172,12 @@ namespace PoissonRecon } }; - unsigned int ThreadPool::_NumThreads = std::thread::hardware_concurrency(); - ThreadPool::ParallelType ThreadPool::ParallelizationType = ThreadPool::ParallelType::NONE; - ThreadPool::ScheduleType ThreadPool::Schedule = ThreadPool::DYNAMIC; - size_t ThreadPool::ChunkSize = 128; + inline ThreadPool::ParallelType ThreadPool::ParallelizationType = ThreadPool::ParallelType::NONE; + inline unsigned int ThreadPool::_NumThreads = std::thread::hardware_concurrency(); + inline ThreadPool::ScheduleType ThreadPool::Schedule = ThreadPool::DYNAMIC; + inline size_t ThreadPool::ChunkSize = 128; - const std::vector< std::string > ThreadPool::ParallelNames = + const inline std::vector< std::string > ThreadPool::ParallelNames = { #ifdef _OPENMP "open mp" , @@ -185,6 +185,6 @@ namespace PoissonRecon "async" , "none" }; - const std::vector< std::string > ThreadPool::ScheduleNames = { "static" , "dynamic" }; + const inline std::vector< std::string > ThreadPool::ScheduleNames = { "static" , "dynamic" }; } #endif // MULTI_THREADING_INCLUDED diff --git a/Src/PPolynomial.inl b/Src/PPolynomial.inl index 324731bb..70b4633f 100644 --- a/Src/PPolynomial.inl +++ b/Src/PPolynomial.inl @@ -401,7 +401,7 @@ void PPolynomial::printnl(void) const{ printf("\n"); } template< > -PPolynomial< 0 > PPolynomial< 0 >::BSpline( double radius ) +inline PPolynomial< 0 > PPolynomial< 0 >::BSpline( double radius ) { PPolynomial q; q.set(2); diff --git a/Src/Ply.h b/Src/Ply.h index 2f70d0c3..23d72438 100644 --- a/Src/Ply.h +++ b/Src/Ply.h @@ -73,7 +73,7 @@ namespace PoissonRecon struct Edge { Index v1 , v2; - static PlyProperty Properties[]; + static const PlyProperty Properties[]; }; // A structure representing a face @@ -83,15 +83,15 @@ namespace PoissonRecon unsigned int nr_vertices; Index *vertices; - static PlyProperty Properties[]; + static const PlyProperty Properties[]; }; - int DefaultFileType( void ); + inline int DefaultFileType( void ); // PLY read header functionality // Get the properties (and return the file type) - int ReadVertexHeader( std::string fileName , std::vector< PlyProperty > &properties ); + inline int ReadVertexHeader( std::string fileName , std::vector< PlyProperty > &properties ); // Test which properties are represented by elements of the vertex factory (and return the file type) template< typename VertexFactory > diff --git a/Src/Ply.inl b/Src/Ply.inl index 71de1414..0f6a0277 100644 --- a/Src/Ply.inl +++ b/Src/Ply.inl @@ -42,26 +42,26 @@ namespace PLY return -1; } - template<> const std::string Traits< int >::name="int"; - template<> const std::string Traits< unsigned int >::name="unsigned int"; - template<> const std::string Traits< long >::name="long"; - template<> const std::string Traits< unsigned long >::name="unsigned long"; - template<> const std::string Traits< long long >::name="long long"; - template<> const std::string Traits< unsigned long long >::name="unsigned long long"; - - template<> PlyProperty Edge< int >::Properties[] = { PlyProperty( "v1" , PLY_INT , PLY_INT , offsetof( Edge , v1 ) ) , PlyProperty( "v2" , PLY_INT , PLY_INT , offsetof( Edge , v2 ) ) }; - template<> PlyProperty Edge< unsigned int >::Properties[] = { PlyProperty( "v1" , PLY_UINT , PLY_UINT , offsetof( Edge , v1 ) ) , PlyProperty( "v2" , PLY_UINT , PLY_UINT , offsetof( Edge , v2 ) ) }; - template<> PlyProperty Edge< long long >::Properties[] = { PlyProperty( "v1" , PLY_LONGLONG , PLY_LONGLONG , offsetof( Edge , v1 ) ) , PlyProperty( "v2" , PLY_LONGLONG , PLY_LONGLONG , offsetof( Edge , v2 ) ) }; - template<> PlyProperty Edge< unsigned long long >::Properties[] = { PlyProperty( "v1" , PLY_ULONGLONG , PLY_ULONGLONG , offsetof( Edge , v1 ) ) , PlyProperty( "v2" , PLY_ULONGLONG , PLY_ULONGLONG , offsetof( Edge , v2 ) ) }; - - template<> PlyProperty Face< int , false >::Properties[] = { PlyProperty( "vertex_indices" , PLY_INT , PLY_INT , offsetof( Face , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( Face , nr_vertices ) ) }; - template<> PlyProperty Face< unsigned int , false >::Properties[] = { PlyProperty( "vertex_indices" , PLY_UINT , PLY_UINT , offsetof( Face , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( Face , nr_vertices ) ) }; - template<> PlyProperty Face< long long , false >::Properties[] = { PlyProperty( "vertex_indices" , PLY_LONGLONG , PLY_LONGLONG , offsetof( Face , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( Face , nr_vertices ) ) }; - template<> PlyProperty Face< unsigned long long , false >::Properties[] = { PlyProperty( "vertex_indices" , PLY_ULONGLONG , PLY_ULONGLONG , offsetof( Face , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( Face , nr_vertices ) ) }; - template<> PlyProperty Face< int , true >::Properties[] = { PlyProperty( "vertex_indices" , PLY_INT , PLY_INT , offsetof( Face , vertices ) , 1 , PLY_CHAR , PLY_CHAR , offsetof( Face , nr_vertices ) ) }; - template<> PlyProperty Face< unsigned int , true >::Properties[] = { PlyProperty( "vertex_indices" , PLY_UINT , PLY_UINT , offsetof( Face , vertices ) , 1 , PLY_CHAR , PLY_CHAR , offsetof( Face , nr_vertices ) ) }; - template<> PlyProperty Face< long long , true >::Properties[] = { PlyProperty( "vertex_indices" , PLY_LONGLONG , PLY_LONGLONG , offsetof( Face , vertices ) , 1 , PLY_CHAR , PLY_CHAR , offsetof( Face , nr_vertices ) ) }; - template<> PlyProperty Face< unsigned long long , true >::Properties[] = { PlyProperty( "vertex_indices" , PLY_ULONGLONG , PLY_ULONGLONG , offsetof( Face , vertices ) , 1 , PLY_CHAR , PLY_CHAR , offsetof( Face , nr_vertices ) ) }; + template<> const inline std::string Traits< int >::name="int"; + template<> const inline std::string Traits< unsigned int >::name="unsigned int"; + template<> const inline std::string Traits< long >::name="long"; + template<> const inline std::string Traits< unsigned long >::name="unsigned long"; + template<> const inline std::string Traits< long long >::name="long long"; + template<> const inline std::string Traits< unsigned long long >::name="unsigned long long"; + + template<> const inline PlyProperty Edge< int >::Properties[] = { PlyProperty( "v1" , PLY_INT , PLY_INT , offsetof( Edge , v1 ) ) , PlyProperty( "v2" , PLY_INT , PLY_INT , offsetof( Edge , v2 ) ) }; + template<> const inline PlyProperty Edge< unsigned int >::Properties[] = { PlyProperty( "v1" , PLY_UINT , PLY_UINT , offsetof( Edge , v1 ) ) , PlyProperty( "v2" , PLY_UINT , PLY_UINT , offsetof( Edge , v2 ) ) }; + template<> const inline PlyProperty Edge< long long >::Properties[] = { PlyProperty( "v1" , PLY_LONGLONG , PLY_LONGLONG , offsetof( Edge , v1 ) ) , PlyProperty( "v2" , PLY_LONGLONG , PLY_LONGLONG , offsetof( Edge , v2 ) ) }; + template<> const inline PlyProperty Edge< unsigned long long >::Properties[] = { PlyProperty( "v1" , PLY_ULONGLONG , PLY_ULONGLONG , offsetof( Edge , v1 ) ) , PlyProperty( "v2" , PLY_ULONGLONG , PLY_ULONGLONG , offsetof( Edge , v2 ) ) }; + + template<> const inline PlyProperty Face< int , false >::Properties[] = { PlyProperty( "vertex_indices" , PLY_INT , PLY_INT , offsetof( Face , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( Face , nr_vertices ) ) }; + template<> const inline PlyProperty Face< unsigned int , false >::Properties[] = { PlyProperty( "vertex_indices" , PLY_UINT , PLY_UINT , offsetof( Face , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( Face , nr_vertices ) ) }; + template<> const inline PlyProperty Face< long long , false >::Properties[] = { PlyProperty( "vertex_indices" , PLY_LONGLONG , PLY_LONGLONG , offsetof( Face , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( Face , nr_vertices ) ) }; + template<> const inline PlyProperty Face< unsigned long long , false >::Properties[] = { PlyProperty( "vertex_indices" , PLY_ULONGLONG , PLY_ULONGLONG , offsetof( Face , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( Face , nr_vertices ) ) }; + template<> const inline PlyProperty Face< int , true >::Properties[] = { PlyProperty( "vertex_indices" , PLY_INT , PLY_INT , offsetof( Face , vertices ) , 1 , PLY_CHAR , PLY_CHAR , offsetof( Face , nr_vertices ) ) }; + template<> const inline PlyProperty Face< unsigned int , true >::Properties[] = { PlyProperty( "vertex_indices" , PLY_UINT , PLY_UINT , offsetof( Face , vertices ) , 1 , PLY_CHAR , PLY_CHAR , offsetof( Face , nr_vertices ) ) }; + template<> const inline PlyProperty Face< long long , true >::Properties[] = { PlyProperty( "vertex_indices" , PLY_LONGLONG , PLY_LONGLONG , offsetof( Face , vertices ) , 1 , PLY_CHAR , PLY_CHAR , offsetof( Face , nr_vertices ) ) }; + template<> const inline PlyProperty Face< unsigned long long , true >::Properties[] = { PlyProperty( "vertex_indices" , PLY_ULONGLONG , PLY_ULONGLONG , offsetof( Face , vertices ) , 1 , PLY_CHAR , PLY_CHAR , offsetof( Face , nr_vertices ) ) }; // Read inline PlyFile *ReadHeader( std::string fileName , int &fileType , std::vector< std::tuple< std::string , size_t , std::vector< PlyProperty > > > &elems , std::vector< std::string > &comments ) diff --git a/Src/PlyFile.h b/Src/PlyFile.h index d4fc0c29..e1654d92 100644 --- a/Src/PlyFile.h +++ b/Src/PlyFile.h @@ -165,7 +165,7 @@ namespace PoissonRecon } }; - std::ostream &operator << ( std::ostream &os , PlyProperty p ) + inline std::ostream &operator << ( std::ostream &os , PlyProperty p ) { if( p.is_list ) return os << "{ " << p.name << " , " << PlyTypes[ p.count_external ] << " -> " << PlyTypes[ p.count_internal ] << " , " << PlyTypes[ p.external_type ] << " -> " << PlyTypes[ p.internal_type ] << " , " << p.offset << " }"; else return os << "{ " << p.name << " , " << PlyTypes[ p.external_type ] << " -> " << PlyTypes[ p.internal_type ] << " , " << p.offset << " }"; diff --git a/Src/PlyFile.inl b/Src/PlyFile.inl index 4d2b034f..a47a1ae5 100644 --- a/Src/PlyFile.inl +++ b/Src/PlyFile.inl @@ -47,7 +47,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -const char *type_names[] = +static const char *type_names[] = { "invalid", "char", @@ -60,7 +60,6 @@ const char *type_names[] = "ulonglong", "float", "double", - "int8", // character 1 "uint8", // unsigned character 1 "int16", // short integer 2 @@ -73,7 +72,7 @@ const char *type_names[] = "float64", // double-precision float 8 }; -int ply_type_size[] = +static const int ply_type_size[] = { 0, 1, @@ -118,36 +117,39 @@ static const int named_prop = 1; /* write to a file the word describing a PLY file data type */ -void write_scalar_type( FILE * , int ); +inline void write_scalar_type( FILE * , int ); /* read a line from a file and break it up into separate words */ -std::vector< std::string > get_words( FILE * , char ** ); +inline std::vector< std::string > get_words( FILE * , char ** ); /* write to a file the word describing a PLY file data type */ -void write_scalar_type( FILE * , int ); +inline void write_scalar_type( FILE * , int ); /* write an item to a file */ -void write_binary_item( FILE * , int , int , unsigned int , long long , unsigned long long , double , int ); -void write_ascii_item ( FILE * , int , unsigned int , long long , unsigned long long , double , int ); +inline void write_binary_item( FILE * , int , int , unsigned int , long long , unsigned long long , double , int ); +inline void write_ascii_item ( FILE * , int , unsigned int , long long , unsigned long long , double , int ); /* store a value into where a pointer and a type specify */ -void store_item( void * , int , int , unsigned int , long long , unsigned long long , double ); +inline void store_item( void * , int , int , unsigned int , long long , unsigned long long , double ); /* return the value of a stored item */ -void get_stored_item( void * , int , int & , unsigned int & , long long & , unsigned long long & , double & ); +inline void get_stored_item( void * , int , int & , unsigned int & , long long & , unsigned long long & , double & ); /* return the value stored in an item, given ptr to it and its type */ -double get_item_value( const void * , int ); +inline double get_item_value( const void * , int ); /* get binary or ascii item and store it according to ptr and type */ -void get_ascii_item( const std::string & , int , int & , unsigned int & , long long & , unsigned long long & , double & ); -void get_binary_item( FILE * , int , int , int & , unsigned int & , long long & , unsigned long long & , double & ); +inline void get_ascii_item( const std::string & , int , int & , unsigned int & , long long & , unsigned long long & , double & ); +inline void get_binary_item( FILE * , int , int , int & , unsigned int & , long long & , unsigned long long & , double & ); /* byte ordering */ -void get_native_binary_type(); -void swap_bytes( void * , int ); +inline void get_native_binary_type(); +inline void swap_bytes( void * , int ); + +inline void check_types( void ); -void check_types(); +inline int get_prop_type( const std::string &type_name ); +inline void setup_other_props( PlyElement *elem ); /*************/ /* Writing */ @@ -1673,7 +1675,7 @@ void get_binary_item( FILE *fp , int file_type , int type , int &int_val , unsig ptr = ( void * )c; - if( fread( ptr , ply_type_size[type] , 1 , fp )!=1 ) ERROR_OUT( "fread() failed -- aborting: " , std::string( type_names[type] ) ); + if( fread( ptr , ply_type_size[type] , 1 , fp )!=1 ) ERROR_OUT( "fread() failed -- aborting: " , std::string( type_names[type] ) ); if( ( file_type!=native_binary_type ) && ( ply_type_size[type]>1 ) ) swap_bytes( (char *)ptr , ply_type_size[type] ); switch( type ) diff --git a/Src/Polynomial.inl b/Src/Polynomial.inl index 88940038..39e09554 100644 --- a/Src/Polynomial.inl +++ b/Src/Polynomial.inl @@ -55,9 +55,10 @@ 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< 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< > inline double Polynomial< 0 >::operator() ( double t ) const { return coefficients[0]; } +template< > inline double Polynomial< 1 >::operator() ( double t ) const { return coefficients[0]+coefficients[1]*t; } +template< > inline double Polynomial< 2 >::operator() ( double t ) const { return coefficients[0]+(coefficients[1]+coefficients[2]*t)*t; } template< int Degree > double Polynomial::operator() ( double t ) const{ double v=coefficients[Degree]; @@ -250,8 +251,8 @@ void Polynomial::printnl(void) const{ printf("\n"); } -template<> -int Polynomial< 1 >::getSolutions( double c , double* roots , double EPS ) const +template< > +inline int Polynomial< 1 >::getSolutions( double c , double* roots , double EPS ) const { std::complex< double > _roots[4]; int _rCount = Factor( coefficients[1] , coefficients[0]-c , _roots , EPS ); @@ -260,8 +261,8 @@ int Polynomial< 1 >::getSolutions( double c , double* roots , double EPS ) const return rCount; } -template<> -int Polynomial< 2 >::getSolutions( double c , double* roots , double EPS ) const +template< > +inline int Polynomial< 2 >::getSolutions( double c , double* roots , double EPS ) const { std::complex< double > _roots[4]; int _rCount = Factor( coefficients[2] , coefficients[1] , coefficients[0]-c , _roots , EPS ); @@ -270,8 +271,8 @@ int Polynomial< 2 >::getSolutions( double c , double* roots , double EPS ) const return rCount; } -template<> -int Polynomial< 3 >::getSolutions( double c , double* roots , double EPS ) const +template< > +inline int Polynomial< 3 >::getSolutions( double c , double* roots , double EPS ) const { std::complex< double > _roots[4]; int _rCount = Factor( coefficients[3] , coefficients[2] , coefficients[1] , coefficients[0]-c , _roots , EPS ); @@ -281,8 +282,8 @@ int Polynomial< 3 >::getSolutions( double c , double* roots , double EPS ) const } #if 0 -template<> -int Polynomial< 4 >::getSolutions( double c , double* roots , double EPS ) const +template< > +inline int Polynomial< 4 >::getSolutions( double c , double* roots , double EPS ) const { std::complex< double > _roots[4]; int _rCount = Factor( coefficients[4] , coefficients[3] , coefficients[2] , coefficients[1] , coefficients[0]-c , _roots , EPS ); @@ -301,7 +302,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 ) +inline Polynomial< 0 > Polynomial< 0 >::BSplineComponent( int i ) { Polynomial p; p.coefficients[0] = 1.; @@ -331,7 +332,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< > inline 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 ) { @@ -347,7 +348,8 @@ template< int Degree > void Polynomial< Degree >::BSplineComponentValues( double } // Using the recurrence formulation for Pascal's triangle -template< > void Polynomial< 0 >::BinomialCoefficients( int bCoefficients[1] ){ bCoefficients[0] = 1; } +template< > inline 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 ); diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h index 5cf556da..ebf73e15 100644 --- a/Src/Reconstructors.h +++ b/Src/Reconstructors.h @@ -41,7 +41,7 @@ namespace PoissonRecon namespace Reconstructor { - unsigned int ProfilerMS = 20; // The number of ms at which to poll the performance (set to zero for no polling) + static unsigned int ProfilerMS = 20; // The number of ms at which to poll the performance (set to zero for no polling) static const unsigned int DataDegree = 0; // The order of the B-Spline used to splat in data for auxiliary data interpolation static const unsigned int WeightDegree = 2; // The order of the B-Spline used to splat in the weights for density estimation diff --git a/Src/RegularGrid.h b/Src/RegularGrid.h index ec561f1e..8ea9fbc6 100644 --- a/Src/RegularGrid.h +++ b/Src/RegularGrid.h @@ -42,22 +42,22 @@ namespace PoissonRecon template<> struct RegularGridDataType<> { - static void Write( FILE *fp , unsigned int dim , std::string name ); - static bool Read( FILE *fp , unsigned int dim , std::string name ); + static inline void Write( FILE *fp , unsigned int dim , std::string name ); + static inline bool Read( FILE *fp , unsigned int dim , std::string name ); }; template<> struct RegularGridDataType< char >{ static const std::string Name ; static void Write( FILE *fp ){ RegularGridDataType<>::Write( fp , 1 , Name ); } ; static bool Read( FILE *fp ){ return RegularGridDataType<>::Read( fp , 1 , Name ); } }; - const std::string RegularGridDataType< char >::Name = "CHAR"; + inline const std::string RegularGridDataType< char >::Name = "CHAR"; template<> struct RegularGridDataType< unsigned char >{ static const std::string Name ; static void Write( FILE *fp ){ RegularGridDataType<>::Write( fp , 1 , Name ); } static bool Read( FILE *fp ){ return RegularGridDataType<>::Read( fp , 1 , Name ); } }; - const std::string RegularGridDataType< unsigned char >::Name = "UNSIGNED_CHAR"; + inline const std::string RegularGridDataType< unsigned char >::Name = "UNSIGNED_CHAR"; template<> struct RegularGridDataType< int >{ static const std::string Name ; static void Write( FILE *fp ){ RegularGridDataType<>::Write( fp , 1 , Name ); } static bool Read( FILE *fp ){ return RegularGridDataType<>::Read( fp , 1 , Name ); } }; - const std::string RegularGridDataType< int >::Name = "INT"; + inline const std::string RegularGridDataType< int >::Name = "INT"; template<> struct RegularGridDataType< unsigned int >{ static const std::string Name ; static void Write( FILE *fp ){ RegularGridDataType<>::Write( fp , 1 , Name ); } static bool Read( FILE *fp ){ return RegularGridDataType<>::Read( fp , 1 , Name ); } }; - const std::string RegularGridDataType< unsigned int >::Name = "UNSIGNED_INT"; + inline const std::string RegularGridDataType< unsigned int >::Name = "UNSIGNED_INT"; template<> struct RegularGridDataType< float >{ static const std::string Name ; static void Write( FILE *fp ){ RegularGridDataType<>::Write( fp , 1 , Name ); } static bool Read( FILE *fp ){ return RegularGridDataType<>::Read( fp , 1 , Name ); } }; - const std::string RegularGridDataType< float >::Name = "FLOAT"; + inline const std::string RegularGridDataType< float >::Name = "FLOAT"; template<> struct RegularGridDataType< double >{ static const std::string Name ; static void Write( FILE *fp ){ RegularGridDataType<>::Write( fp , 1 , Name ); } static bool Read( FILE *fp ){ return RegularGridDataType<>::Read( fp , 1 , Name ); } }; - const std::string RegularGridDataType< double >::Name = "DOUBLE"; + inline const std::string RegularGridDataType< double >::Name = "DOUBLE"; template< typename Real , unsigned int Dim > struct RegularGridDataType< Point< Real , Dim > >{ static const std::string Name ; static void Write( FILE *fp ){ RegularGridDataType<>::Write( fp , Dim , Name ); } static bool Read( FILE *fp ){ return RegularGridDataType<>::Read( fp , Dim , Name ); } }; template< typename Real , unsigned int Dim > const std::string RegularGridDataType< Point< Real , Dim > >::Name = RegularGridDataType< Real >::Name; diff --git a/Src/VertexFactory.h b/Src/VertexFactory.h index d481e63b..c39ef78a 100644 --- a/Src/VertexFactory.h +++ b/Src/VertexFactory.h @@ -57,8 +57,8 @@ namespace PoissonRecon UNKNOWN }; - int ToPlyType( TypeOnDisk typeOnDisk ); - TypeOnDisk FromPlyType( int plyType ); + inline int ToPlyType( TypeOnDisk typeOnDisk ); + inline TypeOnDisk FromPlyType( int plyType ); template< typename Real > TypeOnDisk GetTypeOnDisk( void ); template< typename Real > From db726522d435d99b97da423f15fc911ad6592e48 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Thu, 21 Nov 2024 08:54:24 -0500 Subject: [PATCH 70/86] Version 18.50 --- Src/Extrapolator.h | 2 +- Src/FEMTree.System.inl | 43 ++++++------ Src/FEMTree.WeightedSamples.inl | 24 +++---- Src/FEMTree.h | 80 +++++++++++++++------ Src/FEMTree.inl | 55 ++++++++------- Src/Geometry.h | 120 +++++++++++++++++++++----------- Src/MyAtomic.h | 55 +++++++++++++++ Src/PoissonRecon.client.inl | 10 +-- Src/PreProcessor.h | 2 +- Src/Reconstruction.example.cpp | 14 ++++ Src/Reconstructors.h | 14 ++-- 11 files changed, 282 insertions(+), 137 deletions(-) diff --git a/Src/Extrapolator.h b/Src/Extrapolator.h index 87f73d15..c053d14b 100644 --- a/Src/Extrapolator.h +++ b/Src/Extrapolator.h @@ -207,7 +207,7 @@ namespace PoissonRecon profiler.reset(); auto SampleFunctor = [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return (*samples)[i]; }; auto SampleDataFunctor = [&]( size_t i ) -> const AuxData & { return (*sampleAuxData)[i]; }; - auxData = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( tree.template setExtrapolatedDataField< DataSig , false , 0 , AuxData >( samples->size() , SampleFunctor , SampleDataFunctor , (DensityEstimator*)nullptr ) ); + auxData = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( tree.template setExtrapolatedDataField< DataSig , false , 0 , AuxData >( zeroAuxData , samples->size() , SampleFunctor , SampleDataFunctor , (DensityEstimator*)nullptr ) ); delete sampleAuxData; if( params.verbose ) std::cout << "# Got aux data: " << profiler << std::endl; } diff --git a/Src/FEMTree.System.inl b/Src/FEMTree.System.inl index 8eb50f62..99195974 100644 --- a/Src/FEMTree.System.inl +++ b/Src/FEMTree.System.inl @@ -1338,7 +1338,7 @@ void FEMTree< Dim , Real >::_updateRestrictedIntegralConstraints( UIntPack< FEMS { for( int i=0 ; i::Size ; i++ ) if( _isValidFEM1Node( nodes[i] ) ) { - AddAtomic( restrictedConstraints[ nodes[i]->nodeData.nodeIndex ] , solution * (Real)stencilValues[i] ); + Atomic< T >::Add( restrictedConstraints[ nodes[i]->nodeData.nodeIndex ] , solution * (Real)stencilValues[i] ); } } else @@ -1347,13 +1347,12 @@ void FEMTree< Dim , Real >::_updateRestrictedIntegralConstraints( UIntPack< FEMS { LocalDepth _d ; LocalOffset _off; _localDepthAndOffset( nodes[i] , _d , _off ); - AddAtomic( restrictedConstraints[ nodes[i]->nodeData.nodeIndex ] , solution * (Real)F.pcIntegrate( _off , off ) ); + Atomic< T >::Add( restrictedConstraints[ nodes[i]->nodeData.nodeIndex ] , solution * (Real)F.pcIntegrate( _off , off ) ); } } } } - } - ); + } ); } template< unsigned int Dim , class Real > @@ -1444,19 +1443,19 @@ void FEMTree< Dim , Real >::_updateRestrictedInterpolationConstraints( const Poi ZeroUIntPack< Dim >() , SupportSizes() , [&]( int d , int i ){ s[d] = i; } , [&]( const FEMTreeNode* node ) - { - if( _isValidFEM1Node( node ) ) { - LocalDepth d ; LocalOffset off; - _localDepthAndOffset( node , d , off ); - CumulativeDerivativeValues< Real , Dim , PointD > values = peState.template dValues< Real , CumulativeDerivatives< Dim , PointD > >( off ); - T temp = {}; - for( int d=0 ; d::Size ; d++ ) temp += dualValues[d] * values[d]; - AddAtomic( restrictedConstraints[ node->nodeData.nodeIndex ] , temp ); - } - } , + if( _isValidFEM1Node( node ) ) + { + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + CumulativeDerivativeValues< Real , Dim , PointD > values = peState.template dValues< Real , CumulativeDerivatives< Dim , PointD > >( off ); + T temp = {}; + for( int d=0 ; d::Size ; d++ ) temp += dualValues[d] * values[d]; + Atomic< T >::Add( restrictedConstraints[ node->nodeData.nodeIndex ] , temp ); + } + } , neighbors.neighbors() - ); + ); } } } @@ -3033,7 +3032,7 @@ void FEMTree< Dim , Real >::_addFEMConstraints( UIntPack< FEMSigs ... > , UIntPa unsigned int idx = indices[i]; if( nodes[idx] ) { - AddAtomic( _constraints[ nodes[idx]->nodeData.nodeIndex ] , _StencilDot< double , T , CDim >( stencilValues[idx] , data ) ); + Atomic< T >::Add( _constraints[ nodes[idx]->nodeData.nodeIndex ] , _StencilDot< double , T , CDim >( stencilValues[idx] , data ) ); } } } @@ -3045,7 +3044,7 @@ void FEMTree< Dim , Real >::_addFEMConstraints( UIntPack< FEMSigs ... > , UIntPa if( nodes[idx] ) { LocalDepth _d ; LocalOffset _off ; _localDepthAndOffset( nodes[idx] , _d , _off ); - AddAtomic( _constraints[ nodes[idx]->nodeData.nodeIndex ] , _StencilDot< double , T , CDim >( F.pcIntegrate( _off , off ) , data ) ); + Atomic< T >::Add( _constraints[ nodes[idx]->nodeData.nodeIndex ] , _StencilDot< double , T , CDim >( F.pcIntegrate( _off , off ) , data ) ); } } } @@ -3198,14 +3197,14 @@ void FEMTree< Dim , Real >::_addInterpolationConstraints( DenseNodeData< T , UIn [&]( int d , int i ){ s[d] = i; } , [&]( const FEMTreeNode* _node ) { - if( _isValidFEM1Node( _node ) && !_node->nodeData.getDirichletElementFlag() ) - { + if( _isValidFEM1Node( _node ) && !_node->nodeData.getDirichletElementFlag() ) + { LocalDepth _d ; LocalOffset _off ; _localDepthAndOffset( _node , _d , _off ); CumulativeDerivativeValues< Real , Dim , PointD > values = WrapperLambda( eState , _off ); T dot = {}; for( int s=0 ; s::Size ; s++ ) dot += pData.dualValues[s] * values[s]; - AddAtomic( constraints[ _node->nodeData.nodeIndex ] , dot ); - } + Atomic< T >::Add( constraints[ _node->nodeData.nodeIndex ] , dot ); + } } , neighbors.neighbors() ); @@ -3456,7 +3455,7 @@ double FEMTree< Dim , Real >::_dot( UIntPack< FEMSigs1 ... > , UIntPack< FEMSigs LocalDepth _d ; LocalOffset _off ; _localDepthAndOffset( node , _d , _off ); _dot = (*_data1) * F.cpIntegrate( off , _off )[0]; } - AddAtomic( cumulative2[ node->nodeData.nodeIndex ] , _dot ); + Atomic< T >::Add( cumulative2[ node->nodeData.nodeIndex ] , _dot ); } } , neighbors.neighbors() , _stencil() diff --git a/Src/FEMTree.WeightedSamples.inl b/Src/FEMTree.WeightedSamples.inl index c6d4e6c6..823835a2 100644 --- a/Src/FEMTree.WeightedSamples.inl +++ b/Src/FEMTree.WeightedSamples.inl @@ -280,7 +280,7 @@ void FEMTree< Dim , Real >::_getSampleDepthAndWeight( const DensityEstimator< We template< unsigned int Dim , class Real > template< bool CreateNodes , bool ThreadSafe , class V , unsigned int ... DataSigs > -void FEMTree< Dim , Real >::_splatPointData( Allocator< FEMTreeNode > *nodeAllocator , FEMTreeNode* node , Point< Real , Dim > position , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& dataInfo , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey ) +void FEMTree< Dim , Real >::_splatPointData( V zero , Allocator< FEMTreeNode > *nodeAllocator , FEMTreeNode* node , Point< Real , Dim > position , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& dataInfo , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey ) { typedef UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportSize ... > SupportSizes; double values[ Dim ][ SupportSizes::Max() ]; @@ -295,13 +295,13 @@ void FEMTree< Dim , Real >::_splatPointData( Allocator< FEMTreeNode > *nodeAlloc ( ZeroUIntPack< Dim >() , UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportSize ... >() , [&]( int d , int i ){ scratch[d+1] = scratch[d] * values[d][i]; } , - [&]( FEMTreeNode* node ){ if( IsActiveNode< Dim >( node ) ) AddAtomic( dataInfo[ node ] , v * (Real)scratch[Dim] ); } , + [&]( FEMTreeNode* node ){ if( IsActiveNode< Dim >( node ) ) Atomic< V >::Add( dataInfo.at( node , zero ) , v * (Real)scratch[Dim] ); } , neighbors.neighbors() ); } template< unsigned int Dim , class Real > template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > -Point< Real , 2 > FEMTree< Dim , Real >::_splatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >& densityWeights , Real minDepthCutoff , Point< Real , Dim > position , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& dataInfo , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , LocalDepth minDepth , LocalDepth maxDepth , int dim , Real depthBias ) +Point< Real , 2 > FEMTree< Dim , Real >::_splatPointData( V zero , Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >& densityWeights , Real minDepthCutoff , Point< Real , Dim > position , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& dataInfo , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , LocalDepth minDepth , LocalDepth maxDepth , int dim , Real depthBias ) { // Get the depth and weight at position Real weight , depth; @@ -361,9 +361,9 @@ Point< Real , 2 > FEMTree< Dim , Real >::_splatPointData( Allocator< FEMTreeNode #ifdef SHOW_WARNINGS #warning "you've got me gcc version<5" #endif // SHOW_WARNINGS - _splatPointData< CreateNodes , ThreadSafe , V >( nodeAllocator , temp , position , _v , dataInfo , dataKey ); + _splatPointData< CreateNodes , ThreadSafe , V >( zero , nodeAllocator , temp , position , _v , dataInfo , dataKey ); #else // !__GNUC__ || __GNUC__ >=5 - _splatPointData< CreateNodes , ThreadSafe , V , DataSigs ... >( nodeAllocator , temp , position , _v , dataInfo , dataKey ); + _splatPointData< CreateNodes , ThreadSafe , V , DataSigs ... >( zero , nodeAllocator , temp , position , _v , dataInfo , dataKey ); #endif // __GNUC__ || __GNUC__ < 4 }; Splat( temp , (Real)dx ); @@ -373,7 +373,7 @@ Point< Real , 2 > FEMTree< Dim , Real >::_splatPointData( Allocator< FEMTreeNode template< unsigned int Dim , class Real > template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > -Point< Real , 2 > FEMTree< Dim , Real >::_splatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >& densityWeights , Real minDepthCutoff , Point< Real , Dim > position , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& dataInfo , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , LocalDepth minDepth , std::function< int ( Point< Real , Dim > ) > &pointDepthFunctor , int dim , Real depthBias ) +Point< Real , 2 > FEMTree< Dim , Real >::_splatPointData( V zero , Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >& densityWeights , Real minDepthCutoff , Point< Real , Dim > position , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& dataInfo , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , LocalDepth minDepth , std::function< int ( Point< Real , Dim > ) > &pointDepthFunctor , int dim , Real depthBias ) { // Get the depth and weight at position Real sampleWeight , sampleDepth; @@ -437,9 +437,9 @@ Point< Real , 2 > FEMTree< Dim , Real >::_splatPointData( Allocator< FEMTreeNode #ifdef SHOW_WARNINGS #warning "you've got me gcc version<5" #endif // SHOW_WARNINGS - _splatPointData< CreateNodes , ThreadSafe , V >( nodeAllocator , temp , position , _v , dataInfo , dataKey ); + _splatPointData< CreateNodes , ThreadSafe , V >( zero , nodeAllocator , temp , position , _v , dataInfo , dataKey ); #else // !__GNUC__ || __GNUC__ >=5 - _splatPointData< CreateNodes , ThreadSafe , V , DataSigs ... >( nodeAllocator , temp , position , _v , dataInfo , dataKey ); + _splatPointData< CreateNodes , ThreadSafe , V , DataSigs ... >( zero , nodeAllocator , temp , position , _v , dataInfo , dataKey ); #endif // __GNUC__ || __GNUC__ < 4 }; Splat( temp , (Real)dx ); @@ -449,7 +449,7 @@ Point< Real , 2 > FEMTree< Dim , Real >::_splatPointData( Allocator< FEMTreeNode template< unsigned int Dim , class Real > template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > -Point< Real , 2 > FEMTree< Dim , Real >::_multiSplatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >* densityWeights , FEMTreeNode* node , Point< Real , Dim > position , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& dataInfo , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , int dim ) +Point< Real , 2 > FEMTree< Dim , Real >::_multiSplatPointData( V zero , Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >* densityWeights , FEMTreeNode* node , Point< Real , Dim > position , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& dataInfo , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , int dim ) { typedef UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportSize ... > SupportSizes; Real _depth , weight; @@ -474,7 +474,7 @@ Point< Real , 2 > FEMTree< Dim , Real >::_multiSplatPointData( Allocator< FEMTre ( ZeroUIntPack< Dim >() , UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportSize ... >() , [&]( int d , int i ){ scratch[d+1] = scratch[d] * values[d][i]; } , - [&]( FEMTreeNode* node ){ if( IsActiveNode< Dim >( node ) ) dataInfo[ node ] += __v * (Real)scratch[Dim]; } , + [&]( FEMTreeNode* node ){ if( IsActiveNode< Dim >( node ) ) Atomic< V >::Add( dataInfo.at( node , zero ) , __v * (Real)scratch[Dim] ) ; } , neighbors.neighbors() ); } @@ -483,14 +483,14 @@ Point< Real , 2 > FEMTree< Dim , Real >::_multiSplatPointData( Allocator< FEMTre template< unsigned int Dim , class Real > template< unsigned int WeightDegree , class V , unsigned int ... DataSigs > -Real FEMTree< Dim , Real >::_nearestMultiSplatPointData( const DensityEstimator< WeightDegree >* densityWeights , FEMTreeNode* node , Point< Real , Dim > position , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& dataInfo , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , int dim ) +Real FEMTree< Dim , Real >::_nearestMultiSplatPointData( V zero , const DensityEstimator< WeightDegree >* densityWeights , FEMTreeNode* node , Point< Real , Dim > position , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& dataInfo , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , int dim ) { Real _depth , weight; if( densityWeights ) _getSampleDepthAndWeight( *densityWeights , position , weightKey , _depth , weight ); else weight = (Real)1.; V _v = v * weight; - for( FEMTreeNode* _node=node ; _localDepth( _node )>=0 ; _node=_node->parent ) if( IsActiveNode< Dim >( _node ) ) dataInfo[ _node ] += _v * (Real)pow( 1<<_localDepth( _node ) , dim ); + for( FEMTreeNode* _node=node ; _localDepth( _node )>=0 ; _node=_node->parent ) if( IsActiveNode< Dim >( _node ) ) Atomic< V >::Add( dataInfo.at( _node , zero ) , _v * (Real)pow( 1<<_localDepth( _node ) , dim ) ); return weight; } ////////////////////////////////// diff --git a/Src/FEMTree.h b/Src/FEMTree.h index 3bdd7071..3828f22c 100644 --- a/Src/FEMTree.h +++ b/Src/FEMTree.h @@ -334,7 +334,9 @@ namespace PoissonRecon size_t reserved( void ) const { return _indices.size(); } Data* operator()( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ){ return ( node->nodeData.nodeIndex<0 || node->nodeData.nodeIndex>=(node_index_type)_indices.size() || _indices[ node->nodeData.nodeIndex ]==-1 ) ? NULL : &_data[ _indices[ node->nodeData.nodeIndex ] ]; } const Data* operator()( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ) const { return ( node->nodeData.nodeIndex<0 || node->nodeData.nodeIndex>=(node_index_type)_indices.size() || _indices[ node->nodeData.nodeIndex ]==-1 ) ? NULL : &_data[ _indices[ node->nodeData.nodeIndex ] ]; } - Data& operator[]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ) + + Data& operator[]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node ){ return at( node ); } + Data &at( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *node , Data zero=Data() ) { _indices.resize( node->nodeData.nodeIndex+1 , -1 ); @@ -354,7 +356,7 @@ namespace PoissonRecon if( _index==-1 ) { size_t sz = _data.size(); - _data.resize( sz + 1 ); + _data.resize( sz+1 , zero ); #ifdef SANITIZED_PR _index = (node_index_type)sz; SetAtomic( *indexPtr , _index ); @@ -1418,10 +1420,47 @@ namespace PoissonRecon }; template< class Real , unsigned int Dim > - void AddAtomic( volatile Point< Real , Dim > & a , const Point< Real , Dim >& b ) + struct Atomic< Point< Real , Dim > > { - for( int d=0 ; d; + static void Add( volatile Value &a , const Value &b ){ for( unsigned int d=0 ; d + struct Atomic< Point< Real > > + { + using Value = Point< Real >; + static void Add( volatile Value &a , const Value &b ) + { + if( a._dim !=b._dim ) ERROR_OUT( "Sizes don't match: " , a._dim , " != " , b._dim ); + for( unsigned int d=0 ; d + struct Atomic< ProjectiveData< Data , Real > > + { + using Value = ProjectiveData< Data , Real >; + static void Add( volatile Value &a , const Value &b ){ Atomic< Real >::Add( a.weight , b.weight ) ; Atomic< Data >::Add( a.data , b.data ); } + }; + + template< typename Real , typename FirstType , typename ... RestTypes > + struct Atomic< DirectSum< Real , FirstType , RestTypes... > > + { + using Value = DirectSum< Real , FirstType , RestTypes... >; + static void Add( volatile Value &a , const Value &b ) + { + Atomic< FirstType >::Add( a._first , b._first ); + Atomic< DirectSum< Real , RestTypes... > >::Add( a._rest , b._rest ); + } + }; + + template< typename Real > + struct Atomic< DirectSum< Real > > + { + using Value = DirectSum< Real >; + static void Add( volatile Value &a , const Value &b ){} + }; template< class Real , unsigned int Dim > Point< Real , Dim > ReadAtomic( const volatile Point< Real , Dim > & a ) @@ -2297,11 +2336,11 @@ namespace PoissonRecon template< unsigned int WeightDegree , class WeightKey > void _getSampleDepthAndWeight( const DensityEstimator< WeightDegree >& densityWeights , Point< Real , Dim > position , WeightKey& weightKey , Real& depth , Real& weight ) const; - template< bool CreateNodes , bool ThreadSafe , class V , unsigned int ... DataSigs > void _splatPointData( Allocator< FEMTreeNode > *nodeAllocator , FEMTreeNode* node , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey ); - template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > Point< Real , 2 > _splatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >& densityWeights , Real minDepthCutoff , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , LocalDepth minDepth , LocalDepth maxDepth , int dim , Real depthBias ); - template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > Point< Real , 2 > _splatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >& densityWeights , Real minDepthCutoff , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , LocalDepth minDepth , std::function< int ( Point< Real , Dim > ) > &pointDepthFunctor , int dim , Real depthBias ); - template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > Point< Real , 2 > _multiSplatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >* densityWeights , FEMTreeNode* node , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , int dim ); - template< unsigned int WeightDegree , class V , unsigned int ... DataSigs > Real _nearestMultiSplatPointData( const DensityEstimator< WeightDegree >* densityWeights , FEMTreeNode* node , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , int dim=Dim ); + template< bool CreateNodes , bool ThreadSafe , class V , unsigned int ... DataSigs > void _splatPointData( V zero , Allocator< FEMTreeNode > *nodeAllocator , FEMTreeNode* node , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey ); + template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > Point< Real , 2 > _splatPointData( V zero , Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >& densityWeights , Real minDepthCutoff , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , LocalDepth minDepth , LocalDepth maxDepth , int dim , Real depthBias ); + template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > Point< Real , 2 > _splatPointData( V zero , Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >& densityWeights , Real minDepthCutoff , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , LocalDepth minDepth , std::function< int ( Point< Real , Dim > ) > &pointDepthFunctor , int dim , Real depthBias ); + template< bool CreateNodes , bool ThreadSafe , unsigned int WeightDegree , class V , unsigned int ... DataSigs > Point< Real , 2 > _multiSplatPointData( V zero , Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >* densityWeights , FEMTreeNode* node , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , int dim ); + template< unsigned int WeightDegree , class V , unsigned int ... DataSigs > Real _nearestMultiSplatPointData( V zero , const DensityEstimator< WeightDegree >* densityWeights , FEMTreeNode* node , Point< Real , Dim > point , V v , SparseNodeData< V , UIntPack< DataSigs ... > >& data , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , int dim=Dim ); template< class V , class Coefficients , unsigned int D , unsigned int ... DataSigs > void _addEvaluation( const Coefficients& coefficients , Point< Real , Dim > p , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey , V &value ) const; template< class V , class Coefficients , unsigned int D , unsigned int ... DataSigs > @@ -2593,33 +2632,32 @@ namespace PoissonRecon void updateDensityEstimator( typename FEMTree::template DensityEstimator< DensityDegree > &density , const std::vector< PointSample >& samples , LocalDepth minSplatDepth , LocalDepth maxSplatDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real samplesPerNode ); template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > - SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction ); + SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( OutData zero , UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction ); #if defined(_WIN32) || defined(_WIN64) template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > - SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction = []( InData ){ return 0.f; } ); + SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( OutData zero , UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction = []( InData ){ return 0.f; } ); #else // !_WIN32 && !_WIN64 template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > - SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction = []( InData ){ return (Real)0; } ); + SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( OutData zero , UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction = []( InData ){ return (Real)0; } ); #endif // _WIN32 || _WIN64 template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > - SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction ); + SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( OutData zero , UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction ); #if defined(_WIN32) || defined(_WIN64) template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > - SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction = []( InData ){ return 0.f; } ); + SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( OutData zero , UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction = []( InData ){ return 0.f; } ); #else // !_WIN32 && !_WIN64 template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > - SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction = []( InData ){ return (Real)0; } ); + SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( OutData zero , UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction = []( InData ){ return (Real)0; } ); #endif // _WIN32 || _WIN64 template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data > - SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > setExtrapolatedDataField( const std::vector< PointSample >& samples , const std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density , bool nearest=false ); + SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > setExtrapolatedDataField( Data zero , const std::vector< PointSample >& samples , const std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density , bool nearest=false ); template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data > - void updateExtrapolatedDataField( SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > &dataField , const std::vector< PointSample >& samples , const std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density , bool nearest=false ); - + void updateExtrapolatedDataField( Data zero , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > &dataField , const std::vector< PointSample >& samples , const std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density , bool nearest=false ); template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data , class SampleFunctor /* = std::function< const PointSample & (size_t) >*/ , class SampleDataFunctor /* = std::function< const Data & (size_t) > */ > - SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > setExtrapolatedDataField( size_t sampleNum , SampleFunctor sampleFunctor , SampleDataFunctor sampleDataFunctor , const DensityEstimator< DensityDegree >* density , bool nearest=false ); + SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > setExtrapolatedDataField( Data zero , size_t sampleNum , SampleFunctor sampleFunctor , SampleDataFunctor sampleDataFunctor , const DensityEstimator< DensityDegree >* density , bool nearest=false ); template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data , class SampleFunctor /* = std::function< const PointSample & (size_t) >*/ , class SampleDataFunctor /* = std::function< const Data & (size_t) > */ > - void updateExtrapolatedDataField( SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > &dataField , size_t sampleNum , SampleFunctor sampleFunctor , SampleDataFunctor sampleDataFunctor , const DensityEstimator< DensityDegree >* density , bool nearest=false ); + void updateExtrapolatedDataField( Data zero , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > &dataField , size_t sampleNum , SampleFunctor sampleFunctor , SampleDataFunctor sampleDataFunctor , const DensityEstimator< DensityDegree >* density , bool nearest=false ); template< unsigned int MaxDegree , unsigned int SystemDegree , typename AddNodeFunctor , typename HasDataFunctor , typename IsDirichletLeafFunctor , typename ... InterpolationInfos , typename ... DenseOrSparseNodeData > std::vector< node_index_type > finalizeForMultigridWithDirichlet( LocalDepth baseDepth , const AddNodeFunctor addNodeFunctor , const HasDataFunctor hasDataFunctor , const IsDirichletLeafFunctor isDirichletLeafFunctor , std::tuple< InterpolationInfos *... > interpolationInfos , std::tuple< DenseOrSparseNodeData *... > data ); template< unsigned int MaxDegree , unsigned int SystemDegree , typename AddNodeFunctor , typename HasDataFunctor , typename IsDirichletLeafFunctor , typename ... InterpolationInfos > std::vector< node_index_type > finalizeForMultigridWithDirichlet( LocalDepth baseDepth , const AddNodeFunctor addNodeFunctor , const HasDataFunctor hasDataFunctor , const IsDirichletLeafFunctor isDirichletLeafFunctor , std::tuple< InterpolationInfos *... > interpolationInfos ){ return finalizeForMultigridWithDirichlet< MaxDegree , SystemDegree , AddNodeFunctor , HasDataFunctor >( baseDepth , addNodeFunctor , hasDataFunctor , isDirichletLeafFunctor , interpolationInfos , std::make_tuple() ); } diff --git a/Src/FEMTree.inl b/Src/FEMTree.inl index 69da9217..d0441d8d 100644 --- a/Src/FEMTree.inl +++ b/Src/FEMTree.inl @@ -882,7 +882,7 @@ typename FEMTree< Dim , Real >::template DensityEstimator< DensityDegree >* FEMT template< unsigned int Dim , class Real > template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > -SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData& ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction ) +SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setInterpolatedDataField( OutData zero , UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData& ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction ) { std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction = [&]( InData in , OutData &out , Real &bias ) { @@ -893,12 +893,12 @@ SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setI } else return false; }; - return setInterpolatedDataField( UIntPack< DataSigs ... >() , samples , data , density , minDepth , maxDepth , minDepthCutoff , pointDepthAndWeight , ConversionAndBiasFunction ); + return setInterpolatedDataField( zero , UIntPack< DataSigs ... >() , samples , data , density , minDepth , maxDepth , minDepthCutoff , pointDepthAndWeight , ConversionAndBiasFunction ); } template< unsigned int Dim , class Real > template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > -SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction ) +SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setInterpolatedDataField( OutData zero , UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction ) { // typename FEMTreeNode::SubTreeExtractor subtreeExtractor( _spaceRoot ); SubTreeExtractor subtreeExtractor( _spaceRoot , _depthOffset ); @@ -941,9 +941,9 @@ SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setI #ifdef SHOW_WARNINGS #warning "you've got me gcc version<5" #endif // SHOW_WARNINGS - if( density ) pointDepthAndWeightSums[thread] += _splatPointData< true , true , DensityDegree , OutData >( nodeAllocator , *density , minDepthCutoff , p , out , dataField , densityKey , oneKey ? *( (DataKey*)&densityKey ) : dataKey , minDepth , maxDepth , Dim , depthBias ) * sample.weight; + if( density ) pointDepthAndWeightSums[thread] += _splatPointData< true , true , DensityDegree , OutData >( zero , nodeAllocator , *density , minDepthCutoff , p , out , dataField , densityKey , oneKey ? *( (DataKey*)&densityKey ) : dataKey , minDepth , maxDepth , Dim , depthBias ) * sample.weight; #else // !__GNUC__ || __GNUC__ >=5 - if( density ) pointDepthAndWeightSums[thread] += _splatPointData< true , true , DensityDegree , OutData , DataSigs ... >( nodeAllocator , *density , minDepthCutoff , p , out , dataField , densityKey , oneKey ? *( (DataKey*)&densityKey ) : dataKey , minDepth , maxDepth , Dim , depthBias ) * sample.weight; + if( density ) pointDepthAndWeightSums[thread] += _splatPointData< true , true , DensityDegree , OutData , DataSigs ... >( zero , nodeAllocator , *density , minDepthCutoff , p , out , dataField , densityKey , oneKey ? *( (DataKey*)&densityKey ) : dataKey , minDepth , maxDepth , Dim , depthBias ) * sample.weight; #endif // __GNUC__ && __GNUC__ < 5 else { @@ -952,9 +952,9 @@ SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setI #ifdef SHOW_WARNINGS #warning "you've got me gcc version<5" #endif // SHOW_WARNINGS - _splatPointData< true , true , OutData >( nodeAllocator , _leaf< true >( nodeAllocator , p , maxDepth ) , p , out / (Real)pow( width , Dim ) , dataField , oneKey ? *( (DataKey*)&densityKey ) : dataKey ); + _splatPointData< true , true , OutData >( zero , nodeAllocator , _leaf< true >( nodeAllocator , p , maxDepth ) , p , out / (Real)pow( width , Dim ) , dataField , oneKey ? *( (DataKey*)&densityKey ) : dataKey ); #else // !__GNUC__ || __GNUC__ >=5 - _splatPointData< true , true , OutData , DataSigs ... >( nodeAllocator , _leaf< true >( nodeAllocator , p , maxDepth ) , p , out / (Real)pow( width , Dim ) , dataField , oneKey ? *( (DataKey*)&densityKey ) : dataKey ); + _splatPointData< true , true , OutData , DataSigs ... >( zero , nodeAllocator , _leaf< true >( nodeAllocator , p , maxDepth ) , p , out / (Real)pow( width , Dim ) , dataField , oneKey ? *( (DataKey*)&densityKey ) : dataKey ); #endif // __GNUC__ && __GNUC__ < 5 pointDepthAndWeightSums[thread] += Point< Real , 2 >( (Real)1. , (Real)maxDepth ) * sample.weight; } @@ -971,7 +971,7 @@ SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setI template< unsigned int Dim , class Real > template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > -SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData& ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction ) +SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setInterpolatedDataField( OutData zero , UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData& ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction ) { std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction = [&]( InData in , OutData &out , Real &bias ) { @@ -982,12 +982,12 @@ SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setI } else return false; }; - return setInterpolatedDataField( UIntPack< DataSigs ... >() , samples , data , density , minDepth , maxDepth , pointDepthFunctor , minDepthCutoff , pointDepthAndWeight , ConversionAndBiasFunction ); + return setInterpolatedDataField( zero , UIntPack< DataSigs ... >() , samples , data , density , minDepth , maxDepth , pointDepthFunctor , minDepthCutoff , pointDepthAndWeight , ConversionAndBiasFunction ); } template< unsigned int Dim , class Real > template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > -SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setInterpolatedDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction ) +SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setInterpolatedDataField( OutData zero , UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction ) { // typename FEMTreeNode::SubTreeExtractor subtreeExtractor( _spaceRoot ); SubTreeExtractor subtreeExtractor( _spaceRoot , _depthOffset ); @@ -1030,9 +1030,9 @@ SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setI #ifdef SHOW_WARNINGS #warning "you've got me gcc version<5" #endif // SHOW_WARNINGS - if( density ) pointDepthAndWeightSums[thread] += _splatPointData< true , true , DensityDegree , OutData >( nodeAllocator , *density , minDepthCutoff , p , out , dataField , densityKey , oneKey ? *( (DataKey*)&densityKey ) : dataKey , minDepth , pointDepthFunctor , Dim , depthBias ) * sample.weight; + if( density ) pointDepthAndWeightSums[thread] += _splatPointData< true , true , DensityDegree , OutData >( zero , nodeAllocator , *density , minDepthCutoff , p , out , dataField , densityKey , oneKey ? *( (DataKey*)&densityKey ) : dataKey , minDepth , pointDepthFunctor , Dim , depthBias ) * sample.weight; #else // !__GNUC__ || __GNUC__ >=5 - if( density ) pointDepthAndWeightSums[thread] += _splatPointData< true , true , DensityDegree , OutData , DataSigs ... >( nodeAllocator , *density , minDepthCutoff , p , out , dataField , densityKey , oneKey ? *( (DataKey*)&densityKey ) : dataKey , minDepth , pointDepthFunctor , Dim , depthBias ) * sample.weight; + if( density ) pointDepthAndWeightSums[thread] += _splatPointData< true , true , DensityDegree , OutData , DataSigs ... >( zero , nodeAllocator , *density , minDepthCutoff , p , out , dataField , densityKey , oneKey ? *( (DataKey*)&densityKey ) : dataKey , minDepth , pointDepthFunctor , Dim , depthBias ) * sample.weight; #endif // __GNUC__ && __GNUC__ < 5 else { @@ -1041,9 +1041,9 @@ SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setI #ifdef SHOW_WARNINGS #warning "you've got me gcc version<5" #endif // SHOW_WARNINGS - _splatPointData< true , true , OutData >( nodeAllocator , _leaf< true >( nodeAllocator , p , pointDepthFunctor ) , p , out / (Real)pow( width , Dim ) , dataField , oneKey ? *( (DataKey*)&densityKey ) : dataKey ); + _splatPointData< true , true , OutData >( zero , nodeAllocator , _leaf< true >( nodeAllocator , p , pointDepthFunctor ) , p , out / (Real)pow( width , Dim ) , dataField , oneKey ? *( (DataKey*)&densityKey ) : dataKey ); #else // !__GNUC__ || __GNUC__ >=5 - _splatPointData< true , true , OutData , DataSigs ... >( nodeAllocator , _leaf< true >( nodeAllocator , p , pointDepthFunctor ) , p , out / (Real)pow( width , Dim ) , dataField , oneKey ? *( (DataKey*)&densityKey ) : dataKey ); + _splatPointData< true , true , OutData , DataSigs ... >( zero , nodeAllocator , _leaf< true >( nodeAllocator , p , pointDepthFunctor ) , p , out / (Real)pow( width , Dim ) , dataField , oneKey ? *( (DataKey*)&densityKey ) : dataKey ); #endif // __GNUC__ && __GNUC__ < 5 pointDepthAndWeightSums[thread] += Point< Real , 2 >( (Real)1 , (Real)maxDepth ) * sample.weight; } @@ -1060,30 +1060,30 @@ SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setI template< unsigned int Dim , class Real > template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data > -SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > FEMTree< Dim , Real >::setExtrapolatedDataField( const std::vector< PointSample >& samples , const std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density , bool nearest ) +SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > FEMTree< Dim , Real >::setExtrapolatedDataField( Data zero , const std::vector< PointSample >& samples , const std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density , bool nearest ) { - return this->template setExtrapolatedDataField< DataSig , CreateNodes , DensityDegree , Data >( samples.size() , [&]( size_t i ) -> const PointSample & { return samples[i]; } , [&]( size_t i ) -> const Data & { return sampleData[i]; } , density , nearest ); + return this->template setExtrapolatedDataField< DataSig , CreateNodes , DensityDegree , Data >( zero , samples.size() , [&]( size_t i ) -> const PointSample & { return samples[i]; } , [&]( size_t i ) -> const Data & { return sampleData[i]; } , density , nearest ); } template< unsigned int Dim , class Real > template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data > -void FEMTree< Dim , Real >::updateExtrapolatedDataField( SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > &dataField , const std::vector< PointSample >& samples , const std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density , bool nearest ) +void FEMTree< Dim , Real >::updateExtrapolatedDataField( Data zero , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > &dataField , const std::vector< PointSample >& samples , const std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density , bool nearest ) { - return this->template updateExtrapolatedDataField< DataSig , CreateNodes , DensityDegree , Data >( dataField , samples.size() , [&]( size_t i ) -> const PointSample & { return samples[i]; } , [&]( size_t i ) -> const Data & { return sampleData[i]; } , density , nearest ); + return this->template updateExtrapolatedDataField< DataSig , CreateNodes , DensityDegree , Data >( zero , dataField , samples.size() , [&]( size_t i ) -> const PointSample & { return samples[i]; } , [&]( size_t i ) -> const Data & { return sampleData[i]; } , density , nearest ); } template< unsigned int Dim , class Real > template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data , class SampleFunctor /* = std::function< const PointSample & (size_t) >*/ , class SampleDataFunctor /* = std::function< const Data & (size_t) > */ > -SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > FEMTree< Dim , Real >::setExtrapolatedDataField( size_t sampleNum , SampleFunctor sampleFunctor , SampleDataFunctor sampleDataFunctor , const DensityEstimator< DensityDegree >* density , bool nearest ) +SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > FEMTree< Dim , Real >::setExtrapolatedDataField( Data zero , size_t sampleNum , SampleFunctor sampleFunctor , SampleDataFunctor sampleDataFunctor , const DensityEstimator< DensityDegree >* density , bool nearest ) { SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > dataField; - this->template updateExtrapolatedDataField< DataSig , CreateNodes , DensityDegree , Data >( dataField , sampleNum , sampleFunctor , sampleDataFunctor , density , nearest ); + this->template updateExtrapolatedDataField< DataSig , CreateNodes , DensityDegree , Data >( zero , dataField , sampleNum , sampleFunctor , sampleDataFunctor , density , nearest ); return dataField; } template< unsigned int Dim , class Real > template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data , class SampleFunctor /* = std::function< const PointSample & (size_t) >*/ , class SampleDataFunctor /* = std::function< const Data & (size_t) > */ > -void FEMTree< Dim , Real >::updateExtrapolatedDataField( SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > &dataField , size_t sampleNum , SampleFunctor sampleFunctor , SampleDataFunctor sampleDataFunctor , const DensityEstimator< DensityDegree >* density , bool nearest ) +void FEMTree< Dim , Real >::updateExtrapolatedDataField( Data zero , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > &dataField , size_t sampleNum , SampleFunctor sampleFunctor , SampleDataFunctor sampleDataFunctor , const DensityEstimator< DensityDegree >* density , bool nearest ) { Allocator< FEMTreeNode > *nodeAllocator = nodeAllocators.size() ? nodeAllocators[0] : NULL; LocalDepth maxDepth = _spaceRoot->maxDepth(); @@ -1104,8 +1104,8 @@ void FEMTree< Dim , Real >::updateExtrapolatedDataField( SparseNodeData< Project WARN( "Point is out of bounds" ); continue; } - if( nearest ) _nearestMultiSplatPointData< DensityDegree >( density , (FEMTreeNode*)sampleAndNode.node , p , ProjectiveData< Data , Real >( data , sample.weight ) , dataField , densityKey , 2 ); - else _multiSplatPointData< CreateNodes , false , DensityDegree >( nodeAllocator , density , (FEMTreeNode*)sampleAndNode.node , p , ProjectiveData< Data , Real >( data , sample.weight ) , dataField , densityKey , dataKey , 2 ); + if( nearest ) _nearestMultiSplatPointData< DensityDegree >( ProjectiveData< Data , Real >( zero ) , density , (FEMTreeNode*)sampleAndNode.node , p , ProjectiveData< Data , Real >( data , sample.weight ) , dataField , densityKey , 2 ); + else _multiSplatPointData< CreateNodes , false , DensityDegree >( ProjectiveData< Data , Real >( zero ) , nodeAllocator , density , (FEMTreeNode*)sampleAndNode.node , p , ProjectiveData< Data , Real >( data , sample.weight ) , dataField , densityKey , dataKey , 2 ); } } else @@ -1125,11 +1125,12 @@ void FEMTree< Dim , Real >::updateExtrapolatedDataField( SparseNodeData< Project if( !_InBounds(p) ) WARN( "Point is out of bounds" ); else { - if( nearest ) _nearestMultiSplatPointData< DensityDegree >( density , (FEMTreeNode*)sampleAndNode.node , p , ProjectiveData< Data , Real >( data , sample.weight ) , dataField , densityKey , 2 ); - else _multiSplatPointData< CreateNodes , false , DensityDegree >( nodeAllocator , density , (FEMTreeNode*)sampleAndNode.node , p , ProjectiveData< Data , Real >( data , sample.weight ) , dataField , densityKey , dataKey , 2 ); + if( nearest ) _nearestMultiSplatPointData< DensityDegree >( ProjectiveData< Data , Real >( zero ) , density , (FEMTreeNode*)sampleAndNode.node , p , ProjectiveData< Data , Real >( data , sample.weight ) , dataField , densityKey , 2 ); + else _multiSplatPointData< CreateNodes , false , DensityDegree >( ProjectiveData< Data , Real >( zero ) , nodeAllocator , density , (FEMTreeNode*)sampleAndNode.node , p , ProjectiveData< Data , Real >( data , sample.weight ) , dataField , densityKey , dataKey , 2 ); } - } ); - }} + } ); + } +} template< unsigned int Dim , class Real > template< unsigned int MaxDegree > diff --git a/Src/Geometry.h b/Src/Geometry.h index 762f1136..d119ebcf 100644 --- a/Src/Geometry.h +++ b/Src/Geometry.h @@ -61,34 +61,42 @@ namespace PoissonRecon }; template< typename Real > EmptyVectorType< Real > operator * ( Real s , EmptyVectorType< Real > v ){ return v*s; } - template< typename _Real , typename ... VectorTypes > - struct DirectSum + template< typename _Real , typename ... VectorTypes > struct DirectSum; + + template< typename _Real , typename FirstType , typename ... RestTypes > + struct DirectSum< _Real , FirstType , RestTypes... > { - protected: - typedef std::tuple< VectorTypes ... > _VectorTuple; - public: - typedef _Real Real; - template< unsigned int I > using VectorType = typename std::tuple_element< I , _VectorTuple >::type; - template< unsigned int I > VectorType< I >& get( void ) { return std::get< I >( _vectorTypeTuple ); } - template< unsigned int I > const VectorType< I >& get( void ) const { return std::get< I >( _vectorTypeTuple ); } - - DirectSum& operator += ( const DirectSum& p ){ _add<0>( p ) ; return *this; } - DirectSum& operator -= ( const DirectSum& p ){ _sub<0>( p ) ; return *this; } - DirectSum& operator *= ( Real s ) { _mul<0>( s ) ; return *this; } - DirectSum& operator /= ( Real s ) { _div<0>( s ) ; return *this; } - DirectSum operator + ( const DirectSum& p ) const { DirectSum _p = *this ; _p += p ; return _p; } - DirectSum operator - ( const DirectSum& p ) const { DirectSum _p = *this ; _p -= p ; return _p; } - DirectSum operator * ( Real s ) const { DirectSum _p = *this ; _p *= s ; return _p; } - DirectSum operator / ( Real s ) const { DirectSum _p = *this ; _p /= s ; return _p; } + friend Atomic< DirectSum< _Real , FirstType , RestTypes... > >; - template< typename ... _VectorTypes > - DirectSum( const _VectorTypes & ... vectors ) + using Real = _Real; + + template< unsigned int I > using VectorType = std::tuple_element_t< I , std::tuple< FirstType , RestTypes ... > >; + + template< unsigned int I > VectorType< I >& get( void ) + { + if constexpr( I==0 ) return _first; + else return _rest.template get< I-1 >(); + } + template< unsigned int I > const VectorType< I >& get( void ) const { - if constexpr( sizeof...(_VectorTypes)==0 ) ; - else if constexpr( sizeof...(_VectorTypes)==sizeof...(VectorTypes) ) _set<0>( vectors... ); - else ERROR_OUT( "Invalid number of arguments" ); + if constexpr( I==0 ) return _first; + else return _rest.template get< I-1 >(); } + DirectSum& operator += ( const DirectSum& p ){ _first += p._first ; _rest += p._rest ; return *this; } + DirectSum& operator -= ( const DirectSum& p ){ _first -= p._first ; _rest -= p._rest ; return *this; } + DirectSum& operator *= ( Real s ) { _first *= s ; _rest *= s ; return *this; } + DirectSum& operator /= ( Real s ) { _first /= s ; _rest /= s ; return *this; } + DirectSum operator + ( const DirectSum& p ) const { DirectSum _p = *this ; _p += p ; return _p; } + DirectSum operator - ( const DirectSum& p ) const { DirectSum _p = *this ; _p -= p ; return _p; } + DirectSum operator * ( Real s ) const { DirectSum _p = *this ; _p *= s ; return _p; } + DirectSum operator / ( Real s ) const { DirectSum _p = *this ; _p /= s ; return _p; } + + DirectSum( void ){} + + template< typename _FirstType , typename ... _RestTypes > + DirectSum( const _FirstType &first , const _RestTypes & ... rest ) : _first(first) , _rest(rest...){} + template< typename ComponentFunctor /*=std::function< void (VectorTypes&...)>*/ > void process( ComponentFunctor f ){ _process( f ); } @@ -98,38 +106,64 @@ namespace PoissonRecon friend std::ostream &operator << ( std::ostream &os , const DirectSum &v ) { os << "{ "; - v._streamOut< 0 >( os ); + v._write( os ); os << " }"; return os; } + protected: - std::tuple< VectorTypes ... > _vectorTypeTuple; - template< unsigned int I , typename _Vector , typename ... _Vectors > void _set( const _Vector &vector , const _Vectors & ... vectors ){ get< I >() = vector ; _set< I+1 >( vectors ... ); } - template< unsigned int I , typename _Vector > void _set( const _Vector &vector ){ get< I >() = vector ; } - template< unsigned int I > typename std::enable_if< I!=sizeof...(VectorTypes) >::type _add( const DirectSum& p ){ get() += p.get() ; _add< I+1 >( p ); } - template< unsigned int I > typename std::enable_if< I==sizeof...(VectorTypes) >::type _add( const DirectSum& p ){ } - template< unsigned int I > typename std::enable_if< I!=sizeof...(VectorTypes) >::type _sub( const DirectSum& p ){ get() -= p.get() ; _sub< I+1 >( p ); } - template< unsigned int I > typename std::enable_if< I==sizeof...(VectorTypes) >::type _sub( const DirectSum& p ){ } - template< unsigned int I > typename std::enable_if< I!=sizeof...(VectorTypes) >::type _mul( Real s ){ get() *= s ; _mul< I+1 >( s ); } - template< unsigned int I > typename std::enable_if< I==sizeof...(VectorTypes) >::type _mul( Real s ){ } - template< unsigned int I > typename std::enable_if< I!=sizeof...(VectorTypes) >::type _div( Real s ){ get() /= s ; _div< I+1 >( s ); } - template< unsigned int I > typename std::enable_if< I==sizeof...(VectorTypes) >::type _div( Real s ){ } - template< unsigned int I > typename std::enable_if< I!=sizeof...(VectorTypes) >::type _streamOut( std::ostream &os ) const { os << get() ; if( I!=sizeof...(VectorTypes)-1 ) os << " , "; _streamOut< I+1 >( os ); } - template< unsigned int I > typename std::enable_if< I==sizeof...(VectorTypes) >::type _streamOut( std::ostream &os ) const { } - - template< typename ComponentFunctor /*=std::function< void (VectorTypes&...)>*/ , typename ... Components > + FirstType _first; + DirectSum< Real , RestTypes... > _rest; + + void _write( std::ostream &os ) const + { + os << _first; + if constexpr( sizeof...(RestTypes) ) + { + os << " , "; + _rest._write( os ); + } + } + + template< typename ComponentFunctor /*=std::function< void ( FirstType& , RestTypes&... )>*/ , typename ... Components > void _process( ComponentFunctor &f , Components ... c ) { - if constexpr( sizeof...(Components)==sizeof...(VectorTypes) ) f( c... ); + if constexpr( sizeof...(Components)==sizeof...(RestTypes)+1 ) f( c... ); else _process( f , c... , this->template get< sizeof...(Components) >() ); } - template< typename ComponentFunctor /*=std::function< void (const VectorTypes&...)>*/ , typename ... Components > + template< typename ComponentFunctor /*=std::function< void ( const FirstType& , const RestTypes&... )>*/ , typename ... Components > void _process( ComponentFunctor &f , Components ... c ) const { - if constexpr( sizeof...(Components)==sizeof...(VectorTypes) ) f( c... ); + if constexpr( sizeof...(Components)==sizeof...(RestTypes)+1 ) f( c... ); else _process( f , c... , this->template get< sizeof...(Components) >() ); } }; + + template< typename _Real > + struct DirectSum< _Real > + { + using Real = _Real; + + DirectSum& operator += ( const DirectSum& p ){ return *this; } + DirectSum& operator -= ( const DirectSum& p ){ return *this; } + DirectSum& operator *= ( Real s ) { return *this; } + DirectSum& operator /= ( Real s ) { return *this; } + DirectSum operator + ( const DirectSum& p ) const { return DirectSum(); } + DirectSum operator - ( const DirectSum& p ) const { return DirectSum(); } + DirectSum operator * ( Real s ) const { return DirectSum(); } + DirectSum operator / ( Real s ) const { return DirectSum(); } + + DirectSum( void ){} + + template< typename ComponentFunctor /*=std::function< void (VectorTypes&...)>*/ > + void process( ComponentFunctor f ){ f(); } + + template< typename ComponentFunctor /*=std::function< void (const VectorTypes&...)>*/ > + void process( ComponentFunctor f ) const { f(); } + + friend std::ostream &operator << ( std::ostream &os , const DirectSum &v ){ return os << "{ }"; } + }; + template< typename Real , typename ... Vectors > DirectSum< Real , Vectors ... > operator * ( Real s , DirectSum< Real , Vectors ... > vu ){ return vu * s; } @@ -231,6 +265,8 @@ namespace PoissonRecon template< class Real > struct Point< Real > { + friend struct Atomic< Point< Real > >; + Point( void ) : _coords( NullPointer(Real) ) , _dim(0){} Point( size_t dim ) : _coords( NullPointer(Real) ) , _dim(0) { if( dim ){ _resize( (unsigned int)dim ) ; memset( _coords , 0 , sizeof(Real)*_dim ); } } Point( const Point &p ) : _coords( NullPointer(Real) ) , _dim(0) { if( p._dim ){ _resize( p._dim ) ; memcpy( _coords , p._coords , sizeof(Real)*_dim ); } } diff --git a/Src/MyAtomic.h b/Src/MyAtomic.h index 070c7916..4de9fb7f 100644 --- a/Src/MyAtomic.h +++ b/Src/MyAtomic.h @@ -120,6 +120,61 @@ namespace PoissonRecon } } + template< typename Value > + struct Atomic + { + static void Add( volatile Value &a , const Value &b ) + { + if constexpr( std::is_pod_v< Value > ) AddAtomic( a , b ); + else + { + WARN_ONCE( "should not use this function: " , typeid(Value).name() ); + static std::mutex addAtomicMutex; + std::lock_guard< std::mutex > lock( addAtomicMutex ); + *(Value*)&a += b; + } + } + + static Value Set( volatile Value & value , Value newValue ) + { + if constexpr( std::is_pod_v< Value > ) return SetAtomic( value , newValue ); + else + { + WARN_ONCE( "should not use this function: " , typeid(Value).name() ); + static std::mutex setAtomicMutex; + std::lock_guard< std::mutex > lock( setAtomicMutex ); + Value oldValue = *(Value*)&value; + *(Value*)&value = newValue; + return oldValue; + } + } + + static bool Set( volatile Value & value , Value newValue , Value oldValue ) + { + if constexpr( std::is_pod_v< Value > ) return SetAtomic( value , newValue , oldValue ); + else + { + WARN_ONCE( "should not use this function: " , typeid(Value).name() , " , " , sizeof(Value) ); + static std::mutex setAtomicMutex; + std::lock_guard< std::mutex > lock( setAtomicMutex ); + if( value==oldValue ){ value = newValue ; return true; } + else return false; + } + } + + static Value Read( const volatile Value & value ) + { + if constexpr( std::is_pod_v< Value > ) return ReadAtomic( value ); + else + { + WARN_ONCE( "should not use this function: " , typeid(Value).name() , " , " , sizeof(Value) ); + static std::mutex readAtomicMutex; + std::lock_guard< std::mutex > lock( readAtomicMutex ); + return *(Value*)&value; + } + } + }; + /////////////////////////////////////////////// /////////////////////////////////////////////// /////////////////////////////////////////////// diff --git a/Src/PoissonRecon.client.inl b/Src/PoissonRecon.client.inl index bff01583..884bab42 100644 --- a/Src/PoissonRecon.client.inl +++ b/Src/PoissonRecon.client.inl @@ -624,12 +624,12 @@ void Client< Real , Dim , BType , Degree >::_process1( const ClientReconstructio }; { - *_normalInfo = _tree.setInterpolatedDataField( NormalSigs() , _samples , _sampleData , _density , clientReconInfo.sharedDepth , clientReconInfo.reconstructionDepth , (Real)0 , pointDepthAndWeight , ConversionFunction ); + *_normalInfo = _tree.setInterpolatedDataField( Point< Real , Dim >() , NormalSigs() , _samples , _sampleData , _density , clientReconInfo.sharedDepth , clientReconInfo.reconstructionDepth , (Real)0 , pointDepthAndWeight , ConversionFunction ); if( clientReconInfo.verbose>1 ) std::cout << "Nodes [Interior Data Field " << _normalInfo->size() << " / " << _normalInfo->reserved() << "]: " << _tree.allNodes() << std::endl; #ifdef ADAPTIVE_PADDING - *_paddedNormalInfo = _tree.setInterpolatedDataField( NormalSigs() , _paddedSamples , _paddedSampleData , _density , clientReconInfo.sharedDepth , clientReconInfo.reconstructionDepth , pointDepthFunctor , (Real)0 , paddedPointDepthAndWeight , ConversionFunction ); + *_paddedNormalInfo = _tree.setInterpolatedDataField( Point< Real , Dim >() , NormalSigs() , _paddedSamples , _paddedSampleData , _density , clientReconInfo.sharedDepth , clientReconInfo.reconstructionDepth , pointDepthFunctor , (Real)0 , paddedPointDepthAndWeight , ConversionFunction ); #else // !ADAPTIVE_PADDING - *_paddedNormalInfo = _tree.setInterpolatedDataField( NormalSigs() , _paddedSamples , _paddedSampleData , _density , clientReconInfo.sharedDepth , clientReconInfo.reconstructionDepth , (Real)0 , paddedPointDepthAndWeight , ConversionFunction ); + *_paddedNormalInfo = _tree.setInterpolatedDataField( Point< Real , Dim >() , NormalSigs() , _paddedSamples , _paddedSampleData , _density , clientReconInfo.sharedDepth , clientReconInfo.reconstructionDepth , (Real)0 , paddedPointDepthAndWeight , ConversionFunction ); #endif // ADAPTIVE_PADDING } @@ -819,7 +819,7 @@ void Client< Real , Dim , BType , Degree >::_process3( const ClientReconstructio if( clientReconInfo.verbose>1 ) std::cout << "#Set interior point constraints: " << timer << std::endl; } } - if( needAuxData ) _auxDataField = _tree.template setExtrapolatedDataField< DataSig , false , Reconstructor::WeightDegree , AuxData >( _samples.size() , [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return _samples[i]; } , [&]( size_t i ) -> const AuxData & { return _sampleData[i].template get<1>(); } , (DensityEstimator*)NULL ); + if( needAuxData ) _auxDataField = _tree.template setExtrapolatedDataField< DataSig , false , Reconstructor::WeightDegree , AuxData >( auxDataFactory() , _samples.size() , [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return _samples[i]; } , [&]( size_t i ) -> const AuxData & { return _sampleData[i].template get<1>(); } , (DensityEstimator*)NULL ); // Get the shared tree, constraints, interpolation info, and data-field { @@ -838,7 +838,7 @@ void Client< Real , Dim , BType , Degree >::_process3( const ClientReconstructio if( needAuxData ) { - _tree.template updateExtrapolatedDataField< DataSig , false >( _auxDataField , _paddedSamples.size() , [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return _paddedSamples[i]; } , [&]( size_t i ) -> const AuxData & { return _paddedSampleData[i].template get<1>(); } , (DensityEstimator*)NULL ); + _tree.template updateExtrapolatedDataField< DataSig , false >( auxDataFactory() , _auxDataField , _paddedSamples.size() , [&]( size_t i ) -> const typename FEMTree< Dim , Real >::PointSample & { return _paddedSamples[i]; } , [&]( size_t i ) -> const AuxData & { return _paddedSampleData[i].template get<1>(); } , (DensityEstimator*)NULL ); auto nodeFunctor = [&]( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > *n ) { ProjectiveData< AuxData , Real >* clr = _auxDataField( n ); diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index b2a629b5..c138ae86 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -46,7 +46,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "18.42" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "18.50" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth diff --git a/Src/Reconstruction.example.cpp b/Src/Reconstruction.example.cpp index 3f3b99e4..88ade1e2 100644 --- a/Src/Reconstruction.example.cpp +++ b/Src/Reconstruction.example.cpp @@ -81,6 +81,20 @@ struct RGBColor RGBColor operator / ( Real s ) const { return operator * (1/s); } }; +namespace PoissonRecon +{ + template< typename Real > + struct Atomic< RGBColor< Real > > + { + static void Add( volatile RGBColor< Real > &a , const RGBColor< Real > & b ) + { + Atomic< Real >::Add( a.r , b.r ); + Atomic< Real >::Add( a.g , b.g ); + Atomic< Real >::Add( a.b , b.b ); + } + }; +} + // A stream for generating random oriented samples on the sphere template< typename Real , unsigned int Dim > struct SphereOrientedSampleStream : public Reconstructor::InputOrientedSampleStream< Real , Dim > diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h index ebf73e15..7f72656d 100644 --- a/Src/Reconstructors.h +++ b/Src/Reconstructors.h @@ -681,10 +681,10 @@ namespace PoissonRecon size_t pointCount; ProjectiveData< Point< Real , 2 > , Real > pointDepthAndWeight; - std::vector< typename FEMTree< Dim , Real >::PointSample > *valueInterpolationSamples = NULL; - std::vector< Real > *valueInterpolationSampleData = NULL; + std::vector< typename FEMTree< Dim , Real >::PointSample > *valueInterpolationSamples = nullptr; + std::vector< Real > *valueInterpolationSampleData = nullptr; DenseNodeData< GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > geometryNodeDesignators; - SparseNodeData< Point< Real , Dim > , NormalSigs > *normalInfo = NULL; + SparseNodeData< Point< Real , Dim > , NormalSigs > *normalInfo = nullptr; std::vector< typename FEMTree< Dim , Real >::PointSample > *samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); std::vector< InternalNormalAndAuxData > *sampleNormalAndAuxData = new std::vector< InternalNormalAndAuxData >(); @@ -801,7 +801,7 @@ namespace PoissonRecon out = n / l; return true; }; - *normalInfo = implicit.tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , implicit.density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionFunction ); + *normalInfo = implicit.tree.setInterpolatedDataField( Point< Real , Dim >() , NormalSigs() , *samples , *sampleNormalAndAuxData , implicit.density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionFunction ); ThreadPool::ParallelFor( 0 , normalInfo->size() , [&]( unsigned int , size_t i ){ (*normalInfo)[i] *= (Real)-1.; } ); if( params.verbose ) @@ -914,6 +914,7 @@ namespace PoissonRecon ( implicit.tree.template setExtrapolatedDataField< DataSig , false , Reconstructor::WeightDegree , InternalAuxData > ( + InternalAuxData( zero... ) , samples->size() , PointSampleFunctor , AuxDataSampleFunctor , @@ -1086,7 +1087,7 @@ namespace PoissonRecon size_t pointCount; ProjectiveData< Point< Real , 2 > , Real > pointDepthAndWeight; - SparseNodeData< Point< Real , Dim > , NormalSigs > *normalInfo = NULL; + SparseNodeData< Point< Real , Dim > , NormalSigs > *normalInfo = nullptr; std::vector< typename FEMTree< Dim , Real >::PointSample > *samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); std::vector< InternalNormalAndAuxData > *sampleNormalAndAuxData = new std::vector< InternalNormalAndAuxData >();; @@ -1190,7 +1191,7 @@ namespace PoissonRecon out = n / l; return true; }; - *normalInfo = implicit.tree.setInterpolatedDataField( NormalSigs() , *samples , *sampleNormalAndAuxData , implicit.density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionFunction ); + *normalInfo = implicit.tree.setInterpolatedDataField( Point< Real , Dim >() , NormalSigs() , *samples , *sampleNormalAndAuxData , implicit.density , params.baseDepth , params.depth , params.lowDepthCutOff , pointDepthAndWeight , ConversionFunction ); if( params.verbose ) { @@ -1208,6 +1209,7 @@ namespace PoissonRecon ( implicit.tree.template setExtrapolatedDataField< DataSig , false , Reconstructor::WeightDegree , InternalAuxData > ( + InternalAuxData( zero... ) , samples->size() , PointSampleFunctor , AuxDataSampleFunctor , From 8718872658a3a9eb032e951caca80146a59fc975 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Thu, 21 Nov 2024 09:11:51 -0500 Subject: [PATCH 71/86] Version 18.50 --- README.md | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 9c986532..4e65db1f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 18.42)

    +

    Adaptive Multigrid Solvers (Version 18.50)

    links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
    Executables: -Win64
    +Win64
    Source Code: -ZIP GitHub
    +ZIP GitHub
    Older Versions: +V18.42, V18.41, V18.40, V18.35, @@ -1114,23 +1115,24 @@ This method returns the extrapolated value at the prescribed position.
      These steps can be found in the Reconstruction.example.cpp code.
        -
      • The finite-elements signatures are created in lines 308 and 311. -
      • An input sample stream generating a specified number of random points on the surface of the sphere is defined in lines 85-122 and constructed in line 379. -
      • An output polygon stream that pushes the polygon to an std::vector of std::vector< int >s is defined in lines 213-230 and constructed in line 389. -
      • An output vertex stream that pushes just the position information to an std::vector of Reals is desfined in lines 223-244 and constructed in line 390. -
      • The implicit representation is computed in line 382. -
      • The level-set extraction is performed on line 393. -
      • The evaluator is created on line 340. -
      • The evaluator is used to query the values and gradients of the implicit function in line 333. -
      • The extrapolator is constructed on line 411. -
      • The extrapolator is evaluated at the vertex positions at line 421. +
      • The finite-elements signatures are created in lines 322 and 325. +
      • An input sample stream generating a specified number of random points on the surface of the sphere is defined in lines 99-136 and constructed in line 393. +
      • An output polygon stream that pushes the polygon to an std::vector of std::vector< int >s is defined in lines 227-244 and constructed in line 403. +
      • An output vertex stream that pushes just the position information to an std::vector of Reals is desfined in lines 247-258 and constructed in line 404. +
      • The implicit representation is computed in line 396. +
      • The level-set extraction is performed on line 407. +
      • The evaluator is created on line 354. +
      • The evaluator is used to query the values and gradients of the implicit function in line 347. +
      • The extrapolator is constructed on line 425. +
      • The extrapolator is evaluated at the vertex positions at line 435.
      -Note that a similar approach can be used to perform the Smoothed Signed Distance reconstruction (lines 459 and 460).
      +Note that a similar approach can be used to perform the Smoothed Signed Distance reconstruction (lines 473 and 474).
      The approach also supports reconstruction of meshes with auxiliary information like color, with the only constraint that the auxiliary data type supports the computation affine combinations (e.g. the RGBColor type defined in lines 67-82). The auxiliary inform is derived in one of two ways:
        -
      1. As part of the reconstruction process, so that the level-set extraction phase also sets the auxiliary information. (Lines 349-375) -
      2. Independently by constructing the extrapolation field from the samples and then evaluating at the positions of the level-set vertices. (Lines 400-427) +
      3. As part of the reconstruction process, so that the level-set extraction phase also sets the auxiliary information. (Lines 363-389) +
      4. Independently by constructing the extrapolation field from the samples and then evaluating at the positions of the level-set vertices. (Lines 414-441)
      +To avoid inefficient locking in a multi-threaded application, the Add method of the type trait PoissonRecon::Atomic<RGBColor> is specialized (lines 84-96) to define the atomic operation a += b.
    @@ -1721,10 +1723,15 @@ Similarly, to reduce compilation times, support for specific degrees can be remo Version 18.42:
      -
    1. Fixed parallelization bugy in Extrapolator. +
    2. Fixed parallelization bugs in Extrapolator.
    3. Moified Reconstruction.example to use parallelized extrapolation.
    +Version 18.50: +
      +
    1. Cleaned-up multi-threading code. +
    +
    From 737f28e180a38d988d76c296576435dc5dda8912 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Wed, 11 Dec 2024 10:43:08 -0500 Subject: [PATCH 72/86] Version 18.55 --- AdaptiveSolvers.sln | 10 +++ Makefile | 13 ++- README.md | 43 ++++++++- ScaleNormals.vcxproj | 141 +++++++++++++++++++++++++++++ Src/FEMTree.h | 4 +- Src/FEMTree.inl | 8 +- Src/PoissonRecon.client.inl | 4 +- Src/PreProcessor.h | 2 +- Src/ScaleNormals.cpp | 175 ++++++++++++++++++++++++++++++++++++ 9 files changed, 387 insertions(+), 13 deletions(-) create mode 100644 ScaleNormals.vcxproj create mode 100644 Src/ScaleNormals.cpp diff --git a/AdaptiveSolvers.sln b/AdaptiveSolvers.sln index 4fafb677..cd4aba7e 100644 --- a/AdaptiveSolvers.sln +++ b/AdaptiveSolvers.sln @@ -141,6 +141,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Reconstruction.example", "R EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PointsToDisks", "PointsToDisks.vcxproj", "{6AE727A9-A3F0-4970-8F5B-1F1A3AEAC552}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ScaleNormals", "ScaleNormals.vcxproj", "{BB5F81BE-3FDD-4BB3-9358-9B908C3644DE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -270,6 +272,14 @@ Global {6AE727A9-A3F0-4970-8F5B-1F1A3AEAC552}.Release|x64.Build.0 = Release|x64 {6AE727A9-A3F0-4970-8F5B-1F1A3AEAC552}.Release|x86.ActiveCfg = Release|Win32 {6AE727A9-A3F0-4970-8F5B-1F1A3AEAC552}.Release|x86.Build.0 = Release|Win32 + {BB5F81BE-3FDD-4BB3-9358-9B908C3644DE}.Debug|x64.ActiveCfg = Debug|x64 + {BB5F81BE-3FDD-4BB3-9358-9B908C3644DE}.Debug|x64.Build.0 = Debug|x64 + {BB5F81BE-3FDD-4BB3-9358-9B908C3644DE}.Debug|x86.ActiveCfg = Debug|Win32 + {BB5F81BE-3FDD-4BB3-9358-9B908C3644DE}.Debug|x86.Build.0 = Debug|Win32 + {BB5F81BE-3FDD-4BB3-9358-9B908C3644DE}.Release|x64.ActiveCfg = Release|x64 + {BB5F81BE-3FDD-4BB3-9358-9B908C3644DE}.Release|x64.Build.0 = Release|x64 + {BB5F81BE-3FDD-4BB3-9358-9B908C3644DE}.Release|x86.ActiveCfg = Release|Win32 + {BB5F81BE-3FDD-4BB3-9358-9B908C3644DE}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Makefile b/Makefile index 5758d413..71bdf688 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,7 @@ AV_TARGET=AdaptiveTreeVisualization CP_TARGET=ChunkPLY RE_TARGET=ReconExample PTD_TARGET=PointsToDisks +SN_TARGET=ScaleNormals PR_SOURCE=PoissonRecon.cpp PRC_SOURCE=PoissonReconClient.cpp @@ -23,6 +24,7 @@ AV_SOURCE=AdaptiveTreeVisualization.cpp CP_SOURCE=ChunkPLY.cpp RE_SOURCE=Reconstruction.example.cpp PTD_SOURCE=PointsToDisks.cpp +SN_SOURCE=ScaleNormals.cpp COMPILER ?= gcc #COMPILER ?= clang @@ -81,6 +83,7 @@ AV_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(AV_SOURCE)))) CP_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(CP_SOURCE)))) RE_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(RE_SOURCE)))) PTD_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(PTD_SOURCE)))) +SN_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(SN_SOURCE)))) all: CFLAGS += $(CFLAGS_RELEASE) @@ -175,6 +178,11 @@ pointstodisks: LFLAGS += $(LFLAGS_RELEASE) pointstodisks: make_dir pointstodisks: $(BIN)$(PTD_TARGET) +scalenormals: CFLAGS += $(CFLAGS_RELEASE) +scalenormals: LFLAGS += $(LFLAGS_RELEASE) +scalenormals: make_dir +scalenormals: $(BIN)$(SN_TARGET) + clean: rm -rf $(BIN)$(PR_TARGET) rm -rf $(BIN)$(PRC_TARGET) @@ -199,9 +207,9 @@ clean: rm -rf $(CP_OBJECTS) rm -rf $(RE_OBJECTS) rm -rf $(PTD_OBJECTS) + rm -rf $(SN_OBJECTS) cd PNG && make clean - make_dir: $(MD) -p $(BIN) @@ -247,6 +255,9 @@ $(BIN)$(RE_TARGET): $(RE_OBJECTS) $(BIN)$(PTD_TARGET): $(PTD_OBJECTS) $(CXX) -pthread -o $@ $(PTD_OBJECTS) -L$(BIN) $(LFLAGS) +$(BIN)$(SN_TARGET): $(SN_OBJECTS) + $(CXX) -pthread -o $@ $(SN_OBJECTS) -L$(BIN) $(LFLAGS) + $(BIN)%.o: $(SRC)%.c $(CC) -c -o $@ -I$(INCLUDE) $< diff --git a/README.md b/README.md index 4e65db1f..651930ab 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 18.50)

    +

    Adaptive Multigrid Solvers (Version 18.55)

    links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
    Executables: -Win64
    +Win64
    Source Code: -ZIP GitHub
    +ZIP GitHub
    Older Versions: +V18.50, V18.42, V18.41, V18.40, @@ -1040,6 +1041,37 @@ If both the --keep flag and the --fraction flag are set, the -- +
      +
      +
      + +ScaleNormals: +Scales the normal magnitudes using auxiliary confidence attributes encoded with the samples. + +
      --in <input points> +
      This string is the name of the file from which the point set will be read.
      +The file is assumed to be in PLY format.
      + +
      --out <output ply file name> +
      This string is the name of the file to which the point set should be written.
      +The file will be written out in PLY format.
      + +
      --cNames <confidence attribute count, confidence attribute name 1, confidence attribute name 2, ...>] +
      These strings give the names of the attributes encoding confidence information.
      + +
      --cExps <confidence attribute count, confidence attribute value 1, confidence attribute value 2, ...>] +
      These floating point values encode the exponents applied to the confidence attributes when scaling the normal magnitude.
      +Note that the count of confidence attributes for the --cNames and --cExps need to match. + +
      [--verbose] +
      Enabling this flag provides a description of running state. + +
      +
      +
      +
    + +
    HEADER-ONLY LIBRARY
    @@ -1732,6 +1764,11 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • Cleaned-up multi-threading code. +Version 18.55: +
      +
    1. Added the ScaleNormals executable. +
    +
    diff --git a/ScaleNormals.vcxproj b/ScaleNormals.vcxproj new file mode 100644 index 00000000..fddef1d0 --- /dev/null +++ b/ScaleNormals.vcxproj @@ -0,0 +1,141 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + 17.0 + Win32Proj + {bb5f81be-3fdd-4bb3-9358-9b908c3644de} + ScaleNormals + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)\Bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\Obj\$(TargetName)\$(Platform)\$(Configuration)\ + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + NOMINMAX;_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp17 + true + + + Console + true + true + true + + + + + + \ No newline at end of file diff --git a/Src/FEMTree.h b/Src/FEMTree.h index 3828f22c..d4ad6ca6 100644 --- a/Src/FEMTree.h +++ b/Src/FEMTree.h @@ -2625,11 +2625,11 @@ namespace PoissonRecon template< unsigned int CoDim , unsigned int DensityDegree > typename FEMTree::template DensityEstimator< DensityDegree > *setDensityEstimator( const std::vector< PointSample >& samples , LocalDepth splatDepth , Real samplesPerNode ); template< unsigned int CoDim , unsigned int DensityDegree > - void updateDensityEstimator( typename FEMTree::template DensityEstimator< DensityDegree > &density , const std::vector< PointSample >& samples , LocalDepth minSplatDepth , LocalDepth maxSplatDepth , Real samplesPerNode ); + void updateDensityEstimator( typename FEMTree::template DensityEstimator< DensityDegree > &density , const std::vector< PointSample >& samples , LocalDepth minSplatDepth , LocalDepth maxSplatDepth ); template< unsigned int CoDim , unsigned int DensityDegree > typename FEMTree::template DensityEstimator< DensityDegree > *setDensityEstimator( const std::vector< PointSample >& samples , LocalDepth splatDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real samplesPerNode ); template< unsigned int CoDim , unsigned int DensityDegree > - void updateDensityEstimator( typename FEMTree::template DensityEstimator< DensityDegree > &density , const std::vector< PointSample >& samples , LocalDepth minSplatDepth , LocalDepth maxSplatDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real samplesPerNode ); + void updateDensityEstimator( typename FEMTree::template DensityEstimator< DensityDegree > &density , const std::vector< PointSample >& samples , LocalDepth minSplatDepth , LocalDepth maxSplatDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor ); template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > SparseNodeData< OutData , UIntPack< DataSigs ... > > setInterpolatedDataField( OutData zero , UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , LocalDepth minDepth , LocalDepth maxDepth , Real minDepthCutoff , ProjectiveData< Point< Real , 2 > , Real > &pointDepthAndWeight , std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction ); diff --git a/Src/FEMTree.inl b/Src/FEMTree.inl index d0441d8d..c7fc1be3 100644 --- a/Src/FEMTree.inl +++ b/Src/FEMTree.inl @@ -788,7 +788,7 @@ typename FEMTree< Dim , Real >::template ApproximatePointAndDataInterpolationInf template< unsigned int Dim , class Real > template< unsigned int CoDim , unsigned int DensityDegree > -void FEMTree< Dim , Real >::updateDensityEstimator( typename FEMTree< Dim , Real >::template DensityEstimator< DensityDegree > &density , const std::vector< PointSample >& samples , LocalDepth minSplatDepth , LocalDepth maxSplatDepth , Real samplesPerNode ) +void FEMTree< Dim , Real >::updateDensityEstimator( typename FEMTree< Dim , Real >::template DensityEstimator< DensityDegree > &density , const std::vector< PointSample >& samples , LocalDepth minSplatDepth , LocalDepth maxSplatDepth ) { // typename FEMTreeNode::SubTreeExtractor subtreeExtractor( _spaceRoot ); SubTreeExtractor subtreeExtractor( _spaceRoot , _depthOffset ); @@ -820,7 +820,7 @@ void FEMTree< Dim , Real >::updateDensityEstimator( typename FEMTree< Dim , Real template< unsigned int Dim , class Real > template< unsigned int CoDim , unsigned int DensityDegree > -void FEMTree< Dim , Real >::updateDensityEstimator( typename FEMTree< Dim , Real >::template DensityEstimator< DensityDegree > &density , const std::vector< PointSample >& samples , LocalDepth minSplatDepth , LocalDepth maxSplatDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor , Real samplesPerNode ) +void FEMTree< Dim , Real >::updateDensityEstimator( typename FEMTree< Dim , Real >::template DensityEstimator< DensityDegree > &density , const std::vector< PointSample >& samples , LocalDepth minSplatDepth , LocalDepth maxSplatDepth , std::function< int ( Point< Real , Dim > ) > pointDepthFunctor ) { // typename FEMTreeNode::SubTreeExtractor subtreeExtractor( _spaceRoot ); SubTreeExtractor subtreeExtractor( _spaceRoot , _depthOffset ); @@ -863,7 +863,7 @@ typename FEMTree< Dim , Real >::template DensityEstimator< DensityDegree >* FEMT LocalDepth maxDepth = _spaceRoot->maxDepth(); splatDepth = std::max< LocalDepth >( 0 , std::min< LocalDepth >( splatDepth , maxDepth ) ); DensityEstimator< DensityDegree > *density = new DensityEstimator< DensityDegree >( splatDepth , CoDim , samplesPerNode ); - this->template updateDensityEstimator< CoDim , DensityDegree >( *density , samples , 0 , splatDepth , samplesPerNode ); + this->template updateDensityEstimator< CoDim , DensityDegree >( *density , samples , 0 , splatDepth ); return density; } @@ -875,7 +875,7 @@ typename FEMTree< Dim , Real >::template DensityEstimator< DensityDegree >* FEMT LocalDepth maxDepth = _spaceRoot->maxDepth(); splatDepth = std::max< LocalDepth >( 0 , std::min< LocalDepth >( splatDepth , maxDepth ) ); DensityEstimator< DensityDegree > *density = new DensityEstimator< DensityDegree >( splatDepth , CoDim , samplesPerNode ); - this->template updateDensityEstimator< CoDim , DensityDegree >( *density , samples , 0 , splatDepth , pointDepthFunctor , samplesPerNode ); + this->template updateDensityEstimator< CoDim , DensityDegree >( *density , samples , 0 , splatDepth , pointDepthFunctor ); return density; } diff --git a/Src/PoissonRecon.client.inl b/Src/PoissonRecon.client.inl index 884bab42..7f943fc3 100644 --- a/Src/PoissonRecon.client.inl +++ b/Src/PoissonRecon.client.inl @@ -597,9 +597,9 @@ void Client< Real , Dim , BType , Degree >::_process1( const ClientReconstructio Timer timer; _density = _tree.template setDensityEstimator< 1 , Reconstructor::WeightDegree >( _samples , clientReconInfo.kernelDepth , clientReconInfo.samplesPerNode ); #ifdef ADAPTIVE_PADDING - _tree.template updateDensityEstimator< 1 , Reconstructor::WeightDegree >( *_density , _paddedSamples , 0 , clientReconInfo.kernelDepth , pointDepthFunctor , clientReconInfo.samplesPerNode ); + _tree.template updateDensityEstimator< 1 , Reconstructor::WeightDegree >( *_density , _paddedSamples , 0 , clientReconInfo.kernelDepth , pointDepthFunctor ); #else // !ADAPTIVE_PADDING - _tree.template updateDensityEstimator< 1 , Reconstructor::WeightDegree >( *_density , _paddedSamples , 0 , clientReconInfo.kernelDepth , clientReconInfo.samplesPerNode ); + _tree.template updateDensityEstimator< 1 , Reconstructor::WeightDegree >( *_density , _paddedSamples , 0 , clientReconInfo.kernelDepth ); #endif // ADAPTIVE_PADDING profiler.update(); if( clientReconInfo.verbose>1 ) std::cout << "# Got kernel density: " << timer << std::endl; diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index c138ae86..4f9619ce 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -46,7 +46,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "18.50" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "18.55" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth diff --git a/Src/ScaleNormals.cpp b/Src/ScaleNormals.cpp new file mode 100644 index 00000000..82708c4d --- /dev/null +++ b/Src/ScaleNormals.cpp @@ -0,0 +1,175 @@ +/* +Copyright (c) 2024, 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. +*/ + +#include "PreProcessor.h" + +#include +#include +#include +#include +#include +#define _USE_MATH_DEFINES +#include +#include "Ply.h" +#include "CmdLineParser.h" +#include "Geometry.h" +#include "VertexFactory.h" +#include "MyMiscellany.h" +#include "DataStream.imp.h" + +using namespace PoissonRecon; + +CmdLineParameter< std::string > + In( "in" ) , + Out( "out" ); + +CmdLineParameters< std::string > + ConfidenceNames( "cNames" ); + +CmdLineParameters< float > + ConfidenceExponents( "cExps" ); + + +CmdLineReadable + Verbose( "verbose" ); + +CmdLineReadable* params[] = +{ + &In , + &Out , + &ConfidenceNames , + &ConfidenceExponents , + &Verbose , + NULL +}; + + +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" , ConfidenceNames.name ); + printf( "\t --%s \n" , ConfidenceExponents.name ); + printf( "\t[--%s]\n" , Verbose.name ); +} + +template< typename Real , unsigned int Dim , typename Factory > +void Execute( Factory factory ) +{ + auto Scale = [&]( Point< Real > scales ) + { + Real s = (Real)1.; + for( unsigned int d=0 ; d inPointStream( In.value.c_str() , factory , count ); + PLYOutputDataStream< Factory > outPointStream( Out.value.c_str() , factory , count ); + + if( Verbose.set ) std::cout << "Points: " << count << std::endl; + + typename Factory::VertexType v = factory(); + while( inPointStream.read( v ) ) + { + v.template get<1>() *= Scale( v.template get<2>() ); + outPointStream.write( v ); + } +}; + +template< typename Real , unsigned int Dim > +void Execute( void ) +{ + std::vector< std::pair< std::string , VertexFactory::TypeOnDisk > > namesAndTypesOnDisk( ConfidenceNames.count ); + for( unsigned int i=0 ; i(); + } + + VertexFactory::PositionFactory< Real , Dim > positionFactory; + VertexFactory::NormalFactory< Real , Dim > normalFactory; + VertexFactory::DynamicFactory< Real > scaleFactory( namesAndTypesOnDisk ); + + typedef VertexFactory::Factory< Real , typename VertexFactory::PositionFactory< Real , Dim > , typename VertexFactory::NormalFactory< Real , Dim > , VertexFactory::DynamicFactory< Real > > Factory; + Factory factory( positionFactory , normalFactory , scaleFactory ); + + bool *readFlags = new bool[ factory.plyReadNum() ]; + std::vector< PlyProperty > unprocessedProperties; + + PLY::ReadVertexHeader( In.value , factory , readFlags , unprocessedProperties ); + if( !factory.plyValidReadProperties<0>( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); + if( !factory.plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain normals" ); + if( !factory.plyValidReadProperties<2>( readFlags ) ) ERROR_OUT( "Ply file does not contain scales" ); + delete[] readFlags; + + if( Verbose.set && unprocessedProperties.size() ) + { + std::cout << "Unprocessed properties:" << std::endl; + for( unsigned int i=0 ; i , typename VertexFactory::NormalFactory< Real , Dim > , VertexFactory::DynamicFactory< Real > , VertexFactory::DynamicFactory< Real > >; + Execute< Real , Dim >( _Factory( positionFactory , normalFactory , scaleFactory , VertexFactory::DynamicFactory< Real >( unprocessedProperties ) ) ); + } + else + { + using _Factory = VertexFactory::Factory< Real , typename VertexFactory::PositionFactory< Real , Dim > , typename VertexFactory::NormalFactory< Real , Dim > , VertexFactory::DynamicFactory< Real > >; + Execute< Real , Dim >( _Factory( positionFactory , normalFactory , scaleFactory ) ); + } +} + +int main( int argc , char* argv[] ) +{ + CmdLineParse( argc-1 , &argv[1] , params ); + if( !In.set || !Out.set || !ConfidenceNames.set || !ConfidenceExponents.set ) + { + ShowUsage( argv [0] ); + return EXIT_FAILURE; + } + + if( ConfidenceNames.count!=ConfidenceExponents.count ) + ERROR_OUT( "Number of confidence names and exponents does not match: " , ConfidenceNames.count , " != " , ConfidenceExponents.count ); + + if( Verbose.set ) + { + std::cout << "*******************************************" << std::endl; + std::cout << "*******************************************" << std::endl; + std::cout << "** Running Scale Normals (Version " << ADAPTIVE_SOLVERS_VERSION << ") **" << std::endl; + std::cout << "*******************************************" << std::endl; + std::cout << "*******************************************" << std::endl; + } + + Execute< float , 3 >(); + + + return EXIT_SUCCESS; +} \ No newline at end of file From 966fe111e7e31f0f3a8073bbfc8d825178e7ef18 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Fri, 20 Dec 2024 15:23:02 -0500 Subject: [PATCH 73/86] Version 18.55 Minor resolution of clang compilation issues. --- Makefile | 2 ++ Src/PoissonRecon.cpp | 8 ++++---- Src/SSDRecon.cpp | 8 ++++---- Src/ScaleNormals.cpp | 6 +++--- Src/SurfaceTrimmer.cpp | 4 ++-- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 71bdf688..4c91985c 100644 --- a/Makefile +++ b/Makefile @@ -101,6 +101,7 @@ all: $(BIN)$(AV_TARGET) all: $(BIN)$(CP_TARGET) all: $(BIN)$(RE_TARGET) all: $(BIN)$(PTD_TARGET) +all: $(BIN)$(SN_TARGET) debug: CFLAGS += $(CFLAGS_DEBUG) debug: LFLAGS += $(LFLAGS_DEBUG) @@ -117,6 +118,7 @@ debug: $(BIN)$(AV_TARGET) debug: $(BIN)$(CP_TARGET) debug: $(BIN)$(RE_TARGET) debug: $(BIN)$(PTD_TARGET) +debug: $(BIN)$(SN_TARGET) poissonrecon: CFLAGS += $(CFLAGS_RELEASE) poissonrecon: LFLAGS += $(LFLAGS_RELEASE) diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index 8f2ec190..5f61346d 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -620,8 +620,8 @@ int main( int argc , char* argv[] ) bool *readFlags = new bool[ factory.plyReadNum() ]; std::vector< PlyProperty > unprocessedProperties; PLY::ReadVertexHeader( In.value , factory , readFlags , unprocessedProperties ); - if( !factory.plyValidReadProperties<0>( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); - if( !factory.plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain normals" ); + if( !factory.template plyValidReadProperties<0>( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); + if( !factory.template plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain normals" ); delete[] readFlags; if( unprocessedProperties.size() ) Execute< Real , Dim , FEMSig >( VertexFactory::DynamicFactory< Real >( unprocessedProperties ) ); @@ -643,8 +643,8 @@ int main( int argc , char* argv[] ) bool *readFlags = new bool[ factory.plyReadNum() ]; std::vector< PlyProperty > unprocessedProperties; PLY::ReadVertexHeader( In.value , factory , readFlags , unprocessedProperties ); - if( !factory.plyValidReadProperties<0>( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); - if( !factory.plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain normals" ); + if( !factory.template plyValidReadProperties<0>( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); + if( !factory.template plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain normals" ); delete[] readFlags; if( unprocessedProperties.size() ) Execute< DEFAULT_DIMENSION , Real >( VertexFactory::DynamicFactory< Real >( unprocessedProperties ) ); diff --git a/Src/SSDRecon.cpp b/Src/SSDRecon.cpp index bd96ec75..c4d9c7a3 100644 --- a/Src/SSDRecon.cpp +++ b/Src/SSDRecon.cpp @@ -605,8 +605,8 @@ int main( int argc , char* argv[] ) bool *readFlags = new bool[ factory.plyReadNum() ]; std::vector< PlyProperty > unprocessedProperties; PLY::ReadVertexHeader( In.value , factory , readFlags , unprocessedProperties ); - if( !factory.plyValidReadProperties<0>( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); - if( !factory.plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain normals" ); + if( !factory.template plyValidReadProperties<0>( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); + if( !factory.template plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain normals" ); delete[] readFlags; if( unprocessedProperties.size() ) Execute< Real , Dim , FEMSig >( VertexFactory::DynamicFactory< Real >( unprocessedProperties ) ); @@ -627,8 +627,8 @@ int main( int argc , char* argv[] ) bool *readFlags = new bool[ factory.plyReadNum() ]; std::vector< PlyProperty > unprocessedProperties; PLY::ReadVertexHeader( In.value , factory , readFlags , unprocessedProperties ); - if( !factory.plyValidReadProperties<0>( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); - if( !factory.plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain normals" ); + if( !factory.template plyValidReadProperties<0>( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); + if( !factory.template plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain normals" ); delete[] readFlags; if( unprocessedProperties.size() ) Execute< DEFAULT_DIMENSION , Real >( VertexFactory::DynamicFactory< Real >( unprocessedProperties ) ); diff --git a/Src/ScaleNormals.cpp b/Src/ScaleNormals.cpp index 82708c4d..cfb367db 100644 --- a/Src/ScaleNormals.cpp +++ b/Src/ScaleNormals.cpp @@ -124,9 +124,9 @@ void Execute( void ) std::vector< PlyProperty > unprocessedProperties; PLY::ReadVertexHeader( In.value , factory , readFlags , unprocessedProperties ); - if( !factory.plyValidReadProperties<0>( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); - if( !factory.plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain normals" ); - if( !factory.plyValidReadProperties<2>( readFlags ) ) ERROR_OUT( "Ply file does not contain scales" ); + if( !factory.template plyValidReadProperties<0>( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); + if( !factory.template plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain normals" ); + if( !factory.template plyValidReadProperties<2>( readFlags ) ) ERROR_OUT( "Ply file does not contain scales" ); delete[] readFlags; if( Verbose.set && unprocessedProperties.size() ) diff --git a/Src/SurfaceTrimmer.cpp b/Src/SurfaceTrimmer.cpp index 668d5e6f..07c7f55c 100644 --- a/Src/SurfaceTrimmer.cpp +++ b/Src/SurfaceTrimmer.cpp @@ -584,8 +584,8 @@ int main( int argc , char* argv[] ) if( !Long.set ) WARN( "Number of vertices not supported by 32-bit indexing. Switching to 64-bit indexing" ); Long.set = true; } - if( !factory.plyValidReadProperties<0>( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); - if( !factory.plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain values" ); + if( !factory.template plyValidReadProperties<0>( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); + if( !factory.template plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain values" ); delete[] readFlags; if( Long.set ) return Execute< Real , Dim , long long >( VertexFactory::DynamicFactory< Real >( unprocessedProperties ) ); From afab8a67cfaa566221802bb473a82e8882f74d17 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Fri, 20 Dec 2024 15:52:57 -0500 Subject: [PATCH 74/86] Version 18.60 --- README.md | 44 ++++++++++++++------------------ Src/PoissonRecon.client.inl | 2 +- Src/PoissonRecon.cpp | 6 ++--- Src/PoissonReconClientServer.h | 4 +-- Src/PoissonReconClientServer.inl | 6 ++--- Src/PoissonReconServer.cpp | 6 ++--- Src/PreProcessor.h | 2 +- Src/Reconstructors.h | 10 ++++---- Src/SSDRecon.cpp | 6 ++--- 9 files changed, 40 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 651930ab..820037a9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 18.55)

    +

    Adaptive Multigrid Solvers (Version 18.60)

    links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
    Executables: -Win64
    +Win64
    Source Code: -ZIP GitHub
    +ZIP GitHub
    Older Versions: +V18.55, V18.50, V18.42, V18.41, @@ -244,13 +245,8 @@ The default value for this parameter is 8. of finer data over lower data in performing the extrapolation.
    The default value for this parameter is 32. -
  • [--confidence <normal confidence exponent>] -
    This floating point value specifies the exponent to be applied to a point's confidence to adjust its weight. (A point's confidence is defined by the magnitude of its normal.)
    -The default value for this parameter is 0. - -
    [--confidenceBias <normal confidence bias exponent>] -
    This floating point value specifies the exponent to be applied to a point's confidence to bias the resolution at which the sample contributes to the linear system. (Points with lower confidence are biased to contribute at coarser resolutions.)
    -The default value for this parameter is 0. +
    [--confidence] +
    Enabling this flag specifies that the normal lengths should be used as weights when considering the contribution of a sample.
    [--primalGrid]
    Enabling this flag when outputing to a grid file has the reconstructor sample the implicit function at the corners of the grid, rather than the centers of the cells. @@ -388,18 +384,14 @@ The results of the original (unscreened) Poisson Reconstruction can be obtained of finer data over lower data in performing the extrapolation.
    -
    [--confidence <normal confidence exponent>=0] -
    This floating point value specifies the exponent to be applied to a point's confidence to adjust its weight. (A point's confidence is defined by the magnitude of its normal.)
    -
    - -
    [--confidenceBias <normal confidence bias exponent>=0] -
    This floating point value specifies the exponent to be applied to a point's confidence to bias the resolution at which the sample contributes to the linear system. (Points with lower confidence are biased to contribute at coarser resolutions.)
    -
    -
    [--verbose <verbosity>=0]
    This integer value specifies the level of verbosity of output provided by the client and server, with "0" corresponding to no output and "4" giving the most.
    +
    [--confidence] +
    Enabling this flag specifies that the normal lengths should be used as weights when considering the contribution of a sample. +
    +
    [--linearFit]
    Enabling this flag has the reconstructor use linear interpolation to estimate the positions of iso-vertices.
    @@ -579,13 +571,8 @@ The default value for this parameter is 8. of finer data over lower data in performing the extrapolation.
    The default value for this parameter is 32. -
    [--confidence <normal confidence exponent>] -
    This floating point value specifies the exponent to be applied to a point's confidence to adjust its weight. (A point's confidence is defined by the magnitude of its normal.)
    -The default value for this parameter is 0. - -
    [--confidenceBias <normal confidence bias exponent>] -
    This floating point value specifies the exponent to be applied to a point's confidence to bias the resolution at which the sample contributes to the linear system. (Points with lower confidence are biased to contribute at coarser resolutions.)
    -The default value for this parameter is 0. +
    [--confidence] +
    Enabling this flag specifies that the normal lengths should be used as weights when considering the contribution of a sample.
    [--primalGrid]
    Enabling this flag when outputing to a grid file has the reconstructor sample the implicit function at the corners of the grid, rather than the centers of the cells. @@ -1767,6 +1754,13 @@ Similarly, to reduce compilation times, support for specific degrees can be remo Version 18.55:
    1. Added the ScaleNormals executable. +
    2. Removed the --confidenceBias flag. +
    + +Version 18.60: +
      +
    1. Changed the --confidence flag to be a bool (enabling is equivalent to having set to 1.0). +
    2. Resolved clang compilation issues.
    diff --git a/Src/PoissonRecon.client.inl b/Src/PoissonRecon.client.inl index 7f943fc3..efbbe740 100644 --- a/Src/PoissonRecon.client.inl +++ b/Src/PoissonRecon.client.inl @@ -492,7 +492,7 @@ void Client< Real , Dim , BType , Degree >::_process1( const ClientReconstructio Real l = (Real)Length( d.template get<0>() ); if( !l || !std::isfinite( l ) ) return (Real)-1.; d.template get<0>() /= l; - return clientReconInfo.confidence>0 ? (Real)pow( l , clientReconInfo.confidence ) : (Real)1.; + return clientReconInfo.confidence ? l : (Real)1.; }; std::vector< InputDataStream< typename InputSampleFactory::VertexType > * > pointStreams( endPaddedIndex - beginPaddedIndex , NULL ); diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index 5f61346d..e4e992e1 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -71,6 +71,7 @@ CmdLineReadable NoDirichletErode( "noErode" ) , Gradients( "gradients" ) , GridCoordinates( "gridCoordinates" ) , + Confidence( "confidence" ) , Verbose( "verbose" ); CmdLineParameter< int > @@ -99,7 +100,6 @@ CmdLineParameter< float > SamplesPerNode( "samplesPerNode" , 1.5f ) , Scale( "scale" , 1.1f ) , Width( "width" , 0.f ) , - Confidence( "confidence" , 0.f ) , CGSolverAccuracy( "cgAccuracy" , 1e-3f ) , LowDepthCutOff( "lowDepthCutOff" , 0.f ) , PointWeight( "pointWeight" ); @@ -177,8 +177,8 @@ void ShowUsage(char* ex) for( size_t i=0 ; i=%d]\n" , ThreadChunkSize.name , ThreadChunkSize.value ); printf( "\t[--%s =%f]\n" , LowDepthCutOff.name , LowDepthCutOff.value ); - printf( "\t[--%s =%f]\n" , Confidence.name , Confidence.value ); printf( "\t[--%s =%d]\n" , AlignmentDir.name , AlignmentDir.value ); + printf( "\t[--%s]\n" , Confidence.name ); printf( "\t[--%s]\n" , NonManifold.name ); printf( "\t[--%s]\n" , PolygonMesh.name ); printf( "\t[--%s =%g]\n" , CGSolverAccuracy.name , CGSolverAccuracy.value ); @@ -317,8 +317,8 @@ void Execute( const AuxDataFactory &auxDataFactory ) sParams.dirichletErode = !NoDirichletErode.set; sParams.exactInterpolation = ExactInterpolation.set; sParams.showResidual = ShowResidual.set; + sParams.confidence = Confidence.set; sParams.scale = (Real)Scale.value; - sParams.confidence = (Real)Confidence.value; sParams.lowDepthCutOff = (Real)LowDepthCutOff.value; sParams.width = (Real)Width.value; sParams.pointWeight = (Real)PointWeight.value; diff --git a/Src/PoissonReconClientServer.h b/Src/PoissonReconClientServer.h index dde81632..a41152cc 100644 --- a/Src/PoissonReconClientServer.h +++ b/Src/PoissonReconClientServer.h @@ -63,9 +63,9 @@ namespace PoissonRecon std::string header , inDir , tempDir , outDir; unsigned int solveDepth , reconstructionDepth , sharedDepth , distributionDepth , baseDepth , kernelDepth , iters , bufferSize , filesPerDir , padSize , verbose; - Real pointWeight , confidence , samplesPerNode , dataX , cgSolverAccuracy , targetValue; + Real pointWeight , samplesPerNode , dataX , cgSolverAccuracy , targetValue; MergeType mergeType; - bool density , linearFit , ouputVoxelGrid , outputSolution , gridCoordinates; + bool density , linearFit , ouputVoxelGrid , outputSolution , gridCoordinates , confidence; std::vector< PlyProperty > auxProperties; ClientReconstructionInfo( void ); diff --git a/Src/PoissonReconClientServer.inl b/Src/PoissonReconClientServer.inl index aaaf3a42..fb004f93 100644 --- a/Src/PoissonReconClientServer.inl +++ b/Src/PoissonReconClientServer.inl @@ -322,7 +322,7 @@ ClientReconstructionInfo< Real , Dim >::ClientReconstructionInfo( void ) distributionDepth = 0; baseDepth = 5; iters = 8; - confidence = (Real)0.; + confidence = false; samplesPerNode = (Real)1.5; dataX = (Real)32.; density = false; @@ -361,7 +361,6 @@ ClientReconstructionInfo< Real , Dim >::ClientReconstructionInfo( BinaryStream & if( !stream.read( cgSolverAccuracy ) ) ERROR_OUT( "Failed to read CG-solver-accuracy" ); if( !stream.read( targetValue ) ) ERROR_OUT( "Failed to read target-value" ); if( !stream.read( pointWeight ) ) ERROR_OUT( "Failed to read point-weight" ); - if( !stream.read( confidence ) ) ERROR_OUT( "Failed to read confidence" ); if( !stream.read( samplesPerNode ) ) ERROR_OUT( "Failed to read samples-per-node" ); if( !stream.read( dataX ) ) ERROR_OUT( "Failed to read data-multiplier" ); if( !stream.read( padSize ) ) ERROR_OUT( "Failed to read padSize" ); @@ -372,6 +371,7 @@ ClientReconstructionInfo< Real , Dim >::ClientReconstructionInfo( BinaryStream & if( !ReadBool( outputSolution ) ) ERROR_OUT( "Failed to read output-solution flag" ); if( !ReadBool( gridCoordinates ) ) ERROR_OUT( "Failed to read grid-coordinates flag" ); if( !ReadBool( ouputVoxelGrid ) ) ERROR_OUT( "Failed to read output-voxel-grid flag" ); + if( !ReadBool( confidence ) ) ERROR_OUT( "Failed to read confidence flag" ); { size_t sz; if( !stream.read( sz ) ) ERROR_OUT( "Failed to read number of auxiliary properties" ); @@ -404,7 +404,6 @@ void ClientReconstructionInfo< Real , Dim >::write( BinaryStream &stream ) const stream.write( cgSolverAccuracy ); stream.write( targetValue ); stream.write( pointWeight ); - stream.write( confidence ); stream.write( samplesPerNode ); stream.write( dataX ); stream.write( padSize ); @@ -415,6 +414,7 @@ void ClientReconstructionInfo< Real , Dim >::write( BinaryStream &stream ) const WriteBool( outputSolution ); WriteBool( gridCoordinates ); WriteBool( ouputVoxelGrid ); + WriteBool( confidence ); { size_t sz = auxProperties.size(); stream.write( sz ); diff --git a/Src/PoissonReconServer.cpp b/Src/PoissonReconServer.cpp index a68fe89d..0723f864 100644 --- a/Src/PoissonReconServer.cpp +++ b/Src/PoissonReconServer.cpp @@ -99,12 +99,12 @@ CmdLineReadable GridCoordinates( "gridCoordinates" ) , KeepSeparate( "keepSeparate" ) , OutputSolution( "solution" ) , + Confidence( "confidence" ) , ShowDiscontinuity( "showDiscontinuity" ); CmdLineParameter< float > Scale( "scale" , 1.1f ) , Width( "width" , 0.f ) , - Confidence( "confidence" , 0.f ) , SamplesPerNode( "samplesPerNode" , 1.5f ) , DataX( "data" , 32.f ) , PointWeight( "pointWeight" ) , @@ -172,7 +172,6 @@ void ShowUsage( char* ex ) printf( "\t[--%s =%g]\n" , CGSolverAccuracy.name , CGSolverAccuracy.value ); printf( "\t[--%s =%f]\n" , TargetValue.name , TargetValue.value ); printf( "\t[--%s =%.3e * ]\n" , PointWeight.name , Reconstructor::Poisson::WeightMultiplier ); - printf( "\t[--%s =%f]\n" , Confidence.name , Confidence.value ); printf( "\t[--%s =%f]\n" , DataX.name , DataX.value ); printf( "\t[--%s =%d]\n" , PadSize.name , PadSize.value ); printf( "\t[--%s =%d]\n" , BufferSize.name , BufferSize.value ); @@ -188,6 +187,7 @@ void ShowUsage( char* ex ) for( unsigned int i=0 ; i=%d]\n" , AlignmentDir.name , AlignmentDir.value ); printf( "\t[--%s =%d]\n" , Verbose.name , Verbose.value ); + printf( "\t[--%s]\n" , Confidence.name ); printf( "\t[--%s]\n" , NoLoadBalance.name ); printf( "\t[--%s]\n" , Density.name ); printf( "\t[--%s]\n" , LinearFit.name ); @@ -488,12 +488,12 @@ int main( int argc , char* argv[] ) clientReconInfo.bufferSize = BufferSize.value; clientReconInfo.iters = Iters.value; clientReconInfo.pointWeight = PointWeight.value; - clientReconInfo.confidence = Confidence.value; clientReconInfo.kernelDepth = KernelDepth.value; clientReconInfo.samplesPerNode = SamplesPerNode.value; clientReconInfo.dataX = DataX.value; clientReconInfo.density = Density.set; clientReconInfo.linearFit = LinearFit.set; + clientReconInfo.confidence = Confidence.set; switch( MergeSlabs.value ) { case MergeSlabType::NONE: clientReconInfo.mergeType = PoissonReconClientServer::ClientReconstructionInfo< Real , Dim >::MergeType::NONE ; break; diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 4f9619ce..8998b99d 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -46,7 +46,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "18.55" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "18.60" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h index 7f72656d..4646da3d 100644 --- a/Src/Reconstructors.h +++ b/Src/Reconstructors.h @@ -68,8 +68,8 @@ namespace PoissonRecon bool verbose; bool exactInterpolation; bool showResidual; + bool confidence; Real scale; - Real confidence; Real lowDepthCutOff; Real width; Real samplesPerNode; @@ -85,8 +85,8 @@ namespace PoissonRecon unsigned int alignDir; SolutionParameters( void ) : - verbose(false) , exactInterpolation(false) , showResidual(false) , - scale((Real)1.1) ,confidence((Real)0.) , + verbose(false) , exactInterpolation(false) , showResidual(false) , confidence(false) , + scale((Real)1.1) , lowDepthCutOff((Real)0.) , width((Real)0.) , samplesPerNode((Real)1.5) , cgSolverAccuracy((Real)1e-3 ) , perLevelDataScaleFactor((Real)32.) , depth((unsigned int)8) , solveDepth((unsigned int)-1) , baseDepth((unsigned int)-1) , fullDepth((unsigned int)5) , kernelDepth((unsigned int)-1) , @@ -716,7 +716,7 @@ namespace PoissonRecon auto Process = [&]( FEMTreeNode &node , const Point< Real , Dim > &p , Normal< Real , Dim > &n , AuxData ... d ) { Real l = (Real)Length( n ); - Real weight = params.confidence>0 ? pow( l , params.confidence ) : (Real)1.; + Real weight = params.confidence ? l : (Real)1.; n /= l; node_index_type nodeIndex = node.nodeData.nodeIndex; @@ -1124,7 +1124,7 @@ namespace PoissonRecon auto Process = [&]( FEMTreeNode &node , const Point< Real , Dim > &p , Normal< Real , Dim > &n , AuxData ... d ) { Real l = (Real)Length( n ); - Real weight = params.confidence>0 ? pow( l , params.confidence ) : (Real)1.; + Real weight = params.confidence ? l : (Real)1.; n /= l; node_index_type nodeIndex = node.nodeData.nodeIndex; diff --git a/Src/SSDRecon.cpp b/Src/SSDRecon.cpp index c4d9c7a3..56619855 100644 --- a/Src/SSDRecon.cpp +++ b/Src/SSDRecon.cpp @@ -69,6 +69,7 @@ CmdLineReadable InCore( "inCore" ) , Gradients( "gradients" ) , GridCoordinates( "gridCoordinates" ) , + Confidence( "confidence" ) , Verbose( "verbose" ); CmdLineParameter< int > @@ -96,7 +97,6 @@ CmdLineParameter< float > SamplesPerNode( "samplesPerNode" , 1.5f ) , Scale( "scale" , 1.1f ) , Width( "width" , 0.f ) , - Confidence( "confidence" , 0.f ) , LowDepthCutOff( "lowDepthCutOff" , 0.f ) , CGSolverAccuracy( "cgAccuracy" , 1e-3f ) , ValueWeight ( "valueWeight" , 1.f ) , @@ -173,13 +173,13 @@ void ShowUsage(char* ex) printf( "\t[--%s =%d]\n" , ScheduleType.name , ScheduleType.value ); for( size_t i=0 ; i=%d]\n" , ThreadChunkSize.name , ThreadChunkSize.value ); - printf( "\t[--%s =%f]\n" , Confidence.name , Confidence.value ); printf( "\t[--%s =%f]\n" , LowDepthCutOff.name , LowDepthCutOff.value ); printf( "\t[--%s =%d]\n" , AlignmentDir.name , AlignmentDir.value ); printf( "\t[--%s]\n" , NonManifold.name ); printf( "\t[--%s]\n" , PolygonMesh.name ); printf( "\t[--%s =%g]\n" , CGSolverAccuracy.name , CGSolverAccuracy.value ); printf( "\t[--%s =%d]\n" , MaxMemoryGB.name , MaxMemoryGB.value ); + printf( "\t[--%s]\n" , Confidence.name ); printf( "\t[--%s]\n" , GridCoordinates.name ); printf( "\t[--%s]\n" , Performance.name ); printf( "\t[--%s]\n" , Density.name ); @@ -313,8 +313,8 @@ void Execute( const AuxDataFactory &auxDataFactory ) sParams.verbose = Verbose.set; sParams.exactInterpolation = ExactInterpolation.set; sParams.showResidual = ShowResidual.set; + sParams.confidence = Confidence.set; sParams.scale = (Real)Scale.value; - sParams.confidence = (Real)Confidence.value; sParams.lowDepthCutOff = (Real)LowDepthCutOff.value; sParams.width = (Real)Width.value; sParams.pointWeight = (Real)ValueWeight.value; From 4ffa838cd3ea4348ac02b2883692d4338312150d Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Thu, 16 Jan 2025 21:30:32 -0500 Subject: [PATCH 75/86] Version18.60 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 820037a9..d9a5d0e9 100644 --- a/README.md +++ b/README.md @@ -33,8 +33,8 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo Source Code: ZIP GitHub
    Older Versions: -V18.55, -V18.50, +V18.55, +V18.50, V18.42, V18.41, V18.40, From 87793e561d68b752b0070e309676b7c4f3749545 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Mon, 3 Mar 2025 17:57:22 -0500 Subject: [PATCH 76/86] Version 18.69 --- Src/PreProcessor.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 8998b99d..731df6a5 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -51,6 +51,10 @@ DAMAGE. #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth +#ifdef BIG_DATA +#define NESTED_VECTOR_LEVELS 2 // The number of nesting levels for the nested-vector +#else // !BIG_DATA #define NESTED_VECTOR_LEVELS 1 // The number of nesting levels for the nested-vector +#endif // BIG_DATA #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file From 9fedb1860fd8fcabb57e1ab0d91965de4d8dd699 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Mon, 3 Mar 2025 20:40:22 -0500 Subject: [PATCH 77/86] Version 18.60 --- Src/PreProcessor.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 731df6a5..0e114f19 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -50,11 +50,6 @@ DAMAGE. #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth - -#ifdef BIG_DATA #define NESTED_VECTOR_LEVELS 2 // The number of nesting levels for the nested-vector -#else // !BIG_DATA -#define NESTED_VECTOR_LEVELS 1 // The number of nesting levels for the nested-vector -#endif // BIG_DATA #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file From 165cb4ffa6ef534dde4e7f53842c7938239707c9 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Mon, 3 Mar 2025 20:40:46 -0500 Subject: [PATCH 78/86] Version 18.60 --- Src/PreProcessor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 0e114f19..c02e770e 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -50,6 +50,6 @@ DAMAGE. #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth -#define NESTED_VECTOR_LEVELS 2 // The number of nesting levels for the nested-vector +#define NESTED_VECTOR_LEVELS 1 // The number of nesting levels for the nested-vector #endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file From d17d5247fae48d89a94638c5b462e56f0399ff3d Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Tue, 8 Apr 2025 11:44:53 -0400 Subject: [PATCH 79/86] Version 18.70 --- AdaptiveSolvers.sln | 1 + AdaptiveTreeVisualization.vcxproj | 6 +- ChunkPLY.vcxproj | 6 +- EDTInHeat.vcxproj | 6 +- ImageStitching.vcxproj | 6 +- JPEG.vcxproj | 6 +- PNG.vcxproj | 6 +- PointInterpolant.vcxproj | 6 +- PointsToDisks.vcxproj | 6 +- PoissonRecon.vcxproj | 6 +- SSDRecon.vcxproj | 6 +- Src/AdaptiveTreeVisualization.cpp | 22 +- Src/Allocator.h | 4 +- Src/Array.inl | 36 +- Src/BSplineData.inl | 4 +- Src/BlockedVector.h | 28 +- Src/ChunkPLY.cpp | 22 +- Src/CmdLineParser.inl | 10 +- Src/DataStream.imp.h | 2 +- Src/DataStream.imp.inl | 22 +- Src/DataStream.inl | 4 +- Src/EDTInHeat.cpp | 18 +- Src/Extrapolator.h | 4 +- Src/FEMTree.Evaluation.inl | 16 +- Src/FEMTree.Initialize.inl | 36 +- Src/FEMTree.LevelSet.2D.inl | 58 ++- Src/FEMTree.LevelSet.3D.inl | 58 +-- Src/FEMTree.LevelSet.inl | 16 +- Src/FEMTree.SortedTreeNodes.inl | 4 +- Src/FEMTree.System.inl | 28 +- Src/FEMTree.WeightedSamples.inl | 4 +- Src/FEMTree.h | 88 ++--- Src/FEMTree.inl | 56 +-- Src/Geometry.h | 26 +- Src/Image.h | 46 +-- Src/ImageStitching.cpp | 14 +- Src/JPEG.inl | 10 +- Src/MarchingCubes.h | 6 +- Src/MergePlyClientServer.inl | 28 +- Src/MyAtomic.h | 16 +- Src/MyExceptions.h | 37 +- Src/MyMiscellany.h | 2 +- Src/NestedVector.h | 16 +- Src/PNG.inl | 28 +- Src/ParameterPack.h | 349 +++++++++++++++++ Src/Ply.inl | 48 +-- Src/PlyFile.h | 14 +- Src/PlyFile.inl | 54 +-- Src/PointInterpolant.cpp | 44 +-- Src/PointPartition.inl | 36 +- Src/PointPartitionClientServer.inl | 52 +-- Src/PointsToDisks.cpp | 6 +- Src/PoissonRecon.client.inl | 26 +- Src/PoissonRecon.cpp | 26 +- Src/PoissonRecon.server.inl | 12 +- Src/PoissonReconClient.cpp | 10 +- Src/PoissonReconClientServer.inl | 64 ++-- Src/PoissonReconServer.cpp | 26 +- Src/Polynomial.inl | 2 +- Src/PreProcessor.h | 2 +- Src/Rasterizer.h | 2 +- Src/Rasterizer.inl | 6 +- Src/Reconstructors.h | 30 +- Src/Reconstructors.streams.h | 2 +- Src/RegularGrid.inl | 16 +- Src/RegularTree.h | 109 +++--- Src/RegularTree.inl | 176 +++++---- Src/SSDRecon.cpp | 28 +- Src/ScaleNormals.cpp | 8 +- Src/Socket.h | 8 +- Src/Socket.inl | 24 +- Src/SparseMatrix.inl | 20 +- Src/SurfaceTrimmer.cpp | 12 +- Src/VertexFactory.h | 20 +- Src/VertexFactory.inl | 66 ++-- Src/Window.h | 593 ++++++++++++----------------- Src/Window.inl | 373 +++++------------- SurfaceTrimmer.vcxproj | 6 +- ZLIB.vcxproj | 6 +- 79 files changed, 1572 insertions(+), 1534 deletions(-) create mode 100644 Src/ParameterPack.h diff --git a/AdaptiveSolvers.sln b/AdaptiveSolvers.sln index cd4aba7e..e1136125 100644 --- a/AdaptiveSolvers.sln +++ b/AdaptiveSolvers.sln @@ -65,6 +65,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Header Files", "Header File Src\MyExceptions.h = Src\MyExceptions.h Src\MyMiscellany.h = Src\MyMiscellany.h Src\NestedVector.h = Src\NestedVector.h + Src\ParameterPack.h = Src\ParameterPack.h Src\Ply.h = Src\Ply.h Src\PlyFile.h = Src\PlyFile.h Src\PNG.h = Src\PNG.h diff --git a/AdaptiveTreeVisualization.vcxproj b/AdaptiveTreeVisualization.vcxproj index 42ee0efc..d294be5c 100644 --- a/AdaptiveTreeVisualization.vcxproj +++ b/AdaptiveTreeVisualization.vcxproj @@ -31,20 +31,20 @@ Application true - v142 + v143 Unicode Application false - v142 + v143 true Unicode Application true - v142 + v143 Unicode diff --git a/ChunkPLY.vcxproj b/ChunkPLY.vcxproj index f245d0e9..cdca268c 100644 --- a/ChunkPLY.vcxproj +++ b/ChunkPLY.vcxproj @@ -32,20 +32,20 @@ Application true - v142 + v143 Unicode Application false - v142 + v143 true Unicode Application true - v142 + v143 Unicode diff --git a/EDTInHeat.vcxproj b/EDTInHeat.vcxproj index 4b89ed10..832fca3d 100644 --- a/EDTInHeat.vcxproj +++ b/EDTInHeat.vcxproj @@ -31,20 +31,20 @@ Application true - v142 + v143 Unicode Application false - v142 + v143 true Unicode Application true - v142 + v143 Unicode diff --git a/ImageStitching.vcxproj b/ImageStitching.vcxproj index 8790825d..03630e81 100644 --- a/ImageStitching.vcxproj +++ b/ImageStitching.vcxproj @@ -31,20 +31,20 @@ Application true - v142 + v143 Unicode Application false - v142 + v143 true Unicode Application true - v142 + v143 Unicode diff --git a/JPEG.vcxproj b/JPEG.vcxproj index 22bb606b..230ea232 100644 --- a/JPEG.vcxproj +++ b/JPEG.vcxproj @@ -91,20 +91,20 @@ StaticLibrary true Unicode - v142 + v143 StaticLibrary true Unicode - v142 + v143 StaticLibrary false true Unicode - v142 + v143 StaticLibrary diff --git a/PNG.vcxproj b/PNG.vcxproj index 310c88f9..3f133dc8 100644 --- a/PNG.vcxproj +++ b/PNG.vcxproj @@ -54,12 +54,12 @@ StaticLibrary Unicode true - v142 + v143 StaticLibrary Unicode - v142 + v143 StaticLibrary @@ -70,7 +70,7 @@ StaticLibrary Unicode - v142 + v143 diff --git a/PointInterpolant.vcxproj b/PointInterpolant.vcxproj index 47200e41..5b7dadc8 100644 --- a/PointInterpolant.vcxproj +++ b/PointInterpolant.vcxproj @@ -33,20 +33,20 @@ Application true - v142 + v143 Unicode Application false - v142 + v143 true Unicode Application true - v142 + v143 Unicode diff --git a/PointsToDisks.vcxproj b/PointsToDisks.vcxproj index bd675b4e..f57aa006 100644 --- a/PointsToDisks.vcxproj +++ b/PointsToDisks.vcxproj @@ -32,20 +32,20 @@ Application true - v142 + v143 Unicode Application false - v142 + v143 true Unicode Application true - v142 + v143 Unicode diff --git a/PoissonRecon.vcxproj b/PoissonRecon.vcxproj index bffa049d..7c3c45c2 100644 --- a/PoissonRecon.vcxproj +++ b/PoissonRecon.vcxproj @@ -30,12 +30,12 @@ Application MultiByte true - v142 + v143 Application MultiByte - v142 + v143 Application @@ -46,7 +46,7 @@ Application MultiByte - v142 + v143 diff --git a/SSDRecon.vcxproj b/SSDRecon.vcxproj index 00ac642b..95f3a1b2 100644 --- a/SSDRecon.vcxproj +++ b/SSDRecon.vcxproj @@ -32,20 +32,20 @@ Application true - v142 + v143 Unicode Application false - v142 + v143 true Unicode Application true - v142 + v143 Unicode diff --git a/Src/AdaptiveTreeVisualization.cpp b/Src/AdaptiveTreeVisualization.cpp index 392ce04a..6af250e0 100644 --- a/Src/AdaptiveTreeVisualization.cpp +++ b/Src/AdaptiveTreeVisualization.cpp @@ -176,7 +176,7 @@ void WriteGrid( const char *fileName , ConstPointer( Real ) values , unsigned in else if( !strcasecmp( ext , "iso" ) ) { FILE *fp = fopen( fileName , "wb" ); - if( !fp ) ERROR_OUT( "Failed to open file for writing: " , fileName ); + if( !fp ) MK_ERROR_OUT( "Failed to open file for writing: " , fileName ); int r = (int)res; fwrite( &r , sizeof(int) , 1 , fp ); size_t count = 1; @@ -381,7 +381,7 @@ void _Execute( const FEMTree< Dim , Real > *tree , XForm< Real , Dim+1 > modelTo sliceModelToUnitCube(Dim-1,i) = modelToUnitCube(Dim,i); } FILE *fp = fopen( OutSlice.value , "wb" ); - if( !fp ) ERROR_OUT( "Failed to open file for writing: " , OutSlice.value ); + if( !fp ) MK_ERROR_OUT( "Failed to open file for writing: " , OutSlice.value ); FileStream fs(fp); FEMTree< Dim-1 , Real >::WriteParameter( fs ); DenseNodeData< Real , IsotropicUIntPack< Dim-1 , FEMSig > >::WriteSignatures( fs ); @@ -432,7 +432,7 @@ void Execute( BinaryStream &stream , int degree , FEMTree< Dim , Real > *tree , case 2: _Execute< Dim , Real , FEMDegreeAndBType< 2 , BType >::Signature >( tree , modelToUnitCube , stream ) ; break; case 3: _Execute< Dim , Real , FEMDegreeAndBType< 3 , BType >::Signature >( tree , modelToUnitCube , stream ) ; break; case 4: _Execute< Dim , Real , FEMDegreeAndBType< 4 , BType >::Signature >( tree , modelToUnitCube , stream ) ; break; - default: ERROR_OUT( "Only B-Splines of degree 1 - 4 are supported" ); + default: MK_ERROR_OUT( "Only B-Splines of degree 1 - 4 are supported" ); } } @@ -450,14 +450,14 @@ void Execute( BinaryStream &stream , int degree , BoundaryType bType ) case BOUNDARY_FREE: return Execute< Dim , Real , BOUNDARY_FREE >( stream , degree , &tree , modelToUnitCube ); case BOUNDARY_NEUMANN: return Execute< Dim , Real , BOUNDARY_NEUMANN >( stream , degree , &tree , modelToUnitCube ); case BOUNDARY_DIRICHLET: return Execute< Dim , Real , BOUNDARY_DIRICHLET >( stream , degree , &tree , modelToUnitCube ); - default: ERROR_OUT( "Not a valid boundary type: " , bType ); + default: MK_ERROR_OUT( "Not a valid boundary type: " , bType ); } } int main( int argc , char* argv[] ) { #ifdef ARRAY_DEBUG - WARN( "Array debugging enabled" ); + MK_WARN( "Array debugging enabled" ); #endif // ARRAY_DEBUG CmdLineParse( argc-1 , &argv[1] , params ); ThreadPool::ChunkSize = ThreadChunkSize.value; @@ -477,7 +477,7 @@ int main( int argc , char* argv[] ) return EXIT_FAILURE; } FILE* fp = fopen( In.value , "rb" ); - if( !fp ) ERROR_OUT( "Failed to open file for reading: " , In.value ); + if( !fp ) MK_ERROR_OUT( "Failed to open file for reading: " , In.value ); FEMTreeRealType realType ; int degree ; BoundaryType bType; unsigned int dimension; FileStream fs(fp); @@ -485,8 +485,8 @@ int main( int argc , char* argv[] ) { unsigned int dim = dimension; unsigned int* sigs = ReadDenseNodeDataSignatures( fs , dim ); - if( dimension!=dim ) ERROR_OUT( "Octree and node data dimensions don't math: " , dimension , " != " , dim ); - for( unsigned int d=1 ; d( fs , degree , bType ) ; break; case FEM_TREE_REAL_DOUBLE: Execute< 2 , double >( fs , degree , bType ) ; break; - default: ERROR_OUT( "Unrecognized real type: " , realType ); + default: MK_ERROR_OUT( "Unrecognized real type: " , realType ); } break; case 3: @@ -508,10 +508,10 @@ int main( int argc , char* argv[] ) { case FEM_TREE_REAL_FLOAT: Execute< 3 , float >( fs , degree , bType ) ; break; case FEM_TREE_REAL_DOUBLE: Execute< 3 , double >( fs , degree , bType ) ; break; - default: ERROR_OUT( "Unrecognized real type: " , realType ); + default: MK_ERROR_OUT( "Unrecognized real type: " , realType ); } break; - default: ERROR_OUT( "Only dimensions 1-4 supported" ); + default: MK_ERROR_OUT( "Only dimensions 1-4 supported" ); } fclose( fp ); diff --git a/Src/Allocator.h b/Src/Allocator.h index 7ecd050d..e35e3542 100644 --- a/Src/Allocator.h +++ b/Src/Allocator.h @@ -88,13 +88,13 @@ namespace PoissonRecon { Pointer( T ) mem; if( !elements ) return NullPointer( T ); - if( elements>_blockSize ) ERROR_OUT( "elements bigger than block-size: " , elements , " > " , _blockSize ); + if( elements>_blockSize ) MK_ERROR_OUT( "elements bigger than block-size: " , elements , " > " , _blockSize ); if( _state.remains( _blockSize ); - if( !mem ) ERROR_OUT( "Failed to allocate memory" ); + if( !mem ) MK_ERROR_OUT( "Failed to allocate memory" ); _memory.push_back( mem ); } _state.index++; diff --git a/Src/Array.inl b/Src/Array.inl index 16cbc1f4..7eb1f472 100644 --- a/Src/Array.inl +++ b/Src/Array.inl @@ -35,7 +35,7 @@ class Array friend class ConstArray< C >; void _assertBounds( std::ptrdiff_t idx ) const { - if( idx=max ) PoissonRecon::ERROR_OUT( "Array index out-of-bounds: " , min , " <= " , idx , " < " , max ); + if( idx=max ) PoissonRecon::MK_ERROR_OUT( "Array index out-of-bounds: " , min , " <= " , idx , " < " , max ); } protected: C *data , *_data; @@ -119,7 +119,7 @@ public: 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 ) PoissonRecon::ERROR_OUT( "Could not convert array [ " , a.minimum() , " , " , a.maximum() , " ] * " , szD , " => [ " , min , " , " , max , " ] * " , szC ); + if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD ) PoissonRecon::MK_ERROR_OUT( "Could not convert array [ " , a.minimum() , " , " , a.maximum() , " ] * " , szD , " => [ " , min , " , " , max , " ] * " , szC ); } } static Array FromPointer( C* data , std::ptrdiff_t max ) @@ -236,7 +236,7 @@ class ConstArray template< class D > friend class ConstArray; void _assertBounds( std::ptrdiff_t idx ) const { - if( idx=max ) PoissonRecon::ERROR_OUT( "ConstArray index out-of-bounds: " , min , " <= " , idx , " < " , max ); + if( idx=max ) PoissonRecon::MK_ERROR_OUT( "ConstArray index out-of-bounds: " , min , " <= " , idx , " < " , max ); } protected: const C *data; @@ -266,7 +266,7 @@ public: 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 ) PoissonRecon::ERROR_OUT( "Could not convert const array [ " , a.minimum() , " , " , a.maximum() , " ] * " , szD , " => [ " , min , " , " , max , " ] * " , szC ); + if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD ) PoissonRecon::MK_ERROR_OUT( "Could not convert const array [ " , a.minimum() , " , " , a.maximum() , " ] * " , szD , " => [ " , min , " , " , max , " ] * " , szC ); } template< class D > inline ConstArray( ConstArray< D > a ) @@ -277,7 +277,7 @@ public: 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 ) PoissonRecon::ERROR_OUT( "Could not convert array [ " , a.minimum() , " , " , a.maximum() , " ] * " , szD , " => [ " , min , " , " , max , " ] * " , szC ); + if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD ) PoissonRecon::MK_ERROR_OUT( "Could not convert array [ " , a.minimum() , " , " , a.maximum() , " ] * " , szD , " => [ " , min , " , " , max , " ] * " , szC ); } explicit operator Array< C >() const { @@ -361,44 +361,44 @@ public: template< class C > Array< C > memcpy( Array< C > destination , const void* source , size_t size ) { - if( size>destination.maximum()*sizeof(C) ) PoissonRecon::ERROR_OUT( "Size of copy exceeds destination maximum: " , size , " > " , destination.maximum()*sizeof( C ) ); + if( size>destination.maximum()*sizeof(C) ) PoissonRecon::MK_ERROR_OUT( "Size of copy exceeds destination maximum: " , size , " > " , destination.maximum()*sizeof( C ) ); 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 ) ) PoissonRecon::ERROR_OUT( "Size of copy exceeds destination maximum: " , size , " > " , destination.maximum()*sizeof( C ) ); - if( size>source.maximum()*sizeof( D ) ) PoissonRecon::ERROR_OUT( "Size of copy exceeds source maximum: " , size , " > " , source.maximum()*sizeof( D ) ); + if( size>destination.maximum()*sizeof( C ) ) PoissonRecon::MK_ERROR_OUT( "Size of copy exceeds destination maximum: " , size , " > " , destination.maximum()*sizeof( C ) ); + if( size>source.maximum()*sizeof( D ) ) PoissonRecon::MK_ERROR_OUT( "Size of copy exceeds source maximum: " , size , " > " , source.maximum()*sizeof( D ) ); 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 ) ) PoissonRecon::ERROR_OUT( "Size of copy exceeds destination maximum: " , size , " > " , destination.maximum()*sizeof( C ) ); - if( size>source.maximum()*sizeof( D ) ) PoissonRecon::ERROR_OUT( "Size of copy exceeds source maximum: " , size , " > " , source.maximum()*sizeof( D ) ); + if( size>destination.maximum()*sizeof( C ) ) PoissonRecon::MK_ERROR_OUT( "Size of copy exceeds destination maximum: " , size , " > " , destination.maximum()*sizeof( C ) ); + if( size>source.maximum()*sizeof( D ) ) PoissonRecon::MK_ERROR_OUT( "Size of copy exceeds source maximum: " , size , " > " , source.maximum()*sizeof( D ) ); 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 ) ) PoissonRecon::ERROR_OUT( "Size of copy exceeds source maximum: " , size , " > " , source.maximum()*sizeof( D ) ); + if( size>source.maximum()*sizeof( D ) ) PoissonRecon::MK_ERROR_OUT( "Size of copy exceeds source maximum: " , size , " > " , source.maximum()*sizeof( D ) ); 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 ) ) PoissonRecon::ERROR_OUT( "Size of copy exceeds source maximum: " , size , " > " , source.maximum()*sizeof( D ) ); + if( size>source.maximum()*sizeof( D ) ) PoissonRecon::MK_ERROR_OUT( "Size of copy exceeds source maximum: " , size , " > " , source.maximum()*sizeof( D ) ); 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 ) ) PoissonRecon::ERROR_OUT( "Size of set exceeds destination maximum: " , size , " > " , destination.maximum()*sizeof( C ) ); + if( size>destination.maximum()*sizeof( C ) ) PoissonRecon::MK_ERROR_OUT( "Size of set exceeds destination maximum: " , size , " > " , destination.maximum()*sizeof( C ) ); if( size ) memset( &destination[0] , value , size ); return destination; } @@ -406,28 +406,28 @@ Array< C > memset( Array< C > destination , int value , size_t size ) template< class C > size_t fread( Array< C > destination , size_t eSize , size_t count , FILE* fp ) { - if( count*eSize>destination.maximum()*sizeof( C ) ) PoissonRecon::ERROR_OUT( "Size of read exceeds source maximum: " , count*eSize , " > " , destination.maximum()*sizeof( C ) ); + if( count*eSize>destination.maximum()*sizeof( C ) ) PoissonRecon::MK_ERROR_OUT( "Size of read exceeds source maximum: " , count*eSize , " > " , destination.maximum()*sizeof( C ) ); if( count ) return fread( &destination[0] , eSize , count , fp ); else return 0; } template< class C > size_t fwrite( Array< C > source , size_t eSize , size_t count , FILE* fp ) { - if( count*eSize>source.maximum()*sizeof( C ) ) PoissonRecon::ERROR_OUT( "Size of write exceeds source maximum: " , count*eSize , " > " , source.maximum()*sizeof( C ) ); + if( count*eSize>source.maximum()*sizeof( C ) ) PoissonRecon::MK_ERROR_OUT( "Size of write exceeds source maximum: " , count*eSize , " > " , source.maximum()*sizeof( C ) ); if( count ) return fwrite( &source[0] , eSize , count , fp ); else return 0; } template< class C > size_t fwrite( ConstArray< C > source , size_t eSize , size_t count , FILE* fp ) { - if( count*eSize>source.maximum()*sizeof( C ) ) PoissonRecon::ERROR_OUT( "Size of write exceeds source maximum: " , count*eSize , " > " , source.maximum()*sizeof( C ) ); + if( count*eSize>source.maximum()*sizeof( C ) ) PoissonRecon::MK_ERROR_OUT( "Size of write exceeds source maximum: " , count*eSize , " > " , source.maximum()*sizeof( C ) ); if( count ) return fwrite( &source[0] , eSize , count , fp ); else return 0; } template< class C > void qsort( Array< C > base , size_t numElements , size_t elementSize , int (*compareFunction)( const void* , const void* ) ) { - if( sizeof(C)!=elementSize ) PoissonRecon::ERROR_OUT( "Element sizes differ: " , sizeof(C) , " != " , elementSize ); - if( base.minimum()>0 || base.maximum() " , Degree1 ); - if( D2>Degree2 ) ERROR_OUT( "Taking more derivatives than the degree: " , D2 , " > " , Degree2 ); + if( D1>Degree1 ) MK_ERROR_OUT( "Taking more derivatives than the degree: " , D1 , " > " , Degree1 ); + if( D2>Degree2 ) MK_ERROR_OUT( "Taking more derivatives than the degree: " , D2 , " > " , Degree2 ); const int _Degree1 = ( Degree1>=D1 ) ? Degree1 - D1 : 0 , _Degree2 = ( Degree2>=D2 ) ? Degree2 - D2 : 0; int sums[ Degree1+1 ][ Degree2+1 ]; diff --git a/Src/BlockedVector.h b/Src/BlockedVector.h index 225be466..92f0bce0 100644 --- a/Src/BlockedVector.h +++ b/Src/BlockedVector.h @@ -182,19 +182,19 @@ namespace PoissonRecon { for( size_t i=0 ; i<_allocatedBlocks ; i++ ) DeletePointer( _blocks[i] ); DeletePointer( _blocks ); - if( !stream.read( _size ) ) ERROR_OUT( "Failed to read _size" ); - if( !stream.read( _defaultValue ) ) ERROR_OUT( "Failed to read _defaultValue" ); - if( !stream.read( _reservedBlocks ) ) ERROR_OUT( "Failed to read _reservedBlocks" ); - if( !stream.read( _allocatedBlocks ) ) ERROR_OUT( "Failed to read _allocatedBlocks" ); + if( !stream.read( _size ) ) MK_ERROR_OUT( "Failed to read _size" ); + if( !stream.read( _defaultValue ) ) MK_ERROR_OUT( "Failed to read _defaultValue" ); + if( !stream.read( _reservedBlocks ) ) MK_ERROR_OUT( "Failed to read _reservedBlocks" ); + if( !stream.read( _allocatedBlocks ) ) MK_ERROR_OUT( "Failed to read _allocatedBlocks" ); _blocks = NewPointer< Pointer( T ) >( _reservedBlocks ); - if( !_blocks ) ERROR_OUT( "Failed to allocate _blocks: " , _reservedBlocks ); + if( !_blocks ) MK_ERROR_OUT( "Failed to allocate _blocks: " , _reservedBlocks ); for( size_t i=0 ; i<_allocatedBlocks ; i++ ) { _blocks[i] = NewPointer< T >( _BlockSize ); - if( !_blocks[i] ) ERROR_OUT( "Failed to allocate _blocks[" , i , "]" ); - if( !stream.read( _blocks[i] , _BlockSize ) ) ERROR_OUT( "Failed to read _blocks[" , i , "]" ); + if( !_blocks[i] ) MK_ERROR_OUT( "Failed to allocate _blocks[" , i , "]" ); + if( !stream.read( _blocks[i] , _BlockSize ) ) MK_ERROR_OUT( "Failed to read _blocks[" , i , "]" ); } for( size_t i=_allocatedBlocks ; i<_reservedBlocks ; i++ ) _blocks[i] = NullPointer( T ); } @@ -207,24 +207,24 @@ namespace PoissonRecon DeletePointer( _blocks ); _size = _allocatedBlocks = _reservedBlocks = 0; - if( !stream.read( _size ) ) ERROR_OUT( "Failed to read _size" ); + if( !stream.read( _size ) ) MK_ERROR_OUT( "Failed to read _size" ); #ifdef SHOW_WARNINGS #pragma message( "[WARNING] Should deserialize default value" ) #endif // SHOW_WARNINGS - if( !stream.read( _defaultValue ) ) ERROR_OUT( "Failed to read _defaultValue" ); - if( !stream.read( _reservedBlocks ) ) ERROR_OUT( "Failed to read _reservedBlocks" ); - if( !stream.read( _allocatedBlocks ) ) ERROR_OUT( "Failed to read _allocatedBlocks" ); + if( !stream.read( _defaultValue ) ) MK_ERROR_OUT( "Failed to read _defaultValue" ); + if( !stream.read( _reservedBlocks ) ) MK_ERROR_OUT( "Failed to read _reservedBlocks" ); + if( !stream.read( _allocatedBlocks ) ) MK_ERROR_OUT( "Failed to read _allocatedBlocks" ); _blocks = NewPointer< Pointer( T ) >( _reservedBlocks ); - if( !_blocks ) ERROR_OUT( "Failed to allocate _blocks: " , _reservedBlocks ); + if( !_blocks ) MK_ERROR_OUT( "Failed to allocate _blocks: " , _reservedBlocks ); for( size_t i=0 ; i<_allocatedBlocks ; i++ ) { _blocks[i] = NewPointer< T >( _BlockSize ); - if( !_blocks[i] ) ERROR_OUT( "Failed to allocate _blocks[" , i , "]" ); + if( !_blocks[i] ) MK_ERROR_OUT( "Failed to allocate _blocks[" , i , "]" ); } if( _size ) { Pointer( char ) buffer = NewPointer< char >( _size * serializedSize ); - if( !stream.read( buffer , serializedSize*_size ) ) ERROR_OUT( "Failed tor read in data" ); + if( !stream.read( buffer , serializedSize*_size ) ) MK_ERROR_OUT( "Failed tor read in data" ); for( unsigned int i=0 ; i<_size ; i++ ) serializer.deserialize( buffer+i*serializedSize , operator[]( i ) ); DeletePointer( buffer ); } diff --git a/Src/ChunkPLY.cpp b/Src/ChunkPLY.cpp index 0231e9fe..ff3da727 100644 --- a/Src/ChunkPLY.cpp +++ b/Src/ChunkPLY.cpp @@ -164,13 +164,13 @@ void WriteMesh( const char *fileName , int ft , VertexDataFactory vertexDataFact FullVertexFactory< Real , Dim , VertexDataFactory > vertexFactory( VertexFactory::PositionFactory< Real , Dim >() , vertexDataFactory ); char *ext = GetFileExtension( fileName ); - if( strcasecmp( ext , "ply" ) ) ERROR_OUT( "Can only output mesh to .ply file" ); + if( strcasecmp( ext , "ply" ) ) MK_ERROR_OUT( "Can only output mesh to .ply file" ); delete[] ext; if( vertices.size()>std::numeric_limits< int >::max() ) { - if( vertices.size()>std::numeric_limits< unsigned int >::max() ) ERROR_OUT( "more vertices than can be indexed by an unsigned int: %llu" , (unsigned long long)vertices.size() ); - WARN( "more vertices than can be indexed by an int, using unsigned int instead: %llu" , (unsigned long long)vertices.size() ); + if( vertices.size()>std::numeric_limits< unsigned int >::max() ) MK_ERROR_OUT( "more vertices than can be indexed by an unsigned int: %llu" , (unsigned long long)vertices.size() ); + MK_WARN( "more vertices than can be indexed by an int, using unsigned int instead: %llu" , (unsigned long long)vertices.size() ); std::vector< std::vector< unsigned int > > outPolygons; outPolygons.resize( polygons.size() ); for( size_t i=0 ; i0 ) @@ -545,11 +545,11 @@ void Execute( VertexDataFactory vertexDataFactory ) { if( polygons.size() ) { - if( pCount!=polygons.size() ) WARN( "polygon counts don't match: " , polygons.size() , " != " , pCount ); + if( pCount!=polygons.size() ) MK_WARN( "polygon counts don't match: " , polygons.size() , " != " , pCount ); } else { - if( vCount!=vertices.size() ) WARN( "vertex counts don't match:" , vertices.size() , " != " , vCount ); + if( vCount!=vertices.size() ) MK_WARN( "vertex counts don't match:" , vertices.size() , " != " , vCount ); } } } @@ -569,7 +569,7 @@ int main( int argc , char* argv[] ) CmdLineParse( argc-1 , &argv[1] , params ); #ifdef ARRAY_DEBUG - WARN( "Array debugging enabled" ); + MK_WARN( "Array debugging enabled" ); #endif // ARRAY_DEBUG if( !In.set ) @@ -585,7 +585,7 @@ int main( int argc , char* argv[] ) char *ext = GetFileExtension( In.values[i] ); bool _isPly = strcasecmp( ext , "ply" )==0; if( !i ) isPly = _isPly; - else if( isPly!=_isPly ) ERROR_OUT( "All files must be of the same type" ); + else if( isPly!=_isPly ) MK_ERROR_OUT( "All files must be of the same type" ); delete[] ext; } if( isPly ) @@ -597,10 +597,10 @@ int main( int argc , char* argv[] ) { std::vector< PlyProperty > unprocessedProperties; PLY::ReadVertexHeader( In.values[i] , factory , readFlags , unprocessedProperties ); - if( !factory.plyValidReadProperties( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); + if( !factory.plyValidReadProperties( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain positions" ); VertexFactory::DynamicFactory< Real > _remainingProperties( unprocessedProperties ); if( !i ) remainingProperties = new VertexFactory::DynamicFactory< Real >( _remainingProperties ); - else if( (*remainingProperties)!=(_remainingProperties) ) ERROR_OUT( "Remaining properties differ" ); + else if( (*remainingProperties)!=(_remainingProperties) ) MK_ERROR_OUT( "Remaining properties differ" ); } delete[] readFlags; if( !remainingProperties || !remainingProperties->size() ) Execute( VertexFactory::EmptyFactory< Real >() ); diff --git a/Src/CmdLineParser.inl b/Src/CmdLineParser.inl index b4ce704e..57a7a5f3 100644 --- a/Src/CmdLineParser.inl +++ b/Src/CmdLineParser.inl @@ -91,12 +91,12 @@ Point< Real , Dim > CmdLineType< Point< Real , Dim > >::StringToType( const char { if( d==0 ) { - if( temp[0]!='{' ) ERROR_OUT( "Expected opening brace: " , std::string( str ) ); + if( temp[0]!='{' ) MK_ERROR_OUT( "Expected opening brace: " , std::string( str ) ); t[d++] = CmdLineType< Real >::StringToType( temp+1 ); } else if( d==Dim-1 ) { - if( temp[ strlen(temp)-1 ]!='}' ) ERROR_OUT( "Expected closing brace: " , std::string( str ) ); + if( temp[ strlen(temp)-1 ]!='}' ) MK_ERROR_OUT( "Expected closing brace: " , std::string( str ) ); temp[ strlen(temp)-1 ] = 0; t[d++] = CmdLineType< Real >::StringToType( temp ); break; @@ -104,7 +104,7 @@ Point< Real , Dim > CmdLineType< Point< Real , Dim > >::StringToType( const char else t[d++] = CmdLineType< Real >::StringToType( temp ); temp = strtok( NULL ,"," ); } - if( dname ); } } - else WARN( "Parameter name should be of the form --: " , argv[0] ); + else MK_WARN( "Parameter name should be of the form --: " , argv[0] ); ++argv , --argc; } } diff --git a/Src/DataStream.imp.h b/Src/DataStream.imp.h index 4279758c..3f65eb97 100644 --- a/Src/DataStream.imp.h +++ b/Src/DataStream.imp.h @@ -145,7 +145,7 @@ namespace PoissonRecon { d.resize( pSize ); if( fread( &d[0] , sizeof(Data) , pSize , _fp )==pSize ) return true; - ERROR_OUT( "Failed to read polygon from file" ); + MK_ERROR_OUT( "Failed to read polygon from file" ); return true; } else return false; diff --git a/Src/DataStream.imp.inl b/Src/DataStream.imp.inl index 080affa0..4528fda8 100644 --- a/Src/DataStream.imp.inl +++ b/Src/DataStream.imp.inl @@ -33,7 +33,7 @@ template< typename Factory > ASCIIInputDataStream< Factory >::ASCIIInputDataStream( const char* fileName , const Factory &factory ) : _factory( factory ) { _fp = fopen( fileName , "r" ); - if( !_fp ) ERROR_OUT( "Failed to open file for reading: %s" , fileName ); + if( !_fp ) MK_ERROR_OUT( "Failed to open file for reading: %s" , fileName ); } template< typename Factory > @@ -56,7 +56,7 @@ template< typename Factory > ASCIIOutputDataStream< Factory >::ASCIIOutputDataStream( const char* fileName , const Factory &factory ) : _factory( factory ) { _fp = fopen( fileName , "w" ); - if( !_fp ) ERROR_OUT( "Failed to open file for writing: %s" , fileName ); + if( !_fp ) MK_ERROR_OUT( "Failed to open file for writing: %s" , fileName ); } template< typename Factory > @@ -76,7 +76,7 @@ template< typename Factory > BinaryInputDataStream< Factory >::BinaryInputDataStream( const char* fileName , const Factory &factory ) : _factory(factory) { _fp = fopen( fileName , "rb" ); - if( !_fp ) ERROR_OUT( "Failed to open file for reading: %s" , fileName ); + if( !_fp ) MK_ERROR_OUT( "Failed to open file for reading: %s" , fileName ); } template< typename Factory > @@ -92,7 +92,7 @@ template< typename Factory > BinaryOutputDataStream< Factory >::BinaryOutputDataStream( const char* fileName , const Factory &factory ) : _factory(factory) { _fp = fopen( fileName , "wb" ); - if( !_fp ) ERROR_OUT( "Failed to open file for writing: %s" , fileName ); + if( !_fp ) MK_ERROR_OUT( "Failed to open file for writing: %s" , fileName ); } template< typename Factory > @@ -131,7 +131,7 @@ void PLYInputDataStream< Factory >::reset( void ) float version; if( _ply ) _free(); _ply = PlyFile::Read( _fileName, _elist, fileType, version ); - if( !_ply ) ERROR_OUT( "Failed to open ply file for reading: " , _fileName ); + if( !_ply ) MK_ERROR_OUT( "Failed to open ply file for reading: " , _fileName ); bool foundData = false; for( int i=0 ; i<_elist.size() ; i++ ) @@ -142,7 +142,7 @@ void PLYInputDataStream< Factory >::reset( void ) { size_t num_elems; std::vector< PlyProperty > plist = _ply->get_element_description( elem_name , num_elems ); - if( !plist.size() ) ERROR_OUT( "Failed to get description for \"" , elem_name , "\"" ); + if( !plist.size() ) MK_ERROR_OUT( "Failed to get description for \"" , elem_name , "\"" ); foundData = true; _pCount = num_elems , _pIdx = 0; @@ -156,10 +156,10 @@ void PLYInputDataStream< Factory >::reset( void ) } bool valid = _factory.plyValidReadProperties( properties ); delete[] properties; - if( !valid ) ERROR_OUT( "Failed to validate properties in file" ); + if( !valid ) MK_ERROR_OUT( "Failed to validate properties in file" ); } } - if( !foundData ) ERROR_OUT( "Could not find data in ply file" ); + if( !foundData ) MK_ERROR_OUT( "Could not find data in ply file" ); } template< typename Factory > @@ -199,7 +199,7 @@ PLYOutputDataStream< Factory >::PLYOutputDataStream( const char* fileName , cons float version; std::vector< std::string > elem_names = { std::string( "vertex" ) }; _ply = PlyFile::Write( fileName , elem_names , fileType , version ); - if( !_ply ) ERROR_OUT( "Failed to open ply file for writing: " , fileName ); + if( !_ply ) MK_ERROR_OUT( "Failed to open ply file for writing: " , fileName ); _pIdx = 0; _pCount = count; @@ -218,7 +218,7 @@ PLYOutputDataStream< Factory >::PLYOutputDataStream( const char* fileName , cons template< typename Factory > PLYOutputDataStream< Factory >::~PLYOutputDataStream( void ) { - if( _pIdx!=_pCount ) ERROR_OUT( "Streamed points not equal to total count: " , _pIdx , " != " , _pCount ); + if( _pIdx!=_pCount ) MK_ERROR_OUT( "Streamed points not equal to total count: " , _pIdx , " != " , _pCount ); delete _ply; DeletePointer( _buffer ); } @@ -226,7 +226,7 @@ PLYOutputDataStream< Factory >::~PLYOutputDataStream( void ) template< typename Factory > size_t PLYOutputDataStream< Factory >::write( const Data &d ) { - if( _pIdx==_pCount ) ERROR_OUT( "Trying to add more points than total: " , _pIdx , " < " , _pCount ); + if( _pIdx==_pCount ) MK_ERROR_OUT( "Trying to add more points than total: " , _pIdx , " < " , _pCount ); if( _factory.isStaticallyAllocated() ) _ply->put_element( (void *)&d ); else { diff --git a/Src/DataStream.inl b/Src/DataStream.inl index 0587c2ac..43c6d41a 100644 --- a/Src/DataStream.inl +++ b/Src/DataStream.inl @@ -82,7 +82,7 @@ template< typename ... Data > bool InputDataStream< Data ... >::read( unsigned int thread , Data& ... d ) { #ifdef SHOW_WARNINGS - WARN_ONCE( "Serializing read: " , typeid(*this).name() ); + MK_WARN_ONCE( "Serializing read: " , typeid(*this).name() ); #endif // SHOW_WARNINGS std::lock_guard< std::mutex > lock( _insertionMutex ); return read(d...); @@ -142,7 +142,7 @@ template< typename ... Data > size_t OutputDataStream< Data ... >::write( unsigned int thread , const Data& ... d ) { #ifdef SHOW_WARNINGS - WARN_ONCE( "Serializing write: " , typeid(*this).name() ); + MK_WARN_ONCE( "Serializing write: " , typeid(*this).name() ); #endif // SHOW_WARNINGS std::lock_guard< std::mutex > lock( _insertionMutex ); return write(d...); diff --git a/Src/EDTInHeat.cpp b/Src/EDTInHeat.cpp index b7c5b3d7..46e78dc8 100644 --- a/Src/EDTInHeat.cpp +++ b/Src/EDTInHeat.cpp @@ -200,7 +200,7 @@ void _Execute( int argc , char* argv[] ) FILE* fp = fopen( InXForm.value , "r" ); if( !fp ) { - WARN( "Could not open file for reading x-form: " , InXForm.value ); + MK_WARN( "Could not open file for reading x-form: " , InXForm.value ); modelToUnitCube = XForm< Real , Dim+1 >::Identity(); } else @@ -208,7 +208,7 @@ void _Execute( int argc , char* argv[] ) for( int i=0 ; i<4 ; i++ ) for( int j=0 ; j<4 ; j++ ) { float f; - if( fscanf( fp , " %f " , &f )!=1 ) ERROR_OUT( "Failed to read xform" ); + if( fscanf( fp , " %f " , &f )!=1 ) MK_ERROR_OUT( "Failed to read xform" ); modelToUnitCube(i,j) = (Real)f; } fclose( fp ); @@ -265,7 +265,7 @@ void _Execute( int argc , char* argv[] ) if( OutXForm.set ) { FILE* fp = fopen( OutXForm.value , "w" ); - if( !fp ) WARN( "Could not open file for writing x-form: %s" ); + if( !fp ) MK_WARN( "Could not open file for writing x-form: %s" ); else { for( int i=0 ; iGradientCutOff ) g /= len; Point< Real , Dim+1 >* leafValue = leafValues(leaf); if( leafValue ) for( int d=0 ; d::WriteParameter( fs ); DenseNodeData< Real , IsotropicUIntPack< Dim , FEMSig > >::WriteSignatures( fs ); @@ -546,7 +546,7 @@ void Execute( int argc , char* argv[] ) case 2: return _Execute< Dim , Real , FEMDegreeAndBType< 2 , BOUNDARY_FREE >::Signature >( argc , argv ); case 3: return _Execute< Dim , Real , FEMDegreeAndBType< 3 , BOUNDARY_FREE >::Signature >( argc , argv ); case 4: return _Execute< Dim , Real , FEMDegreeAndBType< 4 , BOUNDARY_FREE >::Signature >( argc , argv ); - default: ERROR_OUT( "Only B-Splines of degree 1 - 4 are supported" ); + default: MK_ERROR_OUT( "Only B-Splines of degree 1 - 4 are supported" ); } } #endif // !FAST_COMPILE @@ -554,7 +554,7 @@ int main( int argc , char* argv[] ) { Timer timer; #ifdef ARRAY_DEBUG - WARN( "Array debugging enabled" ); + MK_WARN( "Array debugging enabled" ); #endif // ARRAY_DEBUG CmdLineParse( argc-1 , &argv[1] , params ); ThreadPool::ChunkSize = ThreadChunkSize.value; @@ -571,11 +571,11 @@ int main( int argc , char* argv[] ) static const int Degree = DEFAULT_FEM_DEGREE; static const BoundaryType BType = BOUNDARY_FREE; - WARN( "Compiled for degree-" , Degree , ", boundary-" , BoundaryNames[ BType ] , ", " , sizeof(Real)==4 ? "single" : "double" , "-precision _only_" ); + MK_WARN( "Compiled for degree-" , Degree , ", boundary-" , BoundaryNames[ BType ] , ", " , sizeof(Real)==4 ? "single" : "double" , "-precision _only_" ); if( !BaseDepth.set ) BaseDepth.value = FullDepth.value; if( BaseDepth.value>FullDepth.value ) { - if( BaseDepth.set ) WARN( "Base depth must be smaller than full depth: " , BaseDepth.value , " <= " , FullDepth.value ); + if( BaseDepth.set ) MK_WARN( "Base depth must be smaller than full depth: " , BaseDepth.value , " <= " , FullDepth.value ); BaseDepth.value = FullDepth.value; } _Execute< DEFAULT_DIMENSION , Real , FEMDegreeAndBType< Degree , BType >::Signature >( argc , argv ); diff --git a/Src/Extrapolator.h b/Src/Extrapolator.h index c053d14b..4448028c 100644 --- a/Src/Extrapolator.h +++ b/Src/Extrapolator.h @@ -184,12 +184,12 @@ namespace PoissonRecon if( params.fullDepth>params.depth ) { - if( params.fullDepth!=-1 ) WARN( "Full depth cannot exceed depth: " , params.fullDepth , " <= " , params.depth ); + if( params.fullDepth!=-1 ) MK_WARN( "Full depth cannot exceed depth: " , params.fullDepth , " <= " , params.depth ); params.fullDepth = params.depth; } if( params.baseDepth>params.fullDepth ) { - if( params.baseDepth!=-1 ) WARN( "Base depth must be smaller than full depth: " , params.baseDepth , " <= " , params.fullDepth ); + if( params.baseDepth!=-1 ) MK_WARN( "Base depth must be smaller than full depth: " , params.baseDepth , " <= " , params.fullDepth ); params.baseDepth = params.fullDepth; } diff --git a/Src/FEMTree.Evaluation.inl b/Src/FEMTree.Evaluation.inl index 69e47212..2c7b7a6e 100644 --- a/Src/FEMTree.Evaluation.inl +++ b/Src/FEMTree.Evaluation.inl @@ -152,7 +152,7 @@ CumulativeDerivativeValues< V , Dim , _PointD > FEMTree< Dim , Real >::_getValue { typedef UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... > SupportSizes; - if( IsActiveNode< Dim >( node->children ) && _localDepth( node->children )<=maxDepth ) WARN( "getValue assumes leaf node" ); + if( IsActiveNode< Dim >( node->children ) && _localDepth( node->children )<=maxDepth ) MK_WARN( "getValue assumes leaf node" ); CumulativeDerivativeValues< V , Dim , _PointD > values; PointEvaluatorState< UIntPack< FEMSigs ... > , IsotropicUIntPack< Dim , _PointD > > state; @@ -208,12 +208,12 @@ template< unsigned int Dim , class Real > template< class V , unsigned int _PointD , unsigned int ... FEMSigs , unsigned int PointD > CumulativeDerivativeValues< V , Dim , _PointD > FEMTree< Dim , Real >::_getCenterValues( const ConstPointSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& neighborKey , const FEMTreeNode* node , ConstPointer( V ) solution , ConstPointer( V ) coarseSolution , const _Evaluator< UIntPack< FEMSigs ... > , PointD >& evaluator , int maxDepth , bool isInterior ) const { - if( IsActiveNode< Dim >( node->children ) && _localDepth( node->children )<=maxDepth ) ERROR_OUT( "getCenterValues assumes leaf node" ); + if( IsActiveNode< Dim >( node->children ) && _localDepth( node->children )<=maxDepth ) MK_ERROR_OUT( "getCenterValues assumes leaf node" ); typedef _Evaluator< UIntPack< FEMSigs ... > , PointD > _Evaluator; typedef UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... > SupportSizes; static const unsigned int supportSizes[] = { BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... }; - if( IsActiveNode< Dim >( node->children ) && _localDepth( node->children )<=maxDepth ) ERROR_OUT( "getCenterValue assumes leaf node" ); + if( IsActiveNode< Dim >( node->children ) && _localDepth( node->children )<=maxDepth ) MK_ERROR_OUT( "getCenterValue assumes leaf node" ); CumulativeDerivativeValues< V , Dim , _PointD > values; LocalDepth d ; LocalOffset cIdx; @@ -320,7 +320,7 @@ template< unsigned int Dim , class Real > template< class V , unsigned int _PointD , unsigned int ... FEMSigs , unsigned int PointD > CumulativeDerivativeValues< V , Dim , _PointD > FEMTree< Dim , Real >::_getCornerValues( const ConstPointSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& neighborKey , const FEMTreeNode* node , int corner , ConstPointer( V ) solution , ConstPointer( V ) coarseSolution , const _Evaluator< UIntPack< FEMSigs ... > , PointD >& evaluator , int maxDepth , bool isInterior ) const { - if( IsActiveNode< Dim >( node->children ) && _localDepth( node->children )<=maxDepth ) WARN( "getValue assumes leaf node" ); + if( IsActiveNode< Dim >( node->children ) && _localDepth( node->children )<=maxDepth ) MK_WARN( "getValue assumes leaf node" ); typedef _Evaluator< UIntPack< FEMSigs ... > , PointD > _Evaluator; typedef UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... > SupportSizes; static const unsigned int supportSizes[] = { BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... }; @@ -494,7 +494,7 @@ template< unsigned int ... FEMSigs , unsigned int PointD , typename T > template< unsigned int _PointD > CumulativeDerivativeValues< T , Dim , _PointD > FEMTree< Dim , Real >::_MultiThreadedEvaluator< UIntPack< FEMSigs ... > , PointD , T >::values( Point< Real , Dim > p , int thread , const FEMTreeNode* node ) { - if( _PointD>PointD ) ERROR_OUT( "Evaluating more derivatives than available: " , _PointD , " <= " , PointD ); + if( _PointD>PointD ) MK_ERROR_OUT( "Evaluating more derivatives than available: " , _PointD , " <= " , PointD ); if( !node ) node = _tree->leaf( p ); ConstPointSupportKey< FEMDegrees >& nKey = _pointNeighborKeys[thread]; nKey.getNeighbors( node ); @@ -506,7 +506,7 @@ template< unsigned int ... FEMSigs , unsigned int PointD , typename T > template< unsigned int _PointD > CumulativeDerivativeValues< T , Dim , _PointD > FEMTree< Dim , Real >::_MultiThreadedEvaluator< UIntPack< FEMSigs ... > , PointD , T >::centerValues( const FEMTreeNode* node , int thread ) { - if( _PointD>PointD ) ERROR_OUT( "Evaluating more derivatives than available: " , _PointD, " <= " , PointD ); + if( _PointD>PointD ) MK_ERROR_OUT( "Evaluating more derivatives than available: " , _PointD, " <= " , PointD ); ConstPointSupportKey< FEMDegrees >& nKey = _pointNeighborKeys[thread]; nKey.getNeighbors( node ); LocalDepth d ; LocalOffset off; @@ -518,7 +518,7 @@ template< unsigned int ... FEMSigs , unsigned int PointD , typename T > template< unsigned int _PointD > CumulativeDerivativeValues< T , Dim , _PointD > FEMTree< Dim , Real >::_MultiThreadedEvaluator< UIntPack< FEMSigs ... > , PointD , T >::cornerValues( const FEMTreeNode* node , int corner , int thread ) { - if( _PointD>PointD ) ERROR_OUT( "Evaluating more derivatives than available: " , _PointD , " <= " , PointD ); + if( _PointD>PointD ) MK_ERROR_OUT( "Evaluating more derivatives than available: " , _PointD , " <= " , PointD ); ConstCornerSupportKey< FEMDegrees >& nKey = _cornerNeighborKeys[thread]; nKey.getNeighbors( node ); LocalDepth d ; LocalOffset off; @@ -598,7 +598,7 @@ void FEMTree< Dim , Real >::_accumulate( const Coefficients& coefficients , Poin { { const FEMTreeNode* node = dataKey.neighbors[d].neighbors.data[ WindowIndex< UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportSize ... > , UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportEnd ... > >::Index ]; - if( !node ) ERROR_OUT( "Point is not centered on a node: " , p , " " , WindowIndex< UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportSize ... > , UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportEnd ... > >::Index , " @ " , d ); + if( !node ) MK_ERROR_OUT( "Point is not centered on a node: " , p , " " , WindowIndex< UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportSize ... > , UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportEnd ... > >::Index , " @ " , d ); pointEvaluator.initEvaluationState( p , _localDepth( node ) , state ); } double scratch[Dim+1]; diff --git a/Src/FEMTree.Initialize.inl b/Src/FEMTree.Initialize.inl index 81f3904d..7d177a6e 100644 --- a/Src/FEMTree.Initialize.inl +++ b/Src/FEMTree.Initialize.inl @@ -453,7 +453,7 @@ size_t FEMTreeInitializer< Dim , Real >::_AddSimplex( FEMTreeNode* node , Simple template< unsigned int Dim , class Real > void FEMTreeInitializer< Dim , Real >::Initialize( FEMTreeNode& root , const std::vector< Point< Real , Dim > >& vertices , const std::vector< SimplexIndex< Dim-1 , node_index_type > >& simplices , unsigned int regularGridDepth , unsigned int maxDepth , std::vector< NodeSimplices< Dim , Real > >& nodeSimplices , std::vector< Allocator< FEMTreeNode > * > &nodeAllocators , std::function< void ( FEMTreeNode& ) > NodeInitializer ) { - if( regularGridDepth>maxDepth ) ERROR_OUT( "Regular grid depth cannot excceed maximum depth: " , regularGridDepth , " <= " , maxDepth ); + if( regularGridDepth>maxDepth ) MK_ERROR_OUT( "Regular grid depth cannot excceed maximum depth: " , regularGridDepth , " <= " , maxDepth ); // Allocate the tree up to the prescribed depth const Real RegularGridWidth = (Real)( 1./(1< typename std::enable_if< _Dim==1 , DenseNodeData< typename FEMTreeInitializer< Dim , Real >::GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > >::type FEMTreeInitializer< Dim , Real >::GetGeometryNodeDesignators( FEMTreeNode *root , const std::vector< Point< Real , Dim > >& vertices , const std::vector< SimplexIndex< Dim-1 , node_index_type > >& simplices , unsigned int regularGridDepth , unsigned int maxDepth , std::vector< Allocator< FEMTreeNode > * > &nodeAllocators , std::function< void ( FEMTreeNode& ) > NodeInitializer ) { static_assert( Dim==_Dim , "[ERROR] Dimensions don't match" ); - if( simplices.size()%2 ) ERROR_OUT( "Expected even number of hull points: " , simplices.size() ); + if( simplices.size()%2 ) MK_ERROR_OUT( "Expected even number of hull points: " , simplices.size() ); struct HullPoint { Real x; @@ -905,7 +905,7 @@ DenseNodeData< typename FEMTreeInitializer< Dim , Real >::GeometryNodeType , Iso interiorNodes.reserve( interiorCount ) , exteriorNodes.reserve( exteriorCount ); for( int i=0 ; i<_interiorNodes.size() ; i++ ) for( int j=0 ; j<_interiorNodes[i].size() ; j++ ) { - if( geometryNodeDesignators[ _interiorNodes[i][j] ]==GeometryNodeType::BOUNDARY ) ERROR_OUT( "Interior node has geometry" ); + if( geometryNodeDesignators[ _interiorNodes[i][j] ]==GeometryNodeType::BOUNDARY ) MK_ERROR_OUT( "Interior node has geometry" ); else if( geometryNodeDesignators[ _interiorNodes[i][j] ]==GeometryNodeType::UNKNOWN ) { geometryNodeDesignators[ _interiorNodes[i][j] ] = GeometryNodeType::INTERIOR; @@ -914,7 +914,7 @@ DenseNodeData< typename FEMTreeInitializer< Dim , Real >::GeometryNodeType , Iso } for( int i=0 ; i<_exteriorNodes.size() ; i++ ) for( int j=0 ; j<_exteriorNodes[i].size() ; j++ ) { - if( geometryNodeDesignators[ _exteriorNodes[i][j] ]==GeometryNodeType::BOUNDARY ) ERROR_OUT( "Exterior node has geometry" ); + if( geometryNodeDesignators[ _exteriorNodes[i][j] ]==GeometryNodeType::BOUNDARY ) MK_ERROR_OUT( "Exterior node has geometry" ); else if( geometryNodeDesignators[ _exteriorNodes[i][j] ]==GeometryNodeType::UNKNOWN ) { geometryNodeDesignators[ _exteriorNodes[i][j] ] = GeometryNodeType::EXTERIOR; @@ -990,7 +990,7 @@ DenseNodeData< typename FEMTreeInitializer< Dim , Real >::GeometryNodeType , Iso for( int i=0 ; i<_interiorNodes.size() ; i++ ) for( int j=0 ; j<_interiorNodes[i].size() ; j++ ) { - if( geometryNodeDesignators[ _interiorNodes[i][j] ]==GeometryNodeType::BOUNDARY ) ERROR_OUT( "Interior node has geometry" ); + if( geometryNodeDesignators[ _interiorNodes[i][j] ]==GeometryNodeType::BOUNDARY ) MK_ERROR_OUT( "Interior node has geometry" ); else if( geometryNodeDesignators[ _interiorNodes[i][j] ]==GeometryNodeType::UNKNOWN ) { geometryNodeDesignators[ _interiorNodes[i][j] ] = GeometryNodeType::INTERIOR; @@ -999,7 +999,7 @@ DenseNodeData< typename FEMTreeInitializer< Dim , Real >::GeometryNodeType , Iso } for( int i=0 ; i<_exteriorNodes.size() ; i++ ) for( int j=0 ; j<_exteriorNodes[i].size() ; j++ ) { - if( geometryNodeDesignators[ _exteriorNodes[i][j] ]==GeometryNodeType::BOUNDARY ) ERROR_OUT( "Exterior node has geometry" ); + if( geometryNodeDesignators[ _exteriorNodes[i][j] ]==GeometryNodeType::BOUNDARY ) MK_ERROR_OUT( "Exterior node has geometry" ); else if( geometryNodeDesignators[ _exteriorNodes[i][j] ]==GeometryNodeType::UNKNOWN ) { geometryNodeDesignators[ _exteriorNodes[i][j] ] = GeometryNodeType::EXTERIOR; @@ -1050,7 +1050,7 @@ DenseNodeData< typename FEMTreeInitializer< Dim , Real >::GeometryNodeType , Iso } }; CorrectDesignatorsFromChildren( root ); - if( correctionCount ) WARN( "Adjusted designator inconsistencies: " , correctionCount ); + if( correctionCount ) MK_WARN( "Adjusted designator inconsistencies: " , correctionCount ); std::function< void ( FEMTreeNode * ) > SetUnknownDesignatorsFromParents = [&]( FEMTreeNode *node ) { @@ -1070,13 +1070,13 @@ DenseNodeData< typename FEMTreeInitializer< Dim , Real >::GeometryNodeType , Iso else if( geometryNodeDesignators[node->children+c]==GeometryNodeType::EXTERIOR ) exteriorCount++; else if( geometryNodeDesignators[node->children+c]==GeometryNodeType::BOUNDARY ) boundaryCount++; } - if( interiorCount+exteriorCount+boundaryCount!=(1<::TestGeometryNodeDesignators( const FEMTre } if( boundaryCount || ( interiorCount && exteriorCount ) ) { - if( type!=GeometryNodeType::UNKNOWN && type!=GeometryNodeType::BOUNDARY ) ERROR_OUT( "Expected unknown or boundary, got: " , type , " | " , node->depthAndOffset() ); + if( type!=GeometryNodeType::UNKNOWN && type!=GeometryNodeType::BOUNDARY ) MK_ERROR_OUT( "Expected unknown or boundary, got: " , type , " | " , node->depthAndOffset() ); } else if( interiorCount==(1<depthAndOffset() ); + if( type!=GeometryNodeType::UNKNOWN && type!=GeometryNodeType::INTERIOR ) MK_ERROR_OUT( "Expected unknown or interior, got: " , type , " | " , node->depthAndOffset() ); } else if( exteriorCount==(1<depthAndOffset() ); + if( type!=GeometryNodeType::UNKNOWN && type!=GeometryNodeType::EXTERIOR ) MK_ERROR_OUT( "Expected unknown or exterior, got: " , type , " | " , node->depthAndOffset() ); } else if( interiorCount ) { - if( type!=GeometryNodeType::UNKNOWN && type!=GeometryNodeType::INTERIOR && type!=GeometryNodeType::BOUNDARY ) ERROR_OUT( "Expected unknown, interior , or boundary, got: " , type , " | " , node->depthAndOffset() ); + if( type!=GeometryNodeType::UNKNOWN && type!=GeometryNodeType::INTERIOR && type!=GeometryNodeType::BOUNDARY ) MK_ERROR_OUT( "Expected unknown, interior , or boundary, got: " , type , " | " , node->depthAndOffset() ); } else if( exteriorCount==(1<depthAndOffset() ); + if( type!=GeometryNodeType::UNKNOWN && type!=GeometryNodeType::EXTERIOR && type!=GeometryNodeType::BOUNDARY ) MK_ERROR_OUT( "Expected unknown, exterior, or boundary, got: " , type , " | " , node->depthAndOffset() ); } } @@ -1143,12 +1143,12 @@ void FEMTreeInitializer< Dim , Real >::PushGeometryNodeDesignatorsToFiner( const { if( geometryNodeDesignators[node]==GeometryNodeType::UNKNOWN ) if( node!=root ) geometryNodeDesignators[node] = geometryNodeDesignators[node->parent]; - else ERROR_OUT( "Root node should not be unknown" ); + else MK_ERROR_OUT( "Root node should not be unknown" ); else if( node!=root && geometryNodeDesignators[node]!=geometryNodeDesignators[node->parent] && geometryNodeDesignators[node->parent]!=GeometryNodeType::BOUNDARY ) { int d , off[Dim]; node->depthAndOffset( d , off ); - ERROR_OUT( "Child designator does not match parent: " , geometryNodeDesignators[node] , " != " , geometryNodeDesignators[node->parent] , " | " , d , " @ ( " , off[0] , " , " , off[1] , " , " , off[2] , " ) " ); + MK_ERROR_OUT( "Child designator does not match parent: " , geometryNodeDesignators[node] , " != " , geometryNodeDesignators[node->parent] , " | " , d , " @ ( " , off[0] , " , " , off[1] , " , " , off[2] , " ) " ); } if( node->depth()<(long long)maxDepth && node->children ) for( int c=0 ; c<(1<children+c ); } @@ -1177,7 +1177,7 @@ void FEMTreeInitializer< Dim , Real >::PullGeometryNodeDesignatorsFromFiner( con else if( exteriorCount==(1<( cellIndices.size() ); - if( !stream.read( mcIndices , cellIndices.size() ) ) ERROR_OUT( "Failed to read mc indices" ); + if( !stream.read( mcIndices , cellIndices.size() ) ) MK_ERROR_OUT( "Failed to read mc indices" ); } if( cellIndices.counts[0] ) { cornerValues = AllocPointer< Real >( cellIndices.counts[0] ); - if( !stream.read( cornerValues , cellIndices.counts[0] ) ) ERROR_OUT( "Failed to read corner values" ); + if( !stream.read( cornerValues , cellIndices.counts[0] ) ) MK_ERROR_OUT( "Failed to read corner values" ); char hasCornerGradients; - if( !stream.read( hasCornerGradients ) ) ERROR_OUT( "Could not read corner gradient state" ); + if( !stream.read( hasCornerGradients ) ) MK_ERROR_OUT( "Could not read corner gradient state" ); if( hasCornerGradients ) { cornerGradients = AllocPointer< Point< Real , Dim > >( cellIndices.counts[0] ); - if( !stream.read( cornerGradients , cellIndices.counts[0] ) ) ERROR_OUT( "Could not read corner gradients" ); + if( !stream.read( cornerGradients , cellIndices.counts[0] ) ) MK_ERROR_OUT( "Could not read corner gradients" ); } } if( cellIndices.counts[1] ) { edgeKeys = NewPointer< Key >( cellIndices.counts[1] ); - if( !stream.read( edgeKeys , cellIndices.counts[1]) ) ERROR_OUT( "Could not read edge keys" ); + if( !stream.read( edgeKeys , cellIndices.counts[1]) ) MK_ERROR_OUT( "Could not read edge keys" ); } if( cellIndices.counts[2] ) { faceEdges = NewPointer< FaceEdges >( cellIndices.counts[2] ); - if( !stream.read( faceEdges , cellIndices.counts[2] ) ) ERROR_OUT( "Could not read face edges" ); + if( !stream.read( faceEdges , cellIndices.counts[2] ) ) MK_ERROR_OUT( "Could not read face edges" ); } auto ReadIsoEdgeVector = [&]( BinaryStream &stream , std::vector< IsoEdge > &edges ) { size_t sz; - if( !stream.read( sz ) ) ERROR_OUT( "Could not read iso-edge vector size" ); + if( !stream.read( sz ) ) MK_ERROR_OUT( "Could not read iso-edge vector size" ); edges.resize( sz ); - if( sz && !stream.read( GetPointer( edges ) , sz ) ) ERROR_OUT( "Could not read iso-edges" ); + if( sz && !stream.read( GetPointer( edges ) , sz ) ) MK_ERROR_OUT( "Could not read iso-edges" ); }; { size_t sz; - if( !stream.read( sz ) ) ERROR_OUT( "Could not read face-edge-map size" ); + if( !stream.read( sz ) ) MK_ERROR_OUT( "Could not read face-edge-map size" ); for( unsigned int i=0 ; i::const_iterator iter=sliceValues[i].edgeVertexMap.cbegin() ; iter!=sliceValues[i].edgeVertexMap.cend() ; iter++ ) { - if( iter->second>=(node_index_type)vertexPositions.size() ) ERROR_OUT( "Unexpected vertex index: " , iter->second , " <= " , vertexPositions.size() ); + if( iter->second>=(node_index_type)vertexPositions.size() ) MK_ERROR_OUT( "Unexpected vertex index: " , iter->second , " <= " , vertexPositions.size() ); keys[iter->second] = iter->first; } return keys; @@ -750,7 +750,7 @@ public: // The corner indices incident on the edeg const typename HyperCube::Cube< Dim >::template Element< 0 > *c = HyperCubeTables< Dim , 1 , 0 >::OverlapElements[e.index]; // [SANITY CHECK] - // if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[0].index )!=tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[1].index ) ) ERROR_OUT( "Finer edges should both be valid or invalid" ); + // if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[0].index )!=tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[1].index ) ) MK_ERROR_OUT( "Finer edges should both be valid or invalid" ); // Can only copy edge information from the finer nodes incident on the edge if they are valid (note since we refine in broods, we can't have one child in and the other out) if( !tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[0].index ) || !tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[1].index ) ) continue; @@ -829,7 +829,7 @@ public: fe.count = HyperCube::MarchingSquares::AddEdgeIndices( mcIndex , isoEdges ); for( int j=0 ; j::const_iterator iter; node_index_type idx1 , idx2; if( ( iter=sValues.edgeVertexMap.find( e[0] ) )!=sValues.edgeVertexMap.end() ) idx1 = iter->second; - else ERROR_OUT( "Couldn't find vertex in edge map" ); + else MK_ERROR_OUT( "Couldn't find vertex in edge map" ); if( ( iter=sValues.edgeVertexMap.find( e[1] ) )!=sValues.edgeVertexMap.end() ) idx2 = iter->second; - else ERROR_OUT( "Couldn't find vertex in edge map" ); + else MK_ERROR_OUT( "Couldn't find vertex in edge map" ); if( flipOrientation ) edgeStream.write( thread , std::make_pair( idx2 , idx1 ) ); else edgeStream.write( thread , std::make_pair( idx1 , idx2 ) ); }; @@ -961,7 +961,7 @@ public: // 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 ) ERROR_OUT( "Not a zero-crossing root: " , x0 , " " , x1 ); + if( x0==x1 ) MK_ERROR_OUT( "Not a zero-crossing root: " , x0 , " " , x1 ); averageRoot = ( isoValue - x0 ) / ( x1 - x0 ); } if( averageRoot<=0 || averageRoot>=1 ) @@ -1033,7 +1033,7 @@ public: template< unsigned int WeightDegree , unsigned int DataSig , typename VertexStream , unsigned int ... FEMSigs > static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , VertexStream &vertexStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , std::vector< SliceValues > &sliceValues , int setFlag ) { - if( maxKeyDepth() ); static const int FEMDegrees[] = { FEMSignature< FEMSigs >::Degree ... }; - for( int d=0 ; d(); @@ -1116,7 +1116,7 @@ public: } size_t badRootCount = _BadRootCount; - if( badRootCount!=0 ) WARN( "bad average roots: " , badRootCount ); + if( badRootCount!=0 ) MK_WARN( "bad average roots: " , badRootCount ); return stats; } @@ -1163,7 +1163,6 @@ struct LevelSetExtractor< Real , 2 > template< unsigned int WeightDegree , unsigned int ... FEMSigs > static Stats Extract( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real >& tree , const DensityEstimator< WeightDegree >* densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , Real isoValue , OutputVertexStream &vertexStream , OutputDataStream< std::pair< node_index_type , node_index_type > > &edgeStream , bool nonLinearFit , bool outputGradients , bool flipOrientation ) { - typedef unsigned char Data; Data zeroData = 0; static const unsigned int DataSig = FEMDegreeAndBType< 0 , BOUNDARY_FREE >::Signature; const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data = NULL; @@ -1173,7 +1172,6 @@ struct LevelSetExtractor< Real , 2 > template< unsigned int WeightDegree , unsigned int ... FEMSigs > static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , OutputVertexStream &vertexStream , bool nonLinearFit , bool outputGradients , std::vector< SliceValues > &sliceValues , int setFlag ) { - typedef unsigned char Data; Data zeroData = 0; static const unsigned int DataSig = FEMDegreeAndBType< 0 , BOUNDARY_FREE >::Signature; const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data = NULL; diff --git a/Src/FEMTree.LevelSet.3D.inl b/Src/FEMTree.LevelSet.3D.inl index 35a130ce..22cd7d90 100644 --- a/Src/FEMTree.LevelSet.3D.inl +++ b/Src/FEMTree.LevelSet.3D.inl @@ -315,7 +315,7 @@ public: typename HyperCube::Cube< Dim >::template Element< 2 > f; if ( offset[Dim-1]+0==sliceIndex ) f = typename HyperCube::Cube< Dim >::template Element< 2 >( HyperCube::BACK , 0 ); else if( offset[Dim-1]+1==sliceIndex ) f = typename HyperCube::Cube< Dim >::template Element< 2 >( HyperCube::FRONT , 0 ); - else ERROR_OUT( "Node/slice-index mismatch: " , offset[Dim-1] , " <-> " , sliceIndex ); + else MK_ERROR_OUT( "Node/slice-index mismatch: " , offset[Dim-1] , " <-> " , sliceIndex ); return faceIndexFunctor( node , f ); }; @@ -341,7 +341,7 @@ public: LocalDepth d ; LocalOffset off; tree.depthAndOffset( leaf , d , off ); // [WARNING] Is this right? If the face isn't set, wouldn't it inherit? - WARN( "Invalid face: [" , off[0] , " " , off[1] , " " , off[2] , " @ " , d , " | " , sliceIndex , " : " , leaf->nodeData.nodeIndex , " ( " , keyGenerator.to_string(key) , " | " , key.to_string() , " )" ); + MK_WARN( "Invalid face: [" , off[0] , " " , off[1] , " " , off[2] , " @ " , d , " | " , sliceIndex , " : " , leaf->nodeData.nodeIndex , " ( " , keyGenerator.to_string(key) , " | " , key.to_string() , " )" ); } } } @@ -579,17 +579,17 @@ public: SliceLocalDepth sliceDepth ; SliceLocalOffset sliceOffset; tree.depthAndOffset( node , depth , offset ); sliceTree.depthAndOffset( sliceNode , sliceDepth , sliceOffset ); - if( depth!=sliceDepth ) ERROR_OUT( "Depths do not match: " , depth , " != " , sliceDepth ); - for( unsigned int i=0 ; inodeData.nodeIndex==-1 ) MK_ERROR_OUT( "Expected valid slice node" ); - if( sliceAtMaxDepthendAtMaxDepth ) ERROR_OUT( "Bad slice: " , sliceAtMaxDepth , " in [ " , beginAtMaxDepth , " , " , endAtMaxDepth , " ]" ); + if( sliceAtMaxDepthendAtMaxDepth ) MK_ERROR_OUT( "Bad slice: " , sliceAtMaxDepth , " in [ " , beginAtMaxDepth , " , " , endAtMaxDepth , " ]" ); if( depth>=fullDepth ) { // Set the incidence @@ -613,7 +613,7 @@ public: for( unsigned int d=0 ; d " , _p , " @ " , _d , " : ", node->nodeData.nodeIndex , " <-> " , sliceNode->nodeData.nodeIndex ); + MK_ERROR_OUT( "Expected slice children: " , p , " @ " , d , " <-> " , _p , " @ " , _d , " : ", node->nodeData.nodeIndex , " <-> " , sliceNode->nodeData.nodeIndex ); } if( sliceAtMaxDepth<=midAtMaxDepth ) for( int c=0 ; c<(1<<(Dim-1)) ; c++ ) SetIncidenceFunctor( node->children+(c ) , sliceNode->children + c ); if( sliceAtMaxDepth>=midAtMaxDepth ) for( int c=0 ; c<(1<<(Dim-1)) ; c++ ) SetIncidenceFunctor( node->children+(c|(1<<(Dim-1))) , sliceNode->children + c ); @@ -834,11 +834,11 @@ public: unsigned int slice = sliceAtMaxDepth>>( maxDepth - depth ); if( !isBack && sliceAtMaxDepth!=( slice<<(maxDepth-depth ) ) ) slice++; - if( !slabValues[depth].validSlice( slice ) ) ERROR_OUT( "Invalid slice: " , slice , " @ " , depth , " : " , slabValues[depth].sliceValues(slice).slice() ); + if( !slabValues[depth].validSlice( slice ) ) MK_ERROR_OUT( "Invalid slice: " , slice , " @ " , depth , " : " , slabValues[depth].sliceValues(slice).slice() ); SliceValues &sValues = slabValues[depth].sliceValues( slice ); const SliceSliceValues &ssValues = boundaryInfo.sliceValues[depth]; - if( sValues.cornerGradients && !ssValues.cornerGradients ) ERROR_OUT( "Epxected slice gradients" ); + if( sValues.cornerGradients && !ssValues.cornerGradients ) MK_ERROR_OUT( "Epxected slice gradients" ); auto CopyCornerInfo = [&]( node_index_type sliceIndex , node_index_type index ) { @@ -1293,7 +1293,7 @@ public: typename HyperCube::Cube< Dim >::template Element< 1 > e( zDir , _e.index ); const typename HyperCube::Cube< Dim >::template Element< 0 > *c = HyperCubeTables< Dim , 1 , 0 >::OverlapElements[e.index]; // [SANITY CHECK] - // if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[0].index )!=tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[1].index ) ) ERROR_OUT( "Finer edges should both be valid or invalid" ); + // if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[0].index )!=tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[1].index ) ) MK_ERROR_OUT( "Finer edges should both be valid or invalid" ); if( !tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[0].index ) || !tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[1].index ) ) continue; node_index_type cIndex1 = cCellIndices.template indices<1>( tree._sNodes.treeNodes[i]->children + c[0].index )[_e.index]; @@ -1365,7 +1365,7 @@ public: typename HyperCube::Cube< Dim >::template Element< 0 > c0( HyperCube::BACK , _c.index ) , c1( HyperCube::FRONT , _c.index ); // [SANITY CHECK] - // if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c0 )!=tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c1 ) ) ERROR_OUT( "Finer edges should both be valid or invalid" ); + // if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c0 )!=tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c1 ) ) MK_ERROR_OUT( "Finer edges should both be valid or invalid" ); if( !tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c0.index ) || !tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c1.index ) ) continue; node_index_type cIndex0 , cIndex1; @@ -1451,7 +1451,7 @@ public: fe.count = HyperCube::MarchingSquares::AddEdgeIndices( mcIndex , isoEdges ); for( int j=0 ; j((node_index_type)i)[ coIndex ]; - if( !sScratch.eSet[ idx ] ) ERROR_OUT( "Edge not set: " , slab , " / " , 1<& _edges = iter->second; for( size_t j=0 ; j<_edges.size() ; j++ ) edges.push_back( IsoEdge( _edges[j][flip] , _edges[j][1-flip] ) ); } - else ERROR_OUT( "Invalid faces: " , i , " " , fDir==HyperCube::BACK ? "back" : ( fDir==HyperCube::FRONT ? "front" : ( fDir==HyperCube::CROSS ? "cross" : "unknown" ) ) ); + else MK_ERROR_OUT( "Invalid faces: " , i , " " , fDir==HyperCube::BACK ? "back" : ( fDir==HyperCube::FRONT ? "front" : ( fDir==HyperCube::CROSS ? "cross" : "unknown" ) ) ); } } } @@ -1642,7 +1642,7 @@ public: if ( bValues.setVertexPair(current,pair) ) loops.back().push_back( current ) , current = pair; else if( fValues.setVertexPair(current,pair) ) loops.back().push_back( current ) , current = pair; else if( (iter=xValues.vertexPairMap.find(current))!=xValues.vertexPairMap.end() ) loops.back().push_back( current ) , current = iter->second; - else ERROR_OUT( "Failed to close loop for node[" , i , "]: [" , off[0] , " " , off[1] , " " , off[2] , " @ " , d , "] | " , keyGenerator.to_string( current ) , " -- " , keyGenerator.to_string( start ) , " | " , current.to_string() , " -- " , start.to_string() ); + else MK_ERROR_OUT( "Failed to close loop for node[" , i , "]: [" , off[0] , " " , off[1] , " " , off[2] , " @ " , d , "] | " , keyGenerator.to_string( current ) , " -- " , keyGenerator.to_string( start ) , " | " , current.to_string() , " -- " , start.to_string() ); } else { @@ -1665,7 +1665,7 @@ public: if ( bValues.setEdgeVertex( key , polygon[kk] ) ); else if( fValues.setEdgeVertex( key , polygon[kk] ) ); else if( ( iter=xValues.edgeVertexMap.find( key ) )!=xValues.edgeVertexMap.end() ) polygon[kk] = iter->second; - else ERROR_OUT( "Couldn't find vertex in edge map: " , off[0] , " , " , off[1] , " , " , off[2] , " @ " , depth , " : " , keyGenerator.to_string( key ) , " | " , key.to_string() ); + else MK_ERROR_OUT( "Couldn't find vertex in edge map: " , off[0] , " , " , off[1] , " , " , off[2] , " @ " , depth , " : " , keyGenerator.to_string( key ) , " | " , key.to_string() ); } AddIsoPolygons( thread , vertexStream , polygonStream , polygon , polygonMesh , addBarycenter ); } @@ -1748,7 +1748,7 @@ public: // 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 ) ERROR_OUT( "Not a zero-crossing root: " , x0 , " " , x1 ); + if( x0==x1 ) MK_ERROR_OUT( "Not a zero-crossing root: " , x0 , " " , x1 ); averageRoot = ( isoValue - x0 ) / ( x1 - x0 ); } if( averageRoot<=0 || averageRoot>=1 ) @@ -1859,7 +1859,7 @@ public: // 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 ) ERROR_OUT( "Not a zero-crossing root: " , x0 , " " , x1 ); + if( x0==x1 ) MK_ERROR_OUT( "Not a zero-crossing root: " , x0 , " " , x1 ); averageRoot = ( isoValue - x0 ) / ( x1 - x0 ); } if( averageRoot<=0 || averageRoot>=1 ) @@ -1945,7 +1945,7 @@ public: std::vector< Point< Real , Dim > > vertices( polygon.size() ); for( unsigned int i=0 ; i(); std::vector< TriangleIndex< node_index_type > > triangles = MinimalAreaTriangulation< node_index_type , Real , Dim >( ( ConstPointer( Point< Real , Dim > ) )GetPointer( vertices ) , (node_index_type)vertices.size() ); - if( triangles.size()!=polygon.size()-2 ) ERROR_OUT( "Minimal area triangulation failed:" , triangles.size() , " != " , polygon.size()-2 ); + if( triangles.size()!=polygon.size()-2 ) MK_ERROR_OUT( "Minimal area triangulation failed:" , triangles.size() , " != " , polygon.size()-2 ); for( unsigned int i=0 ; i(1u<(1u<(unsigned int)fullDepth && ( ( slabStart!=0 && !backBoundary ) || ( slabEnd+1!=1<<(slabDepth) && !frontBoundary ) ) ) MK_WARN( "Slab depth exceeds full depth, reconstruction may not be water-tight: " , slabDepth , " <= " , fullDepth , " [ " , slabStart , " , " , slabEnd , " )" ); #endif // SHOW_WARNINGS _BadRootCount = 0u; @@ -2030,7 +2030,7 @@ public: tree._setFEM1ValidityFlags( UIntPack< FEMSigs ... >() ); static const unsigned int DataDegree = FEMSignature< DataSig >::Degree; static const int FEMDegrees[] = { FEMSignature< FEMSigs >::Degree ... }; - for( int d=0 ; d(); LevelSetExtraction::SetHyperCubeTables< Dim-1 >(); @@ -2194,7 +2194,7 @@ public: for( LocalDepth d=maxDepth ; d>=fullDepth ; d-- ) if( d<=boundary->sliceTree.depth() && d<=tree._maxDepth ) { unsigned int slice; - if( !SetCoarseSlice( sliceAtMaxDepth , d , slice ) ) ERROR_OUT( "Could not set coarse slice" ); + if( !SetCoarseSlice( sliceAtMaxDepth , d , slice ) ) MK_ERROR_OUT( "Could not set coarse slice" ); OverwriteCornerValues( *boundary , (*dValues)[d] , tree , d , sliceAtMaxDepth , maxDepth , sliceAtMaxDepth==slabStartAtMaxDepth , slabValues , *incidence ); SetMCIndices( tree , isoValue , d , fullDepth , slice , slabValues ); } @@ -2240,13 +2240,13 @@ public: auto sliceFunctor = [&]( unsigned int depth ) -> SliceValues & { unsigned int slice; - if( !SetCoarseSlice( sliceAtMaxDepth , depth , slice ) ) ERROR_OUT( "Could not set coarse slice" ); + if( !SetCoarseSlice( sliceAtMaxDepth , depth , slice ) ) MK_ERROR_OUT( "Could not set coarse slice" ); return slabValues[depth].sliceValues( slice ); }; auto scratchFunctor = [&]( unsigned int depth ) -> typename SliceValues::Scratch & { unsigned int slice; - if( !SetCoarseSlice( sliceAtMaxDepth , depth , slice ) ) ERROR_OUT( "Could not set coarse slice" ); + if( !SetCoarseSlice( sliceAtMaxDepth , depth , slice ) ) MK_ERROR_OUT( "Could not set coarse slice" ); return slabValues[depth].sliceScratch( slice ); }; CopyIsoStructure< WeightDegree , DataSig >( keyGenerator , *boundary , tree , fullDepth , sliceAtMaxDepth , maxDepth , sliceFunctor , scratchFunctor , *incidence , vertexStream , gradientNormals , pointEvaluator , densityWeights , data , zeroData ); @@ -2395,7 +2395,7 @@ public: if( pointEvaluator ) delete pointEvaluator; size_t badRootCount = _BadRootCount; - if( badRootCount!=0 ) WARN( "bad average roots: " , badRootCount ); + if( badRootCount!=0 ) MK_WARN( "bad average roots: " , badRootCount ); return stats; } }; diff --git a/Src/FEMTree.LevelSet.inl b/Src/FEMTree.LevelSet.inl index e4b509ab..34c91f7e 100644 --- a/Src/FEMTree.LevelSet.inl +++ b/Src/FEMTree.LevelSet.inl @@ -249,7 +249,7 @@ namespace LevelSetExtraction void _zeroOut( size_t sz ) { if( sz && maps[CellDim] ) memset( maps[CellDim] , 0 , sizeof(node_index_type) * sz * HyperCube::Cube< Dim >::template ElementNum< CellDim >() ); - else if( sz ) ERROR_OUT( "Traying to zero out null pointer" ); + else if( sz ) MK_ERROR_OUT( "Traying to zero out null pointer" ); if constexpr( CellDim==MaxCellDim ) return; else _zeroOut< CellDim+1 >( sz ); @@ -298,7 +298,7 @@ namespace LevelSetExtraction void read( BinaryStream &stream ) { - if( !stream.read( _size ) ) ERROR_OUT( "Failed to read node count" ); + if( !stream.read( _size ) ) MK_ERROR_OUT( "Failed to read node count" ); resize( _size ); if( _size ) _read<0>( stream ); } @@ -344,8 +344,8 @@ namespace LevelSetExtraction template< unsigned int CellDim > void _read( BinaryStream &stream ) { - if( !stream.read( counts[CellDim] ) ) ERROR_OUT( "Failed to read count at dimension: " , CellDim ); - if( !stream.read( std::get< CellDim >( tables ) , _size ) ) ERROR_OUT( "Failed to read table at dimension: " , CellDim ); + if( !stream.read( counts[CellDim] ) ) MK_ERROR_OUT( "Failed to read count at dimension: " , CellDim ); + if( !stream.read( std::get< CellDim >( tables ) , _size ) ) MK_ERROR_OUT( "Failed to read table at dimension: " , CellDim ); if constexpr( CellDim==MaxCellDim ) return; else _read< CellDim+1 >( stream ); @@ -386,7 +386,7 @@ namespace LevelSetExtraction void read( BinaryStream &stream ) { - if( !stream.read( nodeOffset ) ) ERROR_OUT( "Failed to read node ofset" ); + if( !stream.read( nodeOffset ) ) MK_ERROR_OUT( "Failed to read node ofset" ); CellIndexData< Dim , MaxCellDim >::read( stream ); } @@ -516,7 +516,7 @@ namespace LevelSetExtraction void read( BinaryStream &stream ) { - if( !stream.read( nodeOffset ) ) ERROR_OUT( "Failed to read node ofset" ); + if( !stream.read( nodeOffset ) ) MK_ERROR_OUT( "Failed to read node ofset" ); CellIndexData< _Dim , _Dim >::read( stream ); } @@ -650,7 +650,7 @@ namespace LevelSetExtraction void read( BinaryStream &stream ) { - if( !stream.read( nodeOffset ) ) ERROR_OUT( "Failed to read node ofset" ); + if( !stream.read( nodeOffset ) ) MK_ERROR_OUT( "Failed to read node ofset" ); CellIndexData< _Dim , _Dim >::read( stream ); } @@ -782,7 +782,7 @@ namespace LevelSetExtraction Key< Dim > operator()( int depth , int offset , Key< Dim-1 > key ) const { Key< Dim > pKey; - if( depth>_maxDepth ) ERROR_OUT( "Depth cannot exceed max depth: " , depth , " <= " , _maxDepth ); + if( depth>_maxDepth ) MK_ERROR_OUT( "Depth cannot exceed max depth: " , depth , " <= " , _maxDepth ); for( unsigned int d=0 ; d::read( BinaryStream &stream , TreeNode &root ) _sliceStart = NullPointer( Pointer( node_index_type ) ); treeNodes = NullPointer( TreeNode* ); - if( !stream.read( _levels ) ) ERROR_OUT( "Failed to read levels" ); + if( !stream.read( _levels ) ) MK_ERROR_OUT( "Failed to read levels" ); if( _levels ) { _sliceStart = AllocPointer< Pointer( node_index_type ) >( _levels ); @@ -75,7 +75,7 @@ void SortedTreeNodes< Dim >::read( BinaryStream &stream , TreeNode &root ) { size_t sz = ((size_t)1<( sz ); - if( !stream.read( _sliceStart[l] , sz ) ) ERROR_OUT( "Failed to read slices at level: " , l ); + if( !stream.read( _sliceStart[l] , sz ) ) MK_ERROR_OUT( "Failed to read slices at level: " , l ); } size_t sz = _sliceStart[_levels-1][(size_t)1<<(_levels-1)]; diff --git a/Src/FEMTree.System.inl b/Src/FEMTree.System.inl index 99195974..4f4e4b08 100644 --- a/Src/FEMTree.System.inl +++ b/Src/FEMTree.System.inl @@ -443,7 +443,7 @@ int FEMTree< Dim , Real >::_solveSlicedSystemGS( UIntPack< FEMSigs ... > , const int b = _residualWindow.begin(!forward); if( FullWindow.inBlock( b ) ) maxBlockSize = std::max< size_t >( maxBlockSize , _sNodesEnd( depth , BlockLast( b ) ) - _sNodesBegin( depth , BlockFirst( b ) ) ); } - if( maxBlockSize>std::numeric_limits< matrix_index_type >::max() ) ERROR_OUT( "more entries in a block than can be indexed in " , sizeof(matrix_index_type) , " bytes" ); + if( maxBlockSize>std::numeric_limits< matrix_index_type >::max() ) MK_ERROR_OUT( "more entries in a block than can be indexed in " , sizeof(matrix_index_type) , " bytes" ); for( int i=0 ; i( maxBlockSize ) , _D[i] = AllocPointer< Real >( maxBlockSize ); for( ; residualWindow.end(!forward)*dir template< unsigned int ... FEMSigs , typename T , typename TDotT , typename ... InterpolationInfos > void FEMTree< Dim , Real >::_solveRegularMG( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , LocalDepth maxSolveDepth , Pointer( T ) solution , ConstPointer( T ) constraints , TDotT Dot , int vCycles , int iters , _SolverStats& stats , bool computeNorms , double cgAccuracy , std::tuple< InterpolationInfos *... > interpolationInfos ) const { - if( maxSolveDepth>_baseDepth ) ERROR_OUT( "Regular MG depth cannot exceed base depth: " , maxSolveDepth , " <= " , _baseDepth ); + if( maxSolveDepth>_baseDepth ) MK_ERROR_OUT( "Regular MG depth cannot exceed base depth: " , maxSolveDepth , " <= " , _baseDepth ); double& systemTime = stats.systemTime; double& solveTime = stats. solveTime; @@ -843,7 +843,7 @@ void FEMTree< Dim , Real >::_addPointValues( UIntPack< FEMSigs ... > , StaticWin typedef UIntPack< ( -BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportStart ) ... > RightPointSupportRadii; typedef UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... > SupportSizes; - if( !( FEMDegrees() >= IsotropicUIntPack< Dim , PointD >() ) ) ERROR_OUT( "Insufficient derivatives" ); + if( !( FEMDegrees() >= IsotropicUIntPack< Dim , PointD >() ) ) MK_ERROR_OUT( "Insufficient derivatives" ); if( !interpolationInfo ) return; const InterpolationInfo< T , PointD >& iInfo = *interpolationInfo; @@ -883,7 +883,7 @@ void FEMTree< Dim , Real >::_addPointValues( UIntPack< FEMSigs ... > , StaticWin if( Dim==1 ) { Point< double , PointD+1 > partialDot = peState.template partialDotDValues< Real , CumulativeDerivatives< Dim , PointD > >( dualValues , _idx ); - Pointer( Real ) _pointValues = GetPointer( pointValues.data + idx[Dim-1] + OverlapRadii::Values[Dim-1] , - idx[Dim-1] - (int)OverlapRadii::Values[Dim-1] , pointValues.Size - idx[Dim-1] - (int)OverlapRadii::Values[Dim-1] ); + Pointer( Real ) _pointValues = GetPointer( pointValues.data + idx[Dim-1] + OverlapRadii::Values[Dim-1] , - idx[Dim-1] - (int)OverlapRadii::Values[Dim-1] , pointValues.Size() - idx[Dim-1] - (int)OverlapRadii::Values[Dim-1] ); int _i = idx[Dim-1] + (int)OverlapRadii::Values[Dim-1] - (int)LeftPointSupportRadii::Values[Dim-1]; const double (*splineValues)[PointD+1] = peState.template values< Dim-1 >(); @@ -895,7 +895,7 @@ void FEMTree< Dim , Real >::_addPointValues( UIntPack< FEMSigs ... > , StaticWin int start[Dim==1 ? 1 : Dim-1] , end[Dim==1 ? 1 : Dim-1]; // Compute the bounds of nodes which can be supported on the point for( int d=0 ; d::Run + Window::Loop< Dim , Dim-1 >::Run ( start , end , [&]( int d , int i ){ _idx[d] = i - (int)OverlapRadii::Values[d] + off[d]; } , @@ -1003,7 +1003,7 @@ void FEMTree< Dim , Real >::_addProlongedPointValues( UIntPack< FEMSigs ... > , #pragma message( "[WARNING] This code is broken" ) #endif // SHOW_WARNINGS #if 1 - ERROR_OUT( "Broken code" ); + MK_ERROR_OUT( "Broken code" ); #else if( !interpolationInfo ) return; const InterpolationInfo< T , PointD >& iInfo = *interpolationInfo; @@ -1622,7 +1622,7 @@ SparseMatrix< Real , matrix_index_type > FEMTree< Dim , Real >::systemMatrix( UI { _setFEM1ValidityFlags( UIntPack< FEMSigs ... >() ); typedef typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > > BaseSystem; - if( depth<0 || depth>_maxDepth ) ERROR_OUT( "System depth out of bounds: 0 <= " , depth , " <= " , _maxDepth ); + if( depth<0 || depth>_maxDepth ) MK_ERROR_OUT( "System depth out of bounds: 0 <= " , depth , " <= " , _maxDepth ); SparseMatrix< Real , matrix_index_type > matrix; F.init( depth ); PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > > bsData( depth ); @@ -1658,7 +1658,7 @@ template< unsigned int ... FEMSigs , typename ... InterpolationInfos > SparseMatrix< Real , matrix_index_type > FEMTree< Dim , Real >::prolongedSystemMatrix( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack::Degree ... > >& F , LocalDepth highDepth , std::tuple< InterpolationInfos *... > interpolationInfos ) const { _setFEM1ValidityFlags( UIntPack< FEMSigs ... >() ); - if( highDepth<=0 || highDepth>_maxDepth ) ERROR_OUT( "System depth out of bounds: 0 < " , highDepth , " <= " , _maxDepth ); + if( highDepth<=0 || highDepth>_maxDepth ) MK_ERROR_OUT( "System depth out of bounds: 0 < " , highDepth , " <= " , _maxDepth ); LocalDepth lowDepth = highDepth-1; SparseMatrix< Real , matrix_index_type > matrix; @@ -1768,7 +1768,7 @@ SparseMatrix< Real , matrix_index_type > FEMTree< Dim , Real >::_downSampleMatri ); double values[Dim+1] ; values[0] = 1; - WindowLoop< Dim , Dim >::Run + WindowLoop< Dim >::Run ( ZeroUIntPack< Dim >() , UpSampleSizes() , [&]( int d , int i ){ values[d+1] = values[d] * upSampleValues[d][i]; } , @@ -2632,13 +2632,13 @@ void FEMTree< Dim , Real >::solveSystem( UIntPack< FEMSigs ... > , typename Base if( maxSolveDepth>_maxDepth ) { - WARN( "Solver depth should not exceed maximum depth: " , maxSolveDepth , " <= " , _maxDepth ); + MK_WARN( "Solver depth should not exceed maximum depth: " , maxSolveDepth , " <= " , _maxDepth ); maxSolveDepth = _maxDepth; } if( minSolveDepth>maxSolveDepth ) return; else if( minSolveDepth<_baseDepth ) { - WARN( "Minimum solver depth should not be smaller than base solver depth: " , minSolveDepth , " >= " , _baseDepth ); + MK_WARN( "Minimum solver depth should not be smaller than base solver depth: " , minSolveDepth , " >= " , _baseDepth ); minSolveDepth = _baseDepth; } @@ -2647,7 +2647,7 @@ void FEMTree< Dim , Real >::solveSystem( UIntPack< FEMSigs ... > , typename Base PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > > bsData( sizeof...(InterpolationInfos)==0 ? 0 : maxSolveDepth ); if( solverInfo.clearSolution ) solution = initDenseNodeData< T >( UIntPack< FEMSigs ... >() ); - else if( solution.size()!=_sNodesEnd( _maxDepth ) ) ERROR_OUT( "Solution is the wrong size: " , solution.size() , " != " , _sNodesEnd(_maxDepth) ); + else if( solution.size()!=_sNodesEnd( _maxDepth ) ) MK_ERROR_OUT( "Solution is the wrong size: " , solution.size() , " != " , _sNodesEnd(_maxDepth) ); // The initial estimate of the solution (may be empty or may come in with an initial guess) Pointer( T ) _solution = solution(); @@ -2976,7 +2976,7 @@ void FEMTree< Dim , Real >::_addFEMConstraints( UIntPack< FEMSigs ... > , UIntPa { if( isInterior ) { - unsigned int size = neighbors.neighbors.Size; + unsigned int size = neighbors.neighbors.Size(); Pointer( const FEMTreeNode* ) nodes = neighbors.neighbors().data; Pointer( Point< double , CDim > ) stencilValues = stencil.data; for( unsigned int j=0 ; j::_addFEMConstraints( UIntPack< FEMSigs ... > , UIntPa } else { - unsigned int size = neighbors.neighbors.Size; + unsigned int size = neighbors.neighbors.Size(); Pointer( const FEMTreeNode* ) nodes = neighbors.neighbors().data; for( unsigned int j=0 ; j::_getSamplesPerNode( const DensityEstimator< WeightDe ( IsotropicUIntPack< Dim , 0 >() , IsotropicUIntPack< Dim , BSplineSupportSizes< WeightDegree >::SupportSize >() , [&]( int d , int i ){ scratch[d+1] = scratch[d] * values[d][i]; } , - [&]( typename Neighbors::Window::data_type node ){ if( node ){ const Real* w = densityWeights( node ) ; if( w ) weight += (Real)( scratch[Dim] * (*w) ); } } , + [&]( typename Neighbors::StaticWindow::data_type node ){ if( node ){ const Real *w = densityWeights( node ) ; if( w ) weight += (Real)( scratch[Dim] * (*w) ); } } , neighbors.neighbors() ); return weight; @@ -267,7 +267,7 @@ void FEMTree< Dim , Real >::_getSampleDepthAndWeight( const DensityEstimator< We temp = _spaceRoot; while( _localDepth( temp )( temp->children ) ) break; // ERROR_OUT( "" ); + if( !IsActiveNode< Dim >( temp->children ) ) break; // MK_ERROR_OUT( "" ); int cIndex = FEMTreeNode::ChildIndex( myCenter , position ); temp = temp->children + cIndex; myWidth /= 2; diff --git a/Src/FEMTree.h b/Src/FEMTree.h index d4ad6ca6..15ffe1bd 100644 --- a/Src/FEMTree.h +++ b/Src/FEMTree.h @@ -154,7 +154,7 @@ namespace PoissonRecon size_t size( void ) const { return _levels ? _sliceStart[_levels-1][(size_t)1<<(_levels-1)] : 0; } size_t size( int depth ) const { - if( depth<0 || depth>=_levels ) ERROR_OUT( "bad depth: 0 <= " , depth , " < " , _levels ); + if( depth<0 || depth>=_levels ) MK_ERROR_OUT( "bad depth: 0 <= " , depth , " < " , _levels ); return _sliceStart[depth][(size_t)1<( _sz ); - if( !stream.read( _data , _sz ) ) ERROR_OUT( "failed to read data" ); + if( !stream.read( _data , _sz ) ) MK_ERROR_OUT( "failed to read data" ); } Data& operator[] ( size_t idx ) { return _data[idx]; } @@ -575,15 +575,15 @@ namespace PoissonRecon inline void ReadFEMTreeParameter( BinaryStream &stream , FEMTreeRealType& realType , unsigned int &dimension ) { - if( !stream.read( realType ) ) ERROR_OUT( "Failed to read real type" ); - if( !stream.read( dimension ) ) ERROR_OUT( "Failed to read dimension" ); + if( !stream.read( realType ) ) MK_ERROR_OUT( "Failed to read real type" ); + if( !stream.read( dimension ) ) MK_ERROR_OUT( "Failed to read dimension" ); } inline unsigned int* ReadDenseNodeDataSignatures( BinaryStream &stream , unsigned int &dim ) { - if( !stream.read( dim ) ) ERROR_OUT( "Failed to read dimension" ); + if( !stream.read( dim ) ) MK_ERROR_OUT( "Failed to read dimension" ); unsigned int* femSigs = new unsigned int[dim]; - if( !stream.read( GetPointer( femSigs , dim ) , dim ) ) ERROR_OUT( "Failed to read signatures" ); + if( !stream.read( GetPointer( femSigs , dim ) , dim ) ) MK_ERROR_OUT( "Failed to read signatures" ); return femSigs; } @@ -635,7 +635,7 @@ namespace PoissonRecon { unsigned int dCount = 0; for( unsigned int d=0 ; d=D ) ERROR_OUT( "More derivatives than allowed" ); + if( dCount>=D ) MK_ERROR_OUT( "More derivatives than allowed" ); else if( dCount; @@ -1114,7 +1114,7 @@ namespace PoissonRecon struct PointEvaluatorState< UIntPack< TSignatures ... > , UIntPack< TDs ... > > : public BaseFEMIntegrator::template PointEvaluatorState< sizeof ... ( TSignatures ) > { static_assert( sizeof...(TSignatures)==sizeof...(TDs) , "[ERROR] Degree and derivative dimensions don't match" ); - static_assert( UIntPack< FEMSignature< TSignatures >::Degree ... >::template Compare< UIntPack< TDs ... > >::GreaterThanOrEqual , "[ERROR] PointEvaluatorState: More derivatives than degrees" ); + static_assert( ParameterPack::Comparison< UIntPack< FEMSignature< TSignatures >::Degree ... > , UIntPack< TDs ... > >::GreaterThanOrEqual , "[ERROR] PointEvaluatorState: More derivatives than degrees" ); static const unsigned int Dim = sizeof...(TSignatures); @@ -1145,7 +1145,7 @@ namespace PoissonRecon struct PointEvaluator< UIntPack< TSignatures ... > , UIntPack< TDs ... > > : public BaseFEMIntegrator::template PointEvaluator< UIntPack< FEMSignature< TSignatures >::Degree ... > > { static_assert( sizeof...(TSignatures)==sizeof...(TDs) , "[ERROR] PointEvaluator: Degree and derivative dimensions don't match" ); - static_assert( UIntPack< FEMSignature< TSignatures >::Degree ... >::template Compare< UIntPack< TDs ... > >::GreaterThanOrEqual , "[ERROR] PointEvaluator: More derivatives than degrees" ); + static_assert( ParameterPack::Comparison< UIntPack< FEMSignature< TSignatures >::Degree ... > , UIntPack< TDs ... > >::GreaterThanOrEqual , "[ERROR] PointEvaluator: More derivatives than degrees" ); static const unsigned int Dim = sizeof ... ( TSignatures ); @@ -1162,7 +1162,7 @@ namespace PoissonRecon template< unsigned int ... EDs > void initEvaluationState( Point< double , Dim > p , unsigned int depth , const int* offset , PointEvaluatorState< UIntPack< TSignatures ... > , UIntPack< EDs ... > >& state ) const { - static_assert( UIntPack< TDs ... >::template Compare< UIntPack< EDs ... > >::GreaterThanOrEqual , "[ERROR] PointEvaluator::init: More evaluation derivatives than stored derivatives" ); + static_assert( ParameterPack::Comparison< UIntPack< TDs ... > , UIntPack< EDs ... > >::GreaterThanOrEqual , "[ERROR] PointEvaluator::init: More evaluation derivatives than stored derivatives" ); for( int d=0 ; d() , UIntPack< EDs ... >() , &p[0] , depth , state ); } @@ -1226,8 +1226,8 @@ namespace PoissonRecon static_assert( sizeof ... ( TSignatures ) == sizeof ... ( CSignatures ) , "[ERROR] Test signatures and contraint signatures must have the same dimension" ); static_assert( sizeof ... ( TSignatures ) == sizeof ... ( TDerivatives ) , "[ERROR] Test signatures and derivatives must have the same dimension" ); static_assert( sizeof ... ( CSignatures ) == sizeof ... ( CDerivatives ) , "[ERROR] Constraint signatures and derivatives must have the same dimension" ); - static_assert( UIntPack< FEMSignature< TSignatures >::Degree ... >::template Compare< UIntPack< TDerivatives ... > >::GreaterThanOrEqual , "[ERROR] Test functions cannot have more derivatives than the degree" ); - static_assert( UIntPack< FEMSignature< CSignatures >::Degree ... >::template Compare< UIntPack< CDerivatives ... > >::GreaterThanOrEqual , "[ERROR] Test functions cannot have more derivatives than the degree" ); + static_assert( ParameterPack::Comparison< UIntPack< FEMSignature< TSignatures >::Degree ... > , UIntPack< TDerivatives ... > >::GreaterThanOrEqual , "[ERROR] Test functions cannot have more derivatives than the degree" ); + static_assert( ParameterPack::Comparison< UIntPack< FEMSignature< CSignatures >::Degree ... > , UIntPack< CDerivatives ... > >::GreaterThanOrEqual , "[ERROR] Test functions cannot have more derivatives than the degree" ); static const unsigned int Dim = sizeof ... ( TSignatures ); typedef typename BaseFEMIntegrator::template Constraint< UIntPack< FEMSignature< TSignatures >::Degree ... > , UIntPack< FEMSignature< CSignatures >::Degree ... > , CDim > Base; @@ -1305,7 +1305,7 @@ namespace PoissonRecon case INTEGRATE_CHILD_CHILD: return std::get< D >( _integrators ).ccIntegrator.dot( off1[D] , off2[D] , d1[D] , d2[D] ) * remainingIntegral; case INTEGRATE_PARENT_CHILD: return std::get< D >( _integrators ).pcIntegrator.dot( off1[D] , off2[D] , d1[D] , d2[D] ) * remainingIntegral; case INTEGRATE_CHILD_PARENT: return std::get< D >( _integrators ).cpIntegrator.dot( off2[D] , off1[D] , d2[D] , d1[D] ) * remainingIntegral; - default: ERROR_OUT( "Undefined integration type" ); + default: MK_ERROR_OUT( "Undefined integration type" ); } return 0; } @@ -1413,7 +1413,7 @@ namespace PoissonRecon ( start , end , [&]( int d , int i ){ idx[d] = i; } , - [&]( void ){ indices[c][ size[c]++ ] = GetWindowIndex( UIntPack< Sizes ... >() , idx ); } + [&]( void ){ indices[c][ size[c]++ ] = Window::GetIndex< Sizes ... >( idx ); } ); } } @@ -1432,7 +1432,7 @@ namespace PoissonRecon using Value = Point< Real >; static void Add( volatile Value &a , const Value &b ) { - if( a._dim !=b._dim ) ERROR_OUT( "Sizes don't match: " , a._dim , " != " , b._dim ); + if( a._dim !=b._dim ) MK_ERROR_OUT( "Sizes don't match: " , a._dim , " != " , b._dim ); for( unsigned int d=0 ; d::Signature > >::read( stream ); } DensityEstimator( BinaryStream &stream ){ read(stream); } @@ -2601,7 +2601,7 @@ namespace PoissonRecon FEMTreeRealType realType; if ( typeid( Real )==typeid( float ) ) realType=FEM_TREE_REAL_FLOAT; else if( typeid( Real )==typeid( double ) ) realType=FEM_TREE_REAL_DOUBLE; - else ERROR_OUT( "Unrecognized real type" ); + else MK_ERROR_OUT( "Unrecognized real type" ); stream.write( realType ); int dim = Dim; stream.write( dim ); @@ -2693,8 +2693,8 @@ namespace PoissonRecon typedef SparseNodeData< Point< T , CDim > , UIntPack< CSigs ... > > SparseType; typedef DenseNodeData< Point< T , CDim > , UIntPack< CSigs ... > > DenseType; static_assert( sizeof...( FEMDegrees )==Dim && sizeof...( FEMSigs )==Dim && sizeof...( CDegrees )==Dim && sizeof...( CSigs )==Dim , "[ERROR] Dimensions don't match" ); - static_assert( UIntPack< FEMDegrees ... >::template Compare< UIntPack< FEMSignature< FEMSigs >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); - static_assert( UIntPack< CDegrees ... >::template Compare< UIntPack< FEMSignature< CSigs >::Degree ... > >::Equal , "[ERROR] Constraint signature and degrees don't match" ); + static_assert( ParameterPack::Comparison< UIntPack< FEMDegrees ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); + static_assert( ParameterPack::Comparison< UIntPack< CDegrees ... > , UIntPack< FEMSignature< CSigs >::Degree ... > >::Equal , "[ERROR] Constraint signature and degrees don't match" ); if ( typeid(coefficients)==typeid(SparseType) ) return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< CSigs ... >() , F , static_cast< const SparseType& >( coefficients ) , constraints() , maxDepth ); else if( typeid(coefficients)==typeid( DenseType) ) return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< CSigs ... >() , F , static_cast< const DenseType& >( coefficients ) , constraints() , maxDepth ); else return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< CSigs ... >() , F , coefficients , constraints() , maxDepth ); @@ -2706,8 +2706,8 @@ namespace PoissonRecon typedef SparseNodeData< T , UIntPack< CSigs ... > > SparseType; typedef DenseNodeData< T , UIntPack< CSigs ... > > DenseType; static_assert( sizeof...( FEMDegrees )==Dim && sizeof...( FEMSigs )==Dim && sizeof...( CDegrees )==Dim && sizeof...( CSigs )==Dim , "[ERROR] Dimensions don't match" ); - static_assert( UIntPack< FEMDegrees ... >::template Compare< UIntPack< FEMSignature< FEMSigs >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); - static_assert( UIntPack< CDegrees ... >::template Compare< UIntPack< FEMSignature< CSigs >::Degree ... > >::Equal , "[ERROR] Constaint signature and degrees don't match" ); + static_assert( ParameterPack::Comparison< UIntPack< FEMDegrees ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); + static_assert( ParameterPack::Comparison< UIntPack< CDegrees ... > , UIntPack< FEMSignature< CSigs >::Degree ... > >::Equal , "[ERROR] Constaint signature and degrees don't match" ); if ( typeid(coefficients)==typeid(SparseType) ) return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< CSigs ... >() , F , static_cast< const SparseType& >( coefficients ) , constraints() , maxDepth ); else if( typeid(coefficients)==typeid( DenseType) ) return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< CSigs ... >() , F , static_cast< const DenseType& >( coefficients ) , constraints() , maxDepth ); else return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< CSigs ... >() , F , coefficients , constraints() , maxDepth ); @@ -2719,7 +2719,7 @@ namespace PoissonRecon typedef SparseNodeData< T , UIntPack< FEMSigs ... > > SparseType; typedef DenseNodeData< T , UIntPack< FEMSigs ... > > DenseType; static_assert( sizeof...( FEMDegrees )==Dim && sizeof...( FEMSigs )==Dim , "[ERROR] Dimensions don't match" ); - static_assert( UIntPack< FEMDegrees ... >::template Compare< UIntPack< FEMSignature< FEMSigs >::Degree ... > >::Equal , "[ERROR] FEM signatures and degrees don't match" ); + static_assert( ParameterPack::Comparison< UIntPack< FEMDegrees ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >::Equal , "[ERROR] FEM signatures and degrees don't match" ); typename BaseFEMIntegrator::template SystemConstraint< UIntPack< FEMDegrees ... > > _F( F ); if ( typeid(coefficients)==typeid(SparseType) ) return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const SparseType& >( coefficients ) , constraints() , maxDepth ); else if( typeid(coefficients)==typeid( DenseType) ) return _addFEMConstraints< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const DenseType& >( coefficients ) , constraints() , maxDepth ); @@ -2756,8 +2756,8 @@ namespace PoissonRecon typedef SparseNodeData< Real , UIntPack< FEMSigs2 ... > > SparseType2; typedef DenseNodeData< Real , UIntPack< FEMSigs2 ... > > DenseType2; static_assert( sizeof...( FEMDegrees1 )==Dim && sizeof...( FEMSigs1 )==Dim && sizeof...( FEMDegrees2 )==Dim && sizeof...( FEMSigs2 )==Dim , "[ERROR] Dimensions don't match" ); - static_assert( UIntPack< FEMDegrees1 ... >::template Compare< UIntPack< FEMSignature< FEMSigs1 >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); - static_assert( UIntPack< FEMDegrees2 ... >::template Compare< UIntPack< FEMSignature< FEMSigs2 >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); + static_assert( ParameterPack::Comparison< UIntPack< FEMDegrees1 ... > , UIntPack< FEMSignature< FEMSigs1 >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); + static_assert( ParameterPack::Comparison< UIntPack< FEMDegrees2 ... > , UIntPack< FEMSignature< FEMSigs2 >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); if ( typeid(coefficients1)==typeid(SparseType1) && typeid(coefficients2)==typeid(SparseType2) ) return _dot< Real >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , static_cast< const SparseType1& >( coefficients1 ) , static_cast< const SparseType2& >( coefficients2 ) , []( Real v , Real w ){ return v*w; } ); else if( typeid(coefficients1)==typeid(SparseType1) && typeid(coefficients2)==typeid( DenseType2) ) return _dot< Real >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , static_cast< const SparseType1& >( coefficients1 ) , static_cast< const DenseType2& >( coefficients2 ) , []( Real v , Real w ){ return v*w; } ); else if( typeid(coefficients1)==typeid( DenseType1) && typeid(coefficients2)==typeid( DenseType2) ) return _dot< Real >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , static_cast< const DenseType1& >( coefficients1 ) , static_cast< const DenseType2& >( coefficients2 ) , []( Real v , Real w ){ return v*w; } ); @@ -2770,7 +2770,7 @@ namespace PoissonRecon typedef SparseNodeData< Real , UIntPack< FEMSigs ... > > SparseType; typedef DenseNodeData< Real , UIntPack< FEMSigs ... > > DenseType; static_assert( sizeof...( FEMDegrees )==Dim && sizeof...( FEMSigs )==Dim , "[ERROR] Dimensions don't match" ); - static_assert( UIntPack< FEMDegrees ... >::template Compare< UIntPack< FEMSignature< FEMSigs >::Degree ... > >::Equal , "[ERROR] FEM signatures and degrees don't match" ); + static_assert( ParameterPack::Comparison< UIntPack< FEMDegrees ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >::Equal , "[ERROR] FEM signatures and degrees don't match" ); typename BaseFEMIntegrator::template SystemConstraint< UIntPack< FEMDegrees ... > > _F( F ); if ( typeid(coefficients1)==typeid(SparseType) && typeid(coefficients2)==typeid(SparseType) ) return _dot< Real >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const SparseType& >( coefficients1 ) , static_cast< const SparseType& >( coefficients2 ) , []( Real v , Real w ){ return v*w; } ); else if( typeid(coefficients1)==typeid(SparseType) && typeid(coefficients2)==typeid( DenseType) ) return _dot< Real >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const SparseType& >( coefficients1 ) , static_cast< const DenseType& >( coefficients2 ) , []( Real v , Real w ){ return v*w; } ); @@ -2811,8 +2811,8 @@ namespace PoissonRecon typedef SparseNodeData< T , UIntPack< FEMSigs2 ... > > SparseType2; typedef DenseNodeData< T , UIntPack< FEMSigs2 ... > > DenseType2; static_assert( sizeof...( FEMDegrees1 )==Dim && sizeof...( FEMSigs1 )==Dim && sizeof...( FEMDegrees2 )==Dim && sizeof...( FEMSigs2 )==Dim , "[ERROR] Dimensions don't match" ); - static_assert( UIntPack< FEMDegrees1 ... >::template Compare< UIntPack< FEMSignature< FEMSigs1 >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); - static_assert( UIntPack< FEMDegrees2 ... >::template Compare< UIntPack< FEMSignature< FEMSigs2 >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); + static_assert( ParameterPack::Comparison< UIntPack< FEMDegrees1 ... > , UIntPack< FEMSignature< FEMSigs1 >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); + static_assert( ParameterPack::Comparison< UIntPack< FEMDegrees2 ... > , UIntPack< FEMSignature< FEMSigs2 >::Degree ... > >::Equal , "[ERROR] FEM signature and degrees don't match" ); if ( typeid(coefficients1)==typeid(SparseType1) && typeid(coefficients2)==typeid(SparseType2) ) return _dot< T >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , static_cast< const SparseType1& >( coefficients1 ) , static_cast< const SparseType2& >( coefficients2 ) , Dot ); else if( typeid(coefficients1)==typeid(SparseType1) && typeid(coefficients2)==typeid( DenseType2) ) return _dot< T >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , static_cast< const SparseType1& >( coefficients1 ) , static_cast< const DenseType2& >( coefficients2 ) , Dot ); else if( typeid(coefficients1)==typeid( DenseType1) && typeid(coefficients2)==typeid( DenseType2) ) return _dot< T >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , F , static_cast< const DenseType1& >( coefficients1 ) , static_cast< const DenseType2& >( coefficients2 ) , Dot ); @@ -2825,7 +2825,7 @@ namespace PoissonRecon typedef SparseNodeData< T , UIntPack< FEMSigs ... > > SparseType; typedef DenseNodeData< T , UIntPack< FEMSigs ... > > DenseType; static_assert( sizeof...( FEMDegrees )==Dim && sizeof...( FEMSigs )==Dim , "[ERROR] Dimensions don't match" ); - static_assert( UIntPack< FEMDegrees ... >::template Compare< UIntPack< FEMSignature< FEMSigs >::Degree ... > >::Equal , "[ERROR] FEM signatures and degrees don't match" ); + static_assert( ParameterPack::Comparison< UIntPack< FEMDegrees ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >::Equal , "[ERROR] FEM signatures and degrees don't match" ); typename BaseFEMIntegrator::template SystemConstraint< UIntPack< FEMDegrees ... > > _F( F ); if ( typeid(coefficients1)==typeid(SparseType) && typeid(coefficients2)==typeid(SparseType) ) return _dot< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const SparseType& >( coefficients1 ) , static_cast< const SparseType& >( coefficients2 ) , Dot ); else if( typeid(coefficients1)==typeid(SparseType) && typeid(coefficients2)==typeid( DenseType) ) return _dot< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , _F , static_cast< const SparseType& >( coefficients1 ) , static_cast< const DenseType& >( coefficients2 ) , Dot ); diff --git a/Src/FEMTree.inl b/Src/FEMTree.inl index c7fc1be3..cbe4c093 100644 --- a/Src/FEMTree.inl +++ b/Src/FEMTree.inl @@ -59,7 +59,7 @@ void FEMTree< Dim , Real >::_init( void ) _spaceRoot = &_tree; for( int d=0 ; d<_depthOffset ; d++ ) { - if( !_spaceRoot->children ) ERROR_OUT( "Expected child node: " , d , " / " , _depthOffset ); + if( !_spaceRoot->children ) MK_ERROR_OUT( "Expected child node: " , d , " / " , _depthOffset ); else if( d==0 ) _spaceRoot = _spaceRoot->children + (1<children; } @@ -68,8 +68,8 @@ void FEMTree< Dim , Real >::_init( void ) template< unsigned int Dim , class Real > FEMTree< Dim , Real > *FEMTree< Dim , Real >::Merge( const FEMTree< Dim , Real > &tree1 , const FEMTree< Dim , Real > &tree2 , size_t blockSize ) { - if( tree1._baseDepth != tree2._baseDepth ) ERROR_OUT( "Base depths differ: " , tree1._baseDepth , " != " , tree2._baseDepth ); - if( tree1._depthOffset != tree2._depthOffset ) ERROR_OUT( "Depth offsets differ: " , tree1._depthOffset , " != " , tree2._depthOffset ); + if( tree1._baseDepth != tree2._baseDepth ) MK_ERROR_OUT( "Base depths differ: " , tree1._baseDepth , " != " , tree2._baseDepth ); + if( tree1._depthOffset != tree2._depthOffset ) MK_ERROR_OUT( "Depth offsets differ: " , tree1._depthOffset , " != " , tree2._depthOffset ); FEMTree< Dim , Real > *mergeTree = new FEMTree( blockSize ); // have support overlapping the slice. @@ -108,7 +108,7 @@ template< unsigned int Dim , class Real > template< unsigned int CrossDegree , unsigned int Pad > FEMTree< Dim , Real > *FEMTree< Dim , Real >::Slice( const FEMTree< Dim+1 , Real > &tree , unsigned int sliceDepth , unsigned int sliceIndex , bool includeBounds , size_t blockSize ) { - if( sliceIndex>(unsigned int)(1<nodeData.nodeIndex==-1 ) MK_ERROR_OUT( "Merge node not set" ); LocalDepth d ; LocalOffset off; tree.depthAndOffset( node , d , off ); mergeCoefficients[ mergeNode->nodeData.nodeIndex ] += coefficients[ node->nodeData.nodeIndex ]; @@ -218,7 +218,7 @@ struct SliceEvaluator { double eps = 1e-4/(1< " , FEMSignature< FEMSig >::Degree ); + else MK_ERROR_OUT( "Derivative exceeds degree: " , d , " > " , FEMSignature< FEMSig >::Degree ); } Real operator()( int off ) const { @@ -318,7 +318,7 @@ void FEMTree< Dim , Real >::slice( const FEMTree< Dim+1 , Real > &tree , unsigne { if( node->nodeData.nodeIndex!=-1 ) { - if( sliceNode->nodeData.nodeIndex==-1 ) ERROR_OUT( "Slice node not set" ); + if( sliceNode->nodeData.nodeIndex==-1 ) MK_ERROR_OUT( "Slice node not set" ); typename FEMTree< Dim+1 , Real >::LocalDepth d ; typename FEMTree< Dim+1 , Real >::LocalOffset off; tree.depthAndOffset( node , d , off ); sliceCoefficients[ sliceNode->nodeData.nodeIndex ] += coefficients[ node->nodeData.nodeIndex ] * sliceEvaluator( d , off[Dim] ); @@ -358,11 +358,11 @@ FEMTree< Dim , Real >::FEMTree( BinaryStream &stream , size_t blockSize ) : FEMT { Allocator< FEMTreeNode > *nodeAllocator = nodeAllocators.size() ? nodeAllocators[0] : NULL; node_index_type nodeCount; - if( !stream.read( nodeCount ) ) ERROR_OUT( "Failed to read nodeCount" ); + if( !stream.read( nodeCount ) ) MK_ERROR_OUT( "Failed to read nodeCount" ); _nodeCount = nodeCount; - if( !stream.read( _maxDepth ) ) ERROR_OUT( "Failed to read _maxDepth" ); - if( !stream.read( _depthOffset ) ) ERROR_OUT( "Failed to read _depthOffset" ); - if( !stream.read( _baseDepth ) ) ERROR_OUT( "Failed to read _baseDepth" ); + if( !stream.read( _maxDepth ) ) MK_ERROR_OUT( "Failed to read _maxDepth" ); + if( !stream.read( _depthOffset ) ) MK_ERROR_OUT( "Failed to read _depthOffset" ); + if( !stream.read( _baseDepth ) ) MK_ERROR_OUT( "Failed to read _baseDepth" ); _tree.read( stream , nodeAllocator ); _init(); _sNodes.read( stream , _tree ); @@ -630,9 +630,9 @@ typename FEMTree< Dim , Real >::LocalDepth FEMTree< Dim , Real >::getFullDepth( LocalDepth _depth ; LocalOffset _begin , _end; for( unsigned int d=0 ; dend[d] ) ERROR_OUT( "Bad bounds [" , d , "]: " , begin[d] , " <= " , end[d] ); - if( begin[d]<0 ) ERROR_OUT( "Start bound cannot be negative [" , d , "]: 0 <= " , begin[d] ); - if( end[d]>(1<maxSplatDepth ) MK_ERROR_OUT( "Minimum splat depth exceeds maximum splat depth" ); PointSupportKey< IsotropicUIntPack< Dim , DensityDegree > > densityKey; densityKey.set( maxSplatDepth ); @@ -828,7 +828,7 @@ void FEMTree< Dim , Real >::updateDensityEstimator( typename FEMTree< Dim , Real LocalDepth maxDepth = _spaceRoot->maxDepth(); maxSplatDepth = std::max< LocalDepth >( 0 , std::min< LocalDepth >( maxSplatDepth , maxDepth ) ); minSplatDepth = std::max< LocalDepth >( 0 , std::min< LocalDepth >( minSplatDepth , maxDepth ) ); - if( minSplatDepth>maxSplatDepth ) ERROR_OUT( "Minimum splat depth exceeds maximum splat depth" ); + if( minSplatDepth>maxSplatDepth ) MK_ERROR_OUT( "Minimum splat depth exceeds maximum splat depth" ); PointSupportKey< IsotropicUIntPack< Dim , DensityDegree > > densityKey; densityKey.set( maxSplatDepth ); @@ -928,7 +928,7 @@ SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setI OutData out; Real depthBias; - if( !_InBounds(p) ) WARN( "Point sample is out of bounds" ); + if( !_InBounds(p) ) MK_WARN( "Point sample is out of bounds" ); else if( ConversionAndBiasFunction( in , out , depthBias ) ) { depthAndWeightSums[thread] += sample.weight; @@ -1017,7 +1017,7 @@ SparseNodeData< OutData , UIntPack< DataSigs ... > > FEMTree< Dim , Real >::setI OutData out; Real depthBias; - if( !_InBounds(p) ) WARN( "Point sample is out of bounds" ); + if( !_InBounds(p) ) MK_WARN( "Point sample is out of bounds" ); else if( ConversionAndBiasFunction( in , out , depthBias ) ) { depthAndWeightSums[thread] += sample.weight; @@ -1101,7 +1101,7 @@ void FEMTree< Dim , Real >::updateExtrapolatedDataField( Data zero , SparseNodeD Point< Real , Dim > p = sample.weight==0 ? sample.data : sample.data / sample.weight; if( !_InBounds(p) ) { - WARN( "Point is out of bounds" ); + MK_WARN( "Point is out of bounds" ); continue; } if( nearest ) _nearestMultiSplatPointData< DensityDegree >( ProjectiveData< Data , Real >( zero ) , density , (FEMTreeNode*)sampleAndNode.node , p , ProjectiveData< Data , Real >( data , sample.weight ) , dataField , densityKey , 2 ); @@ -1122,7 +1122,7 @@ void FEMTree< Dim , Real >::updateExtrapolatedDataField( Data zero , SparseNodeD const ProjectiveData< Point< Real , Dim > , Real >& sample = sampleAndNode.sample; const Data& data = sampleDataFunctor(i); Point< Real , Dim > p = sample.weight==0 ? sample.data : sample.data / sample.weight; - if( !_InBounds(p) ) WARN( "Point is out of bounds" ); + if( !_InBounds(p) ) MK_WARN( "Point is out of bounds" ); else { if( nearest ) _nearestMultiSplatPointData< DensityDegree >( ProjectiveData< Data , Real >( zero ) , density , (FEMTreeNode*)sampleAndNode.node , p , ProjectiveData< Data , Real >( data , sample.weight ) , dataField , densityKey , 2 ); @@ -1163,7 +1163,7 @@ void FEMTree< Dim , Real >::_supportApproximateProlongation( void ) // Mark the neighbors as active Pointer( FEMTreeNode* ) nodes = neighborKey.neighbors[ _localToGlobal(d) ].neighbors().data; - unsigned int size = neighborKey.neighbors[ _localToGlobal(d) ].neighbors.Size; + unsigned int size = neighborKey.neighbors[ _localToGlobal(d) ].neighbors.Size(); for( unsigned int i=0 ; i::_markNonBaseDirichletElements( void ) { supportKey.setLeafNeighbors( node , neighborLeaves ); bool hasDirichletNeighbor = false; - for( int i=0 ; inodeData.getDirichletNodeFlag() ) hasDirichletNeighbor = true; + for( unsigned int i=0 ; inodeData.getDirichletNodeFlag() ) hasDirichletNeighbor = true; node->nodeData.setDirichletElementFlag( hasDirichletNeighbor ); if( node->children ) for( int c=0 ; c<(1<children+c , supportKey , neighborLeaves ); @@ -1228,7 +1228,7 @@ void FEMTree< Dim , Real >::_markBaseDirichletElements( void ) for( LocalDepth d=0 ; d<=_baseDepth ; d++ ) { Pointer( FEMTreeNode* ) _nodes = supportKey.neighbors[ _localToGlobal(d) ].neighbors().data; - unsigned int size = supportKey.neighbors[ _localToGlobal(d) ].neighbors.Size; + unsigned int size = supportKey.neighbors[ _localToGlobal(d) ].neighbors.Size(); for( unsigned int i=0 ; inodeData.setDirichletElementFlag( true ); } } ); @@ -1315,7 +1315,7 @@ std::vector< node_index_type > FEMTree< Dim , Real >::_finalizeForMultigrid( Loc // -- Swap the children sitting off the last node of the old children to the first node of the old children FEMTreeNode *oldChildren = _tree.children; FEMTreeNode *newChildren = FEMTreeNode::NewBrood( nodeAllocator , _nodeInitializer ); - if( !oldChildren ) ERROR_OUT( "Expected children" ); + if( !oldChildren ) MK_ERROR_OUT( "Expected children" ); { if( oldChildren[(1< std::vector< node_index_type > FEMTree< Dim , Real >::merge( FEMTree* tree ) { std::vector< node_index_type > map; - if( _depthOffset!=tree->_depthOffset ) ERROR_OUT( "depthOffsets don't match: %d != %d" , _depthOffset , tree->_depthOffset ); + if( _depthOffset!=tree->_depthOffset ) MK_ERROR_OUT( "depthOffsets don't match: %d != %d" , _depthOffset , tree->_depthOffset ); // Compute the next available index node_index_type nextIndex = 0; diff --git a/Src/Geometry.h b/Src/Geometry.h index d119ebcf..12dde7b3 100644 --- a/Src/Geometry.h +++ b/Src/Geometry.h @@ -180,7 +180,7 @@ namespace PoissonRecon void _init( unsigned int d ) { if( !d ) memset( coords , 0 , sizeof(Real)*Dim ); - else ERROR_OUT( "Should never be called" ); + else MK_ERROR_OUT( "Should never be called" ); } template< class _Real , class ... _Reals > void _init( unsigned int d , _Real v , _Reals ... values ) { @@ -276,7 +276,7 @@ namespace PoissonRecon { if( !_dim ){ _resize( p._dim ) ; memcpy( _coords , p._coords , sizeof(Real)*_dim ); } else if( _dim==p._dim ) memcpy( _coords , p._coords , sizeof(Real)*_dim ); - else ERROR_OUT( "Dimensions don't match: " , _dim , " != " , p._dim ); + else MK_ERROR_OUT( "Dimensions don't match: " , _dim , " != " , p._dim ); return *this; } @@ -289,14 +289,14 @@ namespace PoissonRecon { if( !_dim ){ _resize( p._dim ) ; for( unsigned int i=0 ; i<_dim ; i++ ) _coords[i] = p._coords[i]; } else if( _dim==p._dim ) for( unsigned int i=0 ; i<_dim ; i++ ) _coords[i] += p._coords[i]; - else ERROR_OUT( "Dimensions don't match: " , _dim , " != " , p._dim ); + else MK_ERROR_OUT( "Dimensions don't match: " , _dim , " != " , p._dim ); return *this; } Point& operator -= ( const Point& p ) { if( !_dim ){ _resize( p._dim ) ; for( unsigned int i=0 ; i<_dim ; i++ ) _coords[i] = -p._coords[i]; } else if( _dim==p._dim ) for( unsigned int i=0 ; i<_dim ; i++ ) _coords[i] -= p._coords[i]; - else ERROR_OUT( "Dimensions don't match: " , _dim , " != " , p._dim ); + else MK_ERROR_OUT( "Dimensions don't match: " , _dim , " != " , p._dim ); return *this; } Point& operator *= ( Real s ) @@ -317,7 +317,7 @@ namespace PoissonRecon static Real Dot( const Point &p1 , const Point &p2 ) { Real dot; - if( p1._dim!=p2._dim ) ERROR_OUT( "Dimensions differ: " , p1._dim , " != " , p2._dim ); + if( p1._dim!=p2._dim ) MK_ERROR_OUT( "Dimensions differ: " , p1._dim , " != " , p2._dim ); for( size_t d=0 ; d static typename std::enable_if< _K==Dim-1 , bool >::type IsInterior( Point< Real , Dim > p , const std::vector< Simplex< Real , Dim , Dim-1 > > &simplices ) { - if( !simplices.size() ) ERROR_OUT( "No simplices provided" ); + if( !simplices.size() ) MK_ERROR_OUT( "No simplices provided" ); // Create a ray that intersecting the largest simplex int idx; @@ -709,7 +709,7 @@ namespace PoissonRecon } Ray< Real , Dim > ray( p , simplices[idx].center() - p ); Real l = (Real)Point< Real , Dim >::SquareNorm( ray.direction ); - if( !l ) ERROR_OUT( "point is on simplex" ); + if( !l ) MK_ERROR_OUT( "point is on simplex" ); l = (Real)sqrt(l); ray.direction /= l; @@ -729,7 +729,7 @@ namespace PoissonRecon template< unsigned int _K=K > static typename std::enable_if< _K==Dim-1 , bool >::type IsInterior( Point< Real , Dim > p , const std::vector< Simplex< Real , Dim , Dim-1 > > &simplices , const std::vector< Point< Real , Dim > > &normals ) { - if( !simplices.size() ) ERROR_OUT( "No simplices provided" ); + if( !simplices.size() ) MK_ERROR_OUT( "No simplices provided" ); #if 0 // A more conservative approach for ray-tracing, sending a ray for each simplex and using the consensus solution @@ -738,7 +738,7 @@ namespace PoissonRecon { Ray< Real , Dim > ray( p , simplices[idx].center() - p ); Real l = (Real)Point< Real , Dim >::SquareNorm( ray.direction ); - if( !l ){ WARN( "point is on simplex" ) ; continue; } + if( !l ){ MK_WARN( "point is on simplex" ) ; continue; } l = (Real)sqrt(l); ray.direction /= l; @@ -770,7 +770,7 @@ namespace PoissonRecon } Ray< Real , Dim > ray( p , simplices[idx].center() - p ); Real l = (Real)Point< Real , Dim >::SquareNorm( ray.direction ); - if( !l ) ERROR_OUT( "point is on simplex" ); + if( !l ) MK_ERROR_OUT( "point is on simplex" ); l = (Real)sqrt(l); ray.direction /= l; @@ -819,11 +819,11 @@ namespace PoissonRecon template< unsigned int _K=0 > static typename std::enable_if< _K==Dim-1 , bool >::type IsInterior( Point< Real , Dim > p , const std::vector< Simplex< Real , Dim , Dim-1 > > &simplices , const std::vector< Point< Real , Dim > > &normals ) { - if( !simplices.size() ) ERROR_OUT( "No simplices provided" ); + if( !simplices.size() ) MK_ERROR_OUT( "No simplices provided" ); Ray< Real , Dim > ray( p , simplices[0].center() - p ); Real l = (Real)Point< Real , Dim >::SquareNorm( ray.direction ); - if( !l ) ERROR_OUT( "point is on simplex" ); + if( !l ) MK_ERROR_OUT( "point is on simplex" ); l = (Real)sqrt(l); ray.direction /= l; @@ -863,7 +863,7 @@ namespace PoissonRecon void _init( unsigned int k ) { if( !k ) memset( idx , 0 , sizeof(idx) ); - else ERROR_OUT( "Should never be called" ); + else MK_ERROR_OUT( "Should never be called" ); } template< class ... Ints > void _init( unsigned int k , Index v , Ints ... values ) { diff --git a/Src/Image.h b/Src/Image.h index 460d64a0..b60ad1ac 100644 --- a/Src/Image.h +++ b/Src/Image.h @@ -54,7 +54,7 @@ namespace PoissonRecon unsigned int channels; ImageReader* reader = Get( fileName ); width = reader->width() , height = reader->height() , channels = reader->channels(); - if( channels!=1 && channels!=3 ) ERROR_OUT( "Requres one- or three-channel input" ); + if( channels!=1 && channels!=3 ) MK_ERROR_OUT( "Requres one- or three-channel input" ); unsigned char* pixels = new unsigned char[ width*height*3 ]; unsigned char* pixelRow = new unsigned char[ width*channels]; for( unsigned int j=0 ; j_width = width; reader->_height = height; @@ -290,7 +290,7 @@ namespace PoissonRecon else { delete[] ext; - THROW( "failed to get image writer for: " , fileName ); + MK_THROW( "failed to get image writer for: " , fileName ); } writer->_width = width; writer->_height = height; @@ -307,22 +307,22 @@ namespace PoissonRecon unsigned int *_tileHeights , *_tileWidths; unsigned int _tileRows , _tileColumns , _channels; FILE* fp = fopen( fileName , "r" ); - if( !fp ){ WARN( "Couldn't open file for reading: " , fileName ) ; return false; } + if( !fp ){ MK_WARN( "Couldn't open file for reading: " , fileName ) ; return false; } { char line[1024]; - if( !fgets( line , 1024 , fp ) ) ERROR_OUT( "Failed to read column line from: " , fileName ); + if( !fgets( line , 1024 , fp ) ) MK_ERROR_OUT( "Failed to read column line from: " , fileName ); line[strlen(line)-1] = 0; - if( sscanf( line , "Columns: %d" , &_tileColumns )!=1 ) ERROR_OUT( "Failed to read column count from: " , fileName , " (" , line , ")" ); - if( !fgets( line , 1024 , fp ) ) ERROR_OUT( "Failed to read row line from: " , fileName ); + if( sscanf( line , "Columns: %d" , &_tileColumns )!=1 ) MK_ERROR_OUT( "Failed to read column count from: " , fileName , " (" , line , ")" ); + if( !fgets( line , 1024 , fp ) ) MK_ERROR_OUT( "Failed to read row line from: " , fileName ); line[strlen(line)-1] = 0; - if( sscanf( line , "Rows: %d" , &_tileRows )!=1 ) ERROR_OUT( "Failed to read row count from: " , fileName , " (" , line , ")" ); + if( sscanf( line , "Rows: %d" , &_tileRows )!=1 ) MK_ERROR_OUT( "Failed to read row count from: " , fileName , " (" , line , ")" ); _tileHeights = new unsigned int[ _tileRows+1 ]; _tileWidths = new unsigned int[ _tileColumns+1 ]; char tileName[2048]; for( unsigned int r=0 ; r<_tileRows ; r++ ) for( unsigned int c=0 ; c<_tileColumns ; c++ ) { - if( !fgets( line , 1024 , fp ) ) ERROR_OUT( "Failed to read tile name from: " , fileName ); + if( !fgets( line , 1024 , fp ) ) MK_ERROR_OUT( "Failed to read tile name from: " , fileName ); line[strlen(line)-1] = 0; if( fileDir ) sprintf( tileName , "%s%c%s" , fileDir , FileNameParser::Separator , line ); else sprintf( tileName , "%s" , line ); @@ -330,11 +330,11 @@ namespace PoissonRecon unsigned int _w , _h , _c; ImageReader::GetInfo( tileName , _w , _h , _c ); if( !r && !c ) _channels = _c; - else if( _channels!=_c ) ERROR_OUT( "Number of color channels don't match: " , _channels , " != " , _c ); + else if( _channels!=_c ) MK_ERROR_OUT( "Number of color channels don't match: " , _channels , " != " , _c ); if( !r ) _tileWidths[c+1] = _w; - else if( _tileWidths[c+1]!=_w ) ERROR_OUT( "Images in the same column must have the same width: " , _tileWidths[c+1] , " != " , _w ); + else if( _tileWidths[c+1]!=_w ) MK_ERROR_OUT( "Images in the same column must have the same width: " , _tileWidths[c+1] , " != " , _w ); if( !c ) _tileHeights[r+1] = _h; - else if( _tileHeights[r+1]!=_h ) ERROR_OUT( "Images in the same row must have the same heights: " , _tileHeights[r+1] ," != " , _h ); + else if( _tileHeights[r+1]!=_h ) MK_ERROR_OUT( "Images in the same row must have the same heights: " , _tileHeights[r+1] ," != " , _h ); } } fclose( fp ); @@ -350,15 +350,15 @@ namespace PoissonRecon { char* fileDir = FileNameParser::Dir( fileName ); FILE* fp = fopen( fileName , "r" ); - if( !fp ) ERROR_OUT( "Couldn't open file for reading: " , fileName ); + if( !fp ) MK_ERROR_OUT( "Couldn't open file for reading: " , fileName ); { char line[1024]; - if( !fgets( line , 1024 , fp ) ) ERROR_OUT( "Failed read column line from: " , fileName ); + if( !fgets( line , 1024 , fp ) ) MK_ERROR_OUT( "Failed read column line from: " , fileName ); line[strlen(line)-1] = 0; - if( sscanf( line , "Columns: %d" , &_tileColumns )!=1 ) ERROR_OUT( "Failed to read column count from: " , fileName , " (" , line , ")" ); - if( !fgets( line , 1024 , fp ) ) ERROR_OUT( "Failed read row line from: " , fileName ); + if( sscanf( line , "Columns: %d" , &_tileColumns )!=1 ) MK_ERROR_OUT( "Failed to read column count from: " , fileName , " (" , line , ")" ); + if( !fgets( line , 1024 , fp ) ) MK_ERROR_OUT( "Failed read row line from: " , fileName ); line[strlen(line)-1] = 0; - if( sscanf( line , "Rows: %d" , &_tileRows )!=1 ) ERROR_OUT( "Failed to read row count from: " , fileName , " (" , line , ")" ); + if( sscanf( line , "Rows: %d" , &_tileRows )!=1 ) MK_ERROR_OUT( "Failed to read row count from: " , fileName , " (" , line , ")" ); _tileReaders = new ImageReader*[ _tileColumns ]; _tileHeights = new unsigned int[ _tileRows+1 ]; @@ -368,7 +368,7 @@ namespace PoissonRecon char tileName[2048]; for( unsigned int r=0 ; r<_tileRows ; r++ ) for( unsigned int c=0 ; c<_tileColumns ; c++ ) { - if( !fgets( line , 1024 , fp ) ) ERROR_OUT( "Failed to read tile name from: " , fileName ); + if( !fgets( line , 1024 , fp ) ) MK_ERROR_OUT( "Failed to read tile name from: " , fileName ); line[strlen(line)-1] = 0; if( fileDir ) sprintf( tileName , "%s%c%s" , fileDir , FileNameParser::Separator , line ); else sprintf( tileName , "%s" , line ); @@ -383,11 +383,11 @@ namespace PoissonRecon unsigned int _w , _h , _c; ImageReader::GetInfo( _tileNames[r*_tileColumns+c] , _w , _h , _c ); if( !r && !c ) _channels = _c; - else if( _channels!=_c ) ERROR_OUT( "Number of color channels don't match: " , _channels , " != " , _c ); + else if( _channels!=_c ) MK_ERROR_OUT( "Number of color channels don't match: " , _channels , " != " , _c ); if( !r ) _tileWidths[c+1] = _w; - else if( _tileWidths[c+1]!=_w ) ERROR_OUT( "Images in the same column must have the same width: " , _tileWidths[c+1] , " != " , _w ); + else if( _tileWidths[c+1]!=_w ) MK_ERROR_OUT( "Images in the same column must have the same width: " , _tileWidths[c+1] , " != " , _w ); if( !c ) _tileHeights[r+1] = _h; - else if( _tileHeights[r+1]!=_h ) ERROR_OUT( "Images in the same row must have the same heights: " , _tileHeights[r+1] , " != " , _h ); + else if( _tileHeights[r+1]!=_h ) MK_ERROR_OUT( "Images in the same row must have the same heights: " , _tileHeights[r+1] , " != " , _h ); } _tileWidths[0] = _tileHeights[0] = 0; for( unsigned int c=0 ; c<_tileColumns ; c++ ) _tileWidths[c+1] += _tileWidths[c]; @@ -439,7 +439,7 @@ namespace PoissonRecon } delete[] tileHeader; FILE* fp = fopen( fileName , "w" ); - if( !fp ) ERROR_OUT( "Failed to open file for writing: " , fileName ); + if( !fp ) MK_ERROR_OUT( "Failed to open file for writing: " , fileName ); fprintf( fp , "Columns: %d\n" , _tileColumns ); fprintf( fp , "Rows: %d\n" , _tileRows ); for( unsigned int i=0 ; i<_tileRows*_tileColumns ; i++ ) diff --git a/Src/ImageStitching.cpp b/Src/ImageStitching.cpp index 416d57ec..9096c0d4 100644 --- a/Src/ImageStitching.cpp +++ b/Src/ImageStitching.cpp @@ -186,8 +186,8 @@ struct BufferedImageDerivativeStream : public FEMTreeInitializer< DEFAULT_DIMENS _labelRows[i] = new RGBPixel[ _resolution[0] ]; _maskRows [i] = new int[ _resolution[0] ]; } - if( pixels->channels()!=3 && pixels->channels()!=1 ) ERROR_OUT( "Pixel input must have 1 or 3 channels: " , pixels->channels() ); - if( labels->channels()!=3 && labels->channels()!=1 ) ERROR_OUT( "Label input must have 1 or 3 channels: " , labels->channels() ); + if( pixels->channels()!=3 && pixels->channels()!=1 ) MK_ERROR_OUT( "Pixel input must have 1 or 3 channels: " , pixels->channels() ); + if( labels->channels()!=3 && labels->channels()!=1 ) MK_ERROR_OUT( "Label input must have 1 or 3 channels: " , labels->channels() ); __pixelRow = pixels->channels()==3 ? NULL : new unsigned char[ _resolution[0] ]; __labelRow = labels->channels()==3 ? NULL : new unsigned char[ _resolution[0] ]; _r = -2 ; prefetch(); @@ -281,7 +281,7 @@ void _Execute( void ) ImageReader::GetInfo( In.values[0] , _w , _h , _c ); w = _w , h = _h; ImageReader::GetInfo( In.values[1] , _w , _h , _c ); - if( w!=_w || h!=_h ) ERROR_OUT( "Pixel and label dimensions don't match: " , _w , " x " , _h , " != " , w , " x " , h ); + if( w!=_w || h!=_h ) MK_ERROR_OUT( "Pixel and label dimensions don't match: " , _w , " x " , _h , " != " , w , " x " , h ); } if( Verbose.set ) printf( "Resolution: %d x %d\n" , w , h ); @@ -495,7 +495,7 @@ void _Execute( void ) case 2: _Execute< Real , 2 >() ; break; // case 3: _Execute< Real , 3 >() ; break; // case 4: _Execute< Real , 4 >() ; break; - default: ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); + default: MK_ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); } } #endif // FAST_COMPILE @@ -504,7 +504,7 @@ int main( int argc , char* argv[] ) { Timer timer; #ifdef ARRAY_DEBUG - WARN( "Array debugging enabled" ); + MK_WARN( "Array debugging enabled" ); #endif // ARRAY_DEBUG CmdLineParse( argc-1 , &argv[1] , params ); if( MaxMemoryGB.value>0 ) SetPeakMemoryMB( MaxMemoryGB.value<<10 ); @@ -527,7 +527,7 @@ int main( int argc , char* argv[] ) if( !BaseDepth.set ) BaseDepth.value = FullDepth.value; if( BaseDepth.value>FullDepth.value ) { - if( BaseDepth.set ) WARN( "Base depth must be smaller than full depth: " , BaseDepth.value , " <= " , FullDepth.value ); + if( BaseDepth.set ) MK_WARN( "Base depth must be smaller than full depth: " , BaseDepth.value , " <= " , FullDepth.value ); BaseDepth.value = FullDepth.value; } @@ -539,7 +539,7 @@ int main( int argc , char* argv[] ) #ifdef FAST_COMPILE static const int Degree = DEFAULT_FEM_DEGREE; - WARN( "Compiled for degree-" , Degree , ", " , sizeof(Real)==4 ? "single" : "double" , "-precision _only_" ); + MK_WARN( "Compiled for degree-" , Degree , ", " , sizeof(Real)==4 ? "single" : "double" , "-precision _only_" ); _Execute< Real , Degree >(); #else // !FAST_COMPILE _Execute< Real >(); diff --git a/Src/JPEG.inl b/Src/JPEG.inl index 09aeb76b..e9b3bb0e 100644 --- a/Src/JPEG.inl +++ b/Src/JPEG.inl @@ -43,7 +43,7 @@ my_error_exit (j_common_ptr cinfo) inline bool JPEGReader::GetInfo( const char* fileName , unsigned int& width , unsigned int& height , unsigned int& channels ) { FILE* fp = fopen( fileName , "rb" ); - if( !fp ) ERROR_OUT( "Failed to open: " , fileName ); + if( !fp ) MK_ERROR_OUT( "Failed to open: " , fileName ); struct jpeg_decompress_struct cInfo; struct my_error_mgr jErr; @@ -53,7 +53,7 @@ inline bool JPEGReader::GetInfo( const char* fileName , unsigned int& width , un if( setjmp( jErr.setjmp_buffer ) ) { jpeg_destroy_decompress( &cInfo ); - ERROR_OUT( "JPEG error occured" ); + MK_ERROR_OUT( "JPEG error occured" ); } jpeg_create_decompress( &cInfo ); @@ -74,14 +74,14 @@ inline JPEGReader::JPEGReader( const char* fileName , unsigned int& width , unsi { _currentRow = 0; _fp = fopen( fileName , "rb" ); - if( !_fp ) ERROR_OUT( "Failed to open: " , fileName ); + if( !_fp ) MK_ERROR_OUT( "Failed to open: " , fileName ); _cInfo.err = jpeg_std_error( &_jErr.pub ); _jErr.pub.error_exit = my_error_exit; if( setjmp( _jErr.setjmp_buffer ) ) { jpeg_destroy_decompress( &_cInfo ); - ERROR_OUT( "JPEG error occured" ); + MK_ERROR_OUT( "JPEG error occured" ); } jpeg_create_decompress( &_cInfo ); @@ -112,7 +112,7 @@ inline JPEGWriter::JPEGWriter( const char* fileName , unsigned int width , unsig { _currentRow = 0; _fp = fopen( fileName , "wb" ); - if( !_fp ) ERROR_OUT( "Failed to open: " , fileName ); + if( !_fp ) MK_ERROR_OUT( "Failed to open: " , fileName ); _cInfo.err = jpeg_std_error( &_jErr.pub ); jpeg_create_compress( &_cInfo ); diff --git a/Src/MarchingCubes.h b/Src/MarchingCubes.h index 2e7b6df7..2756f496 100644 --- a/Src/MarchingCubes.h +++ b/Src/MarchingCubes.h @@ -46,7 +46,7 @@ namespace PoissonRecon if( dir==BACK ) return std::string( "back" ); else if( dir==CROSS ) return std::string( "cross" ); else if( dir==FRONT ) return std::string( "front" ); - else{ ERROR_OUT( "Unrecognized direction" ) ; return std::string( "" ); } + else{ MK_ERROR_OUT( "Unrecognized direction" ) ; return std::string( "" ); } } // The number of k-dimensional elements in a d-dimensional cube is equal to @@ -346,7 +346,7 @@ namespace PoissonRecon case BACK: index = coIndex ; break; case CROSS: index = coIndex + HyperCube::ElementNum< D-1 , K >::Value ; break; case FRONT: index = coIndex + HyperCube::ElementNum< D-1 , K >::Value + HyperCube::ElementNum< D-1 , K-1 >::Value ; break; - default: ERROR_OUT( "Bad direction: " , dir ); + default: MK_ERROR_OUT( "Bad direction: " , dir ); } } template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > @@ -356,7 +356,7 @@ namespace PoissonRecon { case BACK: index = coIndex ; break; case FRONT: index = coIndex + HyperCube::ElementNum< D-1 , K >::Value ; break; - default: ERROR_OUT( "Bad direction: " , dir ); + default: MK_ERROR_OUT( "Bad direction: " , dir ); } } template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > diff --git a/Src/MergePlyClientServer.inl b/Src/MergePlyClientServer.inl index 700a28d4..48e17c6d 100644 --- a/Src/MergePlyClientServer.inl +++ b/Src/MergePlyClientServer.inl @@ -47,8 +47,8 @@ inline void _Copy( FILE *target , FILE *source , size_t sz , size_t bufferSize=1 while( sz ) { size_t ioBytes = std::min< size_t >( bufferSize , sz ); - if( ioBytes!=fread( buffer , sizeof(unsigned char) , ioBytes , source ) ) ERROR_OUT( "Failed to read from source: " , ioBytes ); - if( ioBytes!=fwrite( buffer , sizeof(unsigned char) , ioBytes , target ) ) ERROR_OUT( "Failed to write to target: " , ioBytes ); + if( ioBytes!=fread( buffer , sizeof(unsigned char) , ioBytes , source ) ) MK_ERROR_OUT( "Failed to read from source: " , ioBytes ); + if( ioBytes!=fwrite( buffer , sizeof(unsigned char) , ioBytes , target ) ) MK_ERROR_OUT( "Failed to write to target: " , ioBytes ); sz -= ioBytes; } } @@ -101,13 +101,13 @@ void _OffsetPolygons( const Factory &factory , std::string in , std::string out auto ReadPolygon = [&]( FILE *fp ) { int n; - if( fread( &n , sizeof(int) , 1 , fp )!=1 ) ERROR_OUT( "Failed to read polygon size" ); + if( fread( &n , sizeof(int) , 1 , fp )!=1 ) MK_ERROR_OUT( "Failed to read polygon size" ); if( n>maxIndices ) { maxIndices = n; faceIndices = (Index*)realloc( faceIndices , sizeof(Index) * maxIndices ); } - if( fread( faceIndices , sizeof(Index) , n , fp )!=n ) ERROR_OUT( "Failed to read polygon indices" ); + if( fread( faceIndices , sizeof(Index) , n , fp )!=n ) MK_ERROR_OUT( "Failed to read polygon indices" ); return n; }; @@ -184,8 +184,8 @@ void _RunServer for( unsigned int j=0 ; j( elems[j] )==std::string( "vertex" ) ) foundVertices = true , vNum[i] = std::get<1>( elems[j] ); else if( std::get<0>( elems[j] )==std::string( "face" ) ) foundFaces = true , fNum[i] = std::get<1>( elems[j] ); - if( !foundVertices ) ERROR_OUT( "Could not find vertices" ); - if( !foundFaces ) ERROR_OUT( "Could not find faces" ); + if( !foundVertices ) MK_ERROR_OUT( "Could not find vertices" ); + if( !foundFaces ) MK_ERROR_OUT( "Could not find faces" ); profiler.update(); } offsets[0] = 0; @@ -194,7 +194,7 @@ void _RunServer // Strip out the polygons (though perhaps we should just have the reconstruction code do this). #ifdef SHOW_WARNINGS - WARN( "Should split the mesh during reconstruction" ); + MK_WARN( "Should split the mesh during reconstruction" ); #endif // SHOW_WARNINGS _IndexType idxType; @@ -253,7 +253,7 @@ void _RunServer case INT: std::get<2>( elems[1] )[0] = PLY::Face< int >::Properties[0] ; break; case U_INT: std::get<2>( elems[1] )[0] = PLY::Face< unsigned int >::Properties[0] ; break; case LONG_LONG: std::get<2>( elems[1] )[0] = PLY::Face< long long >::Properties[0] ; break; - default: ERROR_OUT( "Unrecognized output type" ); + default: MK_ERROR_OUT( "Unrecognized output type" ); } } @@ -402,7 +402,7 @@ void RunServer std::function< std::vector< std::string > (unsigned int) > commentFunctor ) { - if( clientSockets.size()!=sharedVertexCounts.size()+1 ) ERROR_OUT( "Socket num and shared vertex count don't match: " , clientSockets.size() , " / " , sharedVertexCounts.size() ); + if( clientSockets.size()!=sharedVertexCounts.size()+1 ) MK_ERROR_OUT( "Socket num and shared vertex count don't match: " , clientSockets.size() , " / " , sharedVertexCounts.size() ); for( unsigned int i=0 ; i( factory , in , out , offset , profiler ) ; break; case U_INT: _OffsetPolygons< unsigned int >( factory , in , out , offset , profiler ) ; break; case LONG_LONG: _OffsetPolygons< long long >( factory , in , out , offset , profiler ) ; break; - default: ERROR_OUT( "Unrecognized output index type" ); + default: MK_ERROR_OUT( "Unrecognized output index type" ); } char done = 1; socketStream.write( done ); @@ -508,15 +508,15 @@ ClientMergePlyInfo::ClientMergePlyInfo( BinaryStream &stream ) return true; }; - if( !stream.read( bufferSize ) ) ERROR_OUT( "Failed to read buffer size" ); + if( !stream.read( bufferSize ) ) MK_ERROR_OUT( "Failed to read buffer size" ); { size_t sz; - if( !stream.read( sz ) ) ERROR_OUT( "Failed to read number of auxiliary properties" ); + if( !stream.read( sz ) ) MK_ERROR_OUT( "Failed to read number of auxiliary properties" ); auxProperties.resize(sz); for( size_t i=0 ; i lock( setAtomicMutex ); Value oldValue = *(Value*)&value; @@ -82,7 +82,7 @@ namespace PoissonRecon else if constexpr( sizeof(Value)==8 ) return SetAtomic64_( &value , newValue , oldValue ); else { - WARN_ONCE( "should not use this function: " , sizeof(Value) ); + MK_WARN_ONCE( "should not use this function: " , sizeof(Value) ); static std::mutex setAtomicMutex; std::lock_guard< std::mutex > lock( setAtomicMutex ); if( value==oldValue ){ value = newValue ; return true; } @@ -98,7 +98,7 @@ namespace PoissonRecon else if constexpr( sizeof(Value)==8 ) return AddAtomic64_( &a , b ); else { - WARN_ONCE( "should not use this function: " , sizeof(Value) ); + MK_WARN_ONCE( "should not use this function: " , sizeof(Value) ); static std::mutex addAtomicMutex; std::lock_guard< std::mutex > lock( addAtomicMutex ); *(Value*)&a += b; @@ -113,7 +113,7 @@ namespace PoissonRecon else if constexpr( sizeof(Value)==8 ) return ReadAtomic64_( &value ); else { - WARN_ONCE( "should not use this function: " , sizeof(Value) ); + MK_WARN_ONCE( "should not use this function: " , sizeof(Value) ); static std::mutex readAtomicMutex; std::lock_guard< std::mutex > lock( readAtomicMutex ); return *(Value*)&value; @@ -128,7 +128,7 @@ namespace PoissonRecon if constexpr( std::is_pod_v< Value > ) AddAtomic( a , b ); else { - WARN_ONCE( "should not use this function: " , typeid(Value).name() ); + MK_WARN_ONCE( "should not use this function: " , typeid(Value).name() ); static std::mutex addAtomicMutex; std::lock_guard< std::mutex > lock( addAtomicMutex ); *(Value*)&a += b; @@ -140,7 +140,7 @@ namespace PoissonRecon if constexpr( std::is_pod_v< Value > ) return SetAtomic( value , newValue ); else { - WARN_ONCE( "should not use this function: " , typeid(Value).name() ); + MK_WARN_ONCE( "should not use this function: " , typeid(Value).name() ); static std::mutex setAtomicMutex; std::lock_guard< std::mutex > lock( setAtomicMutex ); Value oldValue = *(Value*)&value; @@ -154,7 +154,7 @@ namespace PoissonRecon if constexpr( std::is_pod_v< Value > ) return SetAtomic( value , newValue , oldValue ); else { - WARN_ONCE( "should not use this function: " , typeid(Value).name() , " , " , sizeof(Value) ); + MK_WARN_ONCE( "should not use this function: " , typeid(Value).name() , " , " , sizeof(Value) ); static std::mutex setAtomicMutex; std::lock_guard< std::mutex > lock( setAtomicMutex ); if( value==oldValue ){ value = newValue ; return true; } @@ -167,7 +167,7 @@ namespace PoissonRecon if constexpr( std::is_pod_v< Value > ) return ReadAtomic( value ); else { - WARN_ONCE( "should not use this function: " , typeid(Value).name() , " , " , sizeof(Value) ); + MK_WARN_ONCE( "should not use this function: " , typeid(Value).name() , " , " , sizeof(Value) ); static std::mutex readAtomicMutex; std::lock_guard< std::mutex > lock( readAtomicMutex ); return *(Value*)&value; diff --git a/Src/MyExceptions.h b/Src/MyExceptions.h index ad5bf110..34852de8 100644 --- a/Src/MyExceptions.h +++ b/Src/MyExceptions.h @@ -91,30 +91,17 @@ namespace PoissonRecon exit( EXIT_FAILURE ); } } -#ifndef WARN -#define WARN( ... ) Warn( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) -#endif // WARN -#ifndef WARN_ONCE -#define WARN_ONCE( ... ) { static bool firstTime = true ; if( firstTime ) Warn( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) ; firstTime = false; } -#endif // WARN_ONCE -#ifndef THROW -#define THROW( ... ) Throw( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) -#endif // THROW -#ifndef ERROR_OUT -#define ERROR_OUT( ... ) ErrorOut( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) -#endif // ERROR_OUT - -#ifndef PR_WARN -#define PR_WARN( ... ) PoissonRecon::Warn( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) -#endif // PR_WARN -#ifndef PR_WARN_ONCE -#define PR_WARN_ONCE( ... ) { static bool firstTime = true ; if( firstTime ) PoissonRecon::Warn( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) ; firstTime = false; } -#endif // PR_WARN_ONCE -#ifndef PR_THROW -#define PR_THROW( ... ) PoissonRecon::Throw( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) -#endif // PR_THROW -#ifndef PR_ERROR_OUT -#define PR_ERROR_OUT( ... ) PoissonRecon::ErrorOut( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) -#endif // PR_ERROR_OUT +#ifndef MK_WARN +#define MK_WARN( ... ) Warn( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) +#endif // MK_WARN +#ifndef MK_WARN_ONCE +#define MK_WARN_ONCE( ... ) { static bool firstTime = true ; if( firstTime ) Warn( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) ; firstTime = false; } +#endif // MK_WARN_ONCE +#ifndef MK_THROW +#define MK_THROW( ... ) Throw( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) +#endif // MK_THROW +#ifndef MK_ERROR_OUT +#define MK_ERROR_OUT( ... ) ErrorOut( __FILE__ , __LINE__ , __FUNCTION__ , __VA_ARGS__ ) +#endif // MK_ERROR_OUT #endif // MY_EXCEPTIONS_INCLUDED diff --git a/Src/MyMiscellany.h b/Src/MyMiscellany.h index 007285b8..509cf3df 100644 --- a/Src/MyMiscellany.h +++ b/Src/MyMiscellany.h @@ -257,7 +257,7 @@ namespace PoissonRecon JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 }; jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_JOB_MEMORY; jeli.JobMemoryLimit = peakMemory; - if( !SetInformationJobObject( h , JobObjectExtendedLimitInformation , &jeli , sizeof( jeli ) ) ) WARN( "Failed to set memory limit" ); + if( !SetInformationJobObject( h , JobObjectExtendedLimitInformation , &jeli , sizeof( jeli ) ) ) MK_WARN( "Failed to set memory limit" ); } #else // !_WIN32 && !_WIN64 inline void SetPeakMemoryMB( size_t sz ) diff --git a/Src/NestedVector.h b/Src/NestedVector.h index 7022a80a..8952a102 100644 --- a/Src/NestedVector.h +++ b/Src/NestedVector.h @@ -90,7 +90,7 @@ namespace PoissonRecon size_t resize( size_t sz , const T &defaultValue ) { - if( sz>_MaxSize ) ERROR_OUT( "Resize size exceeds max size, considering increasing nesting: " , sz , " > " , _MaxSize ); + if( sz>_MaxSize ) MK_ERROR_OUT( "Resize size exceeds max size, considering increasing nesting: " , sz , " > " , _MaxSize ); // Quick check to see if anything needs doing if( sz<_size ) return size(); @@ -117,9 +117,9 @@ namespace PoissonRecon void read( BinaryStream &stream ) { size_t sz; - if( !stream.read( sz ) ) ERROR_OUT( "Failed to read _size" ); + if( !stream.read( sz ) ) MK_ERROR_OUT( "Failed to read _size" ); resize( sz ); - if( !stream.read( GetPointer( _data , _Size ) , _size ) ) ERROR_OUT( "Failed to read _data" ); + if( !stream.read( GetPointer( _data , _Size ) , _size ) ) MK_ERROR_OUT( "Failed to read _data" ); } void write( BinaryStream &stream , const Serializer< T > &serializer ) const @@ -141,12 +141,12 @@ namespace PoissonRecon const size_t serializedSize = serializer.size(); size_t sz; - if( !stream.read( sz ) ) ERROR_OUT( "Failed to read _size" ); + if( !stream.read( sz ) ) MK_ERROR_OUT( "Failed to read _size" ); if( _size ) { resize( sz ); char *buffer = new char[ _size * serializedSize ]; - if( !stream.read( buffer , serializedSize*_size ) ) ERROR_OUT( "Failed tor read in data" ); + if( !stream.read( buffer , serializedSize*_size ) ) MK_ERROR_OUT( "Failed tor read in data" ); for( size_t i=0 ; i<_size ; i++ ) serializer.deserialize( buffer+i*serializedSize , operator[]( i ) ); delete[] buffer; } @@ -226,7 +226,7 @@ namespace PoissonRecon size_t resize( size_t sz , const T &defaultValue ) { - if( sz>_MaxSize ) ERROR_OUT( "Resize size exceeds max size, considering increasing nesting: " , sz , " > " , _MaxSize ); + if( sz>_MaxSize ) MK_ERROR_OUT( "Resize size exceeds max size, considering increasing nesting: " , sz , " > " , _MaxSize ); size_t _sz = (sz+NestedVector< T , Depth-1 , LogSize >::_Mask)>>(LogSize*Depth); @@ -272,7 +272,7 @@ namespace PoissonRecon void read( BinaryStream &stream ) { size_t sz; - if( !stream.read( sz ) ) ERROR_OUT( "Failed to read _size" ); + if( !stream.read( sz ) ) MK_ERROR_OUT( "Failed to read _size" ); resize( sz ); for( size_t i=0 ; i<_size ; i++ ) _data[i]->read(stream); } @@ -289,7 +289,7 @@ namespace PoissonRecon const size_t serializedSize = serializer.size(); size_t sz; - if( !stream.read( sz ) ) ERROR_OUT( "Failed to read _size" ); + if( !stream.read( sz ) ) MK_ERROR_OUT( "Failed to read _size" ); resize( sz ); for( size_t i=0 ; i<_size ; i++ ) _data[i]->read( stream , serializer ); } diff --git a/Src/PNG.inl b/Src/PNG.inl index bbf4d69f..edd3080a 100644 --- a/Src/PNG.inl +++ b/Src/PNG.inl @@ -31,16 +31,16 @@ inline PNGReader::PNGReader( const char* fileName , unsigned int& width , unsign _currentRow = 0; _png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING , 0 , 0 , 0); - if( !_png_ptr ) ERROR_OUT( "Failed to create png pointer" ); + if( !_png_ptr ) MK_ERROR_OUT( "Failed to create png pointer" ); _info_ptr = png_create_info_struct( _png_ptr ); - if( !_info_ptr ) ERROR_OUT( "Failed to create info pointer" ); + if( !_info_ptr ) MK_ERROR_OUT( "Failed to create info pointer" ); _end_info = png_create_info_struct( _png_ptr ); - if( !_end_info ) ERROR_OUT( "Failed to create end pointer" ); + if( !_end_info ) MK_ERROR_OUT( "Failed to create end pointer" ); _fp = fopen( fileName , "rb" ); - if( !_fp ) ERROR_OUT( "Failed to open file for reading: " , fileName ); + if( !_fp ) MK_ERROR_OUT( "Failed to open file for reading: " , fileName ); png_init_io( _png_ptr , _fp ); png_read_info( _png_ptr, _info_ptr ); @@ -52,12 +52,12 @@ inline PNGReader::PNGReader( const char* fileName , unsigned int& width , unsign int color_type = png_get_color_type( _png_ptr , _info_ptr ); if( bit_depth==16 ) { - WARN( "Converting 16-bit image to 8-bit image" ); + MK_WARN( "Converting 16-bit image to 8-bit image" ); _scratchRow = new unsigned char[ channels*width*2 ]; } else { - if( bit_depth!=8 ) ERROR_OUT( "Expected 8 bits per channel" ); + if( bit_depth!=8 ) MK_ERROR_OUT( "Expected 8 bits per channel" ); _scratchRow = NULL; } if( color_type==PNG_COLOR_TYPE_PALETTE ) png_set_expand( _png_ptr ) , printf( "Expanding PNG color pallette\n" ); @@ -98,14 +98,14 @@ inline bool PNGReader::GetInfo( const char* fileName , unsigned int& width , uns FILE* fp; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING , 0 , 0 , 0); - if( !png_ptr ) ERROR_OUT( "Failed to create png pointer" ); + if( !png_ptr ) MK_ERROR_OUT( "Failed to create png pointer" ); info_ptr = png_create_info_struct( png_ptr ); - if( !info_ptr ) ERROR_OUT( "Failed to create info pointer" ); + if( !info_ptr ) MK_ERROR_OUT( "Failed to create info pointer" ); end_info = png_create_info_struct( png_ptr ); - if( !end_info ) ERROR_OUT( "Failed to create end pointer" ); + if( !end_info ) MK_ERROR_OUT( "Failed to create end pointer" ); fp = fopen( fileName , "rb" ); - if( !fp ) ERROR_OUT( "Failed to open file for reading: " , fileName ); + if( !fp ) MK_ERROR_OUT( "Failed to open file for reading: " , fileName ); png_init_io( png_ptr , fp ); png_read_info( png_ptr, info_ptr ); @@ -124,12 +124,12 @@ PNGWriter::PNGWriter( const char* fileName , unsigned int width , unsigned int h _currentRow = 0; _png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING , 0 , 0 , 0 ); - if( !_png_ptr ) ERROR_OUT( "Failed to create png write struct" ); + if( !_png_ptr ) MK_ERROR_OUT( "Failed to create png write struct" ); _info_ptr = png_create_info_struct( _png_ptr ); - if( !_info_ptr ) ERROR_OUT( "Failed to create png info struct"); + if( !_info_ptr ) MK_ERROR_OUT( "Failed to create png info struct"); _fp = fopen( fileName , "wb" ); - if( !_fp ) ERROR_OUT( "Failed to open file for writing: %s" , fileName ); + if( !_fp ) MK_ERROR_OUT( "Failed to open file for writing: %s" , fileName ); png_init_io( _png_ptr , _fp ); png_set_compression_level( _png_ptr , Z_BEST_SPEED ); @@ -140,7 +140,7 @@ PNGWriter::PNGWriter( const char* fileName , unsigned int width , unsigned int h case 1: pngColorType = PNG_COLOR_TYPE_GRAY ; break; case 3: pngColorType = PNG_COLOR_TYPE_RGB ; break; case 4: pngColorType = PNG_COLOR_TYPE_RGBA ; break; - default: ERROR_OUT( "Only 1, 3, or 4 channel PNGs are supported" ); + default: MK_ERROR_OUT( "Only 1, 3, or 4 channel PNGs are supported" ); }; png_set_IHDR( _png_ptr , _info_ptr, width , height, 8 , pngColorType , PNG_INTERLACE_NONE , PNG_COMPRESSION_TYPE_DEFAULT , PNG_FILTER_TYPE_DEFAULT ); png_write_info( _png_ptr , _info_ptr ); diff --git a/Src/ParameterPack.h b/Src/ParameterPack.h new file mode 100644 index 00000000..58369708 --- /dev/null +++ b/Src/ParameterPack.h @@ -0,0 +1,349 @@ +/* +Copyright (c) 2016, 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 PARAMETER_PACK_INCLUDED +#define PARAMETER_PACK_INCLUDED + +///////////////////// +// parameter packs // +///////////////////// + +namespace ParameterPack +{ + //////////////////////////// + //////////////////////////// + //// Short declarations //// + //////////////////////////// + //////////////////////////// + + // A wrapper class for passing unsigned integer parameter packs + template< typename IntegralType , IntegralType ... Values > struct Pack; + + // A class that identifies a single entry and its complement + template< unsigned int I , typename Pack > struct Selection; + + // A class that splits a Pack into two sub-packs + template< unsigned int I , typename Pack > struct Partition; + + // A class for comparing two Packs + template< typename Pack1 , typename Pack2 > struct Comparison; + + // A class for adding/subtracting two Packs + template< typename Pack1 , typename Pack2 > struct Arithmetic; + + // A helper class for defining a concatenation of multiple Packs + template< typename ... Packs > struct _Concatenation; + + // A helper class for defining the permutation of a Pack + template< typename Pack , typename PermutationPack > struct _Permutation; + + // A helper class for defining a Pack with the same value repeated Dim times + template< typename IntegralType , unsigned int Dim , IntegralType Value > struct _IsotropicPack; + + // A helper class for defining a Pack with sequentially increasing values + template< typename IntegralType , unsigned int Dim , IntegralType StartValue > struct _SequentialPack; + + // A Pack that is the concatenation of multiple Packs + template< typename ... Packs > using Concatenation = typename _Concatenation< Packs ... >::type; + + // A Pack that is the permtuation of a Pack + // [NOTE] The entry in the i-th position of PermutationPack indicates where the i-th position comes from (not goes to) + template< typename Pack , typename PermutationPack > using Permutation = typename _Permutation< Pack , PermutationPack >::type; + + // A Pack that has the same value repeated Dim times + template< typename IntegralType , unsigned int Dim , IntegralType Value=0 > using IsotropicPack = typename _IsotropicPack< IntegralType , Dim , Value >::type; + + // A Pack with sequentially increasing values + template< typename IntegralType , unsigned int Dim , IntegralType StartValue=0 > using SequentialPack = typename _SequentialPack< IntegralType , Dim , StartValue >::type; + + ///////////////////////// + ///////////////////////// + //// Specializations //// + ///////////////////////// + ///////////////////////// + + // A pack with int values + template< int ... Values > using IntPack = Pack< int , Values... >; + + // A pack with unsigned int values + template< unsigned int ... Values > using UIntPack = Pack< unsigned int , Values... >; + + // An isotropic pack with int values + template< unsigned int Dim , int Value=0 > using IsotropicIntPack = IsotropicPack< int , Dim , Value >; + + // An isotropic pack with unsigned int values + template< unsigned int Dim , unsigned int Value=0 > using IsotropicUIntPack = IsotropicPack< unsigned int , Dim , Value >; + + + ///////////////////// + ///////////////////// + //// Definitions //// + ///////////////////// + ///////////////////// + + + ////////// + // Pack // + ////////// + + // The general case + template< typename IntegralType , IntegralType _Value , IntegralType ... _Values > struct Pack< IntegralType , _Value , _Values ... > + { + static const IntegralType First = _Value; + typedef Pack< IntegralType , _Values ... > Rest; + typedef typename Rest::Transpose::template Append< First > Transpose; + + static const unsigned int Size = 1 + sizeof ... ( _Values ); + + template< IntegralType ... __Values > using Append = Pack< IntegralType , _Value , _Values ... , __Values ... >; + template< IntegralType ... __Values > using Prepend = Pack< IntegralType , __Values ... , _Value , _Values ... >; + + static const IntegralType Values[]; + + template< unsigned int I > constexpr static IntegralType Get( void ) + { + if constexpr( I==0 ) return _Value; + else return Rest::template Get< I-1 >(); + } + + static constexpr IntegralType Min( void ){ return _Value < Rest::Min() ? _Value : Rest::Min(); } + static constexpr IntegralType Max( void ){ return _Value > Rest::Max() ? _Value : Rest::Max(); } + + friend std::ostream &operator << ( std::ostream &os , Pack ) + { + os << "< "; + for( unsigned int i=0 ; i"; + } + }; + + // The specialized case with one entry + template< typename IntegralType , IntegralType _Value > struct Pack< IntegralType , _Value > + { + static const IntegralType First = _Value; + typedef Pack< IntegralType > Rest; + typedef Pack< IntegralType , _Value > Transpose; + + static const unsigned int Size = 1; + + template< IntegralType ... __Values > using Append = Pack< IntegralType , _Value , __Values ... >; + template< IntegralType ... __Values > using Prepend = Pack< IntegralType , __Values ... , _Value >; + + static const IntegralType Values[]; + + template< unsigned int I > constexpr static IntegralType Get( void ) + { + static_assert( I==0 , "[ERROR] Pack< IntegralType , Value >::Get called with non-zero index" ); + return _Value; + } + + static constexpr IntegralType Min( void ){ return _Value; } + static constexpr IntegralType Max( void ){ return _Value; } + + friend std::ostream &operator << ( std::ostream &os , Pack ) + { + return os << "< " << First << " >"; + } + }; + + // The specialized case with no entries + template< typename IntegralType > struct Pack< IntegralType > + { + typedef Pack< IntegralType > Rest; + static const unsigned int Size = 0; + static constexpr IntegralType Values[] = { 0 }; + typedef Pack< IntegralType > Transpose; + template< IntegralType ... __Values > using Append = Pack< IntegralType , __Values ... >; + template< IntegralType ... __Values > using Prepend = Pack< IntegralType , __Values ... >; + friend std::ostream &operator << ( std::ostream &os , Pack ){ return os << "< >"; } + }; + + template< typename IntegralType , IntegralType _Value , IntegralType ... _Values > const IntegralType Pack< IntegralType , _Value , _Values ... >::Values[] = { _Value , _Values ... }; + template< typename IntegralType , IntegralType _Value > const IntegralType Pack< IntegralType , _Value >::Values[] = { _Value }; + + /////////////// + // Selection // + /////////////// + template< unsigned int I , typename IntegralType , IntegralType _Value , IntegralType ... _Values > + struct Selection< I , Pack< IntegralType , _Value , _Values ... > > + { + static const IntegralType Value = Selection< I-1 , Pack< IntegralType , _Values ... > >::Value; + typedef typename Selection< I-1 , Pack< IntegralType , _Values ... > >::Complement::template Prepend< _Value > Complement; + }; + + template< typename IntegralType , IntegralType _Value , IntegralType ... _Values > + struct Selection< 0 , Pack< IntegralType , _Value , _Values ... > > + { + static const IntegralType Value = _Value; + typedef Pack< IntegralType , _Values ... > Complement; + }; + + /////////////// + // Partition // + /////////////// + template< typename IntegralType , IntegralType ... Values > + struct Partition< 0 , Pack< IntegralType , Values ... > > + { + typedef Pack< IntegralType > First; + typedef Pack< IntegralType , Values ... > Second; + }; + + template< unsigned int I , typename IntegralType , IntegralType ... Values > + struct Partition< I , Pack< IntegralType , Values ... > > + { + typedef Concatenation< Pack< IntegralType , Pack< IntegralType , Values ... >::First > , typename Partition< I-1 , typename Pack< IntegralType , Values ... >::Rest >::First > First; + typedef typename Partition< I-1 , typename Pack< IntegralType , Values ... >::Rest >::Second Second; + }; + + //////////////// + // Arithmetic // + //////////////// + template< typename IntegralType > + struct Arithmetic< Pack< IntegralType > , Pack< IntegralType > > + { + using Sum = Pack< IntegralType >; + using Difference = Pack< IntegralType >; + }; + + template< typename IntegralType , IntegralType Value1 , IntegralType ... Values1 , IntegralType Value2 , IntegralType ... Values2 > + struct Arithmetic< Pack< IntegralType , Value1 , Values1 ... > , Pack< IntegralType , Value2 , Values2 ... > > + { + using Sum = Concatenation< Pack< IntegralType , Value1+Value2 > , typename Arithmetic< Pack< IntegralType , Values1 ... > , Pack< IntegralType , Values2... > >::Sum >; + using Difference = Concatenation< Pack< IntegralType , Value1-Value2 > , typename Arithmetic< Pack< IntegralType , Values1 ... > , Pack< IntegralType , Values2... > >::Difference >; + }; + + template< typename IntegralType , IntegralType ... Values1 , IntegralType ... Values2 > + typename Arithmetic< Pack< IntegralType , Values1... > , Pack< IntegralType , Values2... > >::Sum operator + ( Pack< IntegralType , Values1... > , Pack< IntegralType , Values2... > ){ return typename Arithmetic< Pack< IntegralType , Values1... > , Pack< IntegralType , Values2... > >::Sum(); } + + template< typename IntegralType , IntegralType ... Values1 , IntegralType ... Values2 > + typename Arithmetic< Pack< IntegralType , Values1... > , Pack< IntegralType , Values2... > >::Difference operator - ( Pack< IntegralType , Values1... > , Pack< IntegralType , Values2... > ){ return typename Arithmetic< Pack< IntegralType , Values1... > , Pack< IntegralType , Values2... > >::Difference(); } + + + //////////////// + // Comparison // + //////////////// + template< typename IntegralType , IntegralType ... Values1 , IntegralType ... Values2 > + struct Comparison< Pack< IntegralType , Values1 ... > , Pack< IntegralType , Values2 ... > > + { + typedef Pack< IntegralType , Values1 ... > Pack1; + typedef Pack< IntegralType , Values2 ... > Pack2; + static const bool Equal = Pack1::First==Pack2::First && Comparison< typename Pack1::Rest , typename Pack2::Rest >::Equal; + static const bool NotEqual = Pack1::First!=Pack2::First || Comparison< typename Pack1::Rest , typename Pack2::Rest >::NotEqual; + static const bool LessThan = Pack1::First< Pack2::First && Comparison< typename Pack1::Rest , typename Pack2::Rest >::LessThan; + static const bool LessThanOrEqual = Pack1::First<=Pack2::First && Comparison< typename Pack1::Rest , typename Pack2::Rest >::LessThanOrEqual; + static const bool GreaterThan = Pack1::First> Pack2::First && Comparison< typename Pack1::Rest , typename Pack2::Rest >::GreaterThan; + static const bool GreaterThanOrEqual = Pack1::First>=Pack2::First && Comparison< typename Pack1::Rest , typename Pack2::Rest >::GreaterThanOrEqual; + }; + + template< typename IntegralType , IntegralType Value1 , IntegralType Value2 > + struct Comparison< Pack< IntegralType , Value1 > , Pack< IntegralType , Value2 > > + { + static const bool Equal = Value1==Value2; + static const bool NotEqual = Value1!=Value2; + static const bool LessThan = Value1Value2; + static const bool GreaterThanOrEqual = Value1>=Value2; + }; + + template< typename IntegralType > + struct Comparison< Pack< IntegralType > , Pack< IntegralType > > + { + static const bool Equal = true; + static const bool NotEqual = false; + static const bool LessThan = false; + static const bool LessThanOrEqual = true; + static const bool GreaterThan = false; + static const bool GreaterThanOrEqual = true; + }; + + template< typename IntegralType , IntegralType ... Values1 , IntegralType ... Values2 > + bool operator==( const Pack< IntegralType , Values1... > , const Pack< IntegralType , Values2... > ){ return Comparison< Pack< IntegralType , Values1... > , Pack< IntegralType , Values2... > >::Equal; } + + template< typename IntegralType , IntegralType ... Values1 , IntegralType ... Values2 > + bool operator!=( const Pack< IntegralType , Values1... > , const Pack< IntegralType , Values2... > ){ return Comparison< Pack< IntegralType , Values1... > , Pack< IntegralType , Values2... > >::NotEqual; } + + template< typename IntegralType , IntegralType ... Values1 , IntegralType ... Values2 > + bool operator<( const Pack< IntegralType , Values1... > , const Pack< IntegralType , Values2... > ){ return Comparison< Pack< IntegralType , Values1... > , Pack< IntegralType , Values2... > >::LessThan; } + + template< typename IntegralType , IntegralType ... Values1 , IntegralType ... Values2 > + bool operator<=( const Pack< IntegralType , Values1... > , const Pack< IntegralType , Values2... > ){ return Comparison< Pack< IntegralType , Values1... > , Pack< IntegralType , Values2... > >::LessThanOrEqual; } + + template< typename IntegralType , IntegralType ... Values1 , IntegralType ... Values2 > + bool operator>( const Pack< IntegralType , Values1... > , const Pack< IntegralType , Values2... > ){ return Comparison< Pack< IntegralType , Values1... > , Pack< IntegralType , Values2... > >::GreaterThan; } + + template< typename IntegralType , IntegralType ... Values1 , IntegralType ... Values2 > + bool operator>=( const Pack< IntegralType , Values1... > , const Pack< IntegralType , Values2... > ){ return Comparison< Pack< IntegralType , Values1... > , Pack< IntegralType , Values2... > >::GreaterThanOrEqual; } + + //////////////////// + // _Concatenation // + //////////////////// + template< typename IntegralType , IntegralType ... Values1 , IntegralType ... Values2 , typename ... Packs > + struct _Concatenation< Pack< IntegralType , Values1 ... > , Pack< IntegralType , Values2 ... > , Packs ... > + { + typedef typename _Concatenation< typename Pack< IntegralType , Values1 ... >::template Append< Values2 ... > , Packs ... >::type type; + }; + template< typename IntegralType , IntegralType ... Values > + struct _Concatenation< Pack< IntegralType , Values ... > > + { + typedef Pack< IntegralType , Values ... > type; + }; + + ////////////////// + // _Permutation // + ////////////////// + template< typename IntegralType , IntegralType ... Values , unsigned int ... PermutationValues > + struct _Permutation< Pack< IntegralType , Values ... > , Pack< unsigned int , PermutationValues ... > > + { + typedef Pack< IntegralType , PermutationValues ... > PPack; + typedef Concatenation< Pack< IntegralType , Selection< PPack::First , Pack< IntegralType , Values ... > >::Value > , typename _Permutation< Pack< IntegralType , Values ... > , typename PPack::Rest >::type > type; + }; + template< typename IntegralType , IntegralType ... Values > + struct _Permutation< Pack< IntegralType , Values ... > , Pack< unsigned int > > + { + typedef Pack< IntegralType > type; + }; + + //////////////////// + // _IsotropicPack // + //////////////////// + template< typename IntegralType , unsigned int Dim , IntegralType Value > struct _IsotropicPack { typedef typename _IsotropicPack< IntegralType , Dim-1 , Value >::type::template Append< Value > type; }; + template< typename IntegralType , IntegralType Value > struct _IsotropicPack< IntegralType , 1 , Value >{ typedef Pack< IntegralType , Value > type; }; + template< typename IntegralType , IntegralType Value > struct _IsotropicPack< IntegralType , 0 , Value >{ typedef Pack< IntegralType > type; }; + + ///////////////////// + // _SequentialPack // + ///////////////////// + template< typename IntegralType , unsigned int Dim , IntegralType Value > struct _SequentialPack { typedef Concatenation< Pack< IntegralType , Value > , typename _SequentialPack< IntegralType , Dim-1 , Value+1 >::type > type; }; + template< typename IntegralType , IntegralType Value > struct _SequentialPack< IntegralType , 0 , Value >{ typedef Pack< IntegralType > type; }; +} +#endif // PARAMETER_PACK_INCLUDED diff --git a/Src/Ply.inl b/Src/Ply.inl index 0f6a0277..99dba468 100644 --- a/Src/Ply.inl +++ b/Src/Ply.inl @@ -38,7 +38,7 @@ namespace PLY template<> inline int Type< double >( void ){ return PLY_DOUBLE; } template< class Scalar > inline int Type( void ) { - ERROR_OUT( "Unrecognized scalar type: " , typeid(Scalar).name() ); + MK_ERROR_OUT( "Unrecognized scalar type: " , typeid(Scalar).name() ); return -1; } @@ -70,7 +70,7 @@ namespace PLY float version; PlyFile *ply = PlyFile::Read( fileName , elist , fileType , version ); - if( !ply ) ERROR_OUT( "Could not open ply file for reading: " , fileName ); + if( !ply ) MK_ERROR_OUT( "Could not open ply file for reading: " , fileName ); elems.resize( elist.size() ); for( unsigned int i=0 ; i( elems[i] ); ply = PlyFile::Write( fileName , elist , fileType , version ); } - if( !ply ) ERROR_OUT( "Could not open ply for writing: " , fileName ); + if( !ply ) MK_ERROR_OUT( "Could not open ply for writing: " , fileName ); for( unsigned int i=0 ; ielement_count( std::get<0>( elems[i] ) , std::get<1>( elems[i] ) ); @@ -128,7 +128,7 @@ namespace PLY float version; PlyFile *ply = PlyFile::Read( fileName , elist , fileType , version ); - if( !ply ) THROW( "could not create read ply file: " , fileName ); + if( !ply ) MK_THROW( "could not create read ply file: " , fileName ); for( int i=0 ; i<(int)elist.size() ; i++ ) if( elist[i]=="vertex" ) for( unsigned int j=0 ; j plist = ply->get_element_description( "vertex" , vNum ); - if( !plist.size() ) ERROR_OUT( "Failed to get element description: vertex" ); + if( !plist.size() ) MK_ERROR_OUT( "Failed to get element description: vertex" ); for( unsigned int i=0 ; i plist = ply->get_element_description( "vertex" , vNum ); for( int i=0 ; icomments.size() ); for( int i=0 ; icomments.size() ; i++ ) comments.push_back( ply->comments[i] ); @@ -212,7 +212,7 @@ namespace PLY std::string &elem_name = elist[i]; size_t num_elems; std::vector< PlyProperty > plist = ply->get_element_description( elem_name , num_elems ); - if( !plist.size() ) ERROR_OUT( "Could not read element properties: " , elem_name ); + if( !plist.size() ) MK_ERROR_OUT( "Could not read element properties: " , elem_name ); if( elem_name=="vertex" ) { for( unsigned int i=0 ; icomments.size() ); for( int i=0 ; icomments.size() ; i++ ) comments.push_back( ply->comments[i] ); @@ -270,7 +270,7 @@ namespace PLY std::string &elem_name = elist[i]; size_t num_elems; std::vector< PlyProperty > plist = ply->get_element_description( elem_name , num_elems ); - if( !plist.size() ) ERROR_OUT( "Could not read element properties: " , elem_name ); + if( !plist.size() ) MK_ERROR_OUT( "Could not read element properties: " , elem_name ); if( elem_name=="vertex" ) { for( unsigned int i=0 ; i elem_names = { std::string( "vertex" ) , std::string( "face" ) }; PlyFile *ply = PlyFile::Write( fileName , elem_names , file_type , version ); - if( !ply ) ERROR_OUT( "Could not create ply file for writing: " , fileName ); + if( !ply ) MK_ERROR_OUT( "Could not create ply file for writing: " , fileName ); // // describe vertex and face properties @@ -381,14 +381,14 @@ namespace PLY { if( vertexNum>(size_t)std::numeric_limits< OutputIndex >::max() ) { - if( std::is_same< Index , OutputIndex >::value ) ERROR_OUT( "more vertices than can be represented using " , Traits< Index >::name ); - WARN( "more vertices than can be represented using " , Traits< OutputIndex >::name , " using " , Traits< Index >::name , " instead" ); + if( std::is_same< Index , OutputIndex >::value ) MK_ERROR_OUT( "more vertices than can be represented using " , Traits< Index >::name ); + MK_WARN( "more vertices than can be represented using " , Traits< OutputIndex >::name , " using " , Traits< Index >::name , " instead" ); return Write< VertexFactory , Index , Real , Dim , Index >( fileName , vFactory , vertexNum , polygonNum , vertexStream , polygonStream , file_type , comments ); } float version; std::vector< std::string > elem_names = { std::string( "vertex" ) , std::string( "face" ) }; PlyFile *ply = PlyFile::Write( fileName , elem_names , file_type , version ); - if( !ply ) ERROR_OUT( "Could not create ply file for writing: " , fileName ); + if( !ply ) MK_ERROR_OUT( "Could not create ply file for writing: " , fileName ); vertexStream.reset(); polygonStream.reset(); @@ -416,7 +416,7 @@ namespace PLY for( size_t i=0; iput_element( (void *)&vertex ); } } @@ -426,7 +426,7 @@ namespace PLY for( size_t i=0; iput_element( PointerAddress( buffer ) ); } @@ -442,7 +442,7 @@ namespace PLY // create and fill a struct that the ply code can handle // Face< OutputIndex > ply_face; - if( !polygonStream.read( polygon ) ) ERROR_OUT( "Failed to read polygon " , i , " / " , polygonNum ); + if( !polygonStream.read( polygon ) ) MK_ERROR_OUT( "Failed to read polygon " , i , " / " , polygonNum ); ply_face.nr_vertices = int( polygon.size() ); ply_face.vertices = new OutputIndex[ polygon.size() ]; for( int j=0 ; j(size_t)std::numeric_limits< OutputIndex >::max() ) { - if( std::is_same< Index , OutputIndex >::value ) ERROR_OUT( "more vertices than can be represented using " , Traits< Index >::name ); - WARN( "more vertices than can be represented using " , Traits< OutputIndex >::name , " using " , Traits< Index >::name , " instead" ); + if( std::is_same< Index , OutputIndex >::value ) MK_ERROR_OUT( "more vertices than can be represented using " , Traits< Index >::name ); + MK_WARN( "more vertices than can be represented using " , Traits< OutputIndex >::name , " using " , Traits< Index >::name , " instead" ); return Write< VertexFactory , Index , Real , Dim , Index >( fileName , vFactory , vertexNum , edgeNum , vertexStream , edgeStream , file_type , comments ); } float version; std::vector< std::string > elem_names = { std::string( "vertex" ) , std::string( "edge" ) }; PlyFile *ply = PlyFile::Write( fileName , elem_names , file_type , version ); - if( !ply ) ERROR_OUT( "Could not create ply file for writing: " , fileName ); + if( !ply ) MK_ERROR_OUT( "Could not create ply file for writing: " , fileName ); vertexStream.reset(); edgeStream.reset(); @@ -495,7 +495,7 @@ namespace PLY for( size_t i=0; iput_element( (void *)&vertex ); } } @@ -505,7 +505,7 @@ namespace PLY for( size_t i=0; iput_element( PointerAddress( buffer ) ); } @@ -521,7 +521,7 @@ namespace PLY // create and fill a struct that the ply code can handle // Edge< OutputIndex > ply_edge; - if( !edgeStream.read( edge ) ) ERROR_OUT( "Failed to read edge " , i , " / " , edgeNum ); + if( !edgeStream.read( edge ) ) MK_ERROR_OUT( "Failed to read edge " , i , " / " , edgeNum ); ply_edge.v1 = (OutputIndex)edge.first; ply_edge.v2 = (OutputIndex)edge.second; ply->put_element( (void *)&ply_edge ); diff --git a/Src/PlyFile.h b/Src/PlyFile.h index e1654d92..0c712d59 100644 --- a/Src/PlyFile.h +++ b/Src/PlyFile.h @@ -155,13 +155,13 @@ namespace PoissonRecon } void read( BinaryStream &stream ) { - if( !stream.read( name ) ) ERROR_OUT( "Failed to read name" ); - if( !stream.read( external_type ) ) ERROR_OUT( "Failed to read external_type" ); - if( !stream.read( offset ) ) ERROR_OUT( "Failed to read offset" ); - if( !stream.read( is_list ) ) ERROR_OUT( "Failed to read is_list" ); - if( !stream.read( count_external ) ) ERROR_OUT( "Failed to read count_external" ); - if( !stream.read( count_internal ) ) ERROR_OUT( "Failed to read count_internal" ); - if( !stream.read( count_offset ) ) ERROR_OUT( "Failed to read count_offset" ); + if( !stream.read( name ) ) MK_ERROR_OUT( "Failed to read name" ); + if( !stream.read( external_type ) ) MK_ERROR_OUT( "Failed to read external_type" ); + if( !stream.read( offset ) ) MK_ERROR_OUT( "Failed to read offset" ); + if( !stream.read( is_list ) ) MK_ERROR_OUT( "Failed to read is_list" ); + if( !stream.read( count_external ) ) MK_ERROR_OUT( "Failed to read count_external" ); + if( !stream.read( count_internal ) ) MK_ERROR_OUT( "Failed to read count_internal" ); + if( !stream.read( count_offset ) ) MK_ERROR_OUT( "Failed to read count_offset" ); } }; diff --git a/Src/PlyFile.inl b/Src/PlyFile.inl index a47a1ae5..6e449c9d 100644 --- a/Src/PlyFile.inl +++ b/Src/PlyFile.inl @@ -246,7 +246,7 @@ void PlyFile::describe_element( const std::string &elem_name , size_t nelems , i { /* look for appropriate element */ PlyElement *elem = find_element( elem_name ); - if( elem==NULL ) ERROR_OUT( "Can't find element '" , elem_name , "'" ); + if( elem==NULL ) MK_ERROR_OUT( "Can't find element '" , elem_name , "'" ); elem->num = nelems; @@ -270,7 +270,7 @@ void PlyFile::describe_property( const std::string &elem_name , const PlyPropert PlyElement *elem = find_element( elem_name ); if( elem == NULL ) { - WARN( "Can't find element '" , elem_name , "'" ); + MK_WARN( "Can't find element '" , elem_name , "'" ); return; } @@ -289,7 +289,7 @@ void PlyFile::describe_other_properties( const PlyOtherProp &other , int offset PlyElement *elem = find_element( other.name ); if( elem==NULL ) { - WARN( "Can't find element '" , other.name , "'" ); + MK_WARN( "Can't find element '" , other.name , "'" ); return; } @@ -313,7 +313,7 @@ void PlyFile::element_count( const std::string &elem_name , size_t nelems ) { /* look for appropriate element */ PlyElement *elem = find_element( elem_name ); - if( elem==NULL ) ERROR_OUT( "Can't find element '" , elem_name , "'" ); + if( elem==NULL ) MK_ERROR_OUT( "Can't find element '" , elem_name , "'" ); elem->num = nelems; } @@ -332,7 +332,7 @@ void PlyFile::header_complete( void ) case PLY_ASCII: fprintf( fp , "format ascii 1.0\n" ) ; break; case PLY_BINARY_BE: fprintf( fp , "format binary_big_endian 1.0\n" ) ; break; case PLY_BINARY_LE: fprintf( fp , "format binary_little_endian 1.0\n" ) ; break; - default: ERROR_OUT( "Bad file type: " , file_type ); + default: MK_ERROR_OUT( "Bad file type: " , file_type ); } /* write out the comments */ @@ -380,7 +380,7 @@ elem_name - name of element we're talking about void PlyFile::put_element_setup( const std::string &elem_name ) { PlyElement *elem = find_element( elem_name ); - if( elem==NULL ) ERROR_OUT( "Can't find element '" , elem_name , "'" ); + if( elem==NULL ) MK_ERROR_OUT( "Can't find element '" , elem_name , "'" ); which_elem = elem; } @@ -663,7 +663,7 @@ void PlyFile::get_element_setup( const std::string &elem_name , int nprops , Ply PlyProperty *prop = elem->find_property( prop_list[i].name , index ); if( prop==NULL ) { - WARN( "Can't find property '" , prop_list[i].name , "' in element '" , elem_name , "'" ); + MK_WARN( "Can't find property '" , prop_list[i].name , "' in element '" , elem_name , "'" ); continue; } @@ -830,7 +830,7 @@ bool PlyFile::set_other_properties( const std::string &elem_name , int offset , PlyElement *elem = find_element( elem_name ); if( elem==NULL ) { - WARN( "Can't find element '" , elem_name , "'" ); + MK_WARN( "Can't find element '" , elem_name , "'" ); return false; } @@ -876,7 +876,7 @@ PlyOtherElems *PlyFile::get_other_element( std::string &elem_name , size_t elem_ { /* look for appropriate element */ PlyElement *elem = find_element( elem_name ); - if( elem==NULL ) ERROR_OUT( "Can't find element '" , elem_name , "'" ); + if( elem==NULL ) MK_ERROR_OUT( "Can't find element '" , elem_name , "'" ); if( other_elems==NULL ) other_elems = new PlyOtherElems(); other_elems->other_list.resize( other_elems->other_list.size()+1 ); @@ -1053,7 +1053,7 @@ void PlyFile::_ascii_get_element( void *elem_ptr ) /* read in the element */ words = get_words( fp , &orig_line ); - if( !words.size() ) ERROR_OUT( "Unexpected end of file" ); + if( !words.size() ) MK_ERROR_OUT( "Unexpected end of file" ); which_word = 0; @@ -1232,7 +1232,7 @@ code - code for type void write_scalar_type( FILE *fp , int code ) { /* make sure this is a valid code */ - if( code<=PLY_START_TYPE || code>=PLY_END_TYPE ) ERROR_OUT( "Bad data code: " , code ); + if( code<=PLY_START_TYPE || code>=PLY_END_TYPE ) MK_ERROR_OUT( "Bad data code: " , code ); /* write the code to a file */ fprintf( fp , "%s" , type_names[code] ); @@ -1276,7 +1276,7 @@ void get_native_binary_type( void ) test.int_value = 1; if ( test.byte_values[0]==1 ) native_binary_type = PLY_BINARY_LE; else if( test.byte_values[sizeof(int)-1] == 1) native_binary_type = PLY_BINARY_BE; - else ERROR_OUT( "Couldn't determine machine endianness" ); + else MK_ERROR_OUT( "Couldn't determine machine endianness" ); } /****************************************************************************** @@ -1297,7 +1297,7 @@ void check_types() (ply_type_size[PLY_ULONGLONG] != sizeof(unsigned long long)) || (ply_type_size[PLY_FLOAT] != sizeof(float)) || (ply_type_size[PLY_DOUBLE] != sizeof(double))) - ERROR_OUT( "Type sizes do not match built-in types" ); + MK_ERROR_OUT( "Type sizes do not match built-in types" ); types_checked = 1; } @@ -1422,7 +1422,7 @@ double get_item_value( const void *item , int type ) case PLY_FLOAT_32: return (double)*(const float *)item; case PLY_DOUBLE: case PLY_FLOAT_64: return (double)*(const double *)item; - default: ERROR_OUT( "Bad type: " , type ); + default: MK_ERROR_OUT( "Bad type: " , type ); } return 0; } @@ -1494,12 +1494,12 @@ void write_binary_item( FILE *fp , int file_type , int int_val , unsigned int ui case PLY_FLOAT_64: value = &double_val; break; - default: ERROR_OUT( "Bad type: " , type ); + default: MK_ERROR_OUT( "Bad type: " , type ); } if( (file_type!=native_binary_type) && (ply_type_size[type]>1) ) swap_bytes( (char *)value , ply_type_size[type] ); - if( fwrite( value , ply_type_size[type] , 1 , fp )!=1 ) ERROR_OUT( "Failed to write binary item" ); + if( fwrite( value , ply_type_size[type] , 1 , fp )!=1 ) MK_ERROR_OUT( "Failed to write binary item" ); } @@ -1524,11 +1524,11 @@ void write_ascii_item( FILE *fp , int int_val , unsigned int uint_val , long lon case PLY_INT_16: case PLY_INT: case PLY_INT_32: - if( fprintf( fp , "%d " , int_val )<=0 ) ERROR_OUT( "fprintf() failed -- aborting" ); + if( fprintf( fp , "%d " , int_val )<=0 ) MK_ERROR_OUT( "fprintf() failed -- aborting" ); break; case PLY_LONGLONG: case PLY_INT_64: - if( fprintf( fp , "%lld " , longlong_val )<=0 ) ERROR_OUT( "fprintf() failed -- aborting" ); + if( fprintf( fp , "%lld " , longlong_val )<=0 ) MK_ERROR_OUT( "fprintf() failed -- aborting" ); break; case PLY_UCHAR: case PLY_UINT_8: @@ -1536,19 +1536,19 @@ void write_ascii_item( FILE *fp , int int_val , unsigned int uint_val , long lon case PLY_UINT_16: case PLY_UINT: case PLY_UINT_32: - if( fprintf( fp , "%u " , uint_val )<=0 ) ERROR_OUT( "fprintf() failed -- aborting" ); + if( fprintf( fp , "%u " , uint_val )<=0 ) MK_ERROR_OUT( "fprintf() failed -- aborting" ); break; case PLY_ULONGLONG: case PLY_UINT_64: - if( fprintf( fp , "%llu " , ulonglong_val )<=0 ) ERROR_OUT( "fprintf() failed -- aborting" ); + if( fprintf( fp , "%llu " , ulonglong_val )<=0 ) MK_ERROR_OUT( "fprintf() failed -- aborting" ); break; case PLY_FLOAT: case PLY_FLOAT_32: case PLY_DOUBLE: case PLY_FLOAT_64: - if( fprintf( fp , "%g " , double_val )<=0 ) ERROR_OUT( "fprintf() failed -- aborting" ); + if( fprintf( fp , "%g " , double_val )<=0 ) MK_ERROR_OUT( "fprintf() failed -- aborting" ); break; - default: ERROR_OUT( "Bad type: " , type ); + default: MK_ERROR_OUT( "Bad type: " , type ); } } @@ -1650,7 +1650,7 @@ void get_stored_item( void *ptr , int type , int &int_val , unsigned int &uint_v longlong_val = (long long)double_val; ulonglong_val = (unsigned long long)double_val; break; - default: ERROR_OUT( "Bad type: " , type ); + default: MK_ERROR_OUT( "Bad type: " , type ); } } @@ -1675,7 +1675,7 @@ void get_binary_item( FILE *fp , int file_type , int type , int &int_val , unsig ptr = ( void * )c; - if( fread( ptr , ply_type_size[type] , 1 , fp )!=1 ) ERROR_OUT( "fread() failed -- aborting: " , std::string( type_names[type] ) ); + if( fread( ptr , ply_type_size[type] , 1 , fp )!=1 ) MK_ERROR_OUT( "fread() failed -- aborting: " , std::string( type_names[type] ) ); if( ( file_type!=native_binary_type ) && ( ply_type_size[type]>1 ) ) swap_bytes( (char *)ptr , ply_type_size[type] ); switch( type ) @@ -1760,7 +1760,7 @@ void get_binary_item( FILE *fp , int file_type , int type , int &int_val , unsig longlong_val = (long long)double_val; ulonglong_val = (unsigned long long)int_val; break; - default: ERROR_OUT( "Bad type: " , type ); + default: MK_ERROR_OUT( "Bad type: " , type ); } } @@ -1832,7 +1832,7 @@ void get_ascii_item( const std::string &word , int type , int &int_val , unsigne longlong_val = (long long)double_val; ulonglong_val = (unsigned long long)double_val; break; - default: ERROR_OUT( "Bad type: " , type ); + default: MK_ERROR_OUT( "Bad type: " , type ); } } @@ -1874,7 +1874,7 @@ void store_item( void *item , int type , int int_val , unsigned int uint_val , l case PLY_FLOAT_32: *( float *)item = ( float)double_val ; break; case PLY_DOUBLE: case PLY_FLOAT_64: *( double *)item = ( double)double_val ; break; - default: ERROR_OUT( "Bad type: " , type ); + default: MK_ERROR_OUT( "Bad type: " , type ); } } diff --git a/Src/PointInterpolant.cpp b/Src/PointInterpolant.cpp index 060536f0..66351ac4 100644 --- a/Src/PointInterpolant.cpp +++ b/Src/PointInterpolant.cpp @@ -432,7 +432,7 @@ void WriteGrid( const char *fileName , ConstPointer( Real ) values , unsigned in else if( !strcasecmp( ext , "iso" ) ) { FILE *fp = fopen( fileName , "wb" ); - if( !fp ) ERROR_OUT( "Failed to open file for writing: " , fileName ); + if( !fp ) MK_ERROR_OUT( "Failed to open file for writing: " , fileName ); int r = (int)res; fwrite( &r , sizeof(int) , 1 , fp ); size_t count = 1; @@ -549,7 +549,7 @@ void Execute( UIntPack< FEMSigs ... > ) FILE* fp = fopen( Transform.value , "r" ); if( !fp ) { - WARN( "Could not read x-form from: " , Transform.value ); + MK_WARN( "Could not read x-form from: " , Transform.value ); modelToUnitCube = XForm< Real , Dim+1 >::Identity(); } else @@ -557,7 +557,7 @@ void Execute( UIntPack< FEMSigs ... > ) for( int i=0 ; i ) if( Depth.set && Width.value>0 ) { - WARN( "Both --" , Depth.name , " and --" , Width.name , " set, ignoring --" , Width.name ); + MK_WARN( "Both --" , Depth.name , " and --" , Width.name , " set, ignoring --" , Width.name ); Width.value = 0; } @@ -673,17 +673,17 @@ void Execute( UIntPack< FEMSigs ... > ) if( !SolveDepth.set || SolveDepth.value==-1 ) SolveDepth.value = Depth.value; if( SolveDepth.value>Depth.value ) { - WARN( "Solution depth cannot exceed system depth: " , SolveDepth.value , " <= " , Depth.value ); + MK_WARN( "Solution depth cannot exceed system depth: " , SolveDepth.value , " <= " , Depth.value ); SolveDepth.value = Depth.value; } if( FullDepth.value>Depth.value ) { - WARN( "Full depth cannot exceed system depth: " , FullDepth.value , " <= " , Depth.value ); + MK_WARN( "Full depth cannot exceed system depth: " , FullDepth.value , " <= " , Depth.value ); FullDepth.value = Depth.value; } if( BaseDepth.value>FullDepth.value ) { - if( BaseDepth.set ) WARN( "Base depth must be smaller than full depth: " , BaseDepth.value , " <= " , FullDepth.value ); + if( BaseDepth.set ) MK_WARN( "Base depth must be smaller than full depth: " , BaseDepth.value , " <= " , FullDepth.value ); BaseDepth.value = FullDepth.value; } } @@ -872,7 +872,7 @@ void Execute( UIntPack< FEMSigs ... > ) if( Tree.set ) { FILE* fp = fopen( Tree.value , "wb" ); - if( !fp ) ERROR_OUT( "Failed to open file for writing: " , Tree.value ); + if( !fp ) MK_ERROR_OUT( "Failed to open file for writing: " , Tree.value ); FileStream fs( fp ); FEMTree< Dim , Real >::WriteParameter( fs ); DenseNodeData< Real , Sigs >::WriteSignatures( fs ); @@ -949,7 +949,7 @@ void Execute( void ) case 2: return Execute< Real >( IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BType >::Signature >() ); case 3: return Execute< Real >( IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BType >::Signature >() ); // case 4: return Execute< Real >( IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BType >::Signature >() ); - default: ERROR_OUT( "Only B-Splines of degree 1 - 3 are supported" ); + default: MK_ERROR_OUT( "Only B-Splines of degree 1 - 3 are supported" ); } } @@ -961,7 +961,7 @@ void Execute( void ) case BOUNDARY_FREE+1: return Execute< Dim , Real , BOUNDARY_FREE >(); case BOUNDARY_NEUMANN+1: return Execute< Dim , Real , BOUNDARY_NEUMANN >(); case BOUNDARY_DIRICHLET+1: return Execute< Dim , Real , BOUNDARY_DIRICHLET >(); - default: ERROR_OUT( "Not a valid boundary type: " , BType.value ); + default: MK_ERROR_OUT( "Not a valid boundary type: " , BType.value ); } } #endif // !FAST_COMPILE @@ -970,7 +970,7 @@ int main( int argc , char* argv[] ) { Timer timer; #ifdef ARRAY_DEBUG - WARN( "Array debugging enabled" ); + MK_WARN( "Array debugging enabled" ); #endif // ARRAY_DEBUG CmdLineParse( argc-1 , &argv[1] , params ); @@ -982,30 +982,30 @@ int main( int argc , char* argv[] ) if( !InValues.set && !InGradients.set ) { ShowUsage( argv[0] ); - ERROR_OUT( "Either values or gradients need to be specified" ); + MK_ERROR_OUT( "Either values or gradients need to be specified" ); return 0; } if( !InValues.set ) ValueWeight.value = 0; if( !InGradients.set ) GradientWeight.value = 0; - if( ValueWeight.value<0 ) ERROR_OUT( "Value weight must be non-negative: " , ValueWeight.value , "> 0" ); - if( GradientWeight.value<0 ) ERROR_OUT( "Gradient weight must be non-negative: " , GradientWeight.value , "> 0" ); - if( !ValueWeight.value && !GradientWeight.value ) ERROR_OUT( "Either value or gradient weight must be positive" ); + if( ValueWeight.value<0 ) MK_ERROR_OUT( "Value weight must be non-negative: " , ValueWeight.value , "> 0" ); + if( GradientWeight.value<0 ) MK_ERROR_OUT( "Gradient weight must be non-negative: " , GradientWeight.value , "> 0" ); + if( !ValueWeight.value && !GradientWeight.value ) MK_ERROR_OUT( "Either value or gradient weight must be positive" ); - if( LapWeight.value<0 ) ERROR_OUT( "Laplacian weight must be non-negative: " , LapWeight.value , " > 0" ); - if( BiLapWeight.value<0 ) ERROR_OUT( "Bi-Laplacian weight must be non-negative: " , BiLapWeight.value , " > 0" ); - if( !LapWeight.value && !BiLapWeight.value ) ERROR_OUT( "Eiter Laplacian or bi-Laplacian weight must be positive" ); + if( LapWeight.value<0 ) MK_ERROR_OUT( "Laplacian weight must be non-negative: " , LapWeight.value , " > 0" ); + if( BiLapWeight.value<0 ) MK_ERROR_OUT( "Bi-Laplacian weight must be non-negative: " , BiLapWeight.value , " > 0" ); + if( !LapWeight.value && !BiLapWeight.value ) MK_ERROR_OUT( "Eiter Laplacian or bi-Laplacian weight must be positive" ); if( !BaseDepth.set ) BaseDepth.value = FullDepth.value; if( BaseDepth.value>FullDepth.value ) { - if( BaseDepth.set ) WARN( "Base depth must be smaller than full depth: " , BaseDepth.value , " <= " , FullDepth.value ); + if( BaseDepth.set ) MK_WARN( "Base depth must be smaller than full depth: " , BaseDepth.value , " <= " , FullDepth.value ); BaseDepth.value = FullDepth.value; } if( !SolveDepth.set || SolveDepth.value==-1 ) SolveDepth.value = Depth.value; if( SolveDepth.value>Depth.value ) { - WARN( "Solution depth cannot exceed system depth: " , SolveDepth.value , " <= " , Depth.value ); + MK_WARN( "Solution depth cannot exceed system depth: " , SolveDepth.value , " <= " , Depth.value ); SolveDepth.value = Depth.value; } @@ -1020,12 +1020,12 @@ int main( int argc , char* argv[] ) static const int Degree = DEFAULT_FEM_DEGREE; static const BoundaryType BType = DEFAULT_FEM_BOUNDARY; typedef IsotropicUIntPack< Dimension , FEMDegreeAndBType< Degree , BType >::Signature > FEMSigs; - WARN( "Compiled for degree-" , Degree , ", boundary-" , BoundaryNames[ BType ] , ", " , sizeof(Real)==4 ? "single" : "double" , "-precision _only_" ); + MK_WARN( "Compiled for degree-" , Degree , ", boundary-" , BoundaryNames[ BType ] , ", " , sizeof(Real)==4 ? "single" : "double" , "-precision _only_" ); Execute< Real >( FEMSigs() ); #else // !FAST_COMPILE if ( Dimension.value==2 ) Execute< 2 , Real >(); else if( Dimension.value==3 ) Execute< 3 , Real >(); - else ERROR_OUT( "Only Degrees 2 and 3 are supported" ); + else MK_ERROR_OUT( "Only Degrees 2 and 3 are supported" ); #endif // FAST_COMPILE if( Performance.set ) { diff --git a/Src/PointPartition.inl b/Src/PointPartition.inl index cab02b5b..fd343dd2 100644 --- a/Src/PointPartition.inl +++ b/Src/PointPartition.inl @@ -41,7 +41,7 @@ std::string FileDir( std::string dir , std::string header , unsigned int clientI std::string FileName( std::string dir , unsigned int slab , unsigned int slabs , unsigned int filesPerDir ) { - if( filesPerDir<=1 ) ERROR_OUT( "Need at least two files per directory" ); + if( filesPerDir<=1 ) MK_ERROR_OUT( "Need at least two files per directory" ); if( !dir.length() ) dir = std::string( "." ); if( dir.back()!=FileSeparator ) dir.push_back( FileSeparator ); @@ -95,16 +95,16 @@ PointSetInfo< Real , Dim >::PointSetInfo( unsigned int slabs ) : modelToUnitCube template< typename Real , unsigned int Dim > PointSetInfo< Real , Dim >::PointSetInfo( BinaryStream &stream ) { - if( !stream.read( header ) ) ERROR_OUT( "Failed to read header" ); - if( !stream.read( modelToUnitCube ) ) ERROR_OUT( "Failed to read model-to-unit-cube transform" ); - if( !stream.read( pointsPerSlab ) ) ERROR_OUT( "Failed to read points-per-slab" ); + if( !stream.read( header ) ) MK_ERROR_OUT( "Failed to read header" ); + if( !stream.read( modelToUnitCube ) ) MK_ERROR_OUT( "Failed to read model-to-unit-cube transform" ); + if( !stream.read( pointsPerSlab ) ) MK_ERROR_OUT( "Failed to read points-per-slab" ); { size_t sz; - if( !stream.read( sz ) ) ERROR_OUT( "Failed to read number of auxiliary properties" ); + if( !stream.read( sz ) ) MK_ERROR_OUT( "Failed to read number of auxiliary properties" ); auxiliaryProperties.resize(sz); for( size_t i=0 ; i @@ -124,12 +124,12 @@ void PointSetInfo< Real , Dim >::write( BinaryStream &stream ) const void RemovePointSlabDirs( std::string dir ){ std::filesystem::remove_all( dir ); } void CreatePointSlabDirs( std::string dir , unsigned int count , unsigned int filesPerDir ) { - if( filesPerDir<=1 ) ERROR_OUT( "Need at least two files per directory" ); + if( filesPerDir<=1 ) MK_ERROR_OUT( "Need at least two files per directory" ); if( !dir.length() ) dir = std::string( "." ); if( dir.back()!=FileSeparator ) dir += std::string(1,FileSeparator); try{ std::filesystem::create_directories( dir ); } - catch( ... ){ ERROR_OUT( "Failed to create directory: " , dir ); } + catch( ... ){ MK_ERROR_OUT( "Failed to create directory: " , dir ); } unsigned int depth = 0; { @@ -155,7 +155,7 @@ void CreatePointSlabDirs( std::string dir , unsigned int count , unsigned int fi sStream << dir << i << FileSeparator; std::string _dir = sStream.str(); try{ std::filesystem::create_directories( _dir ); } - catch( ... ){ ERROR_OUT( "Failed to create directory: " , _dir ); } + catch( ... ){ MK_ERROR_OUT( "Failed to create directory: " , _dir ); } MakeDirs( _dir , std::min< unsigned int >( count-(i*_filesPerDir) , _filesPerDir ) , depth-1 , filesPerDir ); } } @@ -258,7 +258,7 @@ protected: } } } - if( minIndex==-1 ) ERROR_OUT( "Could not find a solution: [ " , start , " , " , end , " ) " , interiorBoundaries ); + if( minIndex==-1 ) MK_ERROR_OUT( "Could not find a solution: [ " , start , " , " , end , " ) " , interiorBoundaries ); _solutions[start][end][interiorBoundaries].e = minEnergy; _solutions[start][end][interiorBoundaries].idx = minIndex; return minEnergy; @@ -361,7 +361,7 @@ size_t Partition::size( unsigned int i ) const size_t Partition::size( unsigned int i , unsigned int padSize ) const #endif // ADAPTIVE_PADDING { - if( i>_starts.size() ) ERROR_OUT( "Index out of bounds: 0 <= " , i , " <= " , _starts.size() ); + if( i>_starts.size() ) MK_ERROR_OUT( "Index out of bounds: 0 <= " , i , " <= " , _starts.size() ); #ifdef ADAPTIVE_PADDING std::pair< unsigned int , unsigned int > r = range( i ); #else // !ADAPTIVE_PADDING @@ -448,7 +448,7 @@ unsigned int Partition::partitions( void ) const{ return (unsigned int)_starts.s long ReadPLYProperties( FILE *fp , std::vector< PlyProperty > &properties ) { size_t sz; - if( fread( &sz , sizeof( size_t ) , 1 , fp )!=1 ) ERROR_OUT( "Failed to read property size" ); + if( fread( &sz , sizeof( size_t ) , 1 , fp )!=1 ) MK_ERROR_OUT( "Failed to read property size" ); properties.resize( sz ); FileStream fs(fp); for( size_t i=0 ; i &properties ) long ReadPLYProperties( const char *fileName , std::vector< PlyProperty > &properties ) { FILE *fp = fopen( fileName , "rb" ); - if( !fp ) ERROR_OUT( "Could not open file for reading: " , fileName ); + if( !fp ) MK_ERROR_OUT( "Could not open file for reading: " , fileName ); long pos = ReadPLYProperties( fp , properties ); fclose( fp ); return pos; @@ -476,7 +476,7 @@ long WritePLYProperties( FILE *fp , const std::vector< PlyProperty > &properties long WritePLYProperties( const char *fileName , const std::vector< PlyProperty > &properties ) { FILE *fp = fopen( fileName , "wb" ); - if( !fp ) ERROR_OUT( "Could not open file for writing: " , fileName ); + if( !fp ) MK_ERROR_OUT( "Could not open file for writing: " , fileName ); long pos = WritePLYProperties( fp , properties ); fclose( fp ); return pos; @@ -491,13 +491,13 @@ BufferedBinaryInputDataStream< InputFactory >::BufferedBinaryInputDataStream( co if( !_bufferSize ) { - WARN_ONCE( "BufferSize cannot be zero , setting to one" ); + MK_WARN_ONCE( "BufferSize cannot be zero , setting to one" ); _bufferSize = 1; } _elementSize = _factory.bufferSize(); _buffer = AllocPointer< char >( _elementSize*_bufferSize ); _fp = fopen( fileName , "rb" ); - if( !_fp ) ERROR_OUT( "Could not open file for reading: " , fileName ); + if( !_fp ) MK_ERROR_OUT( "Could not open file for reading: " , fileName ); std::vector< PlyProperty > properties; _inset = ReadPLYProperties( _fp , properties ); } @@ -542,13 +542,13 @@ BufferedBinaryOutputDataStream< OutputFactory >::BufferedBinaryOutputDataStream( { if( !_bufferSize ) { - WARN_ONCE( "BufferSize cannot be zero , setting to one" ); + MK_WARN_ONCE( "BufferSize cannot be zero , setting to one" ); _bufferSize = 1; } _elementSize = _factory.bufferSize(); _buffer = AllocPointer< char >( _elementSize*_bufferSize ); _fp = fopen( fileName , "wb" ); - if( !_fp ) ERROR_OUT( "Could not open file for writing: " , fileName ); + if( !_fp ) MK_ERROR_OUT( "Could not open file for writing: " , fileName ); std::vector< PlyProperty > properties( factory.plyWriteNum() ); for( unsigned int i=0 ; i size_t _SampleCount( std::string in , std::vector< PlyProperty > &auxProperties ) { char *ext = GetFileExtension( in.c_str() ); - if( strcasecmp( ext , "ply" ) ) ERROR_OUT( "Only .ply files supported: " , in ); + if( strcasecmp( ext , "ply" ) ) MK_ERROR_OUT( "Only .ply files supported: " , in ); delete[] ext; size_t vNum; @@ -38,9 +38,9 @@ size_t _SampleCount( std::string in , std::vector< PlyProperty > &auxProperties Factory factory; bool *readFlags = new bool[ factory.plyReadNum() ]; int fileType = PLY::ReadVertexHeader( in , factory , readFlags , auxProperties , vNum ); - if( fileType==PLY_ASCII ) ERROR_OUT( "Point set must be in binary format" ); - if( !factory.template plyValidReadProperties<0>( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); - if( !factory.template plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain normals" ); + if( fileType==PLY_ASCII ) MK_ERROR_OUT( "Point set must be in binary format" ); + if( !factory.template plyValidReadProperties<0>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain positions" ); + if( !factory.template plyValidReadProperties<1>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain normals" ); delete[] readFlags; return vNum; } @@ -55,17 +55,17 @@ void _ProcessPLY( std::string in , std::pair< size_t , size_t > range , const Fa int file_type; PlyFile *ply = PlyFile::Read( in , elist , file_type , version ); - if( !ply ) ERROR_OUT( "Could not create ply file for reading: " , in ); - if( file_type==PLY_ASCII ) ERROR_OUT( "Only binary file type supported" ); + if( !ply ) MK_ERROR_OUT( "Could not create ply file for reading: " , in ); + if( file_type==PLY_ASCII ) MK_ERROR_OUT( "Only binary file type supported" ); size_t vCount; std::vector< PlyProperty > plist = ply->get_element_description( std::string( "vertex" ) , vCount ); - if( !plist.size() ) ERROR_OUT( "Could not read element properties: vertex" ); + if( !plist.size() ) MK_ERROR_OUT( "Could not read element properties: vertex" ); if( range.second==-1 ) range.second = vCount; - if( range.first>=range.second ) ERROR_OUT( "Bad Range: [ " , range.first , " , " , range.second , " )" ); + if( range.first>=range.second ) MK_ERROR_OUT( "Bad Range: [ " , range.first , " , " , range.second , " )" ); if( range.second>vCount ) { - WARN( "Max range too large, resetting" ); + MK_WARN( "Max range too large, resetting" ); range.second = vCount; } @@ -157,7 +157,7 @@ std::vector< size_t > _PartitionIntoSlabs( std::string in , std::string dir , st }; _ProcessPLY( in , range , factory , vertexFunctor ); for( unsigned int i=0 ; i std::vector< PlyProperty > _GetUnprocessedProperties( std::string in ) { char *ext = GetFileExtension( in.c_str() ); - if( strcasecmp( ext , "ply" ) ) ERROR_OUT( "Expected .ply file" ); + if( strcasecmp( ext , "ply" ) ) MK_ERROR_OUT( "Expected .ply file" ); delete[] ext; std::vector< PlyProperty > unprocessedProperties; @@ -183,8 +183,8 @@ std::vector< PlyProperty > _GetUnprocessedProperties( std::string in ) Factory factory; bool *readFlags = new bool[ factory.plyReadNum() ]; PLY::ReadVertexHeader( in , factory , readFlags , unprocessedProperties ); - if( !factory.template plyValidReadProperties<0>( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); - if( !factory.template plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain normals" ); + if( !factory.template plyValidReadProperties<0>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain positions" ); + if( !factory.template plyValidReadProperties<1>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain normals" ); delete[] readFlags; } return unprocessedProperties; @@ -258,7 +258,7 @@ std::pair< PointPartition::PointSetInfo< Real , Dim > , PointPartition::Partitio { std::vector< size_t > slabSizes; SocketStream( clientSockets[c] ).read( slabSizes ); - if( slabSizes.size()!=clientPartitionInfo.slabs ) ERROR_OUT( "Unexpected number of slabs: " , slabSizes.size() , " != " , clientPartitionInfo.slabs ); + if( slabSizes.size()!=clientPartitionInfo.slabs ) MK_ERROR_OUT( "Unexpected number of slabs: " , slabSizes.size() , " != " , clientPartitionInfo.slabs ); for( unsigned int i=0 ; i::ClientPartitionInfo( BinaryStream &stream ) b = _b!=0; return true; }; - if( !stream.read( in ) ) ERROR_OUT( "Failed to read in" ); - if( !stream.read( tempDir ) ) ERROR_OUT( "Failed to read temp dir" ); - if( !stream.read( outDir ) ) ERROR_OUT( "Failed to read out dir" ); - if( !stream.read( outHeader ) ) ERROR_OUT( "Failed to read out header" ); - if( !stream.read( slabs ) ) ERROR_OUT( "Failed to read slabs" ); - if( !stream.read( filesPerDir ) ) ERROR_OUT( "Failed to read files per dir" ); - if( !stream.read( bufferSize ) ) ERROR_OUT( "Failed to read buffer size" ); - if( !stream.read( scale ) ) ERROR_OUT( "Failed to read scale" ); - if( !stream.read( clientCount ) ) ERROR_OUT( "Failed to read client count" ); - if( !stream.read( sliceDir ) ) ERROR_OUT( "Failed to read slice direction" ); - if( !ReadBool( verbose ) ) ERROR_OUT( "Failed to read verbose flag" ); + if( !stream.read( in ) ) MK_ERROR_OUT( "Failed to read in" ); + if( !stream.read( tempDir ) ) MK_ERROR_OUT( "Failed to read temp dir" ); + if( !stream.read( outDir ) ) MK_ERROR_OUT( "Failed to read out dir" ); + if( !stream.read( outHeader ) ) MK_ERROR_OUT( "Failed to read out header" ); + if( !stream.read( slabs ) ) MK_ERROR_OUT( "Failed to read slabs" ); + if( !stream.read( filesPerDir ) ) MK_ERROR_OUT( "Failed to read files per dir" ); + if( !stream.read( bufferSize ) ) MK_ERROR_OUT( "Failed to read buffer size" ); + if( !stream.read( scale ) ) MK_ERROR_OUT( "Failed to read scale" ); + if( !stream.read( clientCount ) ) MK_ERROR_OUT( "Failed to read client count" ); + if( !stream.read( sliceDir ) ) MK_ERROR_OUT( "Failed to read slice direction" ); + if( !ReadBool( verbose ) ) MK_ERROR_OUT( "Failed to read verbose flag" ); } template< typename Real > diff --git a/Src/PointsToDisks.cpp b/Src/PointsToDisks.cpp index 4a0af0fe..41fc6c1f 100644 --- a/Src/PointsToDisks.cpp +++ b/Src/PointsToDisks.cpp @@ -125,7 +125,7 @@ int main( int argc , char* argv[] ) if( PointsToKeep.set && Fraction.set ) { - WARN( "One of --" , PointsToKeep.name , " and --" , Fraction.name , " should be set. Using --" , PointsToKeep.name ); + MK_WARN( "One of --" , PointsToKeep.name , " and --" , Fraction.name , " should be set. Using --" , PointsToKeep.name ); Fraction.set = false; } @@ -186,11 +186,11 @@ int main( int argc , char* argv[] ) if( Verbose.set ) std::cout << "Input points: " << vertices.size() << std::endl; if( PointsToKeep.set && PointsToKeep.value>vertices.size() ) { - WARN( "--" , PointsToKeep.name , " value exceeds number of points: " , PointsToKeep.value , " > " , vertices.size() ); + MK_WARN( "--" , PointsToKeep.name , " value exceeds number of points: " , PointsToKeep.value , " > " , vertices.size() ); PointsToKeep.value = (unsigned int)vertices.size(); } - if( !hasNormals ) ERROR_OUT( "Input is not oriented" ); + if( !hasNormals ) MK_ERROR_OUT( "Input is not oriented" ); if( PointsToKeep.set ) { diff --git a/Src/PoissonRecon.client.inl b/Src/PoissonRecon.client.inl index efbbe740..524a555f 100644 --- a/Src/PoissonRecon.client.inl +++ b/Src/PoissonRecon.client.inl @@ -90,7 +90,7 @@ protected: struct BoundaryInfo { - using SliceSigs = typename Sigs::Reverse::Rest::Reverse; + using SliceSigs = typename Sigs::Transpose::Rest::Transpose; FEMTree< Dim-1 , Real > *tree; DenseNodeData< Real , SliceSigs > solution , dSolution; BoundaryInfo( void ) : tree(NULL) {} @@ -441,7 +441,7 @@ size_t Client< Real , Dim , BType , Degree >::_receive1( const ClientReconstruct ClientServerStream< true > serverStream( _serverSocket , _index , clientReconInfo ); serverStream.ioBytes = 0; - if( !serverStream.read( _modelToUnitCube ) ) ERROR_OUT( "Failed to read model-to-unit-cube transform" ); + if( !serverStream.read( _modelToUnitCube ) ) MK_ERROR_OUT( "Failed to read model-to-unit-cube transform" ); serverStream.read( _range ); profiler.update(); @@ -682,7 +682,7 @@ size_t Client< Real , Dim , BType , Degree >::_receive3( const ClientReconstruct { ClientServerStream< true > serverStream( _serverSocket , _index , clientReconInfo ); serverStream.ioBytes = 0; - if( !serverStream.read( cumulativePointWeight ) ) ERROR_OUT( "Could not read cumulative point weight" ); + if( !serverStream.read( cumulativePointWeight ) ) MK_ERROR_OUT( "Could not read cumulative point weight" ); profiler.update(); return serverStream.ioBytes; } @@ -1043,7 +1043,7 @@ std::pair< double , double > Client< Real , Dim , BType , Degree >::_process5( c { if( clientNode->nodeData.nodeIndex!=-1 ) { - if( clientNode->nodeData.nodeIndex>=(node_index_type)clientToServer.size() ) ERROR_OUT( "More client nodes than server nodes" ); + if( clientNode->nodeData.nodeIndex>=(node_index_type)clientToServer.size() ) MK_ERROR_OUT( "More client nodes than server nodes" ); clientToServer[ clientNode->nodeData.nodeIndex ] = serverNode->nodeData.nodeIndex; } if( _tree.depth( clientNode )<(int)clientReconInfo.sharedDepth && clientNode->children ) @@ -1120,8 +1120,8 @@ std::pair< double , double > Client< Real , Dim , BType , Degree >::_process5( c if constexpr( Dim==3 ) { Timer timer; - using SliceSigs = typename Sigs::Reverse::Rest::Reverse; - static const unsigned int CrossSig = Sigs::Reverse::First; + using SliceSigs = typename Sigs::Transpose::Rest::Transpose; + static const unsigned int CrossSig = Sigs::Transpose::First; auto SetBoundary = [&]( unsigned int index , typename _State5::BoundaryInfo &boundaryInfo ) { @@ -1146,7 +1146,7 @@ std::pair< double , double > Client< Real , Dim , BType , Degree >::_process5( c if( clientReconInfo.outDir.length() ) outFileName = PointPartition::FileDir( clientReconInfo.outDir , outFileName ); FILE* fp = fopen( outFileName.c_str() , "wb" ); - if( !fp ) ERROR_OUT( "Failed to open file for writing: " , outFileName ); + if( !fp ) MK_ERROR_OUT( "Failed to open file for writing: " , outFileName ); FileStream fs(fp); FEMTree< Dim , Real >::WriteParameter( fs ); DenseNodeData< Real , Sigs >::WriteSignatures( fs ); @@ -1350,7 +1350,7 @@ Client< Real , Dim , BType , Degree >::Client( const ClientReconstructionInfo< R AuxDataFactory auxDataFactory( clientReconInfo.auxProperties ); bool needAuxData = clientReconInfo.dataX>0 && auxDataFactory.bufferSize(); - if( phase!=3 && phase!=5 && phase!=7 ) ERROR_OUT( "Only phases 3, 5, and 7 supported: " , phase ); + if( phase!=3 && phase!=5 && phase!=7 ) MK_ERROR_OUT( "Only phases 3, 5, and 7 supported: " , phase ); stream.read( _index ); stream.read( _range ); @@ -1366,10 +1366,10 @@ Client< Real , Dim , BType , Degree >::Client( const ClientReconstructionInfo< R std::vector< FEMTreeNode * > nodes( _tree.spaceRoot().nodes() , NULL ); size_t idx = 0; _tree.spaceRoot().processNodes( [&]( FEMTreeNode *node ){ nodes[idx++] = node; } ); -if( idx!=nodes.size() ) ERROR_OUT( "uhoh" ); +if( idx!=nodes.size() ) MK_ERROR_OUT( "uhoh" ); std::vector< T > _samples; - if( !stream.read( _samples ) ) ERROR_OUT( "Failed to read samples" ); + if( !stream.read( _samples ) ) MK_ERROR_OUT( "Failed to read samples" ); samples.resize( _samples.size() ); // Convert indices to node pointers for( size_t i=0 ; i _samples; - if( !stream.read( _samples ) ) ERROR_OUT( "Failed to read samples" ); + if( !stream.read( _samples ) ) MK_ERROR_OUT( "Failed to read samples" ); size_t sz = _samples.size(); SampleDataTypeSerializer< Real , Dim > serializer( clientReconInfo.auxProperties ); samples.resize( sz ); @@ -1397,7 +1397,7 @@ if( idx!=nodes.size() ) ERROR_OUT( "uhoh" ); size_t serializedSize = serializer.size(); { Pointer( char ) buffer = NewPointer< char >( sz * serializedSize ); - if( !stream.read( buffer , sz*serializedSize ) ) ERROR_OUT( "Failed to read sample data" ); + if( !stream.read( buffer , sz*serializedSize ) ) MK_ERROR_OUT( "Failed to read sample data" ); for( unsigned int i=0 ; i::_write( const ClientReconstructionIn AuxDataFactory auxDataFactory( clientReconInfo.auxProperties ); bool needAuxData = clientReconInfo.dataX>0 && auxDataFactory.bufferSize(); - if( phase!=1 && phase!=3 && phase!=5 ) ERROR_OUT( "Only phases 1, 3, and 5 supported: " , phase ); + if( phase!=1 && phase!=3 && phase!=5 ) MK_ERROR_OUT( "Only phases 1, 3, and 5 supported: " , phase ); _tree.write( stream , false ); stream.write( _modelToUnitCube ); diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index e4e992e1..e09b1581 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -355,13 +355,13 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( Transform.set ) { FILE* fp = fopen( Transform.value , "r" ); - if( !fp ) WARN( "Could not read x-form from: " , Transform.value ); + if( !fp ) MK_WARN( "Could not read x-form from: " , Transform.value ); else { for( int i=0 ; i() , envelopeMesh->vertices , polygons , file_type , comments ); envelopeMesh->simplices.resize( polygons.size() ); for( int i=0 ; isimplices[i][j] = polygons[i][j]; } } @@ -499,7 +499,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( Tree.set ) { FILE* fp = fopen( Tree.value , "wb" ); - if( !fp ) ERROR_OUT( "Failed to open file for writing: " , Tree.value ); + if( !fp ) MK_ERROR_OUT( "Failed to open file for writing: " , Tree.value ); FileStream fs(fp); FEMTree< Dim , Real >::WriteParameter( fs ); DenseNodeData< Real , Sigs >::WriteSignatures( fs ); @@ -548,7 +548,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) if constexpr( HasAuxData ) WriteMesh< Real , Dim , FEMSig >( Gradients.set , Density.set , InCore.set , *implicit , meParams , Out.value , ASCII.set , auxDataFactory ); else WriteMesh< Real , Dim , FEMSig >( Gradients.set , Density.set , InCore.set , *implicit , meParams , Out.value , ASCII.set ); } - else WARN( "Mesh extraction is only supported in dimensions 2 and 3" ); + else MK_WARN( "Mesh extraction is only supported in dimensions 2 and 3" ); if( Verbose.set ) std::cout << "# Total Solve: " << Time()-startTime << " (s), " << MemoryInfo::PeakMemoryUsageMB() << " (MB)" << std::endl; delete implicit; @@ -564,7 +564,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) case 2: return Execute< Real , Dim , FEMDegreeAndBType< 2 , BType >::Signature >( auxDataFactory ); // case 3: return Execute< Real , Dim , FEMDegreeAndBType< 3 , BType >::Signature >( auxDataFactory ); // case 4: return Execute< Real , Dim , FEMDegreeAndBType< 4 , BType >::Signature >( auxDataFactory ); - default: ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); + default: MK_ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); } } @@ -576,7 +576,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) case BOUNDARY_FREE+1: return Execute< Dim , Real , BOUNDARY_FREE >( auxDataFactory ); case BOUNDARY_NEUMANN+1: return Execute< Dim , Real , BOUNDARY_NEUMANN >( auxDataFactory ); case BOUNDARY_DIRICHLET+1: return Execute< Dim , Real , BOUNDARY_DIRICHLET >( auxDataFactory ); - default: ERROR_OUT( "Not a valid boundary type: " , BType.value ); + default: MK_ERROR_OUT( "Not a valid boundary type: " , BType.value ); } } #endif // !FAST_COMPILE @@ -585,7 +585,7 @@ int main( int argc , char* argv[] ) { Timer timer; #ifdef ARRAY_DEBUG - WARN( "Array debugging enabled" ); + MK_WARN( "Array debugging enabled" ); #endif // ARRAY_DEBUG CmdLineParse( argc-1 , &argv[1] , params ); if( MaxMemoryGB.value>0 ) SetPeakMemoryMB( MaxMemoryGB.value<<10 ); @@ -610,7 +610,7 @@ int main( int argc , char* argv[] ) static const BoundaryType BType = Reconstructor::Poisson::DefaultFEMBoundary; static const unsigned int Dim = DEFAULT_DIMENSION; static const unsigned int FEMSig = FEMDegreeAndBType< Degree , BType >::Signature; - WARN( "Compiled for degree-" , Degree , ", boundary-" , BoundaryNames[ BType ] , ", " , sizeof(Real)==4 ? "single" : "double" , "-precision _only_" ); + MK_WARN( "Compiled for degree-" , Degree , ", boundary-" , BoundaryNames[ BType ] , ", " , sizeof(Real)==4 ? "single" : "double" , "-precision _only_" ); if( !PointWeight.set ) PointWeight.value = Reconstructor::Poisson::WeightMultiplier*Degree; char *ext = GetFileExtension( In.value ); if( !strcasecmp( ext , "ply" ) ) @@ -620,8 +620,8 @@ int main( int argc , char* argv[] ) bool *readFlags = new bool[ factory.plyReadNum() ]; std::vector< PlyProperty > unprocessedProperties; PLY::ReadVertexHeader( In.value , factory , readFlags , unprocessedProperties ); - if( !factory.template plyValidReadProperties<0>( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); - if( !factory.template plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain normals" ); + if( !factory.template plyValidReadProperties<0>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain positions" ); + if( !factory.template plyValidReadProperties<1>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain normals" ); delete[] readFlags; if( unprocessedProperties.size() ) Execute< Real , Dim , FEMSig >( VertexFactory::DynamicFactory< Real >( unprocessedProperties ) ); @@ -643,8 +643,8 @@ int main( int argc , char* argv[] ) bool *readFlags = new bool[ factory.plyReadNum() ]; std::vector< PlyProperty > unprocessedProperties; PLY::ReadVertexHeader( In.value , factory , readFlags , unprocessedProperties ); - if( !factory.template plyValidReadProperties<0>( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); - if( !factory.template plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain normals" ); + if( !factory.template plyValidReadProperties<0>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain positions" ); + if( !factory.template plyValidReadProperties<1>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain normals" ); delete[] readFlags; if( unprocessedProperties.size() ) Execute< DEFAULT_DIMENSION , Real >( VertexFactory::DynamicFactory< Real >( unprocessedProperties ) ); diff --git a/Src/PoissonRecon.server.inl b/Src/PoissonRecon.server.inl index 5d7ff384..08f39c35 100644 --- a/Src/PoissonRecon.server.inl +++ b/Src/PoissonRecon.server.inl @@ -61,7 +61,7 @@ protected: }; struct _State6 { - using SliceSigs = typename Sigs::Reverse::Rest::Reverse; + using SliceSigs = typename Sigs::Transpose::Rest::Transpose; using Vertex = typename VertexFactory::PositionFactory< Real , Dim-1 >::VertexType; FEMTree< Dim-1 , Real > *sliceTree; XForm< Real , Dim > xForm; @@ -384,7 +384,7 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase4( const ClientReconstruc timer = Timer(); for( unsigned int i=0 ; i<_constraints.size() ; i++ ) - if( clientToServer[i]==-1 || clientToServer[i]>=(node_index_type)state4.constraints.size() ){ WARN_ONCE( "Unmatched client node(s): " , clientToServer[i] ); } + if( clientToServer[i]==-1 || clientToServer[i]>=(node_index_type)state4.constraints.size() ){ MK_WARN_ONCE( "Unmatched client node(s): " , clientToServer[i] ); } else state4.constraints[ clientToServer[i] ] += _constraints[i]; phaseInfo.processTime += timer.wallTime(); } @@ -481,7 +481,7 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase4( const ClientReconstruc if( d<0 ) return true; else if( d>(int)clientReconInfo.sharedDepth ) { - WARN( "Why does the client have fine nodes?" ); + MK_WARN( "Why does the client have fine nodes?" ); return false; } else @@ -570,7 +570,7 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase4( const ClientReconstruc if( clientReconInfo.outDir.length() ) outFileName = PointPartition::FileDir( clientReconInfo.outDir , outFileName ); FILE* fp = fopen( outFileName.c_str() , "wb" ); - if( !fp ) ERROR_OUT( "Failed to open file for writing: " , outFileName ); + if( !fp ) MK_ERROR_OUT( "Failed to open file for writing: " , outFileName ); FileStream fs(fp); FEMTree< Dim , Real >::WriteParameter( fs ); DenseNodeData< Real , Sigs >::WriteSignatures( fs ); @@ -630,7 +630,7 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase6( const ClientReconstruc int res1 = 0 , res2 = 0; Pointer( Real ) values1 = backSliceTree->template regularGridEvaluate< true >( backSolution , res1 , -1 , false ); Pointer( Real ) values2 = frontSliceTree->template regularGridEvaluate< true >( frontSolution , res2 , -1 , false ); - if( res1!=res2 ) ERROR_OUT( "Different resolutions: " , res1 , " != " , res2 ); + if( res1!=res2 ) MK_ERROR_OUT( "Different resolutions: " , res1 , " != " , res2 ); size_t count = 1; for( unsigned int d=0 ; d<(Dim-1) ; d++ ) count *= (unsigned int)res1; discontinuityCount += count; @@ -673,7 +673,7 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase6( const ClientReconstruc auto WriteBoundary = [&]( std::string fileName , const FEMTree< Dim-1 , Real > *sliceTree , const DenseNodeData< Real , SliceSigs > &solution ) { FILE* fp = fopen( fileName.c_str() , "wb" ); - if( !fp ) ERROR_OUT( "Failed to open file for writing: " , fileName ); + if( !fp ) MK_ERROR_OUT( "Failed to open file for writing: " , fileName ); FileStream fs(fp); FEMTree< Dim-1 , Real >::WriteParameter( fs ); DenseNodeData< Real , SliceSigs >::WriteSignatures( fs ); diff --git a/Src/PoissonReconClient.cpp b/Src/PoissonReconClient.cpp index 329ea045..de094658 100644 --- a/Src/PoissonReconClient.cpp +++ b/Src/PoissonReconClient.cpp @@ -119,7 +119,7 @@ void Reconstruct( unsigned int degree , std::vector< Socket > &serverSockets ) { case 1: return Reconstruct< Real , Dim , BType , 1 >( serverSockets ); case 2: return Reconstruct< Real , Dim , BType , 2 >( serverSockets ); - default: ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); + default: MK_ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); } } @@ -131,7 +131,7 @@ void Reconstruct( BoundaryType bType , unsigned int degree , std::vector< Socket case BOUNDARY_FREE: return Reconstruct< Real , Dim , BOUNDARY_FREE >( degree , serverSockets ); case BOUNDARY_NEUMANN: return Reconstruct< Real , Dim , BOUNDARY_NEUMANN >( degree , serverSockets ); case BOUNDARY_DIRICHLET: return Reconstruct< Real , Dim , BOUNDARY_DIRICHLET >( degree , serverSockets ); - default: ERROR_OUT( "Not a valid boundary type: " , bType ); + default: MK_ERROR_OUT( "Not a valid boundary type: " , bType ); } } @@ -142,8 +142,8 @@ void Reconstruct( std::vector< Socket > &serverSockets ) unsigned int degree; for( unsigned int i=0 ; i( bType , degree , serverSockets ); } @@ -153,7 +153,7 @@ void Reconstruct( std::vector< Socket > &serverSockets ) int main( int argc , char* argv[] ) { #ifdef ARRAY_DEBUG - WARN( "Array debugging enabled" ); + MK_WARN( "Array debugging enabled" ); #endif // ARRAY_DEBUG #ifdef USE_DOUBLE typedef double Real; diff --git a/Src/PoissonReconClientServer.inl b/Src/PoissonReconClientServer.inl index fb004f93..efdf3ea9 100644 --- a/Src/PoissonReconClientServer.inl +++ b/Src/PoissonReconClientServer.inl @@ -249,7 +249,7 @@ struct ClientServerStream : BinaryStream tries++; } _fs.open( _fileName , std::ios::in | std::ios::binary ); - if( !_fs.is_open() ) ERROR_OUT( "Failed to open file for reading: " , _fileName ); + if( !_fs.is_open() ) MK_ERROR_OUT( "Failed to open file for reading: " , _fileName ); } else { @@ -266,10 +266,10 @@ struct ClientServerStream : BinaryStream std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) ); tries++; } - if( !validFile( _fileName ) ) ERROR_OUT( "File exists: " , _fileName , " , " , tries , " / " , maxTries ); + if( !validFile( _fileName ) ) MK_ERROR_OUT( "File exists: " , _fileName , " , " , tries , " / " , maxTries ); _fs.open( _fileName , std::ios::out | std::ios::binary ); - if( !_fs.is_open() ) ERROR_OUT( "Failed to open file for writing: " , _fileName ); + if( !_fs.is_open() ) MK_ERROR_OUT( "Failed to open file for writing: " , _fileName ); } } ~ClientServerStream( void ) @@ -345,36 +345,36 @@ ClientReconstructionInfo< Real , Dim >::ClientReconstructionInfo( BinaryStream & b = _b!=0; return true; }; - if( !stream.read( inDir ) ) ERROR_OUT( "Failed to read in dir" ); - if( !stream.read( tempDir ) ) ERROR_OUT( "Failed to read temp dir" ); - if( !stream.read( outDir ) ) ERROR_OUT( "Failed to read out dir" ); - if( !stream.read( header ) ) ERROR_OUT( "Failed to read header" ); - if( !stream.read( bufferSize ) ) ERROR_OUT( "Failed to read buffer size" ); - if( !stream.read( filesPerDir ) ) ERROR_OUT( "Failed to read files per dir" ); - if( !stream.read( reconstructionDepth ) ) ERROR_OUT( "Failed to read reconstruction depth" ); - if( !stream.read( sharedDepth ) ) ERROR_OUT( "Failed to read shared depth" ); - if( !stream.read( distributionDepth ) ) ERROR_OUT( "Failed to read distribution depth" ); - if( !stream.read( baseDepth ) ) ERROR_OUT( "Failed to read base depth" ); - if( !stream.read( kernelDepth ) ) ERROR_OUT( "Failed to read kernel depth" ); - if( !stream.read( solveDepth ) ) ERROR_OUT( "Failed to read solveDepth depth" ); - if( !stream.read( iters ) ) ERROR_OUT( "Failed to read iters" ); - if( !stream.read( cgSolverAccuracy ) ) ERROR_OUT( "Failed to read CG-solver-accuracy" ); - if( !stream.read( targetValue ) ) ERROR_OUT( "Failed to read target-value" ); - if( !stream.read( pointWeight ) ) ERROR_OUT( "Failed to read point-weight" ); - if( !stream.read( samplesPerNode ) ) ERROR_OUT( "Failed to read samples-per-node" ); - if( !stream.read( dataX ) ) ERROR_OUT( "Failed to read data-multiplier" ); - if( !stream.read( padSize ) ) ERROR_OUT( "Failed to read padSize" ); - if( !stream.read( verbose ) ) ERROR_OUT( "Failed to read verbose" ); - if( !stream.read( mergeType ) ) ERROR_OUT( "Failed to read merge-type" ); - if( !ReadBool( density ) ) ERROR_OUT( "Failed to read density flag" ); - if( !ReadBool( linearFit ) ) ERROR_OUT( "Failed to read linear-fit flag" ); - if( !ReadBool( outputSolution ) ) ERROR_OUT( "Failed to read output-solution flag" ); - if( !ReadBool( gridCoordinates ) ) ERROR_OUT( "Failed to read grid-coordinates flag" ); - if( !ReadBool( ouputVoxelGrid ) ) ERROR_OUT( "Failed to read output-voxel-grid flag" ); - if( !ReadBool( confidence ) ) ERROR_OUT( "Failed to read confidence flag" ); + if( !stream.read( inDir ) ) MK_ERROR_OUT( "Failed to read in dir" ); + if( !stream.read( tempDir ) ) MK_ERROR_OUT( "Failed to read temp dir" ); + if( !stream.read( outDir ) ) MK_ERROR_OUT( "Failed to read out dir" ); + if( !stream.read( header ) ) MK_ERROR_OUT( "Failed to read header" ); + if( !stream.read( bufferSize ) ) MK_ERROR_OUT( "Failed to read buffer size" ); + if( !stream.read( filesPerDir ) ) MK_ERROR_OUT( "Failed to read files per dir" ); + if( !stream.read( reconstructionDepth ) ) MK_ERROR_OUT( "Failed to read reconstruction depth" ); + if( !stream.read( sharedDepth ) ) MK_ERROR_OUT( "Failed to read shared depth" ); + if( !stream.read( distributionDepth ) ) MK_ERROR_OUT( "Failed to read distribution depth" ); + if( !stream.read( baseDepth ) ) MK_ERROR_OUT( "Failed to read base depth" ); + if( !stream.read( kernelDepth ) ) MK_ERROR_OUT( "Failed to read kernel depth" ); + if( !stream.read( solveDepth ) ) MK_ERROR_OUT( "Failed to read solveDepth depth" ); + if( !stream.read( iters ) ) MK_ERROR_OUT( "Failed to read iters" ); + if( !stream.read( cgSolverAccuracy ) ) MK_ERROR_OUT( "Failed to read CG-solver-accuracy" ); + if( !stream.read( targetValue ) ) MK_ERROR_OUT( "Failed to read target-value" ); + if( !stream.read( pointWeight ) ) MK_ERROR_OUT( "Failed to read point-weight" ); + if( !stream.read( samplesPerNode ) ) MK_ERROR_OUT( "Failed to read samples-per-node" ); + if( !stream.read( dataX ) ) MK_ERROR_OUT( "Failed to read data-multiplier" ); + if( !stream.read( padSize ) ) MK_ERROR_OUT( "Failed to read padSize" ); + if( !stream.read( verbose ) ) MK_ERROR_OUT( "Failed to read verbose" ); + if( !stream.read( mergeType ) ) MK_ERROR_OUT( "Failed to read merge-type" ); + if( !ReadBool( density ) ) MK_ERROR_OUT( "Failed to read density flag" ); + if( !ReadBool( linearFit ) ) MK_ERROR_OUT( "Failed to read linear-fit flag" ); + if( !ReadBool( outputSolution ) ) MK_ERROR_OUT( "Failed to read output-solution flag" ); + if( !ReadBool( gridCoordinates ) ) MK_ERROR_OUT( "Failed to read grid-coordinates flag" ); + if( !ReadBool( ouputVoxelGrid ) ) MK_ERROR_OUT( "Failed to read output-voxel-grid flag" ); + if( !ReadBool( confidence ) ) MK_ERROR_OUT( "Failed to read confidence flag" ); { size_t sz; - if( !stream.read( sz ) ) ERROR_OUT( "Failed to read number of auxiliary properties" ); + if( !stream.read( sz ) ) MK_ERROR_OUT( "Failed to read number of auxiliary properties" ); auxProperties.resize(sz); for( size_t i=0 ; i::sharedFile( unsigned int idx case BACK: sStream << PointPartition::FileDir( tempDir , header ) << "." << idx << ".back.shared" ; break; case CENTER: sStream << PointPartition::FileDir( tempDir , header ) << "." << idx << ".shared" ; break; case FRONT: sStream << PointPartition::FileDir( tempDir , header ) << "." << idx << ".front.shared" ; break; - default: ERROR_OUT( "Unrecognized share type: " , shareType ); + default: MK_ERROR_OUT( "Unrecognized share type: " , shareType ); } return sStream.str(); } diff --git a/Src/PoissonReconServer.cpp b/Src/PoissonReconServer.cpp index 0723f864..0da5fd29 100644 --- a/Src/PoissonReconServer.cpp +++ b/Src/PoissonReconServer.cpp @@ -280,7 +280,7 @@ std::vector< unsigned int > Reconstruct( unsigned int degree , const PointPartit { case 1: return Reconstruct< Real , Dim , BType , 1 >( pointSetInfo , partition , clientSockets , clientReconInfo ); case 2: return Reconstruct< Real , Dim , BType , 2 >( pointSetInfo , partition , clientSockets , clientReconInfo ); - default: ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); + default: MK_ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); } return std::vector< unsigned int >(); } @@ -298,7 +298,7 @@ std::vector< unsigned int > Reconstruct( BoundaryType bType , unsigned int degre case BOUNDARY_FREE: return Reconstruct< Real , Dim , BOUNDARY_FREE >( degree , pointSetInfo , partition , clientSockets , clientReconInfo ); case BOUNDARY_NEUMANN: return Reconstruct< Real , Dim , BOUNDARY_NEUMANN >( degree , pointSetInfo , partition , clientSockets , clientReconInfo ); case BOUNDARY_DIRICHLET: return Reconstruct< Real , Dim , BOUNDARY_DIRICHLET >( degree , pointSetInfo , partition , clientSockets , clientReconInfo ); - default: ERROR_OUT( "Not a valid boundary type: " , bType ); + default: MK_ERROR_OUT( "Not a valid boundary type: " , bType ); } return std::vector< unsigned int >(); } @@ -371,7 +371,7 @@ void Merge int main( int argc , char* argv[] ) { #ifdef ARRAY_DEBUG - WARN( "Array debugging enabled" ); + MK_WARN( "Array debugging enabled" ); #endif // ARRAY_DEBUG #ifdef USE_DOUBLE typedef double Real; @@ -387,7 +387,7 @@ int main( int argc , char* argv[] ) ShowUsage( argv[0] ); return 0; } - if( PadSize.value<0 ) ERROR_OUT( "Padding size cannot be negative" ); + if( PadSize.value<0 ) MK_ERROR_OUT( "Padding size cannot be negative" ); if( Verbose.value>1 ) { @@ -406,7 +406,7 @@ int main( int argc , char* argv[] ) if( Depth.set && Width.value>0 ) { - WARN( "Both --" , Depth.name , " and --" , Width.name , " set, ignoring --" , Width.name ); + MK_WARN( "Both --" , Depth.name , " and --" , Width.name , " set, ignoring --" , Width.name ); Width.value = 0; } @@ -426,7 +426,7 @@ int main( int argc , char* argv[] ) // Create a listening SOCKET for connecting to server AcceptorSocket listenSocket = GetListenSocket( port ); - if( listenSocket == _INVALID_ACCEPTOR_SOCKET_ ) ERROR_OUT( "Could not create listener socket" ); + if( listenSocket == _INVALID_ACCEPTOR_SOCKET_ ) MK_ERROR_OUT( "Could not create listener socket" ); std::cout << "Server Address: " << address << ":" << port << std::endl; { std::stringstream ss; @@ -511,15 +511,15 @@ int main( int argc , char* argv[] ) clientReconInfo.reconstructionDepth = Depth.value; clientReconInfo.sharedDepth = 0; while( ((size_t)1<clientReconInfo.reconstructionDepth ) ERROR_OUT( "Slab depth cannot exceed reconstruction depth: " , clientReconInfo.sharedDepth , " <= " , clientReconInfo.reconstructionDepth ); + if( clientReconInfo.sharedDepth>clientReconInfo.reconstructionDepth ) MK_ERROR_OUT( "Slab depth cannot exceed reconstruction depth: " , clientReconInfo.sharedDepth , " <= " , clientReconInfo.reconstructionDepth ); if( clientReconInfo.baseDepth>clientReconInfo.sharedDepth ) { - if( BaseDepth.set ) ERROR_OUT( "Base depth cannot exceed shared depth: " , clientReconInfo.baseDepth , " <=" , clientReconInfo.sharedDepth ); + if( BaseDepth.set ) MK_ERROR_OUT( "Base depth cannot exceed shared depth: " , clientReconInfo.baseDepth , " <=" , clientReconInfo.sharedDepth ); else clientReconInfo.baseDepth = clientReconInfo.sharedDepth; } if( !KernelDepth.set ) KernelDepth.value = clientReconInfo.reconstructionDepth-2; @@ -527,19 +527,19 @@ int main( int argc , char* argv[] ) if( clientReconInfo.kernelDepth>clientReconInfo.reconstructionDepth ) { - WARN( "Kernel depth should not exceed depth: " , clientReconInfo.kernelDepth , " <= " , clientReconInfo.reconstructionDepth ); + MK_WARN( "Kernel depth should not exceed depth: " , clientReconInfo.kernelDepth , " <= " , clientReconInfo.reconstructionDepth ); clientReconInfo.kernelDepth = clientReconInfo.reconstructionDepth; } clientReconInfo.solveDepth = ( SolveDepth.set && SolveDepth.value!=-1 ) ? SolveDepth.value : clientReconInfo.reconstructionDepth; if( clientReconInfo.solveDepth>clientReconInfo.reconstructionDepth ) { - WARN( "Solve depth cannot exceed reconstruction depth: " , clientReconInfo.solveDepth , " <= " , clientReconInfo.reconstructionDepth ); + MK_WARN( "Solve depth cannot exceed reconstruction depth: " , clientReconInfo.solveDepth , " <= " , clientReconInfo.reconstructionDepth ); clientReconInfo.solveDepth = clientReconInfo.reconstructionDepth; } if( clientReconInfo.solveDepth= " , clientReconInfo.baseDepth ); + MK_WARN( "Solve depth cannot be smaller than base depth: " , clientReconInfo.solveDepth , " >= " , clientReconInfo.baseDepth ); clientReconInfo.solveDepth = clientReconInfo.baseDepth; } #ifdef FAST_COMPILE diff --git a/Src/Polynomial.inl b/Src/Polynomial.inl index 39e09554..f6842be1 100644 --- a/Src/Polynomial.inl +++ b/Src/Polynomial.inl @@ -296,7 +296,7 @@ inline int Polynomial< 4 >::getSolutions( double c , double* roots , double EPS template< int Degree > int Polynomial::getSolutions( double c , double* roots , double EPS ) const { - ERROR_OUT( "Can't solve polynomial of degree: " , Degree ); + MK_ERROR_OUT( "Can't solve polynomial of degree: " , Degree ); return 0; } diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index c02e770e..c081f957 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -46,7 +46,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "18.60" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "18.70" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth diff --git a/Src/Rasterizer.h b/Src/Rasterizer.h index 046f7816..5b38ae79 100644 --- a/Src/Rasterizer.h +++ b/Src/Rasterizer.h @@ -89,7 +89,7 @@ namespace PoissonRecon { if( lockDepth>maxDepth ) { - WARN( "Lock depth exceeds max depth: " , lockDepth , " > " , maxDepth ); + MK_WARN( "Lock depth exceeds max depth: " , lockDepth , " > " , maxDepth ); lockDepth = maxDepth; } _bitShift = maxDepth - lockDepth; diff --git a/Src/Rasterizer.inl b/Src/Rasterizer.inl index 5fe3374b..18fb11d6 100644 --- a/Src/Rasterizer.inl +++ b/Src/Rasterizer.inl @@ -56,7 +56,7 @@ Rasterizer< Real , Dim >::_RegularGridIndex::_RegularGridIndex( unsigned int max for( int k=1 ; k<=K && !done ; k++ ) if( _RegularGridIndex( depth , simplex[k] )!=idx ) done = true; if( done ) break; } - if( depth==0 ) ERROR_OUT( "Simplex is not in unit cube: " , simplex ); + if( depth==0 ) MK_ERROR_OUT( "Simplex is not in unit cube: " , simplex ); else *this = _RegularGridIndex( depth-1 , simplex[0] ); } @@ -166,7 +166,7 @@ typename Rasterizer< Real , Dim >::template SimplexRasterizationGrid< IndexType if( threadSafety.type==ThreadSafety::MUTEXES ) { - if( threadSafety.lockDepth>depth ) ERROR_OUT( "Lock depth cannot excceed depth: " , threadSafety.lockDepth , " <= " , depth ); + if( threadSafety.lockDepth>depth ) MK_ERROR_OUT( "Lock depth cannot excceed depth: " , threadSafety.lockDepth , " <= " , depth ); _RegularGridMutexes mutexes( threadSafety.lockDepth , depth ); ThreadPool::ParallelFor( 0 , simplicialComplex.size() , [&]( unsigned int t , size_t i ) @@ -269,6 +269,6 @@ typename Rasterizer< Real , Dim >::template SimplexRasterizationGrid< IndexType for( int t=0 ; tdepth ) { - if( solveDepth!=-1 ) WARN( "Solution depth cannot exceed system depth: " , solveDepth , " <= " , depth ); + if( solveDepth!=-1 ) MK_WARN( "Solution depth cannot exceed system depth: " , solveDepth , " <= " , depth ); solveDepth = depth; } if( fullDepth>solveDepth ) { - if( fullDepth!=-1 ) WARN( "Full depth cannot exceed system depth: " , fullDepth , " <= " , solveDepth ); + if( fullDepth!=-1 ) MK_WARN( "Full depth cannot exceed system depth: " , fullDepth , " <= " , solveDepth ); fullDepth = solveDepth; } if( baseDepth>fullDepth ) { - if( baseDepth!=-1 ) WARN( "Base depth must be smaller than full depth: " , baseDepth , " <= " , fullDepth ); + if( baseDepth!=-1 ) MK_WARN( "Base depth must be smaller than full depth: " , baseDepth , " <= " , fullDepth ); baseDepth = fullDepth; } if( kernelDepth==-1 ) kernelDepth = depth>2 ? depth-2 : 0; if( kernelDepth>depth ) { - if( kernelDepth!=-1 ) WARN( "Kernel depth cannot exceed system depth: " , kernelDepth , " <= " , depth ); + if( kernelDepth!=-1 ) MK_WARN( "Kernel depth cannot exceed system depth: " , kernelDepth , " <= " , depth ); kernelDepth = depth; } } @@ -483,12 +483,12 @@ namespace PoissonRecon if( envelopeDepth==-1 ) envelopeDepth = Reconstructor::SolutionParameters< Real >::baseDepth; if( envelopeDepth>Reconstructor::SolutionParameters< Real >::depth ) { - if( envelopeDepth!=-1 ) WARN( "Envelope depth cannot exceed system depth: " , envelopeDepth , " <= " , Reconstructor::SolutionParameters< Real >::depth ); + if( envelopeDepth!=-1 ) MK_WARN( "Envelope depth cannot exceed system depth: " , envelopeDepth , " <= " , Reconstructor::SolutionParameters< Real >::depth ); envelopeDepth = Reconstructor::SolutionParameters< Real >::depth; } if( envelopeDepth::baseDepth ) { - WARN( "Envelope depth cannot be less than base depth: " , envelopeDepth , " >= " , Reconstructor::SolutionParameters< Real >::baseDepth ); + MK_WARN( "Envelope depth cannot be less than base depth: " , envelopeDepth , " >= " , Reconstructor::SolutionParameters< Real >::baseDepth ); envelopeDepth = Reconstructor::SolutionParameters< Real >::baseDepth; } } @@ -615,12 +615,20 @@ namespace PoissonRecon // OutputDataStream< Position< Real , Dim > , Gradient< Real , Dim > , Weight< Real > , AuxData... > // -> OutputDataStream< Position< Real , Dim > , Gradient< Real , Dim > , Weight< Real > , InternalAuxData > OutputDataStreamConverter< typename _VertexTypeConverter::InternalVertexType , typename _VertexTypeConverter::ExternalVertexType > __vertexStream( _vertexStream , _VertexTypeConverter::ConvertX2I ); - typename LevelSetExtractor< Real , Dim , InternalAuxData >::Stats stats = LevelSetExtractor< Real , Dim , InternalAuxData >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , UIntPack< DataSig >() , tree , density , _auxData , solution , isoValue , __vertexStream , faceStream , _zeroAuxData , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); + typename LevelSetExtractor< Real , Dim , InternalAuxData >::Stats stats; + if constexpr( Dim==3 ) + stats = LevelSetExtractor< Real , Dim , InternalAuxData >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , UIntPack< DataSig >() , tree , density , _auxData , solution , isoValue , __vertexStream , faceStream , _zeroAuxData , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); + else if constexpr( Dim==2 ) + stats = LevelSetExtractor< Real , Dim , InternalAuxData >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , UIntPack< DataSig >() , tree , density , _auxData , solution , isoValue , __vertexStream , faceStream , _zeroAuxData , !params.linearFit , params.outputGradients , false ); statsString = stats.toString(); } else { - typename LevelSetExtractor< Real , Dim >::Stats stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , tree , density , solution , isoValue , _vertexStream , faceStream , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); + typename LevelSetExtractor< Real , Dim >::Stats stats; + if constexpr( Dim==3 ) + stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , tree , density , solution , isoValue , _vertexStream , faceStream , !params.linearFit , params.outputGradients , params.forceManifold , params.polygonMesh , false ); + else if constexpr( Dim==2 ) + stats = LevelSetExtractor< Real , Dim >::Extract( Sigs() , UIntPack< Reconstructor::WeightDegree >() , tree , density , solution , isoValue , _vertexStream , faceStream , !params.linearFit , params.outputGradients , false ); statsString = stats.toString(); } @@ -631,7 +639,7 @@ namespace PoissonRecon std::cout << "# Got Faces: " << profiler << std::endl; } } - else WARN( "Extraction only supported for dimensions 2 and 3" ); + else MK_WARN( "Extraction only supported for dimensions 2 and 3" ); } // Implementation of the derived Poisson::Implicit's constructor @@ -643,10 +651,10 @@ namespace PoissonRecon if( params.valueInterpolationWeight<0 ) { - WARN( "Negative value interpolation weight clamped to zero" ); + MK_WARN( "Negative value interpolation weight clamped to zero" ); params.valueInterpolationWeight = 0; } - if( valueInterpolationStream && !params.valueInterpolationWeight ) WARN( "Value interpolation stream provided but interpolation weight is zero" ); + if( valueInterpolationStream && !params.valueInterpolationWeight ) MK_WARN( "Value interpolation stream provided but interpolation weight is zero" ); // The signature for the finite-elements representing the auxiliary data (if it's there) static const unsigned int DataSig = FEMDegreeAndBType< Reconstructor::DataDegree , BOUNDARY_FREE >::Signature; diff --git a/Src/Reconstructors.streams.h b/Src/Reconstructors.streams.h index fd787901..c98923fc 100644 --- a/Src/Reconstructors.streams.h +++ b/Src/Reconstructors.streams.h @@ -197,7 +197,7 @@ namespace PoissonRecon { this->fp = std::tmpfile(); _closeFile = true; - if( !this->fp ) ERROR_OUT( "Failed to open temporary file" ); + if( !this->fp ) MK_ERROR_OUT( "Failed to open temporary file" ); } } ~FileDescription( void ){ if( _closeFile ) fclose(fp); } diff --git a/Src/RegularGrid.inl b/Src/RegularGrid.inl index c281ca9e..230ee33d 100644 --- a/Src/RegularGrid.inl +++ b/Src/RegularGrid.inl @@ -120,7 +120,7 @@ template< typename Real > void RegularGrid< DataType , Dim >::Write( std::string fileName , const unsigned int res[Dim] , ConstPointer( DataType ) values , XForm< Real , Dim+1 > gridToModel ) { FILE *fp = fopen( fileName.c_str() , "wb" ); - if( !fp ) ERROR_OUT( "Failed to open grid file for writing: " , fileName ); + if( !fp ) MK_ERROR_OUT( "Failed to open grid file for writing: " , fileName ); else { // Write the magic number @@ -164,25 +164,25 @@ template< typename Real > void RegularGrid< DataType , Dim >::Read( std::string fileName , unsigned int res[Dim] , Pointer( DataType ) &values , XForm< Real , Dim+1 > &gridToModel ) { FILE *fp = fopen( fileName.c_str() , "rb" ); - if( !fp ) ERROR_OUT( "Failed to open grid file for reading: " , fileName ); + if( !fp ) MK_ERROR_OUT( "Failed to open grid file for reading: " , fileName ); else { // Read the magic number { int dim; - if( fscanf( fp , " G%d " , &dim )!=1 ) ERROR_OUT( "Failed to read magic number: " , fileName ); - if( dim!=Dim ) ERROR_OUT( "Dimensions don't match: " , Dim , " != " , dim ); + if( fscanf( fp , " G%d " , &dim )!=1 ) MK_ERROR_OUT( "Failed to read magic number: " , fileName ); + if( dim!=Dim ) MK_ERROR_OUT( "Dimensions don't match: " , Dim , " != " , dim ); } // Read the data type - if( !RegularGridDataType< DataType >::Read( fp ) ) ERROR_OUT( "Failed to read type" ); + if( !RegularGridDataType< DataType >::Read( fp ) ) MK_ERROR_OUT( "Failed to read type" ); // Read the dimensions { int r; for( int d=0 ; d::Read( std::string fileName , unsigned int re float x; for( int j=0 ; j::Read( std::string fileName , unsigned int re // Read through the end of the line { char line[1024]; - if( !fgets( line , sizeof(line)/sizeof(char) , fp ) ) ERROR_OUT( "Could not read end of line" ); + if( !fgets( line , sizeof(line)/sizeof(char) , fp ) ) MK_ERROR_OUT( "Could not read end of line" ); } values = NewPointer< DataType >( _Resolution(res) ); diff --git a/Src/RegularTree.h b/Src/RegularTree.h index f2d31cf3..6f97328a 100644 --- a/Src/RegularTree.h +++ b/Src/RegularTree.h @@ -38,10 +38,11 @@ DAMAGE. #include "BinaryNode.h" #include "Window.h" #include "MyMiscellany.h" +#include "Array.h" +#include "MyAtomic.h" namespace PoissonRecon { - template< unsigned int Dim , class NodeData , class DepthAndOffsetType > struct RegularTreeNode { @@ -67,6 +68,7 @@ namespace PoissonRecon RegularTreeNode &_root , *_rootParent; int _depth , _offset[Dim]; }; + struct DepthAndOffset { DepthAndOffsetType depth , offset[Dim]; @@ -113,7 +115,7 @@ namespace PoissonRecon bool initChildren( Allocator< RegularTreeNode >* nodeAllocator ) { auto initializer = []( RegularTreeNode & ){}; - return initChildren( nodeAllocator , initializer ); + return this->template initChildren< ThreadSafe >( nodeAllocator , initializer ); } template< bool ThreadSafe , typename Initializer > bool initChildren( Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ) @@ -136,7 +138,7 @@ namespace PoissonRecon template< class MergeFunctor > void merge( RegularTreeNode* node , MergeFunctor& f ); - void depthAndOffset( int& depth , int offset[Dim] ) const; + void depthAndOffset( int& depth , int offset[Dim] ) const; DepthAndOffset depthAndOffset( void ) const; void centerIndex( int index[Dim] ) const; int depth( void ) const; @@ -174,7 +176,7 @@ namespace PoissonRecon void setFullDepth( int maxDepth , Allocator< RegularTreeNode >* nodeAllocator ) { auto initializer = []( RegularTreeNode & ){}; - return setFulDepth( nodeAllocator , initializer ); + return setFullDepth( nodeAllocator , initializer ); } template< typename Initializer > void setFullDepth( int maxDepth , Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ); @@ -200,78 +202,77 @@ namespace PoissonRecon return read( stream , nodeAllocator , initializer ); } - template< typename Initializer > - bool read( const char* fileName , Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ); - template< typename Initializer > - bool read( FILE* fp , Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ); - template< typename Pack > struct Neighbors{}; + template< unsigned int ... Widths > - struct Neighbors< UIntPack< Widths ... > > + struct Neighbors< ParameterPack::UIntPack< Widths ... > > { - typedef StaticWindow< RegularTreeNode* , UIntPack< Widths ... > > Window; - Window neighbors; + using StaticWindow = Window::StaticWindow< RegularTreeNode * , Widths ... >; + StaticWindow neighbors; Neighbors( void ); void clear( void ); }; template< typename Pack > struct ConstNeighbors{}; template< unsigned int ... Widths > - struct ConstNeighbors< UIntPack< Widths ... > > + struct ConstNeighbors< ParameterPack::UIntPack< Widths ... > > { - typedef StaticWindow< const RegularTreeNode* , UIntPack< Widths ... > > Window; - Window neighbors; + using StaticWindow = Window::StaticWindow< const RegularTreeNode * , Widths ... >; + StaticWindow neighbors; ConstNeighbors( void ); void clear( void ); }; template< typename LeftPack , typename RightPack > struct NeighborKey{}; template< unsigned int ... LeftRadii , unsigned int ... RightRadii > - struct NeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > > + struct NeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > > { protected: static_assert( sizeof...(LeftRadii)==sizeof...(RightRadii) , "[ERROR] Left and right radii dimensions don't match" ); - static const unsigned int CenterIndex = WindowIndex< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > , UIntPack< LeftRadii ... > >::Index; int _depth; template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , unsigned int ... _PLeftRadii , unsigned int ... _PRightRadii , unsigned int ... _CLeftRadii , unsigned int ... _CRightRadii > - static unsigned int _NeighborsLoop( UIntPack< _PLeftRadii ... > , UIntPack< _PRightRadii ... > , UIntPack< _CLeftRadii ... > , UIntPack< _CRightRadii ... > , ConstWindowSlice< RegularTreeNode* , UIntPack< ( _PLeftRadii+_PRightRadii+1 ) ... > > pNeighbors , WindowSlice< RegularTreeNode* , UIntPack< ( _CLeftRadii+_CRightRadii+1 ) ... > > cNeighbors , int cIdx , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ); + static unsigned int _NeighborsLoop( ParameterPack::UIntPack< _PLeftRadii ... > , ParameterPack::UIntPack< _PRightRadii ... > , ParameterPack::UIntPack< _CLeftRadii ... > , ParameterPack::UIntPack< _CRightRadii ... > , Window::ConstSlice< RegularTreeNode* , ( _PLeftRadii+_PRightRadii+1 ) ... > pNeighbors , Window::Slice< RegularTreeNode* , ( _CLeftRadii+_CRightRadii+1 ) ... > cNeighbors , int cIdx , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ); template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , unsigned int ... _PLeftRadii , unsigned int ... _PRightRadii , unsigned int ... _CLeftRadii , unsigned int ... _CRightRadii > - static unsigned int _NeighborsLoop( UIntPack< _PLeftRadii ... > , UIntPack< _PRightRadii ... > , UIntPack< _CLeftRadii ... > , UIntPack< _CRightRadii ... > , WindowSlice< RegularTreeNode* , UIntPack< ( _PLeftRadii+_PRightRadii+1 ) ... > > pNeighbors , WindowSlice< RegularTreeNode* , UIntPack< ( _CLeftRadii+_CRightRadii+1 ) ... > > cNeighbors , int cIdx , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ); + static unsigned int _NeighborsLoop( ParameterPack::UIntPack< _PLeftRadii ... > , ParameterPack::UIntPack< _PRightRadii ... > , ParameterPack::UIntPack< _CLeftRadii ... > , ParameterPack::UIntPack< _CRightRadii ... > , Window::Slice< RegularTreeNode* , ( _PLeftRadii+_PRightRadii+1 ) ... > pNeighbors , Window::Slice< RegularTreeNode* , ( _CLeftRadii+_CRightRadii+1 ) ... > cNeighbors , int cIdx , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ); template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , typename PLeft , typename PRight , typename CLeft , typename CRight > struct _Run{}; template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , unsigned int _PLeftRadius , unsigned int ... _PLeftRadii , unsigned int _PRightRadius , unsigned int ... _PRightRadii , unsigned int _CLeftRadius , unsigned int ... _CLeftRadii , unsigned int _CRightRadius , unsigned int ... _CRightRadii > - struct _Run< CreateNodes , ThreadSafe , NodeInitializer , UIntPack< _PLeftRadius , _PLeftRadii ... > , UIntPack< _PRightRadius , _PRightRadii ... > , UIntPack< _CLeftRadius , _CLeftRadii ... > , UIntPack< _CRightRadius , _CRightRadii ... > > + struct _Run< CreateNodes , ThreadSafe , NodeInitializer , ParameterPack::UIntPack< _PLeftRadius , _PLeftRadii ... > , ParameterPack::UIntPack< _PRightRadius , _PRightRadii ... > , ParameterPack::UIntPack< _CLeftRadius , _CLeftRadii ... > , ParameterPack::UIntPack< _CRightRadius , _CRightRadii ... > > { - static unsigned int Run( ConstWindowSlice< RegularTreeNode* , UIntPack< _PLeftRadius+_PRightRadius+1 , ( _PLeftRadii+_PRightRadii+1 ) ... > > pNeighbors , WindowSlice< RegularTreeNode* , UIntPack< _CLeftRadius+_CRightRadius+1 , ( _CLeftRadii+_CRightRadii+1 ) ... > > cNeighbors , int* c , int cornerIndex , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ); + static unsigned int Run( Window::ConstSlice< RegularTreeNode* , _PLeftRadius+_PRightRadius+1 , ( _PLeftRadii+_PRightRadii+1 ) ... > pNeighbors , Window::Slice< RegularTreeNode* , _CLeftRadius+_CRightRadius+1 , ( _CLeftRadii+_CRightRadii+1 ) ... > cNeighbors , int* c , int cornerIndex , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ); }; template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , unsigned int _PLeftRadius , unsigned int _PRightRadius , unsigned int _CLeftRadius , unsigned int _CRightRadius > - struct _Run< CreateNodes , ThreadSafe , NodeInitializer , UIntPack< _PLeftRadius > , UIntPack< _PRightRadius > , UIntPack< _CLeftRadius > , UIntPack< _CRightRadius > > + struct _Run< CreateNodes , ThreadSafe , NodeInitializer , ParameterPack::UIntPack< _PLeftRadius > , ParameterPack::UIntPack< _PRightRadius > , ParameterPack::UIntPack< _CLeftRadius > , ParameterPack::UIntPack< _CRightRadius > > { - static unsigned int Run( ConstWindowSlice< RegularTreeNode* , UIntPack< _PLeftRadius+_PRightRadius+1 > > pNeighbors , WindowSlice< RegularTreeNode* , UIntPack< _CLeftRadius+_CRightRadius+1 > > cNeighbors , int* c , int cornerIndex , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ); + static unsigned int Run( Window::ConstSlice< RegularTreeNode* , _PLeftRadius+_PRightRadius+1 > pNeighbors , Window::Slice< RegularTreeNode* , _CLeftRadius+_CRightRadius+1 > cNeighbors , int* c , int cornerIndex , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ); }; public: - typedef Neighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > > NeighborType; + static const unsigned int CenterIndex = Window::Index< ( LeftRadii + RightRadii + 1 ) ... >::template I< LeftRadii ... >(); + typedef Neighbors< ParameterPack::UIntPack< ( LeftRadii + RightRadii + 1 ) ... > > NeighborType; NeighborType* neighbors; NeighborKey( void ); NeighborKey( const NeighborKey& key ); ~NeighborKey( void ); - int depth( void ) const { return _depth; } + int depth( void ) const { return _depth; } void set( int depth ); + RegularTreeNode *center( unsigned int depth ){ return neighbors[depth].neighbors.data[ CenterIndex ]; } + const RegularTreeNode *center( unsigned int depth ) const { return neighbors[depth].neighbors.data[ CenterIndex ]; } + template< bool CreateNodes , bool ThreadSafe > - typename RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::template Neighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& getNeighbors( RegularTreeNode* node , Allocator< RegularTreeNode >* nodeAllocator ) + typename RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::template Neighbors< ParameterPack::UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& getNeighbors( RegularTreeNode* node , Allocator< RegularTreeNode >* nodeAllocator ) { auto initializer = []( RegularTreeNode & ){}; - return getNeighbors( node , nodeAllocator , initializer ); + return getNeighbors< CreateNodes , ThreadSafe >( node , nodeAllocator , initializer ); } template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer > - typename RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::template Neighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& getNeighbors( RegularTreeNode* node , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &nodeInitializer ); + typename RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::template Neighbors< ParameterPack::UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& getNeighbors( RegularTreeNode* node , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &nodeInitializer ); NeighborType& getNeighbors( const RegularTreeNode* node ) { @@ -280,37 +281,37 @@ namespace PoissonRecon } template< bool CreateNodes , bool ThreadSafe , unsigned int ... _LeftRadii , unsigned int ... _RightRadii > - void getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , RegularTreeNode* node , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors , Allocator< RegularTreeNode >* nodeAllocator ) + void getNeighbors( ParameterPack::UIntPack< _LeftRadii ... > , ParameterPack::UIntPack< _RightRadii ... > , RegularTreeNode* node , Neighbors< ParameterPack::UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors , Allocator< RegularTreeNode >* nodeAllocator ) { auto initializer = []( RegularTreeNode & ){}; - return getNeighbors( UIntPack< _LeftRadii ... >() , UIntPack< _RightRadii ... >() , node , neighbors , nodeAllocator , initializer ); + return getNeighbors( ParameterPack::UIntPack< _LeftRadii ... >() , ParameterPack::UIntPack< _RightRadii ... >() , node , neighbors , nodeAllocator , initializer ); } template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , unsigned int ... _LeftRadii , unsigned int ... _RightRadii > - void getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , RegularTreeNode* node , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ); + void getNeighbors( ParameterPack::UIntPack< _LeftRadii ... > , ParameterPack::UIntPack< _RightRadii ... > , RegularTreeNode* node , Neighbors< ParameterPack::UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ); template< unsigned int ... _LeftRadii , unsigned int ... _RightRadii > - void getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , const RegularTreeNode* node , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors ) + void getNeighbors( ParameterPack::UIntPack< _LeftRadii ... > , ParameterPack::UIntPack< _RightRadii ... > , const RegularTreeNode* node , Neighbors< ParameterPack::UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors ) { auto initializer = []( RegularTreeNode & ){}; - return getNeighbors< false , false >( UIntPack< _LeftRadii ... >() , UIntPack< _RightRadii ... >() , (RegularTreeNode*)node , NULL , initializer ); + return getNeighbors< false , false >( ParameterPack::UIntPack< _LeftRadii ... >() , ParameterPack::UIntPack< _RightRadii ... >() , (RegularTreeNode*)node , NULL , initializer ); } template< bool CreateNodes , bool ThreadSafe , unsigned int ... _LeftRadii , unsigned int ... _RightRadii > - void getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , RegularTreeNode* node , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& pNeighbors , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors , Allocator< RegularTreeNode >* nodeAllocator ) + void getNeighbors( ParameterPack::UIntPack< _LeftRadii ... > , ParameterPack::UIntPack< _RightRadii ... > , RegularTreeNode* node , Neighbors< ParameterPack::UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& pNeighbors , Neighbors< ParameterPack::UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors , Allocator< RegularTreeNode >* nodeAllocator ) { auto initializer = []( RegularTreeNode & ){}; - return getNeighbors( UIntPack< _LeftRadii ... >() , UIntPack< _RightRadii ... >() , node , pNeighbors , neighbors , nodeAllocator , initializer ); + return getNeighbors( ParameterPack::UIntPack< _LeftRadii ... >() , ParameterPack::UIntPack< _RightRadii ... >() , node , pNeighbors , neighbors , nodeAllocator , initializer ); } template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , unsigned int ... _LeftRadii , unsigned int ... _RightRadii > - void getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , RegularTreeNode* node , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& pNeighbors , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ); + void getNeighbors( ParameterPack::UIntPack< _LeftRadii ... > , ParameterPack::UIntPack< _RightRadii ... > , RegularTreeNode* node , Neighbors< ParameterPack::UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& pNeighbors , Neighbors< ParameterPack::UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ); template< unsigned int ... _LeftRadii , unsigned int ... _RightRadii > - void getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , const RegularTreeNode* node , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& pNeighbors , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors ) + void getNeighbors( ParameterPack::UIntPack< _LeftRadii ... > , ParameterPack::UIntPack< _RightRadii ... > , const RegularTreeNode* node , Neighbors< ParameterPack::UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& pNeighbors , Neighbors< ParameterPack::UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors ) { auto initializer = []( RegularTreeNode & ){}; - return getNeighbors< false , false >( UIntPack< _LeftRadii ... >() , UIntPack< _RightRadii ... >() , (RegularTreeNode*)node , NULL , initializer ); + return getNeighbors< false , false >( ParameterPack::UIntPack< _LeftRadii ... >() , ParameterPack::UIntPack< _RightRadii ... >() , (RegularTreeNode*)node , NULL , initializer ); } template< bool CreateNodes , bool ThreadSafe > @@ -346,40 +347,39 @@ namespace PoissonRecon return getChildNeighbors< false , false , Real >( p , d , childNeighbors , NULL , initializer ); } - void setLeafNeighbors( RegularTreeNode *node , StaticWindow< RegularTreeNode * , UIntPack< ( LeftRadii + RightRadii + 1 ) ... > > &leaves ); + void setLeafNeighbors( RegularTreeNode *node , Window::StaticWindow< RegularTreeNode * , ( LeftRadii + RightRadii + 1 ) ... > &leaves ); }; template< typename LeftPack , typename RightPack > struct ConstNeighborKey{}; template< unsigned int ... LeftRadii , unsigned int ... RightRadii > - struct ConstNeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > > + struct ConstNeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > > { protected: static_assert( sizeof...(LeftRadii)==sizeof...(RightRadii) , "[ERROR] Left and right radii dimensions don't match" ); - static const unsigned int CenterIndex = WindowIndex< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > , UIntPack< LeftRadii ... > >::Index; int _depth; template< unsigned int ... _PLeftRadii , unsigned int ... _PRightRadii , unsigned int ... _CLeftRadii , unsigned int ... _CRightRadii > - static unsigned int _NeighborsLoop( UIntPack< _PLeftRadii ... > , UIntPack< _PRightRadii ... > , UIntPack< _CLeftRadii ... > , UIntPack< _CRightRadii ... > , ConstWindowSlice< const RegularTreeNode* , UIntPack< ( _PLeftRadii+_PRightRadii+1 ) ... > > pNeighbors , WindowSlice< const RegularTreeNode* , UIntPack< ( _CLeftRadii+_CRightRadii+1 ) ... > > cNeighbors , int cIdx ); + static unsigned int _NeighborsLoop( ParameterPack::UIntPack< _PLeftRadii ... > , ParameterPack::UIntPack< _PRightRadii ... > , ParameterPack::UIntPack< _CLeftRadii ... > , ParameterPack::UIntPack< _CRightRadii ... > , Window::ConstSlice< const RegularTreeNode* , ( _PLeftRadii+_PRightRadii+1 ) ... > pNeighbors , Window::Slice< const RegularTreeNode* , ( _CLeftRadii+_CRightRadii+1 ) ... > cNeighbors , int cIdx ); template< unsigned int ... _PLeftRadii , unsigned int ... _PRightRadii , unsigned int ... _CLeftRadii , unsigned int ... _CRightRadii > - static unsigned int _NeighborsLoop( UIntPack< _PLeftRadii ... > , UIntPack< _PRightRadii ... > , UIntPack< _CLeftRadii ... > , UIntPack< _CRightRadii ... > , WindowSlice< const RegularTreeNode* , UIntPack< ( _PLeftRadii+_PRightRadii+1 ) ... > > pNeighbors , WindowSlice< const RegularTreeNode* , UIntPack< ( _CLeftRadii+_CRightRadii+1 ) ... > > cNeighbors , int cIdx ); + static unsigned int _NeighborsLoop( ParameterPack::UIntPack< _PLeftRadii ... > , ParameterPack::UIntPack< _PRightRadii ... > , ParameterPack::UIntPack< _CLeftRadii ... > , ParameterPack::UIntPack< _CRightRadii ... > , Window::Slice< const RegularTreeNode* , ( _PLeftRadii+_PRightRadii+1 ) ... > pNeighbors , Window::Slice< const RegularTreeNode* , ( _CLeftRadii+_CRightRadii+1 ) ... > cNeighbors , int cIdx ); template< typename PLeft , typename PRight , typename CLeft , typename CRight > struct _Run{}; template< unsigned int _PLeftRadius , unsigned int ... _PLeftRadii , unsigned int _PRightRadius , unsigned int ... _PRightRadii , unsigned int _CLeftRadius , unsigned int ... _CLeftRadii , unsigned int _CRightRadius , unsigned int ... _CRightRadii > - struct _Run< UIntPack< _PLeftRadius , _PLeftRadii ... > , UIntPack< _PRightRadius , _PRightRadii ... > , UIntPack< _CLeftRadius , _CLeftRadii ... > , UIntPack< _CRightRadius , _CRightRadii ... > > + struct _Run< ParameterPack::UIntPack< _PLeftRadius , _PLeftRadii ... > , ParameterPack::UIntPack< _PRightRadius , _PRightRadii ... > , ParameterPack::UIntPack< _CLeftRadius , _CLeftRadii ... > , ParameterPack::UIntPack< _CRightRadius , _CRightRadii ... > > { - static unsigned int Run( ConstWindowSlice< const RegularTreeNode* , UIntPack< _PLeftRadius + _PRightRadius + 1 , ( _PLeftRadii+_PRightRadii+1 ) ... > > pNeighbors , WindowSlice< const RegularTreeNode* , UIntPack< _CLeftRadius + _CRightRadius + 1 , ( _CLeftRadii+_CRightRadii+1 ) ... > > cNeighbors , int* c , int cornerIndex ); + static unsigned int Run( Window::ConstSlice< const RegularTreeNode* , _PLeftRadius + _PRightRadius + 1 , ( _PLeftRadii+_PRightRadii+1 ) ... > pNeighbors , Window::Slice< const RegularTreeNode* , _CLeftRadius + _CRightRadius + 1 , ( _CLeftRadii+_CRightRadii+1 ) ... > cNeighbors , int* c , int cornerIndex ); }; template< unsigned int _PLeftRadius , unsigned int _PRightRadius , unsigned int _CLeftRadius , unsigned int _CRightRadius > - struct _Run< UIntPack< _PLeftRadius > , UIntPack< _PRightRadius > , UIntPack< _CLeftRadius > , UIntPack< _CRightRadius > > + struct _Run< ParameterPack::UIntPack< _PLeftRadius > , ParameterPack::UIntPack< _PRightRadius > , ParameterPack::UIntPack< _CLeftRadius > , ParameterPack::UIntPack< _CRightRadius > > { - static unsigned int Run( ConstWindowSlice< const RegularTreeNode* , UIntPack< _PLeftRadius+_PRightRadius+1 > > pNeighbors , WindowSlice< const RegularTreeNode* , UIntPack< _CLeftRadius+_CRightRadius+1 > > cNeighbors , int* c , int cornerIndex ); + static unsigned int Run( Window::ConstSlice< const RegularTreeNode* , _PLeftRadius+_PRightRadius+1 > pNeighbors , Window::Slice< const RegularTreeNode* , _CLeftRadius+_CRightRadius+1 > cNeighbors , int* c , int cornerIndex ); }; public: - - typedef ConstNeighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > > NeighborType; + static const unsigned int CenterIndex = Window::Index< ( LeftRadii + RightRadii + 1 ) ... >::template I< LeftRadii ... >(); + typedef ConstNeighbors< ParameterPack::UIntPack< ( LeftRadii + RightRadii + 1 ) ... > > NeighborType; NeighborType* neighbors; ConstNeighborKey( void ); @@ -389,17 +389,18 @@ namespace PoissonRecon int depth( void ) const { return _depth; } void set( int depth ); + const RegularTreeNode *center( unsigned int depth ) const { return neighbors[depth].neighbors.data[ CenterIndex ]; } - typename RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::template ConstNeighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& getNeighbors( const RegularTreeNode* node ); + typename RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::template ConstNeighbors< ParameterPack::UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& getNeighbors( const RegularTreeNode* node ); template< unsigned int ... _LeftRadii , unsigned int ... _RightRadii > - void getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , const RegularTreeNode* node , ConstNeighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors ); + void getNeighbors( ParameterPack::UIntPack< _LeftRadii ... > , ParameterPack::UIntPack< _RightRadii ... > , const RegularTreeNode* node , ConstNeighbors< ParameterPack::UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors ); template< unsigned int ... _LeftRadii , unsigned int ... _RightRadii > - void getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , const RegularTreeNode* node , ConstNeighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& pNeighbors , ConstNeighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors ); + void getNeighbors( ParameterPack::UIntPack< _LeftRadii ... > , ParameterPack::UIntPack< _RightRadii ... > , const RegularTreeNode* node , ConstNeighbors< ParameterPack::UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& pNeighbors , ConstNeighbors< ParameterPack::UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors ); unsigned int getChildNeighbors( int cIdx , int d , NeighborType& childNeighbors ) const; template< class Real > - unsigned int getChildNeighbors( Point< Real , Dim > p , int d , ConstNeighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& childNeighbors ) const; + unsigned int getChildNeighbors( Point< Real , Dim > p , int d , ConstNeighbors< ParameterPack::UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& childNeighbors ) const; - void setLeafNeighbors( const RegularTreeNode *node , StaticWindow< RegularTreeNode * , UIntPack< ( LeftRadii + RightRadii + 1 ) ... > > &leaves ); + void setLeafNeighbors( const RegularTreeNode *node , Window::StaticWindow< RegularTreeNode * , ( LeftRadii + RightRadii + 1 ) ... > &leaves ); }; int width( int maxDepth ) const; diff --git a/Src/RegularTree.inl b/Src/RegularTree.inl index ba002492..f5713426 100644 --- a/Src/RegularTree.inl +++ b/Src/RegularTree.inl @@ -50,6 +50,7 @@ void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::cleanChildren( bool } children = NULL; } + template< unsigned int Dim , class NodeData , class DepthAndOffsetType > RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::~RegularTreeNode(void) { @@ -122,7 +123,7 @@ bool RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::_initChildren( Allo if( children ) delete[] children; children = new RegularTreeNode[ 1<::_initChildren_s( Al // Allocate the children if( nodeAllocator ) _children = PointerAddress( nodeAllocator->newElements( 1<::centerIndex( } template< unsigned int Dim , class NodeData , class DepthAndOffsetType > inline int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::depth( void ) const { return _depth; } + template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< class Real > void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::centerAndWidth( Point< Real , Dim >& center , Real& width ) const @@ -277,7 +279,6 @@ size_t RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::maxDepthLeaves( i return c; } } - template< unsigned int Dim , class NodeData , class DepthAndOffsetType > const RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::root( void ) const { @@ -545,7 +546,7 @@ bool RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::read( BinaryStream { node->children = NULL; node->initChildren< false >( nodeAllocator , initializer ); - if( !stream.read( GetPointer( node->children , 1<children , 1<children[i].parent = node; @@ -553,7 +554,7 @@ bool RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::read( BinaryStream } } }; - if( !stream.read( *this ) ) ERROR_OUT( "Failed to read root" ); + if( !stream.read( *this ) ) MK_ERROR_OUT( "Failed to read root" ); ReadChildren( this ); return true; } @@ -570,45 +571,45 @@ int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::width( int maxDepth //////////////////////////////// template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... Widths > -RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::Neighbors< UIntPack< Widths ... > >::Neighbors( void ){ static_assert( sizeof...(Widths)==Dim , "[ERROR] Window and tree dimensions don't match" ) ; clear(); } +RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::Neighbors< ParameterPack::UIntPack< Widths ... > >::Neighbors( void ){ static_assert( sizeof...(Widths)==Dim , "[ERROR] Window and tree dimensions don't match" ) ; clear(); } template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... Widths > -void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::Neighbors< UIntPack< Widths ... > >::clear( void ){ for( int i=0 ; i >::Size ; i++ ) neighbors.data[i] = NULL; } +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::Neighbors< ParameterPack::UIntPack< Widths ... > >::clear( void ){ for( unsigned int i=0 ; i() ; i++ ) neighbors.data[i] = NULL; } ///////////////////////////////////// // RegularTreeNode::ConstNeighbors // ///////////////////////////////////// template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... Widths > -RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighbors< UIntPack< Widths ... > >::ConstNeighbors( void ){ static_assert( sizeof...(Widths)==Dim , "[ERROR] Window and tree dimensions don't match" ) ; clear(); } +RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighbors< ParameterPack::UIntPack< Widths ... > >::ConstNeighbors( void ){ static_assert( sizeof...(Widths)==Dim , "[ERROR] Window and tree dimensions don't match" ) ; clear(); } template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... Widths > -void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighbors< UIntPack< Widths ... > >::clear( void ){ for( int i=0 ; i >::Size ; i++ ) neighbors.data[i] = NULL; } +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighbors< ParameterPack::UIntPack< Widths ... > >::clear( void ){ for( unsigned int i=0 ; i() ; i++ ) neighbors.data[i] = NULL; } ////////////////////////////////// // RegularTreeNode::NeighborKey // ////////////////////////////////// template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > -RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::NeighborKey( void ){ _depth=-1 , neighbors=NULL; } +RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::NeighborKey( void ){ _depth=-1 , neighbors=NULL; } template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > -RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::NeighborKey( const NeighborKey& key ) +RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::NeighborKey( const NeighborKey& key ) { _depth = 0 , neighbors = NULL; set( key._depth ); - for( int d=0 ; d<=_depth ; d++ ) memcpy( &neighbors[d] , &key.neighbors[d] , sizeof( Neighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > > ) ); + for( int d=0 ; d<=_depth ; d++ ) memcpy( &neighbors[d] , &key.neighbors[d] , sizeof( Neighbors< ParameterPack::UIntPack< ( LeftRadii + RightRadii + 1 ) ... > > ) ); } template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > -RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::~NeighborKey( void ) +RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::~NeighborKey( void ) { if( neighbors ) delete[] neighbors; neighbors=NULL; } template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > -void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::set( int d ) +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::set( int d ) { if( neighbors ) delete[] neighbors; neighbors = NULL; @@ -616,34 +617,37 @@ void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< UIntPa if( d<0 ) return; neighbors = new NeighborType[d+1]; } + template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , unsigned int ... _PLeftRadii , unsigned int ... _PRightRadii , unsigned int ... _CLeftRadii , unsigned int ... _CRightRadii > -unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::_NeighborsLoop( UIntPack< _PLeftRadii ... > pLeftRadii , UIntPack< _PRightRadii ... > pRightRadii , UIntPack< _CLeftRadii ... > cLeftRadii , UIntPack< _CRightRadii ... > cRightRadii , ConstWindowSlice< RegularTreeNode* , UIntPack< ( _PLeftRadii + _PRightRadii + 1 ) ... > > pNeighbors , WindowSlice< RegularTreeNode* , UIntPack< ( _CLeftRadii + _CRightRadii + 1 ) ... > > cNeighbors , int cIdx , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ) +unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::_NeighborsLoop( ParameterPack::UIntPack< _PLeftRadii ... > pLeftRadii , ParameterPack::UIntPack< _PRightRadii ... > pRightRadii , ParameterPack::UIntPack< _CLeftRadii ... > cLeftRadii , ParameterPack::UIntPack< _CRightRadii ... > cRightRadii , Window::ConstSlice< RegularTreeNode* , ( _PLeftRadii + _PRightRadii + 1 ) ... > pNeighbors , Window::Slice< RegularTreeNode* , ( _CLeftRadii + _CRightRadii + 1 ) ... > cNeighbors , int cIdx , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ) { static_assert( Dim==sizeof ... ( _PLeftRadii ) && Dim==sizeof ... ( _PRightRadii ) && Dim==sizeof ... ( _CLeftRadii ) && Dim==sizeof ... ( _CRightRadii ) , "[ERROR] Dimensions don't match" ); int c[Dim]; for( int d=0 ; d>d ) & 1; - return _Run< CreateNodes , ThreadSafe , NodeInitializer , UIntPack< _PLeftRadii ... > , UIntPack< _PRightRadii ... > , UIntPack< _CLeftRadii ... > , UIntPack< _CRightRadii ... > >::Run( pNeighbors , cNeighbors , c , 0 , nodeAllocator , initializer ); + return _Run< CreateNodes , ThreadSafe , NodeInitializer , ParameterPack::UIntPack< _PLeftRadii ... > , ParameterPack::UIntPack< _PRightRadii ... > , ParameterPack::UIntPack< _CLeftRadii ... > , ParameterPack::UIntPack< _CRightRadii ... > >::Run( pNeighbors , cNeighbors , c , 0 , nodeAllocator , initializer ); } + template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , unsigned int ... _PLeftRadii , unsigned int ... _PRightRadii , unsigned int ... _CLeftRadii , unsigned int ... _CRightRadii > -unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::_NeighborsLoop( UIntPack< _PLeftRadii ... > pLeftRadii , UIntPack< _PRightRadii ... > pRightRadii , UIntPack< _CLeftRadii ... > cLeftRadii , UIntPack< _CRightRadii ... > cRightRadii , WindowSlice< RegularTreeNode* , UIntPack< ( _PLeftRadii + _PRightRadii + 1 ) ... > > pNeighbors , WindowSlice< RegularTreeNode* , UIntPack< ( _CLeftRadii + _CRightRadii + 1 ) ... > > cNeighbors , int cIdx , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ) +unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::_NeighborsLoop( ParameterPack::UIntPack< _PLeftRadii ... > pLeftRadii , ParameterPack::UIntPack< _PRightRadii ... > pRightRadii , ParameterPack::UIntPack< _CLeftRadii ... > cLeftRadii , ParameterPack::UIntPack< _CRightRadii ... > cRightRadii , Window::Slice< RegularTreeNode* , ( _PLeftRadii + _PRightRadii + 1 ) ... > pNeighbors , Window::Slice< RegularTreeNode* , ( _CLeftRadii + _CRightRadii + 1 ) ... > cNeighbors , int cIdx , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ) { - return _NeighborsLoop< CreateNodes , ThreadSafe , NodeInitializer >( UIntPack< _PLeftRadii ... >() , UIntPack< _PRightRadii ... >() , UIntPack< _CLeftRadii ... >() , UIntPack< _CRightRadii ... >() , ( ConstWindowSlice< RegularTreeNode* , UIntPack< ( _PLeftRadii + _PRightRadii + 1 ) ... > > )pNeighbors , cNeighbors , cIdx , nodeAllocator , initializer ); + return _NeighborsLoop< CreateNodes , ThreadSafe , NodeInitializer >( ParameterPack::UIntPack< _PLeftRadii ... >() , ParameterPack::UIntPack< _PRightRadii ... >() , ParameterPack::UIntPack< _CLeftRadii ... >() , ParameterPack::UIntPack< _CRightRadii ... >() , ( Window::ConstSlice< RegularTreeNode* , ( _PLeftRadii + _PRightRadii + 1 ) ... > )pNeighbors , cNeighbors , cIdx , nodeAllocator , initializer ); } + template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , unsigned int _PLeftRadius , unsigned int ... _PLeftRadii , unsigned int _PRightRadius , unsigned int ... _PRightRadii , unsigned int _CLeftRadius , unsigned int ... _CLeftRadii , unsigned int _CRightRadius , unsigned int ... _CRightRadii > -unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::_Run< CreateNodes , ThreadSafe , NodeInitializer , UIntPack< _PLeftRadius , _PLeftRadii ... > , UIntPack< _PRightRadius , _PRightRadii ... > , UIntPack< _CLeftRadius , _CLeftRadii ... > , UIntPack< _CRightRadius , _CRightRadii ... > >::Run( ConstWindowSlice< RegularTreeNode* , UIntPack< _PLeftRadius + _PRightRadius + 1 , ( _PLeftRadii + _PRightRadii + 1 ) ... > > pNeighbors , WindowSlice< RegularTreeNode* , UIntPack< _CLeftRadius + _CRightRadius + 1 , ( _CLeftRadii + _CRightRadii + 1 ) ... > > cNeighbors , int* c , int cornerIndex , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ) +unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::_Run< CreateNodes , ThreadSafe , NodeInitializer , ParameterPack::UIntPack< _PLeftRadius , _PLeftRadii ... > , ParameterPack::UIntPack< _PRightRadius , _PRightRadii ... > , ParameterPack::UIntPack< _CLeftRadius , _CLeftRadii ... > , ParameterPack::UIntPack< _CRightRadius , _CRightRadii ... > >::Run( Window::ConstSlice< RegularTreeNode* , _PLeftRadius + _PRightRadius + 1 , ( _PLeftRadii + _PRightRadii + 1 ) ... > pNeighbors , Window::Slice< RegularTreeNode* , _CLeftRadius + _CRightRadius + 1 , ( _CLeftRadii + _CRightRadii + 1 ) ... > cNeighbors , int* c , int cornerIndex , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ) { static const int D = sizeof ... ( _PLeftRadii ) + 1; unsigned int count=0; for( int i=-(int)_CLeftRadius ; i<=(int)_CRightRadius ; i++ ) { int _i = (i+c[Dim-D]) + ( _CLeftRadius<<1 ) , pi = ( _i>>1 ) - _CLeftRadius + _PLeftRadius , ci = i + _CLeftRadius; - count += _Run< CreateNodes , ThreadSafe , NodeInitializer , UIntPack< _PLeftRadii ... > , UIntPack< _PRightRadii ... > , UIntPack< _CLeftRadii ... > , UIntPack< _CRightRadii ... > >::Run( pNeighbors[pi] , cNeighbors[ci] , c , cornerIndex | ( ( _i&1)<<(Dim-D) ) , nodeAllocator , initializer ); + count += _Run< CreateNodes , ThreadSafe , NodeInitializer , ParameterPack::UIntPack< _PLeftRadii ... > , ParameterPack::UIntPack< _PRightRadii ... > , ParameterPack::UIntPack< _CLeftRadii ... > , ParameterPack::UIntPack< _CRightRadii ... > >::Run( pNeighbors[pi] , cNeighbors[ci] , c , cornerIndex | ( ( _i&1)<<(Dim-D) ) , nodeAllocator , initializer ); } return count; } @@ -652,7 +656,7 @@ unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , unsigned int _PLeftRadius , unsigned int _PRightRadius , unsigned int _CLeftRadius , unsigned int _CRightRadius > -unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::_Run< CreateNodes , ThreadSafe , NodeInitializer , UIntPack< _PLeftRadius > , UIntPack< _PRightRadius > , UIntPack< _CLeftRadius > , UIntPack< _CRightRadius > >::Run( ConstWindowSlice< RegularTreeNode* , UIntPack< _PLeftRadius+_PRightRadius+1 > > pNeighbors , WindowSlice< RegularTreeNode* , UIntPack< _CLeftRadius+_CRightRadius+1 > > cNeighbors , int* c , int cornerIndex , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ) +unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::_Run< CreateNodes , ThreadSafe , NodeInitializer , ParameterPack::UIntPack< _PLeftRadius > , ParameterPack::UIntPack< _PRightRadius > , ParameterPack::UIntPack< _CLeftRadius > , ParameterPack::UIntPack< _CRightRadius > >::Run( Window::ConstSlice< RegularTreeNode* , _PLeftRadius+_PRightRadius+1 > pNeighbors , Window::Slice< RegularTreeNode* , _CLeftRadius+_CRightRadius+1 > cNeighbors , int* c , int cornerIndex , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ) { static const int D = 1; unsigned int count=0; @@ -664,6 +668,7 @@ unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey if( pNeighbors[pi] ) { #ifdef SANITIZED_PR +//#ifdef NEW_CODE RegularTreeNode * children = ReadAtomic( pNeighbors[pi]->children ); if( !children ) { @@ -691,18 +696,18 @@ unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer > -unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::getChildNeighbors( int cIdx , int d , NeighborType& cNeighbors , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ) const +unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::getChildNeighbors( int cIdx , int d , NeighborType& cNeighbors , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ) const { NeighborType& pNeighbors = neighbors[d]; // Check that we actually have a center node if( !pNeighbors.neighbors.data[ CenterIndex ] ) return 0; - return _NeighborsLoop< CreateNodes , ThreadSafe >( UIntPack< LeftRadii ... >() , UIntPack< RightRadii ... >() , UIntPack< LeftRadii ... >() , UIntPack< RightRadii ... >() , pNeighbors.neighbors() , cNeighbors.neighbors() , cIdx , nodeAllocator , initializer ); + return _NeighborsLoop< CreateNodes , ThreadSafe >( ParameterPack::UIntPack< LeftRadii ... >() , ParameterPack::UIntPack< RightRadii ... >() , ParameterPack::UIntPack< LeftRadii ... >() , ParameterPack::UIntPack< RightRadii ... >() , pNeighbors.neighbors() , cNeighbors.neighbors() , cIdx , nodeAllocator , initializer ); } template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , class Real > -unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::getChildNeighbors( Point< Real , Dim > p , int d , NeighborType& cNeighbors , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ) const +unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::getChildNeighbors( Point< Real , Dim > p , int d , NeighborType& cNeighbors , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ) const { NeighborType& pNeighbors = neighbors[d]; // Check that we actually have a center node @@ -716,14 +721,14 @@ unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer > -typename RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::template Neighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::getNeighbors( RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* node , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ) +typename RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::template Neighbors< ParameterPack::UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::getNeighbors( RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* node , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ) { NeighborType& neighbors = this->neighbors[node->depth()]; // This is required in case the neighbors have been constructed between the last call to getNeighbors and this one if( node==neighbors.neighbors.data[ CenterIndex ] ) { bool reset = false; - for( int i=0 ; i >::Size ; i++ ) if( !neighbors.neighbors.data[i] ) reset = true; + for( unsigned int i=0 ; i() ; i++ ) if( !neighbors.neighbors.data[i] ) reset = true; if( reset ) neighbors.neighbors.data[ CenterIndex ] = NULL; } if( node!=neighbors.neighbors.data[ CenterIndex ] ) @@ -731,7 +736,7 @@ typename RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::template Neighb for( int d=node->depth()+1 ; d<=_depth && this->neighbors[d].neighbors.data[ CenterIndex ] ; d++ ) this->neighbors[d].neighbors.data[ CenterIndex ] = NULL; neighbors.clear(); if( !node->parent ) neighbors.neighbors.data[ CenterIndex ] = node; - else _NeighborsLoop< CreateNodes , ThreadSafe >( UIntPack< LeftRadii ... >() , UIntPack< RightRadii ... >() , UIntPack< LeftRadii ... >() , UIntPack< RightRadii ... >() , getNeighbors< CreateNodes , ThreadSafe >( node->parent , nodeAllocator , initializer ).neighbors() , neighbors.neighbors() , (int)( node - node->parent->children ) , nodeAllocator , initializer ); + else _NeighborsLoop< CreateNodes , ThreadSafe >( ParameterPack::UIntPack< LeftRadii ... >() , ParameterPack::UIntPack< RightRadii ... >() , ParameterPack::UIntPack< LeftRadii ... >() , ParameterPack::UIntPack< RightRadii ... >() , getNeighbors< CreateNodes , ThreadSafe >( node->parent , nodeAllocator , initializer ).neighbors() , neighbors.neighbors() , (int)( node - node->parent->children ) , nodeAllocator , initializer ); } return neighbors; } @@ -739,19 +744,19 @@ typename RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::template Neighb template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , unsigned int ... _LeftRadii , unsigned int ... _RightRadii > -void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* node , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ) +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::getNeighbors( ParameterPack::UIntPack< _LeftRadii ... > , ParameterPack::UIntPack< _RightRadii ... > , RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* node , Neighbors< ParameterPack::UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ) { - static const unsigned int _CenterIndex = WindowIndex< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > , UIntPack< _LeftRadii ... > >::Index; + static const unsigned int _CenterIndex = Window::Index( ParameterPack::UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... >() , ParameterPack::UIntPack< _LeftRadii ... >() ); neighbors.clear(); if( !node ) return; // [WARNING] This estimate of the required radius is somewhat conservative if the readius is odd (depending on where the node is relative to its parent) - UIntPack< LeftRadii ... > leftRadii; - UIntPack< RightRadii ... > rightRadii; - UIntPack< ( _LeftRadii+1 )/2 ... > pLeftRadii; - UIntPack< ( _RightRadii+1 )/2 ... > pRightRadii; - UIntPack< _LeftRadii ... > cLeftRadii; - UIntPack< _RightRadii ... > cRightRadii; + ParameterPack::UIntPack< LeftRadii ... > leftRadii; + ParameterPack::UIntPack< RightRadii ... > rightRadii; + ParameterPack::UIntPack< ( _LeftRadii+1 )/2 ... > pLeftRadii; + ParameterPack::UIntPack< ( _RightRadii+1 )/2 ... > pRightRadii; + ParameterPack::UIntPack< _LeftRadii ... > cLeftRadii; + ParameterPack::UIntPack< _RightRadii ... > cRightRadii; // If we are at the root of the tree, we are done if( !node->parent ) neighbors.neighbors.data[ _CenterIndex ] = node; @@ -759,13 +764,13 @@ void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< UIntPa else if( pLeftRadii<=leftRadii && pRightRadii<=rightRadii ) { getNeighbors< CreateNodes , ThreadSafe >( node->parent , nodeAllocator , initializer ); - const Neighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& pNeighbors = this->neighbors[ node->depth()-1 ]; + const Neighbors< ParameterPack::UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& pNeighbors = this->neighbors[ node->depth()-1 ]; _NeighborsLoop< CreateNodes , ThreadSafe >( leftRadii , rightRadii , cLeftRadii , cRightRadii , pNeighbors.neighbors() , neighbors.neighbors() , (int)( node - node->parent->children ) , nodeAllocator , initializer ); } // Otherwise recurse else { - Neighbors< UIntPack< ( ( _LeftRadii+1 )/2 + ( _RightRadii+1 )/2 + 1 ) ... > > pNeighbors; + Neighbors< ParameterPack::UIntPack< ( ( _LeftRadii+1 )/2 + ( _RightRadii+1 )/2 + 1 ) ... > > pNeighbors; getNeighbors< CreateNodes , ThreadSafe >( pLeftRadii , pRightRadii , node->parent , pNeighbors , nodeAllocator , initializer ); _NeighborsLoop< CreateNodes , ThreadSafe >( pLeftRadii , pRightRadii , cLeftRadii , cRightRadii , pNeighbors.neighbors() , neighbors.neighbors() , (int)( node - node->parent->children ) , nodeAllocator , initializer ); } @@ -774,10 +779,10 @@ void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< UIntPa template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > template< bool CreateNodes , bool ThreadSafe , typename NodeInitializer , unsigned int ... _LeftRadii , unsigned int ... _RightRadii > -void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* node , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& pNeighbors , Neighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ) +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::getNeighbors( ParameterPack::UIntPack< _LeftRadii ... > , ParameterPack::UIntPack< _RightRadii ... > , RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* node , Neighbors< ParameterPack::UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& pNeighbors , Neighbors< ParameterPack::UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors , Allocator< RegularTreeNode >* nodeAllocator , NodeInitializer &initializer ) { - UIntPack< _LeftRadii ... > leftRadii; - UIntPack< _RightRadii ... > rightRadii; + ParameterPack::UIntPack< _LeftRadii ... > leftRadii; + ParameterPack::UIntPack< _RightRadii ... > rightRadii; if( !node->parent ) getNeighbors< CreateNodes , ThreadSafe >( leftRadii , rightRadii , node , neighbors , nodeAllocator , initializer ); else { @@ -788,7 +793,7 @@ void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< UIntPa template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > -void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::setLeafNeighbors( RegularTreeNode *node , StaticWindow< RegularTreeNode * , UIntPack< ( LeftRadii + RightRadii + 1 ) ... > > &leaves ) +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::setLeafNeighbors( RegularTreeNode *node , Window::StaticWindow< RegularTreeNode * , ( LeftRadii + RightRadii + 1 ) ... > &leaves ) { // Suppose that we have a node at index I and we want the leaf nodes supported on the (possibly virtual) node K away // Case 1: The K-th neighbor exists @@ -802,7 +807,7 @@ void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< UIntPa static const unsigned int _LeftRadii[] = { LeftRadii ... }; auto GetNeighborLeaf = [&]( unsigned int depth , const int index[Dim] , const int offset[Dim] ) { - // unsigned int _index[Dim] , _offset[Dim] , __offset[Dim]; +// unsigned int _index[Dim] , _offset[Dim] , __offset[Dim]; int _index[Dim] , _offset[Dim] , __offset[Dim]; for( int dim=0 ; dim=0 ; d-- ) @@ -824,9 +829,9 @@ void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< UIntPa int depth , index[Dim] , offset[Dim] , _offset[Dim]; node->depthAndOffset( depth , index ); - WindowLoop< Dim >::Run + Window::Loop< Dim >::Run ( - IsotropicUIntPack< Dim , 0 >() , UIntPack< ( LeftRadii + RightRadii + 1 ) ... >() , + ParameterPack::IsotropicUIntPack< Dim , 0 >() , ParameterPack::UIntPack< ( LeftRadii + RightRadii + 1 ) ... >() , [&]( int d , int i ){ offset[d] = i , _offset[d] = i-_LeftRadii[d]; } , [&]( void ){ leaves( offset ) = GetNeighborLeaf( depth , index , _offset ); } ); @@ -837,32 +842,32 @@ void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::NeighborKey< UIntPa /////////////////////////////////////// template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > -RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::ConstNeighborKey( void ){ _depth=-1 , neighbors=NULL; } +RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::ConstNeighborKey( void ){ _depth=-1 , neighbors=NULL; } template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > -RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::ConstNeighborKey( const ConstNeighborKey& key ) +RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::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< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > > ) ); + for( int d=0 ; d<=_depth ; d++ ) memcpy( &neighbors[d] , &key.neighbors[d] , sizeof( ConstNeighbors< ParameterPack::UIntPack< ( LeftRadii + RightRadii + 1 ) ... > > ) ); } template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > -RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::~ConstNeighborKey( void ) +RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::~ConstNeighborKey( void ) { if( neighbors ) delete[] neighbors; neighbors=NULL; } template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > -typename RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::template ConstNeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >& RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::operator = ( const ConstNeighborKey& key ) +typename RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::template ConstNeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >& RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::operator = ( const ConstNeighborKey& key ) { set( key._depth ); - for( int d=0 ; d<=_depth ; d++ ) memcpy( &neighbors[d] , &key.neighbors[d] , sizeof( ConstNeighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > > ) ); + for( int d=0 ; d<=_depth ; d++ ) memcpy( &neighbors[d] , &key.neighbors[d] , sizeof( ConstNeighbors< ParameterPack::UIntPack< ( LeftRadii + RightRadii + 1 ) ... > > ) ); } template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > -void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::set( int d ) +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::set( int d ) { if( neighbors ) delete[] neighbors; neighbors = NULL; @@ -874,39 +879,41 @@ void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< U template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > template< unsigned int ... _PLeftRadii , unsigned int ... _PRightRadii , unsigned int ... _CLeftRadii , unsigned int ... _CRightRadii > -unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::_NeighborsLoop( UIntPack< _PLeftRadii ... > pLeftRadii , UIntPack< _PRightRadii ... > pRightRadii , UIntPack< _CLeftRadii ... > cLeftRadii , UIntPack< _CRightRadii ... > cRightRadii , ConstWindowSlice< const RegularTreeNode * , UIntPack< ( _PLeftRadii + _PRightRadii + 1 ) ... > > pNeighbors , WindowSlice< const RegularTreeNode * , UIntPack< ( _CLeftRadii + _CRightRadii + 1 ) ... > > cNeighbors , int cIdx ) +unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::_NeighborsLoop( ParameterPack::UIntPack< _PLeftRadii ... > pLeftRadii , ParameterPack::UIntPack< _PRightRadii ... > pRightRadii , ParameterPack::UIntPack< _CLeftRadii ... > cLeftRadii , ParameterPack::UIntPack< _CRightRadii ... > cRightRadii , Window::ConstSlice< const RegularTreeNode * , ( _PLeftRadii + _PRightRadii + 1 ) ... > pNeighbors , Window::Slice< const RegularTreeNode * , ( _CLeftRadii + _CRightRadii + 1 ) ... > cNeighbors , int cIdx ) { static_assert( Dim==sizeof ... ( _PLeftRadii ) && Dim==sizeof ... ( _PRightRadii ) && Dim==sizeof ... ( _CLeftRadii ) && Dim==sizeof ... ( _CRightRadii ) , "[ERROR] Dimensions don't match" ); int c[Dim]; for( int d=0 ; d>d ) & 1; - return _Run< UIntPack< _PLeftRadii ... > , UIntPack< _PRightRadii ... > , UIntPack< _CLeftRadii ... > , UIntPack< _CRightRadii ... > >::Run( pNeighbors , cNeighbors , c , 0 ); + return _Run< ParameterPack::UIntPack< _PLeftRadii ... > , ParameterPack::UIntPack< _PRightRadii ... > , ParameterPack::UIntPack< _CLeftRadii ... > , ParameterPack::UIntPack< _CRightRadii ... > >::Run( pNeighbors , cNeighbors , c , 0 ); } template< unsigned int Dim , class NodeData , class DepthAndOffsetType > + template< unsigned int ... LeftRadii , unsigned int ... RightRadii > template< unsigned int ... _PLeftRadii , unsigned int ... _PRightRadii , unsigned int ... _CLeftRadii , unsigned int ... _CRightRadii > -unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::_NeighborsLoop( UIntPack< _PLeftRadii ... > pLeftRadii , UIntPack< _PRightRadii ... > pRightRadii , UIntPack< _CLeftRadii ... > cLeftRadii , UIntPack< _CRightRadii ... > cRightRadii , WindowSlice< const RegularTreeNode* , UIntPack< ( _PLeftRadii + _PRightRadii + 1 ) ... > > pNeighbors , WindowSlice< const RegularTreeNode* , UIntPack< ( _CLeftRadii + _CRightRadii + 1 ) ... > > cNeighbors , int cIdx ) +unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::_NeighborsLoop( ParameterPack::UIntPack< _PLeftRadii ... > pLeftRadii , ParameterPack::UIntPack< _PRightRadii ... > pRightRadii , ParameterPack::UIntPack< _CLeftRadii ... > cLeftRadii , ParameterPack::UIntPack< _CRightRadii ... > cRightRadii , Window::Slice< const RegularTreeNode* , ( _PLeftRadii + _PRightRadii + 1 ) ... > pNeighbors , Window::Slice< const RegularTreeNode* , ( _CLeftRadii + _CRightRadii + 1 ) ... > cNeighbors , int cIdx ) { - return _NeighborsLoop( UIntPack< _PLeftRadii ... >() , UIntPack< _PRightRadii ... >() , UIntPack< _CLeftRadii ... >() , UIntPack< _CRightRadii ... >() , ( ConstWindowSlice< const RegularTreeNode* , UIntPack< ( _PLeftRadii + _PRightRadii + 1 ) ... > > )pNeighbors , cNeighbors , cIdx ); + return _NeighborsLoop( ParameterPack::UIntPack< _PLeftRadii ... >() , ParameterPack::UIntPack< _PRightRadii ... >() , ParameterPack::UIntPack< _CLeftRadii ... >() , ParameterPack::UIntPack< _CRightRadii ... >() , ( Window::ConstSlice< const RegularTreeNode* , ( _PLeftRadii + _PRightRadii + 1 ) ... > )pNeighbors , cNeighbors , cIdx ); } template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > template< unsigned int _PLeftRadius , unsigned int ... _PLeftRadii , unsigned int _PRightRadius , unsigned int ... _PRightRadii , unsigned int _CLeftRadius , unsigned int ... _CLeftRadii , unsigned int _CRightRadius , unsigned int ... _CRightRadii > -unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::_Run< UIntPack< _PLeftRadius , _PLeftRadii ... > , UIntPack< _PRightRadius , _PRightRadii ... > , UIntPack< _CLeftRadius , _CLeftRadii ... > , UIntPack< _CRightRadius , _CRightRadii ... > >::Run( ConstWindowSlice< const RegularTreeNode* , UIntPack< _PLeftRadius + _PRightRadius + 1 , ( _PLeftRadii + _PRightRadii + 1 ) ... > > pNeighbors , WindowSlice< const RegularTreeNode* , UIntPack< _CLeftRadius + _CRightRadius + 1 , ( _CLeftRadii + _CRightRadii + 1 ) ... > > cNeighbors , int* c , int cornerIndex ) +unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::_Run< ParameterPack::UIntPack< _PLeftRadius , _PLeftRadii ... > , ParameterPack::UIntPack< _PRightRadius , _PRightRadii ... > , ParameterPack::UIntPack< _CLeftRadius , _CLeftRadii ... > , ParameterPack::UIntPack< _CRightRadius , _CRightRadii ... > >::Run( Window::ConstSlice< const RegularTreeNode* , _PLeftRadius + _PRightRadius + 1 , ( _PLeftRadii + _PRightRadii + 1 ) ... > pNeighbors , Window::Slice< const RegularTreeNode* , _CLeftRadius + _CRightRadius + 1 , ( _CLeftRadii + _CRightRadii + 1 ) ... > cNeighbors , int* c , int cornerIndex ) { static const int D = sizeof ... ( _PLeftRadii ) + 1; unsigned int count=0; for( int i=-(int)_CLeftRadius ; i<=(int)_CRightRadius ; i++ ) { int _i = (i+c[Dim-D]) + ( _CLeftRadius<<1 ) , pi = ( _i>>1 ) - _CLeftRadius + _PLeftRadius , ci = i + _CLeftRadius; - count += _Run< UIntPack< _PLeftRadii ... > , UIntPack< _PRightRadii ... > , UIntPack< _CLeftRadii ... > , UIntPack< _CRightRadii ... > >::Run( pNeighbors[pi] , cNeighbors[ci] , c , cornerIndex | ( ( _i&1)<<(Dim-D) ) ); + count += _Run< ParameterPack::UIntPack< _PLeftRadii ... > , ParameterPack::UIntPack< _PRightRadii ... > , ParameterPack::UIntPack< _CLeftRadii ... > , ParameterPack::UIntPack< _CRightRadii ... > >::Run( pNeighbors[pi] , cNeighbors[ci] , c , cornerIndex | ( ( _i&1)<<(Dim-D) ) ); } return count; } + template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > template< unsigned int _PLeftRadius , unsigned int _PRightRadius , unsigned int _CLeftRadius , unsigned int _CRightRadius > -unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::_Run< UIntPack< _PLeftRadius > , UIntPack< _PRightRadius > , UIntPack< _CLeftRadius > , UIntPack< _CRightRadius > >::Run( ConstWindowSlice< const RegularTreeNode* , UIntPack< _PLeftRadius+_PRightRadius+1 > > pNeighbors , WindowSlice< const RegularTreeNode* , UIntPack< _CLeftRadius+_CRightRadius+1 > > cNeighbors , int* c , int cornerIndex ) +unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::_Run< ParameterPack::UIntPack< _PLeftRadius > , ParameterPack::UIntPack< _PRightRadius > , ParameterPack::UIntPack< _CLeftRadius > , ParameterPack::UIntPack< _CRightRadius > >::Run( Window::ConstSlice< const RegularTreeNode* , _PLeftRadius+_PRightRadius+1 > pNeighbors , Window::Slice< const RegularTreeNode* , _CLeftRadius+_CRightRadius+1 > cNeighbors , int* c , int cornerIndex ) { static const int D = 1; unsigned int count=0; @@ -921,70 +928,72 @@ unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighb template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > -unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::getChildNeighbors( int cIdx , int d , ConstNeighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& cNeighbors ) const +unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::getChildNeighbors( int cIdx , int d , ConstNeighbors< ParameterPack::UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& cNeighbors ) const { - const ConstNeighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& pNeighbors = neighbors[d]; + const ConstNeighbors< ParameterPack::UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& pNeighbors = neighbors[d]; // Check that we actually have a center node if( !pNeighbors.neighbors.data[ CenterIndex ] ) return 0; - return _NeighborsLoop( UIntPack< LeftRadii ... >() , UIntPack< RightRadii ... >() , UIntPack< LeftRadii ... >() , UIntPack< RightRadii ... >() , pNeighbors.neighbors() , cNeighbors.neighbors() , cIdx ); + return _NeighborsLoop( ParameterPack::UIntPack< LeftRadii ... >() , ParameterPack::UIntPack< RightRadii ... >() , ParameterPack::UIntPack< LeftRadii ... >() , ParameterPack::UIntPack< RightRadii ... >() , pNeighbors.neighbors() , cNeighbors.neighbors() , cIdx ); } template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > -typename RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::template ConstNeighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::getNeighbors( const RegularTreeNode* node ) +typename RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::template ConstNeighbors< ParameterPack::UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::getNeighbors( const RegularTreeNode* node ) { - ConstNeighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& neighbors = this->neighbors[ node->depth() ]; + ConstNeighbors< ParameterPack::UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& neighbors = this->neighbors[ node->depth() ]; if( node!=neighbors.neighbors.data[ CenterIndex ] ) { for( int d=node->depth()+1 ; d<=_depth && this->neighbors[d].neighbors.data[ CenterIndex ] ; d++ ) this->neighbors[d].neighbors.data[ CenterIndex ] = NULL; neighbors.clear(); if( !node->parent ) neighbors.neighbors.data[ CenterIndex ] = node; - else _NeighborsLoop( UIntPack< LeftRadii ... >() , UIntPack< RightRadii ... >() , UIntPack< LeftRadii ... >() , UIntPack< RightRadii ... >() , getNeighbors( node->parent ).neighbors() , neighbors.neighbors() , (int)( node - node->parent->children ) ); + else _NeighborsLoop( ParameterPack::UIntPack< LeftRadii ... >() , ParameterPack::UIntPack< RightRadii ... >() , ParameterPack::UIntPack< LeftRadii ... >() , ParameterPack::UIntPack< RightRadii ... >() , getNeighbors( node->parent ).neighbors() , neighbors.neighbors() , (int)( node - node->parent->children ) ); } return neighbors; } + template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > template< unsigned int ... _LeftRadii , unsigned int ... _RightRadii > -void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , const RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* node , ConstNeighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors ) +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::getNeighbors( ParameterPack::UIntPack< _LeftRadii ... > , ParameterPack::UIntPack< _RightRadii ... > , const RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* node , ConstNeighbors< ParameterPack::UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors ) { - static const unsigned int _CenterIndex = WindowIndex< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > , UIntPack< _LeftRadii ... > >::Index; + static const unsigned int _CenterIndex = Window::Index< ( _LeftRadii + _RightRadii + 1 ) ... >::template I< _LeftRadii ... >(); neighbors.clear(); if( !node ) return; - UIntPack< LeftRadii ... > leftRadii; - UIntPack< RightRadii ... > rightRadii; - UIntPack< ( _LeftRadii+1 )/2 ... > pLeftRadii; - UIntPack< ( _RightRadii+1 )/2 ... > pRightRadii; - UIntPack< _LeftRadii ... > cLeftRadii; - UIntPack< _RightRadii ... > cRightRadii; + ParameterPack::UIntPack< LeftRadii ... > leftRadii; + ParameterPack::UIntPack< RightRadii ... > rightRadii; + ParameterPack::UIntPack< ( _LeftRadii+1 )/2 ... > pLeftRadii; + ParameterPack::UIntPack< ( _RightRadii+1 )/2 ... > pRightRadii; + ParameterPack::UIntPack< _LeftRadii ... > cLeftRadii; + ParameterPack::UIntPack< _RightRadii ... > cRightRadii; // If we are at the root of the tree, we are done if( !node->parent ) neighbors.neighbors.data[ _CenterIndex ] = node; // If we can get the data from the the key for the parent node, do that else if( pLeftRadii<=leftRadii && pRightRadii<=rightRadii ) { getNeighbors( node->parent ); - const ConstNeighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& pNeighbors = this->neighbors[ node->depth()-1 ]; + const ConstNeighbors< ParameterPack::UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& pNeighbors = this->neighbors[ node->depth()-1 ]; _NeighborsLoop( leftRadii , rightRadii , cLeftRadii , cRightRadii , pNeighbors.neighbors() , neighbors.neighbors() , (int)( node - node->parent->children ) ); } // Otherwise recurse else { - ConstNeighbors< UIntPack< ( ( _LeftRadii+1 )/2 + ( _RightRadii+1 )/2 + 1 ) ... > > pNeighbors; + ConstNeighbors< ParameterPack::UIntPack< ( ( _LeftRadii+1 )/2 + ( _RightRadii+1 )/2 + 1 ) ... > > pNeighbors; getNeighbors( pLeftRadii , pRightRadii , node->parent , pNeighbors ); _NeighborsLoop( pLeftRadii , pRightRadii , cLeftRadii , cRightRadii , pNeighbors.neighbors() , neighbors.neighbors() , (int)( node - node->parent->children ) ); } return; } + template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > template< unsigned int ... _LeftRadii , unsigned int ... _RightRadii > -void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::getNeighbors( UIntPack< _LeftRadii ... > , UIntPack< _RightRadii ... > , const RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* node , ConstNeighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& pNeighbors , ConstNeighbors< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors ) +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::getNeighbors( ParameterPack::UIntPack< _LeftRadii ... > , ParameterPack::UIntPack< _RightRadii ... > , const RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* node , ConstNeighbors< ParameterPack::UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& pNeighbors , ConstNeighbors< ParameterPack::UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > >& neighbors ) { - UIntPack< _LeftRadii ... > leftRadii; - UIntPack< _RightRadii ... > rightRadii; + ParameterPack::UIntPack< _LeftRadii ... > leftRadii; + ParameterPack::UIntPack< _RightRadii ... > rightRadii; if( !node->parent ) return getNeighbors( leftRadii , rightRadii , node , neighbors ); else { @@ -992,12 +1001,13 @@ void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< U _NeighborsLoop( leftRadii , rightRadii , leftRadii , rightRadii , pNeighbors.neighbors() , neighbors.neighbors() , (int)( node - node->parent->children ) ); } } + template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > template< class Real > -unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::getChildNeighbors( Point< Real , Dim > p , int d , ConstNeighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& cNeighbors ) const +unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::getChildNeighbors( Point< Real , Dim > p , int d , ConstNeighbors< ParameterPack::UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& cNeighbors ) const { - ConstNeighbors< UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& pNeighbors = neighbors[d]; + ConstNeighbors< ParameterPack::UIntPack< ( LeftRadii + RightRadii + 1 ) ... > >& pNeighbors = neighbors[d]; // Check that we actually have a center node if( !pNeighbors.neighbors.data[ CenterIndex ] ) return 0; Point< Real , Dim > c; @@ -1010,7 +1020,7 @@ unsigned int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighb template< unsigned int Dim , class NodeData , class DepthAndOffsetType > template< unsigned int ... LeftRadii , unsigned int ... RightRadii > -void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< UIntPack< LeftRadii ... > , UIntPack< RightRadii ... > >::setLeafNeighbors( const RegularTreeNode *node , StaticWindow< RegularTreeNode * , UIntPack< ( LeftRadii + RightRadii + 1 ) ... > > &leaves ) +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< ParameterPack::UIntPack< LeftRadii ... > , ParameterPack::UIntPack< RightRadii ... > >::setLeafNeighbors( const RegularTreeNode *node , Window::StaticWindow< RegularTreeNode * , ( LeftRadii + RightRadii + 1 ) ... > &leaves ) { // Suppose that we have a node at index I and we want the leaf nodes supported on the (possibly virtual) node K away // Case 1: The K-th neighbor exists @@ -1046,10 +1056,10 @@ void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ConstNeighborKey< U int depth , index[Dim] , offset[Dim] , _offset[Dim]; node->depthAndOffset( depth , index ); - WindowLoop< Dim >::Run + Window::Loop< Dim >::Run ( - IsotropicUIntPack< Dim , 0 >() , UIntPack< ( LeftRadii + RightRadii + 1 ) ... >() , + ParameterPack::IsotropicUIntPack< Dim , 0 >() , ParameterPack::UIntPack< ( LeftRadii + RightRadii + 1 ) ... >() , [&]( int d , int i ){ offset[d] = i , _offset[d] = i-_LeftRadii[d]; } , [&]( void ){ leaves( offset ) = GetNeighborLeaf( depth , index , _offset ); } ); -} \ No newline at end of file +} diff --git a/Src/SSDRecon.cpp b/Src/SSDRecon.cpp index 56619855..3facf0ff 100644 --- a/Src/SSDRecon.cpp +++ b/Src/SSDRecon.cpp @@ -352,13 +352,13 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( Transform.set ) { FILE* fp = fopen( Transform.value , "r" ); - if( !fp ) WARN( "Could not read x-form from: " , Transform.value ); + if( !fp ) MK_WARN( "Could not read x-form from: " , Transform.value ); else { for( int i=0 ; i::WriteParameter( fs ); DenseNodeData< Real , Sigs >::WriteSignatures( fs ); @@ -527,7 +527,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) if constexpr( HasAuxData ) WriteMesh< Real , Dim , FEMSig >( Gradients.set , Density.set , InCore.set , *implicit , meParams , Out.value , ASCII.set , auxDataFactory ); else WriteMesh< Real , Dim , FEMSig >( Gradients.set , Density.set , InCore.set , *implicit , meParams , Out.value , ASCII.set ); } - else WARN( "Mesh extraction is only supported in dimensions 2 and 3" ); + else MK_WARN( "Mesh extraction is only supported in dimensions 2 and 3" ); if( Verbose.set ) std::cout << "# Total Solve: " << Time()-startTime << " (s), " << MemoryInfo::PeakMemoryUsageMB() << " (MB)" << std::endl; delete implicit; @@ -542,7 +542,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) case 2: return Execute< Real , Dim , FEMDegreeAndBType< 2 , BType >::Signature >( auxDataFactory ); case 3: return Execute< Real , Dim , FEMDegreeAndBType< 3 , BType >::Signature >( auxDataFactory ); // case 4: return Execute< Real , Dim , FEMDegreeAndBType< 4 , BType >::Signature >( auxDataFactory ); - default: ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); + default: MK_ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); } } @@ -554,7 +554,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) case BOUNDARY_FREE+1: return Execute< Dim , Real , BOUNDARY_FREE >( auxDataFactory ); case BOUNDARY_NEUMANN+1: return Execute< Dim , Real , BOUNDARY_NEUMANN >( auxDataFactory ); case BOUNDARY_DIRICHLET+1: return Execute< Dim , Real , BOUNDARY_DIRICHLET >( auxDataFactory ); - default: ERROR_OUT( "Not a valid boundary type: " , BType.value ); + default: MK_ERROR_OUT( "Not a valid boundary type: " , BType.value ); } } #endif // !FAST_COMPILE @@ -563,7 +563,7 @@ int main( int argc , char* argv[] ) { Timer timer; #ifdef ARRAY_DEBUG - WARN( "Array debugging enabled" ); + MK_WARN( "Array debugging enabled" ); #endif // ARRAY_DEBUG CmdLineParse( argc-1 , &argv[1] , params ); @@ -577,8 +577,8 @@ int main( int argc , char* argv[] ) ShowUsage( argv[0] ); return 0; } - if( GradientWeight.value<=0 ) ERROR_OUT( "Gradient weight must be positive: " , GradientWeight.value , "> 0" ); - if( BiLapWeight.value<=0 ) ERROR_OUT( "Bi-Laplacian weight must be positive: " , BiLapWeight.value , " > 0" ); + if( GradientWeight.value<=0 ) MK_ERROR_OUT( "Gradient weight must be positive: " , GradientWeight.value , "> 0" ); + if( BiLapWeight.value<=0 ) MK_ERROR_OUT( "Bi-Laplacian weight must be positive: " , BiLapWeight.value , " > 0" ); ValueWeight.value *= (float)Reconstructor::SSD::WeightMultipliers[0]; GradientWeight.value *= (float)Reconstructor::SSD::WeightMultipliers[1]; @@ -595,7 +595,7 @@ int main( int argc , char* argv[] ) static const BoundaryType BType = Reconstructor::SSD::DefaultFEMBoundary; static const unsigned int Dim = DEFAULT_DIMENSION; static const unsigned int FEMSig = FEMDegreeAndBType< Degree , BType >::Signature; - WARN( "Compiled for degree-" , Degree , ", boundary-" , BoundaryNames[ BType ] , ", " , sizeof(Real)==4 ? "single" : "double" , "-precision _only_" ); + MK_WARN( "Compiled for degree-" , Degree , ", boundary-" , BoundaryNames[ BType ] , ", " , sizeof(Real)==4 ? "single" : "double" , "-precision _only_" ); char *ext = GetFileExtension( In.value ); if( !strcasecmp( ext , "ply" ) ) @@ -605,8 +605,8 @@ int main( int argc , char* argv[] ) bool *readFlags = new bool[ factory.plyReadNum() ]; std::vector< PlyProperty > unprocessedProperties; PLY::ReadVertexHeader( In.value , factory , readFlags , unprocessedProperties ); - if( !factory.template plyValidReadProperties<0>( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); - if( !factory.template plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain normals" ); + if( !factory.template plyValidReadProperties<0>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain positions" ); + if( !factory.template plyValidReadProperties<1>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain normals" ); delete[] readFlags; if( unprocessedProperties.size() ) Execute< Real , Dim , FEMSig >( VertexFactory::DynamicFactory< Real >( unprocessedProperties ) ); @@ -627,8 +627,8 @@ int main( int argc , char* argv[] ) bool *readFlags = new bool[ factory.plyReadNum() ]; std::vector< PlyProperty > unprocessedProperties; PLY::ReadVertexHeader( In.value , factory , readFlags , unprocessedProperties ); - if( !factory.template plyValidReadProperties<0>( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); - if( !factory.template plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain normals" ); + if( !factory.template plyValidReadProperties<0>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain positions" ); + if( !factory.template plyValidReadProperties<1>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain normals" ); delete[] readFlags; if( unprocessedProperties.size() ) Execute< DEFAULT_DIMENSION , Real >( VertexFactory::DynamicFactory< Real >( unprocessedProperties ) ); diff --git a/Src/ScaleNormals.cpp b/Src/ScaleNormals.cpp index cfb367db..8ad6f35a 100644 --- a/Src/ScaleNormals.cpp +++ b/Src/ScaleNormals.cpp @@ -124,9 +124,9 @@ void Execute( void ) std::vector< PlyProperty > unprocessedProperties; PLY::ReadVertexHeader( In.value , factory , readFlags , unprocessedProperties ); - if( !factory.template plyValidReadProperties<0>( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); - if( !factory.template plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain normals" ); - if( !factory.template plyValidReadProperties<2>( readFlags ) ) ERROR_OUT( "Ply file does not contain scales" ); + if( !factory.template plyValidReadProperties<0>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain positions" ); + if( !factory.template plyValidReadProperties<1>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain normals" ); + if( !factory.template plyValidReadProperties<2>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain scales" ); delete[] readFlags; if( Verbose.set && unprocessedProperties.size() ) @@ -157,7 +157,7 @@ int main( int argc , char* argv[] ) } if( ConfidenceNames.count!=ConfidenceExponents.count ) - ERROR_OUT( "Number of confidence names and exponents does not match: " , ConfidenceNames.count , " != " , ConfidenceExponents.count ); + MK_ERROR_OUT( "Number of confidence names and exponents does not match: " , ConfidenceNames.count , " != " , ConfidenceExponents.count ); if( Verbose.set ) { diff --git a/Src/Socket.h b/Src/Socket.h index 667c0af5..7a20270b 100644 --- a/Src/Socket.h +++ b/Src/Socket.h @@ -59,7 +59,7 @@ namespace PoissonRecon { boost::system::error_code ec; int ret = (int)( boost::asio::read( *s , boost::asio::buffer( destination , len ) , ec ) ); - if( ec ) ERROR_OUT( "Failed to read from socket" ); + if( ec ) MK_ERROR_OUT( "Failed to read from socket" ); return ret; } @@ -67,7 +67,7 @@ namespace PoissonRecon { boost::system::error_code ec; int ret = (int)( boost::asio::write( *s , boost::asio::buffer( source , len ) , ec ) ); - if( ec ) ERROR_OUT( "Failed to write to socket" ); + if( ec ) MK_ERROR_OUT( "Failed to write to socket" ); return ret; } @@ -91,14 +91,14 @@ namespace PoissonRecon int socket_receive( Socket& s , Array< C > destination , size_t len ) { if( len>destination.maximum()*sizeof( C ) ) - ERROR_OUT( "Size of socket_receive exceeds destination maximum: " , len , " > " , destination.maximum()*sizeof( C ) ); + MK_ERROR_OUT( "Size of socket_receive exceeds destination maximum: " , len , " > " , destination.maximum()*sizeof( C ) ); return socket_receive( s , (char*)&destination[0] , len ); } template< class C > int socket_send( Socket s , ConstArray< C > source , size_t len ) { if( len>source.maximum()*sizeof( C ) ) - ERROR_OUT( "Size of socket_send exceeds source maximum: " , len , " > " , source.maximum()*sizeof( C ) ); + MK_ERROR_OUT( "Size of socket_send exceeds source maximum: " , len , " > " , source.maximum()*sizeof( C ) ); return socket_send( s , (char*)&source[0] , len ); } #endif // ARRAY_DEBUG diff --git a/Src/Socket.inl b/Src/Socket.inl index 09c17c58..b064fb92 100644 --- a/Src/Socket.inl +++ b/Src/Socket.inl @@ -30,7 +30,7 @@ template bool ReceiveOnSocket( Socket& s , Pointer( C ) data , size_t dataSize ) { #ifdef ARRAY_DEBUG - if( dataSize>data.maximum()*sizeof( C ) ) ERROR_OUT( "Size of socket read exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); + if( dataSize>data.maximum()*sizeof( C ) ) MK_ERROR_OUT( "Size of socket read exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); #endif // ARRAY_DEBUG unsigned long long rec=0; while( rec!=dataSize ) @@ -38,8 +38,8 @@ bool ReceiveOnSocket( Socket& s , Pointer( C ) data , size_t dataSize ) int tmp = socket_receive( s , ( ( Pointer( char ) ) data) + rec , dataSize-rec ); if( tmp<=0 ) { - if( !tmp ) ERROR_OUT( "Connection Closed" ); - else ERROR_OUT( "socket_receive from client failed: " , LastSocketError() ); + if( !tmp ) MK_ERROR_OUT( "Connection Closed" ); + else MK_ERROR_OUT( "socket_receive from client failed: " , LastSocketError() ); return false; } rec+=tmp; @@ -51,11 +51,11 @@ template bool SendOnSocket( Socket& s , ConstPointer( C ) data , size_t dataSize ) { #ifdef ARRAY_DEBUG - if( dataSize>data.maximum()*sizeof( C ) ) ERROR_OUT( "Size of socket write exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); + if( dataSize>data.maximum()*sizeof( C ) ) MK_ERROR_OUT( "Size of socket write exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); #endif // ARRAY_DEBUG if( socket_send( s , ( ConstPointer( char ) )data , dataSize )<0 ) { - ERROR_OUT( "socket_send to client failed (" , s , "): " , LastSocketError() ); + MK_ERROR_OUT( "socket_send to client failed (" , s , "): " , LastSocketError() ); return false; } return true; @@ -68,7 +68,7 @@ template void ReceiveOnSocket( Socket& s , Pointer( C ) data , size_t dataSize , const char* errorMessage , ... ) { #ifdef ARRAY_DEBUG - if( dataSize>data.maximum()*sizeof( C ) ) ERROR_OUT( "Size of socket read exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); + if( dataSize>data.maximum()*sizeof( C ) ) MK_ERROR_OUT( "Size of socket read exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); #endif // ARRAY_DEBUG unsigned long long rec=0; while( rec!=dataSize ) @@ -76,8 +76,8 @@ void ReceiveOnSocket( Socket& s , Pointer( C ) data , size_t dataSize , const ch int tmp = socket_receive( s , ( ( Pointer( char ) ) data) + rec , dataSize-rec ); if( tmp<=0 ) { - if( !tmp ) ERROR_OUT( "Connection Closed" ); - else ERROR_OUT( "socket_receive from client failed: " , LastSocketError() ); + if( !tmp ) MK_ERROR_OUT( "Connection Closed" ); + else MK_ERROR_OUT( "socket_receive from client failed: " , LastSocketError() ); { fprintf( stderr , "\t" ); va_list args; @@ -96,20 +96,20 @@ template void SendOnSocket( Socket& s , ConstPointer( C ) data , size_t dataSize , const char* errorMessage , ... ) { #ifdef ARRAY_DEBUG - if( dataSize>data.maximum()*sizeof( C ) ) ERROR_OUT( "Size of socket write exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); + if( dataSize>data.maximum()*sizeof( C ) ) MK_ERROR_OUT( "Size of socket write exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); #endif // ARRAY_DEBUG if( socket_send( s , ( ConstPointer( char ) )data , dataSize )<0 ) - ERROR_OUT( "socket_send to client failed: " , LastSocketError() ); + MK_ERROR_OUT( "socket_send to client failed: " , LastSocketError() ); } template void SendOnSocket( Socket& s , Pointer( C ) data , size_t dataSize , const char* errorMessage , ... ) { #ifdef ARRAY_DEBUG - if( dataSize>data.maximum()*sizeof( C ) ) ERROR_OUT( "Size of socket write exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); + if( dataSize>data.maximum()*sizeof( C ) ) MK_ERROR_OUT( "Size of socket write exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); #endif // ARRAY_DEBUG if( socket_send( s , ( ConstPointer( char ) )data , dataSize )<0 ) - ERROR_OUT( "socket_send to client failed: " , LastSocketError() ); + MK_ERROR_OUT( "socket_send to client failed: " , LastSocketError() ); } inline bool GetHostEndpointAddress( EndpointAddress* address , const char* prefix ) diff --git a/Src/SparseMatrix.inl b/Src/SparseMatrix.inl index 8b897a22..136ac15c 100644 --- a/Src/SparseMatrix.inl +++ b/Src/SparseMatrix.inl @@ -166,7 +166,7 @@ void SparseMatrix< T , IndexType , 0 >::setRowSize( size_t row , size_t count ) } rowSizes[row] = count; } - else ERROR_OUT( "Row is out of bounds: 0 <= " , row , " < " , rowNum ); + else MK_ERROR_OUT( "Row is out of bounds: 0 <= " , row , " < " , rowNum ); } template< class T , class IndexType > void SparseMatrix< T , IndexType , 0 >::resetRowSize( size_t row , size_t count ) @@ -178,7 +178,7 @@ void SparseMatrix< T , IndexType , 0 >::resetRowSize( size_t row , size_t count if( count>oldCount ) memset( _entries[row]+oldCount , 0 , sizeof( MatrixEntry< T , IndexType > ) * ( count - oldCount ) ); rowSizes[row] = count; } - else ERROR_OUT( "Row is out of bounds: 0 <= " , row , " < " , rowNum ); + else MK_ERROR_OUT( "Row is out of bounds: 0 <= " , row , " < " , rowNum ); } template< class T , class IndexType > @@ -235,7 +235,7 @@ SparseMatrix< T , IndexType , 0 > SparseMatrix< T , IndexType , 0 >::operator * size_t bCols = 0 , bRows = B.rowNum; for( size_t i=0 ; i SparseMatrix< T , IndexType , 0 >::transpose( const SparseMatrix& At = *this; size_t _aRows = 0 , aCols = At.rowNum; for( size_t i=0 ; iaRows ) ERROR_OUT( "Prescribed output dimension too low: " , aRows , " < " , _aRows ); + if( _aRows>aRows ) MK_ERROR_OUT( "Prescribed output dimension too low: " , aRows , " < " , _aRows ); A.resize( aRows ); for( size_t i=0 ; i SparseMatrix< T , IndexType , 0 >::Multiply( c size_t bCols = 0 , bRows = B.rows(); for( size_t i=0 ; iN ) aCols = iter->N+1; for( size_t i=0 ; iN ) bCols = iter->N+1; - if( bRows SparseMatrix< T , IndexType , 0 >::Transpose( SparseMatrix< T , IndexType , 0 > A; size_t _aRows = 0 , aCols = At.rows() , aRows = outRows; for( size_t i=0 ; iN ) _aRows = iter->N+1; - if( _aRows>aRows ) ERROR_OUT( "Prescribed output dimension too low: " , aRows , " < " , _aRows ); + if( _aRows>aRows ) MK_ERROR_OUT( "Prescribed output dimension too low: " , aRows , " < " , _aRows ); A.resize( aRows ); for( size_t i=0 ; i::resize( size_t rowNum ) template< class T , class IndexType , size_t MaxRowSize > void SparseMatrix< T , IndexType , MaxRowSize >::setRowSize( size_t row , size_t rowSize ) { - if( row>=_rowNum ) ERROR_OUT( "Row is out of bounds: 0 <= " , row , " < " , _rowNum ); - else if( rowSize>MaxRowSize ) ERROR_OUT( "Row size larger than max row size: " , rowSize , " < " , MaxRowSize ); + if( row>=_rowNum ) MK_ERROR_OUT( "Row is out of bounds: 0 <= " , row , " < " , _rowNum ); + else if( rowSize>MaxRowSize ) MK_ERROR_OUT( "Row size larger than max row size: " , rowSize , " < " , MaxRowSize ); else _rowSizes[row] = rowSize; } template< class T , class IndexType , size_t MaxRowSize > void SparseMatrix< T , IndexType , MaxRowSize >::resetRowSize( size_t row , size_t rowSize ) { - if( row>=_rowNum ) ERROR_OUT( "Row is out of bounds: 0 <= " , row , " < " , _rowNum ); - else if( rowSize>MaxRowSize ) ERROR_OUT( "Row size larger than max row size: " , rowSize , " < " , MaxRowSize ); + if( row>=_rowNum ) MK_ERROR_OUT( "Row is out of bounds: 0 <= " , row , " < " , _rowNum ); + else if( rowSize>MaxRowSize ) MK_ERROR_OUT( "Row size larger than max row size: " , rowSize , " < " , MaxRowSize ); else _rowSizes[row] = rowSize; } diff --git a/Src/SurfaceTrimmer.cpp b/Src/SurfaceTrimmer.cpp index 07c7f55c..0dc04e5c 100644 --- a/Src/SurfaceTrimmer.cpp +++ b/Src/SurfaceTrimmer.cpp @@ -101,7 +101,7 @@ struct ComponentGraph nodes.pop_back(); }; - if( !neighbors.size() ) ERROR_OUT( "No neighbors" ); + if( !neighbors.size() ) MK_ERROR_OUT( "No neighbors" ); // Remove the node from the neighbors of the neighbors for( unsigned int i=0 ; ineighbors.size()-1 ; j>=0 ; j-- ) if( neighbors[i]->neighbors[j]==this ) @@ -148,10 +148,10 @@ struct ComponentGraph for( auto iter=flags.begin() ; iter!=flags.end() ; iter++ ) for( unsigned int j=0 ; jfirst->neighbors.size() ; j++ ) { - if( iter->second==flags[ iter->first->neighbors[j] ] ) ERROR_OUT( "Not a bipartite graph" ); + if( iter->second==flags[ iter->first->neighbors[j] ] ) MK_ERROR_OUT( "Not a bipartite graph" ); bool foundSelf = false; for( unsigned int k=0 ; kfirst->neighbors[j]->neighbors.size() ; k++ ) if( iter->first->neighbors[j]->neighbors[k]==iter->first ) foundSelf = true; - if( !foundSelf ) ERROR_OUT( "Asymmetric graph" ); + if( !foundSelf ) MK_ERROR_OUT( "Asymmetric graph" ); } } @@ -581,11 +581,11 @@ int main( int argc , char* argv[] ) PLY::ReadVertexHeader( In.value , factory , readFlags , unprocessedProperties , vNum ); if( vNum>std::numeric_limits< int >::max() ) { - if( !Long.set ) WARN( "Number of vertices not supported by 32-bit indexing. Switching to 64-bit indexing" ); + if( !Long.set ) MK_WARN( "Number of vertices not supported by 32-bit indexing. Switching to 64-bit indexing" ); Long.set = true; } - if( !factory.template plyValidReadProperties<0>( readFlags ) ) ERROR_OUT( "Ply file does not contain positions" ); - if( !factory.template plyValidReadProperties<1>( readFlags ) ) ERROR_OUT( "Ply file does not contain values" ); + if( !factory.template plyValidReadProperties<0>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain positions" ); + if( !factory.template plyValidReadProperties<1>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain values" ); delete[] readFlags; if( Long.set ) return Execute< Real , Dim , long long >( VertexFactory::DynamicFactory< Real >( unprocessedProperties ) ); diff --git a/Src/VertexFactory.h b/Src/VertexFactory.h index c39ef78a..4998e1b2 100644 --- a/Src/VertexFactory.h +++ b/Src/VertexFactory.h @@ -129,16 +129,16 @@ namespace PoissonRecon unsigned int plyReadNum( void ) const { return 0; } unsigned int plyWriteNum( void ) const { return 0; } bool plyValidReadProperties( const bool *flags ) const { return true ; } - PlyProperty plyReadProperty( unsigned int idx ) const { if( idx>= plyReadNum() ) ERROR_OUT( "read property out of bounds" ) ; return PlyProperty(); } - PlyProperty plyWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ) ; return PlyProperty(); } + PlyProperty plyReadProperty( unsigned int idx ) const { if( idx>= plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ) ; return PlyProperty(); } + PlyProperty plyWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ) ; return PlyProperty(); } bool readASCII( FILE *fp , VertexType &dt ) const { return true; } bool readBinary( FILE *fp , VertexType &dt ) const { return true; } void writeASCII( FILE *fp , const VertexType &dt ) const {} void writeBinary( FILE *fp , const VertexType &dt ) const {}; bool isStaticallyAllocated( void ) const{ return true; } - PlyProperty plyStaticReadProperty( unsigned int idx ) const { if( idx>= plyReadNum() ) ERROR_OUT( "read property out of bounds" ) ; return PlyProperty(); } - PlyProperty plyStaticWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ) ; return PlyProperty(); } + PlyProperty plyStaticReadProperty( unsigned int idx ) const { if( idx>= plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ) ; return PlyProperty(); } + PlyProperty plyStaticWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ) ; return PlyProperty(); } size_t bufferSize( void ) const { return 0; } void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const {} @@ -484,8 +484,8 @@ namespace PoissonRecon void writeBinary( FILE *fp , const VertexType &dt ) const; bool isStaticallyAllocated( void ) const{ return false; } - PlyProperty plyStaticReadProperty( unsigned int idx ) const { ERROR_OUT( "does not support static allocation" ) ; return PlyProperty(); } - PlyProperty plyStaticWriteProperty( unsigned int idx ) const { ERROR_OUT( "does not support static allocation" ) ; return PlyProperty(); } + PlyProperty plyStaticReadProperty( unsigned int idx ) const { MK_ERROR_OUT( "does not support static allocation" ) ; return PlyProperty(); } + PlyProperty plyStaticWriteProperty( unsigned int idx ) const { MK_ERROR_OUT( "does not support static allocation" ) ; return PlyProperty(); } size_t size( void ) const { return _namesAndTypesOnDisk.size(); } @@ -577,8 +577,8 @@ namespace PoissonRecon template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , bool >::type _plyValidReadProperties( const bool *flags ) const { return true; } template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , PlyProperty >::type _plyReadProperty( unsigned int idx , size_t offset ) const; template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , PlyProperty >::type _plyWriteProperty( unsigned int idx , size_t offset ) const; - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyReadProperty( unsigned int idx , size_t offset ) const { ERROR_OUT( "read property out of bounds" ) ; return PlyProperty(); } - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyWriteProperty( unsigned int idx , size_t offset ) const { ERROR_OUT( "write property out of bounds" ) ; return PlyProperty(); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyReadProperty( unsigned int idx , size_t offset ) const { MK_ERROR_OUT( "read property out of bounds" ) ; return PlyProperty(); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyWriteProperty( unsigned int idx , size_t offset ) const { MK_ERROR_OUT( "write property out of bounds" ) ; return PlyProperty(); } template< unsigned int I > typename std::enable_if< I==0 , unsigned int >::type _readOffset( void ) const { return 0; } template< unsigned int I > typename std::enable_if< I!=0 , unsigned int >::type _readOffset( void ) const { return _readOffset< I-1 >() + get< I-1 >().plyReadNum(); } template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , bool >::type _readASCII( FILE *fp , VertexType &dt ) const { return this->template get().readASCII( fp , dt.template get() ) && _readASCII< I+1 >( fp , dt ); } @@ -594,8 +594,8 @@ namespace PoissonRecon template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , bool >::type _isStaticallyAllocated( void ) const { return true; } template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , PlyProperty >::type _plyStaticReadProperty ( unsigned int idx ) const; template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , PlyProperty >::type _plyStaticWriteProperty( unsigned int idx ) const; - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyStaticReadProperty ( unsigned int idx ) const { ERROR_OUT( "read property out of bounds" ) ; return PlyProperty(); } - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyStaticWriteProperty( unsigned int idx ) const { ERROR_OUT( "write property out of bounds" ) ; return PlyProperty(); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyStaticReadProperty ( unsigned int idx ) const { MK_ERROR_OUT( "read property out of bounds" ) ; return PlyProperty(); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyStaticWriteProperty( unsigned int idx ) const { MK_ERROR_OUT( "write property out of bounds" ) ; return PlyProperty(); } template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , size_t >::type _bufferSize( void ) const { return this->template get().bufferSize() + _bufferSize< I+1 >(); } template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , size_t >::type _bufferSize( void ) const { return 0; } diff --git a/Src/VertexFactory.inl b/Src/VertexFactory.inl index 92ea6439..354f91ca 100644 --- a/Src/VertexFactory.inl +++ b/Src/VertexFactory.inl @@ -46,7 +46,7 @@ namespace VertexFactory case TypeOnDisk::UINT_32: return PLY::Type< uint32_t >(); case TypeOnDisk::INT_64: return PLY::Type< int64_t >(); case TypeOnDisk::UINT_64: return PLY::Type< uint64_t >(); - default: ERROR_OUT( "Unrecognized type: " , typeOnDisk ); + default: MK_ERROR_OUT( "Unrecognized type: " , typeOnDisk ); } return -1; } @@ -71,7 +71,7 @@ namespace VertexFactory case PLY_UINT_64: return TypeOnDisk::UINT_64; case PLY_FLOAT_32: return TypeOnDisk::FLOAT; case PLY_FLOAT_64: return TypeOnDisk::DOUBLE; - default: ERROR_OUT( "Unrecognized type: " , plyType ); + default: MK_ERROR_OUT( "Unrecognized type: " , plyType ); } return TypeOnDisk::UNKNOWN; } @@ -92,7 +92,7 @@ namespace VertexFactory else if constexpr( std::is_same< Type , uint64_t >::value ) return TypeOnDisk::UINT_64; else if constexpr( std::is_same< Type , float >::value ) return TypeOnDisk::FLOAT; else if constexpr( std::is_same< Type , double >::value ) return TypeOnDisk::DOUBLE; - else ERROR_OUT( "Unrecognized type" ); + else MK_ERROR_OUT( "Unrecognized type" ); return TypeOnDisk::UNKNOWN; } @@ -139,7 +139,7 @@ namespace VertexFactory case TypeOnDisk::UINT_32: return _ReadBinary< uint32_t >( fp , s ); case TypeOnDisk::INT_64: return _ReadBinary< int64_t >( fp , s ); case TypeOnDisk::UINT_64: return _ReadBinary< uint64_t >( fp , s ); - default: ERROR_OUT( "Unrecognized type: " , typeOnDisk ); + default: MK_ERROR_OUT( "Unrecognized type: " , typeOnDisk ); } return true; } @@ -162,7 +162,7 @@ namespace VertexFactory case TypeOnDisk::UINT_32: fprintf( fp , " %" PRIu32 , ( uint32_t)s ) ; break; case TypeOnDisk::INT_64: fprintf( fp , " %" PRId64 , ( int64_t)s ) ; break; case TypeOnDisk::UINT_64: fprintf( fp , " %" PRIu64 , ( uint64_t)s ) ; break; - default: ERROR_OUT( "Unrecongized type: " , typeOnDisk ); + default: MK_ERROR_OUT( "Unrecongized type: " , typeOnDisk ); } } @@ -186,7 +186,7 @@ namespace VertexFactory case TypeOnDisk::UINT_32: _WriteBinary< uint32_t >( fp , s ) ; break; case TypeOnDisk::INT_64: _WriteBinary< int64_t >( fp , s ) ; break; case TypeOnDisk::UINT_64: _WriteBinary< uint64_t >( fp , s ) ; break; - default: ERROR_OUT( "Unrecongized type: " , typeOnDisk ); + default: MK_ERROR_OUT( "Unrecongized type: " , typeOnDisk ); } } @@ -223,26 +223,26 @@ namespace VertexFactory template< typename Real , unsigned int Dim > PlyProperty PositionFactory< Real , Dim >::plyReadProperty( unsigned int idx ) const { - if( idx>= plyReadNum() ) ERROR_OUT( "read property out of bounds" ); + if( idx>= plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real , unsigned int Dim > PlyProperty PositionFactory< Real , Dim >::plyWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real , unsigned int Dim > PlyProperty PositionFactory< Real , Dim >::plyStaticReadProperty( unsigned int idx ) const { - if( idx>=plyReadNum() ) ERROR_OUT( "read property out of bounds" ); + if( idx>=plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); } template< typename Real , unsigned int Dim > PlyProperty PositionFactory< Real , Dim >::plyStaticWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); } @@ -259,26 +259,26 @@ namespace VertexFactory template< typename Real , unsigned int Dim > PlyProperty NormalFactory< Real , Dim >::plyReadProperty( unsigned int idx ) const { - if( idx>= plyReadNum() ) ERROR_OUT( "read property out of bounds" ); + if( idx>= plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real , unsigned int Dim > PlyProperty NormalFactory< Real , Dim >::plyWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real , unsigned int Dim > PlyProperty NormalFactory< Real , Dim >::plyStaticReadProperty( unsigned int idx ) const { - if( idx>=plyReadNum() ) ERROR_OUT( "read property out of bounds" ); + if( idx>=plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); } template< typename Real , unsigned int Dim > PlyProperty NormalFactory< Real , Dim >::plyStaticWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); } @@ -295,26 +295,26 @@ namespace VertexFactory template< typename Real , unsigned int Dim > PlyProperty TextureFactory< Real , Dim >::plyReadProperty( unsigned int idx ) const { - if( idx>= plyReadNum() ) ERROR_OUT( "read property out of bounds" ); + if( idx>= plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real , unsigned int Dim > PlyProperty TextureFactory< Real , Dim >::plyWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real , unsigned int Dim > PlyProperty TextureFactory< Real , Dim >::plyStaticReadProperty( unsigned int idx ) const { - if( idx>=plyReadNum() ) ERROR_OUT( "read property out of bounds" ); + if( idx>=plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); } template< typename Real , unsigned int Dim > PlyProperty TextureFactory< Real , Dim >::plyStaticWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); } @@ -331,26 +331,26 @@ namespace VertexFactory template< typename Real > PlyProperty RGBColorFactory< Real >::plyReadProperty( unsigned int idx ) const { - if( idx>= plyReadNum() ) ERROR_OUT( "read property out of bounds" ); + if( idx>= plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real > PlyProperty RGBColorFactory< Real >::plyWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real > PlyProperty RGBColorFactory< Real >::plyStaticReadProperty( unsigned int idx ) const { - if( idx>=plyReadNum() ) ERROR_OUT( "read property out of bounds" ); + if( idx>=plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + (idx%3)*sizeof(Real) ) ); } template< typename Real > PlyProperty RGBColorFactory< Real >::plyStaticWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); } @@ -367,28 +367,28 @@ namespace VertexFactory template< typename Real > PlyProperty RGBAColorFactory< Real >::plyReadProperty( unsigned int idx ) const { - if( idx>= plyReadNum() ) ERROR_OUT( "read property out of bounds" ); + if( idx>= plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real > PlyProperty RGBAColorFactory< Real >::plyWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real > PlyProperty RGBAColorFactory< Real >::plyStaticReadProperty( unsigned int idx ) const { - if( idx>=plyReadNum() ) ERROR_OUT( "read property out of bounds" ); + if( idx>=plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + (idx%4)*sizeof(Real) ) ); } template< typename Real > PlyProperty RGBAColorFactory< Real >::plyStaticWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); } @@ -405,28 +405,28 @@ namespace VertexFactory template< typename Real > PlyProperty ValueFactory< Real >::plyReadProperty( unsigned int idx ) const { - if( idx>= plyReadNum() ) ERROR_OUT( "read property out of bounds" ); + if( idx>= plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real > PlyProperty ValueFactory< Real >::plyWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real > PlyProperty ValueFactory< Real >::plyStaticReadProperty( unsigned int idx ) const { - if( idx>=plyReadNum() ) ERROR_OUT( "read property out of bounds" ); + if( idx>=plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , 0 ); } template< typename Real > PlyProperty ValueFactory< Real >::plyStaticWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , 0 ); } @@ -451,7 +451,7 @@ namespace VertexFactory { for( int i=0 ; i( plyProperties[i].name , FromPlyType( plyProperties[i].external_type ) ) ); - else WARN( "List property not supported: " , plyProperties[i].name ); + else MK_WARN( "List property not supported: " , plyProperties[i].name ); _realTypeOnDisk = true; for( unsigned int i=0 ; i<_namesAndTypesOnDisk.size() ; i++ ) _realTypeOnDisk &= GetTypeOnDisk< Real>()!=_namesAndTypesOnDisk[i].second; } @@ -490,13 +490,13 @@ namespace VertexFactory template< typename Real > PlyProperty DynamicFactory< Real >::plyReadProperty( unsigned int idx ) const { - if( idx>=plyReadNum() ) ERROR_OUT( "read property out of bounds" ); + if( idx>=plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); return PlyProperty( _namesAndTypesOnDisk[idx].first , ToPlyType( _namesAndTypesOnDisk[idx].second ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real > PlyProperty DynamicFactory< Real >::plyWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); return PlyProperty( _namesAndTypesOnDisk[idx].first , ToPlyType( _namesAndTypesOnDisk[idx].second ) , PLY::Type< Real >() , sizeof(Real)*idx ); } diff --git a/Src/Window.h b/Src/Window.h index 0b4452c2..6ff5cc45 100644 --- a/Src/Window.h +++ b/Src/Window.h @@ -30,424 +30,309 @@ DAMAGE. #define WINDOW_INCLUDED #include -#include "MyMiscellany.h" -#include "Allocator.h" #include "Array.h" +#include "ParameterPack.h" +#include "MultiThreading.h" -namespace PoissonRecon +namespace Window { + using namespace PoissonRecon; + template< unsigned int Res , unsigned int ... Ress > + constexpr unsigned int Size( void ) + { + if constexpr( sizeof...(Ress)==0 ) return Res; + else return Res * Size< Ress... >(); + } - ////////////////////////////////////////////////////////// - // Some basic functionality for integer parameter packs // - ////////////////////////////////////////////////////////// - - // A wrapper class for passing unsigned integer parameter packs - template< unsigned int ... Values > struct UIntPack{}; - template< unsigned int _Value , unsigned int ... _Values > struct UIntPack< _Value , _Values ... > + template< unsigned int Dim , unsigned int Res > + constexpr unsigned int IsotropicSize( void ) { - static const unsigned int First = _Value; - typedef UIntPack< _Values ... > Rest; - - static const unsigned int Size = 1 + sizeof ... ( _Values ); - template< unsigned int __Value > using Append = UIntPack< _Value , _Values ... , __Value >; - template< unsigned int __Value > using Prepend = UIntPack< __Value , _Value , _Values ... >; - static const unsigned int Values[]; - static constexpr unsigned int Min( void ){ return _Value < Rest::Min() ? _Value : Rest::Min(); } - static constexpr unsigned int Max( void ){ return _Value > Rest::Max() ? _Value : Rest::Max(); } - - using Reverse = typename Rest::Reverse::template Append< First >; - - template< typename T > struct Plus{}; - template< typename T > struct Minus{}; - template< typename T > struct Compare{}; - template< unsigned int __Value , unsigned int ... __Values > struct Plus < UIntPack< __Value , __Values ... > >{ typedef typename Rest::template Plus < UIntPack< __Values ... > >::type::template Prepend< _Value + __Value > type; }; - template< unsigned int __Value , unsigned int ... __Values > struct Minus< UIntPack< __Value , __Values ... > >{ typedef typename Rest::template Minus< UIntPack< __Values ... > >::type::template Prepend< _Value - __Value > type; }; - template< unsigned int __Value , unsigned int ... __Values > struct Compare< UIntPack< __Value , __Values ... > > - { - static const bool Equal = _Value==__Value && Rest::template Compare< UIntPack< __Values ... > >:: Equal; - static const bool NotEqual = _Value!=__Value || Rest::template Compare< UIntPack< __Values ... > >:: NotEqual; - static const bool LessThan = _Value< __Value && Rest::template Compare< UIntPack< __Values ... > >:: LessThan ; - static const bool LessThanOrEqual = _Value<=__Value && Rest::template Compare< UIntPack< __Values ... > >:: LessThanOrEqual; - static const bool GreaterThan = _Value> __Value && Rest::template Compare< UIntPack< __Values ... > >::GreaterThan ; - static const bool GreaterThanOrEqual = _Value>=__Value && Rest::template Compare< UIntPack< __Values ... > >::GreaterThanOrEqual; - }; - - static void Print( FILE* fp=stdout , bool leadingSpace=false ){ if( leadingSpace ) fprintf( fp , " " ) ; fprintf( fp , "%d" , _Value ) ; Rest::Print( fp , true ); } - - template< unsigned int I > constexpr static typename std::enable_if< I==0 , unsigned int >::type Get( void ){ return _Value; } - template< unsigned int I > constexpr static typename std::enable_if< I!=0 , unsigned int >::type Get( void ){ return Rest::template Get< I-1 >(); } - - template< unsigned int __Value , unsigned int ... __Values > constexpr bool operator < ( UIntPack< __Value , __Values ... > ) const { return _Value< __Value && Rest()< UIntPack< __Values ... >(); } - template< unsigned int __Value , unsigned int ... __Values > constexpr bool operator <= ( UIntPack< __Value , __Values ... > ) const { return _Value<=__Value && Rest()<=UIntPack< __Values ... >(); } - template< unsigned int __Value , unsigned int ... __Values > constexpr bool operator > ( UIntPack< __Value , __Values ... > ) const { return _Value> __Value && Rest()> UIntPack< __Values ... >(); } - template< unsigned int __Value , unsigned int ... __Values > constexpr bool operator >= ( UIntPack< __Value , __Values ... > ) const { return _Value>=__Value && Rest()>=UIntPack< __Values ... >(); } - template< unsigned int __Value , unsigned int ... __Values > constexpr bool operator == ( UIntPack< __Value , __Values ... > ) const { return _Value==__Value && Rest()==UIntPack< __Values ... >(); } - template< unsigned int __Value , unsigned int ... __Values > constexpr bool operator != ( UIntPack< __Value , __Values ... > ) const { return _Value!=__Value && Rest()!=UIntPack< __Values ... >(); } - }; + if constexpr( Dim==1 ) return Res; + else return Res * IsotropicSize< Dim-1 , Res >(); + } - template< unsigned int _Value > struct UIntPack< _Value > + template< unsigned int Res , unsigned int ... Ress > + struct Index { - static const unsigned int First = _Value; - - static const unsigned int Size = 1; - template< unsigned int __Value > using Append = UIntPack< _Value , __Value >; - template< unsigned int __Value > using Prepend = UIntPack< __Value , _Value >; - static const unsigned int Values[]; - static constexpr unsigned int Min( void ){ return _Value; } - static constexpr unsigned int Max( void ){ return _Value; } - - using Reverse = UIntPack< _Value >; - - template< typename T > struct Plus{}; - template< typename T > struct Minus{}; - template< typename T > struct Compare{}; - template< unsigned int __Value > struct Plus < UIntPack< __Value > >{ typedef UIntPack< _Value + __Value > type; }; - template< unsigned int __Value > struct Minus< UIntPack< __Value > >{ typedef UIntPack< _Value - __Value > type; }; - template< unsigned int __Value > struct Compare< UIntPack< __Value > > + template< unsigned int Idx , unsigned int ... Idxs > + static constexpr unsigned int I( void ) { - static const bool Equal = _Value==__Value; - static const bool NotEqual = _Value!=__Value; - static const bool LessThan = _Value< __Value; - static const bool LessThanOrEqual = _Value<=__Value; - static const bool GreaterThan = _Value> __Value; - static const bool GreaterThanOrEqual = _Value>=__Value; - }; - - static void Print( FILE* fp=stdout , bool leadingSpace=false ){ if( leadingSpace ) fprintf( fp , " " ) ; fprintf( fp , "%d" , _Value ); } - template< unsigned int I > constexpr static unsigned int Get( void ){ static_assert( I==0 , "[ERROR] UIntPack< Value >::Get called with non-zero index" ) ; return _Value; } - - template< unsigned int __Value > constexpr bool operator < ( UIntPack< __Value > ) const { return _Value< __Value; } - template< unsigned int __Value > constexpr bool operator <= ( UIntPack< __Value > ) const { return _Value<=__Value; } - template< unsigned int __Value > constexpr bool operator > ( UIntPack< __Value > ) const { return _Value> __Value; } - template< unsigned int __Value > constexpr bool operator >= ( UIntPack< __Value > ) const { return _Value>=__Value; } - template< unsigned int __Value > constexpr bool operator == ( UIntPack< __Value > ) const { return _Value==__Value; } - template< unsigned int __Value > constexpr bool operator != ( UIntPack< __Value > ) const { return _Value!=__Value; } + static_assert( sizeof...(Ress)==sizeof...(Idxs) , "[ERROR] sizes don't match" ); + if constexpr( sizeof...(Ress)==0 ) return Idx; + else return Idx * Size< Ress ... >() + Index< Ress... >::template I< Idxs... >(); + } }; - template< unsigned int _Value , unsigned int ... _Values > const unsigned int UIntPack< _Value , _Values ... >::Values[] = { _Value , _Values ... }; - template< unsigned int _Value > const unsigned int UIntPack< _Value >::Values[] = { _Value }; - template< unsigned int ... V1 , unsigned int ... V2 > typename UIntPack< V1 ... >::template Plus < UIntPack< V2 ... > >::type operator + ( UIntPack< V1 ... > , UIntPack< V2 ... > ){ return typename UIntPack< V1 ... >::template Plus < UIntPack< V2 ... > >::type(); } - template< unsigned int ... V1 , unsigned int ... V2 > typename UIntPack< V1 ... >::template Minus< UIntPack< V2 ... > >::type operator - ( UIntPack< V1 ... > , UIntPack< V2 ... > ){ return typename UIntPack< V1 ... >::template Minus< UIntPack< V2 ... > >::type(); } - template< int ... Values > struct IntPack{}; - template< int _Value , int ... _Values > struct IntPack< _Value , _Values ... > + template< unsigned int Dim , unsigned int Res > + struct IsotropicIndex { - static const int First = _Value; - typedef IntPack< _Values ... > Rest; - - static const unsigned int Size = 1 + sizeof ... ( _Values ); - template< int __Value > using Append = IntPack< _Value , _Values ... , __Value >; - template< int __Value > using Prepend = IntPack< __Value , _Value , _Values ... >; - static const int Values[]; - static constexpr int Min( void ){ return _Value < Rest::Min ? _Value : Rest::Min; } - static constexpr int Max( void ){ return _Value > Rest::Max ? _Value : Rest::Max; } - - using Reverse = typename Rest::Reverse::template Append< First >; - - template< typename T > struct Plus{}; - template< typename T > struct Minus{}; - template< typename T > struct Compare{}; - template< int __Value , int ... __Values > struct Plus < IntPack< __Value , __Values ... > >{ typedef typename Rest::template Plus < IntPack< __Values ... > >::type::template Prepend< _Value + __Value > type; }; - template< int __Value , int ... __Values > struct Minus< IntPack< __Value , __Values ... > >{ typedef typename Rest::template Minus< IntPack< __Values ... > >::type::template Prepend< _Value - __Value > type; }; - template< int __Value , int ... __Values > struct Compare< IntPack< __Value , __Values ... > > + template< unsigned int Idx > + static constexpr unsigned int I( void ) { - static const bool Equal = _Value==__Value && Rest::template Compare< IntPack< __Values ... > >:: Equal; - static const bool NotEqual = _Value!=__Value || Rest::template Compare< IntPack< __Values ... > >:: NotEqual; - static const bool LessThan = _Value< __Value && Rest::template Compare< IntPack< __Values ... > >:: LessThan ; - static const bool LessThanOrEqual = _Value<=__Value && Rest::template Compare< IntPack< __Values ... > >:: LessThanOrEqual; - static const bool GreaterThan = _Value> __Value && Rest::template Compare< IntPack< __Values ... > >::GreaterThan ; - static const bool GreaterThanOrEqual = _Value>=__Value && Rest::template Compare< IntPack< __Values ... > >::GreaterThanOrEqual; - }; - - static void Print( FILE* fp=stdout , bool leadingSpace=false ){ if( leadingSpace ) fprintf( fp , " " ) ; fprintf( fp , "%d" , _Value ) ; Rest::Print( fp , true ); } - - template< unsigned int I > constexpr static typename std::enable_if< I==0 , unsigned int >::type Get( void ){ return _Value; } - template< unsigned int I > constexpr static typename std::enable_if< I!=0 , unsigned int >::type Get( void ){ return Rest::template Get< I-1 >(); } - - template< int __Value , int ... __Values > constexpr bool operator < ( IntPack< __Value , __Values ... > ) const { return _Value< __Value && Rest()< IntPack< __Values ... >(); } - template< int __Value , int ... __Values > constexpr bool operator <= ( IntPack< __Value , __Values ... > ) const { return _Value<=__Value && Rest()<=IntPack< __Values ... >(); } - template< int __Value , int ... __Values > constexpr bool operator > ( IntPack< __Value , __Values ... > ) const { return _Value> __Value && Rest()> IntPack< __Values ... >(); } - template< int __Value , int ... __Values > constexpr bool operator >= ( IntPack< __Value , __Values ... > ) const { return _Value>=__Value && Rest()>=IntPack< __Values ... >(); } - template< int __Value , int ... __Values > constexpr bool operator == ( IntPack< __Value , __Values ... > ) const { return _Value==__Value && Rest()==IntPack< __Values ... >(); } - template< int __Value , int ... __Values > constexpr bool operator != ( IntPack< __Value , __Values ... > ) const { return _Value!=__Value && Rest()!=IntPack< __Values ... >(); } + if constexpr( Dim==1 ) return Idx; + else return Idx * IsotropicSize< Dim-1 , Res >() + IsotropicIndex< Dim-1 , Res >::template I< Idx >(); + } }; - template< int _Value > struct IntPack< _Value > + + template< unsigned int Res , unsigned int ... Ress > + unsigned int GetIndex( const unsigned int idx[] ) { - static const int First = _Value; - - static const unsigned int Size = 1; - template< int __Value > using Append = IntPack< _Value , __Value >; - template< int __Value > using Prepend = IntPack< __Value , _Value >; - static const int Values[]; - static constexpr int Min( void ){ return _Value; } - static constexpr int Max( void ){ return _Value; } - - using Reverse = IntPack< _Value >; - - template< typename T > struct Plus{}; - template< typename T > struct Minus{}; - template< typename T > struct Compare{}; - template< int __Value > struct Plus < IntPack< __Value > >{ typedef IntPack< _Value + __Value > type; }; - template< int __Value > struct Minus< IntPack< __Value > >{ typedef IntPack< _Value - __Value > type; }; - template< int __Value > struct Compare< IntPack< __Value > > - { - static const bool Equal = _Value==__Value; - static const bool NotEqual = _Value!=__Value; - static const bool LessThan = _Value< __Value; - static const bool LessThanOrEqual = _Value<=__Value; - static const bool GreaterThan = _Value> __Value; - static const bool GreaterThanOrEqual = _Value>=__Value; - }; - - static void Print( FILE* fp=stdout , bool leadingSpace=false ){ if( leadingSpace ) fprintf( fp , " " ) ; fprintf( fp , "%d" , _Value ); } - template< unsigned int I > constexpr static unsigned int Get( void ){ static_assert( I==0 , "[ERROR] IntPack< Value >::Get called with non-zero index" ) ; return _Value; } - - template< int __Value > constexpr bool operator < ( IntPack< __Value > ) const { return _Value< __Value; } - template< int __Value > constexpr bool operator <= ( IntPack< __Value > ) const { return _Value<=__Value; } - template< int __Value > constexpr bool operator > ( IntPack< __Value > ) const { return _Value> __Value; } - template< int __Value > constexpr bool operator >= ( IntPack< __Value > ) const { return _Value>=__Value; } - template< int __Value > constexpr bool operator == ( IntPack< __Value > ) const { return _Value==__Value; } - template< int __Value > constexpr bool operator != ( IntPack< __Value > ) const { return _Value!=__Value; } - }; - template< int _Value , int ... _Values > const int IntPack< _Value , _Values ... >::Values[] = { _Value , _Values ... }; - template< int _Value > const int IntPack< _Value >::Values[] = { _Value }; - template< int ... V1 , int ... V2 > typename IntPack< V1 ... >::template Plus < IntPack< V2 ... > >::type operator + ( IntPack< V1 ... > , IntPack< V2 ... > ){ return typename IntPack< V1 ... >::template Plus < IntPack< V2 ... > >::type(); } - template< int ... V1 , int ... V2 > typename IntPack< V1 ... >::template Minus< IntPack< V2 ... > >::type operator - ( IntPack< V1 ... > , IntPack< V2 ... > ){ return typename IntPack< V1 ... >::template Minus< IntPack< V2 ... > >::type(); } - - /////////////////////////// - // The isotropic variant // - /////////////////////////// - template< unsigned int Dim , unsigned int Value > struct _IsotropicUIntPack { typedef typename _IsotropicUIntPack< Dim-1 , Value >::type::template Append< Value > type; }; - template< unsigned int Value > struct _IsotropicUIntPack< 1 , Value >{ typedef UIntPack< Value > type; }; - template< unsigned int Value > struct _IsotropicUIntPack< 0 , Value >{ typedef UIntPack< > type; }; - template< unsigned int Dim , unsigned int Value > using IsotropicUIntPack = typename _IsotropicUIntPack< Dim , Value >::type; - template< unsigned int Dim > using ZeroUIntPack = IsotropicUIntPack< Dim , 0 >; - - template< int Dim , int Value > struct _IsotropicIntPack { typedef typename _IsotropicUIntPack< Dim-1 , Value >::type::template Append< Value > type; }; - template< int Value > struct _IsotropicIntPack< 1 , Value >{ typedef IntPack< Value > type; }; - template< int Value > struct _IsotropicIntPack< 0 , Value >{ typedef IntPack< > type; }; - template< int Dim , int Value > using IsotropicIntPack = typename _IsotropicIntPack< Dim , Value >::type; - template< int Dim > using ZeroIntPack = IsotropicIntPack< Dim , 0 >; - ///////////////////////////// - // And now for the windows // - ///////////////////////////// - template< typename T > struct WindowSize{}; - template< typename T1 , typename T2 > struct WindowIndex{}; - - template< unsigned int Res , unsigned int ... Ress > struct WindowSize< UIntPack< Res , Ress ... > >{ static const unsigned int Size = WindowSize< UIntPack< Ress ... > >::Size * Res; }; - template< unsigned int Res > struct WindowSize< UIntPack< Res > >{ static const unsigned int Size = Res; }; - - template< unsigned int Res , unsigned int ... Ress , unsigned int Idx , unsigned int ... Idxs > struct WindowIndex< UIntPack< Res , Ress ... > , UIntPack< Idx , Idxs ... > >{ static const unsigned int Index = Idx * WindowSize< UIntPack< Ress ... > >::Size + WindowIndex< UIntPack< Ress ... > , UIntPack< Idxs ... > >::Index; }; - template< unsigned int Res , unsigned int Idx > struct WindowIndex< UIntPack< Res > , UIntPack< Idx > >{ static const unsigned int Index = Idx; }; - - template< unsigned int Res , unsigned int ... Ress > typename std::enable_if< (sizeof...(Ress)!=0) , unsigned int >::type GetWindowIndex( UIntPack< Res , Ress ... > , const unsigned int idx[] ){ return idx[0] * WindowSize< UIntPack< Ress ... > >::Size + GetWindowIndex( UIntPack< Ress ... >() , idx+1 ); }; - template< unsigned int Res > unsigned int GetWindowIndex( UIntPack< Res > , const unsigned int idx[] ){ return idx[0]; } - - template< unsigned int Res , unsigned int ... Ress > typename std::enable_if< (sizeof...(Ress)!=0) , unsigned int >::type GetWindowIndex( UIntPack< Res , Ress ... > , const int idx[] ){ return idx[0] * WindowSize< UIntPack< Ress ... > >::Size + GetWindowIndex( UIntPack< Ress ... >() , idx+1 ); }; - template< unsigned int Res > unsigned int GetWindowIndex( UIntPack< Res > , const int idx[] ){ return idx[0]; } - - template< typename Data , typename Pack > struct ConstWindowSlice{}; - template< typename Data , typename Pack > struct WindowSlice{}; - template< typename Data , typename Pack > struct StaticWindow {}; - template< typename Data , typename Pack > struct DynamicWindow {}; - - - template< class Data , unsigned int ... Ress > - struct ConstWindowSlice< Data , UIntPack< Ress ... > > + if constexpr( sizeof...(Ress)==0 ) return idx[0]; + else return idx[0] * Size< Ress ... >() + GetIndex< Ress... >( idx+1 ); + } + + template< unsigned int Res , unsigned int ... Ress > + unsigned int GetIndex( const int idx[] ) { - typedef UIntPack< Ress ... > Pack; - static const unsigned int Size = WindowSize< Pack >::Size; - typedef Data data_type; - typedef const Data& data_reference_type; - typedef const Data& const_data_reference_type; - ConstWindowSlice( Pointer( Data ) d ) : data(d) { ; } - ConstWindowSlice( ConstPointer( Data ) d ) : data(d) { ; } - ConstWindowSlice< Data , typename Pack::Rest > operator[]( int idx ) const { return ConstWindowSlice< Data , typename Pack::Rest >( data + WindowSize< typename Pack::Rest >::Size * idx ); } - data_reference_type operator()( const int idx[sizeof...(Ress)] ) const { return data[ GetWindowIndex( UIntPack< Ress ... >() , idx ) ]; } - data_reference_type operator()( const unsigned int idx[sizeof...(Ress)] ) const { return data[ GetWindowIndex( UIntPack< Ress ... >() , idx ) ]; } - ConstPointer( Data ) data; + if constexpr( sizeof...(Ress)==0 ) return idx[0]; + else return idx[0] * Size< Ress ... >() + GetIndex< Ress... >( idx+1 ); }; - template< class Data , unsigned int Res > - struct ConstWindowSlice< Data , UIntPack< Res > > + + + template< class Data , unsigned int ... Res > struct ConstSlice{}; + + template< class Data , unsigned int Res , unsigned int ... Ress > + struct ConstSlice< Data , Res , Ress... > { - typedef UIntPack< Res > Pack; - static const unsigned int Size = Res; - typedef Data data_type; - typedef const Data& data_reference_type; - typedef const Data& const_data_reference_type; - ConstWindowSlice( Pointer( Data ) d ) : data(d) { ; } - ConstWindowSlice( ConstPointer( Data ) d ) : data(d) { ; } - inline data_reference_type operator[]( int idx ) const { return data[idx]; } - data_reference_type operator()( const int idx[1] ) const { return data[ idx[0] ]; } - data_reference_type operator()( const unsigned int idx[1] ) const { return data[ idx[0] ]; } + using data_type = Data; + using data_reference_type = const Data &; + using const_data_reference_type = const Data &; + static constexpr unsigned int Size( void ){ return Window::Size< Res , Ress... >(); } + + ConstSlice( Pointer( Data ) d ) : data(d) {} + ConstSlice( ConstPointer( Data ) d ) : data(d) {} + + std::conditional_t< sizeof...(Ress)==0 , data_reference_type , ConstSlice< Data , Ress... > > operator[]( int idx ) const + { + if constexpr( sizeof...(Ress)==0 ) return data[idx]; + else return ConstSlice< Data , Ress... >( data + Window::Size< Ress... >() * idx ); + } + data_reference_type operator()( const int idx[] ) const { return data[ GetIndex< Res , Ress... >( idx ) ]; } + data_reference_type operator()( const unsigned int idx[] ) const { return data[ GetIndex< Res , Ress... >( idx ) ]; } ConstPointer( Data ) data; }; - template< class Data , unsigned int ... Ress > - struct WindowSlice< Data , UIntPack< Ress ... > > - { - typedef UIntPack< Ress ... > Pack; - static const unsigned int Size = WindowSize< Pack >::Size; - typedef Data data_type; - typedef Data& data_reference_type; - typedef const Data& const_data_reference_type; - WindowSlice( Pointer( Data ) d ) : data(d) { ; } - WindowSlice< Data , typename Pack::Rest > operator[]( int idx ){ return WindowSlice< Data , typename Pack::Rest >( data + WindowSize< typename Pack::Rest >::Size * idx ); } - inline data_reference_type operator()( const int idx[sizeof...(Ress)] ){ return (*this)[ idx[0] ]( idx+1 ); } - const_data_reference_type operator()( const int idx[sizeof...(Ress)] ) const { return (*this)[ idx[0] ]( idx+1 ); } - operator ConstWindowSlice< Data , Pack >() const { return ConstWindowSlice< Data , Pack >( ( ConstPointer( Data ) )data ); } - Pointer( Data ) data; - }; - template< class Data , unsigned int Res > - struct WindowSlice< Data , UIntPack< Res > > + + template< typename Data , unsigned Dim , unsigned int Res , unsigned int ... Ress > + struct _IsotropicConstSlice{ using Type = std::conditional_t< Dim==1 , ConstSlice< Data , Res , Ress... > , _IsotropicConstSlice< Data , Dim-1 , Res , Res , Ress... > >; }; + template< typename Data , unsigned int Dim , unsigned int Res > + using IsotropicConstSlice = typename _IsotropicConstSlice< Data , Dim , Res >::Type; + + + template< class Data , unsigned int ... Res > struct Slice{}; + + template< class Data , unsigned int Res , unsigned int ... Ress > + struct Slice< Data , Res , Ress... > { - typedef UIntPack< Res > Pack; - static const unsigned int Size = Res; - typedef Data data_type; - typedef Data& data_reference_type; - typedef const Data& const_data_reference_type; - WindowSlice( Pointer( Data ) d ) : data(d) { ; } - inline data_reference_type operator[]( int idx ){ return data[idx]; } - inline const_data_reference_type operator[]( int idx ) const { return data[idx]; } - data_reference_type operator()( const int idx[1] ){ return (*this)[ idx[0] ]; } - const_data_reference_type operator()( const int idx[1] ) const { return (*this)[ idx[0] ]; } - operator ConstWindowSlice< Data , Pack >() const { return ConstWindowSlice< Data , Pack >( ( ConstPointer( Data ) )data ); } + using data_type = Data; + using data_reference_type = Data &; + using const_data_reference_type = const Data &; + static constexpr unsigned int Size( void ){ return Window::Size< Res , Ress... >(); } + + Slice( Pointer( Data ) d ) : data(d) {} + std::conditional_t< sizeof...(Ress)==0 , data_reference_type , Slice< Data , Ress... > > operator[]( int idx ) + { + if constexpr( sizeof...(Ress)==0 ) return data[idx]; + else return Slice< Data , Ress... >( data + Window::Size< Ress... >() * idx ); + } + std::conditional_t< sizeof...(Ress)==0 , const_data_reference_type , ConstSlice< Data , Ress... > > operator[]( int idx ) const + { + if constexpr( sizeof...(Ress)==0 ) return data[idx]; + else return ConstSlice< Data , Ress... >( data + Window::Size< Ress... >() * idx ); + } + data_reference_type operator()( const int idx[] ) + { + if constexpr( sizeof...(Ress)==0 ) return operator[]( idx[0] ); + else return operator[]( idx[0] )( idx+1 ); + } + const_data_reference_type operator()( const int idx[] ) const + { + if constexpr( sizeof...(Ress)==0 ) return operator[]( idx[0] ); + else return operator[]( idx[0] )( idx+1 ); + } + data_reference_type operator()( const unsigned int idx[] ) + { + if constexpr( sizeof...(Ress)==0 ) return operator[]( idx[0] ); + else return operator[]( idx[0] )( idx+1 ); + } + const_data_reference_type operator()( const unsigned int idx[] ) const + { + if constexpr( sizeof...(Ress)==0 ) return operator[]( idx[0] ); + else return operator[]( idx[0] )( idx+1 ); + } + operator ConstSlice< Data , Res , Ress... >() const { return ConstSlice< Data , Res , Ress... >( ( ConstPointer( Data ) )data ); } Pointer( Data ) data; }; - template< class Data , unsigned int ... Ress > - struct StaticWindow< Data , UIntPack< Ress ... > > - { - typedef UIntPack< Ress ... > Pack; -#if defined( __GNUC__ ) && defined( DEBUG ) -#ifdef SHOW_WARNINGS - #warning "you've got me gcc" -#endif // SHOW_WARNINGS - static const unsigned int Size; -#else // !( __GNUC__ && DEBUG ) - static const unsigned int Size = WindowSize< Pack >::Size; -#endif // ( __GNUC__ && DEBUG ) - typedef ConstWindowSlice< Data , Pack > const_window_slice_type; - typedef WindowSlice< Data , Pack > window_slice_type; - typedef Data data_type; - WindowSlice< Data , typename Pack::Rest > operator[]( int idx ){ return WindowSlice< Data , typename Pack::Rest >( GetPointer( data , WindowSize< Pack >::Size ) + WindowSize< typename Pack::Rest >::Size * idx ); } - ConstWindowSlice< Data , typename Pack::Rest > operator[]( int idx ) const { return ConstWindowSlice< Data , typename Pack::Rest >( ( ConstPointer( Data ) )GetPointer( data , WindowSize< Pack >::Size ) + WindowSize< typename Pack::Rest >::Size * idx ); } - WindowSlice< Data , Pack > operator()( void ){ return WindowSlice< Data , Pack >( GetPointer( data , WindowSize< Pack >::Size ) ); } - ConstWindowSlice< Data , Pack > operator()( void ) const { return ConstWindowSlice< Data , Pack >( ( ConstPointer( Data ) )GetPointer( data , WindowSize< Pack >::Size ) ); } - Data& operator()( const int idx[sizeof...(Ress)] ){ return (*this)()( idx ); } - const Data& operator()( const unsigned int idx[sizeof...(Ress)] ) const { return data[ GetWindowIndex( UIntPack< Ress ... >() , idx ) ]; } - const Data& operator()( const int idx[sizeof...(Ress)] ) const { return data[ GetWindowIndex( UIntPack< Ress ... >() , idx ) ]; } - Data data[ WindowSize< Pack >::Size ]; - }; -#if defined( __GNUC__ ) && defined( DEBUG ) - template< class Data , unsigned int ... Ress > - const unsigned int StaticWindow< Data , UIntPack< Ress ... > >::Size = WindowSize< UIntPack< Ress ... > >::Size; -#endif // ( __GNUC__ && DEBUG ) - template< class Data , unsigned int Res > - struct StaticWindow< Data , UIntPack< Res > > - { - typedef UIntPack< Res > Pack; -#if defined( __GNUC__ ) && defined( DEBUG ) -#ifdef SHOW_WARNINGS - #warning "you've got me gcc" -#endif // SHOW_WARNINGS - static const unsigned int Size; -#else // !( __GNUC__ && DEBUG ) - static const unsigned int Size = Res; -#endif // ( __GNUC__ && DEBUG ) - typedef Data data_type; - Data& operator[]( int idx ){ return data[idx]; }; - const Data& operator[]( int idx ) const { return data[idx]; }; - WindowSlice< Data , Pack > operator()( void ){ return WindowSlice< Data , Pack >( GetPointer( data , WindowSize< Pack >::Size ) ); } - ConstWindowSlice< Data , Pack > operator()( void ) const { return ConstWindowSlice< Data , Pack >( ( ConstPointer( Data ) )GetPointer( data , WindowSize< Pack >::Size ) ); } - Data& operator()( const int idx[1] ){ return (*this)()( idx ); } - const Data& operator()( const unsigned int idx[1] ) const { return data[ idx[0] ]; } - const Data& operator()( const int idx[1] ) const { return data[ idx[0] ]; } - Data data[ Res ]; - }; -#if defined( __GNUC__ ) && defined( DEBUG ) - template< class Data , unsigned int Res > - const unsigned int StaticWindow< Data , UIntPack< Res > >::Size = Res; -#endif // ( __GNUC__ && DEBUG ) + template< typename Data , unsigned Dim , unsigned int Res , unsigned int ... Ress > + struct _IsotropicSlice{ using Type = std::conditional_t< Dim==1 , Slice< Data , Res , Ress... > , _IsotropicSlice< Data , Dim-1 , Res , Res , Ress... > >; }; + template< typename Data , unsigned int Dim , unsigned int Res > + using IsotropicSlice = typename _IsotropicSlice< Data , Dim , Res >::Type; - template< class Data , unsigned int ... Ress > - struct DynamicWindow< Data , UIntPack< Ress ... > > + + template< class Data , unsigned int Res , unsigned int ... Ress > + struct StaticWindow { - typedef UIntPack< Ress ... > Pack; - static const unsigned int Size = WindowSize< Pack >::Size; - typedef ConstWindowSlice< Data , Pack > const_window_slice_type; - typedef WindowSlice< Data , Pack > window_slice_type; - typedef Data data_type; - WindowSlice< Data , typename Pack::Rest > operator[]( int idx ){ return WindowSlice< Data , typename Pack::Rest >( data + WindowSize< typename Pack::Rest >::Size * idx ); } - ConstWindowSlice< Data , typename Pack::Rest > operator[]( int idx ) const { return ConstWindowSlice< Data , typename Pack::Rest >( ( ConstPointer( Data ) )( data + WindowSize< typename Pack::Rest >::Size * idx ) ); } - WindowSlice< Data , Pack > operator()( void ){ return WindowSlice< Data , Pack >( data ); } - ConstWindowSlice< Data , Pack > operator()( void ) const { return ConstWindowSlice< Data , Pack >( ( ConstPointer( Data ) )data ); } - Data& operator()( const int idx[sizeof...(Ress)+1] ){ return (*this)()( idx ); } - const Data& operator()( const int idx[sizeof...(Ress)+1] ) const { return (*this)()( idx ); } - - DynamicWindow( void ){ data = NewPointer< Data >( WindowSize< Pack >::Size ); } - ~DynamicWindow( void ){ DeletePointer( data ); } - Pointer( Data ) data; + using const_window_slice_type = ConstSlice< Data , Res , Ress... >; + using window_slice_type = Slice< Data , Res , Ress... >; + using data_type = Data ; + static constexpr unsigned int Size( void ){ return Window::Size< Res , Ress... >(); } + + std::conditional_t< sizeof...(Ress)==0 , Data & , Slice< Data , Ress... > > operator[]( int idx ) + { + if constexpr( sizeof...(Ress)==0 ) return data[idx]; + else return Slice< Data , Ress... >( GetPointer( data , Size() ) + Window::Size< Ress... >() * idx ); + } + + std::conditional_t< sizeof...(Ress)==0 , const Data & , ConstSlice< Data , Ress... > > operator[]( int idx ) const + { + if constexpr( sizeof...(Ress)==0 ) return data[idx]; + else return ConstSlice< Data , Ress... >( ( ConstPointer( Data ) )GetPointer( data , Size() ) + Window::Size< Ress... >() * idx ); + } + + Slice< Data , Res , Ress... > operator()( void ){ return Slice< Data , Res , Ress... >( GetPointer( data , Size() ) ); } + + ConstSlice< Data , Res , Ress... > operator()( void ) const { return ConstSlice< Data , Res , Ress... >( ( ConstPointer( Data ) )GetPointer( data , Size() ) ); } + + Data& operator()( const unsigned int idx[] ){ return (*this)()( idx ); } + Data& operator()( const int idx[] ){ return (*this)()( idx ); } + + const Data& operator()( const unsigned int idx[] ) const { return data[ GetIndex< Res , Ress... >( idx ) ]; } + const Data& operator()( const int idx[] ) const { return data[ GetIndex< Res , Ress... >( idx ) ]; } + + Data data[ Window::Size< Res , Ress... >() ]; }; - template< class Data , unsigned int Res > - struct DynamicWindow< Data , UIntPack< Res > > + + template< typename Data , unsigned Dim , unsigned int Res , unsigned int ... Ress > + struct _IsotropicStaticWindow{ using Type = std::conditional_t< Dim==1 , StaticWindow< Data , Res , Ress... > , _IsotropicStaticWindow< Data , Dim-1 , Res , Res , Ress... > >; }; + template< typename Data , unsigned int Dim , unsigned int Res > + using IsotropicStaticWindow = typename _IsotropicStaticWindow< Data , Dim , Res >::Type; + + + template< class Data , unsigned int Res , unsigned int ... Ress > + struct DynamicWindow { - typedef UIntPack< Res > Pack; - static const unsigned int Size = Res; - typedef Data data_type; - Data& operator[]( int idx ){ return data[idx]; }; - const Data& operator[]( int idx ) const { return data[idx]; }; - WindowSlice< Data , Pack > operator()( void ) { return WindowSlice< Data , Pack >( data ); } - ConstWindowSlice< Data , Pack > operator()( void ) const { return ConstWindowSlice< Data , Pack >( ( ConstPointer( Data ) )data ); } - Data& operator()( const int idx[1] ){ return (*this)()( idx ); } - const Data& operator()( const int idx[1] ) const { return (*this)()( idx ); } - - DynamicWindow( void ){ data = NewPointer< Data >( Res ); } + using const_window_slice_type = ConstSlice< Data , Res , Ress... >; + using window_slice_type = Slice< Data , Res , Ress... >; + using data_type = Data; + static constexpr unsigned int Size( void ){ return Window::Size< Res , Ress... >(); } + + std::conditional_t< sizeof...(Ress)==0 , Data & , Slice< Data , Ress... > > operator[]( int idx ) + { + if constexpr( sizeof...(Ress)==0 ) return data[idx]; + else return Slice< Data , Ress... >( data + Window::Size< Ress... >() * idx ); + } + + std::conditional_t< sizeof...(Ress)==0 , const Data & , ConstSlice< Data , Ress... > > operator[]( int idx ) const + { + if constexpr( sizeof...(Ress)==0 ) return data[idx]; + else ConstSlice< Data , Ress... >( ( ConstPointer( Data ) )( data + Window::Size< Ress... >() * idx ) ); + } + + Slice< Data , Res , Ress... > operator()( void ){ return Slice< Data , Res , Ress... >( data ); } + ConstSlice< Data , Res , Ress... > operator()( void ) const { return ConstSlice< Data , Res , Ress... >( ( ConstPointer( Data ) )data ); } + + Data& operator()( const int idx[] ){ return (*this)()( idx ); } + const Data& operator()( const int idx[] ) const { return (*this)()( idx ); } + + DynamicWindow( void ){ data = NewPointer< Data >( Size() ); } + ~DynamicWindow( void ){ DeletePointer( data ); } + Pointer( Data ) data; }; + template< typename Data , unsigned Dim , unsigned int Res , unsigned int ... Ress > + struct _IsotropicDynamicWindow{ using Type = std::conditional_t< Dim==1 , DynamicWindow< Data , Res , Ress... > , _IsotropicDynamicWindow< Data , Dim-1 , Res , Res , Ress... > >; }; + template< typename Data , unsigned int Dim , unsigned int Res > + using IsotropicDynamicWindow = typename _IsotropicDynamicWindow< Data , Dim , Res >::Type; + // Recursive loop iterations for processing window slices // WindowDimension: the the window slice // IterationDimensions: the number of dimensions to process // Res: the resolution of the window - template< unsigned int WindowDimension , unsigned int IterationDimensions , unsigned int CurrentIteration > struct _WindowLoop; + template< unsigned int WindowDimension , unsigned int IterationDimensions , unsigned int CurrentIteration > struct _Loop; + template< unsigned int WindowDimension , unsigned int IterationDimensions=WindowDimension > - struct WindowLoop + struct Loop { template< typename UpdateFunction , typename ProcessFunction , class ... Windows > static void Run( int begin , int end , UpdateFunction updateState , ProcessFunction function , Windows ... w ) { - _WindowLoop< WindowDimension , IterationDimensions , IterationDimensions >::Run( begin , end , updateState , function , w ... ); + _Loop< WindowDimension , IterationDimensions , IterationDimensions >::Run( begin , end , updateState , function , w ... ); } template< typename UpdateFunction , typename ProcessFunction , class ... Windows > static void Run( const int* begin , const int* end , UpdateFunction updateState , ProcessFunction function , Windows ... w ) { - _WindowLoop< WindowDimension , IterationDimensions , IterationDimensions >::Run( begin , end , updateState , function , w ... ); + _Loop< WindowDimension , IterationDimensions , IterationDimensions >::Run( begin , end , updateState , function , w ... ); } template< unsigned int ... Begin , unsigned int ... End , typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void Run( UIntPack< Begin ... > begin , UIntPack< End ... > end , UpdateFunction updateState , ProcessFunction function , Windows ... w ) + static void Run( ParameterPack::UIntPack< Begin ... > begin , ParameterPack::UIntPack< End ... > end , UpdateFunction updateState , ProcessFunction function , Windows ... w ) { - _WindowLoop< WindowDimension , IterationDimensions , IterationDimensions >::Run( begin , end , updateState , function , w ... ); + _Loop< WindowDimension , IterationDimensions , IterationDimensions >::Run( begin , end , updateState , function , w ... ); } template< typename UpdateFunction , typename ProcessFunction , class ... Windows > static void RunParallel( int begin , int end , UpdateFunction updateState , ProcessFunction function , Windows ... w ) { - _WindowLoop< WindowDimension , IterationDimensions , IterationDimensions >::RunParallel( begin , end , updateState , function , w ... ); + _Loop< WindowDimension , IterationDimensions , IterationDimensions >::RunParallel( begin , end , updateState , function , w ... ); } template< typename UpdateFunction , typename ProcessFunction , class ... Windows > static void RunParallel( const int* begin , const int* end , UpdateFunction updateState , ProcessFunction function , Windows ... w ) { - _WindowLoop< WindowDimension , IterationDimensions , IterationDimensions >::RunParallel( begin , end , updateState , function , w ... ); + _Loop< WindowDimension , IterationDimensions , IterationDimensions >::RunParallel( begin , end , updateState , function , w ... ); } template< unsigned int ... Begin , unsigned int ... End , typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunParallel( UIntPack< Begin ... > begin , UIntPack< End ... > end , UpdateFunction updateState , ProcessFunction function , Windows ... w ) + static void RunParallel( ParameterPack::UIntPack< Begin ... > begin , ParameterPack::UIntPack< End ... > end , UpdateFunction updateState , ProcessFunction function , Windows ... w ) { - _WindowLoop< WindowDimension , IterationDimensions , IterationDimensions >::RunParallel( begin , end , updateState , function , w ... ); + _Loop< WindowDimension , IterationDimensions , IterationDimensions >::RunParallel( begin , end , updateState , function , w ... ); } }; #include "Window.inl" } +// Adding definitions to be consistent with old code +namespace PoissonRecon +{ + template< typename Pack1 , typename Pack2 > struct WindowIndex; + template< unsigned int ... Res , unsigned int ... Idx > + struct WindowIndex< ParameterPack::UIntPack< Res... > , ParameterPack::UIntPack< Idx... > >{ static const unsigned int Index = Window::Index< Res... >::template I< Idx ... >(); }; + + template< int ... Values > + using IntPack = ParameterPack::IntPack< Values... >; + template< unsigned int ... Values > + using UIntPack = ParameterPack::UIntPack< Values... >; + + template< unsigned int Dim , unsigned int Res > + using IsotropicUIntPack = ParameterPack::IsotropicPack< unsigned int , Dim , Res >; + + template< unsigned int Dim > + using ZeroUIntPack = IsotropicUIntPack< Dim , 0 >; + + template< typename Data , typename Pack > struct _WindowSlice; + template< typename Data , unsigned int ... Res > struct _WindowSlice< Data , ParameterPack::UIntPack< Res... > >{ using type = Window::Slice< Data , Res... >; }; + template< typename Data , typename Pack > using WindowSlice = typename _WindowSlice< Data , Pack >::type; + + template< typename Data , typename Pack > struct _ConstWindowSlice; + template< typename Data , unsigned int ... Res > struct _ConstWindowSlice< Data , ParameterPack::UIntPack< Res... > >{ using type = Window::ConstSlice< Data , Res... >; }; + template< typename Data , typename Pack > using ConstWindowSlice = typename _ConstWindowSlice< Data , Pack >::type; + + template< typename Data , typename Pack > struct StaticWindow; + template< typename Data , unsigned int ... Res > + struct StaticWindow< Data , ParameterPack::UIntPack< Res... > > : public Window::StaticWindow< Data , Res... >{}; + + template< typename Data , typename Pack > struct DynamicWindow; + template< typename Data , unsigned int ... Res > + struct DynamicWindow< Data , ParameterPack::UIntPack< Res... > > : public Window::DynamicWindow< Data , Res... >{}; + + template< typename Pack > struct WindowSize; + template< unsigned int ... Res > struct WindowSize< ParameterPack::UIntPack< Res... > >{ static const unsigned int Size = Window::Size< Res... >(); }; + + template< unsigned ... Res > + unsigned int GetWindowIndex( UIntPack< Res... > , const unsigned int idx[] ){ return Window::GetIndex< Res... >( idx ); } + + template< unsigned int WindowDimension > + using WindowLoop = Window::Loop< WindowDimension >; +} #endif // WINDOW_INCLUDED diff --git a/Src/Window.inl b/Src/Window.inl index 957eeae4..b3dbd3b1 100644 --- a/Src/Window.inl +++ b/Src/Window.inl @@ -26,336 +26,135 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ -////////////////////////////////////////// -// IterationDimension < WindowDimension // -////////////////////////////////////////// template< unsigned int WindowDimension , unsigned int IterationDimensions , unsigned int CurrentIteration > -struct _WindowLoop +struct _Loop { -protected: - static const int CurrentDimension = CurrentIteration + WindowDimension - IterationDimensions; - friend struct WindowLoop< WindowDimension , IterationDimensions >; - friend struct _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration+1 >; - - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void Run( int begin , int end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - for( int i=begin ; i::Run( begin , end , updateState , function , w[i] ... ); } - } - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void Run( const int* begin , const int* end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - for( int i=begin[0] ; i::Run( begin+1 , end+1 , updateState , function , w[i] ... ); } - } - template< unsigned int ... Begin , unsigned int ... End , typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void Run( UIntPack< Begin ... > begin , UIntPack< End ... > end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - for( int i=UIntPack< Begin ... >::First ; i::First ; i++ ){ updateState( WindowDimension - CurrentDimension , i ) ; _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration-1 >::Run( typename UIntPack< Begin ... >::Rest() , typename UIntPack< End ... >::Rest() , updateState , function , w[i] ... ); } - } - - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunParallel( int begin , int end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - ThreadPool::ParallelFor( begin , end , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration-1 >::RunThread( begin , end , thread , updateState , function , w[i] ... ); } ); - } - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunParallel( const int* begin , const int* end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - ThreadPool::ParallelFor( begin[0] , end[0] , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration-1 >::RunThread( begin+1 , end+1 , thread , updateState , function , w[i] ... ); } ); - } - template< unsigned int ... Begin , unsigned int ... End , typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunParallel( UIntPack< Begin ... > begin , UIntPack< End ... > end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - ThreadPool::ParallelFor( UIntPack< Begin ... >::First , UIntPack< End ... >::First , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration-1 >::RunThread( typename UIntPack< Begin ... >::Rest() , typename UIntPack< End ... >::Rest() , thread , updateState , function , w[i] ... ); } ); - } + static_assert( IterationDimensions<=WindowDimension , "[ERROR] Iteration dimensions cannot excceed window dimension" ); + static_assert( CurrentIteration>0 , "[ERROR] Current iteration cannot be zero" ); + static_assert( CurrentIteration<=IterationDimensions , "[ERROR] Current iteration cannot exceed iteration dimensions" ); - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunThread( int begin , int end , unsigned int thread , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - for( int i=begin ; i::RunThread( begin , end , thread , updateState , function , w[i] ... ); } - } - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunThread( const int* begin , const int* end , unsigned int thread , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - for( int i=begin[0] ; i::RunThread( begin+1 , end+1 , thread , updateState , function , w[i] ... ); } - } - template< unsigned int ... Begin , unsigned int ... End , typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunThread( UIntPack< Begin ... > begin , UIntPack< End ... > end , unsigned int thread , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - for( int i=UIntPack< Begin ... >::First ; i::First ; i++ ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration-1 >::RunThread( typename UIntPack< Begin ... >::Rest() , typename UIntPack< End ... >::Rest() , thread , updateState , function , w[i] ... ); } - } -}; -////////////////////////////////////////// -// IterationDimension = WindowDimension // -////////////////////////////////////////// -template< unsigned int WindowDimension , unsigned int CurrentIteration > -struct _WindowLoop< WindowDimension , WindowDimension , CurrentIteration > -{ protected: - static const int IterationDimensions = WindowDimension; static const int CurrentDimension = CurrentIteration + WindowDimension - IterationDimensions; - friend struct WindowLoop< WindowDimension , IterationDimensions >; - friend struct _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration+1 >; - - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void Run( int begin , int end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - for( int i=begin ; i::Run( begin , end , updateState , function , w[i] ... ); } - } - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void Run( const int* begin , const int* end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - for( int i=begin[0] ; i::Run( begin+1 , end+1 , updateState , function , w[i] ... ); } - } - template< unsigned int ... Begin , unsigned int ... End , typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void Run( UIntPack< Begin ... > begin , UIntPack< End ... > end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - for( int i=UIntPack< Begin ... >::First ; i::First ; i++ ){ updateState( WindowDimension - CurrentDimension , i ) ; _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration-1 >::Run( typename UIntPack< Begin ... >::Rest() , typename UIntPack< End ... >::Rest() , updateState , function , w[i] ... ); } - } + friend struct Loop< WindowDimension , IterationDimensions >; + friend struct _Loop< WindowDimension , IterationDimensions , CurrentIteration+1 >; - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunParallel( int begin , int end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - ThreadPool::ParallelFor( begin , end , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration-1 >::RunThread( begin , end , thread , updateState , function , w[i] ... ); } ); - } - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunParallel( const int* begin , const int* end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - ThreadPool::ParallelFor( begin[0] , end[0] , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration-1 >::RunThread( begin+1 , end+1 , thread , updateState , function , w[i] ... ); } ); - } - template< unsigned int ... Begin , unsigned int ... End , typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunParallel( UIntPack< Begin ... > begin , UIntPack< End ... > end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - ThreadPool::ParallelFor( UIntPack< Begin ... >::First , UIntPack< End ... >::First , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration-1 >::RunThread( typename UIntPack< Begin ... >::Rest() , typename UIntPack< End ... >::Rest() , thread , updateState , function , w[i] ... ); } ); - } - - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunThread( int begin , int end , unsigned int thread , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - for( int i=begin ; i::RunThread( begin , end , thread , updateState , function , w[i] ... ); } - } - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunThread( const int* begin , const int* end , unsigned int thread , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - for( int i=begin[0] ; i::RunThread( begin+1 , end+1 , thread , updateState , function , w[i] ... ); } - } - template< unsigned int ... Begin , unsigned int ... End , typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunThread( UIntPack< Begin ... > begin , UIntPack< End ... > end , unsigned int thread , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - for( int i=UIntPack< Begin ... >::First ; i::First ; i++ ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration-1 >::RunThread( typename UIntPack< Begin ... >::Rest() , typename UIntPack< End ... >::Rest() , thread , updateState , function , w[i] ... ); } - } -}; -/////////////////////////////////////////////////////////////////// -// IterationDimension < WindowDimension and CurrentIteration = 1 // -/////////////////////////////////////////////////////////////////// -template< unsigned int WindowDimension , unsigned int IterationDimensions > -struct _WindowLoop< WindowDimension , IterationDimensions , 1 > -{ -protected: - static const unsigned int CurrentIteration = 1; - static const int CurrentDimension = CurrentIteration + WindowDimension - IterationDimensions; - friend struct WindowLoop< WindowDimension , IterationDimensions >; - friend struct _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration+1 >; + /////////////////////////////// + // Single-threaded execution // + /////////////////////////////// template< typename UpdateFunction , typename ProcessFunction , class ... Windows > static void Run( int begin , int end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) { - for( int i=begin ; i - static void Run( const int* begin , const int* end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - for( int i=begin[0] ; i - static void Run( UIntPack< Begin ... > begin , UIntPack< End ... > end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - for( int i=UIntPack< Begin ... >::First ; i::First ; i++ ){ updateState( WindowDimension - CurrentDimension , i ) ; function( w[i] ... ); } + for( int i=begin ; i::Run( begin , end , updateState , function , w[i] ... ); + } } template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunParallel( int begin , int end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - ThreadPool::ParallelFor( begin , end , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); - } - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunParallel( const int* begin , const int* end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - ThreadPool::ParallelFor( begin[0] , end[0] , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); - } - template< unsigned int ... Begin , unsigned int ... End , typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunParallel( UIntPack< Begin ... > begin , UIntPack< End ... > end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) + static void Run( const int* begin , const int* end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) { - ThreadPool::ParallelFor( UIntPack< Begin ... >::First , UIntPack< End ... >::First , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); + for( int i=begin[0] ; i::Run( begin+1 , end+1 , updateState , function , w[i] ... ); + } } - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunThread( int begin , int end , unsigned int thread , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - for( int i=begin ; i - static void RunThread( const int* begin , const int* end , unsigned int thread , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - for( int i=begin[0] ; i - static void RunThread( UIntPack< Begin ... > begin , UIntPack< End ... > end , unsigned int thread , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) + static void Run( ParameterPack::UIntPack< Begin ... > begin , ParameterPack::UIntPack< End ... > end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) { - for( int i=UIntPack< Begin ... >::First ; i::First ; i++ ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } + for( int i=ParameterPack::UIntPack< Begin ... >::First ; i::First ; i++ ) + { + updateState( WindowDimension - CurrentDimension , i ); + if constexpr( CurrentIteration==1 ) function( w[i] ... ); + else _Loop< WindowDimension , IterationDimensions , CurrentIteration-1 >::Run( typename ParameterPack::UIntPack< Begin ... >::Rest() , typename ParameterPack::UIntPack< End ... >::Rest() , updateState , function , w[i] ... ); + } } -}; -/////////////////////////////////////////////////////////////////// -// IterationDimension = WindowDimension and CurrentIteration = 1 // -/////////////////////////////////////////////////////////////////// -template< unsigned int WindowDimension > -struct _WindowLoop< WindowDimension , WindowDimension , 1 > -{ -protected: - static const unsigned int CurrentIteration = 1; - static const int IterationDimensions = WindowDimension; - static const int CurrentDimension = CurrentIteration + WindowDimension - IterationDimensions; - friend struct WindowLoop< WindowDimension , IterationDimensions >; - friend struct _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration+1 >; - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void Run( int begin , int end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - for( int i=begin ; i - static void Run( const int* begin , const int* end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - for( int i=begin[0] ; i - static void Run( UIntPack< Begin ... > begin , UIntPack< End ... > end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - for( int i=UIntPack< Begin ... >::First ; i::First ; i++ ){ updateState( WindowDimension - CurrentDimension , i ) ; function( w[i] ... ); } - } + ////////////////////////////// + // Multi-threaded execution // + ////////////////////////////// template< typename UpdateFunction , typename ProcessFunction , class ... Windows > static void RunParallel( int begin , int end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) { - ThreadPool::ParallelFor( begin , end , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); - } - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunParallel( const int* begin , const int* end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - ThreadPool::ParallelFor( begin[0] , end[0] , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); - } - template< unsigned int ... Begin , unsigned int ... End , typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunParallel( UIntPack< Begin ... > begin , UIntPack< End ... > end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - ThreadPool::ParallelFor( UIntPack< Begin ... >::First , UIntPack< End ... >::First , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); + ThreadPool::ParallelFor + ( + begin , end , + [&]( unsigned int thread , size_t i ) + { + updateState( thread , WindowDimension - CurrentDimension , i ); + if constexpr( CurrentIteration==1 ) function( thread , w[i] ... ); + else _Loop< WindowDimension , IterationDimensions , CurrentIteration-1 >::RunThread( begin , end , thread , updateState , function , w[i] ... ); + } + ); } template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunThread( int begin , int end , unsigned int thread , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - for( int i=begin ; i - static void RunThread( const int* begin , const int* end , unsigned int thread , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - for( int i=begin[0] ; i - static void RunThread( UIntPack< Begin ... > begin , UIntPack< End ... > end , unsigned int thread , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) + static void RunParallel( const int* begin , const int* end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) { - for( int i=UIntPack< Begin ... >::First ; i::First ; i++ ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } + ThreadPool::ParallelFor + ( + begin[0] , end[0] , + [&]( unsigned int thread , size_t i ) + { + updateState( thread , WindowDimension - CurrentDimension , i ); + if constexpr( CurrentIteration==1 ) function( thread , w[i] ... ); + else _Loop< WindowDimension , IterationDimensions , CurrentIteration-1 >::RunThread( begin+1 , end+1 , thread , updateState , function , w[i] ... ); + } + ); } -}; -///////////////////////////////////////////////////////////////// -// IterationDimension = WindowDimension = CurrentIteration = 1 // -//////////////////////////////////////////////////////////////// -template< > -struct _WindowLoop< 1 , 1 , 1 > -{ -protected: - static const unsigned int CurrentIteration = 1; - static const int WindowDimension = 1; - static const int IterationDimensions = WindowDimension; - static const int CurrentDimension = CurrentIteration + WindowDimension - IterationDimensions; - friend struct WindowLoop< WindowDimension , IterationDimensions >; - friend struct _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration+1 >; - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void Run( int begin , int end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - for( int i=begin ; i - static void Run( const int* begin , const int* end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - for( int i=begin[0] ; i - static void Run( UIntPack< Begin ... > begin , UIntPack< End ... > end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) + static void RunParallel( ParameterPack::UIntPack< Begin ... > begin , ParameterPack::UIntPack< End ... > end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) { - for( int i=UIntPack< Begin ... >::First ; i::First ; i++ ){ updateState( WindowDimension - CurrentDimension , i ) ; function( w[i] ... ); } + ThreadPool::ParallelFor + ( + ParameterPack::UIntPack< Begin ... >::First , ParameterPack::UIntPack< End ... >::First , + [&]( unsigned int thread , size_t i ) + { + updateState( thread , WindowDimension - CurrentDimension , i ); + if constexpr( CurrentIteration==1 ) function( thread , w[i] ... ); + else _Loop< WindowDimension , IterationDimensions , CurrentIteration-1 >::RunThread( typename ParameterPack::UIntPack< Begin ... >::Rest() , typename ParameterPack::UIntPack< End ... >::Rest() , thread , updateState , function , w[i] ... ); + } + ); } - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunParallel( int begin , int end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - ThreadPool::ParallelFor( begin , end , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); - } - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunParallel( const int* begin , const int* end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - ThreadPool::ParallelFor( begin[0] , end[0] , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); - } - template< unsigned int ... Begin , unsigned int ... End , typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunParallel( UIntPack< Begin ... > begin , UIntPack< End ... > end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) - { - ThreadPool::ParallelFor( UIntPack< Begin ... >::First , UIntPack< End ... >::First , [&]( unsigned int thread , size_t i ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } ); - } template< typename UpdateFunction , typename ProcessFunction , class ... Windows > static void RunThread( int begin , int end , unsigned int thread , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) { - for( int i=begin ; i::RunThread( begin , end , thread , updateState , function , w[i] ... ); + } } + template< typename UpdateFunction , typename ProcessFunction , class ... Windows > static void RunThread( const int* begin , const int* end , unsigned int thread , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) { - for( int i=begin[0] ; i::RunThread( begin+1 , end+1 , thread , updateState , function , w[i] ... ); + } } + template< unsigned int ... Begin , unsigned int ... End , typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunThread( UIntPack< Begin ... > begin , UIntPack< End ... > end , unsigned int thread , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) + static void RunThread( ParameterPack::UIntPack< Begin ... > begin , ParameterPack::UIntPack< End ... > end , unsigned int thread , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ) { - for( int i=UIntPack< Begin ... >::First ; i::First ; i++ ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , w[i] ... ); } + for( int i=ParameterPack::UIntPack< Begin ... >::First ; i::First ; i++ ) + { + updateState( thread , WindowDimension - CurrentDimension , i ); + if constexpr( CurrentIteration==1 ) function( thread , w[i] ... ); + else _Loop< WindowDimension , IterationDimensions , CurrentIteration-1 >::RunThread( typename ParameterPack::UIntPack< Begin ... >::Rest() , typename ParameterPack::UIntPack< End ... >::Rest() , thread , updateState , function , w[i] ... ); + } } -}; -////////////////////////// -// CurrentIteration = 0 // -////////////////////////// -template< unsigned int WindowDimension , unsigned int IterationDimensions > -struct _WindowLoop< WindowDimension , IterationDimensions , 0 > -{ -protected: - static const unsigned int CurrentIteration = 0; - static const int CurrentDimension = CurrentIteration + WindowDimension - IterationDimensions; - friend struct WindowLoop< WindowDimension , IterationDimensions >; - friend struct _WindowLoop< WindowDimension , IterationDimensions , CurrentIteration+1 >; - - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void Run( int begin , int end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ){ ERROR_OUT( "Shouldn't be here" ); } - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void Run( const int* begin , const int* end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ){ ERROR_OUT( "Shouldn't be here" ); } - template< unsigned int ... Begin , unsigned int ... End , typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void Run( UIntPack< Begin ... > begin , UIntPack< End ... > end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ){ ERROR_OUT( "Shouldn't be here" ); } - - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunParallel( int begin , int end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ){ ERROR_OUT( "Shouldn't be here" ); } - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunParallel( const int* begin , const int* end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ){ ERROR_OUT( "Shouldn't be here" ); } - template< unsigned int ... Begin , unsigned int ... End , typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunParallel( UIntPack< Begin ... > begin , UIntPack< End ... > end , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ){ ERROR_OUT( "Shouldn't be here" ); } - - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunThread( int begin , int end , unsigned int thread , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ){ ERROR_OUT( "Shouldn't be here" ); } - template< typename UpdateFunction , typename ProcessFunction , class ... Windows > - static void RunThread( const int* begin , const int* end , unsigned int thread , UpdateFunction& updateState , ProcessFunction& function , Windows ... w ){ ERROR_OUT( "Shouldn't be here" ); } -}; +}; \ No newline at end of file diff --git a/SurfaceTrimmer.vcxproj b/SurfaceTrimmer.vcxproj index 3382f951..34d1e1fa 100644 --- a/SurfaceTrimmer.vcxproj +++ b/SurfaceTrimmer.vcxproj @@ -30,7 +30,7 @@ Application Unicode true - v142 + v143 Application @@ -41,12 +41,12 @@ Application Unicode - v142 + v143 Application Unicode - v142 + v143 diff --git a/ZLIB.vcxproj b/ZLIB.vcxproj index 05eb804b..205dbff6 100644 --- a/ZLIB.vcxproj +++ b/ZLIB.vcxproj @@ -58,12 +58,12 @@ StaticLibrary Unicode true - v142 + v143 StaticLibrary Unicode - v142 + v143 StaticLibrary @@ -74,7 +74,7 @@ StaticLibrary Unicode - v142 + v143 From cfb26f3a4a2a0eec94aa643a32db485fc6218923 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Fri, 25 Apr 2025 10:34:19 -0400 Subject: [PATCH 80/86] Version18.71 --- Src/PreProcessor.h | 2 +- Src/Reconstructors.h | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index c081f957..05d98a11 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -46,7 +46,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "18.70" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "18.71" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth diff --git a/Src/Reconstructors.h b/Src/Reconstructors.h index 9c3d2d9e..5f39579a 100644 --- a/Src/Reconstructors.h +++ b/Src/Reconstructors.h @@ -94,7 +94,7 @@ namespace PoissonRecon {} template< unsigned int Dim > - void testAndSet( XForm< Real , Dim > unitCubeToModel ) + void testAndSet( XForm< Real , Dim+1 > unitCubeToModel ) { if( width>0 ) { @@ -477,9 +477,9 @@ namespace PoissonRecon {} template< unsigned int Dim > - void testAndSet( XForm< Real , Dim > unitCubeToModel ) + void testAndSet( XForm< Real , Dim+1 > unitCubeToModel ) { - Reconstructor::SolutionParameters< Real >::testAndSet( unitCubeToModel ); + Reconstructor::SolutionParameters< Real >::template testAndSet< Dim >( unitCubeToModel ); if( envelopeDepth==-1 ) envelopeDepth = Reconstructor::SolutionParameters< Real >::baseDepth; if( envelopeDepth>Reconstructor::SolutionParameters< Real >::depth ) { @@ -707,7 +707,7 @@ namespace PoissonRecon implicit.unitCubeToModel = modelToUnitCube.inverse(); pointStream.reset(); - params.testAndSet( implicit.unitCubeToModel ); + params.template testAndSet< Dim >( implicit.unitCubeToModel ); { // Apply the transformation @@ -1110,7 +1110,7 @@ namespace PoissonRecon implicit.unitCubeToModel = modelToUnitCube.inverse(); pointStream.reset(); - params.testAndSet( implicit.unitCubeToModel ); + params.template testAndSet< Dim >( implicit.unitCubeToModel ); { // Apply the transformation From 4ec0c793853db27a5ac4fa27f9b4318d0a6c5a94 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Fri, 25 Apr 2025 10:37:14 -0400 Subject: [PATCH 81/86] Version18.71 --- README.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d9a5d0e9..661a6a7d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 18.60)

    +

    Adaptive Multigrid Solvers (Version 18.71)

    links compilation @@ -29,10 +29,12 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
    Executables: -Win64
    +Win64
    Source Code: -ZIP GitHub
    +ZIP GitHub
    Older Versions: +V18.70, +V18.60, V18.55, V18.50, V18.42, @@ -1763,6 +1765,16 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • Resolved clang compilation issues. +Version 18.70: +
      +
    1. Added support for 2D iso-surfacing. +
    + +Version 18.70: +
      +
    1. Fixed bug with width estimation reading translational component. +
    +
    From 2c10a4eda26ffd46091b38f8dabe906a07780dbb Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Tue, 29 Apr 2025 09:55:19 -0400 Subject: [PATCH 82/86] Version 18.72 --- README.md | 20 +++++++++------ Src/DataStream.imp.inl | 12 ++++++--- Src/Geometry.h | 2 +- Src/MergePlyClientServer.inl | 12 +++++---- Src/Ply.inl | 38 ++++++++++++++++++++--------- Src/PointPartitionClientServer.inl | 10 +++++--- Src/PoissonRecon.client.inl | 12 ++++----- Src/PoissonRecon.cpp | 22 +++++++++++------ Src/PoissonRecon.server.inl | 4 +-- Src/PreProcessor.h | 2 +- Src/VertexFactory.h | 39 +++++++++++++++++++----------- 11 files changed, 110 insertions(+), 63 deletions(-) diff --git a/README.md b/README.md index 661a6a7d..dfce4aa1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 18.71)

    +

    Adaptive Multigrid Solvers (Version 18.72)

    links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
    Executables: -Win64
    +Win64
    Source Code: -ZIP GitHub
    +ZIP GitHub
    Older Versions: +V18.71, V18.70, V18.60, V18.55, @@ -1753,28 +1754,33 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • Cleaned-up multi-threading code. -Version 18.55: +Version 18.55:
    1. Added the ScaleNormals executable.
    2. Removed the --confidenceBias flag.
    -Version 18.60: +Version 18.60:
    1. Changed the --confidence flag to be a bool (enabling is equivalent to having set to 1.0).
    2. Resolved clang compilation issues.
    -Version 18.70: +Version 18.70:
    1. Added support for 2D iso-surfacing.
    -Version 18.70: +Version 18.71:
    1. Fixed bug with width estimation reading translational component.
    +Version 18.72: +
      +
    1. Minor code refactoring +
    +
    diff --git a/Src/DataStream.imp.inl b/Src/DataStream.imp.inl index 4528fda8..eae03dcd 100644 --- a/Src/DataStream.imp.inl +++ b/Src/DataStream.imp.inl @@ -150,7 +150,9 @@ void PLYInputDataStream< Factory >::reset( void ) bool* properties = new bool[ _factory.plyReadNum() ]; for( unsigned int i=0 ; i<_factory.plyReadNum() ; i++ ) { - PlyProperty prop = _factory.isStaticallyAllocated() ? _factory.plyStaticReadProperty(i) : _factory.plyReadProperty(i); + PlyProperty prop; + if constexpr( Factory::IsStaticallyAllocated() ) prop = _factory.plyStaticReadProperty(i); + else prop = _factory.plyReadProperty(i); if( !_ply->get_property( elem_name , &prop ) ) properties[i] = false; else properties[i] = true; } @@ -178,7 +180,7 @@ bool PLYInputDataStream< Factory >::read( Data &d ) { if( _pIdx<_pCount ) { - if( _factory.isStaticallyAllocated() ) _ply->get_element( (void *)&d ); + if constexpr( Factory::IsStaticallyAllocated() ) _ply->get_element( (void *)&d ); else { _ply->get_element( PointerAddress( _buffer ) ); @@ -206,7 +208,9 @@ PLYOutputDataStream< Factory >::PLYOutputDataStream( const char* fileName , cons _ply->element_count( "vertex" , _pCount ); for( unsigned int i=0 ; i<_factory.plyWriteNum() ; i++ ) { - PlyProperty prop = _factory.isStaticallyAllocated() ? _factory.plyStaticWriteProperty(i) : _factory.plyWriteProperty(i); + PlyProperty prop; + if constexpr( Factory::IsStaticallyAllocated() ) prop = _factory.plyStaticWriteProperty(i); + else prop = _factory.plyWriteProperty(i); _ply->describe_property( "vertex" , &prop ); } _ply->header_complete(); @@ -227,7 +231,7 @@ template< typename Factory > size_t PLYOutputDataStream< Factory >::write( const Data &d ) { if( _pIdx==_pCount ) MK_ERROR_OUT( "Trying to add more points than total: " , _pIdx , " < " , _pCount ); - if( _factory.isStaticallyAllocated() ) _ply->put_element( (void *)&d ); + if constexpr( Factory::IsStaticallyAllocated() ) _ply->put_element( (void *)&d ); else { _factory.toBuffer( d , _buffer ); diff --git a/Src/Geometry.h b/Src/Geometry.h index 12dde7b3..3310ca57 100644 --- a/Src/Geometry.h +++ b/Src/Geometry.h @@ -274,7 +274,7 @@ namespace PoissonRecon Point &operator = ( const Point &p ) { - if( !_dim ){ _resize( p._dim ) ; memcpy( _coords , p._coords , sizeof(Real)*_dim ); } + if( !_dim || !p._dim ){ _resize( p._dim ) ; memcpy( _coords , p._coords , sizeof(Real)*_dim ); } else if( _dim==p._dim ) memcpy( _coords , p._coords , sizeof(Real)*_dim ); else MK_ERROR_OUT( "Dimensions don't match: " , _dim , " != " , p._dim ); return *this; diff --git a/Src/MergePlyClientServer.inl b/Src/MergePlyClientServer.inl index 48e17c6d..9a17e618 100644 --- a/Src/MergePlyClientServer.inl +++ b/Src/MergePlyClientServer.inl @@ -59,8 +59,8 @@ template< typename Factory > size_t SizeOnDisk( const Factory &factory ) { size_t sizeOnDisk = 0; - if( factory.isStaticallyAllocated() ) for( unsigned int i=0 ; i( elems[0] ) += vNum[i]; for( unsigned int i=0 ; i( elems[0] ) -= sharedVertexCounts[i]; std::get<2>( elems[0] ).resize( factory.plyWriteNum() ); - for( unsigned int i=0 ; i( elems[0] )[i] = factory.isStaticallyAllocated() ? factory.plyStaticWriteProperty(i) : factory.plyWriteProperty(i); + for( unsigned int i=0 ; i( elems[0] )[i] = factory.plyStaticWriteProperty(i); + else std::get<2>( elems[0] )[i] = factory.plyWriteProperty(i); std::get<0>( elems[1] ) = std::string( "face" ); std::get<1>( elems[1] ) = 0; @@ -300,7 +302,7 @@ void _RunServer Vertex v = factory(); for( unsigned int j=0 ; jget_element( &v ); sharedVertices[j] = ( sharedVertices[j] + v ) / (Real)2.; @@ -344,7 +346,7 @@ void _RunServer for( unsigned int j=0 ; jget_element( (void*)&sharedVertices[j] ); + if constexpr( Factory::IsStaticallyAllocated() ) inPly->get_element( (void*)&sharedVertices[j] ); else { inPly->get_element( PointerAddress( vBuffer ) ); diff --git a/Src/Ply.inl b/Src/Ply.inl index 99dba468..0fbb54b6 100644 --- a/Src/Ply.inl +++ b/Src/Ply.inl @@ -132,7 +132,9 @@ namespace PLY for( int i=0 ; i<(int)elist.size() ; i++ ) if( elist[i]=="vertex" ) for( unsigned int j=0 ; jget_property( elist[i] , &prop )!=0 ); } @@ -159,7 +161,9 @@ namespace PLY bool found = false; for( unsigned int j=0 ; jget_property( elem_name , &prop ); if( readFlags ) readFlags[i] = (hasProperty!=0); } @@ -225,7 +231,7 @@ namespace PLY Pointer( char ) buffer = NewPointer< char >( vFactory.bufferSize() ); for( size_t j=0 ; jget_element( (void*)&vertices[j] ); + if constexpr( VertexFactory::IsStaticallyAllocated() ) ply->get_element( (void*)&vertices[j] ); else { ply->get_element( PointerAddress( buffer ) ); @@ -275,7 +281,9 @@ namespace PLY { for( unsigned int i=0 ; iget_property( elem_name , &prop ); if( readFlags ) readFlags[i] = (hasProperty!=0); } @@ -283,7 +291,7 @@ namespace PLY Pointer( char ) buffer = NewPointer< char >( vFactory.bufferSize() ); for( size_t j=0 ; jget_element( (void *)&vertices[j] ); + if constexpr( VertexFactory::IsStaticallyAllocated() ) ply->get_element( (void*)&vertices[j] ); else { ply->get_element( PointerAddress( buffer ) ); @@ -327,7 +335,9 @@ namespace PLY ply->element_count( "vertex", nr_vertices ); for( unsigned int i=0 ; idescribe_property( "vertex" , &prop ); } ply->element_count( "face" , nr_faces ); @@ -343,7 +353,7 @@ namespace PLY Pointer( char ) buffer = NewPointer< char >( vFactory.bufferSize() ); for( size_t j=0 ; jput_element( (void *)&vertices[j] ); + if constexpr( VertexFactory::IsStaticallyAllocated() ) ply->put_element( (void *)&vertices[j] ); else { vFactory.toBuffer( vertices[j] , buffer ); @@ -399,7 +409,9 @@ namespace PLY ply->element_count( "vertex" , vertexNum ); for( unsigned int i=0 ; idescribe_property( "vertex" , &prop ); } ply->element_count( "face" , polygonNum ); @@ -411,7 +423,7 @@ namespace PLY // write vertices ply->put_element_setup( "vertex" ); - if( vFactory.isStaticallyAllocated() ) + if constexpr( VertexFactory::IsStaticallyAllocated() ) { for( size_t i=0; ielement_count( "vertex" , vertexNum ); for( unsigned int i=0 ; idescribe_property( "vertex" , &prop ); } ply->element_count( "edge" , edgeNum ); @@ -490,7 +504,7 @@ namespace PLY // write vertices ply->put_element_setup( "vertex" ); - if( vFactory.isStaticallyAllocated() ) + if constexpr( VertexFactory::IsStaticallyAllocated() ) { for( size_t i=0; i range , const Fa } size_t leftToReadCount = range.second - range.first; - size_t vSize = factory.isStaticallyAllocated() ? sizeof( Vertex ) : factory.bufferSize(); + size_t vSize = 0; + if constexpr( Factory::IsStaticallyAllocated() ) vSize = sizeof( Vertex ); + else vSize = factory.bufferSize(); for( unsigned int i=0 ; iget_property( std::string( "vertex" ) , &prop ); } @@ -91,7 +95,7 @@ void _ProcessPLY( std::string in , std::pair< size_t , size_t > range , const Fa Pointer( char ) buffer = NewPointer< char >( factory.bufferSize() ); for( size_t i=range.first ; iget_element( (void *)&vertex ); + if constexpr( Factory::IsStaticallyAllocated() ) ply->get_element( (void *)&vertex ); else { ply->get_element( PointerAddress( buffer ) ); diff --git a/Src/PoissonRecon.client.inl b/Src/PoissonRecon.client.inl index 524a555f..25dcc150 100644 --- a/Src/PoissonRecon.client.inl +++ b/Src/PoissonRecon.client.inl @@ -713,7 +713,7 @@ size_t Client< Real , Dim , BType , Degree >::_send3( const ClientReconstruction if( needAuxData ) { - if( !auxDataFactory.isStaticallyAllocated() ) + if constexpr( !AuxDataFactory::IsStaticallyAllocated() ) { ProjectiveAuxDataTypeSerializer< Real > serializer( clientReconInfo.auxProperties ); state3.auxDataField.write( serverStream , serializer ); @@ -952,7 +952,7 @@ size_t Client< Real , Dim , BType , Degree >::_receive5( const ClientReconstruct using Data = typename _State5::Data; Data defaultValue; - if( !auxDataFactory.isStaticallyAllocated() ) + if constexpr( !AuxDataFactory::IsStaticallyAllocated() ) { ProjectiveAuxDataTypeSerializer< Real > serializer( clientReconInfo.auxProperties ); state5.auxDataField = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( serverStream , serializer ); @@ -1428,7 +1428,7 @@ if( idx!=nodes.size() ) MK_ERROR_OUT( "uhoh" ); if( needAuxData ) { - if( !auxDataFactory.isStaticallyAllocated() ) + if constexpr( !AuxDataFactory::IsStaticallyAllocated() ) { ProjectiveAuxDataTypeSerializer< Real > serializer( clientReconInfo.auxProperties ); _auxDataField.read( stream , serializer ); @@ -1443,7 +1443,7 @@ if( idx!=nodes.size() ) MK_ERROR_OUT( "uhoh" ); bool needAuxData = clientReconInfo.dataX>0 && auxDataFactory.bufferSize(); if( needAuxData ) { - if( !auxDataFactory.isStaticallyAllocated() ) + if constexpr( !AuxDataFactory::IsStaticallyAllocated() ) { ProjectiveAuxDataTypeSerializer< Real > serializer( clientReconInfo.auxProperties ); _auxDataField.read( stream , serializer ); @@ -1532,7 +1532,7 @@ void Client< Real , Dim , BType , Degree >::_write( const ClientReconstructionIn if( needAuxData ) { - if( !auxDataFactory.isStaticallyAllocated() ) + if constexpr( !AuxDataFactory::IsStaticallyAllocated() ) { ProjectiveAuxDataTypeSerializer< Real > serializer( clientReconInfo.auxProperties ); _auxDataField.write( stream , serializer ); @@ -1546,7 +1546,7 @@ void Client< Real , Dim , BType , Degree >::_write( const ClientReconstructionIn if( _auxDataField.size() ) { - if( !auxDataFactory.isStaticallyAllocated() ) + if constexpr( !AuxDataFactory::IsStaticallyAllocated() ) { ProjectiveAuxDataTypeSerializer< Real > serializer( clientReconInfo.auxProperties ); _auxDataField.write( stream , serializer ); diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index e09b1581..961830d5 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -420,17 +420,20 @@ void Execute( const AuxDataFactory &auxDataFactory ) typedef InputDataStream< SampleType > _InputPointStream; _InputPointStream &pointStream; SampleType scratch; - _InputOrientedSampleStream( _InputPointStream &pointStream ) : pointStream( pointStream ) - { - scratch = SampleType( Reconstructor::Position< Real , Dim >() , Reconstructor::Normal< Real , Dim >() ); - } + + _InputOrientedSampleStream( _InputPointStream &pointStream ) + : pointStream( pointStream ) , scratch( Reconstructor::Position< Real , Dim >() , Reconstructor::Normal< Real , Dim >() ) + {} + void reset( void ){ pointStream.reset(); } + bool read( Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n ) { bool ret = pointStream.read( scratch ); if( ret ) p = scratch.template get<0>() , n = scratch.template get<1>(); return ret; } + bool read( unsigned int thread , Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n ) { bool ret = pointStream.read( thread , scratch ); @@ -447,17 +450,20 @@ void Execute( const AuxDataFactory &auxDataFactory ) typedef InputDataStream< SampleType > _InputPointStream; _InputPointStream &pointStream; SampleType scratch; - _InputOrientedSampleWithDataStream( _InputPointStream &pointStream , typename AuxDataFactory::VertexType zero ) : pointStream( pointStream ) - { - scratch = SampleType( Reconstructor::Position< Real , Dim >() , DataType( Reconstructor::Normal< Real , Dim >() , zero ) ); - } + + _InputOrientedSampleWithDataStream( _InputPointStream &pointStream , typename AuxDataFactory::VertexType zero ) + : pointStream( pointStream ) , scratch( Reconstructor::Position< Real , Dim >() , DataType( Reconstructor::Normal< Real , Dim >() , zero ) ) + {} + void reset( void ){ pointStream.reset(); } + bool read( Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n , typename AuxDataFactory::VertexType &d ) { bool ret = pointStream.read( scratch ); if( ret ) p = scratch.template get<0>() , n = scratch.template get<1>().template get<0>() , d = scratch.template get<1>().template get<1>(); return ret; } + bool read( unsigned int thread , Reconstructor::Position< Real , Dim > &p , Reconstructor::Normal< Real , Dim > &n , typename AuxDataFactory::VertexType &d ) { bool ret = pointStream.read( thread , scratch ); diff --git a/Src/PoissonRecon.server.inl b/Src/PoissonRecon.server.inl index 08f39c35..1647a7b5 100644 --- a/Src/PoissonRecon.server.inl +++ b/Src/PoissonRecon.server.inl @@ -404,7 +404,7 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase4( const ClientReconstruc { Timer timer; SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > > *_auxDataField; - if( !auxDataFactory.isStaticallyAllocated() ) + if constexpr( !AuxDataFactory::IsStaticallyAllocated() ) { ProjectiveAuxDataTypeSerializer< Real > serializer( clientReconInfo.auxProperties ); _auxDataField = new SparseNodeData< ProjectiveData< AuxData , Real > , IsotropicUIntPack< Dim , DataSig > >( clientStream , serializer ); @@ -538,7 +538,7 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase4( const ClientReconstruc phaseInfo.processTime += timer.wallTime(); timer = Timer(); - if( !auxDataFactory.isStaticallyAllocated() ) + if constexpr( !AuxDataFactory::IsStaticallyAllocated() ) { ProjectiveAuxDataTypeSerializer< Real > serializer( clientReconInfo.auxProperties ); _auxDataField.write( clientStream , serializer ); diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 05d98a11..84f4a3a1 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -46,7 +46,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "18.71" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "18.72" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth diff --git a/Src/VertexFactory.h b/Src/VertexFactory.h index 4998e1b2..aea015e5 100644 --- a/Src/VertexFactory.h +++ b/Src/VertexFactory.h @@ -103,7 +103,6 @@ namespace PoissonRecon virtual void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const = 0; virtual void fromBuffer( ConstPointer( char ) buffer , VertexType &dt ) const = 0; - virtual bool isStaticallyAllocated( void ) const = 0; virtual PlyProperty plyStaticReadProperty( unsigned int idx ) const = 0; virtual PlyProperty plyStaticWriteProperty( unsigned int idx ) const = 0; @@ -136,7 +135,8 @@ namespace PoissonRecon void writeASCII( FILE *fp , const VertexType &dt ) const {} void writeBinary( FILE *fp , const VertexType &dt ) const {}; - bool isStaticallyAllocated( void ) const{ return true; } + static constexpr bool IsStaticallyAllocated( void ){ return true; } + PlyProperty plyStaticReadProperty( unsigned int idx ) const { if( idx>= plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ) ; return PlyProperty(); } PlyProperty plyStaticWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ) ; return PlyProperty(); } @@ -183,7 +183,8 @@ namespace PoissonRecon if( _realTypeOnDisk ) fwrite( &dt[0] , sizeof(Real) , Dim , fp ); else VertexIO< Real >::WriteBinary( fp , _typeOnDisk , Dim , &dt[0] ); } - bool isStaticallyAllocated( void ) const{ return true; } + + static constexpr bool IsStaticallyAllocated( void ){ return true; } PlyProperty plyStaticReadProperty( unsigned int idx ) const; PlyProperty plyStaticWriteProperty( unsigned int idx ) const; @@ -241,7 +242,8 @@ namespace PoissonRecon else VertexIO< Real >::WriteBinary( fp , _typeOnDisk , Dim , &dt[0] ); } - bool isStaticallyAllocated( void ) const{ return true; } + static constexpr bool IsStaticallyAllocated( void ){ return true; } + PlyProperty plyStaticReadProperty( unsigned int idx ) const; PlyProperty plyStaticWriteProperty( unsigned int idx ) const; @@ -291,7 +293,8 @@ namespace PoissonRecon VertexIO< Real >::WriteBinary( fp , _typeOnDisk , Dim , &dt[0] ); } - bool isStaticallyAllocated( void ) const{ return true; } + static constexpr bool IsStaticallyAllocated( void ){ return true; } + PlyProperty plyStaticReadProperty( unsigned int idx ) const; PlyProperty plyStaticWriteProperty( unsigned int idx ) const; @@ -342,7 +345,8 @@ namespace PoissonRecon VertexIO< Real >::WriteBinary( fp , _typeOnDisk , 3 , &dt[0] ); } - bool isStaticallyAllocated( void ) const{ return true; } + static constexpr bool IsStaticallyAllocated( void ){ return true; } + PlyProperty plyStaticReadProperty( unsigned int idx ) const; PlyProperty plyStaticWriteProperty( unsigned int idx ) const; @@ -392,7 +396,8 @@ namespace PoissonRecon VertexIO< Real >::WriteBinary( fp , _typeOnDisk , 4 , &dt[0] ); } - bool isStaticallyAllocated( void ) const{ return true; } + static constexpr bool IsStaticallyAllocated( void ){ return true; } + PlyProperty plyStaticReadProperty( unsigned int idx ) const; PlyProperty plyStaticWriteProperty( unsigned int idx ) const; @@ -441,7 +446,8 @@ namespace PoissonRecon else VertexIO< Real >::WriteBinary( fp , _typeOnDisk , 1 , &dt ); } - bool isStaticallyAllocated( void ) const{ return true; } + static constexpr bool IsStaticallyAllocated( void ){ return true; } + PlyProperty plyStaticReadProperty( unsigned int idx ) const; PlyProperty plyStaticWriteProperty( unsigned int idx ) const; @@ -483,7 +489,8 @@ namespace PoissonRecon void writeASCII( FILE *fp , const VertexType &dt ) const; void writeBinary( FILE *fp , const VertexType &dt ) const; - bool isStaticallyAllocated( void ) const{ return false; } + static constexpr bool IsStaticallyAllocated( void ){ return false; } + PlyProperty plyStaticReadProperty( unsigned int idx ) const { MK_ERROR_OUT( "does not support static allocation" ) ; return PlyProperty(); } PlyProperty plyStaticWriteProperty( unsigned int idx ) const { MK_ERROR_OUT( "does not support static allocation" ) ; return PlyProperty(); } @@ -550,9 +557,9 @@ namespace PoissonRecon void writeASCII( FILE *fp , const VertexType &dt ) const { _writeASCII<0>( fp , dt ); } void writeBinary( FILE *fp , const VertexType &dt ) const { _writeBinary<0>( fp , dt ); } - bool isStaticallyAllocated( void ) const { return _isStaticallyAllocated<0>(); } - PlyProperty plyStaticReadProperty( unsigned int idx ) const { return _plyStaticReadProperty<0>( idx ); } - PlyProperty plyStaticWriteProperty( unsigned int idx ) const { return _plyStaticWriteProperty<0>( idx ); } + static constexpr bool IsStaticallyAllocated( void ){ return _IsStaticallyAllocated<0>(); } + PlyProperty plyStaticReadProperty( unsigned int idx ) const { if constexpr( IsStaticallyAllocated() ) return _plyStaticReadProperty<0>( idx ) ; else return PlyProperty(); } + PlyProperty plyStaticWriteProperty( unsigned int idx ) const { if constexpr( IsStaticallyAllocated() ) return _plyStaticWriteProperty<0>( idx ) ; else return PlyProperty(); } size_t bufferSize( void ) const { return _bufferSize<0>(); } void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const { _toBuffer<0>( dt , buffer ); } @@ -590,8 +597,12 @@ namespace PoissonRecon template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) >::type _writeBinary( FILE *fp , const VertexType &dt ) const { this->template get().writeBinary( fp , dt.template get() ) ; _writeBinary< I+1 >( fp , dt ); } template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) >::type _writeBinary( FILE *fp , const VertexType &dt ) const {} - template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , bool >::type _isStaticallyAllocated( void ) const { return this->template get< I >().isStaticallyAllocated() && _isStaticallyAllocated< I+1 >(); } - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , bool >::type _isStaticallyAllocated( void ) const { return true; } + template< unsigned int I > static constexpr bool _IsStaticallyAllocated( void ) + { + if constexpr( I::IsStaticallyAllocated() && _IsStaticallyAllocated< I+1 >(); + else return true; + } + template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , PlyProperty >::type _plyStaticReadProperty ( unsigned int idx ) const; template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , PlyProperty >::type _plyStaticWriteProperty( unsigned int idx ) const; template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyStaticReadProperty ( unsigned int idx ) const { MK_ERROR_OUT( "read property out of bounds" ) ; return PlyProperty(); } From 8f08175d5ee69d7c41197fed5861b7e896a47d7f Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Tue, 29 Apr 2025 11:22:17 -0400 Subject: [PATCH 83/86] Version 18.73 --- README.md | 12 ++++-- Src/AdaptiveTreeVisualization.cpp | 20 +++++----- Src/Allocator.h | 4 +- Src/Array.inl | 36 ++++++++--------- Src/BSplineData.inl | 4 +- Src/BlockedVector.h | 28 ++++++------- Src/ChunkPLY.cpp | 10 ++--- Src/CmdLineParser.inl | 6 +-- Src/DataStream.imp.h | 2 +- Src/DataStream.imp.inl | 22 +++++----- Src/EDTInHeat.cpp | 8 ++-- Src/FEMTree.Evaluation.inl | 12 +++--- Src/FEMTree.Initialize.inl | 34 ++++++++-------- Src/FEMTree.LevelSet.2D.inl | 54 ++++++++++++------------- Src/FEMTree.LevelSet.3D.inl | 52 ++++++++++++------------ Src/FEMTree.LevelSet.inl | 16 ++++---- Src/FEMTree.SortedTreeNodes.inl | 4 +- Src/FEMTree.System.inl | 14 +++---- Src/FEMTree.WeightedSamples.inl | 2 +- Src/FEMTree.h | 54 ++++++++++++------------- Src/FEMTree.inl | 36 ++++++++--------- Src/Geometry.h | 24 +++++------ Src/Image.h | 40 +++++++++---------- Src/ImageStitching.cpp | 8 ++-- Src/JPEG.inl | 10 ++--- Src/MarchingCubes.h | 6 +-- Src/MergePlyClientServer.inl | 26 ++++++------ Src/NestedVector.h | 16 ++++---- Src/PNG.inl | 26 ++++++------ Src/Ply.inl | 42 ++++++++++---------- Src/PlyFile.h | 14 +++---- Src/PlyFile.inl | 46 ++++++++++----------- Src/PointInterpolant.cpp | 26 ++++++------ Src/PointPartition.inl | 32 +++++++-------- Src/PointPartitionClientServer.inl | 48 +++++++++++----------- Src/PointsToDisks.cpp | 2 +- Src/PoissonRecon.client.inl | 20 +++++----- Src/PoissonRecon.cpp | 18 ++++----- Src/PoissonRecon.server.inl | 6 +-- Src/PoissonReconClient.cpp | 8 ++-- Src/PoissonReconClientServer.inl | 64 +++++++++++++++--------------- Src/PoissonReconServer.cpp | 16 ++++---- Src/Polynomial.inl | 2 +- Src/PreProcessor.h | 2 +- Src/Rasterizer.inl | 6 +-- Src/Reconstructors.streams.h | 2 +- Src/RegularGrid.inl | 16 ++++---- Src/RegularTree.inl | 8 ++-- Src/SSDRecon.cpp | 20 +++++----- Src/ScaleNormals.cpp | 8 ++-- Src/Socket.h | 8 ++-- Src/Socket.inl | 24 +++++------ Src/SparseMatrix.inl | 20 +++++----- Src/SurfaceTrimmer.cpp | 10 ++--- Src/VertexFactory.h | 20 +++++----- Src/VertexFactory.inl | 64 +++++++++++++++--------------- 56 files changed, 572 insertions(+), 566 deletions(-) diff --git a/README.md b/README.md index dfce4aa1..80a37cf7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 18.72)

    +

    Adaptive Multigrid Solvers (Version 18.73)

    links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
    Executables: -Win64
    +Win64
    Source Code: -ZIP GitHub
    +ZIP GitHub
    Older Versions: +V18.72, V18.71, V18.70, V18.60, @@ -1781,6 +1782,11 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • Minor code refactoring +Version 18.73: +
      +
    1. Replaced MK_ERROR_OUT with MK_THROW to throw an exception rather than exit directly. +
    +
    diff --git a/Src/AdaptiveTreeVisualization.cpp b/Src/AdaptiveTreeVisualization.cpp index 6af250e0..a2a7812b 100644 --- a/Src/AdaptiveTreeVisualization.cpp +++ b/Src/AdaptiveTreeVisualization.cpp @@ -176,7 +176,7 @@ void WriteGrid( const char *fileName , ConstPointer( Real ) values , unsigned in else if( !strcasecmp( ext , "iso" ) ) { FILE *fp = fopen( fileName , "wb" ); - if( !fp ) MK_ERROR_OUT( "Failed to open file for writing: " , fileName ); + if( !fp ) MK_THROW( "Failed to open file for writing: " , fileName ); int r = (int)res; fwrite( &r , sizeof(int) , 1 , fp ); size_t count = 1; @@ -381,7 +381,7 @@ void _Execute( const FEMTree< Dim , Real > *tree , XForm< Real , Dim+1 > modelTo sliceModelToUnitCube(Dim-1,i) = modelToUnitCube(Dim,i); } FILE *fp = fopen( OutSlice.value , "wb" ); - if( !fp ) MK_ERROR_OUT( "Failed to open file for writing: " , OutSlice.value ); + if( !fp ) MK_THROW( "Failed to open file for writing: " , OutSlice.value ); FileStream fs(fp); FEMTree< Dim-1 , Real >::WriteParameter( fs ); DenseNodeData< Real , IsotropicUIntPack< Dim-1 , FEMSig > >::WriteSignatures( fs ); @@ -432,7 +432,7 @@ void Execute( BinaryStream &stream , int degree , FEMTree< Dim , Real > *tree , case 2: _Execute< Dim , Real , FEMDegreeAndBType< 2 , BType >::Signature >( tree , modelToUnitCube , stream ) ; break; case 3: _Execute< Dim , Real , FEMDegreeAndBType< 3 , BType >::Signature >( tree , modelToUnitCube , stream ) ; break; case 4: _Execute< Dim , Real , FEMDegreeAndBType< 4 , BType >::Signature >( tree , modelToUnitCube , stream ) ; break; - default: MK_ERROR_OUT( "Only B-Splines of degree 1 - 4 are supported" ); + default: MK_THROW( "Only B-Splines of degree 1 - 4 are supported" ); } } @@ -450,7 +450,7 @@ void Execute( BinaryStream &stream , int degree , BoundaryType bType ) case BOUNDARY_FREE: return Execute< Dim , Real , BOUNDARY_FREE >( stream , degree , &tree , modelToUnitCube ); case BOUNDARY_NEUMANN: return Execute< Dim , Real , BOUNDARY_NEUMANN >( stream , degree , &tree , modelToUnitCube ); case BOUNDARY_DIRICHLET: return Execute< Dim , Real , BOUNDARY_DIRICHLET >( stream , degree , &tree , modelToUnitCube ); - default: MK_ERROR_OUT( "Not a valid boundary type: " , bType ); + default: MK_THROW( "Not a valid boundary type: " , bType ); } } @@ -477,7 +477,7 @@ int main( int argc , char* argv[] ) return EXIT_FAILURE; } FILE* fp = fopen( In.value , "rb" ); - if( !fp ) MK_ERROR_OUT( "Failed to open file for reading: " , In.value ); + if( !fp ) MK_THROW( "Failed to open file for reading: " , In.value ); FEMTreeRealType realType ; int degree ; BoundaryType bType; unsigned int dimension; FileStream fs(fp); @@ -485,8 +485,8 @@ int main( int argc , char* argv[] ) { unsigned int dim = dimension; unsigned int* sigs = ReadDenseNodeDataSignatures( fs , dim ); - if( dimension!=dim ) MK_ERROR_OUT( "Octree and node data dimensions don't math: " , dimension , " != " , dim ); - for( unsigned int d=1 ; d( fs , degree , bType ) ; break; case FEM_TREE_REAL_DOUBLE: Execute< 2 , double >( fs , degree , bType ) ; break; - default: MK_ERROR_OUT( "Unrecognized real type: " , realType ); + default: MK_THROW( "Unrecognized real type: " , realType ); } break; case 3: @@ -508,10 +508,10 @@ int main( int argc , char* argv[] ) { case FEM_TREE_REAL_FLOAT: Execute< 3 , float >( fs , degree , bType ) ; break; case FEM_TREE_REAL_DOUBLE: Execute< 3 , double >( fs , degree , bType ) ; break; - default: MK_ERROR_OUT( "Unrecognized real type: " , realType ); + default: MK_THROW( "Unrecognized real type: " , realType ); } break; - default: MK_ERROR_OUT( "Only dimensions 1-4 supported" ); + default: MK_THROW( "Only dimensions 1-4 supported" ); } fclose( fp ); diff --git a/Src/Allocator.h b/Src/Allocator.h index e35e3542..4c8c2b3c 100644 --- a/Src/Allocator.h +++ b/Src/Allocator.h @@ -88,13 +88,13 @@ namespace PoissonRecon { Pointer( T ) mem; if( !elements ) return NullPointer( T ); - if( elements>_blockSize ) MK_ERROR_OUT( "elements bigger than block-size: " , elements , " > " , _blockSize ); + if( elements>_blockSize ) MK_THROW( "elements bigger than block-size: " , elements , " > " , _blockSize ); if( _state.remains( _blockSize ); - if( !mem ) MK_ERROR_OUT( "Failed to allocate memory" ); + if( !mem ) MK_THROW( "Failed to allocate memory" ); _memory.push_back( mem ); } _state.index++; diff --git a/Src/Array.inl b/Src/Array.inl index 7eb1f472..e8faf3ef 100644 --- a/Src/Array.inl +++ b/Src/Array.inl @@ -35,7 +35,7 @@ class Array friend class ConstArray< C >; void _assertBounds( std::ptrdiff_t idx ) const { - if( idx=max ) PoissonRecon::MK_ERROR_OUT( "Array index out-of-bounds: " , min , " <= " , idx , " < " , max ); + if( idx=max ) PoissonRecon::MK_THROW( "Array index out-of-bounds: " , min , " <= " , idx , " < " , max ); } protected: C *data , *_data; @@ -119,7 +119,7 @@ public: 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 ) PoissonRecon::MK_ERROR_OUT( "Could not convert array [ " , a.minimum() , " , " , a.maximum() , " ] * " , szD , " => [ " , min , " , " , max , " ] * " , szC ); + if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD ) PoissonRecon::MK_THROW( "Could not convert array [ " , a.minimum() , " , " , a.maximum() , " ] * " , szD , " => [ " , min , " , " , max , " ] * " , szC ); } } static Array FromPointer( C* data , std::ptrdiff_t max ) @@ -236,7 +236,7 @@ class ConstArray template< class D > friend class ConstArray; void _assertBounds( std::ptrdiff_t idx ) const { - if( idx=max ) PoissonRecon::MK_ERROR_OUT( "ConstArray index out-of-bounds: " , min , " <= " , idx , " < " , max ); + if( idx=max ) PoissonRecon::MK_THROW( "ConstArray index out-of-bounds: " , min , " <= " , idx , " < " , max ); } protected: const C *data; @@ -266,7 +266,7 @@ public: 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 ) PoissonRecon::MK_ERROR_OUT( "Could not convert const array [ " , a.minimum() , " , " , a.maximum() , " ] * " , szD , " => [ " , min , " , " , max , " ] * " , szC ); + if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD ) PoissonRecon::MK_THROW( "Could not convert const array [ " , a.minimum() , " , " , a.maximum() , " ] * " , szD , " => [ " , min , " , " , max , " ] * " , szC ); } template< class D > inline ConstArray( ConstArray< D > a ) @@ -277,7 +277,7 @@ public: 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 ) PoissonRecon::MK_ERROR_OUT( "Could not convert array [ " , a.minimum() , " , " , a.maximum() , " ] * " , szD , " => [ " , min , " , " , max , " ] * " , szC ); + if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD ) PoissonRecon::MK_THROW( "Could not convert array [ " , a.minimum() , " , " , a.maximum() , " ] * " , szD , " => [ " , min , " , " , max , " ] * " , szC ); } explicit operator Array< C >() const { @@ -361,44 +361,44 @@ public: template< class C > Array< C > memcpy( Array< C > destination , const void* source , size_t size ) { - if( size>destination.maximum()*sizeof(C) ) PoissonRecon::MK_ERROR_OUT( "Size of copy exceeds destination maximum: " , size , " > " , destination.maximum()*sizeof( C ) ); + if( size>destination.maximum()*sizeof(C) ) PoissonRecon::MK_THROW( "Size of copy exceeds destination maximum: " , size , " > " , destination.maximum()*sizeof( C ) ); 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 ) ) PoissonRecon::MK_ERROR_OUT( "Size of copy exceeds destination maximum: " , size , " > " , destination.maximum()*sizeof( C ) ); - if( size>source.maximum()*sizeof( D ) ) PoissonRecon::MK_ERROR_OUT( "Size of copy exceeds source maximum: " , size , " > " , source.maximum()*sizeof( D ) ); + if( size>destination.maximum()*sizeof( C ) ) PoissonRecon::MK_THROW( "Size of copy exceeds destination maximum: " , size , " > " , destination.maximum()*sizeof( C ) ); + if( size>source.maximum()*sizeof( D ) ) PoissonRecon::MK_THROW( "Size of copy exceeds source maximum: " , size , " > " , source.maximum()*sizeof( D ) ); 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 ) ) PoissonRecon::MK_ERROR_OUT( "Size of copy exceeds destination maximum: " , size , " > " , destination.maximum()*sizeof( C ) ); - if( size>source.maximum()*sizeof( D ) ) PoissonRecon::MK_ERROR_OUT( "Size of copy exceeds source maximum: " , size , " > " , source.maximum()*sizeof( D ) ); + if( size>destination.maximum()*sizeof( C ) ) PoissonRecon::MK_THROW( "Size of copy exceeds destination maximum: " , size , " > " , destination.maximum()*sizeof( C ) ); + if( size>source.maximum()*sizeof( D ) ) PoissonRecon::MK_THROW( "Size of copy exceeds source maximum: " , size , " > " , source.maximum()*sizeof( D ) ); 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 ) ) PoissonRecon::MK_ERROR_OUT( "Size of copy exceeds source maximum: " , size , " > " , source.maximum()*sizeof( D ) ); + if( size>source.maximum()*sizeof( D ) ) PoissonRecon::MK_THROW( "Size of copy exceeds source maximum: " , size , " > " , source.maximum()*sizeof( D ) ); 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 ) ) PoissonRecon::MK_ERROR_OUT( "Size of copy exceeds source maximum: " , size , " > " , source.maximum()*sizeof( D ) ); + if( size>source.maximum()*sizeof( D ) ) PoissonRecon::MK_THROW( "Size of copy exceeds source maximum: " , size , " > " , source.maximum()*sizeof( D ) ); 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 ) ) PoissonRecon::MK_ERROR_OUT( "Size of set exceeds destination maximum: " , size , " > " , destination.maximum()*sizeof( C ) ); + if( size>destination.maximum()*sizeof( C ) ) PoissonRecon::MK_THROW( "Size of set exceeds destination maximum: " , size , " > " , destination.maximum()*sizeof( C ) ); if( size ) memset( &destination[0] , value , size ); return destination; } @@ -406,28 +406,28 @@ Array< C > memset( Array< C > destination , int value , size_t size ) template< class C > size_t fread( Array< C > destination , size_t eSize , size_t count , FILE* fp ) { - if( count*eSize>destination.maximum()*sizeof( C ) ) PoissonRecon::MK_ERROR_OUT( "Size of read exceeds source maximum: " , count*eSize , " > " , destination.maximum()*sizeof( C ) ); + if( count*eSize>destination.maximum()*sizeof( C ) ) PoissonRecon::MK_THROW( "Size of read exceeds source maximum: " , count*eSize , " > " , destination.maximum()*sizeof( C ) ); if( count ) return fread( &destination[0] , eSize , count , fp ); else return 0; } template< class C > size_t fwrite( Array< C > source , size_t eSize , size_t count , FILE* fp ) { - if( count*eSize>source.maximum()*sizeof( C ) ) PoissonRecon::MK_ERROR_OUT( "Size of write exceeds source maximum: " , count*eSize , " > " , source.maximum()*sizeof( C ) ); + if( count*eSize>source.maximum()*sizeof( C ) ) PoissonRecon::MK_THROW( "Size of write exceeds source maximum: " , count*eSize , " > " , source.maximum()*sizeof( C ) ); if( count ) return fwrite( &source[0] , eSize , count , fp ); else return 0; } template< class C > size_t fwrite( ConstArray< C > source , size_t eSize , size_t count , FILE* fp ) { - if( count*eSize>source.maximum()*sizeof( C ) ) PoissonRecon::MK_ERROR_OUT( "Size of write exceeds source maximum: " , count*eSize , " > " , source.maximum()*sizeof( C ) ); + if( count*eSize>source.maximum()*sizeof( C ) ) PoissonRecon::MK_THROW( "Size of write exceeds source maximum: " , count*eSize , " > " , source.maximum()*sizeof( C ) ); if( count ) return fwrite( &source[0] , eSize , count , fp ); else return 0; } template< class C > void qsort( Array< C > base , size_t numElements , size_t elementSize , int (*compareFunction)( const void* , const void* ) ) { - if( sizeof(C)!=elementSize ) PoissonRecon::MK_ERROR_OUT( "Element sizes differ: " , sizeof(C) , " != " , elementSize ); - if( base.minimum()>0 || base.maximum() " , Degree1 ); - if( D2>Degree2 ) MK_ERROR_OUT( "Taking more derivatives than the degree: " , D2 , " > " , Degree2 ); + if( D1>Degree1 ) MK_THROW( "Taking more derivatives than the degree: " , D1 , " > " , Degree1 ); + if( D2>Degree2 ) MK_THROW( "Taking more derivatives than the degree: " , D2 , " > " , Degree2 ); const int _Degree1 = ( Degree1>=D1 ) ? Degree1 - D1 : 0 , _Degree2 = ( Degree2>=D2 ) ? Degree2 - D2 : 0; int sums[ Degree1+1 ][ Degree2+1 ]; diff --git a/Src/BlockedVector.h b/Src/BlockedVector.h index 92f0bce0..27d4ca2d 100644 --- a/Src/BlockedVector.h +++ b/Src/BlockedVector.h @@ -182,19 +182,19 @@ namespace PoissonRecon { for( size_t i=0 ; i<_allocatedBlocks ; i++ ) DeletePointer( _blocks[i] ); DeletePointer( _blocks ); - if( !stream.read( _size ) ) MK_ERROR_OUT( "Failed to read _size" ); - if( !stream.read( _defaultValue ) ) MK_ERROR_OUT( "Failed to read _defaultValue" ); - if( !stream.read( _reservedBlocks ) ) MK_ERROR_OUT( "Failed to read _reservedBlocks" ); - if( !stream.read( _allocatedBlocks ) ) MK_ERROR_OUT( "Failed to read _allocatedBlocks" ); + if( !stream.read( _size ) ) MK_THROW( "Failed to read _size" ); + if( !stream.read( _defaultValue ) ) MK_THROW( "Failed to read _defaultValue" ); + if( !stream.read( _reservedBlocks ) ) MK_THROW( "Failed to read _reservedBlocks" ); + if( !stream.read( _allocatedBlocks ) ) MK_THROW( "Failed to read _allocatedBlocks" ); _blocks = NewPointer< Pointer( T ) >( _reservedBlocks ); - if( !_blocks ) MK_ERROR_OUT( "Failed to allocate _blocks: " , _reservedBlocks ); + if( !_blocks ) MK_THROW( "Failed to allocate _blocks: " , _reservedBlocks ); for( size_t i=0 ; i<_allocatedBlocks ; i++ ) { _blocks[i] = NewPointer< T >( _BlockSize ); - if( !_blocks[i] ) MK_ERROR_OUT( "Failed to allocate _blocks[" , i , "]" ); - if( !stream.read( _blocks[i] , _BlockSize ) ) MK_ERROR_OUT( "Failed to read _blocks[" , i , "]" ); + if( !_blocks[i] ) MK_THROW( "Failed to allocate _blocks[" , i , "]" ); + if( !stream.read( _blocks[i] , _BlockSize ) ) MK_THROW( "Failed to read _blocks[" , i , "]" ); } for( size_t i=_allocatedBlocks ; i<_reservedBlocks ; i++ ) _blocks[i] = NullPointer( T ); } @@ -207,24 +207,24 @@ namespace PoissonRecon DeletePointer( _blocks ); _size = _allocatedBlocks = _reservedBlocks = 0; - if( !stream.read( _size ) ) MK_ERROR_OUT( "Failed to read _size" ); + if( !stream.read( _size ) ) MK_THROW( "Failed to read _size" ); #ifdef SHOW_WARNINGS #pragma message( "[WARNING] Should deserialize default value" ) #endif // SHOW_WARNINGS - if( !stream.read( _defaultValue ) ) MK_ERROR_OUT( "Failed to read _defaultValue" ); - if( !stream.read( _reservedBlocks ) ) MK_ERROR_OUT( "Failed to read _reservedBlocks" ); - if( !stream.read( _allocatedBlocks ) ) MK_ERROR_OUT( "Failed to read _allocatedBlocks" ); + if( !stream.read( _defaultValue ) ) MK_THROW( "Failed to read _defaultValue" ); + if( !stream.read( _reservedBlocks ) ) MK_THROW( "Failed to read _reservedBlocks" ); + if( !stream.read( _allocatedBlocks ) ) MK_THROW( "Failed to read _allocatedBlocks" ); _blocks = NewPointer< Pointer( T ) >( _reservedBlocks ); - if( !_blocks ) MK_ERROR_OUT( "Failed to allocate _blocks: " , _reservedBlocks ); + if( !_blocks ) MK_THROW( "Failed to allocate _blocks: " , _reservedBlocks ); for( size_t i=0 ; i<_allocatedBlocks ; i++ ) { _blocks[i] = NewPointer< T >( _BlockSize ); - if( !_blocks[i] ) MK_ERROR_OUT( "Failed to allocate _blocks[" , i , "]" ); + if( !_blocks[i] ) MK_THROW( "Failed to allocate _blocks[" , i , "]" ); } if( _size ) { Pointer( char ) buffer = NewPointer< char >( _size * serializedSize ); - if( !stream.read( buffer , serializedSize*_size ) ) MK_ERROR_OUT( "Failed tor read in data" ); + if( !stream.read( buffer , serializedSize*_size ) ) MK_THROW( "Failed tor read in data" ); for( unsigned int i=0 ; i<_size ; i++ ) serializer.deserialize( buffer+i*serializedSize , operator[]( i ) ); DeletePointer( buffer ); } diff --git a/Src/ChunkPLY.cpp b/Src/ChunkPLY.cpp index ff3da727..608aa2a6 100644 --- a/Src/ChunkPLY.cpp +++ b/Src/ChunkPLY.cpp @@ -164,12 +164,12 @@ void WriteMesh( const char *fileName , int ft , VertexDataFactory vertexDataFact FullVertexFactory< Real , Dim , VertexDataFactory > vertexFactory( VertexFactory::PositionFactory< Real , Dim >() , vertexDataFactory ); char *ext = GetFileExtension( fileName ); - if( strcasecmp( ext , "ply" ) ) MK_ERROR_OUT( "Can only output mesh to .ply file" ); + if( strcasecmp( ext , "ply" ) ) MK_THROW( "Can only output mesh to .ply file" ); delete[] ext; if( vertices.size()>std::numeric_limits< int >::max() ) { - if( vertices.size()>std::numeric_limits< unsigned int >::max() ) MK_ERROR_OUT( "more vertices than can be indexed by an unsigned int: %llu" , (unsigned long long)vertices.size() ); + if( vertices.size()>std::numeric_limits< unsigned int >::max() ) MK_THROW( "more vertices than can be indexed by an unsigned int: %llu" , (unsigned long long)vertices.size() ); MK_WARN( "more vertices than can be indexed by an int, using unsigned int instead: %llu" , (unsigned long long)vertices.size() ); std::vector< std::vector< unsigned int > > outPolygons; outPolygons.resize( polygons.size() ); @@ -585,7 +585,7 @@ int main( int argc , char* argv[] ) char *ext = GetFileExtension( In.values[i] ); bool _isPly = strcasecmp( ext , "ply" )==0; if( !i ) isPly = _isPly; - else if( isPly!=_isPly ) MK_ERROR_OUT( "All files must be of the same type" ); + else if( isPly!=_isPly ) MK_THROW( "All files must be of the same type" ); delete[] ext; } if( isPly ) @@ -597,10 +597,10 @@ int main( int argc , char* argv[] ) { std::vector< PlyProperty > unprocessedProperties; PLY::ReadVertexHeader( In.values[i] , factory , readFlags , unprocessedProperties ); - if( !factory.plyValidReadProperties( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain positions" ); + if( !factory.plyValidReadProperties( readFlags ) ) MK_THROW( "Ply file does not contain positions" ); VertexFactory::DynamicFactory< Real > _remainingProperties( unprocessedProperties ); if( !i ) remainingProperties = new VertexFactory::DynamicFactory< Real >( _remainingProperties ); - else if( (*remainingProperties)!=(_remainingProperties) ) MK_ERROR_OUT( "Remaining properties differ" ); + else if( (*remainingProperties)!=(_remainingProperties) ) MK_THROW( "Remaining properties differ" ); } delete[] readFlags; if( !remainingProperties || !remainingProperties->size() ) Execute( VertexFactory::EmptyFactory< Real >() ); diff --git a/Src/CmdLineParser.inl b/Src/CmdLineParser.inl index 57a7a5f3..6ba7cdd2 100644 --- a/Src/CmdLineParser.inl +++ b/Src/CmdLineParser.inl @@ -91,12 +91,12 @@ Point< Real , Dim > CmdLineType< Point< Real , Dim > >::StringToType( const char { if( d==0 ) { - if( temp[0]!='{' ) MK_ERROR_OUT( "Expected opening brace: " , std::string( str ) ); + if( temp[0]!='{' ) MK_THROW( "Expected opening brace: " , std::string( str ) ); t[d++] = CmdLineType< Real >::StringToType( temp+1 ); } else if( d==Dim-1 ) { - if( temp[ strlen(temp)-1 ]!='}' ) MK_ERROR_OUT( "Expected closing brace: " , std::string( str ) ); + if( temp[ strlen(temp)-1 ]!='}' ) MK_THROW( "Expected closing brace: " , std::string( str ) ); temp[ strlen(temp)-1 ] = 0; t[d++] = CmdLineType< Real >::StringToType( temp ); break; @@ -104,7 +104,7 @@ Point< Real , Dim > CmdLineType< Point< Real , Dim > >::StringToType( const char else t[d++] = CmdLineType< Real >::StringToType( temp ); temp = strtok( NULL ,"," ); } - if( d ASCIIInputDataStream< Factory >::ASCIIInputDataStream( const char* fileName , const Factory &factory ) : _factory( factory ) { _fp = fopen( fileName , "r" ); - if( !_fp ) MK_ERROR_OUT( "Failed to open file for reading: %s" , fileName ); + if( !_fp ) MK_THROW( "Failed to open file for reading: %s" , fileName ); } template< typename Factory > @@ -56,7 +56,7 @@ template< typename Factory > ASCIIOutputDataStream< Factory >::ASCIIOutputDataStream( const char* fileName , const Factory &factory ) : _factory( factory ) { _fp = fopen( fileName , "w" ); - if( !_fp ) MK_ERROR_OUT( "Failed to open file for writing: %s" , fileName ); + if( !_fp ) MK_THROW( "Failed to open file for writing: %s" , fileName ); } template< typename Factory > @@ -76,7 +76,7 @@ template< typename Factory > BinaryInputDataStream< Factory >::BinaryInputDataStream( const char* fileName , const Factory &factory ) : _factory(factory) { _fp = fopen( fileName , "rb" ); - if( !_fp ) MK_ERROR_OUT( "Failed to open file for reading: %s" , fileName ); + if( !_fp ) MK_THROW( "Failed to open file for reading: %s" , fileName ); } template< typename Factory > @@ -92,7 +92,7 @@ template< typename Factory > BinaryOutputDataStream< Factory >::BinaryOutputDataStream( const char* fileName , const Factory &factory ) : _factory(factory) { _fp = fopen( fileName , "wb" ); - if( !_fp ) MK_ERROR_OUT( "Failed to open file for writing: %s" , fileName ); + if( !_fp ) MK_THROW( "Failed to open file for writing: %s" , fileName ); } template< typename Factory > @@ -131,7 +131,7 @@ void PLYInputDataStream< Factory >::reset( void ) float version; if( _ply ) _free(); _ply = PlyFile::Read( _fileName, _elist, fileType, version ); - if( !_ply ) MK_ERROR_OUT( "Failed to open ply file for reading: " , _fileName ); + if( !_ply ) MK_THROW( "Failed to open ply file for reading: " , _fileName ); bool foundData = false; for( int i=0 ; i<_elist.size() ; i++ ) @@ -142,7 +142,7 @@ void PLYInputDataStream< Factory >::reset( void ) { size_t num_elems; std::vector< PlyProperty > plist = _ply->get_element_description( elem_name , num_elems ); - if( !plist.size() ) MK_ERROR_OUT( "Failed to get description for \"" , elem_name , "\"" ); + if( !plist.size() ) MK_THROW( "Failed to get description for \"" , elem_name , "\"" ); foundData = true; _pCount = num_elems , _pIdx = 0; @@ -158,10 +158,10 @@ void PLYInputDataStream< Factory >::reset( void ) } bool valid = _factory.plyValidReadProperties( properties ); delete[] properties; - if( !valid ) MK_ERROR_OUT( "Failed to validate properties in file" ); + if( !valid ) MK_THROW( "Failed to validate properties in file" ); } } - if( !foundData ) MK_ERROR_OUT( "Could not find data in ply file" ); + if( !foundData ) MK_THROW( "Could not find data in ply file" ); } template< typename Factory > @@ -201,7 +201,7 @@ PLYOutputDataStream< Factory >::PLYOutputDataStream( const char* fileName , cons float version; std::vector< std::string > elem_names = { std::string( "vertex" ) }; _ply = PlyFile::Write( fileName , elem_names , fileType , version ); - if( !_ply ) MK_ERROR_OUT( "Failed to open ply file for writing: " , fileName ); + if( !_ply ) MK_THROW( "Failed to open ply file for writing: " , fileName ); _pIdx = 0; _pCount = count; @@ -222,7 +222,7 @@ PLYOutputDataStream< Factory >::PLYOutputDataStream( const char* fileName , cons template< typename Factory > PLYOutputDataStream< Factory >::~PLYOutputDataStream( void ) { - if( _pIdx!=_pCount ) MK_ERROR_OUT( "Streamed points not equal to total count: " , _pIdx , " != " , _pCount ); + if( _pIdx!=_pCount ) MK_THROW( "Streamed points not equal to total count: " , _pIdx , " != " , _pCount ); delete _ply; DeletePointer( _buffer ); } @@ -230,7 +230,7 @@ PLYOutputDataStream< Factory >::~PLYOutputDataStream( void ) template< typename Factory > size_t PLYOutputDataStream< Factory >::write( const Data &d ) { - if( _pIdx==_pCount ) MK_ERROR_OUT( "Trying to add more points than total: " , _pIdx , " < " , _pCount ); + if( _pIdx==_pCount ) MK_THROW( "Trying to add more points than total: " , _pIdx , " < " , _pCount ); if constexpr( Factory::IsStaticallyAllocated() ) _ply->put_element( (void *)&d ); else { diff --git a/Src/EDTInHeat.cpp b/Src/EDTInHeat.cpp index 46e78dc8..27bf2e8d 100644 --- a/Src/EDTInHeat.cpp +++ b/Src/EDTInHeat.cpp @@ -208,7 +208,7 @@ void _Execute( int argc , char* argv[] ) for( int i=0 ; i<4 ; i++ ) for( int j=0 ; j<4 ; j++ ) { float f; - if( fscanf( fp , " %f " , &f )!=1 ) MK_ERROR_OUT( "Failed to read xform" ); + if( fscanf( fp , " %f " , &f )!=1 ) MK_THROW( "Failed to read xform" ); modelToUnitCube(i,j) = (Real)f; } fclose( fp ); @@ -441,7 +441,7 @@ void _Execute( int argc , char* argv[] ) if( len>GradientCutOff ) g /= len; Point< Real , Dim+1 >* leafValue = leafValues(leaf); if( leafValue ) for( int d=0 ; d::WriteParameter( fs ); DenseNodeData< Real , IsotropicUIntPack< Dim , FEMSig > >::WriteSignatures( fs ); @@ -546,7 +546,7 @@ void Execute( int argc , char* argv[] ) case 2: return _Execute< Dim , Real , FEMDegreeAndBType< 2 , BOUNDARY_FREE >::Signature >( argc , argv ); case 3: return _Execute< Dim , Real , FEMDegreeAndBType< 3 , BOUNDARY_FREE >::Signature >( argc , argv ); case 4: return _Execute< Dim , Real , FEMDegreeAndBType< 4 , BOUNDARY_FREE >::Signature >( argc , argv ); - default: MK_ERROR_OUT( "Only B-Splines of degree 1 - 4 are supported" ); + default: MK_THROW( "Only B-Splines of degree 1 - 4 are supported" ); } } #endif // !FAST_COMPILE diff --git a/Src/FEMTree.Evaluation.inl b/Src/FEMTree.Evaluation.inl index 2c7b7a6e..da9a15fd 100644 --- a/Src/FEMTree.Evaluation.inl +++ b/Src/FEMTree.Evaluation.inl @@ -208,12 +208,12 @@ template< unsigned int Dim , class Real > template< class V , unsigned int _PointD , unsigned int ... FEMSigs , unsigned int PointD > CumulativeDerivativeValues< V , Dim , _PointD > FEMTree< Dim , Real >::_getCenterValues( const ConstPointSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& neighborKey , const FEMTreeNode* node , ConstPointer( V ) solution , ConstPointer( V ) coarseSolution , const _Evaluator< UIntPack< FEMSigs ... > , PointD >& evaluator , int maxDepth , bool isInterior ) const { - if( IsActiveNode< Dim >( node->children ) && _localDepth( node->children )<=maxDepth ) MK_ERROR_OUT( "getCenterValues assumes leaf node" ); + if( IsActiveNode< Dim >( node->children ) && _localDepth( node->children )<=maxDepth ) MK_THROW( "getCenterValues assumes leaf node" ); typedef _Evaluator< UIntPack< FEMSigs ... > , PointD > _Evaluator; typedef UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... > SupportSizes; static const unsigned int supportSizes[] = { BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... }; - if( IsActiveNode< Dim >( node->children ) && _localDepth( node->children )<=maxDepth ) MK_ERROR_OUT( "getCenterValue assumes leaf node" ); + if( IsActiveNode< Dim >( node->children ) && _localDepth( node->children )<=maxDepth ) MK_THROW( "getCenterValue assumes leaf node" ); CumulativeDerivativeValues< V , Dim , _PointD > values; LocalDepth d ; LocalOffset cIdx; @@ -494,7 +494,7 @@ template< unsigned int ... FEMSigs , unsigned int PointD , typename T > template< unsigned int _PointD > CumulativeDerivativeValues< T , Dim , _PointD > FEMTree< Dim , Real >::_MultiThreadedEvaluator< UIntPack< FEMSigs ... > , PointD , T >::values( Point< Real , Dim > p , int thread , const FEMTreeNode* node ) { - if( _PointD>PointD ) MK_ERROR_OUT( "Evaluating more derivatives than available: " , _PointD , " <= " , PointD ); + if( _PointD>PointD ) MK_THROW( "Evaluating more derivatives than available: " , _PointD , " <= " , PointD ); if( !node ) node = _tree->leaf( p ); ConstPointSupportKey< FEMDegrees >& nKey = _pointNeighborKeys[thread]; nKey.getNeighbors( node ); @@ -506,7 +506,7 @@ template< unsigned int ... FEMSigs , unsigned int PointD , typename T > template< unsigned int _PointD > CumulativeDerivativeValues< T , Dim , _PointD > FEMTree< Dim , Real >::_MultiThreadedEvaluator< UIntPack< FEMSigs ... > , PointD , T >::centerValues( const FEMTreeNode* node , int thread ) { - if( _PointD>PointD ) MK_ERROR_OUT( "Evaluating more derivatives than available: " , _PointD, " <= " , PointD ); + if( _PointD>PointD ) MK_THROW( "Evaluating more derivatives than available: " , _PointD, " <= " , PointD ); ConstPointSupportKey< FEMDegrees >& nKey = _pointNeighborKeys[thread]; nKey.getNeighbors( node ); LocalDepth d ; LocalOffset off; @@ -518,7 +518,7 @@ template< unsigned int ... FEMSigs , unsigned int PointD , typename T > template< unsigned int _PointD > CumulativeDerivativeValues< T , Dim , _PointD > FEMTree< Dim , Real >::_MultiThreadedEvaluator< UIntPack< FEMSigs ... > , PointD , T >::cornerValues( const FEMTreeNode* node , int corner , int thread ) { - if( _PointD>PointD ) MK_ERROR_OUT( "Evaluating more derivatives than available: " , _PointD , " <= " , PointD ); + if( _PointD>PointD ) MK_THROW( "Evaluating more derivatives than available: " , _PointD , " <= " , PointD ); ConstCornerSupportKey< FEMDegrees >& nKey = _cornerNeighborKeys[thread]; nKey.getNeighbors( node ); LocalDepth d ; LocalOffset off; @@ -598,7 +598,7 @@ void FEMTree< Dim , Real >::_accumulate( const Coefficients& coefficients , Poin { { const FEMTreeNode* node = dataKey.neighbors[d].neighbors.data[ WindowIndex< UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportSize ... > , UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportEnd ... > >::Index ]; - if( !node ) MK_ERROR_OUT( "Point is not centered on a node: " , p , " " , WindowIndex< UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportSize ... > , UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportEnd ... > >::Index , " @ " , d ); + if( !node ) MK_THROW( "Point is not centered on a node: " , p , " " , WindowIndex< UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportSize ... > , UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportEnd ... > >::Index , " @ " , d ); pointEvaluator.initEvaluationState( p , _localDepth( node ) , state ); } double scratch[Dim+1]; diff --git a/Src/FEMTree.Initialize.inl b/Src/FEMTree.Initialize.inl index 7d177a6e..b826a984 100644 --- a/Src/FEMTree.Initialize.inl +++ b/Src/FEMTree.Initialize.inl @@ -453,7 +453,7 @@ size_t FEMTreeInitializer< Dim , Real >::_AddSimplex( FEMTreeNode* node , Simple template< unsigned int Dim , class Real > void FEMTreeInitializer< Dim , Real >::Initialize( FEMTreeNode& root , const std::vector< Point< Real , Dim > >& vertices , const std::vector< SimplexIndex< Dim-1 , node_index_type > >& simplices , unsigned int regularGridDepth , unsigned int maxDepth , std::vector< NodeSimplices< Dim , Real > >& nodeSimplices , std::vector< Allocator< FEMTreeNode > * > &nodeAllocators , std::function< void ( FEMTreeNode& ) > NodeInitializer ) { - if( regularGridDepth>maxDepth ) MK_ERROR_OUT( "Regular grid depth cannot excceed maximum depth: " , regularGridDepth , " <= " , maxDepth ); + if( regularGridDepth>maxDepth ) MK_THROW( "Regular grid depth cannot excceed maximum depth: " , regularGridDepth , " <= " , maxDepth ); // Allocate the tree up to the prescribed depth const Real RegularGridWidth = (Real)( 1./(1< typename std::enable_if< _Dim==1 , DenseNodeData< typename FEMTreeInitializer< Dim , Real >::GeometryNodeType , IsotropicUIntPack< Dim , FEMTrivialSignature > > >::type FEMTreeInitializer< Dim , Real >::GetGeometryNodeDesignators( FEMTreeNode *root , const std::vector< Point< Real , Dim > >& vertices , const std::vector< SimplexIndex< Dim-1 , node_index_type > >& simplices , unsigned int regularGridDepth , unsigned int maxDepth , std::vector< Allocator< FEMTreeNode > * > &nodeAllocators , std::function< void ( FEMTreeNode& ) > NodeInitializer ) { static_assert( Dim==_Dim , "[ERROR] Dimensions don't match" ); - if( simplices.size()%2 ) MK_ERROR_OUT( "Expected even number of hull points: " , simplices.size() ); + if( simplices.size()%2 ) MK_THROW( "Expected even number of hull points: " , simplices.size() ); struct HullPoint { Real x; @@ -905,7 +905,7 @@ DenseNodeData< typename FEMTreeInitializer< Dim , Real >::GeometryNodeType , Iso interiorNodes.reserve( interiorCount ) , exteriorNodes.reserve( exteriorCount ); for( int i=0 ; i<_interiorNodes.size() ; i++ ) for( int j=0 ; j<_interiorNodes[i].size() ; j++ ) { - if( geometryNodeDesignators[ _interiorNodes[i][j] ]==GeometryNodeType::BOUNDARY ) MK_ERROR_OUT( "Interior node has geometry" ); + if( geometryNodeDesignators[ _interiorNodes[i][j] ]==GeometryNodeType::BOUNDARY ) MK_THROW( "Interior node has geometry" ); else if( geometryNodeDesignators[ _interiorNodes[i][j] ]==GeometryNodeType::UNKNOWN ) { geometryNodeDesignators[ _interiorNodes[i][j] ] = GeometryNodeType::INTERIOR; @@ -914,7 +914,7 @@ DenseNodeData< typename FEMTreeInitializer< Dim , Real >::GeometryNodeType , Iso } for( int i=0 ; i<_exteriorNodes.size() ; i++ ) for( int j=0 ; j<_exteriorNodes[i].size() ; j++ ) { - if( geometryNodeDesignators[ _exteriorNodes[i][j] ]==GeometryNodeType::BOUNDARY ) MK_ERROR_OUT( "Exterior node has geometry" ); + if( geometryNodeDesignators[ _exteriorNodes[i][j] ]==GeometryNodeType::BOUNDARY ) MK_THROW( "Exterior node has geometry" ); else if( geometryNodeDesignators[ _exteriorNodes[i][j] ]==GeometryNodeType::UNKNOWN ) { geometryNodeDesignators[ _exteriorNodes[i][j] ] = GeometryNodeType::EXTERIOR; @@ -990,7 +990,7 @@ DenseNodeData< typename FEMTreeInitializer< Dim , Real >::GeometryNodeType , Iso for( int i=0 ; i<_interiorNodes.size() ; i++ ) for( int j=0 ; j<_interiorNodes[i].size() ; j++ ) { - if( geometryNodeDesignators[ _interiorNodes[i][j] ]==GeometryNodeType::BOUNDARY ) MK_ERROR_OUT( "Interior node has geometry" ); + if( geometryNodeDesignators[ _interiorNodes[i][j] ]==GeometryNodeType::BOUNDARY ) MK_THROW( "Interior node has geometry" ); else if( geometryNodeDesignators[ _interiorNodes[i][j] ]==GeometryNodeType::UNKNOWN ) { geometryNodeDesignators[ _interiorNodes[i][j] ] = GeometryNodeType::INTERIOR; @@ -999,7 +999,7 @@ DenseNodeData< typename FEMTreeInitializer< Dim , Real >::GeometryNodeType , Iso } for( int i=0 ; i<_exteriorNodes.size() ; i++ ) for( int j=0 ; j<_exteriorNodes[i].size() ; j++ ) { - if( geometryNodeDesignators[ _exteriorNodes[i][j] ]==GeometryNodeType::BOUNDARY ) MK_ERROR_OUT( "Exterior node has geometry" ); + if( geometryNodeDesignators[ _exteriorNodes[i][j] ]==GeometryNodeType::BOUNDARY ) MK_THROW( "Exterior node has geometry" ); else if( geometryNodeDesignators[ _exteriorNodes[i][j] ]==GeometryNodeType::UNKNOWN ) { geometryNodeDesignators[ _exteriorNodes[i][j] ] = GeometryNodeType::EXTERIOR; @@ -1070,13 +1070,13 @@ DenseNodeData< typename FEMTreeInitializer< Dim , Real >::GeometryNodeType , Iso else if( geometryNodeDesignators[node->children+c]==GeometryNodeType::EXTERIOR ) exteriorCount++; else if( geometryNodeDesignators[node->children+c]==GeometryNodeType::BOUNDARY ) boundaryCount++; } - if( interiorCount+exteriorCount+boundaryCount!=(1<::TestGeometryNodeDesignators( const FEMTre } if( boundaryCount || ( interiorCount && exteriorCount ) ) { - if( type!=GeometryNodeType::UNKNOWN && type!=GeometryNodeType::BOUNDARY ) MK_ERROR_OUT( "Expected unknown or boundary, got: " , type , " | " , node->depthAndOffset() ); + if( type!=GeometryNodeType::UNKNOWN && type!=GeometryNodeType::BOUNDARY ) MK_THROW( "Expected unknown or boundary, got: " , type , " | " , node->depthAndOffset() ); } else if( interiorCount==(1<depthAndOffset() ); + if( type!=GeometryNodeType::UNKNOWN && type!=GeometryNodeType::INTERIOR ) MK_THROW( "Expected unknown or interior, got: " , type , " | " , node->depthAndOffset() ); } else if( exteriorCount==(1<depthAndOffset() ); + if( type!=GeometryNodeType::UNKNOWN && type!=GeometryNodeType::EXTERIOR ) MK_THROW( "Expected unknown or exterior, got: " , type , " | " , node->depthAndOffset() ); } else if( interiorCount ) { - if( type!=GeometryNodeType::UNKNOWN && type!=GeometryNodeType::INTERIOR && type!=GeometryNodeType::BOUNDARY ) MK_ERROR_OUT( "Expected unknown, interior , or boundary, got: " , type , " | " , node->depthAndOffset() ); + if( type!=GeometryNodeType::UNKNOWN && type!=GeometryNodeType::INTERIOR && type!=GeometryNodeType::BOUNDARY ) MK_THROW( "Expected unknown, interior , or boundary, got: " , type , " | " , node->depthAndOffset() ); } else if( exteriorCount==(1<depthAndOffset() ); + if( type!=GeometryNodeType::UNKNOWN && type!=GeometryNodeType::EXTERIOR && type!=GeometryNodeType::BOUNDARY ) MK_THROW( "Expected unknown, exterior, or boundary, got: " , type , " | " , node->depthAndOffset() ); } } @@ -1143,12 +1143,12 @@ void FEMTreeInitializer< Dim , Real >::PushGeometryNodeDesignatorsToFiner( const { if( geometryNodeDesignators[node]==GeometryNodeType::UNKNOWN ) if( node!=root ) geometryNodeDesignators[node] = geometryNodeDesignators[node->parent]; - else MK_ERROR_OUT( "Root node should not be unknown" ); + else MK_THROW( "Root node should not be unknown" ); else if( node!=root && geometryNodeDesignators[node]!=geometryNodeDesignators[node->parent] && geometryNodeDesignators[node->parent]!=GeometryNodeType::BOUNDARY ) { int d , off[Dim]; node->depthAndOffset( d , off ); - MK_ERROR_OUT( "Child designator does not match parent: " , geometryNodeDesignators[node] , " != " , geometryNodeDesignators[node->parent] , " | " , d , " @ ( " , off[0] , " , " , off[1] , " , " , off[2] , " ) " ); + MK_THROW( "Child designator does not match parent: " , geometryNodeDesignators[node] , " != " , geometryNodeDesignators[node->parent] , " | " , d , " @ ( " , off[0] , " , " , off[1] , " , " , off[2] , " ) " ); } if( node->depth()<(long long)maxDepth && node->children ) for( int c=0 ; c<(1<children+c ); } @@ -1177,7 +1177,7 @@ void FEMTreeInitializer< Dim , Real >::PullGeometryNodeDesignatorsFromFiner( con else if( exteriorCount==(1<( cellIndices.size() ); - if( !stream.read( mcIndices , cellIndices.size() ) ) MK_ERROR_OUT( "Failed to read mc indices" ); + if( !stream.read( mcIndices , cellIndices.size() ) ) MK_THROW( "Failed to read mc indices" ); } if( cellIndices.counts[0] ) { cornerValues = AllocPointer< Real >( cellIndices.counts[0] ); - if( !stream.read( cornerValues , cellIndices.counts[0] ) ) MK_ERROR_OUT( "Failed to read corner values" ); + if( !stream.read( cornerValues , cellIndices.counts[0] ) ) MK_THROW( "Failed to read corner values" ); char hasCornerGradients; - if( !stream.read( hasCornerGradients ) ) MK_ERROR_OUT( "Could not read corner gradient state" ); + if( !stream.read( hasCornerGradients ) ) MK_THROW( "Could not read corner gradient state" ); if( hasCornerGradients ) { cornerGradients = AllocPointer< Point< Real , Dim > >( cellIndices.counts[0] ); - if( !stream.read( cornerGradients , cellIndices.counts[0] ) ) MK_ERROR_OUT( "Could not read corner gradients" ); + if( !stream.read( cornerGradients , cellIndices.counts[0] ) ) MK_THROW( "Could not read corner gradients" ); } } if( cellIndices.counts[1] ) { edgeKeys = NewPointer< Key >( cellIndices.counts[1] ); - if( !stream.read( edgeKeys , cellIndices.counts[1]) ) MK_ERROR_OUT( "Could not read edge keys" ); + if( !stream.read( edgeKeys , cellIndices.counts[1]) ) MK_THROW( "Could not read edge keys" ); } if( cellIndices.counts[2] ) { faceEdges = NewPointer< FaceEdges >( cellIndices.counts[2] ); - if( !stream.read( faceEdges , cellIndices.counts[2] ) ) MK_ERROR_OUT( "Could not read face edges" ); + if( !stream.read( faceEdges , cellIndices.counts[2] ) ) MK_THROW( "Could not read face edges" ); } auto ReadIsoEdgeVector = [&]( BinaryStream &stream , std::vector< IsoEdge > &edges ) { size_t sz; - if( !stream.read( sz ) ) MK_ERROR_OUT( "Could not read iso-edge vector size" ); + if( !stream.read( sz ) ) MK_THROW( "Could not read iso-edge vector size" ); edges.resize( sz ); - if( sz && !stream.read( GetPointer( edges ) , sz ) ) MK_ERROR_OUT( "Could not read iso-edges" ); + if( sz && !stream.read( GetPointer( edges ) , sz ) ) MK_THROW( "Could not read iso-edges" ); }; { size_t sz; - if( !stream.read( sz ) ) MK_ERROR_OUT( "Could not read face-edge-map size" ); + if( !stream.read( sz ) ) MK_THROW( "Could not read face-edge-map size" ); for( unsigned int i=0 ; i::const_iterator iter=sliceValues[i].edgeVertexMap.cbegin() ; iter!=sliceValues[i].edgeVertexMap.cend() ; iter++ ) { - if( iter->second>=(node_index_type)vertexPositions.size() ) MK_ERROR_OUT( "Unexpected vertex index: " , iter->second , " <= " , vertexPositions.size() ); + if( iter->second>=(node_index_type)vertexPositions.size() ) MK_THROW( "Unexpected vertex index: " , iter->second , " <= " , vertexPositions.size() ); keys[iter->second] = iter->first; } return keys; @@ -750,7 +750,7 @@ public: // The corner indices incident on the edeg const typename HyperCube::Cube< Dim >::template Element< 0 > *c = HyperCubeTables< Dim , 1 , 0 >::OverlapElements[e.index]; // [SANITY CHECK] - // if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[0].index )!=tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[1].index ) ) MK_ERROR_OUT( "Finer edges should both be valid or invalid" ); + // if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[0].index )!=tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[1].index ) ) MK_THROW( "Finer edges should both be valid or invalid" ); // Can only copy edge information from the finer nodes incident on the edge if they are valid (note since we refine in broods, we can't have one child in and the other out) if( !tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[0].index ) || !tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[1].index ) ) continue; @@ -829,7 +829,7 @@ public: fe.count = HyperCube::MarchingSquares::AddEdgeIndices( mcIndex , isoEdges ); for( int j=0 ; j::const_iterator iter; node_index_type idx1 , idx2; if( ( iter=sValues.edgeVertexMap.find( e[0] ) )!=sValues.edgeVertexMap.end() ) idx1 = iter->second; - else MK_ERROR_OUT( "Couldn't find vertex in edge map" ); + else MK_THROW( "Couldn't find vertex in edge map" ); if( ( iter=sValues.edgeVertexMap.find( e[1] ) )!=sValues.edgeVertexMap.end() ) idx2 = iter->second; - else MK_ERROR_OUT( "Couldn't find vertex in edge map" ); + else MK_THROW( "Couldn't find vertex in edge map" ); if( flipOrientation ) edgeStream.write( thread , std::make_pair( idx2 , idx1 ) ); else edgeStream.write( thread , std::make_pair( idx1 , idx2 ) ); }; @@ -961,7 +961,7 @@ public: // 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 ) MK_ERROR_OUT( "Not a zero-crossing root: " , x0 , " " , x1 ); + if( x0==x1 ) MK_THROW( "Not a zero-crossing root: " , x0 , " " , x1 ); averageRoot = ( isoValue - x0 ) / ( x1 - x0 ); } if( averageRoot<=0 || averageRoot>=1 ) @@ -1033,7 +1033,7 @@ public: template< unsigned int WeightDegree , unsigned int DataSig , typename VertexStream , unsigned int ... FEMSigs > static Stats SetSliceValues( UIntPack< FEMSigs ... > , UIntPack< WeightDegree > , UIntPack< DataSig > , const FEMTree< Dim , Real > &tree , int maxKeyDepth , const DensityEstimator< WeightDegree > *densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > *data , const DenseNodeData< Real , UIntPack< FEMSigs ... > > &coefficients , Real isoValue , VertexStream &vertexStream , const Data &zeroData , bool nonLinearFit , bool outputGradients , std::vector< SliceValues > &sliceValues , int setFlag ) { - if( maxKeyDepth() ); static const int FEMDegrees[] = { FEMSignature< FEMSigs >::Degree ... }; - for( int d=0 ; d(); diff --git a/Src/FEMTree.LevelSet.3D.inl b/Src/FEMTree.LevelSet.3D.inl index 22cd7d90..50c85b0b 100644 --- a/Src/FEMTree.LevelSet.3D.inl +++ b/Src/FEMTree.LevelSet.3D.inl @@ -315,7 +315,7 @@ public: typename HyperCube::Cube< Dim >::template Element< 2 > f; if ( offset[Dim-1]+0==sliceIndex ) f = typename HyperCube::Cube< Dim >::template Element< 2 >( HyperCube::BACK , 0 ); else if( offset[Dim-1]+1==sliceIndex ) f = typename HyperCube::Cube< Dim >::template Element< 2 >( HyperCube::FRONT , 0 ); - else MK_ERROR_OUT( "Node/slice-index mismatch: " , offset[Dim-1] , " <-> " , sliceIndex ); + else MK_THROW( "Node/slice-index mismatch: " , offset[Dim-1] , " <-> " , sliceIndex ); return faceIndexFunctor( node , f ); }; @@ -579,17 +579,17 @@ public: SliceLocalDepth sliceDepth ; SliceLocalOffset sliceOffset; tree.depthAndOffset( node , depth , offset ); sliceTree.depthAndOffset( sliceNode , sliceDepth , sliceOffset ); - if( depth!=sliceDepth ) MK_ERROR_OUT( "Depths do not match: " , depth , " != " , sliceDepth ); - for( unsigned int i=0 ; inodeData.nodeIndex==-1 ) MK_THROW( "Expected valid slice node" ); - if( sliceAtMaxDepthendAtMaxDepth ) MK_ERROR_OUT( "Bad slice: " , sliceAtMaxDepth , " in [ " , beginAtMaxDepth , " , " , endAtMaxDepth , " ]" ); + if( sliceAtMaxDepthendAtMaxDepth ) MK_THROW( "Bad slice: " , sliceAtMaxDepth , " in [ " , beginAtMaxDepth , " , " , endAtMaxDepth , " ]" ); if( depth>=fullDepth ) { // Set the incidence @@ -613,7 +613,7 @@ public: for( unsigned int d=0 ; d " , _p , " @ " , _d , " : ", node->nodeData.nodeIndex , " <-> " , sliceNode->nodeData.nodeIndex ); + MK_THROW( "Expected slice children: " , p , " @ " , d , " <-> " , _p , " @ " , _d , " : ", node->nodeData.nodeIndex , " <-> " , sliceNode->nodeData.nodeIndex ); } if( sliceAtMaxDepth<=midAtMaxDepth ) for( int c=0 ; c<(1<<(Dim-1)) ; c++ ) SetIncidenceFunctor( node->children+(c ) , sliceNode->children + c ); if( sliceAtMaxDepth>=midAtMaxDepth ) for( int c=0 ; c<(1<<(Dim-1)) ; c++ ) SetIncidenceFunctor( node->children+(c|(1<<(Dim-1))) , sliceNode->children + c ); @@ -834,11 +834,11 @@ public: unsigned int slice = sliceAtMaxDepth>>( maxDepth - depth ); if( !isBack && sliceAtMaxDepth!=( slice<<(maxDepth-depth ) ) ) slice++; - if( !slabValues[depth].validSlice( slice ) ) MK_ERROR_OUT( "Invalid slice: " , slice , " @ " , depth , " : " , slabValues[depth].sliceValues(slice).slice() ); + if( !slabValues[depth].validSlice( slice ) ) MK_THROW( "Invalid slice: " , slice , " @ " , depth , " : " , slabValues[depth].sliceValues(slice).slice() ); SliceValues &sValues = slabValues[depth].sliceValues( slice ); const SliceSliceValues &ssValues = boundaryInfo.sliceValues[depth]; - if( sValues.cornerGradients && !ssValues.cornerGradients ) MK_ERROR_OUT( "Epxected slice gradients" ); + if( sValues.cornerGradients && !ssValues.cornerGradients ) MK_THROW( "Epxected slice gradients" ); auto CopyCornerInfo = [&]( node_index_type sliceIndex , node_index_type index ) { @@ -1293,7 +1293,7 @@ public: typename HyperCube::Cube< Dim >::template Element< 1 > e( zDir , _e.index ); const typename HyperCube::Cube< Dim >::template Element< 0 > *c = HyperCubeTables< Dim , 1 , 0 >::OverlapElements[e.index]; // [SANITY CHECK] - // if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[0].index )!=tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[1].index ) ) MK_ERROR_OUT( "Finer edges should both be valid or invalid" ); + // if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[0].index )!=tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[1].index ) ) MK_THROW( "Finer edges should both be valid or invalid" ); if( !tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[0].index ) || !tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c[1].index ) ) continue; node_index_type cIndex1 = cCellIndices.template indices<1>( tree._sNodes.treeNodes[i]->children + c[0].index )[_e.index]; @@ -1365,7 +1365,7 @@ public: typename HyperCube::Cube< Dim >::template Element< 0 > c0( HyperCube::BACK , _c.index ) , c1( HyperCube::FRONT , _c.index ); // [SANITY CHECK] - // if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c0 )!=tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c1 ) ) MK_ERROR_OUT( "Finer edges should both be valid or invalid" ); + // if( tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c0 )!=tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c1 ) ) MK_THROW( "Finer edges should both be valid or invalid" ); if( !tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c0.index ) || !tree._isValidSpaceNode( tree._sNodes.treeNodes[i]->children + c1.index ) ) continue; node_index_type cIndex0 , cIndex1; @@ -1451,7 +1451,7 @@ public: fe.count = HyperCube::MarchingSquares::AddEdgeIndices( mcIndex , isoEdges ); for( int j=0 ; j((node_index_type)i)[ coIndex ]; - if( !sScratch.eSet[ idx ] ) MK_ERROR_OUT( "Edge not set: " , slab , " / " , 1<& _edges = iter->second; for( size_t j=0 ; j<_edges.size() ; j++ ) edges.push_back( IsoEdge( _edges[j][flip] , _edges[j][1-flip] ) ); } - else MK_ERROR_OUT( "Invalid faces: " , i , " " , fDir==HyperCube::BACK ? "back" : ( fDir==HyperCube::FRONT ? "front" : ( fDir==HyperCube::CROSS ? "cross" : "unknown" ) ) ); + else MK_THROW( "Invalid faces: " , i , " " , fDir==HyperCube::BACK ? "back" : ( fDir==HyperCube::FRONT ? "front" : ( fDir==HyperCube::CROSS ? "cross" : "unknown" ) ) ); } } } @@ -1642,7 +1642,7 @@ public: if ( bValues.setVertexPair(current,pair) ) loops.back().push_back( current ) , current = pair; else if( fValues.setVertexPair(current,pair) ) loops.back().push_back( current ) , current = pair; else if( (iter=xValues.vertexPairMap.find(current))!=xValues.vertexPairMap.end() ) loops.back().push_back( current ) , current = iter->second; - else MK_ERROR_OUT( "Failed to close loop for node[" , i , "]: [" , off[0] , " " , off[1] , " " , off[2] , " @ " , d , "] | " , keyGenerator.to_string( current ) , " -- " , keyGenerator.to_string( start ) , " | " , current.to_string() , " -- " , start.to_string() ); + else MK_THROW( "Failed to close loop for node[" , i , "]: [" , off[0] , " " , off[1] , " " , off[2] , " @ " , d , "] | " , keyGenerator.to_string( current ) , " -- " , keyGenerator.to_string( start ) , " | " , current.to_string() , " -- " , start.to_string() ); } else { @@ -1665,7 +1665,7 @@ public: if ( bValues.setEdgeVertex( key , polygon[kk] ) ); else if( fValues.setEdgeVertex( key , polygon[kk] ) ); else if( ( iter=xValues.edgeVertexMap.find( key ) )!=xValues.edgeVertexMap.end() ) polygon[kk] = iter->second; - else MK_ERROR_OUT( "Couldn't find vertex in edge map: " , off[0] , " , " , off[1] , " , " , off[2] , " @ " , depth , " : " , keyGenerator.to_string( key ) , " | " , key.to_string() ); + else MK_THROW( "Couldn't find vertex in edge map: " , off[0] , " , " , off[1] , " , " , off[2] , " @ " , depth , " : " , keyGenerator.to_string( key ) , " | " , key.to_string() ); } AddIsoPolygons( thread , vertexStream , polygonStream , polygon , polygonMesh , addBarycenter ); } @@ -1748,7 +1748,7 @@ public: // 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 ) MK_ERROR_OUT( "Not a zero-crossing root: " , x0 , " " , x1 ); + if( x0==x1 ) MK_THROW( "Not a zero-crossing root: " , x0 , " " , x1 ); averageRoot = ( isoValue - x0 ) / ( x1 - x0 ); } if( averageRoot<=0 || averageRoot>=1 ) @@ -1859,7 +1859,7 @@ public: // 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 ) MK_ERROR_OUT( "Not a zero-crossing root: " , x0 , " " , x1 ); + if( x0==x1 ) MK_THROW( "Not a zero-crossing root: " , x0 , " " , x1 ); averageRoot = ( isoValue - x0 ) / ( x1 - x0 ); } if( averageRoot<=0 || averageRoot>=1 ) @@ -1945,7 +1945,7 @@ public: std::vector< Point< Real , Dim > > vertices( polygon.size() ); for( unsigned int i=0 ; i(); std::vector< TriangleIndex< node_index_type > > triangles = MinimalAreaTriangulation< node_index_type , Real , Dim >( ( ConstPointer( Point< Real , Dim > ) )GetPointer( vertices ) , (node_index_type)vertices.size() ); - if( triangles.size()!=polygon.size()-2 ) MK_ERROR_OUT( "Minimal area triangulation failed:" , triangles.size() , " != " , polygon.size()-2 ); + if( triangles.size()!=polygon.size()-2 ) MK_THROW( "Minimal area triangulation failed:" , triangles.size() , " != " , polygon.size()-2 ); for( unsigned int i=0 ; i(1u<(1u<(); LevelSetExtraction::SetHyperCubeTables< Dim-1 >(); @@ -2194,7 +2194,7 @@ public: for( LocalDepth d=maxDepth ; d>=fullDepth ; d-- ) if( d<=boundary->sliceTree.depth() && d<=tree._maxDepth ) { unsigned int slice; - if( !SetCoarseSlice( sliceAtMaxDepth , d , slice ) ) MK_ERROR_OUT( "Could not set coarse slice" ); + if( !SetCoarseSlice( sliceAtMaxDepth , d , slice ) ) MK_THROW( "Could not set coarse slice" ); OverwriteCornerValues( *boundary , (*dValues)[d] , tree , d , sliceAtMaxDepth , maxDepth , sliceAtMaxDepth==slabStartAtMaxDepth , slabValues , *incidence ); SetMCIndices( tree , isoValue , d , fullDepth , slice , slabValues ); } @@ -2240,13 +2240,13 @@ public: auto sliceFunctor = [&]( unsigned int depth ) -> SliceValues & { unsigned int slice; - if( !SetCoarseSlice( sliceAtMaxDepth , depth , slice ) ) MK_ERROR_OUT( "Could not set coarse slice" ); + if( !SetCoarseSlice( sliceAtMaxDepth , depth , slice ) ) MK_THROW( "Could not set coarse slice" ); return slabValues[depth].sliceValues( slice ); }; auto scratchFunctor = [&]( unsigned int depth ) -> typename SliceValues::Scratch & { unsigned int slice; - if( !SetCoarseSlice( sliceAtMaxDepth , depth , slice ) ) MK_ERROR_OUT( "Could not set coarse slice" ); + if( !SetCoarseSlice( sliceAtMaxDepth , depth , slice ) ) MK_THROW( "Could not set coarse slice" ); return slabValues[depth].sliceScratch( slice ); }; CopyIsoStructure< WeightDegree , DataSig >( keyGenerator , *boundary , tree , fullDepth , sliceAtMaxDepth , maxDepth , sliceFunctor , scratchFunctor , *incidence , vertexStream , gradientNormals , pointEvaluator , densityWeights , data , zeroData ); diff --git a/Src/FEMTree.LevelSet.inl b/Src/FEMTree.LevelSet.inl index 34c91f7e..b782dcb7 100644 --- a/Src/FEMTree.LevelSet.inl +++ b/Src/FEMTree.LevelSet.inl @@ -249,7 +249,7 @@ namespace LevelSetExtraction void _zeroOut( size_t sz ) { if( sz && maps[CellDim] ) memset( maps[CellDim] , 0 , sizeof(node_index_type) * sz * HyperCube::Cube< Dim >::template ElementNum< CellDim >() ); - else if( sz ) MK_ERROR_OUT( "Traying to zero out null pointer" ); + else if( sz ) MK_THROW( "Traying to zero out null pointer" ); if constexpr( CellDim==MaxCellDim ) return; else _zeroOut< CellDim+1 >( sz ); @@ -298,7 +298,7 @@ namespace LevelSetExtraction void read( BinaryStream &stream ) { - if( !stream.read( _size ) ) MK_ERROR_OUT( "Failed to read node count" ); + if( !stream.read( _size ) ) MK_THROW( "Failed to read node count" ); resize( _size ); if( _size ) _read<0>( stream ); } @@ -344,8 +344,8 @@ namespace LevelSetExtraction template< unsigned int CellDim > void _read( BinaryStream &stream ) { - if( !stream.read( counts[CellDim] ) ) MK_ERROR_OUT( "Failed to read count at dimension: " , CellDim ); - if( !stream.read( std::get< CellDim >( tables ) , _size ) ) MK_ERROR_OUT( "Failed to read table at dimension: " , CellDim ); + if( !stream.read( counts[CellDim] ) ) MK_THROW( "Failed to read count at dimension: " , CellDim ); + if( !stream.read( std::get< CellDim >( tables ) , _size ) ) MK_THROW( "Failed to read table at dimension: " , CellDim ); if constexpr( CellDim==MaxCellDim ) return; else _read< CellDim+1 >( stream ); @@ -386,7 +386,7 @@ namespace LevelSetExtraction void read( BinaryStream &stream ) { - if( !stream.read( nodeOffset ) ) MK_ERROR_OUT( "Failed to read node ofset" ); + if( !stream.read( nodeOffset ) ) MK_THROW( "Failed to read node ofset" ); CellIndexData< Dim , MaxCellDim >::read( stream ); } @@ -516,7 +516,7 @@ namespace LevelSetExtraction void read( BinaryStream &stream ) { - if( !stream.read( nodeOffset ) ) MK_ERROR_OUT( "Failed to read node ofset" ); + if( !stream.read( nodeOffset ) ) MK_THROW( "Failed to read node ofset" ); CellIndexData< _Dim , _Dim >::read( stream ); } @@ -650,7 +650,7 @@ namespace LevelSetExtraction void read( BinaryStream &stream ) { - if( !stream.read( nodeOffset ) ) MK_ERROR_OUT( "Failed to read node ofset" ); + if( !stream.read( nodeOffset ) ) MK_THROW( "Failed to read node ofset" ); CellIndexData< _Dim , _Dim >::read( stream ); } @@ -782,7 +782,7 @@ namespace LevelSetExtraction Key< Dim > operator()( int depth , int offset , Key< Dim-1 > key ) const { Key< Dim > pKey; - if( depth>_maxDepth ) MK_ERROR_OUT( "Depth cannot exceed max depth: " , depth , " <= " , _maxDepth ); + if( depth>_maxDepth ) MK_THROW( "Depth cannot exceed max depth: " , depth , " <= " , _maxDepth ); for( unsigned int d=0 ; d::read( BinaryStream &stream , TreeNode &root ) _sliceStart = NullPointer( Pointer( node_index_type ) ); treeNodes = NullPointer( TreeNode* ); - if( !stream.read( _levels ) ) MK_ERROR_OUT( "Failed to read levels" ); + if( !stream.read( _levels ) ) MK_THROW( "Failed to read levels" ); if( _levels ) { _sliceStart = AllocPointer< Pointer( node_index_type ) >( _levels ); @@ -75,7 +75,7 @@ void SortedTreeNodes< Dim >::read( BinaryStream &stream , TreeNode &root ) { size_t sz = ((size_t)1<( sz ); - if( !stream.read( _sliceStart[l] , sz ) ) MK_ERROR_OUT( "Failed to read slices at level: " , l ); + if( !stream.read( _sliceStart[l] , sz ) ) MK_THROW( "Failed to read slices at level: " , l ); } size_t sz = _sliceStart[_levels-1][(size_t)1<<(_levels-1)]; diff --git a/Src/FEMTree.System.inl b/Src/FEMTree.System.inl index 4f4e4b08..5a7238a9 100644 --- a/Src/FEMTree.System.inl +++ b/Src/FEMTree.System.inl @@ -443,7 +443,7 @@ int FEMTree< Dim , Real >::_solveSlicedSystemGS( UIntPack< FEMSigs ... > , const int b = _residualWindow.begin(!forward); if( FullWindow.inBlock( b ) ) maxBlockSize = std::max< size_t >( maxBlockSize , _sNodesEnd( depth , BlockLast( b ) ) - _sNodesBegin( depth , BlockFirst( b ) ) ); } - if( maxBlockSize>std::numeric_limits< matrix_index_type >::max() ) MK_ERROR_OUT( "more entries in a block than can be indexed in " , sizeof(matrix_index_type) , " bytes" ); + if( maxBlockSize>std::numeric_limits< matrix_index_type >::max() ) MK_THROW( "more entries in a block than can be indexed in " , sizeof(matrix_index_type) , " bytes" ); for( int i=0 ; i( maxBlockSize ) , _D[i] = AllocPointer< Real >( maxBlockSize ); for( ; residualWindow.end(!forward)*dir template< unsigned int ... FEMSigs , typename T , typename TDotT , typename ... InterpolationInfos > void FEMTree< Dim , Real >::_solveRegularMG( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , LocalDepth maxSolveDepth , Pointer( T ) solution , ConstPointer( T ) constraints , TDotT Dot , int vCycles , int iters , _SolverStats& stats , bool computeNorms , double cgAccuracy , std::tuple< InterpolationInfos *... > interpolationInfos ) const { - if( maxSolveDepth>_baseDepth ) MK_ERROR_OUT( "Regular MG depth cannot exceed base depth: " , maxSolveDepth , " <= " , _baseDepth ); + if( maxSolveDepth>_baseDepth ) MK_THROW( "Regular MG depth cannot exceed base depth: " , maxSolveDepth , " <= " , _baseDepth ); double& systemTime = stats.systemTime; double& solveTime = stats. solveTime; @@ -843,7 +843,7 @@ void FEMTree< Dim , Real >::_addPointValues( UIntPack< FEMSigs ... > , StaticWin typedef UIntPack< ( -BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportStart ) ... > RightPointSupportRadii; typedef UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... > SupportSizes; - if( !( FEMDegrees() >= IsotropicUIntPack< Dim , PointD >() ) ) MK_ERROR_OUT( "Insufficient derivatives" ); + if( !( FEMDegrees() >= IsotropicUIntPack< Dim , PointD >() ) ) MK_THROW( "Insufficient derivatives" ); if( !interpolationInfo ) return; const InterpolationInfo< T , PointD >& iInfo = *interpolationInfo; @@ -1003,7 +1003,7 @@ void FEMTree< Dim , Real >::_addProlongedPointValues( UIntPack< FEMSigs ... > , #pragma message( "[WARNING] This code is broken" ) #endif // SHOW_WARNINGS #if 1 - MK_ERROR_OUT( "Broken code" ); + MK_THROW( "Broken code" ); #else if( !interpolationInfo ) return; const InterpolationInfo< T , PointD >& iInfo = *interpolationInfo; @@ -1622,7 +1622,7 @@ SparseMatrix< Real , matrix_index_type > FEMTree< Dim , Real >::systemMatrix( UI { _setFEM1ValidityFlags( UIntPack< FEMSigs ... >() ); typedef typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > > BaseSystem; - if( depth<0 || depth>_maxDepth ) MK_ERROR_OUT( "System depth out of bounds: 0 <= " , depth , " <= " , _maxDepth ); + if( depth<0 || depth>_maxDepth ) MK_THROW( "System depth out of bounds: 0 <= " , depth , " <= " , _maxDepth ); SparseMatrix< Real , matrix_index_type > matrix; F.init( depth ); PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > > bsData( depth ); @@ -1658,7 +1658,7 @@ template< unsigned int ... FEMSigs , typename ... InterpolationInfos > SparseMatrix< Real , matrix_index_type > FEMTree< Dim , Real >::prolongedSystemMatrix( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack::Degree ... > >& F , LocalDepth highDepth , std::tuple< InterpolationInfos *... > interpolationInfos ) const { _setFEM1ValidityFlags( UIntPack< FEMSigs ... >() ); - if( highDepth<=0 || highDepth>_maxDepth ) MK_ERROR_OUT( "System depth out of bounds: 0 < " , highDepth , " <= " , _maxDepth ); + if( highDepth<=0 || highDepth>_maxDepth ) MK_THROW( "System depth out of bounds: 0 < " , highDepth , " <= " , _maxDepth ); LocalDepth lowDepth = highDepth-1; SparseMatrix< Real , matrix_index_type > matrix; @@ -2647,7 +2647,7 @@ void FEMTree< Dim , Real >::solveSystem( UIntPack< FEMSigs ... > , typename Base PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > > bsData( sizeof...(InterpolationInfos)==0 ? 0 : maxSolveDepth ); if( solverInfo.clearSolution ) solution = initDenseNodeData< T >( UIntPack< FEMSigs ... >() ); - else if( solution.size()!=_sNodesEnd( _maxDepth ) ) MK_ERROR_OUT( "Solution is the wrong size: " , solution.size() , " != " , _sNodesEnd(_maxDepth) ); + else if( solution.size()!=_sNodesEnd( _maxDepth ) ) MK_THROW( "Solution is the wrong size: " , solution.size() , " != " , _sNodesEnd(_maxDepth) ); // The initial estimate of the solution (may be empty or may come in with an initial guess) Pointer( T ) _solution = solution(); diff --git a/Src/FEMTree.WeightedSamples.inl b/Src/FEMTree.WeightedSamples.inl index 4bd7bd51..deb1db54 100644 --- a/Src/FEMTree.WeightedSamples.inl +++ b/Src/FEMTree.WeightedSamples.inl @@ -267,7 +267,7 @@ void FEMTree< Dim , Real >::_getSampleDepthAndWeight( const DensityEstimator< We temp = _spaceRoot; while( _localDepth( temp )( temp->children ) ) break; // MK_ERROR_OUT( "" ); + if( !IsActiveNode< Dim >( temp->children ) ) break; // MK_THROW( "" ); int cIndex = FEMTreeNode::ChildIndex( myCenter , position ); temp = temp->children + cIndex; myWidth /= 2; diff --git a/Src/FEMTree.h b/Src/FEMTree.h index 15ffe1bd..64e235f1 100644 --- a/Src/FEMTree.h +++ b/Src/FEMTree.h @@ -154,7 +154,7 @@ namespace PoissonRecon size_t size( void ) const { return _levels ? _sliceStart[_levels-1][(size_t)1<<(_levels-1)] : 0; } size_t size( int depth ) const { - if( depth<0 || depth>=_levels ) MK_ERROR_OUT( "bad depth: 0 <= " , depth , " < " , _levels ); + if( depth<0 || depth>=_levels ) MK_THROW( "bad depth: 0 <= " , depth , " < " , _levels ); return _sliceStart[depth][(size_t)1<( _sz ); - if( !stream.read( _data , _sz ) ) MK_ERROR_OUT( "failed to read data" ); + if( !stream.read( _data , _sz ) ) MK_THROW( "failed to read data" ); } Data& operator[] ( size_t idx ) { return _data[idx]; } @@ -575,15 +575,15 @@ namespace PoissonRecon inline void ReadFEMTreeParameter( BinaryStream &stream , FEMTreeRealType& realType , unsigned int &dimension ) { - if( !stream.read( realType ) ) MK_ERROR_OUT( "Failed to read real type" ); - if( !stream.read( dimension ) ) MK_ERROR_OUT( "Failed to read dimension" ); + if( !stream.read( realType ) ) MK_THROW( "Failed to read real type" ); + if( !stream.read( dimension ) ) MK_THROW( "Failed to read dimension" ); } inline unsigned int* ReadDenseNodeDataSignatures( BinaryStream &stream , unsigned int &dim ) { - if( !stream.read( dim ) ) MK_ERROR_OUT( "Failed to read dimension" ); + if( !stream.read( dim ) ) MK_THROW( "Failed to read dimension" ); unsigned int* femSigs = new unsigned int[dim]; - if( !stream.read( GetPointer( femSigs , dim ) , dim ) ) MK_ERROR_OUT( "Failed to read signatures" ); + if( !stream.read( GetPointer( femSigs , dim ) , dim ) ) MK_THROW( "Failed to read signatures" ); return femSigs; } @@ -635,7 +635,7 @@ namespace PoissonRecon { unsigned int dCount = 0; for( unsigned int d=0 ; d=D ) MK_ERROR_OUT( "More derivatives than allowed" ); + if( dCount>=D ) MK_THROW( "More derivatives than allowed" ); else if( dCount; @@ -1305,7 +1305,7 @@ namespace PoissonRecon case INTEGRATE_CHILD_CHILD: return std::get< D >( _integrators ).ccIntegrator.dot( off1[D] , off2[D] , d1[D] , d2[D] ) * remainingIntegral; case INTEGRATE_PARENT_CHILD: return std::get< D >( _integrators ).pcIntegrator.dot( off1[D] , off2[D] , d1[D] , d2[D] ) * remainingIntegral; case INTEGRATE_CHILD_PARENT: return std::get< D >( _integrators ).cpIntegrator.dot( off2[D] , off1[D] , d2[D] , d1[D] ) * remainingIntegral; - default: MK_ERROR_OUT( "Undefined integration type" ); + default: MK_THROW( "Undefined integration type" ); } return 0; } @@ -1432,7 +1432,7 @@ namespace PoissonRecon using Value = Point< Real >; static void Add( volatile Value &a , const Value &b ) { - if( a._dim !=b._dim ) MK_ERROR_OUT( "Sizes don't match: " , a._dim , " != " , b._dim ); + if( a._dim !=b._dim ) MK_THROW( "Sizes don't match: " , a._dim , " != " , b._dim ); for( unsigned int d=0 ; d::Signature > >::read( stream ); } DensityEstimator( BinaryStream &stream ){ read(stream); } @@ -2601,7 +2601,7 @@ namespace PoissonRecon FEMTreeRealType realType; if ( typeid( Real )==typeid( float ) ) realType=FEM_TREE_REAL_FLOAT; else if( typeid( Real )==typeid( double ) ) realType=FEM_TREE_REAL_DOUBLE; - else MK_ERROR_OUT( "Unrecognized real type" ); + else MK_THROW( "Unrecognized real type" ); stream.write( realType ); int dim = Dim; stream.write( dim ); diff --git a/Src/FEMTree.inl b/Src/FEMTree.inl index cbe4c093..0e720143 100644 --- a/Src/FEMTree.inl +++ b/Src/FEMTree.inl @@ -59,7 +59,7 @@ void FEMTree< Dim , Real >::_init( void ) _spaceRoot = &_tree; for( int d=0 ; d<_depthOffset ; d++ ) { - if( !_spaceRoot->children ) MK_ERROR_OUT( "Expected child node: " , d , " / " , _depthOffset ); + if( !_spaceRoot->children ) MK_THROW( "Expected child node: " , d , " / " , _depthOffset ); else if( d==0 ) _spaceRoot = _spaceRoot->children + (1<children; } @@ -68,8 +68,8 @@ void FEMTree< Dim , Real >::_init( void ) template< unsigned int Dim , class Real > FEMTree< Dim , Real > *FEMTree< Dim , Real >::Merge( const FEMTree< Dim , Real > &tree1 , const FEMTree< Dim , Real > &tree2 , size_t blockSize ) { - if( tree1._baseDepth != tree2._baseDepth ) MK_ERROR_OUT( "Base depths differ: " , tree1._baseDepth , " != " , tree2._baseDepth ); - if( tree1._depthOffset != tree2._depthOffset ) MK_ERROR_OUT( "Depth offsets differ: " , tree1._depthOffset , " != " , tree2._depthOffset ); + if( tree1._baseDepth != tree2._baseDepth ) MK_THROW( "Base depths differ: " , tree1._baseDepth , " != " , tree2._baseDepth ); + if( tree1._depthOffset != tree2._depthOffset ) MK_THROW( "Depth offsets differ: " , tree1._depthOffset , " != " , tree2._depthOffset ); FEMTree< Dim , Real > *mergeTree = new FEMTree( blockSize ); // have support overlapping the slice. @@ -108,7 +108,7 @@ template< unsigned int Dim , class Real > template< unsigned int CrossDegree , unsigned int Pad > FEMTree< Dim , Real > *FEMTree< Dim , Real >::Slice( const FEMTree< Dim+1 , Real > &tree , unsigned int sliceDepth , unsigned int sliceIndex , bool includeBounds , size_t blockSize ) { - if( sliceIndex>(unsigned int)(1<nodeData.nodeIndex==-1 ) MK_THROW( "Merge node not set" ); LocalDepth d ; LocalOffset off; tree.depthAndOffset( node , d , off ); mergeCoefficients[ mergeNode->nodeData.nodeIndex ] += coefficients[ node->nodeData.nodeIndex ]; @@ -243,7 +243,7 @@ struct SliceEvaluator } } - else MK_ERROR_OUT( "Derivative exceeds degree: " , d , " > " , FEMSignature< FEMSig >::Degree ); + else MK_THROW( "Derivative exceeds degree: " , d , " > " , FEMSignature< FEMSig >::Degree ); } Real operator()( int off ) const { @@ -318,7 +318,7 @@ void FEMTree< Dim , Real >::slice( const FEMTree< Dim+1 , Real > &tree , unsigne { if( node->nodeData.nodeIndex!=-1 ) { - if( sliceNode->nodeData.nodeIndex==-1 ) MK_ERROR_OUT( "Slice node not set" ); + if( sliceNode->nodeData.nodeIndex==-1 ) MK_THROW( "Slice node not set" ); typename FEMTree< Dim+1 , Real >::LocalDepth d ; typename FEMTree< Dim+1 , Real >::LocalOffset off; tree.depthAndOffset( node , d , off ); sliceCoefficients[ sliceNode->nodeData.nodeIndex ] += coefficients[ node->nodeData.nodeIndex ] * sliceEvaluator( d , off[Dim] ); @@ -358,11 +358,11 @@ FEMTree< Dim , Real >::FEMTree( BinaryStream &stream , size_t blockSize ) : FEMT { Allocator< FEMTreeNode > *nodeAllocator = nodeAllocators.size() ? nodeAllocators[0] : NULL; node_index_type nodeCount; - if( !stream.read( nodeCount ) ) MK_ERROR_OUT( "Failed to read nodeCount" ); + if( !stream.read( nodeCount ) ) MK_THROW( "Failed to read nodeCount" ); _nodeCount = nodeCount; - if( !stream.read( _maxDepth ) ) MK_ERROR_OUT( "Failed to read _maxDepth" ); - if( !stream.read( _depthOffset ) ) MK_ERROR_OUT( "Failed to read _depthOffset" ); - if( !stream.read( _baseDepth ) ) MK_ERROR_OUT( "Failed to read _baseDepth" ); + if( !stream.read( _maxDepth ) ) MK_THROW( "Failed to read _maxDepth" ); + if( !stream.read( _depthOffset ) ) MK_THROW( "Failed to read _depthOffset" ); + if( !stream.read( _baseDepth ) ) MK_THROW( "Failed to read _baseDepth" ); _tree.read( stream , nodeAllocator ); _init(); _sNodes.read( stream , _tree ); @@ -630,9 +630,9 @@ typename FEMTree< Dim , Real >::LocalDepth FEMTree< Dim , Real >::getFullDepth( LocalDepth _depth ; LocalOffset _begin , _end; for( unsigned int d=0 ; dend[d] ) MK_ERROR_OUT( "Bad bounds [" , d , "]: " , begin[d] , " <= " , end[d] ); - if( begin[d]<0 ) MK_ERROR_OUT( "Start bound cannot be negative [" , d , "]: 0 <= " , begin[d] ); - if( end[d]>(1<maxSplatDepth ) MK_THROW( "Minimum splat depth exceeds maximum splat depth" ); PointSupportKey< IsotropicUIntPack< Dim , DensityDegree > > densityKey; densityKey.set( maxSplatDepth ); @@ -828,7 +828,7 @@ void FEMTree< Dim , Real >::updateDensityEstimator( typename FEMTree< Dim , Real LocalDepth maxDepth = _spaceRoot->maxDepth(); maxSplatDepth = std::max< LocalDepth >( 0 , std::min< LocalDepth >( maxSplatDepth , maxDepth ) ); minSplatDepth = std::max< LocalDepth >( 0 , std::min< LocalDepth >( minSplatDepth , maxDepth ) ); - if( minSplatDepth>maxSplatDepth ) MK_ERROR_OUT( "Minimum splat depth exceeds maximum splat depth" ); + if( minSplatDepth>maxSplatDepth ) MK_THROW( "Minimum splat depth exceeds maximum splat depth" ); PointSupportKey< IsotropicUIntPack< Dim , DensityDegree > > densityKey; densityKey.set( maxSplatDepth ); @@ -1315,7 +1315,7 @@ std::vector< node_index_type > FEMTree< Dim , Real >::_finalizeForMultigrid( Loc // -- Swap the children sitting off the last node of the old children to the first node of the old children FEMTreeNode *oldChildren = _tree.children; FEMTreeNode *newChildren = FEMTreeNode::NewBrood( nodeAllocator , _nodeInitializer ); - if( !oldChildren ) MK_ERROR_OUT( "Expected children" ); + if( !oldChildren ) MK_THROW( "Expected children" ); { if( oldChildren[(1< std::vector< node_index_type > FEMTree< Dim , Real >::merge( FEMTree* tree ) { std::vector< node_index_type > map; - if( _depthOffset!=tree->_depthOffset ) MK_ERROR_OUT( "depthOffsets don't match: %d != %d" , _depthOffset , tree->_depthOffset ); + if( _depthOffset!=tree->_depthOffset ) MK_THROW( "depthOffsets don't match: %d != %d" , _depthOffset , tree->_depthOffset ); // Compute the next available index node_index_type nextIndex = 0; diff --git a/Src/Geometry.h b/Src/Geometry.h index 3310ca57..fec6005f 100644 --- a/Src/Geometry.h +++ b/Src/Geometry.h @@ -180,7 +180,7 @@ namespace PoissonRecon void _init( unsigned int d ) { if( !d ) memset( coords , 0 , sizeof(Real)*Dim ); - else MK_ERROR_OUT( "Should never be called" ); + else MK_THROW( "Should never be called" ); } template< class _Real , class ... _Reals > void _init( unsigned int d , _Real v , _Reals ... values ) { @@ -276,7 +276,7 @@ namespace PoissonRecon { if( !_dim || !p._dim ){ _resize( p._dim ) ; memcpy( _coords , p._coords , sizeof(Real)*_dim ); } else if( _dim==p._dim ) memcpy( _coords , p._coords , sizeof(Real)*_dim ); - else MK_ERROR_OUT( "Dimensions don't match: " , _dim , " != " , p._dim ); + else MK_THROW( "Dimensions don't match: " , _dim , " != " , p._dim ); return *this; } @@ -289,14 +289,14 @@ namespace PoissonRecon { if( !_dim ){ _resize( p._dim ) ; for( unsigned int i=0 ; i<_dim ; i++ ) _coords[i] = p._coords[i]; } else if( _dim==p._dim ) for( unsigned int i=0 ; i<_dim ; i++ ) _coords[i] += p._coords[i]; - else MK_ERROR_OUT( "Dimensions don't match: " , _dim , " != " , p._dim ); + else MK_THROW( "Dimensions don't match: " , _dim , " != " , p._dim ); return *this; } Point& operator -= ( const Point& p ) { if( !_dim ){ _resize( p._dim ) ; for( unsigned int i=0 ; i<_dim ; i++ ) _coords[i] = -p._coords[i]; } else if( _dim==p._dim ) for( unsigned int i=0 ; i<_dim ; i++ ) _coords[i] -= p._coords[i]; - else MK_ERROR_OUT( "Dimensions don't match: " , _dim , " != " , p._dim ); + else MK_THROW( "Dimensions don't match: " , _dim , " != " , p._dim ); return *this; } Point& operator *= ( Real s ) @@ -317,7 +317,7 @@ namespace PoissonRecon static Real Dot( const Point &p1 , const Point &p2 ) { Real dot; - if( p1._dim!=p2._dim ) MK_ERROR_OUT( "Dimensions differ: " , p1._dim , " != " , p2._dim ); + if( p1._dim!=p2._dim ) MK_THROW( "Dimensions differ: " , p1._dim , " != " , p2._dim ); for( size_t d=0 ; d static typename std::enable_if< _K==Dim-1 , bool >::type IsInterior( Point< Real , Dim > p , const std::vector< Simplex< Real , Dim , Dim-1 > > &simplices ) { - if( !simplices.size() ) MK_ERROR_OUT( "No simplices provided" ); + if( !simplices.size() ) MK_THROW( "No simplices provided" ); // Create a ray that intersecting the largest simplex int idx; @@ -709,7 +709,7 @@ namespace PoissonRecon } Ray< Real , Dim > ray( p , simplices[idx].center() - p ); Real l = (Real)Point< Real , Dim >::SquareNorm( ray.direction ); - if( !l ) MK_ERROR_OUT( "point is on simplex" ); + if( !l ) MK_THROW( "point is on simplex" ); l = (Real)sqrt(l); ray.direction /= l; @@ -729,7 +729,7 @@ namespace PoissonRecon template< unsigned int _K=K > static typename std::enable_if< _K==Dim-1 , bool >::type IsInterior( Point< Real , Dim > p , const std::vector< Simplex< Real , Dim , Dim-1 > > &simplices , const std::vector< Point< Real , Dim > > &normals ) { - if( !simplices.size() ) MK_ERROR_OUT( "No simplices provided" ); + if( !simplices.size() ) MK_THROW( "No simplices provided" ); #if 0 // A more conservative approach for ray-tracing, sending a ray for each simplex and using the consensus solution @@ -770,7 +770,7 @@ namespace PoissonRecon } Ray< Real , Dim > ray( p , simplices[idx].center() - p ); Real l = (Real)Point< Real , Dim >::SquareNorm( ray.direction ); - if( !l ) MK_ERROR_OUT( "point is on simplex" ); + if( !l ) MK_THROW( "point is on simplex" ); l = (Real)sqrt(l); ray.direction /= l; @@ -819,11 +819,11 @@ namespace PoissonRecon template< unsigned int _K=0 > static typename std::enable_if< _K==Dim-1 , bool >::type IsInterior( Point< Real , Dim > p , const std::vector< Simplex< Real , Dim , Dim-1 > > &simplices , const std::vector< Point< Real , Dim > > &normals ) { - if( !simplices.size() ) MK_ERROR_OUT( "No simplices provided" ); + if( !simplices.size() ) MK_THROW( "No simplices provided" ); Ray< Real , Dim > ray( p , simplices[0].center() - p ); Real l = (Real)Point< Real , Dim >::SquareNorm( ray.direction ); - if( !l ) MK_ERROR_OUT( "point is on simplex" ); + if( !l ) MK_THROW( "point is on simplex" ); l = (Real)sqrt(l); ray.direction /= l; @@ -863,7 +863,7 @@ namespace PoissonRecon void _init( unsigned int k ) { if( !k ) memset( idx , 0 , sizeof(idx) ); - else MK_ERROR_OUT( "Should never be called" ); + else MK_THROW( "Should never be called" ); } template< class ... Ints > void _init( unsigned int k , Index v , Ints ... values ) { diff --git a/Src/Image.h b/Src/Image.h index b60ad1ac..18b11948 100644 --- a/Src/Image.h +++ b/Src/Image.h @@ -54,7 +54,7 @@ namespace PoissonRecon unsigned int channels; ImageReader* reader = Get( fileName ); width = reader->width() , height = reader->height() , channels = reader->channels(); - if( channels!=1 && channels!=3 ) MK_ERROR_OUT( "Requres one- or three-channel input" ); + if( channels!=1 && channels!=3 ) MK_THROW( "Requres one- or three-channel input" ); unsigned char* pixels = new unsigned char[ width*height*3 ]; unsigned char* pixelRow = new unsigned char[ width*channels]; for( unsigned int j=0 ; jchannels()!=3 && pixels->channels()!=1 ) MK_ERROR_OUT( "Pixel input must have 1 or 3 channels: " , pixels->channels() ); - if( labels->channels()!=3 && labels->channels()!=1 ) MK_ERROR_OUT( "Label input must have 1 or 3 channels: " , labels->channels() ); + if( pixels->channels()!=3 && pixels->channels()!=1 ) MK_THROW( "Pixel input must have 1 or 3 channels: " , pixels->channels() ); + if( labels->channels()!=3 && labels->channels()!=1 ) MK_THROW( "Label input must have 1 or 3 channels: " , labels->channels() ); __pixelRow = pixels->channels()==3 ? NULL : new unsigned char[ _resolution[0] ]; __labelRow = labels->channels()==3 ? NULL : new unsigned char[ _resolution[0] ]; _r = -2 ; prefetch(); @@ -281,7 +281,7 @@ void _Execute( void ) ImageReader::GetInfo( In.values[0] , _w , _h , _c ); w = _w , h = _h; ImageReader::GetInfo( In.values[1] , _w , _h , _c ); - if( w!=_w || h!=_h ) MK_ERROR_OUT( "Pixel and label dimensions don't match: " , _w , " x " , _h , " != " , w , " x " , h ); + if( w!=_w || h!=_h ) MK_THROW( "Pixel and label dimensions don't match: " , _w , " x " , _h , " != " , w , " x " , h ); } if( Verbose.set ) printf( "Resolution: %d x %d\n" , w , h ); @@ -495,7 +495,7 @@ void _Execute( void ) case 2: _Execute< Real , 2 >() ; break; // case 3: _Execute< Real , 3 >() ; break; // case 4: _Execute< Real , 4 >() ; break; - default: MK_ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); + default: MK_THROW( "Only B-Splines of degree 1 - 2 are supported" ); } } #endif // FAST_COMPILE diff --git a/Src/JPEG.inl b/Src/JPEG.inl index e9b3bb0e..d9d31ea8 100644 --- a/Src/JPEG.inl +++ b/Src/JPEG.inl @@ -43,7 +43,7 @@ my_error_exit (j_common_ptr cinfo) inline bool JPEGReader::GetInfo( const char* fileName , unsigned int& width , unsigned int& height , unsigned int& channels ) { FILE* fp = fopen( fileName , "rb" ); - if( !fp ) MK_ERROR_OUT( "Failed to open: " , fileName ); + if( !fp ) MK_THROW( "Failed to open: " , fileName ); struct jpeg_decompress_struct cInfo; struct my_error_mgr jErr; @@ -53,7 +53,7 @@ inline bool JPEGReader::GetInfo( const char* fileName , unsigned int& width , un if( setjmp( jErr.setjmp_buffer ) ) { jpeg_destroy_decompress( &cInfo ); - MK_ERROR_OUT( "JPEG error occured" ); + MK_THROW( "JPEG error occured" ); } jpeg_create_decompress( &cInfo ); @@ -74,14 +74,14 @@ inline JPEGReader::JPEGReader( const char* fileName , unsigned int& width , unsi { _currentRow = 0; _fp = fopen( fileName , "rb" ); - if( !_fp ) MK_ERROR_OUT( "Failed to open: " , fileName ); + if( !_fp ) MK_THROW( "Failed to open: " , fileName ); _cInfo.err = jpeg_std_error( &_jErr.pub ); _jErr.pub.error_exit = my_error_exit; if( setjmp( _jErr.setjmp_buffer ) ) { jpeg_destroy_decompress( &_cInfo ); - MK_ERROR_OUT( "JPEG error occured" ); + MK_THROW( "JPEG error occured" ); } jpeg_create_decompress( &_cInfo ); @@ -112,7 +112,7 @@ inline JPEGWriter::JPEGWriter( const char* fileName , unsigned int width , unsig { _currentRow = 0; _fp = fopen( fileName , "wb" ); - if( !_fp ) MK_ERROR_OUT( "Failed to open: " , fileName ); + if( !_fp ) MK_THROW( "Failed to open: " , fileName ); _cInfo.err = jpeg_std_error( &_jErr.pub ); jpeg_create_compress( &_cInfo ); diff --git a/Src/MarchingCubes.h b/Src/MarchingCubes.h index 2756f496..5ef3ae56 100644 --- a/Src/MarchingCubes.h +++ b/Src/MarchingCubes.h @@ -46,7 +46,7 @@ namespace PoissonRecon if( dir==BACK ) return std::string( "back" ); else if( dir==CROSS ) return std::string( "cross" ); else if( dir==FRONT ) return std::string( "front" ); - else{ MK_ERROR_OUT( "Unrecognized direction" ) ; return std::string( "" ); } + else{ MK_THROW( "Unrecognized direction" ) ; return std::string( "" ); } } // The number of k-dimensional elements in a d-dimensional cube is equal to @@ -346,7 +346,7 @@ namespace PoissonRecon case BACK: index = coIndex ; break; case CROSS: index = coIndex + HyperCube::ElementNum< D-1 , K >::Value ; break; case FRONT: index = coIndex + HyperCube::ElementNum< D-1 , K >::Value + HyperCube::ElementNum< D-1 , K-1 >::Value ; break; - default: MK_ERROR_OUT( "Bad direction: " , dir ); + default: MK_THROW( "Bad direction: " , dir ); } } template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > @@ -356,7 +356,7 @@ namespace PoissonRecon { case BACK: index = coIndex ; break; case FRONT: index = coIndex + HyperCube::ElementNum< D-1 , K >::Value ; break; - default: MK_ERROR_OUT( "Bad direction: " , dir ); + default: MK_THROW( "Bad direction: " , dir ); } } template< unsigned int D > template< unsigned int K > template< unsigned int _D , unsigned int _K > diff --git a/Src/MergePlyClientServer.inl b/Src/MergePlyClientServer.inl index 9a17e618..c84a23b1 100644 --- a/Src/MergePlyClientServer.inl +++ b/Src/MergePlyClientServer.inl @@ -47,8 +47,8 @@ inline void _Copy( FILE *target , FILE *source , size_t sz , size_t bufferSize=1 while( sz ) { size_t ioBytes = std::min< size_t >( bufferSize , sz ); - if( ioBytes!=fread( buffer , sizeof(unsigned char) , ioBytes , source ) ) MK_ERROR_OUT( "Failed to read from source: " , ioBytes ); - if( ioBytes!=fwrite( buffer , sizeof(unsigned char) , ioBytes , target ) ) MK_ERROR_OUT( "Failed to write to target: " , ioBytes ); + if( ioBytes!=fread( buffer , sizeof(unsigned char) , ioBytes , source ) ) MK_THROW( "Failed to read from source: " , ioBytes ); + if( ioBytes!=fwrite( buffer , sizeof(unsigned char) , ioBytes , target ) ) MK_THROW( "Failed to write to target: " , ioBytes ); sz -= ioBytes; } } @@ -101,13 +101,13 @@ void _OffsetPolygons( const Factory &factory , std::string in , std::string out auto ReadPolygon = [&]( FILE *fp ) { int n; - if( fread( &n , sizeof(int) , 1 , fp )!=1 ) MK_ERROR_OUT( "Failed to read polygon size" ); + if( fread( &n , sizeof(int) , 1 , fp )!=1 ) MK_THROW( "Failed to read polygon size" ); if( n>maxIndices ) { maxIndices = n; faceIndices = (Index*)realloc( faceIndices , sizeof(Index) * maxIndices ); } - if( fread( faceIndices , sizeof(Index) , n , fp )!=n ) MK_ERROR_OUT( "Failed to read polygon indices" ); + if( fread( faceIndices , sizeof(Index) , n , fp )!=n ) MK_THROW( "Failed to read polygon indices" ); return n; }; @@ -184,8 +184,8 @@ void _RunServer for( unsigned int j=0 ; j( elems[j] )==std::string( "vertex" ) ) foundVertices = true , vNum[i] = std::get<1>( elems[j] ); else if( std::get<0>( elems[j] )==std::string( "face" ) ) foundFaces = true , fNum[i] = std::get<1>( elems[j] ); - if( !foundVertices ) MK_ERROR_OUT( "Could not find vertices" ); - if( !foundFaces ) MK_ERROR_OUT( "Could not find faces" ); + if( !foundVertices ) MK_THROW( "Could not find vertices" ); + if( !foundFaces ) MK_THROW( "Could not find faces" ); profiler.update(); } offsets[0] = 0; @@ -255,7 +255,7 @@ void _RunServer case INT: std::get<2>( elems[1] )[0] = PLY::Face< int >::Properties[0] ; break; case U_INT: std::get<2>( elems[1] )[0] = PLY::Face< unsigned int >::Properties[0] ; break; case LONG_LONG: std::get<2>( elems[1] )[0] = PLY::Face< long long >::Properties[0] ; break; - default: MK_ERROR_OUT( "Unrecognized output type" ); + default: MK_THROW( "Unrecognized output type" ); } } @@ -404,7 +404,7 @@ void RunServer std::function< std::vector< std::string > (unsigned int) > commentFunctor ) { - if( clientSockets.size()!=sharedVertexCounts.size()+1 ) MK_ERROR_OUT( "Socket num and shared vertex count don't match: " , clientSockets.size() , " / " , sharedVertexCounts.size() ); + if( clientSockets.size()!=sharedVertexCounts.size()+1 ) MK_THROW( "Socket num and shared vertex count don't match: " , clientSockets.size() , " / " , sharedVertexCounts.size() ); for( unsigned int i=0 ; i( factory , in , out , offset , profiler ) ; break; case U_INT: _OffsetPolygons< unsigned int >( factory , in , out , offset , profiler ) ; break; case LONG_LONG: _OffsetPolygons< long long >( factory , in , out , offset , profiler ) ; break; - default: MK_ERROR_OUT( "Unrecognized output index type" ); + default: MK_THROW( "Unrecognized output index type" ); } char done = 1; socketStream.write( done ); @@ -510,15 +510,15 @@ ClientMergePlyInfo::ClientMergePlyInfo( BinaryStream &stream ) return true; }; - if( !stream.read( bufferSize ) ) MK_ERROR_OUT( "Failed to read buffer size" ); + if( !stream.read( bufferSize ) ) MK_THROW( "Failed to read buffer size" ); { size_t sz; - if( !stream.read( sz ) ) MK_ERROR_OUT( "Failed to read number of auxiliary properties" ); + if( !stream.read( sz ) ) MK_THROW( "Failed to read number of auxiliary properties" ); auxProperties.resize(sz); for( size_t i=0 ; i_MaxSize ) MK_ERROR_OUT( "Resize size exceeds max size, considering increasing nesting: " , sz , " > " , _MaxSize ); + if( sz>_MaxSize ) MK_THROW( "Resize size exceeds max size, considering increasing nesting: " , sz , " > " , _MaxSize ); // Quick check to see if anything needs doing if( sz<_size ) return size(); @@ -117,9 +117,9 @@ namespace PoissonRecon void read( BinaryStream &stream ) { size_t sz; - if( !stream.read( sz ) ) MK_ERROR_OUT( "Failed to read _size" ); + if( !stream.read( sz ) ) MK_THROW( "Failed to read _size" ); resize( sz ); - if( !stream.read( GetPointer( _data , _Size ) , _size ) ) MK_ERROR_OUT( "Failed to read _data" ); + if( !stream.read( GetPointer( _data , _Size ) , _size ) ) MK_THROW( "Failed to read _data" ); } void write( BinaryStream &stream , const Serializer< T > &serializer ) const @@ -141,12 +141,12 @@ namespace PoissonRecon const size_t serializedSize = serializer.size(); size_t sz; - if( !stream.read( sz ) ) MK_ERROR_OUT( "Failed to read _size" ); + if( !stream.read( sz ) ) MK_THROW( "Failed to read _size" ); if( _size ) { resize( sz ); char *buffer = new char[ _size * serializedSize ]; - if( !stream.read( buffer , serializedSize*_size ) ) MK_ERROR_OUT( "Failed tor read in data" ); + if( !stream.read( buffer , serializedSize*_size ) ) MK_THROW( "Failed tor read in data" ); for( size_t i=0 ; i<_size ; i++ ) serializer.deserialize( buffer+i*serializedSize , operator[]( i ) ); delete[] buffer; } @@ -226,7 +226,7 @@ namespace PoissonRecon size_t resize( size_t sz , const T &defaultValue ) { - if( sz>_MaxSize ) MK_ERROR_OUT( "Resize size exceeds max size, considering increasing nesting: " , sz , " > " , _MaxSize ); + if( sz>_MaxSize ) MK_THROW( "Resize size exceeds max size, considering increasing nesting: " , sz , " > " , _MaxSize ); size_t _sz = (sz+NestedVector< T , Depth-1 , LogSize >::_Mask)>>(LogSize*Depth); @@ -272,7 +272,7 @@ namespace PoissonRecon void read( BinaryStream &stream ) { size_t sz; - if( !stream.read( sz ) ) MK_ERROR_OUT( "Failed to read _size" ); + if( !stream.read( sz ) ) MK_THROW( "Failed to read _size" ); resize( sz ); for( size_t i=0 ; i<_size ; i++ ) _data[i]->read(stream); } @@ -289,7 +289,7 @@ namespace PoissonRecon const size_t serializedSize = serializer.size(); size_t sz; - if( !stream.read( sz ) ) MK_ERROR_OUT( "Failed to read _size" ); + if( !stream.read( sz ) ) MK_THROW( "Failed to read _size" ); resize( sz ); for( size_t i=0 ; i<_size ; i++ ) _data[i]->read( stream , serializer ); } diff --git a/Src/PNG.inl b/Src/PNG.inl index edd3080a..2f3dc29e 100644 --- a/Src/PNG.inl +++ b/Src/PNG.inl @@ -31,16 +31,16 @@ inline PNGReader::PNGReader( const char* fileName , unsigned int& width , unsign _currentRow = 0; _png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING , 0 , 0 , 0); - if( !_png_ptr ) MK_ERROR_OUT( "Failed to create png pointer" ); + if( !_png_ptr ) MK_THROW( "Failed to create png pointer" ); _info_ptr = png_create_info_struct( _png_ptr ); - if( !_info_ptr ) MK_ERROR_OUT( "Failed to create info pointer" ); + if( !_info_ptr ) MK_THROW( "Failed to create info pointer" ); _end_info = png_create_info_struct( _png_ptr ); - if( !_end_info ) MK_ERROR_OUT( "Failed to create end pointer" ); + if( !_end_info ) MK_THROW( "Failed to create end pointer" ); _fp = fopen( fileName , "rb" ); - if( !_fp ) MK_ERROR_OUT( "Failed to open file for reading: " , fileName ); + if( !_fp ) MK_THROW( "Failed to open file for reading: " , fileName ); png_init_io( _png_ptr , _fp ); png_read_info( _png_ptr, _info_ptr ); @@ -57,7 +57,7 @@ inline PNGReader::PNGReader( const char* fileName , unsigned int& width , unsign } else { - if( bit_depth!=8 ) MK_ERROR_OUT( "Expected 8 bits per channel" ); + if( bit_depth!=8 ) MK_THROW( "Expected 8 bits per channel" ); _scratchRow = NULL; } if( color_type==PNG_COLOR_TYPE_PALETTE ) png_set_expand( _png_ptr ) , printf( "Expanding PNG color pallette\n" ); @@ -98,14 +98,14 @@ inline bool PNGReader::GetInfo( const char* fileName , unsigned int& width , uns FILE* fp; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING , 0 , 0 , 0); - if( !png_ptr ) MK_ERROR_OUT( "Failed to create png pointer" ); + if( !png_ptr ) MK_THROW( "Failed to create png pointer" ); info_ptr = png_create_info_struct( png_ptr ); - if( !info_ptr ) MK_ERROR_OUT( "Failed to create info pointer" ); + if( !info_ptr ) MK_THROW( "Failed to create info pointer" ); end_info = png_create_info_struct( png_ptr ); - if( !end_info ) MK_ERROR_OUT( "Failed to create end pointer" ); + if( !end_info ) MK_THROW( "Failed to create end pointer" ); fp = fopen( fileName , "rb" ); - if( !fp ) MK_ERROR_OUT( "Failed to open file for reading: " , fileName ); + if( !fp ) MK_THROW( "Failed to open file for reading: " , fileName ); png_init_io( png_ptr , fp ); png_read_info( png_ptr, info_ptr ); @@ -124,12 +124,12 @@ PNGWriter::PNGWriter( const char* fileName , unsigned int width , unsigned int h _currentRow = 0; _png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING , 0 , 0 , 0 ); - if( !_png_ptr ) MK_ERROR_OUT( "Failed to create png write struct" ); + if( !_png_ptr ) MK_THROW( "Failed to create png write struct" ); _info_ptr = png_create_info_struct( _png_ptr ); - if( !_info_ptr ) MK_ERROR_OUT( "Failed to create png info struct"); + if( !_info_ptr ) MK_THROW( "Failed to create png info struct"); _fp = fopen( fileName , "wb" ); - if( !_fp ) MK_ERROR_OUT( "Failed to open file for writing: %s" , fileName ); + if( !_fp ) MK_THROW( "Failed to open file for writing: %s" , fileName ); png_init_io( _png_ptr , _fp ); png_set_compression_level( _png_ptr , Z_BEST_SPEED ); @@ -140,7 +140,7 @@ PNGWriter::PNGWriter( const char* fileName , unsigned int width , unsigned int h case 1: pngColorType = PNG_COLOR_TYPE_GRAY ; break; case 3: pngColorType = PNG_COLOR_TYPE_RGB ; break; case 4: pngColorType = PNG_COLOR_TYPE_RGBA ; break; - default: MK_ERROR_OUT( "Only 1, 3, or 4 channel PNGs are supported" ); + default: MK_THROW( "Only 1, 3, or 4 channel PNGs are supported" ); }; png_set_IHDR( _png_ptr , _info_ptr, width , height, 8 , pngColorType , PNG_INTERLACE_NONE , PNG_COMPRESSION_TYPE_DEFAULT , PNG_FILTER_TYPE_DEFAULT ); png_write_info( _png_ptr , _info_ptr ); diff --git a/Src/Ply.inl b/Src/Ply.inl index 0fbb54b6..76ec1773 100644 --- a/Src/Ply.inl +++ b/Src/Ply.inl @@ -38,7 +38,7 @@ namespace PLY template<> inline int Type< double >( void ){ return PLY_DOUBLE; } template< class Scalar > inline int Type( void ) { - MK_ERROR_OUT( "Unrecognized scalar type: " , typeid(Scalar).name() ); + MK_THROW( "Unrecognized scalar type: " , typeid(Scalar).name() ); return -1; } @@ -70,7 +70,7 @@ namespace PLY float version; PlyFile *ply = PlyFile::Read( fileName , elist , fileType , version ); - if( !ply ) MK_ERROR_OUT( "Could not open ply file for reading: " , fileName ); + if( !ply ) MK_THROW( "Could not open ply file for reading: " , fileName ); elems.resize( elist.size() ); for( unsigned int i=0 ; i( elems[i] ); ply = PlyFile::Write( fileName , elist , fileType , version ); } - if( !ply ) MK_ERROR_OUT( "Could not open ply for writing: " , fileName ); + if( !ply ) MK_THROW( "Could not open ply for writing: " , fileName ); for( unsigned int i=0 ; ielement_count( std::get<0>( elems[i] ) , std::get<1>( elems[i] ) ); @@ -150,10 +150,10 @@ namespace PLY float version; PlyFile *ply = PlyFile::Read( fileName, elist, fileType, version ); - if( !ply ) MK_ERROR_OUT( "Failed to open ply file for reading: " , fileName ); + if( !ply ) MK_THROW( "Failed to open ply file for reading: " , fileName ); std::vector< PlyProperty > plist = ply->get_element_description( "vertex" , vNum ); - if( !plist.size() ) MK_ERROR_OUT( "Failed to get element description: vertex" ); + if( !plist.size() ) MK_THROW( "Failed to get element description: vertex" ); for( unsigned int i=0 ; i plist = ply->get_element_description( "vertex" , vNum ); for( int i=0 ; icomments.size() ); for( int i=0 ; icomments.size() ; i++ ) comments.push_back( ply->comments[i] ); @@ -216,7 +216,7 @@ namespace PLY std::string &elem_name = elist[i]; size_t num_elems; std::vector< PlyProperty > plist = ply->get_element_description( elem_name , num_elems ); - if( !plist.size() ) MK_ERROR_OUT( "Could not read element properties: " , elem_name ); + if( !plist.size() ) MK_THROW( "Could not read element properties: " , elem_name ); if( elem_name=="vertex" ) { for( unsigned int i=0 ; icomments.size() ); for( int i=0 ; icomments.size() ; i++ ) comments.push_back( ply->comments[i] ); @@ -276,7 +276,7 @@ namespace PLY std::string &elem_name = elist[i]; size_t num_elems; std::vector< PlyProperty > plist = ply->get_element_description( elem_name , num_elems ); - if( !plist.size() ) MK_ERROR_OUT( "Could not read element properties: " , elem_name ); + if( !plist.size() ) MK_THROW( "Could not read element properties: " , elem_name ); if( elem_name=="vertex" ) { for( unsigned int i=0 ; i elem_names = { std::string( "vertex" ) , std::string( "face" ) }; PlyFile *ply = PlyFile::Write( fileName , elem_names , file_type , version ); - if( !ply ) MK_ERROR_OUT( "Could not create ply file for writing: " , fileName ); + if( !ply ) MK_THROW( "Could not create ply file for writing: " , fileName ); // // describe vertex and face properties @@ -391,14 +391,14 @@ namespace PLY { if( vertexNum>(size_t)std::numeric_limits< OutputIndex >::max() ) { - if( std::is_same< Index , OutputIndex >::value ) MK_ERROR_OUT( "more vertices than can be represented using " , Traits< Index >::name ); + if( std::is_same< Index , OutputIndex >::value ) MK_THROW( "more vertices than can be represented using " , Traits< Index >::name ); MK_WARN( "more vertices than can be represented using " , Traits< OutputIndex >::name , " using " , Traits< Index >::name , " instead" ); return Write< VertexFactory , Index , Real , Dim , Index >( fileName , vFactory , vertexNum , polygonNum , vertexStream , polygonStream , file_type , comments ); } float version; std::vector< std::string > elem_names = { std::string( "vertex" ) , std::string( "face" ) }; PlyFile *ply = PlyFile::Write( fileName , elem_names , file_type , version ); - if( !ply ) MK_ERROR_OUT( "Could not create ply file for writing: " , fileName ); + if( !ply ) MK_THROW( "Could not create ply file for writing: " , fileName ); vertexStream.reset(); polygonStream.reset(); @@ -428,7 +428,7 @@ namespace PLY for( size_t i=0; iput_element( (void *)&vertex ); } } @@ -438,7 +438,7 @@ namespace PLY for( size_t i=0; iput_element( PointerAddress( buffer ) ); } @@ -454,7 +454,7 @@ namespace PLY // create and fill a struct that the ply code can handle // Face< OutputIndex > ply_face; - if( !polygonStream.read( polygon ) ) MK_ERROR_OUT( "Failed to read polygon " , i , " / " , polygonNum ); + if( !polygonStream.read( polygon ) ) MK_THROW( "Failed to read polygon " , i , " / " , polygonNum ); ply_face.nr_vertices = int( polygon.size() ); ply_face.vertices = new OutputIndex[ polygon.size() ]; for( int j=0 ; j(size_t)std::numeric_limits< OutputIndex >::max() ) { - if( std::is_same< Index , OutputIndex >::value ) MK_ERROR_OUT( "more vertices than can be represented using " , Traits< Index >::name ); + if( std::is_same< Index , OutputIndex >::value ) MK_THROW( "more vertices than can be represented using " , Traits< Index >::name ); MK_WARN( "more vertices than can be represented using " , Traits< OutputIndex >::name , " using " , Traits< Index >::name , " instead" ); return Write< VertexFactory , Index , Real , Dim , Index >( fileName , vFactory , vertexNum , edgeNum , vertexStream , edgeStream , file_type , comments ); } float version; std::vector< std::string > elem_names = { std::string( "vertex" ) , std::string( "edge" ) }; PlyFile *ply = PlyFile::Write( fileName , elem_names , file_type , version ); - if( !ply ) MK_ERROR_OUT( "Could not create ply file for writing: " , fileName ); + if( !ply ) MK_THROW( "Could not create ply file for writing: " , fileName ); vertexStream.reset(); edgeStream.reset(); @@ -509,7 +509,7 @@ namespace PLY for( size_t i=0; iput_element( (void *)&vertex ); } } @@ -519,7 +519,7 @@ namespace PLY for( size_t i=0; iput_element( PointerAddress( buffer ) ); } @@ -535,7 +535,7 @@ namespace PLY // create and fill a struct that the ply code can handle // Edge< OutputIndex > ply_edge; - if( !edgeStream.read( edge ) ) MK_ERROR_OUT( "Failed to read edge " , i , " / " , edgeNum ); + if( !edgeStream.read( edge ) ) MK_THROW( "Failed to read edge " , i , " / " , edgeNum ); ply_edge.v1 = (OutputIndex)edge.first; ply_edge.v2 = (OutputIndex)edge.second; ply->put_element( (void *)&ply_edge ); diff --git a/Src/PlyFile.h b/Src/PlyFile.h index 0c712d59..f9f1fac6 100644 --- a/Src/PlyFile.h +++ b/Src/PlyFile.h @@ -155,13 +155,13 @@ namespace PoissonRecon } void read( BinaryStream &stream ) { - if( !stream.read( name ) ) MK_ERROR_OUT( "Failed to read name" ); - if( !stream.read( external_type ) ) MK_ERROR_OUT( "Failed to read external_type" ); - if( !stream.read( offset ) ) MK_ERROR_OUT( "Failed to read offset" ); - if( !stream.read( is_list ) ) MK_ERROR_OUT( "Failed to read is_list" ); - if( !stream.read( count_external ) ) MK_ERROR_OUT( "Failed to read count_external" ); - if( !stream.read( count_internal ) ) MK_ERROR_OUT( "Failed to read count_internal" ); - if( !stream.read( count_offset ) ) MK_ERROR_OUT( "Failed to read count_offset" ); + if( !stream.read( name ) ) MK_THROW( "Failed to read name" ); + if( !stream.read( external_type ) ) MK_THROW( "Failed to read external_type" ); + if( !stream.read( offset ) ) MK_THROW( "Failed to read offset" ); + if( !stream.read( is_list ) ) MK_THROW( "Failed to read is_list" ); + if( !stream.read( count_external ) ) MK_THROW( "Failed to read count_external" ); + if( !stream.read( count_internal ) ) MK_THROW( "Failed to read count_internal" ); + if( !stream.read( count_offset ) ) MK_THROW( "Failed to read count_offset" ); } }; diff --git a/Src/PlyFile.inl b/Src/PlyFile.inl index 6e449c9d..9ac7f5fc 100644 --- a/Src/PlyFile.inl +++ b/Src/PlyFile.inl @@ -246,7 +246,7 @@ void PlyFile::describe_element( const std::string &elem_name , size_t nelems , i { /* look for appropriate element */ PlyElement *elem = find_element( elem_name ); - if( elem==NULL ) MK_ERROR_OUT( "Can't find element '" , elem_name , "'" ); + if( elem==NULL ) MK_THROW( "Can't find element '" , elem_name , "'" ); elem->num = nelems; @@ -313,7 +313,7 @@ void PlyFile::element_count( const std::string &elem_name , size_t nelems ) { /* look for appropriate element */ PlyElement *elem = find_element( elem_name ); - if( elem==NULL ) MK_ERROR_OUT( "Can't find element '" , elem_name , "'" ); + if( elem==NULL ) MK_THROW( "Can't find element '" , elem_name , "'" ); elem->num = nelems; } @@ -332,7 +332,7 @@ void PlyFile::header_complete( void ) case PLY_ASCII: fprintf( fp , "format ascii 1.0\n" ) ; break; case PLY_BINARY_BE: fprintf( fp , "format binary_big_endian 1.0\n" ) ; break; case PLY_BINARY_LE: fprintf( fp , "format binary_little_endian 1.0\n" ) ; break; - default: MK_ERROR_OUT( "Bad file type: " , file_type ); + default: MK_THROW( "Bad file type: " , file_type ); } /* write out the comments */ @@ -380,7 +380,7 @@ elem_name - name of element we're talking about void PlyFile::put_element_setup( const std::string &elem_name ) { PlyElement *elem = find_element( elem_name ); - if( elem==NULL ) MK_ERROR_OUT( "Can't find element '" , elem_name , "'" ); + if( elem==NULL ) MK_THROW( "Can't find element '" , elem_name , "'" ); which_elem = elem; } @@ -876,7 +876,7 @@ PlyOtherElems *PlyFile::get_other_element( std::string &elem_name , size_t elem_ { /* look for appropriate element */ PlyElement *elem = find_element( elem_name ); - if( elem==NULL ) MK_ERROR_OUT( "Can't find element '" , elem_name , "'" ); + if( elem==NULL ) MK_THROW( "Can't find element '" , elem_name , "'" ); if( other_elems==NULL ) other_elems = new PlyOtherElems(); other_elems->other_list.resize( other_elems->other_list.size()+1 ); @@ -1053,7 +1053,7 @@ void PlyFile::_ascii_get_element( void *elem_ptr ) /* read in the element */ words = get_words( fp , &orig_line ); - if( !words.size() ) MK_ERROR_OUT( "Unexpected end of file" ); + if( !words.size() ) MK_THROW( "Unexpected end of file" ); which_word = 0; @@ -1232,7 +1232,7 @@ code - code for type void write_scalar_type( FILE *fp , int code ) { /* make sure this is a valid code */ - if( code<=PLY_START_TYPE || code>=PLY_END_TYPE ) MK_ERROR_OUT( "Bad data code: " , code ); + if( code<=PLY_START_TYPE || code>=PLY_END_TYPE ) MK_THROW( "Bad data code: " , code ); /* write the code to a file */ fprintf( fp , "%s" , type_names[code] ); @@ -1276,7 +1276,7 @@ void get_native_binary_type( void ) test.int_value = 1; if ( test.byte_values[0]==1 ) native_binary_type = PLY_BINARY_LE; else if( test.byte_values[sizeof(int)-1] == 1) native_binary_type = PLY_BINARY_BE; - else MK_ERROR_OUT( "Couldn't determine machine endianness" ); + else MK_THROW( "Couldn't determine machine endianness" ); } /****************************************************************************** @@ -1297,7 +1297,7 @@ void check_types() (ply_type_size[PLY_ULONGLONG] != sizeof(unsigned long long)) || (ply_type_size[PLY_FLOAT] != sizeof(float)) || (ply_type_size[PLY_DOUBLE] != sizeof(double))) - MK_ERROR_OUT( "Type sizes do not match built-in types" ); + MK_THROW( "Type sizes do not match built-in types" ); types_checked = 1; } @@ -1422,7 +1422,7 @@ double get_item_value( const void *item , int type ) case PLY_FLOAT_32: return (double)*(const float *)item; case PLY_DOUBLE: case PLY_FLOAT_64: return (double)*(const double *)item; - default: MK_ERROR_OUT( "Bad type: " , type ); + default: MK_THROW( "Bad type: " , type ); } return 0; } @@ -1494,12 +1494,12 @@ void write_binary_item( FILE *fp , int file_type , int int_val , unsigned int ui case PLY_FLOAT_64: value = &double_val; break; - default: MK_ERROR_OUT( "Bad type: " , type ); + default: MK_THROW( "Bad type: " , type ); } if( (file_type!=native_binary_type) && (ply_type_size[type]>1) ) swap_bytes( (char *)value , ply_type_size[type] ); - if( fwrite( value , ply_type_size[type] , 1 , fp )!=1 ) MK_ERROR_OUT( "Failed to write binary item" ); + if( fwrite( value , ply_type_size[type] , 1 , fp )!=1 ) MK_THROW( "Failed to write binary item" ); } @@ -1524,11 +1524,11 @@ void write_ascii_item( FILE *fp , int int_val , unsigned int uint_val , long lon case PLY_INT_16: case PLY_INT: case PLY_INT_32: - if( fprintf( fp , "%d " , int_val )<=0 ) MK_ERROR_OUT( "fprintf() failed -- aborting" ); + if( fprintf( fp , "%d " , int_val )<=0 ) MK_THROW( "fprintf() failed -- aborting" ); break; case PLY_LONGLONG: case PLY_INT_64: - if( fprintf( fp , "%lld " , longlong_val )<=0 ) MK_ERROR_OUT( "fprintf() failed -- aborting" ); + if( fprintf( fp , "%lld " , longlong_val )<=0 ) MK_THROW( "fprintf() failed -- aborting" ); break; case PLY_UCHAR: case PLY_UINT_8: @@ -1536,19 +1536,19 @@ void write_ascii_item( FILE *fp , int int_val , unsigned int uint_val , long lon case PLY_UINT_16: case PLY_UINT: case PLY_UINT_32: - if( fprintf( fp , "%u " , uint_val )<=0 ) MK_ERROR_OUT( "fprintf() failed -- aborting" ); + if( fprintf( fp , "%u " , uint_val )<=0 ) MK_THROW( "fprintf() failed -- aborting" ); break; case PLY_ULONGLONG: case PLY_UINT_64: - if( fprintf( fp , "%llu " , ulonglong_val )<=0 ) MK_ERROR_OUT( "fprintf() failed -- aborting" ); + if( fprintf( fp , "%llu " , ulonglong_val )<=0 ) MK_THROW( "fprintf() failed -- aborting" ); break; case PLY_FLOAT: case PLY_FLOAT_32: case PLY_DOUBLE: case PLY_FLOAT_64: - if( fprintf( fp , "%g " , double_val )<=0 ) MK_ERROR_OUT( "fprintf() failed -- aborting" ); + if( fprintf( fp , "%g " , double_val )<=0 ) MK_THROW( "fprintf() failed -- aborting" ); break; - default: MK_ERROR_OUT( "Bad type: " , type ); + default: MK_THROW( "Bad type: " , type ); } } @@ -1650,7 +1650,7 @@ void get_stored_item( void *ptr , int type , int &int_val , unsigned int &uint_v longlong_val = (long long)double_val; ulonglong_val = (unsigned long long)double_val; break; - default: MK_ERROR_OUT( "Bad type: " , type ); + default: MK_THROW( "Bad type: " , type ); } } @@ -1675,7 +1675,7 @@ void get_binary_item( FILE *fp , int file_type , int type , int &int_val , unsig ptr = ( void * )c; - if( fread( ptr , ply_type_size[type] , 1 , fp )!=1 ) MK_ERROR_OUT( "fread() failed -- aborting: " , std::string( type_names[type] ) ); + if( fread( ptr , ply_type_size[type] , 1 , fp )!=1 ) MK_THROW( "fread() failed -- aborting: " , std::string( type_names[type] ) ); if( ( file_type!=native_binary_type ) && ( ply_type_size[type]>1 ) ) swap_bytes( (char *)ptr , ply_type_size[type] ); switch( type ) @@ -1760,7 +1760,7 @@ void get_binary_item( FILE *fp , int file_type , int type , int &int_val , unsig longlong_val = (long long)double_val; ulonglong_val = (unsigned long long)int_val; break; - default: MK_ERROR_OUT( "Bad type: " , type ); + default: MK_THROW( "Bad type: " , type ); } } @@ -1832,7 +1832,7 @@ void get_ascii_item( const std::string &word , int type , int &int_val , unsigne longlong_val = (long long)double_val; ulonglong_val = (unsigned long long)double_val; break; - default: MK_ERROR_OUT( "Bad type: " , type ); + default: MK_THROW( "Bad type: " , type ); } } @@ -1874,7 +1874,7 @@ void store_item( void *item , int type , int int_val , unsigned int uint_val , l case PLY_FLOAT_32: *( float *)item = ( float)double_val ; break; case PLY_DOUBLE: case PLY_FLOAT_64: *( double *)item = ( double)double_val ; break; - default: MK_ERROR_OUT( "Bad type: " , type ); + default: MK_THROW( "Bad type: " , type ); } } diff --git a/Src/PointInterpolant.cpp b/Src/PointInterpolant.cpp index 66351ac4..ed68f66a 100644 --- a/Src/PointInterpolant.cpp +++ b/Src/PointInterpolant.cpp @@ -432,7 +432,7 @@ void WriteGrid( const char *fileName , ConstPointer( Real ) values , unsigned in else if( !strcasecmp( ext , "iso" ) ) { FILE *fp = fopen( fileName , "wb" ); - if( !fp ) MK_ERROR_OUT( "Failed to open file for writing: " , fileName ); + if( !fp ) MK_THROW( "Failed to open file for writing: " , fileName ); int r = (int)res; fwrite( &r , sizeof(int) , 1 , fp ); size_t count = 1; @@ -557,7 +557,7 @@ void Execute( UIntPack< FEMSigs ... > ) for( int i=0 ; i ) if( Tree.set ) { FILE* fp = fopen( Tree.value , "wb" ); - if( !fp ) MK_ERROR_OUT( "Failed to open file for writing: " , Tree.value ); + if( !fp ) MK_THROW( "Failed to open file for writing: " , Tree.value ); FileStream fs( fp ); FEMTree< Dim , Real >::WriteParameter( fs ); DenseNodeData< Real , Sigs >::WriteSignatures( fs ); @@ -949,7 +949,7 @@ void Execute( void ) case 2: return Execute< Real >( IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BType >::Signature >() ); case 3: return Execute< Real >( IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BType >::Signature >() ); // case 4: return Execute< Real >( IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BType >::Signature >() ); - default: MK_ERROR_OUT( "Only B-Splines of degree 1 - 3 are supported" ); + default: MK_THROW( "Only B-Splines of degree 1 - 3 are supported" ); } } @@ -961,7 +961,7 @@ void Execute( void ) case BOUNDARY_FREE+1: return Execute< Dim , Real , BOUNDARY_FREE >(); case BOUNDARY_NEUMANN+1: return Execute< Dim , Real , BOUNDARY_NEUMANN >(); case BOUNDARY_DIRICHLET+1: return Execute< Dim , Real , BOUNDARY_DIRICHLET >(); - default: MK_ERROR_OUT( "Not a valid boundary type: " , BType.value ); + default: MK_THROW( "Not a valid boundary type: " , BType.value ); } } #endif // !FAST_COMPILE @@ -982,19 +982,19 @@ int main( int argc , char* argv[] ) if( !InValues.set && !InGradients.set ) { ShowUsage( argv[0] ); - MK_ERROR_OUT( "Either values or gradients need to be specified" ); + MK_THROW( "Either values or gradients need to be specified" ); return 0; } if( !InValues.set ) ValueWeight.value = 0; if( !InGradients.set ) GradientWeight.value = 0; - if( ValueWeight.value<0 ) MK_ERROR_OUT( "Value weight must be non-negative: " , ValueWeight.value , "> 0" ); - if( GradientWeight.value<0 ) MK_ERROR_OUT( "Gradient weight must be non-negative: " , GradientWeight.value , "> 0" ); - if( !ValueWeight.value && !GradientWeight.value ) MK_ERROR_OUT( "Either value or gradient weight must be positive" ); + if( ValueWeight.value<0 ) MK_THROW( "Value weight must be non-negative: " , ValueWeight.value , "> 0" ); + if( GradientWeight.value<0 ) MK_THROW( "Gradient weight must be non-negative: " , GradientWeight.value , "> 0" ); + if( !ValueWeight.value && !GradientWeight.value ) MK_THROW( "Either value or gradient weight must be positive" ); - if( LapWeight.value<0 ) MK_ERROR_OUT( "Laplacian weight must be non-negative: " , LapWeight.value , " > 0" ); - if( BiLapWeight.value<0 ) MK_ERROR_OUT( "Bi-Laplacian weight must be non-negative: " , BiLapWeight.value , " > 0" ); - if( !LapWeight.value && !BiLapWeight.value ) MK_ERROR_OUT( "Eiter Laplacian or bi-Laplacian weight must be positive" ); + if( LapWeight.value<0 ) MK_THROW( "Laplacian weight must be non-negative: " , LapWeight.value , " > 0" ); + if( BiLapWeight.value<0 ) MK_THROW( "Bi-Laplacian weight must be non-negative: " , BiLapWeight.value , " > 0" ); + if( !LapWeight.value && !BiLapWeight.value ) MK_THROW( "Eiter Laplacian or bi-Laplacian weight must be positive" ); if( !BaseDepth.set ) BaseDepth.value = FullDepth.value; if( BaseDepth.value>FullDepth.value ) @@ -1025,7 +1025,7 @@ int main( int argc , char* argv[] ) #else // !FAST_COMPILE if ( Dimension.value==2 ) Execute< 2 , Real >(); else if( Dimension.value==3 ) Execute< 3 , Real >(); - else MK_ERROR_OUT( "Only Degrees 2 and 3 are supported" ); + else MK_THROW( "Only Degrees 2 and 3 are supported" ); #endif // FAST_COMPILE if( Performance.set ) { diff --git a/Src/PointPartition.inl b/Src/PointPartition.inl index fd343dd2..9fa514d3 100644 --- a/Src/PointPartition.inl +++ b/Src/PointPartition.inl @@ -41,7 +41,7 @@ std::string FileDir( std::string dir , std::string header , unsigned int clientI std::string FileName( std::string dir , unsigned int slab , unsigned int slabs , unsigned int filesPerDir ) { - if( filesPerDir<=1 ) MK_ERROR_OUT( "Need at least two files per directory" ); + if( filesPerDir<=1 ) MK_THROW( "Need at least two files per directory" ); if( !dir.length() ) dir = std::string( "." ); if( dir.back()!=FileSeparator ) dir.push_back( FileSeparator ); @@ -95,16 +95,16 @@ PointSetInfo< Real , Dim >::PointSetInfo( unsigned int slabs ) : modelToUnitCube template< typename Real , unsigned int Dim > PointSetInfo< Real , Dim >::PointSetInfo( BinaryStream &stream ) { - if( !stream.read( header ) ) MK_ERROR_OUT( "Failed to read header" ); - if( !stream.read( modelToUnitCube ) ) MK_ERROR_OUT( "Failed to read model-to-unit-cube transform" ); - if( !stream.read( pointsPerSlab ) ) MK_ERROR_OUT( "Failed to read points-per-slab" ); + if( !stream.read( header ) ) MK_THROW( "Failed to read header" ); + if( !stream.read( modelToUnitCube ) ) MK_THROW( "Failed to read model-to-unit-cube transform" ); + if( !stream.read( pointsPerSlab ) ) MK_THROW( "Failed to read points-per-slab" ); { size_t sz; - if( !stream.read( sz ) ) MK_ERROR_OUT( "Failed to read number of auxiliary properties" ); + if( !stream.read( sz ) ) MK_THROW( "Failed to read number of auxiliary properties" ); auxiliaryProperties.resize(sz); for( size_t i=0 ; i @@ -124,12 +124,12 @@ void PointSetInfo< Real , Dim >::write( BinaryStream &stream ) const void RemovePointSlabDirs( std::string dir ){ std::filesystem::remove_all( dir ); } void CreatePointSlabDirs( std::string dir , unsigned int count , unsigned int filesPerDir ) { - if( filesPerDir<=1 ) MK_ERROR_OUT( "Need at least two files per directory" ); + if( filesPerDir<=1 ) MK_THROW( "Need at least two files per directory" ); if( !dir.length() ) dir = std::string( "." ); if( dir.back()!=FileSeparator ) dir += std::string(1,FileSeparator); try{ std::filesystem::create_directories( dir ); } - catch( ... ){ MK_ERROR_OUT( "Failed to create directory: " , dir ); } + catch( ... ){ MK_THROW( "Failed to create directory: " , dir ); } unsigned int depth = 0; { @@ -155,7 +155,7 @@ void CreatePointSlabDirs( std::string dir , unsigned int count , unsigned int fi sStream << dir << i << FileSeparator; std::string _dir = sStream.str(); try{ std::filesystem::create_directories( _dir ); } - catch( ... ){ MK_ERROR_OUT( "Failed to create directory: " , _dir ); } + catch( ... ){ MK_THROW( "Failed to create directory: " , _dir ); } MakeDirs( _dir , std::min< unsigned int >( count-(i*_filesPerDir) , _filesPerDir ) , depth-1 , filesPerDir ); } } @@ -258,7 +258,7 @@ protected: } } } - if( minIndex==-1 ) MK_ERROR_OUT( "Could not find a solution: [ " , start , " , " , end , " ) " , interiorBoundaries ); + if( minIndex==-1 ) MK_THROW( "Could not find a solution: [ " , start , " , " , end , " ) " , interiorBoundaries ); _solutions[start][end][interiorBoundaries].e = minEnergy; _solutions[start][end][interiorBoundaries].idx = minIndex; return minEnergy; @@ -361,7 +361,7 @@ size_t Partition::size( unsigned int i ) const size_t Partition::size( unsigned int i , unsigned int padSize ) const #endif // ADAPTIVE_PADDING { - if( i>_starts.size() ) MK_ERROR_OUT( "Index out of bounds: 0 <= " , i , " <= " , _starts.size() ); + if( i>_starts.size() ) MK_THROW( "Index out of bounds: 0 <= " , i , " <= " , _starts.size() ); #ifdef ADAPTIVE_PADDING std::pair< unsigned int , unsigned int > r = range( i ); #else // !ADAPTIVE_PADDING @@ -448,7 +448,7 @@ unsigned int Partition::partitions( void ) const{ return (unsigned int)_starts.s long ReadPLYProperties( FILE *fp , std::vector< PlyProperty > &properties ) { size_t sz; - if( fread( &sz , sizeof( size_t ) , 1 , fp )!=1 ) MK_ERROR_OUT( "Failed to read property size" ); + if( fread( &sz , sizeof( size_t ) , 1 , fp )!=1 ) MK_THROW( "Failed to read property size" ); properties.resize( sz ); FileStream fs(fp); for( size_t i=0 ; i &properties ) long ReadPLYProperties( const char *fileName , std::vector< PlyProperty > &properties ) { FILE *fp = fopen( fileName , "rb" ); - if( !fp ) MK_ERROR_OUT( "Could not open file for reading: " , fileName ); + if( !fp ) MK_THROW( "Could not open file for reading: " , fileName ); long pos = ReadPLYProperties( fp , properties ); fclose( fp ); return pos; @@ -476,7 +476,7 @@ long WritePLYProperties( FILE *fp , const std::vector< PlyProperty > &properties long WritePLYProperties( const char *fileName , const std::vector< PlyProperty > &properties ) { FILE *fp = fopen( fileName , "wb" ); - if( !fp ) MK_ERROR_OUT( "Could not open file for writing: " , fileName ); + if( !fp ) MK_THROW( "Could not open file for writing: " , fileName ); long pos = WritePLYProperties( fp , properties ); fclose( fp ); return pos; @@ -497,7 +497,7 @@ BufferedBinaryInputDataStream< InputFactory >::BufferedBinaryInputDataStream( co _elementSize = _factory.bufferSize(); _buffer = AllocPointer< char >( _elementSize*_bufferSize ); _fp = fopen( fileName , "rb" ); - if( !_fp ) MK_ERROR_OUT( "Could not open file for reading: " , fileName ); + if( !_fp ) MK_THROW( "Could not open file for reading: " , fileName ); std::vector< PlyProperty > properties; _inset = ReadPLYProperties( _fp , properties ); } @@ -548,7 +548,7 @@ BufferedBinaryOutputDataStream< OutputFactory >::BufferedBinaryOutputDataStream( _elementSize = _factory.bufferSize(); _buffer = AllocPointer< char >( _elementSize*_bufferSize ); _fp = fopen( fileName , "wb" ); - if( !_fp ) MK_ERROR_OUT( "Could not open file for writing: " , fileName ); + if( !_fp ) MK_THROW( "Could not open file for writing: " , fileName ); std::vector< PlyProperty > properties( factory.plyWriteNum() ); for( unsigned int i=0 ; i size_t _SampleCount( std::string in , std::vector< PlyProperty > &auxProperties ) { char *ext = GetFileExtension( in.c_str() ); - if( strcasecmp( ext , "ply" ) ) MK_ERROR_OUT( "Only .ply files supported: " , in ); + if( strcasecmp( ext , "ply" ) ) MK_THROW( "Only .ply files supported: " , in ); delete[] ext; size_t vNum; @@ -38,9 +38,9 @@ size_t _SampleCount( std::string in , std::vector< PlyProperty > &auxProperties Factory factory; bool *readFlags = new bool[ factory.plyReadNum() ]; int fileType = PLY::ReadVertexHeader( in , factory , readFlags , auxProperties , vNum ); - if( fileType==PLY_ASCII ) MK_ERROR_OUT( "Point set must be in binary format" ); - if( !factory.template plyValidReadProperties<0>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain positions" ); - if( !factory.template plyValidReadProperties<1>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain normals" ); + if( fileType==PLY_ASCII ) MK_THROW( "Point set must be in binary format" ); + if( !factory.template plyValidReadProperties<0>( readFlags ) ) MK_THROW( "Ply file does not contain positions" ); + if( !factory.template plyValidReadProperties<1>( readFlags ) ) MK_THROW( "Ply file does not contain normals" ); delete[] readFlags; return vNum; } @@ -55,14 +55,14 @@ void _ProcessPLY( std::string in , std::pair< size_t , size_t > range , const Fa int file_type; PlyFile *ply = PlyFile::Read( in , elist , file_type , version ); - if( !ply ) MK_ERROR_OUT( "Could not create ply file for reading: " , in ); - if( file_type==PLY_ASCII ) MK_ERROR_OUT( "Only binary file type supported" ); + if( !ply ) MK_THROW( "Could not create ply file for reading: " , in ); + if( file_type==PLY_ASCII ) MK_THROW( "Only binary file type supported" ); size_t vCount; std::vector< PlyProperty > plist = ply->get_element_description( std::string( "vertex" ) , vCount ); - if( !plist.size() ) MK_ERROR_OUT( "Could not read element properties: vertex" ); + if( !plist.size() ) MK_THROW( "Could not read element properties: vertex" ); if( range.second==-1 ) range.second = vCount; - if( range.first>=range.second ) MK_ERROR_OUT( "Bad Range: [ " , range.first , " , " , range.second , " )" ); + if( range.first>=range.second ) MK_THROW( "Bad Range: [ " , range.first , " , " , range.second , " )" ); if( range.second>vCount ) { MK_WARN( "Max range too large, resetting" ); @@ -178,7 +178,7 @@ template< typename Real , unsigned int Dim > std::vector< PlyProperty > _GetUnprocessedProperties( std::string in ) { char *ext = GetFileExtension( in.c_str() ); - if( strcasecmp( ext , "ply" ) ) MK_ERROR_OUT( "Expected .ply file" ); + if( strcasecmp( ext , "ply" ) ) MK_THROW( "Expected .ply file" ); delete[] ext; std::vector< PlyProperty > unprocessedProperties; @@ -187,8 +187,8 @@ std::vector< PlyProperty > _GetUnprocessedProperties( std::string in ) Factory factory; bool *readFlags = new bool[ factory.plyReadNum() ]; PLY::ReadVertexHeader( in , factory , readFlags , unprocessedProperties ); - if( !factory.template plyValidReadProperties<0>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain positions" ); - if( !factory.template plyValidReadProperties<1>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain normals" ); + if( !factory.template plyValidReadProperties<0>( readFlags ) ) MK_THROW( "Ply file does not contain positions" ); + if( !factory.template plyValidReadProperties<1>( readFlags ) ) MK_THROW( "Ply file does not contain normals" ); delete[] readFlags; } return unprocessedProperties; @@ -262,7 +262,7 @@ std::pair< PointPartition::PointSetInfo< Real , Dim > , PointPartition::Partitio { std::vector< size_t > slabSizes; SocketStream( clientSockets[c] ).read( slabSizes ); - if( slabSizes.size()!=clientPartitionInfo.slabs ) MK_ERROR_OUT( "Unexpected number of slabs: " , slabSizes.size() , " != " , clientPartitionInfo.slabs ); + if( slabSizes.size()!=clientPartitionInfo.slabs ) MK_THROW( "Unexpected number of slabs: " , slabSizes.size() , " != " , clientPartitionInfo.slabs ); for( unsigned int i=0 ; i::ClientPartitionInfo( BinaryStream &stream ) b = _b!=0; return true; }; - if( !stream.read( in ) ) MK_ERROR_OUT( "Failed to read in" ); - if( !stream.read( tempDir ) ) MK_ERROR_OUT( "Failed to read temp dir" ); - if( !stream.read( outDir ) ) MK_ERROR_OUT( "Failed to read out dir" ); - if( !stream.read( outHeader ) ) MK_ERROR_OUT( "Failed to read out header" ); - if( !stream.read( slabs ) ) MK_ERROR_OUT( "Failed to read slabs" ); - if( !stream.read( filesPerDir ) ) MK_ERROR_OUT( "Failed to read files per dir" ); - if( !stream.read( bufferSize ) ) MK_ERROR_OUT( "Failed to read buffer size" ); - if( !stream.read( scale ) ) MK_ERROR_OUT( "Failed to read scale" ); - if( !stream.read( clientCount ) ) MK_ERROR_OUT( "Failed to read client count" ); - if( !stream.read( sliceDir ) ) MK_ERROR_OUT( "Failed to read slice direction" ); - if( !ReadBool( verbose ) ) MK_ERROR_OUT( "Failed to read verbose flag" ); + if( !stream.read( in ) ) MK_THROW( "Failed to read in" ); + if( !stream.read( tempDir ) ) MK_THROW( "Failed to read temp dir" ); + if( !stream.read( outDir ) ) MK_THROW( "Failed to read out dir" ); + if( !stream.read( outHeader ) ) MK_THROW( "Failed to read out header" ); + if( !stream.read( slabs ) ) MK_THROW( "Failed to read slabs" ); + if( !stream.read( filesPerDir ) ) MK_THROW( "Failed to read files per dir" ); + if( !stream.read( bufferSize ) ) MK_THROW( "Failed to read buffer size" ); + if( !stream.read( scale ) ) MK_THROW( "Failed to read scale" ); + if( !stream.read( clientCount ) ) MK_THROW( "Failed to read client count" ); + if( !stream.read( sliceDir ) ) MK_THROW( "Failed to read slice direction" ); + if( !ReadBool( verbose ) ) MK_THROW( "Failed to read verbose flag" ); } template< typename Real > diff --git a/Src/PointsToDisks.cpp b/Src/PointsToDisks.cpp index 41fc6c1f..56bb03d6 100644 --- a/Src/PointsToDisks.cpp +++ b/Src/PointsToDisks.cpp @@ -190,7 +190,7 @@ int main( int argc , char* argv[] ) PointsToKeep.value = (unsigned int)vertices.size(); } - if( !hasNormals ) MK_ERROR_OUT( "Input is not oriented" ); + if( !hasNormals ) MK_THROW( "Input is not oriented" ); if( PointsToKeep.set ) { diff --git a/Src/PoissonRecon.client.inl b/Src/PoissonRecon.client.inl index 25dcc150..a00dc0cf 100644 --- a/Src/PoissonRecon.client.inl +++ b/Src/PoissonRecon.client.inl @@ -441,7 +441,7 @@ size_t Client< Real , Dim , BType , Degree >::_receive1( const ClientReconstruct ClientServerStream< true > serverStream( _serverSocket , _index , clientReconInfo ); serverStream.ioBytes = 0; - if( !serverStream.read( _modelToUnitCube ) ) MK_ERROR_OUT( "Failed to read model-to-unit-cube transform" ); + if( !serverStream.read( _modelToUnitCube ) ) MK_THROW( "Failed to read model-to-unit-cube transform" ); serverStream.read( _range ); profiler.update(); @@ -682,7 +682,7 @@ size_t Client< Real , Dim , BType , Degree >::_receive3( const ClientReconstruct { ClientServerStream< true > serverStream( _serverSocket , _index , clientReconInfo ); serverStream.ioBytes = 0; - if( !serverStream.read( cumulativePointWeight ) ) MK_ERROR_OUT( "Could not read cumulative point weight" ); + if( !serverStream.read( cumulativePointWeight ) ) MK_THROW( "Could not read cumulative point weight" ); profiler.update(); return serverStream.ioBytes; } @@ -1043,7 +1043,7 @@ std::pair< double , double > Client< Real , Dim , BType , Degree >::_process5( c { if( clientNode->nodeData.nodeIndex!=-1 ) { - if( clientNode->nodeData.nodeIndex>=(node_index_type)clientToServer.size() ) MK_ERROR_OUT( "More client nodes than server nodes" ); + if( clientNode->nodeData.nodeIndex>=(node_index_type)clientToServer.size() ) MK_THROW( "More client nodes than server nodes" ); clientToServer[ clientNode->nodeData.nodeIndex ] = serverNode->nodeData.nodeIndex; } if( _tree.depth( clientNode )<(int)clientReconInfo.sharedDepth && clientNode->children ) @@ -1146,7 +1146,7 @@ std::pair< double , double > Client< Real , Dim , BType , Degree >::_process5( c if( clientReconInfo.outDir.length() ) outFileName = PointPartition::FileDir( clientReconInfo.outDir , outFileName ); FILE* fp = fopen( outFileName.c_str() , "wb" ); - if( !fp ) MK_ERROR_OUT( "Failed to open file for writing: " , outFileName ); + if( !fp ) MK_THROW( "Failed to open file for writing: " , outFileName ); FileStream fs(fp); FEMTree< Dim , Real >::WriteParameter( fs ); DenseNodeData< Real , Sigs >::WriteSignatures( fs ); @@ -1350,7 +1350,7 @@ Client< Real , Dim , BType , Degree >::Client( const ClientReconstructionInfo< R AuxDataFactory auxDataFactory( clientReconInfo.auxProperties ); bool needAuxData = clientReconInfo.dataX>0 && auxDataFactory.bufferSize(); - if( phase!=3 && phase!=5 && phase!=7 ) MK_ERROR_OUT( "Only phases 3, 5, and 7 supported: " , phase ); + if( phase!=3 && phase!=5 && phase!=7 ) MK_THROW( "Only phases 3, 5, and 7 supported: " , phase ); stream.read( _index ); stream.read( _range ); @@ -1366,10 +1366,10 @@ Client< Real , Dim , BType , Degree >::Client( const ClientReconstructionInfo< R std::vector< FEMTreeNode * > nodes( _tree.spaceRoot().nodes() , NULL ); size_t idx = 0; _tree.spaceRoot().processNodes( [&]( FEMTreeNode *node ){ nodes[idx++] = node; } ); -if( idx!=nodes.size() ) MK_ERROR_OUT( "uhoh" ); +if( idx!=nodes.size() ) MK_THROW( "uhoh" ); std::vector< T > _samples; - if( !stream.read( _samples ) ) MK_ERROR_OUT( "Failed to read samples" ); + if( !stream.read( _samples ) ) MK_THROW( "Failed to read samples" ); samples.resize( _samples.size() ); // Convert indices to node pointers for( size_t i=0 ; i _samples; - if( !stream.read( _samples ) ) MK_ERROR_OUT( "Failed to read samples" ); + if( !stream.read( _samples ) ) MK_THROW( "Failed to read samples" ); size_t sz = _samples.size(); SampleDataTypeSerializer< Real , Dim > serializer( clientReconInfo.auxProperties ); samples.resize( sz ); @@ -1397,7 +1397,7 @@ if( idx!=nodes.size() ) MK_ERROR_OUT( "uhoh" ); size_t serializedSize = serializer.size(); { Pointer( char ) buffer = NewPointer< char >( sz * serializedSize ); - if( !stream.read( buffer , sz*serializedSize ) ) MK_ERROR_OUT( "Failed to read sample data" ); + if( !stream.read( buffer , sz*serializedSize ) ) MK_THROW( "Failed to read sample data" ); for( unsigned int i=0 ; i::_write( const ClientReconstructionIn AuxDataFactory auxDataFactory( clientReconInfo.auxProperties ); bool needAuxData = clientReconInfo.dataX>0 && auxDataFactory.bufferSize(); - if( phase!=1 && phase!=3 && phase!=5 ) MK_ERROR_OUT( "Only phases 1, 3, and 5 supported: " , phase ); + if( phase!=1 && phase!=3 && phase!=5 ) MK_THROW( "Only phases 1, 3, and 5 supported: " , phase ); _tree.write( stream , false ); stream.write( _modelToUnitCube ); diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp index 961830d5..198aec0e 100644 --- a/Src/PoissonRecon.cpp +++ b/Src/PoissonRecon.cpp @@ -361,7 +361,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) for( int i=0 ; i() , envelopeMesh->vertices , polygons , file_type , comments ); envelopeMesh->simplices.resize( polygons.size() ); for( int i=0 ; isimplices[i][j] = polygons[i][j]; } } @@ -505,7 +505,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) if( Tree.set ) { FILE* fp = fopen( Tree.value , "wb" ); - if( !fp ) MK_ERROR_OUT( "Failed to open file for writing: " , Tree.value ); + if( !fp ) MK_THROW( "Failed to open file for writing: " , Tree.value ); FileStream fs(fp); FEMTree< Dim , Real >::WriteParameter( fs ); DenseNodeData< Real , Sigs >::WriteSignatures( fs ); @@ -570,7 +570,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) case 2: return Execute< Real , Dim , FEMDegreeAndBType< 2 , BType >::Signature >( auxDataFactory ); // case 3: return Execute< Real , Dim , FEMDegreeAndBType< 3 , BType >::Signature >( auxDataFactory ); // case 4: return Execute< Real , Dim , FEMDegreeAndBType< 4 , BType >::Signature >( auxDataFactory ); - default: MK_ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); + default: MK_THROW( "Only B-Splines of degree 1 - 2 are supported" ); } } @@ -582,7 +582,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) case BOUNDARY_FREE+1: return Execute< Dim , Real , BOUNDARY_FREE >( auxDataFactory ); case BOUNDARY_NEUMANN+1: return Execute< Dim , Real , BOUNDARY_NEUMANN >( auxDataFactory ); case BOUNDARY_DIRICHLET+1: return Execute< Dim , Real , BOUNDARY_DIRICHLET >( auxDataFactory ); - default: MK_ERROR_OUT( "Not a valid boundary type: " , BType.value ); + default: MK_THROW( "Not a valid boundary type: " , BType.value ); } } #endif // !FAST_COMPILE @@ -626,8 +626,8 @@ int main( int argc , char* argv[] ) bool *readFlags = new bool[ factory.plyReadNum() ]; std::vector< PlyProperty > unprocessedProperties; PLY::ReadVertexHeader( In.value , factory , readFlags , unprocessedProperties ); - if( !factory.template plyValidReadProperties<0>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain positions" ); - if( !factory.template plyValidReadProperties<1>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain normals" ); + if( !factory.template plyValidReadProperties<0>( readFlags ) ) MK_THROW( "Ply file does not contain positions" ); + if( !factory.template plyValidReadProperties<1>( readFlags ) ) MK_THROW( "Ply file does not contain normals" ); delete[] readFlags; if( unprocessedProperties.size() ) Execute< Real , Dim , FEMSig >( VertexFactory::DynamicFactory< Real >( unprocessedProperties ) ); @@ -649,8 +649,8 @@ int main( int argc , char* argv[] ) bool *readFlags = new bool[ factory.plyReadNum() ]; std::vector< PlyProperty > unprocessedProperties; PLY::ReadVertexHeader( In.value , factory , readFlags , unprocessedProperties ); - if( !factory.template plyValidReadProperties<0>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain positions" ); - if( !factory.template plyValidReadProperties<1>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain normals" ); + if( !factory.template plyValidReadProperties<0>( readFlags ) ) MK_THROW( "Ply file does not contain positions" ); + if( !factory.template plyValidReadProperties<1>( readFlags ) ) MK_THROW( "Ply file does not contain normals" ); delete[] readFlags; if( unprocessedProperties.size() ) Execute< DEFAULT_DIMENSION , Real >( VertexFactory::DynamicFactory< Real >( unprocessedProperties ) ); diff --git a/Src/PoissonRecon.server.inl b/Src/PoissonRecon.server.inl index 1647a7b5..9e869611 100644 --- a/Src/PoissonRecon.server.inl +++ b/Src/PoissonRecon.server.inl @@ -570,7 +570,7 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase4( const ClientReconstruc if( clientReconInfo.outDir.length() ) outFileName = PointPartition::FileDir( clientReconInfo.outDir , outFileName ); FILE* fp = fopen( outFileName.c_str() , "wb" ); - if( !fp ) MK_ERROR_OUT( "Failed to open file for writing: " , outFileName ); + if( !fp ) MK_THROW( "Failed to open file for writing: " , outFileName ); FileStream fs(fp); FEMTree< Dim , Real >::WriteParameter( fs ); DenseNodeData< Real , Sigs >::WriteSignatures( fs ); @@ -630,7 +630,7 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase6( const ClientReconstruc int res1 = 0 , res2 = 0; Pointer( Real ) values1 = backSliceTree->template regularGridEvaluate< true >( backSolution , res1 , -1 , false ); Pointer( Real ) values2 = frontSliceTree->template regularGridEvaluate< true >( frontSolution , res2 , -1 , false ); - if( res1!=res2 ) MK_ERROR_OUT( "Different resolutions: " , res1 , " != " , res2 ); + if( res1!=res2 ) MK_THROW( "Different resolutions: " , res1 , " != " , res2 ); size_t count = 1; for( unsigned int d=0 ; d<(Dim-1) ; d++ ) count *= (unsigned int)res1; discontinuityCount += count; @@ -673,7 +673,7 @@ PhaseInfo Server< Real , Dim , BType , Degree >::_phase6( const ClientReconstruc auto WriteBoundary = [&]( std::string fileName , const FEMTree< Dim-1 , Real > *sliceTree , const DenseNodeData< Real , SliceSigs > &solution ) { FILE* fp = fopen( fileName.c_str() , "wb" ); - if( !fp ) MK_ERROR_OUT( "Failed to open file for writing: " , fileName ); + if( !fp ) MK_THROW( "Failed to open file for writing: " , fileName ); FileStream fs(fp); FEMTree< Dim-1 , Real >::WriteParameter( fs ); DenseNodeData< Real , SliceSigs >::WriteSignatures( fs ); diff --git a/Src/PoissonReconClient.cpp b/Src/PoissonReconClient.cpp index de094658..7ad6c635 100644 --- a/Src/PoissonReconClient.cpp +++ b/Src/PoissonReconClient.cpp @@ -119,7 +119,7 @@ void Reconstruct( unsigned int degree , std::vector< Socket > &serverSockets ) { case 1: return Reconstruct< Real , Dim , BType , 1 >( serverSockets ); case 2: return Reconstruct< Real , Dim , BType , 2 >( serverSockets ); - default: MK_ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); + default: MK_THROW( "Only B-Splines of degree 1 - 2 are supported" ); } } @@ -131,7 +131,7 @@ void Reconstruct( BoundaryType bType , unsigned int degree , std::vector< Socket case BOUNDARY_FREE: return Reconstruct< Real , Dim , BOUNDARY_FREE >( degree , serverSockets ); case BOUNDARY_NEUMANN: return Reconstruct< Real , Dim , BOUNDARY_NEUMANN >( degree , serverSockets ); case BOUNDARY_DIRICHLET: return Reconstruct< Real , Dim , BOUNDARY_DIRICHLET >( degree , serverSockets ); - default: MK_ERROR_OUT( "Not a valid boundary type: " , bType ); + default: MK_THROW( "Not a valid boundary type: " , bType ); } } @@ -142,8 +142,8 @@ void Reconstruct( std::vector< Socket > &serverSockets ) unsigned int degree; for( unsigned int i=0 ; i( bType , degree , serverSockets ); } diff --git a/Src/PoissonReconClientServer.inl b/Src/PoissonReconClientServer.inl index efdf3ea9..c22e7ee7 100644 --- a/Src/PoissonReconClientServer.inl +++ b/Src/PoissonReconClientServer.inl @@ -249,7 +249,7 @@ struct ClientServerStream : BinaryStream tries++; } _fs.open( _fileName , std::ios::in | std::ios::binary ); - if( !_fs.is_open() ) MK_ERROR_OUT( "Failed to open file for reading: " , _fileName ); + if( !_fs.is_open() ) MK_THROW( "Failed to open file for reading: " , _fileName ); } else { @@ -266,10 +266,10 @@ struct ClientServerStream : BinaryStream std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) ); tries++; } - if( !validFile( _fileName ) ) MK_ERROR_OUT( "File exists: " , _fileName , " , " , tries , " / " , maxTries ); + if( !validFile( _fileName ) ) MK_THROW( "File exists: " , _fileName , " , " , tries , " / " , maxTries ); _fs.open( _fileName , std::ios::out | std::ios::binary ); - if( !_fs.is_open() ) MK_ERROR_OUT( "Failed to open file for writing: " , _fileName ); + if( !_fs.is_open() ) MK_THROW( "Failed to open file for writing: " , _fileName ); } } ~ClientServerStream( void ) @@ -345,36 +345,36 @@ ClientReconstructionInfo< Real , Dim >::ClientReconstructionInfo( BinaryStream & b = _b!=0; return true; }; - if( !stream.read( inDir ) ) MK_ERROR_OUT( "Failed to read in dir" ); - if( !stream.read( tempDir ) ) MK_ERROR_OUT( "Failed to read temp dir" ); - if( !stream.read( outDir ) ) MK_ERROR_OUT( "Failed to read out dir" ); - if( !stream.read( header ) ) MK_ERROR_OUT( "Failed to read header" ); - if( !stream.read( bufferSize ) ) MK_ERROR_OUT( "Failed to read buffer size" ); - if( !stream.read( filesPerDir ) ) MK_ERROR_OUT( "Failed to read files per dir" ); - if( !stream.read( reconstructionDepth ) ) MK_ERROR_OUT( "Failed to read reconstruction depth" ); - if( !stream.read( sharedDepth ) ) MK_ERROR_OUT( "Failed to read shared depth" ); - if( !stream.read( distributionDepth ) ) MK_ERROR_OUT( "Failed to read distribution depth" ); - if( !stream.read( baseDepth ) ) MK_ERROR_OUT( "Failed to read base depth" ); - if( !stream.read( kernelDepth ) ) MK_ERROR_OUT( "Failed to read kernel depth" ); - if( !stream.read( solveDepth ) ) MK_ERROR_OUT( "Failed to read solveDepth depth" ); - if( !stream.read( iters ) ) MK_ERROR_OUT( "Failed to read iters" ); - if( !stream.read( cgSolverAccuracy ) ) MK_ERROR_OUT( "Failed to read CG-solver-accuracy" ); - if( !stream.read( targetValue ) ) MK_ERROR_OUT( "Failed to read target-value" ); - if( !stream.read( pointWeight ) ) MK_ERROR_OUT( "Failed to read point-weight" ); - if( !stream.read( samplesPerNode ) ) MK_ERROR_OUT( "Failed to read samples-per-node" ); - if( !stream.read( dataX ) ) MK_ERROR_OUT( "Failed to read data-multiplier" ); - if( !stream.read( padSize ) ) MK_ERROR_OUT( "Failed to read padSize" ); - if( !stream.read( verbose ) ) MK_ERROR_OUT( "Failed to read verbose" ); - if( !stream.read( mergeType ) ) MK_ERROR_OUT( "Failed to read merge-type" ); - if( !ReadBool( density ) ) MK_ERROR_OUT( "Failed to read density flag" ); - if( !ReadBool( linearFit ) ) MK_ERROR_OUT( "Failed to read linear-fit flag" ); - if( !ReadBool( outputSolution ) ) MK_ERROR_OUT( "Failed to read output-solution flag" ); - if( !ReadBool( gridCoordinates ) ) MK_ERROR_OUT( "Failed to read grid-coordinates flag" ); - if( !ReadBool( ouputVoxelGrid ) ) MK_ERROR_OUT( "Failed to read output-voxel-grid flag" ); - if( !ReadBool( confidence ) ) MK_ERROR_OUT( "Failed to read confidence flag" ); + if( !stream.read( inDir ) ) MK_THROW( "Failed to read in dir" ); + if( !stream.read( tempDir ) ) MK_THROW( "Failed to read temp dir" ); + if( !stream.read( outDir ) ) MK_THROW( "Failed to read out dir" ); + if( !stream.read( header ) ) MK_THROW( "Failed to read header" ); + if( !stream.read( bufferSize ) ) MK_THROW( "Failed to read buffer size" ); + if( !stream.read( filesPerDir ) ) MK_THROW( "Failed to read files per dir" ); + if( !stream.read( reconstructionDepth ) ) MK_THROW( "Failed to read reconstruction depth" ); + if( !stream.read( sharedDepth ) ) MK_THROW( "Failed to read shared depth" ); + if( !stream.read( distributionDepth ) ) MK_THROW( "Failed to read distribution depth" ); + if( !stream.read( baseDepth ) ) MK_THROW( "Failed to read base depth" ); + if( !stream.read( kernelDepth ) ) MK_THROW( "Failed to read kernel depth" ); + if( !stream.read( solveDepth ) ) MK_THROW( "Failed to read solveDepth depth" ); + if( !stream.read( iters ) ) MK_THROW( "Failed to read iters" ); + if( !stream.read( cgSolverAccuracy ) ) MK_THROW( "Failed to read CG-solver-accuracy" ); + if( !stream.read( targetValue ) ) MK_THROW( "Failed to read target-value" ); + if( !stream.read( pointWeight ) ) MK_THROW( "Failed to read point-weight" ); + if( !stream.read( samplesPerNode ) ) MK_THROW( "Failed to read samples-per-node" ); + if( !stream.read( dataX ) ) MK_THROW( "Failed to read data-multiplier" ); + if( !stream.read( padSize ) ) MK_THROW( "Failed to read padSize" ); + if( !stream.read( verbose ) ) MK_THROW( "Failed to read verbose" ); + if( !stream.read( mergeType ) ) MK_THROW( "Failed to read merge-type" ); + if( !ReadBool( density ) ) MK_THROW( "Failed to read density flag" ); + if( !ReadBool( linearFit ) ) MK_THROW( "Failed to read linear-fit flag" ); + if( !ReadBool( outputSolution ) ) MK_THROW( "Failed to read output-solution flag" ); + if( !ReadBool( gridCoordinates ) ) MK_THROW( "Failed to read grid-coordinates flag" ); + if( !ReadBool( ouputVoxelGrid ) ) MK_THROW( "Failed to read output-voxel-grid flag" ); + if( !ReadBool( confidence ) ) MK_THROW( "Failed to read confidence flag" ); { size_t sz; - if( !stream.read( sz ) ) MK_ERROR_OUT( "Failed to read number of auxiliary properties" ); + if( !stream.read( sz ) ) MK_THROW( "Failed to read number of auxiliary properties" ); auxProperties.resize(sz); for( size_t i=0 ; i::sharedFile( unsigned int idx case BACK: sStream << PointPartition::FileDir( tempDir , header ) << "." << idx << ".back.shared" ; break; case CENTER: sStream << PointPartition::FileDir( tempDir , header ) << "." << idx << ".shared" ; break; case FRONT: sStream << PointPartition::FileDir( tempDir , header ) << "." << idx << ".front.shared" ; break; - default: MK_ERROR_OUT( "Unrecognized share type: " , shareType ); + default: MK_THROW( "Unrecognized share type: " , shareType ); } return sStream.str(); } diff --git a/Src/PoissonReconServer.cpp b/Src/PoissonReconServer.cpp index 0da5fd29..cbb358ea 100644 --- a/Src/PoissonReconServer.cpp +++ b/Src/PoissonReconServer.cpp @@ -280,7 +280,7 @@ std::vector< unsigned int > Reconstruct( unsigned int degree , const PointPartit { case 1: return Reconstruct< Real , Dim , BType , 1 >( pointSetInfo , partition , clientSockets , clientReconInfo ); case 2: return Reconstruct< Real , Dim , BType , 2 >( pointSetInfo , partition , clientSockets , clientReconInfo ); - default: MK_ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); + default: MK_THROW( "Only B-Splines of degree 1 - 2 are supported" ); } return std::vector< unsigned int >(); } @@ -298,7 +298,7 @@ std::vector< unsigned int > Reconstruct( BoundaryType bType , unsigned int degre case BOUNDARY_FREE: return Reconstruct< Real , Dim , BOUNDARY_FREE >( degree , pointSetInfo , partition , clientSockets , clientReconInfo ); case BOUNDARY_NEUMANN: return Reconstruct< Real , Dim , BOUNDARY_NEUMANN >( degree , pointSetInfo , partition , clientSockets , clientReconInfo ); case BOUNDARY_DIRICHLET: return Reconstruct< Real , Dim , BOUNDARY_DIRICHLET >( degree , pointSetInfo , partition , clientSockets , clientReconInfo ); - default: MK_ERROR_OUT( "Not a valid boundary type: " , bType ); + default: MK_THROW( "Not a valid boundary type: " , bType ); } return std::vector< unsigned int >(); } @@ -387,7 +387,7 @@ int main( int argc , char* argv[] ) ShowUsage( argv[0] ); return 0; } - if( PadSize.value<0 ) MK_ERROR_OUT( "Padding size cannot be negative" ); + if( PadSize.value<0 ) MK_THROW( "Padding size cannot be negative" ); if( Verbose.value>1 ) { @@ -426,7 +426,7 @@ int main( int argc , char* argv[] ) // Create a listening SOCKET for connecting to server AcceptorSocket listenSocket = GetListenSocket( port ); - if( listenSocket == _INVALID_ACCEPTOR_SOCKET_ ) MK_ERROR_OUT( "Could not create listener socket" ); + if( listenSocket == _INVALID_ACCEPTOR_SOCKET_ ) MK_THROW( "Could not create listener socket" ); std::cout << "Server Address: " << address << ":" << port << std::endl; { std::stringstream ss; @@ -511,15 +511,15 @@ int main( int argc , char* argv[] ) clientReconInfo.reconstructionDepth = Depth.value; clientReconInfo.sharedDepth = 0; while( ((size_t)1<clientReconInfo.reconstructionDepth ) MK_ERROR_OUT( "Slab depth cannot exceed reconstruction depth: " , clientReconInfo.sharedDepth , " <= " , clientReconInfo.reconstructionDepth ); + if( clientReconInfo.sharedDepth>clientReconInfo.reconstructionDepth ) MK_THROW( "Slab depth cannot exceed reconstruction depth: " , clientReconInfo.sharedDepth , " <= " , clientReconInfo.reconstructionDepth ); if( clientReconInfo.baseDepth>clientReconInfo.sharedDepth ) { - if( BaseDepth.set ) MK_ERROR_OUT( "Base depth cannot exceed shared depth: " , clientReconInfo.baseDepth , " <=" , clientReconInfo.sharedDepth ); + if( BaseDepth.set ) MK_THROW( "Base depth cannot exceed shared depth: " , clientReconInfo.baseDepth , " <=" , clientReconInfo.sharedDepth ); else clientReconInfo.baseDepth = clientReconInfo.sharedDepth; } if( !KernelDepth.set ) KernelDepth.value = clientReconInfo.reconstructionDepth-2; diff --git a/Src/Polynomial.inl b/Src/Polynomial.inl index f6842be1..4b15f88c 100644 --- a/Src/Polynomial.inl +++ b/Src/Polynomial.inl @@ -296,7 +296,7 @@ inline int Polynomial< 4 >::getSolutions( double c , double* roots , double EPS template< int Degree > int Polynomial::getSolutions( double c , double* roots , double EPS ) const { - MK_ERROR_OUT( "Can't solve polynomial of degree: " , Degree ); + MK_THROW( "Can't solve polynomial of degree: " , Degree ); return 0; } diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 84f4a3a1..20695971 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -46,7 +46,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "18.72" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "18.73" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth diff --git a/Src/Rasterizer.inl b/Src/Rasterizer.inl index 18fb11d6..5c3b2441 100644 --- a/Src/Rasterizer.inl +++ b/Src/Rasterizer.inl @@ -56,7 +56,7 @@ Rasterizer< Real , Dim >::_RegularGridIndex::_RegularGridIndex( unsigned int max for( int k=1 ; k<=K && !done ; k++ ) if( _RegularGridIndex( depth , simplex[k] )!=idx ) done = true; if( done ) break; } - if( depth==0 ) MK_ERROR_OUT( "Simplex is not in unit cube: " , simplex ); + if( depth==0 ) MK_THROW( "Simplex is not in unit cube: " , simplex ); else *this = _RegularGridIndex( depth-1 , simplex[0] ); } @@ -166,7 +166,7 @@ typename Rasterizer< Real , Dim >::template SimplexRasterizationGrid< IndexType if( threadSafety.type==ThreadSafety::MUTEXES ) { - if( threadSafety.lockDepth>depth ) MK_ERROR_OUT( "Lock depth cannot excceed depth: " , threadSafety.lockDepth , " <= " , depth ); + if( threadSafety.lockDepth>depth ) MK_THROW( "Lock depth cannot excceed depth: " , threadSafety.lockDepth , " <= " , depth ); _RegularGridMutexes mutexes( threadSafety.lockDepth , depth ); ThreadPool::ParallelFor( 0 , simplicialComplex.size() , [&]( unsigned int t , size_t i ) @@ -269,6 +269,6 @@ typename Rasterizer< Real , Dim >::template SimplexRasterizationGrid< IndexType for( int t=0 ; tfp = std::tmpfile(); _closeFile = true; - if( !this->fp ) MK_ERROR_OUT( "Failed to open temporary file" ); + if( !this->fp ) MK_THROW( "Failed to open temporary file" ); } } ~FileDescription( void ){ if( _closeFile ) fclose(fp); } diff --git a/Src/RegularGrid.inl b/Src/RegularGrid.inl index 230ee33d..0960a71e 100644 --- a/Src/RegularGrid.inl +++ b/Src/RegularGrid.inl @@ -120,7 +120,7 @@ template< typename Real > void RegularGrid< DataType , Dim >::Write( std::string fileName , const unsigned int res[Dim] , ConstPointer( DataType ) values , XForm< Real , Dim+1 > gridToModel ) { FILE *fp = fopen( fileName.c_str() , "wb" ); - if( !fp ) MK_ERROR_OUT( "Failed to open grid file for writing: " , fileName ); + if( !fp ) MK_THROW( "Failed to open grid file for writing: " , fileName ); else { // Write the magic number @@ -164,25 +164,25 @@ template< typename Real > void RegularGrid< DataType , Dim >::Read( std::string fileName , unsigned int res[Dim] , Pointer( DataType ) &values , XForm< Real , Dim+1 > &gridToModel ) { FILE *fp = fopen( fileName.c_str() , "rb" ); - if( !fp ) MK_ERROR_OUT( "Failed to open grid file for reading: " , fileName ); + if( !fp ) MK_THROW( "Failed to open grid file for reading: " , fileName ); else { // Read the magic number { int dim; - if( fscanf( fp , " G%d " , &dim )!=1 ) MK_ERROR_OUT( "Failed to read magic number: " , fileName ); - if( dim!=Dim ) MK_ERROR_OUT( "Dimensions don't match: " , Dim , " != " , dim ); + if( fscanf( fp , " G%d " , &dim )!=1 ) MK_THROW( "Failed to read magic number: " , fileName ); + if( dim!=Dim ) MK_THROW( "Dimensions don't match: " , Dim , " != " , dim ); } // Read the data type - if( !RegularGridDataType< DataType >::Read( fp ) ) MK_ERROR_OUT( "Failed to read type" ); + if( !RegularGridDataType< DataType >::Read( fp ) ) MK_THROW( "Failed to read type" ); // Read the dimensions { int r; for( int d=0 ; d::Read( std::string fileName , unsigned int re float x; for( int j=0 ; j::Read( std::string fileName , unsigned int re // Read through the end of the line { char line[1024]; - if( !fgets( line , sizeof(line)/sizeof(char) , fp ) ) MK_ERROR_OUT( "Could not read end of line" ); + if( !fgets( line , sizeof(line)/sizeof(char) , fp ) ) MK_THROW( "Could not read end of line" ); } values = NewPointer< DataType >( _Resolution(res) ); diff --git a/Src/RegularTree.inl b/Src/RegularTree.inl index f5713426..0974dd04 100644 --- a/Src/RegularTree.inl +++ b/Src/RegularTree.inl @@ -123,7 +123,7 @@ bool RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::_initChildren( Allo if( children ) delete[] children; children = new RegularTreeNode[ 1<::_initChildren_s( Al // Allocate the children if( nodeAllocator ) _children = PointerAddress( nodeAllocator->newElements( 1<::read( BinaryStream { node->children = NULL; node->initChildren< false >( nodeAllocator , initializer ); - if( !stream.read( GetPointer( node->children , 1<children , 1<children[i].parent = node; @@ -554,7 +554,7 @@ bool RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::read( BinaryStream } } }; - if( !stream.read( *this ) ) MK_ERROR_OUT( "Failed to read root" ); + if( !stream.read( *this ) ) MK_THROW( "Failed to read root" ); ReadChildren( this ); return true; } diff --git a/Src/SSDRecon.cpp b/Src/SSDRecon.cpp index 3facf0ff..1c749a82 100644 --- a/Src/SSDRecon.cpp +++ b/Src/SSDRecon.cpp @@ -358,7 +358,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) for( int i=0 ; i::WriteParameter( fs ); DenseNodeData< Real , Sigs >::WriteSignatures( fs ); @@ -542,7 +542,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) case 2: return Execute< Real , Dim , FEMDegreeAndBType< 2 , BType >::Signature >( auxDataFactory ); case 3: return Execute< Real , Dim , FEMDegreeAndBType< 3 , BType >::Signature >( auxDataFactory ); // case 4: return Execute< Real , Dim , FEMDegreeAndBType< 4 , BType >::Signature >( auxDataFactory ); - default: MK_ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); + default: MK_THROW( "Only B-Splines of degree 1 - 2 are supported" ); } } @@ -554,7 +554,7 @@ void Execute( const AuxDataFactory &auxDataFactory ) case BOUNDARY_FREE+1: return Execute< Dim , Real , BOUNDARY_FREE >( auxDataFactory ); case BOUNDARY_NEUMANN+1: return Execute< Dim , Real , BOUNDARY_NEUMANN >( auxDataFactory ); case BOUNDARY_DIRICHLET+1: return Execute< Dim , Real , BOUNDARY_DIRICHLET >( auxDataFactory ); - default: MK_ERROR_OUT( "Not a valid boundary type: " , BType.value ); + default: MK_THROW( "Not a valid boundary type: " , BType.value ); } } #endif // !FAST_COMPILE @@ -577,8 +577,8 @@ int main( int argc , char* argv[] ) ShowUsage( argv[0] ); return 0; } - if( GradientWeight.value<=0 ) MK_ERROR_OUT( "Gradient weight must be positive: " , GradientWeight.value , "> 0" ); - if( BiLapWeight.value<=0 ) MK_ERROR_OUT( "Bi-Laplacian weight must be positive: " , BiLapWeight.value , " > 0" ); + if( GradientWeight.value<=0 ) MK_THROW( "Gradient weight must be positive: " , GradientWeight.value , "> 0" ); + if( BiLapWeight.value<=0 ) MK_THROW( "Bi-Laplacian weight must be positive: " , BiLapWeight.value , " > 0" ); ValueWeight.value *= (float)Reconstructor::SSD::WeightMultipliers[0]; GradientWeight.value *= (float)Reconstructor::SSD::WeightMultipliers[1]; @@ -605,8 +605,8 @@ int main( int argc , char* argv[] ) bool *readFlags = new bool[ factory.plyReadNum() ]; std::vector< PlyProperty > unprocessedProperties; PLY::ReadVertexHeader( In.value , factory , readFlags , unprocessedProperties ); - if( !factory.template plyValidReadProperties<0>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain positions" ); - if( !factory.template plyValidReadProperties<1>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain normals" ); + if( !factory.template plyValidReadProperties<0>( readFlags ) ) MK_THROW( "Ply file does not contain positions" ); + if( !factory.template plyValidReadProperties<1>( readFlags ) ) MK_THROW( "Ply file does not contain normals" ); delete[] readFlags; if( unprocessedProperties.size() ) Execute< Real , Dim , FEMSig >( VertexFactory::DynamicFactory< Real >( unprocessedProperties ) ); @@ -627,8 +627,8 @@ int main( int argc , char* argv[] ) bool *readFlags = new bool[ factory.plyReadNum() ]; std::vector< PlyProperty > unprocessedProperties; PLY::ReadVertexHeader( In.value , factory , readFlags , unprocessedProperties ); - if( !factory.template plyValidReadProperties<0>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain positions" ); - if( !factory.template plyValidReadProperties<1>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain normals" ); + if( !factory.template plyValidReadProperties<0>( readFlags ) ) MK_THROW( "Ply file does not contain positions" ); + if( !factory.template plyValidReadProperties<1>( readFlags ) ) MK_THROW( "Ply file does not contain normals" ); delete[] readFlags; if( unprocessedProperties.size() ) Execute< DEFAULT_DIMENSION , Real >( VertexFactory::DynamicFactory< Real >( unprocessedProperties ) ); diff --git a/Src/ScaleNormals.cpp b/Src/ScaleNormals.cpp index 8ad6f35a..20d8417d 100644 --- a/Src/ScaleNormals.cpp +++ b/Src/ScaleNormals.cpp @@ -124,9 +124,9 @@ void Execute( void ) std::vector< PlyProperty > unprocessedProperties; PLY::ReadVertexHeader( In.value , factory , readFlags , unprocessedProperties ); - if( !factory.template plyValidReadProperties<0>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain positions" ); - if( !factory.template plyValidReadProperties<1>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain normals" ); - if( !factory.template plyValidReadProperties<2>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain scales" ); + if( !factory.template plyValidReadProperties<0>( readFlags ) ) MK_THROW( "Ply file does not contain positions" ); + if( !factory.template plyValidReadProperties<1>( readFlags ) ) MK_THROW( "Ply file does not contain normals" ); + if( !factory.template plyValidReadProperties<2>( readFlags ) ) MK_THROW( "Ply file does not contain scales" ); delete[] readFlags; if( Verbose.set && unprocessedProperties.size() ) @@ -157,7 +157,7 @@ int main( int argc , char* argv[] ) } if( ConfidenceNames.count!=ConfidenceExponents.count ) - MK_ERROR_OUT( "Number of confidence names and exponents does not match: " , ConfidenceNames.count , " != " , ConfidenceExponents.count ); + MK_THROW( "Number of confidence names and exponents does not match: " , ConfidenceNames.count , " != " , ConfidenceExponents.count ); if( Verbose.set ) { diff --git a/Src/Socket.h b/Src/Socket.h index 7a20270b..5fa72f9a 100644 --- a/Src/Socket.h +++ b/Src/Socket.h @@ -59,7 +59,7 @@ namespace PoissonRecon { boost::system::error_code ec; int ret = (int)( boost::asio::read( *s , boost::asio::buffer( destination , len ) , ec ) ); - if( ec ) MK_ERROR_OUT( "Failed to read from socket" ); + if( ec ) MK_THROW( "Failed to read from socket" ); return ret; } @@ -67,7 +67,7 @@ namespace PoissonRecon { boost::system::error_code ec; int ret = (int)( boost::asio::write( *s , boost::asio::buffer( source , len ) , ec ) ); - if( ec ) MK_ERROR_OUT( "Failed to write to socket" ); + if( ec ) MK_THROW( "Failed to write to socket" ); return ret; } @@ -91,14 +91,14 @@ namespace PoissonRecon int socket_receive( Socket& s , Array< C > destination , size_t len ) { if( len>destination.maximum()*sizeof( C ) ) - MK_ERROR_OUT( "Size of socket_receive exceeds destination maximum: " , len , " > " , destination.maximum()*sizeof( C ) ); + MK_THROW( "Size of socket_receive exceeds destination maximum: " , len , " > " , destination.maximum()*sizeof( C ) ); return socket_receive( s , (char*)&destination[0] , len ); } template< class C > int socket_send( Socket s , ConstArray< C > source , size_t len ) { if( len>source.maximum()*sizeof( C ) ) - MK_ERROR_OUT( "Size of socket_send exceeds source maximum: " , len , " > " , source.maximum()*sizeof( C ) ); + MK_THROW( "Size of socket_send exceeds source maximum: " , len , " > " , source.maximum()*sizeof( C ) ); return socket_send( s , (char*)&source[0] , len ); } #endif // ARRAY_DEBUG diff --git a/Src/Socket.inl b/Src/Socket.inl index b064fb92..a50d2b34 100644 --- a/Src/Socket.inl +++ b/Src/Socket.inl @@ -30,7 +30,7 @@ template bool ReceiveOnSocket( Socket& s , Pointer( C ) data , size_t dataSize ) { #ifdef ARRAY_DEBUG - if( dataSize>data.maximum()*sizeof( C ) ) MK_ERROR_OUT( "Size of socket read exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); + if( dataSize>data.maximum()*sizeof( C ) ) MK_THROW( "Size of socket read exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); #endif // ARRAY_DEBUG unsigned long long rec=0; while( rec!=dataSize ) @@ -38,8 +38,8 @@ bool ReceiveOnSocket( Socket& s , Pointer( C ) data , size_t dataSize ) int tmp = socket_receive( s , ( ( Pointer( char ) ) data) + rec , dataSize-rec ); if( tmp<=0 ) { - if( !tmp ) MK_ERROR_OUT( "Connection Closed" ); - else MK_ERROR_OUT( "socket_receive from client failed: " , LastSocketError() ); + if( !tmp ) MK_THROW( "Connection Closed" ); + else MK_THROW( "socket_receive from client failed: " , LastSocketError() ); return false; } rec+=tmp; @@ -51,11 +51,11 @@ template bool SendOnSocket( Socket& s , ConstPointer( C ) data , size_t dataSize ) { #ifdef ARRAY_DEBUG - if( dataSize>data.maximum()*sizeof( C ) ) MK_ERROR_OUT( "Size of socket write exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); + if( dataSize>data.maximum()*sizeof( C ) ) MK_THROW( "Size of socket write exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); #endif // ARRAY_DEBUG if( socket_send( s , ( ConstPointer( char ) )data , dataSize )<0 ) { - MK_ERROR_OUT( "socket_send to client failed (" , s , "): " , LastSocketError() ); + MK_THROW( "socket_send to client failed (" , s , "): " , LastSocketError() ); return false; } return true; @@ -68,7 +68,7 @@ template void ReceiveOnSocket( Socket& s , Pointer( C ) data , size_t dataSize , const char* errorMessage , ... ) { #ifdef ARRAY_DEBUG - if( dataSize>data.maximum()*sizeof( C ) ) MK_ERROR_OUT( "Size of socket read exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); + if( dataSize>data.maximum()*sizeof( C ) ) MK_THROW( "Size of socket read exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); #endif // ARRAY_DEBUG unsigned long long rec=0; while( rec!=dataSize ) @@ -76,8 +76,8 @@ void ReceiveOnSocket( Socket& s , Pointer( C ) data , size_t dataSize , const ch int tmp = socket_receive( s , ( ( Pointer( char ) ) data) + rec , dataSize-rec ); if( tmp<=0 ) { - if( !tmp ) MK_ERROR_OUT( "Connection Closed" ); - else MK_ERROR_OUT( "socket_receive from client failed: " , LastSocketError() ); + if( !tmp ) MK_THROW( "Connection Closed" ); + else MK_THROW( "socket_receive from client failed: " , LastSocketError() ); { fprintf( stderr , "\t" ); va_list args; @@ -96,20 +96,20 @@ template void SendOnSocket( Socket& s , ConstPointer( C ) data , size_t dataSize , const char* errorMessage , ... ) { #ifdef ARRAY_DEBUG - if( dataSize>data.maximum()*sizeof( C ) ) MK_ERROR_OUT( "Size of socket write exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); + if( dataSize>data.maximum()*sizeof( C ) ) MK_THROW( "Size of socket write exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); #endif // ARRAY_DEBUG if( socket_send( s , ( ConstPointer( char ) )data , dataSize )<0 ) - MK_ERROR_OUT( "socket_send to client failed: " , LastSocketError() ); + MK_THROW( "socket_send to client failed: " , LastSocketError() ); } template void SendOnSocket( Socket& s , Pointer( C ) data , size_t dataSize , const char* errorMessage , ... ) { #ifdef ARRAY_DEBUG - if( dataSize>data.maximum()*sizeof( C ) ) MK_ERROR_OUT( "Size of socket write exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); + if( dataSize>data.maximum()*sizeof( C ) ) MK_THROW( "Size of socket write exceeds source maximum: " , dataSize , " > " , data.maximum()*sizeof( C ) ); #endif // ARRAY_DEBUG if( socket_send( s , ( ConstPointer( char ) )data , dataSize )<0 ) - MK_ERROR_OUT( "socket_send to client failed: " , LastSocketError() ); + MK_THROW( "socket_send to client failed: " , LastSocketError() ); } inline bool GetHostEndpointAddress( EndpointAddress* address , const char* prefix ) diff --git a/Src/SparseMatrix.inl b/Src/SparseMatrix.inl index 136ac15c..2a348a8e 100644 --- a/Src/SparseMatrix.inl +++ b/Src/SparseMatrix.inl @@ -166,7 +166,7 @@ void SparseMatrix< T , IndexType , 0 >::setRowSize( size_t row , size_t count ) } rowSizes[row] = count; } - else MK_ERROR_OUT( "Row is out of bounds: 0 <= " , row , " < " , rowNum ); + else MK_THROW( "Row is out of bounds: 0 <= " , row , " < " , rowNum ); } template< class T , class IndexType > void SparseMatrix< T , IndexType , 0 >::resetRowSize( size_t row , size_t count ) @@ -178,7 +178,7 @@ void SparseMatrix< T , IndexType , 0 >::resetRowSize( size_t row , size_t count if( count>oldCount ) memset( _entries[row]+oldCount , 0 , sizeof( MatrixEntry< T , IndexType > ) * ( count - oldCount ) ); rowSizes[row] = count; } - else MK_ERROR_OUT( "Row is out of bounds: 0 <= " , row , " < " , rowNum ); + else MK_THROW( "Row is out of bounds: 0 <= " , row , " < " , rowNum ); } template< class T , class IndexType > @@ -235,7 +235,7 @@ SparseMatrix< T , IndexType , 0 > SparseMatrix< T , IndexType , 0 >::operator * size_t bCols = 0 , bRows = B.rowNum; for( size_t i=0 ; i SparseMatrix< T , IndexType , 0 >::transpose( const SparseMatrix& At = *this; size_t _aRows = 0 , aCols = At.rowNum; for( size_t i=0 ; iaRows ) MK_ERROR_OUT( "Prescribed output dimension too low: " , aRows , " < " , _aRows ); + if( _aRows>aRows ) MK_THROW( "Prescribed output dimension too low: " , aRows , " < " , _aRows ); A.resize( aRows ); for( size_t i=0 ; i SparseMatrix< T , IndexType , 0 >::Multiply( c size_t bCols = 0 , bRows = B.rows(); for( size_t i=0 ; iN ) aCols = iter->N+1; for( size_t i=0 ; iN ) bCols = iter->N+1; - if( bRows SparseMatrix< T , IndexType , 0 >::Transpose( SparseMatrix< T , IndexType , 0 > A; size_t _aRows = 0 , aCols = At.rows() , aRows = outRows; for( size_t i=0 ; iN ) _aRows = iter->N+1; - if( _aRows>aRows ) MK_ERROR_OUT( "Prescribed output dimension too low: " , aRows , " < " , _aRows ); + if( _aRows>aRows ) MK_THROW( "Prescribed output dimension too low: " , aRows , " < " , _aRows ); A.resize( aRows ); for( size_t i=0 ; i::resize( size_t rowNum ) template< class T , class IndexType , size_t MaxRowSize > void SparseMatrix< T , IndexType , MaxRowSize >::setRowSize( size_t row , size_t rowSize ) { - if( row>=_rowNum ) MK_ERROR_OUT( "Row is out of bounds: 0 <= " , row , " < " , _rowNum ); - else if( rowSize>MaxRowSize ) MK_ERROR_OUT( "Row size larger than max row size: " , rowSize , " < " , MaxRowSize ); + if( row>=_rowNum ) MK_THROW( "Row is out of bounds: 0 <= " , row , " < " , _rowNum ); + else if( rowSize>MaxRowSize ) MK_THROW( "Row size larger than max row size: " , rowSize , " < " , MaxRowSize ); else _rowSizes[row] = rowSize; } template< class T , class IndexType , size_t MaxRowSize > void SparseMatrix< T , IndexType , MaxRowSize >::resetRowSize( size_t row , size_t rowSize ) { - if( row>=_rowNum ) MK_ERROR_OUT( "Row is out of bounds: 0 <= " , row , " < " , _rowNum ); - else if( rowSize>MaxRowSize ) MK_ERROR_OUT( "Row size larger than max row size: " , rowSize , " < " , MaxRowSize ); + if( row>=_rowNum ) MK_THROW( "Row is out of bounds: 0 <= " , row , " < " , _rowNum ); + else if( rowSize>MaxRowSize ) MK_THROW( "Row size larger than max row size: " , rowSize , " < " , MaxRowSize ); else _rowSizes[row] = rowSize; } diff --git a/Src/SurfaceTrimmer.cpp b/Src/SurfaceTrimmer.cpp index 0dc04e5c..e9f67e5d 100644 --- a/Src/SurfaceTrimmer.cpp +++ b/Src/SurfaceTrimmer.cpp @@ -101,7 +101,7 @@ struct ComponentGraph nodes.pop_back(); }; - if( !neighbors.size() ) MK_ERROR_OUT( "No neighbors" ); + if( !neighbors.size() ) MK_THROW( "No neighbors" ); // Remove the node from the neighbors of the neighbors for( unsigned int i=0 ; ineighbors.size()-1 ; j>=0 ; j-- ) if( neighbors[i]->neighbors[j]==this ) @@ -148,10 +148,10 @@ struct ComponentGraph for( auto iter=flags.begin() ; iter!=flags.end() ; iter++ ) for( unsigned int j=0 ; jfirst->neighbors.size() ; j++ ) { - if( iter->second==flags[ iter->first->neighbors[j] ] ) MK_ERROR_OUT( "Not a bipartite graph" ); + if( iter->second==flags[ iter->first->neighbors[j] ] ) MK_THROW( "Not a bipartite graph" ); bool foundSelf = false; for( unsigned int k=0 ; kfirst->neighbors[j]->neighbors.size() ; k++ ) if( iter->first->neighbors[j]->neighbors[k]==iter->first ) foundSelf = true; - if( !foundSelf ) MK_ERROR_OUT( "Asymmetric graph" ); + if( !foundSelf ) MK_THROW( "Asymmetric graph" ); } } @@ -584,8 +584,8 @@ int main( int argc , char* argv[] ) if( !Long.set ) MK_WARN( "Number of vertices not supported by 32-bit indexing. Switching to 64-bit indexing" ); Long.set = true; } - if( !factory.template plyValidReadProperties<0>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain positions" ); - if( !factory.template plyValidReadProperties<1>( readFlags ) ) MK_ERROR_OUT( "Ply file does not contain values" ); + if( !factory.template plyValidReadProperties<0>( readFlags ) ) MK_THROW( "Ply file does not contain positions" ); + if( !factory.template plyValidReadProperties<1>( readFlags ) ) MK_THROW( "Ply file does not contain values" ); delete[] readFlags; if( Long.set ) return Execute< Real , Dim , long long >( VertexFactory::DynamicFactory< Real >( unprocessedProperties ) ); diff --git a/Src/VertexFactory.h b/Src/VertexFactory.h index aea015e5..2d80c555 100644 --- a/Src/VertexFactory.h +++ b/Src/VertexFactory.h @@ -128,8 +128,8 @@ namespace PoissonRecon unsigned int plyReadNum( void ) const { return 0; } unsigned int plyWriteNum( void ) const { return 0; } bool plyValidReadProperties( const bool *flags ) const { return true ; } - PlyProperty plyReadProperty( unsigned int idx ) const { if( idx>= plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ) ; return PlyProperty(); } - PlyProperty plyWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ) ; return PlyProperty(); } + PlyProperty plyReadProperty( unsigned int idx ) const { if( idx>= plyReadNum() ) MK_THROW( "read property out of bounds" ) ; return PlyProperty(); } + PlyProperty plyWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) MK_THROW( "write property out of bounds" ) ; return PlyProperty(); } bool readASCII( FILE *fp , VertexType &dt ) const { return true; } bool readBinary( FILE *fp , VertexType &dt ) const { return true; } void writeASCII( FILE *fp , const VertexType &dt ) const {} @@ -137,8 +137,8 @@ namespace PoissonRecon static constexpr bool IsStaticallyAllocated( void ){ return true; } - PlyProperty plyStaticReadProperty( unsigned int idx ) const { if( idx>= plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ) ; return PlyProperty(); } - PlyProperty plyStaticWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ) ; return PlyProperty(); } + PlyProperty plyStaticReadProperty( unsigned int idx ) const { if( idx>= plyReadNum() ) MK_THROW( "read property out of bounds" ) ; return PlyProperty(); } + PlyProperty plyStaticWriteProperty( unsigned int idx ) const { if( idx>=plyWriteNum() ) MK_THROW( "write property out of bounds" ) ; return PlyProperty(); } size_t bufferSize( void ) const { return 0; } void toBuffer( const VertexType &dt , Pointer( char ) buffer ) const {} @@ -491,8 +491,8 @@ namespace PoissonRecon static constexpr bool IsStaticallyAllocated( void ){ return false; } - PlyProperty plyStaticReadProperty( unsigned int idx ) const { MK_ERROR_OUT( "does not support static allocation" ) ; return PlyProperty(); } - PlyProperty plyStaticWriteProperty( unsigned int idx ) const { MK_ERROR_OUT( "does not support static allocation" ) ; return PlyProperty(); } + PlyProperty plyStaticReadProperty( unsigned int idx ) const { MK_THROW( "does not support static allocation" ) ; return PlyProperty(); } + PlyProperty plyStaticWriteProperty( unsigned int idx ) const { MK_THROW( "does not support static allocation" ) ; return PlyProperty(); } size_t size( void ) const { return _namesAndTypesOnDisk.size(); } @@ -584,8 +584,8 @@ namespace PoissonRecon template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , bool >::type _plyValidReadProperties( const bool *flags ) const { return true; } template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , PlyProperty >::type _plyReadProperty( unsigned int idx , size_t offset ) const; template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , PlyProperty >::type _plyWriteProperty( unsigned int idx , size_t offset ) const; - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyReadProperty( unsigned int idx , size_t offset ) const { MK_ERROR_OUT( "read property out of bounds" ) ; return PlyProperty(); } - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyWriteProperty( unsigned int idx , size_t offset ) const { MK_ERROR_OUT( "write property out of bounds" ) ; return PlyProperty(); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyReadProperty( unsigned int idx , size_t offset ) const { MK_THROW( "read property out of bounds" ) ; return PlyProperty(); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyWriteProperty( unsigned int idx , size_t offset ) const { MK_THROW( "write property out of bounds" ) ; return PlyProperty(); } template< unsigned int I > typename std::enable_if< I==0 , unsigned int >::type _readOffset( void ) const { return 0; } template< unsigned int I > typename std::enable_if< I!=0 , unsigned int >::type _readOffset( void ) const { return _readOffset< I-1 >() + get< I-1 >().plyReadNum(); } template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , bool >::type _readASCII( FILE *fp , VertexType &dt ) const { return this->template get().readASCII( fp , dt.template get() ) && _readASCII< I+1 >( fp , dt ); } @@ -605,8 +605,8 @@ namespace PoissonRecon template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , PlyProperty >::type _plyStaticReadProperty ( unsigned int idx ) const; template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , PlyProperty >::type _plyStaticWriteProperty( unsigned int idx ) const; - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyStaticReadProperty ( unsigned int idx ) const { MK_ERROR_OUT( "read property out of bounds" ) ; return PlyProperty(); } - template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyStaticWriteProperty( unsigned int idx ) const { MK_ERROR_OUT( "write property out of bounds" ) ; return PlyProperty(); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyStaticReadProperty ( unsigned int idx ) const { MK_THROW( "read property out of bounds" ) ; return PlyProperty(); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , PlyProperty >::type _plyStaticWriteProperty( unsigned int idx ) const { MK_THROW( "write property out of bounds" ) ; return PlyProperty(); } template< unsigned int I > typename std::enable_if< I!=sizeof...(Factories) , size_t >::type _bufferSize( void ) const { return this->template get().bufferSize() + _bufferSize< I+1 >(); } template< unsigned int I > typename std::enable_if< I==sizeof...(Factories) , size_t >::type _bufferSize( void ) const { return 0; } diff --git a/Src/VertexFactory.inl b/Src/VertexFactory.inl index 354f91ca..0e52b1f4 100644 --- a/Src/VertexFactory.inl +++ b/Src/VertexFactory.inl @@ -46,7 +46,7 @@ namespace VertexFactory case TypeOnDisk::UINT_32: return PLY::Type< uint32_t >(); case TypeOnDisk::INT_64: return PLY::Type< int64_t >(); case TypeOnDisk::UINT_64: return PLY::Type< uint64_t >(); - default: MK_ERROR_OUT( "Unrecognized type: " , typeOnDisk ); + default: MK_THROW( "Unrecognized type: " , typeOnDisk ); } return -1; } @@ -71,7 +71,7 @@ namespace VertexFactory case PLY_UINT_64: return TypeOnDisk::UINT_64; case PLY_FLOAT_32: return TypeOnDisk::FLOAT; case PLY_FLOAT_64: return TypeOnDisk::DOUBLE; - default: MK_ERROR_OUT( "Unrecognized type: " , plyType ); + default: MK_THROW( "Unrecognized type: " , plyType ); } return TypeOnDisk::UNKNOWN; } @@ -92,7 +92,7 @@ namespace VertexFactory else if constexpr( std::is_same< Type , uint64_t >::value ) return TypeOnDisk::UINT_64; else if constexpr( std::is_same< Type , float >::value ) return TypeOnDisk::FLOAT; else if constexpr( std::is_same< Type , double >::value ) return TypeOnDisk::DOUBLE; - else MK_ERROR_OUT( "Unrecognized type" ); + else MK_THROW( "Unrecognized type" ); return TypeOnDisk::UNKNOWN; } @@ -139,7 +139,7 @@ namespace VertexFactory case TypeOnDisk::UINT_32: return _ReadBinary< uint32_t >( fp , s ); case TypeOnDisk::INT_64: return _ReadBinary< int64_t >( fp , s ); case TypeOnDisk::UINT_64: return _ReadBinary< uint64_t >( fp , s ); - default: MK_ERROR_OUT( "Unrecognized type: " , typeOnDisk ); + default: MK_THROW( "Unrecognized type: " , typeOnDisk ); } return true; } @@ -162,7 +162,7 @@ namespace VertexFactory case TypeOnDisk::UINT_32: fprintf( fp , " %" PRIu32 , ( uint32_t)s ) ; break; case TypeOnDisk::INT_64: fprintf( fp , " %" PRId64 , ( int64_t)s ) ; break; case TypeOnDisk::UINT_64: fprintf( fp , " %" PRIu64 , ( uint64_t)s ) ; break; - default: MK_ERROR_OUT( "Unrecongized type: " , typeOnDisk ); + default: MK_THROW( "Unrecongized type: " , typeOnDisk ); } } @@ -186,7 +186,7 @@ namespace VertexFactory case TypeOnDisk::UINT_32: _WriteBinary< uint32_t >( fp , s ) ; break; case TypeOnDisk::INT_64: _WriteBinary< int64_t >( fp , s ) ; break; case TypeOnDisk::UINT_64: _WriteBinary< uint64_t >( fp , s ) ; break; - default: MK_ERROR_OUT( "Unrecongized type: " , typeOnDisk ); + default: MK_THROW( "Unrecongized type: " , typeOnDisk ); } } @@ -223,26 +223,26 @@ namespace VertexFactory template< typename Real , unsigned int Dim > PlyProperty PositionFactory< Real , Dim >::plyReadProperty( unsigned int idx ) const { - if( idx>= plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); + if( idx>= plyReadNum() ) MK_THROW( "read property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real , unsigned int Dim > PlyProperty PositionFactory< Real , Dim >::plyWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_THROW( "write property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real , unsigned int Dim > PlyProperty PositionFactory< Real , Dim >::plyStaticReadProperty( unsigned int idx ) const { - if( idx>=plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); + if( idx>=plyReadNum() ) MK_THROW( "read property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); } template< typename Real , unsigned int Dim > PlyProperty PositionFactory< Real , Dim >::plyStaticWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_THROW( "write property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); } @@ -259,26 +259,26 @@ namespace VertexFactory template< typename Real , unsigned int Dim > PlyProperty NormalFactory< Real , Dim >::plyReadProperty( unsigned int idx ) const { - if( idx>= plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); + if( idx>= plyReadNum() ) MK_THROW( "read property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real , unsigned int Dim > PlyProperty NormalFactory< Real , Dim >::plyWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_THROW( "write property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real , unsigned int Dim > PlyProperty NormalFactory< Real , Dim >::plyStaticReadProperty( unsigned int idx ) const { - if( idx>=plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); + if( idx>=plyReadNum() ) MK_THROW( "read property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); } template< typename Real , unsigned int Dim > PlyProperty NormalFactory< Real , Dim >::plyStaticWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_THROW( "write property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); } @@ -295,26 +295,26 @@ namespace VertexFactory template< typename Real , unsigned int Dim > PlyProperty TextureFactory< Real , Dim >::plyReadProperty( unsigned int idx ) const { - if( idx>= plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); + if( idx>= plyReadNum() ) MK_THROW( "read property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real , unsigned int Dim > PlyProperty TextureFactory< Real , Dim >::plyWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_THROW( "write property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real , unsigned int Dim > PlyProperty TextureFactory< Real , Dim >::plyStaticReadProperty( unsigned int idx ) const { - if( idx>=plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); + if( idx>=plyReadNum() ) MK_THROW( "read property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); } template< typename Real , unsigned int Dim > PlyProperty TextureFactory< Real , Dim >::plyStaticWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_THROW( "write property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); } @@ -331,26 +331,26 @@ namespace VertexFactory template< typename Real > PlyProperty RGBColorFactory< Real >::plyReadProperty( unsigned int idx ) const { - if( idx>= plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); + if( idx>= plyReadNum() ) MK_THROW( "read property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real > PlyProperty RGBColorFactory< Real >::plyWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_THROW( "write property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real > PlyProperty RGBColorFactory< Real >::plyStaticReadProperty( unsigned int idx ) const { - if( idx>=plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); + if( idx>=plyReadNum() ) MK_THROW( "read property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + (idx%3)*sizeof(Real) ) ); } template< typename Real > PlyProperty RGBColorFactory< Real >::plyStaticWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_THROW( "write property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); } @@ -367,28 +367,28 @@ namespace VertexFactory template< typename Real > PlyProperty RGBAColorFactory< Real >::plyReadProperty( unsigned int idx ) const { - if( idx>= plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); + if( idx>= plyReadNum() ) MK_THROW( "read property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real > PlyProperty RGBAColorFactory< Real >::plyWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_THROW( "write property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real > PlyProperty RGBAColorFactory< Real >::plyStaticReadProperty( unsigned int idx ) const { - if( idx>=plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); + if( idx>=plyReadNum() ) MK_THROW( "read property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + (idx%4)*sizeof(Real) ) ); } template< typename Real > PlyProperty RGBAColorFactory< Real >::plyStaticWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_THROW( "write property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , (int)( offsetof( VertexType , coords ) + idx*sizeof(Real) ) ); } @@ -405,28 +405,28 @@ namespace VertexFactory template< typename Real > PlyProperty ValueFactory< Real >::plyReadProperty( unsigned int idx ) const { - if( idx>= plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); + if( idx>= plyReadNum() ) MK_THROW( "read property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real > PlyProperty ValueFactory< Real >::plyWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_THROW( "write property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real > PlyProperty ValueFactory< Real >::plyStaticReadProperty( unsigned int idx ) const { - if( idx>=plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); + if( idx>=plyReadNum() ) MK_THROW( "read property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , 0 ); } template< typename Real > PlyProperty ValueFactory< Real >::plyStaticWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_THROW( "write property out of bounds" ); return PlyProperty( _PlyName(idx) , ToPlyType( _typeOnDisk ) , PLY::Type< Real >() , 0 ); } @@ -490,13 +490,13 @@ namespace VertexFactory template< typename Real > PlyProperty DynamicFactory< Real >::plyReadProperty( unsigned int idx ) const { - if( idx>=plyReadNum() ) MK_ERROR_OUT( "read property out of bounds" ); + if( idx>=plyReadNum() ) MK_THROW( "read property out of bounds" ); return PlyProperty( _namesAndTypesOnDisk[idx].first , ToPlyType( _namesAndTypesOnDisk[idx].second ) , PLY::Type< Real >() , sizeof(Real)*idx ); } template< typename Real > PlyProperty DynamicFactory< Real >::plyWriteProperty( unsigned int idx ) const { - if( idx>=plyWriteNum() ) MK_ERROR_OUT( "write property out of bounds" ); + if( idx>=plyWriteNum() ) MK_THROW( "write property out of bounds" ); return PlyProperty( _namesAndTypesOnDisk[idx].first , ToPlyType( _namesAndTypesOnDisk[idx].second ) , PLY::Type< Real >() , sizeof(Real)*idx ); } From 23446519aa82d625372935b76be3dab3b17b572d Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Thu, 26 Jun 2025 20:30:36 -0400 Subject: [PATCH 84/86] Version 18.74 --- README.md | 12 +++++++++--- Src/FEMTree.h | 6 +++--- Src/PreProcessor.h | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 80a37cf7..1fc8e35f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

    Adaptive Multigrid Solvers (Version 18.73)

    +

    Adaptive Multigrid Solvers (Version 18.74)

    links compilation @@ -29,10 +29,11 @@ This code-base was born from the Poisson Surface Reconstruction code. It has evo [Kazhdan and Hoppe, 2023]
    Executables: -Win64
    +Win64
    Source Code: -ZIP GitHub
    +ZIP GitHub
    Older Versions: +V18.73, V18.72, V18.71, V18.70, @@ -1787,6 +1788,11 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
  • Replaced MK_ERROR_OUT with MK_THROW to throw an exception rather than exit directly. +Version 18.74: +
      +
    1. Made code compliant with MSVC 17.14. +
    +
    diff --git a/Src/FEMTree.h b/Src/FEMTree.h index 64e235f1..a325cc36 100644 --- a/Src/FEMTree.h +++ b/Src/FEMTree.h @@ -1170,7 +1170,7 @@ namespace PoissonRecon unsigned int _maxDepth; std::tuple< BSplineData< TSignatures , TDs > ... > _bSplineData; template< unsigned int I=0 > typename std::enable_if< I==Dim >::type _init( void ){} - template< unsigned int I=0 > typename std::enable_if< I< Dim >::type _init( void ){ std::get< I >( _bSplineData ).reset( _maxDepth ) ; _init< I+1 >( ); } + template< unsigned int I=0 > typename std::enable_if< (I::type _init( void ){ std::get< I >( _bSplineData ).reset( _maxDepth ) ; _init< I+1 >( ); } template< unsigned int I , unsigned int TSig , unsigned int D , typename State > void _setEvaluationState( const double* p , unsigned int depth , State& state ) const @@ -2434,7 +2434,7 @@ namespace PoissonRecon template< unsigned int _PointD=PointD > CumulativeDerivativeValues< double , Dim , _PointD > _centerValues( unsigned int d , const int fIdx[Dim] , const int idx[Dim] , bool parentChild ) const; template< unsigned int _PointD=PointD > CumulativeDerivativeValues< double , Dim , _PointD > _cornerValues( unsigned int d , const int fIdx[Dim] , const int idx[Dim] , int corner , bool parentChild ) const; template< unsigned int _PointD=PointD , unsigned int I=0 > typename std::enable_if< I==Dim >::type _setDValues( unsigned int d , const int fIdx[] , const int cIdx[] , const _CenterOffset off[] , bool pc , double dValues[][_PointD+1] ) const{ } - template< unsigned int _PointD=PointD , unsigned int I=0 > typename std::enable_if< I< Dim >::type _setDValues( unsigned int d , const int fIdx[] , const int cIdx[] , const _CenterOffset off[] , bool pc , double dValues[][_PointD+1] ) const + template< unsigned int _PointD=PointD , unsigned int I=0 > typename std::enable_if< (I::type _setDValues( unsigned int d , const int fIdx[] , const int cIdx[] , const _CenterOffset off[] , bool pc , double dValues[][_PointD+1] ) const { if( pc ) for( int dd=0 ; dd<=_PointD ; dd++ ) dValues[I][dd] = off[I]==CENTER ? std::get< I >( childEvaluators[d] ).centerValue( fIdx[I] , cIdx[I] , dd ) : std::get< I >( childEvaluators[d] ).cornerValue( fIdx[I] , cIdx[I]+off[I] , dd ); else for( int dd=0 ; dd<=_PointD ; dd++ ) dValues[I][dd] = off[I]==CENTER ? std::get< I >( evaluators[d] ).centerValue( fIdx[I] , cIdx[I] , dd ) : std::get< I >( evaluators[d] ).cornerValue( fIdx[I] , cIdx[I]+off[I] , dd ); @@ -2442,7 +2442,7 @@ namespace PoissonRecon } template< unsigned int I=0 > typename std::enable_if< I==Dim >::type _setEvaluators( unsigned int maxDepth ){ } - template< unsigned int I=0 > typename std::enable_if< I< Dim >::type _setEvaluators( unsigned int maxDepth ) + template< unsigned int I=0 > typename std::enable_if< (I::type _setEvaluators( unsigned int maxDepth ) { static const unsigned int FEMSig = UIntPack< FEMSigs ... >::template Get< I >(); for( unsigned int d=0 ; d<=maxDepth ; d++ ) BSplineEvaluationData< FEMSig >:: SetEvaluator( std::template get< I >( evaluators[d] ) , d ); diff --git a/Src/PreProcessor.h b/Src/PreProcessor.h index 20695971..694f167b 100644 --- a/Src/PreProcessor.h +++ b/Src/PreProcessor.h @@ -46,7 +46,7 @@ DAMAGE. #define USE_DEEP_TREE_NODES // Chances are that if you are using big data, you want to support a tree with depth>15. #endif // BIG_DATA -#define ADAPTIVE_SOLVERS_VERSION "18.73" // The version of the code +#define ADAPTIVE_SOLVERS_VERSION "18.74" // The version of the code #define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation #define ADAPTIVE_PADDING // Only pushes padding points deep enough so that they are "close" to the slab in terms of units at that depth From 2641b492baa1b12aecbd44ebe53b76094a45af34 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Fri, 1 Aug 2025 17:35:29 -0400 Subject: [PATCH 85/86] Version 18.74 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1fc8e35f..b15e25af 100644 --- a/README.md +++ b/README.md @@ -1798,7 +1798,7 @@ Similarly, to reduce compilation times, support for specific degrees can be remo
    SUPPORT
    \ No newline at end of file From eea22ab701d0067e36a2de33f0251c0d0511ac69 Mon Sep 17 00:00:00 2001 From: mkazhdan Date: Mon, 15 Sep 2025 23:56:40 -0400 Subject: [PATCH 86/86] Version 18.74 --- ZLIB.vcxproj | 15 +- ZLIB/Make_vms.com | 115 - ZLIB/adler32.c | 176 +- ZLIB/compress.c | 73 +- ZLIB/crc32.c | 1141 +++++- ZLIB/crc32.h | 9446 +++++++++++++++++++++++++++++++++++++++++++++ ZLIB/deflate.c | 1993 +++++++--- ZLIB/deflate.h | 153 +- ZLIB/gzclose.c | 23 + ZLIB/gzguts.h | 214 + ZLIB/gzio.c | 875 ----- ZLIB/gzlib.c | 582 +++ ZLIB/gzread.c | 602 +++ ZLIB/gzwrite.c | 631 +++ ZLIB/infback.c | 628 +++ ZLIB/infblock.c | 403 -- ZLIB/infblock.h | 39 - ZLIB/infcodes.c | 251 -- ZLIB/infcodes.h | 27 - ZLIB/inffast.c | 479 ++- ZLIB/inffast.h | 12 +- ZLIB/inffixed.h | 241 +- ZLIB/inflate.c | 1830 +++++++-- ZLIB/inflate.h | 126 + ZLIB/inftrees.c | 693 ++-- ZLIB/inftrees.h | 102 +- ZLIB/infutil.c | 87 - ZLIB/infutil.h | 98 - ZLIB/trees.c | 853 ++-- ZLIB/trees.h | 4 +- ZLIB/uncompr.c | 103 +- ZLIB/zconf.h | 534 ++- ZLIB/zlib.h | 2019 +++++++--- ZLIB/zutil.c | 230 +- ZLIB/zutil.h | 180 +- 35 files changed, 19812 insertions(+), 5166 deletions(-) delete mode 100644 ZLIB/Make_vms.com create mode 100644 ZLIB/crc32.h create mode 100644 ZLIB/gzclose.c create mode 100644 ZLIB/gzguts.h delete mode 100644 ZLIB/gzio.c create mode 100644 ZLIB/gzlib.c create mode 100644 ZLIB/gzread.c create mode 100644 ZLIB/gzwrite.c create mode 100644 ZLIB/infback.c delete mode 100644 ZLIB/infblock.c delete mode 100644 ZLIB/infblock.h delete mode 100644 ZLIB/infcodes.c delete mode 100644 ZLIB/infcodes.h create mode 100644 ZLIB/inflate.h delete mode 100644 ZLIB/infutil.c delete mode 100644 ZLIB/infutil.h diff --git a/ZLIB.vcxproj b/ZLIB.vcxproj index 205dbff6..71b30d88 100644 --- a/ZLIB.vcxproj +++ b/ZLIB.vcxproj @@ -23,25 +23,26 @@ - - - + + + + + - + - - + + - diff --git a/ZLIB/Make_vms.com b/ZLIB/Make_vms.com deleted file mode 100644 index 1c57e8f0..00000000 --- a/ZLIB/Make_vms.com +++ /dev/null @@ -1,115 +0,0 @@ -$! make libz under VMS -$! written by Martin P.J. Zinser -$! -$! Look for the compiler used -$! -$ ccopt = "" -$ if f$getsyi("HW_MODEL").ge.1024 -$ then -$ ccopt = "/prefix=all"+ccopt -$ comp = "__decc__=1" -$ if f$trnlnm("SYS").eqs."" then define sys sys$library: -$ else -$ if f$search("SYS$SYSTEM:DECC$COMPILER.EXE").eqs."" -$ then -$ comp = "__vaxc__=1" -$ if f$trnlnm("SYS").eqs."" then define sys sys$library: -$ else -$ if f$trnlnm("SYS").eqs."" then define sys decc$library_include: -$ ccopt = "/decc/prefix=all"+ccopt -$ comp = "__decc__=1" -$ endif -$ endif -$! -$! Build the thing plain or with mms -$! -$ write sys$output "Compiling Zlib sources ..." -$ if f$search("SYS$SYSTEM:MMS.EXE").eqs."" -$ then -$ dele example.obj;*,minigzip.obj;* -$ CALL MAKE adler32.OBJ "CC ''CCOPT' adler32" - - adler32.c zlib.h zconf.h -$ CALL MAKE compress.OBJ "CC ''CCOPT' compress" - - compress.c zlib.h zconf.h -$ CALL MAKE crc32.OBJ "CC ''CCOPT' crc32" - - crc32.c zlib.h zconf.h -$ CALL MAKE deflate.OBJ "CC ''CCOPT' deflate" - - deflate.c deflate.h zutil.h zlib.h zconf.h -$ CALL MAKE gzio.OBJ "CC ''CCOPT' gzio" - - gzio.c zutil.h zlib.h zconf.h -$ CALL MAKE infblock.OBJ "CC ''CCOPT' infblock" - - infblock.c zutil.h zlib.h zconf.h infblock.h -$ CALL MAKE infcodes.OBJ "CC ''CCOPT' infcodes" - - infcodes.c zutil.h zlib.h zconf.h inftrees.h -$ CALL MAKE inffast.OBJ "CC ''CCOPT' inffast" - - inffast.c zutil.h zlib.h zconf.h inffast.h -$ CALL MAKE inflate.OBJ "CC ''CCOPT' inflate" - - inflate.c zutil.h zlib.h zconf.h infblock.h -$ CALL MAKE inftrees.OBJ "CC ''CCOPT' inftrees" - - inftrees.c zutil.h zlib.h zconf.h inftrees.h -$ CALL MAKE infutil.OBJ "CC ''CCOPT' infutil" - - infutil.c zutil.h zlib.h zconf.h inftrees.h infutil.h -$ CALL MAKE trees.OBJ "CC ''CCOPT' trees" - - trees.c deflate.h zutil.h zlib.h zconf.h -$ CALL MAKE uncompr.OBJ "CC ''CCOPT' uncompr" - - uncompr.c zlib.h zconf.h -$ CALL MAKE zutil.OBJ "CC ''CCOPT' zutil" - - zutil.c zutil.h zlib.h zconf.h -$ write sys$output "Building Zlib ..." -$ CALL MAKE libz.OLB "lib/crea libz.olb *.obj" *.OBJ -$ write sys$output "Building example..." -$ CALL MAKE example.OBJ "CC ''CCOPT' example" - - example.c zlib.h zconf.h -$ call make example.exe "LINK example,libz.olb/lib" example.obj libz.olb -$ write sys$output "Building minigzip..." -$ CALL MAKE minigzip.OBJ "CC ''CCOPT' minigzip" - - minigzip.c zlib.h zconf.h -$ call make minigzip.exe - - "LINK minigzip,libz.olb/lib,x11vms:xvmsutils.olb/lib" - - minigzip.obj libz.olb -$ else -$ mms/macro=('comp') -$ endif -$ write sys$output "Zlib build completed" -$ exit -$! -$! -$MAKE: SUBROUTINE !SUBROUTINE TO CHECK DEPENDENCIES -$ V = 'F$Verify(0) -$! P1 = What we are trying to make -$! P2 = Command to make it -$! P3 - P8 What it depends on -$ -$ If F$Search(P1) .Eqs. "" Then Goto Makeit -$ Time = F$CvTime(F$File(P1,"RDT")) -$arg=3 -$Loop: -$ Argument = P'arg -$ If Argument .Eqs. "" Then Goto Exit -$ El=0 -$Loop2: -$ File = F$Element(El," ",Argument) -$ If File .Eqs. " " Then Goto Endl -$ AFile = "" -$Loop3: -$ OFile = AFile -$ AFile = F$Search(File) -$ If AFile .Eqs. "" .Or. AFile .Eqs. OFile Then Goto NextEl -$ If F$CvTime(F$File(AFile,"RDT")) .Ges. Time Then Goto Makeit -$ Goto Loop3 -$NextEL: -$ El = El + 1 -$ Goto Loop2 -$EndL: -$ arg=arg+1 -$ If arg .Le. 8 Then Goto Loop -$ Goto Exit -$ -$Makeit: -$ VV=F$VERIFY(0) -$ write sys$output P2 -$ 'P2 -$ VV='F$Verify(VV) -$Exit: -$ If V Then Set Verify -$ENDSUBROUTINE diff --git a/ZLIB/adler32.c b/ZLIB/adler32.c index fdb0e6c0..04b81d29 100644 --- a/ZLIB/adler32.c +++ b/ZLIB/adler32.c @@ -1,48 +1,164 @@ /* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-2002 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2011, 2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h */ -/* @(#) $Id: adler32.c,v 1.1 2014/03/04 21:20:43 uid42406 Exp $ */ +/* @(#) $Id$ */ -#include "zlib.h" +#include "zutil.h" -#define BASE 65521L /* largest prime smaller than 65536 */ +#define BASE 65521U /* largest prime smaller than 65536 */ #define NMAX 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ -#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); #define DO16(buf) DO8(buf,0); DO8(buf,8); +/* use NO_DIVIDE if your processor does not do division in hardware -- + try it both ways to see which is faster */ +#ifdef NO_DIVIDE +/* note that this assumes BASE is 65521, where 65536 % 65521 == 15 + (thank you to John Reiser for pointing this out) */ +# define CHOP(a) \ + do { \ + unsigned long tmp = a >> 16; \ + a &= 0xffffUL; \ + a += (tmp << 4) - tmp; \ + } while (0) +# define MOD28(a) \ + do { \ + CHOP(a); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD(a) \ + do { \ + CHOP(a); \ + MOD28(a); \ + } while (0) +# define MOD63(a) \ + do { /* this assumes a is not negative */ \ + z_off64_t tmp = a >> 32; \ + a &= 0xffffffffL; \ + a += (tmp << 8) - (tmp << 5) + tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD28(a) a %= BASE +# define MOD63(a) a %= BASE +#endif + /* ========================================================================= */ -uLong ZEXPORT adler32(adler, buf, len) - uLong adler; - const Bytef *buf; - uInt len; -{ - unsigned long s1 = adler & 0xffff; - unsigned long s2 = (adler >> 16) & 0xffff; - int k; - - if (buf == Z_NULL) return 1L; - - while (len > 0) { - k = len < NMAX ? len : NMAX; - len -= k; - while (k >= 16) { +uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, z_size_t len) { + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD28(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; DO16(buf); - buf += 16; - k -= 16; + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; } - if (k != 0) do { - s1 += *buf++; - s2 += s1; - } while (--k); - s1 %= BASE; - s2 %= BASE; + MOD(adler); + MOD(sum2); } - return (s2 << 16) | s1; + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len) { + return adler32_z(adler, buf, len); +} + +/* ========================================================================= */ +local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2) { + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* for negative len, return invalid adler32 as a clue for debugging */ + if (len2 < 0) + return 0xffffffffUL; + + /* the derivation of this formula is left as an exercise for the reader */ + MOD63(len2); /* assumes len2 >= 0 */ + rem = (unsigned)len2; + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 >= BASE) sum1 -= BASE; + if (sum1 >= BASE) sum1 -= BASE; + if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1); + if (sum2 >= BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, z_off_t len2) { + return adler32_combine_(adler1, adler2, len2); +} + +uLong ZEXPORT adler32_combine64(uLong adler1, uLong adler2, z_off64_t len2) { + return adler32_combine_(adler1, adler2, len2); } diff --git a/ZLIB/compress.c b/ZLIB/compress.c index 9371538d..f43bacf7 100644 --- a/ZLIB/compress.c +++ b/ZLIB/compress.c @@ -1,10 +1,11 @@ /* compress.c -- compress a memory buffer - * Copyright (C) 1995-2002 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2005, 2014, 2016 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h */ -/* @(#) $Id: compress.c,v 1.1 2014/03/04 21:20:43 uid42406 Exp $ */ +/* @(#) $Id$ */ +#define ZLIB_INTERNAL #include "zlib.h" /* =========================================================================== @@ -18,25 +19,15 @@ memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ -int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; - int level; -{ +int ZEXPORT compress2(Bytef *dest, uLongf *destLen, const Bytef *source, + uLong sourceLen, int level) { z_stream stream; int err; + const uInt max = (uInt)-1; + uLong left; - stream.next_in = (Bytef*)source; - stream.avail_in = (uInt)sourceLen; -#ifdef MAXSEG_64K - /* Check for source > 64K on 16-bit machine: */ - if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; -#endif - stream.next_out = dest; - stream.avail_out = (uInt)*destLen; - if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + left = *destLen; + *destLen = 0; stream.zalloc = (alloc_func)0; stream.zfree = (free_func)0; @@ -45,24 +36,40 @@ int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) err = deflateInit(&stream, level); if (err != Z_OK) return err; - err = deflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) { - deflateEnd(&stream); - return err == Z_OK ? Z_BUF_ERROR : err; - } - *destLen = stream.total_out; + stream.next_out = dest; + stream.avail_out = 0; + stream.next_in = (z_const Bytef *)source; + stream.avail_in = 0; - err = deflateEnd(&stream); - return err; + do { + if (stream.avail_out == 0) { + stream.avail_out = left > (uLong)max ? max : (uInt)left; + left -= stream.avail_out; + } + if (stream.avail_in == 0) { + stream.avail_in = sourceLen > (uLong)max ? max : (uInt)sourceLen; + sourceLen -= stream.avail_in; + } + err = deflate(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH); + } while (err == Z_OK); + + *destLen = stream.total_out; + deflateEnd(&stream); + return err == Z_STREAM_END ? Z_OK : err; } /* =========================================================================== */ -int ZEXPORT compress (dest, destLen, source, sourceLen) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; -{ +int ZEXPORT compress(Bytef *dest, uLongf *destLen, const Bytef *source, + uLong sourceLen) { return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); } + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound(uLong sourceLen) { + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + + (sourceLen >> 25) + 13; +} diff --git a/ZLIB/crc32.c b/ZLIB/crc32.c index 9e43ab17..6c38f5c0 100644 --- a/ZLIB/crc32.c +++ b/ZLIB/crc32.c @@ -1,162 +1,1049 @@ /* crc32.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-2002 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2022 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * This interleaved implementation of a CRC makes use of pipelined multiple + * arithmetic-logic units, commonly found in modern CPU cores. It is due to + * Kadatch and Jenkins (2010). See doc/crc-doc.1.0.pdf in this distribution. */ -/* @(#) $Id: crc32.c,v 1.1 2014/03/04 21:20:43 uid42406 Exp $ */ +/* @(#) $Id$ */ -#include "zlib.h" +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + + MAKECRCH can be #defined to write out crc32.h. A main() routine is also + produced, so that this one source file can be compiled to an executable. + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for Z_U4, Z_U8, z_crc_t, and FAR definitions */ + + /* + A CRC of a message is computed on N braids of words in the message, where + each word consists of W bytes (4 or 8). If N is 3, for example, then three + running sparse CRCs are calculated respectively on each braid, at these + indices in the array of words: 0, 3, 6, ..., 1, 4, 7, ..., and 2, 5, 8, ... + This is done starting at a word boundary, and continues until as many blocks + of N * W bytes as are available have been processed. The results are combined + into a single CRC at the end. For this code, N must be in the range 1..6 and + W must be 4 or 8. The upper limit on N can be increased if desired by adding + more #if blocks, extending the patterns apparent in the code. In addition, + crc32.h would need to be regenerated, if the maximum N value is increased. + + N and W are chosen empirically by benchmarking the execution time on a given + processor. The choices for N and W below were based on testing on Intel Kaby + Lake i7, AMD Ryzen 7, ARM Cortex-A57, Sparc64-VII, PowerPC POWER9, and MIPS64 + Octeon II processors. The Intel, AMD, and ARM processors were all fastest + with N=5, W=8. The Sparc, PowerPC, and MIPS64 were all fastest at N=5, W=4. + They were all tested with either gcc or clang, all using the -O3 optimization + level. Your mileage may vary. + */ + +/* Define N */ +#ifdef Z_TESTN +# define N Z_TESTN +#else +# define N 5 +#endif +#if N < 1 || N > 6 +# error N must be in 1..6 +#endif + +/* + z_crc_t must be at least 32 bits. z_word_t must be at least as long as + z_crc_t. It is assumed here that z_word_t is either 32 bits or 64 bits, and + that bytes are eight bits. + */ + +/* + Define W and the associated z_word_t type. If W is not defined, then a + braided calculation is not used, and the associated tables and code are not + compiled. + */ +#ifdef Z_TESTW +# if Z_TESTW-1 != -1 +# define W Z_TESTW +# endif +#else +# ifdef MAKECRCH +# define W 8 /* required for MAKECRCH */ +# else +# if defined(__x86_64__) || defined(__aarch64__) +# define W 8 +# else +# define W 4 +# endif +# endif +#endif +#ifdef W +# if W == 8 && defined(Z_U8) + typedef Z_U8 z_word_t; +# elif defined(Z_U4) +# undef W +# define W 4 + typedef Z_U4 z_word_t; +# else +# undef W +# endif +#endif -#define local static +/* If available, use the ARM processor CRC32 instruction. */ +#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) && W == 8 +# define ARMCRC32 +#endif + +#if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE)) +/* + Swap the bytes in a z_word_t to convert between little and big endian. Any + self-respecting compiler will optimize this to a single machine byte-swap + instruction, if one is available. This assumes that word_t is either 32 bits + or 64 bits. + */ +local z_word_t byte_swap(z_word_t word) { +# if W == 8 + return + (word & 0xff00000000000000) >> 56 | + (word & 0xff000000000000) >> 40 | + (word & 0xff0000000000) >> 24 | + (word & 0xff00000000) >> 8 | + (word & 0xff000000) << 8 | + (word & 0xff0000) << 24 | + (word & 0xff00) << 40 | + (word & 0xff) << 56; +# else /* W == 4 */ + return + (word & 0xff000000) >> 24 | + (word & 0xff0000) >> 8 | + (word & 0xff00) << 8 | + (word & 0xff) << 24; +# endif +} +#endif #ifdef DYNAMIC_CRC_TABLE +/* ========================================================================= + * Table of powers of x for combining CRC-32s, filled in by make_crc_table() + * below. + */ + local z_crc_t FAR x2n_table[32]; +#else +/* ========================================================================= + * Tables for byte-wise and braided CRC-32 calculations, and a table of powers + * of x for combining CRC-32s, all made by make_crc_table(). + */ +# include "crc32.h" +#endif -local int crc_table_empty = 1; -local uLongf crc_table[256]; -local void make_crc_table OF((void)); +/* CRC polynomial. */ +#define POLY 0xedb88320 /* p(x) reflected, with x^32 implied */ /* - Generate a table for a byte-wise 32-bit CRC calculation on the polynomial: + Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial, + reflected. For speed, this requires that a not be zero. + */ +local z_crc_t multmodp(z_crc_t a, z_crc_t b) { + z_crc_t m, p; + + m = (z_crc_t)1 << 31; + p = 0; + for (;;) { + if (a & m) { + p ^= b; + if ((a & (m - 1)) == 0) + break; + } + m >>= 1; + b = b & 1 ? (b >> 1) ^ POLY : b >> 1; + } + return p; +} + +/* + Return x^(n * 2^k) modulo p(x). Requires that x2n_table[] has been + initialized. + */ +local z_crc_t x2nmodp(z_off64_t n, unsigned k) { + z_crc_t p; + + p = (z_crc_t)1 << 31; /* x^0 == 1 */ + while (n) { + if (n & 1) + p = multmodp(x2n_table[k & 31], p); + n >>= 1; + k++; + } + return p; +} + +#ifdef DYNAMIC_CRC_TABLE +/* ========================================================================= + * Build the tables for byte-wise and braided CRC-32 calculations, and a table + * of powers of x for combining CRC-32s. + */ +local z_crc_t FAR crc_table[256]; +#ifdef W + local z_word_t FAR crc_big_table[256]; + local z_crc_t FAR crc_braid_table[W][256]; + local z_word_t FAR crc_braid_big_table[W][256]; + local void braid(z_crc_t [][256], z_word_t [][256], int, int); +#endif +#ifdef MAKECRCH + local void write_table(FILE *, const z_crc_t FAR *, int); + local void write_table32hi(FILE *, const z_word_t FAR *, int); + local void write_table64(FILE *, const z_word_t FAR *, int); +#endif /* MAKECRCH */ + +/* + Define a once() function depending on the availability of atomics. If this is + compiled with DYNAMIC_CRC_TABLE defined, and if CRCs will be computed in + multiple threads, and if atomics are not available, then get_crc_table() must + be called to initialize the tables and must return before any threads are + allowed to compute or combine CRCs. + */ + +/* Definition of once functionality. */ +typedef struct once_s once_t; + +/* Check for the availability of atomics. */ +#if defined(__STDC__) && __STDC_VERSION__ >= 201112L && \ + !defined(__STDC_NO_ATOMICS__) + +#include + +/* Structure for once(), which must be initialized with ONCE_INIT. */ +struct once_s { + atomic_flag begun; + atomic_int done; +}; +#define ONCE_INIT {ATOMIC_FLAG_INIT, 0} + +/* + Run the provided init() function exactly once, even if multiple threads + invoke once() at the same time. The state must be a once_t initialized with + ONCE_INIT. + */ +local void once(once_t *state, void (*init)(void)) { + if (!atomic_load(&state->done)) { + if (atomic_flag_test_and_set(&state->begun)) + while (!atomic_load(&state->done)) + ; + else { + init(); + atomic_store(&state->done, 1); + } + } +} + +#else /* no atomics */ + +/* Structure for once(), which must be initialized with ONCE_INIT. */ +struct once_s { + volatile int begun; + volatile int done; +}; +#define ONCE_INIT {0, 0} + +/* Test and set. Alas, not atomic, but tries to minimize the period of + vulnerability. */ +local int test_and_set(int volatile *flag) { + int was; + + was = *flag; + *flag = 1; + return was; +} + +/* Run the provided init() function once. This is not thread-safe. */ +local void once(once_t *state, void (*init)(void)) { + if (!state->done) { + if (test_and_set(&state->begun)) + while (!state->done) + ; + else { + init(); + state->done = 1; + } + } +} + +#endif + +/* State for once(). */ +local once_t made = ONCE_INIT; + +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. Polynomials over GF(2) are represented in binary, one bit per coefficient, - with the lowest powers in the most significant bit. Then adding polynomials + with the lowest powers in the most significant bit. Then adding polynomials is just exclusive-or, and multiplying a polynomial by x is a right shift by - one. If we call the above polynomial p, and represent a byte as the + one. If we call the above polynomial p, and represent a byte as the polynomial q, also with the lowest power in the most significant bit (so the - byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + byte 0xb1 is the polynomial x^7+x^3+x^2+1), then the CRC is (q*x^32) mod p, where a mod b means the remainder after dividing a by b. This calculation is done using the shift-register method of multiplying and - taking the remainder. The register is initialized to zero, and for each + taking the remainder. The register is initialized to zero, and for each incoming bit, x^32 is added mod p to the register if the bit is a one (where - x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by - x (which is shifting right by one and adding x^32 mod p if the bit shifted - out is a one). We start with the highest power (least significant bit) of - q and repeat for all eight bits of q. + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by x + (which is shifting right by one and adding x^32 mod p if the bit shifted out + is a one). We start with the highest power (least significant bit) of q and + repeat for all eight bits of q. - The table is simply the CRC of all possible eight bit values. This is all - the information needed to generate CRC's on data a byte at a time for all + The table is simply the CRC of all possible eight bit values. This is all the + information needed to generate CRCs on data a byte at a time for all combinations of CRC register values and incoming bytes. -*/ -local void make_crc_table() -{ - uLong c; - int n, k; - uLong poly; /* polynomial exclusive-or pattern */ - /* terms of polynomial defining this crc (except x^32): */ - static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; - - /* make exclusive-or pattern from polynomial (0xedb88320L) */ - poly = 0L; - for (n = 0; n < sizeof(p)/sizeof(Byte); n++) - poly |= 1L << (31 - p[n]); - - for (n = 0; n < 256; n++) - { - c = (uLong)n; - for (k = 0; k < 8; k++) - c = c & 1 ? poly ^ (c >> 1) : c >> 1; - crc_table[n] = c; - } - crc_table_empty = 0; + */ + +local void make_crc_table(void) { + unsigned i, j, n; + z_crc_t p; + + /* initialize the CRC of bytes tables */ + for (i = 0; i < 256; i++) { + p = i; + for (j = 0; j < 8; j++) + p = p & 1 ? (p >> 1) ^ POLY : p >> 1; + crc_table[i] = p; +#ifdef W + crc_big_table[i] = byte_swap(p); +#endif + } + + /* initialize the x^2^n mod p(x) table */ + p = (z_crc_t)1 << 30; /* x^1 */ + x2n_table[0] = p; + for (n = 1; n < 32; n++) + x2n_table[n] = p = multmodp(p, p); + +#ifdef W + /* initialize the braiding tables -- needs x2n_table[] */ + braid(crc_braid_table, crc_braid_big_table, N, W); +#endif + +#ifdef MAKECRCH + { + /* + The crc32.h header file contains tables for both 32-bit and 64-bit + z_word_t's, and so requires a 64-bit type be available. In that case, + z_word_t must be defined to be 64-bits. This code then also generates + and writes out the tables for the case that z_word_t is 32 bits. + */ +#if !defined(W) || W != 8 +# error Need a 64-bit integer type in order to generate crc32.h. +#endif + FILE *out; + int k, n; + z_crc_t ltl[8][256]; + z_word_t big[8][256]; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + + /* write out little-endian CRC table to crc32.h */ + fprintf(out, + "/* crc32.h -- tables for rapid CRC calculation\n" + " * Generated automatically by crc32.c\n */\n" + "\n" + "local const z_crc_t FAR crc_table[] = {\n" + " "); + write_table(out, crc_table, 256); + fprintf(out, + "};\n"); + + /* write out big-endian CRC table for 64-bit z_word_t to crc32.h */ + fprintf(out, + "\n" + "#ifdef W\n" + "\n" + "#if W == 8\n" + "\n" + "local const z_word_t FAR crc_big_table[] = {\n" + " "); + write_table64(out, crc_big_table, 256); + fprintf(out, + "};\n"); + + /* write out big-endian CRC table for 32-bit z_word_t to crc32.h */ + fprintf(out, + "\n" + "#else /* W == 4 */\n" + "\n" + "local const z_word_t FAR crc_big_table[] = {\n" + " "); + write_table32hi(out, crc_big_table, 256); + fprintf(out, + "};\n" + "\n" + "#endif\n"); + + /* write out braid tables for each value of N */ + for (n = 1; n <= 6; n++) { + fprintf(out, + "\n" + "#if N == %d\n", n); + + /* compute braid tables for this N and 64-bit word_t */ + braid(ltl, big, n, 8); + + /* write out braid tables for 64-bit z_word_t to crc32.h */ + fprintf(out, + "\n" + "#if W == 8\n" + "\n" + "local const z_crc_t FAR crc_braid_table[][256] = {\n"); + for (k = 0; k < 8; k++) { + fprintf(out, " {"); + write_table(out, ltl[k], 256); + fprintf(out, "}%s", k < 7 ? ",\n" : ""); + } + fprintf(out, + "};\n" + "\n" + "local const z_word_t FAR crc_braid_big_table[][256] = {\n"); + for (k = 0; k < 8; k++) { + fprintf(out, " {"); + write_table64(out, big[k], 256); + fprintf(out, "}%s", k < 7 ? ",\n" : ""); + } + fprintf(out, + "};\n"); + + /* compute braid tables for this N and 32-bit word_t */ + braid(ltl, big, n, 4); + + /* write out braid tables for 32-bit z_word_t to crc32.h */ + fprintf(out, + "\n" + "#else /* W == 4 */\n" + "\n" + "local const z_crc_t FAR crc_braid_table[][256] = {\n"); + for (k = 0; k < 4; k++) { + fprintf(out, " {"); + write_table(out, ltl[k], 256); + fprintf(out, "}%s", k < 3 ? ",\n" : ""); + } + fprintf(out, + "};\n" + "\n" + "local const z_word_t FAR crc_braid_big_table[][256] = {\n"); + for (k = 0; k < 4; k++) { + fprintf(out, " {"); + write_table32hi(out, big[k], 256); + fprintf(out, "}%s", k < 3 ? ",\n" : ""); + } + fprintf(out, + "};\n" + "\n" + "#endif\n" + "\n" + "#endif\n"); + } + fprintf(out, + "\n" + "#endif\n"); + + /* write out zeros operator table to crc32.h */ + fprintf(out, + "\n" + "local const z_crc_t FAR x2n_table[] = {\n" + " "); + write_table(out, x2n_table, 32); + fprintf(out, + "};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH + +/* + Write the 32-bit values in table[0..k-1] to out, five per line in + hexadecimal separated by commas. + */ +local void write_table(FILE *out, const z_crc_t FAR *table, int k) { + int n; + + for (n = 0; n < k; n++) + fprintf(out, "%s0x%08lx%s", n == 0 || n % 5 ? "" : " ", + (unsigned long)(table[n]), + n == k - 1 ? "" : (n % 5 == 4 ? ",\n" : ", ")); +} + +/* + Write the high 32-bits of each value in table[0..k-1] to out, five per line + in hexadecimal separated by commas. + */ +local void write_table32hi(FILE *out, const z_word_t FAR *table, int k) { + int n; + + for (n = 0; n < k; n++) + fprintf(out, "%s0x%08lx%s", n == 0 || n % 5 ? "" : " ", + (unsigned long)(table[n] >> 32), + n == k - 1 ? "" : (n % 5 == 4 ? ",\n" : ", ")); +} + +/* + Write the 64-bit values in table[0..k-1] to out, three per line in + hexadecimal separated by commas. This assumes that if there is a 64-bit + type, then there is also a long long integer type, and it is at least 64 + bits. If not, then the type cast and format string can be adjusted + accordingly. + */ +local void write_table64(FILE *out, const z_word_t FAR *table, int k) { + int n; + + for (n = 0; n < k; n++) + fprintf(out, "%s0x%016llx%s", n == 0 || n % 3 ? "" : " ", + (unsigned long long)(table[n]), + n == k - 1 ? "" : (n % 3 == 2 ? ",\n" : ", ")); +} + +/* Actually do the deed. */ +int main(void) { + make_crc_table(); + return 0; +} + +#endif /* MAKECRCH */ + +#ifdef W +/* + Generate the little and big-endian braid tables for the given n and z_word_t + size w. Each array must have room for w blocks of 256 elements. + */ +local void braid(z_crc_t ltl[][256], z_word_t big[][256], int n, int w) { + int k; + z_crc_t i, p, q; + for (k = 0; k < w; k++) { + p = x2nmodp((n * w + 3 - k) << 3, 0); + ltl[k][0] = 0; + big[w - 1 - k][0] = 0; + for (i = 1; i < 256; i++) { + ltl[k][i] = q = multmodp(i << 24, p); + big[w - 1 - k][i] = byte_swap(q); + } + } } -#else -/* ======================================================================== - * Table of CRC-32's of all single-byte values (made by make_crc_table) - */ -local const uLongf crc_table[256] = { - 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, - 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, - 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, - 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, - 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, - 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, - 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, - 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, - 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, - 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, - 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, - 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, - 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, - 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, - 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, - 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, - 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, - 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, - 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, - 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, - 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, - 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, - 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, - 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, - 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, - 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, - 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, - 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, - 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, - 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, - 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, - 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, - 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, - 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, - 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, - 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, - 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, - 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, - 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, - 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, - 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, - 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, - 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, - 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, - 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, - 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, - 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, - 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, - 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, - 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, - 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, - 0x2d02ef8dL -}; #endif +#endif /* DYNAMIC_CRC_TABLE */ + /* ========================================================================= - * This function can be used by asm versions of crc32() + * This function can be used by asm versions of crc32(), and to force the + * generation of the CRC tables in a threaded application. */ -const uLongf * ZEXPORT get_crc_table() -{ +const z_crc_t FAR * ZEXPORT get_crc_table(void) { #ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) make_crc_table(); -#endif - return (const uLongf *)crc_table; + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + return (const z_crc_t FAR *)crc_table; } -/* ========================================================================= */ -#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); -#define DO2(buf) DO1(buf); DO1(buf); -#define DO4(buf) DO2(buf); DO2(buf); -#define DO8(buf) DO4(buf); DO4(buf); +/* ========================================================================= + * Use ARM machine instructions if available. This will compute the CRC about + * ten times faster than the braided calculation. This code does not check for + * the presence of the CRC instruction at run time. __ARM_FEATURE_CRC32 will + * only be defined if the compilation specifies an ARM processor architecture + * that has the instructions. For example, compiling with -march=armv8.1-a or + * -march=armv8-a+crc, or -march=native if the compile machine has the crc32 + * instructions. + */ +#ifdef ARMCRC32 + +/* + Constants empirically determined to maximize speed. These values are from + measurements on a Cortex-A57. Your mileage may vary. + */ +#define Z_BATCH 3990 /* number of words in a batch */ +#define Z_BATCH_ZEROS 0xa10d3d0c /* computed from Z_BATCH = 3990 */ +#define Z_BATCH_MIN 800 /* fewest words in a final batch */ + +unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf, + z_size_t len) { + z_crc_t val; + z_word_t crc1, crc2; + const z_word_t *word; + z_word_t val0, val1, val2; + z_size_t last, last2, i; + z_size_t num; + + /* Return initial CRC, if requested. */ + if (buf == Z_NULL) return 0; + +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + + /* Pre-condition the CRC */ + crc = (~crc) & 0xffffffff; + + /* Compute the CRC up to a word boundary. */ + while (len && ((z_size_t)buf & 7) != 0) { + len--; + val = *buf++; + __asm__ volatile("crc32b %w0, %w0, %w1" : "+r"(crc) : "r"(val)); + } + + /* Prepare to compute the CRC on full 64-bit words word[0..num-1]. */ + word = (z_word_t const *)buf; + num = len >> 3; + len &= 7; + + /* Do three interleaved CRCs to realize the throughput of one crc32x + instruction per cycle. Each CRC is calculated on Z_BATCH words. The + three CRCs are combined into a single CRC after each set of batches. */ + while (num >= 3 * Z_BATCH) { + crc1 = 0; + crc2 = 0; + for (i = 0; i < Z_BATCH; i++) { + val0 = word[i]; + val1 = word[i + Z_BATCH]; + val2 = word[i + 2 * Z_BATCH]; + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0)); + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc1) : "r"(val1)); + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc2) : "r"(val2)); + } + word += 3 * Z_BATCH; + num -= 3 * Z_BATCH; + crc = multmodp(Z_BATCH_ZEROS, crc) ^ crc1; + crc = multmodp(Z_BATCH_ZEROS, crc) ^ crc2; + } + + /* Do one last smaller batch with the remaining words, if there are enough + to pay for the combination of CRCs. */ + last = num / 3; + if (last >= Z_BATCH_MIN) { + last2 = last << 1; + crc1 = 0; + crc2 = 0; + for (i = 0; i < last; i++) { + val0 = word[i]; + val1 = word[i + last]; + val2 = word[i + last2]; + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0)); + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc1) : "r"(val1)); + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc2) : "r"(val2)); + } + word += 3 * last; + num -= 3 * last; + val = x2nmodp(last, 6); + crc = multmodp(val, crc) ^ crc1; + crc = multmodp(val, crc) ^ crc2; + } + + /* Compute the CRC on any remaining words. */ + for (i = 0; i < num; i++) { + val0 = word[i]; + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0)); + } + word += num; + + /* Complete the CRC on any remaining bytes. */ + buf = (const unsigned char FAR *)word; + while (len) { + len--; + val = *buf++; + __asm__ volatile("crc32b %w0, %w0, %w1" : "+r"(crc) : "r"(val)); + } + + /* Return the CRC, post-conditioned. */ + return crc ^ 0xffffffff; +} + +#else + +#ifdef W + +/* + Return the CRC of the W bytes in the word_t data, taking the + least-significant byte of the word as the first byte of data, without any pre + or post conditioning. This is used to combine the CRCs of each braid. + */ +local z_crc_t crc_word(z_word_t data) { + int k; + for (k = 0; k < W; k++) + data = (data >> 8) ^ crc_table[data & 0xff]; + return (z_crc_t)data; +} + +local z_word_t crc_word_big(z_word_t data) { + int k; + for (k = 0; k < W; k++) + data = (data << 8) ^ + crc_big_table[(data >> ((W - 1) << 3)) & 0xff]; + return data; +} + +#endif /* ========================================================================= */ -uLong ZEXPORT crc32(crc, buf, len) - uLong crc; - const Bytef *buf; - uInt len; -{ - if (buf == Z_NULL) return 0L; +unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf, + z_size_t len) { + /* Return initial CRC, if requested. */ + if (buf == Z_NULL) return 0; + #ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) - make_crc_table(); + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + + /* Pre-condition the CRC */ + crc = (~crc) & 0xffffffff; + +#ifdef W + + /* If provided enough bytes, do a braided CRC calculation. */ + if (len >= N * W + W - 1) { + z_size_t blks; + z_word_t const *words; + unsigned endian; + int k; + + /* Compute the CRC up to a z_word_t boundary. */ + while (len && ((z_size_t)buf & (W - 1)) != 0) { + len--; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + } + + /* Compute the CRC on as many N z_word_t blocks as are available. */ + blks = len / (N * W); + len -= blks * N * W; + words = (z_word_t const *)buf; + + /* Do endian check at execution time instead of compile time, since ARM + processors can change the endianness at execution time. If the + compiler knows what the endianness will be, it can optimize out the + check and the unused branch. */ + endian = 1; + if (*(unsigned char *)&endian) { + /* Little endian. */ + + z_crc_t crc0; + z_word_t word0; +#if N > 1 + z_crc_t crc1; + z_word_t word1; +#if N > 2 + z_crc_t crc2; + z_word_t word2; +#if N > 3 + z_crc_t crc3; + z_word_t word3; +#if N > 4 + z_crc_t crc4; + z_word_t word4; +#if N > 5 + z_crc_t crc5; + z_word_t word5; #endif - crc = crc ^ 0xffffffffL; - while (len >= 8) - { - DO8(buf); - len -= 8; +#endif +#endif +#endif +#endif + + /* Initialize the CRC for each braid. */ + crc0 = crc; +#if N > 1 + crc1 = 0; +#if N > 2 + crc2 = 0; +#if N > 3 + crc3 = 0; +#if N > 4 + crc4 = 0; +#if N > 5 + crc5 = 0; +#endif +#endif +#endif +#endif +#endif + + /* + Process the first blks-1 blocks, computing the CRCs on each braid + independently. + */ + while (--blks) { + /* Load the word for each braid into registers. */ + word0 = crc0 ^ words[0]; +#if N > 1 + word1 = crc1 ^ words[1]; +#if N > 2 + word2 = crc2 ^ words[2]; +#if N > 3 + word3 = crc3 ^ words[3]; +#if N > 4 + word4 = crc4 ^ words[4]; +#if N > 5 + word5 = crc5 ^ words[5]; +#endif +#endif +#endif +#endif +#endif + words += N; + + /* Compute and update the CRC for each word. The loop should + get unrolled. */ + crc0 = crc_braid_table[0][word0 & 0xff]; +#if N > 1 + crc1 = crc_braid_table[0][word1 & 0xff]; +#if N > 2 + crc2 = crc_braid_table[0][word2 & 0xff]; +#if N > 3 + crc3 = crc_braid_table[0][word3 & 0xff]; +#if N > 4 + crc4 = crc_braid_table[0][word4 & 0xff]; +#if N > 5 + crc5 = crc_braid_table[0][word5 & 0xff]; +#endif +#endif +#endif +#endif +#endif + for (k = 1; k < W; k++) { + crc0 ^= crc_braid_table[k][(word0 >> (k << 3)) & 0xff]; +#if N > 1 + crc1 ^= crc_braid_table[k][(word1 >> (k << 3)) & 0xff]; +#if N > 2 + crc2 ^= crc_braid_table[k][(word2 >> (k << 3)) & 0xff]; +#if N > 3 + crc3 ^= crc_braid_table[k][(word3 >> (k << 3)) & 0xff]; +#if N > 4 + crc4 ^= crc_braid_table[k][(word4 >> (k << 3)) & 0xff]; +#if N > 5 + crc5 ^= crc_braid_table[k][(word5 >> (k << 3)) & 0xff]; +#endif +#endif +#endif +#endif +#endif + } + } + + /* + Process the last block, combining the CRCs of the N braids at the + same time. + */ + crc = crc_word(crc0 ^ words[0]); +#if N > 1 + crc = crc_word(crc1 ^ words[1] ^ crc); +#if N > 2 + crc = crc_word(crc2 ^ words[2] ^ crc); +#if N > 3 + crc = crc_word(crc3 ^ words[3] ^ crc); +#if N > 4 + crc = crc_word(crc4 ^ words[4] ^ crc); +#if N > 5 + crc = crc_word(crc5 ^ words[5] ^ crc); +#endif +#endif +#endif +#endif +#endif + words += N; + } + else { + /* Big endian. */ + + z_word_t crc0, word0, comb; +#if N > 1 + z_word_t crc1, word1; +#if N > 2 + z_word_t crc2, word2; +#if N > 3 + z_word_t crc3, word3; +#if N > 4 + z_word_t crc4, word4; +#if N > 5 + z_word_t crc5, word5; +#endif +#endif +#endif +#endif +#endif + + /* Initialize the CRC for each braid. */ + crc0 = byte_swap(crc); +#if N > 1 + crc1 = 0; +#if N > 2 + crc2 = 0; +#if N > 3 + crc3 = 0; +#if N > 4 + crc4 = 0; +#if N > 5 + crc5 = 0; +#endif +#endif +#endif +#endif +#endif + + /* + Process the first blks-1 blocks, computing the CRCs on each braid + independently. + */ + while (--blks) { + /* Load the word for each braid into registers. */ + word0 = crc0 ^ words[0]; +#if N > 1 + word1 = crc1 ^ words[1]; +#if N > 2 + word2 = crc2 ^ words[2]; +#if N > 3 + word3 = crc3 ^ words[3]; +#if N > 4 + word4 = crc4 ^ words[4]; +#if N > 5 + word5 = crc5 ^ words[5]; +#endif +#endif +#endif +#endif +#endif + words += N; + + /* Compute and update the CRC for each word. The loop should + get unrolled. */ + crc0 = crc_braid_big_table[0][word0 & 0xff]; +#if N > 1 + crc1 = crc_braid_big_table[0][word1 & 0xff]; +#if N > 2 + crc2 = crc_braid_big_table[0][word2 & 0xff]; +#if N > 3 + crc3 = crc_braid_big_table[0][word3 & 0xff]; +#if N > 4 + crc4 = crc_braid_big_table[0][word4 & 0xff]; +#if N > 5 + crc5 = crc_braid_big_table[0][word5 & 0xff]; +#endif +#endif +#endif +#endif +#endif + for (k = 1; k < W; k++) { + crc0 ^= crc_braid_big_table[k][(word0 >> (k << 3)) & 0xff]; +#if N > 1 + crc1 ^= crc_braid_big_table[k][(word1 >> (k << 3)) & 0xff]; +#if N > 2 + crc2 ^= crc_braid_big_table[k][(word2 >> (k << 3)) & 0xff]; +#if N > 3 + crc3 ^= crc_braid_big_table[k][(word3 >> (k << 3)) & 0xff]; +#if N > 4 + crc4 ^= crc_braid_big_table[k][(word4 >> (k << 3)) & 0xff]; +#if N > 5 + crc5 ^= crc_braid_big_table[k][(word5 >> (k << 3)) & 0xff]; +#endif +#endif +#endif +#endif +#endif + } + } + + /* + Process the last block, combining the CRCs of the N braids at the + same time. + */ + comb = crc_word_big(crc0 ^ words[0]); +#if N > 1 + comb = crc_word_big(crc1 ^ words[1] ^ comb); +#if N > 2 + comb = crc_word_big(crc2 ^ words[2] ^ comb); +#if N > 3 + comb = crc_word_big(crc3 ^ words[3] ^ comb); +#if N > 4 + comb = crc_word_big(crc4 ^ words[4] ^ comb); +#if N > 5 + comb = crc_word_big(crc5 ^ words[5] ^ comb); +#endif +#endif +#endif +#endif +#endif + words += N; + crc = byte_swap(comb); + } + + /* + Update the pointer to the remaining bytes to process. + */ + buf = (unsigned char const *)words; + } + +#endif /* W */ + + /* Complete the computation of the CRC on any remaining bytes. */ + while (len >= 8) { + len -= 8; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; } - if (len) do { - DO1(buf); - } while (--len); - return crc ^ 0xffffffffL; + while (len) { + len--; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + } + + /* Return the CRC, post-conditioned. */ + return crc ^ 0xffffffff; +} + +#endif + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(unsigned long crc, const unsigned char FAR *buf, + uInt len) { + return crc32_z(crc, buf, len); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine64(uLong crc1, uLong crc2, z_off64_t len2) { +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + return multmodp(x2nmodp(len2, 3), crc1) ^ (crc2 & 0xffffffff); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2) { + return crc32_combine64(crc1, crc2, (z_off64_t)len2); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine_gen64(z_off64_t len2) { +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + return x2nmodp(len2, 3); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine_gen(z_off_t len2) { + return crc32_combine_gen64((z_off64_t)len2); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op) { + return multmodp(op, crc1) ^ (crc2 & 0xffffffff); } diff --git a/ZLIB/crc32.h b/ZLIB/crc32.h new file mode 100644 index 00000000..137df68d --- /dev/null +++ b/ZLIB/crc32.h @@ -0,0 +1,9446 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const z_crc_t FAR crc_table[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d}; + +#ifdef W + +#if W == 8 + +local const z_word_t FAR crc_big_table[] = { + 0x0000000000000000, 0x9630077700000000, 0x2c610eee00000000, + 0xba51099900000000, 0x19c46d0700000000, 0x8ff46a7000000000, + 0x35a563e900000000, 0xa395649e00000000, 0x3288db0e00000000, + 0xa4b8dc7900000000, 0x1ee9d5e000000000, 0x88d9d29700000000, + 0x2b4cb60900000000, 0xbd7cb17e00000000, 0x072db8e700000000, + 0x911dbf9000000000, 0x6410b71d00000000, 0xf220b06a00000000, + 0x4871b9f300000000, 0xde41be8400000000, 0x7dd4da1a00000000, + 0xebe4dd6d00000000, 0x51b5d4f400000000, 0xc785d38300000000, + 0x56986c1300000000, 0xc0a86b6400000000, 0x7af962fd00000000, + 0xecc9658a00000000, 0x4f5c011400000000, 0xd96c066300000000, + 0x633d0ffa00000000, 0xf50d088d00000000, 0xc8206e3b00000000, + 0x5e10694c00000000, 0xe44160d500000000, 0x727167a200000000, + 0xd1e4033c00000000, 0x47d4044b00000000, 0xfd850dd200000000, + 0x6bb50aa500000000, 0xfaa8b53500000000, 0x6c98b24200000000, + 0xd6c9bbdb00000000, 0x40f9bcac00000000, 0xe36cd83200000000, + 0x755cdf4500000000, 0xcf0dd6dc00000000, 0x593dd1ab00000000, + 0xac30d92600000000, 0x3a00de5100000000, 0x8051d7c800000000, + 0x1661d0bf00000000, 0xb5f4b42100000000, 0x23c4b35600000000, + 0x9995bacf00000000, 0x0fa5bdb800000000, 0x9eb8022800000000, + 0x0888055f00000000, 0xb2d90cc600000000, 0x24e90bb100000000, + 0x877c6f2f00000000, 0x114c685800000000, 0xab1d61c100000000, + 0x3d2d66b600000000, 0x9041dc7600000000, 0x0671db0100000000, + 0xbc20d29800000000, 0x2a10d5ef00000000, 0x8985b17100000000, + 0x1fb5b60600000000, 0xa5e4bf9f00000000, 0x33d4b8e800000000, + 0xa2c9077800000000, 0x34f9000f00000000, 0x8ea8099600000000, + 0x18980ee100000000, 0xbb0d6a7f00000000, 0x2d3d6d0800000000, + 0x976c649100000000, 0x015c63e600000000, 0xf4516b6b00000000, + 0x62616c1c00000000, 0xd830658500000000, 0x4e0062f200000000, + 0xed95066c00000000, 0x7ba5011b00000000, 0xc1f4088200000000, + 0x57c40ff500000000, 0xc6d9b06500000000, 0x50e9b71200000000, + 0xeab8be8b00000000, 0x7c88b9fc00000000, 0xdf1ddd6200000000, + 0x492dda1500000000, 0xf37cd38c00000000, 0x654cd4fb00000000, + 0x5861b24d00000000, 0xce51b53a00000000, 0x7400bca300000000, + 0xe230bbd400000000, 0x41a5df4a00000000, 0xd795d83d00000000, + 0x6dc4d1a400000000, 0xfbf4d6d300000000, 0x6ae9694300000000, + 0xfcd96e3400000000, 0x468867ad00000000, 0xd0b860da00000000, + 0x732d044400000000, 0xe51d033300000000, 0x5f4c0aaa00000000, + 0xc97c0ddd00000000, 0x3c71055000000000, 0xaa41022700000000, + 0x10100bbe00000000, 0x86200cc900000000, 0x25b5685700000000, + 0xb3856f2000000000, 0x09d466b900000000, 0x9fe461ce00000000, + 0x0ef9de5e00000000, 0x98c9d92900000000, 0x2298d0b000000000, + 0xb4a8d7c700000000, 0x173db35900000000, 0x810db42e00000000, + 0x3b5cbdb700000000, 0xad6cbac000000000, 0x2083b8ed00000000, + 0xb6b3bf9a00000000, 0x0ce2b60300000000, 0x9ad2b17400000000, + 0x3947d5ea00000000, 0xaf77d29d00000000, 0x1526db0400000000, + 0x8316dc7300000000, 0x120b63e300000000, 0x843b649400000000, + 0x3e6a6d0d00000000, 0xa85a6a7a00000000, 0x0bcf0ee400000000, + 0x9dff099300000000, 0x27ae000a00000000, 0xb19e077d00000000, + 0x44930ff000000000, 0xd2a3088700000000, 0x68f2011e00000000, + 0xfec2066900000000, 0x5d5762f700000000, 0xcb67658000000000, + 0x71366c1900000000, 0xe7066b6e00000000, 0x761bd4fe00000000, + 0xe02bd38900000000, 0x5a7ada1000000000, 0xcc4add6700000000, + 0x6fdfb9f900000000, 0xf9efbe8e00000000, 0x43beb71700000000, + 0xd58eb06000000000, 0xe8a3d6d600000000, 0x7e93d1a100000000, + 0xc4c2d83800000000, 0x52f2df4f00000000, 0xf167bbd100000000, + 0x6757bca600000000, 0xdd06b53f00000000, 0x4b36b24800000000, + 0xda2b0dd800000000, 0x4c1b0aaf00000000, 0xf64a033600000000, + 0x607a044100000000, 0xc3ef60df00000000, 0x55df67a800000000, + 0xef8e6e3100000000, 0x79be694600000000, 0x8cb361cb00000000, + 0x1a8366bc00000000, 0xa0d26f2500000000, 0x36e2685200000000, + 0x95770ccc00000000, 0x03470bbb00000000, 0xb916022200000000, + 0x2f26055500000000, 0xbe3bbac500000000, 0x280bbdb200000000, + 0x925ab42b00000000, 0x046ab35c00000000, 0xa7ffd7c200000000, + 0x31cfd0b500000000, 0x8b9ed92c00000000, 0x1daede5b00000000, + 0xb0c2649b00000000, 0x26f263ec00000000, 0x9ca36a7500000000, + 0x0a936d0200000000, 0xa906099c00000000, 0x3f360eeb00000000, + 0x8567077200000000, 0x1357000500000000, 0x824abf9500000000, + 0x147ab8e200000000, 0xae2bb17b00000000, 0x381bb60c00000000, + 0x9b8ed29200000000, 0x0dbed5e500000000, 0xb7efdc7c00000000, + 0x21dfdb0b00000000, 0xd4d2d38600000000, 0x42e2d4f100000000, + 0xf8b3dd6800000000, 0x6e83da1f00000000, 0xcd16be8100000000, + 0x5b26b9f600000000, 0xe177b06f00000000, 0x7747b71800000000, + 0xe65a088800000000, 0x706a0fff00000000, 0xca3b066600000000, + 0x5c0b011100000000, 0xff9e658f00000000, 0x69ae62f800000000, + 0xd3ff6b6100000000, 0x45cf6c1600000000, 0x78e20aa000000000, + 0xeed20dd700000000, 0x5483044e00000000, 0xc2b3033900000000, + 0x612667a700000000, 0xf71660d000000000, 0x4d47694900000000, + 0xdb776e3e00000000, 0x4a6ad1ae00000000, 0xdc5ad6d900000000, + 0x660bdf4000000000, 0xf03bd83700000000, 0x53aebca900000000, + 0xc59ebbde00000000, 0x7fcfb24700000000, 0xe9ffb53000000000, + 0x1cf2bdbd00000000, 0x8ac2baca00000000, 0x3093b35300000000, + 0xa6a3b42400000000, 0x0536d0ba00000000, 0x9306d7cd00000000, + 0x2957de5400000000, 0xbf67d92300000000, 0x2e7a66b300000000, + 0xb84a61c400000000, 0x021b685d00000000, 0x942b6f2a00000000, + 0x37be0bb400000000, 0xa18e0cc300000000, 0x1bdf055a00000000, + 0x8def022d00000000}; + +#else /* W == 4 */ + +local const z_word_t FAR crc_big_table[] = { + 0x00000000, 0x96300777, 0x2c610eee, 0xba510999, 0x19c46d07, + 0x8ff46a70, 0x35a563e9, 0xa395649e, 0x3288db0e, 0xa4b8dc79, + 0x1ee9d5e0, 0x88d9d297, 0x2b4cb609, 0xbd7cb17e, 0x072db8e7, + 0x911dbf90, 0x6410b71d, 0xf220b06a, 0x4871b9f3, 0xde41be84, + 0x7dd4da1a, 0xebe4dd6d, 0x51b5d4f4, 0xc785d383, 0x56986c13, + 0xc0a86b64, 0x7af962fd, 0xecc9658a, 0x4f5c0114, 0xd96c0663, + 0x633d0ffa, 0xf50d088d, 0xc8206e3b, 0x5e10694c, 0xe44160d5, + 0x727167a2, 0xd1e4033c, 0x47d4044b, 0xfd850dd2, 0x6bb50aa5, + 0xfaa8b535, 0x6c98b242, 0xd6c9bbdb, 0x40f9bcac, 0xe36cd832, + 0x755cdf45, 0xcf0dd6dc, 0x593dd1ab, 0xac30d926, 0x3a00de51, + 0x8051d7c8, 0x1661d0bf, 0xb5f4b421, 0x23c4b356, 0x9995bacf, + 0x0fa5bdb8, 0x9eb80228, 0x0888055f, 0xb2d90cc6, 0x24e90bb1, + 0x877c6f2f, 0x114c6858, 0xab1d61c1, 0x3d2d66b6, 0x9041dc76, + 0x0671db01, 0xbc20d298, 0x2a10d5ef, 0x8985b171, 0x1fb5b606, + 0xa5e4bf9f, 0x33d4b8e8, 0xa2c90778, 0x34f9000f, 0x8ea80996, + 0x18980ee1, 0xbb0d6a7f, 0x2d3d6d08, 0x976c6491, 0x015c63e6, + 0xf4516b6b, 0x62616c1c, 0xd8306585, 0x4e0062f2, 0xed95066c, + 0x7ba5011b, 0xc1f40882, 0x57c40ff5, 0xc6d9b065, 0x50e9b712, + 0xeab8be8b, 0x7c88b9fc, 0xdf1ddd62, 0x492dda15, 0xf37cd38c, + 0x654cd4fb, 0x5861b24d, 0xce51b53a, 0x7400bca3, 0xe230bbd4, + 0x41a5df4a, 0xd795d83d, 0x6dc4d1a4, 0xfbf4d6d3, 0x6ae96943, + 0xfcd96e34, 0x468867ad, 0xd0b860da, 0x732d0444, 0xe51d0333, + 0x5f4c0aaa, 0xc97c0ddd, 0x3c710550, 0xaa410227, 0x10100bbe, + 0x86200cc9, 0x25b56857, 0xb3856f20, 0x09d466b9, 0x9fe461ce, + 0x0ef9de5e, 0x98c9d929, 0x2298d0b0, 0xb4a8d7c7, 0x173db359, + 0x810db42e, 0x3b5cbdb7, 0xad6cbac0, 0x2083b8ed, 0xb6b3bf9a, + 0x0ce2b603, 0x9ad2b174, 0x3947d5ea, 0xaf77d29d, 0x1526db04, + 0x8316dc73, 0x120b63e3, 0x843b6494, 0x3e6a6d0d, 0xa85a6a7a, + 0x0bcf0ee4, 0x9dff0993, 0x27ae000a, 0xb19e077d, 0x44930ff0, + 0xd2a30887, 0x68f2011e, 0xfec20669, 0x5d5762f7, 0xcb676580, + 0x71366c19, 0xe7066b6e, 0x761bd4fe, 0xe02bd389, 0x5a7ada10, + 0xcc4add67, 0x6fdfb9f9, 0xf9efbe8e, 0x43beb717, 0xd58eb060, + 0xe8a3d6d6, 0x7e93d1a1, 0xc4c2d838, 0x52f2df4f, 0xf167bbd1, + 0x6757bca6, 0xdd06b53f, 0x4b36b248, 0xda2b0dd8, 0x4c1b0aaf, + 0xf64a0336, 0x607a0441, 0xc3ef60df, 0x55df67a8, 0xef8e6e31, + 0x79be6946, 0x8cb361cb, 0x1a8366bc, 0xa0d26f25, 0x36e26852, + 0x95770ccc, 0x03470bbb, 0xb9160222, 0x2f260555, 0xbe3bbac5, + 0x280bbdb2, 0x925ab42b, 0x046ab35c, 0xa7ffd7c2, 0x31cfd0b5, + 0x8b9ed92c, 0x1daede5b, 0xb0c2649b, 0x26f263ec, 0x9ca36a75, + 0x0a936d02, 0xa906099c, 0x3f360eeb, 0x85670772, 0x13570005, + 0x824abf95, 0x147ab8e2, 0xae2bb17b, 0x381bb60c, 0x9b8ed292, + 0x0dbed5e5, 0xb7efdc7c, 0x21dfdb0b, 0xd4d2d386, 0x42e2d4f1, + 0xf8b3dd68, 0x6e83da1f, 0xcd16be81, 0x5b26b9f6, 0xe177b06f, + 0x7747b718, 0xe65a0888, 0x706a0fff, 0xca3b0666, 0x5c0b0111, + 0xff9e658f, 0x69ae62f8, 0xd3ff6b61, 0x45cf6c16, 0x78e20aa0, + 0xeed20dd7, 0x5483044e, 0xc2b30339, 0x612667a7, 0xf71660d0, + 0x4d476949, 0xdb776e3e, 0x4a6ad1ae, 0xdc5ad6d9, 0x660bdf40, + 0xf03bd837, 0x53aebca9, 0xc59ebbde, 0x7fcfb247, 0xe9ffb530, + 0x1cf2bdbd, 0x8ac2baca, 0x3093b353, 0xa6a3b424, 0x0536d0ba, + 0x9306d7cd, 0x2957de54, 0xbf67d923, 0x2e7a66b3, 0xb84a61c4, + 0x021b685d, 0x942b6f2a, 0x37be0bb4, 0xa18e0cc3, 0x1bdf055a, + 0x8def022d}; + +#endif + +#if N == 1 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa, + 0x48e00e64, 0xc66f0987, 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b, + 0x91c01cc8, 0x5d6a1c56, 0x57af154f, 0x9b0515d1, 0x158a1232, + 0xd92012ac, 0x7cbb312b, 0xb01131b5, 0x3e9e3656, 0xf23436c8, + 0xf8f13fd1, 0x345b3f4f, 0xbad438ac, 0x767e3832, 0xaf5e2a9e, + 0x63f42a00, 0xed7b2de3, 0x21d12d7d, 0x2b142464, 0xe7be24fa, + 0x69312319, 0xa59b2387, 0xf9766256, 0x35dc62c8, 0xbb53652b, + 0x77f965b5, 0x7d3c6cac, 0xb1966c32, 0x3f196bd1, 0xf3b36b4f, + 0x2a9379e3, 0xe639797d, 0x68b67e9e, 0xa41c7e00, 0xaed97719, + 0x62737787, 0xecfc7064, 0x205670fa, 0x85cd537d, 0x496753e3, + 0xc7e85400, 0x0b42549e, 0x01875d87, 0xcd2d5d19, 0x43a25afa, + 0x8f085a64, 0x562848c8, 0x9a824856, 0x140d4fb5, 0xd8a74f2b, + 0xd2624632, 0x1ec846ac, 0x9047414f, 0x5ced41d1, 0x299dc2ed, + 0xe537c273, 0x6bb8c590, 0xa712c50e, 0xadd7cc17, 0x617dcc89, + 0xeff2cb6a, 0x2358cbf4, 0xfa78d958, 0x36d2d9c6, 0xb85dde25, + 0x74f7debb, 0x7e32d7a2, 0xb298d73c, 0x3c17d0df, 0xf0bdd041, + 0x5526f3c6, 0x998cf358, 0x1703f4bb, 0xdba9f425, 0xd16cfd3c, + 0x1dc6fda2, 0x9349fa41, 0x5fe3fadf, 0x86c3e873, 0x4a69e8ed, + 0xc4e6ef0e, 0x084cef90, 0x0289e689, 0xce23e617, 0x40ace1f4, + 0x8c06e16a, 0xd0eba0bb, 0x1c41a025, 0x92cea7c6, 0x5e64a758, + 0x54a1ae41, 0x980baedf, 0x1684a93c, 0xda2ea9a2, 0x030ebb0e, + 0xcfa4bb90, 0x412bbc73, 0x8d81bced, 0x8744b5f4, 0x4beeb56a, + 0xc561b289, 0x09cbb217, 0xac509190, 0x60fa910e, 0xee7596ed, + 0x22df9673, 0x281a9f6a, 0xe4b09ff4, 0x6a3f9817, 0xa6959889, + 0x7fb58a25, 0xb31f8abb, 0x3d908d58, 0xf13a8dc6, 0xfbff84df, + 0x37558441, 0xb9da83a2, 0x7570833c, 0x533b85da, 0x9f918544, + 0x111e82a7, 0xddb48239, 0xd7718b20, 0x1bdb8bbe, 0x95548c5d, + 0x59fe8cc3, 0x80de9e6f, 0x4c749ef1, 0xc2fb9912, 0x0e51998c, + 0x04949095, 0xc83e900b, 0x46b197e8, 0x8a1b9776, 0x2f80b4f1, + 0xe32ab46f, 0x6da5b38c, 0xa10fb312, 0xabcaba0b, 0x6760ba95, + 0xe9efbd76, 0x2545bde8, 0xfc65af44, 0x30cfafda, 0xbe40a839, + 0x72eaa8a7, 0x782fa1be, 0xb485a120, 0x3a0aa6c3, 0xf6a0a65d, + 0xaa4de78c, 0x66e7e712, 0xe868e0f1, 0x24c2e06f, 0x2e07e976, + 0xe2ade9e8, 0x6c22ee0b, 0xa088ee95, 0x79a8fc39, 0xb502fca7, + 0x3b8dfb44, 0xf727fbda, 0xfde2f2c3, 0x3148f25d, 0xbfc7f5be, + 0x736df520, 0xd6f6d6a7, 0x1a5cd639, 0x94d3d1da, 0x5879d144, + 0x52bcd85d, 0x9e16d8c3, 0x1099df20, 0xdc33dfbe, 0x0513cd12, + 0xc9b9cd8c, 0x4736ca6f, 0x8b9ccaf1, 0x8159c3e8, 0x4df3c376, + 0xc37cc495, 0x0fd6c40b, 0x7aa64737, 0xb60c47a9, 0x3883404a, + 0xf42940d4, 0xfeec49cd, 0x32464953, 0xbcc94eb0, 0x70634e2e, + 0xa9435c82, 0x65e95c1c, 0xeb665bff, 0x27cc5b61, 0x2d095278, + 0xe1a352e6, 0x6f2c5505, 0xa386559b, 0x061d761c, 0xcab77682, + 0x44387161, 0x889271ff, 0x825778e6, 0x4efd7878, 0xc0727f9b, + 0x0cd87f05, 0xd5f86da9, 0x19526d37, 0x97dd6ad4, 0x5b776a4a, + 0x51b26353, 0x9d1863cd, 0x1397642e, 0xdf3d64b0, 0x83d02561, + 0x4f7a25ff, 0xc1f5221c, 0x0d5f2282, 0x079a2b9b, 0xcb302b05, + 0x45bf2ce6, 0x89152c78, 0x50353ed4, 0x9c9f3e4a, 0x121039a9, + 0xdeba3937, 0xd47f302e, 0x18d530b0, 0x965a3753, 0x5af037cd, + 0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0, + 0xb78b1a2e, 0x39041dcd, 0xf5ae1d53, 0x2c8e0fff, 0xe0240f61, + 0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678, + 0x264b06e6}, + {0x00000000, 0xa6770bb4, 0x979f1129, 0x31e81a9d, 0xf44f2413, + 0x52382fa7, 0x63d0353a, 0xc5a73e8e, 0x33ef4e67, 0x959845d3, + 0xa4705f4e, 0x020754fa, 0xc7a06a74, 0x61d761c0, 0x503f7b5d, + 0xf64870e9, 0x67de9cce, 0xc1a9977a, 0xf0418de7, 0x56368653, + 0x9391b8dd, 0x35e6b369, 0x040ea9f4, 0xa279a240, 0x5431d2a9, + 0xf246d91d, 0xc3aec380, 0x65d9c834, 0xa07ef6ba, 0x0609fd0e, + 0x37e1e793, 0x9196ec27, 0xcfbd399c, 0x69ca3228, 0x582228b5, + 0xfe552301, 0x3bf21d8f, 0x9d85163b, 0xac6d0ca6, 0x0a1a0712, + 0xfc5277fb, 0x5a257c4f, 0x6bcd66d2, 0xcdba6d66, 0x081d53e8, + 0xae6a585c, 0x9f8242c1, 0x39f54975, 0xa863a552, 0x0e14aee6, + 0x3ffcb47b, 0x998bbfcf, 0x5c2c8141, 0xfa5b8af5, 0xcbb39068, + 0x6dc49bdc, 0x9b8ceb35, 0x3dfbe081, 0x0c13fa1c, 0xaa64f1a8, + 0x6fc3cf26, 0xc9b4c492, 0xf85cde0f, 0x5e2bd5bb, 0x440b7579, + 0xe27c7ecd, 0xd3946450, 0x75e36fe4, 0xb044516a, 0x16335ade, + 0x27db4043, 0x81ac4bf7, 0x77e43b1e, 0xd19330aa, 0xe07b2a37, + 0x460c2183, 0x83ab1f0d, 0x25dc14b9, 0x14340e24, 0xb2430590, + 0x23d5e9b7, 0x85a2e203, 0xb44af89e, 0x123df32a, 0xd79acda4, + 0x71edc610, 0x4005dc8d, 0xe672d739, 0x103aa7d0, 0xb64dac64, + 0x87a5b6f9, 0x21d2bd4d, 0xe47583c3, 0x42028877, 0x73ea92ea, + 0xd59d995e, 0x8bb64ce5, 0x2dc14751, 0x1c295dcc, 0xba5e5678, + 0x7ff968f6, 0xd98e6342, 0xe86679df, 0x4e11726b, 0xb8590282, + 0x1e2e0936, 0x2fc613ab, 0x89b1181f, 0x4c162691, 0xea612d25, + 0xdb8937b8, 0x7dfe3c0c, 0xec68d02b, 0x4a1fdb9f, 0x7bf7c102, + 0xdd80cab6, 0x1827f438, 0xbe50ff8c, 0x8fb8e511, 0x29cfeea5, + 0xdf879e4c, 0x79f095f8, 0x48188f65, 0xee6f84d1, 0x2bc8ba5f, + 0x8dbfb1eb, 0xbc57ab76, 0x1a20a0c2, 0x8816eaf2, 0x2e61e146, + 0x1f89fbdb, 0xb9fef06f, 0x7c59cee1, 0xda2ec555, 0xebc6dfc8, + 0x4db1d47c, 0xbbf9a495, 0x1d8eaf21, 0x2c66b5bc, 0x8a11be08, + 0x4fb68086, 0xe9c18b32, 0xd82991af, 0x7e5e9a1b, 0xefc8763c, + 0x49bf7d88, 0x78576715, 0xde206ca1, 0x1b87522f, 0xbdf0599b, + 0x8c184306, 0x2a6f48b2, 0xdc27385b, 0x7a5033ef, 0x4bb82972, + 0xedcf22c6, 0x28681c48, 0x8e1f17fc, 0xbff70d61, 0x198006d5, + 0x47abd36e, 0xe1dcd8da, 0xd034c247, 0x7643c9f3, 0xb3e4f77d, + 0x1593fcc9, 0x247be654, 0x820cede0, 0x74449d09, 0xd23396bd, + 0xe3db8c20, 0x45ac8794, 0x800bb91a, 0x267cb2ae, 0x1794a833, + 0xb1e3a387, 0x20754fa0, 0x86024414, 0xb7ea5e89, 0x119d553d, + 0xd43a6bb3, 0x724d6007, 0x43a57a9a, 0xe5d2712e, 0x139a01c7, + 0xb5ed0a73, 0x840510ee, 0x22721b5a, 0xe7d525d4, 0x41a22e60, + 0x704a34fd, 0xd63d3f49, 0xcc1d9f8b, 0x6a6a943f, 0x5b828ea2, + 0xfdf58516, 0x3852bb98, 0x9e25b02c, 0xafcdaab1, 0x09baa105, + 0xfff2d1ec, 0x5985da58, 0x686dc0c5, 0xce1acb71, 0x0bbdf5ff, + 0xadcafe4b, 0x9c22e4d6, 0x3a55ef62, 0xabc30345, 0x0db408f1, + 0x3c5c126c, 0x9a2b19d8, 0x5f8c2756, 0xf9fb2ce2, 0xc813367f, + 0x6e643dcb, 0x982c4d22, 0x3e5b4696, 0x0fb35c0b, 0xa9c457bf, + 0x6c636931, 0xca146285, 0xfbfc7818, 0x5d8b73ac, 0x03a0a617, + 0xa5d7ada3, 0x943fb73e, 0x3248bc8a, 0xf7ef8204, 0x519889b0, + 0x6070932d, 0xc6079899, 0x304fe870, 0x9638e3c4, 0xa7d0f959, + 0x01a7f2ed, 0xc400cc63, 0x6277c7d7, 0x539fdd4a, 0xf5e8d6fe, + 0x647e3ad9, 0xc209316d, 0xf3e12bf0, 0x55962044, 0x90311eca, + 0x3646157e, 0x07ae0fe3, 0xa1d90457, 0x579174be, 0xf1e67f0a, + 0xc00e6597, 0x66796e23, 0xa3de50ad, 0x05a95b19, 0x34414184, + 0x92364a30}, + {0x00000000, 0xcb5cd3a5, 0x4dc8a10b, 0x869472ae, 0x9b914216, + 0x50cd91b3, 0xd659e31d, 0x1d0530b8, 0xec53826d, 0x270f51c8, + 0xa19b2366, 0x6ac7f0c3, 0x77c2c07b, 0xbc9e13de, 0x3a0a6170, + 0xf156b2d5, 0x03d6029b, 0xc88ad13e, 0x4e1ea390, 0x85427035, + 0x9847408d, 0x531b9328, 0xd58fe186, 0x1ed33223, 0xef8580f6, + 0x24d95353, 0xa24d21fd, 0x6911f258, 0x7414c2e0, 0xbf481145, + 0x39dc63eb, 0xf280b04e, 0x07ac0536, 0xccf0d693, 0x4a64a43d, + 0x81387798, 0x9c3d4720, 0x57619485, 0xd1f5e62b, 0x1aa9358e, + 0xebff875b, 0x20a354fe, 0xa6372650, 0x6d6bf5f5, 0x706ec54d, + 0xbb3216e8, 0x3da66446, 0xf6fab7e3, 0x047a07ad, 0xcf26d408, + 0x49b2a6a6, 0x82ee7503, 0x9feb45bb, 0x54b7961e, 0xd223e4b0, + 0x197f3715, 0xe82985c0, 0x23755665, 0xa5e124cb, 0x6ebdf76e, + 0x73b8c7d6, 0xb8e41473, 0x3e7066dd, 0xf52cb578, 0x0f580a6c, + 0xc404d9c9, 0x4290ab67, 0x89cc78c2, 0x94c9487a, 0x5f959bdf, + 0xd901e971, 0x125d3ad4, 0xe30b8801, 0x28575ba4, 0xaec3290a, + 0x659ffaaf, 0x789aca17, 0xb3c619b2, 0x35526b1c, 0xfe0eb8b9, + 0x0c8e08f7, 0xc7d2db52, 0x4146a9fc, 0x8a1a7a59, 0x971f4ae1, + 0x5c439944, 0xdad7ebea, 0x118b384f, 0xe0dd8a9a, 0x2b81593f, + 0xad152b91, 0x6649f834, 0x7b4cc88c, 0xb0101b29, 0x36846987, + 0xfdd8ba22, 0x08f40f5a, 0xc3a8dcff, 0x453cae51, 0x8e607df4, + 0x93654d4c, 0x58399ee9, 0xdeadec47, 0x15f13fe2, 0xe4a78d37, + 0x2ffb5e92, 0xa96f2c3c, 0x6233ff99, 0x7f36cf21, 0xb46a1c84, + 0x32fe6e2a, 0xf9a2bd8f, 0x0b220dc1, 0xc07ede64, 0x46eaacca, + 0x8db67f6f, 0x90b34fd7, 0x5bef9c72, 0xdd7beedc, 0x16273d79, + 0xe7718fac, 0x2c2d5c09, 0xaab92ea7, 0x61e5fd02, 0x7ce0cdba, + 0xb7bc1e1f, 0x31286cb1, 0xfa74bf14, 0x1eb014d8, 0xd5ecc77d, + 0x5378b5d3, 0x98246676, 0x852156ce, 0x4e7d856b, 0xc8e9f7c5, + 0x03b52460, 0xf2e396b5, 0x39bf4510, 0xbf2b37be, 0x7477e41b, + 0x6972d4a3, 0xa22e0706, 0x24ba75a8, 0xefe6a60d, 0x1d661643, + 0xd63ac5e6, 0x50aeb748, 0x9bf264ed, 0x86f75455, 0x4dab87f0, + 0xcb3ff55e, 0x006326fb, 0xf135942e, 0x3a69478b, 0xbcfd3525, + 0x77a1e680, 0x6aa4d638, 0xa1f8059d, 0x276c7733, 0xec30a496, + 0x191c11ee, 0xd240c24b, 0x54d4b0e5, 0x9f886340, 0x828d53f8, + 0x49d1805d, 0xcf45f2f3, 0x04192156, 0xf54f9383, 0x3e134026, + 0xb8873288, 0x73dbe12d, 0x6eded195, 0xa5820230, 0x2316709e, + 0xe84aa33b, 0x1aca1375, 0xd196c0d0, 0x5702b27e, 0x9c5e61db, + 0x815b5163, 0x4a0782c6, 0xcc93f068, 0x07cf23cd, 0xf6999118, + 0x3dc542bd, 0xbb513013, 0x700de3b6, 0x6d08d30e, 0xa65400ab, + 0x20c07205, 0xeb9ca1a0, 0x11e81eb4, 0xdab4cd11, 0x5c20bfbf, + 0x977c6c1a, 0x8a795ca2, 0x41258f07, 0xc7b1fda9, 0x0ced2e0c, + 0xfdbb9cd9, 0x36e74f7c, 0xb0733dd2, 0x7b2fee77, 0x662adecf, + 0xad760d6a, 0x2be27fc4, 0xe0beac61, 0x123e1c2f, 0xd962cf8a, + 0x5ff6bd24, 0x94aa6e81, 0x89af5e39, 0x42f38d9c, 0xc467ff32, + 0x0f3b2c97, 0xfe6d9e42, 0x35314de7, 0xb3a53f49, 0x78f9ecec, + 0x65fcdc54, 0xaea00ff1, 0x28347d5f, 0xe368aefa, 0x16441b82, + 0xdd18c827, 0x5b8cba89, 0x90d0692c, 0x8dd55994, 0x46898a31, + 0xc01df89f, 0x0b412b3a, 0xfa1799ef, 0x314b4a4a, 0xb7df38e4, + 0x7c83eb41, 0x6186dbf9, 0xaada085c, 0x2c4e7af2, 0xe712a957, + 0x15921919, 0xdececabc, 0x585ab812, 0x93066bb7, 0x8e035b0f, + 0x455f88aa, 0xc3cbfa04, 0x089729a1, 0xf9c19b74, 0x329d48d1, + 0xb4093a7f, 0x7f55e9da, 0x6250d962, 0xa90c0ac7, 0x2f987869, + 0xe4c4abcc}, + {0x00000000, 0x3d6029b0, 0x7ac05360, 0x47a07ad0, 0xf580a6c0, + 0xc8e08f70, 0x8f40f5a0, 0xb220dc10, 0x30704bc1, 0x0d106271, + 0x4ab018a1, 0x77d03111, 0xc5f0ed01, 0xf890c4b1, 0xbf30be61, + 0x825097d1, 0x60e09782, 0x5d80be32, 0x1a20c4e2, 0x2740ed52, + 0x95603142, 0xa80018f2, 0xefa06222, 0xd2c04b92, 0x5090dc43, + 0x6df0f5f3, 0x2a508f23, 0x1730a693, 0xa5107a83, 0x98705333, + 0xdfd029e3, 0xe2b00053, 0xc1c12f04, 0xfca106b4, 0xbb017c64, + 0x866155d4, 0x344189c4, 0x0921a074, 0x4e81daa4, 0x73e1f314, + 0xf1b164c5, 0xccd14d75, 0x8b7137a5, 0xb6111e15, 0x0431c205, + 0x3951ebb5, 0x7ef19165, 0x4391b8d5, 0xa121b886, 0x9c419136, + 0xdbe1ebe6, 0xe681c256, 0x54a11e46, 0x69c137f6, 0x2e614d26, + 0x13016496, 0x9151f347, 0xac31daf7, 0xeb91a027, 0xd6f18997, + 0x64d15587, 0x59b17c37, 0x1e1106e7, 0x23712f57, 0x58f35849, + 0x659371f9, 0x22330b29, 0x1f532299, 0xad73fe89, 0x9013d739, + 0xd7b3ade9, 0xead38459, 0x68831388, 0x55e33a38, 0x124340e8, + 0x2f236958, 0x9d03b548, 0xa0639cf8, 0xe7c3e628, 0xdaa3cf98, + 0x3813cfcb, 0x0573e67b, 0x42d39cab, 0x7fb3b51b, 0xcd93690b, + 0xf0f340bb, 0xb7533a6b, 0x8a3313db, 0x0863840a, 0x3503adba, + 0x72a3d76a, 0x4fc3feda, 0xfde322ca, 0xc0830b7a, 0x872371aa, + 0xba43581a, 0x9932774d, 0xa4525efd, 0xe3f2242d, 0xde920d9d, + 0x6cb2d18d, 0x51d2f83d, 0x167282ed, 0x2b12ab5d, 0xa9423c8c, + 0x9422153c, 0xd3826fec, 0xeee2465c, 0x5cc29a4c, 0x61a2b3fc, + 0x2602c92c, 0x1b62e09c, 0xf9d2e0cf, 0xc4b2c97f, 0x8312b3af, + 0xbe729a1f, 0x0c52460f, 0x31326fbf, 0x7692156f, 0x4bf23cdf, + 0xc9a2ab0e, 0xf4c282be, 0xb362f86e, 0x8e02d1de, 0x3c220dce, + 0x0142247e, 0x46e25eae, 0x7b82771e, 0xb1e6b092, 0x8c869922, + 0xcb26e3f2, 0xf646ca42, 0x44661652, 0x79063fe2, 0x3ea64532, + 0x03c66c82, 0x8196fb53, 0xbcf6d2e3, 0xfb56a833, 0xc6368183, + 0x74165d93, 0x49767423, 0x0ed60ef3, 0x33b62743, 0xd1062710, + 0xec660ea0, 0xabc67470, 0x96a65dc0, 0x248681d0, 0x19e6a860, + 0x5e46d2b0, 0x6326fb00, 0xe1766cd1, 0xdc164561, 0x9bb63fb1, + 0xa6d61601, 0x14f6ca11, 0x2996e3a1, 0x6e369971, 0x5356b0c1, + 0x70279f96, 0x4d47b626, 0x0ae7ccf6, 0x3787e546, 0x85a73956, + 0xb8c710e6, 0xff676a36, 0xc2074386, 0x4057d457, 0x7d37fde7, + 0x3a978737, 0x07f7ae87, 0xb5d77297, 0x88b75b27, 0xcf1721f7, + 0xf2770847, 0x10c70814, 0x2da721a4, 0x6a075b74, 0x576772c4, + 0xe547aed4, 0xd8278764, 0x9f87fdb4, 0xa2e7d404, 0x20b743d5, + 0x1dd76a65, 0x5a7710b5, 0x67173905, 0xd537e515, 0xe857cca5, + 0xaff7b675, 0x92979fc5, 0xe915e8db, 0xd475c16b, 0x93d5bbbb, + 0xaeb5920b, 0x1c954e1b, 0x21f567ab, 0x66551d7b, 0x5b3534cb, + 0xd965a31a, 0xe4058aaa, 0xa3a5f07a, 0x9ec5d9ca, 0x2ce505da, + 0x11852c6a, 0x562556ba, 0x6b457f0a, 0x89f57f59, 0xb49556e9, + 0xf3352c39, 0xce550589, 0x7c75d999, 0x4115f029, 0x06b58af9, + 0x3bd5a349, 0xb9853498, 0x84e51d28, 0xc34567f8, 0xfe254e48, + 0x4c059258, 0x7165bbe8, 0x36c5c138, 0x0ba5e888, 0x28d4c7df, + 0x15b4ee6f, 0x521494bf, 0x6f74bd0f, 0xdd54611f, 0xe03448af, + 0xa794327f, 0x9af41bcf, 0x18a48c1e, 0x25c4a5ae, 0x6264df7e, + 0x5f04f6ce, 0xed242ade, 0xd044036e, 0x97e479be, 0xaa84500e, + 0x4834505d, 0x755479ed, 0x32f4033d, 0x0f942a8d, 0xbdb4f69d, + 0x80d4df2d, 0xc774a5fd, 0xfa148c4d, 0x78441b9c, 0x4524322c, + 0x028448fc, 0x3fe4614c, 0x8dc4bd5c, 0xb0a494ec, 0xf704ee3c, + 0xca64c78c}, + {0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757, + 0x37def032, 0x256b5fdc, 0x9dd738b9, 0xc5b428ef, 0x7d084f8a, + 0x6fbde064, 0xd7018701, 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, + 0x58631056, 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871, + 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 0x95ad7f70, + 0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42, + 0xb0c620ac, 0x087a47c9, 0xa032af3e, 0x188ec85b, 0x0a3b67b5, + 0xb28700d0, 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787, + 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, 0xeae41086, + 0x525877e3, 0x40edd80d, 0xf851bf68, 0xf02bf8a1, 0x48979fc4, + 0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d, + 0x6dfcc018, 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, + 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, 0x9b14583d, + 0x23a83f58, 0x311d90b6, 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f, + 0xbe7f07e1, 0x06c36084, 0x5ea070d2, 0xe61c17b7, 0xf4a9b859, + 0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b, + 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5, + 0xfcd3ff90, 0xee66507e, 0x56da371b, 0x0eb9274d, 0xb6054028, + 0xa4b0efc6, 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891, + 0x936e1ff4, 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed, + 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, 0xfe92dfec, + 0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, 0xc94c2fde, + 0xdbf98030, 0x6345e755, 0x6b3fa09c, 0xd383c7f9, 0xc1366817, + 0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825, + 0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24, + 0x99557841, 0x8be0d7af, 0x335cb0ca, 0xed59b63b, 0x55e5d15e, + 0x47507eb0, 0xffec19d5, 0x623b216c, 0xda874609, 0xc832e9e7, + 0x708e8e82, 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a, + 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, 0xbd40e1a4, + 0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196, + 0x982bbe78, 0x2097d91d, 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, + 0x6a4166a5, 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2, + 0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, 0xc2098e52, + 0x7ab5e937, 0x680046d9, 0xd0bc21bc, 0x88df31ea, 0x3063568f, + 0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, + 0x15080953, 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, + 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, 0xd8c66675, + 0x607a0110, 0x72cfaefe, 0xca73c99b, 0x57a4f122, 0xef189647, + 0xfdad39a9, 0x45115ecc, 0x764dee06, 0xcef18963, 0xdc44268d, + 0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf, + 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be, + 0x842736db, 0x96929935, 0x2e2efe50, 0x2654b999, 0x9ee8defc, + 0x8c5d7112, 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645, + 0xbb838120, 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98, + 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, 0xd67f4138, + 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, 0xe1a1b10a, + 0xf3141ee4, 0x4ba87981, 0x13cb69d7, 0xab770eb2, 0xb9c2a15c, + 0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e, + 0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0, + 0xb1b8e695, 0xa30d497b, 0x1bb12e1e, 0x43d23e48, 0xfb6e592d, + 0xe9dbf6c3, 0x516791a6, 0xccb0a91f, 0x740cce7a, 0x66b96194, + 0xde0506f1}, + {0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc, + 0x06cbc2eb, 0x048d7cb2, 0x054f1685, 0x0e1351b8, 0x0fd13b8f, + 0x0d9785d6, 0x0c55efe1, 0x091af964, 0x08d89353, 0x0a9e2d0a, + 0x0b5c473d, 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29, + 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 0x1235f2c8, + 0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023, + 0x16b88e7a, 0x177ae44d, 0x384d46e0, 0x398f2cd7, 0x3bc9928e, + 0x3a0bf8b9, 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065, + 0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, 0x3157bf84, + 0x3095d5b3, 0x32d36bea, 0x331101dd, 0x246be590, 0x25a98fa7, + 0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922, + 0x2124f315, 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, + 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, 0x709a8dc0, + 0x7158e7f7, 0x731e59ae, 0x72dc3399, 0x7793251c, 0x76514f2b, + 0x7417f172, 0x75d59b45, 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816, + 0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd, + 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c, + 0x6a77ec5b, 0x68315202, 0x69f33835, 0x62af7f08, 0x636d153f, + 0x612bab66, 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba, + 0x67e0698d, 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579, + 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, 0x46c49a98, + 0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, 0x400f5873, + 0x4249e62a, 0x438b8c1d, 0x54f16850, 0x55330267, 0x5775bc3e, + 0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5, + 0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134, + 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, 0xe1351b80, 0xe0f771b7, + 0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, 0xe7fed96b, 0xe5b86732, + 0xe47a0d05, 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461, + 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, 0xfd13b8f0, + 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b, + 0xf99ec442, 0xf85cae75, 0xf300e948, 0xf2c2837f, 0xf0843d26, + 0xf1465711, 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd, + 0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, 0xde71f5bc, + 0xdfb39f8b, 0xddf521d2, 0xdc374be5, 0xd76b0cd8, 0xd6a966ef, + 0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a, + 0xd2241a5d, 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, + 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, 0xcb4dafa8, + 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, 0xcc440774, 0xcd866d43, + 0xcfc0d31a, 0xce02b92d, 0x91af9640, 0x906dfc77, 0x922b422e, + 0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5, + 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24, + 0x99770513, 0x9b31bb4a, 0x9af3d17d, 0x8d893530, 0x8c4b5f07, + 0x8e0de15e, 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982, + 0x88c623b5, 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1, + 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, 0xa9e2d0a0, + 0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, 0xaf29124b, + 0xad6fac12, 0xacadc625, 0xa7f18118, 0xa633eb2f, 0xa4755576, + 0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d, + 0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c, + 0xb30fb13b, 0xb1490f62, 0xb08b6555, 0xbbd72268, 0xba15485f, + 0xb853f606, 0xb9919c31, 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda, + 0xbe9834ed}, + {0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504, + 0x7d77f445, 0x565aa786, 0x4f4196c7, 0xc8d98a08, 0xd1c2bb49, + 0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e, + 0x87981ccf, 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192, + 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 0x821b9859, + 0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c, + 0xd4413fdf, 0xcd5a0e9e, 0x958424a2, 0x8c9f15e3, 0xa7b24620, + 0xbea97761, 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265, + 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, 0x39316bae, + 0x202a5aef, 0x0b07092c, 0x121c386d, 0xdf4636f3, 0xc65d07b2, + 0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175, + 0x9007a034, 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, + 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, 0xf0794f05, + 0xe9627e44, 0xc24f2d87, 0xdb541cc6, 0x94158a01, 0x8d0ebb40, + 0xa623e883, 0xbf38d9c2, 0x38a0c50d, 0x21bbf44c, 0x0a96a78f, + 0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca, + 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850, + 0xc7cca911, 0xece1fad2, 0xf5facb93, 0x7262d75c, 0x6b79e61d, + 0x4054b5de, 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da, + 0x3d23419b, 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864, + 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, 0xad24e1af, + 0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, 0xd05315ea, + 0xfb7e4629, 0xe2657768, 0x2f3f79f6, 0x362448b7, 0x1d091b74, + 0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31, + 0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa, + 0x9a9107bb, 0xb1bc5478, 0xa8a76539, 0x3b83984b, 0x2298a90a, + 0x09b5fac9, 0x10aecb88, 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd, + 0x74c20e8c, 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180, + 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, 0x71418a1a, + 0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f, + 0x271b2d9c, 0x3e001cdd, 0xb9980012, 0xa0833153, 0x8bae6290, + 0x92b553d1, 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5, + 0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, 0xca6b79ed, + 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 0x66de36e1, 0x7fc507a0, + 0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, + 0x299fa026, 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, + 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, 0x2c1c24b0, + 0x350715f1, 0x1e2a4632, 0x07317773, 0x4870e1b4, 0x516bd0f5, + 0x7a468336, 0x635db277, 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc, + 0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189, + 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842, + 0x7e54a903, 0x5579fac0, 0x4c62cb81, 0x8138c51f, 0x9823f45e, + 0xb30ea79d, 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299, + 0xce7953d8, 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, + 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, 0x5e7ef3ec, + 0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, 0x230907a9, + 0x0824546a, 0x113f652b, 0x96a779e4, 0x8fbc48a5, 0xa4911b66, + 0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23, + 0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9, + 0x69cb15f8, 0x42e6463b, 0x5bfd777a, 0xdc656bb5, 0xc57e5af4, + 0xee530937, 0xf7483876, 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33, + 0x9324fd72}, + {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0x9630077700000000, 0x2c610eee00000000, + 0xba51099900000000, 0x19c46d0700000000, 0x8ff46a7000000000, + 0x35a563e900000000, 0xa395649e00000000, 0x3288db0e00000000, + 0xa4b8dc7900000000, 0x1ee9d5e000000000, 0x88d9d29700000000, + 0x2b4cb60900000000, 0xbd7cb17e00000000, 0x072db8e700000000, + 0x911dbf9000000000, 0x6410b71d00000000, 0xf220b06a00000000, + 0x4871b9f300000000, 0xde41be8400000000, 0x7dd4da1a00000000, + 0xebe4dd6d00000000, 0x51b5d4f400000000, 0xc785d38300000000, + 0x56986c1300000000, 0xc0a86b6400000000, 0x7af962fd00000000, + 0xecc9658a00000000, 0x4f5c011400000000, 0xd96c066300000000, + 0x633d0ffa00000000, 0xf50d088d00000000, 0xc8206e3b00000000, + 0x5e10694c00000000, 0xe44160d500000000, 0x727167a200000000, + 0xd1e4033c00000000, 0x47d4044b00000000, 0xfd850dd200000000, + 0x6bb50aa500000000, 0xfaa8b53500000000, 0x6c98b24200000000, + 0xd6c9bbdb00000000, 0x40f9bcac00000000, 0xe36cd83200000000, + 0x755cdf4500000000, 0xcf0dd6dc00000000, 0x593dd1ab00000000, + 0xac30d92600000000, 0x3a00de5100000000, 0x8051d7c800000000, + 0x1661d0bf00000000, 0xb5f4b42100000000, 0x23c4b35600000000, + 0x9995bacf00000000, 0x0fa5bdb800000000, 0x9eb8022800000000, + 0x0888055f00000000, 0xb2d90cc600000000, 0x24e90bb100000000, + 0x877c6f2f00000000, 0x114c685800000000, 0xab1d61c100000000, + 0x3d2d66b600000000, 0x9041dc7600000000, 0x0671db0100000000, + 0xbc20d29800000000, 0x2a10d5ef00000000, 0x8985b17100000000, + 0x1fb5b60600000000, 0xa5e4bf9f00000000, 0x33d4b8e800000000, + 0xa2c9077800000000, 0x34f9000f00000000, 0x8ea8099600000000, + 0x18980ee100000000, 0xbb0d6a7f00000000, 0x2d3d6d0800000000, + 0x976c649100000000, 0x015c63e600000000, 0xf4516b6b00000000, + 0x62616c1c00000000, 0xd830658500000000, 0x4e0062f200000000, + 0xed95066c00000000, 0x7ba5011b00000000, 0xc1f4088200000000, + 0x57c40ff500000000, 0xc6d9b06500000000, 0x50e9b71200000000, + 0xeab8be8b00000000, 0x7c88b9fc00000000, 0xdf1ddd6200000000, + 0x492dda1500000000, 0xf37cd38c00000000, 0x654cd4fb00000000, + 0x5861b24d00000000, 0xce51b53a00000000, 0x7400bca300000000, + 0xe230bbd400000000, 0x41a5df4a00000000, 0xd795d83d00000000, + 0x6dc4d1a400000000, 0xfbf4d6d300000000, 0x6ae9694300000000, + 0xfcd96e3400000000, 0x468867ad00000000, 0xd0b860da00000000, + 0x732d044400000000, 0xe51d033300000000, 0x5f4c0aaa00000000, + 0xc97c0ddd00000000, 0x3c71055000000000, 0xaa41022700000000, + 0x10100bbe00000000, 0x86200cc900000000, 0x25b5685700000000, + 0xb3856f2000000000, 0x09d466b900000000, 0x9fe461ce00000000, + 0x0ef9de5e00000000, 0x98c9d92900000000, 0x2298d0b000000000, + 0xb4a8d7c700000000, 0x173db35900000000, 0x810db42e00000000, + 0x3b5cbdb700000000, 0xad6cbac000000000, 0x2083b8ed00000000, + 0xb6b3bf9a00000000, 0x0ce2b60300000000, 0x9ad2b17400000000, + 0x3947d5ea00000000, 0xaf77d29d00000000, 0x1526db0400000000, + 0x8316dc7300000000, 0x120b63e300000000, 0x843b649400000000, + 0x3e6a6d0d00000000, 0xa85a6a7a00000000, 0x0bcf0ee400000000, + 0x9dff099300000000, 0x27ae000a00000000, 0xb19e077d00000000, + 0x44930ff000000000, 0xd2a3088700000000, 0x68f2011e00000000, + 0xfec2066900000000, 0x5d5762f700000000, 0xcb67658000000000, + 0x71366c1900000000, 0xe7066b6e00000000, 0x761bd4fe00000000, + 0xe02bd38900000000, 0x5a7ada1000000000, 0xcc4add6700000000, + 0x6fdfb9f900000000, 0xf9efbe8e00000000, 0x43beb71700000000, + 0xd58eb06000000000, 0xe8a3d6d600000000, 0x7e93d1a100000000, + 0xc4c2d83800000000, 0x52f2df4f00000000, 0xf167bbd100000000, + 0x6757bca600000000, 0xdd06b53f00000000, 0x4b36b24800000000, + 0xda2b0dd800000000, 0x4c1b0aaf00000000, 0xf64a033600000000, + 0x607a044100000000, 0xc3ef60df00000000, 0x55df67a800000000, + 0xef8e6e3100000000, 0x79be694600000000, 0x8cb361cb00000000, + 0x1a8366bc00000000, 0xa0d26f2500000000, 0x36e2685200000000, + 0x95770ccc00000000, 0x03470bbb00000000, 0xb916022200000000, + 0x2f26055500000000, 0xbe3bbac500000000, 0x280bbdb200000000, + 0x925ab42b00000000, 0x046ab35c00000000, 0xa7ffd7c200000000, + 0x31cfd0b500000000, 0x8b9ed92c00000000, 0x1daede5b00000000, + 0xb0c2649b00000000, 0x26f263ec00000000, 0x9ca36a7500000000, + 0x0a936d0200000000, 0xa906099c00000000, 0x3f360eeb00000000, + 0x8567077200000000, 0x1357000500000000, 0x824abf9500000000, + 0x147ab8e200000000, 0xae2bb17b00000000, 0x381bb60c00000000, + 0x9b8ed29200000000, 0x0dbed5e500000000, 0xb7efdc7c00000000, + 0x21dfdb0b00000000, 0xd4d2d38600000000, 0x42e2d4f100000000, + 0xf8b3dd6800000000, 0x6e83da1f00000000, 0xcd16be8100000000, + 0x5b26b9f600000000, 0xe177b06f00000000, 0x7747b71800000000, + 0xe65a088800000000, 0x706a0fff00000000, 0xca3b066600000000, + 0x5c0b011100000000, 0xff9e658f00000000, 0x69ae62f800000000, + 0xd3ff6b6100000000, 0x45cf6c1600000000, 0x78e20aa000000000, + 0xeed20dd700000000, 0x5483044e00000000, 0xc2b3033900000000, + 0x612667a700000000, 0xf71660d000000000, 0x4d47694900000000, + 0xdb776e3e00000000, 0x4a6ad1ae00000000, 0xdc5ad6d900000000, + 0x660bdf4000000000, 0xf03bd83700000000, 0x53aebca900000000, + 0xc59ebbde00000000, 0x7fcfb24700000000, 0xe9ffb53000000000, + 0x1cf2bdbd00000000, 0x8ac2baca00000000, 0x3093b35300000000, + 0xa6a3b42400000000, 0x0536d0ba00000000, 0x9306d7cd00000000, + 0x2957de5400000000, 0xbf67d92300000000, 0x2e7a66b300000000, + 0xb84a61c400000000, 0x021b685d00000000, 0x942b6f2a00000000, + 0x37be0bb400000000, 0xa18e0cc300000000, 0x1bdf055a00000000, + 0x8def022d00000000}, + {0x0000000000000000, 0x41311b1900000000, 0x8262363200000000, + 0xc3532d2b00000000, 0x04c56c6400000000, 0x45f4777d00000000, + 0x86a75a5600000000, 0xc796414f00000000, 0x088ad9c800000000, + 0x49bbc2d100000000, 0x8ae8effa00000000, 0xcbd9f4e300000000, + 0x0c4fb5ac00000000, 0x4d7eaeb500000000, 0x8e2d839e00000000, + 0xcf1c988700000000, 0x5112c24a00000000, 0x1023d95300000000, + 0xd370f47800000000, 0x9241ef6100000000, 0x55d7ae2e00000000, + 0x14e6b53700000000, 0xd7b5981c00000000, 0x9684830500000000, + 0x59981b8200000000, 0x18a9009b00000000, 0xdbfa2db000000000, + 0x9acb36a900000000, 0x5d5d77e600000000, 0x1c6c6cff00000000, + 0xdf3f41d400000000, 0x9e0e5acd00000000, 0xa224849500000000, + 0xe3159f8c00000000, 0x2046b2a700000000, 0x6177a9be00000000, + 0xa6e1e8f100000000, 0xe7d0f3e800000000, 0x2483dec300000000, + 0x65b2c5da00000000, 0xaaae5d5d00000000, 0xeb9f464400000000, + 0x28cc6b6f00000000, 0x69fd707600000000, 0xae6b313900000000, + 0xef5a2a2000000000, 0x2c09070b00000000, 0x6d381c1200000000, + 0xf33646df00000000, 0xb2075dc600000000, 0x715470ed00000000, + 0x30656bf400000000, 0xf7f32abb00000000, 0xb6c231a200000000, + 0x75911c8900000000, 0x34a0079000000000, 0xfbbc9f1700000000, + 0xba8d840e00000000, 0x79dea92500000000, 0x38efb23c00000000, + 0xff79f37300000000, 0xbe48e86a00000000, 0x7d1bc54100000000, + 0x3c2ade5800000000, 0x054f79f000000000, 0x447e62e900000000, + 0x872d4fc200000000, 0xc61c54db00000000, 0x018a159400000000, + 0x40bb0e8d00000000, 0x83e823a600000000, 0xc2d938bf00000000, + 0x0dc5a03800000000, 0x4cf4bb2100000000, 0x8fa7960a00000000, + 0xce968d1300000000, 0x0900cc5c00000000, 0x4831d74500000000, + 0x8b62fa6e00000000, 0xca53e17700000000, 0x545dbbba00000000, + 0x156ca0a300000000, 0xd63f8d8800000000, 0x970e969100000000, + 0x5098d7de00000000, 0x11a9ccc700000000, 0xd2fae1ec00000000, + 0x93cbfaf500000000, 0x5cd7627200000000, 0x1de6796b00000000, + 0xdeb5544000000000, 0x9f844f5900000000, 0x58120e1600000000, + 0x1923150f00000000, 0xda70382400000000, 0x9b41233d00000000, + 0xa76bfd6500000000, 0xe65ae67c00000000, 0x2509cb5700000000, + 0x6438d04e00000000, 0xa3ae910100000000, 0xe29f8a1800000000, + 0x21cca73300000000, 0x60fdbc2a00000000, 0xafe124ad00000000, + 0xeed03fb400000000, 0x2d83129f00000000, 0x6cb2098600000000, + 0xab2448c900000000, 0xea1553d000000000, 0x29467efb00000000, + 0x687765e200000000, 0xf6793f2f00000000, 0xb748243600000000, + 0x741b091d00000000, 0x352a120400000000, 0xf2bc534b00000000, + 0xb38d485200000000, 0x70de657900000000, 0x31ef7e6000000000, + 0xfef3e6e700000000, 0xbfc2fdfe00000000, 0x7c91d0d500000000, + 0x3da0cbcc00000000, 0xfa368a8300000000, 0xbb07919a00000000, + 0x7854bcb100000000, 0x3965a7a800000000, 0x4b98833b00000000, + 0x0aa9982200000000, 0xc9fab50900000000, 0x88cbae1000000000, + 0x4f5def5f00000000, 0x0e6cf44600000000, 0xcd3fd96d00000000, + 0x8c0ec27400000000, 0x43125af300000000, 0x022341ea00000000, + 0xc1706cc100000000, 0x804177d800000000, 0x47d7369700000000, + 0x06e62d8e00000000, 0xc5b500a500000000, 0x84841bbc00000000, + 0x1a8a417100000000, 0x5bbb5a6800000000, 0x98e8774300000000, + 0xd9d96c5a00000000, 0x1e4f2d1500000000, 0x5f7e360c00000000, + 0x9c2d1b2700000000, 0xdd1c003e00000000, 0x120098b900000000, + 0x533183a000000000, 0x9062ae8b00000000, 0xd153b59200000000, + 0x16c5f4dd00000000, 0x57f4efc400000000, 0x94a7c2ef00000000, + 0xd596d9f600000000, 0xe9bc07ae00000000, 0xa88d1cb700000000, + 0x6bde319c00000000, 0x2aef2a8500000000, 0xed796bca00000000, + 0xac4870d300000000, 0x6f1b5df800000000, 0x2e2a46e100000000, + 0xe136de6600000000, 0xa007c57f00000000, 0x6354e85400000000, + 0x2265f34d00000000, 0xe5f3b20200000000, 0xa4c2a91b00000000, + 0x6791843000000000, 0x26a09f2900000000, 0xb8aec5e400000000, + 0xf99fdefd00000000, 0x3accf3d600000000, 0x7bfde8cf00000000, + 0xbc6ba98000000000, 0xfd5ab29900000000, 0x3e099fb200000000, + 0x7f3884ab00000000, 0xb0241c2c00000000, 0xf115073500000000, + 0x32462a1e00000000, 0x7377310700000000, 0xb4e1704800000000, + 0xf5d06b5100000000, 0x3683467a00000000, 0x77b25d6300000000, + 0x4ed7facb00000000, 0x0fe6e1d200000000, 0xccb5ccf900000000, + 0x8d84d7e000000000, 0x4a1296af00000000, 0x0b238db600000000, + 0xc870a09d00000000, 0x8941bb8400000000, 0x465d230300000000, + 0x076c381a00000000, 0xc43f153100000000, 0x850e0e2800000000, + 0x42984f6700000000, 0x03a9547e00000000, 0xc0fa795500000000, + 0x81cb624c00000000, 0x1fc5388100000000, 0x5ef4239800000000, + 0x9da70eb300000000, 0xdc9615aa00000000, 0x1b0054e500000000, + 0x5a314ffc00000000, 0x996262d700000000, 0xd85379ce00000000, + 0x174fe14900000000, 0x567efa5000000000, 0x952dd77b00000000, + 0xd41ccc6200000000, 0x138a8d2d00000000, 0x52bb963400000000, + 0x91e8bb1f00000000, 0xd0d9a00600000000, 0xecf37e5e00000000, + 0xadc2654700000000, 0x6e91486c00000000, 0x2fa0537500000000, + 0xe836123a00000000, 0xa907092300000000, 0x6a54240800000000, + 0x2b653f1100000000, 0xe479a79600000000, 0xa548bc8f00000000, + 0x661b91a400000000, 0x272a8abd00000000, 0xe0bccbf200000000, + 0xa18dd0eb00000000, 0x62defdc000000000, 0x23efe6d900000000, + 0xbde1bc1400000000, 0xfcd0a70d00000000, 0x3f838a2600000000, + 0x7eb2913f00000000, 0xb924d07000000000, 0xf815cb6900000000, + 0x3b46e64200000000, 0x7a77fd5b00000000, 0xb56b65dc00000000, + 0xf45a7ec500000000, 0x370953ee00000000, 0x763848f700000000, + 0xb1ae09b800000000, 0xf09f12a100000000, 0x33cc3f8a00000000, + 0x72fd249300000000}, + {0x0000000000000000, 0x376ac20100000000, 0x6ed4840300000000, + 0x59be460200000000, 0xdca8090700000000, 0xebc2cb0600000000, + 0xb27c8d0400000000, 0x85164f0500000000, 0xb851130e00000000, + 0x8f3bd10f00000000, 0xd685970d00000000, 0xe1ef550c00000000, + 0x64f91a0900000000, 0x5393d80800000000, 0x0a2d9e0a00000000, + 0x3d475c0b00000000, 0x70a3261c00000000, 0x47c9e41d00000000, + 0x1e77a21f00000000, 0x291d601e00000000, 0xac0b2f1b00000000, + 0x9b61ed1a00000000, 0xc2dfab1800000000, 0xf5b5691900000000, + 0xc8f2351200000000, 0xff98f71300000000, 0xa626b11100000000, + 0x914c731000000000, 0x145a3c1500000000, 0x2330fe1400000000, + 0x7a8eb81600000000, 0x4de47a1700000000, 0xe0464d3800000000, + 0xd72c8f3900000000, 0x8e92c93b00000000, 0xb9f80b3a00000000, + 0x3cee443f00000000, 0x0b84863e00000000, 0x523ac03c00000000, + 0x6550023d00000000, 0x58175e3600000000, 0x6f7d9c3700000000, + 0x36c3da3500000000, 0x01a9183400000000, 0x84bf573100000000, + 0xb3d5953000000000, 0xea6bd33200000000, 0xdd01113300000000, + 0x90e56b2400000000, 0xa78fa92500000000, 0xfe31ef2700000000, + 0xc95b2d2600000000, 0x4c4d622300000000, 0x7b27a02200000000, + 0x2299e62000000000, 0x15f3242100000000, 0x28b4782a00000000, + 0x1fdeba2b00000000, 0x4660fc2900000000, 0x710a3e2800000000, + 0xf41c712d00000000, 0xc376b32c00000000, 0x9ac8f52e00000000, + 0xada2372f00000000, 0xc08d9a7000000000, 0xf7e7587100000000, + 0xae591e7300000000, 0x9933dc7200000000, 0x1c25937700000000, + 0x2b4f517600000000, 0x72f1177400000000, 0x459bd57500000000, + 0x78dc897e00000000, 0x4fb64b7f00000000, 0x16080d7d00000000, + 0x2162cf7c00000000, 0xa474807900000000, 0x931e427800000000, + 0xcaa0047a00000000, 0xfdcac67b00000000, 0xb02ebc6c00000000, + 0x87447e6d00000000, 0xdefa386f00000000, 0xe990fa6e00000000, + 0x6c86b56b00000000, 0x5bec776a00000000, 0x0252316800000000, + 0x3538f36900000000, 0x087faf6200000000, 0x3f156d6300000000, + 0x66ab2b6100000000, 0x51c1e96000000000, 0xd4d7a66500000000, + 0xe3bd646400000000, 0xba03226600000000, 0x8d69e06700000000, + 0x20cbd74800000000, 0x17a1154900000000, 0x4e1f534b00000000, + 0x7975914a00000000, 0xfc63de4f00000000, 0xcb091c4e00000000, + 0x92b75a4c00000000, 0xa5dd984d00000000, 0x989ac44600000000, + 0xaff0064700000000, 0xf64e404500000000, 0xc124824400000000, + 0x4432cd4100000000, 0x73580f4000000000, 0x2ae6494200000000, + 0x1d8c8b4300000000, 0x5068f15400000000, 0x6702335500000000, + 0x3ebc755700000000, 0x09d6b75600000000, 0x8cc0f85300000000, + 0xbbaa3a5200000000, 0xe2147c5000000000, 0xd57ebe5100000000, + 0xe839e25a00000000, 0xdf53205b00000000, 0x86ed665900000000, + 0xb187a45800000000, 0x3491eb5d00000000, 0x03fb295c00000000, + 0x5a456f5e00000000, 0x6d2fad5f00000000, 0x801b35e100000000, + 0xb771f7e000000000, 0xeecfb1e200000000, 0xd9a573e300000000, + 0x5cb33ce600000000, 0x6bd9fee700000000, 0x3267b8e500000000, + 0x050d7ae400000000, 0x384a26ef00000000, 0x0f20e4ee00000000, + 0x569ea2ec00000000, 0x61f460ed00000000, 0xe4e22fe800000000, + 0xd388ede900000000, 0x8a36abeb00000000, 0xbd5c69ea00000000, + 0xf0b813fd00000000, 0xc7d2d1fc00000000, 0x9e6c97fe00000000, + 0xa90655ff00000000, 0x2c101afa00000000, 0x1b7ad8fb00000000, + 0x42c49ef900000000, 0x75ae5cf800000000, 0x48e900f300000000, + 0x7f83c2f200000000, 0x263d84f000000000, 0x115746f100000000, + 0x944109f400000000, 0xa32bcbf500000000, 0xfa958df700000000, + 0xcdff4ff600000000, 0x605d78d900000000, 0x5737bad800000000, + 0x0e89fcda00000000, 0x39e33edb00000000, 0xbcf571de00000000, + 0x8b9fb3df00000000, 0xd221f5dd00000000, 0xe54b37dc00000000, + 0xd80c6bd700000000, 0xef66a9d600000000, 0xb6d8efd400000000, + 0x81b22dd500000000, 0x04a462d000000000, 0x33cea0d100000000, + 0x6a70e6d300000000, 0x5d1a24d200000000, 0x10fe5ec500000000, + 0x27949cc400000000, 0x7e2adac600000000, 0x494018c700000000, + 0xcc5657c200000000, 0xfb3c95c300000000, 0xa282d3c100000000, + 0x95e811c000000000, 0xa8af4dcb00000000, 0x9fc58fca00000000, + 0xc67bc9c800000000, 0xf1110bc900000000, 0x740744cc00000000, + 0x436d86cd00000000, 0x1ad3c0cf00000000, 0x2db902ce00000000, + 0x4096af9100000000, 0x77fc6d9000000000, 0x2e422b9200000000, + 0x1928e99300000000, 0x9c3ea69600000000, 0xab54649700000000, + 0xf2ea229500000000, 0xc580e09400000000, 0xf8c7bc9f00000000, + 0xcfad7e9e00000000, 0x9613389c00000000, 0xa179fa9d00000000, + 0x246fb59800000000, 0x1305779900000000, 0x4abb319b00000000, + 0x7dd1f39a00000000, 0x3035898d00000000, 0x075f4b8c00000000, + 0x5ee10d8e00000000, 0x698bcf8f00000000, 0xec9d808a00000000, + 0xdbf7428b00000000, 0x8249048900000000, 0xb523c68800000000, + 0x88649a8300000000, 0xbf0e588200000000, 0xe6b01e8000000000, + 0xd1dadc8100000000, 0x54cc938400000000, 0x63a6518500000000, + 0x3a18178700000000, 0x0d72d58600000000, 0xa0d0e2a900000000, + 0x97ba20a800000000, 0xce0466aa00000000, 0xf96ea4ab00000000, + 0x7c78ebae00000000, 0x4b1229af00000000, 0x12ac6fad00000000, + 0x25c6adac00000000, 0x1881f1a700000000, 0x2feb33a600000000, + 0x765575a400000000, 0x413fb7a500000000, 0xc429f8a000000000, + 0xf3433aa100000000, 0xaafd7ca300000000, 0x9d97bea200000000, + 0xd073c4b500000000, 0xe71906b400000000, 0xbea740b600000000, + 0x89cd82b700000000, 0x0cdbcdb200000000, 0x3bb10fb300000000, + 0x620f49b100000000, 0x55658bb000000000, 0x6822d7bb00000000, + 0x5f4815ba00000000, 0x06f653b800000000, 0x319c91b900000000, + 0xb48adebc00000000, 0x83e01cbd00000000, 0xda5e5abf00000000, + 0xed3498be00000000}, + {0x0000000000000000, 0x6567bcb800000000, 0x8bc809aa00000000, + 0xeeafb51200000000, 0x5797628f00000000, 0x32f0de3700000000, + 0xdc5f6b2500000000, 0xb938d79d00000000, 0xef28b4c500000000, + 0x8a4f087d00000000, 0x64e0bd6f00000000, 0x018701d700000000, + 0xb8bfd64a00000000, 0xddd86af200000000, 0x3377dfe000000000, + 0x5610635800000000, 0x9f57195000000000, 0xfa30a5e800000000, + 0x149f10fa00000000, 0x71f8ac4200000000, 0xc8c07bdf00000000, + 0xada7c76700000000, 0x4308727500000000, 0x266fcecd00000000, + 0x707fad9500000000, 0x1518112d00000000, 0xfbb7a43f00000000, + 0x9ed0188700000000, 0x27e8cf1a00000000, 0x428f73a200000000, + 0xac20c6b000000000, 0xc9477a0800000000, 0x3eaf32a000000000, + 0x5bc88e1800000000, 0xb5673b0a00000000, 0xd00087b200000000, + 0x6938502f00000000, 0x0c5fec9700000000, 0xe2f0598500000000, + 0x8797e53d00000000, 0xd187866500000000, 0xb4e03add00000000, + 0x5a4f8fcf00000000, 0x3f28337700000000, 0x8610e4ea00000000, + 0xe377585200000000, 0x0dd8ed4000000000, 0x68bf51f800000000, + 0xa1f82bf000000000, 0xc49f974800000000, 0x2a30225a00000000, + 0x4f579ee200000000, 0xf66f497f00000000, 0x9308f5c700000000, + 0x7da740d500000000, 0x18c0fc6d00000000, 0x4ed09f3500000000, + 0x2bb7238d00000000, 0xc518969f00000000, 0xa07f2a2700000000, + 0x1947fdba00000000, 0x7c20410200000000, 0x928ff41000000000, + 0xf7e848a800000000, 0x3d58149b00000000, 0x583fa82300000000, + 0xb6901d3100000000, 0xd3f7a18900000000, 0x6acf761400000000, + 0x0fa8caac00000000, 0xe1077fbe00000000, 0x8460c30600000000, + 0xd270a05e00000000, 0xb7171ce600000000, 0x59b8a9f400000000, + 0x3cdf154c00000000, 0x85e7c2d100000000, 0xe0807e6900000000, + 0x0e2fcb7b00000000, 0x6b4877c300000000, 0xa20f0dcb00000000, + 0xc768b17300000000, 0x29c7046100000000, 0x4ca0b8d900000000, + 0xf5986f4400000000, 0x90ffd3fc00000000, 0x7e5066ee00000000, + 0x1b37da5600000000, 0x4d27b90e00000000, 0x284005b600000000, + 0xc6efb0a400000000, 0xa3880c1c00000000, 0x1ab0db8100000000, + 0x7fd7673900000000, 0x9178d22b00000000, 0xf41f6e9300000000, + 0x03f7263b00000000, 0x66909a8300000000, 0x883f2f9100000000, + 0xed58932900000000, 0x546044b400000000, 0x3107f80c00000000, + 0xdfa84d1e00000000, 0xbacff1a600000000, 0xecdf92fe00000000, + 0x89b82e4600000000, 0x67179b5400000000, 0x027027ec00000000, + 0xbb48f07100000000, 0xde2f4cc900000000, 0x3080f9db00000000, + 0x55e7456300000000, 0x9ca03f6b00000000, 0xf9c783d300000000, + 0x176836c100000000, 0x720f8a7900000000, 0xcb375de400000000, + 0xae50e15c00000000, 0x40ff544e00000000, 0x2598e8f600000000, + 0x73888bae00000000, 0x16ef371600000000, 0xf840820400000000, + 0x9d273ebc00000000, 0x241fe92100000000, 0x4178559900000000, + 0xafd7e08b00000000, 0xcab05c3300000000, 0x3bb659ed00000000, + 0x5ed1e55500000000, 0xb07e504700000000, 0xd519ecff00000000, + 0x6c213b6200000000, 0x094687da00000000, 0xe7e932c800000000, + 0x828e8e7000000000, 0xd49eed2800000000, 0xb1f9519000000000, + 0x5f56e48200000000, 0x3a31583a00000000, 0x83098fa700000000, + 0xe66e331f00000000, 0x08c1860d00000000, 0x6da63ab500000000, + 0xa4e140bd00000000, 0xc186fc0500000000, 0x2f29491700000000, + 0x4a4ef5af00000000, 0xf376223200000000, 0x96119e8a00000000, + 0x78be2b9800000000, 0x1dd9972000000000, 0x4bc9f47800000000, + 0x2eae48c000000000, 0xc001fdd200000000, 0xa566416a00000000, + 0x1c5e96f700000000, 0x79392a4f00000000, 0x97969f5d00000000, + 0xf2f123e500000000, 0x05196b4d00000000, 0x607ed7f500000000, + 0x8ed162e700000000, 0xebb6de5f00000000, 0x528e09c200000000, + 0x37e9b57a00000000, 0xd946006800000000, 0xbc21bcd000000000, + 0xea31df8800000000, 0x8f56633000000000, 0x61f9d62200000000, + 0x049e6a9a00000000, 0xbda6bd0700000000, 0xd8c101bf00000000, + 0x366eb4ad00000000, 0x5309081500000000, 0x9a4e721d00000000, + 0xff29cea500000000, 0x11867bb700000000, 0x74e1c70f00000000, + 0xcdd9109200000000, 0xa8beac2a00000000, 0x4611193800000000, + 0x2376a58000000000, 0x7566c6d800000000, 0x10017a6000000000, + 0xfeaecf7200000000, 0x9bc973ca00000000, 0x22f1a45700000000, + 0x479618ef00000000, 0xa939adfd00000000, 0xcc5e114500000000, + 0x06ee4d7600000000, 0x6389f1ce00000000, 0x8d2644dc00000000, + 0xe841f86400000000, 0x51792ff900000000, 0x341e934100000000, + 0xdab1265300000000, 0xbfd69aeb00000000, 0xe9c6f9b300000000, + 0x8ca1450b00000000, 0x620ef01900000000, 0x07694ca100000000, + 0xbe519b3c00000000, 0xdb36278400000000, 0x3599929600000000, + 0x50fe2e2e00000000, 0x99b9542600000000, 0xfcdee89e00000000, + 0x12715d8c00000000, 0x7716e13400000000, 0xce2e36a900000000, + 0xab498a1100000000, 0x45e63f0300000000, 0x208183bb00000000, + 0x7691e0e300000000, 0x13f65c5b00000000, 0xfd59e94900000000, + 0x983e55f100000000, 0x2106826c00000000, 0x44613ed400000000, + 0xaace8bc600000000, 0xcfa9377e00000000, 0x38417fd600000000, + 0x5d26c36e00000000, 0xb389767c00000000, 0xd6eecac400000000, + 0x6fd61d5900000000, 0x0ab1a1e100000000, 0xe41e14f300000000, + 0x8179a84b00000000, 0xd769cb1300000000, 0xb20e77ab00000000, + 0x5ca1c2b900000000, 0x39c67e0100000000, 0x80fea99c00000000, + 0xe599152400000000, 0x0b36a03600000000, 0x6e511c8e00000000, + 0xa716668600000000, 0xc271da3e00000000, 0x2cde6f2c00000000, + 0x49b9d39400000000, 0xf081040900000000, 0x95e6b8b100000000, + 0x7b490da300000000, 0x1e2eb11b00000000, 0x483ed24300000000, + 0x2d596efb00000000, 0xc3f6dbe900000000, 0xa691675100000000, + 0x1fa9b0cc00000000, 0x7ace0c7400000000, 0x9461b96600000000, + 0xf10605de00000000}, + {0x0000000000000000, 0xb029603d00000000, 0x6053c07a00000000, + 0xd07aa04700000000, 0xc0a680f500000000, 0x708fe0c800000000, + 0xa0f5408f00000000, 0x10dc20b200000000, 0xc14b703000000000, + 0x7162100d00000000, 0xa118b04a00000000, 0x1131d07700000000, + 0x01edf0c500000000, 0xb1c490f800000000, 0x61be30bf00000000, + 0xd197508200000000, 0x8297e06000000000, 0x32be805d00000000, + 0xe2c4201a00000000, 0x52ed402700000000, 0x4231609500000000, + 0xf21800a800000000, 0x2262a0ef00000000, 0x924bc0d200000000, + 0x43dc905000000000, 0xf3f5f06d00000000, 0x238f502a00000000, + 0x93a6301700000000, 0x837a10a500000000, 0x3353709800000000, + 0xe329d0df00000000, 0x5300b0e200000000, 0x042fc1c100000000, + 0xb406a1fc00000000, 0x647c01bb00000000, 0xd455618600000000, + 0xc489413400000000, 0x74a0210900000000, 0xa4da814e00000000, + 0x14f3e17300000000, 0xc564b1f100000000, 0x754dd1cc00000000, + 0xa537718b00000000, 0x151e11b600000000, 0x05c2310400000000, + 0xb5eb513900000000, 0x6591f17e00000000, 0xd5b8914300000000, + 0x86b821a100000000, 0x3691419c00000000, 0xe6ebe1db00000000, + 0x56c281e600000000, 0x461ea15400000000, 0xf637c16900000000, + 0x264d612e00000000, 0x9664011300000000, 0x47f3519100000000, + 0xf7da31ac00000000, 0x27a091eb00000000, 0x9789f1d600000000, + 0x8755d16400000000, 0x377cb15900000000, 0xe706111e00000000, + 0x572f712300000000, 0x4958f35800000000, 0xf971936500000000, + 0x290b332200000000, 0x9922531f00000000, 0x89fe73ad00000000, + 0x39d7139000000000, 0xe9adb3d700000000, 0x5984d3ea00000000, + 0x8813836800000000, 0x383ae35500000000, 0xe840431200000000, + 0x5869232f00000000, 0x48b5039d00000000, 0xf89c63a000000000, + 0x28e6c3e700000000, 0x98cfa3da00000000, 0xcbcf133800000000, + 0x7be6730500000000, 0xab9cd34200000000, 0x1bb5b37f00000000, + 0x0b6993cd00000000, 0xbb40f3f000000000, 0x6b3a53b700000000, + 0xdb13338a00000000, 0x0a84630800000000, 0xbaad033500000000, + 0x6ad7a37200000000, 0xdafec34f00000000, 0xca22e3fd00000000, + 0x7a0b83c000000000, 0xaa71238700000000, 0x1a5843ba00000000, + 0x4d77329900000000, 0xfd5e52a400000000, 0x2d24f2e300000000, + 0x9d0d92de00000000, 0x8dd1b26c00000000, 0x3df8d25100000000, + 0xed82721600000000, 0x5dab122b00000000, 0x8c3c42a900000000, + 0x3c15229400000000, 0xec6f82d300000000, 0x5c46e2ee00000000, + 0x4c9ac25c00000000, 0xfcb3a26100000000, 0x2cc9022600000000, + 0x9ce0621b00000000, 0xcfe0d2f900000000, 0x7fc9b2c400000000, + 0xafb3128300000000, 0x1f9a72be00000000, 0x0f46520c00000000, + 0xbf6f323100000000, 0x6f15927600000000, 0xdf3cf24b00000000, + 0x0eaba2c900000000, 0xbe82c2f400000000, 0x6ef862b300000000, + 0xded1028e00000000, 0xce0d223c00000000, 0x7e24420100000000, + 0xae5ee24600000000, 0x1e77827b00000000, 0x92b0e6b100000000, + 0x2299868c00000000, 0xf2e326cb00000000, 0x42ca46f600000000, + 0x5216664400000000, 0xe23f067900000000, 0x3245a63e00000000, + 0x826cc60300000000, 0x53fb968100000000, 0xe3d2f6bc00000000, + 0x33a856fb00000000, 0x838136c600000000, 0x935d167400000000, + 0x2374764900000000, 0xf30ed60e00000000, 0x4327b63300000000, + 0x102706d100000000, 0xa00e66ec00000000, 0x7074c6ab00000000, + 0xc05da69600000000, 0xd081862400000000, 0x60a8e61900000000, + 0xb0d2465e00000000, 0x00fb266300000000, 0xd16c76e100000000, + 0x614516dc00000000, 0xb13fb69b00000000, 0x0116d6a600000000, + 0x11caf61400000000, 0xa1e3962900000000, 0x7199366e00000000, + 0xc1b0565300000000, 0x969f277000000000, 0x26b6474d00000000, + 0xf6cce70a00000000, 0x46e5873700000000, 0x5639a78500000000, + 0xe610c7b800000000, 0x366a67ff00000000, 0x864307c200000000, + 0x57d4574000000000, 0xe7fd377d00000000, 0x3787973a00000000, + 0x87aef70700000000, 0x9772d7b500000000, 0x275bb78800000000, + 0xf72117cf00000000, 0x470877f200000000, 0x1408c71000000000, + 0xa421a72d00000000, 0x745b076a00000000, 0xc472675700000000, + 0xd4ae47e500000000, 0x648727d800000000, 0xb4fd879f00000000, + 0x04d4e7a200000000, 0xd543b72000000000, 0x656ad71d00000000, + 0xb510775a00000000, 0x0539176700000000, 0x15e537d500000000, + 0xa5cc57e800000000, 0x75b6f7af00000000, 0xc59f979200000000, + 0xdbe815e900000000, 0x6bc175d400000000, 0xbbbbd59300000000, + 0x0b92b5ae00000000, 0x1b4e951c00000000, 0xab67f52100000000, + 0x7b1d556600000000, 0xcb34355b00000000, 0x1aa365d900000000, + 0xaa8a05e400000000, 0x7af0a5a300000000, 0xcad9c59e00000000, + 0xda05e52c00000000, 0x6a2c851100000000, 0xba56255600000000, + 0x0a7f456b00000000, 0x597ff58900000000, 0xe95695b400000000, + 0x392c35f300000000, 0x890555ce00000000, 0x99d9757c00000000, + 0x29f0154100000000, 0xf98ab50600000000, 0x49a3d53b00000000, + 0x983485b900000000, 0x281de58400000000, 0xf86745c300000000, + 0x484e25fe00000000, 0x5892054c00000000, 0xe8bb657100000000, + 0x38c1c53600000000, 0x88e8a50b00000000, 0xdfc7d42800000000, + 0x6feeb41500000000, 0xbf94145200000000, 0x0fbd746f00000000, + 0x1f6154dd00000000, 0xaf4834e000000000, 0x7f3294a700000000, + 0xcf1bf49a00000000, 0x1e8ca41800000000, 0xaea5c42500000000, + 0x7edf646200000000, 0xcef6045f00000000, 0xde2a24ed00000000, + 0x6e0344d000000000, 0xbe79e49700000000, 0x0e5084aa00000000, + 0x5d50344800000000, 0xed79547500000000, 0x3d03f43200000000, + 0x8d2a940f00000000, 0x9df6b4bd00000000, 0x2ddfd48000000000, + 0xfda574c700000000, 0x4d8c14fa00000000, 0x9c1b447800000000, + 0x2c32244500000000, 0xfc48840200000000, 0x4c61e43f00000000, + 0x5cbdc48d00000000, 0xec94a4b000000000, 0x3cee04f700000000, + 0x8cc764ca00000000}, + {0x0000000000000000, 0xa5d35ccb00000000, 0x0ba1c84d00000000, + 0xae72948600000000, 0x1642919b00000000, 0xb391cd5000000000, + 0x1de359d600000000, 0xb830051d00000000, 0x6d8253ec00000000, + 0xc8510f2700000000, 0x66239ba100000000, 0xc3f0c76a00000000, + 0x7bc0c27700000000, 0xde139ebc00000000, 0x70610a3a00000000, + 0xd5b256f100000000, 0x9b02d60300000000, 0x3ed18ac800000000, + 0x90a31e4e00000000, 0x3570428500000000, 0x8d40479800000000, + 0x28931b5300000000, 0x86e18fd500000000, 0x2332d31e00000000, + 0xf68085ef00000000, 0x5353d92400000000, 0xfd214da200000000, + 0x58f2116900000000, 0xe0c2147400000000, 0x451148bf00000000, + 0xeb63dc3900000000, 0x4eb080f200000000, 0x3605ac0700000000, + 0x93d6f0cc00000000, 0x3da4644a00000000, 0x9877388100000000, + 0x20473d9c00000000, 0x8594615700000000, 0x2be6f5d100000000, + 0x8e35a91a00000000, 0x5b87ffeb00000000, 0xfe54a32000000000, + 0x502637a600000000, 0xf5f56b6d00000000, 0x4dc56e7000000000, + 0xe81632bb00000000, 0x4664a63d00000000, 0xe3b7faf600000000, + 0xad077a0400000000, 0x08d426cf00000000, 0xa6a6b24900000000, + 0x0375ee8200000000, 0xbb45eb9f00000000, 0x1e96b75400000000, + 0xb0e423d200000000, 0x15377f1900000000, 0xc08529e800000000, + 0x6556752300000000, 0xcb24e1a500000000, 0x6ef7bd6e00000000, + 0xd6c7b87300000000, 0x7314e4b800000000, 0xdd66703e00000000, + 0x78b52cf500000000, 0x6c0a580f00000000, 0xc9d904c400000000, + 0x67ab904200000000, 0xc278cc8900000000, 0x7a48c99400000000, + 0xdf9b955f00000000, 0x71e901d900000000, 0xd43a5d1200000000, + 0x01880be300000000, 0xa45b572800000000, 0x0a29c3ae00000000, + 0xaffa9f6500000000, 0x17ca9a7800000000, 0xb219c6b300000000, + 0x1c6b523500000000, 0xb9b80efe00000000, 0xf7088e0c00000000, + 0x52dbd2c700000000, 0xfca9464100000000, 0x597a1a8a00000000, + 0xe14a1f9700000000, 0x4499435c00000000, 0xeaebd7da00000000, + 0x4f388b1100000000, 0x9a8adde000000000, 0x3f59812b00000000, + 0x912b15ad00000000, 0x34f8496600000000, 0x8cc84c7b00000000, + 0x291b10b000000000, 0x8769843600000000, 0x22bad8fd00000000, + 0x5a0ff40800000000, 0xffdca8c300000000, 0x51ae3c4500000000, + 0xf47d608e00000000, 0x4c4d659300000000, 0xe99e395800000000, + 0x47ecadde00000000, 0xe23ff11500000000, 0x378da7e400000000, + 0x925efb2f00000000, 0x3c2c6fa900000000, 0x99ff336200000000, + 0x21cf367f00000000, 0x841c6ab400000000, 0x2a6efe3200000000, + 0x8fbda2f900000000, 0xc10d220b00000000, 0x64de7ec000000000, + 0xcaacea4600000000, 0x6f7fb68d00000000, 0xd74fb39000000000, + 0x729cef5b00000000, 0xdcee7bdd00000000, 0x793d271600000000, + 0xac8f71e700000000, 0x095c2d2c00000000, 0xa72eb9aa00000000, + 0x02fde56100000000, 0xbacde07c00000000, 0x1f1ebcb700000000, + 0xb16c283100000000, 0x14bf74fa00000000, 0xd814b01e00000000, + 0x7dc7ecd500000000, 0xd3b5785300000000, 0x7666249800000000, + 0xce56218500000000, 0x6b857d4e00000000, 0xc5f7e9c800000000, + 0x6024b50300000000, 0xb596e3f200000000, 0x1045bf3900000000, + 0xbe372bbf00000000, 0x1be4777400000000, 0xa3d4726900000000, + 0x06072ea200000000, 0xa875ba2400000000, 0x0da6e6ef00000000, + 0x4316661d00000000, 0xe6c53ad600000000, 0x48b7ae5000000000, + 0xed64f29b00000000, 0x5554f78600000000, 0xf087ab4d00000000, + 0x5ef53fcb00000000, 0xfb26630000000000, 0x2e9435f100000000, + 0x8b47693a00000000, 0x2535fdbc00000000, 0x80e6a17700000000, + 0x38d6a46a00000000, 0x9d05f8a100000000, 0x33776c2700000000, + 0x96a430ec00000000, 0xee111c1900000000, 0x4bc240d200000000, + 0xe5b0d45400000000, 0x4063889f00000000, 0xf8538d8200000000, + 0x5d80d14900000000, 0xf3f245cf00000000, 0x5621190400000000, + 0x83934ff500000000, 0x2640133e00000000, 0x883287b800000000, + 0x2de1db7300000000, 0x95d1de6e00000000, 0x300282a500000000, + 0x9e70162300000000, 0x3ba34ae800000000, 0x7513ca1a00000000, + 0xd0c096d100000000, 0x7eb2025700000000, 0xdb615e9c00000000, + 0x63515b8100000000, 0xc682074a00000000, 0x68f093cc00000000, + 0xcd23cf0700000000, 0x189199f600000000, 0xbd42c53d00000000, + 0x133051bb00000000, 0xb6e30d7000000000, 0x0ed3086d00000000, + 0xab0054a600000000, 0x0572c02000000000, 0xa0a19ceb00000000, + 0xb41ee81100000000, 0x11cdb4da00000000, 0xbfbf205c00000000, + 0x1a6c7c9700000000, 0xa25c798a00000000, 0x078f254100000000, + 0xa9fdb1c700000000, 0x0c2eed0c00000000, 0xd99cbbfd00000000, + 0x7c4fe73600000000, 0xd23d73b000000000, 0x77ee2f7b00000000, + 0xcfde2a6600000000, 0x6a0d76ad00000000, 0xc47fe22b00000000, + 0x61acbee000000000, 0x2f1c3e1200000000, 0x8acf62d900000000, + 0x24bdf65f00000000, 0x816eaa9400000000, 0x395eaf8900000000, + 0x9c8df34200000000, 0x32ff67c400000000, 0x972c3b0f00000000, + 0x429e6dfe00000000, 0xe74d313500000000, 0x493fa5b300000000, + 0xececf97800000000, 0x54dcfc6500000000, 0xf10fa0ae00000000, + 0x5f7d342800000000, 0xfaae68e300000000, 0x821b441600000000, + 0x27c818dd00000000, 0x89ba8c5b00000000, 0x2c69d09000000000, + 0x9459d58d00000000, 0x318a894600000000, 0x9ff81dc000000000, + 0x3a2b410b00000000, 0xef9917fa00000000, 0x4a4a4b3100000000, + 0xe438dfb700000000, 0x41eb837c00000000, 0xf9db866100000000, + 0x5c08daaa00000000, 0xf27a4e2c00000000, 0x57a912e700000000, + 0x1919921500000000, 0xbccacede00000000, 0x12b85a5800000000, + 0xb76b069300000000, 0x0f5b038e00000000, 0xaa885f4500000000, + 0x04facbc300000000, 0xa129970800000000, 0x749bc1f900000000, + 0xd1489d3200000000, 0x7f3a09b400000000, 0xdae9557f00000000, + 0x62d9506200000000, 0xc70a0ca900000000, 0x6978982f00000000, + 0xccabc4e400000000}, + {0x0000000000000000, 0xb40b77a600000000, 0x29119f9700000000, + 0x9d1ae83100000000, 0x13244ff400000000, 0xa72f385200000000, + 0x3a35d06300000000, 0x8e3ea7c500000000, 0x674eef3300000000, + 0xd345989500000000, 0x4e5f70a400000000, 0xfa54070200000000, + 0x746aa0c700000000, 0xc061d76100000000, 0x5d7b3f5000000000, + 0xe97048f600000000, 0xce9cde6700000000, 0x7a97a9c100000000, + 0xe78d41f000000000, 0x5386365600000000, 0xddb8919300000000, + 0x69b3e63500000000, 0xf4a90e0400000000, 0x40a279a200000000, + 0xa9d2315400000000, 0x1dd946f200000000, 0x80c3aec300000000, + 0x34c8d96500000000, 0xbaf67ea000000000, 0x0efd090600000000, + 0x93e7e13700000000, 0x27ec969100000000, 0x9c39bdcf00000000, + 0x2832ca6900000000, 0xb528225800000000, 0x012355fe00000000, + 0x8f1df23b00000000, 0x3b16859d00000000, 0xa60c6dac00000000, + 0x12071a0a00000000, 0xfb7752fc00000000, 0x4f7c255a00000000, + 0xd266cd6b00000000, 0x666dbacd00000000, 0xe8531d0800000000, + 0x5c586aae00000000, 0xc142829f00000000, 0x7549f53900000000, + 0x52a563a800000000, 0xe6ae140e00000000, 0x7bb4fc3f00000000, + 0xcfbf8b9900000000, 0x41812c5c00000000, 0xf58a5bfa00000000, + 0x6890b3cb00000000, 0xdc9bc46d00000000, 0x35eb8c9b00000000, + 0x81e0fb3d00000000, 0x1cfa130c00000000, 0xa8f164aa00000000, + 0x26cfc36f00000000, 0x92c4b4c900000000, 0x0fde5cf800000000, + 0xbbd52b5e00000000, 0x79750b4400000000, 0xcd7e7ce200000000, + 0x506494d300000000, 0xe46fe37500000000, 0x6a5144b000000000, + 0xde5a331600000000, 0x4340db2700000000, 0xf74bac8100000000, + 0x1e3be47700000000, 0xaa3093d100000000, 0x372a7be000000000, + 0x83210c4600000000, 0x0d1fab8300000000, 0xb914dc2500000000, + 0x240e341400000000, 0x900543b200000000, 0xb7e9d52300000000, + 0x03e2a28500000000, 0x9ef84ab400000000, 0x2af33d1200000000, + 0xa4cd9ad700000000, 0x10c6ed7100000000, 0x8ddc054000000000, + 0x39d772e600000000, 0xd0a73a1000000000, 0x64ac4db600000000, + 0xf9b6a58700000000, 0x4dbdd22100000000, 0xc38375e400000000, + 0x7788024200000000, 0xea92ea7300000000, 0x5e999dd500000000, + 0xe54cb68b00000000, 0x5147c12d00000000, 0xcc5d291c00000000, + 0x78565eba00000000, 0xf668f97f00000000, 0x42638ed900000000, + 0xdf7966e800000000, 0x6b72114e00000000, 0x820259b800000000, + 0x36092e1e00000000, 0xab13c62f00000000, 0x1f18b18900000000, + 0x9126164c00000000, 0x252d61ea00000000, 0xb83789db00000000, + 0x0c3cfe7d00000000, 0x2bd068ec00000000, 0x9fdb1f4a00000000, + 0x02c1f77b00000000, 0xb6ca80dd00000000, 0x38f4271800000000, + 0x8cff50be00000000, 0x11e5b88f00000000, 0xa5eecf2900000000, + 0x4c9e87df00000000, 0xf895f07900000000, 0x658f184800000000, + 0xd1846fee00000000, 0x5fbac82b00000000, 0xebb1bf8d00000000, + 0x76ab57bc00000000, 0xc2a0201a00000000, 0xf2ea168800000000, + 0x46e1612e00000000, 0xdbfb891f00000000, 0x6ff0feb900000000, + 0xe1ce597c00000000, 0x55c52eda00000000, 0xc8dfc6eb00000000, + 0x7cd4b14d00000000, 0x95a4f9bb00000000, 0x21af8e1d00000000, + 0xbcb5662c00000000, 0x08be118a00000000, 0x8680b64f00000000, + 0x328bc1e900000000, 0xaf9129d800000000, 0x1b9a5e7e00000000, + 0x3c76c8ef00000000, 0x887dbf4900000000, 0x1567577800000000, + 0xa16c20de00000000, 0x2f52871b00000000, 0x9b59f0bd00000000, + 0x0643188c00000000, 0xb2486f2a00000000, 0x5b3827dc00000000, + 0xef33507a00000000, 0x7229b84b00000000, 0xc622cfed00000000, + 0x481c682800000000, 0xfc171f8e00000000, 0x610df7bf00000000, + 0xd506801900000000, 0x6ed3ab4700000000, 0xdad8dce100000000, + 0x47c234d000000000, 0xf3c9437600000000, 0x7df7e4b300000000, + 0xc9fc931500000000, 0x54e67b2400000000, 0xe0ed0c8200000000, + 0x099d447400000000, 0xbd9633d200000000, 0x208cdbe300000000, + 0x9487ac4500000000, 0x1ab90b8000000000, 0xaeb27c2600000000, + 0x33a8941700000000, 0x87a3e3b100000000, 0xa04f752000000000, + 0x1444028600000000, 0x895eeab700000000, 0x3d559d1100000000, + 0xb36b3ad400000000, 0x07604d7200000000, 0x9a7aa54300000000, + 0x2e71d2e500000000, 0xc7019a1300000000, 0x730aedb500000000, + 0xee10058400000000, 0x5a1b722200000000, 0xd425d5e700000000, + 0x602ea24100000000, 0xfd344a7000000000, 0x493f3dd600000000, + 0x8b9f1dcc00000000, 0x3f946a6a00000000, 0xa28e825b00000000, + 0x1685f5fd00000000, 0x98bb523800000000, 0x2cb0259e00000000, + 0xb1aacdaf00000000, 0x05a1ba0900000000, 0xecd1f2ff00000000, + 0x58da855900000000, 0xc5c06d6800000000, 0x71cb1ace00000000, + 0xfff5bd0b00000000, 0x4bfecaad00000000, 0xd6e4229c00000000, + 0x62ef553a00000000, 0x4503c3ab00000000, 0xf108b40d00000000, + 0x6c125c3c00000000, 0xd8192b9a00000000, 0x56278c5f00000000, + 0xe22cfbf900000000, 0x7f3613c800000000, 0xcb3d646e00000000, + 0x224d2c9800000000, 0x96465b3e00000000, 0x0b5cb30f00000000, + 0xbf57c4a900000000, 0x3169636c00000000, 0x856214ca00000000, + 0x1878fcfb00000000, 0xac738b5d00000000, 0x17a6a00300000000, + 0xa3add7a500000000, 0x3eb73f9400000000, 0x8abc483200000000, + 0x0482eff700000000, 0xb089985100000000, 0x2d93706000000000, + 0x999807c600000000, 0x70e84f3000000000, 0xc4e3389600000000, + 0x59f9d0a700000000, 0xedf2a70100000000, 0x63cc00c400000000, + 0xd7c7776200000000, 0x4add9f5300000000, 0xfed6e8f500000000, + 0xd93a7e6400000000, 0x6d3109c200000000, 0xf02be1f300000000, + 0x4420965500000000, 0xca1e319000000000, 0x7e15463600000000, + 0xe30fae0700000000, 0x5704d9a100000000, 0xbe74915700000000, + 0x0a7fe6f100000000, 0x97650ec000000000, 0x236e796600000000, + 0xad50dea300000000, 0x195ba90500000000, 0x8441413400000000, + 0x304a369200000000}, + {0x0000000000000000, 0x9e00aacc00000000, 0x7d07254200000000, + 0xe3078f8e00000000, 0xfa0e4a8400000000, 0x640ee04800000000, + 0x87096fc600000000, 0x1909c50a00000000, 0xb51be5d300000000, + 0x2b1b4f1f00000000, 0xc81cc09100000000, 0x561c6a5d00000000, + 0x4f15af5700000000, 0xd115059b00000000, 0x32128a1500000000, + 0xac1220d900000000, 0x2b31bb7c00000000, 0xb53111b000000000, + 0x56369e3e00000000, 0xc83634f200000000, 0xd13ff1f800000000, + 0x4f3f5b3400000000, 0xac38d4ba00000000, 0x32387e7600000000, + 0x9e2a5eaf00000000, 0x002af46300000000, 0xe32d7bed00000000, + 0x7d2dd12100000000, 0x6424142b00000000, 0xfa24bee700000000, + 0x1923316900000000, 0x87239ba500000000, 0x566276f900000000, + 0xc862dc3500000000, 0x2b6553bb00000000, 0xb565f97700000000, + 0xac6c3c7d00000000, 0x326c96b100000000, 0xd16b193f00000000, + 0x4f6bb3f300000000, 0xe379932a00000000, 0x7d7939e600000000, + 0x9e7eb66800000000, 0x007e1ca400000000, 0x1977d9ae00000000, + 0x8777736200000000, 0x6470fcec00000000, 0xfa70562000000000, + 0x7d53cd8500000000, 0xe353674900000000, 0x0054e8c700000000, + 0x9e54420b00000000, 0x875d870100000000, 0x195d2dcd00000000, + 0xfa5aa24300000000, 0x645a088f00000000, 0xc848285600000000, + 0x5648829a00000000, 0xb54f0d1400000000, 0x2b4fa7d800000000, + 0x324662d200000000, 0xac46c81e00000000, 0x4f41479000000000, + 0xd141ed5c00000000, 0xedc29d2900000000, 0x73c237e500000000, + 0x90c5b86b00000000, 0x0ec512a700000000, 0x17ccd7ad00000000, + 0x89cc7d6100000000, 0x6acbf2ef00000000, 0xf4cb582300000000, + 0x58d978fa00000000, 0xc6d9d23600000000, 0x25de5db800000000, + 0xbbdef77400000000, 0xa2d7327e00000000, 0x3cd798b200000000, + 0xdfd0173c00000000, 0x41d0bdf000000000, 0xc6f3265500000000, + 0x58f38c9900000000, 0xbbf4031700000000, 0x25f4a9db00000000, + 0x3cfd6cd100000000, 0xa2fdc61d00000000, 0x41fa499300000000, + 0xdffae35f00000000, 0x73e8c38600000000, 0xede8694a00000000, + 0x0eefe6c400000000, 0x90ef4c0800000000, 0x89e6890200000000, + 0x17e623ce00000000, 0xf4e1ac4000000000, 0x6ae1068c00000000, + 0xbba0ebd000000000, 0x25a0411c00000000, 0xc6a7ce9200000000, + 0x58a7645e00000000, 0x41aea15400000000, 0xdfae0b9800000000, + 0x3ca9841600000000, 0xa2a92eda00000000, 0x0ebb0e0300000000, + 0x90bba4cf00000000, 0x73bc2b4100000000, 0xedbc818d00000000, + 0xf4b5448700000000, 0x6ab5ee4b00000000, 0x89b261c500000000, + 0x17b2cb0900000000, 0x909150ac00000000, 0x0e91fa6000000000, + 0xed9675ee00000000, 0x7396df2200000000, 0x6a9f1a2800000000, + 0xf49fb0e400000000, 0x17983f6a00000000, 0x899895a600000000, + 0x258ab57f00000000, 0xbb8a1fb300000000, 0x588d903d00000000, + 0xc68d3af100000000, 0xdf84fffb00000000, 0x4184553700000000, + 0xa283dab900000000, 0x3c83707500000000, 0xda853b5300000000, + 0x4485919f00000000, 0xa7821e1100000000, 0x3982b4dd00000000, + 0x208b71d700000000, 0xbe8bdb1b00000000, 0x5d8c549500000000, + 0xc38cfe5900000000, 0x6f9ede8000000000, 0xf19e744c00000000, + 0x1299fbc200000000, 0x8c99510e00000000, 0x9590940400000000, + 0x0b903ec800000000, 0xe897b14600000000, 0x76971b8a00000000, + 0xf1b4802f00000000, 0x6fb42ae300000000, 0x8cb3a56d00000000, + 0x12b30fa100000000, 0x0bbacaab00000000, 0x95ba606700000000, + 0x76bdefe900000000, 0xe8bd452500000000, 0x44af65fc00000000, + 0xdaafcf3000000000, 0x39a840be00000000, 0xa7a8ea7200000000, + 0xbea12f7800000000, 0x20a185b400000000, 0xc3a60a3a00000000, + 0x5da6a0f600000000, 0x8ce74daa00000000, 0x12e7e76600000000, + 0xf1e068e800000000, 0x6fe0c22400000000, 0x76e9072e00000000, + 0xe8e9ade200000000, 0x0bee226c00000000, 0x95ee88a000000000, + 0x39fca87900000000, 0xa7fc02b500000000, 0x44fb8d3b00000000, + 0xdafb27f700000000, 0xc3f2e2fd00000000, 0x5df2483100000000, + 0xbef5c7bf00000000, 0x20f56d7300000000, 0xa7d6f6d600000000, + 0x39d65c1a00000000, 0xdad1d39400000000, 0x44d1795800000000, + 0x5dd8bc5200000000, 0xc3d8169e00000000, 0x20df991000000000, + 0xbedf33dc00000000, 0x12cd130500000000, 0x8ccdb9c900000000, + 0x6fca364700000000, 0xf1ca9c8b00000000, 0xe8c3598100000000, + 0x76c3f34d00000000, 0x95c47cc300000000, 0x0bc4d60f00000000, + 0x3747a67a00000000, 0xa9470cb600000000, 0x4a40833800000000, + 0xd44029f400000000, 0xcd49ecfe00000000, 0x5349463200000000, + 0xb04ec9bc00000000, 0x2e4e637000000000, 0x825c43a900000000, + 0x1c5ce96500000000, 0xff5b66eb00000000, 0x615bcc2700000000, + 0x7852092d00000000, 0xe652a3e100000000, 0x05552c6f00000000, + 0x9b5586a300000000, 0x1c761d0600000000, 0x8276b7ca00000000, + 0x6171384400000000, 0xff71928800000000, 0xe678578200000000, + 0x7878fd4e00000000, 0x9b7f72c000000000, 0x057fd80c00000000, + 0xa96df8d500000000, 0x376d521900000000, 0xd46add9700000000, + 0x4a6a775b00000000, 0x5363b25100000000, 0xcd63189d00000000, + 0x2e64971300000000, 0xb0643ddf00000000, 0x6125d08300000000, + 0xff257a4f00000000, 0x1c22f5c100000000, 0x82225f0d00000000, + 0x9b2b9a0700000000, 0x052b30cb00000000, 0xe62cbf4500000000, + 0x782c158900000000, 0xd43e355000000000, 0x4a3e9f9c00000000, + 0xa939101200000000, 0x3739bade00000000, 0x2e307fd400000000, + 0xb030d51800000000, 0x53375a9600000000, 0xcd37f05a00000000, + 0x4a146bff00000000, 0xd414c13300000000, 0x37134ebd00000000, + 0xa913e47100000000, 0xb01a217b00000000, 0x2e1a8bb700000000, + 0xcd1d043900000000, 0x531daef500000000, 0xff0f8e2c00000000, + 0x610f24e000000000, 0x8208ab6e00000000, 0x1c0801a200000000, + 0x0501c4a800000000, 0x9b016e6400000000, 0x7806e1ea00000000, + 0xe6064b2600000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757, + 0x37def032, 0x256b5fdc, 0x9dd738b9, 0xc5b428ef, 0x7d084f8a, + 0x6fbde064, 0xd7018701, 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, + 0x58631056, 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871, + 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 0x95ad7f70, + 0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42, + 0xb0c620ac, 0x087a47c9, 0xa032af3e, 0x188ec85b, 0x0a3b67b5, + 0xb28700d0, 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787, + 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, 0xeae41086, + 0x525877e3, 0x40edd80d, 0xf851bf68, 0xf02bf8a1, 0x48979fc4, + 0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d, + 0x6dfcc018, 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, + 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, 0x9b14583d, + 0x23a83f58, 0x311d90b6, 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f, + 0xbe7f07e1, 0x06c36084, 0x5ea070d2, 0xe61c17b7, 0xf4a9b859, + 0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b, + 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5, + 0xfcd3ff90, 0xee66507e, 0x56da371b, 0x0eb9274d, 0xb6054028, + 0xa4b0efc6, 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891, + 0x936e1ff4, 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed, + 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, 0xfe92dfec, + 0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, 0xc94c2fde, + 0xdbf98030, 0x6345e755, 0x6b3fa09c, 0xd383c7f9, 0xc1366817, + 0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825, + 0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24, + 0x99557841, 0x8be0d7af, 0x335cb0ca, 0xed59b63b, 0x55e5d15e, + 0x47507eb0, 0xffec19d5, 0x623b216c, 0xda874609, 0xc832e9e7, + 0x708e8e82, 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a, + 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, 0xbd40e1a4, + 0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196, + 0x982bbe78, 0x2097d91d, 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, + 0x6a4166a5, 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2, + 0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, 0xc2098e52, + 0x7ab5e937, 0x680046d9, 0xd0bc21bc, 0x88df31ea, 0x3063568f, + 0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, + 0x15080953, 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, + 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, 0xd8c66675, + 0x607a0110, 0x72cfaefe, 0xca73c99b, 0x57a4f122, 0xef189647, + 0xfdad39a9, 0x45115ecc, 0x764dee06, 0xcef18963, 0xdc44268d, + 0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf, + 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be, + 0x842736db, 0x96929935, 0x2e2efe50, 0x2654b999, 0x9ee8defc, + 0x8c5d7112, 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645, + 0xbb838120, 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98, + 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, 0xd67f4138, + 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, 0xe1a1b10a, + 0xf3141ee4, 0x4ba87981, 0x13cb69d7, 0xab770eb2, 0xb9c2a15c, + 0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e, + 0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0, + 0xb1b8e695, 0xa30d497b, 0x1bb12e1e, 0x43d23e48, 0xfb6e592d, + 0xe9dbf6c3, 0x516791a6, 0xccb0a91f, 0x740cce7a, 0x66b96194, + 0xde0506f1}, + {0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc, + 0x06cbc2eb, 0x048d7cb2, 0x054f1685, 0x0e1351b8, 0x0fd13b8f, + 0x0d9785d6, 0x0c55efe1, 0x091af964, 0x08d89353, 0x0a9e2d0a, + 0x0b5c473d, 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29, + 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 0x1235f2c8, + 0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023, + 0x16b88e7a, 0x177ae44d, 0x384d46e0, 0x398f2cd7, 0x3bc9928e, + 0x3a0bf8b9, 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065, + 0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, 0x3157bf84, + 0x3095d5b3, 0x32d36bea, 0x331101dd, 0x246be590, 0x25a98fa7, + 0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922, + 0x2124f315, 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, + 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, 0x709a8dc0, + 0x7158e7f7, 0x731e59ae, 0x72dc3399, 0x7793251c, 0x76514f2b, + 0x7417f172, 0x75d59b45, 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816, + 0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd, + 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c, + 0x6a77ec5b, 0x68315202, 0x69f33835, 0x62af7f08, 0x636d153f, + 0x612bab66, 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba, + 0x67e0698d, 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579, + 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, 0x46c49a98, + 0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, 0x400f5873, + 0x4249e62a, 0x438b8c1d, 0x54f16850, 0x55330267, 0x5775bc3e, + 0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5, + 0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134, + 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, 0xe1351b80, 0xe0f771b7, + 0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, 0xe7fed96b, 0xe5b86732, + 0xe47a0d05, 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461, + 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, 0xfd13b8f0, + 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b, + 0xf99ec442, 0xf85cae75, 0xf300e948, 0xf2c2837f, 0xf0843d26, + 0xf1465711, 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd, + 0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, 0xde71f5bc, + 0xdfb39f8b, 0xddf521d2, 0xdc374be5, 0xd76b0cd8, 0xd6a966ef, + 0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a, + 0xd2241a5d, 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, + 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, 0xcb4dafa8, + 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, 0xcc440774, 0xcd866d43, + 0xcfc0d31a, 0xce02b92d, 0x91af9640, 0x906dfc77, 0x922b422e, + 0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5, + 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24, + 0x99770513, 0x9b31bb4a, 0x9af3d17d, 0x8d893530, 0x8c4b5f07, + 0x8e0de15e, 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982, + 0x88c623b5, 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1, + 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, 0xa9e2d0a0, + 0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, 0xaf29124b, + 0xad6fac12, 0xacadc625, 0xa7f18118, 0xa633eb2f, 0xa4755576, + 0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d, + 0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c, + 0xb30fb13b, 0xb1490f62, 0xb08b6555, 0xbbd72268, 0xba15485f, + 0xb853f606, 0xb9919c31, 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda, + 0xbe9834ed}, + {0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504, + 0x7d77f445, 0x565aa786, 0x4f4196c7, 0xc8d98a08, 0xd1c2bb49, + 0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e, + 0x87981ccf, 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192, + 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 0x821b9859, + 0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c, + 0xd4413fdf, 0xcd5a0e9e, 0x958424a2, 0x8c9f15e3, 0xa7b24620, + 0xbea97761, 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265, + 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, 0x39316bae, + 0x202a5aef, 0x0b07092c, 0x121c386d, 0xdf4636f3, 0xc65d07b2, + 0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175, + 0x9007a034, 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, + 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, 0xf0794f05, + 0xe9627e44, 0xc24f2d87, 0xdb541cc6, 0x94158a01, 0x8d0ebb40, + 0xa623e883, 0xbf38d9c2, 0x38a0c50d, 0x21bbf44c, 0x0a96a78f, + 0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca, + 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850, + 0xc7cca911, 0xece1fad2, 0xf5facb93, 0x7262d75c, 0x6b79e61d, + 0x4054b5de, 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da, + 0x3d23419b, 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864, + 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, 0xad24e1af, + 0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, 0xd05315ea, + 0xfb7e4629, 0xe2657768, 0x2f3f79f6, 0x362448b7, 0x1d091b74, + 0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31, + 0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa, + 0x9a9107bb, 0xb1bc5478, 0xa8a76539, 0x3b83984b, 0x2298a90a, + 0x09b5fac9, 0x10aecb88, 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd, + 0x74c20e8c, 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180, + 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, 0x71418a1a, + 0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f, + 0x271b2d9c, 0x3e001cdd, 0xb9980012, 0xa0833153, 0x8bae6290, + 0x92b553d1, 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5, + 0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, 0xca6b79ed, + 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 0x66de36e1, 0x7fc507a0, + 0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, + 0x299fa026, 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, + 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, 0x2c1c24b0, + 0x350715f1, 0x1e2a4632, 0x07317773, 0x4870e1b4, 0x516bd0f5, + 0x7a468336, 0x635db277, 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc, + 0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189, + 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842, + 0x7e54a903, 0x5579fac0, 0x4c62cb81, 0x8138c51f, 0x9823f45e, + 0xb30ea79d, 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299, + 0xce7953d8, 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, + 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, 0x5e7ef3ec, + 0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, 0x230907a9, + 0x0824546a, 0x113f652b, 0x96a779e4, 0x8fbc48a5, 0xa4911b66, + 0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23, + 0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9, + 0x69cb15f8, 0x42e6463b, 0x5bfd777a, 0xdc656bb5, 0xc57e5af4, + 0xee530937, 0xf7483876, 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33, + 0x9324fd72}, + {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x96300777, 0x2c610eee, 0xba510999, 0x19c46d07, + 0x8ff46a70, 0x35a563e9, 0xa395649e, 0x3288db0e, 0xa4b8dc79, + 0x1ee9d5e0, 0x88d9d297, 0x2b4cb609, 0xbd7cb17e, 0x072db8e7, + 0x911dbf90, 0x6410b71d, 0xf220b06a, 0x4871b9f3, 0xde41be84, + 0x7dd4da1a, 0xebe4dd6d, 0x51b5d4f4, 0xc785d383, 0x56986c13, + 0xc0a86b64, 0x7af962fd, 0xecc9658a, 0x4f5c0114, 0xd96c0663, + 0x633d0ffa, 0xf50d088d, 0xc8206e3b, 0x5e10694c, 0xe44160d5, + 0x727167a2, 0xd1e4033c, 0x47d4044b, 0xfd850dd2, 0x6bb50aa5, + 0xfaa8b535, 0x6c98b242, 0xd6c9bbdb, 0x40f9bcac, 0xe36cd832, + 0x755cdf45, 0xcf0dd6dc, 0x593dd1ab, 0xac30d926, 0x3a00de51, + 0x8051d7c8, 0x1661d0bf, 0xb5f4b421, 0x23c4b356, 0x9995bacf, + 0x0fa5bdb8, 0x9eb80228, 0x0888055f, 0xb2d90cc6, 0x24e90bb1, + 0x877c6f2f, 0x114c6858, 0xab1d61c1, 0x3d2d66b6, 0x9041dc76, + 0x0671db01, 0xbc20d298, 0x2a10d5ef, 0x8985b171, 0x1fb5b606, + 0xa5e4bf9f, 0x33d4b8e8, 0xa2c90778, 0x34f9000f, 0x8ea80996, + 0x18980ee1, 0xbb0d6a7f, 0x2d3d6d08, 0x976c6491, 0x015c63e6, + 0xf4516b6b, 0x62616c1c, 0xd8306585, 0x4e0062f2, 0xed95066c, + 0x7ba5011b, 0xc1f40882, 0x57c40ff5, 0xc6d9b065, 0x50e9b712, + 0xeab8be8b, 0x7c88b9fc, 0xdf1ddd62, 0x492dda15, 0xf37cd38c, + 0x654cd4fb, 0x5861b24d, 0xce51b53a, 0x7400bca3, 0xe230bbd4, + 0x41a5df4a, 0xd795d83d, 0x6dc4d1a4, 0xfbf4d6d3, 0x6ae96943, + 0xfcd96e34, 0x468867ad, 0xd0b860da, 0x732d0444, 0xe51d0333, + 0x5f4c0aaa, 0xc97c0ddd, 0x3c710550, 0xaa410227, 0x10100bbe, + 0x86200cc9, 0x25b56857, 0xb3856f20, 0x09d466b9, 0x9fe461ce, + 0x0ef9de5e, 0x98c9d929, 0x2298d0b0, 0xb4a8d7c7, 0x173db359, + 0x810db42e, 0x3b5cbdb7, 0xad6cbac0, 0x2083b8ed, 0xb6b3bf9a, + 0x0ce2b603, 0x9ad2b174, 0x3947d5ea, 0xaf77d29d, 0x1526db04, + 0x8316dc73, 0x120b63e3, 0x843b6494, 0x3e6a6d0d, 0xa85a6a7a, + 0x0bcf0ee4, 0x9dff0993, 0x27ae000a, 0xb19e077d, 0x44930ff0, + 0xd2a30887, 0x68f2011e, 0xfec20669, 0x5d5762f7, 0xcb676580, + 0x71366c19, 0xe7066b6e, 0x761bd4fe, 0xe02bd389, 0x5a7ada10, + 0xcc4add67, 0x6fdfb9f9, 0xf9efbe8e, 0x43beb717, 0xd58eb060, + 0xe8a3d6d6, 0x7e93d1a1, 0xc4c2d838, 0x52f2df4f, 0xf167bbd1, + 0x6757bca6, 0xdd06b53f, 0x4b36b248, 0xda2b0dd8, 0x4c1b0aaf, + 0xf64a0336, 0x607a0441, 0xc3ef60df, 0x55df67a8, 0xef8e6e31, + 0x79be6946, 0x8cb361cb, 0x1a8366bc, 0xa0d26f25, 0x36e26852, + 0x95770ccc, 0x03470bbb, 0xb9160222, 0x2f260555, 0xbe3bbac5, + 0x280bbdb2, 0x925ab42b, 0x046ab35c, 0xa7ffd7c2, 0x31cfd0b5, + 0x8b9ed92c, 0x1daede5b, 0xb0c2649b, 0x26f263ec, 0x9ca36a75, + 0x0a936d02, 0xa906099c, 0x3f360eeb, 0x85670772, 0x13570005, + 0x824abf95, 0x147ab8e2, 0xae2bb17b, 0x381bb60c, 0x9b8ed292, + 0x0dbed5e5, 0xb7efdc7c, 0x21dfdb0b, 0xd4d2d386, 0x42e2d4f1, + 0xf8b3dd68, 0x6e83da1f, 0xcd16be81, 0x5b26b9f6, 0xe177b06f, + 0x7747b718, 0xe65a0888, 0x706a0fff, 0xca3b0666, 0x5c0b0111, + 0xff9e658f, 0x69ae62f8, 0xd3ff6b61, 0x45cf6c16, 0x78e20aa0, + 0xeed20dd7, 0x5483044e, 0xc2b30339, 0x612667a7, 0xf71660d0, + 0x4d476949, 0xdb776e3e, 0x4a6ad1ae, 0xdc5ad6d9, 0x660bdf40, + 0xf03bd837, 0x53aebca9, 0xc59ebbde, 0x7fcfb247, 0xe9ffb530, + 0x1cf2bdbd, 0x8ac2baca, 0x3093b353, 0xa6a3b424, 0x0536d0ba, + 0x9306d7cd, 0x2957de54, 0xbf67d923, 0x2e7a66b3, 0xb84a61c4, + 0x021b685d, 0x942b6f2a, 0x37be0bb4, 0xa18e0cc3, 0x1bdf055a, + 0x8def022d}, + {0x00000000, 0x41311b19, 0x82623632, 0xc3532d2b, 0x04c56c64, + 0x45f4777d, 0x86a75a56, 0xc796414f, 0x088ad9c8, 0x49bbc2d1, + 0x8ae8effa, 0xcbd9f4e3, 0x0c4fb5ac, 0x4d7eaeb5, 0x8e2d839e, + 0xcf1c9887, 0x5112c24a, 0x1023d953, 0xd370f478, 0x9241ef61, + 0x55d7ae2e, 0x14e6b537, 0xd7b5981c, 0x96848305, 0x59981b82, + 0x18a9009b, 0xdbfa2db0, 0x9acb36a9, 0x5d5d77e6, 0x1c6c6cff, + 0xdf3f41d4, 0x9e0e5acd, 0xa2248495, 0xe3159f8c, 0x2046b2a7, + 0x6177a9be, 0xa6e1e8f1, 0xe7d0f3e8, 0x2483dec3, 0x65b2c5da, + 0xaaae5d5d, 0xeb9f4644, 0x28cc6b6f, 0x69fd7076, 0xae6b3139, + 0xef5a2a20, 0x2c09070b, 0x6d381c12, 0xf33646df, 0xb2075dc6, + 0x715470ed, 0x30656bf4, 0xf7f32abb, 0xb6c231a2, 0x75911c89, + 0x34a00790, 0xfbbc9f17, 0xba8d840e, 0x79dea925, 0x38efb23c, + 0xff79f373, 0xbe48e86a, 0x7d1bc541, 0x3c2ade58, 0x054f79f0, + 0x447e62e9, 0x872d4fc2, 0xc61c54db, 0x018a1594, 0x40bb0e8d, + 0x83e823a6, 0xc2d938bf, 0x0dc5a038, 0x4cf4bb21, 0x8fa7960a, + 0xce968d13, 0x0900cc5c, 0x4831d745, 0x8b62fa6e, 0xca53e177, + 0x545dbbba, 0x156ca0a3, 0xd63f8d88, 0x970e9691, 0x5098d7de, + 0x11a9ccc7, 0xd2fae1ec, 0x93cbfaf5, 0x5cd76272, 0x1de6796b, + 0xdeb55440, 0x9f844f59, 0x58120e16, 0x1923150f, 0xda703824, + 0x9b41233d, 0xa76bfd65, 0xe65ae67c, 0x2509cb57, 0x6438d04e, + 0xa3ae9101, 0xe29f8a18, 0x21cca733, 0x60fdbc2a, 0xafe124ad, + 0xeed03fb4, 0x2d83129f, 0x6cb20986, 0xab2448c9, 0xea1553d0, + 0x29467efb, 0x687765e2, 0xf6793f2f, 0xb7482436, 0x741b091d, + 0x352a1204, 0xf2bc534b, 0xb38d4852, 0x70de6579, 0x31ef7e60, + 0xfef3e6e7, 0xbfc2fdfe, 0x7c91d0d5, 0x3da0cbcc, 0xfa368a83, + 0xbb07919a, 0x7854bcb1, 0x3965a7a8, 0x4b98833b, 0x0aa99822, + 0xc9fab509, 0x88cbae10, 0x4f5def5f, 0x0e6cf446, 0xcd3fd96d, + 0x8c0ec274, 0x43125af3, 0x022341ea, 0xc1706cc1, 0x804177d8, + 0x47d73697, 0x06e62d8e, 0xc5b500a5, 0x84841bbc, 0x1a8a4171, + 0x5bbb5a68, 0x98e87743, 0xd9d96c5a, 0x1e4f2d15, 0x5f7e360c, + 0x9c2d1b27, 0xdd1c003e, 0x120098b9, 0x533183a0, 0x9062ae8b, + 0xd153b592, 0x16c5f4dd, 0x57f4efc4, 0x94a7c2ef, 0xd596d9f6, + 0xe9bc07ae, 0xa88d1cb7, 0x6bde319c, 0x2aef2a85, 0xed796bca, + 0xac4870d3, 0x6f1b5df8, 0x2e2a46e1, 0xe136de66, 0xa007c57f, + 0x6354e854, 0x2265f34d, 0xe5f3b202, 0xa4c2a91b, 0x67918430, + 0x26a09f29, 0xb8aec5e4, 0xf99fdefd, 0x3accf3d6, 0x7bfde8cf, + 0xbc6ba980, 0xfd5ab299, 0x3e099fb2, 0x7f3884ab, 0xb0241c2c, + 0xf1150735, 0x32462a1e, 0x73773107, 0xb4e17048, 0xf5d06b51, + 0x3683467a, 0x77b25d63, 0x4ed7facb, 0x0fe6e1d2, 0xccb5ccf9, + 0x8d84d7e0, 0x4a1296af, 0x0b238db6, 0xc870a09d, 0x8941bb84, + 0x465d2303, 0x076c381a, 0xc43f1531, 0x850e0e28, 0x42984f67, + 0x03a9547e, 0xc0fa7955, 0x81cb624c, 0x1fc53881, 0x5ef42398, + 0x9da70eb3, 0xdc9615aa, 0x1b0054e5, 0x5a314ffc, 0x996262d7, + 0xd85379ce, 0x174fe149, 0x567efa50, 0x952dd77b, 0xd41ccc62, + 0x138a8d2d, 0x52bb9634, 0x91e8bb1f, 0xd0d9a006, 0xecf37e5e, + 0xadc26547, 0x6e91486c, 0x2fa05375, 0xe836123a, 0xa9070923, + 0x6a542408, 0x2b653f11, 0xe479a796, 0xa548bc8f, 0x661b91a4, + 0x272a8abd, 0xe0bccbf2, 0xa18dd0eb, 0x62defdc0, 0x23efe6d9, + 0xbde1bc14, 0xfcd0a70d, 0x3f838a26, 0x7eb2913f, 0xb924d070, + 0xf815cb69, 0x3b46e642, 0x7a77fd5b, 0xb56b65dc, 0xf45a7ec5, + 0x370953ee, 0x763848f7, 0xb1ae09b8, 0xf09f12a1, 0x33cc3f8a, + 0x72fd2493}, + {0x00000000, 0x376ac201, 0x6ed48403, 0x59be4602, 0xdca80907, + 0xebc2cb06, 0xb27c8d04, 0x85164f05, 0xb851130e, 0x8f3bd10f, + 0xd685970d, 0xe1ef550c, 0x64f91a09, 0x5393d808, 0x0a2d9e0a, + 0x3d475c0b, 0x70a3261c, 0x47c9e41d, 0x1e77a21f, 0x291d601e, + 0xac0b2f1b, 0x9b61ed1a, 0xc2dfab18, 0xf5b56919, 0xc8f23512, + 0xff98f713, 0xa626b111, 0x914c7310, 0x145a3c15, 0x2330fe14, + 0x7a8eb816, 0x4de47a17, 0xe0464d38, 0xd72c8f39, 0x8e92c93b, + 0xb9f80b3a, 0x3cee443f, 0x0b84863e, 0x523ac03c, 0x6550023d, + 0x58175e36, 0x6f7d9c37, 0x36c3da35, 0x01a91834, 0x84bf5731, + 0xb3d59530, 0xea6bd332, 0xdd011133, 0x90e56b24, 0xa78fa925, + 0xfe31ef27, 0xc95b2d26, 0x4c4d6223, 0x7b27a022, 0x2299e620, + 0x15f32421, 0x28b4782a, 0x1fdeba2b, 0x4660fc29, 0x710a3e28, + 0xf41c712d, 0xc376b32c, 0x9ac8f52e, 0xada2372f, 0xc08d9a70, + 0xf7e75871, 0xae591e73, 0x9933dc72, 0x1c259377, 0x2b4f5176, + 0x72f11774, 0x459bd575, 0x78dc897e, 0x4fb64b7f, 0x16080d7d, + 0x2162cf7c, 0xa4748079, 0x931e4278, 0xcaa0047a, 0xfdcac67b, + 0xb02ebc6c, 0x87447e6d, 0xdefa386f, 0xe990fa6e, 0x6c86b56b, + 0x5bec776a, 0x02523168, 0x3538f369, 0x087faf62, 0x3f156d63, + 0x66ab2b61, 0x51c1e960, 0xd4d7a665, 0xe3bd6464, 0xba032266, + 0x8d69e067, 0x20cbd748, 0x17a11549, 0x4e1f534b, 0x7975914a, + 0xfc63de4f, 0xcb091c4e, 0x92b75a4c, 0xa5dd984d, 0x989ac446, + 0xaff00647, 0xf64e4045, 0xc1248244, 0x4432cd41, 0x73580f40, + 0x2ae64942, 0x1d8c8b43, 0x5068f154, 0x67023355, 0x3ebc7557, + 0x09d6b756, 0x8cc0f853, 0xbbaa3a52, 0xe2147c50, 0xd57ebe51, + 0xe839e25a, 0xdf53205b, 0x86ed6659, 0xb187a458, 0x3491eb5d, + 0x03fb295c, 0x5a456f5e, 0x6d2fad5f, 0x801b35e1, 0xb771f7e0, + 0xeecfb1e2, 0xd9a573e3, 0x5cb33ce6, 0x6bd9fee7, 0x3267b8e5, + 0x050d7ae4, 0x384a26ef, 0x0f20e4ee, 0x569ea2ec, 0x61f460ed, + 0xe4e22fe8, 0xd388ede9, 0x8a36abeb, 0xbd5c69ea, 0xf0b813fd, + 0xc7d2d1fc, 0x9e6c97fe, 0xa90655ff, 0x2c101afa, 0x1b7ad8fb, + 0x42c49ef9, 0x75ae5cf8, 0x48e900f3, 0x7f83c2f2, 0x263d84f0, + 0x115746f1, 0x944109f4, 0xa32bcbf5, 0xfa958df7, 0xcdff4ff6, + 0x605d78d9, 0x5737bad8, 0x0e89fcda, 0x39e33edb, 0xbcf571de, + 0x8b9fb3df, 0xd221f5dd, 0xe54b37dc, 0xd80c6bd7, 0xef66a9d6, + 0xb6d8efd4, 0x81b22dd5, 0x04a462d0, 0x33cea0d1, 0x6a70e6d3, + 0x5d1a24d2, 0x10fe5ec5, 0x27949cc4, 0x7e2adac6, 0x494018c7, + 0xcc5657c2, 0xfb3c95c3, 0xa282d3c1, 0x95e811c0, 0xa8af4dcb, + 0x9fc58fca, 0xc67bc9c8, 0xf1110bc9, 0x740744cc, 0x436d86cd, + 0x1ad3c0cf, 0x2db902ce, 0x4096af91, 0x77fc6d90, 0x2e422b92, + 0x1928e993, 0x9c3ea696, 0xab546497, 0xf2ea2295, 0xc580e094, + 0xf8c7bc9f, 0xcfad7e9e, 0x9613389c, 0xa179fa9d, 0x246fb598, + 0x13057799, 0x4abb319b, 0x7dd1f39a, 0x3035898d, 0x075f4b8c, + 0x5ee10d8e, 0x698bcf8f, 0xec9d808a, 0xdbf7428b, 0x82490489, + 0xb523c688, 0x88649a83, 0xbf0e5882, 0xe6b01e80, 0xd1dadc81, + 0x54cc9384, 0x63a65185, 0x3a181787, 0x0d72d586, 0xa0d0e2a9, + 0x97ba20a8, 0xce0466aa, 0xf96ea4ab, 0x7c78ebae, 0x4b1229af, + 0x12ac6fad, 0x25c6adac, 0x1881f1a7, 0x2feb33a6, 0x765575a4, + 0x413fb7a5, 0xc429f8a0, 0xf3433aa1, 0xaafd7ca3, 0x9d97bea2, + 0xd073c4b5, 0xe71906b4, 0xbea740b6, 0x89cd82b7, 0x0cdbcdb2, + 0x3bb10fb3, 0x620f49b1, 0x55658bb0, 0x6822d7bb, 0x5f4815ba, + 0x06f653b8, 0x319c91b9, 0xb48adebc, 0x83e01cbd, 0xda5e5abf, + 0xed3498be}, + {0x00000000, 0x6567bcb8, 0x8bc809aa, 0xeeafb512, 0x5797628f, + 0x32f0de37, 0xdc5f6b25, 0xb938d79d, 0xef28b4c5, 0x8a4f087d, + 0x64e0bd6f, 0x018701d7, 0xb8bfd64a, 0xddd86af2, 0x3377dfe0, + 0x56106358, 0x9f571950, 0xfa30a5e8, 0x149f10fa, 0x71f8ac42, + 0xc8c07bdf, 0xada7c767, 0x43087275, 0x266fcecd, 0x707fad95, + 0x1518112d, 0xfbb7a43f, 0x9ed01887, 0x27e8cf1a, 0x428f73a2, + 0xac20c6b0, 0xc9477a08, 0x3eaf32a0, 0x5bc88e18, 0xb5673b0a, + 0xd00087b2, 0x6938502f, 0x0c5fec97, 0xe2f05985, 0x8797e53d, + 0xd1878665, 0xb4e03add, 0x5a4f8fcf, 0x3f283377, 0x8610e4ea, + 0xe3775852, 0x0dd8ed40, 0x68bf51f8, 0xa1f82bf0, 0xc49f9748, + 0x2a30225a, 0x4f579ee2, 0xf66f497f, 0x9308f5c7, 0x7da740d5, + 0x18c0fc6d, 0x4ed09f35, 0x2bb7238d, 0xc518969f, 0xa07f2a27, + 0x1947fdba, 0x7c204102, 0x928ff410, 0xf7e848a8, 0x3d58149b, + 0x583fa823, 0xb6901d31, 0xd3f7a189, 0x6acf7614, 0x0fa8caac, + 0xe1077fbe, 0x8460c306, 0xd270a05e, 0xb7171ce6, 0x59b8a9f4, + 0x3cdf154c, 0x85e7c2d1, 0xe0807e69, 0x0e2fcb7b, 0x6b4877c3, + 0xa20f0dcb, 0xc768b173, 0x29c70461, 0x4ca0b8d9, 0xf5986f44, + 0x90ffd3fc, 0x7e5066ee, 0x1b37da56, 0x4d27b90e, 0x284005b6, + 0xc6efb0a4, 0xa3880c1c, 0x1ab0db81, 0x7fd76739, 0x9178d22b, + 0xf41f6e93, 0x03f7263b, 0x66909a83, 0x883f2f91, 0xed589329, + 0x546044b4, 0x3107f80c, 0xdfa84d1e, 0xbacff1a6, 0xecdf92fe, + 0x89b82e46, 0x67179b54, 0x027027ec, 0xbb48f071, 0xde2f4cc9, + 0x3080f9db, 0x55e74563, 0x9ca03f6b, 0xf9c783d3, 0x176836c1, + 0x720f8a79, 0xcb375de4, 0xae50e15c, 0x40ff544e, 0x2598e8f6, + 0x73888bae, 0x16ef3716, 0xf8408204, 0x9d273ebc, 0x241fe921, + 0x41785599, 0xafd7e08b, 0xcab05c33, 0x3bb659ed, 0x5ed1e555, + 0xb07e5047, 0xd519ecff, 0x6c213b62, 0x094687da, 0xe7e932c8, + 0x828e8e70, 0xd49eed28, 0xb1f95190, 0x5f56e482, 0x3a31583a, + 0x83098fa7, 0xe66e331f, 0x08c1860d, 0x6da63ab5, 0xa4e140bd, + 0xc186fc05, 0x2f294917, 0x4a4ef5af, 0xf3762232, 0x96119e8a, + 0x78be2b98, 0x1dd99720, 0x4bc9f478, 0x2eae48c0, 0xc001fdd2, + 0xa566416a, 0x1c5e96f7, 0x79392a4f, 0x97969f5d, 0xf2f123e5, + 0x05196b4d, 0x607ed7f5, 0x8ed162e7, 0xebb6de5f, 0x528e09c2, + 0x37e9b57a, 0xd9460068, 0xbc21bcd0, 0xea31df88, 0x8f566330, + 0x61f9d622, 0x049e6a9a, 0xbda6bd07, 0xd8c101bf, 0x366eb4ad, + 0x53090815, 0x9a4e721d, 0xff29cea5, 0x11867bb7, 0x74e1c70f, + 0xcdd91092, 0xa8beac2a, 0x46111938, 0x2376a580, 0x7566c6d8, + 0x10017a60, 0xfeaecf72, 0x9bc973ca, 0x22f1a457, 0x479618ef, + 0xa939adfd, 0xcc5e1145, 0x06ee4d76, 0x6389f1ce, 0x8d2644dc, + 0xe841f864, 0x51792ff9, 0x341e9341, 0xdab12653, 0xbfd69aeb, + 0xe9c6f9b3, 0x8ca1450b, 0x620ef019, 0x07694ca1, 0xbe519b3c, + 0xdb362784, 0x35999296, 0x50fe2e2e, 0x99b95426, 0xfcdee89e, + 0x12715d8c, 0x7716e134, 0xce2e36a9, 0xab498a11, 0x45e63f03, + 0x208183bb, 0x7691e0e3, 0x13f65c5b, 0xfd59e949, 0x983e55f1, + 0x2106826c, 0x44613ed4, 0xaace8bc6, 0xcfa9377e, 0x38417fd6, + 0x5d26c36e, 0xb389767c, 0xd6eecac4, 0x6fd61d59, 0x0ab1a1e1, + 0xe41e14f3, 0x8179a84b, 0xd769cb13, 0xb20e77ab, 0x5ca1c2b9, + 0x39c67e01, 0x80fea99c, 0xe5991524, 0x0b36a036, 0x6e511c8e, + 0xa7166686, 0xc271da3e, 0x2cde6f2c, 0x49b9d394, 0xf0810409, + 0x95e6b8b1, 0x7b490da3, 0x1e2eb11b, 0x483ed243, 0x2d596efb, + 0xc3f6dbe9, 0xa6916751, 0x1fa9b0cc, 0x7ace0c74, 0x9461b966, + 0xf10605de}}; + +#endif + +#endif + +#if N == 2 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xae689191, 0x87a02563, 0x29c8b4f2, 0xd4314c87, + 0x7a59dd16, 0x539169e4, 0xfdf9f875, 0x73139f4f, 0xdd7b0ede, + 0xf4b3ba2c, 0x5adb2bbd, 0xa722d3c8, 0x094a4259, 0x2082f6ab, + 0x8eea673a, 0xe6273e9e, 0x484faf0f, 0x61871bfd, 0xcfef8a6c, + 0x32167219, 0x9c7ee388, 0xb5b6577a, 0x1bdec6eb, 0x9534a1d1, + 0x3b5c3040, 0x129484b2, 0xbcfc1523, 0x4105ed56, 0xef6d7cc7, + 0xc6a5c835, 0x68cd59a4, 0x173f7b7d, 0xb957eaec, 0x909f5e1e, + 0x3ef7cf8f, 0xc30e37fa, 0x6d66a66b, 0x44ae1299, 0xeac68308, + 0x642ce432, 0xca4475a3, 0xe38cc151, 0x4de450c0, 0xb01da8b5, + 0x1e753924, 0x37bd8dd6, 0x99d51c47, 0xf11845e3, 0x5f70d472, + 0x76b86080, 0xd8d0f111, 0x25290964, 0x8b4198f5, 0xa2892c07, + 0x0ce1bd96, 0x820bdaac, 0x2c634b3d, 0x05abffcf, 0xabc36e5e, + 0x563a962b, 0xf85207ba, 0xd19ab348, 0x7ff222d9, 0x2e7ef6fa, + 0x8016676b, 0xa9ded399, 0x07b64208, 0xfa4fba7d, 0x54272bec, + 0x7def9f1e, 0xd3870e8f, 0x5d6d69b5, 0xf305f824, 0xdacd4cd6, + 0x74a5dd47, 0x895c2532, 0x2734b4a3, 0x0efc0051, 0xa09491c0, + 0xc859c864, 0x663159f5, 0x4ff9ed07, 0xe1917c96, 0x1c6884e3, + 0xb2001572, 0x9bc8a180, 0x35a03011, 0xbb4a572b, 0x1522c6ba, + 0x3cea7248, 0x9282e3d9, 0x6f7b1bac, 0xc1138a3d, 0xe8db3ecf, + 0x46b3af5e, 0x39418d87, 0x97291c16, 0xbee1a8e4, 0x10893975, + 0xed70c100, 0x43185091, 0x6ad0e463, 0xc4b875f2, 0x4a5212c8, + 0xe43a8359, 0xcdf237ab, 0x639aa63a, 0x9e635e4f, 0x300bcfde, + 0x19c37b2c, 0xb7abeabd, 0xdf66b319, 0x710e2288, 0x58c6967a, + 0xf6ae07eb, 0x0b57ff9e, 0xa53f6e0f, 0x8cf7dafd, 0x229f4b6c, + 0xac752c56, 0x021dbdc7, 0x2bd50935, 0x85bd98a4, 0x784460d1, + 0xd62cf140, 0xffe445b2, 0x518cd423, 0x5cfdedf4, 0xf2957c65, + 0xdb5dc897, 0x75355906, 0x88cca173, 0x26a430e2, 0x0f6c8410, + 0xa1041581, 0x2fee72bb, 0x8186e32a, 0xa84e57d8, 0x0626c649, + 0xfbdf3e3c, 0x55b7afad, 0x7c7f1b5f, 0xd2178ace, 0xbadad36a, + 0x14b242fb, 0x3d7af609, 0x93126798, 0x6eeb9fed, 0xc0830e7c, + 0xe94bba8e, 0x47232b1f, 0xc9c94c25, 0x67a1ddb4, 0x4e696946, + 0xe001f8d7, 0x1df800a2, 0xb3909133, 0x9a5825c1, 0x3430b450, + 0x4bc29689, 0xe5aa0718, 0xcc62b3ea, 0x620a227b, 0x9ff3da0e, + 0x319b4b9f, 0x1853ff6d, 0xb63b6efc, 0x38d109c6, 0x96b99857, + 0xbf712ca5, 0x1119bd34, 0xece04541, 0x4288d4d0, 0x6b406022, + 0xc528f1b3, 0xade5a817, 0x038d3986, 0x2a458d74, 0x842d1ce5, + 0x79d4e490, 0xd7bc7501, 0xfe74c1f3, 0x501c5062, 0xdef63758, + 0x709ea6c9, 0x5956123b, 0xf73e83aa, 0x0ac77bdf, 0xa4afea4e, + 0x8d675ebc, 0x230fcf2d, 0x72831b0e, 0xdceb8a9f, 0xf5233e6d, + 0x5b4baffc, 0xa6b25789, 0x08dac618, 0x211272ea, 0x8f7ae37b, + 0x01908441, 0xaff815d0, 0x8630a122, 0x285830b3, 0xd5a1c8c6, + 0x7bc95957, 0x5201eda5, 0xfc697c34, 0x94a42590, 0x3accb401, + 0x130400f3, 0xbd6c9162, 0x40956917, 0xeefdf886, 0xc7354c74, + 0x695ddde5, 0xe7b7badf, 0x49df2b4e, 0x60179fbc, 0xce7f0e2d, + 0x3386f658, 0x9dee67c9, 0xb426d33b, 0x1a4e42aa, 0x65bc6073, + 0xcbd4f1e2, 0xe21c4510, 0x4c74d481, 0xb18d2cf4, 0x1fe5bd65, + 0x362d0997, 0x98459806, 0x16afff3c, 0xb8c76ead, 0x910fda5f, + 0x3f674bce, 0xc29eb3bb, 0x6cf6222a, 0x453e96d8, 0xeb560749, + 0x839b5eed, 0x2df3cf7c, 0x043b7b8e, 0xaa53ea1f, 0x57aa126a, + 0xf9c283fb, 0xd00a3709, 0x7e62a698, 0xf088c1a2, 0x5ee05033, + 0x7728e4c1, 0xd9407550, 0x24b98d25, 0x8ad11cb4, 0xa319a846, + 0x0d7139d7}, + {0x00000000, 0xb9fbdbe8, 0xa886b191, 0x117d6a79, 0x8a7c6563, + 0x3387be8b, 0x22fad4f2, 0x9b010f1a, 0xcf89cc87, 0x7672176f, + 0x670f7d16, 0xdef4a6fe, 0x45f5a9e4, 0xfc0e720c, 0xed731875, + 0x5488c39d, 0x44629f4f, 0xfd9944a7, 0xece42ede, 0x551ff536, + 0xce1efa2c, 0x77e521c4, 0x66984bbd, 0xdf639055, 0x8beb53c8, + 0x32108820, 0x236de259, 0x9a9639b1, 0x019736ab, 0xb86ced43, + 0xa911873a, 0x10ea5cd2, 0x88c53e9e, 0x313ee576, 0x20438f0f, + 0x99b854e7, 0x02b95bfd, 0xbb428015, 0xaa3fea6c, 0x13c43184, + 0x474cf219, 0xfeb729f1, 0xefca4388, 0x56319860, 0xcd30977a, + 0x74cb4c92, 0x65b626eb, 0xdc4dfd03, 0xcca7a1d1, 0x755c7a39, + 0x64211040, 0xdddacba8, 0x46dbc4b2, 0xff201f5a, 0xee5d7523, + 0x57a6aecb, 0x032e6d56, 0xbad5b6be, 0xaba8dcc7, 0x1253072f, + 0x89520835, 0x30a9d3dd, 0x21d4b9a4, 0x982f624c, 0xcafb7b7d, + 0x7300a095, 0x627dcaec, 0xdb861104, 0x40871e1e, 0xf97cc5f6, + 0xe801af8f, 0x51fa7467, 0x0572b7fa, 0xbc896c12, 0xadf4066b, + 0x140fdd83, 0x8f0ed299, 0x36f50971, 0x27886308, 0x9e73b8e0, + 0x8e99e432, 0x37623fda, 0x261f55a3, 0x9fe48e4b, 0x04e58151, + 0xbd1e5ab9, 0xac6330c0, 0x1598eb28, 0x411028b5, 0xf8ebf35d, + 0xe9969924, 0x506d42cc, 0xcb6c4dd6, 0x7297963e, 0x63eafc47, + 0xda1127af, 0x423e45e3, 0xfbc59e0b, 0xeab8f472, 0x53432f9a, + 0xc8422080, 0x71b9fb68, 0x60c49111, 0xd93f4af9, 0x8db78964, + 0x344c528c, 0x253138f5, 0x9ccae31d, 0x07cbec07, 0xbe3037ef, + 0xaf4d5d96, 0x16b6867e, 0x065cdaac, 0xbfa70144, 0xaeda6b3d, + 0x1721b0d5, 0x8c20bfcf, 0x35db6427, 0x24a60e5e, 0x9d5dd5b6, + 0xc9d5162b, 0x702ecdc3, 0x6153a7ba, 0xd8a87c52, 0x43a97348, + 0xfa52a8a0, 0xeb2fc2d9, 0x52d41931, 0x4e87f0bb, 0xf77c2b53, + 0xe601412a, 0x5ffa9ac2, 0xc4fb95d8, 0x7d004e30, 0x6c7d2449, + 0xd586ffa1, 0x810e3c3c, 0x38f5e7d4, 0x29888dad, 0x90735645, + 0x0b72595f, 0xb28982b7, 0xa3f4e8ce, 0x1a0f3326, 0x0ae56ff4, + 0xb31eb41c, 0xa263de65, 0x1b98058d, 0x80990a97, 0x3962d17f, + 0x281fbb06, 0x91e460ee, 0xc56ca373, 0x7c97789b, 0x6dea12e2, + 0xd411c90a, 0x4f10c610, 0xf6eb1df8, 0xe7967781, 0x5e6dac69, + 0xc642ce25, 0x7fb915cd, 0x6ec47fb4, 0xd73fa45c, 0x4c3eab46, + 0xf5c570ae, 0xe4b81ad7, 0x5d43c13f, 0x09cb02a2, 0xb030d94a, + 0xa14db333, 0x18b668db, 0x83b767c1, 0x3a4cbc29, 0x2b31d650, + 0x92ca0db8, 0x8220516a, 0x3bdb8a82, 0x2aa6e0fb, 0x935d3b13, + 0x085c3409, 0xb1a7efe1, 0xa0da8598, 0x19215e70, 0x4da99ded, + 0xf4524605, 0xe52f2c7c, 0x5cd4f794, 0xc7d5f88e, 0x7e2e2366, + 0x6f53491f, 0xd6a892f7, 0x847c8bc6, 0x3d87502e, 0x2cfa3a57, + 0x9501e1bf, 0x0e00eea5, 0xb7fb354d, 0xa6865f34, 0x1f7d84dc, + 0x4bf54741, 0xf20e9ca9, 0xe373f6d0, 0x5a882d38, 0xc1892222, + 0x7872f9ca, 0x690f93b3, 0xd0f4485b, 0xc01e1489, 0x79e5cf61, + 0x6898a518, 0xd1637ef0, 0x4a6271ea, 0xf399aa02, 0xe2e4c07b, + 0x5b1f1b93, 0x0f97d80e, 0xb66c03e6, 0xa711699f, 0x1eeab277, + 0x85ebbd6d, 0x3c106685, 0x2d6d0cfc, 0x9496d714, 0x0cb9b558, + 0xb5426eb0, 0xa43f04c9, 0x1dc4df21, 0x86c5d03b, 0x3f3e0bd3, + 0x2e4361aa, 0x97b8ba42, 0xc33079df, 0x7acba237, 0x6bb6c84e, + 0xd24d13a6, 0x494c1cbc, 0xf0b7c754, 0xe1caad2d, 0x583176c5, + 0x48db2a17, 0xf120f1ff, 0xe05d9b86, 0x59a6406e, 0xc2a74f74, + 0x7b5c949c, 0x6a21fee5, 0xd3da250d, 0x8752e690, 0x3ea93d78, + 0x2fd45701, 0x962f8ce9, 0x0d2e83f3, 0xb4d5581b, 0xa5a83262, + 0x1c53e98a}, + {0x00000000, 0x9d0fe176, 0xe16ec4ad, 0x7c6125db, 0x19ac8f1b, + 0x84a36e6d, 0xf8c24bb6, 0x65cdaac0, 0x33591e36, 0xae56ff40, + 0xd237da9b, 0x4f383bed, 0x2af5912d, 0xb7fa705b, 0xcb9b5580, + 0x5694b4f6, 0x66b23c6c, 0xfbbddd1a, 0x87dcf8c1, 0x1ad319b7, + 0x7f1eb377, 0xe2115201, 0x9e7077da, 0x037f96ac, 0x55eb225a, + 0xc8e4c32c, 0xb485e6f7, 0x298a0781, 0x4c47ad41, 0xd1484c37, + 0xad2969ec, 0x3026889a, 0xcd6478d8, 0x506b99ae, 0x2c0abc75, + 0xb1055d03, 0xd4c8f7c3, 0x49c716b5, 0x35a6336e, 0xa8a9d218, + 0xfe3d66ee, 0x63328798, 0x1f53a243, 0x825c4335, 0xe791e9f5, + 0x7a9e0883, 0x06ff2d58, 0x9bf0cc2e, 0xabd644b4, 0x36d9a5c2, + 0x4ab88019, 0xd7b7616f, 0xb27acbaf, 0x2f752ad9, 0x53140f02, + 0xce1bee74, 0x988f5a82, 0x0580bbf4, 0x79e19e2f, 0xe4ee7f59, + 0x8123d599, 0x1c2c34ef, 0x604d1134, 0xfd42f042, 0x41b9f7f1, + 0xdcb61687, 0xa0d7335c, 0x3dd8d22a, 0x581578ea, 0xc51a999c, + 0xb97bbc47, 0x24745d31, 0x72e0e9c7, 0xefef08b1, 0x938e2d6a, + 0x0e81cc1c, 0x6b4c66dc, 0xf64387aa, 0x8a22a271, 0x172d4307, + 0x270bcb9d, 0xba042aeb, 0xc6650f30, 0x5b6aee46, 0x3ea74486, + 0xa3a8a5f0, 0xdfc9802b, 0x42c6615d, 0x1452d5ab, 0x895d34dd, + 0xf53c1106, 0x6833f070, 0x0dfe5ab0, 0x90f1bbc6, 0xec909e1d, + 0x719f7f6b, 0x8cdd8f29, 0x11d26e5f, 0x6db34b84, 0xf0bcaaf2, + 0x95710032, 0x087ee144, 0x741fc49f, 0xe91025e9, 0xbf84911f, + 0x228b7069, 0x5eea55b2, 0xc3e5b4c4, 0xa6281e04, 0x3b27ff72, + 0x4746daa9, 0xda493bdf, 0xea6fb345, 0x77605233, 0x0b0177e8, + 0x960e969e, 0xf3c33c5e, 0x6eccdd28, 0x12adf8f3, 0x8fa21985, + 0xd936ad73, 0x44394c05, 0x385869de, 0xa55788a8, 0xc09a2268, + 0x5d95c31e, 0x21f4e6c5, 0xbcfb07b3, 0x8373efe2, 0x1e7c0e94, + 0x621d2b4f, 0xff12ca39, 0x9adf60f9, 0x07d0818f, 0x7bb1a454, + 0xe6be4522, 0xb02af1d4, 0x2d2510a2, 0x51443579, 0xcc4bd40f, + 0xa9867ecf, 0x34899fb9, 0x48e8ba62, 0xd5e75b14, 0xe5c1d38e, + 0x78ce32f8, 0x04af1723, 0x99a0f655, 0xfc6d5c95, 0x6162bde3, + 0x1d039838, 0x800c794e, 0xd698cdb8, 0x4b972cce, 0x37f60915, + 0xaaf9e863, 0xcf3442a3, 0x523ba3d5, 0x2e5a860e, 0xb3556778, + 0x4e17973a, 0xd318764c, 0xaf795397, 0x3276b2e1, 0x57bb1821, + 0xcab4f957, 0xb6d5dc8c, 0x2bda3dfa, 0x7d4e890c, 0xe041687a, + 0x9c204da1, 0x012facd7, 0x64e20617, 0xf9ede761, 0x858cc2ba, + 0x188323cc, 0x28a5ab56, 0xb5aa4a20, 0xc9cb6ffb, 0x54c48e8d, + 0x3109244d, 0xac06c53b, 0xd067e0e0, 0x4d680196, 0x1bfcb560, + 0x86f35416, 0xfa9271cd, 0x679d90bb, 0x02503a7b, 0x9f5fdb0d, + 0xe33efed6, 0x7e311fa0, 0xc2ca1813, 0x5fc5f965, 0x23a4dcbe, + 0xbeab3dc8, 0xdb669708, 0x4669767e, 0x3a0853a5, 0xa707b2d3, + 0xf1930625, 0x6c9ce753, 0x10fdc288, 0x8df223fe, 0xe83f893e, + 0x75306848, 0x09514d93, 0x945eace5, 0xa478247f, 0x3977c509, + 0x4516e0d2, 0xd81901a4, 0xbdd4ab64, 0x20db4a12, 0x5cba6fc9, + 0xc1b58ebf, 0x97213a49, 0x0a2edb3f, 0x764ffee4, 0xeb401f92, + 0x8e8db552, 0x13825424, 0x6fe371ff, 0xf2ec9089, 0x0fae60cb, + 0x92a181bd, 0xeec0a466, 0x73cf4510, 0x1602efd0, 0x8b0d0ea6, + 0xf76c2b7d, 0x6a63ca0b, 0x3cf77efd, 0xa1f89f8b, 0xdd99ba50, + 0x40965b26, 0x255bf1e6, 0xb8541090, 0xc435354b, 0x593ad43d, + 0x691c5ca7, 0xf413bdd1, 0x8872980a, 0x157d797c, 0x70b0d3bc, + 0xedbf32ca, 0x91de1711, 0x0cd1f667, 0x5a454291, 0xc74aa3e7, + 0xbb2b863c, 0x2624674a, 0x43e9cd8a, 0xdee62cfc, 0xa2870927, + 0x3f88e851}, + {0x00000000, 0xdd96d985, 0x605cb54b, 0xbdca6cce, 0xc0b96a96, + 0x1d2fb313, 0xa0e5dfdd, 0x7d730658, 0x5a03d36d, 0x87950ae8, + 0x3a5f6626, 0xe7c9bfa3, 0x9abab9fb, 0x472c607e, 0xfae60cb0, + 0x2770d535, 0xb407a6da, 0x69917f5f, 0xd45b1391, 0x09cdca14, + 0x74becc4c, 0xa92815c9, 0x14e27907, 0xc974a082, 0xee0475b7, + 0x3392ac32, 0x8e58c0fc, 0x53ce1979, 0x2ebd1f21, 0xf32bc6a4, + 0x4ee1aa6a, 0x937773ef, 0xb37e4bf5, 0x6ee89270, 0xd322febe, + 0x0eb4273b, 0x73c72163, 0xae51f8e6, 0x139b9428, 0xce0d4dad, + 0xe97d9898, 0x34eb411d, 0x89212dd3, 0x54b7f456, 0x29c4f20e, + 0xf4522b8b, 0x49984745, 0x940e9ec0, 0x0779ed2f, 0xdaef34aa, + 0x67255864, 0xbab381e1, 0xc7c087b9, 0x1a565e3c, 0xa79c32f2, + 0x7a0aeb77, 0x5d7a3e42, 0x80ece7c7, 0x3d268b09, 0xe0b0528c, + 0x9dc354d4, 0x40558d51, 0xfd9fe19f, 0x2009381a, 0xbd8d91ab, + 0x601b482e, 0xddd124e0, 0x0047fd65, 0x7d34fb3d, 0xa0a222b8, + 0x1d684e76, 0xc0fe97f3, 0xe78e42c6, 0x3a189b43, 0x87d2f78d, + 0x5a442e08, 0x27372850, 0xfaa1f1d5, 0x476b9d1b, 0x9afd449e, + 0x098a3771, 0xd41ceef4, 0x69d6823a, 0xb4405bbf, 0xc9335de7, + 0x14a58462, 0xa96fe8ac, 0x74f93129, 0x5389e41c, 0x8e1f3d99, + 0x33d55157, 0xee4388d2, 0x93308e8a, 0x4ea6570f, 0xf36c3bc1, + 0x2efae244, 0x0ef3da5e, 0xd36503db, 0x6eaf6f15, 0xb339b690, + 0xce4ab0c8, 0x13dc694d, 0xae160583, 0x7380dc06, 0x54f00933, + 0x8966d0b6, 0x34acbc78, 0xe93a65fd, 0x944963a5, 0x49dfba20, + 0xf415d6ee, 0x29830f6b, 0xbaf47c84, 0x6762a501, 0xdaa8c9cf, + 0x073e104a, 0x7a4d1612, 0xa7dbcf97, 0x1a11a359, 0xc7877adc, + 0xe0f7afe9, 0x3d61766c, 0x80ab1aa2, 0x5d3dc327, 0x204ec57f, + 0xfdd81cfa, 0x40127034, 0x9d84a9b1, 0xa06a2517, 0x7dfcfc92, + 0xc036905c, 0x1da049d9, 0x60d34f81, 0xbd459604, 0x008ffaca, + 0xdd19234f, 0xfa69f67a, 0x27ff2fff, 0x9a354331, 0x47a39ab4, + 0x3ad09cec, 0xe7464569, 0x5a8c29a7, 0x871af022, 0x146d83cd, + 0xc9fb5a48, 0x74313686, 0xa9a7ef03, 0xd4d4e95b, 0x094230de, + 0xb4885c10, 0x691e8595, 0x4e6e50a0, 0x93f88925, 0x2e32e5eb, + 0xf3a43c6e, 0x8ed73a36, 0x5341e3b3, 0xee8b8f7d, 0x331d56f8, + 0x13146ee2, 0xce82b767, 0x7348dba9, 0xaede022c, 0xd3ad0474, + 0x0e3bddf1, 0xb3f1b13f, 0x6e6768ba, 0x4917bd8f, 0x9481640a, + 0x294b08c4, 0xf4ddd141, 0x89aed719, 0x54380e9c, 0xe9f26252, + 0x3464bbd7, 0xa713c838, 0x7a8511bd, 0xc74f7d73, 0x1ad9a4f6, + 0x67aaa2ae, 0xba3c7b2b, 0x07f617e5, 0xda60ce60, 0xfd101b55, + 0x2086c2d0, 0x9d4cae1e, 0x40da779b, 0x3da971c3, 0xe03fa846, + 0x5df5c488, 0x80631d0d, 0x1de7b4bc, 0xc0716d39, 0x7dbb01f7, + 0xa02dd872, 0xdd5ede2a, 0x00c807af, 0xbd026b61, 0x6094b2e4, + 0x47e467d1, 0x9a72be54, 0x27b8d29a, 0xfa2e0b1f, 0x875d0d47, + 0x5acbd4c2, 0xe701b80c, 0x3a976189, 0xa9e01266, 0x7476cbe3, + 0xc9bca72d, 0x142a7ea8, 0x695978f0, 0xb4cfa175, 0x0905cdbb, + 0xd493143e, 0xf3e3c10b, 0x2e75188e, 0x93bf7440, 0x4e29adc5, + 0x335aab9d, 0xeecc7218, 0x53061ed6, 0x8e90c753, 0xae99ff49, + 0x730f26cc, 0xcec54a02, 0x13539387, 0x6e2095df, 0xb3b64c5a, + 0x0e7c2094, 0xd3eaf911, 0xf49a2c24, 0x290cf5a1, 0x94c6996f, + 0x495040ea, 0x342346b2, 0xe9b59f37, 0x547ff3f9, 0x89e92a7c, + 0x1a9e5993, 0xc7088016, 0x7ac2ecd8, 0xa754355d, 0xda273305, + 0x07b1ea80, 0xba7b864e, 0x67ed5fcb, 0x409d8afe, 0x9d0b537b, + 0x20c13fb5, 0xfd57e630, 0x8024e068, 0x5db239ed, 0xe0785523, + 0x3dee8ca6}, + {0x00000000, 0x9ba54c6f, 0xec3b9e9f, 0x779ed2f0, 0x03063b7f, + 0x98a37710, 0xef3da5e0, 0x7498e98f, 0x060c76fe, 0x9da93a91, + 0xea37e861, 0x7192a40e, 0x050a4d81, 0x9eaf01ee, 0xe931d31e, + 0x72949f71, 0x0c18edfc, 0x97bda193, 0xe0237363, 0x7b863f0c, + 0x0f1ed683, 0x94bb9aec, 0xe325481c, 0x78800473, 0x0a149b02, + 0x91b1d76d, 0xe62f059d, 0x7d8a49f2, 0x0912a07d, 0x92b7ec12, + 0xe5293ee2, 0x7e8c728d, 0x1831dbf8, 0x83949797, 0xf40a4567, + 0x6faf0908, 0x1b37e087, 0x8092ace8, 0xf70c7e18, 0x6ca93277, + 0x1e3dad06, 0x8598e169, 0xf2063399, 0x69a37ff6, 0x1d3b9679, + 0x869eda16, 0xf10008e6, 0x6aa54489, 0x14293604, 0x8f8c7a6b, + 0xf812a89b, 0x63b7e4f4, 0x172f0d7b, 0x8c8a4114, 0xfb1493e4, + 0x60b1df8b, 0x122540fa, 0x89800c95, 0xfe1ede65, 0x65bb920a, + 0x11237b85, 0x8a8637ea, 0xfd18e51a, 0x66bda975, 0x3063b7f0, + 0xabc6fb9f, 0xdc58296f, 0x47fd6500, 0x33658c8f, 0xa8c0c0e0, + 0xdf5e1210, 0x44fb5e7f, 0x366fc10e, 0xadca8d61, 0xda545f91, + 0x41f113fe, 0x3569fa71, 0xaeccb61e, 0xd95264ee, 0x42f72881, + 0x3c7b5a0c, 0xa7de1663, 0xd040c493, 0x4be588fc, 0x3f7d6173, + 0xa4d82d1c, 0xd346ffec, 0x48e3b383, 0x3a772cf2, 0xa1d2609d, + 0xd64cb26d, 0x4de9fe02, 0x3971178d, 0xa2d45be2, 0xd54a8912, + 0x4eefc57d, 0x28526c08, 0xb3f72067, 0xc469f297, 0x5fccbef8, + 0x2b545777, 0xb0f11b18, 0xc76fc9e8, 0x5cca8587, 0x2e5e1af6, + 0xb5fb5699, 0xc2658469, 0x59c0c806, 0x2d582189, 0xb6fd6de6, + 0xc163bf16, 0x5ac6f379, 0x244a81f4, 0xbfefcd9b, 0xc8711f6b, + 0x53d45304, 0x274cba8b, 0xbce9f6e4, 0xcb772414, 0x50d2687b, + 0x2246f70a, 0xb9e3bb65, 0xce7d6995, 0x55d825fa, 0x2140cc75, + 0xbae5801a, 0xcd7b52ea, 0x56de1e85, 0x60c76fe0, 0xfb62238f, + 0x8cfcf17f, 0x1759bd10, 0x63c1549f, 0xf86418f0, 0x8ffaca00, + 0x145f866f, 0x66cb191e, 0xfd6e5571, 0x8af08781, 0x1155cbee, + 0x65cd2261, 0xfe686e0e, 0x89f6bcfe, 0x1253f091, 0x6cdf821c, + 0xf77ace73, 0x80e41c83, 0x1b4150ec, 0x6fd9b963, 0xf47cf50c, + 0x83e227fc, 0x18476b93, 0x6ad3f4e2, 0xf176b88d, 0x86e86a7d, + 0x1d4d2612, 0x69d5cf9d, 0xf27083f2, 0x85ee5102, 0x1e4b1d6d, + 0x78f6b418, 0xe353f877, 0x94cd2a87, 0x0f6866e8, 0x7bf08f67, + 0xe055c308, 0x97cb11f8, 0x0c6e5d97, 0x7efac2e6, 0xe55f8e89, + 0x92c15c79, 0x09641016, 0x7dfcf999, 0xe659b5f6, 0x91c76706, + 0x0a622b69, 0x74ee59e4, 0xef4b158b, 0x98d5c77b, 0x03708b14, + 0x77e8629b, 0xec4d2ef4, 0x9bd3fc04, 0x0076b06b, 0x72e22f1a, + 0xe9476375, 0x9ed9b185, 0x057cfdea, 0x71e41465, 0xea41580a, + 0x9ddf8afa, 0x067ac695, 0x50a4d810, 0xcb01947f, 0xbc9f468f, + 0x273a0ae0, 0x53a2e36f, 0xc807af00, 0xbf997df0, 0x243c319f, + 0x56a8aeee, 0xcd0de281, 0xba933071, 0x21367c1e, 0x55ae9591, + 0xce0bd9fe, 0xb9950b0e, 0x22304761, 0x5cbc35ec, 0xc7197983, + 0xb087ab73, 0x2b22e71c, 0x5fba0e93, 0xc41f42fc, 0xb381900c, + 0x2824dc63, 0x5ab04312, 0xc1150f7d, 0xb68bdd8d, 0x2d2e91e2, + 0x59b6786d, 0xc2133402, 0xb58de6f2, 0x2e28aa9d, 0x489503e8, + 0xd3304f87, 0xa4ae9d77, 0x3f0bd118, 0x4b933897, 0xd03674f8, + 0xa7a8a608, 0x3c0dea67, 0x4e997516, 0xd53c3979, 0xa2a2eb89, + 0x3907a7e6, 0x4d9f4e69, 0xd63a0206, 0xa1a4d0f6, 0x3a019c99, + 0x448dee14, 0xdf28a27b, 0xa8b6708b, 0x33133ce4, 0x478bd56b, + 0xdc2e9904, 0xabb04bf4, 0x3015079b, 0x428198ea, 0xd924d485, + 0xaeba0675, 0x351f4a1a, 0x4187a395, 0xda22effa, 0xadbc3d0a, + 0x36197165}, + {0x00000000, 0xc18edfc0, 0x586cb9c1, 0x99e26601, 0xb0d97382, + 0x7157ac42, 0xe8b5ca43, 0x293b1583, 0xbac3e145, 0x7b4d3e85, + 0xe2af5884, 0x23218744, 0x0a1a92c7, 0xcb944d07, 0x52762b06, + 0x93f8f4c6, 0xaef6c4cb, 0x6f781b0b, 0xf69a7d0a, 0x3714a2ca, + 0x1e2fb749, 0xdfa16889, 0x46430e88, 0x87cdd148, 0x1435258e, + 0xd5bbfa4e, 0x4c599c4f, 0x8dd7438f, 0xa4ec560c, 0x656289cc, + 0xfc80efcd, 0x3d0e300d, 0x869c8fd7, 0x47125017, 0xdef03616, + 0x1f7ee9d6, 0x3645fc55, 0xf7cb2395, 0x6e294594, 0xafa79a54, + 0x3c5f6e92, 0xfdd1b152, 0x6433d753, 0xa5bd0893, 0x8c861d10, + 0x4d08c2d0, 0xd4eaa4d1, 0x15647b11, 0x286a4b1c, 0xe9e494dc, + 0x7006f2dd, 0xb1882d1d, 0x98b3389e, 0x593de75e, 0xc0df815f, + 0x01515e9f, 0x92a9aa59, 0x53277599, 0xcac51398, 0x0b4bcc58, + 0x2270d9db, 0xe3fe061b, 0x7a1c601a, 0xbb92bfda, 0xd64819ef, + 0x17c6c62f, 0x8e24a02e, 0x4faa7fee, 0x66916a6d, 0xa71fb5ad, + 0x3efdd3ac, 0xff730c6c, 0x6c8bf8aa, 0xad05276a, 0x34e7416b, + 0xf5699eab, 0xdc528b28, 0x1ddc54e8, 0x843e32e9, 0x45b0ed29, + 0x78bedd24, 0xb93002e4, 0x20d264e5, 0xe15cbb25, 0xc867aea6, + 0x09e97166, 0x900b1767, 0x5185c8a7, 0xc27d3c61, 0x03f3e3a1, + 0x9a1185a0, 0x5b9f5a60, 0x72a44fe3, 0xb32a9023, 0x2ac8f622, + 0xeb4629e2, 0x50d49638, 0x915a49f8, 0x08b82ff9, 0xc936f039, + 0xe00de5ba, 0x21833a7a, 0xb8615c7b, 0x79ef83bb, 0xea17777d, + 0x2b99a8bd, 0xb27bcebc, 0x73f5117c, 0x5ace04ff, 0x9b40db3f, + 0x02a2bd3e, 0xc32c62fe, 0xfe2252f3, 0x3fac8d33, 0xa64eeb32, + 0x67c034f2, 0x4efb2171, 0x8f75feb1, 0x169798b0, 0xd7194770, + 0x44e1b3b6, 0x856f6c76, 0x1c8d0a77, 0xdd03d5b7, 0xf438c034, + 0x35b61ff4, 0xac5479f5, 0x6ddaa635, 0x77e1359f, 0xb66fea5f, + 0x2f8d8c5e, 0xee03539e, 0xc738461d, 0x06b699dd, 0x9f54ffdc, + 0x5eda201c, 0xcd22d4da, 0x0cac0b1a, 0x954e6d1b, 0x54c0b2db, + 0x7dfba758, 0xbc757898, 0x25971e99, 0xe419c159, 0xd917f154, + 0x18992e94, 0x817b4895, 0x40f59755, 0x69ce82d6, 0xa8405d16, + 0x31a23b17, 0xf02ce4d7, 0x63d41011, 0xa25acfd1, 0x3bb8a9d0, + 0xfa367610, 0xd30d6393, 0x1283bc53, 0x8b61da52, 0x4aef0592, + 0xf17dba48, 0x30f36588, 0xa9110389, 0x689fdc49, 0x41a4c9ca, + 0x802a160a, 0x19c8700b, 0xd846afcb, 0x4bbe5b0d, 0x8a3084cd, + 0x13d2e2cc, 0xd25c3d0c, 0xfb67288f, 0x3ae9f74f, 0xa30b914e, + 0x62854e8e, 0x5f8b7e83, 0x9e05a143, 0x07e7c742, 0xc6691882, + 0xef520d01, 0x2edcd2c1, 0xb73eb4c0, 0x76b06b00, 0xe5489fc6, + 0x24c64006, 0xbd242607, 0x7caaf9c7, 0x5591ec44, 0x941f3384, + 0x0dfd5585, 0xcc738a45, 0xa1a92c70, 0x6027f3b0, 0xf9c595b1, + 0x384b4a71, 0x11705ff2, 0xd0fe8032, 0x491ce633, 0x889239f3, + 0x1b6acd35, 0xdae412f5, 0x430674f4, 0x8288ab34, 0xabb3beb7, + 0x6a3d6177, 0xf3df0776, 0x3251d8b6, 0x0f5fe8bb, 0xced1377b, + 0x5733517a, 0x96bd8eba, 0xbf869b39, 0x7e0844f9, 0xe7ea22f8, + 0x2664fd38, 0xb59c09fe, 0x7412d63e, 0xedf0b03f, 0x2c7e6fff, + 0x05457a7c, 0xc4cba5bc, 0x5d29c3bd, 0x9ca71c7d, 0x2735a3a7, + 0xe6bb7c67, 0x7f591a66, 0xbed7c5a6, 0x97ecd025, 0x56620fe5, + 0xcf8069e4, 0x0e0eb624, 0x9df642e2, 0x5c789d22, 0xc59afb23, + 0x041424e3, 0x2d2f3160, 0xeca1eea0, 0x754388a1, 0xb4cd5761, + 0x89c3676c, 0x484db8ac, 0xd1afdead, 0x1021016d, 0x391a14ee, + 0xf894cb2e, 0x6176ad2f, 0xa0f872ef, 0x33008629, 0xf28e59e9, + 0x6b6c3fe8, 0xaae2e028, 0x83d9f5ab, 0x42572a6b, 0xdbb54c6a, + 0x1a3b93aa}, + {0x00000000, 0xefc26b3e, 0x04f5d03d, 0xeb37bb03, 0x09eba07a, + 0xe629cb44, 0x0d1e7047, 0xe2dc1b79, 0x13d740f4, 0xfc152bca, + 0x172290c9, 0xf8e0fbf7, 0x1a3ce08e, 0xf5fe8bb0, 0x1ec930b3, + 0xf10b5b8d, 0x27ae81e8, 0xc86cead6, 0x235b51d5, 0xcc993aeb, + 0x2e452192, 0xc1874aac, 0x2ab0f1af, 0xc5729a91, 0x3479c11c, + 0xdbbbaa22, 0x308c1121, 0xdf4e7a1f, 0x3d926166, 0xd2500a58, + 0x3967b15b, 0xd6a5da65, 0x4f5d03d0, 0xa09f68ee, 0x4ba8d3ed, + 0xa46ab8d3, 0x46b6a3aa, 0xa974c894, 0x42437397, 0xad8118a9, + 0x5c8a4324, 0xb348281a, 0x587f9319, 0xb7bdf827, 0x5561e35e, + 0xbaa38860, 0x51943363, 0xbe56585d, 0x68f38238, 0x8731e906, + 0x6c065205, 0x83c4393b, 0x61182242, 0x8eda497c, 0x65edf27f, + 0x8a2f9941, 0x7b24c2cc, 0x94e6a9f2, 0x7fd112f1, 0x901379cf, + 0x72cf62b6, 0x9d0d0988, 0x763ab28b, 0x99f8d9b5, 0x9eba07a0, + 0x71786c9e, 0x9a4fd79d, 0x758dbca3, 0x9751a7da, 0x7893cce4, + 0x93a477e7, 0x7c661cd9, 0x8d6d4754, 0x62af2c6a, 0x89989769, + 0x665afc57, 0x8486e72e, 0x6b448c10, 0x80733713, 0x6fb15c2d, + 0xb9148648, 0x56d6ed76, 0xbde15675, 0x52233d4b, 0xb0ff2632, + 0x5f3d4d0c, 0xb40af60f, 0x5bc89d31, 0xaac3c6bc, 0x4501ad82, + 0xae361681, 0x41f47dbf, 0xa32866c6, 0x4cea0df8, 0xa7ddb6fb, + 0x481fddc5, 0xd1e70470, 0x3e256f4e, 0xd512d44d, 0x3ad0bf73, + 0xd80ca40a, 0x37cecf34, 0xdcf97437, 0x333b1f09, 0xc2304484, + 0x2df22fba, 0xc6c594b9, 0x2907ff87, 0xcbdbe4fe, 0x24198fc0, + 0xcf2e34c3, 0x20ec5ffd, 0xf6498598, 0x198beea6, 0xf2bc55a5, + 0x1d7e3e9b, 0xffa225e2, 0x10604edc, 0xfb57f5df, 0x14959ee1, + 0xe59ec56c, 0x0a5cae52, 0xe16b1551, 0x0ea97e6f, 0xec756516, + 0x03b70e28, 0xe880b52b, 0x0742de15, 0xe6050901, 0x09c7623f, + 0xe2f0d93c, 0x0d32b202, 0xefeea97b, 0x002cc245, 0xeb1b7946, + 0x04d91278, 0xf5d249f5, 0x1a1022cb, 0xf12799c8, 0x1ee5f2f6, + 0xfc39e98f, 0x13fb82b1, 0xf8cc39b2, 0x170e528c, 0xc1ab88e9, + 0x2e69e3d7, 0xc55e58d4, 0x2a9c33ea, 0xc8402893, 0x278243ad, + 0xccb5f8ae, 0x23779390, 0xd27cc81d, 0x3dbea323, 0xd6891820, + 0x394b731e, 0xdb976867, 0x34550359, 0xdf62b85a, 0x30a0d364, + 0xa9580ad1, 0x469a61ef, 0xadaddaec, 0x426fb1d2, 0xa0b3aaab, + 0x4f71c195, 0xa4467a96, 0x4b8411a8, 0xba8f4a25, 0x554d211b, + 0xbe7a9a18, 0x51b8f126, 0xb364ea5f, 0x5ca68161, 0xb7913a62, + 0x5853515c, 0x8ef68b39, 0x6134e007, 0x8a035b04, 0x65c1303a, + 0x871d2b43, 0x68df407d, 0x83e8fb7e, 0x6c2a9040, 0x9d21cbcd, + 0x72e3a0f3, 0x99d41bf0, 0x761670ce, 0x94ca6bb7, 0x7b080089, + 0x903fbb8a, 0x7ffdd0b4, 0x78bf0ea1, 0x977d659f, 0x7c4ade9c, + 0x9388b5a2, 0x7154aedb, 0x9e96c5e5, 0x75a17ee6, 0x9a6315d8, + 0x6b684e55, 0x84aa256b, 0x6f9d9e68, 0x805ff556, 0x6283ee2f, + 0x8d418511, 0x66763e12, 0x89b4552c, 0x5f118f49, 0xb0d3e477, + 0x5be45f74, 0xb426344a, 0x56fa2f33, 0xb938440d, 0x520fff0e, + 0xbdcd9430, 0x4cc6cfbd, 0xa304a483, 0x48331f80, 0xa7f174be, + 0x452d6fc7, 0xaaef04f9, 0x41d8bffa, 0xae1ad4c4, 0x37e20d71, + 0xd820664f, 0x3317dd4c, 0xdcd5b672, 0x3e09ad0b, 0xd1cbc635, + 0x3afc7d36, 0xd53e1608, 0x24354d85, 0xcbf726bb, 0x20c09db8, + 0xcf02f686, 0x2ddeedff, 0xc21c86c1, 0x292b3dc2, 0xc6e956fc, + 0x104c8c99, 0xff8ee7a7, 0x14b95ca4, 0xfb7b379a, 0x19a72ce3, + 0xf66547dd, 0x1d52fcde, 0xf29097e0, 0x039bcc6d, 0xec59a753, + 0x076e1c50, 0xe8ac776e, 0x0a706c17, 0xe5b20729, 0x0e85bc2a, + 0xe147d714}, + {0x00000000, 0x177b1443, 0x2ef62886, 0x398d3cc5, 0x5dec510c, + 0x4a97454f, 0x731a798a, 0x64616dc9, 0xbbd8a218, 0xaca3b65b, + 0x952e8a9e, 0x82559edd, 0xe634f314, 0xf14fe757, 0xc8c2db92, + 0xdfb9cfd1, 0xacc04271, 0xbbbb5632, 0x82366af7, 0x954d7eb4, + 0xf12c137d, 0xe657073e, 0xdfda3bfb, 0xc8a12fb8, 0x1718e069, + 0x0063f42a, 0x39eec8ef, 0x2e95dcac, 0x4af4b165, 0x5d8fa526, + 0x640299e3, 0x73798da0, 0x82f182a3, 0x958a96e0, 0xac07aa25, + 0xbb7cbe66, 0xdf1dd3af, 0xc866c7ec, 0xf1ebfb29, 0xe690ef6a, + 0x392920bb, 0x2e5234f8, 0x17df083d, 0x00a41c7e, 0x64c571b7, + 0x73be65f4, 0x4a335931, 0x5d484d72, 0x2e31c0d2, 0x394ad491, + 0x00c7e854, 0x17bcfc17, 0x73dd91de, 0x64a6859d, 0x5d2bb958, + 0x4a50ad1b, 0x95e962ca, 0x82927689, 0xbb1f4a4c, 0xac645e0f, + 0xc80533c6, 0xdf7e2785, 0xe6f31b40, 0xf1880f03, 0xde920307, + 0xc9e91744, 0xf0642b81, 0xe71f3fc2, 0x837e520b, 0x94054648, + 0xad887a8d, 0xbaf36ece, 0x654aa11f, 0x7231b55c, 0x4bbc8999, + 0x5cc79dda, 0x38a6f013, 0x2fdde450, 0x1650d895, 0x012bccd6, + 0x72524176, 0x65295535, 0x5ca469f0, 0x4bdf7db3, 0x2fbe107a, + 0x38c50439, 0x014838fc, 0x16332cbf, 0xc98ae36e, 0xdef1f72d, + 0xe77ccbe8, 0xf007dfab, 0x9466b262, 0x831da621, 0xba909ae4, + 0xadeb8ea7, 0x5c6381a4, 0x4b1895e7, 0x7295a922, 0x65eebd61, + 0x018fd0a8, 0x16f4c4eb, 0x2f79f82e, 0x3802ec6d, 0xe7bb23bc, + 0xf0c037ff, 0xc94d0b3a, 0xde361f79, 0xba5772b0, 0xad2c66f3, + 0x94a15a36, 0x83da4e75, 0xf0a3c3d5, 0xe7d8d796, 0xde55eb53, + 0xc92eff10, 0xad4f92d9, 0xba34869a, 0x83b9ba5f, 0x94c2ae1c, + 0x4b7b61cd, 0x5c00758e, 0x658d494b, 0x72f65d08, 0x169730c1, + 0x01ec2482, 0x38611847, 0x2f1a0c04, 0x6655004f, 0x712e140c, + 0x48a328c9, 0x5fd83c8a, 0x3bb95143, 0x2cc24500, 0x154f79c5, + 0x02346d86, 0xdd8da257, 0xcaf6b614, 0xf37b8ad1, 0xe4009e92, + 0x8061f35b, 0x971ae718, 0xae97dbdd, 0xb9eccf9e, 0xca95423e, + 0xddee567d, 0xe4636ab8, 0xf3187efb, 0x97791332, 0x80020771, + 0xb98f3bb4, 0xaef42ff7, 0x714de026, 0x6636f465, 0x5fbbc8a0, + 0x48c0dce3, 0x2ca1b12a, 0x3bdaa569, 0x025799ac, 0x152c8def, + 0xe4a482ec, 0xf3df96af, 0xca52aa6a, 0xdd29be29, 0xb948d3e0, + 0xae33c7a3, 0x97befb66, 0x80c5ef25, 0x5f7c20f4, 0x480734b7, + 0x718a0872, 0x66f11c31, 0x029071f8, 0x15eb65bb, 0x2c66597e, + 0x3b1d4d3d, 0x4864c09d, 0x5f1fd4de, 0x6692e81b, 0x71e9fc58, + 0x15889191, 0x02f385d2, 0x3b7eb917, 0x2c05ad54, 0xf3bc6285, + 0xe4c776c6, 0xdd4a4a03, 0xca315e40, 0xae503389, 0xb92b27ca, + 0x80a61b0f, 0x97dd0f4c, 0xb8c70348, 0xafbc170b, 0x96312bce, + 0x814a3f8d, 0xe52b5244, 0xf2504607, 0xcbdd7ac2, 0xdca66e81, + 0x031fa150, 0x1464b513, 0x2de989d6, 0x3a929d95, 0x5ef3f05c, + 0x4988e41f, 0x7005d8da, 0x677ecc99, 0x14074139, 0x037c557a, + 0x3af169bf, 0x2d8a7dfc, 0x49eb1035, 0x5e900476, 0x671d38b3, + 0x70662cf0, 0xafdfe321, 0xb8a4f762, 0x8129cba7, 0x9652dfe4, + 0xf233b22d, 0xe548a66e, 0xdcc59aab, 0xcbbe8ee8, 0x3a3681eb, + 0x2d4d95a8, 0x14c0a96d, 0x03bbbd2e, 0x67dad0e7, 0x70a1c4a4, + 0x492cf861, 0x5e57ec22, 0x81ee23f3, 0x969537b0, 0xaf180b75, + 0xb8631f36, 0xdc0272ff, 0xcb7966bc, 0xf2f45a79, 0xe58f4e3a, + 0x96f6c39a, 0x818dd7d9, 0xb800eb1c, 0xaf7bff5f, 0xcb1a9296, + 0xdc6186d5, 0xe5ecba10, 0xf297ae53, 0x2d2e6182, 0x3a5575c1, + 0x03d84904, 0x14a35d47, 0x70c2308e, 0x67b924cd, 0x5e341808, + 0x494f0c4b}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0x43147b1700000000, 0x8628f62e00000000, + 0xc53c8d3900000000, 0x0c51ec5d00000000, 0x4f45974a00000000, + 0x8a791a7300000000, 0xc96d616400000000, 0x18a2d8bb00000000, + 0x5bb6a3ac00000000, 0x9e8a2e9500000000, 0xdd9e558200000000, + 0x14f334e600000000, 0x57e74ff100000000, 0x92dbc2c800000000, + 0xd1cfb9df00000000, 0x7142c0ac00000000, 0x3256bbbb00000000, + 0xf76a368200000000, 0xb47e4d9500000000, 0x7d132cf100000000, + 0x3e0757e600000000, 0xfb3bdadf00000000, 0xb82fa1c800000000, + 0x69e0181700000000, 0x2af4630000000000, 0xefc8ee3900000000, + 0xacdc952e00000000, 0x65b1f44a00000000, 0x26a58f5d00000000, + 0xe399026400000000, 0xa08d797300000000, 0xa382f18200000000, + 0xe0968a9500000000, 0x25aa07ac00000000, 0x66be7cbb00000000, + 0xafd31ddf00000000, 0xecc766c800000000, 0x29fbebf100000000, + 0x6aef90e600000000, 0xbb20293900000000, 0xf834522e00000000, + 0x3d08df1700000000, 0x7e1ca40000000000, 0xb771c56400000000, + 0xf465be7300000000, 0x3159334a00000000, 0x724d485d00000000, + 0xd2c0312e00000000, 0x91d44a3900000000, 0x54e8c70000000000, + 0x17fcbc1700000000, 0xde91dd7300000000, 0x9d85a66400000000, + 0x58b92b5d00000000, 0x1bad504a00000000, 0xca62e99500000000, + 0x8976928200000000, 0x4c4a1fbb00000000, 0x0f5e64ac00000000, + 0xc63305c800000000, 0x85277edf00000000, 0x401bf3e600000000, + 0x030f88f100000000, 0x070392de00000000, 0x4417e9c900000000, + 0x812b64f000000000, 0xc23f1fe700000000, 0x0b527e8300000000, + 0x4846059400000000, 0x8d7a88ad00000000, 0xce6ef3ba00000000, + 0x1fa14a6500000000, 0x5cb5317200000000, 0x9989bc4b00000000, + 0xda9dc75c00000000, 0x13f0a63800000000, 0x50e4dd2f00000000, + 0x95d8501600000000, 0xd6cc2b0100000000, 0x7641527200000000, + 0x3555296500000000, 0xf069a45c00000000, 0xb37ddf4b00000000, + 0x7a10be2f00000000, 0x3904c53800000000, 0xfc38480100000000, + 0xbf2c331600000000, 0x6ee38ac900000000, 0x2df7f1de00000000, + 0xe8cb7ce700000000, 0xabdf07f000000000, 0x62b2669400000000, + 0x21a61d8300000000, 0xe49a90ba00000000, 0xa78eebad00000000, + 0xa481635c00000000, 0xe795184b00000000, 0x22a9957200000000, + 0x61bdee6500000000, 0xa8d08f0100000000, 0xebc4f41600000000, + 0x2ef8792f00000000, 0x6dec023800000000, 0xbc23bbe700000000, + 0xff37c0f000000000, 0x3a0b4dc900000000, 0x791f36de00000000, + 0xb07257ba00000000, 0xf3662cad00000000, 0x365aa19400000000, + 0x754eda8300000000, 0xd5c3a3f000000000, 0x96d7d8e700000000, + 0x53eb55de00000000, 0x10ff2ec900000000, 0xd9924fad00000000, + 0x9a8634ba00000000, 0x5fbab98300000000, 0x1caec29400000000, + 0xcd617b4b00000000, 0x8e75005c00000000, 0x4b498d6500000000, + 0x085df67200000000, 0xc130971600000000, 0x8224ec0100000000, + 0x4718613800000000, 0x040c1a2f00000000, 0x4f00556600000000, + 0x0c142e7100000000, 0xc928a34800000000, 0x8a3cd85f00000000, + 0x4351b93b00000000, 0x0045c22c00000000, 0xc5794f1500000000, + 0x866d340200000000, 0x57a28ddd00000000, 0x14b6f6ca00000000, + 0xd18a7bf300000000, 0x929e00e400000000, 0x5bf3618000000000, + 0x18e71a9700000000, 0xdddb97ae00000000, 0x9ecfecb900000000, + 0x3e4295ca00000000, 0x7d56eedd00000000, 0xb86a63e400000000, + 0xfb7e18f300000000, 0x3213799700000000, 0x7107028000000000, + 0xb43b8fb900000000, 0xf72ff4ae00000000, 0x26e04d7100000000, + 0x65f4366600000000, 0xa0c8bb5f00000000, 0xe3dcc04800000000, + 0x2ab1a12c00000000, 0x69a5da3b00000000, 0xac99570200000000, + 0xef8d2c1500000000, 0xec82a4e400000000, 0xaf96dff300000000, + 0x6aaa52ca00000000, 0x29be29dd00000000, 0xe0d348b900000000, + 0xa3c733ae00000000, 0x66fbbe9700000000, 0x25efc58000000000, + 0xf4207c5f00000000, 0xb734074800000000, 0x72088a7100000000, + 0x311cf16600000000, 0xf871900200000000, 0xbb65eb1500000000, + 0x7e59662c00000000, 0x3d4d1d3b00000000, 0x9dc0644800000000, + 0xded41f5f00000000, 0x1be8926600000000, 0x58fce97100000000, + 0x9191881500000000, 0xd285f30200000000, 0x17b97e3b00000000, + 0x54ad052c00000000, 0x8562bcf300000000, 0xc676c7e400000000, + 0x034a4add00000000, 0x405e31ca00000000, 0x893350ae00000000, + 0xca272bb900000000, 0x0f1ba68000000000, 0x4c0fdd9700000000, + 0x4803c7b800000000, 0x0b17bcaf00000000, 0xce2b319600000000, + 0x8d3f4a8100000000, 0x44522be500000000, 0x074650f200000000, + 0xc27addcb00000000, 0x816ea6dc00000000, 0x50a11f0300000000, + 0x13b5641400000000, 0xd689e92d00000000, 0x959d923a00000000, + 0x5cf0f35e00000000, 0x1fe4884900000000, 0xdad8057000000000, + 0x99cc7e6700000000, 0x3941071400000000, 0x7a557c0300000000, + 0xbf69f13a00000000, 0xfc7d8a2d00000000, 0x3510eb4900000000, + 0x7604905e00000000, 0xb3381d6700000000, 0xf02c667000000000, + 0x21e3dfaf00000000, 0x62f7a4b800000000, 0xa7cb298100000000, + 0xe4df529600000000, 0x2db233f200000000, 0x6ea648e500000000, + 0xab9ac5dc00000000, 0xe88ebecb00000000, 0xeb81363a00000000, + 0xa8954d2d00000000, 0x6da9c01400000000, 0x2ebdbb0300000000, + 0xe7d0da6700000000, 0xa4c4a17000000000, 0x61f82c4900000000, + 0x22ec575e00000000, 0xf323ee8100000000, 0xb037959600000000, + 0x750b18af00000000, 0x361f63b800000000, 0xff7202dc00000000, + 0xbc6679cb00000000, 0x795af4f200000000, 0x3a4e8fe500000000, + 0x9ac3f69600000000, 0xd9d78d8100000000, 0x1ceb00b800000000, + 0x5fff7baf00000000, 0x96921acb00000000, 0xd58661dc00000000, + 0x10baece500000000, 0x53ae97f200000000, 0x82612e2d00000000, + 0xc175553a00000000, 0x0449d80300000000, 0x475da31400000000, + 0x8e30c27000000000, 0xcd24b96700000000, 0x0818345e00000000, + 0x4b0c4f4900000000}, + {0x0000000000000000, 0x3e6bc2ef00000000, 0x3dd0f50400000000, + 0x03bb37eb00000000, 0x7aa0eb0900000000, 0x44cb29e600000000, + 0x47701e0d00000000, 0x791bdce200000000, 0xf440d71300000000, + 0xca2b15fc00000000, 0xc990221700000000, 0xf7fbe0f800000000, + 0x8ee03c1a00000000, 0xb08bfef500000000, 0xb330c91e00000000, + 0x8d5b0bf100000000, 0xe881ae2700000000, 0xd6ea6cc800000000, + 0xd5515b2300000000, 0xeb3a99cc00000000, 0x9221452e00000000, + 0xac4a87c100000000, 0xaff1b02a00000000, 0x919a72c500000000, + 0x1cc1793400000000, 0x22aabbdb00000000, 0x21118c3000000000, + 0x1f7a4edf00000000, 0x6661923d00000000, 0x580a50d200000000, + 0x5bb1673900000000, 0x65daa5d600000000, 0xd0035d4f00000000, + 0xee689fa000000000, 0xedd3a84b00000000, 0xd3b86aa400000000, + 0xaaa3b64600000000, 0x94c874a900000000, 0x9773434200000000, + 0xa91881ad00000000, 0x24438a5c00000000, 0x1a2848b300000000, + 0x19937f5800000000, 0x27f8bdb700000000, 0x5ee3615500000000, + 0x6088a3ba00000000, 0x6333945100000000, 0x5d5856be00000000, + 0x3882f36800000000, 0x06e9318700000000, 0x0552066c00000000, + 0x3b39c48300000000, 0x4222186100000000, 0x7c49da8e00000000, + 0x7ff2ed6500000000, 0x41992f8a00000000, 0xccc2247b00000000, + 0xf2a9e69400000000, 0xf112d17f00000000, 0xcf79139000000000, + 0xb662cf7200000000, 0x88090d9d00000000, 0x8bb23a7600000000, + 0xb5d9f89900000000, 0xa007ba9e00000000, 0x9e6c787100000000, + 0x9dd74f9a00000000, 0xa3bc8d7500000000, 0xdaa7519700000000, + 0xe4cc937800000000, 0xe777a49300000000, 0xd91c667c00000000, + 0x54476d8d00000000, 0x6a2caf6200000000, 0x6997988900000000, + 0x57fc5a6600000000, 0x2ee7868400000000, 0x108c446b00000000, + 0x1337738000000000, 0x2d5cb16f00000000, 0x488614b900000000, + 0x76edd65600000000, 0x7556e1bd00000000, 0x4b3d235200000000, + 0x3226ffb000000000, 0x0c4d3d5f00000000, 0x0ff60ab400000000, + 0x319dc85b00000000, 0xbcc6c3aa00000000, 0x82ad014500000000, + 0x811636ae00000000, 0xbf7df44100000000, 0xc66628a300000000, + 0xf80dea4c00000000, 0xfbb6dda700000000, 0xc5dd1f4800000000, + 0x7004e7d100000000, 0x4e6f253e00000000, 0x4dd412d500000000, + 0x73bfd03a00000000, 0x0aa40cd800000000, 0x34cfce3700000000, + 0x3774f9dc00000000, 0x091f3b3300000000, 0x844430c200000000, + 0xba2ff22d00000000, 0xb994c5c600000000, 0x87ff072900000000, + 0xfee4dbcb00000000, 0xc08f192400000000, 0xc3342ecf00000000, + 0xfd5fec2000000000, 0x988549f600000000, 0xa6ee8b1900000000, + 0xa555bcf200000000, 0x9b3e7e1d00000000, 0xe225a2ff00000000, + 0xdc4e601000000000, 0xdff557fb00000000, 0xe19e951400000000, + 0x6cc59ee500000000, 0x52ae5c0a00000000, 0x51156be100000000, + 0x6f7ea90e00000000, 0x166575ec00000000, 0x280eb70300000000, + 0x2bb580e800000000, 0x15de420700000000, 0x010905e600000000, + 0x3f62c70900000000, 0x3cd9f0e200000000, 0x02b2320d00000000, + 0x7ba9eeef00000000, 0x45c22c0000000000, 0x46791beb00000000, + 0x7812d90400000000, 0xf549d2f500000000, 0xcb22101a00000000, + 0xc89927f100000000, 0xf6f2e51e00000000, 0x8fe939fc00000000, + 0xb182fb1300000000, 0xb239ccf800000000, 0x8c520e1700000000, + 0xe988abc100000000, 0xd7e3692e00000000, 0xd4585ec500000000, + 0xea339c2a00000000, 0x932840c800000000, 0xad43822700000000, + 0xaef8b5cc00000000, 0x9093772300000000, 0x1dc87cd200000000, + 0x23a3be3d00000000, 0x201889d600000000, 0x1e734b3900000000, + 0x676897db00000000, 0x5903553400000000, 0x5ab862df00000000, + 0x64d3a03000000000, 0xd10a58a900000000, 0xef619a4600000000, + 0xecdaadad00000000, 0xd2b16f4200000000, 0xabaab3a000000000, + 0x95c1714f00000000, 0x967a46a400000000, 0xa811844b00000000, + 0x254a8fba00000000, 0x1b214d5500000000, 0x189a7abe00000000, + 0x26f1b85100000000, 0x5fea64b300000000, 0x6181a65c00000000, + 0x623a91b700000000, 0x5c51535800000000, 0x398bf68e00000000, + 0x07e0346100000000, 0x045b038a00000000, 0x3a30c16500000000, + 0x432b1d8700000000, 0x7d40df6800000000, 0x7efbe88300000000, + 0x40902a6c00000000, 0xcdcb219d00000000, 0xf3a0e37200000000, + 0xf01bd49900000000, 0xce70167600000000, 0xb76bca9400000000, + 0x8900087b00000000, 0x8abb3f9000000000, 0xb4d0fd7f00000000, + 0xa10ebf7800000000, 0x9f657d9700000000, 0x9cde4a7c00000000, + 0xa2b5889300000000, 0xdbae547100000000, 0xe5c5969e00000000, + 0xe67ea17500000000, 0xd815639a00000000, 0x554e686b00000000, + 0x6b25aa8400000000, 0x689e9d6f00000000, 0x56f55f8000000000, + 0x2fee836200000000, 0x1185418d00000000, 0x123e766600000000, + 0x2c55b48900000000, 0x498f115f00000000, 0x77e4d3b000000000, + 0x745fe45b00000000, 0x4a3426b400000000, 0x332ffa5600000000, + 0x0d4438b900000000, 0x0eff0f5200000000, 0x3094cdbd00000000, + 0xbdcfc64c00000000, 0x83a404a300000000, 0x801f334800000000, + 0xbe74f1a700000000, 0xc76f2d4500000000, 0xf904efaa00000000, + 0xfabfd84100000000, 0xc4d41aae00000000, 0x710de23700000000, + 0x4f6620d800000000, 0x4cdd173300000000, 0x72b6d5dc00000000, + 0x0bad093e00000000, 0x35c6cbd100000000, 0x367dfc3a00000000, + 0x08163ed500000000, 0x854d352400000000, 0xbb26f7cb00000000, + 0xb89dc02000000000, 0x86f602cf00000000, 0xffedde2d00000000, + 0xc1861cc200000000, 0xc23d2b2900000000, 0xfc56e9c600000000, + 0x998c4c1000000000, 0xa7e78eff00000000, 0xa45cb91400000000, + 0x9a377bfb00000000, 0xe32ca71900000000, 0xdd4765f600000000, + 0xdefc521d00000000, 0xe09790f200000000, 0x6dcc9b0300000000, + 0x53a759ec00000000, 0x501c6e0700000000, 0x6e77ace800000000, + 0x176c700a00000000, 0x2907b2e500000000, 0x2abc850e00000000, + 0x14d747e100000000}, + {0x0000000000000000, 0xc0df8ec100000000, 0xc1b96c5800000000, + 0x0166e29900000000, 0x8273d9b000000000, 0x42ac577100000000, + 0x43cab5e800000000, 0x83153b2900000000, 0x45e1c3ba00000000, + 0x853e4d7b00000000, 0x8458afe200000000, 0x4487212300000000, + 0xc7921a0a00000000, 0x074d94cb00000000, 0x062b765200000000, + 0xc6f4f89300000000, 0xcbc4f6ae00000000, 0x0b1b786f00000000, + 0x0a7d9af600000000, 0xcaa2143700000000, 0x49b72f1e00000000, + 0x8968a1df00000000, 0x880e434600000000, 0x48d1cd8700000000, + 0x8e25351400000000, 0x4efabbd500000000, 0x4f9c594c00000000, + 0x8f43d78d00000000, 0x0c56eca400000000, 0xcc89626500000000, + 0xcdef80fc00000000, 0x0d300e3d00000000, 0xd78f9c8600000000, + 0x1750124700000000, 0x1636f0de00000000, 0xd6e97e1f00000000, + 0x55fc453600000000, 0x9523cbf700000000, 0x9445296e00000000, + 0x549aa7af00000000, 0x926e5f3c00000000, 0x52b1d1fd00000000, + 0x53d7336400000000, 0x9308bda500000000, 0x101d868c00000000, + 0xd0c2084d00000000, 0xd1a4ead400000000, 0x117b641500000000, + 0x1c4b6a2800000000, 0xdc94e4e900000000, 0xddf2067000000000, + 0x1d2d88b100000000, 0x9e38b39800000000, 0x5ee73d5900000000, + 0x5f81dfc000000000, 0x9f5e510100000000, 0x59aaa99200000000, + 0x9975275300000000, 0x9813c5ca00000000, 0x58cc4b0b00000000, + 0xdbd9702200000000, 0x1b06fee300000000, 0x1a601c7a00000000, + 0xdabf92bb00000000, 0xef1948d600000000, 0x2fc6c61700000000, + 0x2ea0248e00000000, 0xee7faa4f00000000, 0x6d6a916600000000, + 0xadb51fa700000000, 0xacd3fd3e00000000, 0x6c0c73ff00000000, + 0xaaf88b6c00000000, 0x6a2705ad00000000, 0x6b41e73400000000, + 0xab9e69f500000000, 0x288b52dc00000000, 0xe854dc1d00000000, + 0xe9323e8400000000, 0x29edb04500000000, 0x24ddbe7800000000, + 0xe40230b900000000, 0xe564d22000000000, 0x25bb5ce100000000, + 0xa6ae67c800000000, 0x6671e90900000000, 0x67170b9000000000, + 0xa7c8855100000000, 0x613c7dc200000000, 0xa1e3f30300000000, + 0xa085119a00000000, 0x605a9f5b00000000, 0xe34fa47200000000, + 0x23902ab300000000, 0x22f6c82a00000000, 0xe22946eb00000000, + 0x3896d45000000000, 0xf8495a9100000000, 0xf92fb80800000000, + 0x39f036c900000000, 0xbae50de000000000, 0x7a3a832100000000, + 0x7b5c61b800000000, 0xbb83ef7900000000, 0x7d7717ea00000000, + 0xbda8992b00000000, 0xbcce7bb200000000, 0x7c11f57300000000, + 0xff04ce5a00000000, 0x3fdb409b00000000, 0x3ebda20200000000, + 0xfe622cc300000000, 0xf35222fe00000000, 0x338dac3f00000000, + 0x32eb4ea600000000, 0xf234c06700000000, 0x7121fb4e00000000, + 0xb1fe758f00000000, 0xb098971600000000, 0x704719d700000000, + 0xb6b3e14400000000, 0x766c6f8500000000, 0x770a8d1c00000000, + 0xb7d503dd00000000, 0x34c038f400000000, 0xf41fb63500000000, + 0xf57954ac00000000, 0x35a6da6d00000000, 0x9f35e17700000000, + 0x5fea6fb600000000, 0x5e8c8d2f00000000, 0x9e5303ee00000000, + 0x1d4638c700000000, 0xdd99b60600000000, 0xdcff549f00000000, + 0x1c20da5e00000000, 0xdad422cd00000000, 0x1a0bac0c00000000, + 0x1b6d4e9500000000, 0xdbb2c05400000000, 0x58a7fb7d00000000, + 0x987875bc00000000, 0x991e972500000000, 0x59c119e400000000, + 0x54f117d900000000, 0x942e991800000000, 0x95487b8100000000, + 0x5597f54000000000, 0xd682ce6900000000, 0x165d40a800000000, + 0x173ba23100000000, 0xd7e42cf000000000, 0x1110d46300000000, + 0xd1cf5aa200000000, 0xd0a9b83b00000000, 0x107636fa00000000, + 0x93630dd300000000, 0x53bc831200000000, 0x52da618b00000000, + 0x9205ef4a00000000, 0x48ba7df100000000, 0x8865f33000000000, + 0x890311a900000000, 0x49dc9f6800000000, 0xcac9a44100000000, + 0x0a162a8000000000, 0x0b70c81900000000, 0xcbaf46d800000000, + 0x0d5bbe4b00000000, 0xcd84308a00000000, 0xcce2d21300000000, + 0x0c3d5cd200000000, 0x8f2867fb00000000, 0x4ff7e93a00000000, + 0x4e910ba300000000, 0x8e4e856200000000, 0x837e8b5f00000000, + 0x43a1059e00000000, 0x42c7e70700000000, 0x821869c600000000, + 0x010d52ef00000000, 0xc1d2dc2e00000000, 0xc0b43eb700000000, + 0x006bb07600000000, 0xc69f48e500000000, 0x0640c62400000000, + 0x072624bd00000000, 0xc7f9aa7c00000000, 0x44ec915500000000, + 0x84331f9400000000, 0x8555fd0d00000000, 0x458a73cc00000000, + 0x702ca9a100000000, 0xb0f3276000000000, 0xb195c5f900000000, + 0x714a4b3800000000, 0xf25f701100000000, 0x3280fed000000000, + 0x33e61c4900000000, 0xf339928800000000, 0x35cd6a1b00000000, + 0xf512e4da00000000, 0xf474064300000000, 0x34ab888200000000, + 0xb7beb3ab00000000, 0x77613d6a00000000, 0x7607dff300000000, + 0xb6d8513200000000, 0xbbe85f0f00000000, 0x7b37d1ce00000000, + 0x7a51335700000000, 0xba8ebd9600000000, 0x399b86bf00000000, + 0xf944087e00000000, 0xf822eae700000000, 0x38fd642600000000, + 0xfe099cb500000000, 0x3ed6127400000000, 0x3fb0f0ed00000000, + 0xff6f7e2c00000000, 0x7c7a450500000000, 0xbca5cbc400000000, + 0xbdc3295d00000000, 0x7d1ca79c00000000, 0xa7a3352700000000, + 0x677cbbe600000000, 0x661a597f00000000, 0xa6c5d7be00000000, + 0x25d0ec9700000000, 0xe50f625600000000, 0xe46980cf00000000, + 0x24b60e0e00000000, 0xe242f69d00000000, 0x229d785c00000000, + 0x23fb9ac500000000, 0xe324140400000000, 0x60312f2d00000000, + 0xa0eea1ec00000000, 0xa188437500000000, 0x6157cdb400000000, + 0x6c67c38900000000, 0xacb84d4800000000, 0xaddeafd100000000, + 0x6d01211000000000, 0xee141a3900000000, 0x2ecb94f800000000, + 0x2fad766100000000, 0xef72f8a000000000, 0x2986003300000000, + 0xe9598ef200000000, 0xe83f6c6b00000000, 0x28e0e2aa00000000, + 0xabf5d98300000000, 0x6b2a574200000000, 0x6a4cb5db00000000, + 0xaa933b1a00000000}, + {0x0000000000000000, 0x6f4ca59b00000000, 0x9f9e3bec00000000, + 0xf0d29e7700000000, 0x7f3b060300000000, 0x1077a39800000000, + 0xe0a53def00000000, 0x8fe9987400000000, 0xfe760c0600000000, + 0x913aa99d00000000, 0x61e837ea00000000, 0x0ea4927100000000, + 0x814d0a0500000000, 0xee01af9e00000000, 0x1ed331e900000000, + 0x719f947200000000, 0xfced180c00000000, 0x93a1bd9700000000, + 0x637323e000000000, 0x0c3f867b00000000, 0x83d61e0f00000000, + 0xec9abb9400000000, 0x1c4825e300000000, 0x7304807800000000, + 0x029b140a00000000, 0x6dd7b19100000000, 0x9d052fe600000000, + 0xf2498a7d00000000, 0x7da0120900000000, 0x12ecb79200000000, + 0xe23e29e500000000, 0x8d728c7e00000000, 0xf8db311800000000, + 0x9797948300000000, 0x67450af400000000, 0x0809af6f00000000, + 0x87e0371b00000000, 0xe8ac928000000000, 0x187e0cf700000000, + 0x7732a96c00000000, 0x06ad3d1e00000000, 0x69e1988500000000, + 0x993306f200000000, 0xf67fa36900000000, 0x79963b1d00000000, + 0x16da9e8600000000, 0xe60800f100000000, 0x8944a56a00000000, + 0x0436291400000000, 0x6b7a8c8f00000000, 0x9ba812f800000000, + 0xf4e4b76300000000, 0x7b0d2f1700000000, 0x14418a8c00000000, + 0xe49314fb00000000, 0x8bdfb16000000000, 0xfa40251200000000, + 0x950c808900000000, 0x65de1efe00000000, 0x0a92bb6500000000, + 0x857b231100000000, 0xea37868a00000000, 0x1ae518fd00000000, + 0x75a9bd6600000000, 0xf0b7633000000000, 0x9ffbc6ab00000000, + 0x6f2958dc00000000, 0x0065fd4700000000, 0x8f8c653300000000, + 0xe0c0c0a800000000, 0x10125edf00000000, 0x7f5efb4400000000, + 0x0ec16f3600000000, 0x618dcaad00000000, 0x915f54da00000000, + 0xfe13f14100000000, 0x71fa693500000000, 0x1eb6ccae00000000, + 0xee6452d900000000, 0x8128f74200000000, 0x0c5a7b3c00000000, + 0x6316dea700000000, 0x93c440d000000000, 0xfc88e54b00000000, + 0x73617d3f00000000, 0x1c2dd8a400000000, 0xecff46d300000000, + 0x83b3e34800000000, 0xf22c773a00000000, 0x9d60d2a100000000, + 0x6db24cd600000000, 0x02fee94d00000000, 0x8d17713900000000, + 0xe25bd4a200000000, 0x12894ad500000000, 0x7dc5ef4e00000000, + 0x086c522800000000, 0x6720f7b300000000, 0x97f269c400000000, + 0xf8becc5f00000000, 0x7757542b00000000, 0x181bf1b000000000, + 0xe8c96fc700000000, 0x8785ca5c00000000, 0xf61a5e2e00000000, + 0x9956fbb500000000, 0x698465c200000000, 0x06c8c05900000000, + 0x8921582d00000000, 0xe66dfdb600000000, 0x16bf63c100000000, + 0x79f3c65a00000000, 0xf4814a2400000000, 0x9bcdefbf00000000, + 0x6b1f71c800000000, 0x0453d45300000000, 0x8bba4c2700000000, + 0xe4f6e9bc00000000, 0x142477cb00000000, 0x7b68d25000000000, + 0x0af7462200000000, 0x65bbe3b900000000, 0x95697dce00000000, + 0xfa25d85500000000, 0x75cc402100000000, 0x1a80e5ba00000000, + 0xea527bcd00000000, 0x851ede5600000000, 0xe06fc76000000000, + 0x8f2362fb00000000, 0x7ff1fc8c00000000, 0x10bd591700000000, + 0x9f54c16300000000, 0xf01864f800000000, 0x00cafa8f00000000, + 0x6f865f1400000000, 0x1e19cb6600000000, 0x71556efd00000000, + 0x8187f08a00000000, 0xeecb551100000000, 0x6122cd6500000000, + 0x0e6e68fe00000000, 0xfebcf68900000000, 0x91f0531200000000, + 0x1c82df6c00000000, 0x73ce7af700000000, 0x831ce48000000000, + 0xec50411b00000000, 0x63b9d96f00000000, 0x0cf57cf400000000, + 0xfc27e28300000000, 0x936b471800000000, 0xe2f4d36a00000000, + 0x8db876f100000000, 0x7d6ae88600000000, 0x12264d1d00000000, + 0x9dcfd56900000000, 0xf28370f200000000, 0x0251ee8500000000, + 0x6d1d4b1e00000000, 0x18b4f67800000000, 0x77f853e300000000, + 0x872acd9400000000, 0xe866680f00000000, 0x678ff07b00000000, + 0x08c355e000000000, 0xf811cb9700000000, 0x975d6e0c00000000, + 0xe6c2fa7e00000000, 0x898e5fe500000000, 0x795cc19200000000, + 0x1610640900000000, 0x99f9fc7d00000000, 0xf6b559e600000000, + 0x0667c79100000000, 0x692b620a00000000, 0xe459ee7400000000, + 0x8b154bef00000000, 0x7bc7d59800000000, 0x148b700300000000, + 0x9b62e87700000000, 0xf42e4dec00000000, 0x04fcd39b00000000, + 0x6bb0760000000000, 0x1a2fe27200000000, 0x756347e900000000, + 0x85b1d99e00000000, 0xeafd7c0500000000, 0x6514e47100000000, + 0x0a5841ea00000000, 0xfa8adf9d00000000, 0x95c67a0600000000, + 0x10d8a45000000000, 0x7f9401cb00000000, 0x8f469fbc00000000, + 0xe00a3a2700000000, 0x6fe3a25300000000, 0x00af07c800000000, + 0xf07d99bf00000000, 0x9f313c2400000000, 0xeeaea85600000000, + 0x81e20dcd00000000, 0x713093ba00000000, 0x1e7c362100000000, + 0x9195ae5500000000, 0xfed90bce00000000, 0x0e0b95b900000000, + 0x6147302200000000, 0xec35bc5c00000000, 0x837919c700000000, + 0x73ab87b000000000, 0x1ce7222b00000000, 0x930eba5f00000000, + 0xfc421fc400000000, 0x0c9081b300000000, 0x63dc242800000000, + 0x1243b05a00000000, 0x7d0f15c100000000, 0x8ddd8bb600000000, + 0xe2912e2d00000000, 0x6d78b65900000000, 0x023413c200000000, + 0xf2e68db500000000, 0x9daa282e00000000, 0xe803954800000000, + 0x874f30d300000000, 0x779daea400000000, 0x18d10b3f00000000, + 0x9738934b00000000, 0xf87436d000000000, 0x08a6a8a700000000, + 0x67ea0d3c00000000, 0x1675994e00000000, 0x79393cd500000000, + 0x89eba2a200000000, 0xe6a7073900000000, 0x694e9f4d00000000, + 0x06023ad600000000, 0xf6d0a4a100000000, 0x999c013a00000000, + 0x14ee8d4400000000, 0x7ba228df00000000, 0x8b70b6a800000000, + 0xe43c133300000000, 0x6bd58b4700000000, 0x04992edc00000000, + 0xf44bb0ab00000000, 0x9b07153000000000, 0xea98814200000000, + 0x85d424d900000000, 0x7506baae00000000, 0x1a4a1f3500000000, + 0x95a3874100000000, 0xfaef22da00000000, 0x0a3dbcad00000000, + 0x6571193600000000}, + {0x0000000000000000, 0x85d996dd00000000, 0x4bb55c6000000000, + 0xce6ccabd00000000, 0x966ab9c000000000, 0x13b32f1d00000000, + 0xdddfe5a000000000, 0x5806737d00000000, 0x6dd3035a00000000, + 0xe80a958700000000, 0x26665f3a00000000, 0xa3bfc9e700000000, + 0xfbb9ba9a00000000, 0x7e602c4700000000, 0xb00ce6fa00000000, + 0x35d5702700000000, 0xdaa607b400000000, 0x5f7f916900000000, + 0x91135bd400000000, 0x14cacd0900000000, 0x4cccbe7400000000, + 0xc91528a900000000, 0x0779e21400000000, 0x82a074c900000000, + 0xb77504ee00000000, 0x32ac923300000000, 0xfcc0588e00000000, + 0x7919ce5300000000, 0x211fbd2e00000000, 0xa4c62bf300000000, + 0x6aaae14e00000000, 0xef73779300000000, 0xf54b7eb300000000, + 0x7092e86e00000000, 0xbefe22d300000000, 0x3b27b40e00000000, + 0x6321c77300000000, 0xe6f851ae00000000, 0x28949b1300000000, + 0xad4d0dce00000000, 0x98987de900000000, 0x1d41eb3400000000, + 0xd32d218900000000, 0x56f4b75400000000, 0x0ef2c42900000000, + 0x8b2b52f400000000, 0x4547984900000000, 0xc09e0e9400000000, + 0x2fed790700000000, 0xaa34efda00000000, 0x6458256700000000, + 0xe181b3ba00000000, 0xb987c0c700000000, 0x3c5e561a00000000, + 0xf2329ca700000000, 0x77eb0a7a00000000, 0x423e7a5d00000000, + 0xc7e7ec8000000000, 0x098b263d00000000, 0x8c52b0e000000000, + 0xd454c39d00000000, 0x518d554000000000, 0x9fe19ffd00000000, + 0x1a38092000000000, 0xab918dbd00000000, 0x2e481b6000000000, + 0xe024d1dd00000000, 0x65fd470000000000, 0x3dfb347d00000000, + 0xb822a2a000000000, 0x764e681d00000000, 0xf397fec000000000, + 0xc6428ee700000000, 0x439b183a00000000, 0x8df7d28700000000, + 0x082e445a00000000, 0x5028372700000000, 0xd5f1a1fa00000000, + 0x1b9d6b4700000000, 0x9e44fd9a00000000, 0x71378a0900000000, + 0xf4ee1cd400000000, 0x3a82d66900000000, 0xbf5b40b400000000, + 0xe75d33c900000000, 0x6284a51400000000, 0xace86fa900000000, + 0x2931f97400000000, 0x1ce4895300000000, 0x993d1f8e00000000, + 0x5751d53300000000, 0xd28843ee00000000, 0x8a8e309300000000, + 0x0f57a64e00000000, 0xc13b6cf300000000, 0x44e2fa2e00000000, + 0x5edaf30e00000000, 0xdb0365d300000000, 0x156faf6e00000000, + 0x90b639b300000000, 0xc8b04ace00000000, 0x4d69dc1300000000, + 0x830516ae00000000, 0x06dc807300000000, 0x3309f05400000000, + 0xb6d0668900000000, 0x78bcac3400000000, 0xfd653ae900000000, + 0xa563499400000000, 0x20badf4900000000, 0xeed615f400000000, + 0x6b0f832900000000, 0x847cf4ba00000000, 0x01a5626700000000, + 0xcfc9a8da00000000, 0x4a103e0700000000, 0x12164d7a00000000, + 0x97cfdba700000000, 0x59a3111a00000000, 0xdc7a87c700000000, + 0xe9aff7e000000000, 0x6c76613d00000000, 0xa21aab8000000000, + 0x27c33d5d00000000, 0x7fc54e2000000000, 0xfa1cd8fd00000000, + 0x3470124000000000, 0xb1a9849d00000000, 0x17256aa000000000, + 0x92fcfc7d00000000, 0x5c9036c000000000, 0xd949a01d00000000, + 0x814fd36000000000, 0x049645bd00000000, 0xcafa8f0000000000, + 0x4f2319dd00000000, 0x7af669fa00000000, 0xff2fff2700000000, + 0x3143359a00000000, 0xb49aa34700000000, 0xec9cd03a00000000, + 0x694546e700000000, 0xa7298c5a00000000, 0x22f01a8700000000, + 0xcd836d1400000000, 0x485afbc900000000, 0x8636317400000000, + 0x03efa7a900000000, 0x5be9d4d400000000, 0xde30420900000000, + 0x105c88b400000000, 0x95851e6900000000, 0xa0506e4e00000000, + 0x2589f89300000000, 0xebe5322e00000000, 0x6e3ca4f300000000, + 0x363ad78e00000000, 0xb3e3415300000000, 0x7d8f8bee00000000, + 0xf8561d3300000000, 0xe26e141300000000, 0x67b782ce00000000, + 0xa9db487300000000, 0x2c02deae00000000, 0x7404add300000000, + 0xf1dd3b0e00000000, 0x3fb1f1b300000000, 0xba68676e00000000, + 0x8fbd174900000000, 0x0a64819400000000, 0xc4084b2900000000, + 0x41d1ddf400000000, 0x19d7ae8900000000, 0x9c0e385400000000, + 0x5262f2e900000000, 0xd7bb643400000000, 0x38c813a700000000, + 0xbd11857a00000000, 0x737d4fc700000000, 0xf6a4d91a00000000, + 0xaea2aa6700000000, 0x2b7b3cba00000000, 0xe517f60700000000, + 0x60ce60da00000000, 0x551b10fd00000000, 0xd0c2862000000000, + 0x1eae4c9d00000000, 0x9b77da4000000000, 0xc371a93d00000000, + 0x46a83fe000000000, 0x88c4f55d00000000, 0x0d1d638000000000, + 0xbcb4e71d00000000, 0x396d71c000000000, 0xf701bb7d00000000, + 0x72d82da000000000, 0x2ade5edd00000000, 0xaf07c80000000000, + 0x616b02bd00000000, 0xe4b2946000000000, 0xd167e44700000000, + 0x54be729a00000000, 0x9ad2b82700000000, 0x1f0b2efa00000000, + 0x470d5d8700000000, 0xc2d4cb5a00000000, 0x0cb801e700000000, + 0x8961973a00000000, 0x6612e0a900000000, 0xe3cb767400000000, + 0x2da7bcc900000000, 0xa87e2a1400000000, 0xf078596900000000, + 0x75a1cfb400000000, 0xbbcd050900000000, 0x3e1493d400000000, + 0x0bc1e3f300000000, 0x8e18752e00000000, 0x4074bf9300000000, + 0xc5ad294e00000000, 0x9dab5a3300000000, 0x1872ccee00000000, + 0xd61e065300000000, 0x53c7908e00000000, 0x49ff99ae00000000, + 0xcc260f7300000000, 0x024ac5ce00000000, 0x8793531300000000, + 0xdf95206e00000000, 0x5a4cb6b300000000, 0x94207c0e00000000, + 0x11f9ead300000000, 0x242c9af400000000, 0xa1f50c2900000000, + 0x6f99c69400000000, 0xea40504900000000, 0xb246233400000000, + 0x379fb5e900000000, 0xf9f37f5400000000, 0x7c2ae98900000000, + 0x93599e1a00000000, 0x168008c700000000, 0xd8ecc27a00000000, + 0x5d3554a700000000, 0x053327da00000000, 0x80eab10700000000, + 0x4e867bba00000000, 0xcb5fed6700000000, 0xfe8a9d4000000000, + 0x7b530b9d00000000, 0xb53fc12000000000, 0x30e657fd00000000, + 0x68e0248000000000, 0xed39b25d00000000, 0x235578e000000000, + 0xa68cee3d00000000}, + {0x0000000000000000, 0x76e10f9d00000000, 0xadc46ee100000000, + 0xdb25617c00000000, 0x1b8fac1900000000, 0x6d6ea38400000000, + 0xb64bc2f800000000, 0xc0aacd6500000000, 0x361e593300000000, + 0x40ff56ae00000000, 0x9bda37d200000000, 0xed3b384f00000000, + 0x2d91f52a00000000, 0x5b70fab700000000, 0x80559bcb00000000, + 0xf6b4945600000000, 0x6c3cb26600000000, 0x1addbdfb00000000, + 0xc1f8dc8700000000, 0xb719d31a00000000, 0x77b31e7f00000000, + 0x015211e200000000, 0xda77709e00000000, 0xac967f0300000000, + 0x5a22eb5500000000, 0x2cc3e4c800000000, 0xf7e685b400000000, + 0x81078a2900000000, 0x41ad474c00000000, 0x374c48d100000000, + 0xec6929ad00000000, 0x9a88263000000000, 0xd87864cd00000000, + 0xae996b5000000000, 0x75bc0a2c00000000, 0x035d05b100000000, + 0xc3f7c8d400000000, 0xb516c74900000000, 0x6e33a63500000000, + 0x18d2a9a800000000, 0xee663dfe00000000, 0x9887326300000000, + 0x43a2531f00000000, 0x35435c8200000000, 0xf5e991e700000000, + 0x83089e7a00000000, 0x582dff0600000000, 0x2eccf09b00000000, + 0xb444d6ab00000000, 0xc2a5d93600000000, 0x1980b84a00000000, + 0x6f61b7d700000000, 0xafcb7ab200000000, 0xd92a752f00000000, + 0x020f145300000000, 0x74ee1bce00000000, 0x825a8f9800000000, + 0xf4bb800500000000, 0x2f9ee17900000000, 0x597feee400000000, + 0x99d5238100000000, 0xef342c1c00000000, 0x34114d6000000000, + 0x42f042fd00000000, 0xf1f7b94100000000, 0x8716b6dc00000000, + 0x5c33d7a000000000, 0x2ad2d83d00000000, 0xea78155800000000, + 0x9c991ac500000000, 0x47bc7bb900000000, 0x315d742400000000, + 0xc7e9e07200000000, 0xb108efef00000000, 0x6a2d8e9300000000, + 0x1ccc810e00000000, 0xdc664c6b00000000, 0xaa8743f600000000, + 0x71a2228a00000000, 0x07432d1700000000, 0x9dcb0b2700000000, + 0xeb2a04ba00000000, 0x300f65c600000000, 0x46ee6a5b00000000, + 0x8644a73e00000000, 0xf0a5a8a300000000, 0x2b80c9df00000000, + 0x5d61c64200000000, 0xabd5521400000000, 0xdd345d8900000000, + 0x06113cf500000000, 0x70f0336800000000, 0xb05afe0d00000000, + 0xc6bbf19000000000, 0x1d9e90ec00000000, 0x6b7f9f7100000000, + 0x298fdd8c00000000, 0x5f6ed21100000000, 0x844bb36d00000000, + 0xf2aabcf000000000, 0x3200719500000000, 0x44e17e0800000000, + 0x9fc41f7400000000, 0xe92510e900000000, 0x1f9184bf00000000, + 0x69708b2200000000, 0xb255ea5e00000000, 0xc4b4e5c300000000, + 0x041e28a600000000, 0x72ff273b00000000, 0xa9da464700000000, + 0xdf3b49da00000000, 0x45b36fea00000000, 0x3352607700000000, + 0xe877010b00000000, 0x9e960e9600000000, 0x5e3cc3f300000000, + 0x28ddcc6e00000000, 0xf3f8ad1200000000, 0x8519a28f00000000, + 0x73ad36d900000000, 0x054c394400000000, 0xde69583800000000, + 0xa88857a500000000, 0x68229ac000000000, 0x1ec3955d00000000, + 0xc5e6f42100000000, 0xb307fbbc00000000, 0xe2ef738300000000, + 0x940e7c1e00000000, 0x4f2b1d6200000000, 0x39ca12ff00000000, + 0xf960df9a00000000, 0x8f81d00700000000, 0x54a4b17b00000000, + 0x2245bee600000000, 0xd4f12ab000000000, 0xa210252d00000000, + 0x7935445100000000, 0x0fd44bcc00000000, 0xcf7e86a900000000, + 0xb99f893400000000, 0x62bae84800000000, 0x145be7d500000000, + 0x8ed3c1e500000000, 0xf832ce7800000000, 0x2317af0400000000, + 0x55f6a09900000000, 0x955c6dfc00000000, 0xe3bd626100000000, + 0x3898031d00000000, 0x4e790c8000000000, 0xb8cd98d600000000, + 0xce2c974b00000000, 0x1509f63700000000, 0x63e8f9aa00000000, + 0xa34234cf00000000, 0xd5a33b5200000000, 0x0e865a2e00000000, + 0x786755b300000000, 0x3a97174e00000000, 0x4c7618d300000000, + 0x975379af00000000, 0xe1b2763200000000, 0x2118bb5700000000, + 0x57f9b4ca00000000, 0x8cdcd5b600000000, 0xfa3dda2b00000000, + 0x0c894e7d00000000, 0x7a6841e000000000, 0xa14d209c00000000, + 0xd7ac2f0100000000, 0x1706e26400000000, 0x61e7edf900000000, + 0xbac28c8500000000, 0xcc23831800000000, 0x56aba52800000000, + 0x204aaab500000000, 0xfb6fcbc900000000, 0x8d8ec45400000000, + 0x4d24093100000000, 0x3bc506ac00000000, 0xe0e067d000000000, + 0x9601684d00000000, 0x60b5fc1b00000000, 0x1654f38600000000, + 0xcd7192fa00000000, 0xbb909d6700000000, 0x7b3a500200000000, + 0x0ddb5f9f00000000, 0xd6fe3ee300000000, 0xa01f317e00000000, + 0x1318cac200000000, 0x65f9c55f00000000, 0xbedca42300000000, + 0xc83dabbe00000000, 0x089766db00000000, 0x7e76694600000000, + 0xa553083a00000000, 0xd3b207a700000000, 0x250693f100000000, + 0x53e79c6c00000000, 0x88c2fd1000000000, 0xfe23f28d00000000, + 0x3e893fe800000000, 0x4868307500000000, 0x934d510900000000, + 0xe5ac5e9400000000, 0x7f2478a400000000, 0x09c5773900000000, + 0xd2e0164500000000, 0xa40119d800000000, 0x64abd4bd00000000, + 0x124adb2000000000, 0xc96fba5c00000000, 0xbf8eb5c100000000, + 0x493a219700000000, 0x3fdb2e0a00000000, 0xe4fe4f7600000000, + 0x921f40eb00000000, 0x52b58d8e00000000, 0x2454821300000000, + 0xff71e36f00000000, 0x8990ecf200000000, 0xcb60ae0f00000000, + 0xbd81a19200000000, 0x66a4c0ee00000000, 0x1045cf7300000000, + 0xd0ef021600000000, 0xa60e0d8b00000000, 0x7d2b6cf700000000, + 0x0bca636a00000000, 0xfd7ef73c00000000, 0x8b9ff8a100000000, + 0x50ba99dd00000000, 0x265b964000000000, 0xe6f15b2500000000, + 0x901054b800000000, 0x4b3535c400000000, 0x3dd43a5900000000, + 0xa75c1c6900000000, 0xd1bd13f400000000, 0x0a98728800000000, + 0x7c797d1500000000, 0xbcd3b07000000000, 0xca32bfed00000000, + 0x1117de9100000000, 0x67f6d10c00000000, 0x9142455a00000000, + 0xe7a34ac700000000, 0x3c862bbb00000000, 0x4a67242600000000, + 0x8acde94300000000, 0xfc2ce6de00000000, 0x270987a200000000, + 0x51e8883f00000000}, + {0x0000000000000000, 0xe8dbfbb900000000, 0x91b186a800000000, + 0x796a7d1100000000, 0x63657c8a00000000, 0x8bbe873300000000, + 0xf2d4fa2200000000, 0x1a0f019b00000000, 0x87cc89cf00000000, + 0x6f17727600000000, 0x167d0f6700000000, 0xfea6f4de00000000, + 0xe4a9f54500000000, 0x0c720efc00000000, 0x751873ed00000000, + 0x9dc3885400000000, 0x4f9f624400000000, 0xa74499fd00000000, + 0xde2ee4ec00000000, 0x36f51f5500000000, 0x2cfa1ece00000000, + 0xc421e57700000000, 0xbd4b986600000000, 0x559063df00000000, + 0xc853eb8b00000000, 0x2088103200000000, 0x59e26d2300000000, + 0xb139969a00000000, 0xab36970100000000, 0x43ed6cb800000000, + 0x3a8711a900000000, 0xd25cea1000000000, 0x9e3ec58800000000, + 0x76e53e3100000000, 0x0f8f432000000000, 0xe754b89900000000, + 0xfd5bb90200000000, 0x158042bb00000000, 0x6cea3faa00000000, + 0x8431c41300000000, 0x19f24c4700000000, 0xf129b7fe00000000, + 0x8843caef00000000, 0x6098315600000000, 0x7a9730cd00000000, + 0x924ccb7400000000, 0xeb26b66500000000, 0x03fd4ddc00000000, + 0xd1a1a7cc00000000, 0x397a5c7500000000, 0x4010216400000000, + 0xa8cbdadd00000000, 0xb2c4db4600000000, 0x5a1f20ff00000000, + 0x23755dee00000000, 0xcbaea65700000000, 0x566d2e0300000000, + 0xbeb6d5ba00000000, 0xc7dca8ab00000000, 0x2f07531200000000, + 0x3508528900000000, 0xddd3a93000000000, 0xa4b9d42100000000, + 0x4c622f9800000000, 0x7d7bfbca00000000, 0x95a0007300000000, + 0xecca7d6200000000, 0x041186db00000000, 0x1e1e874000000000, + 0xf6c57cf900000000, 0x8faf01e800000000, 0x6774fa5100000000, + 0xfab7720500000000, 0x126c89bc00000000, 0x6b06f4ad00000000, + 0x83dd0f1400000000, 0x99d20e8f00000000, 0x7109f53600000000, + 0x0863882700000000, 0xe0b8739e00000000, 0x32e4998e00000000, + 0xda3f623700000000, 0xa3551f2600000000, 0x4b8ee49f00000000, + 0x5181e50400000000, 0xb95a1ebd00000000, 0xc03063ac00000000, + 0x28eb981500000000, 0xb528104100000000, 0x5df3ebf800000000, + 0x249996e900000000, 0xcc426d5000000000, 0xd64d6ccb00000000, + 0x3e96977200000000, 0x47fcea6300000000, 0xaf2711da00000000, + 0xe3453e4200000000, 0x0b9ec5fb00000000, 0x72f4b8ea00000000, + 0x9a2f435300000000, 0x802042c800000000, 0x68fbb97100000000, + 0x1191c46000000000, 0xf94a3fd900000000, 0x6489b78d00000000, + 0x8c524c3400000000, 0xf538312500000000, 0x1de3ca9c00000000, + 0x07eccb0700000000, 0xef3730be00000000, 0x965d4daf00000000, + 0x7e86b61600000000, 0xacda5c0600000000, 0x4401a7bf00000000, + 0x3d6bdaae00000000, 0xd5b0211700000000, 0xcfbf208c00000000, + 0x2764db3500000000, 0x5e0ea62400000000, 0xb6d55d9d00000000, + 0x2b16d5c900000000, 0xc3cd2e7000000000, 0xbaa7536100000000, + 0x527ca8d800000000, 0x4873a94300000000, 0xa0a852fa00000000, + 0xd9c22feb00000000, 0x3119d45200000000, 0xbbf0874e00000000, + 0x532b7cf700000000, 0x2a4101e600000000, 0xc29afa5f00000000, + 0xd895fbc400000000, 0x304e007d00000000, 0x49247d6c00000000, + 0xa1ff86d500000000, 0x3c3c0e8100000000, 0xd4e7f53800000000, + 0xad8d882900000000, 0x4556739000000000, 0x5f59720b00000000, + 0xb78289b200000000, 0xcee8f4a300000000, 0x26330f1a00000000, + 0xf46fe50a00000000, 0x1cb41eb300000000, 0x65de63a200000000, + 0x8d05981b00000000, 0x970a998000000000, 0x7fd1623900000000, + 0x06bb1f2800000000, 0xee60e49100000000, 0x73a36cc500000000, + 0x9b78977c00000000, 0xe212ea6d00000000, 0x0ac911d400000000, + 0x10c6104f00000000, 0xf81debf600000000, 0x817796e700000000, + 0x69ac6d5e00000000, 0x25ce42c600000000, 0xcd15b97f00000000, + 0xb47fc46e00000000, 0x5ca43fd700000000, 0x46ab3e4c00000000, + 0xae70c5f500000000, 0xd71ab8e400000000, 0x3fc1435d00000000, + 0xa202cb0900000000, 0x4ad930b000000000, 0x33b34da100000000, + 0xdb68b61800000000, 0xc167b78300000000, 0x29bc4c3a00000000, + 0x50d6312b00000000, 0xb80dca9200000000, 0x6a51208200000000, + 0x828adb3b00000000, 0xfbe0a62a00000000, 0x133b5d9300000000, + 0x09345c0800000000, 0xe1efa7b100000000, 0x9885daa000000000, + 0x705e211900000000, 0xed9da94d00000000, 0x054652f400000000, + 0x7c2c2fe500000000, 0x94f7d45c00000000, 0x8ef8d5c700000000, + 0x66232e7e00000000, 0x1f49536f00000000, 0xf792a8d600000000, + 0xc68b7c8400000000, 0x2e50873d00000000, 0x573afa2c00000000, + 0xbfe1019500000000, 0xa5ee000e00000000, 0x4d35fbb700000000, + 0x345f86a600000000, 0xdc847d1f00000000, 0x4147f54b00000000, + 0xa99c0ef200000000, 0xd0f673e300000000, 0x382d885a00000000, + 0x222289c100000000, 0xcaf9727800000000, 0xb3930f6900000000, + 0x5b48f4d000000000, 0x89141ec000000000, 0x61cfe57900000000, + 0x18a5986800000000, 0xf07e63d100000000, 0xea71624a00000000, + 0x02aa99f300000000, 0x7bc0e4e200000000, 0x931b1f5b00000000, + 0x0ed8970f00000000, 0xe6036cb600000000, 0x9f6911a700000000, + 0x77b2ea1e00000000, 0x6dbdeb8500000000, 0x8566103c00000000, + 0xfc0c6d2d00000000, 0x14d7969400000000, 0x58b5b90c00000000, + 0xb06e42b500000000, 0xc9043fa400000000, 0x21dfc41d00000000, + 0x3bd0c58600000000, 0xd30b3e3f00000000, 0xaa61432e00000000, + 0x42bab89700000000, 0xdf7930c300000000, 0x37a2cb7a00000000, + 0x4ec8b66b00000000, 0xa6134dd200000000, 0xbc1c4c4900000000, + 0x54c7b7f000000000, 0x2dadcae100000000, 0xc576315800000000, + 0x172adb4800000000, 0xfff120f100000000, 0x869b5de000000000, + 0x6e40a65900000000, 0x744fa7c200000000, 0x9c945c7b00000000, + 0xe5fe216a00000000, 0x0d25dad300000000, 0x90e6528700000000, + 0x783da93e00000000, 0x0157d42f00000000, 0xe98c2f9600000000, + 0xf3832e0d00000000, 0x1b58d5b400000000, 0x6232a8a500000000, + 0x8ae9531c00000000}, + {0x0000000000000000, 0x919168ae00000000, 0x6325a08700000000, + 0xf2b4c82900000000, 0x874c31d400000000, 0x16dd597a00000000, + 0xe469915300000000, 0x75f8f9fd00000000, 0x4f9f137300000000, + 0xde0e7bdd00000000, 0x2cbab3f400000000, 0xbd2bdb5a00000000, + 0xc8d322a700000000, 0x59424a0900000000, 0xabf6822000000000, + 0x3a67ea8e00000000, 0x9e3e27e600000000, 0x0faf4f4800000000, + 0xfd1b876100000000, 0x6c8aefcf00000000, 0x1972163200000000, + 0x88e37e9c00000000, 0x7a57b6b500000000, 0xebc6de1b00000000, + 0xd1a1349500000000, 0x40305c3b00000000, 0xb284941200000000, + 0x2315fcbc00000000, 0x56ed054100000000, 0xc77c6def00000000, + 0x35c8a5c600000000, 0xa459cd6800000000, 0x7d7b3f1700000000, + 0xecea57b900000000, 0x1e5e9f9000000000, 0x8fcff73e00000000, + 0xfa370ec300000000, 0x6ba6666d00000000, 0x9912ae4400000000, + 0x0883c6ea00000000, 0x32e42c6400000000, 0xa37544ca00000000, + 0x51c18ce300000000, 0xc050e44d00000000, 0xb5a81db000000000, + 0x2439751e00000000, 0xd68dbd3700000000, 0x471cd59900000000, + 0xe34518f100000000, 0x72d4705f00000000, 0x8060b87600000000, + 0x11f1d0d800000000, 0x6409292500000000, 0xf598418b00000000, + 0x072c89a200000000, 0x96bde10c00000000, 0xacda0b8200000000, + 0x3d4b632c00000000, 0xcfffab0500000000, 0x5e6ec3ab00000000, + 0x2b963a5600000000, 0xba0752f800000000, 0x48b39ad100000000, + 0xd922f27f00000000, 0xfaf67e2e00000000, 0x6b67168000000000, + 0x99d3dea900000000, 0x0842b60700000000, 0x7dba4ffa00000000, + 0xec2b275400000000, 0x1e9fef7d00000000, 0x8f0e87d300000000, + 0xb5696d5d00000000, 0x24f805f300000000, 0xd64ccdda00000000, + 0x47dda57400000000, 0x32255c8900000000, 0xa3b4342700000000, + 0x5100fc0e00000000, 0xc09194a000000000, 0x64c859c800000000, + 0xf559316600000000, 0x07edf94f00000000, 0x967c91e100000000, + 0xe384681c00000000, 0x721500b200000000, 0x80a1c89b00000000, + 0x1130a03500000000, 0x2b574abb00000000, 0xbac6221500000000, + 0x4872ea3c00000000, 0xd9e3829200000000, 0xac1b7b6f00000000, + 0x3d8a13c100000000, 0xcf3edbe800000000, 0x5eafb34600000000, + 0x878d413900000000, 0x161c299700000000, 0xe4a8e1be00000000, + 0x7539891000000000, 0x00c170ed00000000, 0x9150184300000000, + 0x63e4d06a00000000, 0xf275b8c400000000, 0xc812524a00000000, + 0x59833ae400000000, 0xab37f2cd00000000, 0x3aa69a6300000000, + 0x4f5e639e00000000, 0xdecf0b3000000000, 0x2c7bc31900000000, + 0xbdeaabb700000000, 0x19b366df00000000, 0x88220e7100000000, + 0x7a96c65800000000, 0xeb07aef600000000, 0x9eff570b00000000, + 0x0f6e3fa500000000, 0xfddaf78c00000000, 0x6c4b9f2200000000, + 0x562c75ac00000000, 0xc7bd1d0200000000, 0x3509d52b00000000, + 0xa498bd8500000000, 0xd160447800000000, 0x40f12cd600000000, + 0xb245e4ff00000000, 0x23d48c5100000000, 0xf4edfd5c00000000, + 0x657c95f200000000, 0x97c85ddb00000000, 0x0659357500000000, + 0x73a1cc8800000000, 0xe230a42600000000, 0x10846c0f00000000, + 0x811504a100000000, 0xbb72ee2f00000000, 0x2ae3868100000000, + 0xd8574ea800000000, 0x49c6260600000000, 0x3c3edffb00000000, + 0xadafb75500000000, 0x5f1b7f7c00000000, 0xce8a17d200000000, + 0x6ad3daba00000000, 0xfb42b21400000000, 0x09f67a3d00000000, + 0x9867129300000000, 0xed9feb6e00000000, 0x7c0e83c000000000, + 0x8eba4be900000000, 0x1f2b234700000000, 0x254cc9c900000000, + 0xb4dda16700000000, 0x4669694e00000000, 0xd7f801e000000000, + 0xa200f81d00000000, 0x339190b300000000, 0xc125589a00000000, + 0x50b4303400000000, 0x8996c24b00000000, 0x1807aae500000000, + 0xeab362cc00000000, 0x7b220a6200000000, 0x0edaf39f00000000, + 0x9f4b9b3100000000, 0x6dff531800000000, 0xfc6e3bb600000000, + 0xc609d13800000000, 0x5798b99600000000, 0xa52c71bf00000000, + 0x34bd191100000000, 0x4145e0ec00000000, 0xd0d4884200000000, + 0x2260406b00000000, 0xb3f128c500000000, 0x17a8e5ad00000000, + 0x86398d0300000000, 0x748d452a00000000, 0xe51c2d8400000000, + 0x90e4d47900000000, 0x0175bcd700000000, 0xf3c174fe00000000, + 0x62501c5000000000, 0x5837f6de00000000, 0xc9a69e7000000000, + 0x3b12565900000000, 0xaa833ef700000000, 0xdf7bc70a00000000, + 0x4eeaafa400000000, 0xbc5e678d00000000, 0x2dcf0f2300000000, + 0x0e1b837200000000, 0x9f8aebdc00000000, 0x6d3e23f500000000, + 0xfcaf4b5b00000000, 0x8957b2a600000000, 0x18c6da0800000000, + 0xea72122100000000, 0x7be37a8f00000000, 0x4184900100000000, + 0xd015f8af00000000, 0x22a1308600000000, 0xb330582800000000, + 0xc6c8a1d500000000, 0x5759c97b00000000, 0xa5ed015200000000, + 0x347c69fc00000000, 0x9025a49400000000, 0x01b4cc3a00000000, + 0xf300041300000000, 0x62916cbd00000000, 0x1769954000000000, + 0x86f8fdee00000000, 0x744c35c700000000, 0xe5dd5d6900000000, + 0xdfbab7e700000000, 0x4e2bdf4900000000, 0xbc9f176000000000, + 0x2d0e7fce00000000, 0x58f6863300000000, 0xc967ee9d00000000, + 0x3bd326b400000000, 0xaa424e1a00000000, 0x7360bc6500000000, + 0xe2f1d4cb00000000, 0x10451ce200000000, 0x81d4744c00000000, + 0xf42c8db100000000, 0x65bde51f00000000, 0x97092d3600000000, + 0x0698459800000000, 0x3cffaf1600000000, 0xad6ec7b800000000, + 0x5fda0f9100000000, 0xce4b673f00000000, 0xbbb39ec200000000, + 0x2a22f66c00000000, 0xd8963e4500000000, 0x490756eb00000000, + 0xed5e9b8300000000, 0x7ccff32d00000000, 0x8e7b3b0400000000, + 0x1fea53aa00000000, 0x6a12aa5700000000, 0xfb83c2f900000000, + 0x09370ad000000000, 0x98a6627e00000000, 0xa2c188f000000000, + 0x3350e05e00000000, 0xc1e4287700000000, 0x507540d900000000, + 0x258db92400000000, 0xb41cd18a00000000, 0x46a819a300000000, + 0xd739710d00000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa, + 0x48e00e64, 0xc66f0987, 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b, + 0x91c01cc8, 0x5d6a1c56, 0x57af154f, 0x9b0515d1, 0x158a1232, + 0xd92012ac, 0x7cbb312b, 0xb01131b5, 0x3e9e3656, 0xf23436c8, + 0xf8f13fd1, 0x345b3f4f, 0xbad438ac, 0x767e3832, 0xaf5e2a9e, + 0x63f42a00, 0xed7b2de3, 0x21d12d7d, 0x2b142464, 0xe7be24fa, + 0x69312319, 0xa59b2387, 0xf9766256, 0x35dc62c8, 0xbb53652b, + 0x77f965b5, 0x7d3c6cac, 0xb1966c32, 0x3f196bd1, 0xf3b36b4f, + 0x2a9379e3, 0xe639797d, 0x68b67e9e, 0xa41c7e00, 0xaed97719, + 0x62737787, 0xecfc7064, 0x205670fa, 0x85cd537d, 0x496753e3, + 0xc7e85400, 0x0b42549e, 0x01875d87, 0xcd2d5d19, 0x43a25afa, + 0x8f085a64, 0x562848c8, 0x9a824856, 0x140d4fb5, 0xd8a74f2b, + 0xd2624632, 0x1ec846ac, 0x9047414f, 0x5ced41d1, 0x299dc2ed, + 0xe537c273, 0x6bb8c590, 0xa712c50e, 0xadd7cc17, 0x617dcc89, + 0xeff2cb6a, 0x2358cbf4, 0xfa78d958, 0x36d2d9c6, 0xb85dde25, + 0x74f7debb, 0x7e32d7a2, 0xb298d73c, 0x3c17d0df, 0xf0bdd041, + 0x5526f3c6, 0x998cf358, 0x1703f4bb, 0xdba9f425, 0xd16cfd3c, + 0x1dc6fda2, 0x9349fa41, 0x5fe3fadf, 0x86c3e873, 0x4a69e8ed, + 0xc4e6ef0e, 0x084cef90, 0x0289e689, 0xce23e617, 0x40ace1f4, + 0x8c06e16a, 0xd0eba0bb, 0x1c41a025, 0x92cea7c6, 0x5e64a758, + 0x54a1ae41, 0x980baedf, 0x1684a93c, 0xda2ea9a2, 0x030ebb0e, + 0xcfa4bb90, 0x412bbc73, 0x8d81bced, 0x8744b5f4, 0x4beeb56a, + 0xc561b289, 0x09cbb217, 0xac509190, 0x60fa910e, 0xee7596ed, + 0x22df9673, 0x281a9f6a, 0xe4b09ff4, 0x6a3f9817, 0xa6959889, + 0x7fb58a25, 0xb31f8abb, 0x3d908d58, 0xf13a8dc6, 0xfbff84df, + 0x37558441, 0xb9da83a2, 0x7570833c, 0x533b85da, 0x9f918544, + 0x111e82a7, 0xddb48239, 0xd7718b20, 0x1bdb8bbe, 0x95548c5d, + 0x59fe8cc3, 0x80de9e6f, 0x4c749ef1, 0xc2fb9912, 0x0e51998c, + 0x04949095, 0xc83e900b, 0x46b197e8, 0x8a1b9776, 0x2f80b4f1, + 0xe32ab46f, 0x6da5b38c, 0xa10fb312, 0xabcaba0b, 0x6760ba95, + 0xe9efbd76, 0x2545bde8, 0xfc65af44, 0x30cfafda, 0xbe40a839, + 0x72eaa8a7, 0x782fa1be, 0xb485a120, 0x3a0aa6c3, 0xf6a0a65d, + 0xaa4de78c, 0x66e7e712, 0xe868e0f1, 0x24c2e06f, 0x2e07e976, + 0xe2ade9e8, 0x6c22ee0b, 0xa088ee95, 0x79a8fc39, 0xb502fca7, + 0x3b8dfb44, 0xf727fbda, 0xfde2f2c3, 0x3148f25d, 0xbfc7f5be, + 0x736df520, 0xd6f6d6a7, 0x1a5cd639, 0x94d3d1da, 0x5879d144, + 0x52bcd85d, 0x9e16d8c3, 0x1099df20, 0xdc33dfbe, 0x0513cd12, + 0xc9b9cd8c, 0x4736ca6f, 0x8b9ccaf1, 0x8159c3e8, 0x4df3c376, + 0xc37cc495, 0x0fd6c40b, 0x7aa64737, 0xb60c47a9, 0x3883404a, + 0xf42940d4, 0xfeec49cd, 0x32464953, 0xbcc94eb0, 0x70634e2e, + 0xa9435c82, 0x65e95c1c, 0xeb665bff, 0x27cc5b61, 0x2d095278, + 0xe1a352e6, 0x6f2c5505, 0xa386559b, 0x061d761c, 0xcab77682, + 0x44387161, 0x889271ff, 0x825778e6, 0x4efd7878, 0xc0727f9b, + 0x0cd87f05, 0xd5f86da9, 0x19526d37, 0x97dd6ad4, 0x5b776a4a, + 0x51b26353, 0x9d1863cd, 0x1397642e, 0xdf3d64b0, 0x83d02561, + 0x4f7a25ff, 0xc1f5221c, 0x0d5f2282, 0x079a2b9b, 0xcb302b05, + 0x45bf2ce6, 0x89152c78, 0x50353ed4, 0x9c9f3e4a, 0x121039a9, + 0xdeba3937, 0xd47f302e, 0x18d530b0, 0x965a3753, 0x5af037cd, + 0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0, + 0xb78b1a2e, 0x39041dcd, 0xf5ae1d53, 0x2c8e0fff, 0xe0240f61, + 0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678, + 0x264b06e6}, + {0x00000000, 0xa6770bb4, 0x979f1129, 0x31e81a9d, 0xf44f2413, + 0x52382fa7, 0x63d0353a, 0xc5a73e8e, 0x33ef4e67, 0x959845d3, + 0xa4705f4e, 0x020754fa, 0xc7a06a74, 0x61d761c0, 0x503f7b5d, + 0xf64870e9, 0x67de9cce, 0xc1a9977a, 0xf0418de7, 0x56368653, + 0x9391b8dd, 0x35e6b369, 0x040ea9f4, 0xa279a240, 0x5431d2a9, + 0xf246d91d, 0xc3aec380, 0x65d9c834, 0xa07ef6ba, 0x0609fd0e, + 0x37e1e793, 0x9196ec27, 0xcfbd399c, 0x69ca3228, 0x582228b5, + 0xfe552301, 0x3bf21d8f, 0x9d85163b, 0xac6d0ca6, 0x0a1a0712, + 0xfc5277fb, 0x5a257c4f, 0x6bcd66d2, 0xcdba6d66, 0x081d53e8, + 0xae6a585c, 0x9f8242c1, 0x39f54975, 0xa863a552, 0x0e14aee6, + 0x3ffcb47b, 0x998bbfcf, 0x5c2c8141, 0xfa5b8af5, 0xcbb39068, + 0x6dc49bdc, 0x9b8ceb35, 0x3dfbe081, 0x0c13fa1c, 0xaa64f1a8, + 0x6fc3cf26, 0xc9b4c492, 0xf85cde0f, 0x5e2bd5bb, 0x440b7579, + 0xe27c7ecd, 0xd3946450, 0x75e36fe4, 0xb044516a, 0x16335ade, + 0x27db4043, 0x81ac4bf7, 0x77e43b1e, 0xd19330aa, 0xe07b2a37, + 0x460c2183, 0x83ab1f0d, 0x25dc14b9, 0x14340e24, 0xb2430590, + 0x23d5e9b7, 0x85a2e203, 0xb44af89e, 0x123df32a, 0xd79acda4, + 0x71edc610, 0x4005dc8d, 0xe672d739, 0x103aa7d0, 0xb64dac64, + 0x87a5b6f9, 0x21d2bd4d, 0xe47583c3, 0x42028877, 0x73ea92ea, + 0xd59d995e, 0x8bb64ce5, 0x2dc14751, 0x1c295dcc, 0xba5e5678, + 0x7ff968f6, 0xd98e6342, 0xe86679df, 0x4e11726b, 0xb8590282, + 0x1e2e0936, 0x2fc613ab, 0x89b1181f, 0x4c162691, 0xea612d25, + 0xdb8937b8, 0x7dfe3c0c, 0xec68d02b, 0x4a1fdb9f, 0x7bf7c102, + 0xdd80cab6, 0x1827f438, 0xbe50ff8c, 0x8fb8e511, 0x29cfeea5, + 0xdf879e4c, 0x79f095f8, 0x48188f65, 0xee6f84d1, 0x2bc8ba5f, + 0x8dbfb1eb, 0xbc57ab76, 0x1a20a0c2, 0x8816eaf2, 0x2e61e146, + 0x1f89fbdb, 0xb9fef06f, 0x7c59cee1, 0xda2ec555, 0xebc6dfc8, + 0x4db1d47c, 0xbbf9a495, 0x1d8eaf21, 0x2c66b5bc, 0x8a11be08, + 0x4fb68086, 0xe9c18b32, 0xd82991af, 0x7e5e9a1b, 0xefc8763c, + 0x49bf7d88, 0x78576715, 0xde206ca1, 0x1b87522f, 0xbdf0599b, + 0x8c184306, 0x2a6f48b2, 0xdc27385b, 0x7a5033ef, 0x4bb82972, + 0xedcf22c6, 0x28681c48, 0x8e1f17fc, 0xbff70d61, 0x198006d5, + 0x47abd36e, 0xe1dcd8da, 0xd034c247, 0x7643c9f3, 0xb3e4f77d, + 0x1593fcc9, 0x247be654, 0x820cede0, 0x74449d09, 0xd23396bd, + 0xe3db8c20, 0x45ac8794, 0x800bb91a, 0x267cb2ae, 0x1794a833, + 0xb1e3a387, 0x20754fa0, 0x86024414, 0xb7ea5e89, 0x119d553d, + 0xd43a6bb3, 0x724d6007, 0x43a57a9a, 0xe5d2712e, 0x139a01c7, + 0xb5ed0a73, 0x840510ee, 0x22721b5a, 0xe7d525d4, 0x41a22e60, + 0x704a34fd, 0xd63d3f49, 0xcc1d9f8b, 0x6a6a943f, 0x5b828ea2, + 0xfdf58516, 0x3852bb98, 0x9e25b02c, 0xafcdaab1, 0x09baa105, + 0xfff2d1ec, 0x5985da58, 0x686dc0c5, 0xce1acb71, 0x0bbdf5ff, + 0xadcafe4b, 0x9c22e4d6, 0x3a55ef62, 0xabc30345, 0x0db408f1, + 0x3c5c126c, 0x9a2b19d8, 0x5f8c2756, 0xf9fb2ce2, 0xc813367f, + 0x6e643dcb, 0x982c4d22, 0x3e5b4696, 0x0fb35c0b, 0xa9c457bf, + 0x6c636931, 0xca146285, 0xfbfc7818, 0x5d8b73ac, 0x03a0a617, + 0xa5d7ada3, 0x943fb73e, 0x3248bc8a, 0xf7ef8204, 0x519889b0, + 0x6070932d, 0xc6079899, 0x304fe870, 0x9638e3c4, 0xa7d0f959, + 0x01a7f2ed, 0xc400cc63, 0x6277c7d7, 0x539fdd4a, 0xf5e8d6fe, + 0x647e3ad9, 0xc209316d, 0xf3e12bf0, 0x55962044, 0x90311eca, + 0x3646157e, 0x07ae0fe3, 0xa1d90457, 0x579174be, 0xf1e67f0a, + 0xc00e6597, 0x66796e23, 0xa3de50ad, 0x05a95b19, 0x34414184, + 0x92364a30}, + {0x00000000, 0xcb5cd3a5, 0x4dc8a10b, 0x869472ae, 0x9b914216, + 0x50cd91b3, 0xd659e31d, 0x1d0530b8, 0xec53826d, 0x270f51c8, + 0xa19b2366, 0x6ac7f0c3, 0x77c2c07b, 0xbc9e13de, 0x3a0a6170, + 0xf156b2d5, 0x03d6029b, 0xc88ad13e, 0x4e1ea390, 0x85427035, + 0x9847408d, 0x531b9328, 0xd58fe186, 0x1ed33223, 0xef8580f6, + 0x24d95353, 0xa24d21fd, 0x6911f258, 0x7414c2e0, 0xbf481145, + 0x39dc63eb, 0xf280b04e, 0x07ac0536, 0xccf0d693, 0x4a64a43d, + 0x81387798, 0x9c3d4720, 0x57619485, 0xd1f5e62b, 0x1aa9358e, + 0xebff875b, 0x20a354fe, 0xa6372650, 0x6d6bf5f5, 0x706ec54d, + 0xbb3216e8, 0x3da66446, 0xf6fab7e3, 0x047a07ad, 0xcf26d408, + 0x49b2a6a6, 0x82ee7503, 0x9feb45bb, 0x54b7961e, 0xd223e4b0, + 0x197f3715, 0xe82985c0, 0x23755665, 0xa5e124cb, 0x6ebdf76e, + 0x73b8c7d6, 0xb8e41473, 0x3e7066dd, 0xf52cb578, 0x0f580a6c, + 0xc404d9c9, 0x4290ab67, 0x89cc78c2, 0x94c9487a, 0x5f959bdf, + 0xd901e971, 0x125d3ad4, 0xe30b8801, 0x28575ba4, 0xaec3290a, + 0x659ffaaf, 0x789aca17, 0xb3c619b2, 0x35526b1c, 0xfe0eb8b9, + 0x0c8e08f7, 0xc7d2db52, 0x4146a9fc, 0x8a1a7a59, 0x971f4ae1, + 0x5c439944, 0xdad7ebea, 0x118b384f, 0xe0dd8a9a, 0x2b81593f, + 0xad152b91, 0x6649f834, 0x7b4cc88c, 0xb0101b29, 0x36846987, + 0xfdd8ba22, 0x08f40f5a, 0xc3a8dcff, 0x453cae51, 0x8e607df4, + 0x93654d4c, 0x58399ee9, 0xdeadec47, 0x15f13fe2, 0xe4a78d37, + 0x2ffb5e92, 0xa96f2c3c, 0x6233ff99, 0x7f36cf21, 0xb46a1c84, + 0x32fe6e2a, 0xf9a2bd8f, 0x0b220dc1, 0xc07ede64, 0x46eaacca, + 0x8db67f6f, 0x90b34fd7, 0x5bef9c72, 0xdd7beedc, 0x16273d79, + 0xe7718fac, 0x2c2d5c09, 0xaab92ea7, 0x61e5fd02, 0x7ce0cdba, + 0xb7bc1e1f, 0x31286cb1, 0xfa74bf14, 0x1eb014d8, 0xd5ecc77d, + 0x5378b5d3, 0x98246676, 0x852156ce, 0x4e7d856b, 0xc8e9f7c5, + 0x03b52460, 0xf2e396b5, 0x39bf4510, 0xbf2b37be, 0x7477e41b, + 0x6972d4a3, 0xa22e0706, 0x24ba75a8, 0xefe6a60d, 0x1d661643, + 0xd63ac5e6, 0x50aeb748, 0x9bf264ed, 0x86f75455, 0x4dab87f0, + 0xcb3ff55e, 0x006326fb, 0xf135942e, 0x3a69478b, 0xbcfd3525, + 0x77a1e680, 0x6aa4d638, 0xa1f8059d, 0x276c7733, 0xec30a496, + 0x191c11ee, 0xd240c24b, 0x54d4b0e5, 0x9f886340, 0x828d53f8, + 0x49d1805d, 0xcf45f2f3, 0x04192156, 0xf54f9383, 0x3e134026, + 0xb8873288, 0x73dbe12d, 0x6eded195, 0xa5820230, 0x2316709e, + 0xe84aa33b, 0x1aca1375, 0xd196c0d0, 0x5702b27e, 0x9c5e61db, + 0x815b5163, 0x4a0782c6, 0xcc93f068, 0x07cf23cd, 0xf6999118, + 0x3dc542bd, 0xbb513013, 0x700de3b6, 0x6d08d30e, 0xa65400ab, + 0x20c07205, 0xeb9ca1a0, 0x11e81eb4, 0xdab4cd11, 0x5c20bfbf, + 0x977c6c1a, 0x8a795ca2, 0x41258f07, 0xc7b1fda9, 0x0ced2e0c, + 0xfdbb9cd9, 0x36e74f7c, 0xb0733dd2, 0x7b2fee77, 0x662adecf, + 0xad760d6a, 0x2be27fc4, 0xe0beac61, 0x123e1c2f, 0xd962cf8a, + 0x5ff6bd24, 0x94aa6e81, 0x89af5e39, 0x42f38d9c, 0xc467ff32, + 0x0f3b2c97, 0xfe6d9e42, 0x35314de7, 0xb3a53f49, 0x78f9ecec, + 0x65fcdc54, 0xaea00ff1, 0x28347d5f, 0xe368aefa, 0x16441b82, + 0xdd18c827, 0x5b8cba89, 0x90d0692c, 0x8dd55994, 0x46898a31, + 0xc01df89f, 0x0b412b3a, 0xfa1799ef, 0x314b4a4a, 0xb7df38e4, + 0x7c83eb41, 0x6186dbf9, 0xaada085c, 0x2c4e7af2, 0xe712a957, + 0x15921919, 0xdececabc, 0x585ab812, 0x93066bb7, 0x8e035b0f, + 0x455f88aa, 0xc3cbfa04, 0x089729a1, 0xf9c19b74, 0x329d48d1, + 0xb4093a7f, 0x7f55e9da, 0x6250d962, 0xa90c0ac7, 0x2f987869, + 0xe4c4abcc}, + {0x00000000, 0x3d6029b0, 0x7ac05360, 0x47a07ad0, 0xf580a6c0, + 0xc8e08f70, 0x8f40f5a0, 0xb220dc10, 0x30704bc1, 0x0d106271, + 0x4ab018a1, 0x77d03111, 0xc5f0ed01, 0xf890c4b1, 0xbf30be61, + 0x825097d1, 0x60e09782, 0x5d80be32, 0x1a20c4e2, 0x2740ed52, + 0x95603142, 0xa80018f2, 0xefa06222, 0xd2c04b92, 0x5090dc43, + 0x6df0f5f3, 0x2a508f23, 0x1730a693, 0xa5107a83, 0x98705333, + 0xdfd029e3, 0xe2b00053, 0xc1c12f04, 0xfca106b4, 0xbb017c64, + 0x866155d4, 0x344189c4, 0x0921a074, 0x4e81daa4, 0x73e1f314, + 0xf1b164c5, 0xccd14d75, 0x8b7137a5, 0xb6111e15, 0x0431c205, + 0x3951ebb5, 0x7ef19165, 0x4391b8d5, 0xa121b886, 0x9c419136, + 0xdbe1ebe6, 0xe681c256, 0x54a11e46, 0x69c137f6, 0x2e614d26, + 0x13016496, 0x9151f347, 0xac31daf7, 0xeb91a027, 0xd6f18997, + 0x64d15587, 0x59b17c37, 0x1e1106e7, 0x23712f57, 0x58f35849, + 0x659371f9, 0x22330b29, 0x1f532299, 0xad73fe89, 0x9013d739, + 0xd7b3ade9, 0xead38459, 0x68831388, 0x55e33a38, 0x124340e8, + 0x2f236958, 0x9d03b548, 0xa0639cf8, 0xe7c3e628, 0xdaa3cf98, + 0x3813cfcb, 0x0573e67b, 0x42d39cab, 0x7fb3b51b, 0xcd93690b, + 0xf0f340bb, 0xb7533a6b, 0x8a3313db, 0x0863840a, 0x3503adba, + 0x72a3d76a, 0x4fc3feda, 0xfde322ca, 0xc0830b7a, 0x872371aa, + 0xba43581a, 0x9932774d, 0xa4525efd, 0xe3f2242d, 0xde920d9d, + 0x6cb2d18d, 0x51d2f83d, 0x167282ed, 0x2b12ab5d, 0xa9423c8c, + 0x9422153c, 0xd3826fec, 0xeee2465c, 0x5cc29a4c, 0x61a2b3fc, + 0x2602c92c, 0x1b62e09c, 0xf9d2e0cf, 0xc4b2c97f, 0x8312b3af, + 0xbe729a1f, 0x0c52460f, 0x31326fbf, 0x7692156f, 0x4bf23cdf, + 0xc9a2ab0e, 0xf4c282be, 0xb362f86e, 0x8e02d1de, 0x3c220dce, + 0x0142247e, 0x46e25eae, 0x7b82771e, 0xb1e6b092, 0x8c869922, + 0xcb26e3f2, 0xf646ca42, 0x44661652, 0x79063fe2, 0x3ea64532, + 0x03c66c82, 0x8196fb53, 0xbcf6d2e3, 0xfb56a833, 0xc6368183, + 0x74165d93, 0x49767423, 0x0ed60ef3, 0x33b62743, 0xd1062710, + 0xec660ea0, 0xabc67470, 0x96a65dc0, 0x248681d0, 0x19e6a860, + 0x5e46d2b0, 0x6326fb00, 0xe1766cd1, 0xdc164561, 0x9bb63fb1, + 0xa6d61601, 0x14f6ca11, 0x2996e3a1, 0x6e369971, 0x5356b0c1, + 0x70279f96, 0x4d47b626, 0x0ae7ccf6, 0x3787e546, 0x85a73956, + 0xb8c710e6, 0xff676a36, 0xc2074386, 0x4057d457, 0x7d37fde7, + 0x3a978737, 0x07f7ae87, 0xb5d77297, 0x88b75b27, 0xcf1721f7, + 0xf2770847, 0x10c70814, 0x2da721a4, 0x6a075b74, 0x576772c4, + 0xe547aed4, 0xd8278764, 0x9f87fdb4, 0xa2e7d404, 0x20b743d5, + 0x1dd76a65, 0x5a7710b5, 0x67173905, 0xd537e515, 0xe857cca5, + 0xaff7b675, 0x92979fc5, 0xe915e8db, 0xd475c16b, 0x93d5bbbb, + 0xaeb5920b, 0x1c954e1b, 0x21f567ab, 0x66551d7b, 0x5b3534cb, + 0xd965a31a, 0xe4058aaa, 0xa3a5f07a, 0x9ec5d9ca, 0x2ce505da, + 0x11852c6a, 0x562556ba, 0x6b457f0a, 0x89f57f59, 0xb49556e9, + 0xf3352c39, 0xce550589, 0x7c75d999, 0x4115f029, 0x06b58af9, + 0x3bd5a349, 0xb9853498, 0x84e51d28, 0xc34567f8, 0xfe254e48, + 0x4c059258, 0x7165bbe8, 0x36c5c138, 0x0ba5e888, 0x28d4c7df, + 0x15b4ee6f, 0x521494bf, 0x6f74bd0f, 0xdd54611f, 0xe03448af, + 0xa794327f, 0x9af41bcf, 0x18a48c1e, 0x25c4a5ae, 0x6264df7e, + 0x5f04f6ce, 0xed242ade, 0xd044036e, 0x97e479be, 0xaa84500e, + 0x4834505d, 0x755479ed, 0x32f4033d, 0x0f942a8d, 0xbdb4f69d, + 0x80d4df2d, 0xc774a5fd, 0xfa148c4d, 0x78441b9c, 0x4524322c, + 0x028448fc, 0x3fe4614c, 0x8dc4bd5c, 0xb0a494ec, 0xf704ee3c, + 0xca64c78c}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0xb029603d, 0x6053c07a, 0xd07aa047, 0xc0a680f5, + 0x708fe0c8, 0xa0f5408f, 0x10dc20b2, 0xc14b7030, 0x7162100d, + 0xa118b04a, 0x1131d077, 0x01edf0c5, 0xb1c490f8, 0x61be30bf, + 0xd1975082, 0x8297e060, 0x32be805d, 0xe2c4201a, 0x52ed4027, + 0x42316095, 0xf21800a8, 0x2262a0ef, 0x924bc0d2, 0x43dc9050, + 0xf3f5f06d, 0x238f502a, 0x93a63017, 0x837a10a5, 0x33537098, + 0xe329d0df, 0x5300b0e2, 0x042fc1c1, 0xb406a1fc, 0x647c01bb, + 0xd4556186, 0xc4894134, 0x74a02109, 0xa4da814e, 0x14f3e173, + 0xc564b1f1, 0x754dd1cc, 0xa537718b, 0x151e11b6, 0x05c23104, + 0xb5eb5139, 0x6591f17e, 0xd5b89143, 0x86b821a1, 0x3691419c, + 0xe6ebe1db, 0x56c281e6, 0x461ea154, 0xf637c169, 0x264d612e, + 0x96640113, 0x47f35191, 0xf7da31ac, 0x27a091eb, 0x9789f1d6, + 0x8755d164, 0x377cb159, 0xe706111e, 0x572f7123, 0x4958f358, + 0xf9719365, 0x290b3322, 0x9922531f, 0x89fe73ad, 0x39d71390, + 0xe9adb3d7, 0x5984d3ea, 0x88138368, 0x383ae355, 0xe8404312, + 0x5869232f, 0x48b5039d, 0xf89c63a0, 0x28e6c3e7, 0x98cfa3da, + 0xcbcf1338, 0x7be67305, 0xab9cd342, 0x1bb5b37f, 0x0b6993cd, + 0xbb40f3f0, 0x6b3a53b7, 0xdb13338a, 0x0a846308, 0xbaad0335, + 0x6ad7a372, 0xdafec34f, 0xca22e3fd, 0x7a0b83c0, 0xaa712387, + 0x1a5843ba, 0x4d773299, 0xfd5e52a4, 0x2d24f2e3, 0x9d0d92de, + 0x8dd1b26c, 0x3df8d251, 0xed827216, 0x5dab122b, 0x8c3c42a9, + 0x3c152294, 0xec6f82d3, 0x5c46e2ee, 0x4c9ac25c, 0xfcb3a261, + 0x2cc90226, 0x9ce0621b, 0xcfe0d2f9, 0x7fc9b2c4, 0xafb31283, + 0x1f9a72be, 0x0f46520c, 0xbf6f3231, 0x6f159276, 0xdf3cf24b, + 0x0eaba2c9, 0xbe82c2f4, 0x6ef862b3, 0xded1028e, 0xce0d223c, + 0x7e244201, 0xae5ee246, 0x1e77827b, 0x92b0e6b1, 0x2299868c, + 0xf2e326cb, 0x42ca46f6, 0x52166644, 0xe23f0679, 0x3245a63e, + 0x826cc603, 0x53fb9681, 0xe3d2f6bc, 0x33a856fb, 0x838136c6, + 0x935d1674, 0x23747649, 0xf30ed60e, 0x4327b633, 0x102706d1, + 0xa00e66ec, 0x7074c6ab, 0xc05da696, 0xd0818624, 0x60a8e619, + 0xb0d2465e, 0x00fb2663, 0xd16c76e1, 0x614516dc, 0xb13fb69b, + 0x0116d6a6, 0x11caf614, 0xa1e39629, 0x7199366e, 0xc1b05653, + 0x969f2770, 0x26b6474d, 0xf6cce70a, 0x46e58737, 0x5639a785, + 0xe610c7b8, 0x366a67ff, 0x864307c2, 0x57d45740, 0xe7fd377d, + 0x3787973a, 0x87aef707, 0x9772d7b5, 0x275bb788, 0xf72117cf, + 0x470877f2, 0x1408c710, 0xa421a72d, 0x745b076a, 0xc4726757, + 0xd4ae47e5, 0x648727d8, 0xb4fd879f, 0x04d4e7a2, 0xd543b720, + 0x656ad71d, 0xb510775a, 0x05391767, 0x15e537d5, 0xa5cc57e8, + 0x75b6f7af, 0xc59f9792, 0xdbe815e9, 0x6bc175d4, 0xbbbbd593, + 0x0b92b5ae, 0x1b4e951c, 0xab67f521, 0x7b1d5566, 0xcb34355b, + 0x1aa365d9, 0xaa8a05e4, 0x7af0a5a3, 0xcad9c59e, 0xda05e52c, + 0x6a2c8511, 0xba562556, 0x0a7f456b, 0x597ff589, 0xe95695b4, + 0x392c35f3, 0x890555ce, 0x99d9757c, 0x29f01541, 0xf98ab506, + 0x49a3d53b, 0x983485b9, 0x281de584, 0xf86745c3, 0x484e25fe, + 0x5892054c, 0xe8bb6571, 0x38c1c536, 0x88e8a50b, 0xdfc7d428, + 0x6feeb415, 0xbf941452, 0x0fbd746f, 0x1f6154dd, 0xaf4834e0, + 0x7f3294a7, 0xcf1bf49a, 0x1e8ca418, 0xaea5c425, 0x7edf6462, + 0xcef6045f, 0xde2a24ed, 0x6e0344d0, 0xbe79e497, 0x0e5084aa, + 0x5d503448, 0xed795475, 0x3d03f432, 0x8d2a940f, 0x9df6b4bd, + 0x2ddfd480, 0xfda574c7, 0x4d8c14fa, 0x9c1b4478, 0x2c322445, + 0xfc488402, 0x4c61e43f, 0x5cbdc48d, 0xec94a4b0, 0x3cee04f7, + 0x8cc764ca}, + {0x00000000, 0xa5d35ccb, 0x0ba1c84d, 0xae729486, 0x1642919b, + 0xb391cd50, 0x1de359d6, 0xb830051d, 0x6d8253ec, 0xc8510f27, + 0x66239ba1, 0xc3f0c76a, 0x7bc0c277, 0xde139ebc, 0x70610a3a, + 0xd5b256f1, 0x9b02d603, 0x3ed18ac8, 0x90a31e4e, 0x35704285, + 0x8d404798, 0x28931b53, 0x86e18fd5, 0x2332d31e, 0xf68085ef, + 0x5353d924, 0xfd214da2, 0x58f21169, 0xe0c21474, 0x451148bf, + 0xeb63dc39, 0x4eb080f2, 0x3605ac07, 0x93d6f0cc, 0x3da4644a, + 0x98773881, 0x20473d9c, 0x85946157, 0x2be6f5d1, 0x8e35a91a, + 0x5b87ffeb, 0xfe54a320, 0x502637a6, 0xf5f56b6d, 0x4dc56e70, + 0xe81632bb, 0x4664a63d, 0xe3b7faf6, 0xad077a04, 0x08d426cf, + 0xa6a6b249, 0x0375ee82, 0xbb45eb9f, 0x1e96b754, 0xb0e423d2, + 0x15377f19, 0xc08529e8, 0x65567523, 0xcb24e1a5, 0x6ef7bd6e, + 0xd6c7b873, 0x7314e4b8, 0xdd66703e, 0x78b52cf5, 0x6c0a580f, + 0xc9d904c4, 0x67ab9042, 0xc278cc89, 0x7a48c994, 0xdf9b955f, + 0x71e901d9, 0xd43a5d12, 0x01880be3, 0xa45b5728, 0x0a29c3ae, + 0xaffa9f65, 0x17ca9a78, 0xb219c6b3, 0x1c6b5235, 0xb9b80efe, + 0xf7088e0c, 0x52dbd2c7, 0xfca94641, 0x597a1a8a, 0xe14a1f97, + 0x4499435c, 0xeaebd7da, 0x4f388b11, 0x9a8adde0, 0x3f59812b, + 0x912b15ad, 0x34f84966, 0x8cc84c7b, 0x291b10b0, 0x87698436, + 0x22bad8fd, 0x5a0ff408, 0xffdca8c3, 0x51ae3c45, 0xf47d608e, + 0x4c4d6593, 0xe99e3958, 0x47ecadde, 0xe23ff115, 0x378da7e4, + 0x925efb2f, 0x3c2c6fa9, 0x99ff3362, 0x21cf367f, 0x841c6ab4, + 0x2a6efe32, 0x8fbda2f9, 0xc10d220b, 0x64de7ec0, 0xcaacea46, + 0x6f7fb68d, 0xd74fb390, 0x729cef5b, 0xdcee7bdd, 0x793d2716, + 0xac8f71e7, 0x095c2d2c, 0xa72eb9aa, 0x02fde561, 0xbacde07c, + 0x1f1ebcb7, 0xb16c2831, 0x14bf74fa, 0xd814b01e, 0x7dc7ecd5, + 0xd3b57853, 0x76662498, 0xce562185, 0x6b857d4e, 0xc5f7e9c8, + 0x6024b503, 0xb596e3f2, 0x1045bf39, 0xbe372bbf, 0x1be47774, + 0xa3d47269, 0x06072ea2, 0xa875ba24, 0x0da6e6ef, 0x4316661d, + 0xe6c53ad6, 0x48b7ae50, 0xed64f29b, 0x5554f786, 0xf087ab4d, + 0x5ef53fcb, 0xfb266300, 0x2e9435f1, 0x8b47693a, 0x2535fdbc, + 0x80e6a177, 0x38d6a46a, 0x9d05f8a1, 0x33776c27, 0x96a430ec, + 0xee111c19, 0x4bc240d2, 0xe5b0d454, 0x4063889f, 0xf8538d82, + 0x5d80d149, 0xf3f245cf, 0x56211904, 0x83934ff5, 0x2640133e, + 0x883287b8, 0x2de1db73, 0x95d1de6e, 0x300282a5, 0x9e701623, + 0x3ba34ae8, 0x7513ca1a, 0xd0c096d1, 0x7eb20257, 0xdb615e9c, + 0x63515b81, 0xc682074a, 0x68f093cc, 0xcd23cf07, 0x189199f6, + 0xbd42c53d, 0x133051bb, 0xb6e30d70, 0x0ed3086d, 0xab0054a6, + 0x0572c020, 0xa0a19ceb, 0xb41ee811, 0x11cdb4da, 0xbfbf205c, + 0x1a6c7c97, 0xa25c798a, 0x078f2541, 0xa9fdb1c7, 0x0c2eed0c, + 0xd99cbbfd, 0x7c4fe736, 0xd23d73b0, 0x77ee2f7b, 0xcfde2a66, + 0x6a0d76ad, 0xc47fe22b, 0x61acbee0, 0x2f1c3e12, 0x8acf62d9, + 0x24bdf65f, 0x816eaa94, 0x395eaf89, 0x9c8df342, 0x32ff67c4, + 0x972c3b0f, 0x429e6dfe, 0xe74d3135, 0x493fa5b3, 0xececf978, + 0x54dcfc65, 0xf10fa0ae, 0x5f7d3428, 0xfaae68e3, 0x821b4416, + 0x27c818dd, 0x89ba8c5b, 0x2c69d090, 0x9459d58d, 0x318a8946, + 0x9ff81dc0, 0x3a2b410b, 0xef9917fa, 0x4a4a4b31, 0xe438dfb7, + 0x41eb837c, 0xf9db8661, 0x5c08daaa, 0xf27a4e2c, 0x57a912e7, + 0x19199215, 0xbccacede, 0x12b85a58, 0xb76b0693, 0x0f5b038e, + 0xaa885f45, 0x04facbc3, 0xa1299708, 0x749bc1f9, 0xd1489d32, + 0x7f3a09b4, 0xdae9557f, 0x62d95062, 0xc70a0ca9, 0x6978982f, + 0xccabc4e4}, + {0x00000000, 0xb40b77a6, 0x29119f97, 0x9d1ae831, 0x13244ff4, + 0xa72f3852, 0x3a35d063, 0x8e3ea7c5, 0x674eef33, 0xd3459895, + 0x4e5f70a4, 0xfa540702, 0x746aa0c7, 0xc061d761, 0x5d7b3f50, + 0xe97048f6, 0xce9cde67, 0x7a97a9c1, 0xe78d41f0, 0x53863656, + 0xddb89193, 0x69b3e635, 0xf4a90e04, 0x40a279a2, 0xa9d23154, + 0x1dd946f2, 0x80c3aec3, 0x34c8d965, 0xbaf67ea0, 0x0efd0906, + 0x93e7e137, 0x27ec9691, 0x9c39bdcf, 0x2832ca69, 0xb5282258, + 0x012355fe, 0x8f1df23b, 0x3b16859d, 0xa60c6dac, 0x12071a0a, + 0xfb7752fc, 0x4f7c255a, 0xd266cd6b, 0x666dbacd, 0xe8531d08, + 0x5c586aae, 0xc142829f, 0x7549f539, 0x52a563a8, 0xe6ae140e, + 0x7bb4fc3f, 0xcfbf8b99, 0x41812c5c, 0xf58a5bfa, 0x6890b3cb, + 0xdc9bc46d, 0x35eb8c9b, 0x81e0fb3d, 0x1cfa130c, 0xa8f164aa, + 0x26cfc36f, 0x92c4b4c9, 0x0fde5cf8, 0xbbd52b5e, 0x79750b44, + 0xcd7e7ce2, 0x506494d3, 0xe46fe375, 0x6a5144b0, 0xde5a3316, + 0x4340db27, 0xf74bac81, 0x1e3be477, 0xaa3093d1, 0x372a7be0, + 0x83210c46, 0x0d1fab83, 0xb914dc25, 0x240e3414, 0x900543b2, + 0xb7e9d523, 0x03e2a285, 0x9ef84ab4, 0x2af33d12, 0xa4cd9ad7, + 0x10c6ed71, 0x8ddc0540, 0x39d772e6, 0xd0a73a10, 0x64ac4db6, + 0xf9b6a587, 0x4dbdd221, 0xc38375e4, 0x77880242, 0xea92ea73, + 0x5e999dd5, 0xe54cb68b, 0x5147c12d, 0xcc5d291c, 0x78565eba, + 0xf668f97f, 0x42638ed9, 0xdf7966e8, 0x6b72114e, 0x820259b8, + 0x36092e1e, 0xab13c62f, 0x1f18b189, 0x9126164c, 0x252d61ea, + 0xb83789db, 0x0c3cfe7d, 0x2bd068ec, 0x9fdb1f4a, 0x02c1f77b, + 0xb6ca80dd, 0x38f42718, 0x8cff50be, 0x11e5b88f, 0xa5eecf29, + 0x4c9e87df, 0xf895f079, 0x658f1848, 0xd1846fee, 0x5fbac82b, + 0xebb1bf8d, 0x76ab57bc, 0xc2a0201a, 0xf2ea1688, 0x46e1612e, + 0xdbfb891f, 0x6ff0feb9, 0xe1ce597c, 0x55c52eda, 0xc8dfc6eb, + 0x7cd4b14d, 0x95a4f9bb, 0x21af8e1d, 0xbcb5662c, 0x08be118a, + 0x8680b64f, 0x328bc1e9, 0xaf9129d8, 0x1b9a5e7e, 0x3c76c8ef, + 0x887dbf49, 0x15675778, 0xa16c20de, 0x2f52871b, 0x9b59f0bd, + 0x0643188c, 0xb2486f2a, 0x5b3827dc, 0xef33507a, 0x7229b84b, + 0xc622cfed, 0x481c6828, 0xfc171f8e, 0x610df7bf, 0xd5068019, + 0x6ed3ab47, 0xdad8dce1, 0x47c234d0, 0xf3c94376, 0x7df7e4b3, + 0xc9fc9315, 0x54e67b24, 0xe0ed0c82, 0x099d4474, 0xbd9633d2, + 0x208cdbe3, 0x9487ac45, 0x1ab90b80, 0xaeb27c26, 0x33a89417, + 0x87a3e3b1, 0xa04f7520, 0x14440286, 0x895eeab7, 0x3d559d11, + 0xb36b3ad4, 0x07604d72, 0x9a7aa543, 0x2e71d2e5, 0xc7019a13, + 0x730aedb5, 0xee100584, 0x5a1b7222, 0xd425d5e7, 0x602ea241, + 0xfd344a70, 0x493f3dd6, 0x8b9f1dcc, 0x3f946a6a, 0xa28e825b, + 0x1685f5fd, 0x98bb5238, 0x2cb0259e, 0xb1aacdaf, 0x05a1ba09, + 0xecd1f2ff, 0x58da8559, 0xc5c06d68, 0x71cb1ace, 0xfff5bd0b, + 0x4bfecaad, 0xd6e4229c, 0x62ef553a, 0x4503c3ab, 0xf108b40d, + 0x6c125c3c, 0xd8192b9a, 0x56278c5f, 0xe22cfbf9, 0x7f3613c8, + 0xcb3d646e, 0x224d2c98, 0x96465b3e, 0x0b5cb30f, 0xbf57c4a9, + 0x3169636c, 0x856214ca, 0x1878fcfb, 0xac738b5d, 0x17a6a003, + 0xa3add7a5, 0x3eb73f94, 0x8abc4832, 0x0482eff7, 0xb0899851, + 0x2d937060, 0x999807c6, 0x70e84f30, 0xc4e33896, 0x59f9d0a7, + 0xedf2a701, 0x63cc00c4, 0xd7c77762, 0x4add9f53, 0xfed6e8f5, + 0xd93a7e64, 0x6d3109c2, 0xf02be1f3, 0x44209655, 0xca1e3190, + 0x7e154636, 0xe30fae07, 0x5704d9a1, 0xbe749157, 0x0a7fe6f1, + 0x97650ec0, 0x236e7966, 0xad50dea3, 0x195ba905, 0x84414134, + 0x304a3692}, + {0x00000000, 0x9e00aacc, 0x7d072542, 0xe3078f8e, 0xfa0e4a84, + 0x640ee048, 0x87096fc6, 0x1909c50a, 0xb51be5d3, 0x2b1b4f1f, + 0xc81cc091, 0x561c6a5d, 0x4f15af57, 0xd115059b, 0x32128a15, + 0xac1220d9, 0x2b31bb7c, 0xb53111b0, 0x56369e3e, 0xc83634f2, + 0xd13ff1f8, 0x4f3f5b34, 0xac38d4ba, 0x32387e76, 0x9e2a5eaf, + 0x002af463, 0xe32d7bed, 0x7d2dd121, 0x6424142b, 0xfa24bee7, + 0x19233169, 0x87239ba5, 0x566276f9, 0xc862dc35, 0x2b6553bb, + 0xb565f977, 0xac6c3c7d, 0x326c96b1, 0xd16b193f, 0x4f6bb3f3, + 0xe379932a, 0x7d7939e6, 0x9e7eb668, 0x007e1ca4, 0x1977d9ae, + 0x87777362, 0x6470fcec, 0xfa705620, 0x7d53cd85, 0xe3536749, + 0x0054e8c7, 0x9e54420b, 0x875d8701, 0x195d2dcd, 0xfa5aa243, + 0x645a088f, 0xc8482856, 0x5648829a, 0xb54f0d14, 0x2b4fa7d8, + 0x324662d2, 0xac46c81e, 0x4f414790, 0xd141ed5c, 0xedc29d29, + 0x73c237e5, 0x90c5b86b, 0x0ec512a7, 0x17ccd7ad, 0x89cc7d61, + 0x6acbf2ef, 0xf4cb5823, 0x58d978fa, 0xc6d9d236, 0x25de5db8, + 0xbbdef774, 0xa2d7327e, 0x3cd798b2, 0xdfd0173c, 0x41d0bdf0, + 0xc6f32655, 0x58f38c99, 0xbbf40317, 0x25f4a9db, 0x3cfd6cd1, + 0xa2fdc61d, 0x41fa4993, 0xdffae35f, 0x73e8c386, 0xede8694a, + 0x0eefe6c4, 0x90ef4c08, 0x89e68902, 0x17e623ce, 0xf4e1ac40, + 0x6ae1068c, 0xbba0ebd0, 0x25a0411c, 0xc6a7ce92, 0x58a7645e, + 0x41aea154, 0xdfae0b98, 0x3ca98416, 0xa2a92eda, 0x0ebb0e03, + 0x90bba4cf, 0x73bc2b41, 0xedbc818d, 0xf4b54487, 0x6ab5ee4b, + 0x89b261c5, 0x17b2cb09, 0x909150ac, 0x0e91fa60, 0xed9675ee, + 0x7396df22, 0x6a9f1a28, 0xf49fb0e4, 0x17983f6a, 0x899895a6, + 0x258ab57f, 0xbb8a1fb3, 0x588d903d, 0xc68d3af1, 0xdf84fffb, + 0x41845537, 0xa283dab9, 0x3c837075, 0xda853b53, 0x4485919f, + 0xa7821e11, 0x3982b4dd, 0x208b71d7, 0xbe8bdb1b, 0x5d8c5495, + 0xc38cfe59, 0x6f9ede80, 0xf19e744c, 0x1299fbc2, 0x8c99510e, + 0x95909404, 0x0b903ec8, 0xe897b146, 0x76971b8a, 0xf1b4802f, + 0x6fb42ae3, 0x8cb3a56d, 0x12b30fa1, 0x0bbacaab, 0x95ba6067, + 0x76bdefe9, 0xe8bd4525, 0x44af65fc, 0xdaafcf30, 0x39a840be, + 0xa7a8ea72, 0xbea12f78, 0x20a185b4, 0xc3a60a3a, 0x5da6a0f6, + 0x8ce74daa, 0x12e7e766, 0xf1e068e8, 0x6fe0c224, 0x76e9072e, + 0xe8e9ade2, 0x0bee226c, 0x95ee88a0, 0x39fca879, 0xa7fc02b5, + 0x44fb8d3b, 0xdafb27f7, 0xc3f2e2fd, 0x5df24831, 0xbef5c7bf, + 0x20f56d73, 0xa7d6f6d6, 0x39d65c1a, 0xdad1d394, 0x44d17958, + 0x5dd8bc52, 0xc3d8169e, 0x20df9910, 0xbedf33dc, 0x12cd1305, + 0x8ccdb9c9, 0x6fca3647, 0xf1ca9c8b, 0xe8c35981, 0x76c3f34d, + 0x95c47cc3, 0x0bc4d60f, 0x3747a67a, 0xa9470cb6, 0x4a408338, + 0xd44029f4, 0xcd49ecfe, 0x53494632, 0xb04ec9bc, 0x2e4e6370, + 0x825c43a9, 0x1c5ce965, 0xff5b66eb, 0x615bcc27, 0x7852092d, + 0xe652a3e1, 0x05552c6f, 0x9b5586a3, 0x1c761d06, 0x8276b7ca, + 0x61713844, 0xff719288, 0xe6785782, 0x7878fd4e, 0x9b7f72c0, + 0x057fd80c, 0xa96df8d5, 0x376d5219, 0xd46add97, 0x4a6a775b, + 0x5363b251, 0xcd63189d, 0x2e649713, 0xb0643ddf, 0x6125d083, + 0xff257a4f, 0x1c22f5c1, 0x82225f0d, 0x9b2b9a07, 0x052b30cb, + 0xe62cbf45, 0x782c1589, 0xd43e3550, 0x4a3e9f9c, 0xa9391012, + 0x3739bade, 0x2e307fd4, 0xb030d518, 0x53375a96, 0xcd37f05a, + 0x4a146bff, 0xd414c133, 0x37134ebd, 0xa913e471, 0xb01a217b, + 0x2e1a8bb7, 0xcd1d0439, 0x531daef5, 0xff0f8e2c, 0x610f24e0, + 0x8208ab6e, 0x1c0801a2, 0x0501c4a8, 0x9b016e64, 0x7806e1ea, + 0xe6064b26}}; + +#endif + +#endif + +#if N == 3 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x81256527, 0xd93bcc0f, 0x581ea928, 0x69069e5f, + 0xe823fb78, 0xb03d5250, 0x31183777, 0xd20d3cbe, 0x53285999, + 0x0b36f0b1, 0x8a139596, 0xbb0ba2e1, 0x3a2ec7c6, 0x62306eee, + 0xe3150bc9, 0x7f6b7f3d, 0xfe4e1a1a, 0xa650b332, 0x2775d615, + 0x166de162, 0x97488445, 0xcf562d6d, 0x4e73484a, 0xad664383, + 0x2c4326a4, 0x745d8f8c, 0xf578eaab, 0xc460dddc, 0x4545b8fb, + 0x1d5b11d3, 0x9c7e74f4, 0xfed6fe7a, 0x7ff39b5d, 0x27ed3275, + 0xa6c85752, 0x97d06025, 0x16f50502, 0x4eebac2a, 0xcfcec90d, + 0x2cdbc2c4, 0xadfea7e3, 0xf5e00ecb, 0x74c56bec, 0x45dd5c9b, + 0xc4f839bc, 0x9ce69094, 0x1dc3f5b3, 0x81bd8147, 0x0098e460, + 0x58864d48, 0xd9a3286f, 0xe8bb1f18, 0x699e7a3f, 0x3180d317, + 0xb0a5b630, 0x53b0bdf9, 0xd295d8de, 0x8a8b71f6, 0x0bae14d1, + 0x3ab623a6, 0xbb934681, 0xe38defa9, 0x62a88a8e, 0x26dcfab5, + 0xa7f99f92, 0xffe736ba, 0x7ec2539d, 0x4fda64ea, 0xceff01cd, + 0x96e1a8e5, 0x17c4cdc2, 0xf4d1c60b, 0x75f4a32c, 0x2dea0a04, + 0xaccf6f23, 0x9dd75854, 0x1cf23d73, 0x44ec945b, 0xc5c9f17c, + 0x59b78588, 0xd892e0af, 0x808c4987, 0x01a92ca0, 0x30b11bd7, + 0xb1947ef0, 0xe98ad7d8, 0x68afb2ff, 0x8bbab936, 0x0a9fdc11, + 0x52817539, 0xd3a4101e, 0xe2bc2769, 0x6399424e, 0x3b87eb66, + 0xbaa28e41, 0xd80a04cf, 0x592f61e8, 0x0131c8c0, 0x8014ade7, + 0xb10c9a90, 0x3029ffb7, 0x6837569f, 0xe91233b8, 0x0a073871, + 0x8b225d56, 0xd33cf47e, 0x52199159, 0x6301a62e, 0xe224c309, + 0xba3a6a21, 0x3b1f0f06, 0xa7617bf2, 0x26441ed5, 0x7e5ab7fd, + 0xff7fd2da, 0xce67e5ad, 0x4f42808a, 0x175c29a2, 0x96794c85, + 0x756c474c, 0xf449226b, 0xac578b43, 0x2d72ee64, 0x1c6ad913, + 0x9d4fbc34, 0xc551151c, 0x4474703b, 0x4db9f56a, 0xcc9c904d, + 0x94823965, 0x15a75c42, 0x24bf6b35, 0xa59a0e12, 0xfd84a73a, + 0x7ca1c21d, 0x9fb4c9d4, 0x1e91acf3, 0x468f05db, 0xc7aa60fc, + 0xf6b2578b, 0x779732ac, 0x2f899b84, 0xaeacfea3, 0x32d28a57, + 0xb3f7ef70, 0xebe94658, 0x6acc237f, 0x5bd41408, 0xdaf1712f, + 0x82efd807, 0x03cabd20, 0xe0dfb6e9, 0x61fad3ce, 0x39e47ae6, + 0xb8c11fc1, 0x89d928b6, 0x08fc4d91, 0x50e2e4b9, 0xd1c7819e, + 0xb36f0b10, 0x324a6e37, 0x6a54c71f, 0xeb71a238, 0xda69954f, + 0x5b4cf068, 0x03525940, 0x82773c67, 0x616237ae, 0xe0475289, + 0xb859fba1, 0x397c9e86, 0x0864a9f1, 0x8941ccd6, 0xd15f65fe, + 0x507a00d9, 0xcc04742d, 0x4d21110a, 0x153fb822, 0x941add05, + 0xa502ea72, 0x24278f55, 0x7c39267d, 0xfd1c435a, 0x1e094893, + 0x9f2c2db4, 0xc732849c, 0x4617e1bb, 0x770fd6cc, 0xf62ab3eb, + 0xae341ac3, 0x2f117fe4, 0x6b650fdf, 0xea406af8, 0xb25ec3d0, + 0x337ba6f7, 0x02639180, 0x8346f4a7, 0xdb585d8f, 0x5a7d38a8, + 0xb9683361, 0x384d5646, 0x6053ff6e, 0xe1769a49, 0xd06ead3e, + 0x514bc819, 0x09556131, 0x88700416, 0x140e70e2, 0x952b15c5, + 0xcd35bced, 0x4c10d9ca, 0x7d08eebd, 0xfc2d8b9a, 0xa43322b2, + 0x25164795, 0xc6034c5c, 0x4726297b, 0x1f388053, 0x9e1de574, + 0xaf05d203, 0x2e20b724, 0x763e1e0c, 0xf71b7b2b, 0x95b3f1a5, + 0x14969482, 0x4c883daa, 0xcdad588d, 0xfcb56ffa, 0x7d900add, + 0x258ea3f5, 0xa4abc6d2, 0x47becd1b, 0xc69ba83c, 0x9e850114, + 0x1fa06433, 0x2eb85344, 0xaf9d3663, 0xf7839f4b, 0x76a6fa6c, + 0xead88e98, 0x6bfdebbf, 0x33e34297, 0xb2c627b0, 0x83de10c7, + 0x02fb75e0, 0x5ae5dcc8, 0xdbc0b9ef, 0x38d5b226, 0xb9f0d701, + 0xe1ee7e29, 0x60cb1b0e, 0x51d32c79, 0xd0f6495e, 0x88e8e076, + 0x09cd8551}, + {0x00000000, 0x9b73ead4, 0xed96d3e9, 0x76e5393d, 0x005ca193, + 0x9b2f4b47, 0xedca727a, 0x76b998ae, 0x00b94326, 0x9bcaa9f2, + 0xed2f90cf, 0x765c7a1b, 0x00e5e2b5, 0x9b960861, 0xed73315c, + 0x7600db88, 0x0172864c, 0x9a016c98, 0xece455a5, 0x7797bf71, + 0x012e27df, 0x9a5dcd0b, 0xecb8f436, 0x77cb1ee2, 0x01cbc56a, + 0x9ab82fbe, 0xec5d1683, 0x772efc57, 0x019764f9, 0x9ae48e2d, + 0xec01b710, 0x77725dc4, 0x02e50c98, 0x9996e64c, 0xef73df71, + 0x740035a5, 0x02b9ad0b, 0x99ca47df, 0xef2f7ee2, 0x745c9436, + 0x025c4fbe, 0x992fa56a, 0xefca9c57, 0x74b97683, 0x0200ee2d, + 0x997304f9, 0xef963dc4, 0x74e5d710, 0x03978ad4, 0x98e46000, + 0xee01593d, 0x7572b3e9, 0x03cb2b47, 0x98b8c193, 0xee5df8ae, + 0x752e127a, 0x032ec9f2, 0x985d2326, 0xeeb81a1b, 0x75cbf0cf, + 0x03726861, 0x980182b5, 0xeee4bb88, 0x7597515c, 0x05ca1930, + 0x9eb9f3e4, 0xe85ccad9, 0x732f200d, 0x0596b8a3, 0x9ee55277, + 0xe8006b4a, 0x7373819e, 0x05735a16, 0x9e00b0c2, 0xe8e589ff, + 0x7396632b, 0x052ffb85, 0x9e5c1151, 0xe8b9286c, 0x73cac2b8, + 0x04b89f7c, 0x9fcb75a8, 0xe92e4c95, 0x725da641, 0x04e43eef, + 0x9f97d43b, 0xe972ed06, 0x720107d2, 0x0401dc5a, 0x9f72368e, + 0xe9970fb3, 0x72e4e567, 0x045d7dc9, 0x9f2e971d, 0xe9cbae20, + 0x72b844f4, 0x072f15a8, 0x9c5cff7c, 0xeab9c641, 0x71ca2c95, + 0x0773b43b, 0x9c005eef, 0xeae567d2, 0x71968d06, 0x0796568e, + 0x9ce5bc5a, 0xea008567, 0x71736fb3, 0x07caf71d, 0x9cb91dc9, + 0xea5c24f4, 0x712fce20, 0x065d93e4, 0x9d2e7930, 0xebcb400d, + 0x70b8aad9, 0x06013277, 0x9d72d8a3, 0xeb97e19e, 0x70e40b4a, + 0x06e4d0c2, 0x9d973a16, 0xeb72032b, 0x7001e9ff, 0x06b87151, + 0x9dcb9b85, 0xeb2ea2b8, 0x705d486c, 0x0b943260, 0x90e7d8b4, + 0xe602e189, 0x7d710b5d, 0x0bc893f3, 0x90bb7927, 0xe65e401a, + 0x7d2daace, 0x0b2d7146, 0x905e9b92, 0xe6bba2af, 0x7dc8487b, + 0x0b71d0d5, 0x90023a01, 0xe6e7033c, 0x7d94e9e8, 0x0ae6b42c, + 0x91955ef8, 0xe77067c5, 0x7c038d11, 0x0aba15bf, 0x91c9ff6b, + 0xe72cc656, 0x7c5f2c82, 0x0a5ff70a, 0x912c1dde, 0xe7c924e3, + 0x7cbace37, 0x0a035699, 0x9170bc4d, 0xe7958570, 0x7ce66fa4, + 0x09713ef8, 0x9202d42c, 0xe4e7ed11, 0x7f9407c5, 0x092d9f6b, + 0x925e75bf, 0xe4bb4c82, 0x7fc8a656, 0x09c87dde, 0x92bb970a, + 0xe45eae37, 0x7f2d44e3, 0x0994dc4d, 0x92e73699, 0xe4020fa4, + 0x7f71e570, 0x0803b8b4, 0x93705260, 0xe5956b5d, 0x7ee68189, + 0x085f1927, 0x932cf3f3, 0xe5c9cace, 0x7eba201a, 0x08bafb92, + 0x93c91146, 0xe52c287b, 0x7e5fc2af, 0x08e65a01, 0x9395b0d5, + 0xe57089e8, 0x7e03633c, 0x0e5e2b50, 0x952dc184, 0xe3c8f8b9, + 0x78bb126d, 0x0e028ac3, 0x95716017, 0xe394592a, 0x78e7b3fe, + 0x0ee76876, 0x959482a2, 0xe371bb9f, 0x7802514b, 0x0ebbc9e5, + 0x95c82331, 0xe32d1a0c, 0x785ef0d8, 0x0f2cad1c, 0x945f47c8, + 0xe2ba7ef5, 0x79c99421, 0x0f700c8f, 0x9403e65b, 0xe2e6df66, + 0x799535b2, 0x0f95ee3a, 0x94e604ee, 0xe2033dd3, 0x7970d707, + 0x0fc94fa9, 0x94baa57d, 0xe25f9c40, 0x792c7694, 0x0cbb27c8, + 0x97c8cd1c, 0xe12df421, 0x7a5e1ef5, 0x0ce7865b, 0x97946c8f, + 0xe17155b2, 0x7a02bf66, 0x0c0264ee, 0x97718e3a, 0xe194b707, + 0x7ae75dd3, 0x0c5ec57d, 0x972d2fa9, 0xe1c81694, 0x7abbfc40, + 0x0dc9a184, 0x96ba4b50, 0xe05f726d, 0x7b2c98b9, 0x0d950017, + 0x96e6eac3, 0xe003d3fe, 0x7b70392a, 0x0d70e2a2, 0x96030876, + 0xe0e6314b, 0x7b95db9f, 0x0d2c4331, 0x965fa9e5, 0xe0ba90d8, + 0x7bc97a0c}, + {0x00000000, 0x172864c0, 0x2e50c980, 0x3978ad40, 0x5ca19300, + 0x4b89f7c0, 0x72f15a80, 0x65d93e40, 0xb9432600, 0xae6b42c0, + 0x9713ef80, 0x803b8b40, 0xe5e2b500, 0xf2cad1c0, 0xcbb27c80, + 0xdc9a1840, 0xa9f74a41, 0xbedf2e81, 0x87a783c1, 0x908fe701, + 0xf556d941, 0xe27ebd81, 0xdb0610c1, 0xcc2e7401, 0x10b46c41, + 0x079c0881, 0x3ee4a5c1, 0x29ccc101, 0x4c15ff41, 0x5b3d9b81, + 0x624536c1, 0x756d5201, 0x889f92c3, 0x9fb7f603, 0xa6cf5b43, + 0xb1e73f83, 0xd43e01c3, 0xc3166503, 0xfa6ec843, 0xed46ac83, + 0x31dcb4c3, 0x26f4d003, 0x1f8c7d43, 0x08a41983, 0x6d7d27c3, + 0x7a554303, 0x432dee43, 0x54058a83, 0x2168d882, 0x3640bc42, + 0x0f381102, 0x181075c2, 0x7dc94b82, 0x6ae12f42, 0x53998202, + 0x44b1e6c2, 0x982bfe82, 0x8f039a42, 0xb67b3702, 0xa15353c2, + 0xc48a6d82, 0xd3a20942, 0xeadaa402, 0xfdf2c0c2, 0xca4e23c7, + 0xdd664707, 0xe41eea47, 0xf3368e87, 0x96efb0c7, 0x81c7d407, + 0xb8bf7947, 0xaf971d87, 0x730d05c7, 0x64256107, 0x5d5dcc47, + 0x4a75a887, 0x2fac96c7, 0x3884f207, 0x01fc5f47, 0x16d43b87, + 0x63b96986, 0x74910d46, 0x4de9a006, 0x5ac1c4c6, 0x3f18fa86, + 0x28309e46, 0x11483306, 0x066057c6, 0xdafa4f86, 0xcdd22b46, + 0xf4aa8606, 0xe382e2c6, 0x865bdc86, 0x9173b846, 0xa80b1506, + 0xbf2371c6, 0x42d1b104, 0x55f9d5c4, 0x6c817884, 0x7ba91c44, + 0x1e702204, 0x095846c4, 0x3020eb84, 0x27088f44, 0xfb929704, + 0xecbaf3c4, 0xd5c25e84, 0xc2ea3a44, 0xa7330404, 0xb01b60c4, + 0x8963cd84, 0x9e4ba944, 0xeb26fb45, 0xfc0e9f85, 0xc57632c5, + 0xd25e5605, 0xb7876845, 0xa0af0c85, 0x99d7a1c5, 0x8effc505, + 0x5265dd45, 0x454db985, 0x7c3514c5, 0x6b1d7005, 0x0ec44e45, + 0x19ec2a85, 0x209487c5, 0x37bce305, 0x4fed41cf, 0x58c5250f, + 0x61bd884f, 0x7695ec8f, 0x134cd2cf, 0x0464b60f, 0x3d1c1b4f, + 0x2a347f8f, 0xf6ae67cf, 0xe186030f, 0xd8feae4f, 0xcfd6ca8f, + 0xaa0ff4cf, 0xbd27900f, 0x845f3d4f, 0x9377598f, 0xe61a0b8e, + 0xf1326f4e, 0xc84ac20e, 0xdf62a6ce, 0xbabb988e, 0xad93fc4e, + 0x94eb510e, 0x83c335ce, 0x5f592d8e, 0x4871494e, 0x7109e40e, + 0x662180ce, 0x03f8be8e, 0x14d0da4e, 0x2da8770e, 0x3a8013ce, + 0xc772d30c, 0xd05ab7cc, 0xe9221a8c, 0xfe0a7e4c, 0x9bd3400c, + 0x8cfb24cc, 0xb583898c, 0xa2abed4c, 0x7e31f50c, 0x691991cc, + 0x50613c8c, 0x4749584c, 0x2290660c, 0x35b802cc, 0x0cc0af8c, + 0x1be8cb4c, 0x6e85994d, 0x79adfd8d, 0x40d550cd, 0x57fd340d, + 0x32240a4d, 0x250c6e8d, 0x1c74c3cd, 0x0b5ca70d, 0xd7c6bf4d, + 0xc0eedb8d, 0xf99676cd, 0xeebe120d, 0x8b672c4d, 0x9c4f488d, + 0xa537e5cd, 0xb21f810d, 0x85a36208, 0x928b06c8, 0xabf3ab88, + 0xbcdbcf48, 0xd902f108, 0xce2a95c8, 0xf7523888, 0xe07a5c48, + 0x3ce04408, 0x2bc820c8, 0x12b08d88, 0x0598e948, 0x6041d708, + 0x7769b3c8, 0x4e111e88, 0x59397a48, 0x2c542849, 0x3b7c4c89, + 0x0204e1c9, 0x152c8509, 0x70f5bb49, 0x67dddf89, 0x5ea572c9, + 0x498d1609, 0x95170e49, 0x823f6a89, 0xbb47c7c9, 0xac6fa309, + 0xc9b69d49, 0xde9ef989, 0xe7e654c9, 0xf0ce3009, 0x0d3cf0cb, + 0x1a14940b, 0x236c394b, 0x34445d8b, 0x519d63cb, 0x46b5070b, + 0x7fcdaa4b, 0x68e5ce8b, 0xb47fd6cb, 0xa357b20b, 0x9a2f1f4b, + 0x8d077b8b, 0xe8de45cb, 0xfff6210b, 0xc68e8c4b, 0xd1a6e88b, + 0xa4cbba8a, 0xb3e3de4a, 0x8a9b730a, 0x9db317ca, 0xf86a298a, + 0xef424d4a, 0xd63ae00a, 0xc11284ca, 0x1d889c8a, 0x0aa0f84a, + 0x33d8550a, 0x24f031ca, 0x41290f8a, 0x56016b4a, 0x6f79c60a, + 0x7851a2ca}, + {0x00000000, 0x9fda839e, 0xe4c4017d, 0x7b1e82e3, 0x12f904bb, + 0x8d238725, 0xf63d05c6, 0x69e78658, 0x25f20976, 0xba288ae8, + 0xc136080b, 0x5eec8b95, 0x370b0dcd, 0xa8d18e53, 0xd3cf0cb0, + 0x4c158f2e, 0x4be412ec, 0xd43e9172, 0xaf201391, 0x30fa900f, + 0x591d1657, 0xc6c795c9, 0xbdd9172a, 0x220394b4, 0x6e161b9a, + 0xf1cc9804, 0x8ad21ae7, 0x15089979, 0x7cef1f21, 0xe3359cbf, + 0x982b1e5c, 0x07f19dc2, 0x97c825d8, 0x0812a646, 0x730c24a5, + 0xecd6a73b, 0x85312163, 0x1aeba2fd, 0x61f5201e, 0xfe2fa380, + 0xb23a2cae, 0x2de0af30, 0x56fe2dd3, 0xc924ae4d, 0xa0c32815, + 0x3f19ab8b, 0x44072968, 0xdbddaaf6, 0xdc2c3734, 0x43f6b4aa, + 0x38e83649, 0xa732b5d7, 0xced5338f, 0x510fb011, 0x2a1132f2, + 0xb5cbb16c, 0xf9de3e42, 0x6604bddc, 0x1d1a3f3f, 0x82c0bca1, + 0xeb273af9, 0x74fdb967, 0x0fe33b84, 0x9039b81a, 0xf4e14df1, + 0x6b3bce6f, 0x10254c8c, 0x8fffcf12, 0xe618494a, 0x79c2cad4, + 0x02dc4837, 0x9d06cba9, 0xd1134487, 0x4ec9c719, 0x35d745fa, + 0xaa0dc664, 0xc3ea403c, 0x5c30c3a2, 0x272e4141, 0xb8f4c2df, + 0xbf055f1d, 0x20dfdc83, 0x5bc15e60, 0xc41bddfe, 0xadfc5ba6, + 0x3226d838, 0x49385adb, 0xd6e2d945, 0x9af7566b, 0x052dd5f5, + 0x7e335716, 0xe1e9d488, 0x880e52d0, 0x17d4d14e, 0x6cca53ad, + 0xf310d033, 0x63296829, 0xfcf3ebb7, 0x87ed6954, 0x1837eaca, + 0x71d06c92, 0xee0aef0c, 0x95146def, 0x0aceee71, 0x46db615f, + 0xd901e2c1, 0xa21f6022, 0x3dc5e3bc, 0x542265e4, 0xcbf8e67a, + 0xb0e66499, 0x2f3ce707, 0x28cd7ac5, 0xb717f95b, 0xcc097bb8, + 0x53d3f826, 0x3a347e7e, 0xa5eefde0, 0xdef07f03, 0x412afc9d, + 0x0d3f73b3, 0x92e5f02d, 0xe9fb72ce, 0x7621f150, 0x1fc67708, + 0x801cf496, 0xfb027675, 0x64d8f5eb, 0x32b39da3, 0xad691e3d, + 0xd6779cde, 0x49ad1f40, 0x204a9918, 0xbf901a86, 0xc48e9865, + 0x5b541bfb, 0x174194d5, 0x889b174b, 0xf38595a8, 0x6c5f1636, + 0x05b8906e, 0x9a6213f0, 0xe17c9113, 0x7ea6128d, 0x79578f4f, + 0xe68d0cd1, 0x9d938e32, 0x02490dac, 0x6bae8bf4, 0xf474086a, + 0x8f6a8a89, 0x10b00917, 0x5ca58639, 0xc37f05a7, 0xb8618744, + 0x27bb04da, 0x4e5c8282, 0xd186011c, 0xaa9883ff, 0x35420061, + 0xa57bb87b, 0x3aa13be5, 0x41bfb906, 0xde653a98, 0xb782bcc0, + 0x28583f5e, 0x5346bdbd, 0xcc9c3e23, 0x8089b10d, 0x1f533293, + 0x644db070, 0xfb9733ee, 0x9270b5b6, 0x0daa3628, 0x76b4b4cb, + 0xe96e3755, 0xee9faa97, 0x71452909, 0x0a5babea, 0x95812874, + 0xfc66ae2c, 0x63bc2db2, 0x18a2af51, 0x87782ccf, 0xcb6da3e1, + 0x54b7207f, 0x2fa9a29c, 0xb0732102, 0xd994a75a, 0x464e24c4, + 0x3d50a627, 0xa28a25b9, 0xc652d052, 0x598853cc, 0x2296d12f, + 0xbd4c52b1, 0xd4abd4e9, 0x4b715777, 0x306fd594, 0xafb5560a, + 0xe3a0d924, 0x7c7a5aba, 0x0764d859, 0x98be5bc7, 0xf159dd9f, + 0x6e835e01, 0x159ddce2, 0x8a475f7c, 0x8db6c2be, 0x126c4120, + 0x6972c3c3, 0xf6a8405d, 0x9f4fc605, 0x0095459b, 0x7b8bc778, + 0xe45144e6, 0xa844cbc8, 0x379e4856, 0x4c80cab5, 0xd35a492b, + 0xbabdcf73, 0x25674ced, 0x5e79ce0e, 0xc1a34d90, 0x519af58a, + 0xce407614, 0xb55ef4f7, 0x2a847769, 0x4363f131, 0xdcb972af, + 0xa7a7f04c, 0x387d73d2, 0x7468fcfc, 0xebb27f62, 0x90acfd81, + 0x0f767e1f, 0x6691f847, 0xf94b7bd9, 0x8255f93a, 0x1d8f7aa4, + 0x1a7ee766, 0x85a464f8, 0xfebae61b, 0x61606585, 0x0887e3dd, + 0x975d6043, 0xec43e2a0, 0x7399613e, 0x3f8cee10, 0xa0566d8e, + 0xdb48ef6d, 0x44926cf3, 0x2d75eaab, 0xb2af6935, 0xc9b1ebd6, + 0x566b6848}, + {0x00000000, 0x65673b46, 0xcace768c, 0xafa94dca, 0x4eedeb59, + 0x2b8ad01f, 0x84239dd5, 0xe144a693, 0x9ddbd6b2, 0xf8bcedf4, + 0x5715a03e, 0x32729b78, 0xd3363deb, 0xb65106ad, 0x19f84b67, + 0x7c9f7021, 0xe0c6ab25, 0x85a19063, 0x2a08dda9, 0x4f6fe6ef, + 0xae2b407c, 0xcb4c7b3a, 0x64e536f0, 0x01820db6, 0x7d1d7d97, + 0x187a46d1, 0xb7d30b1b, 0xd2b4305d, 0x33f096ce, 0x5697ad88, + 0xf93ee042, 0x9c59db04, 0x1afc500b, 0x7f9b6b4d, 0xd0322687, + 0xb5551dc1, 0x5411bb52, 0x31768014, 0x9edfcdde, 0xfbb8f698, + 0x872786b9, 0xe240bdff, 0x4de9f035, 0x288ecb73, 0xc9ca6de0, + 0xacad56a6, 0x03041b6c, 0x6663202a, 0xfa3afb2e, 0x9f5dc068, + 0x30f48da2, 0x5593b6e4, 0xb4d71077, 0xd1b02b31, 0x7e1966fb, + 0x1b7e5dbd, 0x67e12d9c, 0x028616da, 0xad2f5b10, 0xc8486056, + 0x290cc6c5, 0x4c6bfd83, 0xe3c2b049, 0x86a58b0f, 0x35f8a016, + 0x509f9b50, 0xff36d69a, 0x9a51eddc, 0x7b154b4f, 0x1e727009, + 0xb1db3dc3, 0xd4bc0685, 0xa82376a4, 0xcd444de2, 0x62ed0028, + 0x078a3b6e, 0xe6ce9dfd, 0x83a9a6bb, 0x2c00eb71, 0x4967d037, + 0xd53e0b33, 0xb0593075, 0x1ff07dbf, 0x7a9746f9, 0x9bd3e06a, + 0xfeb4db2c, 0x511d96e6, 0x347aada0, 0x48e5dd81, 0x2d82e6c7, + 0x822bab0d, 0xe74c904b, 0x060836d8, 0x636f0d9e, 0xccc64054, + 0xa9a17b12, 0x2f04f01d, 0x4a63cb5b, 0xe5ca8691, 0x80adbdd7, + 0x61e91b44, 0x048e2002, 0xab276dc8, 0xce40568e, 0xb2df26af, + 0xd7b81de9, 0x78115023, 0x1d766b65, 0xfc32cdf6, 0x9955f6b0, + 0x36fcbb7a, 0x539b803c, 0xcfc25b38, 0xaaa5607e, 0x050c2db4, + 0x606b16f2, 0x812fb061, 0xe4488b27, 0x4be1c6ed, 0x2e86fdab, + 0x52198d8a, 0x377eb6cc, 0x98d7fb06, 0xfdb0c040, 0x1cf466d3, + 0x79935d95, 0xd63a105f, 0xb35d2b19, 0x6bf1402c, 0x0e967b6a, + 0xa13f36a0, 0xc4580de6, 0x251cab75, 0x407b9033, 0xefd2ddf9, + 0x8ab5e6bf, 0xf62a969e, 0x934dadd8, 0x3ce4e012, 0x5983db54, + 0xb8c77dc7, 0xdda04681, 0x72090b4b, 0x176e300d, 0x8b37eb09, + 0xee50d04f, 0x41f99d85, 0x249ea6c3, 0xc5da0050, 0xa0bd3b16, + 0x0f1476dc, 0x6a734d9a, 0x16ec3dbb, 0x738b06fd, 0xdc224b37, + 0xb9457071, 0x5801d6e2, 0x3d66eda4, 0x92cfa06e, 0xf7a89b28, + 0x710d1027, 0x146a2b61, 0xbbc366ab, 0xdea45ded, 0x3fe0fb7e, + 0x5a87c038, 0xf52e8df2, 0x9049b6b4, 0xecd6c695, 0x89b1fdd3, + 0x2618b019, 0x437f8b5f, 0xa23b2dcc, 0xc75c168a, 0x68f55b40, + 0x0d926006, 0x91cbbb02, 0xf4ac8044, 0x5b05cd8e, 0x3e62f6c8, + 0xdf26505b, 0xba416b1d, 0x15e826d7, 0x708f1d91, 0x0c106db0, + 0x697756f6, 0xc6de1b3c, 0xa3b9207a, 0x42fd86e9, 0x279abdaf, + 0x8833f065, 0xed54cb23, 0x5e09e03a, 0x3b6edb7c, 0x94c796b6, + 0xf1a0adf0, 0x10e40b63, 0x75833025, 0xda2a7def, 0xbf4d46a9, + 0xc3d23688, 0xa6b50dce, 0x091c4004, 0x6c7b7b42, 0x8d3fddd1, + 0xe858e697, 0x47f1ab5d, 0x2296901b, 0xbecf4b1f, 0xdba87059, + 0x74013d93, 0x116606d5, 0xf022a046, 0x95459b00, 0x3aecd6ca, + 0x5f8bed8c, 0x23149dad, 0x4673a6eb, 0xe9daeb21, 0x8cbdd067, + 0x6df976f4, 0x089e4db2, 0xa7370078, 0xc2503b3e, 0x44f5b031, + 0x21928b77, 0x8e3bc6bd, 0xeb5cfdfb, 0x0a185b68, 0x6f7f602e, + 0xc0d62de4, 0xa5b116a2, 0xd92e6683, 0xbc495dc5, 0x13e0100f, + 0x76872b49, 0x97c38dda, 0xf2a4b69c, 0x5d0dfb56, 0x386ac010, + 0xa4331b14, 0xc1542052, 0x6efd6d98, 0x0b9a56de, 0xeadef04d, + 0x8fb9cb0b, 0x201086c1, 0x4577bd87, 0x39e8cda6, 0x5c8ff6e0, + 0xf326bb2a, 0x9641806c, 0x770526ff, 0x12621db9, 0xbdcb5073, + 0xd8ac6b35}, + {0x00000000, 0xd7e28058, 0x74b406f1, 0xa35686a9, 0xe9680de2, + 0x3e8a8dba, 0x9ddc0b13, 0x4a3e8b4b, 0x09a11d85, 0xde439ddd, + 0x7d151b74, 0xaaf79b2c, 0xe0c91067, 0x372b903f, 0x947d1696, + 0x439f96ce, 0x13423b0a, 0xc4a0bb52, 0x67f63dfb, 0xb014bda3, + 0xfa2a36e8, 0x2dc8b6b0, 0x8e9e3019, 0x597cb041, 0x1ae3268f, + 0xcd01a6d7, 0x6e57207e, 0xb9b5a026, 0xf38b2b6d, 0x2469ab35, + 0x873f2d9c, 0x50ddadc4, 0x26847614, 0xf166f64c, 0x523070e5, + 0x85d2f0bd, 0xcfec7bf6, 0x180efbae, 0xbb587d07, 0x6cbafd5f, + 0x2f256b91, 0xf8c7ebc9, 0x5b916d60, 0x8c73ed38, 0xc64d6673, + 0x11afe62b, 0xb2f96082, 0x651be0da, 0x35c64d1e, 0xe224cd46, + 0x41724bef, 0x9690cbb7, 0xdcae40fc, 0x0b4cc0a4, 0xa81a460d, + 0x7ff8c655, 0x3c67509b, 0xeb85d0c3, 0x48d3566a, 0x9f31d632, + 0xd50f5d79, 0x02eddd21, 0xa1bb5b88, 0x7659dbd0, 0x4d08ec28, + 0x9aea6c70, 0x39bcead9, 0xee5e6a81, 0xa460e1ca, 0x73826192, + 0xd0d4e73b, 0x07366763, 0x44a9f1ad, 0x934b71f5, 0x301df75c, + 0xe7ff7704, 0xadc1fc4f, 0x7a237c17, 0xd975fabe, 0x0e977ae6, + 0x5e4ad722, 0x89a8577a, 0x2afed1d3, 0xfd1c518b, 0xb722dac0, + 0x60c05a98, 0xc396dc31, 0x14745c69, 0x57ebcaa7, 0x80094aff, + 0x235fcc56, 0xf4bd4c0e, 0xbe83c745, 0x6961471d, 0xca37c1b4, + 0x1dd541ec, 0x6b8c9a3c, 0xbc6e1a64, 0x1f389ccd, 0xc8da1c95, + 0x82e497de, 0x55061786, 0xf650912f, 0x21b21177, 0x622d87b9, + 0xb5cf07e1, 0x16998148, 0xc17b0110, 0x8b458a5b, 0x5ca70a03, + 0xfff18caa, 0x28130cf2, 0x78cea136, 0xaf2c216e, 0x0c7aa7c7, + 0xdb98279f, 0x91a6acd4, 0x46442c8c, 0xe512aa25, 0x32f02a7d, + 0x716fbcb3, 0xa68d3ceb, 0x05dbba42, 0xd2393a1a, 0x9807b151, + 0x4fe53109, 0xecb3b7a0, 0x3b5137f8, 0x9a11d850, 0x4df35808, + 0xeea5dea1, 0x39475ef9, 0x7379d5b2, 0xa49b55ea, 0x07cdd343, + 0xd02f531b, 0x93b0c5d5, 0x4452458d, 0xe704c324, 0x30e6437c, + 0x7ad8c837, 0xad3a486f, 0x0e6ccec6, 0xd98e4e9e, 0x8953e35a, + 0x5eb16302, 0xfde7e5ab, 0x2a0565f3, 0x603beeb8, 0xb7d96ee0, + 0x148fe849, 0xc36d6811, 0x80f2fedf, 0x57107e87, 0xf446f82e, + 0x23a47876, 0x699af33d, 0xbe787365, 0x1d2ef5cc, 0xcacc7594, + 0xbc95ae44, 0x6b772e1c, 0xc821a8b5, 0x1fc328ed, 0x55fda3a6, + 0x821f23fe, 0x2149a557, 0xf6ab250f, 0xb534b3c1, 0x62d63399, + 0xc180b530, 0x16623568, 0x5c5cbe23, 0x8bbe3e7b, 0x28e8b8d2, + 0xff0a388a, 0xafd7954e, 0x78351516, 0xdb6393bf, 0x0c8113e7, + 0x46bf98ac, 0x915d18f4, 0x320b9e5d, 0xe5e91e05, 0xa67688cb, + 0x71940893, 0xd2c28e3a, 0x05200e62, 0x4f1e8529, 0x98fc0571, + 0x3baa83d8, 0xec480380, 0xd7193478, 0x00fbb420, 0xa3ad3289, + 0x744fb2d1, 0x3e71399a, 0xe993b9c2, 0x4ac53f6b, 0x9d27bf33, + 0xdeb829fd, 0x095aa9a5, 0xaa0c2f0c, 0x7deeaf54, 0x37d0241f, + 0xe032a447, 0x436422ee, 0x9486a2b6, 0xc45b0f72, 0x13b98f2a, + 0xb0ef0983, 0x670d89db, 0x2d330290, 0xfad182c8, 0x59870461, + 0x8e658439, 0xcdfa12f7, 0x1a1892af, 0xb94e1406, 0x6eac945e, + 0x24921f15, 0xf3709f4d, 0x502619e4, 0x87c499bc, 0xf19d426c, + 0x267fc234, 0x8529449d, 0x52cbc4c5, 0x18f54f8e, 0xcf17cfd6, + 0x6c41497f, 0xbba3c927, 0xf83c5fe9, 0x2fdedfb1, 0x8c885918, + 0x5b6ad940, 0x1154520b, 0xc6b6d253, 0x65e054fa, 0xb202d4a2, + 0xe2df7966, 0x353df93e, 0x966b7f97, 0x4189ffcf, 0x0bb77484, + 0xdc55f4dc, 0x7f037275, 0xa8e1f22d, 0xeb7e64e3, 0x3c9ce4bb, + 0x9fca6212, 0x4828e24a, 0x02166901, 0xd5f4e959, 0x76a26ff0, + 0xa140efa8}, + {0x00000000, 0xef52b6e1, 0x05d46b83, 0xea86dd62, 0x0ba8d706, + 0xe4fa61e7, 0x0e7cbc85, 0xe12e0a64, 0x1751ae0c, 0xf80318ed, + 0x1285c58f, 0xfdd7736e, 0x1cf9790a, 0xf3abcfeb, 0x192d1289, + 0xf67fa468, 0x2ea35c18, 0xc1f1eaf9, 0x2b77379b, 0xc425817a, + 0x250b8b1e, 0xca593dff, 0x20dfe09d, 0xcf8d567c, 0x39f2f214, + 0xd6a044f5, 0x3c269997, 0xd3742f76, 0x325a2512, 0xdd0893f3, + 0x378e4e91, 0xd8dcf870, 0x5d46b830, 0xb2140ed1, 0x5892d3b3, + 0xb7c06552, 0x56ee6f36, 0xb9bcd9d7, 0x533a04b5, 0xbc68b254, + 0x4a17163c, 0xa545a0dd, 0x4fc37dbf, 0xa091cb5e, 0x41bfc13a, + 0xaeed77db, 0x446baab9, 0xab391c58, 0x73e5e428, 0x9cb752c9, + 0x76318fab, 0x9963394a, 0x784d332e, 0x971f85cf, 0x7d9958ad, + 0x92cbee4c, 0x64b44a24, 0x8be6fcc5, 0x616021a7, 0x8e329746, + 0x6f1c9d22, 0x804e2bc3, 0x6ac8f6a1, 0x859a4040, 0xba8d7060, + 0x55dfc681, 0xbf591be3, 0x500bad02, 0xb125a766, 0x5e771187, + 0xb4f1cce5, 0x5ba37a04, 0xaddcde6c, 0x428e688d, 0xa808b5ef, + 0x475a030e, 0xa674096a, 0x4926bf8b, 0xa3a062e9, 0x4cf2d408, + 0x942e2c78, 0x7b7c9a99, 0x91fa47fb, 0x7ea8f11a, 0x9f86fb7e, + 0x70d44d9f, 0x9a5290fd, 0x7500261c, 0x837f8274, 0x6c2d3495, + 0x86abe9f7, 0x69f95f16, 0x88d75572, 0x6785e393, 0x8d033ef1, + 0x62518810, 0xe7cbc850, 0x08997eb1, 0xe21fa3d3, 0x0d4d1532, + 0xec631f56, 0x0331a9b7, 0xe9b774d5, 0x06e5c234, 0xf09a665c, + 0x1fc8d0bd, 0xf54e0ddf, 0x1a1cbb3e, 0xfb32b15a, 0x146007bb, + 0xfee6dad9, 0x11b46c38, 0xc9689448, 0x263a22a9, 0xccbcffcb, + 0x23ee492a, 0xc2c0434e, 0x2d92f5af, 0xc71428cd, 0x28469e2c, + 0xde393a44, 0x316b8ca5, 0xdbed51c7, 0x34bfe726, 0xd591ed42, + 0x3ac35ba3, 0xd04586c1, 0x3f173020, 0xae6be681, 0x41395060, + 0xabbf8d02, 0x44ed3be3, 0xa5c33187, 0x4a918766, 0xa0175a04, + 0x4f45ece5, 0xb93a488d, 0x5668fe6c, 0xbcee230e, 0x53bc95ef, + 0xb2929f8b, 0x5dc0296a, 0xb746f408, 0x581442e9, 0x80c8ba99, + 0x6f9a0c78, 0x851cd11a, 0x6a4e67fb, 0x8b606d9f, 0x6432db7e, + 0x8eb4061c, 0x61e6b0fd, 0x97991495, 0x78cba274, 0x924d7f16, + 0x7d1fc9f7, 0x9c31c393, 0x73637572, 0x99e5a810, 0x76b71ef1, + 0xf32d5eb1, 0x1c7fe850, 0xf6f93532, 0x19ab83d3, 0xf88589b7, + 0x17d73f56, 0xfd51e234, 0x120354d5, 0xe47cf0bd, 0x0b2e465c, + 0xe1a89b3e, 0x0efa2ddf, 0xefd427bb, 0x0086915a, 0xea004c38, + 0x0552fad9, 0xdd8e02a9, 0x32dcb448, 0xd85a692a, 0x3708dfcb, + 0xd626d5af, 0x3974634e, 0xd3f2be2c, 0x3ca008cd, 0xcadfaca5, + 0x258d1a44, 0xcf0bc726, 0x205971c7, 0xc1777ba3, 0x2e25cd42, + 0xc4a31020, 0x2bf1a6c1, 0x14e696e1, 0xfbb42000, 0x1132fd62, + 0xfe604b83, 0x1f4e41e7, 0xf01cf706, 0x1a9a2a64, 0xf5c89c85, + 0x03b738ed, 0xece58e0c, 0x0663536e, 0xe931e58f, 0x081fefeb, + 0xe74d590a, 0x0dcb8468, 0xe2993289, 0x3a45caf9, 0xd5177c18, + 0x3f91a17a, 0xd0c3179b, 0x31ed1dff, 0xdebfab1e, 0x3439767c, + 0xdb6bc09d, 0x2d1464f5, 0xc246d214, 0x28c00f76, 0xc792b997, + 0x26bcb3f3, 0xc9ee0512, 0x2368d870, 0xcc3a6e91, 0x49a02ed1, + 0xa6f29830, 0x4c744552, 0xa326f3b3, 0x4208f9d7, 0xad5a4f36, + 0x47dc9254, 0xa88e24b5, 0x5ef180dd, 0xb1a3363c, 0x5b25eb5e, + 0xb4775dbf, 0x555957db, 0xba0be13a, 0x508d3c58, 0xbfdf8ab9, + 0x670372c9, 0x8851c428, 0x62d7194a, 0x8d85afab, 0x6caba5cf, + 0x83f9132e, 0x697fce4c, 0x862d78ad, 0x7052dcc5, 0x9f006a24, + 0x7586b746, 0x9ad401a7, 0x7bfa0bc3, 0x94a8bd22, 0x7e2e6040, + 0x917cd6a1}, + {0x00000000, 0x87a6cb43, 0xd43c90c7, 0x539a5b84, 0x730827cf, + 0xf4aeec8c, 0xa734b708, 0x20927c4b, 0xe6104f9e, 0x61b684dd, + 0x322cdf59, 0xb58a141a, 0x95186851, 0x12bea312, 0x4124f896, + 0xc68233d5, 0x1751997d, 0x90f7523e, 0xc36d09ba, 0x44cbc2f9, + 0x6459beb2, 0xe3ff75f1, 0xb0652e75, 0x37c3e536, 0xf141d6e3, + 0x76e71da0, 0x257d4624, 0xa2db8d67, 0x8249f12c, 0x05ef3a6f, + 0x567561eb, 0xd1d3aaa8, 0x2ea332fa, 0xa905f9b9, 0xfa9fa23d, + 0x7d39697e, 0x5dab1535, 0xda0dde76, 0x899785f2, 0x0e314eb1, + 0xc8b37d64, 0x4f15b627, 0x1c8feda3, 0x9b2926e0, 0xbbbb5aab, + 0x3c1d91e8, 0x6f87ca6c, 0xe821012f, 0x39f2ab87, 0xbe5460c4, + 0xedce3b40, 0x6a68f003, 0x4afa8c48, 0xcd5c470b, 0x9ec61c8f, + 0x1960d7cc, 0xdfe2e419, 0x58442f5a, 0x0bde74de, 0x8c78bf9d, + 0xaceac3d6, 0x2b4c0895, 0x78d65311, 0xff709852, 0x5d4665f4, + 0xdae0aeb7, 0x897af533, 0x0edc3e70, 0x2e4e423b, 0xa9e88978, + 0xfa72d2fc, 0x7dd419bf, 0xbb562a6a, 0x3cf0e129, 0x6f6abaad, + 0xe8cc71ee, 0xc85e0da5, 0x4ff8c6e6, 0x1c629d62, 0x9bc45621, + 0x4a17fc89, 0xcdb137ca, 0x9e2b6c4e, 0x198da70d, 0x391fdb46, + 0xbeb91005, 0xed234b81, 0x6a8580c2, 0xac07b317, 0x2ba17854, + 0x783b23d0, 0xff9de893, 0xdf0f94d8, 0x58a95f9b, 0x0b33041f, + 0x8c95cf5c, 0x73e5570e, 0xf4439c4d, 0xa7d9c7c9, 0x207f0c8a, + 0x00ed70c1, 0x874bbb82, 0xd4d1e006, 0x53772b45, 0x95f51890, + 0x1253d3d3, 0x41c98857, 0xc66f4314, 0xe6fd3f5f, 0x615bf41c, + 0x32c1af98, 0xb56764db, 0x64b4ce73, 0xe3120530, 0xb0885eb4, + 0x372e95f7, 0x17bce9bc, 0x901a22ff, 0xc380797b, 0x4426b238, + 0x82a481ed, 0x05024aae, 0x5698112a, 0xd13eda69, 0xf1aca622, + 0x760a6d61, 0x259036e5, 0xa236fda6, 0xba8ccbe8, 0x3d2a00ab, + 0x6eb05b2f, 0xe916906c, 0xc984ec27, 0x4e222764, 0x1db87ce0, + 0x9a1eb7a3, 0x5c9c8476, 0xdb3a4f35, 0x88a014b1, 0x0f06dff2, + 0x2f94a3b9, 0xa83268fa, 0xfba8337e, 0x7c0ef83d, 0xaddd5295, + 0x2a7b99d6, 0x79e1c252, 0xfe470911, 0xded5755a, 0x5973be19, + 0x0ae9e59d, 0x8d4f2ede, 0x4bcd1d0b, 0xcc6bd648, 0x9ff18dcc, + 0x1857468f, 0x38c53ac4, 0xbf63f187, 0xecf9aa03, 0x6b5f6140, + 0x942ff912, 0x13893251, 0x401369d5, 0xc7b5a296, 0xe727dedd, + 0x6081159e, 0x331b4e1a, 0xb4bd8559, 0x723fb68c, 0xf5997dcf, + 0xa603264b, 0x21a5ed08, 0x01379143, 0x86915a00, 0xd50b0184, + 0x52adcac7, 0x837e606f, 0x04d8ab2c, 0x5742f0a8, 0xd0e43beb, + 0xf07647a0, 0x77d08ce3, 0x244ad767, 0xa3ec1c24, 0x656e2ff1, + 0xe2c8e4b2, 0xb152bf36, 0x36f47475, 0x1666083e, 0x91c0c37d, + 0xc25a98f9, 0x45fc53ba, 0xe7caae1c, 0x606c655f, 0x33f63edb, + 0xb450f598, 0x94c289d3, 0x13644290, 0x40fe1914, 0xc758d257, + 0x01dae182, 0x867c2ac1, 0xd5e67145, 0x5240ba06, 0x72d2c64d, + 0xf5740d0e, 0xa6ee568a, 0x21489dc9, 0xf09b3761, 0x773dfc22, + 0x24a7a7a6, 0xa3016ce5, 0x839310ae, 0x0435dbed, 0x57af8069, + 0xd0094b2a, 0x168b78ff, 0x912db3bc, 0xc2b7e838, 0x4511237b, + 0x65835f30, 0xe2259473, 0xb1bfcff7, 0x361904b4, 0xc9699ce6, + 0x4ecf57a5, 0x1d550c21, 0x9af3c762, 0xba61bb29, 0x3dc7706a, + 0x6e5d2bee, 0xe9fbe0ad, 0x2f79d378, 0xa8df183b, 0xfb4543bf, + 0x7ce388fc, 0x5c71f4b7, 0xdbd73ff4, 0x884d6470, 0x0febaf33, + 0xde38059b, 0x599eced8, 0x0a04955c, 0x8da25e1f, 0xad302254, + 0x2a96e917, 0x790cb293, 0xfeaa79d0, 0x38284a05, 0xbf8e8146, + 0xec14dac2, 0x6bb21181, 0x4b206dca, 0xcc86a689, 0x9f1cfd0d, + 0x18ba364e}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0x43cba68700000000, 0xc7903cd400000000, + 0x845b9a5300000000, 0xcf27087300000000, 0x8cecaef400000000, + 0x08b734a700000000, 0x4b7c922000000000, 0x9e4f10e600000000, + 0xdd84b66100000000, 0x59df2c3200000000, 0x1a148ab500000000, + 0x5168189500000000, 0x12a3be1200000000, 0x96f8244100000000, + 0xd53382c600000000, 0x7d99511700000000, 0x3e52f79000000000, + 0xba096dc300000000, 0xf9c2cb4400000000, 0xb2be596400000000, + 0xf175ffe300000000, 0x752e65b000000000, 0x36e5c33700000000, + 0xe3d641f100000000, 0xa01de77600000000, 0x24467d2500000000, + 0x678ddba200000000, 0x2cf1498200000000, 0x6f3aef0500000000, + 0xeb61755600000000, 0xa8aad3d100000000, 0xfa32a32e00000000, + 0xb9f905a900000000, 0x3da29ffa00000000, 0x7e69397d00000000, + 0x3515ab5d00000000, 0x76de0dda00000000, 0xf285978900000000, + 0xb14e310e00000000, 0x647db3c800000000, 0x27b6154f00000000, + 0xa3ed8f1c00000000, 0xe026299b00000000, 0xab5abbbb00000000, + 0xe8911d3c00000000, 0x6cca876f00000000, 0x2f0121e800000000, + 0x87abf23900000000, 0xc46054be00000000, 0x403bceed00000000, + 0x03f0686a00000000, 0x488cfa4a00000000, 0x0b475ccd00000000, + 0x8f1cc69e00000000, 0xccd7601900000000, 0x19e4e2df00000000, + 0x5a2f445800000000, 0xde74de0b00000000, 0x9dbf788c00000000, + 0xd6c3eaac00000000, 0x95084c2b00000000, 0x1153d67800000000, + 0x529870ff00000000, 0xf465465d00000000, 0xb7aee0da00000000, + 0x33f57a8900000000, 0x703edc0e00000000, 0x3b424e2e00000000, + 0x7889e8a900000000, 0xfcd272fa00000000, 0xbf19d47d00000000, + 0x6a2a56bb00000000, 0x29e1f03c00000000, 0xadba6a6f00000000, + 0xee71cce800000000, 0xa50d5ec800000000, 0xe6c6f84f00000000, + 0x629d621c00000000, 0x2156c49b00000000, 0x89fc174a00000000, + 0xca37b1cd00000000, 0x4e6c2b9e00000000, 0x0da78d1900000000, + 0x46db1f3900000000, 0x0510b9be00000000, 0x814b23ed00000000, + 0xc280856a00000000, 0x17b307ac00000000, 0x5478a12b00000000, + 0xd0233b7800000000, 0x93e89dff00000000, 0xd8940fdf00000000, + 0x9b5fa95800000000, 0x1f04330b00000000, 0x5ccf958c00000000, + 0x0e57e57300000000, 0x4d9c43f400000000, 0xc9c7d9a700000000, + 0x8a0c7f2000000000, 0xc170ed0000000000, 0x82bb4b8700000000, + 0x06e0d1d400000000, 0x452b775300000000, 0x9018f59500000000, + 0xd3d3531200000000, 0x5788c94100000000, 0x14436fc600000000, + 0x5f3ffde600000000, 0x1cf45b6100000000, 0x98afc13200000000, + 0xdb6467b500000000, 0x73ceb46400000000, 0x300512e300000000, + 0xb45e88b000000000, 0xf7952e3700000000, 0xbce9bc1700000000, + 0xff221a9000000000, 0x7b7980c300000000, 0x38b2264400000000, + 0xed81a48200000000, 0xae4a020500000000, 0x2a11985600000000, + 0x69da3ed100000000, 0x22a6acf100000000, 0x616d0a7600000000, + 0xe536902500000000, 0xa6fd36a200000000, 0xe8cb8cba00000000, + 0xab002a3d00000000, 0x2f5bb06e00000000, 0x6c9016e900000000, + 0x27ec84c900000000, 0x6427224e00000000, 0xe07cb81d00000000, + 0xa3b71e9a00000000, 0x76849c5c00000000, 0x354f3adb00000000, + 0xb114a08800000000, 0xf2df060f00000000, 0xb9a3942f00000000, + 0xfa6832a800000000, 0x7e33a8fb00000000, 0x3df80e7c00000000, + 0x9552ddad00000000, 0xd6997b2a00000000, 0x52c2e17900000000, + 0x110947fe00000000, 0x5a75d5de00000000, 0x19be735900000000, + 0x9de5e90a00000000, 0xde2e4f8d00000000, 0x0b1dcd4b00000000, + 0x48d66bcc00000000, 0xcc8df19f00000000, 0x8f46571800000000, + 0xc43ac53800000000, 0x87f163bf00000000, 0x03aaf9ec00000000, + 0x40615f6b00000000, 0x12f92f9400000000, 0x5132891300000000, + 0xd569134000000000, 0x96a2b5c700000000, 0xddde27e700000000, + 0x9e15816000000000, 0x1a4e1b3300000000, 0x5985bdb400000000, + 0x8cb63f7200000000, 0xcf7d99f500000000, 0x4b2603a600000000, + 0x08eda52100000000, 0x4391370100000000, 0x005a918600000000, + 0x84010bd500000000, 0xc7caad5200000000, 0x6f607e8300000000, + 0x2cabd80400000000, 0xa8f0425700000000, 0xeb3be4d000000000, + 0xa04776f000000000, 0xe38cd07700000000, 0x67d74a2400000000, + 0x241ceca300000000, 0xf12f6e6500000000, 0xb2e4c8e200000000, + 0x36bf52b100000000, 0x7574f43600000000, 0x3e08661600000000, + 0x7dc3c09100000000, 0xf9985ac200000000, 0xba53fc4500000000, + 0x1caecae700000000, 0x5f656c6000000000, 0xdb3ef63300000000, + 0x98f550b400000000, 0xd389c29400000000, 0x9042641300000000, + 0x1419fe4000000000, 0x57d258c700000000, 0x82e1da0100000000, + 0xc12a7c8600000000, 0x4571e6d500000000, 0x06ba405200000000, + 0x4dc6d27200000000, 0x0e0d74f500000000, 0x8a56eea600000000, + 0xc99d482100000000, 0x61379bf000000000, 0x22fc3d7700000000, + 0xa6a7a72400000000, 0xe56c01a300000000, 0xae10938300000000, + 0xeddb350400000000, 0x6980af5700000000, 0x2a4b09d000000000, + 0xff788b1600000000, 0xbcb32d9100000000, 0x38e8b7c200000000, + 0x7b23114500000000, 0x305f836500000000, 0x739425e200000000, + 0xf7cfbfb100000000, 0xb404193600000000, 0xe69c69c900000000, + 0xa557cf4e00000000, 0x210c551d00000000, 0x62c7f39a00000000, + 0x29bb61ba00000000, 0x6a70c73d00000000, 0xee2b5d6e00000000, + 0xade0fbe900000000, 0x78d3792f00000000, 0x3b18dfa800000000, + 0xbf4345fb00000000, 0xfc88e37c00000000, 0xb7f4715c00000000, + 0xf43fd7db00000000, 0x70644d8800000000, 0x33afeb0f00000000, + 0x9b0538de00000000, 0xd8ce9e5900000000, 0x5c95040a00000000, + 0x1f5ea28d00000000, 0x542230ad00000000, 0x17e9962a00000000, + 0x93b20c7900000000, 0xd079aafe00000000, 0x054a283800000000, + 0x46818ebf00000000, 0xc2da14ec00000000, 0x8111b26b00000000, + 0xca6d204b00000000, 0x89a686cc00000000, 0x0dfd1c9f00000000, + 0x4e36ba1800000000}, + {0x0000000000000000, 0xe1b652ef00000000, 0x836bd40500000000, + 0x62dd86ea00000000, 0x06d7a80b00000000, 0xe761fae400000000, + 0x85bc7c0e00000000, 0x640a2ee100000000, 0x0cae511700000000, + 0xed1803f800000000, 0x8fc5851200000000, 0x6e73d7fd00000000, + 0x0a79f91c00000000, 0xebcfabf300000000, 0x89122d1900000000, + 0x68a47ff600000000, 0x185ca32e00000000, 0xf9eaf1c100000000, + 0x9b37772b00000000, 0x7a8125c400000000, 0x1e8b0b2500000000, + 0xff3d59ca00000000, 0x9de0df2000000000, 0x7c568dcf00000000, + 0x14f2f23900000000, 0xf544a0d600000000, 0x9799263c00000000, + 0x762f74d300000000, 0x12255a3200000000, 0xf39308dd00000000, + 0x914e8e3700000000, 0x70f8dcd800000000, 0x30b8465d00000000, + 0xd10e14b200000000, 0xb3d3925800000000, 0x5265c0b700000000, + 0x366fee5600000000, 0xd7d9bcb900000000, 0xb5043a5300000000, + 0x54b268bc00000000, 0x3c16174a00000000, 0xdda045a500000000, + 0xbf7dc34f00000000, 0x5ecb91a000000000, 0x3ac1bf4100000000, + 0xdb77edae00000000, 0xb9aa6b4400000000, 0x581c39ab00000000, + 0x28e4e57300000000, 0xc952b79c00000000, 0xab8f317600000000, + 0x4a39639900000000, 0x2e334d7800000000, 0xcf851f9700000000, + 0xad58997d00000000, 0x4ceecb9200000000, 0x244ab46400000000, + 0xc5fce68b00000000, 0xa721606100000000, 0x4697328e00000000, + 0x229d1c6f00000000, 0xc32b4e8000000000, 0xa1f6c86a00000000, + 0x40409a8500000000, 0x60708dba00000000, 0x81c6df5500000000, + 0xe31b59bf00000000, 0x02ad0b5000000000, 0x66a725b100000000, + 0x8711775e00000000, 0xe5ccf1b400000000, 0x047aa35b00000000, + 0x6cdedcad00000000, 0x8d688e4200000000, 0xefb508a800000000, + 0x0e035a4700000000, 0x6a0974a600000000, 0x8bbf264900000000, + 0xe962a0a300000000, 0x08d4f24c00000000, 0x782c2e9400000000, + 0x999a7c7b00000000, 0xfb47fa9100000000, 0x1af1a87e00000000, + 0x7efb869f00000000, 0x9f4dd47000000000, 0xfd90529a00000000, + 0x1c26007500000000, 0x74827f8300000000, 0x95342d6c00000000, + 0xf7e9ab8600000000, 0x165ff96900000000, 0x7255d78800000000, + 0x93e3856700000000, 0xf13e038d00000000, 0x1088516200000000, + 0x50c8cbe700000000, 0xb17e990800000000, 0xd3a31fe200000000, + 0x32154d0d00000000, 0x561f63ec00000000, 0xb7a9310300000000, + 0xd574b7e900000000, 0x34c2e50600000000, 0x5c669af000000000, + 0xbdd0c81f00000000, 0xdf0d4ef500000000, 0x3ebb1c1a00000000, + 0x5ab132fb00000000, 0xbb07601400000000, 0xd9dae6fe00000000, + 0x386cb41100000000, 0x489468c900000000, 0xa9223a2600000000, + 0xcbffbccc00000000, 0x2a49ee2300000000, 0x4e43c0c200000000, + 0xaff5922d00000000, 0xcd2814c700000000, 0x2c9e462800000000, + 0x443a39de00000000, 0xa58c6b3100000000, 0xc751eddb00000000, + 0x26e7bf3400000000, 0x42ed91d500000000, 0xa35bc33a00000000, + 0xc18645d000000000, 0x2030173f00000000, 0x81e66bae00000000, + 0x6050394100000000, 0x028dbfab00000000, 0xe33bed4400000000, + 0x8731c3a500000000, 0x6687914a00000000, 0x045a17a000000000, + 0xe5ec454f00000000, 0x8d483ab900000000, 0x6cfe685600000000, + 0x0e23eebc00000000, 0xef95bc5300000000, 0x8b9f92b200000000, + 0x6a29c05d00000000, 0x08f446b700000000, 0xe942145800000000, + 0x99bac88000000000, 0x780c9a6f00000000, 0x1ad11c8500000000, + 0xfb674e6a00000000, 0x9f6d608b00000000, 0x7edb326400000000, + 0x1c06b48e00000000, 0xfdb0e66100000000, 0x9514999700000000, + 0x74a2cb7800000000, 0x167f4d9200000000, 0xf7c91f7d00000000, + 0x93c3319c00000000, 0x7275637300000000, 0x10a8e59900000000, + 0xf11eb77600000000, 0xb15e2df300000000, 0x50e87f1c00000000, + 0x3235f9f600000000, 0xd383ab1900000000, 0xb78985f800000000, + 0x563fd71700000000, 0x34e251fd00000000, 0xd554031200000000, + 0xbdf07ce400000000, 0x5c462e0b00000000, 0x3e9ba8e100000000, + 0xdf2dfa0e00000000, 0xbb27d4ef00000000, 0x5a91860000000000, + 0x384c00ea00000000, 0xd9fa520500000000, 0xa9028edd00000000, + 0x48b4dc3200000000, 0x2a695ad800000000, 0xcbdf083700000000, + 0xafd526d600000000, 0x4e63743900000000, 0x2cbef2d300000000, + 0xcd08a03c00000000, 0xa5acdfca00000000, 0x441a8d2500000000, + 0x26c70bcf00000000, 0xc771592000000000, 0xa37b77c100000000, + 0x42cd252e00000000, 0x2010a3c400000000, 0xc1a6f12b00000000, + 0xe196e61400000000, 0x0020b4fb00000000, 0x62fd321100000000, + 0x834b60fe00000000, 0xe7414e1f00000000, 0x06f71cf000000000, + 0x642a9a1a00000000, 0x859cc8f500000000, 0xed38b70300000000, + 0x0c8ee5ec00000000, 0x6e53630600000000, 0x8fe531e900000000, + 0xebef1f0800000000, 0x0a594de700000000, 0x6884cb0d00000000, + 0x893299e200000000, 0xf9ca453a00000000, 0x187c17d500000000, + 0x7aa1913f00000000, 0x9b17c3d000000000, 0xff1ded3100000000, + 0x1eabbfde00000000, 0x7c76393400000000, 0x9dc06bdb00000000, + 0xf564142d00000000, 0x14d246c200000000, 0x760fc02800000000, + 0x97b992c700000000, 0xf3b3bc2600000000, 0x1205eec900000000, + 0x70d8682300000000, 0x916e3acc00000000, 0xd12ea04900000000, + 0x3098f2a600000000, 0x5245744c00000000, 0xb3f326a300000000, + 0xd7f9084200000000, 0x364f5aad00000000, 0x5492dc4700000000, + 0xb5248ea800000000, 0xdd80f15e00000000, 0x3c36a3b100000000, + 0x5eeb255b00000000, 0xbf5d77b400000000, 0xdb57595500000000, + 0x3ae10bba00000000, 0x583c8d5000000000, 0xb98adfbf00000000, + 0xc972036700000000, 0x28c4518800000000, 0x4a19d76200000000, + 0xabaf858d00000000, 0xcfa5ab6c00000000, 0x2e13f98300000000, + 0x4cce7f6900000000, 0xad782d8600000000, 0xc5dc527000000000, + 0x246a009f00000000, 0x46b7867500000000, 0xa701d49a00000000, + 0xc30bfa7b00000000, 0x22bda89400000000, 0x40602e7e00000000, + 0xa1d67c9100000000}, + {0x0000000000000000, 0x5880e2d700000000, 0xf106b47400000000, + 0xa98656a300000000, 0xe20d68e900000000, 0xba8d8a3e00000000, + 0x130bdc9d00000000, 0x4b8b3e4a00000000, 0x851da10900000000, + 0xdd9d43de00000000, 0x741b157d00000000, 0x2c9bf7aa00000000, + 0x6710c9e000000000, 0x3f902b3700000000, 0x96167d9400000000, + 0xce969f4300000000, 0x0a3b421300000000, 0x52bba0c400000000, + 0xfb3df66700000000, 0xa3bd14b000000000, 0xe8362afa00000000, + 0xb0b6c82d00000000, 0x19309e8e00000000, 0x41b07c5900000000, + 0x8f26e31a00000000, 0xd7a601cd00000000, 0x7e20576e00000000, + 0x26a0b5b900000000, 0x6d2b8bf300000000, 0x35ab692400000000, + 0x9c2d3f8700000000, 0xc4addd5000000000, 0x1476842600000000, + 0x4cf666f100000000, 0xe570305200000000, 0xbdf0d28500000000, + 0xf67beccf00000000, 0xaefb0e1800000000, 0x077d58bb00000000, + 0x5ffdba6c00000000, 0x916b252f00000000, 0xc9ebc7f800000000, + 0x606d915b00000000, 0x38ed738c00000000, 0x73664dc600000000, + 0x2be6af1100000000, 0x8260f9b200000000, 0xdae01b6500000000, + 0x1e4dc63500000000, 0x46cd24e200000000, 0xef4b724100000000, + 0xb7cb909600000000, 0xfc40aedc00000000, 0xa4c04c0b00000000, + 0x0d461aa800000000, 0x55c6f87f00000000, 0x9b50673c00000000, + 0xc3d085eb00000000, 0x6a56d34800000000, 0x32d6319f00000000, + 0x795d0fd500000000, 0x21dded0200000000, 0x885bbba100000000, + 0xd0db597600000000, 0x28ec084d00000000, 0x706cea9a00000000, + 0xd9eabc3900000000, 0x816a5eee00000000, 0xcae160a400000000, + 0x9261827300000000, 0x3be7d4d000000000, 0x6367360700000000, + 0xadf1a94400000000, 0xf5714b9300000000, 0x5cf71d3000000000, + 0x0477ffe700000000, 0x4ffcc1ad00000000, 0x177c237a00000000, + 0xbefa75d900000000, 0xe67a970e00000000, 0x22d74a5e00000000, + 0x7a57a88900000000, 0xd3d1fe2a00000000, 0x8b511cfd00000000, + 0xc0da22b700000000, 0x985ac06000000000, 0x31dc96c300000000, + 0x695c741400000000, 0xa7caeb5700000000, 0xff4a098000000000, + 0x56cc5f2300000000, 0x0e4cbdf400000000, 0x45c783be00000000, + 0x1d47616900000000, 0xb4c137ca00000000, 0xec41d51d00000000, + 0x3c9a8c6b00000000, 0x641a6ebc00000000, 0xcd9c381f00000000, + 0x951cdac800000000, 0xde97e48200000000, 0x8617065500000000, + 0x2f9150f600000000, 0x7711b22100000000, 0xb9872d6200000000, + 0xe107cfb500000000, 0x4881991600000000, 0x10017bc100000000, + 0x5b8a458b00000000, 0x030aa75c00000000, 0xaa8cf1ff00000000, + 0xf20c132800000000, 0x36a1ce7800000000, 0x6e212caf00000000, + 0xc7a77a0c00000000, 0x9f2798db00000000, 0xd4aca69100000000, + 0x8c2c444600000000, 0x25aa12e500000000, 0x7d2af03200000000, + 0xb3bc6f7100000000, 0xeb3c8da600000000, 0x42badb0500000000, + 0x1a3a39d200000000, 0x51b1079800000000, 0x0931e54f00000000, + 0xa0b7b3ec00000000, 0xf837513b00000000, 0x50d8119a00000000, + 0x0858f34d00000000, 0xa1dea5ee00000000, 0xf95e473900000000, + 0xb2d5797300000000, 0xea559ba400000000, 0x43d3cd0700000000, + 0x1b532fd000000000, 0xd5c5b09300000000, 0x8d45524400000000, + 0x24c304e700000000, 0x7c43e63000000000, 0x37c8d87a00000000, + 0x6f483aad00000000, 0xc6ce6c0e00000000, 0x9e4e8ed900000000, + 0x5ae3538900000000, 0x0263b15e00000000, 0xabe5e7fd00000000, + 0xf365052a00000000, 0xb8ee3b6000000000, 0xe06ed9b700000000, + 0x49e88f1400000000, 0x11686dc300000000, 0xdffef28000000000, + 0x877e105700000000, 0x2ef846f400000000, 0x7678a42300000000, + 0x3df39a6900000000, 0x657378be00000000, 0xccf52e1d00000000, + 0x9475ccca00000000, 0x44ae95bc00000000, 0x1c2e776b00000000, + 0xb5a821c800000000, 0xed28c31f00000000, 0xa6a3fd5500000000, + 0xfe231f8200000000, 0x57a5492100000000, 0x0f25abf600000000, + 0xc1b334b500000000, 0x9933d66200000000, 0x30b580c100000000, + 0x6835621600000000, 0x23be5c5c00000000, 0x7b3ebe8b00000000, + 0xd2b8e82800000000, 0x8a380aff00000000, 0x4e95d7af00000000, + 0x1615357800000000, 0xbf9363db00000000, 0xe713810c00000000, + 0xac98bf4600000000, 0xf4185d9100000000, 0x5d9e0b3200000000, + 0x051ee9e500000000, 0xcb8876a600000000, 0x9308947100000000, + 0x3a8ec2d200000000, 0x620e200500000000, 0x29851e4f00000000, + 0x7105fc9800000000, 0xd883aa3b00000000, 0x800348ec00000000, + 0x783419d700000000, 0x20b4fb0000000000, 0x8932ada300000000, + 0xd1b24f7400000000, 0x9a39713e00000000, 0xc2b993e900000000, + 0x6b3fc54a00000000, 0x33bf279d00000000, 0xfd29b8de00000000, + 0xa5a95a0900000000, 0x0c2f0caa00000000, 0x54afee7d00000000, + 0x1f24d03700000000, 0x47a432e000000000, 0xee22644300000000, + 0xb6a2869400000000, 0x720f5bc400000000, 0x2a8fb91300000000, + 0x8309efb000000000, 0xdb890d6700000000, 0x9002332d00000000, + 0xc882d1fa00000000, 0x6104875900000000, 0x3984658e00000000, + 0xf712facd00000000, 0xaf92181a00000000, 0x06144eb900000000, + 0x5e94ac6e00000000, 0x151f922400000000, 0x4d9f70f300000000, + 0xe419265000000000, 0xbc99c48700000000, 0x6c429df100000000, + 0x34c27f2600000000, 0x9d44298500000000, 0xc5c4cb5200000000, + 0x8e4ff51800000000, 0xd6cf17cf00000000, 0x7f49416c00000000, + 0x27c9a3bb00000000, 0xe95f3cf800000000, 0xb1dfde2f00000000, + 0x1859888c00000000, 0x40d96a5b00000000, 0x0b52541100000000, + 0x53d2b6c600000000, 0xfa54e06500000000, 0xa2d402b200000000, + 0x6679dfe200000000, 0x3ef93d3500000000, 0x977f6b9600000000, + 0xcfff894100000000, 0x8474b70b00000000, 0xdcf455dc00000000, + 0x7572037f00000000, 0x2df2e1a800000000, 0xe3647eeb00000000, + 0xbbe49c3c00000000, 0x1262ca9f00000000, 0x4ae2284800000000, + 0x0169160200000000, 0x59e9f4d500000000, 0xf06fa27600000000, + 0xa8ef40a100000000}, + {0x0000000000000000, 0x463b676500000000, 0x8c76ceca00000000, + 0xca4da9af00000000, 0x59ebed4e00000000, 0x1fd08a2b00000000, + 0xd59d238400000000, 0x93a644e100000000, 0xb2d6db9d00000000, + 0xf4edbcf800000000, 0x3ea0155700000000, 0x789b723200000000, + 0xeb3d36d300000000, 0xad0651b600000000, 0x674bf81900000000, + 0x21709f7c00000000, 0x25abc6e000000000, 0x6390a18500000000, + 0xa9dd082a00000000, 0xefe66f4f00000000, 0x7c402bae00000000, + 0x3a7b4ccb00000000, 0xf036e56400000000, 0xb60d820100000000, + 0x977d1d7d00000000, 0xd1467a1800000000, 0x1b0bd3b700000000, + 0x5d30b4d200000000, 0xce96f03300000000, 0x88ad975600000000, + 0x42e03ef900000000, 0x04db599c00000000, 0x0b50fc1a00000000, + 0x4d6b9b7f00000000, 0x872632d000000000, 0xc11d55b500000000, + 0x52bb115400000000, 0x1480763100000000, 0xdecddf9e00000000, + 0x98f6b8fb00000000, 0xb986278700000000, 0xffbd40e200000000, + 0x35f0e94d00000000, 0x73cb8e2800000000, 0xe06dcac900000000, + 0xa656adac00000000, 0x6c1b040300000000, 0x2a20636600000000, + 0x2efb3afa00000000, 0x68c05d9f00000000, 0xa28df43000000000, + 0xe4b6935500000000, 0x7710d7b400000000, 0x312bb0d100000000, + 0xfb66197e00000000, 0xbd5d7e1b00000000, 0x9c2de16700000000, + 0xda16860200000000, 0x105b2fad00000000, 0x566048c800000000, + 0xc5c60c2900000000, 0x83fd6b4c00000000, 0x49b0c2e300000000, + 0x0f8ba58600000000, 0x16a0f83500000000, 0x509b9f5000000000, + 0x9ad636ff00000000, 0xdced519a00000000, 0x4f4b157b00000000, + 0x0970721e00000000, 0xc33ddbb100000000, 0x8506bcd400000000, + 0xa47623a800000000, 0xe24d44cd00000000, 0x2800ed6200000000, + 0x6e3b8a0700000000, 0xfd9dcee600000000, 0xbba6a98300000000, + 0x71eb002c00000000, 0x37d0674900000000, 0x330b3ed500000000, + 0x753059b000000000, 0xbf7df01f00000000, 0xf946977a00000000, + 0x6ae0d39b00000000, 0x2cdbb4fe00000000, 0xe6961d5100000000, + 0xa0ad7a3400000000, 0x81dde54800000000, 0xc7e6822d00000000, + 0x0dab2b8200000000, 0x4b904ce700000000, 0xd836080600000000, + 0x9e0d6f6300000000, 0x5440c6cc00000000, 0x127ba1a900000000, + 0x1df0042f00000000, 0x5bcb634a00000000, 0x9186cae500000000, + 0xd7bdad8000000000, 0x441be96100000000, 0x02208e0400000000, + 0xc86d27ab00000000, 0x8e5640ce00000000, 0xaf26dfb200000000, + 0xe91db8d700000000, 0x2350117800000000, 0x656b761d00000000, + 0xf6cd32fc00000000, 0xb0f6559900000000, 0x7abbfc3600000000, + 0x3c809b5300000000, 0x385bc2cf00000000, 0x7e60a5aa00000000, + 0xb42d0c0500000000, 0xf2166b6000000000, 0x61b02f8100000000, + 0x278b48e400000000, 0xedc6e14b00000000, 0xabfd862e00000000, + 0x8a8d195200000000, 0xccb67e3700000000, 0x06fbd79800000000, + 0x40c0b0fd00000000, 0xd366f41c00000000, 0x955d937900000000, + 0x5f103ad600000000, 0x192b5db300000000, 0x2c40f16b00000000, + 0x6a7b960e00000000, 0xa0363fa100000000, 0xe60d58c400000000, + 0x75ab1c2500000000, 0x33907b4000000000, 0xf9ddd2ef00000000, + 0xbfe6b58a00000000, 0x9e962af600000000, 0xd8ad4d9300000000, + 0x12e0e43c00000000, 0x54db835900000000, 0xc77dc7b800000000, + 0x8146a0dd00000000, 0x4b0b097200000000, 0x0d306e1700000000, + 0x09eb378b00000000, 0x4fd050ee00000000, 0x859df94100000000, + 0xc3a69e2400000000, 0x5000dac500000000, 0x163bbda000000000, + 0xdc76140f00000000, 0x9a4d736a00000000, 0xbb3dec1600000000, + 0xfd068b7300000000, 0x374b22dc00000000, 0x717045b900000000, + 0xe2d6015800000000, 0xa4ed663d00000000, 0x6ea0cf9200000000, + 0x289ba8f700000000, 0x27100d7100000000, 0x612b6a1400000000, + 0xab66c3bb00000000, 0xed5da4de00000000, 0x7efbe03f00000000, + 0x38c0875a00000000, 0xf28d2ef500000000, 0xb4b6499000000000, + 0x95c6d6ec00000000, 0xd3fdb18900000000, 0x19b0182600000000, + 0x5f8b7f4300000000, 0xcc2d3ba200000000, 0x8a165cc700000000, + 0x405bf56800000000, 0x0660920d00000000, 0x02bbcb9100000000, + 0x4480acf400000000, 0x8ecd055b00000000, 0xc8f6623e00000000, + 0x5b5026df00000000, 0x1d6b41ba00000000, 0xd726e81500000000, + 0x911d8f7000000000, 0xb06d100c00000000, 0xf656776900000000, + 0x3c1bdec600000000, 0x7a20b9a300000000, 0xe986fd4200000000, + 0xafbd9a2700000000, 0x65f0338800000000, 0x23cb54ed00000000, + 0x3ae0095e00000000, 0x7cdb6e3b00000000, 0xb696c79400000000, + 0xf0ada0f100000000, 0x630be41000000000, 0x2530837500000000, + 0xef7d2ada00000000, 0xa9464dbf00000000, 0x8836d2c300000000, + 0xce0db5a600000000, 0x04401c0900000000, 0x427b7b6c00000000, + 0xd1dd3f8d00000000, 0x97e658e800000000, 0x5dabf14700000000, + 0x1b90962200000000, 0x1f4bcfbe00000000, 0x5970a8db00000000, + 0x933d017400000000, 0xd506661100000000, 0x46a022f000000000, + 0x009b459500000000, 0xcad6ec3a00000000, 0x8ced8b5f00000000, + 0xad9d142300000000, 0xeba6734600000000, 0x21ebdae900000000, + 0x67d0bd8c00000000, 0xf476f96d00000000, 0xb24d9e0800000000, + 0x780037a700000000, 0x3e3b50c200000000, 0x31b0f54400000000, + 0x778b922100000000, 0xbdc63b8e00000000, 0xfbfd5ceb00000000, + 0x685b180a00000000, 0x2e607f6f00000000, 0xe42dd6c000000000, + 0xa216b1a500000000, 0x83662ed900000000, 0xc55d49bc00000000, + 0x0f10e01300000000, 0x492b877600000000, 0xda8dc39700000000, + 0x9cb6a4f200000000, 0x56fb0d5d00000000, 0x10c06a3800000000, + 0x141b33a400000000, 0x522054c100000000, 0x986dfd6e00000000, + 0xde569a0b00000000, 0x4df0deea00000000, 0x0bcbb98f00000000, + 0xc186102000000000, 0x87bd774500000000, 0xa6cde83900000000, + 0xe0f68f5c00000000, 0x2abb26f300000000, 0x6c80419600000000, + 0xff26057700000000, 0xb91d621200000000, 0x7350cbbd00000000, + 0x356bacd800000000}, + {0x0000000000000000, 0x9e83da9f00000000, 0x7d01c4e400000000, + 0xe3821e7b00000000, 0xbb04f91200000000, 0x2587238d00000000, + 0xc6053df600000000, 0x5886e76900000000, 0x7609f22500000000, + 0xe88a28ba00000000, 0x0b0836c100000000, 0x958bec5e00000000, + 0xcd0d0b3700000000, 0x538ed1a800000000, 0xb00ccfd300000000, + 0x2e8f154c00000000, 0xec12e44b00000000, 0x72913ed400000000, + 0x911320af00000000, 0x0f90fa3000000000, 0x57161d5900000000, + 0xc995c7c600000000, 0x2a17d9bd00000000, 0xb494032200000000, + 0x9a1b166e00000000, 0x0498ccf100000000, 0xe71ad28a00000000, + 0x7999081500000000, 0x211fef7c00000000, 0xbf9c35e300000000, + 0x5c1e2b9800000000, 0xc29df10700000000, 0xd825c89700000000, + 0x46a6120800000000, 0xa5240c7300000000, 0x3ba7d6ec00000000, + 0x6321318500000000, 0xfda2eb1a00000000, 0x1e20f56100000000, + 0x80a32ffe00000000, 0xae2c3ab200000000, 0x30afe02d00000000, + 0xd32dfe5600000000, 0x4dae24c900000000, 0x1528c3a000000000, + 0x8bab193f00000000, 0x6829074400000000, 0xf6aadddb00000000, + 0x34372cdc00000000, 0xaab4f64300000000, 0x4936e83800000000, + 0xd7b532a700000000, 0x8f33d5ce00000000, 0x11b00f5100000000, + 0xf232112a00000000, 0x6cb1cbb500000000, 0x423edef900000000, + 0xdcbd046600000000, 0x3f3f1a1d00000000, 0xa1bcc08200000000, + 0xf93a27eb00000000, 0x67b9fd7400000000, 0x843be30f00000000, + 0x1ab8399000000000, 0xf14de1f400000000, 0x6fce3b6b00000000, + 0x8c4c251000000000, 0x12cfff8f00000000, 0x4a4918e600000000, + 0xd4cac27900000000, 0x3748dc0200000000, 0xa9cb069d00000000, + 0x874413d100000000, 0x19c7c94e00000000, 0xfa45d73500000000, + 0x64c60daa00000000, 0x3c40eac300000000, 0xa2c3305c00000000, + 0x41412e2700000000, 0xdfc2f4b800000000, 0x1d5f05bf00000000, + 0x83dcdf2000000000, 0x605ec15b00000000, 0xfedd1bc400000000, + 0xa65bfcad00000000, 0x38d8263200000000, 0xdb5a384900000000, + 0x45d9e2d600000000, 0x6b56f79a00000000, 0xf5d52d0500000000, + 0x1657337e00000000, 0x88d4e9e100000000, 0xd0520e8800000000, + 0x4ed1d41700000000, 0xad53ca6c00000000, 0x33d010f300000000, + 0x2968296300000000, 0xb7ebf3fc00000000, 0x5469ed8700000000, + 0xcaea371800000000, 0x926cd07100000000, 0x0cef0aee00000000, + 0xef6d149500000000, 0x71eece0a00000000, 0x5f61db4600000000, + 0xc1e201d900000000, 0x22601fa200000000, 0xbce3c53d00000000, + 0xe465225400000000, 0x7ae6f8cb00000000, 0x9964e6b000000000, + 0x07e73c2f00000000, 0xc57acd2800000000, 0x5bf917b700000000, + 0xb87b09cc00000000, 0x26f8d35300000000, 0x7e7e343a00000000, + 0xe0fdeea500000000, 0x037ff0de00000000, 0x9dfc2a4100000000, + 0xb3733f0d00000000, 0x2df0e59200000000, 0xce72fbe900000000, + 0x50f1217600000000, 0x0877c61f00000000, 0x96f41c8000000000, + 0x757602fb00000000, 0xebf5d86400000000, 0xa39db33200000000, + 0x3d1e69ad00000000, 0xde9c77d600000000, 0x401fad4900000000, + 0x18994a2000000000, 0x861a90bf00000000, 0x65988ec400000000, + 0xfb1b545b00000000, 0xd594411700000000, 0x4b179b8800000000, + 0xa89585f300000000, 0x36165f6c00000000, 0x6e90b80500000000, + 0xf013629a00000000, 0x13917ce100000000, 0x8d12a67e00000000, + 0x4f8f577900000000, 0xd10c8de600000000, 0x328e939d00000000, + 0xac0d490200000000, 0xf48bae6b00000000, 0x6a0874f400000000, + 0x898a6a8f00000000, 0x1709b01000000000, 0x3986a55c00000000, + 0xa7057fc300000000, 0x448761b800000000, 0xda04bb2700000000, + 0x82825c4e00000000, 0x1c0186d100000000, 0xff8398aa00000000, + 0x6100423500000000, 0x7bb87ba500000000, 0xe53ba13a00000000, + 0x06b9bf4100000000, 0x983a65de00000000, 0xc0bc82b700000000, + 0x5e3f582800000000, 0xbdbd465300000000, 0x233e9ccc00000000, + 0x0db1898000000000, 0x9332531f00000000, 0x70b04d6400000000, + 0xee3397fb00000000, 0xb6b5709200000000, 0x2836aa0d00000000, + 0xcbb4b47600000000, 0x55376ee900000000, 0x97aa9fee00000000, + 0x0929457100000000, 0xeaab5b0a00000000, 0x7428819500000000, + 0x2cae66fc00000000, 0xb22dbc6300000000, 0x51afa21800000000, + 0xcf2c788700000000, 0xe1a36dcb00000000, 0x7f20b75400000000, + 0x9ca2a92f00000000, 0x022173b000000000, 0x5aa794d900000000, + 0xc4244e4600000000, 0x27a6503d00000000, 0xb9258aa200000000, + 0x52d052c600000000, 0xcc53885900000000, 0x2fd1962200000000, + 0xb1524cbd00000000, 0xe9d4abd400000000, 0x7757714b00000000, + 0x94d56f3000000000, 0x0a56b5af00000000, 0x24d9a0e300000000, + 0xba5a7a7c00000000, 0x59d8640700000000, 0xc75bbe9800000000, + 0x9fdd59f100000000, 0x015e836e00000000, 0xe2dc9d1500000000, + 0x7c5f478a00000000, 0xbec2b68d00000000, 0x20416c1200000000, + 0xc3c3726900000000, 0x5d40a8f600000000, 0x05c64f9f00000000, + 0x9b45950000000000, 0x78c78b7b00000000, 0xe64451e400000000, + 0xc8cb44a800000000, 0x56489e3700000000, 0xb5ca804c00000000, + 0x2b495ad300000000, 0x73cfbdba00000000, 0xed4c672500000000, + 0x0ece795e00000000, 0x904da3c100000000, 0x8af59a5100000000, + 0x147640ce00000000, 0xf7f45eb500000000, 0x6977842a00000000, + 0x31f1634300000000, 0xaf72b9dc00000000, 0x4cf0a7a700000000, + 0xd2737d3800000000, 0xfcfc687400000000, 0x627fb2eb00000000, + 0x81fdac9000000000, 0x1f7e760f00000000, 0x47f8916600000000, + 0xd97b4bf900000000, 0x3af9558200000000, 0xa47a8f1d00000000, + 0x66e77e1a00000000, 0xf864a48500000000, 0x1be6bafe00000000, + 0x8565606100000000, 0xdde3870800000000, 0x43605d9700000000, + 0xa0e243ec00000000, 0x3e61997300000000, 0x10ee8c3f00000000, + 0x8e6d56a000000000, 0x6def48db00000000, 0xf36c924400000000, + 0xabea752d00000000, 0x3569afb200000000, 0xd6ebb1c900000000, + 0x48686b5600000000}, + {0x0000000000000000, 0xc064281700000000, 0x80c9502e00000000, + 0x40ad783900000000, 0x0093a15c00000000, 0xc0f7894b00000000, + 0x805af17200000000, 0x403ed96500000000, 0x002643b900000000, + 0xc0426bae00000000, 0x80ef139700000000, 0x408b3b8000000000, + 0x00b5e2e500000000, 0xc0d1caf200000000, 0x807cb2cb00000000, + 0x40189adc00000000, 0x414af7a900000000, 0x812edfbe00000000, + 0xc183a78700000000, 0x01e78f9000000000, 0x41d956f500000000, + 0x81bd7ee200000000, 0xc11006db00000000, 0x01742ecc00000000, + 0x416cb41000000000, 0x81089c0700000000, 0xc1a5e43e00000000, + 0x01c1cc2900000000, 0x41ff154c00000000, 0x819b3d5b00000000, + 0xc136456200000000, 0x01526d7500000000, 0xc3929f8800000000, + 0x03f6b79f00000000, 0x435bcfa600000000, 0x833fe7b100000000, + 0xc3013ed400000000, 0x036516c300000000, 0x43c86efa00000000, + 0x83ac46ed00000000, 0xc3b4dc3100000000, 0x03d0f42600000000, + 0x437d8c1f00000000, 0x8319a40800000000, 0xc3277d6d00000000, + 0x0343557a00000000, 0x43ee2d4300000000, 0x838a055400000000, + 0x82d8682100000000, 0x42bc403600000000, 0x0211380f00000000, + 0xc275101800000000, 0x824bc97d00000000, 0x422fe16a00000000, + 0x0282995300000000, 0xc2e6b14400000000, 0x82fe2b9800000000, + 0x429a038f00000000, 0x02377bb600000000, 0xc25353a100000000, + 0x826d8ac400000000, 0x4209a2d300000000, 0x02a4daea00000000, + 0xc2c0f2fd00000000, 0xc7234eca00000000, 0x074766dd00000000, + 0x47ea1ee400000000, 0x878e36f300000000, 0xc7b0ef9600000000, + 0x07d4c78100000000, 0x4779bfb800000000, 0x871d97af00000000, + 0xc7050d7300000000, 0x0761256400000000, 0x47cc5d5d00000000, + 0x87a8754a00000000, 0xc796ac2f00000000, 0x07f2843800000000, + 0x475ffc0100000000, 0x873bd41600000000, 0x8669b96300000000, + 0x460d917400000000, 0x06a0e94d00000000, 0xc6c4c15a00000000, + 0x86fa183f00000000, 0x469e302800000000, 0x0633481100000000, + 0xc657600600000000, 0x864ffada00000000, 0x462bd2cd00000000, + 0x0686aaf400000000, 0xc6e282e300000000, 0x86dc5b8600000000, + 0x46b8739100000000, 0x06150ba800000000, 0xc67123bf00000000, + 0x04b1d14200000000, 0xc4d5f95500000000, 0x8478816c00000000, + 0x441ca97b00000000, 0x0422701e00000000, 0xc446580900000000, + 0x84eb203000000000, 0x448f082700000000, 0x049792fb00000000, + 0xc4f3baec00000000, 0x845ec2d500000000, 0x443aeac200000000, + 0x040433a700000000, 0xc4601bb000000000, 0x84cd638900000000, + 0x44a94b9e00000000, 0x45fb26eb00000000, 0x859f0efc00000000, + 0xc53276c500000000, 0x05565ed200000000, 0x456887b700000000, + 0x850cafa000000000, 0xc5a1d79900000000, 0x05c5ff8e00000000, + 0x45dd655200000000, 0x85b94d4500000000, 0xc514357c00000000, + 0x05701d6b00000000, 0x454ec40e00000000, 0x852aec1900000000, + 0xc587942000000000, 0x05e3bc3700000000, 0xcf41ed4f00000000, + 0x0f25c55800000000, 0x4f88bd6100000000, 0x8fec957600000000, + 0xcfd24c1300000000, 0x0fb6640400000000, 0x4f1b1c3d00000000, + 0x8f7f342a00000000, 0xcf67aef600000000, 0x0f0386e100000000, + 0x4faefed800000000, 0x8fcad6cf00000000, 0xcff40faa00000000, + 0x0f9027bd00000000, 0x4f3d5f8400000000, 0x8f59779300000000, + 0x8e0b1ae600000000, 0x4e6f32f100000000, 0x0ec24ac800000000, + 0xcea662df00000000, 0x8e98bbba00000000, 0x4efc93ad00000000, + 0x0e51eb9400000000, 0xce35c38300000000, 0x8e2d595f00000000, + 0x4e49714800000000, 0x0ee4097100000000, 0xce80216600000000, + 0x8ebef80300000000, 0x4edad01400000000, 0x0e77a82d00000000, + 0xce13803a00000000, 0x0cd372c700000000, 0xccb75ad000000000, + 0x8c1a22e900000000, 0x4c7e0afe00000000, 0x0c40d39b00000000, + 0xcc24fb8c00000000, 0x8c8983b500000000, 0x4cedaba200000000, + 0x0cf5317e00000000, 0xcc91196900000000, 0x8c3c615000000000, + 0x4c58494700000000, 0x0c66902200000000, 0xcc02b83500000000, + 0x8cafc00c00000000, 0x4ccbe81b00000000, 0x4d99856e00000000, + 0x8dfdad7900000000, 0xcd50d54000000000, 0x0d34fd5700000000, + 0x4d0a243200000000, 0x8d6e0c2500000000, 0xcdc3741c00000000, + 0x0da75c0b00000000, 0x4dbfc6d700000000, 0x8ddbeec000000000, + 0xcd7696f900000000, 0x0d12beee00000000, 0x4d2c678b00000000, + 0x8d484f9c00000000, 0xcde537a500000000, 0x0d811fb200000000, + 0x0862a38500000000, 0xc8068b9200000000, 0x88abf3ab00000000, + 0x48cfdbbc00000000, 0x08f102d900000000, 0xc8952ace00000000, + 0x883852f700000000, 0x485c7ae000000000, 0x0844e03c00000000, + 0xc820c82b00000000, 0x888db01200000000, 0x48e9980500000000, + 0x08d7416000000000, 0xc8b3697700000000, 0x881e114e00000000, + 0x487a395900000000, 0x4928542c00000000, 0x894c7c3b00000000, + 0xc9e1040200000000, 0x09852c1500000000, 0x49bbf57000000000, + 0x89dfdd6700000000, 0xc972a55e00000000, 0x09168d4900000000, + 0x490e179500000000, 0x896a3f8200000000, 0xc9c747bb00000000, + 0x09a36fac00000000, 0x499db6c900000000, 0x89f99ede00000000, + 0xc954e6e700000000, 0x0930cef000000000, 0xcbf03c0d00000000, + 0x0b94141a00000000, 0x4b396c2300000000, 0x8b5d443400000000, + 0xcb639d5100000000, 0x0b07b54600000000, 0x4baacd7f00000000, + 0x8bcee56800000000, 0xcbd67fb400000000, 0x0bb257a300000000, + 0x4b1f2f9a00000000, 0x8b7b078d00000000, 0xcb45dee800000000, + 0x0b21f6ff00000000, 0x4b8c8ec600000000, 0x8be8a6d100000000, + 0x8abacba400000000, 0x4adee3b300000000, 0x0a739b8a00000000, + 0xca17b39d00000000, 0x8a296af800000000, 0x4a4d42ef00000000, + 0x0ae03ad600000000, 0xca8412c100000000, 0x8a9c881d00000000, + 0x4af8a00a00000000, 0x0a55d83300000000, 0xca31f02400000000, + 0x8a0f294100000000, 0x4a6b015600000000, 0x0ac6796f00000000, + 0xcaa2517800000000}, + {0x0000000000000000, 0xd4ea739b00000000, 0xe9d396ed00000000, + 0x3d39e57600000000, 0x93a15c0000000000, 0x474b2f9b00000000, + 0x7a72caed00000000, 0xae98b97600000000, 0x2643b90000000000, + 0xf2a9ca9b00000000, 0xcf902fed00000000, 0x1b7a5c7600000000, + 0xb5e2e50000000000, 0x6108969b00000000, 0x5c3173ed00000000, + 0x88db007600000000, 0x4c86720100000000, 0x986c019a00000000, + 0xa555e4ec00000000, 0x71bf977700000000, 0xdf272e0100000000, + 0x0bcd5d9a00000000, 0x36f4b8ec00000000, 0xe21ecb7700000000, + 0x6ac5cb0100000000, 0xbe2fb89a00000000, 0x83165dec00000000, + 0x57fc2e7700000000, 0xf964970100000000, 0x2d8ee49a00000000, + 0x10b701ec00000000, 0xc45d727700000000, 0x980ce50200000000, + 0x4ce6969900000000, 0x71df73ef00000000, 0xa535007400000000, + 0x0badb90200000000, 0xdf47ca9900000000, 0xe27e2fef00000000, + 0x36945c7400000000, 0xbe4f5c0200000000, 0x6aa52f9900000000, + 0x579ccaef00000000, 0x8376b97400000000, 0x2dee000200000000, + 0xf904739900000000, 0xc43d96ef00000000, 0x10d7e57400000000, + 0xd48a970300000000, 0x0060e49800000000, 0x3d5901ee00000000, + 0xe9b3727500000000, 0x472bcb0300000000, 0x93c1b89800000000, + 0xaef85dee00000000, 0x7a122e7500000000, 0xf2c92e0300000000, + 0x26235d9800000000, 0x1b1ab8ee00000000, 0xcff0cb7500000000, + 0x6168720300000000, 0xb582019800000000, 0x88bbe4ee00000000, + 0x5c51977500000000, 0x3019ca0500000000, 0xe4f3b99e00000000, + 0xd9ca5ce800000000, 0x0d202f7300000000, 0xa3b8960500000000, + 0x7752e59e00000000, 0x4a6b00e800000000, 0x9e81737300000000, + 0x165a730500000000, 0xc2b0009e00000000, 0xff89e5e800000000, + 0x2b63967300000000, 0x85fb2f0500000000, 0x51115c9e00000000, + 0x6c28b9e800000000, 0xb8c2ca7300000000, 0x7c9fb80400000000, + 0xa875cb9f00000000, 0x954c2ee900000000, 0x41a65d7200000000, + 0xef3ee40400000000, 0x3bd4979f00000000, 0x06ed72e900000000, + 0xd207017200000000, 0x5adc010400000000, 0x8e36729f00000000, + 0xb30f97e900000000, 0x67e5e47200000000, 0xc97d5d0400000000, + 0x1d972e9f00000000, 0x20aecbe900000000, 0xf444b87200000000, + 0xa8152f0700000000, 0x7cff5c9c00000000, 0x41c6b9ea00000000, + 0x952cca7100000000, 0x3bb4730700000000, 0xef5e009c00000000, + 0xd267e5ea00000000, 0x068d967100000000, 0x8e56960700000000, + 0x5abce59c00000000, 0x678500ea00000000, 0xb36f737100000000, + 0x1df7ca0700000000, 0xc91db99c00000000, 0xf4245cea00000000, + 0x20ce2f7100000000, 0xe4935d0600000000, 0x30792e9d00000000, + 0x0d40cbeb00000000, 0xd9aab87000000000, 0x7732010600000000, + 0xa3d8729d00000000, 0x9ee197eb00000000, 0x4a0be47000000000, + 0xc2d0e40600000000, 0x163a979d00000000, 0x2b0372eb00000000, + 0xffe9017000000000, 0x5171b80600000000, 0x859bcb9d00000000, + 0xb8a22eeb00000000, 0x6c485d7000000000, 0x6032940b00000000, + 0xb4d8e79000000000, 0x89e102e600000000, 0x5d0b717d00000000, + 0xf393c80b00000000, 0x2779bb9000000000, 0x1a405ee600000000, + 0xceaa2d7d00000000, 0x46712d0b00000000, 0x929b5e9000000000, + 0xafa2bbe600000000, 0x7b48c87d00000000, 0xd5d0710b00000000, + 0x013a029000000000, 0x3c03e7e600000000, 0xe8e9947d00000000, + 0x2cb4e60a00000000, 0xf85e959100000000, 0xc56770e700000000, + 0x118d037c00000000, 0xbf15ba0a00000000, 0x6bffc99100000000, + 0x56c62ce700000000, 0x822c5f7c00000000, 0x0af75f0a00000000, + 0xde1d2c9100000000, 0xe324c9e700000000, 0x37ceba7c00000000, + 0x9956030a00000000, 0x4dbc709100000000, 0x708595e700000000, + 0xa46fe67c00000000, 0xf83e710900000000, 0x2cd4029200000000, + 0x11ede7e400000000, 0xc507947f00000000, 0x6b9f2d0900000000, + 0xbf755e9200000000, 0x824cbbe400000000, 0x56a6c87f00000000, + 0xde7dc80900000000, 0x0a97bb9200000000, 0x37ae5ee400000000, + 0xe3442d7f00000000, 0x4ddc940900000000, 0x9936e79200000000, + 0xa40f02e400000000, 0x70e5717f00000000, 0xb4b8030800000000, + 0x6052709300000000, 0x5d6b95e500000000, 0x8981e67e00000000, + 0x27195f0800000000, 0xf3f32c9300000000, 0xcecac9e500000000, + 0x1a20ba7e00000000, 0x92fbba0800000000, 0x4611c99300000000, + 0x7b282ce500000000, 0xafc25f7e00000000, 0x015ae60800000000, + 0xd5b0959300000000, 0xe88970e500000000, 0x3c63037e00000000, + 0x502b5e0e00000000, 0x84c12d9500000000, 0xb9f8c8e300000000, + 0x6d12bb7800000000, 0xc38a020e00000000, 0x1760719500000000, + 0x2a5994e300000000, 0xfeb3e77800000000, 0x7668e70e00000000, + 0xa282949500000000, 0x9fbb71e300000000, 0x4b51027800000000, + 0xe5c9bb0e00000000, 0x3123c89500000000, 0x0c1a2de300000000, + 0xd8f05e7800000000, 0x1cad2c0f00000000, 0xc8475f9400000000, + 0xf57ebae200000000, 0x2194c97900000000, 0x8f0c700f00000000, + 0x5be6039400000000, 0x66dfe6e200000000, 0xb235957900000000, + 0x3aee950f00000000, 0xee04e69400000000, 0xd33d03e200000000, + 0x07d7707900000000, 0xa94fc90f00000000, 0x7da5ba9400000000, + 0x409c5fe200000000, 0x94762c7900000000, 0xc827bb0c00000000, + 0x1ccdc89700000000, 0x21f42de100000000, 0xf51e5e7a00000000, + 0x5b86e70c00000000, 0x8f6c949700000000, 0xb25571e100000000, + 0x66bf027a00000000, 0xee64020c00000000, 0x3a8e719700000000, + 0x07b794e100000000, 0xd35de77a00000000, 0x7dc55e0c00000000, + 0xa92f2d9700000000, 0x9416c8e100000000, 0x40fcbb7a00000000, + 0x84a1c90d00000000, 0x504bba9600000000, 0x6d725fe000000000, + 0xb9982c7b00000000, 0x1700950d00000000, 0xc3eae69600000000, + 0xfed303e000000000, 0x2a39707b00000000, 0xa2e2700d00000000, + 0x7608039600000000, 0x4b31e6e000000000, 0x9fdb957b00000000, + 0x31432c0d00000000, 0xe5a95f9600000000, 0xd890bae000000000, + 0x0c7ac97b00000000}, + {0x0000000000000000, 0x2765258100000000, 0x0fcc3bd900000000, + 0x28a91e5800000000, 0x5f9e066900000000, 0x78fb23e800000000, + 0x50523db000000000, 0x7737183100000000, 0xbe3c0dd200000000, + 0x9959285300000000, 0xb1f0360b00000000, 0x9695138a00000000, + 0xe1a20bbb00000000, 0xc6c72e3a00000000, 0xee6e306200000000, + 0xc90b15e300000000, 0x3d7f6b7f00000000, 0x1a1a4efe00000000, + 0x32b350a600000000, 0x15d6752700000000, 0x62e16d1600000000, + 0x4584489700000000, 0x6d2d56cf00000000, 0x4a48734e00000000, + 0x834366ad00000000, 0xa426432c00000000, 0x8c8f5d7400000000, + 0xabea78f500000000, 0xdcdd60c400000000, 0xfbb8454500000000, + 0xd3115b1d00000000, 0xf4747e9c00000000, 0x7afed6fe00000000, + 0x5d9bf37f00000000, 0x7532ed2700000000, 0x5257c8a600000000, + 0x2560d09700000000, 0x0205f51600000000, 0x2aaceb4e00000000, + 0x0dc9cecf00000000, 0xc4c2db2c00000000, 0xe3a7fead00000000, + 0xcb0ee0f500000000, 0xec6bc57400000000, 0x9b5cdd4500000000, + 0xbc39f8c400000000, 0x9490e69c00000000, 0xb3f5c31d00000000, + 0x4781bd8100000000, 0x60e4980000000000, 0x484d865800000000, + 0x6f28a3d900000000, 0x181fbbe800000000, 0x3f7a9e6900000000, + 0x17d3803100000000, 0x30b6a5b000000000, 0xf9bdb05300000000, + 0xded895d200000000, 0xf6718b8a00000000, 0xd114ae0b00000000, + 0xa623b63a00000000, 0x814693bb00000000, 0xa9ef8de300000000, + 0x8e8aa86200000000, 0xb5fadc2600000000, 0x929ff9a700000000, + 0xba36e7ff00000000, 0x9d53c27e00000000, 0xea64da4f00000000, + 0xcd01ffce00000000, 0xe5a8e19600000000, 0xc2cdc41700000000, + 0x0bc6d1f400000000, 0x2ca3f47500000000, 0x040aea2d00000000, + 0x236fcfac00000000, 0x5458d79d00000000, 0x733df21c00000000, + 0x5b94ec4400000000, 0x7cf1c9c500000000, 0x8885b75900000000, + 0xafe092d800000000, 0x87498c8000000000, 0xa02ca90100000000, + 0xd71bb13000000000, 0xf07e94b100000000, 0xd8d78ae900000000, + 0xffb2af6800000000, 0x36b9ba8b00000000, 0x11dc9f0a00000000, + 0x3975815200000000, 0x1e10a4d300000000, 0x6927bce200000000, + 0x4e42996300000000, 0x66eb873b00000000, 0x418ea2ba00000000, + 0xcf040ad800000000, 0xe8612f5900000000, 0xc0c8310100000000, + 0xe7ad148000000000, 0x909a0cb100000000, 0xb7ff293000000000, + 0x9f56376800000000, 0xb83312e900000000, 0x7138070a00000000, + 0x565d228b00000000, 0x7ef43cd300000000, 0x5991195200000000, + 0x2ea6016300000000, 0x09c324e200000000, 0x216a3aba00000000, + 0x060f1f3b00000000, 0xf27b61a700000000, 0xd51e442600000000, + 0xfdb75a7e00000000, 0xdad27fff00000000, 0xade567ce00000000, + 0x8a80424f00000000, 0xa2295c1700000000, 0x854c799600000000, + 0x4c476c7500000000, 0x6b2249f400000000, 0x438b57ac00000000, + 0x64ee722d00000000, 0x13d96a1c00000000, 0x34bc4f9d00000000, + 0x1c1551c500000000, 0x3b70744400000000, 0x6af5b94d00000000, + 0x4d909ccc00000000, 0x6539829400000000, 0x425ca71500000000, + 0x356bbf2400000000, 0x120e9aa500000000, 0x3aa784fd00000000, + 0x1dc2a17c00000000, 0xd4c9b49f00000000, 0xf3ac911e00000000, + 0xdb058f4600000000, 0xfc60aac700000000, 0x8b57b2f600000000, + 0xac32977700000000, 0x849b892f00000000, 0xa3feacae00000000, + 0x578ad23200000000, 0x70eff7b300000000, 0x5846e9eb00000000, + 0x7f23cc6a00000000, 0x0814d45b00000000, 0x2f71f1da00000000, + 0x07d8ef8200000000, 0x20bdca0300000000, 0xe9b6dfe000000000, + 0xced3fa6100000000, 0xe67ae43900000000, 0xc11fc1b800000000, + 0xb628d98900000000, 0x914dfc0800000000, 0xb9e4e25000000000, + 0x9e81c7d100000000, 0x100b6fb300000000, 0x376e4a3200000000, + 0x1fc7546a00000000, 0x38a271eb00000000, 0x4f9569da00000000, + 0x68f04c5b00000000, 0x4059520300000000, 0x673c778200000000, + 0xae37626100000000, 0x895247e000000000, 0xa1fb59b800000000, + 0x869e7c3900000000, 0xf1a9640800000000, 0xd6cc418900000000, + 0xfe655fd100000000, 0xd9007a5000000000, 0x2d7404cc00000000, + 0x0a11214d00000000, 0x22b83f1500000000, 0x05dd1a9400000000, + 0x72ea02a500000000, 0x558f272400000000, 0x7d26397c00000000, + 0x5a431cfd00000000, 0x9348091e00000000, 0xb42d2c9f00000000, + 0x9c8432c700000000, 0xbbe1174600000000, 0xccd60f7700000000, + 0xebb32af600000000, 0xc31a34ae00000000, 0xe47f112f00000000, + 0xdf0f656b00000000, 0xf86a40ea00000000, 0xd0c35eb200000000, + 0xf7a67b3300000000, 0x8091630200000000, 0xa7f4468300000000, + 0x8f5d58db00000000, 0xa8387d5a00000000, 0x613368b900000000, + 0x46564d3800000000, 0x6eff536000000000, 0x499a76e100000000, + 0x3ead6ed000000000, 0x19c84b5100000000, 0x3161550900000000, + 0x1604708800000000, 0xe2700e1400000000, 0xc5152b9500000000, + 0xedbc35cd00000000, 0xcad9104c00000000, 0xbdee087d00000000, + 0x9a8b2dfc00000000, 0xb22233a400000000, 0x9547162500000000, + 0x5c4c03c600000000, 0x7b29264700000000, 0x5380381f00000000, + 0x74e51d9e00000000, 0x03d205af00000000, 0x24b7202e00000000, + 0x0c1e3e7600000000, 0x2b7b1bf700000000, 0xa5f1b39500000000, + 0x8294961400000000, 0xaa3d884c00000000, 0x8d58adcd00000000, + 0xfa6fb5fc00000000, 0xdd0a907d00000000, 0xf5a38e2500000000, + 0xd2c6aba400000000, 0x1bcdbe4700000000, 0x3ca89bc600000000, + 0x1401859e00000000, 0x3364a01f00000000, 0x4453b82e00000000, + 0x63369daf00000000, 0x4b9f83f700000000, 0x6cfaa67600000000, + 0x988ed8ea00000000, 0xbfebfd6b00000000, 0x9742e33300000000, + 0xb027c6b200000000, 0xc710de8300000000, 0xe075fb0200000000, + 0xc8dce55a00000000, 0xefb9c0db00000000, 0x26b2d53800000000, + 0x01d7f0b900000000, 0x297eeee100000000, 0x0e1bcb6000000000, + 0x792cd35100000000, 0x5e49f6d000000000, 0x76e0e88800000000, + 0x5185cd0900000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x9ba54c6f, 0xec3b9e9f, 0x779ed2f0, 0x03063b7f, + 0x98a37710, 0xef3da5e0, 0x7498e98f, 0x060c76fe, 0x9da93a91, + 0xea37e861, 0x7192a40e, 0x050a4d81, 0x9eaf01ee, 0xe931d31e, + 0x72949f71, 0x0c18edfc, 0x97bda193, 0xe0237363, 0x7b863f0c, + 0x0f1ed683, 0x94bb9aec, 0xe325481c, 0x78800473, 0x0a149b02, + 0x91b1d76d, 0xe62f059d, 0x7d8a49f2, 0x0912a07d, 0x92b7ec12, + 0xe5293ee2, 0x7e8c728d, 0x1831dbf8, 0x83949797, 0xf40a4567, + 0x6faf0908, 0x1b37e087, 0x8092ace8, 0xf70c7e18, 0x6ca93277, + 0x1e3dad06, 0x8598e169, 0xf2063399, 0x69a37ff6, 0x1d3b9679, + 0x869eda16, 0xf10008e6, 0x6aa54489, 0x14293604, 0x8f8c7a6b, + 0xf812a89b, 0x63b7e4f4, 0x172f0d7b, 0x8c8a4114, 0xfb1493e4, + 0x60b1df8b, 0x122540fa, 0x89800c95, 0xfe1ede65, 0x65bb920a, + 0x11237b85, 0x8a8637ea, 0xfd18e51a, 0x66bda975, 0x3063b7f0, + 0xabc6fb9f, 0xdc58296f, 0x47fd6500, 0x33658c8f, 0xa8c0c0e0, + 0xdf5e1210, 0x44fb5e7f, 0x366fc10e, 0xadca8d61, 0xda545f91, + 0x41f113fe, 0x3569fa71, 0xaeccb61e, 0xd95264ee, 0x42f72881, + 0x3c7b5a0c, 0xa7de1663, 0xd040c493, 0x4be588fc, 0x3f7d6173, + 0xa4d82d1c, 0xd346ffec, 0x48e3b383, 0x3a772cf2, 0xa1d2609d, + 0xd64cb26d, 0x4de9fe02, 0x3971178d, 0xa2d45be2, 0xd54a8912, + 0x4eefc57d, 0x28526c08, 0xb3f72067, 0xc469f297, 0x5fccbef8, + 0x2b545777, 0xb0f11b18, 0xc76fc9e8, 0x5cca8587, 0x2e5e1af6, + 0xb5fb5699, 0xc2658469, 0x59c0c806, 0x2d582189, 0xb6fd6de6, + 0xc163bf16, 0x5ac6f379, 0x244a81f4, 0xbfefcd9b, 0xc8711f6b, + 0x53d45304, 0x274cba8b, 0xbce9f6e4, 0xcb772414, 0x50d2687b, + 0x2246f70a, 0xb9e3bb65, 0xce7d6995, 0x55d825fa, 0x2140cc75, + 0xbae5801a, 0xcd7b52ea, 0x56de1e85, 0x60c76fe0, 0xfb62238f, + 0x8cfcf17f, 0x1759bd10, 0x63c1549f, 0xf86418f0, 0x8ffaca00, + 0x145f866f, 0x66cb191e, 0xfd6e5571, 0x8af08781, 0x1155cbee, + 0x65cd2261, 0xfe686e0e, 0x89f6bcfe, 0x1253f091, 0x6cdf821c, + 0xf77ace73, 0x80e41c83, 0x1b4150ec, 0x6fd9b963, 0xf47cf50c, + 0x83e227fc, 0x18476b93, 0x6ad3f4e2, 0xf176b88d, 0x86e86a7d, + 0x1d4d2612, 0x69d5cf9d, 0xf27083f2, 0x85ee5102, 0x1e4b1d6d, + 0x78f6b418, 0xe353f877, 0x94cd2a87, 0x0f6866e8, 0x7bf08f67, + 0xe055c308, 0x97cb11f8, 0x0c6e5d97, 0x7efac2e6, 0xe55f8e89, + 0x92c15c79, 0x09641016, 0x7dfcf999, 0xe659b5f6, 0x91c76706, + 0x0a622b69, 0x74ee59e4, 0xef4b158b, 0x98d5c77b, 0x03708b14, + 0x77e8629b, 0xec4d2ef4, 0x9bd3fc04, 0x0076b06b, 0x72e22f1a, + 0xe9476375, 0x9ed9b185, 0x057cfdea, 0x71e41465, 0xea41580a, + 0x9ddf8afa, 0x067ac695, 0x50a4d810, 0xcb01947f, 0xbc9f468f, + 0x273a0ae0, 0x53a2e36f, 0xc807af00, 0xbf997df0, 0x243c319f, + 0x56a8aeee, 0xcd0de281, 0xba933071, 0x21367c1e, 0x55ae9591, + 0xce0bd9fe, 0xb9950b0e, 0x22304761, 0x5cbc35ec, 0xc7197983, + 0xb087ab73, 0x2b22e71c, 0x5fba0e93, 0xc41f42fc, 0xb381900c, + 0x2824dc63, 0x5ab04312, 0xc1150f7d, 0xb68bdd8d, 0x2d2e91e2, + 0x59b6786d, 0xc2133402, 0xb58de6f2, 0x2e28aa9d, 0x489503e8, + 0xd3304f87, 0xa4ae9d77, 0x3f0bd118, 0x4b933897, 0xd03674f8, + 0xa7a8a608, 0x3c0dea67, 0x4e997516, 0xd53c3979, 0xa2a2eb89, + 0x3907a7e6, 0x4d9f4e69, 0xd63a0206, 0xa1a4d0f6, 0x3a019c99, + 0x448dee14, 0xdf28a27b, 0xa8b6708b, 0x33133ce4, 0x478bd56b, + 0xdc2e9904, 0xabb04bf4, 0x3015079b, 0x428198ea, 0xd924d485, + 0xaeba0675, 0x351f4a1a, 0x4187a395, 0xda22effa, 0xadbc3d0a, + 0x36197165}, + {0x00000000, 0xc18edfc0, 0x586cb9c1, 0x99e26601, 0xb0d97382, + 0x7157ac42, 0xe8b5ca43, 0x293b1583, 0xbac3e145, 0x7b4d3e85, + 0xe2af5884, 0x23218744, 0x0a1a92c7, 0xcb944d07, 0x52762b06, + 0x93f8f4c6, 0xaef6c4cb, 0x6f781b0b, 0xf69a7d0a, 0x3714a2ca, + 0x1e2fb749, 0xdfa16889, 0x46430e88, 0x87cdd148, 0x1435258e, + 0xd5bbfa4e, 0x4c599c4f, 0x8dd7438f, 0xa4ec560c, 0x656289cc, + 0xfc80efcd, 0x3d0e300d, 0x869c8fd7, 0x47125017, 0xdef03616, + 0x1f7ee9d6, 0x3645fc55, 0xf7cb2395, 0x6e294594, 0xafa79a54, + 0x3c5f6e92, 0xfdd1b152, 0x6433d753, 0xa5bd0893, 0x8c861d10, + 0x4d08c2d0, 0xd4eaa4d1, 0x15647b11, 0x286a4b1c, 0xe9e494dc, + 0x7006f2dd, 0xb1882d1d, 0x98b3389e, 0x593de75e, 0xc0df815f, + 0x01515e9f, 0x92a9aa59, 0x53277599, 0xcac51398, 0x0b4bcc58, + 0x2270d9db, 0xe3fe061b, 0x7a1c601a, 0xbb92bfda, 0xd64819ef, + 0x17c6c62f, 0x8e24a02e, 0x4faa7fee, 0x66916a6d, 0xa71fb5ad, + 0x3efdd3ac, 0xff730c6c, 0x6c8bf8aa, 0xad05276a, 0x34e7416b, + 0xf5699eab, 0xdc528b28, 0x1ddc54e8, 0x843e32e9, 0x45b0ed29, + 0x78bedd24, 0xb93002e4, 0x20d264e5, 0xe15cbb25, 0xc867aea6, + 0x09e97166, 0x900b1767, 0x5185c8a7, 0xc27d3c61, 0x03f3e3a1, + 0x9a1185a0, 0x5b9f5a60, 0x72a44fe3, 0xb32a9023, 0x2ac8f622, + 0xeb4629e2, 0x50d49638, 0x915a49f8, 0x08b82ff9, 0xc936f039, + 0xe00de5ba, 0x21833a7a, 0xb8615c7b, 0x79ef83bb, 0xea17777d, + 0x2b99a8bd, 0xb27bcebc, 0x73f5117c, 0x5ace04ff, 0x9b40db3f, + 0x02a2bd3e, 0xc32c62fe, 0xfe2252f3, 0x3fac8d33, 0xa64eeb32, + 0x67c034f2, 0x4efb2171, 0x8f75feb1, 0x169798b0, 0xd7194770, + 0x44e1b3b6, 0x856f6c76, 0x1c8d0a77, 0xdd03d5b7, 0xf438c034, + 0x35b61ff4, 0xac5479f5, 0x6ddaa635, 0x77e1359f, 0xb66fea5f, + 0x2f8d8c5e, 0xee03539e, 0xc738461d, 0x06b699dd, 0x9f54ffdc, + 0x5eda201c, 0xcd22d4da, 0x0cac0b1a, 0x954e6d1b, 0x54c0b2db, + 0x7dfba758, 0xbc757898, 0x25971e99, 0xe419c159, 0xd917f154, + 0x18992e94, 0x817b4895, 0x40f59755, 0x69ce82d6, 0xa8405d16, + 0x31a23b17, 0xf02ce4d7, 0x63d41011, 0xa25acfd1, 0x3bb8a9d0, + 0xfa367610, 0xd30d6393, 0x1283bc53, 0x8b61da52, 0x4aef0592, + 0xf17dba48, 0x30f36588, 0xa9110389, 0x689fdc49, 0x41a4c9ca, + 0x802a160a, 0x19c8700b, 0xd846afcb, 0x4bbe5b0d, 0x8a3084cd, + 0x13d2e2cc, 0xd25c3d0c, 0xfb67288f, 0x3ae9f74f, 0xa30b914e, + 0x62854e8e, 0x5f8b7e83, 0x9e05a143, 0x07e7c742, 0xc6691882, + 0xef520d01, 0x2edcd2c1, 0xb73eb4c0, 0x76b06b00, 0xe5489fc6, + 0x24c64006, 0xbd242607, 0x7caaf9c7, 0x5591ec44, 0x941f3384, + 0x0dfd5585, 0xcc738a45, 0xa1a92c70, 0x6027f3b0, 0xf9c595b1, + 0x384b4a71, 0x11705ff2, 0xd0fe8032, 0x491ce633, 0x889239f3, + 0x1b6acd35, 0xdae412f5, 0x430674f4, 0x8288ab34, 0xabb3beb7, + 0x6a3d6177, 0xf3df0776, 0x3251d8b6, 0x0f5fe8bb, 0xced1377b, + 0x5733517a, 0x96bd8eba, 0xbf869b39, 0x7e0844f9, 0xe7ea22f8, + 0x2664fd38, 0xb59c09fe, 0x7412d63e, 0xedf0b03f, 0x2c7e6fff, + 0x05457a7c, 0xc4cba5bc, 0x5d29c3bd, 0x9ca71c7d, 0x2735a3a7, + 0xe6bb7c67, 0x7f591a66, 0xbed7c5a6, 0x97ecd025, 0x56620fe5, + 0xcf8069e4, 0x0e0eb624, 0x9df642e2, 0x5c789d22, 0xc59afb23, + 0x041424e3, 0x2d2f3160, 0xeca1eea0, 0x754388a1, 0xb4cd5761, + 0x89c3676c, 0x484db8ac, 0xd1afdead, 0x1021016d, 0x391a14ee, + 0xf894cb2e, 0x6176ad2f, 0xa0f872ef, 0x33008629, 0xf28e59e9, + 0x6b6c3fe8, 0xaae2e028, 0x83d9f5ab, 0x42572a6b, 0xdbb54c6a, + 0x1a3b93aa}, + {0x00000000, 0xefc26b3e, 0x04f5d03d, 0xeb37bb03, 0x09eba07a, + 0xe629cb44, 0x0d1e7047, 0xe2dc1b79, 0x13d740f4, 0xfc152bca, + 0x172290c9, 0xf8e0fbf7, 0x1a3ce08e, 0xf5fe8bb0, 0x1ec930b3, + 0xf10b5b8d, 0x27ae81e8, 0xc86cead6, 0x235b51d5, 0xcc993aeb, + 0x2e452192, 0xc1874aac, 0x2ab0f1af, 0xc5729a91, 0x3479c11c, + 0xdbbbaa22, 0x308c1121, 0xdf4e7a1f, 0x3d926166, 0xd2500a58, + 0x3967b15b, 0xd6a5da65, 0x4f5d03d0, 0xa09f68ee, 0x4ba8d3ed, + 0xa46ab8d3, 0x46b6a3aa, 0xa974c894, 0x42437397, 0xad8118a9, + 0x5c8a4324, 0xb348281a, 0x587f9319, 0xb7bdf827, 0x5561e35e, + 0xbaa38860, 0x51943363, 0xbe56585d, 0x68f38238, 0x8731e906, + 0x6c065205, 0x83c4393b, 0x61182242, 0x8eda497c, 0x65edf27f, + 0x8a2f9941, 0x7b24c2cc, 0x94e6a9f2, 0x7fd112f1, 0x901379cf, + 0x72cf62b6, 0x9d0d0988, 0x763ab28b, 0x99f8d9b5, 0x9eba07a0, + 0x71786c9e, 0x9a4fd79d, 0x758dbca3, 0x9751a7da, 0x7893cce4, + 0x93a477e7, 0x7c661cd9, 0x8d6d4754, 0x62af2c6a, 0x89989769, + 0x665afc57, 0x8486e72e, 0x6b448c10, 0x80733713, 0x6fb15c2d, + 0xb9148648, 0x56d6ed76, 0xbde15675, 0x52233d4b, 0xb0ff2632, + 0x5f3d4d0c, 0xb40af60f, 0x5bc89d31, 0xaac3c6bc, 0x4501ad82, + 0xae361681, 0x41f47dbf, 0xa32866c6, 0x4cea0df8, 0xa7ddb6fb, + 0x481fddc5, 0xd1e70470, 0x3e256f4e, 0xd512d44d, 0x3ad0bf73, + 0xd80ca40a, 0x37cecf34, 0xdcf97437, 0x333b1f09, 0xc2304484, + 0x2df22fba, 0xc6c594b9, 0x2907ff87, 0xcbdbe4fe, 0x24198fc0, + 0xcf2e34c3, 0x20ec5ffd, 0xf6498598, 0x198beea6, 0xf2bc55a5, + 0x1d7e3e9b, 0xffa225e2, 0x10604edc, 0xfb57f5df, 0x14959ee1, + 0xe59ec56c, 0x0a5cae52, 0xe16b1551, 0x0ea97e6f, 0xec756516, + 0x03b70e28, 0xe880b52b, 0x0742de15, 0xe6050901, 0x09c7623f, + 0xe2f0d93c, 0x0d32b202, 0xefeea97b, 0x002cc245, 0xeb1b7946, + 0x04d91278, 0xf5d249f5, 0x1a1022cb, 0xf12799c8, 0x1ee5f2f6, + 0xfc39e98f, 0x13fb82b1, 0xf8cc39b2, 0x170e528c, 0xc1ab88e9, + 0x2e69e3d7, 0xc55e58d4, 0x2a9c33ea, 0xc8402893, 0x278243ad, + 0xccb5f8ae, 0x23779390, 0xd27cc81d, 0x3dbea323, 0xd6891820, + 0x394b731e, 0xdb976867, 0x34550359, 0xdf62b85a, 0x30a0d364, + 0xa9580ad1, 0x469a61ef, 0xadaddaec, 0x426fb1d2, 0xa0b3aaab, + 0x4f71c195, 0xa4467a96, 0x4b8411a8, 0xba8f4a25, 0x554d211b, + 0xbe7a9a18, 0x51b8f126, 0xb364ea5f, 0x5ca68161, 0xb7913a62, + 0x5853515c, 0x8ef68b39, 0x6134e007, 0x8a035b04, 0x65c1303a, + 0x871d2b43, 0x68df407d, 0x83e8fb7e, 0x6c2a9040, 0x9d21cbcd, + 0x72e3a0f3, 0x99d41bf0, 0x761670ce, 0x94ca6bb7, 0x7b080089, + 0x903fbb8a, 0x7ffdd0b4, 0x78bf0ea1, 0x977d659f, 0x7c4ade9c, + 0x9388b5a2, 0x7154aedb, 0x9e96c5e5, 0x75a17ee6, 0x9a6315d8, + 0x6b684e55, 0x84aa256b, 0x6f9d9e68, 0x805ff556, 0x6283ee2f, + 0x8d418511, 0x66763e12, 0x89b4552c, 0x5f118f49, 0xb0d3e477, + 0x5be45f74, 0xb426344a, 0x56fa2f33, 0xb938440d, 0x520fff0e, + 0xbdcd9430, 0x4cc6cfbd, 0xa304a483, 0x48331f80, 0xa7f174be, + 0x452d6fc7, 0xaaef04f9, 0x41d8bffa, 0xae1ad4c4, 0x37e20d71, + 0xd820664f, 0x3317dd4c, 0xdcd5b672, 0x3e09ad0b, 0xd1cbc635, + 0x3afc7d36, 0xd53e1608, 0x24354d85, 0xcbf726bb, 0x20c09db8, + 0xcf02f686, 0x2ddeedff, 0xc21c86c1, 0x292b3dc2, 0xc6e956fc, + 0x104c8c99, 0xff8ee7a7, 0x14b95ca4, 0xfb7b379a, 0x19a72ce3, + 0xf66547dd, 0x1d52fcde, 0xf29097e0, 0x039bcc6d, 0xec59a753, + 0x076e1c50, 0xe8ac776e, 0x0a706c17, 0xe5b20729, 0x0e85bc2a, + 0xe147d714}, + {0x00000000, 0x177b1443, 0x2ef62886, 0x398d3cc5, 0x5dec510c, + 0x4a97454f, 0x731a798a, 0x64616dc9, 0xbbd8a218, 0xaca3b65b, + 0x952e8a9e, 0x82559edd, 0xe634f314, 0xf14fe757, 0xc8c2db92, + 0xdfb9cfd1, 0xacc04271, 0xbbbb5632, 0x82366af7, 0x954d7eb4, + 0xf12c137d, 0xe657073e, 0xdfda3bfb, 0xc8a12fb8, 0x1718e069, + 0x0063f42a, 0x39eec8ef, 0x2e95dcac, 0x4af4b165, 0x5d8fa526, + 0x640299e3, 0x73798da0, 0x82f182a3, 0x958a96e0, 0xac07aa25, + 0xbb7cbe66, 0xdf1dd3af, 0xc866c7ec, 0xf1ebfb29, 0xe690ef6a, + 0x392920bb, 0x2e5234f8, 0x17df083d, 0x00a41c7e, 0x64c571b7, + 0x73be65f4, 0x4a335931, 0x5d484d72, 0x2e31c0d2, 0x394ad491, + 0x00c7e854, 0x17bcfc17, 0x73dd91de, 0x64a6859d, 0x5d2bb958, + 0x4a50ad1b, 0x95e962ca, 0x82927689, 0xbb1f4a4c, 0xac645e0f, + 0xc80533c6, 0xdf7e2785, 0xe6f31b40, 0xf1880f03, 0xde920307, + 0xc9e91744, 0xf0642b81, 0xe71f3fc2, 0x837e520b, 0x94054648, + 0xad887a8d, 0xbaf36ece, 0x654aa11f, 0x7231b55c, 0x4bbc8999, + 0x5cc79dda, 0x38a6f013, 0x2fdde450, 0x1650d895, 0x012bccd6, + 0x72524176, 0x65295535, 0x5ca469f0, 0x4bdf7db3, 0x2fbe107a, + 0x38c50439, 0x014838fc, 0x16332cbf, 0xc98ae36e, 0xdef1f72d, + 0xe77ccbe8, 0xf007dfab, 0x9466b262, 0x831da621, 0xba909ae4, + 0xadeb8ea7, 0x5c6381a4, 0x4b1895e7, 0x7295a922, 0x65eebd61, + 0x018fd0a8, 0x16f4c4eb, 0x2f79f82e, 0x3802ec6d, 0xe7bb23bc, + 0xf0c037ff, 0xc94d0b3a, 0xde361f79, 0xba5772b0, 0xad2c66f3, + 0x94a15a36, 0x83da4e75, 0xf0a3c3d5, 0xe7d8d796, 0xde55eb53, + 0xc92eff10, 0xad4f92d9, 0xba34869a, 0x83b9ba5f, 0x94c2ae1c, + 0x4b7b61cd, 0x5c00758e, 0x658d494b, 0x72f65d08, 0x169730c1, + 0x01ec2482, 0x38611847, 0x2f1a0c04, 0x6655004f, 0x712e140c, + 0x48a328c9, 0x5fd83c8a, 0x3bb95143, 0x2cc24500, 0x154f79c5, + 0x02346d86, 0xdd8da257, 0xcaf6b614, 0xf37b8ad1, 0xe4009e92, + 0x8061f35b, 0x971ae718, 0xae97dbdd, 0xb9eccf9e, 0xca95423e, + 0xddee567d, 0xe4636ab8, 0xf3187efb, 0x97791332, 0x80020771, + 0xb98f3bb4, 0xaef42ff7, 0x714de026, 0x6636f465, 0x5fbbc8a0, + 0x48c0dce3, 0x2ca1b12a, 0x3bdaa569, 0x025799ac, 0x152c8def, + 0xe4a482ec, 0xf3df96af, 0xca52aa6a, 0xdd29be29, 0xb948d3e0, + 0xae33c7a3, 0x97befb66, 0x80c5ef25, 0x5f7c20f4, 0x480734b7, + 0x718a0872, 0x66f11c31, 0x029071f8, 0x15eb65bb, 0x2c66597e, + 0x3b1d4d3d, 0x4864c09d, 0x5f1fd4de, 0x6692e81b, 0x71e9fc58, + 0x15889191, 0x02f385d2, 0x3b7eb917, 0x2c05ad54, 0xf3bc6285, + 0xe4c776c6, 0xdd4a4a03, 0xca315e40, 0xae503389, 0xb92b27ca, + 0x80a61b0f, 0x97dd0f4c, 0xb8c70348, 0xafbc170b, 0x96312bce, + 0x814a3f8d, 0xe52b5244, 0xf2504607, 0xcbdd7ac2, 0xdca66e81, + 0x031fa150, 0x1464b513, 0x2de989d6, 0x3a929d95, 0x5ef3f05c, + 0x4988e41f, 0x7005d8da, 0x677ecc99, 0x14074139, 0x037c557a, + 0x3af169bf, 0x2d8a7dfc, 0x49eb1035, 0x5e900476, 0x671d38b3, + 0x70662cf0, 0xafdfe321, 0xb8a4f762, 0x8129cba7, 0x9652dfe4, + 0xf233b22d, 0xe548a66e, 0xdcc59aab, 0xcbbe8ee8, 0x3a3681eb, + 0x2d4d95a8, 0x14c0a96d, 0x03bbbd2e, 0x67dad0e7, 0x70a1c4a4, + 0x492cf861, 0x5e57ec22, 0x81ee23f3, 0x969537b0, 0xaf180b75, + 0xb8631f36, 0xdc0272ff, 0xcb7966bc, 0xf2f45a79, 0xe58f4e3a, + 0x96f6c39a, 0x818dd7d9, 0xb800eb1c, 0xaf7bff5f, 0xcb1a9296, + 0xdc6186d5, 0xe5ecba10, 0xf297ae53, 0x2d2e6182, 0x3a5575c1, + 0x03d84904, 0x14a35d47, 0x70c2308e, 0x67b924cd, 0x5e341808, + 0x494f0c4b}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x43147b17, 0x8628f62e, 0xc53c8d39, 0x0c51ec5d, + 0x4f45974a, 0x8a791a73, 0xc96d6164, 0x18a2d8bb, 0x5bb6a3ac, + 0x9e8a2e95, 0xdd9e5582, 0x14f334e6, 0x57e74ff1, 0x92dbc2c8, + 0xd1cfb9df, 0x7142c0ac, 0x3256bbbb, 0xf76a3682, 0xb47e4d95, + 0x7d132cf1, 0x3e0757e6, 0xfb3bdadf, 0xb82fa1c8, 0x69e01817, + 0x2af46300, 0xefc8ee39, 0xacdc952e, 0x65b1f44a, 0x26a58f5d, + 0xe3990264, 0xa08d7973, 0xa382f182, 0xe0968a95, 0x25aa07ac, + 0x66be7cbb, 0xafd31ddf, 0xecc766c8, 0x29fbebf1, 0x6aef90e6, + 0xbb202939, 0xf834522e, 0x3d08df17, 0x7e1ca400, 0xb771c564, + 0xf465be73, 0x3159334a, 0x724d485d, 0xd2c0312e, 0x91d44a39, + 0x54e8c700, 0x17fcbc17, 0xde91dd73, 0x9d85a664, 0x58b92b5d, + 0x1bad504a, 0xca62e995, 0x89769282, 0x4c4a1fbb, 0x0f5e64ac, + 0xc63305c8, 0x85277edf, 0x401bf3e6, 0x030f88f1, 0x070392de, + 0x4417e9c9, 0x812b64f0, 0xc23f1fe7, 0x0b527e83, 0x48460594, + 0x8d7a88ad, 0xce6ef3ba, 0x1fa14a65, 0x5cb53172, 0x9989bc4b, + 0xda9dc75c, 0x13f0a638, 0x50e4dd2f, 0x95d85016, 0xd6cc2b01, + 0x76415272, 0x35552965, 0xf069a45c, 0xb37ddf4b, 0x7a10be2f, + 0x3904c538, 0xfc384801, 0xbf2c3316, 0x6ee38ac9, 0x2df7f1de, + 0xe8cb7ce7, 0xabdf07f0, 0x62b26694, 0x21a61d83, 0xe49a90ba, + 0xa78eebad, 0xa481635c, 0xe795184b, 0x22a99572, 0x61bdee65, + 0xa8d08f01, 0xebc4f416, 0x2ef8792f, 0x6dec0238, 0xbc23bbe7, + 0xff37c0f0, 0x3a0b4dc9, 0x791f36de, 0xb07257ba, 0xf3662cad, + 0x365aa194, 0x754eda83, 0xd5c3a3f0, 0x96d7d8e7, 0x53eb55de, + 0x10ff2ec9, 0xd9924fad, 0x9a8634ba, 0x5fbab983, 0x1caec294, + 0xcd617b4b, 0x8e75005c, 0x4b498d65, 0x085df672, 0xc1309716, + 0x8224ec01, 0x47186138, 0x040c1a2f, 0x4f005566, 0x0c142e71, + 0xc928a348, 0x8a3cd85f, 0x4351b93b, 0x0045c22c, 0xc5794f15, + 0x866d3402, 0x57a28ddd, 0x14b6f6ca, 0xd18a7bf3, 0x929e00e4, + 0x5bf36180, 0x18e71a97, 0xdddb97ae, 0x9ecfecb9, 0x3e4295ca, + 0x7d56eedd, 0xb86a63e4, 0xfb7e18f3, 0x32137997, 0x71070280, + 0xb43b8fb9, 0xf72ff4ae, 0x26e04d71, 0x65f43666, 0xa0c8bb5f, + 0xe3dcc048, 0x2ab1a12c, 0x69a5da3b, 0xac995702, 0xef8d2c15, + 0xec82a4e4, 0xaf96dff3, 0x6aaa52ca, 0x29be29dd, 0xe0d348b9, + 0xa3c733ae, 0x66fbbe97, 0x25efc580, 0xf4207c5f, 0xb7340748, + 0x72088a71, 0x311cf166, 0xf8719002, 0xbb65eb15, 0x7e59662c, + 0x3d4d1d3b, 0x9dc06448, 0xded41f5f, 0x1be89266, 0x58fce971, + 0x91918815, 0xd285f302, 0x17b97e3b, 0x54ad052c, 0x8562bcf3, + 0xc676c7e4, 0x034a4add, 0x405e31ca, 0x893350ae, 0xca272bb9, + 0x0f1ba680, 0x4c0fdd97, 0x4803c7b8, 0x0b17bcaf, 0xce2b3196, + 0x8d3f4a81, 0x44522be5, 0x074650f2, 0xc27addcb, 0x816ea6dc, + 0x50a11f03, 0x13b56414, 0xd689e92d, 0x959d923a, 0x5cf0f35e, + 0x1fe48849, 0xdad80570, 0x99cc7e67, 0x39410714, 0x7a557c03, + 0xbf69f13a, 0xfc7d8a2d, 0x3510eb49, 0x7604905e, 0xb3381d67, + 0xf02c6670, 0x21e3dfaf, 0x62f7a4b8, 0xa7cb2981, 0xe4df5296, + 0x2db233f2, 0x6ea648e5, 0xab9ac5dc, 0xe88ebecb, 0xeb81363a, + 0xa8954d2d, 0x6da9c014, 0x2ebdbb03, 0xe7d0da67, 0xa4c4a170, + 0x61f82c49, 0x22ec575e, 0xf323ee81, 0xb0379596, 0x750b18af, + 0x361f63b8, 0xff7202dc, 0xbc6679cb, 0x795af4f2, 0x3a4e8fe5, + 0x9ac3f696, 0xd9d78d81, 0x1ceb00b8, 0x5fff7baf, 0x96921acb, + 0xd58661dc, 0x10baece5, 0x53ae97f2, 0x82612e2d, 0xc175553a, + 0x0449d803, 0x475da314, 0x8e30c270, 0xcd24b967, 0x0818345e, + 0x4b0c4f49}, + {0x00000000, 0x3e6bc2ef, 0x3dd0f504, 0x03bb37eb, 0x7aa0eb09, + 0x44cb29e6, 0x47701e0d, 0x791bdce2, 0xf440d713, 0xca2b15fc, + 0xc9902217, 0xf7fbe0f8, 0x8ee03c1a, 0xb08bfef5, 0xb330c91e, + 0x8d5b0bf1, 0xe881ae27, 0xd6ea6cc8, 0xd5515b23, 0xeb3a99cc, + 0x9221452e, 0xac4a87c1, 0xaff1b02a, 0x919a72c5, 0x1cc17934, + 0x22aabbdb, 0x21118c30, 0x1f7a4edf, 0x6661923d, 0x580a50d2, + 0x5bb16739, 0x65daa5d6, 0xd0035d4f, 0xee689fa0, 0xedd3a84b, + 0xd3b86aa4, 0xaaa3b646, 0x94c874a9, 0x97734342, 0xa91881ad, + 0x24438a5c, 0x1a2848b3, 0x19937f58, 0x27f8bdb7, 0x5ee36155, + 0x6088a3ba, 0x63339451, 0x5d5856be, 0x3882f368, 0x06e93187, + 0x0552066c, 0x3b39c483, 0x42221861, 0x7c49da8e, 0x7ff2ed65, + 0x41992f8a, 0xccc2247b, 0xf2a9e694, 0xf112d17f, 0xcf791390, + 0xb662cf72, 0x88090d9d, 0x8bb23a76, 0xb5d9f899, 0xa007ba9e, + 0x9e6c7871, 0x9dd74f9a, 0xa3bc8d75, 0xdaa75197, 0xe4cc9378, + 0xe777a493, 0xd91c667c, 0x54476d8d, 0x6a2caf62, 0x69979889, + 0x57fc5a66, 0x2ee78684, 0x108c446b, 0x13377380, 0x2d5cb16f, + 0x488614b9, 0x76edd656, 0x7556e1bd, 0x4b3d2352, 0x3226ffb0, + 0x0c4d3d5f, 0x0ff60ab4, 0x319dc85b, 0xbcc6c3aa, 0x82ad0145, + 0x811636ae, 0xbf7df441, 0xc66628a3, 0xf80dea4c, 0xfbb6dda7, + 0xc5dd1f48, 0x7004e7d1, 0x4e6f253e, 0x4dd412d5, 0x73bfd03a, + 0x0aa40cd8, 0x34cfce37, 0x3774f9dc, 0x091f3b33, 0x844430c2, + 0xba2ff22d, 0xb994c5c6, 0x87ff0729, 0xfee4dbcb, 0xc08f1924, + 0xc3342ecf, 0xfd5fec20, 0x988549f6, 0xa6ee8b19, 0xa555bcf2, + 0x9b3e7e1d, 0xe225a2ff, 0xdc4e6010, 0xdff557fb, 0xe19e9514, + 0x6cc59ee5, 0x52ae5c0a, 0x51156be1, 0x6f7ea90e, 0x166575ec, + 0x280eb703, 0x2bb580e8, 0x15de4207, 0x010905e6, 0x3f62c709, + 0x3cd9f0e2, 0x02b2320d, 0x7ba9eeef, 0x45c22c00, 0x46791beb, + 0x7812d904, 0xf549d2f5, 0xcb22101a, 0xc89927f1, 0xf6f2e51e, + 0x8fe939fc, 0xb182fb13, 0xb239ccf8, 0x8c520e17, 0xe988abc1, + 0xd7e3692e, 0xd4585ec5, 0xea339c2a, 0x932840c8, 0xad438227, + 0xaef8b5cc, 0x90937723, 0x1dc87cd2, 0x23a3be3d, 0x201889d6, + 0x1e734b39, 0x676897db, 0x59035534, 0x5ab862df, 0x64d3a030, + 0xd10a58a9, 0xef619a46, 0xecdaadad, 0xd2b16f42, 0xabaab3a0, + 0x95c1714f, 0x967a46a4, 0xa811844b, 0x254a8fba, 0x1b214d55, + 0x189a7abe, 0x26f1b851, 0x5fea64b3, 0x6181a65c, 0x623a91b7, + 0x5c515358, 0x398bf68e, 0x07e03461, 0x045b038a, 0x3a30c165, + 0x432b1d87, 0x7d40df68, 0x7efbe883, 0x40902a6c, 0xcdcb219d, + 0xf3a0e372, 0xf01bd499, 0xce701676, 0xb76bca94, 0x8900087b, + 0x8abb3f90, 0xb4d0fd7f, 0xa10ebf78, 0x9f657d97, 0x9cde4a7c, + 0xa2b58893, 0xdbae5471, 0xe5c5969e, 0xe67ea175, 0xd815639a, + 0x554e686b, 0x6b25aa84, 0x689e9d6f, 0x56f55f80, 0x2fee8362, + 0x1185418d, 0x123e7666, 0x2c55b489, 0x498f115f, 0x77e4d3b0, + 0x745fe45b, 0x4a3426b4, 0x332ffa56, 0x0d4438b9, 0x0eff0f52, + 0x3094cdbd, 0xbdcfc64c, 0x83a404a3, 0x801f3348, 0xbe74f1a7, + 0xc76f2d45, 0xf904efaa, 0xfabfd841, 0xc4d41aae, 0x710de237, + 0x4f6620d8, 0x4cdd1733, 0x72b6d5dc, 0x0bad093e, 0x35c6cbd1, + 0x367dfc3a, 0x08163ed5, 0x854d3524, 0xbb26f7cb, 0xb89dc020, + 0x86f602cf, 0xffedde2d, 0xc1861cc2, 0xc23d2b29, 0xfc56e9c6, + 0x998c4c10, 0xa7e78eff, 0xa45cb914, 0x9a377bfb, 0xe32ca719, + 0xdd4765f6, 0xdefc521d, 0xe09790f2, 0x6dcc9b03, 0x53a759ec, + 0x501c6e07, 0x6e77ace8, 0x176c700a, 0x2907b2e5, 0x2abc850e, + 0x14d747e1}, + {0x00000000, 0xc0df8ec1, 0xc1b96c58, 0x0166e299, 0x8273d9b0, + 0x42ac5771, 0x43cab5e8, 0x83153b29, 0x45e1c3ba, 0x853e4d7b, + 0x8458afe2, 0x44872123, 0xc7921a0a, 0x074d94cb, 0x062b7652, + 0xc6f4f893, 0xcbc4f6ae, 0x0b1b786f, 0x0a7d9af6, 0xcaa21437, + 0x49b72f1e, 0x8968a1df, 0x880e4346, 0x48d1cd87, 0x8e253514, + 0x4efabbd5, 0x4f9c594c, 0x8f43d78d, 0x0c56eca4, 0xcc896265, + 0xcdef80fc, 0x0d300e3d, 0xd78f9c86, 0x17501247, 0x1636f0de, + 0xd6e97e1f, 0x55fc4536, 0x9523cbf7, 0x9445296e, 0x549aa7af, + 0x926e5f3c, 0x52b1d1fd, 0x53d73364, 0x9308bda5, 0x101d868c, + 0xd0c2084d, 0xd1a4ead4, 0x117b6415, 0x1c4b6a28, 0xdc94e4e9, + 0xddf20670, 0x1d2d88b1, 0x9e38b398, 0x5ee73d59, 0x5f81dfc0, + 0x9f5e5101, 0x59aaa992, 0x99752753, 0x9813c5ca, 0x58cc4b0b, + 0xdbd97022, 0x1b06fee3, 0x1a601c7a, 0xdabf92bb, 0xef1948d6, + 0x2fc6c617, 0x2ea0248e, 0xee7faa4f, 0x6d6a9166, 0xadb51fa7, + 0xacd3fd3e, 0x6c0c73ff, 0xaaf88b6c, 0x6a2705ad, 0x6b41e734, + 0xab9e69f5, 0x288b52dc, 0xe854dc1d, 0xe9323e84, 0x29edb045, + 0x24ddbe78, 0xe40230b9, 0xe564d220, 0x25bb5ce1, 0xa6ae67c8, + 0x6671e909, 0x67170b90, 0xa7c88551, 0x613c7dc2, 0xa1e3f303, + 0xa085119a, 0x605a9f5b, 0xe34fa472, 0x23902ab3, 0x22f6c82a, + 0xe22946eb, 0x3896d450, 0xf8495a91, 0xf92fb808, 0x39f036c9, + 0xbae50de0, 0x7a3a8321, 0x7b5c61b8, 0xbb83ef79, 0x7d7717ea, + 0xbda8992b, 0xbcce7bb2, 0x7c11f573, 0xff04ce5a, 0x3fdb409b, + 0x3ebda202, 0xfe622cc3, 0xf35222fe, 0x338dac3f, 0x32eb4ea6, + 0xf234c067, 0x7121fb4e, 0xb1fe758f, 0xb0989716, 0x704719d7, + 0xb6b3e144, 0x766c6f85, 0x770a8d1c, 0xb7d503dd, 0x34c038f4, + 0xf41fb635, 0xf57954ac, 0x35a6da6d, 0x9f35e177, 0x5fea6fb6, + 0x5e8c8d2f, 0x9e5303ee, 0x1d4638c7, 0xdd99b606, 0xdcff549f, + 0x1c20da5e, 0xdad422cd, 0x1a0bac0c, 0x1b6d4e95, 0xdbb2c054, + 0x58a7fb7d, 0x987875bc, 0x991e9725, 0x59c119e4, 0x54f117d9, + 0x942e9918, 0x95487b81, 0x5597f540, 0xd682ce69, 0x165d40a8, + 0x173ba231, 0xd7e42cf0, 0x1110d463, 0xd1cf5aa2, 0xd0a9b83b, + 0x107636fa, 0x93630dd3, 0x53bc8312, 0x52da618b, 0x9205ef4a, + 0x48ba7df1, 0x8865f330, 0x890311a9, 0x49dc9f68, 0xcac9a441, + 0x0a162a80, 0x0b70c819, 0xcbaf46d8, 0x0d5bbe4b, 0xcd84308a, + 0xcce2d213, 0x0c3d5cd2, 0x8f2867fb, 0x4ff7e93a, 0x4e910ba3, + 0x8e4e8562, 0x837e8b5f, 0x43a1059e, 0x42c7e707, 0x821869c6, + 0x010d52ef, 0xc1d2dc2e, 0xc0b43eb7, 0x006bb076, 0xc69f48e5, + 0x0640c624, 0x072624bd, 0xc7f9aa7c, 0x44ec9155, 0x84331f94, + 0x8555fd0d, 0x458a73cc, 0x702ca9a1, 0xb0f32760, 0xb195c5f9, + 0x714a4b38, 0xf25f7011, 0x3280fed0, 0x33e61c49, 0xf3399288, + 0x35cd6a1b, 0xf512e4da, 0xf4740643, 0x34ab8882, 0xb7beb3ab, + 0x77613d6a, 0x7607dff3, 0xb6d85132, 0xbbe85f0f, 0x7b37d1ce, + 0x7a513357, 0xba8ebd96, 0x399b86bf, 0xf944087e, 0xf822eae7, + 0x38fd6426, 0xfe099cb5, 0x3ed61274, 0x3fb0f0ed, 0xff6f7e2c, + 0x7c7a4505, 0xbca5cbc4, 0xbdc3295d, 0x7d1ca79c, 0xa7a33527, + 0x677cbbe6, 0x661a597f, 0xa6c5d7be, 0x25d0ec97, 0xe50f6256, + 0xe46980cf, 0x24b60e0e, 0xe242f69d, 0x229d785c, 0x23fb9ac5, + 0xe3241404, 0x60312f2d, 0xa0eea1ec, 0xa1884375, 0x6157cdb4, + 0x6c67c389, 0xacb84d48, 0xaddeafd1, 0x6d012110, 0xee141a39, + 0x2ecb94f8, 0x2fad7661, 0xef72f8a0, 0x29860033, 0xe9598ef2, + 0xe83f6c6b, 0x28e0e2aa, 0xabf5d983, 0x6b2a5742, 0x6a4cb5db, + 0xaa933b1a}, + {0x00000000, 0x6f4ca59b, 0x9f9e3bec, 0xf0d29e77, 0x7f3b0603, + 0x1077a398, 0xe0a53def, 0x8fe99874, 0xfe760c06, 0x913aa99d, + 0x61e837ea, 0x0ea49271, 0x814d0a05, 0xee01af9e, 0x1ed331e9, + 0x719f9472, 0xfced180c, 0x93a1bd97, 0x637323e0, 0x0c3f867b, + 0x83d61e0f, 0xec9abb94, 0x1c4825e3, 0x73048078, 0x029b140a, + 0x6dd7b191, 0x9d052fe6, 0xf2498a7d, 0x7da01209, 0x12ecb792, + 0xe23e29e5, 0x8d728c7e, 0xf8db3118, 0x97979483, 0x67450af4, + 0x0809af6f, 0x87e0371b, 0xe8ac9280, 0x187e0cf7, 0x7732a96c, + 0x06ad3d1e, 0x69e19885, 0x993306f2, 0xf67fa369, 0x79963b1d, + 0x16da9e86, 0xe60800f1, 0x8944a56a, 0x04362914, 0x6b7a8c8f, + 0x9ba812f8, 0xf4e4b763, 0x7b0d2f17, 0x14418a8c, 0xe49314fb, + 0x8bdfb160, 0xfa402512, 0x950c8089, 0x65de1efe, 0x0a92bb65, + 0x857b2311, 0xea37868a, 0x1ae518fd, 0x75a9bd66, 0xf0b76330, + 0x9ffbc6ab, 0x6f2958dc, 0x0065fd47, 0x8f8c6533, 0xe0c0c0a8, + 0x10125edf, 0x7f5efb44, 0x0ec16f36, 0x618dcaad, 0x915f54da, + 0xfe13f141, 0x71fa6935, 0x1eb6ccae, 0xee6452d9, 0x8128f742, + 0x0c5a7b3c, 0x6316dea7, 0x93c440d0, 0xfc88e54b, 0x73617d3f, + 0x1c2dd8a4, 0xecff46d3, 0x83b3e348, 0xf22c773a, 0x9d60d2a1, + 0x6db24cd6, 0x02fee94d, 0x8d177139, 0xe25bd4a2, 0x12894ad5, + 0x7dc5ef4e, 0x086c5228, 0x6720f7b3, 0x97f269c4, 0xf8becc5f, + 0x7757542b, 0x181bf1b0, 0xe8c96fc7, 0x8785ca5c, 0xf61a5e2e, + 0x9956fbb5, 0x698465c2, 0x06c8c059, 0x8921582d, 0xe66dfdb6, + 0x16bf63c1, 0x79f3c65a, 0xf4814a24, 0x9bcdefbf, 0x6b1f71c8, + 0x0453d453, 0x8bba4c27, 0xe4f6e9bc, 0x142477cb, 0x7b68d250, + 0x0af74622, 0x65bbe3b9, 0x95697dce, 0xfa25d855, 0x75cc4021, + 0x1a80e5ba, 0xea527bcd, 0x851ede56, 0xe06fc760, 0x8f2362fb, + 0x7ff1fc8c, 0x10bd5917, 0x9f54c163, 0xf01864f8, 0x00cafa8f, + 0x6f865f14, 0x1e19cb66, 0x71556efd, 0x8187f08a, 0xeecb5511, + 0x6122cd65, 0x0e6e68fe, 0xfebcf689, 0x91f05312, 0x1c82df6c, + 0x73ce7af7, 0x831ce480, 0xec50411b, 0x63b9d96f, 0x0cf57cf4, + 0xfc27e283, 0x936b4718, 0xe2f4d36a, 0x8db876f1, 0x7d6ae886, + 0x12264d1d, 0x9dcfd569, 0xf28370f2, 0x0251ee85, 0x6d1d4b1e, + 0x18b4f678, 0x77f853e3, 0x872acd94, 0xe866680f, 0x678ff07b, + 0x08c355e0, 0xf811cb97, 0x975d6e0c, 0xe6c2fa7e, 0x898e5fe5, + 0x795cc192, 0x16106409, 0x99f9fc7d, 0xf6b559e6, 0x0667c791, + 0x692b620a, 0xe459ee74, 0x8b154bef, 0x7bc7d598, 0x148b7003, + 0x9b62e877, 0xf42e4dec, 0x04fcd39b, 0x6bb07600, 0x1a2fe272, + 0x756347e9, 0x85b1d99e, 0xeafd7c05, 0x6514e471, 0x0a5841ea, + 0xfa8adf9d, 0x95c67a06, 0x10d8a450, 0x7f9401cb, 0x8f469fbc, + 0xe00a3a27, 0x6fe3a253, 0x00af07c8, 0xf07d99bf, 0x9f313c24, + 0xeeaea856, 0x81e20dcd, 0x713093ba, 0x1e7c3621, 0x9195ae55, + 0xfed90bce, 0x0e0b95b9, 0x61473022, 0xec35bc5c, 0x837919c7, + 0x73ab87b0, 0x1ce7222b, 0x930eba5f, 0xfc421fc4, 0x0c9081b3, + 0x63dc2428, 0x1243b05a, 0x7d0f15c1, 0x8ddd8bb6, 0xe2912e2d, + 0x6d78b659, 0x023413c2, 0xf2e68db5, 0x9daa282e, 0xe8039548, + 0x874f30d3, 0x779daea4, 0x18d10b3f, 0x9738934b, 0xf87436d0, + 0x08a6a8a7, 0x67ea0d3c, 0x1675994e, 0x79393cd5, 0x89eba2a2, + 0xe6a70739, 0x694e9f4d, 0x06023ad6, 0xf6d0a4a1, 0x999c013a, + 0x14ee8d44, 0x7ba228df, 0x8b70b6a8, 0xe43c1333, 0x6bd58b47, + 0x04992edc, 0xf44bb0ab, 0x9b071530, 0xea988142, 0x85d424d9, + 0x7506baae, 0x1a4a1f35, 0x95a38741, 0xfaef22da, 0x0a3dbcad, + 0x65711936}}; + +#endif + +#endif + +#if N == 4 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xf1da05aa, 0x38c50d15, 0xc91f08bf, 0x718a1a2a, + 0x80501f80, 0x494f173f, 0xb8951295, 0xe3143454, 0x12ce31fe, + 0xdbd13941, 0x2a0b3ceb, 0x929e2e7e, 0x63442bd4, 0xaa5b236b, + 0x5b8126c1, 0x1d596ee9, 0xec836b43, 0x259c63fc, 0xd4466656, + 0x6cd374c3, 0x9d097169, 0x541679d6, 0xa5cc7c7c, 0xfe4d5abd, + 0x0f975f17, 0xc68857a8, 0x37525202, 0x8fc74097, 0x7e1d453d, + 0xb7024d82, 0x46d84828, 0x3ab2ddd2, 0xcb68d878, 0x0277d0c7, + 0xf3add56d, 0x4b38c7f8, 0xbae2c252, 0x73fdcaed, 0x8227cf47, + 0xd9a6e986, 0x287cec2c, 0xe163e493, 0x10b9e139, 0xa82cf3ac, + 0x59f6f606, 0x90e9feb9, 0x6133fb13, 0x27ebb33b, 0xd631b691, + 0x1f2ebe2e, 0xeef4bb84, 0x5661a911, 0xa7bbacbb, 0x6ea4a404, + 0x9f7ea1ae, 0xc4ff876f, 0x352582c5, 0xfc3a8a7a, 0x0de08fd0, + 0xb5759d45, 0x44af98ef, 0x8db09050, 0x7c6a95fa, 0x7565bba4, + 0x84bfbe0e, 0x4da0b6b1, 0xbc7ab31b, 0x04efa18e, 0xf535a424, + 0x3c2aac9b, 0xcdf0a931, 0x96718ff0, 0x67ab8a5a, 0xaeb482e5, + 0x5f6e874f, 0xe7fb95da, 0x16219070, 0xdf3e98cf, 0x2ee49d65, + 0x683cd54d, 0x99e6d0e7, 0x50f9d858, 0xa123ddf2, 0x19b6cf67, + 0xe86ccacd, 0x2173c272, 0xd0a9c7d8, 0x8b28e119, 0x7af2e4b3, + 0xb3edec0c, 0x4237e9a6, 0xfaa2fb33, 0x0b78fe99, 0xc267f626, + 0x33bdf38c, 0x4fd76676, 0xbe0d63dc, 0x77126b63, 0x86c86ec9, + 0x3e5d7c5c, 0xcf8779f6, 0x06987149, 0xf74274e3, 0xacc35222, + 0x5d195788, 0x94065f37, 0x65dc5a9d, 0xdd494808, 0x2c934da2, + 0xe58c451d, 0x145640b7, 0x528e089f, 0xa3540d35, 0x6a4b058a, + 0x9b910020, 0x230412b5, 0xd2de171f, 0x1bc11fa0, 0xea1b1a0a, + 0xb19a3ccb, 0x40403961, 0x895f31de, 0x78853474, 0xc01026e1, + 0x31ca234b, 0xf8d52bf4, 0x090f2e5e, 0xeacb7748, 0x1b1172e2, + 0xd20e7a5d, 0x23d47ff7, 0x9b416d62, 0x6a9b68c8, 0xa3846077, + 0x525e65dd, 0x09df431c, 0xf80546b6, 0x311a4e09, 0xc0c04ba3, + 0x78555936, 0x898f5c9c, 0x40905423, 0xb14a5189, 0xf79219a1, + 0x06481c0b, 0xcf5714b4, 0x3e8d111e, 0x8618038b, 0x77c20621, + 0xbedd0e9e, 0x4f070b34, 0x14862df5, 0xe55c285f, 0x2c4320e0, + 0xdd99254a, 0x650c37df, 0x94d63275, 0x5dc93aca, 0xac133f60, + 0xd079aa9a, 0x21a3af30, 0xe8bca78f, 0x1966a225, 0xa1f3b0b0, + 0x5029b51a, 0x9936bda5, 0x68ecb80f, 0x336d9ece, 0xc2b79b64, + 0x0ba893db, 0xfa729671, 0x42e784e4, 0xb33d814e, 0x7a2289f1, + 0x8bf88c5b, 0xcd20c473, 0x3cfac1d9, 0xf5e5c966, 0x043fcccc, + 0xbcaade59, 0x4d70dbf3, 0x846fd34c, 0x75b5d6e6, 0x2e34f027, + 0xdfeef58d, 0x16f1fd32, 0xe72bf898, 0x5fbeea0d, 0xae64efa7, + 0x677be718, 0x96a1e2b2, 0x9faeccec, 0x6e74c946, 0xa76bc1f9, + 0x56b1c453, 0xee24d6c6, 0x1ffed36c, 0xd6e1dbd3, 0x273bde79, + 0x7cbaf8b8, 0x8d60fd12, 0x447ff5ad, 0xb5a5f007, 0x0d30e292, + 0xfceae738, 0x35f5ef87, 0xc42fea2d, 0x82f7a205, 0x732da7af, + 0xba32af10, 0x4be8aaba, 0xf37db82f, 0x02a7bd85, 0xcbb8b53a, + 0x3a62b090, 0x61e39651, 0x903993fb, 0x59269b44, 0xa8fc9eee, + 0x10698c7b, 0xe1b389d1, 0x28ac816e, 0xd97684c4, 0xa51c113e, + 0x54c61494, 0x9dd91c2b, 0x6c031981, 0xd4960b14, 0x254c0ebe, + 0xec530601, 0x1d8903ab, 0x4608256a, 0xb7d220c0, 0x7ecd287f, + 0x8f172dd5, 0x37823f40, 0xc6583aea, 0x0f473255, 0xfe9d37ff, + 0xb8457fd7, 0x499f7a7d, 0x808072c2, 0x715a7768, 0xc9cf65fd, + 0x38156057, 0xf10a68e8, 0x00d06d42, 0x5b514b83, 0xaa8b4e29, + 0x63944696, 0x924e433c, 0x2adb51a9, 0xdb015403, 0x121e5cbc, + 0xe3c45916}, + {0x00000000, 0x0ee7e8d1, 0x1dcfd1a2, 0x13283973, 0x3b9fa344, + 0x35784b95, 0x265072e6, 0x28b79a37, 0x773f4688, 0x79d8ae59, + 0x6af0972a, 0x64177ffb, 0x4ca0e5cc, 0x42470d1d, 0x516f346e, + 0x5f88dcbf, 0xee7e8d10, 0xe09965c1, 0xf3b15cb2, 0xfd56b463, + 0xd5e12e54, 0xdb06c685, 0xc82efff6, 0xc6c91727, 0x9941cb98, + 0x97a62349, 0x848e1a3a, 0x8a69f2eb, 0xa2de68dc, 0xac39800d, + 0xbf11b97e, 0xb1f651af, 0x078c1c61, 0x096bf4b0, 0x1a43cdc3, + 0x14a42512, 0x3c13bf25, 0x32f457f4, 0x21dc6e87, 0x2f3b8656, + 0x70b35ae9, 0x7e54b238, 0x6d7c8b4b, 0x639b639a, 0x4b2cf9ad, + 0x45cb117c, 0x56e3280f, 0x5804c0de, 0xe9f29171, 0xe71579a0, + 0xf43d40d3, 0xfadaa802, 0xd26d3235, 0xdc8adae4, 0xcfa2e397, + 0xc1450b46, 0x9ecdd7f9, 0x902a3f28, 0x8302065b, 0x8de5ee8a, + 0xa55274bd, 0xabb59c6c, 0xb89da51f, 0xb67a4dce, 0x0f1838c2, + 0x01ffd013, 0x12d7e960, 0x1c3001b1, 0x34879b86, 0x3a607357, + 0x29484a24, 0x27afa2f5, 0x78277e4a, 0x76c0969b, 0x65e8afe8, + 0x6b0f4739, 0x43b8dd0e, 0x4d5f35df, 0x5e770cac, 0x5090e47d, + 0xe166b5d2, 0xef815d03, 0xfca96470, 0xf24e8ca1, 0xdaf91696, + 0xd41efe47, 0xc736c734, 0xc9d12fe5, 0x9659f35a, 0x98be1b8b, + 0x8b9622f8, 0x8571ca29, 0xadc6501e, 0xa321b8cf, 0xb00981bc, + 0xbeee696d, 0x089424a3, 0x0673cc72, 0x155bf501, 0x1bbc1dd0, + 0x330b87e7, 0x3dec6f36, 0x2ec45645, 0x2023be94, 0x7fab622b, + 0x714c8afa, 0x6264b389, 0x6c835b58, 0x4434c16f, 0x4ad329be, + 0x59fb10cd, 0x571cf81c, 0xe6eaa9b3, 0xe80d4162, 0xfb257811, + 0xf5c290c0, 0xdd750af7, 0xd392e226, 0xc0badb55, 0xce5d3384, + 0x91d5ef3b, 0x9f3207ea, 0x8c1a3e99, 0x82fdd648, 0xaa4a4c7f, + 0xa4ada4ae, 0xb7859ddd, 0xb962750c, 0x1e307184, 0x10d79955, + 0x03ffa026, 0x0d1848f7, 0x25afd2c0, 0x2b483a11, 0x38600362, + 0x3687ebb3, 0x690f370c, 0x67e8dfdd, 0x74c0e6ae, 0x7a270e7f, + 0x52909448, 0x5c777c99, 0x4f5f45ea, 0x41b8ad3b, 0xf04efc94, + 0xfea91445, 0xed812d36, 0xe366c5e7, 0xcbd15fd0, 0xc536b701, + 0xd61e8e72, 0xd8f966a3, 0x8771ba1c, 0x899652cd, 0x9abe6bbe, + 0x9459836f, 0xbcee1958, 0xb209f189, 0xa121c8fa, 0xafc6202b, + 0x19bc6de5, 0x175b8534, 0x0473bc47, 0x0a945496, 0x2223cea1, + 0x2cc42670, 0x3fec1f03, 0x310bf7d2, 0x6e832b6d, 0x6064c3bc, + 0x734cfacf, 0x7dab121e, 0x551c8829, 0x5bfb60f8, 0x48d3598b, + 0x4634b15a, 0xf7c2e0f5, 0xf9250824, 0xea0d3157, 0xe4ead986, + 0xcc5d43b1, 0xc2baab60, 0xd1929213, 0xdf757ac2, 0x80fda67d, + 0x8e1a4eac, 0x9d3277df, 0x93d59f0e, 0xbb620539, 0xb585ede8, + 0xa6add49b, 0xa84a3c4a, 0x11284946, 0x1fcfa197, 0x0ce798e4, + 0x02007035, 0x2ab7ea02, 0x245002d3, 0x37783ba0, 0x399fd371, + 0x66170fce, 0x68f0e71f, 0x7bd8de6c, 0x753f36bd, 0x5d88ac8a, + 0x536f445b, 0x40477d28, 0x4ea095f9, 0xff56c456, 0xf1b12c87, + 0xe29915f4, 0xec7efd25, 0xc4c96712, 0xca2e8fc3, 0xd906b6b0, + 0xd7e15e61, 0x886982de, 0x868e6a0f, 0x95a6537c, 0x9b41bbad, + 0xb3f6219a, 0xbd11c94b, 0xae39f038, 0xa0de18e9, 0x16a45527, + 0x1843bdf6, 0x0b6b8485, 0x058c6c54, 0x2d3bf663, 0x23dc1eb2, + 0x30f427c1, 0x3e13cf10, 0x619b13af, 0x6f7cfb7e, 0x7c54c20d, + 0x72b32adc, 0x5a04b0eb, 0x54e3583a, 0x47cb6149, 0x492c8998, + 0xf8dad837, 0xf63d30e6, 0xe5150995, 0xebf2e144, 0xc3457b73, + 0xcda293a2, 0xde8aaad1, 0xd06d4200, 0x8fe59ebf, 0x8102766e, + 0x922a4f1d, 0x9ccda7cc, 0xb47a3dfb, 0xba9dd52a, 0xa9b5ec59, + 0xa7520488}, + {0x00000000, 0x3c60e308, 0x78c1c610, 0x44a12518, 0xf1838c20, + 0xcde36f28, 0x89424a30, 0xb522a938, 0x38761e01, 0x0416fd09, + 0x40b7d811, 0x7cd73b19, 0xc9f59221, 0xf5957129, 0xb1345431, + 0x8d54b739, 0x70ec3c02, 0x4c8cdf0a, 0x082dfa12, 0x344d191a, + 0x816fb022, 0xbd0f532a, 0xf9ae7632, 0xc5ce953a, 0x489a2203, + 0x74fac10b, 0x305be413, 0x0c3b071b, 0xb919ae23, 0x85794d2b, + 0xc1d86833, 0xfdb88b3b, 0xe1d87804, 0xddb89b0c, 0x9919be14, + 0xa5795d1c, 0x105bf424, 0x2c3b172c, 0x689a3234, 0x54fad13c, + 0xd9ae6605, 0xe5ce850d, 0xa16fa015, 0x9d0f431d, 0x282dea25, + 0x144d092d, 0x50ec2c35, 0x6c8ccf3d, 0x91344406, 0xad54a70e, + 0xe9f58216, 0xd595611e, 0x60b7c826, 0x5cd72b2e, 0x18760e36, + 0x2416ed3e, 0xa9425a07, 0x9522b90f, 0xd1839c17, 0xede37f1f, + 0x58c1d627, 0x64a1352f, 0x20001037, 0x1c60f33f, 0x18c1f649, + 0x24a11541, 0x60003059, 0x5c60d351, 0xe9427a69, 0xd5229961, + 0x9183bc79, 0xade35f71, 0x20b7e848, 0x1cd70b40, 0x58762e58, + 0x6416cd50, 0xd1346468, 0xed548760, 0xa9f5a278, 0x95954170, + 0x682dca4b, 0x544d2943, 0x10ec0c5b, 0x2c8cef53, 0x99ae466b, + 0xa5cea563, 0xe16f807b, 0xdd0f6373, 0x505bd44a, 0x6c3b3742, + 0x289a125a, 0x14faf152, 0xa1d8586a, 0x9db8bb62, 0xd9199e7a, + 0xe5797d72, 0xf9198e4d, 0xc5796d45, 0x81d8485d, 0xbdb8ab55, + 0x089a026d, 0x34fae165, 0x705bc47d, 0x4c3b2775, 0xc16f904c, + 0xfd0f7344, 0xb9ae565c, 0x85ceb554, 0x30ec1c6c, 0x0c8cff64, + 0x482dda7c, 0x744d3974, 0x89f5b24f, 0xb5955147, 0xf134745f, + 0xcd549757, 0x78763e6f, 0x4416dd67, 0x00b7f87f, 0x3cd71b77, + 0xb183ac4e, 0x8de34f46, 0xc9426a5e, 0xf5228956, 0x4000206e, + 0x7c60c366, 0x38c1e67e, 0x04a10576, 0x3183ec92, 0x0de30f9a, + 0x49422a82, 0x7522c98a, 0xc00060b2, 0xfc6083ba, 0xb8c1a6a2, + 0x84a145aa, 0x09f5f293, 0x3595119b, 0x71343483, 0x4d54d78b, + 0xf8767eb3, 0xc4169dbb, 0x80b7b8a3, 0xbcd75bab, 0x416fd090, + 0x7d0f3398, 0x39ae1680, 0x05cef588, 0xb0ec5cb0, 0x8c8cbfb8, + 0xc82d9aa0, 0xf44d79a8, 0x7919ce91, 0x45792d99, 0x01d80881, + 0x3db8eb89, 0x889a42b1, 0xb4faa1b9, 0xf05b84a1, 0xcc3b67a9, + 0xd05b9496, 0xec3b779e, 0xa89a5286, 0x94fab18e, 0x21d818b6, + 0x1db8fbbe, 0x5919dea6, 0x65793dae, 0xe82d8a97, 0xd44d699f, + 0x90ec4c87, 0xac8caf8f, 0x19ae06b7, 0x25cee5bf, 0x616fc0a7, + 0x5d0f23af, 0xa0b7a894, 0x9cd74b9c, 0xd8766e84, 0xe4168d8c, + 0x513424b4, 0x6d54c7bc, 0x29f5e2a4, 0x159501ac, 0x98c1b695, + 0xa4a1559d, 0xe0007085, 0xdc60938d, 0x69423ab5, 0x5522d9bd, + 0x1183fca5, 0x2de31fad, 0x29421adb, 0x1522f9d3, 0x5183dccb, + 0x6de33fc3, 0xd8c196fb, 0xe4a175f3, 0xa00050eb, 0x9c60b3e3, + 0x113404da, 0x2d54e7d2, 0x69f5c2ca, 0x559521c2, 0xe0b788fa, + 0xdcd76bf2, 0x98764eea, 0xa416ade2, 0x59ae26d9, 0x65cec5d1, + 0x216fe0c9, 0x1d0f03c1, 0xa82daaf9, 0x944d49f1, 0xd0ec6ce9, + 0xec8c8fe1, 0x61d838d8, 0x5db8dbd0, 0x1919fec8, 0x25791dc0, + 0x905bb4f8, 0xac3b57f0, 0xe89a72e8, 0xd4fa91e0, 0xc89a62df, + 0xf4fa81d7, 0xb05ba4cf, 0x8c3b47c7, 0x3919eeff, 0x05790df7, + 0x41d828ef, 0x7db8cbe7, 0xf0ec7cde, 0xcc8c9fd6, 0x882dbace, + 0xb44d59c6, 0x016ff0fe, 0x3d0f13f6, 0x79ae36ee, 0x45ced5e6, + 0xb8765edd, 0x8416bdd5, 0xc0b798cd, 0xfcd77bc5, 0x49f5d2fd, + 0x759531f5, 0x313414ed, 0x0d54f7e5, 0x800040dc, 0xbc60a3d4, + 0xf8c186cc, 0xc4a165c4, 0x7183ccfc, 0x4de32ff4, 0x09420aec, + 0x3522e9e4}, + {0x00000000, 0x6307d924, 0xc60fb248, 0xa5086b6c, 0x576e62d1, + 0x3469bbf5, 0x9161d099, 0xf26609bd, 0xaedcc5a2, 0xcddb1c86, + 0x68d377ea, 0x0bd4aece, 0xf9b2a773, 0x9ab57e57, 0x3fbd153b, + 0x5cbacc1f, 0x86c88d05, 0xe5cf5421, 0x40c73f4d, 0x23c0e669, + 0xd1a6efd4, 0xb2a136f0, 0x17a95d9c, 0x74ae84b8, 0x281448a7, + 0x4b139183, 0xee1bfaef, 0x8d1c23cb, 0x7f7a2a76, 0x1c7df352, + 0xb975983e, 0xda72411a, 0xd6e01c4b, 0xb5e7c56f, 0x10efae03, + 0x73e87727, 0x818e7e9a, 0xe289a7be, 0x4781ccd2, 0x248615f6, + 0x783cd9e9, 0x1b3b00cd, 0xbe336ba1, 0xdd34b285, 0x2f52bb38, + 0x4c55621c, 0xe95d0970, 0x8a5ad054, 0x5028914e, 0x332f486a, + 0x96272306, 0xf520fa22, 0x0746f39f, 0x64412abb, 0xc14941d7, + 0xa24e98f3, 0xfef454ec, 0x9df38dc8, 0x38fbe6a4, 0x5bfc3f80, + 0xa99a363d, 0xca9def19, 0x6f958475, 0x0c925d51, 0x76b13ed7, + 0x15b6e7f3, 0xb0be8c9f, 0xd3b955bb, 0x21df5c06, 0x42d88522, + 0xe7d0ee4e, 0x84d7376a, 0xd86dfb75, 0xbb6a2251, 0x1e62493d, + 0x7d659019, 0x8f0399a4, 0xec044080, 0x490c2bec, 0x2a0bf2c8, + 0xf079b3d2, 0x937e6af6, 0x3676019a, 0x5571d8be, 0xa717d103, + 0xc4100827, 0x6118634b, 0x021fba6f, 0x5ea57670, 0x3da2af54, + 0x98aac438, 0xfbad1d1c, 0x09cb14a1, 0x6acccd85, 0xcfc4a6e9, + 0xacc37fcd, 0xa051229c, 0xc356fbb8, 0x665e90d4, 0x055949f0, + 0xf73f404d, 0x94389969, 0x3130f205, 0x52372b21, 0x0e8de73e, + 0x6d8a3e1a, 0xc8825576, 0xab858c52, 0x59e385ef, 0x3ae45ccb, + 0x9fec37a7, 0xfcebee83, 0x2699af99, 0x459e76bd, 0xe0961dd1, + 0x8391c4f5, 0x71f7cd48, 0x12f0146c, 0xb7f87f00, 0xd4ffa624, + 0x88456a3b, 0xeb42b31f, 0x4e4ad873, 0x2d4d0157, 0xdf2b08ea, + 0xbc2cd1ce, 0x1924baa2, 0x7a236386, 0xed627dae, 0x8e65a48a, + 0x2b6dcfe6, 0x486a16c2, 0xba0c1f7f, 0xd90bc65b, 0x7c03ad37, + 0x1f047413, 0x43beb80c, 0x20b96128, 0x85b10a44, 0xe6b6d360, + 0x14d0dadd, 0x77d703f9, 0xd2df6895, 0xb1d8b1b1, 0x6baaf0ab, + 0x08ad298f, 0xada542e3, 0xcea29bc7, 0x3cc4927a, 0x5fc34b5e, + 0xfacb2032, 0x99ccf916, 0xc5763509, 0xa671ec2d, 0x03798741, + 0x607e5e65, 0x921857d8, 0xf11f8efc, 0x5417e590, 0x37103cb4, + 0x3b8261e5, 0x5885b8c1, 0xfd8dd3ad, 0x9e8a0a89, 0x6cec0334, + 0x0febda10, 0xaae3b17c, 0xc9e46858, 0x955ea447, 0xf6597d63, + 0x5351160f, 0x3056cf2b, 0xc230c696, 0xa1371fb2, 0x043f74de, + 0x6738adfa, 0xbd4aece0, 0xde4d35c4, 0x7b455ea8, 0x1842878c, + 0xea248e31, 0x89235715, 0x2c2b3c79, 0x4f2ce55d, 0x13962942, + 0x7091f066, 0xd5999b0a, 0xb69e422e, 0x44f84b93, 0x27ff92b7, + 0x82f7f9db, 0xe1f020ff, 0x9bd34379, 0xf8d49a5d, 0x5ddcf131, + 0x3edb2815, 0xccbd21a8, 0xafbaf88c, 0x0ab293e0, 0x69b54ac4, + 0x350f86db, 0x56085fff, 0xf3003493, 0x9007edb7, 0x6261e40a, + 0x01663d2e, 0xa46e5642, 0xc7698f66, 0x1d1bce7c, 0x7e1c1758, + 0xdb147c34, 0xb813a510, 0x4a75acad, 0x29727589, 0x8c7a1ee5, + 0xef7dc7c1, 0xb3c70bde, 0xd0c0d2fa, 0x75c8b996, 0x16cf60b2, + 0xe4a9690f, 0x87aeb02b, 0x22a6db47, 0x41a10263, 0x4d335f32, + 0x2e348616, 0x8b3ced7a, 0xe83b345e, 0x1a5d3de3, 0x795ae4c7, + 0xdc528fab, 0xbf55568f, 0xe3ef9a90, 0x80e843b4, 0x25e028d8, + 0x46e7f1fc, 0xb481f841, 0xd7862165, 0x728e4a09, 0x1189932d, + 0xcbfbd237, 0xa8fc0b13, 0x0df4607f, 0x6ef3b95b, 0x9c95b0e6, + 0xff9269c2, 0x5a9a02ae, 0x399ddb8a, 0x65271795, 0x0620ceb1, + 0xa328a5dd, 0xc02f7cf9, 0x32497544, 0x514eac60, 0xf446c70c, + 0x97411e28}, + {0x00000000, 0x01b5fd1d, 0x036bfa3a, 0x02de0727, 0x06d7f474, + 0x07620969, 0x05bc0e4e, 0x0409f353, 0x0dafe8e8, 0x0c1a15f5, + 0x0ec412d2, 0x0f71efcf, 0x0b781c9c, 0x0acde181, 0x0813e6a6, + 0x09a61bbb, 0x1b5fd1d0, 0x1aea2ccd, 0x18342bea, 0x1981d6f7, + 0x1d8825a4, 0x1c3dd8b9, 0x1ee3df9e, 0x1f562283, 0x16f03938, + 0x1745c425, 0x159bc302, 0x142e3e1f, 0x1027cd4c, 0x11923051, + 0x134c3776, 0x12f9ca6b, 0x36bfa3a0, 0x370a5ebd, 0x35d4599a, + 0x3461a487, 0x306857d4, 0x31ddaac9, 0x3303adee, 0x32b650f3, + 0x3b104b48, 0x3aa5b655, 0x387bb172, 0x39ce4c6f, 0x3dc7bf3c, + 0x3c724221, 0x3eac4506, 0x3f19b81b, 0x2de07270, 0x2c558f6d, + 0x2e8b884a, 0x2f3e7557, 0x2b378604, 0x2a827b19, 0x285c7c3e, + 0x29e98123, 0x204f9a98, 0x21fa6785, 0x232460a2, 0x22919dbf, + 0x26986eec, 0x272d93f1, 0x25f394d6, 0x244669cb, 0x6d7f4740, + 0x6ccaba5d, 0x6e14bd7a, 0x6fa14067, 0x6ba8b334, 0x6a1d4e29, + 0x68c3490e, 0x6976b413, 0x60d0afa8, 0x616552b5, 0x63bb5592, + 0x620ea88f, 0x66075bdc, 0x67b2a6c1, 0x656ca1e6, 0x64d95cfb, + 0x76209690, 0x77956b8d, 0x754b6caa, 0x74fe91b7, 0x70f762e4, + 0x71429ff9, 0x739c98de, 0x722965c3, 0x7b8f7e78, 0x7a3a8365, + 0x78e48442, 0x7951795f, 0x7d588a0c, 0x7ced7711, 0x7e337036, + 0x7f868d2b, 0x5bc0e4e0, 0x5a7519fd, 0x58ab1eda, 0x591ee3c7, + 0x5d171094, 0x5ca2ed89, 0x5e7ceaae, 0x5fc917b3, 0x566f0c08, + 0x57daf115, 0x5504f632, 0x54b10b2f, 0x50b8f87c, 0x510d0561, + 0x53d30246, 0x5266ff5b, 0x409f3530, 0x412ac82d, 0x43f4cf0a, + 0x42413217, 0x4648c144, 0x47fd3c59, 0x45233b7e, 0x4496c663, + 0x4d30ddd8, 0x4c8520c5, 0x4e5b27e2, 0x4feedaff, 0x4be729ac, + 0x4a52d4b1, 0x488cd396, 0x49392e8b, 0xdafe8e80, 0xdb4b739d, + 0xd99574ba, 0xd82089a7, 0xdc297af4, 0xdd9c87e9, 0xdf4280ce, + 0xdef77dd3, 0xd7516668, 0xd6e49b75, 0xd43a9c52, 0xd58f614f, + 0xd186921c, 0xd0336f01, 0xd2ed6826, 0xd358953b, 0xc1a15f50, + 0xc014a24d, 0xc2caa56a, 0xc37f5877, 0xc776ab24, 0xc6c35639, + 0xc41d511e, 0xc5a8ac03, 0xcc0eb7b8, 0xcdbb4aa5, 0xcf654d82, + 0xced0b09f, 0xcad943cc, 0xcb6cbed1, 0xc9b2b9f6, 0xc80744eb, + 0xec412d20, 0xedf4d03d, 0xef2ad71a, 0xee9f2a07, 0xea96d954, + 0xeb232449, 0xe9fd236e, 0xe848de73, 0xe1eec5c8, 0xe05b38d5, + 0xe2853ff2, 0xe330c2ef, 0xe73931bc, 0xe68ccca1, 0xe452cb86, + 0xe5e7369b, 0xf71efcf0, 0xf6ab01ed, 0xf47506ca, 0xf5c0fbd7, + 0xf1c90884, 0xf07cf599, 0xf2a2f2be, 0xf3170fa3, 0xfab11418, + 0xfb04e905, 0xf9daee22, 0xf86f133f, 0xfc66e06c, 0xfdd31d71, + 0xff0d1a56, 0xfeb8e74b, 0xb781c9c0, 0xb63434dd, 0xb4ea33fa, + 0xb55fcee7, 0xb1563db4, 0xb0e3c0a9, 0xb23dc78e, 0xb3883a93, + 0xba2e2128, 0xbb9bdc35, 0xb945db12, 0xb8f0260f, 0xbcf9d55c, + 0xbd4c2841, 0xbf922f66, 0xbe27d27b, 0xacde1810, 0xad6be50d, + 0xafb5e22a, 0xae001f37, 0xaa09ec64, 0xabbc1179, 0xa962165e, + 0xa8d7eb43, 0xa171f0f8, 0xa0c40de5, 0xa21a0ac2, 0xa3aff7df, + 0xa7a6048c, 0xa613f991, 0xa4cdfeb6, 0xa57803ab, 0x813e6a60, + 0x808b977d, 0x8255905a, 0x83e06d47, 0x87e99e14, 0x865c6309, + 0x8482642e, 0x85379933, 0x8c918288, 0x8d247f95, 0x8ffa78b2, + 0x8e4f85af, 0x8a4676fc, 0x8bf38be1, 0x892d8cc6, 0x889871db, + 0x9a61bbb0, 0x9bd446ad, 0x990a418a, 0x98bfbc97, 0x9cb64fc4, + 0x9d03b2d9, 0x9fddb5fe, 0x9e6848e3, 0x97ce5358, 0x967bae45, + 0x94a5a962, 0x9510547f, 0x9119a72c, 0x90ac5a31, 0x92725d16, + 0x93c7a00b}, + {0x00000000, 0x6e8c1b41, 0xdd183682, 0xb3942dc3, 0x61416b45, + 0x0fcd7004, 0xbc595dc7, 0xd2d54686, 0xc282d68a, 0xac0ecdcb, + 0x1f9ae008, 0x7116fb49, 0xa3c3bdcf, 0xcd4fa68e, 0x7edb8b4d, + 0x1057900c, 0x5e74ab55, 0x30f8b014, 0x836c9dd7, 0xede08696, + 0x3f35c010, 0x51b9db51, 0xe22df692, 0x8ca1edd3, 0x9cf67ddf, + 0xf27a669e, 0x41ee4b5d, 0x2f62501c, 0xfdb7169a, 0x933b0ddb, + 0x20af2018, 0x4e233b59, 0xbce956aa, 0xd2654deb, 0x61f16028, + 0x0f7d7b69, 0xdda83def, 0xb32426ae, 0x00b00b6d, 0x6e3c102c, + 0x7e6b8020, 0x10e79b61, 0xa373b6a2, 0xcdffade3, 0x1f2aeb65, + 0x71a6f024, 0xc232dde7, 0xacbec6a6, 0xe29dfdff, 0x8c11e6be, + 0x3f85cb7d, 0x5109d03c, 0x83dc96ba, 0xed508dfb, 0x5ec4a038, + 0x3048bb79, 0x201f2b75, 0x4e933034, 0xfd071df7, 0x938b06b6, + 0x415e4030, 0x2fd25b71, 0x9c4676b2, 0xf2ca6df3, 0xa2a3ab15, + 0xcc2fb054, 0x7fbb9d97, 0x113786d6, 0xc3e2c050, 0xad6edb11, + 0x1efaf6d2, 0x7076ed93, 0x60217d9f, 0x0ead66de, 0xbd394b1d, + 0xd3b5505c, 0x016016da, 0x6fec0d9b, 0xdc782058, 0xb2f43b19, + 0xfcd70040, 0x925b1b01, 0x21cf36c2, 0x4f432d83, 0x9d966b05, + 0xf31a7044, 0x408e5d87, 0x2e0246c6, 0x3e55d6ca, 0x50d9cd8b, + 0xe34de048, 0x8dc1fb09, 0x5f14bd8f, 0x3198a6ce, 0x820c8b0d, + 0xec80904c, 0x1e4afdbf, 0x70c6e6fe, 0xc352cb3d, 0xadded07c, + 0x7f0b96fa, 0x11878dbb, 0xa213a078, 0xcc9fbb39, 0xdcc82b35, + 0xb2443074, 0x01d01db7, 0x6f5c06f6, 0xbd894070, 0xd3055b31, + 0x609176f2, 0x0e1d6db3, 0x403e56ea, 0x2eb24dab, 0x9d266068, + 0xf3aa7b29, 0x217f3daf, 0x4ff326ee, 0xfc670b2d, 0x92eb106c, + 0x82bc8060, 0xec309b21, 0x5fa4b6e2, 0x3128ada3, 0xe3fdeb25, + 0x8d71f064, 0x3ee5dda7, 0x5069c6e6, 0x9e36506b, 0xf0ba4b2a, + 0x432e66e9, 0x2da27da8, 0xff773b2e, 0x91fb206f, 0x226f0dac, + 0x4ce316ed, 0x5cb486e1, 0x32389da0, 0x81acb063, 0xef20ab22, + 0x3df5eda4, 0x5379f6e5, 0xe0eddb26, 0x8e61c067, 0xc042fb3e, + 0xaecee07f, 0x1d5acdbc, 0x73d6d6fd, 0xa103907b, 0xcf8f8b3a, + 0x7c1ba6f9, 0x1297bdb8, 0x02c02db4, 0x6c4c36f5, 0xdfd81b36, + 0xb1540077, 0x638146f1, 0x0d0d5db0, 0xbe997073, 0xd0156b32, + 0x22df06c1, 0x4c531d80, 0xffc73043, 0x914b2b02, 0x439e6d84, + 0x2d1276c5, 0x9e865b06, 0xf00a4047, 0xe05dd04b, 0x8ed1cb0a, + 0x3d45e6c9, 0x53c9fd88, 0x811cbb0e, 0xef90a04f, 0x5c048d8c, + 0x328896cd, 0x7cabad94, 0x1227b6d5, 0xa1b39b16, 0xcf3f8057, + 0x1deac6d1, 0x7366dd90, 0xc0f2f053, 0xae7eeb12, 0xbe297b1e, + 0xd0a5605f, 0x63314d9c, 0x0dbd56dd, 0xdf68105b, 0xb1e40b1a, + 0x027026d9, 0x6cfc3d98, 0x3c95fb7e, 0x5219e03f, 0xe18dcdfc, + 0x8f01d6bd, 0x5dd4903b, 0x33588b7a, 0x80cca6b9, 0xee40bdf8, + 0xfe172df4, 0x909b36b5, 0x230f1b76, 0x4d830037, 0x9f5646b1, + 0xf1da5df0, 0x424e7033, 0x2cc26b72, 0x62e1502b, 0x0c6d4b6a, + 0xbff966a9, 0xd1757de8, 0x03a03b6e, 0x6d2c202f, 0xdeb80dec, + 0xb03416ad, 0xa06386a1, 0xceef9de0, 0x7d7bb023, 0x13f7ab62, + 0xc122ede4, 0xafaef6a5, 0x1c3adb66, 0x72b6c027, 0x807cadd4, + 0xeef0b695, 0x5d649b56, 0x33e88017, 0xe13dc691, 0x8fb1ddd0, + 0x3c25f013, 0x52a9eb52, 0x42fe7b5e, 0x2c72601f, 0x9fe64ddc, + 0xf16a569d, 0x23bf101b, 0x4d330b5a, 0xfea72699, 0x902b3dd8, + 0xde080681, 0xb0841dc0, 0x03103003, 0x6d9c2b42, 0xbf496dc4, + 0xd1c57685, 0x62515b46, 0x0cdd4007, 0x1c8ad00b, 0x7206cb4a, + 0xc192e689, 0xaf1efdc8, 0x7dcbbb4e, 0x1347a00f, 0xa0d38dcc, + 0xce5f968d}, + {0x00000000, 0xe71da697, 0x154a4b6f, 0xf257edf8, 0x2a9496de, + 0xcd893049, 0x3fdeddb1, 0xd8c37b26, 0x55292dbc, 0xb2348b2b, + 0x406366d3, 0xa77ec044, 0x7fbdbb62, 0x98a01df5, 0x6af7f00d, + 0x8dea569a, 0xaa525b78, 0x4d4ffdef, 0xbf181017, 0x5805b680, + 0x80c6cda6, 0x67db6b31, 0x958c86c9, 0x7291205e, 0xff7b76c4, + 0x1866d053, 0xea313dab, 0x0d2c9b3c, 0xd5efe01a, 0x32f2468d, + 0xc0a5ab75, 0x27b80de2, 0x8fd5b0b1, 0x68c81626, 0x9a9ffbde, + 0x7d825d49, 0xa541266f, 0x425c80f8, 0xb00b6d00, 0x5716cb97, + 0xdafc9d0d, 0x3de13b9a, 0xcfb6d662, 0x28ab70f5, 0xf0680bd3, + 0x1775ad44, 0xe52240bc, 0x023fe62b, 0x2587ebc9, 0xc29a4d5e, + 0x30cda0a6, 0xd7d00631, 0x0f137d17, 0xe80edb80, 0x1a593678, + 0xfd4490ef, 0x70aec675, 0x97b360e2, 0x65e48d1a, 0x82f92b8d, + 0x5a3a50ab, 0xbd27f63c, 0x4f701bc4, 0xa86dbd53, 0xc4da6723, + 0x23c7c1b4, 0xd1902c4c, 0x368d8adb, 0xee4ef1fd, 0x0953576a, + 0xfb04ba92, 0x1c191c05, 0x91f34a9f, 0x76eeec08, 0x84b901f0, + 0x63a4a767, 0xbb67dc41, 0x5c7a7ad6, 0xae2d972e, 0x493031b9, + 0x6e883c5b, 0x89959acc, 0x7bc27734, 0x9cdfd1a3, 0x441caa85, + 0xa3010c12, 0x5156e1ea, 0xb64b477d, 0x3ba111e7, 0xdcbcb770, + 0x2eeb5a88, 0xc9f6fc1f, 0x11358739, 0xf62821ae, 0x047fcc56, + 0xe3626ac1, 0x4b0fd792, 0xac127105, 0x5e459cfd, 0xb9583a6a, + 0x619b414c, 0x8686e7db, 0x74d10a23, 0x93ccacb4, 0x1e26fa2e, + 0xf93b5cb9, 0x0b6cb141, 0xec7117d6, 0x34b26cf0, 0xd3afca67, + 0x21f8279f, 0xc6e58108, 0xe15d8cea, 0x06402a7d, 0xf417c785, + 0x130a6112, 0xcbc91a34, 0x2cd4bca3, 0xde83515b, 0x399ef7cc, + 0xb474a156, 0x536907c1, 0xa13eea39, 0x46234cae, 0x9ee03788, + 0x79fd911f, 0x8baa7ce7, 0x6cb7da70, 0x52c5c807, 0xb5d86e90, + 0x478f8368, 0xa09225ff, 0x78515ed9, 0x9f4cf84e, 0x6d1b15b6, + 0x8a06b321, 0x07ece5bb, 0xe0f1432c, 0x12a6aed4, 0xf5bb0843, + 0x2d787365, 0xca65d5f2, 0x3832380a, 0xdf2f9e9d, 0xf897937f, + 0x1f8a35e8, 0xedddd810, 0x0ac07e87, 0xd20305a1, 0x351ea336, + 0xc7494ece, 0x2054e859, 0xadbebec3, 0x4aa31854, 0xb8f4f5ac, + 0x5fe9533b, 0x872a281d, 0x60378e8a, 0x92606372, 0x757dc5e5, + 0xdd1078b6, 0x3a0dde21, 0xc85a33d9, 0x2f47954e, 0xf784ee68, + 0x109948ff, 0xe2cea507, 0x05d30390, 0x8839550a, 0x6f24f39d, + 0x9d731e65, 0x7a6eb8f2, 0xa2adc3d4, 0x45b06543, 0xb7e788bb, + 0x50fa2e2c, 0x774223ce, 0x905f8559, 0x620868a1, 0x8515ce36, + 0x5dd6b510, 0xbacb1387, 0x489cfe7f, 0xaf8158e8, 0x226b0e72, + 0xc576a8e5, 0x3721451d, 0xd03ce38a, 0x08ff98ac, 0xefe23e3b, + 0x1db5d3c3, 0xfaa87554, 0x961faf24, 0x710209b3, 0x8355e44b, + 0x644842dc, 0xbc8b39fa, 0x5b969f6d, 0xa9c17295, 0x4edcd402, + 0xc3368298, 0x242b240f, 0xd67cc9f7, 0x31616f60, 0xe9a21446, + 0x0ebfb2d1, 0xfce85f29, 0x1bf5f9be, 0x3c4df45c, 0xdb5052cb, + 0x2907bf33, 0xce1a19a4, 0x16d96282, 0xf1c4c415, 0x039329ed, + 0xe48e8f7a, 0x6964d9e0, 0x8e797f77, 0x7c2e928f, 0x9b333418, + 0x43f04f3e, 0xa4ede9a9, 0x56ba0451, 0xb1a7a2c6, 0x19ca1f95, + 0xfed7b902, 0x0c8054fa, 0xeb9df26d, 0x335e894b, 0xd4432fdc, + 0x2614c224, 0xc10964b3, 0x4ce33229, 0xabfe94be, 0x59a97946, + 0xbeb4dfd1, 0x6677a4f7, 0x816a0260, 0x733def98, 0x9420490f, + 0xb39844ed, 0x5485e27a, 0xa6d20f82, 0x41cfa915, 0x990cd233, + 0x7e1174a4, 0x8c46995c, 0x6b5b3fcb, 0xe6b16951, 0x01accfc6, + 0xf3fb223e, 0x14e684a9, 0xcc25ff8f, 0x2b385918, 0xd96fb4e0, + 0x3e721277}, + {0x00000000, 0xa58b900e, 0x9066265d, 0x35edb653, 0xfbbd4afb, + 0x5e36daf5, 0x6bdb6ca6, 0xce50fca8, 0x2c0b93b7, 0x898003b9, + 0xbc6db5ea, 0x19e625e4, 0xd7b6d94c, 0x723d4942, 0x47d0ff11, + 0xe25b6f1f, 0x5817276e, 0xfd9cb760, 0xc8710133, 0x6dfa913d, + 0xa3aa6d95, 0x0621fd9b, 0x33cc4bc8, 0x9647dbc6, 0x741cb4d9, + 0xd19724d7, 0xe47a9284, 0x41f1028a, 0x8fa1fe22, 0x2a2a6e2c, + 0x1fc7d87f, 0xba4c4871, 0xb02e4edc, 0x15a5ded2, 0x20486881, + 0x85c3f88f, 0x4b930427, 0xee189429, 0xdbf5227a, 0x7e7eb274, + 0x9c25dd6b, 0x39ae4d65, 0x0c43fb36, 0xa9c86b38, 0x67989790, + 0xc213079e, 0xf7feb1cd, 0x527521c3, 0xe83969b2, 0x4db2f9bc, + 0x785f4fef, 0xddd4dfe1, 0x13842349, 0xb60fb347, 0x83e20514, + 0x2669951a, 0xc432fa05, 0x61b96a0b, 0x5454dc58, 0xf1df4c56, + 0x3f8fb0fe, 0x9a0420f0, 0xafe996a3, 0x0a6206ad, 0xbb2d9bf9, + 0x1ea60bf7, 0x2b4bbda4, 0x8ec02daa, 0x4090d102, 0xe51b410c, + 0xd0f6f75f, 0x757d6751, 0x9726084e, 0x32ad9840, 0x07402e13, + 0xa2cbbe1d, 0x6c9b42b5, 0xc910d2bb, 0xfcfd64e8, 0x5976f4e6, + 0xe33abc97, 0x46b12c99, 0x735c9aca, 0xd6d70ac4, 0x1887f66c, + 0xbd0c6662, 0x88e1d031, 0x2d6a403f, 0xcf312f20, 0x6ababf2e, + 0x5f57097d, 0xfadc9973, 0x348c65db, 0x9107f5d5, 0xa4ea4386, + 0x0161d388, 0x0b03d525, 0xae88452b, 0x9b65f378, 0x3eee6376, + 0xf0be9fde, 0x55350fd0, 0x60d8b983, 0xc553298d, 0x27084692, + 0x8283d69c, 0xb76e60cf, 0x12e5f0c1, 0xdcb50c69, 0x793e9c67, + 0x4cd32a34, 0xe958ba3a, 0x5314f24b, 0xf69f6245, 0xc372d416, + 0x66f94418, 0xa8a9b8b0, 0x0d2228be, 0x38cf9eed, 0x9d440ee3, + 0x7f1f61fc, 0xda94f1f2, 0xef7947a1, 0x4af2d7af, 0x84a22b07, + 0x2129bb09, 0x14c40d5a, 0xb14f9d54, 0xad2a31b3, 0x08a1a1bd, + 0x3d4c17ee, 0x98c787e0, 0x56977b48, 0xf31ceb46, 0xc6f15d15, + 0x637acd1b, 0x8121a204, 0x24aa320a, 0x11478459, 0xb4cc1457, + 0x7a9ce8ff, 0xdf1778f1, 0xeafacea2, 0x4f715eac, 0xf53d16dd, + 0x50b686d3, 0x655b3080, 0xc0d0a08e, 0x0e805c26, 0xab0bcc28, + 0x9ee67a7b, 0x3b6dea75, 0xd936856a, 0x7cbd1564, 0x4950a337, + 0xecdb3339, 0x228bcf91, 0x87005f9f, 0xb2ede9cc, 0x176679c2, + 0x1d047f6f, 0xb88fef61, 0x8d625932, 0x28e9c93c, 0xe6b93594, + 0x4332a59a, 0x76df13c9, 0xd35483c7, 0x310fecd8, 0x94847cd6, + 0xa169ca85, 0x04e25a8b, 0xcab2a623, 0x6f39362d, 0x5ad4807e, + 0xff5f1070, 0x45135801, 0xe098c80f, 0xd5757e5c, 0x70feee52, + 0xbeae12fa, 0x1b2582f4, 0x2ec834a7, 0x8b43a4a9, 0x6918cbb6, + 0xcc935bb8, 0xf97eedeb, 0x5cf57de5, 0x92a5814d, 0x372e1143, + 0x02c3a710, 0xa748371e, 0x1607aa4a, 0xb38c3a44, 0x86618c17, + 0x23ea1c19, 0xedbae0b1, 0x483170bf, 0x7ddcc6ec, 0xd85756e2, + 0x3a0c39fd, 0x9f87a9f3, 0xaa6a1fa0, 0x0fe18fae, 0xc1b17306, + 0x643ae308, 0x51d7555b, 0xf45cc555, 0x4e108d24, 0xeb9b1d2a, + 0xde76ab79, 0x7bfd3b77, 0xb5adc7df, 0x102657d1, 0x25cbe182, + 0x8040718c, 0x621b1e93, 0xc7908e9d, 0xf27d38ce, 0x57f6a8c0, + 0x99a65468, 0x3c2dc466, 0x09c07235, 0xac4be23b, 0xa629e496, + 0x03a27498, 0x364fc2cb, 0x93c452c5, 0x5d94ae6d, 0xf81f3e63, + 0xcdf28830, 0x6879183e, 0x8a227721, 0x2fa9e72f, 0x1a44517c, + 0xbfcfc172, 0x719f3dda, 0xd414add4, 0xe1f91b87, 0x44728b89, + 0xfe3ec3f8, 0x5bb553f6, 0x6e58e5a5, 0xcbd375ab, 0x05838903, + 0xa008190d, 0x95e5af5e, 0x306e3f50, 0xd235504f, 0x77bec041, + 0x42537612, 0xe7d8e61c, 0x29881ab4, 0x8c038aba, 0xb9ee3ce9, + 0x1c65ace7}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0x0e908ba500000000, 0x5d26669000000000, + 0x53b6ed3500000000, 0xfb4abdfb00000000, 0xf5da365e00000000, + 0xa66cdb6b00000000, 0xa8fc50ce00000000, 0xb7930b2c00000000, + 0xb903808900000000, 0xeab56dbc00000000, 0xe425e61900000000, + 0x4cd9b6d700000000, 0x42493d7200000000, 0x11ffd04700000000, + 0x1f6f5be200000000, 0x6e27175800000000, 0x60b79cfd00000000, + 0x330171c800000000, 0x3d91fa6d00000000, 0x956daaa300000000, + 0x9bfd210600000000, 0xc84bcc3300000000, 0xc6db479600000000, + 0xd9b41c7400000000, 0xd72497d100000000, 0x84927ae400000000, + 0x8a02f14100000000, 0x22fea18f00000000, 0x2c6e2a2a00000000, + 0x7fd8c71f00000000, 0x71484cba00000000, 0xdc4e2eb000000000, + 0xd2dea51500000000, 0x8168482000000000, 0x8ff8c38500000000, + 0x2704934b00000000, 0x299418ee00000000, 0x7a22f5db00000000, + 0x74b27e7e00000000, 0x6bdd259c00000000, 0x654dae3900000000, + 0x36fb430c00000000, 0x386bc8a900000000, 0x9097986700000000, + 0x9e0713c200000000, 0xcdb1fef700000000, 0xc321755200000000, + 0xb26939e800000000, 0xbcf9b24d00000000, 0xef4f5f7800000000, + 0xe1dfd4dd00000000, 0x4923841300000000, 0x47b30fb600000000, + 0x1405e28300000000, 0x1a95692600000000, 0x05fa32c400000000, + 0x0b6ab96100000000, 0x58dc545400000000, 0x564cdff100000000, + 0xfeb08f3f00000000, 0xf020049a00000000, 0xa396e9af00000000, + 0xad06620a00000000, 0xf99b2dbb00000000, 0xf70ba61e00000000, + 0xa4bd4b2b00000000, 0xaa2dc08e00000000, 0x02d1904000000000, + 0x0c411be500000000, 0x5ff7f6d000000000, 0x51677d7500000000, + 0x4e08269700000000, 0x4098ad3200000000, 0x132e400700000000, + 0x1dbecba200000000, 0xb5429b6c00000000, 0xbbd210c900000000, + 0xe864fdfc00000000, 0xe6f4765900000000, 0x97bc3ae300000000, + 0x992cb14600000000, 0xca9a5c7300000000, 0xc40ad7d600000000, + 0x6cf6871800000000, 0x62660cbd00000000, 0x31d0e18800000000, + 0x3f406a2d00000000, 0x202f31cf00000000, 0x2ebfba6a00000000, + 0x7d09575f00000000, 0x7399dcfa00000000, 0xdb658c3400000000, + 0xd5f5079100000000, 0x8643eaa400000000, 0x88d3610100000000, + 0x25d5030b00000000, 0x2b4588ae00000000, 0x78f3659b00000000, + 0x7663ee3e00000000, 0xde9fbef000000000, 0xd00f355500000000, + 0x83b9d86000000000, 0x8d2953c500000000, 0x9246082700000000, + 0x9cd6838200000000, 0xcf606eb700000000, 0xc1f0e51200000000, + 0x690cb5dc00000000, 0x679c3e7900000000, 0x342ad34c00000000, + 0x3aba58e900000000, 0x4bf2145300000000, 0x45629ff600000000, + 0x16d472c300000000, 0x1844f96600000000, 0xb0b8a9a800000000, + 0xbe28220d00000000, 0xed9ecf3800000000, 0xe30e449d00000000, + 0xfc611f7f00000000, 0xf2f194da00000000, 0xa14779ef00000000, + 0xafd7f24a00000000, 0x072ba28400000000, 0x09bb292100000000, + 0x5a0dc41400000000, 0x549d4fb100000000, 0xb3312aad00000000, + 0xbda1a10800000000, 0xee174c3d00000000, 0xe087c79800000000, + 0x487b975600000000, 0x46eb1cf300000000, 0x155df1c600000000, + 0x1bcd7a6300000000, 0x04a2218100000000, 0x0a32aa2400000000, + 0x5984471100000000, 0x5714ccb400000000, 0xffe89c7a00000000, + 0xf17817df00000000, 0xa2cefaea00000000, 0xac5e714f00000000, + 0xdd163df500000000, 0xd386b65000000000, 0x80305b6500000000, + 0x8ea0d0c000000000, 0x265c800e00000000, 0x28cc0bab00000000, + 0x7b7ae69e00000000, 0x75ea6d3b00000000, 0x6a8536d900000000, + 0x6415bd7c00000000, 0x37a3504900000000, 0x3933dbec00000000, + 0x91cf8b2200000000, 0x9f5f008700000000, 0xcce9edb200000000, + 0xc279661700000000, 0x6f7f041d00000000, 0x61ef8fb800000000, + 0x3259628d00000000, 0x3cc9e92800000000, 0x9435b9e600000000, + 0x9aa5324300000000, 0xc913df7600000000, 0xc78354d300000000, + 0xd8ec0f3100000000, 0xd67c849400000000, 0x85ca69a100000000, + 0x8b5ae20400000000, 0x23a6b2ca00000000, 0x2d36396f00000000, + 0x7e80d45a00000000, 0x70105fff00000000, 0x0158134500000000, + 0x0fc898e000000000, 0x5c7e75d500000000, 0x52eefe7000000000, + 0xfa12aebe00000000, 0xf482251b00000000, 0xa734c82e00000000, + 0xa9a4438b00000000, 0xb6cb186900000000, 0xb85b93cc00000000, + 0xebed7ef900000000, 0xe57df55c00000000, 0x4d81a59200000000, + 0x43112e3700000000, 0x10a7c30200000000, 0x1e3748a700000000, + 0x4aaa071600000000, 0x443a8cb300000000, 0x178c618600000000, + 0x191cea2300000000, 0xb1e0baed00000000, 0xbf70314800000000, + 0xecc6dc7d00000000, 0xe25657d800000000, 0xfd390c3a00000000, + 0xf3a9879f00000000, 0xa01f6aaa00000000, 0xae8fe10f00000000, + 0x0673b1c100000000, 0x08e33a6400000000, 0x5b55d75100000000, + 0x55c55cf400000000, 0x248d104e00000000, 0x2a1d9beb00000000, + 0x79ab76de00000000, 0x773bfd7b00000000, 0xdfc7adb500000000, + 0xd157261000000000, 0x82e1cb2500000000, 0x8c71408000000000, + 0x931e1b6200000000, 0x9d8e90c700000000, 0xce387df200000000, + 0xc0a8f65700000000, 0x6854a69900000000, 0x66c42d3c00000000, + 0x3572c00900000000, 0x3be24bac00000000, 0x96e429a600000000, + 0x9874a20300000000, 0xcbc24f3600000000, 0xc552c49300000000, + 0x6dae945d00000000, 0x633e1ff800000000, 0x3088f2cd00000000, + 0x3e18796800000000, 0x2177228a00000000, 0x2fe7a92f00000000, + 0x7c51441a00000000, 0x72c1cfbf00000000, 0xda3d9f7100000000, + 0xd4ad14d400000000, 0x871bf9e100000000, 0x898b724400000000, + 0xf8c33efe00000000, 0xf653b55b00000000, 0xa5e5586e00000000, + 0xab75d3cb00000000, 0x0389830500000000, 0x0d1908a000000000, + 0x5eafe59500000000, 0x503f6e3000000000, 0x4f5035d200000000, + 0x41c0be7700000000, 0x1276534200000000, 0x1ce6d8e700000000, + 0xb41a882900000000, 0xba8a038c00000000, 0xe93ceeb900000000, + 0xe7ac651c00000000}, + {0x0000000000000000, 0x97a61de700000000, 0x6f4b4a1500000000, + 0xf8ed57f200000000, 0xde96942a00000000, 0x493089cd00000000, + 0xb1ddde3f00000000, 0x267bc3d800000000, 0xbc2d295500000000, + 0x2b8b34b200000000, 0xd366634000000000, 0x44c07ea700000000, + 0x62bbbd7f00000000, 0xf51da09800000000, 0x0df0f76a00000000, + 0x9a56ea8d00000000, 0x785b52aa00000000, 0xeffd4f4d00000000, + 0x171018bf00000000, 0x80b6055800000000, 0xa6cdc68000000000, + 0x316bdb6700000000, 0xc9868c9500000000, 0x5e20917200000000, + 0xc4767bff00000000, 0x53d0661800000000, 0xab3d31ea00000000, + 0x3c9b2c0d00000000, 0x1ae0efd500000000, 0x8d46f23200000000, + 0x75aba5c000000000, 0xe20db82700000000, 0xb1b0d58f00000000, + 0x2616c86800000000, 0xdefb9f9a00000000, 0x495d827d00000000, + 0x6f2641a500000000, 0xf8805c4200000000, 0x006d0bb000000000, + 0x97cb165700000000, 0x0d9dfcda00000000, 0x9a3be13d00000000, + 0x62d6b6cf00000000, 0xf570ab2800000000, 0xd30b68f000000000, + 0x44ad751700000000, 0xbc4022e500000000, 0x2be63f0200000000, + 0xc9eb872500000000, 0x5e4d9ac200000000, 0xa6a0cd3000000000, + 0x3106d0d700000000, 0x177d130f00000000, 0x80db0ee800000000, + 0x7836591a00000000, 0xef9044fd00000000, 0x75c6ae7000000000, + 0xe260b39700000000, 0x1a8de46500000000, 0x8d2bf98200000000, + 0xab503a5a00000000, 0x3cf627bd00000000, 0xc41b704f00000000, + 0x53bd6da800000000, 0x2367dac400000000, 0xb4c1c72300000000, + 0x4c2c90d100000000, 0xdb8a8d3600000000, 0xfdf14eee00000000, + 0x6a57530900000000, 0x92ba04fb00000000, 0x051c191c00000000, + 0x9f4af39100000000, 0x08ecee7600000000, 0xf001b98400000000, + 0x67a7a46300000000, 0x41dc67bb00000000, 0xd67a7a5c00000000, + 0x2e972dae00000000, 0xb931304900000000, 0x5b3c886e00000000, + 0xcc9a958900000000, 0x3477c27b00000000, 0xa3d1df9c00000000, + 0x85aa1c4400000000, 0x120c01a300000000, 0xeae1565100000000, + 0x7d474bb600000000, 0xe711a13b00000000, 0x70b7bcdc00000000, + 0x885aeb2e00000000, 0x1ffcf6c900000000, 0x3987351100000000, + 0xae2128f600000000, 0x56cc7f0400000000, 0xc16a62e300000000, + 0x92d70f4b00000000, 0x057112ac00000000, 0xfd9c455e00000000, + 0x6a3a58b900000000, 0x4c419b6100000000, 0xdbe7868600000000, + 0x230ad17400000000, 0xb4accc9300000000, 0x2efa261e00000000, + 0xb95c3bf900000000, 0x41b16c0b00000000, 0xd61771ec00000000, + 0xf06cb23400000000, 0x67caafd300000000, 0x9f27f82100000000, + 0x0881e5c600000000, 0xea8c5de100000000, 0x7d2a400600000000, + 0x85c717f400000000, 0x12610a1300000000, 0x341ac9cb00000000, + 0xa3bcd42c00000000, 0x5b5183de00000000, 0xccf79e3900000000, + 0x56a174b400000000, 0xc107695300000000, 0x39ea3ea100000000, + 0xae4c234600000000, 0x8837e09e00000000, 0x1f91fd7900000000, + 0xe77caa8b00000000, 0x70dab76c00000000, 0x07c8c55200000000, + 0x906ed8b500000000, 0x68838f4700000000, 0xff2592a000000000, + 0xd95e517800000000, 0x4ef84c9f00000000, 0xb6151b6d00000000, + 0x21b3068a00000000, 0xbbe5ec0700000000, 0x2c43f1e000000000, + 0xd4aea61200000000, 0x4308bbf500000000, 0x6573782d00000000, + 0xf2d565ca00000000, 0x0a38323800000000, 0x9d9e2fdf00000000, + 0x7f9397f800000000, 0xe8358a1f00000000, 0x10d8dded00000000, + 0x877ec00a00000000, 0xa10503d200000000, 0x36a31e3500000000, + 0xce4e49c700000000, 0x59e8542000000000, 0xc3bebead00000000, + 0x5418a34a00000000, 0xacf5f4b800000000, 0x3b53e95f00000000, + 0x1d282a8700000000, 0x8a8e376000000000, 0x7263609200000000, + 0xe5c57d7500000000, 0xb67810dd00000000, 0x21de0d3a00000000, + 0xd9335ac800000000, 0x4e95472f00000000, 0x68ee84f700000000, + 0xff48991000000000, 0x07a5cee200000000, 0x9003d30500000000, + 0x0a55398800000000, 0x9df3246f00000000, 0x651e739d00000000, + 0xf2b86e7a00000000, 0xd4c3ada200000000, 0x4365b04500000000, + 0xbb88e7b700000000, 0x2c2efa5000000000, 0xce23427700000000, + 0x59855f9000000000, 0xa168086200000000, 0x36ce158500000000, + 0x10b5d65d00000000, 0x8713cbba00000000, 0x7ffe9c4800000000, + 0xe85881af00000000, 0x720e6b2200000000, 0xe5a876c500000000, + 0x1d45213700000000, 0x8ae33cd000000000, 0xac98ff0800000000, + 0x3b3ee2ef00000000, 0xc3d3b51d00000000, 0x5475a8fa00000000, + 0x24af1f9600000000, 0xb309027100000000, 0x4be4558300000000, + 0xdc42486400000000, 0xfa398bbc00000000, 0x6d9f965b00000000, + 0x9572c1a900000000, 0x02d4dc4e00000000, 0x988236c300000000, + 0x0f242b2400000000, 0xf7c97cd600000000, 0x606f613100000000, + 0x4614a2e900000000, 0xd1b2bf0e00000000, 0x295fe8fc00000000, + 0xbef9f51b00000000, 0x5cf44d3c00000000, 0xcb5250db00000000, + 0x33bf072900000000, 0xa4191ace00000000, 0x8262d91600000000, + 0x15c4c4f100000000, 0xed29930300000000, 0x7a8f8ee400000000, + 0xe0d9646900000000, 0x777f798e00000000, 0x8f922e7c00000000, + 0x1834339b00000000, 0x3e4ff04300000000, 0xa9e9eda400000000, + 0x5104ba5600000000, 0xc6a2a7b100000000, 0x951fca1900000000, + 0x02b9d7fe00000000, 0xfa54800c00000000, 0x6df29deb00000000, + 0x4b895e3300000000, 0xdc2f43d400000000, 0x24c2142600000000, + 0xb36409c100000000, 0x2932e34c00000000, 0xbe94feab00000000, + 0x4679a95900000000, 0xd1dfb4be00000000, 0xf7a4776600000000, + 0x60026a8100000000, 0x98ef3d7300000000, 0x0f49209400000000, + 0xed4498b300000000, 0x7ae2855400000000, 0x820fd2a600000000, + 0x15a9cf4100000000, 0x33d20c9900000000, 0xa474117e00000000, + 0x5c99468c00000000, 0xcb3f5b6b00000000, 0x5169b1e600000000, + 0xc6cfac0100000000, 0x3e22fbf300000000, 0xa984e61400000000, + 0x8fff25cc00000000, 0x1859382b00000000, 0xe0b46fd900000000, + 0x7712723e00000000}, + {0x0000000000000000, 0x411b8c6e00000000, 0x823618dd00000000, + 0xc32d94b300000000, 0x456b416100000000, 0x0470cd0f00000000, + 0xc75d59bc00000000, 0x8646d5d200000000, 0x8ad682c200000000, + 0xcbcd0eac00000000, 0x08e09a1f00000000, 0x49fb167100000000, + 0xcfbdc3a300000000, 0x8ea64fcd00000000, 0x4d8bdb7e00000000, + 0x0c90571000000000, 0x55ab745e00000000, 0x14b0f83000000000, + 0xd79d6c8300000000, 0x9686e0ed00000000, 0x10c0353f00000000, + 0x51dbb95100000000, 0x92f62de200000000, 0xd3eda18c00000000, + 0xdf7df69c00000000, 0x9e667af200000000, 0x5d4bee4100000000, + 0x1c50622f00000000, 0x9a16b7fd00000000, 0xdb0d3b9300000000, + 0x1820af2000000000, 0x593b234e00000000, 0xaa56e9bc00000000, + 0xeb4d65d200000000, 0x2860f16100000000, 0x697b7d0f00000000, + 0xef3da8dd00000000, 0xae2624b300000000, 0x6d0bb00000000000, + 0x2c103c6e00000000, 0x20806b7e00000000, 0x619be71000000000, + 0xa2b673a300000000, 0xe3adffcd00000000, 0x65eb2a1f00000000, + 0x24f0a67100000000, 0xe7dd32c200000000, 0xa6c6beac00000000, + 0xfffd9de200000000, 0xbee6118c00000000, 0x7dcb853f00000000, + 0x3cd0095100000000, 0xba96dc8300000000, 0xfb8d50ed00000000, + 0x38a0c45e00000000, 0x79bb483000000000, 0x752b1f2000000000, + 0x3430934e00000000, 0xf71d07fd00000000, 0xb6068b9300000000, + 0x30405e4100000000, 0x715bd22f00000000, 0xb276469c00000000, + 0xf36dcaf200000000, 0x15aba3a200000000, 0x54b02fcc00000000, + 0x979dbb7f00000000, 0xd686371100000000, 0x50c0e2c300000000, + 0x11db6ead00000000, 0xd2f6fa1e00000000, 0x93ed767000000000, + 0x9f7d216000000000, 0xde66ad0e00000000, 0x1d4b39bd00000000, + 0x5c50b5d300000000, 0xda16600100000000, 0x9b0dec6f00000000, + 0x582078dc00000000, 0x193bf4b200000000, 0x4000d7fc00000000, + 0x011b5b9200000000, 0xc236cf2100000000, 0x832d434f00000000, + 0x056b969d00000000, 0x44701af300000000, 0x875d8e4000000000, + 0xc646022e00000000, 0xcad6553e00000000, 0x8bcdd95000000000, + 0x48e04de300000000, 0x09fbc18d00000000, 0x8fbd145f00000000, + 0xcea6983100000000, 0x0d8b0c8200000000, 0x4c9080ec00000000, + 0xbffd4a1e00000000, 0xfee6c67000000000, 0x3dcb52c300000000, + 0x7cd0dead00000000, 0xfa960b7f00000000, 0xbb8d871100000000, + 0x78a013a200000000, 0x39bb9fcc00000000, 0x352bc8dc00000000, + 0x743044b200000000, 0xb71dd00100000000, 0xf6065c6f00000000, + 0x704089bd00000000, 0x315b05d300000000, 0xf276916000000000, + 0xb36d1d0e00000000, 0xea563e4000000000, 0xab4db22e00000000, + 0x6860269d00000000, 0x297baaf300000000, 0xaf3d7f2100000000, + 0xee26f34f00000000, 0x2d0b67fc00000000, 0x6c10eb9200000000, + 0x6080bc8200000000, 0x219b30ec00000000, 0xe2b6a45f00000000, + 0xa3ad283100000000, 0x25ebfde300000000, 0x64f0718d00000000, + 0xa7dde53e00000000, 0xe6c6695000000000, 0x6b50369e00000000, + 0x2a4bbaf000000000, 0xe9662e4300000000, 0xa87da22d00000000, + 0x2e3b77ff00000000, 0x6f20fb9100000000, 0xac0d6f2200000000, + 0xed16e34c00000000, 0xe186b45c00000000, 0xa09d383200000000, + 0x63b0ac8100000000, 0x22ab20ef00000000, 0xa4edf53d00000000, + 0xe5f6795300000000, 0x26dbede000000000, 0x67c0618e00000000, + 0x3efb42c000000000, 0x7fe0ceae00000000, 0xbccd5a1d00000000, + 0xfdd6d67300000000, 0x7b9003a100000000, 0x3a8b8fcf00000000, + 0xf9a61b7c00000000, 0xb8bd971200000000, 0xb42dc00200000000, + 0xf5364c6c00000000, 0x361bd8df00000000, 0x770054b100000000, + 0xf146816300000000, 0xb05d0d0d00000000, 0x737099be00000000, + 0x326b15d000000000, 0xc106df2200000000, 0x801d534c00000000, + 0x4330c7ff00000000, 0x022b4b9100000000, 0x846d9e4300000000, + 0xc576122d00000000, 0x065b869e00000000, 0x47400af000000000, + 0x4bd05de000000000, 0x0acbd18e00000000, 0xc9e6453d00000000, + 0x88fdc95300000000, 0x0ebb1c8100000000, 0x4fa090ef00000000, + 0x8c8d045c00000000, 0xcd96883200000000, 0x94adab7c00000000, + 0xd5b6271200000000, 0x169bb3a100000000, 0x57803fcf00000000, + 0xd1c6ea1d00000000, 0x90dd667300000000, 0x53f0f2c000000000, + 0x12eb7eae00000000, 0x1e7b29be00000000, 0x5f60a5d000000000, + 0x9c4d316300000000, 0xdd56bd0d00000000, 0x5b1068df00000000, + 0x1a0be4b100000000, 0xd926700200000000, 0x983dfc6c00000000, + 0x7efb953c00000000, 0x3fe0195200000000, 0xfccd8de100000000, + 0xbdd6018f00000000, 0x3b90d45d00000000, 0x7a8b583300000000, + 0xb9a6cc8000000000, 0xf8bd40ee00000000, 0xf42d17fe00000000, + 0xb5369b9000000000, 0x761b0f2300000000, 0x3700834d00000000, + 0xb146569f00000000, 0xf05ddaf100000000, 0x33704e4200000000, + 0x726bc22c00000000, 0x2b50e16200000000, 0x6a4b6d0c00000000, + 0xa966f9bf00000000, 0xe87d75d100000000, 0x6e3ba00300000000, + 0x2f202c6d00000000, 0xec0db8de00000000, 0xad1634b000000000, + 0xa18663a000000000, 0xe09defce00000000, 0x23b07b7d00000000, + 0x62abf71300000000, 0xe4ed22c100000000, 0xa5f6aeaf00000000, + 0x66db3a1c00000000, 0x27c0b67200000000, 0xd4ad7c8000000000, + 0x95b6f0ee00000000, 0x569b645d00000000, 0x1780e83300000000, + 0x91c63de100000000, 0xd0ddb18f00000000, 0x13f0253c00000000, + 0x52eba95200000000, 0x5e7bfe4200000000, 0x1f60722c00000000, + 0xdc4de69f00000000, 0x9d566af100000000, 0x1b10bf2300000000, + 0x5a0b334d00000000, 0x9926a7fe00000000, 0xd83d2b9000000000, + 0x810608de00000000, 0xc01d84b000000000, 0x0330100300000000, + 0x422b9c6d00000000, 0xc46d49bf00000000, 0x8576c5d100000000, + 0x465b516200000000, 0x0740dd0c00000000, 0x0bd08a1c00000000, + 0x4acb067200000000, 0x89e692c100000000, 0xc8fd1eaf00000000, + 0x4ebbcb7d00000000, 0x0fa0471300000000, 0xcc8dd3a000000000, + 0x8d965fce00000000}, + {0x0000000000000000, 0x1dfdb50100000000, 0x3afa6b0300000000, + 0x2707de0200000000, 0x74f4d70600000000, 0x6909620700000000, + 0x4e0ebc0500000000, 0x53f3090400000000, 0xe8e8af0d00000000, + 0xf5151a0c00000000, 0xd212c40e00000000, 0xcfef710f00000000, + 0x9c1c780b00000000, 0x81e1cd0a00000000, 0xa6e6130800000000, + 0xbb1ba60900000000, 0xd0d15f1b00000000, 0xcd2cea1a00000000, + 0xea2b341800000000, 0xf7d6811900000000, 0xa425881d00000000, + 0xb9d83d1c00000000, 0x9edfe31e00000000, 0x8322561f00000000, + 0x3839f01600000000, 0x25c4451700000000, 0x02c39b1500000000, + 0x1f3e2e1400000000, 0x4ccd271000000000, 0x5130921100000000, + 0x76374c1300000000, 0x6bcaf91200000000, 0xa0a3bf3600000000, + 0xbd5e0a3700000000, 0x9a59d43500000000, 0x87a4613400000000, + 0xd457683000000000, 0xc9aadd3100000000, 0xeead033300000000, + 0xf350b63200000000, 0x484b103b00000000, 0x55b6a53a00000000, + 0x72b17b3800000000, 0x6f4cce3900000000, 0x3cbfc73d00000000, + 0x2142723c00000000, 0x0645ac3e00000000, 0x1bb8193f00000000, + 0x7072e02d00000000, 0x6d8f552c00000000, 0x4a888b2e00000000, + 0x57753e2f00000000, 0x0486372b00000000, 0x197b822a00000000, + 0x3e7c5c2800000000, 0x2381e92900000000, 0x989a4f2000000000, + 0x8567fa2100000000, 0xa260242300000000, 0xbf9d912200000000, + 0xec6e982600000000, 0xf1932d2700000000, 0xd694f32500000000, + 0xcb69462400000000, 0x40477f6d00000000, 0x5dbaca6c00000000, + 0x7abd146e00000000, 0x6740a16f00000000, 0x34b3a86b00000000, + 0x294e1d6a00000000, 0x0e49c36800000000, 0x13b4766900000000, + 0xa8afd06000000000, 0xb552656100000000, 0x9255bb6300000000, + 0x8fa80e6200000000, 0xdc5b076600000000, 0xc1a6b26700000000, + 0xe6a16c6500000000, 0xfb5cd96400000000, 0x9096207600000000, + 0x8d6b957700000000, 0xaa6c4b7500000000, 0xb791fe7400000000, + 0xe462f77000000000, 0xf99f427100000000, 0xde989c7300000000, + 0xc365297200000000, 0x787e8f7b00000000, 0x65833a7a00000000, + 0x4284e47800000000, 0x5f79517900000000, 0x0c8a587d00000000, + 0x1177ed7c00000000, 0x3670337e00000000, 0x2b8d867f00000000, + 0xe0e4c05b00000000, 0xfd19755a00000000, 0xda1eab5800000000, + 0xc7e31e5900000000, 0x9410175d00000000, 0x89eda25c00000000, + 0xaeea7c5e00000000, 0xb317c95f00000000, 0x080c6f5600000000, + 0x15f1da5700000000, 0x32f6045500000000, 0x2f0bb15400000000, + 0x7cf8b85000000000, 0x61050d5100000000, 0x4602d35300000000, + 0x5bff665200000000, 0x30359f4000000000, 0x2dc82a4100000000, + 0x0acff44300000000, 0x1732414200000000, 0x44c1484600000000, + 0x593cfd4700000000, 0x7e3b234500000000, 0x63c6964400000000, + 0xd8dd304d00000000, 0xc520854c00000000, 0xe2275b4e00000000, + 0xffdaee4f00000000, 0xac29e74b00000000, 0xb1d4524a00000000, + 0x96d38c4800000000, 0x8b2e394900000000, 0x808efeda00000000, + 0x9d734bdb00000000, 0xba7495d900000000, 0xa78920d800000000, + 0xf47a29dc00000000, 0xe9879cdd00000000, 0xce8042df00000000, + 0xd37df7de00000000, 0x686651d700000000, 0x759be4d600000000, + 0x529c3ad400000000, 0x4f618fd500000000, 0x1c9286d100000000, + 0x016f33d000000000, 0x2668edd200000000, 0x3b9558d300000000, + 0x505fa1c100000000, 0x4da214c000000000, 0x6aa5cac200000000, + 0x77587fc300000000, 0x24ab76c700000000, 0x3956c3c600000000, + 0x1e511dc400000000, 0x03aca8c500000000, 0xb8b70ecc00000000, + 0xa54abbcd00000000, 0x824d65cf00000000, 0x9fb0d0ce00000000, + 0xcc43d9ca00000000, 0xd1be6ccb00000000, 0xf6b9b2c900000000, + 0xeb4407c800000000, 0x202d41ec00000000, 0x3dd0f4ed00000000, + 0x1ad72aef00000000, 0x072a9fee00000000, 0x54d996ea00000000, + 0x492423eb00000000, 0x6e23fde900000000, 0x73de48e800000000, + 0xc8c5eee100000000, 0xd5385be000000000, 0xf23f85e200000000, + 0xefc230e300000000, 0xbc3139e700000000, 0xa1cc8ce600000000, + 0x86cb52e400000000, 0x9b36e7e500000000, 0xf0fc1ef700000000, + 0xed01abf600000000, 0xca0675f400000000, 0xd7fbc0f500000000, + 0x8408c9f100000000, 0x99f57cf000000000, 0xbef2a2f200000000, + 0xa30f17f300000000, 0x1814b1fa00000000, 0x05e904fb00000000, + 0x22eedaf900000000, 0x3f136ff800000000, 0x6ce066fc00000000, + 0x711dd3fd00000000, 0x561a0dff00000000, 0x4be7b8fe00000000, + 0xc0c981b700000000, 0xdd3434b600000000, 0xfa33eab400000000, + 0xe7ce5fb500000000, 0xb43d56b100000000, 0xa9c0e3b000000000, + 0x8ec73db200000000, 0x933a88b300000000, 0x28212eba00000000, + 0x35dc9bbb00000000, 0x12db45b900000000, 0x0f26f0b800000000, + 0x5cd5f9bc00000000, 0x41284cbd00000000, 0x662f92bf00000000, + 0x7bd227be00000000, 0x1018deac00000000, 0x0de56bad00000000, + 0x2ae2b5af00000000, 0x371f00ae00000000, 0x64ec09aa00000000, + 0x7911bcab00000000, 0x5e1662a900000000, 0x43ebd7a800000000, + 0xf8f071a100000000, 0xe50dc4a000000000, 0xc20a1aa200000000, + 0xdff7afa300000000, 0x8c04a6a700000000, 0x91f913a600000000, + 0xb6fecda400000000, 0xab0378a500000000, 0x606a3e8100000000, + 0x7d978b8000000000, 0x5a90558200000000, 0x476de08300000000, + 0x149ee98700000000, 0x09635c8600000000, 0x2e64828400000000, + 0x3399378500000000, 0x8882918c00000000, 0x957f248d00000000, + 0xb278fa8f00000000, 0xaf854f8e00000000, 0xfc76468a00000000, + 0xe18bf38b00000000, 0xc68c2d8900000000, 0xdb71988800000000, + 0xb0bb619a00000000, 0xad46d49b00000000, 0x8a410a9900000000, + 0x97bcbf9800000000, 0xc44fb69c00000000, 0xd9b2039d00000000, + 0xfeb5dd9f00000000, 0xe348689e00000000, 0x5853ce9700000000, + 0x45ae7b9600000000, 0x62a9a59400000000, 0x7f54109500000000, + 0x2ca7199100000000, 0x315aac9000000000, 0x165d729200000000, + 0x0ba0c79300000000}, + {0x0000000000000000, 0x24d9076300000000, 0x48b20fc600000000, + 0x6c6b08a500000000, 0xd1626e5700000000, 0xf5bb693400000000, + 0x99d0619100000000, 0xbd0966f200000000, 0xa2c5dcae00000000, + 0x861cdbcd00000000, 0xea77d36800000000, 0xceaed40b00000000, + 0x73a7b2f900000000, 0x577eb59a00000000, 0x3b15bd3f00000000, + 0x1fccba5c00000000, 0x058dc88600000000, 0x2154cfe500000000, + 0x4d3fc74000000000, 0x69e6c02300000000, 0xd4efa6d100000000, + 0xf036a1b200000000, 0x9c5da91700000000, 0xb884ae7400000000, + 0xa748142800000000, 0x8391134b00000000, 0xeffa1bee00000000, + 0xcb231c8d00000000, 0x762a7a7f00000000, 0x52f37d1c00000000, + 0x3e9875b900000000, 0x1a4172da00000000, 0x4b1ce0d600000000, + 0x6fc5e7b500000000, 0x03aeef1000000000, 0x2777e87300000000, + 0x9a7e8e8100000000, 0xbea789e200000000, 0xd2cc814700000000, + 0xf615862400000000, 0xe9d93c7800000000, 0xcd003b1b00000000, + 0xa16b33be00000000, 0x85b234dd00000000, 0x38bb522f00000000, + 0x1c62554c00000000, 0x70095de900000000, 0x54d05a8a00000000, + 0x4e91285000000000, 0x6a482f3300000000, 0x0623279600000000, + 0x22fa20f500000000, 0x9ff3460700000000, 0xbb2a416400000000, + 0xd74149c100000000, 0xf3984ea200000000, 0xec54f4fe00000000, + 0xc88df39d00000000, 0xa4e6fb3800000000, 0x803ffc5b00000000, + 0x3d369aa900000000, 0x19ef9dca00000000, 0x7584956f00000000, + 0x515d920c00000000, 0xd73eb17600000000, 0xf3e7b61500000000, + 0x9f8cbeb000000000, 0xbb55b9d300000000, 0x065cdf2100000000, + 0x2285d84200000000, 0x4eeed0e700000000, 0x6a37d78400000000, + 0x75fb6dd800000000, 0x51226abb00000000, 0x3d49621e00000000, + 0x1990657d00000000, 0xa499038f00000000, 0x804004ec00000000, + 0xec2b0c4900000000, 0xc8f20b2a00000000, 0xd2b379f000000000, + 0xf66a7e9300000000, 0x9a01763600000000, 0xbed8715500000000, + 0x03d117a700000000, 0x270810c400000000, 0x4b63186100000000, + 0x6fba1f0200000000, 0x7076a55e00000000, 0x54afa23d00000000, + 0x38c4aa9800000000, 0x1c1dadfb00000000, 0xa114cb0900000000, + 0x85cdcc6a00000000, 0xe9a6c4cf00000000, 0xcd7fc3ac00000000, + 0x9c2251a000000000, 0xb8fb56c300000000, 0xd4905e6600000000, + 0xf049590500000000, 0x4d403ff700000000, 0x6999389400000000, + 0x05f2303100000000, 0x212b375200000000, 0x3ee78d0e00000000, + 0x1a3e8a6d00000000, 0x765582c800000000, 0x528c85ab00000000, + 0xef85e35900000000, 0xcb5ce43a00000000, 0xa737ec9f00000000, + 0x83eeebfc00000000, 0x99af992600000000, 0xbd769e4500000000, + 0xd11d96e000000000, 0xf5c4918300000000, 0x48cdf77100000000, + 0x6c14f01200000000, 0x007ff8b700000000, 0x24a6ffd400000000, + 0x3b6a458800000000, 0x1fb342eb00000000, 0x73d84a4e00000000, + 0x57014d2d00000000, 0xea082bdf00000000, 0xced12cbc00000000, + 0xa2ba241900000000, 0x8663237a00000000, 0xae7d62ed00000000, + 0x8aa4658e00000000, 0xe6cf6d2b00000000, 0xc2166a4800000000, + 0x7f1f0cba00000000, 0x5bc60bd900000000, 0x37ad037c00000000, + 0x1374041f00000000, 0x0cb8be4300000000, 0x2861b92000000000, + 0x440ab18500000000, 0x60d3b6e600000000, 0xdddad01400000000, + 0xf903d77700000000, 0x9568dfd200000000, 0xb1b1d8b100000000, + 0xabf0aa6b00000000, 0x8f29ad0800000000, 0xe342a5ad00000000, + 0xc79ba2ce00000000, 0x7a92c43c00000000, 0x5e4bc35f00000000, + 0x3220cbfa00000000, 0x16f9cc9900000000, 0x093576c500000000, + 0x2dec71a600000000, 0x4187790300000000, 0x655e7e6000000000, + 0xd857189200000000, 0xfc8e1ff100000000, 0x90e5175400000000, + 0xb43c103700000000, 0xe561823b00000000, 0xc1b8855800000000, + 0xadd38dfd00000000, 0x890a8a9e00000000, 0x3403ec6c00000000, + 0x10daeb0f00000000, 0x7cb1e3aa00000000, 0x5868e4c900000000, + 0x47a45e9500000000, 0x637d59f600000000, 0x0f16515300000000, + 0x2bcf563000000000, 0x96c630c200000000, 0xb21f37a100000000, + 0xde743f0400000000, 0xfaad386700000000, 0xe0ec4abd00000000, + 0xc4354dde00000000, 0xa85e457b00000000, 0x8c87421800000000, + 0x318e24ea00000000, 0x1557238900000000, 0x793c2b2c00000000, + 0x5de52c4f00000000, 0x4229961300000000, 0x66f0917000000000, + 0x0a9b99d500000000, 0x2e429eb600000000, 0x934bf84400000000, + 0xb792ff2700000000, 0xdbf9f78200000000, 0xff20f0e100000000, + 0x7943d39b00000000, 0x5d9ad4f800000000, 0x31f1dc5d00000000, + 0x1528db3e00000000, 0xa821bdcc00000000, 0x8cf8baaf00000000, + 0xe093b20a00000000, 0xc44ab56900000000, 0xdb860f3500000000, + 0xff5f085600000000, 0x933400f300000000, 0xb7ed079000000000, + 0x0ae4616200000000, 0x2e3d660100000000, 0x42566ea400000000, + 0x668f69c700000000, 0x7cce1b1d00000000, 0x58171c7e00000000, + 0x347c14db00000000, 0x10a513b800000000, 0xadac754a00000000, + 0x8975722900000000, 0xe51e7a8c00000000, 0xc1c77def00000000, + 0xde0bc7b300000000, 0xfad2c0d000000000, 0x96b9c87500000000, + 0xb260cf1600000000, 0x0f69a9e400000000, 0x2bb0ae8700000000, + 0x47dba62200000000, 0x6302a14100000000, 0x325f334d00000000, + 0x1686342e00000000, 0x7aed3c8b00000000, 0x5e343be800000000, + 0xe33d5d1a00000000, 0xc7e45a7900000000, 0xab8f52dc00000000, + 0x8f5655bf00000000, 0x909aefe300000000, 0xb443e88000000000, + 0xd828e02500000000, 0xfcf1e74600000000, 0x41f881b400000000, + 0x652186d700000000, 0x094a8e7200000000, 0x2d93891100000000, + 0x37d2fbcb00000000, 0x130bfca800000000, 0x7f60f40d00000000, + 0x5bb9f36e00000000, 0xe6b0959c00000000, 0xc26992ff00000000, + 0xae029a5a00000000, 0x8adb9d3900000000, 0x9517276500000000, + 0xb1ce200600000000, 0xdda528a300000000, 0xf97c2fc000000000, + 0x4475493200000000, 0x60ac4e5100000000, 0x0cc746f400000000, + 0x281e419700000000}, + {0x0000000000000000, 0x08e3603c00000000, 0x10c6c17800000000, + 0x1825a14400000000, 0x208c83f100000000, 0x286fe3cd00000000, + 0x304a428900000000, 0x38a922b500000000, 0x011e763800000000, + 0x09fd160400000000, 0x11d8b74000000000, 0x193bd77c00000000, + 0x2192f5c900000000, 0x297195f500000000, 0x315434b100000000, + 0x39b7548d00000000, 0x023cec7000000000, 0x0adf8c4c00000000, + 0x12fa2d0800000000, 0x1a194d3400000000, 0x22b06f8100000000, + 0x2a530fbd00000000, 0x3276aef900000000, 0x3a95cec500000000, + 0x03229a4800000000, 0x0bc1fa7400000000, 0x13e45b3000000000, + 0x1b073b0c00000000, 0x23ae19b900000000, 0x2b4d798500000000, + 0x3368d8c100000000, 0x3b8bb8fd00000000, 0x0478d8e100000000, + 0x0c9bb8dd00000000, 0x14be199900000000, 0x1c5d79a500000000, + 0x24f45b1000000000, 0x2c173b2c00000000, 0x34329a6800000000, + 0x3cd1fa5400000000, 0x0566aed900000000, 0x0d85cee500000000, + 0x15a06fa100000000, 0x1d430f9d00000000, 0x25ea2d2800000000, + 0x2d094d1400000000, 0x352cec5000000000, 0x3dcf8c6c00000000, + 0x0644349100000000, 0x0ea754ad00000000, 0x1682f5e900000000, + 0x1e6195d500000000, 0x26c8b76000000000, 0x2e2bd75c00000000, + 0x360e761800000000, 0x3eed162400000000, 0x075a42a900000000, + 0x0fb9229500000000, 0x179c83d100000000, 0x1f7fe3ed00000000, + 0x27d6c15800000000, 0x2f35a16400000000, 0x3710002000000000, + 0x3ff3601c00000000, 0x49f6c11800000000, 0x4115a12400000000, + 0x5930006000000000, 0x51d3605c00000000, 0x697a42e900000000, + 0x619922d500000000, 0x79bc839100000000, 0x715fe3ad00000000, + 0x48e8b72000000000, 0x400bd71c00000000, 0x582e765800000000, + 0x50cd166400000000, 0x686434d100000000, 0x608754ed00000000, + 0x78a2f5a900000000, 0x7041959500000000, 0x4bca2d6800000000, + 0x43294d5400000000, 0x5b0cec1000000000, 0x53ef8c2c00000000, + 0x6b46ae9900000000, 0x63a5cea500000000, 0x7b806fe100000000, + 0x73630fdd00000000, 0x4ad45b5000000000, 0x42373b6c00000000, + 0x5a129a2800000000, 0x52f1fa1400000000, 0x6a58d8a100000000, + 0x62bbb89d00000000, 0x7a9e19d900000000, 0x727d79e500000000, + 0x4d8e19f900000000, 0x456d79c500000000, 0x5d48d88100000000, + 0x55abb8bd00000000, 0x6d029a0800000000, 0x65e1fa3400000000, + 0x7dc45b7000000000, 0x75273b4c00000000, 0x4c906fc100000000, + 0x44730ffd00000000, 0x5c56aeb900000000, 0x54b5ce8500000000, + 0x6c1cec3000000000, 0x64ff8c0c00000000, 0x7cda2d4800000000, + 0x74394d7400000000, 0x4fb2f58900000000, 0x475195b500000000, + 0x5f7434f100000000, 0x579754cd00000000, 0x6f3e767800000000, + 0x67dd164400000000, 0x7ff8b70000000000, 0x771bd73c00000000, + 0x4eac83b100000000, 0x464fe38d00000000, 0x5e6a42c900000000, + 0x568922f500000000, 0x6e20004000000000, 0x66c3607c00000000, + 0x7ee6c13800000000, 0x7605a10400000000, 0x92ec833100000000, + 0x9a0fe30d00000000, 0x822a424900000000, 0x8ac9227500000000, + 0xb26000c000000000, 0xba8360fc00000000, 0xa2a6c1b800000000, + 0xaa45a18400000000, 0x93f2f50900000000, 0x9b11953500000000, + 0x8334347100000000, 0x8bd7544d00000000, 0xb37e76f800000000, + 0xbb9d16c400000000, 0xa3b8b78000000000, 0xab5bd7bc00000000, + 0x90d06f4100000000, 0x98330f7d00000000, 0x8016ae3900000000, + 0x88f5ce0500000000, 0xb05cecb000000000, 0xb8bf8c8c00000000, + 0xa09a2dc800000000, 0xa8794df400000000, 0x91ce197900000000, + 0x992d794500000000, 0x8108d80100000000, 0x89ebb83d00000000, + 0xb1429a8800000000, 0xb9a1fab400000000, 0xa1845bf000000000, + 0xa9673bcc00000000, 0x96945bd000000000, 0x9e773bec00000000, + 0x86529aa800000000, 0x8eb1fa9400000000, 0xb618d82100000000, + 0xbefbb81d00000000, 0xa6de195900000000, 0xae3d796500000000, + 0x978a2de800000000, 0x9f694dd400000000, 0x874cec9000000000, + 0x8faf8cac00000000, 0xb706ae1900000000, 0xbfe5ce2500000000, + 0xa7c06f6100000000, 0xaf230f5d00000000, 0x94a8b7a000000000, + 0x9c4bd79c00000000, 0x846e76d800000000, 0x8c8d16e400000000, + 0xb424345100000000, 0xbcc7546d00000000, 0xa4e2f52900000000, + 0xac01951500000000, 0x95b6c19800000000, 0x9d55a1a400000000, + 0x857000e000000000, 0x8d9360dc00000000, 0xb53a426900000000, + 0xbdd9225500000000, 0xa5fc831100000000, 0xad1fe32d00000000, + 0xdb1a422900000000, 0xd3f9221500000000, 0xcbdc835100000000, + 0xc33fe36d00000000, 0xfb96c1d800000000, 0xf375a1e400000000, + 0xeb5000a000000000, 0xe3b3609c00000000, 0xda04341100000000, + 0xd2e7542d00000000, 0xcac2f56900000000, 0xc221955500000000, + 0xfa88b7e000000000, 0xf26bd7dc00000000, 0xea4e769800000000, + 0xe2ad16a400000000, 0xd926ae5900000000, 0xd1c5ce6500000000, + 0xc9e06f2100000000, 0xc1030f1d00000000, 0xf9aa2da800000000, + 0xf1494d9400000000, 0xe96cecd000000000, 0xe18f8cec00000000, + 0xd838d86100000000, 0xd0dbb85d00000000, 0xc8fe191900000000, + 0xc01d792500000000, 0xf8b45b9000000000, 0xf0573bac00000000, + 0xe8729ae800000000, 0xe091fad400000000, 0xdf629ac800000000, + 0xd781faf400000000, 0xcfa45bb000000000, 0xc7473b8c00000000, + 0xffee193900000000, 0xf70d790500000000, 0xef28d84100000000, + 0xe7cbb87d00000000, 0xde7cecf000000000, 0xd69f8ccc00000000, + 0xceba2d8800000000, 0xc6594db400000000, 0xfef06f0100000000, + 0xf6130f3d00000000, 0xee36ae7900000000, 0xe6d5ce4500000000, + 0xdd5e76b800000000, 0xd5bd168400000000, 0xcd98b7c000000000, + 0xc57bd7fc00000000, 0xfdd2f54900000000, 0xf531957500000000, + 0xed14343100000000, 0xe5f7540d00000000, 0xdc40008000000000, + 0xd4a360bc00000000, 0xcc86c1f800000000, 0xc465a1c400000000, + 0xfccc837100000000, 0xf42fe34d00000000, 0xec0a420900000000, + 0xe4e9223500000000}, + {0x0000000000000000, 0xd1e8e70e00000000, 0xa2d1cf1d00000000, + 0x7339281300000000, 0x44a39f3b00000000, 0x954b783500000000, + 0xe672502600000000, 0x379ab72800000000, 0x88463f7700000000, + 0x59aed87900000000, 0x2a97f06a00000000, 0xfb7f176400000000, + 0xcce5a04c00000000, 0x1d0d474200000000, 0x6e346f5100000000, + 0xbfdc885f00000000, 0x108d7eee00000000, 0xc16599e000000000, + 0xb25cb1f300000000, 0x63b456fd00000000, 0x542ee1d500000000, + 0x85c606db00000000, 0xf6ff2ec800000000, 0x2717c9c600000000, + 0x98cb419900000000, 0x4923a69700000000, 0x3a1a8e8400000000, + 0xebf2698a00000000, 0xdc68dea200000000, 0x0d8039ac00000000, + 0x7eb911bf00000000, 0xaf51f6b100000000, 0x611c8c0700000000, + 0xb0f46b0900000000, 0xc3cd431a00000000, 0x1225a41400000000, + 0x25bf133c00000000, 0xf457f43200000000, 0x876edc2100000000, + 0x56863b2f00000000, 0xe95ab37000000000, 0x38b2547e00000000, + 0x4b8b7c6d00000000, 0x9a639b6300000000, 0xadf92c4b00000000, + 0x7c11cb4500000000, 0x0f28e35600000000, 0xdec0045800000000, + 0x7191f2e900000000, 0xa07915e700000000, 0xd3403df400000000, + 0x02a8dafa00000000, 0x35326dd200000000, 0xe4da8adc00000000, + 0x97e3a2cf00000000, 0x460b45c100000000, 0xf9d7cd9e00000000, + 0x283f2a9000000000, 0x5b06028300000000, 0x8aeee58d00000000, + 0xbd7452a500000000, 0x6c9cb5ab00000000, 0x1fa59db800000000, + 0xce4d7ab600000000, 0xc238180f00000000, 0x13d0ff0100000000, + 0x60e9d71200000000, 0xb101301c00000000, 0x869b873400000000, + 0x5773603a00000000, 0x244a482900000000, 0xf5a2af2700000000, + 0x4a7e277800000000, 0x9b96c07600000000, 0xe8afe86500000000, + 0x39470f6b00000000, 0x0eddb84300000000, 0xdf355f4d00000000, + 0xac0c775e00000000, 0x7de4905000000000, 0xd2b566e100000000, + 0x035d81ef00000000, 0x7064a9fc00000000, 0xa18c4ef200000000, + 0x9616f9da00000000, 0x47fe1ed400000000, 0x34c736c700000000, + 0xe52fd1c900000000, 0x5af3599600000000, 0x8b1bbe9800000000, + 0xf822968b00000000, 0x29ca718500000000, 0x1e50c6ad00000000, + 0xcfb821a300000000, 0xbc8109b000000000, 0x6d69eebe00000000, + 0xa324940800000000, 0x72cc730600000000, 0x01f55b1500000000, + 0xd01dbc1b00000000, 0xe7870b3300000000, 0x366fec3d00000000, + 0x4556c42e00000000, 0x94be232000000000, 0x2b62ab7f00000000, + 0xfa8a4c7100000000, 0x89b3646200000000, 0x585b836c00000000, + 0x6fc1344400000000, 0xbe29d34a00000000, 0xcd10fb5900000000, + 0x1cf81c5700000000, 0xb3a9eae600000000, 0x62410de800000000, + 0x117825fb00000000, 0xc090c2f500000000, 0xf70a75dd00000000, + 0x26e292d300000000, 0x55dbbac000000000, 0x84335dce00000000, + 0x3befd59100000000, 0xea07329f00000000, 0x993e1a8c00000000, + 0x48d6fd8200000000, 0x7f4c4aaa00000000, 0xaea4ada400000000, + 0xdd9d85b700000000, 0x0c7562b900000000, 0x8471301e00000000, + 0x5599d71000000000, 0x26a0ff0300000000, 0xf748180d00000000, + 0xc0d2af2500000000, 0x113a482b00000000, 0x6203603800000000, + 0xb3eb873600000000, 0x0c370f6900000000, 0xdddfe86700000000, + 0xaee6c07400000000, 0x7f0e277a00000000, 0x4894905200000000, + 0x997c775c00000000, 0xea455f4f00000000, 0x3badb84100000000, + 0x94fc4ef000000000, 0x4514a9fe00000000, 0x362d81ed00000000, + 0xe7c566e300000000, 0xd05fd1cb00000000, 0x01b736c500000000, + 0x728e1ed600000000, 0xa366f9d800000000, 0x1cba718700000000, + 0xcd52968900000000, 0xbe6bbe9a00000000, 0x6f83599400000000, + 0x5819eebc00000000, 0x89f109b200000000, 0xfac821a100000000, + 0x2b20c6af00000000, 0xe56dbc1900000000, 0x34855b1700000000, + 0x47bc730400000000, 0x9654940a00000000, 0xa1ce232200000000, + 0x7026c42c00000000, 0x031fec3f00000000, 0xd2f70b3100000000, + 0x6d2b836e00000000, 0xbcc3646000000000, 0xcffa4c7300000000, + 0x1e12ab7d00000000, 0x29881c5500000000, 0xf860fb5b00000000, + 0x8b59d34800000000, 0x5ab1344600000000, 0xf5e0c2f700000000, + 0x240825f900000000, 0x57310dea00000000, 0x86d9eae400000000, + 0xb1435dcc00000000, 0x60abbac200000000, 0x139292d100000000, + 0xc27a75df00000000, 0x7da6fd8000000000, 0xac4e1a8e00000000, + 0xdf77329d00000000, 0x0e9fd59300000000, 0x390562bb00000000, + 0xe8ed85b500000000, 0x9bd4ada600000000, 0x4a3c4aa800000000, + 0x4649281100000000, 0x97a1cf1f00000000, 0xe498e70c00000000, + 0x3570000200000000, 0x02eab72a00000000, 0xd302502400000000, + 0xa03b783700000000, 0x71d39f3900000000, 0xce0f176600000000, + 0x1fe7f06800000000, 0x6cded87b00000000, 0xbd363f7500000000, + 0x8aac885d00000000, 0x5b446f5300000000, 0x287d474000000000, + 0xf995a04e00000000, 0x56c456ff00000000, 0x872cb1f100000000, + 0xf41599e200000000, 0x25fd7eec00000000, 0x1267c9c400000000, + 0xc38f2eca00000000, 0xb0b606d900000000, 0x615ee1d700000000, + 0xde82698800000000, 0x0f6a8e8600000000, 0x7c53a69500000000, + 0xadbb419b00000000, 0x9a21f6b300000000, 0x4bc911bd00000000, + 0x38f039ae00000000, 0xe918dea000000000, 0x2755a41600000000, + 0xf6bd431800000000, 0x85846b0b00000000, 0x546c8c0500000000, + 0x63f63b2d00000000, 0xb21edc2300000000, 0xc127f43000000000, + 0x10cf133e00000000, 0xaf139b6100000000, 0x7efb7c6f00000000, + 0x0dc2547c00000000, 0xdc2ab37200000000, 0xebb0045a00000000, + 0x3a58e35400000000, 0x4961cb4700000000, 0x98892c4900000000, + 0x37d8daf800000000, 0xe6303df600000000, 0x950915e500000000, + 0x44e1f2eb00000000, 0x737b45c300000000, 0xa293a2cd00000000, + 0xd1aa8ade00000000, 0x00426dd000000000, 0xbf9ee58f00000000, + 0x6e76028100000000, 0x1d4f2a9200000000, 0xcca7cd9c00000000, + 0xfb3d7ab400000000, 0x2ad59dba00000000, 0x59ecb5a900000000, + 0x880452a700000000}, + {0x0000000000000000, 0xaa05daf100000000, 0x150dc53800000000, + 0xbf081fc900000000, 0x2a1a8a7100000000, 0x801f508000000000, + 0x3f174f4900000000, 0x951295b800000000, 0x543414e300000000, + 0xfe31ce1200000000, 0x4139d1db00000000, 0xeb3c0b2a00000000, + 0x7e2e9e9200000000, 0xd42b446300000000, 0x6b235baa00000000, + 0xc126815b00000000, 0xe96e591d00000000, 0x436b83ec00000000, + 0xfc639c2500000000, 0x566646d400000000, 0xc374d36c00000000, + 0x6971099d00000000, 0xd679165400000000, 0x7c7ccca500000000, + 0xbd5a4dfe00000000, 0x175f970f00000000, 0xa85788c600000000, + 0x0252523700000000, 0x9740c78f00000000, 0x3d451d7e00000000, + 0x824d02b700000000, 0x2848d84600000000, 0xd2ddb23a00000000, + 0x78d868cb00000000, 0xc7d0770200000000, 0x6dd5adf300000000, + 0xf8c7384b00000000, 0x52c2e2ba00000000, 0xedcafd7300000000, + 0x47cf278200000000, 0x86e9a6d900000000, 0x2cec7c2800000000, + 0x93e463e100000000, 0x39e1b91000000000, 0xacf32ca800000000, + 0x06f6f65900000000, 0xb9fee99000000000, 0x13fb336100000000, + 0x3bb3eb2700000000, 0x91b631d600000000, 0x2ebe2e1f00000000, + 0x84bbf4ee00000000, 0x11a9615600000000, 0xbbacbba700000000, + 0x04a4a46e00000000, 0xaea17e9f00000000, 0x6f87ffc400000000, + 0xc582253500000000, 0x7a8a3afc00000000, 0xd08fe00d00000000, + 0x459d75b500000000, 0xef98af4400000000, 0x5090b08d00000000, + 0xfa956a7c00000000, 0xa4bb657500000000, 0x0ebebf8400000000, + 0xb1b6a04d00000000, 0x1bb37abc00000000, 0x8ea1ef0400000000, + 0x24a435f500000000, 0x9bac2a3c00000000, 0x31a9f0cd00000000, + 0xf08f719600000000, 0x5a8aab6700000000, 0xe582b4ae00000000, + 0x4f876e5f00000000, 0xda95fbe700000000, 0x7090211600000000, + 0xcf983edf00000000, 0x659de42e00000000, 0x4dd53c6800000000, + 0xe7d0e69900000000, 0x58d8f95000000000, 0xf2dd23a100000000, + 0x67cfb61900000000, 0xcdca6ce800000000, 0x72c2732100000000, + 0xd8c7a9d000000000, 0x19e1288b00000000, 0xb3e4f27a00000000, + 0x0cecedb300000000, 0xa6e9374200000000, 0x33fba2fa00000000, + 0x99fe780b00000000, 0x26f667c200000000, 0x8cf3bd3300000000, + 0x7666d74f00000000, 0xdc630dbe00000000, 0x636b127700000000, + 0xc96ec88600000000, 0x5c7c5d3e00000000, 0xf67987cf00000000, + 0x4971980600000000, 0xe37442f700000000, 0x2252c3ac00000000, + 0x8857195d00000000, 0x375f069400000000, 0x9d5adc6500000000, + 0x084849dd00000000, 0xa24d932c00000000, 0x1d458ce500000000, + 0xb740561400000000, 0x9f088e5200000000, 0x350d54a300000000, + 0x8a054b6a00000000, 0x2000919b00000000, 0xb512042300000000, + 0x1f17ded200000000, 0xa01fc11b00000000, 0x0a1a1bea00000000, + 0xcb3c9ab100000000, 0x6139404000000000, 0xde315f8900000000, + 0x7434857800000000, 0xe12610c000000000, 0x4b23ca3100000000, + 0xf42bd5f800000000, 0x5e2e0f0900000000, 0x4877cbea00000000, + 0xe272111b00000000, 0x5d7a0ed200000000, 0xf77fd42300000000, + 0x626d419b00000000, 0xc8689b6a00000000, 0x776084a300000000, + 0xdd655e5200000000, 0x1c43df0900000000, 0xb64605f800000000, + 0x094e1a3100000000, 0xa34bc0c000000000, 0x3659557800000000, + 0x9c5c8f8900000000, 0x2354904000000000, 0x89514ab100000000, + 0xa11992f700000000, 0x0b1c480600000000, 0xb41457cf00000000, + 0x1e118d3e00000000, 0x8b03188600000000, 0x2106c27700000000, + 0x9e0eddbe00000000, 0x340b074f00000000, 0xf52d861400000000, + 0x5f285ce500000000, 0xe020432c00000000, 0x4a2599dd00000000, + 0xdf370c6500000000, 0x7532d69400000000, 0xca3ac95d00000000, + 0x603f13ac00000000, 0x9aaa79d000000000, 0x30afa32100000000, + 0x8fa7bce800000000, 0x25a2661900000000, 0xb0b0f3a100000000, + 0x1ab5295000000000, 0xa5bd369900000000, 0x0fb8ec6800000000, + 0xce9e6d3300000000, 0x649bb7c200000000, 0xdb93a80b00000000, + 0x719672fa00000000, 0xe484e74200000000, 0x4e813db300000000, + 0xf189227a00000000, 0x5b8cf88b00000000, 0x73c420cd00000000, + 0xd9c1fa3c00000000, 0x66c9e5f500000000, 0xcccc3f0400000000, + 0x59deaabc00000000, 0xf3db704d00000000, 0x4cd36f8400000000, + 0xe6d6b57500000000, 0x27f0342e00000000, 0x8df5eedf00000000, + 0x32fdf11600000000, 0x98f82be700000000, 0x0deabe5f00000000, + 0xa7ef64ae00000000, 0x18e77b6700000000, 0xb2e2a19600000000, + 0xecccae9f00000000, 0x46c9746e00000000, 0xf9c16ba700000000, + 0x53c4b15600000000, 0xc6d624ee00000000, 0x6cd3fe1f00000000, + 0xd3dbe1d600000000, 0x79de3b2700000000, 0xb8f8ba7c00000000, + 0x12fd608d00000000, 0xadf57f4400000000, 0x07f0a5b500000000, + 0x92e2300d00000000, 0x38e7eafc00000000, 0x87eff53500000000, + 0x2dea2fc400000000, 0x05a2f78200000000, 0xafa72d7300000000, + 0x10af32ba00000000, 0xbaaae84b00000000, 0x2fb87df300000000, + 0x85bda70200000000, 0x3ab5b8cb00000000, 0x90b0623a00000000, + 0x5196e36100000000, 0xfb93399000000000, 0x449b265900000000, + 0xee9efca800000000, 0x7b8c691000000000, 0xd189b3e100000000, + 0x6e81ac2800000000, 0xc48476d900000000, 0x3e111ca500000000, + 0x9414c65400000000, 0x2b1cd99d00000000, 0x8119036c00000000, + 0x140b96d400000000, 0xbe0e4c2500000000, 0x010653ec00000000, + 0xab03891d00000000, 0x6a25084600000000, 0xc020d2b700000000, + 0x7f28cd7e00000000, 0xd52d178f00000000, 0x403f823700000000, + 0xea3a58c600000000, 0x5532470f00000000, 0xff379dfe00000000, + 0xd77f45b800000000, 0x7d7a9f4900000000, 0xc272808000000000, + 0x68775a7100000000, 0xfd65cfc900000000, 0x5760153800000000, + 0xe8680af100000000, 0x426dd00000000000, 0x834b515b00000000, + 0x294e8baa00000000, 0x9646946300000000, 0x3c434e9200000000, + 0xa951db2a00000000, 0x035401db00000000, 0xbc5c1e1200000000, + 0x1659c4e300000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xae689191, 0x87a02563, 0x29c8b4f2, 0xd4314c87, + 0x7a59dd16, 0x539169e4, 0xfdf9f875, 0x73139f4f, 0xdd7b0ede, + 0xf4b3ba2c, 0x5adb2bbd, 0xa722d3c8, 0x094a4259, 0x2082f6ab, + 0x8eea673a, 0xe6273e9e, 0x484faf0f, 0x61871bfd, 0xcfef8a6c, + 0x32167219, 0x9c7ee388, 0xb5b6577a, 0x1bdec6eb, 0x9534a1d1, + 0x3b5c3040, 0x129484b2, 0xbcfc1523, 0x4105ed56, 0xef6d7cc7, + 0xc6a5c835, 0x68cd59a4, 0x173f7b7d, 0xb957eaec, 0x909f5e1e, + 0x3ef7cf8f, 0xc30e37fa, 0x6d66a66b, 0x44ae1299, 0xeac68308, + 0x642ce432, 0xca4475a3, 0xe38cc151, 0x4de450c0, 0xb01da8b5, + 0x1e753924, 0x37bd8dd6, 0x99d51c47, 0xf11845e3, 0x5f70d472, + 0x76b86080, 0xd8d0f111, 0x25290964, 0x8b4198f5, 0xa2892c07, + 0x0ce1bd96, 0x820bdaac, 0x2c634b3d, 0x05abffcf, 0xabc36e5e, + 0x563a962b, 0xf85207ba, 0xd19ab348, 0x7ff222d9, 0x2e7ef6fa, + 0x8016676b, 0xa9ded399, 0x07b64208, 0xfa4fba7d, 0x54272bec, + 0x7def9f1e, 0xd3870e8f, 0x5d6d69b5, 0xf305f824, 0xdacd4cd6, + 0x74a5dd47, 0x895c2532, 0x2734b4a3, 0x0efc0051, 0xa09491c0, + 0xc859c864, 0x663159f5, 0x4ff9ed07, 0xe1917c96, 0x1c6884e3, + 0xb2001572, 0x9bc8a180, 0x35a03011, 0xbb4a572b, 0x1522c6ba, + 0x3cea7248, 0x9282e3d9, 0x6f7b1bac, 0xc1138a3d, 0xe8db3ecf, + 0x46b3af5e, 0x39418d87, 0x97291c16, 0xbee1a8e4, 0x10893975, + 0xed70c100, 0x43185091, 0x6ad0e463, 0xc4b875f2, 0x4a5212c8, + 0xe43a8359, 0xcdf237ab, 0x639aa63a, 0x9e635e4f, 0x300bcfde, + 0x19c37b2c, 0xb7abeabd, 0xdf66b319, 0x710e2288, 0x58c6967a, + 0xf6ae07eb, 0x0b57ff9e, 0xa53f6e0f, 0x8cf7dafd, 0x229f4b6c, + 0xac752c56, 0x021dbdc7, 0x2bd50935, 0x85bd98a4, 0x784460d1, + 0xd62cf140, 0xffe445b2, 0x518cd423, 0x5cfdedf4, 0xf2957c65, + 0xdb5dc897, 0x75355906, 0x88cca173, 0x26a430e2, 0x0f6c8410, + 0xa1041581, 0x2fee72bb, 0x8186e32a, 0xa84e57d8, 0x0626c649, + 0xfbdf3e3c, 0x55b7afad, 0x7c7f1b5f, 0xd2178ace, 0xbadad36a, + 0x14b242fb, 0x3d7af609, 0x93126798, 0x6eeb9fed, 0xc0830e7c, + 0xe94bba8e, 0x47232b1f, 0xc9c94c25, 0x67a1ddb4, 0x4e696946, + 0xe001f8d7, 0x1df800a2, 0xb3909133, 0x9a5825c1, 0x3430b450, + 0x4bc29689, 0xe5aa0718, 0xcc62b3ea, 0x620a227b, 0x9ff3da0e, + 0x319b4b9f, 0x1853ff6d, 0xb63b6efc, 0x38d109c6, 0x96b99857, + 0xbf712ca5, 0x1119bd34, 0xece04541, 0x4288d4d0, 0x6b406022, + 0xc528f1b3, 0xade5a817, 0x038d3986, 0x2a458d74, 0x842d1ce5, + 0x79d4e490, 0xd7bc7501, 0xfe74c1f3, 0x501c5062, 0xdef63758, + 0x709ea6c9, 0x5956123b, 0xf73e83aa, 0x0ac77bdf, 0xa4afea4e, + 0x8d675ebc, 0x230fcf2d, 0x72831b0e, 0xdceb8a9f, 0xf5233e6d, + 0x5b4baffc, 0xa6b25789, 0x08dac618, 0x211272ea, 0x8f7ae37b, + 0x01908441, 0xaff815d0, 0x8630a122, 0x285830b3, 0xd5a1c8c6, + 0x7bc95957, 0x5201eda5, 0xfc697c34, 0x94a42590, 0x3accb401, + 0x130400f3, 0xbd6c9162, 0x40956917, 0xeefdf886, 0xc7354c74, + 0x695ddde5, 0xe7b7badf, 0x49df2b4e, 0x60179fbc, 0xce7f0e2d, + 0x3386f658, 0x9dee67c9, 0xb426d33b, 0x1a4e42aa, 0x65bc6073, + 0xcbd4f1e2, 0xe21c4510, 0x4c74d481, 0xb18d2cf4, 0x1fe5bd65, + 0x362d0997, 0x98459806, 0x16afff3c, 0xb8c76ead, 0x910fda5f, + 0x3f674bce, 0xc29eb3bb, 0x6cf6222a, 0x453e96d8, 0xeb560749, + 0x839b5eed, 0x2df3cf7c, 0x043b7b8e, 0xaa53ea1f, 0x57aa126a, + 0xf9c283fb, 0xd00a3709, 0x7e62a698, 0xf088c1a2, 0x5ee05033, + 0x7728e4c1, 0xd9407550, 0x24b98d25, 0x8ad11cb4, 0xa319a846, + 0x0d7139d7}, + {0x00000000, 0xb9fbdbe8, 0xa886b191, 0x117d6a79, 0x8a7c6563, + 0x3387be8b, 0x22fad4f2, 0x9b010f1a, 0xcf89cc87, 0x7672176f, + 0x670f7d16, 0xdef4a6fe, 0x45f5a9e4, 0xfc0e720c, 0xed731875, + 0x5488c39d, 0x44629f4f, 0xfd9944a7, 0xece42ede, 0x551ff536, + 0xce1efa2c, 0x77e521c4, 0x66984bbd, 0xdf639055, 0x8beb53c8, + 0x32108820, 0x236de259, 0x9a9639b1, 0x019736ab, 0xb86ced43, + 0xa911873a, 0x10ea5cd2, 0x88c53e9e, 0x313ee576, 0x20438f0f, + 0x99b854e7, 0x02b95bfd, 0xbb428015, 0xaa3fea6c, 0x13c43184, + 0x474cf219, 0xfeb729f1, 0xefca4388, 0x56319860, 0xcd30977a, + 0x74cb4c92, 0x65b626eb, 0xdc4dfd03, 0xcca7a1d1, 0x755c7a39, + 0x64211040, 0xdddacba8, 0x46dbc4b2, 0xff201f5a, 0xee5d7523, + 0x57a6aecb, 0x032e6d56, 0xbad5b6be, 0xaba8dcc7, 0x1253072f, + 0x89520835, 0x30a9d3dd, 0x21d4b9a4, 0x982f624c, 0xcafb7b7d, + 0x7300a095, 0x627dcaec, 0xdb861104, 0x40871e1e, 0xf97cc5f6, + 0xe801af8f, 0x51fa7467, 0x0572b7fa, 0xbc896c12, 0xadf4066b, + 0x140fdd83, 0x8f0ed299, 0x36f50971, 0x27886308, 0x9e73b8e0, + 0x8e99e432, 0x37623fda, 0x261f55a3, 0x9fe48e4b, 0x04e58151, + 0xbd1e5ab9, 0xac6330c0, 0x1598eb28, 0x411028b5, 0xf8ebf35d, + 0xe9969924, 0x506d42cc, 0xcb6c4dd6, 0x7297963e, 0x63eafc47, + 0xda1127af, 0x423e45e3, 0xfbc59e0b, 0xeab8f472, 0x53432f9a, + 0xc8422080, 0x71b9fb68, 0x60c49111, 0xd93f4af9, 0x8db78964, + 0x344c528c, 0x253138f5, 0x9ccae31d, 0x07cbec07, 0xbe3037ef, + 0xaf4d5d96, 0x16b6867e, 0x065cdaac, 0xbfa70144, 0xaeda6b3d, + 0x1721b0d5, 0x8c20bfcf, 0x35db6427, 0x24a60e5e, 0x9d5dd5b6, + 0xc9d5162b, 0x702ecdc3, 0x6153a7ba, 0xd8a87c52, 0x43a97348, + 0xfa52a8a0, 0xeb2fc2d9, 0x52d41931, 0x4e87f0bb, 0xf77c2b53, + 0xe601412a, 0x5ffa9ac2, 0xc4fb95d8, 0x7d004e30, 0x6c7d2449, + 0xd586ffa1, 0x810e3c3c, 0x38f5e7d4, 0x29888dad, 0x90735645, + 0x0b72595f, 0xb28982b7, 0xa3f4e8ce, 0x1a0f3326, 0x0ae56ff4, + 0xb31eb41c, 0xa263de65, 0x1b98058d, 0x80990a97, 0x3962d17f, + 0x281fbb06, 0x91e460ee, 0xc56ca373, 0x7c97789b, 0x6dea12e2, + 0xd411c90a, 0x4f10c610, 0xf6eb1df8, 0xe7967781, 0x5e6dac69, + 0xc642ce25, 0x7fb915cd, 0x6ec47fb4, 0xd73fa45c, 0x4c3eab46, + 0xf5c570ae, 0xe4b81ad7, 0x5d43c13f, 0x09cb02a2, 0xb030d94a, + 0xa14db333, 0x18b668db, 0x83b767c1, 0x3a4cbc29, 0x2b31d650, + 0x92ca0db8, 0x8220516a, 0x3bdb8a82, 0x2aa6e0fb, 0x935d3b13, + 0x085c3409, 0xb1a7efe1, 0xa0da8598, 0x19215e70, 0x4da99ded, + 0xf4524605, 0xe52f2c7c, 0x5cd4f794, 0xc7d5f88e, 0x7e2e2366, + 0x6f53491f, 0xd6a892f7, 0x847c8bc6, 0x3d87502e, 0x2cfa3a57, + 0x9501e1bf, 0x0e00eea5, 0xb7fb354d, 0xa6865f34, 0x1f7d84dc, + 0x4bf54741, 0xf20e9ca9, 0xe373f6d0, 0x5a882d38, 0xc1892222, + 0x7872f9ca, 0x690f93b3, 0xd0f4485b, 0xc01e1489, 0x79e5cf61, + 0x6898a518, 0xd1637ef0, 0x4a6271ea, 0xf399aa02, 0xe2e4c07b, + 0x5b1f1b93, 0x0f97d80e, 0xb66c03e6, 0xa711699f, 0x1eeab277, + 0x85ebbd6d, 0x3c106685, 0x2d6d0cfc, 0x9496d714, 0x0cb9b558, + 0xb5426eb0, 0xa43f04c9, 0x1dc4df21, 0x86c5d03b, 0x3f3e0bd3, + 0x2e4361aa, 0x97b8ba42, 0xc33079df, 0x7acba237, 0x6bb6c84e, + 0xd24d13a6, 0x494c1cbc, 0xf0b7c754, 0xe1caad2d, 0x583176c5, + 0x48db2a17, 0xf120f1ff, 0xe05d9b86, 0x59a6406e, 0xc2a74f74, + 0x7b5c949c, 0x6a21fee5, 0xd3da250d, 0x8752e690, 0x3ea93d78, + 0x2fd45701, 0x962f8ce9, 0x0d2e83f3, 0xb4d5581b, 0xa5a83262, + 0x1c53e98a}, + {0x00000000, 0x9d0fe176, 0xe16ec4ad, 0x7c6125db, 0x19ac8f1b, + 0x84a36e6d, 0xf8c24bb6, 0x65cdaac0, 0x33591e36, 0xae56ff40, + 0xd237da9b, 0x4f383bed, 0x2af5912d, 0xb7fa705b, 0xcb9b5580, + 0x5694b4f6, 0x66b23c6c, 0xfbbddd1a, 0x87dcf8c1, 0x1ad319b7, + 0x7f1eb377, 0xe2115201, 0x9e7077da, 0x037f96ac, 0x55eb225a, + 0xc8e4c32c, 0xb485e6f7, 0x298a0781, 0x4c47ad41, 0xd1484c37, + 0xad2969ec, 0x3026889a, 0xcd6478d8, 0x506b99ae, 0x2c0abc75, + 0xb1055d03, 0xd4c8f7c3, 0x49c716b5, 0x35a6336e, 0xa8a9d218, + 0xfe3d66ee, 0x63328798, 0x1f53a243, 0x825c4335, 0xe791e9f5, + 0x7a9e0883, 0x06ff2d58, 0x9bf0cc2e, 0xabd644b4, 0x36d9a5c2, + 0x4ab88019, 0xd7b7616f, 0xb27acbaf, 0x2f752ad9, 0x53140f02, + 0xce1bee74, 0x988f5a82, 0x0580bbf4, 0x79e19e2f, 0xe4ee7f59, + 0x8123d599, 0x1c2c34ef, 0x604d1134, 0xfd42f042, 0x41b9f7f1, + 0xdcb61687, 0xa0d7335c, 0x3dd8d22a, 0x581578ea, 0xc51a999c, + 0xb97bbc47, 0x24745d31, 0x72e0e9c7, 0xefef08b1, 0x938e2d6a, + 0x0e81cc1c, 0x6b4c66dc, 0xf64387aa, 0x8a22a271, 0x172d4307, + 0x270bcb9d, 0xba042aeb, 0xc6650f30, 0x5b6aee46, 0x3ea74486, + 0xa3a8a5f0, 0xdfc9802b, 0x42c6615d, 0x1452d5ab, 0x895d34dd, + 0xf53c1106, 0x6833f070, 0x0dfe5ab0, 0x90f1bbc6, 0xec909e1d, + 0x719f7f6b, 0x8cdd8f29, 0x11d26e5f, 0x6db34b84, 0xf0bcaaf2, + 0x95710032, 0x087ee144, 0x741fc49f, 0xe91025e9, 0xbf84911f, + 0x228b7069, 0x5eea55b2, 0xc3e5b4c4, 0xa6281e04, 0x3b27ff72, + 0x4746daa9, 0xda493bdf, 0xea6fb345, 0x77605233, 0x0b0177e8, + 0x960e969e, 0xf3c33c5e, 0x6eccdd28, 0x12adf8f3, 0x8fa21985, + 0xd936ad73, 0x44394c05, 0x385869de, 0xa55788a8, 0xc09a2268, + 0x5d95c31e, 0x21f4e6c5, 0xbcfb07b3, 0x8373efe2, 0x1e7c0e94, + 0x621d2b4f, 0xff12ca39, 0x9adf60f9, 0x07d0818f, 0x7bb1a454, + 0xe6be4522, 0xb02af1d4, 0x2d2510a2, 0x51443579, 0xcc4bd40f, + 0xa9867ecf, 0x34899fb9, 0x48e8ba62, 0xd5e75b14, 0xe5c1d38e, + 0x78ce32f8, 0x04af1723, 0x99a0f655, 0xfc6d5c95, 0x6162bde3, + 0x1d039838, 0x800c794e, 0xd698cdb8, 0x4b972cce, 0x37f60915, + 0xaaf9e863, 0xcf3442a3, 0x523ba3d5, 0x2e5a860e, 0xb3556778, + 0x4e17973a, 0xd318764c, 0xaf795397, 0x3276b2e1, 0x57bb1821, + 0xcab4f957, 0xb6d5dc8c, 0x2bda3dfa, 0x7d4e890c, 0xe041687a, + 0x9c204da1, 0x012facd7, 0x64e20617, 0xf9ede761, 0x858cc2ba, + 0x188323cc, 0x28a5ab56, 0xb5aa4a20, 0xc9cb6ffb, 0x54c48e8d, + 0x3109244d, 0xac06c53b, 0xd067e0e0, 0x4d680196, 0x1bfcb560, + 0x86f35416, 0xfa9271cd, 0x679d90bb, 0x02503a7b, 0x9f5fdb0d, + 0xe33efed6, 0x7e311fa0, 0xc2ca1813, 0x5fc5f965, 0x23a4dcbe, + 0xbeab3dc8, 0xdb669708, 0x4669767e, 0x3a0853a5, 0xa707b2d3, + 0xf1930625, 0x6c9ce753, 0x10fdc288, 0x8df223fe, 0xe83f893e, + 0x75306848, 0x09514d93, 0x945eace5, 0xa478247f, 0x3977c509, + 0x4516e0d2, 0xd81901a4, 0xbdd4ab64, 0x20db4a12, 0x5cba6fc9, + 0xc1b58ebf, 0x97213a49, 0x0a2edb3f, 0x764ffee4, 0xeb401f92, + 0x8e8db552, 0x13825424, 0x6fe371ff, 0xf2ec9089, 0x0fae60cb, + 0x92a181bd, 0xeec0a466, 0x73cf4510, 0x1602efd0, 0x8b0d0ea6, + 0xf76c2b7d, 0x6a63ca0b, 0x3cf77efd, 0xa1f89f8b, 0xdd99ba50, + 0x40965b26, 0x255bf1e6, 0xb8541090, 0xc435354b, 0x593ad43d, + 0x691c5ca7, 0xf413bdd1, 0x8872980a, 0x157d797c, 0x70b0d3bc, + 0xedbf32ca, 0x91de1711, 0x0cd1f667, 0x5a454291, 0xc74aa3e7, + 0xbb2b863c, 0x2624674a, 0x43e9cd8a, 0xdee62cfc, 0xa2870927, + 0x3f88e851}, + {0x00000000, 0xdd96d985, 0x605cb54b, 0xbdca6cce, 0xc0b96a96, + 0x1d2fb313, 0xa0e5dfdd, 0x7d730658, 0x5a03d36d, 0x87950ae8, + 0x3a5f6626, 0xe7c9bfa3, 0x9abab9fb, 0x472c607e, 0xfae60cb0, + 0x2770d535, 0xb407a6da, 0x69917f5f, 0xd45b1391, 0x09cdca14, + 0x74becc4c, 0xa92815c9, 0x14e27907, 0xc974a082, 0xee0475b7, + 0x3392ac32, 0x8e58c0fc, 0x53ce1979, 0x2ebd1f21, 0xf32bc6a4, + 0x4ee1aa6a, 0x937773ef, 0xb37e4bf5, 0x6ee89270, 0xd322febe, + 0x0eb4273b, 0x73c72163, 0xae51f8e6, 0x139b9428, 0xce0d4dad, + 0xe97d9898, 0x34eb411d, 0x89212dd3, 0x54b7f456, 0x29c4f20e, + 0xf4522b8b, 0x49984745, 0x940e9ec0, 0x0779ed2f, 0xdaef34aa, + 0x67255864, 0xbab381e1, 0xc7c087b9, 0x1a565e3c, 0xa79c32f2, + 0x7a0aeb77, 0x5d7a3e42, 0x80ece7c7, 0x3d268b09, 0xe0b0528c, + 0x9dc354d4, 0x40558d51, 0xfd9fe19f, 0x2009381a, 0xbd8d91ab, + 0x601b482e, 0xddd124e0, 0x0047fd65, 0x7d34fb3d, 0xa0a222b8, + 0x1d684e76, 0xc0fe97f3, 0xe78e42c6, 0x3a189b43, 0x87d2f78d, + 0x5a442e08, 0x27372850, 0xfaa1f1d5, 0x476b9d1b, 0x9afd449e, + 0x098a3771, 0xd41ceef4, 0x69d6823a, 0xb4405bbf, 0xc9335de7, + 0x14a58462, 0xa96fe8ac, 0x74f93129, 0x5389e41c, 0x8e1f3d99, + 0x33d55157, 0xee4388d2, 0x93308e8a, 0x4ea6570f, 0xf36c3bc1, + 0x2efae244, 0x0ef3da5e, 0xd36503db, 0x6eaf6f15, 0xb339b690, + 0xce4ab0c8, 0x13dc694d, 0xae160583, 0x7380dc06, 0x54f00933, + 0x8966d0b6, 0x34acbc78, 0xe93a65fd, 0x944963a5, 0x49dfba20, + 0xf415d6ee, 0x29830f6b, 0xbaf47c84, 0x6762a501, 0xdaa8c9cf, + 0x073e104a, 0x7a4d1612, 0xa7dbcf97, 0x1a11a359, 0xc7877adc, + 0xe0f7afe9, 0x3d61766c, 0x80ab1aa2, 0x5d3dc327, 0x204ec57f, + 0xfdd81cfa, 0x40127034, 0x9d84a9b1, 0xa06a2517, 0x7dfcfc92, + 0xc036905c, 0x1da049d9, 0x60d34f81, 0xbd459604, 0x008ffaca, + 0xdd19234f, 0xfa69f67a, 0x27ff2fff, 0x9a354331, 0x47a39ab4, + 0x3ad09cec, 0xe7464569, 0x5a8c29a7, 0x871af022, 0x146d83cd, + 0xc9fb5a48, 0x74313686, 0xa9a7ef03, 0xd4d4e95b, 0x094230de, + 0xb4885c10, 0x691e8595, 0x4e6e50a0, 0x93f88925, 0x2e32e5eb, + 0xf3a43c6e, 0x8ed73a36, 0x5341e3b3, 0xee8b8f7d, 0x331d56f8, + 0x13146ee2, 0xce82b767, 0x7348dba9, 0xaede022c, 0xd3ad0474, + 0x0e3bddf1, 0xb3f1b13f, 0x6e6768ba, 0x4917bd8f, 0x9481640a, + 0x294b08c4, 0xf4ddd141, 0x89aed719, 0x54380e9c, 0xe9f26252, + 0x3464bbd7, 0xa713c838, 0x7a8511bd, 0xc74f7d73, 0x1ad9a4f6, + 0x67aaa2ae, 0xba3c7b2b, 0x07f617e5, 0xda60ce60, 0xfd101b55, + 0x2086c2d0, 0x9d4cae1e, 0x40da779b, 0x3da971c3, 0xe03fa846, + 0x5df5c488, 0x80631d0d, 0x1de7b4bc, 0xc0716d39, 0x7dbb01f7, + 0xa02dd872, 0xdd5ede2a, 0x00c807af, 0xbd026b61, 0x6094b2e4, + 0x47e467d1, 0x9a72be54, 0x27b8d29a, 0xfa2e0b1f, 0x875d0d47, + 0x5acbd4c2, 0xe701b80c, 0x3a976189, 0xa9e01266, 0x7476cbe3, + 0xc9bca72d, 0x142a7ea8, 0x695978f0, 0xb4cfa175, 0x0905cdbb, + 0xd493143e, 0xf3e3c10b, 0x2e75188e, 0x93bf7440, 0x4e29adc5, + 0x335aab9d, 0xeecc7218, 0x53061ed6, 0x8e90c753, 0xae99ff49, + 0x730f26cc, 0xcec54a02, 0x13539387, 0x6e2095df, 0xb3b64c5a, + 0x0e7c2094, 0xd3eaf911, 0xf49a2c24, 0x290cf5a1, 0x94c6996f, + 0x495040ea, 0x342346b2, 0xe9b59f37, 0x547ff3f9, 0x89e92a7c, + 0x1a9e5993, 0xc7088016, 0x7ac2ecd8, 0xa754355d, 0xda273305, + 0x07b1ea80, 0xba7b864e, 0x67ed5fcb, 0x409d8afe, 0x9d0b537b, + 0x20c13fb5, 0xfd57e630, 0x8024e068, 0x5db239ed, 0xe0785523, + 0x3dee8ca6}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x85d996dd, 0x4bb55c60, 0xce6ccabd, 0x966ab9c0, + 0x13b32f1d, 0xdddfe5a0, 0x5806737d, 0x6dd3035a, 0xe80a9587, + 0x26665f3a, 0xa3bfc9e7, 0xfbb9ba9a, 0x7e602c47, 0xb00ce6fa, + 0x35d57027, 0xdaa607b4, 0x5f7f9169, 0x91135bd4, 0x14cacd09, + 0x4cccbe74, 0xc91528a9, 0x0779e214, 0x82a074c9, 0xb77504ee, + 0x32ac9233, 0xfcc0588e, 0x7919ce53, 0x211fbd2e, 0xa4c62bf3, + 0x6aaae14e, 0xef737793, 0xf54b7eb3, 0x7092e86e, 0xbefe22d3, + 0x3b27b40e, 0x6321c773, 0xe6f851ae, 0x28949b13, 0xad4d0dce, + 0x98987de9, 0x1d41eb34, 0xd32d2189, 0x56f4b754, 0x0ef2c429, + 0x8b2b52f4, 0x45479849, 0xc09e0e94, 0x2fed7907, 0xaa34efda, + 0x64582567, 0xe181b3ba, 0xb987c0c7, 0x3c5e561a, 0xf2329ca7, + 0x77eb0a7a, 0x423e7a5d, 0xc7e7ec80, 0x098b263d, 0x8c52b0e0, + 0xd454c39d, 0x518d5540, 0x9fe19ffd, 0x1a380920, 0xab918dbd, + 0x2e481b60, 0xe024d1dd, 0x65fd4700, 0x3dfb347d, 0xb822a2a0, + 0x764e681d, 0xf397fec0, 0xc6428ee7, 0x439b183a, 0x8df7d287, + 0x082e445a, 0x50283727, 0xd5f1a1fa, 0x1b9d6b47, 0x9e44fd9a, + 0x71378a09, 0xf4ee1cd4, 0x3a82d669, 0xbf5b40b4, 0xe75d33c9, + 0x6284a514, 0xace86fa9, 0x2931f974, 0x1ce48953, 0x993d1f8e, + 0x5751d533, 0xd28843ee, 0x8a8e3093, 0x0f57a64e, 0xc13b6cf3, + 0x44e2fa2e, 0x5edaf30e, 0xdb0365d3, 0x156faf6e, 0x90b639b3, + 0xc8b04ace, 0x4d69dc13, 0x830516ae, 0x06dc8073, 0x3309f054, + 0xb6d06689, 0x78bcac34, 0xfd653ae9, 0xa5634994, 0x20badf49, + 0xeed615f4, 0x6b0f8329, 0x847cf4ba, 0x01a56267, 0xcfc9a8da, + 0x4a103e07, 0x12164d7a, 0x97cfdba7, 0x59a3111a, 0xdc7a87c7, + 0xe9aff7e0, 0x6c76613d, 0xa21aab80, 0x27c33d5d, 0x7fc54e20, + 0xfa1cd8fd, 0x34701240, 0xb1a9849d, 0x17256aa0, 0x92fcfc7d, + 0x5c9036c0, 0xd949a01d, 0x814fd360, 0x049645bd, 0xcafa8f00, + 0x4f2319dd, 0x7af669fa, 0xff2fff27, 0x3143359a, 0xb49aa347, + 0xec9cd03a, 0x694546e7, 0xa7298c5a, 0x22f01a87, 0xcd836d14, + 0x485afbc9, 0x86363174, 0x03efa7a9, 0x5be9d4d4, 0xde304209, + 0x105c88b4, 0x95851e69, 0xa0506e4e, 0x2589f893, 0xebe5322e, + 0x6e3ca4f3, 0x363ad78e, 0xb3e34153, 0x7d8f8bee, 0xf8561d33, + 0xe26e1413, 0x67b782ce, 0xa9db4873, 0x2c02deae, 0x7404add3, + 0xf1dd3b0e, 0x3fb1f1b3, 0xba68676e, 0x8fbd1749, 0x0a648194, + 0xc4084b29, 0x41d1ddf4, 0x19d7ae89, 0x9c0e3854, 0x5262f2e9, + 0xd7bb6434, 0x38c813a7, 0xbd11857a, 0x737d4fc7, 0xf6a4d91a, + 0xaea2aa67, 0x2b7b3cba, 0xe517f607, 0x60ce60da, 0x551b10fd, + 0xd0c28620, 0x1eae4c9d, 0x9b77da40, 0xc371a93d, 0x46a83fe0, + 0x88c4f55d, 0x0d1d6380, 0xbcb4e71d, 0x396d71c0, 0xf701bb7d, + 0x72d82da0, 0x2ade5edd, 0xaf07c800, 0x616b02bd, 0xe4b29460, + 0xd167e447, 0x54be729a, 0x9ad2b827, 0x1f0b2efa, 0x470d5d87, + 0xc2d4cb5a, 0x0cb801e7, 0x8961973a, 0x6612e0a9, 0xe3cb7674, + 0x2da7bcc9, 0xa87e2a14, 0xf0785969, 0x75a1cfb4, 0xbbcd0509, + 0x3e1493d4, 0x0bc1e3f3, 0x8e18752e, 0x4074bf93, 0xc5ad294e, + 0x9dab5a33, 0x1872ccee, 0xd61e0653, 0x53c7908e, 0x49ff99ae, + 0xcc260f73, 0x024ac5ce, 0x87935313, 0xdf95206e, 0x5a4cb6b3, + 0x94207c0e, 0x11f9ead3, 0x242c9af4, 0xa1f50c29, 0x6f99c694, + 0xea405049, 0xb2462334, 0x379fb5e9, 0xf9f37f54, 0x7c2ae989, + 0x93599e1a, 0x168008c7, 0xd8ecc27a, 0x5d3554a7, 0x053327da, + 0x80eab107, 0x4e867bba, 0xcb5fed67, 0xfe8a9d40, 0x7b530b9d, + 0xb53fc120, 0x30e657fd, 0x68e02480, 0xed39b25d, 0x235578e0, + 0xa68cee3d}, + {0x00000000, 0x76e10f9d, 0xadc46ee1, 0xdb25617c, 0x1b8fac19, + 0x6d6ea384, 0xb64bc2f8, 0xc0aacd65, 0x361e5933, 0x40ff56ae, + 0x9bda37d2, 0xed3b384f, 0x2d91f52a, 0x5b70fab7, 0x80559bcb, + 0xf6b49456, 0x6c3cb266, 0x1addbdfb, 0xc1f8dc87, 0xb719d31a, + 0x77b31e7f, 0x015211e2, 0xda77709e, 0xac967f03, 0x5a22eb55, + 0x2cc3e4c8, 0xf7e685b4, 0x81078a29, 0x41ad474c, 0x374c48d1, + 0xec6929ad, 0x9a882630, 0xd87864cd, 0xae996b50, 0x75bc0a2c, + 0x035d05b1, 0xc3f7c8d4, 0xb516c749, 0x6e33a635, 0x18d2a9a8, + 0xee663dfe, 0x98873263, 0x43a2531f, 0x35435c82, 0xf5e991e7, + 0x83089e7a, 0x582dff06, 0x2eccf09b, 0xb444d6ab, 0xc2a5d936, + 0x1980b84a, 0x6f61b7d7, 0xafcb7ab2, 0xd92a752f, 0x020f1453, + 0x74ee1bce, 0x825a8f98, 0xf4bb8005, 0x2f9ee179, 0x597feee4, + 0x99d52381, 0xef342c1c, 0x34114d60, 0x42f042fd, 0xf1f7b941, + 0x8716b6dc, 0x5c33d7a0, 0x2ad2d83d, 0xea781558, 0x9c991ac5, + 0x47bc7bb9, 0x315d7424, 0xc7e9e072, 0xb108efef, 0x6a2d8e93, + 0x1ccc810e, 0xdc664c6b, 0xaa8743f6, 0x71a2228a, 0x07432d17, + 0x9dcb0b27, 0xeb2a04ba, 0x300f65c6, 0x46ee6a5b, 0x8644a73e, + 0xf0a5a8a3, 0x2b80c9df, 0x5d61c642, 0xabd55214, 0xdd345d89, + 0x06113cf5, 0x70f03368, 0xb05afe0d, 0xc6bbf190, 0x1d9e90ec, + 0x6b7f9f71, 0x298fdd8c, 0x5f6ed211, 0x844bb36d, 0xf2aabcf0, + 0x32007195, 0x44e17e08, 0x9fc41f74, 0xe92510e9, 0x1f9184bf, + 0x69708b22, 0xb255ea5e, 0xc4b4e5c3, 0x041e28a6, 0x72ff273b, + 0xa9da4647, 0xdf3b49da, 0x45b36fea, 0x33526077, 0xe877010b, + 0x9e960e96, 0x5e3cc3f3, 0x28ddcc6e, 0xf3f8ad12, 0x8519a28f, + 0x73ad36d9, 0x054c3944, 0xde695838, 0xa88857a5, 0x68229ac0, + 0x1ec3955d, 0xc5e6f421, 0xb307fbbc, 0xe2ef7383, 0x940e7c1e, + 0x4f2b1d62, 0x39ca12ff, 0xf960df9a, 0x8f81d007, 0x54a4b17b, + 0x2245bee6, 0xd4f12ab0, 0xa210252d, 0x79354451, 0x0fd44bcc, + 0xcf7e86a9, 0xb99f8934, 0x62bae848, 0x145be7d5, 0x8ed3c1e5, + 0xf832ce78, 0x2317af04, 0x55f6a099, 0x955c6dfc, 0xe3bd6261, + 0x3898031d, 0x4e790c80, 0xb8cd98d6, 0xce2c974b, 0x1509f637, + 0x63e8f9aa, 0xa34234cf, 0xd5a33b52, 0x0e865a2e, 0x786755b3, + 0x3a97174e, 0x4c7618d3, 0x975379af, 0xe1b27632, 0x2118bb57, + 0x57f9b4ca, 0x8cdcd5b6, 0xfa3dda2b, 0x0c894e7d, 0x7a6841e0, + 0xa14d209c, 0xd7ac2f01, 0x1706e264, 0x61e7edf9, 0xbac28c85, + 0xcc238318, 0x56aba528, 0x204aaab5, 0xfb6fcbc9, 0x8d8ec454, + 0x4d240931, 0x3bc506ac, 0xe0e067d0, 0x9601684d, 0x60b5fc1b, + 0x1654f386, 0xcd7192fa, 0xbb909d67, 0x7b3a5002, 0x0ddb5f9f, + 0xd6fe3ee3, 0xa01f317e, 0x1318cac2, 0x65f9c55f, 0xbedca423, + 0xc83dabbe, 0x089766db, 0x7e766946, 0xa553083a, 0xd3b207a7, + 0x250693f1, 0x53e79c6c, 0x88c2fd10, 0xfe23f28d, 0x3e893fe8, + 0x48683075, 0x934d5109, 0xe5ac5e94, 0x7f2478a4, 0x09c57739, + 0xd2e01645, 0xa40119d8, 0x64abd4bd, 0x124adb20, 0xc96fba5c, + 0xbf8eb5c1, 0x493a2197, 0x3fdb2e0a, 0xe4fe4f76, 0x921f40eb, + 0x52b58d8e, 0x24548213, 0xff71e36f, 0x8990ecf2, 0xcb60ae0f, + 0xbd81a192, 0x66a4c0ee, 0x1045cf73, 0xd0ef0216, 0xa60e0d8b, + 0x7d2b6cf7, 0x0bca636a, 0xfd7ef73c, 0x8b9ff8a1, 0x50ba99dd, + 0x265b9640, 0xe6f15b25, 0x901054b8, 0x4b3535c4, 0x3dd43a59, + 0xa75c1c69, 0xd1bd13f4, 0x0a987288, 0x7c797d15, 0xbcd3b070, + 0xca32bfed, 0x1117de91, 0x67f6d10c, 0x9142455a, 0xe7a34ac7, + 0x3c862bbb, 0x4a672426, 0x8acde943, 0xfc2ce6de, 0x270987a2, + 0x51e8883f}, + {0x00000000, 0xe8dbfbb9, 0x91b186a8, 0x796a7d11, 0x63657c8a, + 0x8bbe8733, 0xf2d4fa22, 0x1a0f019b, 0x87cc89cf, 0x6f177276, + 0x167d0f67, 0xfea6f4de, 0xe4a9f545, 0x0c720efc, 0x751873ed, + 0x9dc38854, 0x4f9f6244, 0xa74499fd, 0xde2ee4ec, 0x36f51f55, + 0x2cfa1ece, 0xc421e577, 0xbd4b9866, 0x559063df, 0xc853eb8b, + 0x20881032, 0x59e26d23, 0xb139969a, 0xab369701, 0x43ed6cb8, + 0x3a8711a9, 0xd25cea10, 0x9e3ec588, 0x76e53e31, 0x0f8f4320, + 0xe754b899, 0xfd5bb902, 0x158042bb, 0x6cea3faa, 0x8431c413, + 0x19f24c47, 0xf129b7fe, 0x8843caef, 0x60983156, 0x7a9730cd, + 0x924ccb74, 0xeb26b665, 0x03fd4ddc, 0xd1a1a7cc, 0x397a5c75, + 0x40102164, 0xa8cbdadd, 0xb2c4db46, 0x5a1f20ff, 0x23755dee, + 0xcbaea657, 0x566d2e03, 0xbeb6d5ba, 0xc7dca8ab, 0x2f075312, + 0x35085289, 0xddd3a930, 0xa4b9d421, 0x4c622f98, 0x7d7bfbca, + 0x95a00073, 0xecca7d62, 0x041186db, 0x1e1e8740, 0xf6c57cf9, + 0x8faf01e8, 0x6774fa51, 0xfab77205, 0x126c89bc, 0x6b06f4ad, + 0x83dd0f14, 0x99d20e8f, 0x7109f536, 0x08638827, 0xe0b8739e, + 0x32e4998e, 0xda3f6237, 0xa3551f26, 0x4b8ee49f, 0x5181e504, + 0xb95a1ebd, 0xc03063ac, 0x28eb9815, 0xb5281041, 0x5df3ebf8, + 0x249996e9, 0xcc426d50, 0xd64d6ccb, 0x3e969772, 0x47fcea63, + 0xaf2711da, 0xe3453e42, 0x0b9ec5fb, 0x72f4b8ea, 0x9a2f4353, + 0x802042c8, 0x68fbb971, 0x1191c460, 0xf94a3fd9, 0x6489b78d, + 0x8c524c34, 0xf5383125, 0x1de3ca9c, 0x07eccb07, 0xef3730be, + 0x965d4daf, 0x7e86b616, 0xacda5c06, 0x4401a7bf, 0x3d6bdaae, + 0xd5b02117, 0xcfbf208c, 0x2764db35, 0x5e0ea624, 0xb6d55d9d, + 0x2b16d5c9, 0xc3cd2e70, 0xbaa75361, 0x527ca8d8, 0x4873a943, + 0xa0a852fa, 0xd9c22feb, 0x3119d452, 0xbbf0874e, 0x532b7cf7, + 0x2a4101e6, 0xc29afa5f, 0xd895fbc4, 0x304e007d, 0x49247d6c, + 0xa1ff86d5, 0x3c3c0e81, 0xd4e7f538, 0xad8d8829, 0x45567390, + 0x5f59720b, 0xb78289b2, 0xcee8f4a3, 0x26330f1a, 0xf46fe50a, + 0x1cb41eb3, 0x65de63a2, 0x8d05981b, 0x970a9980, 0x7fd16239, + 0x06bb1f28, 0xee60e491, 0x73a36cc5, 0x9b78977c, 0xe212ea6d, + 0x0ac911d4, 0x10c6104f, 0xf81debf6, 0x817796e7, 0x69ac6d5e, + 0x25ce42c6, 0xcd15b97f, 0xb47fc46e, 0x5ca43fd7, 0x46ab3e4c, + 0xae70c5f5, 0xd71ab8e4, 0x3fc1435d, 0xa202cb09, 0x4ad930b0, + 0x33b34da1, 0xdb68b618, 0xc167b783, 0x29bc4c3a, 0x50d6312b, + 0xb80dca92, 0x6a512082, 0x828adb3b, 0xfbe0a62a, 0x133b5d93, + 0x09345c08, 0xe1efa7b1, 0x9885daa0, 0x705e2119, 0xed9da94d, + 0x054652f4, 0x7c2c2fe5, 0x94f7d45c, 0x8ef8d5c7, 0x66232e7e, + 0x1f49536f, 0xf792a8d6, 0xc68b7c84, 0x2e50873d, 0x573afa2c, + 0xbfe10195, 0xa5ee000e, 0x4d35fbb7, 0x345f86a6, 0xdc847d1f, + 0x4147f54b, 0xa99c0ef2, 0xd0f673e3, 0x382d885a, 0x222289c1, + 0xcaf97278, 0xb3930f69, 0x5b48f4d0, 0x89141ec0, 0x61cfe579, + 0x18a59868, 0xf07e63d1, 0xea71624a, 0x02aa99f3, 0x7bc0e4e2, + 0x931b1f5b, 0x0ed8970f, 0xe6036cb6, 0x9f6911a7, 0x77b2ea1e, + 0x6dbdeb85, 0x8566103c, 0xfc0c6d2d, 0x14d79694, 0x58b5b90c, + 0xb06e42b5, 0xc9043fa4, 0x21dfc41d, 0x3bd0c586, 0xd30b3e3f, + 0xaa61432e, 0x42bab897, 0xdf7930c3, 0x37a2cb7a, 0x4ec8b66b, + 0xa6134dd2, 0xbc1c4c49, 0x54c7b7f0, 0x2dadcae1, 0xc5763158, + 0x172adb48, 0xfff120f1, 0x869b5de0, 0x6e40a659, 0x744fa7c2, + 0x9c945c7b, 0xe5fe216a, 0x0d25dad3, 0x90e65287, 0x783da93e, + 0x0157d42f, 0xe98c2f96, 0xf3832e0d, 0x1b58d5b4, 0x6232a8a5, + 0x8ae9531c}, + {0x00000000, 0x919168ae, 0x6325a087, 0xf2b4c829, 0x874c31d4, + 0x16dd597a, 0xe4699153, 0x75f8f9fd, 0x4f9f1373, 0xde0e7bdd, + 0x2cbab3f4, 0xbd2bdb5a, 0xc8d322a7, 0x59424a09, 0xabf68220, + 0x3a67ea8e, 0x9e3e27e6, 0x0faf4f48, 0xfd1b8761, 0x6c8aefcf, + 0x19721632, 0x88e37e9c, 0x7a57b6b5, 0xebc6de1b, 0xd1a13495, + 0x40305c3b, 0xb2849412, 0x2315fcbc, 0x56ed0541, 0xc77c6def, + 0x35c8a5c6, 0xa459cd68, 0x7d7b3f17, 0xecea57b9, 0x1e5e9f90, + 0x8fcff73e, 0xfa370ec3, 0x6ba6666d, 0x9912ae44, 0x0883c6ea, + 0x32e42c64, 0xa37544ca, 0x51c18ce3, 0xc050e44d, 0xb5a81db0, + 0x2439751e, 0xd68dbd37, 0x471cd599, 0xe34518f1, 0x72d4705f, + 0x8060b876, 0x11f1d0d8, 0x64092925, 0xf598418b, 0x072c89a2, + 0x96bde10c, 0xacda0b82, 0x3d4b632c, 0xcfffab05, 0x5e6ec3ab, + 0x2b963a56, 0xba0752f8, 0x48b39ad1, 0xd922f27f, 0xfaf67e2e, + 0x6b671680, 0x99d3dea9, 0x0842b607, 0x7dba4ffa, 0xec2b2754, + 0x1e9fef7d, 0x8f0e87d3, 0xb5696d5d, 0x24f805f3, 0xd64ccdda, + 0x47dda574, 0x32255c89, 0xa3b43427, 0x5100fc0e, 0xc09194a0, + 0x64c859c8, 0xf5593166, 0x07edf94f, 0x967c91e1, 0xe384681c, + 0x721500b2, 0x80a1c89b, 0x1130a035, 0x2b574abb, 0xbac62215, + 0x4872ea3c, 0xd9e38292, 0xac1b7b6f, 0x3d8a13c1, 0xcf3edbe8, + 0x5eafb346, 0x878d4139, 0x161c2997, 0xe4a8e1be, 0x75398910, + 0x00c170ed, 0x91501843, 0x63e4d06a, 0xf275b8c4, 0xc812524a, + 0x59833ae4, 0xab37f2cd, 0x3aa69a63, 0x4f5e639e, 0xdecf0b30, + 0x2c7bc319, 0xbdeaabb7, 0x19b366df, 0x88220e71, 0x7a96c658, + 0xeb07aef6, 0x9eff570b, 0x0f6e3fa5, 0xfddaf78c, 0x6c4b9f22, + 0x562c75ac, 0xc7bd1d02, 0x3509d52b, 0xa498bd85, 0xd1604478, + 0x40f12cd6, 0xb245e4ff, 0x23d48c51, 0xf4edfd5c, 0x657c95f2, + 0x97c85ddb, 0x06593575, 0x73a1cc88, 0xe230a426, 0x10846c0f, + 0x811504a1, 0xbb72ee2f, 0x2ae38681, 0xd8574ea8, 0x49c62606, + 0x3c3edffb, 0xadafb755, 0x5f1b7f7c, 0xce8a17d2, 0x6ad3daba, + 0xfb42b214, 0x09f67a3d, 0x98671293, 0xed9feb6e, 0x7c0e83c0, + 0x8eba4be9, 0x1f2b2347, 0x254cc9c9, 0xb4dda167, 0x4669694e, + 0xd7f801e0, 0xa200f81d, 0x339190b3, 0xc125589a, 0x50b43034, + 0x8996c24b, 0x1807aae5, 0xeab362cc, 0x7b220a62, 0x0edaf39f, + 0x9f4b9b31, 0x6dff5318, 0xfc6e3bb6, 0xc609d138, 0x5798b996, + 0xa52c71bf, 0x34bd1911, 0x4145e0ec, 0xd0d48842, 0x2260406b, + 0xb3f128c5, 0x17a8e5ad, 0x86398d03, 0x748d452a, 0xe51c2d84, + 0x90e4d479, 0x0175bcd7, 0xf3c174fe, 0x62501c50, 0x5837f6de, + 0xc9a69e70, 0x3b125659, 0xaa833ef7, 0xdf7bc70a, 0x4eeaafa4, + 0xbc5e678d, 0x2dcf0f23, 0x0e1b8372, 0x9f8aebdc, 0x6d3e23f5, + 0xfcaf4b5b, 0x8957b2a6, 0x18c6da08, 0xea721221, 0x7be37a8f, + 0x41849001, 0xd015f8af, 0x22a13086, 0xb3305828, 0xc6c8a1d5, + 0x5759c97b, 0xa5ed0152, 0x347c69fc, 0x9025a494, 0x01b4cc3a, + 0xf3000413, 0x62916cbd, 0x17699540, 0x86f8fdee, 0x744c35c7, + 0xe5dd5d69, 0xdfbab7e7, 0x4e2bdf49, 0xbc9f1760, 0x2d0e7fce, + 0x58f68633, 0xc967ee9d, 0x3bd326b4, 0xaa424e1a, 0x7360bc65, + 0xe2f1d4cb, 0x10451ce2, 0x81d4744c, 0xf42c8db1, 0x65bde51f, + 0x97092d36, 0x06984598, 0x3cffaf16, 0xad6ec7b8, 0x5fda0f91, + 0xce4b673f, 0xbbb39ec2, 0x2a22f66c, 0xd8963e45, 0x490756eb, + 0xed5e9b83, 0x7ccff32d, 0x8e7b3b04, 0x1fea53aa, 0x6a12aa57, + 0xfb83c2f9, 0x09370ad0, 0x98a6627e, 0xa2c188f0, 0x3350e05e, + 0xc1e42877, 0x507540d9, 0x258db924, 0xb41cd18a, 0x46a819a3, + 0xd739710d}}; + +#endif + +#endif + +#if N == 5 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xaf449247, 0x85f822cf, 0x2abcb088, 0xd08143df, + 0x7fc5d198, 0x55796110, 0xfa3df357, 0x7a7381ff, 0xd53713b8, + 0xff8ba330, 0x50cf3177, 0xaaf2c220, 0x05b65067, 0x2f0ae0ef, + 0x804e72a8, 0xf4e703fe, 0x5ba391b9, 0x711f2131, 0xde5bb376, + 0x24664021, 0x8b22d266, 0xa19e62ee, 0x0edaf0a9, 0x8e948201, + 0x21d01046, 0x0b6ca0ce, 0xa4283289, 0x5e15c1de, 0xf1515399, + 0xdbede311, 0x74a97156, 0x32bf01bd, 0x9dfb93fa, 0xb7472372, + 0x1803b135, 0xe23e4262, 0x4d7ad025, 0x67c660ad, 0xc882f2ea, + 0x48cc8042, 0xe7881205, 0xcd34a28d, 0x627030ca, 0x984dc39d, + 0x370951da, 0x1db5e152, 0xb2f17315, 0xc6580243, 0x691c9004, + 0x43a0208c, 0xece4b2cb, 0x16d9419c, 0xb99dd3db, 0x93216353, + 0x3c65f114, 0xbc2b83bc, 0x136f11fb, 0x39d3a173, 0x96973334, + 0x6caac063, 0xc3ee5224, 0xe952e2ac, 0x461670eb, 0x657e037a, + 0xca3a913d, 0xe08621b5, 0x4fc2b3f2, 0xb5ff40a5, 0x1abbd2e2, + 0x3007626a, 0x9f43f02d, 0x1f0d8285, 0xb04910c2, 0x9af5a04a, + 0x35b1320d, 0xcf8cc15a, 0x60c8531d, 0x4a74e395, 0xe53071d2, + 0x91990084, 0x3edd92c3, 0x1461224b, 0xbb25b00c, 0x4118435b, + 0xee5cd11c, 0xc4e06194, 0x6ba4f3d3, 0xebea817b, 0x44ae133c, + 0x6e12a3b4, 0xc15631f3, 0x3b6bc2a4, 0x942f50e3, 0xbe93e06b, + 0x11d7722c, 0x57c102c7, 0xf8859080, 0xd2392008, 0x7d7db24f, + 0x87404118, 0x2804d35f, 0x02b863d7, 0xadfcf190, 0x2db28338, + 0x82f6117f, 0xa84aa1f7, 0x070e33b0, 0xfd33c0e7, 0x527752a0, + 0x78cbe228, 0xd78f706f, 0xa3260139, 0x0c62937e, 0x26de23f6, + 0x899ab1b1, 0x73a742e6, 0xdce3d0a1, 0xf65f6029, 0x591bf26e, + 0xd95580c6, 0x76111281, 0x5cada209, 0xf3e9304e, 0x09d4c319, + 0xa690515e, 0x8c2ce1d6, 0x23687391, 0xcafc06f4, 0x65b894b3, + 0x4f04243b, 0xe040b67c, 0x1a7d452b, 0xb539d76c, 0x9f8567e4, + 0x30c1f5a3, 0xb08f870b, 0x1fcb154c, 0x3577a5c4, 0x9a333783, + 0x600ec4d4, 0xcf4a5693, 0xe5f6e61b, 0x4ab2745c, 0x3e1b050a, + 0x915f974d, 0xbbe327c5, 0x14a7b582, 0xee9a46d5, 0x41ded492, + 0x6b62641a, 0xc426f65d, 0x446884f5, 0xeb2c16b2, 0xc190a63a, + 0x6ed4347d, 0x94e9c72a, 0x3bad556d, 0x1111e5e5, 0xbe5577a2, + 0xf8430749, 0x5707950e, 0x7dbb2586, 0xd2ffb7c1, 0x28c24496, + 0x8786d6d1, 0xad3a6659, 0x027ef41e, 0x823086b6, 0x2d7414f1, + 0x07c8a479, 0xa88c363e, 0x52b1c569, 0xfdf5572e, 0xd749e7a6, + 0x780d75e1, 0x0ca404b7, 0xa3e096f0, 0x895c2678, 0x2618b43f, + 0xdc254768, 0x7361d52f, 0x59dd65a7, 0xf699f7e0, 0x76d78548, + 0xd993170f, 0xf32fa787, 0x5c6b35c0, 0xa656c697, 0x091254d0, + 0x23aee458, 0x8cea761f, 0xaf82058e, 0x00c697c9, 0x2a7a2741, + 0x853eb506, 0x7f034651, 0xd047d416, 0xfafb649e, 0x55bff6d9, + 0xd5f18471, 0x7ab51636, 0x5009a6be, 0xff4d34f9, 0x0570c7ae, + 0xaa3455e9, 0x8088e561, 0x2fcc7726, 0x5b650670, 0xf4219437, + 0xde9d24bf, 0x71d9b6f8, 0x8be445af, 0x24a0d7e8, 0x0e1c6760, + 0xa158f527, 0x2116878f, 0x8e5215c8, 0xa4eea540, 0x0baa3707, + 0xf197c450, 0x5ed35617, 0x746fe69f, 0xdb2b74d8, 0x9d3d0433, + 0x32799674, 0x18c526fc, 0xb781b4bb, 0x4dbc47ec, 0xe2f8d5ab, + 0xc8446523, 0x6700f764, 0xe74e85cc, 0x480a178b, 0x62b6a703, + 0xcdf23544, 0x37cfc613, 0x988b5454, 0xb237e4dc, 0x1d73769b, + 0x69da07cd, 0xc69e958a, 0xec222502, 0x4366b745, 0xb95b4412, + 0x161fd655, 0x3ca366dd, 0x93e7f49a, 0x13a98632, 0xbced1475, + 0x9651a4fd, 0x391536ba, 0xc328c5ed, 0x6c6c57aa, 0x46d0e722, + 0xe9947565}, + {0x00000000, 0x4e890ba9, 0x9d121752, 0xd39b1cfb, 0xe15528e5, + 0xafdc234c, 0x7c473fb7, 0x32ce341e, 0x19db578b, 0x57525c22, + 0x84c940d9, 0xca404b70, 0xf88e7f6e, 0xb60774c7, 0x659c683c, + 0x2b156395, 0x33b6af16, 0x7d3fa4bf, 0xaea4b844, 0xe02db3ed, + 0xd2e387f3, 0x9c6a8c5a, 0x4ff190a1, 0x01789b08, 0x2a6df89d, + 0x64e4f334, 0xb77fefcf, 0xf9f6e466, 0xcb38d078, 0x85b1dbd1, + 0x562ac72a, 0x18a3cc83, 0x676d5e2c, 0x29e45585, 0xfa7f497e, + 0xb4f642d7, 0x863876c9, 0xc8b17d60, 0x1b2a619b, 0x55a36a32, + 0x7eb609a7, 0x303f020e, 0xe3a41ef5, 0xad2d155c, 0x9fe32142, + 0xd16a2aeb, 0x02f13610, 0x4c783db9, 0x54dbf13a, 0x1a52fa93, + 0xc9c9e668, 0x8740edc1, 0xb58ed9df, 0xfb07d276, 0x289cce8d, + 0x6615c524, 0x4d00a6b1, 0x0389ad18, 0xd012b1e3, 0x9e9bba4a, + 0xac558e54, 0xe2dc85fd, 0x31479906, 0x7fce92af, 0xcedabc58, + 0x8053b7f1, 0x53c8ab0a, 0x1d41a0a3, 0x2f8f94bd, 0x61069f14, + 0xb29d83ef, 0xfc148846, 0xd701ebd3, 0x9988e07a, 0x4a13fc81, + 0x049af728, 0x3654c336, 0x78ddc89f, 0xab46d464, 0xe5cfdfcd, + 0xfd6c134e, 0xb3e518e7, 0x607e041c, 0x2ef70fb5, 0x1c393bab, + 0x52b03002, 0x812b2cf9, 0xcfa22750, 0xe4b744c5, 0xaa3e4f6c, + 0x79a55397, 0x372c583e, 0x05e26c20, 0x4b6b6789, 0x98f07b72, + 0xd67970db, 0xa9b7e274, 0xe73ee9dd, 0x34a5f526, 0x7a2cfe8f, + 0x48e2ca91, 0x066bc138, 0xd5f0ddc3, 0x9b79d66a, 0xb06cb5ff, + 0xfee5be56, 0x2d7ea2ad, 0x63f7a904, 0x51399d1a, 0x1fb096b3, + 0xcc2b8a48, 0x82a281e1, 0x9a014d62, 0xd48846cb, 0x07135a30, + 0x499a5199, 0x7b546587, 0x35dd6e2e, 0xe64672d5, 0xa8cf797c, + 0x83da1ae9, 0xcd531140, 0x1ec80dbb, 0x50410612, 0x628f320c, + 0x2c0639a5, 0xff9d255e, 0xb1142ef7, 0x46c47ef1, 0x084d7558, + 0xdbd669a3, 0x955f620a, 0xa7915614, 0xe9185dbd, 0x3a834146, + 0x740a4aef, 0x5f1f297a, 0x119622d3, 0xc20d3e28, 0x8c843581, + 0xbe4a019f, 0xf0c30a36, 0x235816cd, 0x6dd11d64, 0x7572d1e7, + 0x3bfbda4e, 0xe860c6b5, 0xa6e9cd1c, 0x9427f902, 0xdaaef2ab, + 0x0935ee50, 0x47bce5f9, 0x6ca9866c, 0x22208dc5, 0xf1bb913e, + 0xbf329a97, 0x8dfcae89, 0xc375a520, 0x10eeb9db, 0x5e67b272, + 0x21a920dd, 0x6f202b74, 0xbcbb378f, 0xf2323c26, 0xc0fc0838, + 0x8e750391, 0x5dee1f6a, 0x136714c3, 0x38727756, 0x76fb7cff, + 0xa5606004, 0xebe96bad, 0xd9275fb3, 0x97ae541a, 0x443548e1, + 0x0abc4348, 0x121f8fcb, 0x5c968462, 0x8f0d9899, 0xc1849330, + 0xf34aa72e, 0xbdc3ac87, 0x6e58b07c, 0x20d1bbd5, 0x0bc4d840, + 0x454dd3e9, 0x96d6cf12, 0xd85fc4bb, 0xea91f0a5, 0xa418fb0c, + 0x7783e7f7, 0x390aec5e, 0x881ec2a9, 0xc697c900, 0x150cd5fb, + 0x5b85de52, 0x694bea4c, 0x27c2e1e5, 0xf459fd1e, 0xbad0f6b7, + 0x91c59522, 0xdf4c9e8b, 0x0cd78270, 0x425e89d9, 0x7090bdc7, + 0x3e19b66e, 0xed82aa95, 0xa30ba13c, 0xbba86dbf, 0xf5216616, + 0x26ba7aed, 0x68337144, 0x5afd455a, 0x14744ef3, 0xc7ef5208, + 0x896659a1, 0xa2733a34, 0xecfa319d, 0x3f612d66, 0x71e826cf, + 0x432612d1, 0x0daf1978, 0xde340583, 0x90bd0e2a, 0xef739c85, + 0xa1fa972c, 0x72618bd7, 0x3ce8807e, 0x0e26b460, 0x40afbfc9, + 0x9334a332, 0xddbda89b, 0xf6a8cb0e, 0xb821c0a7, 0x6bbadc5c, + 0x2533d7f5, 0x17fde3eb, 0x5974e842, 0x8aeff4b9, 0xc466ff10, + 0xdcc53393, 0x924c383a, 0x41d724c1, 0x0f5e2f68, 0x3d901b76, + 0x731910df, 0xa0820c24, 0xee0b078d, 0xc51e6418, 0x8b976fb1, + 0x580c734a, 0x168578e3, 0x244b4cfd, 0x6ac24754, 0xb9595baf, + 0xf7d05006}, + {0x00000000, 0x8d88fde2, 0xc060fd85, 0x4de80067, 0x5bb0fd4b, + 0xd63800a9, 0x9bd000ce, 0x1658fd2c, 0xb761fa96, 0x3ae90774, + 0x77010713, 0xfa89faf1, 0xecd107dd, 0x6159fa3f, 0x2cb1fa58, + 0xa13907ba, 0xb5b2f36d, 0x383a0e8f, 0x75d20ee8, 0xf85af30a, + 0xee020e26, 0x638af3c4, 0x2e62f3a3, 0xa3ea0e41, 0x02d309fb, + 0x8f5bf419, 0xc2b3f47e, 0x4f3b099c, 0x5963f4b0, 0xd4eb0952, + 0x99030935, 0x148bf4d7, 0xb014e09b, 0x3d9c1d79, 0x70741d1e, + 0xfdfce0fc, 0xeba41dd0, 0x662ce032, 0x2bc4e055, 0xa64c1db7, + 0x07751a0d, 0x8afde7ef, 0xc715e788, 0x4a9d1a6a, 0x5cc5e746, + 0xd14d1aa4, 0x9ca51ac3, 0x112de721, 0x05a613f6, 0x882eee14, + 0xc5c6ee73, 0x484e1391, 0x5e16eebd, 0xd39e135f, 0x9e761338, + 0x13feeeda, 0xb2c7e960, 0x3f4f1482, 0x72a714e5, 0xff2fe907, + 0xe977142b, 0x64ffe9c9, 0x2917e9ae, 0xa49f144c, 0xbb58c777, + 0x36d03a95, 0x7b383af2, 0xf6b0c710, 0xe0e83a3c, 0x6d60c7de, + 0x2088c7b9, 0xad003a5b, 0x0c393de1, 0x81b1c003, 0xcc59c064, + 0x41d13d86, 0x5789c0aa, 0xda013d48, 0x97e93d2f, 0x1a61c0cd, + 0x0eea341a, 0x8362c9f8, 0xce8ac99f, 0x4302347d, 0x555ac951, + 0xd8d234b3, 0x953a34d4, 0x18b2c936, 0xb98bce8c, 0x3403336e, + 0x79eb3309, 0xf463ceeb, 0xe23b33c7, 0x6fb3ce25, 0x225bce42, + 0xafd333a0, 0x0b4c27ec, 0x86c4da0e, 0xcb2cda69, 0x46a4278b, + 0x50fcdaa7, 0xdd742745, 0x909c2722, 0x1d14dac0, 0xbc2ddd7a, + 0x31a52098, 0x7c4d20ff, 0xf1c5dd1d, 0xe79d2031, 0x6a15ddd3, + 0x27fdddb4, 0xaa752056, 0xbefed481, 0x33762963, 0x7e9e2904, + 0xf316d4e6, 0xe54e29ca, 0x68c6d428, 0x252ed44f, 0xa8a629ad, + 0x099f2e17, 0x8417d3f5, 0xc9ffd392, 0x44772e70, 0x522fd35c, + 0xdfa72ebe, 0x924f2ed9, 0x1fc7d33b, 0xadc088af, 0x2048754d, + 0x6da0752a, 0xe02888c8, 0xf67075e4, 0x7bf88806, 0x36108861, + 0xbb987583, 0x1aa17239, 0x97298fdb, 0xdac18fbc, 0x5749725e, + 0x41118f72, 0xcc997290, 0x817172f7, 0x0cf98f15, 0x18727bc2, + 0x95fa8620, 0xd8128647, 0x559a7ba5, 0x43c28689, 0xce4a7b6b, + 0x83a27b0c, 0x0e2a86ee, 0xaf138154, 0x229b7cb6, 0x6f737cd1, + 0xe2fb8133, 0xf4a37c1f, 0x792b81fd, 0x34c3819a, 0xb94b7c78, + 0x1dd46834, 0x905c95d6, 0xddb495b1, 0x503c6853, 0x4664957f, + 0xcbec689d, 0x860468fa, 0x0b8c9518, 0xaab592a2, 0x273d6f40, + 0x6ad56f27, 0xe75d92c5, 0xf1056fe9, 0x7c8d920b, 0x3165926c, + 0xbced6f8e, 0xa8669b59, 0x25ee66bb, 0x680666dc, 0xe58e9b3e, + 0xf3d66612, 0x7e5e9bf0, 0x33b69b97, 0xbe3e6675, 0x1f0761cf, + 0x928f9c2d, 0xdf679c4a, 0x52ef61a8, 0x44b79c84, 0xc93f6166, + 0x84d76101, 0x095f9ce3, 0x16984fd8, 0x9b10b23a, 0xd6f8b25d, + 0x5b704fbf, 0x4d28b293, 0xc0a04f71, 0x8d484f16, 0x00c0b2f4, + 0xa1f9b54e, 0x2c7148ac, 0x619948cb, 0xec11b529, 0xfa494805, + 0x77c1b5e7, 0x3a29b580, 0xb7a14862, 0xa32abcb5, 0x2ea24157, + 0x634a4130, 0xeec2bcd2, 0xf89a41fe, 0x7512bc1c, 0x38fabc7b, + 0xb5724199, 0x144b4623, 0x99c3bbc1, 0xd42bbba6, 0x59a34644, + 0x4ffbbb68, 0xc273468a, 0x8f9b46ed, 0x0213bb0f, 0xa68caf43, + 0x2b0452a1, 0x66ec52c6, 0xeb64af24, 0xfd3c5208, 0x70b4afea, + 0x3d5caf8d, 0xb0d4526f, 0x11ed55d5, 0x9c65a837, 0xd18da850, + 0x5c0555b2, 0x4a5da89e, 0xc7d5557c, 0x8a3d551b, 0x07b5a8f9, + 0x133e5c2e, 0x9eb6a1cc, 0xd35ea1ab, 0x5ed65c49, 0x488ea165, + 0xc5065c87, 0x88ee5ce0, 0x0566a102, 0xa45fa6b8, 0x29d75b5a, + 0x643f5b3d, 0xe9b7a6df, 0xffef5bf3, 0x7267a611, 0x3f8fa676, + 0xb2075b94}, + {0x00000000, 0x80f0171f, 0xda91287f, 0x5a613f60, 0x6e5356bf, + 0xeea341a0, 0xb4c27ec0, 0x343269df, 0xdca6ad7e, 0x5c56ba61, + 0x06378501, 0x86c7921e, 0xb2f5fbc1, 0x3205ecde, 0x6864d3be, + 0xe894c4a1, 0x623c5cbd, 0xe2cc4ba2, 0xb8ad74c2, 0x385d63dd, + 0x0c6f0a02, 0x8c9f1d1d, 0xd6fe227d, 0x560e3562, 0xbe9af1c3, + 0x3e6ae6dc, 0x640bd9bc, 0xe4fbcea3, 0xd0c9a77c, 0x5039b063, + 0x0a588f03, 0x8aa8981c, 0xc478b97a, 0x4488ae65, 0x1ee99105, + 0x9e19861a, 0xaa2befc5, 0x2adbf8da, 0x70bac7ba, 0xf04ad0a5, + 0x18de1404, 0x982e031b, 0xc24f3c7b, 0x42bf2b64, 0x768d42bb, + 0xf67d55a4, 0xac1c6ac4, 0x2cec7ddb, 0xa644e5c7, 0x26b4f2d8, + 0x7cd5cdb8, 0xfc25daa7, 0xc817b378, 0x48e7a467, 0x12869b07, + 0x92768c18, 0x7ae248b9, 0xfa125fa6, 0xa07360c6, 0x208377d9, + 0x14b11e06, 0x94410919, 0xce203679, 0x4ed02166, 0x538074b5, + 0xd37063aa, 0x89115cca, 0x09e14bd5, 0x3dd3220a, 0xbd233515, + 0xe7420a75, 0x67b21d6a, 0x8f26d9cb, 0x0fd6ced4, 0x55b7f1b4, + 0xd547e6ab, 0xe1758f74, 0x6185986b, 0x3be4a70b, 0xbb14b014, + 0x31bc2808, 0xb14c3f17, 0xeb2d0077, 0x6bdd1768, 0x5fef7eb7, + 0xdf1f69a8, 0x857e56c8, 0x058e41d7, 0xed1a8576, 0x6dea9269, + 0x378bad09, 0xb77bba16, 0x8349d3c9, 0x03b9c4d6, 0x59d8fbb6, + 0xd928eca9, 0x97f8cdcf, 0x1708dad0, 0x4d69e5b0, 0xcd99f2af, + 0xf9ab9b70, 0x795b8c6f, 0x233ab30f, 0xa3caa410, 0x4b5e60b1, + 0xcbae77ae, 0x91cf48ce, 0x113f5fd1, 0x250d360e, 0xa5fd2111, + 0xff9c1e71, 0x7f6c096e, 0xf5c49172, 0x7534866d, 0x2f55b90d, + 0xafa5ae12, 0x9b97c7cd, 0x1b67d0d2, 0x4106efb2, 0xc1f6f8ad, + 0x29623c0c, 0xa9922b13, 0xf3f31473, 0x7303036c, 0x47316ab3, + 0xc7c17dac, 0x9da042cc, 0x1d5055d3, 0xa700e96a, 0x27f0fe75, + 0x7d91c115, 0xfd61d60a, 0xc953bfd5, 0x49a3a8ca, 0x13c297aa, + 0x933280b5, 0x7ba64414, 0xfb56530b, 0xa1376c6b, 0x21c77b74, + 0x15f512ab, 0x950505b4, 0xcf643ad4, 0x4f942dcb, 0xc53cb5d7, + 0x45cca2c8, 0x1fad9da8, 0x9f5d8ab7, 0xab6fe368, 0x2b9ff477, + 0x71fecb17, 0xf10edc08, 0x199a18a9, 0x996a0fb6, 0xc30b30d6, + 0x43fb27c9, 0x77c94e16, 0xf7395909, 0xad586669, 0x2da87176, + 0x63785010, 0xe388470f, 0xb9e9786f, 0x39196f70, 0x0d2b06af, + 0x8ddb11b0, 0xd7ba2ed0, 0x574a39cf, 0xbfdefd6e, 0x3f2eea71, + 0x654fd511, 0xe5bfc20e, 0xd18dabd1, 0x517dbcce, 0x0b1c83ae, + 0x8bec94b1, 0x01440cad, 0x81b41bb2, 0xdbd524d2, 0x5b2533cd, + 0x6f175a12, 0xefe74d0d, 0xb586726d, 0x35766572, 0xdde2a1d3, + 0x5d12b6cc, 0x077389ac, 0x87839eb3, 0xb3b1f76c, 0x3341e073, + 0x6920df13, 0xe9d0c80c, 0xf4809ddf, 0x74708ac0, 0x2e11b5a0, + 0xaee1a2bf, 0x9ad3cb60, 0x1a23dc7f, 0x4042e31f, 0xc0b2f400, + 0x282630a1, 0xa8d627be, 0xf2b718de, 0x72470fc1, 0x4675661e, + 0xc6857101, 0x9ce44e61, 0x1c14597e, 0x96bcc162, 0x164cd67d, + 0x4c2de91d, 0xccddfe02, 0xf8ef97dd, 0x781f80c2, 0x227ebfa2, + 0xa28ea8bd, 0x4a1a6c1c, 0xcaea7b03, 0x908b4463, 0x107b537c, + 0x24493aa3, 0xa4b92dbc, 0xfed812dc, 0x7e2805c3, 0x30f824a5, + 0xb00833ba, 0xea690cda, 0x6a991bc5, 0x5eab721a, 0xde5b6505, + 0x843a5a65, 0x04ca4d7a, 0xec5e89db, 0x6cae9ec4, 0x36cfa1a4, + 0xb63fb6bb, 0x820ddf64, 0x02fdc87b, 0x589cf71b, 0xd86ce004, + 0x52c47818, 0xd2346f07, 0x88555067, 0x08a54778, 0x3c972ea7, + 0xbc6739b8, 0xe60606d8, 0x66f611c7, 0x8e62d566, 0x0e92c279, + 0x54f3fd19, 0xd403ea06, 0xe03183d9, 0x60c194c6, 0x3aa0aba6, + 0xba50bcb9}, + {0x00000000, 0x9570d495, 0xf190af6b, 0x64e07bfe, 0x38505897, + 0xad208c02, 0xc9c0f7fc, 0x5cb02369, 0x70a0b12e, 0xe5d065bb, + 0x81301e45, 0x1440cad0, 0x48f0e9b9, 0xdd803d2c, 0xb96046d2, + 0x2c109247, 0xe141625c, 0x7431b6c9, 0x10d1cd37, 0x85a119a2, + 0xd9113acb, 0x4c61ee5e, 0x288195a0, 0xbdf14135, 0x91e1d372, + 0x049107e7, 0x60717c19, 0xf501a88c, 0xa9b18be5, 0x3cc15f70, + 0x5821248e, 0xcd51f01b, 0x19f3c2f9, 0x8c83166c, 0xe8636d92, + 0x7d13b907, 0x21a39a6e, 0xb4d34efb, 0xd0333505, 0x4543e190, + 0x695373d7, 0xfc23a742, 0x98c3dcbc, 0x0db30829, 0x51032b40, + 0xc473ffd5, 0xa093842b, 0x35e350be, 0xf8b2a0a5, 0x6dc27430, + 0x09220fce, 0x9c52db5b, 0xc0e2f832, 0x55922ca7, 0x31725759, + 0xa40283cc, 0x8812118b, 0x1d62c51e, 0x7982bee0, 0xecf26a75, + 0xb042491c, 0x25329d89, 0x41d2e677, 0xd4a232e2, 0x33e785f2, + 0xa6975167, 0xc2772a99, 0x5707fe0c, 0x0bb7dd65, 0x9ec709f0, + 0xfa27720e, 0x6f57a69b, 0x434734dc, 0xd637e049, 0xb2d79bb7, + 0x27a74f22, 0x7b176c4b, 0xee67b8de, 0x8a87c320, 0x1ff717b5, + 0xd2a6e7ae, 0x47d6333b, 0x233648c5, 0xb6469c50, 0xeaf6bf39, + 0x7f866bac, 0x1b661052, 0x8e16c4c7, 0xa2065680, 0x37768215, + 0x5396f9eb, 0xc6e62d7e, 0x9a560e17, 0x0f26da82, 0x6bc6a17c, + 0xfeb675e9, 0x2a14470b, 0xbf64939e, 0xdb84e860, 0x4ef43cf5, + 0x12441f9c, 0x8734cb09, 0xe3d4b0f7, 0x76a46462, 0x5ab4f625, + 0xcfc422b0, 0xab24594e, 0x3e548ddb, 0x62e4aeb2, 0xf7947a27, + 0x937401d9, 0x0604d54c, 0xcb552557, 0x5e25f1c2, 0x3ac58a3c, + 0xafb55ea9, 0xf3057dc0, 0x6675a955, 0x0295d2ab, 0x97e5063e, + 0xbbf59479, 0x2e8540ec, 0x4a653b12, 0xdf15ef87, 0x83a5ccee, + 0x16d5187b, 0x72356385, 0xe745b710, 0x67cf0be4, 0xf2bfdf71, + 0x965fa48f, 0x032f701a, 0x5f9f5373, 0xcaef87e6, 0xae0ffc18, + 0x3b7f288d, 0x176fbaca, 0x821f6e5f, 0xe6ff15a1, 0x738fc134, + 0x2f3fe25d, 0xba4f36c8, 0xdeaf4d36, 0x4bdf99a3, 0x868e69b8, + 0x13febd2d, 0x771ec6d3, 0xe26e1246, 0xbede312f, 0x2baee5ba, + 0x4f4e9e44, 0xda3e4ad1, 0xf62ed896, 0x635e0c03, 0x07be77fd, + 0x92cea368, 0xce7e8001, 0x5b0e5494, 0x3fee2f6a, 0xaa9efbff, + 0x7e3cc91d, 0xeb4c1d88, 0x8fac6676, 0x1adcb2e3, 0x466c918a, + 0xd31c451f, 0xb7fc3ee1, 0x228cea74, 0x0e9c7833, 0x9becaca6, + 0xff0cd758, 0x6a7c03cd, 0x36cc20a4, 0xa3bcf431, 0xc75c8fcf, + 0x522c5b5a, 0x9f7dab41, 0x0a0d7fd4, 0x6eed042a, 0xfb9dd0bf, + 0xa72df3d6, 0x325d2743, 0x56bd5cbd, 0xc3cd8828, 0xefdd1a6f, + 0x7aadcefa, 0x1e4db504, 0x8b3d6191, 0xd78d42f8, 0x42fd966d, + 0x261ded93, 0xb36d3906, 0x54288e16, 0xc1585a83, 0xa5b8217d, + 0x30c8f5e8, 0x6c78d681, 0xf9080214, 0x9de879ea, 0x0898ad7f, + 0x24883f38, 0xb1f8ebad, 0xd5189053, 0x406844c6, 0x1cd867af, + 0x89a8b33a, 0xed48c8c4, 0x78381c51, 0xb569ec4a, 0x201938df, + 0x44f94321, 0xd18997b4, 0x8d39b4dd, 0x18496048, 0x7ca91bb6, + 0xe9d9cf23, 0xc5c95d64, 0x50b989f1, 0x3459f20f, 0xa129269a, + 0xfd9905f3, 0x68e9d166, 0x0c09aa98, 0x99797e0d, 0x4ddb4cef, + 0xd8ab987a, 0xbc4be384, 0x293b3711, 0x758b1478, 0xe0fbc0ed, + 0x841bbb13, 0x116b6f86, 0x3d7bfdc1, 0xa80b2954, 0xcceb52aa, + 0x599b863f, 0x052ba556, 0x905b71c3, 0xf4bb0a3d, 0x61cbdea8, + 0xac9a2eb3, 0x39eafa26, 0x5d0a81d8, 0xc87a554d, 0x94ca7624, + 0x01baa2b1, 0x655ad94f, 0xf02a0dda, 0xdc3a9f9d, 0x494a4b08, + 0x2daa30f6, 0xb8dae463, 0xe46ac70a, 0x711a139f, 0x15fa6861, + 0x808abcf4}, + {0x00000000, 0xcf9e17c8, 0x444d29d1, 0x8bd33e19, 0x889a53a2, + 0x4704446a, 0xccd77a73, 0x03496dbb, 0xca45a105, 0x05dbb6cd, + 0x8e0888d4, 0x41969f1c, 0x42dff2a7, 0x8d41e56f, 0x0692db76, + 0xc90cccbe, 0x4ffa444b, 0x80645383, 0x0bb76d9a, 0xc4297a52, + 0xc76017e9, 0x08fe0021, 0x832d3e38, 0x4cb329f0, 0x85bfe54e, + 0x4a21f286, 0xc1f2cc9f, 0x0e6cdb57, 0x0d25b6ec, 0xc2bba124, + 0x49689f3d, 0x86f688f5, 0x9ff48896, 0x506a9f5e, 0xdbb9a147, + 0x1427b68f, 0x176edb34, 0xd8f0ccfc, 0x5323f2e5, 0x9cbde52d, + 0x55b12993, 0x9a2f3e5b, 0x11fc0042, 0xde62178a, 0xdd2b7a31, + 0x12b56df9, 0x996653e0, 0x56f84428, 0xd00eccdd, 0x1f90db15, + 0x9443e50c, 0x5bddf2c4, 0x58949f7f, 0x970a88b7, 0x1cd9b6ae, + 0xd347a166, 0x1a4b6dd8, 0xd5d57a10, 0x5e064409, 0x919853c1, + 0x92d13e7a, 0x5d4f29b2, 0xd69c17ab, 0x19020063, 0xe498176d, + 0x2b0600a5, 0xa0d53ebc, 0x6f4b2974, 0x6c0244cf, 0xa39c5307, + 0x284f6d1e, 0xe7d17ad6, 0x2eddb668, 0xe143a1a0, 0x6a909fb9, + 0xa50e8871, 0xa647e5ca, 0x69d9f202, 0xe20acc1b, 0x2d94dbd3, + 0xab625326, 0x64fc44ee, 0xef2f7af7, 0x20b16d3f, 0x23f80084, + 0xec66174c, 0x67b52955, 0xa82b3e9d, 0x6127f223, 0xaeb9e5eb, + 0x256adbf2, 0xeaf4cc3a, 0xe9bda181, 0x2623b649, 0xadf08850, + 0x626e9f98, 0x7b6c9ffb, 0xb4f28833, 0x3f21b62a, 0xf0bfa1e2, + 0xf3f6cc59, 0x3c68db91, 0xb7bbe588, 0x7825f240, 0xb1293efe, + 0x7eb72936, 0xf564172f, 0x3afa00e7, 0x39b36d5c, 0xf62d7a94, + 0x7dfe448d, 0xb2605345, 0x3496dbb0, 0xfb08cc78, 0x70dbf261, + 0xbf45e5a9, 0xbc0c8812, 0x73929fda, 0xf841a1c3, 0x37dfb60b, + 0xfed37ab5, 0x314d6d7d, 0xba9e5364, 0x750044ac, 0x76492917, + 0xb9d73edf, 0x320400c6, 0xfd9a170e, 0x1241289b, 0xdddf3f53, + 0x560c014a, 0x99921682, 0x9adb7b39, 0x55456cf1, 0xde9652e8, + 0x11084520, 0xd804899e, 0x179a9e56, 0x9c49a04f, 0x53d7b787, + 0x509eda3c, 0x9f00cdf4, 0x14d3f3ed, 0xdb4de425, 0x5dbb6cd0, + 0x92257b18, 0x19f64501, 0xd66852c9, 0xd5213f72, 0x1abf28ba, + 0x916c16a3, 0x5ef2016b, 0x97fecdd5, 0x5860da1d, 0xd3b3e404, + 0x1c2df3cc, 0x1f649e77, 0xd0fa89bf, 0x5b29b7a6, 0x94b7a06e, + 0x8db5a00d, 0x422bb7c5, 0xc9f889dc, 0x06669e14, 0x052ff3af, + 0xcab1e467, 0x4162da7e, 0x8efccdb6, 0x47f00108, 0x886e16c0, + 0x03bd28d9, 0xcc233f11, 0xcf6a52aa, 0x00f44562, 0x8b277b7b, + 0x44b96cb3, 0xc24fe446, 0x0dd1f38e, 0x8602cd97, 0x499cda5f, + 0x4ad5b7e4, 0x854ba02c, 0x0e989e35, 0xc10689fd, 0x080a4543, + 0xc794528b, 0x4c476c92, 0x83d97b5a, 0x809016e1, 0x4f0e0129, + 0xc4dd3f30, 0x0b4328f8, 0xf6d93ff6, 0x3947283e, 0xb2941627, + 0x7d0a01ef, 0x7e436c54, 0xb1dd7b9c, 0x3a0e4585, 0xf590524d, + 0x3c9c9ef3, 0xf302893b, 0x78d1b722, 0xb74fa0ea, 0xb406cd51, + 0x7b98da99, 0xf04be480, 0x3fd5f348, 0xb9237bbd, 0x76bd6c75, + 0xfd6e526c, 0x32f045a4, 0x31b9281f, 0xfe273fd7, 0x75f401ce, + 0xba6a1606, 0x7366dab8, 0xbcf8cd70, 0x372bf369, 0xf8b5e4a1, + 0xfbfc891a, 0x34629ed2, 0xbfb1a0cb, 0x702fb703, 0x692db760, + 0xa6b3a0a8, 0x2d609eb1, 0xe2fe8979, 0xe1b7e4c2, 0x2e29f30a, + 0xa5facd13, 0x6a64dadb, 0xa3681665, 0x6cf601ad, 0xe7253fb4, + 0x28bb287c, 0x2bf245c7, 0xe46c520f, 0x6fbf6c16, 0xa0217bde, + 0x26d7f32b, 0xe949e4e3, 0x629adafa, 0xad04cd32, 0xae4da089, + 0x61d3b741, 0xea008958, 0x259e9e90, 0xec92522e, 0x230c45e6, + 0xa8df7bff, 0x67416c37, 0x6408018c, 0xab961644, 0x2045285d, + 0xefdb3f95}, + {0x00000000, 0x24825136, 0x4904a26c, 0x6d86f35a, 0x920944d8, + 0xb68b15ee, 0xdb0de6b4, 0xff8fb782, 0xff638ff1, 0xdbe1dec7, + 0xb6672d9d, 0x92e57cab, 0x6d6acb29, 0x49e89a1f, 0x246e6945, + 0x00ec3873, 0x25b619a3, 0x01344895, 0x6cb2bbcf, 0x4830eaf9, + 0xb7bf5d7b, 0x933d0c4d, 0xfebbff17, 0xda39ae21, 0xdad59652, + 0xfe57c764, 0x93d1343e, 0xb7536508, 0x48dcd28a, 0x6c5e83bc, + 0x01d870e6, 0x255a21d0, 0x4b6c3346, 0x6fee6270, 0x0268912a, + 0x26eac01c, 0xd965779e, 0xfde726a8, 0x9061d5f2, 0xb4e384c4, + 0xb40fbcb7, 0x908ded81, 0xfd0b1edb, 0xd9894fed, 0x2606f86f, + 0x0284a959, 0x6f025a03, 0x4b800b35, 0x6eda2ae5, 0x4a587bd3, + 0x27de8889, 0x035cd9bf, 0xfcd36e3d, 0xd8513f0b, 0xb5d7cc51, + 0x91559d67, 0x91b9a514, 0xb53bf422, 0xd8bd0778, 0xfc3f564e, + 0x03b0e1cc, 0x2732b0fa, 0x4ab443a0, 0x6e361296, 0x96d8668c, + 0xb25a37ba, 0xdfdcc4e0, 0xfb5e95d6, 0x04d12254, 0x20537362, + 0x4dd58038, 0x6957d10e, 0x69bbe97d, 0x4d39b84b, 0x20bf4b11, + 0x043d1a27, 0xfbb2ada5, 0xdf30fc93, 0xb2b60fc9, 0x96345eff, + 0xb36e7f2f, 0x97ec2e19, 0xfa6add43, 0xdee88c75, 0x21673bf7, + 0x05e56ac1, 0x6863999b, 0x4ce1c8ad, 0x4c0df0de, 0x688fa1e8, + 0x050952b2, 0x218b0384, 0xde04b406, 0xfa86e530, 0x9700166a, + 0xb382475c, 0xddb455ca, 0xf93604fc, 0x94b0f7a6, 0xb032a690, + 0x4fbd1112, 0x6b3f4024, 0x06b9b37e, 0x223be248, 0x22d7da3b, + 0x06558b0d, 0x6bd37857, 0x4f512961, 0xb0de9ee3, 0x945ccfd5, + 0xf9da3c8f, 0xdd586db9, 0xf8024c69, 0xdc801d5f, 0xb106ee05, + 0x9584bf33, 0x6a0b08b1, 0x4e895987, 0x230faadd, 0x078dfbeb, + 0x0761c398, 0x23e392ae, 0x4e6561f4, 0x6ae730c2, 0x95688740, + 0xb1ead676, 0xdc6c252c, 0xf8ee741a, 0xf6c1cb59, 0xd2439a6f, + 0xbfc56935, 0x9b473803, 0x64c88f81, 0x404adeb7, 0x2dcc2ded, + 0x094e7cdb, 0x09a244a8, 0x2d20159e, 0x40a6e6c4, 0x6424b7f2, + 0x9bab0070, 0xbf295146, 0xd2afa21c, 0xf62df32a, 0xd377d2fa, + 0xf7f583cc, 0x9a737096, 0xbef121a0, 0x417e9622, 0x65fcc714, + 0x087a344e, 0x2cf86578, 0x2c145d0b, 0x08960c3d, 0x6510ff67, + 0x4192ae51, 0xbe1d19d3, 0x9a9f48e5, 0xf719bbbf, 0xd39bea89, + 0xbdadf81f, 0x992fa929, 0xf4a95a73, 0xd02b0b45, 0x2fa4bcc7, + 0x0b26edf1, 0x66a01eab, 0x42224f9d, 0x42ce77ee, 0x664c26d8, + 0x0bcad582, 0x2f4884b4, 0xd0c73336, 0xf4456200, 0x99c3915a, + 0xbd41c06c, 0x981be1bc, 0xbc99b08a, 0xd11f43d0, 0xf59d12e6, + 0x0a12a564, 0x2e90f452, 0x43160708, 0x6794563e, 0x67786e4d, + 0x43fa3f7b, 0x2e7ccc21, 0x0afe9d17, 0xf5712a95, 0xd1f37ba3, + 0xbc7588f9, 0x98f7d9cf, 0x6019add5, 0x449bfce3, 0x291d0fb9, + 0x0d9f5e8f, 0xf210e90d, 0xd692b83b, 0xbb144b61, 0x9f961a57, + 0x9f7a2224, 0xbbf87312, 0xd67e8048, 0xf2fcd17e, 0x0d7366fc, + 0x29f137ca, 0x4477c490, 0x60f595a6, 0x45afb476, 0x612de540, + 0x0cab161a, 0x2829472c, 0xd7a6f0ae, 0xf324a198, 0x9ea252c2, + 0xba2003f4, 0xbacc3b87, 0x9e4e6ab1, 0xf3c899eb, 0xd74ac8dd, + 0x28c57f5f, 0x0c472e69, 0x61c1dd33, 0x45438c05, 0x2b759e93, + 0x0ff7cfa5, 0x62713cff, 0x46f36dc9, 0xb97cda4b, 0x9dfe8b7d, + 0xf0787827, 0xd4fa2911, 0xd4161162, 0xf0944054, 0x9d12b30e, + 0xb990e238, 0x461f55ba, 0x629d048c, 0x0f1bf7d6, 0x2b99a6e0, + 0x0ec38730, 0x2a41d606, 0x47c7255c, 0x6345746a, 0x9ccac3e8, + 0xb84892de, 0xd5ce6184, 0xf14c30b2, 0xf1a008c1, 0xd52259f7, + 0xb8a4aaad, 0x9c26fb9b, 0x63a94c19, 0x472b1d2f, 0x2aadee75, + 0x0e2fbf43}, + {0x00000000, 0x36f290f3, 0x6de521e6, 0x5b17b115, 0xdbca43cc, + 0xed38d33f, 0xb62f622a, 0x80ddf2d9, 0x6ce581d9, 0x5a17112a, + 0x0100a03f, 0x37f230cc, 0xb72fc215, 0x81dd52e6, 0xdacae3f3, + 0xec387300, 0xd9cb03b2, 0xef399341, 0xb42e2254, 0x82dcb2a7, + 0x0201407e, 0x34f3d08d, 0x6fe46198, 0x5916f16b, 0xb52e826b, + 0x83dc1298, 0xd8cba38d, 0xee39337e, 0x6ee4c1a7, 0x58165154, + 0x0301e041, 0x35f370b2, 0x68e70125, 0x5e1591d6, 0x050220c3, + 0x33f0b030, 0xb32d42e9, 0x85dfd21a, 0xdec8630f, 0xe83af3fc, + 0x040280fc, 0x32f0100f, 0x69e7a11a, 0x5f1531e9, 0xdfc8c330, + 0xe93a53c3, 0xb22de2d6, 0x84df7225, 0xb12c0297, 0x87de9264, + 0xdcc92371, 0xea3bb382, 0x6ae6415b, 0x5c14d1a8, 0x070360bd, + 0x31f1f04e, 0xddc9834e, 0xeb3b13bd, 0xb02ca2a8, 0x86de325b, + 0x0603c082, 0x30f15071, 0x6be6e164, 0x5d147197, 0xd1ce024a, + 0xe73c92b9, 0xbc2b23ac, 0x8ad9b35f, 0x0a044186, 0x3cf6d175, + 0x67e16060, 0x5113f093, 0xbd2b8393, 0x8bd91360, 0xd0cea275, + 0xe63c3286, 0x66e1c05f, 0x501350ac, 0x0b04e1b9, 0x3df6714a, + 0x080501f8, 0x3ef7910b, 0x65e0201e, 0x5312b0ed, 0xd3cf4234, + 0xe53dd2c7, 0xbe2a63d2, 0x88d8f321, 0x64e08021, 0x521210d2, + 0x0905a1c7, 0x3ff73134, 0xbf2ac3ed, 0x89d8531e, 0xd2cfe20b, + 0xe43d72f8, 0xb929036f, 0x8fdb939c, 0xd4cc2289, 0xe23eb27a, + 0x62e340a3, 0x5411d050, 0x0f066145, 0x39f4f1b6, 0xd5cc82b6, + 0xe33e1245, 0xb829a350, 0x8edb33a3, 0x0e06c17a, 0x38f45189, + 0x63e3e09c, 0x5511706f, 0x60e200dd, 0x5610902e, 0x0d07213b, + 0x3bf5b1c8, 0xbb284311, 0x8ddad3e2, 0xd6cd62f7, 0xe03ff204, + 0x0c078104, 0x3af511f7, 0x61e2a0e2, 0x57103011, 0xd7cdc2c8, + 0xe13f523b, 0xba28e32e, 0x8cda73dd, 0x78ed02d5, 0x4e1f9226, + 0x15082333, 0x23fab3c0, 0xa3274119, 0x95d5d1ea, 0xcec260ff, + 0xf830f00c, 0x1408830c, 0x22fa13ff, 0x79eda2ea, 0x4f1f3219, + 0xcfc2c0c0, 0xf9305033, 0xa227e126, 0x94d571d5, 0xa1260167, + 0x97d49194, 0xccc32081, 0xfa31b072, 0x7aec42ab, 0x4c1ed258, + 0x1709634d, 0x21fbf3be, 0xcdc380be, 0xfb31104d, 0xa026a158, + 0x96d431ab, 0x1609c372, 0x20fb5381, 0x7bece294, 0x4d1e7267, + 0x100a03f0, 0x26f89303, 0x7def2216, 0x4b1db2e5, 0xcbc0403c, + 0xfd32d0cf, 0xa62561da, 0x90d7f129, 0x7cef8229, 0x4a1d12da, + 0x110aa3cf, 0x27f8333c, 0xa725c1e5, 0x91d75116, 0xcac0e003, + 0xfc3270f0, 0xc9c10042, 0xff3390b1, 0xa42421a4, 0x92d6b157, + 0x120b438e, 0x24f9d37d, 0x7fee6268, 0x491cf29b, 0xa524819b, + 0x93d61168, 0xc8c1a07d, 0xfe33308e, 0x7eeec257, 0x481c52a4, + 0x130be3b1, 0x25f97342, 0xa923009f, 0x9fd1906c, 0xc4c62179, + 0xf234b18a, 0x72e94353, 0x441bd3a0, 0x1f0c62b5, 0x29fef246, + 0xc5c68146, 0xf33411b5, 0xa823a0a0, 0x9ed13053, 0x1e0cc28a, + 0x28fe5279, 0x73e9e36c, 0x451b739f, 0x70e8032d, 0x461a93de, + 0x1d0d22cb, 0x2bffb238, 0xab2240e1, 0x9dd0d012, 0xc6c76107, + 0xf035f1f4, 0x1c0d82f4, 0x2aff1207, 0x71e8a312, 0x471a33e1, + 0xc7c7c138, 0xf13551cb, 0xaa22e0de, 0x9cd0702d, 0xc1c401ba, + 0xf7369149, 0xac21205c, 0x9ad3b0af, 0x1a0e4276, 0x2cfcd285, + 0x77eb6390, 0x4119f363, 0xad218063, 0x9bd31090, 0xc0c4a185, + 0xf6363176, 0x76ebc3af, 0x4019535c, 0x1b0ee249, 0x2dfc72ba, + 0x180f0208, 0x2efd92fb, 0x75ea23ee, 0x4318b31d, 0xc3c541c4, + 0xf537d137, 0xae206022, 0x98d2f0d1, 0x74ea83d1, 0x42181322, + 0x190fa237, 0x2ffd32c4, 0xaf20c01d, 0x99d250ee, 0xc2c5e1fb, + 0xf4377108}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0xf390f23600000000, 0xe621e56d00000000, + 0x15b1175b00000000, 0xcc43cadb00000000, 0x3fd338ed00000000, + 0x2a622fb600000000, 0xd9f2dd8000000000, 0xd981e56c00000000, + 0x2a11175a00000000, 0x3fa0000100000000, 0xcc30f23700000000, + 0x15c22fb700000000, 0xe652dd8100000000, 0xf3e3cada00000000, + 0x007338ec00000000, 0xb203cbd900000000, 0x419339ef00000000, + 0x54222eb400000000, 0xa7b2dc8200000000, 0x7e40010200000000, + 0x8dd0f33400000000, 0x9861e46f00000000, 0x6bf1165900000000, + 0x6b822eb500000000, 0x9812dc8300000000, 0x8da3cbd800000000, + 0x7e3339ee00000000, 0xa7c1e46e00000000, 0x5451165800000000, + 0x41e0010300000000, 0xb270f33500000000, 0x2501e76800000000, + 0xd691155e00000000, 0xc320020500000000, 0x30b0f03300000000, + 0xe9422db300000000, 0x1ad2df8500000000, 0x0f63c8de00000000, + 0xfcf33ae800000000, 0xfc80020400000000, 0x0f10f03200000000, + 0x1aa1e76900000000, 0xe931155f00000000, 0x30c3c8df00000000, + 0xc3533ae900000000, 0xd6e22db200000000, 0x2572df8400000000, + 0x97022cb100000000, 0x6492de8700000000, 0x7123c9dc00000000, + 0x82b33bea00000000, 0x5b41e66a00000000, 0xa8d1145c00000000, + 0xbd60030700000000, 0x4ef0f13100000000, 0x4e83c9dd00000000, + 0xbd133beb00000000, 0xa8a22cb000000000, 0x5b32de8600000000, + 0x82c0030600000000, 0x7150f13000000000, 0x64e1e66b00000000, + 0x9771145d00000000, 0x4a02ced100000000, 0xb9923ce700000000, + 0xac232bbc00000000, 0x5fb3d98a00000000, 0x8641040a00000000, + 0x75d1f63c00000000, 0x6060e16700000000, 0x93f0135100000000, + 0x93832bbd00000000, 0x6013d98b00000000, 0x75a2ced000000000, + 0x86323ce600000000, 0x5fc0e16600000000, 0xac50135000000000, + 0xb9e1040b00000000, 0x4a71f63d00000000, 0xf801050800000000, + 0x0b91f73e00000000, 0x1e20e06500000000, 0xedb0125300000000, + 0x3442cfd300000000, 0xc7d23de500000000, 0xd2632abe00000000, + 0x21f3d88800000000, 0x2180e06400000000, 0xd210125200000000, + 0xc7a1050900000000, 0x3431f73f00000000, 0xedc32abf00000000, + 0x1e53d88900000000, 0x0be2cfd200000000, 0xf8723de400000000, + 0x6f0329b900000000, 0x9c93db8f00000000, 0x8922ccd400000000, + 0x7ab23ee200000000, 0xa340e36200000000, 0x50d0115400000000, + 0x4561060f00000000, 0xb6f1f43900000000, 0xb682ccd500000000, + 0x45123ee300000000, 0x50a329b800000000, 0xa333db8e00000000, + 0x7ac1060e00000000, 0x8951f43800000000, 0x9ce0e36300000000, + 0x6f70115500000000, 0xdd00e26000000000, 0x2e90105600000000, + 0x3b21070d00000000, 0xc8b1f53b00000000, 0x114328bb00000000, + 0xe2d3da8d00000000, 0xf762cdd600000000, 0x04f23fe000000000, + 0x0481070c00000000, 0xf711f53a00000000, 0xe2a0e26100000000, + 0x1130105700000000, 0xc8c2cdd700000000, 0x3b523fe100000000, + 0x2ee328ba00000000, 0xdd73da8c00000000, 0xd502ed7800000000, + 0x26921f4e00000000, 0x3323081500000000, 0xc0b3fa2300000000, + 0x194127a300000000, 0xead1d59500000000, 0xff60c2ce00000000, + 0x0cf030f800000000, 0x0c83081400000000, 0xff13fa2200000000, + 0xeaa2ed7900000000, 0x19321f4f00000000, 0xc0c0c2cf00000000, + 0x335030f900000000, 0x26e127a200000000, 0xd571d59400000000, + 0x670126a100000000, 0x9491d49700000000, 0x8120c3cc00000000, + 0x72b031fa00000000, 0xab42ec7a00000000, 0x58d21e4c00000000, + 0x4d63091700000000, 0xbef3fb2100000000, 0xbe80c3cd00000000, + 0x4d1031fb00000000, 0x58a126a000000000, 0xab31d49600000000, + 0x72c3091600000000, 0x8153fb2000000000, 0x94e2ec7b00000000, + 0x67721e4d00000000, 0xf0030a1000000000, 0x0393f82600000000, + 0x1622ef7d00000000, 0xe5b21d4b00000000, 0x3c40c0cb00000000, + 0xcfd032fd00000000, 0xda6125a600000000, 0x29f1d79000000000, + 0x2982ef7c00000000, 0xda121d4a00000000, 0xcfa30a1100000000, + 0x3c33f82700000000, 0xe5c125a700000000, 0x1651d79100000000, + 0x03e0c0ca00000000, 0xf07032fc00000000, 0x4200c1c900000000, + 0xb19033ff00000000, 0xa42124a400000000, 0x57b1d69200000000, + 0x8e430b1200000000, 0x7dd3f92400000000, 0x6862ee7f00000000, + 0x9bf21c4900000000, 0x9b8124a500000000, 0x6811d69300000000, + 0x7da0c1c800000000, 0x8e3033fe00000000, 0x57c2ee7e00000000, + 0xa4521c4800000000, 0xb1e30b1300000000, 0x4273f92500000000, + 0x9f0023a900000000, 0x6c90d19f00000000, 0x7921c6c400000000, + 0x8ab134f200000000, 0x5343e97200000000, 0xa0d31b4400000000, + 0xb5620c1f00000000, 0x46f2fe2900000000, 0x4681c6c500000000, + 0xb51134f300000000, 0xa0a023a800000000, 0x5330d19e00000000, + 0x8ac20c1e00000000, 0x7952fe2800000000, 0x6ce3e97300000000, + 0x9f731b4500000000, 0x2d03e87000000000, 0xde931a4600000000, + 0xcb220d1d00000000, 0x38b2ff2b00000000, 0xe14022ab00000000, + 0x12d0d09d00000000, 0x0761c7c600000000, 0xf4f135f000000000, + 0xf4820d1c00000000, 0x0712ff2a00000000, 0x12a3e87100000000, + 0xe1331a4700000000, 0x38c1c7c700000000, 0xcb5135f100000000, + 0xdee022aa00000000, 0x2d70d09c00000000, 0xba01c4c100000000, + 0x499136f700000000, 0x5c2021ac00000000, 0xafb0d39a00000000, + 0x76420e1a00000000, 0x85d2fc2c00000000, 0x9063eb7700000000, + 0x63f3194100000000, 0x638021ad00000000, 0x9010d39b00000000, + 0x85a1c4c000000000, 0x763136f600000000, 0xafc3eb7600000000, + 0x5c53194000000000, 0x49e20e1b00000000, 0xba72fc2d00000000, + 0x08020f1800000000, 0xfb92fd2e00000000, 0xee23ea7500000000, + 0x1db3184300000000, 0xc441c5c300000000, 0x37d137f500000000, + 0x226020ae00000000, 0xd1f0d29800000000, 0xd183ea7400000000, + 0x2213184200000000, 0x37a20f1900000000, 0xc432fd2f00000000, + 0x1dc020af00000000, 0xee50d29900000000, 0xfbe1c5c200000000, + 0x087137f400000000}, + {0x0000000000000000, 0x3651822400000000, 0x6ca2044900000000, + 0x5af3866d00000000, 0xd844099200000000, 0xee158bb600000000, + 0xb4e60ddb00000000, 0x82b78fff00000000, 0xf18f63ff00000000, + 0xc7dee1db00000000, 0x9d2d67b600000000, 0xab7ce59200000000, + 0x29cb6a6d00000000, 0x1f9ae84900000000, 0x45696e2400000000, + 0x7338ec0000000000, 0xa319b62500000000, 0x9548340100000000, + 0xcfbbb26c00000000, 0xf9ea304800000000, 0x7b5dbfb700000000, + 0x4d0c3d9300000000, 0x17ffbbfe00000000, 0x21ae39da00000000, + 0x5296d5da00000000, 0x64c757fe00000000, 0x3e34d19300000000, + 0x086553b700000000, 0x8ad2dc4800000000, 0xbc835e6c00000000, + 0xe670d80100000000, 0xd0215a2500000000, 0x46336c4b00000000, + 0x7062ee6f00000000, 0x2a91680200000000, 0x1cc0ea2600000000, + 0x9e7765d900000000, 0xa826e7fd00000000, 0xf2d5619000000000, + 0xc484e3b400000000, 0xb7bc0fb400000000, 0x81ed8d9000000000, + 0xdb1e0bfd00000000, 0xed4f89d900000000, 0x6ff8062600000000, + 0x59a9840200000000, 0x035a026f00000000, 0x350b804b00000000, + 0xe52ada6e00000000, 0xd37b584a00000000, 0x8988de2700000000, + 0xbfd95c0300000000, 0x3d6ed3fc00000000, 0x0b3f51d800000000, + 0x51ccd7b500000000, 0x679d559100000000, 0x14a5b99100000000, + 0x22f43bb500000000, 0x7807bdd800000000, 0x4e563ffc00000000, + 0xcce1b00300000000, 0xfab0322700000000, 0xa043b44a00000000, + 0x9612366e00000000, 0x8c66d89600000000, 0xba375ab200000000, + 0xe0c4dcdf00000000, 0xd6955efb00000000, 0x5422d10400000000, + 0x6273532000000000, 0x3880d54d00000000, 0x0ed1576900000000, + 0x7de9bb6900000000, 0x4bb8394d00000000, 0x114bbf2000000000, + 0x271a3d0400000000, 0xa5adb2fb00000000, 0x93fc30df00000000, + 0xc90fb6b200000000, 0xff5e349600000000, 0x2f7f6eb300000000, + 0x192eec9700000000, 0x43dd6afa00000000, 0x758ce8de00000000, + 0xf73b672100000000, 0xc16ae50500000000, 0x9b99636800000000, + 0xadc8e14c00000000, 0xdef00d4c00000000, 0xe8a18f6800000000, + 0xb252090500000000, 0x84038b2100000000, 0x06b404de00000000, + 0x30e586fa00000000, 0x6a16009700000000, 0x5c4782b300000000, + 0xca55b4dd00000000, 0xfc0436f900000000, 0xa6f7b09400000000, + 0x90a632b000000000, 0x1211bd4f00000000, 0x24403f6b00000000, + 0x7eb3b90600000000, 0x48e23b2200000000, 0x3bdad72200000000, + 0x0d8b550600000000, 0x5778d36b00000000, 0x6129514f00000000, + 0xe39edeb000000000, 0xd5cf5c9400000000, 0x8f3cdaf900000000, + 0xb96d58dd00000000, 0x694c02f800000000, 0x5f1d80dc00000000, + 0x05ee06b100000000, 0x33bf849500000000, 0xb1080b6a00000000, + 0x8759894e00000000, 0xddaa0f2300000000, 0xebfb8d0700000000, + 0x98c3610700000000, 0xae92e32300000000, 0xf461654e00000000, + 0xc230e76a00000000, 0x4087689500000000, 0x76d6eab100000000, + 0x2c256cdc00000000, 0x1a74eef800000000, 0x59cbc1f600000000, + 0x6f9a43d200000000, 0x3569c5bf00000000, 0x0338479b00000000, + 0x818fc86400000000, 0xb7de4a4000000000, 0xed2dcc2d00000000, + 0xdb7c4e0900000000, 0xa844a20900000000, 0x9e15202d00000000, + 0xc4e6a64000000000, 0xf2b7246400000000, 0x7000ab9b00000000, + 0x465129bf00000000, 0x1ca2afd200000000, 0x2af32df600000000, + 0xfad277d300000000, 0xcc83f5f700000000, 0x9670739a00000000, + 0xa021f1be00000000, 0x22967e4100000000, 0x14c7fc6500000000, + 0x4e347a0800000000, 0x7865f82c00000000, 0x0b5d142c00000000, + 0x3d0c960800000000, 0x67ff106500000000, 0x51ae924100000000, + 0xd3191dbe00000000, 0xe5489f9a00000000, 0xbfbb19f700000000, + 0x89ea9bd300000000, 0x1ff8adbd00000000, 0x29a92f9900000000, + 0x735aa9f400000000, 0x450b2bd000000000, 0xc7bca42f00000000, + 0xf1ed260b00000000, 0xab1ea06600000000, 0x9d4f224200000000, + 0xee77ce4200000000, 0xd8264c6600000000, 0x82d5ca0b00000000, + 0xb484482f00000000, 0x3633c7d000000000, 0x006245f400000000, + 0x5a91c39900000000, 0x6cc041bd00000000, 0xbce11b9800000000, + 0x8ab099bc00000000, 0xd0431fd100000000, 0xe6129df500000000, + 0x64a5120a00000000, 0x52f4902e00000000, 0x0807164300000000, + 0x3e56946700000000, 0x4d6e786700000000, 0x7b3ffa4300000000, + 0x21cc7c2e00000000, 0x179dfe0a00000000, 0x952a71f500000000, + 0xa37bf3d100000000, 0xf98875bc00000000, 0xcfd9f79800000000, + 0xd5ad196000000000, 0xe3fc9b4400000000, 0xb90f1d2900000000, + 0x8f5e9f0d00000000, 0x0de910f200000000, 0x3bb892d600000000, + 0x614b14bb00000000, 0x571a969f00000000, 0x24227a9f00000000, + 0x1273f8bb00000000, 0x48807ed600000000, 0x7ed1fcf200000000, + 0xfc66730d00000000, 0xca37f12900000000, 0x90c4774400000000, + 0xa695f56000000000, 0x76b4af4500000000, 0x40e52d6100000000, + 0x1a16ab0c00000000, 0x2c47292800000000, 0xaef0a6d700000000, + 0x98a124f300000000, 0xc252a29e00000000, 0xf40320ba00000000, + 0x873bccba00000000, 0xb16a4e9e00000000, 0xeb99c8f300000000, + 0xddc84ad700000000, 0x5f7fc52800000000, 0x692e470c00000000, + 0x33ddc16100000000, 0x058c434500000000, 0x939e752b00000000, + 0xa5cff70f00000000, 0xff3c716200000000, 0xc96df34600000000, + 0x4bda7cb900000000, 0x7d8bfe9d00000000, 0x277878f000000000, + 0x1129fad400000000, 0x621116d400000000, 0x544094f000000000, + 0x0eb3129d00000000, 0x38e290b900000000, 0xba551f4600000000, + 0x8c049d6200000000, 0xd6f71b0f00000000, 0xe0a6992b00000000, + 0x3087c30e00000000, 0x06d6412a00000000, 0x5c25c74700000000, + 0x6a74456300000000, 0xe8c3ca9c00000000, 0xde9248b800000000, + 0x8461ced500000000, 0xb2304cf100000000, 0xc108a0f100000000, + 0xf75922d500000000, 0xadaaa4b800000000, 0x9bfb269c00000000, + 0x194ca96300000000, 0x2f1d2b4700000000, 0x75eead2a00000000, + 0x43bf2f0e00000000}, + {0x0000000000000000, 0xc8179ecf00000000, 0xd1294d4400000000, + 0x193ed38b00000000, 0xa2539a8800000000, 0x6a44044700000000, + 0x737ad7cc00000000, 0xbb6d490300000000, 0x05a145ca00000000, + 0xcdb6db0500000000, 0xd488088e00000000, 0x1c9f964100000000, + 0xa7f2df4200000000, 0x6fe5418d00000000, 0x76db920600000000, + 0xbecc0cc900000000, 0x4b44fa4f00000000, 0x8353648000000000, + 0x9a6db70b00000000, 0x527a29c400000000, 0xe91760c700000000, + 0x2100fe0800000000, 0x383e2d8300000000, 0xf029b34c00000000, + 0x4ee5bf8500000000, 0x86f2214a00000000, 0x9fccf2c100000000, + 0x57db6c0e00000000, 0xecb6250d00000000, 0x24a1bbc200000000, + 0x3d9f684900000000, 0xf588f68600000000, 0x9688f49f00000000, + 0x5e9f6a5000000000, 0x47a1b9db00000000, 0x8fb6271400000000, + 0x34db6e1700000000, 0xfcccf0d800000000, 0xe5f2235300000000, + 0x2de5bd9c00000000, 0x9329b15500000000, 0x5b3e2f9a00000000, + 0x4200fc1100000000, 0x8a1762de00000000, 0x317a2bdd00000000, + 0xf96db51200000000, 0xe053669900000000, 0x2844f85600000000, + 0xddcc0ed000000000, 0x15db901f00000000, 0x0ce5439400000000, + 0xc4f2dd5b00000000, 0x7f9f945800000000, 0xb7880a9700000000, + 0xaeb6d91c00000000, 0x66a147d300000000, 0xd86d4b1a00000000, + 0x107ad5d500000000, 0x0944065e00000000, 0xc153989100000000, + 0x7a3ed19200000000, 0xb2294f5d00000000, 0xab179cd600000000, + 0x6300021900000000, 0x6d1798e400000000, 0xa500062b00000000, + 0xbc3ed5a000000000, 0x74294b6f00000000, 0xcf44026c00000000, + 0x07539ca300000000, 0x1e6d4f2800000000, 0xd67ad1e700000000, + 0x68b6dd2e00000000, 0xa0a143e100000000, 0xb99f906a00000000, + 0x71880ea500000000, 0xcae547a600000000, 0x02f2d96900000000, + 0x1bcc0ae200000000, 0xd3db942d00000000, 0x265362ab00000000, + 0xee44fc6400000000, 0xf77a2fef00000000, 0x3f6db12000000000, + 0x8400f82300000000, 0x4c1766ec00000000, 0x5529b56700000000, + 0x9d3e2ba800000000, 0x23f2276100000000, 0xebe5b9ae00000000, + 0xf2db6a2500000000, 0x3accf4ea00000000, 0x81a1bde900000000, + 0x49b6232600000000, 0x5088f0ad00000000, 0x989f6e6200000000, + 0xfb9f6c7b00000000, 0x3388f2b400000000, 0x2ab6213f00000000, + 0xe2a1bff000000000, 0x59ccf6f300000000, 0x91db683c00000000, + 0x88e5bbb700000000, 0x40f2257800000000, 0xfe3e29b100000000, + 0x3629b77e00000000, 0x2f1764f500000000, 0xe700fa3a00000000, + 0x5c6db33900000000, 0x947a2df600000000, 0x8d44fe7d00000000, + 0x455360b200000000, 0xb0db963400000000, 0x78cc08fb00000000, + 0x61f2db7000000000, 0xa9e545bf00000000, 0x12880cbc00000000, + 0xda9f927300000000, 0xc3a141f800000000, 0x0bb6df3700000000, + 0xb57ad3fe00000000, 0x7d6d4d3100000000, 0x64539eba00000000, + 0xac44007500000000, 0x1729497600000000, 0xdf3ed7b900000000, + 0xc600043200000000, 0x0e179afd00000000, 0x9b28411200000000, + 0x533fdfdd00000000, 0x4a010c5600000000, 0x8216929900000000, + 0x397bdb9a00000000, 0xf16c455500000000, 0xe85296de00000000, + 0x2045081100000000, 0x9e8904d800000000, 0x569e9a1700000000, + 0x4fa0499c00000000, 0x87b7d75300000000, 0x3cda9e5000000000, + 0xf4cd009f00000000, 0xedf3d31400000000, 0x25e44ddb00000000, + 0xd06cbb5d00000000, 0x187b259200000000, 0x0145f61900000000, + 0xc95268d600000000, 0x723f21d500000000, 0xba28bf1a00000000, + 0xa3166c9100000000, 0x6b01f25e00000000, 0xd5cdfe9700000000, + 0x1dda605800000000, 0x04e4b3d300000000, 0xccf32d1c00000000, + 0x779e641f00000000, 0xbf89fad000000000, 0xa6b7295b00000000, + 0x6ea0b79400000000, 0x0da0b58d00000000, 0xc5b72b4200000000, + 0xdc89f8c900000000, 0x149e660600000000, 0xaff32f0500000000, + 0x67e4b1ca00000000, 0x7eda624100000000, 0xb6cdfc8e00000000, + 0x0801f04700000000, 0xc0166e8800000000, 0xd928bd0300000000, + 0x113f23cc00000000, 0xaa526acf00000000, 0x6245f40000000000, + 0x7b7b278b00000000, 0xb36cb94400000000, 0x46e44fc200000000, + 0x8ef3d10d00000000, 0x97cd028600000000, 0x5fda9c4900000000, + 0xe4b7d54a00000000, 0x2ca04b8500000000, 0x359e980e00000000, + 0xfd8906c100000000, 0x43450a0800000000, 0x8b5294c700000000, + 0x926c474c00000000, 0x5a7bd98300000000, 0xe116908000000000, + 0x29010e4f00000000, 0x303fddc400000000, 0xf828430b00000000, + 0xf63fd9f600000000, 0x3e28473900000000, 0x271694b200000000, + 0xef010a7d00000000, 0x546c437e00000000, 0x9c7bddb100000000, + 0x85450e3a00000000, 0x4d5290f500000000, 0xf39e9c3c00000000, + 0x3b8902f300000000, 0x22b7d17800000000, 0xeaa04fb700000000, + 0x51cd06b400000000, 0x99da987b00000000, 0x80e44bf000000000, + 0x48f3d53f00000000, 0xbd7b23b900000000, 0x756cbd7600000000, + 0x6c526efd00000000, 0xa445f03200000000, 0x1f28b93100000000, + 0xd73f27fe00000000, 0xce01f47500000000, 0x06166aba00000000, + 0xb8da667300000000, 0x70cdf8bc00000000, 0x69f32b3700000000, + 0xa1e4b5f800000000, 0x1a89fcfb00000000, 0xd29e623400000000, + 0xcba0b1bf00000000, 0x03b72f7000000000, 0x60b72d6900000000, + 0xa8a0b3a600000000, 0xb19e602d00000000, 0x7989fee200000000, + 0xc2e4b7e100000000, 0x0af3292e00000000, 0x13cdfaa500000000, + 0xdbda646a00000000, 0x651668a300000000, 0xad01f66c00000000, + 0xb43f25e700000000, 0x7c28bb2800000000, 0xc745f22b00000000, + 0x0f526ce400000000, 0x166cbf6f00000000, 0xde7b21a000000000, + 0x2bf3d72600000000, 0xe3e449e900000000, 0xfada9a6200000000, + 0x32cd04ad00000000, 0x89a04dae00000000, 0x41b7d36100000000, + 0x588900ea00000000, 0x909e9e2500000000, 0x2e5292ec00000000, + 0xe6450c2300000000, 0xff7bdfa800000000, 0x376c416700000000, + 0x8c01086400000000, 0x441696ab00000000, 0x5d28452000000000, + 0x953fdbef00000000}, + {0x0000000000000000, 0x95d4709500000000, 0x6baf90f100000000, + 0xfe7be06400000000, 0x9758503800000000, 0x028c20ad00000000, + 0xfcf7c0c900000000, 0x6923b05c00000000, 0x2eb1a07000000000, + 0xbb65d0e500000000, 0x451e308100000000, 0xd0ca401400000000, + 0xb9e9f04800000000, 0x2c3d80dd00000000, 0xd24660b900000000, + 0x4792102c00000000, 0x5c6241e100000000, 0xc9b6317400000000, + 0x37cdd11000000000, 0xa219a18500000000, 0xcb3a11d900000000, + 0x5eee614c00000000, 0xa095812800000000, 0x3541f1bd00000000, + 0x72d3e19100000000, 0xe707910400000000, 0x197c716000000000, + 0x8ca801f500000000, 0xe58bb1a900000000, 0x705fc13c00000000, + 0x8e24215800000000, 0x1bf051cd00000000, 0xf9c2f31900000000, + 0x6c16838c00000000, 0x926d63e800000000, 0x07b9137d00000000, + 0x6e9aa32100000000, 0xfb4ed3b400000000, 0x053533d000000000, + 0x90e1434500000000, 0xd773536900000000, 0x42a723fc00000000, + 0xbcdcc39800000000, 0x2908b30d00000000, 0x402b035100000000, + 0xd5ff73c400000000, 0x2b8493a000000000, 0xbe50e33500000000, + 0xa5a0b2f800000000, 0x3074c26d00000000, 0xce0f220900000000, + 0x5bdb529c00000000, 0x32f8e2c000000000, 0xa72c925500000000, + 0x5957723100000000, 0xcc8302a400000000, 0x8b11128800000000, + 0x1ec5621d00000000, 0xe0be827900000000, 0x756af2ec00000000, + 0x1c4942b000000000, 0x899d322500000000, 0x77e6d24100000000, + 0xe232a2d400000000, 0xf285e73300000000, 0x675197a600000000, + 0x992a77c200000000, 0x0cfe075700000000, 0x65ddb70b00000000, + 0xf009c79e00000000, 0x0e7227fa00000000, 0x9ba6576f00000000, + 0xdc34474300000000, 0x49e037d600000000, 0xb79bd7b200000000, + 0x224fa72700000000, 0x4b6c177b00000000, 0xdeb867ee00000000, + 0x20c3878a00000000, 0xb517f71f00000000, 0xaee7a6d200000000, + 0x3b33d64700000000, 0xc548362300000000, 0x509c46b600000000, + 0x39bff6ea00000000, 0xac6b867f00000000, 0x5210661b00000000, + 0xc7c4168e00000000, 0x805606a200000000, 0x1582763700000000, + 0xebf9965300000000, 0x7e2de6c600000000, 0x170e569a00000000, + 0x82da260f00000000, 0x7ca1c66b00000000, 0xe975b6fe00000000, + 0x0b47142a00000000, 0x9e9364bf00000000, 0x60e884db00000000, + 0xf53cf44e00000000, 0x9c1f441200000000, 0x09cb348700000000, + 0xf7b0d4e300000000, 0x6264a47600000000, 0x25f6b45a00000000, + 0xb022c4cf00000000, 0x4e5924ab00000000, 0xdb8d543e00000000, + 0xb2aee46200000000, 0x277a94f700000000, 0xd901749300000000, + 0x4cd5040600000000, 0x572555cb00000000, 0xc2f1255e00000000, + 0x3c8ac53a00000000, 0xa95eb5af00000000, 0xc07d05f300000000, + 0x55a9756600000000, 0xabd2950200000000, 0x3e06e59700000000, + 0x7994f5bb00000000, 0xec40852e00000000, 0x123b654a00000000, + 0x87ef15df00000000, 0xeecca58300000000, 0x7b18d51600000000, + 0x8563357200000000, 0x10b745e700000000, 0xe40bcf6700000000, + 0x71dfbff200000000, 0x8fa45f9600000000, 0x1a702f0300000000, + 0x73539f5f00000000, 0xe687efca00000000, 0x18fc0fae00000000, + 0x8d287f3b00000000, 0xcaba6f1700000000, 0x5f6e1f8200000000, + 0xa115ffe600000000, 0x34c18f7300000000, 0x5de23f2f00000000, + 0xc8364fba00000000, 0x364dafde00000000, 0xa399df4b00000000, + 0xb8698e8600000000, 0x2dbdfe1300000000, 0xd3c61e7700000000, + 0x46126ee200000000, 0x2f31debe00000000, 0xbae5ae2b00000000, + 0x449e4e4f00000000, 0xd14a3eda00000000, 0x96d82ef600000000, + 0x030c5e6300000000, 0xfd77be0700000000, 0x68a3ce9200000000, + 0x01807ece00000000, 0x94540e5b00000000, 0x6a2fee3f00000000, + 0xfffb9eaa00000000, 0x1dc93c7e00000000, 0x881d4ceb00000000, + 0x7666ac8f00000000, 0xe3b2dc1a00000000, 0x8a916c4600000000, + 0x1f451cd300000000, 0xe13efcb700000000, 0x74ea8c2200000000, + 0x33789c0e00000000, 0xa6acec9b00000000, 0x58d70cff00000000, + 0xcd037c6a00000000, 0xa420cc3600000000, 0x31f4bca300000000, + 0xcf8f5cc700000000, 0x5a5b2c5200000000, 0x41ab7d9f00000000, + 0xd47f0d0a00000000, 0x2a04ed6e00000000, 0xbfd09dfb00000000, + 0xd6f32da700000000, 0x43275d3200000000, 0xbd5cbd5600000000, + 0x2888cdc300000000, 0x6f1addef00000000, 0xfacead7a00000000, + 0x04b54d1e00000000, 0x91613d8b00000000, 0xf8428dd700000000, + 0x6d96fd4200000000, 0x93ed1d2600000000, 0x06396db300000000, + 0x168e285400000000, 0x835a58c100000000, 0x7d21b8a500000000, + 0xe8f5c83000000000, 0x81d6786c00000000, 0x140208f900000000, + 0xea79e89d00000000, 0x7fad980800000000, 0x383f882400000000, + 0xadebf8b100000000, 0x539018d500000000, 0xc644684000000000, + 0xaf67d81c00000000, 0x3ab3a88900000000, 0xc4c848ed00000000, + 0x511c387800000000, 0x4aec69b500000000, 0xdf38192000000000, + 0x2143f94400000000, 0xb49789d100000000, 0xddb4398d00000000, + 0x4860491800000000, 0xb61ba97c00000000, 0x23cfd9e900000000, + 0x645dc9c500000000, 0xf189b95000000000, 0x0ff2593400000000, + 0x9a2629a100000000, 0xf30599fd00000000, 0x66d1e96800000000, + 0x98aa090c00000000, 0x0d7e799900000000, 0xef4cdb4d00000000, + 0x7a98abd800000000, 0x84e34bbc00000000, 0x11373b2900000000, + 0x78148b7500000000, 0xedc0fbe000000000, 0x13bb1b8400000000, + 0x866f6b1100000000, 0xc1fd7b3d00000000, 0x54290ba800000000, + 0xaa52ebcc00000000, 0x3f869b5900000000, 0x56a52b0500000000, + 0xc3715b9000000000, 0x3d0abbf400000000, 0xa8decb6100000000, + 0xb32e9aac00000000, 0x26faea3900000000, 0xd8810a5d00000000, + 0x4d557ac800000000, 0x2476ca9400000000, 0xb1a2ba0100000000, + 0x4fd95a6500000000, 0xda0d2af000000000, 0x9d9f3adc00000000, + 0x084b4a4900000000, 0xf630aa2d00000000, 0x63e4dab800000000, + 0x0ac76ae400000000, 0x9f131a7100000000, 0x6168fa1500000000, + 0xf4bc8a8000000000}, + {0x0000000000000000, 0x1f17f08000000000, 0x7f2891da00000000, + 0x603f615a00000000, 0xbf56536e00000000, 0xa041a3ee00000000, + 0xc07ec2b400000000, 0xdf69323400000000, 0x7eada6dc00000000, + 0x61ba565c00000000, 0x0185370600000000, 0x1e92c78600000000, + 0xc1fbf5b200000000, 0xdeec053200000000, 0xbed3646800000000, + 0xa1c494e800000000, 0xbd5c3c6200000000, 0xa24bcce200000000, + 0xc274adb800000000, 0xdd635d3800000000, 0x020a6f0c00000000, + 0x1d1d9f8c00000000, 0x7d22fed600000000, 0x62350e5600000000, + 0xc3f19abe00000000, 0xdce66a3e00000000, 0xbcd90b6400000000, + 0xa3cefbe400000000, 0x7ca7c9d000000000, 0x63b0395000000000, + 0x038f580a00000000, 0x1c98a88a00000000, 0x7ab978c400000000, + 0x65ae884400000000, 0x0591e91e00000000, 0x1a86199e00000000, + 0xc5ef2baa00000000, 0xdaf8db2a00000000, 0xbac7ba7000000000, + 0xa5d04af000000000, 0x0414de1800000000, 0x1b032e9800000000, + 0x7b3c4fc200000000, 0x642bbf4200000000, 0xbb428d7600000000, + 0xa4557df600000000, 0xc46a1cac00000000, 0xdb7dec2c00000000, + 0xc7e544a600000000, 0xd8f2b42600000000, 0xb8cdd57c00000000, + 0xa7da25fc00000000, 0x78b317c800000000, 0x67a4e74800000000, + 0x079b861200000000, 0x188c769200000000, 0xb948e27a00000000, + 0xa65f12fa00000000, 0xc66073a000000000, 0xd977832000000000, + 0x061eb11400000000, 0x1909419400000000, 0x793620ce00000000, + 0x6621d04e00000000, 0xb574805300000000, 0xaa6370d300000000, + 0xca5c118900000000, 0xd54be10900000000, 0x0a22d33d00000000, + 0x153523bd00000000, 0x750a42e700000000, 0x6a1db26700000000, + 0xcbd9268f00000000, 0xd4ced60f00000000, 0xb4f1b75500000000, + 0xabe647d500000000, 0x748f75e100000000, 0x6b98856100000000, + 0x0ba7e43b00000000, 0x14b014bb00000000, 0x0828bc3100000000, + 0x173f4cb100000000, 0x77002deb00000000, 0x6817dd6b00000000, + 0xb77eef5f00000000, 0xa8691fdf00000000, 0xc8567e8500000000, + 0xd7418e0500000000, 0x76851aed00000000, 0x6992ea6d00000000, + 0x09ad8b3700000000, 0x16ba7bb700000000, 0xc9d3498300000000, + 0xd6c4b90300000000, 0xb6fbd85900000000, 0xa9ec28d900000000, + 0xcfcdf89700000000, 0xd0da081700000000, 0xb0e5694d00000000, + 0xaff299cd00000000, 0x709babf900000000, 0x6f8c5b7900000000, + 0x0fb33a2300000000, 0x10a4caa300000000, 0xb1605e4b00000000, + 0xae77aecb00000000, 0xce48cf9100000000, 0xd15f3f1100000000, + 0x0e360d2500000000, 0x1121fda500000000, 0x711e9cff00000000, + 0x6e096c7f00000000, 0x7291c4f500000000, 0x6d86347500000000, + 0x0db9552f00000000, 0x12aea5af00000000, 0xcdc7979b00000000, + 0xd2d0671b00000000, 0xb2ef064100000000, 0xadf8f6c100000000, + 0x0c3c622900000000, 0x132b92a900000000, 0x7314f3f300000000, + 0x6c03037300000000, 0xb36a314700000000, 0xac7dc1c700000000, + 0xcc42a09d00000000, 0xd355501d00000000, 0x6ae900a700000000, + 0x75fef02700000000, 0x15c1917d00000000, 0x0ad661fd00000000, + 0xd5bf53c900000000, 0xcaa8a34900000000, 0xaa97c21300000000, + 0xb580329300000000, 0x1444a67b00000000, 0x0b5356fb00000000, + 0x6b6c37a100000000, 0x747bc72100000000, 0xab12f51500000000, + 0xb405059500000000, 0xd43a64cf00000000, 0xcb2d944f00000000, + 0xd7b53cc500000000, 0xc8a2cc4500000000, 0xa89dad1f00000000, + 0xb78a5d9f00000000, 0x68e36fab00000000, 0x77f49f2b00000000, + 0x17cbfe7100000000, 0x08dc0ef100000000, 0xa9189a1900000000, + 0xb60f6a9900000000, 0xd6300bc300000000, 0xc927fb4300000000, + 0x164ec97700000000, 0x095939f700000000, 0x696658ad00000000, + 0x7671a82d00000000, 0x1050786300000000, 0x0f4788e300000000, + 0x6f78e9b900000000, 0x706f193900000000, 0xaf062b0d00000000, + 0xb011db8d00000000, 0xd02ebad700000000, 0xcf394a5700000000, + 0x6efddebf00000000, 0x71ea2e3f00000000, 0x11d54f6500000000, + 0x0ec2bfe500000000, 0xd1ab8dd100000000, 0xcebc7d5100000000, + 0xae831c0b00000000, 0xb194ec8b00000000, 0xad0c440100000000, + 0xb21bb48100000000, 0xd224d5db00000000, 0xcd33255b00000000, + 0x125a176f00000000, 0x0d4de7ef00000000, 0x6d7286b500000000, + 0x7265763500000000, 0xd3a1e2dd00000000, 0xccb6125d00000000, + 0xac89730700000000, 0xb39e838700000000, 0x6cf7b1b300000000, + 0x73e0413300000000, 0x13df206900000000, 0x0cc8d0e900000000, + 0xdf9d80f400000000, 0xc08a707400000000, 0xa0b5112e00000000, + 0xbfa2e1ae00000000, 0x60cbd39a00000000, 0x7fdc231a00000000, + 0x1fe3424000000000, 0x00f4b2c000000000, 0xa130262800000000, + 0xbe27d6a800000000, 0xde18b7f200000000, 0xc10f477200000000, + 0x1e66754600000000, 0x017185c600000000, 0x614ee49c00000000, + 0x7e59141c00000000, 0x62c1bc9600000000, 0x7dd64c1600000000, + 0x1de92d4c00000000, 0x02feddcc00000000, 0xdd97eff800000000, + 0xc2801f7800000000, 0xa2bf7e2200000000, 0xbda88ea200000000, + 0x1c6c1a4a00000000, 0x037beaca00000000, 0x63448b9000000000, + 0x7c537b1000000000, 0xa33a492400000000, 0xbc2db9a400000000, + 0xdc12d8fe00000000, 0xc305287e00000000, 0xa524f83000000000, + 0xba3308b000000000, 0xda0c69ea00000000, 0xc51b996a00000000, + 0x1a72ab5e00000000, 0x05655bde00000000, 0x655a3a8400000000, + 0x7a4dca0400000000, 0xdb895eec00000000, 0xc49eae6c00000000, + 0xa4a1cf3600000000, 0xbbb63fb600000000, 0x64df0d8200000000, + 0x7bc8fd0200000000, 0x1bf79c5800000000, 0x04e06cd800000000, + 0x1878c45200000000, 0x076f34d200000000, 0x6750558800000000, + 0x7847a50800000000, 0xa72e973c00000000, 0xb83967bc00000000, + 0xd80606e600000000, 0xc711f66600000000, 0x66d5628e00000000, + 0x79c2920e00000000, 0x19fdf35400000000, 0x06ea03d400000000, + 0xd98331e000000000, 0xc694c16000000000, 0xa6aba03a00000000, + 0xb9bc50ba00000000}, + {0x0000000000000000, 0xe2fd888d00000000, 0x85fd60c000000000, + 0x6700e84d00000000, 0x4bfdb05b00000000, 0xa90038d600000000, + 0xce00d09b00000000, 0x2cfd581600000000, 0x96fa61b700000000, + 0x7407e93a00000000, 0x1307017700000000, 0xf1fa89fa00000000, + 0xdd07d1ec00000000, 0x3ffa596100000000, 0x58fab12c00000000, + 0xba0739a100000000, 0x6df3b2b500000000, 0x8f0e3a3800000000, + 0xe80ed27500000000, 0x0af35af800000000, 0x260e02ee00000000, + 0xc4f38a6300000000, 0xa3f3622e00000000, 0x410eeaa300000000, + 0xfb09d30200000000, 0x19f45b8f00000000, 0x7ef4b3c200000000, + 0x9c093b4f00000000, 0xb0f4635900000000, 0x5209ebd400000000, + 0x3509039900000000, 0xd7f48b1400000000, 0x9be014b000000000, + 0x791d9c3d00000000, 0x1e1d747000000000, 0xfce0fcfd00000000, + 0xd01da4eb00000000, 0x32e02c6600000000, 0x55e0c42b00000000, + 0xb71d4ca600000000, 0x0d1a750700000000, 0xefe7fd8a00000000, + 0x88e715c700000000, 0x6a1a9d4a00000000, 0x46e7c55c00000000, + 0xa41a4dd100000000, 0xc31aa59c00000000, 0x21e72d1100000000, + 0xf613a60500000000, 0x14ee2e8800000000, 0x73eec6c500000000, + 0x91134e4800000000, 0xbdee165e00000000, 0x5f139ed300000000, + 0x3813769e00000000, 0xdaeefe1300000000, 0x60e9c7b200000000, + 0x82144f3f00000000, 0xe514a77200000000, 0x07e92fff00000000, + 0x2b1477e900000000, 0xc9e9ff6400000000, 0xaee9172900000000, + 0x4c149fa400000000, 0x77c758bb00000000, 0x953ad03600000000, + 0xf23a387b00000000, 0x10c7b0f600000000, 0x3c3ae8e000000000, + 0xdec7606d00000000, 0xb9c7882000000000, 0x5b3a00ad00000000, + 0xe13d390c00000000, 0x03c0b18100000000, 0x64c059cc00000000, + 0x863dd14100000000, 0xaac0895700000000, 0x483d01da00000000, + 0x2f3de99700000000, 0xcdc0611a00000000, 0x1a34ea0e00000000, + 0xf8c9628300000000, 0x9fc98ace00000000, 0x7d34024300000000, + 0x51c95a5500000000, 0xb334d2d800000000, 0xd4343a9500000000, + 0x36c9b21800000000, 0x8cce8bb900000000, 0x6e33033400000000, + 0x0933eb7900000000, 0xebce63f400000000, 0xc7333be200000000, + 0x25ceb36f00000000, 0x42ce5b2200000000, 0xa033d3af00000000, + 0xec274c0b00000000, 0x0edac48600000000, 0x69da2ccb00000000, + 0x8b27a44600000000, 0xa7dafc5000000000, 0x452774dd00000000, + 0x22279c9000000000, 0xc0da141d00000000, 0x7add2dbc00000000, + 0x9820a53100000000, 0xff204d7c00000000, 0x1dddc5f100000000, + 0x31209de700000000, 0xd3dd156a00000000, 0xb4ddfd2700000000, + 0x562075aa00000000, 0x81d4febe00000000, 0x6329763300000000, + 0x04299e7e00000000, 0xe6d416f300000000, 0xca294ee500000000, + 0x28d4c66800000000, 0x4fd42e2500000000, 0xad29a6a800000000, + 0x172e9f0900000000, 0xf5d3178400000000, 0x92d3ffc900000000, + 0x702e774400000000, 0x5cd32f5200000000, 0xbe2ea7df00000000, + 0xd92e4f9200000000, 0x3bd3c71f00000000, 0xaf88c0ad00000000, + 0x4d75482000000000, 0x2a75a06d00000000, 0xc88828e000000000, + 0xe47570f600000000, 0x0688f87b00000000, 0x6188103600000000, + 0x837598bb00000000, 0x3972a11a00000000, 0xdb8f299700000000, + 0xbc8fc1da00000000, 0x5e72495700000000, 0x728f114100000000, + 0x907299cc00000000, 0xf772718100000000, 0x158ff90c00000000, + 0xc27b721800000000, 0x2086fa9500000000, 0x478612d800000000, + 0xa57b9a5500000000, 0x8986c24300000000, 0x6b7b4ace00000000, + 0x0c7ba28300000000, 0xee862a0e00000000, 0x548113af00000000, + 0xb67c9b2200000000, 0xd17c736f00000000, 0x3381fbe200000000, + 0x1f7ca3f400000000, 0xfd812b7900000000, 0x9a81c33400000000, + 0x787c4bb900000000, 0x3468d41d00000000, 0xd6955c9000000000, + 0xb195b4dd00000000, 0x53683c5000000000, 0x7f95644600000000, + 0x9d68eccb00000000, 0xfa68048600000000, 0x18958c0b00000000, + 0xa292b5aa00000000, 0x406f3d2700000000, 0x276fd56a00000000, + 0xc5925de700000000, 0xe96f05f100000000, 0x0b928d7c00000000, + 0x6c92653100000000, 0x8e6fedbc00000000, 0x599b66a800000000, + 0xbb66ee2500000000, 0xdc66066800000000, 0x3e9b8ee500000000, + 0x1266d6f300000000, 0xf09b5e7e00000000, 0x979bb63300000000, + 0x75663ebe00000000, 0xcf61071f00000000, 0x2d9c8f9200000000, + 0x4a9c67df00000000, 0xa861ef5200000000, 0x849cb74400000000, + 0x66613fc900000000, 0x0161d78400000000, 0xe39c5f0900000000, + 0xd84f981600000000, 0x3ab2109b00000000, 0x5db2f8d600000000, + 0xbf4f705b00000000, 0x93b2284d00000000, 0x714fa0c000000000, + 0x164f488d00000000, 0xf4b2c00000000000, 0x4eb5f9a100000000, + 0xac48712c00000000, 0xcb48996100000000, 0x29b511ec00000000, + 0x054849fa00000000, 0xe7b5c17700000000, 0x80b5293a00000000, + 0x6248a1b700000000, 0xb5bc2aa300000000, 0x5741a22e00000000, + 0x30414a6300000000, 0xd2bcc2ee00000000, 0xfe419af800000000, + 0x1cbc127500000000, 0x7bbcfa3800000000, 0x994172b500000000, + 0x23464b1400000000, 0xc1bbc39900000000, 0xa6bb2bd400000000, + 0x4446a35900000000, 0x68bbfb4f00000000, 0x8a4673c200000000, + 0xed469b8f00000000, 0x0fbb130200000000, 0x43af8ca600000000, + 0xa152042b00000000, 0xc652ec6600000000, 0x24af64eb00000000, + 0x08523cfd00000000, 0xeaafb47000000000, 0x8daf5c3d00000000, + 0x6f52d4b000000000, 0xd555ed1100000000, 0x37a8659c00000000, + 0x50a88dd100000000, 0xb255055c00000000, 0x9ea85d4a00000000, + 0x7c55d5c700000000, 0x1b553d8a00000000, 0xf9a8b50700000000, + 0x2e5c3e1300000000, 0xcca1b69e00000000, 0xaba15ed300000000, + 0x495cd65e00000000, 0x65a18e4800000000, 0x875c06c500000000, + 0xe05cee8800000000, 0x02a1660500000000, 0xb8a65fa400000000, + 0x5a5bd72900000000, 0x3d5b3f6400000000, 0xdfa6b7e900000000, + 0xf35befff00000000, 0x11a6677200000000, 0x76a68f3f00000000, + 0x945b07b200000000}, + {0x0000000000000000, 0xa90b894e00000000, 0x5217129d00000000, + 0xfb1c9bd300000000, 0xe52855e100000000, 0x4c23dcaf00000000, + 0xb73f477c00000000, 0x1e34ce3200000000, 0x8b57db1900000000, + 0x225c525700000000, 0xd940c98400000000, 0x704b40ca00000000, + 0x6e7f8ef800000000, 0xc77407b600000000, 0x3c689c6500000000, + 0x9563152b00000000, 0x16afb63300000000, 0xbfa43f7d00000000, + 0x44b8a4ae00000000, 0xedb32de000000000, 0xf387e3d200000000, + 0x5a8c6a9c00000000, 0xa190f14f00000000, 0x089b780100000000, + 0x9df86d2a00000000, 0x34f3e46400000000, 0xcfef7fb700000000, + 0x66e4f6f900000000, 0x78d038cb00000000, 0xd1dbb18500000000, + 0x2ac72a5600000000, 0x83cca31800000000, 0x2c5e6d6700000000, + 0x8555e42900000000, 0x7e497ffa00000000, 0xd742f6b400000000, + 0xc976388600000000, 0x607db1c800000000, 0x9b612a1b00000000, + 0x326aa35500000000, 0xa709b67e00000000, 0x0e023f3000000000, + 0xf51ea4e300000000, 0x5c152dad00000000, 0x4221e39f00000000, + 0xeb2a6ad100000000, 0x1036f10200000000, 0xb93d784c00000000, + 0x3af1db5400000000, 0x93fa521a00000000, 0x68e6c9c900000000, + 0xc1ed408700000000, 0xdfd98eb500000000, 0x76d207fb00000000, + 0x8dce9c2800000000, 0x24c5156600000000, 0xb1a6004d00000000, + 0x18ad890300000000, 0xe3b112d000000000, 0x4aba9b9e00000000, + 0x548e55ac00000000, 0xfd85dce200000000, 0x0699473100000000, + 0xaf92ce7f00000000, 0x58bcdace00000000, 0xf1b7538000000000, + 0x0aabc85300000000, 0xa3a0411d00000000, 0xbd948f2f00000000, + 0x149f066100000000, 0xef839db200000000, 0x468814fc00000000, + 0xd3eb01d700000000, 0x7ae0889900000000, 0x81fc134a00000000, + 0x28f79a0400000000, 0x36c3543600000000, 0x9fc8dd7800000000, + 0x64d446ab00000000, 0xcddfcfe500000000, 0x4e136cfd00000000, + 0xe718e5b300000000, 0x1c047e6000000000, 0xb50ff72e00000000, + 0xab3b391c00000000, 0x0230b05200000000, 0xf92c2b8100000000, + 0x5027a2cf00000000, 0xc544b7e400000000, 0x6c4f3eaa00000000, + 0x9753a57900000000, 0x3e582c3700000000, 0x206ce20500000000, + 0x89676b4b00000000, 0x727bf09800000000, 0xdb7079d600000000, + 0x74e2b7a900000000, 0xdde93ee700000000, 0x26f5a53400000000, + 0x8ffe2c7a00000000, 0x91cae24800000000, 0x38c16b0600000000, + 0xc3ddf0d500000000, 0x6ad6799b00000000, 0xffb56cb000000000, + 0x56bee5fe00000000, 0xada27e2d00000000, 0x04a9f76300000000, + 0x1a9d395100000000, 0xb396b01f00000000, 0x488a2bcc00000000, + 0xe181a28200000000, 0x624d019a00000000, 0xcb4688d400000000, + 0x305a130700000000, 0x99519a4900000000, 0x8765547b00000000, + 0x2e6edd3500000000, 0xd57246e600000000, 0x7c79cfa800000000, + 0xe91ada8300000000, 0x401153cd00000000, 0xbb0dc81e00000000, + 0x1206415000000000, 0x0c328f6200000000, 0xa539062c00000000, + 0x5e259dff00000000, 0xf72e14b100000000, 0xf17ec44600000000, + 0x58754d0800000000, 0xa369d6db00000000, 0x0a625f9500000000, + 0x145691a700000000, 0xbd5d18e900000000, 0x4641833a00000000, + 0xef4a0a7400000000, 0x7a291f5f00000000, 0xd322961100000000, + 0x283e0dc200000000, 0x8135848c00000000, 0x9f014abe00000000, + 0x360ac3f000000000, 0xcd16582300000000, 0x641dd16d00000000, + 0xe7d1727500000000, 0x4edafb3b00000000, 0xb5c660e800000000, + 0x1ccde9a600000000, 0x02f9279400000000, 0xabf2aeda00000000, + 0x50ee350900000000, 0xf9e5bc4700000000, 0x6c86a96c00000000, + 0xc58d202200000000, 0x3e91bbf100000000, 0x979a32bf00000000, + 0x89aefc8d00000000, 0x20a575c300000000, 0xdbb9ee1000000000, + 0x72b2675e00000000, 0xdd20a92100000000, 0x742b206f00000000, + 0x8f37bbbc00000000, 0x263c32f200000000, 0x3808fcc000000000, + 0x9103758e00000000, 0x6a1fee5d00000000, 0xc314671300000000, + 0x5677723800000000, 0xff7cfb7600000000, 0x046060a500000000, + 0xad6be9eb00000000, 0xb35f27d900000000, 0x1a54ae9700000000, + 0xe148354400000000, 0x4843bc0a00000000, 0xcb8f1f1200000000, + 0x6284965c00000000, 0x99980d8f00000000, 0x309384c100000000, + 0x2ea74af300000000, 0x87acc3bd00000000, 0x7cb0586e00000000, + 0xd5bbd12000000000, 0x40d8c40b00000000, 0xe9d34d4500000000, + 0x12cfd69600000000, 0xbbc45fd800000000, 0xa5f091ea00000000, + 0x0cfb18a400000000, 0xf7e7837700000000, 0x5eec0a3900000000, + 0xa9c21e8800000000, 0x00c997c600000000, 0xfbd50c1500000000, + 0x52de855b00000000, 0x4cea4b6900000000, 0xe5e1c22700000000, + 0x1efd59f400000000, 0xb7f6d0ba00000000, 0x2295c59100000000, + 0x8b9e4cdf00000000, 0x7082d70c00000000, 0xd9895e4200000000, + 0xc7bd907000000000, 0x6eb6193e00000000, 0x95aa82ed00000000, + 0x3ca10ba300000000, 0xbf6da8bb00000000, 0x166621f500000000, + 0xed7aba2600000000, 0x4471336800000000, 0x5a45fd5a00000000, + 0xf34e741400000000, 0x0852efc700000000, 0xa159668900000000, + 0x343a73a200000000, 0x9d31faec00000000, 0x662d613f00000000, + 0xcf26e87100000000, 0xd112264300000000, 0x7819af0d00000000, + 0x830534de00000000, 0x2a0ebd9000000000, 0x859c73ef00000000, + 0x2c97faa100000000, 0xd78b617200000000, 0x7e80e83c00000000, + 0x60b4260e00000000, 0xc9bfaf4000000000, 0x32a3349300000000, + 0x9ba8bddd00000000, 0x0ecba8f600000000, 0xa7c021b800000000, + 0x5cdcba6b00000000, 0xf5d7332500000000, 0xebe3fd1700000000, + 0x42e8745900000000, 0xb9f4ef8a00000000, 0x10ff66c400000000, + 0x9333c5dc00000000, 0x3a384c9200000000, 0xc124d74100000000, + 0x682f5e0f00000000, 0x761b903d00000000, 0xdf10197300000000, + 0x240c82a000000000, 0x8d070bee00000000, 0x18641ec500000000, + 0xb16f978b00000000, 0x4a730c5800000000, 0xe378851600000000, + 0xfd4c4b2400000000, 0x5447c26a00000000, 0xaf5b59b900000000, + 0x0650d0f700000000}, + {0x0000000000000000, 0x479244af00000000, 0xcf22f88500000000, + 0x88b0bc2a00000000, 0xdf4381d000000000, 0x98d1c57f00000000, + 0x1061795500000000, 0x57f33dfa00000000, 0xff81737a00000000, + 0xb81337d500000000, 0x30a38bff00000000, 0x7731cf5000000000, + 0x20c2f2aa00000000, 0x6750b60500000000, 0xefe00a2f00000000, + 0xa8724e8000000000, 0xfe03e7f400000000, 0xb991a35b00000000, + 0x31211f7100000000, 0x76b35bde00000000, 0x2140662400000000, + 0x66d2228b00000000, 0xee629ea100000000, 0xa9f0da0e00000000, + 0x0182948e00000000, 0x4610d02100000000, 0xcea06c0b00000000, + 0x893228a400000000, 0xdec1155e00000000, 0x995351f100000000, + 0x11e3eddb00000000, 0x5671a97400000000, 0xbd01bf3200000000, + 0xfa93fb9d00000000, 0x722347b700000000, 0x35b1031800000000, + 0x62423ee200000000, 0x25d07a4d00000000, 0xad60c66700000000, + 0xeaf282c800000000, 0x4280cc4800000000, 0x051288e700000000, + 0x8da234cd00000000, 0xca30706200000000, 0x9dc34d9800000000, + 0xda51093700000000, 0x52e1b51d00000000, 0x1573f1b200000000, + 0x430258c600000000, 0x04901c6900000000, 0x8c20a04300000000, + 0xcbb2e4ec00000000, 0x9c41d91600000000, 0xdbd39db900000000, + 0x5363219300000000, 0x14f1653c00000000, 0xbc832bbc00000000, + 0xfb116f1300000000, 0x73a1d33900000000, 0x3433979600000000, + 0x63c0aa6c00000000, 0x2452eec300000000, 0xace252e900000000, + 0xeb70164600000000, 0x7a037e6500000000, 0x3d913aca00000000, + 0xb52186e000000000, 0xf2b3c24f00000000, 0xa540ffb500000000, + 0xe2d2bb1a00000000, 0x6a62073000000000, 0x2df0439f00000000, + 0x85820d1f00000000, 0xc21049b000000000, 0x4aa0f59a00000000, + 0x0d32b13500000000, 0x5ac18ccf00000000, 0x1d53c86000000000, + 0x95e3744a00000000, 0xd27130e500000000, 0x8400999100000000, + 0xc392dd3e00000000, 0x4b22611400000000, 0x0cb025bb00000000, + 0x5b43184100000000, 0x1cd15cee00000000, 0x9461e0c400000000, + 0xd3f3a46b00000000, 0x7b81eaeb00000000, 0x3c13ae4400000000, + 0xb4a3126e00000000, 0xf33156c100000000, 0xa4c26b3b00000000, + 0xe3502f9400000000, 0x6be093be00000000, 0x2c72d71100000000, + 0xc702c15700000000, 0x809085f800000000, 0x082039d200000000, + 0x4fb27d7d00000000, 0x1841408700000000, 0x5fd3042800000000, + 0xd763b80200000000, 0x90f1fcad00000000, 0x3883b22d00000000, + 0x7f11f68200000000, 0xf7a14aa800000000, 0xb0330e0700000000, + 0xe7c033fd00000000, 0xa052775200000000, 0x28e2cb7800000000, + 0x6f708fd700000000, 0x390126a300000000, 0x7e93620c00000000, + 0xf623de2600000000, 0xb1b19a8900000000, 0xe642a77300000000, + 0xa1d0e3dc00000000, 0x29605ff600000000, 0x6ef21b5900000000, + 0xc68055d900000000, 0x8112117600000000, 0x09a2ad5c00000000, + 0x4e30e9f300000000, 0x19c3d40900000000, 0x5e5190a600000000, + 0xd6e12c8c00000000, 0x9173682300000000, 0xf406fcca00000000, + 0xb394b86500000000, 0x3b24044f00000000, 0x7cb640e000000000, + 0x2b457d1a00000000, 0x6cd739b500000000, 0xe467859f00000000, + 0xa3f5c13000000000, 0x0b878fb000000000, 0x4c15cb1f00000000, + 0xc4a5773500000000, 0x8337339a00000000, 0xd4c40e6000000000, + 0x93564acf00000000, 0x1be6f6e500000000, 0x5c74b24a00000000, + 0x0a051b3e00000000, 0x4d975f9100000000, 0xc527e3bb00000000, + 0x82b5a71400000000, 0xd5469aee00000000, 0x92d4de4100000000, + 0x1a64626b00000000, 0x5df626c400000000, 0xf584684400000000, + 0xb2162ceb00000000, 0x3aa690c100000000, 0x7d34d46e00000000, + 0x2ac7e99400000000, 0x6d55ad3b00000000, 0xe5e5111100000000, + 0xa27755be00000000, 0x490743f800000000, 0x0e95075700000000, + 0x8625bb7d00000000, 0xc1b7ffd200000000, 0x9644c22800000000, + 0xd1d6868700000000, 0x59663aad00000000, 0x1ef47e0200000000, + 0xb686308200000000, 0xf114742d00000000, 0x79a4c80700000000, + 0x3e368ca800000000, 0x69c5b15200000000, 0x2e57f5fd00000000, + 0xa6e749d700000000, 0xe1750d7800000000, 0xb704a40c00000000, + 0xf096e0a300000000, 0x78265c8900000000, 0x3fb4182600000000, + 0x684725dc00000000, 0x2fd5617300000000, 0xa765dd5900000000, + 0xe0f799f600000000, 0x4885d77600000000, 0x0f1793d900000000, + 0x87a72ff300000000, 0xc0356b5c00000000, 0x97c656a600000000, + 0xd054120900000000, 0x58e4ae2300000000, 0x1f76ea8c00000000, + 0x8e0582af00000000, 0xc997c60000000000, 0x41277a2a00000000, + 0x06b53e8500000000, 0x5146037f00000000, 0x16d447d000000000, + 0x9e64fbfa00000000, 0xd9f6bf5500000000, 0x7184f1d500000000, + 0x3616b57a00000000, 0xbea6095000000000, 0xf9344dff00000000, + 0xaec7700500000000, 0xe95534aa00000000, 0x61e5888000000000, + 0x2677cc2f00000000, 0x7006655b00000000, 0x379421f400000000, + 0xbf249dde00000000, 0xf8b6d97100000000, 0xaf45e48b00000000, + 0xe8d7a02400000000, 0x60671c0e00000000, 0x27f558a100000000, + 0x8f87162100000000, 0xc815528e00000000, 0x40a5eea400000000, + 0x0737aa0b00000000, 0x50c497f100000000, 0x1756d35e00000000, + 0x9fe66f7400000000, 0xd8742bdb00000000, 0x33043d9d00000000, + 0x7496793200000000, 0xfc26c51800000000, 0xbbb481b700000000, + 0xec47bc4d00000000, 0xabd5f8e200000000, 0x236544c800000000, + 0x64f7006700000000, 0xcc854ee700000000, 0x8b170a4800000000, + 0x03a7b66200000000, 0x4435f2cd00000000, 0x13c6cf3700000000, + 0x54548b9800000000, 0xdce437b200000000, 0x9b76731d00000000, + 0xcd07da6900000000, 0x8a959ec600000000, 0x022522ec00000000, + 0x45b7664300000000, 0x12445bb900000000, 0x55d61f1600000000, + 0xdd66a33c00000000, 0x9af4e79300000000, 0x3286a91300000000, + 0x7514edbc00000000, 0xfda4519600000000, 0xba36153900000000, + 0xedc528c300000000, 0xaa576c6c00000000, 0x22e7d04600000000, + 0x657594e900000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x65673b46, 0xcace768c, 0xafa94dca, 0x4eedeb59, + 0x2b8ad01f, 0x84239dd5, 0xe144a693, 0x9ddbd6b2, 0xf8bcedf4, + 0x5715a03e, 0x32729b78, 0xd3363deb, 0xb65106ad, 0x19f84b67, + 0x7c9f7021, 0xe0c6ab25, 0x85a19063, 0x2a08dda9, 0x4f6fe6ef, + 0xae2b407c, 0xcb4c7b3a, 0x64e536f0, 0x01820db6, 0x7d1d7d97, + 0x187a46d1, 0xb7d30b1b, 0xd2b4305d, 0x33f096ce, 0x5697ad88, + 0xf93ee042, 0x9c59db04, 0x1afc500b, 0x7f9b6b4d, 0xd0322687, + 0xb5551dc1, 0x5411bb52, 0x31768014, 0x9edfcdde, 0xfbb8f698, + 0x872786b9, 0xe240bdff, 0x4de9f035, 0x288ecb73, 0xc9ca6de0, + 0xacad56a6, 0x03041b6c, 0x6663202a, 0xfa3afb2e, 0x9f5dc068, + 0x30f48da2, 0x5593b6e4, 0xb4d71077, 0xd1b02b31, 0x7e1966fb, + 0x1b7e5dbd, 0x67e12d9c, 0x028616da, 0xad2f5b10, 0xc8486056, + 0x290cc6c5, 0x4c6bfd83, 0xe3c2b049, 0x86a58b0f, 0x35f8a016, + 0x509f9b50, 0xff36d69a, 0x9a51eddc, 0x7b154b4f, 0x1e727009, + 0xb1db3dc3, 0xd4bc0685, 0xa82376a4, 0xcd444de2, 0x62ed0028, + 0x078a3b6e, 0xe6ce9dfd, 0x83a9a6bb, 0x2c00eb71, 0x4967d037, + 0xd53e0b33, 0xb0593075, 0x1ff07dbf, 0x7a9746f9, 0x9bd3e06a, + 0xfeb4db2c, 0x511d96e6, 0x347aada0, 0x48e5dd81, 0x2d82e6c7, + 0x822bab0d, 0xe74c904b, 0x060836d8, 0x636f0d9e, 0xccc64054, + 0xa9a17b12, 0x2f04f01d, 0x4a63cb5b, 0xe5ca8691, 0x80adbdd7, + 0x61e91b44, 0x048e2002, 0xab276dc8, 0xce40568e, 0xb2df26af, + 0xd7b81de9, 0x78115023, 0x1d766b65, 0xfc32cdf6, 0x9955f6b0, + 0x36fcbb7a, 0x539b803c, 0xcfc25b38, 0xaaa5607e, 0x050c2db4, + 0x606b16f2, 0x812fb061, 0xe4488b27, 0x4be1c6ed, 0x2e86fdab, + 0x52198d8a, 0x377eb6cc, 0x98d7fb06, 0xfdb0c040, 0x1cf466d3, + 0x79935d95, 0xd63a105f, 0xb35d2b19, 0x6bf1402c, 0x0e967b6a, + 0xa13f36a0, 0xc4580de6, 0x251cab75, 0x407b9033, 0xefd2ddf9, + 0x8ab5e6bf, 0xf62a969e, 0x934dadd8, 0x3ce4e012, 0x5983db54, + 0xb8c77dc7, 0xdda04681, 0x72090b4b, 0x176e300d, 0x8b37eb09, + 0xee50d04f, 0x41f99d85, 0x249ea6c3, 0xc5da0050, 0xa0bd3b16, + 0x0f1476dc, 0x6a734d9a, 0x16ec3dbb, 0x738b06fd, 0xdc224b37, + 0xb9457071, 0x5801d6e2, 0x3d66eda4, 0x92cfa06e, 0xf7a89b28, + 0x710d1027, 0x146a2b61, 0xbbc366ab, 0xdea45ded, 0x3fe0fb7e, + 0x5a87c038, 0xf52e8df2, 0x9049b6b4, 0xecd6c695, 0x89b1fdd3, + 0x2618b019, 0x437f8b5f, 0xa23b2dcc, 0xc75c168a, 0x68f55b40, + 0x0d926006, 0x91cbbb02, 0xf4ac8044, 0x5b05cd8e, 0x3e62f6c8, + 0xdf26505b, 0xba416b1d, 0x15e826d7, 0x708f1d91, 0x0c106db0, + 0x697756f6, 0xc6de1b3c, 0xa3b9207a, 0x42fd86e9, 0x279abdaf, + 0x8833f065, 0xed54cb23, 0x5e09e03a, 0x3b6edb7c, 0x94c796b6, + 0xf1a0adf0, 0x10e40b63, 0x75833025, 0xda2a7def, 0xbf4d46a9, + 0xc3d23688, 0xa6b50dce, 0x091c4004, 0x6c7b7b42, 0x8d3fddd1, + 0xe858e697, 0x47f1ab5d, 0x2296901b, 0xbecf4b1f, 0xdba87059, + 0x74013d93, 0x116606d5, 0xf022a046, 0x95459b00, 0x3aecd6ca, + 0x5f8bed8c, 0x23149dad, 0x4673a6eb, 0xe9daeb21, 0x8cbdd067, + 0x6df976f4, 0x089e4db2, 0xa7370078, 0xc2503b3e, 0x44f5b031, + 0x21928b77, 0x8e3bc6bd, 0xeb5cfdfb, 0x0a185b68, 0x6f7f602e, + 0xc0d62de4, 0xa5b116a2, 0xd92e6683, 0xbc495dc5, 0x13e0100f, + 0x76872b49, 0x97c38dda, 0xf2a4b69c, 0x5d0dfb56, 0x386ac010, + 0xa4331b14, 0xc1542052, 0x6efd6d98, 0x0b9a56de, 0xeadef04d, + 0x8fb9cb0b, 0x201086c1, 0x4577bd87, 0x39e8cda6, 0x5c8ff6e0, + 0xf326bb2a, 0x9641806c, 0x770526ff, 0x12621db9, 0xbdcb5073, + 0xd8ac6b35}, + {0x00000000, 0xd7e28058, 0x74b406f1, 0xa35686a9, 0xe9680de2, + 0x3e8a8dba, 0x9ddc0b13, 0x4a3e8b4b, 0x09a11d85, 0xde439ddd, + 0x7d151b74, 0xaaf79b2c, 0xe0c91067, 0x372b903f, 0x947d1696, + 0x439f96ce, 0x13423b0a, 0xc4a0bb52, 0x67f63dfb, 0xb014bda3, + 0xfa2a36e8, 0x2dc8b6b0, 0x8e9e3019, 0x597cb041, 0x1ae3268f, + 0xcd01a6d7, 0x6e57207e, 0xb9b5a026, 0xf38b2b6d, 0x2469ab35, + 0x873f2d9c, 0x50ddadc4, 0x26847614, 0xf166f64c, 0x523070e5, + 0x85d2f0bd, 0xcfec7bf6, 0x180efbae, 0xbb587d07, 0x6cbafd5f, + 0x2f256b91, 0xf8c7ebc9, 0x5b916d60, 0x8c73ed38, 0xc64d6673, + 0x11afe62b, 0xb2f96082, 0x651be0da, 0x35c64d1e, 0xe224cd46, + 0x41724bef, 0x9690cbb7, 0xdcae40fc, 0x0b4cc0a4, 0xa81a460d, + 0x7ff8c655, 0x3c67509b, 0xeb85d0c3, 0x48d3566a, 0x9f31d632, + 0xd50f5d79, 0x02eddd21, 0xa1bb5b88, 0x7659dbd0, 0x4d08ec28, + 0x9aea6c70, 0x39bcead9, 0xee5e6a81, 0xa460e1ca, 0x73826192, + 0xd0d4e73b, 0x07366763, 0x44a9f1ad, 0x934b71f5, 0x301df75c, + 0xe7ff7704, 0xadc1fc4f, 0x7a237c17, 0xd975fabe, 0x0e977ae6, + 0x5e4ad722, 0x89a8577a, 0x2afed1d3, 0xfd1c518b, 0xb722dac0, + 0x60c05a98, 0xc396dc31, 0x14745c69, 0x57ebcaa7, 0x80094aff, + 0x235fcc56, 0xf4bd4c0e, 0xbe83c745, 0x6961471d, 0xca37c1b4, + 0x1dd541ec, 0x6b8c9a3c, 0xbc6e1a64, 0x1f389ccd, 0xc8da1c95, + 0x82e497de, 0x55061786, 0xf650912f, 0x21b21177, 0x622d87b9, + 0xb5cf07e1, 0x16998148, 0xc17b0110, 0x8b458a5b, 0x5ca70a03, + 0xfff18caa, 0x28130cf2, 0x78cea136, 0xaf2c216e, 0x0c7aa7c7, + 0xdb98279f, 0x91a6acd4, 0x46442c8c, 0xe512aa25, 0x32f02a7d, + 0x716fbcb3, 0xa68d3ceb, 0x05dbba42, 0xd2393a1a, 0x9807b151, + 0x4fe53109, 0xecb3b7a0, 0x3b5137f8, 0x9a11d850, 0x4df35808, + 0xeea5dea1, 0x39475ef9, 0x7379d5b2, 0xa49b55ea, 0x07cdd343, + 0xd02f531b, 0x93b0c5d5, 0x4452458d, 0xe704c324, 0x30e6437c, + 0x7ad8c837, 0xad3a486f, 0x0e6ccec6, 0xd98e4e9e, 0x8953e35a, + 0x5eb16302, 0xfde7e5ab, 0x2a0565f3, 0x603beeb8, 0xb7d96ee0, + 0x148fe849, 0xc36d6811, 0x80f2fedf, 0x57107e87, 0xf446f82e, + 0x23a47876, 0x699af33d, 0xbe787365, 0x1d2ef5cc, 0xcacc7594, + 0xbc95ae44, 0x6b772e1c, 0xc821a8b5, 0x1fc328ed, 0x55fda3a6, + 0x821f23fe, 0x2149a557, 0xf6ab250f, 0xb534b3c1, 0x62d63399, + 0xc180b530, 0x16623568, 0x5c5cbe23, 0x8bbe3e7b, 0x28e8b8d2, + 0xff0a388a, 0xafd7954e, 0x78351516, 0xdb6393bf, 0x0c8113e7, + 0x46bf98ac, 0x915d18f4, 0x320b9e5d, 0xe5e91e05, 0xa67688cb, + 0x71940893, 0xd2c28e3a, 0x05200e62, 0x4f1e8529, 0x98fc0571, + 0x3baa83d8, 0xec480380, 0xd7193478, 0x00fbb420, 0xa3ad3289, + 0x744fb2d1, 0x3e71399a, 0xe993b9c2, 0x4ac53f6b, 0x9d27bf33, + 0xdeb829fd, 0x095aa9a5, 0xaa0c2f0c, 0x7deeaf54, 0x37d0241f, + 0xe032a447, 0x436422ee, 0x9486a2b6, 0xc45b0f72, 0x13b98f2a, + 0xb0ef0983, 0x670d89db, 0x2d330290, 0xfad182c8, 0x59870461, + 0x8e658439, 0xcdfa12f7, 0x1a1892af, 0xb94e1406, 0x6eac945e, + 0x24921f15, 0xf3709f4d, 0x502619e4, 0x87c499bc, 0xf19d426c, + 0x267fc234, 0x8529449d, 0x52cbc4c5, 0x18f54f8e, 0xcf17cfd6, + 0x6c41497f, 0xbba3c927, 0xf83c5fe9, 0x2fdedfb1, 0x8c885918, + 0x5b6ad940, 0x1154520b, 0xc6b6d253, 0x65e054fa, 0xb202d4a2, + 0xe2df7966, 0x353df93e, 0x966b7f97, 0x4189ffcf, 0x0bb77484, + 0xdc55f4dc, 0x7f037275, 0xa8e1f22d, 0xeb7e64e3, 0x3c9ce4bb, + 0x9fca6212, 0x4828e24a, 0x02166901, 0xd5f4e959, 0x76a26ff0, + 0xa140efa8}, + {0x00000000, 0xef52b6e1, 0x05d46b83, 0xea86dd62, 0x0ba8d706, + 0xe4fa61e7, 0x0e7cbc85, 0xe12e0a64, 0x1751ae0c, 0xf80318ed, + 0x1285c58f, 0xfdd7736e, 0x1cf9790a, 0xf3abcfeb, 0x192d1289, + 0xf67fa468, 0x2ea35c18, 0xc1f1eaf9, 0x2b77379b, 0xc425817a, + 0x250b8b1e, 0xca593dff, 0x20dfe09d, 0xcf8d567c, 0x39f2f214, + 0xd6a044f5, 0x3c269997, 0xd3742f76, 0x325a2512, 0xdd0893f3, + 0x378e4e91, 0xd8dcf870, 0x5d46b830, 0xb2140ed1, 0x5892d3b3, + 0xb7c06552, 0x56ee6f36, 0xb9bcd9d7, 0x533a04b5, 0xbc68b254, + 0x4a17163c, 0xa545a0dd, 0x4fc37dbf, 0xa091cb5e, 0x41bfc13a, + 0xaeed77db, 0x446baab9, 0xab391c58, 0x73e5e428, 0x9cb752c9, + 0x76318fab, 0x9963394a, 0x784d332e, 0x971f85cf, 0x7d9958ad, + 0x92cbee4c, 0x64b44a24, 0x8be6fcc5, 0x616021a7, 0x8e329746, + 0x6f1c9d22, 0x804e2bc3, 0x6ac8f6a1, 0x859a4040, 0xba8d7060, + 0x55dfc681, 0xbf591be3, 0x500bad02, 0xb125a766, 0x5e771187, + 0xb4f1cce5, 0x5ba37a04, 0xaddcde6c, 0x428e688d, 0xa808b5ef, + 0x475a030e, 0xa674096a, 0x4926bf8b, 0xa3a062e9, 0x4cf2d408, + 0x942e2c78, 0x7b7c9a99, 0x91fa47fb, 0x7ea8f11a, 0x9f86fb7e, + 0x70d44d9f, 0x9a5290fd, 0x7500261c, 0x837f8274, 0x6c2d3495, + 0x86abe9f7, 0x69f95f16, 0x88d75572, 0x6785e393, 0x8d033ef1, + 0x62518810, 0xe7cbc850, 0x08997eb1, 0xe21fa3d3, 0x0d4d1532, + 0xec631f56, 0x0331a9b7, 0xe9b774d5, 0x06e5c234, 0xf09a665c, + 0x1fc8d0bd, 0xf54e0ddf, 0x1a1cbb3e, 0xfb32b15a, 0x146007bb, + 0xfee6dad9, 0x11b46c38, 0xc9689448, 0x263a22a9, 0xccbcffcb, + 0x23ee492a, 0xc2c0434e, 0x2d92f5af, 0xc71428cd, 0x28469e2c, + 0xde393a44, 0x316b8ca5, 0xdbed51c7, 0x34bfe726, 0xd591ed42, + 0x3ac35ba3, 0xd04586c1, 0x3f173020, 0xae6be681, 0x41395060, + 0xabbf8d02, 0x44ed3be3, 0xa5c33187, 0x4a918766, 0xa0175a04, + 0x4f45ece5, 0xb93a488d, 0x5668fe6c, 0xbcee230e, 0x53bc95ef, + 0xb2929f8b, 0x5dc0296a, 0xb746f408, 0x581442e9, 0x80c8ba99, + 0x6f9a0c78, 0x851cd11a, 0x6a4e67fb, 0x8b606d9f, 0x6432db7e, + 0x8eb4061c, 0x61e6b0fd, 0x97991495, 0x78cba274, 0x924d7f16, + 0x7d1fc9f7, 0x9c31c393, 0x73637572, 0x99e5a810, 0x76b71ef1, + 0xf32d5eb1, 0x1c7fe850, 0xf6f93532, 0x19ab83d3, 0xf88589b7, + 0x17d73f56, 0xfd51e234, 0x120354d5, 0xe47cf0bd, 0x0b2e465c, + 0xe1a89b3e, 0x0efa2ddf, 0xefd427bb, 0x0086915a, 0xea004c38, + 0x0552fad9, 0xdd8e02a9, 0x32dcb448, 0xd85a692a, 0x3708dfcb, + 0xd626d5af, 0x3974634e, 0xd3f2be2c, 0x3ca008cd, 0xcadfaca5, + 0x258d1a44, 0xcf0bc726, 0x205971c7, 0xc1777ba3, 0x2e25cd42, + 0xc4a31020, 0x2bf1a6c1, 0x14e696e1, 0xfbb42000, 0x1132fd62, + 0xfe604b83, 0x1f4e41e7, 0xf01cf706, 0x1a9a2a64, 0xf5c89c85, + 0x03b738ed, 0xece58e0c, 0x0663536e, 0xe931e58f, 0x081fefeb, + 0xe74d590a, 0x0dcb8468, 0xe2993289, 0x3a45caf9, 0xd5177c18, + 0x3f91a17a, 0xd0c3179b, 0x31ed1dff, 0xdebfab1e, 0x3439767c, + 0xdb6bc09d, 0x2d1464f5, 0xc246d214, 0x28c00f76, 0xc792b997, + 0x26bcb3f3, 0xc9ee0512, 0x2368d870, 0xcc3a6e91, 0x49a02ed1, + 0xa6f29830, 0x4c744552, 0xa326f3b3, 0x4208f9d7, 0xad5a4f36, + 0x47dc9254, 0xa88e24b5, 0x5ef180dd, 0xb1a3363c, 0x5b25eb5e, + 0xb4775dbf, 0x555957db, 0xba0be13a, 0x508d3c58, 0xbfdf8ab9, + 0x670372c9, 0x8851c428, 0x62d7194a, 0x8d85afab, 0x6caba5cf, + 0x83f9132e, 0x697fce4c, 0x862d78ad, 0x7052dcc5, 0x9f006a24, + 0x7586b746, 0x9ad401a7, 0x7bfa0bc3, 0x94a8bd22, 0x7e2e6040, + 0x917cd6a1}, + {0x00000000, 0x87a6cb43, 0xd43c90c7, 0x539a5b84, 0x730827cf, + 0xf4aeec8c, 0xa734b708, 0x20927c4b, 0xe6104f9e, 0x61b684dd, + 0x322cdf59, 0xb58a141a, 0x95186851, 0x12bea312, 0x4124f896, + 0xc68233d5, 0x1751997d, 0x90f7523e, 0xc36d09ba, 0x44cbc2f9, + 0x6459beb2, 0xe3ff75f1, 0xb0652e75, 0x37c3e536, 0xf141d6e3, + 0x76e71da0, 0x257d4624, 0xa2db8d67, 0x8249f12c, 0x05ef3a6f, + 0x567561eb, 0xd1d3aaa8, 0x2ea332fa, 0xa905f9b9, 0xfa9fa23d, + 0x7d39697e, 0x5dab1535, 0xda0dde76, 0x899785f2, 0x0e314eb1, + 0xc8b37d64, 0x4f15b627, 0x1c8feda3, 0x9b2926e0, 0xbbbb5aab, + 0x3c1d91e8, 0x6f87ca6c, 0xe821012f, 0x39f2ab87, 0xbe5460c4, + 0xedce3b40, 0x6a68f003, 0x4afa8c48, 0xcd5c470b, 0x9ec61c8f, + 0x1960d7cc, 0xdfe2e419, 0x58442f5a, 0x0bde74de, 0x8c78bf9d, + 0xaceac3d6, 0x2b4c0895, 0x78d65311, 0xff709852, 0x5d4665f4, + 0xdae0aeb7, 0x897af533, 0x0edc3e70, 0x2e4e423b, 0xa9e88978, + 0xfa72d2fc, 0x7dd419bf, 0xbb562a6a, 0x3cf0e129, 0x6f6abaad, + 0xe8cc71ee, 0xc85e0da5, 0x4ff8c6e6, 0x1c629d62, 0x9bc45621, + 0x4a17fc89, 0xcdb137ca, 0x9e2b6c4e, 0x198da70d, 0x391fdb46, + 0xbeb91005, 0xed234b81, 0x6a8580c2, 0xac07b317, 0x2ba17854, + 0x783b23d0, 0xff9de893, 0xdf0f94d8, 0x58a95f9b, 0x0b33041f, + 0x8c95cf5c, 0x73e5570e, 0xf4439c4d, 0xa7d9c7c9, 0x207f0c8a, + 0x00ed70c1, 0x874bbb82, 0xd4d1e006, 0x53772b45, 0x95f51890, + 0x1253d3d3, 0x41c98857, 0xc66f4314, 0xe6fd3f5f, 0x615bf41c, + 0x32c1af98, 0xb56764db, 0x64b4ce73, 0xe3120530, 0xb0885eb4, + 0x372e95f7, 0x17bce9bc, 0x901a22ff, 0xc380797b, 0x4426b238, + 0x82a481ed, 0x05024aae, 0x5698112a, 0xd13eda69, 0xf1aca622, + 0x760a6d61, 0x259036e5, 0xa236fda6, 0xba8ccbe8, 0x3d2a00ab, + 0x6eb05b2f, 0xe916906c, 0xc984ec27, 0x4e222764, 0x1db87ce0, + 0x9a1eb7a3, 0x5c9c8476, 0xdb3a4f35, 0x88a014b1, 0x0f06dff2, + 0x2f94a3b9, 0xa83268fa, 0xfba8337e, 0x7c0ef83d, 0xaddd5295, + 0x2a7b99d6, 0x79e1c252, 0xfe470911, 0xded5755a, 0x5973be19, + 0x0ae9e59d, 0x8d4f2ede, 0x4bcd1d0b, 0xcc6bd648, 0x9ff18dcc, + 0x1857468f, 0x38c53ac4, 0xbf63f187, 0xecf9aa03, 0x6b5f6140, + 0x942ff912, 0x13893251, 0x401369d5, 0xc7b5a296, 0xe727dedd, + 0x6081159e, 0x331b4e1a, 0xb4bd8559, 0x723fb68c, 0xf5997dcf, + 0xa603264b, 0x21a5ed08, 0x01379143, 0x86915a00, 0xd50b0184, + 0x52adcac7, 0x837e606f, 0x04d8ab2c, 0x5742f0a8, 0xd0e43beb, + 0xf07647a0, 0x77d08ce3, 0x244ad767, 0xa3ec1c24, 0x656e2ff1, + 0xe2c8e4b2, 0xb152bf36, 0x36f47475, 0x1666083e, 0x91c0c37d, + 0xc25a98f9, 0x45fc53ba, 0xe7caae1c, 0x606c655f, 0x33f63edb, + 0xb450f598, 0x94c289d3, 0x13644290, 0x40fe1914, 0xc758d257, + 0x01dae182, 0x867c2ac1, 0xd5e67145, 0x5240ba06, 0x72d2c64d, + 0xf5740d0e, 0xa6ee568a, 0x21489dc9, 0xf09b3761, 0x773dfc22, + 0x24a7a7a6, 0xa3016ce5, 0x839310ae, 0x0435dbed, 0x57af8069, + 0xd0094b2a, 0x168b78ff, 0x912db3bc, 0xc2b7e838, 0x4511237b, + 0x65835f30, 0xe2259473, 0xb1bfcff7, 0x361904b4, 0xc9699ce6, + 0x4ecf57a5, 0x1d550c21, 0x9af3c762, 0xba61bb29, 0x3dc7706a, + 0x6e5d2bee, 0xe9fbe0ad, 0x2f79d378, 0xa8df183b, 0xfb4543bf, + 0x7ce388fc, 0x5c71f4b7, 0xdbd73ff4, 0x884d6470, 0x0febaf33, + 0xde38059b, 0x599eced8, 0x0a04955c, 0x8da25e1f, 0xad302254, + 0x2a96e917, 0x790cb293, 0xfeaa79d0, 0x38284a05, 0xbf8e8146, + 0xec14dac2, 0x6bb21181, 0x4b206dca, 0xcc86a689, 0x9f1cfd0d, + 0x18ba364e}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x43cba687, 0xc7903cd4, 0x845b9a53, 0xcf270873, + 0x8cecaef4, 0x08b734a7, 0x4b7c9220, 0x9e4f10e6, 0xdd84b661, + 0x59df2c32, 0x1a148ab5, 0x51681895, 0x12a3be12, 0x96f82441, + 0xd53382c6, 0x7d995117, 0x3e52f790, 0xba096dc3, 0xf9c2cb44, + 0xb2be5964, 0xf175ffe3, 0x752e65b0, 0x36e5c337, 0xe3d641f1, + 0xa01de776, 0x24467d25, 0x678ddba2, 0x2cf14982, 0x6f3aef05, + 0xeb617556, 0xa8aad3d1, 0xfa32a32e, 0xb9f905a9, 0x3da29ffa, + 0x7e69397d, 0x3515ab5d, 0x76de0dda, 0xf2859789, 0xb14e310e, + 0x647db3c8, 0x27b6154f, 0xa3ed8f1c, 0xe026299b, 0xab5abbbb, + 0xe8911d3c, 0x6cca876f, 0x2f0121e8, 0x87abf239, 0xc46054be, + 0x403bceed, 0x03f0686a, 0x488cfa4a, 0x0b475ccd, 0x8f1cc69e, + 0xccd76019, 0x19e4e2df, 0x5a2f4458, 0xde74de0b, 0x9dbf788c, + 0xd6c3eaac, 0x95084c2b, 0x1153d678, 0x529870ff, 0xf465465d, + 0xb7aee0da, 0x33f57a89, 0x703edc0e, 0x3b424e2e, 0x7889e8a9, + 0xfcd272fa, 0xbf19d47d, 0x6a2a56bb, 0x29e1f03c, 0xadba6a6f, + 0xee71cce8, 0xa50d5ec8, 0xe6c6f84f, 0x629d621c, 0x2156c49b, + 0x89fc174a, 0xca37b1cd, 0x4e6c2b9e, 0x0da78d19, 0x46db1f39, + 0x0510b9be, 0x814b23ed, 0xc280856a, 0x17b307ac, 0x5478a12b, + 0xd0233b78, 0x93e89dff, 0xd8940fdf, 0x9b5fa958, 0x1f04330b, + 0x5ccf958c, 0x0e57e573, 0x4d9c43f4, 0xc9c7d9a7, 0x8a0c7f20, + 0xc170ed00, 0x82bb4b87, 0x06e0d1d4, 0x452b7753, 0x9018f595, + 0xd3d35312, 0x5788c941, 0x14436fc6, 0x5f3ffde6, 0x1cf45b61, + 0x98afc132, 0xdb6467b5, 0x73ceb464, 0x300512e3, 0xb45e88b0, + 0xf7952e37, 0xbce9bc17, 0xff221a90, 0x7b7980c3, 0x38b22644, + 0xed81a482, 0xae4a0205, 0x2a119856, 0x69da3ed1, 0x22a6acf1, + 0x616d0a76, 0xe5369025, 0xa6fd36a2, 0xe8cb8cba, 0xab002a3d, + 0x2f5bb06e, 0x6c9016e9, 0x27ec84c9, 0x6427224e, 0xe07cb81d, + 0xa3b71e9a, 0x76849c5c, 0x354f3adb, 0xb114a088, 0xf2df060f, + 0xb9a3942f, 0xfa6832a8, 0x7e33a8fb, 0x3df80e7c, 0x9552ddad, + 0xd6997b2a, 0x52c2e179, 0x110947fe, 0x5a75d5de, 0x19be7359, + 0x9de5e90a, 0xde2e4f8d, 0x0b1dcd4b, 0x48d66bcc, 0xcc8df19f, + 0x8f465718, 0xc43ac538, 0x87f163bf, 0x03aaf9ec, 0x40615f6b, + 0x12f92f94, 0x51328913, 0xd5691340, 0x96a2b5c7, 0xddde27e7, + 0x9e158160, 0x1a4e1b33, 0x5985bdb4, 0x8cb63f72, 0xcf7d99f5, + 0x4b2603a6, 0x08eda521, 0x43913701, 0x005a9186, 0x84010bd5, + 0xc7caad52, 0x6f607e83, 0x2cabd804, 0xa8f04257, 0xeb3be4d0, + 0xa04776f0, 0xe38cd077, 0x67d74a24, 0x241ceca3, 0xf12f6e65, + 0xb2e4c8e2, 0x36bf52b1, 0x7574f436, 0x3e086616, 0x7dc3c091, + 0xf9985ac2, 0xba53fc45, 0x1caecae7, 0x5f656c60, 0xdb3ef633, + 0x98f550b4, 0xd389c294, 0x90426413, 0x1419fe40, 0x57d258c7, + 0x82e1da01, 0xc12a7c86, 0x4571e6d5, 0x06ba4052, 0x4dc6d272, + 0x0e0d74f5, 0x8a56eea6, 0xc99d4821, 0x61379bf0, 0x22fc3d77, + 0xa6a7a724, 0xe56c01a3, 0xae109383, 0xeddb3504, 0x6980af57, + 0x2a4b09d0, 0xff788b16, 0xbcb32d91, 0x38e8b7c2, 0x7b231145, + 0x305f8365, 0x739425e2, 0xf7cfbfb1, 0xb4041936, 0xe69c69c9, + 0xa557cf4e, 0x210c551d, 0x62c7f39a, 0x29bb61ba, 0x6a70c73d, + 0xee2b5d6e, 0xade0fbe9, 0x78d3792f, 0x3b18dfa8, 0xbf4345fb, + 0xfc88e37c, 0xb7f4715c, 0xf43fd7db, 0x70644d88, 0x33afeb0f, + 0x9b0538de, 0xd8ce9e59, 0x5c95040a, 0x1f5ea28d, 0x542230ad, + 0x17e9962a, 0x93b20c79, 0xd079aafe, 0x054a2838, 0x46818ebf, + 0xc2da14ec, 0x8111b26b, 0xca6d204b, 0x89a686cc, 0x0dfd1c9f, + 0x4e36ba18}, + {0x00000000, 0xe1b652ef, 0x836bd405, 0x62dd86ea, 0x06d7a80b, + 0xe761fae4, 0x85bc7c0e, 0x640a2ee1, 0x0cae5117, 0xed1803f8, + 0x8fc58512, 0x6e73d7fd, 0x0a79f91c, 0xebcfabf3, 0x89122d19, + 0x68a47ff6, 0x185ca32e, 0xf9eaf1c1, 0x9b37772b, 0x7a8125c4, + 0x1e8b0b25, 0xff3d59ca, 0x9de0df20, 0x7c568dcf, 0x14f2f239, + 0xf544a0d6, 0x9799263c, 0x762f74d3, 0x12255a32, 0xf39308dd, + 0x914e8e37, 0x70f8dcd8, 0x30b8465d, 0xd10e14b2, 0xb3d39258, + 0x5265c0b7, 0x366fee56, 0xd7d9bcb9, 0xb5043a53, 0x54b268bc, + 0x3c16174a, 0xdda045a5, 0xbf7dc34f, 0x5ecb91a0, 0x3ac1bf41, + 0xdb77edae, 0xb9aa6b44, 0x581c39ab, 0x28e4e573, 0xc952b79c, + 0xab8f3176, 0x4a396399, 0x2e334d78, 0xcf851f97, 0xad58997d, + 0x4ceecb92, 0x244ab464, 0xc5fce68b, 0xa7216061, 0x4697328e, + 0x229d1c6f, 0xc32b4e80, 0xa1f6c86a, 0x40409a85, 0x60708dba, + 0x81c6df55, 0xe31b59bf, 0x02ad0b50, 0x66a725b1, 0x8711775e, + 0xe5ccf1b4, 0x047aa35b, 0x6cdedcad, 0x8d688e42, 0xefb508a8, + 0x0e035a47, 0x6a0974a6, 0x8bbf2649, 0xe962a0a3, 0x08d4f24c, + 0x782c2e94, 0x999a7c7b, 0xfb47fa91, 0x1af1a87e, 0x7efb869f, + 0x9f4dd470, 0xfd90529a, 0x1c260075, 0x74827f83, 0x95342d6c, + 0xf7e9ab86, 0x165ff969, 0x7255d788, 0x93e38567, 0xf13e038d, + 0x10885162, 0x50c8cbe7, 0xb17e9908, 0xd3a31fe2, 0x32154d0d, + 0x561f63ec, 0xb7a93103, 0xd574b7e9, 0x34c2e506, 0x5c669af0, + 0xbdd0c81f, 0xdf0d4ef5, 0x3ebb1c1a, 0x5ab132fb, 0xbb076014, + 0xd9dae6fe, 0x386cb411, 0x489468c9, 0xa9223a26, 0xcbffbccc, + 0x2a49ee23, 0x4e43c0c2, 0xaff5922d, 0xcd2814c7, 0x2c9e4628, + 0x443a39de, 0xa58c6b31, 0xc751eddb, 0x26e7bf34, 0x42ed91d5, + 0xa35bc33a, 0xc18645d0, 0x2030173f, 0x81e66bae, 0x60503941, + 0x028dbfab, 0xe33bed44, 0x8731c3a5, 0x6687914a, 0x045a17a0, + 0xe5ec454f, 0x8d483ab9, 0x6cfe6856, 0x0e23eebc, 0xef95bc53, + 0x8b9f92b2, 0x6a29c05d, 0x08f446b7, 0xe9421458, 0x99bac880, + 0x780c9a6f, 0x1ad11c85, 0xfb674e6a, 0x9f6d608b, 0x7edb3264, + 0x1c06b48e, 0xfdb0e661, 0x95149997, 0x74a2cb78, 0x167f4d92, + 0xf7c91f7d, 0x93c3319c, 0x72756373, 0x10a8e599, 0xf11eb776, + 0xb15e2df3, 0x50e87f1c, 0x3235f9f6, 0xd383ab19, 0xb78985f8, + 0x563fd717, 0x34e251fd, 0xd5540312, 0xbdf07ce4, 0x5c462e0b, + 0x3e9ba8e1, 0xdf2dfa0e, 0xbb27d4ef, 0x5a918600, 0x384c00ea, + 0xd9fa5205, 0xa9028edd, 0x48b4dc32, 0x2a695ad8, 0xcbdf0837, + 0xafd526d6, 0x4e637439, 0x2cbef2d3, 0xcd08a03c, 0xa5acdfca, + 0x441a8d25, 0x26c70bcf, 0xc7715920, 0xa37b77c1, 0x42cd252e, + 0x2010a3c4, 0xc1a6f12b, 0xe196e614, 0x0020b4fb, 0x62fd3211, + 0x834b60fe, 0xe7414e1f, 0x06f71cf0, 0x642a9a1a, 0x859cc8f5, + 0xed38b703, 0x0c8ee5ec, 0x6e536306, 0x8fe531e9, 0xebef1f08, + 0x0a594de7, 0x6884cb0d, 0x893299e2, 0xf9ca453a, 0x187c17d5, + 0x7aa1913f, 0x9b17c3d0, 0xff1ded31, 0x1eabbfde, 0x7c763934, + 0x9dc06bdb, 0xf564142d, 0x14d246c2, 0x760fc028, 0x97b992c7, + 0xf3b3bc26, 0x1205eec9, 0x70d86823, 0x916e3acc, 0xd12ea049, + 0x3098f2a6, 0x5245744c, 0xb3f326a3, 0xd7f90842, 0x364f5aad, + 0x5492dc47, 0xb5248ea8, 0xdd80f15e, 0x3c36a3b1, 0x5eeb255b, + 0xbf5d77b4, 0xdb575955, 0x3ae10bba, 0x583c8d50, 0xb98adfbf, + 0xc9720367, 0x28c45188, 0x4a19d762, 0xabaf858d, 0xcfa5ab6c, + 0x2e13f983, 0x4cce7f69, 0xad782d86, 0xc5dc5270, 0x246a009f, + 0x46b78675, 0xa701d49a, 0xc30bfa7b, 0x22bda894, 0x40602e7e, + 0xa1d67c91}, + {0x00000000, 0x5880e2d7, 0xf106b474, 0xa98656a3, 0xe20d68e9, + 0xba8d8a3e, 0x130bdc9d, 0x4b8b3e4a, 0x851da109, 0xdd9d43de, + 0x741b157d, 0x2c9bf7aa, 0x6710c9e0, 0x3f902b37, 0x96167d94, + 0xce969f43, 0x0a3b4213, 0x52bba0c4, 0xfb3df667, 0xa3bd14b0, + 0xe8362afa, 0xb0b6c82d, 0x19309e8e, 0x41b07c59, 0x8f26e31a, + 0xd7a601cd, 0x7e20576e, 0x26a0b5b9, 0x6d2b8bf3, 0x35ab6924, + 0x9c2d3f87, 0xc4addd50, 0x14768426, 0x4cf666f1, 0xe5703052, + 0xbdf0d285, 0xf67beccf, 0xaefb0e18, 0x077d58bb, 0x5ffdba6c, + 0x916b252f, 0xc9ebc7f8, 0x606d915b, 0x38ed738c, 0x73664dc6, + 0x2be6af11, 0x8260f9b2, 0xdae01b65, 0x1e4dc635, 0x46cd24e2, + 0xef4b7241, 0xb7cb9096, 0xfc40aedc, 0xa4c04c0b, 0x0d461aa8, + 0x55c6f87f, 0x9b50673c, 0xc3d085eb, 0x6a56d348, 0x32d6319f, + 0x795d0fd5, 0x21dded02, 0x885bbba1, 0xd0db5976, 0x28ec084d, + 0x706cea9a, 0xd9eabc39, 0x816a5eee, 0xcae160a4, 0x92618273, + 0x3be7d4d0, 0x63673607, 0xadf1a944, 0xf5714b93, 0x5cf71d30, + 0x0477ffe7, 0x4ffcc1ad, 0x177c237a, 0xbefa75d9, 0xe67a970e, + 0x22d74a5e, 0x7a57a889, 0xd3d1fe2a, 0x8b511cfd, 0xc0da22b7, + 0x985ac060, 0x31dc96c3, 0x695c7414, 0xa7caeb57, 0xff4a0980, + 0x56cc5f23, 0x0e4cbdf4, 0x45c783be, 0x1d476169, 0xb4c137ca, + 0xec41d51d, 0x3c9a8c6b, 0x641a6ebc, 0xcd9c381f, 0x951cdac8, + 0xde97e482, 0x86170655, 0x2f9150f6, 0x7711b221, 0xb9872d62, + 0xe107cfb5, 0x48819916, 0x10017bc1, 0x5b8a458b, 0x030aa75c, + 0xaa8cf1ff, 0xf20c1328, 0x36a1ce78, 0x6e212caf, 0xc7a77a0c, + 0x9f2798db, 0xd4aca691, 0x8c2c4446, 0x25aa12e5, 0x7d2af032, + 0xb3bc6f71, 0xeb3c8da6, 0x42badb05, 0x1a3a39d2, 0x51b10798, + 0x0931e54f, 0xa0b7b3ec, 0xf837513b, 0x50d8119a, 0x0858f34d, + 0xa1dea5ee, 0xf95e4739, 0xb2d57973, 0xea559ba4, 0x43d3cd07, + 0x1b532fd0, 0xd5c5b093, 0x8d455244, 0x24c304e7, 0x7c43e630, + 0x37c8d87a, 0x6f483aad, 0xc6ce6c0e, 0x9e4e8ed9, 0x5ae35389, + 0x0263b15e, 0xabe5e7fd, 0xf365052a, 0xb8ee3b60, 0xe06ed9b7, + 0x49e88f14, 0x11686dc3, 0xdffef280, 0x877e1057, 0x2ef846f4, + 0x7678a423, 0x3df39a69, 0x657378be, 0xccf52e1d, 0x9475ccca, + 0x44ae95bc, 0x1c2e776b, 0xb5a821c8, 0xed28c31f, 0xa6a3fd55, + 0xfe231f82, 0x57a54921, 0x0f25abf6, 0xc1b334b5, 0x9933d662, + 0x30b580c1, 0x68356216, 0x23be5c5c, 0x7b3ebe8b, 0xd2b8e828, + 0x8a380aff, 0x4e95d7af, 0x16153578, 0xbf9363db, 0xe713810c, + 0xac98bf46, 0xf4185d91, 0x5d9e0b32, 0x051ee9e5, 0xcb8876a6, + 0x93089471, 0x3a8ec2d2, 0x620e2005, 0x29851e4f, 0x7105fc98, + 0xd883aa3b, 0x800348ec, 0x783419d7, 0x20b4fb00, 0x8932ada3, + 0xd1b24f74, 0x9a39713e, 0xc2b993e9, 0x6b3fc54a, 0x33bf279d, + 0xfd29b8de, 0xa5a95a09, 0x0c2f0caa, 0x54afee7d, 0x1f24d037, + 0x47a432e0, 0xee226443, 0xb6a28694, 0x720f5bc4, 0x2a8fb913, + 0x8309efb0, 0xdb890d67, 0x9002332d, 0xc882d1fa, 0x61048759, + 0x3984658e, 0xf712facd, 0xaf92181a, 0x06144eb9, 0x5e94ac6e, + 0x151f9224, 0x4d9f70f3, 0xe4192650, 0xbc99c487, 0x6c429df1, + 0x34c27f26, 0x9d442985, 0xc5c4cb52, 0x8e4ff518, 0xd6cf17cf, + 0x7f49416c, 0x27c9a3bb, 0xe95f3cf8, 0xb1dfde2f, 0x1859888c, + 0x40d96a5b, 0x0b525411, 0x53d2b6c6, 0xfa54e065, 0xa2d402b2, + 0x6679dfe2, 0x3ef93d35, 0x977f6b96, 0xcfff8941, 0x8474b70b, + 0xdcf455dc, 0x7572037f, 0x2df2e1a8, 0xe3647eeb, 0xbbe49c3c, + 0x1262ca9f, 0x4ae22848, 0x01691602, 0x59e9f4d5, 0xf06fa276, + 0xa8ef40a1}, + {0x00000000, 0x463b6765, 0x8c76ceca, 0xca4da9af, 0x59ebed4e, + 0x1fd08a2b, 0xd59d2384, 0x93a644e1, 0xb2d6db9d, 0xf4edbcf8, + 0x3ea01557, 0x789b7232, 0xeb3d36d3, 0xad0651b6, 0x674bf819, + 0x21709f7c, 0x25abc6e0, 0x6390a185, 0xa9dd082a, 0xefe66f4f, + 0x7c402bae, 0x3a7b4ccb, 0xf036e564, 0xb60d8201, 0x977d1d7d, + 0xd1467a18, 0x1b0bd3b7, 0x5d30b4d2, 0xce96f033, 0x88ad9756, + 0x42e03ef9, 0x04db599c, 0x0b50fc1a, 0x4d6b9b7f, 0x872632d0, + 0xc11d55b5, 0x52bb1154, 0x14807631, 0xdecddf9e, 0x98f6b8fb, + 0xb9862787, 0xffbd40e2, 0x35f0e94d, 0x73cb8e28, 0xe06dcac9, + 0xa656adac, 0x6c1b0403, 0x2a206366, 0x2efb3afa, 0x68c05d9f, + 0xa28df430, 0xe4b69355, 0x7710d7b4, 0x312bb0d1, 0xfb66197e, + 0xbd5d7e1b, 0x9c2de167, 0xda168602, 0x105b2fad, 0x566048c8, + 0xc5c60c29, 0x83fd6b4c, 0x49b0c2e3, 0x0f8ba586, 0x16a0f835, + 0x509b9f50, 0x9ad636ff, 0xdced519a, 0x4f4b157b, 0x0970721e, + 0xc33ddbb1, 0x8506bcd4, 0xa47623a8, 0xe24d44cd, 0x2800ed62, + 0x6e3b8a07, 0xfd9dcee6, 0xbba6a983, 0x71eb002c, 0x37d06749, + 0x330b3ed5, 0x753059b0, 0xbf7df01f, 0xf946977a, 0x6ae0d39b, + 0x2cdbb4fe, 0xe6961d51, 0xa0ad7a34, 0x81dde548, 0xc7e6822d, + 0x0dab2b82, 0x4b904ce7, 0xd8360806, 0x9e0d6f63, 0x5440c6cc, + 0x127ba1a9, 0x1df0042f, 0x5bcb634a, 0x9186cae5, 0xd7bdad80, + 0x441be961, 0x02208e04, 0xc86d27ab, 0x8e5640ce, 0xaf26dfb2, + 0xe91db8d7, 0x23501178, 0x656b761d, 0xf6cd32fc, 0xb0f65599, + 0x7abbfc36, 0x3c809b53, 0x385bc2cf, 0x7e60a5aa, 0xb42d0c05, + 0xf2166b60, 0x61b02f81, 0x278b48e4, 0xedc6e14b, 0xabfd862e, + 0x8a8d1952, 0xccb67e37, 0x06fbd798, 0x40c0b0fd, 0xd366f41c, + 0x955d9379, 0x5f103ad6, 0x192b5db3, 0x2c40f16b, 0x6a7b960e, + 0xa0363fa1, 0xe60d58c4, 0x75ab1c25, 0x33907b40, 0xf9ddd2ef, + 0xbfe6b58a, 0x9e962af6, 0xd8ad4d93, 0x12e0e43c, 0x54db8359, + 0xc77dc7b8, 0x8146a0dd, 0x4b0b0972, 0x0d306e17, 0x09eb378b, + 0x4fd050ee, 0x859df941, 0xc3a69e24, 0x5000dac5, 0x163bbda0, + 0xdc76140f, 0x9a4d736a, 0xbb3dec16, 0xfd068b73, 0x374b22dc, + 0x717045b9, 0xe2d60158, 0xa4ed663d, 0x6ea0cf92, 0x289ba8f7, + 0x27100d71, 0x612b6a14, 0xab66c3bb, 0xed5da4de, 0x7efbe03f, + 0x38c0875a, 0xf28d2ef5, 0xb4b64990, 0x95c6d6ec, 0xd3fdb189, + 0x19b01826, 0x5f8b7f43, 0xcc2d3ba2, 0x8a165cc7, 0x405bf568, + 0x0660920d, 0x02bbcb91, 0x4480acf4, 0x8ecd055b, 0xc8f6623e, + 0x5b5026df, 0x1d6b41ba, 0xd726e815, 0x911d8f70, 0xb06d100c, + 0xf6567769, 0x3c1bdec6, 0x7a20b9a3, 0xe986fd42, 0xafbd9a27, + 0x65f03388, 0x23cb54ed, 0x3ae0095e, 0x7cdb6e3b, 0xb696c794, + 0xf0ada0f1, 0x630be410, 0x25308375, 0xef7d2ada, 0xa9464dbf, + 0x8836d2c3, 0xce0db5a6, 0x04401c09, 0x427b7b6c, 0xd1dd3f8d, + 0x97e658e8, 0x5dabf147, 0x1b909622, 0x1f4bcfbe, 0x5970a8db, + 0x933d0174, 0xd5066611, 0x46a022f0, 0x009b4595, 0xcad6ec3a, + 0x8ced8b5f, 0xad9d1423, 0xeba67346, 0x21ebdae9, 0x67d0bd8c, + 0xf476f96d, 0xb24d9e08, 0x780037a7, 0x3e3b50c2, 0x31b0f544, + 0x778b9221, 0xbdc63b8e, 0xfbfd5ceb, 0x685b180a, 0x2e607f6f, + 0xe42dd6c0, 0xa216b1a5, 0x83662ed9, 0xc55d49bc, 0x0f10e013, + 0x492b8776, 0xda8dc397, 0x9cb6a4f2, 0x56fb0d5d, 0x10c06a38, + 0x141b33a4, 0x522054c1, 0x986dfd6e, 0xde569a0b, 0x4df0deea, + 0x0bcbb98f, 0xc1861020, 0x87bd7745, 0xa6cde839, 0xe0f68f5c, + 0x2abb26f3, 0x6c804196, 0xff260577, 0xb91d6212, 0x7350cbbd, + 0x356bacd8}}; + +#endif + +#endif + +#if N == 6 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x3db1ecdc, 0x7b63d9b8, 0x46d23564, 0xf6c7b370, + 0xcb765fac, 0x8da46ac8, 0xb0158614, 0x36fe60a1, 0x0b4f8c7d, + 0x4d9db919, 0x702c55c5, 0xc039d3d1, 0xfd883f0d, 0xbb5a0a69, + 0x86ebe6b5, 0x6dfcc142, 0x504d2d9e, 0x169f18fa, 0x2b2ef426, + 0x9b3b7232, 0xa68a9eee, 0xe058ab8a, 0xdde94756, 0x5b02a1e3, + 0x66b34d3f, 0x2061785b, 0x1dd09487, 0xadc51293, 0x9074fe4f, + 0xd6a6cb2b, 0xeb1727f7, 0xdbf98284, 0xe6486e58, 0xa09a5b3c, + 0x9d2bb7e0, 0x2d3e31f4, 0x108fdd28, 0x565de84c, 0x6bec0490, + 0xed07e225, 0xd0b60ef9, 0x96643b9d, 0xabd5d741, 0x1bc05155, + 0x2671bd89, 0x60a388ed, 0x5d126431, 0xb60543c6, 0x8bb4af1a, + 0xcd669a7e, 0xf0d776a2, 0x40c2f0b6, 0x7d731c6a, 0x3ba1290e, + 0x0610c5d2, 0x80fb2367, 0xbd4acfbb, 0xfb98fadf, 0xc6291603, + 0x763c9017, 0x4b8d7ccb, 0x0d5f49af, 0x30eea573, 0x6c820349, + 0x5133ef95, 0x17e1daf1, 0x2a50362d, 0x9a45b039, 0xa7f45ce5, + 0xe1266981, 0xdc97855d, 0x5a7c63e8, 0x67cd8f34, 0x211fba50, + 0x1cae568c, 0xacbbd098, 0x910a3c44, 0xd7d80920, 0xea69e5fc, + 0x017ec20b, 0x3ccf2ed7, 0x7a1d1bb3, 0x47acf76f, 0xf7b9717b, + 0xca089da7, 0x8cdaa8c3, 0xb16b441f, 0x3780a2aa, 0x0a314e76, + 0x4ce37b12, 0x715297ce, 0xc14711da, 0xfcf6fd06, 0xba24c862, + 0x879524be, 0xb77b81cd, 0x8aca6d11, 0xcc185875, 0xf1a9b4a9, + 0x41bc32bd, 0x7c0dde61, 0x3adfeb05, 0x076e07d9, 0x8185e16c, + 0xbc340db0, 0xfae638d4, 0xc757d408, 0x7742521c, 0x4af3bec0, + 0x0c218ba4, 0x31906778, 0xda87408f, 0xe736ac53, 0xa1e49937, + 0x9c5575eb, 0x2c40f3ff, 0x11f11f23, 0x57232a47, 0x6a92c69b, + 0xec79202e, 0xd1c8ccf2, 0x971af996, 0xaaab154a, 0x1abe935e, + 0x270f7f82, 0x61dd4ae6, 0x5c6ca63a, 0xd9040692, 0xe4b5ea4e, + 0xa267df2a, 0x9fd633f6, 0x2fc3b5e2, 0x1272593e, 0x54a06c5a, + 0x69118086, 0xeffa6633, 0xd24b8aef, 0x9499bf8b, 0xa9285357, + 0x193dd543, 0x248c399f, 0x625e0cfb, 0x5fefe027, 0xb4f8c7d0, + 0x89492b0c, 0xcf9b1e68, 0xf22af2b4, 0x423f74a0, 0x7f8e987c, + 0x395cad18, 0x04ed41c4, 0x8206a771, 0xbfb74bad, 0xf9657ec9, + 0xc4d49215, 0x74c11401, 0x4970f8dd, 0x0fa2cdb9, 0x32132165, + 0x02fd8416, 0x3f4c68ca, 0x799e5dae, 0x442fb172, 0xf43a3766, + 0xc98bdbba, 0x8f59eede, 0xb2e80202, 0x3403e4b7, 0x09b2086b, + 0x4f603d0f, 0x72d1d1d3, 0xc2c457c7, 0xff75bb1b, 0xb9a78e7f, + 0x841662a3, 0x6f014554, 0x52b0a988, 0x14629cec, 0x29d37030, + 0x99c6f624, 0xa4771af8, 0xe2a52f9c, 0xdf14c340, 0x59ff25f5, + 0x644ec929, 0x229cfc4d, 0x1f2d1091, 0xaf389685, 0x92897a59, + 0xd45b4f3d, 0xe9eaa3e1, 0xb58605db, 0x8837e907, 0xcee5dc63, + 0xf35430bf, 0x4341b6ab, 0x7ef05a77, 0x38226f13, 0x059383cf, + 0x8378657a, 0xbec989a6, 0xf81bbcc2, 0xc5aa501e, 0x75bfd60a, + 0x480e3ad6, 0x0edc0fb2, 0x336de36e, 0xd87ac499, 0xe5cb2845, + 0xa3191d21, 0x9ea8f1fd, 0x2ebd77e9, 0x130c9b35, 0x55deae51, + 0x686f428d, 0xee84a438, 0xd33548e4, 0x95e77d80, 0xa856915c, + 0x18431748, 0x25f2fb94, 0x6320cef0, 0x5e91222c, 0x6e7f875f, + 0x53ce6b83, 0x151c5ee7, 0x28adb23b, 0x98b8342f, 0xa509d8f3, + 0xe3dbed97, 0xde6a014b, 0x5881e7fe, 0x65300b22, 0x23e23e46, + 0x1e53d29a, 0xae46548e, 0x93f7b852, 0xd5258d36, 0xe89461ea, + 0x0383461d, 0x3e32aac1, 0x78e09fa5, 0x45517379, 0xf544f56d, + 0xc8f519b1, 0x8e272cd5, 0xb396c009, 0x357d26bc, 0x08ccca60, + 0x4e1eff04, 0x73af13d8, 0xc3ba95cc, 0xfe0b7910, 0xb8d94c74, + 0x8568a0a8}, + {0x00000000, 0x69790b65, 0xd2f216ca, 0xbb8b1daf, 0x7e952bd5, + 0x17ec20b0, 0xac673d1f, 0xc51e367a, 0xfd2a57aa, 0x94535ccf, + 0x2fd84160, 0x46a14a05, 0x83bf7c7f, 0xeac6771a, 0x514d6ab5, + 0x383461d0, 0x2125a915, 0x485ca270, 0xf3d7bfdf, 0x9aaeb4ba, + 0x5fb082c0, 0x36c989a5, 0x8d42940a, 0xe43b9f6f, 0xdc0ffebf, + 0xb576f5da, 0x0efde875, 0x6784e310, 0xa29ad56a, 0xcbe3de0f, + 0x7068c3a0, 0x1911c8c5, 0x424b522a, 0x2b32594f, 0x90b944e0, + 0xf9c04f85, 0x3cde79ff, 0x55a7729a, 0xee2c6f35, 0x87556450, + 0xbf610580, 0xd6180ee5, 0x6d93134a, 0x04ea182f, 0xc1f42e55, + 0xa88d2530, 0x1306389f, 0x7a7f33fa, 0x636efb3f, 0x0a17f05a, + 0xb19cedf5, 0xd8e5e690, 0x1dfbd0ea, 0x7482db8f, 0xcf09c620, + 0xa670cd45, 0x9e44ac95, 0xf73da7f0, 0x4cb6ba5f, 0x25cfb13a, + 0xe0d18740, 0x89a88c25, 0x3223918a, 0x5b5a9aef, 0x8496a454, + 0xedefaf31, 0x5664b29e, 0x3f1db9fb, 0xfa038f81, 0x937a84e4, + 0x28f1994b, 0x4188922e, 0x79bcf3fe, 0x10c5f89b, 0xab4ee534, + 0xc237ee51, 0x0729d82b, 0x6e50d34e, 0xd5dbcee1, 0xbca2c584, + 0xa5b30d41, 0xccca0624, 0x77411b8b, 0x1e3810ee, 0xdb262694, + 0xb25f2df1, 0x09d4305e, 0x60ad3b3b, 0x58995aeb, 0x31e0518e, + 0x8a6b4c21, 0xe3124744, 0x260c713e, 0x4f757a5b, 0xf4fe67f4, + 0x9d876c91, 0xc6ddf67e, 0xafa4fd1b, 0x142fe0b4, 0x7d56ebd1, + 0xb848ddab, 0xd131d6ce, 0x6abacb61, 0x03c3c004, 0x3bf7a1d4, + 0x528eaab1, 0xe905b71e, 0x807cbc7b, 0x45628a01, 0x2c1b8164, + 0x97909ccb, 0xfee997ae, 0xe7f85f6b, 0x8e81540e, 0x350a49a1, + 0x5c7342c4, 0x996d74be, 0xf0147fdb, 0x4b9f6274, 0x22e66911, + 0x1ad208c1, 0x73ab03a4, 0xc8201e0b, 0xa159156e, 0x64472314, + 0x0d3e2871, 0xb6b535de, 0xdfcc3ebb, 0xd25c4ee9, 0xbb25458c, + 0x00ae5823, 0x69d75346, 0xacc9653c, 0xc5b06e59, 0x7e3b73f6, + 0x17427893, 0x2f761943, 0x460f1226, 0xfd840f89, 0x94fd04ec, + 0x51e33296, 0x389a39f3, 0x8311245c, 0xea682f39, 0xf379e7fc, + 0x9a00ec99, 0x218bf136, 0x48f2fa53, 0x8deccc29, 0xe495c74c, + 0x5f1edae3, 0x3667d186, 0x0e53b056, 0x672abb33, 0xdca1a69c, + 0xb5d8adf9, 0x70c69b83, 0x19bf90e6, 0xa2348d49, 0xcb4d862c, + 0x90171cc3, 0xf96e17a6, 0x42e50a09, 0x2b9c016c, 0xee823716, + 0x87fb3c73, 0x3c7021dc, 0x55092ab9, 0x6d3d4b69, 0x0444400c, + 0xbfcf5da3, 0xd6b656c6, 0x13a860bc, 0x7ad16bd9, 0xc15a7676, + 0xa8237d13, 0xb132b5d6, 0xd84bbeb3, 0x63c0a31c, 0x0ab9a879, + 0xcfa79e03, 0xa6de9566, 0x1d5588c9, 0x742c83ac, 0x4c18e27c, + 0x2561e919, 0x9eeaf4b6, 0xf793ffd3, 0x328dc9a9, 0x5bf4c2cc, + 0xe07fdf63, 0x8906d406, 0x56caeabd, 0x3fb3e1d8, 0x8438fc77, + 0xed41f712, 0x285fc168, 0x4126ca0d, 0xfaadd7a2, 0x93d4dcc7, + 0xabe0bd17, 0xc299b672, 0x7912abdd, 0x106ba0b8, 0xd57596c2, + 0xbc0c9da7, 0x07878008, 0x6efe8b6d, 0x77ef43a8, 0x1e9648cd, + 0xa51d5562, 0xcc645e07, 0x097a687d, 0x60036318, 0xdb887eb7, + 0xb2f175d2, 0x8ac51402, 0xe3bc1f67, 0x583702c8, 0x314e09ad, + 0xf4503fd7, 0x9d2934b2, 0x26a2291d, 0x4fdb2278, 0x1481b897, + 0x7df8b3f2, 0xc673ae5d, 0xaf0aa538, 0x6a149342, 0x036d9827, + 0xb8e68588, 0xd19f8eed, 0xe9abef3d, 0x80d2e458, 0x3b59f9f7, + 0x5220f292, 0x973ec4e8, 0xfe47cf8d, 0x45ccd222, 0x2cb5d947, + 0x35a41182, 0x5cdd1ae7, 0xe7560748, 0x8e2f0c2d, 0x4b313a57, + 0x22483132, 0x99c32c9d, 0xf0ba27f8, 0xc88e4628, 0xa1f74d4d, + 0x1a7c50e2, 0x73055b87, 0xb61b6dfd, 0xdf626698, 0x64e97b37, + 0x0d907052}, + {0x00000000, 0x7fc99b93, 0xff933726, 0x805aacb5, 0x2457680d, + 0x5b9ef39e, 0xdbc45f2b, 0xa40dc4b8, 0x48aed01a, 0x37674b89, + 0xb73de73c, 0xc8f47caf, 0x6cf9b817, 0x13302384, 0x936a8f31, + 0xeca314a2, 0x915da034, 0xee943ba7, 0x6ece9712, 0x11070c81, + 0xb50ac839, 0xcac353aa, 0x4a99ff1f, 0x3550648c, 0xd9f3702e, + 0xa63aebbd, 0x26604708, 0x59a9dc9b, 0xfda41823, 0x826d83b0, + 0x02372f05, 0x7dfeb496, 0xf9ca4629, 0x8603ddba, 0x0659710f, + 0x7990ea9c, 0xdd9d2e24, 0xa254b5b7, 0x220e1902, 0x5dc78291, + 0xb1649633, 0xcead0da0, 0x4ef7a115, 0x313e3a86, 0x9533fe3e, + 0xeafa65ad, 0x6aa0c918, 0x1569528b, 0x6897e61d, 0x175e7d8e, + 0x9704d13b, 0xe8cd4aa8, 0x4cc08e10, 0x33091583, 0xb353b936, + 0xcc9a22a5, 0x20393607, 0x5ff0ad94, 0xdfaa0121, 0xa0639ab2, + 0x046e5e0a, 0x7ba7c599, 0xfbfd692c, 0x8434f2bf, 0x28e58a13, + 0x572c1180, 0xd776bd35, 0xa8bf26a6, 0x0cb2e21e, 0x737b798d, + 0xf321d538, 0x8ce84eab, 0x604b5a09, 0x1f82c19a, 0x9fd86d2f, + 0xe011f6bc, 0x441c3204, 0x3bd5a997, 0xbb8f0522, 0xc4469eb1, + 0xb9b82a27, 0xc671b1b4, 0x462b1d01, 0x39e28692, 0x9def422a, + 0xe226d9b9, 0x627c750c, 0x1db5ee9f, 0xf116fa3d, 0x8edf61ae, + 0x0e85cd1b, 0x714c5688, 0xd5419230, 0xaa8809a3, 0x2ad2a516, + 0x551b3e85, 0xd12fcc3a, 0xaee657a9, 0x2ebcfb1c, 0x5175608f, + 0xf578a437, 0x8ab13fa4, 0x0aeb9311, 0x75220882, 0x99811c20, + 0xe64887b3, 0x66122b06, 0x19dbb095, 0xbdd6742d, 0xc21fefbe, + 0x4245430b, 0x3d8cd898, 0x40726c0e, 0x3fbbf79d, 0xbfe15b28, + 0xc028c0bb, 0x64250403, 0x1bec9f90, 0x9bb63325, 0xe47fa8b6, + 0x08dcbc14, 0x77152787, 0xf74f8b32, 0x888610a1, 0x2c8bd419, + 0x53424f8a, 0xd318e33f, 0xacd178ac, 0x51cb1426, 0x2e028fb5, + 0xae582300, 0xd191b893, 0x759c7c2b, 0x0a55e7b8, 0x8a0f4b0d, + 0xf5c6d09e, 0x1965c43c, 0x66ac5faf, 0xe6f6f31a, 0x993f6889, + 0x3d32ac31, 0x42fb37a2, 0xc2a19b17, 0xbd680084, 0xc096b412, + 0xbf5f2f81, 0x3f058334, 0x40cc18a7, 0xe4c1dc1f, 0x9b08478c, + 0x1b52eb39, 0x649b70aa, 0x88386408, 0xf7f1ff9b, 0x77ab532e, + 0x0862c8bd, 0xac6f0c05, 0xd3a69796, 0x53fc3b23, 0x2c35a0b0, + 0xa801520f, 0xd7c8c99c, 0x57926529, 0x285bfeba, 0x8c563a02, + 0xf39fa191, 0x73c50d24, 0x0c0c96b7, 0xe0af8215, 0x9f661986, + 0x1f3cb533, 0x60f52ea0, 0xc4f8ea18, 0xbb31718b, 0x3b6bdd3e, + 0x44a246ad, 0x395cf23b, 0x469569a8, 0xc6cfc51d, 0xb9065e8e, + 0x1d0b9a36, 0x62c201a5, 0xe298ad10, 0x9d513683, 0x71f22221, + 0x0e3bb9b2, 0x8e611507, 0xf1a88e94, 0x55a54a2c, 0x2a6cd1bf, + 0xaa367d0a, 0xd5ffe699, 0x792e9e35, 0x06e705a6, 0x86bda913, + 0xf9743280, 0x5d79f638, 0x22b06dab, 0xa2eac11e, 0xdd235a8d, + 0x31804e2f, 0x4e49d5bc, 0xce137909, 0xb1dae29a, 0x15d72622, + 0x6a1ebdb1, 0xea441104, 0x958d8a97, 0xe8733e01, 0x97baa592, + 0x17e00927, 0x682992b4, 0xcc24560c, 0xb3edcd9f, 0x33b7612a, + 0x4c7efab9, 0xa0ddee1b, 0xdf147588, 0x5f4ed93d, 0x208742ae, + 0x848a8616, 0xfb431d85, 0x7b19b130, 0x04d02aa3, 0x80e4d81c, + 0xff2d438f, 0x7f77ef3a, 0x00be74a9, 0xa4b3b011, 0xdb7a2b82, + 0x5b208737, 0x24e91ca4, 0xc84a0806, 0xb7839395, 0x37d93f20, + 0x4810a4b3, 0xec1d600b, 0x93d4fb98, 0x138e572d, 0x6c47ccbe, + 0x11b97828, 0x6e70e3bb, 0xee2a4f0e, 0x91e3d49d, 0x35ee1025, + 0x4a278bb6, 0xca7d2703, 0xb5b4bc90, 0x5917a832, 0x26de33a1, + 0xa6849f14, 0xd94d0487, 0x7d40c03f, 0x02895bac, 0x82d3f719, + 0xfd1a6c8a}, + {0x00000000, 0xa396284c, 0x9c5d56d9, 0x3fcb7e95, 0xe3cbabf3, + 0x405d83bf, 0x7f96fd2a, 0xdc00d566, 0x1ce651a7, 0xbf7079eb, + 0x80bb077e, 0x232d2f32, 0xff2dfa54, 0x5cbbd218, 0x6370ac8d, + 0xc0e684c1, 0x39cca34e, 0x9a5a8b02, 0xa591f597, 0x0607dddb, + 0xda0708bd, 0x799120f1, 0x465a5e64, 0xe5cc7628, 0x252af2e9, + 0x86bcdaa5, 0xb977a430, 0x1ae18c7c, 0xc6e1591a, 0x65777156, + 0x5abc0fc3, 0xf92a278f, 0x7399469c, 0xd00f6ed0, 0xefc41045, + 0x4c523809, 0x9052ed6f, 0x33c4c523, 0x0c0fbbb6, 0xaf9993fa, + 0x6f7f173b, 0xcce93f77, 0xf32241e2, 0x50b469ae, 0x8cb4bcc8, + 0x2f229484, 0x10e9ea11, 0xb37fc25d, 0x4a55e5d2, 0xe9c3cd9e, + 0xd608b30b, 0x759e9b47, 0xa99e4e21, 0x0a08666d, 0x35c318f8, + 0x965530b4, 0x56b3b475, 0xf5259c39, 0xcaeee2ac, 0x6978cae0, + 0xb5781f86, 0x16ee37ca, 0x2925495f, 0x8ab36113, 0xe7328d38, + 0x44a4a574, 0x7b6fdbe1, 0xd8f9f3ad, 0x04f926cb, 0xa76f0e87, + 0x98a47012, 0x3b32585e, 0xfbd4dc9f, 0x5842f4d3, 0x67898a46, + 0xc41fa20a, 0x181f776c, 0xbb895f20, 0x844221b5, 0x27d409f9, + 0xdefe2e76, 0x7d68063a, 0x42a378af, 0xe13550e3, 0x3d358585, + 0x9ea3adc9, 0xa168d35c, 0x02fefb10, 0xc2187fd1, 0x618e579d, + 0x5e452908, 0xfdd30144, 0x21d3d422, 0x8245fc6e, 0xbd8e82fb, + 0x1e18aab7, 0x94abcba4, 0x373de3e8, 0x08f69d7d, 0xab60b531, + 0x77606057, 0xd4f6481b, 0xeb3d368e, 0x48ab1ec2, 0x884d9a03, + 0x2bdbb24f, 0x1410ccda, 0xb786e496, 0x6b8631f0, 0xc81019bc, + 0xf7db6729, 0x544d4f65, 0xad6768ea, 0x0ef140a6, 0x313a3e33, + 0x92ac167f, 0x4eacc319, 0xed3aeb55, 0xd2f195c0, 0x7167bd8c, + 0xb181394d, 0x12171101, 0x2ddc6f94, 0x8e4a47d8, 0x524a92be, + 0xf1dcbaf2, 0xce17c467, 0x6d81ec2b, 0x15141c31, 0xb682347d, + 0x89494ae8, 0x2adf62a4, 0xf6dfb7c2, 0x55499f8e, 0x6a82e11b, + 0xc914c957, 0x09f24d96, 0xaa6465da, 0x95af1b4f, 0x36393303, + 0xea39e665, 0x49afce29, 0x7664b0bc, 0xd5f298f0, 0x2cd8bf7f, + 0x8f4e9733, 0xb085e9a6, 0x1313c1ea, 0xcf13148c, 0x6c853cc0, + 0x534e4255, 0xf0d86a19, 0x303eeed8, 0x93a8c694, 0xac63b801, + 0x0ff5904d, 0xd3f5452b, 0x70636d67, 0x4fa813f2, 0xec3e3bbe, + 0x668d5aad, 0xc51b72e1, 0xfad00c74, 0x59462438, 0x8546f15e, + 0x26d0d912, 0x191ba787, 0xba8d8fcb, 0x7a6b0b0a, 0xd9fd2346, + 0xe6365dd3, 0x45a0759f, 0x99a0a0f9, 0x3a3688b5, 0x05fdf620, + 0xa66bde6c, 0x5f41f9e3, 0xfcd7d1af, 0xc31caf3a, 0x608a8776, + 0xbc8a5210, 0x1f1c7a5c, 0x20d704c9, 0x83412c85, 0x43a7a844, + 0xe0318008, 0xdffafe9d, 0x7c6cd6d1, 0xa06c03b7, 0x03fa2bfb, + 0x3c31556e, 0x9fa77d22, 0xf2269109, 0x51b0b945, 0x6e7bc7d0, + 0xcdedef9c, 0x11ed3afa, 0xb27b12b6, 0x8db06c23, 0x2e26446f, + 0xeec0c0ae, 0x4d56e8e2, 0x729d9677, 0xd10bbe3b, 0x0d0b6b5d, + 0xae9d4311, 0x91563d84, 0x32c015c8, 0xcbea3247, 0x687c1a0b, + 0x57b7649e, 0xf4214cd2, 0x282199b4, 0x8bb7b1f8, 0xb47ccf6d, + 0x17eae721, 0xd70c63e0, 0x749a4bac, 0x4b513539, 0xe8c71d75, + 0x34c7c813, 0x9751e05f, 0xa89a9eca, 0x0b0cb686, 0x81bfd795, + 0x2229ffd9, 0x1de2814c, 0xbe74a900, 0x62747c66, 0xc1e2542a, + 0xfe292abf, 0x5dbf02f3, 0x9d598632, 0x3ecfae7e, 0x0104d0eb, + 0xa292f8a7, 0x7e922dc1, 0xdd04058d, 0xe2cf7b18, 0x41595354, + 0xb87374db, 0x1be55c97, 0x242e2202, 0x87b80a4e, 0x5bb8df28, + 0xf82ef764, 0xc7e589f1, 0x6473a1bd, 0xa495257c, 0x07030d30, + 0x38c873a5, 0x9b5e5be9, 0x475e8e8f, 0xe4c8a6c3, 0xdb03d856, + 0x7895f01a}, + {0x00000000, 0x2a283862, 0x545070c4, 0x7e7848a6, 0xa8a0e188, + 0x8288d9ea, 0xfcf0914c, 0xd6d8a92e, 0x8a30c551, 0xa018fd33, + 0xde60b595, 0xf4488df7, 0x229024d9, 0x08b81cbb, 0x76c0541d, + 0x5ce86c7f, 0xcf108ce3, 0xe538b481, 0x9b40fc27, 0xb168c445, + 0x67b06d6b, 0x4d985509, 0x33e01daf, 0x19c825cd, 0x452049b2, + 0x6f0871d0, 0x11703976, 0x3b580114, 0xed80a83a, 0xc7a89058, + 0xb9d0d8fe, 0x93f8e09c, 0x45501f87, 0x6f7827e5, 0x11006f43, + 0x3b285721, 0xedf0fe0f, 0xc7d8c66d, 0xb9a08ecb, 0x9388b6a9, + 0xcf60dad6, 0xe548e2b4, 0x9b30aa12, 0xb1189270, 0x67c03b5e, + 0x4de8033c, 0x33904b9a, 0x19b873f8, 0x8a409364, 0xa068ab06, + 0xde10e3a0, 0xf438dbc2, 0x22e072ec, 0x08c84a8e, 0x76b00228, + 0x5c983a4a, 0x00705635, 0x2a586e57, 0x542026f1, 0x7e081e93, + 0xa8d0b7bd, 0x82f88fdf, 0xfc80c779, 0xd6a8ff1b, 0x8aa03f0e, + 0xa088076c, 0xdef04fca, 0xf4d877a8, 0x2200de86, 0x0828e6e4, + 0x7650ae42, 0x5c789620, 0x0090fa5f, 0x2ab8c23d, 0x54c08a9b, + 0x7ee8b2f9, 0xa8301bd7, 0x821823b5, 0xfc606b13, 0xd6485371, + 0x45b0b3ed, 0x6f988b8f, 0x11e0c329, 0x3bc8fb4b, 0xed105265, + 0xc7386a07, 0xb94022a1, 0x93681ac3, 0xcf8076bc, 0xe5a84ede, + 0x9bd00678, 0xb1f83e1a, 0x67209734, 0x4d08af56, 0x3370e7f0, + 0x1958df92, 0xcff02089, 0xe5d818eb, 0x9ba0504d, 0xb188682f, + 0x6750c101, 0x4d78f963, 0x3300b1c5, 0x192889a7, 0x45c0e5d8, + 0x6fe8ddba, 0x1190951c, 0x3bb8ad7e, 0xed600450, 0xc7483c32, + 0xb9307494, 0x93184cf6, 0x00e0ac6a, 0x2ac89408, 0x54b0dcae, + 0x7e98e4cc, 0xa8404de2, 0x82687580, 0xfc103d26, 0xd6380544, + 0x8ad0693b, 0xa0f85159, 0xde8019ff, 0xf4a8219d, 0x227088b3, + 0x0858b0d1, 0x7620f877, 0x5c08c015, 0xce31785d, 0xe419403f, + 0x9a610899, 0xb04930fb, 0x669199d5, 0x4cb9a1b7, 0x32c1e911, + 0x18e9d173, 0x4401bd0c, 0x6e29856e, 0x1051cdc8, 0x3a79f5aa, + 0xeca15c84, 0xc68964e6, 0xb8f12c40, 0x92d91422, 0x0121f4be, + 0x2b09ccdc, 0x5571847a, 0x7f59bc18, 0xa9811536, 0x83a92d54, + 0xfdd165f2, 0xd7f95d90, 0x8b1131ef, 0xa139098d, 0xdf41412b, + 0xf5697949, 0x23b1d067, 0x0999e805, 0x77e1a0a3, 0x5dc998c1, + 0x8b6167da, 0xa1495fb8, 0xdf31171e, 0xf5192f7c, 0x23c18652, + 0x09e9be30, 0x7791f696, 0x5db9cef4, 0x0151a28b, 0x2b799ae9, + 0x5501d24f, 0x7f29ea2d, 0xa9f14303, 0x83d97b61, 0xfda133c7, + 0xd7890ba5, 0x4471eb39, 0x6e59d35b, 0x10219bfd, 0x3a09a39f, + 0xecd10ab1, 0xc6f932d3, 0xb8817a75, 0x92a94217, 0xce412e68, + 0xe469160a, 0x9a115eac, 0xb03966ce, 0x66e1cfe0, 0x4cc9f782, + 0x32b1bf24, 0x18998746, 0x44914753, 0x6eb97f31, 0x10c13797, + 0x3ae90ff5, 0xec31a6db, 0xc6199eb9, 0xb861d61f, 0x9249ee7d, + 0xcea18202, 0xe489ba60, 0x9af1f2c6, 0xb0d9caa4, 0x6601638a, + 0x4c295be8, 0x3251134e, 0x18792b2c, 0x8b81cbb0, 0xa1a9f3d2, + 0xdfd1bb74, 0xf5f98316, 0x23212a38, 0x0909125a, 0x77715afc, + 0x5d59629e, 0x01b10ee1, 0x2b993683, 0x55e17e25, 0x7fc94647, + 0xa911ef69, 0x8339d70b, 0xfd419fad, 0xd769a7cf, 0x01c158d4, + 0x2be960b6, 0x55912810, 0x7fb91072, 0xa961b95c, 0x8349813e, + 0xfd31c998, 0xd719f1fa, 0x8bf19d85, 0xa1d9a5e7, 0xdfa1ed41, + 0xf589d523, 0x23517c0d, 0x0979446f, 0x77010cc9, 0x5d2934ab, + 0xced1d437, 0xe4f9ec55, 0x9a81a4f3, 0xb0a99c91, 0x667135bf, + 0x4c590ddd, 0x3221457b, 0x18097d19, 0x44e11166, 0x6ec92904, + 0x10b161a2, 0x3a9959c0, 0xec41f0ee, 0xc669c88c, 0xb811802a, + 0x9239b848}, + {0x00000000, 0x4713f6fb, 0x8e27edf6, 0xc9341b0d, 0xc73eddad, + 0x802d2b56, 0x4919305b, 0x0e0ac6a0, 0x550cbd1b, 0x121f4be0, + 0xdb2b50ed, 0x9c38a616, 0x923260b6, 0xd521964d, 0x1c158d40, + 0x5b067bbb, 0xaa197a36, 0xed0a8ccd, 0x243e97c0, 0x632d613b, + 0x6d27a79b, 0x2a345160, 0xe3004a6d, 0xa413bc96, 0xff15c72d, + 0xb80631d6, 0x71322adb, 0x3621dc20, 0x382b1a80, 0x7f38ec7b, + 0xb60cf776, 0xf11f018d, 0x8f43f22d, 0xc85004d6, 0x01641fdb, + 0x4677e920, 0x487d2f80, 0x0f6ed97b, 0xc65ac276, 0x8149348d, + 0xda4f4f36, 0x9d5cb9cd, 0x5468a2c0, 0x137b543b, 0x1d71929b, + 0x5a626460, 0x93567f6d, 0xd4458996, 0x255a881b, 0x62497ee0, + 0xab7d65ed, 0xec6e9316, 0xe26455b6, 0xa577a34d, 0x6c43b840, + 0x2b504ebb, 0x70563500, 0x3745c3fb, 0xfe71d8f6, 0xb9622e0d, + 0xb768e8ad, 0xf07b1e56, 0x394f055b, 0x7e5cf3a0, 0xc5f6e21b, + 0x82e514e0, 0x4bd10fed, 0x0cc2f916, 0x02c83fb6, 0x45dbc94d, + 0x8cefd240, 0xcbfc24bb, 0x90fa5f00, 0xd7e9a9fb, 0x1eddb2f6, + 0x59ce440d, 0x57c482ad, 0x10d77456, 0xd9e36f5b, 0x9ef099a0, + 0x6fef982d, 0x28fc6ed6, 0xe1c875db, 0xa6db8320, 0xa8d14580, + 0xefc2b37b, 0x26f6a876, 0x61e55e8d, 0x3ae32536, 0x7df0d3cd, + 0xb4c4c8c0, 0xf3d73e3b, 0xfdddf89b, 0xbace0e60, 0x73fa156d, + 0x34e9e396, 0x4ab51036, 0x0da6e6cd, 0xc492fdc0, 0x83810b3b, + 0x8d8bcd9b, 0xca983b60, 0x03ac206d, 0x44bfd696, 0x1fb9ad2d, + 0x58aa5bd6, 0x919e40db, 0xd68db620, 0xd8877080, 0x9f94867b, + 0x56a09d76, 0x11b36b8d, 0xe0ac6a00, 0xa7bf9cfb, 0x6e8b87f6, + 0x2998710d, 0x2792b7ad, 0x60814156, 0xa9b55a5b, 0xeea6aca0, + 0xb5a0d71b, 0xf2b321e0, 0x3b873aed, 0x7c94cc16, 0x729e0ab6, + 0x358dfc4d, 0xfcb9e740, 0xbbaa11bb, 0x509cc277, 0x178f348c, + 0xdebb2f81, 0x99a8d97a, 0x97a21fda, 0xd0b1e921, 0x1985f22c, + 0x5e9604d7, 0x05907f6c, 0x42838997, 0x8bb7929a, 0xcca46461, + 0xc2aea2c1, 0x85bd543a, 0x4c894f37, 0x0b9ab9cc, 0xfa85b841, + 0xbd964eba, 0x74a255b7, 0x33b1a34c, 0x3dbb65ec, 0x7aa89317, + 0xb39c881a, 0xf48f7ee1, 0xaf89055a, 0xe89af3a1, 0x21aee8ac, + 0x66bd1e57, 0x68b7d8f7, 0x2fa42e0c, 0xe6903501, 0xa183c3fa, + 0xdfdf305a, 0x98ccc6a1, 0x51f8ddac, 0x16eb2b57, 0x18e1edf7, + 0x5ff21b0c, 0x96c60001, 0xd1d5f6fa, 0x8ad38d41, 0xcdc07bba, + 0x04f460b7, 0x43e7964c, 0x4ded50ec, 0x0afea617, 0xc3cabd1a, + 0x84d94be1, 0x75c64a6c, 0x32d5bc97, 0xfbe1a79a, 0xbcf25161, + 0xb2f897c1, 0xf5eb613a, 0x3cdf7a37, 0x7bcc8ccc, 0x20caf777, + 0x67d9018c, 0xaeed1a81, 0xe9feec7a, 0xe7f42ada, 0xa0e7dc21, + 0x69d3c72c, 0x2ec031d7, 0x956a206c, 0xd279d697, 0x1b4dcd9a, + 0x5c5e3b61, 0x5254fdc1, 0x15470b3a, 0xdc731037, 0x9b60e6cc, + 0xc0669d77, 0x87756b8c, 0x4e417081, 0x0952867a, 0x075840da, + 0x404bb621, 0x897fad2c, 0xce6c5bd7, 0x3f735a5a, 0x7860aca1, + 0xb154b7ac, 0xf6474157, 0xf84d87f7, 0xbf5e710c, 0x766a6a01, + 0x31799cfa, 0x6a7fe741, 0x2d6c11ba, 0xe4580ab7, 0xa34bfc4c, + 0xad413aec, 0xea52cc17, 0x2366d71a, 0x647521e1, 0x1a29d241, + 0x5d3a24ba, 0x940e3fb7, 0xd31dc94c, 0xdd170fec, 0x9a04f917, + 0x5330e21a, 0x142314e1, 0x4f256f5a, 0x083699a1, 0xc10282ac, + 0x86117457, 0x881bb2f7, 0xcf08440c, 0x063c5f01, 0x412fa9fa, + 0xb030a877, 0xf7235e8c, 0x3e174581, 0x7904b37a, 0x770e75da, + 0x301d8321, 0xf929982c, 0xbe3a6ed7, 0xe53c156c, 0xa22fe397, + 0x6b1bf89a, 0x2c080e61, 0x2202c8c1, 0x65113e3a, 0xac252537, + 0xeb36d3cc}, + {0x00000000, 0xa13984ee, 0x99020f9d, 0x383b8b73, 0xe975197b, + 0x484c9d95, 0x707716e6, 0xd14e9208, 0x099b34b7, 0xa8a2b059, + 0x90993b2a, 0x31a0bfc4, 0xe0ee2dcc, 0x41d7a922, 0x79ec2251, + 0xd8d5a6bf, 0x1336696e, 0xb20fed80, 0x8a3466f3, 0x2b0de21d, + 0xfa437015, 0x5b7af4fb, 0x63417f88, 0xc278fb66, 0x1aad5dd9, + 0xbb94d937, 0x83af5244, 0x2296d6aa, 0xf3d844a2, 0x52e1c04c, + 0x6ada4b3f, 0xcbe3cfd1, 0x266cd2dc, 0x87555632, 0xbf6edd41, + 0x1e5759af, 0xcf19cba7, 0x6e204f49, 0x561bc43a, 0xf72240d4, + 0x2ff7e66b, 0x8ece6285, 0xb6f5e9f6, 0x17cc6d18, 0xc682ff10, + 0x67bb7bfe, 0x5f80f08d, 0xfeb97463, 0x355abbb2, 0x94633f5c, + 0xac58b42f, 0x0d6130c1, 0xdc2fa2c9, 0x7d162627, 0x452dad54, + 0xe41429ba, 0x3cc18f05, 0x9df80beb, 0xa5c38098, 0x04fa0476, + 0xd5b4967e, 0x748d1290, 0x4cb699e3, 0xed8f1d0d, 0x4cd9a5b8, + 0xede02156, 0xd5dbaa25, 0x74e22ecb, 0xa5acbcc3, 0x0495382d, + 0x3caeb35e, 0x9d9737b0, 0x4542910f, 0xe47b15e1, 0xdc409e92, + 0x7d791a7c, 0xac378874, 0x0d0e0c9a, 0x353587e9, 0x940c0307, + 0x5fefccd6, 0xfed64838, 0xc6edc34b, 0x67d447a5, 0xb69ad5ad, + 0x17a35143, 0x2f98da30, 0x8ea15ede, 0x5674f861, 0xf74d7c8f, + 0xcf76f7fc, 0x6e4f7312, 0xbf01e11a, 0x1e3865f4, 0x2603ee87, + 0x873a6a69, 0x6ab57764, 0xcb8cf38a, 0xf3b778f9, 0x528efc17, + 0x83c06e1f, 0x22f9eaf1, 0x1ac26182, 0xbbfbe56c, 0x632e43d3, + 0xc217c73d, 0xfa2c4c4e, 0x5b15c8a0, 0x8a5b5aa8, 0x2b62de46, + 0x13595535, 0xb260d1db, 0x79831e0a, 0xd8ba9ae4, 0xe0811197, + 0x41b89579, 0x90f60771, 0x31cf839f, 0x09f408ec, 0xa8cd8c02, + 0x70182abd, 0xd121ae53, 0xe91a2520, 0x4823a1ce, 0x996d33c6, + 0x3854b728, 0x006f3c5b, 0xa156b8b5, 0x99b34b70, 0x388acf9e, + 0x00b144ed, 0xa188c003, 0x70c6520b, 0xd1ffd6e5, 0xe9c45d96, + 0x48fdd978, 0x90287fc7, 0x3111fb29, 0x092a705a, 0xa813f4b4, + 0x795d66bc, 0xd864e252, 0xe05f6921, 0x4166edcf, 0x8a85221e, + 0x2bbca6f0, 0x13872d83, 0xb2bea96d, 0x63f03b65, 0xc2c9bf8b, + 0xfaf234f8, 0x5bcbb016, 0x831e16a9, 0x22279247, 0x1a1c1934, + 0xbb259dda, 0x6a6b0fd2, 0xcb528b3c, 0xf369004f, 0x525084a1, + 0xbfdf99ac, 0x1ee61d42, 0x26dd9631, 0x87e412df, 0x56aa80d7, + 0xf7930439, 0xcfa88f4a, 0x6e910ba4, 0xb644ad1b, 0x177d29f5, + 0x2f46a286, 0x8e7f2668, 0x5f31b460, 0xfe08308e, 0xc633bbfd, + 0x670a3f13, 0xace9f0c2, 0x0dd0742c, 0x35ebff5f, 0x94d27bb1, + 0x459ce9b9, 0xe4a56d57, 0xdc9ee624, 0x7da762ca, 0xa572c475, + 0x044b409b, 0x3c70cbe8, 0x9d494f06, 0x4c07dd0e, 0xed3e59e0, + 0xd505d293, 0x743c567d, 0xd56aeec8, 0x74536a26, 0x4c68e155, + 0xed5165bb, 0x3c1ff7b3, 0x9d26735d, 0xa51df82e, 0x04247cc0, + 0xdcf1da7f, 0x7dc85e91, 0x45f3d5e2, 0xe4ca510c, 0x3584c304, + 0x94bd47ea, 0xac86cc99, 0x0dbf4877, 0xc65c87a6, 0x67650348, + 0x5f5e883b, 0xfe670cd5, 0x2f299edd, 0x8e101a33, 0xb62b9140, + 0x171215ae, 0xcfc7b311, 0x6efe37ff, 0x56c5bc8c, 0xf7fc3862, + 0x26b2aa6a, 0x878b2e84, 0xbfb0a5f7, 0x1e892119, 0xf3063c14, + 0x523fb8fa, 0x6a043389, 0xcb3db767, 0x1a73256f, 0xbb4aa181, + 0x83712af2, 0x2248ae1c, 0xfa9d08a3, 0x5ba48c4d, 0x639f073e, + 0xc2a683d0, 0x13e811d8, 0xb2d19536, 0x8aea1e45, 0x2bd39aab, + 0xe030557a, 0x4109d194, 0x79325ae7, 0xd80bde09, 0x09454c01, + 0xa87cc8ef, 0x9047439c, 0x317ec772, 0xe9ab61cd, 0x4892e523, + 0x70a96e50, 0xd190eabe, 0x00de78b6, 0xa1e7fc58, 0x99dc772b, + 0x38e5f3c5}, + {0x00000000, 0xe81790a1, 0x0b5e2703, 0xe349b7a2, 0x16bc4e06, + 0xfeabdea7, 0x1de26905, 0xf5f5f9a4, 0x2d789c0c, 0xc56f0cad, + 0x2626bb0f, 0xce312bae, 0x3bc4d20a, 0xd3d342ab, 0x309af509, + 0xd88d65a8, 0x5af13818, 0xb2e6a8b9, 0x51af1f1b, 0xb9b88fba, + 0x4c4d761e, 0xa45ae6bf, 0x4713511d, 0xaf04c1bc, 0x7789a414, + 0x9f9e34b5, 0x7cd78317, 0x94c013b6, 0x6135ea12, 0x89227ab3, + 0x6a6bcd11, 0x827c5db0, 0xb5e27030, 0x5df5e091, 0xbebc5733, + 0x56abc792, 0xa35e3e36, 0x4b49ae97, 0xa8001935, 0x40178994, + 0x989aec3c, 0x708d7c9d, 0x93c4cb3f, 0x7bd35b9e, 0x8e26a23a, + 0x6631329b, 0x85788539, 0x6d6f1598, 0xef134828, 0x0704d889, + 0xe44d6f2b, 0x0c5aff8a, 0xf9af062e, 0x11b8968f, 0xf2f1212d, + 0x1ae6b18c, 0xc26bd424, 0x2a7c4485, 0xc935f327, 0x21226386, + 0xd4d79a22, 0x3cc00a83, 0xdf89bd21, 0x379e2d80, 0xb0b5e621, + 0x58a27680, 0xbbebc122, 0x53fc5183, 0xa609a827, 0x4e1e3886, + 0xad578f24, 0x45401f85, 0x9dcd7a2d, 0x75daea8c, 0x96935d2e, + 0x7e84cd8f, 0x8b71342b, 0x6366a48a, 0x802f1328, 0x68388389, + 0xea44de39, 0x02534e98, 0xe11af93a, 0x090d699b, 0xfcf8903f, + 0x14ef009e, 0xf7a6b73c, 0x1fb1279d, 0xc73c4235, 0x2f2bd294, + 0xcc626536, 0x2475f597, 0xd1800c33, 0x39979c92, 0xdade2b30, + 0x32c9bb91, 0x05579611, 0xed4006b0, 0x0e09b112, 0xe61e21b3, + 0x13ebd817, 0xfbfc48b6, 0x18b5ff14, 0xf0a26fb5, 0x282f0a1d, + 0xc0389abc, 0x23712d1e, 0xcb66bdbf, 0x3e93441b, 0xd684d4ba, + 0x35cd6318, 0xdddaf3b9, 0x5fa6ae09, 0xb7b13ea8, 0x54f8890a, + 0xbcef19ab, 0x491ae00f, 0xa10d70ae, 0x4244c70c, 0xaa5357ad, + 0x72de3205, 0x9ac9a2a4, 0x79801506, 0x919785a7, 0x64627c03, + 0x8c75eca2, 0x6f3c5b00, 0x872bcba1, 0xba1aca03, 0x520d5aa2, + 0xb144ed00, 0x59537da1, 0xaca68405, 0x44b114a4, 0xa7f8a306, + 0x4fef33a7, 0x9762560f, 0x7f75c6ae, 0x9c3c710c, 0x742be1ad, + 0x81de1809, 0x69c988a8, 0x8a803f0a, 0x6297afab, 0xe0ebf21b, + 0x08fc62ba, 0xebb5d518, 0x03a245b9, 0xf657bc1d, 0x1e402cbc, + 0xfd099b1e, 0x151e0bbf, 0xcd936e17, 0x2584feb6, 0xc6cd4914, + 0x2edad9b5, 0xdb2f2011, 0x3338b0b0, 0xd0710712, 0x386697b3, + 0x0ff8ba33, 0xe7ef2a92, 0x04a69d30, 0xecb10d91, 0x1944f435, + 0xf1536494, 0x121ad336, 0xfa0d4397, 0x2280263f, 0xca97b69e, + 0x29de013c, 0xc1c9919d, 0x343c6839, 0xdc2bf898, 0x3f624f3a, + 0xd775df9b, 0x5509822b, 0xbd1e128a, 0x5e57a528, 0xb6403589, + 0x43b5cc2d, 0xaba25c8c, 0x48ebeb2e, 0xa0fc7b8f, 0x78711e27, + 0x90668e86, 0x732f3924, 0x9b38a985, 0x6ecd5021, 0x86dac080, + 0x65937722, 0x8d84e783, 0x0aaf2c22, 0xe2b8bc83, 0x01f10b21, + 0xe9e69b80, 0x1c136224, 0xf404f285, 0x174d4527, 0xff5ad586, + 0x27d7b02e, 0xcfc0208f, 0x2c89972d, 0xc49e078c, 0x316bfe28, + 0xd97c6e89, 0x3a35d92b, 0xd222498a, 0x505e143a, 0xb849849b, + 0x5b003339, 0xb317a398, 0x46e25a3c, 0xaef5ca9d, 0x4dbc7d3f, + 0xa5abed9e, 0x7d268836, 0x95311897, 0x7678af35, 0x9e6f3f94, + 0x6b9ac630, 0x838d5691, 0x60c4e133, 0x88d37192, 0xbf4d5c12, + 0x575accb3, 0xb4137b11, 0x5c04ebb0, 0xa9f11214, 0x41e682b5, + 0xa2af3517, 0x4ab8a5b6, 0x9235c01e, 0x7a2250bf, 0x996be71d, + 0x717c77bc, 0x84898e18, 0x6c9e1eb9, 0x8fd7a91b, 0x67c039ba, + 0xe5bc640a, 0x0dabf4ab, 0xeee24309, 0x06f5d3a8, 0xf3002a0c, + 0x1b17baad, 0xf85e0d0f, 0x10499dae, 0xc8c4f806, 0x20d368a7, + 0xc39adf05, 0x2b8d4fa4, 0xde78b600, 0x366f26a1, 0xd5269103, + 0x3d3101a2}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0xa19017e800000000, 0x03275e0b00000000, + 0xa2b749e300000000, 0x064ebc1600000000, 0xa7deabfe00000000, + 0x0569e21d00000000, 0xa4f9f5f500000000, 0x0c9c782d00000000, + 0xad0c6fc500000000, 0x0fbb262600000000, 0xae2b31ce00000000, + 0x0ad2c43b00000000, 0xab42d3d300000000, 0x09f59a3000000000, + 0xa8658dd800000000, 0x1838f15a00000000, 0xb9a8e6b200000000, + 0x1b1faf5100000000, 0xba8fb8b900000000, 0x1e764d4c00000000, + 0xbfe65aa400000000, 0x1d51134700000000, 0xbcc104af00000000, + 0x14a4897700000000, 0xb5349e9f00000000, 0x1783d77c00000000, + 0xb613c09400000000, 0x12ea356100000000, 0xb37a228900000000, + 0x11cd6b6a00000000, 0xb05d7c8200000000, 0x3070e2b500000000, + 0x91e0f55d00000000, 0x3357bcbe00000000, 0x92c7ab5600000000, + 0x363e5ea300000000, 0x97ae494b00000000, 0x351900a800000000, + 0x9489174000000000, 0x3cec9a9800000000, 0x9d7c8d7000000000, + 0x3fcbc49300000000, 0x9e5bd37b00000000, 0x3aa2268e00000000, + 0x9b32316600000000, 0x3985788500000000, 0x98156f6d00000000, + 0x284813ef00000000, 0x89d8040700000000, 0x2b6f4de400000000, + 0x8aff5a0c00000000, 0x2e06aff900000000, 0x8f96b81100000000, + 0x2d21f1f200000000, 0x8cb1e61a00000000, 0x24d46bc200000000, + 0x85447c2a00000000, 0x27f335c900000000, 0x8663222100000000, + 0x229ad7d400000000, 0x830ac03c00000000, 0x21bd89df00000000, + 0x802d9e3700000000, 0x21e6b5b000000000, 0x8076a25800000000, + 0x22c1ebbb00000000, 0x8351fc5300000000, 0x27a809a600000000, + 0x86381e4e00000000, 0x248f57ad00000000, 0x851f404500000000, + 0x2d7acd9d00000000, 0x8ceada7500000000, 0x2e5d939600000000, + 0x8fcd847e00000000, 0x2b34718b00000000, 0x8aa4666300000000, + 0x28132f8000000000, 0x8983386800000000, 0x39de44ea00000000, + 0x984e530200000000, 0x3af91ae100000000, 0x9b690d0900000000, + 0x3f90f8fc00000000, 0x9e00ef1400000000, 0x3cb7a6f700000000, + 0x9d27b11f00000000, 0x35423cc700000000, 0x94d22b2f00000000, + 0x366562cc00000000, 0x97f5752400000000, 0x330c80d100000000, + 0x929c973900000000, 0x302bdeda00000000, 0x91bbc93200000000, + 0x1196570500000000, 0xb00640ed00000000, 0x12b1090e00000000, + 0xb3211ee600000000, 0x17d8eb1300000000, 0xb648fcfb00000000, + 0x14ffb51800000000, 0xb56fa2f000000000, 0x1d0a2f2800000000, + 0xbc9a38c000000000, 0x1e2d712300000000, 0xbfbd66cb00000000, + 0x1b44933e00000000, 0xbad484d600000000, 0x1863cd3500000000, + 0xb9f3dadd00000000, 0x09aea65f00000000, 0xa83eb1b700000000, + 0x0a89f85400000000, 0xab19efbc00000000, 0x0fe01a4900000000, + 0xae700da100000000, 0x0cc7444200000000, 0xad5753aa00000000, + 0x0532de7200000000, 0xa4a2c99a00000000, 0x0615807900000000, + 0xa785979100000000, 0x037c626400000000, 0xa2ec758c00000000, + 0x005b3c6f00000000, 0xa1cb2b8700000000, 0x03ca1aba00000000, + 0xa25a0d5200000000, 0x00ed44b100000000, 0xa17d535900000000, + 0x0584a6ac00000000, 0xa414b14400000000, 0x06a3f8a700000000, + 0xa733ef4f00000000, 0x0f56629700000000, 0xaec6757f00000000, + 0x0c713c9c00000000, 0xade12b7400000000, 0x0918de8100000000, + 0xa888c96900000000, 0x0a3f808a00000000, 0xabaf976200000000, + 0x1bf2ebe000000000, 0xba62fc0800000000, 0x18d5b5eb00000000, + 0xb945a20300000000, 0x1dbc57f600000000, 0xbc2c401e00000000, + 0x1e9b09fd00000000, 0xbf0b1e1500000000, 0x176e93cd00000000, + 0xb6fe842500000000, 0x1449cdc600000000, 0xb5d9da2e00000000, + 0x11202fdb00000000, 0xb0b0383300000000, 0x120771d000000000, + 0xb397663800000000, 0x33baf80f00000000, 0x922aefe700000000, + 0x309da60400000000, 0x910db1ec00000000, 0x35f4441900000000, + 0x946453f100000000, 0x36d31a1200000000, 0x97430dfa00000000, + 0x3f26802200000000, 0x9eb697ca00000000, 0x3c01de2900000000, + 0x9d91c9c100000000, 0x39683c3400000000, 0x98f82bdc00000000, + 0x3a4f623f00000000, 0x9bdf75d700000000, 0x2b82095500000000, + 0x8a121ebd00000000, 0x28a5575e00000000, 0x893540b600000000, + 0x2dccb54300000000, 0x8c5ca2ab00000000, 0x2eebeb4800000000, + 0x8f7bfca000000000, 0x271e717800000000, 0x868e669000000000, + 0x24392f7300000000, 0x85a9389b00000000, 0x2150cd6e00000000, + 0x80c0da8600000000, 0x2277936500000000, 0x83e7848d00000000, + 0x222caf0a00000000, 0x83bcb8e200000000, 0x210bf10100000000, + 0x809be6e900000000, 0x2462131c00000000, 0x85f204f400000000, + 0x27454d1700000000, 0x86d55aff00000000, 0x2eb0d72700000000, + 0x8f20c0cf00000000, 0x2d97892c00000000, 0x8c079ec400000000, + 0x28fe6b3100000000, 0x896e7cd900000000, 0x2bd9353a00000000, + 0x8a4922d200000000, 0x3a145e5000000000, 0x9b8449b800000000, + 0x3933005b00000000, 0x98a317b300000000, 0x3c5ae24600000000, + 0x9dcaf5ae00000000, 0x3f7dbc4d00000000, 0x9eedaba500000000, + 0x3688267d00000000, 0x9718319500000000, 0x35af787600000000, + 0x943f6f9e00000000, 0x30c69a6b00000000, 0x91568d8300000000, + 0x33e1c46000000000, 0x9271d38800000000, 0x125c4dbf00000000, + 0xb3cc5a5700000000, 0x117b13b400000000, 0xb0eb045c00000000, + 0x1412f1a900000000, 0xb582e64100000000, 0x1735afa200000000, + 0xb6a5b84a00000000, 0x1ec0359200000000, 0xbf50227a00000000, + 0x1de76b9900000000, 0xbc777c7100000000, 0x188e898400000000, + 0xb91e9e6c00000000, 0x1ba9d78f00000000, 0xba39c06700000000, + 0x0a64bce500000000, 0xabf4ab0d00000000, 0x0943e2ee00000000, + 0xa8d3f50600000000, 0x0c2a00f300000000, 0xadba171b00000000, + 0x0f0d5ef800000000, 0xae9d491000000000, 0x06f8c4c800000000, + 0xa768d32000000000, 0x05df9ac300000000, 0xa44f8d2b00000000, + 0x00b678de00000000, 0xa1266f3600000000, 0x039126d500000000, + 0xa201313d00000000}, + {0x0000000000000000, 0xee8439a100000000, 0x9d0f029900000000, + 0x738b3b3800000000, 0x7b1975e900000000, 0x959d4c4800000000, + 0xe616777000000000, 0x08924ed100000000, 0xb7349b0900000000, + 0x59b0a2a800000000, 0x2a3b999000000000, 0xc4bfa03100000000, + 0xcc2deee000000000, 0x22a9d74100000000, 0x5122ec7900000000, + 0xbfa6d5d800000000, 0x6e69361300000000, 0x80ed0fb200000000, + 0xf366348a00000000, 0x1de20d2b00000000, 0x157043fa00000000, + 0xfbf47a5b00000000, 0x887f416300000000, 0x66fb78c200000000, + 0xd95dad1a00000000, 0x37d994bb00000000, 0x4452af8300000000, + 0xaad6962200000000, 0xa244d8f300000000, 0x4cc0e15200000000, + 0x3f4bda6a00000000, 0xd1cfe3cb00000000, 0xdcd26c2600000000, + 0x3256558700000000, 0x41dd6ebf00000000, 0xaf59571e00000000, + 0xa7cb19cf00000000, 0x494f206e00000000, 0x3ac41b5600000000, + 0xd44022f700000000, 0x6be6f72f00000000, 0x8562ce8e00000000, + 0xf6e9f5b600000000, 0x186dcc1700000000, 0x10ff82c600000000, + 0xfe7bbb6700000000, 0x8df0805f00000000, 0x6374b9fe00000000, + 0xb2bb5a3500000000, 0x5c3f639400000000, 0x2fb458ac00000000, + 0xc130610d00000000, 0xc9a22fdc00000000, 0x2726167d00000000, + 0x54ad2d4500000000, 0xba2914e400000000, 0x058fc13c00000000, + 0xeb0bf89d00000000, 0x9880c3a500000000, 0x7604fa0400000000, + 0x7e96b4d500000000, 0x90128d7400000000, 0xe399b64c00000000, + 0x0d1d8fed00000000, 0xb8a5d94c00000000, 0x5621e0ed00000000, + 0x25aadbd500000000, 0xcb2ee27400000000, 0xc3bcaca500000000, + 0x2d38950400000000, 0x5eb3ae3c00000000, 0xb037979d00000000, + 0x0f91424500000000, 0xe1157be400000000, 0x929e40dc00000000, + 0x7c1a797d00000000, 0x748837ac00000000, 0x9a0c0e0d00000000, + 0xe987353500000000, 0x07030c9400000000, 0xd6ccef5f00000000, + 0x3848d6fe00000000, 0x4bc3edc600000000, 0xa547d46700000000, + 0xadd59ab600000000, 0x4351a31700000000, 0x30da982f00000000, + 0xde5ea18e00000000, 0x61f8745600000000, 0x8f7c4df700000000, + 0xfcf776cf00000000, 0x12734f6e00000000, 0x1ae101bf00000000, + 0xf465381e00000000, 0x87ee032600000000, 0x696a3a8700000000, + 0x6477b56a00000000, 0x8af38ccb00000000, 0xf978b7f300000000, + 0x17fc8e5200000000, 0x1f6ec08300000000, 0xf1eaf92200000000, + 0x8261c21a00000000, 0x6ce5fbbb00000000, 0xd3432e6300000000, + 0x3dc717c200000000, 0x4e4c2cfa00000000, 0xa0c8155b00000000, + 0xa85a5b8a00000000, 0x46de622b00000000, 0x3555591300000000, + 0xdbd160b200000000, 0x0a1e837900000000, 0xe49abad800000000, + 0x971181e000000000, 0x7995b84100000000, 0x7107f69000000000, + 0x9f83cf3100000000, 0xec08f40900000000, 0x028ccda800000000, + 0xbd2a187000000000, 0x53ae21d100000000, 0x20251ae900000000, + 0xcea1234800000000, 0xc6336d9900000000, 0x28b7543800000000, + 0x5b3c6f0000000000, 0xb5b856a100000000, 0x704bb39900000000, + 0x9ecf8a3800000000, 0xed44b10000000000, 0x03c088a100000000, + 0x0b52c67000000000, 0xe5d6ffd100000000, 0x965dc4e900000000, + 0x78d9fd4800000000, 0xc77f289000000000, 0x29fb113100000000, + 0x5a702a0900000000, 0xb4f413a800000000, 0xbc665d7900000000, + 0x52e264d800000000, 0x21695fe000000000, 0xcfed664100000000, + 0x1e22858a00000000, 0xf0a6bc2b00000000, 0x832d871300000000, + 0x6da9beb200000000, 0x653bf06300000000, 0x8bbfc9c200000000, + 0xf834f2fa00000000, 0x16b0cb5b00000000, 0xa9161e8300000000, + 0x4792272200000000, 0x34191c1a00000000, 0xda9d25bb00000000, + 0xd20f6b6a00000000, 0x3c8b52cb00000000, 0x4f0069f300000000, + 0xa184505200000000, 0xac99dfbf00000000, 0x421de61e00000000, + 0x3196dd2600000000, 0xdf12e48700000000, 0xd780aa5600000000, + 0x390493f700000000, 0x4a8fa8cf00000000, 0xa40b916e00000000, + 0x1bad44b600000000, 0xf5297d1700000000, 0x86a2462f00000000, + 0x68267f8e00000000, 0x60b4315f00000000, 0x8e3008fe00000000, + 0xfdbb33c600000000, 0x133f0a6700000000, 0xc2f0e9ac00000000, + 0x2c74d00d00000000, 0x5fffeb3500000000, 0xb17bd29400000000, + 0xb9e99c4500000000, 0x576da5e400000000, 0x24e69edc00000000, + 0xca62a77d00000000, 0x75c472a500000000, 0x9b404b0400000000, + 0xe8cb703c00000000, 0x064f499d00000000, 0x0edd074c00000000, + 0xe0593eed00000000, 0x93d205d500000000, 0x7d563c7400000000, + 0xc8ee6ad500000000, 0x266a537400000000, 0x55e1684c00000000, + 0xbb6551ed00000000, 0xb3f71f3c00000000, 0x5d73269d00000000, + 0x2ef81da500000000, 0xc07c240400000000, 0x7fdaf1dc00000000, + 0x915ec87d00000000, 0xe2d5f34500000000, 0x0c51cae400000000, + 0x04c3843500000000, 0xea47bd9400000000, 0x99cc86ac00000000, + 0x7748bf0d00000000, 0xa6875cc600000000, 0x4803656700000000, + 0x3b885e5f00000000, 0xd50c67fe00000000, 0xdd9e292f00000000, + 0x331a108e00000000, 0x40912bb600000000, 0xae15121700000000, + 0x11b3c7cf00000000, 0xff37fe6e00000000, 0x8cbcc55600000000, + 0x6238fcf700000000, 0x6aaab22600000000, 0x842e8b8700000000, + 0xf7a5b0bf00000000, 0x1921891e00000000, 0x143c06f300000000, + 0xfab83f5200000000, 0x8933046a00000000, 0x67b73dcb00000000, + 0x6f25731a00000000, 0x81a14abb00000000, 0xf22a718300000000, + 0x1cae482200000000, 0xa3089dfa00000000, 0x4d8ca45b00000000, + 0x3e079f6300000000, 0xd083a6c200000000, 0xd811e81300000000, + 0x3695d1b200000000, 0x451eea8a00000000, 0xab9ad32b00000000, + 0x7a5530e000000000, 0x94d1094100000000, 0xe75a327900000000, + 0x09de0bd800000000, 0x014c450900000000, 0xefc87ca800000000, + 0x9c43479000000000, 0x72c77e3100000000, 0xcd61abe900000000, + 0x23e5924800000000, 0x506ea97000000000, 0xbeea90d100000000, + 0xb678de0000000000, 0x58fce7a100000000, 0x2b77dc9900000000, + 0xc5f3e53800000000}, + {0x0000000000000000, 0xfbf6134700000000, 0xf6ed278e00000000, + 0x0d1b34c900000000, 0xaddd3ec700000000, 0x562b2d8000000000, + 0x5b30194900000000, 0xa0c60a0e00000000, 0x1bbd0c5500000000, + 0xe04b1f1200000000, 0xed502bdb00000000, 0x16a6389c00000000, + 0xb660329200000000, 0x4d9621d500000000, 0x408d151c00000000, + 0xbb7b065b00000000, 0x367a19aa00000000, 0xcd8c0aed00000000, + 0xc0973e2400000000, 0x3b612d6300000000, 0x9ba7276d00000000, + 0x6051342a00000000, 0x6d4a00e300000000, 0x96bc13a400000000, + 0x2dc715ff00000000, 0xd63106b800000000, 0xdb2a327100000000, + 0x20dc213600000000, 0x801a2b3800000000, 0x7bec387f00000000, + 0x76f70cb600000000, 0x8d011ff100000000, 0x2df2438f00000000, + 0xd60450c800000000, 0xdb1f640100000000, 0x20e9774600000000, + 0x802f7d4800000000, 0x7bd96e0f00000000, 0x76c25ac600000000, + 0x8d34498100000000, 0x364f4fda00000000, 0xcdb95c9d00000000, + 0xc0a2685400000000, 0x3b547b1300000000, 0x9b92711d00000000, + 0x6064625a00000000, 0x6d7f569300000000, 0x968945d400000000, + 0x1b885a2500000000, 0xe07e496200000000, 0xed657dab00000000, + 0x16936eec00000000, 0xb65564e200000000, 0x4da377a500000000, + 0x40b8436c00000000, 0xbb4e502b00000000, 0x0035567000000000, + 0xfbc3453700000000, 0xf6d871fe00000000, 0x0d2e62b900000000, + 0xade868b700000000, 0x561e7bf000000000, 0x5b054f3900000000, + 0xa0f35c7e00000000, 0x1be2f6c500000000, 0xe014e58200000000, + 0xed0fd14b00000000, 0x16f9c20c00000000, 0xb63fc80200000000, + 0x4dc9db4500000000, 0x40d2ef8c00000000, 0xbb24fccb00000000, + 0x005ffa9000000000, 0xfba9e9d700000000, 0xf6b2dd1e00000000, + 0x0d44ce5900000000, 0xad82c45700000000, 0x5674d71000000000, + 0x5b6fe3d900000000, 0xa099f09e00000000, 0x2d98ef6f00000000, + 0xd66efc2800000000, 0xdb75c8e100000000, 0x2083dba600000000, + 0x8045d1a800000000, 0x7bb3c2ef00000000, 0x76a8f62600000000, + 0x8d5ee56100000000, 0x3625e33a00000000, 0xcdd3f07d00000000, + 0xc0c8c4b400000000, 0x3b3ed7f300000000, 0x9bf8ddfd00000000, + 0x600eceba00000000, 0x6d15fa7300000000, 0x96e3e93400000000, + 0x3610b54a00000000, 0xcde6a60d00000000, 0xc0fd92c400000000, + 0x3b0b818300000000, 0x9bcd8b8d00000000, 0x603b98ca00000000, + 0x6d20ac0300000000, 0x96d6bf4400000000, 0x2dadb91f00000000, + 0xd65baa5800000000, 0xdb409e9100000000, 0x20b68dd600000000, + 0x807087d800000000, 0x7b86949f00000000, 0x769da05600000000, + 0x8d6bb31100000000, 0x006aace000000000, 0xfb9cbfa700000000, + 0xf6878b6e00000000, 0x0d71982900000000, 0xadb7922700000000, + 0x5641816000000000, 0x5b5ab5a900000000, 0xa0aca6ee00000000, + 0x1bd7a0b500000000, 0xe021b3f200000000, 0xed3a873b00000000, + 0x16cc947c00000000, 0xb60a9e7200000000, 0x4dfc8d3500000000, + 0x40e7b9fc00000000, 0xbb11aabb00000000, 0x77c29c5000000000, + 0x8c348f1700000000, 0x812fbbde00000000, 0x7ad9a89900000000, + 0xda1fa29700000000, 0x21e9b1d000000000, 0x2cf2851900000000, + 0xd704965e00000000, 0x6c7f900500000000, 0x9789834200000000, + 0x9a92b78b00000000, 0x6164a4cc00000000, 0xc1a2aec200000000, + 0x3a54bd8500000000, 0x374f894c00000000, 0xccb99a0b00000000, + 0x41b885fa00000000, 0xba4e96bd00000000, 0xb755a27400000000, + 0x4ca3b13300000000, 0xec65bb3d00000000, 0x1793a87a00000000, + 0x1a889cb300000000, 0xe17e8ff400000000, 0x5a0589af00000000, + 0xa1f39ae800000000, 0xace8ae2100000000, 0x571ebd6600000000, + 0xf7d8b76800000000, 0x0c2ea42f00000000, 0x013590e600000000, + 0xfac383a100000000, 0x5a30dfdf00000000, 0xa1c6cc9800000000, + 0xacddf85100000000, 0x572beb1600000000, 0xf7ede11800000000, + 0x0c1bf25f00000000, 0x0100c69600000000, 0xfaf6d5d100000000, + 0x418dd38a00000000, 0xba7bc0cd00000000, 0xb760f40400000000, + 0x4c96e74300000000, 0xec50ed4d00000000, 0x17a6fe0a00000000, + 0x1abdcac300000000, 0xe14bd98400000000, 0x6c4ac67500000000, + 0x97bcd53200000000, 0x9aa7e1fb00000000, 0x6151f2bc00000000, + 0xc197f8b200000000, 0x3a61ebf500000000, 0x377adf3c00000000, + 0xcc8ccc7b00000000, 0x77f7ca2000000000, 0x8c01d96700000000, + 0x811aedae00000000, 0x7aecfee900000000, 0xda2af4e700000000, + 0x21dce7a000000000, 0x2cc7d36900000000, 0xd731c02e00000000, + 0x6c206a9500000000, 0x97d679d200000000, 0x9acd4d1b00000000, + 0x613b5e5c00000000, 0xc1fd545200000000, 0x3a0b471500000000, + 0x371073dc00000000, 0xcce6609b00000000, 0x779d66c000000000, + 0x8c6b758700000000, 0x8170414e00000000, 0x7a86520900000000, + 0xda40580700000000, 0x21b64b4000000000, 0x2cad7f8900000000, + 0xd75b6cce00000000, 0x5a5a733f00000000, 0xa1ac607800000000, + 0xacb754b100000000, 0x574147f600000000, 0xf7874df800000000, + 0x0c715ebf00000000, 0x016a6a7600000000, 0xfa9c793100000000, + 0x41e77f6a00000000, 0xba116c2d00000000, 0xb70a58e400000000, + 0x4cfc4ba300000000, 0xec3a41ad00000000, 0x17cc52ea00000000, + 0x1ad7662300000000, 0xe121756400000000, 0x41d2291a00000000, + 0xba243a5d00000000, 0xb73f0e9400000000, 0x4cc91dd300000000, + 0xec0f17dd00000000, 0x17f9049a00000000, 0x1ae2305300000000, + 0xe114231400000000, 0x5a6f254f00000000, 0xa199360800000000, + 0xac8202c100000000, 0x5774118600000000, 0xf7b21b8800000000, + 0x0c4408cf00000000, 0x015f3c0600000000, 0xfaa92f4100000000, + 0x77a830b000000000, 0x8c5e23f700000000, 0x8145173e00000000, + 0x7ab3047900000000, 0xda750e7700000000, 0x21831d3000000000, + 0x2c9829f900000000, 0xd76e3abe00000000, 0x6c153ce500000000, + 0x97e32fa200000000, 0x9af81b6b00000000, 0x610e082c00000000, + 0xc1c8022200000000, 0x3a3e116500000000, 0x372525ac00000000, + 0xccd336eb00000000}, + {0x0000000000000000, 0x6238282a00000000, 0xc470505400000000, + 0xa648787e00000000, 0x88e1a0a800000000, 0xead9888200000000, + 0x4c91f0fc00000000, 0x2ea9d8d600000000, 0x51c5308a00000000, + 0x33fd18a000000000, 0x95b560de00000000, 0xf78d48f400000000, + 0xd924902200000000, 0xbb1cb80800000000, 0x1d54c07600000000, + 0x7f6ce85c00000000, 0xe38c10cf00000000, 0x81b438e500000000, + 0x27fc409b00000000, 0x45c468b100000000, 0x6b6db06700000000, + 0x0955984d00000000, 0xaf1de03300000000, 0xcd25c81900000000, + 0xb249204500000000, 0xd071086f00000000, 0x7639701100000000, + 0x1401583b00000000, 0x3aa880ed00000000, 0x5890a8c700000000, + 0xfed8d0b900000000, 0x9ce0f89300000000, 0x871f504500000000, + 0xe527786f00000000, 0x436f001100000000, 0x2157283b00000000, + 0x0ffef0ed00000000, 0x6dc6d8c700000000, 0xcb8ea0b900000000, + 0xa9b6889300000000, 0xd6da60cf00000000, 0xb4e248e500000000, + 0x12aa309b00000000, 0x709218b100000000, 0x5e3bc06700000000, + 0x3c03e84d00000000, 0x9a4b903300000000, 0xf873b81900000000, + 0x6493408a00000000, 0x06ab68a000000000, 0xa0e310de00000000, + 0xc2db38f400000000, 0xec72e02200000000, 0x8e4ac80800000000, + 0x2802b07600000000, 0x4a3a985c00000000, 0x3556700000000000, + 0x576e582a00000000, 0xf126205400000000, 0x931e087e00000000, + 0xbdb7d0a800000000, 0xdf8ff88200000000, 0x79c780fc00000000, + 0x1bffa8d600000000, 0x0e3fa08a00000000, 0x6c0788a000000000, + 0xca4ff0de00000000, 0xa877d8f400000000, 0x86de002200000000, + 0xe4e6280800000000, 0x42ae507600000000, 0x2096785c00000000, + 0x5ffa900000000000, 0x3dc2b82a00000000, 0x9b8ac05400000000, + 0xf9b2e87e00000000, 0xd71b30a800000000, 0xb523188200000000, + 0x136b60fc00000000, 0x715348d600000000, 0xedb3b04500000000, + 0x8f8b986f00000000, 0x29c3e01100000000, 0x4bfbc83b00000000, + 0x655210ed00000000, 0x076a38c700000000, 0xa12240b900000000, + 0xc31a689300000000, 0xbc7680cf00000000, 0xde4ea8e500000000, + 0x7806d09b00000000, 0x1a3ef8b100000000, 0x3497206700000000, + 0x56af084d00000000, 0xf0e7703300000000, 0x92df581900000000, + 0x8920f0cf00000000, 0xeb18d8e500000000, 0x4d50a09b00000000, + 0x2f6888b100000000, 0x01c1506700000000, 0x63f9784d00000000, + 0xc5b1003300000000, 0xa789281900000000, 0xd8e5c04500000000, + 0xbadde86f00000000, 0x1c95901100000000, 0x7eadb83b00000000, + 0x500460ed00000000, 0x323c48c700000000, 0x947430b900000000, + 0xf64c189300000000, 0x6aace00000000000, 0x0894c82a00000000, + 0xaedcb05400000000, 0xcce4987e00000000, 0xe24d40a800000000, + 0x8075688200000000, 0x263d10fc00000000, 0x440538d600000000, + 0x3b69d08a00000000, 0x5951f8a000000000, 0xff1980de00000000, + 0x9d21a8f400000000, 0xb388702200000000, 0xd1b0580800000000, + 0x77f8207600000000, 0x15c0085c00000000, 0x5d7831ce00000000, + 0x3f4019e400000000, 0x9908619a00000000, 0xfb3049b000000000, + 0xd599916600000000, 0xb7a1b94c00000000, 0x11e9c13200000000, + 0x73d1e91800000000, 0x0cbd014400000000, 0x6e85296e00000000, + 0xc8cd511000000000, 0xaaf5793a00000000, 0x845ca1ec00000000, + 0xe66489c600000000, 0x402cf1b800000000, 0x2214d99200000000, + 0xbef4210100000000, 0xdccc092b00000000, 0x7a84715500000000, + 0x18bc597f00000000, 0x361581a900000000, 0x542da98300000000, + 0xf265d1fd00000000, 0x905df9d700000000, 0xef31118b00000000, + 0x8d0939a100000000, 0x2b4141df00000000, 0x497969f500000000, + 0x67d0b12300000000, 0x05e8990900000000, 0xa3a0e17700000000, + 0xc198c95d00000000, 0xda67618b00000000, 0xb85f49a100000000, + 0x1e1731df00000000, 0x7c2f19f500000000, 0x5286c12300000000, + 0x30bee90900000000, 0x96f6917700000000, 0xf4ceb95d00000000, + 0x8ba2510100000000, 0xe99a792b00000000, 0x4fd2015500000000, + 0x2dea297f00000000, 0x0343f1a900000000, 0x617bd98300000000, + 0xc733a1fd00000000, 0xa50b89d700000000, 0x39eb714400000000, + 0x5bd3596e00000000, 0xfd9b211000000000, 0x9fa3093a00000000, + 0xb10ad1ec00000000, 0xd332f9c600000000, 0x757a81b800000000, + 0x1742a99200000000, 0x682e41ce00000000, 0x0a1669e400000000, + 0xac5e119a00000000, 0xce6639b000000000, 0xe0cfe16600000000, + 0x82f7c94c00000000, 0x24bfb13200000000, 0x4687991800000000, + 0x5347914400000000, 0x317fb96e00000000, 0x9737c11000000000, + 0xf50fe93a00000000, 0xdba631ec00000000, 0xb99e19c600000000, + 0x1fd661b800000000, 0x7dee499200000000, 0x0282a1ce00000000, + 0x60ba89e400000000, 0xc6f2f19a00000000, 0xa4cad9b000000000, + 0x8a63016600000000, 0xe85b294c00000000, 0x4e13513200000000, + 0x2c2b791800000000, 0xb0cb818b00000000, 0xd2f3a9a100000000, + 0x74bbd1df00000000, 0x1683f9f500000000, 0x382a212300000000, + 0x5a12090900000000, 0xfc5a717700000000, 0x9e62595d00000000, + 0xe10eb10100000000, 0x8336992b00000000, 0x257ee15500000000, + 0x4746c97f00000000, 0x69ef11a900000000, 0x0bd7398300000000, + 0xad9f41fd00000000, 0xcfa769d700000000, 0xd458c10100000000, + 0xb660e92b00000000, 0x1028915500000000, 0x7210b97f00000000, + 0x5cb961a900000000, 0x3e81498300000000, 0x98c931fd00000000, + 0xfaf119d700000000, 0x859df18b00000000, 0xe7a5d9a100000000, + 0x41eda1df00000000, 0x23d589f500000000, 0x0d7c512300000000, + 0x6f44790900000000, 0xc90c017700000000, 0xab34295d00000000, + 0x37d4d1ce00000000, 0x55ecf9e400000000, 0xf3a4819a00000000, + 0x919ca9b000000000, 0xbf35716600000000, 0xdd0d594c00000000, + 0x7b45213200000000, 0x197d091800000000, 0x6611e14400000000, + 0x0429c96e00000000, 0xa261b11000000000, 0xc059993a00000000, + 0xeef041ec00000000, 0x8cc869c600000000, 0x2a8011b800000000, + 0x48b8399200000000}, + {0x0000000000000000, 0x4c2896a300000000, 0xd9565d9c00000000, + 0x957ecb3f00000000, 0xf3abcbe300000000, 0xbf835d4000000000, + 0x2afd967f00000000, 0x66d500dc00000000, 0xa751e61c00000000, + 0xeb7970bf00000000, 0x7e07bb8000000000, 0x322f2d2300000000, + 0x54fa2dff00000000, 0x18d2bb5c00000000, 0x8dac706300000000, + 0xc184e6c000000000, 0x4ea3cc3900000000, 0x028b5a9a00000000, + 0x97f591a500000000, 0xdbdd070600000000, 0xbd0807da00000000, + 0xf120917900000000, 0x645e5a4600000000, 0x2876cce500000000, + 0xe9f22a2500000000, 0xa5dabc8600000000, 0x30a477b900000000, + 0x7c8ce11a00000000, 0x1a59e1c600000000, 0x5671776500000000, + 0xc30fbc5a00000000, 0x8f272af900000000, 0x9c46997300000000, + 0xd06e0fd000000000, 0x4510c4ef00000000, 0x0938524c00000000, + 0x6fed529000000000, 0x23c5c43300000000, 0xb6bb0f0c00000000, + 0xfa9399af00000000, 0x3b177f6f00000000, 0x773fe9cc00000000, + 0xe24122f300000000, 0xae69b45000000000, 0xc8bcb48c00000000, + 0x8494222f00000000, 0x11eae91000000000, 0x5dc27fb300000000, + 0xd2e5554a00000000, 0x9ecdc3e900000000, 0x0bb308d600000000, + 0x479b9e7500000000, 0x214e9ea900000000, 0x6d66080a00000000, + 0xf818c33500000000, 0xb430559600000000, 0x75b4b35600000000, + 0x399c25f500000000, 0xace2eeca00000000, 0xe0ca786900000000, + 0x861f78b500000000, 0xca37ee1600000000, 0x5f49252900000000, + 0x1361b38a00000000, 0x388d32e700000000, 0x74a5a44400000000, + 0xe1db6f7b00000000, 0xadf3f9d800000000, 0xcb26f90400000000, + 0x870e6fa700000000, 0x1270a49800000000, 0x5e58323b00000000, + 0x9fdcd4fb00000000, 0xd3f4425800000000, 0x468a896700000000, + 0x0aa21fc400000000, 0x6c771f1800000000, 0x205f89bb00000000, + 0xb521428400000000, 0xf909d42700000000, 0x762efede00000000, + 0x3a06687d00000000, 0xaf78a34200000000, 0xe35035e100000000, + 0x8585353d00000000, 0xc9ada39e00000000, 0x5cd368a100000000, + 0x10fbfe0200000000, 0xd17f18c200000000, 0x9d578e6100000000, + 0x0829455e00000000, 0x4401d3fd00000000, 0x22d4d32100000000, + 0x6efc458200000000, 0xfb828ebd00000000, 0xb7aa181e00000000, + 0xa4cbab9400000000, 0xe8e33d3700000000, 0x7d9df60800000000, + 0x31b560ab00000000, 0x5760607700000000, 0x1b48f6d400000000, + 0x8e363deb00000000, 0xc21eab4800000000, 0x039a4d8800000000, + 0x4fb2db2b00000000, 0xdacc101400000000, 0x96e486b700000000, + 0xf031866b00000000, 0xbc1910c800000000, 0x2967dbf700000000, + 0x654f4d5400000000, 0xea6867ad00000000, 0xa640f10e00000000, + 0x333e3a3100000000, 0x7f16ac9200000000, 0x19c3ac4e00000000, + 0x55eb3aed00000000, 0xc095f1d200000000, 0x8cbd677100000000, + 0x4d3981b100000000, 0x0111171200000000, 0x946fdc2d00000000, + 0xd8474a8e00000000, 0xbe924a5200000000, 0xf2badcf100000000, + 0x67c417ce00000000, 0x2bec816d00000000, 0x311c141500000000, + 0x7d3482b600000000, 0xe84a498900000000, 0xa462df2a00000000, + 0xc2b7dff600000000, 0x8e9f495500000000, 0x1be1826a00000000, + 0x57c914c900000000, 0x964df20900000000, 0xda6564aa00000000, + 0x4f1baf9500000000, 0x0333393600000000, 0x65e639ea00000000, + 0x29ceaf4900000000, 0xbcb0647600000000, 0xf098f2d500000000, + 0x7fbfd82c00000000, 0x33974e8f00000000, 0xa6e985b000000000, + 0xeac1131300000000, 0x8c1413cf00000000, 0xc03c856c00000000, + 0x55424e5300000000, 0x196ad8f000000000, 0xd8ee3e3000000000, + 0x94c6a89300000000, 0x01b863ac00000000, 0x4d90f50f00000000, + 0x2b45f5d300000000, 0x676d637000000000, 0xf213a84f00000000, + 0xbe3b3eec00000000, 0xad5a8d6600000000, 0xe1721bc500000000, + 0x740cd0fa00000000, 0x3824465900000000, 0x5ef1468500000000, + 0x12d9d02600000000, 0x87a71b1900000000, 0xcb8f8dba00000000, + 0x0a0b6b7a00000000, 0x4623fdd900000000, 0xd35d36e600000000, + 0x9f75a04500000000, 0xf9a0a09900000000, 0xb588363a00000000, + 0x20f6fd0500000000, 0x6cde6ba600000000, 0xe3f9415f00000000, + 0xafd1d7fc00000000, 0x3aaf1cc300000000, 0x76878a6000000000, + 0x10528abc00000000, 0x5c7a1c1f00000000, 0xc904d72000000000, + 0x852c418300000000, 0x44a8a74300000000, 0x088031e000000000, + 0x9dfefadf00000000, 0xd1d66c7c00000000, 0xb7036ca000000000, + 0xfb2bfa0300000000, 0x6e55313c00000000, 0x227da79f00000000, + 0x099126f200000000, 0x45b9b05100000000, 0xd0c77b6e00000000, + 0x9cefedcd00000000, 0xfa3aed1100000000, 0xb6127bb200000000, + 0x236cb08d00000000, 0x6f44262e00000000, 0xaec0c0ee00000000, + 0xe2e8564d00000000, 0x77969d7200000000, 0x3bbe0bd100000000, + 0x5d6b0b0d00000000, 0x11439dae00000000, 0x843d569100000000, + 0xc815c03200000000, 0x4732eacb00000000, 0x0b1a7c6800000000, + 0x9e64b75700000000, 0xd24c21f400000000, 0xb499212800000000, + 0xf8b1b78b00000000, 0x6dcf7cb400000000, 0x21e7ea1700000000, + 0xe0630cd700000000, 0xac4b9a7400000000, 0x3935514b00000000, + 0x751dc7e800000000, 0x13c8c73400000000, 0x5fe0519700000000, + 0xca9e9aa800000000, 0x86b60c0b00000000, 0x95d7bf8100000000, + 0xd9ff292200000000, 0x4c81e21d00000000, 0x00a974be00000000, + 0x667c746200000000, 0x2a54e2c100000000, 0xbf2a29fe00000000, + 0xf302bf5d00000000, 0x3286599d00000000, 0x7eaecf3e00000000, + 0xebd0040100000000, 0xa7f892a200000000, 0xc12d927e00000000, + 0x8d0504dd00000000, 0x187bcfe200000000, 0x5453594100000000, + 0xdb7473b800000000, 0x975ce51b00000000, 0x02222e2400000000, + 0x4e0ab88700000000, 0x28dfb85b00000000, 0x64f72ef800000000, + 0xf189e5c700000000, 0xbda1736400000000, 0x7c2595a400000000, + 0x300d030700000000, 0xa573c83800000000, 0xe95b5e9b00000000, + 0x8f8e5e4700000000, 0xc3a6c8e400000000, 0x56d803db00000000, + 0x1af0957800000000}, + {0x0000000000000000, 0x939bc97f00000000, 0x263793ff00000000, + 0xb5ac5a8000000000, 0x0d68572400000000, 0x9ef39e5b00000000, + 0x2b5fc4db00000000, 0xb8c40da400000000, 0x1ad0ae4800000000, + 0x894b673700000000, 0x3ce73db700000000, 0xaf7cf4c800000000, + 0x17b8f96c00000000, 0x8423301300000000, 0x318f6a9300000000, + 0xa214a3ec00000000, 0x34a05d9100000000, 0xa73b94ee00000000, + 0x1297ce6e00000000, 0x810c071100000000, 0x39c80ab500000000, + 0xaa53c3ca00000000, 0x1fff994a00000000, 0x8c64503500000000, + 0x2e70f3d900000000, 0xbdeb3aa600000000, 0x0847602600000000, + 0x9bdca95900000000, 0x2318a4fd00000000, 0xb0836d8200000000, + 0x052f370200000000, 0x96b4fe7d00000000, 0x2946caf900000000, + 0xbadd038600000000, 0x0f71590600000000, 0x9cea907900000000, + 0x242e9ddd00000000, 0xb7b554a200000000, 0x02190e2200000000, + 0x9182c75d00000000, 0x339664b100000000, 0xa00dadce00000000, + 0x15a1f74e00000000, 0x863a3e3100000000, 0x3efe339500000000, + 0xad65faea00000000, 0x18c9a06a00000000, 0x8b52691500000000, + 0x1de6976800000000, 0x8e7d5e1700000000, 0x3bd1049700000000, + 0xa84acde800000000, 0x108ec04c00000000, 0x8315093300000000, + 0x36b953b300000000, 0xa5229acc00000000, 0x0736392000000000, + 0x94adf05f00000000, 0x2101aadf00000000, 0xb29a63a000000000, + 0x0a5e6e0400000000, 0x99c5a77b00000000, 0x2c69fdfb00000000, + 0xbff2348400000000, 0x138ae52800000000, 0x80112c5700000000, + 0x35bd76d700000000, 0xa626bfa800000000, 0x1ee2b20c00000000, + 0x8d797b7300000000, 0x38d521f300000000, 0xab4ee88c00000000, + 0x095a4b6000000000, 0x9ac1821f00000000, 0x2f6dd89f00000000, + 0xbcf611e000000000, 0x04321c4400000000, 0x97a9d53b00000000, + 0x22058fbb00000000, 0xb19e46c400000000, 0x272ab8b900000000, + 0xb4b171c600000000, 0x011d2b4600000000, 0x9286e23900000000, + 0x2a42ef9d00000000, 0xb9d926e200000000, 0x0c757c6200000000, + 0x9feeb51d00000000, 0x3dfa16f100000000, 0xae61df8e00000000, + 0x1bcd850e00000000, 0x88564c7100000000, 0x309241d500000000, + 0xa30988aa00000000, 0x16a5d22a00000000, 0x853e1b5500000000, + 0x3acc2fd100000000, 0xa957e6ae00000000, 0x1cfbbc2e00000000, + 0x8f60755100000000, 0x37a478f500000000, 0xa43fb18a00000000, + 0x1193eb0a00000000, 0x8208227500000000, 0x201c819900000000, + 0xb38748e600000000, 0x062b126600000000, 0x95b0db1900000000, + 0x2d74d6bd00000000, 0xbeef1fc200000000, 0x0b43454200000000, + 0x98d88c3d00000000, 0x0e6c724000000000, 0x9df7bb3f00000000, + 0x285be1bf00000000, 0xbbc028c000000000, 0x0304256400000000, + 0x909fec1b00000000, 0x2533b69b00000000, 0xb6a87fe400000000, + 0x14bcdc0800000000, 0x8727157700000000, 0x328b4ff700000000, + 0xa110868800000000, 0x19d48b2c00000000, 0x8a4f425300000000, + 0x3fe318d300000000, 0xac78d1ac00000000, 0x2614cb5100000000, + 0xb58f022e00000000, 0x002358ae00000000, 0x93b891d100000000, + 0x2b7c9c7500000000, 0xb8e7550a00000000, 0x0d4b0f8a00000000, + 0x9ed0c6f500000000, 0x3cc4651900000000, 0xaf5fac6600000000, + 0x1af3f6e600000000, 0x89683f9900000000, 0x31ac323d00000000, + 0xa237fb4200000000, 0x179ba1c200000000, 0x840068bd00000000, + 0x12b496c000000000, 0x812f5fbf00000000, 0x3483053f00000000, + 0xa718cc4000000000, 0x1fdcc1e400000000, 0x8c47089b00000000, + 0x39eb521b00000000, 0xaa709b6400000000, 0x0864388800000000, + 0x9bfff1f700000000, 0x2e53ab7700000000, 0xbdc8620800000000, + 0x050c6fac00000000, 0x9697a6d300000000, 0x233bfc5300000000, + 0xb0a0352c00000000, 0x0f5201a800000000, 0x9cc9c8d700000000, + 0x2965925700000000, 0xbafe5b2800000000, 0x023a568c00000000, + 0x91a19ff300000000, 0x240dc57300000000, 0xb7960c0c00000000, + 0x1582afe000000000, 0x8619669f00000000, 0x33b53c1f00000000, + 0xa02ef56000000000, 0x18eaf8c400000000, 0x8b7131bb00000000, + 0x3edd6b3b00000000, 0xad46a24400000000, 0x3bf25c3900000000, + 0xa869954600000000, 0x1dc5cfc600000000, 0x8e5e06b900000000, + 0x369a0b1d00000000, 0xa501c26200000000, 0x10ad98e200000000, + 0x8336519d00000000, 0x2122f27100000000, 0xb2b93b0e00000000, + 0x0715618e00000000, 0x948ea8f100000000, 0x2c4aa55500000000, + 0xbfd16c2a00000000, 0x0a7d36aa00000000, 0x99e6ffd500000000, + 0x359e2e7900000000, 0xa605e70600000000, 0x13a9bd8600000000, + 0x803274f900000000, 0x38f6795d00000000, 0xab6db02200000000, + 0x1ec1eaa200000000, 0x8d5a23dd00000000, 0x2f4e803100000000, + 0xbcd5494e00000000, 0x097913ce00000000, 0x9ae2dab100000000, + 0x2226d71500000000, 0xb1bd1e6a00000000, 0x041144ea00000000, + 0x978a8d9500000000, 0x013e73e800000000, 0x92a5ba9700000000, + 0x2709e01700000000, 0xb492296800000000, 0x0c5624cc00000000, + 0x9fcdedb300000000, 0x2a61b73300000000, 0xb9fa7e4c00000000, + 0x1beedda000000000, 0x887514df00000000, 0x3dd94e5f00000000, + 0xae42872000000000, 0x16868a8400000000, 0x851d43fb00000000, + 0x30b1197b00000000, 0xa32ad00400000000, 0x1cd8e48000000000, + 0x8f432dff00000000, 0x3aef777f00000000, 0xa974be0000000000, + 0x11b0b3a400000000, 0x822b7adb00000000, 0x3787205b00000000, + 0xa41ce92400000000, 0x06084ac800000000, 0x959383b700000000, + 0x203fd93700000000, 0xb3a4104800000000, 0x0b601dec00000000, + 0x98fbd49300000000, 0x2d578e1300000000, 0xbecc476c00000000, + 0x2878b91100000000, 0xbbe3706e00000000, 0x0e4f2aee00000000, + 0x9dd4e39100000000, 0x2510ee3500000000, 0xb68b274a00000000, + 0x03277dca00000000, 0x90bcb4b500000000, 0x32a8175900000000, + 0xa133de2600000000, 0x149f84a600000000, 0x87044dd900000000, + 0x3fc0407d00000000, 0xac5b890200000000, 0x19f7d38200000000, + 0x8a6c1afd00000000}, + {0x0000000000000000, 0x650b796900000000, 0xca16f2d200000000, + 0xaf1d8bbb00000000, 0xd52b957e00000000, 0xb020ec1700000000, + 0x1f3d67ac00000000, 0x7a361ec500000000, 0xaa572afd00000000, + 0xcf5c539400000000, 0x6041d82f00000000, 0x054aa14600000000, + 0x7f7cbf8300000000, 0x1a77c6ea00000000, 0xb56a4d5100000000, + 0xd061343800000000, 0x15a9252100000000, 0x70a25c4800000000, + 0xdfbfd7f300000000, 0xbab4ae9a00000000, 0xc082b05f00000000, + 0xa589c93600000000, 0x0a94428d00000000, 0x6f9f3be400000000, + 0xbffe0fdc00000000, 0xdaf576b500000000, 0x75e8fd0e00000000, + 0x10e3846700000000, 0x6ad59aa200000000, 0x0fdee3cb00000000, + 0xa0c3687000000000, 0xc5c8111900000000, 0x2a524b4200000000, + 0x4f59322b00000000, 0xe044b99000000000, 0x854fc0f900000000, + 0xff79de3c00000000, 0x9a72a75500000000, 0x356f2cee00000000, + 0x5064558700000000, 0x800561bf00000000, 0xe50e18d600000000, + 0x4a13936d00000000, 0x2f18ea0400000000, 0x552ef4c100000000, + 0x30258da800000000, 0x9f38061300000000, 0xfa337f7a00000000, + 0x3ffb6e6300000000, 0x5af0170a00000000, 0xf5ed9cb100000000, + 0x90e6e5d800000000, 0xead0fb1d00000000, 0x8fdb827400000000, + 0x20c609cf00000000, 0x45cd70a600000000, 0x95ac449e00000000, + 0xf0a73df700000000, 0x5fbab64c00000000, 0x3ab1cf2500000000, + 0x4087d1e000000000, 0x258ca88900000000, 0x8a91233200000000, + 0xef9a5a5b00000000, 0x54a4968400000000, 0x31afefed00000000, + 0x9eb2645600000000, 0xfbb91d3f00000000, 0x818f03fa00000000, + 0xe4847a9300000000, 0x4b99f12800000000, 0x2e92884100000000, + 0xfef3bc7900000000, 0x9bf8c51000000000, 0x34e54eab00000000, + 0x51ee37c200000000, 0x2bd8290700000000, 0x4ed3506e00000000, + 0xe1cedbd500000000, 0x84c5a2bc00000000, 0x410db3a500000000, + 0x2406cacc00000000, 0x8b1b417700000000, 0xee10381e00000000, + 0x942626db00000000, 0xf12d5fb200000000, 0x5e30d40900000000, + 0x3b3bad6000000000, 0xeb5a995800000000, 0x8e51e03100000000, + 0x214c6b8a00000000, 0x444712e300000000, 0x3e710c2600000000, + 0x5b7a754f00000000, 0xf467fef400000000, 0x916c879d00000000, + 0x7ef6ddc600000000, 0x1bfda4af00000000, 0xb4e02f1400000000, + 0xd1eb567d00000000, 0xabdd48b800000000, 0xced631d100000000, + 0x61cbba6a00000000, 0x04c0c30300000000, 0xd4a1f73b00000000, + 0xb1aa8e5200000000, 0x1eb705e900000000, 0x7bbc7c8000000000, + 0x018a624500000000, 0x64811b2c00000000, 0xcb9c909700000000, + 0xae97e9fe00000000, 0x6b5ff8e700000000, 0x0e54818e00000000, + 0xa1490a3500000000, 0xc442735c00000000, 0xbe746d9900000000, + 0xdb7f14f000000000, 0x74629f4b00000000, 0x1169e62200000000, + 0xc108d21a00000000, 0xa403ab7300000000, 0x0b1e20c800000000, + 0x6e1559a100000000, 0x1423476400000000, 0x71283e0d00000000, + 0xde35b5b600000000, 0xbb3eccdf00000000, 0xe94e5cd200000000, + 0x8c4525bb00000000, 0x2358ae0000000000, 0x4653d76900000000, + 0x3c65c9ac00000000, 0x596eb0c500000000, 0xf6733b7e00000000, + 0x9378421700000000, 0x4319762f00000000, 0x26120f4600000000, + 0x890f84fd00000000, 0xec04fd9400000000, 0x9632e35100000000, + 0xf3399a3800000000, 0x5c24118300000000, 0x392f68ea00000000, + 0xfce779f300000000, 0x99ec009a00000000, 0x36f18b2100000000, + 0x53faf24800000000, 0x29ccec8d00000000, 0x4cc795e400000000, + 0xe3da1e5f00000000, 0x86d1673600000000, 0x56b0530e00000000, + 0x33bb2a6700000000, 0x9ca6a1dc00000000, 0xf9add8b500000000, + 0x839bc67000000000, 0xe690bf1900000000, 0x498d34a200000000, + 0x2c864dcb00000000, 0xc31c179000000000, 0xa6176ef900000000, + 0x090ae54200000000, 0x6c019c2b00000000, 0x163782ee00000000, + 0x733cfb8700000000, 0xdc21703c00000000, 0xb92a095500000000, + 0x694b3d6d00000000, 0x0c40440400000000, 0xa35dcfbf00000000, + 0xc656b6d600000000, 0xbc60a81300000000, 0xd96bd17a00000000, + 0x76765ac100000000, 0x137d23a800000000, 0xd6b532b100000000, + 0xb3be4bd800000000, 0x1ca3c06300000000, 0x79a8b90a00000000, + 0x039ea7cf00000000, 0x6695dea600000000, 0xc988551d00000000, + 0xac832c7400000000, 0x7ce2184c00000000, 0x19e9612500000000, + 0xb6f4ea9e00000000, 0xd3ff93f700000000, 0xa9c98d3200000000, + 0xccc2f45b00000000, 0x63df7fe000000000, 0x06d4068900000000, + 0xbdeaca5600000000, 0xd8e1b33f00000000, 0x77fc388400000000, + 0x12f741ed00000000, 0x68c15f2800000000, 0x0dca264100000000, + 0xa2d7adfa00000000, 0xc7dcd49300000000, 0x17bde0ab00000000, + 0x72b699c200000000, 0xddab127900000000, 0xb8a06b1000000000, + 0xc29675d500000000, 0xa79d0cbc00000000, 0x0880870700000000, + 0x6d8bfe6e00000000, 0xa843ef7700000000, 0xcd48961e00000000, + 0x62551da500000000, 0x075e64cc00000000, 0x7d687a0900000000, + 0x1863036000000000, 0xb77e88db00000000, 0xd275f1b200000000, + 0x0214c58a00000000, 0x671fbce300000000, 0xc802375800000000, + 0xad094e3100000000, 0xd73f50f400000000, 0xb234299d00000000, + 0x1d29a22600000000, 0x7822db4f00000000, 0x97b8811400000000, + 0xf2b3f87d00000000, 0x5dae73c600000000, 0x38a50aaf00000000, + 0x4293146a00000000, 0x27986d0300000000, 0x8885e6b800000000, + 0xed8e9fd100000000, 0x3defabe900000000, 0x58e4d28000000000, + 0xf7f9593b00000000, 0x92f2205200000000, 0xe8c43e9700000000, + 0x8dcf47fe00000000, 0x22d2cc4500000000, 0x47d9b52c00000000, + 0x8211a43500000000, 0xe71add5c00000000, 0x480756e700000000, + 0x2d0c2f8e00000000, 0x573a314b00000000, 0x3231482200000000, + 0x9d2cc39900000000, 0xf827baf000000000, 0x28468ec800000000, + 0x4d4df7a100000000, 0xe2507c1a00000000, 0x875b057300000000, + 0xfd6d1bb600000000, 0x986662df00000000, 0x377be96400000000, + 0x5270900d00000000}, + {0x0000000000000000, 0xdcecb13d00000000, 0xb8d9637b00000000, + 0x6435d24600000000, 0x70b3c7f600000000, 0xac5f76cb00000000, + 0xc86aa48d00000000, 0x148615b000000000, 0xa160fe3600000000, + 0x7d8c4f0b00000000, 0x19b99d4d00000000, 0xc5552c7000000000, + 0xd1d339c000000000, 0x0d3f88fd00000000, 0x690a5abb00000000, + 0xb5e6eb8600000000, 0x42c1fc6d00000000, 0x9e2d4d5000000000, + 0xfa189f1600000000, 0x26f42e2b00000000, 0x32723b9b00000000, + 0xee9e8aa600000000, 0x8aab58e000000000, 0x5647e9dd00000000, + 0xe3a1025b00000000, 0x3f4db36600000000, 0x5b78612000000000, + 0x8794d01d00000000, 0x9312c5ad00000000, 0x4ffe749000000000, + 0x2bcba6d600000000, 0xf72717eb00000000, 0x8482f9db00000000, + 0x586e48e600000000, 0x3c5b9aa000000000, 0xe0b72b9d00000000, + 0xf4313e2d00000000, 0x28dd8f1000000000, 0x4ce85d5600000000, + 0x9004ec6b00000000, 0x25e207ed00000000, 0xf90eb6d000000000, + 0x9d3b649600000000, 0x41d7d5ab00000000, 0x5551c01b00000000, + 0x89bd712600000000, 0xed88a36000000000, 0x3164125d00000000, + 0xc64305b600000000, 0x1aafb48b00000000, 0x7e9a66cd00000000, + 0xa276d7f000000000, 0xb6f0c24000000000, 0x6a1c737d00000000, + 0x0e29a13b00000000, 0xd2c5100600000000, 0x6723fb8000000000, + 0xbbcf4abd00000000, 0xdffa98fb00000000, 0x031629c600000000, + 0x17903c7600000000, 0xcb7c8d4b00000000, 0xaf495f0d00000000, + 0x73a5ee3000000000, 0x4903826c00000000, 0x95ef335100000000, + 0xf1dae11700000000, 0x2d36502a00000000, 0x39b0459a00000000, + 0xe55cf4a700000000, 0x816926e100000000, 0x5d8597dc00000000, + 0xe8637c5a00000000, 0x348fcd6700000000, 0x50ba1f2100000000, + 0x8c56ae1c00000000, 0x98d0bbac00000000, 0x443c0a9100000000, + 0x2009d8d700000000, 0xfce569ea00000000, 0x0bc27e0100000000, + 0xd72ecf3c00000000, 0xb31b1d7a00000000, 0x6ff7ac4700000000, + 0x7b71b9f700000000, 0xa79d08ca00000000, 0xc3a8da8c00000000, + 0x1f446bb100000000, 0xaaa2803700000000, 0x764e310a00000000, + 0x127be34c00000000, 0xce97527100000000, 0xda1147c100000000, + 0x06fdf6fc00000000, 0x62c824ba00000000, 0xbe24958700000000, + 0xcd817bb700000000, 0x116dca8a00000000, 0x755818cc00000000, + 0xa9b4a9f100000000, 0xbd32bc4100000000, 0x61de0d7c00000000, + 0x05ebdf3a00000000, 0xd9076e0700000000, 0x6ce1858100000000, + 0xb00d34bc00000000, 0xd438e6fa00000000, 0x08d457c700000000, + 0x1c52427700000000, 0xc0bef34a00000000, 0xa48b210c00000000, + 0x7867903100000000, 0x8f4087da00000000, 0x53ac36e700000000, + 0x3799e4a100000000, 0xeb75559c00000000, 0xfff3402c00000000, + 0x231ff11100000000, 0x472a235700000000, 0x9bc6926a00000000, + 0x2e2079ec00000000, 0xf2ccc8d100000000, 0x96f91a9700000000, + 0x4a15abaa00000000, 0x5e93be1a00000000, 0x827f0f2700000000, + 0xe64add6100000000, 0x3aa66c5c00000000, 0x920604d900000000, + 0x4eeab5e400000000, 0x2adf67a200000000, 0xf633d69f00000000, + 0xe2b5c32f00000000, 0x3e59721200000000, 0x5a6ca05400000000, + 0x8680116900000000, 0x3366faef00000000, 0xef8a4bd200000000, + 0x8bbf999400000000, 0x575328a900000000, 0x43d53d1900000000, + 0x9f398c2400000000, 0xfb0c5e6200000000, 0x27e0ef5f00000000, + 0xd0c7f8b400000000, 0x0c2b498900000000, 0x681e9bcf00000000, + 0xb4f22af200000000, 0xa0743f4200000000, 0x7c988e7f00000000, + 0x18ad5c3900000000, 0xc441ed0400000000, 0x71a7068200000000, + 0xad4bb7bf00000000, 0xc97e65f900000000, 0x1592d4c400000000, + 0x0114c17400000000, 0xddf8704900000000, 0xb9cda20f00000000, + 0x6521133200000000, 0x1684fd0200000000, 0xca684c3f00000000, + 0xae5d9e7900000000, 0x72b12f4400000000, 0x66373af400000000, + 0xbadb8bc900000000, 0xdeee598f00000000, 0x0202e8b200000000, + 0xb7e4033400000000, 0x6b08b20900000000, 0x0f3d604f00000000, + 0xd3d1d17200000000, 0xc757c4c200000000, 0x1bbb75ff00000000, + 0x7f8ea7b900000000, 0xa362168400000000, 0x5445016f00000000, + 0x88a9b05200000000, 0xec9c621400000000, 0x3070d32900000000, + 0x24f6c69900000000, 0xf81a77a400000000, 0x9c2fa5e200000000, + 0x40c314df00000000, 0xf525ff5900000000, 0x29c94e6400000000, + 0x4dfc9c2200000000, 0x91102d1f00000000, 0x859638af00000000, + 0x597a899200000000, 0x3d4f5bd400000000, 0xe1a3eae900000000, + 0xdb0586b500000000, 0x07e9378800000000, 0x63dce5ce00000000, + 0xbf3054f300000000, 0xabb6414300000000, 0x775af07e00000000, + 0x136f223800000000, 0xcf83930500000000, 0x7a65788300000000, + 0xa689c9be00000000, 0xc2bc1bf800000000, 0x1e50aac500000000, + 0x0ad6bf7500000000, 0xd63a0e4800000000, 0xb20fdc0e00000000, + 0x6ee36d3300000000, 0x99c47ad800000000, 0x4528cbe500000000, + 0x211d19a300000000, 0xfdf1a89e00000000, 0xe977bd2e00000000, + 0x359b0c1300000000, 0x51aede5500000000, 0x8d426f6800000000, + 0x38a484ee00000000, 0xe44835d300000000, 0x807de79500000000, + 0x5c9156a800000000, 0x4817431800000000, 0x94fbf22500000000, + 0xf0ce206300000000, 0x2c22915e00000000, 0x5f877f6e00000000, + 0x836bce5300000000, 0xe75e1c1500000000, 0x3bb2ad2800000000, + 0x2f34b89800000000, 0xf3d809a500000000, 0x97eddbe300000000, + 0x4b016ade00000000, 0xfee7815800000000, 0x220b306500000000, + 0x463ee22300000000, 0x9ad2531e00000000, 0x8e5446ae00000000, + 0x52b8f79300000000, 0x368d25d500000000, 0xea6194e800000000, + 0x1d46830300000000, 0xc1aa323e00000000, 0xa59fe07800000000, + 0x7973514500000000, 0x6df544f500000000, 0xb119f5c800000000, + 0xd52c278e00000000, 0x09c096b300000000, 0xbc267d3500000000, + 0x60cacc0800000000, 0x04ff1e4e00000000, 0xd813af7300000000, + 0xcc95bac300000000, 0x10790bfe00000000, 0x744cd9b800000000, + 0xa8a0688500000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x81256527, 0xd93bcc0f, 0x581ea928, 0x69069e5f, + 0xe823fb78, 0xb03d5250, 0x31183777, 0xd20d3cbe, 0x53285999, + 0x0b36f0b1, 0x8a139596, 0xbb0ba2e1, 0x3a2ec7c6, 0x62306eee, + 0xe3150bc9, 0x7f6b7f3d, 0xfe4e1a1a, 0xa650b332, 0x2775d615, + 0x166de162, 0x97488445, 0xcf562d6d, 0x4e73484a, 0xad664383, + 0x2c4326a4, 0x745d8f8c, 0xf578eaab, 0xc460dddc, 0x4545b8fb, + 0x1d5b11d3, 0x9c7e74f4, 0xfed6fe7a, 0x7ff39b5d, 0x27ed3275, + 0xa6c85752, 0x97d06025, 0x16f50502, 0x4eebac2a, 0xcfcec90d, + 0x2cdbc2c4, 0xadfea7e3, 0xf5e00ecb, 0x74c56bec, 0x45dd5c9b, + 0xc4f839bc, 0x9ce69094, 0x1dc3f5b3, 0x81bd8147, 0x0098e460, + 0x58864d48, 0xd9a3286f, 0xe8bb1f18, 0x699e7a3f, 0x3180d317, + 0xb0a5b630, 0x53b0bdf9, 0xd295d8de, 0x8a8b71f6, 0x0bae14d1, + 0x3ab623a6, 0xbb934681, 0xe38defa9, 0x62a88a8e, 0x26dcfab5, + 0xa7f99f92, 0xffe736ba, 0x7ec2539d, 0x4fda64ea, 0xceff01cd, + 0x96e1a8e5, 0x17c4cdc2, 0xf4d1c60b, 0x75f4a32c, 0x2dea0a04, + 0xaccf6f23, 0x9dd75854, 0x1cf23d73, 0x44ec945b, 0xc5c9f17c, + 0x59b78588, 0xd892e0af, 0x808c4987, 0x01a92ca0, 0x30b11bd7, + 0xb1947ef0, 0xe98ad7d8, 0x68afb2ff, 0x8bbab936, 0x0a9fdc11, + 0x52817539, 0xd3a4101e, 0xe2bc2769, 0x6399424e, 0x3b87eb66, + 0xbaa28e41, 0xd80a04cf, 0x592f61e8, 0x0131c8c0, 0x8014ade7, + 0xb10c9a90, 0x3029ffb7, 0x6837569f, 0xe91233b8, 0x0a073871, + 0x8b225d56, 0xd33cf47e, 0x52199159, 0x6301a62e, 0xe224c309, + 0xba3a6a21, 0x3b1f0f06, 0xa7617bf2, 0x26441ed5, 0x7e5ab7fd, + 0xff7fd2da, 0xce67e5ad, 0x4f42808a, 0x175c29a2, 0x96794c85, + 0x756c474c, 0xf449226b, 0xac578b43, 0x2d72ee64, 0x1c6ad913, + 0x9d4fbc34, 0xc551151c, 0x4474703b, 0x4db9f56a, 0xcc9c904d, + 0x94823965, 0x15a75c42, 0x24bf6b35, 0xa59a0e12, 0xfd84a73a, + 0x7ca1c21d, 0x9fb4c9d4, 0x1e91acf3, 0x468f05db, 0xc7aa60fc, + 0xf6b2578b, 0x779732ac, 0x2f899b84, 0xaeacfea3, 0x32d28a57, + 0xb3f7ef70, 0xebe94658, 0x6acc237f, 0x5bd41408, 0xdaf1712f, + 0x82efd807, 0x03cabd20, 0xe0dfb6e9, 0x61fad3ce, 0x39e47ae6, + 0xb8c11fc1, 0x89d928b6, 0x08fc4d91, 0x50e2e4b9, 0xd1c7819e, + 0xb36f0b10, 0x324a6e37, 0x6a54c71f, 0xeb71a238, 0xda69954f, + 0x5b4cf068, 0x03525940, 0x82773c67, 0x616237ae, 0xe0475289, + 0xb859fba1, 0x397c9e86, 0x0864a9f1, 0x8941ccd6, 0xd15f65fe, + 0x507a00d9, 0xcc04742d, 0x4d21110a, 0x153fb822, 0x941add05, + 0xa502ea72, 0x24278f55, 0x7c39267d, 0xfd1c435a, 0x1e094893, + 0x9f2c2db4, 0xc732849c, 0x4617e1bb, 0x770fd6cc, 0xf62ab3eb, + 0xae341ac3, 0x2f117fe4, 0x6b650fdf, 0xea406af8, 0xb25ec3d0, + 0x337ba6f7, 0x02639180, 0x8346f4a7, 0xdb585d8f, 0x5a7d38a8, + 0xb9683361, 0x384d5646, 0x6053ff6e, 0xe1769a49, 0xd06ead3e, + 0x514bc819, 0x09556131, 0x88700416, 0x140e70e2, 0x952b15c5, + 0xcd35bced, 0x4c10d9ca, 0x7d08eebd, 0xfc2d8b9a, 0xa43322b2, + 0x25164795, 0xc6034c5c, 0x4726297b, 0x1f388053, 0x9e1de574, + 0xaf05d203, 0x2e20b724, 0x763e1e0c, 0xf71b7b2b, 0x95b3f1a5, + 0x14969482, 0x4c883daa, 0xcdad588d, 0xfcb56ffa, 0x7d900add, + 0x258ea3f5, 0xa4abc6d2, 0x47becd1b, 0xc69ba83c, 0x9e850114, + 0x1fa06433, 0x2eb85344, 0xaf9d3663, 0xf7839f4b, 0x76a6fa6c, + 0xead88e98, 0x6bfdebbf, 0x33e34297, 0xb2c627b0, 0x83de10c7, + 0x02fb75e0, 0x5ae5dcc8, 0xdbc0b9ef, 0x38d5b226, 0xb9f0d701, + 0xe1ee7e29, 0x60cb1b0e, 0x51d32c79, 0xd0f6495e, 0x88e8e076, + 0x09cd8551}, + {0x00000000, 0x9b73ead4, 0xed96d3e9, 0x76e5393d, 0x005ca193, + 0x9b2f4b47, 0xedca727a, 0x76b998ae, 0x00b94326, 0x9bcaa9f2, + 0xed2f90cf, 0x765c7a1b, 0x00e5e2b5, 0x9b960861, 0xed73315c, + 0x7600db88, 0x0172864c, 0x9a016c98, 0xece455a5, 0x7797bf71, + 0x012e27df, 0x9a5dcd0b, 0xecb8f436, 0x77cb1ee2, 0x01cbc56a, + 0x9ab82fbe, 0xec5d1683, 0x772efc57, 0x019764f9, 0x9ae48e2d, + 0xec01b710, 0x77725dc4, 0x02e50c98, 0x9996e64c, 0xef73df71, + 0x740035a5, 0x02b9ad0b, 0x99ca47df, 0xef2f7ee2, 0x745c9436, + 0x025c4fbe, 0x992fa56a, 0xefca9c57, 0x74b97683, 0x0200ee2d, + 0x997304f9, 0xef963dc4, 0x74e5d710, 0x03978ad4, 0x98e46000, + 0xee01593d, 0x7572b3e9, 0x03cb2b47, 0x98b8c193, 0xee5df8ae, + 0x752e127a, 0x032ec9f2, 0x985d2326, 0xeeb81a1b, 0x75cbf0cf, + 0x03726861, 0x980182b5, 0xeee4bb88, 0x7597515c, 0x05ca1930, + 0x9eb9f3e4, 0xe85ccad9, 0x732f200d, 0x0596b8a3, 0x9ee55277, + 0xe8006b4a, 0x7373819e, 0x05735a16, 0x9e00b0c2, 0xe8e589ff, + 0x7396632b, 0x052ffb85, 0x9e5c1151, 0xe8b9286c, 0x73cac2b8, + 0x04b89f7c, 0x9fcb75a8, 0xe92e4c95, 0x725da641, 0x04e43eef, + 0x9f97d43b, 0xe972ed06, 0x720107d2, 0x0401dc5a, 0x9f72368e, + 0xe9970fb3, 0x72e4e567, 0x045d7dc9, 0x9f2e971d, 0xe9cbae20, + 0x72b844f4, 0x072f15a8, 0x9c5cff7c, 0xeab9c641, 0x71ca2c95, + 0x0773b43b, 0x9c005eef, 0xeae567d2, 0x71968d06, 0x0796568e, + 0x9ce5bc5a, 0xea008567, 0x71736fb3, 0x07caf71d, 0x9cb91dc9, + 0xea5c24f4, 0x712fce20, 0x065d93e4, 0x9d2e7930, 0xebcb400d, + 0x70b8aad9, 0x06013277, 0x9d72d8a3, 0xeb97e19e, 0x70e40b4a, + 0x06e4d0c2, 0x9d973a16, 0xeb72032b, 0x7001e9ff, 0x06b87151, + 0x9dcb9b85, 0xeb2ea2b8, 0x705d486c, 0x0b943260, 0x90e7d8b4, + 0xe602e189, 0x7d710b5d, 0x0bc893f3, 0x90bb7927, 0xe65e401a, + 0x7d2daace, 0x0b2d7146, 0x905e9b92, 0xe6bba2af, 0x7dc8487b, + 0x0b71d0d5, 0x90023a01, 0xe6e7033c, 0x7d94e9e8, 0x0ae6b42c, + 0x91955ef8, 0xe77067c5, 0x7c038d11, 0x0aba15bf, 0x91c9ff6b, + 0xe72cc656, 0x7c5f2c82, 0x0a5ff70a, 0x912c1dde, 0xe7c924e3, + 0x7cbace37, 0x0a035699, 0x9170bc4d, 0xe7958570, 0x7ce66fa4, + 0x09713ef8, 0x9202d42c, 0xe4e7ed11, 0x7f9407c5, 0x092d9f6b, + 0x925e75bf, 0xe4bb4c82, 0x7fc8a656, 0x09c87dde, 0x92bb970a, + 0xe45eae37, 0x7f2d44e3, 0x0994dc4d, 0x92e73699, 0xe4020fa4, + 0x7f71e570, 0x0803b8b4, 0x93705260, 0xe5956b5d, 0x7ee68189, + 0x085f1927, 0x932cf3f3, 0xe5c9cace, 0x7eba201a, 0x08bafb92, + 0x93c91146, 0xe52c287b, 0x7e5fc2af, 0x08e65a01, 0x9395b0d5, + 0xe57089e8, 0x7e03633c, 0x0e5e2b50, 0x952dc184, 0xe3c8f8b9, + 0x78bb126d, 0x0e028ac3, 0x95716017, 0xe394592a, 0x78e7b3fe, + 0x0ee76876, 0x959482a2, 0xe371bb9f, 0x7802514b, 0x0ebbc9e5, + 0x95c82331, 0xe32d1a0c, 0x785ef0d8, 0x0f2cad1c, 0x945f47c8, + 0xe2ba7ef5, 0x79c99421, 0x0f700c8f, 0x9403e65b, 0xe2e6df66, + 0x799535b2, 0x0f95ee3a, 0x94e604ee, 0xe2033dd3, 0x7970d707, + 0x0fc94fa9, 0x94baa57d, 0xe25f9c40, 0x792c7694, 0x0cbb27c8, + 0x97c8cd1c, 0xe12df421, 0x7a5e1ef5, 0x0ce7865b, 0x97946c8f, + 0xe17155b2, 0x7a02bf66, 0x0c0264ee, 0x97718e3a, 0xe194b707, + 0x7ae75dd3, 0x0c5ec57d, 0x972d2fa9, 0xe1c81694, 0x7abbfc40, + 0x0dc9a184, 0x96ba4b50, 0xe05f726d, 0x7b2c98b9, 0x0d950017, + 0x96e6eac3, 0xe003d3fe, 0x7b70392a, 0x0d70e2a2, 0x96030876, + 0xe0e6314b, 0x7b95db9f, 0x0d2c4331, 0x965fa9e5, 0xe0ba90d8, + 0x7bc97a0c}, + {0x00000000, 0x172864c0, 0x2e50c980, 0x3978ad40, 0x5ca19300, + 0x4b89f7c0, 0x72f15a80, 0x65d93e40, 0xb9432600, 0xae6b42c0, + 0x9713ef80, 0x803b8b40, 0xe5e2b500, 0xf2cad1c0, 0xcbb27c80, + 0xdc9a1840, 0xa9f74a41, 0xbedf2e81, 0x87a783c1, 0x908fe701, + 0xf556d941, 0xe27ebd81, 0xdb0610c1, 0xcc2e7401, 0x10b46c41, + 0x079c0881, 0x3ee4a5c1, 0x29ccc101, 0x4c15ff41, 0x5b3d9b81, + 0x624536c1, 0x756d5201, 0x889f92c3, 0x9fb7f603, 0xa6cf5b43, + 0xb1e73f83, 0xd43e01c3, 0xc3166503, 0xfa6ec843, 0xed46ac83, + 0x31dcb4c3, 0x26f4d003, 0x1f8c7d43, 0x08a41983, 0x6d7d27c3, + 0x7a554303, 0x432dee43, 0x54058a83, 0x2168d882, 0x3640bc42, + 0x0f381102, 0x181075c2, 0x7dc94b82, 0x6ae12f42, 0x53998202, + 0x44b1e6c2, 0x982bfe82, 0x8f039a42, 0xb67b3702, 0xa15353c2, + 0xc48a6d82, 0xd3a20942, 0xeadaa402, 0xfdf2c0c2, 0xca4e23c7, + 0xdd664707, 0xe41eea47, 0xf3368e87, 0x96efb0c7, 0x81c7d407, + 0xb8bf7947, 0xaf971d87, 0x730d05c7, 0x64256107, 0x5d5dcc47, + 0x4a75a887, 0x2fac96c7, 0x3884f207, 0x01fc5f47, 0x16d43b87, + 0x63b96986, 0x74910d46, 0x4de9a006, 0x5ac1c4c6, 0x3f18fa86, + 0x28309e46, 0x11483306, 0x066057c6, 0xdafa4f86, 0xcdd22b46, + 0xf4aa8606, 0xe382e2c6, 0x865bdc86, 0x9173b846, 0xa80b1506, + 0xbf2371c6, 0x42d1b104, 0x55f9d5c4, 0x6c817884, 0x7ba91c44, + 0x1e702204, 0x095846c4, 0x3020eb84, 0x27088f44, 0xfb929704, + 0xecbaf3c4, 0xd5c25e84, 0xc2ea3a44, 0xa7330404, 0xb01b60c4, + 0x8963cd84, 0x9e4ba944, 0xeb26fb45, 0xfc0e9f85, 0xc57632c5, + 0xd25e5605, 0xb7876845, 0xa0af0c85, 0x99d7a1c5, 0x8effc505, + 0x5265dd45, 0x454db985, 0x7c3514c5, 0x6b1d7005, 0x0ec44e45, + 0x19ec2a85, 0x209487c5, 0x37bce305, 0x4fed41cf, 0x58c5250f, + 0x61bd884f, 0x7695ec8f, 0x134cd2cf, 0x0464b60f, 0x3d1c1b4f, + 0x2a347f8f, 0xf6ae67cf, 0xe186030f, 0xd8feae4f, 0xcfd6ca8f, + 0xaa0ff4cf, 0xbd27900f, 0x845f3d4f, 0x9377598f, 0xe61a0b8e, + 0xf1326f4e, 0xc84ac20e, 0xdf62a6ce, 0xbabb988e, 0xad93fc4e, + 0x94eb510e, 0x83c335ce, 0x5f592d8e, 0x4871494e, 0x7109e40e, + 0x662180ce, 0x03f8be8e, 0x14d0da4e, 0x2da8770e, 0x3a8013ce, + 0xc772d30c, 0xd05ab7cc, 0xe9221a8c, 0xfe0a7e4c, 0x9bd3400c, + 0x8cfb24cc, 0xb583898c, 0xa2abed4c, 0x7e31f50c, 0x691991cc, + 0x50613c8c, 0x4749584c, 0x2290660c, 0x35b802cc, 0x0cc0af8c, + 0x1be8cb4c, 0x6e85994d, 0x79adfd8d, 0x40d550cd, 0x57fd340d, + 0x32240a4d, 0x250c6e8d, 0x1c74c3cd, 0x0b5ca70d, 0xd7c6bf4d, + 0xc0eedb8d, 0xf99676cd, 0xeebe120d, 0x8b672c4d, 0x9c4f488d, + 0xa537e5cd, 0xb21f810d, 0x85a36208, 0x928b06c8, 0xabf3ab88, + 0xbcdbcf48, 0xd902f108, 0xce2a95c8, 0xf7523888, 0xe07a5c48, + 0x3ce04408, 0x2bc820c8, 0x12b08d88, 0x0598e948, 0x6041d708, + 0x7769b3c8, 0x4e111e88, 0x59397a48, 0x2c542849, 0x3b7c4c89, + 0x0204e1c9, 0x152c8509, 0x70f5bb49, 0x67dddf89, 0x5ea572c9, + 0x498d1609, 0x95170e49, 0x823f6a89, 0xbb47c7c9, 0xac6fa309, + 0xc9b69d49, 0xde9ef989, 0xe7e654c9, 0xf0ce3009, 0x0d3cf0cb, + 0x1a14940b, 0x236c394b, 0x34445d8b, 0x519d63cb, 0x46b5070b, + 0x7fcdaa4b, 0x68e5ce8b, 0xb47fd6cb, 0xa357b20b, 0x9a2f1f4b, + 0x8d077b8b, 0xe8de45cb, 0xfff6210b, 0xc68e8c4b, 0xd1a6e88b, + 0xa4cbba8a, 0xb3e3de4a, 0x8a9b730a, 0x9db317ca, 0xf86a298a, + 0xef424d4a, 0xd63ae00a, 0xc11284ca, 0x1d889c8a, 0x0aa0f84a, + 0x33d8550a, 0x24f031ca, 0x41290f8a, 0x56016b4a, 0x6f79c60a, + 0x7851a2ca}, + {0x00000000, 0x9fda839e, 0xe4c4017d, 0x7b1e82e3, 0x12f904bb, + 0x8d238725, 0xf63d05c6, 0x69e78658, 0x25f20976, 0xba288ae8, + 0xc136080b, 0x5eec8b95, 0x370b0dcd, 0xa8d18e53, 0xd3cf0cb0, + 0x4c158f2e, 0x4be412ec, 0xd43e9172, 0xaf201391, 0x30fa900f, + 0x591d1657, 0xc6c795c9, 0xbdd9172a, 0x220394b4, 0x6e161b9a, + 0xf1cc9804, 0x8ad21ae7, 0x15089979, 0x7cef1f21, 0xe3359cbf, + 0x982b1e5c, 0x07f19dc2, 0x97c825d8, 0x0812a646, 0x730c24a5, + 0xecd6a73b, 0x85312163, 0x1aeba2fd, 0x61f5201e, 0xfe2fa380, + 0xb23a2cae, 0x2de0af30, 0x56fe2dd3, 0xc924ae4d, 0xa0c32815, + 0x3f19ab8b, 0x44072968, 0xdbddaaf6, 0xdc2c3734, 0x43f6b4aa, + 0x38e83649, 0xa732b5d7, 0xced5338f, 0x510fb011, 0x2a1132f2, + 0xb5cbb16c, 0xf9de3e42, 0x6604bddc, 0x1d1a3f3f, 0x82c0bca1, + 0xeb273af9, 0x74fdb967, 0x0fe33b84, 0x9039b81a, 0xf4e14df1, + 0x6b3bce6f, 0x10254c8c, 0x8fffcf12, 0xe618494a, 0x79c2cad4, + 0x02dc4837, 0x9d06cba9, 0xd1134487, 0x4ec9c719, 0x35d745fa, + 0xaa0dc664, 0xc3ea403c, 0x5c30c3a2, 0x272e4141, 0xb8f4c2df, + 0xbf055f1d, 0x20dfdc83, 0x5bc15e60, 0xc41bddfe, 0xadfc5ba6, + 0x3226d838, 0x49385adb, 0xd6e2d945, 0x9af7566b, 0x052dd5f5, + 0x7e335716, 0xe1e9d488, 0x880e52d0, 0x17d4d14e, 0x6cca53ad, + 0xf310d033, 0x63296829, 0xfcf3ebb7, 0x87ed6954, 0x1837eaca, + 0x71d06c92, 0xee0aef0c, 0x95146def, 0x0aceee71, 0x46db615f, + 0xd901e2c1, 0xa21f6022, 0x3dc5e3bc, 0x542265e4, 0xcbf8e67a, + 0xb0e66499, 0x2f3ce707, 0x28cd7ac5, 0xb717f95b, 0xcc097bb8, + 0x53d3f826, 0x3a347e7e, 0xa5eefde0, 0xdef07f03, 0x412afc9d, + 0x0d3f73b3, 0x92e5f02d, 0xe9fb72ce, 0x7621f150, 0x1fc67708, + 0x801cf496, 0xfb027675, 0x64d8f5eb, 0x32b39da3, 0xad691e3d, + 0xd6779cde, 0x49ad1f40, 0x204a9918, 0xbf901a86, 0xc48e9865, + 0x5b541bfb, 0x174194d5, 0x889b174b, 0xf38595a8, 0x6c5f1636, + 0x05b8906e, 0x9a6213f0, 0xe17c9113, 0x7ea6128d, 0x79578f4f, + 0xe68d0cd1, 0x9d938e32, 0x02490dac, 0x6bae8bf4, 0xf474086a, + 0x8f6a8a89, 0x10b00917, 0x5ca58639, 0xc37f05a7, 0xb8618744, + 0x27bb04da, 0x4e5c8282, 0xd186011c, 0xaa9883ff, 0x35420061, + 0xa57bb87b, 0x3aa13be5, 0x41bfb906, 0xde653a98, 0xb782bcc0, + 0x28583f5e, 0x5346bdbd, 0xcc9c3e23, 0x8089b10d, 0x1f533293, + 0x644db070, 0xfb9733ee, 0x9270b5b6, 0x0daa3628, 0x76b4b4cb, + 0xe96e3755, 0xee9faa97, 0x71452909, 0x0a5babea, 0x95812874, + 0xfc66ae2c, 0x63bc2db2, 0x18a2af51, 0x87782ccf, 0xcb6da3e1, + 0x54b7207f, 0x2fa9a29c, 0xb0732102, 0xd994a75a, 0x464e24c4, + 0x3d50a627, 0xa28a25b9, 0xc652d052, 0x598853cc, 0x2296d12f, + 0xbd4c52b1, 0xd4abd4e9, 0x4b715777, 0x306fd594, 0xafb5560a, + 0xe3a0d924, 0x7c7a5aba, 0x0764d859, 0x98be5bc7, 0xf159dd9f, + 0x6e835e01, 0x159ddce2, 0x8a475f7c, 0x8db6c2be, 0x126c4120, + 0x6972c3c3, 0xf6a8405d, 0x9f4fc605, 0x0095459b, 0x7b8bc778, + 0xe45144e6, 0xa844cbc8, 0x379e4856, 0x4c80cab5, 0xd35a492b, + 0xbabdcf73, 0x25674ced, 0x5e79ce0e, 0xc1a34d90, 0x519af58a, + 0xce407614, 0xb55ef4f7, 0x2a847769, 0x4363f131, 0xdcb972af, + 0xa7a7f04c, 0x387d73d2, 0x7468fcfc, 0xebb27f62, 0x90acfd81, + 0x0f767e1f, 0x6691f847, 0xf94b7bd9, 0x8255f93a, 0x1d8f7aa4, + 0x1a7ee766, 0x85a464f8, 0xfebae61b, 0x61606585, 0x0887e3dd, + 0x975d6043, 0xec43e2a0, 0x7399613e, 0x3f8cee10, 0xa0566d8e, + 0xdb48ef6d, 0x44926cf3, 0x2d75eaab, 0xb2af6935, 0xc9b1ebd6, + 0x566b6848}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x9e83da9f, 0x7d01c4e4, 0xe3821e7b, 0xbb04f912, + 0x2587238d, 0xc6053df6, 0x5886e769, 0x7609f225, 0xe88a28ba, + 0x0b0836c1, 0x958bec5e, 0xcd0d0b37, 0x538ed1a8, 0xb00ccfd3, + 0x2e8f154c, 0xec12e44b, 0x72913ed4, 0x911320af, 0x0f90fa30, + 0x57161d59, 0xc995c7c6, 0x2a17d9bd, 0xb4940322, 0x9a1b166e, + 0x0498ccf1, 0xe71ad28a, 0x79990815, 0x211fef7c, 0xbf9c35e3, + 0x5c1e2b98, 0xc29df107, 0xd825c897, 0x46a61208, 0xa5240c73, + 0x3ba7d6ec, 0x63213185, 0xfda2eb1a, 0x1e20f561, 0x80a32ffe, + 0xae2c3ab2, 0x30afe02d, 0xd32dfe56, 0x4dae24c9, 0x1528c3a0, + 0x8bab193f, 0x68290744, 0xf6aadddb, 0x34372cdc, 0xaab4f643, + 0x4936e838, 0xd7b532a7, 0x8f33d5ce, 0x11b00f51, 0xf232112a, + 0x6cb1cbb5, 0x423edef9, 0xdcbd0466, 0x3f3f1a1d, 0xa1bcc082, + 0xf93a27eb, 0x67b9fd74, 0x843be30f, 0x1ab83990, 0xf14de1f4, + 0x6fce3b6b, 0x8c4c2510, 0x12cfff8f, 0x4a4918e6, 0xd4cac279, + 0x3748dc02, 0xa9cb069d, 0x874413d1, 0x19c7c94e, 0xfa45d735, + 0x64c60daa, 0x3c40eac3, 0xa2c3305c, 0x41412e27, 0xdfc2f4b8, + 0x1d5f05bf, 0x83dcdf20, 0x605ec15b, 0xfedd1bc4, 0xa65bfcad, + 0x38d82632, 0xdb5a3849, 0x45d9e2d6, 0x6b56f79a, 0xf5d52d05, + 0x1657337e, 0x88d4e9e1, 0xd0520e88, 0x4ed1d417, 0xad53ca6c, + 0x33d010f3, 0x29682963, 0xb7ebf3fc, 0x5469ed87, 0xcaea3718, + 0x926cd071, 0x0cef0aee, 0xef6d1495, 0x71eece0a, 0x5f61db46, + 0xc1e201d9, 0x22601fa2, 0xbce3c53d, 0xe4652254, 0x7ae6f8cb, + 0x9964e6b0, 0x07e73c2f, 0xc57acd28, 0x5bf917b7, 0xb87b09cc, + 0x26f8d353, 0x7e7e343a, 0xe0fdeea5, 0x037ff0de, 0x9dfc2a41, + 0xb3733f0d, 0x2df0e592, 0xce72fbe9, 0x50f12176, 0x0877c61f, + 0x96f41c80, 0x757602fb, 0xebf5d864, 0xa39db332, 0x3d1e69ad, + 0xde9c77d6, 0x401fad49, 0x18994a20, 0x861a90bf, 0x65988ec4, + 0xfb1b545b, 0xd5944117, 0x4b179b88, 0xa89585f3, 0x36165f6c, + 0x6e90b805, 0xf013629a, 0x13917ce1, 0x8d12a67e, 0x4f8f5779, + 0xd10c8de6, 0x328e939d, 0xac0d4902, 0xf48bae6b, 0x6a0874f4, + 0x898a6a8f, 0x1709b010, 0x3986a55c, 0xa7057fc3, 0x448761b8, + 0xda04bb27, 0x82825c4e, 0x1c0186d1, 0xff8398aa, 0x61004235, + 0x7bb87ba5, 0xe53ba13a, 0x06b9bf41, 0x983a65de, 0xc0bc82b7, + 0x5e3f5828, 0xbdbd4653, 0x233e9ccc, 0x0db18980, 0x9332531f, + 0x70b04d64, 0xee3397fb, 0xb6b57092, 0x2836aa0d, 0xcbb4b476, + 0x55376ee9, 0x97aa9fee, 0x09294571, 0xeaab5b0a, 0x74288195, + 0x2cae66fc, 0xb22dbc63, 0x51afa218, 0xcf2c7887, 0xe1a36dcb, + 0x7f20b754, 0x9ca2a92f, 0x022173b0, 0x5aa794d9, 0xc4244e46, + 0x27a6503d, 0xb9258aa2, 0x52d052c6, 0xcc538859, 0x2fd19622, + 0xb1524cbd, 0xe9d4abd4, 0x7757714b, 0x94d56f30, 0x0a56b5af, + 0x24d9a0e3, 0xba5a7a7c, 0x59d86407, 0xc75bbe98, 0x9fdd59f1, + 0x015e836e, 0xe2dc9d15, 0x7c5f478a, 0xbec2b68d, 0x20416c12, + 0xc3c37269, 0x5d40a8f6, 0x05c64f9f, 0x9b459500, 0x78c78b7b, + 0xe64451e4, 0xc8cb44a8, 0x56489e37, 0xb5ca804c, 0x2b495ad3, + 0x73cfbdba, 0xed4c6725, 0x0ece795e, 0x904da3c1, 0x8af59a51, + 0x147640ce, 0xf7f45eb5, 0x6977842a, 0x31f16343, 0xaf72b9dc, + 0x4cf0a7a7, 0xd2737d38, 0xfcfc6874, 0x627fb2eb, 0x81fdac90, + 0x1f7e760f, 0x47f89166, 0xd97b4bf9, 0x3af95582, 0xa47a8f1d, + 0x66e77e1a, 0xf864a485, 0x1be6bafe, 0x85656061, 0xdde38708, + 0x43605d97, 0xa0e243ec, 0x3e619973, 0x10ee8c3f, 0x8e6d56a0, + 0x6def48db, 0xf36c9244, 0xabea752d, 0x3569afb2, 0xd6ebb1c9, + 0x48686b56}, + {0x00000000, 0xc0642817, 0x80c9502e, 0x40ad7839, 0x0093a15c, + 0xc0f7894b, 0x805af172, 0x403ed965, 0x002643b9, 0xc0426bae, + 0x80ef1397, 0x408b3b80, 0x00b5e2e5, 0xc0d1caf2, 0x807cb2cb, + 0x40189adc, 0x414af7a9, 0x812edfbe, 0xc183a787, 0x01e78f90, + 0x41d956f5, 0x81bd7ee2, 0xc11006db, 0x01742ecc, 0x416cb410, + 0x81089c07, 0xc1a5e43e, 0x01c1cc29, 0x41ff154c, 0x819b3d5b, + 0xc1364562, 0x01526d75, 0xc3929f88, 0x03f6b79f, 0x435bcfa6, + 0x833fe7b1, 0xc3013ed4, 0x036516c3, 0x43c86efa, 0x83ac46ed, + 0xc3b4dc31, 0x03d0f426, 0x437d8c1f, 0x8319a408, 0xc3277d6d, + 0x0343557a, 0x43ee2d43, 0x838a0554, 0x82d86821, 0x42bc4036, + 0x0211380f, 0xc2751018, 0x824bc97d, 0x422fe16a, 0x02829953, + 0xc2e6b144, 0x82fe2b98, 0x429a038f, 0x02377bb6, 0xc25353a1, + 0x826d8ac4, 0x4209a2d3, 0x02a4daea, 0xc2c0f2fd, 0xc7234eca, + 0x074766dd, 0x47ea1ee4, 0x878e36f3, 0xc7b0ef96, 0x07d4c781, + 0x4779bfb8, 0x871d97af, 0xc7050d73, 0x07612564, 0x47cc5d5d, + 0x87a8754a, 0xc796ac2f, 0x07f28438, 0x475ffc01, 0x873bd416, + 0x8669b963, 0x460d9174, 0x06a0e94d, 0xc6c4c15a, 0x86fa183f, + 0x469e3028, 0x06334811, 0xc6576006, 0x864ffada, 0x462bd2cd, + 0x0686aaf4, 0xc6e282e3, 0x86dc5b86, 0x46b87391, 0x06150ba8, + 0xc67123bf, 0x04b1d142, 0xc4d5f955, 0x8478816c, 0x441ca97b, + 0x0422701e, 0xc4465809, 0x84eb2030, 0x448f0827, 0x049792fb, + 0xc4f3baec, 0x845ec2d5, 0x443aeac2, 0x040433a7, 0xc4601bb0, + 0x84cd6389, 0x44a94b9e, 0x45fb26eb, 0x859f0efc, 0xc53276c5, + 0x05565ed2, 0x456887b7, 0x850cafa0, 0xc5a1d799, 0x05c5ff8e, + 0x45dd6552, 0x85b94d45, 0xc514357c, 0x05701d6b, 0x454ec40e, + 0x852aec19, 0xc5879420, 0x05e3bc37, 0xcf41ed4f, 0x0f25c558, + 0x4f88bd61, 0x8fec9576, 0xcfd24c13, 0x0fb66404, 0x4f1b1c3d, + 0x8f7f342a, 0xcf67aef6, 0x0f0386e1, 0x4faefed8, 0x8fcad6cf, + 0xcff40faa, 0x0f9027bd, 0x4f3d5f84, 0x8f597793, 0x8e0b1ae6, + 0x4e6f32f1, 0x0ec24ac8, 0xcea662df, 0x8e98bbba, 0x4efc93ad, + 0x0e51eb94, 0xce35c383, 0x8e2d595f, 0x4e497148, 0x0ee40971, + 0xce802166, 0x8ebef803, 0x4edad014, 0x0e77a82d, 0xce13803a, + 0x0cd372c7, 0xccb75ad0, 0x8c1a22e9, 0x4c7e0afe, 0x0c40d39b, + 0xcc24fb8c, 0x8c8983b5, 0x4cedaba2, 0x0cf5317e, 0xcc911969, + 0x8c3c6150, 0x4c584947, 0x0c669022, 0xcc02b835, 0x8cafc00c, + 0x4ccbe81b, 0x4d99856e, 0x8dfdad79, 0xcd50d540, 0x0d34fd57, + 0x4d0a2432, 0x8d6e0c25, 0xcdc3741c, 0x0da75c0b, 0x4dbfc6d7, + 0x8ddbeec0, 0xcd7696f9, 0x0d12beee, 0x4d2c678b, 0x8d484f9c, + 0xcde537a5, 0x0d811fb2, 0x0862a385, 0xc8068b92, 0x88abf3ab, + 0x48cfdbbc, 0x08f102d9, 0xc8952ace, 0x883852f7, 0x485c7ae0, + 0x0844e03c, 0xc820c82b, 0x888db012, 0x48e99805, 0x08d74160, + 0xc8b36977, 0x881e114e, 0x487a3959, 0x4928542c, 0x894c7c3b, + 0xc9e10402, 0x09852c15, 0x49bbf570, 0x89dfdd67, 0xc972a55e, + 0x09168d49, 0x490e1795, 0x896a3f82, 0xc9c747bb, 0x09a36fac, + 0x499db6c9, 0x89f99ede, 0xc954e6e7, 0x0930cef0, 0xcbf03c0d, + 0x0b94141a, 0x4b396c23, 0x8b5d4434, 0xcb639d51, 0x0b07b546, + 0x4baacd7f, 0x8bcee568, 0xcbd67fb4, 0x0bb257a3, 0x4b1f2f9a, + 0x8b7b078d, 0xcb45dee8, 0x0b21f6ff, 0x4b8c8ec6, 0x8be8a6d1, + 0x8abacba4, 0x4adee3b3, 0x0a739b8a, 0xca17b39d, 0x8a296af8, + 0x4a4d42ef, 0x0ae03ad6, 0xca8412c1, 0x8a9c881d, 0x4af8a00a, + 0x0a55d833, 0xca31f024, 0x8a0f2941, 0x4a6b0156, 0x0ac6796f, + 0xcaa25178}, + {0x00000000, 0xd4ea739b, 0xe9d396ed, 0x3d39e576, 0x93a15c00, + 0x474b2f9b, 0x7a72caed, 0xae98b976, 0x2643b900, 0xf2a9ca9b, + 0xcf902fed, 0x1b7a5c76, 0xb5e2e500, 0x6108969b, 0x5c3173ed, + 0x88db0076, 0x4c867201, 0x986c019a, 0xa555e4ec, 0x71bf9777, + 0xdf272e01, 0x0bcd5d9a, 0x36f4b8ec, 0xe21ecb77, 0x6ac5cb01, + 0xbe2fb89a, 0x83165dec, 0x57fc2e77, 0xf9649701, 0x2d8ee49a, + 0x10b701ec, 0xc45d7277, 0x980ce502, 0x4ce69699, 0x71df73ef, + 0xa5350074, 0x0badb902, 0xdf47ca99, 0xe27e2fef, 0x36945c74, + 0xbe4f5c02, 0x6aa52f99, 0x579ccaef, 0x8376b974, 0x2dee0002, + 0xf9047399, 0xc43d96ef, 0x10d7e574, 0xd48a9703, 0x0060e498, + 0x3d5901ee, 0xe9b37275, 0x472bcb03, 0x93c1b898, 0xaef85dee, + 0x7a122e75, 0xf2c92e03, 0x26235d98, 0x1b1ab8ee, 0xcff0cb75, + 0x61687203, 0xb5820198, 0x88bbe4ee, 0x5c519775, 0x3019ca05, + 0xe4f3b99e, 0xd9ca5ce8, 0x0d202f73, 0xa3b89605, 0x7752e59e, + 0x4a6b00e8, 0x9e817373, 0x165a7305, 0xc2b0009e, 0xff89e5e8, + 0x2b639673, 0x85fb2f05, 0x51115c9e, 0x6c28b9e8, 0xb8c2ca73, + 0x7c9fb804, 0xa875cb9f, 0x954c2ee9, 0x41a65d72, 0xef3ee404, + 0x3bd4979f, 0x06ed72e9, 0xd2070172, 0x5adc0104, 0x8e36729f, + 0xb30f97e9, 0x67e5e472, 0xc97d5d04, 0x1d972e9f, 0x20aecbe9, + 0xf444b872, 0xa8152f07, 0x7cff5c9c, 0x41c6b9ea, 0x952cca71, + 0x3bb47307, 0xef5e009c, 0xd267e5ea, 0x068d9671, 0x8e569607, + 0x5abce59c, 0x678500ea, 0xb36f7371, 0x1df7ca07, 0xc91db99c, + 0xf4245cea, 0x20ce2f71, 0xe4935d06, 0x30792e9d, 0x0d40cbeb, + 0xd9aab870, 0x77320106, 0xa3d8729d, 0x9ee197eb, 0x4a0be470, + 0xc2d0e406, 0x163a979d, 0x2b0372eb, 0xffe90170, 0x5171b806, + 0x859bcb9d, 0xb8a22eeb, 0x6c485d70, 0x6032940b, 0xb4d8e790, + 0x89e102e6, 0x5d0b717d, 0xf393c80b, 0x2779bb90, 0x1a405ee6, + 0xceaa2d7d, 0x46712d0b, 0x929b5e90, 0xafa2bbe6, 0x7b48c87d, + 0xd5d0710b, 0x013a0290, 0x3c03e7e6, 0xe8e9947d, 0x2cb4e60a, + 0xf85e9591, 0xc56770e7, 0x118d037c, 0xbf15ba0a, 0x6bffc991, + 0x56c62ce7, 0x822c5f7c, 0x0af75f0a, 0xde1d2c91, 0xe324c9e7, + 0x37ceba7c, 0x9956030a, 0x4dbc7091, 0x708595e7, 0xa46fe67c, + 0xf83e7109, 0x2cd40292, 0x11ede7e4, 0xc507947f, 0x6b9f2d09, + 0xbf755e92, 0x824cbbe4, 0x56a6c87f, 0xde7dc809, 0x0a97bb92, + 0x37ae5ee4, 0xe3442d7f, 0x4ddc9409, 0x9936e792, 0xa40f02e4, + 0x70e5717f, 0xb4b80308, 0x60527093, 0x5d6b95e5, 0x8981e67e, + 0x27195f08, 0xf3f32c93, 0xcecac9e5, 0x1a20ba7e, 0x92fbba08, + 0x4611c993, 0x7b282ce5, 0xafc25f7e, 0x015ae608, 0xd5b09593, + 0xe88970e5, 0x3c63037e, 0x502b5e0e, 0x84c12d95, 0xb9f8c8e3, + 0x6d12bb78, 0xc38a020e, 0x17607195, 0x2a5994e3, 0xfeb3e778, + 0x7668e70e, 0xa2829495, 0x9fbb71e3, 0x4b510278, 0xe5c9bb0e, + 0x3123c895, 0x0c1a2de3, 0xd8f05e78, 0x1cad2c0f, 0xc8475f94, + 0xf57ebae2, 0x2194c979, 0x8f0c700f, 0x5be60394, 0x66dfe6e2, + 0xb2359579, 0x3aee950f, 0xee04e694, 0xd33d03e2, 0x07d77079, + 0xa94fc90f, 0x7da5ba94, 0x409c5fe2, 0x94762c79, 0xc827bb0c, + 0x1ccdc897, 0x21f42de1, 0xf51e5e7a, 0x5b86e70c, 0x8f6c9497, + 0xb25571e1, 0x66bf027a, 0xee64020c, 0x3a8e7197, 0x07b794e1, + 0xd35de77a, 0x7dc55e0c, 0xa92f2d97, 0x9416c8e1, 0x40fcbb7a, + 0x84a1c90d, 0x504bba96, 0x6d725fe0, 0xb9982c7b, 0x1700950d, + 0xc3eae696, 0xfed303e0, 0x2a39707b, 0xa2e2700d, 0x76080396, + 0x4b31e6e0, 0x9fdb957b, 0x31432c0d, 0xe5a95f96, 0xd890bae0, + 0x0c7ac97b}, + {0x00000000, 0x27652581, 0x0fcc3bd9, 0x28a91e58, 0x5f9e0669, + 0x78fb23e8, 0x50523db0, 0x77371831, 0xbe3c0dd2, 0x99592853, + 0xb1f0360b, 0x9695138a, 0xe1a20bbb, 0xc6c72e3a, 0xee6e3062, + 0xc90b15e3, 0x3d7f6b7f, 0x1a1a4efe, 0x32b350a6, 0x15d67527, + 0x62e16d16, 0x45844897, 0x6d2d56cf, 0x4a48734e, 0x834366ad, + 0xa426432c, 0x8c8f5d74, 0xabea78f5, 0xdcdd60c4, 0xfbb84545, + 0xd3115b1d, 0xf4747e9c, 0x7afed6fe, 0x5d9bf37f, 0x7532ed27, + 0x5257c8a6, 0x2560d097, 0x0205f516, 0x2aaceb4e, 0x0dc9cecf, + 0xc4c2db2c, 0xe3a7fead, 0xcb0ee0f5, 0xec6bc574, 0x9b5cdd45, + 0xbc39f8c4, 0x9490e69c, 0xb3f5c31d, 0x4781bd81, 0x60e49800, + 0x484d8658, 0x6f28a3d9, 0x181fbbe8, 0x3f7a9e69, 0x17d38031, + 0x30b6a5b0, 0xf9bdb053, 0xded895d2, 0xf6718b8a, 0xd114ae0b, + 0xa623b63a, 0x814693bb, 0xa9ef8de3, 0x8e8aa862, 0xb5fadc26, + 0x929ff9a7, 0xba36e7ff, 0x9d53c27e, 0xea64da4f, 0xcd01ffce, + 0xe5a8e196, 0xc2cdc417, 0x0bc6d1f4, 0x2ca3f475, 0x040aea2d, + 0x236fcfac, 0x5458d79d, 0x733df21c, 0x5b94ec44, 0x7cf1c9c5, + 0x8885b759, 0xafe092d8, 0x87498c80, 0xa02ca901, 0xd71bb130, + 0xf07e94b1, 0xd8d78ae9, 0xffb2af68, 0x36b9ba8b, 0x11dc9f0a, + 0x39758152, 0x1e10a4d3, 0x6927bce2, 0x4e429963, 0x66eb873b, + 0x418ea2ba, 0xcf040ad8, 0xe8612f59, 0xc0c83101, 0xe7ad1480, + 0x909a0cb1, 0xb7ff2930, 0x9f563768, 0xb83312e9, 0x7138070a, + 0x565d228b, 0x7ef43cd3, 0x59911952, 0x2ea60163, 0x09c324e2, + 0x216a3aba, 0x060f1f3b, 0xf27b61a7, 0xd51e4426, 0xfdb75a7e, + 0xdad27fff, 0xade567ce, 0x8a80424f, 0xa2295c17, 0x854c7996, + 0x4c476c75, 0x6b2249f4, 0x438b57ac, 0x64ee722d, 0x13d96a1c, + 0x34bc4f9d, 0x1c1551c5, 0x3b707444, 0x6af5b94d, 0x4d909ccc, + 0x65398294, 0x425ca715, 0x356bbf24, 0x120e9aa5, 0x3aa784fd, + 0x1dc2a17c, 0xd4c9b49f, 0xf3ac911e, 0xdb058f46, 0xfc60aac7, + 0x8b57b2f6, 0xac329777, 0x849b892f, 0xa3feacae, 0x578ad232, + 0x70eff7b3, 0x5846e9eb, 0x7f23cc6a, 0x0814d45b, 0x2f71f1da, + 0x07d8ef82, 0x20bdca03, 0xe9b6dfe0, 0xced3fa61, 0xe67ae439, + 0xc11fc1b8, 0xb628d989, 0x914dfc08, 0xb9e4e250, 0x9e81c7d1, + 0x100b6fb3, 0x376e4a32, 0x1fc7546a, 0x38a271eb, 0x4f9569da, + 0x68f04c5b, 0x40595203, 0x673c7782, 0xae376261, 0x895247e0, + 0xa1fb59b8, 0x869e7c39, 0xf1a96408, 0xd6cc4189, 0xfe655fd1, + 0xd9007a50, 0x2d7404cc, 0x0a11214d, 0x22b83f15, 0x05dd1a94, + 0x72ea02a5, 0x558f2724, 0x7d26397c, 0x5a431cfd, 0x9348091e, + 0xb42d2c9f, 0x9c8432c7, 0xbbe11746, 0xccd60f77, 0xebb32af6, + 0xc31a34ae, 0xe47f112f, 0xdf0f656b, 0xf86a40ea, 0xd0c35eb2, + 0xf7a67b33, 0x80916302, 0xa7f44683, 0x8f5d58db, 0xa8387d5a, + 0x613368b9, 0x46564d38, 0x6eff5360, 0x499a76e1, 0x3ead6ed0, + 0x19c84b51, 0x31615509, 0x16047088, 0xe2700e14, 0xc5152b95, + 0xedbc35cd, 0xcad9104c, 0xbdee087d, 0x9a8b2dfc, 0xb22233a4, + 0x95471625, 0x5c4c03c6, 0x7b292647, 0x5380381f, 0x74e51d9e, + 0x03d205af, 0x24b7202e, 0x0c1e3e76, 0x2b7b1bf7, 0xa5f1b395, + 0x82949614, 0xaa3d884c, 0x8d58adcd, 0xfa6fb5fc, 0xdd0a907d, + 0xf5a38e25, 0xd2c6aba4, 0x1bcdbe47, 0x3ca89bc6, 0x1401859e, + 0x3364a01f, 0x4453b82e, 0x63369daf, 0x4b9f83f7, 0x6cfaa676, + 0x988ed8ea, 0xbfebfd6b, 0x9742e333, 0xb027c6b2, 0xc710de83, + 0xe075fb02, 0xc8dce55a, 0xefb9c0db, 0x26b2d538, 0x01d7f0b9, + 0x297eeee1, 0x0e1bcb60, 0x792cd351, 0x5e49f6d0, 0x76e0e888, + 0x5185cd09}}; + +#endif + +#endif + +#endif + +local const z_crc_t FAR x2n_table[] = { + 0x40000000, 0x20000000, 0x08000000, 0x00800000, 0x00008000, + 0xedb88320, 0xb1e6b092, 0xa06a2517, 0xed627dae, 0x88d14467, + 0xd7bbfe6a, 0xec447f11, 0x8e7ea170, 0x6427800e, 0x4d47bae0, + 0x09fe548f, 0x83852d0f, 0x30362f1a, 0x7b5a9cc3, 0x31fec169, + 0x9fec022a, 0x6c8dedc4, 0x15d6874d, 0x5fde7a4e, 0xbad90e37, + 0x2e4e5eef, 0x4eaba214, 0xa8a472c0, 0x429a969e, 0x148d302a, + 0xc40ba6d0, 0xc4e22c3c}; diff --git a/ZLIB/deflate.c b/ZLIB/deflate.c index ece57647..012ea814 100644 --- a/ZLIB/deflate.c +++ b/ZLIB/deflate.c @@ -1,6 +1,6 @@ /* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-2002 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h */ /* @@ -37,7 +37,7 @@ * REFERENCES * * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". - * Available in ftp://ds.internic.net/rfc/rfc1951.txt + * Available in http://tools.ietf.org/html/rfc1951 * * A description of the Rabin and Karp algorithm is given in the book * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. @@ -47,12 +47,12 @@ * */ -/* @(#) $Id: deflate.c,v 1.1 2014/03/04 21:20:43 uid42406 Exp $ */ +/* @(#) $Id$ */ #include "deflate.h" const char deflate_copyright[] = - " deflate 1.1.4 Copyright 1995-2002 Jean-loup Gailly "; + " deflate 1.3.1 Copyright 1995-2024 Jean-loup Gailly and Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -60,9 +60,6 @@ const char deflate_copyright[] = copyright string in the executable of your product. */ -/* =========================================================================== - * Function prototypes. - */ typedef enum { need_more, /* block not completed, need more input or more output */ block_done, /* block flush performed */ @@ -70,28 +67,16 @@ typedef enum { finish_done /* finish done, accept no more input or output */ } block_state; -typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +typedef block_state (*compress_func)(deflate_state *s, int flush); /* Compression function. Returns the block state after the call. */ -local void fill_window OF((deflate_state *s)); -local block_state deflate_stored OF((deflate_state *s, int flush)); -local block_state deflate_fast OF((deflate_state *s, int flush)); -local block_state deflate_slow OF((deflate_state *s, int flush)); -local void lm_init OF((deflate_state *s)); -local void putShortMSB OF((deflate_state *s, uInt b)); -local void flush_pending OF((z_streamp strm)); -local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); -#ifdef ASMV - void match_init OF((void)); /* asm code initialization */ - uInt longest_match OF((deflate_state *s, IPos cur_match)); -#else -local uInt longest_match OF((deflate_state *s, IPos cur_match)); -#endif - -#ifdef DEBUG -local void check_match OF((deflate_state *s, IPos start, IPos match, - int length)); +local block_state deflate_stored(deflate_state *s, int flush); +local block_state deflate_fast(deflate_state *s, int flush); +#ifndef FASTEST +local block_state deflate_slow(deflate_state *s, int flush); #endif +local block_state deflate_rle(deflate_state *s, int flush); +local block_state deflate_huff(deflate_state *s, int flush); /* =========================================================================== * Local data @@ -105,11 +90,6 @@ local void check_match OF((deflate_state *s, IPos start, IPos match, #endif /* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - /* Values for max_lazy_match, good_match and max_chain_length, depending on * the desired pack level (0..9). The values given below have been tuned to * exclude worst case performance for pathological files. Better values may be @@ -123,10 +103,16 @@ typedef struct config_s { compress_func func; } config; +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else local const config configuration_table[10] = { /* good lazy nice chain */ /* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ -/* 1 */ {4, 4, 8, 4, deflate_fast}, /* maximum speed, no lazy matches */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ /* 2 */ {4, 5, 16, 8, deflate_fast}, /* 3 */ {4, 6, 32, 32, deflate_fast}, @@ -135,25 +121,24 @@ local const config configuration_table[10] = { /* 6 */ {8, 16, 128, 128, deflate_slow}, /* 7 */ {8, 32, 128, 256, deflate_slow}, /* 8 */ {32, 128, 258, 1024, deflate_slow}, -/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */ +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif /* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 * For deflate_fast() (levels <= 3) good is ignored and lazy has a different * meaning. */ -#define EQUAL 0 -/* result of memcmp for equal strings */ - -struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */ +#define RANK(f) (((f) * 2) - ((f) > 4 ? 9 : 0)) /* =========================================================================== * Update a hash value with the given input byte - * IN assertion: all calls to to UPDATE_HASH are made with consecutive - * input characters, so that a running hash key can be computed from the - * previous key instead of complete recalculation each time. + * IN assertion: all calls to UPDATE_HASH are made with consecutive input + * characters, so that a running hash key can be computed from the previous + * key instead of complete recalculation each time. */ -#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) +#define UPDATE_HASH(s,h,c) (h = (((h) << s->hash_shift) ^ (c)) & s->hash_mask) /* =========================================================================== @@ -162,9 +147,9 @@ struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ * the previous length of the hash chain. * If this file is compiled with -DFASTEST, the compression level is forced * to 1, and no hash chains are maintained. - * IN assertion: all calls to to INSERT_STRING are made with consecutive - * input characters and the first MIN_MATCH bytes of str are valid - * (except for the last MIN_MATCH-1 bytes of the input file). + * IN assertion: all calls to INSERT_STRING are made with consecutive input + * characters and the first MIN_MATCH bytes of str are valid (except for + * the last MIN_MATCH-1 bytes of the input file). */ #ifdef FASTEST #define INSERT_STRING(s, str, match_head) \ @@ -174,7 +159,7 @@ struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ #else #define INSERT_STRING(s, str, match_head) \ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ - s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ s->head[s->ins_h] = (Pos)(str)) #endif @@ -183,102 +168,353 @@ struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ * prev[] will be initialized on the fly. */ #define CLEAR_HASH(s) \ - s->head[s->hash_size-1] = NIL; \ - zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + do { \ + s->head[s->hash_size - 1] = NIL; \ + zmemzero((Bytef *)s->head, \ + (unsigned)(s->hash_size - 1)*sizeof(*s->head)); \ + } while (0) + +/* =========================================================================== + * Slide the hash table when sliding the window down (could be avoided with 32 + * bit values at the expense of memory usage). We slide even when level == 0 to + * keep the hash table consistent if we switch back to level > 0 later. + */ +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) + __attribute__((no_sanitize("memory"))) +# endif +#endif +local void slide_hash(deflate_state *s) { + unsigned n, m; + Posf *p; + uInt wsize = s->w_size; + + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m - wsize : NIL); + } while (--n); + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m - wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local unsigned read_buf(z_streamp strm, Bytef *buf, unsigned size) { + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + zmemcpy(buf, strm->next_in, len); + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, buf, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, buf, len); + } +#endif + strm->next_in += len; + strm->total_in += len; + + return len; +} + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(deflate_state *s) { + unsigned n; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize + MAX_DIST(s)) { + + zmemcpy(s->window, s->window + wsize, (unsigned)wsize - more); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + if (s->insert > s->strstart) + s->insert = s->strstart; + slide_hash(s); + more += wsize; + } + if (s->strm->avail_in == 0) break; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead + s->insert >= MIN_MATCH) { + uInt str = s->strstart - s->insert; + s->ins_h = s->window[str]; + UPDATE_HASH(s, s->ins_h, s->window[str + 1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + while (s->insert) { + UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); +#ifndef FASTEST + s->prev[str & s->w_mask] = s->head[s->ins_h]; +#endif + s->head[s->ins_h] = (Pos)str; + str++; + s->insert--; + if (s->lookahead + s->insert < MIN_MATCH) + break; + } + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); + + /* If the WIN_INIT bytes after the end of the current data have never been + * written, then zero those bytes in order to avoid memory check reports of + * the use of uninitialized (or uninitialised as Julian writes) bytes by + * the longest match routines. Update the high water mark for the next + * time through here. WIN_INIT is set to MAX_MATCH since the longest match + * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. + */ + if (s->high_water < s->window_size) { + ulg curr = s->strstart + (ulg)(s->lookahead); + ulg init; + + if (s->high_water < curr) { + /* Previous high water mark below current data -- zero WIN_INIT + * bytes or up to end of window, whichever is less. + */ + init = s->window_size - curr; + if (init > WIN_INIT) + init = WIN_INIT; + zmemzero(s->window + curr, (unsigned)init); + s->high_water = curr + init; + } + else if (s->high_water < (ulg)curr + WIN_INIT) { + /* High water mark at or above current data, but below current data + * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up + * to end of window, whichever is less. + */ + init = (ulg)curr + WIN_INIT - s->high_water; + if (init > s->window_size - s->high_water) + init = s->window_size - s->high_water; + zmemzero(s->window + s->high_water, (unsigned)init); + s->high_water += init; + } + } + + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "not enough room for search"); +} /* ========================================================================= */ -int ZEXPORT deflateInit_(strm, level, version, stream_size) - z_streamp strm; - int level; - const char *version; - int stream_size; -{ +int ZEXPORT deflateInit_(z_streamp strm, int level, const char *version, + int stream_size) { return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, - Z_DEFAULT_STRATEGY, version, stream_size); + Z_DEFAULT_STRATEGY, version, stream_size); /* To do: ignore strm->next_in if we use it as window */ } /* ========================================================================= */ -int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, - version, stream_size) - z_streamp strm; - int level; - int method; - int windowBits; - int memLevel; - int strategy; - const char *version; - int stream_size; -{ +int ZEXPORT deflateInit2_(z_streamp strm, int level, int method, + int windowBits, int memLevel, int strategy, + const char *version, int stream_size) { deflate_state *s; - int noheader = 0; - static const char* my_version = ZLIB_VERSION; - - ushf *overlay; - /* We overlay pending_buf and d_buf+l_buf. This works since the average - * output size for (length,distance) codes is <= 24 bits. - */ + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; if (version == Z_NULL || version[0] != my_version[0] || stream_size != sizeof(z_stream)) { - return Z_VERSION_ERROR; + return Z_VERSION_ERROR; } if (strm == Z_NULL) return Z_STREAM_ERROR; strm->msg = Z_NULL; - if (strm->zalloc == Z_NULL) { - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif } - if (strm->zfree == Z_NULL) strm->zfree = zcfree; + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif - if (level == Z_DEFAULT_COMPRESSION) level = 6; #ifdef FASTEST - level = 1; + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; #endif - if (windowBits < 0) { /* undocumented feature: suppress zlib header */ - noheader = 1; + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + if (windowBits < -15) + return Z_STREAM_ERROR; windowBits = -windowBits; } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || - windowBits < 9 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_HUFFMAN_ONLY) { + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED || (windowBits == 8 && wrap != 1)) { return Z_STREAM_ERROR; } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); if (s == Z_NULL) return Z_MEM_ERROR; strm->state = (struct internal_state FAR *)s; s->strm = strm; + s->status = INIT_STATE; /* to pass state test in deflateReset() */ - s->noheader = noheader; - s->w_bits = windowBits; + s->wrap = wrap; + s->gzhead = Z_NULL; + s->w_bits = (uInt)windowBits; s->w_size = 1 << s->w_bits; s->w_mask = s->w_size - 1; - s->hash_bits = memLevel + 7; + s->hash_bits = (uInt)memLevel + 7; s->hash_size = 1 << s->hash_bits; s->hash_mask = s->hash_size - 1; - s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + s->hash_shift = ((s->hash_bits + MIN_MATCH-1) / MIN_MATCH); s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + s->high_water = 0; /* nothing written to s->window yet */ + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ - overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); - s->pending_buf = (uchf *) overlay; - s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + /* We overlay pending_buf and sym_buf. This works since the average size + * for length/distance pairs over any compressed block is assured to be 31 + * bits or less. + * + * Analysis: The longest fixed codes are a length code of 8 bits plus 5 + * extra bits, for lengths 131 to 257. The longest fixed distance codes are + * 5 bits plus 13 extra bits, for distances 16385 to 32768. The longest + * possible fixed-codes length/distance pair is then 31 bits total. + * + * sym_buf starts one-fourth of the way into pending_buf. So there are + * three bytes in sym_buf for every four bytes in pending_buf. Each symbol + * in sym_buf is three bytes -- two for the distance and one for the + * literal/length. As each symbol is consumed, the pointer to the next + * sym_buf value to read moves forward three bytes. From that symbol, up to + * 31 bits are written to pending_buf. The closest the written pending_buf + * bits gets to the next sym_buf symbol to read is just before the last + * code is written. At that time, 31*(n - 2) bits have been written, just + * after 24*(n - 2) bits have been consumed from sym_buf. sym_buf starts at + * 8*n bits into pending_buf. (Note that the symbol buffer fills when n - 1 + * symbols are written.) The closest the writing gets to what is unread is + * then n + 14 bits. Here n is lit_bufsize, which is 16384 by default, and + * can range from 128 to 32768. + * + * Therefore, at a minimum, there are 142 bits of space between what is + * written and what is read in the overlain buffers, so the symbols cannot + * be overwritten by the compressed data. That space is actually 139 bits, + * due to the three-bit fixed-code block header. + * + * That covers the case where either Z_FIXED is specified, forcing fixed + * codes, or when the use of fixed codes is chosen, because that choice + * results in a smaller compressed block than dynamic codes. That latter + * condition then assures that the above analysis also covers all dynamic + * blocks. A dynamic-code block will only be chosen to be emitted if it has + * fewer bits than a fixed-code block would for the same set of symbols. + * Therefore its average symbol length is assured to be less than 31. So + * the compressed data for a dynamic block also cannot overwrite the + * symbols from which it is being constructed. + */ + + s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, LIT_BUFS); + s->pending_buf_size = (ulg)s->lit_bufsize * 4; if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || s->pending_buf == Z_NULL) { - strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + s->status = FINISH_STATE; + strm->msg = ERR_MSG(Z_MEM_ERROR); deflateEnd (strm); return Z_MEM_ERROR; } - s->d_buf = overlay + s->lit_bufsize/sizeof(ush); - s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; +#ifdef LIT_MEM + s->d_buf = (ushf *)(s->pending_buf + (s->lit_bufsize << 1)); + s->l_buf = s->pending_buf + (s->lit_bufsize << 2); + s->sym_end = s->lit_bufsize - 1; +#else + s->sym_buf = s->pending_buf + s->lit_bufsize; + s->sym_end = (s->lit_bufsize - 1) * 3; +#endif + /* We avoid equality with lit_bufsize*3 because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ s->level = level; s->strategy = strategy; @@ -287,55 +523,121 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, return deflateReset(strm); } -/* ========================================================================= */ -int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) - z_streamp strm; - const Bytef *dictionary; - uInt dictLength; -{ +/* ========================================================================= + * Check for a valid deflate stream state. Return 0 if ok, 1 if not. + */ +local int deflateStateCheck(z_streamp strm) { deflate_state *s; - uInt length = dictLength; - uInt n; - IPos hash_head = 0; + if (strm == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) + return 1; + s = strm->state; + if (s == Z_NULL || s->strm != strm || (s->status != INIT_STATE && +#ifdef GZIP + s->status != GZIP_STATE && +#endif + s->status != EXTRA_STATE && + s->status != NAME_STATE && + s->status != COMMENT_STATE && + s->status != HCRC_STATE && + s->status != BUSY_STATE && + s->status != FINISH_STATE)) + return 1; + return 0; +} - if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || - strm->state->status != INIT_STATE) return Z_STREAM_ERROR; +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary(z_streamp strm, const Bytef *dictionary, + uInt dictLength) { + deflate_state *s; + uInt str, n; + int wrap; + unsigned avail; + z_const unsigned char *next; + if (deflateStateCheck(strm) || dictionary == Z_NULL) + return Z_STREAM_ERROR; s = strm->state; - strm->adler = adler32(strm->adler, dictionary, dictLength); + wrap = s->wrap; + if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead) + return Z_STREAM_ERROR; - if (length < MIN_MATCH) return Z_OK; - if (length > MAX_DIST(s)) { - length = MAX_DIST(s); -#ifndef USE_DICT_HEAD - dictionary += dictLength - length; /* use the tail of the dictionary */ -#endif + /* when using zlib wrappers, compute Adler-32 for provided dictionary */ + if (wrap == 1) + strm->adler = adler32(strm->adler, dictionary, dictLength); + s->wrap = 0; /* avoid computing Adler-32 in read_buf */ + + /* if dictionary would fill window, just replace the history */ + if (dictLength >= s->w_size) { + if (wrap == 0) { /* already empty otherwise */ + CLEAR_HASH(s); + s->strstart = 0; + s->block_start = 0L; + s->insert = 0; + } + dictionary += dictLength - s->w_size; /* use the tail */ + dictLength = s->w_size; } - zmemcpy(s->window, dictionary, length); - s->strstart = length; - s->block_start = (long)length; - /* Insert all strings in the hash table (except for the last two bytes). - * s->lookahead stays null, so s->ins_h will be recomputed at the next - * call of fill_window. - */ - s->ins_h = s->window[0]; - UPDATE_HASH(s, s->ins_h, s->window[1]); - for (n = 0; n <= length - MIN_MATCH; n++) { - INSERT_STRING(s, n, hash_head); + /* insert dictionary into window and hash */ + avail = strm->avail_in; + next = strm->next_in; + strm->avail_in = dictLength; + strm->next_in = (z_const Bytef *)dictionary; + fill_window(s); + while (s->lookahead >= MIN_MATCH) { + str = s->strstart; + n = s->lookahead - (MIN_MATCH-1); + do { + UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); +#ifndef FASTEST + s->prev[str & s->w_mask] = s->head[s->ins_h]; +#endif + s->head[s->ins_h] = (Pos)str; + str++; + } while (--n); + s->strstart = str; + s->lookahead = MIN_MATCH-1; + fill_window(s); } - if (hash_head) hash_head = 0; /* to make compiler happy */ + s->strstart += s->lookahead; + s->block_start = (long)s->strstart; + s->insert = s->lookahead; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + strm->next_in = next; + strm->avail_in = avail; + s->wrap = wrap; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateGetDictionary(z_streamp strm, Bytef *dictionary, + uInt *dictLength) { + deflate_state *s; + uInt len; + + if (deflateStateCheck(strm)) + return Z_STREAM_ERROR; + s = strm->state; + len = s->strstart + s->lookahead; + if (len > s->w_size) + len = s->w_size; + if (dictionary != Z_NULL && len) + zmemcpy(dictionary, s->window + s->strstart + s->lookahead - len, len); + if (dictLength != Z_NULL) + *dictLength = len; return Z_OK; } /* ========================================================================= */ -int ZEXPORT deflateReset (strm) - z_streamp strm; -{ +int ZEXPORT deflateResetKeep(z_streamp strm) { deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL || - strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR; + + if (deflateStateCheck(strm)) { + return Z_STREAM_ERROR; + } strm->total_in = strm->total_out = 0; strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ @@ -345,53 +647,253 @@ int ZEXPORT deflateReset (strm) s->pending = 0; s->pending_out = s->pending_buf; - if (s->noheader < 0) { - s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */ + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ } - s->status = s->noheader ? BUSY_STATE : INIT_STATE; - strm->adler = 1; - s->last_flush = Z_NO_FLUSH; + s->status = +#ifdef GZIP + s->wrap == 2 ? GZIP_STATE : +#endif + INIT_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = -2; _tr_init(s); - lm_init(s); return Z_OK; } +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init(deflate_state *s) { + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->insert = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset(z_streamp strm) { + int ret; + + ret = deflateResetKeep(strm); + if (ret == Z_OK) + lm_init(strm->state); + return ret; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetHeader(z_streamp strm, gz_headerp head) { + if (deflateStateCheck(strm) || strm->state->wrap != 2) + return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePending(z_streamp strm, unsigned *pending, int *bits) { + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + if (pending != Z_NULL) + *pending = strm->state->pending; + if (bits != Z_NULL) + *bits = strm->state->bi_valid; + return Z_OK; +} + /* ========================================================================= */ -int ZEXPORT deflateParams(strm, level, strategy) - z_streamp strm; - int level; - int strategy; -{ +int ZEXPORT deflatePrime(z_streamp strm, int bits, int value) { + deflate_state *s; + int put; + + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + s = strm->state; +#ifdef LIT_MEM + if (bits < 0 || bits > 16 || + (uchf *)s->d_buf < s->pending_out + ((Buf_size + 7) >> 3)) + return Z_BUF_ERROR; +#else + if (bits < 0 || bits > 16 || + s->sym_buf < s->pending_out + ((Buf_size + 7) >> 3)) + return Z_BUF_ERROR; +#endif + do { + put = Buf_size - s->bi_valid; + if (put > bits) + put = bits; + s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid); + s->bi_valid += put; + _tr_flush_bits(s); + value >>= put; + bits -= put; + } while (bits); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(z_streamp strm, int level, int strategy) { deflate_state *s; compress_func func; - int err = Z_OK; - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; - if (level == Z_DEFAULT_COMPRESSION) { - level = 6; - } - if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) { - return Z_STREAM_ERROR; +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; } func = configuration_table[s->level].func; - if (func != configuration_table[level].func && strm->total_in != 0) { - /* Flush the last buffer: */ - err = deflate(strm, Z_PARTIAL_FLUSH); + if ((strategy != s->strategy || func != configuration_table[level].func) && + s->last_flush != -2) { + /* Flush the last buffer: */ + int err = deflate(strm, Z_BLOCK); + if (err == Z_STREAM_ERROR) + return err; + if (strm->avail_in || (s->strstart - s->block_start) + s->lookahead) + return Z_BUF_ERROR; } if (s->level != level) { - s->level = level; - s->max_lazy_match = configuration_table[level].max_lazy; - s->good_match = configuration_table[level].good_length; - s->nice_match = configuration_table[level].nice_length; - s->max_chain_length = configuration_table[level].max_chain; + if (s->level == 0 && s->matches != 0) { + if (s->matches == 1) + slide_hash(s); + else + CLEAR_HASH(s); + s->matches = 0; + } + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; } s->strategy = strategy; - return err; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateTune(z_streamp strm, int good_length, int max_lazy, + int nice_length, int max_chain) { + deflate_state *s; + + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = (uInt)good_length; + s->max_lazy_match = (uInt)max_lazy; + s->nice_match = nice_length; + s->max_chain_length = (uInt)max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns a + * close to exact, as well as small, upper bound on the compressed size. This + * is an expansion of ~0.03%, plus a small constant. + * + * For any setting other than those defaults for windowBits and memLevel, one + * of two worst case bounds is returned. This is at most an expansion of ~4% or + * ~13%, plus a small constant. + * + * Both the 0.03% and 4% derive from the overhead of stored blocks. The first + * one is for stored blocks of 16383 bytes (memLevel == 8), whereas the second + * is for stored blocks of 127 bytes (the worst case memLevel == 1). The + * expansion results from five bytes of header for each stored block. + * + * The larger expansion of 13% results from a window size less than or equal to + * the symbols buffer size (windowBits <= memLevel + 7). In that case some of + * the data being compressed may have slid out of the sliding window, impeding + * a stored block from being emitted. Then the only choice is a fixed or + * dynamic block, where a fixed block limits the maximum expansion to 9 bits + * per 8-bit byte, plus 10 bits for every block. The smallest block size for + * which this can occur is 255 (memLevel == 2). + * + * Shifts are used to approximate divisions, for speed. + */ +uLong ZEXPORT deflateBound(z_streamp strm, uLong sourceLen) { + deflate_state *s; + uLong fixedlen, storelen, wraplen; + + /* upper bound for fixed blocks with 9-bit literals and length 255 + (memLevel == 2, which is the lowest that may not use stored blocks) -- + ~13% overhead plus a small constant */ + fixedlen = sourceLen + (sourceLen >> 3) + (sourceLen >> 8) + + (sourceLen >> 9) + 4; + + /* upper bound for stored blocks with length 127 (memLevel == 1) -- + ~4% overhead plus a small constant */ + storelen = sourceLen + (sourceLen >> 5) + (sourceLen >> 7) + + (sourceLen >> 11) + 7; + + /* if can't get parameters, return larger bound plus a zlib wrapper */ + if (deflateStateCheck(strm)) + return (fixedlen > storelen ? fixedlen : storelen) + 6; + + /* compute wrapper length */ + s = strm->state; + switch (s->wrap) { + case 0: /* raw deflate */ + wraplen = 0; + break; + case 1: /* zlib wrapper */ + wraplen = 6 + (s->strstart ? 4 : 0); + break; +#ifdef GZIP + case 2: /* gzip wrapper */ + wraplen = 18; + if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ + Bytef *str; + if (s->gzhead->extra != Z_NULL) + wraplen += 2 + s->gzhead->extra_len; + str = s->gzhead->name; + if (str != Z_NULL) + do { + wraplen++; + } while (*str++); + str = s->gzhead->comment; + if (str != Z_NULL) + do { + wraplen++; + } while (*str++); + if (s->gzhead->hcrc) + wraplen += 2; + } + break; +#endif + default: /* for compiler happiness */ + wraplen = 6; + } + + /* if not default parameters, return one of the conservative bounds */ + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return (s->w_bits <= s->hash_bits && s->level ? fixedlen : storelen) + + wraplen; + + /* default settings: return tight bound for that case -- ~0.03% overhead + plus a small constant */ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + + (sourceLen >> 25) + 13 - 6 + wraplen; } /* ========================================================================= @@ -399,113 +901,277 @@ int ZEXPORT deflateParams(strm, level, strategy) * IN assertion: the stream state is correct and there is enough room in * pending_buf. */ -local void putShortMSB (s, b) - deflate_state *s; - uInt b; -{ +local void putShortMSB(deflate_state *s, uInt b) { put_byte(s, (Byte)(b >> 8)); put_byte(s, (Byte)(b & 0xff)); -} +} /* ========================================================================= - * Flush as much pending output as possible. All deflate() output goes - * through this function so some applications may wish to modify it - * to avoid allocating a large strm->next_out buffer and copying into it. - * (See also read_buf()). + * Flush as much pending output as possible. All deflate() output, except for + * some deflate_stored() output, goes through this function so some + * applications may wish to modify it to avoid allocating a large + * strm->next_out buffer and copying into it. (See also read_buf()). */ -local void flush_pending(strm) - z_streamp strm; -{ - unsigned len = strm->state->pending; +local void flush_pending(z_streamp strm) { + unsigned len; + deflate_state *s = strm->state; + _tr_flush_bits(s); + len = s->pending; if (len > strm->avail_out) len = strm->avail_out; if (len == 0) return; - zmemcpy(strm->next_out, strm->state->pending_out, len); + zmemcpy(strm->next_out, s->pending_out, len); strm->next_out += len; - strm->state->pending_out += len; + s->pending_out += len; strm->total_out += len; - strm->avail_out -= len; - strm->state->pending -= len; - if (strm->state->pending == 0) { - strm->state->pending_out = strm->state->pending_buf; + strm->avail_out -= len; + s->pending -= len; + if (s->pending == 0) { + s->pending_out = s->pending_buf; } } +/* =========================================================================== + * Update the header CRC with the bytes s->pending_buf[beg..s->pending - 1]. + */ +#define HCRC_UPDATE(beg) \ + do { \ + if (s->gzhead->hcrc && s->pending > (beg)) \ + strm->adler = crc32(strm->adler, s->pending_buf + (beg), \ + s->pending - (beg)); \ + } while (0) + /* ========================================================================= */ -int ZEXPORT deflate (strm, flush) - z_streamp strm; - int flush; -{ +int ZEXPORT deflate(z_streamp strm, int flush) { int old_flush; /* value of flush param for previous deflate call */ deflate_state *s; - if (strm == Z_NULL || strm->state == Z_NULL || - flush > Z_FINISH || flush < 0) { + if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) { return Z_STREAM_ERROR; } s = strm->state; if (strm->next_out == Z_NULL || - (strm->next_in == Z_NULL && strm->avail_in != 0) || - (s->status == FINISH_STATE && flush != Z_FINISH)) { + (strm->avail_in != 0 && strm->next_in == Z_NULL) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { ERR_RETURN(strm, Z_STREAM_ERROR); } - if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); - - s->strm = strm; /* just in case */ - old_flush = s->last_flush; - s->last_flush = flush; - - /* Write the zlib header */ - if (s->status == INIT_STATE) { - - uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; - uInt level_flags = (s->level-1) >> 1; - - if (level_flags > 3) level_flags = 3; - header |= (level_flags << 6); - if (s->strstart != 0) header |= PRESET_DICT; - header += 31 - (header % 31); - + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + old_flush = s->last_flush; + s->last_flush = flush; + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Write the header */ + if (s->status == INIT_STATE && s->wrap == 0) + s->status = BUSY_STATE; + if (s->status == INIT_STATE) { + /* zlib header */ + uInt header = (Z_DEFLATED + ((s->w_bits - 8) << 4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } +#ifdef GZIP + if (s->status == GZIP_STATE) { + /* gzip header */ + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == Z_NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != Z_NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != Z_NULL) { + ulg beg = s->pending; /* start of bytes to update crc */ + uInt left = (s->gzhead->extra_len & 0xffff) - s->gzindex; + while (s->pending + left > s->pending_buf_size) { + uInt copy = s->pending_buf_size - s->pending; + zmemcpy(s->pending_buf + s->pending, + s->gzhead->extra + s->gzindex, copy); + s->pending = s->pending_buf_size; + HCRC_UPDATE(beg); + s->gzindex += copy; + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + beg = 0; + left -= copy; + } + zmemcpy(s->pending_buf + s->pending, + s->gzhead->extra + s->gzindex, left); + s->pending += left; + HCRC_UPDATE(beg); + s->gzindex = 0; + } + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != Z_NULL) { + ulg beg = s->pending; /* start of bytes to update crc */ + int val; + do { + if (s->pending == s->pending_buf_size) { + HCRC_UPDATE(beg); + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + beg = 0; + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + HCRC_UPDATE(beg); + s->gzindex = 0; + } + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != Z_NULL) { + ulg beg = s->pending; /* start of bytes to update crc */ + int val; + do { + if (s->pending == s->pending_buf_size) { + HCRC_UPDATE(beg); + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + beg = 0; + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + HCRC_UPDATE(beg); + } + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) { + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + } s->status = BUSY_STATE; - putShortMSB(s, header); - - /* Save the adler32 of the preset dictionary: */ - if (s->strstart != 0) { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - strm->adler = 1L; - } - /* Flush as much pending output as possible */ - if (s->pending != 0) { + /* Compression must start with an empty pending buffer */ flush_pending(strm); - if (strm->avail_out == 0) { - /* Since avail_out is 0, deflate will be called again with - * more output space, but possibly with both pending and - * avail_in equal to zero. There won't be anything to do, - * but this is not an error situation so make sure we - * return OK instead of BUF_ERROR at next call of deflate: - */ - s->last_flush = -1; - return Z_OK; - } - - /* Make sure there is something to do and avoid duplicate consecutive - * flushes. For repeated and useless calls with Z_FINISH, we keep - * returning Z_STREAM_END instead of Z_BUFF_ERROR. - */ - } else if (strm->avail_in == 0 && flush <= old_flush && - flush != Z_FINISH) { - ERR_RETURN(strm, Z_BUF_ERROR); - } - - /* User must not provide more input after the first FINISH: */ - if (s->status == FINISH_STATE && strm->avail_in != 0) { - ERR_RETURN(strm, Z_BUF_ERROR); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } } +#endif /* Start a new block or continue the current one. */ @@ -513,72 +1179,88 @@ int ZEXPORT deflate (strm, flush) (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { block_state bstate; - bstate = (*(configuration_table[s->level].func))(s, flush); + bstate = s->level == 0 ? deflate_stored(s, flush) : + s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : + s->strategy == Z_RLE ? deflate_rle(s, flush) : + (*(configuration_table[s->level].func))(s, flush); if (bstate == finish_started || bstate == finish_done) { s->status = FINISH_STATE; } if (bstate == need_more || bstate == finish_started) { - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ - } - return Z_OK; - /* If flush != Z_NO_FLUSH && avail_out == 0, the next call - * of deflate should use the same flush parameter to make sure - * that the flush is complete. So we don't have to output an - * empty block here, this will be done at next call. This also - * ensures that for a very small output buffer, we emit at most - * one empty block. - */ - } + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } if (bstate == block_done) { if (flush == Z_PARTIAL_FLUSH) { _tr_align(s); - } else { /* FULL_FLUSH or SYNC_FLUSH */ + } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ _tr_stored_block(s, (char*)0, 0L, 0); /* For a full flush, this empty block will be recognized * as a special marker by inflate_sync(). */ if (flush == Z_FULL_FLUSH) { CLEAR_HASH(s); /* forget history */ + if (s->lookahead == 0) { + s->strstart = 0; + s->block_start = 0L; + s->insert = 0; + } } } flush_pending(strm); - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ - return Z_OK; - } + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } } } - Assert(strm->avail_out > 0, "bug2"); if (flush != Z_FINISH) return Z_OK; - if (s->noheader) return Z_STREAM_END; - - /* Write the zlib trailer (adler32) */ - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } flush_pending(strm); /* If avail_out is zero, the application will call deflate again * to flush the rest. */ - s->noheader = -1; /* write the trailer only once! */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ return s->pending != 0 ? Z_OK : Z_STREAM_END; } /* ========================================================================= */ -int ZEXPORT deflateEnd (strm) - z_streamp strm; -{ +int ZEXPORT deflateEnd(z_streamp strm) { int status; - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; status = strm->state->status; - if (status != INIT_STATE && status != BUSY_STATE && - status != FINISH_STATE) { - return Z_STREAM_ERROR; - } /* Deallocate in reverse order of allocations: */ TRY_FREE(strm, strm->state->pending_buf); @@ -597,37 +1279,34 @@ int ZEXPORT deflateEnd (strm) * To simplify the source, this is not supported for 16-bit MSDOS (which * doesn't have enough memory anyway to duplicate compression states). */ -int ZEXPORT deflateCopy (dest, source) - z_streamp dest; - z_streamp source; -{ +int ZEXPORT deflateCopy(z_streamp dest, z_streamp source) { #ifdef MAXSEG_64K + (void)dest; + (void)source; return Z_STREAM_ERROR; #else deflate_state *ds; deflate_state *ss; - ushf *overlay; - if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + if (deflateStateCheck(source) || dest == Z_NULL) { return Z_STREAM_ERROR; } ss = source->state; - *dest = *source; + zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); if (ds == Z_NULL) return Z_MEM_ERROR; dest->state = (struct internal_state FAR *) ds; - *ds = *ss; + zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); ds->strm = dest; ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); - overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); - ds->pending_buf = (uchf *) overlay; + ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, LIT_BUFS); if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || ds->pending_buf == Z_NULL) { @@ -636,79 +1315,27 @@ int ZEXPORT deflateCopy (dest, source) } /* following zmemcpy do not work for 16-bit MSDOS */ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); - zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); - zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); - zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, ds->lit_bufsize * LIT_BUFS); ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); - ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); - ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; +#ifdef LIT_MEM + ds->d_buf = (ushf *)(ds->pending_buf + (ds->lit_bufsize << 1)); + ds->l_buf = ds->pending_buf + (ds->lit_bufsize << 2); +#else + ds->sym_buf = ds->pending_buf + ds->lit_bufsize; +#endif ds->l_desc.dyn_tree = ds->dyn_ltree; ds->d_desc.dyn_tree = ds->dyn_dtree; ds->bl_desc.dyn_tree = ds->bl_tree; return Z_OK; -#endif -} - -/* =========================================================================== - * Read a new buffer from the current input stream, update the adler32 - * and total number of bytes read. All deflate() input goes through - * this function so some applications may wish to modify it to avoid - * allocating a large strm->next_in buffer and copying from it. - * (See also flush_pending()). - */ -local int read_buf(strm, buf, size) - z_streamp strm; - Bytef *buf; - unsigned size; -{ - unsigned len = strm->avail_in; - - if (len > size) len = size; - if (len == 0) return 0; - - strm->avail_in -= len; - - if (!strm->state->noheader) { - strm->adler = adler32(strm->adler, strm->next_in, len); - } - zmemcpy(buf, strm->next_in, len); - strm->next_in += len; - strm->total_in += len; - - return (int)len; -} - -/* =========================================================================== - * Initialize the "longest match" routines for a new zlib stream - */ -local void lm_init (s) - deflate_state *s; -{ - s->window_size = (ulg)2L*s->w_size; - - CLEAR_HASH(s); - - /* Set the default configuration parameters: - */ - s->max_lazy_match = configuration_table[s->level].max_lazy; - s->good_match = configuration_table[s->level].good_length; - s->nice_match = configuration_table[s->level].nice_length; - s->max_chain_length = configuration_table[s->level].max_chain; - - s->strstart = 0; - s->block_start = 0L; - s->lookahead = 0; - s->match_length = s->prev_length = MIN_MATCH-1; - s->match_available = 0; - s->ins_h = 0; -#ifdef ASMV - match_init(); /* initialize the asm code */ -#endif +#endif /* MAXSEG_64K */ } +#ifndef FASTEST /* =========================================================================== * Set match_start to the longest match starting at the given string and * return its length. Matches shorter or equal to prev_length are discarded, @@ -718,20 +1345,12 @@ local void lm_init (s) * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 * OUT assertion: the match length is not greater than s->lookahead. */ -#ifndef ASMV -/* For 80x86 and 680x0, an optimized version will be provided in match.asm or - * match.S. The code will be functionally equivalent. - */ -#ifndef FASTEST -local uInt longest_match(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ +local uInt longest_match(deflate_state *s, IPos cur_match) { unsigned chain_length = s->max_chain_length;/* max hash chain length */ register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ + register Bytef *match; /* matched string */ register int len; /* length of current match */ - int best_len = s->prev_length; /* best match length so far */ + int best_len = (int)s->prev_length; /* best match length so far */ int nice_match = s->nice_match; /* stop if match long enough */ IPos limit = s->strstart > (IPos)MAX_DIST(s) ? s->strstart - (IPos)MAX_DIST(s) : NIL; @@ -747,10 +1366,10 @@ local uInt longest_match(s, cur_match) */ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; register ush scan_start = *(ushf*)scan; - register ush scan_end = *(ushf*)(scan+best_len-1); + register ush scan_end = *(ushf*)(scan + best_len - 1); #else register Bytef *strend = s->window + s->strstart + MAX_MATCH; - register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end1 = scan[best_len - 1]; register Byte scan_end = scan[best_len]; #endif @@ -766,58 +1385,65 @@ local uInt longest_match(s, cur_match) /* Do not look for matches beyond the end of the input. This is necessary * to make deflate deterministic. */ - if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead; - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "need lookahead"); do { Assert(cur_match < s->strstart, "no future"); match = s->window + cur_match; /* Skip to next match if the match length cannot increase - * or if the match length is less than 2: + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. */ #if (defined(UNALIGNED_OK) && MAX_MATCH == 258) /* This code assumes sizeof(unsigned short) == 2. Do not use * UNALIGNED_OK if your compiler uses a different size. */ - if (*(ushf*)(match+best_len-1) != scan_end || + if (*(ushf*)(match + best_len - 1) != scan_end || *(ushf*)match != scan_start) continue; /* It is not necessary to compare scan[2] and match[2] since they are * always equal when the other bytes match, given that the hash keys * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at - * strstart+3, +5, ... up to strstart+257. We check for insufficient + * strstart + 3, + 5, up to strstart + 257. We check for insufficient * lookahead only every 4th comparison; the 128th check will be made - * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * at strstart + 257. If MAX_MATCH-2 is not a multiple of 8, it is * necessary to put more guard bytes at the end of the window, or * to check more often for insufficient lookahead. */ Assert(scan[2] == match[2], "scan[2]?"); scan++, match++; do { - } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + } while (*(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && scan < strend); /* The funny "do {}" generates better code on most compilers */ - /* Here, scan <= window+strstart+257 */ - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + /* Here, scan <= window + strstart + 257 */ + Assert(scan <= s->window + (unsigned)(s->window_size - 1), + "wild scan"); if (*scan == *match) scan++; - len = (MAX_MATCH - 1) - (int)(strend-scan); + len = (MAX_MATCH - 1) - (int)(strend - scan); scan = strend - (MAX_MATCH-1); #else /* UNALIGNED_OK */ - if (match[best_len] != scan_end || - match[best_len-1] != scan_end1 || - *match != *scan || - *++match != scan[1]) continue; + if (match[best_len] != scan_end || + match[best_len - 1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; - /* The check at best_len-1 can be removed because it will be made + /* The check at best_len - 1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that @@ -827,7 +1453,7 @@ local uInt longest_match(s, cur_match) Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. + * the 256th check will be made at strstart + 258. */ do { } while (*++scan == *++match && *++scan == *++match && @@ -836,7 +1462,8 @@ local uInt longest_match(s, cur_match) *++scan == *++match && *++scan == *++match && scan < strend); - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + Assert(scan <= s->window + (unsigned)(s->window_size - 1), + "wild scan"); len = MAX_MATCH - (int)(strend - scan); scan = strend - MAX_MATCH; @@ -848,9 +1475,9 @@ local uInt longest_match(s, cur_match) best_len = len; if (len >= nice_match) break; #ifdef UNALIGNED_OK - scan_end = *(ushf*)(scan+best_len-1); + scan_end = *(ushf*)(scan + best_len - 1); #else - scan_end1 = scan[best_len-1]; + scan_end1 = scan[best_len - 1]; scan_end = scan[best_len]; #endif } @@ -862,13 +1489,11 @@ local uInt longest_match(s, cur_match) } #else /* FASTEST */ + /* --------------------------------------------------------------------------- - * Optimized version for level == 1 only + * Optimized version for FASTEST only */ -local uInt longest_match(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ +local uInt longest_match(deflate_state *s, IPos cur_match) { register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ register int len; /* length of current match */ @@ -879,7 +1504,8 @@ local uInt longest_match(s, cur_match) */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "need lookahead"); Assert(cur_match < s->strstart, "no future"); @@ -889,7 +1515,7 @@ local uInt longest_match(s, cur_match) */ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; - /* The check at best_len-1 can be removed because it will be made + /* The check at best_len - 1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that @@ -899,234 +1525,280 @@ local uInt longest_match(s, cur_match) Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. + * the 256th check will be made at strstart + 258. */ do { } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + Assert(scan <= s->window + (unsigned)(s->window_size - 1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); if (len < MIN_MATCH) return MIN_MATCH - 1; s->match_start = cur_match; - return len <= s->lookahead ? len : s->lookahead; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; } + #endif /* FASTEST */ -#endif /* ASMV */ -#ifdef DEBUG +#ifdef ZLIB_DEBUG + +#define EQUAL 0 +/* result of memcmp for equal strings */ + /* =========================================================================== * Check that the match at match_start is indeed a match. */ -local void check_match(s, start, match, length) - deflate_state *s; - IPos start, match; - int length; -{ +local void check_match(deflate_state *s, IPos start, IPos match, int length) { /* check that the match is indeed a match */ - if (zmemcmp(s->window + match, - s->window + start, length) != EQUAL) { - fprintf(stderr, " start %u, match %u, length %d\n", - start, match, length); + Bytef *back = s->window + (int)match, *here = s->window + start; + IPos len = length; + if (match == (IPos)-1) { + /* match starts one byte before the current window -- just compare the + subsequent length-1 bytes */ + back++; + here++; + len--; + } + if (zmemcmp(back, here, len) != EQUAL) { + fprintf(stderr, " start %u, match %d, length %d\n", + start, (int)match, length); do { - fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); - } while (--length != 0); + fprintf(stderr, "(%02x %02x)", *back++, *here++); + } while (--len != 0); z_error("invalid match"); } if (z_verbose > 1) { - fprintf(stderr,"\\[%d,%d]", start-match, length); + fprintf(stderr,"\\[%d,%d]", start - match, length); do { putc(s->window[start++], stderr); } while (--length != 0); } } #else # define check_match(s, start, match, length) -#endif - -/* =========================================================================== - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead. - * - * IN assertion: lookahead < MIN_LOOKAHEAD - * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - * At least one byte has been read, or avail_in == 0; reads are - * performed for at least two bytes (required for the zip translate_eol - * option -- not supported here). - */ -local void fill_window(s) - deflate_state *s; -{ - register unsigned n, m; - register Posf *p; - unsigned more; /* Amount of free space at the end of the window. */ - uInt wsize = s->w_size; - - do { - more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); - - /* Deal with !@#$% 64K limit: */ - if (more == 0 && s->strstart == 0 && s->lookahead == 0) { - more = wsize; - - } else if (more == (unsigned)(-1)) { - /* Very unlikely, but possible on 16 bit machine if strstart == 0 - * and lookahead == 1 (input done one byte at time) - */ - more--; - - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - } else if (s->strstart >= wsize+MAX_DIST(s)) { - - zmemcpy(s->window, s->window+wsize, (unsigned)wsize); - s->match_start -= wsize; - s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ - s->block_start -= (long) wsize; - - /* Slide the hash table (could be avoided with 32 bit values - at the expense of memory usage). We slide even when level == 0 - to keep the hash table consistent if we switch back to level > 0 - later. (Using level 0 permanently is not an optimal usage of - zlib, so we don't care about this pathological case.) - */ - n = s->hash_size; - p = &s->head[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - } while (--n); - - n = wsize; -#ifndef FASTEST - p = &s->prev[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } while (--n); -#endif - more += wsize; - } - if (s->strm->avail_in == 0) return; - - /* If there was no sliding: - * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && - * more == window_size - lookahead - strstart - * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) - * => more >= window_size - 2*WSIZE + 2 - * In the BIG_MEM or MMAP case (not yet supported), - * window_size == input_size + MIN_LOOKAHEAD && - * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. - * Otherwise, window_size == 2*WSIZE so more >= 2. - * If there was sliding, more >= WSIZE. So in all cases, more >= 2. - */ - Assert(more >= 2, "more < 2"); - - n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); - s->lookahead += n; - - /* Initialize the hash value now that we have some input: */ - if (s->lookahead >= MIN_MATCH) { - s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - } - /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, - * but this is not important since only literal bytes will be emitted. - */ - - } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); -} +#endif /* ZLIB_DEBUG */ /* =========================================================================== * Flush the current block, with given end-of-file flag. * IN assertion: strstart is set to the end of the current match. */ -#define FLUSH_BLOCK_ONLY(s, eof) { \ +#define FLUSH_BLOCK_ONLY(s, last) { \ _tr_flush_block(s, (s->block_start >= 0L ? \ (charf *)&s->window[(unsigned)s->block_start] : \ (charf *)Z_NULL), \ - (ulg)((long)s->strstart - s->block_start), \ - (eof)); \ + (ulg)((long)s->strstart - s->block_start), \ + (last)); \ s->block_start = s->strstart; \ flush_pending(s->strm); \ Tracev((stderr,"[FLUSH]")); \ } /* Same but force premature exit if necessary. */ -#define FLUSH_BLOCK(s, eof) { \ - FLUSH_BLOCK_ONLY(s, eof); \ - if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +#define FLUSH_BLOCK(s, last) { \ + FLUSH_BLOCK_ONLY(s, last); \ + if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ } +/* Maximum stored block length in deflate format (not including header). */ +#define MAX_STORED 65535 + +/* Minimum of a and b. */ +#define MIN(a, b) ((a) > (b) ? (b) : (a)) + /* =========================================================================== * Copy without compression as much as possible from the input stream, return * the current block state. - * This function does not insert new strings in the dictionary since - * uncompressible data is probably not useful. This function is used - * only for the level=0 compression option. - * NOTE: this function should be optimized to avoid extra copying from - * window to pending_buf. + * + * In case deflateParams() is used to later switch to a non-zero compression + * level, s->matches (otherwise unused when storing) keeps track of the number + * of hash table slides to perform. If s->matches is 1, then one hash table + * slide will be done when switching. If s->matches is 2, the maximum value + * allowed here, then the hash table will be cleared, since two or more slides + * is the same as a clear. + * + * deflate_stored() is written to minimize the number of times an input byte is + * copied. It is most efficient with large input and output buffers, which + * maximizes the opportunities to have a single copy from next_in to next_out. */ -local block_state deflate_stored(s, flush) - deflate_state *s; - int flush; -{ - /* Stored blocks are limited to 0xffff bytes, pending_buf is limited - * to pending_buf_size, and each stored block has a 5 byte header: +local block_state deflate_stored(deflate_state *s, int flush) { + /* Smallest worthy block size when not flushing or finishing. By default + * this is 32K. This can be as small as 507 bytes for memLevel == 1. For + * large input and output buffers, the stored block size will be larger. */ - ulg max_block_size = 0xffff; - ulg max_start; + unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size); - if (max_block_size > s->pending_buf_size - 5) { - max_block_size = s->pending_buf_size - 5; - } - - /* Copy as much as possible from input to output: */ - for (;;) { - /* Fill the window as much as possible: */ - if (s->lookahead <= 1) { + /* Copy as many min_block or larger stored blocks directly to next_out as + * possible. If flushing, copy the remaining available input to next_out as + * stored blocks, if there is enough space. + */ + unsigned len, left, have, last = 0; + unsigned used = s->strm->avail_in; + do { + /* Set len to the maximum size block that we can copy directly with the + * available input data and output space. Set left to how much of that + * would be copied from what's left in the window. + */ + len = MAX_STORED; /* maximum deflate stored block length */ + have = (s->bi_valid + 42) >> 3; /* number of header bytes */ + if (s->strm->avail_out < have) /* need room for header */ + break; + /* maximum stored block length that will fit in avail_out: */ + have = s->strm->avail_out - have; + left = s->strstart - s->block_start; /* bytes left in window */ + if (len > (ulg)left + s->strm->avail_in) + len = left + s->strm->avail_in; /* limit len to the input */ + if (len > have) + len = have; /* limit len to the output */ + + /* If the stored block would be less than min_block in length, or if + * unable to copy all of the available input when flushing, then try + * copying to the window and the pending buffer instead. Also don't + * write an empty block when flushing -- deflate() does that. + */ + if (len < min_block && ((len == 0 && flush != Z_FINISH) || + flush == Z_NO_FLUSH || + len != left + s->strm->avail_in)) + break; - Assert(s->strstart < s->w_size+MAX_DIST(s) || - s->block_start >= (long)s->w_size, "slide too late"); + /* Make a dummy stored block in pending to get the header bytes, + * including any pending bits. This also updates the debugging counts. + */ + last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0; + _tr_stored_block(s, (char *)0, 0L, last); + + /* Replace the lengths in the dummy stored block with len. */ + s->pending_buf[s->pending - 4] = len; + s->pending_buf[s->pending - 3] = len >> 8; + s->pending_buf[s->pending - 2] = ~len; + s->pending_buf[s->pending - 1] = ~len >> 8; + + /* Write the stored block header bytes. */ + flush_pending(s->strm); + +#ifdef ZLIB_DEBUG + /* Update debugging counts for the data about to be copied. */ + s->compressed_len += len << 3; + s->bits_sent += len << 3; +#endif - fill_window(s); - if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + /* Copy uncompressed bytes from the window to next_out. */ + if (left) { + if (left > len) + left = len; + zmemcpy(s->strm->next_out, s->window + s->block_start, left); + s->strm->next_out += left; + s->strm->avail_out -= left; + s->strm->total_out += left; + s->block_start += left; + len -= left; + } - if (s->lookahead == 0) break; /* flush the current block */ + /* Copy uncompressed bytes directly from next_in to next_out, updating + * the check value. + */ + if (len) { + read_buf(s->strm, s->strm->next_out, len); + s->strm->next_out += len; + s->strm->avail_out -= len; + s->strm->total_out += len; } - Assert(s->block_start >= 0L, "block gone"); - - s->strstart += s->lookahead; - s->lookahead = 0; - - /* Emit a stored block if pending_buf will be full: */ - max_start = s->block_start + max_block_size; - if (s->strstart == 0 || (ulg)s->strstart >= max_start) { - /* strstart == 0 is possible when wraparound on 16-bit machine */ - s->lookahead = (uInt)(s->strstart - max_start); - s->strstart = (uInt)max_start; - FLUSH_BLOCK(s, 0); - } - /* Flush if we may have to slide, otherwise block_start may become - * negative and the data will be gone: + } while (last == 0); + + /* Update the sliding window with the last s->w_size bytes of the copied + * data, or append all of the copied data to the existing window if less + * than s->w_size bytes were copied. Also update the number of bytes to + * insert in the hash tables, in the event that deflateParams() switches to + * a non-zero compression level. + */ + used -= s->strm->avail_in; /* number of input bytes directly copied */ + if (used) { + /* If any input was used, then no unused input remains in the window, + * therefore s->block_start == s->strstart. */ - if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { - FLUSH_BLOCK(s, 0); - } + if (used >= s->w_size) { /* supplant the previous history */ + s->matches = 2; /* clear hash */ + zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size); + s->strstart = s->w_size; + s->insert = s->strstart; + } + else { + if (s->window_size - s->strstart <= used) { + /* Slide the window down. */ + s->strstart -= s->w_size; + zmemcpy(s->window, s->window + s->w_size, s->strstart); + if (s->matches < 2) + s->matches++; /* add a pending slide_hash() */ + if (s->insert > s->strstart) + s->insert = s->strstart; + } + zmemcpy(s->window + s->strstart, s->strm->next_in - used, used); + s->strstart += used; + s->insert += MIN(used, s->w_size - s->insert); + } + s->block_start = s->strstart; + } + if (s->high_water < s->strstart) + s->high_water = s->strstart; + + /* If the last block was written to next_out, then done. */ + if (last) + return finish_done; + + /* If flushing and all input has been consumed, then done. */ + if (flush != Z_NO_FLUSH && flush != Z_FINISH && + s->strm->avail_in == 0 && (long)s->strstart == s->block_start) + return block_done; + + /* Fill the window with any remaining input. */ + have = s->window_size - s->strstart; + if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) { + /* Slide the window down. */ + s->block_start -= s->w_size; + s->strstart -= s->w_size; + zmemcpy(s->window, s->window + s->w_size, s->strstart); + if (s->matches < 2) + s->matches++; /* add a pending slide_hash() */ + have += s->w_size; /* more space now */ + if (s->insert > s->strstart) + s->insert = s->strstart; + } + if (have > s->strm->avail_in) + have = s->strm->avail_in; + if (have) { + read_buf(s->strm, s->window + s->strstart, have); + s->strstart += have; + s->insert += MIN(have, s->w_size - s->insert); } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; + if (s->high_water < s->strstart) + s->high_water = s->strstart; + + /* There was not enough avail_out to write a complete worthy or flushed + * stored block to next_out. Write a stored block to pending instead, if we + * have enough input for a worthy block, or if flushing and there is enough + * room for the remaining input as a stored block in the pending buffer. + */ + have = (s->bi_valid + 42) >> 3; /* number of header bytes */ + /* maximum stored block length that will fit in pending: */ + have = MIN(s->pending_buf_size - have, MAX_STORED); + min_block = MIN(have, s->w_size); + left = s->strstart - s->block_start; + if (left >= min_block || + ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH && + s->strm->avail_in == 0 && left <= have)) { + len = MIN(left, have); + last = flush == Z_FINISH && s->strm->avail_in == 0 && + len == left ? 1 : 0; + _tr_stored_block(s, (charf *)s->window + s->block_start, len, last); + s->block_start += len; + flush_pending(s->strm); + } + + /* We've done all we can with the available input and output. */ + return last ? finish_started : need_more; } /* =========================================================================== @@ -1136,11 +1808,8 @@ local block_state deflate_stored(s, flush) * new strings in the dictionary only for unmatched strings or for short * matches. It is used only for the fast compression options. */ -local block_state deflate_fast(s, flush) - deflate_state *s; - int flush; -{ - IPos hash_head = NIL; /* head of the hash chain */ +local block_state deflate_fast(deflate_state *s, int flush) { + IPos hash_head; /* head of the hash chain */ int bflush; /* set if current block must be flushed */ for (;;) { @@ -1152,14 +1821,15 @@ local block_state deflate_fast(s, flush) if (s->lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } + return need_more; + } if (s->lookahead == 0) break; /* flush the current block */ } - /* Insert the string window[strstart .. strstart+2] in the + /* Insert the string window[strstart .. strstart + 2] in the * dictionary, and set hash_head to the head of the hash chain: */ + hash_head = NIL; if (s->lookahead >= MIN_MATCH) { INSERT_STRING(s, s->strstart, hash_head); } @@ -1172,9 +1842,7 @@ local block_state deflate_fast(s, flush) * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ - if (s->strategy != Z_HUFFMAN_ONLY) { - s->match_length = longest_match (s, hash_head); - } + s->match_length = longest_match (s, hash_head); /* longest_match() sets match_start */ } if (s->match_length >= MIN_MATCH) { @@ -1191,7 +1859,7 @@ local block_state deflate_fast(s, flush) #ifndef FASTEST if (s->match_length <= s->max_insert_length && s->lookahead >= MIN_MATCH) { - s->match_length--; /* string at strstart already in hash table */ + s->match_length--; /* string at strstart already in table */ do { s->strstart++; INSERT_STRING(s, s->strstart, hash_head); @@ -1199,14 +1867,14 @@ local block_state deflate_fast(s, flush) * always MIN_MATCH bytes ahead. */ } while (--s->match_length != 0); - s->strstart++; + s->strstart++; } else #endif - { + { s->strstart += s->match_length; s->match_length = 0; s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); + UPDATE_HASH(s, s->ins_h, s->window[s->strstart + 1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif @@ -1217,26 +1885,30 @@ local block_state deflate_fast(s, flush) } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); + _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; - s->strstart++; + s->strstart++; } if (bflush) FLUSH_BLOCK(s, 0); } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; + s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->sym_next) + FLUSH_BLOCK(s, 0); + return block_done; } +#ifndef FASTEST /* =========================================================================== * Same as above, but achieves better compression. We use a lazy * evaluation for matches: a match is finally adopted only if there is * no better match at the next window position. */ -local block_state deflate_slow(s, flush) - deflate_state *s; - int flush; -{ - IPos hash_head = NIL; /* head of hash chain */ +local block_state deflate_slow(deflate_state *s, int flush) { + IPos hash_head; /* head of hash chain */ int bflush; /* set if current block must be flushed */ /* Process the input block. */ @@ -1249,14 +1921,15 @@ local block_state deflate_slow(s, flush) if (s->lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } + return need_more; + } if (s->lookahead == 0) break; /* flush the current block */ } - /* Insert the string window[strstart .. strstart+2] in the + /* Insert the string window[strstart .. strstart + 2] in the * dictionary, and set hash_head to the head of the hash chain: */ + hash_head = NIL; if (s->lookahead >= MIN_MATCH) { INSERT_STRING(s, s->strstart, hash_head); } @@ -1272,14 +1945,15 @@ local block_state deflate_slow(s, flush) * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ - if (s->strategy != Z_HUFFMAN_ONLY) { - s->match_length = longest_match (s, hash_head); - } + s->match_length = longest_match (s, hash_head); /* longest_match() sets match_start */ - if (s->match_length <= 5 && (s->strategy == Z_FILTERED || - (s->match_length == MIN_MATCH && - s->strstart - s->match_start > TOO_FAR))) { + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { /* If prev_match is also MIN_MATCH, match_start is garbage * but we will ignore the current match anyway. @@ -1294,17 +1968,17 @@ local block_state deflate_slow(s, flush) uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; /* Do not insert strings in hash table beyond this. */ - check_match(s, s->strstart-1, s->prev_match, s->prev_length); + check_match(s, s->strstart - 1, s->prev_match, s->prev_length); - _tr_tally_dist(s, s->strstart -1 - s->prev_match, - s->prev_length - MIN_MATCH, bflush); + _tr_tally_dist(s, s->strstart - 1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not + * strstart - 1 and strstart are already inserted. If there is not * enough lookahead, the last two strings are not inserted in * the hash table. */ - s->lookahead -= s->prev_length-1; + s->lookahead -= s->prev_length - 1; s->prev_length -= 2; do { if (++s->strstart <= max_insert) { @@ -1322,9 +1996,9 @@ local block_state deflate_slow(s, flush) * single literal. If there was a match but the current match * is longer, truncate the previous match to a single literal. */ - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); - if (bflush) { + Tracevv((stderr,"%c", s->window[s->strstart - 1])); + _tr_tally_lit(s, s->window[s->strstart - 1], bflush); + if (bflush) { FLUSH_BLOCK_ONLY(s, 0); } s->strstart++; @@ -1341,10 +2015,125 @@ local block_state deflate_slow(s, flush) } Assert (flush != Z_NO_FLUSH, "no flush?"); if (s->match_available) { - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); + Tracevv((stderr,"%c", s->window[s->strstart - 1])); + _tr_tally_lit(s, s->window[s->strstart - 1], bflush); s->match_available = 0; } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; + s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->sym_next) + FLUSH_BLOCK(s, 0); + return block_done; +} +#endif /* FASTEST */ + +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(deflate_state *s, int flush) { + int bflush; /* set if current block must be flushed */ + uInt prev; /* byte at distance one to match */ + Bytef *scan, *strend; /* scan goes up to strend for length of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest run, plus one for the unrolled loop. + */ + if (s->lookahead <= MAX_MATCH) { + fill_window(s); + if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + s->match_length = 0; + if (s->lookahead >= MIN_MATCH && s->strstart > 0) { + scan = s->window + s->strstart - 1; + prev = *scan; + if (prev == *++scan && prev == *++scan && prev == *++scan) { + strend = s->window + s->strstart + MAX_MATCH; + do { + } while (prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + scan < strend); + s->match_length = MAX_MATCH - (uInt)(strend - scan); + if (s->match_length > s->lookahead) + s->match_length = s->lookahead; + } + Assert(scan <= s->window + (uInt)(s->window_size - 1), + "wild scan"); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, s->match_length); + + _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + s->strstart += s->match_length; + s->match_length = 0; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit(s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->sym_next) + FLUSH_BLOCK(s, 0); + return block_done; +} + +/* =========================================================================== + * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. + * (It will be regenerated if this run of deflate switches away from Huffman.) + */ +local block_state deflate_huff(deflate_state *s, int flush) { + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we have a literal to write. */ + if (s->lookahead == 0) { + fill_window(s); + if (s->lookahead == 0) { + if (flush == Z_NO_FLUSH) + return need_more; + break; /* flush the current block */ + } + } + + /* Output a literal byte */ + s->match_length = 0; + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit(s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + if (bflush) FLUSH_BLOCK(s, 0); + } + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->sym_next) + FLUSH_BLOCK(s, 0); + return block_done; } diff --git a/ZLIB/deflate.h b/ZLIB/deflate.h index 1a77c5f4..300c6ada 100644 --- a/ZLIB/deflate.h +++ b/ZLIB/deflate.h @@ -1,6 +1,6 @@ /* deflate.h -- internal compression state - * Copyright (C) 1995-2002 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2024 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is @@ -8,13 +8,25 @@ subject to change. Applications should only use zlib.h. */ -/* @(#) $Id: deflate.h,v 1.1 2014/03/04 21:20:44 uid42406 Exp $ */ +/* @(#) $Id$ */ -#ifndef _DEFLATE_H -#define _DEFLATE_H +#ifndef DEFLATE_H +#define DEFLATE_H #include "zutil.h" +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* define LIT_MEM to slightly increase the speed of deflate (order 1% to 2%) at + the cost of a larger memory footprint */ +/* #define LIT_MEM */ + /* =========================================================================== * Internal compression state. */ @@ -40,9 +52,19 @@ #define MAX_BITS 15 /* All codes must not exceed MAX_BITS bits */ -#define INIT_STATE 42 -#define BUSY_STATE 113 -#define FINISH_STATE 666 +#define Buf_size 16 +/* size of bit buffer in bi_buf */ + +#define INIT_STATE 42 /* zlib header -> BUSY_STATE */ +#ifdef GZIP +# define GZIP_STATE 57 /* gzip header -> BUSY_STATE | EXTRA_STATE */ +#endif +#define EXTRA_STATE 69 /* gzip extra block -> NAME_STATE */ +#define NAME_STATE 73 /* gzip file name -> COMMENT_STATE */ +#define COMMENT_STATE 91 /* gzip comment -> HCRC_STATE */ +#define HCRC_STATE 103 /* gzip header CRC -> BUSY_STATE */ +#define BUSY_STATE 113 /* deflate -> FINISH_STATE */ +#define FINISH_STATE 666 /* stream complete */ /* Stream status */ @@ -68,7 +90,7 @@ typedef struct static_tree_desc_s static_tree_desc; typedef struct tree_desc_s { ct_data *dyn_tree; /* the dynamic tree */ int max_code; /* largest code with non zero frequency */ - static_tree_desc *stat_desc; /* the corresponding static tree */ + const static_tree_desc *stat_desc; /* the corresponding static tree */ } FAR tree_desc; typedef ush Pos; @@ -85,10 +107,11 @@ typedef struct internal_state { Bytef *pending_buf; /* output still pending */ ulg pending_buf_size; /* size of pending_buf */ Bytef *pending_out; /* next pending byte to output to the stream */ - int pending; /* nb of bytes in the pending buffer */ - int noheader; /* suppress zlib header and adler32 */ - Byte data_type; /* UNKNOWN, BINARY or ASCII */ - Byte method; /* STORED (for zip only) or DEFLATED */ + ulg pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + ulg gzindex; /* where in extra, name, or comment */ + Byte method; /* can only be DEFLATED */ int last_flush; /* value of flush param for previous deflate call */ /* used by deflate.c: */ @@ -175,7 +198,7 @@ typedef struct internal_state { int nice_match; /* Stop searching when current match exceeds this */ /* used by trees.c: */ - /* Didn't use ct_data typedef below to supress compiler warning */ + /* Didn't use ct_data typedef below to suppress compiler warning */ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ @@ -198,7 +221,14 @@ typedef struct internal_state { /* Depth of each subtree used as tie breaker for trees of equal frequency */ - uchf *l_buf; /* buffer for literals or lengths */ +#ifdef LIT_MEM +# define LIT_BUFS 5 + ushf *d_buf; /* buffer for distances */ + uchf *l_buf; /* buffer for literals/lengths */ +#else +# define LIT_BUFS 4 + uchf *sym_buf; /* buffer for distances and literals/lengths */ +#endif uInt lit_bufsize; /* Size of match buffer for literals/lengths. There are 4 reasons for @@ -220,20 +250,15 @@ typedef struct internal_state { * - I can't count above 4 */ - uInt last_lit; /* running index in l_buf */ - - ushf *d_buf; - /* Buffer for distances. To simplify the code, d_buf and l_buf have - * the same number of elements. To use different lengths, an extra flag - * array would be necessary. - */ + uInt sym_next; /* running index in symbol buffer */ + uInt sym_end; /* symbol table full when sym_next reaches this */ ulg opt_len; /* bit length of current block with optimal trees */ ulg static_len; /* bit length of current block with static trees */ uInt matches; /* number of string matches in current block */ - int last_eob_len; /* bit length of EOB code for last block */ + uInt insert; /* bytes at end of window left to insert */ -#ifdef DEBUG +#ifdef ZLIB_DEBUG ulg compressed_len; /* total bit length of compressed file mod 2^32 */ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ #endif @@ -247,12 +272,19 @@ typedef struct internal_state { * are always zero. */ + ulg high_water; + /* High water mark offset in window for initialized bytes -- bytes above + * this are set to zero in order to avoid memory check warnings when + * longest match routines access bytes past the input. This is then + * updated to the new high water mark. + */ + } FAR deflate_state; /* Output a byte on the stream. * IN assertion: there is enough room in pending_buf. */ -#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} +#define put_byte(s, c) {s->pending_buf[s->pending++] = (Bytef)(c);} #define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) @@ -265,14 +297,19 @@ typedef struct internal_state { * distances are limited to MAX_DIST instead of WSIZE. */ +#define WIN_INIT MAX_MATCH +/* Number of bytes after end of data in window to initialize in order to avoid + memory checker errors from longest match routines */ + /* in trees.c */ -void _tr_init OF((deflate_state *s)); -int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); -void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, - int eof)); -void _tr_align OF((deflate_state *s)); -void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, - int eof)); +void ZLIB_INTERNAL _tr_init(deflate_state *s); +int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc); +void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf, + ulg stored_len, int last); +void ZLIB_INTERNAL _tr_flush_bits(deflate_state *s); +void ZLIB_INTERNAL _tr_align(deflate_state *s); +void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf, + ulg stored_len, int last); #define d_code(dist) \ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) @@ -281,38 +318,60 @@ void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, * used. */ -#ifndef DEBUG +#ifndef ZLIB_DEBUG /* Inline versions of _tr_tally for speed: */ #if defined(GEN_TREES_H) || !defined(STDC) - extern uch _length_code[]; - extern uch _dist_code[]; + extern uch ZLIB_INTERNAL _length_code[]; + extern uch ZLIB_INTERNAL _dist_code[]; #else - extern const uch _length_code[]; - extern const uch _dist_code[]; + extern const uch ZLIB_INTERNAL _length_code[]; + extern const uch ZLIB_INTERNAL _dist_code[]; #endif +#ifdef LIT_MEM # define _tr_tally_lit(s, c, flush) \ { uch cc = (c); \ - s->d_buf[s->last_lit] = 0; \ - s->l_buf[s->last_lit++] = cc; \ + s->d_buf[s->sym_next] = 0; \ + s->l_buf[s->sym_next++] = cc; \ s->dyn_ltree[cc].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ + flush = (s->sym_next == s->sym_end); \ } # define _tr_tally_dist(s, distance, length, flush) \ - { uch len = (length); \ - ush dist = (distance); \ - s->d_buf[s->last_lit] = dist; \ - s->l_buf[s->last_lit++] = len; \ + { uch len = (uch)(length); \ + ush dist = (ush)(distance); \ + s->d_buf[s->sym_next] = dist; \ + s->l_buf[s->sym_next++] = len; \ dist--; \ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ s->dyn_dtree[d_code(dist)].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ + flush = (s->sym_next == s->sym_end); \ } #else +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->sym_buf[s->sym_next++] = 0; \ + s->sym_buf[s->sym_next++] = 0; \ + s->sym_buf[s->sym_next++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->sym_next == s->sym_end); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (uch)(length); \ + ush dist = (ush)(distance); \ + s->sym_buf[s->sym_next++] = (uch)dist; \ + s->sym_buf[s->sym_next++] = (uch)(dist >> 8); \ + s->sym_buf[s->sym_next++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->sym_next == s->sym_end); \ + } +#endif +#else # define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) # define _tr_tally_dist(s, distance, length, flush) \ - flush = _tr_tally(s, distance, length) + flush = _tr_tally(s, distance, length) #endif -#endif +#endif /* DEFLATE_H */ diff --git a/ZLIB/gzclose.c b/ZLIB/gzclose.c new file mode 100644 index 00000000..48d6a86f --- /dev/null +++ b/ZLIB/gzclose.c @@ -0,0 +1,23 @@ +/* gzclose.c -- zlib gzclose() function + * Copyright (C) 2004, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* gzclose() is in a separate file so that it is linked in only if it is used. + That way the other gzclose functions can be used instead to avoid linking in + unneeded compression or decompression routines. */ +int ZEXPORT gzclose(gzFile file) { +#ifndef NO_GZCOMPRESS + gz_statep state; + + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file); +#else + return gzclose_r(file); +#endif +} diff --git a/ZLIB/gzguts.h b/ZLIB/gzguts.h new file mode 100644 index 00000000..eba72085 --- /dev/null +++ b/ZLIB/gzguts.h @@ -0,0 +1,214 @@ +/* gzguts.h -- zlib internal header definitions for gz* operations + * Copyright (C) 2004-2024 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef _LARGEFILE64_SOURCE +# ifndef _LARGEFILE_SOURCE +# define _LARGEFILE_SOURCE 1 +# endif +# undef _FILE_OFFSET_BITS +# undef _TIME_BITS +#endif + +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include +#include "zlib.h" +#ifdef STDC +# include +# include +# include +#endif + +#ifndef _POSIX_SOURCE +# define _POSIX_SOURCE +#endif +#include + +#ifdef _WIN32 +# include +#endif + +#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) +# include +#endif + +#if defined(_WIN32) +# define WIDECHAR +#endif + +#ifdef WINAPI_FAMILY +# define open _open +# define read _read +# define write _write +# define close _close +#endif + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS +/* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 +/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) +# define vsnprintf _vsnprintf +# endif +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +# ifdef VMS +# define NO_vsnprintf +# endif +# ifdef __OS400__ +# define NO_vsnprintf +# endif +# ifdef __MVS__ +# define NO_vsnprintf +# endif +#endif + +/* unlike snprintf (which is required in C99), _snprintf does not guarantee + null termination of the result -- however this is only used in gzlib.c where + the result is assured to fit in the space provided */ +#if defined(_MSC_VER) && _MSC_VER < 1900 +# define snprintf _snprintf +#endif + +#ifndef local +# define local static +#endif +/* since "static" is used to mean two completely different things in C, we + define "local" for the non-static meaning of "static", for readability + (compile with -Dlocal if your debugger can't find static symbols) */ + +/* gz* functions always use library allocation functions */ +#ifndef STDC + extern voidp malloc(uInt size); + extern void free(voidpf ptr); +#endif + +/* get errno and strerror definition */ +#if defined UNDER_CE +# include +# define zstrerror() gz_strwinerror((DWORD)GetLastError()) +#else +# ifndef NO_STRERROR +# include +# define zstrerror() strerror(errno) +# else +# define zstrerror() "stdio error (consult errno)" +# endif +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 + ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *); + ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int); + ZEXTERN z_off64_t ZEXPORT gztell64(gzFile); + ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile); +#endif + +/* default memLevel */ +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif + +/* default i/o buffer size -- double this for output when reading (this and + twice this must be able to fit in an unsigned type) */ +#define GZBUFSIZE 8192 + +/* gzip modes, also provide a little integrity check on the passed structure */ +#define GZ_NONE 0 +#define GZ_READ 7247 +#define GZ_WRITE 31153 +#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ + +/* values for gz_state how */ +#define LOOK 0 /* look for a gzip header */ +#define COPY 1 /* copy input directly */ +#define GZIP 2 /* decompress a gzip stream */ + +/* internal gzip file state data structure */ +typedef struct { + /* exposed contents for gzgetc() macro */ + struct gzFile_s x; /* "x" for exposed */ + /* x.have: number of bytes available at x.next */ + /* x.next: next output data to deliver or write */ + /* x.pos: current position in uncompressed data */ + /* used for both reading and writing */ + int mode; /* see gzip modes above */ + int fd; /* file descriptor */ + char *path; /* path or fd for error messages */ + unsigned size; /* buffer size, zero if not allocated yet */ + unsigned want; /* requested buffer size, default is GZBUFSIZE */ + unsigned char *in; /* input buffer (double-sized when writing) */ + unsigned char *out; /* output buffer (double-sized when reading) */ + int direct; /* 0 if processing gzip, 1 if transparent */ + /* just for reading */ + int how; /* 0: get header, 1: copy, 2: decompress */ + z_off64_t start; /* where the gzip data started, for rewinding */ + int eof; /* true if end of input file reached */ + int past; /* true if read requested past end */ + /* just for writing */ + int level; /* compression level */ + int strategy; /* compression strategy */ + int reset; /* true if a reset is pending after a Z_FINISH */ + /* seek request */ + z_off64_t skip; /* amount to skip (already rewound if backwards) */ + int seek; /* true if seek request pending */ + /* error information */ + int err; /* error code */ + char *msg; /* error message */ + /* zlib inflate or deflate stream */ + z_stream strm; /* stream structure in-place (not a pointer) */ +} gz_state; +typedef gz_state FAR *gz_statep; + +/* shared functions */ +void ZLIB_INTERNAL gz_error(gz_statep, int, const char *); +#if defined UNDER_CE +char ZLIB_INTERNAL *gz_strwinerror(DWORD error); +#endif + +/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t + value -- needed when comparing unsigned to z_off64_t, which is signed + (possible z_off64_t types off_t, off64_t, and long are all signed) */ +unsigned ZLIB_INTERNAL gz_intmax(void); +#define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) diff --git a/ZLIB/gzio.c b/ZLIB/gzio.c deleted file mode 100644 index 9c5b9ca9..00000000 --- a/ZLIB/gzio.c +++ /dev/null @@ -1,875 +0,0 @@ -/* gzio.c -- IO on .gz files - * Copyright (C) 1995-2002 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - * - * Compile this file with -DNO_DEFLATE to avoid the compression code. - */ - -/* @(#) $Id: gzio.c,v 1.1 2014/03/04 21:20:44 uid42406 Exp $ */ - -#include - -#include "zutil.h" - -struct internal_state {int dummy;}; /* for buggy compilers */ - -#ifndef Z_BUFSIZE -# ifdef MAXSEG_64K -# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ -# else -# define Z_BUFSIZE 16384 -# endif -#endif -#ifndef Z_PRINTF_BUFSIZE -# define Z_PRINTF_BUFSIZE 4096 -#endif - -#define ALLOC(size) malloc(size) -#define TRYFREE(p) {if (p) free(p);} - -static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ - -/* gzip flag byte */ -#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ -#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ -#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ -#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ -#define COMMENT 0x10 /* bit 4 set: file comment present */ -#define RESERVED 0xE0 /* bits 5..7: reserved */ - -typedef struct gz_stream { - z_stream stream; - int z_err; /* error code for last stream operation */ - int z_eof; /* set if end of input file */ - FILE *file; /* .gz file */ - Byte *inbuf; /* input buffer */ - Byte *outbuf; /* output buffer */ - uLong crc; /* crc32 of uncompressed data */ - char *msg; /* error message */ - char *path; /* path name for debugging only */ - int transparent; /* 1 if input file is not a .gz file */ - char mode; /* 'w' or 'r' */ - long startpos; /* start of compressed data in file (header skipped) */ -} gz_stream; - - -local gzFile gz_open OF((const char *path, const char *mode, int fd)); -local int do_flush OF((gzFile file, int flush)); -local int get_byte OF((gz_stream *s)); -local void check_header OF((gz_stream *s)); -local int destroy OF((gz_stream *s)); -local void putLong OF((FILE *file, uLong x)); -local uLong getLong OF((gz_stream *s)); - -/* =========================================================================== - Opens a gzip (.gz) file for reading or writing. The mode parameter - is as in fopen ("rb" or "wb"). The file is given either by file descriptor - or path name (if fd == -1). - gz_open return NULL if the file could not be opened or if there was - insufficient memory to allocate the (de)compression state; errno - can be checked to distinguish the two cases (if errno is zero, the - zlib error is Z_MEM_ERROR). -*/ -local gzFile gz_open (path, mode, fd) - const char *path; - const char *mode; - int fd; -{ - int err; - int level = Z_DEFAULT_COMPRESSION; /* compression level */ - int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ - char *p = (char*)mode; - gz_stream *s; - char fmode[80]; /* copy of mode, without the compression level */ - char *m = fmode; - - if (!path || !mode) return Z_NULL; - - s = (gz_stream *)ALLOC(sizeof(gz_stream)); - if (!s) return Z_NULL; - - s->stream.zalloc = (alloc_func)0; - s->stream.zfree = (free_func)0; - s->stream.opaque = (voidpf)0; - s->stream.next_in = s->inbuf = Z_NULL; - s->stream.next_out = s->outbuf = Z_NULL; - s->stream.avail_in = s->stream.avail_out = 0; - s->file = NULL; - s->z_err = Z_OK; - s->z_eof = 0; - s->crc = crc32(0L, Z_NULL, 0); - s->msg = NULL; - s->transparent = 0; - - s->path = (char*)ALLOC(strlen(path)+1); - if (s->path == NULL) { - return destroy(s), (gzFile)Z_NULL; - } - strcpy(s->path, path); /* do this early for debugging */ - - s->mode = '\0'; - do { - if (*p == 'r') s->mode = 'r'; - if (*p == 'w' || *p == 'a') s->mode = 'w'; - if (*p >= '0' && *p <= '9') { - level = *p - '0'; - } else if (*p == 'f') { - strategy = Z_FILTERED; - } else if (*p == 'h') { - strategy = Z_HUFFMAN_ONLY; - } else { - *m++ = *p; /* copy the mode */ - } - } while (*p++ && m != fmode + sizeof(fmode)); - if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; - - if (s->mode == 'w') { -#ifdef NO_DEFLATE - err = Z_STREAM_ERROR; -#else - err = deflateInit2(&(s->stream), level, - Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); - /* windowBits is passed < 0 to suppress zlib header */ - - s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); -#endif - if (err != Z_OK || s->outbuf == Z_NULL) { - return destroy(s), (gzFile)Z_NULL; - } - } else { - s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); - - err = inflateInit2(&(s->stream), -MAX_WBITS); - /* windowBits is passed < 0 to tell that there is no zlib header. - * Note that in this case inflate *requires* an extra "dummy" byte - * after the compressed stream in order to complete decompression and - * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are - * present after the compressed stream. - */ - if (err != Z_OK || s->inbuf == Z_NULL) { - return destroy(s), (gzFile)Z_NULL; - } - } - s->stream.avail_out = Z_BUFSIZE; - - errno = 0; - s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); - - if (s->file == NULL) { - return destroy(s), (gzFile)Z_NULL; - } - if (s->mode == 'w') { - /* Write a very simple .gz header: - */ - fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], - Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); - s->startpos = 10L; - /* We use 10L instead of ftell(s->file) to because ftell causes an - * fflush on some systems. This version of the library doesn't use - * startpos anyway in write mode, so this initialization is not - * necessary. - */ - } else { - check_header(s); /* skip the .gz header */ - s->startpos = (ftell(s->file) - s->stream.avail_in); - } - - return (gzFile)s; -} - -/* =========================================================================== - Opens a gzip (.gz) file for reading or writing. -*/ -gzFile ZEXPORT gzopen (path, mode) - const char *path; - const char *mode; -{ - return gz_open (path, mode, -1); -} - -/* =========================================================================== - Associate a gzFile with the file descriptor fd. fd is not dup'ed here - to mimic the behavio(u)r of fdopen. -*/ -gzFile ZEXPORT gzdopen (fd, mode) - int fd; - const char *mode; -{ - char name[20]; - - if (fd < 0) return (gzFile)Z_NULL; - sprintf(name, "", fd); /* for debugging */ - - return gz_open (name, mode, fd); -} - -/* =========================================================================== - * Update the compression level and strategy - */ -int ZEXPORT gzsetparams (file, level, strategy) - gzFile file; - int level; - int strategy; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; - - /* Make room to allow flushing */ - if (s->stream.avail_out == 0) { - - s->stream.next_out = s->outbuf; - if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { - s->z_err = Z_ERRNO; - } - s->stream.avail_out = Z_BUFSIZE; - } - - return deflateParams (&(s->stream), level, strategy); -} - -/* =========================================================================== - Read a byte from a gz_stream; update next_in and avail_in. Return EOF - for end of file. - IN assertion: the stream s has been sucessfully opened for reading. -*/ -local int get_byte(s) - gz_stream *s; -{ - if (s->z_eof) return EOF; - if (s->stream.avail_in == 0) { - errno = 0; - s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); - if (s->stream.avail_in == 0) { - s->z_eof = 1; - if (ferror(s->file)) s->z_err = Z_ERRNO; - return EOF; - } - s->stream.next_in = s->inbuf; - } - s->stream.avail_in--; - return *(s->stream.next_in)++; -} - -/* =========================================================================== - Check the gzip header of a gz_stream opened for reading. Set the stream - mode to transparent if the gzip magic header is not present; set s->err - to Z_DATA_ERROR if the magic header is present but the rest of the header - is incorrect. - IN assertion: the stream s has already been created sucessfully; - s->stream.avail_in is zero for the first time, but may be non-zero - for concatenated .gz files. -*/ -local void check_header(s) - gz_stream *s; -{ - int method; /* method byte */ - int flags; /* flags byte */ - uInt len; - int c; - - /* Check the gzip magic header */ - for (len = 0; len < 2; len++) { - c = get_byte(s); - if (c != gz_magic[len]) { - if (len != 0) s->stream.avail_in++, s->stream.next_in--; - if (c != EOF) { - s->stream.avail_in++, s->stream.next_in--; - s->transparent = 1; - } - s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END; - return; - } - } - method = get_byte(s); - flags = get_byte(s); - if (method != Z_DEFLATED || (flags & RESERVED) != 0) { - s->z_err = Z_DATA_ERROR; - return; - } - - /* Discard time, xflags and OS code: */ - for (len = 0; len < 6; len++) (void)get_byte(s); - - if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ - len = (uInt)get_byte(s); - len += ((uInt)get_byte(s))<<8; - /* len is garbage if EOF but the loop below will quit anyway */ - while (len-- != 0 && get_byte(s) != EOF) ; - } - if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ - while ((c = get_byte(s)) != 0 && c != EOF) ; - } - if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ - while ((c = get_byte(s)) != 0 && c != EOF) ; - } - if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ - for (len = 0; len < 2; len++) (void)get_byte(s); - } - s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; -} - - /* =========================================================================== - * Cleanup then free the given gz_stream. Return a zlib error code. - Try freeing in the reverse order of allocations. - */ -local int destroy (s) - gz_stream *s; -{ - int err = Z_OK; - - if (!s) return Z_STREAM_ERROR; - - TRYFREE(s->msg); - - if (s->stream.state != NULL) { - if (s->mode == 'w') { -#ifdef NO_DEFLATE - err = Z_STREAM_ERROR; -#else - err = deflateEnd(&(s->stream)); -#endif - } else if (s->mode == 'r') { - err = inflateEnd(&(s->stream)); - } - } - if (s->file != NULL && fclose(s->file)) { -#ifdef ESPIPE - if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ -#endif - err = Z_ERRNO; - } - if (s->z_err < 0) err = s->z_err; - - TRYFREE(s->inbuf); - TRYFREE(s->outbuf); - TRYFREE(s->path); - TRYFREE(s); - return err; -} - -/* =========================================================================== - Reads the given number of uncompressed bytes from the compressed file. - gzread returns the number of bytes actually read (0 for end of file). -*/ -int ZEXPORT gzread (file, buf, len) - gzFile file; - voidp buf; - unsigned len; -{ - gz_stream *s = (gz_stream*)file; - Bytef *start = (Bytef*)buf; /* starting point for crc computation */ - Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ - - if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; - - if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; - if (s->z_err == Z_STREAM_END) return 0; /* EOF */ - - next_out = (Byte*)buf; - s->stream.next_out = (Bytef*)buf; - s->stream.avail_out = len; - - while (s->stream.avail_out != 0) { - - if (s->transparent) { - /* Copy first the lookahead bytes: */ - uInt n = s->stream.avail_in; - if (n > s->stream.avail_out) n = s->stream.avail_out; - if (n > 0) { - zmemcpy(s->stream.next_out, s->stream.next_in, n); - next_out += n; - s->stream.next_out = next_out; - s->stream.next_in += n; - s->stream.avail_out -= n; - s->stream.avail_in -= n; - } - if (s->stream.avail_out > 0) { - s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out, - s->file); - } - len -= s->stream.avail_out; - s->stream.total_in += (uLong)len; - s->stream.total_out += (uLong)len; - if (len == 0) s->z_eof = 1; - return (int)len; - } - if (s->stream.avail_in == 0 && !s->z_eof) { - - errno = 0; - s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); - if (s->stream.avail_in == 0) { - s->z_eof = 1; - if (ferror(s->file)) { - s->z_err = Z_ERRNO; - break; - } - } - s->stream.next_in = s->inbuf; - } - s->z_err = inflate(&(s->stream), Z_NO_FLUSH); - - if (s->z_err == Z_STREAM_END) { - /* Check CRC and original size */ - s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); - start = s->stream.next_out; - - if (getLong(s) != s->crc) { - s->z_err = Z_DATA_ERROR; - } else { - (void)getLong(s); - /* The uncompressed length returned by above getlong() may - * be different from s->stream.total_out) in case of - * concatenated .gz files. Check for such files: - */ - check_header(s); - if (s->z_err == Z_OK) { - uLong total_in = s->stream.total_in; - uLong total_out = s->stream.total_out; - - inflateReset(&(s->stream)); - s->stream.total_in = total_in; - s->stream.total_out = total_out; - s->crc = crc32(0L, Z_NULL, 0); - } - } - } - if (s->z_err != Z_OK || s->z_eof) break; - } - s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); - - return (int)(len - s->stream.avail_out); -} - - -/* =========================================================================== - Reads one byte from the compressed file. gzgetc returns this byte - or -1 in case of end of file or error. -*/ -int ZEXPORT gzgetc(file) - gzFile file; -{ - unsigned char c; - - return gzread(file, &c, 1) == 1 ? c : -1; -} - - -/* =========================================================================== - Reads bytes from the compressed file until len-1 characters are - read, or a newline character is read and transferred to buf, or an - end-of-file condition is encountered. The string is then terminated - with a null character. - gzgets returns buf, or Z_NULL in case of error. - - The current implementation is not optimized at all. -*/ -char * ZEXPORT gzgets(file, buf, len) - gzFile file; - char *buf; - int len; -{ - char *b = buf; - if (buf == Z_NULL || len <= 0) return Z_NULL; - - while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; - *buf = '\0'; - return b == buf && len > 0 ? Z_NULL : b; -} - - -#ifndef NO_DEFLATE -/* =========================================================================== - Writes the given number of uncompressed bytes into the compressed file. - gzwrite returns the number of bytes actually written (0 in case of error). -*/ -int ZEXPORT gzwrite (file, buf, len) - gzFile file; - const voidp buf; - unsigned len; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; - - s->stream.next_in = (Bytef*)buf; - s->stream.avail_in = len; - - while (s->stream.avail_in != 0) { - - if (s->stream.avail_out == 0) { - - s->stream.next_out = s->outbuf; - if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { - s->z_err = Z_ERRNO; - break; - } - s->stream.avail_out = Z_BUFSIZE; - } - s->z_err = deflate(&(s->stream), Z_NO_FLUSH); - if (s->z_err != Z_OK) break; - } - s->crc = crc32(s->crc, (const Bytef *)buf, len); - - return (int)(len - s->stream.avail_in); -} - -/* =========================================================================== - Converts, formats, and writes the args to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written (0 in case of error). -*/ -#ifdef STDC -#include - -int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) -{ - char buf[Z_PRINTF_BUFSIZE]; - va_list va; - int len; - - va_start(va, format); -#ifdef HAS_vsnprintf - (void)vsnprintf(buf, sizeof(buf), format, va); -#else - (void)vsprintf(buf, format, va); -#endif - va_end(va); - len = strlen(buf); /* some *sprintf don't return the nb of bytes written */ - if (len <= 0) return 0; - - return gzwrite(file, buf, (unsigned)len); -} -#else /* not ANSI C */ - -int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, - a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) - gzFile file; - const char *format; - int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, - a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; -{ - char buf[Z_PRINTF_BUFSIZE]; - int len; - -#ifdef HAS_snprintf - snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); -#else - sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); -#endif - len = strlen(buf); /* old sprintf doesn't return the nb of bytes written */ - if (len <= 0) return 0; - - return gzwrite(file, buf, len); -} -#endif - -/* =========================================================================== - Writes c, converted to an unsigned char, into the compressed file. - gzputc returns the value that was written, or -1 in case of error. -*/ -int ZEXPORT gzputc(file, c) - gzFile file; - int c; -{ - unsigned char cc = (unsigned char) c; /* required for big endian systems */ - - return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; -} - - -/* =========================================================================== - Writes the given null-terminated string to the compressed file, excluding - the terminating null character. - gzputs returns the number of characters written, or -1 in case of error. -*/ -int ZEXPORT gzputs(file, s) - gzFile file; - const char *s; -{ - return gzwrite(file, (char*)s, (unsigned)strlen(s)); -} - - -/* =========================================================================== - Flushes all pending output into the compressed file. The parameter - flush is as in the deflate() function. -*/ -local int do_flush (file, flush) - gzFile file; - int flush; -{ - uInt len; - int done = 0; - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; - - s->stream.avail_in = 0; /* should be zero already anyway */ - - for (;;) { - len = Z_BUFSIZE - s->stream.avail_out; - - if (len != 0) { - if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { - s->z_err = Z_ERRNO; - return Z_ERRNO; - } - s->stream.next_out = s->outbuf; - s->stream.avail_out = Z_BUFSIZE; - } - if (done) break; - s->z_err = deflate(&(s->stream), flush); - - /* Ignore the second of two consecutive flushes: */ - if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; - - /* deflate has finished flushing only when it hasn't used up - * all the available space in the output buffer: - */ - done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); - - if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; - } - return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; -} - -int ZEXPORT gzflush (file, flush) - gzFile file; - int flush; -{ - gz_stream *s = (gz_stream*)file; - int err = do_flush (file, flush); - - if (err) return err; - fflush(s->file); - return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; -} -#endif /* NO_DEFLATE */ - -/* =========================================================================== - Sets the starting position for the next gzread or gzwrite on the given - compressed file. The offset represents a number of bytes in the - gzseek returns the resulting offset location as measured in bytes from - the beginning of the uncompressed stream, or -1 in case of error. - SEEK_END is not implemented, returns error. - In this version of the library, gzseek can be extremely slow. -*/ -z_off_t ZEXPORT gzseek (file, offset, whence) - gzFile file; - z_off_t offset; - int whence; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || whence == SEEK_END || - s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { - return -1L; - } - - if (s->mode == 'w') { -#ifdef NO_DEFLATE - return -1L; -#else - if (whence == SEEK_SET) { - offset -= s->stream.total_in; - } - if (offset < 0) return -1L; - - /* At this point, offset is the number of zero bytes to write. */ - if (s->inbuf == Z_NULL) { - s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ - zmemzero(s->inbuf, Z_BUFSIZE); - } - while (offset > 0) { - uInt size = Z_BUFSIZE; - if (offset < Z_BUFSIZE) size = (uInt)offset; - - size = gzwrite(file, s->inbuf, size); - if (size == 0) return -1L; - - offset -= size; - } - return (z_off_t)s->stream.total_in; -#endif - } - /* Rest of function is for reading only */ - - /* compute absolute position */ - if (whence == SEEK_CUR) { - offset += s->stream.total_out; - } - if (offset < 0) return -1L; - - if (s->transparent) { - /* map to fseek */ - s->stream.avail_in = 0; - s->stream.next_in = s->inbuf; - if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; - - s->stream.total_in = s->stream.total_out = (uLong)offset; - return offset; - } - - /* For a negative seek, rewind and use positive seek */ - if ((uLong)offset >= s->stream.total_out) { - offset -= s->stream.total_out; - } else if (gzrewind(file) < 0) { - return -1L; - } - /* offset is now the number of bytes to skip. */ - - if (offset != 0 && s->outbuf == Z_NULL) { - s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); - } - while (offset > 0) { - int size = Z_BUFSIZE; - if (offset < Z_BUFSIZE) size = (int)offset; - - size = gzread(file, s->outbuf, (uInt)size); - if (size <= 0) return -1L; - offset -= size; - } - return (z_off_t)s->stream.total_out; -} - -/* =========================================================================== - Rewinds input file. -*/ -int ZEXPORT gzrewind (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'r') return -1; - - s->z_err = Z_OK; - s->z_eof = 0; - s->stream.avail_in = 0; - s->stream.next_in = s->inbuf; - s->crc = crc32(0L, Z_NULL, 0); - - if (s->startpos == 0) { /* not a compressed file */ - rewind(s->file); - return 0; - } - - (void) inflateReset(&s->stream); - return fseek(s->file, s->startpos, SEEK_SET); -} - -/* =========================================================================== - Returns the starting position for the next gzread or gzwrite on the - given compressed file. This position represents a number of bytes in the - uncompressed data stream. -*/ -z_off_t ZEXPORT gztell (file) - gzFile file; -{ - return gzseek(file, 0L, SEEK_CUR); -} - -/* =========================================================================== - Returns 1 when EOF has previously been detected reading the given - input stream, otherwise zero. -*/ -int ZEXPORT gzeof (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - return (s == NULL || s->mode != 'r') ? 0 : s->z_eof; -} - -/* =========================================================================== - Outputs a long in LSB order to the given file -*/ -local void putLong (file, x) - FILE *file; - uLong x; -{ - int n; - for (n = 0; n < 4; n++) { - fputc((int)(x & 0xff), file); - x >>= 8; - } -} - -/* =========================================================================== - Reads a long in LSB order from the given gz_stream. Sets z_err in case - of error. -*/ -local uLong getLong (s) - gz_stream *s; -{ - uLong x = (uLong)get_byte(s); - int c; - - x += ((uLong)get_byte(s))<<8; - x += ((uLong)get_byte(s))<<16; - c = get_byte(s); - if (c == EOF) s->z_err = Z_DATA_ERROR; - x += ((uLong)c)<<24; - return x; -} - -/* =========================================================================== - Flushes all pending output if necessary, closes the compressed file - and deallocates all the (de)compression state. -*/ -int ZEXPORT gzclose (file) - gzFile file; -{ - int err; - gz_stream *s = (gz_stream*)file; - - if (s == NULL) return Z_STREAM_ERROR; - - if (s->mode == 'w') { -#ifdef NO_DEFLATE - return Z_STREAM_ERROR; -#else - err = do_flush (file, Z_FINISH); - if (err != Z_OK) return destroy((gz_stream*)file); - - putLong (s->file, s->crc); - putLong (s->file, s->stream.total_in); -#endif - } - return destroy((gz_stream*)file); -} - -/* =========================================================================== - Returns the error message for the last error which occured on the - given compressed file. errnum is set to zlib error number. If an - error occured in the file system and not in the compression library, - errnum is set to Z_ERRNO and the application may consult errno - to get the exact error code. -*/ -const char* ZEXPORT gzerror (file, errnum) - gzFile file; - int *errnum; -{ - char *m; - gz_stream *s = (gz_stream*)file; - - if (s == NULL) { - *errnum = Z_STREAM_ERROR; - return (const char*)ERR_MSG(Z_STREAM_ERROR); - } - *errnum = s->z_err; - if (*errnum == Z_OK) return (const char*)""; - - m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); - - if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); - - TRYFREE(s->msg); - s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); - strcpy(s->msg, s->path); - strcat(s->msg, ": "); - strcat(s->msg, m); - return (const char*)s->msg; -} diff --git a/ZLIB/gzlib.c b/ZLIB/gzlib.c new file mode 100644 index 00000000..983153cc --- /dev/null +++ b/ZLIB/gzlib.c @@ -0,0 +1,582 @@ +/* gzlib.c -- zlib functions common to reading and writing gzip files + * Copyright (C) 2004-2024 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +#if defined(_WIN32) && !defined(__BORLANDC__) +# define LSEEK _lseeki64 +#else +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +# define LSEEK lseek64 +#else +# define LSEEK lseek +#endif +#endif + +#if defined UNDER_CE + +/* Map the Windows error number in ERROR to a locale-dependent error message + string and return a pointer to it. Typically, the values for ERROR come + from GetLastError. + + The string pointed to shall not be modified by the application, but may be + overwritten by a subsequent call to gz_strwinerror + + The gz_strwinerror function does not change the current setting of + GetLastError. */ +char ZLIB_INTERNAL *gz_strwinerror(DWORD error) { + static char buf[1024]; + + wchar_t *msgbuf; + DWORD lasterr = GetLastError(); + DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + error, + 0, /* Default language */ + (LPVOID)&msgbuf, + 0, + NULL); + if (chars != 0) { + /* If there is an \r\n appended, zap it. */ + if (chars >= 2 + && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { + chars -= 2; + msgbuf[chars] = 0; + } + + if (chars > sizeof (buf) - 1) { + chars = sizeof (buf) - 1; + msgbuf[chars] = 0; + } + + wcstombs(buf, msgbuf, chars + 1); + LocalFree(msgbuf); + } + else { + sprintf(buf, "unknown win32 error (%ld)", error); + } + + SetLastError(lasterr); + return buf; +} + +#endif /* UNDER_CE */ + +/* Reset gzip file state */ +local void gz_reset(gz_statep state) { + state->x.have = 0; /* no output data available */ + if (state->mode == GZ_READ) { /* for reading ... */ + state->eof = 0; /* not at end of file */ + state->past = 0; /* have not read past end yet */ + state->how = LOOK; /* look for gzip header */ + } + else /* for writing ... */ + state->reset = 0; /* no deflateReset pending */ + state->seek = 0; /* no seek request pending */ + gz_error(state, Z_OK, NULL); /* clear error */ + state->x.pos = 0; /* no uncompressed data yet */ + state->strm.avail_in = 0; /* no input data yet */ +} + +/* Open a gzip file either by name or file descriptor. */ +local gzFile gz_open(const void *path, int fd, const char *mode) { + gz_statep state; + z_size_t len; + int oflag; +#ifdef O_CLOEXEC + int cloexec = 0; +#endif +#ifdef O_EXCL + int exclusive = 0; +#endif + + /* check input */ + if (path == NULL) + return NULL; + + /* allocate gzFile structure to return */ + state = (gz_statep)malloc(sizeof(gz_state)); + if (state == NULL) + return NULL; + state->size = 0; /* no buffers allocated yet */ + state->want = GZBUFSIZE; /* requested buffer size */ + state->msg = NULL; /* no error message yet */ + + /* interpret mode */ + state->mode = GZ_NONE; + state->level = Z_DEFAULT_COMPRESSION; + state->strategy = Z_DEFAULT_STRATEGY; + state->direct = 0; + while (*mode) { + if (*mode >= '0' && *mode <= '9') + state->level = *mode - '0'; + else + switch (*mode) { + case 'r': + state->mode = GZ_READ; + break; +#ifndef NO_GZCOMPRESS + case 'w': + state->mode = GZ_WRITE; + break; + case 'a': + state->mode = GZ_APPEND; + break; +#endif + case '+': /* can't read and write at the same time */ + free(state); + return NULL; + case 'b': /* ignore -- will request binary anyway */ + break; +#ifdef O_CLOEXEC + case 'e': + cloexec = 1; + break; +#endif +#ifdef O_EXCL + case 'x': + exclusive = 1; + break; +#endif + case 'f': + state->strategy = Z_FILTERED; + break; + case 'h': + state->strategy = Z_HUFFMAN_ONLY; + break; + case 'R': + state->strategy = Z_RLE; + break; + case 'F': + state->strategy = Z_FIXED; + break; + case 'T': + state->direct = 1; + break; + default: /* could consider as an error, but just ignore */ + ; + } + mode++; + } + + /* must provide an "r", "w", or "a" */ + if (state->mode == GZ_NONE) { + free(state); + return NULL; + } + + /* can't force transparent read */ + if (state->mode == GZ_READ) { + if (state->direct) { + free(state); + return NULL; + } + state->direct = 1; /* for empty file */ + } + + /* save the path name for error messages */ +#ifdef WIDECHAR + if (fd == -2) { + len = wcstombs(NULL, path, 0); + if (len == (z_size_t)-1) + len = 0; + } + else +#endif + len = strlen((const char *)path); + state->path = (char *)malloc(len + 1); + if (state->path == NULL) { + free(state); + return NULL; + } +#ifdef WIDECHAR + if (fd == -2) + if (len) + wcstombs(state->path, path, len + 1); + else + *(state->path) = 0; + else +#endif +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + (void)snprintf(state->path, len + 1, "%s", (const char *)path); +#else + strcpy(state->path, path); +#endif + + /* compute the flags for open() */ + oflag = +#ifdef O_LARGEFILE + O_LARGEFILE | +#endif +#ifdef O_BINARY + O_BINARY | +#endif +#ifdef O_CLOEXEC + (cloexec ? O_CLOEXEC : 0) | +#endif + (state->mode == GZ_READ ? + O_RDONLY : + (O_WRONLY | O_CREAT | +#ifdef O_EXCL + (exclusive ? O_EXCL : 0) | +#endif + (state->mode == GZ_WRITE ? + O_TRUNC : + O_APPEND))); + + /* open the file with the appropriate flags (or just use fd) */ + state->fd = fd > -1 ? fd : ( +#ifdef WIDECHAR + fd == -2 ? _wopen(path, oflag, 0666) : +#endif + open((const char *)path, oflag, 0666)); + if (state->fd == -1) { + free(state->path); + free(state); + return NULL; + } + if (state->mode == GZ_APPEND) { + LSEEK(state->fd, 0, SEEK_END); /* so gzoffset() is correct */ + state->mode = GZ_WRITE; /* simplify later checks */ + } + + /* save the current position for rewinding (only if reading) */ + if (state->mode == GZ_READ) { + state->start = LSEEK(state->fd, 0, SEEK_CUR); + if (state->start == -1) state->start = 0; + } + + /* initialize stream */ + gz_reset(state); + + /* return stream */ + return (gzFile)state; +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzopen(const char *path, const char *mode) { + return gz_open(path, -1, mode); +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzopen64(const char *path, const char *mode) { + return gz_open(path, -1, mode); +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzdopen(int fd, const char *mode) { + char *path; /* identifier for error messages */ + gzFile gz; + + if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL) + return NULL; +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + (void)snprintf(path, 7 + 3 * sizeof(int), "", fd); +#else + sprintf(path, "", fd); /* for debugging */ +#endif + gz = gz_open(path, fd, mode); + free(path); + return gz; +} + +/* -- see zlib.h -- */ +#ifdef WIDECHAR +gzFile ZEXPORT gzopen_w(const wchar_t *path, const char *mode) { + return gz_open(path, -2, mode); +} +#endif + +/* -- see zlib.h -- */ +int ZEXPORT gzbuffer(gzFile file, unsigned size) { + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* make sure we haven't already allocated memory */ + if (state->size != 0) + return -1; + + /* check and set requested size */ + if ((size << 1) < size) + return -1; /* need to be able to double it */ + if (size < 8) + size = 8; /* needed to behave well with flushing */ + state->want = size; + return 0; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzrewind(gzFile file) { + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* back up and start over */ + if (LSEEK(state->fd, state->start, SEEK_SET) == -1) + return -1; + gz_reset(state); + return 0; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) { + unsigned n; + z_off64_t ret; + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* check that there's no error */ + if (state->err != Z_OK && state->err != Z_BUF_ERROR) + return -1; + + /* can only seek from start or relative to current position */ + if (whence != SEEK_SET && whence != SEEK_CUR) + return -1; + + /* normalize offset to a SEEK_CUR specification */ + if (whence == SEEK_SET) + offset -= state->x.pos; + else if (state->seek) + offset += state->skip; + state->seek = 0; + + /* if within raw area while reading, just go there */ + if (state->mode == GZ_READ && state->how == COPY && + state->x.pos + offset >= 0) { + ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR); + if (ret == -1) + return -1; + state->x.have = 0; + state->eof = 0; + state->past = 0; + state->seek = 0; + gz_error(state, Z_OK, NULL); + state->strm.avail_in = 0; + state->x.pos += offset; + return state->x.pos; + } + + /* calculate skip amount, rewinding if needed for back seek when reading */ + if (offset < 0) { + if (state->mode != GZ_READ) /* writing -- can't go backwards */ + return -1; + offset += state->x.pos; + if (offset < 0) /* before start of file! */ + return -1; + if (gzrewind(file) == -1) /* rewind, then skip to offset */ + return -1; + } + + /* if reading, skip what's in output buffer (one less gzgetc() check) */ + if (state->mode == GZ_READ) { + n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ? + (unsigned)offset : state->x.have; + state->x.have -= n; + state->x.next += n; + state->x.pos += n; + offset -= n; + } + + /* request skip (if not zero) */ + if (offset) { + state->seek = 1; + state->skip = offset; + } + return state->x.pos + offset; +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gzseek(gzFile file, z_off_t offset, int whence) { + z_off64_t ret; + + ret = gzseek64(file, (z_off64_t)offset, whence); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gztell64(gzFile file) { + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* return position */ + return state->x.pos + (state->seek ? state->skip : 0); +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gztell(gzFile file) { + z_off64_t ret; + + ret = gztell64(file); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gzoffset64(gzFile file) { + z_off64_t offset; + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* compute and return effective offset in file */ + offset = LSEEK(state->fd, 0, SEEK_CUR); + if (offset == -1) + return -1; + if (state->mode == GZ_READ) /* reading */ + offset -= state->strm.avail_in; /* don't count buffered input */ + return offset; +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gzoffset(gzFile file) { + z_off64_t ret; + + ret = gzoffset64(file); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzeof(gzFile file) { + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return 0; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return 0; + + /* return end-of-file state */ + return state->mode == GZ_READ ? state->past : 0; +} + +/* -- see zlib.h -- */ +const char * ZEXPORT gzerror(gzFile file, int *errnum) { + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return NULL; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return NULL; + + /* return error information */ + if (errnum != NULL) + *errnum = state->err; + return state->err == Z_MEM_ERROR ? "out of memory" : + (state->msg == NULL ? "" : state->msg); +} + +/* -- see zlib.h -- */ +void ZEXPORT gzclearerr(gzFile file) { + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return; + + /* clear error and end-of-file */ + if (state->mode == GZ_READ) { + state->eof = 0; + state->past = 0; + } + gz_error(state, Z_OK, NULL); +} + +/* Create an error message in allocated memory and set state->err and + state->msg accordingly. Free any previous error message already there. Do + not try to free or allocate space if the error is Z_MEM_ERROR (out of + memory). Simply save the error message as a static string. If there is an + allocation failure constructing the error message, then convert the error to + out of memory. */ +void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) { + /* free previously allocated message and clear */ + if (state->msg != NULL) { + if (state->err != Z_MEM_ERROR) + free(state->msg); + state->msg = NULL; + } + + /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */ + if (err != Z_OK && err != Z_BUF_ERROR) + state->x.have = 0; + + /* set error code, and if no message, then done */ + state->err = err; + if (msg == NULL) + return; + + /* for an out of memory error, return literal string when requested */ + if (err == Z_MEM_ERROR) + return; + + /* construct error message with path */ + if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) == + NULL) { + state->err = Z_MEM_ERROR; + return; + } +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, + "%s%s%s", state->path, ": ", msg); +#else + strcpy(state->msg, state->path); + strcat(state->msg, ": "); + strcat(state->msg, msg); +#endif +} + +/* portably return maximum value for an int (when limits.h presumed not + available) -- we need to do this to cover cases where 2's complement not + used, since C standard permits 1's complement and sign-bit representations, + otherwise we could just use ((unsigned)-1) >> 1 */ +unsigned ZLIB_INTERNAL gz_intmax(void) { +#ifdef INT_MAX + return INT_MAX; +#else + unsigned p = 1, q; + do { + q = p; + p <<= 1; + p++; + } while (p > q); + return q >> 1; +#endif +} diff --git a/ZLIB/gzread.c b/ZLIB/gzread.c new file mode 100644 index 00000000..4168cbc8 --- /dev/null +++ b/ZLIB/gzread.c @@ -0,0 +1,602 @@ +/* gzread.c -- zlib functions for reading gzip files + * Copyright (C) 2004-2017 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from + state->fd, and update state->eof, state->err, and state->msg as appropriate. + This function needs to loop on read(), since read() is not guaranteed to + read the number of bytes requested, depending on the type of descriptor. */ +local int gz_load(gz_statep state, unsigned char *buf, unsigned len, + unsigned *have) { + int ret; + unsigned get, max = ((unsigned)-1 >> 2) + 1; + + *have = 0; + do { + get = len - *have; + if (get > max) + get = max; + ret = read(state->fd, buf + *have, get); + if (ret <= 0) + break; + *have += (unsigned)ret; + } while (*have < len); + if (ret < 0) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + if (ret == 0) + state->eof = 1; + return 0; +} + +/* Load up input buffer and set eof flag if last data loaded -- return -1 on + error, 0 otherwise. Note that the eof flag is set when the end of the input + file is reached, even though there may be unused data in the buffer. Once + that data has been used, no more attempts will be made to read the file. + If strm->avail_in != 0, then the current data is moved to the beginning of + the input buffer, and then the remainder of the buffer is loaded with the + available data from the input file. */ +local int gz_avail(gz_statep state) { + unsigned got; + z_streamp strm = &(state->strm); + + if (state->err != Z_OK && state->err != Z_BUF_ERROR) + return -1; + if (state->eof == 0) { + if (strm->avail_in) { /* copy what's there to the start */ + unsigned char *p = state->in; + unsigned const char *q = strm->next_in; + unsigned n = strm->avail_in; + do { + *p++ = *q++; + } while (--n); + } + if (gz_load(state, state->in + strm->avail_in, + state->size - strm->avail_in, &got) == -1) + return -1; + strm->avail_in += got; + strm->next_in = state->in; + } + return 0; +} + +/* Look for gzip header, set up for inflate or copy. state->x.have must be 0. + If this is the first time in, allocate required memory. state->how will be + left unchanged if there is no more input data available, will be set to COPY + if there is no gzip header and direct copying will be performed, or it will + be set to GZIP for decompression. If direct copying, then leftover input + data from the input buffer will be copied to the output buffer. In that + case, all further file reads will be directly to either the output buffer or + a user buffer. If decompressing, the inflate state will be initialized. + gz_look() will return 0 on success or -1 on failure. */ +local int gz_look(gz_statep state) { + z_streamp strm = &(state->strm); + + /* allocate read buffers and inflate memory */ + if (state->size == 0) { + /* allocate buffers */ + state->in = (unsigned char *)malloc(state->want); + state->out = (unsigned char *)malloc(state->want << 1); + if (state->in == NULL || state->out == NULL) { + free(state->out); + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + state->size = state->want; + + /* allocate inflate memory */ + state->strm.zalloc = Z_NULL; + state->strm.zfree = Z_NULL; + state->strm.opaque = Z_NULL; + state->strm.avail_in = 0; + state->strm.next_in = Z_NULL; + if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) { /* gunzip */ + free(state->out); + free(state->in); + state->size = 0; + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + } + + /* get at least the magic bytes in the input buffer */ + if (strm->avail_in < 2) { + if (gz_avail(state) == -1) + return -1; + if (strm->avail_in == 0) + return 0; + } + + /* look for gzip magic bytes -- if there, do gzip decoding (note: there is + a logical dilemma here when considering the case of a partially written + gzip file, to wit, if a single 31 byte is written, then we cannot tell + whether this is a single-byte file, or just a partially written gzip + file -- for here we assume that if a gzip file is being written, then + the header will be written in a single operation, so that reading a + single byte is sufficient indication that it is not a gzip file) */ + if (strm->avail_in > 1 && + strm->next_in[0] == 31 && strm->next_in[1] == 139) { + inflateReset(strm); + state->how = GZIP; + state->direct = 0; + return 0; + } + + /* no gzip header -- if we were decoding gzip before, then this is trailing + garbage. Ignore the trailing garbage and finish. */ + if (state->direct == 0) { + strm->avail_in = 0; + state->eof = 1; + state->x.have = 0; + return 0; + } + + /* doing raw i/o, copy any leftover input to output -- this assumes that + the output buffer is larger than the input buffer, which also assures + space for gzungetc() */ + state->x.next = state->out; + memcpy(state->x.next, strm->next_in, strm->avail_in); + state->x.have = strm->avail_in; + strm->avail_in = 0; + state->how = COPY; + state->direct = 1; + return 0; +} + +/* Decompress from input to the provided next_out and avail_out in the state. + On return, state->x.have and state->x.next point to the just decompressed + data. If the gzip stream completes, state->how is reset to LOOK to look for + the next gzip stream or raw data, once state->x.have is depleted. Returns 0 + on success, -1 on failure. */ +local int gz_decomp(gz_statep state) { + int ret = Z_OK; + unsigned had; + z_streamp strm = &(state->strm); + + /* fill output buffer up to end of deflate stream */ + had = strm->avail_out; + do { + /* get more input for inflate() */ + if (strm->avail_in == 0 && gz_avail(state) == -1) + return -1; + if (strm->avail_in == 0) { + gz_error(state, Z_BUF_ERROR, "unexpected end of file"); + break; + } + + /* decompress and handle errors */ + ret = inflate(strm, Z_NO_FLUSH); + if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { + gz_error(state, Z_STREAM_ERROR, + "internal error: inflate stream corrupt"); + return -1; + } + if (ret == Z_MEM_ERROR) { + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ + gz_error(state, Z_DATA_ERROR, + strm->msg == NULL ? "compressed data error" : strm->msg); + return -1; + } + } while (strm->avail_out && ret != Z_STREAM_END); + + /* update available output */ + state->x.have = had - strm->avail_out; + state->x.next = strm->next_out - state->x.have; + + /* if the gzip stream completed successfully, look for another */ + if (ret == Z_STREAM_END) + state->how = LOOK; + + /* good decompression */ + return 0; +} + +/* Fetch data and put it in the output buffer. Assumes state->x.have is 0. + Data is either copied from the input file or decompressed from the input + file depending on state->how. If state->how is LOOK, then a gzip header is + looked for to determine whether to copy or decompress. Returns -1 on error, + otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the + end of the input file has been reached and all data has been processed. */ +local int gz_fetch(gz_statep state) { + z_streamp strm = &(state->strm); + + do { + switch(state->how) { + case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */ + if (gz_look(state) == -1) + return -1; + if (state->how == LOOK) + return 0; + break; + case COPY: /* -> COPY */ + if (gz_load(state, state->out, state->size << 1, &(state->x.have)) + == -1) + return -1; + state->x.next = state->out; + return 0; + case GZIP: /* -> GZIP or LOOK (if end of gzip stream) */ + strm->avail_out = state->size << 1; + strm->next_out = state->out; + if (gz_decomp(state) == -1) + return -1; + } + } while (state->x.have == 0 && (!state->eof || strm->avail_in)); + return 0; +} + +/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ +local int gz_skip(gz_statep state, z_off64_t len) { + unsigned n; + + /* skip over len bytes or reach end-of-file, whichever comes first */ + while (len) + /* skip over whatever is in output buffer */ + if (state->x.have) { + n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ? + (unsigned)len : state->x.have; + state->x.have -= n; + state->x.next += n; + state->x.pos += n; + len -= n; + } + + /* output buffer empty -- return if we're at the end of the input */ + else if (state->eof && state->strm.avail_in == 0) + break; + + /* need more data to skip -- load up output buffer */ + else { + /* get more output, looking for header if required */ + if (gz_fetch(state) == -1) + return -1; + } + return 0; +} + +/* Read len bytes into buf from file, or less than len up to the end of the + input. Return the number of bytes read. If zero is returned, either the + end of file was reached, or there was an error. state->err must be + consulted in that case to determine which. */ +local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) { + z_size_t got; + unsigned n; + + /* if len is zero, avoid unnecessary operations */ + if (len == 0) + return 0; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return 0; + } + + /* get len bytes to buf, or less than len if at the end */ + got = 0; + do { + /* set n to the maximum amount of len that fits in an unsigned int */ + n = (unsigned)-1; + if (n > len) + n = (unsigned)len; + + /* first just try copying data from the output buffer */ + if (state->x.have) { + if (state->x.have < n) + n = state->x.have; + memcpy(buf, state->x.next, n); + state->x.next += n; + state->x.have -= n; + } + + /* output buffer empty -- return if we're at the end of the input */ + else if (state->eof && state->strm.avail_in == 0) { + state->past = 1; /* tried to read past end */ + break; + } + + /* need output data -- for small len or new stream load up our output + buffer */ + else if (state->how == LOOK || n < (state->size << 1)) { + /* get more output, looking for header if required */ + if (gz_fetch(state) == -1) + return 0; + continue; /* no progress yet -- go back to copy above */ + /* the copy above assures that we will leave with space in the + output buffer, allowing at least one gzungetc() to succeed */ + } + + /* large len -- read directly into user buffer */ + else if (state->how == COPY) { /* read directly */ + if (gz_load(state, (unsigned char *)buf, n, &n) == -1) + return 0; + } + + /* large len -- decompress directly into user buffer */ + else { /* state->how == GZIP */ + state->strm.avail_out = n; + state->strm.next_out = (unsigned char *)buf; + if (gz_decomp(state) == -1) + return 0; + n = state->x.have; + state->x.have = 0; + } + + /* update progress */ + len -= n; + buf = (char *)buf + n; + got += n; + state->x.pos += n; + } while (len); + + /* return number of bytes read into user buffer */ + return got; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzread(gzFile file, voidp buf, unsigned len) { + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* since an int is returned, make sure len fits in one, otherwise return + with an error (this avoids a flaw in the interface) */ + if ((int)len < 0) { + gz_error(state, Z_STREAM_ERROR, "request does not fit in an int"); + return -1; + } + + /* read len or fewer bytes to buf */ + len = (unsigned)gz_read(state, buf, len); + + /* check for an error */ + if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR) + return -1; + + /* return the number of bytes read (this is assured to fit in an int) */ + return (int)len; +} + +/* -- see zlib.h -- */ +z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems, gzFile file) { + z_size_t len; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return 0; + + /* compute bytes to read -- error on overflow */ + len = nitems * size; + if (size && len / size != nitems) { + gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); + return 0; + } + + /* read len or fewer bytes to buf, return the number of full items read */ + return len ? gz_read(state, buf, len) / size : 0; +} + +/* -- see zlib.h -- */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +#else +# undef gzgetc +#endif +int ZEXPORT gzgetc(gzFile file) { + unsigned char buf[1]; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* try output buffer (no need to check for skip request) */ + if (state->x.have) { + state->x.have--; + state->x.pos++; + return *(state->x.next)++; + } + + /* nothing there -- try gz_read() */ + return gz_read(state, buf, 1) < 1 ? -1 : buf[0]; +} + +int ZEXPORT gzgetc_(gzFile file) { + return gzgetc(file); +} + +/* -- see zlib.h -- */ +int ZEXPORT gzungetc(int c, gzFile file) { + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* in case this was just opened, set up the input buffer */ + if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) + (void)gz_look(state); + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return -1; + } + + /* can't push EOF */ + if (c < 0) + return -1; + + /* if output buffer empty, put byte at end (allows more pushing) */ + if (state->x.have == 0) { + state->x.have = 1; + state->x.next = state->out + (state->size << 1) - 1; + state->x.next[0] = (unsigned char)c; + state->x.pos--; + state->past = 0; + return c; + } + + /* if no room, give up (must have already done a gzungetc()) */ + if (state->x.have == (state->size << 1)) { + gz_error(state, Z_DATA_ERROR, "out of room to push characters"); + return -1; + } + + /* slide output data if needed and insert byte before existing data */ + if (state->x.next == state->out) { + unsigned char *src = state->out + state->x.have; + unsigned char *dest = state->out + (state->size << 1); + while (src > state->out) + *--dest = *--src; + state->x.next = dest; + } + state->x.have++; + state->x.next--; + state->x.next[0] = (unsigned char)c; + state->x.pos--; + state->past = 0; + return c; +} + +/* -- see zlib.h -- */ +char * ZEXPORT gzgets(gzFile file, char *buf, int len) { + unsigned left, n; + char *str; + unsigned char *eol; + gz_statep state; + + /* check parameters and get internal structure */ + if (file == NULL || buf == NULL || len < 1) + return NULL; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return NULL; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return NULL; + } + + /* copy output bytes up to new line or len - 1, whichever comes first -- + append a terminating zero to the string (we don't check for a zero in + the contents, let the user worry about that) */ + str = buf; + left = (unsigned)len - 1; + if (left) do { + /* assure that something is in the output buffer */ + if (state->x.have == 0 && gz_fetch(state) == -1) + return NULL; /* error */ + if (state->x.have == 0) { /* end of file */ + state->past = 1; /* read past end */ + break; /* return what we have */ + } + + /* look for end-of-line in current output buffer */ + n = state->x.have > left ? left : state->x.have; + eol = (unsigned char *)memchr(state->x.next, '\n', n); + if (eol != NULL) + n = (unsigned)(eol - state->x.next) + 1; + + /* copy through end-of-line, or remainder if not found */ + memcpy(buf, state->x.next, n); + state->x.have -= n; + state->x.next += n; + state->x.pos += n; + left -= n; + buf += n; + } while (left && eol == NULL); + + /* return terminated string, or if nothing, end of file */ + if (buf == str) + return NULL; + buf[0] = 0; + return str; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzdirect(gzFile file) { + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* if the state is not known, but we can find out, then do so (this is + mainly for right after a gzopen() or gzdopen()) */ + if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) + (void)gz_look(state); + + /* return 1 if transparent, 0 if processing a gzip stream */ + return state->direct; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzclose_r(gzFile file) { + int ret, err; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + /* check that we're reading */ + if (state->mode != GZ_READ) + return Z_STREAM_ERROR; + + /* free memory and close file */ + if (state->size) { + inflateEnd(&(state->strm)); + free(state->out); + free(state->in); + } + err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK; + gz_error(state, Z_OK, NULL); + free(state->path); + ret = close(state->fd); + free(state); + return ret ? Z_ERRNO : err; +} diff --git a/ZLIB/gzwrite.c b/ZLIB/gzwrite.c new file mode 100644 index 00000000..435b4621 --- /dev/null +++ b/ZLIB/gzwrite.c @@ -0,0 +1,631 @@ +/* gzwrite.c -- zlib functions for writing gzip files + * Copyright (C) 2004-2019 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* Initialize state for writing a gzip file. Mark initialization by setting + state->size to non-zero. Return -1 on a memory allocation failure, or 0 on + success. */ +local int gz_init(gz_statep state) { + int ret; + z_streamp strm = &(state->strm); + + /* allocate input buffer (double size for gzprintf) */ + state->in = (unsigned char *)malloc(state->want << 1); + if (state->in == NULL) { + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + + /* only need output buffer and deflate state if compressing */ + if (!state->direct) { + /* allocate output buffer */ + state->out = (unsigned char *)malloc(state->want); + if (state->out == NULL) { + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + + /* allocate deflate memory, set up for gzip compression */ + strm->zalloc = Z_NULL; + strm->zfree = Z_NULL; + strm->opaque = Z_NULL; + ret = deflateInit2(strm, state->level, Z_DEFLATED, + MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy); + if (ret != Z_OK) { + free(state->out); + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + strm->next_in = NULL; + } + + /* mark state as initialized */ + state->size = state->want; + + /* initialize write buffer if compressing */ + if (!state->direct) { + strm->avail_out = state->size; + strm->next_out = state->out; + state->x.next = strm->next_out; + } + return 0; +} + +/* Compress whatever is at avail_in and next_in and write to the output file. + Return -1 if there is an error writing to the output file or if gz_init() + fails to allocate memory, otherwise 0. flush is assumed to be a valid + deflate() flush value. If flush is Z_FINISH, then the deflate() state is + reset to start a new gzip stream. If gz->direct is true, then simply write + to the output file without compressing, and ignore flush. */ +local int gz_comp(gz_statep state, int flush) { + int ret, writ; + unsigned have, put, max = ((unsigned)-1 >> 2) + 1; + z_streamp strm = &(state->strm); + + /* allocate memory if this is the first time through */ + if (state->size == 0 && gz_init(state) == -1) + return -1; + + /* write directly if requested */ + if (state->direct) { + while (strm->avail_in) { + put = strm->avail_in > max ? max : strm->avail_in; + writ = write(state->fd, strm->next_in, put); + if (writ < 0) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + strm->avail_in -= (unsigned)writ; + strm->next_in += writ; + } + return 0; + } + + /* check for a pending reset */ + if (state->reset) { + /* don't start a new gzip member unless there is data to write */ + if (strm->avail_in == 0) + return 0; + deflateReset(strm); + state->reset = 0; + } + + /* run deflate() on provided input until it produces no more output */ + ret = Z_OK; + do { + /* write out current buffer contents if full, or if flushing, but if + doing Z_FINISH then don't write until we get to Z_STREAM_END */ + if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && + (flush != Z_FINISH || ret == Z_STREAM_END))) { + while (strm->next_out > state->x.next) { + put = strm->next_out - state->x.next > (int)max ? max : + (unsigned)(strm->next_out - state->x.next); + writ = write(state->fd, state->x.next, put); + if (writ < 0) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + state->x.next += writ; + } + if (strm->avail_out == 0) { + strm->avail_out = state->size; + strm->next_out = state->out; + state->x.next = state->out; + } + } + + /* compress */ + have = strm->avail_out; + ret = deflate(strm, flush); + if (ret == Z_STREAM_ERROR) { + gz_error(state, Z_STREAM_ERROR, + "internal error: deflate stream corrupt"); + return -1; + } + have -= strm->avail_out; + } while (have); + + /* if that completed a deflate stream, allow another to start */ + if (flush == Z_FINISH) + state->reset = 1; + + /* all done, no errors */ + return 0; +} + +/* Compress len zeros to output. Return -1 on a write error or memory + allocation failure by gz_comp(), or 0 on success. */ +local int gz_zero(gz_statep state, z_off64_t len) { + int first; + unsigned n; + z_streamp strm = &(state->strm); + + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return -1; + + /* compress len zeros (len guaranteed > 0) */ + first = 1; + while (len) { + n = GT_OFF(state->size) || (z_off64_t)state->size > len ? + (unsigned)len : state->size; + if (first) { + memset(state->in, 0, n); + first = 0; + } + strm->avail_in = n; + strm->next_in = state->in; + state->x.pos += n; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return -1; + len -= n; + } + return 0; +} + +/* Write len bytes from buf to file. Return the number of bytes written. If + the returned value is less than len, then there was an error. */ +local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) { + z_size_t put = len; + + /* if len is zero, avoid unnecessary operations */ + if (len == 0) + return 0; + + /* allocate memory if this is the first time through */ + if (state->size == 0 && gz_init(state) == -1) + return 0; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return 0; + } + + /* for small len, copy to input buffer, otherwise compress directly */ + if (len < state->size) { + /* copy to input buffer, compress when full */ + do { + unsigned have, copy; + + if (state->strm.avail_in == 0) + state->strm.next_in = state->in; + have = (unsigned)((state->strm.next_in + state->strm.avail_in) - + state->in); + copy = state->size - have; + if (copy > len) + copy = (unsigned)len; + memcpy(state->in + have, buf, copy); + state->strm.avail_in += copy; + state->x.pos += copy; + buf = (const char *)buf + copy; + len -= copy; + if (len && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + } while (len); + } + else { + /* consume whatever's left in the input buffer */ + if (state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + + /* directly compress user buffer to file */ + state->strm.next_in = (z_const Bytef *)buf; + do { + unsigned n = (unsigned)-1; + if (n > len) + n = (unsigned)len; + state->strm.avail_in = n; + state->x.pos += n; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + len -= n; + } while (len); + } + + /* input was all buffered or compressed */ + return put; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len) { + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* since an int is returned, make sure len fits in one, otherwise return + with an error (this avoids a flaw in the interface) */ + if ((int)len < 0) { + gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); + return 0; + } + + /* write len bytes from buf (the return value will fit in an int) */ + return (int)gz_write(state, buf, len); +} + +/* -- see zlib.h -- */ +z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, z_size_t nitems, + gzFile file) { + z_size_t len; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* compute bytes to read -- error on overflow */ + len = nitems * size; + if (size && len / size != nitems) { + gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); + return 0; + } + + /* write len bytes to buf, return the number of full items written */ + return len ? gz_write(state, buf, len) / size : 0; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzputc(gzFile file, int c) { + unsigned have; + unsigned char buf[1]; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return -1; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return -1; + } + + /* try writing to input buffer for speed (state->size == 0 if buffer not + initialized) */ + if (state->size) { + if (strm->avail_in == 0) + strm->next_in = state->in; + have = (unsigned)((strm->next_in + strm->avail_in) - state->in); + if (have < state->size) { + state->in[have] = (unsigned char)c; + strm->avail_in++; + state->x.pos++; + return c & 0xff; + } + } + + /* no room in buffer or not initialized, use gz_write() */ + buf[0] = (unsigned char)c; + if (gz_write(state, buf, 1) != 1) + return -1; + return c & 0xff; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzputs(gzFile file, const char *s) { + z_size_t len, put; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return -1; + + /* write string */ + len = strlen(s); + if ((int)len < 0 || (unsigned)len != len) { + gz_error(state, Z_STREAM_ERROR, "string length does not fit in int"); + return -1; + } + put = gz_write(state, s, len); + return put < len ? -1 : (int)len; +} + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +#include + +/* -- see zlib.h -- */ +int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) { + int len; + unsigned left; + char *next; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* make sure we have some buffer space */ + if (state->size == 0 && gz_init(state) == -1) + return state->err; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return state->err; + } + + /* do the printf() into the input buffer, put length in len -- the input + buffer is double-sized just for this function, so there is guaranteed to + be state->size bytes available after the current contents */ + if (strm->avail_in == 0) + strm->next_in = state->in; + next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in); + next[state->size - 1] = 0; +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(next, format, va); + for (len = 0; len < state->size; len++) + if (next[len] == 0) break; +# else + len = vsprintf(next, format, va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(next, state->size, format, va); + len = strlen(next); +# else + len = vsnprintf(next, state->size, format, va); +# endif +#endif + + /* check that printf() results fit in buffer */ + if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0) + return 0; + + /* update buffer and position, compress first half if past that */ + strm->avail_in += (unsigned)len; + state->x.pos += len; + if (strm->avail_in >= state->size) { + left = strm->avail_in - state->size; + strm->avail_in = state->size; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return state->err; + memmove(state->in, state->in + state->size, left); + strm->next_in = state->in; + strm->avail_in = left; + } + return len; +} + +int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) { + va_list va; + int ret; + + va_start(va, format); + ret = gzvprintf(file, format, va); + va_end(va); + return ret; +} + +#else /* !STDC && !Z_HAVE_STDARG_H */ + +/* -- see zlib.h -- */ +int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3, + int a4, int a5, int a6, int a7, int a8, int a9, int a10, + int a11, int a12, int a13, int a14, int a15, int a16, + int a17, int a18, int a19, int a20) { + unsigned len, left; + char *next; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that can really pass pointer in ints */ + if (sizeof(int) != sizeof(void *)) + return Z_STREAM_ERROR; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* make sure we have some buffer space */ + if (state->size == 0 && gz_init(state) == -1) + return state->error; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return state->error; + } + + /* do the printf() into the input buffer, put length in len -- the input + buffer is double-sized just for this function, so there is guaranteed to + be state->size bytes available after the current contents */ + if (strm->avail_in == 0) + strm->next_in = state->in; + next = (char *)(strm->next_in + strm->avail_in); + next[state->size - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, + a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < size; len++) + if (next[len] == 0) + break; +# else + len = sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, + a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(next); +# else + len = snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + + /* check that printf() results fit in buffer */ + if (len == 0 || len >= state->size || next[state->size - 1] != 0) + return 0; + + /* update buffer and position, compress first half if past that */ + strm->avail_in += len; + state->x.pos += len; + if (strm->avail_in >= state->size) { + left = strm->avail_in - state->size; + strm->avail_in = state->size; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return state->err; + memmove(state->in, state->in + state->size, left); + strm->next_in = state->in; + strm->avail_in = left; + } + return (int)len; +} + +#endif + +/* -- see zlib.h -- */ +int ZEXPORT gzflush(gzFile file, int flush) { + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* check flush parameter */ + if (flush < 0 || flush > Z_FINISH) + return Z_STREAM_ERROR; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return state->err; + } + + /* compress remaining data with requested flush */ + (void)gz_comp(state, flush); + return state->err; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzsetparams(gzFile file, int level, int strategy) { + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK || state->direct) + return Z_STREAM_ERROR; + + /* if no change is requested, then do nothing */ + if (level == state->level && strategy == state->strategy) + return Z_OK; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return state->err; + } + + /* change compression parameters for subsequent input */ + if (state->size) { + /* flush previous input with previous parameters before changing */ + if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1) + return state->err; + deflateParams(strm, level, strategy); + } + state->level = level; + state->strategy = strategy; + return Z_OK; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzclose_w(gzFile file) { + int ret = Z_OK; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + /* check that we're writing */ + if (state->mode != GZ_WRITE) + return Z_STREAM_ERROR; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + ret = state->err; + } + + /* flush, free memory, and close file */ + if (gz_comp(state, Z_FINISH) == -1) + ret = state->err; + if (state->size) { + if (!state->direct) { + (void)deflateEnd(&(state->strm)); + free(state->out); + } + free(state->in); + } + gz_error(state, Z_OK, NULL); + free(state->path); + if (close(state->fd) == -1) + ret = Z_ERRNO; + free(state); + return ret; +} diff --git a/ZLIB/infback.c b/ZLIB/infback.c new file mode 100644 index 00000000..e7b25b30 --- /dev/null +++ b/ZLIB/infback.c @@ -0,0 +1,628 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2022 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits, + unsigned char FAR *window, const char *version, + int stream_size) { + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; + state->wbits = (uInt)windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->wnext = 0; + state->whave = 0; + state->sane = 1; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(struct inflate_state FAR *state) { +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc) { + struct inflate_state FAR *state; + z_const unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + /* fallthrough */ + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + state->length = (unsigned)here.val; + + /* process literal */ + if (here.op == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(here.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)here.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(here.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly */ + ret = Z_STREAM_END; + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: + /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Write leftover output and return unused input */ + inf_leave: + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left) && + ret == Z_STREAM_END) + ret = Z_BUF_ERROR; + } + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(z_streamp strm) { + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/ZLIB/infblock.c b/ZLIB/infblock.c deleted file mode 100644 index dd7a6d40..00000000 --- a/ZLIB/infblock.c +++ /dev/null @@ -1,403 +0,0 @@ -/* infblock.c -- interpret and process block types to last block - * Copyright (C) 1995-2002 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "infblock.h" -#include "inftrees.h" -#include "infcodes.h" -#include "infutil.h" - -struct inflate_codes_state {int dummy;}; /* for buggy compilers */ - -/* simplify the use of the inflate_huft type with some defines */ -#define exop word.what.Exop -#define bits word.what.Bits - -/* Table for deflate from PKZIP's appnote.txt. */ -local const uInt border[] = { /* Order of the bit length code lengths */ - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - -/* - Notes beyond the 1.93a appnote.txt: - - 1. Distance pointers never point before the beginning of the output - stream. - 2. Distance pointers can point back across blocks, up to 32k away. - 3. There is an implied maximum of 7 bits for the bit length table and - 15 bits for the actual data. - 4. If only one code exists, then it is encoded using one bit. (Zero - would be more efficient, but perhaps a little confusing.) If two - codes exist, they are coded using one bit each (0 and 1). - 5. There is no way of sending zero distance codes--a dummy must be - sent if there are none. (History: a pre 2.0 version of PKZIP would - store blocks with no distance codes, but this was discovered to be - too harsh a criterion.) Valid only for 1.93a. 2.04c does allow - zero distance codes, which is sent as one code of zero bits in - length. - 6. There are up to 286 literal/length codes. Code 256 represents the - end-of-block. Note however that the static length tree defines - 288 codes just to fill out the Huffman codes. Codes 286 and 287 - cannot be used though, since there is no length base or extra bits - defined for them. Similarily, there are up to 30 distance codes. - However, static trees define 32 codes (all 5 bits) to fill out the - Huffman codes, but the last two had better not show up in the data. - 7. Unzip can check dynamic Huffman blocks for complete code sets. - The exception is that a single code would not be complete (see #4). - 8. The five bits following the block type is really the number of - literal codes sent minus 257. - 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits - (1+6+6). Therefore, to output three times the length, you output - three codes (1+1+1), whereas to output four times the same length, - you only need two codes (1+3). Hmm. - 10. In the tree reconstruction algorithm, Code = Code + Increment - only if BitLength(i) is not zero. (Pretty obvious.) - 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) - 12. Note: length code 284 can represent 227-258, but length code 285 - really is 258. The last length deserves its own, short code - since it gets used a lot in very redundant files. The length - 258 is special since 258 - 3 (the min match length) is 255. - 13. The literal/length and distance code bit lengths are read as a - single stream of lengths. It is possible (and advantageous) for - a repeat code (16, 17, or 18) to go across the boundary between - the two sets of lengths. - */ - - -void inflate_blocks_reset(s, z, c) -inflate_blocks_statef *s; -z_streamp z; -uLongf *c; -{ - if (c != Z_NULL) - *c = s->check; - if (s->mode == BTREE || s->mode == DTREE) - ZFREE(z, s->sub.trees.blens); - if (s->mode == CODES) - inflate_codes_free(s->sub.decode.codes, z); - s->mode = TYPE; - s->bitk = 0; - s->bitb = 0; - s->read = s->write = s->window; - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0); - Tracev((stderr, "inflate: blocks reset\n")); -} - - -inflate_blocks_statef *inflate_blocks_new(z, c, w) -z_streamp z; -check_func c; -uInt w; -{ - inflate_blocks_statef *s; - - if ((s = (inflate_blocks_statef *)ZALLOC - (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) - return s; - if ((s->hufts = - (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL) - { - ZFREE(z, s); - return Z_NULL; - } - if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL) - { - ZFREE(z, s->hufts); - ZFREE(z, s); - return Z_NULL; - } - s->end = s->window + w; - s->checkfn = c; - s->mode = TYPE; - Tracev((stderr, "inflate: blocks allocated\n")); - inflate_blocks_reset(s, z, Z_NULL); - return s; -} - - -int inflate_blocks(s, z, r) -inflate_blocks_statef *s; -z_streamp z; -int r; -{ - uInt t; /* temporary storage */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - - /* copy input/output information to locals (UPDATE macro restores) */ - LOAD - - /* process input based on current state */ - while (1) switch (s->mode) - { - case TYPE: - NEEDBITS(3) - t = (uInt)b & 7; - s->last = t & 1; - switch (t >> 1) - { - case 0: /* stored */ - Tracev((stderr, "inflate: stored block%s\n", - s->last ? " (last)" : "")); - DUMPBITS(3) - t = k & 7; /* go to byte boundary */ - DUMPBITS(t) - s->mode = LENS; /* get length of stored block */ - break; - case 1: /* fixed */ - Tracev((stderr, "inflate: fixed codes block%s\n", - s->last ? " (last)" : "")); - { - uInt bl, bd; - inflate_huft *tl, *td; - - inflate_trees_fixed(&bl, &bd, &tl, &td, z); - s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); - if (s->sub.decode.codes == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - } - DUMPBITS(3) - s->mode = CODES; - break; - case 2: /* dynamic */ - Tracev((stderr, "inflate: dynamic codes block%s\n", - s->last ? " (last)" : "")); - DUMPBITS(3) - s->mode = TABLE; - break; - case 3: /* illegal */ - DUMPBITS(3) - s->mode = BAD; - z->msg = (char*)"invalid block type"; - r = Z_DATA_ERROR; - LEAVE - } - break; - case LENS: - NEEDBITS(32) - if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) - { - s->mode = BAD; - z->msg = (char*)"invalid stored block lengths"; - r = Z_DATA_ERROR; - LEAVE - } - s->sub.left = (uInt)b & 0xffff; - b = k = 0; /* dump bits */ - Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); - s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); - break; - case STORED: - if (n == 0) - LEAVE - NEEDOUT - t = s->sub.left; - if (t > n) t = n; - if (t > m) t = m; - zmemcpy(q, p, t); - p += t; n -= t; - q += t; m -= t; - if ((s->sub.left -= t) != 0) - break; - Tracev((stderr, "inflate: stored end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); - s->mode = s->last ? DRY : TYPE; - break; - case TABLE: - NEEDBITS(14) - s->sub.trees.table = t = (uInt)b & 0x3fff; -#ifndef PKZIP_BUG_WORKAROUND - if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) - { - s->mode = BAD; - z->msg = (char*)"too many length or distance symbols"; - r = Z_DATA_ERROR; - LEAVE - } -#endif - t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); - if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - DUMPBITS(14) - s->sub.trees.index = 0; - Tracev((stderr, "inflate: table sizes ok\n")); - s->mode = BTREE; - case BTREE: - while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) - { - NEEDBITS(3) - s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; - DUMPBITS(3) - } - while (s->sub.trees.index < 19) - s->sub.trees.blens[border[s->sub.trees.index++]] = 0; - s->sub.trees.bb = 7; - t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, - &s->sub.trees.tb, s->hufts, z); - if (t != Z_OK) - { - r = t; - if (r == Z_DATA_ERROR) - { - ZFREE(z, s->sub.trees.blens); - s->mode = BAD; - } - LEAVE - } - s->sub.trees.index = 0; - Tracev((stderr, "inflate: bits tree ok\n")); - s->mode = DTREE; - case DTREE: - while (t = s->sub.trees.table, - s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) - { - inflate_huft *h; - uInt i, j, c; - - t = s->sub.trees.bb; - NEEDBITS(t) - h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); - t = h->bits; - c = h->base; - if (c < 16) - { - DUMPBITS(t) - s->sub.trees.blens[s->sub.trees.index++] = c; - } - else /* c == 16..18 */ - { - i = c == 18 ? 7 : c - 14; - j = c == 18 ? 11 : 3; - NEEDBITS(t + i) - DUMPBITS(t) - j += (uInt)b & inflate_mask[i]; - DUMPBITS(i) - i = s->sub.trees.index; - t = s->sub.trees.table; - if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || - (c == 16 && i < 1)) - { - ZFREE(z, s->sub.trees.blens); - s->mode = BAD; - z->msg = (char*)"invalid bit length repeat"; - r = Z_DATA_ERROR; - LEAVE - } - c = c == 16 ? s->sub.trees.blens[i - 1] : 0; - do { - s->sub.trees.blens[i++] = c; - } while (--j); - s->sub.trees.index = i; - } - } - s->sub.trees.tb = Z_NULL; - { - uInt bl, bd; - inflate_huft *tl, *td; - inflate_codes_statef *c; - - bl = 9; /* must be <= 9 for lookahead assumptions */ - bd = 6; /* must be <= 9 for lookahead assumptions */ - t = s->sub.trees.table; - t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), - s->sub.trees.blens, &bl, &bd, &tl, &td, - s->hufts, z); - if (t != Z_OK) - { - if (t == (uInt)Z_DATA_ERROR) - { - ZFREE(z, s->sub.trees.blens); - s->mode = BAD; - } - r = t; - LEAVE - } - Tracev((stderr, "inflate: trees ok\n")); - if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - s->sub.decode.codes = c; - } - ZFREE(z, s->sub.trees.blens); - s->mode = CODES; - case CODES: - UPDATE - if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) - return inflate_flush(s, z, r); - r = Z_OK; - inflate_codes_free(s->sub.decode.codes, z); - LOAD - Tracev((stderr, "inflate: codes end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); - if (!s->last) - { - s->mode = TYPE; - break; - } - s->mode = DRY; - case DRY: - FLUSH - if (s->read != s->write) - LEAVE - s->mode = DONE; - case DONE: - r = Z_STREAM_END; - LEAVE - case BAD: - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -} - - -int inflate_blocks_free(s, z) -inflate_blocks_statef *s; -z_streamp z; -{ - inflate_blocks_reset(s, z, Z_NULL); - ZFREE(z, s->window); - ZFREE(z, s->hufts); - ZFREE(z, s); - Tracev((stderr, "inflate: blocks freed\n")); - return Z_OK; -} - - -void inflate_set_dictionary(s, d, n) -inflate_blocks_statef *s; -const Bytef *d; -uInt n; -{ - zmemcpy(s->window, d, n); - s->read = s->write = s->window + n; -} - - -/* Returns true if inflate is currently at the end of a block generated - * by Z_SYNC_FLUSH or Z_FULL_FLUSH. - * IN assertion: s != Z_NULL - */ -int inflate_blocks_sync_point(s) -inflate_blocks_statef *s; -{ - return s->mode == LENS; -} diff --git a/ZLIB/infblock.h b/ZLIB/infblock.h deleted file mode 100644 index 173b2267..00000000 --- a/ZLIB/infblock.h +++ /dev/null @@ -1,39 +0,0 @@ -/* infblock.h -- header to use infblock.c - * Copyright (C) 1995-2002 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -struct inflate_blocks_state; -typedef struct inflate_blocks_state FAR inflate_blocks_statef; - -extern inflate_blocks_statef * inflate_blocks_new OF(( - z_streamp z, - check_func c, /* check function */ - uInt w)); /* window size */ - -extern int inflate_blocks OF(( - inflate_blocks_statef *, - z_streamp , - int)); /* initial return code */ - -extern void inflate_blocks_reset OF(( - inflate_blocks_statef *, - z_streamp , - uLongf *)); /* check value on output */ - -extern int inflate_blocks_free OF(( - inflate_blocks_statef *, - z_streamp)); - -extern void inflate_set_dictionary OF(( - inflate_blocks_statef *s, - const Bytef *d, /* dictionary */ - uInt n)); /* dictionary length */ - -extern int inflate_blocks_sync_point OF(( - inflate_blocks_statef *s)); diff --git a/ZLIB/infcodes.c b/ZLIB/infcodes.c deleted file mode 100644 index 9abe5412..00000000 --- a/ZLIB/infcodes.c +++ /dev/null @@ -1,251 +0,0 @@ -/* infcodes.c -- process literals and length/distance pairs - * Copyright (C) 1995-2002 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "inftrees.h" -#include "infblock.h" -#include "infcodes.h" -#include "infutil.h" -#include "inffast.h" - -/* simplify the use of the inflate_huft type with some defines */ -#define exop word.what.Exop -#define bits word.what.Bits - -typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ - START, /* x: set up for LEN */ - LEN, /* i: get length/literal/eob next */ - LENEXT, /* i: getting length extra (have base) */ - DIST, /* i: get distance next */ - DISTEXT, /* i: getting distance extra */ - COPY, /* o: copying bytes in window, waiting for space */ - LIT, /* o: got literal, waiting for output space */ - WASH, /* o: got eob, possibly still output waiting */ - END, /* x: got eob and all data flushed */ - BADCODE} /* x: got error */ -inflate_codes_mode; - -/* inflate codes private state */ -struct inflate_codes_state { - - /* mode */ - inflate_codes_mode mode; /* current inflate_codes mode */ - - /* mode dependent information */ - uInt len; - union { - struct { - inflate_huft *tree; /* pointer into tree */ - uInt need; /* bits needed */ - } code; /* if LEN or DIST, where in tree */ - uInt lit; /* if LIT, literal */ - struct { - uInt get; /* bits to get for extra */ - uInt dist; /* distance back to copy from */ - } copy; /* if EXT or COPY, where and how much */ - } sub; /* submode */ - - /* mode independent information */ - Byte lbits; /* ltree bits decoded per branch */ - Byte dbits; /* dtree bits decoder per branch */ - inflate_huft *ltree; /* literal/length/eob tree */ - inflate_huft *dtree; /* distance tree */ - -}; - - -inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z) -uInt bl, bd; -inflate_huft *tl; -inflate_huft *td; /* need separate declaration for Borland C++ */ -z_streamp z; -{ - inflate_codes_statef *c; - - if ((c = (inflate_codes_statef *) - ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) - { - c->mode = START; - c->lbits = (Byte)bl; - c->dbits = (Byte)bd; - c->ltree = tl; - c->dtree = td; - Tracev((stderr, "inflate: codes new\n")); - } - return c; -} - - -int inflate_codes(s, z, r) -inflate_blocks_statef *s; -z_streamp z; -int r; -{ - uInt j; /* temporary storage */ - inflate_huft *t; /* temporary pointer */ - uInt e; /* extra bits or operation */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - Bytef *f; /* pointer to copy strings from */ - inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ - - /* copy input/output information to locals (UPDATE macro restores) */ - LOAD - - /* process input and output based on current state */ - while (1) switch (c->mode) - { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ - case START: /* x: set up for LEN */ -#ifndef SLOW - if (m >= 258 && n >= 10) - { - UPDATE - r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); - LOAD - if (r != Z_OK) - { - c->mode = r == Z_STREAM_END ? WASH : BADCODE; - break; - } - } -#endif /* !SLOW */ - c->sub.code.need = c->lbits; - c->sub.code.tree = c->ltree; - c->mode = LEN; - case LEN: /* i: get length/literal/eob next */ - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e == 0) /* literal */ - { - c->sub.lit = t->base; - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", t->base)); - c->mode = LIT; - break; - } - if (e & 16) /* length */ - { - c->sub.copy.get = e & 15; - c->len = t->base; - c->mode = LENEXT; - break; - } - if ((e & 64) == 0) /* next table */ - { - c->sub.code.need = e; - c->sub.code.tree = t + t->base; - break; - } - if (e & 32) /* end of block */ - { - Tracevv((stderr, "inflate: end of block\n")); - c->mode = WASH; - break; - } - c->mode = BADCODE; /* invalid code */ - z->msg = (char*)"invalid literal/length code"; - r = Z_DATA_ERROR; - LEAVE - case LENEXT: /* i: getting length extra (have base) */ - j = c->sub.copy.get; - NEEDBITS(j) - c->len += (uInt)b & inflate_mask[j]; - DUMPBITS(j) - c->sub.code.need = c->dbits; - c->sub.code.tree = c->dtree; - Tracevv((stderr, "inflate: length %u\n", c->len)); - c->mode = DIST; - case DIST: /* i: get distance next */ - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e & 16) /* distance */ - { - c->sub.copy.get = e & 15; - c->sub.copy.dist = t->base; - c->mode = DISTEXT; - break; - } - if ((e & 64) == 0) /* next table */ - { - c->sub.code.need = e; - c->sub.code.tree = t + t->base; - break; - } - c->mode = BADCODE; /* invalid code */ - z->msg = (char*)"invalid distance code"; - r = Z_DATA_ERROR; - LEAVE - case DISTEXT: /* i: getting distance extra */ - j = c->sub.copy.get; - NEEDBITS(j) - c->sub.copy.dist += (uInt)b & inflate_mask[j]; - DUMPBITS(j) - Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); - c->mode = COPY; - case COPY: /* o: copying bytes in window, waiting for space */ - f = q - c->sub.copy.dist; - while (f < s->window) /* modulo window size-"while" instead */ - f += s->end - s->window; /* of "if" handles invalid distances */ - while (c->len) - { - NEEDOUT - OUTBYTE(*f++) - if (f == s->end) - f = s->window; - c->len--; - } - c->mode = START; - break; - case LIT: /* o: got literal, waiting for output space */ - NEEDOUT - OUTBYTE(c->sub.lit) - c->mode = START; - break; - case WASH: /* o: got eob, possibly more output */ - if (k > 7) /* return unused byte, if any */ - { - Assert(k < 16, "inflate_codes grabbed too many bytes") - k -= 8; - n++; - p--; /* can always return one */ - } - FLUSH - if (s->read != s->write) - LEAVE - c->mode = END; - case END: - r = Z_STREAM_END; - LEAVE - case BADCODE: /* x: got error */ - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -#ifdef NEED_DUMMY_RETURN - return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ -#endif -} - - -void inflate_codes_free(c, z) -inflate_codes_statef *c; -z_streamp z; -{ - ZFREE(z, c); - Tracev((stderr, "inflate: codes free\n")); -} diff --git a/ZLIB/infcodes.h b/ZLIB/infcodes.h deleted file mode 100644 index 46821a02..00000000 --- a/ZLIB/infcodes.h +++ /dev/null @@ -1,27 +0,0 @@ -/* infcodes.h -- header to use infcodes.c - * Copyright (C) 1995-2002 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -struct inflate_codes_state; -typedef struct inflate_codes_state FAR inflate_codes_statef; - -extern inflate_codes_statef *inflate_codes_new OF(( - uInt, uInt, - inflate_huft *, inflate_huft *, - z_streamp )); - -extern int inflate_codes OF(( - inflate_blocks_statef *, - z_streamp , - int)); - -extern void inflate_codes_free OF(( - inflate_codes_statef *, - z_streamp )); - diff --git a/ZLIB/inffast.c b/ZLIB/inffast.c index aa7f1d4d..9354676e 100644 --- a/ZLIB/inffast.c +++ b/ZLIB/inffast.c @@ -1,183 +1,320 @@ -/* inffast.c -- process literals and length/distance pairs fast - * Copyright (C) 1995-2002 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h +/* inffast.c -- fast decoding + * Copyright (C) 1995-2017 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zutil.h" #include "inftrees.h" -#include "infblock.h" -#include "infcodes.h" -#include "infutil.h" +#include "inflate.h" #include "inffast.h" -struct inflate_codes_state {int dummy;}; /* for buggy compilers */ - -/* simplify the use of the inflate_huft type with some defines */ -#define exop word.what.Exop -#define bits word.what.Bits - -/* macros for bit input with no checking and for returning unused bytes */ -#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;} - -/* Called with number of bytes left to write in window at least 258 - (the maximum string length) and number of input bytes available - at least ten. The ten bytes are six bytes for the longest length/ - distance pair plus four bytes for overloading the bit buffer. */ - -int inflate_fast(bl, bd, tl, td, s, z) -uInt bl, bd; -inflate_huft *tl; -inflate_huft *td; /* need separate declaration for Borland C++ */ -inflate_blocks_statef *s; -z_streamp z; -{ - inflate_huft *t; /* temporary pointer */ - uInt e; /* extra bits or operation */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - uInt ml; /* mask for literal/length tree */ - uInt md; /* mask for distance tree */ - uInt c; /* bytes to copy */ - uInt d; /* distance back to copy from */ - Bytef *r; /* copy source pointer */ - - /* load input, output, bit values */ - LOAD - - /* initialize masks */ - ml = inflate_mask[bl]; - md = inflate_mask[bd]; - - /* do until not enough input or output space for fast loop */ - do { /* assume called with m >= 258 && n >= 10 */ - /* get literal/length code */ - GRABBITS(20) /* max bits for literal/length code */ - if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) - { - DUMPBITS(t->bits) - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); - *q++ = (Byte)t->base; - m--; - continue; - } +#ifdef ASMINF +# pragma message("Assembler code may have bugs -- use at your own risk") +#else + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) { + struct inflate_state FAR *state; + z_const unsigned char FAR *in; /* local strm->next_in */ + z_const unsigned char FAR *last; /* have enough input while in < last */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code const *here; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in; + last = in + (strm->avail_in - 5); + out = strm->next_out; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + wnext = state->wnext; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ do { - DUMPBITS(t->bits) - if (e & 16) - { - /* get extra bits for length */ - e &= 15; - c = t->base + ((uInt)b & inflate_mask[e]); - DUMPBITS(e) - Tracevv((stderr, "inflate: * length %u\n", c)); - - /* decode distance base of block to copy */ - GRABBITS(15); /* max bits for distance code */ - e = (t = td + ((uInt)b & md))->exop; - do { - DUMPBITS(t->bits) - if (e & 16) - { - /* get extra bits to add to distance base */ - e &= 15; - GRABBITS(e) /* get extra bits (up to 13) */ - d = t->base + ((uInt)b & inflate_mask[e]); - DUMPBITS(e) - Tracevv((stderr, "inflate: * distance %u\n", d)); - - /* do the copy */ - m -= c; - r = q - d; - if (r < s->window) /* wrap if needed */ - { - do { - r += s->end - s->window; /* force pointer in window */ - } while (r < s->window); /* covers invalid distances */ - e = s->end - r; - if (c > e) - { - c -= e; /* wrapped copy */ - do { - *q++ = *r++; - } while (--e); - r = s->window; - do { - *q++ = *r++; - } while (--c); - } - else /* normal copy */ - { - *q++ = *r++; c--; - *q++ = *r++; c--; - do { - *q++ = *r++; - } while (--c); - } + if (bits < 15) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + here = lcode + (hold & lmask); + dolen: + op = (unsigned)(here->bits); + hold >>= op; + bits -= op; + op = (unsigned)(here->op); + if (op == 0) { /* literal */ + Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here->val)); + *out++ = (unsigned char)(here->val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(here->val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; } - else /* normal copy */ - { - *q++ = *r++; c--; - *q++ = *r++; c--; - do { - *q++ = *r++; - } while (--c); + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + hold += (unsigned long)(*in++) << bits; + bits += 8; } + here = dcode + (hold & dmask); + dodist: + op = (unsigned)(here->bits); + hold >>= op; + bits -= op; + op = (unsigned)(here->op); + if (op & 16) { /* distance base */ + dist = (unsigned)(here->val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + if (state->sane) { + strm->msg = + (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + if (len <= op - whave) { + do { + *out++ = 0; + } while (--len); + continue; + } + len -= op - whave; + do { + *out++ = 0; + } while (--op > whave); + if (op == 0) { + from = out - dist; + do { + *out++ = *from++; + } while (--len); + continue; + } +#endif + } + from = window; + if (wnext == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (wnext < op) { /* wrap around window */ + from += wsize + wnext - op; + op -= wnext; + if (op < len) { /* some from end of window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = window; + if (wnext < len) { /* some from start of window */ + op = wnext; + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += wnext - op; + if (op < len) { /* some from window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + *out++ = *from++; + *out++ = *from++; + *out++ = *from++; + len -= 3; + } + if (len) { + *out++ = *from++; + if (len > 1) + *out++ = *from++; + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + *out++ = *from++; + *out++ = *from++; + *out++ = *from++; + len -= 3; + } while (len > 2); + if (len) { + *out++ = *from++; + if (len > 1) + *out++ = *from++; + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + here = dcode + here->val + (hold & ((1U << op) - 1)); + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + here = lcode + here->val + (hold & ((1U << op) - 1)); + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; break; - } - else if ((e & 64) == 0) - { - t += t->base; - e = (t += ((uInt)b & inflate_mask[e]))->exop; - } - else - { - z->msg = (char*)"invalid distance code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - } while (1); - break; - } - if ((e & 64) == 0) - { - t += t->base; - if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) - { - DUMPBITS(t->bits) - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); - *q++ = (Byte)t->base; - m--; - break; } - } - else if (e & 32) - { - Tracevv((stderr, "inflate: * end of block\n")); - UNGRAB - UPDATE - return Z_STREAM_END; - } - else - { - z->msg = (char*)"invalid literal/length code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - } while (1); - } while (m >= 258 && n >= 10); - - /* not enough input or output--restore pointers and return */ - UNGRAB - UPDATE - return Z_OK; + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in; + strm->next_out = out; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; } + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and wnext == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/ZLIB/inffast.h b/ZLIB/inffast.h index a31a4bbb..49c6d156 100644 --- a/ZLIB/inffast.h +++ b/ZLIB/inffast.h @@ -1,6 +1,6 @@ /* inffast.h -- header to use inffast.c - * Copyright (C) 1995-2002 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2003, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is @@ -8,10 +8,4 @@ subject to change. Applications should only use zlib.h. */ -extern int inflate_fast OF(( - uInt, - uInt, - inflate_huft *, - inflate_huft *, - inflate_blocks_statef *, - z_streamp )); +void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start); diff --git a/ZLIB/inffixed.h b/ZLIB/inffixed.h index 77f7e763..d6283277 100644 --- a/ZLIB/inffixed.h +++ b/ZLIB/inffixed.h @@ -1,151 +1,94 @@ -/* inffixed.h -- table for decoding fixed codes - * Generated automatically by the maketree.c program - */ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ + /* WARNING: this file should *not* be used by applications. + It is part of the implementation of this library and is + subject to change. Applications should only use zlib.h. + */ -local uInt fixed_bl = 9; -local uInt fixed_bd = 5; -local inflate_huft fixed_tl[] = { - {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, - {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, - {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, - {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224}, - {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144}, - {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208}, - {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176}, - {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240}, - {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, - {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200}, - {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168}, - {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232}, - {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152}, - {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216}, - {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184}, - {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248}, - {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, - {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196}, - {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164}, - {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228}, - {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148}, - {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212}, - {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180}, - {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244}, - {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, - {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204}, - {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172}, - {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236}, - {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156}, - {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220}, - {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188}, - {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252}, - {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, - {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194}, - {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162}, - {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226}, - {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146}, - {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210}, - {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178}, - {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242}, - {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, - {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202}, - {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170}, - {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234}, - {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154}, - {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218}, - {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186}, - {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250}, - {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, - {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198}, - {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166}, - {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230}, - {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150}, - {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214}, - {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182}, - {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246}, - {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, - {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206}, - {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174}, - {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238}, - {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158}, - {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222}, - {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190}, - {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254}, - {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, - {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193}, - {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161}, - {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225}, - {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145}, - {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209}, - {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177}, - {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241}, - {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, - {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201}, - {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169}, - {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233}, - {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153}, - {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217}, - {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185}, - {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249}, - {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, - {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197}, - {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165}, - {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229}, - {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149}, - {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213}, - {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181}, - {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245}, - {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, - {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205}, - {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173}, - {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237}, - {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157}, - {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221}, - {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189}, - {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253}, - {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, - {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195}, - {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163}, - {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227}, - {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147}, - {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211}, - {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179}, - {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243}, - {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, - {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203}, - {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171}, - {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235}, - {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155}, - {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219}, - {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187}, - {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251}, - {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, - {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199}, - {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167}, - {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231}, - {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151}, - {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215}, - {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183}, - {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247}, - {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, - {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207}, - {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175}, - {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239}, - {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159}, - {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223}, - {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, - {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} - }; -local inflate_huft fixed_td[] = { - {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, - {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, - {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, - {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577}, - {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145}, - {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577}, - {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289}, - {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577} - }; + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/ZLIB/inflate.c b/ZLIB/inflate.c index dfb2e867..94ecff01 100644 --- a/ZLIB/inflate.c +++ b/ZLIB/inflate.c @@ -1,366 +1,1526 @@ -/* inflate.c -- zlib interface to inflate modules - * Copyright (C) 1995-2002 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2022 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common wnext == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. */ #include "zutil.h" -#include "infblock.h" - -struct inflate_blocks_state {int dummy;}; /* for buggy compilers */ - -typedef enum { - METHOD, /* waiting for method byte */ - FLAG, /* waiting for flag byte */ - DICT4, /* four dictionary check bytes to go */ - DICT3, /* three dictionary check bytes to go */ - DICT2, /* two dictionary check bytes to go */ - DICT1, /* one dictionary check byte to go */ - DICT0, /* waiting for inflateSetDictionary */ - BLOCKS, /* decompressing blocks */ - CHECK4, /* four check bytes to go */ - CHECK3, /* three check bytes to go */ - CHECK2, /* two check bytes to go */ - CHECK1, /* one check byte to go */ - DONE, /* finished check, done */ - BAD} /* got an error--stay here */ -inflate_mode; - -/* inflate private state */ -struct internal_state { - - /* mode */ - inflate_mode mode; /* current inflate mode */ - - /* mode dependent information */ - union { - uInt method; /* if FLAGS, method byte */ - struct { - uLong was; /* computed check value */ - uLong need; /* stream check value */ - } check; /* if CHECK, check values to compare */ - uInt marker; /* if BAD, inflateSync's marker bytes count */ - } sub; /* submode */ - - /* mode independent information */ - int nowrap; /* flag for no wrapper */ - uInt wbits; /* log2(window size) (8..15, defaults to 15) */ - inflate_blocks_statef - *blocks; /* current inflate_blocks state */ - -}; - - -int ZEXPORT inflateReset(z) -z_streamp z; -{ - if (z == Z_NULL || z->state == Z_NULL) - return Z_STREAM_ERROR; - z->total_in = z->total_out = 0; - z->msg = Z_NULL; - z->state->mode = z->state->nowrap ? BLOCKS : METHOD; - inflate_blocks_reset(z->state->blocks, z, Z_NULL); - Tracev((stderr, "inflate: reset\n")); - return Z_OK; +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +local int inflateStateCheck(z_streamp strm) { + struct inflate_state FAR *state; + if (strm == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) + return 1; + state = (struct inflate_state FAR *)strm->state; + if (state == Z_NULL || state->strm != strm || + state->mode < HEAD || state->mode > SYNC) + return 1; + return 0; } +int ZEXPORT inflateResetKeep(z_streamp strm) { + struct inflate_state FAR *state; -int ZEXPORT inflateEnd(z) -z_streamp z; -{ - if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) - return Z_STREAM_ERROR; - if (z->state->blocks != Z_NULL) - inflate_blocks_free(z->state->blocks, z); - ZFREE(z, z->state); - z->state = Z_NULL; - Tracev((stderr, "inflate: end\n")); - return Z_OK; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + if (state->wrap) /* to support ill-conceived Java test suite */ + strm->adler = state->wrap & 1; + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->flags = -1; + state->dmax = 32768U; + state->head = Z_NULL; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + state->sane = 1; + state->back = -1; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; } +int ZEXPORT inflateReset(z_streamp strm) { + struct inflate_state FAR *state; -int ZEXPORT inflateInit2_(z, w, version, stream_size) -z_streamp z; -int w; -const char *version; -int stream_size; -{ - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != sizeof(z_stream)) - return Z_VERSION_ERROR; - - /* initialize state */ - if (z == Z_NULL) - return Z_STREAM_ERROR; - z->msg = Z_NULL; - if (z->zalloc == Z_NULL) - { - z->zalloc = zcalloc; - z->opaque = (voidpf)0; - } - if (z->zfree == Z_NULL) z->zfree = zcfree; - if ((z->state = (struct internal_state FAR *) - ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) - return Z_MEM_ERROR; - z->state->blocks = Z_NULL; - - /* handle undocumented nowrap option (no zlib header or check) */ - z->state->nowrap = 0; - if (w < 0) - { - w = - w; - z->state->nowrap = 1; - } - - /* set window size */ - if (w < 8 || w > 15) - { - inflateEnd(z); - return Z_STREAM_ERROR; - } - z->state->wbits = (uInt)w; - - /* create inflate_blocks state */ - if ((z->state->blocks = - inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) - == Z_NULL) - { - inflateEnd(z); - return Z_MEM_ERROR; - } - Tracev((stderr, "inflate: allocated\n")); - - /* reset state */ - inflateReset(z); - return Z_OK; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + state->wsize = 0; + state->whave = 0; + state->wnext = 0; + return inflateResetKeep(strm); } +int ZEXPORT inflateReset2(z_streamp strm, int windowBits) { + int wrap; + struct inflate_state FAR *state; -int ZEXPORT inflateInit_(z, version, stream_size) -z_streamp z; -const char *version; -int stream_size; -{ - return inflateInit2_(z, DEF_WBITS, version, stream_size); + /* get the state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* extract wrap request from windowBits parameter */ + if (windowBits < 0) { + if (windowBits < -15) + return Z_STREAM_ERROR; + wrap = 0; + windowBits = -windowBits; + } + else { + wrap = (windowBits >> 4) + 5; +#ifdef GUNZIP + if (windowBits < 48) + windowBits &= 15; +#endif + } + + /* set number of window bits, free window if different */ + if (windowBits && (windowBits < 8 || windowBits > 15)) + return Z_STREAM_ERROR; + if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { + ZFREE(strm, state->window); + state->window = Z_NULL; + } + + /* update state and reset the rest of it */ + state->wrap = wrap; + state->wbits = (unsigned)windowBits; + return inflateReset(strm); +} + +int ZEXPORT inflateInit2_(z_streamp strm, int windowBits, + const char *version, int stream_size) { + int ret; + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->strm = strm; + state->window = Z_NULL; + state->mode = HEAD; /* to pass state test in inflateReset2() */ + ret = inflateReset2(strm, windowBits); + if (ret != Z_OK) { + ZFREE(strm, state); + strm->state = Z_NULL; + } + return ret; +} + +int ZEXPORT inflateInit_(z_streamp strm, const char *version, + int stream_size) { + return inflateInit2_(strm, DEF_WBITS, version, stream_size); } +int ZEXPORT inflatePrime(z_streamp strm, int bits, int value) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + if (bits == 0) + return Z_OK; + state = (struct inflate_state FAR *)strm->state; + if (bits < 0) { + state->hold = 0; + state->bits = 0; + return Z_OK; + } + if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += (unsigned)value << state->bits; + state->bits += (uInt)bits; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(struct inflate_state FAR *state) { +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); -#define NEEDBYTE {if(z->avail_in==0)return r;r=f;} -#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); -int ZEXPORT inflate(z, f) -z_streamp z; -int f; + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed(void) { - int r; - uInt b; - - if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) - return Z_STREAM_ERROR; - f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; - r = Z_BUF_ERROR; - while (1) switch (z->state->mode) - { - case METHOD: - NEEDBYTE - if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED) - { - z->state->mode = BAD; - z->msg = (char*)"unknown compression method"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - if ((z->state->sub.method >> 4) + 8 > z->state->wbits) - { - z->state->mode = BAD; - z->msg = (char*)"invalid window size"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - z->state->mode = FLAG; - case FLAG: - NEEDBYTE - b = NEXTBYTE; - if (((z->state->sub.method << 8) + b) % 31) - { - z->state->mode = BAD; - z->msg = (char*)"incorrect header check"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - Tracev((stderr, "inflate: zlib header ok\n")); - if (!(b & PRESET_DICT)) - { - z->state->mode = BLOCKS; - break; - } - z->state->mode = DICT4; - case DICT4: - NEEDBYTE - z->state->sub.check.need = (uLong)NEXTBYTE << 24; - z->state->mode = DICT3; - case DICT3: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 16; - z->state->mode = DICT2; - case DICT2: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 8; - z->state->mode = DICT1; - case DICT1: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE; - z->adler = z->state->sub.check.need; - z->state->mode = DICT0; - return Z_NEED_DICT; - case DICT0: - z->state->mode = BAD; - z->msg = (char*)"need dictionary"; - z->state->sub.marker = 0; /* can try inflateSync */ - return Z_STREAM_ERROR; - case BLOCKS: - r = inflate_blocks(z->state->blocks, z, r); - if (r == Z_DATA_ERROR) - { - z->state->mode = BAD; - z->state->sub.marker = 0; /* can try inflateSync */ - break; - } - if (r == Z_OK) - r = f; - if (r != Z_STREAM_END) - return r; - r = f; - inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); - if (z->state->nowrap) - { - z->state->mode = DONE; - break; - } - z->state->mode = CHECK4; - case CHECK4: - NEEDBYTE - z->state->sub.check.need = (uLong)NEXTBYTE << 24; - z->state->mode = CHECK3; - case CHECK3: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 16; - z->state->mode = CHECK2; - case CHECK2: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 8; - z->state->mode = CHECK1; - case CHECK1: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE; - - if (z->state->sub.check.was != z->state->sub.check.need) - { - z->state->mode = BAD; - z->msg = (char*)"incorrect data check"; - z->state->sub.marker = 5; /* can't try inflateSync */ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op, + state.lencode[low].bits, state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(z_streamp strm, const Bytef *end, unsigned copy) { + struct inflate_state FAR *state; + unsigned dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->wnext = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + if (copy >= state->wsize) { + zmemcpy(state->window, end - state->wsize, state->wsize); + state->wnext = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->wnext; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->wnext, end - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, end - copy, copy); + state->wnext = copy; + state->whave = state->wsize; + } + else { + state->wnext += dist; + if (state->wnext == state->wsize) state->wnext = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE_CHECK(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE_CHECK(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; break; - } - Tracev((stderr, "inflate: zlib check ok\n")); - z->state->mode = DONE; - case DONE: - return Z_STREAM_END; - case BAD: - return Z_DATA_ERROR; - default: - return Z_STREAM_ERROR; - } -#ifdef NEED_DUMMY_RETURN - return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(z_streamp strm, int flush) { + struct inflate_state FAR *state; + z_const unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (inflateStateCheck(strm) || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + if (state->wbits == 0) + state->wbits = 15; + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (state->wbits == 0) + state->wbits = len; + if (len > 15 || len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + state->flags = 0; /* indicate zlib header */ + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + /* fallthrough */ + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + /* fallthrough */ + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + /* fallthrough */ + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + /* fallthrough */ + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL && + (len = state->head->extra_len - state->length) < + state->head->extra_max) { + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + /* fallthrough */ + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = (Bytef)len; + } while (len && copy < have); + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + /* fallthrough */ + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = (Bytef)len; + } while (len && copy < have); + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + /* fallthrough */ + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if ((state->wrap & 4) && hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; #endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = ZSWAP32(hold); + INITBITS(); + state->mode = DICT; + /* fallthrough */ + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + /* fallthrough */ + case TYPE: + if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; + /* fallthrough */ + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN_; /* decode codes */ + if (flush == Z_TREES) { + DROPBITS(2); + goto inf_leave; + } + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY_; + if (flush == Z_TREES) goto inf_leave; + /* fallthrough */ + case COPY_: + state->mode = COPY; + /* fallthrough */ + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + /* fallthrough */ + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (const code FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + /* fallthrough */ + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (const code FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (const code FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN_; + if (flush == Z_TREES) goto inf_leave; + /* fallthrough */ + case LEN_: + state->mode = LEN; + /* fallthrough */ + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + if (state->mode == TYPE) + state->back = -1; + break; + } + state->back = 0; + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + state->length = (unsigned)here.val; + if ((int)(here.op) == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + state->mode = LIT; + break; + } + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->back = -1; + state->mode = TYPE; + break; + } + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(here.op) & 15; + state->mode = LENEXT; + /* fallthrough */ + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->was = state->length; + state->mode = DIST; + /* fallthrough */ + case DIST: + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)here.val; + state->extra = (unsigned)(here.op) & 15; + state->mode = DISTEXT; + /* fallthrough */ + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + /* fallthrough */ + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->whave) { + if (state->sane) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + Trace((stderr, "inflate.c too far\n")); + copy -= state->whave; + if (copy > state->length) copy = state->length; + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = 0; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; +#endif + } + if (copy > state->wnext) { + copy -= state->wnext; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->wnext - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if ((state->wrap & 4) && out) + strm->adler = state->check = + UPDATE_CHECK(state->check, put - out, out); + out = left; + if ((state->wrap & 4) && ( +#ifdef GUNZIP + state->flags ? hold : +#endif + ZSWAP32(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + /* fallthrough */ + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if ((state->wrap & 4) && hold != (state->total & 0xffffffff)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + /* fallthrough */ + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + /* fallthrough */ + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (out != strm->avail_out && state->mode < BAD && + (state->mode < CHECK || flush != Z_FINISH))) + if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if ((state->wrap & 4) && out) + strm->adler = state->check = + UPDATE_CHECK(state->check, strm->next_out - out, out); + strm->data_type = (int)state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0) + + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(z_streamp strm) { + struct inflate_state FAR *state; + if (inflateStateCheck(strm)) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; } +int ZEXPORT inflateGetDictionary(z_streamp strm, Bytef *dictionary, + uInt *dictLength) { + struct inflate_state FAR *state; -int ZEXPORT inflateSetDictionary(z, dictionary, dictLength) -z_streamp z; -const Bytef *dictionary; -uInt dictLength; -{ - uInt length = dictLength; - - if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0) - return Z_STREAM_ERROR; - - if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR; - z->adler = 1L; - - if (length >= ((uInt)1<state->wbits)) - { - length = (1<state->wbits)-1; - dictionary += dictLength - length; - } - inflate_set_dictionary(z->state->blocks, dictionary, length); - z->state->mode = BLOCKS; - return Z_OK; + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* copy dictionary */ + if (state->whave && dictionary != Z_NULL) { + zmemcpy(dictionary, state->window + state->wnext, + state->whave - state->wnext); + zmemcpy(dictionary + state->whave - state->wnext, + state->window, state->wnext); + } + if (dictLength != Z_NULL) + *dictLength = state->whave; + return Z_OK; } +int ZEXPORT inflateSetDictionary(z_streamp strm, const Bytef *dictionary, + uInt dictLength) { + struct inflate_state FAR *state; + unsigned long dictid; + int ret; -int ZEXPORT inflateSync(z) -z_streamp z; -{ - uInt n; /* number of bytes to look at */ - Bytef *p; /* pointer to bytes */ - uInt m; /* number of marker bytes found in a row */ - uLong r, w; /* temporaries to save total_in and total_out */ - - /* set up */ - if (z == Z_NULL || z->state == Z_NULL) - return Z_STREAM_ERROR; - if (z->state->mode != BAD) - { - z->state->mode = BAD; - z->state->sub.marker = 0; - } - if ((n = z->avail_in) == 0) - return Z_BUF_ERROR; - p = z->next_in; - m = z->state->sub.marker; - - /* search */ - while (n && m < 4) - { - static const Byte mark[4] = {0, 0, 0xff, 0xff}; - if (*p == mark[m]) - m++; - else if (*p) - m = 0; + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary identifier */ + if (state->mode == DICT) { + dictid = adler32(0L, Z_NULL, 0); + dictid = adler32(dictid, dictionary, dictLength); + if (dictid != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window using updatewindow(), which will amend the + existing dictionary if appropriate */ + ret = updatewindow(strm, dictionary + dictLength, dictLength); + if (ret) { + state->mode = MEM; + return Z_MEM_ERROR; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(z_streamp strm, gz_headerp head) { + struct inflate_state FAR *state; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(unsigned FAR *have, const unsigned char FAR *buf, + unsigned len) { + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(z_streamp strm) { + unsigned len; /* number of bytes to look at or looked at */ + int flags; /* temporary to save header status */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold >>= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + if (state->flags == -1) + state->wrap = 0; /* if no header yet, treat as raw */ else - m = 4 - m; - p++, n--; - } - - /* restore */ - z->total_in += p - z->next_in; - z->next_in = p; - z->avail_in = n; - z->state->sub.marker = m; - - /* return no joy or set up to restart on a new block */ - if (m != 4) + state->wrap &= ~4; /* no point in computing a check value now */ + flags = state->flags; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->flags = flags; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(z_streamp strm) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(z_streamp dest, z_streamp source) { + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (inflateStateCheck(source) || dest == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); + zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); + copy->strm = dest; + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} + +int ZEXPORT inflateUndermine(z_streamp strm, int subvert) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + state->sane = !subvert; + return Z_OK; +#else + (void)subvert; + state->sane = 1; return Z_DATA_ERROR; - r = z->total_in; w = z->total_out; - inflateReset(z); - z->total_in = r; z->total_out = w; - z->state->mode = BLOCKS; - return Z_OK; +#endif } +int ZEXPORT inflateValidate(z_streamp strm, int check) { + struct inflate_state FAR *state; -/* Returns true if inflate is currently at the end of a block generated - * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP - * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH - * but removes the length bytes of the resulting empty stored block. When - * decompressing, PPP checks that at the end of input packet, inflate is - * waiting for these length bytes. - */ -int ZEXPORT inflateSyncPoint(z) -z_streamp z; -{ - if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL) - return Z_STREAM_ERROR; - return inflate_blocks_sync_point(z->state->blocks); + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (check && state->wrap) + state->wrap |= 4; + else + state->wrap &= ~4; + return Z_OK; +} + +long ZEXPORT inflateMark(z_streamp strm) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) + return -(1L << 16); + state = (struct inflate_state FAR *)strm->state; + return (long)(((unsigned long)((long)state->back)) << 16) + + (state->mode == COPY ? state->length : + (state->mode == MATCH ? state->was - state->length : 0)); +} + +unsigned long ZEXPORT inflateCodesUsed(z_streamp strm) { + struct inflate_state FAR *state; + if (inflateStateCheck(strm)) return (unsigned long)-1; + state = (struct inflate_state FAR *)strm->state; + return (unsigned long)(state->next - state->codes); } diff --git a/ZLIB/inflate.h b/ZLIB/inflate.h new file mode 100644 index 00000000..f127b6b1 --- /dev/null +++ b/ZLIB/inflate.h @@ -0,0 +1,126 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2019 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD = 16180, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY_, /* i/o: same as COPY below, but only first time in */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN_, /* i: same as LEN below, but only first time in */ + LEN, /* i: waiting for length/lit/eob code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to BAD or MEM on error -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) or (raw) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> + HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + (raw) -> TYPEDO + Read deflate blocks: + TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK + STORED -> COPY_ -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN_ + LEN_ -> LEN + Read deflate codes in fixed or dynamic block: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* State maintained between inflate() calls -- approximately 7K bytes, not + including the allocated sliding window, which is up to 32K bytes. */ +struct inflate_state { + z_streamp strm; /* pointer back to this zlib stream */ + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip, + bit 2 true to validate check value */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags, 0 if zlib, or + -1 if raw or no header yet */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ + int sane; /* if false, allow invalid distance too far */ + int back; /* bits back of last unprocessed length/lit */ + unsigned was; /* initial length of match */ +}; diff --git a/ZLIB/inftrees.c b/ZLIB/inftrees.c index 4c32ca30..98cfe164 100644 --- a/ZLIB/inftrees.c +++ b/ZLIB/inftrees.c @@ -1,454 +1,299 @@ /* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-2002 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2024 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zutil.h" #include "inftrees.h" -#if !defined(BUILDFIXED) && !defined(STDC) -# define BUILDFIXED /* non ANSI compilers may not accept inffixed.h */ -#endif +#define MAXBITS 15 const char inflate_copyright[] = - " inflate 1.1.4 Copyright 1995-2002 Mark Adler "; + " inflate 1.3.1 Copyright 1995-2024 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. */ -struct internal_state {int dummy;}; /* for buggy compilers */ - -/* simplify the use of the inflate_huft type with some defines */ -#define exop word.what.Exop -#define bits word.what.Bits - - -local int huft_build OF(( - uIntf *, /* code lengths in bits */ - uInt, /* number of codes */ - uInt, /* number of "simple" codes */ - const uIntf *, /* list of base values for non-simple codes */ - const uIntf *, /* list of extra bits for non-simple codes */ - inflate_huft * FAR*,/* result: starting table */ - uIntf *, /* maximum lookup bits (returns actual) */ - inflate_huft *, /* space for trees */ - uInt *, /* hufts used in space */ - uIntf * )); /* space for values */ - -/* Tables for deflate from PKZIP's appnote.txt. */ -local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work) { + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code here; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + unsigned match; /* use base and extra for symbol >= match */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; - /* see note #13 above about 258 */ -local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ -local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 203, 77}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577}; -local const uInt cpdext[30] = { /* Extra bits for distance codes */ - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13}; - -/* - Huffman code decoding is performed using a multi-level table lookup. - The fastest way to decode is to simply build a lookup table whose - size is determined by the longest code. However, the time it takes - to build this table can also be a factor if the data being decoded - is not very long. The most common codes are necessarily the - shortest codes, so those codes dominate the decoding time, and hence - the speed. The idea is you can have a shorter table that decodes the - shorter, more probable codes, and then point to subsidiary tables for - the longer codes. The time it costs to decode the longer codes is - then traded against the time it takes to make longer tables. - - This results of this trade are in the variables lbits and dbits - below. lbits is the number of bits the first level table for literal/ - length codes can decode in one step, and dbits is the same thing for - the distance codes. Subsequent tables are also less than or equal to - those sizes. These values may be adjusted either when all of the - codes are shorter than that, in which case the longest code length in - bits is used, or when the shortest code is *longer* than the requested - table size, in which case the length of the shortest code in bits is - used. - - There are two different values for the two tables, since they code a - different number of possibilities each. The literal/length table - codes 286 possible values, or in a flat code, a little over eight - bits. The distance table codes 30 possible values, or a little less - than five bits, flat. The optimum values for speed end up being - about one bit more than those, so lbits is 8+1 and dbits is 5+1. - The optimum values may differ though from machine to machine, and - possibly even between compilers. Your mileage may vary. - */ - + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)1; + here.val = (unsigned short)0; + *(*table)++ = here; /* make a table to force an error */ + *(*table)++ = here; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min < max; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for LENS and DIST tables against + the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in + the initial root table size constants. See the comments in inftrees.h + for more information. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + match = 20; + break; + case LENS: + base = lbase; + extra = lext; + match = 257; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + match = 0; + } -/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ -#define BMAX 15 /* maximum bit length of any code */ - -local int huft_build(b, n, s, d, e, t, m, hp, hn, v) -uIntf *b; /* code lengths in bits (all assumed <= BMAX) */ -uInt n; /* number of codes (assumed <= 288) */ -uInt s; /* number of simple-valued codes (0..s-1) */ -const uIntf *d; /* list of base values for non-simple codes */ -const uIntf *e; /* list of extra bits for non-simple codes */ -inflate_huft * FAR *t; /* result: starting table */ -uIntf *m; /* maximum lookup bits, returns actual */ -inflate_huft *hp; /* space for trees */ -uInt *hn; /* hufts used in space */ -uIntf *v; /* working area: values in order of bit length */ -/* Given a list of code lengths and a maximum table size, make a set of - tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR - if the given code set is incomplete (the tables are still built in this - case), or Z_DATA_ERROR if the input is invalid. */ -{ - - uInt a; /* counter for codes of length k */ - uInt c[BMAX+1]; /* bit length count table */ - uInt f; /* i repeats in table every f entries */ - int g; /* maximum code length */ - int h; /* table level */ - register uInt i; /* counter, current code */ - register uInt j; /* counter */ - register int k; /* number of bits in current code */ - int l; /* bits per table (returned in m) */ - uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */ - register uIntf *p; /* pointer into c[], b[], or v[] */ - inflate_huft *q; /* points to current table */ - struct inflate_huft_s r; /* table entry for structure assignment */ - inflate_huft *u[BMAX]; /* table stack */ - register int w; /* bits before this table == (l * h) */ - uInt x[BMAX+1]; /* bit offsets, then code stack */ - uIntf *xp; /* pointer into x */ - int y; /* number of dummy codes added */ - uInt z; /* number of entries in current table */ - - - /* Generate counts for each bit length */ - p = c; -#define C0 *p++ = 0; -#define C2 C0 C0 C0 C0 -#define C4 C2 C2 C2 C2 - C4 /* clear c[]--assume BMAX+1 is 16 */ - p = b; i = n; - do { - c[*p++]++; /* assume all entries <= BMAX */ - } while (--i); - if (c[0] == n) /* null input--all zero length codes */ - { - *t = (inflate_huft *)Z_NULL; - *m = 0; - return Z_OK; - } - - - /* Find minimum and maximum length, bound *m by those */ - l = *m; - for (j = 1; j <= BMAX; j++) - if (c[j]) - break; - k = j; /* minimum code length */ - if ((uInt)l < j) - l = j; - for (i = BMAX; i; i--) - if (c[i]) - break; - g = i; /* maximum code length */ - if ((uInt)l > i) - l = i; - *m = l; - - - /* Adjust last length count to fill out codes, if needed */ - for (y = 1 << j; j < i; j++, y <<= 1) - if ((y -= c[j]) < 0) - return Z_DATA_ERROR; - if ((y -= c[i]) < 0) - return Z_DATA_ERROR; - c[i] += y; - - - /* Generate starting offsets into the value table for each length */ - x[1] = j = 0; - p = c + 1; xp = x + 2; - while (--i) { /* note that i == g from above */ - *xp++ = (j += *p++); - } - - - /* Make a table of values in order of bit lengths */ - p = b; i = 0; - do { - if ((j = *p++) != 0) - v[x[j]++] = i; - } while (++i < n); - n = x[g]; /* set n to length of v */ - - - /* Generate the Huffman codes and for each, make the table entries */ - x[0] = i = 0; /* first Huffman code is zero */ - p = v; /* grab values in bit order */ - h = -1; /* no tables yet--level -1 */ - w = -l; /* bits decoded == (l * h) */ - u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ - q = (inflate_huft *)Z_NULL; /* ditto */ - z = 0; /* ditto */ - - /* go through the bit lengths (k already is bits in shortest code) */ - for (; k <= g; k++) - { - a = c[k]; - while (a--) - { - /* here i is the Huffman code of length k bits for value *p */ - /* make tables up to required level */ - while (k > w + l) - { - h++; - w += l; /* previous table always l bits */ - - /* compute minimum size table less than or equal to l bits */ - z = g - w; - z = z > (uInt)l ? l : z; /* table size upper limit */ - if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ - { /* too few codes for k-w bit table */ - f -= a + 1; /* deduct codes from patterns left */ - xp = c + k; - if (j < z) - while (++j < z) /* try smaller tables up to z bits */ - { - if ((f <<= 1) <= *++xp) - break; /* enough codes to use up j bits */ - f -= *xp; /* else deduct codes from patterns */ - } + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if ((type == LENS && used > ENOUGH_LENS) || + (type == DISTS && used > ENOUGH_DISTS)) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + here.bits = (unsigned char)(len - drop); + if (work[sym] + 1U < match) { + here.op = (unsigned char)0; + here.val = work[sym]; } - z = 1 << j; /* table entries for j-bit table */ - - /* allocate new table */ - if (*hn + z > MANY) /* (note: doesn't matter for fixed) */ - return Z_DATA_ERROR; /* overflow of MANY */ - u[h] = q = hp + *hn; - *hn += z; - - /* connect to last table, if there is one */ - if (h) - { - x[h] = i; /* save pattern for backing up */ - r.bits = (Byte)l; /* bits to dump before this table */ - r.exop = (Byte)j; /* bits in this table */ - j = i >> (w - l); - r.base = (uInt)(q - u[h-1] - j); /* offset to this table */ - u[h-1][j] = r; /* connect to last table */ + else if (work[sym] >= match) { + here.op = (unsigned char)(extra[work[sym] - match]); + here.val = base[work[sym] - match]; + } + else { + here.op = (unsigned char)(32 + 64); /* end of block */ + here.val = 0; } - else - *t = q; /* first table is returned result */ - } - - /* set up table entry in r */ - r.bits = (Byte)(k - w); - if (p >= v + n) - r.exop = 128 + 64; /* out of values--invalid code */ - else if (*p < s) - { - r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ - r.base = *p++; /* simple code is just the value */ - } - else - { - r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ - r.base = d[*p++ - s]; - } - - /* fill code-like entries with r */ - f = 1 << (k - w); - for (j = i >> w; j < z; j += f) - q[j] = r; - - /* backwards increment the k-bit code i */ - for (j = 1 << (k - 1); i & j; j >>= 1) - i ^= j; - i ^= j; - - /* backup over finished tables */ - mask = (1 << w) - 1; /* needed on HP, cc -O bug */ - while ((i & mask) != x[h]) - { - h--; /* don't need to update q */ - w -= l; - mask = (1 << w) - 1; - } - } - } - - - /* Return Z_BUF_ERROR if we were given an incomplete table */ - return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; -} + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = here; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; -int inflate_trees_bits(c, bb, tb, hp, z) -uIntf *c; /* 19 code lengths */ -uIntf *bb; /* bits tree desired/actual depth */ -inflate_huft * FAR *tb; /* bits tree result */ -inflate_huft *hp; /* space for trees */ -z_streamp z; /* for messages */ -{ - int r; - uInt hn = 0; /* hufts used in space */ - uIntf *v; /* work area for huft_build */ - - if ((v = (uIntf*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL) - return Z_MEM_ERROR; - r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, - tb, bb, hp, &hn, v); - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed dynamic bit lengths tree"; - else if (r == Z_BUF_ERROR || *bb == 0) - { - z->msg = (char*)"incomplete dynamic bit lengths tree"; - r = Z_DATA_ERROR; - } - ZFREE(z, v); - return r; -} + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } -int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z) -uInt nl; /* number of literal/length codes */ -uInt nd; /* number of distance codes */ -uIntf *c; /* that many (total) code lengths */ -uIntf *bl; /* literal desired/actual bit depth */ -uIntf *bd; /* distance desired/actual bit depth */ -inflate_huft * FAR *tl; /* literal/length tree result */ -inflate_huft * FAR *td; /* distance tree result */ -inflate_huft *hp; /* space for trees */ -z_streamp z; /* for messages */ -{ - int r; - uInt hn = 0; /* hufts used in space */ - uIntf *v; /* work area for huft_build */ - - /* allocate work area */ - if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) - return Z_MEM_ERROR; - - /* build literal/length tree */ - r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); - if (r != Z_OK || *bl == 0) - { - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed literal/length tree"; - else if (r != Z_MEM_ERROR) - { - z->msg = (char*)"incomplete literal/length tree"; - r = Z_DATA_ERROR; - } - ZFREE(z, v); - return r; - } - - /* build distance tree */ - r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); - if (r != Z_OK || (*bd == 0 && nl > 257)) - { - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed distance tree"; - else if (r == Z_BUF_ERROR) { -#ifdef PKZIP_BUG_WORKAROUND - r = Z_OK; - } -#else - z->msg = (char*)"incomplete distance tree"; - r = Z_DATA_ERROR; - } - else if (r != Z_MEM_ERROR) - { - z->msg = (char*)"empty distance tree with lengths"; - r = Z_DATA_ERROR; + /* check for enough space */ + used += 1U << curr; + if ((type == LENS && used > ENOUGH_LENS) || + (type == DISTS && used > ENOUGH_DISTS)) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } } - ZFREE(z, v); - return r; -#endif - } - - /* done */ - ZFREE(z, v); - return Z_OK; -} - -/* build fixed tables only once--keep them here */ -#ifdef BUILDFIXED -local int fixed_built = 0; -#define FIXEDH 544 /* number of hufts used by fixed tables */ -local inflate_huft fixed_mem[FIXEDH]; -local uInt fixed_bl; -local uInt fixed_bd; -local inflate_huft *fixed_tl; -local inflate_huft *fixed_td; -#else -#include "inffixed.h" -#endif - - -int inflate_trees_fixed(bl, bd, tl, td, z) -uIntf *bl; /* literal desired/actual bit depth */ -uIntf *bd; /* distance desired/actual bit depth */ -inflate_huft * FAR *tl; /* literal/length tree result */ -inflate_huft * FAR *td; /* distance tree result */ -z_streamp z; /* for memory allocation */ -{ -#ifdef BUILDFIXED - /* build fixed tables if not already */ - if (!fixed_built) - { - int k; /* temporary variable */ - uInt f = 0; /* number of hufts used in fixed_mem */ - uIntf *c; /* length list for huft_build */ - uIntf *v; /* work area for huft_build */ - - /* allocate memory */ - if ((c = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) - return Z_MEM_ERROR; - if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) - { - ZFREE(z, c); - return Z_MEM_ERROR; + /* fill in remaining table entry if code is incomplete (guaranteed to have + at most one remaining entry, since if the code is incomplete, the + maximum code length that was allowed to get this far is one bit) */ + if (huff != 0) { + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)(len - drop); + here.val = (unsigned short)0; + next[huff] = here; } - /* literal table */ - for (k = 0; k < 144; k++) - c[k] = 8; - for (; k < 256; k++) - c[k] = 9; - for (; k < 280; k++) - c[k] = 7; - for (; k < 288; k++) - c[k] = 8; - fixed_bl = 9; - huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, - fixed_mem, &f, v); - - /* distance table */ - for (k = 0; k < 30; k++) - c[k] = 5; - fixed_bd = 5; - huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, - fixed_mem, &f, v); - - /* done */ - ZFREE(z, v); - ZFREE(z, c); - fixed_built = 1; - } -#endif - *bl = fixed_bl; - *bd = fixed_bd; - *tl = fixed_tl; - *td = fixed_td; - return Z_OK; + /* set return parameters */ + *table += used; + *bits = root; + return 0; } diff --git a/ZLIB/inftrees.h b/ZLIB/inftrees.h index 04b73b72..396f74b5 100644 --- a/ZLIB/inftrees.h +++ b/ZLIB/inftrees.h @@ -1,6 +1,6 @@ /* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995-2002 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is @@ -8,51 +8,55 @@ subject to change. Applications should only use zlib.h. */ -/* Huffman code lookup table entry--this entry is four bytes for machines - that have 16-bit pointers (e.g. PC's in the small or medium model). */ - -typedef struct inflate_huft_s FAR inflate_huft; - -struct inflate_huft_s { - union { - struct { - Byte Exop; /* number of extra bits or operation */ - Byte Bits; /* number of bits in this code or subcode */ - } what; - uInt pad; /* pad structure to a power of 2 (4 bytes for */ - } word; /* 16-bit, 8 bytes for 32-bit int's) */ - uInt base; /* literal, length base, distance base, - or table offset */ -}; - -/* Maximum size of dynamic tree. The maximum found in a long but non- - exhaustive search was 1004 huft structures (850 for length/literals - and 154 for distances, the latter actually the result of an - exhaustive search). The actual maximum is not known, but the - value below is more than safe. */ -#define MANY 1440 - -extern int inflate_trees_bits OF(( - uIntf *, /* 19 code lengths */ - uIntf *, /* bits tree desired/actual depth */ - inflate_huft * FAR *, /* bits tree result */ - inflate_huft *, /* space for trees */ - z_streamp)); /* for messages */ - -extern int inflate_trees_dynamic OF(( - uInt, /* number of literal/length codes */ - uInt, /* number of distance codes */ - uIntf *, /* that many (total) code lengths */ - uIntf *, /* literal desired/actual bit depth */ - uIntf *, /* distance desired/actual bit depth */ - inflate_huft * FAR *, /* literal/length tree result */ - inflate_huft * FAR *, /* distance tree result */ - inflate_huft *, /* space for trees */ - z_streamp)); /* for messages */ +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ -extern int inflate_trees_fixed OF(( - uIntf *, /* literal desired/actual bit depth */ - uIntf *, /* distance desired/actual bit depth */ - inflate_huft * FAR *, /* literal/length tree result */ - inflate_huft * FAR *, /* distance tree result */ - z_streamp)); /* for memory allocation */ +/* Maximum size of the dynamic table. The maximum number of code structures is + 1444, which is the sum of 852 for literal/length codes and 592 for distance + codes. These values were found by exhaustive searches using the program + examples/enough.c found in the zlib distribution. The arguments to that + program are the number of symbols, the initial root table size, and the + maximum bit length of a code. "enough 286 9 15" for literal/length codes + returns 852, and "enough 30 6 15" for distance codes returns 592. The + initial root table size (9 or 6) is found in the fifth argument of the + inflate_table() calls in inflate.c and infback.c. If the root table size is + changed, then these maximum sizes would be need to be recalculated and + updated. */ +#define ENOUGH_LENS 852 +#define ENOUGH_DISTS 592 +#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) + +/* Type of code to build for inflate_table() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work); diff --git a/ZLIB/infutil.c b/ZLIB/infutil.c deleted file mode 100644 index 9a076221..00000000 --- a/ZLIB/infutil.c +++ /dev/null @@ -1,87 +0,0 @@ -/* inflate_util.c -- data and routines common to blocks and codes - * Copyright (C) 1995-2002 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "infblock.h" -#include "inftrees.h" -#include "infcodes.h" -#include "infutil.h" - -struct inflate_codes_state {int dummy;}; /* for buggy compilers */ - -/* And'ing with mask[n] masks the lower n bits */ -uInt inflate_mask[17] = { - 0x0000, - 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, - 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff -}; - - -/* copy as much as possible from the sliding window to the output area */ -int inflate_flush(s, z, r) -inflate_blocks_statef *s; -z_streamp z; -int r; -{ - uInt n; - Bytef *p; - Bytef *q; - - /* local copies of source and destination pointers */ - p = z->next_out; - q = s->read; - - /* compute number of bytes to copy as far as end of window */ - n = (uInt)((q <= s->write ? s->write : s->end) - q); - if (n > z->avail_out) n = z->avail_out; - if (n && r == Z_BUF_ERROR) r = Z_OK; - - /* update counters */ - z->avail_out -= n; - z->total_out += n; - - /* update check information */ - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(s->check, q, n); - - /* copy as far as end of window */ - zmemcpy(p, q, n); - p += n; - q += n; - - /* see if more to copy at beginning of window */ - if (q == s->end) - { - /* wrap pointers */ - q = s->window; - if (s->write == s->end) - s->write = s->window; - - /* compute bytes to copy */ - n = (uInt)(s->write - q); - if (n > z->avail_out) n = z->avail_out; - if (n && r == Z_BUF_ERROR) r = Z_OK; - - /* update counters */ - z->avail_out -= n; - z->total_out += n; - - /* update check information */ - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(s->check, q, n); - - /* copy */ - zmemcpy(p, q, n); - p += n; - q += n; - } - - /* update pointers */ - z->next_out = p; - s->read = q; - - /* done */ - return r; -} diff --git a/ZLIB/infutil.h b/ZLIB/infutil.h deleted file mode 100644 index 4401df82..00000000 --- a/ZLIB/infutil.h +++ /dev/null @@ -1,98 +0,0 @@ -/* infutil.h -- types and macros common to blocks and codes - * Copyright (C) 1995-2002 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -#ifndef _INFUTIL_H -#define _INFUTIL_H - -typedef enum { - TYPE, /* get type bits (3, including end bit) */ - LENS, /* get lengths for stored */ - STORED, /* processing stored block */ - TABLE, /* get table lengths */ - BTREE, /* get bit lengths tree for a dynamic block */ - DTREE, /* get length, distance trees for a dynamic block */ - CODES, /* processing fixed or dynamic block */ - DRY, /* output remaining window bytes */ - DONE, /* finished last block, done */ - BAD} /* got a data error--stuck here */ -inflate_block_mode; - -/* inflate blocks semi-private state */ -struct inflate_blocks_state { - - /* mode */ - inflate_block_mode mode; /* current inflate_block mode */ - - /* mode dependent information */ - union { - uInt left; /* if STORED, bytes left to copy */ - struct { - uInt table; /* table lengths (14 bits) */ - uInt index; /* index into blens (or border) */ - uIntf *blens; /* bit lengths of codes */ - uInt bb; /* bit length tree depth */ - inflate_huft *tb; /* bit length decoding tree */ - } trees; /* if DTREE, decoding info for trees */ - struct { - inflate_codes_statef - *codes; - } decode; /* if CODES, current state */ - } sub; /* submode */ - uInt last; /* true if this block is the last block */ - - /* mode independent information */ - uInt bitk; /* bits in bit buffer */ - uLong bitb; /* bit buffer */ - inflate_huft *hufts; /* single malloc for tree space */ - Bytef *window; /* sliding window */ - Bytef *end; /* one byte after sliding window */ - Bytef *read; /* window read pointer */ - Bytef *write; /* window write pointer */ - check_func checkfn; /* check function */ - uLong check; /* check on output */ - -}; - - -/* defines for inflate input/output */ -/* update pointers and return */ -#define UPDBITS {s->bitb=b;s->bitk=k;} -#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} -#define UPDOUT {s->write=q;} -#define UPDATE {UPDBITS UPDIN UPDOUT} -#define LEAVE {UPDATE return inflate_flush(s,z,r);} -/* get bytes and bits */ -#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} -#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} -#define NEXTBYTE (n--,*p++) -#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} -/* output bytes */ -#define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) -#define LOADOUT {q=s->write;m=(uInt)WAVAIL;} -#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} -#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} -#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} -#define OUTBYTE(a) {*q++=(Byte)(a);m--;} -/* load local pointers */ -#define LOAD {LOADIN LOADOUT} - -/* masks for lower bits (size given to avoid silly warnings with Visual C++) */ -extern uInt inflate_mask[17]; - -/* copy as much as possible from the sliding window to the output area */ -extern int inflate_flush OF(( - inflate_blocks_statef *, - z_streamp , - int)); - -struct internal_state {int dummy;}; /* for buggy compilers */ - -#endif diff --git a/ZLIB/trees.c b/ZLIB/trees.c index 1942c186..6a523ef3 100644 --- a/ZLIB/trees.c +++ b/ZLIB/trees.c @@ -1,6 +1,7 @@ /* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-2002 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2024 Jean-loup Gailly + * detect_data_type() function provided freely by Cosmin Truta, 2006 + * For conditions of distribution and use, see copyright notice in zlib.h */ /* @@ -29,13 +30,13 @@ * Addison-Wesley, 1983. ISBN 0-201-06672-6. */ -/* @(#) $Id: trees.c,v 1.1 2014/03/04 21:20:44 uid42406 Exp $ */ +/* @(#) $Id$ */ /* #define GEN_TREES_H */ #include "deflate.h" -#ifdef DEBUG +#ifdef ZLIB_DEBUG # include #endif @@ -73,11 +74,6 @@ local const uch bl_order[BL_CODES] * probability, to avoid transmitting the lengths for unused bit length codes. */ -#define Buf_size (8 * 2*sizeof(char)) -/* Number of bits used within bi_buf. (bi_buf might be implemented on - * more than 16 bits on some systems.) - */ - /* =========================================================================== * Local data. These are initialized only once. */ @@ -126,118 +122,176 @@ struct static_tree_desc_s { int max_length; /* max bit length for the codes */ }; -local static_tree_desc static_l_desc = +#ifdef NO_INIT_GLOBAL_POINTERS +# define TCONST +#else +# define TCONST const +#endif + +local TCONST static_tree_desc static_l_desc = {static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; -local static_tree_desc static_d_desc = +local TCONST static_tree_desc static_d_desc = {static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; -local static_tree_desc static_bl_desc = +local TCONST static_tree_desc static_bl_desc = {(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; /* =========================================================================== - * Local (static) routines in this file. + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 */ +local unsigned bi_reverse(unsigned code, int len) { + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(deflate_state *s) { + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(deflate_state *s) { + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef ZLIB_DEBUG + s->bits_sent = (s->bits_sent + 7) & ~7; +#endif +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes(ct_data *tree, int max_code, ushf *bl_count) { + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + unsigned code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + code = (code + bl_count[bits - 1]) << 1; + next_code[bits] = (ush)code; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1, + "inconsistent bit counts"); + Tracev((stderr,"\ngen_codes: max_code %d ", max_code)); + + for (n = 0; n <= max_code; n++) { + int len = tree[n].Len; + if (len == 0) continue; + /* Now reverse the bits */ + tree[n].Code = (ush)bi_reverse(next_code[len]++, len); -local void tr_static_init OF((void)); -local void init_block OF((deflate_state *s)); -local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); -local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); -local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); -local void build_tree OF((deflate_state *s, tree_desc *desc)); -local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local int build_bl_tree OF((deflate_state *s)); -local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, - int blcodes)); -local void compress_block OF((deflate_state *s, ct_data *ltree, - ct_data *dtree)); -local void set_data_type OF((deflate_state *s)); -local unsigned bi_reverse OF((unsigned value, int length)); -local void bi_windup OF((deflate_state *s)); -local void bi_flush OF((deflate_state *s)); -local void copy_block OF((deflate_state *s, charf *buf, unsigned len, - int header)); + Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ", + n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len] - 1)); + } +} #ifdef GEN_TREES_H -local void gen_trees_header OF((void)); +local void gen_trees_header(void); #endif -#ifndef DEBUG +#ifndef ZLIB_DEBUG # define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) /* Send a code of the given tree. c and tree must not have side effects */ -#else /* DEBUG */ +#else /* !ZLIB_DEBUG */ # define send_code(s, c, tree) \ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ send_bits(s, tree[c].Code, tree[c].Len); } #endif -/* =========================================================================== - * Output a short LSB first on the stream. - * IN assertion: there is enough room in pendingBuf. - */ -#define put_short(s, w) { \ - put_byte(s, (uch)((w) & 0xff)); \ - put_byte(s, (uch)((ush)(w) >> 8)); \ -} - /* =========================================================================== * Send a value on a given number of bits. * IN assertion: length <= 16 and value fits in length bits. */ -#ifdef DEBUG -local void send_bits OF((deflate_state *s, int value, int length)); - -local void send_bits(s, value, length) - deflate_state *s; - int value; /* value to send */ - int length; /* number of bits */ -{ +#ifdef ZLIB_DEBUG +local void send_bits(deflate_state *s, int value, int length) { Tracevv((stderr," l %2d v %4x ", length, value)); Assert(length > 0 && length <= 15, "invalid length"); s->bits_sent += (ulg)length; /* If not enough room in bi_buf, use (valid) bits from bi_buf and - * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * (16 - bi_valid) bits from value, leaving (width - (16 - bi_valid)) * unused bits in value. */ if (s->bi_valid > (int)Buf_size - length) { - s->bi_buf |= (value << s->bi_valid); + s->bi_buf |= (ush)value << s->bi_valid; put_short(s, s->bi_buf); s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); s->bi_valid += length - Buf_size; } else { - s->bi_buf |= value << s->bi_valid; + s->bi_buf |= (ush)value << s->bi_valid; s->bi_valid += length; } } -#else /* !DEBUG */ +#else /* !ZLIB_DEBUG */ #define send_bits(s, value, length) \ { int len = length;\ if (s->bi_valid > (int)Buf_size - len) {\ - int val = value;\ - s->bi_buf |= (val << s->bi_valid);\ + int val = (int)value;\ + s->bi_buf |= (ush)val << s->bi_valid;\ put_short(s, s->bi_buf);\ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ s->bi_valid += len - Buf_size;\ } else {\ - s->bi_buf |= (value) << s->bi_valid;\ + s->bi_buf |= (ush)(value) << s->bi_valid;\ s->bi_valid += len;\ }\ } -#endif /* DEBUG */ +#endif /* ZLIB_DEBUG */ -#define MAX(a,b) (a >= b ? a : b) /* the arguments must not have side effects */ /* =========================================================================== * Initialize the various 'constant' tables. */ -local void tr_static_init() -{ +local void tr_static_init(void) { #if defined(GEN_TREES_H) || !defined(STDC) static int static_init_done = 0; int n; /* iterates over tree elements */ @@ -251,17 +305,19 @@ local void tr_static_init() if (static_init_done) return; /* For some embedded targets, global variables are not initialized: */ +#ifdef NO_INIT_GLOBAL_POINTERS static_l_desc.static_tree = static_ltree; static_l_desc.extra_bits = extra_lbits; static_d_desc.static_tree = static_dtree; static_d_desc.extra_bits = extra_dbits; static_bl_desc.extra_bits = extra_blbits; +#endif /* Initialize the mapping length (0..255) -> length code (0..28) */ length = 0; for (code = 0; code < LENGTH_CODES-1; code++) { base_length[code] = length; - for (n = 0; n < (1< dist code (0..29) */ dist = 0; for (code = 0 ; code < 16; code++) { base_dist[code] = dist; - for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ for ( ; code < D_CODES; code++) { base_dist[code] = dist << 7; - for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) { _dist_code[256 + dist++] = (uch)code; } } - Assert (dist == 256, "tr_static_init: 256+dist != 512"); + Assert (dist == 256, "tr_static_init: 256 + dist != 512"); /* Construct the codes of the static literal tree */ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; @@ -317,72 +373,86 @@ local void tr_static_init() } /* =========================================================================== - * Genererate the file trees.h describing the static trees. + * Generate the file trees.h describing the static trees. */ #ifdef GEN_TREES_H -# ifndef DEBUG +# ifndef ZLIB_DEBUG # include # endif # define SEPARATOR(i, last, width) \ ((i) == (last)? "\n};\n\n" : \ - ((i) % (width) == (width)-1 ? ",\n" : ", ")) + ((i) % (width) == (width) - 1 ? ",\n" : ", ")) -void gen_trees_header() -{ +void gen_trees_header(void) { FILE *header = fopen("trees.h", "w"); int i; Assert (header != NULL, "Can't open trees.h"); fprintf(header, - "/* header created automatically with -DGEN_TREES_H */\n\n"); + "/* header created automatically with -DGEN_TREES_H */\n\n"); fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); for (i = 0; i < L_CODES+2; i++) { - fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, - static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); } fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); for (i = 0; i < D_CODES; i++) { - fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, - static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); } - fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n"); for (i = 0; i < DIST_CODE_LEN; i++) { - fprintf(header, "%2u%s", _dist_code[i], - SEPARATOR(i, DIST_CODE_LEN-1, 20)); + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); } - fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + fprintf(header, + "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { - fprintf(header, "%2u%s", _length_code[i], - SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); } fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); for (i = 0; i < LENGTH_CODES; i++) { - fprintf(header, "%1u%s", base_length[i], - SEPARATOR(i, LENGTH_CODES-1, 20)); + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); } fprintf(header, "local const int base_dist[D_CODES] = {\n"); for (i = 0; i < D_CODES; i++) { - fprintf(header, "%5u%s", base_dist[i], - SEPARATOR(i, D_CODES-1, 10)); + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); } fclose(header); } #endif /* GEN_TREES_H */ +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(deflate_state *s) { + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->sym_next = s->matches = 0; +} + /* =========================================================================== * Initialize the tree data structures for a new zlib stream. */ -void _tr_init(s) - deflate_state *s; -{ +void ZLIB_INTERNAL _tr_init(deflate_state *s) { tr_static_init(); s->l_desc.dyn_tree = s->dyn_ltree; @@ -396,8 +466,7 @@ void _tr_init(s) s->bi_buf = 0; s->bi_valid = 0; - s->last_eob_len = 8; /* enough lookahead for inflate */ -#ifdef DEBUG +#ifdef ZLIB_DEBUG s->compressed_len = 0L; s->bits_sent = 0L; #endif @@ -406,24 +475,6 @@ void _tr_init(s) init_block(s); } -/* =========================================================================== - * Initialize a new block. - */ -local void init_block(s) - deflate_state *s; -{ - int n; /* iterates over tree elements */ - - /* Initialize the trees. */ - for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; - for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; - for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; - - s->dyn_ltree[END_BLOCK].Freq = 1; - s->opt_len = s->static_len = 0L; - s->last_lit = s->matches = 0; -} - #define SMALLEST 1 /* Index within the heap array of least frequent node in the Huffman tree */ @@ -453,17 +504,13 @@ local void init_block(s) * when the heap property is re-established (each father smaller than its * two sons). */ -local void pqdownheap(s, tree, k) - deflate_state *s; - ct_data *tree; /* the tree to restore */ - int k; /* node to move down */ -{ +local void pqdownheap(deflate_state *s, ct_data *tree, int k) { int v = s->heap[k]; int j = k << 1; /* left son of k */ while (j <= s->heap_len) { /* Set j to the smallest of the two sons: */ if (j < s->heap_len && - smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + smaller(tree, s->heap[j + 1], s->heap[j], s->depth)) { j++; } /* Exit if v is smaller than both sons */ @@ -488,10 +535,7 @@ local void pqdownheap(s, tree, k) * The length opt_len is updated; static_len is also updated if stree is * not null. */ -local void gen_bitlen(s, desc) - deflate_state *s; - tree_desc *desc; /* the tree descriptor */ -{ +local void gen_bitlen(deflate_state *s, tree_desc *desc) { ct_data *tree = desc->dyn_tree; int max_code = desc->max_code; const ct_data *stree = desc->stat_desc->static_tree; @@ -512,7 +556,7 @@ local void gen_bitlen(s, desc) */ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ - for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + for (h = s->heap_max + 1; h < HEAP_SIZE; h++) { n = s->heap[h]; bits = tree[tree[n].Dad].Len + 1; if (bits > max_length) bits = max_length, overflow++; @@ -523,22 +567,22 @@ local void gen_bitlen(s, desc) s->bl_count[bits]++; xbits = 0; - if (n >= base) xbits = extra[n-base]; + if (n >= base) xbits = extra[n - base]; f = tree[n].Freq; - s->opt_len += (ulg)f * (bits + xbits); - if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + s->opt_len += (ulg)f * (unsigned)(bits + xbits); + if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits); } if (overflow == 0) return; - Trace((stderr,"\nbit length overflow\n")); + Tracev((stderr,"\nbit length overflow\n")); /* This happens for example on obj2 and pic of the Calgary corpus */ /* Find the first bit length which could increase: */ do { - bits = max_length-1; + bits = max_length - 1; while (s->bl_count[bits] == 0) bits--; - s->bl_count[bits]--; /* move one leaf down the tree */ - s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits + 1] += 2; /* move one overflow item as its brother */ s->bl_count[max_length]--; /* The brother of the overflow item also moves one step up, * but this does not affect bl_count[max_length] @@ -556,10 +600,9 @@ local void gen_bitlen(s, desc) while (n != 0) { m = s->heap[--h]; if (m > max_code) continue; - if (tree[m].Len != (unsigned) bits) { - Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); - s->opt_len += ((long)bits - (long)tree[m].Len) - *(long)tree[m].Freq; + if ((unsigned) tree[m].Len != (unsigned) bits) { + Tracev((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((ulg)bits - tree[m].Len) * tree[m].Freq; tree[m].Len = (ush)bits; } n--; @@ -567,47 +610,9 @@ local void gen_bitlen(s, desc) } } -/* =========================================================================== - * Generate the codes for a given tree and bit counts (which need not be - * optimal). - * IN assertion: the array bl_count contains the bit length statistics for - * the given tree and the field len is set for all tree elements. - * OUT assertion: the field code is set for all tree elements of non - * zero code length. - */ -local void gen_codes (tree, max_code, bl_count) - ct_data *tree; /* the tree to decorate */ - int max_code; /* largest code with non zero frequency */ - ushf *bl_count; /* number of codes at each bit length */ -{ - ush next_code[MAX_BITS+1]; /* next code value for each bit length */ - ush code = 0; /* running code value */ - int bits; /* bit index */ - int n; /* code index */ - - /* The distribution counts are first used to generate the code values - * without bit reversal. - */ - for (bits = 1; bits <= MAX_BITS; bits++) { - next_code[bits] = code = (code + bl_count[bits-1]) << 1; - } - /* Check that the bit counts in bl_count are consistent. The last code - * must be all ones. - */ - Assert (code + bl_count[MAX_BITS]-1 == (1< +#endif /* =========================================================================== * Construct one Huffman tree and assigns the code bit strings and lengths. @@ -617,10 +622,7 @@ local void gen_codes (tree, max_code, bl_count) * and corresponding code. The length opt_len is updated; static_len is * also updated if stree is not null. The field max_code is set. */ -local void build_tree(s, desc) - deflate_state *s; - tree_desc *desc; /* the tree descriptor */ -{ +local void build_tree(deflate_state *s, tree_desc *desc) { ct_data *tree = desc->dyn_tree; const ct_data *stree = desc->stat_desc->static_tree; int elems = desc->stat_desc->elems; @@ -629,7 +631,7 @@ local void build_tree(s, desc) int node; /* new node being created */ /* Construct the initial heap, with least frequent element in - * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n + 1]. * heap[0] is not used. */ s->heap_len = 0, s->heap_max = HEAP_SIZE; @@ -657,7 +659,7 @@ local void build_tree(s, desc) } desc->max_code = max_code; - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + /* The elements heap[heap_len/2 + 1 .. heap_len] are leaves of the tree, * establish sub-heaps of increasing lengths: */ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); @@ -675,7 +677,8 @@ local void build_tree(s, desc) /* Create a new node father of n and m */ tree[node].Freq = tree[n].Freq + tree[m].Freq; - s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1); + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); tree[n].Dad = tree[m].Dad = (ush)node; #ifdef DUMP_BL_TREE if (tree == s->bl_tree) { @@ -704,11 +707,7 @@ local void build_tree(s, desc) * Scan a literal or distance tree to determine the frequencies of the codes * in the bit length tree. */ -local void scan_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ +local void scan_tree(deflate_state *s, ct_data *tree, int max_code) { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ @@ -718,10 +717,10 @@ local void scan_tree (s, tree, max_code) int min_count = 4; /* min repeat count */ if (nextlen == 0) max_count = 138, min_count = 3; - tree[max_code+1].Len = (ush)0xffff; /* guard */ + tree[max_code + 1].Len = (ush)0xffff; /* guard */ for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; + curlen = nextlen; nextlen = tree[n + 1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { @@ -749,11 +748,7 @@ local void scan_tree (s, tree, max_code) * Send a literal or distance tree in compressed form, using the codes in * bl_tree. */ -local void send_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ +local void send_tree(deflate_state *s, ct_data *tree, int max_code) { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ @@ -762,11 +757,11 @@ local void send_tree (s, tree, max_code) int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ - /* tree[max_code+1].Len = -1; */ /* guard already set */ + /* tree[max_code + 1].Len = -1; */ /* guard already set */ if (nextlen == 0) max_count = 138, min_count = 3; for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; + curlen = nextlen; nextlen = tree[n + 1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { @@ -777,13 +772,13 @@ local void send_tree (s, tree, max_code) send_code(s, curlen, s->bl_tree); count--; } Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count - 3, 2); } else if (count <= 10) { - send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count - 3, 3); } else { - send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count - 11, 7); } count = 0; prevlen = curlen; if (nextlen == 0) { @@ -800,9 +795,7 @@ local void send_tree (s, tree, max_code) * Construct the Huffman tree for the bit lengths and return the index in * bl_order of the last bit length code to send. */ -local int build_bl_tree(s) - deflate_state *s; -{ +local int build_bl_tree(deflate_state *s) { int max_blindex; /* index of last bit length code of non zero freq */ /* Determine the bit length frequencies for literal and distance trees */ @@ -811,8 +804,8 @@ local int build_bl_tree(s) /* Build the bit length tree: */ build_tree(s, (tree_desc *)(&(s->bl_desc))); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + /* opt_len now includes the length of the tree representations, except the + * lengths of the bit lengths codes and the 5 + 5 + 4 bits for the counts. */ /* Determine the number of bit length codes to send. The pkzip format @@ -823,7 +816,7 @@ local int build_bl_tree(s) if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; } /* Update opt_len to include the bit length tree and counts */ - s->opt_len += 3*(max_blindex+1) + 5+5+4; + s->opt_len += 3*((ulg)max_blindex + 1) + 5 + 5 + 4; Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", s->opt_len, s->static_len)); @@ -835,140 +828,221 @@ local int build_bl_tree(s) * lengths of the bit length codes, the literal tree and the distance tree. * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. */ -local void send_all_trees(s, lcodes, dcodes, blcodes) - deflate_state *s; - int lcodes, dcodes, blcodes; /* number of codes for each tree */ -{ +local void send_all_trees(deflate_state *s, int lcodes, int dcodes, + int blcodes) { int rank; /* index in bl_order */ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, "too many codes"); Tracev((stderr, "\nbl counts: ")); - send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ - send_bits(s, dcodes-1, 5); - send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes - 1, 5); + send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */ for (rank = 0; rank < blcodes; rank++) { Tracev((stderr, "\nbl code %2d ", bl_order[rank])); send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); } Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); - send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + send_tree(s, (ct_data *)s->dyn_ltree, lcodes - 1); /* literal tree */ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); - send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + send_tree(s, (ct_data *)s->dyn_dtree, dcodes - 1); /* distance tree */ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); } /* =========================================================================== * Send a stored block */ -void _tr_stored_block(s, buf, stored_len, eof) - deflate_state *s; - charf *buf; /* input block */ - ulg stored_len; /* length of input block */ - int eof; /* true if this is the last block for a file */ -{ - send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ -#ifdef DEBUG +void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf, + ulg stored_len, int last) { + send_bits(s, (STORED_BLOCK<<1) + last, 3); /* send block type */ + bi_windup(s); /* align on byte boundary */ + put_short(s, (ush)stored_len); + put_short(s, (ush)~stored_len); + if (stored_len) + zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len); + s->pending += stored_len; +#ifdef ZLIB_DEBUG s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; s->compressed_len += (stored_len + 4) << 3; + s->bits_sent += 2*16; + s->bits_sent += stored_len << 3; #endif - copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Flush the bits in the bit buffer to pending output (leaves at most 7 bits) + */ +void ZLIB_INTERNAL _tr_flush_bits(deflate_state *s) { + bi_flush(s); } /* =========================================================================== * Send one empty static block to give enough lookahead for inflate. * This takes 10 bits, of which 7 may remain in the bit buffer. - * The current inflate code requires 9 bits of lookahead. If the - * last two codes for the previous block (real code plus EOB) were coded - * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode - * the last real code. In this case we send two empty static blocks instead - * of one. (There are no problems if the previous block is stored or fixed.) - * To simplify the code, we assume the worst case of last real code encoded - * on one bit only. */ -void _tr_align(s) - deflate_state *s; -{ +void ZLIB_INTERNAL _tr_align(deflate_state *s) { send_bits(s, STATIC_TREES<<1, 3); send_code(s, END_BLOCK, static_ltree); -#ifdef DEBUG +#ifdef ZLIB_DEBUG s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ #endif bi_flush(s); - /* Of the 10 bits for the empty block, we have already sent - * (10 - bi_valid) bits. The lookahead for the last real code (before - * the EOB of the previous block) was thus at least one plus the length - * of the EOB plus what we have just sent of the empty static block. - */ - if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { - send_bits(s, STATIC_TREES<<1, 3); - send_code(s, END_BLOCK, static_ltree); -#ifdef DEBUG - s->compressed_len += 10L; +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(deflate_state *s, const ct_data *ltree, + const ct_data *dtree) { + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned sx = 0; /* running index in symbol buffers */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->sym_next != 0) do { +#ifdef LIT_MEM + dist = s->d_buf[sx]; + lc = s->l_buf[sx++]; +#else + dist = s->sym_buf[sx++] & 0xff; + dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8; + lc = s->sym_buf[sx++]; #endif - bi_flush(s); - } - s->last_eob_len = 7; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code + LITERALS + 1, ltree); /* send length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= (unsigned)base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check for no overlay of pending_buf on needed symbols */ +#ifdef LIT_MEM + Assert(s->pending < 2 * (s->lit_bufsize + sx), "pendingBuf overflow"); +#else + Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow"); +#endif + + } while (sx < s->sym_next); + + send_code(s, END_BLOCK, ltree); +} + +/* =========================================================================== + * Check if the data type is TEXT or BINARY, using the following algorithm: + * - TEXT if the two conditions below are satisfied: + * a) There are no non-portable control characters belonging to the + * "block list" (0..6, 14..25, 28..31). + * b) There is at least one printable character belonging to the + * "allow list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). + * - BINARY otherwise. + * - The following partially-portable control characters form a + * "gray list" that is ignored in this detection algorithm: + * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local int detect_data_type(deflate_state *s) { + /* block_mask is the bit mask of block-listed bytes + * set bits 0..6, 14..25, and 28..31 + * 0xf3ffc07f = binary 11110011111111111100000001111111 + */ + unsigned long block_mask = 0xf3ffc07fUL; + int n; + + /* Check for non-textual ("block-listed") bytes. */ + for (n = 0; n <= 31; n++, block_mask >>= 1) + if ((block_mask & 1) && (s->dyn_ltree[n].Freq != 0)) + return Z_BINARY; + + /* Check for textual ("allow-listed") bytes. */ + if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 + || s->dyn_ltree[13].Freq != 0) + return Z_TEXT; + for (n = 32; n < LITERALS; n++) + if (s->dyn_ltree[n].Freq != 0) + return Z_TEXT; + + /* There are no "block-listed" or "allow-listed" bytes: + * this stream either is empty or has tolerated ("gray-listed") bytes only. + */ + return Z_BINARY; } /* =========================================================================== * Determine the best encoding for the current block: dynamic trees, static - * trees or store, and output the encoded block to the zip file. + * trees or store, and write out the encoded block. */ -void _tr_flush_block(s, buf, stored_len, eof) - deflate_state *s; - charf *buf; /* input block, or NULL if too old */ - ulg stored_len; /* length of input block */ - int eof; /* true if this is the last block for a file */ -{ +void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf, + ulg stored_len, int last) { ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ int max_blindex = 0; /* index of last bit length code of non zero freq */ /* Build the Huffman trees unless a stored block is forced */ if (s->level > 0) { - /* Check if the file is ascii or binary */ - if (s->data_type == Z_UNKNOWN) set_data_type(s); + /* Check if the file is binary or text */ + if (s->strm->data_type == Z_UNKNOWN) + s->strm->data_type = detect_data_type(s); - /* Construct the literal and distance trees */ - build_tree(s, (tree_desc *)(&(s->l_desc))); - Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); - build_tree(s, (tree_desc *)(&(s->d_desc))); - Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - /* At this point, opt_len and static_len are the total bit lengths of - * the compressed block data, excluding the tree representations. - */ + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ - /* Build the bit length tree for the above two trees, and get the index - * in bl_order of the last bit length code to send. - */ - max_blindex = build_bl_tree(s); + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); - /* Determine the best encoding. Compute first the block length in bytes*/ - opt_lenb = (s->opt_len+3+7)>>3; - static_lenb = (s->static_len+3+7)>>3; + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len + 3 + 7) >> 3; + static_lenb = (s->static_len + 3 + 7) >> 3; - Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", - opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, - s->last_lit)); + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->sym_next / 3)); - if (static_lenb <= opt_lenb) opt_lenb = static_lenb; +#ifndef FORCE_STATIC + if (static_lenb <= opt_lenb || s->strategy == Z_FIXED) +#endif + opt_lenb = static_lenb; } else { Assert(buf != (char*)0, "lost buf"); - opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ } #ifdef FORCE_STORED if (buf != (char*)0) { /* force stored block */ #else - if (stored_len+4 <= opt_lenb && buf != (char*)0) { + if (stored_len + 4 <= opt_lenb && buf != (char*)0) { /* 4: two words for the lengths */ #endif /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. @@ -977,24 +1051,22 @@ void _tr_flush_block(s, buf, stored_len, eof) * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to * transform a block into a stored block. */ - _tr_stored_block(s, buf, stored_len, eof); + _tr_stored_block(s, buf, stored_len, last); -#ifdef FORCE_STATIC - } else if (static_lenb >= 0) { /* force static trees */ -#else } else if (static_lenb == opt_lenb) { -#endif - send_bits(s, (STATIC_TREES<<1)+eof, 3); - compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); -#ifdef DEBUG + send_bits(s, (STATIC_TREES<<1) + last, 3); + compress_block(s, (const ct_data *)static_ltree, + (const ct_data *)static_dtree); +#ifdef ZLIB_DEBUG s->compressed_len += 3 + s->static_len; #endif } else { - send_bits(s, (DYN_TREES<<1)+eof, 3); - send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, - max_blindex+1); - compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); -#ifdef DEBUG + send_bits(s, (DYN_TREES<<1) + last, 3); + send_all_trees(s, s->l_desc.max_code + 1, s->d_desc.max_code + 1, + max_blindex + 1); + compress_block(s, (const ct_data *)s->dyn_ltree, + (const ct_data *)s->dyn_dtree); +#ifdef ZLIB_DEBUG s->compressed_len += 3 + s->opt_len; #endif } @@ -1004,27 +1076,29 @@ void _tr_flush_block(s, buf, stored_len, eof) */ init_block(s); - if (eof) { + if (last) { bi_windup(s); -#ifdef DEBUG +#ifdef ZLIB_DEBUG s->compressed_len += 7; /* align on byte boundary */ #endif } - Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, - s->compressed_len-7*eof)); + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len >> 3, + s->compressed_len - 7*last)); } /* =========================================================================== * Save the match info and tally the frequency counts. Return true if * the current block must be flushed. */ -int _tr_tally (s, dist, lc) - deflate_state *s; - unsigned dist; /* distance of matched string */ - unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ -{ - s->d_buf[s->last_lit] = (ush)dist; - s->l_buf[s->last_lit++] = (uch)lc; +int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc) { +#ifdef LIT_MEM + s->d_buf[s->sym_next] = (ush)dist; + s->l_buf[s->sym_next++] = (uch)lc; +#else + s->sym_buf[s->sym_next++] = (uch)dist; + s->sym_buf[s->sym_next++] = (uch)(dist >> 8); + s->sym_buf[s->sym_next++] = (uch)lc; +#endif if (dist == 0) { /* lc is the unmatched char */ s->dyn_ltree[lc].Freq++; @@ -1036,179 +1110,8 @@ int _tr_tally (s, dist, lc) (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); - s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_ltree[_length_code[lc] + LITERALS + 1].Freq++; s->dyn_dtree[d_code(dist)].Freq++; } - -#ifdef TRUNCATE_BLOCK - /* Try to guess if it is profitable to stop the current block here */ - if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { - /* Compute an upper bound for the compressed length */ - ulg out_length = (ulg)s->last_lit*8L; - ulg in_length = (ulg)((long)s->strstart - s->block_start); - int dcode; - for (dcode = 0; dcode < D_CODES; dcode++) { - out_length += (ulg)s->dyn_dtree[dcode].Freq * - (5L+extra_dbits[dcode]); - } - out_length >>= 3; - Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", - s->last_lit, in_length, out_length, - 100L - out_length*100L/in_length)); - if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; - } -#endif - return (s->last_lit == s->lit_bufsize-1); - /* We avoid equality with lit_bufsize because of wraparound at 64K - * on 16 bit machines and because stored blocks are restricted to - * 64K-1 bytes. - */ -} - -/* =========================================================================== - * Send the block data compressed using the given Huffman trees - */ -local void compress_block(s, ltree, dtree) - deflate_state *s; - ct_data *ltree; /* literal tree */ - ct_data *dtree; /* distance tree */ -{ - unsigned dist; /* distance of matched string */ - int lc; /* match length or unmatched char (if dist == 0) */ - unsigned lx = 0; /* running index in l_buf */ - unsigned code; /* the code to send */ - int extra; /* number of extra bits to send */ - - if (s->last_lit != 0) do { - dist = s->d_buf[lx]; - lc = s->l_buf[lx++]; - if (dist == 0) { - send_code(s, lc, ltree); /* send a literal byte */ - Tracecv(isgraph(lc), (stderr," '%c' ", lc)); - } else { - /* Here, lc is the match length - MIN_MATCH */ - code = _length_code[lc]; - send_code(s, code+LITERALS+1, ltree); /* send the length code */ - extra = extra_lbits[code]; - if (extra != 0) { - lc -= base_length[code]; - send_bits(s, lc, extra); /* send the extra length bits */ - } - dist--; /* dist is now the match distance - 1 */ - code = d_code(dist); - Assert (code < D_CODES, "bad d_code"); - - send_code(s, code, dtree); /* send the distance code */ - extra = extra_dbits[code]; - if (extra != 0) { - dist -= base_dist[code]; - send_bits(s, dist, extra); /* send the extra distance bits */ - } - } /* literal or match pair ? */ - - /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ - Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow"); - - } while (lx < s->last_lit); - - send_code(s, END_BLOCK, ltree); - s->last_eob_len = ltree[END_BLOCK].Len; -} - -/* =========================================================================== - * Set the data type to ASCII or BINARY, using a crude approximation: - * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. - * IN assertion: the fields freq of dyn_ltree are set and the total of all - * frequencies does not exceed 64K (to fit in an int on 16 bit machines). - */ -local void set_data_type(s) - deflate_state *s; -{ - int n = 0; - unsigned ascii_freq = 0; - unsigned bin_freq = 0; - while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; - while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; - while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; - s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); -} - -/* =========================================================================== - * Reverse the first len bits of a code, using straightforward code (a faster - * method would use a table) - * IN assertion: 1 <= len <= 15 - */ -local unsigned bi_reverse(code, len) - unsigned code; /* the value to invert */ - int len; /* its bit length */ -{ - register unsigned res = 0; - do { - res |= code & 1; - code >>= 1, res <<= 1; - } while (--len > 0); - return res >> 1; -} - -/* =========================================================================== - * Flush the bit buffer, keeping at most 7 bits in it. - */ -local void bi_flush(s) - deflate_state *s; -{ - if (s->bi_valid == 16) { - put_short(s, s->bi_buf); - s->bi_buf = 0; - s->bi_valid = 0; - } else if (s->bi_valid >= 8) { - put_byte(s, (Byte)s->bi_buf); - s->bi_buf >>= 8; - s->bi_valid -= 8; - } -} - -/* =========================================================================== - * Flush the bit buffer and align the output on a byte boundary - */ -local void bi_windup(s) - deflate_state *s; -{ - if (s->bi_valid > 8) { - put_short(s, s->bi_buf); - } else if (s->bi_valid > 0) { - put_byte(s, (Byte)s->bi_buf); - } - s->bi_buf = 0; - s->bi_valid = 0; -#ifdef DEBUG - s->bits_sent = (s->bits_sent+7) & ~7; -#endif -} - -/* =========================================================================== - * Copy a stored block, storing first the length and its - * one's complement if requested. - */ -local void copy_block(s, buf, len, header) - deflate_state *s; - charf *buf; /* the input data */ - unsigned len; /* its length */ - int header; /* true if block header must be written */ -{ - bi_windup(s); /* align on byte boundary */ - s->last_eob_len = 8; /* enough lookahead for inflate */ - - if (header) { - put_short(s, (ush)len); - put_short(s, (ush)~len); -#ifdef DEBUG - s->bits_sent += 2*16; -#endif - } -#ifdef DEBUG - s->bits_sent += (ulg)len<<3; -#endif - while (len--) { - put_byte(s, *buf++); - } + return (s->sym_next == s->sym_end); } diff --git a/ZLIB/trees.h b/ZLIB/trees.h index 72facf90..d35639d8 100644 --- a/ZLIB/trees.h +++ b/ZLIB/trees.h @@ -70,7 +70,7 @@ local const ct_data static_dtree[D_CODES] = { {{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} }; -const uch _dist_code[DIST_CODE_LEN] = { +const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = { 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, @@ -99,7 +99,7 @@ const uch _dist_code[DIST_CODE_LEN] = { 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 }; -const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { +const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, diff --git a/ZLIB/uncompr.c b/ZLIB/uncompr.c index 39f15b4c..5e256663 100644 --- a/ZLIB/uncompr.c +++ b/ZLIB/uncompr.c @@ -1,58 +1,85 @@ /* uncompr.c -- decompress a memory buffer - * Copyright (C) 1995-2002 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2003, 2010, 2014, 2016 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h */ -/* @(#) $Id: uncompr.c,v 1.1 2014/03/04 21:20:44 uid42406 Exp $ */ +/* @(#) $Id$ */ +#define ZLIB_INTERNAL #include "zlib.h" /* =========================================================================== - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be large enough to hold the - entire uncompressed data. (The size of the uncompressed data must have - been saved previously by the compressor and transmitted to the decompressor - by some mechanism outside the scope of this compression library.) - Upon exit, destLen is the actual size of the compressed buffer. - This function can be used to decompress a whole file at once if the - input file is mmap'ed. - - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted. + Decompresses the source buffer into the destination buffer. *sourceLen is + the byte length of the source buffer. Upon entry, *destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, + *destLen is the size of the decompressed data and *sourceLen is the number + of source bytes consumed. Upon return, source + *sourceLen points to the + first unused input byte. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, or + Z_DATA_ERROR if the input data was corrupted, including if the input data is + an incomplete zlib stream. */ -int ZEXPORT uncompress (dest, destLen, source, sourceLen) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; -{ +int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen, const Bytef *source, + uLong *sourceLen) { z_stream stream; int err; + const uInt max = (uInt)-1; + uLong len, left; + Byte buf[1]; /* for detection of incomplete stream when *destLen == 0 */ - stream.next_in = (Bytef*)source; - stream.avail_in = (uInt)sourceLen; - /* Check for source > 64K on 16-bit machine: */ - if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; - - stream.next_out = dest; - stream.avail_out = (uInt)*destLen; - if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + len = *sourceLen; + if (*destLen) { + left = *destLen; + *destLen = 0; + } + else { + left = 1; + dest = buf; + } + stream.next_in = (z_const Bytef *)source; + stream.avail_in = 0; stream.zalloc = (alloc_func)0; stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; err = inflateInit(&stream); if (err != Z_OK) return err; - err = inflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) { - inflateEnd(&stream); - return err == Z_OK ? Z_BUF_ERROR : err; - } - *destLen = stream.total_out; + stream.next_out = dest; + stream.avail_out = 0; + + do { + if (stream.avail_out == 0) { + stream.avail_out = left > (uLong)max ? max : (uInt)left; + left -= stream.avail_out; + } + if (stream.avail_in == 0) { + stream.avail_in = len > (uLong)max ? max : (uInt)len; + len -= stream.avail_in; + } + err = inflate(&stream, Z_NO_FLUSH); + } while (err == Z_OK); + + *sourceLen -= len + stream.avail_in; + if (dest != buf) + *destLen = stream.total_out; + else if (stream.total_out && err == Z_BUF_ERROR) + left = 1; + + inflateEnd(&stream); + return err == Z_STREAM_END ? Z_OK : + err == Z_NEED_DICT ? Z_DATA_ERROR : + err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR : + err; +} - err = inflateEnd(&stream); - return err; +int ZEXPORT uncompress(Bytef *dest, uLongf *destLen, const Bytef *source, + uLong sourceLen) { + return uncompress2(dest, destLen, source, &sourceLen); } diff --git a/ZLIB/zconf.h b/ZLIB/zconf.h index 26756ec0..62adc8d8 100644 --- a/ZLIB/zconf.h +++ b/ZLIB/zconf.h @@ -1,102 +1,264 @@ /* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2002 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h */ -/* @(#) $Id: zconf.h,v 1.1 2014/03/04 21:20:44 uid42406 Exp $ */ +/* @(#) $Id$ */ -#ifndef _ZCONF_H -#define _ZCONF_H +#ifndef ZCONF_H +#define ZCONF_H /* * If you *really* need a unique prefix for all types and library functions, * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". */ -#ifdef Z_PREFIX -# define deflateInit_ z_deflateInit_ -# define deflate z_deflate -# define deflateEnd z_deflateEnd -# define inflateInit_ z_inflateInit_ -# define inflate z_inflate -# define inflateEnd z_inflateEnd -# define deflateInit2_ z_deflateInit2_ -# define deflateSetDictionary z_deflateSetDictionary -# define deflateCopy z_deflateCopy -# define deflateReset z_deflateReset -# define deflateParams z_deflateParams -# define inflateInit2_ z_inflateInit2_ -# define inflateSetDictionary z_inflateSetDictionary -# define inflateSync z_inflateSync -# define inflateSyncPoint z_inflateSyncPoint -# define inflateReset z_inflateReset -# define compress z_compress -# define compress2 z_compress2 -# define uncompress z_uncompress -# define adler32 z_adler32 -# define crc32 z_crc32 -# define get_crc_table z_get_crc_table - -# define Byte z_Byte -# define uInt z_uInt -# define uLong z_uLong -# define Bytef z_Bytef -# define charf z_charf -# define intf z_intf -# define uIntf z_uIntf -# define uLongf z_uLongf -# define voidpf z_voidpf -# define voidp z_voidp -#endif - -#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) -# define WIN32 -#endif -#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386) -# ifndef __32BIT__ -# define __32BIT__ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ +# define Z_PREFIX_SET + +/* all linked symbols and init macros */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_bits z__tr_flush_bits +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# define adler32_z z_adler32_z +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define crc32_combine_gen z_crc32_combine_gen +# define crc32_combine_gen64 z_crc32_combine_gen64 +# define crc32_combine_op z_crc32_combine_op +# define crc32_z z_crc32_z +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateGetDictionary z_deflateGetDictionary +# define deflateInit z_deflateInit +# define deflateInit2 z_deflateInit2 +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePending z_deflatePending +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# ifndef Z_SOLO +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzfread z_gzfread +# define gzfwrite z_gzfwrite +# define gzgetc z_gzgetc +# define gzgetc_ z_gzgetc_ +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# ifdef _WIN32 +# define gzopen_w z_gzopen_w +# endif +# define gzprintf z_gzprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzvprintf z_gzvprintf +# define gzwrite z_gzwrite +# endif +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit z_inflateBackInit +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCodesUsed z_inflateCodesUsed +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetDictionary z_inflateGetDictionary +# define inflateGetHeader z_inflateGetHeader +# define inflateInit z_inflateInit +# define inflateInit2 z_inflateInit2 +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateResetKeep z_inflateResetKeep +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflateValidate z_inflateValidate +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# ifndef Z_SOLO +# define uncompress z_uncompress +# define uncompress2 z_uncompress2 +# endif +# define zError z_zError +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# ifndef Z_SOLO +# define gzFile z_gzFile # endif +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + #endif + #if defined(__MSDOS__) && !defined(MSDOS) # define MSDOS #endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif /* * Compile with -DMAXSEG_64K if the alloc function cannot allocate more * than 64k bytes at a time (needed on systems with 16-bit int). */ -#if defined(MSDOS) && !defined(__32BIT__) +#ifdef SYS16BIT # define MAXSEG_64K #endif #ifdef MSDOS # define UNALIGNED_OK #endif -#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32)) && !defined(STDC) -# define STDC -#endif -#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__) +#ifdef __STDC_VERSION__ # ifndef STDC # define STDC # endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC #endif #ifndef STDC # ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ -# define const +# define const /* note: need a more gentle solution here */ # endif #endif -/* Some Mac compilers merge all .h files incorrectly: */ -#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__) -# define NO_DUMMY_DECL +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const #endif -/* Old Borland C incorrectly complains about missing returns: */ -#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500) -# define NEED_DUMMY_RETURN +#ifdef Z_SOLO +# ifdef _WIN64 + typedef unsigned long long z_size_t; +# else + typedef unsigned long z_size_t; +# endif +#else +# define z_longlong long long +# if defined(NO_SIZE_T) + typedef unsigned NO_SIZE_T z_size_t; +# elif defined(STDC) +# include + typedef size_t z_size_t; +# else + typedef unsigned long z_size_t; +# endif +# undef z_longlong #endif - /* Maximum value for memLevel in deflateInit2 */ #ifndef MAX_MEM_LEVEL # ifdef MAXSEG_64K @@ -124,7 +286,7 @@ Of course this will generally degrade compression (there's no free lunch). The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes + that is, 32K for windowBits=15 (default value) plus about 7 kilobytes for small objects. */ @@ -144,73 +306,90 @@ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, * just define FAR to be empty. */ -#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__) - /* MSC small or medium model */ -# define SMALL_MEDIUM -# ifdef _MSC_VER -# define FAR _far -# else -# define FAR far +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif # endif -#endif -#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__)) -# ifndef __32BIT__ +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ # define SMALL_MEDIUM -# define FAR _far +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif # endif #endif -/* Compile with -DZLIB_DLL for Windows DLL support */ -#if defined(ZLIB_DLL) -# if defined(_WINDOWS) || defined(WINDOWS) +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI # ifdef FAR # undef FAR # endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif # include -# define ZEXPORT WINAPI + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI # ifdef WIN32 -# define ZEXPORTVA WINAPIV -# else -# define ZEXPORTVA FAR _cdecl _export -# endif -# endif -# if defined (__BORLANDC__) -# if (__BORLANDC__ >= 0x0500) && defined (WIN32) -# include -# define ZEXPORT __declspec(dllexport) WINAPI -# define ZEXPORTRVA __declspec(dllexport) WINAPIV +# define ZEXPORTVA WINAPIV # else -# if defined (_Windows) && defined (__DLL__) -# define ZEXPORT _export -# define ZEXPORTVA _export -# endif +# define ZEXPORTVA FAR CDECL # endif # endif #endif #if defined (__BEOS__) -# if defined (ZLIB_DLL) -# define ZEXTERN extern __declspec(dllexport) -# else -# define ZEXTERN extern __declspec(dllimport) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif # endif #endif +#ifndef ZEXTERN +# define ZEXTERN extern +#endif #ifndef ZEXPORT # define ZEXPORT #endif #ifndef ZEXPORTVA # define ZEXPORTVA #endif -#ifndef ZEXTERN -# define ZEXTERN extern -#endif #ifndef FAR -# define FAR +# define FAR #endif -#if !defined(MACOS) && !defined(TARGET_OS_MAC) +#if !defined(__MACTYPES__) typedef unsigned char Byte; /* 8 bits */ #endif typedef unsigned int uInt; /* 16 bits or more */ @@ -228,52 +407,137 @@ typedef uInt FAR uIntf; typedef uLong FAR uLongf; #ifdef STDC - typedef void FAR *voidpf; - typedef void *voidp; + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# elif (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# elif (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short +# endif +#endif + +#ifdef Z_U4 + typedef Z_U4 z_crc_t; #else - typedef Byte FAR *voidpf; - typedef Byte *voidp; + typedef unsigned long z_crc_t; #endif -#ifdef HAVE_UNISTD_H -# include /* for off_t */ -# include /* for SEEK_* and off_t */ -# define z_off_t off_t +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H #endif -#ifndef SEEK_SET + +#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + +#ifdef STDC +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#endif + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +# include /* for va_list */ +# endif +#endif + +#ifdef _WIN32 +# ifndef Z_SOLO +# include /* for wchar_t */ +# endif +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#ifndef Z_HAVE_UNISTD_H +# ifdef __WATCOMC__ +# define Z_HAVE_UNISTD_H +# endif +#endif +#ifndef Z_HAVE_UNISTD_H +# if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32) +# define Z_HAVE_UNISTD_H +# endif +#endif +#ifndef Z_SOLO +# if defined(Z_HAVE_UNISTD_H) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && !defined(Z_SOLO) # define SEEK_SET 0 /* Seek from beginning of file. */ # define SEEK_CUR 1 /* Seek from current position. */ # define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ #endif + #ifndef z_off_t -# define z_off_t long +# define z_off_t long +#endif + +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(_WIN32) && !defined(__GNUC__) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif #endif /* MVS linker does not support external names larger than 8 bytes */ #if defined(__MVS__) -# pragma map(deflateInit_,"DEIN") -# pragma map(deflateInit2_,"DEIN2") -# pragma map(deflateEnd,"DEEND") -# pragma map(inflateInit_,"ININ") -# pragma map(inflateInit2_,"ININ2") -# pragma map(inflateEnd,"INEND") -# pragma map(inflateSync,"INSY") -# pragma map(inflateSetDictionary,"INSEDI") -# pragma map(inflate_blocks,"INBL") -# pragma map(inflate_blocks_new,"INBLNE") -# pragma map(inflate_blocks_free,"INBLFR") -# pragma map(inflate_blocks_reset,"INBLRE") -# pragma map(inflate_codes_free,"INCOFR") -# pragma map(inflate_codes,"INCO") -# pragma map(inflate_fast,"INFA") -# pragma map(inflate_flush,"INFLU") -# pragma map(inflate_mask,"INMA") -# pragma map(inflate_set_dictionary,"INSEDI2") -# pragma map(inflate_copyright,"INCOPY") -# pragma map(inflate_trees_bits,"INTRBI") -# pragma map(inflate_trees_dynamic,"INTRDY") -# pragma map(inflate_trees_fixed,"INTRFI") -# pragma map(inflate_trees_free,"INTRFR") -#endif - -#endif /* _ZCONF_H */ + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/ZLIB/zlib.h b/ZLIB/zlib.h index 52cb529f..8d4b932e 100644 --- a/ZLIB/zlib.h +++ b/ZLIB/zlib.h @@ -1,7 +1,7 @@ /* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.1.4, March 11th, 2002 + version 1.3.1, January 22nd, 2024 - Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler + Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -24,12 +24,12 @@ The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt - (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). */ -#ifndef _ZLIB_H -#define _ZLIB_H +#ifndef ZLIB_H +#define ZLIB_H #include "zconf.h" @@ -37,97 +37,142 @@ extern "C" { #endif -#define ZLIB_VERSION "1.1.4" +#define ZLIB_VERSION "1.3.1" +#define ZLIB_VERNUM 0x1310 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 3 +#define ZLIB_VER_REVISION 1 +#define ZLIB_VER_SUBREVISION 0 -/* - The 'zlib' compression library provides in-memory compression and - decompression functions, including integrity checks of the uncompressed - data. This version of the library supports only one compression method - (deflation) but other algorithms will be added later and will have the same - stream interface. - - Compression can be done in a single step if the buffers are large - enough (for example if an input file is mmap'ed), or can be done by - repeated calls of the compression function. In the latter case, the - application must provide more input and/or consume the output +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed data. + This version of the library supports only one compression method (deflation) + but other algorithms will be added later and will have the same stream + interface. + + Compression can be done in a single step if the buffers are large enough, + or can be done by repeated calls of the compression function. In the latter + case, the application must provide more input and/or consume the output (providing more output space) before each call. - The library also supports reading and writing files in gzip (.gz) format - with an interface similar to that of stdio. + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip and raw deflate streams in + memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. - The library does not install any signal handler. The decoder checks - the consistency of the compressed data, so the library should never - crash even in case of corrupted input. + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never crash + even in the case of corrupted input. */ -typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); -typedef void (*free_func) OF((voidpf opaque, voidpf address)); +typedef voidpf (*alloc_func)(voidpf opaque, uInt items, uInt size); +typedef void (*free_func)(voidpf opaque, voidpf address); struct internal_state; typedef struct z_stream_s { - Bytef *next_in; /* next input byte */ + z_const Bytef *next_in; /* next input byte */ uInt avail_in; /* number of bytes available at next_in */ - uLong total_in; /* total nb of input bytes read so far */ + uLong total_in; /* total number of input bytes read so far */ - Bytef *next_out; /* next output byte should be put there */ + Bytef *next_out; /* next output byte will go here */ uInt avail_out; /* remaining free space at next_out */ - uLong total_out; /* total nb of bytes output so far */ + uLong total_out; /* total number of bytes output so far */ - char *msg; /* last error message, NULL if no error */ + z_const char *msg; /* last error message, NULL if no error */ struct internal_state FAR *state; /* not visible by applications */ alloc_func zalloc; /* used to allocate the internal state */ free_func zfree; /* used to free the internal state */ voidpf opaque; /* private data object passed to zalloc and zfree */ - int data_type; /* best guess about the data type: ascii or binary */ - uLong adler; /* adler32 value of the uncompressed data */ + int data_type; /* best guess about the data type: binary or text + for deflate, or the decoding state for inflate */ + uLong adler; /* Adler-32 or CRC-32 value of the uncompressed data */ uLong reserved; /* reserved for future use */ } z_stream; typedef z_stream FAR *z_streamp; /* - The application must update next_in and avail_in when avail_in has - dropped to zero. It must update next_out and avail_out when avail_out - has dropped to zero. The application must initialize zalloc, zfree and - opaque before calling the init function. All other fields are set by the - compression library and must not be updated by the application. + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; - The opaque value provided by the application will be passed as the first - parameter for calls of zalloc and zfree. This can be useful for custom - memory management. The compression library attaches no meaning to the +/* + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the opaque value. - zalloc must return Z_NULL if there is not enough memory for the object. + zalloc must return Z_NULL if there is not enough memory for the object. If zlib is used in a multi-threaded application, zalloc and zfree must be - thread safe. - - On 16-bit systems, the functions zalloc and zfree must be able to allocate - exactly 65536 bytes, but will not be required to allocate more than this - if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, - pointers returned by zalloc for objects of exactly 65536 bytes *must* - have their offset normalized to zero. The default allocation function - provided by this library ensures this (see zutil.c). To reduce memory - requirements and avoid any allocation of 64K objects, at the expense of - compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). - - The fields total_in and total_out can be used for statistics or - progress reports. After compression, total_in holds the total size of - the uncompressed data and may be saved for use in the decompressor - (particularly if the decompressor wants to decompress everything in - a single step). + thread safe. In that case, zlib is thread-safe. When zalloc and zfree are + Z_NULL on entry to the initialization function, they are set to internal + routines that use the standard library functions malloc() and free(). + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this if + the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers + returned by zalloc for objects of exactly 65536 bytes *must* have their + offset normalized to zero. The default allocation function provided by this + library ensures this (see zutil.c). To reduce memory requirements and avoid + any allocation of 64K objects, at the expense of compression ratio, compile + the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use by the decompressor (particularly + if the decompressor wants to decompress everything in a single step). */ /* constants */ #define Z_NO_FLUSH 0 -#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_PARTIAL_FLUSH 1 #define Z_SYNC_FLUSH 2 #define Z_FULL_FLUSH 3 #define Z_FINISH 4 -/* Allowed flush values; see deflate() below for details */ +#define Z_BLOCK 5 +#define Z_TREES 6 +/* Allowed flush values; see deflate() and inflate() below for details */ #define Z_OK 0 #define Z_STREAM_END 1 @@ -138,8 +183,8 @@ typedef z_stream FAR *z_streamp; #define Z_MEM_ERROR (-4) #define Z_BUF_ERROR (-5) #define Z_VERSION_ERROR (-6) -/* Return codes for the compression/decompression functions. Negative - * values are errors, positive values are used for special but normal events. +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. */ #define Z_NO_COMPRESSION 0 @@ -150,13 +195,16 @@ typedef z_stream FAR *z_streamp; #define Z_FILTERED 1 #define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 #define Z_DEFAULT_STRATEGY 0 /* compression strategy; see deflateInit2() below for details */ #define Z_BINARY 0 -#define Z_ASCII 1 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ #define Z_UNKNOWN 2 -/* Possible values of the data_type field */ +/* Possible values of the data_type field for deflate() */ #define Z_DEFLATED 8 /* The deflate compression method (the only one supported in this version) */ @@ -166,666 +214,1492 @@ typedef z_stream FAR *z_streamp; #define zlib_version zlibVersion() /* for compatibility with versions < 1.0.2 */ + /* basic functions */ -ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +ZEXTERN const char * ZEXPORT zlibVersion(void); /* The application can compare zlibVersion and ZLIB_VERSION for consistency. - If the first character differs, the library code actually used is - not compatible with the zlib.h header file used by the application. - This check is automatically made by deflateInit and inflateInit. + If the first character differs, the library code actually used is not + compatible with the zlib.h header file used by the application. This check + is automatically made by deflateInit and inflateInit. */ -/* -ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); +/* +ZEXTERN int ZEXPORT deflateInit(z_streamp strm, int level); - Initializes the internal stream state for compression. The fields - zalloc, zfree and opaque must be initialized before by the caller. - If zalloc and zfree are set to Z_NULL, deflateInit updates them to - use default allocation functions. + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. total_in, total_out, adler, and msg are initialized. The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: - 1 gives best speed, 9 gives best compression, 0 gives no compression at - all (the input data is simply copied a block at a time). - Z_DEFAULT_COMPRESSION requests a default compromise between speed and - compression (currently equivalent to level 6). + 1 gives best speed, 9 gives best compression, 0 gives no compression at all + (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION + requests a default compromise between speed and compression (currently + equivalent to level 6). - deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if level is not a valid compression level, + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if level is not a valid compression level, or Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible - with the version assumed by the caller (ZLIB_VERSION). - msg is set to null if there is no error message. deflateInit does not - perform any compression: this will be done by deflate(). + with the version assumed by the caller (ZLIB_VERSION). msg is set to null + if there is no error message. deflateInit does not perform any compression: + this will be done by deflate(). */ -ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +ZEXTERN int ZEXPORT deflate(z_streamp strm, int flush); /* deflate compresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce some - output latency (reading input without producing any output) except when + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when forced to flush. - The detailed semantics are as follows. deflate performs one or both of the + The detailed semantics are as follows. deflate performs one or both of the following actions: - Compress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not + accordingly. If not all input can be processed (because there is not enough room in the output buffer), next_in and avail_in are updated and processing will resume at this point for the next call of deflate(). - - Provide more output starting at next_out and update next_out and avail_out - accordingly. This action is forced if the parameter flush is non zero. + - Generate more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. Forcing flush frequently degrades the compression ratio, so this parameter - should be set only when necessary (in interactive applications). - Some output may be provided even if flush is not set. - - Before the call of deflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating avail_in or avail_out accordingly; avail_out - should never be zero before the call. The application can consume the - compressed output when it wants, for example when the output buffer is full - (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK - and with zero avail_out, it must be called again after making room in the - output buffer because there might be more output pending. + should be set only when necessary. Some output may be provided even if + flush is zero. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating avail_in or avail_out accordingly; avail_out should + never be zero before the call. The application can consume the compressed + output when it wants, for example when the output buffer is full (avail_out + == 0), or after each call of deflate(). If deflate returns Z_OK and with + zero avail_out, it must be called again after making room in the output + buffer because there might be more output pending. See deflatePending(), + which can be used if desired to determine whether or not there is more output + in that case. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumulate before producing output, in order to + maximize compression. If the parameter flush is set to Z_SYNC_FLUSH, all pending output is flushed to the output buffer and the output is aligned on a byte boundary, so - that the decompressor can get all input data available so far. (In particular - avail_in is zero after the call if enough output space has been provided - before the call.) Flushing may degrade compression for some compression - algorithms and so it should be used only when necessary. + that the decompressor can get all input data available so far. (In + particular avail_in is zero after the call if enough output space has been + provided before the call.) Flushing may degrade compression for some + compression algorithms and so it should be used only when necessary. This + completes the current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed by four bytes + (00 00 ff ff). + + If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the + output buffer, but the output is not aligned to a byte boundary. All of the + input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + This completes the current deflate block and follows it with an empty fixed + codes block that is 10 bits long. This assures that enough bytes are output + in order for the decompressor to finish the block before the empty fixed + codes block. + + If flush is set to Z_BLOCK, a deflate block is completed and emitted, as + for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to + seven bits of the current block are held to be written as the next byte after + the next deflate block is completed. In this case, the decompressor may not + be provided enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait for the next + block to be emitted. This is for advanced applications that need to control + the emission of deflate blocks. If flush is set to Z_FULL_FLUSH, all output is flushed as with Z_SYNC_FLUSH, and the compression state is reset so that decompression can restart from this point if previous compressed data has been damaged or if - random access is desired. Using Z_FULL_FLUSH too often can seriously degrade - the compression. + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. If deflate returns with avail_out == 0, this function must be called again with the same value of the flush parameter and more output space (updated avail_out), until the flush is complete (deflate returns with non-zero - avail_out). + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six when the flush marker begins, in order to avoid + repeated flush markers upon calling deflate() again when avail_out == 0. If the parameter flush is set to Z_FINISH, pending input is processed, - pending output is flushed and deflate returns with Z_STREAM_END if there - was enough output space; if deflate returns with Z_OK, this function must be - called again with Z_FINISH and more output space (updated avail_out) but no - more input data, until it returns with Z_STREAM_END or an error. After - deflate has returned Z_STREAM_END, the only possible operations on the - stream are deflateReset or deflateEnd. - - Z_FINISH can be used immediately after deflateInit if all the compression - is to be done in a single step. In this case, avail_out must be at least - 0.1% larger than avail_in plus 12 bytes. If deflate does not return - Z_STREAM_END, then it must be called again as described above. - - deflate() sets strm->adler to the adler32 checksum of all input read - so far (that is, total_in bytes). - - deflate() may update data_type if it can make a good guess about - the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered - binary. This field is only for information purposes and does not affect - the compression algorithm in any manner. + pending output is flushed and deflate returns with Z_STREAM_END if there was + enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this + function must be called again with Z_FINISH and more output space (updated + avail_out) but no more input data, until it returns with Z_STREAM_END or an + error. After deflate has returned Z_STREAM_END, the only possible operations + on the stream are deflateReset or deflateEnd. + + Z_FINISH can be used in the first deflate call after deflateInit if all the + compression is to be done in a single step. In order to complete in one + call, avail_out must be at least the value returned by deflateBound (see + below). Then deflate is guaranteed to return Z_STREAM_END. If not enough + output space is provided, deflate will not return Z_STREAM_END, and it must + be called again as described above. + + deflate() sets strm->adler to the Adler-32 checksum of all input read + so far (that is, total_in bytes). If a gzip stream is being generated, then + strm->adler will be the CRC-32 checksum of the input read so far. (See + deflateInit2 below.) + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). If in doubt, the data is + considered binary. This field is only for information purposes and does not + affect the compression algorithm in any manner. deflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if all input has been consumed and all output has been produced (only when flush is set to Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example - if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible - (for example avail_in or avail_out was zero). + if next_in or next_out was Z_NULL or the state was inadvertently written over + by the application), or Z_BUF_ERROR if no progress is possible (for example + avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and + deflate() can be called again with more input and more output space to + continue compressing. */ -ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +ZEXTERN int ZEXPORT deflateEnd(z_streamp strm); /* All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. + This function discards any unprocessed input and does not flush any pending + output. deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state was inconsistent, Z_DATA_ERROR if the stream was freed - prematurely (some input or output was discarded). In the error case, - msg may be set but then points to a static string (which must not be + prematurely (some input or output was discarded). In the error case, msg + may be set but then points to a static string (which must not be deallocated). */ -/* -ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); +/* +ZEXTERN int ZEXPORT inflateInit(z_streamp strm); - Initializes the internal stream state for decompression. The fields + Initializes the internal stream state for decompression. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by - the caller. If next_in is not Z_NULL and avail_in is large enough (the exact - value depends on the compression method), inflateInit determines the - compression method from the zlib header and allocates all data structures - accordingly; otherwise the allocation will be deferred to the first call of - inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to - use default allocation functions. + the caller. In the current version of inflate, the provided input is not + read or consumed. The allocation of a sliding window will be deferred to + the first call of inflate (if the decompression does not complete on the + first call). If zalloc and zfree are set to Z_NULL, inflateInit updates + them to use default allocation functions. total_in, total_out, adler, and + msg are initialized. inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the - version assumed by the caller. msg is set to null if there is no error - message. inflateInit does not perform any decompression apart from reading - the zlib header if present: this will be done by inflate(). (So next_in and - avail_in may be modified, but next_out and avail_out are unchanged.) + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit does not perform any decompression. + Actual decompression will be done by inflate(). So next_in, and avail_in, + next_out, and avail_out are unused and unchanged. The current + implementation of inflateInit() does not process any header information -- + that is deferred until inflate() is called. */ -ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +ZEXTERN int ZEXPORT inflate(z_streamp strm, int flush); /* inflate decompresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may some - introduce some output latency (reading input without producing any output) - except when forced to flush. + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. - The detailed semantics are as follows. inflate performs one or both of the + The detailed semantics are as follows. inflate performs one or both of the following actions: - Decompress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in is updated and processing - will resume at this point for the next call of inflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. inflate() provides as much output as possible, until there - is no more input data or no more space in the output buffer (see below - about the flush parameter). - - Before the call of inflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating the next_* and avail_* values accordingly. - The application can consume the uncompressed output when it wants, for - example when the output buffer is full (avail_out == 0), or after each - call of inflate(). If inflate returns Z_OK and with zero avail_out, it - must be called again after making room in the output buffer because there - might be more output pending. - - If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much - output as possible to the output buffer. The flushing behavior of inflate is - not specified for values of the flush parameter other than Z_SYNC_FLUSH - and Z_FINISH, but the current implementation actually flushes as much output - as possible anyway. + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), then next_in and avail_in are updated + accordingly, and processing will resume at this point for the next call of + inflate(). + + - Generate more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there is + no more input data or no more space in the output buffer (see below about + the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating the next_* and avail_* values accordingly. If the + caller of inflate() does not provide both available input and available + output space, it is possible that there will be no progress made. The + application can consume the uncompressed output when it wants, for example + when the output buffer is full (avail_out == 0), or after each call of + inflate(). If inflate returns Z_OK and with zero avail_out, it must be + called again after making room in the output buffer because there might be + more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, + Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() + stop if and when it gets to the next deflate block boundary. When decoding + the zlib or gzip format, this will cause inflate() to return immediately + after the header and before the first block. When doing a raw inflate, + inflate() will go ahead and process the first block, and will return when it + gets to the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + To assist in this, on return inflate() always sets strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 if + inflate() is currently decoding the last block in the deflate stream, plus + 128 if inflate() returned immediately after decoding an end-of-block code or + decoding the complete header up to just before the first byte of the deflate + stream. The end-of-block will not be indicated until all of the uncompressed + data from that block has been written to strm->next_out. The number of + unused bits may in general be greater than seven, except when bit 7 of + data_type is set, in which case the number of unused bits will be less than + eight. data_type is set as noted here every time inflate() returns for all + flush options, and so can be used to determine the amount of currently + consumed input in bits. + + The Z_TREES option behaves as Z_BLOCK does, but it also returns when the + end of each deflate block header is reached, before any actual data in that + block is decoded. This allows the caller to determine the length of the + deflate block header for later use in random access within a deflate block. + 256 is added to the value of strm->data_type when inflate() returns + immediately after reaching the end of the deflate block header. inflate() should normally be called until it returns Z_STREAM_END or an - error. However if all decompression is to be performed in a single step - (a single call of inflate), the parameter flush should be set to - Z_FINISH. In this case all pending input is processed and all pending - output is flushed; avail_out must be large enough to hold all the - uncompressed data. (The size of the uncompressed data may have been saved - by the compressor for this purpose.) The next operation on this stream must - be inflateEnd to deallocate the decompression state. The use of Z_FINISH - is never required, but can be used to inform inflate that a faster routine - may be used for the single inflate() call. - - If a preset dictionary is needed at this point (see inflateSetDictionary - below), inflate sets strm-adler to the adler32 checksum of the - dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise - it sets strm->adler to the adler32 checksum of all output produced - so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or - an error code as described below. At the end of the stream, inflate() - checks that its computed adler32 checksum is equal to that saved by the - compressor and returns Z_STREAM_END only if the checksum is correct. + error. However if all decompression is to be performed in a single step (a + single call of inflate), the parameter flush should be set to Z_FINISH. In + this case all pending input is processed and all pending output is flushed; + avail_out must be large enough to hold all of the uncompressed data for the + operation to complete. (The size of the uncompressed data may have been + saved by the compressor for this purpose.) The use of Z_FINISH is not + required to perform an inflation in one step. However it may be used to + inform inflate that a faster approach can be used for the single inflate() + call. Z_FINISH also informs inflate to not maintain a sliding window if the + stream completes, which reduces inflate's memory footprint. If the stream + does not complete, either because not all of the stream is provided or not + enough output space is provided, then a sliding window will be allocated and + inflate() can be called again to continue the operation as if Z_NO_FLUSH had + been used. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the effects of the flush parameter in this implementation are + on the return value of inflate() as noted below, when inflate() returns early + when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of + memory for a sliding window when Z_FINISH is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the Adler-32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the Adler-32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed Adler-32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() can decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically, if requested when + initializing with inflateInit2(). Any information contained in the gzip + header is not retained unless inflateGetHeader() is used. When processing + gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output + produced so far. The CRC-32 is checked against the gzip trailer, as is the + uncompressed length, modulo 2^32. inflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if the end of the compressed data has been reached and all uncompressed output has been produced, Z_NEED_DICT if a preset dictionary is needed at this point, Z_DATA_ERROR if the input data was - corrupted (input stream not conforming to the zlib format or incorrect - adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent - (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if no progress is possible or if there was not - enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR - case, the application may then call inflateSync to look for a good - compression block. + corrupted (input stream not conforming to the zlib format or incorrect check + value, in which case strm->msg points to a string with a more specific + error), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was Z_NULL, or the state was inadvertently written over + by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR + if no progress was possible or if there was not enough room in the output + buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may + then call inflateSync() to look for a good compression block if a partial + recovery of the data is to be attempted. */ -ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +ZEXTERN int ZEXPORT inflateEnd(z_streamp strm); /* All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. + This function discards any unprocessed input and does not flush any pending + output. - inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state - was inconsistent. In the error case, msg may be set but then points to a - static string (which must not be deallocated). + inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state + was inconsistent. */ + /* Advanced functions */ /* The following functions are needed only in some special applications. */ -/* -ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, - int level, - int method, - int windowBits, - int memLevel, - int strategy)); +/* +ZEXTERN int ZEXPORT deflateInit2(z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy); - This is another version of deflateInit with more compression options. The - fields next_in, zalloc, zfree and opaque must be initialized before by - the caller. + This is another version of deflateInit with more compression options. The + fields zalloc, zfree and opaque must be initialized before by the caller. - The method parameter is the compression method. It must be Z_DEFLATED in + The method parameter is the compression method. It must be Z_DEFLATED in this version of the library. The windowBits parameter is the base two logarithm of the window size (the size of the history buffer). It should be in the range 8..15 for this - version of the library. Larger values of this parameter result in better - compression at the expense of memory usage. The default value is 15 if + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if deflateInit is used instead. + For the current implementation of deflate(), a windowBits value of 8 (a + window size of 256 bytes) is not supported. As a result, a request for 8 + will result in 9 (a 512-byte window). In that case, providing 8 to + inflateInit2() will result in an error when the zlib header with 9 is + checked against the initialization of inflate(). The remedy is to not use 8 + with deflateInit2() with this initialization, or at least in that case use 9 + with inflateInit2(). + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute a check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), no + header crc, and the operating system will be set to the appropriate value, + if the operating system was determined at compile time. If a gzip stream is + being written, strm->adler is a CRC-32 instead of an Adler-32. + + For raw deflate or gzip encoding, a request for a 256-byte window is + rejected as invalid, since only the zlib header provides a means of + transmitting the window size to the decompressor. + The memLevel parameter specifies how much memory should be allocated - for the internal compression state. memLevel=1 uses minimum memory but - is slow and reduces compression ratio; memLevel=9 uses maximum memory - for optimal speed. The default value is 8. See zconf.h for total memory - usage as a function of windowBits and memLevel. + for the internal compression state. memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. The default value is 8. See zconf.h for total memory usage + as a function of windowBits and memLevel. - The strategy parameter is used to tune the compression algorithm. Use the + The strategy parameter is used to tune the compression algorithm. Use the value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a - filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no - string match). Filtered data consists mostly of small values with a - somewhat random distribution. In this case, the compression algorithm is - tuned to compress them better. The effect of Z_FILTERED is to force more - Huffman coding and less string matching; it is somewhat intermediate - between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects - the compression ratio but not the correctness of the compressed output even - if it is not set appropriately. - - deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid - method). msg is set to null if there is no error message. deflateInit2 does - not perform any compression: this will be done by deflate(). + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as + fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The + strategy parameter only affects the compression ratio but not the + correctness of the compressed output even if it is not set appropriately. + Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler + decoder for special applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid + method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is + incompatible with the version assumed by the caller (ZLIB_VERSION). msg is + set to null if there is no error message. deflateInit2 does not perform any + compression: this will be done by deflate(). */ - -ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); + +ZEXTERN int ZEXPORT deflateSetDictionary(z_streamp strm, + const Bytef *dictionary, + uInt dictLength); /* Initializes the compression dictionary from the given byte sequence - without producing any compressed output. This function must be called - immediately after deflateInit, deflateInit2 or deflateReset, before any - call of deflate. The compressor and decompressor must use exactly the same - dictionary (see inflateSetDictionary). + without producing any compressed output. When using the zlib format, this + function must be called immediately after deflateInit, deflateInit2 or + deflateReset, and before any call of deflate. When doing raw deflate, this + function must be called either before any call of deflate, or immediately + after the completion of a deflate block, i.e. after all input has been + consumed and all output has been delivered when using any of the flush + options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The + compressor and decompressor must use exactly the same dictionary (see + inflateSetDictionary). The dictionary should consist of strings (byte sequences) that are likely to be encountered later in the data to be compressed, with the most commonly - used strings preferably put towards the end of the dictionary. Using a + used strings preferably put towards the end of the dictionary. Using a dictionary is most useful when the data to be compressed is short and can be predicted with good accuracy; the data can then be compressed better than with the default empty dictionary. Depending on the size of the compression data structures selected by deflateInit or deflateInit2, a part of the dictionary may in effect be - discarded, for example if the dictionary is larger than the window size in - deflate or deflate2. Thus the strings most likely to be useful should be - put at the end of the dictionary, not at the front. + discarded, for example if the dictionary is larger than the window size + provided in deflateInit or deflateInit2. Thus the strings most likely to be + useful should be put at the end of the dictionary, not at the front. In + addition, the current implementation of deflate will use at most the window + size minus 262 bytes of the provided dictionary. - Upon return of this function, strm->adler is set to the Adler32 value + Upon return of this function, strm->adler is set to the Adler-32 value of the dictionary; the decompressor may later use this value to determine - which dictionary has been used by the compressor. (The Adler32 value + which dictionary has been used by the compressor. (The Adler-32 value applies to the whole dictionary even if only a subset of the dictionary is - actually used by the compressor.) + actually used by the compressor.) If a raw deflate was requested, then the + Adler-32 value is not computed and strm->adler is not set. deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent (for example if deflate has already been called for this stream - or if the compression method is bsort). deflateSetDictionary does not - perform any compression: this will be done by deflate(). + or if not at a block boundary for raw deflate). deflateSetDictionary does + not perform any compression: this will be done by deflate(). */ -ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, - z_streamp source)); +ZEXTERN int ZEXPORT deflateGetDictionary(z_streamp strm, + Bytef *dictionary, + uInt *dictLength); +/* + Returns the sliding dictionary being maintained by deflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If deflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similarly, if dictLength is Z_NULL, then it is not set. + + deflateGetDictionary() may return a length less than the window size, even + when more than the window size in input has been provided. It may return up + to 258 bytes less in that case, due to how zlib's implementation of deflate + manages the sliding window and lookahead for matches, where matches can be + up to 258 bytes long. If the application needs the last window-size bytes of + input, then that would need to be saved by the application outside of zlib. + + deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateCopy(z_streamp dest, + z_streamp source); /* Sets the destination stream as a complete copy of the source stream. This function can be useful when several compression strategies will be tried, for example when there are several ways of pre-processing the input - data with a filter. The streams that will be discarded should then be freed + data with a filter. The streams that will be discarded should then be freed by calling deflateEnd. Note that deflateCopy duplicates the internal - compression state which can be quite large, so this strategy is slow and - can consume lots of memory. + compression state which can be quite large, so this strategy is slow and can + consume lots of memory. deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and + (such as zalloc being Z_NULL). msg is left unchanged in both source and destination. */ -ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +ZEXTERN int ZEXPORT deflateReset(z_streamp strm); /* - This function is equivalent to deflateEnd followed by deflateInit, - but does not free and reallocate all the internal compression state. - The stream will keep the same compression level and any other attributes - that may have been set by deflateInit2. + This function is equivalent to deflateEnd followed by deflateInit, but + does not free and reallocate the internal compression state. The stream + will leave the compression level and any other attributes that may have been + set unchanged. total_in, total_out, adler, and msg are initialized. - deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). */ -ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, - int level, - int strategy)); +ZEXTERN int ZEXPORT deflateParams(z_streamp strm, + int level, + int strategy); /* Dynamically update the compression level and compression strategy. The - interpretation of level and strategy is as in deflateInit2. This can be + interpretation of level and strategy is as in deflateInit2(). This can be used to switch between compression and straight copy of the input data, or - to switch to a different kind of input data requiring a different - strategy. If the compression level is changed, the input available so far - is compressed with the old level (and may be flushed); the new level will - take effect only at the next call of deflate(). + to switch to a different kind of input data requiring a different strategy. + If the compression approach (which is a function of the level) or the + strategy is changed, and if there have been any deflate() calls since the + state was initialized or reset, then the input available so far is + compressed with the old level and strategy using deflate(strm, Z_BLOCK). + There are three approaches for the compression levels 0, 1..3, and 4..9 + respectively. The new level and strategy will take effect at the next call + of deflate(). + + If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does + not have enough output space to complete, then the parameter change will not + take effect. In this case, deflateParams() can be called again with the + same parameters and more output space to try again. + + In order to assure a change in the parameters on the first try, the + deflate stream should be flushed using deflate() with Z_BLOCK or other flush + request until strm.avail_out is not zero, before calling deflateParams(). + Then no more input data should be provided before the deflateParams() call. + If this is done, the old level and strategy will be applied to the data + compressed before deflateParams(), and the new level and strategy will be + applied to the data compressed after deflateParams(). + + deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream + state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if + there was not enough output space to complete the compression of the + available input data before a change in the strategy or approach. Note that + in the case of a Z_BUF_ERROR, the parameters are not changed. A return + value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be + retried with more output space. +*/ - Before the call of deflateParams, the stream state must be set as for - a call of deflate(), since the currently available input may have to - be compressed and flushed. In particular, strm->avail_out must be non-zero. +ZEXTERN int ZEXPORT deflateTune(z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ - deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source - stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR - if strm->avail_out was zero. +ZEXTERN uLong ZEXPORT deflateBound(z_streamp strm, + uLong sourceLen); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() or + deflateInit2(), and after deflateSetHeader(), if used. This would be used + to allocate an output buffer for deflation in a single pass, and so would be + called before deflate(). If that first deflate() call is provided the + sourceLen input bytes, an output buffer allocated to the size returned by + deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed + to return Z_STREAM_END. Note that it is possible for the compressed size to + be larger than the value returned by deflateBound() if flush options other + than Z_FINISH or Z_NO_FLUSH are used. */ -/* -ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, - int windowBits)); +ZEXTERN int ZEXPORT deflatePending(z_streamp strm, + unsigned *pending, + int *bits); +/* + deflatePending() returns the number of bytes and bits of output that have + been generated, but not yet provided in the available output. The bytes not + provided would be due to the available output space having being consumed. + The number of bits of output not provided are between 0 and 7, where they + await more bits to join them in order to fill out a full byte. If pending + or bits are Z_NULL, then those values are not set. + + deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. + */ - This is another version of inflateInit with an extra parameter. The +ZEXTERN int ZEXPORT deflatePrime(z_streamp strm, + int bits, + int value); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the bits + leftover from a previous deflate stream when appending to it. As such, this + function can only be used for raw deflate, and must be used before the first + deflate() call after a deflateInit2() or deflateReset(). bits must be less + than or equal to 16, and that many of the least significant bits of value + will be inserted in the output. + + deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough + room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader(z_streamp strm, + gz_headerp head); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to the current operating system, with no + extra, name, or comment fields. The gzip header is returned to the default + state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2(z_streamp strm, + int windowBits); + + This is another version of inflateInit with an extra parameter. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. The windowBits parameter is the base two logarithm of the maximum window size (the size of the history buffer). It should be in the range 8..15 for - this version of the library. The default value is 15 if inflateInit is used - instead. If a compressed stream with a larger window size is given as - input, inflate() will return with the error code Z_DATA_ERROR instead of - trying to allocate a larger window. - - inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative - memLevel). msg is set to null if there is no error message. inflateInit2 - does not perform any decompression apart from reading the zlib header if - present: this will be done by inflate(). (So next_in and avail_in may be - modified, but next_out and avail_out are unchanged.) + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be zero to request that inflate use the window size in + the zlib header of the compressed stream. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an Adler-32 or a CRC-32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a + CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see + below), inflate() will *not* automatically decode concatenated gzip members. + inflate() will return Z_STREAM_END at the end of the gzip member. The state + would need to be reset to continue decoding a subsequent gzip member. This + *must* be done if there is more data after a gzip member, in order for the + decompression to be compliant with the gzip standard (RFC 1952). + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit2 does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit2() does not process any header information -- that is + deferred until inflate() is called. */ -ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); +ZEXTERN int ZEXPORT inflateSetDictionary(z_streamp strm, + const Bytef *dictionary, + uInt dictLength); /* Initializes the decompression dictionary from the given uncompressed byte - sequence. This function must be called immediately after a call of inflate - if this call returned Z_NEED_DICT. The dictionary chosen by the compressor - can be determined from the Adler32 value returned by this call of - inflate. The compressor and decompressor must use exactly the same - dictionary (see deflateSetDictionary). + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler-32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called at any + time to set the dictionary. If the provided dictionary is smaller than the + window and there is already data in the window, then the provided dictionary + will amend what's there. The application must insure that the dictionary + that was used for compression is provided. inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the - expected one (incorrect Adler32 value). inflateSetDictionary does not + expected one (incorrect Adler-32 value). inflateSetDictionary does not perform any decompression: this will be done by subsequent calls of inflate(). */ -ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); -/* - Skips invalid compressed data until a full flush point (see above the - description of deflate with Z_FULL_FLUSH) can be found, or until all - available input is skipped. No output is provided. +ZEXTERN int ZEXPORT inflateGetDictionary(z_streamp strm, + Bytef *dictionary, + uInt *dictLength); +/* + Returns the sliding dictionary being maintained by inflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If inflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similarly, if dictLength is Z_NULL, then it is not set. + + inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateSync(z_streamp strm); +/* + Skips invalid compressed data until a possible full flush point (see above + for the description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync searches for a 00 00 FF FF pattern in the compressed data. + All full flush points have this pattern, but not all occurrences of this + pattern are full flush points. + + inflateSync returns Z_OK if a possible full flush point has been found, + Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point + has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. + In the success case, the application may save the current value of total_in + which indicates where valid compressed data was found. In the error case, + the application may repeatedly call inflateSync, providing more input each + time, until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy(z_streamp dest, + z_streamp source); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. - inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR - if no more input was provided, Z_DATA_ERROR if no flush point has been found, - or Z_STREAM_ERROR if the stream structure was inconsistent. In the success - case, the application may save the current current value of total_in which - indicates where valid compressed data was found. In the error case, the - application may repeatedly call inflateSync, providing more input each time, - until success or end of the input data. + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. */ -ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +ZEXTERN int ZEXPORT inflateReset(z_streamp strm); /* This function is equivalent to inflateEnd followed by inflateInit, - but does not free and reallocate all the internal decompression state. - The stream will keep attributes that may have been set by inflateInit2. + but does not free and reallocate the internal decompression state. The + stream will keep attributes that may have been set by inflateInit2. + total_in, total_out, adler, and msg are initialized. - inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). */ +ZEXTERN int ZEXPORT inflateReset2(z_streamp strm, + int windowBits); +/* + This function is the same as inflateReset, but it also permits changing + the wrap and window size requests. The windowBits parameter is interpreted + the same as it is for inflateInit2. If the window size is changed, then the + memory allocated for the window is freed, and the window will be reallocated + by inflate() if needed. + + inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL), or if + the windowBits parameter is invalid. +*/ + +ZEXTERN int ZEXPORT inflatePrime(z_streamp strm, + int bits, + int value); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + If bits is negative, then the input stream bit buffer is emptied. Then + inflatePrime() can be called again to put bits in the buffer. This is used + to clear out bits leftover after feeding inflate a block description prior + to feeding inflate codes. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN long ZEXPORT inflateMark(z_streamp strm); +/* + This function returns two values, one in the lower 16 bits of the return + value, and the other in the remaining upper bits, obtained by shifting the + return value down 16 bits. If the upper value is -1 and the lower value is + zero, then inflate() is currently decoding information outside of a block. + If the upper value is -1 and the lower value is non-zero, then inflate is in + the middle of a stored block, with the lower value equaling the number of + bytes from the input remaining to copy. If the upper value is not -1, then + it is the number of bits back from the current bit position in the input of + the code (literal or length/distance pair) currently being processed. In + that case the lower value is the number of bytes already emitted for that + code. + + A code is being processed if inflate is waiting for more input to complete + decoding of the code, or if it has completed decoding but is waiting for + more output space to write the literal or match data. + + inflateMark() is used to mark locations in the input data for random + access, which may be at bit positions, and to note those cases where the + output of a code may span boundaries of random access blocks. The current + location in the input stream can be determined from avail_in and data_type + as noted in the description for the Z_BLOCK flush parameter for inflate. + + inflateMark returns the value noted above, or -65536 if the provided + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader(z_streamp strm, + gz_headerp head); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be + used to force inflate() to return immediately after header processing is + complete and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When any + of extra, name, or comment are not Z_NULL and the respective field is not + present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit(z_streamp strm, int windowBits, + unsigned char FAR *window); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the parameters are invalid, Z_MEM_ERROR if the internal state could not be + allocated, or Z_VERSION_ERROR if the version of the library does not match + the version of the header file. +*/ + +typedef unsigned (*in_func)(void FAR *, + z_const unsigned char FAR * FAR *); +typedef int (*out_func)(void FAR *, unsigned char FAR *, unsigned); + +ZEXTERN int ZEXPORT inflateBack(z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is potentially more efficient than + inflate() for file i/o applications, in that it avoids copying between the + output and the sliding window by simply making the window itself the output + buffer. inflate() can be faster on modern CPUs when used with large + buffers. inflateBack() trusts the application to not change the output + buffer passed by the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free the + allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects only + the raw deflate stream to decompress. This is different from the default + behavior of inflate(), which expects a zlib header and trailer around the + deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero -- buf is ignored in that + case -- and inflateBack() will return a buffer error. inflateBack() will + call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. + out() should return zero on success, or non-zero on failure. If out() + returns non-zero, inflateBack() will return with an error. Neither in() nor + out() are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format error + in the deflate stream (in which case strm->msg is set to indicate the nature + of the error), or Z_STREAM_ERROR if the stream was not properly initialized. + In the case of Z_BUF_ERROR, an input or output error can be distinguished + using strm->next_in which will be Z_NULL only if in() returned an error. If + strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning + non-zero. (in() will always be called before out(), so strm->next_in is + assured to be defined if out() returns non-zero.) Note that inflateBack() + cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd(z_streamp strm); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags(void); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: ZLIB_DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + +#ifndef Z_SOLO /* utility functions */ /* - The following utility functions are implemented on top of the - basic stream-oriented functions. To simplify the interface, some - default options are assumed (compression level and memory usage, - standard memory allocation functions). The source code of these - utility functions can easily be modified if you need special options. + The following utility functions are implemented on top of the basic + stream-oriented functions. To simplify the interface, some default options + are assumed (compression level and memory usage, standard memory allocation + functions). The source code of these utility functions can be modified if + you need special options. */ -ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); +ZEXTERN int ZEXPORT compress(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen); /* Compresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be at least 0.1% larger than - sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the - compressed buffer. - This function can be used to compress a whole file at once if the - input file is mmap'ed. + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed data. compress() is equivalent to compress2() with a level + parameter of Z_DEFAULT_COMPRESSION. + compress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer. */ -ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen, - int level)); +ZEXTERN int ZEXPORT compress2(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level); /* - Compresses the source buffer into the destination buffer. The level + Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least 0.1% larger than sourceLen plus - 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed data. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ -ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); +ZEXTERN uLong ZEXPORT compressBound(uLong sourceLen); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before a + compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen); /* Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be large enough to hold the - entire uncompressed data. (The size of the uncompressed data must have - been saved previously by the compressor and transmitted to the decompressor - by some mechanism outside the scope of this compression library.) - Upon exit, destLen is the actual size of the compressed buffer. - This function can be used to decompress a whole file at once if the - input file is mmap'ed. + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, destLen + is the actual size of the uncompressed data. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted. + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In + the case where there is not enough room, uncompress() will fill the output + buffer with the uncompressed data up to that point. */ +ZEXTERN int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong *sourceLen); +/* + Same as uncompress, except that sourceLen is a pointer, where the + length of the source is *sourceLen. On return, *sourceLen is the number of + source bytes consumed. +*/ + + /* gzip file access functions */ + +/* + This library supports reading and writing files in gzip (.gz) format with + an interface similar to that of stdio, using the functions that start with + "gz". The gzip format is different from the zlib format. gzip is a gzip + wrapper, documented in RFC 1952, wrapped around a deflate stream. +*/ -typedef voidp gzFile; +typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ -ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); /* - Opens a gzip (.gz) file for reading or writing. The mode parameter - is as in fopen ("rb" or "wb") but can also include a compression level - ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for - Huffman only compression as in "wb1h". (See the description - of deflateInit2 for more information about the strategy parameter.) +ZEXTERN gzFile ZEXPORT gzopen(const char *path, const char *mode); + + Open the gzip (.gz) file at path for reading and decompressing, or + compressing and writing. The mode parameter is as in fopen ("rb" or "wb") + but can also include a compression level ("wb9") or a strategy: 'f' for + filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h", + 'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression + as in "wb9F". (See the description of deflateInit2 for more information + about the strategy parameter.) 'T' will request transparent writing or + appending with no compression and not using the gzip format. + + "a" can be used instead of "w" to request that the gzip stream that will + be written be appended to the file. "+" will result in an error, since + reading and writing to the same gzip file is not supported. The addition of + "x" when writing will create the file exclusively, which fails if the file + already exists. On systems that support it, the addition of "e" when + reading or writing will set the flag to close the file on an execve() call. + + These functions, as well as gzip, will read and decode a sequence of gzip + streams in a file. The append function of gzopen() can be used to create + such a file. (Also see gzflush() for another way to do this.) When + appending, gzopen does not test whether the file begins with a gzip stream, + nor does it look for the end of the gzip streams to begin appending. gzopen + will simply append a gzip stream to the existing file. gzopen can be used to read a file which is not in gzip format; in this - case gzread will directly read from the file without decompression. + case gzread will directly read from the file without decompression. When + reading, this will be detected automatically by looking for the magic two- + byte gzip header. + + gzopen returns NULL if the file could not be opened, if there was + insufficient memory to allocate the gzFile state, or if an invalid mode was + specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). + errno can be checked to determine if the reason gzopen failed was that the + file could not be opened. +*/ + +ZEXTERN gzFile ZEXPORT gzdopen(int fd, const char *mode); +/* + Associate a gzFile with the file descriptor fd. File descriptors are + obtained from calls like open, dup, creat, pipe or fileno (if the file has + been previously opened with fopen). The mode parameter is as in gzopen. + + The next call of gzclose on the returned gzFile will also close the file + descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor + fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, + mode);. The duplicated descriptor should be saved to avoid a leak, since + gzdopen does not close fd if it fails. If you are using fileno() to get the + file descriptor from a FILE *, then you will have to use dup() to avoid + double-close()ing the file descriptor. Both gzclose() and fclose() will + close the associated file descriptor, so they need to have different file + descriptors. + + gzdopen returns NULL if there was insufficient memory to allocate the + gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not + provided, or '+' was provided), or if fd is -1. The file descriptor is not + used until the next gz* read, write, seek, or close operation, so gzdopen + will not detect if fd is invalid (unless fd is -1). +*/ - gzopen returns NULL if the file could not be opened or if there was - insufficient memory to allocate the (de)compression state; errno - can be checked to distinguish the two cases (if errno is zero, the - zlib error is Z_MEM_ERROR). */ +ZEXTERN int ZEXPORT gzbuffer(gzFile file, unsigned size); +/* + Set the internal buffer size used by this library's functions for file to + size. The default buffer size is 8192 bytes. This function must be called + after gzopen() or gzdopen(), and before any other calls that read or write + the file. The buffer memory allocation is always deferred to the first read + or write. Three times that size in buffer space is allocated. A larger + buffer size of, for example, 64K or 128K bytes will noticeably increase the + speed of decompression (reading). + + The new buffer size also affects the maximum length for gzprintf(). + + gzbuffer() returns 0 on success, or -1 on failure, such as being called + too late. +*/ + +ZEXTERN int ZEXPORT gzsetparams(gzFile file, int level, int strategy); +/* + Dynamically update the compression level and strategy for file. See the + description of deflateInit2 for the meaning of these parameters. Previously + provided data is flushed before applying the parameter changes. + + gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not + opened for writing, Z_ERRNO if there is an error writing the flushed data, + or Z_MEM_ERROR if there is a memory allocation error. +*/ -ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +ZEXTERN int ZEXPORT gzread(gzFile file, voidp buf, unsigned len); /* - gzdopen() associates a gzFile with the file descriptor fd. File - descriptors are obtained from calls like open, dup, creat, pipe or - fileno (in the file has been previously opened with fopen). - The mode parameter is as in gzopen. - The next call of gzclose on the returned gzFile will also close the - file descriptor fd, just like fclose(fdopen(fd), mode) closes the file - descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). - gzdopen returns NULL if there was insufficient memory to allocate - the (de)compression state. + Read and decompress up to len uncompressed bytes from file into buf. If + the input file is not in gzip format, gzread copies the given number of + bytes into the buffer directly from the file. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream. Any number of gzip streams may be + concatenated in the input file, and will all be decompressed by gzread(). + If something other than a gzip stream is encountered after a gzip stream, + that remaining trailing garbage is ignored (and no error is returned). + + gzread can be used to read a gzip file that is being concurrently written. + Upon reaching the end of the input, gzread will return with the available + data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then + gzclearerr can be used to clear the end of file indicator in order to permit + gzread to be tried again. Z_OK indicates that a gzip stream was completed + on the last gzread. Z_BUF_ERROR indicates that the input file ended in the + middle of a gzip stream. Note that gzread does not return -1 in the event + of an incomplete gzip stream. This error is deferred until gzclose(), which + will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip + stream. Alternatively, gzerror can be used before gzclose to detect this + case. + + gzread returns the number of uncompressed bytes actually read, less than + len for end of file, or -1 for error. If len is too large to fit in an int, + then nothing is read, -1 is returned, and the error state is set to + Z_STREAM_ERROR. */ -ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +ZEXTERN z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems, + gzFile file); /* - Dynamically update the compression level or strategy. See the description - of deflateInit2 for the meaning of these parameters. - gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not - opened for writing. + Read and decompress up to nitems items of size size from file into buf, + otherwise operating as gzread() does. This duplicates the interface of + stdio's fread(), with size_t request and return types. If the library + defines size_t, then z_size_t is identical to size_t. If not, then z_size_t + is an unsigned integer type that can contain a pointer. + + gzfread() returns the number of full items read of size size, or zero if + the end of the file was reached and a full item could not be read, or if + there was an error. gzerror() must be consulted if zero is returned in + order to determine if there was an error. If the multiplication of size and + nitems overflows, i.e. the product does not fit in a z_size_t, then nothing + is read, zero is returned, and the error state is set to Z_STREAM_ERROR. + + In the event that the end of file is reached and only a partial item is + available at the end, i.e. the remaining uncompressed data length is not a + multiple of size, then the final partial item is nevertheless read into buf + and the end-of-file flag is set. The length of the partial item read is not + provided, but could be inferred from the result of gztell(). This behavior + is the same as the behavior of fread() implementations in common libraries, + but it prevents the direct use of gzfread() to read a concurrently written + file, resetting and retrying on end-of-file, when size is not 1. */ -ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +ZEXTERN int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len); /* - Reads the given number of uncompressed bytes from the compressed file. - If the input file was not in gzip format, gzread copies the given number - of bytes into the buffer. - gzread returns the number of uncompressed bytes actually read (0 for - end of file, -1 for error). */ + Compress and write the len uncompressed bytes at buf to file. gzwrite + returns the number of uncompressed bytes written or 0 in case of error. +*/ -ZEXTERN int ZEXPORT gzwrite OF((gzFile file, - const voidp buf, unsigned len)); +ZEXTERN z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, + z_size_t nitems, gzFile file); /* - Writes the given number of uncompressed bytes into the compressed file. - gzwrite returns the number of uncompressed bytes actually written - (0 in case of error). + Compress and write nitems items of size size from buf to file, duplicating + the interface of stdio's fwrite(), with size_t request and return types. If + the library defines size_t, then z_size_t is identical to size_t. If not, + then z_size_t is an unsigned integer type that can contain a pointer. + + gzfwrite() returns the number of full items written of size size, or zero + if there was an error. If the multiplication of size and nitems overflows, + i.e. the product does not fit in a z_size_t, then nothing is written, zero + is returned, and the error state is set to Z_STREAM_ERROR. */ -ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +ZEXTERN int ZEXPORTVA gzprintf(gzFile file, const char *format, ...); /* - Converts, formats, and writes the args to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written (0 in case of error). + Convert, format, compress, and write the arguments (...) to file under + control of the string format, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written, or a negative zlib error code in case + of error. The number of uncompressed bytes written is limited to 8191, or + one less than the buffer size given to gzbuffer(). The caller should assure + that this limit is not exceeded. If it is exceeded, then gzprintf() will + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf(), + because the secure snprintf() or vsnprintf() functions were not available. + This can be determined using zlibCompileFlags(). */ -ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +ZEXTERN int ZEXPORT gzputs(gzFile file, const char *s); /* - Writes the given null-terminated string to the compressed file, excluding + Compress and write the given null-terminated string s to file, excluding the terminating null character. - gzputs returns the number of characters written, or -1 in case of error. + + gzputs returns the number of characters written, or -1 in case of error. */ -ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +ZEXTERN char * ZEXPORT gzgets(gzFile file, char *buf, int len); /* - Reads bytes from the compressed file until len-1 characters are read, or - a newline character is read and transferred to buf, or an end-of-file - condition is encountered. The string is then terminated with a null - character. - gzgets returns buf, or Z_NULL in case of error. + Read and decompress bytes from file into buf, until len-1 characters are + read, or until a newline character is read and transferred to buf, or an + end-of-file condition is encountered. If any characters are read or if len + is one, the string is terminated with a null character. If no characters + are read due to an end-of-file or len is less than one, then the buffer is + left untouched. + + gzgets returns buf which is a null-terminated string, or it returns NULL + for end-of-file or in case of error. If there was an error, the contents at + buf are indeterminate. */ -ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +ZEXTERN int ZEXPORT gzputc(gzFile file, int c); /* - Writes c, converted to an unsigned char, into the compressed file. - gzputc returns the value that was written, or -1 in case of error. + Compress and write c, converted to an unsigned char, into file. gzputc + returns the value that was written, or -1 in case of error. */ -ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +ZEXTERN int ZEXPORT gzgetc(gzFile file); /* - Reads one byte from the compressed file. gzgetc returns this byte - or -1 in case of end of file or error. + Read and decompress one byte from file. gzgetc returns this byte or -1 + in case of end of file or error. This is implemented as a macro for speed. + As such, it does not do all of the checking the other functions do. I.e. + it does not check to see if file is NULL, nor whether the structure file + points to has been clobbered or not. */ -ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +ZEXTERN int ZEXPORT gzungetc(int c, gzFile file); /* - Flushes all pending output into the compressed file. The parameter - flush is as in the deflate() function. The return value is the zlib - error number (see function gzerror below). gzflush returns Z_OK if - the flush parameter is Z_FINISH and all output could be flushed. - gzflush should be called only when strictly necessary because it can - degrade compression. + Push c back onto the stream for file to be read as the first character on + the next read. At least one character of push-back is always allowed. + gzungetc() returns the character pushed, or -1 on failure. gzungetc() will + fail if c is -1, and may fail if a character has been pushed but not read + yet. If gzungetc is used immediately after gzopen or gzdopen, at least the + output buffer size of pushed characters is allowed. (See gzbuffer above.) + The pushed character will be discarded if the stream is repositioned with + gzseek() or gzrewind(). */ -ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, - z_off_t offset, int whence)); -/* - Sets the starting position for the next gzread or gzwrite on the - given compressed file. The offset represents a number of bytes in the - uncompressed data stream. The whence parameter is defined as in lseek(2); +ZEXTERN int ZEXPORT gzflush(gzFile file, int flush); +/* + Flush all pending output to file. The parameter flush is as in the + deflate() function. The return value is the zlib error number (see function + gzerror below). gzflush is only permitted when writing. + + If the flush parameter is Z_FINISH, the remaining data is written and the + gzip stream is completed in the output. If gzwrite() is called again, a new + gzip stream will be started in the output. gzread() is able to read such + concatenated gzip streams. + + gzflush should be called only when strictly necessary because it will + degrade compression if called too often. +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzseek(gzFile file, + z_off_t offset, int whence); + + Set the starting position to offset relative to whence for the next gzread + or gzwrite on file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be - extremely slow. If the file is opened for writing, only forward seeks are + extremely slow. If the file is opened for writing, only forward seeks are supported; gzseek then compresses a sequence of zeroes up to the new starting position. - gzseek returns the resulting offset location as measured in bytes from + gzseek returns the resulting offset location as measured in bytes from the beginning of the uncompressed stream, or -1 in case of error, in particular if the file is opened for writing and the new starting position would be before the current position. */ -ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +ZEXTERN int ZEXPORT gzrewind(gzFile file); /* - Rewinds the given file. This function is supported only for reading. + Rewind file. This function is supported only for reading. - gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET). */ -ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); /* - Returns the starting position for the next gzread or gzwrite on the - given compressed file. This position represents a number of bytes in the - uncompressed data stream. +ZEXTERN z_off_t ZEXPORT gztell(gzFile file); + + Return the starting position for the next gzread or gzwrite on file. + This position represents a number of bytes in the uncompressed data stream, + and is zero when starting, even if appending or reading a gzip stream from + the middle of a file using gzdopen(). - gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) */ -ZEXTERN int ZEXPORT gzeof OF((gzFile file)); /* - Returns 1 when EOF has previously been detected reading the given - input stream, otherwise zero. +ZEXTERN z_off_t ZEXPORT gzoffset(gzFile file); + + Return the current compressed (actual) read or write offset of file. This + offset includes the count of bytes that precede the gzip stream, for example + when appending or when using gzdopen() for reading. When reading, the + offset does not include as yet unused buffered input. This information can + be used for a progress indicator. On error, gzoffset() returns -1. */ -ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +ZEXTERN int ZEXPORT gzeof(gzFile file); /* - Flushes all pending output if necessary, closes the compressed file - and deallocates all the (de)compression state. The return value is the zlib - error number (see function gzerror below). + Return true (1) if the end-of-file indicator for file has been set while + reading, false (0) otherwise. Note that the end-of-file indicator is set + only if the read tried to go past the end of the input, but came up short. + Therefore, just like feof(), gzeof() may return false even if there is no + more data to read, in the event that the last read request was for the exact + number of bytes remaining in the input file. This will happen if the input + file size is an exact multiple of the buffer size. + + If gzeof() returns true, then the read functions will return no more data, + unless the end-of-file indicator is reset by gzclearerr() and the input file + has grown since the previous end of file was detected. */ -ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +ZEXTERN int ZEXPORT gzdirect(gzFile file); /* - Returns the error message for the last error which occurred on the - given compressed file. errnum is set to zlib error number. If an - error occurred in the file system and not in the compression library, - errnum is set to Z_ERRNO and the application may consult errno - to get the exact error code. + Return true (1) if file is being copied directly while reading, or false + (0) if file is a gzip stream being decompressed. + + If the input file is empty, gzdirect() will return true, since the input + does not contain a gzip stream. + + If gzdirect() is used immediately after gzopen() or gzdopen() it will + cause buffers to be allocated to allow reading the file to determine if it + is a gzip file. Therefore if gzbuffer() is used, it should be called before + gzdirect(). + + When writing, gzdirect() returns true (1) if transparent writing was + requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: + gzdirect() is not needed when writing. Transparent writing must be + explicitly requested, so the application already knows the answer. When + linking statically, using gzdirect() will include all of the zlib code for + gzip file reading and decompression, which may not be desired.) */ +ZEXTERN int ZEXPORT gzclose(gzFile file); +/* + Flush all pending output for file, if necessary, close file and + deallocate the (de)compression state. Note that once file is closed, you + cannot call gzerror with file, since its structures have been deallocated. + gzclose must not be called more than once on the same file, just as free + must not be called more than once on the same allocation. + + gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a + file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the + last read ended in the middle of a gzip stream, or Z_OK on success. +*/ + +ZEXTERN int ZEXPORT gzclose_r(gzFile file); +ZEXTERN int ZEXPORT gzclose_w(gzFile file); +/* + Same as gzclose(), but gzclose_r() is only for use when reading, and + gzclose_w() is only for use when writing or appending. The advantage to + using these instead of gzclose() is that they avoid linking in zlib + compression or decompression code that is not used when only reading or only + writing respectively. If gzclose() is used, then both compression and + decompression code will be included the application when linking to a static + zlib library. +*/ + +ZEXTERN const char * ZEXPORT gzerror(gzFile file, int *errnum); +/* + Return the error message for the last error which occurred on file. + errnum is set to zlib error number. If an error occurred in the file system + and not in the compression library, errnum is set to Z_ERRNO and the + application may consult errno to get the exact error code. + + The application must not modify the returned string. Future calls to + this function may invalidate the previously returned string. If file is + closed, then the string previously returned by gzerror will no longer be + available. + + gzerror() should be used to distinguish errors from end-of-file for those + functions above that do not distinguish those cases in their return values. +*/ + +ZEXTERN void ZEXPORT gzclearerr(gzFile file); +/* + Clear the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + +#endif /* !Z_SOLO */ + /* checksum functions */ /* These functions are not related to compression but are exported - anyway because they might be useful in applications using the - compression library. + anyway because they might be useful in applications using the compression + library. */ -ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); - +ZEXTERN uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len); /* Update a running Adler-32 checksum with the bytes buf[0..len-1] and - return the updated checksum. If buf is NULL, this function returns - the required initial value for the checksum. - An Adler-32 checksum is almost as reliable as a CRC32 but can be computed - much faster. Usage example: + return the updated checksum. An Adler-32 value is in the range of a 32-bit + unsigned integer. If buf is Z_NULL, this function returns the required + initial value for the checksum. + + An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed + much faster. + + Usage example: uLong adler = adler32(0L, Z_NULL, 0); @@ -835,12 +1709,32 @@ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); if (adler != original_adler) error(); */ -ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +ZEXTERN uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, + z_size_t len); /* - Update a running crc with the bytes buf[0..len-1] and return the updated - crc. If buf is NULL, this function returns the required initial value - for the crc. Pre- and post-conditioning (one's complement) is performed - within this function so it shouldn't be done by the application. + Same as adler32(), but with a size_t length. +*/ + +/* +ZEXTERN uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, + z_off_t len2); + + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note + that the z_off_t type (like off_t) is a signed integer. If len2 is + negative, the result has no meaning or utility. +*/ + +ZEXTERN uLong ZEXPORT crc32(uLong crc, const Bytef *buf, uInt len); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. A CRC-32 value is in the range of a 32-bit unsigned integer. + If buf is Z_NULL, this function returns the required initial value for the + crc. Pre- and post-conditioning (one's complement) is performed within this + function so it shouldn't be done by the application. + Usage example: uLong crc = crc32(0L, Z_NULL, 0); @@ -851,43 +1745,194 @@ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); if (crc != original_crc) error(); */ +ZEXTERN uLong ZEXPORT crc32_z(uLong crc, const Bytef *buf, + z_size_t len); +/* + Same as crc32(), but with a size_t length. +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2); + + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. len2 must be non-negative. +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t len2); + + Return the operator corresponding to length len2, to be used with + crc32_combine_op(). len2 must be non-negative. +*/ + +ZEXTERN uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op); +/* + Give the same result as crc32_combine(), using op in place of len2. op is + is generated from len2 by crc32_combine_gen(). This will be faster than + crc32_combine() if the generated op is used more than once. +*/ + /* various hacks, don't look :) */ /* deflateInit and inflateInit are macros to allow checking the zlib version * and the compiler's view of z_stream: */ -ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, - int windowBits, int memLevel, - int strategy, const char *version, - int stream_size)); -ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, - const char *version, int stream_size)); -#define deflateInit(strm, level) \ - deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit(strm) \ - inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) -#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ - deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ - (strategy), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit2(strm, windowBits) \ - inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) - - -#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL) - struct internal_state {int dummy;}; /* hack for buggy compilers */ +ZEXTERN int ZEXPORT deflateInit_(z_streamp strm, int level, + const char *version, int stream_size); +ZEXTERN int ZEXPORT inflateInit_(z_streamp strm, + const char *version, int stream_size); +ZEXTERN int ZEXPORT deflateInit2_(z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size); +ZEXTERN int ZEXPORT inflateInit2_(z_streamp strm, int windowBits, + const char *version, int stream_size); +ZEXTERN int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size); +#ifdef Z_PREFIX_SET +# define z_deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +# define z_inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) +#else +# define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +# define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +# define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +# define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +# define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) #endif -ZEXTERN const char * ZEXPORT zError OF((int err)); -ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); -ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); +#ifndef Z_SOLO + +/* gzgetc() macro and its supporting function and exposed data structure. Note + * that the real internal state is much larger than the exposed structure. + * This abbreviated structure exposes just enough for the gzgetc() macro. The + * user should not mess with these exposed elements, since their names or + * behavior could change in the future, perhaps even capriciously. They can + * only be used by the gzgetc() macro. You have been warned. + */ +struct gzFile_s { + unsigned have; + unsigned char *next; + z_off64_t pos; +}; +ZEXTERN int ZEXPORT gzgetc_(gzFile file); /* backward compatibility */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +# define z_gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) +#else +# define gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) +#endif + +/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or + * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if + * both are true, the application gets the *64 functions, and the regular + * functions are changed to 64 bits) -- in case these are set on systems + * without large file support, _LFS64_LARGEFILE must also be true + */ +#ifdef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *); + ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int); + ZEXTERN z_off64_t ZEXPORT gztell64(gzFile); + ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile); + ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off64_t); + ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off64_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off64_t); +#endif + +#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) +# ifdef Z_PREFIX_SET +# define z_gzopen z_gzopen64 +# define z_gzseek z_gzseek64 +# define z_gztell z_gztell64 +# define z_gzoffset z_gzoffset64 +# define z_adler32_combine z_adler32_combine64 +# define z_crc32_combine z_crc32_combine64 +# define z_crc32_combine_gen z_crc32_combine_gen64 +# else +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# define crc32_combine_gen crc32_combine_gen64 +# endif +# ifndef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *); + ZEXTERN z_off_t ZEXPORT gzseek64(gzFile, z_off_t, int); + ZEXTERN z_off_t ZEXPORT gztell64(gzFile); + ZEXTERN z_off_t ZEXPORT gzoffset64(gzFile); + ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t); +# endif +#else + ZEXTERN gzFile ZEXPORT gzopen(const char *, const char *); + ZEXTERN z_off_t ZEXPORT gzseek(gzFile, z_off_t, int); + ZEXTERN z_off_t ZEXPORT gztell(gzFile); + ZEXTERN z_off_t ZEXPORT gzoffset(gzFile); + ZEXTERN uLong ZEXPORT adler32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t); +#endif + +#else /* Z_SOLO */ + + ZEXTERN uLong ZEXPORT adler32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t); + +#endif /* !Z_SOLO */ + +/* undocumented functions */ +ZEXTERN const char * ZEXPORT zError(int); +ZEXTERN int ZEXPORT inflateSyncPoint(z_streamp); +ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table(void); +ZEXTERN int ZEXPORT inflateUndermine(z_streamp, int); +ZEXTERN int ZEXPORT inflateValidate(z_streamp, int); +ZEXTERN unsigned long ZEXPORT inflateCodesUsed(z_streamp); +ZEXTERN int ZEXPORT inflateResetKeep(z_streamp); +ZEXTERN int ZEXPORT deflateResetKeep(z_streamp); +#if defined(_WIN32) && !defined(Z_SOLO) +ZEXTERN gzFile ZEXPORT gzopen_w(const wchar_t *path, + const char *mode); +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +ZEXTERN int ZEXPORTVA gzvprintf(gzFile file, + const char *format, + va_list va); +# endif +#endif #ifdef __cplusplus } #endif -#endif /* _ZLIB_H */ +#endif /* ZLIB_H */ diff --git a/ZLIB/zutil.c b/ZLIB/zutil.c index 0a163dfc..b1c5d2d3 100644 --- a/ZLIB/zutil.c +++ b/ZLIB/zutil.c @@ -1,46 +1,125 @@ /* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995-2002 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2017 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h */ -/* @(#) $Id: zutil.c,v 1.1 2014/03/04 21:20:44 uid42406 Exp $ */ +/* @(#) $Id$ */ #include "zutil.h" - -struct internal_state {int dummy;}; /* for buggy compilers */ - -#ifndef STDC -extern void exit OF((int)); +#ifndef Z_SOLO +# include "gzguts.h" #endif -const char *z_errmsg[10] = { -"need dictionary", /* Z_NEED_DICT 2 */ -"stream end", /* Z_STREAM_END 1 */ -"", /* Z_OK 0 */ -"file error", /* Z_ERRNO (-1) */ -"stream error", /* Z_STREAM_ERROR (-2) */ -"data error", /* Z_DATA_ERROR (-3) */ -"insufficient memory", /* Z_MEM_ERROR (-4) */ -"buffer error", /* Z_BUF_ERROR (-5) */ -"incompatible version",/* Z_VERSION_ERROR (-6) */ -""}; - - -const char * ZEXPORT zlibVersion() -{ +z_const char * const z_errmsg[10] = { + (z_const char *)"need dictionary", /* Z_NEED_DICT 2 */ + (z_const char *)"stream end", /* Z_STREAM_END 1 */ + (z_const char *)"", /* Z_OK 0 */ + (z_const char *)"file error", /* Z_ERRNO (-1) */ + (z_const char *)"stream error", /* Z_STREAM_ERROR (-2) */ + (z_const char *)"data error", /* Z_DATA_ERROR (-3) */ + (z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */ + (z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */ + (z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */ + (z_const char *)"" +}; + + +const char * ZEXPORT zlibVersion(void) { return ZLIB_VERSION; } -#ifdef DEBUG +uLong ZEXPORT zlibCompileFlags(void) { + uLong flags; + flags = 0; + switch ((int)(sizeof(uInt))) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch ((int)(sizeof(uLong))) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch ((int)(sizeof(voidpf))) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch ((int)(sizeof(z_off_t))) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef ZLIB_DEBUG + flags += 1 << 8; +#endif + /* +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif + */ +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef ZLIB_DEBUG +#include # ifndef verbose # define verbose 0 # endif -int z_verbose = verbose; +int ZLIB_INTERNAL z_verbose = verbose; -void z_error (m) - char *m; -{ +void ZLIB_INTERNAL z_error(char *m) { fprintf(stderr, "%s\n", m); exit(1); } @@ -49,31 +128,28 @@ void z_error (m) /* exported to allow conversion of error code to string for compress() and * uncompress() */ -const char * ZEXPORT zError(err) - int err; -{ +const char * ZEXPORT zError(int err) { return ERR_MSG(err); } +#if defined(_WIN32_WCE) && _WIN32_WCE < 0x800 + /* The older Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif #ifndef HAVE_MEMCPY -void zmemcpy(dest, source, len) - Bytef* dest; - const Bytef* source; - uInt len; -{ +void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len) { if (len == 0) return; do { *dest++ = *source++; /* ??? to be unrolled */ } while (--len != 0); } -int zmemcmp(s1, s2, len) - const Bytef* s1; - const Bytef* s2; - uInt len; -{ +int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len) { uInt j; for (j = 0; j < len; j++) { @@ -82,10 +158,7 @@ int zmemcmp(s1, s2, len) return 0; } -void zmemzero(dest, len) - Bytef* dest; - uInt len; -{ +void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len) { if (len == 0) return; do { *dest++ = 0; /* ??? to be unrolled */ @@ -93,11 +166,13 @@ void zmemzero(dest, len) } #endif +#ifndef Z_SOLO + +#ifdef SYS16BIT + #ifdef __TURBOC__ -#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__) -/* Small and medium model in Turbo C are for now limited to near allocation - * with reduced MAX_WBITS and MAX_MEM_LEVEL - */ +/* Turbo C in 16-bit mode */ + # define MY_ZCALLOC /* Turbo C malloc() does not allow dynamic allocation of 64K bytes @@ -124,11 +199,12 @@ local ptr_table table[MAX_PTR]; * a protected system like OS/2. Use Microsoft C instead. */ -voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) -{ - voidpf buf = opaque; /* just to make some compilers happy */ +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) { + voidpf buf; ulg bsize = (ulg)items*size; + (void)opaque; + /* If we allocate less than 65520 bytes, we assume that farmalloc * will return a usable pointer which doesn't have to be normalized. */ @@ -148,9 +224,11 @@ voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) return buf; } -void zcfree (voidpf opaque, voidpf ptr) -{ +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { int n; + + (void)opaque; + if (*(ush*)&ptr != 0) { /* object < 64K */ farfree(ptr); return; @@ -166,14 +244,13 @@ void zcfree (voidpf opaque, voidpf ptr) next_ptr--; return; } - ptr = opaque; /* just to make some compilers happy */ Assert(0, "zcfree: ptr not found"); } -#endif + #endif /* __TURBOC__ */ -#if defined(M_I86) && !defined(__32BIT__) +#ifdef M_I86 /* Microsoft C in 16-bit mode */ # define MY_ZCALLOC @@ -183,43 +260,40 @@ void zcfree (voidpf opaque, voidpf ptr) # define _hfree hfree #endif -voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) -{ - if (opaque) opaque = 0; /* to make compiler happy */ +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, uInt items, uInt size) { + (void)opaque; return _halloc((long)items, size); } -void zcfree (voidpf opaque, voidpf ptr) -{ - if (opaque) opaque = 0; /* to make compiler happy */ +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { + (void)opaque; _hfree(ptr); } -#endif /* MSC */ +#endif /* M_I86 */ + +#endif /* SYS16BIT */ #ifndef MY_ZCALLOC /* Any system without a special alloc function */ #ifndef STDC -extern voidp calloc OF((uInt items, uInt size)); -extern void free OF((voidpf ptr)); +extern voidp malloc(uInt size); +extern voidp calloc(uInt items, uInt size); +extern void free(voidpf ptr); #endif -voidpf zcalloc (opaque, items, size) - voidpf opaque; - unsigned items; - unsigned size; -{ - if (opaque) items += size - size; /* make compiler happy */ - return (voidpf)calloc(items, size); +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) { + (void)opaque; + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); } -void zcfree (opaque, ptr) - voidpf opaque; - voidpf ptr; -{ +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { + (void)opaque; free(ptr); - if (opaque) return; /* make compiler happy */ } #endif /* MY_ZCALLOC */ + +#endif /* !Z_SOLO */ diff --git a/ZLIB/zutil.h b/ZLIB/zutil.h index 1bf5bc6b..48dd7feb 100644 --- a/ZLIB/zutil.h +++ b/ZLIB/zutil.h @@ -1,5 +1,5 @@ /* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-2002 Jean-loup Gailly. + * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -8,28 +8,33 @@ subject to change. Applications should only use zlib.h. */ -/* @(#) $Id: zutil.h,v 1.1 2014/03/04 21:20:44 uid42406 Exp $ */ +/* @(#) $Id$ */ -#ifndef _Z_UTIL_H -#define _Z_UTIL_H +#ifndef ZUTIL_H +#define ZUTIL_H + +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif #include "zlib.h" -#ifdef STDC -# include +#if defined(STDC) && !defined(Z_SOLO) +# if !(defined(_WIN32_WCE) && defined(_MSC_VER)) +# include +# endif # include # include #endif -#ifdef NO_ERRNO_H - extern int errno; -#else -# include -#endif #ifndef local # define local static #endif -/* compile with -Dlocal if your debugger can't find static symbols */ +/* since "static" is used to mean two completely different things in C, we + define "local" for the non-static meaning of "static", for readability + (compile with -Dlocal if your debugger can't find static symbols) */ typedef unsigned char uch; typedef uch FAR uchf; @@ -37,13 +42,24 @@ typedef unsigned short ush; typedef ush FAR ushf; typedef unsigned long ulg; -extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ +#if !defined(Z_U8) && !defined(Z_SOLO) && defined(STDC) +# include +# if (ULONG_MAX == 0xffffffffffffffff) +# define Z_U8 unsigned long +# elif (ULLONG_MAX == 0xffffffffffffffff) +# define Z_U8 unsigned long long +# elif (UINT_MAX == 0xffffffffffffffff) +# define Z_U8 unsigned +# endif +#endif + +extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ /* (size given to avoid silly warnings with Visual C++) */ -#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] +#define ERR_MSG(err) z_errmsg[(err) < -6 || (err) > 2 ? 9 : 2 - (err)] #define ERR_RETURN(strm,err) \ - return (strm->msg = (char*)ERR_MSG(err), (err)) + return (strm->msg = ERR_MSG(err), (err)) /* To be used only when the state is known to be valid */ /* common constants */ @@ -73,75 +89,96 @@ extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ /* target dependencies */ -#ifdef MSDOS +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) # define OS_CODE 0x00 -# if defined(__TURBOC__) || defined(__BORLANDC__) -# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) - /* Allow compilation with ANSI keywords only enabled */ - void _Cdecl farfree( void *block ); - void *_Cdecl farmalloc( unsigned long nbytes ); -# else -# include +# ifndef Z_SOLO +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include # endif -# else /* MSC or DJGPP */ -# include # endif #endif -#ifdef OS2 -# define OS_CODE 0x06 -#endif - -#ifdef WIN32 /* Window 95 & Windows NT */ -# define OS_CODE 0x0b +#ifdef AMIGA +# define OS_CODE 1 #endif #if defined(VAXC) || defined(VMS) -# define OS_CODE 0x02 +# define OS_CODE 2 # define F_OPEN(name, mode) \ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") #endif -#ifdef AMIGA -# define OS_CODE 0x01 +#ifdef __370__ +# if __TARGET_LIB__ < 0x20000000 +# define OS_CODE 4 +# elif __TARGET_LIB__ < 0x40000000 +# define OS_CODE 11 +# else +# define OS_CODE 8 +# endif #endif #if defined(ATARI) || defined(atarist) -# define OS_CODE 0x05 +# define OS_CODE 5 #endif -#if defined(MACOS) || defined(TARGET_OS_MAC) -# define OS_CODE 0x07 -# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os -# include /* for fdopen */ -# else -# ifndef fdopen -# define fdopen(fd,mode) NULL /* No fdopen() */ -# endif +#ifdef OS2 +# define OS_CODE 6 +# if defined(M_I86) && !defined(Z_SOLO) +# include # endif #endif -#ifdef __50SERIES /* Prime/PRIMOS */ -# define OS_CODE 0x0F +#if defined(MACOS) +# define OS_CODE 7 #endif -#ifdef TOPS20 -# define OS_CODE 0x0a +#ifdef __acorn +# define OS_CODE 13 #endif -#if defined(_BEOS_) || defined(RISCOS) -# define fdopen(fd,mode) NULL /* No fdopen() */ +#if defined(WIN32) && !defined(__CYGWIN__) +# define OS_CODE 10 #endif -#if (defined(_MSC_VER) && (_MSC_VER > 600)) -# define fdopen(fd,type) _fdopen(fd,type) +#ifdef _BEOS_ +# define OS_CODE 16 #endif +#ifdef __TOS_OS400__ +# define OS_CODE 18 +#endif - /* Common defaults */ +#ifdef __APPLE__ +# define OS_CODE 19 +#endif + +#if defined(__BORLANDC__) && !defined(MSDOS) + #pragma warn -8004 + #pragma warn -8008 + #pragma warn -8066 +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_WIN32) && \ + (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) + ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t); +#endif + + /* common defaults */ #ifndef OS_CODE -# define OS_CODE 0x03 /* assume Unix */ +# define OS_CODE 3 /* assume Unix */ #endif #ifndef F_OPEN @@ -150,14 +187,7 @@ extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ /* functions */ -#ifdef HAVE_STRERROR - extern char *strerror OF((int)); -# define zstrerror(errnum) strerror(errnum) -#else -# define zstrerror(errnum) "" -#endif - -#if defined(pyr) +#if defined(pyr) || defined(Z_SOLO) # define NO_MEMCPY #endif #if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) @@ -181,16 +211,16 @@ extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ # define zmemzero(dest, len) memset(dest, 0, len) # endif #else - extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); - extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); - extern void zmemzero OF((Bytef* dest, uInt len)); + void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len); + int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len); + void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len); #endif /* Diagnostic functions */ -#ifdef DEBUG +#ifdef ZLIB_DEBUG # include - extern int z_verbose; - extern void z_error OF((char *m)); + extern int ZLIB_INTERNAL z_verbose; + extern void ZLIB_INTERNAL z_error(char *m); # define Assert(cond,msg) {if(!(cond)) z_error(msg);} # define Trace(x) {if (z_verbose>=0) fprintf x ;} # define Tracev(x) {if (z_verbose>0) fprintf x ;} @@ -206,15 +236,19 @@ extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ # define Tracecv(c,x) #endif - -typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf, - uInt len)); -voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); -void zcfree OF((voidpf opaque, voidpf ptr)); +#ifndef Z_SOLO + voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, + unsigned size); + void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr); +#endif #define ZALLOC(strm, items, size) \ (*((strm)->zalloc))((strm)->opaque, (items), (size)) #define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) #define TRY_FREE(s, p) {if (p) ZFREE(s, p);} -#endif /* _Z_UTIL_H */ +/* Reverse the bytes in a 32-bit value */ +#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +#endif /* ZUTIL_H */