diff --git a/.gitignore b/.gitignore index 3fb3f818..73ae1738 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ /Bin/ *.opensdf *.bat +*.zip +.vs/* \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..5f806177 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,50 @@ +cmake_minimum_required(VERSION 3.7) + +set(CMAKE_DISABLE_SOURCE_CHANGES ON) +set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) +set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) + +project(PoissonRecon LANGUAGES CXX) + +if(MSVC) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set_property(GLOBAL PROPERTY USE_FOLDERS ON) +endif() + +if((CMAKE_CXX_COMPILER_ID MATCHES "Clang") OR CMAKE_COMPILER_IS_GNUCC + OR CMAKE_COMPILER_IS_GNUCXX) + if(DEBUG) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Winline") + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -DNDEBUG") + endif() +endif() + +message(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +if(NOT TARGET uninstall) + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake IMMEDIATE @ONLY) + + add_custom_target( + uninstall COMMAND ${CMAKE_COMMAND} -P + ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) +endif() + +export(TARGETS FILE ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake) + +file(WRITE ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Config.cmake + "include(CMakeFindDependencyMacro)\n" + "include(\${CMAKE_CURRENT_LIST_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake)\n") + +add_subdirectory(modules) +add_subdirectory(apps) + +install(FILES ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Config.cmake + DESTINATION lib/cmake/${CMAKE_PROJECT_NAME}) + +install(EXPORT ${CMAKE_PROJECT_NAME}Targets + DESTINATION lib/cmake/${CMAKE_PROJECT_NAME}) diff --git a/Makefile b/Makefile deleted file mode 100644 index f71afaf5..00000000 --- a/Makefile +++ /dev/null @@ -1,71 +0,0 @@ -PR_TARGET=PoissonRecon -SR_TARGET=SSDRecon -ST_TARGET=SurfaceTrimmer -PR_SOURCE=CmdLineParser.cpp Factor.cpp Geometry.cpp MarchingCubes.cpp PlyFile.cpp PoissonRecon.cpp -SR_SOURCE=CmdLineParser.cpp Factor.cpp Geometry.cpp MarchingCubes.cpp PlyFile.cpp SSDRecon.cpp -ST_SOURCE=CmdLineParser.cpp Factor.cpp Geometry.cpp MarchingCubes.cpp PlyFile.cpp SurfaceTrimmer.cpp - -CFLAGS += -fopenmp -Wno-deprecated -Wno-write-strings -std=c++11 -LFLAGS += -lgomp -lstdc++ - -CFLAGS_DEBUG = -DDEBUG -g3 -LFLAGS_DEBUG = - -CFLAGS_RELEASE = -O3 -DRELEASE -funroll-loops -ffast-math -LFLAGS_RELEASE = -O3 - -SRC = Src/ -BIN = Bin/Linux/ -INCLUDE = /usr/include/ - -CC=gcc -CXX=g++ -MD=mkdir - -PR_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(PR_SOURCE)))) -SR_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(SR_SOURCE)))) -ST_OBJECTS=$(addprefix $(BIN), $(addsuffix .o, $(basename $(ST_SOURCE)))) - - -all: CFLAGS += $(CFLAGS_DEBUG) -all: LFLAGS += $(LFLAGS_DEBUG) -all: $(BIN) -all: $(BIN)$(PR_TARGET) -all: $(BIN)$(SR_TARGET) -all: $(BIN)$(ST_TARGET) - -release: CFLAGS += $(CFLAGS_RELEASE) -release: LFLAGS += $(LFLAGS_RELEASE) -release: $(BIN) -release: $(BIN)$(PR_TARGET) -release: $(BIN)$(SR_TARGET) -release: $(BIN)$(ST_TARGET) - -clean: - rm -f $(BIN)$(PR_TARGET) - rm -f $(BIN)$(SR_TARGET) - rm -f $(BIN)$(ST_TARGET) - rm -f $(PR_OBJECTS) - rm -f $(SR_OBJECTS) - rm -f $(ST_OBJECTS) - -$(BIN): - $(MD) -p $(BIN) - -$(BIN)$(PR_TARGET): $(PR_OBJECTS) - $(CXX) -o $@ $(PR_OBJECTS) $(LFLAGS) - -$(BIN)$(SR_TARGET): $(SR_OBJECTS) - $(CXX) -o $@ $(SR_OBJECTS) $(LFLAGS) - -$(BIN)$(ST_TARGET): $(ST_OBJECTS) - $(CXX) -o $@ $(ST_OBJECTS) $(LFLAGS) - -$(BIN)%.o: $(SRC)%.c - mkdir -p $(BIN) - $(CC) -c -o $@ $(CFLAGS) -I$(INCLUDE) $< - -$(BIN)%.o: $(SRC)%.cpp - mkdir -p $(BIN) - $(CXX) -c -o $@ $(CFLAGS) -I$(INCLUDE) $< - diff --git a/PoissonRecon.sln b/PoissonRecon.sln deleted file mode 100644 index ed7a3b4f..00000000 --- a/PoissonRecon.sln +++ /dev/null @@ -1,34 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PoissonRecon", "PoissonRecon.vcxproj", "{46F87D0E-C53A-4F95-AB48-A5DBA8014340}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SurfaceTrimmer", "SurfaceTrimmer.vcxproj", "{99BEAFED-8DB9-4B7D-A0BE-5186158193FE}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SSDRecon", "SSDRecon.vcxproj", "{7838CA1E-8A39-4A2B-AC3D-3E25FEAEA2D6}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {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}.Release|x64.ActiveCfg = Release|x64 - {46F87D0E-C53A-4F95-AB48-A5DBA8014340}.Release|x64.Build.0 = Release|x64 - {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}.Release|x64.ActiveCfg = Release|x64 - {99BEAFED-8DB9-4B7D-A0BE-5186158193FE}.Release|x64.Build.0 = Release|x64 - {7838CA1E-8A39-4A2B-AC3D-3E25FEAEA2D6}.Debug|x64.ActiveCfg = Debug|x64 - {7838CA1E-8A39-4A2B-AC3D-3E25FEAEA2D6}.Debug|x64.Build.0 = Debug|x64 - {7838CA1E-8A39-4A2B-AC3D-3E25FEAEA2D6}.Release|x64.ActiveCfg = Release|x64 - {7838CA1E-8A39-4A2B-AC3D-3E25FEAEA2D6}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/PoissonRecon.vcxproj b/PoissonRecon.vcxproj deleted file mode 100644 index e5d1740e..00000000 --- a/PoissonRecon.vcxproj +++ /dev/null @@ -1,235 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - PoissonRecon - {46F87D0E-C53A-4F95-AB48-A5DBA8014340} - PoissonRecon - Win32Proj - 8.1 - - - - Application - MultiByte - true - v140 - - - Application - MultiByte - v140 - - - Application - MultiByte - true - v140 - - - Application - MultiByte - v140 - true - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(SolutionDir)\Bin\$(Platform)\$(Configuration)\ - $(SolutionDir)\Obj\$(Platform)\$(Configuration)\ - true - $(SolutionDir)\Bin\$(Platform)\$(Configuration)\ - $(SolutionDir)\Obj\$(TargetName)\$(Platform)\$(Configuration)\ - true - $(SolutionDir)Bin\$(Platform)\$(Configuration)\ - $(SolutionDir)\Obj\$(TargetName)\$(Platform)\$(Configuration)\ - false - $(SolutionDir)\Bin\$(Platform)\$(Configuration)\ - $(SolutionDir)\Obj\$(TargetName)\$(Platform)\$(Configuration)\ - false - .exe - - - - Disabled - WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - EditAndContinue - - - true - Console - false - - - MachineX86 - - - - - X64 - - - Disabled - WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - ProgramDatabase - true - - - true - Console - false - - - MachineX64 - - - - - WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - MultiThreadedDLL - - - Level3 - ProgramDatabase - true - %(AdditionalIncludeDirectories) - - - true - Console - true - true - true - false - - - MachineX86 - 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) - - - - - X64 - - - %(AdditionalIncludeDirectories) - WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - MultiThreadedDLL - - - Level3 - ProgramDatabase - Precise - true - false - AdvancedVectorExtensions2 - - - true - Console - true - true - false - - - MachineX64 - 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) - - - $(OutDir)$(TargetName)$(TargetExt) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/PoissonRecon.vcxproj.filters b/PoissonRecon.vcxproj.filters deleted file mode 100644 index 16466a46..00000000 --- a/PoissonRecon.vcxproj.filters +++ /dev/null @@ -1,143 +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} - inc;inl - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - \ No newline at end of file diff --git a/README.md b/README.md index 482b9742..f7db3246 100644 --- a/README.md +++ b/README.md @@ -1,55 +1,84 @@ -

Screened Poisson Surface Reconstruction
(and Smoothed Signed Distance Reconstruction)
Version 9.01

-
-links -executables -usage -changes -support -
-
-LINKS
+

Adaptive Multigrid Solvers (Version 12.00)

+
+links +executables +usage +changes + +
+
+This code-base was born from the Poisson Surface Reconstruction code. It has evolved to support more general adaptive finite-elements systems: -
-EXECUTABLES
- +
[--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). +
[--performance] +
Enabling this flag provides running time and peak memory usage at the end of the execution. - + + + +
+ + + + + + + +
[--polygonMesh] +
Enabling this flag tells the trimmer to output a polygon mesh (rather than triangulating the trimming results). + +
[--verbose] +
Enabling this flag provides a more verbose description of the running times and memory usages of individual components of the surface reconstructor. + +
+ + + + + + + + + + + + + + + +
+USAGE EXAMPLES (WITH SAMPLE DATA)
+ + + + + + + + + + + +
+
+ +HISTORY OF CHANGES + +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: +
    +
  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. 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: +
    +
  1. The algorithmic complexity of the solver was reduced from log-linear to linear. +
+Version 4.51: +
    +
  1. Smart pointers were added to ensure that memory accesses were in bounds. +
+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: +
    +
  1. Minor bug-fix to address incorrect neighborhood estimation in the octree finalization. +
+ +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: +
    +
  1. Added the --normalWeight flag to support setting a point's interpolation weight in proportion to the magnitude of its normal. +
+ +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: +
    +
  1. Added the function GetSolutionValue to support the evaluation of the implicit function at a specific point. +
+ +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: +
    +
  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: +
    +
  1. Fixed a bug that created a crash in the evaluation phase when --pointWeight is set zero. +
+ +Version 6.12: +
    +
  1. Removed the OpenMP firstprivate directive as it seemed to cause trouble under Linux compilations. +
+ +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: +
    +
  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] +
+ +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: +
    +
  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. -If higher order degrees are desired, additional template parameters can be easily added in the body of the Execute function inside of PoissonRecon.cpp. +If higher order degrees are desired, additional template parameters can be easily added in the body of the Execute function inside of PoissonRecon.cpp. Similarly, to reduce compilation times, support for specific degrees can be removed.) -
  2. Added the --primalVoxel flag to support to extraction of a voxel grid using primal sampling. -
  3. Changed the implementation of the voxel sampling so that computation is now linear, rather than log-linear, in the number of samples. -
- -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. 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: -
    -
  1. Reverted the density estimation to behave as in Version 8.0. -
- -
-SUPPORT
+
  • Added the --primalGrid flag to support to extraction of a grid using primal sampling. +
  • 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: +
      +
    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. 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: +
      +
    1. Reverted the density estimation to behave as in Version 8.0. +
    + +Version 9.011: +
      +
    1. Added a parameter for specifying the temporary directory. +
    + +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. +
    3. 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.
    4. +
    5. 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.
    6. +
    + +Version 10.01: +
      +
    1. Modified the reconstruction code to facilitate interpolation of other input-sample quantities, in addition to color.
    2. +
    + +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.
    2. +
    + +Version 10.03: +
      +
    1. Cleaned up memory leaks and fixed a bug causing ImageStitching and EDTInHeat to SEGFAULT on Linux. +
    + +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: +
      +
    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: +
      +
    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: +
      +
    1. Removed a bug that would cause memory access errors when some slices were empty. +
    + +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: +
      +
    1. Fixed bug with _mktemp that caused the code to crash on Windows machine with more than 26 cores. +
    + +Version 11.02: +
      +
    1. Added error handling for numerical imprecision issues arrising when too many samples fall into a leaf node. +
    + +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. +
    + +
    + + +
    +SUPPORT
    This work genersouly supported by NSF grants #0746039 and #1422325. - -
    -HOME diff --git a/SSDRecon.vcxproj b/SSDRecon.vcxproj deleted file mode 100644 index 5ddf8894..00000000 --- a/SSDRecon.vcxproj +++ /dev/null @@ -1,235 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - SSDRecon - {7838CA1E-8A39-4A2B-AC3D-3E25FEAEA2D6} - PoissonRecon - Win32Proj - 8.1 - - - - Application - MultiByte - true - v140 - - - Application - MultiByte - v140 - - - Application - MultiByte - true - v140 - - - Application - MultiByte - v140 - true - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(SolutionDir)\Bin\$(Platform)\$(Configuration)\ - $(SolutionDir)\Obj\$(Platform)\$(Configuration)\ - true - $(SolutionDir)\Bin\$(Platform)\$(Configuration)\ - $(SolutionDir)\Obj\$(TargetName)\$(Platform)\$(Configuration)\ - true - $(SolutionDir)Bin\$(Platform)\$(Configuration)\ - $(SolutionDir)\Obj\$(TargetName)\$(Platform)\$(Configuration)\ - false - $(SolutionDir)\Bin\$(Platform)\$(Configuration)\ - $(SolutionDir)\Obj\$(TargetName)\$(Platform)\$(Configuration)\ - false - .exe - - - - Disabled - WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - EditAndContinue - - - true - Console - false - - - MachineX86 - - - - - X64 - - - Disabled - WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - ProgramDatabase - true - - - true - Console - false - - - MachineX64 - - - - - WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - MultiThreadedDLL - - - Level3 - ProgramDatabase - true - %(AdditionalIncludeDirectories) - - - true - Console - true - true - true - false - - - MachineX86 - 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) - - - - - X64 - - - %(AdditionalIncludeDirectories) - WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - MultiThreadedDLL - - - Level3 - ProgramDatabase - Precise - true - false - AdvancedVectorExtensions2 - - - true - Console - true - true - false - - - MachineX64 - 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) - - - $(OutDir)$(TargetName)$(TargetExt) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/SSDRecon.vcxproj.filters b/SSDRecon.vcxproj.filters deleted file mode 100644 index ce331d6a..00000000 --- a/SSDRecon.vcxproj.filters +++ /dev/null @@ -1,143 +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} - inc;inl - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - Include Files - - - \ No newline at end of file diff --git a/Src/Array.inl b/Src/Array.inl deleted file mode 100644 index 6247f528..00000000 --- a/Src/Array.inl +++ /dev/null @@ -1,662 +0,0 @@ -/* -Copyright (c) 2011, Michael Kazhdan and Ming Chuang -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ -#define FULL_ARRAY_DEBUG 0 // Note that this is not thread-safe - -#include -#include -#include -#ifdef _WIN32 -#include -#endif // _WIN32 -#include - -inline bool isfinitef( float fp ){ float f=fp; return ((*(unsigned *)&f)&0x7f800000)!=0x7f800000; } - - -template< class C > bool IsValid( const C& c ); -#if _DEBUG -template< > inline bool IsValid< float >( const float& f ) { return isfinitef( f ) && ( f==0.f || abs(f)>1e-31f ); } -#else // !_DEBUG -template< > inline bool IsValid< float >( const float& f ) { return isfinitef( f ); } -#endif // _DEBUG -template< > inline bool IsValid< __m128 >( const __m128& m ) -{ - const __m128* addr = &m; - if( size_t(addr) & 15 ) return false; - else return true; -} -template< class C > inline bool IsValid( const C& c ){ return true; } - - -#if FULL_ARRAY_DEBUG -class DebugMemoryInfo -{ -public: - const void* address; - char name[512]; -}; -static std::vector< DebugMemoryInfo > memoryInfo; -#endif // FULL_ARRAY_DEBUG - -template< class C > -class Array -{ - void _assertBounds( long long idx ) const - { - if( idx=max ) - { - fprintf( stderr , "Array index out-of-bounds: %lld <= %lld < %lld\n" , min , idx , max ); - ASSERT( 0 ); - exit( 0 ); - } - } -protected: - C *data , *_data; - long long min , max; -#if FULL_ARRAY_DEBUG - static void _AddMemoryInfo( const void* ptr , const char* name ) - { - size_t sz = memoryInfo.size(); - memoryInfo.resize( sz + 1 ); - memoryInfo[sz].address = ptr; - if( name ) strcpy( memoryInfo[sz].name , name ); - else memoryInfo[sz].name[0] = 0; - } - static void _RemoveMemoryInfo( const void* ptr ) - { - { - size_t idx; - for( idx=0 ; idx - Array( Array< D >& a ) - { - _data = NULL; - if( !a ) - { - data = NULL; - min = max = 0; - } - else - { - // [WARNING] Chaning szC and szD to size_t causes some really strange behavior. - long long szC = sizeof( C ); - long long szD = sizeof( D ); - data = (C*)a.data; - min = ( a.minimum() * szD ) / szC; - max = ( a.maximum() * szD ) / szC; - if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD ) - { - fprintf( stderr , "Could not convert array [ %lld , %lld ] * %lld => [ %lld , %lld ] * %lld\n" , a.minimum() , a.maximum() , szD , min , max , szC ); - ASSERT( 0 ); - exit( 0 ); - } - } - } - static Array FromPointer( C* data , long long max ) - { - Array a; - a._data = NULL; - a.data = data; - a.min = 0; - a.max = max; - return a; - } - static Array FromPointer( C* data , long long min , long long max ) - { - Array a; - a._data = NULL; - a.data = data; - a.min = min; - a.max = max; - return a; - } - inline bool operator == ( const Array< C >& a ) const { return data==a.data; } - inline bool operator != ( const Array< C >& a ) const { return data!=a.data; } - inline bool operator == ( const C* c ) const { return data==c; } - inline bool operator != ( const C* c ) const { return data!=c; } - inline C* operator -> ( void ) - { - _assertBounds( 0 ); - return data; - } - inline const C* operator -> ( ) const - { - _assertBounds( 0 ); - return data; - } - inline C& operator[]( long long idx ) - { - _assertBounds( idx ); - return data[idx]; - } - inline const C& operator[]( long long idx ) const - { - _assertBounds( idx ); - return data[idx]; - } - inline Array operator + ( int idx ) const - { - Array a; - a._data = _data; - a.data = data+idx; - a.min = min-idx; - a.max = max-idx; - return a; - } - inline Array operator + ( long long idx ) const - { - Array a; - a._data = _data; - a.data = data+idx; - a.min = min-idx; - a.max = max-idx; - return a; - } - inline Array operator + ( unsigned int idx ) const - { - Array a; - a._data = _data; - a.data = data+idx; - a.min = min-idx; - a.max = max-idx; - return a; - } - inline Array operator + ( unsigned long long idx ) const - { - Array a; - a._data = _data; - a.data = data+idx; - a.min = min-idx; - a.max = max-idx; - return a; - } - inline Array& operator += ( int idx ) - { - min -= idx; - max -= idx; - data += idx; - return (*this); - } - inline Array& operator += ( long long idx ) - { - min -= idx; - max -= idx; - data += idx; - return (*this); - } - inline Array& operator += ( unsigned int idx ) - { - min -= idx; - max -= idx; - data += idx; - return (*this); - } - inline Array& operator += ( unsigned long long idx ) - { - min -= idx; - max -= idx; - data += idx; - return (*this); - } - inline Array& operator ++ ( void ) { return (*this) += 1; } - inline Array operator++( int ){ Array< C > temp = (*this) ; (*this) +=1 ; return temp; } - Array operator - ( int idx ) const { return (*this) + (-idx); } - Array operator - ( long long idx ) const { return (*this) + (-idx); } - Array operator - ( unsigned int idx ) const { return (*this) + (-idx); } - Array operator - ( unsigned long long idx ) const { return (*this) + (-idx); } - Array& operator -= ( int idx ) { return (*this) += (-idx); } - Array& operator -= ( long long idx ) { return (*this) += (-idx); } - Array& operator -= ( unsigned int idx ) { return (*this) += (-idx); } - Array& operator -= ( unsigned long long idx ) { return (*this) += (-idx); } - Array& operator -- ( void ) { return (*this) -= 1; } - inline Array operator--( int ){ Array< C > temp = (*this) ; (*this) -=1 ; return temp; } - long long operator - ( const Array& a ) const { return ( long long )( data - a.data ); } - - void Free( void ) - { - if( _data ) - { - free( _data ); -#if FULL_ARRAY_DEBUG - _RemoveMemoryInfo( _data ); -#endif // FULL_ARRAY_DEBUG - } - (*this) = Array( ); - } - void Delete( void ) - { - if( _data ) - { - delete[] _data; -#if FULL_ARRAY_DEBUG - _RemoveMemoryInfo( _data ); -#endif // FULL_ARRAY_DEBUG - } - (*this) = Array( ); - } - C* pointer( void ){ return data; } - const C* pointer( void ) const { return data; } - bool operator !( void ) const { return data==NULL; } - operator bool( ) const { return data!=NULL; } -}; - -template< class C > -class ConstArray -{ - void _assertBounds( long long idx ) const - { - if( idx=max ) - { - fprintf( stderr , "ConstArray index out-of-bounds: %lld <= %lld < %lld\n" , min , idx , max ); - ASSERT( 0 ); - exit( 0 ); - } - } -protected: - const C *data; - long long min , max; -public: - long long minimum( void ) const { return min; } - long long maximum( void ) const { return max; } - - inline ConstArray( void ) - { - data = NULL; - min = max = 0; - } - inline ConstArray( const Array< C >& a ) - { - // [WARNING] Changing szC and szD to size_t causes some really strange behavior. - data = ( const C* )a.pointer( ); - min = a.minimum(); - max = a.maximum(); - } - template< class D > - inline ConstArray( const Array< D >& a ) - { - // [WARNING] Changing szC and szD to size_t causes some really strange behavior. - long long szC = ( long long ) sizeof( C ); - long long szD = ( long long ) sizeof( D ); - data = ( const C* )a.pointer( ); - min = ( a.minimum() * szD ) / szC; - max = ( a.maximum() * szD ) / szC; - if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD ) - { -// fprintf( stderr , "Could not convert const array [ %lld , %lld ] * %lld => [ %lld , %lld ] * %lld\n" , a.minimum() , a.maximum() , szD , min , max , szC ); - fprintf( stderr , "Could not convert const array [ %lld , %lld ] * %lld => [ %lld , %lld ] * %lld\n %lld %lld %lld\n" , a.minimum() , a.maximum() , szD , min , max , szC , a.minimum() , a.minimum()*szD , (a.minimum()*szD)/szC ); - ASSERT( 0 ); - exit( 0 ); - } - } - template< class D > - inline ConstArray( const ConstArray< D >& a ) - { - // [WARNING] Chaning szC and szD to size_t causes some really strange behavior. - long long szC = sizeof( C ); - long long szD = sizeof( D ); - data = ( const C*)a.pointer( ); - min = ( a.minimum() * szD ) / szC; - max = ( a.maximum() * szD ) / szC; - if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD ) - { - fprintf( stderr , "Could not convert array [ %lld , %lld ] * %lld => [ %lld , %lld ] * %lld\n" , a.minimum() , a.maximum() , szD , min , max , szC ); - ASSERT( 0 ); - exit( 0 ); - } - } - static ConstArray FromPointer( const C* data , long long max ) - { - ConstArray a; - a.data = data; - a.min = 0; - a.max = max; - return a; - } - static ConstArray FromPointer( const C* data , long long min , long long max ) - { - ConstArray a; - a.data = data; - a.min = min; - a.max = max; - return a; - } - - inline bool operator == ( const ConstArray< C >& a ) const { return data==a.data; } - inline bool operator != ( const ConstArray< C >& a ) const { return data!=a.data; } - inline bool operator == ( const C* c ) const { return data==c; } - inline bool operator != ( const C* c ) const { return data!=c; } - inline const C* operator -> ( void ) - { - _assertBounds( 0 ); - return data; - } - inline const C& operator[]( long long idx ) const - { - _assertBounds( idx ); - return data[idx]; - } - inline ConstArray operator + ( int idx ) const - { - ConstArray a; - a.data = data+idx; - a.min = min-idx; - a.max = max-idx; - return a; - } - inline ConstArray operator + ( long long idx ) const - { - ConstArray a; - a.data = data+idx; - a.min = min-idx; - a.max = max-idx; - return a; - } - inline ConstArray operator + ( unsigned int idx ) const - { - ConstArray a; - a.data = data+idx; - a.min = min-idx; - a.max = max-idx; - return a; - } - inline ConstArray operator + ( unsigned long long idx ) const - { - ConstArray a; - a.data = data+idx; - a.min = min-idx; - a.max = max-idx; - return a; - } - inline ConstArray& operator += ( int idx ) - { - min -= idx; - max -= idx; - data += idx; - return (*this); - } - inline ConstArray& operator += ( long long idx ) - { - min -= idx; - max -= idx; - data += idx; - return (*this); - } - inline ConstArray& operator += ( unsigned int idx ) - { - min -= idx; - max -= idx; - data += idx; - return (*this); - } - inline ConstArray& operator += ( unsigned long long idx ) - { - min -= idx; - max -= idx; - data += idx; - return (*this); - } - inline ConstArray& operator ++ ( void ) { return (*this) += 1; } - inline ConstArray operator++( int ){ ConstArray< C > temp = (*this) ; (*this) +=1 ; return temp; } - ConstArray operator - ( int idx ) const { return (*this) + (-idx); } - ConstArray operator - ( long long idx ) const { return (*this) + (-idx); } - ConstArray operator - ( unsigned int idx ) const { return (*this) + (-idx); } - ConstArray operator - ( unsigned long long idx ) const { return (*this) + (-idx); } - ConstArray& operator -= ( int idx ) { return (*this) += (-idx); } - ConstArray& operator -= ( long long idx ) { return (*this) += (-idx); } - ConstArray& operator -= ( unsigned int idx ) { return (*this) += (-idx); } - ConstArray& operator -= ( unsigned long long idx ) { return (*this) += (-idx); } - ConstArray& operator -- ( void ) { return (*this) -= 1; } - inline ConstArray operator--( int ){ ConstArray< C > temp = (*this) ; (*this) -=1 ; return temp; } - long long operator - ( const ConstArray& a ) const { return ( long long )( data - a.data ); } - long long operator - ( const Array< C >& a ) const { return ( long long )( data - a.pointer() ); } - - const C* pointer( void ) const { return data; } - bool operator !( void ) { return data==NULL; } - operator bool( ) { return data!=NULL; } -}; - -#if FULL_ARRAY_DEBUG -inline void PrintMemoryInfo( void ){ for( size_t i=0 ; i -Array< C > memcpy( Array< C > destination , const void* source , size_t size ) -{ - if( size>destination.maximum()*sizeof(C) ) - { - fprintf( stderr , "Size of copy exceeds destination maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( destination.maximum()*sizeof( C ) ) ); - ASSERT( 0 ); - exit( 0 ); - } - if( size ) memcpy( &destination[0] , source , size ); - return destination; -} -template< class C , class D > -Array< C > memcpy( Array< C > destination , Array< D > source , size_t size ) -{ - if( size>destination.maximum()*sizeof( C ) ) - { - fprintf( stderr , "Size of copy exceeds destination maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( destination.maximum()*sizeof( C ) ) ); - ASSERT( 0 ); - exit( 0 ); - } - if( size>source.maximum()*sizeof( D ) ) - { - fprintf( stderr , "Size of copy exceeds source maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( source.maximum()*sizeof( D ) ) ); - ASSERT( 0 ); - exit( 0 ); - } - if( size ) memcpy( &destination[0] , &source[0] , size ); - return destination; -} -template< class C , class D > -Array< C > memcpy( Array< C > destination , ConstArray< D > source , size_t size ) -{ - if( size>destination.maximum()*sizeof( C ) ) - { - fprintf( stderr , "Size of copy exceeds destination maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( destination.maximum()*sizeof( C ) ) ); - ASSERT( 0 ); - exit( 0 ); - } - if( size>source.maximum()*sizeof( D ) ) - { - fprintf( stderr , "Size of copy exceeds source maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( source.maximum()*sizeof( D ) ) ); - ASSERT( 0 ); - exit( 0 ); - } - if( size ) memcpy( &destination[0] , &source[0] , size ); - return destination; -} -template< class D > -void* memcpy( void* destination , Array< D > source , size_t size ) -{ - if( size>source.maximum()*sizeof( D ) ) - { - fprintf( stderr , "Size of copy exceeds source maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( source.maximum()*sizeof( D ) ) ); - ASSERT( 0 ); - exit( 0 ); - } - if( size ) memcpy( destination , &source[0] , size ); - return destination; -} -template< class D > -void* memcpy( void* destination , ConstArray< D > source , size_t size ) -{ - if( size>source.maximum()*sizeof( D ) ) - { - fprintf( stderr , "Size of copy exceeds source maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( source.maximum()*sizeof( D ) ) ); - ASSERT( 0 ); - exit( 0 ); - } - if( size ) memcpy( destination , &source[0] , size ); - return destination; -} -template< class C > -Array< C > memset( Array< C > destination , int value , size_t size ) -{ - if( size>destination.maximum()*sizeof( C ) ) - { - fprintf( stderr , "Size of set exceeds destination maximum: %lld > %lld\n" , ( long long )( size ) , ( long long )( destination.maximum()*sizeof( C ) ) ); - ASSERT( 0 ); - exit( 0 ); - } - if( size ) memset( &destination[0] , value , size ); - return destination; -} - -template< class C > -size_t fread( Array< C > destination , size_t eSize , size_t count , FILE* fp ) -{ - if( count*eSize>destination.maximum()*sizeof( C ) ) - { - fprintf( stderr , "Size of read exceeds source maximum: %lld > %lld\n" , ( long long )( count*eSize ) , ( long long )( destination.maximum()*sizeof( C ) ) ); - ASSERT( 0 ); - exit( 0 ); - } - return fread( &destination[0] , eSize , count , fp ); -} -template< class C > -size_t fwrite( Array< C > source , size_t eSize , size_t count , FILE* fp ) -{ - if( count*eSize>source.maximum()*sizeof( C ) ) - { - fprintf( stderr , "Size of write exceeds source maximum: %lld > %lld\n" , ( long long )( count*eSize ) , ( long long )( source.maximum()*sizeof( C ) ) ); - ASSERT( 0 ); - exit( 0 ); - } - return fwrite( &source[0] , eSize , count , fp ); -} -template< class C > -size_t fwrite( ConstArray< C > source , size_t eSize , size_t count , FILE* fp ) -{ - if( count*eSize>source.maximum()*sizeof( C ) ) - { - fprintf( stderr , "Size of write exceeds source maximum: %lld > %lld\n" , ( long long )( count*eSize ) , ( long long )( source.maximum()*sizeof( C ) ) ); - ASSERT( 0 ); - exit( 0 ); - } - return fwrite( &source[0] , eSize , count , fp ); -} -template< class C > -void qsort( Array< C > base , size_t numElements , size_t elementSize , int (*compareFunction)( const void* , const void* ) ) -{ - if( sizeof(C)!=elementSize ) - { - fprintf( stderr , "Element sizes differ: %lld != %lld\n" , ( long long )( sizeof(C) ) , ( long long )( elementSize ) ); - ASSERT( 0 ); - exit( 0 ); - } - if( base.minimum()>0 || base.maximum() static inline Real Width( int depth ){ return Real(1.0/(1< static inline void CenterAndWidth( int depth , int offset , Real& center , Real& width ){ width = Real (1.0/(1< static inline void CornerAndWidth( int depth , int offset , Real& corner , Real& width ){ width = Real(1.0/(1< static inline void CenterAndWidth( int idx , Real& center , Real& width ) - { - int depth , offset; - CenterDepthAndOffset( idx , depth , offset ); - CenterAndWidth( depth , offset , center , width ); - } - template< class Real > static inline void CornerAndWidth( int idx , Real& corner , Real& width ) - { - int depth , offset; - CornerDepthAndOffset( idx , depth , offset ); - CornerAndWidth( depth , offset , corner , width ); - } - static inline void CenterDepthAndOffset( int idx , int& depth , int& offset ) - { - offset = idx , depth = 0; - while( offset>=(1<=( (1< -#include -#include -#include -#include "CmdLineParser.h" - - -#ifdef WIN32 -int strcasecmp(char* c1,char* c2){return _stricmp(c1,c2);} -#endif - -cmdLineReadable::cmdLineReadable(const char* name) -{ - set=false; - this->name=new char[strlen(name)+1]; - strcpy(this->name,name); -} -cmdLineReadable::~cmdLineReadable(void) -{ - if(name) delete[] name; - name=NULL; -} -int cmdLineReadable::read(char**,int){ - set=true; - return 0; -} -void cmdLineReadable::writeValue(char* str) -{ - str[0] = 0; -} - -//////////////// -// cmdLineInt // -//////////////// -cmdLineInt::cmdLineInt(const char* name) : cmdLineReadable(name) {value=0;} -cmdLineInt::cmdLineInt(const char* name,const int& v) : cmdLineReadable(name) {value=v;} -int cmdLineInt::read(char** argv,int argc){ - if(argc>0){ - value=atoi(argv[0]); - set=true; - return 1; - } - else{return 0;} -} -void cmdLineInt::writeValue(char* str) -{ - sprintf(str,"%d",value); -} - -////////////////// -// cmdLineFloat // -////////////////// -cmdLineFloat::cmdLineFloat(const char* name) : cmdLineReadable(name) {value=0;} -cmdLineFloat::cmdLineFloat(const char* name, const float& v) : cmdLineReadable(name) {value=v;} -int cmdLineFloat::read(char** argv,int argc){ - if(argc>0){ - value=(float)atof(argv[0]); - set=true; - return 1; - } - else{return 0;} -} -void cmdLineFloat::writeValue(char* str) -{ - sprintf(str,"%f",value); -} - -/////////////////// -// cmdLineString // -/////////////////// -cmdLineString::cmdLineString(const char* name) : cmdLineReadable(name) {value=NULL;} -cmdLineString::~cmdLineString(void) -{ - if(value) delete[] value; - value=NULL; -} -int cmdLineString::read(char** argv,int argc){ - if(argc>0) - { - value=new char[strlen(argv[0])+1]; - strcpy(value,argv[0]); - set=true; - return 1; - } - else{return 0;} -} -void cmdLineString::writeValue(char* str) -{ - sprintf(str,"%s",value); -} - -//////////////////// -// cmdLineStrings // -//////////////////// -cmdLineStrings::cmdLineStrings(const char* name,int Dim) : cmdLineReadable(name) -{ - this->Dim=Dim; - values=new char*[Dim]; - for(int i=0;i=Dim) - { - for(int i=0;i 0) - { - if (argv[0][0] == '-' && argv[0][1]=='-') - { - for(i=0;iname)) - { - argv++, argc--; - j=readable[i]->read(argv,argc); - argv+=j,argc-=j; - break; - } - } - if(i==num){ - if(dumpError) - { - fprintf(stderr, "invalid option: %s\n",*argv); - fprintf(stderr, "possible options are:\n"); - for(i=0;iname); - } - argv++, argc--; - } - } - else - { - if(dumpError) - { - fprintf(stderr, "invalid option: %s\n", *argv); - fprintf(stderr, " options must start with a \'--\'\n"); - } - argv++, argc--; - } - } -} -char** ReadWords(const char* fileName,int& cnt) -{ - char** names; - char temp[500]; - FILE* fp; - - fp=fopen(fileName,"r"); - if(!fp){return NULL;} - cnt=0; - while(fscanf(fp," %s ",temp)==1){cnt++;} - fclose(fp); - - names=new char*[cnt]; - if(!names){return NULL;} - - fp=fopen(fileName,"r"); - if(!fp){ - delete[] names; - cnt=0; - return NULL; - } - cnt=0; - while(fscanf(fp," %s ",temp)==1){ - names[cnt]=new char[strlen(temp)+1]; - if(!names){ - for(int j=0;j -#include - - -#ifdef WIN32 -int strcasecmp(char* c1,char* c2); -#endif - -class cmdLineReadable{ -public: - bool set; - char* name; - cmdLineReadable(const char* name); - virtual ~cmdLineReadable(void); - virtual int read(char** argv,int argc); - virtual void writeValue(char* str); -}; - -class cmdLineInt : public cmdLineReadable { -public: - int value; - cmdLineInt(const char* name); - cmdLineInt(const char* name,const int& v); - int read(char** argv,int argc); - void writeValue(char* str); -}; -template -class cmdLineIntArray : public cmdLineReadable { -public: - int values[Dim]; - cmdLineIntArray(const char* name); - cmdLineIntArray(const char* name,const int v[Dim]); - int read(char** argv,int argc); - void writeValue(char* str); -}; - -class cmdLineFloat : public cmdLineReadable { -public: - float value; - cmdLineFloat(const char* name); - cmdLineFloat(const char* name,const float& f); - int read(char** argv,int argc); - void writeValue(char* str); -}; -template -class cmdLineFloatArray : public cmdLineReadable { -public: - float values[Dim]; - cmdLineFloatArray(const char* name); - cmdLineFloatArray(const char* name,const float f[Dim]); - int read(char** argv,int argc); - void writeValue(char* str); -}; -class cmdLineString : public cmdLineReadable { -public: - char* value; - cmdLineString(const char* name); - ~cmdLineString(); - int read(char** argv,int argc); - void writeValue(char* str); -}; -class cmdLineStrings : public cmdLineReadable { - int Dim; -public: - char** values; - cmdLineStrings(const char* name,int Dim); - ~cmdLineStrings(void); - int read(char** argv,int argc); - void writeValue(char* str); -}; -template -class cmdLineStringArray : public cmdLineReadable { -public: - char* values[Dim]; - cmdLineStringArray(const char* name); - ~cmdLineStringArray(); - int read(char** argv,int argc); - void writeValue(char* str); -}; - -// This reads the arguments in argc, matches them against "names" and sets -// the values of "r" appropriately. Parameters start with "--" -void cmdLineParse(int argc, char **argv,int num,cmdLineReadable** r,int dumpError=1); - -char* GetFileExtension(char* fileName); -char* GetLocalFileName(char* fileName); -char** ReadWords(const char* fileName,int& cnt); - -#include "CmdLineParser.inl" -#endif // CMD_LINE_PARSER_INCLUDED diff --git a/Src/CmdLineParser.inl b/Src/CmdLineParser.inl deleted file mode 100644 index eeded680..00000000 --- a/Src/CmdLineParser.inl +++ /dev/null @@ -1,141 +0,0 @@ -/* -*- C++ -*- -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -///////////////////// -// cmdLineIntArray // -///////////////////// -template -cmdLineIntArray::cmdLineIntArray(const char* name) : cmdLineReadable(name) -{ - for(int i=0;i -cmdLineIntArray::cmdLineIntArray(const char* name,const int v[Dim]) : cmdLineReadable(name) -{ - for(int i=0;i -int cmdLineIntArray::read(char** argv,int argc) -{ - if(argc>=Dim) - { - for(int i=0;i -void cmdLineIntArray::writeValue(char* str) -{ - char* temp=str; - for(int i=0;i -cmdLineFloatArray::cmdLineFloatArray(const char* name) : cmdLineReadable(name) -{ - for(int i=0;i -cmdLineFloatArray::cmdLineFloatArray(const char* name,const float f[Dim]) : cmdLineReadable(name) -{ - for(int i=0;i -int cmdLineFloatArray::read(char** argv,int argc) -{ - if(argc>=Dim) - { - for(int i=0;i -void cmdLineFloatArray::writeValue(char* str) -{ - char* temp=str; - for(int i=0;i -cmdLineStringArray::cmdLineStringArray(const char* name) : cmdLineReadable(name) -{ - for(int i=0;i -cmdLineStringArray::~cmdLineStringArray(void) -{ - for(int i=0;i -int cmdLineStringArray::read(char** argv,int argc) -{ - if(argc>=Dim) - { - for(int i=0;i -void cmdLineStringArray::writeValue(char* str) -{ - char* temp=str; - for(int i=0;i -#include "Factor.h" -int Factor(double a1,double a0,double roots[1][2],double EPS){ - if(fabs(a1)<=EPS){return 0;} - roots[0][0]=-a0/a1; - roots[0][1]=0; - return 1; -} -int Factor(double a2,double a1,double a0,double roots[2][2],double EPS){ - double d; - if(fabs(a2)<=EPS){return Factor(a1,a0,roots,EPS);} - - d=a1*a1-4*a0*a2; - a1/=(2*a2); - if(d<0){ - d=sqrt(-d)/(2*a2); - roots[0][0]=roots[1][0]=-a1; - roots[0][1]=-d; - roots[1][1]= d; - } - else{ - d=sqrt(d)/(2*a2); - roots[0][1]=roots[1][1]=0; - roots[0][0]=-a1-d; - roots[1][0]=-a1+d; - } - return 2; -} -// Solution taken from: http://mathworld.wolfram.com/CubicFormula.html -// and http://www.csit.fsu.edu/~burkardt/f_src/subpak/subpak.f90 -int Factor(double a3,double a2,double a1,double a0,double roots[3][2],double EPS){ - double q,r,r2,q3; - - if(fabs(a3)<=EPS){return Factor(a2,a1,a0,roots,EPS);} - a2/=a3; - a1/=a3; - a0/=a3; - - q=-(3*a1-a2*a2)/9; - r=-(9*a2*a1-27*a0-2*a2*a2*a2)/54; - r2=r*r; - q3=q*q*q; - - if(r20){return PI/2.0;} - else{return -PI/2.0;} - } - if(x>=0){return atan(y/x);} - else{ - if(y>=0){return atan(y/x)+PI;} - else{return atan(y/x)-PI;} - } -} -double Angle(const double in[2]){ - if((in[0]*in[0]+in[1]*in[1])==0.0){return 0;} - else{return ArcTan2(in[1],in[0]);} -} -void Sqrt(const double in[2],double out[2]){ - double r=sqrt(sqrt(in[0]*in[0]+in[1]*in[1])); - double a=Angle(in)*0.5; - out[0]=r*cos(a); - out[1]=r*sin(a); -} -void Add(const double in1[2],const double in2[2],double out[2]){ - out[0]=in1[0]+in2[0]; - out[1]=in1[1]+in2[1]; -} -void Subtract(const double in1[2],const double in2[2],double out[2]){ - out[0]=in1[0]-in2[0]; - out[1]=in1[1]-in2[1]; -} -void Multiply(const double in1[2],const double in2[2],double out[2]){ - out[0]=in1[0]*in2[0]-in1[1]*in2[1]; - out[1]=in1[0]*in2[1]+in1[1]*in2[0]; -} -void Divide(const double in1[2],const double in2[2],double out[2]){ - double temp[2]; - double l=in2[0]*in2[0]+in2[1]*in2[1]; - temp[0]= in2[0]/l; - temp[1]=-in2[1]/l; - Multiply(in1,temp,out); -} -// Solution taken from: http://mathworld.wolfram.com/QuarticEquation.html -// and http://www.csit.fsu.edu/~burkardt/f_src/subpak/subpak.f90 -int Factor(double a4,double a3,double a2,double a1,double a0,double roots[4][2],double EPS){ - double R[2],D[2],E[2],R2[2]; - - if(fabs(a4)10e-8){ - double temp1[2],temp2[2]; - double p1[2],p2[2]; - - p1[0]=a3*a3*0.75-2.0*a2-R2[0]; - p1[1]=0; - - temp2[0]=((4.0*a3*a2-8.0*a1-a3*a3*a3)/4.0); - temp2[1]=0; - Divide(temp2,R,p2); - - Add (p1,p2,temp1); - Subtract(p1,p2,temp2); - - Sqrt(temp1,D); - Sqrt(temp2,E); - } - else{ - R[0]=R[1]=0; - double temp1[2],temp2[2]; - temp1[0]=roots[0][0]*roots[0][0]-4.0*a0; - temp1[1]=0; - Sqrt(temp1,temp2); - temp1[0]=a3*a3*0.75-2.0*a2+2.0*temp2[0]; - temp1[1]= 2.0*temp2[1]; - Sqrt(temp1,D); - temp1[0]=a3*a3*0.75-2.0*a2-2.0*temp2[0]; - temp1[1]= -2.0*temp2[1]; - Sqrt(temp1,E); - } - - roots[0][0]=-a3/4.0+R[0]/2.0+D[0]/2.0; - roots[0][1]= R[1]/2.0+D[1]/2.0; - - roots[1][0]=-a3/4.0+R[0]/2.0-D[0]/2.0; - roots[1][1]= R[1]/2.0-D[1]/2.0; - - roots[2][0]=-a3/4.0-R[0]/2.0+E[0]/2.0; - roots[2][1]= -R[1]/2.0+E[1]/2.0; - - roots[3][0]=-a3/4.0-R[0]/2.0-E[0]/2.0; - roots[3][1]= -R[1]/2.0-E[1]/2.0; - return 4; -} - -int Solve(const double* eqns,const double* values,double* solutions,int dim){ - int i,j,eIndex; - double v,m; - int *index=new int[dim]; - int *set=new int[dim]; - double* myEqns=new double[dim*dim]; - double* myValues=new double[dim]; - - for(i=0;im){ - m=fabs(myEqns[j*dim+i]); - eIndex=j; - } - } - if(eIndex==-1){ - delete[] index; - delete[] myValues; - delete[] myEqns; - delete[] set; - return 0; - } - // The position in which the solution for the i-th variable can be found - index[i]=eIndex; - set[eIndex]=1; - - // Normalize the equation - v=myEqns[eIndex*dim+i]; - for(j=0;j -class FunctionData{ - bool useDotRatios; - int normalize; -#if BOUNDARY_CONDITIONS - bool reflectBoundary; -#endif // BOUNDARY_CONDITIONS -public: - const static int DOT_FLAG = 1; - const static int D_DOT_FLAG = 2; - const static int D2_DOT_FLAG = 4; - const static int VALUE_FLAG = 1; - const static int D_VALUE_FLAG = 2; - - int depth , res , res2; - Real *dotTable , *dDotTable , *d2DotTable; - Real *valueTables , *dValueTables; -#if BOUNDARY_CONDITIONS - PPolynomial baseFunction , leftBaseFunction , rightBaseFunction; - PPolynomial dBaseFunction , dLeftBaseFunction , dRightBaseFunction; -#else // !BOUNDARY_CONDITIONS - PPolynomial baseFunction; - PPolynomial dBaseFunction; -#endif // BOUNDARY_CONDITIONS - PPolynomial* baseFunctions; - - FunctionData(void); - ~FunctionData(void); - - virtual void setDotTables(const int& flags); - virtual void clearDotTables(const int& flags); - - virtual void setValueTables(const int& flags,const double& smooth=0); - virtual void setValueTables(const int& flags,const double& valueSmooth,const double& normalSmooth); - virtual void clearValueTables(void); - - /******************************************************** - * Sets the translates and scales of the basis function - * up to the prescribed depth - * the maximum depth - * the basis function - * how the functions should be scaled - * 0] Value at zero equals 1 - * 1] Integral equals 1 - * 2] L2-norm equals 1 - * specifies if dot-products of derivatives - * should be pre-divided by function integrals - * 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/Geometry.cpp b/Src/Geometry.cpp deleted file mode 100644 index e6d03d88..00000000 --- a/Src/Geometry.cpp +++ /dev/null @@ -1,123 +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 "Geometry.h" -#include -#include -#ifdef _WIN32 -#include -#endif // _WIN32 - -/////////////////// -// CoredMeshData // -/////////////////// - -TriangulationEdge::TriangulationEdge(void){pIndex[0]=pIndex[1]=tIndex[0]=tIndex[1]=-1;} -TriangulationTriangle::TriangulationTriangle(void){eIndex[0]=eIndex[1]=eIndex[2]=-1;} - -/////////////////////////// -// BufferedReadWriteFile // -/////////////////////////// -BufferedReadWriteFile::BufferedReadWriteFile( const char* fileName , const char* fileHeader , int bufferSize ) -{ - _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 ) fprintf( stderr , "[ERROR] Failed to open file: %s\n" , _fileName ) , exit( 0 ); - _buffer = (char*) malloc( _bufferSize ); -} -BufferedReadWriteFile::~BufferedReadWriteFile( void ) -{ - free( _buffer ); - fclose( _fp ); - if( tempFile ) remove( _fileName ); -} -void BufferedReadWriteFile::reset( void ) -{ - if( _bufferIndex ) fwrite( _buffer , 1 , _bufferIndex , _fp ); - _bufferIndex = 0; - fseek( _fp , 0 , SEEK_SET ); - _bufferIndex = 0; - _bufferSize = fread( _buffer , 1 , _bufferSize , _fp ); -} -bool BufferedReadWriteFile::write( const void* data , size_t size ) -{ - if( !size ) return true; - char* _data = (char*) data; - size_t sz = _bufferSize - _bufferIndex; - while( sz<=size ) - { - memcpy( _buffer+_bufferIndex , _data , sz ); - fwrite( _buffer , 1 , _bufferSize , _fp ); - _data += sz; - size -= sz; - _bufferIndex = 0; - sz = _bufferSize; - } - if( size ) - { - memcpy( _buffer+_bufferIndex , _data , size ); - _bufferIndex += size; - } - return true; -} -bool BufferedReadWriteFile::read( void* data , size_t size ) -{ - if( !size ) return true; - char *_data = (char*) data; - size_t sz = _bufferSize - _bufferIndex; - while( sz<=size ) - { - if( size && !_bufferSize ) return false; - memcpy( _data , _buffer+_bufferIndex , sz ); - _bufferSize = fread( _buffer , 1 , _bufferSize , _fp ); - _data += sz; - size -= sz; - _bufferIndex = 0; - if( !size ) return true; - sz = _bufferSize; - } - if( size ) - { - if( !_bufferSize ) return false; - memcpy( _data , _buffer+_bufferIndex , size ); - _bufferIndex += size; - } - return true; -} \ No newline at end of file diff --git a/Src/Geometry.h b/Src/Geometry.h deleted file mode 100644 index ea8c951c..00000000 --- a/Src/Geometry.h +++ /dev/null @@ -1,414 +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 GEOMETRY_INCLUDED -#define GEOMETRY_INCLUDED - -#include -#include -#include -#include -#include - -template -Real Random(void); - -template< class Real > -struct Point3D -{ - Real coords[3]; - Point3D( void ) { coords[0] = coords[1] = coords[2] = Real(0); } - Point3D( Real v ) { coords[0] = coords[1] = coords[2] = v; } - template< class _Real > Point3D( _Real v0 , _Real v1 , _Real v2 ){ coords[0] = Real(v0) , coords[1] = Real(v1) , coords[2] = Real(v2); } - template< class _Real > Point3D( const Point3D< _Real >& p ){ coords[0] = Real( p[0] ) , coords[1] = Real( p[1] ) , coords[2] = Real( p[2] ); } - inline Real& operator[] ( int i ) { return coords[i]; } - inline const Real& operator[] ( int i ) const { return coords[i]; } - inline Point3D operator - ( void ) const { Point3D q ; q.coords[0] = -coords[0] , q.coords[1] = -coords[1] , q.coords[2] = -coords[2] ; return q; } - - template< class _Real > inline Point3D& operator += ( Point3D< _Real > p ){ coords[0] += Real(p.coords[0]) , coords[1] += Real(p.coords[1]) , coords[2] += Real(p.coords[2]) ; return *this; } - template< class _Real > inline Point3D operator + ( Point3D< _Real > p ) const { Point3D q ; q.coords[0] = coords[0] + Real(p.coords[0]) , q.coords[1] = coords[1] + Real(p.coords[1]) , q.coords[2] = coords[2] + Real(p.coords[2]) ; return q; } - template< class _Real > inline Point3D& operator *= ( _Real r ) { coords[0] *= Real(r) , coords[1] *= Real(r) , coords[2] *= Real(r) ; return *this; } - template< class _Real > inline Point3D operator * ( _Real r ) const { Point3D q ; q.coords[0] = coords[0] * Real(r) , q.coords[1] = coords[1] * Real(r) , q.coords[2] = coords[2] * Real(r) ; return q; } - - template< class _Real > inline Point3D& operator -= ( Point3D< _Real > p ){ return ( (*this)+=(-p) ); } - template< class _Real > inline Point3D operator - ( Point3D< _Real > p ) const { return (*this)+(-p); } - template< class _Real > inline Point3D& operator /= ( _Real r ){ return ( (*this)*=Real(1./r) ); } - template< class _Real > inline Point3D operator / ( _Real r ) const { return (*this) * ( Real(1.)/r ); } - - static Real Dot( const Point3D< Real >& p1 , const Point3D< Real >& p2 ){ return p1.coords[0]*p2.coords[0] + p1.coords[1]*p2.coords[1] + p1.coords[2]*p2.coords[2]; } - template< class Real1 , class Real2 > - static Real Dot( const Point3D< Real1 >& p1 , const Point3D< Real2 >& p2 ){ return Real( p1.coords[0]*p2.coords[0] + p1.coords[1]*p2.coords[1] + p1.coords[2]*p2.coords[2] ); } -}; - -template< class Real > -struct XForm3x3 -{ - Real coords[3][3]; - XForm3x3( void ) { for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) coords[i][j] = Real(0.); } - static XForm3x3 Identity( void ) - { - XForm3x3 xForm; - xForm(0,0) = xForm(1,1) = xForm(2,2) = Real(1.); - return xForm; - } - Real& operator() ( int i , int j ){ return coords[i][j]; } - const Real& operator() ( int i , int j ) const { return coords[i][j]; } - template< class _Real > Point3D< _Real > operator * ( const Point3D< _Real >& p ) const - { - Point3D< _Real > q; - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) q[i] += _Real( coords[j][i] * p[j] ); - return q; - } - XForm3x3 operator * ( const XForm3x3& m ) const - { - XForm3x3 n; - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) n.coords[i][j] += m.coords[i][k]*coords[k][j]; - return n; - } - XForm3x3 transpose( void ) const - { - XForm3x3 xForm; - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) xForm( i , j ) = coords[j][i]; - return xForm; - } - Real subDeterminant( int i , int j ) const - { - int i1 = (i+1)%3 , i2 = (i+2)%3; - int j1 = (j+1)%3 , j2 = (j+2)%3; - return coords[i1][j1] * coords[i2][j2] - coords[i1][j2] * coords[i2][j1]; - } - Real determinant( void ) const { return coords[0][0] * subDeterminant( 0 , 0 ) + coords[1][0] * subDeterminant( 1 , 0 ) + coords[2][0] * subDeterminant( 2 , 0 ); } - XForm3x3 inverse( void ) const - { - XForm3x3 xForm; - Real d = determinant(); - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ;j++ ) xForm.coords[j][i] = subDeterminant( i , j ) / d; - return xForm; - } -}; - -template< class Real > -struct XForm4x4 -{ - Real coords[4][4]; - XForm4x4( void ) { for( int i=0 ; i<4 ; i++ ) for( int j=0 ; j<4 ; j++ ) coords[i][j] = Real(0.); } - static XForm4x4 Identity( void ) - { - XForm4x4 xForm; - xForm(0,0) = xForm(1,1) = xForm(2,2) = xForm(3,3) = Real(1.); - return xForm; - } - Real& operator() ( int i , int j ){ return coords[i][j]; } - const Real& operator() ( int i , int j ) const { return coords[i][j]; } - template< class _Real > Point3D< _Real > operator * ( const Point3D< _Real >& p ) const - { - Point3D< _Real > q; - for( int i=0 ; i<3 ; i++ ) - { - for( int j=0 ; j<3 ; j++ ) q[i] += (_Real)( coords[j][i] * p[j] ); - q[i] += (_Real)coords[3][i]; - } - return q; - } - XForm4x4 operator * ( const XForm4x4& m ) const - { - XForm4x4 n; - for( int i=0 ; i<4 ; i++ ) for( int j=0 ; j<4 ; j++ ) for( int k=0 ; k<4 ; k++ ) n.coords[i][j] += m.coords[i][k]*coords[k][j]; - return n; - } - XForm4x4 transpose( void ) const - { - XForm4x4 xForm; - for( int i=0 ; i<4 ; i++ ) for( int j=0 ; j<4 ; j++ ) xForm( i , j ) = coords[j][i]; - return xForm; - } - Real subDeterminant( int i , int j ) const - { - XForm3x3< Real > xForm; - int ii[] = { (i+1)%4 , (i+2)%4 , (i+3)%4 } , jj[] = { (j+1)%4 , (j+2)%4 , (j+3)%4 }; - for( int _i=0 ; _i<3 ; _i++ ) for( int _j=0 ; _j<3 ; _j++ ) xForm( _i , _j ) = coords[ ii[_i] ][ jj[_j] ]; - return xForm.determinant(); - } - Real determinant( void ) const { return coords[0][0] * subDeterminant( 0 , 0 ) - coords[1][0] * subDeterminant( 1 , 0 ) + coords[2][0] * subDeterminant( 2 , 0 ) - coords[3][0] * subDeterminant( 3 , 0 ); } - XForm4x4 inverse( void ) const - { - XForm4x4 xForm; - Real d = determinant(); - for( int i=0 ; i<4 ; i++ ) for( int j=0 ; j<4 ;j++ ) - if( (i+j)%2==0 ) xForm.coords[j][i] = subDeterminant( i , j ) / d; - else xForm.coords[j][i] = -subDeterminant( i , j ) / d; - return xForm; - } -}; - -template< class Real > -struct OrientedPoint3D -{ - Point3D< Real > p , n; - OrientedPoint3D( Point3D< Real > pp=Point3D< Real >() , Point3D< Real > nn=Point3D< Real >() ) : p(pp) , n(nn) { ; } - template< class _Real > OrientedPoint3D( const OrientedPoint3D< _Real >& p ) : OrientedPoint3D( Point3D< Real >( p.p ) , Point3D< Real >( p.n ) ){ ; } - - template< class _Real > inline OrientedPoint3D& operator += ( OrientedPoint3D< _Real > _p ){ p += _p.p , n += _p.n ; return *this; } - template< class _Real > inline OrientedPoint3D operator + ( OrientedPoint3D< _Real > _p ) const { return OrientedPoint3D< Real >( p+_p.p , n+_p.n ); } - template< class _Real > inline OrientedPoint3D& operator *= ( _Real r ) { p *= r , n *= r ; return *this; } - template< class _Real > inline OrientedPoint3D operator * ( _Real r ) const { return OrientedPoint3D< Real >( p*r , n*r ); } - - template< class _Real > inline OrientedPoint3D& operator -= ( OrientedPoint3D< _Real > p ){ return ( (*this)+=(-p) ); } - template< class _Real > inline OrientedPoint3D operator - ( OrientedPoint3D< _Real > p ) const { return (*this)+(-p); } - template< class _Real > inline OrientedPoint3D& operator /= ( _Real r ){ return ( (*this)*=Real(1./r) ); } - template< class _Real > inline OrientedPoint3D operator / ( _Real r ) const { return (*this) * ( Real(1.)/r ); } -}; - -template< class Data , class Real > -struct ProjectiveData -{ - Data data; - Real weight; - ProjectiveData( Data d=Data(0) , Real w=Real(0) ) : data(d) , weight(w) { ; } - operator Data (){ return weight!=0 ? data/weight : data*weight; } - ProjectiveData& operator += ( const ProjectiveData& p ){ data += p.data , weight += p.weight ; return *this; } - ProjectiveData& operator -= ( const ProjectiveData& p ){ data -= p.data , weight -= p.weight ; return *this; } - ProjectiveData& operator *= ( Real s ){ data *= s , weight *= s ; return *this; } - ProjectiveData& operator /= ( Real s ){ data /= s , weight /= s ; return *this; } - ProjectiveData operator + ( const ProjectiveData& p ) const { return ProjectiveData( data+p.data , weight+p.weight ); } - ProjectiveData operator - ( const ProjectiveData& p ) const { return ProjectiveData( data-p.data , weight-p.weight ); } - ProjectiveData operator * ( Real s ) const { return ProjectiveData( data*s , weight*s ); } - ProjectiveData operator / ( Real s ) const { return ProjectiveData( data/s , weight/s ); } -}; - -template -Point3D RandomBallPoint(void); - -template -Point3D RandomSpherePoint(void); - -template -double Length(const Point3D& p); - -template -double SquareLength(const Point3D& p); - -template -double Distance(const Point3D& p1,const Point3D& p2); - -template -double SquareDistance(const Point3D& p1,const Point3D& p2); - -template -void CrossProduct(const Point3D& p1,const Point3D& p2,Point3D& p); - - -class Edge{ -public: - double p[2][2]; - double Length(void) const{ - double d[2]; - d[0]=p[0][0]-p[1][0]; - d[1]=p[0][1]-p[1][1]; - - return sqrt(d[0]*d[0]+d[1]*d[1]); - } -}; -class Triangle{ -public: - double p[3][3]; - double Area(void) const{ - double v1[3] , v2[3] , v[3]; - for( int d=0 ; d<3 ; d++ ) - { - v1[d] = p[1][d] - p[0][d]; - v2[d] = p[2][d] - p[0][d]; - } - v[0] = v1[1]*v2[2] - v1[2]*v2[1]; - v[1] = -v1[0]*v2[2] + v1[2]*v2[0]; - v[2] = v1[0]*v2[1] - v1[1]*v2[0]; - return sqrt( v[0]*v[0] + v[1]*v[1] + v[2]*v[2] ) / 2; - } - double AspectRatio(void) const{ - double d=0; - int i,j; - for(i=0;i<3;i++){ - for(i=0;i<3;i++) - for(j=0;j<3;j++){d+=(p[(i+1)%3][j]-p[i][j])*(p[(i+1)%3][j]-p[i][j]);} - } - return Area()/d; - } - -}; -class CoredPointIndex -{ -public: - int index; - char inCore; - - int operator == (const CoredPointIndex& cpi) const {return (index==cpi.index) && (inCore==cpi.inCore);}; - int operator != (const CoredPointIndex& cpi) const {return (index!=cpi.index) || (inCore!=cpi.inCore);}; -}; -class EdgeIndex{ -public: - int idx[2]; -}; -class CoredEdgeIndex -{ -public: - CoredPointIndex idx[2]; -}; -class TriangleIndex{ -public: - int idx[3]; -}; - -class TriangulationEdge -{ -public: - TriangulationEdge(void); - int pIndex[2]; - int tIndex[2]; -}; - -class TriangulationTriangle -{ -public: - TriangulationTriangle(void); - int eIndex[3]; -}; - -template -class Triangulation -{ -public: - - std::vector > points; - std::vector edges; - std::vector triangles; - - int factor( int tIndex,int& p1,int& p2,int& p3); - double area(void); - double area( int tIndex ); - double area( int p1 , int p2 , int p3 ); - int flipMinimize( int eIndex); - int addTriangle( int p1 , int p2 , int p3 ); - -protected: - std::unordered_map edgeMap; - static long long EdgeIndex( int p1 , int p2 ); - double area(const Triangle& t); -}; - - -template -void EdgeCollapse(const Real& edgeRatio,std::vector& triangles,std::vector< Point3D >& positions,std::vector >* normals); -template -void TriangleCollapse(const Real& edgeRatio,std::vector& triangles,std::vector >& positions,std::vector >* normals); - -struct CoredVertexIndex -{ - int idx; - bool inCore; -}; -template< class Vertex > -class CoredMeshData -{ -public: - std::vector< Vertex > inCorePoints; - virtual void resetIterator( void ) = 0; - - virtual int addOutOfCorePoint( const Vertex& p ) = 0; - virtual int addOutOfCorePoint_s( const Vertex& p ) = 0; - virtual int addPolygon_s( const std::vector< CoredVertexIndex >& vertices ) = 0; - virtual int addPolygon_s( const std::vector< int >& vertices ) = 0; - - virtual int nextOutOfCorePoint( Vertex& p )=0; - virtual int nextPolygon( std::vector< CoredVertexIndex >& vertices ) = 0; - - virtual int outOfCorePointCount(void)=0; - virtual int polygonCount( void ) = 0; -}; - -template< class Vertex > -class CoredVectorMeshData : public CoredMeshData< Vertex > -{ - std::vector< Vertex > oocPoints; - std::vector< std::vector< int > > polygons; - int polygonIndex; - int oocPointIndex; -public: - CoredVectorMeshData(void); - - void resetIterator(void); - - int addOutOfCorePoint( const Vertex& p ); - int addOutOfCorePoint_s( const Vertex& p ); - int addPolygon_s( const std::vector< CoredVertexIndex >& vertices ); - int addPolygon_s( const std::vector< int >& vertices ); - - int nextOutOfCorePoint( Vertex& p ); - int nextPolygon( std::vector< CoredVertexIndex >& vertices ); - - int outOfCorePointCount(void); - int polygonCount( void ); -}; -class BufferedReadWriteFile -{ - bool tempFile; - FILE* _fp; - char *_buffer , _fileName[1024]; - size_t _bufferIndex , _bufferSize; -public: - BufferedReadWriteFile( const char* fileName=NULL , const char* fileHeader="" , int bufferSize=(1<<20) ); - ~BufferedReadWriteFile( void ); - bool write( const void* data , size_t size ); - bool read ( void* data , size_t size ); - void reset( void ); -}; -template< class Vertex > -class CoredFileMeshData : public CoredMeshData< Vertex > -{ - char pointFileName[1024] , polygonFileName[1024]; - BufferedReadWriteFile *oocPointFile , *polygonFile; - int oocPoints , polygons; -public: - CoredFileMeshData( const char* fileHeader="" ); - ~CoredFileMeshData( void ); - - void resetIterator( void ); - - int addOutOfCorePoint( const Vertex& p ); - int addOutOfCorePoint_s( const Vertex& p ); - int addPolygon_s( const std::vector< CoredVertexIndex >& vertices ); - int addPolygon_s( const std::vector< int >& vertices ); - - int nextOutOfCorePoint( Vertex& p ); - int nextPolygon( std::vector< CoredVertexIndex >& vertices ); - - int outOfCorePointCount( void ); - int polygonCount( void ); -}; -#include "Geometry.inl" - -#endif // GEOMETRY_INCLUDED diff --git a/Src/Geometry.inl b/Src/Geometry.inl deleted file mode 100644 index ad2be93b..00000000 --- a/Src/Geometry.inl +++ /dev/null @@ -1,591 +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 - -template -Real Random(void){return Real(rand())/RAND_MAX;} - -template -Point3D RandomBallPoint(void){ - Point3D p; - while(1){ - p.coords[0]=Real(1.0-2.0*Random()); - p.coords[1]=Real(1.0-2.0*Random()); - p.coords[2]=Real(1.0-2.0*Random()); - double l=SquareLength(p); - if(l<=1){return p;} - } -} -template -Point3D RandomSpherePoint(void){ - Point3D p=RandomBallPoint(); - Real l=Real(Length(p)); - p.coords[0]/=l; - p.coords[1]/=l; - p.coords[2]/=l; - return p; -} - -template -double SquareLength(const Point3D& p){return p.coords[0]*p.coords[0]+p.coords[1]*p.coords[1]+p.coords[2]*p.coords[2];} - -template -double Length(const Point3D& p){return sqrt(SquareLength(p));} - -template -double SquareDistance(const Point3D& p1,const Point3D& p2){ - return (p1.coords[0]-p2.coords[0])*(p1.coords[0]-p2.coords[0])+(p1.coords[1]-p2.coords[1])*(p1.coords[1]-p2.coords[1])+(p1.coords[2]-p2.coords[2])*(p1.coords[2]-p2.coords[2]); -} - -template -double Distance(const Point3D& p1,const Point3D& p2){return sqrt(SquareDistance(p1,p2));} - -template -void CrossProduct(const Point3D& p1,const Point3D& p2,Point3D& p){ - p.coords[0]= p1.coords[1]*p2.coords[2]-p1.coords[2]*p2.coords[1]; - p.coords[1]=-p1.coords[0]*p2.coords[2]+p1.coords[2]*p2.coords[0]; - p.coords[2]= p1.coords[0]*p2.coords[1]-p1.coords[1]*p2.coords[0]; -} -template -void EdgeCollapse(const Real& edgeRatio,std::vector& triangles,std::vector< Point3D >& positions,std::vector< Point3D >* normals){ - int i,j,*remapTable,*pointCount,idx[3]; - Point3D p[3],q[2],c; - double d[3],a; - double Ratio=12.0/sqrt(3.0); // (Sum of Squares Length / Area) for and equilateral triangle - - remapTable=new int[positions.size()]; - pointCount=new int[positions.size()]; - for(i=0;i=0;i--){ - for(j=0;j<3;j++){ - idx[j]=triangles[i].idx[j]; - while(remapTable[idx[j]] a*Ratio){ - // Find the smallest edge - j=0; - if(d[1]=0;i--){ - for(j=0;j<3;j++){ - idx[j]=triangles[i].idx[j]; - while(remapTable[idx[j]] -void TriangleCollapse(const Real& edgeRatio,std::vector& triangles,std::vector< Point3D >& positions,std::vector< Point3D >* normals){ - int i,j,*remapTable,*pointCount,idx[3]; - Point3D p[3],q[2],c; - double d[3],a; - double Ratio=12.0/sqrt(3.0); // (Sum of Squares Length / Area) for and equilateral triangle - - remapTable=new int[positions.size()]; - pointCount=new int[positions.size()]; - for(i=0;i=0;i--){ - for(j=0;j<3;j++){ - idx[j]=triangles[i].idx[j]; - while(remapTable[idx[j]] a*Ratio){ - // Find the smallest edge - j=0; - if(d[1]=0;i--){ - for(j=0;j<3;j++){ - idx[j]=triangles[i].idx[j]; - while(remapTable[idx[j]] -long long Triangulation::EdgeIndex( int p1 , int p2 ) -{ - if(p1>p2) {return ((long long)(p1)<<32) | ((long long)(p2));} - else {return ((long long)(p2)<<32) | ((long long)(p1));} -} - -template -int Triangulation::factor(int tIndex,int& p1,int& p2,int & p3){ - if(triangles[tIndex].eIndex[0]<0 || triangles[tIndex].eIndex[1]<0 || triangles[tIndex].eIndex[2]<0){return 0;} - if(edges[triangles[tIndex].eIndex[0]].tIndex[0]==tIndex){p1=edges[triangles[tIndex].eIndex[0]].pIndex[0];} - else {p1=edges[triangles[tIndex].eIndex[0]].pIndex[1];} - if(edges[triangles[tIndex].eIndex[1]].tIndex[0]==tIndex){p2=edges[triangles[tIndex].eIndex[1]].pIndex[0];} - else {p2=edges[triangles[tIndex].eIndex[1]].pIndex[1];} - if(edges[triangles[tIndex].eIndex[2]].tIndex[0]==tIndex){p3=edges[triangles[tIndex].eIndex[2]].pIndex[0];} - else {p3=edges[triangles[tIndex].eIndex[2]].pIndex[1];} - return 1; -} -template -double Triangulation::area(int p1,int p2,int p3){ - Point3D q1,q2,q; - for(int i=0;i<3;i++){ - q1.coords[i]=points[p2].coords[i]-points[p1].coords[i]; - q2.coords[i]=points[p3].coords[i]-points[p1].coords[i]; - } - CrossProduct(q1,q2,q); - return Length(q); -} -template -double Triangulation::area(int tIndex){ - int p1,p2,p3; - factor(tIndex,p1,p2,p3); - return area(p1,p2,p3); -} -template -double Triangulation::area(void){ - double a=0; - for(int i=0;i -int Triangulation::addTriangle(int p1,int p2,int p3) -{ - std::unordered_map::iterator iter; - int tIdx,eIdx,p[3]; - p[0]=p1; - p[1]=p2; - p[2]=p3; - triangles.push_back(TriangulationTriangle()); - tIdx=int(triangles.size())-1; - - for(int i=0;i<3;i++) - { - long long e = EdgeIndex(p[i],p[(i+1)%3]); - iter=edgeMap.find(e); - if(iter==edgeMap.end()) - { - TriangulationEdge edge; - edge.pIndex[0]=p[i]; - edge.pIndex[1]=p[(i+1)%3]; - edges.push_back(edge); - eIdx=int(edges.size())-1; - edgeMap[e]=eIdx; - edges[eIdx].tIndex[0]=tIdx; - } - else{ - eIdx=edgeMap[e]; - if(edges[eIdx].pIndex[0]==p[i]){ - if(edges[eIdx].tIndex[0]<0){edges[eIdx].tIndex[0]=tIdx;} - else{printf("Edge Triangle in use 1\n");return 0;} - } - else{ - if(edges[eIdx].tIndex[1]<0){edges[eIdx].tIndex[1]=tIdx;} - else{printf("Edge Triangle in use 2\n");return 0;} - } - - } - triangles[tIdx].eIndex[i]=eIdx; - } - return tIdx; -} -template -int Triangulation::flipMinimize(int eIndex){ - double oldArea,newArea; - int oldP[3],oldQ[3],newP[3],newQ[3]; - TriangulationEdge newEdge; - - if(edges[eIndex].tIndex[0]<0 || edges[eIndex].tIndex[1]<0){return 0;} - - if(!factor(edges[eIndex].tIndex[0],oldP[0],oldP[1],oldP[2])){return 0;} - if(!factor(edges[eIndex].tIndex[1],oldQ[0],oldQ[1],oldQ[2])){return 0;} - - oldArea=area(oldP[0],oldP[1],oldP[2])+area(oldQ[0],oldQ[1],oldQ[2]); - int idxP,idxQ; - for(idxP=0;idxP<3;idxP++){ - int i; - for(i=0;i<3;i++){if(oldP[idxP]==oldQ[i]){break;}} - if(i==3){break;} - } - for(idxQ=0;idxQ<3;idxQ++){ - int i; - for(i=0;i<3;i++){if(oldP[i]==oldQ[idxQ]){break;}} - if(i==3){break;} - } - if(idxP==3 || idxQ==3){return 0;} - newP[0]=oldP[idxP]; - newP[1]=oldP[(idxP+1)%3]; - newP[2]=oldQ[idxQ]; - newQ[0]=oldQ[idxQ]; - newQ[1]=oldP[(idxP+2)%3]; - newQ[2]=oldP[idxP]; - - newArea=area(newP[0],newP[1],newP[2])+area(newQ[0],newQ[1],newQ[2]); - if(oldArea<=newArea){return 0;} - - // Remove the entry in the hash_table for the old edge - edgeMap.erase(EdgeIndex(edges[eIndex].pIndex[0],edges[eIndex].pIndex[1])); - // Set the new edge so that the zero-side is newQ - edges[eIndex].pIndex[0]=newP[0]; - edges[eIndex].pIndex[1]=newQ[0]; - // Insert the entry into the hash_table for the new edge - edgeMap[EdgeIndex(newP[0],newQ[0])]=eIndex; - // Update the triangle information - for(int i=0;i<3;i++){ - int idx; - idx=edgeMap[EdgeIndex(newQ[i],newQ[(i+1)%3])]; - triangles[edges[eIndex].tIndex[0]].eIndex[i]=idx; - if(idx!=eIndex){ - if(edges[idx].tIndex[0]==edges[eIndex].tIndex[1]){edges[idx].tIndex[0]=edges[eIndex].tIndex[0];} - if(edges[idx].tIndex[1]==edges[eIndex].tIndex[1]){edges[idx].tIndex[1]=edges[eIndex].tIndex[0];} - } - - idx=edgeMap[EdgeIndex(newP[i],newP[(i+1)%3])]; - triangles[edges[eIndex].tIndex[1]].eIndex[i]=idx; - if(idx!=eIndex){ - if(edges[idx].tIndex[0]==edges[eIndex].tIndex[0]){edges[idx].tIndex[0]=edges[eIndex].tIndex[1];} - if(edges[idx].tIndex[1]==edges[eIndex].tIndex[0]){edges[idx].tIndex[1]=edges[eIndex].tIndex[1];} - } - } - return 1; -} -///////////////////////// -// CoredVectorMeshData // -///////////////////////// -template< class Vertex > -CoredVectorMeshData< Vertex >::CoredVectorMeshData( void ) { oocPointIndex = polygonIndex = 0; } -template< class Vertex > -void CoredVectorMeshData< Vertex >::resetIterator ( void ) { oocPointIndex = polygonIndex = 0; } -template< class Vertex > -int CoredVectorMeshData< Vertex >::addOutOfCorePoint( const Vertex& p ) -{ - oocPoints.push_back(p); - return int(oocPoints.size())-1; -} -template< class Vertex > -int CoredVectorMeshData< Vertex >::addOutOfCorePoint_s( const Vertex& p ) -{ - size_t sz; -#pragma omp critical (CoredVectorMeshData_addOutOfCorePoint_s ) - { - sz = oocPoints.size(); - oocPoints.push_back(p); - } - return (int)sz; -} -template< class Vertex > -int CoredVectorMeshData< Vertex >::addPolygon_s( const std::vector< int >& polygon ) -{ - size_t sz; -#pragma omp critical (CoredVectorMeshData_addPolygon_s) - { - sz = polygon.size(); - polygons.push_back( polygon ); - } - return (int)sz; -} -template< class Vertex > -int CoredVectorMeshData< Vertex >::addPolygon_s( const std::vector< CoredVertexIndex >& vertices ) -{ - std::vector< int > polygon( vertices.size() ); - for( int i=0 ; i<(int)vertices.size() ; i++ ) - if( vertices[i].inCore ) polygon[i] = vertices[i].idx; - else polygon[i] = -vertices[i].idx-1; - return addPolygon_s( polygon ); -} -template< class Vertex > -int CoredVectorMeshData< Vertex >::nextOutOfCorePoint( Vertex& p ) -{ - if( oocPointIndex -int CoredVectorMeshData< Vertex >::nextPolygon( std::vector< CoredVertexIndex >& vertices ) -{ - if( polygonIndex& polygon = polygons[ polygonIndex++ ]; - vertices.resize( polygon.size() ); - for( int i=0 ; i -int CoredVectorMeshData< Vertex >::outOfCorePointCount(void){return int(oocPoints.size());} -template< class Vertex > -int CoredVectorMeshData< Vertex >::polygonCount( void ) { return int( polygons.size() ); } - -/////////////////////// -// CoredFileMeshData // -/////////////////////// -template< class Vertex > -CoredFileMeshData< Vertex >::CoredFileMeshData( const char* fileHeader ) -{ - oocPoints = polygons = 0; - - oocPointFile = new BufferedReadWriteFile( NULL , fileHeader ); - polygonFile = new BufferedReadWriteFile( NULL , fileHeader ); -} -template< class Vertex > -CoredFileMeshData< Vertex >::~CoredFileMeshData( void ) -{ - delete oocPointFile; - delete polygonFile; -} -template< class Vertex > -void CoredFileMeshData< Vertex >::resetIterator ( void ) -{ - oocPointFile->reset(); - polygonFile->reset(); -} -template< class Vertex > -int CoredFileMeshData< Vertex >::addOutOfCorePoint( const Vertex& p ) -{ - oocPointFile->write( &p , sizeof( Vertex ) ); - oocPoints++; - return oocPoints-1; -} -template< class Vertex > -int CoredFileMeshData< Vertex >::addOutOfCorePoint_s( const Vertex& p ) -{ - int sz; -#pragma omp critical (CoredFileMeshData_addOutOfCorePoint_s) - { - sz = oocPoints; - oocPointFile->write( &p , sizeof( Vertex ) ); - oocPoints++; - } - return sz; -} -template< class Vertex > -int CoredFileMeshData< Vertex >::addPolygon_s( const std::vector< int >& vertices ) -{ - int sz , vSize = (int)vertices.size(); -#pragma omp critical (CoredFileMeshData_addPolygon_s ) - { - sz = polygons; - polygonFile->write( &vSize , sizeof(int) ); - polygonFile->write( &vertices[0] , sizeof(int) * vSize ); - polygons++; - } - return sz; -} -template< class Vertex > -int CoredFileMeshData< Vertex >::addPolygon_s( const std::vector< CoredVertexIndex >& vertices ) -{ - std::vector< int > polygon( vertices.size() ); - for( int i=0 ; i<(int)vertices.size() ; i++ ) - if( vertices[i].inCore ) polygon[i] = vertices[i].idx; - else polygon[i] = -vertices[i].idx-1; - return addPolygon_s( polygon ); -} -template< class Vertex > -int CoredFileMeshData< Vertex >::nextOutOfCorePoint( Vertex& p ) -{ - if( oocPointFile->read( &p , sizeof( Vertex ) ) ) return 1; - else return 0; -} -template< class Vertex > -int CoredFileMeshData< Vertex >::nextPolygon( std::vector< CoredVertexIndex >& vertices ) -{ - int pSize; - if( polygonFile->read( &pSize , sizeof(int) ) ) - { - std::vector< int > polygon( pSize ); - if( polygonFile->read( &polygon[0] , sizeof(int)*pSize ) ) - { - vertices.resize( pSize ); - for( int i=0 ; i -int CoredFileMeshData< Vertex >::outOfCorePointCount( void ){ return oocPoints; } -template< class Vertex > -int CoredFileMeshData< Vertex >::polygonCount( void ) { return polygons; } diff --git a/Src/MAT.inl b/Src/MAT.inl deleted file mode 100644 index 5106659f..00000000 --- a/Src/MAT.inl +++ /dev/null @@ -1,217 +0,0 @@ -/* -Copyright (c) 2007, Michael Kazhdan -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ -////////////////////////////// -// MinimalAreaTriangulation // -////////////////////////////// -template -MinimalAreaTriangulation::MinimalAreaTriangulation(void) -{ - bestTriangulation=NULL; - midPoint=NULL; -} -template -MinimalAreaTriangulation::~MinimalAreaTriangulation(void) -{ - if(bestTriangulation) - delete[] bestTriangulation; - bestTriangulation=NULL; - if(midPoint) - delete[] midPoint; - midPoint=NULL; -} -template -void MinimalAreaTriangulation::GetTriangulation(const std::vector >& vertices,std::vector& triangles) -{ - if(vertices.size()==3) - { - triangles.resize(1); - triangles[0].idx[0]=0; - triangles[0].idx[1]=1; - triangles[0].idx[2]=2; - return; - } - else if(vertices.size()==4) - { - TriangleIndex tIndex[2][2]; - Real area[2]; - - area[0]=area[1]=0; - triangles.resize(2); - - tIndex[0][0].idx[0]=0; - tIndex[0][0].idx[1]=1; - tIndex[0][0].idx[2]=2; - tIndex[0][1].idx[0]=2; - tIndex[0][1].idx[1]=3; - tIndex[0][1].idx[2]=0; - - tIndex[1][0].idx[0]=0; - tIndex[1][0].idx[1]=1; - tIndex[1][0].idx[2]=3; - tIndex[1][1].idx[0]=3; - tIndex[1][1].idx[1]=1; - tIndex[1][1].idx[2]=2; - - Point3D n,p1,p2; - for(int i=0;i<2;i++) - for(int j=0;j<2;j++) - { - p1=vertices[tIndex[i][j].idx[1]]-vertices[tIndex[i][j].idx[0]]; - p2=vertices[tIndex[i][j].idx[2]]-vertices[tIndex[i][j].idx[0]]; - CrossProduct(p1,p2,n); - area[i] += Real( Length(n) ); - } - if(area[0]>area[1]) - { - triangles[0]=tIndex[1][0]; - triangles[1]=tIndex[1][1]; - } - else - { - triangles[0]=tIndex[0][0]; - triangles[1]=tIndex[0][1]; - } - return; - } - if(bestTriangulation) - delete[] bestTriangulation; - if(midPoint) - delete[] midPoint; - bestTriangulation=NULL; - midPoint=NULL; - size_t eCount=vertices.size(); - bestTriangulation=new Real[eCount*eCount]; - midPoint=new int[eCount*eCount]; - for(size_t i=0;i -Real MinimalAreaTriangulation::GetArea(const std::vector >& vertices) -{ - if(bestTriangulation) - delete[] bestTriangulation; - if(midPoint) - delete[] midPoint; - bestTriangulation=NULL; - midPoint=NULL; - int eCount=vertices.size(); - bestTriangulation=new double[eCount*eCount]; - midPoint=new int[eCount*eCount]; - for(int i=0;i -void MinimalAreaTriangulation::GetTriangulation(const size_t& i,const size_t& j,const std::vector >& vertices,std::vector& triangles) -{ - TriangleIndex tIndex; - size_t eCount=vertices.size(); -#ifdef BRUNO_LEVY_FIX - int ii=(int)i; - if( i=ii ) - return; - ii=midPoint[i*eCount+j]; - if( ii>=0 ) - { - tIndex.idx[0] = int( i ); - tIndex.idx[1] = int( j ); - tIndex.idx[2] = int( ii ); - triangles.push_back(tIndex); - GetTriangulation(i,ii,vertices,triangles); - GetTriangulation(ii,j,vertices,triangles); - } -} - -template -Real MinimalAreaTriangulation::GetArea(const size_t& i,const size_t& j,const std::vector >& vertices) -{ - Real a=FLT_MAX,temp; - size_t eCount=vertices.size(); - size_t idx=i*eCount+j; - size_t ii=i; - if(i=ii) - { - bestTriangulation[idx]=0; - return 0; - } - if(midPoint[idx]!=-1) - return bestTriangulation[idx]; - int mid=-1; - for(size_t r=j+1;r p,p1,p2; - p1=vertices[i]-vertices[rr]; - p2=vertices[j]-vertices[rr]; - CrossProduct(p1,p2,p); - temp = Real( Length(p) ); - if(bestTriangulation[idx1]>=0) - { - temp+=bestTriangulation[idx1]; - if(temp>a) - continue; - if(bestTriangulation[idx2]>0) - temp+=bestTriangulation[idx2]; - else - temp+=GetArea(rr,j,vertices); - } - else - { - if(bestTriangulation[idx2]>=0) - temp+=bestTriangulation[idx2]; - else - temp+=GetArea(rr,j,vertices); - if(temp>a) - continue; - temp+=GetArea(i,rr,vertices); - } - - if(temp -#include "MarchingCubes.h" - -//////////// -// Square // -//////////// -int Square::AntipodalCornerIndex(int idx){ - int x,y; - FactorCornerIndex(idx,x,y); - return CornerIndex( (x+1)%2 , (y+1)%2 ); -} -int Square::CornerIndex( int x , int y ){ return (y<<1)|x; } -void Square::FactorCornerIndex( int idx , int& x , int& y ){ x=(idx>>0)&1 , y=(idx>>1)&1; } -int Square::EdgeIndex( int orientation , int i ) -{ - switch( orientation ) - { - case 0: // x - if( !i ) return 0; // (0,0) -> (1,0) - else return 2; // (0,1) -> (1,1) - case 1: // y - if( !i ) return 3; // (0,0) -> (0,1) - else return 1; // (1,0) -> (1,1) - }; - return -1; -} -void Square::FactorEdgeIndex(int idx,int& orientation,int& i){ - switch(idx){ - case 0: case 2: - orientation=0; - i=idx/2; - return; - case 1: case 3: - orientation=1; - i=((idx/2)+1)%2; - return; - }; -} -void Square::EdgeCorners(int idx,int& c1,int& c2){ - int orientation,i; - FactorEdgeIndex(idx,orientation,i); - switch(orientation){ - case 0: - c1 = CornerIndex(0,i); - c2 = CornerIndex(1,i); - break; - case 1: - c1 = CornerIndex(i,0); - c2 = CornerIndex(i,1); - break; - }; -} -int Square::ReflectEdgeIndex(int idx,int edgeIndex){ - int orientation=edgeIndex%2; - int o,i; - FactorEdgeIndex(idx,o,i); - if(o!=orientation){return idx;} - else{return EdgeIndex(o,(i+1)%2);} -} -int Square::ReflectCornerIndex(int idx,int edgeIndex){ - int orientation=edgeIndex%2; - int x,y; - FactorCornerIndex(idx,x,y); - switch(orientation){ - case 0: return CornerIndex((x+1)%2,y); - case 1: return CornerIndex(x,(y+1)%2); - }; - return -1; -} - - - -////////// -// Cube // -////////// -int Cube::CornerIndex( int x , int y , int z ){ return (z<<2)|(y<<1)|x; } -void Cube::FactorCornerIndex( int idx , int& x , int& y , int& z ){ x = (idx>>0)&1 , y = (idx>>1)&1 , z = (idx>>2)&1; } -int Cube::EdgeIndex(int orientation,int i,int j){return (i | (j<<1))|(orientation<<2);} -void Cube::FactorEdgeIndex( int idx , int& orientation , int& i , int &j ) -{ - orientation=idx>>2; - i = (idx&1); - j = (idx&2)>>1; -} -int Cube::FaceIndex( int x , int y , int z ) -{ - if ( x<0 ) return 0; - else if( x>0 ) return 1; - else if( y<0 ) return 2; - else if( y>0 ) return 3; - else if( z<0 ) return 4; - else if( z>0 ) return 5; - else return -1; -} -int Cube::FaceIndex( int dir , int offSet ){ return (dir<<1)|offSet; } - -void Cube::FactorFaceIndex( int idx , int& x , int& y , int& z ) -{ - x=y=z=0; - switch( idx ) - { - case 0: x=-1; break; - case 1: x= 1; break; - case 2: y=-1; break; - case 3: y= 1; break; - case 4: z=-1; break; - case 5: z= 1; break; - }; -} -void Cube::FactorFaceIndex( int idx , int& dir , int& offSet ) -{ - dir = idx>>1; - offSet=idx &1; -} -bool Cube::IsEdgeCorner( int cIndex , int e ) -{ - int o , i , j; - FactorEdgeIndex( e , o , i , j ); - switch( o ) - { - case 0: return (cIndex && 2)==(i<<1) && (cIndex && 4)==(j<<2); - case 1: return (cIndex && 1)==(i<<0) && (cIndex && 4)==(j<<2); - case 2: return (cIndex && 4)==(i<<2) && (cIndex && 2)==(j<<1); - default: return false; - } -} -bool Cube::IsFaceCorner( int cIndex , int f ) -{ - int dir , off; - FactorFaceIndex( f , dir , off ); - return ( cIndex & (1< (1,0) -1} // (1,0) -> (1,1) -2} // (0,1) -> (1,1) -3} // (0,0) -> (0,1) -*/ -const int MarchingSquares::edgeMask[1< -> -> - 9, // 1 -> 0 -> (0,0) -> 0,3 -> 9 - 3, // 2 -> 1 -> (1,0) -> 0,1 -> 3 - 10, // 3 -> 0,1 -> (0,0) (1,0) -> 1,3 -> 10 - 12, // 4 -> 2 -> (0,1) -> 2,3 -> 12 - 5, // 5 -> 0,2 -> (0,0) (0,1) -> 0,2 -> 5 - 15, // 6 -> 1,2 -> (1,0) (0,1) -> 0,1,2,3 -> 15 - 6, // 7 -> 0,1,2 -> (0,0) (1,0) (0,1) -> 1,2 -> 6 - 6, // 8 -> 3 -> (1,1) -> 1,2 -> 6 - 15, // 9 -> 0,3 -> (0,0) (1,1) -> 0,1,2,3 -> 15 - 5, // 10 -> 1,3 -> (1,0) (1,1) -> 0,2 -> 5 - 12, // 11 -> 0,1,3 -> (0,0) (1,0) (1,1) -> 2,3 -> 12 - 10, // 12 -> 2,3 -> (0,1) (1,1) -> 1,3 -> 10 - 3, // 13 -> 0,2,3 -> (0,0) (0,1) (1,1) -> 0,1 -> 3 - 9, // 14 -> 1,2,3 -> (1,0) (0,1) (1,1) -> 0,3 -> 9 - 0, // 15 -> 0,1,2,3 -> (0,0) (1,0) (0,1) (1,1) -> -}; -#if NEW_ORDERING -/* -0} // (0,0) -> (1,0) -1} // (1,0) -> (1,1) -2} // (0,1) -> (1,1) -3} // (0,0) -> (0,1) -*/ -const int MarchingSquares::edges[1<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(1,i,j)];}}} - else if (y<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,0,j)];}}} - else if (y>0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,1,j)];}}} - else if (z<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,j,0)];}}} - else if (z>0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,j,1)];}}} - if (v[0][0] < iso) idx |= 1; - if (v[1][0] < iso) idx |= 2; - if (v[1][1] < iso) idx |= 4; - if (v[0][1] < iso) idx |= 8; - return idx; -} -bool MarchingCubes::IsAmbiguous( const double v[Cube::CORNERS] , double isoValue , int faceIndex ){ return MarchingSquares::IsAmbiguous( GetFaceIndex( v , isoValue , faceIndex ) ); } -bool MarchingCubes::HasRoots( const double v[Cube::CORNERS] , double isoValue , int faceIndex ){ return MarchingSquares::HasRoots( GetFaceIndex( v , isoValue , faceIndex ) ); } -bool MarchingCubes::HasRoots( const double v[Cube::CORNERS] , double isoValue ){ return HasRoots( GetIndex( v , isoValue ) ); } -bool MarchingCubes::HasRoots( unsigned char mcIndex ){ return !(mcIndex==0 || mcIndex==255); } -int MarchingCubes::AddTriangles( const double v[Cube::CORNERS] , double iso , Triangle* isoTriangles ) -{ - unsigned char idx; - int ntriang=0; - Triangle tri; - - idx=GetIndex(v,iso); - - /* Cube is entirely in/out of the surface */ - if (!edgeMask[idx]) return 0; - - /* Find the vertices where the surface intersects the cube */ - int i,j,ii=1; - for(i=0;i<12;i++){ - if(edgeMask[idx] & ii){SetVertex(i,v,iso);} - ii<<=1; - } - /* Create the triangle */ - for( i=0 ; triangles[idx][i]!=-1 ; i+=3 ) - { - for(j=0;j<3;j++){ - tri.p[0][j]=vertexList[triangles[idx][i+0]][j]; - tri.p[1][j]=vertexList[triangles[idx][i+1]][j]; - tri.p[2][j]=vertexList[triangles[idx][i+2]][j]; - } - isoTriangles[ntriang++]=tri; - } - return ntriang; -} - -int MarchingCubes::AddTriangleIndices(const double v[Cube::CORNERS],double iso,int* isoIndices){ - unsigned char idx; - int ntriang=0; - - idx=GetIndex(v,iso); - - /* Cube is entirely in/out of the surface */ - if (!edgeMask[idx]) return 0; - - /* Create the triangle */ - for(int i=0;triangles[idx][i]!=-1;i+=3){ - for(int j=0;j<3;j++){isoIndices[i+j]=triangles[idx][i+j];} - ntriang++; - } - return ntriang; -} - -void MarchingCubes::SetVertex( int e , const double values[Cube::CORNERS] , double iso ) -{ - double t; - int o , i1 , i2; - Cube::FactorEdgeIndex( e , o , i1 , i2 ); - switch( o ) - { - case 0: - t = Interpolate( values[ Cube::CornerIndex( 0 , i1 , i2 ) ] - iso , values[ Cube::CornerIndex( 1 , i1 , i2 ) ] - iso ); - vertexList[e][0] = t , vertexList[e][1] = i1 , vertexList[e][2] = i2; - break; - case 1: - t = Interpolate( values[ Cube::CornerIndex( i1 , 0 , i2 ) ] - iso , values[ Cube::CornerIndex( i1 , 1 , i2 ) ] - iso ); - vertexList[e][0] = i1 , vertexList[e][1] = t , vertexList[e][2] = i2; - break; - case 2: - t = Interpolate( values[ Cube::CornerIndex( i1 , i2 , 0 ) ] - iso , values[ Cube::CornerIndex( i1 , i2 , 1 ) ] - iso ); - vertexList[e][0] = i1 , vertexList[e][1] = i2 , vertexList[e][2] = t; - break; - } -} -double MarchingCubes::Interpolate( double v1 , double v2 ) { return v1/(v1-v2); } - - -/////////////////////////////////// -unsigned char MarchingCubes::GetIndex(const float v[Cube::CORNERS],float iso){ - unsigned char idx=0; - if (v[Cube::CornerIndex(0,0,0)] < iso) idx |= 1; - if (v[Cube::CornerIndex(1,0,0)] < iso) idx |= 2; - if (v[Cube::CornerIndex(1,1,0)] < iso) idx |= 4; - if (v[Cube::CornerIndex(0,1,0)] < iso) idx |= 8; - if (v[Cube::CornerIndex(0,0,1)] < iso) idx |= 16; - if (v[Cube::CornerIndex(1,0,1)] < iso) idx |= 32; - if (v[Cube::CornerIndex(1,1,1)] < iso) idx |= 64; - if (v[Cube::CornerIndex(0,1,1)] < iso) idx |= 128; - return idx; -} -unsigned char MarchingCubes::GetFaceIndex( const float values[Cube::CORNERS] , float iso , int faceIndex ) -{ - int i,j,x,y,z; - unsigned char idx=0; - double v[2][2]; - Cube::FactorFaceIndex(faceIndex,x,y,z); - if (x<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(0,i,j)];}}} - else if (x>0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(1,i,j)];}}} - else if (y<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,0,j)];}}} - else if (y>0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,1,j)];}}} - else if (z<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,j,0)];}}} - else if (z>0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,j,1)];}}} - if (v[0][0] < iso) idx |= 1; - if (v[1][0] < iso) idx |= 2; - if (v[1][1] < iso) idx |= 4; - if (v[0][1] < iso) idx |= 8; - return idx; -} -unsigned char MarchingCubes::GetFaceIndex( unsigned char mcIndex , int faceIndex ) -{ - int i,j,x,y,z; - unsigned char idx=0; - int v[2][2]; - Cube::FactorFaceIndex(faceIndex,x,y,z); - if (x<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=mcIndex&(1<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=mcIndex&(1<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=mcIndex&(1<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=mcIndex&(1< -#include "Geometry.h" - -#define NEW_ORDERING 1 - -class Square -{ -public: - const static unsigned int CORNERS=4 , EDGES=4 , FACES=1; - static int CornerIndex (int x,int y); - static int AntipodalCornerIndex(int idx); - static void FactorCornerIndex (int idx,int& x,int& y); - static int EdgeIndex (int orientation,int i); - static void FactorEdgeIndex (int idx,int& orientation,int& i); - - static int ReflectCornerIndex (int idx,int edgeIndex); - static int ReflectEdgeIndex (int idx,int edgeIndex); - - static void EdgeCorners(int idx,int& c1,int &c2); -}; - -class Cube{ -public: - const static unsigned int CORNERS=8 , EDGES=12 , FACES=6; - - static int CornerIndex ( int x , int y , int z ); - static void FactorCornerIndex ( int idx , int& x , int& y , int& z ); - static int EdgeIndex ( int orientation , int i , int j ); - static void FactorEdgeIndex ( int idx , int& orientation , int& i , int &j); - static int FaceIndex ( int dir , int offSet ); - static int FaceIndex ( int x , int y , int z ); - static void FactorFaceIndex ( int idx , int& x , int &y , int& z ); - static void FactorFaceIndex ( int idx , int& dir , int& offSet ); - - static int AntipodalCornerIndex ( int idx ); - static int FaceReflectCornerIndex ( int idx , int faceIndex ); - static int FaceReflectEdgeIndex ( int idx , int faceIndex ); - static int FaceReflectFaceIndex ( int idx , int faceIndex ); - static int EdgeReflectCornerIndex ( int idx , int edgeIndex ); - static int EdgeReflectEdgeIndex ( int edgeIndex ); - - static int FaceAdjacentToEdges ( int eIndex1 , int eIndex2 ); - static void FacesAdjacentToEdge ( int eIndex , int& f1Index , int& f2Index ); - - static void EdgeCorners( int idx , int& c1 , int &c2 ); - static void FaceCorners( int idx , int& c1 , int &c2 , int& c3 , int& c4 ); - - static bool IsEdgeCorner( int cIndex , int e ); - static bool IsFaceCorner( int cIndex , int f ); -}; - -class MarchingSquares -{ - static double Interpolate(double v1,double v2); - static void SetVertex(int e,const double values[Square::CORNERS],double iso); -public: - const static unsigned int MAX_EDGES=2; - static const int edgeMask[1< -struct MemoryInfo -{ - static size_t Usage( void ) - { - HANDLE h = GetCurrentProcess(); - PROCESS_MEMORY_COUNTERS pmc; - return GetProcessMemoryInfo( h , &pmc , sizeof(pmc) ) ? pmc.WorkingSetSize : 0; - } -}; - -#else // !_WIN32 && !_WIN64 - -#ifndef __APPLE__ // Linux variants - -#include -#include - -class MemoryInfo -{ - public: - static size_t Usage(void) - { - FILE* f = fopen("/proc/self/stat","rb"); - - int d; - long ld; - unsigned long lu; - unsigned long long llu; - char s[1024]; - char c; - - int pid; - unsigned long vm; - - int n = fscanf(f, "%d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %d %ld %llu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu" - ,&pid ,s ,&c ,&d ,&d ,&d ,&d ,&d ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&ld ,&ld ,&ld ,&ld ,&d ,&ld ,&llu ,&vm ,&ld ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&lu ,&d ,&d ,&lu ,&lu ); - - fclose(f); -/* -pid %d -comm %s -state %c -ppid %d -pgrp %d -session %d -tty_nr %d -tpgid %d -flags %lu -minflt %lu -cminflt %lu -majflt %lu -cmajflt %lu -utime %lu -stime %lu -cutime %ld -cstime %ld -priority %ld -nice %ld -0 %ld -itrealvalue %ld -starttime %lu -vsize %lu -rss %ld -rlim %lu -startcode %lu -endcode %lu -startstack %lu -kstkesp %lu -kstkeip %lu -signal %lu -blocked %lu -sigignore %lu -sigcatch %lu -wchan %lu -nswap %lu -cnswap %lu -exit_signal %d -processor %d -rt_priority %lu (since kernel 2.5.19) -policy %lu (since kernel 2.5.19) -*/ - return vm; - } - -}; -#else // __APPLE__: has no "/proc" pseudo-file system - -// Thanks to David O'Gwynn for providing this fix. -// This comes from a post by Michael Knight: -// -// http://miknight.blogspot.com/2005/11/resident-set-size-in-mac-os-x.html - -#include -#include -#include -#include -#include -#include -#include - -void getres(task_t task, unsigned long *rss, unsigned long *vs) -{ - struct task_basic_info t_info; - mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; - - task_info(task, TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count); - *rss = t_info.resident_size; - *vs = t_info.virtual_size; -} - -class MemoryInfo -{ - public: - static size_t Usage(void) - { - unsigned long rss, vs, psize; - task_t task = MACH_PORT_NULL; - - if (task_for_pid(current_task(), getpid(), &task) != KERN_SUCCESS) - abort(); - getres(task, &rss, &vs); - return rss; - } - -}; - -#endif // !__APPLE__ - -#endif // _WIN32 || _WIN64 - -#endif // MEMORY_USAGE_INCLUDE diff --git a/Src/MultiGridOctreeData.Evaluation.inl b/Src/MultiGridOctreeData.Evaluation.inl deleted file mode 100644 index c965effb..00000000 --- a/Src/MultiGridOctreeData.Evaluation.inl +++ /dev/null @@ -1,1151 +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. -*/ - -template< class Real > -template< int FEMDegree , BoundaryType BType> -void Octree< Real >::_Evaluator< FEMDegree , BType >::set( LocalDepth depth ) -{ - static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; - static const int RightPointSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; - - BSplineEvaluationData< FEMDegree , BType >::SetEvaluator( evaluator , depth ); - if( depth>0 ) BSplineEvaluationData< FEMDegree , BType >::SetChildEvaluator( childEvaluator , depth-1 ); - int center = ( 1<>1; - - // First set the stencils for the current depth - for( int x=-LeftPointSupportRadius ; x<=RightPointSupportRadius ; x++ ) for( int y=-LeftPointSupportRadius ; y<=RightPointSupportRadius ; y++ ) for( int z=-LeftPointSupportRadius ; z<=RightPointSupportRadius ; z++ ) - { - int fIdx[] = { center+x , center+y , center+z }; - - // The cell stencil - { - double vv[3] , dv[3]; - for( int dd=0 ; dd( dv[0] * vv[1] * vv[2] , vv[0] * dv[1] * vv[2] , vv[0] * vv[1] * dv[2] ); - } - - //// The face stencil - for( int f=0 ; f( dv[0] * vv[1] * vv[2] , vv[0] * dv[1] * vv[2] , vv[0] * vv[1] * dv[2] ); - } - - //// The edge stencil - for( int e=0 ; e( dv[0] * vv[1] * vv[2] , vv[0] * dv[1] * vv[2] , vv[0] * vv[1] * dv[2] ); - } - - //// The corner stencil - for( int c=0 ; c( dv[0] * vv[1] * vv[2] , vv[0] * dv[1] * vv[2] , vv[0] * vv[1] * dv[2] ); - } - } - - // Now set the stencils for the parents - for( int child=0 ; child( dv[0] * vv[1] * vv[2] , vv[0] * dv[1] * vv[2] , vv[0] * vv[1] * dv[2] ); - } - - //// The face stencil - for( int f=0 ; f( dv[0] * vv[1] * vv[2] , vv[0] * dv[1] * vv[2] , vv[0] * vv[1] * dv[2] ); - } - - //// The edge stencil - for( int e=0 ; e( dv[0] * vv[1] * vv[2] , vv[0] * dv[1] * vv[2] , vv[0] * vv[1] * dv[2] ); - } - - //// The corner stencil - for( int c=0 ; c( dv[0] * vv[1] * vv[2] , vv[0] * dv[1] * vv[2] , vv[0] * vv[1] * dv[2] ); - } - } - } - if( _bsData ) delete _bsData; - _bsData = new BSplineData< FEMDegree , BType >( depth ); -} -template< class Real > -template< class V , int FEMDegree , BoundaryType BType > -V Octree< Real >::_getValue( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , Point3D< Real > p , const DenseNodeData< V , FEMDegree >& solution , const DenseNodeData< V , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator ) const -{ - static const int SupportSize = BSplineSupportSizes< FEMDegree >::SupportSize; - static const int LeftSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; - static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; - static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; - static const int RightPointSupportRadius = - BSplineSupportSizes< FEMDegree >::SupportStart; - - if( IsActiveNode( node->children ) ) fprintf( stderr , "[WARNING] getValue assumes leaf node\n" ); - V value(0); - - while( GetGhostFlag( node ) ) - { - const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); - - for( int i=0 ; i _s ; Real _w; - _startAndWidth( _n , _s , _w ); - int _fIdx[3]; - functionIndex< FEMDegree , BType >( _n , _fIdx ); - for( int dd=0 ; dd<3 ; dd++ ) _pIdx[dd] = std::max< int >( 0 , std::min< int >( SupportSize-1 , LeftSupportRadius + (int)floor( ( p[dd]-_s[dd] ) / _w ) ) ); - value += - solution[ _n->nodeData.nodeIndex ] * - (Real) - ( - evaluator._bsData->baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * - evaluator._bsData->baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * - evaluator._bsData->baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) - ); - } - } - node = node->parent; - } - - LocalDepth d = _localDepth( node ); - - for( int dd=0 ; dd<3 ; dd++ ) - if ( p[dd]==0 ) p[dd] = (Real)(0.+1e-6); - else if( p[dd]==1 ) p[dd] = (Real)(1.-1e-6); - - { - const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); - - for( int i=0 ; i _s ; Real _w; - _startAndWidth( _n , _s , _w ); - int _fIdx[3]; - functionIndex< FEMDegree , BType >( _n , _fIdx ); - for( int dd=0 ; dd<3 ; dd++ ) _pIdx[dd] = std::max< int >( 0 , std::min< int >( SupportSize-1 , LeftSupportRadius + (int)floor( ( p[dd]-_s[dd] ) / _w ) ) ); - value += - solution[ _n->nodeData.nodeIndex ] * - (Real) - ( - evaluator._bsData->baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * - evaluator._bsData->baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * - evaluator._bsData->baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) - ); - } - } - if( d>0 ) - { - const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node->parent ); - for( int i=0 ; i _s ; Real _w; - _startAndWidth( _n , _s , _w ); - int _fIdx[3]; - functionIndex< FEMDegree , BType >( _n , _fIdx ); - for( int dd=0 ; dd<3 ; dd++ ) _pIdx[dd] = std::max< int >( 0 , std::min< int >( SupportSize-1 , LeftSupportRadius + (int)floor( ( p[dd]-_s[dd] ) / _w ) ) ); - value += - coarseSolution[ _n->nodeData.nodeIndex ] * - (Real) - ( - evaluator._bsData->baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * - evaluator._bsData->baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * - evaluator._bsData->baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) - ); - } - } - } - } - return value; -} -template< class Real > -template< int FEMDegree , BoundaryType BType > -std::pair< Real , Point3D< Real > > Octree< Real >::_getValueAndGradient( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , Point3D< Real > p , const DenseNodeData< Real , FEMDegree >& solution , const DenseNodeData< Real , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator ) const -{ - static const int SupportSize = BSplineSupportSizes< FEMDegree >::SupportSize; - static const int LeftSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; - static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; - static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; - static const int RightPointSupportRadius = - BSplineSupportSizes< FEMDegree >::SupportStart; - - if( IsActiveNode( node->children ) ) fprintf( stderr , "[WARNING] _getValueAndGradient assumes leaf node\n" ); - Real value(0); - Point3D< Real > gradient; - - while( GetGhostFlag( node ) ) - { - const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); - - for( int i=0 ; i _s; Real _w; - _startAndWidth( _n , _s , _w ); - int _fIdx[3]; - functionIndex< FEMDegree , BType >( _n , _fIdx ); - for( int dd=0 ; dd<3 ; dd++ ) _pIdx[dd] = std::max< int >( 0 , std::min< int >( SupportSize-1 , LeftSupportRadius + (int)floor( ( p[dd]-_s[dd] ) / _w ) ) ); - value += - solution[ _n->nodeData.nodeIndex ] * - (Real) - ( - evaluator._bsData->baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData->baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData->baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) - ); - gradient += - Point3D< Real > - ( - evaluator._bsData->dBaseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData-> baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData-> baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) , - evaluator._bsData-> baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData->dBaseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData-> baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) , - evaluator._bsData-> baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData-> baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData->dBaseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) - ) * solution[ _n->nodeData.nodeIndex ]; - } - } - node = node->parent; - } - - - LocalDepth d = _localDepth( node ); - - for( int dd=0 ; dd<3 ; dd++ ) - if ( p[dd]==0 ) p[dd] = (Real)(0.+1e-6); - else if( p[dd]==1 ) p[dd] = (Real)(1.-1e-6); - - { - const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); - - for( int i=0 ; i _s ; Real _w; - _startAndWidth( _n , _s , _w ); - int _fIdx[3]; - functionIndex< FEMDegree , BType >( _n , _fIdx ); - for( int dd=0 ; dd<3 ; dd++ ) _pIdx[dd] = std::max< int >( 0 , std::min< int >( SupportSize-1 , LeftSupportRadius + (int)floor( ( p[dd]-_s[dd] ) / _w ) ) ); - value += - solution[ _n->nodeData.nodeIndex ] * - (Real) - ( - evaluator._bsData->baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData->baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData->baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) - ); - gradient += - Point3D< Real > - ( - evaluator._bsData->dBaseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData-> baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData-> baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) , - evaluator._bsData-> baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData->dBaseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData-> baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) , - evaluator._bsData-> baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData-> baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData->dBaseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) - ) * solution[ _n->nodeData.nodeIndex ]; - } - } - if( d>0 ) - { - const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node->parent ); - for( int i=0 ; i _s ; Real _w; - _startAndWidth( _n , _s , _w ); - int _fIdx[3]; - functionIndex< FEMDegree , BType >( _n , _fIdx ); - for( int dd=0 ; dd<3 ; dd++ ) _pIdx[dd] = std::max< int >( 0 , std::min< int >( SupportSize-1 , LeftSupportRadius + (int)floor( ( p[dd]-_s[dd] ) / _w ) ) ); - value += - coarseSolution[ _n->nodeData.nodeIndex ] * - (Real) - ( - evaluator._bsData->baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData->baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData->baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) - ); - gradient += - Point3D< Real > - ( - evaluator._bsData->dBaseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData-> baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData-> baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) , - evaluator._bsData-> baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData->dBaseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData-> baseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) , - evaluator._bsData-> baseBSplines[ _fIdx[0] ][ _pIdx[0] ]( p[0] ) * evaluator._bsData-> baseBSplines[ _fIdx[1] ][ _pIdx[1] ]( p[1] ) * evaluator._bsData->dBaseBSplines[ _fIdx[2] ][ _pIdx[2] ]( p[2] ) - ) * coarseSolution[ _n->nodeData.nodeIndex ]; - } - } - } - } - return std::pair< Real , Point3D< Real > >( value , gradient ); -} -template< class Real > -template< class V , int FEMDegree , BoundaryType BType > -V Octree< Real >::_getCenterValue( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , const DenseNodeData< V , FEMDegree >& solution , const DenseNodeData< V , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator , bool isInterior ) const -{ - static const int SupportSize = BSplineEvaluationData< FEMDegree , BType >::SupportSize; - static const int LeftPointSupportRadius = BSplineEvaluationData< FEMDegree , BType >::SupportEnd; - static const int RightPointSupportRadius = - BSplineEvaluationData< FEMDegree , BType >::SupportStart; - - if( IsActiveNode( node->children ) ) fprintf( stderr , "[WARNING] getCenterValue assumes leaf node\n" ); - V value(0); - LocalDepth d = _localDepth( node ); - - if( isInterior ) - { - const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); - for( int i=0 ; inodeData.nodeIndex ] * Real( evaluator.cellStencil( i , j , k ) ); - } - if( d>0 ) - { - int _corner = int( node - node->parent->children ); - const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node->parent ); - for( int i=0 ; inodeData.nodeIndex] * Real( evaluator.cellStencils[_corner]( i , j , k ) ); - } - } - } - else - { - LocalOffset cIdx; - _localDepthAndOffset( node , d , cIdx ); - const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); - - for( int i=0 ; inodeData.nodeIndex ] * - Real( - evaluator.evaluator.centerValue( fIdx[0] , cIdx[0] , false ) * - evaluator.evaluator.centerValue( fIdx[1] , cIdx[1] , false ) * - evaluator.evaluator.centerValue( fIdx[2] , cIdx[2] , false ) - ); - } - } - if( d>0 ) - { - const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node->parent ); - for( int i=0 ; inodeData.nodeIndex ] * - Real( - evaluator.childEvaluator.centerValue( fIdx[0] , cIdx[0] , false ) * - evaluator.childEvaluator.centerValue( fIdx[1] , cIdx[1] , false ) * - evaluator.childEvaluator.centerValue( fIdx[2] , cIdx[2] , false ) - ); - } - } - } - } - return value; -} -template< class Real > -template< int FEMDegree , BoundaryType BType > -std::pair< Real , Point3D< Real > > Octree< Real >::_getCenterValueAndGradient( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , const DenseNodeData< Real , FEMDegree >& solution , const DenseNodeData< Real , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator , bool isInterior ) const -{ - static const int SupportSize = BSplineEvaluationData< FEMDegree , BType >::SupportSize; - static const int LeftPointSupportRadius = BSplineEvaluationData< FEMDegree , BType >::SupportEnd; - static const int RightPointSupportRadius = - BSplineEvaluationData< FEMDegree , BType >::SupportStart; - - if( IsActiveNode( node->children ) ) fprintf( stderr , "[WARNING] getCenterValueAndGradient assumes leaf node\n" ); - Real value(0); - Point3D< Real > gradient; - LocalDepth d = _localDepth( node ); - - if( isInterior ) - { - const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); - for( int i=0 ; inodeData.nodeIndex ]; - gradient += Point3D< Real >( evaluator.dCellStencil( i , j , k ) ) * solution[ n->nodeData.nodeIndex ]; - } - } - if( d>0 ) - { - int _corner = int( node - node->parent->children ); - const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node->parent ); - for( int i=0 ; inodeData.nodeIndex]; - gradient += Point3D< Real >( evaluator.dCellStencils[_corner]( i , j , k ) ) * coarseSolution[n->nodeData.nodeIndex]; - } - } - } - } - else - { - LocalOffset cIdx; - _localDepthAndOffset( node , d , cIdx ); - const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); - - for( int i=0 ; inodeData.nodeIndex ]; - gradient += - Point3D< Real > - ( - evaluator.evaluator.centerValue( fIdx[0] , cIdx[0] , true ) * evaluator.evaluator.centerValue( fIdx[1] , cIdx[1] , false ) * evaluator.evaluator.centerValue( fIdx[2] , cIdx[2] , false ) , - evaluator.evaluator.centerValue( fIdx[0] , cIdx[0] , false ) * evaluator.evaluator.centerValue( fIdx[1] , cIdx[1] , true ) * evaluator.evaluator.centerValue( fIdx[2] , cIdx[2] , false ) , - evaluator.evaluator.centerValue( fIdx[0] , cIdx[0] , false ) * evaluator.evaluator.centerValue( fIdx[1] , cIdx[1] , false ) * evaluator.evaluator.centerValue( fIdx[2] , cIdx[2] , true ) - ) * solution[ n->nodeData.nodeIndex ]; - } - } - if( d>0 ) - { - const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node->parent ); - for( int i=0 ; inodeData.nodeIndex ]; - gradient += - Point3D< Real > - ( - evaluator.childEvaluator.centerValue( fIdx[0] , cIdx[0] , true ) * evaluator.childEvaluator.centerValue( fIdx[1] , cIdx[1] , false ) * evaluator.childEvaluator.centerValue( fIdx[2] , cIdx[2] , false ) , - evaluator.childEvaluator.centerValue( fIdx[0] , cIdx[0] , false ) * evaluator.childEvaluator.centerValue( fIdx[1] , cIdx[1] , true ) * evaluator.childEvaluator.centerValue( fIdx[2] , cIdx[2] , false ) , - evaluator.childEvaluator.centerValue( fIdx[0] , cIdx[0] , false ) * evaluator.childEvaluator.centerValue( fIdx[1] , cIdx[1] , false ) * evaluator.childEvaluator.centerValue( fIdx[2] , cIdx[2] , true ) - ) * coarseSolution[ n->nodeData.nodeIndex ]; - } - } - } - } - return std::pair< Real , Point3D< Real > >( value , gradient ); -} -template< class Real > -template< class V , int FEMDegree , BoundaryType BType > -V Octree< Real >::_getEdgeValue( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , int edge , const DenseNodeData< V , FEMDegree >& solution , const DenseNodeData< V , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator , bool isInterior ) const -{ - static const int SupportSize = BSplineEvaluationData< FEMDegree , BType >::SupportSize; - static const int LeftPointSupportRadius = BSplineEvaluationData< FEMDegree , BType >::SupportEnd; - static const int RightPointSupportRadius = -BSplineEvaluationData< FEMDegree , BType >::SupportStart; - V value(0); - LocalDepth d ; LocalOffset cIdx; - _localDepthAndOffset( node , d , cIdx ); - int startX = 0 , endX = SupportSize , startY = 0 , endY = SupportSize , startZ = 0 , endZ = SupportSize; - int orientation , i1 , i2; - Cube::FactorEdgeIndex( edge , orientation , i1 , i2 ); - switch( orientation ) - { - case 0: - cIdx[1] += i1 , cIdx[2] += i2; - if( i1 ) startY++ ; else endY--; - if( i2 ) startZ++ ; else endZ--; - break; - case 1: - cIdx[0] += i1 , cIdx[2] += i2; - if( i1 ) startX++ ; else endX--; - if( i2 ) startZ++ ; else endZ--; - break; - case 2: - cIdx[0] += i1 , cIdx[1] += i2; - if( i1 ) startX++ ; else endX--; - if( i2 ) startY++ ; else endY--; - break; - } - - { - const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , d ); - for( int x=startX ; xnodeData.nodeIndex ] * evaluator.edgeStencil[edge]( x , y , z ); - else - { - LocalDepth _d ; LocalOffset fIdx; - _localDepthAndOffset( _node , _d , fIdx ); - switch( orientation ) - { - case 0: - value += - solution[ _node->nodeData.nodeIndex ] * - Real( - evaluator.evaluator.centerValue( fIdx[0] , cIdx[0] , false ) * - evaluator.evaluator.cornerValue( fIdx[1] , cIdx[1] , false ) * - evaluator.evaluator.cornerValue( fIdx[2] , cIdx[2] , false ) - ); - break; - case 1: - value += - solution[ _node->nodeData.nodeIndex ] * - Real( - evaluator.evaluator.cornerValue( fIdx[0] , cIdx[0] , false ) * - evaluator.evaluator.centerValue( fIdx[1] , cIdx[1] , false ) * - evaluator.evaluator.cornerValue( fIdx[2] , cIdx[2] , false ) - ); - break; - case 2: - value += - solution[ _node->nodeData.nodeIndex ] * - Real( - evaluator.evaluator.cornerValue( fIdx[0] , cIdx[0] , false ) * - evaluator.evaluator.cornerValue( fIdx[1] , cIdx[1] , false ) * - evaluator.evaluator.centerValue( fIdx[2] , cIdx[2] , false ) - ); - break; - } - } - } - } - } - if( d>0 ) - { - int _corner = int( node - node->parent->children ); - int _cx , _cy , _cz; - Cube::FactorCornerIndex( _corner , _cx , _cy , _cz ); - // If the corner/child indices don't match, then the sample position is in the interior of the - // coarser cell and so the full support resolution should be used. - switch( orientation ) - { - case 0: - if( _cy!=i1 ) startY = 0 , endY = SupportSize; - if( _cz!=i2 ) startZ = 0 , endZ = SupportSize; - break; - case 1: - if( _cx!=i1 ) startX = 0 , endX = SupportSize; - if( _cz!=i2 ) startZ = 0 , endZ = SupportSize; - break; - case 2: - if( _cx!=i1 ) startX = 0 , endX = SupportSize; - if( _cy!=i2 ) startY = 0 , endY = SupportSize; - break; - } - const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node->parent ); - for( int x=startX ; xnodeData.nodeIndex ] * evaluator.edgeStencils[_corner][edge]( x , y , z ); - else - { - LocalDepth _d ; LocalOffset fIdx; - _localDepthAndOffset( _node , _d , fIdx ); - switch( orientation ) - { - case 0: - value += - coarseSolution[ _node->nodeData.nodeIndex ] * - Real( - evaluator.childEvaluator.centerValue( fIdx[0] , cIdx[0] , false ) * - evaluator.childEvaluator.cornerValue( fIdx[1] , cIdx[1] , false ) * - evaluator.childEvaluator.cornerValue( fIdx[2] , cIdx[2] , false ) - ); - break; - case 1: - value += - coarseSolution[ _node->nodeData.nodeIndex ] * - Real( - evaluator.childEvaluator.cornerValue( fIdx[0] , cIdx[0] , false ) * - evaluator.childEvaluator.centerValue( fIdx[1] , cIdx[1] , false ) * - evaluator.childEvaluator.cornerValue( fIdx[2] , cIdx[2] , false ) - ); - break; - case 2: - value += - coarseSolution[ _node->nodeData.nodeIndex ] * - Real( - evaluator.childEvaluator.cornerValue( fIdx[0] , cIdx[0] , false ) * - evaluator.childEvaluator.cornerValue( fIdx[1] , cIdx[1] , false ) * - evaluator.childEvaluator.centerValue( fIdx[2] , cIdx[2] , false ) - ); - break; - } - } - } - } - } - return Real( value ); -} -template< class Real > -template< int FEMDegree , BoundaryType BType > -std::pair< Real , Point3D< Real > > Octree< Real >::_getEdgeValueAndGradient( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , int edge , const DenseNodeData< Real , FEMDegree >& solution , const DenseNodeData< Real , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator , bool isInterior ) const -{ - static const int SupportSize = BSplineEvaluationData< FEMDegree , BType >::SupportSize; - static const int LeftPointSupportRadius = BSplineEvaluationData< FEMDegree , BType >::SupportEnd; - static const int RightPointSupportRadius = -BSplineEvaluationData< FEMDegree , BType >::SupportStart; - double value = 0; - Point3D< double > gradient; - LocalDepth d ; LocalOffset cIdx; - _localDepthAndOffset( node , d , cIdx ); - - int startX = 0 , endX = SupportSize , startY = 0 , endY = SupportSize , startZ = 0 , endZ = SupportSize; - int orientation , i1 , i2; - Cube::FactorEdgeIndex( edge , orientation , i1 , i2 ); - switch( orientation ) - { - case 0: - cIdx[1] += i1 , cIdx[2] += i2; - if( i1 ) startY++ ; else endY--; - if( i2 ) startZ++ ; else endZ--; - break; - case 1: - cIdx[0] += i1 , cIdx[2] += i2; - if( i1 ) startX++ ; else endX--; - if( i2 ) startZ++ ; else endZ--; - break; - case 2: - cIdx[0] += i1 , cIdx[1] += i2; - if( i1 ) startX++ ; else endX--; - if( i2 ) startY++ ; else endY--; - break; - } - { - const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); - for( int x=startX ; xnodeData.nodeIndex ]; - gradient += evaluator.dEdgeStencil[edge]( x , y , z ) * solution[ _node->nodeData.nodeIndex ]; - } - else - { - LocalDepth _d ; LocalOffset fIdx; - _localDepthAndOffset( _node , _d , fIdx ); - - double vv[3] , dv[3]; - switch( orientation ) - { - case 0: - vv[0] = evaluator.evaluator.centerValue( fIdx[0] , cIdx[0] , false ); - vv[1] = evaluator.evaluator.cornerValue( fIdx[1] , cIdx[1] , false ); - vv[2] = evaluator.evaluator.cornerValue( fIdx[2] , cIdx[2] , false ); - dv[0] = evaluator.evaluator.centerValue( fIdx[0] , cIdx[0] , true ); - dv[1] = evaluator.evaluator.cornerValue( fIdx[1] , cIdx[1] , true ); - dv[2] = evaluator.evaluator.cornerValue( fIdx[2] , cIdx[2] , true ); - break; - case 1: - vv[0] = evaluator.evaluator.cornerValue( fIdx[0] , cIdx[0] , false ); - vv[1] = evaluator.evaluator.centerValue( fIdx[1] , cIdx[1] , false ); - vv[2] = evaluator.evaluator.cornerValue( fIdx[2] , cIdx[2] , false ); - dv[0] = evaluator.evaluator.cornerValue( fIdx[0] , cIdx[0] , true ); - dv[1] = evaluator.evaluator.centerValue( fIdx[1] , cIdx[1] , true ); - dv[2] = evaluator.evaluator.cornerValue( fIdx[2] , cIdx[2] , true ); - break; - case 2: - vv[0] = evaluator.evaluator.cornerValue( fIdx[0] , cIdx[0] , false ); - vv[1] = evaluator.evaluator.cornerValue( fIdx[1] , cIdx[1] , false ); - vv[2] = evaluator.evaluator.centerValue( fIdx[2] , cIdx[2] , false ); - dv[0] = evaluator.evaluator.cornerValue( fIdx[0] , cIdx[0] , true ); - dv[1] = evaluator.evaluator.cornerValue( fIdx[1] , cIdx[1] , true ); - dv[2] = evaluator.evaluator.centerValue( fIdx[2] , cIdx[2] , true ); - break; - } - value += solution[ _node->nodeData.nodeIndex ] * vv[0] * vv[1] * vv[2]; - gradient += Point3D< double >( dv[0]*vv[1]*vv[2] , vv[0]*dv[1]*vv[2] , vv[0]*vv[1]*dv[2] ) * solution[ _node->nodeData.nodeIndex ]; - } - } - } - } - if( d>0 ) - { - int _corner = int( node - node->parent->children ); - int _cx , _cy , _cz; - Cube::FactorCornerIndex( _corner , _cx , _cy , _cz ); - // If the corner/child indices don't match, then the sample position is in the interior of the - // coarser cell and so the full support resolution should be used. - switch( orientation ) - { - case 0: - if( _cy!=i1 ) startY = 0 , endY = SupportSize; - if( _cz!=i2 ) startZ = 0 , endZ = SupportSize; - break; - case 1: - if( _cx!=i1 ) startX = 0 , endX = SupportSize; - if( _cz!=i2 ) startZ = 0 , endZ = SupportSize; - break; - case 2: - if( _cx!=i1 ) startX = 0 , endX = SupportSize; - if( _cy!=i2 ) startY = 0 , endY = SupportSize; - break; - } - const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node->parent ); - for( int x=startX ; xnodeData.nodeIndex ]; - gradient += evaluator.dEdgeStencils[_corner][edge]( x , y , z ) * coarseSolution[ _node->nodeData.nodeIndex ]; - } - else - { - LocalDepth _d ; LocalOffset fIdx; - _localDepthAndOffset( _node , _d , fIdx ); - double vv[3] , dv[3]; - switch( orientation ) - { - case 0: - vv[0] = evaluator.childEvaluator.centerValue( fIdx[0] , cIdx[0] , false ); - vv[1] = evaluator.childEvaluator.cornerValue( fIdx[1] , cIdx[1] , false ); - vv[2] = evaluator.childEvaluator.cornerValue( fIdx[2] , cIdx[2] , false ); - dv[0] = evaluator.childEvaluator.centerValue( fIdx[0] , cIdx[0] , true ); - dv[1] = evaluator.childEvaluator.cornerValue( fIdx[1] , cIdx[1] , true ); - dv[2] = evaluator.childEvaluator.cornerValue( fIdx[2] , cIdx[2] , true ); - break; - case 1: - vv[0] = evaluator.childEvaluator.cornerValue( fIdx[0] , cIdx[0] , false ); - vv[1] = evaluator.childEvaluator.centerValue( fIdx[1] , cIdx[1] , false ); - vv[2] = evaluator.childEvaluator.cornerValue( fIdx[2] , cIdx[2] , false ); - dv[0] = evaluator.childEvaluator.cornerValue( fIdx[0] , cIdx[0] , true ); - dv[1] = evaluator.childEvaluator.centerValue( fIdx[1] , cIdx[1] , true ); - dv[2] = evaluator.childEvaluator.cornerValue( fIdx[2] , cIdx[2] , true ); - break; - case 2: - vv[0] = evaluator.childEvaluator.cornerValue( fIdx[0] , cIdx[0] , false ); - vv[1] = evaluator.childEvaluator.cornerValue( fIdx[1] , cIdx[1] , false ); - vv[2] = evaluator.childEvaluator.centerValue( fIdx[2] , cIdx[2] , false ); - dv[0] = evaluator.childEvaluator.cornerValue( fIdx[0] , cIdx[0] , true ); - dv[1] = evaluator.childEvaluator.cornerValue( fIdx[1] , cIdx[1] , true ); - dv[2] = evaluator.childEvaluator.centerValue( fIdx[2] , cIdx[2] , true ); - break; - } - value += coarseSolution[ _node->nodeData.nodeIndex ] * vv[0] * vv[1] * vv[2]; - gradient += Point3D< double >( dv[0]*vv[1]*vv[2] , vv[0]*dv[1]*vv[2] , vv[0]*vv[1]*dv[2] ) * coarseSolution[ _node->nodeData.nodeIndex ]; - } - } - } - } - return std::pair< Real , Point3D< Real > >( Real( value ) , Point3D< Real >( gradient ) ); -} - -template< class Real > -template< class V , int FEMDegree , BoundaryType BType > -V Octree< Real >::_getCornerValue( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , int corner , const DenseNodeData< V , FEMDegree >& solution , const DenseNodeData< V , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator , bool isInterior ) const -{ - static const int SupportSize = BSplineSupportSizes< FEMDegree >::SupportSize; - static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; - static const int RightPointSupportRadius = - BSplineSupportSizes< FEMDegree >::SupportStart; - - V value(0); - LocalDepth d ; LocalOffset cIdx; - _localDepthAndOffset( node , d , cIdx ); - - int cx , cy , cz; - int startX = 0 , endX = SupportSize , startY = 0 , endY = SupportSize , startZ = 0 , endZ = SupportSize; - Cube::FactorCornerIndex( corner , cx , cy , cz ); - cIdx[0] += cx , cIdx[1] += cy , cIdx[2] += cz; - { - const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); - if( cx==0 ) endX--; - else startX++; - if( cy==0 ) endY--; - else startY++; - if( cz==0 ) endZ--; - else startZ++; - if( isInterior ) - for( int x=startX ; xnodeData.nodeIndex ] * Real( evaluator.cornerStencil[corner]( x , y , z ) ); - } - else - for( int x=startX ; xnodeData.nodeIndex ] * - Real( - evaluator.evaluator.cornerValue( fIdx[0] , cIdx[0] , false ) * - evaluator.evaluator.cornerValue( fIdx[1] , cIdx[1] , false ) * - evaluator.evaluator.cornerValue( fIdx[2] , cIdx[2] , false ) - ); - } - } - } - if( d>0 ) - { - int _corner = int( node - node->parent->children ); - int _cx , _cy , _cz; - Cube::FactorCornerIndex( _corner , _cx , _cy , _cz ); - // If the corner/child indices don't match, then the sample position is in the interior of the - // coarser cell and so the full support resolution should be used. - if( cx!=_cx ) startX = 0 , endX = SupportSize; - if( cy!=_cy ) startY = 0 , endY = SupportSize; - if( cz!=_cz ) startZ = 0 , endZ = SupportSize; - const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node->parent ); - if( isInterior ) - for( int x=startX ; xnodeData.nodeIndex ] * Real( evaluator.cornerStencils[_corner][corner]( x , y , z ) ); - } - else - for( int x=startX ; xnodeData.nodeIndex ] * - Real( - evaluator.childEvaluator.cornerValue( fIdx[0] , cIdx[0] , false ) * - evaluator.childEvaluator.cornerValue( fIdx[1] , cIdx[1] , false ) * - evaluator.childEvaluator.cornerValue( fIdx[2] , cIdx[2] , false ) - ); - } - } - } - return Real( value ); -} -template< class Real > -template< int FEMDegree , BoundaryType BType > -std::pair< Real , Point3D< Real > > Octree< Real >::_getCornerValueAndGradient( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , int corner , const DenseNodeData< Real , FEMDegree >& solution , const DenseNodeData< Real , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator , bool isInterior ) const -{ - static const int SupportSize = BSplineSupportSizes< FEMDegree >::SupportSize; - static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; - static const int RightPointSupportRadius = - BSplineSupportSizes< FEMDegree >::SupportStart; - - double value = 0; - Point3D< double > gradient; - LocalDepth d ; LocalOffset cIdx; - _localDepthAndOffset( node , d , cIdx ); - - int cx , cy , cz; - int startX = 0 , endX = SupportSize , startY = 0 , endY = SupportSize , startZ = 0 , endZ = SupportSize; - Cube::FactorCornerIndex( corner , cx , cy , cz ); - cIdx[0] += cx , cIdx[1] += cy , cIdx[2] += cz; - { - if( cx==0 ) endX--; - else startX++; - if( cy==0 ) endY--; - else startY++; - if( cz==0 ) endZ--; - else startZ++; - const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node ); - if( isInterior ) - for( int x=startX ; xnodeData.nodeIndex ] * evaluator.cornerStencil[corner]( x , y , z ) , gradient += evaluator.dCornerStencil[corner]( x , y , z ) * solution[ _node->nodeData.nodeIndex ]; - } - else - for( int x=startX ; xnodeData.nodeIndex ] * v[0] * v[1] * v[2]; - gradient += Point3D< double >( dv[0]*v[1]*v[2] , v[0]*dv[1]*v[2] , v[0]*v[1]*dv[2] ) * solution[ _node->nodeData.nodeIndex ]; - } - } - } - if( d>0 ) - { - int _corner = int( node - node->parent->children ); - int _cx , _cy , _cz; - Cube::FactorCornerIndex( _corner , _cx , _cy , _cz ); - if( cx!=_cx ) startX = 0 , endX = SupportSize; - if( cy!=_cy ) startY = 0 , endY = SupportSize; - if( cz!=_cz ) startZ = 0 , endZ = SupportSize; - const typename TreeOctNode::ConstNeighbors< SupportSize >& neighbors = _neighbors< LeftPointSupportRadius , RightPointSupportRadius >( neighborKey , node->parent ); - if( isInterior ) - for( int x=startX ; xnodeData.nodeIndex ] * evaluator.cornerStencils[_corner][corner]( x , y , z ) , gradient += evaluator.dCornerStencils[_corner][corner]( x , y , z ) * coarseSolution[ _node->nodeData.nodeIndex ]; - } - else - for( int x=startX ; xnodeData.nodeIndex ] * v[0] * v[1] * v[2]; - gradient += Point3D< double >( dv[0]*v[1]*v[2] , v[0]*dv[1]*v[2] , v[0]*v[1]*dv[2] ) * coarseSolution[ _node->nodeData.nodeIndex ]; - } - } - } - return std::pair< Real , Point3D< Real > >( Real( value ) , Point3D< Real >( gradient ) ); -} -template< class Real > -template< int Degree , BoundaryType BType > -Octree< Real >::MultiThreadedEvaluator< Degree , BType >::MultiThreadedEvaluator( const Octree< Real >* tree , const DenseNodeData< Real , Degree >& coefficients , int threads ) : _coefficients( coefficients ) , _tree( tree ) -{ - _threads = std::max< int >( 1 , threads ); - _neighborKeys.resize( _threads ); - _coarseCoefficients = _tree->template coarseCoefficients< Real , Degree , BType >( _coefficients ); - _evaluator.set( _tree->_maxDepth ); - for( int t=0 ; t<_threads ; t++ ) _neighborKeys[t].set( tree->_localToGlobal( _tree->_maxDepth ) ); -} -template< class Real > -template< int Degree , BoundaryType BType > -Real Octree< Real >::MultiThreadedEvaluator< Degree , BType >::value( Point3D< Real > p , int thread , const TreeOctNode* node ) -{ - if( !node ) node = _tree->leaf( p ); - ConstPointSupportKey< Degree >& nKey = _neighborKeys[thread]; - nKey.getNeighbors( node ); - return _tree->template _getValue< Real , Degree >( nKey , node , p , _coefficients , _coarseCoefficients , _evaluator ); -} -template< class Real > -template< int Degree , BoundaryType BType > -std::pair< Real , Point3D< Real > > Octree< Real >::MultiThreadedEvaluator< Degree , BType >::valueAndGradient( Point3D< Real > p , int thread , const TreeOctNode* node ) -{ - if( !node ) node = _tree->leaf( p ); - ConstPointSupportKey< Degree >& nKey = _neighborKeys[thread]; - nKey.getNeighbors( node ); - return _tree->template _getValueAndGradient< Degree >( nKey , node , p , _coefficients , _coarseCoefficients , _evaluator ); -} diff --git a/Src/MultiGridOctreeData.IsoSurface.inl b/Src/MultiGridOctreeData.IsoSurface.inl deleted file mode 100644 index 2be26dc5..00000000 --- a/Src/MultiGridOctreeData.IsoSurface.inl +++ /dev/null @@ -1,1106 +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 "Octree.h" -#include "MyTime.h" -#include "MemoryUsage.h" -#include "MAT.h" - -template< class Real > -template< class Vertex > -Octree< Real >::_SliceValues< Vertex >::_SliceValues( void ) -{ - _oldCCount = _oldECount = _oldFCount = _oldNCount = 0; - cornerValues = NullPointer( Real ) ; cornerGradients = NullPointer( Point3D< Real > ) ; cornerSet = NullPointer( char ); - edgeKeys = NullPointer( long long ) ; edgeSet = NullPointer( char ); - faceEdges = NullPointer( _FaceEdges ) ; faceSet = NullPointer( char ); - mcIndices = NullPointer( char ); -} -template< class Real > -template< class Vertex > -Octree< Real >::_SliceValues< Vertex >::~_SliceValues( void ) -{ - _oldCCount = _oldECount = _oldFCount = _oldNCount = 0; - FreePointer( cornerValues ) ; FreePointer( cornerGradients ) ; FreePointer( cornerSet ); - FreePointer( edgeKeys ) ; FreePointer( edgeSet ); - FreePointer( faceEdges ) ; FreePointer( faceSet ); - FreePointer( mcIndices ); -} -template< class Real > -template< class Vertex > -void Octree< Real >::_SliceValues< Vertex >::reset( bool nonLinearFit ) -{ - faceEdgeMap.clear() , edgeVertexMap.clear() , vertexPairMap.clear(); - - if( _oldNCount0 ) mcIndices = AllocPointer< char >( _oldNCount ); - } - if( _oldCCount0 ) - { - cornerValues = AllocPointer< Real >( _oldCCount ); - if( nonLinearFit ) cornerGradients = AllocPointer< Point3D< Real > >( _oldCCount ); - cornerSet = AllocPointer< char >( _oldCCount ); - } - } - if( _oldECount( _oldECount ); - edgeSet = AllocPointer< char >( _oldECount ); - } - if( _oldFCount( _oldFCount ); - faceSet = AllocPointer< char >( _oldFCount ); - } - - if( sliceData.cCount>0 ) memset( cornerSet , 0 , sizeof( char ) * sliceData.cCount ); - if( sliceData.eCount>0 ) memset( edgeSet , 0 , sizeof( char ) * sliceData.eCount ); - if( sliceData.fCount>0 ) memset( faceSet , 0 , sizeof( char ) * sliceData.fCount ); -} -template< class Real > -template< class Vertex > -Octree< Real >::_XSliceValues< Vertex >::_XSliceValues( void ) -{ - _oldECount = _oldFCount = 0; - edgeKeys = NullPointer( long long ) ; edgeSet = NullPointer( char ); - faceEdges = NullPointer( _FaceEdges ) ; faceSet = NullPointer( char ); -} -template< class Real > -template< class Vertex > -Octree< Real >::_XSliceValues< Vertex >::~_XSliceValues( void ) -{ - _oldECount = _oldFCount = 0; - FreePointer( edgeKeys ) ; FreePointer( edgeSet ); - FreePointer( faceEdges ) ; FreePointer( faceSet ); -} -template< class Real > -template< class Vertex > -void Octree< Real >::_XSliceValues< Vertex >::reset( void ) -{ - faceEdgeMap.clear() , edgeVertexMap.clear() , vertexPairMap.clear(); - - if( _oldECount( _oldECount ); - edgeSet = AllocPointer< char >( _oldECount ); - } - if( _oldFCount( _oldFCount ); - faceSet = AllocPointer< char >( _oldFCount ); - } - if( xSliceData.eCount>0 ) memset( edgeSet , 0 , sizeof( char ) * xSliceData.eCount ); - if( xSliceData.fCount>0 ) memset( faceSet , 0 , sizeof( char ) * xSliceData.fCount ); -} - -template< class Real > -template< int FEMDegree , BoundaryType BType , int WeightDegree , int ColorDegree , class Vertex > -void Octree< Real >::getMCIsoSurface( const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Point3D< Real > , Real > , ColorDegree >* colorData , const DenseNodeData< Real , FEMDegree >& solution , Real isoValue , CoredMeshData< Vertex >& mesh , bool nonLinearFit , bool addBarycenter , bool polygonMesh ) -{ - if( FEMDegree==1 && nonLinearFit ) fprintf( stderr , "[WARNING] First order B-Splines do not support non-linear interpolation\n" ) , nonLinearFit = false; - - BSplineData< ColorDegree , BOUNDARY_NEUMANN >* colorBSData = NULL; - if( colorData ) colorBSData = new BSplineData< ColorDegree , BOUNDARY_NEUMANN >( _maxDepth ); - DenseNodeData< Real , FEMDegree > coarseSolution( _sNodesEnd(_maxDepth-1) ); - memset( &coarseSolution[0] , 0 , sizeof(Real)*_sNodesEnd( _maxDepth-1) ); -#pragma omp parallel for num_threads( threads ) - for( int i=_sNodesBegin(0) ; i<_sNodesEnd(_maxDepth-1) ; i++ ) coarseSolution[i] = solution[i]; - for( LocalDepth d=1 ; d<_maxDepth ; d++ ) _upSample< Real , FEMDegree , BType >( d , coarseSolution ); - memoryUsage(); - - std::vector< _Evaluator< FEMDegree , BType > > evaluators( _maxDepth+1 ); - for( LocalDepth d=0 ; d<=_maxDepth ; d++ ) evaluators[d].set( d ); - - int vertexOffset = 0; - - std::vector< _SlabValues< Vertex > > slabValues( _maxDepth+1 ); - - // Initialize the back slice - for( LocalDepth d=_maxDepth ; d>=0 ; d-- ) - { - _sNodes.setSliceTableData ( slabValues[d]. sliceValues(0). sliceData , _localToGlobal( d ) , 0 + _localInset( d ) , threads ); - _sNodes.setSliceTableData ( slabValues[d]. sliceValues(1). sliceData , _localToGlobal( d ) , 1 + _localInset( d ) , threads ); - _sNodes.setXSliceTableData( slabValues[d].xSliceValues(0).xSliceData , _localToGlobal( d ) , 0 + _localInset( d ) , threads ); - slabValues[d].sliceValues (0).reset( nonLinearFit ); - slabValues[d].sliceValues (1).reset( nonLinearFit ); - slabValues[d].xSliceValues(0).reset( ); - } - for( LocalDepth d=_maxDepth ; d>=0 ; d-- ) - { - // Copy edges from finer - if( d<_maxDepth ) _copyFinerSliceIsoEdgeKeys( d , 0 , slabValues , threads ); - _setSliceIsoCorners( solution , coarseSolution , isoValue , d , 0 , slabValues , evaluators[d] , threads ); - _setSliceIsoVertices< WeightDegree , ColorDegree >( colorBSData , densityWeights , colorData , isoValue , d , 0 , vertexOffset , mesh , slabValues , threads ); - _setSliceIsoEdges( d , 0 , slabValues , threads ); - } - - // Iterate over the slices at the finest level - for( int slice=0 ; slice<( 1<<_maxDepth ) ; slice++ ) - { - // Process at all depths that contain this slice - LocalDepth d ; int o; - for( d=_maxDepth , o=slice+1 ; d>=0 ; d-- , o>>=1 ) - { - // Copy edges from finer (required to ensure we correctly track edge cancellations) - if( d<_maxDepth ) - { - _copyFinerSliceIsoEdgeKeys( d , o , slabValues , threads ); - _copyFinerXSliceIsoEdgeKeys( d , o-1 , slabValues , threads ); - } - - // Set the slice values/vertices - _setSliceIsoCorners( solution , coarseSolution , isoValue , d , o , slabValues , evaluators[d] , threads ); - _setSliceIsoVertices< WeightDegree , ColorDegree >( colorBSData , densityWeights , colorData , isoValue , d , o , vertexOffset , mesh , slabValues , threads ); - _setSliceIsoEdges( d , o , slabValues , threads ); - - // Set the cross-slice edges - _setXSliceIsoVertices< WeightDegree , ColorDegree >( colorBSData , densityWeights , colorData , isoValue , d , o-1 , vertexOffset , mesh , slabValues , threads ); - _setXSliceIsoEdges( d , o-1 , slabValues , threads ); - - // Add the triangles - _setIsoSurface( d , o-1 , slabValues[d].sliceValues(o-1) , slabValues[d].sliceValues(o) , slabValues[d].xSliceValues(o-1) , mesh , polygonMesh , addBarycenter , vertexOffset , threads ); - - if( o&1 ) break; - } - - for( d=_maxDepth , o=slice+1 ; d>=0 ; d-- , o>>=1 ) - { - // Initialize for the next pass - if( o<(1<<(d+1)) ) - { - _sNodes.setSliceTableData( slabValues[d].sliceValues(o+1).sliceData , _localToGlobal( d ) , o+1 + _localInset( d ) , threads ); - _sNodes.setXSliceTableData( slabValues[d].xSliceValues(o).xSliceData , _localToGlobal( d ) , o + _localInset( d ) , threads ); - slabValues[d].sliceValues(o+1).reset( nonLinearFit ); - slabValues[d].xSliceValues(o).reset(); - } - if( o&1 ) break; - } - } - memoryUsage(); - if( colorBSData ) delete colorBSData; -} - - -template< class Real > -template< class Vertex , int FEMDegree , BoundaryType BType > -void Octree< Real >::_setSliceIsoCorners( const DenseNodeData< Real , FEMDegree >& solution , const DenseNodeData< Real , FEMDegree >& coarseSolution , Real isoValue , LocalDepth depth , int slice , std::vector< _SlabValues< Vertex > >& slabValues , const _Evaluator< FEMDegree , BType >& evaluator , int threads ) -{ - if( slice>0 ) _setSliceIsoCorners( solution , coarseSolution , isoValue , depth , slice , 1 , slabValues , evaluator , threads ); - if( slice<(1< -template< class Vertex , int FEMDegree , BoundaryType BType > -void Octree< Real >::_setSliceIsoCorners( const DenseNodeData< Real , FEMDegree >& solution , const DenseNodeData< Real , FEMDegree >& coarseSolution , Real isoValue , LocalDepth depth , int slice , int z , std::vector< _SlabValues< Vertex > >& slabValues , const struct _Evaluator< FEMDegree , BType >& evaluator , int threads ) -{ - typename Octree::template _SliceValues< Vertex >& sValues = slabValues[depth].sliceValues( slice ); - std::vector< ConstPointSupportKey< FEMDegree > > neighborKeys( std::max< int >( 1 , threads ) ); - for( size_t i=0 ; i& neighborKey = neighborKeys[ omp_get_thread_num() ]; - TreeOctNode* leaf = _sNodes.treeNodes[i]; - if( !IsActiveNode( leaf->children ) ) - { - const typename SortedTreeNodes::SquareCornerIndices& cIndices = sValues.sliceData.cornerIndices( leaf ); - - bool isInterior = _isInteriorlySupported< FEMDegree >( leaf->parent ); - neighborKey.getNeighbors( leaf ); - - for( int x=0 ; x<2 ; x++ ) for( int y=0 ; y<2 ; y++ ) - { - int cc = Cube::CornerIndex( x , y , z ); - int fc = Square::CornerIndex( x , y ); - int vIndex = cIndices[fc]; - if( !sValues.cornerSet[vIndex] ) - { - if( sValues.cornerGradients ) - { - std::pair< Real , Point3D< Real > > p = _getCornerValueAndGradient( neighborKey , leaf , cc , solution , coarseSolution , evaluator , isInterior ); - sValues.cornerValues[vIndex] = p.first , sValues.cornerGradients[vIndex] = p.second; - } - else sValues.cornerValues[vIndex] = _getCornerValue( neighborKey , leaf , cc , solution , coarseSolution , evaluator , isInterior ); - sValues.cornerSet[vIndex] = 1; - } - squareValues[fc] = sValues.cornerValues[ vIndex ]; - TreeOctNode* node = leaf; - LocalDepth _depth = depth; - int _slice = slice; - while( _isValidSpaceNode( node->parent ) && (node-node->parent->children)==cc ) - { - node = node->parent , _depth-- , _slice >>= 1; - typename Octree::template _SliceValues< Vertex >& _sValues = slabValues[_depth].sliceValues( _slice ); - const typename SortedTreeNodes::SquareCornerIndices& _cIndices = _sValues.sliceData.cornerIndices( node ); - int _vIndex = _cIndices[fc]; - _sValues.cornerValues[_vIndex] = sValues.cornerValues[vIndex]; - if( _sValues.cornerGradients ) _sValues.cornerGradients[_vIndex] = sValues.cornerGradients[vIndex]; - _sValues.cornerSet[_vIndex] = 1; - } - } - sValues.mcIndices[ i - sValues.sliceData.nodeOffset ] = MarchingSquares::GetIndex( squareValues , isoValue ); - } - } -} - -template< class Real > -template< int WeightDegree , int ColorDegree , BoundaryType BType , class Vertex > -void Octree< Real >::_setSliceIsoVertices( const BSplineData< ColorDegree , BType >* colorBSData , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Point3D< Real > , Real > , ColorDegree >* colorData , Real isoValue , LocalDepth depth , int slice , int& vOffset , CoredMeshData< Vertex >& mesh , std::vector< _SlabValues< Vertex > >& slabValues , int threads ) -{ - if( slice>0 ) _setSliceIsoVertices< WeightDegree , ColorDegree >( colorBSData , densityWeights , colorData , isoValue , depth , slice , 1 , vOffset , mesh , slabValues , threads ); - if( slice<(1<( colorBSData , densityWeights , colorData , isoValue , depth , slice , 0 , vOffset , mesh , slabValues , threads ); -} -template< class Real > -template< int WeightDegree , int ColorDegree , BoundaryType BType , class Vertex > -void Octree< Real >::_setSliceIsoVertices( const BSplineData< ColorDegree , BType >* colorBSData , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Point3D< Real > , Real > , ColorDegree >* colorData , Real isoValue , LocalDepth depth , int slice , int z , int& vOffset , CoredMeshData< Vertex >& mesh , std::vector< _SlabValues< Vertex > >& slabValues , int threads ) -{ - typename Octree::template _SliceValues< Vertex >& sValues = slabValues[depth].sliceValues( slice ); - // [WARNING] In the case Degree=2, these two keys are the same, so we don't have to maintain them separately. - std::vector< ConstAdjacenctNodeKey > neighborKeys( std::max< int >( 1 , threads ) ); - std::vector< ConstPointSupportKey< WeightDegree > > weightKeys( std::max< int >( 1 , threads ) ); - std::vector< ConstPointSupportKey< ColorDegree > > colorKeys( std::max< int >( 1 , threads ) ); - for( size_t i=0 ; i& weightKey = weightKeys[ omp_get_thread_num() ]; - ConstPointSupportKey< ColorDegree >& colorKey = colorKeys[ omp_get_thread_num() ]; - TreeOctNode* leaf = _sNodes.treeNodes[i]; - if( !IsActiveNode( leaf->children ) ) - { - int idx = i - sValues.sliceData.nodeOffset; - const typename SortedTreeNodes::SquareEdgeIndices& eIndices = sValues.sliceData.edgeIndices( leaf ); - if( MarchingSquares::HasRoots( sValues.mcIndices[idx] ) ) - { - neighborKey.getNeighbors( leaf ); - if( densityWeights ) weightKey.getNeighbors( leaf ); - if( colorData ) colorKey.getNeighbors( leaf ); - for( int e=0 ; e hashed_vertex; -#pragma omp critical (add_point_access) - { - if( !sValues.edgeSet[vIndex] ) - { - mesh.addOutOfCorePoint( vertex ); - sValues.edgeSet[ vIndex ] = 1; - sValues.edgeKeys[ vIndex ] = key; - sValues.edgeVertexMap[key] = hashed_vertex = std::pair< int , Vertex >( vOffset , vertex ); - vOffset++; - stillOwner = true; - } - } - if( stillOwner ) - { - // We only need to pass the iso-vertex down if the edge it lies on is adjacent to a coarser leaf - bool isNeeded; - switch( o ) - { - case 0: isNeeded = ( !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[1][2*y][1] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[1][2*y][2*z] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[1][1][2*z] ) ) ; break; - case 1: isNeeded = ( !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[2*y][1][1] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[2*y][1][2*z] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[1][1][2*z] ) ) ; break; - } - if( isNeeded ) - { - int f[2]; - Cube::FacesAdjacentToEdge( Cube::EdgeIndex( o , y , z ) , f[0] , f[1] ); - for( int k=0 ; k<2 ; k++ ) - { - TreeOctNode* node = leaf; - LocalDepth _depth = depth; - int _slice = slice; - bool _isNeeded = isNeeded; - while( _isNeeded && _isValidSpaceNode( node->parent ) && Cube::IsFaceCorner( (int)(node-node->parent->children) , f[k] ) ) - { - node = node->parent , _depth-- , _slice >>= 1; - typename Octree::template _SliceValues< Vertex >& _sValues = slabValues[_depth].sliceValues( _slice ); -#pragma omp critical (add_coarser_point_access) - _sValues.edgeVertexMap[key] = hashed_vertex; - switch( o ) - { - case 0: _isNeeded = ( !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[1][2*y][1] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[1][2*y][2*z] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[1][1][2*z] ) ) ; break; - case 1: _isNeeded = ( !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[2*y][1][1] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[2*y][1][2*z] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[1][1][2*z] ) ) ; break; - } - } - } - } - } - } - } - } - } - } -} -template< class Real > -template< int WeightDegree , int ColorDegree , BoundaryType BType , class Vertex > -void Octree< Real >::_setXSliceIsoVertices( const BSplineData< ColorDegree , BType >* colorBSData , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Point3D< Real > , Real > , ColorDegree >* colorData , Real isoValue , LocalDepth depth , int slab , int& vOffset , CoredMeshData< Vertex >& mesh , std::vector< _SlabValues< Vertex > >& slabValues , int threads ) -{ - typename Octree::template _SliceValues< Vertex >& bValues = slabValues[depth].sliceValues ( slab ); - typename Octree::template _SliceValues< Vertex >& fValues = slabValues[depth].sliceValues ( slab+1 ); - typename Octree::template _XSliceValues< Vertex >& xValues = slabValues[depth].xSliceValues( slab ); - - // [WARNING] In the case Degree=2, these two keys are the same, so we don't have to maintain them separately. - std::vector< ConstAdjacenctNodeKey > neighborKeys( std::max< int >( 1 , threads ) ); - std::vector< ConstPointSupportKey< WeightDegree > > weightKeys( std::max< int >( 1 , threads ) ); - std::vector< ConstPointSupportKey< ColorDegree > > colorKeys( std::max< int >( 1 , threads ) ); - for( size_t i=0 ; i& weightKey = weightKeys[ omp_get_thread_num() ]; - ConstPointSupportKey< ColorDegree >& colorKey = colorKeys[ omp_get_thread_num() ]; - TreeOctNode* leaf = _sNodes.treeNodes[i]; - if( !IsActiveNode( leaf->children ) ) - { - unsigned char mcIndex = ( bValues.mcIndices[ i - bValues.sliceData.nodeOffset ] ) | ( fValues.mcIndices[ i - fValues.sliceData.nodeOffset ] )<<4; - const typename SortedTreeNodes::SquareCornerIndices& eIndices = xValues.xSliceData.edgeIndices( leaf ); - if( MarchingCubes::HasRoots( mcIndex ) ) - { - neighborKey.getNeighbors( leaf ); - if( densityWeights ) weightKey.getNeighbors( leaf ); - if( colorData ) colorKey.getNeighbors( leaf ); - for( int x=0 ; x<2 ; x++ ) for( int y=0 ; y<2 ; y++ ) - { - int c = Square::CornerIndex( x , y ); - int e = Cube::EdgeIndex( 2 , x , y ); - if( MarchingCubes::HasEdgeRoots( mcIndex , e ) ) - { - int vIndex = eIndices[c]; - if( !xValues.edgeSet[vIndex] ) - { - Vertex vertex; - long long key = VertexData::EdgeIndex( leaf , e , _localToGlobal(_maxDepth) ); - _getIsoVertex( colorBSData , densityWeights , colorData , isoValue , weightKey , colorKey , leaf , c , bValues , fValues , vertex ); - bool stillOwner = false; - std::pair< int , Vertex > hashed_vertex; -#pragma omp critical (add_x_point_access) - { - if( !xValues.edgeSet[vIndex] ) - { - mesh.addOutOfCorePoint( vertex ); - xValues.edgeSet[ vIndex ] = 1; - xValues.edgeKeys[ vIndex ] = key; - xValues.edgeVertexMap[key] = hashed_vertex = std::pair< int , Vertex >( vOffset , vertex ); - stillOwner = true; - vOffset++; - } - } - if( stillOwner ) - { - // We only need to pass the iso-vertex down if the edge it lies on is adjacent to a coarser leaf - bool isNeeded = ( !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[2*x][1][1] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[2*x][2*y][1] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[1][2*y][1] ) ); - if( isNeeded ) - { - int f[2]; - Cube::FacesAdjacentToEdge( e , f[0] , f[1] ); - for( int k=0 ; k<2 ; k++ ) - { - TreeOctNode* node = leaf; - LocalDepth _depth = depth; - int _slab = slab; - bool _isNeeded = isNeeded; - while( _isNeeded && _isValidSpaceNode( node->parent ) && Cube::IsFaceCorner( (int)(node-node->parent->children) , f[k] ) ) - { - node = node->parent , _depth-- , _slab >>= 1; - typename Octree::template _XSliceValues< Vertex >& _xValues = slabValues[_depth].xSliceValues( _slab ); -#pragma omp critical (add_x_coarser_point_access) - _xValues.edgeVertexMap[key] = hashed_vertex; - _isNeeded = ( !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[2*x][1][1] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[2*x][2*y][1] ) || !_isValidSpaceNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[1][2*y][1] ) ); - } - } - } - } - } - } - } - } - } - } -} -template< class Real > -template< class Vertex > -void Octree< Real >::_copyFinerSliceIsoEdgeKeys( LocalDepth depth , int slice , std::vector< _SlabValues< Vertex > >& slabValues , int threads ) -{ - if( slice>0 ) _copyFinerSliceIsoEdgeKeys( depth , slice , 1 , slabValues , threads ); - if( slice<(1< -template< class Vertex > -void Octree< Real >::_copyFinerSliceIsoEdgeKeys( LocalDepth depth , int slice , int z , std::vector< _SlabValues< Vertex > >& slabValues , int threads ) -{ - _SliceValues< Vertex >& pSliceValues = slabValues[depth ].sliceValues(slice ); - _SliceValues< Vertex >& cSliceValues = slabValues[depth+1].sliceValues(slice<<1); - typename SortedTreeNodes::SliceTableData& pSliceData = pSliceValues.sliceData; - typename SortedTreeNodes::SliceTableData& cSliceData = cSliceValues.sliceData; -#pragma omp parallel for num_threads( threads ) - for( int i=_sNodesBegin(depth,slice-z) ; i<_sNodesEnd(depth,slice-z) ; i++ ) if( _isValidSpaceNode( _sNodes.treeNodes[i] ) ) - if( IsActiveNode( _sNodes.treeNodes[i]->children ) ) - { - typename SortedTreeNodes::SquareEdgeIndices& pIndices = pSliceData.edgeIndices( i ); - // Copy the edges that overlap the coarser edges - for( int orientation=0 ; orientation<2 ; orientation++ ) for( int y=0 ; y<2 ; y++ ) - { - int fe = Square::EdgeIndex( orientation , y ); - int pIndex = pIndices[fe]; - if( !pSliceValues.edgeSet[ pIndex ] ) - { - int ce = Cube::EdgeIndex( orientation , y , z ); - int c1 , c2; - switch( orientation ) - { - case 0: c1 = Cube::CornerIndex( 0 , y , z ) , c2 = Cube::CornerIndex( 1 , y , z ) ; break; - case 1: c1 = Cube::CornerIndex( y , 0 , z ) , c2 = Cube::CornerIndex( y , 1 , z ) ; break; - } - // [SANITY CHECK] -// if( _isValidSpaceNode( _sNodes.treeNodes[i]->children + c1 )!=_isValidSpaceNode( _sNodes.treeNodes[i]->children + c2 ) ) fprintf( stderr , "[WARNING] Finer edges should both be valid or invalid\n" ) , exit( 0 ); - if( !_isValidSpaceNode( _sNodes.treeNodes[i]->children + c1 ) || !_isValidSpaceNode( _sNodes.treeNodes[i]->children + c2 ) ) continue; - - int cIndex1 = cSliceData.edgeIndices( _sNodes.treeNodes[i]->children + c1 )[fe]; - int cIndex2 = cSliceData.edgeIndices( _sNodes.treeNodes[i]->children + c2 )[fe]; - if( cSliceValues.edgeSet[cIndex1] != cSliceValues.edgeSet[cIndex2] ) - { - long long key; - if( cSliceValues.edgeSet[cIndex1] ) key = cSliceValues.edgeKeys[cIndex1]; - else key = cSliceValues.edgeKeys[cIndex2]; - std::pair< int , Vertex > vPair = cSliceValues.edgeVertexMap.find( key )->second; -#pragma omp critical ( copy_finer_edge_keys ) - pSliceValues.edgeVertexMap[key] = vPair; - pSliceValues.edgeKeys[pIndex] = key; - pSliceValues.edgeSet[pIndex] = 1; - } - else if( cSliceValues.edgeSet[cIndex1] && cSliceValues.edgeSet[cIndex2] ) - { - long long key1 = cSliceValues.edgeKeys[cIndex1] , key2 = cSliceValues.edgeKeys[cIndex2]; -#pragma omp critical ( set_edge_pairs ) - pSliceValues.vertexPairMap[ key1 ] = key2 , pSliceValues.vertexPairMap[ key2 ] = key1; - - const TreeOctNode* node = _sNodes.treeNodes[i]; - LocalDepth _depth = depth; - int _slice = slice; - while( _isValidSpaceNode( node->parent ) && Cube::IsEdgeCorner( (int)( node - node->parent->children ) , ce ) ) - { - node = node->parent , _depth-- , _slice >>= 1; - _SliceValues< Vertex >& _pSliceValues = slabValues[_depth].sliceValues(_slice); -#pragma omp critical ( set_edge_pairs ) - _pSliceValues.vertexPairMap[ key1 ] = key2 , _pSliceValues.vertexPairMap[ key2 ] = key1; - } - } - } - } - } -} -template< class Real > -template< class Vertex > -void Octree< Real >::_copyFinerXSliceIsoEdgeKeys( LocalDepth depth , int slab , std::vector< _SlabValues< Vertex > >& slabValues , int threads ) -{ - _XSliceValues< Vertex >& pSliceValues = slabValues[depth ].xSliceValues(slab); - _XSliceValues< Vertex >& cSliceValues0 = slabValues[depth+1].xSliceValues( (slab<<1)|0 ); - _XSliceValues< Vertex >& cSliceValues1 = slabValues[depth+1].xSliceValues( (slab<<1)|1 ); - typename SortedTreeNodes::XSliceTableData& pSliceData = pSliceValues.xSliceData; - typename SortedTreeNodes::XSliceTableData& cSliceData0 = cSliceValues0.xSliceData; - typename SortedTreeNodes::XSliceTableData& cSliceData1 = cSliceValues1.xSliceData; -#pragma omp parallel for num_threads( threads ) - for( int i=_sNodesBegin(depth,slab) ; i<_sNodesEnd(depth,slab) ; i++ ) if( _isValidSpaceNode( _sNodes.treeNodes[i] ) ) - if( IsActiveNode( _sNodes.treeNodes[i]->children ) ) - { - typename SortedTreeNodes::SquareCornerIndices& pIndices = pSliceData.edgeIndices( i ); - for( int x=0 ; x<2 ; x++ ) for( int y=0 ; y<2 ; y++ ) - { - int fc = Square::CornerIndex( x , y ); - int pIndex = pIndices[fc]; - if( !pSliceValues.edgeSet[pIndex] ) - { - int c0 = Cube::CornerIndex( x , y , 0 ) , c1 = Cube::CornerIndex( x , y , 1 ); - - // [SANITY CHECK] -// if( _isValidSpaceNode( _sNodes.treeNodes[i]->children + c0 )!=_isValidSpaceNode( _sNodes.treeNodes[i]->children + c1 ) ) fprintf( stderr , "[ERROR] Finer edges should both be valid or invalid\n" ) , exit( 0 ); - if( !_isValidSpaceNode( _sNodes.treeNodes[i]->children + c0 ) || !_isValidSpaceNode( _sNodes.treeNodes[i]->children + c1 ) ) continue; - - int cIndex0 = cSliceData0.edgeIndices( _sNodes.treeNodes[i]->children + c0 )[fc]; - int cIndex1 = cSliceData1.edgeIndices( _sNodes.treeNodes[i]->children + c1 )[fc]; - if( cSliceValues0.edgeSet[cIndex0] != cSliceValues1.edgeSet[cIndex1] ) - { - long long key; - std::pair< int , Vertex > vPair; - if( cSliceValues0.edgeSet[cIndex0] ) key = cSliceValues0.edgeKeys[cIndex0] , vPair = cSliceValues0.edgeVertexMap.find( key )->second; - else key = cSliceValues1.edgeKeys[cIndex1] , vPair = cSliceValues1.edgeVertexMap.find( key )->second; -#pragma omp critical ( copy_finer_x_edge_keys ) - pSliceValues.edgeVertexMap[key] = vPair; - pSliceValues.edgeKeys[ pIndex ] = key; - pSliceValues.edgeSet[ pIndex ] = 1; - } - else if( cSliceValues0.edgeSet[cIndex0] && cSliceValues1.edgeSet[cIndex1] ) - { - long long key0 = cSliceValues0.edgeKeys[cIndex0] , key1 = cSliceValues1.edgeKeys[cIndex1]; -#pragma omp critical ( set_x_edge_pairs ) - pSliceValues.vertexPairMap[ key0 ] = key1 , pSliceValues.vertexPairMap[ key1 ] = key0; - const TreeOctNode* node = _sNodes.treeNodes[i]; - LocalDepth _depth = depth; - int _slab = slab , ce = Cube::CornerIndex( 2 , x , y ); - while( _isValidSpaceNode( node->parent ) && Cube::IsEdgeCorner( (int)( node - node->parent->children ) , ce ) ) - { - node = node->parent , _depth-- , _slab>>= 1; - _SliceValues< Vertex >& _pSliceValues = slabValues[_depth].sliceValues(_slab); -#pragma omp critical ( set_x_edge_pairs ) - _pSliceValues.vertexPairMap[ key0 ] = key1 , _pSliceValues.vertexPairMap[ key1 ] = key0; - } - } - } - } - } -} -template< class Real > -template< class Vertex > -void Octree< Real >::_setSliceIsoEdges( LocalDepth depth , int slice , std::vector< _SlabValues< Vertex > >& slabValues , int threads ) -{ - if( slice>0 ) _setSliceIsoEdges( depth , slice , 1 , slabValues , threads ); - if( slice<(1< -template< class Vertex > -void Octree< Real >::_setSliceIsoEdges( LocalDepth depth , int slice , int z , std::vector< _SlabValues< Vertex > >& slabValues , int threads ) -{ - typename Octree::template _SliceValues< Vertex >& sValues = slabValues[depth].sliceValues( slice ); - std::vector< ConstAdjacenctNodeKey > neighborKeys( std::max< int >( 1 , threads ) ); - for( size_t i=0 ; ichildren ) ) - { - int idx = i - sValues.sliceData.nodeOffset; - const typename SortedTreeNodes::SquareEdgeIndices& eIndices = sValues.sliceData.edgeIndices( leaf ); - const typename SortedTreeNodes::SquareFaceIndices& fIndices = sValues.sliceData.faceIndices( leaf ); - unsigned char mcIndex = sValues.mcIndices[idx]; - if( !sValues.faceSet[ fIndices[0] ] ) - { - neighborKey.getNeighbors( leaf ); - if( !IsActiveNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[1][1][2*z] ) || !IsActiveNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[1][1][2*z]->children ) ) - { - _FaceEdges fe; - fe.count = MarchingSquares::AddEdgeIndices( mcIndex , isoEdges ); - for( int j=0 ; j edges; - edges.resize( fe.count ); - for( int j=0 ; jparent ) && Cube::IsFaceCorner( (int)(node-node->parent->children) , f ) ) - { - node = node->parent , _depth-- , _slice >>= 1; - if( IsActiveNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[1][1][2*z] ) && IsActiveNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[1][1][2*z]->children ) ) break; - long long key = VertexData::FaceIndex( node , f , _localToGlobal(_maxDepth) ); -#pragma omp critical( add_iso_edge_access ) - { - typename Octree::template _SliceValues< Vertex >& _sValues = slabValues[_depth].sliceValues( _slice ); - typename std::unordered_map< long long, std::vector< _IsoEdge > >::iterator iter = _sValues.faceEdgeMap.find(key); - if( iter==_sValues.faceEdgeMap.end() ) _sValues.faceEdgeMap[key] = edges; - else for( int j=0 ; jsecond.push_back( fe.edges[j] ); - } - } - } - } - } - } -} -template< class Real > -template< class Vertex > -void Octree< Real >::_setXSliceIsoEdges( LocalDepth depth , int slab , std::vector< _SlabValues< Vertex > >& slabValues , int threads ) -{ - typename Octree::template _SliceValues< Vertex >& bValues = slabValues[depth].sliceValues ( slab ); - typename Octree::template _SliceValues< Vertex >& fValues = slabValues[depth].sliceValues ( slab+1 ); - typename Octree::template _XSliceValues< Vertex >& xValues = slabValues[depth].xSliceValues( slab ); - - std::vector< ConstAdjacenctNodeKey > neighborKeys( std::max< int >( 1 , threads ) ); - for( size_t i=0 ; ichildren ) ) - { - const typename SortedTreeNodes::SquareCornerIndices& cIndices = xValues.xSliceData.edgeIndices( leaf ); - const typename SortedTreeNodes::SquareEdgeIndices& eIndices = xValues.xSliceData.faceIndices( leaf ); - unsigned char mcIndex = ( bValues.mcIndices[ i - bValues.sliceData.nodeOffset ] ) | ( fValues.mcIndices[ i - fValues.sliceData.nodeOffset ]<<4 ); - { - neighborKey.getNeighbors( leaf ); - for( int o=0 ; o<2 ; o++ ) for( int x=0 ; x<2 ; x++ ) - { - int e = Square::EdgeIndex( o , x ); - int f = Cube::FaceIndex( 1-o , x ); - unsigned char _mcIndex = MarchingCubes::GetFaceIndex( mcIndex , f ); - int xx = o==1 ? 2*x : 1 , yy = o==0 ? 2*x : 1 , zz = 1; - if( !xValues.faceSet[ eIndices[e] ] && ( !IsActiveNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[xx][yy][zz] ) || !IsActiveNode( neighborKey.neighbors[ _localToGlobal( depth ) ].neighbors[xx][yy][zz]->children ) ) ) - { - _FaceEdges fe; - fe.count = MarchingSquares::AddEdgeIndices( _mcIndex , isoEdges ); - for( int j=0 ; j& sValues = (_x==0) ? bValues : fValues; - int idx = sValues.sliceData.edgeIndices(i)[ Square::EdgeIndex(o,x) ]; - if( !sValues.edgeSet[ idx ] ) fprintf( stderr , "[ERROR] Edge not set 5: %d / %d\n" , slab , 1< edges; - edges.resize( fe.count ); - for( int j=0 ; jparent ) && Cube::IsFaceCorner( (int)(node-node->parent->children) , f ) ) - { - node = node->parent , _depth-- , _slab >>= 1; - if( IsActiveNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[xx][yy][zz] ) && IsActiveNode( neighborKey.neighbors[ _localToGlobal( _depth ) ].neighbors[xx][yy][zz]->children ) ) break; - long long key = VertexData::FaceIndex( node , f , _localToGlobal(_maxDepth) ); -#pragma omp critical( add_x_iso_edge_access ) - { - typename Octree::template _XSliceValues< Vertex >& _xValues = slabValues[_depth].xSliceValues( _slab ); - typename std::unordered_map< long long, std::vector< _IsoEdge > >::iterator iter = _xValues.faceEdgeMap.find(key); - if( iter==_xValues.faceEdgeMap.end() ) _xValues.faceEdgeMap[key] = edges; - else for( int j=0 ; jsecond.push_back( fe.edges[j] ); - } - } - } - } - } - } - } -} -template< class Real > -template< class Vertex > -void Octree< Real >::_setIsoSurface( LocalDepth depth , int offset , const _SliceValues< Vertex >& bValues , const _SliceValues< Vertex >& fValues , const _XSliceValues< Vertex >& xValues , CoredMeshData< Vertex >& mesh , bool polygonMesh , bool addBarycenter , int& vOffset , int threads ) -{ - std::vector< std::pair< int , Vertex > > polygon; - std::vector< std::vector< _IsoEdge > > edgess( std::max< int >( 1 , threads ) ); -#pragma omp parallel for num_threads( threads ) - for( int i=_sNodesBegin(depth,offset) ; i<_sNodesEnd(depth,offset) ; i++ ) if( _isValidSpaceNode( _sNodes.treeNodes[i] ) ) - { - std::vector< _IsoEdge >& edges = edgess[ omp_get_thread_num() ]; - TreeOctNode* leaf = _sNodes.treeNodes[i]; - int res = 1<=0 && off[0]=0 && off[1]=0 && off[2]children ) ) - { - edges.clear(); - unsigned char mcIndex = ( bValues.mcIndices[ i - bValues.sliceData.nodeOffset ] ) | ( fValues.mcIndices[ i - fValues.sliceData.nodeOffset ]<<4 ); - // [WARNING] Just because the node looks empty doesn't mean it doesn't get eges from finer neighbors - { - // Gather the edges from the faces (with the correct orientation) - for( int f=0 ; f& sValues = (o==0) ? bValues : fValues; - int fIdx = sValues.sliceData.faceIndices(i)[0]; - if( sValues.faceSet[fIdx] ) - { - const _FaceEdges& fe = sValues.faceEdges[ fIdx ]; - for( int j=0 ; j >::const_iterator iter = sValues.faceEdgeMap.find(key); - if( iter!=sValues.faceEdgeMap.end() ) - { - const std::vector< _IsoEdge >& _edges = iter->second; - for( size_t j=0 ; j<_edges.size() ; j++ ) edges.push_back( _IsoEdge( _edges[j][flip] , _edges[j][1-flip] ) ); - } - else fprintf( stderr , "[ERROR] Invalid faces: %d %d %d\n" , i , d , o ) , exit( 0 ); - } - } - else - { - int fIdx = xValues.xSliceData.faceIndices(i)[ Square::EdgeIndex( 1-d , o ) ]; - if( xValues.faceSet[fIdx] ) - { - const _FaceEdges& fe = xValues.faceEdges[ fIdx ]; - for( int j=0 ; j >::const_iterator iter = xValues.faceEdgeMap.find(key); - if( iter!=xValues.faceEdgeMap.end() ) - { - const std::vector< _IsoEdge >& _edges = iter->second; - for( size_t j=0 ; j<_edges.size() ; j++ ) edges.push_back( _IsoEdge( _edges[j][flip] , _edges[j][1-flip] ) ); - } - else fprintf( stderr , "[ERROR] Invalid faces: %d %d %d\n" , i , d , o ) , exit( 0 ); - } - } - } - // Get the edge loops - std::vector< std::vector< long long > > loops; - while( edges.size() ) - { - loops.resize( loops.size()+1 ); - _IsoEdge edge = edges.back(); - edges.pop_back(); - long long start = edge[0] , current = edge[1]; - while( current!=start ) - { - int idx; - for( idx=0 ; idx<(int)edges.size() ; idx++ ) if( edges[idx][0]==current ) break; - if( idx==edges.size() ) - { - typename std::unordered_map< long long, long long >::const_iterator iter; - if ( (iter=bValues.vertexPairMap.find(current))!=bValues.vertexPairMap.end() ) loops.back().push_back( current ) , current = iter->second; - else if( (iter=fValues.vertexPairMap.find(current))!=fValues.vertexPairMap.end() ) loops.back().push_back( current ) , current = iter->second; - else if( (iter=xValues.vertexPairMap.find(current))!=xValues.vertexPairMap.end() ) loops.back().push_back( current ) , current = iter->second; - else - { - LocalDepth d ; LocalOffset off; - _localDepthAndOffset( leaf , d , off ); - fprintf( stderr , "[ERROR] Failed to close loop [%d: %d %d %d] | (%d): %lld\n" , d-1 , off[0] , off[1] , off[2] , i , current ); - exit( 0 ); - } - } - else - { - loops.back().push_back( current ); - current = edges[idx][1]; - edges[idx] = edges.back() , edges.pop_back(); - } - } - loops.back().push_back( start ); - } - // Add the loops to the mesh - for( size_t j=0 ; j > polygon( loops[j].size() ); - for( size_t k=0 ; k >::const_iterator iter; - if ( ( iter=bValues.edgeVertexMap.find( key ) )!=bValues.edgeVertexMap.end() ) polygon[k] = iter->second; - else if( ( iter=fValues.edgeVertexMap.find( key ) )!=fValues.edgeVertexMap.end() ) polygon[k] = iter->second; - else if( ( iter=xValues.edgeVertexMap.find( key ) )!=xValues.edgeVertexMap.end() ) polygon[k] = iter->second; - else fprintf( stderr , "[ERROR] Couldn't find vertex in edge map\n" ) , exit( 0 ); - } - _addIsoPolygons( mesh , polygon , polygonMesh , addBarycenter , vOffset ); - } - } - } - } -} -template< class Real > void SetColor( Point3D< Real >& color , unsigned char c[3] ){ for( int i=0 ; i<3 ; i++ ) c[i] = (unsigned char)std::max< int >( 0 , std::min< int >( 255 , (int)( color[i]+0.5 ) ) ); } - -template< class Real > void SetIsoVertex( PlyVertex< float >& vertex , Point3D< Real > color , Real value ){ ; } -template< class Real > void SetIsoVertex( PlyColorVertex< float >& vertex , Point3D< Real > color , Real value ){ SetColor( color , vertex.color ); } -template< class Real > void SetIsoVertex( PlyValueVertex< float >& vertex , Point3D< Real > color , Real value ){ vertex.value = float(value); } -template< class Real > void SetIsoVertex( PlyColorAndValueVertex< float >& vertex , Point3D< Real > color , Real value ){ SetColor( color , vertex.color ) , vertex.value = float(value); } -template< class Real > void SetIsoVertex( PlyVertex< double >& vertex , Point3D< Real > color , Real value ){ ; } -template< class Real > void SetIsoVertex( PlyColorVertex< double >& vertex , Point3D< Real > color , Real value ){ SetColor( color , vertex.color ); } -template< class Real > void SetIsoVertex( PlyValueVertex< double >& vertex , Point3D< Real > color , Real value ){ vertex.value = double(value); } -template< class Real > void SetIsoVertex( PlyColorAndValueVertex< double >& vertex , Point3D< Real > color , Real value ){ SetColor( color , vertex.color ) , vertex.value = double(value); } - -template< class Real > -template< int WeightDegree , int ColorDegree , BoundaryType BType , class Vertex > -bool Octree< Real >::_getIsoVertex( const BSplineData< ColorDegree , BType >* colorBSData , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Point3D< Real > , Real > , ColorDegree >* colorData , Real isoValue , ConstPointSupportKey< WeightDegree >& weightKey , ConstPointSupportKey< ColorDegree >& colorKey , const TreeOctNode* node , int edgeIndex , int z , const _SliceValues< Vertex >& sValues , Vertex& vertex ) -{ - Point3D< Real > position; - int c0 , c1; - Square::EdgeCorners( edgeIndex , c0 , c1 ); - - bool nonLinearFit = sValues.cornerGradients!=NullPointer( Point3D< Real > ); - const typename SortedTreeNodes::SquareCornerIndices& idx = sValues.sliceData.cornerIndices( node ); - Real x0 = sValues.cornerValues[idx[c0]] , x1 = sValues.cornerValues[idx[c1]]; - Point3D< Real > s; - Real start , width; - _startAndWidth( node , s , width ); - int o , y; - Square::FactorEdgeIndex( edgeIndex , o , y ); - start = s[o]; - switch( o ) - { - case 0: - position[1] = s[1] + width*y; - position[2] = s[2] + width*z; - break; - case 1: - position[0] = s[0] + width*y; - position[2] = s[2] + width*z; - break; - } - - double averageRoot; - bool rootFound = false; - if( nonLinearFit ) - { - double dx0 = sValues.cornerGradients[idx[c0]][o] * width , dx1 = sValues.cornerGradients[idx[c1]][o] * width; - - // The scaling will turn the Hermite Spline into a quadratic - double scl = (x1-x0) / ( (dx1+dx0 ) / 2 ); - dx0 *= scl , dx1 *= scl; - - // Hermite Spline - Polynomial< 2 > P; - P.coefficients[0] = x0; - P.coefficients[1] = dx0; - P.coefficients[2] = 3*(x1-x0)-dx1-2*dx0; - - double roots[2]; - int rCount = 0 , rootCount = P.getSolutions( isoValue , roots , 0 ); - averageRoot = 0; - for( int i=0 ; i=0 && roots[i]<=1 ) averageRoot += roots[i] , rCount++; - if( rCount ) rootFound = true; - averageRoot /= rCount; - } - if( !rootFound ) - { - // We have a linear function L, with L(0) = x0 and L(1) = x1 - // => L(t) = x0 + t * (x1-x0) - // => L(t) = isoValue <=> t = ( isoValue - x0 ) / ( x1 - x0 ) - if( x0==x1 ) fprintf( stderr , "[ERROR] Not a zero-crossing root: %g %g\n" , x0 , x1 ) , exit( 0 ); - averageRoot = ( isoValue - x0 ) / ( x1 - x0 ); - } - if( averageRoot<0 || averageRoot>1 ) - { - fprintf( stderr , "[WARNING] Bad average root: %f\n" , averageRoot ); - fprintf( stderr , "\t(%f %f) (%f)\n" , x0 , x1 , isoValue ); - if( averageRoot<0 ) averageRoot = 0; - if( averageRoot>1 ) averageRoot = 1; - } - position[o] = Real( start + width*averageRoot ); - vertex.point = position; - Point3D< Real > color; - Real depth(0); - if( densityWeights ) - { - Real weight; - _getSampleDepthAndWeight( *densityWeights , node , position , weightKey , depth , weight ); - } - if( colorData ) color = Point3D< Real >( _evaluate< ProjectiveData< Point3D< Real > , Real > >( *colorData , position , *colorBSData , colorKey ) ); - SetIsoVertex( vertex , color , depth ); - return true; -} -template< class Real > -template< int WeightDegree , int ColorDegree , BoundaryType BType , class Vertex > -bool Octree< Real >::_getIsoVertex( const BSplineData< ColorDegree , BType >* colorBSData , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Point3D< Real > , Real > , ColorDegree >* colorData , Real isoValue , ConstPointSupportKey< WeightDegree >& weightKey , ConstPointSupportKey< ColorDegree >& colorKey , const TreeOctNode* node , int cornerIndex , const _SliceValues< Vertex >& bValues , const _SliceValues< Vertex >& fValues , Vertex& vertex ) -{ - Point3D< Real > position; - - bool nonLinearFit = bValues.cornerGradients!=NullPointer( Point3D< Real > ) && fValues.cornerGradients!=NullPointer( Point3D< Real > ); - const typename SortedTreeNodes::SquareCornerIndices& idx0 = bValues.sliceData.cornerIndices( node ); - const typename SortedTreeNodes::SquareCornerIndices& idx1 = fValues.sliceData.cornerIndices( node ); - Real x0 = bValues.cornerValues[ idx0[cornerIndex] ] , x1 = fValues.cornerValues[ idx1[cornerIndex] ]; - Point3D< Real > s; - Real start , width; - _startAndWidth( node , s , width ); - start = s[2]; - int x , y; - Square::FactorCornerIndex( cornerIndex , x , y ); - - - position[0] = s[0] + width*x; - position[1] = s[1] + width*y; - - double averageRoot; - - bool rootFound = false; - if( nonLinearFit ) - { - double dx0 = bValues.cornerGradients[ idx0[cornerIndex] ][2] * width , dx1 = fValues.cornerGradients[ idx1[cornerIndex] ][2] * width; - // The scaling will turn the Hermite Spline into a quadratic - double scl = (x1-x0) / ( (dx1+dx0 ) / 2 ); - dx0 *= scl , dx1 *= scl; - - // Hermite Spline - Polynomial< 2 > P; - P.coefficients[0] = x0; - P.coefficients[1] = dx0; - P.coefficients[2] = 3*(x1-x0)-dx1-2*dx0; - - double roots[2]; - int rCount = 0 , rootCount = P.getSolutions( isoValue , roots , 0 ); - averageRoot = 0; - for( int i=0 ; i=0 && roots[i]<=1 ) averageRoot += roots[i] , rCount++; - if( rCount ) rootFound = true; - averageRoot /= rCount; - } - if( !rootFound ) - { - // We have a linear function L, with L(0) = x0 and L(1) = x1 - // => L(t) = x0 + t * (x1-x0) - // => L(t) = isoValue <=> t = ( isoValue - x0 ) / ( x1 - x0 ) - if( x0==x1 ) fprintf( stderr , "[ERROR] Not a zero-crossing root: %g %g\n" , x0 , x1 ) , exit( 0 ); - averageRoot = ( isoValue - x0 ) / ( x1 - x0 ); - } - if( averageRoot<0 || averageRoot>1 ) - { - fprintf( stderr , "[WARNING] Bad average root: %f\n" , averageRoot ); - fprintf( stderr , "\t(%f %f) (%f)\n" , x0 , x1 , isoValue ); - if( averageRoot<0 ) averageRoot = 0; - if( averageRoot>1 ) averageRoot = 1; - } - position[2] = Real( start + width*averageRoot ); - vertex.point = position; - Point3D< Real > color; - Real depth(0); - if( densityWeights ) - { - Real weight; - _getSampleDepthAndWeight( *densityWeights , node , position , weightKey , depth , weight ); - } - if( colorData ) color = Point3D< Real >( _evaluate< ProjectiveData< Point3D< Real > , Real > >( *colorData , position , *colorBSData , colorKey ) ); - SetIsoVertex( vertex , color , depth ); - return true; -} - -template< class Real > -template< class Vertex > -int Octree< Real >::_addIsoPolygons( CoredMeshData< Vertex >& mesh , std::vector< std::pair< int , Vertex > >& polygon , bool polygonMesh , bool addBarycenter , int& vOffset ) -{ - if( polygonMesh ) - { - std::vector< int > vertices( polygon.size() ); - for( int i=0 ; i<(int)polygon.size() ; i++ ) vertices[i] = polygon[polygon.size()-1-i].first; - mesh.addPolygon_s( vertices ); - return 1; - } - if( polygon.size()>3 ) - { - bool isCoplanar = false; - std::vector< int > triangle( 3 ); - - if( addBarycenter ) - for( int i=0 ; i<(int)polygon.size() ; i++ ) - for( int j=0 ; j MAT; - std::vector< Point3D< Real > > vertices; - std::vector< TriangleIndex > triangles; - vertices.resize( polygon.size() ); - // Add the points - for( int i=0 ; i<(int)polygon.size() ; i++ ) vertices[i] = polygon[i].second.point; - MAT.GetTriangulation( vertices , triangles ); - for( int i=0 ; i<(int)triangles.size() ; i++ ) - { - for( int j=0 ; j<3 ; j++ ) triangle[2-j] = polygon[ triangles[i].idx[j] ].first; - mesh.addPolygon_s( triangle ); - } - } - } - else if( polygon.size()==3 ) - { - std::vector< int > vertices( 3 ); - for( int i=0 ; i<3 ; i++ ) vertices[2-i] = polygon[i].first; - mesh.addPolygon_s( vertices ); - } - return (int)polygon.size()-2; -} diff --git a/Src/MultiGridOctreeData.SortedTreeNodes.inl b/Src/MultiGridOctreeData.SortedTreeNodes.inl deleted file mode 100644 index 7efc9f87..00000000 --- a/Src/MultiGridOctreeData.SortedTreeNodes.inl +++ /dev/null @@ -1,357 +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. -*/ - -///////////////////// -// SortedTreeNodes // -///////////////////// -SortedTreeNodes::SortedTreeNodes( void ) -{ - _sliceStart = NullPointer( Pointer( int ) ); - treeNodes = NullPointer( TreeOctNode* ); - _levels = 0; -} -SortedTreeNodes::~SortedTreeNodes( void ) -{ - if( _sliceStart ) for( int d=0 ; d<_levels ; d++ ) FreePointer( _sliceStart[d] ); - FreePointer( _sliceStart ); - DeletePointer( treeNodes ); -} -void SortedTreeNodes::set( TreeOctNode& root , std::vector< int >* map ) -{ - set( root ); - - if( map ) - { - map->resize( _sliceStart[_levels-1][(size_t)1<<(_levels-1)] ); - for( int i=0 ; i<_sliceStart[_levels-1][(size_t)1<<(_levels-1)] ; i++ ) (*map)[i] = treeNodes[i]->nodeData.nodeIndex; - } - for( int i=0 ; i<_sliceStart[_levels-1][(size_t)1<<(_levels-1)] ; i++ ) treeNodes[i]->nodeData.nodeIndex = i; -} -void SortedTreeNodes::set( TreeOctNode& root ) -{ - _levels = root.maxDepth()+1; - - if( _sliceStart ) for( int d=0 ; d<_levels ; d++ ) FreePointer( _sliceStart[d] ); - FreePointer( _sliceStart ); - DeletePointer( treeNodes ); - - _sliceStart = AllocPointer< Pointer( int ) >( _levels ); - for( int l=0 ; l<_levels ; l++ ) - { - _sliceStart[l] = AllocPointer< int >( ((size_t)1<depthAndOffset( d , off ); - _sliceStart[d][ off[2]+1 ]++; - } - - // Get the start index for each slice - { - int levelOffset = 0; - for( int l=0 ; l<_levels ; l++ ) - { - _sliceStart[l][0] = levelOffset; - for( int s=0 ; s<((size_t)1<( _sliceStart[_levels-1][(size_t)1<<(_levels-1)] ); - - // Add the tree nodes - for( TreeOctNode* node=root.nextNode() ; node ; node=root.nextNode( node ) ) if( !GetGhostFlag( node ) ) - { - int d , off[3]; - node->depthAndOffset( d , off ); - treeNodes[ _sliceStart[d][ off[2] ]++ ] = node; - } - - // Shift the slice offsets up since we incremented as we added - for( int l=0 ; l<_levels ; l++ ) - { - for( int s=(1<0 ; s-- ) _sliceStart[l][s] = _sliceStart[l][s-1]; - _sliceStart[l][0] = l>0 ? _sliceStart[l-1][(size_t)1<<(l-1)] : 0; - } -} -SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::SliceTableData::cornerIndices( const TreeOctNode* node ) { return cTable[ node->nodeData.nodeIndex - nodeOffset ]; } -SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::SliceTableData::cornerIndices( int idx ) { return cTable[ idx - nodeOffset ]; } -const SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::SliceTableData::cornerIndices( const TreeOctNode* node ) const { return cTable[ node->nodeData.nodeIndex - nodeOffset ]; } -const SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::SliceTableData::cornerIndices( int idx ) const { return cTable[ idx - nodeOffset ]; } -SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::SliceTableData::edgeIndices( const TreeOctNode* node ) { return eTable[ node->nodeData.nodeIndex - nodeOffset ]; } -SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::SliceTableData::edgeIndices( int idx ) { return eTable[ idx - nodeOffset ]; } -const SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::SliceTableData::edgeIndices( const TreeOctNode* node ) const { return eTable[ node->nodeData.nodeIndex - nodeOffset ]; } -const SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::SliceTableData::edgeIndices( int idx ) const { return eTable[ idx - nodeOffset ]; } -SortedTreeNodes::SquareFaceIndices& SortedTreeNodes::SliceTableData::faceIndices( const TreeOctNode* node ) { return fTable[ node->nodeData.nodeIndex - nodeOffset ]; } -SortedTreeNodes::SquareFaceIndices& SortedTreeNodes::SliceTableData::faceIndices( int idx ) { return fTable[ idx - nodeOffset ]; } -const SortedTreeNodes::SquareFaceIndices& SortedTreeNodes::SliceTableData::faceIndices( const TreeOctNode* node ) const { return fTable[ node->nodeData.nodeIndex - nodeOffset ]; } -const SortedTreeNodes::SquareFaceIndices& SortedTreeNodes::SliceTableData::faceIndices( int idx ) const { return fTable[ idx - nodeOffset ]; } -SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::XSliceTableData::edgeIndices( const TreeOctNode* node ) { return eTable[ node->nodeData.nodeIndex - nodeOffset ]; } -SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::XSliceTableData::edgeIndices( int idx ) { return eTable[ idx - nodeOffset ]; } -const SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::XSliceTableData::edgeIndices( const TreeOctNode* node ) const { return eTable[ node->nodeData.nodeIndex - nodeOffset ]; } -const SortedTreeNodes::SquareCornerIndices& SortedTreeNodes::XSliceTableData::edgeIndices( int idx ) const { return eTable[ idx - nodeOffset ]; } -SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::XSliceTableData::faceIndices( const TreeOctNode* node ) { return fTable[ node->nodeData.nodeIndex - nodeOffset ]; } -SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::XSliceTableData::faceIndices( int idx ) { return fTable[ idx - nodeOffset ]; } -const SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::XSliceTableData::faceIndices( const TreeOctNode* node ) const { return fTable[ node->nodeData.nodeIndex - nodeOffset ]; } -const SortedTreeNodes::SquareEdgeIndices& SortedTreeNodes::XSliceTableData::faceIndices( int idx ) const { return fTable[ idx - nodeOffset ]; } - -void SortedTreeNodes::setSliceTableData( SliceTableData& sData , int depth , int offset , int threads ) const -{ - // [NOTE] This is structure is purely for determining adjacency and is independent of the FEM degree - typedef OctNode< TreeNodeData >::template ConstNeighborKey< 1 , 1 > ConstAdjacenctNodeKey; - if( offset<0 || offset>((size_t)1< span( _sliceStart[depth][ std::max< int >( 0 , offset-1 ) ] , _sliceStart[depth][ std::min< int >( (size_t)1<( sData.nodeCount * Square::CORNERS ); - sData._eMap = NewPointer< int >( sData.nodeCount * Square::EDGES ); - sData._fMap = NewPointer< int >( sData.nodeCount * Square::FACES ); - sData.cTable = NewPointer< typename SortedTreeNodes::SquareCornerIndices >( sData.nodeCount ); - sData.eTable = NewPointer< typename SortedTreeNodes::SquareCornerIndices >( sData.nodeCount ); - sData.fTable = NewPointer< typename SortedTreeNodes::SquareFaceIndices >( sData.nodeCount ); - memset( sData._cMap , 0 , sizeof(int) * sData.nodeCount * Square::CORNERS ); - memset( sData._eMap , 0 , sizeof(int) * sData.nodeCount * Square::EDGES ); - memset( sData._fMap , 0 , sizeof(int) * sData.nodeCount * Square::FACES ); - } - std::vector< ConstAdjacenctNodeKey > neighborKeys( std::max< int >( 1 , threads ) ); - for( size_t i=0 ; i& neighbors = neighborKey.getNeighbors( node ); - int d , off[3]; - node->depthAndOffset( d , off ); - int z; - if ( off[2]==offset-1 ) z = 1; - else if( off[2]==offset ) z = 0; - else fprintf( stderr , "[ERROR] Node out of bounds: %d %d\n" , offset , off[2] ) , exit( 0 ); - // Process the corners - for( int x=0 ; x<2 ; x++ ) for( int y=0 ; y<2 ; y++ ) - { - int c = Cube::CornerIndex( x , y , z ); - int fc = Square::CornerIndex( x , y ); - bool cornerOwner = true; - int ac = Cube::AntipodalCornerIndex(c); // The index of the node relative to the corner - for( int cc=0 ; cc::template ConstNeighborKey< 1 , 1 > ConstAdjacenctNodeKey; - if( offset<0 || offset>=((size_t)1< span( _sliceStart[depth][offset] , _sliceStart[depth][offset+1] ); - sData.nodeOffset = span.first; - sData.nodeCount = span.second - span.first; - - DeletePointer( sData._eMap ) ; DeletePointer( sData._fMap ); - DeletePointer( sData.eTable ) ; DeletePointer( sData.fTable ); - if( sData.nodeCount ) - { - sData._eMap = NewPointer< int >( sData.nodeCount * Square::CORNERS ); - sData._fMap = NewPointer< int >( sData.nodeCount * Square::EDGES ); - sData.eTable = NewPointer< typename SortedTreeNodes::SquareCornerIndices >( sData.nodeCount ); - sData.fTable = NewPointer< typename SortedTreeNodes::SquareEdgeIndices >( sData.nodeCount ); - memset( sData._eMap , 0 , sizeof(int) * sData.nodeCount * Square::CORNERS ); - memset( sData._fMap , 0 , sizeof(int) * sData.nodeCount * Square::EDGES ); - } - - std::vector< ConstAdjacenctNodeKey > neighborKeys( std::max< int >( 1 , threads ) ); - for( size_t i=0 ; i& neighbors = neighborKey.getNeighbors( node ); - int d , off[3]; - node->depthAndOffset( d , off ); - // Process the edges - int o=2; - for( int x=0 ; x<2 ; x++ ) for( int y=0 ; y<2 ; y++ ) - { - int fc = Square::CornerIndex( x , y ); - bool edgeOwner = true; - - int ac = Square::AntipodalCornerIndex( Square::CornerIndex( x , y ) ); - for( int cc=0 ; cc -struct _ConstraintCalculator_ -{ - static inline Real _CalculateConstraint_( const PointData< Real , HasGradients >& p , const Polynomial< Degree >& px , const Polynomial< Degree >& py , const Polynomial< Degree >& pz , const Polynomial< Degree >& dpx , const Polynomial< Degree >& dpy , const Polynomial< Degree >& dpz , Real valueWeight , Real gradientWeight ); - static inline Real _CalculateConstraint_( const PointData< Real , HasGradients >& p , const Polynomial< Degree >& px , const Polynomial< Degree >& py , const Polynomial< Degree >& pz , const Polynomial< Degree >& dpx , const Polynomial< Degree >& dpy , const Polynomial< Degree >& dpz ); -#if POINT_DATA_RES - static inline void _CalculateCoarser_( int c , PointData< Real , HasGradients >& p , Real value , Point3D< Real > gradient , Real valueWeight , Real gradientWeight ); -#else // !POINT_DATA_RES - static inline void _CalculateCoarser_( PointData< Real , HasGradients >& p , Real value , Point3D< Real > gradient , Real valueWeight , Real gradientWeight ); -#endif // POINT_DATA_RES - -}; -template< class Real , int Degree > -struct _ConstraintCalculator_< Real , Degree , false > -{ - static inline Real _CalculateConstraint_( const PointData< Real , false >& p , const Polynomial< Degree >& px , const Polynomial< Degree >& py , const Polynomial< Degree >& pz , const Polynomial< Degree >& dpx , const Polynomial< Degree >& dpy , const Polynomial< Degree >& dpz , Real valueWeight , Real gradientWeight ) - { -#if POINT_DATA_RES - Real constraint = 0; - for( int c=0 ; c::SAMPLES ; c++ ) if( p[c].weight ) - { - const Point3D< Real > q = p[c].position; - constraint += (Real)( px( q[0] ) * py( q[1] ) * pz( q[2] ) * p[c].weight * p[c].value ); - } - return constraint * valueWeight; -#else // !POINT_DATA_RES - const Point3D< Real > q = p.position; - return (Real)( px( q[0] ) * py( q[1] ) * pz( q[2] ) * p.weight * p.value ) * valueWeight; -#endif // POINT_DATA_RES - } - static inline Real _CalculateConstraint_( const PointData< Real , false >& p , const Polynomial< Degree >& px , const Polynomial< Degree >& py , const Polynomial< Degree >& pz , const Polynomial< Degree >& dpx , const Polynomial< Degree >& dpy , const Polynomial< Degree >& dpz ) - { -#if POINT_DATA_RES - Real constraint = 0; - for( int c=0 ; c::SAMPLES ; c++ ) if( p[c].weight ) - { - const Point3D< Real > q = p[c].position; - constraint += (Real)( px( q[0] ) * py( q[1] ) * pz( q[2] ) * p[c]._value ); - } - return constraint; -#else // !POINT_DATA_RES - const Point3D< Real > q = p.position; - return (Real)( px( q[0] ) * py( q[1] ) * pz( q[2] ) * p._value ); -#endif // POINT_DATA_RES - } -#if POINT_DATA_RES - static inline void _CalculateCoarser_( int c , PointData< Real , false >& p , Real value , Point3D< Real > gradient , Real valueWeight , Real gradientWeight ){ p[c]._value = value * valueWeight * p[c].weight; } -#else // !POINT_DATA_RES - static inline void _CalculateCoarser_( PointData< Real , false >& p , Real value , Point3D< Real > gradient , Real valueWeight , Real gradientWeight ){ p._value = value * valueWeight * p.weight; } -#endif // POINT_DATA_RES -}; -template< class Real , int Degree > -struct _ConstraintCalculator_< Real , Degree , true > -{ - static inline Real _CalculateConstraint_( const PointData< Real , true >& p , const Polynomial< Degree >& px , const Polynomial< Degree >& py , const Polynomial< Degree >& pz , const Polynomial< Degree >& dpx , const Polynomial< Degree >& dpy , const Polynomial< Degree >& dpz , Real valueWeight , Real gradientWeight ) - { -#if POINT_DATA_RES - Real constraint = 0; - for( int c=0 ; c::SAMPLES ; c++ ) if( p[c].weight ) - { - const Point3D< Real > q = p[c].position; - double _px = px( q[0] ) , _py = py( q[1] ) , _pz = pz( q[2] ); - constraint += - ( - (Real)( _px * _py * _pz * p[c].value ) * valueWeight + - Point3D< Real >::Dot( Point3D< Real >( dpx( q[0] ) * _py * _pz , _px * dpy( q[1] ) * _pz , _px * _py * dpz( q[2] ) ) , p[c].gradient ) * gradientWeight - ) * p[c].weight; - } - return constraint; -#else // !POINT_DATA_RES - const Point3D< Real > q = p.position; - double _px = px( q[0] ) , _py = py( q[1] ) , _pz = pz( q[2] ); - return - ( - (Real)( _px * _py * _pz * p.value ) * valueWeight + - Point3D< Real >::Dot( Point3D< Real >( dpx( q[0] ) * _py * _pz , _px * dpy( q[1] ) * _pz , _px * _py * dpz( q[2] ) ) , p.gradient ) * gradientWeight - ) * p.weight; -#endif // POINT_DATA_RES - } - static inline Real _CalculateConstraint_( const PointData< Real , true >& p , const Polynomial< Degree >& px , const Polynomial< Degree >& py , const Polynomial< Degree >& pz , const Polynomial< Degree >& dpx , const Polynomial< Degree >& dpy , const Polynomial< Degree >& dpz ) - { -#if POINT_DATA_RES - Real constraint = 0; - for( int c=0 ; c::SAMPLES ; c++ ) if( p[c].weight ) - { - const Point3D< Real > q = p[c].position; - double _px = px( q[0] ) , _py = py( q[1] ) , _pz = pz( q[2] ); - constraint += - (Real)( _px * _py * _pz * p[c]._value ) + - Point3D< Real >::Dot( Point3D< Real >( dpx( q[0] ) * _py * _pz , _px * dpy( q[1] ) * _pz , _px * _py * dpz( q[2] ) ) , p[c]._gradient ); - } - return constraint; -#else // !POINT_DATA_RES - const Point3D< Real > q = p.position; - double _px = px( q[0] ) , _py = py( q[1] ) , _pz = pz( q[2] ); - return - (Real)( _px * _py * _pz * p._value ) + - Point3D< Real >::Dot( Point3D< Real >( dpx( q[0] ) * _py * _pz , _px * dpy( q[1] ) * _pz , _px * _py * dpz( q[2] ) ) , p._gradient ); -#endif // POINT_DATA_RES - } -#if POINT_DATA_RES - static inline void _CalculateCoarser_( int c , PointData< Real , true >& p , Real value , Point3D< Real > gradient , Real valueWeight , Real gradientWeight ){ p[c]._value = value * valueWeight * p[c].weight ; p[c]._gradient = gradient * gradientWeight * p[c].weight; } -#else // !POINT_DATA_RES - static inline void _CalculateCoarser_( PointData< Real , true >& p , Real value , Point3D< Real > gradient , Real valueWeight , Real gradientWeight ){ p._value = value * valueWeight * p.weight ; p._gradient = gradient * gradientWeight * p.weight; } -#endif // POINT_DATA_RES -}; - -template< > -template< class I > -double FEMSystemFunctor< 0 , BOUNDARY_FREE >::_integrate( const I& integrator , const int off1[] , const int off2[] ) const -{ -#define D_DOT( D1 , D2 ) { integrator.dot( off1[0] , off2[0] , D1 , D2 ) , integrator.dot( off1[1] , off2[1] , D1 , D2 ) , integrator.dot( off1[2] , off2[2] , D1 , D2 ) } - double d00[] = D_DOT( 0 , 0 ); - return - ( - d00[0] * d00[1] * d00[2] - ) * massWeight; -#undef D_DOT -} -template< > -template< class I > -double FEMSystemFunctor< 0 , BOUNDARY_NEUMANN >::_integrate( const I& integrator , const int off1[] , const int off2[] ) const -{ -#define D_DOT( D1 , D2 ) { integrator.dot( off1[0] , off2[0] , D1 , D2 ) , integrator.dot( off1[1] , off2[1] , D1 , D2 ) , integrator.dot( off1[2] , off2[2] , D1 , D2 ) } - double d00[] = D_DOT( 0 , 0 ); - return - ( - d00[0] * d00[1] * d00[2] - ) * massWeight; -#undef D_DOT -} -template< > -template< class I > -double FEMSystemFunctor< 0 , BOUNDARY_DIRICHLET >::_integrate( const I& integrator , const int off1[] , const int off2[] ) const -{ -#define D_DOT( D1 , D2 ) { integrator.dot( off1[0] , off2[0] , D1 , D2 ) , integrator.dot( off1[1] , off2[1] , D1 , D2 ) , integrator.dot( off1[2] , off2[2] , D1 , D2 ) } - double d00[] = D_DOT( 0 , 0 ); - return - ( - d00[0] * d00[1] * d00[2] - ) * massWeight; -#undef D_DOT -} -template< > -template< class I > -double FEMSystemFunctor< 1 , BOUNDARY_FREE >::_integrate( const I& integrator , const int off1[] , const int off2[] ) const -{ -#define D_DOT( D1 , D2 ) { integrator.dot( off1[0] , off2[0] , D1 , D2 ) , integrator.dot( off1[1] , off2[1] , D1 , D2 ) , integrator.dot( off1[2] , off2[2] , D1 , D2 ) } - double d00[] = D_DOT( 0 , 0 ) , d11[] = D_DOT( 1 , 1 ); - return - ( - d00[0] * d00[1] * d00[2] - ) * massWeight - + - ( - d11[0] * d00[1] * d00[2] + - d11[1] * d00[2] * d00[0] + - d11[2] * d00[0] * d00[1] - ) * lapWeight; -#undef D_DOT -} -template< > -template< class I > -double FEMSystemFunctor< 1 , BOUNDARY_NEUMANN >::_integrate( const I& integrator , const int off1[] , const int off2[] ) const -{ -#define D_DOT( D1 , D2 ) { integrator.dot( off1[0] , off2[0] , D1 , D2 ) , integrator.dot( off1[1] , off2[1] , D1 , D2 ) , integrator.dot( off1[2] , off2[2] , D1 , D2 ) } - double d00[] = D_DOT( 0 , 0 ) , d11[] = D_DOT( 1 , 1 ); - return - ( - d00[0] * d00[1] * d00[2] - ) * massWeight - + - ( - d11[0] * d00[1] * d00[2] + - d11[1] * d00[2] * d00[0] + - d11[2] * d00[0] * d00[1] - ) * lapWeight; -#undef D_DOT -} -template< > -template< class I > -double FEMSystemFunctor< 1 , BOUNDARY_DIRICHLET >::_integrate( const I& integrator , const int off1[] , const int off2[] ) const -{ -#define D_DOT( D1 , D2 ) { integrator.dot( off1[0] , off2[0] , D1 , D2 ) , integrator.dot( off1[1] , off2[1] , D1 , D2 ) , integrator.dot( off1[2] , off2[2] , D1 , D2 ) } - double d00[] = D_DOT( 0 , 0 ) , d11[] = D_DOT( 1 , 1 ); - return - ( - d00[0] * d00[1] * d00[2] - ) * massWeight - + - ( - d11[0] * d00[1] * d00[2] + - d11[1] * d00[2] * d00[0] + - d11[2] * d00[0] * d00[1] - ) * lapWeight; -#undef D_DOT -} - -template< int FEMDegree , BoundaryType BType > -template< class I > -double FEMSystemFunctor< FEMDegree , BType >::_integrate( const I& integrator , const int off1[] , const int off2[] ) const -{ -#define D_DOT( D1 , D2 ) { integrator.dot( off1[0] , off2[0] , D1 , D2 ) , integrator.dot( off1[1] , off2[1] , D1 , D2 ) , integrator.dot( off1[2] , off2[2] , D1 , D2 ) } - double d00[] = D_DOT( 0 , 0 ) , d02[] = D_DOT( 0 , 2 ) , d20[] = D_DOT( 2 , 0 ) , d22[] = D_DOT( 2 , 2 ) , d11[] = D_DOT( 1 , 1 ); - return - ( - d00[0] * d00[1] * d00[2] - ) * massWeight - + - ( - d11[0] * d00[1] * d00[2] + - d11[1] * d00[2] * d00[0] + - d11[2] * d00[0] * d00[1] - ) * lapWeight - + - ( - d22[0] * d00[1] * d00[2] + // Unmixed - d22[1] * d00[2] * d00[0] + // Unmixed - d22[2] * d00[0] * d00[1] + // Unmixed - d00[0] * ( d02[1] * d20[2] + d20[1] * d02[2] ) + // Mixed - d00[1] * ( d02[2] * d20[0] + d20[2] * d02[0] ) + // Mixed - d00[2] * ( d02[0] * d20[1] + d20[0] * d02[1] ) // Mixed - ) * biLapWeight; -#undef D_DOT -} -template< int SFDegree , BoundaryType SFBType , int FEMDegree , BoundaryType FEMBType > -template< bool Reverse , class I > -double FEMSFConstraintFunctor< SFDegree , SFBType , FEMDegree , FEMBType >::_integrate( const I& integrator , const int off1[] , const int off2[] ) const -{ -#define D_DOT( D1 , D2 ) { integrator.dot( off1[0] , off2[0] , Reverse ? D2 : D1 , Reverse ? D1 : D2 ) , integrator.dot( off1[1] , off2[1] , Reverse ? D2 : D1 , Reverse ? D1 : D2 ) , integrator.dot( off1[2] , off2[2] , Reverse ? D2 : D1 , Reverse ? D1 : D2 ) } - double d00[] = D_DOT( 0 , 0 ) , d02[] = D_DOT( 0 , 2 ) , d20[] = D_DOT( 2 , 0 ) , d22[] = D_DOT( 2 , 2 ) , d11[] = D_DOT( 1 , 1 ); - if( SFDegree==0 || FEMDegree==0 ) - return d00[0] * d00[1] * d00[2] * massWeight; - else if( SFDegree<=1 || FEMDegree<=1 ) - return - ( - d00[0] * d00[1] * d00[2] - ) * massWeight - + - ( - d11[0] * d00[1] * d00[2] + - d11[1] * d00[2] * d00[0] + - d11[2] * d00[0] * d00[1] - ) * lapWeight; - else - return - ( - d00[0] * d00[1] * d00[2] - ) * massWeight - + - ( - d11[0] * d00[1] * d00[2] + - d11[1] * d00[2] * d00[0] + - d11[2] * d00[0] * d00[1] - ) * lapWeight - + - ( - d22[0] * d00[1] * d00[2] + // Unmixed - d22[1] * d00[2] * d00[0] + // Unmixed - d22[2] * d00[0] * d00[1] + // Unmixed - d00[0] * ( d02[1] * d20[2] + d20[1] * d02[2] ) + // Mixed - d00[1] * ( d02[2] * d20[0] + d20[2] * d02[0] ) + // Mixed - d00[2] * ( d02[0] * d20[1] + d20[0] * d02[1] ) // Mixed - ) * biLapWeight; -#undef D_DOT -} -template< int VFDegree , BoundaryType VFBType , int FEMDegree , BoundaryType FEMBType > -template< bool Reverse , class I > -Point3D< double > FEMVFConstraintFunctor< VFDegree , VFBType , FEMDegree , FEMBType >::_integrate( const I& integrator , const int off1[] , const int off2[] ) const -{ -#define D_DOT( D1 , D2 ) { integrator.dot( off1[0] , off2[0] , Reverse ? D2 : D1 , Reverse ? D1 : D2 ) , integrator.dot( off1[1] , off2[1] , Reverse ? D2 : D1 , Reverse ? D1 : D2 ) , integrator.dot( off1[2] , off2[2] , Reverse ? D2 : D1 , Reverse ? D1 : D2 ) } - if( FEMDegree==0 ) fprintf( stderr , "[ERROR] FEMDegree does not support differentiation: %d\n" , FEMDegree ) , exit( 0 ); - if( VFDegree==0 || FEMDegree==1 ) - { - double d00[] = D_DOT( 0 , 0 ) , d01[] = D_DOT( 0 , 1 ); - return - Point3D< double > - ( - d01[0] * d00[1] * d00[2] , - d01[1] * d00[2] * d00[0] , - d01[2] * d00[0] * d00[1] - ) * lapWeight; - } - else - { - double d00[] = D_DOT( 0 , 0 ) , d10[] = D_DOT( 1 , 0 ) , d01[] = D_DOT( 0 , 1 ) , d02[] = D_DOT( 0 , 2 ) , d12[] = D_DOT( 1 , 2 ); - return - Point3D< double > - ( - d01[0] * d00[1] * d00[2] , - d01[1] * d00[2] * d00[0] , - d01[2] * d00[0] * d00[1] - ) * lapWeight - + - Point3D< double > - ( - d12[0] * d00[1] * d00[2] + d10[0] * ( d00[1] * d02[2] + d02[1] * d00[2] ) , - d12[1] * d00[2] * d00[0] + d10[1] * ( d00[2] * d02[0] + d02[2] * d00[0] ) , - d12[2] * d00[0] * d00[1] + d10[2] * ( d00[0] * d02[1] + d02[0] * d00[1] ) - ) * biLapWeight; - } -#undef D_DOT -} - -template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > -template< bool Reverse , class _FEMSystemFunctor > -void SystemCoefficients< Degree1 , BType1 , Degree2 , BType2 >::SetCentralConstraintStencil( const _FEMSystemFunctor& F , const Integrator& integrator , Stencil< double , OverlapSize >& stencil ) -{ - int center = ( 1<>1; - int offset[] = { center , center , center }; - for( int x=0 ; x( integrator , _offset , offset ); - } -} -template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > -template< bool Reverse , class _FEMSystemFunctor > -void SystemCoefficients< Degree1 , BType1 , Degree2 , BType2 >::SetCentralConstraintStencils( const _FEMSystemFunctor& F , const ChildIntegrator& integrator , Stencil< double , OverlapSize > stencils[2][2][2] ) -{ - int center = ( 1<>1; - // [NOTE] We want the center to be at the first node of the brood - // Which is not the case when childDepth is 1. - center = ( center>>1 )<<1; - for( int i=0 ; i<2 ; i++ ) for( int j=0 ; j<2 ; j++ ) for( int k=0 ; k<2 ; k++ ) - { - int offset[] = { center+i , center+j , center+k }; - for( int x=0 ; x( integrator , _offset , offset ); - } - } -} -template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > -template< bool Reverse , class _FEMSystemFunctor > -void SystemCoefficients< Degree1 , BType1 , Degree2 , BType2 >::SetCentralConstraintStencil( const _FEMSystemFunctor& F , const Integrator& integrator , Stencil< Point3D< double > , OverlapSize >& stencil ) -{ - int center = ( 1<>1; - int offset[] = { center , center , center }; - for( int x=0 ; x( integrator , _offset , offset ); - } -} -template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > -template< bool Reverse , class _FEMSystemFunctor > -void SystemCoefficients< Degree1 , BType1 , Degree2 , BType2 >::SetCentralConstraintStencils( const _FEMSystemFunctor& F , const ChildIntegrator& integrator , Stencil< Point3D< double > , OverlapSize > stencils[2][2][2] ) -{ - int center = ( 1<>1; - // [NOTE] We want the center to be at the first node of the brood - // Which is not the case when childDepth is 1. - center = ( center>>1 )<<1; - for( int i=0 ; i<2 ; i++ ) for( int j=0 ; j<2 ; j++ ) for( int k=0 ; k<2 ; k++ ) - { - int offset[] = { center+i , center+j , center+k }; - for( int x=0 ; x( integrator , _offset , offset ); - } - } -} -template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > -template< class _FEMSystemFunctor > -void SystemCoefficients< Degree1 , BType1 , Degree2 , BType2 >::SetCentralSystemStencil( const _FEMSystemFunctor& F , const Integrator& integrator , Stencil< double , OverlapSize >& stencil ) -{ - int center = ( 1<>1; - int offset[] = { center , center , center }; - for( int x=0 ; x -template< class _FEMSystemFunctor > -void SystemCoefficients< Degree1 , BType1 , Degree2 , BType2 >::SetCentralSystemStencils( const _FEMSystemFunctor& F , const ChildIntegrator& integrator , Stencil< double , OverlapSize > stencils[2][2][2] ) -{ - int center = ( 1<>1; - // [NOTE] We want the center to be at the first node of the brood - // Which is not the case when childDepth is 1. - center = ( center>>1 )<<1; - for( int i=0 ; i<2 ; i++ ) for( int j=0 ; j<2 ; j++ ) for( int k=0 ; k<2 ; k++ ) - { - int offset[] = { center+i , center+j , center+k }; - for( int x=0 ; x -template< int FEMDegree > -void Octree< Real >::_setMultiColorIndices( int start , int end , std::vector< std::vector< int > >& indices ) const -{ - static const int OverlapRadius = - BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapStart; - - const int modulus = OverlapRadius+1; - indices.resize( modulus*modulus*modulus ); - int count[modulus*modulus*modulus]; - memset( count , 0 , sizeof(int)*modulus*modulus*modulus ); -#pragma omp parallel for num_threads( threads ) - for( int i=start ; idepthAndOffset( d , off ); - int idx = (modulus*modulus) * ( off[2]%modulus ) + modulus * ( off[1]%modulus ) + ( off[0]%modulus ); -#pragma omp atomic - count[idx]++; - } - - for( int i=0 ; idepthAndOffset( d , off ); - int idx = (modulus*modulus) * ( off[2]%modulus ) + modulus * ( off[1]%modulus ) + ( off[0]%modulus ); - indices[idx].push_back( i - start ); - } -} - -template< class Real > -template< class C , int FEMDegree , BoundaryType BType > -void Octree< Real >::_downSample( LocalDepth highDepth , DenseNodeData< C , FEMDegree >& constraints ) const -{ - typedef typename TreeOctNode::NeighborKey< -BSplineSupportSizes< FEMDegree >::UpSampleStart , BSplineSupportSizes< FEMDegree >::UpSampleEnd > UpSampleKey; - - LocalDepth lowDepth = highDepth-1; - if( lowDepth<0 ) return; - - typename BSplineEvaluationData< FEMDegree , BType >::UpSampleEvaluator upSampleEvaluator; - BSplineEvaluationData< FEMDegree , BType >::SetUpSampleEvaluator( upSampleEvaluator , lowDepth ); - std::vector< UpSampleKey > neighborKeys( std::max< int >( 1 , threads ) ); - for( size_t i=0 ; i::UpSampleSize > upSampleStencil; - int lowCenter = ( 1<>1; - for( int i=0 ; i::UpSampleSize ; i++ ) for( int j=0 ; j::UpSampleSize ; j++ ) for( int k=0 ; k::UpSampleSize ; k++ ) - upSampleStencil( i , j , k ) = - upSampleEvaluator.value( lowCenter , 2*lowCenter + i + BSplineSupportSizes< FEMDegree >::UpSampleStart ) * - upSampleEvaluator.value( lowCenter , 2*lowCenter + j + BSplineSupportSizes< FEMDegree >::UpSampleStart ) * - upSampleEvaluator.value( lowCenter , 2*lowCenter + k + BSplineSupportSizes< FEMDegree >::UpSampleStart ); - - // Iterate over all (valid) parent nodes -#pragma omp parallel for num_threads( threads ) - for( int i=_sNodesBegin(lowDepth) ; i<_sNodesEnd(lowDepth) ; i++ ) if( _isValidFEMNode( _sNodes.treeNodes[i] ) ) - { - TreeOctNode* pNode = _sNodes.treeNodes[i]; - - UpSampleKey& neighborKey = neighborKeys[ omp_get_thread_num() ]; - LocalDepth d ; LocalOffset off; - _localDepthAndOffset( pNode , d , off ); - - neighborKey.template getNeighbors< false >( pNode ); - - // Get the child neighbors - typename TreeOctNode::Neighbors< BSplineSupportSizes< FEMDegree >::UpSampleSize > neighbors; - neighborKey.template getChildNeighbors< false >( 0 , _localToGlobal( d ) , neighbors ); - - C& coarseConstraint = constraints[i]; - - // Want to make sure test if contained children are interior. - // This is more conservative because we are test that overlapping children are interior - bool isInterior = _isInteriorlyOverlapped< FEMDegree , FEMDegree >( pNode ); - if( isInterior ) - { - for( int ii=0 ; ii::UpSampleSize ; ii++ ) for( int jj=0 ; jj::UpSampleSize ; jj++ ) for( int kk=0 ; kk::UpSampleSize ; kk++ ) - { - const TreeOctNode* cNode = neighbors.neighbors[ii][jj][kk]; - if( IsActiveNode( cNode ) ) coarseConstraint += (C)( constraints[ cNode->nodeData.nodeIndex ] * upSampleStencil( ii , jj , kk ) ); - } - } - else - { - double upSampleValues[3][ BSplineSupportSizes< FEMDegree >::UpSampleSize ]; - for( int ii=0 ; ii::UpSampleSize ; ii++ ) - { - upSampleValues[0][ii] = upSampleEvaluator.value( off[0] , 2*off[0] + ii + BSplineSupportSizes< FEMDegree >::UpSampleStart ); - upSampleValues[1][ii] = upSampleEvaluator.value( off[1] , 2*off[1] + ii + BSplineSupportSizes< FEMDegree >::UpSampleStart ); - upSampleValues[2][ii] = upSampleEvaluator.value( off[2] , 2*off[2] + ii + BSplineSupportSizes< FEMDegree >::UpSampleStart ); - } - for( int ii=0 ; ii::UpSampleSize ; ii++ ) for( int jj=0 ; jj::UpSampleSize ; jj++ ) - { - double dxy = upSampleValues[0][ii] * upSampleValues[1][jj]; - for( int kk=0 ; kk::UpSampleSize ; kk++ ) - { - const TreeOctNode* cNode = neighbors.neighbors[ii][jj][kk]; - if( _isValidFEMNode( cNode ) ) coarseConstraint += (C)( constraints[ cNode->nodeData.nodeIndex ] * dxy * upSampleValues[2][kk] ); - } - } - } - } -} -template< class Real > -template< class C , int FEMDegree , BoundaryType BType > -void Octree< Real >::_upSample( LocalDepth highDepth , DenseNodeData< C , FEMDegree >& coefficients ) const -{ - static const int LeftDownSampleRadius = -( ( BSplineSupportSizes< FEMDegree >::DownSample0Start < BSplineSupportSizes< FEMDegree >::DownSample1Start ) ? BSplineSupportSizes< FEMDegree >::DownSample0Start : BSplineSupportSizes< FEMDegree >::DownSample1Start ); - static const int RightDownSampleRadius = ( ( BSplineSupportSizes< FEMDegree >::DownSample0End > BSplineSupportSizes< FEMDegree >::DownSample1End ) ? BSplineSupportSizes< FEMDegree >::DownSample0End : BSplineSupportSizes< FEMDegree >::DownSample1End ); - typedef TreeOctNode::NeighborKey< LeftDownSampleRadius , RightDownSampleRadius > DownSampleKey; - - LocalDepth lowDepth = highDepth-1; - if( lowDepth<0 ) return; - - typename BSplineEvaluationData< FEMDegree , BType >::UpSampleEvaluator upSampleEvaluator; - BSplineEvaluationData< FEMDegree , BType >::SetUpSampleEvaluator( upSampleEvaluator , lowDepth ); - std::vector< DownSampleKey > neighborKeys( std::max< int >( 1 , threads ) ); - for( size_t i=0 ; i::DownSample0Size > BSplineSupportSizes< FEMDegree >::DownSample1Size ? BSplineSupportSizes< FEMDegree >::DownSample0Size : BSplineSupportSizes< FEMDegree >::DownSample1Size; - Stencil< double , DownSampleSize > downSampleStencils[ Cube::CORNERS ]; - int lowCenter = ( 1<>1; - for( int c=0 ; c::DownSampleSize[cx] ; ii++ ) - for( int jj=0 ; jj::DownSampleSize[cy] ; jj++ ) - for( int kk=0 ; kk::DownSampleSize[cz] ; kk++ ) - downSampleStencils[c]( ii , jj , kk ) = - upSampleEvaluator.value( lowCenter + ii + BSplineSupportSizes< FEMDegree >::DownSampleStart[cx] , 2*lowCenter + cx ) * - upSampleEvaluator.value( lowCenter + jj + BSplineSupportSizes< FEMDegree >::DownSampleStart[cy] , 2*lowCenter + cy ) * - upSampleEvaluator.value( lowCenter + kk + BSplineSupportSizes< FEMDegree >::DownSampleStart[cz] , 2*lowCenter + cz ) ; - } - - // For Dirichlet constraints, can't get to all children from parents because boundary nodes are invalid -#pragma omp parallel for num_threads( threads ) - for( int i=_sNodesBegin(highDepth) ; i<_sNodesEnd(highDepth) ; i++ ) if( _isValidFEMNode( _sNodes.treeNodes[i] ) ) - { - TreeOctNode *cNode = _sNodes.treeNodes[i] , *pNode = cNode->parent; - int c = (int)( cNode-pNode->children ); - - DownSampleKey& neighborKey = neighborKeys[ omp_get_thread_num() ]; - LocalDepth d ; LocalOffset off; - _localDepthAndOffset( pNode , d , off ); - typename TreeOctNode::Neighbors< LeftDownSampleRadius + RightDownSampleRadius + 1 >& neighbors = neighborKey.template getNeighbors< false >( pNode ); - - // Want to make sure test if contained children are interior. - // This is more conservative because we are test that overlapping children are interior - bool isInterior = _isInteriorlyOverlapped< FEMDegree , FEMDegree >( pNode ); - - C& fineCoefficient = coefficients[ cNode->nodeData.nodeIndex ]; - - int cx , cy , cz; - Cube::FactorCornerIndex( c , cx , cy , cz ); - - if( isInterior ) - { - for( int ii=0 ; ii::DownSampleSize[cx] ; ii++ ) for( int jj=0 ; jj::DownSampleSize[cy] ; jj++ ) - { - int _ii = ii + BSplineSupportSizes< FEMDegree >::DownSampleStart[cx] + LeftDownSampleRadius; - int _jj = jj + BSplineSupportSizes< FEMDegree >::DownSampleStart[cy] + LeftDownSampleRadius; - for( int kk=0 ; kk::DownSampleSize[cz] ; kk++ ) - { - int _kk = kk + BSplineSupportSizes< FEMDegree >::DownSampleStart[cz] + LeftDownSampleRadius; - const TreeOctNode* _pNode = neighbors.neighbors[_ii][_jj][_kk]; - if( _pNode ) fineCoefficient += (C)( coefficients[ _pNode->nodeData.nodeIndex ] * downSampleStencils[c]( ii , jj , kk ) ); - } - } - } - else - { - double downSampleValues[3][ BSplineSupportSizes< FEMDegree >::DownSample0Size > BSplineSupportSizes< FEMDegree >::DownSample1Size ? BSplineSupportSizes< FEMDegree >::DownSample0Size : BSplineSupportSizes< FEMDegree >::DownSample1Size ]; - for( int ii=0 ; ii::DownSampleSize[cx] ; ii++ ) downSampleValues[0][ii] = upSampleEvaluator.value( off[0] + ii + BSplineSupportSizes< FEMDegree >::DownSampleStart[cx] , 2*off[0] + cx ); - for( int ii=0 ; ii::DownSampleSize[cy] ; ii++ ) downSampleValues[1][ii] = upSampleEvaluator.value( off[1] + ii + BSplineSupportSizes< FEMDegree >::DownSampleStart[cy] , 2*off[1] + cy ); - for( int ii=0 ; ii::DownSampleSize[cz] ; ii++ ) downSampleValues[2][ii] = upSampleEvaluator.value( off[2] + ii + BSplineSupportSizes< FEMDegree >::DownSampleStart[cz] , 2*off[2] + cz ); - - for( int ii=0 ; ii::DownSampleSize[cx] ; ii++ ) for( int jj=0 ; jj::DownSampleSize[cy] ; jj++ ) - { - double dxy = downSampleValues[0][ii] * downSampleValues[1][jj]; - int _ii = ii + BSplineSupportSizes< FEMDegree >::DownSampleStart[cx] + LeftDownSampleRadius; - int _jj = jj + BSplineSupportSizes< FEMDegree >::DownSampleStart[cy] + LeftDownSampleRadius; - for( int kk=0 ; kk::DownSampleSize[cz] ; kk++ ) - { - int _kk = kk + BSplineSupportSizes< FEMDegree >::DownSampleStart[cz] + LeftDownSampleRadius; - const TreeOctNode* _pNode = neighbors.neighbors[_ii][_jj][_kk]; - if( _isValidFEMNode( _pNode ) ) fineCoefficient += (C)( coefficients[ _pNode->nodeData.nodeIndex ] * dxy * downSampleValues[2][kk] ); - } - } - } - } -} - -template< class Real > -template< class C , int FEMDegree , BoundaryType BType > -void Octree< Real >::_UpSample( LocalDepth highDepth , ConstPointer( C ) lowCoefficients , Pointer( C ) highCoefficients , int threads ) -{ - static const int LeftDownSampleRadius = -( ( BSplineSupportSizes< FEMDegree >::DownSample0Start < BSplineSupportSizes< FEMDegree >::DownSample1Start ) ? BSplineSupportSizes< FEMDegree >::DownSample0Start : BSplineSupportSizes< FEMDegree >::DownSample1Start ); - static const int RightDownSampleRadius = ( ( BSplineSupportSizes< FEMDegree >::DownSample0End > BSplineSupportSizes< FEMDegree >::DownSample1End ) ? BSplineSupportSizes< FEMDegree >::DownSample0End : BSplineSupportSizes< FEMDegree >::DownSample1End ); - typedef TreeOctNode::NeighborKey< LeftDownSampleRadius , RightDownSampleRadius > DownSampleKey; - - LocalDepth lowDepth = highDepth - 1; - if( lowDepth<0 ) return; - - typename BSplineEvaluationData< FEMDegree , BType >::UpSampleEvaluator upSampleEvaluator; - BSplineEvaluationData< FEMDegree , BType >::SetUpSampleEvaluator( upSampleEvaluator , lowDepth ); - std::vector< DownSampleKey > neighborKeys( std::max< int >( 1 , threads ) ); - - static const int DownSampleSize = BSplineSupportSizes< FEMDegree >::DownSample0Size > BSplineSupportSizes< FEMDegree >::DownSample1Size ? BSplineSupportSizes< FEMDegree >::DownSample0Size : BSplineSupportSizes< FEMDegree >::DownSample1Size; - Stencil< double , DownSampleSize > downSampleStencils[ Cube::CORNERS ]; - int lowCenter = ( 1<>1; - for( int c=0 ; c::DownSample0Size > BSplineSupportSizes< FEMDegree >::DownSample1Size ? BSplineSupportSizes< FEMDegree >::DownSample0Size : BSplineSupportSizes< FEMDegree >::DownSample1Size; - for( int ii=0 ; ii::DownSampleSize[cx] ; ii++ ) - for( int jj=0 ; jj::DownSampleSize[cy] ; jj++ ) - for( int kk=0 ; kk::DownSampleSize[cz] ; kk++ ) - downSampleStencils[c]( ii , jj , kk ) = - upSampleEvaluator.value( lowCenter + ii + BSplineSupportSizes< FEMDegree >::DownSampleStart[cx] , 2*lowCenter + cx ) * - upSampleEvaluator.value( lowCenter + jj + BSplineSupportSizes< FEMDegree >::DownSampleStart[cy] , 2*lowCenter + cy ) * - upSampleEvaluator.value( lowCenter + kk + BSplineSupportSizes< FEMDegree >::DownSampleStart[cz] , 2*lowCenter + cz ) ; - } - int lowBegin = _BSplineBegin< FEMDegree , BType >( lowDepth ) , lowEnd = _BSplineEnd< FEMDegree , BType >( lowDepth ); - int highBegin = _BSplineBegin< FEMDegree , BType >( highDepth ) , highEnd = _BSplineEnd< FEMDegree , BType >( highDepth ); - int lowDim = lowEnd - lowBegin , highDim = highEnd - highBegin; - // Iterate over all child nodes. (This is required since there can be child nodes whose parent is inactive.) -#pragma omp parallel for num_threads( threads ) - for( int k=0 ; k>1 , _off[1] = off[1]>>1 , _off[2] = off[2]>>1; - - // Want to make sure test if contained children are interior. - // This is more conservative because we are test that overlapping children are interior - bool isInterior = _IsInteriorlyOverlapped< FEMDegree , FEMDegree >( lowDepth , _off ); - int cx = off[0]&1 , cy = off[1]&1 , cz = off[2]&1; - int c = Cube::CornerIndex( cx , cy , cz ); - - C& highCoefficient = highCoefficients[ highIdx ]; - - if( isInterior ) - { - for( int ii=0 ; ii::DownSampleSize[cx] ; ii++ ) for( int jj=0 ; jj::DownSampleSize[cy] ; jj++ ) - { - int _i = _off[0] + ii + BSplineSupportSizes< FEMDegree >::DownSampleStart[cx] - lowBegin; - int _j = _off[1] + jj + BSplineSupportSizes< FEMDegree >::DownSampleStart[cy] - lowBegin; - for( int kk=0 ; kk::DownSampleSize[cz] ; kk++ ) - { - int _k = _off[2] + kk + BSplineSupportSizes< FEMDegree >::DownSampleStart[cz] - lowBegin; - highCoefficient += (C)( lowCoefficients[ _i + _j*lowDim + _k*lowDim*lowDim ] * downSampleStencils[c]( ii , jj , kk ) ); - } - } - } - else - { - double downSampleValues[3][ BSplineSupportSizes< FEMDegree >::DownSample0Size > BSplineSupportSizes< FEMDegree >::DownSample1Size ? BSplineSupportSizes< FEMDegree >::DownSample0Size : BSplineSupportSizes< FEMDegree >::DownSample1Size ]; - - for( int ii=0 ; ii::DownSampleSize[cx] ; ii++ ) downSampleValues[0][ii] = upSampleEvaluator.value( _off[0] + ii + BSplineSupportSizes< FEMDegree >::DownSampleStart[cx] , off[0] ); - for( int ii=0 ; ii::DownSampleSize[cy] ; ii++ ) downSampleValues[1][ii] = upSampleEvaluator.value( _off[1] + ii + BSplineSupportSizes< FEMDegree >::DownSampleStart[cy] , off[1] ); - for( int ii=0 ; ii::DownSampleSize[cz] ; ii++ ) downSampleValues[2][ii] = upSampleEvaluator.value( _off[2] + ii + BSplineSupportSizes< FEMDegree >::DownSampleStart[cz] , off[2] ); - - for( int ii=0 ; ii::DownSampleSize[cx] ; ii++ ) for( int jj=0 ; jj::DownSampleSize[cy] ; jj++ ) - { - double dxy = downSampleValues[0][ii] * downSampleValues[1][jj]; - int _i = _off[0] + ii + BSplineSupportSizes< FEMDegree >::DownSampleStart[cx] - lowBegin; - int _j = _off[1] + jj + BSplineSupportSizes< FEMDegree >::DownSampleStart[cy] - lowBegin; - if( _i>=0 && _i=0 && _j::DownSampleSize[cz] ; kk++ ) - { - int _k = _off[2] + kk + BSplineSupportSizes< FEMDegree >::DownSampleStart[cz] - lowBegin; - if( _k>=0 && _k -template< class C , int FEMDegree , BoundaryType BType > -DenseNodeData< C , FEMDegree > Octree< Real >::coarseCoefficients( const DenseNodeData< C , FEMDegree >& coefficients ) const -{ - DenseNodeData< Real , FEMDegree > coarseCoefficients( _sNodesEnd(_maxDepth-1) ); - memset( &coarseCoefficients[0] , 0 , sizeof(Real)*_sNodesEnd(_maxDepth-1) ); -#pragma omp parallel for num_threads( threads ) - for( int i=_sNodesBegin(0) ; i<_sNodesEnd(_maxDepth-1) ; i++ ) coarseCoefficients[i] = coefficients[i]; - for( LocalDepth d=1 ; d<_maxDepth ; d++ ) _upSample< C , FEMDegree , BType >( d , coarseCoefficients ); - return coarseCoefficients; -} -template< class Real > -template< class C , int FEMDegree , BoundaryType BType > -DenseNodeData< C , FEMDegree > Octree< Real >::coarseCoefficients( const SparseNodeData< C , FEMDegree >& coefficients ) const -{ - DenseNodeData< Real , FEMDegree > coarseCoefficients( _sNodesEnd(_maxDepth-1) ); - memset( &coarseCoefficients[0] , 0 , sizeof(Real)*_sNodesEnd(_maxDepth-1) ); -#pragma omp parallel for num_threads( threads ) - for( int i=_sNodesBegin(0) ; i<_sNodesEnd(_maxDepth-1) ; i++ ) - { - const C* c = coefficients( _sNodes.treeNodes[i] ); - if( c ) coarseCoefficients[i] = *c; - } - for( LocalDepth d=1 ; d<_maxDepth ; d++ ) _upSample< C , FEMDegree , BType >( d , coarseCoefficients ); - return coarseCoefficients; -} - -template< class Real > -template< int FEMDegree , BoundaryType BType > -Real Octree< Real >::_coarserFunctionValue( Point3D< Real > p , const PointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* pointNode , const BSplineData< FEMDegree , BType >& bsData , const DenseNodeData< Real , FEMDegree >& upSampledCoefficients ) const -{ - static const int SupportSize = BSplineSupportSizes< FEMDegree >::SupportSize; - static const int LeftSupportRadius = - BSplineSupportSizes< FEMDegree >::SupportStart; - static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; - static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; - static const int RightPointSupportRadius = - BSplineSupportSizes< FEMDegree >::SupportStart; - - double pointValue = 0; - LocalDepth depth = _localDepth( pointNode ); - if( depth<0 ) return (Real)0.; - - // Iterate over all basis functions that overlap the point at the coarser resolution - { - const typename TreeOctNode::Neighbors< SupportSize >& neighbors = neighborKey.neighbors[ _localToGlobal( depth-1 ) ]; - LocalDepth _d ; LocalOffset _off; - _localDepthAndOffset( pointNode->parent , _d , _off ); - int fStart , fEnd; - BSplineData< FEMDegree , BType >::FunctionSpan( _d , fStart , fEnd ); - - double pointValues[ DIMENSION ][SupportSize]; - memset( pointValues , 0 , sizeof(double) * DIMENSION * SupportSize ); - - for( int dd=0 ; dd::FunctionIndex( _d , _off[dd]+i ); - if( fIdx>=fStart && fIdxnodeData.nodeIndex] ); - } - pointValue += _pointValue * xyValue; - } - } - return Real( pointValue ); -} -template< class Real > -template< int FEMDegree , BoundaryType BType > -Point3D< Real > Octree< Real >::_coarserFunctionGradient( Point3D< Real > p , const PointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* pointNode , const BSplineData< FEMDegree , BType >& bsData , const DenseNodeData< Real , FEMDegree >& upSampledCoefficients ) const -{ - static const int SupportSize = BSplineSupportSizes< FEMDegree >::SupportSize; - static const int LeftSupportRadius = - BSplineSupportSizes< FEMDegree >::SupportStart; - static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; - static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; - static const int RightPointSupportRadius = - BSplineSupportSizes< FEMDegree >::SupportStart; - - Point3D< double > pointGradient; - LocalDepth depth = _localDepth( pointNode ); - if( depth<=0 ) return Real(0.); - - // Iterate over all basis functions that overlap the point at the coarser resolution - { - const typename TreeOctNode::Neighbors< SupportSize >& neighbors = neighborKey.neighbors[ _localToGlobal( depth-1 ) ]; - LocalDepth _d ; LocalOffset _off; - _localDepthAndOffset( pointNode->parent , _d , _off ); - int fStart , fEnd; - BSplineData< FEMDegree , BType >::FunctionSpan( _d , fStart , fEnd ); - - double _pointValues[ DIMENSION ][SupportSize] , dPointValues[ DIMENSION ][SupportSize]; - memset( _pointValues , 0 , sizeof(double) * DIMENSION * SupportSize ); - memset( dPointValues , 0 , sizeof(double) * DIMENSION * SupportSize ); - - for( int dd=0 ; dd::FunctionIndex( _d , _off[dd]+i ); - if( fIdx>=fStart && fIdxnodeData.nodeIndex] ); - _dPointValue += dPointValues[2][l] * double( upSampledCoefficients[_node->nodeData.nodeIndex] ); - } - } - - pointGradient += Point3D< double >( __pointValue * dx_yValue , __pointValue * _xdyValue , _dPointValue * _x_yValue ); - } - } - return Point3D< Real >( pointGradient ); -} - -template< class Real > -template< int FEMDegree , BoundaryType BType > -Real Octree< Real >::_finerFunctionValue( Point3D< Real > p , const PointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* pointNode , const BSplineData< FEMDegree , BType >& bsData , const DenseNodeData< Real , FEMDegree >& finerCoefficients ) const -{ - typename TreeOctNode::Neighbors< BSplineSupportSizes< FEMDegree >::SupportSize > childNeighbors; - static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; - static const int RightPointSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; - static const int LeftSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; - static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; - - double pointValue = 0; - LocalDepth depth = _localDepth( pointNode ); - neighborKey.template getChildNeighbors< false >( _childIndex( pointNode , p ) , _localToGlobal( depth ) , childNeighbors ); - for( int j=-LeftPointSupportRadius ; j<=RightPointSupportRadius ; j++ ) - for( int k=-LeftPointSupportRadius ; k<=RightPointSupportRadius ; k++ ) - for( int l=-LeftPointSupportRadius ; l<=RightPointSupportRadius ; l++ ) - { - const TreeOctNode* _node = childNeighbors.neighbors[j+LeftPointSupportRadius][k+LeftPointSupportRadius][l+LeftPointSupportRadius]; - if( _isValidFEMNode( _node ) ) - { - int fIdx[3]; - functionIndex< FEMDegree , BType >( _node , fIdx ); - pointValue += - bsData.baseBSplines[ fIdx[0] ][LeftSupportRadius-j]( p[0] ) * - bsData.baseBSplines[ fIdx[1] ][LeftSupportRadius-k]( p[1] ) * - bsData.baseBSplines[ fIdx[2] ][LeftSupportRadius-l]( p[2] ) * - double( finerCoefficients[ _node->nodeData.nodeIndex ] ); - } - } - return Real( pointValue ); -} -template< class Real > -template< int FEMDegree , BoundaryType BType > -Point3D< Real > Octree< Real >::_finerFunctionGradient( Point3D< Real > p , const PointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* pointNode , const BSplineData< FEMDegree , BType >& bsData , const DenseNodeData< Real , FEMDegree >& finerCoefficients ) const -{ - typename TreeOctNode::Neighbors< BSplineSupportSizes< FEMDegree >::SupportSize > childNeighbors; - static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; - static const int RightPointSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; - static const int LeftSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; - static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; - - Point3D< double > pointGradient = 0; - LocalDepth depth = _localDepth( pointNode ); - neighborKey.template getChildNeighbors< false >( _childIndex( pointNode , p ) , _localToGlobal( depth ) , childNeighbors ); - for( int j=-LeftPointSupportRadius ; j<=RightPointSupportRadius ; j++ ) - for( int k=-LeftPointSupportRadius ; k<=RightPointSupportRadius ; k++ ) - for( int l=-LeftPointSupportRadius ; l<=RightPointSupportRadius ; l++ ) - { - const TreeOctNode* _node = childNeighbors.neighbors[j+LeftPointSupportRadius][k+LeftPointSupportRadius][l+LeftPointSupportRadius]; - if( _isValidFEMNode( _node ) ) - { - int fIdx[3]; - functionIndex< FEMDegree , BType >( _node , fIdx ); - double x = bsData. baseBSplines[ fIdx[0] ][LeftSupportRadius-j]( p[0] ) , y = bsData. baseBSplines[ fIdx[1] ][LeftSupportRadius-k]( p[1] ) , z = bsData. baseBSplines[ fIdx[2] ][LeftSupportRadius-l]( p[2] ); - double dx = bsData.dBaseBSplines[ fIdx[0] ][LeftSupportRadius-j]( p[0] ) , dy = bsData.dBaseBSplines[ fIdx[1] ][LeftSupportRadius-k]( p[1] ) , dz = bsData.dBaseBSplines[ fIdx[2] ][LeftSupportRadius-l]( p[2] ); - pointGradient += Point3D< double >( dx * y * z , x * dy * z , x * y * dz ) * (double)( finerCoefficients[ _node->nodeData.nodeIndex ] ); - } - } - return Point3D< Real >( pointGradient ); -} - -template< class Real > -template< int FEMDegree , BoundaryType BType , bool HasGradients > -void Octree< Real >::_setPointValuesFromCoarser( InterpolationInfo< HasGradients >& interpolationInfo , LocalDepth highDepth , const BSplineData< FEMDegree , BType >& bsData , const DenseNodeData< Real , FEMDegree >& upSampledCoefficients ) -{ - LocalDepth lowDepth = highDepth-1; - if( lowDepth<0 ) return; - std::vector< PointSupportKey< FEMDegree > > neighborKeys( std::max< int >( 1 , threads ) ); - for( size_t i=0 ; i& neighborKey = neighborKeys[ omp_get_thread_num() ]; - PointData< Real , HasGradients >* pData = interpolationInfo( _sNodes.treeNodes[i] ); - if( pData ) - { - neighborKey.template getNeighbors< false >( _sNodes.treeNodes[i]->parent ); -#if POINT_DATA_RES - for( int c=0 ; c::SAMPLES ; c++ ) if( (*pData)[c].weight ) - _ConstraintCalculator_< Real , FEMDegree , HasGradients >::_CalculateCoarser_ - ( - c , *pData , - _coarserFunctionValue( (*pData)[c].position , neighborKey , _sNodes.treeNodes[i] , bsData , upSampledCoefficients ) , - HasGradients ? _coarserFunctionGradient( (*pData)[c].position , neighborKey , _sNodes.treeNodes[i] , bsData , upSampledCoefficients ) : Point3D< Real >() , - interpolationInfo.valueWeight , interpolationInfo.gradientWeight - ); -#else // !POINT_DATA_RES - _ConstraintCalculator_< Real , FEMDegree , HasGradients >::_CalculateCoarser_ - ( - *pData , - _coarserFunctionValue( pData->position , neighborKey , _sNodes.treeNodes[i] , bsData , upSampledCoefficients ) , - HasGradients ? _coarserFunctionGradient( pData->position , neighborKey , _sNodes.treeNodes[i] , bsData , upSampledCoefficients ) : Point3D< Real >() , - interpolationInfo.valueWeight , interpolationInfo.gradientWeight - ); -#endif // POINT_DATA_RES - } - } -} - -template< class Real > -template< int FEMDegree , BoundaryType BType , bool HasGradients > -void Octree< Real >::_updateCumulativeInterpolationConstraintsFromFiner( const InterpolationInfo< HasGradients >& interpolationInfo , const BSplineData< FEMDegree , BType >& bsData , LocalDepth highDepth , const DenseNodeData< Real , FEMDegree >& finerCoefficients , DenseNodeData< Real , FEMDegree >& coarserConstraints ) const -{ - static const int SupportSize = BSplineSupportSizes< FEMDegree >::SupportSize; - static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; - static const int RightPointSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; - static const int LeftSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; - static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; - - // Note: We can't iterate over the finer point nodes as the point weights might be - // scaled incorrectly, due to the adaptive exponent. So instead, we will iterate - // over the coarser nodes and evaluate the finer solution at the associated points. - LocalDepth lowDepth = highDepth-1; - if( lowDepth<0 ) return; - size_t start = _sNodesBegin(lowDepth) , end = _sNodesEnd(lowDepth); - std::vector< PointSupportKey< FEMDegree > > neighborKeys( std::max< int >( 1 , threads ) ); - for( size_t i=0 ; i& neighborKey = neighborKeys[ omp_get_thread_num() ]; - const PointData< Real , HasGradients >* pData = interpolationInfo( _sNodes.treeNodes[i] ); - if( pData ) - { - typename TreeOctNode::Neighbors< SupportSize >& neighbors = neighborKey.template getNeighbors< false >( _sNodes.treeNodes[i] ); - // evaluate the solution @( depth ) at the current point @( depth-1 ) -#if POINT_DATA_RES - for( int c=0 ; c::SAMPLES ; c++ ) if( (*pData)[c].weight ) -#endif // POINT_DATA_RES - { -#if POINT_DATA_RES - Real finerPointDValue = _finerFunctionValue( (*pData)[c].position , neighborKey , _sNodes.treeNodes[i] , bsData , finerCoefficients ) * interpolationInfo.valueWeight * (*pData)[c].weight; - Point3D< Real > finerPointDGradient = HasGradients ? _finerFunctionGradient( (*pData)[c].position , neighborKey , _sNodes.treeNodes[i] , bsData , finerCoefficients ) * interpolationInfo.gradientWeight * (*pData)[c].weight : Point3D< Real >(); - Point3D< Real > p = (*pData)[c].position; -#else // !POINT_DATA_RES - Real finerPointDValue = _finerFunctionValue( pData->position , neighborKey , _sNodes.treeNodes[i] , bsData , finerCoefficients ) * interpolationInfo.valueWeight * pData->weight; - Point3D< Real > finerPointDGradient = HasGradients ? _finerFunctionGradient( pData->position , neighborKey , _sNodes.treeNodes[i] , bsData , finerCoefficients ) * interpolationInfo.gradientWeight * pData->weight : Point3D< Real >(); - Point3D< Real > p = pData->position; -#endif // POINT_DATA_RES - // Update constraints for all nodes @( depth-1 ) that overlap the point - int idx[3]; - functionIndex< FEMDegree , BType >( _sNodes.treeNodes[i] , idx ); - for( int x=-LeftPointSupportRadius ; x<=RightPointSupportRadius ; x++ ) for( int y=-LeftPointSupportRadius ; y<=RightPointSupportRadius ; y++ ) for( int z=-LeftPointSupportRadius ; z<=RightPointSupportRadius ; z++ ) - { - const TreeOctNode* _node = neighbors.neighbors[x+LeftPointSupportRadius][y+LeftPointSupportRadius][z+LeftPointSupportRadius]; - if( _isValidFEMNode( _node ) ) - { - double px = bsData.baseBSplines[idx[0]+x][LeftSupportRadius-x]( p[0] ) , py = bsData.baseBSplines[idx[1]+y][LeftSupportRadius-y]( p[1] ) , pz = bsData.baseBSplines[idx[2]+z][LeftSupportRadius-z]( p[2] ); -#pragma omp atomic - coarserConstraints[ _node->nodeData.nodeIndex ] += (Real)( px * py * pz * finerPointDValue ); - if( HasGradients ) - { - double dpx = bsData.dBaseBSplines[idx[0]+x][LeftSupportRadius-x]( p[0] ) , dpy = bsData.dBaseBSplines[idx[1]+y][LeftSupportRadius-y]( p[1] ) , dpz = bsData.dBaseBSplines[idx[2]+z][LeftSupportRadius-z]( p[2] ); -#pragma omp atomic - coarserConstraints[ _node->nodeData.nodeIndex ] += Point3D< Real >::Dot( finerPointDGradient , Point3D< Real >( dpx * py * pz , px * dpy * pz , px * py * dpz ) ); - } - } - } - } - } - } -} - -template< class Real > -template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > -int Octree< Real >::_setMatrixRow( const FEMSystemFunctor& F , const InterpolationInfo< HasGradients >* interpolationInfo , const typename TreeOctNode::Neighbors< BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& neighbors , Pointer( MatrixEntry< Real > ) row , int offset , const typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template Integrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) >& integrator , const Stencil< double , BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& stencil , const BSplineData< FEMDegree , BType >& bsData ) const -{ - static const int SupportSize = BSplineSupportSizes< FEMDegree >::SupportSize; - static const int OverlapRadius = - BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapStart; - static const int OverlapSize = BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize; - static const int LeftSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; - static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; - static const int LeftPointSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; - static const int RightPointSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; - - bool hasYZPoints[SupportSize] , hasZPoints[SupportSize][SupportSize]; - Real diagonal = 0; - // Given a node: - // -- for each node in its support: - // ---- if the supporting node contains a point: - // ------ evaluate the x, y, and z B-splines of the nodes supporting the point - // splineValues \in [-LeftSupportRadius,RightSupportRadius] x [-LeftSupportRadius,RightSupportRadius] x [-LeftSupportRadius,RightSupportRadius] x [0,Dimension) x [-LeftPointSupportRadius,RightPointSupportRadius] -#if POINT_DATA_RES - Real _splineValues[PointData< Real , HasGradients >::SAMPLES][SupportSize][SupportSize][SupportSize][DIMENSION][SupportSize]; - Real wSplineValues[PointData< Real , HasGradients >::SAMPLES][SupportSize][SupportSize][SupportSize][DIMENSION][SupportSize]; - Real dSplineValues[PointData< Real , HasGradients >::SAMPLES][SupportSize][SupportSize][SupportSize][DIMENSION][SupportSize]; - memset( _splineValues , 0 , sizeof( Real ) * PointData< Real , HasGradients >::SAMPLES * SupportSize * SupportSize * SupportSize * DIMENSION *SupportSize ); - memset( wSplineValues , 0 , sizeof( Real ) * PointData< Real , HasGradients >::SAMPLES * SupportSize * SupportSize * SupportSize * DIMENSION *SupportSize ); - memset( dSplineValues , 0 , sizeof( Real ) * PointData< Real , HasGradients >::SAMPLES * SupportSize * SupportSize * SupportSize * DIMENSION *SupportSize ); -#else // !POINT_DATA_RES - Real _splineValues[SupportSize][SupportSize][SupportSize][DIMENSION][SupportSize]; - Real wSplineValues[SupportSize][SupportSize][SupportSize][DIMENSION][SupportSize]; - Real dSplineValues[SupportSize][SupportSize][SupportSize][DIMENSION][SupportSize]; - memset( _splineValues , 0 , sizeof( Real ) * SupportSize * SupportSize * SupportSize * DIMENSION *SupportSize ); - memset( wSplineValues , 0 , sizeof( Real ) * SupportSize * SupportSize * SupportSize * DIMENSION *SupportSize ); - memset( dSplineValues , 0 , sizeof( Real ) * SupportSize * SupportSize * SupportSize * DIMENSION *SupportSize ); -#endif // NEW_POINT_DATA - - int count = 0; - const TreeOctNode* node = neighbors.neighbors[OverlapRadius][OverlapRadius][OverlapRadius]; - LocalDepth d ; LocalOffset off; - _localDepthAndOffset( node , d , off ); - int fStart , fEnd; - BSplineData< FEMDegree , BType >::FunctionSpan( d , fStart , fEnd ); - bool isInterior = _isInteriorlyOverlapped< FEMDegree , FEMDegree >( node ); - - if( interpolationInfo ) - { - // Iterate over all neighboring nodes that may have a constraining point - // -- For each one, compute the values of the spline functions supported on the point - for( int j=0 ; j& pData = *( (*interpolationInfo)( _node ) ); - -#if POINT_DATA_RES - for( int c=0 ; c::SAMPLES ; c++ ) if( pData[c].weight ) -#endif // POINT_DATA_RES - { -#if POINT_DATA_RES - Real (*__splineValues)[SupportSize] = _splineValues[c][jj][kk][ll]; - Real (*_wSplineValues)[SupportSize] = wSplineValues[c][jj][kk][ll]; - Real (*_dSplineValues)[SupportSize] = dSplineValues[c][jj][kk][ll]; - Real weight = pData[c].weight; - Point3D< Real > p = pData[c].position; -#else // !POINT_DATA_RES - Real (*__splineValues)[SupportSize] = _splineValues[jj][kk][ll]; - Real (*_wSplineValues)[SupportSize] = wSplineValues[jj][kk][ll]; - Real (*_dSplineValues)[SupportSize] = dSplineValues[jj][kk][ll]; - Real weight = pData.weight; - Point3D< Real > p = pData.position; -#endif // POINT_DATA_RES - - // evaluate the point p at all the nodes whose functions have it in their support - for( int s=-LeftPointSupportRadius ; s<=RightPointSupportRadius ; s++ ) for( int dd=0 ; dd::FunctionIndex( d , pOff[dd]+s ); - if( fIdx>=fStart && fIdxvalueWeight * weight; - Point3D< Real > weightedGradient; - if( HasGradients ) - { - Point3D< Real > gradient - ( - _dSplineValues[0][-j+LeftPointSupportRadius] * __splineValues[1][-k+LeftPointSupportRadius] * __splineValues[2][-l+LeftPointSupportRadius] , - __splineValues[0][-j+LeftPointSupportRadius] * _dSplineValues[1][-k+LeftPointSupportRadius] * __splineValues[2][-l+LeftPointSupportRadius] , - __splineValues[0][-j+LeftPointSupportRadius] * __splineValues[1][-k+LeftPointSupportRadius] * _dSplineValues[2][-l+LeftPointSupportRadius] - ); - weightedGradient = gradient * interpolationInfo->gradientWeight * weight; - diagonal += value * weightedValue + Point3D< Real >::Dot( gradient , weightedGradient ); - } - else diagonal += value * weightedValue; - - // Pre-multiply the x-coordinate values so that when we evaluate at one of the neighboring basis functions - // we get the product of the values of the center base function and the base function of the neighboring node - if( HasGradients ) for( int s=0 ; s& pData = *( (*interpolationInfo)( _node ) ); -#if POINT_DATA_RES - for( int c=0 ; c::SAMPLES ; c++ ) if( pData[c].weight ) -#endif // POINT_DATA_RES - { -#if POINT_DATA_RES - Real (*__splineValues)[SupportSize] = _splineValues[c][i+LeftSupportRadius][j+LeftSupportRadius][k+LeftSupportRadius]; - Real (*_wSplineValues)[SupportSize] = wSplineValues[c][i+LeftSupportRadius][j+LeftSupportRadius][k+LeftSupportRadius]; - Real (*_dSplineValues)[SupportSize] = dSplineValues[c][i+LeftSupportRadius][j+LeftSupportRadius][k+LeftSupportRadius]; -#else // !POINT_DATA_RES - Real (*__splineValues)[SupportSize] = _splineValues[i+LeftSupportRadius][j+LeftSupportRadius][k+LeftSupportRadius]; - Real (*_wSplineValues)[SupportSize] = wSplineValues[i+LeftSupportRadius][j+LeftSupportRadius][k+LeftSupportRadius]; - Real (*_dSplineValues)[SupportSize] = dSplineValues[i+LeftSupportRadius][j+LeftSupportRadius][k+LeftSupportRadius]; -#endif // POINT_DATA_RES - // Iterate over all neighbors whose support contains the point and accumulate the mutual integral - for( int ii=-LeftPointSupportRadius ; ii<=RightPointSupportRadius ; ii++ ) - for( int jj=-LeftPointSupportRadius ; jj<=RightPointSupportRadius ; jj++ ) - if( HasGradients ) - { - Real partialW_SplineValue = _wSplineValues[0][ii+LeftPointSupportRadius ] * __splineValues[1][jj+LeftPointSupportRadius ]; - Real partial__SplineValue = __splineValues[0][ii+LeftPointSupportRadius ] * __splineValues[1][jj+LeftPointSupportRadius ]; - Real partialD0SplineValue = _dSplineValues[0][ii+LeftPointSupportRadius ] * __splineValues[1][jj+LeftPointSupportRadius ]; - Real partialD1SplineValue = __splineValues[0][ii+LeftPointSupportRadius ] * _dSplineValues[1][jj+LeftPointSupportRadius ]; - Real* _pointValues = pointValues[i+ii+OverlapRadius][j+jj+OverlapRadius] + k + OverlapRadius; - Real* ___splineValues = __splineValues[2] + LeftPointSupportRadius; - Real* __dSplineValues = _dSplineValues[2] + LeftPointSupportRadius; - TreeOctNode* const * _neighbors = neighbors.neighbors[i+ii+OverlapRadius][j+jj+OverlapRadius] + k + OverlapRadius; - for( int kk=-LeftPointSupportRadius ; kk<=RightPointSupportRadius ; kk++ ) if( _isValidFEMNode( _neighbors[kk] ) ) - _pointValues[kk] += - partialW_SplineValue * ___splineValues[kk] + partialD0SplineValue * ___splineValues[kk] + partialD1SplineValue * ___splineValues[kk] + partial__SplineValue * __dSplineValues[kk]; - } - else - { - Real partialWSplineValue = _wSplineValues[0][ii+LeftPointSupportRadius ] * __splineValues[1][jj+LeftPointSupportRadius ]; - Real* _pointValues = pointValues[i+ii+OverlapRadius][j+jj+OverlapRadius] + k + OverlapRadius; - Real* ___splineValues = __splineValues[2] + LeftPointSupportRadius; - TreeOctNode* const * _neighbors = neighbors.neighbors[i+ii+OverlapRadius][j+jj+OverlapRadius] + k + OverlapRadius; - for( int kk=-LeftPointSupportRadius ; kk<=RightPointSupportRadius ; kk++ ) if( _isValidFEMNode( _neighbors[kk] ) ) - _pointValues[kk] += partialWSplineValue * ___splineValues[kk]; - } - } - } - } - } - pointValues[OverlapRadius][OverlapRadius][OverlapRadius] = diagonal; - int nodeIndex = neighbors.neighbors[OverlapRadius][OverlapRadius][OverlapRadius]->nodeData.nodeIndex; - if( isInterior ) // General case, so try to make fast - { - const TreeOctNode* const * _nodes = &neighbors.neighbors[0][0][0]; - const double* _stencil = &stencil( 0 , 0 , 0 ); - Real* _values = &pointValues[0][0][0]; - const static int CenterIndex = OverlapSize*OverlapSize*OverlapRadius + OverlapSize*OverlapRadius + OverlapRadius; - if( interpolationInfo ) for( int i=0 ; i( nodeIndex-offset , _values[CenterIndex] ); - for( int i=0 ; i( _nodes[i]->nodeData.nodeIndex-offset , _values[i] ); - } - else - { - LocalDepth d ; LocalOffset off; - _localDepthAndOffset( node , d , off ); - Real temp = (Real)F.integrate( integrator , off , off ); - if( interpolationInfo ) temp += pointValues[OverlapRadius][OverlapRadius][OverlapRadius]; - row[count++] = MatrixEntry< Real >( nodeIndex-offset , temp ); - for( int x=0 ; x( _node->nodeData.nodeIndex-offset , temp ); - } - } - return count; -} - -template< class Real > -template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > -int Octree< Real >::_getMatrixAndUpdateConstraints( const FEMSystemFunctor& F , const InterpolationInfo< HasGradients >* interpolationInfo , SparseMatrix< Real >& matrix , DenseNodeData< Real , FEMDegree >& constraints , typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template Integrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) >& integrator , typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template ChildIntegrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) >& childIntegrator , const BSplineData< FEMDegree , BType >& bsData , LocalDepth depth , const DenseNodeData< Real , FEMDegree >& metSolution , bool coarseToFine ) -{ - static const int OverlapRadius = - BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapStart; - static const int OverlapSize = BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize; - - size_t start = _sNodesBegin(depth) , end = _sNodesEnd(depth) , range = end-start; - Stencil< double , OverlapSize > stencil , stencils[2][2][2]; - SystemCoefficients< FEMDegree , BType , FEMDegree , BType >::SetCentralSystemStencil ( F , integrator , stencil ); - SystemCoefficients< FEMDegree , BType , FEMDegree , BType >::SetCentralSystemStencils( F , childIntegrator , stencils ); - matrix.Resize( (int)range ); - std::vector< AdjacenctNodeKey > neighborKeys( std::max< int >( 1 , threads ) ); - for( size_t i=0 ; i neighbors; - neighborKey.template getNeighbors< false , OverlapRadius , OverlapRadius >( node , neighbors ); - int count = _getMatrixRowSize< FEMDegree , BType >( neighbors ); - // Allocate memory for the row - matrix.SetRowSize( i , count ); - - // Set the row entries - matrix.rowSizes[i] = _setMatrixRow( F , interpolationInfo , neighbors , matrix[i] , (int)start , integrator , stencil , bsData ); - if( coarseToFine && depth>0 ) - { - // Offset the constraints using the solution from lower resolutions. - int x , y , z; - Cube::FactorCornerIndex( (int)( node - node->parent->children ) , x , y , z ); - typename TreeOctNode::Neighbors< OverlapSize > pNeighbors; - neighborKey.template getNeighbors< false , OverlapRadius , OverlapRadius >( node->parent , pNeighbors ); - _updateConstraintsFromCoarser( F , interpolationInfo , neighbors , pNeighbors , node , constraints , metSolution , childIntegrator , stencils[x][y][z] , bsData ); - } - } - memoryUsage(); - return 1; -} - -template< class Real > -template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > -int Octree< Real >::_getSliceMatrixAndUpdateConstraints( const FEMSystemFunctor& F , const InterpolationInfo< HasGradients >* interpolationInfo , SparseMatrix< Real >& matrix , DenseNodeData< Real , FEMDegree >& constraints , typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template Integrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) >& integrator , typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template ChildIntegrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) >& childIntegrator , const BSplineData< FEMDegree , BType >& bsData , LocalDepth depth , int slice , const DenseNodeData< Real , FEMDegree >& metSolution , bool coarseToFine ) -{ - static const int OverlapSize = BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize; - static const int OverlapRadius = -BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapStart; - - int nStart = _sNodesBegin( depth , slice ) , nEnd = _sNodesEnd( depth , slice ); - size_t range = nEnd - nStart; - Stencil< double , OverlapSize > stencil , stencils[2][2][2]; - SystemCoefficients< FEMDegree , BType , FEMDegree , BType >::SetCentralSystemStencil ( F , integrator , stencil ); - SystemCoefficients< FEMDegree , BType , FEMDegree , BType >::SetCentralSystemStencils( F , childIntegrator , stencils ); - - matrix.Resize( (int)range ); - std::vector< AdjacenctNodeKey > neighborKeys( std::max< int >( 1 , threads ) ); - for( size_t i=0 ; i neighbors; - neighborKey.template getNeighbors< false , OverlapRadius , OverlapRadius >( node , neighbors ); - int count = _getMatrixRowSize< FEMDegree , BType >( neighbors ); - - // Allocate memory for the row - matrix.SetRowSize( i , count ); - - // Set the row entries - matrix.rowSizes[i] = _setMatrixRow( F , interpolationInfo , neighbors , matrix[i] , _sNodesBegin( depth , slice ) , integrator , stencil , bsData ); - - if( coarseToFine && depth>0 ) - { - // Offset the constraints using the solution from lower resolutions. - int x , y , z; - Cube::FactorCornerIndex( (int)( node - node->parent->children ) , x , y , z ); - typename TreeOctNode::Neighbors< OverlapSize > pNeighbors; - neighborKey.template getNeighbors< false, OverlapRadius , OverlapRadius >( node->parent , pNeighbors ); - _updateConstraintsFromCoarser( F , interpolationInfo , neighbors , pNeighbors , node , constraints , metSolution , childIntegrator , stencils[x][y][z] , bsData ); - } - } -#if !defined( _WIN32 ) && !defined( _WIN64 ) -#pragma message( "[WARNING] I'm not sure how expensive this system call is on non-Windows system. (You may want to comment this out.)" ) -#endif // !_WIN32 && !_WIN64 - memoryUsage(); - return 1; -} - -#ifndef MOD -#define MOD( a , b ) ( (a)>0 ? (a) % (b) : ( (b) - ( -(a) % (b) ) ) % (b) ) -#endif // MOD -template< class Real > -template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > -int Octree< Real >::_solveSystemGS( const FEMSystemFunctor& F , const BSplineData< FEMDegree , BType >& bsData , InterpolationInfo< HasGradients >* interpolationInfo , LocalDepth depth , DenseNodeData< Real , FEMDegree >& solution , DenseNodeData< Real , FEMDegree >& constraints , DenseNodeData< Real , FEMDegree >& metSolutionConstraints , int iters , bool coarseToFine , _SolverStats& stats , bool computeNorms ) -{ - const int OverlapRadius = -BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapStart; - typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template Integrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) > integrator; - typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template ChildIntegrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) > childIntegrator; - BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::SetIntegrator( integrator , depth ); - if( depth>0 ) BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::SetChildIntegrator( childIntegrator , depth-1 ); - - DenseNodeData< Real , FEMDegree >& metSolution = metSolutionConstraints; // This stores the up-sampled solution up to depth-2 - DenseNodeData< Real , FEMDegree >& metConstraints = metSolutionConstraints; // This stores the down-sampled constraints up to depth - - int sliceBegin = _BSplineBegin< FEMDegree , BType >( depth ) , sliceEnd = _BSplineEnd< FEMDegree , BType >( depth ); - double& systemTime = stats. systemTime; - double& solveTime = stats. solveTime; - double& evaluateTime = stats.evaluateTime; - systemTime = solveTime = evaluateTime = 0.; - - if( coarseToFine ) - { - if( depth>0 ) - { - // Up-sample the cumulative change in solution @(depth-2) into the cumulative change in solution @(depth-1) - if( depth-2>=0 ) _upSample< Real , FEMDegree , BType >( depth-1 , metSolution ); - // Add in the change in solution @(depth-1) -#pragma omp parallel for num_threads( threads ) - for( int i=_sNodesBegin(depth-1) ; i<_sNodesEnd(depth-1) ; i++ ) metSolution[i] += solution[i]; - // evaluate the points @(depth) using the cumulative change in solution @(depth-1) - if( interpolationInfo ) - { - evaluateTime = Time(); - _setPointValuesFromCoarser( *interpolationInfo , depth , bsData , metSolution ); - evaluateTime = Time() - evaluateTime; - } - } - } - else if( depth<_maxDepth ) for( int i=_sNodesBegin(depth) ; i<_sNodesEnd(depth) ; i++ ) constraints[i] -= metConstraints[i]; - double bNorm = 0 , inRNorm = 0 , outRNorm = 0; - if( depth>=0 ) - { - // Add padding space if we are computing residuals - int frontOffset = computeNorms ? OverlapRadius : 0 , backOffset = computeNorms ? OverlapRadius : 0; - // Set the number of in-memory slices required for a temporally blocked solver - int solveSlices = std::max< int >( 0 , std::min< int >( OverlapRadius*iters - (OverlapRadius-1) , sliceEnd-sliceBegin ) ) , matrixSlices = std::max< int >( 1 , std::min< int >( solveSlices+frontOffset+backOffset , sliceEnd-sliceBegin ) ); - // The list of matrices for each in-memory slices - std::vector< SparseMatrix< Real > > _M( matrixSlices ); - // The list of multi-colored indices for each in-memory slice - std::vector< std::vector< std::vector< int > > > __mcIndices( solveSlices ); - - int dir = coarseToFine ? -1 : 1 , start = coarseToFine ? sliceEnd-1 : sliceBegin , end = coarseToFine ? sliceBegin-1 : sliceEnd; - for( int frontSlice=start-frontOffset*dir , backSlice = frontSlice-OverlapRadius*(iters-1)*dir ; backSlice!=end+backOffset*dir ; frontSlice+=dir , backSlice+=dir ) - { - double t; - if( frontSlice+frontOffset*dir>=sliceBegin && frontSlice+frontOffset*dir ) start = _M[_s][j]; - ConstPointer( MatrixEntry< Real > ) end = start + _M[_s].rowSizes[j]; - ConstPointer( MatrixEntry< Real > ) e; - for( e=start ; e!=end ; e++ ) temp += X[ e->N ] * e->Value; - bNorm += B[j]*B[j]; - inRNorm += (temp-B[j]) * (temp-B[j]); - } - } - } - t = Time(); - // Compute the multicolor indices - if( iters && frontSlice>=sliceBegin && frontSlice( _sNodesBegin( depth , s ) , _sNodesEnd( depth , s ) , __mcIndices[__s] ); - } - // Advance through the in-memory slices, taking an appropriately sized stride - for( int slice=frontSlice ; slice*dir>=backSlice*dir ; slice-=OverlapRadius*dir ) - if( slice>=sliceBegin && slice::SolveGS( __mcIndices[__s] , _M[_s] , B , X , !coarseToFine , threads ); - } - solveTime += Time() - t; - // Compute residuals - if( computeNorms && backSlice-backOffset*dir>=sliceBegin && backSlice-backOffset*dir ) start = _M[_s][j]; - ConstPointer( MatrixEntry< Real > ) end = start + _M[_s].rowSizes[j]; - ConstPointer( MatrixEntry< Real > ) e; - for( e=start ; e!=end ; e++ ) temp += X[ e->N ] * e->Value; - outRNorm += (temp-B[j]) * (temp-B[j]); - } - } - } - } - if( computeNorms ) stats.bNorm2 = bNorm , stats.inRNorm2 = inRNorm , stats.outRNorm2 = outRNorm; - - if( !coarseToFine && depth>0 ) - { - // Explicitly compute the restriction of the met solution onto the coarser nodes - // and down-sample the previous accumulation - { - _updateCumulativeIntegralConstraintsFromFiner( F , bsData , depth , solution , metConstraints ); - if( interpolationInfo ) _updateCumulativeInterpolationConstraintsFromFiner( *interpolationInfo , bsData , depth , solution , metConstraints ); - if( depth<_maxDepth ) _downSample< Real , FEMDegree , BType >( depth , metConstraints ); - } - } - memoryUsage(); - - return iters; -} -#undef MOD - -template< class Real > -template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > -int Octree< Real >::_solveSystemCG( const FEMSystemFunctor& F , const BSplineData< FEMDegree , BType >& bsData , InterpolationInfo< HasGradients >* interpolationInfo , LocalDepth depth , DenseNodeData< Real , FEMDegree >& solution , DenseNodeData< Real , FEMDegree >& constraints , DenseNodeData< Real , FEMDegree >& metSolutionConstraints , int iters , bool coarseToFine , _SolverStats& stats , bool computeNorms , double accuracy ) -{ - typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template Integrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) > integrator; - typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template ChildIntegrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) > childIntegrator; - BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::SetIntegrator( integrator , depth ); - if( depth>0 ) BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::SetChildIntegrator( childIntegrator , depth-1 ); - - DenseNodeData< Real , FEMDegree >& metSolution = metSolutionConstraints; // This stores the up-sampled solution up to depth-2 - DenseNodeData< Real , FEMDegree >& metConstraints = metSolutionConstraints; // This stores the down-sampled constraints up to depth - - int iter = 0; - Pointer( Real ) X = GetPointer( & solution[0] + _sNodesBegin(depth) , _sNodesSize(depth) ); - Pointer( Real ) B = GetPointer( &constraints[0] + _sNodesBegin(depth) , _sNodesSize(depth) ); - SparseMatrix< Real > M; - double& systemTime = stats. systemTime; - double& solveTime = stats. solveTime; - double& evaluateTime = stats.evaluateTime; - systemTime = solveTime = evaluateTime = 0.; - - if( coarseToFine ) - { - if( depth>0 ) - { - // Up-sample the cumulative change in solution @(depth-2) into the cumulative change in solution @(depth-1) - if( depth-2>=0 ) _upSample< Real , FEMDegree , BType >( depth-1 , metSolution ); - // Add in the change in solution @(depth-1) -#pragma omp parallel for num_threads( threads ) - for( int i=_sNodesBegin(depth-1) ; i<_sNodesEnd(depth-1) ; i++ ) metSolution[i] += solution[i]; - // evaluate the points @(depth) using the cumulative change in solution @(depth-1) - if( interpolationInfo ) - { - evaluateTime = Time(); - _setPointValuesFromCoarser( *interpolationInfo , depth , bsData , metSolution ); - evaluateTime = Time() - evaluateTime; - } - } - } - else if( depth<_maxDepth ) for( int i=_sNodesBegin(depth) ; i<_sNodesEnd(depth) ; i++ ) constraints[i] -= metConstraints[i]; - - // Get the system matrix (and adjust the right-hand-side based on the coarser solution if prolonging) - systemTime = Time(); - _getMatrixAndUpdateConstraints( F , interpolationInfo , M , constraints , integrator , childIntegrator , bsData , depth , metSolution , coarseToFine ); - systemTime = Time()-systemTime; - - solveTime = Time(); - // Solve the linear system - accuracy = Real( accuracy / 100000 ) * M.rows; - int dim = _BSplineEnd< FEMDegree , BType >( depth ) - _BSplineBegin< FEMDegree , BType >( depth ); - int nonZeroRows = 0; - for( int i=0 ; ivalueWeight ) && HasPartitionOfUnity< BType >() && F.vanishesOnConstants() ); - double bNorm = 0 , inRNorm = 0 , outRNorm = 0; - if( computeNorms ) - { -#pragma omp parallel for num_threads( threads ) reduction( + : bNorm , inRNorm ) - for( int j=0 ; j ) start = M[j]; - ConstPointer( MatrixEntry< Real > ) end = start + M.rowSizes[j]; - ConstPointer( MatrixEntry< Real > ) e; - for( e=start ; e!=end ; e++ ) temp += X[ e->N ] * e->Value; - bNorm += B[j] * B[j]; - inRNorm += ( temp-B[j] ) * ( temp-B[j] ); - } - } - - iters = std::min< int >( nonZeroRows , iters ); - if( iters ) iter += SparseMatrix< Real >::SolveCG( M , ( ConstPointer( Real ) )B , iters , X , Real( accuracy ) , 0 , addDCTerm , false , threads ); - - solveTime = Time()-solveTime; - if( computeNorms ) - { -#pragma omp parallel for num_threads( threads ) reduction( + : outRNorm ) - for( int j=0 ; j ) start = M[j]; - ConstPointer( MatrixEntry< Real > ) end = start + M.rowSizes[j]; - ConstPointer( MatrixEntry< Real > ) e; - for( e=start ; e!=end ; e++ ) temp += X[ e->N ] * e->Value; - outRNorm += ( temp-B[j] ) * ( temp-B[j] ); - } - stats.bNorm2 = bNorm , stats.inRNorm2 = inRNorm , stats.outRNorm2 = outRNorm; - } - - // Copy the old solution into the buffer, write in the new solution, compute the change, and update the met solution - if( !coarseToFine && depth>0 ) - { - // Explicitly compute the restriction of the met solution onto the coarser nodes - // and down-sample the previous accumulation - { - _updateCumulativeIntegralConstraintsFromFiner( F , bsData , depth , solution , metConstraints ); - if( interpolationInfo ) _updateCumulativeInterpolationConstraintsFromFiner( *interpolationInfo , bsData , depth , solution , metConstraints ); - if( depth>_maxDepth ) _downSample< Real , FEMDegree , BType >( depth , metConstraints ); - } - } - memoryUsage(); - return iter; -} - -template< class Real > -template< int FEMDegree , BoundaryType BType > -int Octree< Real >::_getMatrixRowSize( const typename TreeOctNode::Neighbors< BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& neighbors ) const -{ - static const int OverlapSize = BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize; - static const int OverlapRadius = - BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapStart; - - int count = 0; - int nodeIndex = neighbors.neighbors[OverlapRadius][OverlapRadius][OverlapRadius]->nodeData.nodeIndex; - const TreeOctNode* const * _nodes = &neighbors.neighbors[0][0][0]; - for( int i=0 ; i -template< int FEMDegree1 , int FEMDegree2 > -void Octree< Real >::_SetParentOverlapBounds( const TreeOctNode* node , int& startX , int& endX , int& startY , int& endY , int& startZ , int& endZ ) -{ - const int OverlapStart = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::OverlapStart; - - if( node->parent ) - { - int x , y , z , c = (int)( node - node->parent->children ); - Cube::FactorCornerIndex( c , x , y , z ); - startX = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::ParentOverlapStart[x]-OverlapStart , endX = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::ParentOverlapEnd[x]-OverlapStart+1; - startY = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::ParentOverlapStart[y]-OverlapStart , endY = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::ParentOverlapEnd[y]-OverlapStart+1; - startZ = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::ParentOverlapStart[z]-OverlapStart , endZ = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::ParentOverlapEnd[z]-OverlapStart+1; - } -} - -// It is assumed that at this point, the evaluationg of the current depth's points, using the coarser resolution solution -// has already happened -template< class Real > -template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > -void Octree< Real >::_updateConstraintsFromCoarser( const FEMSystemFunctor& F , const InterpolationInfo< HasGradients >* interpolationInfo , const typename TreeOctNode::Neighbors< BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& neighbors , const typename TreeOctNode::Neighbors< BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& pNeighbors , TreeOctNode* node , DenseNodeData< Real , FEMDegree >& constraints , const DenseNodeData< Real , FEMDegree >& metSolution , const typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template ChildIntegrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) >& childIntegrator , const Stencil< double , BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& lapStencil , const BSplineData< FEMDegree , BType >& bsData ) const -{ - static const int LeftSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; - static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; - static const int OverlapRadius = - BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapStart; - - if( _localDepth( node )<=0 ) return; - // This is a conservative estimate as we only need to make sure that the parent nodes don't overlap the child (not the parent itself) - bool isInterior = _isInteriorlyOverlapped< FEMDegree , FEMDegree >( node->parent ); - LocalDepth d ; LocalOffset off; - _localDepthAndOffset( node , d , off ); - - // Offset the constraints using the solution from lower resolutions. - int startX , endX , startY , endY , startZ , endZ; - _SetParentOverlapBounds< FEMDegree , FEMDegree >( node , startX , endX , startY , endY , startZ , endZ ); - - for( int x=startX ; xnodeData.nodeIndex ]; - { - if( isInterior ) constraints[ node->nodeData.nodeIndex ] -= Real( lapStencil( x , y , z ) * _solution ); - else - { - LocalDepth _d ; LocalOffset _off; - _localDepthAndOffset( _node , _d , _off ); - constraints[ node->nodeData.nodeIndex ] -= (Real)F.integrate( childIntegrator , _off , off ) * _solution; - } - } - } - - if( interpolationInfo ) - { - double constraint = 0; - int fIdx[3]; - functionIndex< FEMDegree , BType >( node , fIdx ); - // evaluate the current node's basis function at adjacent points - for( int x=-LeftSupportRadius ; x<=RightSupportRadius ; x++ ) for( int y=-LeftSupportRadius ; y<=RightSupportRadius ; y++ ) for( int z=-LeftSupportRadius ; z<=RightSupportRadius ; z++ ) - { - const TreeOctNode* _node = neighbors.neighbors[x+OverlapRadius][y+OverlapRadius][z+OverlapRadius]; - if( _isValidSpaceNode( _node ) && (*interpolationInfo)( _node ) ) - { - const PointData< Real , HasGradients >& pData = *( (*interpolationInfo)( _node ) ); - constraint += _ConstraintCalculator_< Real , FEMDegree , HasGradients >::_CalculateConstraint_ - ( - pData , - bsData. baseBSplines[ fIdx[0] ][x+LeftSupportRadius] , - bsData. baseBSplines[ fIdx[1] ][y+LeftSupportRadius] , - bsData. baseBSplines[ fIdx[2] ][z+LeftSupportRadius] , - bsData.dBaseBSplines[ fIdx[0] ][x+LeftSupportRadius] , - bsData.dBaseBSplines[ fIdx[1] ][y+LeftSupportRadius] , - bsData.dBaseBSplines[ fIdx[2] ][z+LeftSupportRadius] - ); - } - } - constraints[ node->nodeData.nodeIndex ] -= Real( constraint ); - } -} - -// Given the solution @( depth ) add to the met constraints @( depth-1 ) -template< class Real > -template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor > -void Octree< Real >::_updateCumulativeIntegralConstraintsFromFiner( const FEMSystemFunctor& F , const BSplineData< FEMDegree , BType >& bsData , LocalDepth highDepth , const DenseNodeData< Real , FEMDegree >& fineSolution , DenseNodeData< Real , FEMDegree >& coarseConstraints ) const -{ - typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template ChildIntegrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) > childIntegrator; - BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::SetChildIntegrator( childIntegrator , highDepth-1 ); - - static const int OverlapSize = BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize; - static const int OverlapRadius = - BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapStart; - typedef typename TreeOctNode::NeighborKey< -BSplineSupportSizes< FEMDegree >::SupportStart , BSplineSupportSizes< FEMDegree >::SupportEnd >SupportKey; - - if( highDepth<=0 ) return; - // Get the stencil describing the Laplacian relating coefficients @(depth) with coefficients @(depth-1) - Stencil< double , OverlapSize > stencils[2][2][2]; - SystemCoefficients< FEMDegree , BType , FEMDegree , BType >::SetCentralSystemStencils( F , childIntegrator , stencils ); - size_t start = _sNodesBegin( highDepth) , end = _sNodesEnd(highDepth) , range = end-start; - int lStart = _sNodesBegin(highDepth-1); - - // Iterate over the nodes @( depth ) - std::vector< SupportKey > neighborKeys( std::max< int >( 1 , threads ) ); - for( size_t i=0 ; iparent->children ); - Cube::FactorCornerIndex( c , x , y , z ); - { - typename TreeOctNode::Neighbors< OverlapSize > pNeighbors; - neighborKey.template getNeighbors< false , OverlapRadius , OverlapRadius >( node->parent , pNeighbors ); - const Stencil< double , OverlapSize >& stencil = stencils[x][y][z]; - - bool isInterior = _isInteriorlyOverlapped< FEMDegree , FEMDegree >( node->parent ); - LocalDepth d ; LocalOffset off; - _localDepthAndOffset( node , d , off ); - - // Offset the constraints using the solution from finer resolutions. - int startX , endX , startY , endY , startZ , endZ; - _SetParentOverlapBounds< FEMDegree , FEMDegree >( node , startX , endX , startY , endY , startZ , endZ ); - - Real solution = fineSolution[ node->nodeData.nodeIndex ]; - for( int x=startX ; xnodeData.nodeIndex ] += Real( stencil( x , y , z ) * solution ); - else - { - LocalDepth _d ; LocalOffset _off; - _localDepthAndOffset( _node , _d , _off ); -#pragma omp atomic - coarseConstraints[ _node->nodeData.nodeIndex ] += Real( F.integrate( childIntegrator , _off , off ) * solution ); - } - } - } - } -} - -template< class Real > -template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > -void Octree< Real >::setSystemMatrix( const FEMSystemFunctor& F , const InterpolationInfo< HasGradients >* interpolationInfo , LocalDepth depth , SparseMatrix< Real >& matrix ) const -{ - if( depth<0 || depth>_maxDepth ) fprintf( stderr , "[ERROR] System depth out of bounds: %d <= %d <= %d\n" , 0 , depth , _maxDepth ) , exit( 0 ); - typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template Integrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) > integrator; - BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::SetIntegrator( integrator , depth ); - BSplineData< FEMDegree , BType > bsData( depth ); - - static const int OverlapRadius = - BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapStart; - static const int OverlapSize = BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize; - - Stencil< double , OverlapSize > stencil; - SystemCoefficients< FEMDegree , BType , FEMDegree , BType >::SetCentralSystemStencil ( F , integrator , stencil ); - - matrix.Resize( _sNodesSize(depth) ); - std::vector< AdjacenctNodeKey > neighborKeys( std::max< int >( 1 , threads ) ); - for( size_t i=0 ; i neighbors; - neighborKey.template getNeighbors< false , OverlapRadius , OverlapRadius >( _sNodes.treeNodes[i] , neighbors ); - - matrix.SetRowSize( ii , _getMatrixRowSize< FEMDegree , BType >( neighbors ) ); - matrix.rowSizes[ii] = _setMatrixRow( F , interpolationInfo , neighbors , matrix[ii] , _sNodesBegin(depth) , integrator , stencil , bsData ); - } -} - -template< class Real > -template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > -DenseNodeData< Real , FEMDegree > Octree< Real >::solveSystem( const FEMSystemFunctor& F , InterpolationInfo< HasGradients >* interpolationInfo , DenseNodeData< Real , FEMDegree >& constraints , LocalDepth maxSolveDepth , const typename Octree< Real >::SolverInfo& solverInfo ) -{ - BSplineData< FEMDegree , BType > bsData( maxSolveDepth ); - - maxSolveDepth = std::min< LocalDepth >( maxSolveDepth , _maxDepth ); - int iter = 0; - const int _iters = std::max< int >( 0 , solverInfo.iters ); - - DenseNodeData< Real , FEMDegree > solution( _sNodesEnd( _maxDepth ) ); - memset( &solution[0] , 0 , sizeof(Real) * _sNodesEnd( _maxDepth ) ); - - DenseNodeData< Real , FEMDegree > metSolution( _sNodesEnd( _maxDepth-1 ) ); - memset( &metSolution[0] , 0 , sizeof(Real)*_sNodesEnd( _maxDepth-1 ) ); - for( LocalDepth d=0 ; d<=maxSolveDepth ; d++ ) - { - int iters = (int)ceil( _iters * pow( solverInfo.lowResIterMultiplier , maxSolveDepth-d ) ); - _SolverStats sStats; - if( !d ) iter = _solveSystemCG( F , bsData , interpolationInfo , d , solution , constraints , metSolution , _sNodesSize(d) , true , sStats , solverInfo.showResidual , 0 ); - else - { - if( d>solverInfo.cgDepth ) iter = _solveSystemGS( F , bsData , interpolationInfo , d , solution , constraints , metSolution , iters , true , sStats , solverInfo.showResidual ); - else iter = _solveSystemCG( F , bsData , interpolationInfo , d , solution , constraints , metSolution , iters , true , sStats , solverInfo.showResidual , solverInfo.cgAccuracy ); - } - int femNodes = 0; -#pragma omp parallel for reduction( + : femNodes ) - for( int i=_sNodesBegin(d) ; i<_sNodesEnd(d) ; i++ ) if( _isValidFEMNode( _sNodes.treeNodes[i] ) ) femNodes++; - if( solverInfo.verbose ) - { - if( maxSolveDepth<10 ) printf( "Depth[%d/%d]:\t" , d , maxSolveDepth ); - else printf( "Depth[%2d/%d]:\t" , d , maxSolveDepth ); - printf( "Evaluated / Got / Solved in: %6.3f / %6.3f / %6.3f\t(%.3f MB)\tNodes: %d\n" , sStats.evaluateTime , sStats.systemTime , sStats.solveTime , _localMemoryUsage , femNodes ); - } - if( solverInfo.showResidual && iters ) - { - for( LocalDepth dd=0 ; dd %.4e -> %.4e (%.2e) [%d]\n" , d<=solverInfo.cgDepth ? "CG" : "GS" , sqrt( sStats.bNorm2 ) , sqrt( sStats.inRNorm2 ) , sqrt( sStats.outRNorm2 ) , sqrt( sStats.outRNorm2 / sStats.bNorm2 ) , iters ); - } - } - memoryUsage(); - return solution; -} - -template< class Real > -template< int FEMDegree > -DenseNodeData< Real , FEMDegree > Octree< Real >::initDenseNodeData( void ) -{ - DenseNodeData< Real , FEMDegree > constraints( _sNodes.size() ); - memset( &constraints[0] , 0 , sizeof(Real)*_sNodes.size() ); - return constraints; -} -template< > template< > float Octree< float >::_Dot( const float & r1 , const float & r2 ){ return r1*r2; } -template< > template< > double Octree< double >::_Dot( const double& r1 , const double& r2 ){ return r1*r2; } -template< > template< > float Octree< float >::_Dot( const Point3D< float >& p1 , const Point3D< float >& p2 ){ return Point3D< float >::Dot( p1 , p2 ); } -template< > template< > double Octree< double >::_Dot( const Point3D< double >& p1 , const Point3D< double >& p2 ){ return Point3D< double >::Dot( p1 , p2 ); } -template< > template< > bool Octree< float >::_IsZero( const float & r ){ return r==0; } -template< > template< > bool Octree< double >::_IsZero( const double& r ){ return r==0; } -template< > template< > bool Octree< float >::_IsZero( const Point3D< float >& p ){ return p[0]==0 && p[1]==0 && p[2]==0; } -template< > template< > bool Octree< double >::_IsZero( const Point3D< double >& p ){ return p[0]==0 && p[1]==0 && p[2]==0; } -template< class Real > -template< int FEMDegree , BoundaryType FEMBType , int CDegree , BoundaryType CBType , class FEMConstraintFunctor , class Coefficients , class D , class _D > -void Octree< Real >::_addFEMConstraints( const FEMConstraintFunctor& F , const Coefficients& coefficients , DenseNodeData< Real , FEMDegree >& constraints , LocalDepth maxDepth ) -{ - typedef typename TreeOctNode::NeighborKey< -BSplineSupportSizes< FEMDegree >::SupportStart , BSplineSupportSizes< FEMDegree >::SupportEnd > SupportKey; - const int CFEMOverlapSize = BSplineOverlapSizes< CDegree , FEMDegree >::OverlapSize; - const int LeftCFEMOverlapRadius = -BSplineOverlapSizes< CDegree , FEMDegree >::OverlapStart; - const int RightCFEMOverlapRadius = BSplineOverlapSizes< CDegree , FEMDegree >::OverlapEnd; - const int LeftFEMCOverlapRadius = -BSplineOverlapSizes< FEMDegree , CDegree >::OverlapStart; - const int RightFEMCOverlapRadius = BSplineOverlapSizes< FEMDegree , CDegree >::OverlapEnd; - - // To set the constraints, we iterate over the - // splatted normals and compute the dot-product of the - // divergence of the normal field with all the basis functions. - // Within the same depth: set directly as a gather - // Coarser depths - maxDepth = std::min< LocalDepth >( maxDepth , _maxDepth ); - DenseNodeData< Real , FEMDegree >* __constraints = new DenseNodeData< Real , FEMDegree >( _sNodesEnd(maxDepth-1) ); - DenseNodeData< Real , FEMDegree >& _constraints = *__constraints; - memset( &_constraints[0] , 0 , sizeof(Real)*( _sNodesEnd(maxDepth-1) ) ); - memoryUsage(); - - for( LocalDepth d=maxDepth ; d>=0 ; d-- ) - { - Stencil< _D , CFEMOverlapSize > stencil , stencils[2][2][2]; - typename SystemCoefficients< CDegree , CBType , FEMDegree , FEMBType >:: Integrator integrator; - typename SystemCoefficients< FEMDegree , FEMBType , CDegree , CBType >::ChildIntegrator childIntegrator; - BSplineIntegrationData< CDegree , CBType , FEMDegree , FEMBType >::SetIntegrator( integrator , d ); - if( d>0 ) BSplineIntegrationData< FEMDegree , FEMBType , CDegree , CBType >::SetChildIntegrator( childIntegrator , d-1 ); - SystemCoefficients< CDegree , CBType , FEMDegree , FEMBType >::template SetCentralConstraintStencil < false >( F, integrator , stencil ); - SystemCoefficients< FEMDegree , FEMBType , CDegree , CBType >::template SetCentralConstraintStencils< true >( F, childIntegrator , stencils ); - - std::vector< SupportKey > neighborKeys( std::max< int >( 1 , threads ) ); - for( size_t i=0 ; i neighbors; - neighborKey.template getNeighbors< false , LeftFEMCOverlapRadius , RightFEMCOverlapRadius >( node , neighbors ); - bool isInterior = _isInteriorlyOverlapped< FEMDegree , CDegree >( node ) , isInterior2 = _isInteriorlyOverlapped< CDegree , FEMDegree >( node->parent ); - - LocalDepth d ; LocalOffset off; - _localDepthAndOffset( node , d , off ); - // Set constraints from current depth - // Gather the constraints from the vector-field at _node into the constraint stored with node - if( _isValidFEMNode( node ) ) - { - for( int x=startX ; x( _node ) ) - { - const D* d = coefficients( _node ); - if( d ) - if( isInterior ) constraints[i] += _Dot( (D)stencil( x , y , z ) , *d ); - else - { - LocalDepth _d ; LocalOffset _off; - _localDepthAndOffset( _node , _d , _off ); - constraints[i] += _Dot( *d , (D)F.template integrate< false >( integrator , _off , off ) ); - } - } - } - _SetParentOverlapBounds< CDegree , FEMDegree >( node , startX , endX , startY , endY , startZ , endZ ); - } - if( !isValidFEMNode< CDegree , CBType >( node ) ) continue; - const D* _data = coefficients( node ); - if( !_data ) continue; - const D& data = *_data; - if( _IsZero( data ) ) continue; - - // Set the _constraints for the parents - if( d>0 ) - { - int cx , cy , cz; - Cube::FactorCornerIndex( (int)( node - node->parent->children ) , cx , cy ,cz ); - const Stencil< _D , CFEMOverlapSize >& _stencil = stencils[cx][cy][cz]; - - neighborKey.template getNeighbors< false , LeftCFEMOverlapRadius , RightCFEMOverlapRadius >( node->parent , neighbors ); - - for( int x=startX ; x( childIntegrator , _off , off ) ); - } -#pragma omp atomic - _constraints[ _node->nodeData.nodeIndex ] += c; - } - } - } - } - memoryUsage(); - } - - // Fine-to-coarse down-sampling of constraints - for( LocalDepth d=maxDepth-1 ; d>0 ; d-- ) _downSample< Real , FEMDegree , FEMBType >( d , _constraints ); - - // Add the accumulated constraints from all finer depths -#pragma omp parallel for num_threads( threads ) - for( int i=0 ; i<_sNodesEnd(maxDepth-1) ; i++ ) constraints[i] += _constraints[i]; - - delete __constraints; - - DenseNodeData< D , CDegree > _coefficients( _sNodesEnd(maxDepth-1) ); - memset( &_coefficients[0] , 0 , sizeof(D) * _sNodesEnd(maxDepth-1) ); - for( LocalDepth d=maxDepth-1 ; d>=0 ; d-- ) - { -#pragma omp parallel for num_threads( threads ) - for( int i=_sNodesBegin(d) ; i<_sNodesEnd(d) ; i++ ) if( isValidFEMNode< CDegree , CBType >( _sNodes.treeNodes[i] ) ) - { - const D* d = coefficients( _sNodes.treeNodes[i] ); - if( d ) _coefficients[i] += *d; - } - } - - // Coarse-to-fine up-sampling of coefficients - for( LocalDepth d=1 ; d( d , _coefficients ); - - // Compute the contribution from all coarser depths - for( LocalDepth d=1 ; d<=maxDepth ; d++ ) - { - size_t start = _sNodesBegin( d ) , end = _sNodesEnd( d ) , range = end - start; - Stencil< _D , CFEMOverlapSize > stencils[2][2][2]; - typename SystemCoefficients< CDegree , CBType , FEMDegree , FEMBType >::ChildIntegrator childIntegrator; - BSplineIntegrationData< CDegree , CBType , FEMDegree , FEMBType >::SetChildIntegrator( childIntegrator , d-1 ); - SystemCoefficients< CDegree , CBType , FEMDegree , FEMBType >::template SetCentralConstraintStencils< false >( F , childIntegrator , stencils ); - std::vector< SupportKey > neighborKeys( std::max< int >( 1 , threads ) ); - for( size_t i=0 ; i( node , startX , endX , startY , endY , startZ , endZ ); - typename TreeOctNode::Neighbors< CFEMOverlapSize > pNeighbors; - neighborKey.template getNeighbors< false , LeftFEMCOverlapRadius , RightFEMCOverlapRadius >( node->parent , pNeighbors ); - - bool isInterior = _isInteriorlyOverlapped< FEMDegree , CDegree >( node->parent ); - int cx , cy , cz; - if( d>0 ) - { - int c = int( node - node->parent->children ); - Cube::FactorCornerIndex( c , cx , cy , cz ); - } - else cx = cy = cz = 0; - Stencil< _D , CFEMOverlapSize >& _stencil = stencils[cx][cy][cz]; - - Real constraint = Real(0); - LocalDepth d ; LocalOffset off; - _localDepthAndOffset( node , d , off ); - for( int x=startX ; x( _node ) ) - { - if( isInterior ) constraint += _Dot( _coefficients[ _node->nodeData.nodeIndex ] , (D)_stencil( x , y , z ) ); - else - { - LocalDepth _d ; LocalOffset _off; - _localDepthAndOffset ( _node , _d , _off ); - constraint += _Dot( _coefficients[ _node->nodeData.nodeIndex ] , (D)F.template integrate< false >( childIntegrator , _off , off ) ); - } - } - } - constraints[i] += constraint; - } - } - memoryUsage(); -} - -template< class Real > -template< int FEMDegree , BoundaryType BType , bool HasGradients > -void Octree< Real >::addInterpolationConstraints( const InterpolationInfo< HasGradients >& interpolationInfo , DenseNodeData< Real , FEMDegree >& constraints , LocalDepth maxDepth ) -{ - typedef typename TreeOctNode::NeighborKey< -BSplineSupportSizes< FEMDegree >::SupportStart , BSplineSupportSizes< FEMDegree >::SupportEnd > SupportKey; - maxDepth = std::min< LocalDepth >( maxDepth , _maxDepth ); - { - static const int OverlapSize = BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize; - static const int LeftSupportRadius = -BSplineSupportSizes< FEMDegree >::SupportStart; - static const int RightSupportRadius = BSplineSupportSizes< FEMDegree >::SupportEnd; - static const int OverlapRadius = - BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapStart; - BSplineData< FEMDegree , BType > bsData( _maxDepth ); - for( int d=0 ; d<=maxDepth ; d++ ) - { - std::vector< SupportKey > neighborKeys( std::max< int >( 1 , threads ) ); - for( size_t i=0 ; i neighbors; - neighborKey.template getNeighbors< false , OverlapRadius , OverlapRadius >( node , neighbors ); - - double constraint = 0; - int fIdx[3]; - functionIndex< FEMDegree , BType >( node , fIdx ); - // evaluate the current node's basis function at adjacent points - for( int x=-LeftSupportRadius ; x<=RightSupportRadius ; x++ ) for( int y=-LeftSupportRadius ; y<=RightSupportRadius ; y++ ) for( int z=-LeftSupportRadius ; z<=RightSupportRadius ; z++ ) - { - const TreeOctNode* _node = neighbors.neighbors[x+OverlapRadius][y+OverlapRadius][z+OverlapRadius]; - if( _isValidSpaceNode( _node ) && interpolationInfo( _node ) ) - { - const PointData< Real , HasGradients >& pData = *( interpolationInfo( _node ) ); - constraint += _ConstraintCalculator_< Real , FEMDegree , HasGradients >::_CalculateConstraint_ - ( - pData , - bsData. baseBSplines[ fIdx[0] ][x+LeftSupportRadius] , - bsData. baseBSplines[ fIdx[1] ][y+LeftSupportRadius] , - bsData. baseBSplines[ fIdx[2] ][z+LeftSupportRadius] , - bsData.dBaseBSplines[ fIdx[0] ][x+LeftSupportRadius] , - bsData.dBaseBSplines[ fIdx[1] ][y+LeftSupportRadius] , - bsData.dBaseBSplines[ fIdx[2] ][z+LeftSupportRadius] , - interpolationInfo.valueWeight , interpolationInfo.gradientWeight - ); - } - } - constraints[ node->nodeData.nodeIndex ] += (Real)constraint; - } - } - memoryUsage(); - } -} -template< class Real > -template< int FEMDegree1 , BoundaryType FEMBType1 , int FEMDegree2 , BoundaryType FEMBType2 , class DotFunctor , bool HasGradients , class Coefficients1 , class Coefficients2 > -double Octree< Real >::_dot( const DotFunctor& F , const InterpolationInfo< HasGradients >* iInfo , const Coefficients1& coefficients1 , const Coefficients2& coefficients2 ) const -{ - double dot = 0; - - // Calculate the contribution from @(depth,depth) - { - typedef typename TreeOctNode::ConstNeighborKey< -BSplineSupportSizes< FEMDegree1 >::SupportStart , BSplineSupportSizes< FEMDegree1 >::SupportEnd > SupportKey; - const int OverlapSize = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::OverlapSize; - const int LeftOverlapRadius = -BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::OverlapStart; - const int RightOverlapRadius = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::OverlapEnd; - - for( LocalDepth d=0 ; d<=_maxDepth ; d++ ) - { - Stencil< double , OverlapSize > stencil; - typename SystemCoefficients< FEMDegree1 , FEMBType1 , FEMDegree2 , FEMBType2 >::Integrator integrator; - BSplineIntegrationData< FEMDegree1 , FEMBType1 , FEMDegree2 , FEMBType2 >::SetIntegrator( integrator , d ); - SystemCoefficients< FEMDegree1 , FEMBType1 , FEMDegree2 , FEMBType2 >::template SetCentralConstraintStencil< false , DotFunctor >( F , integrator , stencil ); - - std::vector< SupportKey > neighborKeys( std::max< int >( 1 , threads ) ); - for( size_t i=0 ; i( node ) && ( _data1=coefficients1(node) ) ) - { - SupportKey& neighborKey = neighborKeys[ omp_get_thread_num() ]; - typename TreeOctNode::ConstNeighbors< OverlapSize > neighbors; - neighborKey.template getNeighbors< LeftOverlapRadius , RightOverlapRadius >( node , neighbors ); - bool isInterior = _isInteriorlyOverlapped< FEMDegree1 , FEMDegree2 >( node ); - - LocalDepth d ; LocalOffset off; - _localDepthAndOffset( node , d , off ); - - for( int x=0 ; x( _node ) && ( _data2=coefficients2( _node ) ) ) - if( isInterior ) dot += (*_data1) * (*_data2 ) * stencil( x , y , z ); - else - { - LocalDepth _d ; LocalOffset _off; - _localDepthAndOffset( _node , _d , _off ); - dot += (*_data1) * (*_data2) * F.template integrate< false >( integrator , off , _off ); - } - } - } - } - } - } - // Calculate the contribution from @(::SupportStart , BSplineSupportSizes< FEMDegree1 >::SupportEnd > SupportKey; - const int OverlapSize = BSplineOverlapSizes< FEMDegree2 , FEMDegree1 >::OverlapSize; - const int LeftOverlapRadius = -BSplineOverlapSizes< FEMDegree2 , FEMDegree1 >::OverlapStart; - const int RightOverlapRadius = BSplineOverlapSizes< FEMDegree2 , FEMDegree1 >::OverlapEnd; - - DenseNodeData< Real , FEMDegree1 > cumulative1( _sNodesEnd( _maxDepth-1 ) ); - if( _maxDepth>0 ) memset( &cumulative1[0] , 0 , sizeof(Real) * _sNodesEnd( _maxDepth-1 ) ); - - for( LocalDepth d=1 ; d<=_maxDepth ; d++ ) - { - // Update the cumulative coefficients with the coefficients @(depth-1) -#pragma omp parallel for - for( int i=_sNodesBegin(d-1) ; i<_sNodesEnd(d-1) ; i++ ) - { - const Real* _data1 = coefficients1( _sNodes.treeNodes[i] ); - if( _data1 ) cumulative1[i] += *_data1; - } - - Stencil< double , OverlapSize > stencils[2][2][2]; - typename SystemCoefficients< FEMDegree1 , FEMBType1 , FEMDegree2 , FEMBType2 >::ChildIntegrator childIntegrator; - BSplineIntegrationData< FEMDegree1 , FEMBType1 , FEMDegree2 , FEMBType2 >::SetChildIntegrator( childIntegrator , d-1 ); - SystemCoefficients< FEMDegree1 , FEMBType1 , FEMDegree2 , FEMBType2 >::template SetCentralConstraintStencils< false >( F, childIntegrator , stencils ); - - std::vector< SupportKey > neighborKeys( std::max< int >( 1 , threads ) ); - for( size_t i=0 ; i( node ) && ( _data2=coefficients2( node ) ) ) - { - SupportKey& neighborKey = neighborKeys[ omp_get_thread_num() ]; - bool isInterior = _isInteriorlyOverlapped< FEMDegree1 , FEMDegree2 >( node->parent ); - - LocalDepth d ; LocalOffset off; - _localDepthAndOffset( node , d , off ); - - int cx , cy , cz; - Cube::FactorCornerIndex( (int)( node - node->parent->children ) , cx , cy ,cz ); - const Stencil< double , OverlapSize >& _stencil = stencils[cx][cy][cz]; - typename TreeOctNode::ConstNeighbors< OverlapSize > neighbors; - neighborKey.template getNeighbors< LeftOverlapRadius , RightOverlapRadius >( node->parent , neighbors ); - - int startX , endX , startY , endY , startZ , endZ; - _SetParentOverlapBounds< FEMDegree2 , FEMDegree1 >( node , startX , endX , startY , endY , startZ , endZ ); - for( int x=startX ; x( _node ) && ( _data1=cumulative1(_node) ) ) - { - if( isInterior ) dot += (*_data1) * (*_data2) * _stencil( x , y , z ); - else - { - LocalDepth _d ; LocalOffset _off; - _localDepthAndOffset( _node , _d , _off ); - dot += (*_data1) * (*_data2) * F.template integrate< false >( childIntegrator , _off , off ); - } - } - } - } - } - // Up sample the cumulative coefficients for the next level - if( d<_maxDepth ) _upSample< Real , FEMDegree1 , FEMBType1 >( d , cumulative1 ); - } - } - - // Calculate the contribution from @(>depth,depth) - { - typedef typename TreeOctNode::ConstNeighborKey< -BSplineSupportSizes< FEMDegree2 >::SupportStart , BSplineSupportSizes< FEMDegree2 >::SupportEnd > SupportKey; - const int OverlapSize = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::OverlapSize; - const int LeftOverlapRadius = -BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::OverlapStart; - const int RightOverlapRadius = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::OverlapEnd; - - DenseNodeData< Real , FEMDegree2 > cumulative2( _sNodesEnd( _maxDepth-1 ) ); - if( _maxDepth>0 ) memset( &cumulative2[0] , 0 , sizeof(Real) * _sNodesEnd( _maxDepth-1 ) ); - - for( LocalDepth d=_maxDepth ; d>0 ; d-- ) - { - Stencil< double , OverlapSize > stencils[2][2][2]; - typename SystemCoefficients< FEMDegree2 , FEMBType2 , FEMDegree1 , FEMBType1 >::ChildIntegrator childIntegrator; - BSplineIntegrationData< FEMDegree2 , FEMBType2 , FEMDegree1 , FEMBType1 >::SetChildIntegrator( childIntegrator , d-1 ); - SystemCoefficients< FEMDegree2 , FEMBType2 , FEMDegree1 , FEMBType1 >::template SetCentralConstraintStencils< true >( F , childIntegrator , stencils ); - - std::vector< SupportKey > neighborKeys( std::max< int >( 1 , threads ) ); - for( size_t i=0 ; i( node ) && ( _data1=coefficients1( node ) ) ) - { - SupportKey& neighborKey = neighborKeys[ omp_get_thread_num() ]; - bool isInterior = _isInteriorlyOverlapped< FEMDegree2 , FEMDegree1 >( node->parent ); - - LocalDepth d ; LocalOffset off; - _localDepthAndOffset( node , d , off ); - - int cx , cy , cz; - Cube::FactorCornerIndex( (int)( node - node->parent->children ) , cx , cy ,cz ); - const Stencil< double , OverlapSize >& _stencil = stencils[cx][cy][cz]; - typename TreeOctNode::ConstNeighbors< OverlapSize > neighbors; - neighborKey.template getNeighbors< LeftOverlapRadius , RightOverlapRadius >( node->parent , neighbors ); - - int startX , endX , startY , endY , startZ , endZ; - _SetParentOverlapBounds< FEMDegree1 , FEMDegree2 >( node , startX , endX , startY , endY , startZ , endZ ); - - for( int x=startX ; x( _node ) ) - { - Real _dot; - if( isInterior ) _dot = (*_data1) * _stencil( x , y , z ); - else - { - LocalDepth _d ; LocalOffset _off; - _localDepthAndOffset( _node , _d , _off ); - _dot = (*_data1) * F.template integrate< true >( childIntegrator , _off , off ); - } -#pragma omp atomic - cumulative2[ _node->nodeData.nodeIndex ] += _dot; - } - } - } - } - // Update the dot-product using the cumulative constraints @(depth-1) -#pragma omp parallel for num_threads( threads ) reduction( + : dot ) - for( int i=_sNodesBegin(d-1) ; i<_sNodesEnd(d-1) ; i++ ) - { - const TreeOctNode* node = _sNodes.treeNodes[i]; - const Real* _data2; - if( isValidFEMNode< FEMDegree2 , FEMBType2 >( node ) && ( _data2=coefficients2( node ) ) ) dot += cumulative2[ node->nodeData.nodeIndex ] * (*_data2); - } - - // Down-sample the cumulative constraints from @(depth-1) to @(depth-2) for the next pass - if( d-1>0 ) _downSample< Real , FEMDegree2 , FEMBType2 >( d-1 , cumulative2 ); - } - } - - if( iInfo ) - { - MultiThreadedEvaluator< FEMDegree1 , FEMBType1 > mt1( this , coefficients1 , threads ); - MultiThreadedEvaluator< FEMDegree2 , FEMBType2 > mt2( this , coefficients2 , threads ); - -#pragma omp parallel for num_threads( threads ) reduction( + : dot ) - for( int i=_sNodesBegin(0) ; i<_sNodesEnd(_maxDepth) ; i++ ) - { - if( _isValidSpaceNode( _sNodes.treeNodes[i] ) && !_isValidSpaceNode( _sNodes.treeNodes[i]->children ) && (*iInfo)( _sNodes.treeNodes[i] ) ) - { - - const PointData< Real , HasGradients >& pData = *( (*iInfo)( _sNodes.treeNodes[i] ) ); -#if POINT_DATA_RES - for( int c=0 ; c::SAMPLES ; c++ ) if( pData[c].weight ) - { - Point3D< Real > p = pData[c].position; - Real w = pData[c].weight; - if( HasGradients ) - { - std::pair< Real , Point3D< Real > > v1 = mt1.valueAndGradient( p , omp_get_thread_num() ); - std::pair< Real , Point3D< Real > > v2 = mt2.valueAndGradient( p , omp_get_thread_num() ); - dot += v1.first * v2.first * w * iInfo->valueWeight + Point3D< Real >::Dot( v1.second , v2.second ) * w * iInfo->gradientWeight; - } - else dot += mt1.value( p , omp_get_thread_num() ) * mt2.value( p , omp_get_thread_num() ) * w * iInfo->valueWeight; - } -#else // !POINT_DATA_RES - Point3D< Real > p = pData.position; - Real w = pData.weight; - if( HasGradients ) - { - std::pair< Real , Point3D< Real > > v1 = mt1.valueAndGradient( p , omp_get_thread_num() ); - std::pair< Real , Point3D< Real > > v2 = mt2.valueAndGradient( p , omp_get_thread_num() ); - dot += v1.first * v2.first * w * iInfo->valueWeight + Point3D< Real >::Dot( v1.second , v2.second ) * w * iInfo->gradientWeight; - } - else dot += mt1.value( p , omp_get_thread_num() ) * mt2.value( p , omp_get_thread_num() ) * w * iInfo->valueWeight; -#endif // POINT_DATA_RES - } - } - } - - return dot; -} diff --git a/Src/MultiGridOctreeData.WeightedSamples.inl b/Src/MultiGridOctreeData.WeightedSamples.inl deleted file mode 100644 index 279d91b9..00000000 --- a/Src/MultiGridOctreeData.WeightedSamples.inl +++ /dev/null @@ -1,443 +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. -*/ - -// evaluate the result of splatting along a plane and then evaluating at a point on the plane. -template< int Degree > double GetScaleValue( void ) -{ - double centerValues[Degree+1]; - Polynomial< Degree >::BSplineComponentValues( 0.5 , centerValues ); - double scaleValue = 0; - for( int i=0 ; i<=Degree ; i++ ) scaleValue += centerValues[i] * centerValues[i]; - return 1./ scaleValue; -} -template< class Real > -template< int WeightDegree > -void Octree< Real >::_addWeightContribution( DensityEstimator< WeightDegree >& densityWeights , TreeOctNode* node , Point3D< Real > position , PointSupportKey< WeightDegree >& weightKey , Real weight ) -{ - static const double ScaleValue = GetScaleValue< WeightDegree >(); - double dx[ DIMENSION ][ PointSupportKey< WeightDegree >::Size ]; - typename TreeOctNode::Neighbors< PointSupportKey< WeightDegree >::Size >& neighbors = weightKey.template getNeighbors< true >( node , _NodeInitializer ); - densityWeights.reserve( NodeCount() ); - Point3D< Real > start; - Real w; - _startAndWidth( node , start , w ); - for( int dim=0 ; dim::BSplineComponentValues( ( position[dim]-start[dim] ) / w , dx[dim] ); - - weight *= (Real)ScaleValue; - - for( int i=0 ; i::Size ; i++ ) for( int j=0 ; j::Size ; j++ ) - { - double dxdy = dx[0][i] * dx[1][j] * weight; - TreeOctNode** _neighbors = neighbors.neighbors[i][j]; - for( int k=0 ; k::Size ; k++ ) if( _neighbors[k] ) densityWeights[ _neighbors[k] ] += Real( dxdy * dx[2][k] ); - } -} - -template< class Real > -template< int WeightDegree , class PointSupportKey > -Real Octree< Real >::_getSamplesPerNode( const DensityEstimator< WeightDegree >& densityWeights , const TreeOctNode* node , Point3D< Real > position , PointSupportKey& weightKey ) const -{ - Real weight = 0; - double dx[ DIMENSION ][ PointSupportKey::Size ]; - const typename PointSupportKey::template Neighbors< PointSupportKey::Size >& neighbors = weightKey.getNeighbors( node ); - - Point3D< Real > start; - Real w; - _startAndWidth( node , start , w ); - - for( int dim=0 ; dim::BSplineComponentValues( ( position[dim]-start[dim] ) / w , dx[dim] ); - - for( int i=0 ; i -template< int WeightDegree , class PointSupportKey > -void Octree< Real >::_getSampleDepthAndWeight( const DensityEstimator< WeightDegree >& densityWeights , const TreeOctNode* node , Point3D< Real > position , PointSupportKey& weightKey , Real& depth , Real& weight ) const -{ - const TreeOctNode* temp = node; - while( _localDepth( temp )>densityWeights.kernelDepth() ) temp = temp->parent; - weight = _getSamplesPerNode( densityWeights , temp , position , weightKey ); - if( weight>=(Real)1. ) depth = Real( _localDepth( temp ) + log( weight ) / log(double(1<<(DIMENSION-1))) ); - else - { - Real oldWeight , newWeight; - oldWeight = newWeight = weight; - while( newWeight<(Real)1. && temp->parent ) - { - temp=temp->parent; - oldWeight = newWeight; - newWeight = _getSamplesPerNode( densityWeights , temp , position , weightKey ); - } - depth = Real( _localDepth( temp ) + log( newWeight ) / log( newWeight / oldWeight ) ); - } - weight = Real( pow( double(1<<(DIMENSION-1)) , -double(depth) ) ); -} -template< class Real > -template< int WeightDegree , class PointSupportKey > -void Octree< Real >::_getSampleDepthAndWeight( const DensityEstimator< WeightDegree >& densityWeights , Point3D< Real > position , PointSupportKey& weightKey , Real& depth , Real& weight ) const -{ - TreeOctNode* temp; - Point3D< Real > myCenter( (Real)0.5 , (Real)0.5 , (Real)0.5 ); - Real myWidth = Real( 1. ); - - // Get the finest node with depth less than or equal to the splat depth that contains the point - temp = _spaceRoot; - while( _localDepth( temp )children ) ) break;// fprintf( stderr , "[ERROR] Octree::GetSampleDepthAndWeight\n" ) , exit( 0 ); - int cIndex = TreeOctNode::CornerIndex( myCenter , position ); - temp = temp->children + cIndex; - myWidth /= 2; - if( cIndex&1 ) myCenter[0] += myWidth/2; - else myCenter[0] -= myWidth/2; - if( cIndex&2 ) myCenter[1] += myWidth/2; - else myCenter[1] -= myWidth/2; - if( cIndex&4 ) myCenter[2] += myWidth/2; - else myCenter[2] -= myWidth/2; - } - return _getSampleDepthAndWeight( densityWeights , temp , position , weightKey , depth , weight ); -} - -template< class Real > -template< bool CreateNodes , int DataDegree , class V > -void Octree< Real >::_splatPointData( TreeOctNode* node , Point3D< Real > position , V v , SparseNodeData< V , DataDegree >& dataInfo , PointSupportKey< DataDegree >& dataKey ) -{ - double dx[ DIMENSION ][ PointSupportKey< DataDegree >::Size ]; - typename TreeOctNode::Neighbors< PointSupportKey< DataDegree >::Size >& neighbors = dataKey.template getNeighbors< CreateNodes >( node , _NodeInitializer ); - Point3D< Real > start; - Real w; - _startAndWidth( node , start , w ); - - for( int dd=0 ; dd::BSplineComponentValues( ( position[dd]-start[dd] ) / w , dx[dd] ); - - for( int i=0 ; i::Size ; i++ ) for( int j=0 ; j::Size ; j++ ) - { - double dxdy = dx[0][i] * dx[1][j]; - for( int k=0 ; k::Size ; k++ ) - if( IsActiveNode( neighbors.neighbors[i][j][k] ) ) - { - TreeOctNode* _node = neighbors.neighbors[i][j][k]; - - double dxdydz = dxdy * dx[2][k]; - dataInfo[ _node ] += v * (Real)dxdydz; - } - } -} -template< class Real > -template< bool CreateNodes , int WeightDegree , int DataDegree , class V > -Real Octree< Real >::_splatPointData( const DensityEstimator< WeightDegree >& densityWeights , Point3D< Real > position , V v , SparseNodeData< V , DataDegree >& dataInfo , PointSupportKey< WeightDegree >& weightKey , PointSupportKey< DataDegree >& dataKey , LocalDepth minDepth , LocalDepth maxDepth , int dim ) -{ - double dx; - V _v; - TreeOctNode* temp; - int cnt=0; - double width; - Point3D< Real > myCenter( (Real)0.5 , (Real)0.5 , (Real)0.5 ); - Real myWidth = (Real)1.; - - temp = _spaceRoot; - while( _localDepth( temp )children ) ) break; - int cIndex = TreeOctNode::CornerIndex( myCenter , position ); - temp = temp->children + cIndex; - myWidth /= 2; - if( cIndex&1 ) myCenter[0] += myWidth/2; - else myCenter[0] -= myWidth/2; - if( cIndex&2 ) myCenter[1] += myWidth/2; - else myCenter[1] -= myWidth/2; - if( cIndex&4 ) myCenter[2] += myWidth/2; - else myCenter[2] -= myWidth/2; - } - Real weight , depth; - _getSampleDepthAndWeight( densityWeights , temp , position , weightKey , depth , weight ); - - if( depthmaxDepth ) depth = Real(maxDepth); - int topDepth = int(ceil(depth)); - - dx = 1.0-(topDepth-depth); - if ( topDepth<=minDepth ) topDepth = minDepth , dx = 1; - else if( topDepth> maxDepth ) topDepth = maxDepth , dx = 1; - - while( _localDepth( temp )>topDepth ) temp=temp->parent; - while( _localDepth( temp )children ) temp->initChildren( _NodeInitializer ); - int cIndex = TreeOctNode::CornerIndex( myCenter , position ); - temp = &temp->children[cIndex]; - myWidth/=2; - if( cIndex&1 ) myCenter[0] += myWidth/2; - else myCenter[0] -= myWidth/2; - if( cIndex&2 ) myCenter[1] += myWidth/2; - else myCenter[1] -= myWidth/2; - if( cIndex&4 ) myCenter[2] += myWidth/2; - else myCenter[2] -= myWidth/2; - } - width = 1.0 / ( 1<<_localDepth( temp ) ); - _v = v * weight / Real( pow( width , dim ) ) * Real( dx ); - _splatPointData< CreateNodes >( temp , position , _v , dataInfo , dataKey ); - if( fabs(1.0-dx) > EPSILON ) - { - dx = Real(1.0-dx); - temp = temp->parent; - width = 1.0 / ( 1<<_localDepth( temp ) ); - - _v = v * weight / Real( pow( width , dim ) ) * Real( dx ); - _splatPointData< CreateNodes >( temp , position , _v , dataInfo , dataKey ); - } - return weight; -} -template< class Real > -template< bool CreateNodes , int WeightDegree , int DataDegree , class V > -Real Octree< Real >::_multiSplatPointData( const DensityEstimator< WeightDegree >* densityWeights , TreeOctNode* node , Point3D< Real > position , V v , SparseNodeData< V , DataDegree >& dataInfo , PointSupportKey< WeightDegree >& weightKey , PointSupportKey< DataDegree >& dataKey , int dim ) -{ - Real _depth , weight; - if( densityWeights ) _getSampleDepthAndWeight( *densityWeights , position , weightKey , _depth , weight ); - else weight = (Real)1.; - V _v = v * weight; - - double dx[ DIMENSION ][ PointSupportKey< DataDegree >::Size ]; - dataKey.template getNeighbors< CreateNodes >( node , _NodeInitializer ); - - for( TreeOctNode* _node=node ; _localDepth( _node )>=0 ; _node=_node->parent ) - { - V __v = _v * (Real)pow( 1<<_localDepth( _node ) , dim ); - Point3D< Real > start; - Real w; - _startAndWidth( _node , start , w ); - for( int dd=0 ; dd::BSplineComponentValues( ( position[dd]-start[dd] ) / w , dx[dd] ); - typename TreeOctNode::Neighbors< PointSupportKey< DataDegree >::Size >& neighbors = dataKey.neighbors[ _localToGlobal( _localDepth( _node ) ) ]; - for( int i=0 ; i::Size ; i++ ) for( int j=0 ; j::Size ; j++ ) - { - double dxdy = dx[0][i] * dx[1][j]; - for( int k=0 ; k::Size ; k++ ) - if( IsActiveNode( neighbors.neighbors[i][j][k] ) ) - { - TreeOctNode* _node = neighbors.neighbors[i][j][k]; - double dxdydz = dxdy * dx[2][k]; - dataInfo[ _node ] += __v * (Real)dxdydz; - } - } - } - return weight; -} - -template< class Real > -template< class V , int DataDegree , BoundaryType BType , class Coefficients > -V Octree< Real >::_evaluate( const Coefficients& coefficients , Point3D< Real > p , const BSplineData< DataDegree , BType >& bsData , const ConstPointSupportKey< DataDegree >& dataKey ) const -{ - V value = V(0); - - for( int d=_localToGlobal( 0 ) ; d<=dataKey.depth() ; d++ ) - { - double dx[ DIMENSION ][ PointSupportKey< DataDegree >::Size ]; - memset( dx , 0 , sizeof( double ) * DIMENSION * PointSupportKey< DataDegree >::Size ); - { - const TreeOctNode* n = dataKey.neighbors[d].neighbors[ PointSupportKey< DataDegree >::LeftRadius ][ PointSupportKey< DataDegree >::LeftRadius ][ PointSupportKey< DataDegree >::LeftRadius ]; - if( !n ) fprintf( stderr , "[ERROR] Point is not centered on a node\n" ) , exit( 0 ); - int fIdx[3]; - functionIndex< DataDegree , BType >( n , fIdx ); - int fStart , fEnd; - BSplineData< DataDegree , BType >::FunctionSpan( _localDepth( n ) , fStart , fEnd ); - for( int dd=0 ; dd::LeftRadius ; i<=PointSupportKey< DataDegree >::RightRadius ; i++ ) - if( fIdx[dd]+i>=fStart && fIdx[dd]+i::RightRadius ]( p[dd] ); - } - for( int i=0 ; i::Size ; i++ ) for( int j=0 ; j::Size ; j++ ) for( int k=0 ; k::Size ; k++ ) - { - const TreeOctNode* n = dataKey.neighbors[d].neighbors[i][j][k]; - if( isValidFEMNode< DataDegree , BType >( n ) ) - { - const V* v = coefficients( n ); - if( v ) value += (*v) * (Real) ( dx[0][i] * dx[1][j] * dx[2][k] ); - } - } - } - - return value; -} - -template< class Real > -template< class V , int DataDegree , BoundaryType BType > -Pointer( V ) Octree< Real >::voxelEvaluate( const DenseNodeData< V , DataDegree >& coefficients , int& res , Real isoValue , LocalDepth depth , bool primal ) -{ - int begin , end , dim; - if( depth<=0 || depth>_maxDepth ) depth = _maxDepth; - - // Initialize the coefficients at the coarsest level - Pointer( V ) _coefficients = NullPointer( V ); - { - LocalDepth d = 0; - begin = _BSplineBegin< DataDegree , BType >( d ) , end = _BSplineEnd< DataDegree , BType >( d ) , dim = end - begin; - _coefficients = NewPointer< V >( dim * dim * dim ); - memset( _coefficients , 0 , sizeof( V ) * dim * dim * dim ); -#pragma omp parallel for num_threads( threads ) - for( int i=_sNodesBegin(d) ; i<_sNodesEnd(d) ; i++ ) if( !_outOfBounds< DataDegree , BType >( _sNodes.treeNodes[i] ) ) - { - LocalDepth _d ; LocalOffset _off; - _localDepthAndOffset( _sNodes.treeNodes[i] , _d , _off ); - _off[0] -= begin , _off[1] -= begin , _off[2] -= begin; - _coefficients[ _off[0] + _off[1]*dim + _off[2]*dim*dim ] = coefficients[i]; - } - } - - // Up-sample and add in the existing coefficients - for( LocalDepth d=1 ; d<=depth ; d++ ) - { - begin = _BSplineBegin< DataDegree , BType >( d ) , end = _BSplineEnd< DataDegree , BType >( d ) , dim = end - begin; - Pointer( V ) __coefficients = NewPointer< V >( dim * dim *dim ); - memset( __coefficients , 0 , sizeof( V ) * dim * dim * dim ); -#pragma omp parallel for num_threads( threads ) - for( int i=_sNodesBegin(d) ; i<_sNodesEnd(d) ; i++ ) if( !_outOfBounds< DataDegree , BType >( _sNodes.treeNodes[i] ) ) - { - LocalDepth _d ; LocalOffset _off; - _localDepthAndOffset( _sNodes.treeNodes[i] , _d , _off ); - _off[0] -= begin , _off[1] -= begin , _off[2] -= begin; - __coefficients[ _off[0] + _off[1]*dim + _off[2]*dim*dim ] = coefficients[i]; - } - _UpSample< V , DataDegree , BType >( d , ( ConstPointer(V) )_coefficients , __coefficients , threads ); - DeletePointer( _coefficients ); - _coefficients = __coefficients; - } - - res = 1<( res*res*res ); - memset( values , 0 , sizeof(V)*res*res*res ); - - if( primal ) - { - // evaluate at the cell corners - typename BSplineEvaluationData< DataDegree , BType >::CornerEvaluator::Evaluator evaluator; - BSplineEvaluationData< DataDegree , BType >::SetCornerEvaluator( evaluator , depth ); -#pragma omp parallel for num_threads( threads ) - for( int k=0 ; k::CornerEnd ; kk<=-BSplineSupportSizes< DataDegree >::CornerStart ; kk++ ) if( k+kk>=begin && k+kk::CornerEnd ; jj<=-BSplineSupportSizes< DataDegree >::CornerStart ; jj++ ) if( j+jj>=begin && j+jj::CornerEnd ; ii<=-BSplineSupportSizes< DataDegree >::CornerStart ; ii++ ) if( i+ii>=begin && i+ii::CenterEvaluator::Evaluator evaluator; - BSplineEvaluationData< DataDegree , BType >::SetCenterEvaluator( evaluator , depth ); -#pragma omp parallel for num_threads( threads ) - for( int k=0 ; k::SupportEnd ; kk<=-BSplineSupportSizes< DataDegree >::SupportStart ; kk++ ) if( k+kk>=begin && k+kk::SupportEnd ; jj<=-BSplineSupportSizes< DataDegree >::SupportStart ; jj++ ) if( j+jj>=begin && j+jj::SupportEnd ; ii<=-BSplineSupportSizes< DataDegree >::SupportStart ; ii++ ) if( i+ii>=begin && i+ii -template< int FEMDegree , BoundaryType BType > -SparseNodeData< Real , 0 > Octree< Real >::leafValues( const DenseNodeData< Real , FEMDegree >& coefficients ) const -{ - SparseNodeData< Real , 0 > values; - DenseNodeData< Real , FEMDegree > _coefficients( _sNodesEnd(_maxDepth-1) ); - memset( &_coefficients[0] , 0 , sizeof(Real)*_sNodesEnd(_maxDepth-1) ); - for( int i=_sNodes.begin( _localToGlobal( 0 ) ) ; i<_sNodesEnd(_maxDepth-1) ; i++ ) _coefficients[i] = coefficients[i]; - for( LocalDepth d=1 ; d<_maxDepth ; d++ ) _upSample( d , _coefficients ); - for( LocalDepth d=_maxDepth ; d>=0 ; d-- ) - { - _Evaluator< FEMDegree , BType > evaluator; - evaluator.set( d ); - std::vector< ConstPointSupportKey< FEMDegree > > neighborKeys( std::max< int >( 1 , threads ) ); - for( size_t i=0 ; i& neighborKey = neighborKeys[ omp_get_thread_num() ]; - TreeOctNode* node = _sNodes.treeNodes[i]; - if( !IsActiveNode( node->children ) ) - { - neighborKey.getNeighbors( node ); - bool isInterior = _IsInteriorlySupported< FEMDegree >( node->parent ); - values[ node ] = _getCenterValue( neighborKey , node , coefficients , _coefficients , evaluator , isInterior ); - } - } - } - return values; -} -template< class Real > -template< int FEMDegree , BoundaryType BType > -SparseNodeData< Point3D< Real > , 0 > Octree< Real >::leafGradients( const DenseNodeData< Real , FEMDegree >& coefficients ) const -{ - SparseNodeData< Point3D< Real > , 0 > gradients; - DenseNodeData< Real , FEMDegree > _coefficients( _sNodesEnd(_maxDepth-1 ) ); - memset( &_coefficients[0] , 0 , sizeof(Real)*_sNodesEnd(_maxDepth-1) ); - for( int i=_sNodesBegin(0) ; i<_sNodesEnd(_maxDepth-1) ; i++ ) _coefficients[i] = coefficients[i]; - for( LocalDepth d=1 ; d<_maxDepth ; d++ ) _upSample( d , _coefficients ); - for( LocalDepth d=_maxDepth ; d>=0 ; d-- ) - { - _Evaluator< FEMDegree , BType > evaluator; - evaluator.set( d ); - std::vector< ConstPointSupportKey< FEMDegree > > neighborKeys( std::max< int >( 1 , threads ) ); - for( size_t i=0 ; i& neighborKey = neighborKeys[ omp_get_thread_num() ]; - TreeOctNode* node = _sNodes.treeNodes[i]; - if( !IsActiveNode( node->children ) ) - { - neighborKey.getNeighbors( node ); - bool isInterior = _IsInteriorlySupported< FEMDegree >( node->parent ); - gradients[ node ] = _getCenterValueAndGradient( neighborKey , node , coefficients , _coefficients , evaluator , isInterior ).second; - } - } - } - return gradients; -} diff --git a/Src/MultiGridOctreeData.h b/Src/MultiGridOctreeData.h deleted file mode 100644 index 595ebdc7..00000000 --- a/Src/MultiGridOctreeData.h +++ /dev/null @@ -1,988 +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. -*/ -// [COMMENTS] -// -- Throughout the code, should make a distinction between indices and offsets -// -- Make an instance of _evaluate that samples the finite-elements correctly (specifically, to handle the boundaries) -// -- Make functions like depthAndOffset parity dependent (ideally all "depth"s should be relative to the B-Slpline resolution -// -- Make all points relative to the unit-cube, regardless of degree parity -// -- It's possible that for odd degrees, the iso-surfacing will fail because the leaves in the SortedTreeNodes do not form a partition of space -// -- [MAYBE] Treat normal field as a sum of delta functions, rather than a smoothed signal (again, so that high degrees aren't forced to generate smooth reconstructions) -// -- [MAYBE] Make the degree of the B-Spline with which the normals are splatted independent of the degree of the FEM system. (This way, higher degree systems aren't forced to generate smoother normal fields.) -// -- [MAYBE] Remove the isValidFEM/isValidSpace functions since the octree supports all degrees/boundary types (up to the max degree for which finalizedBrooded... was called) - -// [TODO] -// -- Currently, the implementation assumes that the boundary constraints are the same for vector fields and scalar fields -// -- Modify the setting of the flags so that only the subset of the broods that are needed - -#ifndef MULTI_GRID_OCTREE_DATA_INCLUDED -#define MULTI_GRID_OCTREE_DATA_INCLUDED - -#define NEW_CODE -#define FAST_SET_UP // If enabled, kernel density estimation is done aglomeratively - -#define POINT_DATA_RES 0 // Specifies the resolution of the subgrid storing points with each voxel (0==1 but is faster) - -#define DATA_DEGREE 1 // The order of the B-Spline used to splat in data for color interpolation -#define WEIGHT_DEGREE 2 // The order of the B-Spline used to splat in the weights for density estimation -#define NORMAL_DEGREE 2 // The order of the B-Spline used to splat int the normals for constructing the Laplacian constraints -//#define MAX_MEMORY_GB 15 // The maximum memory the application is allowed to use -#define MAX_MEMORY_GB 0 - -#include -#include -#include "BSplineData.h" -#include "PointStream.h" -#include "Geometry.h" -#include "Octree.h" -#include "SparseMatrix.h" - -#ifndef _OPENMP -int omp_get_num_procs( void ){ return 1; } -int omp_get_thread_num( void ){ return 0; } -#endif // _OPENMP - -#define DERIVATIVES( Degree ) ( ( Degree>1 ) ? 2 : ( Degree==1 ? 1 : 0 ) ) - -class TreeNodeData -{ -public: - enum - { - SPACE_FLAG = 1 , - FEM_FLAG = 2 , - GHOST_FLAG = 1<<7 - }; - int nodeIndex; - char flags; - - void setGhostFlag( bool f ){ if( f ) flags |= GHOST_FLAG ; else flags &= ~GHOST_FLAG; } - bool getGhostFlag( void ) const { return ( flags & GHOST_FLAG )!=0; } - TreeNodeData( void ); - ~TreeNodeData( void ); -}; - -class VertexData -{ - typedef OctNode< TreeNodeData > TreeOctNode; -public: - static const int VERTEX_COORDINATE_SHIFT = ( sizeof( long long ) * 8 ) / 3; - static long long EdgeIndex( const TreeOctNode* node , int eIndex , int maxDepth , int index[DIMENSION] ); - static long long EdgeIndex( const TreeOctNode* node , int eIndex , int maxDepth ); - static long long FaceIndex( const TreeOctNode* node , int fIndex , int maxDepth,int index[DIMENSION] ); - static long long FaceIndex( const TreeOctNode* node , int fIndex , int maxDepth ); - static long long CornerIndex( const TreeOctNode* node , int cIndex , int maxDepth , int index[DIMENSION] ); - static long long CornerIndex( const TreeOctNode* node , int cIndex , int maxDepth ); - static long long CenterIndex( const TreeOctNode* node , int maxDepth , int index[DIMENSION] ); - static long long CenterIndex( const TreeOctNode* node , int maxDepth ); - static long long CornerIndex( int depth , const int offSet[DIMENSION] , int cIndex , int maxDepth , int index[DIMENSION] ); - static long long CenterIndex( int depth , const int offSet[DIMENSION] , int maxDepth , int index[DIMENSION] ); - static long long CornerIndexKey( const int index[DIMENSION] ); -}; - -// This class stores the octree nodes, sorted by depth and then by z-slice. -// To support primal representations, the initializer takes a function that -// determines if a node should be included/indexed in the sorted list. -// [NOTE] Indexing of nodes is _GLOBAL_ -class SortedTreeNodes -{ - typedef OctNode< TreeNodeData > TreeOctNode; -protected: - Pointer( Pointer( int ) ) _sliceStart; - int _levels; -public: - Pointer( TreeOctNode* ) treeNodes; - int begin( int depth ) const{ return _sliceStart[depth][0]; } - int end( int depth ) const{ return _sliceStart[depth][(size_t)1<=_levels||slice<0||slice>=(1<=_levels) printf( "uhoh\n" ); return _sliceStart[depth][(size_t)1<* map ); - void set( TreeOctNode& root ); - - template< int Indices > - struct _Indices - { - int idx[Indices]; - _Indices( void ){ memset( idx , -1 , sizeof( int ) * Indices ); } - int& operator[] ( int i ) { return idx[i]; } - const int& operator[] ( int i ) const { return idx[i]; } - }; - typedef _Indices< Square::CORNERS > SquareCornerIndices; - typedef _Indices< Square::EDGES > SquareEdgeIndices; - typedef _Indices< Square::FACES > SquareFaceIndices; - - struct SliceTableData - { - Pointer( SquareCornerIndices ) cTable; - Pointer( SquareEdgeIndices ) eTable; - Pointer( SquareFaceIndices ) fTable; - int cCount , eCount , fCount , nodeOffset , nodeCount; - SliceTableData( void ){ fCount = eCount = cCount = 0 , cTable = NullPointer( SquareCornerIndices ) , eTable = NullPointer( SquareEdgeIndices ) , fTable = NullPointer( SquareFaceIndices ) , _cMap = _eMap = _fMap = NullPointer( int ); } - ~SliceTableData( void ){ clear(); } -#ifdef BRUNO_LEVY_FIX - void clear( void ){ DeletePointer( cTable ) ; DeletePointer( eTable ) ; DeletePointer( fTable ) ; DeletePointer( _cMap ) ; DeletePointer( _eMap ) ; DeletePointer( _fMap ) ; fCount = eCount = cCount = 0; } -#else // !BRUNO_LEVY_FIX - void clear( void ){ DeletePointer( cTable ) ; DeletePointer( eTable ) ; DeletePointer( fTable ) ; fCount = eCount = cCount = 0; } -#endif // BRUNO_LEVY_FIX - SquareCornerIndices& cornerIndices( const TreeOctNode* node ); - SquareCornerIndices& cornerIndices( int idx ); - const SquareCornerIndices& cornerIndices( const TreeOctNode* node ) const; - const SquareCornerIndices& cornerIndices( int idx ) const; - SquareEdgeIndices& edgeIndices( const TreeOctNode* node ); - SquareEdgeIndices& edgeIndices( int idx ); - const SquareEdgeIndices& edgeIndices( const TreeOctNode* node ) const; - const SquareEdgeIndices& edgeIndices( int idx ) const; - SquareFaceIndices& faceIndices( const TreeOctNode* node ); - SquareFaceIndices& faceIndices( int idx ); - const SquareFaceIndices& faceIndices( const TreeOctNode* node ) const; - const SquareFaceIndices& faceIndices( int idx ) const; - protected: - Pointer( int ) _cMap; - Pointer( int ) _eMap; - Pointer( int ) _fMap; - friend class SortedTreeNodes; - }; - struct XSliceTableData - { - Pointer( SquareCornerIndices ) eTable; - Pointer( SquareEdgeIndices ) fTable; - int fCount , eCount , nodeOffset , nodeCount; - XSliceTableData( void ){ fCount = eCount = 0 , eTable = NullPointer( SquareCornerIndices ) , fTable = NullPointer( SquareEdgeIndices ) , _eMap = _fMap = NullPointer( int ); } - ~XSliceTableData( void ){ clear(); } -#ifdef BRUNO_LEVY_FIX - void clear( void ) { DeletePointer( fTable ) ; DeletePointer( eTable ) ; DeletePointer( _eMap ) ; DeletePointer( _fMap ) ; fCount = eCount = 0; } -#else // !BRUNO_LEVY_FIX - void clear( void ) { DeletePointer( fTable ) ; DeletePointer( eTable ) ; fCount = eCount = 0; } -#endif // BRUNO_LEVY_FIX - SquareCornerIndices& edgeIndices( const TreeOctNode* node ); - SquareCornerIndices& edgeIndices( int idx ); - const SquareCornerIndices& edgeIndices( const TreeOctNode* node ) const; - const SquareCornerIndices& edgeIndices( int idx ) const; - SquareEdgeIndices& faceIndices( const TreeOctNode* node ); - SquareEdgeIndices& faceIndices( int idx ); - const SquareEdgeIndices& faceIndices( const TreeOctNode* node ) const; - const SquareEdgeIndices& faceIndices( int idx ) const; - protected: - Pointer( int ) _eMap; - Pointer( int ) _fMap; - friend class SortedTreeNodes; - }; - void setSliceTableData ( SliceTableData& sData , int depth , int offset , int threads ) const; - void setXSliceTableData( XSliceTableData& sData , int depth , int offset , int threads ) const; -}; - -template< int Degree > -struct PointSupportKey : public OctNode< TreeNodeData >::NeighborKey< BSplineSupportSizes< Degree >::SupportEnd , -BSplineSupportSizes< Degree >::SupportStart > -{ - static const int LeftRadius = BSplineSupportSizes< Degree >::SupportEnd; - static const int RightRadius = -BSplineSupportSizes< Degree >::SupportStart; - static const int Size = LeftRadius + RightRadius + 1; -}; -template< int Degree > -struct ConstPointSupportKey : public OctNode< TreeNodeData >::ConstNeighborKey< BSplineSupportSizes< Degree >::SupportEnd , -BSplineSupportSizes< Degree >::SupportStart > -{ - static const int LeftRadius = BSplineSupportSizes< Degree >::SupportEnd; - static const int RightRadius = -BSplineSupportSizes< Degree >::SupportStart; - static const int Size = LeftRadius + RightRadius + 1; -}; - -template< class Real , bool HasGradients > -struct SinglePointData -{ - Point3D< Real > position; - Real weight; - Real value , _value; - SinglePointData operator + ( const SinglePointData& p ) const { return SinglePointData( position + p.position , value + p.value , weight + p.weight ); } - SinglePointData& operator += ( const SinglePointData& p ){ position += p.position ; weight += p.weight , value += p.value ; return *this; } - SinglePointData operator * ( Real s ) const { return SinglePointData( position*s , weight*s , value*s ); } - SinglePointData& operator *= ( Real s ){ position *= s , weight *= s , value *= s ; return *this; } - SinglePointData operator / ( Real s ) const { return SinglePointData( position/s , weight/s , value/s ); } - SinglePointData& operator /= ( Real s ){ position /= s , weight /= s , value /= s ; return *this; } - SinglePointData( void ) : position( Point3D< Real >() ) , weight(0) , value(0) , _value(0) { ; } - SinglePointData( Point3D< Real > p , Real v , Real w ) { position = p , value = v , weight = w , _value = (Real)0; } -}; -template< class Real > -struct SinglePointData< Real , true > : public SinglePointData< Real , false > -{ - using SinglePointData< Real , false >::position; - using SinglePointData< Real , false >::weight; - using SinglePointData< Real , false >::value; - using SinglePointData< Real , false >::_value; - Point3D< Real > gradient , _gradient; - SinglePointData operator + ( const SinglePointData& p ) const { return SinglePointData( position + p.position , weight + p.weight , value + p.value , gradient + p.gradient ); } - SinglePointData& operator += ( const SinglePointData& p ){ position += p.position , weight += p.weight , value += p.value , gradient += p.gradient ; return *this; } - SinglePointData operator * ( Real s ) const { return SinglePointData( position*s , weight*s , value*s , gradient*s ); } - SinglePointData& operator *= ( Real s ){ position *= s , weight *= s , value *= s , gradient *= s ; return *this; } - SinglePointData operator / ( Real s ) const { return SinglePointData( position/s , weight/s , value/s , gradient/s ); } - SinglePointData& operator /= ( Real s ){ position /= s , weight /= s , value /= s , gradient /= s ; return *this; } - SinglePointData( void ) : SinglePointData< Real , false >() , gradient( Point3D< Real >() ) , _gradient( Point3D< Real >() ) { ; } - SinglePointData( Point3D< Real > p , Real v , Point3D< Real > g , Real w ) : SinglePointData< Real , false >( p , v , w ) { gradient = g , _gradient = Point3D< Real >(); } -}; - -#if POINT_DATA_RES -template< class Real , bool HasGradients > -struct PointData -{ - static const int RES = POINT_DATA_RES; - static const int SAMPLES = RES * RES * RES; - - SinglePointData< Real , HasGradients > points[SAMPLES]; - SinglePointData< Real , HasGradients >& operator[] ( int idx ) { return points[idx]; } - const SinglePointData< Real , HasGradients >& operator[] ( int idx ) const { return points[idx]; } - - static void SetIndices( Point3D< Real > p , Point3D< Real > c , Real w , int x[3] ) - { - for( int d=0 ; d<3 ; d++ ) x[d] = std::max< int >( 0 , std::min< int >( RES-1 , int( floor( ( p[d]-( c[d]-w/2 ) ) / w * RES ) ) ) ); - } - - void addPoint( SinglePointData< Real , HasGradients > p , Point3D< Real > center , Real width ) - { - int x[3]; - SetIndices( p.position , center , width , x ); - points[ x[0]+x[1]*RES+x[2]*RES*RES ] += p; - } - - PointData operator + ( const PointData& p ) const { PointData _p ; for( int c=0 ; c using PointData = SinglePointData< Real , HasGradients >; -#endif // POINT_DATA_RES - -template< class Data , int Degree > -struct SparseNodeData -{ - size_t size( void ) const { return _data.size(); } - const Data& operator[] ( int idx ) const { return _data[idx]; } - Data& operator[] ( int idx ) { return _data[idx]; } - void reserve( size_t sz ){ if( sz>_indices.size() ) _indices.resize( sz , -1 ); } - Data* operator()( const OctNode< TreeNodeData >* node ){ return ( node->nodeData.nodeIndex<0 || node->nodeData.nodeIndex>=(int)_indices.size() || _indices[ node->nodeData.nodeIndex ]<0 ) ? NULL : &_data[ _indices[ node->nodeData.nodeIndex ] ]; } - const Data* operator()( const OctNode< TreeNodeData >* node ) const { return ( node->nodeData.nodeIndex<0 || node->nodeData.nodeIndex>=(int)_indices.size() || _indices[ node->nodeData.nodeIndex ]<0 ) ? NULL : &_data[ _indices[ node->nodeData.nodeIndex ] ]; } - Data& operator[]( const OctNode< TreeNodeData >* node ) - { - if( node->nodeData.nodeIndex>=(int)_indices.size() ) _indices.resize( node->nodeData.nodeIndex+1 , -1 ); - if( _indices[ node->nodeData.nodeIndex ]==-1 ) - { - _indices[ node->nodeData.nodeIndex ] = (int)_data.size(); - _data.push_back( Data() ); - } - return _data[ _indices[ node->nodeData.nodeIndex ] ]; - } - void remapIndices( const std::vector< int >& map ) - { - std::vector< int > temp = _indices; - _indices.resize( map.size() ); - for( size_t i=0 ; i friend struct SparseNodeData; - template< class _Data , int _Degree > - void init( const SparseNodeData< _Data , _Degree >& snd ){ _indices = snd._indices , _data.resize( snd._data.size() ); } - void remove( const OctNode< TreeNodeData >* node ){ if( node->nodeData.nodeIndex<(int)_indices.size() && node->nodeData.nodeIndex>=0 ) _indices[ node->nodeData.nodeIndex ] = -1; } -protected: - std::vector< int > _indices; - std::vector< Data > _data; -}; -template< class Data , int Degree > -struct DenseNodeData -{ - DenseNodeData( void ){ _data = NullPointer( Data ) ; _sz = 0; } - DenseNodeData( size_t sz ){ _sz = sz ; if( sz ) _data = NewPointer< Data >( sz ) ; else _data = NullPointer( Data ); } - DenseNodeData( const DenseNodeData& d ) : DenseNodeData() { _resize( d._sz ) ; if( _sz ) memcpy( _data , d._data , sizeof(Data) * _sz ); } - DenseNodeData( DenseNodeData&& d ){ _data = d._data , _sz = d._sz ; d._data = NullPointer( Data ) , d._sz = 0; } - DenseNodeData& operator = ( const DenseNodeData& d ){ _resize( d._sz ) ; if( _sz ) memcpy( _data , d._data , sizeof(Data) * _sz ) ; return *this; } - DenseNodeData& operator = ( DenseNodeData&& d ){ size_t __sz = _sz ; Pointer( Data ) __data = _data ; _data = d._data , _sz = d._sz ; d._data = __data , d._sz = __sz ; return *this; } - ~DenseNodeData( void ){ DeletePointer( _data ) ; _sz = 0; } - - Data& operator[] ( int idx ) { return _data[idx]; } - const Data& operator[] ( int idx ) const { return _data[idx]; } - size_t size( void ) const { return _sz; } - Data& operator[]( const OctNode< TreeNodeData >* node ) { return _data[ node->nodeData.nodeIndex ]; } - Data* operator()( const OctNode< TreeNodeData >* node ) { return ( node==NULL || node->nodeData.nodeIndex>=(int)_sz ) ? NULL : &_data[ node->nodeData.nodeIndex ]; } - const Data* operator()( const OctNode< TreeNodeData >* node ) const { return ( node==NULL || node->nodeData.nodeIndex>=(int)_sz ) ? NULL : &_data[ node->nodeData.nodeIndex ]; } - int index( const OctNode< TreeNodeData >* node ) const { return ( !node || node->nodeData.nodeIndex<0 || node->nodeData.nodeIndex>=(int)_data.size() ) ? -1 : node->nodeData.nodeIndex; } -protected: - size_t _sz; - void _resize( size_t sz ){ DeletePointer( _data ) ; if( sz ) _data = NewPointer< Data >( sz ) ; else _data = NullPointer( Data ) ; _sz = sz; } - Pointer( Data ) _data; -}; - -// This is may be necessary in case the memory usage is larger than what fits on the stack -template< class C , int N > struct Stencil -{ - Stencil( void ){ _values = NewPointer< C >( N * N * N ); } - ~Stencil( void ){ DeletePointer( _values ); } - C& operator()( int i , int j , int k ){ return _values[ i*N*N + j*N + k ]; } - const C& operator()( int i , int j , int k ) const { return _values[ i*N*N + j*N + k ]; } -protected: - Pointer( C ) _values; -}; - -template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > -class SystemCoefficients -{ - typedef typename BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::FunctionIntegrator FunctionIntegrator; - static const int OverlapSize = BSplineOverlapSizes< Degree1 , Degree2 >::OverlapSize; - static const int OverlapStart = BSplineOverlapSizes< Degree1 , Degree2 >::OverlapStart; - static const int OverlapEnd = BSplineOverlapSizes< Degree1 , Degree2 >::OverlapEnd; -public: - typedef typename BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::FunctionIntegrator::template Integrator< DERIVATIVES( Degree1 ) , DERIVATIVES( Degree2 ) > Integrator; - typedef typename BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::FunctionIntegrator::template ChildIntegrator< DERIVATIVES( Degree1 ) , DERIVATIVES( Degree2 ) > ChildIntegrator; - - // The FEMSystemFunctor is a class that takes an object of type Integrator/ChildIntegrator, as well as a pair of indices of octree nodes - // and returns the corresponding system coefficient. - template< class _FEMSystemFunctor > static void SetCentralSystemStencil ( const _FEMSystemFunctor& F , const Integrator& integrator , Stencil< double , OverlapSize >& stencil ); - template< class _FEMSystemFunctor > static void SetCentralSystemStencils( const _FEMSystemFunctor& F , const ChildIntegrator& integrator , Stencil< double , OverlapSize > stencils[2][2][2] ); - template< bool Reverse , class _FEMSystemFunctor > static void SetCentralConstraintStencil ( const _FEMSystemFunctor& F , const Integrator& integrator , Stencil< double , OverlapSize >& stencil ); - template< bool Reverse , class _FEMSystemFunctor > static void SetCentralConstraintStencils( const _FEMSystemFunctor& F , const ChildIntegrator& integrator , Stencil< double , OverlapSize > stencils[2][2][2] ); - template< bool Reverse , class _FEMSystemFunctor > static void SetCentralConstraintStencil ( const _FEMSystemFunctor& F , const Integrator& integrator , Stencil< Point3D< double > , OverlapSize >& stencil ); - template< bool Reverse , class _FEMSystemFunctor > static void SetCentralConstraintStencils( const _FEMSystemFunctor& F , const ChildIntegrator& integrator , Stencil< Point3D< double > , OverlapSize > stencils[2][2][2] ); -}; - -template< int FEMDegree , BoundaryType BType > -struct FEMSystemFunctor -{ - double massWeight , lapWeight , biLapWeight; - FEMSystemFunctor( double mWeight=0 , double lWeight=0 , double bWeight=0 ) : massWeight( mWeight ) , lapWeight( lWeight ) , biLapWeight( bWeight ) { ; } - double integrate( const typename SystemCoefficients< FEMDegree , BType , FEMDegree , BType >:: Integrator& integrator , const int off1[] , const int off2[] ) const { return _integrate( integrator , off1 , off2 ); } - double integrate( const typename SystemCoefficients< FEMDegree , BType , FEMDegree , BType >::ChildIntegrator& integrator , const int off1[] , const int off2[] ) const { return _integrate( integrator , off1 , off2 ); } - bool vanishesOnConstants( void ) const { return massWeight==0; } -protected: - template< class I > double _integrate( const I& integrator , const int off1[] , const int off2[] ) const; -}; -template< int SFDegree , BoundaryType SFBType , int FEMDegree , BoundaryType FEMBType > -struct FEMSFConstraintFunctor -{ - double massWeight , lapWeight , biLapWeight; - FEMSFConstraintFunctor( double mWeight=0 , double lWeight=0 , double bWeight=0 ) : massWeight( mWeight ) , lapWeight( lWeight ) , biLapWeight( bWeight ) { ; } - template< bool Reverse > - double integrate( const typename SystemCoefficients< Reverse ? FEMDegree : SFDegree , Reverse ? FEMBType : SFBType , Reverse ? SFDegree : FEMDegree , Reverse ? SFBType : FEMBType >:: Integrator& integrator , const int off1[] , const int off2[] ) const { return _integrate< Reverse >( integrator , off1 , off2 ); } - template< bool Reverse > - double integrate( const typename SystemCoefficients< Reverse ? FEMDegree : SFDegree , Reverse ? FEMBType : SFBType , Reverse ? SFDegree : FEMDegree , Reverse ? SFBType : FEMBType >::ChildIntegrator& integrator , const int off1[] , const int off2[] ) const { return _integrate< Reverse >( integrator , off1 , off2 ); } -protected: - template< bool Reverse , class I > double _integrate( const I& integrator , const int off1[] , const int off[2] ) const; -}; -template< int VFDegree , BoundaryType VFBType , int FEMDegree , BoundaryType FEMBType > -struct FEMVFConstraintFunctor -{ - double lapWeight , biLapWeight; - FEMVFConstraintFunctor( double lWeight=0 , double bWeight=0 ) : lapWeight( lWeight ) , biLapWeight( bWeight ) { ; } - template< bool Reverse > - Point3D< double > integrate( const typename SystemCoefficients< Reverse ? FEMDegree : VFDegree , Reverse ? FEMBType : VFBType , Reverse ? VFDegree : FEMDegree , Reverse ? VFBType : FEMBType >:: Integrator& integrator , const int off1[] , const int off2[] ) const { return _integrate< Reverse >( integrator , off1 , off2 ); } - template< bool Reverse > - Point3D< double > integrate( const typename SystemCoefficients< Reverse ? FEMDegree : VFDegree , Reverse ? FEMBType : VFBType , Reverse ? VFDegree : FEMDegree , Reverse ? VFBType : FEMBType >::ChildIntegrator& integrator , const int off1[] , const int off2[] ) const { return _integrate< Reverse >( integrator , off1 , off2 ); } -protected: - template< bool Reverse , class I > Point3D< double > _integrate( const I& integrator , const int off1[] , const int off[2] ) const; -}; - -inline void SetGhostFlag( OctNode< TreeNodeData >* node , bool flag ){ if( node && node->parent ) node->parent->nodeData.setGhostFlag( flag ); } -inline bool GetGhostFlag( const OctNode< TreeNodeData >* node ){ return node==NULL || node->parent==NULL || node->parent->nodeData.getGhostFlag( ); } -inline bool IsActiveNode( const OctNode< TreeNodeData >* node ){ return !GetGhostFlag( node ); } - -template< class Real > -class Octree -{ - typedef OctNode< TreeNodeData > TreeOctNode; - static int _NodeCount; - static void _NodeInitializer( TreeOctNode& node ){ node.nodeData.nodeIndex = _NodeCount++; } -public: -#if 0 - struct LocalDepth - { - LocalDepth( int d=0 ) : _d(d) { ; } - operator int&() { return _d; } - operator int () const { return _d; } - protected: - int _d; - }; - struct LocalOffset - { - LocalOffset( const int* off=NULL ){ if( off ) memcpy( _off , off , sizeof(_off) ) ; else memset( _off , 0 , sizeof( _off ) ); } - operator int*() { return _off; } - operator const int*() const { return _off; } - protected: - int _off[3]; - }; -#else - typedef int LocalDepth; - typedef int LocalOffset[3]; -#endif - - static void ResetNodeCount( void ){ _NodeCount = 0 ; } - static int NodeCount( void ){ return _NodeCount; } - template< int FEMDegree , BoundaryType BType > void functionIndex( const TreeOctNode* node , int idx[3] ) const; - - struct PointSample{ const TreeOctNode* node ; ProjectiveData< OrientedPoint3D< Real > , Real > sample; }; - - typedef typename TreeOctNode:: NeighborKey< 1 , 1 > AdjacenctNodeKey; - typedef typename TreeOctNode::ConstNeighborKey< 1 , 1 > ConstAdjacenctNodeKey; - - template< int FEMDegree , BoundaryType BType > bool isValidFEMNode( const TreeOctNode* node ) const; - bool isValidSpaceNode( const TreeOctNode* node ) const; - TreeOctNode* leaf( Point3D< Real > p ); - const TreeOctNode* leaf( Point3D< Real > p ) const; - - template< bool HasGradients > - struct InterpolationInfo - { - SparseNodeData< PointData< Real , HasGradients > , 0 > iData; - Real valueWeight , gradientWeight; - InterpolationInfo( const class Octree< Real >& tree , const std::vector< PointSample >& samples , Real pointValue , int adaptiveExponent , Real v , Real g ) : valueWeight(v) , gradientWeight(g) - { iData = tree._densifyInterpolationInfo< HasGradients >( samples , pointValue , adaptiveExponent ); } - PointData< Real , HasGradients >* operator()( const OctNode< TreeNodeData >* node ){ return iData(node); } - const PointData< Real , HasGradients >* operator()( const OctNode< TreeNodeData >* node ) const { return iData(node); } - }; - - template< int DensityDegree > struct DensityEstimator : public SparseNodeData< Real , DensityDegree > - { - DensityEstimator( int kernelDepth ) : _kernelDepth( kernelDepth ){ ; } - int kernelDepth( void ) const { return _kernelDepth; } - protected: - int _kernelDepth; - }; -protected: - bool _isValidSpaceNode( const TreeOctNode* node ) const { return !GetGhostFlag( node ) && ( node->nodeData.flags & TreeNodeData::SPACE_FLAG ); } - bool _isValidFEMNode( const TreeOctNode* node ) const { return !GetGhostFlag( node ) && ( node->nodeData.flags & TreeNodeData::FEM_FLAG ); } - - TreeOctNode* _tree; - TreeOctNode* _spaceRoot; - SortedTreeNodes _sNodes; - LocalDepth _fullDepth , _maxDepth; - - static bool _InBounds( Point3D< Real > p ); - - int _depthOffset; - int _localToGlobal( LocalDepth d ) const { return d + _depthOffset; } - LocalDepth _localDepth( const TreeOctNode* node ) const { return node->depth() - _depthOffset; } - LocalDepth _localMaxDepth( const TreeOctNode* tree ) const { return tree->maxDepth() - _depthOffset; } - int _localInset( LocalDepth d ) const { return _depthOffset<=1 ? 0 : 1<<( d + _depthOffset - 1 ); } - void _localDepthAndOffset( const TreeOctNode* node , LocalDepth& d , LocalOffset& off ) const - { - node->depthAndOffset( d , off ) ; d -= _depthOffset; - int inset = _localInset( d ); - off[0] -= inset , off[1] -= inset , off[2] -= inset; - } - template< int FEMDegree , BoundaryType BType > static int _BSplineBegin( LocalDepth depth ){ return BSplineEvaluationData< FEMDegree , BType >::Begin( depth ); } - template< int FEMDegree , BoundaryType BType > static int _BSplineEnd ( LocalDepth depth ){ return BSplineEvaluationData< FEMDegree , BType >::End ( depth ); } - template< int FEMDegree , BoundaryType BType > - bool _outOfBounds( const TreeOctNode* node ) const - { - if( !node ) return true; - LocalDepth d ; LocalOffset off; - _localDepthAndOffset( node , d , off ); - return d<0 || BSplineEvaluationData< FEMDegree , BType >::OutOfBounds( d , off[0] ) || BSplineEvaluationData< FEMDegree , BType >::OutOfBounds( d , off[1] ) || BSplineEvaluationData< FEMDegree , BType >::OutOfBounds( d , off[2] ); - } - int _sNodesBegin( LocalDepth d ) const { return _sNodes.begin( _localToGlobal( d ) ); } - int _sNodesEnd ( LocalDepth d ) const { return _sNodes.end ( _localToGlobal( d ) ); } - int _sNodesSize ( LocalDepth d ) const { return _sNodes.size ( _localToGlobal( d ) ); } - int _sNodesBegin( LocalDepth d , int slice ) const { return _sNodes.begin( _localToGlobal( d ) , slice + _localInset( d ) ); } - int _sNodesEnd ( LocalDepth d , int slice ) const { return _sNodes.end ( _localToGlobal( d ) , slice + _localInset( d ) ); } - int _sNodesSize ( LocalDepth d , int slice ) const { return _sNodes.size ( _localToGlobal( d ) , slice + _localInset( d ) ); } - - template< int FEMDegree > static bool _IsInteriorlySupported( LocalDepth depth , const LocalOffset off ) - { - if( depth>=0 ) - { - int begin , end; - BSplineSupportSizes< FEMDegree >::InteriorSupportedSpan( depth , begin , end ); - return ( off[0]>=begin && off[0]=begin && off[1]=begin && off[2] bool _isInteriorlySupported( const TreeOctNode* node ) const - { - if( !node ) return false; - LocalDepth d ; LocalOffset off; - _localDepthAndOffset( node , d , off ); - return _IsInteriorlySupported< FEMDegree >( d , off ); - } - template< int FEMDegree1 , int FEMDegree2 > static bool _IsInteriorlyOverlapped( LocalDepth depth , const LocalOffset off ) - { - if( depth>=0 ) - { - int begin , end; - BSplineIntegrationData< FEMDegree1 , BOUNDARY_NEUMANN , FEMDegree2 , BOUNDARY_NEUMANN >::InteriorOverlappedSpan( depth , begin , end ); - return ( off[0]>=begin && off[0]=begin && off[1]=begin && off[2] bool _isInteriorlyOverlapped( const TreeOctNode* node ) const - { - if( !node ) return false; - LocalDepth d ; LocalOffset off; - _localDepthAndOffset( node , d , off ); - return _IsInteriorlyOverlapped< FEMDegree1 , FEMDegree2 >( d , off ); - } - void _startAndWidth( const TreeOctNode* node , Point3D< Real >& start , Real& width ) const - { - LocalDepth d ; LocalOffset off; - _localDepthAndOffset( node , d , off ); - if( d>=0 ) width = Real( 1.0 / (1<< d ) ); - else width = Real( 1.0 * (1<<(-d)) ); - for( int dd=0 ; dd& center , Real& width ) const - { - int d , off[3]; - _localDepthAndOffset( node , d , off ); - width = Real( 1.0 / (1< p ) const - { - Point3D< Real > c ; Real w; - _centerAndWidth( node , c , w ); - return ( p[0] void _setFullDepth( TreeOctNode* node , LocalDepth depth ) const; - template< int Degree , BoundaryType BType > void _setFullDepth( LocalDepth depth ); - - template< int LeftRadius , int RightRadius > - static typename TreeOctNode::ConstNeighbors< LeftRadius + RightRadius + 1 >& _neighbors( TreeOctNode::ConstNeighborKey< LeftRadius , RightRadius >& key , const TreeOctNode* node ){ return key.neighbors[ node->depth() ]; } - template< int LeftRadius , int RightRadius > - static typename TreeOctNode::Neighbors< LeftRadius + RightRadius + 1 >& _neighbors( TreeOctNode::NeighborKey< LeftRadius , RightRadius >& key , const TreeOctNode* node ){ return key.neighbors[ node->depth() ]; } - template< int LeftRadius , int RightRadius > - static const typename TreeOctNode::template Neighbors< LeftRadius + RightRadius + 1 >& _neighbors( const typename TreeOctNode::template NeighborKey< LeftRadius , RightRadius >& key , const TreeOctNode* node ){ return key.neighbors[ node->depth() ]; } - template< int LeftRadius , int RightRadius > - static const typename TreeOctNode::template ConstNeighbors< LeftRadius + RightRadius + 1 >& _neighbors( const typename TreeOctNode::template ConstNeighborKey< LeftRadius , RightRadius >& key , const TreeOctNode* node ){ return key.neighbors[ node->depth() ]; } - -public: - LocalDepth depth( const TreeOctNode* node ) const { return _localDepth( node ); } - void depthAndOffset( const TreeOctNode* node , LocalDepth& depth , LocalOffset& offset ) const { _localDepthAndOffset( node , depth , offset ); } - - int nodesBegin( LocalDepth d ) const { return _sNodes.begin( _localToGlobal( d ) ); } - int nodesEnd ( LocalDepth d ) const { return _sNodes.end ( _localToGlobal( d ) ); } - int nodesSize ( LocalDepth d ) const { return _sNodes.size ( _localToGlobal( d ) ); } - int nodesBegin( LocalDepth d , int slice ) const { return _sNodes.begin( _localToGlobal( d ) , slice + _localInset( d ) ); } - int nodesEnd ( LocalDepth d , int slice ) const { return _sNodes.end ( _localToGlobal( d ) , slice + _localInset( d ) ); } - int nodesSize ( LocalDepth d , int slice ) const { return _sNodes.size ( _localToGlobal( d ) , slice + _localInset( d ) ); } - const TreeOctNode* node( int idx ) const { return _sNodes.treeNodes[idx]; } -protected: - - //////////////////////////////////// - // System construction code // - // MultiGridOctreeData.System.inl // - //////////////////////////////////// - template< int FEMDegree > - void _setMultiColorIndices( int start , int end , std::vector< std::vector< int > >& indices ) const; - struct _SolverStats - { - double evaluateTime , systemTime , solveTime; - double bNorm2 , inRNorm2 , outRNorm2; - }; - template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > - int _solveSystemGS( const FEMSystemFunctor& F , const BSplineData< FEMDegree , BType >& bsData , InterpolationInfo< HasGradients >* interpolationInfo , LocalDepth depth , DenseNodeData< Real , FEMDegree >& solution , DenseNodeData< Real , FEMDegree >& constraints , DenseNodeData< Real , FEMDegree >& metSolutionConstraints , int iters , bool coarseToFine , _SolverStats& stats , bool computeNorms ); - template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > - int _solveSystemCG( const FEMSystemFunctor& F , const BSplineData< FEMDegree , BType >& bsData , InterpolationInfo< HasGradients >* interpolationInfo , LocalDepth depth , DenseNodeData< Real , FEMDegree >& solution , DenseNodeData< Real , FEMDegree >& constraints , DenseNodeData< Real , FEMDegree >& metSolutionConstraints , int iters , bool coarseToFine , _SolverStats& stats , bool computeNorms , double accuracy ); - template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > - int _setMatrixRow( const FEMSystemFunctor& F , const InterpolationInfo< HasGradients >* interpolationInfo , const typename TreeOctNode::Neighbors< BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& neighbors , Pointer( MatrixEntry< Real > ) row , int offset , const typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template Integrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) >& integrator , const Stencil< double , BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& stencil , const BSplineData< FEMDegree , BType >& bsData ) const; - template< int FEMDegree , BoundaryType BType > - int _getMatrixRowSize( const typename TreeOctNode::Neighbors< BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& neighbors ) const; - - template< int FEMDegree1 , int FEMDegree2 > static void _SetParentOverlapBounds( const TreeOctNode* node , int& startX , int& endX , int& startY , int& endY , int& startZ , int& endZ ); - // Updates the constraints @(depth) based on the solution coefficients @(depth-1) - - template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > - void _updateConstraintsFromCoarser( const FEMSystemFunctor& F , const InterpolationInfo< HasGradients >* interpolationInfo , const typename TreeOctNode::Neighbors< BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& neighbors , const typename TreeOctNode::Neighbors< BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& pNeighbors , TreeOctNode* node , DenseNodeData< Real , FEMDegree >& constraints , const DenseNodeData< Real , FEMDegree >& metSolution , const typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template ChildIntegrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) >& childIntegrator , const Stencil< double , BSplineOverlapSizes< FEMDegree , FEMDegree >::OverlapSize >& stencil , const BSplineData< FEMDegree , BType >& bsData ) const; - - // evaluate the points @(depth) using coefficients @(depth-1) - template< int FEMDegree , BoundaryType BType , bool HasGradients > - void _setPointValuesFromCoarser( InterpolationInfo< HasGradients >& interpolationInfo , LocalDepth highDepth , const BSplineData< FEMDegree , BType >& bsData , const DenseNodeData< Real , FEMDegree >& upSampledCoefficients ); - - // Updates the cumulative integral constraints @(depth-1) based on the change in solution coefficients @(depth) - template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor > - void _updateCumulativeIntegralConstraintsFromFiner( const FEMSystemFunctor& F , - const BSplineData< FEMDegree , BType >& bsData , LocalDepth highDepth , const DenseNodeData< Real , FEMDegree >& fineSolution , DenseNodeData< Real , FEMDegree >& cumulativeConstraints ) const; - // Updates the cumulative interpolation constraints @(depth-1) based on the change in solution coefficient @(depth) - template< int FEMDegree , BoundaryType BType , bool HasGradients > - void _updateCumulativeInterpolationConstraintsFromFiner( const InterpolationInfo< HasGradients >& interpolationInfo , - const BSplineData< FEMDegree , BType >& bsData , LocalDepth highDepth , const DenseNodeData< Real , FEMDegree >& fineSolution , DenseNodeData< Real , FEMDegree >& cumulativeConstraints ) const; - - template< int FEMDegree , BoundaryType BType > - Real _coarserFunctionValue( Point3D< Real > p , const PointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , const BSplineData< FEMDegree , BType >& bsData , const DenseNodeData< Real , FEMDegree >& upSampledCoefficients ) const; - template< int FEMDegree , BoundaryType BType > - Point3D< Real > _coarserFunctionGradient( Point3D< Real > p , const PointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , const BSplineData< FEMDegree , BType >& bsData , const DenseNodeData< Real , FEMDegree >& upSampledCoefficients ) const; - template< int FEMDegree , BoundaryType BType > - Real _finerFunctionValue( Point3D< Real > p , const PointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , const BSplineData< FEMDegree , BType >& bsData , const DenseNodeData< Real , FEMDegree >& coefficients ) const; - template< int FEMDegree , BoundaryType BType > - Point3D< Real > _finerFunctionGradient( Point3D< Real > p , const PointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , const BSplineData< FEMDegree , BType >& bsData , const DenseNodeData< Real , FEMDegree >& coefficients ) const; - template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > - int _getSliceMatrixAndUpdateConstraints( const FEMSystemFunctor& F , const InterpolationInfo< HasGradients >* interpolationInfo , SparseMatrix< Real >& matrix , DenseNodeData< Real , FEMDegree >& constraints , typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template Integrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) >& integrator , typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template ChildIntegrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) >& childIntegrator , const BSplineData< FEMDegree , BType >& bsData , LocalDepth depth , int slice , const DenseNodeData< Real , FEMDegree >& metSolution , bool coarseToFine ); - template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > - int _getMatrixAndUpdateConstraints( const FEMSystemFunctor& F , const InterpolationInfo< HasGradients >* interpolationInfo , SparseMatrix< Real >& matrix , DenseNodeData< Real , FEMDegree >& constraints , typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template Integrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) >& integrator , typename BSplineIntegrationData< FEMDegree , BType , FEMDegree , BType >::FunctionIntegrator::template ChildIntegrator< DERIVATIVES( FEMDegree ) , DERIVATIVES( FEMDegree ) >& childIntegrator , const BSplineData< FEMDegree , BType >& bsData , LocalDepth depth , const DenseNodeData< Real , FEMDegree >& metSolution , bool coarseToFine ); - - // Down samples constraints @(depth) to constraints @(depth-1) - template< class C , int FEMDegree , BoundaryType BType > void _downSample( LocalDepth highDepth , DenseNodeData< C , FEMDegree >& constraints ) const; - // Up samples coefficients @(depth-1) to coefficients @(depth) - template< class C , int FEMDegree , BoundaryType BType > void _upSample( LocalDepth highDepth , DenseNodeData< C , FEMDegree >& coefficients ) const; - template< class C , int FEMDegree , BoundaryType BType > static void _UpSample( LocalDepth highDepth , ConstPointer( C ) lowCoefficients , Pointer( C ) highCoefficients , int threads ); -public: - template< class C , int FEMDegree , BoundaryType BType > DenseNodeData< C , FEMDegree > coarseCoefficients( const DenseNodeData< C , FEMDegree >& coefficients ) const; - template< class C , int FEMDegree , BoundaryType BType > DenseNodeData< C , FEMDegree > coarseCoefficients( const SparseNodeData< C , FEMDegree >& coefficients ) const; -protected: - - ///////////////////////////////////////////// - // Code for splatting point-sample data // - // MultiGridOctreeData.WeightedSamples.inl // - ///////////////////////////////////////////// - template< int WeightDegree > - void _addWeightContribution( DensityEstimator< WeightDegree >& densityWeights , TreeOctNode* node , Point3D< Real > position , PointSupportKey< WeightDegree >& weightKey , Real weight=Real(1.0) ); - template< int WeightDegree , class PointSupportKey > - Real _getSamplesPerNode( const DensityEstimator< WeightDegree >& densityWeights , const TreeOctNode* node , Point3D< Real > position , PointSupportKey& weightKey ) const; - template< int WeightDegree , class PointSupportKey > - void _getSampleDepthAndWeight( const DensityEstimator< WeightDegree >& densityWeights , const TreeOctNode* node , Point3D< Real > position , PointSupportKey& weightKey , Real& depth , Real& weight ) const; - template< int WeightDegree , class PointSupportKey > - void _getSampleDepthAndWeight( const DensityEstimator< WeightDegree >& densityWeights , Point3D< Real > position , PointSupportKey& weightKey , Real& depth , Real& weight ) const; - template< bool CreateNodes , int DataDegree , class V > void _splatPointData( TreeOctNode* node , Point3D< Real > point , V v , SparseNodeData< V , DataDegree >& data , PointSupportKey< DataDegree >& dataKey ); - template< bool CreateNodes , int WeightDegree , int DataDegree , class V > Real _splatPointData( const DensityEstimator< WeightDegree >& densityWeights , Point3D< Real > point , V v , SparseNodeData< V , DataDegree >& data , PointSupportKey< WeightDegree >& weightKey , PointSupportKey< DataDegree >& dataKey , LocalDepth minDepth , LocalDepth maxDepth , int dim=DIMENSION ); - template< bool CreateNodes , int WeightDegree , int DataDegree , class V > Real _multiSplatPointData( const DensityEstimator< WeightDegree >* densityWeights , TreeOctNode* node , Point3D< Real > point , V v , SparseNodeData< V , DataDegree >& data , PointSupportKey< WeightDegree >& weightKey , PointSupportKey< DataDegree >& dataKey , int dim=DIMENSION ); - template< class V , int DataDegree , BoundaryType BType , class Coefficients > V _evaluate( const Coefficients& coefficients , Point3D< Real > p , const BSplineData< DataDegree , BType >& bsData , const ConstPointSupportKey< DataDegree >& dataKey ) const; -public: - template< class V , int DataDegree , BoundaryType BType > Pointer( V ) voxelEvaluate( const DenseNodeData< V , DataDegree >& coefficients , int& res , Real isoValue=0.f , LocalDepth depth=-1 , bool primal=false ); - - template< int NormalDegree > - struct HasNormalDataFunctor - { - const SparseNodeData< Point3D< Real > , NormalDegree >& normalInfo; - HasNormalDataFunctor( const SparseNodeData< Point3D< Real > , NormalDegree >& ni ) : normalInfo( ni ){ ; } - bool operator() ( const TreeOctNode* node ) const - { - const Point3D< Real >* n = normalInfo( node ); - if( n ) - { - const Point3D< Real >& normal = *n; - if( normal[0]!=0 || normal[1]!=0 || normal[2]!=0 ) return true; - } - if( node->children ) for( int c=0 ; cchildren + c ) ) return true; - return false; - } - }; - struct TrivialHasDataFunctor{ bool operator() ( const TreeOctNode* node ) const{ return true; } }; - - // [NOTE] The input/output for this method is pre-scaled by weight - template< bool HasGradients > bool _setInterpolationInfoFromChildren( TreeOctNode* node , SparseNodeData< PointData< Real , HasGradients > , 0 >& iInfo ) const; - template< bool HasGradients > SparseNodeData< PointData< Real , HasGradients > , 0 > _densifyInterpolationInfo( const std::vector< PointSample >& samples , Real pointValue , int adaptiveExponent ) const; - - template< int FEMDegree , BoundaryType BType > void _setValidityFlags( void ); - template< class HasDataFunctor > void _clipTree( const HasDataFunctor& f ); - - template< int FEMDegree , BoundaryType BType > SparseNodeData< Real , 0 > leafValues ( const DenseNodeData< Real , FEMDegree >& coefficients ) const; - template< int FEMDegree , BoundaryType BType > SparseNodeData< Point3D< Real > , 0 > leafGradients( const DenseNodeData< Real , FEMDegree >& coefficients ) const; - - //////////////////////////////////// - // Evaluation Methods // - // MultiGridOctreeData.Evaluation // - //////////////////////////////////// - static const int CHILDREN = Cube::CORNERS; - template< int FEMDegree , BoundaryType BType > - struct _Evaluator - { - typename BSplineEvaluationData< FEMDegree , BType >::Evaluator evaluator; - typename BSplineEvaluationData< FEMDegree , BType >::ChildEvaluator childEvaluator; - Stencil< double , BSplineSupportSizes< FEMDegree >::SupportSize > cellStencil; - Stencil< double , BSplineSupportSizes< FEMDegree >::SupportSize > cellStencils [CHILDREN]; - Stencil< double , BSplineSupportSizes< FEMDegree >::SupportSize > edgeStencil [Cube::EDGES ]; - Stencil< double , BSplineSupportSizes< FEMDegree >::SupportSize > edgeStencils [CHILDREN][Cube::EDGES ]; - Stencil< double , BSplineSupportSizes< FEMDegree >::SupportSize > faceStencil [Cube::FACES ]; - Stencil< double , BSplineSupportSizes< FEMDegree >::SupportSize > faceStencils [CHILDREN][Cube::FACES ]; - Stencil< double , BSplineSupportSizes< FEMDegree >::SupportSize > cornerStencil [Cube::CORNERS]; - Stencil< double , BSplineSupportSizes< FEMDegree >::SupportSize > cornerStencils[CHILDREN][Cube::CORNERS]; - - Stencil< Point3D< double > , BSplineSupportSizes< FEMDegree >::SupportSize > dCellStencil; - Stencil< Point3D< double > , BSplineSupportSizes< FEMDegree >::SupportSize > dCellStencils [CHILDREN]; - Stencil< Point3D< double > , BSplineSupportSizes< FEMDegree >::SupportSize > dEdgeStencil [Cube::EDGES ]; - Stencil< Point3D< double > , BSplineSupportSizes< FEMDegree >::SupportSize > dEdgeStencils [CHILDREN][Cube::EDGES ]; - Stencil< Point3D< double > , BSplineSupportSizes< FEMDegree >::SupportSize > dFaceStencil [Cube::FACES ]; - Stencil< Point3D< double > , BSplineSupportSizes< FEMDegree >::SupportSize > dFaceStencils [CHILDREN][Cube::FACES ]; - Stencil< Point3D< double > , BSplineSupportSizes< FEMDegree >::SupportSize > dCornerStencil [Cube::CORNERS]; - Stencil< Point3D< double > , BSplineSupportSizes< FEMDegree >::SupportSize > dCornerStencils[CHILDREN][Cube::CORNERS]; - - void set( LocalDepth depth ); - _Evaluator( void ){ _bsData = NULL; } - ~_Evaluator( void ){ if( _bsData ) delete _bsData , _bsData = NULL; } - protected: - BSplineData< FEMDegree , BType >* _bsData; - friend Octree; - }; - template< class V , int FEMDegree , BoundaryType BType > - V _getCenterValue( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , const DenseNodeData< V , FEMDegree >& solution , const DenseNodeData< V , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator , bool isInterior ) const; - template< class V , int FEMDegree , BoundaryType BType > - V _getCornerValue( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , int corner , const DenseNodeData< V , FEMDegree >& solution , const DenseNodeData< V , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator , bool isInterior ) const; - template< class V , int FEMDegree , BoundaryType BType > - V _getEdgeValue ( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , int edge , const DenseNodeData< V , FEMDegree >& solution , const DenseNodeData< V , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator , bool isInterior ) const; - template< class V , int FEMDegree , BoundaryType BType > - V _getValue ( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , Point3D< Real > p , const DenseNodeData< V , FEMDegree >& solution , const DenseNodeData< V , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator ) const; - - template< int FEMDegree , BoundaryType BType > - std::pair< Real , Point3D< Real > > _getCenterValueAndGradient( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , const DenseNodeData< Real , FEMDegree >& solution , const DenseNodeData< Real , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator , bool isInterior ) const; - template< int FEMDegree , BoundaryType BType > - std::pair< Real , Point3D< Real > > _getCornerValueAndGradient( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , int corner , const DenseNodeData< Real , FEMDegree >& solution , const DenseNodeData< Real , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator , bool isInterior ) const; - template< int FEMDegree , BoundaryType BType > - std::pair< Real , Point3D< Real > > _getEdgeValueAndGradient ( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , int edge , const DenseNodeData< Real , FEMDegree >& solution , const DenseNodeData< Real , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator , bool isInterior ) const; - template< int FEMDegree , BoundaryType BType > - std::pair< Real , Point3D< Real > > _getValueAndGradient ( const ConstPointSupportKey< FEMDegree >& neighborKey , const TreeOctNode* node , Point3D< Real > p , const DenseNodeData< Real , FEMDegree >& solution , const DenseNodeData< Real , FEMDegree >& coarseSolution , const _Evaluator< FEMDegree , BType >& evaluator ) const; - -public: - template< int Degree , BoundaryType BType > - class MultiThreadedEvaluator - { - const Octree* _tree; - int _threads; - std::vector< ConstPointSupportKey< Degree > > _neighborKeys; - _Evaluator< Degree , BType > _evaluator; - const DenseNodeData< Real , Degree >& _coefficients; - DenseNodeData< Real , Degree > _coarseCoefficients; - public: - MultiThreadedEvaluator( const Octree* tree , const DenseNodeData< Real , Degree >& coefficients , int threads=1 ); - Real value( Point3D< Real > p , int thread=0 , const TreeOctNode* node=NULL ); - std::pair< Real , Point3D< Real > > valueAndGradient( Point3D< Real > , int thread=0 , const TreeOctNode* node=NULL ); - }; - - //////////////////////////////////////// - // Iso-Surfacing Methods // - // MultiGridOctreeData.IsoSurface.inl // - //////////////////////////////////////// -protected: - struct _IsoEdge - { - long long edges[2]; - _IsoEdge( void ){ edges[0] = edges[1] = 0; } - _IsoEdge( long long v1 , long long v2 ){ edges[0] = v1 , edges[1] = v2; } - long long& operator[]( int idx ){ return edges[idx]; } - const long long& operator[]( int idx ) const { return edges[idx]; } - }; - struct _FaceEdges - { - _IsoEdge edges[2]; - int count; - }; - template< class Vertex > - struct _SliceValues - { - typename SortedTreeNodes::SliceTableData sliceData; - Pointer( Real ) cornerValues ; Pointer( Point3D< Real > ) cornerGradients ; Pointer( char ) cornerSet; - Pointer( long long ) edgeKeys ; Pointer( char ) edgeSet; - Pointer( _FaceEdges ) faceEdges ; Pointer( char ) faceSet; - Pointer( char ) mcIndices; - std::unordered_map< long long, std::vector< _IsoEdge > > faceEdgeMap; - std::unordered_map< long long, std::pair< int, Vertex > > edgeVertexMap; - std::unordered_map< long long, long long > vertexPairMap; - - _SliceValues( void ); - ~_SliceValues( void ); - void reset( bool nonLinearFit ); - protected: - int _oldCCount , _oldECount , _oldFCount , _oldNCount; - }; - template< class Vertex > - struct _XSliceValues - { - typename SortedTreeNodes::XSliceTableData xSliceData; - Pointer( long long ) edgeKeys ; Pointer( char ) edgeSet; - Pointer( _FaceEdges ) faceEdges ; Pointer( char ) faceSet; - std::unordered_map< long long, std::vector< _IsoEdge > > faceEdgeMap; - std::unordered_map< long long, std::pair< int, Vertex > > edgeVertexMap; - std::unordered_map< long long, long long > vertexPairMap; - - _XSliceValues( void ); - ~_XSliceValues( void ); - void reset( void ); - protected: - int _oldECount , _oldFCount; - }; - template< class Vertex > - struct _SlabValues - { - protected: - _XSliceValues< Vertex > _xSliceValues[2]; - _SliceValues< Vertex > _sliceValues[2]; - public: - _SliceValues< Vertex >& sliceValues( int idx ){ return _sliceValues[idx&1]; } - const _SliceValues< Vertex >& sliceValues( int idx ) const { return _sliceValues[idx&1]; } - _XSliceValues< Vertex >& xSliceValues( int idx ){ return _xSliceValues[idx&1]; } - const _XSliceValues< Vertex >& xSliceValues( int idx ) const { return _xSliceValues[idx&1]; } - }; - template< class Vertex , int FEMDegree , BoundaryType BType > - void _setSliceIsoCorners( const DenseNodeData< Real , FEMDegree >& solution , const DenseNodeData< Real , FEMDegree >& coarseSolution , Real isoValue , LocalDepth depth , int slice , std::vector< _SlabValues< Vertex > >& sValues , const _Evaluator< FEMDegree , BType >& evaluator , int threads ); - template< class Vertex , int FEMDegree , BoundaryType BType > - void _setSliceIsoCorners( const DenseNodeData< Real , FEMDegree >& solution , const DenseNodeData< Real , FEMDegree >& coarseSolution , Real isoValue , LocalDepth depth , int slice , int z , std::vector< _SlabValues< Vertex > >& sValues , const _Evaluator< FEMDegree , BType >& evaluator , int threads ); - template< int WeightDegree , int ColorDegree , BoundaryType BType , class Vertex > - void _setSliceIsoVertices( const BSplineData< ColorDegree , BType >* colorBSData , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Point3D< Real > , Real > , ColorDegree >* colorData , Real isoValue , LocalDepth depth , int slice , int& vOffset , CoredMeshData< Vertex >& mesh , std::vector< _SlabValues< Vertex > >& sValues , int threads ); - template< int WeightDegree , int ColorDegree , BoundaryType BType , class Vertex > - void _setSliceIsoVertices( const BSplineData< ColorDegree , BType >* colorBSData , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Point3D< Real > , Real > , ColorDegree >* colorData , Real isoValue , LocalDepth depth , int slice , int z , int& vOffset , CoredMeshData< Vertex >& mesh , std::vector< _SlabValues< Vertex > >& sValues , int threads ); - template< int WeightDegree , int ColorDegree , BoundaryType BType , class Vertex > - void _setXSliceIsoVertices( const BSplineData< ColorDegree , BType >* colorBSData , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Point3D< Real > , Real > , ColorDegree >* colorData , Real isoValue , LocalDepth depth , int slab , int& vOffset , CoredMeshData< Vertex >& mesh , std::vector< _SlabValues< Vertex > >& sValues , int threads ); - template< class Vertex > - void _setSliceIsoEdges( LocalDepth depth , int slice , std::vector< _SlabValues< Vertex > >& slabValues , int threads ); - template< class Vertex > - void _setSliceIsoEdges( LocalDepth depth , int slice , int z , std::vector< _SlabValues< Vertex > >& slabValues , int threads ); - template< class Vertex > - void _setXSliceIsoEdges( LocalDepth depth , int slice , std::vector< _SlabValues< Vertex > >& slabValues , int threads ); - template< class Vertex > - void _copyFinerSliceIsoEdgeKeys( LocalDepth depth , int slice , std::vector< _SlabValues< Vertex > >& sValues , int threads ); - template< class Vertex > - void _copyFinerSliceIsoEdgeKeys( LocalDepth depth , int slice , int z , std::vector< _SlabValues< Vertex > >& sValues , int threads ); - template< class Vertex > - void _copyFinerXSliceIsoEdgeKeys( LocalDepth depth , int slab , std::vector< _SlabValues< Vertex > >& sValues , int threads ); - - template< class Vertex > - void _setIsoSurface( LocalDepth depth , int offset , const _SliceValues< Vertex >& bValues , const _SliceValues< Vertex >& fValues , const _XSliceValues< Vertex >& xValues , CoredMeshData< Vertex >& mesh , bool polygonMesh , bool addBarycenter , int& vOffset , int threads ); - - template< class Vertex > - static int _addIsoPolygons( CoredMeshData< Vertex >& mesh , std::vector< std::pair< int , Vertex > >& polygon , bool polygonMesh , bool addBarycenter , int& vOffset ); - - template< int WeightDegree , int ColorDegree , BoundaryType BType , class Vertex > - bool _getIsoVertex( const BSplineData< ColorDegree , BType >* colorBSData , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Point3D< Real > , Real > , ColorDegree >* colorData , Real isoValue , ConstPointSupportKey< WeightDegree >& weightKey , ConstPointSupportKey< ColorDegree >& colorKey , const TreeOctNode* node , int edgeIndex , int z , const _SliceValues< Vertex >& sValues , Vertex& vertex ); - template< int WeightDegree , int ColorDegree , BoundaryType BType , class Vertex > - bool _getIsoVertex( const BSplineData< ColorDegree , BType >* colorBSData , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Point3D< Real > , Real > , ColorDegree >* colorData , Real isoValue , ConstPointSupportKey< WeightDegree >& weightKey , ConstPointSupportKey< ColorDegree >& colorKey , const TreeOctNode* node , int cornerIndex , const _SliceValues< Vertex >& bValues , const _SliceValues< Vertex >& fValues , Vertex& vertex ); - - void _init( TreeOctNode* node , LocalDepth maxDepth , bool (*Refine)( LocalDepth d , LocalOffset off ) ); - - double _maxMemoryUsage , _localMemoryUsage; -public: - int threads; - double maxMemoryUsage( void ) const { return _maxMemoryUsage; } - double localMemoryUsage( void ) const { return _localMemoryUsage; } - void resetLocalMemoryUsage( void ){ _localMemoryUsage = 0; } - double memoryUsage( void ); - - Octree( void ); - - void init( LocalDepth maxDepth , bool (*Refine)( LocalDepth d , LocalOffset off ) ); - template< class Data > - int init( OrientedPointStream< Real >& pointStream , LocalDepth maxDepth , bool useConfidence , std::vector< PointSample >& samples , std::vector< ProjectiveData< Data , Real > >* sampleData ); - template< int DensityDegree > - typename Octree::template DensityEstimator< DensityDegree >* setDensityEstimator( const std::vector< PointSample >& samples , LocalDepth splatDepth , Real samplesPerNode ); - template< int NormalDegree , int DensityDegree > - SparseNodeData< Point3D< Real > , NormalDegree > setNormalField( const std::vector< PointSample >& samples , const DensityEstimator< DensityDegree >& density , Real& pointWeightSum , bool forceNeumann ); - template< int DataDegree , bool CreateNodes , int DensityDegree , class Data > - SparseNodeData< ProjectiveData< Data , Real > , DataDegree > setDataField( const std::vector< PointSample >& samples , std::vector< ProjectiveData< Data , Real > >& sampleData , const DensityEstimator< DensityDegree >* density ); - template< int MaxDegree , int FEMDegree , BoundaryType FEMBType , class HasDataFunctor > void inalizeForBroodedMultigrid( LocalDepth fullDepth , const HasDataFunctor& F , std::vector< int >* map=NULL ); - - // Generate an empty set of constraints - template< int FEMDegree > DenseNodeData< Real , FEMDegree > initDenseNodeData( void ); - - // Add finite-elements constraints (derived from a sparse scalar field) - template< int FEMDegree , BoundaryType FEMBType , int SFDegree , BoundaryType SFBType , class FEMSFConstraintFunctor > void addFEMConstraints( const FEMSFConstraintFunctor& F , const SparseNodeData< Real , SFDegree >& sfCoefficients , DenseNodeData< Real , FEMDegree >& constraints , LocalDepth maxDepth ) - { return _addFEMConstraints< FEMDegree , FEMBType , SFDegree , SFBType , FEMSFConstraintFunctor , const SparseNodeData< Real , SFDegree > , Real , double >( F , sfCoefficients , constraints , maxDepth ); } - // Add finite-elements constraints (derived from a dense scalar field) - template< int FEMDegree , BoundaryType FEMBType , int SFDegree , BoundaryType SFBType , class FEMSFConstraintFunctor > void addFEMConstraints( const FEMSFConstraintFunctor& F , const DenseNodeData< Real , SFDegree >& sfCoefficients , DenseNodeData< Real , FEMDegree >& constraints , LocalDepth maxDepth ) - { return _addFEMConstraints< FEMDegree , FEMBType , SFDegree , SFBType , FEMSFConstraintFunctor , const DenseNodeData< Real , SFDegree > , Real , double >( F , sfCoefficients , constraints , maxDepth ); } - // Add finite-elements constraints (derived from a sparse vector field) - template< int FEMDegree , BoundaryType FEMBType , int VFDegree , BoundaryType VFBType , class FEMVFConstraintFunctor > void addFEMConstraints( const FEMVFConstraintFunctor& F , const SparseNodeData< Point3D< Real > , VFDegree >& vfCoefficients , DenseNodeData< Real , FEMDegree >& constraints , LocalDepth maxDepth ) - { return _addFEMConstraints< FEMDegree , FEMBType , VFDegree , VFBType , FEMVFConstraintFunctor , const SparseNodeData< Point3D< Real > , VFDegree > , Point3D< Real > , Point3D< double > >( F , vfCoefficients , constraints , maxDepth ); } - // Add finite-elements constraints (derived from a dense vector field) - template< int FEMDegree , BoundaryType FEMBType , int VFDegree , BoundaryType VFBType , class FEMVFConstraintFunctor > void addFEMConstraints( const FEMVFConstraintFunctor& F , const DenseNodeData< Point3D< Real > , VFDegree >& vfCoefficients , DenseNodeData< Real , FEMDegree >& constraints , LocalDepth maxDepth ) - { return _addFEMConstraints< FEMDegree , FEMBType , VFDegree , VFBType , FEMVFConstraintFunctor , const DenseNodeData< Point3D< Real > , VFDegree > , Point3D< Real > , Point3D< double > >( F , vfCoefficients , constraints , maxDepth ); } - // Add interpolation constraints - template< int FEMDegree , BoundaryType FEMBType , bool HasGradients > void addInterpolationConstraints( const InterpolationInfo< HasGradients >& interpolationInfo , DenseNodeData< Real , FEMDegree >& constraints , LocalDepth maxDepth ); - - template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 , class DotFunctor > double dot( const DotFunctor& F , const SparseNodeData< Real , Degree1 >& coefficients1 , const SparseNodeData< Real , Degree2 >& coefficients2 ) const - { return _dot< Degree1 , BType1 , Degree2 , BType2 , DotFunctor , false >( F , (const InterpolationInfo< false >*)NULL , coefficients1 , coefficients2 ); } - template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 , class DotFunctor > double dot( const DotFunctor& F , const SparseNodeData< Real , Degree1 >& coefficients1 , const DenseNodeData< Real , Degree2 >& coefficients2 ) const - { return _dot< Degree1 , BType1 , Degree2 , BType2 , DotFunctor , false >( F , (const InterpolationInfo< false >*)NULL , coefficients1 , coefficients2 ); } - template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 , class DotFunctor > double dot( const DotFunctor& F , const DenseNodeData< Real , Degree1 >& coefficients1 , const SparseNodeData< Real , Degree2 >& coefficients2 ) const - { return _dot< Degree1 , BType1 , Degree2 , BType2 , DotFunctor , false >( F , (const InterpolationInfo< false >*)NULL , coefficients1 , coefficients2 ); } - template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 , class DotFunctor > double dot( const DotFunctor& F , const DenseNodeData< Real , Degree1 >& coefficients1 , const DenseNodeData< Real , Degree2 >& coefficients2 ) const - { return _dot< Degree1 , BType1 , Degree2 , BType2 , DotFunctor , false >( F , (const InterpolationInfo< false >*)NULL , coefficients1 , coefficients2 ); } - - template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 , class DotFunctor , bool HasGradients > double dot( const DotFunctor& F , const InterpolationInfo< HasGradients >* iInfo , const SparseNodeData< Real , Degree1 >& coefficients1 , const SparseNodeData< Real , Degree2 >& coefficients2 ) const - { return _dot< Degree1 , BType1 , Degree2 , BType2 , DotFunctor , HasGradients >( F , iInfo , coefficients1 , coefficients2 ); } - template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 , class DotFunctor , bool HasGradients > double dot( const DotFunctor& F , const InterpolationInfo< HasGradients >* iInfo , const SparseNodeData< Real , Degree1 >& coefficients1 , const DenseNodeData< Real , Degree2 >& coefficients2 ) const - { return _dot< Degree1 , BType1 , Degree2 , BType2 , DotFunctor , HasGradients >( F , iInfo , coefficients1 , coefficients2 ); } - template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 , class DotFunctor , bool HasGradients > double dot( const DotFunctor& F , const InterpolationInfo< HasGradients >* iInfo , const DenseNodeData< Real , Degree1 >& coefficients1 , const SparseNodeData< Real , Degree2 >& coefficients2 ) const - { return _dot< Degree1 , BType1 , Degree2 , BType2 , DotFunctor , HasGradients >( F , iInfo , coefficients1 , coefficients2 ); } - template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 , class DotFunctor , bool HasGradients > double dot( const DotFunctor& F , const InterpolationInfo< HasGradients >* iInfo , const DenseNodeData< Real , Degree1 >& coefficients1 , const DenseNodeData< Real , Degree2 >& coefficients2 ) const - { return _dot< Degree1 , BType1 , Degree2 , BType2 , DotFunctor , HasGradients >( F , iInfo , coefficients1 , coefficients2 ); } - - template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > - void setSystemMatrix( const FEMSystemFunctor& F , const InterpolationInfo< HasGradients >* interpolationInfo , LocalDepth depth , SparseMatrix< Real >& matrix ) const; - - // Solve the linear system - struct SolverInfo - { - // How to solve - LocalDepth cgDepth; - int iters; - double cgAccuracy , lowResIterMultiplier; - // What to output - bool verbose , showResidual; - - SolverInfo( void ) : cgDepth(0) , iters(1), cgAccuracy(0) , lowResIterMultiplier(0) , verbose(false) , showResidual(false) { ; } - }; - template< int FEMDegree , BoundaryType BType , class FEMSystemFunctor , bool HasGradients > - DenseNodeData< Real , FEMDegree > solveSystem( const FEMSystemFunctor& F , InterpolationInfo< HasGradients >* iData , DenseNodeData< Real , FEMDegree >& constraints , LocalDepth maxSolveDepth , const SolverInfo& solverInfo ); - - template< int FEMDegree , BoundaryType BType , int WeightDegree , int ColorDegree , class Vertex > - void getMCIsoSurface( const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Point3D< Real > , Real > , ColorDegree >* colorData , const DenseNodeData< Real , FEMDegree >& solution , Real isoValue , CoredMeshData< Vertex >& mesh , bool nonLinearFit=true , bool addBarycenter=false , bool polygonMesh=false ); - - - const TreeOctNode& tree( void ) const{ return *_tree; } - size_t leaves( void ) const { return _tree->leaves(); } - size_t nodes( void ) const { int count = 0 ; for( const TreeOctNode* n=_tree->nextNode() ; n ; n=_tree->nextNode( n ) ) if( IsActiveNode( n ) ) count++ ; return count; } - size_t ghostNodes( void ) const { int count = 0 ; for( const TreeOctNode* n=_tree->nextNode() ; n ; n=_tree->nextNode( n ) ) if( !IsActiveNode( n ) ) count++ ; return count; } - inline size_t validSpaceNodes( void ) const { int count = 0 ; for( const TreeOctNode* n=_tree->nextNode() ; n ; n=_tree->nextNode( n ) ) if( isValidSpaceNode( n ) ) count++ ; return count; } - inline size_t validSpaceNodes( LocalDepth d ) const { int count = 0 ; for( const TreeOctNode* n=_tree->nextNode() ; n ; n=_tree->nextNode( n ) ) if( _localDepth(n)==d && isValidSpaceNode( n ) ) count++ ; return count; } - template< int Degree , BoundaryType BType > size_t validFEMNodes( void ) const { int count = 0 ; for( const TreeOctNode* n=_tree->nextNode() ; n ; n=_tree->nextNode( n ) ) if( isValidFEMNode< Degree , BType >( n ) ) count++ ; return count; } - template< int Degree , BoundaryType BType > size_t validFEMNodes( LocalDepth d ) const { int count = 0 ; for( const TreeOctNode* n=_tree->nextNode() ; n ; n=_tree->nextNode( n ) ) if( _localDepth(n)==d && isValidFEMNode< Degree , BType >( n ) ) count++ ; return count; } - LocalDepth depth( void ) const { return _localMaxDepth( _tree ); } - void resetNodeIndices( void ){ _NodeCount = 0 ; for( TreeOctNode* node=_tree->nextNode() ; node ; node=_tree->nextNode( node ) ) _NodeInitializer( *node ) , node->nodeData.flags=0; } - -protected: - template< class D > static bool _IsZero( const D& d ); - template< class D > static Real _Dot( const D& d1 , const D& d2 ); - template< int FEMDegree , BoundaryType FEMBType , int CDegree , BoundaryType CBType , class FEMConstraintFunctor , class Coefficients , class D , class _D > - void _addFEMConstraints( const FEMConstraintFunctor& F , const Coefficients& coefficients , DenseNodeData< Real , FEMDegree >& constraints , LocalDepth maxDepth ); - template< int FEMDegree1 , BoundaryType FEMBType1 , int FEMDegree2 , BoundaryType FEMBType2 , class DotFunctor , bool HasGradients , class Coefficients1 , class Coefficients2 > - double _dot( const DotFunctor& F , const InterpolationInfo< HasGradients >* iInfo , const Coefficients1& coefficients1 , const Coefficients2& coefficients2 ) const; -}; -template< class Real > int Octree< Real >::_NodeCount = 0; - - -template< class Real > void Reset( void ){ Octree< Real >::ResetNodeCount(); } - - -#include "MultiGridOctreeData.inl" -#include "MultiGridOctreeData.SortedTreeNodes.inl" -#include "MultiGridOctreeData.WeightedSamples.inl" -#include "MultiGridOctreeData.System.inl" -#include "MultiGridOctreeData.IsoSurface.inl" -#include "MultiGridOctreeData.Evaluation.inl" -#endif // MULTI_GRID_OCTREE_DATA_INCLUDED diff --git a/Src/MultiGridOctreeData.inl b/Src/MultiGridOctreeData.inl deleted file mode 100644 index 72195b9d..00000000 --- a/Src/MultiGridOctreeData.inl +++ /dev/null @@ -1,654 +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. -*/ -#ifdef FAST_SET_UP -#include -#endif // FAST_SET_UP -#include -#include "PointStream.h" - -#define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 -//#define MEMORY_ALLOCATOR_BLOCK_SIZE 0 - -const double MATRIX_ENTRY_EPSILON = 0; -const double EPSILON = 1e-6; -const double ROUND_EPS = 1e-5; - -////////////////// -// TreeNodeData // -////////////////// -TreeNodeData::TreeNodeData( void ){ flags = 0; } -TreeNodeData::~TreeNodeData( void ) { } - - -//////////// -// Octree // -//////////// -template< class Real > -double Octree< Real >::memoryUsage( void ) -{ - double mem = double( MemoryInfo::Usage() ) / (1<<20); - _maxMemoryUsage = std::max< double >( mem , _maxMemoryUsage ); - _localMemoryUsage = std::max< double >( mem , _localMemoryUsage ); - return mem; -} - -template< class Real > Octree< Real >::Octree( void ) : threads(1) , _maxMemoryUsage(0) , _localMemoryUsage(0) -{ - _tree = TreeOctNode::NewBrood( _NodeInitializer ); - _tree->initChildren( _NodeInitializer ) , _spaceRoot = _tree->children; - _depthOffset = 1; -} - -template< class Real > -template< int FEMDegree , BoundaryType BType > -void Octree< Real >::functionIndex( const TreeOctNode* node , int idx[3] ) const -{ - LocalDepth d ; LocalOffset off; - _localDepthAndOffset( node , d , off ); - for( int dd=0 ; dd::FunctionIndex( d , off[dd] ); -} - -template< class Real > -OctNode< TreeNodeData >* Octree< Real >::leaf( Point3D< Real > p ) -{ - if( !_InBounds( p ) ) return NULL; - Point3D< Real > center = Point3D< Real >( Real(0.5) , Real(0.5) , Real(0.5) ); - Real width = Real(1.0); - TreeOctNode* node = _spaceRoot; - while( node->children ) - { - int cIndex = TreeOctNode::CornerIndex( center , p ); - node = node->children + cIndex; - width /= 2; - if( cIndex&1 ) center[0] += width/2; - else center[0] -= width/2; - if( cIndex&2 ) center[1] += width/2; - else center[1] -= width/2; - if( cIndex&4 ) center[2] += width/2; - else center[2] -= width/2; - } - return node; -} -template< class Real > -const OctNode< TreeNodeData >* Octree< Real >::leaf( Point3D< Real > p ) const -{ - if( !_InBounds( p ) ) return NULL; - Point3D< Real > center = Point3D< Real >( Real(0.5) , Real(0.5) , Real(0.5) ); - Real width = Real(1.0); - TreeOctNode* node = _spaceRoot; - while( node->children ) - { - int cIndex = TreeOctNode::CornerIndex( center , p ); - node = node->children + cIndex; - width /= 2; - if( cIndex&1 ) center[0] += width/2; - else center[0] -= width/2; - if( cIndex&2 ) center[1] += width/2; - else center[1] -= width/2; - if( cIndex&4 ) center[2] += width/2; - else center[2] -= width/2; - } - return node; -} -template< class Real > bool Octree< Real >::_InBounds( Point3D< Real > p ){ return p[0]>=Real(0.) && p[0]<=Real(1.0) && p[1]>=Real(0.) && p[1]<=Real(1.0) && p[2]>=Real(0.) && p[2]<=Real(1.0); } -template< class Real > -template< int FEMDegree , BoundaryType BType > -bool Octree< Real >::isValidFEMNode( const TreeOctNode* node ) const -{ - if( GetGhostFlag( node ) ) return false; - LocalDepth d ; LocalOffset off; - _localDepthAndOffset( node , d , off ); - if( d<0 ) return false; - return !BSplineEvaluationData< FEMDegree , BType >::OutOfBounds( d , off[0] ) && !BSplineEvaluationData< FEMDegree , BType >::OutOfBounds( d , off[1] ) && !BSplineEvaluationData< FEMDegree , BType >::OutOfBounds( d , off[2] ); -} -template< class Real > -bool Octree< Real >::isValidSpaceNode( const TreeOctNode* node ) const -{ - if( !node ) return false; - LocalDepth d ; LocalOffset off; - _localDepthAndOffset( node , d , off ); - if( d<0 ) return false; - int res = 1<=0 && off[0]=0 && off[1]=0 && off[2] -template< int Degree , BoundaryType BType > -void Octree< Real >::_setFullDepth( TreeOctNode* node , LocalDepth depth ) const -{ - bool refine = false; - LocalDepth d ; LocalOffset off; - _localDepthAndOffset( node , d , off ); - if( d( node ) ) refine = true; - else if( !BSplineSupportSizes< Degree >::OutOfBounds( d , off[0] ) && !BSplineSupportSizes< Degree >::OutOfBounds( d , off[1] ) && !BSplineSupportSizes< Degree >::OutOfBounds( d , off[2] ) ) refine = true; - if( refine ) - { - if( !node->children ) node->initChildren( _NodeInitializer ); - for( int c=0 ; c( node->children+c , depth ); - } -} -template< class Real > -template< int Degree , BoundaryType BType > -void Octree< Real >::_setFullDepth( LocalDepth depth ) -{ - if( !_tree->children ) _tree->initChildren( _NodeInitializer ); - for( int c=0 ; c( _tree->children+c , depth ); -} - -template< class Real , bool HasGradients > -struct _PointDataAccumulator_ -{ -#if POINT_DATA_RES - static inline void _AddToPointData_( PointData< Real , HasGradients >& pData , Point3D< Real > position , Real value , Point3D< Real > gradient , Point3D< Real > center , Real width , Real weight ); -#else // !POINT_DATA_RES - static inline void _AddToPointData_( PointData< Real , HasGradients >& pData , Point3D< Real > position , Real value , Point3D< Real > gradient , Real weight ); -#endif // POINT_DATA_RES -}; -template< class Real > -struct _PointDataAccumulator_< Real , false > -{ -#if POINT_DATA_RES - static inline void _AddToPointData_( PointData< Real , false >& pData , Point3D< Real > position , Real value , Point3D< Real > gradient , Point3D< Real > center , Real width , Real weight ){ pData.addPoint( SinglePointData< Real , false >( position , value , weight ) , center , width ); } -#else // !POINT_DATA_RES - static inline void _AddToPointData_( PointData< Real , false >& pData , Point3D< Real > position , Real value , Point3D< Real > gradient , Real weight ){ pData.position += position , pData.value += value , pData.weight += weight; } -#endif // POINT_DATA_RES -}; -template< class Real > -struct _PointDataAccumulator_< Real , true > -{ -#if POINT_DATA_RES - static inline void _AddToPointData_( PointData< Real , true >& pData , Point3D< Real > position , Real value , Point3D< Real > gradient , Point3D< Real > center , Real width , Real weight ){ pData.addPoint( SinglePointData< Real , true >( position , value , gradient , weight ) , center , width ); } -#else // !POINT_DATA_RES - static inline void _AddToPointData_( PointData< Real , true >& pData , Point3D< Real > position , Real value , Point3D< Real > gradient , Real weight ){ pData.position += position , pData.value += value , pData.gradient += gradient , pData.weight += weight; } -#endif // POINT_DATA_RES -}; - -template< class Real > -void Octree< Real >::_init( TreeOctNode* node , LocalDepth maxDepth , bool (*Refine)( LocalDepth , LocalOffset ) ) -{ - if( _localDepth( node )initChildren( _NodeInitializer ); - for( int c=0 ; cchildren + c , maxDepth , Refine ); - } - } -} -template< class Real > void Octree< Real >::init( LocalDepth maxDepth , bool (*Refine)( LocalDepth , LocalOffset ) ){ _init( _spaceRoot , maxDepth , Refine ); } -template< class Real > -template< class Data > -int Octree< Real >::init( OrientedPointStream< Real >& pointStream , LocalDepth maxDepth , bool useConfidence , std::vector< PointSample >& samples , std::vector< ProjectiveData< Data , Real > >* sampleData ) -{ - OrientedPointStreamWithData< Real , Data >& pointStreamWithData = ( OrientedPointStreamWithData< Real , Data >& )pointStream; - - // Add the point data - int outOfBoundPoints = 0 , zeroLengthNormals = 0 , undefinedNormals = 0 , pointCount = 0; - { - std::vector< int > nodeToIndexMap; - Point3D< Real > p , n; - OrientedPoint3D< Real > _p; - Data _d; - while( ( sampleData ? pointStreamWithData.nextPoint( _p , _d ) : pointStream.nextPoint( _p ) ) ) - { - p = Point3D< Real >(_p.p) , n = Point3D< Real >(_p.n); - Real len = (Real)Length( n ); - if( !_InBounds(p) ){ outOfBoundPoints++ ; continue; } - if( !len ){ zeroLengthNormals++ ; continue; } - if( len!=len ){ undefinedNormals++ ; continue; } - n /= len; - Point3D< Real > center = Point3D< Real >( Real(0.5) , Real(0.5) , Real(0.5) ); - Real width = Real(1.0); - TreeOctNode* temp = _spaceRoot; - LocalDepth depth = _localDepth( temp ); - while( depthchildren ) temp->initChildren( _NodeInitializer ); - int cIndex = TreeOctNode::CornerIndex( center , p ); - temp = temp->children + cIndex; - width /= 2; - if( cIndex&1 ) center[0] += width/2; - else center[0] -= width/2; - if( cIndex&2 ) center[1] += width/2; - else center[1] -= width/2; - if( cIndex&4 ) center[2] += width/2; - else center[2] -= width/2; - depth++; - } - Real weight = (Real)( useConfidence ? len : 1. ); - int nodeIndex = temp->nodeData.nodeIndex; - if( nodeIndex>=nodeToIndexMap.size() ) nodeToIndexMap.resize( nodeIndex+1 , -1 ); - int idx = nodeToIndexMap[ nodeIndex ]; - if( idx==-1 ) - { - idx = (int)samples.size(); - nodeToIndexMap[ nodeIndex ] = idx; - samples.resize( idx+1 ) , samples[idx].node = temp; - if( sampleData ) sampleData->resize( idx+1 ); - } - samples[idx].sample += ProjectiveData< OrientedPoint3D< Real > , Real >( OrientedPoint3D< Real >( p * weight , n * weight ) , weight ); - if( sampleData ) (*sampleData)[ idx ] += ProjectiveData< Data , Real >( _d * weight , weight ); - pointCount++; - } - pointStream.reset(); - } - if( outOfBoundPoints ) fprintf( stderr , "[WARNING] Found out-of-bound points: %d\n" , outOfBoundPoints ); - if( zeroLengthNormals ) fprintf( stderr , "[WARNING] Found zero-length normals: %d\n" , zeroLengthNormals ); - if( undefinedNormals ) fprintf( stderr , "[WARNING] Found undefined normals: %d\n" , undefinedNormals ); - - memoryUsage(); - return pointCount; -} -template< class Real > -template< int DensityDegree > -typename Octree< Real >::template DensityEstimator< DensityDegree >* Octree< Real >::setDensityEstimator( const std::vector< PointSample >& samples , LocalDepth splatDepth , Real samplesPerNode ) -{ - LocalDepth maxDepth = _localMaxDepth( _tree ); - splatDepth = std::max< LocalDepth >( 0 , std::min< LocalDepth >( splatDepth , maxDepth ) ); - DensityEstimator< DensityDegree >* _density = new DensityEstimator< DensityDegree >( splatDepth ); - DensityEstimator< DensityDegree >& density = *_density; - PointSupportKey< DensityDegree > densityKey; - densityKey.set( _localToGlobal( splatDepth ) ); - -#ifdef FAST_SET_UP - std::vector< int > sampleMap( NodeCount() , -1 ); -#pragma omp parallel for num_threads( threads ) - for( int i=0 ; i0 ) sampleMap[ samples[i].node->nodeData.nodeIndex ] = i; - std::function< ProjectiveData< OrientedPoint3D< Real > , Real > ( TreeOctNode* ) > SetDensity = [&] ( TreeOctNode* node ) - { - ProjectiveData< OrientedPoint3D< Real > , Real > sample; - LocalDepth d = _localDepth( node ); - int idx = node->nodeData.nodeIndex; - if( node->children ) - for( int c=0 ; c , Real > s = SetDensity( node->children + c ); - if( d<=splatDepth && s.weight>0 ) - { - Point3D< Real > p = s.data.p / s.weight; - Real w = s.weight / samplesPerNode; - _addWeightContribution( density , node , p , densityKey , w ); - } - sample += s; - } - else if( idx0 ) - { - Point3D< Real > p = sample.data.p / sample.weight; - Real w = sample.weight / samplesPerNode; - _addWeightContribution( density , node , p , densityKey , w ); - } - } - return sample; - }; - SetDensity( _spaceRoot ); -#else // !FAST_SET_UP - for( int i=0 ; i , Real >& sample = samples[i].sample; - if( sample.weight>0 ) - { - Point3D< Real > p = sample.data.p / sample.weight; - Real w = sample.weight / samplesPerNode; - for( TreeOctNode* _node=(TreeOctNode*)node ; _node ; _node=_node->parent ) if( _localDepth( _node )<=splatDepth ) _addWeightContribution( density , _node , p , densityKey , w ); - } - } -#endif // FAST_SET_UP - - memoryUsage(); - return _density; -} -template< class Real > -template< int NormalDegree , int DensityDegree > -SparseNodeData< Point3D< Real > , NormalDegree > Octree< Real >::setNormalField( const std::vector< PointSample >& samples , const DensityEstimator< DensityDegree >& density , Real& pointWeightSum , bool forceNeumann ) -{ - LocalDepth maxDepth = _localMaxDepth( _tree ); - PointSupportKey< DensityDegree > densityKey; - PointSupportKey< NormalDegree > normalKey; - densityKey.set( _localToGlobal( maxDepth ) ) , normalKey.set( _localToGlobal( maxDepth ) ); - - Real weightSum = 0; - pointWeightSum = 0; - SparseNodeData< Point3D< Real > , NormalDegree > normalField; - for( int i=0 ; i , Real >& sample = samples[i].sample; - if( sample.weight>0 ) - { - Point3D< Real > p = sample.data.p / sample.weight , n = sample.data.n; - weightSum += sample.weight; - if( !_InBounds(p) ){ fprintf( stderr , "[WARNING] Octree:setNormalField: Point sample is out of bounds\n" ) ; continue; } - pointWeightSum += _splatPointData< true >( density , p , n , normalField , densityKey , normalKey , 0 , maxDepth , 3 ); - } - } - pointWeightSum /= weightSum; - memoryUsage(); - - return normalField; -} -template< class Real > -template< int DataDegree , bool CreateNodes , int DensityDegree , class Data > -SparseNodeData< ProjectiveData< Data , Real > , DataDegree > Octree< Real >::setDataField( const std::vector< PointSample >& samples , std::vector< ProjectiveData< Data , Real > >& sampleData , const DensityEstimator< DensityDegree >* density ) -{ - LocalDepth maxDepth = _localMaxDepth( _tree ); - PointSupportKey< DensityDegree > densityKey; - PointSupportKey< DataDegree > dataKey; - densityKey.set( _localToGlobal( maxDepth ) ) , dataKey.set( _localToGlobal( maxDepth ) ); - - SparseNodeData< ProjectiveData< Data , Real > , DataDegree > dataField; - for( int i=0 ; i , Real >& sample = samples[i].sample; - const ProjectiveData< Data , Real >& data = sampleData[i]; - Point3D< Real > p = sample.weight==0 ? sample.data.p : sample.data.p / sample.weight; - if( !_InBounds(p) ){ fprintf( stderr , "[WARNING] Point is out of bounds: %f %f %f <- %f %f %f [%f]\n" , p[0] , p[1] , p[2] , sample.data.p[0] , sample.data.p[1] , sample.data.p[2] , sample.weight ) ; continue; } - _multiSplatPointData< CreateNodes >( density , (TreeOctNode*)samples[i].node , p , data , dataField , densityKey , dataKey , 2 ); - } - memoryUsage(); - return dataField; -} -template< class Real > -template< int MaxDegree , int FEMDegree , BoundaryType FEMBType , class HasDataFunctor > -void Octree< Real >::inalizeForBroodedMultigrid( LocalDepth fullDepth , const HasDataFunctor& F , std::vector< int >* map ) -{ - if( FEMDegree>MaxDegree ) fprintf( stderr , "[ERROR] MaxDegree must be at least as large as the FEM degree: %d <= %d\n" , FEMDegree , MaxDegree ); - while( _localInset( 0 ) + BSplineEvaluationData< MaxDegree , BOUNDARY_FREE >::Begin( 0 )<0 || _localInset( 0 ) + BSplineEvaluationData< MaxDegree , BOUNDARY_FREE >::End( 0 )>(1<<_depthOffset) ) - { - // +-+-+-+-+-+-+-+-+ - // | | | | | | | | | - // +-+-+-+-+-+-+-+-+ - // | | | | | | | | | - // +-+-+-+-+ +-+-+-+-+-+-+-+-+ - // | | | | | | | | | | | | | | - // +-+-+ +-+-+-+-+ +-+-+-+-+-+-+-+-+ - // |*| | | | | | | | | | | | | | | | - // +-o-+ -> +-+-o-+-+ -> +-+-+-+-o-+-+-+-+ - // | | | | | |*| | | | | | |*| | | | - // +-+-+ +-+-+-+-+ +-+-+-+-+-+-+-+-+ - // | | | | | | | | | | | | | | - // +-+-+-+-+ +-+-+-+-+-+-+-+-+ - // | | | | | | | | | - // +-+-+-+-+-+-+-+-+ - // | | | | | | | | | - // +-+-+-+-+-+-+-+-+ - - TreeOctNode* newSpaceRootParent = TreeOctNode::NewBrood( _NodeInitializer ); - TreeOctNode* oldSpaceRootParent = _spaceRoot->parent; - int corner = _depthOffset<=1 ? Cube::CORNERS-1 : 0; - newSpaceRootParent[corner].children = _spaceRoot; - oldSpaceRootParent->children = newSpaceRootParent; - for( int c=0 ; c( 0 , std::min< LocalDepth >( _maxDepth , fullDepth ) ); - _setFullDepth< MaxDegree , BOUNDARY_FREE >( _fullDepth ); - // Clear all the flags and make everything that is not low-res a ghost node - for( TreeOctNode* node=_tree->nextNode() ; node ; node=_tree->nextNode( node ) ) node->nodeData.flags = 0 , SetGhostFlag( node , _localDepth( node )>_fullDepth ); - - // Set the ghost nodes for the high-res part of the tree - _clipTree( F ); - - const int OverlapRadius = -BSplineOverlapSizes< MaxDegree , MaxDegree >::OverlapStart; - typename TreeOctNode::NeighborKey< OverlapRadius , OverlapRadius > neighborKey; - neighborKey.set( _localToGlobal( _maxDepth-1 ) ); - - for( LocalDepth d=_maxDepth-1 ; d>=0 ; d-- ) - for( TreeOctNode* node=_tree->nextNode() ; node ; node=_tree->nextNode( node ) ) if( _localDepth( node )==d && IsActiveNode( node->children ) ) - { - neighborKey.template getNeighbors< true >( node , _NodeInitializer ); - for( int i=0 ; i(); - for( TreeOctNode* node=_tree->nextNode() ; node ; node=_tree->nextNode( node ) ) if( !IsActiveNode( node ) ) node->nodeData.nodeIndex = -1; - memoryUsage(); -} - - -template< class Real > -template< int FEMDegree , BoundaryType BType > -void Octree< Real >::_setValidityFlags( void ) -{ - for( int i=0 ; i<_sNodes.size() ; i++ ) - { - const unsigned char MASK = ~( TreeNodeData::SPACE_FLAG | TreeNodeData::FEM_FLAG ); - _sNodes.treeNodes[i]->nodeData.flags &= MASK; - if( isValidSpaceNode( _sNodes.treeNodes[i] ) ) _sNodes.treeNodes[i]->nodeData.flags |= TreeNodeData::SPACE_FLAG; - if( isValidFEMNode< FEMDegree , BType >( _sNodes.treeNodes[i] ) ) _sNodes.treeNodes[i]->nodeData.flags |= TreeNodeData::FEM_FLAG; - } -} - -// Trim off the branches of the tree (finer than _fullDepth) that don't contain data -template< class Real > -template< class HasDataFunctor > -void Octree< Real >::_clipTree( const HasDataFunctor& f ) -{ - // Because we are doing things in a brooded fashion, if any of the children has data then the whole brood is active - for( TreeOctNode* temp=_tree->nextNode() ; temp ; temp=_tree->nextNode(temp) ) if( temp->children && _localDepth( temp )>=_fullDepth ) - { - bool hasData = false; - for( int c=0 ; cchildren + c ); - for( int c=0 ; cchildren+c , !hasData ); - } -} - -template< class Real > -template< bool HasGradients > -bool Octree< Real >::_setInterpolationInfoFromChildren( TreeOctNode* node , SparseNodeData< PointData< Real , HasGradients > , 0 >& interpolationInfo ) const -{ - if( IsActiveNode( node->children ) ) - { - bool hasChildData = false; - PointData< Real , HasGradients > pData; -#if POINT_DATA_RES - Point3D< Real > center; - Real width; - _centerAndWidth( node , center , width ); - for( int c=0 ; cchildren + c , interpolationInfo ) ) - { - const PointData< Real , HasGradients >& _pData = interpolationInfo[ node->children + c ]; - for( int cc=0 ; cc::SAMPLES ; cc++ ) - { - int x[3]; - PointData< Real , HasGradients >::SetIndices( _pData[cc].position / _pData[cc].weight , center , width , x ); - pData[ x[0] + x[1]*PointData< Real , HasGradients >::RES + x[2]*PointData< Real , HasGradients >::RES*PointData< Real , HasGradients >::RES ] += _pData[cc]; - } - hasChildData = true; - } -#else // !POINT_DATA_RES - for( int c=0 ; cchildren + c , interpolationInfo ) ) - { - pData += interpolationInfo[ node->children + c ]; - hasChildData = true; - } -#endif // POINT_DATA_RES - if( hasChildData && IsActiveNode( node ) ) interpolationInfo[ node ] += pData; - return hasChildData; - } - else return interpolationInfo( node )!=NULL; -} -template< class Real > -template< bool HasGradients > -SparseNodeData< PointData< Real , HasGradients > , 0 > Octree< Real >::_densifyInterpolationInfo( const std::vector< PointSample >& samples , Real pointValue , int adaptiveExponent ) const -{ - SparseNodeData< PointData< Real , HasGradients > , 0 > iInfo; - for( int i=0 ; i , Real >& pData = samples[i].sample; - while( !IsActiveNode( node ) ) node = node->parent; - if( pData.weight ) - { -#if POINT_DATA_RES - Point3D< Real > center; - Real width; - _centerAndWidth( node , center , width ); - _PointDataAccumulator_< Real , HasGradients >::_AddToPointData_( iInfo[node] , pData.data.p , pointValue * pData.weight , pData.data.n , center , width , pData.weight ); -#else // !POINT_DATA_RES - _PointDataAccumulator_< Real , HasGradients >::_AddToPointData_( iInfo[node] , pData.data.p , pointValue * pData.weight , pData.data.n , pData.weight ); -#endif // POINT_DATA_RES - } - } - - // Set the interior values - _setInterpolationInfoFromChildren( _spaceRoot, iInfo ); -#pragma omp parallel for - for( int i=0 ; i<(int)iInfo.size() ; i++ ) -#if POINT_DATA_RES - for( int c=0 ; c::SAMPLES ; c++ ) - { - Real w = iInfo[i][c].weight; - iInfo[i][c] /= w ; iInfo[i][c].weight = w; - } -#else // !POINT_DATA_RES - { - Real w = iInfo[i].weight; - iInfo[i] /= w ; iInfo[i].weight = w; - } -#endif // POINT_DATA_RES - LocalDepth maxDepth = _localMaxDepth( _tree ); - - // Set the average position and scale the weights - for( const TreeOctNode* node=_tree->nextNode() ; node ; node=_tree->nextNode(node) ) if( IsActiveNode( node ) ) - { - PointData< Real , HasGradients >* pData = iInfo( node ); - if( pData ) - { - int e = _localDepth( node ) * adaptiveExponent - ( maxDepth ) * (adaptiveExponent-1); -#if POINT_DATA_RES - for( int c=0 ; c::SAMPLES ; c++ ) if( (*pData)[c].weight ) - { - if( e<0 ) (*pData)[c].weight /= Real( 1<<(-e) ); - else (*pData)[c].weight *= Real( 1<< e ); - } -#else // !POINT_DATA_RES - if( e<0 ) pData->weight /= Real( 1<<(-e) ); - else pData->weight *= Real( 1<< e ); -#endif // POINT_DATA_RES - } - } - return iInfo; -} -//////////////// -// VertexData // -//////////////// -long long VertexData::CenterIndex( const TreeOctNode* node , int maxDepth ) -{ - int idx[DIMENSION]; - return CenterIndex(node,maxDepth,idx); -} -long long VertexData::CenterIndex(const TreeOctNode* node,int maxDepth,int idx[DIMENSION]) -{ - int d , o[3]; - node->depthAndOffset( d , o ); - for( int i=0 ; idepthAndOffset( d , o ); - for( int i=0 ; idepthAndOffset(d,o); - for(int i=0;idepthAndOffset( d ,off ); - Cube::FactorEdgeIndex( eIndex , o , i1 , i2 ); - for( int i=0 ; i -#include -#ifndef WIN32 -#include -#endif // WIN32 - -inline double Time( void ) -{ -#ifdef WIN32 - struct _timeb t; - _ftime( &t ); - return double( t.time ) + double( t.millitm ) / 1000.0; -#else // WIN32 - struct timeval t; - gettimeofday( &t , NULL ); - return t.tv_sec + double( t.tv_usec ) / 1000000; -#endif // WIN32 -} - -#endif // MY_TIME_INCLUDED diff --git a/Src/Octree.h b/Src/Octree.h deleted file mode 100644 index 83733965..00000000 --- a/Src/Octree.h +++ /dev/null @@ -1,184 +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 OCT_NODE_INCLUDED -#define OCT_NODE_INCLUDED - -#define NEW_OCTNODE_CODE - -#include "Allocator.h" -#include "BinaryNode.h" -#include "MarchingCubes.h" - - -#define DIMENSION 3 - -template< class NodeData > -class OctNode -{ -private: - static int UseAlloc; - unsigned long long _depthAndOffset; - - const OctNode* __faceNeighbor( int dir , int off ) const; - const OctNode* __edgeNeighbor( int o , const int i[2] , const int idx[2] ) const; - OctNode* __faceNeighbor( int dir , int off , int forceChildren , void (*Initializer)( OctNode& ) ); - OctNode* __edgeNeighbor( int o , const int i[2] , const int idx[2] , int forceChildren , void (*Initializer)( OctNode& ) ); -public: - static const int DepthShift , OffsetShift , OffsetShift1 , OffsetShift2 , OffsetShift3; - static const int DepthMask , OffsetMask; - - static Allocator< OctNode > NodeAllocator; - static int UseAllocator( void ); - static void SetAllocator( int blockSize ); - - OctNode* parent; - OctNode* children; - NodeData nodeData; - - OctNode( void (*Initializer)( OctNode& )=NULL ); - static OctNode* NewBrood( void (*initializer)( OctNode& )=NULL ); - static void ResetDepthAndOffset( OctNode* root , int d , int off[3] ); - ~OctNode( void ); - int initChildren( void (*Initializer)( OctNode& )=NULL ); - - void depthAndOffset( int& depth , int offset[DIMENSION] ) const; - void centerIndex( int index[DIMENSION] ) const; - int depth( void ) const; - static inline void DepthAndOffset( const long long& index , int& depth , int offset[DIMENSION] ); - template< class Real > static inline void CenterAndWidth( const long long& index , Point3D< Real >& center , Real& width ); - template< class Real > static inline void StartAndWidth( const long long& index , Point3D< Real >& start , Real& width ); - static inline int Depth( const long long& index ); - static inline void Index( int depth , const int offset[3] , short& d , short off[DIMENSION] ); - static inline unsigned long long Index( int depth , const int offset[3] ); - template< class Real > void centerAndWidth( Point3D& center , Real& width ) const; - template< class Real > void startAndWidth( Point3D< Real >& start , Real& width ) const; - template< class Real > bool isInside( Point3D< Real > p ) const; - - size_t leaves( void ) const; - size_t maxDepthLeaves( int maxDepth ) const; - size_t nodes( void ) const; - int maxDepth( void ) const; - - const OctNode* root( void ) const; - - const OctNode* nextLeaf( const OctNode* currentLeaf=NULL ) const; - OctNode* nextLeaf( OctNode* currentLeaf=NULL ); - const OctNode* nextNode( const OctNode* currentNode=NULL ) const; - OctNode* nextNode( OctNode* currentNode=NULL ); - const OctNode* nextBranch( const OctNode* current ) const; - OctNode* nextBranch( OctNode* current ); - const OctNode* prevBranch( const OctNode* current ) const; - OctNode* prevBranch( OctNode* current ); - - void setFullDepth( int maxDepth , void (*Initializer)( OctNode& )=NULL ); - - void printLeaves( void ) const; - void printRange( void ) const; - - template< class Real > static int CornerIndex( const Point3D& center , const Point3D &p ); - - OctNode* faceNeighbor( int faceIndex , int forceChildren , void (*Initializer)( OctNode& )=NULL ); - const OctNode* faceNeighbor( int faceIndex ) const; - OctNode* edgeNeighbor( int edgeIndex , int forceChildren , void (*Initializer)( OctNode& )=NULL ); - const OctNode* edgeNeighbor( int edgeIndex ) const; - OctNode* cornerNeighbor( int cornerIndex , int forceChildren , void (*Initializer)( OctNode& )=NULL ); - const OctNode* cornerNeighbor( int cornerIndex ) const; - - int write( const char* fileName ) const; - int write( FILE* fp ) const; - int read( const char* fileName , void (*Initializer)( OctNode& )=NULL ); - int read( FILE* fp , void (*Initializer)( OctNode& )=NULL ); - - template< unsigned int Width > - struct Neighbors - { - OctNode* neighbors[Width][Width][Width]; - Neighbors( void ); - void clear( void ); - }; - template< unsigned int Width > - struct ConstNeighbors - { - const OctNode* neighbors[Width][Width][Width]; - ConstNeighbors( void ); - void clear( void ); - }; - - template< unsigned int LeftRadius , unsigned int RightRadius > - class NeighborKey - { - int _depth; - public: - template< int Width > using Neighbors = typename OctNode::template Neighbors< Width >; - static const int Width = LeftRadius + RightRadius + 1; - Neighbors< Width >* neighbors; - - NeighborKey( void ); - NeighborKey( const NeighborKey& key ); - ~NeighborKey( void ); - int depth( void ) const { return _depth; } - - void set( int depth ); - template< bool CreateNodes > typename OctNode< NodeData >::template Neighbors< LeftRadius+RightRadius+1 >& getNeighbors( OctNode* node , void (*Initializer)( OctNode& )=NULL ); - template< bool CreateNodes , unsigned int _LeftRadius , unsigned int _RightRadius > void getNeighbors( OctNode* node , Neighbors< _LeftRadius + _RightRadius + 1 >& neighbors , void (*Initializer)( OctNode& )=NULL ); - template< bool CreateNodes > bool getChildNeighbors( int cIdx , int d , Neighbors< Width >& childNeighbors , void (*Initializer)( OctNode& )=NULL ) const; - template< bool CreateNodes , class Real > bool getChildNeighbors( Point3D< Real > p , int d , Neighbors< Width >& childNeighbors , void (*Initializer)( OctNode& )=NULL ) const; - typename OctNode< NodeData >::template Neighbors< LeftRadius+RightRadius+1 >& getNeighbors( const OctNode* node ) { return getNeighbors< false >( (OctNode*)node , NULL ); } - template< unsigned int _LeftRadius , unsigned int _RightRadius > void getNeighbors( const OctNode* node , Neighbors< _LeftRadius + _RightRadius + 1 >& neighbors ){ return getNeighbors< false , _LeftRadius , _RightRadius >( (OctNode*)node , NULL ); } - bool getChildNeighbors( int cIdx , int d , Neighbors< Width >& childNeighbors ) const { return getChildNeighbors< false >( cIdx , d , childNeighbors , NULL ); } - template< class Real > bool getChildNeighbors( Point3D< Real > p , int d , Neighbors< Width >& childNeighbors ) const { return getChildNeighbors< false , Real >( p , d , childNeighbors , NULL ); } - }; - - template< unsigned int LeftRadius , unsigned int RightRadius > - class ConstNeighborKey - { - int _depth; - public: - template< int Width > using Neighbors = typename OctNode::template ConstNeighbors< Width >; - static const int Width = LeftRadius + RightRadius + 1; - ConstNeighbors< Width >* neighbors; - - ConstNeighborKey( void ); - ConstNeighborKey( const ConstNeighborKey& key ); - ~ConstNeighborKey( void ); - int depth( void ) const { return _depth; } - - void set( int depth ); - typename OctNode< NodeData >::template ConstNeighbors< LeftRadius+RightRadius+1 >& getNeighbors( const OctNode* node ); - template< unsigned int _LeftRadius , unsigned int _RightRadius > void getNeighbors( const OctNode* node , ConstNeighbors< _LeftRadius + _RightRadius + 1 >& neighbors ); - }; - - void centerIndex( int maxDepth , int index[DIMENSION] ) const; - int width( int maxDepth ) const; -}; - - -#include "Octree.inl" - -#endif // OCT_NODE_INCLUDED diff --git a/Src/Octree.inl b/Src/Octree.inl deleted file mode 100644 index 40202f97..00000000 --- a/Src/Octree.inl +++ /dev/null @@ -1,1135 +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 - -///////////// -// OctNode // -///////////// -template< class NodeData > const int OctNode< NodeData >::DepthShift=5; -template< class NodeData > const int OctNode< NodeData >::OffsetShift = ( sizeof(long long)*8 - DepthShift ) / 3; -template< class NodeData > const int OctNode< NodeData >::DepthMask=(1< const int OctNode< NodeData >::OffsetMask=(1< const int OctNode< NodeData >::OffsetShift1=DepthShift; -template< class NodeData > const int OctNode< NodeData >::OffsetShift2=OffsetShift1+OffsetShift; -template< class NodeData > const int OctNode< NodeData >::OffsetShift3=OffsetShift2+OffsetShift; - -template< class NodeData > int OctNode< NodeData >::UseAlloc=0; -template< class NodeData > Allocator > OctNode< NodeData >::NodeAllocator; - -template< class NodeData > -void OctNode< NodeData >::SetAllocator(int blockSize) -{ - if(blockSize>0) - { - UseAlloc=1; - NodeAllocator.set(blockSize); - } - else{UseAlloc=0;} -} -template< class NodeData > int OctNode< NodeData >::UseAllocator( void ){ return UseAlloc; } - -template< class NodeData > -OctNode< NodeData >::OctNode( void (*Initializer)( OctNode& ) ) -{ - parent = children = NULL; - _depthAndOffset = 0; - if( Initializer ) Initializer( *this ); -} -template< class NodeData > -OctNode< NodeData >::~OctNode( void ) -{ - if( !UseAlloc && children ) delete[] children; - parent = children = NULL; -} - -template< class NodeData > -OctNode< NodeData >* OctNode< NodeData >::NewBrood( void (*Initializer)( OctNode& ) ) -{ - OctNode< NodeData >* brood; - if( UseAlloc ) brood = NodeAllocator.newElements( Cube::CORNERS ); - else brood = new OctNode[Cube::CORNERS]; - for( int i=0 ; i<2 ; i++ ) for( int j=0 ; j<2 ; j++ ) for( int k=0 ; k<2 ; k++ ) - { - int off[] = { i , j , k }; - int idx = Cube::CornerIndex( i , j , k ); - if( Initializer ) Initializer( brood[idx] ); - brood[idx]._depthAndOffset = Index( 0 , off ); - } - return brood; -} -template< class NodeData > -void OctNode< NodeData >::ResetDepthAndOffset( OctNode* root , int d , int off[3] ) -{ - // Recursive lambda requires an explicit declaration -#define PARENT_DEPTH_AND_OFFSET( d , off ) ( d-- , off[0]>>=1 , off[1]>>=1 , off[2]>>=1 ) -#define CHILD_DEPTH_AND_OFFSET( d , off ) ( d++ , off[0]<<=1 , off[1]<<=1 , off[2]<<=1 ) - std::function< OctNode* ( OctNode* , int& , int[] ) > _nextBranch = [&]( OctNode* current , int& d , int off[3] ) - { - if( current==root ) return (OctNode*)NULL; - else - { - int c = (int)( current - current->parent->children ); - - if( c==Cube::CORNERS-1 ) - { - PARENT_DEPTH_AND_OFFSET( d , off ); - return _nextBranch( current->parent , d , off ); - } - else - { - int x , y , z; - Cube::FactorCornerIndex( c+1 , x , y , z ); - PARENT_DEPTH_AND_OFFSET( d , off ) ; CHILD_DEPTH_AND_OFFSET( d , off ); - off[0] |= x , off[1] |= y , off[2] |= z; - return current+1; - } - } - }; - auto _nextNode = [&]( OctNode* current , int& d , int off[3] ) - { - if( !current ) return root; - else if( current->children ) - { - CHILD_DEPTH_AND_OFFSET( d , off ); - return current->children; - } - else return _nextBranch( current , d , off ); - }; -#undef PARENT_DEPTH_AND_OFFSET -#undef CHILD_DEPTH_AND_OFFSET - for( OctNode* node=_nextNode( NULL , d , off ) ; node ; node = _nextNode( node , d , off ) ) node->_depthAndOffset = Index( d , off ); -} - -template< class NodeData > -void OctNode< NodeData >::setFullDepth( int maxDepth , void (*Initializer)( OctNode& ) ) -{ - if( maxDepth ) - { - if( !children ) initChildren( Initializer ); - for( int i=0 ; i<8 ; i++ ) children[i].setFullDepth( maxDepth-1 , Initializer ); - } -} - -template< class NodeData > -int OctNode< NodeData >::initChildren( void (*Initializer)( OctNode& ) ) -{ - { - if( UseAlloc ) children = NodeAllocator.newElements( Cube::CORNERS ); - else - { - if( children ) delete[] children; - children = new OctNode[Cube::CORNERS]; - } - if( !children ) fprintf( stderr , "[ERROR] OctNode::initChildren: Failed to initialize children in OctNode::initChildren\n" ) , exit(0); - int d , off[3]; - depthAndOffset( d , off ); - for( int i=0 ; i<2 ; i++ ) for( int j=0 ; j<2 ; j++ ) for( int k=0 ; k<2 ; k++ ) - { - int idx=Cube::CornerIndex(i,j,k); - children[idx].parent = this; - children[idx].children = NULL; - if( Initializer ) Initializer( children[idx] ); - int off2[3]; - off2[0] = (off[0]<<1)+i; - off2[1] = (off[1]<<1)+j; - off2[2] = (off[2]<<1)+k; - children[idx]._depthAndOffset = Index( d+1 , off2 ); - } - } - return 1; -} -template< class NodeData > -inline void OctNode< NodeData >::Index(int depth,const int offset[3],short& d,short off[3]){ - d=short(depth); - off[0]=short((1< -inline void OctNode< NodeData >::depthAndOffset( int& depth , int offset[DIMENSION] ) const -{ - depth = int( _depthAndOffset & DepthMask ); - offset[0] = int( (_depthAndOffset>>OffsetShift1) & OffsetMask ); - offset[1] = int( (_depthAndOffset>>OffsetShift2) & OffsetMask ); - offset[2] = int( (_depthAndOffset>>OffsetShift3) & OffsetMask ); -} -template< class NodeData > -inline void OctNode< NodeData >::centerIndex( int index[DIMENSION] ) const -{ - int d , off[DIMENSION]; - depthAndOffset( d , off ); - for( int i=0 ; i -inline unsigned long long OctNode< NodeData >::Index( int depth , const int offset[3] ) -{ - unsigned long long idx=0; - idx |= ( ( (unsigned long long)(depth ) ) & DepthMask ); - idx |= ( ( (unsigned long long)(offset[0]) ) & OffsetMask ) << OffsetShift1; - idx |= ( ( (unsigned long long)(offset[1]) ) & OffsetMask ) << OffsetShift2; - idx |= ( ( (unsigned long long)(offset[2]) ) & OffsetMask ) << OffsetShift3; - return idx; -} -template< class NodeData > -inline int OctNode< NodeData >::depth( void ) const {return int( _depthAndOffset & DepthMask );} -template< class NodeData > -inline void OctNode< NodeData >::DepthAndOffset(const long long& index,int& depth,int offset[3]){ - depth=int(index&DepthMask); - offset[0]=(int((index>>OffsetShift1)&OffsetMask)+1)&(~(1<>OffsetShift2)&OffsetMask)+1)&(~(1<>OffsetShift3)&OffsetMask)+1)&(~(1< -inline int OctNode< NodeData >::Depth(const long long& index){return int(index&DepthMask);} -template< class NodeData > -template< class Real > -void OctNode< NodeData >::centerAndWidth( Point3D& center , Real& width ) const -{ - int depth , offset[3]; - depthAndOffset( depth , offset ); - width = Real( 1.0 / (1< -template< class Real > -void OctNode< NodeData >::startAndWidth( Point3D& start , Real& width ) const -{ - int depth , offset[3]; - depthAndOffset( depth , offset ); - width = Real( 1.0 / (1< -template< class Real > -bool OctNode< NodeData >::isInside( Point3D< Real > p ) const -{ - Point3D< Real > c; - Real w; - centerAndWidth( c , w ); - w /= 2; - return (c[0]-w) -template< class Real > -inline void OctNode< NodeData >::CenterAndWidth(const long long& index,Point3D& center,Real& width){ - int depth,offset[3]; - depth=index&DepthMask; - offset[0]=(int((index>>OffsetShift1)&OffsetMask)+1)&(~(1<>OffsetShift2)&OffsetMask)+1)&(~(1<>OffsetShift3)&OffsetMask)+1)&(~(1< -template< class Real > -inline void OctNode< NodeData >::StartAndWidth( const long long& index , Point3D< Real >& start , Real& width ) -{ - int depth,offset[3]; - depth = index&DepthMask; - offset[0] = (int((index>>OffsetShift1)&OffsetMask)+1)&(~(1<>OffsetShift2)&OffsetMask)+1)&(~(1<>OffsetShift3)&OffsetMask)+1)&(~(1< -int OctNode< NodeData >::maxDepth(void) const{ - if(!children){return 0;} - else{ - int c,d; - for(int i=0;ic){c=d;} - } - return c+1; - } -} -template< class NodeData > -size_t OctNode< NodeData >::nodes( void ) const -{ - if( !children ) return 1; - else - { - size_t c=0; - for( int i=0 ; i -size_t OctNode< NodeData >::leaves( void ) const -{ - if( !children ) return 1; - else - { - size_t c=0; - for( int i=0 ; i -size_t OctNode< NodeData >::maxDepthLeaves( int maxDepth ) const -{ - if( depth()>maxDepth ) return 0; - if( !children ) return 1; - else - { - size_t c=0; - for( int i=0 ; i -const OctNode< NodeData >* OctNode< NodeData >::root(void) const{ - const OctNode* temp=this; - while(temp->parent){temp=temp->parent;} - return temp; -} - - -template< class NodeData > -const OctNode< NodeData >* OctNode< NodeData >::nextBranch( const OctNode* current ) const -{ - if( !current->parent || current==this ) return NULL; - if( current-current->parent->children==Cube::CORNERS-1 ) return nextBranch( current->parent ); - else return current+1; -} -template< class NodeData > -OctNode< NodeData >* OctNode< NodeData >::nextBranch(OctNode* current){ - if(!current->parent || current==this){return NULL;} - if(current-current->parent->children==Cube::CORNERS-1){return nextBranch(current->parent);} - else{return current+1;} -} -template< class NodeData > -const OctNode< NodeData >* OctNode< NodeData >::prevBranch( const OctNode* current ) const -{ - if( !current->parent || current==this ) return NULL; - if( current-current->parent->children==0 ) return prevBranch( current->parent ); - else return current-1; -} -template< class NodeData > -OctNode< NodeData >* OctNode< NodeData >::prevBranch( OctNode* current ) -{ - if( !current->parent || current==this ) return NULL; - if( current-current->parent->children==0 ) return prevBranch( current->parent ); - else return current-1; -} -template< class NodeData > -const OctNode< NodeData >* OctNode< NodeData >::nextLeaf(const OctNode* current) const{ - if( !current ) - { - const OctNode< NodeData >* temp=this; - while( temp->children ) temp=&temp->children[0]; - return temp; - } - if( current->children ) return current->nextLeaf(); - const OctNode* temp = nextBranch(current); - if( !temp ) return NULL; - else return temp->nextLeaf(); -} -template< class NodeData > -OctNode< NodeData >* OctNode< NodeData >::nextLeaf( OctNode* current ) -{ - if( !current ) - { - OctNode< NodeData >* temp=this; - while(temp->children){temp=&temp->children[0];} - return temp; - } - if(current->children){return current->nextLeaf();} - OctNode* temp=nextBranch(current); - if(!temp){return NULL;} - else{return temp->nextLeaf();} -} - -template< class NodeData > -const OctNode< NodeData >* OctNode< NodeData >::nextNode( const OctNode* current ) const -{ - if( !current ) return this; - else if( current->children ) return ¤t->children[0]; - else return nextBranch(current); -} -template< class NodeData > -OctNode< NodeData >* OctNode< NodeData >::nextNode( OctNode* current ) -{ - if( !current ) return this; - else if( current->children ) return ¤t->children[0]; - else return nextBranch( current ); -} - -template< class NodeData > -void OctNode< NodeData >::printRange(void) const -{ - Point3D< float > center; - float width; - centerAndWidth(center,width); - for(int dim=0;dim -template< class Real > -int OctNode< NodeData >::CornerIndex(const Point3D& center,const Point3D& p){ - int cIndex=0; - if(p.coords[0]>center.coords[0]){cIndex|=1;} - if(p.coords[1]>center.coords[1]){cIndex|=2;} - if(p.coords[2]>center.coords[2]){cIndex|=4;} - return cIndex; -} - -template< class NodeData > -OctNode< NodeData >* OctNode< NodeData >::faceNeighbor( int faceIndex , int forceChildren , void (*Initializer)( OctNode& ) ){return __faceNeighbor( faceIndex>>1 , faceIndex&1 , forceChildren , Initializer ); } -template< class NodeData > -const OctNode< NodeData >* OctNode< NodeData >::faceNeighbor(int faceIndex) const {return __faceNeighbor(faceIndex>>1,faceIndex&1);} -template< class NodeData > -OctNode< NodeData >* OctNode< NodeData >::__faceNeighbor( int dir , int off , int forceChildren , void (*Initializer)( OctNode& ) ) -{ - if(!parent){return NULL;} - int pIndex=int(this-parent->children); - pIndex^=(1<children[pIndex];} - else{ - OctNode* temp=parent->__faceNeighbor(dir,off,forceChildren); - if( !temp ) return NULL; - if( !temp->children ) - { - if( forceChildren ) temp->initChildren( Initializer ); - else return temp; - } - return &temp->children[pIndex]; - } -} -template< class NodeData > -const OctNode< NodeData >* OctNode< NodeData >::__faceNeighbor(int dir,int off) const { - if(!parent){return NULL;} - int pIndex=int(this-parent->children); - pIndex^=(1<children[pIndex];} - else{ - const OctNode* temp=parent->__faceNeighbor(dir,off); - if(!temp || !temp->children){return temp;} - else{return &temp->children[pIndex];} - } -} - -template< class NodeData > -OctNode< NodeData >* OctNode< NodeData >::edgeNeighbor( int edgeIndex , int forceChildren , void (*Initializer)( OctNode& ) ) -{ - int idx[2],o,i[2]; - Cube::FactorEdgeIndex( edgeIndex , o , i[0] , i[1] ); - switch(o){ - case 0: idx[0]=1; idx[1]=2; break; - case 1: idx[0]=0; idx[1]=2; break; - case 2: idx[0]=0; idx[1]=1; break; - }; - return __edgeNeighbor( o , i , idx , forceChildren , Initializer ); -} -template< class NodeData > -const OctNode< NodeData >* OctNode< NodeData >::edgeNeighbor(int edgeIndex) const { - int idx[2],o,i[2]; - Cube::FactorEdgeIndex(edgeIndex,o,i[0],i[1]); - switch(o){ - case 0: idx[0]=1; idx[1]=2; break; - case 1: idx[0]=0; idx[1]=2; break; - case 2: idx[0]=0; idx[1]=1; break; - }; - return __edgeNeighbor(o,i,idx); -} -template< class NodeData > -const OctNode< NodeData >* OctNode< NodeData >::__edgeNeighbor(int o,const int i[2],const int idx[2]) const{ - if(!parent){return NULL;} - int pIndex=int(this-parent->children); - int aIndex,x[DIMENSION]; - - Cube::FactorCornerIndex(pIndex,x[0],x[1],x[2]); - aIndex=(~((i[0] ^ x[idx[0]]) | ((i[1] ^ x[idx[1]])<<1))) & 3; - pIndex^=(7 ^ (1<__faceNeighbor(idx[0],i[0]); - if(!temp || !temp->children){return NULL;} - else{return &temp->children[pIndex];} - } - else if(aIndex==2) { // I can get the neighbor from the parent's face adjacent neighbor - const OctNode* temp=parent->__faceNeighbor(idx[1],i[1]); - if(!temp || !temp->children){return NULL;} - else{return &temp->children[pIndex];} - } - else if(aIndex==0) { // I can get the neighbor from the parent - return &parent->children[pIndex]; - } - else if(aIndex==3) { // I can get the neighbor from the parent's edge adjacent neighbor - const OctNode* temp=parent->__edgeNeighbor(o,i,idx); - if(!temp || !temp->children){return temp;} - else{return &temp->children[pIndex];} - } - else{return NULL;} -} -template< class NodeData > -OctNode< NodeData >* OctNode< NodeData >::__edgeNeighbor( int o , const int i[2] , const int idx[2] , int forceChildren , void (*Initializer)( OctNode& ) ) -{ - if(!parent){return NULL;} - int pIndex=int(this-parent->children); - int aIndex,x[DIMENSION]; - - Cube::FactorCornerIndex(pIndex,x[0],x[1],x[2]); - aIndex=(~((i[0] ^ x[idx[0]]) | ((i[1] ^ x[idx[1]])<<1))) & 3; - pIndex^=(7 ^ (1<__faceNeighbor(idx[0],i[0],0); - if(!temp || !temp->children){return NULL;} - else{return &temp->children[pIndex];} - } - else if(aIndex==2) { // I can get the neighbor from the parent's face adjacent neighbor - OctNode* temp=parent->__faceNeighbor(idx[1],i[1],0); - if(!temp || !temp->children){return NULL;} - else{return &temp->children[pIndex];} - } - else if(aIndex==0) { // I can get the neighbor from the parent - return &parent->children[pIndex]; - } - else if(aIndex==3) { // I can get the neighbor from the parent's edge adjacent neighbor - OctNode* temp=parent->__edgeNeighbor(o,i,idx,forceChildren); - if( !temp ) return NULL; - if( !temp->children ) - { - if( forceChildren ) temp->initChildren( Initializer ); - else return temp; - } - return &temp->children[pIndex]; - } - else{return NULL;} -} - -template< class NodeData > -const OctNode< NodeData >* OctNode< NodeData >::cornerNeighbor(int cornerIndex) const { - int pIndex,aIndex=0; - if(!parent){return NULL;} - - pIndex=int(this-parent->children); - aIndex=(cornerIndex ^ pIndex); // The disagreement bits - pIndex=(~pIndex)&7; // The antipodal point - if(aIndex==7){ // Agree on no bits - return &parent->children[pIndex]; - } - else if(aIndex==0){ // Agree on all bits - const OctNode* temp=((const OctNode*)parent)->cornerNeighbor(cornerIndex); - if(!temp || !temp->children){return temp;} - else{return &temp->children[pIndex];} - } - else if(aIndex==6){ // Agree on face 0 - const OctNode* temp=((const OctNode*)parent)->__faceNeighbor(0,cornerIndex & 1); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==5){ // Agree on face 1 - const OctNode* temp=((const OctNode*)parent)->__faceNeighbor(1,(cornerIndex & 2)>>1); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==3){ // Agree on face 2 - const OctNode* temp=((const OctNode*)parent)->__faceNeighbor(2,(cornerIndex & 4)>>2); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==4){ // Agree on edge 2 - const OctNode* temp=((const OctNode*)parent)->edgeNeighbor(8 | (cornerIndex & 1) | (cornerIndex & 2) ); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==2){ // Agree on edge 1 - const OctNode* temp=((const OctNode*)parent)->edgeNeighbor(4 | (cornerIndex & 1) | ((cornerIndex & 4)>>1) ); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==1){ // Agree on edge 0 - const OctNode* temp=((const OctNode*)parent)->edgeNeighbor(((cornerIndex & 2) | (cornerIndex & 4))>>1 ); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else{return NULL;} -} -template< class NodeData > -OctNode< NodeData >* OctNode< NodeData >::cornerNeighbor( int cornerIndex , int forceChildren , void (*Initializer)( OctNode& ) ) -{ - int pIndex,aIndex=0; - if(!parent){return NULL;} - - pIndex=int(this-parent->children); - aIndex=(cornerIndex ^ pIndex); // The disagreement bits - pIndex=(~pIndex)&7; // The antipodal point - if(aIndex==7){ // Agree on no bits - return &parent->children[pIndex]; - } - else if(aIndex==0){ // Agree on all bits - OctNode* temp=((OctNode*)parent)->cornerNeighbor( cornerIndex , forceChildren , Initializer ); - if( !temp ) return NULL; - if( !temp->children ) - { - if(forceChildren) temp->initChildren( Initializer ); - else return temp; - } - return &temp->children[pIndex]; - } - else if(aIndex==6){ // Agree on face 0 - OctNode* temp=((OctNode*)parent)->__faceNeighbor(0,cornerIndex & 1,0); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==5){ // Agree on face 1 - OctNode* temp=((OctNode*)parent)->__faceNeighbor(1,(cornerIndex & 2)>>1,0); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==3){ // Agree on face 2 - OctNode* temp=((OctNode*)parent)->__faceNeighbor(2,(cornerIndex & 4)>>2,0); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==4){ // Agree on edge 2 - OctNode* temp=((OctNode*)parent)->edgeNeighbor(8 | (cornerIndex & 1) | (cornerIndex & 2) ); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==2){ // Agree on edge 1 - OctNode* temp=((OctNode*)parent)->edgeNeighbor(4 | (cornerIndex & 1) | ((cornerIndex & 4)>>1) ); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==1){ // Agree on edge 0 - OctNode* temp=((OctNode*)parent)->edgeNeighbor(((cornerIndex & 2) | (cornerIndex & 4))>>1 ); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else{return NULL;} -} - -//////////////////////// -// OctNode::Neighbors // -//////////////////////// -template< class NodeData > -template< unsigned int Width > -OctNode< NodeData >::Neighbors< Width >::Neighbors( void ){ clear(); } -template< class NodeData > -template< unsigned int Width > -void OctNode< NodeData >::Neighbors< Width >::clear( void ){ for( int i=0 ; i -template< unsigned int Width > -OctNode< NodeData >::ConstNeighbors< Width >::ConstNeighbors( void ){ clear(); } -template< class NodeData > -template< unsigned int Width > -void OctNode< NodeData >::ConstNeighbors< Width >::clear( void ){ for( int i=0 ; i -template< unsigned int LeftRadius , unsigned int RightRadius > -OctNode< NodeData >::NeighborKey< LeftRadius , RightRadius >::NeighborKey( void ){ _depth=-1 , neighbors=NULL; } -template< class NodeData > -template< unsigned int LeftRadius , unsigned int RightRadius > -OctNode< NodeData >::NeighborKey< LeftRadius , RightRadius >::NeighborKey( const NeighborKey& nKey ) -{ - _depth = 0 , neighbors = NULL; - set( nKey._depth ); - for( int d=0 ; d<=_depth ; d++ ) memcpy( &neighbors[d] , &nKey.neighbors[d] , sizeof( Neighbors< Width > ) ); -} -template< class NodeData > -template< unsigned int LeftRadius , unsigned int RightRadius > -OctNode< NodeData >::NeighborKey< LeftRadius , RightRadius >::~NeighborKey( void ) -{ - if( neighbors ) delete[] neighbors; - neighbors = NULL; -} - -template< class NodeData > -template< unsigned int LeftRadius , unsigned int RightRadius > -void OctNode< NodeData >::NeighborKey< LeftRadius , RightRadius >::set( int d ) -{ - if( neighbors ) delete[] neighbors; - neighbors = NULL; - _depth = d; - if( d<0 ) return; - neighbors = new Neighbors< Width >[d+1]; -} -template< class NodeData > -template< unsigned int LeftRadius , unsigned int RightRadius > -template< bool CreateNodes > -bool OctNode< NodeData >::NeighborKey< LeftRadius , RightRadius >::getChildNeighbors( int cIdx , int d , Neighbors< Width >& cNeighbors , void (*Initializer)( OctNode& ) ) const -{ - Neighbors< Width >& pNeighbors = neighbors[d]; - // Check that we actuall have a center node - if( !pNeighbors.neighbors[LeftRadius][LeftRadius][LeftRadius] ) return false; - - // Get the indices of the child node that would contain the point (and its antipode) - int cx , cy , cz; - Cube::FactorCornerIndex( cIdx , cx , cy , cz ); - - - // Iterate over the finer neighbors and set them (if you can) - // Here: - // (x,y,z) give the position of the finer nodes relative to the center, - // (_x,_y,_z) give a positive global position, up to an even offset, and - // (px-LeftRadius,py-LeftRadius,pz-LeftRadius) give the positions of their parents relative to the parent of the center - for( int z=-(int)LeftRadius ; z<=(int)RightRadius ; z++ ) - { - int _z = (z+cz) + (LeftRadius<<1) , pz = ( _z>>1 ) , zz = z+LeftRadius; - for( int y=-(int)LeftRadius ; y<=(int)RightRadius ; y++ ) - { - int _y = (y+cy) + (LeftRadius<<1) , py = ( _y>>1 ) , yy = y+LeftRadius; - - int cornerIndex = ( (_z&1)<<2 ) | ( (_y&1)<<1 ); - for( int x=-(int)LeftRadius ; x<=(int)RightRadius ; x++ ) - { - int _x = (x+cx) + (LeftRadius<<1) , px = ( _x>>1 ) , xx = x+LeftRadius; - - if( CreateNodes ) - { - if( pNeighbors.neighbors[px][py][pz] ) - { - if( !pNeighbors.neighbors[px][py][pz]->children ) pNeighbors.neighbors[px][py][pz]->initChildren( Initializer ); - cNeighbors.neighbors[xx][yy][zz] = pNeighbors.neighbors[px][py][pz]->children + ( cornerIndex | (_x&1) ); - } - else cNeighbors.neighbors[xx][yy][zz] = NULL; - } - else - { - if( pNeighbors.neighbors[px][py][pz] && pNeighbors.neighbors[px][py][pz]->children ) - cNeighbors.neighbors[xx][yy][zz] = pNeighbors.neighbors[px][py][pz]->children + ( cornerIndex | (_x&1) ); - else cNeighbors.neighbors[xx][yy][zz] = NULL; - } - } - } - } - return true; -} -template< class NodeData > -template< unsigned int LeftRadius , unsigned int RightRadius > -template< bool CreateNodes , class Real > -bool OctNode< NodeData >::NeighborKey< LeftRadius , RightRadius >::getChildNeighbors( Point3D< Real > p , int d , Neighbors< Width >& cNeighbors , void (*Initializer)( OctNode& ) ) const -{ - Neighbors< Width >& pNeighbors = neighbors[d]; - // Check that we actuall have a center node - if( !pNeighbors.neighbors[LeftRadius][LeftRadius][LeftRadius] ) return false; - Point3D< Real > c; - Real w; - pNeighbors.neighbors[LeftRadius][LeftRadius][LeftRadius]->centerAndWidth( c , w ); - return getChildNeighbors< CreateNodes >( CornerIndex( c , p ) , d , cNeighbors , Initializer ); -} - -template< class NodeData > -template< unsigned int LeftRadius , unsigned int RightRadius > -template< bool CreateNodes > -typename OctNode< NodeData >::template Neighbors< LeftRadius+RightRadius+1 >& OctNode< NodeData >::NeighborKey< LeftRadius , RightRadius >::getNeighbors( OctNode< NodeData >* node , void (*Initializer)( OctNode& ) ) -{ - Neighbors< Width >& neighbors = this->neighbors[ node->depth() ]; - if( node==neighbors.neighbors[LeftRadius][LeftRadius][LeftRadius] ) - { - bool reset = false; - for( int i=0 ; iparent ) neighbors.neighbors[LeftRadius][LeftRadius][LeftRadius] = node; - else - { - Neighbors< Width >& pNeighbors = getNeighbors< CreateNodes >( node->parent , Initializer ); - - // Get the indices of the child node that would contain the point (and its antipode) - int cx , cy , cz; - Cube::FactorCornerIndex( (int)( node - node->parent->children ) , cx , cy , cz ); - - - // Iterate over the finer neighbors and set them (if you can) - // Here: - // (x,y,z) give the position of the finer nodes relative to the center, - // (_x,_y,_z) give a positive global position, up to an even offset, and - // (px-LeftRadius,py-LeftRadius,pz-LeftRadius) give the positions of their parents relative to the parent of the center - for( int z=-(int)LeftRadius ; z<=(int)RightRadius ; z++ ) - { - int _z = (z+cz) + (LeftRadius<<1) , pz = ( _z>>1 ) , zz = z+LeftRadius; - for( int y=-(int)LeftRadius ; y<=(int)RightRadius ; y++ ) - { - int _y = (y+cy) + (LeftRadius<<1) , py = ( _y>>1 ) , yy = y+LeftRadius; - - int cornerIndex = ( (_z&1)<<2 ) | ( (_y&1)<<1 ); - for( int x=-(int)LeftRadius ; x<=(int)RightRadius ; x++ ) - { - int _x = (x+cx) + (LeftRadius<<1) , px = ( _x>>1 ) , xx = x+LeftRadius; - if( CreateNodes ) - { - if( pNeighbors.neighbors[px][py][pz] ) - { - if( !pNeighbors.neighbors[px][py][pz]->children ) pNeighbors.neighbors[px][py][pz]->initChildren( Initializer ); - neighbors.neighbors[xx][yy][zz] = pNeighbors.neighbors[px][py][pz]->children + ( cornerIndex | (_x&1) ); - } - else neighbors.neighbors[xx][yy][zz] = NULL; - } - else - { - if( pNeighbors.neighbors[px][py][pz] && pNeighbors.neighbors[px][py][pz]->children ) - neighbors.neighbors[xx][yy][zz] = pNeighbors.neighbors[px][py][pz]->children + ( cornerIndex | (_x&1) ); - else neighbors.neighbors[xx][yy][zz] = NULL; - } - } - } - } - } - } - return neighbors; -} -template< class NodeData > -template< unsigned int LeftRadius , unsigned int RightRadius > -template< bool CreateNodes , unsigned int _LeftRadius , unsigned int _RightRadius > -void OctNode< NodeData >::NeighborKey< LeftRadius , RightRadius >::getNeighbors( OctNode< NodeData >* node , Neighbors< _LeftRadius + _RightRadius + 1 >& neighbors , void (*Initializer)( OctNode& ) ) -{ - neighbors.clear(); - if( !node ) return; - - // [WARNING] This estimate of the required radius is somewhat conservative if the radius is odd (depending on where the node is relative to its parent) - const unsigned int _PLeftRadius = (_LeftRadius+1)/2 , _PRightRadius = (_RightRadius+1)/2; - // If we are at the root of the tree, we are done - if( !node->parent ) neighbors.neighbors[_LeftRadius][_LeftRadius][_LeftRadius] = node; - // If we can get the data from the the key for the parent node, do that - else if( _PLeftRadius<=LeftRadius && _PRightRadius<=RightRadius ) - { - getNeighbors< CreateNodes >( node->parent , Initializer ); - const Neighbors< LeftRadius + RightRadius + 1 >& pNeighbors = this->neighbors[ node->depth()-1 ]; - // Get the indices of the child node that would contain the point (and its antipode) - int cx , cy , cz; - Cube::FactorCornerIndex( (int)( node - node->parent->children ) , cx , cy , cz ); - - - // Iterate over the finer neighbors - // Here: - // (x,y,z) give the position of the finer nodes relative to the center, - // (_x,_y,_z) give a positive global position, up to an even offset, and - // (px-LeftRadius,py-LeftRadius,pz-LeftRadius) give the positions of their parents relative to the parent of the center - for( int z=-(int)_LeftRadius ; z<=(int)_RightRadius ; z++ ) - { - int _z = (z+cz) + (_LeftRadius<<1) , pz = ( _z>>1 ) - _LeftRadius + LeftRadius , zz = z + _LeftRadius; - for( int y=-(int)_LeftRadius ; y<=(int)_RightRadius ; y++ ) - { - int _y = (y+cy) + (_LeftRadius<<1) , py = ( _y>>1 ) - _LeftRadius + LeftRadius , yy = y + _LeftRadius; - - int cornerIndex = ( (_z&1)<<2 ) | ( (_y&1)<<1 ); - for( int x=-(int)_LeftRadius ; x<=(int)_RightRadius ; x++ ) - { - int _x = (x+cx) + (_LeftRadius<<1) , px = ( _x>>1 ) - _LeftRadius + LeftRadius , xx = x + _LeftRadius; - if( CreateNodes ) - { - if( pNeighbors.neighbors[px][py][pz] ) - { - if( !pNeighbors.neighbors[px][py][pz]->children ) pNeighbors.neighbors[px][py][pz]->initChildren( Initializer ); - neighbors.neighbors[xx][yy][zz] = pNeighbors.neighbors[px][py][pz]->children + ( cornerIndex | (_x&1) ); - } - else neighbors.neighbors[xx][yy][zz] = NULL; - } - else - { - if( pNeighbors.neighbors[px][py][pz] && pNeighbors.neighbors[px][py][pz]->children ) - neighbors.neighbors[xx][yy][zz] = pNeighbors.neighbors[px][py][pz]->children + ( cornerIndex | (_x&1) ); - else neighbors.neighbors[xx][yy][zz] = NULL; - } - } - } - } - } - // Otherwise recurse - else - { - Neighbors< _PLeftRadius + _PRightRadius + 1 > pNeighbors; - getNeighbors< CreateNodes , _PLeftRadius , _PRightRadius >( node->parent , pNeighbors , Initializer ); - - // Get the indices of the child node that would contain the point (and its antipode) - int cx , cy , cz; - Cube::FactorCornerIndex( (int)( node - node->parent->children ) , cx , cy , cz ); - - - // Iterate over the finer neighbors - // Here: - // (x,y,z) give the position of the finer nodes relative to the center, - // (_x,_y,_z) give a positive global position, up to an even offset, and - // (px-LeftRadius,py-LeftRadius,pz-LeftRadius) give the positions of their parents relative to the parent of the center - for( int z=-(int)_LeftRadius ; z<=(int)_RightRadius ; z++ ) - { - int _z = (z+cz) + (_LeftRadius<<1) , pz = ( _z>>1 ) - _LeftRadius + _PLeftRadius , zz = z + _LeftRadius; - for( int y=-(int)_LeftRadius ; y<=(int)_RightRadius ; y++ ) - { - int _y = (y+cy) + (_LeftRadius<<1) , py = ( _y>>1 ) - _LeftRadius + _PLeftRadius , yy = y + _LeftRadius; - - int cornerIndex = ( (_z&1)<<2 ) | ( (_y&1)<<1 ); - for( int x=-(int)_LeftRadius ; x<=(int)_RightRadius ; x++ ) - { - int _x = (x+cx) + (_LeftRadius<<1) , px = ( _x>>1 ) - _LeftRadius + _PLeftRadius , xx = x + _LeftRadius; - if( CreateNodes ) - { - if( pNeighbors.neighbors[px][py][pz] ) - { - if( !pNeighbors.neighbors[px][py][pz]->children ) pNeighbors.neighbors[px][py][pz]->initChildren( Initializer ); - neighbors.neighbors[xx][yy][zz] = pNeighbors.neighbors[px][py][pz]->children + ( cornerIndex | (_x&1) ); - } - else neighbors.neighbors[xx][yy][zz] = NULL; - } - else - { - if( pNeighbors.neighbors[px][py][pz] && pNeighbors.neighbors[px][py][pz]->children ) - neighbors.neighbors[xx][yy][zz] = pNeighbors.neighbors[px][py][pz]->children + ( cornerIndex | (_x&1) ); - else neighbors.neighbors[xx][yy][zz] = NULL; - } - } - } - } - } -} - -/////////////////////////////// -// OctNode::ConstNeighborKey // -/////////////////////////////// -template< class NodeData > -template< unsigned int LeftRadius , unsigned int RightRadius > -OctNode< NodeData >::ConstNeighborKey< LeftRadius , RightRadius >::ConstNeighborKey( void ){ _depth=-1 , neighbors=NULL; } -template< class NodeData > -template< unsigned int LeftRadius , unsigned int RightRadius > -OctNode< NodeData >::ConstNeighborKey< LeftRadius , RightRadius >::ConstNeighborKey( const ConstNeighborKey& key ) -{ - _depth = 0 , neighbors = NULL; - set( key._depth ); - for( int d=0 ; d<=_depth ; d++ ) memcpy( &neighbors[d] , &key.neighbors[d] , sizeof( ConstNeighbors< Width > ) ); -} -template< class NodeData > -template< unsigned int LeftRadius , unsigned int RightRadius > -OctNode< NodeData >::ConstNeighborKey< LeftRadius , RightRadius >::~ConstNeighborKey( void ) -{ - if( neighbors ) delete[] neighbors; - neighbors=NULL; -} - -template< class NodeData > -template< unsigned int LeftRadius , unsigned int RightRadius > -void OctNode< NodeData >::ConstNeighborKey< LeftRadius , RightRadius >::set( int d ) -{ - if( neighbors ) delete[] neighbors; - neighbors = NULL; - _depth = d; - if( d<0 ) return; - neighbors = new ConstNeighbors< Width >[d+1]; -} -template< class NodeData > -template< unsigned int LeftRadius , unsigned int RightRadius > -typename OctNode< NodeData >::template ConstNeighbors< LeftRadius+RightRadius+1 >& OctNode< NodeData >::ConstNeighborKey< LeftRadius , RightRadius >::getNeighbors( const OctNode< NodeData >* node ) -{ - ConstNeighbors< Width >& neighbors = this->neighbors[ node->depth() ]; - if( node!=neighbors.neighbors[LeftRadius][LeftRadius][LeftRadius]) - { - neighbors.clear(); - - if( !node->parent ) neighbors.neighbors[LeftRadius][LeftRadius][LeftRadius] = node; - else - { - ConstNeighbors< Width >& pNeighbors = getNeighbors( node->parent ); - - // Get the indices of the child node that would contain the point (and its antipode) - int cx , cy , cz; - Cube::FactorCornerIndex( (int)( node - node->parent->children ) , cx , cy , cz ); - - - // Iterate over the finer neighbors and set them (if you can) - // Here: - // (x,y,z) give the position of the finer nodes relative to the center, - // (_x,_y,_z) give a positive global position, up to an even offset, and - // (px-LeftRadius,py-LeftRadius,pz-LeftRadius) give the positions of their parents relative to the parent of the center - for( int z=-(int)LeftRadius ; z<=(int)RightRadius ; z++ ) - { - int _z = (z+cz) + (LeftRadius<<1) , pz = ( _z>>1 ) , zz = z+LeftRadius; - for( int y=-(int)LeftRadius ; y<=(int)RightRadius ; y++ ) - { - int _y = (y+cy) + (LeftRadius<<1) , py = ( _y>>1 ) , yy = y+LeftRadius; - - int cornerIndex = ( (_z&1)<<2 ) | ( (_y&1)<<1 ); - for( int x=-(int)LeftRadius ; x<=(int)RightRadius ; x++ ) - { - int _x = (x+cx) + (LeftRadius<<1) , px = ( _x>>1 ) , xx = x+LeftRadius; - if( pNeighbors.neighbors[px][py][pz] && pNeighbors.neighbors[px][py][pz]->children ) - neighbors.neighbors[xx][yy][zz] = pNeighbors.neighbors[px][py][pz]->children + ( cornerIndex | (_x&1) ); - else - neighbors.neighbors[xx][yy][zz] = NULL; - } - } - } - } - } - return neighbors; -} -template< class NodeData > -template< unsigned int LeftRadius , unsigned int RightRadius > -template< unsigned int _LeftRadius , unsigned int _RightRadius > -void OctNode< NodeData >::ConstNeighborKey< LeftRadius , RightRadius >::getNeighbors( const OctNode< NodeData >* node , ConstNeighbors< _LeftRadius+_RightRadius+1 >& neighbors ) -{ - neighbors.clear(); - if( !node ) return; - - // [WARNING] This estimate of the required radius is somewhat conservative if the readius is odd (depending on where the node is relative to its parent) - const unsigned int _PLeftRadius = (_LeftRadius+1)/2 , _PRightRadius = (_RightRadius+1)/2; - // If we are at the root of the tree, we are done - if( !node->parent ) neighbors.neighbors[_LeftRadius][_LeftRadius][_LeftRadius] = node; - // If we can get the data from the the key for the parent node, do that - else if( _PLeftRadius<=LeftRadius && _PRightRadius<=RightRadius ) - { - getNeighbors( node->parent ); - const ConstNeighbors< LeftRadius + RightRadius + 1 >& pNeighbors = this->neighbors[ node->depth()-1 ]; - // Get the indices of the child node that would contain the point (and its antipode) - int cx , cy , cz; - Cube::FactorCornerIndex( (int)( node - node->parent->children ) , cx , cy , cz ); - - - // Iterate over the finer neighbors - // Here: - // (x,y,z) give the position of the finer nodes relative to the center, - // (_x,_y,_z) give a positive global position, up to an even offset, and - // (px-LeftRadius,py-LeftRadius,pz-LeftRadius) give the positions of their parents relative to the parent of the center - for( int z=-(int)_LeftRadius ; z<=(int)_RightRadius ; z++ ) - { - int _z = (z+cz) + (_LeftRadius<<1) , pz = ( _z>>1 ) - _LeftRadius + LeftRadius , zz = z + _LeftRadius; - for( int y=-(int)_LeftRadius ; y<=(int)_RightRadius ; y++ ) - { - int _y = (y+cy) + (_LeftRadius<<1) , py = ( _y>>1 ) - _LeftRadius + LeftRadius , yy = y + _LeftRadius; - - int cornerIndex = ( (_z&1)<<2 ) | ( (_y&1)<<1 ); - for( int x=-(int)_LeftRadius ; x<=(int)_RightRadius ; x++ ) - { - int _x = (x+cx) + (_LeftRadius<<1) , px = ( _x>>1 ) - _LeftRadius + LeftRadius , xx = x + _LeftRadius; - if( pNeighbors.neighbors[px][py][pz] && pNeighbors.neighbors[px][py][pz]->children ) - neighbors.neighbors[xx][yy][zz] = pNeighbors.neighbors[px][py][pz]->children + ( cornerIndex | (_x&1) ); - else - neighbors.neighbors[xx][yy][zz] = NULL; - } - } - } - } - // Otherwise recurse - else - { - ConstNeighbors< _PLeftRadius + _PRightRadius + 1 > pNeighbors; - getNeighbors< _PLeftRadius , _PRightRadius >( node->parent , pNeighbors ); - - // Get the indices of the child node that would contain the point (and its antipode) - int cx , cy , cz; - Cube::FactorCornerIndex( (int)( node - node->parent->children ) , cx , cy , cz ); - - - // Iterate over the finer neighbors - // Here: - // (x,y,z) give the position of the finer nodes relative to the center, - // (_x,_y,_z) give a positive global position, up to an even offset, and - // (px-LeftRadius,py-LeftRadius,pz-LeftRadius) give the positions of their parents relative to the parent of the center - for( int z=-(int)_LeftRadius ; z<=(int)_RightRadius ; z++ ) - { - int _z = (z+cz) + (_LeftRadius<<1) , pz = ( _z>>1 ) - _LeftRadius + _PLeftRadius , zz = z + _LeftRadius; - for( int y=-(int)_LeftRadius ; y<=(int)_RightRadius ; y++ ) - { - int _y = (y+cy) + (_LeftRadius<<1) , py = ( _y>>1 ) - _LeftRadius + _PLeftRadius , yy = y + _LeftRadius; - - int cornerIndex = ( (_z&1)<<2 ) | ( (_y&1)<<1 ); - for( int x=-(int)_LeftRadius ; x<=(int)_RightRadius ; x++ ) - { - int _x = (x+cx) + (_LeftRadius<<1) , px = ( _x>>1 ) - _LeftRadius + _PLeftRadius , xx = x + _LeftRadius; - - if( pNeighbors.neighbors[px][py][pz] && pNeighbors.neighbors[px][py][pz]->children ) - neighbors.neighbors[xx][yy][zz] = pNeighbors.neighbors[px][py][pz]->children + ( cornerIndex | (_x&1) ); - else - neighbors.neighbors[xx][yy][zz] = NULL; - } - } - } - } - return; -} - -template< class NodeData > -int OctNode< NodeData >::write(const char* fileName) const{ - FILE* fp=fopen(fileName,"wb"); - if(!fp){return 0;} - int ret=write(fp); - fclose(fp); - return ret; -} -template< class NodeData > -int OctNode< NodeData >::write(FILE* fp) const{ - fwrite(this,sizeof(OctNode< NodeData >),1,fp); - if(children){for(int i=0;i -int OctNode< NodeData >::read( const char* fileName , void (*Initializer)( OctNode& ) ) -{ - FILE* fp = fopen( fileName , "rb" ); - if( !fp ) return 0; - int ret = read( fp , Initializer ); - fclose( fp ); - return ret; -} -template< class NodeData > -int OctNode< NodeData >::read( FILE* fp , void (*Initializer)( OctNode& ) ) -{ - fread( this , sizeof( OctNode< NodeData > ) , 1 , fp ); - parent = NULL; - if( children ) - { - children=NULL; - initChildren( Initializer ); - for( int i=0 ; i -int OctNode< NodeData >::width(int maxDepth) const { - int d=depth(); - return 1<<(maxDepth-d); -} -template< class NodeData > -void OctNode< NodeData >::centerIndex(int maxDepth,int index[DIMENSION]) const -{ - int d,o[3]; - depthAndOffset(d,o); - for(int i=0;i -#include "Polynomial.h" -#include "Array.h" - -template< int Degree > -class StartingPolynomial -{ -public: - Polynomial< Degree > p; - double start; - - template< int Degree2 > - StartingPolynomial< Degree+Degree2 > operator * ( const StartingPolynomial< Degree2 >& p ) const; - StartingPolynomial scale( double s ) const; - StartingPolynomial shift( double t ) const; - int operator < ( const StartingPolynomial& sp ) const; - static int Compare( const void* v1 , const void* v2 ); -}; - -template< int Degree > -class PPolynomial -{ -public: - size_t polyCount; - Pointer( StartingPolynomial< Degree > ) polys; - - PPolynomial( void ); - PPolynomial( const PPolynomial& p ); - ~PPolynomial( void ); - - PPolynomial& operator = ( const PPolynomial& p ); - - int size( void ) const; - - void set( size_t size ); - // Note: this method will sort the elements in sps - void set( Pointer( StartingPolynomial ) sps , int count ); - void reset( size_t newSize ); - PPolynomial& compress( double delta=0. ); - - - double operator()( double t ) const; - double integral( double tMin , double tMax ) const; - double Integral( void ) const; - - template< int Degree2 > PPolynomial< Degree >& operator = ( const PPolynomial< Degree2 >& p ); - - PPolynomial operator + ( const PPolynomial& p ) const; - PPolynomial operator - ( const PPolynomial& p ) const; - - template< int Degree2 > PPolynomial< Degree+Degree2 > operator * ( const Polynomial< Degree2 >& p ) const; - template< int Degree2 > PPolynomial< Degree+Degree2 > operator * ( const PPolynomial< Degree2 >& p) const; - - - PPolynomial& operator += ( double s ); - PPolynomial& operator -= ( double s ); - PPolynomial& operator *= ( double s ); - PPolynomial& operator /= ( double s ); - PPolynomial operator + ( double s ) const; - PPolynomial operator - ( double s ) const; - PPolynomial operator * ( double s ) const; - PPolynomial operator / ( double s ) const; - - PPolynomial& addScaled( const PPolynomial& poly , double scale ); - - PPolynomial scale( double s ) const; - PPolynomial shift( double t ) const; - PPolynomial reflect( double r=0. ) const; - - PPolynomial< Degree-1 > derivative(void) const; - PPolynomial< Degree+1 > integral(void) const; - - void getSolutions( double c , std::vector< double >& roots , double EPS , double min=-DBL_MAX , double max=DBL_MAX ) const; - - void printnl( void ) const; - - PPolynomial< Degree+1 > MovingAverage( double radius ) const; - static PPolynomial BSpline( double radius=0.5 ); - - void write( FILE* fp , int samples , double min , double max ) const; -}; -#include "PPolynomial.inl" -#endif // P_POLYNOMIAL_INCLUDED diff --git a/Src/Ply.h b/Src/Ply.h deleted file mode 100644 index 699381ff..00000000 --- a/Src/Ply.h +++ /dev/null @@ -1,919 +0,0 @@ -/* - - Header for PLY polygon files. - - - Greg Turk, March 1994 - - A PLY file contains a single polygonal _object_. - - An object is composed of lists of _elements_. Typical elements are - vertices, faces, edges and materials. - - Each type of element for a given object has one or more _properties_ - associated with the element type. For instance, a vertex element may - have as properties three floating-point values x,y,z and three unsigned - chars for red, green and blue. - - --------------------------------------------------------------- - - Copyright (c) 1994 The Board of Trustees of The Leland Stanford - Junior University. All rights reserved. - - Permission to use, copy, modify and distribute this software and its - documentation for any purpose is hereby granted without fee, provided - that the above copyright notice and this permission notice appear in - all copies of this software and that you do not sell the software. - - THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, - EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY - WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -*/ - -#ifndef __PLY_H__ -#define __PLY_H__ - -#define USE_PLY_WRAPPER 1 - -#ifndef WIN32 -#define _strdup strdup -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include -#include - -#define PLY_ASCII 1 /* ascii PLY file */ -#define PLY_BINARY_BE 2 /* binary PLY file, big endian */ -#define PLY_BINARY_LE 3 /* binary PLY file, little endian */ -#define PLY_BINARY_NATIVE 4 /* binary PLY file, same endianness as current architecture */ - -#define PLY_OKAY 0 /* ply routine worked okay */ -#define PLY_ERROR -1 /* error in ply routine */ - - /* scalar data types supported by PLY format */ - -#define PLY_START_TYPE 0 -#define PLY_CHAR 1 -#define PLY_SHORT 2 -#define PLY_INT 3 -#define PLY_UCHAR 4 -#define PLY_USHORT 5 -#define PLY_UINT 6 -#define PLY_FLOAT 7 -#define PLY_DOUBLE 8 -#define PLY_INT_8 9 -#define PLY_UINT_8 10 -#define PLY_INT_16 11 -#define PLY_UINT_16 12 -#define PLY_INT_32 13 -#define PLY_UINT_32 14 -#define PLY_FLOAT_32 15 -#define PLY_FLOAT_64 16 - -#define PLY_END_TYPE 17 - -#define PLY_SCALAR 0 -#define PLY_LIST 1 - -#define PLY_STRIP_COMMENT_HEADER 0 - -typedef struct PlyProperty { /* description of a property */ - - char *name; /* property name */ - int external_type; /* file's data type */ - int internal_type; /* program's data type */ - int offset; /* offset bytes of prop in a struct */ - - int is_list; /* 1 = list, 0 = scalar */ - int count_external; /* file's count type */ - int count_internal; /* program's count type */ - int count_offset; /* offset byte for list count */ - -} PlyProperty; - -typedef struct PlyElement { /* description of an element */ - char *name; /* element name */ - int num; /* number of elements in this object */ - int size; /* size of element (bytes) or -1 if variable */ - int nprops; /* number of properties for this element */ - PlyProperty **props; /* list of properties in the file */ - char *store_prop; /* flags: property wanted by user? */ - int other_offset; /* offset to un-asked-for props, or -1 if none*/ - int other_size; /* size of other_props structure */ -} PlyElement; - -typedef struct PlyOtherProp { /* describes other properties in an element */ - char *name; /* element name */ - int size; /* size of other_props */ - int nprops; /* number of properties in other_props */ - PlyProperty **props; /* list of properties in other_props */ -} PlyOtherProp; - -typedef struct OtherData { /* for storing other_props for an other element */ - void *other_props; -} OtherData; - -typedef struct OtherElem { /* data for one "other" element */ - char *elem_name; /* names of other elements */ - int elem_count; /* count of instances of each element */ - OtherData **other_data; /* actual property data for the elements */ - PlyOtherProp *other_props; /* description of the property data */ -} OtherElem; - -typedef struct PlyOtherElems { /* "other" elements, not interpreted by user */ - int num_elems; /* number of other elements */ - OtherElem *other_list; /* list of data for other elements */ -} PlyOtherElems; - -typedef struct PlyFile { /* description of PLY file */ - FILE *fp; /* file pointer */ - int file_type; /* ascii or binary */ - float version; /* version number of file */ - int nelems; /* number of elements of object */ - PlyElement **elems; /* list of elements */ - int num_comments; /* number of comments */ - char **comments; /* list of comments */ - int num_obj_info; /* number of items of object information */ - char **obj_info; /* list of object info items */ - PlyElement *which_elem; /* which element we're currently writing */ - PlyOtherElems *other_elems; /* "other" elements from a PLY file */ -} PlyFile; - - /* memory allocation */ -extern char *my_alloc(); -#define myalloc(mem_size) my_alloc((mem_size), __LINE__, __FILE__) - -#ifndef ALLOCN -#define REALLOCN(PTR,TYPE,OLD_N,NEW_N) \ -{ \ - if ((OLD_N) == 0) \ -{ ALLOCN((PTR),TYPE,(NEW_N));} \ - else \ -{ \ - (PTR) = (TYPE *)realloc((PTR),(NEW_N)*sizeof(TYPE)); \ - if (((PTR) == NULL) && ((NEW_N) != 0)) \ -{ \ - fprintf(stderr, "Memory reallocation failed on line %d in %s\n", \ - __LINE__, __FILE__); \ - fprintf(stderr, " tried to reallocate %d->%d\n", \ - (OLD_N), (NEW_N)); \ - exit(-1); \ -} \ - if ((NEW_N)>(OLD_N)) \ - memset((char *)(PTR)+(OLD_N)*sizeof(TYPE), 0, \ - ((NEW_N)-(OLD_N))*sizeof(TYPE)); \ -} \ -} - -#define ALLOCN(PTR,TYPE,N) \ -{ (PTR) = (TYPE *) calloc(((unsigned)(N)),sizeof(TYPE));\ - if ((PTR) == NULL) { \ - fprintf(stderr, "Memory allocation failed on line %d in %s\n", \ - __LINE__, __FILE__); \ - exit(-1); \ - } \ -} - - -#define FREE(PTR) { free((PTR)); (PTR) = NULL; } -#endif - - -/*** delcaration of routines ***/ - -extern PlyFile *ply_write(FILE *, int, const char **, int); -extern PlyFile *ply_open_for_writing(char *, int, const char **, int, float *); -extern void ply_describe_element(PlyFile *, char *, int, int, PlyProperty *); -extern void ply_describe_property(PlyFile *, const char *, PlyProperty *); -extern void ply_element_count(PlyFile *, const char *, int); -extern void ply_header_complete(PlyFile *); -extern void ply_put_element_setup(PlyFile *, const char *); -extern void ply_put_element(PlyFile *, void *); -extern void ply_put_comment(PlyFile *, char *); -extern void ply_put_obj_info(PlyFile *, char *); -extern PlyFile *ply_read(FILE *, int *, char ***); -extern PlyFile *ply_open_for_reading( char *, int *, char ***, int *, float *); -extern PlyProperty **ply_get_element_description(PlyFile *, char *, int*, int*); -extern void ply_get_element_setup( PlyFile *, char *, int, PlyProperty *); -extern int ply_get_property(PlyFile *, char *, PlyProperty *); -extern PlyOtherProp *ply_get_other_properties(PlyFile *, char *, int); -extern void ply_get_element(PlyFile *, void *); -extern char **ply_get_comments(PlyFile *, int *); -extern char **ply_get_obj_info(PlyFile *, int *); -extern void ply_close(PlyFile *); -extern void ply_get_info(PlyFile *, float *, int *); -extern PlyOtherElems *ply_get_other_element (PlyFile *, char *, int); -extern void ply_describe_other_elements ( PlyFile *, PlyOtherElems *); -extern void ply_put_other_elements (PlyFile *); -extern void ply_free_other_elements (PlyOtherElems *); -extern void ply_describe_other_properties(PlyFile *, PlyOtherProp *, int); - -extern int equal_strings(const char *, const char *); - -#ifdef __cplusplus -} -#endif -#include "Geometry.h" -#include - -template< class Real > int PLYType( void ); -template<> inline int PLYType< int >( void ){ return PLY_INT ; } -template<> inline int PLYType< char >( void ){ return PLY_CHAR ; } -template<> inline int PLYType< unsigned char >( void ){ return PLY_UCHAR ; } -template<> inline int PLYType< float >( void ){ return PLY_FLOAT ; } -template<> inline int PLYType< double >( void ){ return PLY_DOUBLE; } -template< class Real > inline int PLYType( void ){ fprintf( stderr , "[ERROR] Unrecognized type\n" ) , exit( 0 ); } - -typedef struct PlyFace -{ - unsigned char nr_vertices; - int *vertices; - int segment; -} PlyFace; -static PlyProperty face_props[] = -{ - { _strdup( "vertex_indices" ) , PLY_INT , PLY_INT , offsetof( PlyFace , vertices ) , 1 , PLY_UCHAR, PLY_UCHAR , offsetof(PlyFace,nr_vertices) }, -}; - - -/////////////////// -// PlyVertexType // -/////////////////// - -// The "Wrapper" class indicates the class to cast to/from in order to support linear operations. -template< class Real > -class PlyVertex -{ -public: - typedef PlyVertex Wrapper; - - const static int ReadComponents=3; - const static int WriteComponents=3; - static PlyProperty ReadProperties[]; - static PlyProperty WriteProperties[]; - - Point3D< Real > point; - - PlyVertex( void ) { ; } - PlyVertex( Point3D< Real > p ) { point=p; } - PlyVertex operator + ( PlyVertex p ) const { return PlyVertex( point+p.point ); } - PlyVertex operator - ( PlyVertex p ) const { return PlyVertex( point-p.point ); } - template< class _Real > PlyVertex operator * ( _Real s ) const { return PlyVertex( point*s ); } - template< class _Real > PlyVertex operator / ( _Real s ) const { return PlyVertex( point/s ); } - PlyVertex& operator += ( PlyVertex p ) { point += p.point ; return *this; } - PlyVertex& operator -= ( PlyVertex p ) { point -= p.point ; return *this; } - template< class _Real > PlyVertex& operator *= ( _Real s ) { point *= s ; return *this; } - template< class _Real > PlyVertex& operator /= ( _Real s ) { point /= s ; return *this; } -}; -template< class Real , class _Real > PlyVertex< Real > operator * ( XForm4x4< _Real > xForm , PlyVertex< Real > v ) { return PlyVertex< Real >( xForm * v.point ); } -template< class Real > PlyProperty PlyVertex< Real >::ReadProperties[]= -{ - { _strdup( "x" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "y" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "z" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 } -}; -template< class Real > PlyProperty PlyVertex< Real >::WriteProperties[]= -{ - { _strdup( "x" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "y" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "z" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 } -}; -template< class Real > -class PlyValueVertex -{ -public: - typedef PlyValueVertex Wrapper; - - const static int ReadComponents=4; - const static int WriteComponents=4; - static PlyProperty ReadProperties[]; - static PlyProperty WriteProperties[]; - - Point3D point; - Real value; - - PlyValueVertex( void ) : value( Real(0) ) { ; } - PlyValueVertex( Point3D< Real > p , Real v ) : point(p) , value(v) { ; } - PlyValueVertex operator + ( PlyValueVertex p ) const { return PlyValueVertex( point+p.point , value+p.value ); } - PlyValueVertex operator - ( PlyValueVertex p ) const { return PlyValueVertex( point-p.value , value-p.value ); } - template< class _Real > PlyValueVertex operator * ( _Real s ) const { return PlyValueVertex( point*s , Real(value*s) ); } - template< class _Real > PlyValueVertex operator / ( _Real s ) const { return PlyValueVertex( point/s , Real(value/s) ); } - PlyValueVertex& operator += ( PlyValueVertex p ) { point += p.point , value += p.value ; return *this; } - PlyValueVertex& operator -= ( PlyValueVertex p ) { point -= p.point , value -= p.value ; return *this; } - template< class _Real > PlyValueVertex& operator *= ( _Real s ) { point *= s , value *= Real(s) ; return *this; } - template< class _Real > PlyValueVertex& operator /= ( _Real s ) { point /= s , value /= Real(s) ; return *this; } -}; -template< class Real , class _Real > PlyValueVertex< Real > operator * ( XForm4x4< _Real > xForm , PlyValueVertex< Real > v ) { return PlyValueVertex< Real >( xForm * v.point , v.value ); } -template< class Real > PlyProperty PlyValueVertex< Real >::ReadProperties[]= -{ - { _strdup( "x" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyValueVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "y" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyValueVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "z" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyValueVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "value" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyValueVertex , value ) ) , 0 , 0 , 0 , 0 } -}; -template< class Real > PlyProperty PlyValueVertex< Real >::WriteProperties[]= -{ - { _strdup( "x" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyValueVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "y" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyValueVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "z" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyValueVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "value" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyValueVertex , value ) ) , 0 , 0 , 0 , 0 } -}; -template< class Real > -class PlyOrientedVertex -{ -public: - typedef PlyOrientedVertex Wrapper; - - const static int ReadComponents=6; - const static int WriteComponents=6; - static PlyProperty ReadProperties[]; - static PlyProperty WriteProperties[]; - - Point3D point , normal; - - PlyOrientedVertex( void ) { ; } - PlyOrientedVertex( Point3D< Real > p , Point3D< Real > n ) : point(p) , normal(n) { ; } - PlyOrientedVertex operator + ( PlyOrientedVertex p ) const { return PlyOrientedVertex( point+p.point , normal+p.normal ); } - PlyOrientedVertex operator - ( PlyOrientedVertex p ) const { return PlyOrientedVertex( point-p.value , normal-p.normal ); } - template< class _Real > PlyOrientedVertex operator * ( _Real s ) const { return PlyOrientedVertex( point*s , normal*s ); } - template< class _Real > PlyOrientedVertex operator / ( _Real s ) const { return PlyOrientedVertex( point/s , normal/s ); } - PlyOrientedVertex& operator += ( PlyOrientedVertex p ) { point += p.point , normal += p.normal ; return *this; } - PlyOrientedVertex& operator -= ( PlyOrientedVertex p ) { point -= p.point , normal -= p.normal ; return *this; } - template< class _Real > PlyOrientedVertex& operator *= ( _Real s ) { point *= s , normal *= s ; return *this; } - template< class _Real > PlyOrientedVertex& operator /= ( _Real s ) { point /= s , normal /= s ; return *this; } -}; -template< class Real , class _Real > PlyOrientedVertex< Real > operator * ( XForm4x4< _Real > xForm , PlyOrientedVertex< Real > v ) { return PlyOrientedVertex< Real >( xForm * v.point , xForm.inverse().transpose() * v.normal ); } -template< class Real > PlyProperty PlyOrientedVertex< Real >::ReadProperties[]= -{ - { _strdup( "x" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyOrientedVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "y" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyOrientedVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "z" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyOrientedVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "nx" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyOrientedVertex , normal.coords[0] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "ny" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyOrientedVertex , normal.coords[1] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "nz" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyOrientedVertex , normal.coords[2] ) ) , 0 , 0 , 0 , 0 } -}; -template< class Real > PlyProperty PlyOrientedVertex< Real >::WriteProperties[]= -{ - { _strdup( "x" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyOrientedVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "y" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyOrientedVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "z" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyOrientedVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "nx" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyOrientedVertex , normal.coords[0] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "ny" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyOrientedVertex , normal.coords[1] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "nz" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyOrientedVertex , normal.coords[2] ) ) , 0 , 0 , 0 , 0 } -}; -template< class Real > -class PlyColorVertex -{ -public: - struct _PlyColorVertex - { - Point3D< Real > point , color; - _PlyColorVertex( void ) { ; } - _PlyColorVertex( Point3D< Real > p , Point3D< Real > c ) : point(p) , color(c) { ; } - _PlyColorVertex( PlyColorVertex< Real > p ){ point = p.point ; for( int c=0 ; c<3 ; c++ ) color[c] = (Real) p.color[c]; } - operator PlyColorVertex< Real > () - { - PlyColorVertex< Real > p; - p.point = point; - for( int c=0 ; c<3 ; c++ ) p.color[c] = (unsigned char)std::max< int >( 0 , std::min< int >( 255 , (int)( color[c]+0.5 ) ) ); - return p; - } - - _PlyColorVertex operator + ( _PlyColorVertex p ) const { return _PlyColorVertex( point+p.point , color+p.color ); } - _PlyColorVertex operator - ( _PlyColorVertex p ) const { return _PlyColorVertex( point-p.value , color-p.color ); } - template< class _Real > _PlyColorVertex operator * ( _Real s ) const { return _PlyColorVertex( point*s , color*s ); } - template< class _Real > _PlyColorVertex operator / ( _Real s ) const { return _PlyColorVertex( point/s , color/s ); } - _PlyColorVertex& operator += ( _PlyColorVertex p ) { point += p.point , color += p.color ; return *this; } - _PlyColorVertex& operator -= ( _PlyColorVertex p ) { point -= p.point , color -= p.color ; return *this; } - template< class _Real > _PlyColorVertex& operator *= ( _Real s ) { point *= s , color *= s ; return *this; } - template< class _Real > _PlyColorVertex& operator /= ( _Real s ) { point /= s , color /= s ; return *this; } - }; - - typedef _PlyColorVertex Wrapper; - - const static int ReadComponents=9; - const static int WriteComponents=6; - static PlyProperty ReadProperties[]; - static PlyProperty WriteProperties[]; - - Point3D< Real > point; - unsigned char color[3]; - - operator Point3D< Real >& (){ return point; } - operator const Point3D< Real >& () const { return point; } - PlyColorVertex( void ) { point.coords[0] = point.coords[1] = point.coords[2] = 0 , color[0] = color[1] = color[2] = 0; } - PlyColorVertex( const Point3D& p ) { point=p; } - PlyColorVertex( const Point3D< Real >& p , const unsigned char c[3] ) { point = p , color[0] = c[0] , color[1] = c[1] , color[2] = c[2]; } -}; -template< class Real , class _Real > PlyColorVertex< Real > operator * ( XForm4x4< _Real > xForm , PlyColorVertex< Real > v ) { return PlyColorVertex< Real >( xForm * v.point , v.color ); } - -template< class Real > PlyProperty PlyColorVertex< Real >::ReadProperties[]= -{ - { _strdup( "x" ) , PLYType< Real >() , PLYType< Real >(), int( offsetof( PlyColorVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "y" ) , PLYType< Real >() , PLYType< Real >(), int( offsetof( PlyColorVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "z" ) , PLYType< Real >() , PLYType< Real >(), int( offsetof( PlyColorVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "red" ) , PLYType< unsigned char >() , PLYType< unsigned char >(), int( offsetof( PlyColorVertex , color[0] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "green" ) , PLYType< unsigned char >() , PLYType< unsigned char >(), int( offsetof( PlyColorVertex , color[1] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "blue" ) , PLYType< unsigned char >() , PLYType< unsigned char >(), int( offsetof( PlyColorVertex , color[2] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "r" ) , PLYType< unsigned char >() , PLYType< unsigned char >(), int( offsetof( PlyColorVertex , color[0] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "g" ) , PLYType< unsigned char >() , PLYType< unsigned char >(), int( offsetof( PlyColorVertex , color[1] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "b" ) , PLYType< unsigned char >() , PLYType< unsigned char >(), int( offsetof( PlyColorVertex , color[2] ) ) , 0 , 0 , 0 , 0 } -}; -template< class Real > PlyProperty PlyColorVertex< Real >::WriteProperties[]= -{ - { _strdup( "x" ) , PLYType< Real >() , PLYType< Real >(), int( offsetof( PlyColorVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "y" ) , PLYType< Real >() , PLYType< Real >(), int( offsetof( PlyColorVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "z" ) , PLYType< Real >() , PLYType< Real >(), int( offsetof( PlyColorVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "red" ) , PLYType< unsigned char >() , PLYType< unsigned char >(), int( offsetof( PlyColorVertex , color[0] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "green" ) , PLYType< unsigned char >() , PLYType< unsigned char >(), int( offsetof( PlyColorVertex , color[1] ) ) , 0 , 0 , 0 , 0 }, - { _strdup( "blue" ) , PLYType< unsigned char >() , PLYType< unsigned char >(), int( offsetof( PlyColorVertex , color[2] ) ) , 0 , 0 , 0 , 0 } -}; -template< class Real > -class PlyColorAndValueVertex -{ -public: - struct _PlyColorAndValueVertex - { - Point3D< Real > point , color; - Real value; - _PlyColorAndValueVertex( void ) : value(0) { ; } - _PlyColorAndValueVertex( Point3D< Real > p , Point3D< Real > c , Real v ) : point(p) , color(c) , value(v) { ; } - _PlyColorAndValueVertex( PlyColorAndValueVertex< Real > p ){ point = p.point ; for( int c=0 ; c<3 ; c++ ) color[c] = (Real) p.color[c] ; value = p.value; } - operator PlyColorAndValueVertex< Real > () - { - PlyColorAndValueVertex< Real > p; - p.point = point; - for( int c=0 ; c<3 ; c++ ) p.color[c] = (unsigned char)std::max< int >( 0 , std::min< int >( 255 , (int)( color[c]+0.5 ) ) ); - p.value = value; - return p; - } - - _PlyColorAndValueVertex operator + ( _PlyColorAndValueVertex p ) const { return _PlyColorAndValueVertex( point+p.point , color+p.color , value+p.value ); } - _PlyColorAndValueVertex operator - ( _PlyColorAndValueVertex p ) const { return _PlyColorAndValueVertex( point-p.value , color-p.color , value+p.value ); } - template< class _Real > _PlyColorAndValueVertex operator * ( _Real s ) const { return _PlyColorAndValueVertex( point*s , color*s , value*s ); } - template< class _Real > _PlyColorAndValueVertex operator / ( _Real s ) const { return _PlyColorAndValueVertex( point/s , color/s , value/s ); } - _PlyColorAndValueVertex& operator += ( _PlyColorAndValueVertex p ) { point += p.point , color += p.color , value += p.value ; return *this; } - _PlyColorAndValueVertex& operator -= ( _PlyColorAndValueVertex p ) { point -= p.point , color -= p.color , value -= p.value ; return *this; } - template< class _Real > _PlyColorAndValueVertex& operator *= ( _Real s ) { point *= s , color *= s , value *= (Real)s ; return *this; } - template< class _Real > _PlyColorAndValueVertex& operator /= ( _Real s ) { point /= s , color /= s , value /= (Real)s ; return *this; } - }; - - typedef _PlyColorAndValueVertex Wrapper; - - const static int ReadComponents=10; - const static int WriteComponents=7; - static PlyProperty ReadProperties[]; - static PlyProperty WriteProperties[]; - - Point3D< Real > point; - unsigned char color[3]; - Real value; - - operator Point3D< Real >& (){ return point; } - operator const Point3D< Real >& () const { return point; } - PlyColorAndValueVertex( void ) { point.coords[0] = point.coords[1] = point.coords[2] = (Real)0 , color[0] = color[1] = color[2] = 0 , value = (Real)0; } - PlyColorAndValueVertex( const Point3D< Real >& p ) { point=p; } - PlyColorAndValueVertex( const Point3D< Real >& p , const unsigned char c[3] , Real v) { point = p , color[0] = c[0] , color[1] = c[1] , color[2] = c[2] , value = v; } -}; -template< class Real , class _Real > PlyColorAndValueVertex< Real > operator * ( XForm4x4< _Real > xForm , PlyColorAndValueVertex< Real > v ) { return PlyColorAndValueVertex< Real >( xForm * v.point , v.color , v.value ); } -template< class Real > PlyProperty PlyColorAndValueVertex< Real >::ReadProperties[]= -{ - { _strdup( "x" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyColorAndValueVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 } , - { _strdup( "y" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyColorAndValueVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 } , - { _strdup( "z" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyColorAndValueVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 } , - { _strdup( "value" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyColorAndValueVertex , value ) ) , 0 , 0 , 0 , 0 } , - { _strdup( "red" ) , PLYType< unsigned char >() , PLYType< unsigned char >() , int( offsetof( PlyColorAndValueVertex , color[0] ) ) , 0 , 0 , 0 , 0 } , - { _strdup( "green" ) , PLYType< unsigned char >() , PLYType< unsigned char >() , int( offsetof( PlyColorAndValueVertex , color[1] ) ) , 0 , 0 , 0 , 0 } , - { _strdup( "blue" ) , PLYType< unsigned char >() , PLYType< unsigned char >() , int( offsetof( PlyColorAndValueVertex , color[2] ) ) , 0 , 0 , 0 , 0 } , - { _strdup( "r" ) , PLYType< unsigned char >() , PLYType< unsigned char >() , int( offsetof( PlyColorAndValueVertex , color[0] ) ) , 0 , 0 , 0 , 0 } , - { _strdup( "g" ) , PLYType< unsigned char >() , PLYType< unsigned char >() , int( offsetof( PlyColorAndValueVertex , color[1] ) ) , 0 , 0 , 0 , 0 } , - { _strdup( "b" ) , PLYType< unsigned char >() , PLYType< unsigned char >() , int( offsetof( PlyColorAndValueVertex , color[2] ) ) , 0 , 0 , 0 , 0 } -}; -template< class Real > PlyProperty PlyColorAndValueVertex< Real >::WriteProperties[]= -{ - { _strdup( "x" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyColorAndValueVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 } , - { _strdup( "y" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyColorAndValueVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 } , - { _strdup( "z" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyColorAndValueVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 } , - { _strdup( "value" ) , PLYType< Real >() , PLYType< Real >() , int( offsetof( PlyColorAndValueVertex , value ) ) , 0 , 0 , 0 , 0 } , - { _strdup( "red" ) , PLYType< unsigned char >() , PLYType< unsigned char >() , int( offsetof( PlyColorAndValueVertex , color[0] ) ) , 0 , 0 , 0 , 0 } , - { _strdup( "green" ) , PLYType< unsigned char >() , PLYType< unsigned char >() , int( offsetof( PlyColorAndValueVertex , color[1] ) ) , 0 , 0 , 0 , 0 } , - { _strdup( "blue" ) , PLYType< unsigned char >() , PLYType< unsigned char >() , int( offsetof( PlyColorAndValueVertex , color[2] ) ) , 0 , 0 , 0 , 0 } -}; - -template< class Vertex , class Real > -int PlyWritePolygons( char* fileName , CoredMeshData< Vertex >* mesh , int file_type , const Point3D< float >& translate , float scale , char** comments=NULL , int commentNum=0 , XForm4x4< Real > xForm=XForm4x4< Real >::Identity() ); - -template< class Vertex , class Real > -int PlyWritePolygons( char* fileName , CoredMeshData< Vertex >* mesh , int file_type , char** comments=NULL , int commentNum=0 , XForm4x4< Real > xForm=XForm4x4< Real >::Identity() ); - -inline bool PlyReadHeader( char* fileName , PlyProperty* properties , int propertyNum , bool* readFlags , int& file_type ) -{ - int nr_elems; - char **elist; - float version; - PlyFile* ply; - char* elem_name; - int num_elems; - int nr_props; - PlyProperty** plist; - - ply = ply_open_for_reading( fileName , &nr_elems , &elist , &file_type , &version ); - if( !ply ) return false; - - for( int i=0 ; ielems[i]->name ); - free( ply->elems[i]->store_prop ); - for( int j=0 ; jelems[i]->nprops ; j++ ) - { - free( ply->elems[i]->props[j]->name ); - free( ply->elems[i]->props[j] ); - } - free( ply->elems[i]->props ); - } - for( int i=0 ; ielems[i] ); - free( ply->elems ); - for( int i=0 ; inum_comments ; i++ ) free( ply->comments[i] ); - free( ply->comments ); - for( int i=0 ; inum_obj_info ; i++ ) free( ply->obj_info[i] ); - free( ply->obj_info ); - ply_free_other_elements( ply->other_elems ); - - for( int i=0 ; iname ); - free( plist[j] ); - } - free( plist ); - } // for each type of element - - for( int i=0 ; ielems[i]->name ); - free( ply->elems[i]->store_prop ); - for( int j=0 ; jelems[i]->nprops ; j++ ) - { - free( ply->elems[i]->props[j]->name ); - free( ply->elems[i]->props[j] ); - } - if( ply->elems[i]->props && ply->elems[i]->nprops ) free(ply->elems[i]->props); - } - for( int i=0 ; ielems[i]); - free( ply->elems) ; - for( int i=0 ; inum_comments ; i++ ) free( ply->comments[i] ); - free( ply->comments ); - for( int i=0 ; inum_obj_info ; i++ ) free( ply->obj_info[i] ); - free( ply->obj_info ); - ply_free_other_elements(ply->other_elems); - - - for( int i=0 ; i -int PlyReadPolygons(char* fileName, - std::vector& vertices,std::vector >& polygons, - PlyProperty* properties,int propertyNum, - int& file_type, - char*** comments=NULL,int* commentNum=NULL , bool* readFlags=NULL ); - -template -int PlyWritePolygons(char* fileName, - const std::vector& vertices,const std::vector >& polygons, - PlyProperty* properties,int propertyNum, - int file_type, - char** comments=NULL,const int& commentNum=0); - -template -int PlyWritePolygons(char* fileName, - const std::vector& vertices , const std::vector< std::vector< int > >& polygons, - PlyProperty* properties,int propertyNum, - int file_type, - char** comments,const int& commentNum) -{ - int nr_vertices=int(vertices.size()); - int nr_faces=int(polygons.size()); - float version; - const char *elem_names[] = { "vertex" , "face" }; - PlyFile *ply = ply_open_for_writing( fileName , 2 , elem_names , file_type , &version ); - if (!ply){return 0;} - - // - // describe vertex and face properties - // - ply_element_count(ply, "vertex", nr_vertices); - for(int i=0;imaxFaceVerts) - { - delete[] ply_face.vertices; - maxFaceVerts=int(polygons[i].size()); - ply_face.vertices=new int[maxFaceVerts]; - } - ply_face.nr_vertices=int(polygons[i].size()); - for(int j=0;j -int PlyReadPolygons(char* fileName, - std::vector& vertices , std::vector >& polygons , - PlyProperty* properties , int propertyNum , - int& file_type , - char*** comments , int* commentNum , bool* readFlags ) -{ - int nr_elems; - char **elist; - float version; - int i,j,k; - PlyFile* ply; - char* elem_name; - int num_elems; - int nr_props; - PlyProperty** plist; - PlyFace ply_face; - - ply = ply_open_for_reading(fileName, &nr_elems, &elist, &file_type, &version); - if(!ply) return 0; - - if(comments) - { - (*comments)=new char*[*commentNum+ply->num_comments]; - for(int i=0;inum_comments;i++) - (*comments)[i]=_strdup(ply->comments[i]); - *commentNum=ply->num_comments; - } - - for (i=0; i < nr_elems; i++) { - elem_name = elist[i]; - plist = ply_get_element_description(ply, elem_name, &num_elems, &nr_props); - if(!plist) - { - for(i=0;ielems[i]->name); - free(ply->elems[i]->store_prop); - for(j=0;jelems[i]->nprops;j++){ - free(ply->elems[i]->props[j]->name); - free(ply->elems[i]->props[j]); - } - free(ply->elems[i]->props); - } - for(i=0;ielems[i]);} - free(ply->elems); - for(i=0;inum_comments;i++){free(ply->comments[i]);} - free(ply->comments); - for(i=0;inum_obj_info;i++){free(ply->obj_info[i]);} - free(ply->obj_info); - ply_free_other_elements (ply->other_elems); - - for(i=0;iname); - free(plist[j]); - } - free(plist); - } // for each type of element - - for(i=0;ielems[i]->name); - free(ply->elems[i]->store_prop); - for(j=0;jelems[i]->nprops;j++){ - free(ply->elems[i]->props[j]->name); - free(ply->elems[i]->props[j]); - } - if(ply->elems[i]->props && ply->elems[i]->nprops){free(ply->elems[i]->props);} - } - for(i=0;ielems[i]);} - free(ply->elems); - for(i=0;inum_comments;i++){free(ply->comments[i]);} - free(ply->comments); - for(i=0;inum_obj_info;i++){free(ply->obj_info[i]);} - free(ply->obj_info); - ply_free_other_elements (ply->other_elems); - - - for(i=0;i -int PlyWritePolygons( char* fileName , CoredMeshData< Vertex >* mesh , int file_type , const Point3D& translate , float scale , char** comments , int commentNum , XForm4x4< Real > xForm ) -{ - int i; - int nr_vertices=int(mesh->outOfCorePointCount()+mesh->inCorePoints.size()); - int nr_faces=mesh->polygonCount(); - float version; - const char *elem_names[] = { "vertex" , "face" }; - PlyFile *ply = ply_open_for_writing( fileName , 2 , elem_names , file_type , &version ); - if( !ply ) return 0; - - mesh->resetIterator(); - - // - // describe vertex and face properties - // - ply_element_count( ply , "vertex" , nr_vertices ); - for( int i=0 ; iinCorePoints.size() ) ; i++ ) - { - Vertex vertex = xForm * ( mesh->inCorePoints[i] * scale + translate ); - ply_put_element(ply, (void *) &vertex); - } - for( i=0; ioutOfCorePointCount() ; i++ ) - { - Vertex vertex; - mesh->nextOutOfCorePoint( vertex ); - vertex = xForm * ( vertex * scale +translate ); - ply_put_element(ply, (void *) &vertex); - } // for, write vertices - - // write faces - std::vector< CoredVertexIndex > polygon; - ply_put_element_setup( ply , "face" ); - for( i=0 ; inextPolygon( polygon ); - ply_face.nr_vertices = int( polygon.size() ); - ply_face.vertices = new int[ polygon.size() ]; - for( int i=0 ; iinCorePoints.size() ); - ply_put_element( ply, (void *) &ply_face ); - delete[] ply_face.vertices; - } // for, write faces - - ply_close( ply ); - return 1; -} -template< class Vertex , class Real > -int PlyWritePolygons( char* fileName , CoredMeshData< Vertex >* mesh , int file_type , char** comments , int commentNum , XForm4x4< Real > xForm ) -{ - int i; - int nr_vertices=int(mesh->outOfCorePointCount()+mesh->inCorePoints.size()); - int nr_faces=mesh->polygonCount(); - float version; - const char *elem_names[] = { "vertex" , "face" }; - PlyFile *ply = ply_open_for_writing( fileName , 2 , elem_names , file_type , &version ); - if( !ply ) return 0; - - mesh->resetIterator(); - - // - // describe vertex and face properties - // - ply_element_count( ply , "vertex" , nr_vertices ); - for( int i=0 ; iinCorePoints.size() ) ; i++ ) - { - Vertex vertex = xForm * mesh->inCorePoints[i]; - ply_put_element(ply, (void *) &vertex); - } - for( i=0; ioutOfCorePointCount() ; i++ ) - { - Vertex vertex; - mesh->nextOutOfCorePoint( vertex ); - vertex = xForm * ( vertex ); - ply_put_element(ply, (void *) &vertex); - } // for, write vertices - - // write faces - std::vector< CoredVertexIndex > polygon; - ply_put_element_setup( ply , "face" ); - for( i=0 ; inextPolygon( polygon ); - ply_face.nr_vertices = int( polygon.size() ); - ply_face.vertices = new int[ polygon.size() ]; - for( int i=0 ; iinCorePoints.size() ); - ply_put_element( ply, (void *) &ply_face ); - delete[] ply_face.vertices; - } // for, write faces - - ply_close( ply ); - return 1; -} -inline int PlyDefaultFileType(void){return PLY_ASCII;} - -#endif /* !__PLY_H__ */ diff --git a/Src/PlyFile.cpp b/Src/PlyFile.cpp deleted file mode 100644 index 9d3f37c9..00000000 --- a/Src/PlyFile.cpp +++ /dev/null @@ -1,2730 +0,0 @@ -/* - - The interface routines for reading and writing PLY polygon files. - - Greg Turk, February 1994 - - --------------------------------------------------------------- - - A PLY file contains a single polygonal _object_. - - An object is composed of lists of _elements_. Typical elements are - vertices, faces, edges and materials. - - Each type of element for a given object has one or more _properties_ - associated with the element type. For instance, a vertex element may - have as properties the floating-point values x,y,z and the three unsigned - chars representing red, green and blue. - - --------------------------------------------------------------- - - Copyright (c) 1994 The Board of Trustees of The Leland Stanford - Junior University. All rights reserved. - - Permission to use, copy, modify and distribute this software and its - documentation for any purpose is hereby granted without fee, provided - that the above copyright notice and this permission notice appear in - all copies of this software and that you do not sell the software. - - THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, - EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY - WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -*/ - -#include -#include -#include -#include -#include "Ply.h" - -const char *type_names[] = { - "invalid", - "char", - "short", - "int", - "uchar", - "ushort", - "uint", - "float", - "double", - - "int8", // character 1 - "uint8", // unsigned character 1 - "int16", // short integer 2 - "uint16", // unsigned short integer 2 - "int32", // integer 4 - "uint32", // unsigned integer 4 - "float32", // single-precision float 4 - "float64", // double-precision float 8 - -}; - -int ply_type_size[] = { - 0, - 1, - 2, - 4, - 1, - 2, - 4, - 4, - 8, - 1, - 1, - 2, - 2, - 4, - 4, - 4, - 8 -}; - -typedef union -{ - int int_value; - char byte_values[sizeof(int)]; -} endian_test_type; - - -static int native_binary_type = -1; -static int types_checked = 0; - -#define NO_OTHER_PROPS -1 - -#define DONT_STORE_PROP 0 -#define STORE_PROP 1 - -#define OTHER_PROP 0 -#define NAMED_PROP 1 - - -/* returns 1 if strings are equal, 0 if not */ -int equal_strings(const char *, const char *); - -/* find an element in a plyfile's list */ -PlyElement *find_element(PlyFile *, const char *); - -/* find a property in an element's list */ -PlyProperty *find_property(PlyElement *, const char *, int *); - -/* write to a file the word describing a PLY file data type */ -void write_scalar_type (FILE *, int); - -/* read a line from a file and break it up into separate words */ -char **get_words(FILE *, int *, char **); -char **old_get_words(FILE *, int *); - -/* write an item to a file */ -void write_binary_item(FILE *, int, int, unsigned int, double, int); -void write_ascii_item(FILE *, int, unsigned int, double, int); -double old_write_ascii_item(FILE *, char *, int); - -/* add information to a PLY file descriptor */ -void add_element(PlyFile *, char **); -void add_property(PlyFile *, char **); -void add_comment(PlyFile *, char *); -void add_obj_info(PlyFile *, char *); - -/* copy a property */ -void copy_property(PlyProperty *, PlyProperty *); - -/* store a value into where a pointer and a type specify */ -void store_item(char *, int, int, unsigned int, double); - -/* return the value of a stored item */ -void get_stored_item( void *, int, int *, unsigned int *, double *); - -/* return the value stored in an item, given ptr to it and its type */ -double get_item_value(char *, int); - -/* get binary or ascii item and store it according to ptr and type */ -void get_ascii_item(char *, int, int *, unsigned int *, double *); -void get_binary_item(FILE *, int, int, int *, unsigned int *, double *); - -/* get a bunch of elements from a file */ -void ascii_get_element(PlyFile *, char *); -void binary_get_element(PlyFile *, char *); - -/* memory allocation */ -char *my_alloc(int, int, const char *); - -/* byte ordering */ -void get_native_binary_type(); -void swap_bytes(char *, int); - -void check_types(); - -/*************/ -/* Writing */ -/*************/ - - -/****************************************************************************** -Given a file pointer, get ready to write PLY data to the file. - - Entry: - fp - the given file pointer - nelems - number of elements in object - elem_names - list of element names - file_type - file type, either ascii or binary - - Exit: - returns a pointer to a PlyFile, used to refer to this file, or NULL if error -******************************************************************************/ - -PlyFile *ply_write( - FILE *fp, - int nelems, - const char **elem_names, - int file_type - ) -{ - int i; - PlyFile *plyfile; - PlyElement *elem; - - /* check for NULL file pointer */ - if (fp == NULL) - return (NULL); - - if (native_binary_type == -1) - get_native_binary_type(); - if (!types_checked) - check_types(); - - /* create a record for this object */ - - plyfile = (PlyFile *) myalloc (sizeof (PlyFile)); - if (file_type == PLY_BINARY_NATIVE) - plyfile->file_type = native_binary_type; - else - plyfile->file_type = file_type; - plyfile->num_comments = 0; - plyfile->num_obj_info = 0; - plyfile->nelems = nelems; - plyfile->version = 1.0; - plyfile->fp = fp; - plyfile->other_elems = NULL; - - /* tuck aside the names of the elements */ - - plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *) * nelems); - for (i = 0; i < nelems; i++) { - elem = (PlyElement *) myalloc (sizeof (PlyElement)); - plyfile->elems[i] = elem; - elem->name = _strdup (elem_names[i]); - elem->num = 0; - elem->nprops = 0; - } - - /* return pointer to the file descriptor */ - return (plyfile); -} - - -/****************************************************************************** -Open a polygon file for writing. - - Entry: - filename - name of file to read from - nelems - number of elements in object - elem_names - list of element names - file_type - file type, either ascii or binary - - Exit: - version - version number of PLY file - returns a file identifier, used to refer to this file, or NULL if error -******************************************************************************/ - -PlyFile *ply_open_for_writing( - char *filename, - int nelems, - const char **elem_names, - int file_type, - float *version - ) -{ - PlyFile *plyfile; - char *name; - FILE *fp; - - /* tack on the extension .ply, if necessary */ - - name = (char *) myalloc (int(sizeof (char) * (strlen (filename)) + 5)); - strcpy (name, filename); - if (strlen (name) < 4 || - strcmp (name + strlen (name) - 4, ".ply") != 0) - strcat (name, ".ply"); - - /* open the file for writing */ - - fp = fopen (name, "wb"); - free(name); - if (fp == NULL) { - return (NULL); - } - - /* create the actual PlyFile structure */ - - plyfile = ply_write (fp, nelems, elem_names, file_type); - if (plyfile == NULL) - return (NULL); - - /* say what PLY file version number we're writing */ - *version = plyfile->version; - - /* return pointer to the file descriptor */ - return (plyfile); -} - - -/****************************************************************************** -Describe an element, including its properties and how many will be written -to the file. - - Entry: - plyfile - file identifier - elem_name - name of element that information is being specified about - nelems - number of elements of this type to be written - nprops - number of properties contained in the element - prop_list - list of properties -******************************************************************************/ - -void ply_describe_element( - PlyFile *plyfile, - char *elem_name, - int nelems, - int nprops, - PlyProperty *prop_list - ) -{ - int i; - PlyElement *elem; - PlyProperty *prop; - - /* look for appropriate element */ - elem = find_element (plyfile, elem_name); - if (elem == NULL) { - fprintf(stderr,"ply_describe_element: can't find element '%s'\n",elem_name); - exit (-1); - } - - elem->num = nelems; - - /* copy the list of properties */ - - elem->nprops = nprops; - elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *) * nprops); - elem->store_prop = (char *) myalloc (sizeof (char) * nprops); - - for (i = 0; i < nprops; i++) { - prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); - elem->props[i] = prop; - elem->store_prop[i] = NAMED_PROP; - copy_property (prop, &prop_list[i]); - } -} - - -/****************************************************************************** -Describe a property of an element. - - Entry: - plyfile - file identifier - elem_name - name of element that information is being specified about - prop - the new property -******************************************************************************/ - -void ply_describe_property( - PlyFile *plyfile, - const char *elem_name, - PlyProperty *prop - ) -{ - PlyElement *elem; - PlyProperty *elem_prop; - - /* look for appropriate element */ - elem = find_element (plyfile, elem_name); - if (elem == NULL) { - fprintf(stderr, "ply_describe_property: can't find element '%s'\n", - elem_name); - return; - } - - /* create room for new property */ - - if (elem->nprops == 0) { - elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *)); - elem->store_prop = (char *) myalloc (sizeof (char)); - elem->nprops = 1; - } - else { - elem->nprops++; - elem->props = (PlyProperty **) - realloc (elem->props, sizeof (PlyProperty *) * elem->nprops); - elem->store_prop = (char *) - realloc (elem->store_prop, sizeof (char) * elem->nprops); - } - - /* copy the new property */ - - elem_prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); - elem->props[elem->nprops - 1] = elem_prop; - elem->store_prop[elem->nprops - 1] = NAMED_PROP; - copy_property (elem_prop, prop); -} - - -/****************************************************************************** -Describe what the "other" properties are that are to be stored, and where -they are in an element. -******************************************************************************/ - -void ply_describe_other_properties( - PlyFile *plyfile, - PlyOtherProp *other, - int offset - ) -{ - int i; - PlyElement *elem; - PlyProperty *prop; - - /* look for appropriate element */ - elem = find_element (plyfile, other->name); - if (elem == NULL) { - fprintf(stderr, "ply_describe_other_properties: can't find element '%s'\n", - other->name); - return; - } - - /* create room for other properties */ - - if (elem->nprops == 0) { - elem->props = (PlyProperty **) - myalloc (sizeof (PlyProperty *) * other->nprops); - elem->store_prop = (char *) myalloc (sizeof (char) * other->nprops); - elem->nprops = 0; - } - else { - int newsize; - newsize = elem->nprops + other->nprops; - elem->props = (PlyProperty **) - realloc (elem->props, sizeof (PlyProperty *) * newsize); - elem->store_prop = (char *) - realloc (elem->store_prop, sizeof (char) * newsize); - } - - /* copy the other properties */ - - for (i = 0; i < other->nprops; i++) { - prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); - copy_property (prop, other->props[i]); - elem->props[elem->nprops] = prop; - elem->store_prop[elem->nprops] = OTHER_PROP; - elem->nprops++; - } - - /* save other info about other properties */ - elem->other_size = other->size; - elem->other_offset = offset; -} - - -/****************************************************************************** -State how many of a given element will be written. - - Entry: - plyfile - file identifier - elem_name - name of element that information is being specified about - nelems - number of elements of this type to be written -******************************************************************************/ - -void ply_element_count( - PlyFile *plyfile, - const char *elem_name, - int nelems - ) -{ - PlyElement *elem; - - /* look for appropriate element */ - elem = find_element (plyfile, elem_name); - if (elem == NULL) { - fprintf(stderr,"ply_element_count: can't find element '%s'\n",elem_name); - exit (-1); - } - - elem->num = nelems; -} - - -/****************************************************************************** -Signal that we've described everything a PLY file's header and that the -header should be written to the file. - - Entry: - plyfile - file identifier -******************************************************************************/ - -void ply_header_complete(PlyFile *plyfile) -{ - int i,j; - FILE *fp = plyfile->fp; - PlyElement *elem; - PlyProperty *prop; - - fprintf (fp, "ply\n"); - - switch (plyfile->file_type) { - 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: - fprintf (stderr, "ply_header_complete: bad file type = %d\n", - plyfile->file_type); - exit (-1); - } - - /* write out the comments */ - - for (i = 0; i < plyfile->num_comments; i++) - fprintf (fp, "comment %s\n", plyfile->comments[i]); - - /* write out object information */ - - for (i = 0; i < plyfile->num_obj_info; i++) - fprintf (fp, "obj_info %s\n", plyfile->obj_info[i]); - - /* write out information about each element */ - - for (i = 0; i < plyfile->nelems; i++) { - - elem = plyfile->elems[i]; - fprintf (fp, "element %s %d\n", elem->name, elem->num); - - /* write out each property */ - for (j = 0; j < elem->nprops; j++) { - prop = elem->props[j]; - if (prop->is_list) { - fprintf (fp, "property list "); - write_scalar_type (fp, prop->count_external); - fprintf (fp, " "); - write_scalar_type (fp, prop->external_type); - fprintf (fp, " %s\n", prop->name); - } - else { - fprintf (fp, "property "); - write_scalar_type (fp, prop->external_type); - fprintf (fp, " %s\n", prop->name); - } - } - } - - fprintf (fp, "end_header\n"); -} - - -/****************************************************************************** -Specify which elements are going to be written. This should be called -before a call to the routine ply_put_element(). - - Entry: - plyfile - file identifier - elem_name - name of element we're talking about -******************************************************************************/ - -void ply_put_element_setup(PlyFile *plyfile, const char *elem_name) -{ - PlyElement *elem; - - elem = find_element (plyfile, elem_name); - if (elem == NULL) { - fprintf(stderr, "ply_elements_setup: can't find element '%s'\n", elem_name); - exit (-1); - } - - plyfile->which_elem = elem; -} - - -/****************************************************************************** -Write an element to the file. This routine assumes that we're -writing the type of element specified in the last call to the routine -ply_put_element_setup(). - - Entry: - plyfile - file identifier - elem_ptr - pointer to the element -******************************************************************************/ - -void ply_put_element(PlyFile *plyfile, void *elem_ptr) -{ - int j,k; - FILE *fp = plyfile->fp; - PlyElement *elem; - PlyProperty *prop; - char *elem_data,*item; - char **item_ptr; - int list_count; - int item_size; - int int_val; - unsigned int uint_val; - double double_val; - char **other_ptr; - - elem = plyfile->which_elem; - elem_data = (char *)elem_ptr; - other_ptr = (char **) (((char *) elem_ptr) + elem->other_offset); - - /* write out either to an ascii or binary file */ - - if (plyfile->file_type == PLY_ASCII) { - - /* write an ascii file */ - - /* write out each property of the element */ - for (j = 0; j < elem->nprops; j++) { - prop = elem->props[j]; - if (elem->store_prop[j] == OTHER_PROP) - elem_data = *other_ptr; - else - elem_data = (char *)elem_ptr; - if (prop->is_list) { - item = elem_data + prop->count_offset; - get_stored_item ((void *) item, prop->count_internal, - &int_val, &uint_val, &double_val); - write_ascii_item (fp, int_val, uint_val, double_val, - prop->count_external); - list_count = uint_val; - item_ptr = (char **) (elem_data + prop->offset); - item = item_ptr[0]; - item_size = ply_type_size[prop->internal_type]; - for (k = 0; k < list_count; k++) { - get_stored_item ((void *) item, prop->internal_type, - &int_val, &uint_val, &double_val); - write_ascii_item (fp, int_val, uint_val, double_val, - prop->external_type); - item += item_size; - } - } - else { - item = elem_data + prop->offset; - get_stored_item ((void *) item, prop->internal_type, - &int_val, &uint_val, &double_val); - write_ascii_item (fp, int_val, uint_val, double_val, - prop->external_type); - } - } - - fprintf (fp, "\n"); - } - else { - - /* write a binary file */ - - /* write out each property of the element */ - for (j = 0; j < elem->nprops; j++) { - prop = elem->props[j]; - if (elem->store_prop[j] == OTHER_PROP) - elem_data = *other_ptr; - else - elem_data = (char *)elem_ptr; - if (prop->is_list) { - item = elem_data + prop->count_offset; - item_size = ply_type_size[prop->count_internal]; - get_stored_item ((void *) item, prop->count_internal, - &int_val, &uint_val, &double_val); - write_binary_item (fp, plyfile->file_type, int_val, uint_val, - double_val, prop->count_external); - list_count = uint_val; - item_ptr = (char **) (elem_data + prop->offset); - item = item_ptr[0]; - item_size = ply_type_size[prop->internal_type]; - for (k = 0; k < list_count; k++) { - get_stored_item ((void *) item, prop->internal_type, - &int_val, &uint_val, &double_val); - write_binary_item (fp, plyfile->file_type, int_val, uint_val, - double_val, prop->external_type); - item += item_size; - } - } - else { - item = elem_data + prop->offset; - item_size = ply_type_size[prop->internal_type]; - get_stored_item ((void *) item, prop->internal_type, - &int_val, &uint_val, &double_val); - write_binary_item (fp, plyfile->file_type, int_val, uint_val, - double_val, prop->external_type); - } - } - - } -} - - -/****************************************************************************** -Specify a comment that will be written in the header. - - Entry: - plyfile - file identifier - comment - the comment to be written - ******************************************************************************/ - - void ply_put_comment(PlyFile *plyfile, char *comment) - { - /* (re)allocate space for new comment */ - if (plyfile->num_comments == 0) - plyfile->comments = (char **) myalloc (sizeof (char *)); - else - plyfile->comments = (char **) realloc (plyfile->comments, - sizeof (char *) * (plyfile->num_comments + 1)); - - /* add comment to list */ - plyfile->comments[plyfile->num_comments] = _strdup (comment); - plyfile->num_comments++; - } - - - /****************************************************************************** - Specify a piece of object information (arbitrary text) that will be written - in the header. - - Entry: - plyfile - file identifier - obj_info - the text information to be written - ******************************************************************************/ - - void ply_put_obj_info(PlyFile *plyfile, char *obj_info) - { - /* (re)allocate space for new info */ - if (plyfile->num_obj_info == 0) - plyfile->obj_info = (char **) myalloc (sizeof (char *)); - else - plyfile->obj_info = (char **) realloc (plyfile->obj_info, - sizeof (char *) * (plyfile->num_obj_info + 1)); - - /* add info to list */ - plyfile->obj_info[plyfile->num_obj_info] = _strdup (obj_info); - plyfile->num_obj_info++; - } - - - - - - - - /*************/ - /* Reading */ - /*************/ - - - - /****************************************************************************** - Given a file pointer, get ready to read PLY data from the file. - - Entry: - fp - the given file pointer - - Exit: - nelems - number of elements in object - elem_names - list of element names - returns a pointer to a PlyFile, used to refer to this file, or NULL if error - ******************************************************************************/ - - PlyFile *ply_read(FILE *fp, int *nelems, char ***elem_names) - { - int i,j; - PlyFile *plyfile; - int nwords; - char **words; - char **elist; - PlyElement *elem; - char *orig_line; - /* check for NULL file pointer */ - if (fp == NULL) - return (NULL); - - if (native_binary_type == -1) - get_native_binary_type(); - if (!types_checked) - check_types(); - /* create record for this object */ - - plyfile = (PlyFile *) myalloc (sizeof (PlyFile)); - plyfile->nelems = 0; - plyfile->comments = NULL; - plyfile->num_comments = 0; - plyfile->obj_info = NULL; - plyfile->num_obj_info = 0; - plyfile->fp = fp; - plyfile->other_elems = NULL; - - /* read and parse the file's header */ - - words = get_words (plyfile->fp, &nwords, &orig_line); - if (!words || !equal_strings (words[0], "ply")) - { - if (words) - free(words); - return (NULL); - } - while (words) { - /* parse words */ - - if (equal_strings (words[0], "format")) { - if (nwords != 3) { - free(words); - return (NULL); - } - if (equal_strings (words[1], "ascii")) - plyfile->file_type = PLY_ASCII; - else if (equal_strings (words[1], "binary_big_endian")) - plyfile->file_type = PLY_BINARY_BE; - else if (equal_strings (words[1], "binary_little_endian")) - plyfile->file_type = PLY_BINARY_LE; - else { - free(words); - return (NULL); - } - plyfile->version = (float)atof (words[2]); - } - else if (equal_strings (words[0], "element")) - add_element (plyfile, words); - else if (equal_strings (words[0], "property")) - add_property (plyfile, words); - else if (equal_strings (words[0], "comment")) - add_comment (plyfile, orig_line); - else if (equal_strings (words[0], "obj_info")) - add_obj_info (plyfile, orig_line); - else if (equal_strings (words[0], "end_header")) { - free(words); - break; - } - - /* free up words space */ - free (words); - - words = get_words (plyfile->fp, &nwords, &orig_line); - } - - /* create tags for each property of each element, to be used */ - /* later to say whether or not to store each property for the user */ - - for (i = 0; i < plyfile->nelems; i++) { - elem = plyfile->elems[i]; - elem->store_prop = (char *) myalloc (sizeof (char) * elem->nprops); - for (j = 0; j < elem->nprops; j++) - elem->store_prop[j] = DONT_STORE_PROP; - elem->other_offset = NO_OTHER_PROPS; /* no "other" props by default */ - } - - /* set return values about the elements */ - - elist = (char **) myalloc (sizeof (char *) * plyfile->nelems); - for (i = 0; i < plyfile->nelems; i++) - elist[i] = _strdup (plyfile->elems[i]->name); - - *elem_names = elist; - *nelems = plyfile->nelems; - - /* return a pointer to the file's information */ - - return (plyfile); -} - - -/****************************************************************************** -Open a polygon file for reading. - - Entry: - filename - name of file to read from - - Exit: - nelems - number of elements in object - elem_names - list of element names - file_type - file type, either ascii or binary - version - version number of PLY file - returns a file identifier, used to refer to this file, or NULL if error - ******************************************************************************/ - - PlyFile *ply_open_for_reading( - char *filename, - int *nelems, - char ***elem_names, - int *file_type, - float *version - ) - { - FILE *fp; - PlyFile *plyfile; - char *name; - - /* tack on the extension .ply, if necessary */ - - name = (char *) myalloc (int(sizeof (char) * (strlen (filename) + 5))); - strcpy (name, filename); - if (strlen (name) < 4 || - strcmp (name + strlen (name) - 4, ".ply") != 0) - strcat (name, ".ply"); - - /* open the file for reading */ - - fp = fopen (name, "rb"); - free(name); - if (fp == NULL) - return (NULL); - - /* create the PlyFile data structure */ - - plyfile = ply_read (fp, nelems, elem_names); - - /* determine the file type and version */ - - *file_type = plyfile->file_type; - *version = plyfile->version; - - /* return a pointer to the file's information */ - - return (plyfile); - } - - - /****************************************************************************** - Get information about a particular element. - - Entry: - plyfile - file identifier - elem_name - name of element to get information about - - Exit: - nelems - number of elements of this type in the file - nprops - number of properties - returns a list of properties, or NULL if the file doesn't contain that elem - ******************************************************************************/ - - PlyProperty **ply_get_element_description( - PlyFile *plyfile, - char *elem_name, - int *nelems, - int *nprops - ) - { - int i; - PlyElement *elem; - PlyProperty *prop; - PlyProperty **prop_list; - - /* find information about the element */ - elem = find_element (plyfile, elem_name); - if (elem == NULL) - return (NULL); - - *nelems = elem->num; - *nprops = elem->nprops; - - /* make a copy of the element's property list */ - prop_list = (PlyProperty **) myalloc (sizeof (PlyProperty *) * elem->nprops); - for (i = 0; i < elem->nprops; i++) { - prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); - copy_property (prop, elem->props[i]); - prop_list[i] = prop; - } - - /* return this duplicate property list */ - return (prop_list); - } - - - /****************************************************************************** - Specify which properties of an element are to be returned. This should be - called before a call to the routine ply_get_element(). - - Entry: - plyfile - file identifier - elem_name - which element we're talking about - nprops - number of properties - prop_list - list of properties - ******************************************************************************/ - - void ply_get_element_setup( - PlyFile *plyfile, - char *elem_name, - int nprops, - PlyProperty *prop_list - ) - { - int i; - PlyElement *elem; - PlyProperty *prop; - int index; - - /* find information about the element */ - elem = find_element (plyfile, elem_name); - plyfile->which_elem = elem; - - /* deposit the property information into the element's description */ - for (i = 0; i < nprops; i++) { - - /* look for actual property */ - prop = find_property (elem, prop_list[i].name, &index); - if (prop == NULL) { - fprintf (stderr, "Warning: Can't find property '%s' in element '%s'\n", - prop_list[i].name, elem_name); - continue; - } - - /* store its description */ - prop->internal_type = prop_list[i].internal_type; - prop->offset = prop_list[i].offset; - prop->count_internal = prop_list[i].count_internal; - prop->count_offset = prop_list[i].count_offset; - - /* specify that the user wants this property */ - elem->store_prop[index] = STORE_PROP; - } - } - - - /****************************************************************************** - Specify a property of an element that is to be returned. This should be - called (usually multiple times) before a call to the routine ply_get_element(). - This routine should be used in preference to the less flexible old routine - called ply_get_element_setup(). - - Entry: - plyfile - file identifier - elem_name - which element we're talking about - prop - property to add to those that will be returned - ******************************************************************************/ - - int ply_get_property( - PlyFile *plyfile, - char *elem_name, - PlyProperty *prop - ) - { - PlyElement *elem; - PlyProperty *prop_ptr; - int index; - - /* find information about the element */ - elem = find_element (plyfile, elem_name); - plyfile->which_elem = elem; - - /* deposit the property information into the element's description */ - - prop_ptr = find_property (elem, prop->name, &index); - if (prop_ptr == NULL) { -// fprintf (stderr, "Warning: Can't find property '%s' in element '%s'\n", -// prop->name, elem_name); -// return; - return 0; - } - prop_ptr->internal_type = prop->internal_type; - prop_ptr->offset = prop->offset; - prop_ptr->count_internal = prop->count_internal; - prop_ptr->count_offset = prop->count_offset; - - /* specify that the user wants this property */ - elem->store_prop[index] = STORE_PROP; - return 1; - } - - - /****************************************************************************** - Read one element from the file. This routine assumes that we're reading - the type of element specified in the last call to the routine - ply_get_element_setup(). - - Entry: - plyfile - file identifier - elem_ptr - pointer to location where the element information should be put - ******************************************************************************/ - - void ply_get_element(PlyFile *plyfile, void *elem_ptr) - { - if (plyfile->file_type == PLY_ASCII) - ascii_get_element (plyfile, (char *) elem_ptr); - else - binary_get_element (plyfile, (char *) elem_ptr); - } - - - /****************************************************************************** - Extract the comments from the header information of a PLY file. - - Entry: - plyfile - file identifier - - Exit: - num_comments - number of comments returned - returns a pointer to a list of comments - ******************************************************************************/ - - char **ply_get_comments(PlyFile *plyfile, int *num_comments) - { - *num_comments = plyfile->num_comments; - return (plyfile->comments); - } - - - /****************************************************************************** - Extract the object information (arbitrary text) from the header information - of a PLY file. - - Entry: - plyfile - file identifier - - Exit: - num_obj_info - number of lines of text information returned - returns a pointer to a list of object info lines - ******************************************************************************/ - - char **ply_get_obj_info(PlyFile *plyfile, int *num_obj_info) - { - *num_obj_info = plyfile->num_obj_info; - return (plyfile->obj_info); - } - - - /****************************************************************************** - Make ready for "other" properties of an element-- those properties that - the user has not explicitly asked for, but that are to be stashed away - in a special structure to be carried along with the element's other - information. - - Entry: - plyfile - file identifier - elem - element for which we want to save away other properties - ******************************************************************************/ - - void setup_other_props(PlyElement *elem) - { - int i; - PlyProperty *prop; - int size = 0; - int type_size; - - /* Examine each property in decreasing order of size. */ - /* We do this so that all data types will be aligned by */ - /* word, half-word, or whatever within the structure. */ - - for (type_size = 8; type_size > 0; type_size /= 2) { - - /* add up the space taken by each property, and save this information */ - /* away in the property descriptor */ - - for (i = 0; i < elem->nprops; i++) { - - /* don't bother with properties we've been asked to store explicitly */ - if (elem->store_prop[i]) - continue; - - prop = elem->props[i]; - - /* internal types will be same as external */ - prop->internal_type = prop->external_type; - prop->count_internal = prop->count_external; - - /* check list case */ - if (prop->is_list) { - - /* pointer to list */ - if (type_size == sizeof (void *)) { - prop->offset = size; - size += sizeof (void *); /* always use size of a pointer here */ - } - - /* count of number of list elements */ - if (type_size == ply_type_size[prop->count_external]) { - prop->count_offset = size; - size += ply_type_size[prop->count_external]; - } - } - /* not list */ - else if (type_size == ply_type_size[prop->external_type]) { - prop->offset = size; - size += ply_type_size[prop->external_type]; - } - } - - } - - /* save the size for the other_props structure */ - elem->other_size = size; - } - - - /****************************************************************************** - Specify that we want the "other" properties of an element to be tucked - away within the user's structure. The user needn't be concerned for how - these properties are stored. - - Entry: - plyfile - file identifier - elem_name - name of element that we want to store other_props in - offset - offset to where other_props will be stored inside user's structure - - Exit: - returns pointer to structure containing description of other_props - ******************************************************************************/ - - PlyOtherProp *ply_get_other_properties( - PlyFile *plyfile, - char *elem_name, - int offset - ) - { - int i; - PlyElement *elem; - PlyOtherProp *other; - PlyProperty *prop; - int nprops; - - /* find information about the element */ - elem = find_element (plyfile, elem_name); - if (elem == NULL) { - fprintf (stderr, "ply_get_other_properties: Can't find element '%s'\n", - elem_name); - return (NULL); - } - - /* remember that this is the "current" element */ - plyfile->which_elem = elem; - - /* save the offset to where to store the other_props */ - elem->other_offset = offset; - - /* place the appropriate pointers, etc. in the element's property list */ - setup_other_props (elem); - - /* create structure for describing other_props */ - other = (PlyOtherProp *) myalloc (sizeof (PlyOtherProp)); - other->name = _strdup (elem_name); - other->size = elem->other_size; - other->props = (PlyProperty **) myalloc (sizeof(PlyProperty) * elem->nprops); - - /* save descriptions of each "other" property */ - nprops = 0; - for (i = 0; i < elem->nprops; i++) { - if (elem->store_prop[i]) - continue; - prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); - copy_property (prop, elem->props[i]); - other->props[nprops] = prop; - nprops++; - } - other->nprops = nprops; - - /* set other_offset pointer appropriately if there are NO other properties */ - if (other->nprops == 0) { - elem->other_offset = NO_OTHER_PROPS; - } - - /* return structure */ - return (other); - } - - - - - /*************************/ - /* Other Element Stuff */ - /*************************/ - - - - - /****************************************************************************** - Grab all the data for an element that a user does not want to explicitly - read in. - - Entry: - plyfile - pointer to file - elem_name - name of element whose data is to be read in - elem_count - number of instances of this element stored in the file - - Exit: - returns pointer to ALL the "other" element data for this PLY file - ******************************************************************************/ - - PlyOtherElems *ply_get_other_element ( - PlyFile *plyfile, - char *elem_name, - int elem_count - ) - { - int i; - PlyElement *elem; - PlyOtherElems *other_elems; - OtherElem *other; - - /* look for appropriate element */ - elem = find_element (plyfile, elem_name); - if (elem == NULL) { - fprintf (stderr, - "ply_get_other_element: can't find element '%s'\n", elem_name); - exit (-1); - } - - /* create room for the new "other" element, initializing the */ - /* other data structure if necessary */ - - if (plyfile->other_elems == NULL) { - plyfile->other_elems = (PlyOtherElems *) myalloc (sizeof (PlyOtherElems)); - other_elems = plyfile->other_elems; - other_elems->other_list = (OtherElem *) myalloc (sizeof (OtherElem)); - other = &(other_elems->other_list[0]); - other_elems->num_elems = 1; - } - else { - other_elems = plyfile->other_elems; - other_elems->other_list = (OtherElem *) realloc (other_elems->other_list, - sizeof (OtherElem) * other_elems->num_elems + 1); - other = &(other_elems->other_list[other_elems->num_elems]); - other_elems->num_elems++; - } - - /* count of element instances in file */ - other->elem_count = elem_count; - - /* save name of element */ - other->elem_name = _strdup (elem_name); - - /* create a list to hold all the current elements */ - other->other_data = (OtherData **) - malloc (sizeof (OtherData *) * other->elem_count); - - /* set up for getting elements */ - other->other_props = ply_get_other_properties (plyfile, elem_name, - offsetof(OtherData,other_props)); - - /* grab all these elements */ - for (i = 0; i < other->elem_count; i++) { - /* grab and element from the file */ - other->other_data[i] = (OtherData *) malloc (sizeof (OtherData)); - ply_get_element (plyfile, (void *) other->other_data[i]); - } - - /* return pointer to the other elements data */ - return (other_elems); - } - - - /****************************************************************************** - Pass along a pointer to "other" elements that we want to save in a given - PLY file. These other elements were presumably read from another PLY file. - - Entry: - plyfile - file pointer in which to store this other element info - other_elems - info about other elements that we want to store - ******************************************************************************/ - - void ply_describe_other_elements ( - PlyFile *plyfile, - PlyOtherElems *other_elems - ) - { - int i; - OtherElem *other; - PlyElement *elem; - - /* ignore this call if there is no other element */ - if (other_elems == NULL) - return; - - /* save pointer to this information */ - plyfile->other_elems = other_elems; - - /* describe the other properties of this element */ - /* store them in the main element list as elements with - only other properties */ - - REALLOCN(plyfile->elems, PlyElement *, - plyfile->nelems, plyfile->nelems + other_elems->num_elems); - for (i = 0; i < other_elems->num_elems; i++) { - other = &(other_elems->other_list[i]); - elem = (PlyElement *) myalloc (sizeof (PlyElement)); - plyfile->elems[plyfile->nelems++] = elem; - elem->name = _strdup (other->elem_name); - elem->num = other->elem_count; - elem->nprops = 0; - ply_describe_other_properties (plyfile, other->other_props, - offsetof(OtherData,other_props)); - } - } - - - /****************************************************************************** - Write out the "other" elements specified for this PLY file. - - Entry: - plyfile - pointer to PLY file to write out other elements for - ******************************************************************************/ - - void ply_put_other_elements (PlyFile *plyfile) - { - int i,j; - OtherElem *other; - - /* make sure we have other elements to write */ - if (plyfile->other_elems == NULL) - return; - - /* write out the data for each "other" element */ - - for (i = 0; i < plyfile->other_elems->num_elems; i++) { - - other = &(plyfile->other_elems->other_list[i]); - ply_put_element_setup (plyfile, other->elem_name); - - /* write out each instance of the current element */ - for (j = 0; j < other->elem_count; j++) - ply_put_element (plyfile, (void *) other->other_data[j]); - } - } - - - /****************************************************************************** - Free up storage used by an "other" elements data structure. - - Entry: - other_elems - data structure to free up - ******************************************************************************/ - - void ply_free_other_elements (PlyOtherElems *other_elems) - { - other_elems = other_elems; - } - - - - /*******************/ - /* Miscellaneous */ - /*******************/ - - - - /****************************************************************************** - Close a PLY file. - - Entry: - plyfile - identifier of file to close - ******************************************************************************/ - - void ply_close(PlyFile *plyfile) - { - fclose (plyfile->fp); - - /* free up memory associated with the PLY file */ - free (plyfile); - } - - - /****************************************************************************** - Get version number and file type of a PlyFile. - - Entry: - ply - pointer to PLY file - - Exit: - version - version of the file - file_type - PLY_ASCII, PLY_BINARY_BE, or PLY_BINARY_LE - ******************************************************************************/ - - void ply_get_info(PlyFile *ply, float *version, int *file_type) - { - if (ply == NULL) - return; - - *version = ply->version; - *file_type = ply->file_type; - } - - - /****************************************************************************** - Compare two strings. Returns 1 if they are the same, 0 if not. - ******************************************************************************/ - - int equal_strings(const char *s1, const char *s2) - { - - while (*s1 && *s2) - if (*s1++ != *s2++) - return (0); - - if (*s1 != *s2) - return (0); - else - return (1); - } - - - /****************************************************************************** - Find an element from the element list of a given PLY object. - - Entry: - plyfile - file id for PLY file - element - name of element we're looking for - - Exit: - returns the element, or NULL if not found - ******************************************************************************/ - - PlyElement *find_element(PlyFile *plyfile, const char *element) - { - int i; - - for (i = 0; i < plyfile->nelems; i++) - if (equal_strings (element, plyfile->elems[i]->name)) - return (plyfile->elems[i]); - - return (NULL); - } - - - /****************************************************************************** - Find a property in the list of properties of a given element. - - Entry: - elem - pointer to element in which we want to find the property - prop_name - name of property to find - - Exit: - index - index to position in list - returns a pointer to the property, or NULL if not found - ******************************************************************************/ - - PlyProperty *find_property(PlyElement *elem, const char *prop_name, int *index) - { - int i; - - for (i = 0; i < elem->nprops; i++) - if (equal_strings (prop_name, elem->props[i]->name)) { - *index = i; - return (elem->props[i]); - } - - *index = -1; - return (NULL); - } - - - /****************************************************************************** - Read an element from an ascii file. - - Entry: - plyfile - file identifier - elem_ptr - pointer to element - ******************************************************************************/ - - void ascii_get_element(PlyFile *plyfile, char *elem_ptr) - { - int j,k; - PlyElement *elem; - PlyProperty *prop; - char **words; - int nwords; - int which_word; - char *elem_data,*item=NULL; - char *item_ptr; - int item_size; - int int_val; - unsigned int uint_val; - double double_val; - int list_count; - int store_it; - char **store_array; - char *orig_line; - char *other_data=NULL; - int other_flag; - - /* the kind of element we're reading currently */ - elem = plyfile->which_elem; - - /* do we need to setup for other_props? */ - - if (elem->other_offset != NO_OTHER_PROPS) { - char **ptr; - other_flag = 1; - /* make room for other_props */ - other_data = (char *) myalloc (elem->other_size); - /* store pointer in user's structure to the other_props */ - ptr = (char **) (elem_ptr + elem->other_offset); - *ptr = other_data; - } - else - other_flag = 0; - - /* read in the element */ - - words = get_words (plyfile->fp, &nwords, &orig_line); - if (words == NULL) { - fprintf (stderr, "ply_get_element: unexpected end of file\n"); - exit (-1); - } - - which_word = 0; - - for (j = 0; j < elem->nprops; j++) { - - prop = elem->props[j]; - store_it = (elem->store_prop[j] | other_flag); - - /* store either in the user's structure or in other_props */ - if (elem->store_prop[j]) - elem_data = elem_ptr; - else - elem_data = other_data; - - if (prop->is_list) { /* a list */ - - /* get and store the number of items in the list */ - get_ascii_item (words[which_word++], prop->count_external, - &int_val, &uint_val, &double_val); - if (store_it) { - item = elem_data + prop->count_offset; - store_item(item, prop->count_internal, int_val, uint_val, double_val); - } - - /* allocate space for an array of items and store a ptr to the array */ - list_count = int_val; - item_size = ply_type_size[prop->internal_type]; - store_array = (char **) (elem_data + prop->offset); - - if (list_count == 0) { - if (store_it) - *store_array = NULL; - } - else { - if (store_it) { - item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count); - item = item_ptr; - *store_array = item_ptr; - } - - /* read items and store them into the array */ - for (k = 0; k < list_count; k++) { - get_ascii_item (words[which_word++], prop->external_type, - &int_val, &uint_val, &double_val); - if (store_it) { - store_item (item, prop->internal_type, - int_val, uint_val, double_val); - item += item_size; - } - } - } - - } - else { /* not a list */ - get_ascii_item (words[which_word++], prop->external_type, - &int_val, &uint_val, &double_val); - if (store_it) { - item = elem_data + prop->offset; - store_item (item, prop->internal_type, int_val, uint_val, double_val); - } - } - - } - - free (words); -} - - -/****************************************************************************** -Read an element from a binary file. - - Entry: - plyfile - file identifier - elem_ptr - pointer to an element - ******************************************************************************/ - - void binary_get_element(PlyFile *plyfile, char *elem_ptr) - { - int j,k; - PlyElement *elem; - PlyProperty *prop; - FILE *fp = plyfile->fp; - char *elem_data,*item=NULL; - char *item_ptr; - int item_size; - int int_val; - unsigned int uint_val; - double double_val; - int list_count; - int store_it; - char **store_array; - char *other_data=NULL; - int other_flag; - - /* the kind of element we're reading currently */ - elem = plyfile->which_elem; - - /* do we need to setup for other_props? */ - - if (elem->other_offset != NO_OTHER_PROPS) { - char **ptr; - other_flag = 1; - /* make room for other_props */ - other_data = (char *) myalloc (elem->other_size); - /* store pointer in user's structure to the other_props */ - ptr = (char **) (elem_ptr + elem->other_offset); - *ptr = other_data; - } - else - other_flag = 0; - - /* read in a number of elements */ - - for (j = 0; j < elem->nprops; j++) { - - prop = elem->props[j]; - store_it = (elem->store_prop[j] | other_flag); - - /* store either in the user's structure or in other_props */ - if (elem->store_prop[j]) - elem_data = elem_ptr; - else - elem_data = other_data; - - if (prop->is_list) { /* a list */ - - /* get and store the number of items in the list */ - get_binary_item (fp, plyfile->file_type, prop->count_external, - &int_val, &uint_val, &double_val); - if (store_it) { - item = elem_data + prop->count_offset; - store_item(item, prop->count_internal, int_val, uint_val, double_val); - } - - /* allocate space for an array of items and store a ptr to the array */ - list_count = int_val; - item_size = ply_type_size[prop->internal_type]; - store_array = (char **) (elem_data + prop->offset); - if (list_count == 0) { - if (store_it) - *store_array = NULL; - } - else { - if (store_it) { - item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count); - item = item_ptr; - *store_array = item_ptr; - } - - /* read items and store them into the array */ - for (k = 0; k < list_count; k++) { - get_binary_item (fp, plyfile->file_type, prop->external_type, - &int_val, &uint_val, &double_val); - if (store_it) { - store_item (item, prop->internal_type, - int_val, uint_val, double_val); - item += item_size; - } - } - } - - } - else { /* not a list */ - get_binary_item (fp, plyfile->file_type, prop->external_type, - &int_val, &uint_val, &double_val); - if (store_it) { - item = elem_data + prop->offset; - store_item (item, prop->internal_type, int_val, uint_val, double_val); - } - } - - } - } - - - /****************************************************************************** - Write to a file the word that represents a PLY data type. - - Entry: - fp - file pointer - 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) { - fprintf (stderr, "write_scalar_type: bad data code = %d\n", code); - exit (-1); - } - - /* write the code to a file */ - - fprintf (fp, "%s", type_names[code]); - } - - /****************************************************************************** - Reverse the order in an array of bytes. This is the conversion from big - endian to little endian and vice versa - - Entry: - bytes - array of bytes to reverse (in place) - num_bytes - number of bytes in array - ******************************************************************************/ - - void swap_bytes(char *bytes, int num_bytes) - { - int i; - char temp; - - for (i=0; i < num_bytes/2; i++) - { - temp = bytes[i]; - bytes[i] = bytes[(num_bytes-1)-i]; - bytes[(num_bytes-1)-i] = temp; - } - } - - /****************************************************************************** - Find out if this machine is big endian or little endian - - Exit: - set global variable, native_binary_type = - either PLY_BINARY_BE or PLY_BINARY_LE - - ******************************************************************************/ - - void get_native_binary_type() - { - endian_test_type test; - - test.int_value = 0; - 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 - { - fprintf(stderr, "ply: Couldn't determine machine endianness.\n"); - fprintf(stderr, "ply: Exiting...\n"); - exit(1); - } - } - - /****************************************************************************** - Verify that all the native types are the sizes we need - - - ******************************************************************************/ - - void check_types() - { - if ((ply_type_size[PLY_CHAR] != sizeof(char)) || - (ply_type_size[PLY_SHORT] != sizeof(short)) || - (ply_type_size[PLY_INT] != sizeof(int)) || - (ply_type_size[PLY_UCHAR] != sizeof(unsigned char)) || - (ply_type_size[PLY_USHORT] != sizeof(unsigned short)) || - (ply_type_size[PLY_UINT] != sizeof(unsigned int)) || - (ply_type_size[PLY_FLOAT] != sizeof(float)) || - (ply_type_size[PLY_DOUBLE] != sizeof(double))) - { - fprintf(stderr, "ply: Type sizes do not match built-in types\n"); - fprintf(stderr, "ply: Exiting...\n"); - exit(1); - } - - types_checked = 1; - } - - /****************************************************************************** - Get a text line from a file and break it up into words. - - IMPORTANT: The calling routine call "free" on the returned pointer once - finished with it. - - Entry: - fp - file to read from - - Exit: - nwords - number of words returned - orig_line - the original line of characters - returns a list of words from the line, or NULL if end-of-file - ******************************************************************************/ - - char **get_words(FILE *fp, int *nwords, char **orig_line) - { -#define BIG_STRING 4096 - static char str[BIG_STRING]; - static char str_copy[BIG_STRING]; - char **words; - int max_words = 10; - int num_words = 0; - char *ptr,*ptr2; - char *result; - - words = (char **) myalloc (sizeof (char *) * max_words); - - /* read in a line */ - result = fgets (str, BIG_STRING, fp); - if (result == NULL) { - free(words); - *nwords = 0; - *orig_line = NULL; - return (NULL); - } - /* convert line-feed and tabs into spaces */ - /* (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'; - - for (ptr = str, ptr2 = str_copy; *ptr != '\0'; ptr++, ptr2++) { - *ptr2 = *ptr; - // Added line here to manage carriage returns - if (*ptr == '\t' || *ptr == '\r') { - *ptr = ' '; - *ptr2 = ' '; - } - else if (*ptr == '\n') { - *ptr = ' '; - *ptr2 = '\0'; - break; - } - } - - /* find the words in the line */ - - ptr = str; - while (*ptr != '\0') { - - /* jump over leading spaces */ - while (*ptr == ' ') - ptr++; - - /* break if we reach the end */ - if (*ptr == '\0') - break; - - /* save pointer to beginning of word */ - if (num_words >= max_words) { - max_words += 10; - words = (char **) realloc (words, sizeof (char *) * max_words); - } - words[num_words++] = ptr; - - /* jump over non-spaces */ - while (*ptr != ' ') - ptr++; - - /* place a null character here to mark the end of the word */ - *ptr++ = '\0'; - } - - /* return the list of words */ - *nwords = num_words; - *orig_line = str_copy; - return (words); - } - - - /****************************************************************************** - Return the value of an item, given a pointer to it and its type. - - Entry: - item - pointer to item - type - data type that "item" points to - - Exit: - returns a double-precision float that contains the value of the item - ******************************************************************************/ - - double get_item_value(char *item, int type) - { - unsigned char *puchar; - char *pchar; - short int *pshort; - unsigned short int *pushort; - int *pint; - unsigned int *puint; - float *pfloat; - double *pdouble; - int int_value; - unsigned int uint_value; - double double_value; - - switch (type) { - case PLY_CHAR: - case PLY_INT_8: - pchar = (char *) item; - int_value = *pchar; - return ((double) int_value); - case PLY_UCHAR: - case PLY_UINT_8: - puchar = (unsigned char *) item; - int_value = *puchar; - return ((double) int_value); - case PLY_SHORT: - case PLY_INT_16: - pshort = (short int *) item; - int_value = *pshort; - return ((double) int_value); - case PLY_USHORT: - case PLY_UINT_16: - pushort = (unsigned short int *) item; - int_value = *pushort; - return ((double) int_value); - case PLY_INT: - case PLY_INT_32: - pint = (int *) item; - int_value = *pint; - return ((double) int_value); - case PLY_UINT: - case PLY_UINT_32: - puint = (unsigned int *) item; - uint_value = *puint; - return ((double) uint_value); - case PLY_FLOAT: - case PLY_FLOAT_32: - pfloat = (float *) item; - double_value = *pfloat; - return (double_value); - case PLY_DOUBLE: - case PLY_FLOAT_64: - pdouble = (double *) item; - double_value = *pdouble; - return (double_value); - default: - fprintf (stderr, "get_item_value: bad type = %d\n", type); - exit (-1); - } - } - - - /****************************************************************************** - Write out an item to a file as raw binary bytes. - - Entry: - fp - file to write to - int_val - integer version of item - uint_val - unsigned integer version of item - double_val - double-precision float version of item - type - data type to write out - ******************************************************************************/ - - void write_binary_item( - FILE *fp, - int file_type, - int int_val, - unsigned int uint_val, - double double_val, - int type - ) - { - unsigned char uchar_val; - char char_val; - unsigned short ushort_val; - short short_val; - float float_val; - void *value; - - switch (type) { - case PLY_CHAR: - case PLY_INT_8: - char_val = char(int_val); - value = &char_val; - break; - case PLY_SHORT: - case PLY_INT_16: - short_val = short(int_val); - value = &short_val; - break; - case PLY_INT: - case PLY_INT_32: - value = &int_val; - break; - case PLY_UCHAR: - case PLY_UINT_8: - uchar_val = (unsigned char)(uint_val); - value = &uchar_val; - break; - case PLY_USHORT: - case PLY_UINT_16: - ushort_val = (unsigned short)(uint_val); - value = &ushort_val; - break; - case PLY_UINT: - case PLY_UINT_32: - value = &uint_val; - break; - case PLY_FLOAT: - case PLY_FLOAT_32: - float_val = (float)double_val; - value = &float_val; - break; - case PLY_DOUBLE: - case PLY_FLOAT_64: - value = &double_val; - break; - default: - fprintf (stderr, "write_binary_item: bad type = %d\n", type); - exit (-1); - } - - - 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) - { - fprintf(stderr, "PLY ERROR: fwrite() failed -- aborting.\n"); - exit(1); - } - } - - - /****************************************************************************** - Write out an item to a file as ascii characters. - - Entry: - fp - file to write to - int_val - integer version of item - uint_val - unsigned integer version of item - double_val - double-precision float version of item - type - data type to write out - ******************************************************************************/ - - void write_ascii_item( - FILE *fp, - int int_val, - unsigned int uint_val, - double double_val, - int type - ) - { - switch (type) { - case PLY_CHAR: - case PLY_INT_8: - case PLY_SHORT: - case PLY_INT_16: - case PLY_INT: - case PLY_INT_32: - if (fprintf (fp, "%d ", int_val) <= 0) - { - fprintf(stderr, "PLY ERROR: fprintf() failed -- aborting.\n"); - exit(1); - } - break; - case PLY_UCHAR: - case PLY_UINT_8: - case PLY_USHORT: - case PLY_UINT_16: - case PLY_UINT: - case PLY_UINT_32: - - if (fprintf (fp, "%u ", uint_val) <= 0) - { - fprintf(stderr, "PLY ERROR: fprintf() failed -- aborting.\n"); - exit(1); - } - break; - case PLY_FLOAT: - case PLY_FLOAT_32: - case PLY_DOUBLE: - case PLY_FLOAT_64: - if (fprintf (fp, "%g ", double_val) <= 0) - { - fprintf(stderr, "PLY ERROR: fprintf() failed -- aborting.\n"); - exit(1); - } - break; - default: - fprintf (stderr, "write_ascii_item: bad type = %d\n", type); - exit (-1); - } - } - - - /****************************************************************************** - Write out an item to a file as ascii characters. - - Entry: - fp - file to write to - item - pointer to item to write - type - data type that "item" points to - - Exit: - returns a double-precision float that contains the value of the written item - ******************************************************************************/ - - double old_write_ascii_item(FILE *fp, char *item, int type) - { - unsigned char *puchar; - char *pchar; - short int *pshort; - unsigned short int *pushort; - int *pint; - unsigned int *puint; - float *pfloat; - double *pdouble; - int int_value; - unsigned int uint_value; - double double_value; - - switch (type) { - case PLY_CHAR: - case PLY_INT_8: - pchar = (char *) item; - int_value = *pchar; - fprintf (fp, "%d ", int_value); - return ((double) int_value); - case PLY_UCHAR: - case PLY_UINT_8: - puchar = (unsigned char *) item; - int_value = *puchar; - fprintf (fp, "%d ", int_value); - return ((double) int_value); - case PLY_SHORT: - case PLY_INT_16: - pshort = (short int *) item; - int_value = *pshort; - fprintf (fp, "%d ", int_value); - return ((double) int_value); - case PLY_USHORT: - case PLY_UINT_16: - pushort = (unsigned short int *) item; - int_value = *pushort; - fprintf (fp, "%d ", int_value); - return ((double) int_value); - case PLY_INT: - case PLY_INT_32: - pint = (int *) item; - int_value = *pint; - fprintf (fp, "%d ", int_value); - return ((double) int_value); - case PLY_UINT: - case PLY_UINT_32: - puint = (unsigned int *) item; - uint_value = *puint; - fprintf (fp, "%u ", uint_value); - return ((double) uint_value); - case PLY_FLOAT: - case PLY_FLOAT_32: - pfloat = (float *) item; - double_value = *pfloat; - fprintf (fp, "%g ", double_value); - return (double_value); - case PLY_DOUBLE: - case PLY_FLOAT_64: - pdouble = (double *) item; - double_value = *pdouble; - fprintf (fp, "%g ", double_value); - return (double_value); - default: - fprintf (stderr, "old_write_ascii_item: bad type = %d\n", type); - exit (-1); - } - } - - - /****************************************************************************** - Get the value of an item that is in memory, and place the result - into an integer, an unsigned integer and a double. - - Entry: - ptr - pointer to the item - type - data type supposedly in the item - - Exit: - int_val - integer value - uint_val - unsigned integer value - double_val - double-precision floating point value - ******************************************************************************/ - - void get_stored_item( - void *ptr, - int type, - int *int_val, - unsigned int *uint_val, - double *double_val - ) - { - switch (type) { - case PLY_CHAR: - case PLY_INT_8: - *int_val = *((char *) ptr); - *uint_val = *int_val; - *double_val = *int_val; - break; - case PLY_UCHAR: - case PLY_UINT_8: - *uint_val = *((unsigned char *) ptr); - *int_val = *uint_val; - *double_val = *uint_val; - break; - case PLY_SHORT: - case PLY_INT_16: - *int_val = *((short int *) ptr); - *uint_val = *int_val; - *double_val = *int_val; - break; - case PLY_USHORT: - case PLY_UINT_16: - *uint_val = *((unsigned short int *) ptr); - *int_val = *uint_val; - *double_val = *uint_val; - break; - case PLY_INT: - case PLY_INT_32: - *int_val = *((int *) ptr); - *uint_val = *int_val; - *double_val = *int_val; - break; - case PLY_UINT: - case PLY_UINT_32: - *uint_val = *((unsigned int *) ptr); - *int_val = *uint_val; - *double_val = *uint_val; - break; - case PLY_FLOAT: - case PLY_FLOAT_32: - *double_val = *((float *) ptr); - *int_val = (int) *double_val; - *uint_val = (unsigned int) *double_val; - break; - case PLY_DOUBLE: - case PLY_FLOAT_64: - *double_val = *((double *) ptr); - *int_val = (int) *double_val; - *uint_val = (unsigned int) *double_val; - break; - default: - fprintf (stderr, "get_stored_item: bad type = %d\n", type); - exit (-1); - } - } - - - /****************************************************************************** - Get the value of an item from a binary file, and place the result - into an integer, an unsigned integer and a double. - - Entry: - fp - file to get item from - type - data type supposedly in the word - - Exit: - int_val - integer value - uint_val - unsigned integer value - double_val - double-precision floating point value - ******************************************************************************/ - - void get_binary_item( - FILE *fp, - int file_type, - int type, - int *int_val, - unsigned int *uint_val, - double *double_val - ) - { - char c[8]; - void *ptr; - - ptr = (void *) c; - - if (fread (ptr, ply_type_size[type], 1, fp) != 1) - { - fprintf(stderr, "PLY ERROR: fread() failed -- aborting.\n"); - exit(1); - } - - - if ((file_type != native_binary_type) && (ply_type_size[type] > 1)) - swap_bytes((char *)ptr, ply_type_size[type]); - - switch (type) { - case PLY_CHAR: - case PLY_INT_8: - *int_val = *((char *) ptr); - *uint_val = *int_val; - *double_val = *int_val; - break; - case PLY_UCHAR: - case PLY_UINT_8: - *uint_val = *((unsigned char *) ptr); - *int_val = *uint_val; - *double_val = *uint_val; - break; - case PLY_SHORT: - case PLY_INT_16: - *int_val = *((short int *) ptr); - *uint_val = *int_val; - *double_val = *int_val; - break; - case PLY_USHORT: - case PLY_UINT_16: - *uint_val = *((unsigned short int *) ptr); - *int_val = *uint_val; - *double_val = *uint_val; - break; - case PLY_INT: - case PLY_INT_32: - *int_val = *((int *) ptr); - *uint_val = *int_val; - *double_val = *int_val; - break; - case PLY_UINT: - case PLY_UINT_32: - *uint_val = *((unsigned int *) ptr); - *int_val = *uint_val; - *double_val = *uint_val; - break; - case PLY_FLOAT: - case PLY_FLOAT_32: - *double_val = *((float *) ptr); - *int_val = (int) *double_val; - *uint_val = (unsigned int) *double_val; - break; - case PLY_DOUBLE: - case PLY_FLOAT_64: - *double_val = *((double *) ptr); - *int_val = (int) *double_val; - *uint_val = (unsigned int) *double_val; - break; - default: - fprintf (stderr, "get_binary_item: bad type = %d\n", type); - exit (-1); - } - } - - - /****************************************************************************** - Extract the value of an item from an ascii word, and place the result - into an integer, an unsigned integer and a double. - - Entry: - word - word to extract value from - type - data type supposedly in the word - - Exit: - int_val - integer value - uint_val - unsigned integer value - double_val - double-precision floating point value - ******************************************************************************/ - - void get_ascii_item( - char *word, - int type, - int *int_val, - unsigned int *uint_val, - double *double_val - ) - { - switch (type) { - case PLY_CHAR: - case PLY_INT_8: - case PLY_UCHAR: - case PLY_UINT_8: - case PLY_SHORT: - case PLY_INT_16: - case PLY_USHORT: - case PLY_UINT_16: - case PLY_INT: - case PLY_INT_32: - *int_val = atoi (word); - *uint_val = (unsigned int) *int_val; - *double_val = (double) *int_val; - break; - - case PLY_UINT: - case PLY_UINT_32: - *uint_val = strtol (word, (char **) NULL, 10); - *int_val = (int) *uint_val; - *double_val = (double) *uint_val; - break; - - case PLY_FLOAT: - case PLY_FLOAT_32: - case PLY_DOUBLE: - case PLY_FLOAT_64: - *double_val = atof (word); - *int_val = (int) *double_val; - *uint_val = (unsigned int) *double_val; - break; - - default: - fprintf (stderr, "get_ascii_item: bad type = %d\n", type); - exit (-1); - } - } - - - /****************************************************************************** - Store a value into a place being pointed to, guided by a data type. - - Entry: - item - place to store value - type - data type - int_val - integer version of value - uint_val - unsigned integer version of value - double_val - double version of value - - Exit: - item - pointer to stored value - ******************************************************************************/ - - void store_item ( - char *item, - int type, - int int_val, - unsigned int uint_val, - double double_val - ) - { - unsigned char *puchar; - short int *pshort; - unsigned short int *pushort; - int *pint; - unsigned int *puint; - float *pfloat; - double *pdouble; - - - switch (type) { - case PLY_CHAR: - case PLY_INT_8: - *item = char(int_val); - break; - case PLY_UCHAR: - case PLY_UINT_8: - puchar = (unsigned char *) item; - *puchar = (unsigned char)(uint_val); - break; - case PLY_SHORT: - case PLY_INT_16: - pshort = (short *) item; - *pshort = short(int_val); - break; - case PLY_USHORT: - case PLY_UINT_16: - pushort = (unsigned short *) item; - *pushort = (unsigned short)(uint_val); - break; - case PLY_INT: - case PLY_INT_32: - pint = (int *) item; - *pint = int_val; - break; - case PLY_UINT: - case PLY_UINT_32: - puint = (unsigned int *) item; - *puint = uint_val; - break; - case PLY_FLOAT: - case PLY_FLOAT_32: - pfloat = (float *) item; - *pfloat = (float)double_val; - break; - case PLY_DOUBLE: - case PLY_FLOAT_64: - pdouble = (double *) item; - *pdouble = double_val; - break; - default: - fprintf (stderr, "store_item: bad type = %d\n", type); - exit (-1); - } - } - - - /****************************************************************************** - Add an element to a PLY file descriptor. - - Entry: - plyfile - PLY file descriptor - words - list of words describing the element - nwords - number of words in the list - ******************************************************************************/ - - void add_element (PlyFile *plyfile, char **words) - { - PlyElement *elem; - - /* create the new element */ - elem = (PlyElement *) myalloc (sizeof (PlyElement)); - elem->name = _strdup (words[1]); - elem->num = atoi (words[2]); - elem->nprops = 0; - - /* make room for new element in the object's list of elements */ - if (plyfile->nelems == 0) - plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *)); - else - plyfile->elems = (PlyElement **) realloc (plyfile->elems, - sizeof (PlyElement *) * (plyfile->nelems + 1)); - - /* add the new element to the object's list */ - plyfile->elems[plyfile->nelems] = elem; - plyfile->nelems++; - } - - - /****************************************************************************** - Return the type of a property, given the name of the property. - - Entry: - name - name of property type - - Exit: - returns integer code for property, or 0 if not found - ******************************************************************************/ - - int get_prop_type(char *type_name) - { - int i; - - for (i = PLY_START_TYPE + 1; i < PLY_END_TYPE; i++) - if (equal_strings (type_name, type_names[i])) - return (i); - - /* if we get here, we didn't find the type */ - return (0); - } - - - /****************************************************************************** - Add a property to a PLY file descriptor. - - Entry: - plyfile - PLY file descriptor - words - list of words describing the property - nwords - number of words in the list - ******************************************************************************/ - - void add_property (PlyFile *plyfile, char **words) - { - PlyProperty *prop; - PlyElement *elem; - - /* create the new property */ - - prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); - - if (equal_strings (words[1], "list")) { /* is a list */ - prop->count_external = get_prop_type (words[2]); - prop->external_type = get_prop_type (words[3]); - prop->name = _strdup (words[4]); - prop->is_list = 1; - } - else { /* not a list */ - prop->external_type = get_prop_type (words[1]); - prop->name = _strdup (words[2]); - prop->is_list = 0; - } - - /* add this property to the list of properties of the current element */ - - elem = plyfile->elems[plyfile->nelems - 1]; - - if (elem->nprops == 0) - elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *)); - else - elem->props = (PlyProperty **) realloc (elem->props, - sizeof (PlyProperty *) * (elem->nprops + 1)); - - elem->props[elem->nprops] = prop; - elem->nprops++; - } - - - /****************************************************************************** - Add a comment to a PLY file descriptor. - - Entry: - plyfile - PLY file descriptor - line - line containing comment - ******************************************************************************/ - - void add_comment (PlyFile *plyfile, char *line) - { - int i; - - /* skip over "comment" and leading spaces and tabs */ - i = 7; - while (line[i] == ' ' || line[i] == '\t') - i++; - - ply_put_comment (plyfile, &line[i]); - } - - - /****************************************************************************** - Add a some object information to a PLY file descriptor. - - Entry: - plyfile - PLY file descriptor - line - line containing text info - ******************************************************************************/ - - void add_obj_info (PlyFile *plyfile, char *line) - { - int i; - - /* skip over "obj_info" and leading spaces and tabs */ - i = 8; - while (line[i] == ' ' || line[i] == '\t') - i++; - - ply_put_obj_info (plyfile, &line[i]); - } - - - /****************************************************************************** - Copy a property. - ******************************************************************************/ - - void copy_property(PlyProperty *dest, PlyProperty *src) - { - dest->name = _strdup (src->name); - dest->external_type = src->external_type; - dest->internal_type = src->internal_type; - dest->offset = src->offset; - - dest->is_list = src->is_list; - dest->count_external = src->count_external; - dest->count_internal = src->count_internal; - dest->count_offset = src->count_offset; - } - - - /****************************************************************************** - Allocate some memory. - - Entry: - size - amount of memory requested (in bytes) - lnum - line number from which memory was requested - fname - file name from which memory was requested - ******************************************************************************/ - - char *my_alloc(int size, int lnum, const char *fname) - { - char *ptr; - - ptr = (char *) malloc (size); - - if (ptr == 0) { - fprintf(stderr, "Memory allocation bombed on line %d in %s\n", lnum, fname); - } - - return (ptr); - } - diff --git a/Src/PointStream.h b/Src/PointStream.h deleted file mode 100644 index fc4cb4ce..00000000 --- a/Src/PointStream.h +++ /dev/null @@ -1,241 +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 writften permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#ifndef POINT_STREAM_INCLUDED -#define POINT_STREAM_INCLUDED -#include "Ply.h" -#include "Geometry.h" - - -template< class Real > -class OrientedPointStream -{ -public: - virtual ~OrientedPointStream( void ){} - virtual void reset( void ) = 0; - virtual bool nextPoint( OrientedPoint3D< Real >& p ) = 0; - virtual int nextPoints( OrientedPoint3D< Real >* p , int count ) - { - int c=0; - for( int i=0 ; i& min , Point3D< Real >& max ) - { - bool first = true; - OrientedPoint3D< Real > p; - while( nextPoint( p ) ) - { - for( int i=0 ; i<3 ; i++ ) - { - if( first || p.p[i]max[i] ) max[i] = p.p[i]; - } - first = false; - } - reset(); - } -}; - -template< class Real , class Data > -class OrientedPointStreamWithData : public OrientedPointStream< Real > -{ -public: - virtual ~OrientedPointStreamWithData( void ){} - virtual void reset( void ) = 0; - virtual bool nextPoint( OrientedPoint3D< Real >& p , Data& d ) = 0; - - virtual bool nextPoint( OrientedPoint3D< Real >& p ){ Data d ; return nextPoint( p , d ); } - virtual int nextPoints( OrientedPoint3D< Real >* p , Data* d , int count ) - { - int c=0; - for( int i=0 ; i* p , int count ){ return OrientedPointStream< Real >::nextPoints( p , count ); } -}; - -template< class Real > -class TransformedOrientedPointStream : public OrientedPointStream< Real > -{ - XForm4x4< Real > _xForm; - XForm3x3< Real > _normalXForm; - OrientedPointStream< Real >& _stream; -public: - TransformedOrientedPointStream( XForm4x4< Real > xForm , OrientedPointStream< Real >& stream ) : _xForm(xForm) , _stream(stream) - { - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) _normalXForm(i,j) = _xForm(i,j); - _normalXForm = _normalXForm.transpose().inverse(); - }; - virtual void reset( void ){ _stream.reset(); } - virtual bool nextPoint( OrientedPoint3D< Real >& p ) - { - bool ret = _stream.nextPoint( p ); - p.p = _xForm * p.p , p.n = _normalXForm * p.n; - return ret; - } -}; - -template< class Real , class Data > -class TransformedOrientedPointStreamWithData : public OrientedPointStreamWithData< Real , Data > -{ - XForm4x4< Real > _xForm; - XForm3x3< Real > _normalXForm; - OrientedPointStreamWithData< Real , Data >& _stream; -public: - TransformedOrientedPointStreamWithData( XForm4x4< Real > xForm , OrientedPointStreamWithData< Real , Data >& stream ) : _xForm(xForm) , _stream(stream) - { - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) _normalXForm(i,j) = _xForm(i,j); - _normalXForm = _normalXForm.transpose().inverse(); - }; - virtual void reset( void ){ _stream.reset(); } - virtual bool nextPoint( OrientedPoint3D< Real >& p , Data& d ) - { - bool ret = _stream.nextPoint( p , d ); - p.p = _xForm * p.p , p.n = _normalXForm * p.n; - return ret; - } -}; - -template< class Real > -class MemoryOrientedPointStream : public OrientedPointStream< Real > -{ - const OrientedPoint3D< Real >* _points; - size_t _pointCount; - size_t _current; -public: - MemoryOrientedPointStream( size_t pointCount , const OrientedPoint3D< Real >* points ); - ~MemoryOrientedPointStream( void ); - void reset( void ); - bool nextPoint( OrientedPoint3D< Real >& p ); -}; - -template< class Real , class Data > -class MemoryOrientedPointStreamWithData : public OrientedPointStreamWithData< Real , Data > -{ - const std::pair< OrientedPoint3D< Real > , Data >* _points; - size_t _pointCount; - size_t _current; -public: - MemoryOrientedPointStreamWithData( size_t pointCount , const std::pair< OrientedPoint3D< Real > , Data >* points ); - ~MemoryOrientedPointStreamWithData( void ); - void reset( void ); - bool nextPoint( OrientedPoint3D< Real >& p , Data& d ); -}; - -template< class Real > -class ASCIIOrientedPointStream : public OrientedPointStream< Real > -{ - FILE* _fp; -public: - ASCIIOrientedPointStream( const char* fileName ); - ~ASCIIOrientedPointStream( void ); - void reset( void ); - bool nextPoint( OrientedPoint3D< Real >& p ); -}; - -template< class Real , class Data > -class ASCIIOrientedPointStreamWithData : public OrientedPointStreamWithData< Real , Data > -{ - FILE* _fp; - Data (*_readData)( FILE* ); -public: - ASCIIOrientedPointStreamWithData( const char* fileName , Data (*readData)( FILE* ) ); - ~ASCIIOrientedPointStreamWithData( void ); - void reset( void ); - bool nextPoint( OrientedPoint3D< Real >& p , Data& d ); -}; - -template< class Real , class RealOnDisk=Real > -class BinaryOrientedPointStream : public OrientedPointStream< Real > -{ - FILE* _fp; - static const int POINT_BUFFER_SIZE=1024; - OrientedPoint3D< RealOnDisk > _pointBuffer[ POINT_BUFFER_SIZE ]; - int _pointsInBuffer , _currentPointIndex; -public: - BinaryOrientedPointStream( const char* filename ); - ~BinaryOrientedPointStream( void ); - void reset( void ); - bool nextPoint( OrientedPoint3D< Real >& p ); -}; - -template< class Real , class Data , class RealOnDisk=Real , class DataOnDisk=Data > -class BinaryOrientedPointStreamWithData : public OrientedPointStreamWithData< Real , Data > -{ - FILE* _fp; - static const int POINT_BUFFER_SIZE=1024; - std::pair< OrientedPoint3D< RealOnDisk > , DataOnDisk > _pointBuffer[ POINT_BUFFER_SIZE ]; - int _pointsInBuffer , _currentPointIndex; -public: - BinaryOrientedPointStreamWithData( const char* filename ); - ~BinaryOrientedPointStreamWithData( void ); - void reset( void ); - bool nextPoint( OrientedPoint3D< Real >& p , Data& d ); -}; - -template< class Real > -class PLYOrientedPointStream : public OrientedPointStream< Real > -{ - char* _fileName; - PlyFile* _ply; - int _nr_elems; - char **_elist; - - int _pCount , _pIdx; - void _free( void ); -public: - PLYOrientedPointStream( const char* fileName ); - ~PLYOrientedPointStream( void ); - void reset( void ); - bool nextPoint( OrientedPoint3D< Real >& p ); -}; - -template< class Real , class Data > -class PLYOrientedPointStreamWithData : public OrientedPointStreamWithData< Real , Data > -{ - struct _PlyOrientedVertexWithData : public PlyOrientedVertex< Real > { Data data; }; - char* _fileName; - PlyFile* _ply; - int _nr_elems; - char **_elist; - PlyProperty* _dataProperties; - int _dataPropertiesCount; - bool (*_validationFunction)( const bool* ); - - int _pCount , _pIdx; - void _free( void ); -public: - PLYOrientedPointStreamWithData( const char* fileName , const PlyProperty* dataProperties , int dataPropertiesCount , bool (*validationFunction)( const bool* )=NULL ); - ~PLYOrientedPointStreamWithData( void ); - void reset( void ); - bool nextPoint( OrientedPoint3D< Real >& p , Data& d ); -}; - -#include "PointStream.inl" -#endif // POINT_STREAM_INCLUDED diff --git a/Src/PointStream.inl b/Src/PointStream.inl deleted file mode 100644 index 5d170026..00000000 --- a/Src/PointStream.inl +++ /dev/null @@ -1,408 +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. -*/ - - -/////////////////////////////// -// MemoryOrientedPointStream // -/////////////////////////////// -template< class Real > -MemoryOrientedPointStream< Real >::MemoryOrientedPointStream( size_t pointCount , const OrientedPoint3D< Real >* points ){ _points = points , _pointCount = pointCount , _current = 0; } -template< class Real > -MemoryOrientedPointStream< Real >::~MemoryOrientedPointStream( void ){ ; } -template< class Real > -void MemoryOrientedPointStream< Real >::reset( void ) { _current=0; } -template< class Real > -bool MemoryOrientedPointStream< Real >::nextPoint( OrientedPoint3D< Real >& p ) -{ - if( _current>=_pointCount ) return false; - p = _points[_current]; - _current++; - return true; -} - -////////////////////////////// -// ASCIIOrientedPointStream // -////////////////////////////// -template< class Real > -ASCIIOrientedPointStream< Real >::ASCIIOrientedPointStream( const char* fileName ) -{ - _fp = fopen( fileName , "r" ); - if( !_fp ) fprintf( stderr , "Failed to open file for reading: %s\n" , fileName ) , exit( 0 ); -} -template< class Real > -ASCIIOrientedPointStream< Real >::~ASCIIOrientedPointStream( void ) -{ - fclose( _fp ); - _fp = NULL; -} -template< class Real > -void ASCIIOrientedPointStream< Real >::reset( void ) { fseek( _fp , SEEK_SET , 0 ); } -template< class Real > -bool ASCIIOrientedPointStream< Real >::nextPoint( OrientedPoint3D< Real >& p ) -{ - float c[2*3]; - if( fscanf( _fp , " %f %f %f %f %f %f " , &c[0] , &c[1] , &c[2] , &c[3] , &c[4] , &c[5] )!=2*3 ) return false; - p.p[0] = c[0] , p.p[1] = c[1] , p.p[2] = c[2]; - p.n[0] = c[3] , p.n[1] = c[4] , p.n[2] = c[5]; - return true; -} - -/////////////////////////////// -// BinaryOrientedPointStream // -/////////////////////////////// -template< class Real , class RealOnDisk > -BinaryOrientedPointStream< Real , RealOnDisk >::BinaryOrientedPointStream( const char* fileName ) -{ - _pointsInBuffer = _currentPointIndex = 0; - _fp = fopen( fileName , "rb" ); - if( !_fp ) fprintf( stderr , "Failed to open file for reading: %s\n" , fileName ) , exit( 0 ); -} -template< class Real , class RealOnDisk > -BinaryOrientedPointStream< Real , RealOnDisk >::~BinaryOrientedPointStream( void ) -{ - fclose( _fp ); - _fp = NULL; -} -template< class Real , class RealOnDisk > -void BinaryOrientedPointStream< Real , RealOnDisk >::reset( void ) -{ - fseek( _fp , SEEK_SET , 0 ); - _pointsInBuffer = _currentPointIndex = 0; -} -template< class Real , class RealOnDisk > -bool BinaryOrientedPointStream< Real , RealOnDisk >::nextPoint( OrientedPoint3D< Real >& p ) -{ - if( _currentPointIndex<_pointsInBuffer ) - { - p = OrientedPoint3D< Real >( _pointBuffer[ _currentPointIndex ] ); - _currentPointIndex++; - return true; - } - else - { - _currentPointIndex = 0; - _pointsInBuffer = int( fread( _pointBuffer , sizeof( OrientedPoint3D< RealOnDisk > ) , POINT_BUFFER_SIZE , _fp ) ); - if( !_pointsInBuffer ) return false; - else return nextPoint( p ); - } -} - -//////////////////////////// -// PLYOrientedPointStream // -//////////////////////////// -template< class Real > -PLYOrientedPointStream< Real >::PLYOrientedPointStream( const char* fileName ) -{ - _fileName = new char[ strlen( fileName )+1 ]; - strcpy( _fileName , fileName ); - _ply = NULL; - reset(); -} -template< class Real > -void PLYOrientedPointStream< Real >::reset( void ) -{ - int fileType; - float version; - PlyProperty** plist; - if( _ply ) _free(); - _ply = ply_open_for_reading( _fileName, &_nr_elems, &_elist, &fileType, &version ); - if( !_ply ) - { - fprintf( stderr, "[ERROR] Failed to open ply file for reading: %s\n" , _fileName ); - exit( 0 ); - } - bool foundVertices = false; - for( int i=0 ; i<_nr_elems ; i++ ) - { - int num_elems; - int nr_props; - char* elem_name = _elist[i]; - plist = ply_get_element_description( _ply , elem_name , &num_elems , &nr_props ); - if( !plist ) - { - fprintf( stderr , "[ERROR] Failed to get element description: %s\n" , elem_name ); - exit( 0 ); - } - - if( equal_strings( "vertex" , elem_name ) ) - { - foundVertices = true; - _pCount = num_elems , _pIdx = 0; - for( int i=0 ; i::ReadComponents ; i++ ) - if( !ply_get_property( _ply , elem_name , &(PlyOrientedVertex< Real >::ReadProperties[i]) ) ) - { - fprintf( stderr , "[ERROR] Failed to find property in ply file: %s\n" , PlyOrientedVertex< Real >::ReadProperties[i].name ); - exit( 0 ); - } - } - for( int j=0 ; jname ); - free( plist[j] ); - } - free( plist ); - if( foundVertices ) break; - } - if( !foundVertices ) - { - fprintf( stderr , "[ERROR] Could not find vertices in ply file\n" ); - exit( 0 ); - } -} -template< class Real > -void PLYOrientedPointStream< Real >::_free( void ) -{ - if( _ply ) ply_close( _ply ) , _ply = NULL; - if( _elist ) - { - for( int i=0 ; i<_nr_elems ; i++ ) free( _elist[i] ); - free( _elist ); - } -} -template< class Real > -PLYOrientedPointStream< Real >::~PLYOrientedPointStream( void ) -{ - _free(); - if( _fileName ) delete[] _fileName , _fileName = NULL; -} -template< class Real > -bool PLYOrientedPointStream< Real >::nextPoint( OrientedPoint3D< Real >& p ) -{ - if( _pIdx<_pCount ) - { - PlyOrientedVertex< Real > op; - ply_get_element( _ply, (void *)&op ); - p.p = op.point; - p.n = op.normal; - _pIdx++; - return true; - } - else return false; -} - -/////////////////////////////////////// -// MemoryOrientedPointStreamWithData // -/////////////////////////////////////// -template< class Real , class Data > -MemoryOrientedPointStreamWithData< Real , Data >::MemoryOrientedPointStreamWithData( size_t pointCount , const std::pair< OrientedPoint3D< Real > , Data >* points ){ _points = points , _pointCount = pointCount , _current = 0; } -template< class Real , class Data > -MemoryOrientedPointStreamWithData< Real , Data >::~MemoryOrientedPointStreamWithData( void ){ ; } -template< class Real , class Data > -void MemoryOrientedPointStreamWithData< Real , Data >::reset( void ) { _current=0; } -template< class Real , class Data > -bool MemoryOrientedPointStreamWithData< Real , Data >::nextPoint( OrientedPoint3D< Real >& p , Data& d ) -{ - if( _current>=_pointCount ) return false; - p = _points[_current].first; - d = _points[_current].second; - _current++; - return true; -} - -////////////////////////////////////// -// ASCIIOrientedPointStreamWithData // -////////////////////////////////////// -template< class Real , class Data > -ASCIIOrientedPointStreamWithData< Real , Data >::ASCIIOrientedPointStreamWithData( const char* fileName , Data (*readData)( FILE* ) ) : _readData( readData ) -{ - _fp = fopen( fileName , "r" ); - if( !_fp ) fprintf( stderr , "Failed to open file for reading: %s\n" , fileName ) , exit( 0 ); -} -template< class Real , class Data > -ASCIIOrientedPointStreamWithData< Real , Data >::~ASCIIOrientedPointStreamWithData( void ) -{ - fclose( _fp ); - _fp = NULL; -} -template< class Real , class Data > -void ASCIIOrientedPointStreamWithData< Real , Data >::reset( void ) { fseek( _fp , SEEK_SET , 0 ); } -template< class Real , class Data > -bool ASCIIOrientedPointStreamWithData< Real , Data >::nextPoint( OrientedPoint3D< Real >& p , Data& d ) -{ - float c[2*3]; - if( fscanf( _fp , " %f %f %f %f %f %f " , &c[0] , &c[1] , &c[2] , &c[3] , &c[4] , &c[5] )!=2*3 ) return false; - p.p[0] = c[0] , p.p[1] = c[1] , p.p[2] = c[2]; - p.n[0] = c[3] , p.n[1] = c[4] , p.n[2] = c[5]; - d = _readData( _fp ); - return true; -} - -/////////////////////////////////////// -// BinaryOrientedPointStreamWithData // -/////////////////////////////////////// -template< class Real , class Data , class RealOnDisk , class DataOnDisk > -BinaryOrientedPointStreamWithData< Real , Data , RealOnDisk , DataOnDisk >::BinaryOrientedPointStreamWithData( const char* fileName ) -{ - _pointsInBuffer = _currentPointIndex = 0; - _fp = fopen( fileName , "rb" ); - if( !_fp ) fprintf( stderr , "Failed to open file for reading: %s\n" , fileName ) , exit( 0 ); -} -template< class Real , class Data , class RealOnDisk , class DataOnDisk > -BinaryOrientedPointStreamWithData< Real , Data , RealOnDisk , DataOnDisk >::~BinaryOrientedPointStreamWithData( void ) -{ - fclose( _fp ); - _fp = NULL; -} -template< class Real , class Data , class RealOnDisk , class DataOnDisk > -void BinaryOrientedPointStreamWithData< Real , Data , RealOnDisk , DataOnDisk >::reset( void ) -{ - fseek( _fp , SEEK_SET , 0 ); - _pointsInBuffer = _currentPointIndex = 0; -} -template< class Real , class Data , class RealOnDisk , class DataOnDisk > -bool BinaryOrientedPointStreamWithData< Real , Data , RealOnDisk , DataOnDisk >::nextPoint( OrientedPoint3D< Real >& p , Data& d ) -{ - if( _currentPointIndex<_pointsInBuffer ) - { - p = OrientedPoint3D< Real >( _pointBuffer[ _currentPointIndex ].first ); - d = Data( _pointBuffer[ _currentPointIndex ].second ); - _currentPointIndex++; - return true; - } - else - { - _currentPointIndex = 0; - _pointsInBuffer = int( fread( _pointBuffer , sizeof( std::pair< OrientedPoint3D< RealOnDisk > , DataOnDisk > ) , POINT_BUFFER_SIZE , _fp ) ); - if( !_pointsInBuffer ) return false; - else return nextPoint( p , d ); - } -} - -//////////////////////////////////// -// PLYOrientedPointStreamWithData // -//////////////////////////////////// -template< class Real , class Data > -PLYOrientedPointStreamWithData< Real , Data >::PLYOrientedPointStreamWithData( const char* fileName , const PlyProperty* dataProperties , int dataPropertiesCount , bool (*validationFunction)( const bool* ) ) : _dataPropertiesCount( dataPropertiesCount ) , _validationFunction( validationFunction ) -{ - _dataProperties = new PlyProperty[ _dataPropertiesCount ]; - memcpy( _dataProperties , dataProperties , sizeof(PlyProperty) * _dataPropertiesCount ); - for( int i=0 ; i<_dataPropertiesCount ; i++ ) _dataProperties[i].offset += sizeof( PlyOrientedVertex< Real > ); - _fileName = new char[ strlen( fileName )+1 ]; - strcpy( _fileName , fileName ); - _ply = NULL; - reset(); -} -template< class Real , class Data > -void PLYOrientedPointStreamWithData< Real , Data >::reset( void ) -{ - int fileType; - float version; - PlyProperty** plist; - if( _ply ) _free(); - _ply = ply_open_for_reading( _fileName, &_nr_elems, &_elist, &fileType, &version ); - if( !_ply ) - { - fprintf( stderr, "[ERROR] Failed to open ply file for reading: %s\n" , _fileName ); - exit( 0 ); - } - bool foundVertices = false; - for( int i=0 ; i<_nr_elems ; i++ ) - { - int num_elems; - int nr_props; - char* elem_name = _elist[i]; - plist = ply_get_element_description( _ply , elem_name , &num_elems , &nr_props ); - if( !plist ) - { - fprintf( stderr , "[ERROR] Failed to get element description: %s\n" , elem_name ); - exit( 0 ); - } - - if( equal_strings( "vertex" , elem_name ) ) - { - foundVertices = true; - _pCount = num_elems , _pIdx = 0; - for( int i=0 ; i::ReadComponents ; i++ ) - if( !ply_get_property( _ply , elem_name , &(PlyOrientedVertex< Real >::ReadProperties[i]) ) ) - { - fprintf( stderr , "[ERROR] Failed to find property in ply file: %s\n" , PlyOrientedVertex< Real >::ReadProperties[i].name ); - exit( 0 ); - } - if( _validationFunction ) - { - bool* properties = new bool[_dataPropertiesCount]; - for( int i=0 ; i<_dataPropertiesCount ; i++ ) - if( !ply_get_property( _ply , elem_name , &(_dataProperties[i]) ) ) properties[i] = false; - else properties[i] = true; - bool valid = _validationFunction( properties ); - delete[] properties; - if( !valid ) fprintf( stderr , "[ERROR] Failed to validate properties in file\n" ) , exit( 0 ); - } - else - { - for( int i=0 ; i<_dataPropertiesCount ; i++ ) - if( !ply_get_property( _ply , elem_name , &(_dataProperties[i]) ) ) - fprintf( stderr , "[WARNING] Failed to find property in ply file: %s\n" , _dataProperties[i].name ); - } - } - for( int j=0 ; jname ); - free( plist[j] ); - } - free( plist ); - if( foundVertices ) break; - } - if( !foundVertices ) - { - fprintf( stderr , "[ERROR] Could not find vertices in ply file\n" ); - exit( 0 ); - } -} -template< class Real , class Data > -void PLYOrientedPointStreamWithData< Real , Data >::_free( void ) -{ - if( _ply ) ply_close( _ply ) , _ply = NULL; - if( _elist ) - { - for( int i=0 ; i<_nr_elems ; i++ ) free( _elist[i] ); - free( _elist ); - } -} -template< class Real , class Data > -PLYOrientedPointStreamWithData< Real , Data >::~PLYOrientedPointStreamWithData( void ) -{ - _free(); - if( _fileName ) delete[] _fileName , _fileName = NULL; - if( _dataProperties ) delete[] _dataProperties , _dataProperties = NULL; -} -template< class Real , class Data > -bool PLYOrientedPointStreamWithData< Real , Data >::nextPoint( OrientedPoint3D< Real >& p , Data& d ) -{ - if( _pIdx<_pCount ) - { - _PlyOrientedVertexWithData op; - ply_get_element( _ply, (void *)&op ); - p.p = op.point; - p.n = op.normal; - d = op.data; - _pIdx++; - return true; - } - else return false; -} diff --git a/Src/PoissonRecon.cpp b/Src/PoissonRecon.cpp deleted file mode 100644 index 8e4b71f0..00000000 --- a/Src/PoissonRecon.cpp +++ /dev/null @@ -1,806 +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. -*/ - -#undef FAST_COMPILE -#undef ARRAY_DEBUG -#define BRUNO_LEVY_FIX -#define FOR_RELEASE - -#include -#include -#include -#include -#if defined( _WIN32 ) || defined( _WIN64 ) -#include -#include -#endif // _WIN32 || _WIN64 -#include "MyTime.h" -#include "MarchingCubes.h" -#include "Octree.h" -#include "SparseMatrix.h" -#include "CmdLineParser.h" -#include "PPolynomial.h" -#include "Ply.h" -#include "MemoryUsage.h" -#ifdef _OPENMP -#include "omp.h" -#endif // _OPENMP -void DumpOutput( const char* format , ... ); -void DumpOutput2( std::vector< char* >& comments , const char* format , ... ); -#include "MultiGridOctreeData.h" - -#define DEFAULT_FULL_DEPTH 5 - -#define XSTR(x) STR(x) -#define STR(x) #x -#if DEFAULT_FULL_DEPTH -#pragma message ( "[WARNING] Setting default full depth to " XSTR(DEFAULT_FULL_DEPTH) ) -#endif // DEFAULT_FULL_DEPTH - -#include -char* outputFile=NULL; -int echoStdout=0; -void DumpOutput( const char* format , ... ) -{ - if( outputFile ) - { - FILE* fp = fopen( outputFile , "a" ); - va_list args; - va_start( args , format ); - vfprintf( fp , format , args ); - fclose( fp ); - va_end( args ); - } - if( echoStdout ) - { - va_list args; - va_start( args , format ); - vprintf( format , args ); - va_end( args ); - } -} -void DumpOutput2( std::vector< char* >& comments , const char* format , ... ) -{ - if( outputFile ) - { - FILE* fp = fopen( outputFile , "a" ); - va_list args; - va_start( args , format ); - vfprintf( fp , format , args ); - fclose( fp ); - va_end( args ); - } - if( echoStdout ) - { - va_list args; - va_start( args , format ); - vprintf( format , args ); - va_end( args ); - } - comments.push_back( new char[1024] ); - char* str = comments.back(); - va_list args; - va_start( args , format ); - vsprintf( str , format , args ); - va_end( args ); - if( str[strlen(str)-1]=='\n' ) str[strlen(str)-1] = 0; -} - - -cmdLineString - In( "in" ) , - Out( "out" ) , - TempDir( "tempDir" ) , - VoxelGrid( "voxel" ) , - XForm( "xForm" ); - -cmdLineReadable -#if defined( _WIN32 ) || defined( _WIN64 ) - Performance( "performance" ) , -#endif // _WIN32 || _WIN64 - ShowResidual( "showResidual" ) , - NoComments( "noComments" ) , - PolygonMesh( "polygonMesh" ) , - Confidence( "confidence" ) , - NormalWeights( "nWeights" ) , - NonManifold( "nonManifold" ) , - ASCII( "ascii" ) , - Density( "density" ) , - LinearFit( "linearFit" ) , - PrimalVoxel( "primalVoxel" ) , -#ifndef FAST_COMPILE - Double( "double" ) , -#endif // !FAST_COMPILE - Verbose( "verbose" ); - -cmdLineInt -#ifndef FAST_COMPILE - Degree( "degree" , 2 ) , -#endif // !FAST_COMPILE - Depth( "depth" , 8 ) , - CGDepth( "cgDepth" , 0 ) , - KernelDepth( "kernelDepth" ) , - AdaptiveExponent( "adaptiveExp" , 1 ) , - Iters( "iters" , 8 ) , - VoxelDepth( "voxelDepth" , -1 ) , - FullDepth( "fullDepth" , DEFAULT_FULL_DEPTH ) , -#ifndef FAST_COMPILE - BType( "bType" , BOUNDARY_NEUMANN+1 ) , -#endif // !FAST_COMPILE - MaxSolveDepth( "maxSolveDepth" ) , - Threads( "threads" , omp_get_num_procs() ); - -cmdLineFloat - Color( "color" , 16.f ) , - SamplesPerNode( "samplesPerNode" , 1.5f ) , - Scale( "scale" , 1.1f ) , - CGSolverAccuracy( "cgAccuracy" , float(1e-3) ) , - LowResIterMultiplier( "iterMultiplier" , 1.f ) , - PointWeight( "pointWeight" , 4.f ); - - -cmdLineReadable* params[] = -{ -#ifndef FAST_COMPILE - &Degree , &Double , &BType , -#endif // !FAST_COMPILE - &In , &Depth , &Out , &XForm , - &Scale , &Verbose , &CGSolverAccuracy , &NoComments , &LowResIterMultiplier , - &KernelDepth , &SamplesPerNode , &Confidence , &NormalWeights , &NonManifold , &PolygonMesh , &ASCII , &ShowResidual , &VoxelDepth , - &PointWeight , &VoxelGrid , &Threads , &MaxSolveDepth , - &AdaptiveExponent , - &Density , - &FullDepth , - &CGDepth , &Iters , - &Color , - &LinearFit , - &PrimalVoxel , - &TempDir , -#if defined( _WIN32 ) || defined( _WIN64 ) - &Performance , -#endif // _WIN32 || _WIN64 -}; - - -void ShowUsage(char* ex) -{ - printf( "Usage: %s\n" , ex ); - printf( "\t --%s \n" , In.name ); - - printf( "\t[--%s ]\n" , Out.name ); - - printf( "\t[--%s ]\n" , VoxelGrid.name ); - -#ifndef FAST_COMPILE - printf( "\t[--%s =%d]\n" , Degree.name , Degree.value ); - - printf( "\t[--%s =%d]\n" , BType.name , BType.value ); - for( int i=0 ; i=%d]\n" , Depth.name , Depth.value ); - - printf( "\t[--%s =%f]\n" , Scale.name , Scale.value ); - - printf( "\t[--%s =%f]\n" , SamplesPerNode.name, SamplesPerNode.value ); - - printf( "\t[--%s =%.3e]\n" , PointWeight.name , PointWeight.value ); - - printf( "\t[--%s]\n" , Confidence.name ); - - printf( "\t[--%s]\n" , NormalWeights.name ); - -#ifndef FOR_RELEASE - printf( "\t[--%s =%d]\n", AdaptiveExponent.name , AdaptiveExponent.value ); -#endif // !FOR_RELEASE - - printf( "\t[--%s =%d]\n" , Iters.name , Iters.value ); - -#ifndef FOR_RELEASE - printf( "\t[--%s =%f]\n" , LowResIterMultiplier.name , LowResIterMultiplier.value ); -#endif // FOR_RELEASE - - printf( "\t[--%s =%d]\n" , CGDepth.name , CGDepth.value ); - -#ifndef FOR_RELEASE - printf( "\t[--%s =%g]\n" , CGSolverAccuracy.name , CGSolverAccuracy.value ); -#endif // !FOR_RELEASE - - printf( "\t[--%s =%d]\n" , FullDepth.name , FullDepth.value ); - - printf( "\t[--%s =<%s>]\n" , VoxelDepth.name , Depth.name ); - - printf( "\t[--%s]\n" , PrimalVoxel.name ); - - printf( "\t[--%s ]\n" , Color.name ); - - printf( "\t[--%s]\n" , Density.name ); - - printf( "\t[--%s]\n" , LinearFit.name ); - - printf( "\t[--%s]\n" , PolygonMesh.name); - -#ifndef FOR_RELEASE - printf( "\t[--%s]\n" , NonManifold.name ); -#endif // !FOR_RELEASE - -#ifdef _OPENMP - printf( "\t[--%s =%d]\n" , Threads.name , Threads.value ); -#endif // _OPENMP - - printf( "\t[--%s]\n" , TempDir.name ); - - printf( "\t[--%s]\n" , Verbose.name ); - -#ifndef FOR_RELEASE -#if defined( _WIN32 ) || defined( _WIN64 ) - printf( "\t[--%s]\n" , Performance.name ); -#endif // _WIN32 || _WIN64 -#endif // !FOR_RELEASE - -#ifndef FOR_RELEASE - printf( "\t[--%s]\n" , ASCII.name ); - - printf( "\t[--%s]\n" , NoComments.name ); - -#ifndef FAST_COMPILE - printf( "\t[--%s]\n" , Double.name ); -#endif // FAST_COMPILE -#endif // !FOR_RELEASE -} - -template< class Real > -struct ColorInfo -{ - static Point3D< Real > ReadASCII( FILE* fp ) - { - Point3D< unsigned char > c; - if( fscanf( fp , " %c %c %c " , &c[0] , &c[1] , &c[2] )!=3 ) fprintf( stderr , "[ERROR] Failed to read color\n" ) , exit( 0 ); - return Point3D< Real >( (Real)c[0] , (Real)c[1] , (Real)c[2] ); - }; - static bool ValidPlyProperties( const bool* props ){ return ( props[0] || props[3] ) && ( props[1] || props[4] ) && ( props[2] || props[5] ); } - const static PlyProperty PlyProperties[]; -}; -template<> -const PlyProperty ColorInfo< float >::PlyProperties[] = -{ - { "r" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Point3D< float > , coords[0] ) ) , 0 , 0 , 0 , 0 } , - { "g" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Point3D< float > , coords[1] ) ) , 0 , 0 , 0 , 0 } , - { "b" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Point3D< float > , coords[2] ) ) , 0 , 0 , 0 , 0 } , - { "red" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Point3D< float > , coords[0] ) ) , 0 , 0 , 0 , 0 } , - { "green" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Point3D< float > , coords[1] ) ) , 0 , 0 , 0 , 0 } , - { "blue" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Point3D< float > , coords[2] ) ) , 0 , 0 , 0 , 0 } -}; -template<> -const PlyProperty ColorInfo< double >::PlyProperties[] = -{ - { "r" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Point3D< double > , coords[0] ) ) , 0 , 0 , 0 , 0 } , - { "g" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Point3D< double > , coords[1] ) ) , 0 , 0 , 0 , 0 } , - { "b" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Point3D< double > , coords[2] ) ) , 0 , 0 , 0 , 0 } , - { "red" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Point3D< double > , coords[0] ) ) , 0 , 0 , 0 , 0 } , - { "green" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Point3D< double > , coords[1] ) ) , 0 , 0 , 0 , 0 } , - { "blue" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Point3D< double > , coords[2] ) ) , 0 , 0 , 0 , 0 } -}; - -double Weight( double v , double start , double end ) -{ - v = ( v - start ) / ( end - start ); - if ( v<0 ) return 1.; - else if( v>1 ) return 0.; - else - { - // P(x) = a x^3 + b x^2 + c x + d - // P (0) = 1 , P (1) = 0 , P'(0) = 0 , P'(1) = 0 - // => d = 1 , a + b + c + d = 0 , c = 0 , 3a + 2b + c = 0 - // => c = 0 , d = 1 , a + b = -1 , 3a + 2b = 0 - // => a = 2 , b = -3 , c = 0 , d = 1 - // => P(x) = 2 x^3 - 3 x^2 + 1 - return 2. * v * v * v - 3. * v * v + 1.; - } -} - -#if defined( _WIN32 ) || defined( _WIN64 ) -double PeakMemoryUsageMB( void ) -{ - HANDLE h = GetCurrentProcess(); - PROCESS_MEMORY_COUNTERS pmc; - return GetProcessMemoryInfo( h , &pmc , sizeof(pmc) ) ? ( (double)pmc.PeakWorkingSetSize )/(1<<20) : 0; -} -#endif // _WIN32 || _WIN64 - - -template< class Real > -struct OctreeProfiler -{ - Octree< Real >& tree; - double t; - - OctreeProfiler( Octree< Real >& t ) : tree(t) { ; } - void start( void ){ t = Time() , tree.resetLocalMemoryUsage(); } - void print( const char* header ) const - { - tree.memoryUsage(); -#if defined( _WIN32 ) || defined( _WIN64 ) - if( header ) printf( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); - else printf( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); -#else // !_WIN32 && !_WIN64 - if( header ) printf( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); - else printf( "%9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); -#endif // _WIN32 || _WIN64 - } - void dumpOutput( const char* header ) const - { - tree.memoryUsage(); -#if defined( _WIN32 ) || defined( _WIN64 ) - if( header ) DumpOutput( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); - else DumpOutput( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); -#else // !_WIN32 && !_WIN64 - if( header ) DumpOutput( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); - else DumpOutput( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); -#endif // _WIN32 || _WIN64 - } - void dumpOutput2( std::vector< char* >& comments , const char* header ) const - { - tree.memoryUsage(); -#if defined( _WIN32 ) || defined( _WIN64 ) - if( header ) DumpOutput2( comments , "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); - else DumpOutput2( comments , "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); -#else // !_WIN32 && !_WIN64 - if( header ) DumpOutput2( comments , "%s %9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); - else DumpOutput2( comments , "%9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); -#endif // _WIN32 || _WIN64 - } -}; - -template< class Real > -XForm4x4< Real > GetPointXForm( OrientedPointStream< Real >& stream , Real scaleFactor ) -{ - Point3D< Real > min , max; - stream.boundingBox( min , max ); - Point3D< Real > center = ( max + min ) / 2; - Real scale = std::max< Real >( max[0]-min[0] , std::max< Real >( max[1]-min[1] , max[2]-min[2] ) ); - scale *= scaleFactor; - for( int i=0 ; i<3 ; i++ ) center[i] -= scale/2; - XForm4x4< Real > tXForm = XForm4x4< Real >::Identity() , sXForm = XForm4x4< Real >::Identity(); - for( int i=0 ; i<3 ; i++ ) sXForm(i,i) = (Real)(1./scale ) , tXForm(3,i) = -center[i]; - return sXForm * tXForm; -} - -template< class Real , int Degree , BoundaryType BType , class Vertex > -int _Execute( int argc , char* argv[] ) -{ - typedef typename Octree< Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; - typedef typename Octree< Real >::template InterpolationInfo< false > InterpolationInfo; - typedef OrientedPointStream< Real > PointStream; - typedef OrientedPointStreamWithData< Real , Point3D< Real > > PointStreamWithData; - typedef TransformedOrientedPointStream< Real > XPointStream; - typedef TransformedOrientedPointStreamWithData< Real , Point3D< Real > > XPointStreamWithData; - Reset< Real >(); - int paramNum = sizeof(params)/sizeof(cmdLineReadable*); - std::vector< char* > comments; - - if( Verbose.set ) echoStdout=1; - - XForm4x4< Real > xForm , iXForm; - if( XForm.set ) - { - FILE* fp = fopen( XForm.value , "r" ); - if( !fp ) - { - fprintf( stderr , "[WARNING] Could not read x-form from: %s\n" , XForm.value ); - xForm = XForm4x4< Real >::Identity(); - } - else - { - for( int i=0 ; i<4 ; i++ ) for( int j=0 ; j<4 ; j++ ) - { - float f; - if( fscanf( fp , " %f " , &f )!=1 ) fprintf( stderr , "[ERROR] Execute: Failed to read xform\n" ) , exit( 0 ); - xForm(i,j) = (Real)f; - } - fclose( fp ); - } - } - else xForm = XForm4x4< Real >::Identity(); - - DumpOutput2( comments , "Running Screened Poisson Reconstruction (Version 9.011)\n" ); - char str[1024]; - for( int i=0 ; iset ) - { - params[i]->writeValue( str ); - if( strlen( str ) ) DumpOutput2( comments , "\t--%s %s\n" , params[i]->name , str ); - else DumpOutput2( comments , "\t--%s\n" , params[i]->name ); - } - - double startTime = Time(); - Real isoValue = 0; - - Octree< Real > tree; - OctreeProfiler< Real > profiler( tree ); - tree.threads = Threads.value; - if( !In.set ) - { - ShowUsage( argv[0] ); - return 0; - } - if( !MaxSolveDepth.set ) MaxSolveDepth.value = Depth.value; - - OctNode< TreeNodeData >::SetAllocator( MEMORY_ALLOCATOR_BLOCK_SIZE ); - - int kernelDepth = KernelDepth.set ? KernelDepth.value : Depth.value-2; - if( kernelDepth>Depth.value ) - { - fprintf( stderr,"[WARNING] %s can't be greater than %s: %d <= %d\n" , KernelDepth.name , Depth.name , KernelDepth.value , Depth.value ); - kernelDepth = Depth.value; - } - - int pointCount; - - Real pointWeightSum; - std::vector< typename Octree< Real >::PointSample >* samples = new std::vector< typename Octree< Real >::PointSample >(); - std::vector< ProjectiveData< Point3D< Real > , Real > >* sampleData = NULL; - DensityEstimator* density = NULL; - SparseNodeData< Point3D< Real > , NORMAL_DEGREE >* normalInfo = NULL; - Real targetValue = (Real)0.5; - // Read in the samples (and color data) - { - profiler.start(); - PointStream* pointStream; - char* ext = GetFileExtension( In.value ); - if( Color.set && Color.value>0 ) - { - sampleData = new std::vector< ProjectiveData< Point3D< Real > , Real > >(); - if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryOrientedPointStreamWithData< Real , Point3D< Real > , float , Point3D< unsigned char > >( In.value ); - else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYOrientedPointStreamWithData< Real , Point3D< Real > >( In.value , ColorInfo< Real >::PlyProperties , 6 , ColorInfo< Real >::ValidPlyProperties ); - else pointStream = new ASCIIOrientedPointStreamWithData< Real , Point3D< Real > >( In.value , ColorInfo< Real >::ReadASCII ); - } - else - { - if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryOrientedPointStream< Real , float >( In.value ); - else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYOrientedPointStream< Real >( In.value ); - else pointStream = new ASCIIOrientedPointStream< Real >( In.value ); - } - delete[] ext; - XPointStream _pointStream( xForm , *pointStream ); - xForm = GetPointXForm( _pointStream , (Real)Scale.value ) * xForm; - if( sampleData ) - { - XPointStreamWithData _pointStream( xForm , ( PointStreamWithData& )*pointStream ); - pointCount = tree.template init< Point3D< Real > >( _pointStream , Depth.value , Confidence.set , *samples , sampleData ); - } - else - { - XPointStream _pointStream( xForm , *pointStream ); - pointCount = tree.template init< Point3D< Real > >( _pointStream , Depth.value , Confidence.set , *samples , sampleData ); - } - iXForm = xForm.inverse(); - delete pointStream; -#pragma omp parallel for num_threads( Threads.value ) - for( int i=0 ; i<(int)samples->size() ; i++ ) (*samples)[i].sample.data.n *= (Real)-1; - - DumpOutput( "Input Points / Samples: %d / %d\n" , pointCount , samples->size() ); - profiler.dumpOutput2( comments , "# Read input into tree:" ); - } - DenseNodeData< Real , Degree > solution; - - { - DenseNodeData< Real , Degree > constraints; - InterpolationInfo* iInfo = NULL; - int solveDepth = MaxSolveDepth.value; - - tree.resetNodeIndices(); - - // Get the kernel density estimator [If discarding, compute anew. Otherwise, compute once.] - { - profiler.start(); - density = tree.template setDensityEstimator< WEIGHT_DEGREE >( *samples , kernelDepth , SamplesPerNode.value ); - profiler.dumpOutput2( comments , "# Got kernel density:" ); - } - - // Transform the Hermite samples into a vector field [If discarding, compute anew. Otherwise, compute once.] - { - profiler.start(); - normalInfo = new SparseNodeData< Point3D< Real > , NORMAL_DEGREE >(); - *normalInfo = tree.template setNormalField< NORMAL_DEGREE >( *samples , *density , pointWeightSum , BType==BOUNDARY_NEUMANN ); - profiler.dumpOutput2( comments , "# Got normal field:" ); - } - - if( !Density.set ) delete density , density = NULL; - - // Trim the tree and prepare for multigrid - { - profiler.start(); - std::vector< int > indexMap; - - constexpr int MAX_DEGREE = NORMAL_DEGREE > Degree ? NORMAL_DEGREE : Degree; - tree.template inalizeForBroodedMultigrid< MAX_DEGREE , Degree , BType >( FullDepth.value , typename Octree< Real >::template HasNormalDataFunctor< NORMAL_DEGREE >( *normalInfo ) , &indexMap ); - - if( normalInfo ) normalInfo->remapIndices( indexMap ); - if( density ) density->remapIndices( indexMap ); - profiler.dumpOutput2( comments , "# Finalized tree:" ); - } - - // Add the FEM constraints - { - profiler.start(); - constraints = tree.template initDenseNodeData< Degree >( ); - tree.template addFEMConstraints< Degree , BType , NORMAL_DEGREE , BType >( FEMVFConstraintFunctor< NORMAL_DEGREE , BType , Degree , BType >( 1. , 0. ) , *normalInfo , constraints , solveDepth ); - profiler.dumpOutput2( comments , "# Set FEM constraints:" ); - } - - // Free up the normal info [If we don't need it for subseequent iterations.] - delete normalInfo , normalInfo = NULL; - - // Add the interpolation constraints - if( PointWeight.value>0 ) - { - profiler.start(); - iInfo = new InterpolationInfo( tree , *samples , targetValue , AdaptiveExponent.value , (Real)PointWeight.value * pointWeightSum , (Real)0 ); - tree.template addInterpolationConstraints< Degree , BType >( *iInfo , constraints , solveDepth ); - profiler.dumpOutput2( comments , "#Set point constraints:" ); - } - - DumpOutput( "Leaf Nodes / Active Nodes / Ghost Nodes: %d / %d / %d\n" , (int)tree.leaves() , (int)tree.nodes() , (int)tree.ghostNodes() ); - DumpOutput( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage())/(1<<20) ); - - // Solve the linear system - { - profiler.start(); - typename Octree< Real >::SolverInfo solverInfo; - solverInfo.cgDepth = CGDepth.value , solverInfo.iters = Iters.value , solverInfo.cgAccuracy = CGSolverAccuracy.value , solverInfo.verbose = Verbose.set , solverInfo.showResidual = ShowResidual.set , solverInfo.lowResIterMultiplier = std::max< double >( 1. , LowResIterMultiplier.value ); - solution = tree.template solveSystem< Degree , BType >( FEMSystemFunctor< Degree , BType >( 0 , 1. , 0 ) , iInfo , constraints , solveDepth , solverInfo ); - profiler.dumpOutput2( comments , "# Linear system solved:" ); - if( iInfo ) delete iInfo , iInfo = NULL; - } - } - - char tempHeader[1024]; - { -#if defined( _WIN32 ) || defined( _WIN64 ) - const char FileSeparator = '\\'; -#else // !_WIN - const char FileSeparator = '/'; -#endif // _WIN - char tempPath[1024]; - tempPath[0] = 0; - if( TempDir.set ) strcpy( tempPath , TempDir.value ); - else - { -#if defined( _WIN32 ) || defined( _WIN64 ) - GetTempPath( sizeof(tempPath) , tempPath ); -#else // !_WIN - if( std::getenv( "TMPDIR" ) ) strcpy( tempPath , std::getenv( "TMPDIR" ) ); -#endif // _WIN - } - if( strlen(tempPath)==0 ) sprintf( tempPath , ".%c" , FileSeparator ); - if( tempPath[ strlen( tempPath )-1 ]==FileSeparator ) sprintf( tempHeader , "%sPR_" , tempPath ); - else sprintf( tempHeader , "%s%cPR_" , tempPath , FileSeparator ); - } - CoredFileMeshData< Vertex > mesh( tempHeader ); - - { - profiler.start(); - double valueSum = 0 , weightSum = 0; - typename Octree< Real >::template MultiThreadedEvaluator< Degree , BType > evaluator( &tree , solution , Threads.value ); -#pragma omp parallel for num_threads( Threads.value ) reduction( + : valueSum , weightSum ) - for( int j=0 ; jsize() ; j++ ) - { - ProjectiveData< OrientedPoint3D< Real > , Real >& sample = (*samples)[j].sample; - Real w = sample.weight; - if( w>0 ) weightSum += w , valueSum += evaluator.value( sample.data.p / sample.weight , omp_get_thread_num() , (*samples)[j].node ) * w; - } - isoValue = (Real)( valueSum / weightSum ); - if( !( Color.set && Color.value>0 ) && samples ) delete samples , samples = NULL; - profiler.dumpOutput( "Got average:" ); - DumpOutput( "Iso-Value: %e\n" , isoValue ); - } - - if( VoxelGrid.set ) - { - profiler.start(); - FILE* fp = fopen( VoxelGrid.value , "wb" ); - if( !fp ) fprintf( stderr , "Failed to open voxel file for writing: %s\n" , VoxelGrid.value ); - else - { - int res = 0; - Pointer( Real ) values = tree.template voxelEvaluate< Real , Degree , BType >( solution , res , isoValue , VoxelDepth.value , PrimalVoxel.set ); - fwrite( &res , sizeof(int) , 1 , fp ); - if( sizeof(Real)==sizeof(float) ) fwrite( values , sizeof(float) , res*res*res , fp ); - else - { - float *fValues = new float[res*res*res]; - for( int i=0 ; i , Real > , DATA_DEGREE >* colorData = NULL; - if( sampleData ) - { - colorData = new SparseNodeData< ProjectiveData< Point3D< Real > , Real > , DATA_DEGREE >(); - *colorData = tree.template setDataField< DATA_DEGREE , false >( *samples , *sampleData , (DensityEstimator*)NULL ); - delete sampleData , sampleData = NULL; - for( const OctNode< TreeNodeData >* n = tree.tree().nextNode() ; n ; n=tree.tree().nextNode( n ) ) - { - ProjectiveData< Point3D< Real > , Real >* clr = (*colorData)( n ); - if( clr ) (*clr) *= (Real)pow( Color.value , tree.depth( n ) ); - } - } - tree.template getMCIsoSurface< Degree , BType , WEIGHT_DEGREE , DATA_DEGREE >( density , colorData , solution , isoValue , mesh , !LinearFit.set , !NonManifold.set , PolygonMesh.set ); - DumpOutput( "Vertices / Polygons: %d / %d\n" , mesh.outOfCorePointCount()+mesh.inCorePoints.size() , mesh.polygonCount() ); - if( PolygonMesh.set ) profiler.dumpOutput2( comments , "# Got polygons:" ); - else profiler.dumpOutput2( comments , "# Got triangles:" ); - - if( colorData ) delete colorData , colorData = NULL; - - if( NoComments.set ) - { - if( ASCII.set ) PlyWritePolygons( Out.value , &mesh , PLY_ASCII , NULL , 0 , iXForm ); - else PlyWritePolygons( Out.value , &mesh , PLY_BINARY_NATIVE , NULL , 0 , iXForm ); - } - else - { - if( ASCII.set ) PlyWritePolygons( Out.value , &mesh , PLY_ASCII , &comments[0] , (int)comments.size() , iXForm ); - else PlyWritePolygons( Out.value , &mesh , PLY_BINARY_NATIVE , &comments[0] , (int)comments.size() , iXForm ); - } - } - if( density ) delete density , density = NULL; - DumpOutput2( comments , "# Total Solve: %9.1f (s), %9.1f (MB)\n" , Time()-startTime , tree.maxMemoryUsage() ); - - return 1; -} - -#if defined( _WIN32 ) || defined( _WIN64 ) -inline double to_seconds( const FILETIME& ft ) -{ - const double low_to_sec=100e-9; // 100 nanoseconds - const double high_to_sec=low_to_sec*4294967296.0; - return ft.dwLowDateTime*low_to_sec+ft.dwHighDateTime*high_to_sec; -} -#endif // _WIN32 || _WIN64 - -#ifndef FAST_COMPILE -template< class Real , class Vertex > -int Execute( int argc , char* argv[] ) -{ - switch( BType.value ) - { - case BOUNDARY_FREE+1: - { - switch( Degree.value ) - { - case 1: return _Execute< Real , 1 , BOUNDARY_FREE , Vertex >( argc , argv ); - case 2: return _Execute< Real , 2 , BOUNDARY_FREE , Vertex >( argc , argv ); - case 3: return _Execute< Real , 3 , BOUNDARY_FREE , Vertex >( argc , argv ); - case 4: return _Execute< Real , 4 , BOUNDARY_FREE , Vertex >( argc , argv ); - default: fprintf( stderr , "[ERROR] Only B-Splines of degree 1 - 4 are supported" ) ; return EXIT_FAILURE; - } - } - case BOUNDARY_NEUMANN+1: - { - switch( Degree.value ) - { - case 1: return _Execute< Real , 1 , BOUNDARY_NEUMANN , Vertex >( argc , argv ); - case 2: return _Execute< Real , 2 , BOUNDARY_NEUMANN , Vertex >( argc , argv ); - case 3: return _Execute< Real , 3 , BOUNDARY_NEUMANN , Vertex >( argc , argv ); - case 4: return _Execute< Real , 4 , BOUNDARY_NEUMANN , Vertex >( argc , argv ); - default: fprintf( stderr , "[ERROR] Only B-Splines of degree 1 - 4 are supported" ) ; return EXIT_FAILURE; - } - } - case BOUNDARY_DIRICHLET+1: - { - switch( Degree.value ) - { - case 1: return _Execute< Real , 1 , BOUNDARY_DIRICHLET , Vertex >( argc , argv ); - case 2: return _Execute< Real , 2 , BOUNDARY_DIRICHLET , Vertex >( argc , argv ); - case 3: return _Execute< Real , 3 , BOUNDARY_DIRICHLET , Vertex >( argc , argv ); - case 4: return _Execute< Real , 4 , BOUNDARY_DIRICHLET , Vertex >( argc , argv ); - default: fprintf( stderr , "[ERROR] Only B-Splines of degree 1 - 4 are supported" ) ; return EXIT_FAILURE; - } - } - default: fprintf( stderr , "[ERROR] Not a valid boundary type: %d\n" , BType.value ) ; return EXIT_FAILURE; - } -} -#endif // !FAST_COMPILE -int main( int argc , char* argv[] ) -{ -#ifdef ARRAY_DEBUG - fprintf( stderr , "[WARNING] Running in array debugging mode\n" ); -#endif // ARRAY_DEBUG -#if defined( WIN32 ) && defined( MAX_MEMORY_GB ) - if( MAX_MEMORY_GB>0 ) - { - SIZE_T peakMemory = 1; - peakMemory <<= 30; - peakMemory *= MAX_MEMORY_GB; - printf( "Limiting memory usage to %.2f GB\n" , float( peakMemory>>30 ) ); - HANDLE h = CreateJobObject( NULL , NULL ); - AssignProcessToJobObject( h , GetCurrentProcess() ); - - JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 }; - jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_JOB_MEMORY; - jeli.JobMemoryLimit = peakMemory; - if( !SetInformationJobObject( h , JobObjectExtendedLimitInformation , &jeli , sizeof( jeli ) ) ) - fprintf( stderr , "Failed to set memory limit\n" ); - } -#endif // defined( WIN32 ) && defined( MAX_MEMORY_GB ) - double t = Time(); - - cmdLineParse( argc-1 , &argv[1] , sizeof(params)/sizeof(cmdLineReadable*) , params , 1 ); -#ifdef FAST_COMPILE - static const int Degree = 2; - static const BoundaryType BType = BOUNDARY_NEUMANN; - fprintf( stderr , "[WARNING] Compiling for degree-%d, boundary-%s, single-precision _only_\n" , Degree , BoundaryNames[ BType ] ); - if( Density.set ) - if( Color.set && Color.value>0 ) return _Execute< float , Degree , BType , PlyColorAndValueVertex< float > >( argc , argv ); - else return _Execute< float , Degree , BType , PlyValueVertex< float > >( argc , argv ); - else - if( Color.set && Color.value>0 ) return _Execute< float , Degree , BType , PlyColorVertex< float > >( argc , argv ); - else return _Execute< float , Degree , BType , PlyVertex< float > >( argc , argv ); -#else // !FAST_COMPILE - { - if( Density.set ) - if( Color.set && Color.value>0 ) - if( Double.set ) Execute< double , PlyColorAndValueVertex< float > >( argc , argv ); - else Execute< float , PlyColorAndValueVertex< float > >( argc , argv ); - else - if( Double.set ) Execute< double , PlyValueVertex< float > >( argc , argv ); - else Execute< float , PlyValueVertex< float > >( argc , argv ); - else - if( Color.set && Color.value>0 ) - if( Double.set ) Execute< double , PlyColorVertex< float > >( argc , argv ); - else Execute< float , PlyColorVertex< float > >( argc , argv ); - else - if( Double.set ) Execute< double , PlyVertex< float > >( argc , argv ); - else Execute< float , PlyVertex< float > >( argc , argv ); - } -#endif // FAST_COMPILE -#if defined( _WIN32 ) || defined( _WIN64 ) - if( Performance.set ) - { - HANDLE cur_thread=GetCurrentThread(); - FILETIME tcreat, texit, tkernel, tuser; - if( GetThreadTimes( cur_thread , &tcreat , &texit , &tkernel , &tuser ) ) - printf( "Time (Wall/User/Kernel): %.2f / %.2f / %.2f\n" , Time()-t , to_seconds( tuser ) , to_seconds( tkernel ) ); - else printf( "Time: %.2f\n" , Time()-t ); - HANDLE h = GetCurrentProcess(); - PROCESS_MEMORY_COUNTERS pmc; - if( GetProcessMemoryInfo( h , &pmc , sizeof(pmc) ) ) printf( "Peak Memory (MB): %d\n" , (int)( pmc.PeakWorkingSetSize>>20 ) ); - } -#endif // _WIN32 || _WIN64 - return EXIT_SUCCESS; -} diff --git a/Src/SSDRecon.cpp b/Src/SSDRecon.cpp deleted file mode 100644 index 9fe6e7c7..00000000 --- a/Src/SSDRecon.cpp +++ /dev/null @@ -1,786 +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. -*/ - -#undef FAST_COMPILE -#undef ARRAY_DEBUG -#define BRUNO_LEVY_FIX -#define FOR_RELEASE - -#include -#include -#include -#include -#if defined( _WIN32 ) || defined( _WIN64 ) -#include -#include -#endif // _WIN32 || _WIN64 -#include "MyTime.h" -#include "MarchingCubes.h" -#include "Octree.h" -#include "SparseMatrix.h" -#include "CmdLineParser.h" -#include "PPolynomial.h" -#include "Ply.h" -#include "MemoryUsage.h" -#ifdef _OPENMP -#include "omp.h" -#endif // _OPENMP -void DumpOutput( const char* format , ... ); -void DumpOutput2( std::vector< char* >& comments , const char* format , ... ); -#include "MultiGridOctreeData.h" - -#define DEFAULT_FULL_DEPTH 5 - -#define XSTR(x) STR(x) -#define STR(x) #x -#if DEFAULT_FULL_DEPTH -#pragma message ( "[WARNING] Setting default full depth to " XSTR(DEFAULT_FULL_DEPTH) ) -#endif // DEFAULT_FULL_DEPTH - -#include -char* outputFile=NULL; -int echoStdout=0; -void DumpOutput( const char* format , ... ) -{ - if( outputFile ) - { - FILE* fp = fopen( outputFile , "a" ); - va_list args; - va_start( args , format ); - vfprintf( fp , format , args ); - fclose( fp ); - va_end( args ); - } - if( echoStdout ) - { - va_list args; - va_start( args , format ); - vprintf( format , args ); - va_end( args ); - } -} -void DumpOutput2( std::vector< char* >& comments , const char* format , ... ) -{ - if( outputFile ) - { - FILE* fp = fopen( outputFile , "a" ); - va_list args; - va_start( args , format ); - vfprintf( fp , format , args ); - fclose( fp ); - va_end( args ); - } - if( echoStdout ) - { - va_list args; - va_start( args , format ); - vprintf( format , args ); - va_end( args ); - } - comments.push_back( new char[1024] ); - char* str = comments.back(); - va_list args; - va_start( args , format ); - vsprintf( str , format , args ); - va_end( args ); - if( str[strlen(str)-1]=='\n' ) str[strlen(str)-1] = 0; -} - - -cmdLineString - In( "in" ) , - Out( "out" ) , - TempDir( "tempDir" ) , - VoxelGrid( "voxel" ) , - XForm( "xForm" ); - -cmdLineReadable -#if defined( _WIN32 ) || defined( _WIN64 ) - Performance( "performance" ) , -#endif // _WIN32 || _WIN64 - ShowResidual( "showResidual" ) , - NoComments( "noComments" ) , - PolygonMesh( "polygonMesh" ) , - Confidence( "confidence" ) , - NormalWeights( "nWeights" ) , - NonManifold( "nonManifold" ) , - ASCII( "ascii" ) , - Density( "density" ) , - NonLinearFit( "nonLinearFit" ) , - PrimalVoxel( "primalVoxel" ) , -#ifndef FAST_COMPILE - FreeBoundary( "freeBoundary" ) , - Double( "double" ) , -#endif // !FAST_COMPILE - Verbose( "verbose" ); - -cmdLineInt -#ifndef FAST_COMPILE - Degree( "degree" , 2 ) , -#endif // !FAST_COMPILE - Depth( "depth" , 8 ) , - CGDepth( "cgDepth" , 0 ) , - KernelDepth( "kernelDepth" ) , - AdaptiveExponent( "adaptiveExp" , 1 ) , - Iters( "iters" , 8 ) , - VoxelDepth( "voxelDepth" , -1 ) , - FullDepth( "fullDepth" , DEFAULT_FULL_DEPTH ) , - MaxSolveDepth( "maxSolveDepth" ) , - Threads( "threads" , omp_get_num_procs() ); - -cmdLineFloat - Color( "color" , 16.f ) , - SamplesPerNode( "samplesPerNode" , 1.5f ) , - Scale( "scale" , 1.1f ) , - CGSolverAccuracy( "cgAccuracy" , 1e-3f ) , - LowResIterMultiplier( "iterMultiplier" , 1.5f ) , - ValueWeight ( "valueWeight" , 4e-0f ) , - GradientWeight( "gradientWeight" , 1e-3f ) , - BiLapWeight ( "biLapWeight" , 1e-5f ); - - -cmdLineReadable* params[] = -{ -#ifndef FAST_COMPILE - &Degree , &Double , &FreeBoundary , -#endif // !FAST_COMPILE - &In , &Depth , &Out , &XForm , - &Scale , &Verbose , &CGSolverAccuracy , &NoComments , &LowResIterMultiplier , - &KernelDepth , &SamplesPerNode , &Confidence , &NormalWeights , &NonManifold , &PolygonMesh , &ASCII , &ShowResidual , &VoxelDepth , - &BiLapWeight , - &ValueWeight , &GradientWeight , &VoxelGrid , &Threads , &MaxSolveDepth , - &AdaptiveExponent , - &Density , - &FullDepth , - &CGDepth , &Iters , - &Color , - &NonLinearFit , - &PrimalVoxel , - &TempDir , -#if defined( _WIN32 ) || defined( _WIN64 ) - &Performance , -#endif // _WIN32 || _WIN64 -}; - - -void ShowUsage( char* ex ) -{ - printf( "Usage: %s\n" , ex ); - printf( "\t --%s \n" , In.name ); - - printf( "\t[--%s ]\n" , Out.name ); - - printf( "\t[--%s ]\n" , VoxelGrid.name ); - -#ifndef FAST_COMPILE - printf( "\t[--%s =%d]\n" , Degree.name , Degree.value ); - -#ifndef FOR_RELEASE - printf( "\t[--%s]\n" , FreeBoundary.name ); -#endif // !FOR_RELEASE -#endif // !FAST_COMPILE - - printf( "\t[--%s =%d]\n" , Depth.name , Depth.value ); - - printf( "\t[--%s =%f]\n" , Scale.name , Scale.value ); - - printf( "\t[--%s =%f]\n" , SamplesPerNode.name, SamplesPerNode.value ); - - printf( "\t[--%s =%.3e]\n" , ValueWeight.name , ValueWeight.value ); - - printf( "\t[--%s =%.3e]\n" , GradientWeight.name , GradientWeight.value ); - - printf( "\t[--%s =%.3e]\n" , BiLapWeight.name , BiLapWeight.value ); - - printf( "\t[--%s]\n" , Confidence.name ); - - printf( "\t[--%s]\n" , NormalWeights.name ); - -#ifndef FOR_RELEASE - printf( "\t[--%s =%d]\n", AdaptiveExponent.name , AdaptiveExponent.value ); -#endif // !FOR_RELEASE - - printf( "\t[--%s =%d]\n" , Iters.name , Iters.value ); - -#ifndef FOR_RELEASE - printf( "\t[--%s =%f]\n" , LowResIterMultiplier.name , LowResIterMultiplier.value ); -#endif // FOR_RELEASE - - printf( "\t[--%s =%d]\n" , CGDepth.name , CGDepth.value ); - -#ifndef FOR_RELEASE - printf( "\t[--%s =%g]\n" , CGSolverAccuracy.name , CGSolverAccuracy.value ); -#endif // !FOR_RELEASE - - printf( "\t[--%s =%d]\n" , FullDepth.name , FullDepth.value ); - - printf( "\t[--%s =<%s>]\n" , VoxelDepth.name , Depth.name ); - - printf( "\t[--%s]\n" , PrimalVoxel.name ); - - printf( "\t[--%s ]\n" , Color.name ); - - printf( "\t[--%s]\n" , Density.name ); - - printf( "\t[--%s]\n" , NonLinearFit.name ); - - printf( "\t[--%s]\n" , PolygonMesh.name); - -#ifndef FOR_RELEASE - printf( "\t[--%s]\n" , NonManifold.name ); -#endif // !FOR_RELEASE - -#ifdef _OPENMP - printf( "\t[--%s =%d]\n" , Threads.name , Threads.value ); -#endif // _OPENMP - - printf( "\t[--%s]\n" , TempDir.name ); - - printf( "\t[--%s]\n" , Verbose.name ); - -#ifndef FOR_RELEASE -#if defined( _WIN32 ) || defined( _WIN64 ) - printf( "\t[--%s]\n" , Performance.name ); -#endif // _WIN32 || _WIN64 - -#endif // !FOR_RELEASE -#ifndef FOR_RELEASE - printf( "\t[--%s]\n" , ASCII.name ); - - printf( "\t[--%s]\n" , NoComments.name ); -#endif // !FOR_RELEASE - -#ifndef FAST_COMPILE - printf( "\t[--%s]\n" , Double.name ); -#endif // !FAST_COMPILE -} - -template< class Real > -struct ColorInfo -{ - static Point3D< Real > ReadASCII( FILE* fp ) - { - Point3D< unsigned char > c; - if( fscanf( fp , " %c %c %c " , &c[0] , &c[1] , &c[2] )!=3 ) fprintf( stderr , "[ERROR] Failed to read color\n" ) , exit( 0 ); - return Point3D< Real >( (Real)c[0] , (Real)c[1] , (Real)c[2] ); - }; - static bool ValidPlyProperties( const bool* props ){ return ( props[0] || props[3] ) && ( props[1] || props[4] ) && ( props[2] || props[5] ); } - const static PlyProperty PlyProperties[]; -}; -template<> -const PlyProperty ColorInfo< float >::PlyProperties[] = -{ - { "r" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Point3D< float > , coords[0] ) ) , 0 , 0 , 0 , 0 } , - { "g" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Point3D< float > , coords[1] ) ) , 0 , 0 , 0 , 0 } , - { "b" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Point3D< float > , coords[2] ) ) , 0 , 0 , 0 , 0 } , - { "red" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Point3D< float > , coords[0] ) ) , 0 , 0 , 0 , 0 } , - { "green" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Point3D< float > , coords[1] ) ) , 0 , 0 , 0 , 0 } , - { "blue" , PLY_UCHAR , PLY_FLOAT , int( offsetof( Point3D< float > , coords[2] ) ) , 0 , 0 , 0 , 0 } -}; -template<> -const PlyProperty ColorInfo< double >::PlyProperties[] = -{ - { "r" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Point3D< double > , coords[0] ) ) , 0 , 0 , 0 , 0 } , - { "g" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Point3D< double > , coords[1] ) ) , 0 , 0 , 0 , 0 } , - { "b" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Point3D< double > , coords[2] ) ) , 0 , 0 , 0 , 0 } , - { "red" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Point3D< double > , coords[0] ) ) , 0 , 0 , 0 , 0 } , - { "green" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Point3D< double > , coords[1] ) ) , 0 , 0 , 0 , 0 } , - { "blue" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( Point3D< double > , coords[2] ) ) , 0 , 0 , 0 , 0 } -}; - -bool ValidPlyColorProperties( const bool* props ){ return ( props[0] || props[3] ) && ( props[1] || props[4] ) && ( props[2] || props[5] ); } - -double Weight( double v , double start , double end ) -{ - v = ( v - start ) / ( end - start ); - if ( v<0 ) return 1.; - else if( v>1 ) return 0.; - else - { - // P(x) = a x^3 + b x^2 + c x + d - // P (0) = 1 , P (1) = 0 , P'(0) = 0 , P'(1) = 0 - // => d = 1 , a + b + c + d = 0 , c = 0 , 3a + 2b + c = 0 - // => c = 0 , d = 1 , a + b = -1 , 3a + 2b = 0 - // => a = 2 , b = -3 , c = 0 , d = 1 - // => P(x) = 2 x^3 - 3 x^2 + 1 - return 2. * v * v * v - 3. * v * v + 1.; - } -} - -#if defined( _WIN32 ) || defined( _WIN64 ) -double PeakMemoryUsageMB( void ) -{ - HANDLE h = GetCurrentProcess(); - PROCESS_MEMORY_COUNTERS pmc; - return GetProcessMemoryInfo( h , &pmc , sizeof(pmc) ) ? ( (double)pmc.PeakWorkingSetSize )/(1<<20) : 0; -} -#endif // _WIN32 || _WIN64 - - -template< class Real > -struct OctreeProfiler -{ - Octree< Real >& tree; - double t; - - OctreeProfiler( Octree< Real >& t ) : tree(t) { ; } - void start( void ){ t = Time() , tree.resetLocalMemoryUsage(); } - void print( const char* header ) const - { - tree.memoryUsage(); -#if defined( _WIN32 ) || defined( _WIN64 ) - if( header ) printf( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); - else printf( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); -#else // !_WIN32 && !_WIN64 - if( header ) printf( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); - else printf( "%9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); -#endif // _WIN32 || _WIN64 - } - void dumpOutput( const char* header ) const - { - tree.memoryUsage(); -#if defined( _WIN32 ) || defined( _WIN64 ) - if( header ) DumpOutput( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); - else DumpOutput( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); -#else // !_WIN32 && !_WIN64 - if( header ) DumpOutput( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); - else DumpOutput( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); -#endif // _WIN32 || _WIN64 - } - void dumpOutput2( std::vector< char* >& comments , const char* header ) const - { - tree.memoryUsage(); -#if defined( _WIN32 ) || defined( _WIN64 ) - if( header ) DumpOutput2( comments , "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); - else DumpOutput2( comments , "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() , PeakMemoryUsageMB() ); -#else // !_WIN32 && !_WIN64 - if( header ) DumpOutput2( comments , "%s %9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); - else DumpOutput2( comments , "%9.1f (s), %9.1f (MB) / %9.1f (MB)\n" , Time()-t , tree.localMemoryUsage() , tree.maxMemoryUsage() ); -#endif // _WIN32 || _WIN64 - } -}; - -template< class Real > -XForm4x4< Real > GetPointXForm( OrientedPointStream< Real >& stream , Real scaleFactor ) -{ - Point3D< Real > min , max; - stream.boundingBox( min , max ); - Point3D< Real > center = ( max + min ) / 2; - Real scale = std::max< Real >( max[0]-min[0] , std::max< Real >( max[1]-min[1] , max[2]-min[2] ) ); - scale *= scaleFactor; - for( int i=0 ; i<3 ; i++ ) center[i] -= scale/2; - XForm4x4< Real > tXForm = XForm4x4< Real >::Identity() , sXForm = XForm4x4< Real >::Identity(); - for( int i=0 ; i<3 ; i++ ) sXForm(i,i) = (Real)(1./scale ) , tXForm(3,i) = -center[i]; - return sXForm * tXForm; -} - -template< class Real , int Degree , BoundaryType BType , class Vertex > -int _Execute( int argc , char* argv[] ) -{ - typedef typename Octree< Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; - typedef typename Octree< Real >::template InterpolationInfo< true > InterpolationInfo; - typedef OrientedPointStream< Real > PointStream; - typedef OrientedPointStreamWithData< Real , Point3D< Real > > PointStreamWithData; - typedef TransformedOrientedPointStream< Real > XPointStream; - typedef TransformedOrientedPointStreamWithData< Real , Point3D< Real > > XPointStreamWithData; - Reset< Real >(); - int paramNum = sizeof(params)/sizeof(cmdLineReadable*); - std::vector< char* > comments; - - if( Verbose.set ) echoStdout=1; - - XForm4x4< Real > xForm , iXForm; - if( XForm.set ) - { - FILE* fp = fopen( XForm.value , "r" ); - if( !fp ) - { - fprintf( stderr , "[WARNING] Could not read x-form from: %s\n" , XForm.value ); - xForm = XForm4x4< Real >::Identity(); - } - else - { - for( int i=0 ; i<4 ; i++ ) for( int j=0 ; j<4 ; j++ ) - { - float f; - if( fscanf( fp , " %f " , &f )!=1 ) fprintf( stderr , "[ERROR] Execute: Failed to read xform\n" ) , exit( 0 ); - xForm(i,j) = (Real)f; - } - fclose( fp ); - } - } - else xForm = XForm4x4< Real >::Identity(); - - DumpOutput2( comments , "Running SSD Reconstruction (Version 9.011)\n" ); - char str[1024]; - for( int i=0 ; iset ) - { - params[i]->writeValue( str ); - if( strlen( str ) ) DumpOutput2( comments , "\t--%s %s\n" , params[i]->name , str ); - else DumpOutput2( comments , "\t--%s\n" , params[i]->name ); - } - - double startTime = Time(); - Real isoValue = 0; - - Octree< Real > tree; - OctreeProfiler< Real > profiler( tree ); - tree.threads = Threads.value; - if( !In.set ) - { - ShowUsage( argv[0] ); - return 0; - } - if( !MaxSolveDepth.set ) MaxSolveDepth.value = Depth.value; - - OctNode< TreeNodeData >::SetAllocator( MEMORY_ALLOCATOR_BLOCK_SIZE ); - - int kernelDepth = KernelDepth.set ? KernelDepth.value : Depth.value-2; - if( kernelDepth>Depth.value ) - { - fprintf( stderr,"[WARNING] %s can't be greater than %s: %d <= %d\n" , KernelDepth.name , Depth.name , KernelDepth.value , Depth.value ); - kernelDepth = Depth.value; - } - - int pointCount; - - Real pointWeightSum; - std::vector< typename Octree< Real >::PointSample >* samples = new std::vector< typename Octree< Real >::PointSample >(); - std::vector< ProjectiveData< Point3D< Real > , Real > >* sampleData = NULL; - DensityEstimator* density = NULL; - SparseNodeData< Point3D< Real > , NORMAL_DEGREE >* normalInfo = NULL; - Real targetValue = (Real)0.; - - // Read in the samples (and color data) - { - profiler.start(); - PointStream* pointStream; - char* ext = GetFileExtension( In.value ); - if( Color.set && Color.value>0 ) - { - sampleData = new std::vector< ProjectiveData< Point3D< Real > , Real > >(); - if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryOrientedPointStreamWithData< Real , Point3D< Real > , float , Point3D< unsigned char > >( In.value ); - else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYOrientedPointStreamWithData< Real , Point3D< Real > >( In.value , ColorInfo< Real >::PlyProperties , 6 , ColorInfo< Real >::ValidPlyProperties ); - else pointStream = new ASCIIOrientedPointStreamWithData< Real , Point3D< Real > >( In.value , ColorInfo< Real >::ReadASCII ); - } - else - { - if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryOrientedPointStream< Real , float >( In.value ); - else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYOrientedPointStream< Real >( In.value ); - else pointStream = new ASCIIOrientedPointStream< Real >( In.value ); - } - delete[] ext; - XPointStream _pointStream( xForm , *pointStream ); - xForm = GetPointXForm( _pointStream , (Real)Scale.value ) * xForm; - if( sampleData ) - { - XPointStreamWithData _pointStream( xForm , ( PointStreamWithData& )*pointStream ); - pointCount = tree.template init< Point3D< Real > >( _pointStream , Depth.value , Confidence.set , *samples , sampleData ); - } - else - { - XPointStream _pointStream( xForm , *pointStream ); - pointCount = tree.template init< Point3D< Real > >( _pointStream , Depth.value , Confidence.set , *samples , sampleData ); - } - iXForm = xForm.inverse(); - delete pointStream; -#pragma omp parallel for num_threads( Threads.value ) - for( int i=0 ; i<(int)samples->size() ; i++ ) (*samples)[i].sample.data.n *= (Real)-1; - - DumpOutput( "Input Points / Samples: %d / %d\n" , pointCount , samples->size() ); - profiler.dumpOutput2( comments , "# Read input into tree:" ); - } - - DenseNodeData< Real , Degree > solution; - // Solve - { - DenseNodeData< Real , Degree > constraints; - InterpolationInfo* iInfo = NULL; - int solveDepth = MaxSolveDepth.value; - - tree.resetNodeIndices(); - - // Get the kernel density estimator - { - profiler.start(); - density = tree.template setDensityEstimator< WEIGHT_DEGREE >( *samples , kernelDepth , SamplesPerNode.value ); - profiler.dumpOutput2( comments , "# Got kernel density:" ); - } - - // Transform the Hermite samples into a vector field - { - profiler.start(); - normalInfo = new SparseNodeData< Point3D< Real > , NORMAL_DEGREE >(); - *normalInfo = tree.template setNormalField< NORMAL_DEGREE >( *samples , *density , pointWeightSum , BType==BOUNDARY_NEUMANN ); - profiler.dumpOutput2( comments , "# Got normal field:" ); - } - - if( !Density.set ) delete density , density = NULL; - - // Trim the tree and prepare for multigrid - { - profiler.start(); - std::vector< int > indexMap; - - constexpr int MAX_DEGREE = NORMAL_DEGREE > Degree ? NORMAL_DEGREE : Degree; - tree.template inalizeForBroodedMultigrid< MAX_DEGREE , Degree , BType >( FullDepth.value , typename Octree< Real >::template HasNormalDataFunctor< NORMAL_DEGREE >( *normalInfo ) , &indexMap ); - - if( normalInfo ) normalInfo->remapIndices( indexMap ); - if( density ) density->remapIndices( indexMap ); - profiler.dumpOutput2( comments , "# Finalized tree:" ); - } - - // Free up the normal info - if( normalInfo ) delete normalInfo , normalInfo = NULL; - - // Add the interpolation constraints - if( ValueWeight.value>0 || GradientWeight.value>0 ) - { - profiler.start(); - iInfo = new InterpolationInfo( tree , *samples , targetValue , AdaptiveExponent.value , (Real)ValueWeight.value * pointWeightSum , (Real)GradientWeight.value * pointWeightSum ); - constraints = tree.template initDenseNodeData< Degree >( ); - tree.template addInterpolationConstraints< Degree , BType >( *iInfo , constraints , solveDepth ); - profiler.dumpOutput2( comments , "#Set point constraints:" ); - } - - DumpOutput( "Leaf Nodes / Active Nodes / Ghost Nodes: %d / %d / %d\n" , (int)tree.leaves() , (int)tree.nodes() , (int)tree.ghostNodes() ); - DumpOutput( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage())/(1<<20) ); - - // Solve the linear system - { - profiler.start(); - typename Octree< Real >::SolverInfo solverInfo; - solverInfo.cgDepth = CGDepth.value , solverInfo.iters = Iters.value , solverInfo.cgAccuracy = CGSolverAccuracy.value , solverInfo.verbose = Verbose.set , solverInfo.showResidual = ShowResidual.set , solverInfo.lowResIterMultiplier = std::max< double >( 1. , LowResIterMultiplier.value ); - solution = tree.template solveSystem< Degree , BType >( FEMSystemFunctor< Degree , BType >( 0 , 0 , BiLapWeight.value ) , iInfo , constraints , solveDepth , solverInfo ); - profiler.dumpOutput2( comments , "# Linear system solved:" ); - DumpOutput( "Memory Usage: %.3f MB\n" , float( MemoryInfo::Usage() )/(1<<20) ); - if( iInfo ) delete iInfo , iInfo = NULL; - } - } - - char tempHeader[1024]; - { -#if defined( _WIN32 ) || defined( _WIN64 ) - const char FileSeparator = '\\'; -#else // !_WIN - const char FileSeparator = '/'; -#endif // _WIN - char tempPath[1024]; - tempPath[0] = 0; - if( TempDir.set ) strcpy( tempPath , TempDir.value ); - else - { -#if defined( _WIN32 ) || defined( _WIN64 ) - GetTempPath( sizeof(tempPath) , tempPath ); -#else // !_WIN - if( std::getenv( "TMPDIR" ) ) strcpy( tempPath , std::getenv( "TMPDIR" ) ); -#endif // _WIN - } - if( strlen(tempPath)==0 ) sprintf( tempPath , ".%c" , FileSeparator ); - if( tempPath[ strlen( tempPath )-1 ]==FileSeparator ) sprintf( tempHeader , "%sPR_" , tempPath ); - else sprintf( tempHeader , "%s%cPR_" , tempPath , FileSeparator ); - } - CoredFileMeshData< Vertex > mesh( tempHeader ); - - { - profiler.start(); - double valueSum = 0 , weightSum = 0; - typename Octree< Real >::template MultiThreadedEvaluator< Degree , BType > evaluator( &tree , solution , Threads.value ); -#pragma omp parallel for num_threads( Threads.value ) reduction( + : valueSum , weightSum ) - for( int j=0 ; jsize() ; j++ ) - { - ProjectiveData< OrientedPoint3D< Real > , Real >& sample = (*samples)[j].sample; - Real w = sample.weight; - if( w>0 ) weightSum += w , valueSum += evaluator.value( sample.data.p / sample.weight , omp_get_thread_num() , (*samples)[j].node ) * w; - } - isoValue = (Real)( valueSum / weightSum ); - if( !( Color.set && Color.value>0 ) && samples ) delete samples , samples = NULL; - profiler.dumpOutput( "Got average:" ); - DumpOutput( "Iso-Value: %e\n" , isoValue ); - } - - if( VoxelGrid.set ) - { - profiler.start(); - FILE* fp = fopen( VoxelGrid.value , "wb" ); - if( !fp ) fprintf( stderr , "Failed to open voxel file for writing: %s\n" , VoxelGrid.value ); - else - { - int res = 0; - Pointer( Real ) values = tree.template voxelEvaluate< Real , Degree , BType >( solution , res , isoValue , VoxelDepth.value , PrimalVoxel.set ); - fwrite( &res , sizeof(int) , 1 , fp ); - if( sizeof(Real)==sizeof(float) ) fwrite( values , sizeof(float) , res*res*res , fp ); - else - { - float *fValues = new float[res*res*res]; - for( int i=0 ; i , Real > , DATA_DEGREE >* colorData = NULL; - if( sampleData ) - { - colorData = new SparseNodeData< ProjectiveData< Point3D< Real > , Real > , DATA_DEGREE >(); - *colorData = tree.template setDataField< DATA_DEGREE , false >( *samples , *sampleData , (DensityEstimator*)NULL ); - delete sampleData , sampleData = NULL; - for( const OctNode< TreeNodeData >* n = tree.tree().nextNode() ; n ; n=tree.tree().nextNode( n ) ) - { - ProjectiveData< Point3D< Real > , Real >* clr = (*colorData)( n ); - if( clr ) (*clr) *= (Real)pow( Color.value , tree.depth( n ) ); - } - } - tree.template getMCIsoSurface< Degree , BType , WEIGHT_DEGREE , DATA_DEGREE >( density , colorData , solution , isoValue , mesh , NonLinearFit.set , !NonManifold.set , PolygonMesh.set ); - DumpOutput( "Vertices / Polygons: %d / %d\n" , mesh.outOfCorePointCount()+mesh.inCorePoints.size() , mesh.polygonCount() ); - if( PolygonMesh.set ) profiler.dumpOutput2( comments , "# Got polygons:" ); - else profiler.dumpOutput2( comments , "# Got triangles:" ); - - if( colorData ) delete colorData , colorData = NULL; - - if( NoComments.set ) - { - if( ASCII.set ) PlyWritePolygons( Out.value , &mesh , PLY_ASCII , NULL , 0 , iXForm ); - else PlyWritePolygons( Out.value , &mesh , PLY_BINARY_NATIVE , NULL , 0 , iXForm ); - } - else - { - if( ASCII.set ) PlyWritePolygons( Out.value , &mesh , PLY_ASCII , &comments[0] , (int)comments.size() , iXForm ); - else PlyWritePolygons( Out.value , &mesh , PLY_BINARY_NATIVE , &comments[0] , (int)comments.size() , iXForm ); - } - } - if( density ) delete density , density = NULL; - DumpOutput2( comments , "# Total Solve: %9.1f (s), %9.1f (MB)\n" , Time()-startTime , tree.maxMemoryUsage() ); - - return 1; -} - -#if defined( _WIN32 ) || defined( _WIN64 ) -inline double to_seconds( const FILETIME& ft ) -{ - const double low_to_sec=100e-9; // 100 nanoseconds - const double high_to_sec=low_to_sec*4294967296.0; - return ft.dwLowDateTime*low_to_sec+ft.dwHighDateTime*high_to_sec; -} -#endif // _WIN32 || _WIN64 - -#ifndef FAST_COMPILE -template< class Real , class Vertex > -int Execute( int argc , char* argv[] ) -{ - if( FreeBoundary.set ) - switch( Degree.value ) - { - case 2: return _Execute< Real , 2 , BOUNDARY_FREE , Vertex >( argc , argv ); - case 3: return _Execute< Real , 3 , BOUNDARY_FREE , Vertex >( argc , argv ); - case 4: return _Execute< Real , 4 , BOUNDARY_FREE , Vertex >( argc , argv ); - default: fprintf( stderr , "[ERROR] Only B-Splines of degree 2 - 4 are supported" ) ; return EXIT_FAILURE; - } - else - switch( Degree.value ) - { - case 2: return _Execute< Real , 2 , BOUNDARY_NEUMANN , Vertex >( argc , argv ); - case 3: return _Execute< Real , 3 , BOUNDARY_NEUMANN , Vertex >( argc , argv ); - case 4: return _Execute< Real , 4 , BOUNDARY_NEUMANN , Vertex >( argc , argv ); - default: fprintf( stderr , "[ERROR] Only B-Splines of degree 2 - 4 are supported" ) ; return EXIT_FAILURE; - } -} -#endif // !FAST_COMPILE -int main( int argc , char* argv[] ) -{ -#if defined(WIN32) && defined(MAX_MEMORY_GB) - if( MAX_MEMORY_GB>0 ) - { - SIZE_T peakMemory = 1; - peakMemory <<= 30; - peakMemory *= MAX_MEMORY_GB; - printf( "Limiting memory usage to %.2f GB\n" , float( peakMemory>>30 ) ); - HANDLE h = CreateJobObject( NULL , NULL ); - AssignProcessToJobObject( h , GetCurrentProcess() ); - - JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 }; - jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_JOB_MEMORY; - jeli.JobMemoryLimit = peakMemory; - if( !SetInformationJobObject( h , JobObjectExtendedLimitInformation , &jeli , sizeof( jeli ) ) ) - fprintf( stderr , "Failed to set memory limit\n" ); - } -#endif // defined(WIN32) && defined(MAX_MEMORY_GB) - double t = Time(); - - cmdLineParse( argc-1 , &argv[1] , sizeof(params)/sizeof(cmdLineReadable*) , params , 1 ); - if( GradientWeight.value<=0 ) fprintf( stderr , "[ERROR] Gradient weight must be positive: %g>=0\n" , GradientWeight.value ) , exit( 0 ); - if( BiLapWeight.value<=0 ) fprintf( stderr , "[ERROR] Bi-Laplacian weight must be positive: %g>=0\n" , BiLapWeight.value ) , exit( 0 ); -#ifdef FAST_COMPILE - static const int Degree = 2; - static const BoundaryType BType = BOUNDARY_NEUMANN; - fprintf( stderr , "[WARNING] Compiling for degree-%d, boundary-%s, single-precision _only_\n" , Degree , BoundaryNames[ BType ] ); - if( Density.set ) - if( Color.set && Color.value>0 ) _Execute< float , Degree , BType , PlyColorAndValueVertex< float > >( argc , argv ); - else _Execute< float , Degree , BType , PlyValueVertex< float > >( argc , argv ); - else - if( Color.set && Color.value>0 ) _Execute< float , Degree , BType , PlyColorVertex< float > >( argc , argv ); - else _Execute< float , Degree , BType , PlyVertex< float > >( argc , argv ); -#else // !FAST_COMPILE - if( Density.set ) - if( Color.set && Color.value>0 ) - if( Double.set ) Execute< double , PlyColorAndValueVertex< float > >( argc , argv ); - else Execute< float , PlyColorAndValueVertex< float > >( argc , argv ); - else - if( Double.set ) Execute< double , PlyValueVertex< float > >( argc , argv ); - else Execute< float , PlyValueVertex< float > >( argc , argv ); - else - if( Color.set && Color.value>0 ) - if( Double.set ) Execute< double , PlyColorVertex< float > >( argc , argv ); - else Execute< float , PlyColorVertex< float > >( argc , argv ); - else - if( Double.set ) Execute< double , PlyVertex< float > >( argc , argv ); - else Execute< float , PlyVertex< float > >( argc , argv ); -#endif // FAST_COMPILE -#if defined( _WIN32 ) || defined( _WIN64 ) - if( Performance.set ) - { - HANDLE cur_thread=GetCurrentThread(); - FILETIME tcreat, texit, tkernel, tuser; - if( GetThreadTimes( cur_thread , &tcreat , &texit , &tkernel , &tuser ) ) - printf( "Time (Wall/User/Kernel): %.2f / %.2f / %.2f\n" , Time()-t , to_seconds( tuser ) , to_seconds( tkernel ) ); - else printf( "Time: %.2f\n" , Time()-t ); - HANDLE h = GetCurrentProcess(); - PROCESS_MEMORY_COUNTERS pmc; - if( GetProcessMemoryInfo( h , &pmc , sizeof(pmc) ) ) printf( "Peak Memory (MB): %d\n" , (int)(pmc.PeakWorkingSetSize>>20) ); - } -#endif // _WIN32 || _WIN64 - return EXIT_SUCCESS; -} diff --git a/Src/SparseMatrix.h b/Src/SparseMatrix.h deleted file mode 100644 index f133157f..00000000 --- a/Src/SparseMatrix.h +++ /dev/null @@ -1,194 +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 __SPARSEMATRIX_HPP -#define __SPARSEMATRIX_HPP - -#define NEW_SPARSE_MATRIX 1 -#define ZERO_TESTING_JACOBI 1 - - -#include "Array.h" - -template -struct MatrixEntry -{ - MatrixEntry( void ) { N =-1; Value = 0; } - MatrixEntry( int i ) { N = i; Value = 0; } - MatrixEntry( int i , T v ) { N = i; Value = v; } - int N; - T Value; -}; - -template class SparseMatrix -{ -private: - bool _contiguous; - int _maxEntriesPerRow; - void _init( void ); -public: - int rows; - Pointer( int ) rowSizes; - Pointer( Pointer( MatrixEntry< T > ) ) m_ppElements; - Pointer( MatrixEntry< T > ) operator[] ( int idx ) { return m_ppElements[idx]; } - ConstPointer( MatrixEntry< T > ) operator[] ( int idx ) const { return m_ppElements[idx]; } - - SparseMatrix( void ); - SparseMatrix( int rows ); - SparseMatrix( int rows , int maxEntriesPerRow ); - void Resize( int rows ); - void Resize( int rows , int maxEntriesPerRow ); - void SetRowSize( int row , int count ); - int Entries( void ) const; - - SparseMatrix( const SparseMatrix& M ); - ~SparseMatrix(); - - void SetZero(); - - SparseMatrix& operator = (const SparseMatrix& M); - - SparseMatrix operator * (const T& V) const; - SparseMatrix& operator *= (const T& V); - - template< class T2 > void Multiply( ConstPointer( T2 ) in , Pointer( T2 ) out , int threads=1 ) const; - template< class T2 > void MultiplyAndAddAverage( ConstPointer( T2 ) in , Pointer( T2 ) out , int threads=1 ) const; - - bool write( FILE* fp ) const; - bool write( const char* fileName ) const; - bool read( FILE* fp ); - bool read( const char* fileName ); - - template< class T2 > void getDiagonal( Pointer( T2 ) diagonal , int threads=1 ) const; - template< class T2 > static int SolveJacobi( const SparseMatrix& M , ConstPointer( T2 ) b , Pointer( T2 ) x , Pointer( T2 ) Mx , T2 sor , int threads=1 ); - template< class T2 > static int SolveJacobi( const SparseMatrix& M , ConstPointer( T2 ) diagonal , ConstPointer( T2 ) b , Pointer( T2 ) x , Pointer( T2 ) Mx , T2 sor , int threads=1 ); - template< class T2 > static int SolveGS( const SparseMatrix& M , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward ); - template< class T2 > static int SolveGS( const SparseMatrix& M , ConstPointer( T2 ) diagonal , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward ); - template< class T2 > static int SolveGS( const std::vector< std::vector< int > >& mcIndices , const SparseMatrix& M , ConstPointer( T2 ) diagonal , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward , int threads=1 ); - template< class T2 > static int SolveGS( const std::vector< std::vector< int > >& mcIndices , const SparseMatrix& M , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward , int threads=1 ); - template< class T2 > static int SolveCG( const SparseMatrix& M , ConstPointer( T2 ) b , int iters , Pointer( T2 ) x , T2 eps=1e-8 , int reset=1 , bool addDCTerm=false , bool solveNormal=false , int threads=1 ); -}; - - -#if !NEW_SPARSE_MATRIX -template< class T2 > -struct MapReduceVector -{ -private: - int _dim; -public: - std::vector< T2* > out; - MapReduceVector( void ) { _dim = 0; } - ~MapReduceVector( void ) - { - if( _dim ) for( int t=0 ; t -class SparseSymmetricMatrix : public SparseMatrix< T > -{ -public: - - template< class T2 > - Vector< T2 > operator * ( const Vector& V ) const; - - template< class T2 > - Vector< T2 > Multiply( const Vector& V ) const; - - template< class T2 > - void Multiply( const Vector& In, Vector& Out , bool addDCTerm=false ) const; - - template< class T2 > - void Multiply( const Vector& In, Vector& Out , MapReduceVector< T2 >& OutScratch , bool addDCTerm=false ) const; - - template< class T2 > - void Multiply( const Vector& In, Vector& Out , std::vector< T2* >& OutScratch , const std::vector< int >& bounds ) const; - - template< class T2 > - static int SolveCG( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , T2 eps=1e-8 , int reset=1 , int threads=0 , bool addDCTerm=false , bool solveNormal=false ); - - template< class T2 > - static int SolveCG( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , MapReduceVector& scratch , T2 eps=1e-8 , int reset=1 , bool addDCTerm=false , bool solveNormal=false ); -#ifdef WIN32 - template< class T2 > - static int SolveCGAtomic( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , T2 eps=1e-8 , int reset=1 , int threads=0 , bool solveNormal=false ); -#endif // WIN32 - template< class T2 > - static int SolveJacobi( const SparseSymmetricMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , MapReduceVector& scratch , Vector& Mx , T2 sor , int reset ); - template< class T2 > - static int SolveJacobi( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , MapReduceVector& scratch , T2 sor=T2(1.) , int reset=1 ); - template< class T2 > - static int SolveJacobi( const SparseSymmetricMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , Vector& Mx , T2 sor , int reset ); - template< class T2 > - static int SolveJacobi( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , T2 sor=T2(1.) , int reset=1 ); - - enum - { - ORDERING_UPPER_TRIANGULAR , - ORDERING_LOWER_TRIANGULAR , - ORDERING_NONE - }; - template< class T2 > - static int SolveGS( const std::vector< std::vector< int > >& mcIndices , const SparseSymmetricMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , MapReduceVector& scratch , Vector& Mx , Vector& dx , bool forward , int reset ); - template< class T2 > - static int SolveGS( const std::vector< std::vector< int > >& mcIndices , const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , MapReduceVector& scratch , bool forward , int reset=1 ); - - template< class T2 > - static int SolveGS( const SparseSymmetricMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , MapReduceVector& scratch , Vector& Mx , Vector& dx , bool forward , int reset , int ordering ); - template< class T2 > - static int SolveGS( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , MapReduceVector& scratch , bool forward , int reset=1 , int ordering=ORDERING_NONE ); - template< class T2 > - static int SolveGS( const SparseSymmetricMatrix& M , const Vector& diagonal , const Vector& b , Vector& x , Vector& Mx , Vector& dx , bool forward , int reset , int ordering ); - template< class T2 > - static int SolveGS( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& x , bool forward , int reset=1 , int ordering=ORDERING_NONE ); - - template< class T2 > - void getDiagonal( Vector< T2 >& diagonal , int threads=1 ) const; -}; -#endif // !NEW_SPARSE_MATRIX - -#include "SparseMatrix.inl" - -#endif - diff --git a/Src/SparseMatrix.inl b/Src/SparseMatrix.inl deleted file mode 100644 index 763590ae..00000000 --- a/Src/SparseMatrix.inl +++ /dev/null @@ -1,504 +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 - - -/////////////////// -// SparseMatrix // -/////////////////// -/////////////////////////////////////// -// SparseMatrix Methods and Memebers // -/////////////////////////////////////// - -template< class T > -void SparseMatrix< T >::_init( void ) -{ - _contiguous = false; - _maxEntriesPerRow = 0; - rows = 0; - rowSizes = NullPointer( int ); - m_ppElements = NullPointer( Pointer( MatrixEntry< T > ) ); -} - -template< class T > SparseMatrix< T >::SparseMatrix( void ){ _init(); } - -template< class T > SparseMatrix< T >::SparseMatrix( int rows ){ _init() , Resize( rows ); } -template< class T > SparseMatrix< T >::SparseMatrix( int rows , int maxEntriesPerRow ){ _init() , Resize( rows , maxEntriesPerRow ); } - -template< class T > -SparseMatrix< T >::SparseMatrix( const SparseMatrix& M ) -{ - _init(); - if( M._contiguous ) Resize( M.rows , M._maxEntriesPerRow ); - else Resize( M.rows ); - for( int i=0 ; i ) * rowSizes[i] ); - } -} -template -int SparseMatrix::Entries( void ) const -{ - int e = 0; - for( int i=0 ; i -SparseMatrix& SparseMatrix::operator = (const SparseMatrix& M) -{ - if( M._contiguous ) Resize( M.rows , M._maxEntriesPerRow ); - else Resize( M.rows ); - for( int i=0 ; i ) * rowSizes[i] ); - } - return *this; -} - -template -SparseMatrix::~SparseMatrix( void ){ Resize( 0 ); } - -template< class T > -bool SparseMatrix< T >::write( const char* fileName ) const -{ - FILE* fp = fopen( fileName , "wb" ); - if( !fp ) return false; - bool ret = write( fp ); - fclose( fp ); - return ret; -} -template< class T > -bool SparseMatrix< T >::read( const char* fileName ) -{ - FILE* fp = fopen( fileName , "rb" ); - if( !fp ) return false; - bool ret = read( fp ); - fclose( fp ); - return ret; -} -template< class T > -bool SparseMatrix< T >::write( FILE* fp ) const -{ - if( fwrite( &rows , sizeof( int ) , 1 , fp )!=1 ) return false; - if( fwrite( rowSizes , sizeof( int ) , rows , fp )!=rows ) return false; - for( int i=0 ; i ) , rowSizes[i] , fp )!=rowSizes[i] ) return false; - return true; -} -template< class T > -bool SparseMatrix< T >::read( FILE* fp ) -{ - int r; - if( fread( &r , sizeof( int ) , 1 , fp )!=1 ) return false; - Resize( r ); - if( fread( rowSizes , sizeof( int ) , rows , fp )!=rows ) return false; - for( int i=0 ; i ) , rowSizes[i] , fp )!=rowSizes[i] ) return false; - } - return true; -} - - -template< class T > -void SparseMatrix< T >::Resize( int r ) -{ - if( rows>0 ) - { - if( _contiguous ){ if( _maxEntriesPerRow ) FreePointer( m_ppElements[0] ); } - else for( int i=0 ; i( r ); - m_ppElements = AllocPointer< Pointer( MatrixEntry< T > ) >( r ); - memset( rowSizes , 0 , sizeof( int ) * r ); - } - _contiguous = false; - _maxEntriesPerRow = 0; -} -template< class T > -void SparseMatrix< T >::Resize( int r , int e ) -{ - if( rows>0 ) - { - if( _contiguous ){ if( _maxEntriesPerRow ) FreePointer( m_ppElements[0] ); } - else for( int i=0 ; i( r ); - m_ppElements = AllocPointer< Pointer( MatrixEntry< T > ) >( r ); - m_ppElements[0] = AllocPointer< MatrixEntry< T > >( r * e ); - memset( rowSizes , 0 , sizeof( int ) * r ); - for( int i=1 ; i -void SparseMatrix< T >::SetRowSize( int row , int count ) -{ - if( _contiguous ) - { - if( count>_maxEntriesPerRow ) fprintf( stderr , "[ERROR] Cannot set row size on contiguous matrix: %d<=%d\n" , count , _maxEntriesPerRow ) , exit( 0 ); - rowSizes[row] = count; - } - else if( row>=0 && row0 ) m_ppElements[row] = AllocPointer< MatrixEntry< T > >( count ); - // [WARNING] Why wasn't this line here before??? - rowSizes[row] = count; - } -} - - -template -void SparseMatrix::SetZero() -{ - Resize(this->m_N, this->m_M); -} - -template -SparseMatrix SparseMatrix::operator * (const T& V) const -{ - SparseMatrix M(*this); - M *= V; - return M; -} - -template -SparseMatrix& SparseMatrix::operator *= (const T& V) -{ - for( int i=0 ; i -template< class T2 > -void SparseMatrix< T >::Multiply( ConstPointer( T2 ) in , Pointer( T2 ) out , int threads ) const -{ -#pragma omp parallel for num_threads( threads ) - for( int i=0 ; i ) start = m_ppElements[i]; - ConstPointer( MatrixEntry< T > ) end = start + rowSizes[i]; - ConstPointer( MatrixEntry< T > ) e; - for( e=start ; e!=end ; e++ ) _out += in[ e->N ] * e->Value; - out[i] = _out; - } -} -template< class T > -template< class T2 > -void SparseMatrix< T >::MultiplyAndAddAverage( ConstPointer( T2 ) in , Pointer( T2 ) out , int threads ) const -{ -#if 1 - int count = 0; - T2 average = 0; -#pragma omp parallel for num_threads( threads ) reduction( + : average , count ) - for( int i=0 ; i -template< class T2 > -int SparseMatrix::SolveJacobi( const SparseMatrix& M , ConstPointer( T2 ) diagonal , ConstPointer( T2 ) b , Pointer( T2 ) x , Pointer( T2 ) Mx , T2 sor , int threads ) -{ - M.Multiply( x , Mx , threads ); -#if ZERO_TESTING_JACOBI - for( int j=0 ; j -template< class T2 > -int SparseMatrix::SolveJacobi( const SparseMatrix& M , ConstPointer( T2 ) b , Pointer( T2 ) x , Pointer( T2 ) Mx , T2 sor , int threads ) -{ - M.Multiply( x , Mx , threads ); -#if ZERO_TESTING_JACOBI - for( int j=0 ; j -template -int SparseMatrix::SolveGS( const SparseMatrix& M , ConstPointer( T2 ) diagonal , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward ) -{ -#define ITERATE \ - { \ - ConstPointer( MatrixEntry< T > ) start = M[j]; \ - ConstPointer( MatrixEntry< T > ) end = start + M.rowSizes[j]; \ - ConstPointer( MatrixEntry< T > ) e; \ - T2 _b = b[j]; \ - for( e=start ; e!=end ; e++ ) _b -= x[ e->N ] * e->Value; \ - x[j] += _b / diagonal[j]; \ - } - -#if ZERO_TESTING_JACOBI - if( forward ) for( int j=0 ; j=0 ; j-- ){ if( diagonal[j] ){ ITERATE; } } -#else // !ZERO_TESTING_JACOBI - if( forward ) for( int j=0 ; j=0 ; j-- ){ ITERATE; } -#endif // ZERO_TESTING_JACOBI -#undef ITERATE - return M.rows; -} -template -template -int SparseMatrix::SolveGS( const std::vector< std::vector< int > >& mcIndices , const SparseMatrix& M , ConstPointer( T2 ) diagonal , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward , int threads ) -{ - int sum=0; -#ifdef _WIN32 -#define SetOMPParallel __pragma( omp parallel for num_threads( threads ) ) -#else // !_WIN32 -#define SetOMPParallel _Pragma( "omp parallel for num_threads( threads )" ) -#endif // _WIN32 -#if ZERO_TESTING_JACOBI -#define ITERATE( indices ) \ - { \ -SetOMPParallel \ - for( int k=0 ; k ) start = M[jj]; \ - ConstPointer( MatrixEntry< T > ) end = start + M.rowSizes[jj]; \ - ConstPointer( MatrixEntry< T > ) e; \ - T2 _b = b[jj]; \ - for( e=start ; e!=end ; e++ ) _b -= x[ e->N ] * e->Value; \ - x[jj] += _b / diagonal[jj]; \ - } \ - } -#else // !ZERO_TESTING_JACOBI -#define ITERATE( indices ) \ - { \ -SetOMPParallel \ - for( int k=0 ; k ) start = M[jj]; \ - ConstPointer( MatrixEntry< T > ) end = start + M.rowSizes[jj]; \ - ConstPointer( MatrixEntry< T > ) e; \ - T2 _b = b[jj]; \ - for( e=start ; e!=end ; e++ ) _b -= x[ e->N ] * e->Value; \ - x[jj] += _b / diagonal[jj]; \ - } \ - } -#endif // ZERO_TESTING_JACOBI - if( forward ) for( int j=0 ; j=0 ; j-- ){ sum += int( mcIndices[j].size() ) ; ITERATE( mcIndices[j] ); } -#undef ITERATE -#undef SetOMPParallel - return sum; -} -template -template -int SparseMatrix::SolveGS( const SparseMatrix& M , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward ) -{ - int start = forward ? 0 : M.rows-1 , end = forward ? M.rows : -1 , dir = forward ? 1 : -1; - for( int j=start ; j!=end ; j+=dir ) - { - T diagonal = M[j][0].Value; -#if ZERO_TESTING_JACOBI - if( diagonal ) -#endif // ZERO_TESTING_JACOBI - { - ConstPointer( MatrixEntry< T > ) start = M[j]; - ConstPointer( MatrixEntry< T > ) end = start + M.rowSizes[j]; - ConstPointer( MatrixEntry< T > ) e; - start++; - T2 _b = b[j]; - for( e=start ; e!=end ; e++ ) _b -= x[ e->N ] * e->Value; - x[j] = _b / diagonal; - } - } - return M.rows; -} -template -template -int SparseMatrix::SolveGS( const std::vector< std::vector< int > >& mcIndices , const SparseMatrix& M , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward , int threads ) -{ - int sum=0 , start = forward ? 0 : int( mcIndices.size() )-1 , end = forward ? int( mcIndices.size() ) : -1 , dir = forward ? 1 : -1; - for( int j=start ; j!=end ; j+=dir ) - { - const std::vector< int >& _mcIndices = mcIndices[j]; - sum += int( _mcIndices.size() ); - { -#pragma omp parallel for num_threads( threads ) - for( int k=0 ; k ) start = M[jj]; - ConstPointer( MatrixEntry< T > ) end = start + M.rowSizes[jj]; - ConstPointer( MatrixEntry< T > ) e; - start++; - T2 _b = b[jj]; - for( e=start ; e!=end ; e++ ) _b -= x[ e->N ] * e->Value; - x[jj] = _b / diagonal; - } - } - } - } - return sum; -} - -template< class T > -template< class T2 > -void SparseMatrix< T >::getDiagonal( Pointer( T2 ) diagonal , int threads ) const -{ -#pragma omp parallel for num_threads( threads ) - for( int i=0 ; i ) start = m_ppElements[i]; - ConstPointer( MatrixEntry< T > ) end = start + rowSizes[i]; - ConstPointer( MatrixEntry< T > ) e; - for( e=start ; e!=end ; e++ ) if( e->N==i ) d += e->Value; - diagonal[i] = d; - } -} -template< class T > -template< class T2 > -int SparseMatrix< T >::SolveCG( const SparseMatrix& A , ConstPointer( T2 ) b , int iters , Pointer( T2 ) x , T2 eps , int reset , bool addDCTerm , bool solveNormal , int threads ) -{ - eps *= eps; - int dim = A.rows; - Pointer( T2 ) r = AllocPointer< T2 >( dim ); - Pointer( T2 ) d = AllocPointer< T2 >( dim ); - Pointer( T2 ) q = AllocPointer< T2 >( dim ); - Pointer( T2 ) temp = NullPointer( T2 ); - if( reset ) memset( x , 0 , sizeof(T2)* dim ); - if( solveNormal ) temp = AllocPointer< T2 >( dim ); - - double delta_new = 0 , delta_0; - if( solveNormal ) - { - if( addDCTerm ) A.MultiplyAndAddAverage( ( ConstPointer( T2 ) )x , temp , threads ) , A.MultiplyAndAddAverage( ( ConstPointer( T2 ) )temp , r , threads ) , A.MultiplyAndAddAverage( ( ConstPointer( T2 ) )b , temp , threads ); - else A.Multiply( ( ConstPointer( T2 ) )x , temp , threads ) , A.Multiply( ( ConstPointer( T2 ) )temp , r , threads ) , A.Multiply( ( ConstPointer( T2 ) )b , temp , threads ); -#pragma omp parallel for num_threads( threads ) reduction( + : delta_new ) - for( int i=0 ; ieps*delta_0 ; ii++ ) - { - if( solveNormal ) - if( addDCTerm ) A.MultiplyAndAddAverage( ( ConstPointer( T2 ) )d , temp , threads ) , A.MultiplyAndAddAverage( ( ConstPointer( T2 ) )temp , q , threads ); - else A.Multiply( ( ConstPointer( T2 ) )d , temp , threads ) , A.Multiply( ( ConstPointer( T2 ) )temp , q , threads ); - else - if( addDCTerm ) A.MultiplyAndAddAverage( ( ConstPointer( T2 ) )d , q , threads ); - else A.Multiply( ( ConstPointer( T2 ) )d , q , threads ); - double dDotQ = 0; -#pragma omp parallel for num_threads( threads ) reduction( + : dDotQ ) - for( int i=0 ; i -#include -#include -#ifdef _OPENMP -#include -#endif // _OPENMP -#include -#include "CmdLineParser.h" -#include "Geometry.h" -#include "Ply.h" -#include "MAT.h" -#include "MyTime.h" - -cmdLineString In( "in" ) , Out( "out" ); -cmdLineInt Smooth( "smooth" , 5 ); -cmdLineFloat Trim( "trim" ) , IslandAreaRatio( "aRatio" , 0.001f ); -cmdLineReadable PolygonMesh( "polygonMesh" ); - -cmdLineReadable* params[] = -{ - &In , &Out , &Trim , &PolygonMesh , &Smooth , &IslandAreaRatio -}; - -void ShowUsage( char* ex ) -{ - printf( "Usage: %s\n" , ex ); - printf( "\t --%s \n" , In.name ); - printf( "\t[--%s ]\n" , Trim.name ); - printf( "\t[--%s ]\n" , Out.name ); - printf( "\t[--%s =%d]\n" , Smooth.name , Smooth.value ); - printf( "\t[--%s =%f]\n" , IslandAreaRatio.name , IslandAreaRatio.value ); - printf( "\t[--%s]\n" , PolygonMesh.name ); -} - -long long EdgeKey( int key1 , int key2 ) -{ - if( key1 -Vertex InterpolateVertices( const Vertex& v1 , const Vertex& v2 , Real value ) -{ - typename Vertex::Wrapper _v1(v1) , _v2(v2); - if( _v1.value==_v2.value ) return Vertex( (_v1+_v2)/Real(2.) ); - - Real dx = ( _v1.value-value ) / ( _v1.value-_v2.value ); - return Vertex( _v1*(1.f-dx) + _v2*dx ); -} -template< class Real , class Vertex > -void SmoothValues( std::vector< Vertex >& vertices , const std::vector< std::vector< int > >& polygons ) -{ - std::vector< int > count( vertices.size() ); - std::vector< Real > sums( vertices.size() , 0 ); - for( size_t i=0 ; i -void SplitPolygon - ( - const std::vector< int >& polygon , - std::vector< Vertex >& vertices , - std::vector< std::vector< int > >* ltPolygons , std::vector< std::vector< int > >* gtPolygons , - std::vector< bool >* ltFlags , std::vector< bool >* gtFlags , - std::unordered_map< long long, int >& vertexTable, - Real trimValue - ) -{ - int sz = int( polygon.size() ); - std::vector< bool > gt( sz ); - int gtCount = 0; - for( int j=0 ; jtrimValue ); - if( gt[j] ) gtCount++; - } - if ( gtCount==sz ){ if( gtPolygons ) gtPolygons->push_back( polygon ) ; if( gtFlags ) gtFlags->push_back( false ); } - else if( gtCount==0 ){ if( ltPolygons ) ltPolygons->push_back( polygon ) ; if( ltFlags ) ltFlags->push_back( false ); } - else - { - int start; - for( start=0 ; start poly; - - // Add the initial vertex - { - int j1 = (start+int(sz)-1)%sz , j2 = start; - int v1 = polygon[j1] , v2 = polygon[j2]; - int vIdx; - std::unordered_map< long long, int >::iterator iter = vertexTable.find(EdgeKey(v1, v2)); - if( iter==vertexTable.end() ) - { - vertexTable[ EdgeKey( v1 , v2 ) ] = vIdx = int( vertices.size() ); - vertices.push_back( InterpolateVertices( vertices[v1] , vertices[v2] , trimValue ) ); - } - else vIdx = iter->second; - poly.push_back( vIdx ); - } - - for( int _j=0 ; _j<=sz ; _j++ ) - { - int j1 = (_j+start+sz-1)%sz , j2 = (_j+start)%sz; - int v1 = polygon[j1] , v2 = polygon[j2]; - if( gt[j2]==gtFlag ) poly.push_back( v2 ); - else - { - int vIdx; - std::unordered_map< long long, int >::iterator iter = vertexTable.find(EdgeKey(v1, v2)); - if( iter==vertexTable.end() ) - { - vertexTable[ EdgeKey( v1 , v2 ) ] = vIdx = int( vertices.size() ); - vertices.push_back( InterpolateVertices( vertices[v1] , vertices[v2] , trimValue ) ); - } - else vIdx = iter->second; - poly.push_back( vIdx ); - if( gtFlag ){ if( gtPolygons ) gtPolygons->push_back( poly ) ; if( ltFlags ) ltFlags->push_back( true ); } - else { if( ltPolygons ) ltPolygons->push_back( poly ) ; if( gtFlags ) gtFlags->push_back( true ); } - poly.clear() , poly.push_back( vIdx ) , poly.push_back( v2 ); - gtFlag = !gtFlag; - } - } - } -} -template< class Real , class Vertex > -void Triangulate( const std::vector< Vertex >& vertices , const std::vector< std::vector< int > >& polygons , std::vector< std::vector< int > >& triangles ) -{ - triangles.clear(); - for( size_t i=0 ; i3 ) - { - MinimalAreaTriangulation< Real > mat; - std::vector< Point3D< Real > > _vertices( polygons[i].size() ); - std::vector< TriangleIndex > _triangles; - for( int j=0 ; j -double PolygonArea( const std::vector< Vertex >& vertices , const std::vector< int >& polygon ) -{ - if( polygon.size()<3 ) return 0.; - else if( polygon.size()==3 ) return TriangleArea( vertices[polygon[0]].point , vertices[polygon[1]].point , vertices[polygon[2]].point ); - else - { - Point3D< Real > center; - for( size_t i=0 ; i -void RemoveHangingVertices( std::vector< Vertex >& vertices , std::vector< std::vector< int > >& polygons ) -{ - std::unordered_map< int, int > vMap; - std::vector< bool > vertexFlags( vertices.size() , false ); - for( size_t i=0 ; i _vertices( vCount ); - for( int i=0 ; i >& polygons , std::vector< std::vector< int > >& components ) -{ - std::vector< int > polygonRoots( polygons.size() ); - for( size_t i=0 ; i edgeTable; - for( size_t i=0 ; i::iterator iter = edgeTable.find(eKey); - if( iter==edgeTable.end() ) edgeTable[ eKey ] = int(i); - else - { - int p = iter->second; - while( polygonRoots[p]!=p ) - { - int temp = polygonRoots[p]; - polygonRoots[p] = int(i); - p = temp; - } - polygonRoots[p] = int(i); - } - } - } - for( size_t i=0 ; i vMap; - for( int i= 0 ; i -inline Point3D< Real > CrossProduct( Point3D< Real > p1 , Point3D< Real > p2 ){ return Point3D< Real >( p1[1]*p2[2]-p1[2]*p2[1] , p1[2]*p2[0]-p1[0]*p2[2] , p1[0]*p1[1]-p1[1]*p2[0] ); } -template< class Real > -double TriangleArea( Point3D< Real > v1 , Point3D< Real > v2 , Point3D< Real > v3 ) -{ - Point3D< Real > n = CrossProduct( v2-v1 , v3-v1 ); - return sqrt( n[0]*n[0] + n[1]*n[1] + n[2]*n[2] ) / 2.; -} -template< class Vertex > -int Execute( void ) -{ - float min , max; - int paramNum = sizeof(params)/sizeof(cmdLineReadable*); - std::vector< Vertex > vertices; - std::vector< std::vector< int > > polygons; - - int ft , commentNum = paramNum+2; - char** comments; - PlyReadPolygons( In.value , vertices , polygons , Vertex::ReadProperties , Vertex::ReadComponents , ft , &comments , &commentNum ); - for( int i=0 ; i( vertices , polygons ); - min = max = vertices[0].value; - for( size_t i=0 ; i( min , vertices[i].value ) , max = std::max< float >( max , vertices[i].value ); - printf( "Value Range: [%f,%f]\n" , min , max ); - - std::unordered_map< long long, int > vertexTable; - std::vector< std::vector< int > > ltPolygons , gtPolygons; - std::vector< bool > ltFlags , gtFlags; - - for( int i=0 ; i0 ) - { - std::vector< std::vector< int > > _ltPolygons , _gtPolygons; - std::vector< std::vector< int > > ltComponents , gtComponents; - SetConnectedComponents( ltPolygons , ltComponents ); - SetConnectedComponents( gtPolygons , gtComponents ); - std::vector< double > ltAreas( ltComponents.size() , 0. ) , gtAreas( gtComponents.size() , 0. ); - std::vector< bool > ltComponentFlags( ltComponents.size() , false ) , gtComponentFlags( gtComponents.size() , false ); - double area = 0.; - for( size_t i=0 ; i( vertices , ltPolygons[ ltComponents[i][j] ] ); - ltComponentFlags[i] = ( ltComponentFlags[i] || ltFlags[ ltComponents[i][j] ] ); - } - area += ltAreas[i]; - } - for( size_t i=0 ; i( vertices , gtPolygons[ gtComponents[i][j] ] ); - gtComponentFlags[i] = ( gtComponentFlags[i] || gtFlags[ gtComponents[i][j] ] ); - } - area += gtAreas[i]; - } - for( size_t i=0 ; i > polys = ltPolygons; - Triangulate< float , Vertex >( vertices , ltPolygons , polys ) , ltPolygons = polys; - } - { - std::vector< std::vector< int > > polys = gtPolygons; - Triangulate< float , Vertex >( vertices , gtPolygons , polys ) , gtPolygons = polys; - } - } - - RemoveHangingVertices( vertices , gtPolygons ); - sprintf( comments[commentNum++] , "#Trimmed In: %9.1f (s)" , Time()-t ); - if( Out.set ) PlyWritePolygons( Out.value , vertices , gtPolygons , Vertex::WriteProperties , Vertex::WriteComponents , ft , comments , commentNum ); - - return EXIT_SUCCESS; -} -int main( int argc , char* argv[] ) -{ - int paramNum = sizeof(params)/sizeof(cmdLineReadable*); - cmdLineParse( argc-1 , &argv[1] , paramNum , params , 0 ); - - if( !In.set || !Trim.set ) - { - ShowUsage( argv[0] ); - return EXIT_FAILURE; - } - bool readFlags[ PlyColorAndValueVertex< float >::ReadComponents ]; - if( !PlyReadHeader( In.value , PlyColorAndValueVertex< float >::ReadProperties , PlyColorAndValueVertex< float >::ReadComponents , readFlags ) ) fprintf( stderr , "[ERROR] Failed to read ply header: %s\n" , In.value ) , exit( 0 ); - - bool hasValue = readFlags[3]; - bool hasColor = ( readFlags[4] || readFlags[7] ) && ( readFlags[5] || readFlags[8] ) && ( readFlags[6] || readFlags[9] ); - - if( !hasValue ) fprintf( stderr , "[ERROR] Ply file does not contain values\n" ) , exit( 0 ); - if( hasColor ) return Execute< PlyColorAndValueVertex< float > >(); - else return Execute< PlyValueVertex< float > >(); -} diff --git a/SurfaceTrimmer.vcxproj b/SurfaceTrimmer.vcxproj deleted file mode 100644 index 383f6786..00000000 --- a/SurfaceTrimmer.vcxproj +++ /dev/null @@ -1,184 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {99BEAFED-8DB9-4B7D-A0BE-5186158193FE} - MeshClipper - Win32Proj - SurfaceTrimmer - 8.1 - - - - Application - Unicode - true - v140 - - - Application - Unicode - true - v140 - - - Application - Unicode - v140 - - - Application - Unicode - v140 - true - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.40219.1 - $(SolutionDir)$(Configuration)\ - $(SolutionDir)Bin\$(Platform)\$(Configuration)\ - $(Configuration)\ - $(SolutionDir)\Obj\$(TargetName)\$(Platform)\$(Configuration)\ - true - true - $(SolutionDir)Bin\$(Platform)\$(Configuration)\ - $(SolutionDir)Bin\$(Platform)\$(Configuration)\ - $(SolutionDir)\Obj\$(TargetName)\$(Platform)\$(Configuration)\ - $(SolutionDir)\Obj\$(TargetName)\$(Platform)\$(Configuration)\ - false - false - AllRules.ruleset - AllRules.ruleset - - - - - AllRules.ruleset - AllRules.ruleset - - - - - - - - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - EditAndContinue - - - true - Console - MachineX86 - - - - - Disabled - _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - ProgramDatabase - true - - - true - Console - - - - - %(AdditionalIncludeDirectories) - WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - MultiThreadedDLL - - - Level3 - ProgramDatabase - true - - - true - Console - true - true - MachineX86 - - - - - %(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - MultiThreadedDLL - - - Level3 - ProgramDatabase - true - - - true - Console - true - true - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/SurfaceTrimmer.vcxproj.filters b/SurfaceTrimmer.vcxproj.filters deleted file mode 100644 index b6ea680a..00000000 --- a/SurfaceTrimmer.vcxproj.filters +++ /dev/null @@ -1,47 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - {237cb93d-2caa-4f6b-9bb3-5d597e5fd1dd} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {e857a52e-da0b-4eea-9e27-7b9c21e142c9} - h;hpp;hxx;hm;inl;inc;xsd - - - {61c77966-1174-4dae-9079-00d39bbe4aab} - inc;inl - - - - - Include Files - - - \ No newline at end of file diff --git a/apps/AdaptiveTreeVisualization/CMakeLists.txt b/apps/AdaptiveTreeVisualization/CMakeLists.txt new file mode 100644 index 00000000..049e9c73 --- /dev/null +++ b/apps/AdaptiveTreeVisualization/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.7) + +project(AdaptiveTreeVisualization) + +set(PROJECT_SRCS ${PROJECT_SOURCE_DIR}/src/AdaptiveTreeVisualization.cpp) + +source_group("src" FILES ${PROJECT_SRCS}) + +find_package(OpenMP REQUIRED) + +add_executable(${PROJECT_NAME} ${PROJECT_SRCS}) + +target_link_libraries(${PROJECT_NAME} PoissonRecon OpenMP::OpenMP_CXX) + +set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER ${CMAKE_PROJECT_NAME}/apps) + +install(TARGETS ${PROJECT_NAME} EXPORT ${CMAKE_PROJECT_NAME}Targets DESTINATION + bin) diff --git a/apps/AdaptiveTreeVisualization/src/AdaptiveTreeVisualization.cpp b/apps/AdaptiveTreeVisualization/src/AdaptiveTreeVisualization.cpp new file mode 100644 index 00000000..f08b582a --- /dev/null +++ b/apps/AdaptiveTreeVisualization/src/AdaptiveTreeVisualization.cpp @@ -0,0 +1,351 @@ +/* +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. +*/ + +#include "Mesh/PoissonRecon/PreProcessor.h" + +#include +#include +#include +#include +#include "Mesh/PoissonRecon/MyMiscellany.h" +#include "Mesh/PoissonRecon/CmdLineParser.h" +#include "Mesh/PoissonRecon/PPolynomial.h" +#include "Mesh/PoissonRecon/FEMTree.h" +#include "Mesh/PoissonRecon/Ply.h" +#include "Mesh/PoissonRecon/PointStreamData.h" +#include "Mesh/PoissonRecon/Image.h" + +cmdLineParameter< char* > + In( "in" ) , + Samples( "samples" ) , + OutMesh( "mesh" ) , + OutGrid( "grid" ); + +cmdLineReadable + PolygonMesh( "polygonMesh" ) , + NonManifold( "nonManifold" ) , + FlipOrientation( "flip" ) , + ASCII( "ascii" ) , + NonLinearFit( "nonLinearFit" ) , + PrimalGrid( "primalGrid" ) , + Verbose( "verbose" ); + +cmdLineParameter< int > + ParallelType( "parallel" , (int)ThreadPool::OPEN_MP ) , + ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , + ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , + Threads( "threads" , (int)std::thread::hardware_concurrency() ); + +cmdLineParameter< float > + IsoValue( "iso" , 0.f ); + +cmdLineReadable* params[] = +{ + &In , + &Samples , + &OutMesh , &NonManifold , &PolygonMesh , &FlipOrientation , &ASCII , &NonLinearFit , &IsoValue , + &OutGrid , &PrimalGrid , + &Threads , + &Verbose , + &ParallelType , + &ScheduleType , + &ThreadChunkSize , + NULL +}; + + +void ShowUsage( char* ex ) +{ + printf( "Usage: %s\n" , ex ); + printf( "\t --%s \n" , In.name ); + printf( "\t[--%s sample positions>]\n" , Samples.name ); + printf( "\t[--%s ]\n" , OutMesh.name ); + printf( "\t[--%s ]\n" , OutGrid.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 ); + for( size_t i=0 ; i=%d]\n" , ThreadChunkSize.name , ThreadChunkSize.value ); + printf( "\t[--%s =%f]\n" , IsoValue.name , IsoValue.value ); + printf( "\t[--%s]\n" , NonManifold.name ); + printf( "\t[--%s]\n" , PolygonMesh.name ); + printf( "\t[--%s]\n" , NonLinearFit.name ); + printf( "\t[--%s]\n" , FlipOrientation.name ); + printf( "\t[--%s]\n" , PrimalGrid.name ); + printf( "\t[--%s]\n" , ASCII.name ); + printf( "\t[--%s]\n" , Verbose.name ); +} + +template< typename Real , unsigned int Dim > +void WriteGrid( ConstPointer( Real ) values , int res , const char *fileName ) +{ + int resolution = 1; + for( int d=0 ; d avgs( ThreadPool::NumThreads() , 0 ); + ThreadPool::Parallel_for( 0 , resolution , [&]( unsigned int thread , size_t i ){ avgs[thread] += values[i]; } ); + for( unsigned int t=0 ; t stds( ThreadPool::NumThreads() , 0 ); + ThreadPool::Parallel_for( 0 , resolution , [&]( 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 ); + + unsigned char *pixels = new unsigned char[ resolution*3 ]; + ThreadPool::Parallel_for( 0 , resolution , [&]( 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 + { + + FILE *fp = fopen( fileName , "wb" ); + if( !fp ) ERROR_OUT( "Failed to open grid file for writing: " , fileName ); + else + { + fwrite( &res , sizeof(int) , 1 , fp ); + if( typeid(Real)==typeid(float) ) fwrite( values , sizeof(float) , resolution , fp ); + else + { + float *fValues = new float[resolution]; + for( int i=0 ; i +void _Execute( const FEMTree< Dim , Real >* tree , XForm< Real , Dim+1 > xForm , FILE* fp ) +{ + 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 ); + + // Evaluate at the sample positions + if( Samples.set ) + { + InputPointStream< Real , Dim > *pointStream; + char* ext = GetFileExtension( Samples.value ); + if ( !strcasecmp( ext , "bpts" ) ) pointStream = new BinaryInputPointStream< Real , Dim >( Samples.value ); + else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYInputPointStream< Real , Dim >( Samples.value ); + else pointStream = new ASCIIInputPointStream< Real , Dim >( Samples.value ); + delete[] ext; + typename FEMTree< Dim , Real >::template MultiThreadedEvaluator< IsotropicUIntPack< Dim , FEMSig > , 0 > evaluator( tree , coefficients ); + static const unsigned int CHUNK_SIZE = 1024; + Point< Real , Dim > points[ CHUNK_SIZE ]; + Real values[ CHUNK_SIZE ]; + size_t pointsRead; + while( ( pointsRead=pointStream->nextPoints( points , CHUNK_SIZE ) ) ) + { + ThreadPool::Parallel_for( 0 , pointsRead , [&]( unsigned int thread , size_t j ) + { + Point< Real , Dim > p = xForm * points[j]; + bool inBounds = true; + for( int d=0 ; d1 ) inBounds = false; + if( inBounds ) values[j] = evaluator.values( xForm * points[j] , thread )[0]; + else values[j] = (Real)nan( "" ); + } + ); + for( int j=0 ; jtemplate regularGridEvaluate< true >( coefficients , res , -1 , PrimalGrid.set ); + if( Verbose.set ) printf( "Got grid: %.2f(s)\n" , Time()-t ); + WriteGrid< Real , Dim >( values , res , OutGrid.value ); + DeletePointer( values ); + } + + // Output the mesh + if( OutMesh.set ) + { + double t = Time(); + typedef PlyVertex< Real , Dim > Vertex; + CoredFileMeshData< Vertex , node_index_type > mesh; + std::function< void ( Vertex& , Point< Real , Dim > , Real , Real ) > SetVertex = []( Vertex& v , Point< Real , Dim > p , Real , Real ){ v.point = p; }; +#if defined( __GNUC__ ) && __GNUC__ < 5 +#warning "you've got me gcc version<5" + static const unsigned int DataSig = FEMDegreeAndBType< 0 , BOUNDARY_FREE >::Signature; + IsoSurfaceExtractor< Dim , Real , Vertex >::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 , SetVertex , NonLinearFit.set , !NonManifold.set , PolygonMesh.set , FlipOrientation.set ); +#else // !__GNUC__ || __GNUC__ >=5 + IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< Real >( IsotropicUIntPack< Dim , FEMSig >() , UIntPack< 0 >() , UIntPack< FEMTrivialSignature >() , *tree , ( typename FEMTree< Dim , Real >::template DensityEstimator< 0 >* )NULL , NULL , coefficients , IsoValue.value , mesh , SetVertex , NonLinearFit.set , !NonManifold.set , PolygonMesh.set , FlipOrientation.set ); +#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.outOfCorePointCount()+mesh.inCorePoints.size() ) , (unsigned long long)mesh.polygonCount() ); + + std::vector< std::string > comments; + if( !PlyWritePolygons< Vertex , node_index_type , Real , Dim >( OutMesh.value , &mesh , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , comments , xForm.inverse() ) ) + ERROR_OUT( "Could not write mesh to: " , OutMesh.value ); + } +} + + +template< unsigned int Dim , class Real > +void Execute( FILE* fp , int degree , BoundaryType bType ) +{ + XForm< Real , Dim+1 > xForm; + FEMTree< Dim , Real > tree( fp , xForm , 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() ); + + switch( bType ) + { + case BOUNDARY_FREE: + { + switch( degree ) + { + case 1: _Execute< Dim , Real , FEMDegreeAndBType< 1 , BOUNDARY_FREE >::Signature >( &tree , xForm , fp ) ; break; + case 2: _Execute< Dim , Real , FEMDegreeAndBType< 2 , BOUNDARY_FREE >::Signature >( &tree , xForm , fp ) ; break; + case 3: _Execute< Dim , Real , FEMDegreeAndBType< 3 , BOUNDARY_FREE >::Signature >( &tree , xForm , fp ) ; break; + case 4: _Execute< Dim , Real , FEMDegreeAndBType< 4 , BOUNDARY_FREE >::Signature >( &tree , xForm , fp ) ; break; + default: ERROR_OUT( "Only B-Splines of degree 1 - 4 are supported" ); + } + } + break; + case BOUNDARY_NEUMANN: + { + switch( degree ) + { + case 1: _Execute< Dim , Real , FEMDegreeAndBType< 1 , BOUNDARY_NEUMANN >::Signature >( &tree , xForm , fp ) ; break; + case 2: _Execute< Dim , Real , FEMDegreeAndBType< 2 , BOUNDARY_NEUMANN >::Signature >( &tree , xForm , fp ) ; break; + case 3: _Execute< Dim , Real , FEMDegreeAndBType< 3 , BOUNDARY_NEUMANN >::Signature >( &tree , xForm , fp ) ; break; + case 4: _Execute< Dim , Real , FEMDegreeAndBType< 4 , BOUNDARY_NEUMANN >::Signature >( &tree , xForm , fp ) ; break; + default: ERROR_OUT( "Only B-Splines of degree 1 - 4 are supported" ); + } + } + break; + case BOUNDARY_DIRICHLET: + { + switch( degree ) + { + case 1: _Execute< Dim , Real , FEMDegreeAndBType< 1 , BOUNDARY_DIRICHLET >::Signature >( &tree , xForm , fp ) ; break; + case 2: _Execute< Dim , Real , FEMDegreeAndBType< 2 , BOUNDARY_DIRICHLET >::Signature >( &tree , xForm , fp ) ; break; + case 3: _Execute< Dim , Real , FEMDegreeAndBType< 3 , BOUNDARY_DIRICHLET >::Signature >( &tree , xForm , fp ) ; break; + case 4: _Execute< Dim , Real , FEMDegreeAndBType< 4 , BOUNDARY_DIRICHLET >::Signature >( &tree , xForm , fp ) ; break; + default: ERROR_OUT( "Only B-Splines of degree 1 - 4 are supported" ); + } + } + break; + default: ERROR_OUT( "Not a valid boundary type: " , bType ); + } +} + +int main( int argc , char* argv[] ) +{ +#ifdef ARRAY_DEBUG + WARN( "Array debugging enabled" ); +#endif // ARRAY_DEBUG + cmdLineParse( argc-1 , &argv[1] , params ); + ThreadPool::DefaultChunkSize = ThreadChunkSize.value; + ThreadPool::DefaultSchedule = (ThreadPool::ScheduleType)ScheduleType.value; + if( Verbose.set ) + { + printf( "**************************************************\n" ); + printf( "**************************************************\n" ); + printf( "** Running Octree Visualization (Version %s) **\n" , VERSION ); + printf( "**************************************************\n" ); + printf( "**************************************************\n" ); + if( !Threads.set ) printf( "Running with %d threads\n" , Threads.value ); + } + + if( !In.set ) + { + ShowUsage( argv[0] ); + return EXIT_FAILURE; + } + FILE* fp = fopen( In.value , "rb" ); + 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 ); + { + unsigned int dim = dimension; + unsigned int* sigs = ReadDenseNodeDataSignatures( fp , 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; + 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; + default: ERROR_OUT( "Unrecognized real type: " , realType ); + } + break; + default: ERROR_OUT( "Only dimensions 1-4 supported" ); + } + + fclose( fp ); + return EXIT_SUCCESS; +} diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt new file mode 100644 index 00000000..1f6afa9b --- /dev/null +++ b/apps/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.7) +project(apps) + +add_subdirectory(AdaptiveTreeVisualization) +add_subdirectory(ChunkPLY) +add_subdirectory(EDTInHeat) +add_subdirectory(ImageStitching) +add_subdirectory(PointInterpolant) +add_subdirectory(PoissonRecon) +add_subdirectory(SSDRecon) +add_subdirectory(SurfaceTrimmer) +add_subdirectory(VoxelCompare) diff --git a/apps/ChunkPLY/CMakeLists.txt b/apps/ChunkPLY/CMakeLists.txt new file mode 100644 index 00000000..1a6fdf4e --- /dev/null +++ b/apps/ChunkPLY/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.7) + +project(ChunkPLY) + +set(PROJECT_SRCS ${PROJECT_SOURCE_DIR}/src/ChunkPLY.cpp) + +source_group("src" FILES ${PROJECT_SRCS}) + +add_executable(${PROJECT_NAME} ${PROJECT_SRCS}) + +target_link_libraries(${PROJECT_NAME} PoissonRecon) + +set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER ${CMAKE_PROJECT_NAME}/apps) + +install(TARGETS ${PROJECT_NAME} EXPORT ${CMAKE_PROJECT_NAME}Targets DESTINATION + bin) diff --git a/apps/ChunkPLY/src/ChunkPLY.cpp b/apps/ChunkPLY/src/ChunkPLY.cpp new file mode 100644 index 00000000..0d8589fa --- /dev/null +++ b/apps/ChunkPLY/src/ChunkPLY.cpp @@ -0,0 +1,520 @@ +/* +Copyright (c) 2013, 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 "Mesh/PoissonRecon/PreProcessor.h" + +#define NEW_CHUNKS +#define DISABLE_PARALLELIZATION + +// -80,-130,40 +#include +#include +#include +#include +#include +#include +#include "Mesh/PoissonRecon/MyMiscellany.h" +#include "Mesh/PoissonRecon/CmdLineParser.h" +#include "Mesh/PoissonRecon/Geometry.h" +#include "Mesh/PoissonRecon/Ply.h" +#include "Mesh/PoissonRecon/PointStream.h" +#include "Mesh/PoissonRecon/PointStreamData.h" + +cmdLineParameter< char* > In( "in" ) , Out( "out" ); +cmdLineParameter< float > Width( "width" , -1.f ) , PadRadius( "radius" , 0.f ); +cmdLineParameterArray< float , 6 > BoundingBox( "bBox" ); +cmdLineReadable ASCII( "ascii" ) , Verbose( "verbose" ); + +cmdLineReadable* params[] = { &In , &Out , &Width , &PadRadius , &ASCII , &Verbose , &BoundingBox , 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" , Width.name , Width.value ); + printf( "\t[--%s =%f]\n" , PadRadius.name , PadRadius.value ); + printf( "\t[--%s ]\n" , BoundingBox.name ); + printf( "\t[--%s]\n" , ASCII.name ); + printf( "\t[--%s]\n" , Verbose.name ); +} + +void PrintBoundingBox( Point< float , 3 > min , Point< float , 3 > max ) +{ + printf( "[" ); + 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( " ]" ); +} + +template< typename ... VertexData > +void WritePoints( const char *fileName , int ft , const std::vector< PlyVertexWithData< float , 3 , MultiPointStreamData< float , VertexData ... > > > &vertices , const std::vector< std::string > &comments ) +{ + typedef PlyVertexWithData< float , 3 , MultiPointStreamData< float , VertexData ... > > Vertex; + typedef MultiPointStreamData< float , VertexData ... > StreamData; + + PLYOutputPointStreamWithData< float , 3 , StreamData > pointStream( fileName , vertices.size() , ft , StreamData::PlyWriteProperties() , StreamData::PlyWriteNum ); + for( size_t i=0 ; i +void WriteMesh( const char *fileName , int ft , const std::vector< PlyVertexWithData< float , 3 , MultiPointStreamData< float , VertexData ... > > > &vertices , const std::vector< std::vector< long long > > &polygons , const std::vector< std::string > &comments ) +{ + typedef PlyVertexWithData< float , 3 , MultiPointStreamData< float , VertexData ... > > Vertex; + + 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() ); + std::vector< std::vector< unsigned int > > outPolygons; + outPolygons.resize( polygons.size() ); + for( size_t i=0 ; i( fileName , vertices , outPolygons , Vertex::PlyWriteProperties() , Vertex::PlyWriteNum , ft , comments ) ) ERROR_OUT( "Could not write mesh to: " , fileName ); + } + else + { + std::vector< std::vector< int > > outPolygons; + outPolygons.resize( polygons.size() ); + for( size_t i=0 ; i( fileName , vertices , outPolygons , Vertex::PlyWriteProperties() , Vertex::PlyWriteNum , ft , comments ) ) ERROR_OUT( "Could not write mesh to: " , fileName ); + } +} + +template< typename Vertex > +void GetBoundingBox( const std::vector< Vertex > &vertices , Point< float , 3 > &min , Point< float , 3 > &max ) +{ + min = max = vertices[0].point; + for( size_t i=0 ; i( min[d] , vertices[i].point[d] ); + max[d] = std::max< float >( max[d] , vertices[i].point[d] ); + } +} + +template< typename Vertex > +void GetSubPoints( const std::vector< Vertex > &vertices , Point< float , 3 > min , Point< float , 3 > max , std::vector< Vertex > &subVertices ) +{ + subVertices.resize( 0 ); + + for( size_t i=0 ; i=max[d] ) inside = false; + if( inside ) subVertices.push_back( vertices[i] ); + } +} + +template< typename Vertex > +void GetSubVertices( const std::vector< Vertex > &vertices , std::vector< std::vector< long long > > &polygons , std::vector< Vertex > &subVertices ) +{ + subVertices.resize( 0 ); + long long count = 0; + std::unordered_map< long long , long long > vMap; + for( size_t i=0 ; i +void GetSubMesh( const std::vector< Vertex > &vertices , const std::vector< std::vector< long long > > &polygons , Point< float , 3 > min , Point< float , 3 > max , std::vector< Vertex > &subVertices , std::vector< std::vector< long long > > &subPolygons ) +{ + subPolygons.resize( 0 ); + + for( size_t i=0 ; i center; + for( size_t j=0 ; j=max[d] ) inside = false; + if( inside ) subPolygons.push_back( polygons[i] ); + } + + GetSubVertices( vertices , subPolygons , subVertices ); +} + +template< typename ... VertexData > +void Execute( void ) +{ + Timer timer; + double t = Time(); + typedef PlyVertexWithData< float , 3 , MultiPointStreamData< float , VertexData ... > > Vertex; + std::vector< Vertex > vertices; + std::vector< std::vector< long long > > polygons; + + int ft; + std::vector< std::string > comments; + PlyReadPolygons< Vertex >( In.value , vertices , polygons , Vertex::PlyReadProperties() , Vertex::PlyReadNum , ft , comments ); + printf( "Vertices / Polygons: %llu / %llu\n" , (unsigned long long)vertices.size() , (unsigned long long)polygons.size() ); + printf( "Time (Wall/CPU): %.2f / %.2f\n" , timer.wallTime() , timer.cpuTime() ); + printf( "Peak Memory (MB): %d\n" , MemoryInfo::PeakMemoryUsageMB() ); + + Point< float , 3 > min , max; + GetBoundingBox( vertices , min , max ); + PrintBoundingBox( min , max ) ; printf( "\n" ); + + float width = Width.value; + + + if( BoundingBox.set ) + { + Point< float , 3 > min( BoundingBox.values[0] , BoundingBox.values[1] , BoundingBox.values[2] ); + Point< float , 3 > max( BoundingBox.values[4] , BoundingBox.values[5] , BoundingBox.values[6] ); + auto InBoundingBox = [&]( Point< float , 3 > p ) + { + return + p[0]>=min[0] && p[0]=min[1] && p[1]=min[2] && p[2] > _polygons; + + Timer timer; +#ifdef NEW_CHUNKS + { + size_t polygonCount = 0; + for( size_t i=0 ; i center; + for( int j=0 ; j center; + for( int j=0 ; j _vertices; + GetSubVertices( vertices , _polygons , _vertices ); + + if( Verbose.set ) + { + printf( "\t\t%s\n" , Out.value ); + printf( "\t\t\tVertices / Polygons: %llu / %llu\n" , (unsigned long long)_vertices.size() , (unsigned long long)_polygons.size() ); + } + + WriteMesh( Out.value , ASCII.set ? PLY_ASCII : ft , _vertices , _polygons , comments ); + } + else WARN( "no polygons in bounding box" ); + } + else + { + std::vector< Vertex > _vertices; + + Timer timer; +#ifdef NEW_CHUNKS + { + size_t vertexCount = 0; + for( size_t i=0 ; i0 ) + { + float radius = PadRadius.value * width; + size_t vCount=0 , pCount=0; + 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 ) }; + int size [] = { end[0]-begin[0]+1 , end[1]-begin[1]+1 , end[2]-begin[2]+1 }; + struct Range{ int begin[3] , end[3]; }; + auto SetRange = [&]( Point< float , 3 > p , Range &range ) + { + for( int d=0 ; d<3 ; d++ ) + { + range.begin[d] = (int)floor( (p[d]-radius)/width ) , range.end[d] = (int)ceil( (p[d]+radius)/width ); + if( range.begin[d]==range.end[d] ) range.end[d]++; + } + }; + auto Index1D = [&]( int x , int y , int z ) + { + x -= begin[0] , y -= begin[1] , z -= begin[2]; + return x + y*size[0] + z*size[0]*size[1]; + }; + auto Index3D = [&]( int idx , int &x , int &y , int &z ) + { + x = idx % size[0]; + idx /= size[0]; + y = idx % size[1]; + idx /= size[1]; + z = idx % size[2]; + x += begin[0] , y += begin[1] , z += begin[2]; + }; + + if( polygons.size() ) + { + std::vector< std::vector< std::vector< long long > > > _polygons( size[0]*size[1]*size[2] ); + Range range; + + Timer timer; +#ifdef NEW_CHUNKS + { + std::vector< size_t > polygonCounts( size[0]*size[1]*size[2] , 0 ); + for( size_t i=0 ; i center; + for( int j=0 ; j center; + for( int j=0 ; j _vertices; + GetSubVertices( vertices , _polygons[i] , _vertices ); + std::stringstream stream; + int x , y , z; + Index3D( i , x , y , z ); + + stream << Out.value << "." << x << "." << y << "." << z << ".ply"; + + + Point< float , 3 > min , max; + min = Point< float , 3 >( x+0 , y+0 , z+0 ) * width; + max = Point< float , 3 >( x+1 , y+1 , z+1 ) * width; + if( Verbose.set ) + { + static std::mutex mutex; + std::lock_guard< std::mutex > lock( mutex ); + printf( "\t\t%s\n" , stream.str().c_str() ); + printf( "\t\t\tVertices / Polygons: %llu / %llu\n" , (unsigned long long)_vertices.size() , (unsigned long long)_polygons[i].size() ); + printf( "\t\t\t" ) ; PrintBoundingBox( min , max ) ; printf( "\n" ); + } + + WriteMesh( stream.str().c_str() , ASCII.set ? PLY_ASCII : ft , _vertices , _polygons[i] , comments ); + vCount += _vertices.size() , pCount += _polygons[i].size(); + } + } + } + else + { + std::vector< std::vector< Vertex > > _vertices( size[0]*size[1]*size[2] ); + Range range; + + Timer timer; +#ifdef NEW_CHUNKS + { + std::vector< size_t > vertexCounts( size[0]*size[1]*size[2] , 0 ); + for( size_t i=0 ; i min , max; + min = Point< float , 3 >( x+0 , y+0 , z+0 ) * width; + max = Point< float , 3 >( x+1 , y+1 , z+1 ) * width; + + if( Verbose.set ) + { + static std::mutex mutex; + std::lock_guard< std::mutex > lock( mutex ); + printf( "\t\t%s\n" , stream.str().c_str() ); + printf( "\t\t\tPoints: %llu\n" , (unsigned long long)_vertices[i].size() ); + printf( "\t\t\t" ) ; PrintBoundingBox( min , max ) ; printf( "\n" ); + } + + WritePoints( stream.str().c_str() , ASCII.set ? PLY_ASCII : ft , _vertices[i] , comments ); + vCount += _vertices[i].size(); + } + } + } + if( !radius ) + { + if( polygons.size() ) + { + if( pCount!=polygons.size() ) WARN( "polygon counts don't match: " , polygons.size() , " != " , pCount ); + } + else + { + if( vCount!=vertices.size() ) WARN( "vertex counts don't match:" , vertices.size() , " != " , vCount ); + } + } + } + else + { + if( Out.set ) + { + if( polygons.size() ) WriteMesh( Out.value , ASCII.set ? PLY_ASCII : ft , vertices , polygons , comments ); + else WritePoints( Out.value , ASCII.set ? PLY_ASCII : ft , vertices , comments ); + } + } +} +int main( int argc , char* argv[] ) +{ + 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 + + if( !In.set ) + { + ShowUsage( argv[0] ); + return EXIT_FAILURE; + } + Timer timer; + + typedef MultiPointStreamData< float , PointStreamValue< float > , PointStreamNormal< float , 3 > , PointStreamColor< float > > VertexData; + typedef PlyVertexWithData< float , 3 , VertexData > Vertex; + bool readFlags[ Vertex::PlyReadNum ]; + if( !PlyReadHeader( In.value , Vertex::PlyReadProperties() , Vertex::PlyReadNum , readFlags ) ) ERROR_OUT( "Failed to read ply header: " , In.value ); + + bool hasValue = VertexData::ValidPlyReadProperties< 0 >( readFlags + 3 ); + bool hasNormal = VertexData::ValidPlyReadProperties< 1 >( readFlags + 3 ); + bool hasColor = VertexData::ValidPlyReadProperties< 2 >( readFlags + 3 ); + + if( hasValue ) + if( hasColor ) + if( hasNormal ) Execute< PointStreamValue< float > , PointStreamNormal< float , 3 > , PointStreamColor< float > >(); + else Execute< PointStreamValue< float > , PointStreamColor< float > >(); + else + if( hasNormal ) Execute< PointStreamValue< float > , PointStreamNormal< float , 3 > >(); + else Execute< PointStreamValue< float > >(); + else + if( hasColor ) + if( hasNormal ) Execute< PointStreamNormal< float , 3 > , PointStreamColor< float > >(); + else Execute< PointStreamColor< float > >(); + else + if( hasNormal ) Execute< PointStreamNormal< float , 3 > >(); + else Execute< >(); + printf( "Time (Wall/CPU): %.2f / %.2f\n" , timer.wallTime() , timer.cpuTime() ); + printf( "Peak Memory (MB): %d\n" , MemoryInfo::PeakMemoryUsageMB() ); + + return EXIT_SUCCESS; +} diff --git a/apps/EDTInHeat/CMakeLists.txt b/apps/EDTInHeat/CMakeLists.txt new file mode 100644 index 00000000..f92f6b4a --- /dev/null +++ b/apps/EDTInHeat/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.7) + +project(EDTInHeat) + +set(PROJECT_SRCS ${PROJECT_SOURCE_DIR}/src/EDTInHeat.cpp) + +source_group("src" FILES ${PROJECT_SRCS}) + +find_package(OpenMP REQUIRED) + +add_executable(${PROJECT_NAME} ${PROJECT_SRCS}) + +target_link_libraries(${PROJECT_NAME} PoissonRecon OpenMP::OpenMP_CXX) + +set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER ${CMAKE_PROJECT_NAME}/apps) + +install(TARGETS ${PROJECT_NAME} EXPORT ${CMAKE_PROJECT_NAME}Targets DESTINATION + bin) diff --git a/apps/EDTInHeat/src/EDTInHeat.cpp b/apps/EDTInHeat/src/EDTInHeat.cpp new file mode 100644 index 00000000..afd57cf1 --- /dev/null +++ b/apps/EDTInHeat/src/EDTInHeat.cpp @@ -0,0 +1,612 @@ +/* +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. +*/ + +#include "Mesh/PoissonRecon/PreProcessor.h" + +#undef USE_DOUBLE // If enabled, double-precesion is used +#define DIMENSION 3 // The dimension of the system +#define DEFAULT_FEM_DEGREE 1 // The default finite-element degree + +#include +#include +#include +#include +#include +#include "Mesh/PoissonRecon/MyMiscellany.h" +#include "Mesh/PoissonRecon/CmdLineParser.h" +#include "Mesh/PoissonRecon/PPolynomial.h" +#include "Mesh/PoissonRecon/FEMTree.h" + +MessageWriter messageWriter; + +cmdLineParameter< char* > + In( "in" ) , + Out( "out" ) , + InXForm( "inXForm" ) , + OutXForm( "outXForm" ); + +cmdLineReadable + Performance( "performance" ) , + ShowResidual( "showResidual" ) , + ExactInterpolation( "exact" ) , + Verbose( "verbose" ); + +cmdLineParameter< int > +#ifndef FAST_COMPILE + Degree( "degree" , DEFAULT_FEM_DEGREE ) , +#endif // !FAST_COMPILE + GSIterations( "iters" , 8 ) , + Depth( "depth" , 8 ) , + FullDepth( "fullDepth" , 5 ) , + BaseDepth( "baseDepth" , 0 ) , + BaseVCycles( "baseVCycles" , 1 ) , + 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() ); + +cmdLineParameter< float > + Scale( "scale" , 2.f ) , + CGSolverAccuracy( "cgAccuracy" , float(1e-3) ) , + DiffusionTime( "diffusion" , 0.0005f ) , + WeightScale( "wScl" , 0.125f ) , + WeightExponent( "wExp" , 6.f ) , + ValueWeight( "valueWeight" , 1e-2f ); + +cmdLineReadable* params[] = +{ +#ifndef FAST_COMPILE + &Degree , +#endif // !FAST_COMPILE + &In , &Out , &Depth , &InXForm , &OutXForm , + &Scale , &Verbose , &CGSolverAccuracy , + &ShowResidual , + &ValueWeight , &DiffusionTime , + &Threads , + &FullDepth , + &GSIterations , + &WeightScale , &WeightExponent , + &BaseDepth , &BaseVCycles , + &Performance , + &ExactInterpolation , + &MaxMemoryGB , + &ParallelType , + &ScheduleType , + &ThreadChunkSize , + NULL +}; + + +void ShowUsage( char* ex ) +{ + printf( "Usage: %s\n" , ex ); + printf( "\t --%s \n" , In.name ); + printf( "\t[--%s ]\n" , Out.name ); +#ifndef FAST_COMPILE + printf( "\t[--%s =%d]\n" , Degree.name , Degree.value ); +#endif // !FAST_COMPILE + printf( "\t[--%s =%d]\n" , Depth.name , Depth.value ); + printf( "\t[--%s =%d]\n" , FullDepth.name , FullDepth.value ); + printf( "\t[--%s =%d]\n" , BaseDepth.name , BaseDepth.value ); + printf( "\t[--%s =%d]\n" , BaseVCycles.name , BaseVCycles.value ); + printf( "\t[--%s =%f]\n" , Scale.name , Scale.value ); + printf( "\t[--%s =%.3e]\n" , DiffusionTime.name , DiffusionTime.value ); + 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 ); + printf( "\t[--%s =%d]\n" , MaxMemoryGB.name , MaxMemoryGB.value ); + printf( "\t[--%s]\n" , Performance.name ); + 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) / %9.1f (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) / %9.1f (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) / %9.1f (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) / %9.1f (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) / %9.1f (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) / %9.1f (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 ) +{ + Point< Real , Dim > min , max; + min = max = vertices[0]; + for( int i=0 ; i( min[j] , vertices[i][j] ) , max[j] = std::max< Real >( max[j] , vertices[i][j] ); + 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 +void Print( const XForm< Real , Dim >& xForm ) +{ + for( int j=0 ; j +struct ConstraintDual +{ + CumulativeDerivativeValues< Real , Dim , 0 > operator()( const Point< Real , Dim >& p ) const { return CumulativeDerivativeValues< Real , Dim , 0 >( ); } +}; +template< unsigned int Dim , class Real > +struct SystemDual +{ + Real weight; + SystemDual( Real w ) : weight(w){ } + CumulativeDerivativeValues< Real , Dim , 0 > operator()( Point< Real , Dim > p , const CumulativeDerivativeValues< Real , Dim , 0 >& dValues ) const { return dValues*weight; } + CumulativeDerivativeValues< double , Dim , 0 > operator()( 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()( Point< Real , Dim > p , const CumulativeDerivativeValues< Real , Dim , 0 >& dValues ) const { return dValues*weight; } +}; + +template< unsigned int Dim , class Real , unsigned int FEMSig > +void _Execute( int argc , char* argv[] ) +{ + ThreadPool::Init( (ThreadPool::ParallelType)ParallelType.value , Threads.value ); + static const unsigned int Degree = FEMSignature< FEMSig >::Degree; + typedef typename FEMTree< Dim , Real >::template InterpolationInfo< Real , 0 > InterpolationInfo; + 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 ); + + + XForm< Real , Dim+1 > xForm , iXForm; + if( InXForm.set ) + { + FILE* fp = fopen( InXForm.value , "r" ); + if( !fp ) + { + WARN( "Could not open file for reading x-form: " , InXForm.value ); + xForm = XForm< Real , Dim+1 >::Identity(); + } + else + { + 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" ); + xForm(i,j) = (Real)f; + } + fclose( fp ); + } + } + else xForm = XForm< Real , Dim+1 >::Identity(); + + 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 ); + } + + double startTime = Time(); + + FEMTree< Dim , Real > tree( MEMORY_ALLOCATOR_BLOCK_SIZE ); + FEMTreeProfiler< Dim , Real > profiler( tree ); + if( !In.set ) + { + ShowUsage( argv[0] ); + return; + } + + std::vector< NodeAndPointSample< Dim , Real > > geometrySamples; + std::vector< NodeAndPointSample< Dim , Real > > heatPositions; + std::vector< Point< Real , Dim > > heatGradients; + + // Read the mesh into the tree + { + profiler.start(); + // Read the mesh + std::vector< Point< Real , Dim > > vertices; + std::vector< TriangleIndex< node_index_type > > triangles; + { + int file_type; + std::vector< PlyVertex< float , Dim > > _vertices; + std::vector< std::vector< int > > _polygons; + std::vector< std::string > comments; + if( !PlyReadPolygons( In.value , _vertices , _polygons , PlyVertex< float , Dim >::PlyReadProperties() , PlyVertex< float , Dim >::PlyReadNum , file_type , comments ) ) + ERROR_OUT( "Failed to read ply file: " , In.value ); + vertices.resize( _vertices.size() ); + for( int i=0 ; i _xForm = GetPointXForm< Real , Dim >( vertices , (Real)Scale.value ); + for( int i=0 ; i::Initialize( tree.spaceRoot() , vertices , triangles , Depth.value , geometrySamples , true , tree.nodeAllocators , tree.initializer() ); + iXForm = xForm.inverse(); + if( OutXForm.set ) + { + FILE* fp = fopen( OutXForm.value , "w" ); + if( !fp ) WARN( "Could not open file for writing x-form: %s" ); + else + { + for( int i=0 ; i areas( ThreadPool::NumThreads() , 0 ); + ThreadPool::Parallel_for( 0 , triangles.size() , [&]( unsigned int thread , size_t i ) + { + Simplex< Real , Dim , Dim-1 > s; + for( int k=0 ; k0 ) areas[thread] += sqrt(a2) / 2; + } + ); + for( unsigned int t=0 ; t::FEMTreeNode** nodes = new typename FEMTree< Dim , Real >::FEMTreeNode*[ geometrySamples.size() ]; + for( int i=0 ; i( nodes , (int)geometrySamples.size() ); + profiler.dumpOutput2( comments , "# Thickened tree:" ); + delete[] nodes; + } + + // Finalize the topology of the tree + { + profiler.start(); + tree.template finalizeForMultigrid< Degree >( FullDepth.value , typename FEMTree< Dim , Real >::TrivialHasDataFunctor() ); + profiler.dumpOutput2( comments , "# Finalized tree:" ); + } + + 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) ); + + SparseNodeData< Point< Real , Dim+1 > , IsotropicUIntPack< Dim , FEMTrivialSignature > > leafValues; + const double GradientCutOff = 0; + + // Compute the heat solution + DenseNodeData< Real , IsotropicUIntPack< Dim , FEMSig > > heatSolution; + DenseNodeData< Real , IsotropicUIntPack< Dim , FEMSig > > constraints; + + // Add the FEM constraints + { + profiler.start(); + 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:" ); + } + + // Solve the linear system + { + profiler.start(); + 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 ); + } + sInfo.baseDepth = BaseDepth.value , sInfo.baseVCycles = BaseVCycles.value; + profiler.dumpOutput2( comments , "# Heat system solved:" ); + } + + // Evaluate the gradients at the leaves + { + profiler.start(); + + 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; + typedef typename RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >::template ConstNeighborKey< IsotropicUIntPack< Dim , 1 > , IsotropicUIntPack< Dim , 1 > > OneRingNeighborKey; + std::vector< OneRingNeighborKey > oneRingNeighborKeys( ThreadPool::NumThreads() ); + int treeDepth = tree.tree().maxDepth(); + for( int i=0 ; i > leafCenterValues = tree.initDenseNodeData( IsotropicUIntPack< Dim , FEMTrivialSignature >() ); + + ThreadPool::Parallel_for( tree.nodesBegin(0) , tree.nodesEnd(Depth.value) , [&]( unsigned int thread , size_t i ) + { + if( tree.isValidSpaceNode( tree.node((node_index_type)i) ) ) + { + Point< Real , Dim > center ; Real width; + tree.centerAndWidth( (node_index_type)i , center , width ); + leafCenterValues[i] = evaluator.values( center , thread )[0]; + } + } + ); + + auto CenterGradient = [&] ( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* leaf , int thread ) + { + int d , off[Dim] ; Point< Real , Dim > p ; Real width , _width = (Real)1./(1<nodeData.nodeIndex , p , width ); + int res = 1< g; + unsigned int index1[Dim] , index2[Dim]; + for( int dd=0 ; dd=0 ) index1[c] = 0; + if( off[c]+1* node1 = neighbors.neighbors().data[ GetWindowIndex( IsotropicUIntPack< Dim , 3 >() , index1 ) ]; + const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* node2 = neighbors.neighbors().data[ GetWindowIndex( IsotropicUIntPack< Dim , 3 >() , index2 ) ]; + if( d==Depth.value && tree.isValidSpaceNode( node2 ) ) value2 = leafCenterValues[ node2->nodeData.nodeIndex ]; + else + { + Point< Real , Dim > delta; + delta[c] = ( (int)index2[c]-1 ) * _width; + value2 = evaluator.values( p+delta , thread )[0]; + } + if( d==Depth.value && tree.isValidSpaceNode( node1 ) ) value1 = leafCenterValues[ node1->nodeData.nodeIndex ]; + else + { + Point< Real , Dim > delta; + delta[c] = ( (int)index1[c]-1 ) * _width; + value1 = evaluator.values( p+delta , thread )[0]; + } + + g[c] = ( value2 - value1 ) / ( (Real)( index2[c] - index1[c] ) ); + + index1[c] = index2[c] = 1; + } + + return g * _res; + }; + + for( node_index_type i=tree.nodesBegin(0) ; ichildren ) ) + { + RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* leaf = ( RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* )tree.node(i); + leafValues[leaf] *= 0; + } + + ThreadPool::Parallel_for( 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 ) ) + { + RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* leaf = ( RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* )tree.node((node_index_type)i); + Point< Real , Dim > g = CenterGradient( leaf , thread ); + Real len = (Real)Length( g ); + if( len>GradientCutOff ) g /= len; + Point< Real , Dim+1 >* leafValue = leafValues(leaf); + if( leafValue ) for( int d=0 ; d > edtSolution , constraints; + InterpolationInfo *valueInfo = NULL; + + // Add the FEM constraints + { + profiler.start(); + 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; + typedef IsotropicUIntPack< Dim , 0 > Derivatives2; + unsigned int derivatives2[Dim]; + for( int d=0 ; d::Index( derivatives1 )][ TensorDerivatives< Derivatives2 >::Index( derivatives2 )] = 1.; + } + tree.addFEMConstraints( F , leafValues , constraints , Depth.value ); + profiler.dumpOutput2( comments , "# Set EDT constraints:" ); + } + + // Add the interpolation constraints + if( ValueWeight.value>0 ) + { + profiler.start(); + 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 ); + tree.addInterpolationConstraints( constraints , Depth.value , *valueInfo ); + profiler.dumpOutput2( comments , "#Set point constraints:" ); + } + + // Solve the linear system + { + profiler.start(); + 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; + sInfo.baseDepth = BaseDepth.value , sInfo.baseVCycles = BaseVCycles.value; + 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 , valueInfo ); + profiler.dumpOutput2( comments , "# EDT system solved:" ); + } + if( valueInfo ) delete valueInfo , valueInfo = NULL; + + { + auto GetAverageValueAndError = [&]( const FEMTree< Dim , Real >* tree , const DenseNodeData< Real , IsotropicUIntPack< Dim , FEMSig > >& coefficients , double& average , double& error ) + { + 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 ) + { + ProjectiveData< Point< Real , Dim > , Real >& sample = geometrySamples[j].sample; + Real w = sample.weight; + Real value = evaluator.values( sample.data / sample.weight , thread , geometrySamples[j].node )[0]; + errorSums[thread] += value * value * w; + valueSums[thread] += value * w; + weightSums[thread] += w; + } + ); + for( unsigned int t=0 ; t::WriteParameter( fp ); + DenseNodeData< Real , IsotropicUIntPack< Dim , FEMSig > >::WriteSignatures( fp ); + tree.write( fp , xForm ); + edtSolution.write( fp ); + fclose( fp ); + } + } +} + +#ifndef FAST_COMPILE +template< unsigned int Dim , class Real > +void Execute( int argc , char* argv[] ) +{ + switch( Degree.value ) + { + case 1: return _Execute< Dim , Real , FEMDegreeAndBType< 1 , BOUNDARY_FREE >::Signature >( argc , 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" ); + } +} +#endif // !FAST_COMPILE +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 + cmdLineParse( argc-1 , &argv[1] , params ); + 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; +#else // !USE_DOUBLE + typedef float Real; +#endif // USE_DOUBLE + +#ifdef FAST_COMPILE + 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_" ); + 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; + } + _Execute< DIMENSION , Real , FEMDegreeAndBType< Degree , BType >::Signature >( argc , argv ); +#else // !FAST_COMPILE + Execute< DIMENSION , Real >( argc , argv ); +#endif // FAST_COMPILE + if( Performance.set ) + { + printf( "Time (Wall/CPU): %.2f / %.2f\n" , timer.wallTime() , timer.cpuTime() ); + printf( "Peak Memory (MB): %d\n" , MemoryInfo::PeakMemoryUsageMB() ); + } + return EXIT_SUCCESS; +} diff --git a/apps/ImageStitching/CMakeLists.txt b/apps/ImageStitching/CMakeLists.txt new file mode 100644 index 00000000..e0a0b5fe --- /dev/null +++ b/apps/ImageStitching/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.7) + +project(ImageStitching) + +set(PROJECT_SRCS ${PROJECT_SOURCE_DIR}/src/ImageStitching.cpp) + +source_group("src" FILES ${PROJECT_SRCS}) + +find_package(OpenMP REQUIRED) + +add_executable(${PROJECT_NAME} ${PROJECT_SRCS}) + +target_link_libraries(${PROJECT_NAME} PoissonRecon OpenMP::OpenMP_CXX) + +set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER ${CMAKE_PROJECT_NAME}/apps) + +install(TARGETS ${PROJECT_NAME} EXPORT ${CMAKE_PROJECT_NAME}Targets DESTINATION + bin) diff --git a/apps/ImageStitching/src/ImageStitching.cpp b/apps/ImageStitching/src/ImageStitching.cpp new file mode 100644 index 00000000..6670bf41 --- /dev/null +++ b/apps/ImageStitching/src/ImageStitching.cpp @@ -0,0 +1,548 @@ +/* +Copyright (c) 2013, 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 "Mesh/PoissonRecon/PreProcessor.h" + +#undef USE_DOUBLE +#define DIMENSION 2 +#define ROW_BLOCK_SIZE 16 +#define DEFAULT_FEM_DEGREE 1 + +#ifndef USE_DEEP_TREE_NODES +#define USE_DEEP_TREE_NODES +#endif // USE_DEEP_TREE_NODES + +#include +#include +#include +#include +#include "Mesh/PoissonRecon/Image.h" +#include "Mesh/PoissonRecon/MyMiscellany.h" +#include "Mesh/PoissonRecon/Array.h" +#include "Mesh/PoissonRecon/CmdLineParser.h" +#include "Mesh/PoissonRecon/Geometry.h" +#include "Mesh/PoissonRecon/FEMTree.h" + +cmdLineParameterArray< char* , 2 > + In( "in" ); +cmdLineParameter< char* > + Out( "out" ); +cmdLineParameter< int > +#ifdef FAST_COMPILE +#else // !FAST_COMPILE + Degree( "degree" , DEFAULT_FEM_DEGREE ) , +#endif // FAST_COMPILE + ParallelType( "parallel" , (int)ThreadPool::OPEN_MP ) , + ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , + ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , + Threads( "threads" , (int)std::thread::hardware_concurrency() ) , + MaxMemoryGB( "maxMemory" , 0 ) , + GSIterations( "iters" , 8 ) , + FullDepth( "fullDepth" , 6 ) , + BaseDepth( "baseDepth" , 6 ) , + BaseVCycles( "baseVCycles" , 4 ); +cmdLineReadable + Verbose( "verbose" ) , + ShowResidual( "residual" ) , + Performance( "performance" ); +cmdLineParameter< float > + WeightScale ( "wScl", 0.125f ) , + WeightExponent( "wExp" , 6.f ); + +cmdLineReadable* params[] = +{ + &In , &Out , &Threads , &Verbose , &ShowResidual , &GSIterations , &FullDepth , + &BaseDepth , &BaseVCycles , + &WeightScale , &WeightExponent , + &Performance , + &MaxMemoryGB , +#if !defined( FAST_COMPILE ) + &Degree , +#endif // !FAST_COMPILE + &ParallelType , + &ScheduleType , + &ThreadChunkSize , + NULL +}; + +void ShowUsage( char* ex ) +{ + printf( "Usage: %s\n" , ex ); + printf( "\t --%s \n" , In.name ); + printf( "\t[--%s ]\n" , Out.name ); +#if !defined( FAST_COMPILE ) + printf( "\t[--%s =%d]\n" , Degree.name , Degree.value ); +#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 ); + for( size_t i=0 ; i=%d]\n" , ThreadChunkSize.name , ThreadChunkSize.value ); + printf( "\t[--%s =%f]\n", WeightScale.name , WeightScale.value ); + printf( "\t[--%s =%f]\n", WeightExponent.name , WeightExponent.value ); + printf( "\t[--%s =%d]\n" , MaxMemoryGB.name , MaxMemoryGB.value ); + printf( "\t[--%s]\n" , Performance.name ); + printf( "\t[--%s =%d]\n" , BaseDepth.name , BaseDepth.value ); + printf( "\t[--%s =%d]\n" , BaseVCycles.name , BaseVCycles.value ); + printf( "\t[--%s]\n" , ShowResidual.name ); + printf( "\t[--%s]\n" , Verbose.name ); +} + +struct RGBPixel +{ + unsigned char rgb[3]; + unsigned char& operator[]( int idx ){ return rgb[idx]; } + const unsigned char& operator[]( int idx ) const { return rgb[idx]; } + int mask( void ) const + { + if( rgb[0]==255 && rgb[1]==255 && rgb[2]==255 ) return -1; + else return ( (int)rgb[0] )<<16 | ( (int)rgb[1] )<<8 | ( (int)rgb[2] ); + } + + RGBPixel( void ){ rgb[0] = rgb[1] = rgb[2] = 0; } + RGBPixel( double r , double g , double b ) + { + rgb[0] = (unsigned char)( std::max< int >( 0 , std::min< int >( 255 , (int)( r*255 ) ) ) ); + rgb[1] = (unsigned char)( std::max< int >( 0 , std::min< int >( 255 , (int)( g*255 ) ) ) ); + rgb[2] = (unsigned char)( std::max< int >( 0 , std::min< int >( 255 , (int)( b*255 ) ) ) ); + } + RGBPixel( float r , float g , float b ) + { + rgb[0] = (unsigned char)( std::max< int >( 0 , std::min< int >( 255 , (int)( r*255 ) ) ) ); + rgb[1] = (unsigned char)( std::max< int >( 0 , std::min< int >( 255 , (int)( g*255 ) ) ) ); + rgb[2] = (unsigned char)( std::max< int >( 0 , std::min< int >( 255 , (int)( b*255 ) ) ) ); + } + + template< class Real > + static Point< Real , 3 > ToPoint( RGBPixel rgb ) + { + Point< Real , 3 > p; + for( int c=0 ; c<3 ; c++ ) p[c] = (Real)( ( (double)rgb[c] ) / 255. ); + return p; + } +}; + +void WriteImage( char* fileName , RGBPixel* pixels , int w , int h ) +{ + unsigned int _w = w , _h = h , _c = 3; + 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 ) +{ + RGBPixel* pixelRow = new RGBPixel[ pixels->width() ]; + RGBPixel* labelRow = new RGBPixel[ labels->width() ]; + for( unsigned int r=0 ; rheight() ; r++ ) + { + if( Verbose.set ) printf( "%d / %d \r" , r ,pixels->height() ); + pixels->nextRow( (unsigned char*)pixelRow ); + labels->nextRow( (unsigned char*)labelRow ); + output->nextRow( (unsigned char*)pixelRow ); + } + if( Verbose.set ) printf( "\n" ); + delete[] pixelRow; + delete[] labelRow; +} + +template< class Real , unsigned int Colors > +struct BufferedImageDerivativeStream : public FEMTreeInitializer< DIMENSION , Real >::template DerivativeStream< Point< Real , Colors > > +{ + BufferedImageDerivativeStream( const unsigned int resolution[] , ImageReader* pixels , ImageReader* labels ) : _pixels( pixels ) , _labels( labels ) + { + memcpy( _resolution , resolution , sizeof( unsigned int ) * DIMENSION ); + for( int i=0 ; i<3 ; i++ ) + { + _pixelRows[i] = new RGBPixel[ _resolution[0] ]; + _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() ); + __pixelRow = pixels->channels()==3 ? NULL : new unsigned char[ _resolution[0] ]; + __labelRow = labels->channels()==3 ? NULL : new unsigned char[ _resolution[0] ]; + _r = -2 ; prefetch(); + _r = -1 ; prefetch(); + _c = _r = _dir = 0; + } + ~BufferedImageDerivativeStream( void ) + { + for( int i=0 ; i<3 ; i++ ) delete[] _pixelRows[i] , delete[] _labelRows[i] , delete[] _maskRows[i]; + if( __pixelRow ) delete[] __pixelRow; + if( __labelRow ) delete[] __labelRow; + } + void resolution( unsigned int res[] ) const { memcpy( res , _resolution , sizeof(_resolution) ); } + + void advance( void ){ _c = _dir = 0 , _r++; } + void prefetch( void ) + { + if( _r+2<(int)_resolution[1] ) + { + int j = (_r+2)%3; + RGBPixel *pixelRow = _pixelRows[j] , *labelRow = _labelRows[j]; + int *maskRow = _maskRows[j]; + if( _pixels->channels()==3 ) _pixels->nextRow( (unsigned char*)pixelRow ); + else + { + _pixels->nextRow( __pixelRow ); + for( int i=0 ; i<(int)_resolution[0] ; i++ ) pixelRow[i][0] = pixelRow[i][1] = pixelRow[i][2] = __pixelRow[i]; + } + if( _labels->channels()==3 ) _labels->nextRow( (unsigned char*)labelRow ); + else + { + _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(); } ); + } + } + + bool nextDerivative( unsigned int idx[] , unsigned int& dir , Point< Real , Colors >& dValue ) + { + const RGBPixel *pixelRow1 = _pixelRows[_r%3] , *pixelRow2 = _pixelRows[(_r+1)%3]; + const int *maskRow1 = _maskRows[_r%3] , *maskRow2 = _maskRows[(_r+1)%3]; + if( _dir==0 ) + { + for( ; _c<(int)_resolution[0]-1 ; _c++ ) + { + if( maskRow1[_c]!=maskRow1[_c+1] && maskRow1[_c]>=0 && maskRow1[_c+1]>=0 ) + { + idx[0] = _c , idx[1] = _r , dir = _dir; + dValue = RGBPixel::ToPoint< Real >( pixelRow1[_c+1] ) - RGBPixel::ToPoint< Real >( pixelRow1[_c] ); + _c++; + return true; + } + } + _dir = 1 , _c = 0; + } + if( _dir==1 ) + { + if( _r+1<(int)_resolution[1] ) + { + for( ; _c<(int)_resolution[0] ; _c++ ) + { + if( maskRow1[_c]!=maskRow2[_c] && maskRow1[_c]>=0 && maskRow2[_c]>=0 ) + { + idx[0] = _c , idx[1] = _r , dir = _dir; + dValue = RGBPixel::ToPoint< Real >( pixelRow2[_c] ) - RGBPixel::ToPoint< Real >( pixelRow1[_c] ); + _c++; + return true; + } + } + } + } + return false; + } +protected: + int _r , _c , _dir; + unsigned int _resolution[DIMENSION]; + ImageReader *_pixels , *_labels; + RGBPixel *_pixelRows[3] , *_labelRows[3]; + unsigned char *__pixelRow , *__labelRow; + int* _maskRows[3]; +}; + +template< typename Real , unsigned int Degree > +void _Execute( void ) +{ + ThreadPool::Init( (ThreadPool::ParallelType)ParallelType.value , Threads.value ); + int w , h; + { + unsigned int _w , _h , _c; + 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( Verbose.set ) printf( "Resolution: %d x %d\n" , w , h ); + + static const unsigned int Dim = DIMENSION; + static const unsigned int Colors = 3; + static const unsigned int FEMSig = FEMDegreeAndBType< Degree , BOUNDARY_NEUMANN >::Signature; + + FEMTree< Dim , Real > tree( MEMORY_ALLOCATOR_BLOCK_SIZE ); + std::vector< NodeSample< Dim , Point< Real , Colors > > > derivatives[Dim]; + 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] ); + ImageReader* labels = ImageReader::Get( In.values[1] ); + unsigned int resolution[] = { (unsigned int )w , (unsigned int )h }; + BufferedImageDerivativeStream< Real , Colors > dStream( resolution , pixels , labels ); + for( int j=0 ; j::template Initialize< (Degree&1)==0 , Point< Real , Colors > >( tree.spaceRoot() , dStream , derivatives , tree.nodeAllocators.size() ? tree.nodeAllocators[0] : NULL , tree.initializer() ); } + ); + dStream.advance(); + } + delete pixels; + delete labels; + { + std::vector< typename FEMTree< Dim , Real >::FEMTreeNode* > nodes; + nodes.reserve( derivatives[0].size() + derivatives[1].size() ); + for( int i=0 ; i( &nodes[0] , (int)nodes.size() ); + } + tree.template finalizeForMultigrid< Degree >( FullDepth.value , []( const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* ){ return true; } ); + 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 ); + } + } + + { + Profiler p; + constraints = tree.template initDenseNodeData< Point< Real , Colors > >( IsotropicUIntPack< Dim , FEMSig >() ); + static const unsigned int DFEMSig = FEMSignature< FEMSig >::DSignature(); + // Generate the partial-x constraints + { + typedef UIntPack< DFEMSig , FEMSig > CSignature; + typedef IsotropicUIntPack< 2 , 0 > CDerivative; + typedef UIntPack< FEMSig , FEMSig > FEMSignature; + typedef UIntPack< 1 , 0 > FEMDerivative; + SparseNodeData< Point< Real , Colors > , CSignature > partialX; + for( int i=0 ; i F; + F.weights[0][ TensorDerivatives< FEMDerivative >::Index( derivatives1 ) ][ TensorDerivatives< CDerivative >::Index( derivatives2 ) ] = 1; + tree.addFEMConstraints( F , partialX , constraints , maxDepth ); + } + // Generate the partial-y constraints + { + typedef UIntPack< FEMSig , DFEMSig > CSignature; + typedef IsotropicUIntPack< 2 , 0 > CDerivative; + typedef UIntPack< FEMSig , FEMSig > FEMSignature; + typedef UIntPack< 0 , 1 > FEMDerivative; + SparseNodeData< Point< Real , Colors > , CSignature > partialY; + for( int i=0 ; i F; + 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 ); + } + // Solve the system + { + Profiler p; + double t = Time(); + solution = tree.template initDenseNodeData< Point< Real , Colors > >( IsotropicUIntPack< Dim , FEMSig >() ); + typename FEMTree< Dim , Real >::SolverInfo sInfo; + 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.baseDepth = BaseDepth.value , 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 ); + } + + Point< Real , Colors > average; + { + Profiler p; + Real begin[] = { 0 , 0 } , end[] = { (Real)w/(1<channels()==1 ) inRow = new unsigned char[w]; + + auto FetchInput = [&]( unsigned int block ) + { + int rStart = block*ROW_BLOCK_SIZE; + int rEnd = rStart + ROW_BLOCK_SIZE < h ? rStart + ROW_BLOCK_SIZE : h; + for( int r=rStart , rr=0 ; rchannels()==3 ) in->nextRow( (unsigned char*)( inRows[block&1] + rr*w ) ); + else + { + 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]; } ); + } + } + }; + auto SetOutput = [&]( unsigned int block ) + { + int rStart = block*ROW_BLOCK_SIZE; + int rEnd = rStart + ROW_BLOCK_SIZE < h ? rStart + ROW_BLOCK_SIZE : h; + out->nextRows( (unsigned char*)outRows[block&1] , rEnd-rStart ); + }; + int blockNum = ( h + ROW_BLOCK_SIZE - 1 ) / ROW_BLOCK_SIZE; + + // Prefetch the first block + FetchInput( 0 ); + for( int rStart=0 , block=0 ; rStart0 ) SetOutput( block-1 ); } , + [&]( void ) + { + RGBPixel *_inRows = inRows[block&1] , *_outRows = outRows[block&1]; + int rEnd = rStart + ROW_BLOCK_SIZE < h ? rStart + ROW_BLOCK_SIZE : h; + + // Expand the next block of values + 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 ) + { + Point< Real , Colors > c = Point< Real , Colors >( _inRows[ii][0] , _inRows[ii][1] , _inRows[ii][2] ) / 255; + c += outBlock[ii] - average; + _outRows[ii] = RGBPixel( c[0] , c[1] , c[2] ); + } + ); + DeletePointer( outBlock ); + } + ); + } + // Write out the last block + SetOutput( blockNum-1 ); + if( Verbose.set ) printf( "Wrote output: " ) , p.print( true ); + delete[] inRows[0]; + delete[] outRows[0]; + delete[] inRows[1]; + delete[] outRows[1]; + if( inRow ) delete[] inRow; + delete in; + delete out; + } +} + +#ifdef FAST_COMPILE +#else // !FAST_COMPILE +template< typename Real > +void _Execute( void ) +{ + switch( Degree.value ) + { + case 1: _Execute< Real , 1 >() ; break; + 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" ); + } +} +#endif // FAST_COMPILE + +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 + cmdLineParse( argc-1 , &argv[1] , params ); + if( MaxMemoryGB.value>0 ) SetPeakMemoryMB( MaxMemoryGB.value<<10 ); + ThreadPool::DefaultChunkSize = ThreadChunkSize.value; + ThreadPool::DefaultSchedule = (ThreadPool::ScheduleType)ScheduleType.value; + if( Verbose.set ) + { + printf( "*********************************************\n" ); + printf( "*********************************************\n" ); + printf( "** Running Image Stitching (Version %s) **\n" , VERSION ); + printf( "*********************************************\n" ); + printf( "*********************************************\n" ); + if( !Threads.set ) printf( "Running with %d threads\n" , Threads.value ); + } + + if( !In.set ) + { + ShowUsage( argv[0] ); + return EXIT_FAILURE; + } + 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; + } + +#ifdef USE_DOUBLE + typedef double Real; +#else // !USE_DOUBLE + typedef float Real; +#endif // USE_DOUBLE + +#ifdef FAST_COMPILE + static const int Degree = DEFAULT_FEM_DEGREE; + WARN( "Compiled for degree-" , Degree , ", " , sizeof(Real)==4 ? "single" : "double" , "-precision _only_" ); + _Execute< Real , Degree >(); +#else // !FAST_COMPILE + _Execute< Real >(); +#endif // FAST_COMPILE + + if( Performance.set ) + { + printf( "Time (Wall/CPU): %.2f / %.2f\n" , timer.wallTime() , timer.cpuTime() ); + printf( "Peak Memory (MB): %d\n" , MemoryInfo::PeakMemoryUsageMB() ); + } + return EXIT_SUCCESS; +} diff --git a/apps/PointInterpolant/CMakeLists.txt b/apps/PointInterpolant/CMakeLists.txt new file mode 100644 index 00000000..5a60496c --- /dev/null +++ b/apps/PointInterpolant/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.7) + +project(PointInterpolant) + +set(PROJECT_SRCS ${PROJECT_SOURCE_DIR}/src/PointInterpolant.cpp) + +source_group("src" FILES ${PROJECT_SRCS}) + +find_package(OpenMP REQUIRED) + +add_executable(${PROJECT_NAME} ${PROJECT_SRCS}) + +target_link_libraries(${PROJECT_NAME} PoissonRecon OpenMP::OpenMP_CXX) + +set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER ${CMAKE_PROJECT_NAME}/apps) + +install(TARGETS ${PROJECT_NAME} EXPORT ${CMAKE_PROJECT_NAME}Targets DESTINATION + bin) diff --git a/apps/PointInterpolant/src/PointInterpolant.cpp b/apps/PointInterpolant/src/PointInterpolant.cpp new file mode 100644 index 00000000..8d3685eb --- /dev/null +++ b/apps/PointInterpolant/src/PointInterpolant.cpp @@ -0,0 +1,825 @@ +/* +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 "Mesh/PoissonRecon/PreProcessor.h" + +//#undef USE_DOUBLE // If enabled, double-precesion is used +#define USE_DOUBLE // If enabled, double-precesion is used +#define WEIGHT_DEGREE 2 // The order of the B-Spline used to splat in the weights for density estimation +#define DEFAULT_FEM_DEGREE 2 // The default finite-element degree +#define DEFAULT_FEM_BOUNDARY BOUNDARY_FREE // The default finite-element boundary type +#define DEFAULT_DIMENSION 2 // The dimension of the system + +#include +#include +#include +#include +#include "Mesh/PoissonRecon/MyMiscellany.h" +#include "Mesh/PoissonRecon/CmdLineParser.h" +#include "Mesh/PoissonRecon/PPolynomial.h" +#include "Mesh/PoissonRecon/FEMTree.h" +#include "Mesh/PoissonRecon/Ply.h" +#include "Mesh/PoissonRecon/PointStreamData.h" +#include "Mesh/PoissonRecon/Image.h" + +MessageWriter messageWriter; + +cmdLineParameter< char* > + In( "in" ) , + Out( "out" ) , + TempDir( "tempDir" ) , + Grid( "grid" ) , + Tree( "tree" ) , + Transform( "xForm" ); + +cmdLineReadable + Performance( "performance" ) , + ShowResidual( "showResidual" ) , + PrimalGrid( "primalGrid" ) , + ExactInterpolation( "exact" ) , + InCore( "inCore" ) , + NoValueConstraints( "noValues" ) , + UseGradientConstraints( "useGradients" ) , + NoComments( "noComments" ) , + PolygonMesh( "polygonMesh" ) , + NonManifold( "nonManifold" ) , + NonLinearFit( "nonLinearFit" ) , + ASCII( "ascii" ) , + Verbose( "verbose" ); + +cmdLineParameter< int > +#ifndef FAST_COMPILE + Degree( "degree" , DEFAULT_FEM_DEGREE ) , +#endif // !FAST_COMPILE + Depth( "depth" , 8 ) , + Iters( "iters" , 8 ) , + FullDepth( "fullDepth" , 5 ) , + BaseDepth( "baseDepth" , 5 ) , + BaseVCycles( "baseVCycles" , 4 ) , +#ifndef FAST_COMPILE + BType( "bType" , DEFAULT_FEM_BOUNDARY+1 ) , + Dimension( "dim" , DEFAULT_DIMENSION ) , +#endif // !FAST_COMPILE + MaxMemoryGB( "maxMemory" , 0 ) , + ParallelType( "parallel" , (int)ThreadPool::OPEN_MP ) , + ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , + ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , + Threads( "threads" , (int)std::thread::hardware_concurrency() ); + +cmdLineParameter< float > + Scale( "scale" , 1.1f ) , + Width( "width" , 0.f ) , + CGSolverAccuracy( "cgAccuracy" , 1e-3f ) , + IsoValue( "iso" , 0.f ) , + ValueWeight ( "valueWeight" , 1000.f ) , + GradientWeight( "gradientWeight" , 1.f ) , + LapWeight ( "lapWeight" , 0.f ) , + BiLapWeight ( "biLapWeight" , 1.f ); + +cmdLineReadable* params[] = +{ +#ifndef FAST_COMPILE + &Degree , &BType , &Dimension , +#endif // !FAST_COMPILE + &In , &Out , &Depth , &Transform , + &Width , + &Scale , &Verbose , &CGSolverAccuracy , &NoComments , + &NonManifold , &PolygonMesh , &ASCII , &ShowResidual , + &ValueWeight , &GradientWeight , + &LapWeight , &BiLapWeight , + &Grid , &Threads , + &Tree , + &FullDepth , + &BaseDepth , &BaseVCycles , + &Iters , + &IsoValue , + &PrimalGrid , + &ExactInterpolation , + &Performance , + &MaxMemoryGB , + &InCore , + &ParallelType , + &ScheduleType , + &ThreadChunkSize , + &NoValueConstraints , + &UseGradientConstraints , + &NonLinearFit , + 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" , Grid.name ); + printf( "\t[--%s ]\n" , Tree.name ); +#ifndef FAST_COMPILE + printf( "\t[--%s =%d]\n" , Dimension.name , Dimension.value ); + printf( "\t[--%s =%d]\n" , Degree.name , Degree.value ); + printf( "\t[--%s =%d]\n" , BType.name , BType.value ); + for( int i=0 ; i=%d]\n" , Depth.name , Depth.value ); + printf( "\t[--%s ]\n" , Width.name ); + printf( "\t[--%s =%d]\n" , FullDepth.name , FullDepth.value ); + printf( "\t[--%s =%d]\n" , BaseDepth.name , BaseDepth.value ); + printf( "\t[--%s =%d]\n" , BaseVCycles.name , BaseVCycles.value ); + printf( "\t[--%s =%f]\n" , Scale.name , Scale.value ); + printf( "\t[--%s =%.3e]\n" , ValueWeight.name , ValueWeight.value ); + printf( "\t[--%s =%.3e]\n" , GradientWeight.name , GradientWeight.value ); + printf( "\t[--%s =%.3e]\n" , LapWeight.name , LapWeight.value ); + 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 ); + for( size_t i=0 ; i=%d]\n" , ThreadChunkSize.name , ThreadChunkSize.value ); + printf( "\t[--%s =%g]\n" , CGSolverAccuracy.name , CGSolverAccuracy.value ); + printf( "\t[--%s =%d]\n" , MaxMemoryGB.name , MaxMemoryGB.value ); + printf( "\t[--%s =%f]\n" , IsoValue.name , IsoValue.value ); + printf( "\t[--%s]\n" , NoValueConstraints.name ); + printf( "\t[--%s]\n" , UseGradientConstraints.name ); + 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 ); + printf( "\t[--%s]\n" , InCore.name ); + 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) / %9.1f (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) / %9.1f (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) / %9.1f (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) / %9.1f (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) / %9.1f (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) / %9.1f (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 +XForm< Real , Dim+1 > GetPointXForm( InputPointStream< Real , Dim >& stream , Real width , Real scaleFactor , int& depth ) +{ + Point< Real , Dim > min , max; + stream.boundingBox( min , max ); + return GetBoundingBoxXForm( min , max , width , scaleFactor , depth ); +} +template< class Real , unsigned int Dim > +XForm< Real , Dim+1 > GetPointXForm( InputPointStream< Real , Dim >& stream , Real scaleFactor ) +{ + Point< Real , Dim > min , max; + stream.boundingBox( min , max ); + return GetBoundingBoxXForm( min , max , scaleFactor ); +} + +template< unsigned int Dim , typename Real , typename TotalPointSampleData > struct ValueAndGradientFromSample; + +template< unsigned int Dim , typename Real > +struct ValueAndGradientFromSample< Dim , Real , MultiPointStreamData< Real , PointStreamValue< Real > , PointStreamNormal< Real , Dim > > > +{ + typedef MultiPointStreamData< Real , PointStreamValue< Real > , PointStreamNormal< Real , Dim > > TotalPointSampleData; + std::pair< Real , Point< Real , Dim > > operator()( TotalPointSampleData d ) const { return std::pair< Real , Point< Real , Dim > >( d.template data<0>() , d.template data<1>() ); } +}; + +template< unsigned int Dim , typename Real > +struct ValueAndGradientFromSample< Dim , Real , MultiPointStreamData< Real , PointStreamValue< Real > > > +{ + typedef MultiPointStreamData< Real , PointStreamValue< Real > > TotalPointSampleData; + std::pair< Real , Point< Real , Dim > > operator()( TotalPointSampleData d ) const { return std::pair< Real , Point< Real , Dim > >( d.template data<0>() , Point< Real , Dim >() ); } +}; + +template< unsigned int Dim , typename Real > +struct ValueAndGradientFromSample< Dim , Real , MultiPointStreamData< Real , PointStreamNormal< Real , Dim > > > +{ + typedef MultiPointStreamData< Real , PointStreamNormal< Real , Dim > > TotalPointSampleData; + std::pair< Real , Point< Real , Dim > > operator()( TotalPointSampleData d ) const { return std::pair< Real , Point< Real , Dim > >( (Real)0 , d.template data<0>() ); } +}; + + +template< unsigned int Dim , typename Real , typename TotalPointSampleData > struct ConstraintDual; + +template< unsigned int Dim , typename Real > +struct ConstraintDual< Dim , Real , MultiPointStreamData< Real , PointStreamValue< Real > , PointStreamNormal< Real , Dim > > > +{ + typedef MultiPointStreamData< Real , PointStreamValue< Real > , PointStreamNormal< Real , Dim > > TotalPointSampleData; + Real vWeight , gWeight; + ConstraintDual( Real v , Real g ) : vWeight(v) , gWeight(g) { } + CumulativeDerivativeValues< Real , Dim , 1 > operator()( const Point< Real , Dim >& p , const TotalPointSampleData& data ) const + { + Real value = data.template data<0>(); + Point< Real , Dim > gradient = data.template data<1>(); + CumulativeDerivativeValues< Real , Dim , 1 > cdv; + cdv[0] = value*vWeight; + for( int d=0 ; d +struct ConstraintDual< Dim , Real , MultiPointStreamData< Real , PointStreamValue< Real > > > +{ + typedef MultiPointStreamData< Real , PointStreamValue< Real > > TotalPointSampleData; + Real vWeight , gWeight; + ConstraintDual( Real v , Real g ) : vWeight(v) , gWeight(g) { } + CumulativeDerivativeValues< Real , Dim , 1 > operator()( const Point< Real , Dim >& p , const TotalPointSampleData& data ) const + { + Real value = data.template data<0>(); + CumulativeDerivativeValues< Real , Dim , 1 > cdv; + cdv[0] = value*vWeight; + return cdv; + } +}; +template< unsigned int Dim , typename Real > +struct ConstraintDual< Dim , Real , MultiPointStreamData< Real , PointStreamNormal< Real , Dim > > > +{ + typedef MultiPointStreamData< Real , PointStreamNormal< Real , Dim > > TotalPointSampleData; + Real vWeight , gWeight; + ConstraintDual( Real v , Real g ) : vWeight(v) , gWeight(g) { } + CumulativeDerivativeValues< Real , Dim , 1 > operator()( const Point< Real , Dim >& p , const TotalPointSampleData& data ) const + { + Point< Real , Dim > gradient = data.template data<0>(); + CumulativeDerivativeValues< Real , Dim , 1 > cdv; + 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[0] = v; + for( unsigned int d=0 ; d operator()( Point< Real , Dim > p , const TotalPointSampleData& data , const CumulativeDerivativeValues< Real , Dim , 1 >& dValues ) const + { + return dValues * weight; + } +}; + +template< typename Vertex , typename Real , unsigned int ... FEMSigs , typename TotalPointSampleData > +void ExtractMesh( 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::function< void ( Vertex& , Point< Real , sizeof ... ( FEMSigs ) > , Real , TotalPointSampleData ) > SetVertex , std::vector< std::string > &comments , XForm< Real , sizeof...(FEMSigs)+1 > iXForm ) +{ + static const int Dim = sizeof ... ( FEMSigs ); + typedef UIntPack< FEMSigs ... > Sigs; + static const unsigned int DataSig = FEMDegreeAndBType< WEIGHT_DEGREE , BOUNDARY_FREE >::Signature; + + FEMTreeProfiler< Dim , Real > profiler( tree ); + + char tempHeader[1024]; + { + char tempPath[1024]; + tempPath[0] = 0; + if( TempDir.set ) strcpy( tempPath , TempDir.value ); + else SetTempDirectory( tempPath , sizeof(tempPath) ); + if( strlen(tempPath)==0 ) sprintf( tempPath , ".%c" , FileSeparator ); + if( tempPath[ strlen( tempPath )-1 ]==FileSeparator ) sprintf( tempHeader , "%sPR_" , tempPath ); + else sprintf( tempHeader , "%s%cPR_" , tempPath , FileSeparator ); + } + + CoredMeshData< Vertex , node_index_type > *mesh; + if( InCore.set ) mesh = new CoredVectorMeshData< Vertex , node_index_type >(); + else mesh = new CoredFileMeshData< Vertex , node_index_type >( tempHeader ); + profiler.start(); + typename IsoSurfaceExtractor< Dim , Real , Vertex >::IsoStats isoStats; +#if defined( __GNUC__ ) && __GNUC__ < 5 +#warning "you've got me gcc version<5" + isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< TotalPointSampleData >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , (typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE >*)NULL , (SparseNodeData< ProjectiveData< TotalPointSampleData , Real > , IsotropicUIntPack< Dim , DataSig > > *)NULL , solution , isoValue , *mesh , SetVertex , NonLinearFit.set , !NonManifold.set , PolygonMesh.set , false ); +#else // !__GNUC__ || __GNUC__ >=5 + isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< TotalPointSampleData >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , (typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE >*)NULL , NULL , solution , isoValue , *mesh , SetVertex , NonLinearFit.set , !NonManifold.set , PolygonMesh.set , false ); +#endif // __GNUC__ || __GNUC__ < 4 + messageWriter( "Vertices / Polygons: %llu / %llu\n" , (unsigned long long)( mesh->outOfCorePointCount()+mesh->inCorePoints.size() ) , (unsigned long long)mesh->polygonCount() ); + 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:" ); + + std::vector< std::string > noComments; + if( !PlyWritePolygons< Vertex , node_index_type , Real , Dim >( Out.value , mesh , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , NoComments.set ? noComments : comments , iXForm ) ) + ERROR_OUT( "Could not write mesh to: " , Out.value ); + delete mesh; +} + +template< typename Real , unsigned int Dim > +void WriteGrid( ConstPointer( Real ) values , int res , const char *fileName ) +{ + int resolution = 1; + for( int d=0 ; d avgs( ThreadPool::NumThreads() , 0 ); + ThreadPool::Parallel_for( 0 , resolution , [&]( unsigned int thread , size_t i ){ avgs[thread] += values[i]; } ); + for( unsigned int t=0 ; t stds( ThreadPool::NumThreads() , 0 ); + ThreadPool::Parallel_for( 0 , resolution , [&]( 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 ); + + unsigned char *pixels = new unsigned char[ resolution*3 ]; + ThreadPool::Parallel_for( 0 , resolution , [&]( 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 + { + + FILE *fp = fopen( fileName , "wb" ); + if( !fp ) ERROR_OUT( "Failed to open grid file for writing: " , fileName ); + else + { + fwrite( &res , sizeof(int) , 1 , fp ); + if( typeid(Real)==typeid(float) ) fwrite( values , sizeof(float) , resolution , fp ); + else + { + float *fValues = new float[resolution]; + for( int i=0 ; i +void Execute( int argc , char* argv[] , UIntPack< FEMSigs ... > ) +{ + static const int Dim = sizeof ... ( FEMSigs ); + typedef UIntPack< FEMSigs ... > Sigs; + typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > Degrees; + typedef UIntPack< FEMDegreeAndBType< WEIGHT_DEGREE , DerivativeBoundary< FEMSignature< FEMSigs >::BType , 1 >::BType >::Signature ... > DataSigs; + typedef typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; + typedef typename FEMTree< Dim , Real >::template InterpolationInfo< Real , 1 > InterpolationInfo; + typedef InputPointStreamWithData< Real , Dim , TotalPointSampleData > InputPointStream; + typedef TransformedInputPointStreamWithData< Real , Dim , TotalPointSampleData > XInputPointStream; + 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 ); + + ThreadPool::Init( (ThreadPool::ParallelType)ParallelType.value , Threads.value ); + + XForm< Real , Dim+1 > xForm , iXForm; + if( Transform.set ) + { + FILE* fp = fopen( Transform.value , "r" ); + if( !fp ) + { + WARN( "Could not read x-form from: " , Transform.value ); + xForm = XForm< Real , Dim+1 >::Identity(); + } + else + { + for( int i=0 ; i::Identity(); + + 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 ); + } + + double startTime = Time(); + + FEMTree< Dim , Real > tree( MEMORY_ALLOCATOR_BLOCK_SIZE ); + FEMTreeProfiler< Dim , Real > profiler( tree ); + + if( Depth.set && Width.value>0 ) + { + WARN( "Both --" , Depth.name , " and --" , Width.name , " set, ignoring --" , Width.name ); + Width.value = 0; + } + + size_t pointCount; + + std::vector< typename FEMTree< Dim , Real >::PointSample >* samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); + std::vector< TotalPointSampleData >* sampleData = NULL; + + // Read in the samples + { + profiler.start(); + InputPointStream* pointStream; + char* ext = GetFileExtension( In.value ); + sampleData = new std::vector< TotalPointSampleData >(); + std::vector< std::pair< Point< Real , Dim > , TotalPointSampleData > > inCorePoints; + if( InCore.set ) + { + InputPointStream *_pointStream; + if ( !strcasecmp( ext , "bnpts" ) ) _pointStream = new BinaryInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::ReadBinary ); + else if( !strcasecmp( ext , "ply" ) ) _pointStream = new PLYInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::PlyReadProperties() , TotalPointSampleData::PlyReadNum , TotalPointSampleData::ValidPlyReadProperties ); + else _pointStream = new ASCIIInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::ReadASCII ); + Point< Real , Dim > p; + TotalPointSampleData d; + while( _pointStream->nextPoint( p , d ) ) inCorePoints.push_back( std::pair< Point< Real , Dim > , TotalPointSampleData >( p , d ) ); + delete _pointStream; + + pointStream = new MemoryInputPointStreamWithData< Real , Dim , TotalPointSampleData >( inCorePoints.size() , &inCorePoints[0] ); + } + else + { + if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::ReadBinary ); + else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::PlyReadProperties() , TotalPointSampleData::PlyReadNum , TotalPointSampleData::ValidPlyReadProperties ); + else pointStream = new ASCIIInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::ReadASCII ); + } + delete[] ext; + typename TotalPointSampleData::Transform _xForm( xForm ); + XInputPointStream _pointStream( [&]( Point< Real , Dim >& p , TotalPointSampleData& d ){ p = xForm*p , d = _xForm(d); } , *pointStream ); + if( Width.value>0 ) xForm = GetPointXForm< Real , Dim >( _pointStream , Width.value , (Real)( Scale.value>0 ? Scale.value : 1. ) , Depth.value ) * xForm; + else xForm = Scale.value>0 ? GetPointXForm< Real , Dim >( _pointStream , (Real)Scale.value ) * xForm : xForm; + { + typename TotalPointSampleData::Transform _xForm( xForm ); + XInputPointStream _pointStream( [&]( Point< Real , Dim >& p , TotalPointSampleData& d ){ p = xForm*p , d = _xForm(d); } , *pointStream ); + auto ProcessData = []( const Point< Real , Dim >& p , TotalPointSampleData& d ){ return (Real)1.; }; + pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< TotalPointSampleData >( tree.spaceRoot() , _pointStream , Depth.value , *samples , *sampleData , true , tree.nodeAllocators.size() ? tree.nodeAllocators[0] : NULL , tree.initializer() , ProcessData ); + } + iXForm = xForm.inverse(); + delete pointStream; + + messageWriter( "Input Points / Samples: %llu / %llu\n" , pointCount , (unsigned long long)samples->size() ); + profiler.dumpOutput2( comments , "# Read input into tree:" ); + } + + DenseNodeData< Real , Sigs > solution; + { + DenseNodeData< Real , Sigs > constraints; + InterpolationInfo* iInfo = NULL; + int solveDepth = Depth.value; + + tree.resetNodeIndices(); + + // Prepare for multigrid + { + profiler.start(); + tree.template finalizeForMultigrid< Degrees::Max() >( FullDepth.value , []( const typename FEMTree< Dim , Real >::FEMTreeNode * ){ return true; } ); + profiler.dumpOutput2( comments , "# Finalized tree:" ); + } + + // Add the interpolation constraints + { + profiler.start(); + if( ExactInterpolation.set ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , TotalPointSampleData , 1 >( tree , *samples , GetPointer( *sampleData ) , ConstraintDual< Dim , Real , TotalPointSampleData >( (Real)ValueWeight.value , (Real)GradientWeight.value ) , SystemDual< Dim , Real , TotalPointSampleData >( (Real)ValueWeight.value , (Real)GradientWeight.value ) , true , false ); + else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , TotalPointSampleData , 1 >( tree , *samples , GetPointer( *sampleData ) , ConstraintDual< Dim , Real , TotalPointSampleData >( (Real)ValueWeight.value , (Real)GradientWeight.value ) , SystemDual< Dim , Real , TotalPointSampleData >( (Real)ValueWeight.value , (Real)GradientWeight.value ) , true , 1 ); + constraints = tree.initDenseNodeData( Sigs() ); + tree.addInterpolationConstraints( constraints , solveDepth , *iInfo ); + profiler.dumpOutput2( comments , "#Set point constraints:" ); + } + + 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) ); + + // Solve the linear system + { + profiler.start(); + 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.baseDepth = BaseDepth.value , sInfo.baseVCycles = BaseVCycles.value; + typename FEMIntegrator::template System< Sigs , IsotropicUIntPack< Dim , 2 > > F( { 0. , (double)LapWeight.value , (double)BiLapWeight.value } ); + solution = tree.solveSystem( Sigs() , F , constraints , solveDepth , sInfo , iInfo ); + profiler.dumpOutput2( comments , "# Linear system solved:" ); + if( iInfo ) delete iInfo , iInfo = NULL; + } + } + + if( Verbose.set ) + { + typename FEMTree< Dim , Real >::template MultiThreadedEvaluator< Sigs , 1 > evaluator( &tree , solution ); + std::pair< double , double > valueStat(0,0) , gradientStat(0,0); + std::vector< std::pair< double , double > > valueStats( ThreadPool::NumThreads() , std::pair< double , double >(0,0) ) , gradientStats( ThreadPool::NumThreads() , std::pair< double , double >(0,0) ); + ValueAndGradientFromSample< Dim , Real , TotalPointSampleData > valueAndGradientFromSample; + 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 ) + { + CumulativeDerivativeValues< Real , Dim , 1 > values = evaluator.values( sample.data / sample.weight , thread , (*samples)[j].node ); + Real value = values[0]; + Point< Real , Dim > gradient; + for( int d=0 ; d > valueAndGradient = valueAndGradientFromSample( (*sampleData)[j] / w ); + valueStats[ thread ].first += ( value - valueAndGradient.first ) * ( value - valueAndGradient.first ) * w; + valueStats[ thread ].second += ( value * value + valueAndGradient.first * valueAndGradient.first ) * w; + gradientStats[ thread ].first += Point< Real , Dim >::SquareNorm( gradient - valueAndGradient.second ) * w; + gradientStats[ thread ].second += ( Point< Real , Dim >::SquareNorm( gradient ) + Point< Real , Dim >::SquareNorm( valueAndGradient.second ) ) * w; + } + } + ); + for( unsigned int t=0 ; t0 && GradientWeight.value>0 ) messageWriter( "Value / Gradient Error: %g / %g\n" , (Real)sqrt( valueStat.first / valueStat.second ) , (Real)sqrt( gradientStat.first / gradientStat.second ) ); + else if( ValueWeight.value>0 ) messageWriter( "Value Error: %g\n" , (Real)sqrt( valueStat.first / valueStat.second ) ); + else if( GradientWeight.value>0 ) messageWriter( "Gradient Error: %g\n" , (Real)sqrt( gradientStat.first / gradientStat.second ) ); + } + + delete samples , samples = NULL; + delete sampleData , sampleData = NULL; + + + if( Tree.set ) + { + 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 , xForm ); + solution.write( fp ); + fclose( fp ); + } + + if( Grid.set ) + { + int res = 0; + profiler.start(); + Pointer( Real ) values = tree.template regularGridEvaluate< true >( solution , res , -1 , PrimalGrid.set ); + size_t resolution = 1; + for( int d=0 ; d( values , res , Grid.value ); + DeletePointer( values ); + if( Verbose.set ) + { + printf( "Transform:\n" ); + for( int i=0 ; i Vertex; + std::function< void ( Vertex& , Point< Real , Dim > , Real , TotalPointSampleData ) > SetVertex = []( Vertex& v , Point< Real , Dim > p , Real , TotalPointSampleData ){ v.point = p; }; + ExtractMesh< Vertex >( UIntPack< FEMSigs ... >() , tree , solution , (Real)IsoValue.value , samples , SetVertex , comments , iXForm ); + } + + messageWriter( comments , "# Total Solve: %9.1f (s), %9.1f (MB)\n" , Time()-startTime , FEMTree< Dim , Real >::MaxMemoryUsage() ); +} + +template< class Real , unsigned int ... FEMSigs > +void Execute( int argc , char* argv[] , UIntPack< FEMSigs ... > ) +{ + static const int Dim = sizeof ... ( FEMSigs ); + if ( !UseGradientConstraints.set ) Execute< Real , MultiPointStreamData< Real , PointStreamValue< Real > > >( argc , argv , UIntPack< FEMSigs ... >() ); + else if( NoValueConstraints.set ) Execute< Real , MultiPointStreamData< Real , PointStreamNormal< Real , Dim > > >( argc , argv , UIntPack< FEMSigs ... >() ); + else Execute< Real , MultiPointStreamData< Real , PointStreamValue< Real > , PointStreamNormal< Real , Dim > > >( argc , argv , UIntPack< FEMSigs ... >() ); +} + +#ifndef FAST_COMPILE +template< unsigned int Dim , class Real > +void Execute( int argc , char* argv[] ) +{ + switch( BType.value ) + { + case BOUNDARY_FREE+1: + { + switch( Degree.value ) + { +// case 1: return Execute< Real >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 1 , BOUNDARY_FREE >::Signature >() ); + case 2: return Execute< Real >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BOUNDARY_FREE >::Signature >() ); + case 3: return Execute< Real >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BOUNDARY_FREE >::Signature >() ); +// case 4: return Execute< Real >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BOUNDARY_FREE >::Signature >() ); + default: ERROR_OUT( "Only B-Splines of degree 1 - 3 are supported" ); + } + } + case BOUNDARY_NEUMANN+1: + { + switch( Degree.value ) + { +// case 1: return Execute< Real >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 1 , BOUNDARY_NEUMANN >::Signature >() ); + case 2: return Execute< Real >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BOUNDARY_NEUMANN >::Signature >() ); + case 3: return Execute< Real >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BOUNDARY_NEUMANN >::Signature >() ); +// case 4: return Execute< Real >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BOUNDARY_NEUMANN >::Signature >() ); + default: ERROR_OUT( "Only B-Splines of degree 1 - 3 are supported" ); + } + } + case BOUNDARY_DIRICHLET+1: + { + switch( Degree.value ) + { +// case 1: return Execute< Real >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 1 , BOUNDARY_DIRICHLET >::Signature >() ); + case 2: return Execute< Real >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BOUNDARY_DIRICHLET >::Signature >() ); + case 3: return Execute< Real >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BOUNDARY_DIRICHLET >::Signature >() ); +// case 4: return Execute< Real >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BOUNDARY_DIRICHLET >::Signature >() ); + default: ERROR_OUT( "Only B-Splines of degree 1 - 3 are supported" ); + } + } + default: ERROR_OUT( "Not a valid boundary type: " , BType.value ); + } +} +#endif // !FAST_COMPILE + +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 + + cmdLineParse( argc-1 , &argv[1] , params ); +#if 0 + if( !In.set || !Out.set ) ERROR_OUT( "Need input and output" ); + unsigned int width , height; + unsigned char *pixels = ImageReader::ReadColor( In.value , width , height ); + FILE *fp = fopen( Out.value , "wb" ); + if( !fp ) ERROR_OUT( "Failed to open file for reading: %s" , Out.value ); + for( int i=0 ; i<10000 ; i++ ) + { + int x = rand() % width , y = rand() % height; + double gray = (double)( pixels[ 3*(y*width+x) + 0 ] + pixels[ 3*(y*width+x) + 1 ] + pixels[ 3*(y*width+x) + 2 ] ) / ( 255. * 3 ); + fprintf( fp , "%d %d %f\n" , x , y , gray ); + } + fclose( fp ); +#else + + 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 ) + { + ShowUsage( argv[0] ); + return 0; + } + if( NoValueConstraints.set ) ValueWeight.value = 0; + if( !UseGradientConstraints.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( 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( BaseDepth.value>FullDepth.value ) + { + if( BaseDepth.set ) WARN( "Base depth must be smaller than full depth: " , BaseDepth.value , " <= " , FullDepth.value ); + BaseDepth.value = FullDepth.value; + } + +#ifdef USE_DOUBLE + typedef double Real; +#else // !USE_DOUBLE + typedef float Real; +#endif // USE_DOUBLE + +#ifdef FAST_COMPILE + static const int Dimension = DIMENSION; + 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_" ); + Execute< Real >( argc , argv , FEMSigs() ); +#else // !FAST_COMPILE + if( Dimension.value==2 ) Execute< 2 , Real >( argc , argv ); + else if( Dimension.value==3 ) Execute< 3 , Real >( argc , argv ); + else ERROR_OUT( "Only Degrees 2 and 3 are supported" ); +#endif // FAST_COMPILE + if( Performance.set ) + { + printf( "Time (Wall/CPU): %.2f / %.2f\n" , timer.wallTime() , timer.cpuTime() ); + printf( "Peak Memory (MB): %d\n" , MemoryInfo::PeakMemoryUsageMB() ); + } +#endif + return EXIT_SUCCESS; +} diff --git a/apps/PoissonRecon/CMakeLists.txt b/apps/PoissonRecon/CMakeLists.txt new file mode 100644 index 00000000..031e81ed --- /dev/null +++ b/apps/PoissonRecon/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.7) + +project(PoissonReconApp) + +set(PROJECT_SRCS ${PROJECT_SOURCE_DIR}/src/PoissonRecon.cpp) + +source_group("src" FILES ${PROJECT_SRCS}) + +find_package(OpenMP REQUIRED) + +add_executable(${PROJECT_NAME} ${PROJECT_SRCS}) + +target_link_libraries(${PROJECT_NAME} PoissonRecon OpenMP::OpenMP_CXX) + +set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER ${CMAKE_PROJECT_NAME}/apps) + +install(TARGETS ${PROJECT_NAME} EXPORT ${CMAKE_PROJECT_NAME}Targets DESTINATION + bin) diff --git a/apps/PoissonRecon/src/PoissonRecon.cpp b/apps/PoissonRecon/src/PoissonRecon.cpp new file mode 100644 index 00000000..d2c4e746 --- /dev/null +++ b/apps/PoissonRecon/src/PoissonRecon.cpp @@ -0,0 +1,860 @@ +/* +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 "Mesh/PoissonRecon/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 DIMENSION 3 // The dimension of the system + +#include +#include +#include +#include +#include "Mesh/PoissonRecon/MyMiscellany.h" +#include "Mesh/PoissonRecon/CmdLineParser.h" +#include "Mesh/PoissonRecon/PPolynomial.h" +#include "Mesh/PoissonRecon/FEMTree.h" +#include "Mesh/PoissonRecon/Ply.h" +#include "Mesh/PoissonRecon/PointStreamData.h" +#include "Mesh/PoissonRecon/Image.h" + +MessageWriter messageWriter; + +const float DefaultPointWeightMultiplier = 2.f; + +cmdLineParameter< char* > + In( "in" ) , + Out( "out" ) , + TempDir( "tempDir" ) , + Grid( "grid" ) , + Tree( "tree" ) , + Transform( "xForm" ); + +cmdLineReadable + Performance( "performance" ) , + ShowResidual( "showResidual" ) , + NoComments( "noComments" ) , + PolygonMesh( "polygonMesh" ) , + NonManifold( "nonManifold" ) , + ASCII( "ascii" ) , + Density( "density" ) , + LinearFit( "linearFit" ) , + PrimalGrid( "primalGrid" ) , + ExactInterpolation( "exact" ) , + Normals( "normals" ) , + Colors( "colors" ) , + InCore( "inCore" ) , + Verbose( "verbose" ); + +cmdLineParameter< int > +#ifndef FAST_COMPILE + Degree( "degree" , DEFAULT_FEM_DEGREE ) , +#endif // !FAST_COMPILE + Depth( "depth" , 8 ) , + KernelDepth( "kernelDepth" ) , + Iters( "iters" , 8 ) , + FullDepth( "fullDepth" , 5 ) , + BaseDepth( "baseDepth" , 0 ) , + BaseVCycles( "baseVCycles" , 1 ) , +#ifndef FAST_COMPILE + BType( "bType" , DEFAULT_FEM_BOUNDARY+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 + ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , + ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , + Threads( "threads" , (int)std::thread::hardware_concurrency() ); + +cmdLineParameter< float > + DataX( "data" , 32.f ) , + SamplesPerNode( "samplesPerNode" , 1.5f ) , + Scale( "scale" , 1.1f ) , + Width( "width" , 0.f ) , + Confidence( "confidence" , 0.f ) , + ConfidenceBias( "confidenceBias" , 0.f ) , + CGSolverAccuracy( "cgAccuracy" , 1e-3f ) , + PointWeight( "pointWeight" ); + +cmdLineReadable* params[] = +{ +#ifndef FAST_COMPILE + &Degree , &BType , +#endif // !FAST_COMPILE + &In , &Depth , &Out , &Transform , + &Width , + &Scale , &Verbose , &CGSolverAccuracy , &NoComments , + &KernelDepth , &SamplesPerNode , &Confidence , &NonManifold , &PolygonMesh , &ASCII , &ShowResidual , + &ConfidenceBias , + &BaseDepth , &BaseVCycles , + &PointWeight , + &Grid , &Threads , + &Tree , + &Density , + &FullDepth , + &Iters , + &DataX , + &Colors , + &Normals , + &LinearFit , + &PrimalGrid , + &TempDir , + &ExactInterpolation , + &Performance , + &MaxMemoryGB , + &InCore , + &ParallelType , + &ScheduleType , + &ThreadChunkSize , + 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" , Grid.name ); + printf( "\t[--%s ]\n" , Tree.name ); +#ifndef FAST_COMPILE + printf( "\t[--%s =%d]\n" , Degree.name , Degree.value ); + printf( "\t[--%s =%d]\n" , BType.name , BType.value ); + for( int i=0 ; i=%d]\n" , Depth.name , Depth.value ); + printf( "\t[--%s ]\n" , Width.name ); + printf( "\t[--%s =%d]\n" , FullDepth.name , FullDepth.value ); + printf( "\t[--%s =%d]\n" , BaseDepth.name , BaseDepth.value ); + 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 ); + 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]\n" , Normals.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 ); + 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]\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" , Performance.name ); + printf( "\t[--%s]\n" , Density.name ); + printf( "\t[--%s]\n" , LinearFit.name ); + printf( "\t[--%s]\n" , PrimalGrid.name ); + printf( "\t[--%s]\n" , ASCII.name ); + printf( "\t[--%s]\n" , NoComments.name ); + printf( "\t[--%s]\n" , TempDir.name ); + printf( "\t[--%s]\n" , InCore.name ); + printf( "\t[--%s]\n" , Verbose.name ); +} + +double Weight( double v , double start , double end ) +{ + v = ( v - start ) / ( end - start ); + if ( v<0 ) return 1.; + else if( v>1 ) return 0.; + else + { + // P(x) = a x^3 + b x^2 + c x + d + // P (0) = 1 , P (1) = 0 , P'(0) = 0 , P'(1) = 0 + // => d = 1 , a + b + c + d = 0 , c = 0 , 3a + 2b + c = 0 + // => c = 0 , d = 1 , a + b = -1 , 3a + 2b = 0 + // => a = 2 , b = -3 , c = 0 , d = 1 + // => P(x) = 2 x^3 - 3 x^2 + 1 + return 2. * v * v * v - 3. * v * v + 1.; + } +} + +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) / %9.1f (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) / %9.1f (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) / %9.1f (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) / %9.1f (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) / %9.1f (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) / %9.1f (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 +XForm< Real , Dim+1 > GetPointXForm( InputPointStream< Real , Dim >& stream , Real width , Real scaleFactor , int& depth ) +{ + Point< Real , Dim > min , max; + stream.boundingBox( min , max ); + return GetBoundingBoxXForm( min , max , width , scaleFactor , depth ); +} +template< class Real , unsigned int Dim > +XForm< Real , Dim+1 > GetPointXForm( InputPointStream< Real , Dim >& stream , Real scaleFactor ) +{ + Point< Real , Dim > min , max; + stream.boundingBox( 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 Vertex , typename Real , typename SetVertexFunction , unsigned int ... FEMSigs , typename ... SampleData > +void ExtractMesh( UIntPack< FEMSigs ... > , std::tuple< SampleData ... > , FEMTree< sizeof ... ( FEMSigs ) , Real >& tree , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& solution , Real isoValue , const std::vector< typename FEMTree< sizeof ... ( FEMSigs ) , Real >::PointSample >* samples , std::vector< MultiPointStreamData< Real , PointStreamNormal< Real , DIMENSION > , MultiPointStreamData< Real , SampleData ... > > >* sampleData , const typename FEMTree< sizeof ... ( FEMSigs ) , Real >::template DensityEstimator< WEIGHT_DEGREE >* density , const SetVertexFunction &SetVertex , std::vector< std::string > &comments , XForm< Real , sizeof...(FEMSigs)+1 > iXForm ) +{ + static const int Dim = sizeof ... ( FEMSigs ); + typedef UIntPack< FEMSigs ... > Sigs; + typedef PointStreamNormal< Real , Dim > NormalPointSampleData; + typedef MultiPointStreamData< Real , SampleData ... > AdditionalPointSampleData; + typedef MultiPointStreamData< Real , NormalPointSampleData , AdditionalPointSampleData > TotalPointSampleData; + static const unsigned int DataSig = FEMDegreeAndBType< DATA_DEGREE , BOUNDARY_FREE >::Signature; + typedef typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; + + FEMTreeProfiler< Dim , Real > profiler( tree ); + + char tempHeader[1024]; + { + char tempPath[1024]; + tempPath[0] = 0; + if( TempDir.set ) strcpy( tempPath , TempDir.value ); + else SetTempDirectory( tempPath , sizeof(tempPath) ); + if( strlen(tempPath)==0 ) sprintf( tempPath , ".%c" , FileSeparator ); + if( tempPath[ strlen( tempPath )-1 ]==FileSeparator ) sprintf( tempHeader , "%sPR_" , tempPath ); + else sprintf( tempHeader , "%s%cPR_" , tempPath , FileSeparator ); + } + CoredMeshData< Vertex , node_index_type > *mesh; + if( InCore.set ) mesh = new CoredVectorMeshData< Vertex , node_index_type >(); + else mesh = new CoredFileMeshData< Vertex , node_index_type >( tempHeader ); + + profiler.start(); + typename IsoSurfaceExtractor< Dim , Real , Vertex >::IsoStats isoStats; + if( sampleData ) + { + SparseNodeData< ProjectiveData< TotalPointSampleData , Real > , IsotropicUIntPack< Dim , DataSig > > _sampleData = tree.template setMultiDepthDataField< 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 ) ) + { + ProjectiveData< TotalPointSampleData , Real >* clr = _sampleData( n ); + if( clr ) (*clr) *= (Real)pow( DataX.value , tree.depth( n ) ); + } + isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< TotalPointSampleData >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , &_sampleData , solution , isoValue , *mesh , SetVertex , !LinearFit.set , !NonManifold.set , PolygonMesh.set , false ); + } +#if defined( __GNUC__ ) && __GNUC__ < 5 +#warning "you've got me gcc version<5" + else isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< TotalPointSampleData >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , (SparseNodeData< ProjectiveData< TotalPointSampleData , Real > , IsotropicUIntPack< Dim , DataSig > > *)NULL , solution , isoValue , *mesh , SetVertex , !LinearFit.set , !NonManifold.set , PolygonMesh.set , false ); +#else // !__GNUC__ || __GNUC__ >=5 + else isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< TotalPointSampleData >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , NULL , solution , isoValue , *mesh , SetVertex , !LinearFit.set , !NonManifold.set , PolygonMesh.set , false ); +#endif // __GNUC__ || __GNUC__ < 4 + messageWriter( "Vertices / Polygons: %llu / %llu\n" , (unsigned long long)( mesh->outOfCorePointCount()+mesh->inCorePoints.size() ) , (unsigned long long)mesh->polygonCount() ); + 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:" ); + + std::vector< std::string > noComments; + if( !PlyWritePolygons< Vertex , node_index_type , Real , Dim >( Out.value , mesh , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , NoComments.set ? noComments : comments , iXForm ) ) + ERROR_OUT( "Could not write mesh to: " , Out.value ); + + delete mesh; +} + +template< typename Real , unsigned int Dim > +void WriteGrid( ConstPointer( Real ) values , int res , const char *fileName ) +{ + int resolution = 1; + for( int d=0 ; d avgs( ThreadPool::NumThreads() , 0 ); + ThreadPool::Parallel_for( 0 , resolution , [&]( unsigned int thread , size_t i ){ avgs[thread] += values[i]; } ); + for( unsigned int t=0 ; t stds( ThreadPool::NumThreads() , 0 ); + ThreadPool::Parallel_for( 0 , resolution , [&]( 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 ); + + unsigned char *pixels = new unsigned char[ resolution*3 ]; + ThreadPool::Parallel_for( 0 , resolution , [&]( 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 + { + + FILE *fp = fopen( fileName , "wb" ); + if( !fp ) ERROR_OUT( "Failed to open grid file for writing: " , fileName ); + else + { + fwrite( &res , sizeof(int) , 1 , fp ); + if( typeid(Real)==typeid(float) ) fwrite( values , sizeof(float) , resolution , fp ); + else + { + float *fValues = new float[resolution]; + for( int i=0 ; i +void Execute( int argc , char* argv[] , UIntPack< FEMSigs ... > ) +{ + 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; + typedef PointStreamNormal< Real , Dim > NormalPointSampleData; + typedef MultiPointStreamData< Real , SampleData ... > AdditionalPointSampleData; + typedef MultiPointStreamData< Real , NormalPointSampleData , AdditionalPointSampleData > TotalPointSampleData; + typedef InputPointStreamWithData< Real , Dim , TotalPointSampleData > InputPointStream; + typedef TransformedInputPointStreamWithData< Real , Dim , TotalPointSampleData > XInputPointStream; + std::vector< 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 ); + + + XForm< Real , Dim+1 > xForm , iXForm; + if( Transform.set ) + { + FILE* fp = fopen( Transform.value , "r" ); + if( !fp ) + { + WARN( "Could not read x-form from: " , Transform.value ); + xForm = XForm< Real , Dim+1 >::Identity(); + } + else + { + for( int i=0 ; i::Identity(); + + 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 ); + } + + double startTime = Time(); + Real isoValue = 0; + + FEMTree< Dim , Real > tree( MEMORY_ALLOCATOR_BLOCK_SIZE ); + FEMTreeProfiler< Dim , Real > profiler( tree ); + + if( Depth.set && Width.value>0 ) + { + WARN( "Both --" , Depth.name , " and --" , Width.name , " set, ignoring --" , Width.name ); + Width.value = 0; + } + + size_t pointCount; + + Real pointWeightSum; + std::vector< typename FEMTree< Dim , Real >::PointSample >* samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); + std::vector< TotalPointSampleData >* sampleData = NULL; + DensityEstimator* density = NULL; + SparseNodeData< Point< Real , Dim > , NormalSigs >* normalInfo = NULL; + Real targetValue = (Real)0.5; + + // Read in the samples (and color data) + { + profiler.start(); + InputPointStream* pointStream; + char* ext = GetFileExtension( In.value ); + sampleData = new std::vector< TotalPointSampleData >(); + std::vector< std::pair< Point< Real , Dim > , TotalPointSampleData > > inCorePoints; + if( InCore.set ) + { + InputPointStream *_pointStream; + if ( !strcasecmp( ext , "bnpts" ) ) _pointStream = new BinaryInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::ReadBinary ); + else if( !strcasecmp( ext , "ply" ) ) _pointStream = new PLYInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::PlyReadProperties() , TotalPointSampleData::PlyReadNum , TotalPointSampleData::ValidPlyReadProperties ); + else _pointStream = new ASCIIInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::ReadASCII ); + Point< Real , Dim > p; + TotalPointSampleData d; + while( _pointStream->nextPoint( p , d ) ) inCorePoints.push_back( std::pair< Point< Real , Dim > , TotalPointSampleData >( p , d ) ); + delete _pointStream; + + pointStream = new MemoryInputPointStreamWithData< Real , Dim , TotalPointSampleData >( inCorePoints.size() , &inCorePoints[0] ); + } + else + { + if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::ReadBinary ); + else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::PlyReadProperties() , TotalPointSampleData::PlyReadNum , TotalPointSampleData::ValidPlyReadProperties ); + else pointStream = new ASCIIInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::ReadASCII ); + } + delete[] ext; + typename TotalPointSampleData::Transform _xForm( xForm ); + XInputPointStream _pointStream( [&]( Point< Real , Dim >& p , TotalPointSampleData& d ){ p = xForm*p , d = _xForm(d); } , *pointStream ); + if( Width.value>0 ) xForm = GetPointXForm< Real , Dim >( _pointStream , Width.value , (Real)( Scale.value>0 ? Scale.value : 1. ) , Depth.value ) * xForm; + else xForm = Scale.value>0 ? GetPointXForm< Real , Dim >( _pointStream , (Real)Scale.value ) * xForm : xForm; + { + typename TotalPointSampleData::Transform _xForm( xForm ); + XInputPointStream _pointStream( [&]( Point< Real , Dim >& p , TotalPointSampleData& d ){ p = xForm*p , d = _xForm(d); } , *pointStream ); + auto ProcessDataWithConfidence = [&]( const Point< Real , Dim >& p , TotalPointSampleData& d ) + { + Real l = (Real)Length( d.template data<0>() ); + if( !l || l!=l ) return (Real)-1.; + return (Real)pow( l , Confidence.value ); + }; + auto ProcessData = []( const Point< Real , Dim >& p , TotalPointSampleData& d ) + { + Real l = (Real)Length( d.template data<0>() ); + if( !l || l!=l ) return (Real)-1.; + d.template data<0>() /= l; + return (Real)1.; + }; + if( Confidence.value>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< TotalPointSampleData >( tree.spaceRoot() , _pointStream , Depth.value , *samples , *sampleData , true , tree.nodeAllocators[0] , tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< TotalPointSampleData >( tree.spaceRoot() , _pointStream , Depth.value , *samples , *sampleData , true , tree.nodeAllocators[0] , tree.initializer() , ProcessData ); + } + iXForm = xForm.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:" ); + } + 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; + { + DenseNodeData< Real , Sigs > constraints; + InterpolationInfo* iInfo = NULL; + int solveDepth = Depth.value; + + tree.resetNodeIndices(); + + // Get the kernel density estimator + { + profiler.start(); + density = tree.template setDensityEstimator< WEIGHT_DEGREE >( *samples , kernelDepth , SamplesPerNode.value , 1 ); + profiler.dumpOutput2( comments , "# Got kernel density:" ); + } + + // Transform the Hermite samples into a vector field + { + profiler.start(); + normalInfo = new SparseNodeData< Point< Real , Dim > , NormalSigs >(); + std::function< bool ( TotalPointSampleData , Point< Real , Dim >& ) > ConversionFunction = []( TotalPointSampleData in , Point< Real , Dim > &out ) + { + Point< Real , Dim > n = in.template data<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 ( TotalPointSampleData , Point< Real , Dim >& , Real & ) > ConversionAndBiasFunction = []( TotalPointSampleData in , Point< Real , Dim > &out , Real &bias ) + { + Point< Real , Dim > n = in.template data<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.setDataField( NormalSigs() , *samples , *sampleData , density , pointWeightSum , ConversionAndBiasFunction ); + else *normalInfo = tree.setDataField( NormalSigs() , *samples , *sampleData , density , pointWeightSum , 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 Area: %g / %g\n" , pointWeightSum , pointCount*pointWeightSum ); + } + + + if( !Density.set ) delete density , density = NULL; + if( DataX.value<=0 || ( !Colors.set && !Normals.set ) ) delete sampleData , sampleData = NULL; + + // Trim the tree and prepare for multigrid + { + profiler.start(); + constexpr int MAX_DEGREE = NORMAL_DEGREE > Degrees::Max() ? NORMAL_DEGREE : Degrees::Max(); + tree.template finalizeForMultigrid< MAX_DEGREE >( FullDepth.value , typename FEMTree< Dim , Real >::template HasNormalDataFunctor< NormalSigs >( *normalInfo ) , normalInfo , density ); + profiler.dumpOutput2( comments , "# Finalized tree:" ); + } + // Add the FEM constraints + { + profiler.start(); + 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 ); + profiler.dumpOutput2( comments , "# Set FEM constraints:" ); + } + + // Free up the normal info + delete normalInfo , normalInfo = NULL; + + // 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 ); + tree.addInterpolationConstraints( constraints , solveDepth , *iInfo ); + profiler.dumpOutput2( comments , "#Set point constraints:" ); + } + + 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) ); + + // Solve the linear system + { + profiler.start(); + 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.baseDepth = BaseDepth.value , sInfo.baseVCycles = BaseVCycles.value; + typename FEMIntegrator::template System< Sigs , IsotropicUIntPack< Dim , 1 > > F( { 0. , 1. } ); + solution = tree.solveSystem( Sigs() , F , constraints , solveDepth , sInfo , iInfo ); + profiler.dumpOutput2( comments , "# Linear system solved:" ); + if( iInfo ) delete iInfo , iInfo = NULL; + } + } + + { + profiler.start(); + 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::WriteParameter( fp ); + DenseNodeData< Real , Sigs >::WriteSignatures( fp ); + tree.write( fp , xForm ); + solution.write( fp ); + fclose( fp ); + } + + if( Grid.set ) + { + int res = 0; + profiler.start(); + Pointer( Real ) values = tree.template regularGridEvaluate< true >( solution , res , -1 , PrimalGrid.set ); + size_t resolution = 1; + for( int d=0 ; d( values , res , Grid.value ); + DeletePointer( values ); + if( Verbose.set ) + { + printf( "Transform:\n" ); + for( int i=0 ; i , PointStreamValue< Real > , AdditionalPointSampleData > > Vertex; + auto SetVertex = []( Vertex& v , Point< Real , Dim > p , Real w , TotalPointSampleData d ){ v.point = p , v.data.template data<0>() = d.template data<0>() , v.data.template data<1>() = w , v.data.template data<2>() = d.template data<1>(); }; + ExtractMesh< Vertex >( UIntPack< FEMSigs ... >() , std::tuple< SampleData ... >() , tree , solution , isoValue , samples , sampleData , density , SetVertex , comments , iXForm ); + } + else + { + typedef PlyVertexWithData< Real , Dim , MultiPointStreamData< Real , PointStreamNormal< Real , Dim > , AdditionalPointSampleData > > Vertex; + auto SetVertex = []( Vertex& v , Point< Real , Dim > p , Real w , TotalPointSampleData d ){ v.point = p , v.data.template data<0>() = d.template data<0>() , v.data.template data<1>() = d.template data<1>(); }; + ExtractMesh< Vertex >( UIntPack< FEMSigs ... >() , std::tuple< SampleData ... >() , tree , solution , isoValue , samples , sampleData , density , SetVertex , comments , iXForm ); + } + } + else + { + if( Density.set ) + { + typedef PlyVertexWithData< Real , Dim , MultiPointStreamData< Real , PointStreamValue< Real > , AdditionalPointSampleData > > Vertex; + std::function< void ( Vertex& , Point< Real , Dim > , Real , TotalPointSampleData ) > SetVertex = []( Vertex& v , Point< Real , Dim > p , Real w , TotalPointSampleData d ){ v.point = p , v.data.template data<0>() = w , v.data.template data<1>() = d.template data<1>(); }; + ExtractMesh< Vertex >( UIntPack< FEMSigs ... >() , std::tuple< SampleData ... >() , tree , solution , isoValue , samples , sampleData , density , SetVertex , comments , iXForm ); + } + else + { + typedef PlyVertexWithData< Real , Dim , MultiPointStreamData< Real , AdditionalPointSampleData > > Vertex; + auto SetVertex = []( Vertex& v , Point< Real , Dim > p , Real w , TotalPointSampleData d ){ v.point = p , v.data.template data<0>() = d.template data<1>(); }; + ExtractMesh< Vertex >( UIntPack< FEMSigs ... >() , std::tuple< SampleData ... >() , tree , solution , isoValue , samples , sampleData , density , SetVertex , comments , iXForm ); + } + } + if( sampleData ){ delete sampleData ; sampleData = NULL; } + } + if( density ) delete density , density = NULL; + messageWriter( comments , "# Total Solve: %9.1f (s), %9.1f (MB)\n" , Time()-startTime , FEMTree< Dim , Real >::MaxMemoryUsage() ); +} + +#ifndef FAST_COMPILE +template< unsigned int Dim , class Real , typename ... SampleData > +void Execute( int argc , char* argv[] ) +{ + switch( BType.value ) + { + case BOUNDARY_FREE+1: + { + switch( Degree.value ) + { + case 1: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 1 , BOUNDARY_FREE >::Signature >() ); + case 2: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BOUNDARY_FREE >::Signature >() ); +// case 3: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BOUNDARY_FREE >::Signature >() ); +// case 4: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BOUNDARY_FREE >::Signature >() ); + default: ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); + } + } + case BOUNDARY_NEUMANN+1: + { + switch( Degree.value ) + { + case 1: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 1 , BOUNDARY_NEUMANN >::Signature >() ); + case 2: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BOUNDARY_NEUMANN >::Signature >() ); +// case 3: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BOUNDARY_NEUMANN >::Signature >() ); +// case 4: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BOUNDARY_NEUMANN >::Signature >() ); + default: ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); + } + } + case BOUNDARY_DIRICHLET+1: + { + switch( Degree.value ) + { + case 1: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 1 , BOUNDARY_DIRICHLET >::Signature >() ); + case 2: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BOUNDARY_DIRICHLET >::Signature >() ); +// case 3: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BOUNDARY_DIRICHLET >::Signature >() ); +// case 4: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BOUNDARY_DIRICHLET >::Signature >() ); + default: ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); + } + } + default: ERROR_OUT( "Not a valid boundary type: %d" , BType.value ); + } +} +#endif // !FAST_COMPILE + +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 + 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 ); + + messageWriter.echoSTDOUT = Verbose.set; + if( !In.set ) + { + ShowUsage( argv[0] ); + return 0; + } + if( DataX.value<=0 ) Normals.set = Colors.set = false; + 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; + } + +#ifdef USE_DOUBLE + typedef double Real; +#else // !USE_DOUBLE + typedef float Real; +#endif // USE_DOUBLE + +#ifdef FAST_COMPILE + 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_" ); + if( !PointWeight.set ) PointWeight.value = DefaultPointWeightMultiplier*Degree; + if( Colors.set ) Execute< Real , PointStreamColor< Real > >( argc , argv , FEMSigs() ); + else Execute< Real >( argc , argv , FEMSigs() ); +#else // !FAST_COMPILE + if( !PointWeight.set ) PointWeight.value = DefaultPointWeightMultiplier*Degree.value; + if( Colors.set ) Execute< DIMENSION , Real , PointStreamColor< float > >( argc , argv ); + else Execute< DIMENSION , Real >( argc , argv ); +#endif // FAST_COMPILE + if( Performance.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/apps/SSDRecon/CMakeLists.txt b/apps/SSDRecon/CMakeLists.txt new file mode 100644 index 00000000..d08565d8 --- /dev/null +++ b/apps/SSDRecon/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.7) + +project(SSDRecon) + +set(PROJECT_SRCS ${PROJECT_SOURCE_DIR}/src/SSDRecon.cpp) + +source_group("src" FILES ${PROJECT_SRCS}) + +find_package(OpenMP REQUIRED) + +add_executable(${PROJECT_NAME} ${PROJECT_SRCS}) + +target_link_libraries(${PROJECT_NAME} PoissonRecon OpenMP::OpenMP_CXX) + +set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER ${CMAKE_PROJECT_NAME}/apps) + +install(TARGETS ${PROJECT_NAME} EXPORT ${CMAKE_PROJECT_NAME}Targets DESTINATION + bin) diff --git a/apps/SSDRecon/src/SSDRecon.cpp b/apps/SSDRecon/src/SSDRecon.cpp new file mode 100644 index 00000000..50340f61 --- /dev/null +++ b/apps/SSDRecon/src/SSDRecon.cpp @@ -0,0 +1,861 @@ +/* +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 "Mesh/PoissonRecon/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 DIMENSION 3 // The dimension of the system + +#include +#include +#include +#include +#include "Mesh/PoissonRecon/MyMiscellany.h" +#include "Mesh/PoissonRecon/CmdLineParser.h" +#include "Mesh/PoissonRecon/PPolynomial.h" +#include "Mesh/PoissonRecon/FEMTree.h" +#include "Mesh/PoissonRecon/Ply.h" +#include "Mesh/PoissonRecon/PointStreamData.h" +#include "Mesh/PoissonRecon/Image.h" + +MessageWriter messageWriter; + +double BaseSSDWeights[] = { 5e+1f , 5e-4f , 1e-5f }; + +cmdLineParameter< char* > + In( "in" ) , + Out( "out" ) , + TempDir( "tempDir" ) , + Grid( "grid" ) , + Tree( "tree" ) , + Transform( "xForm" ); + +cmdLineReadable + Performance( "performance" ) , + ShowResidual( "showResidual" ) , + NoComments( "noComments" ) , + PolygonMesh( "polygonMesh" ) , + NonManifold( "nonManifold" ) , + ASCII( "ascii" ) , + Density( "density" ) , + NonLinearFit( "nonLinearFit" ) , + PrimalGrid( "primalGrid" ) , + ExactInterpolation( "exact" ) , + Normals( "normals" ) , + Colors( "colors" ) , + InCore( "inCore" ) , + Verbose( "verbose" ); + +cmdLineParameter< int > +#ifndef FAST_COMPILE + Degree( "degree" , DEFAULT_FEM_DEGREE ) , +#endif // !FAST_COMPILE + Depth( "depth" , 8 ) , + KernelDepth( "kernelDepth" ) , + Iters( "iters" , 8 ) , + FullDepth( "fullDepth" , 5 ) , + BaseDepth( "baseDepth" , 5 ) , + BaseVCycles( "baseVCycles" , 4 ) , +#ifndef FAST_COMPILE + BType( "bType" , DEFAULT_FEM_BOUNDARY+1 ) , +#endif // !FAST_COMPILE + MaxMemoryGB( "maxMemory" , 0 ) , + ParallelType( "parallel" , (int)ThreadPool::OPEN_MP ) , + ScheduleType( "schedule" , (int)ThreadPool::DefaultSchedule ) , + ThreadChunkSize( "chunkSize" , (int)ThreadPool::DefaultChunkSize ) , + Threads( "threads" , (int)std::thread::hardware_concurrency() ); + +cmdLineParameter< float > + DataX( "data" , 32.f ) , + SamplesPerNode( "samplesPerNode" , 1.5f ) , + Scale( "scale" , 1.1f ) , + Width( "width" , 0.f ) , + Confidence( "confidence" , 0.f ) , + ConfidenceBias( "confidenceBias" , 0.f ) , + CGSolverAccuracy( "cgAccuracy" , 1e-3f ) , + ValueWeight ( "valueWeight" , 1.f ) , + GradientWeight( "gradientWeight" , 1.f ) , + BiLapWeight ( "biLapWeight" , 1.f ); + + +cmdLineReadable* params[] = +{ +#ifndef FAST_COMPILE + &Degree , &BType , +#endif // !FAST_COMPILE + &In , &Depth , &Out , &Transform , + &Width , + &Scale , &Verbose , &CGSolverAccuracy , &NoComments , + &KernelDepth , &SamplesPerNode , &Confidence , &NonManifold , &PolygonMesh , &ASCII , &ShowResidual , + &ConfidenceBias , + &ValueWeight , &GradientWeight , &BiLapWeight , + &Grid , &Threads , + &Tree , + &Density , + &FullDepth , + &BaseDepth , &BaseVCycles , + &Iters , + &DataX , + &Colors , + &Normals , + &NonLinearFit , + &PrimalGrid , + &TempDir , + &ExactInterpolation , + &Performance , + &MaxMemoryGB , + &InCore , + &ParallelType , + &ScheduleType , + &ThreadChunkSize , + 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" , Grid.name ); + printf( "\t[--%s ]\n" , Tree.name ); +#ifndef FAST_COMPILE + printf( "\t[--%s =%d]\n" , Degree.name , Degree.value ); + printf( "\t[--%s =%d]\n" , BType.name , BType.value ); + for( int i=0 ; i=%d]\n" , Depth.name , Depth.value ); + printf( "\t[--%s ]\n" , Width.name ); + printf( "\t[--%s =%d]\n" , FullDepth.name , FullDepth.value ); + printf( "\t[--%s =%d]\n" , BaseDepth.name , BaseDepth.value ); + 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" , ValueWeight.name , ValueWeight.value ); + printf( "\t[--%s =%.3e]\n" , GradientWeight.name , GradientWeight.value ); + printf( "\t[--%s =%.3e]\n" , BiLapWeight.name , BiLapWeight.value ); + printf( "\t[--%s =%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]\n" , Normals.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 ); + 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]\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" , Performance.name ); + printf( "\t[--%s]\n" , Density.name ); + printf( "\t[--%s]\n" , NonLinearFit.name ); + printf( "\t[--%s]\n" , PrimalGrid.name ); + printf( "\t[--%s]\n" , ASCII.name ); + printf( "\t[--%s]\n" , NoComments.name ); + printf( "\t[--%s]\n" , TempDir.name ); + printf( "\t[--%s]\n" , InCore.name ); + printf( "\t[--%s]\n" , Verbose.name ); +} + +double Weight( double v , double start , double end ) +{ + v = ( v - start ) / ( end - start ); + if ( v<0 ) return 1.; + else if( v>1 ) return 0.; + else + { + // P(x) = a x^3 + b x^2 + c x + d + // P (0) = 1 , P (1) = 0 , P'(0) = 0 , P'(1) = 0 + // => d = 1 , a + b + c + d = 0 , c = 0 , 3a + 2b + c = 0 + // => c = 0 , d = 1 , a + b = -1 , 3a + 2b = 0 + // => a = 2 , b = -3 , c = 0 , d = 1 + // => P(x) = 2 x^3 - 3 x^2 + 1 + return 2. * v * v * v - 3. * v * v + 1.; + } +} + +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) / %9.1f (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) / %9.1f (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) / %9.1f (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) / %9.1f (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) / %9.1f (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) / %9.1f (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 +XForm< Real , Dim+1 > GetPointXForm( InputPointStream< Real , Dim >& stream , Real width , Real scaleFactor , int& depth ) +{ + Point< Real , Dim > min , max; + stream.boundingBox( min , max ); + return GetBoundingBoxXForm( min , max , width , scaleFactor , depth ); +} +template< class Real , unsigned int Dim > +XForm< Real , Dim+1 > GetPointXForm( InputPointStream< Real , Dim >& stream , Real scaleFactor ) +{ + Point< Real , Dim > min , max; + stream.boundingBox( min , max ); + return GetBoundingBoxXForm( min , max , scaleFactor ); +} + +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 data<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 Vertex , typename Real , unsigned int ... FEMSigs , typename ... SampleData > +void ExtractMesh( UIntPack< FEMSigs ... > , std::tuple< SampleData ... > , FEMTree< sizeof ... ( FEMSigs ) , Real >& tree , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& solution , Real isoValue , const std::vector< typename FEMTree< sizeof ... ( FEMSigs ) , Real >::PointSample >* samples , std::vector< MultiPointStreamData< Real , PointStreamNormal< Real , DIMENSION > , MultiPointStreamData< Real , SampleData ... > > >* sampleData , const typename FEMTree< sizeof ... ( FEMSigs ) , Real >::template DensityEstimator< WEIGHT_DEGREE >* density , std::function< void ( Vertex& , Point< Real , DIMENSION > , Real , MultiPointStreamData< Real , PointStreamNormal< Real , DIMENSION > , MultiPointStreamData< Real , SampleData ... > > ) > SetVertex , std::vector< std::string > &comments , XForm< Real , sizeof...(FEMSigs)+1 > iXForm ) +{ + static const int Dim = sizeof ... ( FEMSigs ); + typedef UIntPack< FEMSigs ... > Sigs; + typedef PointStreamNormal< Real , Dim > NormalPointSampleData; + typedef MultiPointStreamData< Real , SampleData ... > AdditionalPointSampleData; + typedef MultiPointStreamData< Real , NormalPointSampleData , AdditionalPointSampleData > TotalPointSampleData; + static const unsigned int DataSig = FEMDegreeAndBType< DATA_DEGREE , BOUNDARY_FREE >::Signature; + typedef typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; + + FEMTreeProfiler< Dim , Real > profiler( tree ); + + char tempHeader[1024]; + { + char tempPath[1024]; + tempPath[0] = 0; + if( TempDir.set ) strcpy( tempPath , TempDir.value ); + else SetTempDirectory( tempPath , sizeof(tempPath) ); + if( strlen(tempPath)==0 ) sprintf( tempPath , ".%c" , FileSeparator ); + if( tempPath[ strlen( tempPath )-1 ]==FileSeparator ) sprintf( tempHeader , "%sPR_" , tempPath ); + else sprintf( tempHeader , "%s%cPR_" , tempPath , FileSeparator ); + } + + CoredMeshData< Vertex , node_index_type > *mesh; + if( InCore.set ) mesh = new CoredVectorMeshData< Vertex , node_index_type >(); + else mesh = new CoredFileMeshData< Vertex , node_index_type >( tempHeader ); + profiler.start(); + typename IsoSurfaceExtractor< Dim , Real , Vertex >::IsoStats isoStats; + if( sampleData ) + { + SparseNodeData< ProjectiveData< TotalPointSampleData , Real > , IsotropicUIntPack< Dim , DataSig > > _sampleData = tree.template setMultiDepthDataField< 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 ) ) + { + ProjectiveData< TotalPointSampleData , Real >* clr = _sampleData( n ); + if( clr ) (*clr) *= (Real)pow( DataX.value , tree.depth( n ) ); + } + isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< TotalPointSampleData >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , &_sampleData , solution , isoValue , *mesh , SetVertex , NonLinearFit.set , !NonManifold.set , PolygonMesh.set , false ); + } +#if defined( __GNUC__ ) && __GNUC__ < 5 +#warning "you've got me gcc version<5" + else isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< TotalPointSampleData >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , (SparseNodeData< ProjectiveData< TotalPointSampleData , Real > , IsotropicUIntPack< Dim , DataSig > > *)NULL , solution , isoValue , *mesh , SetVertex , NonLinearFit.set , !NonManifold.set , PolygonMesh.set , false ); +#else // !__GNUC__ || __GNUC__ >=5 + else isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< TotalPointSampleData >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , NULL , solution , isoValue , *mesh , SetVertex , NonLinearFit.set , !NonManifold.set , PolygonMesh.set , false ); +#endif // __GNUC__ || __GNUC__ < 4 + messageWriter( "Vertices / Polygons: %llu / %llu\n" , (unsigned long long)( mesh->outOfCorePointCount()+mesh->inCorePoints.size() ) , (unsigned long long)mesh->polygonCount() ); + 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:" ); + + std::vector< std::string > noComments; + if( !PlyWritePolygons< Vertex , node_index_type , Real , Dim >( Out.value , mesh , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , NoComments.set ? noComments : comments , iXForm ) ) + ERROR_OUT( "Could not write mesh to: " , Out.value ); + delete mesh; +} + +template< typename Real , unsigned int Dim > +void WriteGrid( ConstPointer( Real ) values , int res , const char *fileName ) +{ + int resolution = 1; + for( int d=0 ; d avgs( ThreadPool::NumThreads() , 0 ); + ThreadPool::Parallel_for( 0 , resolution , [&]( unsigned int thread , size_t i ){ avgs[thread] += values[i]; } ); + for( unsigned int t=0 ; t stds( ThreadPool::NumThreads() , 0 ); + ThreadPool::Parallel_for( 0 , resolution , [&]( 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 ); + + unsigned char *pixels = new unsigned char[ resolution*3 ]; + ThreadPool::Parallel_for( 0 , resolution , [&]( 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 + { + + FILE *fp = fopen( fileName , "wb" ); + if( !fp ) ERROR_OUT( "Failed to open grid file for writing: " , fileName ); + else + { + fwrite( &res , sizeof(int) , 1 , fp ); + if( typeid(Real)==typeid(float) ) fwrite( values , sizeof(float) , resolution , fp ); + else + { + float *fValues = new float[resolution]; + for( int i=0 ; i +void Execute( int argc , char* argv[] , UIntPack< FEMSigs ... > ) +{ + 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; + typedef PointStreamNormal< Real , Dim > NormalPointSampleData; + typedef MultiPointStreamData< Real , SampleData ... > AdditionalPointSampleData; + typedef MultiPointStreamData< Real , NormalPointSampleData , AdditionalPointSampleData > TotalPointSampleData; + typedef InputPointStreamWithData< Real , Dim , TotalPointSampleData > InputPointStream; + typedef TransformedInputPointStreamWithData< Real , Dim , TotalPointSampleData > XInputPointStream; + std::vector< 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 ); + + + ThreadPool::Init( (ThreadPool::ParallelType)ParallelType.value , Threads.value ); + + XForm< Real , Dim+1 > xForm , iXForm; + if( Transform.set ) + { + FILE* fp = fopen( Transform.value , "r" ); + if( !fp ) + { + WARN( "Could not read x-form from: " , Transform.value ); + xForm = XForm< Real , Dim+1 >::Identity(); + } + else + { + for( int i=0 ; i::Identity(); + + 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 ); + } + + double startTime = Time(); + Real isoValue = 0; + + FEMTree< Dim , Real > tree( MEMORY_ALLOCATOR_BLOCK_SIZE ); + FEMTreeProfiler< Dim , Real > profiler( tree ); + + if( Depth.set && Width.value>0 ) + { + WARN( "Both --" , Depth.name , " and --" , Width.name , " set, ignoring --" , Width.name ); + Width.value = 0; + } + + size_t pointCount; + + Real pointWeightSum; + std::vector< typename FEMTree< Dim , Real >::PointSample >* samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); + std::vector< TotalPointSampleData >* sampleData = NULL; + DensityEstimator* density = NULL; + SparseNodeData< Point< Real , Dim > , NormalSigs >* normalInfo = NULL; + Real targetValue = (Real)0.; + + // Read in the samples (and color data) + { + profiler.start(); + InputPointStream* pointStream; + char* ext = GetFileExtension( In.value ); + sampleData = new std::vector< TotalPointSampleData >(); + std::vector< std::pair< Point< Real , Dim > , TotalPointSampleData > > inCorePoints; + if( InCore.set ) + { + InputPointStream *_pointStream; + if ( !strcasecmp( ext , "bnpts" ) ) _pointStream = new BinaryInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::ReadBinary ); + else if( !strcasecmp( ext , "ply" ) ) _pointStream = new PLYInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::PlyReadProperties() , TotalPointSampleData::PlyReadNum , TotalPointSampleData::ValidPlyReadProperties ); + else _pointStream = new ASCIIInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::ReadASCII ); + Point< Real , Dim > p; + TotalPointSampleData d; + while( _pointStream->nextPoint( p , d ) ) inCorePoints.push_back( std::pair< Point< Real , Dim > , TotalPointSampleData >( p , d ) ); + delete _pointStream; + + pointStream = new MemoryInputPointStreamWithData< Real , Dim , TotalPointSampleData >( inCorePoints.size() , &inCorePoints[0] ); + } + else + { + if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::ReadBinary ); + else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::PlyReadProperties() , TotalPointSampleData::PlyReadNum , TotalPointSampleData::ValidPlyReadProperties ); + else pointStream = new ASCIIInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::ReadASCII ); + } + delete[] ext; + typename TotalPointSampleData::Transform _xForm( xForm ); + XInputPointStream _pointStream( [&]( Point< Real , Dim >& p , TotalPointSampleData& d ){ p = xForm*p , d = _xForm(d); } , *pointStream ); + if( Width.value>0 ) xForm = GetPointXForm< Real , Dim >( _pointStream , Width.value , (Real)( Scale.value>0 ? Scale.value : 1. ) , Depth.value ) * xForm; + else xForm = Scale.value>0 ? GetPointXForm< Real , Dim >( _pointStream , (Real)Scale.value ) * xForm : xForm; + { + typename TotalPointSampleData::Transform _xForm( xForm ); + XInputPointStream _pointStream( [&]( Point< Real , Dim >& p , TotalPointSampleData& d ){ p = xForm*p , d = _xForm(d); } , *pointStream ); + auto ProcessDataWithConfidence = [&]( const Point< Real , Dim >& p , TotalPointSampleData& d ) + { + Real l = (Real)Length( d.template data<0>() ); + if( !l || l!=l ) return (Real)-1.; + return (Real)pow( l , Confidence.value ); + }; + auto ProcessData = []( const Point< Real , Dim >& p , TotalPointSampleData& d ) + { + Real l = (Real)Length( d.template data<0>() ); + if( !l || l!=l ) return (Real)-1.; + d.template data<0>() /= l; + return (Real)1.; + }; + if( Confidence.value>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< TotalPointSampleData >( 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< TotalPointSampleData >( tree.spaceRoot() , _pointStream , Depth.value , *samples , *sampleData , true , tree.nodeAllocators.size() ? tree.nodeAllocators[0] : NULL , tree.initializer() , ProcessData ); + } + iXForm = xForm.inverse(); + delete pointStream; + + messageWriter( "Input Points / Samples: %llu / %llu\n" , pointCount , (unsigned long long)samples->size() ); + profiler.dumpOutput2( comments , "# Read input into tree:" ); + } + 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; + { + DenseNodeData< Real , Sigs > constraints; + InterpolationInfo* iInfo = NULL; + int solveDepth = Depth.value; + + tree.resetNodeIndices(); + + // Get the kernel density estimator + { + profiler.start(); + density = tree.template setDensityEstimator< WEIGHT_DEGREE >( *samples , kernelDepth , SamplesPerNode.value , 1 ); + profiler.dumpOutput2( comments , "# Got kernel density:" ); + } + + // Transform the Hermite samples into a vector field + { + profiler.start(); + normalInfo = new SparseNodeData< Point< Real , Dim > , NormalSigs >(); + std::function< bool ( TotalPointSampleData , Point< Real , Dim >& ) > ConversionFunction = []( TotalPointSampleData in , Point< Real , Dim > &out ) + { + Point< Real , Dim > n = in.template data<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 ( TotalPointSampleData , Point< Real , Dim >& , Real & ) > ConversionAndBiasFunction = []( TotalPointSampleData in , Point< Real , Dim > &out , Real &bias ) + { + Point< Real , Dim > n = in.template data<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.setDataField( NormalSigs() , *samples , *sampleData , density , pointWeightSum , ConversionAndBiasFunction ); + else *normalInfo = tree.setDataField( NormalSigs() , *samples , *sampleData , density , pointWeightSum , ConversionFunction ); + profiler.dumpOutput2( comments , "# Got normal field:" ); + messageWriter( "Point weight / Estimated Area: %g / %g\n" , pointWeightSum , pointCount*pointWeightSum ); + } + + if( !Density.set ) delete density , density = NULL; + + // Trim the tree and prepare for multigrid + { + profiler.start(); + constexpr int MAX_DEGREE = NORMAL_DEGREE > Degrees::Max() ? NORMAL_DEGREE : Degrees::Max(); + tree.template finalizeForMultigrid< MAX_DEGREE >( FullDepth.value , typename FEMTree< Dim , Real >::template HasNormalDataFunctor< NormalSigs >( *normalInfo ) , normalInfo , density ); + profiler.dumpOutput2( comments , "# Finalized tree:" ); + } + + // 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 ) + { + profiler.start(); + if( ExactInterpolation.set ) iInfo = FEMTree< Dim , Real >::template InitializeExactPointAndDataInterpolationInfo< Real , TotalPointSampleData , 1 >( tree , *samples , GetPointer( *sampleData ) , ConstraintDual< Dim , Real , TotalPointSampleData >( targetValue , (Real)ValueWeight.value * pointWeightSum , (Real)GradientWeight.value * pointWeightSum ) , SystemDual< Dim , Real , TotalPointSampleData >( (Real)ValueWeight.value * pointWeightSum , (Real)GradientWeight.value * pointWeightSum ) , true , false ); + else iInfo = FEMTree< Dim , Real >::template InitializeApproximatePointAndDataInterpolationInfo< Real , TotalPointSampleData , 1 >( tree , *samples , GetPointer( *sampleData ) , ConstraintDual< Dim , Real , TotalPointSampleData >( targetValue , (Real)ValueWeight.value * pointWeightSum , (Real)GradientWeight.value * pointWeightSum ) , SystemDual< Dim , Real , TotalPointSampleData >( (Real)ValueWeight.value * pointWeightSum , (Real)GradientWeight.value * pointWeightSum ) , true , 1 ); + constraints = tree.initDenseNodeData( Sigs() ); + tree.addInterpolationConstraints( constraints , solveDepth , *iInfo ); + profiler.dumpOutput2( comments , "#Set point constraints:" ); + if( DataX.value<=0 || ( !Colors.set && !Normals.set ) ) 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) ); + + // Solve the linear system + { + profiler.start(); + 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.baseDepth = BaseDepth.value , 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 , sInfo , iInfo ); + profiler.dumpOutput2( comments , "# Linear system solved:" ); + if( iInfo ) delete iInfo , iInfo = NULL; + } + } + + { + profiler.start(); + 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::WriteParameter( fp ); + DenseNodeData< Real , Sigs >::WriteSignatures( fp ); + tree.write( fp , xForm ); + solution.write( fp ); + fclose( fp ); + } + + if( Grid.set ) + { + int res = 0; + profiler.start(); + Pointer( Real ) values = tree.template regularGridEvaluate< true >( solution , res , -1 , PrimalGrid.set ); + size_t resolution = 1; + for( int d=0 ; d( values , res , Grid.value ); + DeletePointer( values ); + if( Verbose.set ) + { + printf( "Transform:\n" ); + for( int i=0 ; i , PointStreamValue< Real > , AdditionalPointSampleData > > Vertex; + std::function< void ( Vertex& , Point< Real , Dim > , Real , TotalPointSampleData ) > SetVertex = []( Vertex& v , Point< Real , Dim > p , Real w , TotalPointSampleData d ){ v.point = p , v.data.template data<0>() = d.template data<0>() , v.data.template data<1>() = w , v.data.template data<2>() = d.template data<1>(); }; + ExtractMesh< Vertex >( UIntPack< FEMSigs ... >() , std::tuple< SampleData ... >() , tree , solution , isoValue , samples , sampleData , density , SetVertex , comments , iXForm ); + } + else + { + typedef PlyVertexWithData< Real , Dim , MultiPointStreamData< Real , PointStreamNormal< Real , Dim > , AdditionalPointSampleData > > Vertex; + std::function< void ( Vertex& , Point< Real , Dim > , Real , TotalPointSampleData ) > SetVertex = []( Vertex& v , Point< Real , Dim > p , Real w , TotalPointSampleData d ){ v.point = p , v.data.template data<0>() = d.template data<0>() , v.data.template data<1>() = d.template data<1>(); }; + ExtractMesh< Vertex >( UIntPack< FEMSigs ... >() , std::tuple< SampleData ... >() , tree , solution , isoValue , samples , sampleData , density , SetVertex , comments , iXForm ); + } + } + else + { + if( Density.set ) + { + typedef PlyVertexWithData< Real , Dim , MultiPointStreamData< Real , PointStreamValue< Real > , AdditionalPointSampleData > > Vertex; + std::function< void ( Vertex& , Point< Real , Dim > , Real , TotalPointSampleData ) > SetVertex = []( Vertex& v , Point< Real , Dim > p , Real w , TotalPointSampleData d ){ v.point = p , v.data.template data<0>() = w , v.data.template data<1>() = d.template data<1>(); }; + ExtractMesh< Vertex >( UIntPack< FEMSigs ... >() , std::tuple< SampleData ... >() , tree , solution , isoValue , samples , sampleData , density , SetVertex , comments , iXForm ); + } + else + { + typedef PlyVertexWithData< Real , Dim , MultiPointStreamData< Real , AdditionalPointSampleData > > Vertex; + std::function< void ( Vertex& , Point< Real , Dim > , Real , TotalPointSampleData ) > SetVertex = []( Vertex& v , Point< Real , Dim > p , Real w , TotalPointSampleData d ){ v.point = p , v.data.template data<0>() = d.template data<1>(); }; + ExtractMesh< Vertex >( UIntPack< FEMSigs ... >() , std::tuple< SampleData ... >() , tree , solution , isoValue , samples , sampleData , density , SetVertex , comments , iXForm ); + } + } + if( sampleData ){ delete sampleData ; sampleData = NULL; } + } + if( density ) delete density , density = NULL; + messageWriter( comments , "# Total Solve: %9.1f (s), %9.1f (MB)\n" , Time()-startTime , FEMTree< Dim , Real >::MaxMemoryUsage() ); +} + +#ifndef FAST_COMPILE +template< unsigned int Dim , class Real , typename ... SampleData > +void Execute( int argc , char* argv[] ) +{ + switch( BType.value ) + { + case BOUNDARY_FREE+1: + { + switch( Degree.value ) + { + case 2: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BOUNDARY_FREE >::Signature >() ); + case 3: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BOUNDARY_FREE >::Signature >() ); +// case 4: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BOUNDARY_FREE >::Signature >() ); + default: ERROR_OUT( "Only B-Splines of degree 2 - 3 are supported" ); + } + } + case BOUNDARY_NEUMANN+1: + { + switch( Degree.value ) + { + case 2: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BOUNDARY_NEUMANN >::Signature >() ); + case 3: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BOUNDARY_NEUMANN >::Signature >() ); +// case 4: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BOUNDARY_NEUMANN >::Signature >() ); + default: ERROR_OUT( "Only B-Splines of degree 2 - 3 are supported" ); + } + } + case BOUNDARY_DIRICHLET+1: + { + switch( Degree.value ) + { + case 2: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BOUNDARY_DIRICHLET >::Signature >() ); + case 3: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BOUNDARY_DIRICHLET >::Signature >() ); +// case 4: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BOUNDARY_DIRICHLET >::Signature >() ); + default: ERROR_OUT( "Only B-Splines of degree 2 - 3 are supported" ); + } + } + default: ERROR_OUT( "Not a valid boundary type: " , BType.value ); + } +} +#endif // !FAST_COMPILE + +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 + + cmdLineParse( argc-1 , &argv[1] , params ); + 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 ) + { + 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( DataX.value<=0 ) Normals.set = Colors.set = false; + 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)BaseSSDWeights[0]; + GradientWeight.value *= (float)BaseSSDWeights[1]; + BiLapWeight.value *= (float)BaseSSDWeights[2]; + +#ifdef USE_DOUBLE + typedef double Real; +#else // !USE_DOUBLE + typedef float Real; +#endif // USE_DOUBLE + +#ifdef FAST_COMPILE + 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_" ); + if( Colors.set ) Execute< Real , PointStreamColor< Real > >( argc , argv , FEMSigs() ); + else Execute< Real >( argc , argv , FEMSigs() ); +#else // !FAST_COMPILE + if( Colors.set ) Execute< DIMENSION , Real , PointStreamColor< float > >( argc , argv ); + else Execute< DIMENSION , Real >( argc , argv ); +#endif // FAST_COMPILE + if( Performance.set ) + { + printf( "Time (Wall/CPU): %.2f / %.2f\n" , timer.wallTime() , timer.cpuTime() ); + printf( "Peak Memory (MB): %d\n" , MemoryInfo::PeakMemoryUsageMB() ); + } + return EXIT_SUCCESS; +} diff --git a/apps/SurfaceTrimmer/CMakeLists.txt b/apps/SurfaceTrimmer/CMakeLists.txt new file mode 100644 index 00000000..e154bd5b --- /dev/null +++ b/apps/SurfaceTrimmer/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.7) + +project(SurfaceTrimmer) + +set(PROJECT_SRCS ${PROJECT_SOURCE_DIR}/src/SurfaceTrimmer.cpp) + +source_group("src" FILES ${PROJECT_SRCS}) + +add_executable(${PROJECT_NAME} ${PROJECT_SRCS}) + +target_link_libraries(${PROJECT_NAME} PoissonRecon) + +set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER ${CMAKE_PROJECT_NAME}/apps) + +install(TARGETS ${PROJECT_NAME} EXPORT ${CMAKE_PROJECT_NAME}Targets DESTINATION + bin) diff --git a/apps/SurfaceTrimmer/src/SurfaceTrimmer.cpp b/apps/SurfaceTrimmer/src/SurfaceTrimmer.cpp new file mode 100644 index 00000000..75892cf3 --- /dev/null +++ b/apps/SurfaceTrimmer/src/SurfaceTrimmer.cpp @@ -0,0 +1,425 @@ +/* +Copyright (c) 2013, 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 "Mesh/PoissonRecon/PreProcessor.h" + +#define DIMENSION 3 + +#include +#include +#include +#include +#include "Mesh/PoissonRecon/FEMTree.h" +#include "Mesh/PoissonRecon/MyMiscellany.h" +#include "Mesh/PoissonRecon/CmdLineParser.h" +#include "Mesh/PoissonRecon/MAT.h" +#include "Mesh/PoissonRecon/Geometry.h" +#include "Mesh/PoissonRecon/Ply.h" +#include "Mesh/PoissonRecon/PointStreamData.h" + +MessageWriter messageWriter; + + +cmdLineParameter< char* > + In( "in" ) , + Out( "out" ); +cmdLineParameter< int > + Smooth( "smooth" , 5 ); +cmdLineParameter< float > + Trim( "trim" ) , + IslandAreaRatio( "aRatio" , 0.001f ); +cmdLineReadable + PolygonMesh( "polygonMesh" ) , + Long( "long" ) , + Verbose( "verbose" ); + + +cmdLineReadable* params[] = +{ + &In , &Out , &Trim , &PolygonMesh , &Smooth , &IslandAreaRatio , &Verbose , &Long , + NULL +}; + +void ShowUsage( char* ex ) +{ + printf( "Usage: %s\n" , ex ); + printf( "\t --%s \n" , In.name ); + printf( "\t --%s \n" , Trim.name ); + printf( "\t[--%s ]\n" , Out.name ); + printf( "\t[--%s =%d]\n" , Smooth.name , Smooth.value ); + printf( "\t[--%s =%f]\n" , IslandAreaRatio.name , IslandAreaRatio.value ); + printf( "\t[--%s]\n" , PolygonMesh.name ); + printf( "\t[--%s]\n" , Long.name ); + printf( "\t[--%s]\n" , Verbose.name ); +} + +template< typename Index > +struct EdgeKey +{ + Index key1 , key2; + EdgeKey( Index k1=0 , Index k2=0 ) : key1(k1) , key2(k2) {} + 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 +}; + +template< typename Real , typename ... VertexData > +PlyVertexWithData< float , DIMENSION , MultiPointStreamData< float , PointStreamValue< float > , VertexData ... > > InterpolateVertices( const PlyVertexWithData< float , DIMENSION , MultiPointStreamData< float , PointStreamValue< float > , VertexData ... > >& v1 , const PlyVertexWithData< float , DIMENSION , MultiPointStreamData< float , PointStreamValue< float > , VertexData ... > >& v2 , Real value ) +{ + if( v1.data.template data<0>()==v2.data.template data<0>() ) return (v1+v2)/Real(2.); + Real dx = ( v1.data.template data<0>()-value ) / ( v1.data.template data<0>()-v2.data.template data<0>() ); + return v1*(1.f-dx) + v2*dx; +} + +template< typename Real , typename Index , typename ... VertexData > +void SmoothValues( std::vector< PlyVertexWithData< float , DIMENSION , MultiPointStreamData< float , PointStreamValue< float > , VertexData ... > > >& 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].data.template data<0>(); + } + } + for( size_t i=0 ; i() = ( sums[i] + vertices[i].data.template data<0>() ) / ( count[i] + 1 ); +} + +template< class Real , typename Index , typename ... VertexData > +void SplitPolygon +( + const std::vector< Index >& polygon , + std::vector< PlyVertexWithData< float , DIMENSION , MultiPointStreamData< float , PointStreamValue< float > , VertexData ... > > >& vertices , + std::vector< std::vector< Index > >* ltPolygons , std::vector< std::vector< Index > >* gtPolygons , + std::vector< bool >* ltFlags , std::vector< bool >* gtFlags , + std::unordered_map< EdgeKey< Index > , Index , typename EdgeKey< Index >::Hasher >& vertexTable, + Real trimValue +) +{ + int sz = int( polygon.size() ); + std::vector< bool > gt( sz ); + int gtCount = 0; + for( int j=0 ; j()>trimValue ); + if( gt[j] ) gtCount++; + } + if ( gtCount==sz ){ if( gtPolygons ) gtPolygons->push_back( polygon ) ; if( gtFlags ) gtFlags->push_back( false ); } + else if( gtCount==0 ){ if( ltPolygons ) ltPolygons->push_back( polygon ) ; if( ltFlags ) ltFlags->push_back( false ); } + else + { + int start; + for( start=0 ; start poly; + + // Add the initial vertex + { + int j1 = (start+int(sz)-1)%sz , j2 = start; + Index v1 = polygon[j1] , v2 = polygon[j2] , vIdx; + typename std::unordered_map< EdgeKey< Index > , Index , typename EdgeKey< Index >::Hasher >::iterator iter = vertexTable.find( EdgeKey< Index >(v1,v2) ); + if( iter==vertexTable.end() ) + { + vertexTable[ EdgeKey< Index >(v1,v2) ] = vIdx = (Index)vertices.size(); + vertices.push_back( InterpolateVertices( vertices[v1] , vertices[v2] , trimValue ) ); + } + else vIdx = iter->second; + poly.push_back( vIdx ); + } + + for( int _j=0 ; _j<=sz ; _j++ ) + { + int j1 = (_j+start+sz-1)%sz , j2 = (_j+start)%sz; + Index v1 = polygon[j1] , v2 = polygon[j2]; + if( gt[j2]==gtFlag ) poly.push_back( v2 ); + else + { + Index vIdx; + typename std::unordered_map< EdgeKey< Index > , Index , typename EdgeKey< Index >::Hasher >::iterator iter = vertexTable.find( EdgeKey< Index >(v1,v2) ); + if( iter==vertexTable.end() ) + { + vertexTable[ EdgeKey< Index >(v1,v2) ] = vIdx = (Index)vertices.size(); + vertices.push_back( InterpolateVertices( vertices[v1] , vertices[v2] , trimValue ) ); + } + else vIdx = iter->second; + poly.push_back( vIdx ); + if( gtFlag ){ if( gtPolygons ) gtPolygons->push_back( poly ) ; if( ltFlags ) ltFlags->push_back( true ); } + else { if( ltPolygons ) ltPolygons->push_back( poly ) ; if( gtFlags ) gtFlags->push_back( true ); } + poly.clear() , poly.push_back( vIdx ) , poly.push_back( v2 ); + gtFlag = !gtFlag; + } + } + } +} + +template< class Real , typename Index , class Vertex > +void Triangulate( const std::vector< Vertex >& vertices , const std::vector< std::vector< Index > >& polygons , std::vector< std::vector< Index > >& triangles ) +{ + triangles.clear(); + for( size_t i=0 ; i3 ) + { + std::vector< Point< Real , DIMENSION > > _vertices( polygons[i].size() ); + for( int j=0 ; j > _triangles = MinimalAreaTriangulation< Index , Real , DIMENSION >( ( ConstPointer( Point< Real , DIMENSION > ) )GetPointer( _vertices ) , _vertices.size() ); + + // Add the triangles to the mesh + size_t idx = triangles.size(); + triangles.resize( idx+_triangles.size() ); + for( int j=0 ; j +double PolygonArea( const std::vector< Vertex >& vertices , const std::vector< Index >& polygon ) +{ + if( polygon.size()<3 ) return 0.; + else if( polygon.size()==3 ) return Area( vertices[polygon[0]].point , vertices[polygon[1]].point , vertices[polygon[2]].point ); + else + { + Point< Real , DIMENSION > center; + for( size_t i=0 ; i +void RemoveHangingVertices( std::vector< Vertex >& vertices , std::vector< std::vector< Index > >& polygons ) +{ + std::unordered_map< Index, Index > vMap; + std::vector< bool > vertexFlags( vertices.size() , false ); + for( size_t i=0 ; i _vertices( vCount ); + for( Index i=0 ; i<(Index)vertices.size() ; i++ ) if( vertexFlags[i] ) _vertices[ vMap[i] ] = vertices[i]; + vertices = _vertices; +} + +template< typename Index > +void SetConnectedComponents( const std::vector< std::vector< Index > >& polygons , std::vector< std::vector< Index > >& components ) +{ + std::vector< Index > polygonRoots( polygons.size() ); + for( size_t i=0 ; i , Index , typename EdgeKey< Index >::Hasher > edgeTable; + for( size_t i=0 ; i eKey = EdgeKey< Index >(v1,v2); + typename std::unordered_map< EdgeKey< Index > , Index , typename EdgeKey< Index >::Hasher >::iterator iter = edgeTable.find(eKey); + if( iter==edgeTable.end() ) edgeTable[ eKey ] = (Index)i; + else + { + Index p = iter->second; + while( polygonRoots[p]!=p ) + { + Index temp = polygonRoots[p]; + polygonRoots[p] = (Index)i; + p = temp; + } + polygonRoots[p] = (Index)i; + } + } + } + for( size_t i=0 ; i vMap; + for( Index i=0 ; i<(Index)polygonRoots.size() ; i++ ) if( polygonRoots[i]==i ) vMap[i] = cCount++; + components.resize( cCount ); + for( Index i=0 ; i<(Index)polygonRoots.size() ; i++ ) components[ vMap[ polygonRoots[i] ] ].push_back(i); +} + +template< typename Index , typename ... VertexData > +int Execute( void ) +{ + typedef PlyVertexWithData< float , DIMENSION , MultiPointStreamData< float , PointStreamValue< float > , VertexData ... > > Vertex; + float min , max; + std::vector< Vertex > vertices; + std::vector< std::vector< Index > > polygons; + + int ft; + std::vector< std::string > comments; + PlyReadPolygons< Vertex >( In.value , vertices , polygons , Vertex::PlyReadProperties() , Vertex::PlyReadNum , ft , comments ); + + for( int i=0 ; i( vertices , polygons ); + min = max = vertices[0].data.template data<0>(); + for( size_t i=0 ; i( min , vertices[i].data.template data<0>() ) , max = std::max< float >( max , vertices[i].data.template data<0>() ); + + std::unordered_map< EdgeKey< Index > , Index , typename EdgeKey< Index >::Hasher > vertexTable; + 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" ); + 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 ) printf( "Value Range: [%f,%f]\n" , min , max ); + + double t=Time(); + for( size_t i=0 ; i0 ) + { + std::vector< std::vector< Index > > _ltPolygons , _gtPolygons; + std::vector< std::vector< Index > > ltComponents , gtComponents; + SetConnectedComponents( ltPolygons , ltComponents ); + SetConnectedComponents( gtPolygons , gtComponents ); + std::vector< double > ltAreas( ltComponents.size() , 0. ) , gtAreas( gtComponents.size() , 0. ); + std::vector< bool > ltComponentFlags( ltComponents.size() , false ) , gtComponentFlags( gtComponents.size() , false ); + double area = 0.; + for( size_t i=0 ; i( vertices , ltPolygons[ ltComponents[i][j] ] ); + ltComponentFlags[i] = ( ltComponentFlags[i] || ltFlags[ ltComponents[i][j] ] ); + } + area += ltAreas[i]; + } + for( size_t i=0 ; i( vertices , gtPolygons[ gtComponents[i][j] ] ); + gtComponentFlags[i] = ( gtComponentFlags[i] || gtFlags[ gtComponents[i][j] ] ); + } + area += gtAreas[i]; + } + for( size_t i=0 ; i > polys = ltPolygons; + Triangulate< float , Index , Vertex >( vertices , ltPolygons , polys ) , ltPolygons = polys; + } + { + std::vector< std::vector< Index > > polys = gtPolygons; + Triangulate< float , Index , Vertex >( vertices , gtPolygons , polys ) , gtPolygons = polys; + } + } + + RemoveHangingVertices( vertices , gtPolygons ); + char comment[1024]; + sprintf( comment , "#Trimmed In: %9.1f (s)" , Time()-t ); + comments.push_back( comment ); + if( Out.set ) + if( !PlyWritePolygons< Vertex >( Out.value , vertices , gtPolygons , Vertex::PlyWriteProperties() , Vertex::PlyWriteNum , ft , comments ) ) + ERROR_OUT( "Could not write mesh to: " , Out.value ); + + return EXIT_SUCCESS; +} +int main( int argc , char* argv[] ) +{ + cmdLineParse( argc-1 , &argv[1] , params ); + messageWriter.echoSTDOUT = Verbose.set; + + if( !In.set || !Trim.set ) + { + ShowUsage( argv[0] ); + return EXIT_FAILURE; + } + typedef MultiPointStreamData< float , PointStreamValue< float > , PointStreamNormal< float , DIMENSION > , PointStreamColor< float > > VertexData; + typedef PlyVertexWithData< float , DIMENSION , VertexData > Vertex; + bool readFlags[ Vertex::PlyReadNum ]; + if( !PlyReadHeader( In.value , Vertex::PlyReadProperties() , Vertex::PlyReadNum , readFlags ) ) ERROR_OUT( "Failed to read ply header: " , In.value ); + + bool hasValue = VertexData::ValidPlyReadProperties< 0 >( readFlags + DIMENSION ); + bool hasNormal = VertexData::ValidPlyReadProperties< 1 >( readFlags + DIMENSION ); + bool hasColor = VertexData::ValidPlyReadProperties< 2 >( readFlags + DIMENSION ); + + if( !hasValue ) ERROR_OUT( "Ply file does not contain values" ); + + if( Long.set ) + if( hasColor ) + if( hasNormal ) return Execute< long long , PointStreamNormal< float , DIMENSION > , PointStreamColor< float > >(); + else return Execute< long long , PointStreamColor< float > >(); + else + if( hasNormal ) return Execute< long long , PointStreamNormal< float , DIMENSION > >(); + else return Execute< long long >(); + else + if( hasColor ) + if( hasNormal ) return Execute< int , PointStreamNormal< float , DIMENSION > , PointStreamColor< float > >(); + else return Execute< int , PointStreamColor< float > >(); + else + if( hasNormal ) return Execute< int , PointStreamNormal< float , DIMENSION > >(); + else return Execute< int >(); +} diff --git a/apps/VoxelCompare/CMakeLists.txt b/apps/VoxelCompare/CMakeLists.txt new file mode 100644 index 00000000..42963a30 --- /dev/null +++ b/apps/VoxelCompare/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.7) + +project(VoxelCompare) + +set(PROJECT_SRCS ${PROJECT_SOURCE_DIR}/src/VoxelCompare.cpp) + +source_group("src" FILES ${PROJECT_SRCS}) + +add_executable(${PROJECT_NAME} ${PROJECT_SRCS}) + +target_link_libraries(${PROJECT_NAME} PoissonRecon) + +set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER ${CMAKE_PROJECT_NAME}/apps) + +install(TARGETS ${PROJECT_NAME} EXPORT ${CMAKE_PROJECT_NAME}Targets DESTINATION + bin) diff --git a/apps/VoxelCompare/src/VoxelCompare.cpp b/apps/VoxelCompare/src/VoxelCompare.cpp new file mode 100644 index 00000000..54a564df --- /dev/null +++ b/apps/VoxelCompare/src/VoxelCompare.cpp @@ -0,0 +1,153 @@ +/* +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. +*/ + +#undef FAST_COMPILE // If enabled, only a single version of the reconstruction + // code is compiled +#undef ARRAY_DEBUG // If enabled, array access is tested for validity +#define MAX_MEMORY_GB \ + 15 // If non-zero, the maximum memory to be used by the application + +#include +#include +#include +#include +#include "Mesh/PoissonRecon/MyMiscellany.h" + +#include "Mesh/PoissonRecon/CmdLineParser.h" + +#include "Mesh/PoissonRecon/Array.h" + +cmdLineParameterArray In("in"); +cmdLineParameter Out("out"); +cmdLineParameter Scale("scale", 1.f); + +cmdLineReadable* params[] = {&In, &Out, &Scale, 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); +} + +int main(int argc, char* argv[]) +{ + cmdLineParse(argc - 1, &argv[1], params); + if (!In.set) + { + ShowUsage(argv[0]); + return EXIT_FAILURE; + } + + auto ReadVoxel = [](const char* fileName, int& res) { + FILE* fp = fopen(fileName, "rb"); + if (!fp) + fprintf(stderr, "[ERROR] Failed to read voxel: %s\n", fileName), exit(0); + if (fread(&res, sizeof(int), 1, fp) != 1) + fprintf(stderr, + "[ERROR] Failed to read restolution from file: %s\n", + fileName), + exit(0); + Pointer(float) v = AllocPointer(res * res * res); + if (!v) + fprintf(stderr, + "[ERROR] Failed to allocate voxel grid: %d x %d x %d\n", + res, + res, + res), + exit(0); + if (fread(v, sizeof(float), res * res * res, fp) != res * res * res) + fprintf(stderr, + "[ERROR] Failed to read voxel values from file: %s\n", + fileName), + exit(0); + fclose(fp); + return v; + }; + + int res; + Pointer(float) v1; + Pointer(float) v2; + { + int res1, res2; + v1 = ReadVoxel(In.values[0], res1); + v2 = ReadVoxel(In.values[1], res2); + if (res1 != res2) + fprintf(stderr, + "[ERROR] Voxel resolutions don't match: %d x %d\n", + res1, + res2), + exit(0); + res = res1; + } + + double l1Error = 0, l2Error = 0; + double l1Norm1 = 0, l1Norm2 = 0, l2Norm1 = 0, l2Norm2 = 0; +#pragma omp parallel for reduction ( + : l1Error , l2Error , l1Norm1 , l1Norm2 , l2Norm1 , l2Norm2 ) + for (int i = 0; i < res * res * res; i++) + { + l1Error += fabs(v1[i] - v2[i]), l1Norm1 += fabs(v1[i]), + l1Norm2 += fabs(v2[i]); + l2Error += (v1[i] - v2[i]) * (v1[i] - v2[i]), l2Norm1 += v1[i] * v1[i], + l2Norm2 += v2[i] * v2[i]; + } + l1Error /= res * res * res, l1Norm1 /= res * res * res, + l1Norm2 /= res * res * res; + l2Error /= res * res * res, l2Norm1 /= res * res * res, + l2Norm2 /= res * res * res; + l2Error = sqrt(l2Error), l2Norm1 = sqrt(l2Norm1), l2Norm2 = sqrt(l2Norm2); + printf("L1 / L2 differences: %g %g\n", + 2 * l1Error / (l1Norm1 + l1Norm2), + 2 * l2Error / (l2Norm1 + l2Norm2)); + + if (Out.set) + { + if (Scale.value < 0) Scale.value = 1. / ((l1Norm1 + l1Norm2) / 2); +#pragma omp parallel for + for (int i = 0; i < res * res * res; i++) + v1[i] = (v1[i] - v2[i]) * Scale.value; + + FILE* fp = fopen(Out.value, "wb"); + if (!fp) + fprintf( + stderr, "[ERROR] Failed to open file for writing: %s\n", Out.value), + exit(0); + + if (fwrite(&res, sizeof(int), 1, fp) != 1) + fprintf(stderr, "[ERROR] Failed to write voxel resolution\n"), fclose(fp), + exit(0); + fwrite(v1, sizeof(float), res * res * res, fp); + fclose(fp); + } + FreePointer(v1); + FreePointer(v2); + + return EXIT_SUCCESS; +} diff --git a/cmake_uninstall.cmake.in b/cmake_uninstall.cmake.in new file mode 100644 index 00000000..d00a5166 --- /dev/null +++ b/cmake_uninstall.cmake.in @@ -0,0 +1,26 @@ +if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") +endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +if (NOT DEFINED CMAKE_INSTALL_PREFIX) + set (CMAKE_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@") +endif () + message(${CMAKE_INSTALL_PREFIX}) + +file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +string(REGEX REPLACE "\n" ";" files "${files}") +foreach(file ${files}) + message(STATUS "Uninstalling $ENV{DESTDIR}${file}") + if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + exec_program( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + if(NOT "${rm_retval}" STREQUAL 0) + message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") + endif(NOT "${rm_retval}" STREQUAL 0) + else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + message(STATUS "File $ENV{DESTDIR}${file} does not exist.") + endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") +endforeach(file) diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt new file mode 100644 index 00000000..8cce17d3 --- /dev/null +++ b/modules/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.7) +project(modules) + +add_subdirectory(PoissonRecon) diff --git a/modules/PoissonRecon/CMakeLists.txt b/modules/PoissonRecon/CMakeLists.txt new file mode 100644 index 00000000..a5946867 --- /dev/null +++ b/modules/PoissonRecon/CMakeLists.txt @@ -0,0 +1,146 @@ +cmake_minimum_required(VERSION 3.7) +project(PoissonRecon) + +set(PROJECT_INCS + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/Allocator.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/Array.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/Array.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/BinaryNode.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/BlockedVector.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/BMPStream.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/BSplineData.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/BSplineData.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/CmdLineParser.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/CmdLineParser.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/Factor.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/FEMTree.Evaluation.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/FEMTree.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/FEMTree.Initialize.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/FEMTree.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/FEMTree.IsoSurface.specialized.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/FEMTree.SortedTreeNodes.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/FEMTree.System.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/FEMTree.WeightedSamples.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/FunctionData.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/FunctionData.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/Geometry.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/Geometry.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/Image.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/JPEG.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/JPEG.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/LinearSolvers.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/MarchingCubes.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/MAT.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/MAT.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/MyMiscellany.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/Ply.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/PlyFile.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/PlyFile.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/PNG.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/PNG.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/PointStream.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/PointStream.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/PointStreamData.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/PoissonRecon.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/Polynomial.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/Polynomial.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/PPolynomial.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/PPolynomial.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/PreProcessor.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/RegularTree.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/RegularTree.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/SparseMatrix.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/SparseMatrix.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/SparseMatrixInterface.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/SparseMatrixInterface.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/SurfaceTrimmer.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/Window.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/Window.inl) + +source_group("include" FILES ${PROJECT_INCS}) + +find_package(PNG REQUIRED) +find_package(JPEG REQUIRED) + +add_library(${PROJECT_NAME} ${PROJECT_INCS}) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX) + +target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_11) + +target_include_directories( + ${PROJECT_NAME} PUBLIC $ + $) + +target_link_libraries(${PROJECT_NAME} JPEG::JPEG PNG::PNG) + +set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER + ${CMAKE_PROJECT_NAME}/modules) + +install(TARGETS ${PROJECT_NAME} EXPORT ${CMAKE_PROJECT_NAME}Targets + ARCHIVE DESTINATION lib LIBRARY DESTINATION lib RUNTIME DESTINATION bin) + +install( + FILES + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/Allocator.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/Array.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/Array.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/BinaryNode.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/BlockedVector.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/BMPStream.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/BSplineData.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/BSplineData.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/CmdLineParser.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/CmdLineParser.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/Factor.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/FEMTree.Evaluation.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/FEMTree.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/FEMTree.Initialize.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/FEMTree.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/FEMTree.IsoSurface.specialized.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/FEMTree.SortedTreeNodes.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/FEMTree.System.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/FEMTree.WeightedSamples.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/FunctionData.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/FunctionData.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/Geometry.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/Geometry.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/Image.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/JPEG.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/JPEG.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/LinearSolvers.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/MarchingCubes.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/MAT.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/MAT.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/MyMiscellany.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/Ply.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/PlyFile.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/PlyFile.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/PNG.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/PNG.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/PointStream.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/PointStream.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/PointStreamData.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/PoissonRecon.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/Polynomial.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/Polynomial.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/PPolynomial.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/PPolynomial.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/PreProcessor.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/RegularTree.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/RegularTree.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/SparseMatrix.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/SparseMatrix.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/SparseMatrixInterface.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/SparseMatrixInterface.inl + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/SurfaceTrimmer.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/Window.h + ${PROJECT_SOURCE_DIR}/include/Mesh/PoissonRecon/Window.inl + DESTINATION include/Mesh/PoissonRecon) + +export(TARGETS ${PROJECT_NAME} APPEND + FILE ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake) + +file(APPEND ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Config.cmake + "set(POISSONRECON_LIBRARIES \${POISSONRECON_LIBRARIES} ${PROJECT_NAME})\n" + "find_dependency(PNG REQUIRED)\n" "find_dependency(JPEG REQUIRED)\n") diff --git a/Src/Allocator.h b/modules/PoissonRecon/include/Mesh/PoissonRecon/Allocator.h similarity index 65% rename from Src/Allocator.h rename to modules/PoissonRecon/include/Mesh/PoissonRecon/Allocator.h index 3ba23d9d..651c78e0 100644 --- a/Src/Allocator.h +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/Allocator.h @@ -28,14 +28,14 @@ DAMAGE. #ifndef ALLOCATOR_INCLUDED #define ALLOCATOR_INCLUDED - #include -class AllocatorState +struct AllocatorState { -public: - int index , remains; + 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 @@ -44,96 +44,92 @@ class AllocatorState * 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 +template< class T > class Allocator { - int blockSize; - int index , remains; - std::vector< T* > memory; + size_t _blockSize; + AllocatorState _state; + std::vector< T* > _memory; public: - Allocator( void ){ blockSize = index = remains = 0; } + 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 ) { - for( size_t i=0 ; iblockSize = blockSize; - index=-1; - remains=0; + _blockSize = blockSize; + _state.index = -1; + _state.remains = 0; } /** This method returns a pointer to an array of elements objects. If there is left over pre-allocated @@ -141,24 +137,24 @@ class Allocator * more memory. Note that if the number of objects requested is larger than the value blockSize with which * the allocator was initialized, the request for memory will fail. */ - T* newElements( int elements=1 ) + T* newElements( size_t elements=1 ) { T* mem; if( !elements ) return NULL; - if( elements>blockSize ) fprintf( stderr , "[ERROR] Allocator: elements bigger than block-size: %d>%d\n" , elements , blockSize ) , exit( 0 ); - if( remains_blockSize ) ERROR_OUT( "elements bigger than block-size: " , elements , " > " , _blockSize ); + if( _state.remains #define ConstPointer( ... ) ConstArray< __VA_ARGS__ > #define NullPointer( ... ) Array< __VA_ARGS__ >() @@ -79,8 +81,10 @@ template< class C > ConstArray< C > GetPointer( const C& c ) { return ConstArray template< class C > Array< C > GetPointer( std::vector< C >& v ){ return Array< C >::FromPointer( &v[0] , v.size() ); } template< class C > ConstArray< C > GetPointer( const std::vector< C >& v ){ return ConstArray< C >::FromPointer( &v[0] , v.size() ); } -template< class C > Array< C > GetPointer( C* c , int sz ) { return Array< C >::FromPointer( c , sz ); } -template< class C > ConstArray< C > GetPointer( const C* c , int sz ) { return ConstArray< C >::FromPointer( c , sz ); } +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__* @@ -105,8 +109,9 @@ template< class C > const C* GetPointer( const C& c ){ return &c; } template< class C > C* GetPointer( std::vector< C >& v ){ return &v[0]; } template< class C > const C* GetPointer( const std::vector< C >& v ){ return &v[0]; } -template< class C > C* GetPointer( C* c , int sz ) { return c; } -template< class C > const C* GetPointer( const C* c , int sz ) { return c; } - +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/modules/PoissonRecon/include/Mesh/PoissonRecon/Array.inl b/modules/PoissonRecon/include/Mesh/PoissonRecon/Array.inl new file mode 100644 index 00000000..528b3052 --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/Array.inl @@ -0,0 +1,434 @@ +/* +Copyright (c) 2011, Michael Kazhdan and Ming Chuang +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +#include +#include +#include +#include +#ifdef _WIN32 +#include +#endif // _WIN32 +#include +#include +#include + +template< class C > +class Array +{ + template< class D > friend class Array; + void _assertBounds( std::ptrdiff_t idx ) const + { + if( idx=max ) + { + StackTracer::Trace(); + ERROR_OUT( "Array index out-of-bounds: " , min , " <= " , idx , " < " , max ); + } + } +protected: + C *data , *_data; + std::ptrdiff_t min , max; + +public: + std::ptrdiff_t minimum( void ) const { return min; } + std::ptrdiff_t maximum( void ) const { return max; } + + static inline Array New( size_t size , const char* name=NULL ) + { + Array a; + a._data = a.data = new C[size]; + a.min = 0; +#ifdef SHOW_WARNINGS +#pragma message( "[WARNING] Casting unsigned to signed" ) +#endif // SHOW_WARNINGS + a.max = (std::ptrdiff_t)size; + return a; + } + static inline Array Alloc( size_t size , bool clear , const char* name=NULL ) + { + Array a; + a._data = a.data = ( C* ) malloc( size * sizeof( C ) ); + if( clear ) memset( a.data , 0 , size * sizeof( C ) ); + a.min = 0; +#ifdef SHOW_WARNINGS +#pragma message( "[WARNING] Casting unsigned to signed" ) +#endif // SHOW_WARNINGS + a.max = (std::ptrdiff_t)size; + return a; + } + + static inline Array AlignedAlloc( size_t size , size_t alignment , bool clear , const char* name=NULL ) + { + Array a; + a.data = ( C* ) aligned_malloc( sizeof(C) * size , alignment ); + a._data = ( C* )( ( ( void** )a.data )[-1] ); + if( clear ) memset( a.data , 0 , size * sizeof( C ) ); + a.min = 0; +#ifdef SHOW_WARNINGS +#pragma message( "[WARNING] Casting unsigned to signed" ) +#endif // SHOW_WARNINGS + a.max = (std::ptrdiff_t)size; + return a; + } + + static inline Array ReAlloc( Array& a , size_t size , bool clear , const char* name=NULL ) + { + Array _a; + _a._data = _a.data = ( C* ) realloc( a.data , size * sizeof( C ) ); + if( clear ) memset( _a.data , 0 , size * sizeof( C ) ); + a._data = NULL; + _a.min = 0; +#ifdef SHOW_WARNINGS +#pragma message( "[WARNING] Casting unsigned to signed" ) +#endif // SHOW_WARNINGS + _a.max = (std::ptrdiff_t)size; + return _a; + } + + Array( void ) + { + data = _data = NULL; + min = max = 0; + } + template< class D > + Array( Array< D >& a ) + { + _data = NULL; + if( !a ) + { + data = NULL; + min = max = 0; + } + else + { + // [WARNING] Changing szC and szD to size_t causes some really strange behavior. + std::ptrdiff_t szC = (std::ptrdiff_t)sizeof( C ); + std::ptrdiff_t szD = (std::ptrdiff_t)sizeof( D ); + data = (C*)a.data; + min = ( a.minimum() * szD ) / szC; + max = ( a.maximum() * szD ) / szC; + if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD ) ERROR_OUT( "Could not convert array [ " , a.minimum() , " , " , a.maximum() , " ] * " , szD , " => [ " , min , " , " , max , " ] * " , szC ); + } + } + static Array FromPointer( C* data , std::ptrdiff_t max ) + { + Array a; + a._data = NULL; + a.data = data; + a.min = 0; + a.max = max; + return a; + } + static Array FromPointer( C* data , std::ptrdiff_t min , std::ptrdiff_t max ) + { + Array a; + a._data = NULL; + a.data = data; + a.min = min; + a.max = max; + return a; + } + inline bool operator == ( const Array< C >& a ) const { return data==a.data; } + inline bool operator != ( const Array< C >& a ) const { return data!=a.data; } + inline bool operator == ( const C* c ) const { return data==c; } + inline bool operator != ( const C* c ) const { return data!=c; } + inline C* operator -> ( void ) + { + _assertBounds( 0 ); + return data; + } + inline const C* operator -> ( void ) const + { + _assertBounds( 0 ); + return data; + } + inline C &operator * ( void ) + { + _assertBounds( 0 ); + return data[0]; + } + inline const C &operator * ( void ) const + { + _assertBounds( 0 ); + return data[0]; + } + template< typename Int > + inline C& operator[]( Int idx ) + { + static_assert( std::is_integral< Int >::value , "Integral type expected" ); + _assertBounds( idx ); + return data[idx]; + } + + template< typename Int > + inline const C& operator[]( Int idx ) const + { + static_assert( std::is_integral< Int >::value , "Integral type expected" ); + _assertBounds( idx ); + return data[idx]; + } + + template< typename Int > + inline Array operator + ( Int idx ) const + { + static_assert( std::is_integral< Int >::value , "Integral type expected" ); + Array a; + a._data = _data; + a.data = data+idx; + a.min = min-idx; + a.max = max-idx; + return a; + } + template< typename Int > + inline Array& operator += ( Int idx ) + { + static_assert( std::is_integral< Int >::value , "Integral type expected" ); + min -= idx; + max -= idx; + data += idx; + return (*this); + } + template< typename Int > Array operator - ( Int idx ) const { return (*this) + (-idx); } + template< typename Int > Array& operator -= ( Int idx ) { return (*this) += (-idx); } + + inline Array& operator ++ ( void ) { return (*this) += 1; } + inline Array operator++( int ){ Array< C > temp = (*this) ; (*this) +=1 ; return temp; } + inline Array operator--( int ){ Array< C > temp = (*this) ; (*this) -=1 ; return temp; } + std::ptrdiff_t operator - ( const Array& a ) const { return data - a.data; } + + void Free( void ) + { + if( _data ) + { + free( _data ); + } + (*this) = Array( ); + } + void Delete( void ) + { + if( _data ) + { + delete[] _data; + } + (*this) = Array( ); + } + C* pointer( void ){ return data; } + const C* pointer( void ) const { return data; } + bool operator !( void ) const { return data==NULL; } + operator bool( ) const { return data!=NULL; } +}; + +template< class C > +class ConstArray +{ + 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 ); + } +protected: + const C *data; + std::ptrdiff_t min , max; +public: + std::ptrdiff_t minimum( void ) const { return min; } + std::ptrdiff_t maximum( void ) const { return max; } + + inline ConstArray( void ) + { + data = NULL; + min = max = 0; + } + inline ConstArray( const Array< C >& a ) + { + // [WARNING] Changing szC and szD to size_t causes some really strange behavior. + data = ( const C* )a.pointer( ); + min = a.minimum(); + max = a.maximum(); + } + template< class D > + inline ConstArray( const Array< D >& a ) + { + // [WARNING] Changing szC and szD to size_t causes some really strange behavior. + std::ptrdiff_t szC = (std::ptrdiff_t)sizeof( C ); + std::ptrdiff_t szD = (std::ptrdiff_t)sizeof( D ); + data = ( const C* )a.pointer( ); + min = ( a.minimum() * szD ) / szC; + max = ( a.maximum() * szD ) / szC; + if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD ) ERROR_OUT( "Could not convert const array [ " , a.minimum() , " , " , a.maximum() , " ] * " , szD , " => [ " , min , " , " , max , " ] * " , szC ); + } + template< class D > + inline ConstArray( const 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 ); + std::ptrdiff_t szD = (std::ptrdiff_t)sizeof( D ); + data = ( const C*)a.pointer( ); + min = ( a.minimum() * szD ) / szC; + max = ( a.maximum() * szD ) / szC; + if( min*szC!=a.minimum()*szD || max*szC!=a.maximum()*szD ) ERROR_OUT( "Could not convert array [ " , a.minimum() , " , " , a.maximum() , " ] * " , szD , " => [ " , min , " , " , max , " ] * " , szC ); + } + static ConstArray FromPointer( const C* data , std::ptrdiff_t max ) + { + ConstArray a; + a.data = data; + a.min = 0; + a.max = max; + return a; + } + + static ConstArray FromPointer( const C* data , std::ptrdiff_t min , std::ptrdiff_t max ) + { + ConstArray a; + a.data = data; + a.min = min; + a.max = max; + return a; + } + + inline bool operator == ( const ConstArray< C >& a ) const { return data==a.data; } + inline bool operator != ( const ConstArray< C >& a ) const { return data!=a.data; } + inline bool operator == ( const C* c ) const { return data==c; } + inline bool operator != ( const C* c ) const { return data!=c; } + inline const C* operator -> ( void ) + { + _assertBounds( 0 ); + return data; + } + inline const C &operator * ( void ) + { + _assertBounds( 0 ); + return data[0]; + } + template< typename Int > + inline const C& operator[]( Int idx ) const + { + static_assert( std::is_integral< Int >::value , "Integral type expected" ); + _assertBounds( idx ); + return data[idx]; + } + template< typename Int > + inline ConstArray operator + ( Int idx ) const + { + static_assert( std::is_integral< Int >::value , "Integral type expected" ); + ConstArray a; + a.data = data+idx; + a.min = min-idx; + a.max = max-idx; + return a; + } + template< typename Int > + inline ConstArray& operator += ( Int idx ) + { + static_assert( std::is_integral< Int >::value , "Integral type expected" ); + min -= idx; + max -= idx; + data += idx; + return (*this); + } + template< typename Int > ConstArray operator - ( Int idx ) const { return (*this) + (-idx); } + template< typename Int > ConstArray& operator -= ( Int idx ) { return (*this) += (-idx); } + inline ConstArray& operator ++ ( void ) { return (*this) += 1; } + inline ConstArray operator++( int ){ ConstArray< C > temp = (*this) ; (*this) +=1 ; return temp; } + inline ConstArray operator--( int ){ ConstArray< C > temp = (*this) ; (*this) -=1 ; return temp; } + std::ptrdiff_t operator - ( const ConstArray& a ) const { return data - a.data; } + 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; } +}; + +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 ) 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 ) 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 ) 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 ) 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 ) 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 ) memset( &destination[0] , value , size ); + return destination; +} + +template< class C > +size_t fread( Array< C > destination , size_t eSize , size_t count , FILE* fp ) +{ + if( count*eSize>destination.maximum()*sizeof( C ) ) ERROR_OUT( "Size of read exceeds source maximum: " , count*eSize , " > " , destination.maximum()*sizeof( C ) ); + return fread( &destination[0] , eSize , count , fp ); +} +template< class C > +size_t fwrite( Array< C > source , size_t eSize , size_t count , FILE* fp ) +{ + if( count*eSize>source.maximum()*sizeof( C ) ) ERROR_OUT( "Size of write exceeds source maximum: " , count*eSize , " > " , source.maximum()*sizeof( C ) ); + return fwrite( &source[0] , eSize , count , fp ); +} +template< class C > +size_t fwrite( ConstArray< C > source , size_t eSize , size_t count , FILE* fp ) +{ + if( count*eSize>source.maximum()*sizeof( C ) ) ERROR_OUT( "Size of write exceeds source maximum: " , count*eSize , " > " , source.maximum()*sizeof( C ) ); + return fwrite( &source[0] , eSize , count , fp ); +} +template< class C > +void qsort( Array< C > base , size_t numElements , size_t elementSize , int (*compareFunction)( const void* , const void* ) ) +{ + if( sizeof(C)!=elementSize ) ERROR_OUT( "Element sizes differ: " , sizeof(C) , " != " , elementSize ); + if( base.minimum()>0 || base.maximum() +#include "Mesh/PoissonRecon/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/modules/PoissonRecon/include/Mesh/PoissonRecon/BSplineData.h similarity index 53% rename from Src/BSplineData.h rename to modules/PoissonRecon/include/Mesh/PoissonRecon/BSplineData.h index 601253e7..69c4c9e1 100644 --- a/Src/BSplineData.h +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/BSplineData.h @@ -29,11 +29,11 @@ DAMAGE. #ifndef BSPLINE_DATA_INCLUDED #define BSPLINE_DATA_INCLUDED -#define NEW_BSPLINE_CODE +#include -#include "BinaryNode.h" -#include "PPolynomial.h" -#include "Array.h" +#include "Mesh/PoissonRecon/BinaryNode.h" +#include "Mesh/PoissonRecon/PPolynomial.h" +#include "Mesh/PoissonRecon/Array.h" enum BoundaryType { @@ -44,11 +44,37 @@ enum BoundaryType }; 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; }; -// This class represents a function that is a linear combination of B-spline elements. -// The coeff member indicating how much of each element is present. + +// 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< int Degree > +template< unsigned int Degree > struct BSplineElementCoefficients { int coeffs[Degree+1]; @@ -61,7 +87,7 @@ struct BSplineElementCoefficients // On each block, the function is a degree-Degree polynomial, represented by the coefficients // in the associated BSplineElementCoefficients. // [NOTE] This representation of a function is agnostic to the type of boundary conditions (though the constructor is not). -template< int Degree > +template< unsigned int Degree > struct BSplineElements : public std::vector< BSplineElementCoefficients< Degree > > { static const bool _Primal = (Degree&1)==1; @@ -110,12 +136,14 @@ struct BSplineElements : public std::vector< BSplineElementCoefficients< Degree return P.compress(0); } }; -template< int Degree , int DDegree > struct Differentiator { static void Differentiate( const BSplineElements< Degree >& bse , BSplineElements< DDegree >& dbse ); }; -template< int Degree > struct Differentiator< Degree , Degree >{ static void Differentiate( const BSplineElements< Degree >& bse , BSplineElements< Degree >& dbse ); }; + +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 ); }; + #define BSPLINE_SET_BOUNDS( name , s , e ) \ static const int name ## Start = (s); \ static const int name ## End = (e); \ - static const int name ## Size = (e)-(s)+1 + static const unsigned int name ## Size = (e)-(s)+1 // Assumes that x is non-negative #define _FLOOR_OF_HALF( x ) ( (x) >>1 ) @@ -128,13 +156,17 @@ template< int Degree > struct Differentiator< Degree , Degree >{ s #define SMALLEST_INTEGER_LARGER_THAN_OR_EQUAL_TO_HALF( x ) ( CEIL_OF_HALF( x ) ) #define LARGEST_INTEGER_SMALLER_THAN_OR_EQUAL_TO_HALF( x ) ( FLOOR_OF_HALF( x ) ) -template< int Degree > +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) | 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 ); + 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 ) @@ -161,19 +195,22 @@ struct BSplineSupportSizes // Which is the same as the smallest/largest integers J such that: // 2*J + (Degree+1+Inset) >= 0/1 + (Degree+1+Inset)/2 | 2*J - (Degree+1-Inset) <= 0/1 - (Degree+1-Inset)/2 // <=> 2*J >= 0/1 - (Degree+1+Inset)/2 | 2*J <= 0/1 + (Degree+1-Inset)/2 - BSPLINE_SET_BOUNDS( DownSample0 , SMALLEST_INTEGER_LARGER_THAN_OR_EQUAL_TO_HALF( 0 - ( Degree + 1 + Inset ) / 2 ) , LARGEST_INTEGER_SMALLER_THAN_OR_EQUAL_TO_HALF( 0 + ( Degree + 1 - Inset ) / 2 ) ); - BSPLINE_SET_BOUNDS( DownSample1 , SMALLEST_INTEGER_LARGER_THAN_OR_EQUAL_TO_HALF( 1 - ( Degree + 1 + Inset ) / 2 ) , LARGEST_INTEGER_SMALLER_THAN_OR_EQUAL_TO_HALF( 1 + ( Degree + 1 - Inset ) / 2 ) ); - static const int DownSampleStart[] , DownSampleEnd[] , DownSampleSize[]; + 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< int Degree > const int BSplineSupportSizes< Degree >::DownSampleStart[] = { DownSample0Start , DownSample1Start }; -template< int Degree > const int BSplineSupportSizes< Degree >::DownSampleEnd [] = { DownSample0End , DownSample1End }; -template< int Degree > const int BSplineSupportSizes< Degree >::DownSampleSize [] = { DownSample0Size , DownSample1Size }; - +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 }; -// Given a B-Spline of degree Degree1 at position i, this gives the offsets of the B-splines of degree Degree2 that just overlap with it. -template< int Degree1 , int Degree2 > +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 ); @@ -187,19 +224,42 @@ struct BSplineOverlapSizes // 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 ) ); + BSPLINE_SET_BOUNDS( ParentOverlap0 , SMALLEST_INTEGER_LARGER_THAN_HALF( 0 - ( 2*_Degree2 + _Degree1 + 3 + 2*EData2::Inset - EData1::Inset ) / 2 ) , LARGEST_INTEGER_SMALLER_THAN_HALF( 0 + ( 2*_Degree2 + _Degree1 + 3 - 2*EData2::Inset + EData1::Inset ) / 2 ) ); + BSPLINE_SET_BOUNDS( ParentOverlap1 , SMALLEST_INTEGER_LARGER_THAN_HALF( 1 - ( 2*_Degree2 + _Degree1 + 3 + 2*EData2::Inset - EData1::Inset ) / 2 ) , LARGEST_INTEGER_SMALLER_THAN_HALF( 1 + ( 2*_Degree2 + _Degree1 + 3 - 2*EData2::Inset + EData1::Inset ) / 2 ) ); static const int ParentOverlapStart[] , ParentOverlapEnd[] , ParentOverlapSize[]; }; -template< int Degree1 , int Degree2 > const int BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapStart[] = { ParentOverlap0Start , ParentOverlap1Start }; -template< int Degree1 , int Degree2 > const int BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapEnd [] = { ParentOverlap0End , ParentOverlap1End }; -template< int Degree1 , int Degree2 > const int BSplineOverlapSizes< Degree1 , Degree2 >::ParentOverlapSize [] = { ParentOverlap0Size , ParentOverlap1Size }; +template< 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< int Degree , BoundaryType BType > +struct EvaluationData +{ + struct CornerEvaluator + { + virtual double value( int fIdx , int cIdx , int d ) const = 0; + virtual void set( int depth ) = 0; + virtual ~CornerEvaluator( void ){} + }; + struct CenterEvaluator + { + 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 FEMSig > class BSplineEvaluationData { public: - static const int Pad = (BType==BOUNDARY_FREE ) ? BSplineSupportSizes< Degree >::SupportEnd : ( (Degree&1) && BType==BOUNDARY_DIRICHLET ) ? -1 : 0; + 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); } @@ -215,22 +275,9 @@ class BSplineEvaluationData 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 ); - // [NOTE] The offset represents the node position, not the index of the function - static double Value( int depth , int off , double s , bool derivative ); - - // Note that this struct stores the components in left-to-right order - struct BSplineComponents - { - protected: - Polynomial< Degree > _polys[Degree+1]; - public: - BSplineComponents( void ){ ; } - BSplineComponents( int depth , int offset ); - const Polynomial< Degree >& operator[] ( int idx ) const { return _polys[idx]; } - BSplineComponents derivative( void ) const; - void printnl( void ) const { for( int d=0 ; d<=Degree ; d++ ) printf( "[%d] " , d ) , _polys[d].printnl(); } - }; struct BSplineUpSamplingCoefficients { protected: @@ -241,119 +288,121 @@ class BSplineEvaluationData double operator[] ( int idx ){ return (double)_coefficients[idx] / (1< struct CenterEvaluator { - struct Evaluator + struct Evaluator : public EvaluationData::CenterEvaluator { protected: friend BSplineEvaluationData; int _depth; - double _ccValues[2][IndexSize][BSplineSupportSizes< Degree >::SupportSize]; + double _ccValues[D+1][IndexSize][BSplineSupportSizes< Degree >::SupportSize]; public: -#ifdef BRUNO_LEVY_FIX Evaluator( void ){ _depth = 0 ; memset( _ccValues , 0 , sizeof(_ccValues) ); } -#endif // BRUNO_LEVY_FIX - double value( int fIdx , int cIdx , bool d ) const; + 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 + struct ChildEvaluator : public EvaluationData::CenterEvaluator { protected: friend BSplineEvaluationData; int _parentDepth; - double _pcValues[2][IndexSize][BSplineSupportSizes< Degree >::ChildSupportSize]; + double _pcValues[D+1][IndexSize][BSplineSupportSizes< Degree >::ChildSupportSize]; public: -#ifdef BRUNO_LEVY_FIX ChildEvaluator( void ){ _parentDepth = 0 ; memset( _pcValues , 0 , sizeof(_pcValues) ); } -#endif // BRUNO_LEVY_FIX - double value( int fIdx , int cIdx , bool d ) const; + 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 ); } }; }; - static void SetCenterEvaluator( typename CenterEvaluator::Evaluator& evaluator , int depth ); - static void SetChildCenterEvaluator( typename CenterEvaluator::ChildEvaluator& evaluator , int 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 + struct Evaluator : public EvaluationData::CornerEvaluator { protected: friend BSplineEvaluationData; int _depth; - double _ccValues[2][IndexSize][BSplineSupportSizes< Degree >::CornerSize]; + double _ccValues[D+1][IndexSize][BSplineSupportSizes< Degree >::BCornerSize]; public: -#ifdef BRUNO_LEVY_FIX Evaluator( void ){ _depth = 0 ; memset( _ccValues , 0 , sizeof( _ccValues ) ); } -#endif // BRUNO_LEVY_FIX - double value( int fIdx , int cIdx , bool d ) const; + 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 + struct ChildEvaluator : public EvaluationData::CornerEvaluator { protected: friend BSplineEvaluationData; int _parentDepth; - double _pcValues[2][IndexSize][BSplineSupportSizes< Degree >::ChildCornerSize]; + double _pcValues[D+1][IndexSize][BSplineSupportSizes< Degree >::ChildBCornerSize]; public: -#ifdef BRUNO_LEVY_FIX ChildEvaluator( void ){ _parentDepth = 0 ; memset( _pcValues , 0 , sizeof( _pcValues ) ); } -#endif // BRUNO_LEVY_FIX - double value( int fIdx , int cIdx , bool d ) const; + 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 ); } }; }; - static void SetCornerEvaluator( typename CornerEvaluator::Evaluator& evaluator , int depth ); - static void SetChildCornerEvaluator( typename CornerEvaluator::ChildEvaluator& evaluator , int 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::Evaluator centerEvaluator; - typename CornerEvaluator::Evaluator cornerEvaluator; - double centerValue( int fIdx , int cIdx , bool d ) const { return centerEvaluator.value( fIdx , cIdx , d ); } - double cornerValue( int fIdx , int cIdx , bool d ) const { return cornerEvaluator.value( fIdx , cIdx , d ); } + 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 ); } }; - static void SetEvaluator( Evaluator& evaluator , int depth ){ SetCenterEvaluator( evaluator.centerEvaluator , depth ) , SetCornerEvaluator( evaluator.cornerEvaluator , depth ); } - + 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::ChildEvaluator centerEvaluator; - typename CornerEvaluator::ChildEvaluator cornerEvaluator; - double centerValue( int fIdx , int cIdx , bool d ) const { return centerEvaluator.value( fIdx , cIdx , d ); } - double cornerValue( int fIdx , int cIdx , bool d ) const { return cornerEvaluator.value( fIdx , cIdx , d ); } + 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 ); } }; - static void SetChildEvaluator( ChildEvaluator& evaluator , int depth ){ SetChildCenterEvaluator( evaluator.centerEvaluator , depth ) , SetChildCornerEvaluator( evaluator.cornerEvaluator , depth ); } + template< unsigned int D > static void SetChildEvaluator( ChildEvaluator< D >& evaluator , int depth ){ SetChildCenterEvaluator< D >( evaluator.centerEvaluator , depth ) , SetChildCornerEvaluator< D >( evaluator.cornerEvaluator , depth ); } - struct UpSampleEvaluator + struct UpSampleEvaluator : public EvaluationData::UpSampleEvaluator { protected: friend BSplineEvaluationData; int _lowDepth; double _pcValues[IndexSize][BSplineSupportSizes< Degree >::UpSampleSize]; public: -#ifdef BRUNO_LEVY_FIX UpSampleEvaluator( void ){ _lowDepth = 0 ; memset( _pcValues , 0 , sizeof( _pcValues ) ); } -#endif // BRUNO_LEVY_FIX double value( int pIdx , int cIdx ) const; int lowDepth( void ) const { return _lowDepth; } + void set( int lowDepth ){ BSplineEvaluationData::SetUpSampleEvaluator( *this , lowDepth ); } }; static void SetUpSampleEvaluator( UpSampleEvaluator& evaluator , int lowDepth ); }; -template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int FEMSig1 , unsigned int FEMSig2 > class BSplineIntegrationData { public: - static const int OffsetStart = - BSplineOverlapSizes< Degree1 , Degree2 >::OverlapSupportStart , OffsetStop = BSplineOverlapSizes< Degree1 , Degree2 >::OverlapSupportEnd + ( Degree1&1 ) , IndexSize = OffsetStart + OffsetStop + 1 + 2 * BSplineEvaluationData< Degree1 , BType1 >::Pad; + static 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< Degree1 , BType1 >::Pad + OffsetStart + 1 + offset - ( dim-OffsetStop ); - else return BSplineEvaluationData< Degree1 , BType1 >::Pad + OffsetStart; + 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< Degree1 , BType1 >::Pad<=OffsetStart ? idx-BSplineEvaluationData< Degree1 , BType1 >::Pad : ( BSplineSupportSizes< Degree1 >::Nodes(depth) + BSplineEvaluationData< Degree1 , BType1 >::Pad - IndexSize + idx ) ); } + 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< + template< unsigned int D1=Degree1 , unsigned int D2=Degree2 > struct Integrator { protected: @@ -369,13 +418,16 @@ class BSplineIntegrationData int _depth; double _ccIntegrals[D1+1][D2+1][IndexSize][BSplineOverlapSizes< Degree1 , Degree2 >::OverlapSize]; public: -#ifdef BRUNO_LEVY_FIX - Integrator( void ){ _depth = 0 ; memset(_ccIntegrals, 0, sizeof(_ccIntegrals)); } -#endif // BRUNO_LEVY_FIX + 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 , unsigned int D2 > + template< unsigned int D1=Degree1 , unsigned int D2=Degree2 > struct ChildIntegrator { protected: @@ -383,12 +435,15 @@ class BSplineIntegrationData int _parentDepth; double _pcIntegrals[D1+1][D2+1][IndexSize][BSplineOverlapSizes< Degree1 , Degree2 >::ChildOverlapSize]; public: -#ifdef BRUNO_LEVY_FIX - ChildIntegrator( void ){ _parentDepth = 0 ; memset( _pcIntegrals , 0 , sizeof( _pcIntegrals ) ); } -#endif // BRUNO_LEVY_FIX + 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 @@ -441,31 +496,75 @@ class BSplineIntegrationData #undef SMALLEST_INTEGER_LARGER_THAN_OR_EQUAL_TO_HALF #undef LARGEST_INTEGER_SMALLER_THAN_OR_EQUAL_TO_HALF -template< int Degree , BoundaryType BType > + +template< unsigned int FEMSig , unsigned int D=0 > struct BSplineData { - inline static int TotalFunctionCount( int depth ){ return depth<0 ? 0 : (1<<(depth+1)) - 1 + (depth+1) * ( (Degree&1) + 2 * BSplineEvaluationData< Degree , BType >::Pad ); } - inline static int FunctionIndex( int depth , int offset ){ return TotalFunctionCount( depth-1 ) + offset + BSplineEvaluationData< Degree , BType >::Pad; } - inline static void FactorFunctionIndex( int idx , int& depth , int& offset ) + 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 { - int dim; - depth = 0; - while( idx>=( dim = BSplineEvaluationData< Degree , BType >::End( depth ) - BSplineEvaluationData< Degree , BType >::Begin( depth ) ) ) idx -= dim , depth++; - offset = idx - BSplineEvaluationData< Degree , BType >::Pad; - } - inline static void FunctionSpan( int depth , int& fStart , int& fEnd ){ fStart = TotalFunctionCount( depth-1 ) , fEnd = TotalFunctionCount( depth ); } - inline static int RemapOffset( int depth , int idx , bool& reflect ); + 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]; } - size_t functionCount; - Pointer( typename BSplineEvaluationData< Degree , BType >::BSplineComponents ) baseBSplines; - Pointer( typename BSplineEvaluationData< Degree , BType >::BSplineComponents ) dBaseBSplines; + inline static int RemapOffset( int depth , int idx , bool& reflect ); + BSplineData( void ); + void reset( int maxDepth ); BSplineData( int maxDepth ); ~BSplineData( void ); + +protected: + unsigned int _maxDepth; + Pointer( SparseBSplineEvaluator ) _evaluators; }; -template< int Degree1 , int Degree2 > void SetBSplineElementIntegrals( double integrals[Degree1+1][Degree2+1] ); +template< unsigned int Degree1 , unsigned int Degree2 > void SetBSplineElementIntegrals( double integrals[Degree1+1][Degree2+1] ); -#include "BSplineData.inl" +#include "Mesh/PoissonRecon/BSplineData.inl" #endif // BSPLINE_DATA_INCLUDED \ No newline at end of file diff --git a/Src/BSplineData.inl b/modules/PoissonRecon/include/Mesh/PoissonRecon/BSplineData.inl similarity index 54% rename from Src/BSplineData.inl rename to modules/PoissonRecon/include/Mesh/PoissonRecon/BSplineData.inl index 225fed8f..e13f8a5e 100644 --- a/Src/BSplineData.inl +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/BSplineData.inl @@ -29,25 +29,50 @@ DAMAGE. /////////////////////////// // BSplineEvaluationData // /////////////////////////// -template< int Degree , BoundaryType BType > -double BSplineEvaluationData< Degree , BType >::Value( int depth , int off , double s , bool derivative ) +template< unsigned int FEMSig > +double BSplineEvaluationData< FEMSig >::Value( int depth , int off , double s , int d ) { if( s<0 || s>1 ) return 0.; int res = 1<::BSplineComponents components( depth , off ); // [NOTE] This is an ugly way to ensure that when s=1 we evaluate using a B-Spline component within the valid range. int ii = std::max< int >( 0 , std::min< int >( res-1 , (int)floor( s * res ) ) ) - off; if( ii::SupportStart || ii>BSplineSupportSizes< Degree >::SupportEnd ) return 0; - if( derivative ) return components[ ii-BSplineSupportSizes< Degree >::SupportStart ].derivative()(s); - else return components[ ii-BSplineSupportSizes< Degree >::SupportStart ](s); + return d<=Degree ? components[ii-BSplineSupportSizes< Degree >::SupportStart][d](s) : 0; } -template< int Degree , BoundaryType BType > -void BSplineEvaluationData< Degree , BType >::SetCenterEvaluator( typename CenterEvaluator::Evaluator& evaluator , int depth ) +template< unsigned int FEMSig > +double BSplineEvaluationData< FEMSig >::Integral( int depth , int off , double b , double e , int d ) +{ + double integral = 0; + // Check for valid integration bounds + if( OutOfBounds( depth , off ) ) return 0; + if( b>=e || b>=1 || e<=0 ) return 0; + if( b<0 ) b=0; + if( e>1 ) e=1; + + int res = 1<::SupportStart ) )/res; + double _e = ( (double)( off + 1 + BSplineSupportSizes< Degree >::SupportEnd ) )/res; + if( b>=_e || e<=_b ) return 0; + typename BSplineData< FEMSig , Degree >::BSplineComponents components( depth , off ); + for( int i=BSplineSupportSizes< Degree >::SupportStart ; i<=BSplineSupportSizes< Degree >::SupportEnd ; i++ ) + { + // The index of the current cell + int c = off + i; + // The bounds of the current cell + _b = std::max< double >( b , ( (double)c ) / res ) , _e = std::min< double >( e , ( (double)(c+1) )/res ); + if( _b<_e ) integral += d<=Degree ? components[i-BSplineSupportSizes< Degree >::SupportStart][d].integral( _b , _e ) : 0; + } + return integral; +} +template< unsigned int FEMSig > +template< unsigned int D > +void BSplineEvaluationData< FEMSig >::SetCenterEvaluator( typename CenterEvaluator< D >::Evaluator& evaluator , int depth ) { evaluator._depth = depth; int res = 1<::SetCenterEvaluator( typename Cente { int ii = IndexToOffset( depth , i ); double s = 0.5 + ii + j; - for( int d1=0 ; d1<2 ; d1++ ) evaluator._ccValues[d1][i][j-BSplineSupportSizes< Degree >::SupportStart] = Value( depth , ii , s/res , d1!=0 ); + for( int d1=0 ; d1<=D ; d1++ ) evaluator._ccValues[d1][i][j-BSplineSupportSizes< Degree >::SupportStart] = Value( depth , ii , s/res , d1 ); } } -template< int Degree , BoundaryType BType > -void BSplineEvaluationData< Degree , BType >::SetChildCenterEvaluator( typename CenterEvaluator::ChildEvaluator& evaluator , int parentDepth ) +template< unsigned int FEMSig > +template< unsigned int D > +void BSplineEvaluationData< FEMSig >::SetChildCenterEvaluator( typename CenterEvaluator< D >::ChildEvaluator& evaluator , int parentDepth ) { evaluator._parentDepth = parentDepth; int res = 1<<(parentDepth+1); @@ -67,49 +93,89 @@ void BSplineEvaluationData< Degree , BType >::SetChildCenterEvaluator( typename { int ii = IndexToOffset( parentDepth , i ); double s = 0.5 + 2*ii + j; - for( int d1=0 ; d1<2 ; d1++ ) evaluator._pcValues[d1][i][j-BSplineSupportSizes< Degree >::ChildSupportStart] = Value( parentDepth , ii , s/res , d1!=0 ); + for( int d1=0 ; d1<=D ; d1++ ) evaluator._pcValues[d1][i][j-BSplineSupportSizes< Degree >::ChildSupportStart] = Value( parentDepth , ii , s/res , d1 ); } } -template< int Degree , BoundaryType BType > -double BSplineEvaluationData< Degree , BType >::CenterEvaluator::Evaluator::value( int fIdx , int cIdx , bool d ) const +template< unsigned int FEMSig > +template< unsigned int D > +double BSplineEvaluationData< FEMSig >::CenterEvaluator< D >::Evaluator::value( int fIdx , int cIdx , int d ) const { int dd = cIdx-fIdx , res = 1<<(_depth); if( cIdx<0 || cIdx>=res || OutOfBounds( _depth , fIdx ) || dd::SupportStart || dd>BSplineSupportSizes< Degree >::SupportEnd ) return 0; - return _ccValues[d?1:0][ OffsetToIndex( _depth , fIdx ) ][dd-BSplineSupportSizes< Degree >::SupportStart]; + return _ccValues[d][ OffsetToIndex( _depth , fIdx ) ][dd-BSplineSupportSizes< Degree >::SupportStart]; } -template< int Degree , BoundaryType BType > -double BSplineEvaluationData< Degree , BType >::CenterEvaluator::ChildEvaluator::value( int fIdx , int cIdx , bool d ) const +template< unsigned int FEMSig > +template< unsigned int D > +double BSplineEvaluationData< FEMSig >::CenterEvaluator< D >::ChildEvaluator::value( int fIdx , int cIdx , int d ) const { int dd = cIdx-2*fIdx , res = 1<<(_parentDepth+1); if( cIdx<0 || cIdx>=res || OutOfBounds( _parentDepth , fIdx ) || dd::ChildSupportStart || dd>BSplineSupportSizes< Degree >::ChildSupportEnd ) return 0; - return _pcValues[d?1:0][ OffsetToIndex( _parentDepth , fIdx ) ][dd-BSplineSupportSizes< Degree >::ChildSupportStart]; + return _pcValues[d][ OffsetToIndex( _parentDepth , fIdx ) ][dd-BSplineSupportSizes< Degree >::ChildSupportStart]; } -template< int Degree , BoundaryType BType > -void BSplineEvaluationData< Degree , BType >::SetCornerEvaluator( typename CornerEvaluator::Evaluator& evaluator , int depth ) +template< unsigned int FEMSig > +template< unsigned int D > +void BSplineEvaluationData< FEMSig >::SetCornerEvaluator( typename CornerEvaluator< D >::Evaluator& evaluator , int depth ) { evaluator._depth = depth; int res = 1<::CornerStart ; j<=BSplineSupportSizes< Degree >::CornerEnd ; j++ ) + for( int i=0 ; i::BCornerStart ; j<=BSplineSupportSizes< Degree >::BCornerEnd ; j++ ) { int ii = IndexToOffset( depth , i ); double s = ii + j; - for( int d1=0 ; d1<2 ; d1++ ) evaluator._ccValues[d1][i][j-BSplineSupportSizes< Degree >::CornerStart] = Value( depth , ii , s/res , d1!=0 ); + int jj = j-BSplineSupportSizes< Degree >::BCornerStart; + for( int d1=0 ; d1<=D ; d1++ ) + { + if( d1==Degree ) + { + if ( j==BSplineSupportSizes< Degree >::BCornerStart ) evaluator._ccValues[d1][i][jj] = ( Value( depth , ii , ( s+0.5 )/res , d1 ) ) / 2; + else if( j==BSplineSupportSizes< Degree >::BCornerEnd ) evaluator._ccValues[d1][i][jj] = ( Value( depth , ii , ( s-0.5 )/res , d1 ) ) / 2; + else evaluator._ccValues[d1][i][jj] = ( Value( depth , ii , ( s-0.5 )/res , d1 ) + Value( depth , ii , ( s+0.5 )/res , d1 ) ) / 2; + } + else evaluator._ccValues[d1][i][jj] = Value( depth , ii , s /res , d1 ); + } } } -template< int Degree , BoundaryType BType > -void BSplineEvaluationData< Degree , BType >::SetChildCornerEvaluator( typename CornerEvaluator::ChildEvaluator& evaluator , int parentDepth ) +template< unsigned int FEMSig > +template< unsigned int D > +void BSplineEvaluationData< FEMSig >::SetChildCornerEvaluator( typename CornerEvaluator< D >::ChildEvaluator& evaluator , int parentDepth ) { evaluator._parentDepth = parentDepth; int res = 1<<(parentDepth+1); - for( int i=0 ; i::ChildCornerStart ; j<=BSplineSupportSizes< Degree >::ChildCornerEnd ; j++ ) + for( int i=0 ; i::ChildBCornerStart ; j<=BSplineSupportSizes< Degree >::ChildBCornerEnd ; j++ ) { int ii = IndexToOffset( parentDepth , i ); double s = 2*ii + j; - for( int d1=0 ; d1<2 ; d1++ ) evaluator._pcValues[d1][i][j-BSplineSupportSizes< Degree >::ChildCornerStart] = Value( parentDepth , ii , s/res , d1!=0 ); + int jj = j-BSplineSupportSizes< Degree >::ChildBCornerStart; + for( int d1=0 ; d1<=D ; d1++ ) + { + if( d1==Degree ) + { + if ( j==BSplineSupportSizes< Degree >::ChildBCornerStart ) evaluator._pcValues[d1][i][jj] = ( Value( parentDepth , ii , ( s+0.5 )/res , d1 ) ) / 2; + else if( j==BSplineSupportSizes< Degree >::ChildBCornerEnd ) evaluator._pcValues[d1][i][jj] = ( Value( parentDepth , ii , ( s-0.5 )/res , d1 ) ) / 2; + else evaluator._pcValues[d1][i][jj] = ( Value( parentDepth , ii , ( s-0.5 )/res , d1 ) + Value( parentDepth , ii , ( s+0.5 )/res , d1 ) ) / 2; + } + else evaluator._pcValues[d1][i][jj] = Value( parentDepth , ii , s /res , d1 ); + } } } -template< int Degree , BoundaryType BType > -void BSplineEvaluationData< Degree , BType >::SetUpSampleEvaluator( UpSampleEvaluator& evaluator , int lowDepth ) +template< unsigned int FEMSig > +template< unsigned int D > +double BSplineEvaluationData< FEMSig >::CornerEvaluator< D >::Evaluator::value( int fIdx , int cIdx , int d ) const +{ + int dd = cIdx-fIdx , res = ( 1<<_depth ) + 1; + if( cIdx<0 || cIdx>=res || OutOfBounds( _depth , fIdx ) || dd::BCornerStart || dd>BSplineSupportSizes< Degree >::BCornerEnd ) return 0; + return _ccValues[d][ OffsetToIndex( _depth , fIdx ) ][dd-BSplineSupportSizes< Degree >::BCornerStart]; +} +template< unsigned int FEMSig > +template< unsigned int D > +double BSplineEvaluationData< FEMSig >::CornerEvaluator< D >::ChildEvaluator::value( int fIdx , int cIdx , int d ) const +{ + int dd = cIdx-2*fIdx , res = ( 1<<(_parentDepth+1) ) + 1; + if( cIdx<0 || cIdx>=res || OutOfBounds( _parentDepth , fIdx ) || dd::ChildBCornerStart || dd>BSplineSupportSizes< Degree >::ChildBCornerEnd ) return 0; + return _pcValues[d][ OffsetToIndex( _parentDepth , fIdx ) ][dd-BSplineSupportSizes< Degree >::ChildBCornerStart]; +} +template< unsigned int FEMSig > +void BSplineEvaluationData< FEMSig >::SetUpSampleEvaluator( UpSampleEvaluator& evaluator , int lowDepth ) { evaluator._lowDepth = lowDepth; for( int i=0 ; i::SetUpSampleEvaluator( UpSampleEval for( int j=0 ; j::UpSampleSize ; j++ ) evaluator._pcValues[i][j] = b[j]; } } -template< int Degree , BoundaryType BType > -double BSplineEvaluationData< Degree , BType >::CornerEvaluator::Evaluator::value( int fIdx , int cIdx , bool d ) const -{ - int dd = cIdx-fIdx , res = ( 1<<_depth ) + 1; - if( cIdx<0 || cIdx>=res || OutOfBounds( _depth , fIdx ) || dd::CornerStart || dd>BSplineSupportSizes< Degree >::CornerEnd ) return 0; - return _ccValues[d?1:0][ OffsetToIndex( _depth , fIdx ) ][dd-BSplineSupportSizes< Degree >::CornerStart]; -} -template< int Degree , BoundaryType BType > -double BSplineEvaluationData< Degree , BType >::CornerEvaluator::ChildEvaluator::value( int fIdx , int cIdx , bool d ) const -{ - int dd = cIdx-2*fIdx , res = ( 1<<(_parentDepth+1) ) + 1; - if( cIdx<0 || cIdx>=res || OutOfBounds( _parentDepth , fIdx ) || dd::ChildCornerStart || dd>BSplineSupportSizes< Degree >::ChildCornerEnd ) return 0; - return _pcValues[d?1:0][ OffsetToIndex( _parentDepth , fIdx ) ][dd-BSplineSupportSizes< Degree >::ChildCornerStart]; -} -template< int Degree , BoundaryType BType > -double BSplineEvaluationData< Degree , BType >::UpSampleEvaluator::value( int pIdx , int cIdx ) const +template< unsigned int FEMSig > +double BSplineEvaluationData< FEMSig >::UpSampleEvaluator::value( int pIdx , int cIdx ) const { int dd = cIdx-2*pIdx; if( OutOfBounds( _lowDepth+1 , cIdx ) || OutOfBounds( _lowDepth , pIdx ) || dd::UpSampleStart || dd>BSplineSupportSizes< Degree >::UpSampleEnd ) return 0; return _pcValues[ OffsetToIndex( _lowDepth , pIdx ) ][dd-BSplineSupportSizes< Degree >::UpSampleStart]; } -////////////////////////////////////////////// -// BSplineEvaluationData::BSplineComponents // -////////////////////////////////////////////// -template< int Degree , BoundaryType BType > -BSplineEvaluationData< Degree , BType >::BSplineComponents::BSplineComponents( int depth , int offset ) -{ - int res = 1< elements( res , offset , BType ); - - // The first index is the position, the second is the element type - Polynomial< Degree > components[Degree+1][Degree+1]; - // Generate the elements that can appear in the base function corresponding to the base function at (depth,offset) = (0,0) - for( int d=0 ; d<=Degree ; d++ ) for( int dd=0 ; dd<=Degree ; dd++ ) components[d][dd] = Polynomial< Degree >::BSplineComponent( Degree-dd ).shift( -( (Degree+1)/2 ) + d ); - - // Now adjust to the desired depth and offset - double width = 1. / res; - for( int d=0 ; d<=Degree ; d++ ) for( int dd=0 ; dd<=Degree ; dd++ ) components[d][dd] = components[d][dd].scale( width ).shift( width*offset ); - - // Now write in the polynomials - for( int d=0 ; d<=Degree ; d++ ) - { - int idx = offset + BSplineSupportSizes< Degree >::SupportStart + d; - _polys[d] = Polynomial< Degree >(); - - if( idx>=0 && idx -typename BSplineEvaluationData< Degree , BType >::BSplineComponents BSplineEvaluationData< Degree , BType >::BSplineComponents::derivative( void ) const -{ - BSplineComponents b = (*this); - for( int d=0 ; d<=Degree ; d++ ) b._polys[d] = b._polys[d].derivative(); - return b; -} - ////////////////////////////////////////////////////////// // BSplineEvaluationData::BSplineUpSamplingCoefficients // ////////////////////////////////////////////////////////// -template< int Degree , BoundaryType BType > -BSplineEvaluationData< Degree , BType >::BSplineUpSamplingCoefficients::BSplineUpSamplingCoefficients( int depth , int offset ) +template< unsigned int FEMSig > +BSplineEvaluationData< FEMSig >::BSplineUpSamplingCoefficients::BSplineUpSamplingCoefficients( int depth , int offset ) { + static const BoundaryType BType = FEMSignature< FEMSig >::BType; // [ 1/8 1/2 3/4 1/2 1/8] // [ 1 , 1 ] -> [ 3/4 , 1/2 , 1/8 ] + [ 1/8 , 1/2 , 3/4 ] = [ 7/8 , 1 , 7/8 ] int dim = BSplineSupportSizes< Degree >::Nodes(depth) , _dim = BSplineSupportSizes< Degree >::Nodes(depth+1); bool reflect; - offset = BSplineData< Degree , BType >::RemapOffset( depth , offset , reflect ); + offset = BSplineData< FEMSig >::RemapOffset( depth , offset , reflect ); int multiplier = ( BType==BOUNDARY_DIRICHLET && reflect ) ? -1 : 1; bool useReflected = ( BType!=BOUNDARY_FREE ) && ( BSplineSupportSizes< Degree >::Inset || ( offset % ( dim-1 ) ) ); int b[ BSplineSupportSizes< Degree >::UpSampleSize ]; @@ -201,7 +218,7 @@ BSplineEvaluationData< Degree , BType >::BSplineUpSamplingCoefficients::BSplineU for( int i=BSplineSupportSizes< Degree >::UpSampleStart ; i<=BSplineSupportSizes< Degree >::UpSampleEnd ; i++ ) { int _offset = 2*offset+i; - _offset = BSplineData< Degree , BType >::RemapOffset( depth+1 , _offset , reflect ); + _offset = BSplineData< FEMSig >::RemapOffset( depth+1 , _offset , reflect ); if( useReflected || !reflect ) { int _multiplier = multiplier * ( ( BType==BOUNDARY_DIRICHLET && reflect ) ? -1 : 1 ); @@ -210,7 +227,7 @@ BSplineEvaluationData< Degree , BType >::BSplineUpSamplingCoefficients::BSplineU // If we are not inset and we are at the boundary, use the reflection as well if( BType!=BOUNDARY_FREE && !BSplineSupportSizes< Degree >::Inset && ( offset % (dim-1) ) && !( _offset % (_dim-1) ) ) { - _offset = BSplineData< Degree , BType >::RemapOffset( depth+1 , _offset , reflect ); + _offset = BSplineData< FEMSig >::RemapOffset( depth+1 , _offset , reflect ); int _multiplier = multiplier * ( ( BType==BOUNDARY_DIRICHLET && reflect ) ? -1 : 1 ); if( BType==BOUNDARY_DIRICHLET ) _multiplier *= -1; coefficients[ _offset ] += b[ i-BSplineSupportSizes< Degree >::UpSampleStart ] * _multiplier; @@ -221,27 +238,60 @@ BSplineEvaluationData< Degree , BType >::BSplineUpSamplingCoefficients::BSplineU //////////////////////////// // BSplineIntegrationData // //////////////////////////// -template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int FEMSig1 , unsigned int FEMSig2 > template< unsigned int D1 , unsigned int D2 > -double BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::Dot( int depth1 , int off1 , int depth2 , int off2 ) +double BSplineIntegrationData< FEMSig1 , FEMSig2 >::Dot( int depth1 , int off1 , int depth2 , int off2 ) { - if( D1>Degree1 ) fprintf( stderr , "[ERROR] BSplineIntegrationData::Dot: taking more derivatives than the degree: %d > %d\n" , D1 , Degree1 ) , exit( 0 ); - if( D2>Degree2 ) fprintf( stderr , "[ERROR] BSplineIntegrationData::Dot: taking more derivatives than the degree: %d > %d\n" , D2 , Degree2 ) , exit( 0 ); + if( D1>Degree1 ) ERROR_OUT( "Taking more derivatives than the degree: " , D1 , " > " , Degree1 ); + if( D2>Degree2 ) 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 ]; int depth = std::max< int >( depth1 , depth2 ); - BSplineElements< Degree1 > b1( 1< b2( 1< b1; + BSplineElements< Degree2 > b2; + if( BSplineSupportSizes< Degree1 >::IsInteriorlySupported( depth1 , off1 ) && BSplineSupportSizes< Degree2 >::IsInteriorlySupported( depth2 , off2 ) ) { - BSplineElements< Degree1 > b; - while( depth1::SupportStart + BSplineSupportSizes< Degree1 >::SupportEnd; + BSplineSupportSizes< Degree1 >::InteriorSupportedSpan( depth1 , begin1 , end1 ); + b1 = BSplineElements< Degree1 >( res , begin1 , BOUNDARY_FREE ); + for( int d=depth1 ; d b=b1; + b.upSample( b1 ); + res <<= 1; + } + b2 = BSplineElements< Degree2 >( res , off2 - ( (off1-begin1)<<(depth2-depth1) ) , BOUNDARY_FREE ); + } + else + { + int begin2 , end2 , res = 1 - BSplineSupportSizes< Degree2 >::SupportStart + BSplineSupportSizes< Degree2 >::SupportEnd; + BSplineSupportSizes< Degree2 >::InteriorSupportedSpan( depth2 , begin2 , end2 ); + b2 = BSplineElements< Degree2 >( res , begin2 , BOUNDARY_FREE ); + for( int d=depth2 ; d b=b2; + b.upSample( b2 ); + res <<= 1; + } + b1 = BSplineElements< Degree1 >( res , off1 - ( (off2-begin2)<<(depth1-depth2) ) , BOUNDARY_FREE ); + } } + else { - BSplineElements< Degree2 > b; - while( depth2( 1<::BType ); + b2 = BSplineElements< Degree2 >( 1<::BType ); + { + BSplineElements< Degree1 > b; + while( depth1 b; + while( depth2 db1; @@ -279,67 +329,66 @@ double BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::Dot( int d SetBSplineElementIntegrals< _Degree1 , _Degree2 >( integrals ); for( int j=0 ; j<=_Degree1 ; j++ ) for( int k=0 ; k<=_Degree2 ; k++ ) _dot += integrals[j][k] * sums[j][k]; } - _dot /= b1.denominator; _dot /= b2.denominator; return ( !D1 && !D2 ) ? _dot / (1< +template< unsigned int FEMSig1 , unsigned int FEMSig2 > template< unsigned int D1 , unsigned int D2 , unsigned int _D1 , unsigned int _D2 , class Integrator > -void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::IntegratorSetter< D1 , D2 , _D1 , _D2 , Integrator >::Set2D( Integrator& integrator , int depth ) +void BSplineIntegrationData< FEMSig1 , FEMSig2 >::IntegratorSetter< D1 , D2 , _D1 , _D2 , Integrator >::Set2D( Integrator& integrator , int depth ) { IntegratorSetter< D1-1 , D2 , _D1 , _D2 , Integrator >::Set2D( integrator , depth ); IntegratorSetter< D1 , D2 , _D1 , _D2 , Integrator >::Set1D( integrator , depth ); } -template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int FEMSig1 , unsigned int FEMSig2 > template< unsigned int D1 , unsigned int D2 , unsigned int _D1 , unsigned int _D2 , class Integrator > -void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::IntegratorSetter< D1 , D2 , _D1 , _D2 , Integrator >::Set1D( Integrator& integrator , int depth ) +void BSplineIntegrationData< FEMSig1 , FEMSig2 >::IntegratorSetter< D1 , D2 , _D1 , _D2 , Integrator >::Set1D( Integrator& integrator , int depth ) { IntegratorSetter< D1 , D2-1 , _D1 , _D2 , Integrator >::Set1D( integrator , depth ); _IntegratorSetter< D1 , D2 , _D1 , _D2 >::Set( integrator , depth ); } -template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int FEMSig1 , unsigned int FEMSig2 > template< unsigned int D2 , unsigned int _D1 , unsigned int _D2 , class Integrator > -void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::IntegratorSetter< 0 , D2 , _D1 , _D2 , Integrator >::Set2D( Integrator& integrator , int depth ) +void BSplineIntegrationData< FEMSig1 , FEMSig2 >::IntegratorSetter< 0 , D2 , _D1 , _D2 , Integrator >::Set2D( Integrator& integrator , int depth ) { IntegratorSetter< 0 , D2 , _D1 , _D2 , Integrator >::Set1D( integrator , depth ); } -template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int FEMSig1 , unsigned int FEMSig2 > template< unsigned int D2 , unsigned int _D1 , unsigned int _D2 , class Integrator > -void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::IntegratorSetter< 0 , D2 , _D1 , _D2 , Integrator >::Set1D( Integrator& integrator , int depth ) +void BSplineIntegrationData< FEMSig1 , FEMSig2 >::IntegratorSetter< 0 , D2 , _D1 , _D2 , Integrator >::Set1D( Integrator& integrator , int depth ) { IntegratorSetter< 0 , D2-1 , _D1 , _D2 , Integrator >::Set1D( integrator , depth ); _IntegratorSetter< 0 , D2 , _D1 , _D2 >::Set( integrator , depth ); } -template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int FEMSig1 , unsigned int FEMSig2 > template< unsigned int D1 , unsigned int _D1 , unsigned int _D2 , class Integrator > -void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::IntegratorSetter< D1 , 0 , _D1 , _D2 , Integrator >::Set2D( Integrator& integrator , int depth ) +void BSplineIntegrationData< FEMSig1 , FEMSig2 >::IntegratorSetter< D1 , 0 , _D1 , _D2 , Integrator >::Set2D( Integrator& integrator , int depth ) { IntegratorSetter< D1-1 , 0 , _D1 , _D2 , Integrator >::Set2D( integrator , depth ); IntegratorSetter< D1 , 0 , _D1 , _D2 , Integrator >::Set1D( integrator , depth ); } -template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int FEMSig1 , unsigned int FEMSig2 > template< unsigned int D1 , unsigned int _D1 , unsigned int _D2 , class Integrator > -void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::IntegratorSetter< D1 , 0 , _D1 , _D2 , Integrator >::Set1D( Integrator& integrator , int depth ) +void BSplineIntegrationData< FEMSig1 , FEMSig2 >::IntegratorSetter< D1 , 0 , _D1 , _D2 , Integrator >::Set1D( Integrator& integrator , int depth ) { _IntegratorSetter< D1 , 0 , _D1 , _D2 >::Set( integrator , depth ); } -template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int FEMSig1 , unsigned int FEMSig2 > template< unsigned int _D1 , unsigned int _D2 , class Integrator > -void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::IntegratorSetter< 0 , 0 , _D1 , _D2 , Integrator >::Set2D( Integrator& integrator , int depth ) +void BSplineIntegrationData< FEMSig1 , FEMSig2 >::IntegratorSetter< 0 , 0 , _D1 , _D2 , Integrator >::Set2D( Integrator& integrator , int depth ) { IntegratorSetter< 0 , 0 , _D1 , _D2 , Integrator >::Set1D( integrator , depth ); } -template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int FEMSig1 , unsigned int FEMSig2 > template< unsigned int _D1 , unsigned int _D2 , class Integrator > -void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::IntegratorSetter< 0 , 0 , _D1 , _D2 , Integrator >::Set1D( Integrator& integrator , int depth ) +void BSplineIntegrationData< FEMSig1 , FEMSig2 >::IntegratorSetter< 0 , 0 , _D1 , _D2 , Integrator >::Set1D( Integrator& integrator , int depth ) { _IntegratorSetter< 0 , 0 , _D1 , _D2 >::Set( integrator , depth ); } -template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int FEMSig1 , unsigned int FEMSig2 > template< unsigned int D1 , unsigned int D2 , unsigned int _D1 , unsigned int _D2 > -void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::_IntegratorSetter< D1 , D2 , _D1 , _D2 >::Set( typename FunctionIntegrator::template Integrator< _D1 , _D2 >& integrator , int depth ) +void BSplineIntegrationData< FEMSig1 , FEMSig2 >::_IntegratorSetter< D1 , D2 , _D1 , _D2 >::Set( typename FunctionIntegrator::template Integrator< _D1 , _D2 >& integrator , int depth ) { for( int i=0 ; i::OverlapStart ; j<=BSplineOverlapSizes< Degree1 , Degree2 >::OverlapEnd ; j++ ) { @@ -347,9 +396,9 @@ void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::_IntegratorS integrator._ccIntegrals[D1][D2][i][j-BSplineOverlapSizes< Degree1 , Degree2 >::OverlapStart] = Dot< D1 , D2 >( depth , ii , depth , ii+j ); } } -template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int FEMSig1 , unsigned int FEMSig2 > template< unsigned int D1 , unsigned int D2 , unsigned int _D1 , unsigned int _D2 > -void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::_IntegratorSetter< D1 , D2 , _D1 , _D2 >::Set( typename FunctionIntegrator::template ChildIntegrator< _D1 , _D2 >& integrator , int pDepth ) +void BSplineIntegrationData< FEMSig1 , FEMSig2 >::_IntegratorSetter< D1 , D2 , _D1 , _D2 >::Set( typename FunctionIntegrator::template ChildIntegrator< _D1 , _D2 >& integrator , int pDepth ) { for( int i=0 ; i::ChildOverlapStart ; j<=BSplineOverlapSizes< Degree1 , Degree2 >::ChildOverlapEnd ; j++ ) { @@ -358,34 +407,34 @@ void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::_IntegratorS } } -template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int FEMSig1 , unsigned int FEMSig2 > template< unsigned int D1 , unsigned int D2 > -void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::SetIntegrator( typename FunctionIntegrator::template Integrator< D1 , D2 >& integrator , int depth ) +void BSplineIntegrationData< FEMSig1 , FEMSig2 >::SetIntegrator( typename FunctionIntegrator::template Integrator< D1 , D2 >& integrator , int depth ) { integrator._depth = depth; IntegratorSetter< D1 , D2 , D1 , D2 , typename FunctionIntegrator::template Integrator< D1 , D2 > >::Set2D( integrator , depth ); } -template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int FEMSig1 , unsigned int FEMSig2 > template< unsigned int D1 , unsigned int D2 > -void BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::SetChildIntegrator( typename FunctionIntegrator::template ChildIntegrator< D1 , D2 >& integrator , int parentDepth ) +void BSplineIntegrationData< FEMSig1 , FEMSig2 >::SetChildIntegrator( typename FunctionIntegrator::template ChildIntegrator< D1 , D2 >& integrator , int parentDepth ) { integrator._parentDepth = parentDepth; IntegratorSetter< D1 , D2 , D1 , D2 , typename FunctionIntegrator::template ChildIntegrator< D1 , D2 > >::Set2D( integrator , parentDepth ); } -template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int FEMSig1 , unsigned int FEMSig2 > template< unsigned int D1 , unsigned int D2 > -double BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::FunctionIntegrator::Integrator< D1 , D2 >::dot( int off1 , int off2 , int d1 , int d2 ) const +double BSplineIntegrationData< FEMSig1 , FEMSig2 >::FunctionIntegrator::Integrator< D1 , D2 >::dot( int off1 , int off2 , int d1 , int d2 ) const { int d = off2-off1; - if( BSplineEvaluationData< Degree1 , BType1 >::OutOfBounds( _depth , off1 ) || BSplineEvaluationData< Degree2 , BType2 >::OutOfBounds( _depth , off2 ) || d::OverlapStart || d>BSplineOverlapSizes< Degree1 , Degree2 >::OverlapEnd ) return 0; + if( BSplineEvaluationData< FEMSig1 >::OutOfBounds( _depth , off1 ) || BSplineEvaluationData< FEMSig2 >::OutOfBounds( _depth , off2 ) || d::OverlapStart || d>BSplineOverlapSizes< Degree1 , Degree2 >::OverlapEnd ) return 0; return _ccIntegrals[d1][d2][ OffsetToIndex( _depth , off1 ) ][d-BSplineOverlapSizes< Degree1 , Degree2 >::OverlapStart]; } -template< int Degree1 , BoundaryType BType1 , int Degree2 , BoundaryType BType2 > +template< unsigned int FEMSig1 , unsigned int FEMSig2 > template< unsigned int D1 , unsigned int D2 > -double BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::FunctionIntegrator::ChildIntegrator< D1 , D2 >::dot( int off1 , int off2 , int d1 , int d2 ) const +double BSplineIntegrationData< FEMSig1 , FEMSig2 >::FunctionIntegrator::ChildIntegrator< D1 , D2 >::dot( int off1 , int off2 , int d1 , int d2 ) const { int d = off2-2*off1; - if( BSplineEvaluationData< Degree1 , BType1 >::OutOfBounds( _parentDepth , off1 ) || BSplineEvaluationData< Degree2 , BType2 >::OutOfBounds( _parentDepth+1 , off2 ) || d::ChildOverlapStart || d>BSplineOverlapSizes< Degree1 , Degree2 >::ChildOverlapEnd ) return 0; + if( BSplineEvaluationData< FEMSig1 >::OutOfBounds( _parentDepth , off1 ) || BSplineEvaluationData< FEMSig2 >::OutOfBounds( _parentDepth+1 , off2 ) || d::ChildOverlapStart || d>BSplineOverlapSizes< Degree1 , Degree2 >::ChildOverlapEnd ) return 0; return _pcIntegrals[d1][d2][ OffsetToIndex( _parentDepth , off1 ) ][d-BSplineOverlapSizes< Degree1 , Degree2 >::ChildOverlapStart]; } @@ -393,12 +442,40 @@ double BSplineIntegrationData< Degree1 , BType1 , Degree2 , BType2 >::FunctionIn // BSplineData // ///////////////// #define MODULO( A , B ) ( (A)<0 ? ( (B)-((-(A))%(B)) ) % (B) : (A) % (B) ) -template< int Degree , BoundaryType BType > -int BSplineData< Degree , BType >::RemapOffset( int depth , int offset , bool& reflect ) + +template< unsigned int FEMSig , unsigned int D > +BSplineData< FEMSig , D >::BSplineComponents::BSplineComponents( int depth , int offset ) +{ + static const int _Degree = Degree; + int res = 1< elements( res , offset , FEMSignature< FEMSig >::BType ); + + // The first index is the position, the second is the element type + Polynomial< Degree > components[Degree+1][Degree+1]; + // Generate the elements that can appear in the base function corresponding to the base function at (depth,offset) = (0,0) + for( int d=0 ; d<=Degree ; d++ ) for( int dd=0 ; dd<=Degree ; dd++ ) components[d][dd] = Polynomial< Degree >::BSplineComponent( _Degree-dd ).shift( -( (_Degree+1)/2 ) + d ); + + // Now adjust to the desired depth and offset + double width = 1. / res; + for( int d=0 ; d<=Degree ; d++ ) for( int dd=0 ; dd<=Degree ; dd++ ) components[d][dd] = components[d][dd].scale( width ).shift( width*offset ); + + // Now write in the polynomials + for( int d=0 ; d<=Degree ; d++ ) + { + int idx = offset + BSplineSupportSizes< Degree >::SupportStart + d; + _polys[d][0] = Polynomial< Degree >(); + + if( idx>=0 && idx +int BSplineData< FEMSig , D >::RemapOffset( int depth , int offset , bool& reflect ) { const int I = ( Degree&1 ) ? 0 : 1; - if( BType==BOUNDARY_FREE ){ reflect = false ; return offset; } - int dim = BSplineEvaluationData< Degree , BOUNDARY_NEUMANN >::End( depth ) - BSplineEvaluationData< Degree , BOUNDARY_NEUMANN >::Begin( depth ); + 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) ); reflect = offset>=dim; if( reflect ) return 2*(dim-1+I) - (offset+I); @@ -406,32 +483,37 @@ int BSplineData< Degree , BType >::RemapOffset( int depth , int offset , bool& r } #undef MODULO -template< int Degree , BoundaryType BType > -BSplineData< Degree , BType >::BSplineData( int maxDepth ) +template< unsigned int FEMSig , unsigned int D > +BSplineData< FEMSig , D >::BSplineData( void ) { - functionCount = TotalFunctionCount( maxDepth ); - baseBSplines = NewPointer< typename BSplineEvaluationData< Degree , BType >::BSplineComponents >( functionCount ); - dBaseBSplines = NewPointer< typename BSplineEvaluationData< Degree , BType >::BSplineComponents >( functionCount ); + _maxDepth = 0; + _evaluators = NullPointer( SparseBSplineEvaluator ); +} +template< unsigned int FEMSig , unsigned int D > +void BSplineData< FEMSig , D >::reset( int maxDepth ) +{ + if( _evaluators ) DeletePointer( _evaluators ); - for( size_t i=0 ; i::BSplineComponents( d , off ); - dBaseBSplines[i] = baseBSplines[i].derivative(); - } + _maxDepth = maxDepth; + _evaluators = NewPointer< SparseBSplineEvaluator >( _maxDepth+1 ); + for( unsigned int d=0 ; d<=_maxDepth ; d++ ) _evaluators[d].init( d ); +} +template< unsigned int FEMSig , unsigned int D > +BSplineData< FEMSig , D >::BSplineData( int maxDepth ) +{ + _evaluators = NullPointer( SparseBSplineEvaluator ); + reset( maxDepth ); } -template< int Degree , BoundaryType BType > -BSplineData< Degree , BType >::~BSplineData( void ) +template< unsigned int FEMSig , unsigned int D > +BSplineData< FEMSig , D >::~BSplineData( void ) { - FreePointer( baseBSplines ); - FreePointer( dBaseBSplines ); + DeletePointer( _evaluators ); } ///////////////////// // BSplineElements // ///////////////////// -template< int Degree > +template< unsigned int Degree > BSplineElements< Degree >::BSplineElements( int res , int offset , BoundaryType bType ) { denominator = 1; @@ -458,12 +540,12 @@ BSplineElements< Degree >::BSplineElements( int res , int offset , BoundaryType _addPeriodic< true >( _ReflectLeft( offset , res ) , bType==BOUNDARY_DIRICHLET ) , _addPeriodic< false >( _ReflectRight( offset , res ) , bType==BOUNDARY_DIRICHLET ); } } -template< int Degree > int BSplineElements< Degree >::_ReflectLeft ( int offset , int res ){ return (Degree&1) ? -offset : -1-offset; } -template< int Degree > int BSplineElements< Degree >::_ReflectRight( int offset , int res ){ return (Degree&1) ? 2*res-offset : 2*res-1-offset; } -template< int Degree > int BSplineElements< Degree >::_RotateLeft ( int offset , int res ){ return offset-2*res; } -template< int Degree > int BSplineElements< Degree >::_RotateRight ( int offset , int res ){ return offset+2*res; } +template< unsigned int Degree > int BSplineElements< Degree >::_ReflectLeft ( int offset , int res ){ return (Degree&1) ? -offset : -1-offset; } +template< unsigned int Degree > int BSplineElements< Degree >::_ReflectRight( int offset , int res ){ return (Degree&1) ? 2*res-offset : 2*res-1-offset; } +template< unsigned int Degree > int BSplineElements< Degree >::_RotateLeft ( int offset , int res ){ return offset-2*res; } +template< unsigned int Degree > int BSplineElements< Degree >::_RotateRight ( int offset , int res ){ return offset+2*res; } -template< int Degree > +template< unsigned int Degree > template< bool Left > void BSplineElements< Degree >::_addPeriodic( int offset , bool negate ) { @@ -478,7 +560,7 @@ void BSplineElements< Degree >::_addPeriodic( int offset , bool negate ) // If there is a change for additional overlap, give it a go if( set ) _addPeriodic< Left >( Left ? _RotateLeft( offset , res ) : _RotateRight( offset , res ) , negate ); } -template< int Degree > +template< unsigned int Degree > void BSplineElements< Degree >::upSample( BSplineElements< Degree >& high ) const { int bCoefficients[ BSplineSupportSizes< Degree >::UpSampleSize ]; @@ -507,11 +589,10 @@ void BSplineElements< Degree >::upSample( BSplineElements< Degree >& high ) cons high.denominator = denominator< +template< unsigned int Degree > template< unsigned int D > void BSplineElements< Degree >::differentiate( BSplineElements< Degree-D >& d ) const{ Differentiator< Degree , Degree-D >::Differentiate( *this , d ); } - -template< int Degree , int DDegree > +template< unsigned int Degree , unsigned int DDegree > void Differentiator< Degree , DDegree >::Differentiate( const BSplineElements< Degree >& bse , BSplineElements< DDegree >& dbse ) { BSplineElements< Degree-1 > _dbse; @@ -525,13 +606,12 @@ void Differentiator< Degree , DDegree >::Differentiate( const BSplineElements< D _dbse.denominator = bse.denominator; return Differentiator< Degree-1 , DDegree >::Differentiate( _dbse , dbse ); } - -template< int Degree > +template< unsigned int Degree > void Differentiator< Degree , Degree >::Differentiate( const BSplineElements< Degree >& bse , BSplineElements< Degree >& dbse ){ dbse = bse; } // If we were really good, we would implement this integral table to store // rational values to improve precision... -template< int Degree1 , int Degree2 > +template< unsigned int Degree1 , unsigned int Degree2 > void SetBSplineElementIntegrals( double integrals[Degree1+1][Degree2+1] ) { for( int i=0 ; i<=Degree1 ; i++ ) diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/BinaryNode.h b/modules/PoissonRecon/include/Mesh/PoissonRecon/BinaryNode.h new file mode 100644 index 00000000..e0561ae5 --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/BinaryNode.h @@ -0,0 +1,72 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +#ifndef BINARY_NODE_INCLUDED +#define BINARY_NODE_INCLUDED + +class BinaryNode +{ +public: + static inline 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< +struct BlockedVector +{ + BlockedVector( 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; + } + ~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; + _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 ) ); + } + 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( 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] ); + 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; + } + + 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 ) + { + 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; + } + size_t index = size-1; + size_t block = index >> LogBlockSize; + size_t blockIndex = index & _Mask; + + // 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 ) + { + 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; + } + _size = index+1; + return index; + } + size_t push( void ){ return resize( _size+1 ); } + +protected: + static const size_t _BlockSize = 1< +#include +#include +#include +#include + +#ifdef WIN32 +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; +}; + +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< 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 > +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 ); + +#include "Mesh/PoissonRecon/CmdLineParser.inl" +#endif // CMD_LINE_PARSER_INCLUDED diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/CmdLineParser.inl b/modules/PoissonRecon/include/Mesh/PoissonRecon/CmdLineParser.inl new file mode 100644 index 00000000..a27a91ec --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/CmdLineParser.inl @@ -0,0 +1,300 @@ +/* -*- C++ -*- +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +#include +#include + +#if defined( WIN32 ) || defined( _WIN64 ) +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; } +#if defined( WIN32 ) || defined( _WIN64 ) +template< > char* cmdLineCopy( char* t ){ return _strdup( t ); } +#else // !WIN32 && !_WIN64 +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 ) ); } +#if defined( WIN32 ) || defined( _WIN64 ) +template< > char* cmdLineStringToType( const char* str ){ return _strdup( str ); } +#else // !WIN32 && !_WIN64 +template< > char* cmdLineStringToType( const char* str ){ return strdup( str ); } +#endif // WIN32 || _WIN64 + + +///////////////////// +// cmdLineReadable // +///////////////////// +#if defined( WIN32 ) || defined( _WIN64 ) +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 ); } +#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; } + +////////////////////// +// cmdLineParameter // +////////////////////// +template< class Type > 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 > +int cmdLineParameter< Type >::read( char** argv , int argc ) +{ + if( argc>0 ) + { + cmdLineCleanUp< Type >( &value ) , value = cmdLineStringToType< Type >( argv[0] ); + set = true; + return 1; + } + else return 0; +} +template< class Type > +void cmdLineParameter< Type >::writeValue( char* str ) const { cmdLineWriteValue< Type >( value , str ); } + + +/////////////////////////// +// cmdLineParameterArray // +/////////////////////////// +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(); +} +template< class Type , int Dim > +cmdLineParameterArray< Type , Dim >::~cmdLineParameterArray( void ){ for( int i=0 ; i( 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] ); + set = true; + return Dim; + } + else return 0; +} +template< class Type , int Dim > +void cmdLineParameterArray< Type , Dim >::writeValue( char* str ) const +{ + char* temp=str; + for( int i=0 ; i( values[i] , temp ); + temp = str+strlen( str ); + } +} +/////////////////////// +// cmdLineParameters // +/////////////////////// +template< class Type > +cmdLineParameters< Type >::cmdLineParameters( const char* name ) : cmdLineReadable( name ) , values(NULL) , count(0) { } +template< class Type > +cmdLineParameters< Type >::~cmdLineParameters( void ) +{ + if( values ) delete[] values; + values = NULL; + count = 0; +} +template< class Type > +int cmdLineParameters< Type >::read( char** argv , int argc ) +{ + if( values ) delete[] values; + values = NULL; + + if( argc>0 ) + { + count = atoi(argv[0]); + if( count <= 0 || argc <= count ) return 1; + values = new Type[count]; + if( !values ) return 0; + for( int i=0 ; i( argv[i+1] ); + set = true; + return count+1; + } + else return 0; +} +template< class Type > +void cmdLineParameters< Type >::writeValue( char* str ) const +{ + char* temp=str; + for( int i=0 ; i( values[i] , temp ); + temp = str+strlen( str ); + } +} + + +inline char* FileExtension( char* fileName ) +{ + char* temp = fileName; + for( int i=0 ; i=0 ; i-- ) + if( fileName[i] =='\\' ) + { + fileName[i] = 0; + return fileName; + } + fileName[0] = 0; + return fileName; +} + +inline void cmdLineParse( int argc , char **argv , cmdLineReadable** params ) +{ + while( argc>0 ) + { + if( argv[0][0]=='-' && argv[0][1]=='-' ) + { + 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 ) + { + int j = readable->read( argv+1 , argc-1 ); + argv += j , argc -= j; + } + else + { + WARN( "Invalid option: " , argv[0] ); + for( int i=0 ; params[i]!=NULL ; i++ ) fprintf( stderr , "\t--%s\n" , params[i]->name ); + } + } + else WARN( "Parameter name should be of the form --: " , argv[0] ); + ++argv , --argc; + } +} + +inline char** ReadWords(const char* fileName,int& cnt) +{ + char** names; + char temp[500]; + FILE* fp; + + fp=fopen(fileName,"r"); + if(!fp){return NULL;} + cnt=0; + while(fscanf(fp," %s ",temp)==1){cnt++;} + fclose(fp); + + names=new char*[cnt]; + if(!names){return NULL;} + + fp=fopen(fileName,"r"); + if(!fp){ + delete[] names; + cnt=0; + return NULL; + } + cnt=0; + while(fscanf(fp," %s ",temp)==1){ + names[cnt]=new char[strlen(temp)+1]; + if(!names){ + for(int j=0;j +template< unsigned int ... FEMSigs , unsigned int PointD > +template< unsigned int _PointD > +CumulativeDerivativeValues< double , Dim , _PointD > FEMTree< Dim , Real >::_Evaluator< UIntPack< FEMSigs ... > , PointD >::_values( unsigned int d , const int fIdx[Dim] , const int cIdx[Dim] , const _CenterOffset off[Dim] , bool parentChild ) const +{ + double dValues[Dim][_PointD+1]; + _setDValues< _PointD >( d , fIdx , cIdx , off , parentChild , dValues ); + return Evaluate< Dim , double , _PointD >( dValues ); +} +template< unsigned int Dim , class Real > +template< unsigned int ... FEMSigs , unsigned int PointD > +template< unsigned int _PointD > +CumulativeDerivativeValues< double , Dim , _PointD > FEMTree< Dim , Real >::_Evaluator< UIntPack< FEMSigs ... > , PointD >::_centerValues( unsigned int d , const int fIdx[Dim] , const int cIdx[Dim] , bool parentChild ) const +{ + _CenterOffset off[Dim]; + for( int d=0 ; d( d , fIdx , cIdx , off , parentChild ); +} +template< unsigned int Dim , class Real > +template< unsigned int ... FEMSigs , unsigned int PointD > +template< unsigned int _PointD > +CumulativeDerivativeValues< double , Dim , _PointD > FEMTree< Dim , Real >::_Evaluator< UIntPack< FEMSigs ... > , PointD >::_cornerValues( unsigned int d , const int fIdx[Dim] , const int cIdx[Dim] , int corner , bool parentChild ) const +{ + _CenterOffset off[Dim]; + for( int d=0 ; d>d) & 1 ) ? FRONT : BACK; + return _values< _PointD >( d , fIdx , cIdx , off , parentChild ); +} + +template< unsigned int Dim , class Real > +template< unsigned int ... FEMSigs , unsigned int PointD > +void FEMTree< Dim , Real >::_Evaluator< UIntPack< FEMSigs ... > , PointD >::set( LocalDepth maxDepth ) +{ + typedef UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... > CenterSizes; + static const unsigned int LeftCenterRadii[] = { BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportEnd ... }; + typedef UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... > CornerSizes; + static const unsigned int LeftCornerRadii[] = { BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportEnd ... }; + typedef UIntPack< ( BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::BCornerSize + 1 ) ... > BCornerSizes; + static const unsigned int LeftBCornerRadii[] = { BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::BCornerEnd ... }; + + if( stencilData ) DeletePointer( stencilData ); + stencilData = NewPointer< StencilData >( maxDepth+1 ); + if( evaluators ) DeletePointer( evaluators ); + evaluators = NewPointer< Evaluators >( maxDepth+1 ); + if( childEvaluators ) DeletePointer( childEvaluators ); + childEvaluators = NewPointer< ChildEvaluators >( maxDepth+1 ); + _setEvaluators( maxDepth ); + for( int depth=0 ; depth<=maxDepth ; depth++ ) + { + int center = ( 1<>1; + int cIdx[Dim] , fIdx[Dim]; + for( int d=0 ; d::Run + ( + ZeroUIntPack< Dim >() , CenterSizes() , + [&]( int d , int i ){ fIdx[d] = center + i - LeftCenterRadii[d]; } , + [&]( CumulativeDerivativeValues< double , Dim , PointD >& p ){ p = _centerValues( depth , fIdx , cIdx , false ); } , + stencilData[depth].ccCenterStencil() + ); + // The corner stencil + for( int c=0 ; c<(1<::Run + ( + ZeroUIntPack< Dim >() , CornerSizes() , + [&]( int d , int i ){ fIdx[d] = center + i - LeftCornerRadii[d]; } , + [&]( CumulativeDerivativeValues< double , Dim , PointD >& p ){ p = _cornerValues( depth , fIdx , cIdx , c , false ); } , + stencilData[depth].ccCornerStencil[c]() + ); + // The boundary corner stencil + for( int c=0 ; c<(1<::Run + ( + ZeroUIntPack< Dim >() , BCornerSizes() , + [&]( int d , int i ){ fIdx[d] = center + i - LeftBCornerRadii[d]; } , + [&]( CumulativeDerivativeValues< double , Dim , PointD >& p ){ p = _cornerValues( depth , fIdx , cIdx , c , false ); } , + stencilData[depth].ccBCornerStencil[c]() + ); + } + + // Now set the stencils for the parents + for( int c=0 ; c<(1<>d) & 1 ); + + // The center stencil + WindowLoop< Dim >::Run + ( + ZeroUIntPack< Dim >() , CenterSizes() , + [&]( int d , int i ){ fIdx[d] = center/2 + i - LeftCenterRadii[d]; } , + [&]( CumulativeDerivativeValues< double , Dim , PointD >& p ){ p = _centerValues( depth , fIdx , cIdx , true ); } , + stencilData[depth].pcCenterStencils[c]() + ); + // The corner stencil + for( int cc=0 ; cc<(1<::Run + ( + ZeroUIntPack< Dim >() , CornerSizes() , + [&]( int d , int i ){ fIdx[d] = center/2 + i - LeftCornerRadii[d]; } , + [&]( CumulativeDerivativeValues< double , Dim , PointD >& p ){ p = _cornerValues( depth , fIdx , cIdx , cc , true ); } , + stencilData[depth].pcCornerStencils[c][cc]() + ); + // The boundary corner stencil + for( int cc=0 ; cc<(1<::Run + ( + ZeroUIntPack< Dim >() , BCornerSizes() , + [&]( int d , int i ){ fIdx[d] = center/2 + i - LeftBCornerRadii[d]; } , + [&]( CumulativeDerivativeValues< double , Dim , PointD >& p ){ p = _cornerValues( depth , fIdx , cIdx , cc , true ); } , + stencilData[depth].pcBCornerStencils[c][cc]() + ); + } + } + if( _pointEvaluator ) delete _pointEvaluator; + _pointEvaluator = new PointEvaluator< UIntPack< FEMSigs ... > , IsotropicUIntPack< Dim , PointD > >( maxDepth ); +} + +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 >::_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 +{ + typedef UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... > SupportSizes; + + if( IsActiveNode< Dim >( node->children ) && _localDepth( node->children )<=maxDepth ) WARN( "getValue assumes leaf node" ); + CumulativeDerivativeValues< V , Dim , _PointD > values; + + PointEvaluatorState< UIntPack< FEMSigs ... > , IsotropicUIntPack< Dim , _PointD > > state; + +#ifdef SHOW_WARNINGS +#pragma message ( "[WARNING] Nudging evaluation point into the interior" ) +#endif // SHOW_WARNINGS + for( int dd=0 ; dd& neighbors , ConstPointer( V ) coefficients ) + { + ConstPointer( FEMTreeNode * const ) nodes = neighbors.neighbors().data; + for( unsigned int i=0 ; i::Size ; i++ ) if( _isValidFEM1Node( nodes[i] ) ) + { + LocalDepth d ; LocalOffset off ; _localDepthAndOffset( nodes[i] , d , off ); + CumulativeDerivativeValues< Real , Dim , _PointD > _values = state.template dValues< Real , CumulativeDerivatives< Dim , _PointD > >( off ); + for( int d=0 ; d::Size ; d++ ) values[d] += coefficients[ nodes[i]->nodeData.nodeIndex ] * _values[d]; + } + }; + + LocalDepth depth = _localDepth( node ); + while( GetGhostFlag< Dim >( node ) ) node = node->parent , depth--; + + { + evaluator._pointEvaluator->initEvaluationState( p , depth , state ); + AddToValues( neighborKey.neighbors[ node->depth() ] , solution ); + if( depth>0 ) + { + evaluator._pointEvaluator->initEvaluationState( p , depth-1 , state ); + AddToValues( neighborKey.neighbors[ node->parent->depth() ] , coarseSolution ); + } + } + // If there could be finer neighbors whose support overlaps the point + if( depth<_maxDepth ) + { + typename FEMTreeNode::template ConstNeighbors< SupportSizes > cNeighbors; + int cIdx = 0; + Point< Real , Dim > c ; Real w; + _centerAndWidth( node , c , w ); + for( int d=0 ; dc[d] ) cIdx |= (1<depth() , cNeighbors ) ) + { + evaluator._pointEvaluator->initEvaluationState( p , depth+1 , state ); + AddToValues( cNeighbors , solution ); + } + } + return values; +} +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" ); + 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" ); + CumulativeDerivativeValues< V , Dim , _PointD > values; + + LocalDepth d ; LocalOffset cIdx; + _localDepthAndOffset( node , d , cIdx ); + + static const int corner = (1<::Degree >::SupportSize ... > loopData; + auto AddToValuesInterior = [&] + ( + unsigned int size , const unsigned int* indices , + const typename FEMTreeNode::template ConstNeighbors< SupportSizes >& neighbors , + const typename _Evaluator::CornerStencil& cornerStencil , + ConstPointer( V ) coefficients + ) + { + ConstPointer( FEMTreeNode * const ) nodes = neighbors.neighbors().data; + ConstPointer( CumulativeDerivativeValues< double , Dim , PointD > ) _values = cornerStencil().data; + for( unsigned int i=0 ; i( nodes[ idx ] ) ) for( int d=0 ; d::Size ; d++ ) values[d] += coefficients[ nodes[ idx ]->nodeData.nodeIndex ] * (Real)_values[ idx ][d]; + } + }; + auto AddToValuesExterior = [&] + ( + unsigned int size , const unsigned int* indices , + LocalDepth d , LocalOffset cIdx , + const typename FEMTreeNode::template ConstNeighbors< SupportSizes >& neighbors , + ConstPointer( V ) coefficients , bool parent + ) + { + ConstPointer( FEMTreeNode * const ) nodes = neighbors.neighbors().data; + for( unsigned int i=0 ; i( nodes[ idx ] ) ) + { + LocalDepth _d ; LocalOffset fIdx; + this->_localDepthAndOffset( nodes[idx] , _d , fIdx ); + CumulativeDerivativeValues< double , Dim , _PointD > _values = evaluator.template _cornerValues< _PointD >( d , fIdx , cIdx , corner , parent ); + for( int d=0 ; d::Size ; d++ ) values[d] += coefficients[ nodes[ idx ]->nodeData.nodeIndex ] * (Real)_values[d]; + } + } + }; + + if( isInterior ) + { + auto AddToValues = [&] + ( + const typename FEMTreeNode::template ConstNeighbors< SupportSizes >& neighbors , + const typename _Evaluator::CenterStencil& centerStencil , + ConstPointer( V ) coefficients + ) + { + ConstPointer( FEMTreeNode * const ) nodes = neighbors.neighbors().data; + ConstPointer( CumulativeDerivativeValues< double , Dim , PointD > ) _values = centerStencil.data; + for( int i=0 ; i::Size ; i++ ) if( _isValidFEM1Node( nodes[i] ) ) + for( int d=0 ; d::Size ; d++ ) values[d] += coefficients[ nodes[i]->nodeData.nodeIndex ] * (Real)_values[i][d]; + }; + AddToValues( neighborKey.neighbors[ node->depth() ] , evaluator.stencilData[d].ccCenterStencil , solution ); + if( d>0 ) + { + int _corner = int( node - node->parent->children ); + AddToValues( neighborKey.neighbors[ node->parent->depth() ] , evaluator.stencilData[d].pcCenterStencils[_corner] , coarseSolution ); + } + } + else + { + auto AddToValues = [&]( const typename FEMTreeNode::template ConstNeighbors< SupportSizes >& neighbors , ConstPointer( V ) coefficients , bool parentChild ) + { + ConstPointer( FEMTreeNode * const ) nodes = neighbors.neighbors().data; + for( int i=0 ; i::Size ; i++ ) if( _isValidFEM1Node( nodes[i] ) ) + { + LocalDepth _d ; LocalOffset fIdx; + _localDepthAndOffset( nodes[i] , _d , fIdx ); + const CumulativeDerivativeValues< double , Dim , _PointD >& _values = evaluator.template _centerValues< _PointD >( d , fIdx , cIdx , parentChild ); + for( int d=0 ; d::Size ; d++ ) values[d] += coefficients[ nodes[i]->nodeData.nodeIndex ] * (Real)_values[d]; + } + }; + + AddToValues( neighborKey.neighbors[ node->depth() ] , solution , false ); + if( d>0 ) AddToValues( neighborKey.neighbors[ node->parent->depth() ] , coarseSolution , true ); + } + // If there could be finer neighbors whose support overlaps the point + if( d<_maxDepth ) + { + typename FEMTreeNode::template ConstNeighbors< SupportSizes > cNeighbors; + if( neighborKey.getChildNeighbors( 0 , node->depth() , cNeighbors ) ) + { + if( isInterior ) AddToValuesInterior( loopData.ccSize[corner] , loopData.ccIndices[corner] , cNeighbors , evaluator.stencilData[d+1].ccCornerStencil[corner] , solution ); + else + { + LocalDepth _d=d+1 ; LocalOffset _cIdx; + for( int d=0 ; d +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" ); + typedef _Evaluator< UIntPack< FEMSigs ... > , PointD > _Evaluator; + typedef UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... > SupportSizes; + static const unsigned int supportSizes[] = { BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... }; + + CumulativeDerivativeValues< V , Dim , _PointD > values; + LocalDepth d ; LocalOffset cIdx; + _localDepthAndOffset( node , d , cIdx ); + + static const CornerLoopData< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... > loopData; + { + auto AddToValuesInterior = [&] + ( + unsigned int size , const unsigned int* indices , + const typename FEMTreeNode::template ConstNeighbors< SupportSizes >& neighbors , + const typename _Evaluator::CornerStencil& cornerStencil , + ConstPointer( V ) coefficients + ) + { + ConstPointer( FEMTreeNode * const ) nodes = neighbors.neighbors().data; + ConstPointer( CumulativeDerivativeValues< double , Dim , PointD > ) _values = cornerStencil().data; + for( unsigned int i=0 ; i( nodes[ idx ] ) ) for( int d=0 ; d::Size ; d++ ) values[d] += coefficients[ nodes[ idx ]->nodeData.nodeIndex ] * (Real)_values[ idx ][d]; + } + }; + auto AddToValuesExterior = [&] + ( + unsigned int size , const unsigned int* indices , + LocalDepth d , LocalOffset cIdx , + const typename FEMTreeNode::template ConstNeighbors< SupportSizes >& neighbors , + ConstPointer( V ) coefficients , bool parent + ) + { + ConstPointer( FEMTreeNode * const ) nodes = neighbors.neighbors().data; + for( unsigned int i=0 ; i( nodes[ idx ] ) ) + { + LocalDepth _d ; LocalOffset fIdx; + this->_localDepthAndOffset( nodes[idx] , _d , fIdx ); + CumulativeDerivativeValues< double , Dim , _PointD > _values = evaluator.template _cornerValues< _PointD >( d , fIdx , cIdx , corner , parent ); + for( int d=0 ; d::Size ; d++ ) values[d] += coefficients[ nodes[ idx ]->nodeData.nodeIndex ] * (Real)_values[d]; + } + } + }; + if( isInterior ) AddToValuesInterior( loopData.ccSize[corner] , loopData.ccIndices[corner] , neighborKey.neighbors[ node->depth() ] , evaluator.stencilData[d].ccCornerStencil[corner] , solution ); + else AddToValuesExterior( loopData.ccSize[corner] , loopData.ccIndices[corner] , d , cIdx , neighborKey.neighbors[ node->depth() ] , solution , false ); + if( d>0 ) + { + int _corner = int( node - node->parent->children ); + if( isInterior ) AddToValuesInterior( loopData.pcSize[corner][_corner] , loopData.pcIndices[corner][_corner] , neighborKey.neighbors[ node->parent->depth() ] , evaluator.stencilData[d].pcCornerStencils[_corner][corner] , coarseSolution ); + else AddToValuesExterior( loopData.pcSize[corner][_corner] , loopData.pcIndices[corner][_corner] , d , cIdx , neighborKey.neighbors[ node->parent->depth() ] , coarseSolution , true ); + } + // If there could be finer neighbors whose support overlaps the point + if( d<_maxDepth ) + { + typename FEMTreeNode::template ConstNeighbors< SupportSizes > cNeighbors; + if( neighborKey.getChildNeighbors( corner , node->depth() , cNeighbors ) ) + { + if( isInterior ) AddToValuesInterior( loopData.ccSize[corner] , loopData.ccIndices[corner] , cNeighbors , evaluator.stencilData[d+1].ccCornerStencil[corner] , solution ); + else + { + LocalDepth _d=d+1 ; LocalOffset _cIdx; + for( int d=0 ; d +template< class V , unsigned int _PointD , unsigned int ... FEMSigs , unsigned int PointD > +CumulativeDerivativeValues< V , Dim , _PointD > FEMTree< Dim , Real >::_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 +{ + typedef _Evaluator< UIntPack< FEMSigs ... > , PointD > _Evaluator; + + typedef UIntPack< ( BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::BCornerSize + 1 ) ... > BCornerSizes; + static const unsigned int bCornerSizes[] = { ( BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::BCornerSize + 1 ) ... }; + CumulativeDerivativeValues< V , Dim , _PointD > values; + LocalDepth d ; LocalOffset cIdx; + _localDepthAndOffset( node , d , cIdx ); + + static const CornerLoopData< ( BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::BCornerSize + 1 ) ... > loopData; + + { + auto AddToValuesInterior = [&] + ( + unsigned int size , const unsigned int* indices , + const typename FEMTreeNode::template ConstNeighbors< BCornerSizes >& neighbors , + const typename _Evaluator::BCornerStencil& cornerStencil , + ConstPointer( V ) coefficients + ) + { + ConstPointer( FEMTreeNode * const ) nodes = neighbors.neighbors().data; + ConstPointer( CumulativeDerivativeValues< double , Dim , PointD > ) _values = cornerStencil().data; + for( unsigned int i=0 ; i( nodes[ idx ] ) ) for( int d=0 ; d::Size ; d++ ) values[d] += coefficients[ nodes[ idx ]->nodeData.nodeIndex ] * (Real)_values[ idx ][d]; + } + }; + auto AddToValuesExterior = [&] + ( + unsigned int size , const unsigned int* indices , + LocalDepth d , LocalOffset cIdx , + const typename FEMTreeNode::template ConstNeighbors< BCornerSizes >& neighbors , + ConstPointer( V ) coefficients , bool parent + ) + { + ConstPointer( FEMTreeNode * const ) nodes = neighbors.neighbors().data; + for( unsigned int i=0 ; i( nodes[ idx ] ) ) + { + LocalDepth _d ; LocalOffset fIdx; + _localDepthAndOffset( nodes[idx] , _d , fIdx ); + CumulativeDerivativeValues< double , Dim , _PointD > _values = evaluator.template _cornerValues< _PointD >( d , fIdx , cIdx , corner , parent ); + for( int d=0 ; d::Size ; d++ ) values[d] += coefficients[ nodes[idx]->nodeData.nodeIndex ] * (Real)_values[d]; + } + } + }; + if( isInterior ) AddToValuesInterior( loopData.ccSize[corner] , loopData.ccIndices[corner] , neighborKey.neighbors[ node->depth() ] , evaluator.stencilData[d].ccBCornerStencil[corner] , solution ); + else AddToValuesExterior( loopData.ccSize[corner] , loopData.ccIndices[corner] , d , cIdx , neighborKey.neighbors[ node->depth() ] , solution , false ); + if( d>0 ) + { + int _corner = int( node - node->parent->children ); + if( isInterior ) AddToValuesInterior( loopData.pcSize[corner][_corner] , loopData.pcIndices[corner][_corner] , neighborKey.neighbors[ node->parent->depth() ] , evaluator.stencilData[d].pcBCornerStencils[_corner][corner] , coarseSolution ); + else AddToValuesExterior( loopData.pcSize[corner][_corner] , loopData.pcIndices[corner][_corner] , d , cIdx , neighborKey.neighbors[ node->parent->depth() ] , coarseSolution , true ); + } + // If there could be finer neighbors whose support overlaps the point + if( d<_maxDepth ) + { + typename FEMTreeNode::template ConstNeighbors< BCornerSizes > cNeighbors; + if( neighborKey.getChildNeighbors( corner , node->depth() , cNeighbors ) ) + { + if( isInterior ) AddToValuesInterior( loopData.ccSize[corner] , loopData.ccIndices[corner] , cNeighbors , evaluator.stencilData[d+1].ccBCornerStencil[corner] , solution ); + else + { + LocalDepth _d=d+1 ; LocalOffset _cIdx; + for( int d=0 ; d +template< unsigned int ... FEMSigs , unsigned int PointD , typename T > +FEMTree< Dim , Real >::_MultiThreadedEvaluator< UIntPack< FEMSigs ... > , PointD , T >::_MultiThreadedEvaluator( const FEMTree< Dim , Real >* tree , const DenseNodeData< T , FEMSignatures >& coefficients , int threads ) : _coefficients( coefficients ) , _tree( tree ) +{ + tree->_setFEM1ValidityFlags( UIntPack< FEMSigs ... >() ); + _threads = std::max< int >( 1 , threads ); + _pointNeighborKeys.resize( _threads ); + _cornerNeighborKeys.resize( _threads ); + _coarseCoefficients = _tree->template coarseCoefficients< T >( _coefficients ); + _evaluator.set( _tree->_maxDepth ); + for( int t=0 ; t<_pointNeighborKeys.size() ; t++ ) _pointNeighborKeys[t].set( tree->_localToGlobal( _tree->_maxDepth ) ); + for( int t=0 ; t<_cornerNeighborKeys.size() ; t++ ) _cornerNeighborKeys[t].set( tree->_localToGlobal( _tree->_maxDepth ) ); +} +template< unsigned int Dim , class Real > +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( !node ) node = _tree->leaf( p ); + ConstPointSupportKey< FEMDegrees >& nKey = _pointNeighborKeys[thread]; + nKey.getNeighbors( node ); + return _tree->template _getValues< T , _PointD >( nKey , node , p , _coefficients() , _coarseCoefficients() , _evaluator , _tree->_maxDepth ); +} +template< unsigned int Dim , class Real > +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 ); + ConstPointSupportKey< FEMDegrees >& nKey = _pointNeighborKeys[thread]; + nKey.getNeighbors( node ); + LocalDepth d ; LocalOffset off; + _tree->_localDepthAndOffset( node->parent , d , off ); + return _tree->template _getCenterValues< T , _PointD >( nKey , node , _coefficients() , _coarseCoefficients() , _evaluator , _tree->_maxDepth , BaseFEMIntegrator::IsInteriorlySupported( UIntPack< FEMSigs ... >() , d , off ) ); +} +template< unsigned int Dim , class Real > +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 ); + ConstCornerSupportKey< FEMDegrees >& nKey = _cornerNeighborKeys[thread]; + nKey.getNeighbors( node ); + LocalDepth d ; LocalOffset off; + _tree->_localDepthAndOffset( node->parent , d , off ); + return _tree->template _getCornerValues< T , _PointD >( nKey , node , corner , _coefficients() , _coarseCoefficients() , _evaluator , _tree->_maxDepth , BaseFEMIntegrator::IsInteriorlySupported( UIntPack< FEMSigs ... >() , d , off ) ); +} + + + +template< unsigned int Dim , class Real > +template< class V , class Coefficients , unsigned int D , unsigned int ... DataSigs > +V FEMTree< Dim , Real >::_evaluate( const Coefficients& coefficients , Point< Real , Dim > p , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey ) const +{ + typedef UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportSize ... > SupportSizes; + PointEvaluatorState< UIntPack< DataSigs ... > , ZeroUIntPack< Dim > > state; + unsigned int derivatives[Dim]; + memset( derivatives , 0 , sizeof( derivatives ) ); + typedef PointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > > DataKey; + V value = V(); + + for( int d=_localToGlobal( 0 ) ; d<=dataKey.depth() ; d++ ) + { + { + 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" ); + pointEvaluator.initEvaluationState( p , _localDepth( node ) , state ); + } + double scratch[Dim+1]; + scratch[0] = 1; + ConstPointer( FEMTreeNode * const ) nodes = dataKey.neighbors[d].neighbors().data; + for( int i=0 ; i::Size ; i++ ) if( _isValidFEM1Node( nodes[i] ) ) + { + const V* v = coefficients( nodes[i] ); + if( v ) + { + LocalDepth d ; LocalOffset off ; _localDepthAndOffset( nodes[i] , d , off ); + value += (*v) * (Real)state.value( off , derivatives ); + } + } + } + + return value; +} + +template< unsigned int Dim , class Real > +template< bool XMajor , class V , unsigned int ... DataSigs > +Pointer( V ) FEMTree< Dim , Real >::regularGridEvaluate( const DenseNodeData< V , UIntPack< DataSigs ... > >& coefficients , int& res , LocalDepth depth , bool primal ) const +{ + if( depth<=0 ) 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 ) ) ... }; + + res = 1<( 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] && iivalue( 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] && iivalue( 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 +{ + if( depth<=0 ) depth = _maxDepth; + int begin[Dim] , end[Dim]; + FEMIntegrator::BSplineBegin( UIntPack< DataSigs ... >() , depth , begin ); + FEMIntegrator::BSplineEnd ( UIntPack< DataSigs ... >() , depth , end ); + return regularGridUpSample< XMajor >( coefficients , begin , end , depth ); +} +template< unsigned int Dim , class Real > +template< bool XMajor , class V , unsigned int ... DataSigs > +Pointer( V ) FEMTree< Dim , Real >::regularGridUpSample( const DenseNodeData< V , UIntPack< DataSigs ... > >& coefficients , const int begin[Dim] , const int end[Dim] , LocalDepth depth ) const +{ + if( depth<=0 ) depth = _maxDepth; + + static const int DownSampleStart[][sizeof...(DataSigs)] = { { BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::DownSampleStart[0] ... } , { BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::DownSampleStart[1] ... } }; + static const int DownSampleEnd [][sizeof...(DataSigs)] = { { BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::DownSampleEnd [0] ... } , { BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::DownSampleEnd [1] ... } }; + + struct GridDimensions + { + int begin[Dim] , end[Dim] , dim[Dim]; + int dimMultiplier[Dim]; + GridDimensions( void ){ } + GridDimensions( const int b[Dim] , const int e[Dim] ) + { + memcpy( begin , b , sizeof(begin) ); + memcpy( end , e , sizeof(end) ); + for( int d=0 ; d=0 ; d-- ) dimMultiplier[d] = dimMultiplier[d+1] * dim[d+1]; + } + } + }; + + auto SetCoarseGridDimensions = []( const GridDimensions& fine , GridDimensions& coarse , int lowDepth ) + { + int begin[Dim] , end[Dim]; + FEMIntegrator::BSplineBegin( UIntPack< DataSigs ... >() , lowDepth , begin ); + FEMIntegrator::BSplineEnd ( UIntPack< DataSigs ... >() , lowDepth , end ); + for( int d=0 ; d( begin[d] , (fine.begin[d]>>1) + DownSampleStart[fine.begin[d]&1][d] ); + coarse.end [d] = std::min< int >( end [d] , (fine.end [d]>>1) + DownSampleEnd [fine.end [d]&1][d]+1 ); + coarse.dim [d] = coarse.end[d] - coarse.begin[d]; + } + if( XMajor ) + { + coarse.dimMultiplier[0] = 1; + for( int d=1 ; d=0 ; d-- ) coarse.dimMultiplier[d] = coarse.dimMultiplier[d+1] * coarse.dim[d+1]; + } + }; + auto InBounds = []( const LocalOffset& off , const GridDimensions& gDim ) + { + for( int d=0 ; d=gDim.end[d] ) return false; + return true; + }; + + std::vector< GridDimensions > gridDimensions( depth+1 ); + gridDimensions[depth] = GridDimensions( begin , end ); + for( int d=depth ; d>0 ; d-- ) SetCoarseGridDimensions( gridDimensions[d] , gridDimensions[d-1] , d-1 ); + + // Initialize the coefficients at the coarsest level + Pointer( V ) upSampledCoefficients = NullPointer( V ); + { + LocalDepth _depth = 0; + size_t count = 1; + for( int dd=0 ; dd( count ); + memset( upSampledCoefficients , 0 , sizeof( V ) * count ); + ThreadPool::Parallel_for( _sNodesBegin(_depth) , _sNodesEnd(_depth) , [&]( unsigned int , size_t i ) + { + if( !_outOfBounds( UIntPack< DataSigs ... >() , _sNodes.treeNodes[i] ) ) + { + LocalDepth _d ; LocalOffset _off; + _localDepthAndOffset( _sNodes.treeNodes[i] , _d , _off ); + if( InBounds( _off , gridDimensions[_depth] ) ) + { + size_t idx = 0; + for( int d=0 ; d( count ); + memset( _coefficients , 0 , sizeof( V ) * count ); + if( _depth<=_maxDepth ) + ThreadPool::Parallel_for( _sNodesBegin(_depth) , _sNodesEnd(_depth) , [&]( unsigned int , size_t i ) + { + if( !_outOfBounds( UIntPack< DataSigs ... >() , _sNodes.treeNodes[i] ) ) + { + LocalDepth _d ; LocalOffset _off; + _localDepthAndOffset( _sNodes.treeNodes[i] , _d , _off ); + if( InBounds( _off , gridDimensions[_depth] ) ) + { + size_t idx = 0; + for( int d=0 ; d( UIntPack< DataSigs ... >() , gridDimensions[_depth-1].begin , gridDimensions[_depth-1].end , gridDimensions[_depth].begin , gridDimensions[_depth].end , _depth , ( ConstPointer(V) )upSampledCoefficients , _coefficients ); + DeletePointer( upSampledCoefficients ); + upSampledCoefficients = _coefficients; + } + return upSampledCoefficients; +} +template< unsigned int Dim , class Real > +template< class V , unsigned int ... DataSigs > +V FEMTree< Dim , Real >::average( const DenseNodeData< V , UIntPack< DataSigs ... > >& coefficients ) const +{ + Real begin[Dim] , end[Dim]; + for( int d=0 ; d +template< class V , unsigned int ... DataSigs > +V FEMTree< Dim , Real >::average( const DenseNodeData< V , UIntPack< DataSigs ... > >& coefficients , const Real begin[Dim] , const Real end[Dim] ) const +{ + _setFEM1ValidityFlags( UIntPack< DataSigs ... >() ); + std::vector< V > avgs( ThreadPool::NumThreads() ); + for( int i=0 ; i>1; + int off[Dim]; + 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 ) + { + if( _isValidFEM1Node( _sNodes.treeNodes[i] ) ) + { + int d , off[Dim]; + _localDepthAndOffset( _sNodes.treeNodes[i] , d , off ); + if( BaseFEMIntegrator::IsInteriorlySupported( UIntPack< FEMSignature< DataSigs >::Degree ... >() , d , off , _begin , _end ) ) avgs[ thread ] += (V)( coefficients[i] * (Real)integral ); + } + } + ); + } + V avg = {}; + for( int i=0 ; i +template< unsigned int PointD , unsigned int ... FEMSigs > +SparseNodeData< CumulativeDerivativeValues< Real , Dim , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > FEMTree< Dim , Real >::leafValues( const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , int maxDepth ) const +{ + if( maxDepth<0 ) maxDepth = _maxDepth; + _setFEM1ValidityFlags( UIntPack< FEMSigs ... >() ); + SparseNodeData< CumulativeDerivativeValues< Real , Dim , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > values; + DenseNodeData< Real , UIntPack< FEMSigs ... > > _coefficients = coarseCoefficients< Real >( coefficients ); + _Evaluator< UIntPack< FEMSigs ... > , PointD > evaluator; + evaluator.set( maxDepth ); + for( LocalDepth d=maxDepth ; d>=0 ; d-- ) + { + std::vector< ConstPointSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > > > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i::Degree ... > >& neighborKey = neighborKeys[ thread ]; + FEMTreeNode* node = _sNodes.treeNodes[i]; + if( !IsActiveNode< Dim >( node->children ) || d==maxDepth ) + { + neighborKey.getNeighbors( node ); + bool isInterior = _isInteriorlySupported( UIntPack< FEMSignature< FEMSigs >::Degree ... >() , node->parent ); + values[ node ] = _getCenterValues< Real , PointD >( neighborKey , node , coefficients() , _coefficients() , evaluator , maxDepth , isInterior ); + } + } + } + ); + } + return values; +} diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/FEMTree.Initialize.inl b/modules/PoissonRecon/include/Mesh/PoissonRecon/FEMTree.Initialize.inl new file mode 100644 index 00000000..df0e156d --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/FEMTree.Initialize.inl @@ -0,0 +1,646 @@ +/* +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. +*/ + +//////////////////////// +// 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 count = 0; + int d , off[3]; + node.depthAndOffset( d , off ); + if( node.depth()( nodeAllocator , NodeInitializer ) , count += 1< +size_t FEMTreeInitializer< Dim , Real >::Initialize( FEMTreeNode& root , InputPointStream< Real , Dim >& pointStream , int maxDepth , std::vector< PointSample >& samplePoints , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ) +{ + 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; +} + +template< unsigned int Dim , class Real > +template< class Data > +size_t FEMTreeInitializer< Dim , Real >::Initialize( FEMTreeNode& root , InputPointStreamWithData< Real , Dim , Data >& pointStream , int maxDepth , std::vector< PointSample >& samplePoints , std::vector< Data >& sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim >& , Data& ) > 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 , badData = 0 , pointCount = 0; + { + std::vector< node_index_type > nodeToIndexMap; + Point< Real , Dim > p; + Data d; + + while( pointStream.nextPoint( p , d ) ) + { + Real weight = ProcessData( p , d ); + if( weight<=0 ){ badData++ ; continue; } + FEMTreeNode* temp = Leaf( root , p , maxDepth ); + if( !temp ){ outOfBoundPoints++ ; continue; } + node_index_type nodeIndex = temp->nodeData.nodeIndex; + if( mergeNodeSamples ) + { + 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; + sampleData.resize( idx+1 ); + } + samplePoints[idx].sample += ProjectiveData< Point< Real , Dim > , Real >( p*weight , weight ); + sampleData[ idx ] += d*weight; + } + else + { + node_index_type idx = (node_index_type)samplePoints.size(); + samplePoints.resize( idx+1 ) , sampleData.resize( idx+1 ); + samplePoints[idx].node = temp; + samplePoints[idx].sample = ProjectiveData< Point< Real , Dim > , Real >( p*weight , weight ); + sampleData[ idx ] = d*weight; + } + pointCount++; + } + 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 ) +{ + std::vector< node_index_type > nodeToIndexMap; + ThreadPool::Parallel_for( 0 , simplices.size() , [&]( unsigned int t , size_t i ) + { + Simplex< Real , Dim , Dim-1 > s; + for( int k=0 ; k( root , s , maxDepth , samples , &nodeToIndexMap , nodeAllocators.size() ? nodeAllocators[t] : NULL , NodeInitializer ); + else _AddSimplex< true >( root , s , maxDepth , samples , NULL , nodeAllocators.size() ? nodeAllocators[t] : NULL , NodeInitializer ); + } + ); + FEMTree< Dim , Real >::MemoryUsage(); +} + +template< unsigned int Dim , class Real > +template< bool ThreadSafe > +size_t FEMTreeInitializer< Dim , Real >::_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 ) +{ + std::vector< Simplex< Real , Dim , Dim-1 > > subSimplices; + subSimplices.push_back( s ); + + // Clip the simplex to the unit cube + { + for( int d=0 ; d n; + n[d] = 1; + { + std::vector< Simplex< Real , Dim , Dim-1 > > back , front; + for( int i=0 ; i > back , front; + for( int i=0 ; i p , int maxDepth ) + { + for( int d=0 ; d1 ) return (FEMTreeNode*)NULL; + 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; + d++; + width /= 2; + for( int d=0 ; d>d) & 1 ) center[d] += width/2; + else center[d] -= width/2; + } + return node; + }; + + size_t sCount = 0; + for( int i=0 ; i( Leaf( subSimplices[i].center() , tDepth ) , subSimplices[i] , maxDepth , samples , nodeToIndexMap , nodeAllocator , NodeInitializer ); + } + return sCount; +} + +template< unsigned int Dim , class Real > +template< bool ThreadSafe > +size_t FEMTreeInitializer< Dim , Real >::_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 ) +{ + int d = node->depth(); + if( d==maxDepth ) + { + Real weight = s.measure(); + Point< Real , Dim > position = s.center() , normal; + { + Point< Real , Dim > v[Dim-1]; + for( int k=0 ; k::CrossProduct( v ); + } + if( weight && weight==weight ) + { + if( nodeToIndexMap ) + { + node_index_type nodeIndex = node->nodeData.nodeIndex; + { + static std::mutex m; + std::lock_guard< std::mutex > lock(m); + 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)samples.size(); + (*nodeToIndexMap)[ nodeIndex ] = idx; + samples.resize( idx+1 ); + samples[idx].node = node; + } + samples[idx].sample += ProjectiveData< Point< Real , Dim > , Real >( position*weight , weight ); + } + } + else + { + { + static std::mutex m; + std::lock_guard< std::mutex > lock(m); + node_index_type idx = (node_index_type)samples.size(); + samples.resize( idx+1 ); + samples[idx].node = node; + samples[idx].sample = ProjectiveData< Point< Real , Dim > , Real >( position*weight , weight ); + } + } + } + return 1; + } + else + { + size_t sCount = 0; + if( !node->children ) node->template initChildren< ThreadSafe >( nodeAllocator , NodeInitializer ); + + // Split up the simplex and pass the parts on to the children + Point< Real , Dim > center; + Real width; + node->centerAndWidth( center , width ); + + std::vector< std::vector< Simplex< Real , Dim , Dim-1 > > > childSimplices( 1 ); + childSimplices[0].push_back( s ); + for( int d=0 ; d n ; n[Dim-d-1] = 1; + std::vector< std::vector< Simplex< Real , Dim , Dim-1 > > > temp( (int)( 1<<(d+1) ) ); + for( int c=0 ; c<(1<( node->children+c , childSimplices[c][i] , maxDepth , samples , nodeToIndexMap , nodeAllocator , NodeInitializer ); + return sCount; + } +} + +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< NodeSimplices< Dim , Real > >& nodeSimplices , Allocator< FEMTreeNode > *nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ) +{ + std::vector< size_t > nodeToIndexMap; + for( size_t i=0 ; i s; + for( int k=0 ; k( root , s , maxDepth , nodeSimplices , nodeToIndexMap , nodeAllocator , NodeInitializer ); + } + FEMTree< Dim , Real >::MemoryUsage(); +} + +template< unsigned int Dim , class Real > +template< bool ThreadSafe > +size_t FEMTreeInitializer< Dim , Real >::_AddSimplex( FEMTreeNode& root , 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 ) +{ + std::vector< Simplex< Real , Dim , Dim-1 > > subSimplices; + subSimplices.push_back( s ); + + // Clip the simplex to the unit cube + { + for( int d=0 ; d n; + n[d] = 1; + { + std::vector< Simplex< Real , Dim , Dim-1 > > back , front; + for( size_t i=0 ; i > back , front; + for( size_t i=0 ; i p , int maxDepth ) + { + for( int d=0 ; d1 ) return (FEMTreeNode*)NULL; + 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; + d++; + width /= 2; + for( int d=0 ; d>d) & 1 ) center[d] += width/2; + else center[d] -= width/2; + } + return node; + }; + + size_t sCount = 0; + + for( size_t i=0 ; i( subSimplexNode , subSimplices[i] , maxDepth , simplices , nodeToIndexMap , nodeAllocator , NodeInitializer ); + } + return sCount; +} +template< unsigned int Dim , class Real > +template< bool ThreadSafe > +size_t FEMTreeInitializer< Dim , Real >::_AddSimplex( FEMTreeNode* node , 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 ) +{ + int d = node->depth(); + if( d==maxDepth ) + { + // If the simplex has non-zero size, add it to the list + Real weight = s.measure(); + if( weight && weight==weight ) + { + node_index_type nodeIndex = node->nodeData.nodeIndex; + if( nodeIndex>=nodeToIndexMap.size() ) nodeToIndexMap.resize( nodeIndex+1 , -1 ); + node_index_type idx = nodeToIndexMap[ nodeIndex ]; + if( idx==-1 ) + { + idx = (node_index_type)simplices.size(); + nodeToIndexMap[ nodeIndex ] = idx; + simplices.resize( idx+1 ); + simplices[idx].node = node; + } + simplices[idx].data.push_back( s ); + } + return 1; + } + else + { + size_t sCount = 0; + if( !node->children ) node->template initChildren< ThreadSafe >( nodeAllocator , NodeInitializer ); + + // Split up the simplex and pass the parts on to the children + Point< Real , Dim > center; + Real width; + node->centerAndWidth( center , width ); + + std::vector< std::vector< Simplex< Real , Dim , Dim-1 > > > childSimplices( 1 ); + childSimplices[0].push_back( s ); + for( int d=0 ; d n ; n[Dim-d-1] = 1; + std::vector< std::vector< Simplex< Real , Dim , Dim-1 > > > temp( (int)( 1<<(d+1) ) ); + for( int c=0 ; c<(1<( node->children+c , childSimplices[c][i] , maxDepth , simplices , nodeToIndexMap , nodeAllocator , NodeInitializer ); + return sCount; + } +} + +template< unsigned int Dim , class Real > +template< class Data , class _Data , bool Dual > +size_t FEMTreeInitializer< Dim , Real >::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 ) +{ + auto Leaf = [&]( FEMTreeNode& root , const int idx[Dim] , int maxDepth ) + { + for( int d=0 ; d=(1<children ) node->template initChildren< false >( nodeAllocator , NodeInitializer ); + int cIndex = 0; + for( int dd=0 ; ddchildren + cIndex; + } + return node; + }; + auto FactorIndex = []( size_t i , const int resolution[Dim] , int idx[Dim] ) + { + size_t ii = i; + for( int d=0 ; d( maxResolution , resolution[d] ); + int maxDepth = 0; + while( ( (1<=0 && labels[ii]>=0 ) + { + if( !Dual ) idx[d]--; + NodeSample< Dim , _Data > nodeSample; + nodeSample.node = Leaf( root , idx , maxDepth ); + nodeSample.data = DataConverter( values[ii] ) - DataConverter( values[i] ); + if( nodeSample.node ) derivatives[d].push_back( nodeSample ); + } + } + } + return maxDepth; +} + +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 ) +{ + // Note: + // -- Dual: The difference between [i] and [i+1] is stored at cell [i+1] + // -- Primal: The difference between [i] and [i+1] is stored at cell [i] + + // Find the leaf containing the specified cell index + auto Leaf = [&]( FEMTreeNode& root , const unsigned int idx[Dim] , unsigned int maxDepth ) + { + for( int d=0 ; d=(unsigned int)(1<children ) node->template initChildren< false >( nodeAllocator , NodeInitializer ); + int cIndex = 0; + for( int dd=0 ; ddchildren + cIndex; + } + return node; + }; + + unsigned int resolution[Dim]; + dStream.resolution( resolution ); + unsigned int maxResolution = resolution[0]; + for( int d=1 ; d( maxResolution , resolution[d] ); + unsigned int maxDepth = 0; + + // If we are using a dual formulation, we need at least maxResolution cells. + // Otherwise, we need at least maxResolution-1 cells. + while( (unsigned int)( (1< nodeSample; + nodeSample.node = Leaf( root , idx , maxDepth ); + nodeSample.data = dValue; + if( nodeSample.node ) derivatives[dir].push_back( nodeSample ); + } + return maxDepth; +} diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/FEMTree.IsoSurface.specialized.inl b/modules/PoissonRecon/include/Mesh/PoissonRecon/FEMTree.IsoSurface.specialized.inl new file mode 100644 index 00000000..d7e7f2c8 --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/FEMTree.IsoSurface.specialized.inl @@ -0,0 +1,1879 @@ +/* +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 "Mesh/PoissonRecon/MyMiscellany.h" +#include "Mesh/PoissonRecon/MarchingCubes.h" +#include "Mesh/PoissonRecon/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 unsigned int CellOffset[ HyperCube::Cube< D >::template ElementNum< K >() ][ HyperCube::Cube< D >::template IncidentCubeNum< K >() ]; + static unsigned int IncidentElementCoIndex[ HyperCube::Cube< D >::template ElementNum< K >() ][ HyperCube::Cube< D >::template IncidentCubeNum< K >() ]; + static unsigned int CellOffsetAntipodal[ HyperCube::Cube< D >::template ElementNum< K >() ]; + static typename HyperCube::Cube< D >::template IncidentCubeIndex< K > IncidentCube[ HyperCube::Cube< D >::template ElementNum< K >() ]; + static typename HyperCube::Direction Directions[ HyperCube::Cube< D >::template ElementNum< K >() ][ 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 typename HyperCube::Cube< D >::template Element< K2 > OverlapElements[ HyperCube::Cube< D >::template ElementNum< K1 >() ][ HyperCube::Cube< D >::template OverlapElementNum< K1 , K2 >() ]; + static bool Overlap[ HyperCube::Cube< D >::template ElementNum< K1 >() ][ HyperCube::Cube< D >::template ElementNum< K2 >() ]; + 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 nonLinearFit ) + { + 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( nonLinearFit ) 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 , 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 , std::function< void ( Vertex& , Point< Real , Dim > , Real , Data ) > SetVertex ) + { + if( slice>0 ) _SetSliceIsoVertices< WeightDegree , Data , DataSig >( tree , pointEvaluator , densityWeights , data , isoValue , depth , slice , HyperCube::FRONT , vOffset , mesh , slabValues , SetVertex ); + if( slice<(1<( tree , pointEvaluator , densityWeights , data , isoValue , depth , slice , HyperCube::BACK , vOffset , mesh , slabValues , SetVertex ); + } + template< unsigned int WeightDegree , typename Data , unsigned int DataSig > + static void _SetSliceIsoVertices( const FEMTree< Dim , Real >& tree , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , LocalDepth depth , int slice , HyperCube::Direction zDir , node_index_type& vOffset , CoredMeshData< Vertex , node_index_type >& mesh , std::vector< _SlabValues >& slabValues , std::function< void ( Vertex& , Point< Real , Dim > , Real , Data ) > SetVertex ) + { + static const unsigned int DataDegree = FEMSignature< DataSig >::Degree; + _SliceValues& sValues = slabValues[depth].sliceValues( slice ); + // [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 , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , _e , zDir , sValues , vertex , SetVertex ); + bool stillOwner = false; + std::pair< node_index_type , Vertex > hashed_vertex; + { + std::lock_guard< std::mutex > lock( _pointInsertionMutex ); + if( !edgeSet ) + { + mesh.addOutOfCorePoint( 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 , 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 , std::function< void ( Vertex& , 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 , pointEvaluator , densityWeights , data , isoValue , weightKey , dataKey , leaf , _c , bValues , fValues , vertex , SetVertex ); + bool stillOwner = false; + std::pair< node_index_type , Vertex > hashed_vertex; + { + std::lock_guard< std::mutex > lock( _pointInsertionMutex ); + if( !edgeSet ) + { + mesh.addOutOfCorePoint( 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 , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , ConstPointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , ConstPointSupportKey< IsotropicUIntPack< Dim , FEMSignature< DataSig >::Degree > >& dataKey , const TreeNode* node , typename HyperCube::template Cube< Dim-1 >::template Element< 1 > _e , HyperCube::Direction zDir , const _SliceValues& sValues , Vertex& vertex , std::function< void ( Vertex& , Point< Real , Dim > , Real , Data ) > SetVertex ) + { + static const unsigned int DataDegree = FEMSignature< DataSig >::Degree; + Point< Real , Dim > position; + 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; + + bool nonLinearFit = sValues.cornerGradients!=NullPointer( Point< Real , Dim > ); + const typename SliceData::SquareCornerIndices& idx = sValues.sliceData.cornerIndices( node ); + Real x0 = sValues.cornerValues[idx[c0]] , x1 = sValues.cornerValues[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 ); + 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 ); + dataValue = tree.template _evaluate< ProjectiveData< Data , Real > , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > , 0 >( *data , center , *pointEvaluator , dataKey ).value(); + } + else dataValue = tree.template _evaluate< ProjectiveData< Data , Real > , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > , 0 >( *data , position , *pointEvaluator , dataKey ).value(); + } + SetVertex( vertex , position , depth , dataValue ); + return true; + } + template< unsigned int WeightDegree , typename Data , unsigned int DataSig > + static bool _GetIsoVertex( const FEMTree< Dim , Real >& tree , typename FEMIntegrator::template PointEvaluator< IsotropicUIntPack< Dim , DataSig > , ZeroUIntPack< Dim > >* pointEvaluator , const DensityEstimator< WeightDegree >* densityWeights , const SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > >* data , Real isoValue , ConstPointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , ConstPointSupportKey< IsotropicUIntPack< Dim , FEMSignature< DataSig >::Degree > >& dataKey , const TreeNode* node , typename HyperCube::template Cube< Dim-1 >::template Element< 0 > _c , const _SliceValues& bValues , const _SliceValues& fValues , Vertex& vertex , std::function< void ( Vertex& , Point< Real , Dim > , Real , Data ) > SetVertex ) + { + static const unsigned int DataDegree = FEMSignature< DataSig >::Degree; + Point< Real , Dim > position; + + bool nonLinearFit = bValues.cornerGradients!=NullPointer( Point< Real , Dim > ) && fValues.cornerGradients!=NullPointer( Point< Real , Dim > ); + 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 , 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++; + } + position[2] = Real( start + width*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 ); + dataValue = tree.template _evaluate< ProjectiveData< Data , Real > , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > , 0 >( *data , center , *pointEvaluator , dataKey ).value(); + } + else dataValue = tree.template _evaluate< ProjectiveData< Data , Real > , SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > , 0 >( *data , position , *pointEvaluator , dataKey ).value(); + } + SetVertex( vertex , position , depth , dataValue ); + return true; + } + + 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 lock( _pointInsertionMutex ); + cIdx = mesh.addOutOfCorePoint( c ); + vOffset++; + } + for( unsigned i=0 ; i > vertices( polygon.size() ); + for( unsigned int i=0 ; i > 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 SetVertexFunction &SetVertex , bool nonLinearFit , 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 , coarseCoefficients() ); + 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 ); + slabValues[d].sliceValues (1).reset( nonLinearFit ); + 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 , pointEvaluator , densityWeights , data , isoValue , d , 0 , vertexOffset , mesh , slabValues , SetVertex ); + isoStats.verticesTime += Time()-t , t = Time(); + _SetSliceIsoEdges( tree , d , 0 , slabValues ); + isoStats.edgesTime += Time()-t , t = Time(); + } + + // 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 , pointEvaluator , densityWeights , data , isoValue , d , o , vertexOffset , mesh , slabValues , SetVertex ); + isoStats.verticesTime += Time()-t , t = Time(); + _SetSliceIsoEdges( tree , d , o , slabValues ); + isoStats.edgesTime += Time()-t , t = Time(); + + // Set the cross-slice edges + _SetXSliceIsoVertices< WeightDegree , Data , DataSig >( tree , pointEvaluator , densityWeights , data , isoValue , d , o-1 , vertexOffset , mesh , slabValues , 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 ); + 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[ HyperCube::Cube< D >::template ElementNum< K >() ][ HyperCube::Cube< D >::template IncidentCubeNum< K >() ]; +template< class Real , class Vertex > template< unsigned int D , unsigned int K > +unsigned int IsoSurfaceExtractor< 3 , Real , Vertex >::SliceData::HyperCubeTables< D , K >::IncidentElementCoIndex[ HyperCube::Cube< D >::template ElementNum< K >() ][ HyperCube::Cube< D >::template IncidentCubeNum< K >() ]; +template< class Real , class Vertex > template< unsigned int D , unsigned int K > +unsigned int IsoSurfaceExtractor< 3 , Real , Vertex >::SliceData::HyperCubeTables< D , K >::CellOffsetAntipodal[ HyperCube::Cube< D >::template ElementNum< K >() ]; +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[ HyperCube::Cube< D >::template ElementNum< K >() ]; +template< class Real , class Vertex > template< unsigned int D , unsigned int K > +typename HyperCube::Direction IsoSurfaceExtractor< 3 , Real , Vertex >::SliceData::HyperCubeTables< D , K >::Directions[ HyperCube::Cube< D >::template ElementNum< K >() ][ 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[ HyperCube::Cube< D >::template ElementNum< K1 >() ][ HyperCube::Cube< D >::template OverlapElementNum< K1 , K2 >() ]; +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[ HyperCube::Cube< D >::template ElementNum< K1 >() ][ HyperCube::Cube< D >::template ElementNum< K2 >() ]; diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/FEMTree.SortedTreeNodes.inl b/modules/PoissonRecon/include/Mesh/PoissonRecon/FEMTree.SortedTreeNodes.inl new file mode 100644 index 00000000..702e95f9 --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/FEMTree.SortedTreeNodes.inl @@ -0,0 +1,116 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +///////////////////// +// SortedTreeNodes // +///////////////////// +template< unsigned int Dim > +SortedTreeNodes< Dim >::SortedTreeNodes( void ) +{ + _sliceStart = NullPointer( Pointer( node_index_type ) ); + treeNodes = NullPointer( TreeNode* ); + _levels = 0; +} +template< unsigned int Dim > +SortedTreeNodes< Dim >::~SortedTreeNodes( void ) +{ + if( _sliceStart ) for( int d=0 ; d<_levels ; d++ ) FreePointer( _sliceStart[d] ); + FreePointer( _sliceStart ); + DeletePointer( treeNodes ); +} +template< unsigned int Dim > +void SortedTreeNodes< Dim >::set( TreeNode& root , std::vector< node_index_type >* map ) +{ + size_t sz = set( root ); + + if( map ) + { + 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; + } + 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 ) +{ + size_t sz = 0; + _levels = root.maxDepth()+1; + + if( _sliceStart ) for( int d=0 ; d<_levels ; d++ ) FreePointer( _sliceStart[d] ); + FreePointer( _sliceStart ); + DeletePointer( treeNodes ); + + _sliceStart = AllocPointer< Pointer( node_index_type ) >( _levels ); + for( int l=0 ; l<_levels ; l++ ) + { + _sliceStart[l] = AllocPointer< node_index_type >( ((size_t)1<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 ]++; + } + } + + // Get the start index for each slice + { + node_index_type levelOffset = 0; + for( int l=0 ; l<_levels ; l++ ) + { + _sliceStart[l][0] = levelOffset; + for( int s=0 ; s<((size_t)1<( _sliceStart[_levels-1][(size_t)1<<(_levels-1)] ); + + // Add the tree nodes + for( 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; + } + + // Shift the slice offsets up since we incremented as we added + for( int l=0 ; l<_levels ; l++ ) + { + for( int s=(1<0 ; s-- ) _sliceStart[l][s] = _sliceStart[l][s-1]; + _sliceStart[l][0] = l>0 ? _sliceStart[l-1][(size_t)1<<(l-1)] : 0; + } + return sz; +} + diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/FEMTree.System.inl b/modules/PoissonRecon/include/Mesh/PoissonRecon/FEMTree.System.inl new file mode 100644 index 00000000..ae554d41 --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/FEMTree.System.inl @@ -0,0 +1,3330 @@ +/* +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. +*/ + +/////////////////////////////////// +// BaseFEMIntegrator::Constraint // +/////////////////////////////////// +template< unsigned int ... TDegrees , unsigned int ... CDegrees , unsigned int CDim > +template< bool IterateFirst > +void BaseFEMIntegrator::Constraint< UIntPack< TDegrees ... > , UIntPack< CDegrees ... > , CDim >::setStencil( CCStencil & stencil ) const +{ + static const int Dim = sizeof ... ( TDegrees ); + int center = ( 1<<_highDepth )>>1; + int femOffset[Dim] , cOffset[Dim]; + static const int overlapStart[] = { ( IterateFirst ? BSplineOverlapSizes< CDegrees , TDegrees >::OverlapStart : BSplineOverlapSizes< TDegrees , CDegrees >::OverlapStart ) ... }; + if( IterateFirst ) + { + for( int d=0 ; d::Run( IsotropicUIntPack< Dim , 0 >() , UIntPack< BSplineOverlapSizes< TDegrees , CDegrees >::OverlapSize ... >() , [&]( int d , int i ){ femOffset[d] = i + center + overlapStart[d]; } , [&]( Point< double , CDim >& p ){ p = ccIntegrate( femOffset , cOffset ); } , stencil() ); + } + else + { + for( int d=0 ; d::Run( IsotropicUIntPack< Dim , 0 >() , UIntPack< BSplineOverlapSizes< TDegrees , CDegrees >::OverlapSize ... >() , [&]( int d , int i ){ cOffset[d] = i + center + overlapStart[d]; } , [&]( Point< double , CDim >& p ){ p = ccIntegrate( femOffset , cOffset );} , stencil() ); + } +} +template< unsigned int ... TDegrees , unsigned int ... CDegrees , unsigned int CDim > +template< bool IterateFirst > +void BaseFEMIntegrator::Constraint< UIntPack< TDegrees ... > , UIntPack< CDegrees ... > , CDim >::setStencils( PCStencils& stencils ) const +{ + static const int Dim = sizeof ... ( TDegrees ); + typedef UIntPack< BSplineOverlapSizes< TDegrees, CDegrees >::OverlapSize ... > OverlapSizes; + // [NOTE] We want the center to be at the first node of the brood, which is not the case when childDepth is 1. + int center = ( 1<<_highDepth )>>1 ; center = ( center>>1 )<<1; + int fineCenter[Dim] , femOffset[Dim] , cOffset[Dim]; + static const int overlapStart[] = { ( IterateFirst ? BSplineOverlapSizes< CDegrees , TDegrees >::OverlapStart : BSplineOverlapSizes< TDegrees , CDegrees >::OverlapStart ) ... }; + std::function< void ( int , int ) > outerUpdateState = [&]( int d , int i ){ fineCenter[Dim-d-1] = i+center; }; + std::function< void ( Point< double , CDim >& ) > innerFunction = [&]( Point< double , CDim >& p ){ p = pcIntegrate( femOffset , cOffset ); }; + std::function< void ( int , int ) > innerUpdateState = [&]( int d , int i ){ femOffset[d] = IterateFirst ? (i+center/2+overlapStart[d]) : center/2 , cOffset[d] = IterateFirst ? fineCenter[d] : (i+fineCenter[d]+overlapStart[d]); }; + std::function< void ( CCStencil& ) > outerFunction = [&]( CCStencil& s ) + { + WindowLoop< Dim >::Run( IsotropicUIntPack< Dim , 0 >() , OverlapSizes() , innerUpdateState , innerFunction , s() ); + }; + WindowLoop< Dim >::Run( IsotropicUIntPack< Dim , 0 >() , IsotropicUIntPack< Dim , 2 >() , outerUpdateState , outerFunction , stencils() ); +} +template< unsigned int ... TDegrees , unsigned int ... CDegrees , unsigned int CDim > +template< bool IterateFirst > +void BaseFEMIntegrator::Constraint< UIntPack< TDegrees ... > , UIntPack< CDegrees ... > , CDim >::setStencils( CPStencils& stencils ) const +{ + static const int Dim = sizeof ... ( TDegrees ); + typedef UIntPack< BSplineOverlapSizes< TDegrees , CDegrees >::OverlapSize ... > OverlapSizes; + // [NOTE] We want the center to be at the first node of the brood, which is not the case when childDepth is 1. + int center = ( 1<<_highDepth )>>1 ; center = ( center>>1 )<<1; + static const int overlapStart[] = { ( IterateFirst ? BSplineOverlapSizes< CDegrees , TDegrees >::OverlapStart : BSplineOverlapSizes< TDegrees , CDegrees >::OverlapStart ) ... }; + int fineCenter[Dim] , femOffset[Dim] , cOffset[Dim]; + std::function< void ( int , int ) > outerUpdateState = [&]( int d , int i ){ fineCenter[Dim-d-1] = i+center; }; + std::function< void ( Point< double , CDim >& ) > innerFunction = [&]( Point< double , CDim >& p ){ p = cpIntegrate( femOffset , cOffset ); }; + std::function< void ( int , int ) > innerUpdateState = [&]( int d , int i ){ femOffset[d] = IterateFirst ? (i+fineCenter[d]+overlapStart[d]) : fineCenter[d] , cOffset[d] = IterateFirst ? center/2 : (i+center/2+overlapStart[d]); }; + std::function< void ( CCStencil& ) > outerFunction = [&]( CCStencil& s ) + { + WindowLoop< Dim >::Run( IsotropicUIntPack< Dim , 0 >() , OverlapSizes() , innerUpdateState , innerFunction , s() ); + }; + WindowLoop< Dim >::Run( IsotropicUIntPack< Dim , 0 >() , IsotropicUIntPack< Dim , 2 >() , outerUpdateState , outerFunction , stencils() ); +} + +/////////////////////////////// +// BaseFEMIntegrator::System // +/////////////////////////////// +template< unsigned int ... TDegrees > +template< bool IterateFirst > +void BaseFEMIntegrator::System< UIntPack< TDegrees ... > >::setStencil( CCStencil & stencil ) const +{ + static const int Dim = sizeof ... ( TDegrees ); + int center = ( 1<<_highDepth )>>1; + int offset1[Dim] , offset2[Dim]; + static const int overlapStart[] = { BSplineOverlapSizes< TDegrees , TDegrees >::OverlapStart ... }; + if( IterateFirst ) + { + for( int d=0 ; d::Run( IsotropicUIntPack< Dim , 0 >() , UIntPack< BSplineOverlapSizes< TDegrees , TDegrees >::OverlapSize ... >() , [&]( int d , int i ){ offset1[d] = i + center + overlapStart[d]; } , [&]( double& v ){ v = ccIntegrate( offset1 , offset2 ); } , stencil() ); + } + else + { + for( int d=0 ; d::Run( IsotropicUIntPack< Dim , 0 >() , UIntPack< BSplineOverlapSizes< TDegrees , TDegrees >::OverlapSize ... >() , [&]( int d , int i ){ offset2[d] = i + center + overlapStart[d]; } , [&]( double& v ){ v = ccIntegrate( offset1 , offset2 ); } , stencil() ); + } +} +template< unsigned int ... TDegrees > +template< bool IterateFirst > +void BaseFEMIntegrator::System< UIntPack< TDegrees ... > >::setStencils( PCStencils& stencils ) const +{ + static const int Dim = sizeof ... ( TDegrees ); + typedef UIntPack< BSplineOverlapSizes< TDegrees , TDegrees >::OverlapSize ... > OverlapSizes; + // [NOTE] We want the center to be at the first node of the brood + // Which is not the case when childDepth is 1. + int center = ( 1<<_highDepth )>>1 ; center = ( center>>1 )<<1; + static const int overlapStart[] = { BSplineOverlapSizes< TDegrees , TDegrees >::OverlapStart ... }; + int fineCenter[Dim] , offset1[Dim] , offset2[Dim]; + std::function< void ( int , int ) > outerUpdateState = [&]( int d , int i ){ fineCenter[Dim-d-1] = i+center; }; + std::function< void ( double& ) > innerFunction = [&]( double& v ){ v = pcIntegrate( offset1 , offset2 ); }; + std::function< void ( int , int ) > innerUpdateState = [&]( int d , int i ){ offset1[d] = IterateFirst ? (i+center/2+overlapStart[d]) : center/2 , offset2[d] = IterateFirst ? fineCenter[d] : (i+fineCenter[d]+overlapStart[d]); }; + std::function< void ( CCStencil& ) > outerFunction = [&]( CCStencil& s ) + { + WindowLoop< Dim >::Run( IsotropicUIntPack< Dim , 0 >() , OverlapSizes() , innerUpdateState , innerFunction , s() ); + }; + WindowLoop< Dim >::Run( IsotropicUIntPack< Dim , 0 >() , IsotropicUIntPack< Dim , 2 >() , outerUpdateState , outerFunction , stencils() ); +} +///////////////////////////////// +// BaseFEMIntegrator::UpSample // +///////////////////////////////// +template< unsigned int ... TDegrees > +void BaseFEMIntegrator::RestrictionProlongation< UIntPack< TDegrees ... > >::setStencil( UpSampleStencil & stencil ) const +{ + static const int Dim = sizeof ... ( TDegrees ); + int highCenter = ( 1<<_highDepth )>>1; + int pOff[Dim] , cOff[Dim]; + static const int upSampleStart[] = { BSplineSupportSizes< TDegrees >::UpSampleStart ... }; + for( int d=0 ; d::Run( IsotropicUIntPack< Dim , 0 >() , UIntPack< BSplineSupportSizes< TDegrees >::UpSampleSize ... >() , [&]( int d , int i ){ cOff[d] = i + highCenter + upSampleStart[d]; } , [&]( double& v ){ v = upSampleCoefficient( pOff , cOff ); } , stencil() ); +} +template< unsigned int ... TDegrees > +void BaseFEMIntegrator::RestrictionProlongation< UIntPack< TDegrees ... > >::setStencils( DownSampleStencils& stencils ) const +{ + static const int Dim = sizeof ... ( TDegrees ); + // [NOTE] We want the center to be at the first node of the brood, which is not the case when childDepth is 1. + int highCenter = ( 1<<_highDepth )>>1 ; highCenter = ( highCenter>>1 )<<1; + int pOff[Dim] , cOff[Dim]; + static const int offsets[] = { BSplineSupportSizes< TDegrees >::DownSample0Start ... }; + std::function< void ( double& ) > innerFunction = [&]( double& v ){ v = upSampleCoefficient( pOff , cOff ); }; + std::function< void ( int , int ) > innerUpdateState = [&]( int d , int i ){ pOff[d] = cOff[d]/2 + i + offsets[d]; }; + std::function< void ( int , int ) > outerUpdateState = [&]( int d , int i ){ cOff[Dim-d-1] = i+highCenter; }; + std::function< void ( DownSampleStencil& ) > outerFunction = [&]( DownSampleStencil& s ) + { + WindowLoop< Dim >::Run( IsotropicUIntPack< Dim , 0 >() , UIntPack< ( - BSplineSupportSizes< TDegrees >::DownSample0Start + BSplineSupportSizes< TDegrees >::DownSample1End + 1 ) ... >() , innerUpdateState , innerFunction , s() ); + }; + WindowLoop< Dim >::Run( IsotropicUIntPack< Dim , 0 >() , IsotropicUIntPack< Dim , 2 >() , outerUpdateState , outerFunction , stencils() ); +} + +/////////////////////////////// +// FEMIntegrator::Constraint // +/////////////////////////////// + +template< unsigned int ... TSignatures , unsigned int ... TDerivatives , unsigned int ... CSignatures , unsigned int ... CDerivatives , unsigned int CDim > +Point< double , CDim > FEMIntegrator::Constraint< UIntPack< TSignatures ... > , UIntPack< TDerivatives ... > , UIntPack< CSignatures ... > , UIntPack< CDerivatives ... > , CDim >::_integrate( IntegrationType iType , const int off1[] , const int off2[] ) const +{ + Point< double , CDim > integral; + for( unsigned int i=0 ; i<_weightedIndices.size() ; i++ ) + { + const _WeightedIndices& w = _weightedIndices[i]; + unsigned int _d1[Dim] , _d2[Dim]; + TFactorDerivatives( w.d1 , _d1 ); + CFactorDerivatives( w.d2 , _d2 ); + double __integral = _integral( iType , off1 , off2 , _d1 , _d2 ); + for( unsigned int j=0 ; j0 ? (a) % (b) : ( (b) - ( -(a) % (b) ) ) % (b) ) +#endif // MOD + +///////////// +// FEMTree // +///////////// +template< unsigned int Dim , class Real > +template< unsigned int ... FEMSigs > +void FEMTree< Dim , Real >::setMultiColorIndices( UIntPack< FEMSigs ... > , int depth , std::vector< std::vector< size_t > >& indices ) const +{ + _setMultiColorIndices( UIntPack< FEMSigs ... >() , _sNodesBegin(depth) , _sNodesEnd(depth) , indices ); +} +template< unsigned int Dim , class Real > +template< unsigned int ... FEMSigs > +void FEMTree< Dim , Real >::_setMultiColorIndices( UIntPack< FEMSigs ... > , node_index_type start , node_index_type end , std::vector< std::vector< size_t > >& indices ) const +{ + _setFEM1ValidityFlags( UIntPack< FEMSigs ... >() ); + typedef UIntPack< ( 1 - BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree , FEMSignature< FEMSigs >::Degree >::OverlapStart ) ... > Moduli; + static const unsigned int Colors = WindowSize< Moduli >::Size; + indices.resize( Colors ); + struct ColorCount + { + size_t count[ Colors ]; + ColorCount( void ){ memset( count , 0 , sizeof(count) ); } + }; + std::vector< ColorCount > counts( ThreadPool::NumThreads() ); + size_t count[ Colors ]; + memset( count , 0 , sizeof(count) ); + auto MCIndex = [&] ( const FEMTreeNode* node ) + { + LocalDepth d ; LocalOffset off ; _localDepthAndOffset( node , d , off ); + int index = 0; + for( int dd=0 ; dd +template< unsigned int ... FEMSigs , typename T , typename TDotT , typename SORWeights , unsigned int ... PointDs > +int FEMTree< Dim , Real >::_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 , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) const +{ + double& systemTime = stats.systemTime; + double& solveTime = stats. solveTime; + systemTime = solveTime = 0.; + + CCStencil< UIntPack< FEMSignature< FEMSigs >::Degree ... > > ccStencil; + PCStencils< UIntPack< FEMSignature< FEMSigs >::Degree ... > > pcStencils; + F.template setStencil< false >( ccStencil ); + F.template setStencils< true >( pcStencils ); + double bNorm=0 , inRNorm=0 , outRNorm=0; + if( depth>=0 ) + { + SparseMatrix< Real , matrix_index_type , WindowSize< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >::Size > M; + double t = Time(); + 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 , interpolationInfo... ); + 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) ]; } ); + { + node_index_type begin = _sNodesBegin( depth ) , end = _sNodesEnd( depth ); + for( node_index_type i=begin ; i > mcIndices; + _setMultiColorIndices( UIntPack< FEMSigs ... >() , _sNodesBegin( depth ) , _sNodesEnd( depth ) , mcIndices ); + + ConstPointer( T ) B = _constraints; + Pointer( T ) X = GetPointer( &solution[0] + _sNodesBegin( depth ) , _sNodesSize( depth ) ); + 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 ) + { + T temp = {}; + ConstPointer( MatrixEntry< Real , matrix_index_type > ) start = M[j]; + ConstPointer( MatrixEntry< Real , matrix_index_type > ) end = start + M.rowSize(j); + ConstPointer( MatrixEntry< Real , matrix_index_type > ) e; + for( e=start ; e!=end ; e++ ) temp += X[ e->N ] * e->Value; + bNorms[thread] += Dot( B[j] , B[j] ); + inRNorms[thread] += Dot( temp - B[j] , temp - B[j] ); + } + ); + for( unsigned int t=0 ; t outRNorms( ThreadPool::NumThreads() , 0 ); + ThreadPool::Parallel_for( 0 , M.rows() , [&]( unsigned int thread , size_t j ) + { + T temp = {}; + ConstPointer( MatrixEntry< Real , matrix_index_type > ) start = M[j]; + ConstPointer( MatrixEntry< Real , matrix_index_type > ) end = start + M.rowSize(j); + ConstPointer( MatrixEntry< Real , matrix_index_type > ) e; + for( e=start ; e!=end ; e++ ) temp += X[ e->N ] * e->Value; + outRNorms[thread] += Dot( temp-B[j] , temp-B[j] ); + } + ); + for( unsigned int t=0 ; t +template< unsigned int ... FEMSigs , typename T , typename TDotT , typename SORWeights , unsigned int ... PointDs > +int FEMTree< Dim , Real >::_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 , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) const +{ + if( sliceBlockSize<=0 ) return _solveFullSystemGS( UIntPack< FEMSigs ... >() , F , bsData , depth , solution , prolongedSolution , constraints , Dot , iters , coarseToFine , sorWeights , stats , computeNorms , interpolationInfo ... ); + CCStencil< UIntPack< FEMSignature< FEMSigs >::Degree ... > > ccStencil; + PCStencils< UIntPack< FEMSignature< FEMSigs >::Degree ... > > pcStencils; + F.template setStencil< false >( ccStencil ); + F.template setStencils< true >( pcStencils ); + + { + // Assuming Degree=2 and we are solving forward using two iterations, the pattern of relaxations should look like: + // +--+--+--+--+--+ + // * | | | | | + // o| | | | | | + // o | | | | | | + // o | | | | | | + // o | | | | | | + // o | | | | | | + // | * | | | | + // | *| | | | | + // |* | | | | | + // * | | | | | + // o| | | | | | + // o | | | | | | + // | | * | | | + // | | *| | | | + // | |* | | | | + // | * | | | | + // | *| | | | | + // |* | | | | | + // | | | * | | + // | | | *| | | + // | | |* | | | + // | | * | | | + // | | *| | | | + // | |* | | | | + // | | | | * | + // | | | | *| | + // | | | |* | | + // | | | * | | + // | | | *| | | + // | | |* | | | + // | | * | | | + // | | | | | * + // | | | | | *| + // | | | | |* | + // | | | | * | + // | | | | *| | + // | | | |* | | + // | | | | | | o + // | | | | | | o + // | | | | | |o + // | | | | | * + // | | | | | *| + // | | | | |* | + + const int SliceBlockSize = (int)sliceBlockSize; + // OverlapRadius = Degree + const int OverlapRadii[] = { ( -BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapStart ) ... }; + const int OverlapBlockRadius = ( OverlapRadii[Dim-1] + SliceBlockSize - 1 ) / SliceBlockSize; + static const int LastFEMSig = UIntPack< FEMSigs ... >::template Get< Dim-1 >(); + int _sliceBegin = _BSplineBegin< LastFEMSig >( depth ) , _sliceEnd = _BSplineEnd< LastFEMSig >( depth ); + + int blockBegin = ( _sliceBegin - ( SliceBlockSize - 1 ) ) / SliceBlockSize , blockEnd = ( _sliceEnd + ( SliceBlockSize - 1 ) ) / SliceBlockSize; + std::function< int ( int ) > BlockFirst = [&]( int b ){ return std::max< int >( b * SliceBlockSize , _sliceBegin ); }; + std::function< int ( int ) > BlockLast = [&]( int b ){ return std::min< int >( b * SliceBlockSize + SliceBlockSize - 1 , _sliceEnd - 1 ); }; + + auto BBlock = [&]( int d , int b , ConstPointer( T ) B ) + { + return GetPointer( &B[0] + _sNodesBegin( d , BlockFirst( b ) ) , _sNodesEnd( d , BlockLast( b ) ) - _sNodesBegin( d , BlockFirst( b ) ) ); + }; + auto XBlocks = [&]( int d , int b , Pointer( T ) X ) + { + return GetPointer( &X[0] + _sNodesBegin( d , BlockFirst( b ) ) , _sNodesBegin( d , BlockFirst( b - OverlapBlockRadius ) ) - _sNodesBegin( d , BlockFirst( b ) ) , _sNodesEnd( d , BlockLast( b + OverlapBlockRadius ) ) - _sNodesBegin( d , BlockFirst( b ) ) ); + }; + + double& systemTime = stats.systemTime; + double& solveTime = stats. solveTime; + systemTime = solveTime = 0.; + + struct BlockWindow + { + protected: + int _begin , _end; + public: + BlockWindow( int begin , int end ) + { + if( begin<=end ) _begin = begin , _end = end; + else _begin = end+1 , _end = begin+1; + } + int size( void ) const { return _end-_begin; } + BlockWindow& operator += ( int off ){ _begin += off , _end += off ; return *this; } + BlockWindow& operator -= ( int off ){ _begin -= off , _end -= off ; return *this; } + BlockWindow& operator++ ( void ){ _begin++ , _end++ ; return *this; } + BlockWindow& operator-- ( void ){ _begin-- , _end-- ; return *this; } + int begin( bool forward ) const { return forward ? _begin : _end-1; } + int end ( bool forward ) const { return forward ? _end : _begin-1; } + bool inBlock( int b ) const { return b>=_begin && b<_end; } + }; + double bNorm=0 , inRNorm=0 , outRNorm=0; + bool forward = !coarseToFine; + int residualOffset = computeNorms ? OverlapBlockRadius : 0; + // Set the number of in-memory blocks required for a temporally blocked solver + const int ColorModulus = OverlapBlockRadius; + // The number of in-core blocks over which we relax + // [WARNING] If the block size is larger than one, we may be able to use fewer blocks + int solveBlocks = std::max< int >( 0 , std::min< int >( ColorModulus*iters - ( ColorModulus-1 ) , blockEnd-blockBegin ) ); + // The number of in-core blocks over which we either solve or compute residuals + int matrixBlocks = std::max< int >( 1 , std::min< int >( solveBlocks+2*residualOffset , blockEnd-blockBegin ) ); + // The list of matrices for each in-memory block + Pointer( SparseMatrix< Real , matrix_index_type , WindowSize< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >::Size > ) _M = NewPointer< SparseMatrix< Real , matrix_index_type , WindowSize< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >::Size > >( matrixBlocks ); + Pointer( Pointer( Real ) ) _D = AllocPointer< Pointer( Real ) >( matrixBlocks ); + std::vector< Pointer( T ) > _constraints( matrixBlocks ); + for( int i=0 ; i > ) mcIndices = NewPointer< std::vector< std::vector< size_t > > >( solveBlocks ); + int dir = forward ? 1 : -1 , start = forward ? blockBegin : blockEnd-1 , end = forward ? blockEnd : blockBegin-1; + const BlockWindow FullWindow( blockBegin , blockEnd ); + BlockWindow residualWindow( FullWindow.begin(forward) , FullWindow.begin(forward) - ( ColorModulus*iters - ( ColorModulus-1 ) ) * dir - 2*residualOffset*dir ); + 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; + size_t maxBlockSize = 0; + BlockWindow _residualWindow = residualWindow; + for( ; _residualWindow.end(!forward)*dir( 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" ); + for( int i=0 ; i( maxBlockSize ) , _D[i] = AllocPointer< Real >( maxBlockSize ); + for( ; residualWindow.end(!forward)*dir() , F , _M[_b] , _D[_b] , bsData , depth , _sNodesBegin( depth , BlockFirst( b ) ) , _sNodesEnd( depth , BlockLast( b ) ) , prolongedSolution , _constraints[_b] , ccStencil , pcStencils , interpolationInfo... ); + 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 ]; } ); + { + node_index_type begin = _sNodesBegin( depth , BlockFirst( b ) ) , end = _sNodesEnd( depth , BlockLast( b ) ); + for( node_index_type i=begin ; i bNorms( ThreadPool::NumThreads() , 0 ) , inRNorms( ThreadPool::NumThreads() , 0 ); + ThreadPool::Parallel_for( 0 , _M[_b].rows() , [&]( unsigned int thread , size_t j ) + { + T temp = {}; + ConstPointer( MatrixEntry< Real , matrix_index_type > ) start = _M[_b][j]; + ConstPointer( MatrixEntry< Real , matrix_index_type > ) end = start + _M[_b].rowSize(j); + ConstPointer( MatrixEntry< Real , matrix_index_type > ) e; + for( e=start ; e!=end ; e++ ) temp += X[ e->N ] * e->Value; + bNorms[thread] += Dot( B[j] , B[j] ); + inRNorms[thread] += Dot( temp - B[j] , temp - B[j] ); + } + ); + for( unsigned int t=0 ; t() , _sNodesBegin( depth , BlockFirst( b ) ) , _sNodesEnd( depth , BlockLast( b ) ) , mcIndices[__b] ); + } + } + + // 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 ); + 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 ); + } + solveTime += Time() - t; + + // Compute the final residual + { + int residualBlock = residualWindow.begin(forward); + if( computeNorms && FullWindow.inBlock( residualBlock ) ) + { + int b = residualBlock , _b = MOD( b , matrixBlocks ); + 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 ) + { + T temp = {}; + ConstPointer( MatrixEntry< Real , matrix_index_type > ) start = _M[_b][j]; + ConstPointer( MatrixEntry< Real , matrix_index_type > ) end = start + _M[_b].rowSize(j); + ConstPointer( MatrixEntry< Real , matrix_index_type > ) e; + for( e=start ; e!=end ; e++ ) temp += X[ e->N ] * e->Value; + outRNorms[thread] += Dot( temp-B[j] , temp-B[j] ); + } + ); + for( unsigned int t=0 ; t +template< unsigned int ... FEMSigs , typename T , typename TDotT , unsigned int ... PointDs > +int FEMTree< Dim , Real >::_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 accuracy , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) const +{ + int iter = 0; + Pointer( T ) X = GetPointer( &solution[0] + _sNodesBegin(depth) , _sNodesSize(depth) ); + ConstPointer( T ) B = GetPointer( &constraints[0] + _sNodesBegin(depth) , _sNodesSize(depth) ); + SparseMatrix< Real , matrix_index_type , WindowSize< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >::Size > M; + + double& systemTime = stats.systemTime; + double& solveTime = stats. solveTime; + systemTime = solveTime = 0.; + // Get the system matrix (and adjust the right-hand-side based on the coarser solution if prolonging) + systemTime = Time(); + Pointer( T ) _constraints = AllocPointer< T >( _sNodesSize( depth ) ); + B = _constraints; + CCStencil< UIntPack< FEMSignature< FEMSigs >::Degree ... > > ccStencil; + PCStencils< UIntPack< FEMSignature< FEMSigs >::Degree ... > > pcStencils; + 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 , interpolationInfo... ); + ThreadPool::Parallel_for( _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 + accuracy = Real( accuracy / 100000 ) * M.rows(); + int dims[] = { ( _BSplineEnd< FEMSigs >( depth ) - _BSplineBegin< FEMSigs >( depth ) ) ... }; + size_t nonZeroRows = 0; + for( matrix_index_type i=0 ; i<(matrix_index_type)M.rows() ; i++ ) if( M.rowSize(i) ) nonZeroRows++; + size_t totalDim = 1; + for( int d=0 ; d::BType ... }; + bool hasPartitionOfUnity = true; + for( int d=0 ; d bNorms( ThreadPool::NumThreads() , 0 ) , inRNorms( ThreadPool::NumThreads() , 0 ); + ThreadPool::Parallel_for( 0 , M.rows() , [&]( unsigned int thread , size_t j ) + { + T temp = {}; + ConstPointer( MatrixEntry< Real , matrix_index_type > ) start = M[j]; + ConstPointer( MatrixEntry< Real , matrix_index_type > ) end = start + M.rowSize(j); + ConstPointer( MatrixEntry< Real , matrix_index_type > ) e; + for( e=start ; e!=end ; e++ ) temp += X[ e->N ] * e->Value; + bNorms[thread] += Dot( B[j] , B[j] ); + inRNorms[thread] += Dot( temp-B[j] , temp-B[j] ); + } + ); + for( unsigned int t=0 ; t( nonZeroRows , iters ); + struct SPDFunctor + { + protected: + const SparseMatrix< Real , matrix_index_type , WindowSize< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >::Size >& _M; + bool _addDCTerm; + public: + SPDFunctor( const SparseMatrix< Real , matrix_index_type , WindowSize< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >::Size >& M , bool addDCTerm ) : _M(M) , _addDCTerm(addDCTerm){ } + void operator()( ConstPointer( T ) in , Pointer( T ) out ) const + { + _M.multiply( in , out ); + if( _addDCTerm ) + { + T average = {}; + for( matrix_index_type i=0 ; i<(matrix_index_type)_M.rows() ; i++ ) average += in[i]; + average /= _M.rows(); + for( matrix_index_type i=0 ; i<(matrix_index_type)_M.rows() ; i++ ) out[i] += average; + } + } + }; + if( iters ) iter = (int)SolveCG< SPDFunctor , T , Real >( SPDFunctor( M , addDCTerm ) , M.rows() , ( ConstPointer( T ) )B , iters , X , Real( accuracy ) , Dot ); + + solveTime = Time()-solveTime; + if( computeNorms ) + { + std::vector< double > outRNorms( ThreadPool::NumThreads() , 0 ); + ThreadPool::Parallel_for( 0 , M.rows() , [&]( unsigned int thread , size_t j ) + { + T temp = {}; + ConstPointer( MatrixEntry< Real , matrix_index_type > ) start = M[j]; + ConstPointer( MatrixEntry< Real , matrix_index_type > ) end = start + M.rowSize(j); + ConstPointer( MatrixEntry< Real , matrix_index_type > ) e; + for( e=start ; e!=end ; e++ ) temp += X[ e->N ] * e->Value; + outRNorms[thread] += Dot( temp-B[j] , temp-B[j] ); + } + ); + for( unsigned int t=0 ; t +template< unsigned int ... FEMSigs , typename T , typename TDotT , unsigned int ... PointDs > +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 depth , Pointer( T ) solution , ConstPointer( T ) constraints , TDotT Dot , int vCycles , int iters , _SolverStats& stats , bool computeNorms , double cgAccuracy , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) const +{ + double& systemTime = stats.systemTime; + double& solveTime = stats. solveTime; + + std::vector< SparseMatrix< Real , matrix_index_type > > P( depth ) , R( depth ) , M( depth+1 ); + std::vector< Pointer( Real ) > D( depth+1 ); + std::vector< Pointer( T ) > B( depth+1 ) , X( depth+1 ) , MX( depth+1 ); + std::vector< std::vector< std::vector< size_t > > > multiColorIndices( depth+1 ); + + systemTime = Time(); + M.back() = systemMatrix< Real >( UIntPack< FEMSigs ... >() , F , depth , interpolationInfo ... ); + for( int d=depth ; d>0 ; d-- ) + { + R[d-1] = downSampleMatrix( UIntPack< FEMSigs ... >() , d ); + P[d-1] = R[d-1].transpose(); + M[d-1] = R[d-1] * M[d] * P[d-1]; + } + for( int d=0 ; d<=depth ; d++ ) + { + size_t dim = M[d].rows(); + D[d] = AllocPointer< Real >( dim ); + MX[d] = AllocPointer< T >( dim ); + M[d].setDiagonalR( D[d] ); + setMultiColorIndices( UIntPack< FEMSigs ... >() , d , multiColorIndices[d] ); + if( d( dim ); + B[d] = AllocPointer< T >( dim ); + } + } + X.back() = solution + nodesBegin( depth ); + ConstPointer( T ) _B = constraints + nodesBegin( depth ); + systemTime = Time() - systemTime; + + solveTime = Time(); + + double bNorm = 0 , inRNorm = 0 , outRNorm = 0; + if( computeNorms ) + { + 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 ) + { + T temp = {}; + ConstPointer( MatrixEntry< Real , matrix_index_type > ) start = _M[j]; + ConstPointer( MatrixEntry< Real , matrix_index_type > ) end = start + _M.rowSize(j); + ConstPointer( MatrixEntry< Real , matrix_index_type > ) e; + for( e=start ; e!=end ; e++ ) temp += _X[ e->N ] * e->Value; + bNorms[thread] += Dot( _B[j] , _B[j] ); + inRNorms[thread] += Dot( temp-_B[j] , temp-_B[j] ); + } + ); + for( unsigned int t=0 ; t0 ; d-- ) + { + ConstPointer( T ) __B = d==depth ? _B : B[d]; + for( int i=0 ; i& _M; + bool _addDCTerm; + public: + SPDFunctor( const SparseMatrix< Real , matrix_index_type >& M , bool addDCTerm ) : _M(M) , _addDCTerm(addDCTerm){ } + void operator()( ConstPointer( T ) in , Pointer( T ) out ) const + { + _M.multiply( in , out ); + if( _addDCTerm ) + { + T average = {}; + for( matrix_index_type i=0 ; i<(matrix_index_type)_M.rows() ; i++ ) average += in[i]; + average /= _M.rows(); + for( matrix_index_type i=0 ; i<(matrix_index_type)_M.rows() ; i++ ) out[i] += average; + } + } + }; + size_t nonZeroRows = 0; + for( matrix_index_type i=0 ; i<(matrix_index_type)M[d].rows() ; i++ ) if( M[d].rowSize(i) ) nonZeroRows++; + size_t totalDim = 1; + int dims[] = { ( _BSplineEnd< FEMSigs >( depth ) - _BSplineBegin< FEMSigs >( depth ) ) ... }; + for( int dd=0 ; dd::BType ... }; + bool hasPartitionOfUnity = true; + for( int dd=0 ; dd( SPDFunctor( M[d] , addDCTerm ) , M[d].rows() , ( ConstPointer( T ) )__B , nonZeroRows , X[d] , Real( cgAccuracy ) , Dot ); + } + + // Prolongation + for( int d=1 ; d<=depth ; d++ ) + { + ConstPointer( T ) __B = d==depth ? _B : B[d]; + P[d-1].multiply( X[d-1] , X[d] , MULTIPLY_ADD ); + for( int i=0 ; i& _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 ) + { + T temp = {}; + ConstPointer( MatrixEntry< Real , matrix_index_type > ) start = _M[j]; + ConstPointer( MatrixEntry< Real , matrix_index_type > ) end = start + _M.rowSize(j); + ConstPointer( MatrixEntry< Real , matrix_index_type > ) e; + for( e=start ; e!=end ; e++ ) temp += _X[ e->N ] * e->Value; + outRNorms[thread] += Dot( temp-_B[j] , temp-_B[j] ); + } + ); + for( unsigned int t=0 ; t +template< unsigned int ... FEMSigs > +int FEMTree< Dim , Real >::_getMatrixRowSize( UIntPack< FEMSigs ... > , const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& neighbors ) const +#else // !__GNUC__ || __GNUC__ >=5 +template< unsigned int Dim , class Real > +template< unsigned int ... FEMSigs > +int FEMTree< Dim , Real >::_getMatrixRowSize( const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& neighbors ) const +#endif // __GNUC__ || __GNUC__ < 4 +{ + typedef UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > OverlapSizes; + + int count = 0; + const FEMTreeNode* const * _nodes = neighbors.neighbors.data; + for( int i=0 ; i::Size ; i++ ) if( _isValidFEM1Node( _nodes[i] ) ) count++; + return count; +} + +template< unsigned int Dim , class Real > +template< unsigned int ... FEMSigs > +int FEMTree< Dim , Real >::_getProlongedMatrixRowSize( const FEMTreeNode* node , const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& pNeighbors ) const +{ + typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > FEMDegrees; + typedef UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > OverlapSizes; +#ifdef SHOW_WARNINGS +#pragma message( "[WARNING] This change needs to be validated" ) +#endif // SHOW_WARNINGS + int count = 0; + static const WindowLoopData< OverlapSizes > loopData( []( int c , int* start , int*end ){ _SetParentOverlapBounds( FEMDegrees() , FEMDegrees() , c , start , end );} ); + if( node->parent ) + { + int c = (int)( node - node->parent->children ); + const unsigned int size = loopData.size[c]; + const unsigned int* indices = loopData.indices[c]; + ConstPointer( FEMTreeNode * const ) nodes = pNeighbors.neighbors().data; + for( unsigned int i=0 ; i +template< unsigned int ... FEMSigs , typename T , unsigned int PointD > +void FEMTree< Dim , Real >::_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 +{ + typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > FEMDegrees; + typedef UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > OverlapSizes; + typedef UIntPack< ( -BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapStart ) ... > OverlapRadii; + typedef UIntPack< ( -BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportStart ) ... > LeftSupportRadii; + typedef UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportEnd ... > RightSupportRadii; + typedef UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportEnd ... > LeftPointSupportRadii; + 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( !interpolationInfo ) return; + const InterpolationInfo< T , PointD >& iInfo = *interpolationInfo; + + + const FEMTreeNode* node = neighbors.neighbors.data[ WindowIndex< OverlapSizes , OverlapRadii >::Index ]; + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + + PointEvaluatorState< UIntPack< FEMSigs ... > , IsotropicUIntPack< Dim , PointD > > peState; + + int idx[Dim]; // The coordinates of the node containing the point _relative_ to the center node + int _idx[Dim==1 ? 1 : Dim-1]; + CumulativeDerivativeValues< double , Dim , PointD > dualValues; + + auto outerFunction = [&]( const FEMTreeNode* _node ) + { + if( _isValidSpaceNode( _node ) ) + { + LocalOffset pOff; // The coordinates of the node containing the point + for( int d=0 ; d& pData = iInfo[ pIndex ]; + CumulativeDerivativeValues< double , Dim , PointD > values; + { + Real weight = pData.weight; + Point< Real , Dim > p = pData.position; + // Compute the partial evaluation of all B-splines (and derivatives) that are supported on the point + bsData.initEvaluationState( p , d , pOff , peState ); + + // The value (and derivatives) of the function of the center node at this point + values = peState.template dValues< Real , CumulativeDerivatives< Dim , PointD > >( off ); + } + dualValues = iInfo( pIndex , values ) * pData.weight; + 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 + ( + start , end , + [&]( int d , int i ){ _idx[d] = i - (int)OverlapRadii::Values[d] + off[d]; } , + [&]( const WindowSlice< Real , UIntPack< OverlapSizes::template Get< Dim-1 >() > > pointValues , ConstWindowSlice< const FEMTreeNode* , UIntPack< OverlapSizes::template Get< Dim-1 >() > > neighbors ) + { + Point< double , PointD+1 > partialDot = peState.template partialDotDValues< Real , CumulativeDerivatives< Dim , PointD > >( dualValues , _idx ); + Pointer( Real ) _pointValues = pointValues.data + idx[Dim-1] + 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 >(); + for( unsigned int i=0 ; i::Run + ( + OverlapRadii() - LeftSupportRadii() , OverlapRadii() + RightSupportRadii() + IsotropicUIntPack< Dim , 1 >() , + [&]( int d , int i ){ idx[d] = i - (int)OverlapRadii::Values[d]; } , + outerFunction , + neighbors.neighbors() + ); +} + +template< unsigned int Dim , class Real > +template< typename T , unsigned int ... PointDs , unsigned int ... FEMSigs > +T FEMTree< Dim , Real >::_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 , SparseMatrix< Real , matrix_index_type , WindowSize< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >::Size > &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 , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) const +{ + T constraint ={}; + typedef UIntPack< ( -BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapStart ) ... > OverlapRadii; + typedef UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > OverlapSizes; + + int count = 0; + const FEMTreeNode* node = neighbors.neighbors.data[ WindowIndex< OverlapSizes , OverlapRadii >::Index ]; + Pointer( MatrixEntry< Real , matrix_index_type > ) row = M[idx]; + + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + if( d>0 && prolongedSolution ) + { + int cIdx = (int)( node - node->parent->children ); + constraint = _getConstraintFromProlongedSolution( UIntPack< FEMSigs ... >() , F , neighbors , pNeighbors , node , prolongedSolution , pcStencils.data[cIdx] , bsData , interpolationInfo... ); + } + + bool isInterior = BaseFEMIntegrator::IsInteriorlyOverlapped( UIntPack< FEMSignature< FEMSigs >::Degree ... >() , UIntPack< FEMSignature< FEMSigs >::Degree ... >() , d , off ); + + StaticWindow< Real , UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > > pointValues; + memset( pointValues.data , 0 , sizeof(Real)*WindowSize< OverlapSizes >::Size ); + _addPointValues( UIntPack< FEMSigs ... >() , pointValues , neighbors , bsData , interpolationInfo ... ); + node_index_type nodeIndex = node->nodeData.nodeIndex; + if( isInterior ) // General case, so try to make fast + { + const FEMTreeNode* const * _nodes = neighbors.neighbors.data; + ConstPointer( double ) _stencil = ccStencil.data; + Real* _values = pointValues.data; + row[count++] = MatrixEntry< Real , matrix_index_type >( (matrix_index_type)( nodeIndex-offset ) , (Real)( _values[ WindowIndex< OverlapSizes , OverlapRadii >::Index ] + _stencil[ WindowIndex< OverlapSizes , OverlapRadii >::Index ] ) ); + for( int i=0 ; i::Size ; i++ ) if( _isValidFEM1Node( _nodes[i] ) ) + { + if( i!=WindowIndex< OverlapSizes , OverlapRadii >::Index ) row[count++] = MatrixEntry< Real , matrix_index_type >( (matrix_index_type)( _nodes[i]->nodeData.nodeIndex-offset ) , (Real)( _values[i] + _stencil[i] ) ); + } + } + else + { + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + Real temp = (Real)F.ccIntegrate( off , off ) + pointValues.data[ WindowIndex< OverlapSizes , OverlapRadii >::Index ]; + + row[count++] = MatrixEntry< Real , matrix_index_type >( (matrix_index_type)( nodeIndex-offset ) , temp ); + LocalOffset _off; + WindowLoop< Dim >::Run + ( + ZeroUIntPack< Dim >() , OverlapSizes() , + [&]( int d , int i ){ _off[d] = off[d] - (int)OverlapRadii::Values[d] + i; } , + [&]( const FEMTreeNode* _node , Real pointValue ) + { + if( node!=_node && FEMIntegrator::IsValidFEMNode( UIntPack< FEMSigs ... >() , d , _off ) ) + { + Real temp = (Real)F.ccIntegrate( _off , off ) + pointValue; + if( _isValidFEM1Node( _node ) ) row[count++] = MatrixEntry< Real , matrix_index_type >( (matrix_index_type)( _node->nodeData.nodeIndex-offset ) , temp ); + } + } , + neighbors.neighbors() , pointValues() + ); + } + M.setRowSize( idx , count ); + return constraint; +} + +template< unsigned int Dim , class Real > +template< typename T , unsigned int ... PointDs , unsigned int ... FEMSigs > +T FEMTree< Dim , Real >::_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 , Pointer( MatrixEntry< Real , matrix_index_type > ) row , 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 , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) const +{ + T constraint ={}; + typedef UIntPack< ( -BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapStart ) ... > OverlapRadii; + typedef UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > OverlapSizes; + + int count = 0; + const FEMTreeNode* node = neighbors.neighbors.data[ WindowIndex< OverlapSizes , OverlapRadii >::Index ]; + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + if( d>0 && prolongedSolution ) + { + int cIdx = (int)( node - node->parent->children ); + constraint = _getConstraintFromProlongedSolution( UIntPack< FEMSigs ... >() , F , neighbors , pNeighbors , node , prolongedSolution , pcStencils.data[cIdx] , bsData , interpolationInfo... ); + } + + bool isInterior = BaseFEMIntegrator::IsInteriorlyOverlapped( UIntPack< FEMSignature< FEMSigs >::Degree ... >() , UIntPack< FEMSignature< FEMSigs >::Degree ... >() , d , off ); + + StaticWindow< Real , UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > > pointValues; + memset( pointValues.data , 0 , sizeof(Real)*WindowSize< OverlapSizes >::Size ); + _addPointValues( UIntPack< FEMSigs ... >() , pointValues , neighbors , bsData , interpolationInfo ... ); + node_index_type nodeIndex = node->nodeData.nodeIndex; + if( isInterior ) // General case, so try to make fast + { + const FEMTreeNode* const * _nodes = neighbors.neighbors.data; + ConstPointer( double ) _stencil = ccStencil.data; + Real* _values = pointValues.data; + row[count++] = MatrixEntry< Real , matrix_index_type >( (matrix_index_type)( nodeIndex-offset ) , (Real)( _values[ WindowIndex< OverlapSizes , OverlapRadii >::Index ] + _stencil[ WindowIndex< OverlapSizes , OverlapRadii >::Index ] ) ); + for( int i=0 ; i::Size ; i++ ) if( _isValidFEM1Node( _nodes[i] ) ) + { + if( i!=WindowIndex< OverlapSizes , OverlapRadii >::Index ) row[count++] = MatrixEntry< Real , matrix_index_type >( (matrix_index_type)( _nodes[i]->nodeData.nodeIndex-offset ) , (Real)( _values[i] + _stencil[i] ) ); + } + } + else + { + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + Real temp = (Real)F.ccIntegrate( off , off ) + pointValues.data[ WindowIndex< OverlapSizes , OverlapRadii >::Index ]; + + row[count++] = MatrixEntry< Real , matrix_index_type >( (matrix_index_type)( nodeIndex-offset ) , temp ); + LocalOffset _off; + WindowLoop< Dim >::Run + ( + ZeroUIntPack< Dim >() , OverlapSizes() , + [&]( int d , int i ){ _off[d] = off[d] - (int)OverlapRadii::Values[d] + i; } , + [&]( const FEMTreeNode* _node , Real pointValue ) + { + if( node!=_node && FEMIntegrator::IsValidFEMNode( UIntPack< FEMSigs ... >() , d , _off ) ) + { + Real temp = (Real)F.ccIntegrate( _off , off ) + pointValue; + if( _isValidFEM1Node( _node ) ) row[count++] = MatrixEntry< Real , matrix_index_type >( (matrix_index_type)( _node->nodeData.nodeIndex-offset ) , temp ); + } + } , + neighbors.neighbors() , pointValues() + ); + } + return constraint; +} + +template< unsigned int Dim , class Real > +template< unsigned int ... FEMSigs , typename T , unsigned int PointD > +void FEMTree< Dim , Real >::_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 >* interpolationInfo ) const +{ +#ifdef SHOW_WARNINGS +#pragma message( "[WARNING] This code is broken" ) +#endif // SHOW_WARNINGS +#if 1 + ERROR_OUT( "Broken code" ); +#else + if( !interpolationInfo ) return; + const InterpolationInfo< T , PointD >& iInfo = *interpolationInfo; + typedef UIntPack< ( -BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapStart ) ... > OverlapRadii; + typedef UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > OverlapSizes; + + const FEMTreeNode* node = neighbors.neighbors.data[ WindowIndex< OverlapSizes , OverlapRadii >::Index ]; + + LocalDepth d , parentD ; LocalOffset off , parentOff; + _localDepthAndOffset( node , d , off ); + _localDepthAndOffset( node->parent , parentD , parentOff ); + int fStart , fEnd; + BSplineData< FEMSig >::FunctionSpan( d , fStart , fEnd ); + + int fIdx[Dim]; + functionIndex( IsotropicUIntPack< Dim , FEMSig >() , node , fIdx ); + double splineValues[ Dim ] [ PointD+1 ]; + double parentSplineValues[ Dim ][ SupportSize ][ PointD+1 ]; + int s[Dim]; + CumulativeDerivativeValues< Real , Dim , PointD > dualValues; + std::function< void ( const FEMTreeNode* , Real& ) > innerFunction = [&]( const FEMTreeNode* pNode , Real& pointValue ) + { + if( _isValidFEM1Node( pNode ) ) + { + CumulativeDerivativeValues< Real , Dim , PointD > values = Evaluate< SupportSize , Dim , Real , PointD >( s , parentSplineValues ); + pointValue += CumulativeDerivativeValues< Real , Dim , PointD >::Dot( dualValues , values ); + }; + }; + std::function< void ( const FEMTreeNode* ) > outerFunction = [&]( const FEMTreeNode* _node ) + { + if( _isValidSpaceNode( _node ) ) for( const PointData< Dim , Real , T , PointD >* _pData=iInfo.begin( _node ) ; _pData!=iInfo.end( _node ) ; _pData++ ) + { + // Evaluate the node's basis function at the sample + const PointData< Dim , Real , T , PointD >& pData = *_pData; + _setDValues< FEMSig , PointD , FEMDegree >( pData.position , _node , node , bsData , splineValues ); + _setDValues< FEMSig , PointD , FEMDegree >( pData.position , _node->parent , bsData , parentSplineValues ); + dualValues = iInfo.weights * Evaluate< Dim , Real , PointD >( splineValues ) * pData.weight; + + // Get the indices of the parent + LocalDepth _parentD ; LocalOffset _parentOff; + _localDepthAndOffset( _node->parent , _parentD , _parentOff ); + + int _off[Dim]; + for( int dd=0 ; dd::Run + ( + _start , _end , + [&]( int d , int i ){ s[d] = i + LeftPointSupportRadius - _off[d] - OverlapRadius; } , + innerFunction , + pNeighbors.neighbors() , pointValues + ); + } + }; + int start[Dim] , end[Dim]; + for( int dd=0 ; dd::Run + ( + start , end , + [&]( int , int ){;} , + outerFunction , + neighbors.neighbors() + ); +#endif +} + +template< unsigned int Dim , class Real > +template< typename T , unsigned int ... PointDs , unsigned int ... FEMSigs > +int FEMTree< Dim , Real >::_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 , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) const +{ + typedef UIntPack< ( -BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapStart ) ... > OverlapRadii; + typedef UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > OverlapSizes; + typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > FEMDegrees; + + int count = 0; + const FEMTreeNode* node = neighbors.neighbors.data[ WindowIndex< OverlapSizes , OverlapRadii >::Index ]; + LocalDepth d , parentD ; LocalOffset off , parentOff; + _localDepthAndOffset( node , d , off ); + _localDepthAndOffset( node->parent , parentD , parentOff ); + bool isInterior = _isInteriorlyOverlapped( FEMDegrees() , FEMDegrees() , node->parent ); + StaticWindow< Real , UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > > pointValues; + memset( pointValues.data , 0 , sizeof(Real)*WindowSize< OverlapSizes >::Size ); + _addProlongedPointValues( UIntPack< FEMSigs ... >() , pointValues() , neighbors , pNeighbors , bsData , interpolationInfo ... ); + + node_index_type nodeIndex = node->nodeData.nodeIndex; + + int start[Dim] , end[Dim]; + _SetParentOverlapBounds( FEMDegrees() , FEMDegrees() , node , start , end ); + if( isInterior ) // General case, so try to make fast + { + WindowLoop< Dim >::Run + ( + start , end , + [&]( int , int ){;} , + [&]( const FEMTreeNode* node , const Real& pointValue , const Real& stencilValue ) + { + if( _isValidFEM1Node( node ) ) row[count++] = MatrixEntry< Real , matrix_index_type >( (matrix_index_type)( node->nodeData.nodeIndex - offset ) , pointValue + stencilValue ); + } , + pNeighbors.neighbors() , pointValues() , stencil() + ); + } + else + { + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + WindowLoop< Dim >::Run + ( + start , end , + [&]( int , int ){;} , + [&]( const FEMTreeNode* node , const Real& pointValue ) + { + if( _isValidFEM1Node( node ) ) + { + LocalDepth d ; LocalOffset _off; + _localDepthAndOffset( node , d , _off ); + row[count++] = MatrixEntry< Real , matrix_index_type >( (matrix_index_type)( node->nodeData.nodeIndex - offset ) , (Real)F.pcIntegrate( _off , off ) + pointValue ); + } + } , + pNeighbors.neighbors() , pointValues() + ); + } + return count; +} + +template< unsigned int Dim , class Real > +template< unsigned int FEMDegree1 , unsigned int FEMDegree2 > +void FEMTree< Dim , Real >::_SetParentOverlapBounds( const FEMTreeNode* node , int start[Dim] , int end[Dim] ) +{ + const int OverlapStart = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::OverlapStart; + + if( node->parent ) + { + int cIdx = (int)( node - node->parent->children ); + for( int d=0 ; d::ParentOverlapStart[ (cIdx>>d) & 1 ] - OverlapStart; + end [d] = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::ParentOverlapEnd [ (cIdx>>d) & 1 ] - OverlapStart + 1; + } + } +} +template< unsigned int Dim , class Real > +template< unsigned int FEMDegree1 , unsigned int FEMDegree2 > +void FEMTree< Dim , Real >::_SetParentOverlapBounds( int cIdx , int start[Dim] , int end[Dim] ) +{ + const int OverlapStart = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::OverlapStart; + + for( int d=0 ; d::ParentOverlapStart[ (cIdx>>d) & 1 ] - OverlapStart; + end [d] = BSplineOverlapSizes< FEMDegree1 , FEMDegree2 >::ParentOverlapEnd [ (cIdx>>d) & 1 ] - OverlapStart + 1; + } +} + +template< unsigned int Dim , class Real > +template< unsigned int ... FEMSigs , typename T , unsigned int PointD > +T FEMTree< Dim , Real >::_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 >* interpolationInfo ) const +{ + if( !interpolationInfo ) return T(); + typedef UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... > SupportSizes; + typedef UIntPack< ( -BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapStart ) ... > OverlapRadii; + typedef UIntPack< ( -BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportStart ) ... > LeftSupportRadii; + typedef UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > OverlapSizes; + typedef PointEvaluatorState< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > > _PointEvaluatorState; + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + T temp = {}; + if( _isValidFEM1Node( node ) ) + { + int s[Dim]; +#if defined( _WIN32 ) || defined( _WIN64 ) +#pragma message ( "[WARNING] You've got me MSVC" ) + auto UpdateFunction = [&]( int d , int i ){ s[d] = (int)SupportSizes::Values[d] - 1 - ( i - (int)OverlapRadii::Values[d] + (int)LeftSupportRadii::Values[d] ); }; + auto ProcessFunction = [&]( const FEMTreeNode* pNode ) + { + if( _isValidSpaceNode( pNode ) ) + { + size_t begin , end; + interpolationInfo->range( pNode , begin , end ); + for( size_t pIndex=begin ; pIndex _pData = (*interpolationInfo)[ pIndex ]; + _PointEvaluatorState peState; + Point< Real , Dim > p = _pData.position; + LocalDepth pD ; LocalOffset pOff; + _localDepthAndOffset( pNode , pD , pOff ); + bsData.initEvaluationState( p , pD , pOff , peState ); +#ifdef SHOW_WARNINGS +#pragma message( "[WARNING] Why is this necessary?" ) +#endif // SHOW_WARNINGS + const int *_off = off; + CumulativeDerivativeValues< Real , Dim , PointD > values = peState.template dValues< Real , CumulativeDerivatives< Dim , PointD > >( _off ); + for( int d=0 ; d::Size ; d++ ) temp += _pData.dualValues[d] * values[d]; + } + } + }; +#endif // _WIN32 || _WIN64 + WindowLoop< Dim >::Run + ( + OverlapRadii() - LeftSupportRadii() , OverlapRadii() - LeftSupportRadii() + SupportSizes() , +#if defined( _WIN32 ) || defined( _WIN64 ) + UpdateFunction , ProcessFunction , +#else // !_WIN32 && !_WIN64 + [&]( int d , int i ){ s[d] = (int)SupportSizes::Values[d] - 1 - ( i - (int)OverlapRadii::Values[d] + (int)LeftSupportRadii::Values[d] ); } , + [&]( const FEMTreeNode* pNode ) + { + if( _isValidSpaceNode( pNode ) ) + { + size_t begin , end; + interpolationInfo->range( pNode , begin , end ); + for( size_t pIndex=begin ; pIndex _pData = (*interpolationInfo)[ pIndex ]; + _PointEvaluatorState peState; + Point< Real , Dim > p = _pData.position; + LocalDepth pD ; LocalOffset pOff; + _localDepthAndOffset( pNode , pD , pOff ); + bsData.initEvaluationState( p , pD , pOff , peState ); +#ifdef SHOW_WARNINGS +#pragma message( "[WARNING] Why is this necessary?" ) +#endif // SHOW_WARNINGS + const int *_off = off; + CumulativeDerivativeValues< Real , Dim , PointD > values = peState.template dValues< Real , CumulativeDerivatives< Dim , PointD > >( _off ); + for( int d=0 ; d::Size ; d++ ) temp += _pData.dualValues[d] * values[d]; + } + } + } , +#endif // _WIN32 || _WIN64 + neighbors.neighbors() + ); + } + return temp; +} + +template< unsigned int Dim , class Real > +template< unsigned int ... FEMSigs , typename T , unsigned int ... PointDs > +T FEMTree< Dim , Real >::_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 , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) const +{ + typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > FEMDegrees; + + if( _localDepth( node )<=0 ) return T(); + // This is a conservative estimate as we only need to make sure that the parent nodes don't overlap the child (not the parent itself) + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node->parent , d , off ); + bool isInterior = BaseFEMIntegrator::IsInteriorlyOverlapped( FEMDegrees() , FEMDegrees() , d , off ); + + // Offset the constraints using the solution from lower resolutions. + T constraint = {}; + static const WindowLoopData< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > > loopData( []( int c , int* start , int* end ){ BaseFEMIntegrator::ParentOverlapBounds( FEMDegrees() , FEMDegrees() , c , start , end ); } ); + int cIdx = (int)( node - node->parent->children ); + unsigned int size = loopData.size[cIdx]; + const unsigned int* indices = loopData.indices[cIdx]; + ConstPointer( double ) values = stencil.data; + ConstPointer( FEMTreeNode * const ) nodes = pNeighbors.neighbors().data; + if( isInterior ) + { + for( unsigned int i=0 ; inodeData.nodeIndex ] * (Real)values[idx] ); + } + } + else + { + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + for( unsigned int i=0 ; inodeData.nodeIndex ] * (Real)F.pcIntegrate( _off , off ) ); + } + + } + } + return constraint + _getInterpolationConstraintFromProlongedSolution( neighbors , node , prolongedSolution , bsData , interpolationInfo... ); +} + +// Given the solution @( depth ) add to the met constraints @( depth-1 ) +template< unsigned int Dim , class Real > +template< unsigned int ... FEMSigs , typename T > +void FEMTree< Dim , Real >::_updateRestrictedIntegralConstraints( UIntPack< FEMSigs ... > , const typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , LocalDepth highDepth , ConstPointer( T ) fineSolution , Pointer( T ) restrictedConstraints ) const +{ + typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > FEMDegrees; + typedef UIntPack< ( -BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapStart ) ... > OverlapRadii; + typedef UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > OverlapSizes; + + if( highDepth<=0 ) return; + // Get the stencil describing the Laplacian relating coefficients @(highDepth) with coefficients @(highDepth-1) + PCStencils< FEMDegrees > stencils; + F.template setStencils< true >( stencils ); + node_index_type start = _sNodesBegin(highDepth) , end = _sNodesEnd(highDepth); + node_index_type range = end-start; + node_index_type lStart = _sNodesBegin(highDepth-1); + + // Iterate over the nodes @(highDepth) + std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; iparent->children ); + + { + typename FEMTreeNode::template ConstNeighbors< OverlapSizes > pNeighbors; + neighborKey.getNeighbors( OverlapRadii() , OverlapRadii() , node->parent , pNeighbors ); + const DynamicWindow< double , OverlapSizes >& stencil = stencils.data[cIdx]; + + bool isInterior = _isInteriorlyOverlapped( FEMDegrees() , FEMDegrees() , node->parent ); + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + + // Offset the constraints using the solution from finer resolutions. + int start[Dim] , end[Dim]; + _SetParentOverlapBounds( FEMDegrees() , FEMDegrees() , node , start , end ); + + T solution = fineSolution[ node->nodeData.nodeIndex ]; + ConstPointer( FEMTreeNode * const ) nodes = pNeighbors.neighbors().data; + ConstPointer( double ) stencilValues = stencil.data; + if( isInterior ) + { + for( int i=0 ; i::Size ; i++ ) if( _isValidFEM1Node( nodes[i] ) ) + { + AddAtomic( restrictedConstraints[ nodes[i]->nodeData.nodeIndex ] , solution * (Real)stencilValues[i] ); + } + } + else + { + for( int i=0 ; i::Size ; i++ ) if( _isValidFEM1Node( nodes[i] ) ) + { + LocalDepth _d ; LocalOffset _off; + _localDepthAndOffset( nodes[i] , _d , _off ); + AddAtomic( restrictedConstraints[ nodes[i]->nodeData.nodeIndex ] , solution * (Real)F.pcIntegrate( _off , off ) ); + } + } + } + } + } + ); +} + +template< unsigned int Dim , class Real > +template< unsigned int ... FEMSigs , typename T , unsigned int PointD > +void FEMTree< Dim , Real >::_setPointValuesFromProlongedSolution( LocalDepth highDepth , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , ConstPointer( T ) prolongedSolution , InterpolationInfo< T , PointD >* iInfo ) const +{ + if( !iInfo ) return; + typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > FEMDegrees; + InterpolationInfo< T , PointD >& interpolationInfo = *iInfo; + + LocalDepth lowDepth = highDepth-1; + if( lowDepth<0 ) return; + // For every node at the current depth + std::vector< ConstPointSupportKey< FEMDegrees > > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i& neighborKey = neighborKeys[ thread ]; + if( _isValidSpaceNode( _sNodes.treeNodes[i] ) ) + { + size_t begin , end; + interpolationInfo.range( _sNodes.treeNodes[i] , begin , end ); + for( size_t pIndex=begin ; pIndex& pData = interpolationInfo[ pIndex ]; + neighborKey.getNeighbors( _sNodes.treeNodes[i]->parent ); +#ifdef _MSC_VER + pData.dualValues = interpolationInfo( pIndex , _coarserFunctionValues< PointD , T , FEMSigs ... >( UIntPack< FEMSigs ... >() , pData.position , neighborKey , _sNodes.treeNodes[i] , bsData , prolongedSolution ) ) * pData.weight; +#else // !_MSC_VER + pData.dualValues = interpolationInfo( pIndex , _coarserFunctionValues< PointD >( UIntPack< FEMSigs ... >() , pData.position , neighborKey , _sNodes.treeNodes[i] , bsData , prolongedSolution ) ) * pData.weight; +#endif // _MSC_VER + } + } + } + } + ); +} + +template< unsigned int Dim , class Real > +template< unsigned int ... FEMSigs , typename T , unsigned int PointD > +void FEMTree< Dim , Real >::_updateRestrictedInterpolationConstraints( const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , LocalDepth highDepth , ConstPointer( T ) solution , Pointer( T ) restrictedConstraints , const InterpolationInfo< T , PointD >* iInfo ) const +{ + if( !iInfo ) return; + const InterpolationInfo< T , PointD >& interpolationInfo = *iInfo; + typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > FEMDegrees; + typedef UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... > SupportSizes; + + // Note: We can't iterate over the finer point nodes as the point weights might be + // scaled incorrectly, due to the adaptive exponent. So instead, we will iterate + // over the coarser nodes and evaluate the finer solution at the associated points. + LocalDepth lowDepth = highDepth-1; + if( lowDepth<0 ) return; + + node_index_type start = _sNodesBegin(lowDepth) , end = _sNodesEnd(lowDepth); + std::vector< ConstPointSupportKey< FEMDegrees > > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i& neighborKey = neighborKeys[ thread ]; + PointEvaluatorState< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > > peState; + const FEMTreeNode* node = _sNodes.treeNodes[i]; + + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + typename FEMTreeNode::template ConstNeighbors< SupportSizes >& neighbors = neighborKey.getNeighbors( node ); + size_t begin , end; + interpolationInfo.range( node , begin , end ); + for( size_t pIndex=begin ; pIndex& pData = interpolationInfo[ pIndex ]; + Point< Real , Dim > p = pData.position; + bsData.initEvaluationState( p , d , off , peState ); + +#ifdef _MSC_VER + CumulativeDerivativeValues< T , Dim , PointD > dualValues = interpolationInfo( pIndex , _finerFunctionValues< PointD , T , FEMSigs ... >( UIntPack< FEMSigs ... >() , pData.position , neighborKey , node , bsData , solution ) ) * pData.weight; +#else // !_MSC_VER + CumulativeDerivativeValues< T , Dim , PointD > dualValues = interpolationInfo( pIndex , _finerFunctionValues< PointD >( UIntPack< FEMSigs ... >() , pData.position , neighborKey , node , bsData , solution ) ) * pData.weight; +#endif // _MSC_VER + // Update constraints for all nodes @( depth-1 ) that overlap the point + int s[Dim]; + WindowLoop< Dim >::Run + ( + 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 ); + } + } , + neighbors.neighbors() + ); + } + } + } + ); +} + +template< unsigned int Dim , class Real > +template< class C , unsigned int ... FEMSigs > +DenseNodeData< C , UIntPack< FEMSigs ... > > FEMTree< Dim , Real >::coarseCoefficients( const DenseNodeData< C , UIntPack< FEMSigs ... > >& coefficients ) const +{ + 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]; } ); + typename FEMIntegrator::template RestrictionProlongation< UIntPack< FEMSigs ... > > rp; + for( LocalDepth d=1 ; d<_maxDepth ; d++ ) _upSample( UIntPack< FEMSigs ... >() , rp , d , coarseCoefficients() ); + return coarseCoefficients; +} + +template< unsigned int Dim , class Real > +template< class C , unsigned int ... FEMSigs > +DenseNodeData< C , UIntPack< FEMSigs ... > > FEMTree< Dim , Real >::coarseCoefficients( const SparseNodeData< C , UIntPack< FEMSigs ... > >& coefficients ) const +{ + 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 ) + { + const C* c = coefficients( _sNodes.treeNodes[i] ); + if( c ) coarseCoefficients[i] = *c; + } + ); + typename FEMIntegrator::template RestrictionProlongation< UIntPack< FEMSigs ... > > rp; + for( LocalDepth d=1 ; d<_maxDepth ; d++ ) _upSample( UIntPack< FEMSigs ... >() , rp , d , coarseCoefficients() ); + return coarseCoefficients; +} + +template< unsigned int Dim , class Real > +template< unsigned int PointD , typename T , unsigned int ... FEMSigs > +CumulativeDerivativeValues< T , Dim , PointD > FEMTree< Dim , Real >::_coarserFunctionValues( UIntPack< FEMSigs ... > , Point< Real , Dim > p , const ConstPointSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& neighborKey , const FEMTreeNode* pointNode , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , ConstPointer( T ) solution ) const +{ + typedef UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... > SupportSizes; + + CumulativeDerivativeValues< T , Dim , PointD > values; + LocalDepth depth = _localDepth( pointNode ); + if( depth<0 ) return values; + // Iterate over all basis functions that overlap the point at the coarser resolutions + { + + PointEvaluatorState< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > > peState; + LocalDepth _d ; LocalOffset _off; + _localDepthAndOffset( pointNode->parent , _d , _off ); + bsData.initEvaluationState( p , _d , _off , peState ); + const typename FEMTreeNode::template ConstNeighbors< SupportSizes >& neighbors = neighborKey.neighbors[ _localToGlobal( depth-1 ) ]; + ConstPointer( FEMTreeNode * const ) nodes = neighbors.neighbors().data; + + for( unsigned int i=0 ; i::Size ; i++ ) if( _isValidFEM1Node( nodes[i] ) ) + { + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( nodes[i] , d , off ); + CumulativeDerivativeValues< Real , Dim , PointD > temp = peState.template dValues< Real , CumulativeDerivatives< Dim , PointD > >( off ); + const T& _solution = solution[ nodes[i]->nodeData.nodeIndex ]; + for( int s=0 ; s::Size ; s++ ) values[s] += _solution * temp[s]; + } + } + return values; +} + +template< unsigned int Dim , class Real > +template< unsigned int PointD , typename T , unsigned int ... FEMSigs > +CumulativeDerivativeValues< T , Dim , PointD > FEMTree< Dim , Real >::_finerFunctionValues( UIntPack< FEMSigs ... > , Point< Real , Dim > p , const ConstPointSupportKey< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& neighborKey , const FEMTreeNode* pointNode , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , ConstPointer( T ) solution ) const +{ + typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... > > childNeighbors; + typedef UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... > SupportSizes; + + CumulativeDerivativeValues< T , Dim , PointD > values; + LocalDepth depth = _localDepth( pointNode ); + neighborKey.getChildNeighbors( _childIndex( pointNode , p ) , _localToGlobal( depth ) , childNeighbors ); + PointEvaluatorState< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > > peState; + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( pointNode , d , off ); + int cIdx = _childIndex( pointNode , p ); + d++; + for( int dd=0 ; dd>dd) & 1 ); + bsData.initEvaluationState( p , d , off , peState ); + int s[Dim]; + WindowLoop< Dim >::Run + ( + 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 > dValues = peState.template dValues< Real , CumulativeDerivatives< Dim , PointD > >( off ); + const T& _solution = solution[ node->nodeData.nodeIndex ]; + for( int s=0 ; s::Size ; s++ ) values[s] += _solution * dValues[s]; + } + } , + childNeighbors.neighbors() + ); + return values; +} + +template< unsigned int Dim , class Real > +template< unsigned int ... FEMSigs , typename T , unsigned int ... PointDs > +int FEMTree< Dim , Real >::_getSliceMatrixAndProlongationConstraints( UIntPack< FEMSigs ... > , const typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , SparseMatrix< Real , matrix_index_type , WindowSize< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >::Size >& 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 , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) const +{ + typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > FEMDegrees; + typedef UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > OverlapSizes; + typedef UIntPack< ( -BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapStart ) ... > OverlapRadii; + size_t range = nEnd - nBegin; + matrix.resize( range ); + std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i neighbors , pNeighbors; + neighborKey.getNeighbors( OverlapRadii() , OverlapRadii() , node , pNeighbors , neighbors ); + // Set the row entries + if( constraints ) constraints[i] = _setMatrixRowAndGetConstraintFromProlongation( UIntPack< FEMSigs ... >() , F , pNeighbors , neighbors , i , matrix , nBegin , pcStencils , ccStencil , bsData , prolongedSolution , interpolationInfo... ); + else _setMatrixRowAndGetConstraintFromProlongation( UIntPack< FEMSigs ... >() , F , pNeighbors , neighbors , i , matrix , nBegin , pcStencils , ccStencil , bsData , prolongedSolution , interpolationInfo... ); + if( diagonalR ) diagonalR[i] = (Real)1. / matrix[i][0].Value; + } + else if( constraints ) constraints[i] = T(); + } + ); +#ifdef SHOW_WARNINGS +#pragma message( "[WARNING] Why do we care if the node is not valid?" ) +#endif // SHOW_WARNINGS +#if !defined( _WIN32 ) && !defined( _WIN64 ) +#ifdef SHOW_WARNINGS +#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; +} + +template< unsigned int Dim , class Real > +template< typename T , unsigned int ... PointDs , unsigned int ... FEMSigs > +SparseMatrix< Real , matrix_index_type > FEMTree< Dim , Real >::systemMatrix( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , LocalDepth depth , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) const +{ + _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 ); + SparseMatrix< Real , matrix_index_type > matrix; + F.init( depth ); + PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > > bsData( depth ); + + typedef UIntPack< ( -BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapStart ) ... > OverlapRadii; + typedef UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > OverlapSizes; + + CCStencil< UIntPack< FEMSignature< FEMSigs >::Degree ... > > stencil; + PCStencils< UIntPack< FEMSignature< FEMSigs >::Degree ... > > stencils; + + F.template setStencil< false >( stencil ); + + matrix.resize( _sNodesSize(depth) ); + std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i neighbors; + neighborKey.getNeighbors( OverlapRadii() , OverlapRadii() , _sNodes.treeNodes[i] , neighbors ); + +#if defined( __GNUC__ ) && __GNUC__ < 5 + #warning "you've got me gcc version<5" + matrix.setRowSize( ii , _getMatrixRowSize( UIntPack< FEMSigs ... >() , neighbors ) ); +#else // !__GNUC__ || __GNUC__ >=5 + matrix.setRowSize( ii , _getMatrixRowSize< FEMSigs ... >( neighbors ) ); +#endif // __GNUC__ || __GNUC__ < 4 + _setMatrixRowAndGetConstraintFromProlongation( UIntPack< FEMSigs ... >() , F , neighbors , neighbors , matrix[ii] , _sNodesBegin(depth) , stencils , stencil , bsData , ( ConstPointer( T ) )NullPointer( T ) , interpolationInfo ... ); + } + } + ); + return matrix; +} + +template< unsigned int Dim , class Real > +template< typename T , unsigned int ... PointDs , unsigned int ... FEMSigs > +SparseMatrix< Real , matrix_index_type > FEMTree< Dim , Real >::prolongedSystemMatrix( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack::Degree ... > >& F , LocalDepth highDepth , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) const +{ + _setFEM1ValidityFlags( UIntPack< FEMSigs ... >() ); + if( highDepth<=0 || highDepth>_maxDepth ) ERROR_OUT( "System depth out of bounds: 0 < " , highDepth , " <= " , _maxDepth ); + + LocalDepth lowDepth = highDepth-1; + SparseMatrix< Real , matrix_index_type > matrix; + F.init( highDepth ); + PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > > bsData( highDepth ); + typedef UIntPack< ( -BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapStart ) ... > OverlapRadii; + typedef UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > OverlapSizes; + + PCStencils< UIntPack< FEMSignature< FEMSigs >::Degree ... > > stencils; + F.template setStencils< true >( stencils ); + + matrix.resize( _sNodesSize(highDepth) ); + std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; iparent->children ); + + ConstOneRingNeighborKey& neighborKey = neighborKeys[ thread ]; + typename FEMTreeNode::template ConstNeighbors< OverlapSizes > neighbors , pNeighbors; + neighborKey.getNeighbors( OverlapRadii() , OverlapRadii() , _sNodes.treeNodes[i] , neighbors ); + neighborKey.getNeighbors( OverlapRadii() , OverlapRadii() , _sNodes.treeNodes[i]->parent , pNeighbors ); + + matrix.setRowSize( ii , _getProlongedMatrixRowSize< FEMSigs ... >( _sNodes.treeNodes[i] , pNeighbors ) ); + _setProlongedMatrixRow< Real , PointDs ... >( F , neighbors , pNeighbors , matrix[ii] , _sNodesBegin(lowDepth) , stencils.data[cIdx] , bsData , interpolationInfo... ); + } + } + ); + return matrix; +} + +template< unsigned int Dim , class Real > +template< unsigned int ... FEMSigs > +SparseMatrix< Real , matrix_index_type > FEMTree< Dim , Real >::downSampleMatrix( UIntPack< FEMSigs ... > , LocalDepth highDepth ) const +{ + SparseMatrix< Real , matrix_index_type > matrix; + _setFEM1ValidityFlags( UIntPack< FEMSigs ... >() ); + typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > FEMDegrees; + typedef UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::UpSampleSize ... > UpSampleSizes; + typedef IntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::UpSampleStart ... > UpSampleStarts; + typedef typename FEMTreeNode::template ConstNeighborKey< UIntPack< -BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::UpSampleStart ... > , UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::UpSampleEnd ... > > UpSampleKey; + + LocalDepth lowDepth = highDepth-1; + if( lowDepth<0 ) return matrix; + + matrix.resize( _sNodesSize( lowDepth ) ); + + typename EvaluationData::UpSampleEvaluator* upSampleEvaluators[] = { new typename BSplineEvaluationData< FEMSigs >::UpSampleEvaluator() ... }; + for( int d=0 ; dset( lowDepth ); + std::vector< UpSampleKey > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i upSampleStencil; + int lowCenter = ( 1<>1; + double value[Dim+1] ; value[0] = 1; + WindowLoop< Dim >::Run + ( + ZeroUIntPack< Dim >() , UpSampleSizes() , + [&]( int d , int i ){ value[d+1] = value[d] * upSampleEvaluators[d]->value( lowCenter , 2*lowCenter + i + UpSampleStarts::Values[d] ); } , + [&]( double& stencilValue ){ stencilValue = value[Dim]; } , + upSampleStencil() + ); + + ThreadPool::Parallel_for( _sNodesBegin(lowDepth) , _sNodesEnd(lowDepth) , [&]( unsigned int thread , size_t i ) + { + if( _isValidFEM1Node( _sNodes.treeNodes[i] ) ) + { + node_index_type _i = (node_index_type)i - _sNodesBegin(lowDepth); + FEMTreeNode* pNode = _sNodes.treeNodes[i]; + + UpSampleKey& neighborKey = neighborKeys[ thread ]; + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( pNode , d , off ); + neighborKey.getNeighbors( pNode ); + typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::UpSampleSize ... > > neighbors; + neighborKey.getChildNeighbors( 0 , _localToGlobal( d ) , neighbors ); + + + int rowSize = 0; + ConstPointer( FEMTreeNode * const ) nodes = neighbors.neighbors().data; + for( int i=0 ; i::Size ; i++ ) if( _isValidFEM1Node( nodes[i] ) ) rowSize++; + + matrix.setRowSize( _i , rowSize ); + matrix.rowSizes[_i] = 0; + + // Want to make sure test if contained children are interior. + // This is more conservative because we are test that overlapping children are interior + bool isInterior = _isInteriorlyOverlapped( FEMDegrees() , FEMDegrees() , pNode ); + + if( isInterior ) + { + ConstPointer( FEMTreeNode * const ) nodes = neighbors.neighbors().data; + ConstPointer( double ) stencilValues = upSampleStencil().data; + for( int i=0 ; i::Size ; i++ ) if( _isValidFEM1Node( nodes[i] ) ) + matrix[_i][ matrix.rowSizes[_i]++ ] = MatrixEntry< Real , matrix_index_type >( (matrix_index_type)( nodes[i]->nodeData.nodeIndex - _sNodesBegin(highDepth) ) , (Real)stencilValues[i] ); + } + else + { + double upSampleValues[Dim][ UpSampleSizes::Max() ]; + + WindowLoop< Dim >::Run + ( + ZeroUIntPack< Dim >() , UpSampleSizes() , + [&]( int d , int i ){ upSampleValues[d][i] = upSampleEvaluators[d]->value( off[d] , 2*off[d] + i + UpSampleStarts::Values[d] ); } , + [&]( void ){} + ); + + double values[Dim+1] ; values[0] = 1; + WindowLoop< Dim , Dim >::Run + ( + ZeroUIntPack< Dim >() , UpSampleSizes() , + [&]( int d , int i ){ values[d+1] = values[d] * upSampleValues[d][i]; } , + [&]( const FEMTreeNode* node ){ if( _isValidFEM1Node( node ) ) matrix[_i][ matrix.rowSizes[_i]++ ] = MatrixEntry< Real , matrix_index_type >( (matrix_index_type)( node->nodeData.nodeIndex - _sNodesBegin(highDepth) ) , (Real)values[Dim] ); } , + neighbors.neighbors() + ); + } + } + } + ); + for( int d=0 ; d +template< typename T , unsigned int ... PointDs , unsigned int ... FEMSigs > +SparseMatrix< Real , matrix_index_type > FEMTree< Dim , Real >::fullSystemMatrix( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , LocalDepth depth , bool nonRefinableOnly , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) const +{ + SparseMatrix< Real , matrix_index_type > M; + std::vector< SparseMatrix< Real , matrix_index_type > > systemMatrices( depth+1 ); + std::vector< SparseMatrix< Real , matrix_index_type > > prolongedSystemMatrices( depth ); + std::vector< std::vector< SparseMatrix< Real , matrix_index_type > > > upSampleMatrices( depth-1 ); + + for( int d=0 ; d& M = systemMatrices[d]; + M.resize( size ); + SparseMatrix< Real , matrix_index_type > _M = systemMatrix< Real >( UIntPack< FEMSigs ... >() , F , d , interpolationInfo ... ); + ThreadPool::Parallel_for( 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 ); + } + ); + } + for( int d=0 ; d& M = prolongedSystemMatrices[d]; + M.resize( size ); + SparseMatrix< Real , matrix_index_type > _M = prolongedSystemMatrix< Real >( UIntPack< FEMSigs ... >() , F , d+1 , interpolationInfo ... ); + ThreadPool::Parallel_for( 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 ); + } + ); + } + for( int d=0 ; d& 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 ) + { + 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 ); + } + ); + for( int dd=0 ; dd _M; + int _d1 = d1 _M = Matrix( d1 , d2 ); + ThreadPool::Parallel_for( 0 , _M.rows() , [&]( unsigned int , size_t i ) + { + if( _M.rowSize(i) ) + { + size_t oldSize = M.rowSize(i); + M.resetRowSize( i , oldSize + _M.rowSize(i) ); + for( int j=0 ; j<_M.rowSize(i) ; j++ ) M[i][oldSize+j] = _M[i][j]; + } + } + ); + } + } + if( nonRefinableOnly ) + { + _setRefinabilityFlags( UIntPack< FEMSigs ... >() ); + _setFEM1ValidityFlags( UIntPack< FEMSigs ... >() ); + ThreadPool::Parallel_for( 0 , M.rows() , [&]( unsigned int , size_t i ) + { + if( ( _isRefinableNode( _sNodes.treeNodes[i] ) && _localDepth( _sNodes.treeNodes[i] )( i , (Real)1. ); + } + else + { + int jj=0; + for( int j=0 ; j +template< class C , unsigned int ... Degrees , unsigned int ... FEMSigs > +void FEMTree< Dim , Real >::_downSample( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template RestrictionProlongation< UIntPack< Degrees ... > >& rp , LocalDepth highDepth , Pointer( C ) constraints ) const +{ + LocalDepth lowDepth = highDepth-1; + if( lowDepth<0 ) return; + + typedef typename BaseFEMIntegrator::RestrictionProlongation< UIntPack< Degrees ... > > BaseRestrictionProlongation; + typedef typename FEMTreeNode::template ConstNeighborKey< UIntPack< ( - BSplineSupportSizes< Degrees >::UpSampleStart ) ... > , UIntPack< BSplineSupportSizes< Degrees >::UpSampleEnd ... > > UpSampleKey; + typedef typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineSupportSizes< Degrees >::UpSampleSize ... > > UpSampleNeighbors; + typedef UIntPack< BSplineSupportSizes< Degrees >::UpSampleSize ... > UpSampleSizes; + + std::vector< UpSampleKey > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i() , UIntPack< Degrees ... >() , d , off ); + if( isInterior ) + { + Pointer( const FEMTreeNode* ) nodes = neighbors.neighbors().data; + Pointer( double ) stencilValues = upSampleStencil.data; + for( unsigned int i=0 ; i::Size ; i++ ) + if( _isValidFEM1Node( nodes[i] ) ) coarseConstraint += (C)( constraints[ nodes[i]->nodeData.nodeIndex ] * (Real)stencilValues[i] ); + } + else + { + ConstPointer( FEMTreeNode * const ) nodes = neighbors.neighbors().data; + for( int i=0 ; i::Size ; i++ ) if( _isValidFEM1Node( nodes[i] ) ) + { + LocalDepth _d ; LocalOffset _off; + _localDepthAndOffset( nodes[i] , _d , _off ); + coarseConstraint += (C)( constraints[ nodes[i]->nodeData.nodeIndex ] * (Real)rp.upSampleCoefficient( off , _off ) ); + } + } + } + } + ); +} + +template< unsigned int Dim , class Real > +template< unsigned int ... FEMSigs > +DenseNodeData< Real , UIntPack< FEMSigs ... > > FEMTree< Dim , Real >::supportWeights( UIntPack< FEMSigs ... > ) const +{ + typedef typename BaseFEMIntegrator::template System< UIntPack< FEMSignature< FEMSigs >::Degree ... > > BaseSystem; + typedef typename BaseFEMIntegrator::template Constraint< UIntPack< FEMSignature< FEMSigs >::Degree ... > , IsotropicUIntPack< Dim , 0 > , 1 > BaseConstraint; + typedef UIntPack< ( BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree , 0 >::OverlapSize ) ... > OverlapSizes; + typedef UIntPack< ( -BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree , 0 >::OverlapStart ) ... > LeftFEMCOverlapRadii; + typedef UIntPack< ( BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree , 0 >::OverlapEnd ) ... > RightFEMCOverlapRadii; + _setFEM1ValidityFlags( UIntPack< FEMSigs ... >() ); + typename FEMIntegrator::template ScalarConstraint< UIntPack< FEMSigs ... > , ZeroUIntPack< Dim > , IsotropicUIntPack< Dim , FEMTrivialSignature > , ZeroUIntPack< Dim > > F( {1.} ); + DenseNodeData< Real , UIntPack< FEMSigs ... > > weights = initDenseNodeData( UIntPack< FEMSigs ... >() ); + typename BaseConstraint::CCStencil stencil; + std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); + for( int d=0 ; d<=_maxDepth ; d++ ) + { + for( size_t i=0 ; i( stencil ); + ThreadPool::Parallel_for( _sNodesBegin(d) , _sNodesEnd(d) , [&]( unsigned int thread , size_t i ) + { + if( _isValidFEM1Node( _sNodes.treeNodes[i] ) ) + { + ConstOneRingNeighborKey& neighborKey = neighborKeys[ thread ]; + + FEMTreeNode* node = _sNodes.treeNodes[i]; + typename FEMTreeNode::template ConstNeighbors< OverlapSizes > neighbors; + LocalOffset off; + { + LocalDepth d ; _localDepthAndOffset( node , d , off ); + } + neighborKey.getNeighbors( LeftFEMCOverlapRadii() , RightFEMCOverlapRadii() , node , neighbors ); + bool isInterior = BaseFEMIntegrator::IsInteriorlyOverlapped( UIntPack< FEMSignature< FEMSigs >::Degree ... >() , ZeroUIntPack< Dim >() , d , off ); + double sum=0 , totalSum=0; + if( isInterior ) + { + ConstPointer( FEMTreeNode * const ) nodes = neighbors.neighbors().data; + ConstPointer( Point< double , 1 > ) stencilValues = stencil.data; + for( int i=0 ; i::Degree , 0 >::OverlapSize ... > >::Size ; i++ ) + { + double s = stencilValues[i][0]; + totalSum += s; + if( isValidSpaceNode( nodes[i] ) ) sum += s; + } + } + else + { + static const int OverlapStart [] = { BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree , 0 >::OverlapStart ... }; + LocalOffset _off; + WindowLoop< Dim >::Run + ( + IsotropicUIntPack< Dim , 0 >() , OverlapSizes() , + [&]( int d , int i ){ _off[d] = off[d]+i+OverlapStart[d]; } , + [&]( const FEMTreeNode* node ) + { + double s = F.ccIntegrate( off , _off )[0]; + totalSum += s; + if( isValidSpaceNode( node ) ) sum += s; + } , + neighbors.neighbors() + ); + } + weights[i] = (Real)( sum / totalSum ); + } + } + ); + } + return weights; +} +template< unsigned int Dim , class Real > +template< unsigned int ... FEMSigs > +DenseNodeData< Real , UIntPack< FEMSigs ... > > FEMTree< Dim , Real >::prolongationWeights( UIntPack< FEMSigs ... > , bool prolongToChildren ) const +{ + DenseNodeData< Real , UIntPack< FEMSigs ... > > weights = initDenseNodeData( UIntPack< FEMSigs ... >() ); + + _setFEM1ValidityFlags( UIntPack< FEMSigs ... >() ); + typedef typename BaseFEMIntegrator::RestrictionProlongation< UIntPack< FEMSignature< FEMSigs >::Degree ... > > BaseRestrictionProlongation; + typedef typename FEMIntegrator::template RestrictionProlongation< UIntPack< FEMSigs ... > > RestrictionProlongation; + + typename BaseRestrictionProlongation::DownSampleStencils downSampleStencils; + RestrictionProlongation rp; + + typedef typename FEMTreeNode::template ConstNeighborKey< UIntPack< ( - BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::UpSampleStart ) ... > , UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::UpSampleEnd ... > > UpSampleKey; + typedef typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::UpSampleSize ... > > UpSampleNeighbors; + typedef typename FEMTreeNode::template ConstNeighborKey< UIntPack< - BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::DownSample0Start ... > , UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::DownSample1End ... > > DownSampleKey; + typedef typename FEMTreeNode::template ConstNeighbors< UIntPack< ( - BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::DownSample0Start + BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::DownSample1End + 1 ) ... > > DownSampleNeighbors; + const int UpSampleStart[] = { BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::UpSampleStart ... }; + const int DownSampleStart[2][Dim] = { { BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::DownSample0Start ... } , { BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::DownSample1Start ... } }; + const int DownSampleEnd[2][Dim] = { { BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::DownSample0End ... } , { BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::DownSample1End ... } }; + + std::vector< UpSampleKey > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i::Degree ... >() , UIntPack< FEMSignature< FEMSigs >::Degree ... >() , d , pOff ); + + LocalOffset cOff; + if( isInterior ) + { + WindowLoop< Dim >::Run + ( + IsotropicUIntPack< Dim , 0 >() , UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::UpSampleSize ... >() , + [&]( int d , int i ){ cOff[d] = UpSampleStart[d] + pOff[d]*2 + i; } , + [&]( const FEMTreeNode* node , double stencilValue ) + { + if( FEMIntegrator::IsValidFEMNode( UIntPack< FEMSigs ... >() , lowDepth+1 , cOff ) ) + { + totalSum += stencilValue; + if( _isValidFEM1Node( node ) ) partialSum += stencilValue; + } + } , + neighbors.neighbors() , upSampleStencil() + ); + } + else + { + WindowLoop< Dim >::Run + ( + IsotropicUIntPack< Dim , 0 >() , UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::UpSampleSize ... >() , + [&]( int d , int i ){ cOff[d] = UpSampleStart[d] + pOff[d]*2 + i; } , + [&]( const FEMTreeNode* node ) + { + if( FEMIntegrator::IsValidFEMNode( UIntPack< FEMSigs ... >() , lowDepth+1 , cOff ) ) + { + double stencilValue = rp.upSampleCoefficient( pOff , cOff ); + totalSum += stencilValue; + if( _isValidFEM1Node( node ) ) partialSum += stencilValue; + } + } , + neighbors.neighbors() + ); + } + weights[i] = (Real)( partialSum / totalSum ); + } + } + ); + } + if( prolongToChildren ) + { + std::vector< DownSampleKey > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i=0 ; lowDepth-- ) + { + ( ( BaseRestrictionProlongation& )rp ).init( lowDepth+1 ); + typename BaseRestrictionProlongation::DownSampleStencils downSampleStencils; + rp.setStencils( downSampleStencils ); + + ThreadPool::Parallel_for( _sNodesBegin(lowDepth+1) , _sNodesEnd(lowDepth+1) , [&]( unsigned int thread , size_t i ) + { + if( _isValidFEM1Node( _sNodes.treeNodes[i] ) ) + { + FEMTreeNode *cNode = _sNodes.treeNodes[i]; + int c = (int)( cNode-cNode->parent->children ); + + DownSampleKey& neighborKey = neighborKeys[ thread ]; + LocalDepth d ; LocalOffset cOff; + _localDepthAndOffset( cNode , d , cOff ); + DownSampleNeighbors neighbors = neighborKey.getNeighbors( cNode->parent ); + // Want to make sure test if contained children are interior. + // This is more conservative because we are test that overlapping children are interior + bool isInterior; + { + LocalDepth d ; LocalOffset pOff; + _localDepthAndOffset( cNode->parent , d , pOff ); + isInterior = BaseFEMIntegrator::IsInteriorlyOverlapped( UIntPack< FEMSignature< FEMSigs >::Degree ... >() , UIntPack< FEMSignature< FEMSigs >::Degree ... >() , d , pOff ); + } + + typename BaseRestrictionProlongation::DownSampleStencil& downSampleStencil = downSampleStencils.data[c]; + int start[Dim] , end[Dim]; + for( int d=0 ; d>d)&1][d] - DownSampleStart[0][d] , end[d] = - DownSampleStart[0][d] + DownSampleEnd[(c>>d)&1][d] + 1; + + double partialSum = 0 , totalSum = 0; + if( isInterior ) + { + WindowLoop< Dim >::Run + ( + start , end , + [&]( int , int ){ } , + [&]( const FEMTreeNode* node , double stencilValue ){ if( _isValidFEM1Node( node ) ) totalSum += stencilValue , partialSum += weights[ node->nodeData.nodeIndex ] * stencilValue; } , + neighbors.neighbors() , downSampleStencil() + ); + } + else + { + WindowLoop< Dim >::Run + ( + start , end , + [&]( int , int ){ } , + [&]( const FEMTreeNode* node ) + { + if( _isValidFEM1Node( node ) ) + { + LocalDepth d ; LocalOffset pOff; + _localDepthAndOffset( node , d , pOff ); + double stencilValue = rp.upSampleCoefficient( pOff , cOff ); + totalSum += stencilValue , partialSum += weights[ node->nodeData.nodeIndex ] * stencilValue; + } + } , + neighbors.neighbors() + ); + } + weights[i] = (Real)( partialSum / totalSum ); + } + } + ); + } + } + return weights; +} + +template< unsigned int Dim , class Real > +template< class C , unsigned int ... Degrees , unsigned int ... FEMSigs > +void FEMTree< Dim , Real >::_upSample( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template RestrictionProlongation< UIntPack< Degrees ... > >& rp , LocalDepth highDepth , Pointer( C ) coefficients ) const +{ + LocalDepth lowDepth = highDepth-1; + if( lowDepth<0 ) return; + typedef typename BaseFEMIntegrator::RestrictionProlongation< UIntPack< Degrees ... > > BaseRestrictionProlongation; + typedef typename FEMTreeNode::template ConstNeighborKey< UIntPack< - BSplineSupportSizes< Degrees >::DownSample0Start ... > , UIntPack< BSplineSupportSizes< Degrees >::DownSample1End ... > > DownSampleKey; + typedef typename FEMTreeNode::template ConstNeighbors< UIntPack< ( - BSplineSupportSizes< Degrees >::DownSample0Start + BSplineSupportSizes< Degrees >::DownSample1End + 1 ) ... > > DownSampleNeighbors; + typedef UIntPack< ( - BSplineSupportSizes< Degrees >::DownSample0Start + BSplineSupportSizes< Degrees >::DownSample1End + 1 ) ... > DownSampleSizes; + + std::vector< DownSampleKey > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i::DownSample0Start ... } , { BSplineSupportSizes< Degrees >::DownSample1Start ... } }; + const int End[2][Dim] = { { BSplineSupportSizes< Degrees >::DownSample0End ... } , { BSplineSupportSizes< Degrees >::DownSample1End ... } }; + + static const WindowLoopData< UIntPack< ( - BSplineSupportSizes< Degrees >::DownSample0Start + BSplineSupportSizes< Degrees >::DownSample1End + 1 ) ... > > loopData + ( []( int c , int* start , int* end ) + { + const int Start[2][Dim] = { { BSplineSupportSizes< Degrees >::DownSample0Start ... } , { BSplineSupportSizes< Degrees >::DownSample1Start ... } }; + const int End[2][Dim] = { { BSplineSupportSizes< Degrees >::DownSample0End ... } , { BSplineSupportSizes< Degrees >::DownSample1End ... } }; + for( int d=0 ; d>d)&1][d] - Start[0][d] , end[d] = - Start[0][d] + End[(c>>d)&1][d] + 1; + } + ); + // 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 ) + { + if( _isValidFEM1Node( _sNodes.treeNodes[i] ) ) + { + FEMTreeNode *cNode = _sNodes.treeNodes[i]; + int c = (int)( cNode-cNode->parent->children ); + + DownSampleKey& neighborKey = neighborKeys[ thread ]; + DownSampleNeighbors neighbors = neighborKey.getNeighbors( cNode->parent ); + // Want to make sure test if contained children are interior. + // This is more conservative because we are test that overlapping children are interior + bool isInterior; + { + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( cNode->parent , d , off ); + isInterior = BaseFEMIntegrator::IsInteriorlyOverlapped( UIntPack< Degrees ... >() , UIntPack< Degrees ... >() , d , off ); + } + + C& fineCoefficient = coefficients[ cNode->nodeData.nodeIndex ]; + + typename BaseRestrictionProlongation::DownSampleStencil& downSampleStencil = downSampleStencils.data[c]; + unsigned int size = loopData.size[c]; + const unsigned int* indices = loopData.indices[c]; + Pointer( const FEMTreeNode* ) nodes = neighbors.neighbors().data; + Pointer( double ) downSampleValues = downSampleStencil.data; + if( isInterior ) + { + for( unsigned int i=0 ; inodeData.nodeIndex ] * (Real)downSampleValues[idx] ); + } + } + else + { + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( cNode , d , off ); + for( unsigned int i=0 ; inodeData.nodeIndex ] * (Real)rp.upSampleCoefficient( _off , off ) ); + } + } + } + } + } + ); +} + +template< unsigned int Dim , class Real > +template< bool XMajor , class C , unsigned int ... FEMSigs > +void FEMTree< Dim , Real >::_RegularGridUpSample( UIntPack< FEMSigs ... > , LocalDepth highDepth , ConstPointer( C ) lowCoefficients , Pointer( C ) highCoefficients ) +{ + LocalDepth lowDepth = highDepth - 1; + if( lowDepth<0 ) return; + + int lowBegin[Dim] , lowEnd[Dim] , highBegin[Dim] , highEnd[Dim]; + FEMIntegrator::BSplineBegin( UIntPack< FEMSigs ... >() , lowDepth , lowBegin ); + FEMIntegrator::BSplineEnd ( UIntPack< FEMSigs ... >() , lowDepth , lowEnd ); + FEMIntegrator::BSplineBegin( UIntPack< FEMSigs ... >() , highDepth , highBegin ); + FEMIntegrator::BSplineEnd ( UIntPack< FEMSigs ... >() , highDepth , highEnd ); + + _RegularGridUpSample< XMajor >( UIntPack< FEMSigs ... >() , lowBegin , lowEnd , highBegin , highEnd , highDepth , lowCoefficients , highCoefficients ); +} +template< unsigned int Dim , class Real > +template< bool XMajor , class C , unsigned int ... FEMSigs > +void FEMTree< Dim , Real >::_RegularGridUpSample( UIntPack< FEMSigs ... > , const int lowBegin[] , const int lowEnd[] , const int highBegin[] , const int highEnd[] , LocalDepth highDepth , ConstPointer( C ) lowCoefficients , Pointer( C ) highCoefficients ) +{ + // Note: In contrast to the standard grid indexing, where x is the major index in (x,y,z,...) + // For our representation of the grid, x is the minor index + LocalDepth lowDepth = highDepth - 1; + if( lowDepth<0 ) return; + + static const int LeftDownSampleRadii[] = { -( ( BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::DownSample0Start < BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::DownSample1Start ) ? BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::DownSample0Start : BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::DownSample1Start ) ... }; + static const int DownSampleStart[][ sizeof...(FEMSigs) ] = { { BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::DownSample0Start ... } , { BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::DownSample1Start ... } }; + static const unsigned int DownSampleSize [][ sizeof...(FEMSigs) ] = { { BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::DownSample0Size ... } , { BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::DownSample1Size ... } }; + typedef UIntPack< ( - BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::DownSample0Start + BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::DownSample1End + 1 ) ... > DownSampleSizes; + typedef typename FEMIntegrator::template RestrictionProlongation< UIntPack< FEMSigs ... > > RestrictionProlongation; + typedef typename BaseFEMIntegrator::template RestrictionProlongation< UIntPack< FEMSignature< FEMSigs >::Degree ... > > BaseRestrictionProlongation; + + RestrictionProlongation rp; + typename BaseRestrictionProlongation::DownSampleStencils downSampleStencils; + rp.init( highDepth ); + rp.setStencils( downSampleStencils ); + + struct LoopData + { + unsigned int size[1<::Degree >::DownSample0Start + BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::DownSample1End + 1 ) ... > >::Size ]; + long long offsets[1<::Degree >::DownSample0Start + BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::DownSample1End + 1 ) ... > >::Size ]; + LoopData( const int lowBegin[] , const int lowEnd[] , const int highBegin[] , const int highEnd[] ) + { + int start[Dim] , end[Dim] , lowDim[Dim] , highDim[Dim]; + for( int d=0 ; d=0 ; d-- ) lowDimMultiplier[d] = lowDimMultiplier[d+1] * (lowEnd[d+1]-lowBegin[d+1]) , highDimMultiplier[d] = highDimMultiplier[d+1] * (highEnd[d+1]-highBegin[d+1]); + } + + for( int c=0 ; c<(1<>d)&1][d] + LeftDownSampleRadii[d] , end[d] = start[d] + DownSampleSize[(c>>d)&1][d]; + + unsigned int idx[Dim]; + long long off[Dim+1]; + off[0] = 0; + WindowLoop< Dim >::Run + ( + start , end , + [&]( int d , int i ){ idx[d] = i ; off[d+1] = off[d] + ( i - LeftDownSampleRadii[d] - lowBegin[d] ) * lowDimMultiplier[d]; } , + [&]( void ){ indices[c][ size[c] ] = GetWindowIndex( DownSampleSizes() , idx ) , offsets[c][ size[c] ] = off[Dim] ; size[c]++; } + ); + } + } + }; + const LoopData loopData( lowBegin , lowEnd , highBegin , highEnd ); + int lowDim[Dim] , highDim[Dim]; + for( int d=0 ; d=0 ; d-- ) lowDimMultiplier[d] = lowDimMultiplier[d+1] * (lowEnd[d+1]-lowBegin[d+1]) , highDimMultiplier[d] = highDimMultiplier[d+1] * (highEnd[d+1]-highBegin[d+1]); + } + + + struct UpdateData + { + typedef UIntPack< FEMSignature< FEMSigs >::Degree ... > Degrees; + LocalOffset pOff , cOff; + int c; + long long lowIndex[Dim+1] , highIndex[Dim+1]; + bool isInterior[Dim+1]; + int start[Dim] , end[Dim]; + void init( int lowDepth , const int lowBegin[] , const int lowEnd[] , const int highBegin[] , const int highEnd[] ) + { + c = 0; + lowIndex[0] = highIndex[0] = 0; + isInterior[0] = true; + this->lowBegin = lowBegin , this->lowEnd = lowEnd , this->highBegin = highBegin , this->highEnd = highEnd; + if( XMajor ) + { + _lowDim[0] = _highDim[0] = 1; + for( int d=1 ; d=0 ; d-- ) _lowDim[d] = _lowDim[d+1] * (lowEnd[d+1]-lowBegin[d+1]) , _highDim[d] = _highDim[d+1] * (highEnd[d+1]-highBegin[d+1]); + } + BaseFEMIntegrator::InteriorOverlappedSpan( Degrees() , Degrees() , lowDepth , _begin , _end ); + } + void set( int d , int i ) + { + int ii = i + highBegin[d]; + cOff[d] = ii; + pOff[d] = (ii>>1); + c = ( c & ( ~(1<>d)&1][d] + LeftDownSampleRadii[d] , end[d] = start[d] + DownSampleSize[(c>>d)&1][d]; + isInterior[d+1] = isInterior[d] && ( pOff[d] + start[d] - LeftDownSampleRadii[d] )>=lowBegin[d] && ( pOff[d] + end[d] - LeftDownSampleRadii[d] )=_begin[d] && pOff[d]<_end[d]; + } + protected: + const int *lowBegin , *lowEnd , *highBegin , *highEnd; + int _lowDim[Dim] , _highDim[Dim] , _begin[Dim] , _end[Dim]; + }; + std::vector< UpdateData > updateData( ThreadPool::NumThreads() ); + for( int i=0 ; i::RunParallel + ( + Zero , highDim , + [&]( unsigned int t , int d , size_t i ){ updateData[t].set( d , (int)i ); } , + [&]( unsigned int t ) + { + const UpdateData& data = updateData[t]; + const long long highIdx = data.highIndex[Dim] , lowIndex = data.lowIndex[Dim]; + const int c = data.c; + const bool isInterior = data.isInterior[Dim]; + + C highCoefficient = {}; + + if( isInterior ) + { + typename BaseRestrictionProlongation::DownSampleStencil& downSampleStencil = downSampleStencils.data[c]; + const unsigned int size = loopData.size[c]; + const unsigned int* idx = loopData.indices[c]; + const long long* off = loopData.offsets[c]; + ConstPointer( double ) stencilValues = downSampleStencil.data; + ConstPointer( C ) _lowCoefficients = lowCoefficients + lowIndex; + for( unsigned int i=0 ; i::Run + ( + start , end , + [&]( int d , int i ) + { + _pOff[d] = pOff[d] + i - LeftDownSampleRadii[d]; + lowIdx[d+1] = lowIdx[d] + lowDimMultiplier[d] * ( _pOff[d] - lowBegin[d] ); + isValid[d+1] = isValid[d] && ( _pOff[d]>=lowBegin[d] && _pOff[d] +template< unsigned int ... FEMSigs , typename T , typename TDotT , unsigned int ... PointDs > +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 , InterpolationInfo< T , PointDs >* ... interpolationInfo ) const +{ + DenseNodeData< T , UIntPack< FEMSigs ... > > solution; + solveSystem( UIntPack< FEMSigs ... >() , F , constraints , solution , Dot , maxSolveDepth , solverInfo , interpolationInfo... ); + return solution; +} +template< unsigned int Dim , class Real > +template< unsigned int ... FEMSigs , typename T , typename TDotT , unsigned int ... PointDs > +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 , InterpolationInfo< T , PointDs >* ... interpolationInfo ) const +{ + int baseDepth = solverInfo.baseDepth; + if( baseDepth>getFullDepth( UIntPack< FEMSignature< FEMSigs >::Degree ... >() ) ) ERROR_OUT( "Base depth cannot excceed full depth: " , baseDepth , " <= " , getFullDepth( UIntPack< FEMSignature< FEMSigs >::Degree ... >() ) ); + + static_assert( Dim==sizeof ... ( FEMSigs ) , "[ERROR] FEMTree:solveSystem: Dimensions and number of signatures don't match" ); + _setFEM1ValidityFlags( UIntPack< FEMSigs ... >() ); + PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > > bsData( sizeof...(PointDs)==0 ? 0 : maxSolveDepth ); + + maxSolveDepth = std::min< LocalDepth >( maxSolveDepth , _maxDepth ); + + bool clearSolution = solution.size()!=_sNodesEnd( _maxDepth ); + if( clearSolution ) solution = initDenseNodeData< T >( UIntPack< FEMSigs ... >() ) , clearSolution = true; + bool simpleSolve = clearSolution && solverInfo.vCycles==1 && solverInfo.cascadic; + + // The initial estimate of the solution (may be empty or may come in with an initial guess) + Pointer( T ) _solution = solution(); + // The constraints + ConstPointer( T ) _constraints = constraints(); + + // _residualConstraints: + // -- stores the difference between the initial constraints and the constraints met by the current solution at all _other_ levels + // **** This could implemented in one of two ways: + // **** (1) Repeatedly computing the difference using the entire solution + // **** (2) Iteratively updating using the change in the solution + // **** We have opted for #1 to avoid having to compute/store the change in the solution after each solve + Pointer( T ) _residualConstraints = AllocPointer< T >( _sNodesEnd( _maxDepth-1 ) ); + // The constraints met during the restriction phase + Pointer( T ) _restrictedConstraints = NullPointer( T ); + // The solution obtained during the prolongation phase + Pointer( T ) _prolongedSolution = AllocPointer< T >( _sNodesEnd( _maxDepth-1 ) ); + + memset( _prolongedSolution , 0 , sizeof(T) * _sNodesEnd( _maxDepth-1 ) ); + if( !( clearSolution && solverInfo.vCycles==1 && solverInfo.cascadic ) ) + { + _restrictedConstraints = AllocPointer< T >( _sNodesEnd( _maxDepth-1 ) ); + memset( _restrictedConstraints , 0 , sizeof(T) * _sNodesEnd( _maxDepth-1 ) ); + } + + Pointer( double ) _bNorm2 = NullPointer( double ); + if( solverInfo.showGlobalResidual!=SHOW_GLOBAL_RESIDUAL_NONE ) + { + _bNorm2 = AllocPointer< double >( _maxDepth+1 ); + memset( _bNorm2 , 0 , sizeof(double) * ( _maxDepth+1 ) ); + for( LocalDepth d=baseDepth ; d<=maxSolveDepth ; d++ ) for( node_index_type i=_sNodesBegin(d) ; i<_sNodesEnd(d) ; i++ ) _bNorm2[d] += Dot( _constraints[i] , _constraints[i] ); + } + + auto UpdateProlongation = [&] ( int depth ) + { + if( depth<_maxDepth && _prolongedSolution ) + { + memset( _prolongedSolution + _sNodesBegin( depth ) , 0 , sizeof( T ) * _sNodesSize( depth ) ); + // Up-sample the prolonged solution @(depth-1) into the prolonged solution @(depth) + F.init( depth ); + if( depth>baseDepth ) _upSample( UIntPack< FEMSigs ... >() , F.restrictionProlongation() , depth , _prolongedSolution ); + // 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]; } ); + } + }; + auto UpdateRestriction = [&]( int depth , InterpolationInfo< T , PointDs >* ... interpolationInfo ) + { + if( depth>baseDepth && _restrictedConstraints ) + { + memset( _restrictedConstraints + _sNodesBegin( depth-1 ) , 0 , sizeof( T ) * _sNodesSize( depth-1 ) ); + // Update the restricted constraints @(depth-1) based on the solution @(depth) + F.init( depth ); + _updateRestrictedIntegralConstraints( UIntPack< FEMSigs ... >() , F , depth , ( ConstPointer(T) )_solution , _restrictedConstraints ); + _updateRestrictedInterpolationConstraints( bsData , depth , ( ConstPointer( T ) )_solution , _restrictedConstraints , interpolationInfo... ); + // Down-sample the restricted constraints @(depth) into the restricted constraints @(depth-1) + if( depth<_maxDepth ) _downSample( UIntPack< FEMSigs ... >() , F.restrictionProlongation() , depth , _restrictedConstraints ); + } + }; + auto SetResidualConstraints = [&]( int depth , InterpolationInfo< T , PointDs >* ... interpolationInfo ) + { + // Copy the constraints + if( depth<_maxDepth ) memcpy( _residualConstraints + _sNodesBegin(depth) , _constraints + _sNodesBegin(depth) , sizeof( T ) * _sNodesSize(depth) ); + + // Update the constraints @(depth) using the prolonged solution @(depth-1) + if( depth>baseDepth && _prolongedSolution ) _setPointValuesFromProlongedSolution( depth , bsData , ( ConstPointer( T ) )_prolongedSolution , interpolationInfo... ); + // 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]; } ); + }; + auto OutputSolverStats = [&] ( int cycle , int depth , const _SolverStats& sStats , bool showResidual , int actualIters ) + { + if( solverInfo.verbose ) + { + node_index_type femNodes = (node_index_type)validFEMNodes( UIntPack< FEMSigs ... >() , depth ); + if( maxSolveDepth<10 ) + if( solverInfo.vCycles<10 ) printf( "Cycle[%d] Depth[%d/%d]:\t" , cycle , depth , maxSolveDepth ); + else printf( "Cycle[%2d] Depth[%d/%d]:\t" , cycle , depth , maxSolveDepth ); + 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 ); + } + if( solverInfo.showResidual && showResidual ) + { + for( int d=baseDepth ; d %.4e -> %.4e (%.1e) [%d]\n" , depth<=solverInfo.cgDepth ? "CG" : "GS" , sqrt( sStats.bNorm2 ) , sqrt( sStats.inRNorm2 ) , sqrt( sStats.outRNorm2 ) , sqrt( sStats.outRNorm2 / sStats.inRNorm2 ) , actualIters ); + } + }; + + // Set the cumulative solution + if( !clearSolution ) for( LocalDepth d=baseDepth ; d > supportWeights , prolongationSupportWeights; + std::function< Real (Real,Real) > sorFunction; + Real operator[] ( node_index_type idx ) const + { + if ( supportWeights() && prolongationSupportWeights() ) return sorFunction( supportWeights[idx] , prolongationSupportWeights[idx] ); + else if( supportWeights() ) return sorFunction( supportWeights[idx] , 1 ); + else if( prolongationSupportWeights() ) return sorFunction( 1 , prolongationSupportWeights[idx] ); + else return sorFunction( 1 , 1 ); + } + }; + SORWeights sorWeights; + if( solverInfo.useSupportWeights ) sorWeights.supportWeights = supportWeights( UIntPack< FEMSigs ... >() ); + if( solverInfo.useProlongationSupportWeights ) sorWeights.prolongationSupportWeights = prolongationWeights( UIntPack< FEMSigs ... >() , false ); + + auto SolveRestriction = [&]( int v , int depth , InterpolationInfo< T , PointDs >* ... interpolationInfo ) + { + sorWeights.sorFunction = solverInfo.sorRestrictionFunction; + // The restriction phase + if( solverInfo.cascadic ) + { + showResidual = false; + if( !clearSolution || v>0 ) for( LocalDepth d=depth ; d>=baseDepth ; d-- ) { F.init( d ) ; UpdateRestriction( d , interpolationInfo ... ); } + } + else + { + bool coarseToFine = false; + for( LocalDepth d=depth ; d>=baseDepth ; d-- ) + { + sStats.constraintUpdateTime = 0; + showResidual = ( d!=baseDepth ); + int iters = solverInfo.iters( v , true , d ); + t = Time(); + F.init( d ); + SetResidualConstraints( d , interpolationInfo... ); + sStats.constraintUpdateTime += Time()-t; + // 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 , d , _solution , d==_maxDepth ? _constraints : _residualConstraints , Dot , solverInfo.baseVCycles , iters , sStats , solverInfo.showResidual , solverInfo.cgAccuracy , interpolationInfo... ); + 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 , interpolationInfo... ); + else actualIters = _solveSystemCG( UIntPack< FEMSigs ... >() , F , bsData , d , _solution , ( ConstPointer( T ) )_prolongedSolution , d==_maxDepth ? _constraints : _residualConstraints , Dot , iters , coarseToFine , sStats , solverInfo.showResidual , solverInfo.cgAccuracy , interpolationInfo... ); + } + t = Time(); + UpdateRestriction( d , interpolationInfo... ); + sStats.constraintUpdateTime += Time()-t; + OutputSolverStats( v , d , sStats , showResidual , actualIters ); + } + } + }; + auto SolveProlongation = [&]( int v , int depth , InterpolationInfo< T , PointDs >* ... interpolationInfo ) + { + sorWeights.sorFunction = solverInfo.sorProlongationFunction; + showResidual = true; + bool coarseToFine = true; + for( LocalDepth d=baseDepth ; d<=depth ; d++ ) + { + sStats.constraintUpdateTime = 0; + int iters = solverInfo.iters( v , false , d ); + t = Time(); + F.init( d ); + SetResidualConstraints( d , interpolationInfo... ); + sStats.constraintUpdateTime += Time()-t; + if( d==baseDepth ) _solveRegularMG( UIntPack< FEMSigs ... >() , F , bsData , d , _solution , d==_maxDepth ? _constraints : _residualConstraints , Dot , solverInfo.baseVCycles , iters , sStats , solverInfo.showResidual , solverInfo.cgAccuracy , interpolationInfo... ); + 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 , interpolationInfo... ); + else actualIters = _solveSystemCG( UIntPack< FEMSigs ... >() , F , bsData , d , _solution , ( ConstPointer( T ) )_prolongedSolution , d==_maxDepth ? _constraints : _residualConstraints , Dot , iters , coarseToFine , sStats , solverInfo.showResidual , solverInfo.cgAccuracy , interpolationInfo... ); + } + t = Time(); + UpdateProlongation( d ); + sStats.constraintUpdateTime += Time()-t; + OutputSolverStats( v , d , sStats , showResidual , actualIters ); + } + }; + + for( int v=0 ; vbaseDepth ; d-- ) + { + SolveRestriction ( v , d , interpolationInfo ... ); + SolveProlongation( v , d-1 , interpolationInfo ... ); + } + for( int d=baseDepth+1 ; d<=maxSolveDepth ; d++ ) + { + SolveRestriction ( v , d-1 , interpolationInfo ... ); + SolveProlongation( v , d , interpolationInfo ... ); + } + } + else + { + SolveRestriction ( v , maxSolveDepth , interpolationInfo ... ); + SolveProlongation( v , maxSolveDepth , interpolationInfo ... ); + } + if( solverInfo.showGlobalResidual==SHOW_GLOBAL_RESIDUAL_ALL || ( solverInfo.showGlobalResidual==SHOW_GLOBAL_RESIDUAL_LAST && v==solverInfo.vCycles-1 ) ) + { + bool coarseToFine = false; + std::vector< double > rNorms( maxSolveDepth+1 ); + for( LocalDepth d=maxSolveDepth ; d>=baseDepth ; d-- ) + { + F.init( d ); + SetResidualConstraints( d , interpolationInfo... ); + _solveSystemGS( UIntPack< FEMSigs ... >() , Dim!=1 , F , bsData , d , _solution , ( ConstPointer( T ) )_prolongedSolution , d==_maxDepth ? _constraints : _residualConstraints , Dot , 0 , coarseToFine , solverInfo.sliceBlockSize , TrivialSORWeights() , sStats , true , interpolationInfo... ); + UpdateRestriction( d , interpolationInfo... ); + rNorms[d] = sqrt( sStats.outRNorm2 / _bNorm2[d] ); + } + printf( "%3d" , v+1 ); + for( int d=baseDepth ; d<=maxSolveDepth ; d++ ) printf( "\t%.4e" , rNorms[d] ); + printf( "\n" ); + } + } + MemoryUsage(); + + FreePointer( _residualConstraints ); + FreePointer( _restrictedConstraints ); + FreePointer( _prolongedSolution ); + FreePointer( _bNorm2 ); +} + +template< unsigned int Dim , class Real > +template< unsigned int ... FEMSigs > +DenseNodeData< Real , UIntPack< FEMSigs ... > > FEMTree< Dim , Real >::initDenseNodeData( UIntPack< FEMSigs ... > ) const +{ + DenseNodeData< Real , UIntPack< FEMSigs ... > > constraints( _sNodes.size() ); + memset( constraints() , 0 , sizeof(Real)*_sNodes.size() ); + return constraints; +} +template< unsigned int Dim , class Real > +template< class Data , unsigned int ... FEMSigs > +DenseNodeData< Data , UIntPack< FEMSigs ... > > FEMTree< Dim , Real >::initDenseNodeData( UIntPack< FEMSigs ... > ) const +{ + DenseNodeData< Data , UIntPack< FEMSigs ... > > constraints( _sNodes.size() ); + memset( constraints() , 0 , sizeof(Data)*_sNodes.size() ); + return constraints; +} + +template< unsigned int Dim , class Real > template< class SReal , class Data , unsigned int _Dim > Data FEMTree< Dim , Real >::_StencilDot( Point< SReal , _Dim > p1 , Point< Data , _Dim > p2 ){ Data dot={} ; for( int d=0 ; d<_Dim ; d++ ) dot += p2[d] * (Real)p1[d] ; return dot; } +template< unsigned int Dim , class Real > template< class SReal , class Data > Data FEMTree< Dim , Real >::_StencilDot( Point< SReal , 1 > p1 , Point< Data , 1 > p2 ){ return p2[0] * (Real)p1[0]; } +template< unsigned int Dim , class Real > template< class SReal , class Data > Data FEMTree< Dim , Real >::_StencilDot( SReal p1 , Point< Data , 1 > p2 ){ return p2[0] * (Real)p1; } +template< unsigned int Dim , class Real > template< class SReal , class Data > Data FEMTree< Dim , Real >::_StencilDot( Point< SReal , 1 > p1 , Data p2 ){ return p2 * (Real)p1[0]; } +template< unsigned int Dim , class Real > template< class SReal , class Data > Data FEMTree< Dim , Real >::_StencilDot( SReal p1 , Data p2 ){ return p2*(Real)p1; } +template< unsigned int Dim , class Real > template< class Real1 , unsigned int _Dim > bool FEMTree< Dim , Real >::_IsZero( Point< Real1 , _Dim > p ){ for( int d=0 ; d<_Dim ; d++ ) if( !_IsZero( p[d] ) ) return false ; return true; } +template< unsigned int Dim , class Real > template< class Real1 > bool FEMTree< Dim , Real >::_IsZero( Real1 p ){ return p==0; } + +template< unsigned int Dim , class Real > +template< typename T , unsigned int ... FEMSigs , unsigned int ... CSigs , unsigned int ... FEMDegrees , unsigned int ... CDegrees , unsigned int CDim , class Coefficients > +void FEMTree< Dim , Real >::_addFEMConstraints( UIntPack< FEMSigs ... > , UIntPack< CSigs ... > , typename BaseFEMIntegrator::template Constraint< UIntPack< FEMDegrees ... > , UIntPack< CDegrees ... > , CDim >& F , const Coefficients& coefficients , Pointer( T ) constraints , LocalDepth maxDepth ) const +{ + _setFEM1ValidityFlags( UIntPack< FEMSigs ... >() ); + _setFEM2ValidityFlags( UIntPack< CSigs ... >() ); + typedef typename BaseFEMIntegrator::template Constraint< UIntPack< FEMDegrees ... > , UIntPack< CDegrees ... > , CDim > BaseConstraint; + typedef typename Coefficients::data_type D; + typedef UIntPack< ( BSplineOverlapSizes< CDegrees , FEMDegrees >::OverlapSize ) ... > OverlapSizes; + typedef UIntPack< ( -BSplineOverlapSizes< CDegrees , FEMDegrees >::OverlapStart ) ... > LeftCFEMOverlapRadii; + typedef UIntPack< ( BSplineOverlapSizes< CDegrees , FEMDegrees >::OverlapEnd ) ... > RightCFEMOverlapRadii; + typedef UIntPack< ( -BSplineOverlapSizes< FEMDegrees , CDegrees >::OverlapStart ) ... > LeftFEMCOverlapRadii; + typedef UIntPack< ( BSplineOverlapSizes< FEMDegrees , CDegrees >::OverlapEnd ) ... > RightFEMCOverlapRadii; + + // To set the constraints, we iterate over the splatted normals and compute the dot-product of the divergence of the normal field with all the basis functions. + // Within the same depth: set directly as a gather + // Coarser depths + maxDepth = std::min< LocalDepth >( maxDepth , _maxDepth ); + 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 ); } ); + + bool hasCoarserCoefficients = false; + // Iterate from fine to coarse, setting the constraints @(depth) and the cumulative constraints @(depth-1) + for( LocalDepth d=maxDepth ; d>=0 ; d-- ) + { + typename BaseConstraint::CCStencil stencil; + typename BaseConstraint::PCStencils stencils; + F.init( d ); + F.template setStencil < false >( stencil ); + F.template setStencils< true >( stencils ); + std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i::OverlapSize ... }; + memset( start , 0 , sizeof( start ) ); + typename FEMTreeNode::template ConstNeighbors< OverlapSizes > neighbors; + neighborKey.getNeighbors( LeftFEMCOverlapRadii() , RightFEMCOverlapRadii() , node , neighbors ); + bool isInterior , isInterior2; + { + LocalDepth d ; LocalOffset off ; _localDepthAndOffset( node , d , off ); + isInterior = BaseFEMIntegrator::IsInteriorlyOverlapped( UIntPack< FEMDegrees ... >() , UIntPack< CDegrees ... >() , d , off ); + } + { + LocalDepth d ; LocalOffset off ; _localDepthAndOffset( node->parent , d , off ); + isInterior2 = BaseFEMIntegrator::IsInteriorlyOverlapped( UIntPack< CDegrees ... >() , UIntPack< FEMDegrees ... >() , d , off ); + } + + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + + // Set constraints from current depth + // Gather the constraints from _node into the constraint stored with node + if( _isValidFEM1Node( node ) ) + { + if( isInterior ) + { + 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() , UIntPack< FEMDegrees ... >() , d , off , start , end ); + } + if( !_isValidFEM2Node( node ) ) return; + const D* _data = coefficients( node ); + if( !_data ) return; + else if( d0 ) + { + int cIdx = (int)( node - node->parent->children ); + const typename BaseConstraint::CCStencil& _stencil = stencils.data[cIdx]; + neighborKey.getNeighbors( LeftCFEMOverlapRadii() , RightCFEMOverlapRadii() , node->parent , neighbors ); + + unsigned int size = cfemLoopData.size[cIdx]; + const unsigned int* indices = cfemLoopData.indices[cIdx]; + ConstPointer( Point< double , CDim > ) stencilValues = _stencil.data; + Pointer( const FEMTreeNode* ) nodes = neighbors.neighbors().data; + if( isInterior2 ) + { + for( unsigned int i=0 ; inodeData.nodeIndex ] , _StencilDot( stencilValues[idx] , data ) ); + } + } + } + else + { + for( unsigned int i=0 ; inodeData.nodeIndex ] , _StencilDot( F.pcIntegrate( _off , off ) , data ) ); + } + } + } + } + } + ); + if( d>0 && d() , F.tRestrictionProlongation() , d , _constraints ); + MemoryUsage(); + } + FreePointer( _constraints ); + if( hasCoarserCoefficients ) + { + Pointer( D ) _coefficients = AllocPointer< D >( _sNodesEnd( maxDepth-1 ) ); + 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 ) + { + const D* d = coefficients( _sNodes.treeNodes[i] ); + if( d ) _coefficients[i] += *d; + } + ); + } + + // Coarse-to-fine up-sampling of coefficients + for( LocalDepth d=1 ; d() , F.tRestrictionProlongation() , d , _coefficients ); + // Compute the contribution from all coarser depths + for( LocalDepth d=1 ; d<=maxDepth ; d++ ) + { + node_index_type start = _sNodesBegin( d ) , end = _sNodesEnd( d ); + size_t range = end - start; + typename BaseConstraint::CPStencils stencils; + F.init( d ); + F.template setStencils< false >( stencils ); + std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i neighbors; + typename FEMTreeNode::template ConstNeighbors< OverlapSizes > pNeighbors; + bool isInterior; + { + BaseFEMIntegrator::ParentOverlapBounds( UIntPack< FEMDegrees ... >() , UIntPack< CDegrees ... >() , (int)( node - node->parent->children ) , start , end ); + } + { + LocalDepth d ; LocalOffset off ; _localDepthAndOffset( node->parent , d , off ); + neighborKey.getNeighbors( LeftFEMCOverlapRadii() , RightFEMCOverlapRadii() , node->parent , pNeighbors ); + isInterior = BaseFEMIntegrator::IsInteriorlyOverlapped( UIntPack< FEMDegrees ... >() , UIntPack< CDegrees ... >() , d , off ); + } + int cIdx = (int)( node - node->parent->children ); + const typename BaseConstraint::CCStencil& _stencil = stencils.data[cIdx]; + + T constraint = {}; + + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + int corner = (int)( node - node->parent->children ); + unsigned int size = femcLoopData.size[corner]; + const unsigned int* indices = femcLoopData.indices[corner]; + Pointer( const FEMTreeNode* ) nodes = pNeighbors.neighbors().data; + Pointer( Point< double , CDim > ) stencilValues = _stencil.data; + if( isInterior ) + for( unsigned int i=0 ; inodeData.nodeIndex ] ); + } + else + for( unsigned int i=0 ; inodeData.nodeIndex ] ); + } + } + constraints[i] += constraint; + } + } + ); + } + FreePointer( _coefficients ); + } + MemoryUsage(); +} + +template< unsigned int Dim , class Real > +template< typename T , unsigned int ... FEMSigs , unsigned int PointD > +void FEMTree< Dim , Real >::addInterpolationConstraints( DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , LocalDepth maxDepth , const InterpolationInfo< T , PointD >& interpolationInfo ) const +{ + _setFEM1ValidityFlags( UIntPack< FEMSigs ... >() ); + typedef typename FEMIntegrator::template PointEvaluator< UIntPack< FEMSigs ... > , IsotropicUIntPack< Dim , PointD > > PointEvaluator; + PointEvaluator evaluator( std::min< LocalDepth >( maxDepth , _maxDepth ) ); + + typedef typename FEMTreeNode::template ConstNeighborKey< UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportEnd ... > , UIntPack< ( -BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportStart ) ... > > PointSupportKey; + maxDepth = std::min< LocalDepth >( maxDepth , _maxDepth ); + { + typedef UIntPack< (-BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportStart ) ... > LeftSupportRadii; + typedef UIntPack< ( BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportEnd ) ... > LeftPointSupportRadii; + typedef UIntPack< (-BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportStart ) ... > RightPointSupportRadii; + typedef UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::SupportSize ... > SupportSizes; + + for( int d=0 ; d<=maxDepth ; d++ ) + { + std::vector< PointSupportKey > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i , IsotropicUIntPack< Dim , PointD > > _PointEvaluatorState; + auto WrapperLambda = []( const _PointEvaluatorState &eState , LocalOffset off ) + { + return eState.template dValues< Real , CumulativeDerivatives< Dim , PointD > >( off ); + }; + ThreadPool::Parallel_for( _sNodesBegin(d) , _sNodesEnd(d) , [&]( unsigned int thread , size_t i ) + { + if( _isValidSpaceNode( _sNodes.treeNodes[i] ) ) + { + if( _isValidSpaceNode( _sNodes.treeNodes[i] ) ) + { + _PointEvaluatorState eState; + FEMTreeNode* node = _sNodes.treeNodes[i]; + + PointSupportKey& neighborKey = neighborKeys[ thread ]; + typename FEMTreeNode::template ConstNeighbors< SupportSizes > neighbors; + neighborKey.getNeighbors( LeftPointSupportRadii() , RightPointSupportRadii() , node , neighbors ); + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + + size_t begin , end; + interpolationInfo.range( node , begin , end ); + for( size_t pIndex=begin ; pIndex& pData = interpolationInfo[ pIndex ]; + Point< Real , Dim > p = pData.position; + evaluator.initEvaluationState( p , d , off , eState ); + + int s[Dim]; + WindowLoop< Dim >::Run + ( + IsotropicUIntPack< Dim , 0 >() , 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 = WrapperLambda( eState , _off ); + T dot = {}; + for( int s=0 ; s::Size ; s++ ) dot += pData.dualValues[s] * values[s]; + AddAtomic( constraints[ _node->nodeData.nodeIndex ] , dot ); + } + } , + neighbors.neighbors() + ); + } + } + } + } + ); + } + MemoryUsage(); + } +} + +template< unsigned int Dim , class Real > +template< typename T , typename TDotT , unsigned int ... FEMSigs1 , unsigned int ... FEMSigs2 , class Coefficients1 , class Coefficients2 , unsigned int PointD > +double FEMTree< Dim , Real >::_interpolationDot( UIntPack< FEMSigs1 ... > , UIntPack< FEMSigs2 ... > , const Coefficients1& coefficients1 , const Coefficients2& coefficients2 , TDotT Dot , const InterpolationInfo< T , PointD >* iInfo ) const +{ + typedef UIntPack< FEMSignature< FEMSigs1 >::Degree ... > FEMDegrees1; + typedef UIntPack< FEMSignature< FEMSigs2 >::Degree ... > FEMDegrees2; + typedef UIntPack< FEMSigs1 ... > FEMSignatures1; + typedef UIntPack< FEMSigs2 ... > FEMSignatures2; + double dot = 0; + if( iInfo ) + { + MultiThreadedEvaluator< FEMSignatures1 , PointD , T > mt1( this , coefficients1 ); + MultiThreadedEvaluator< FEMSignatures2 , PointD , T > mt2( this , coefficients2 ); + + 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 ) + { + Point< Real , Dim > p = (*iInfo)[i].position; + Real w = (*iInfo)[i].weight; + CumulativeDerivativeValues< T , Dim , PointD > v1 = (*iInfo)( i , mt1.values( p , thread ) ); + CumulativeDerivativeValues< T , Dim , PointD > v2 = mt2.values( p , thread ); + for( int dd=0 ; dd::Size ; dd++ ) dots[thread] += Dot( v1[dd] , v2[dd] ) * w; + } + ); + for( unsigned int t=0 ; t +template< typename T , typename TDotT , unsigned int ... FEMSigs1 , unsigned int ... FEMSigs2 , unsigned int ... Degrees1 , unsigned int ... Degrees2 , class Coefficients1 , class Coefficients2 > +double FEMTree< Dim , Real >::_dot( UIntPack< FEMSigs1 ... > , UIntPack< FEMSigs2 ... > , typename BaseFEMIntegrator::template Constraint< UIntPack< Degrees1 ... > , UIntPack< Degrees2 ... > , 1 >& F , const Coefficients1& coefficients1 , const Coefficients2& coefficients2 , TDotT Dot ) const +{ + _setFEM1ValidityFlags( UIntPack< FEMSigs1 ... >() ); + _setFEM2ValidityFlags( UIntPack< FEMSigs2 ... >() ); + typedef typename BaseFEMIntegrator::template Constraint< UIntPack< Degrees1 ... > , UIntPack< Degrees2 ... > , 1 > BaseConstraint; + double dot = 0; + // Calculate the contribution from @(depth,depth) + { + typedef UIntPack< BSplineOverlapSizes< Degrees1 , Degrees2 >::OverlapSize ... > OverlapSizes; + typedef UIntPack< -BSplineOverlapSizes< Degrees1 , Degrees2 >::OverlapStart ... > LeftOverlapRadii; + typedef UIntPack< BSplineOverlapSizes< Degrees1 , Degrees2 >::OverlapEnd ... > RightOverlapRadii; + + for( LocalDepth d=0 ; d<=_maxDepth ; d++ ) + { + typename BaseConstraint::CCStencil stencil; + F.init( d ); + F.template setStencil< false >( stencil ); + + std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i dots( ThreadPool::NumThreads() , 0 ); + ThreadPool::Parallel_for( _sNodesBegin(d) , _sNodesEnd(d) , [&]( unsigned int thread , size_t i ) + { + double &dot = dots[thread]; + const FEMTreeNode* node = _sNodes.treeNodes[i]; + const T* _data1; + if( _isValidFEM1Node( node ) && ( _data1=coefficients1(node) ) ) + { + ConstOneRingNeighborKey& neighborKey = neighborKeys[ thread ]; + typename FEMTreeNode::template ConstNeighbors< OverlapSizes > neighbors; + neighborKey.getNeighbors( LeftOverlapRadii() , RightOverlapRadii() , node , neighbors ); + bool isInterior = _isInteriorlyOverlapped( UIntPack< Degrees1 ... >() , UIntPack< Degrees2 ... >() , node ); + + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + ConstPointer( FEMTreeNode * const ) nodes = neighbors.neighbors().data; + ConstPointer( Point< double , 1 > ) stencilValues = stencil.data; + if( isInterior ) + { + for( int i=0 ; i::OverlapSize ... > >::Size ; i++ ) + { + const T* _data2; + if( _isValidFEM2Node( nodes[i] ) && ( _data2=coefficients2( nodes[i] ) ) ) dot += Dot( *_data1 , *_data2 ) * stencilValues[i][0]; + } + } + else + { + for( int i=0 ; i::OverlapSize ... > >::Size ; i++ ) + { + const T* _data2; + if( _isValidFEM2Node( nodes[i] ) && ( _data2=coefficients2( nodes[i] ) ) ) + { + LocalDepth _d ; LocalOffset _off ; _localDepthAndOffset( nodes[i] , _d , _off ); + dot += Dot( *_data1 , *_data2 ) * F.ccIntegrate( off , _off )[0]; + } + } + } + } + } + ); + for( unsigned int t=0 ; t::OverlapSize ... > OverlapSizes; + typedef UIntPack< -BSplineOverlapSizes< Degrees2 , Degrees1 >::OverlapStart ... > LeftOverlapRadii; + typedef UIntPack< BSplineOverlapSizes< Degrees2 , Degrees1 >::OverlapEnd ... > RightOverlapRadii; + + DenseNodeData< T , UIntPack< FEMSigs1 ... > > cumulative1( _sNodesEnd( _maxDepth-1 ) ); + if( _maxDepth>0 ) memset( cumulative1() , 0 , sizeof(T) * _sNodesEnd( _maxDepth-1 ) ); + + 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 ) + { + const T* _data1 = coefficients1( _sNodes.treeNodes[i] ); + if( _data1 ) cumulative1[i] += *_data1; + } + ); + + typename BaseConstraint::PCStencils stencils; + F.init( d ); + F.template setStencils< true >( stencils ); + + std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i dots( ThreadPool::NumThreads() , 0 ); + ThreadPool::Parallel_for( _sNodesBegin(d) , _sNodesEnd(d) , [&]( unsigned int thread , size_t i ) + { + double &dot = dots[thread]; + const FEMTreeNode* node = _sNodes.treeNodes[i]; + const T* _data2; + if( _isValidFEM2Node( node ) && ( _data2=coefficients2( node ) ) ) + { + ConstOneRingNeighborKey& neighborKey = neighborKeys[ thread ]; + bool isInterior = _isInteriorlyOverlapped( UIntPack< Degrees1 ... >() , UIntPack< Degrees2 ... >() , node->parent ); + + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + + int cIdx = (int)( node - node->parent->children ); + typename BaseConstraint::CCStencil& _stencil = stencils.data[cIdx]; + typename FEMTreeNode::template ConstNeighbors< OverlapSizes > neighbors; + neighborKey.getNeighbors( LeftOverlapRadii() , RightOverlapRadii() , node->parent , neighbors ); + + int start[Dim] , end[Dim]; + _SetParentOverlapBounds( UIntPack< Degrees1 ... >() , UIntPack< Degrees2 ... >() , node , start , end ); + WindowLoop< Dim >::Run + ( + start , end , + [&]( int , int ){;} , + [&]( const FEMTreeNode* node , Point< double , 1 > stencilValue ) + { + const T* _data1; + if( _isValidFEM1Node( node ) && ( _data1=cumulative1(node) ) ) + { + if( isInterior ) dot += Dot( *_data1 , *_data2 ) * stencilValue[0]; + else + { + LocalDepth _d ; LocalOffset _off ; _localDepthAndOffset( node , _d , _off ); + dot += Dot ( *_data1 , *_data2 ) * F.pcIntegrate( _off , off )[0]; + } + } + } , + neighbors.neighbors() , _stencil() + ); + } + } + ); + for( unsigned int t=0 ; t() , F.tRestrictionProlongation() , d , cumulative1() ); + } + } + + // Calculate the contribution from @(>depth,depth) + { + typedef UIntPack< BSplineOverlapSizes< Degrees1 , Degrees2 >::OverlapSize ... > OverlapSizes; + typedef UIntPack< -BSplineOverlapSizes< Degrees1 , Degrees2 >::OverlapStart ... > LeftOverlapRadii; + typedef UIntPack< BSplineOverlapSizes< Degrees1 , Degrees2 >::OverlapEnd ... > RightOverlapRadii; + + DenseNodeData< T , UIntPack< FEMSigs2 ... > > cumulative2( _sNodesEnd( _maxDepth-1 ) ); + if( _maxDepth>0 ) memset( cumulative2() , 0 , sizeof(T) * _sNodesEnd( _maxDepth-1 ) ); + + for( LocalDepth d=_maxDepth ; d>0 ; d-- ) + { + typename BaseConstraint::CPStencils stencils; + F.init( d ); + F.template setStencils< false >( stencils ); + + std::vector< ConstOneRingNeighborKey > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; i dots( ThreadPool::NumThreads() , 0 ); + ThreadPool::Parallel_for( _sNodesBegin(d) , _sNodesEnd(d) , [&]( unsigned int thread , size_t i ) + { + double &dot = dots[thread]; + const FEMTreeNode* node = _sNodes.treeNodes[i]; + const T* _data1; + if( _isValidFEM1Node( node ) && ( _data1=coefficients1( node ) ) ) + { + ConstOneRingNeighborKey& neighborKey = neighborKeys[ thread ]; + bool isInterior = _isInteriorlyOverlapped( UIntPack< Degrees2 ... >() , UIntPack< Degrees1 ... >() , node->parent ); + + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + + int cIdx = (int)( node - node->parent->children ); + typename BaseConstraint::CCStencil& _stencil = stencils.data[cIdx]; + typename FEMTreeNode::template ConstNeighbors< OverlapSizes > neighbors; + neighborKey.getNeighbors( LeftOverlapRadii() , RightOverlapRadii() , node->parent , neighbors ); + + int start[Dim] , end[Dim]; + _SetParentOverlapBounds( UIntPack< Degrees1 ... >() , UIntPack< Degrees2 ... >() , node , start , end ); + +#ifdef __clang__ +#pragma message ( "[WARNING] You've got me clang" ) + std::function< void (int,int) > updateFunction = [](int,int){}; +#endif // __clang__ + + WindowLoop< Dim >::Run + ( + start , end , +#ifdef __clang__ + updateFunction , +#else // !__clang__ + [&]( int , int ){;} , +#endif // __clang__ + [&]( const FEMTreeNode* node , Point< double , 1 > stencilValue ) + { + if( _isValidFEM2Node( node ) ) + { + T _dot; + if( isInterior ) _dot = (*_data1) * stencilValue[0]; + else + { + LocalDepth _d ; LocalOffset _off ; _localDepthAndOffset( node , _d , _off ); + _dot = (*_data1) * F.cpIntegrate( off , _off )[0]; + } + AddAtomic( cumulative2[ node->nodeData.nodeIndex ] , _dot ); + } + } , + neighbors.neighbors() , _stencil() + ); + } + } + ); + for( unsigned int t=0 ; tnodeData.nodeIndex ] , *_data2 ); + } + ); + for( unsigned int t=0 ; t0 ) _downSample( UIntPack< FEMSigs2 ... >() , F.cRestrictionProlongation() , d-1 , GetPointer( &cumulative2[0] , cumulative2.size() ) ); + } + } + return dot; +} diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/FEMTree.WeightedSamples.inl b/modules/PoissonRecon/include/Mesh/PoissonRecon/FEMTree.WeightedSamples.inl new file mode 100644 index 00000000..b263ddad --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/FEMTree.WeightedSamples.inl @@ -0,0 +1,315 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +template< class Real , unsigned int DataDegree , unsigned int ... DataDegrees > typename std::enable_if< sizeof ... ( DataDegrees )==0 >::type __SetBSplineComponentValues( const Real* position , const Real* start , Real width , double* values , unsigned int stride ) +{ + Polynomial< DataDegree >::BSplineComponentValues( ( position[0] - start[0] ) / width , values ); +} +template< class Real , unsigned int DataDegree , unsigned int ... DataDegrees > typename std::enable_if< sizeof ... ( DataDegrees )!=0 >::type __SetBSplineComponentValues( const Real* position , const Real* start , Real width , double* values , unsigned int stride ) +{ + Polynomial< DataDegree >::BSplineComponentValues( ( position[0] - start[0] ) / width , values ); + __SetBSplineComponentValues< Real , DataDegrees ... >( position+1 , start+1 , width , values + stride , stride ); +} + + +// evaluate the result of splatting along a plane and then evaluating at a point on the plane. +template< unsigned int Degree > double GetScaleValue( void ) +{ + double centerValues[Degree+1]; + Polynomial< Degree >::BSplineComponentValues( 0.5 , centerValues ); + double scaleValue = 0; + for( int i=0 ; i<=Degree ; i++ ) scaleValue += centerValues[i] * centerValues[i]; + return 1./ scaleValue; +} +template< unsigned int Dim , class Real > +template< bool ThreadSafe , unsigned int WeightDegree > +void FEMTree< Dim , Real >::_addWeightContribution( Allocator< FEMTreeNode > *nodeAllocator , DensityEstimator< WeightDegree >& densityWeights , FEMTreeNode* node , Point< Real , Dim > position , PointSupportKey< IsotropicUIntPack< Dim , WeightDegree > >& weightKey , Real weight ) +{ + static const double ScaleValue = GetScaleValue< WeightDegree >(); + double values[ Dim ][ BSplineSupportSizes< WeightDegree >::SupportSize ]; + typename FEMTreeNode::template Neighbors< IsotropicUIntPack< Dim , BSplineSupportSizes< WeightDegree >::SupportSize > >& neighbors = weightKey.template getNeighbors< true , ThreadSafe >( node , nodeAllocator , _nodeInitializer ); + + densityWeights.reserve( nodeCount() ); + + Point< Real , Dim > start; + Real w; + _startAndWidth( node , start , w ); + + for( int dim=0 ; dim::BSplineComponentValues( ( position[dim]-start[dim] ) / w , values[dim] ); + + weight *= (Real)ScaleValue; + double scratch[Dim+1]; + scratch[0] = weight; + WindowLoop< Dim >::Run + ( + IsotropicUIntPack< Dim , 0 >() , IsotropicUIntPack< Dim , BSplineSupportSizes< WeightDegree >::SupportSize >() , + [&]( int d , int i ){ scratch[d+1] = scratch[d] * values[d][i]; } , + [&]( FEMTreeNode* node ) + { + if( node ) + { + AddAtomic( densityWeights[ node ] , (Real)scratch[Dim] ); + } + } , + neighbors.neighbors() + ); +} + +template< unsigned int Dim , class Real > +template< unsigned int WeightDegree , class PointSupportKey > +Real FEMTree< Dim , Real >::_getSamplesPerNode( const DensityEstimator< WeightDegree >& densityWeights , const FEMTreeNode* node , Point< Real , Dim > position , PointSupportKey& weightKey ) const +{ + Real weight = 0; + typedef typename PointSupportKey::NeighborType Neighbors; + double values[ Dim ][ BSplineSupportSizes< WeightDegree >::SupportSize ]; + Neighbors neighbors = weightKey.getNeighbors( node ); + Point< Real , Dim > start; + Real w; + _startAndWidth( node , start , w ); + + for( int dim=0 ; dim::BSplineComponentValues( ( position[dim]-start[dim] ) / w , values[dim] ); + double scratch[Dim+1]; + scratch[0] = 1; + WindowLoop< Dim >::Run + ( + 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) ); } } , + neighbors.neighbors() + ); + return weight; +} +template< unsigned int Dim , class Real > +template< unsigned int WeightDegree , class PointSupportKey > +void FEMTree< Dim , Real >::_getSampleDepthAndWeight( const DensityEstimator< WeightDegree >& densityWeights , const FEMTreeNode* node , Point< Real , Dim > position , PointSupportKey& weightKey , Real& depth , Real& weight ) const +{ + const FEMTreeNode* temp = node; + while( _localDepth( temp )>densityWeights.kernelDepth() ) temp = temp->parent; + weight = _getSamplesPerNode( densityWeights , temp , position , weightKey ); + if( weight>=(Real)1. ) depth = Real( _localDepth( temp ) + log( weight ) / log(double(1<<( Dim-densityWeights.coDimension() ))) ); + else + { + Real oldWeight , newWeight; + oldWeight = newWeight = weight; + while( newWeight<(Real)1. && _localDepth(temp) ) + { + temp=temp->parent; + oldWeight = newWeight; + newWeight = _getSamplesPerNode( densityWeights , temp , position , weightKey ); + } + depth = Real( _localDepth( temp ) + log( newWeight ) / log( newWeight / oldWeight ) ); + } + weight = Real( pow( double(1<<( Dim-densityWeights.coDimension() )) , -double(depth) ) ); +} +template< unsigned int Dim , class Real > +template< unsigned int WeightDegree , class PointSupportKey > +void FEMTree< Dim , Real >::_getSampleDepthAndWeight( const DensityEstimator< WeightDegree >& densityWeights , Point< Real , Dim > position , PointSupportKey& weightKey , Real& depth , Real& weight ) const +{ + FEMTreeNode* temp; + Point< Real, Dim > myCenter; + for( int d=0 ; d( temp->children ) ) break; // ERROR_OUT( "" ); + 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; + } + return _getSampleDepthAndWeight( densityWeights , temp , position , weightKey , depth , weight ); +} + +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 ) +{ + typedef UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportSize ... > SupportSizes; + double values[ Dim ][ SupportSizes::Max() ]; + typename FEMTreeNode::template Neighbors< UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportSize ... > >& neighbors = dataKey.template getNeighbors< CreateNodes , ThreadSafe >( node , nodeAllocator , _nodeInitializer ); + Point< Real , Dim > start; + Real w; + _startAndWidth( node , start , w ); + __SetBSplineComponentValues< Real , FEMSignature< DataSigs >::Degree ... >( &position[0] , &start[0] , w , &values[0][0] , SupportSizes::Max() ); + double scratch[Dim+1]; + scratch[0] = 1; + WindowLoop< Dim >::Run + ( + 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] ); + } + } , + 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 , 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 ) +{ + double dx; + V _v; + FEMTreeNode* temp; + double width; + Point< Real , Dim > myCenter; + 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; + } + Real weight , depth; + _getSampleDepthAndWeight( densityWeights , temp , position , weightKey , depth , weight ); + depth += depthBias; + + if( depthmaxDepth ) depth = Real(maxDepth); + int topDepth = int(ceil(depth)); + + dx = 1.0-(topDepth-depth); + if ( topDepth<=minDepth ) topDepth = minDepth , dx = 1; + else if( topDepth> maxDepth ) topDepth = maxDepth , dx = 1; + + while( _localDepth( temp )>topDepth ) temp=temp->parent; + while( _localDepth( temp )children ) temp->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; + } + + width = 1.0 / ( 1<<_localDepth( temp ) ); + _v = v * weight / Real( pow( width , dim ) ) * Real( dx ); +#if defined( __GNUC__ ) && __GNUC__ < 5 +#warning "you've got me gcc version<5" + _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 + if( fabs(1.0-dx) > 1e-6 ) + { + dx = Real(1.0-dx); + temp = temp->parent; + width = 1.0 / ( 1<<_localDepth( temp ) ); + + _v = v * weight / Real( pow( width , dim ) ) * Real( dx ); +#if defined( __GNUC__ ) && __GNUC__ < 5 +#warning "you've got me gcc version<5" + _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 + } + return weight; +} +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 ) +{ + typedef UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportSize ... > SupportSizes; + Real _depth , weight; + if( densityWeights ) _getSampleDepthAndWeight( *densityWeights , position , weightKey , _depth , weight ); + else weight = (Real)1.; + V _v = v * weight; + + double values[ Dim ][ SupportSizes::Max() ]; + dataKey.template getNeighbors< CreateNodes , ThreadSafe >( node , nodeAllocator , _nodeInitializer ); + + for( FEMTreeNode* _node=node ; _localDepth( _node )>=0 ; _node=_node->parent ) + { + V __v = _v * (Real)pow( 1<<_localDepth( _node ) , dim ); + Point< Real , Dim > start; + Real w; + _startAndWidth( _node , start , w ); + __SetBSplineComponentValues< Real , FEMSignature< DataSigs >::Degree ... >( &position[0] , &start[0] , w , &values[0][0] , SupportSizes::Max() ); + typename FEMTreeNode::template Neighbors< UIntPack< BSplineSupportSizes< FEMSignature< DataSigs >::Degree >::SupportSize ... > >& neighbors = dataKey.neighbors[ _localToGlobal( _localDepth( _node ) ) ]; + double scratch[Dim+1]; + scratch[0] = 1.; + WindowLoop< Dim >::Run + ( + 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]; } , + neighbors.neighbors() + ); + } + return weight; +} + +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 _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 ); + return weight; +} +////////////////////////////////// +// MultiThreadedWeightEvaluator // +////////////////////////////////// +template< unsigned int Dim , class Real > +template< unsigned int DensityDegree > +FEMTree< Dim , Real >::MultiThreadedWeightEvaluator< DensityDegree >::MultiThreadedWeightEvaluator( const FEMTree< Dim , Real >* tree , const DensityEstimator< DensityDegree >& density , int threads ) : _density( density ) , _tree( tree ) +{ + _threads = std::max< int >( 1 , threads ); + _neighborKeys.resize( _threads ); + for( int t=0 ; t<_neighborKeys.size() ; t++ ) _neighborKeys[t].set( tree->_localToGlobal( density.kernelDepth() ) ); +} +template< unsigned int Dim , class Real > +template< unsigned int DensityDegree > +Real FEMTree< Dim , Real >::MultiThreadedWeightEvaluator< DensityDegree >::weight( Point< Real , Dim > p , int thread ) +{ + ConstPointSupportKey< IsotropicUIntPack< Dim , DensityDegree > >& nKey = _neighborKeys[thread]; + Real depth , weight; + _tree->_getSampleDepthAndWeight( _density , p , nKey , depth , weight ); + return weight; +} diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/FEMTree.h b/modules/PoissonRecon/include/Mesh/PoissonRecon/FEMTree.h new file mode 100644 index 00000000..1a98d8c1 --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/FEMTree.h @@ -0,0 +1,2530 @@ +/* +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. +*/ + +// -- [TODO] Make as many of the functions (related to the solver) const as possible. +// -- [TODO] Move the point interpolation constraint scaling by 1< +#include "Mesh/PoissonRecon/MyMiscellany.h" +#include "Mesh/PoissonRecon/BSplineData.h" +#include "Mesh/PoissonRecon/Geometry.h" +#include "Mesh/PoissonRecon/PointStream.h" +#include "Mesh/PoissonRecon/RegularTree.h" +#include "Mesh/PoissonRecon/SparseMatrix.h" +#include "Mesh/PoissonRecon/BlockedVector.h" +#include +#include +#include + +#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; +#else // !BIG_DATA +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; +#else // !USE_DEEP_TREE_NODES +typedef unsigned short depth_and_offset_type; +#endif // USE_DEEP_TREE_NODES + +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 , + FEM_FLAG_1 = 2 , + FEM_FLAG_2 = 4 , + REFINABLE_FLAG = 8 , + GHOST_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; } + 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; +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 ); + size_t set( TreeNode& root ); +}; + +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; } +}; + +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 ... > > +{ + 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; +}; + + +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 ); + + 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 ); } + 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(); + } + 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 ]; + } + +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( const node_index_type *newNodeIndices , 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]; + _indices = newIndices; + } + BlockedVector< node_index_type > _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( void ){ DeletePointer( _data ) ; _sz = 0; } + static void WriteSignatures( FILE* fp ) + { + unsigned int dim = sizeof ... ( FEMSigs ); + fwrite( &dim , sizeof(unsigned int) , 1 , fp ); + unsigned int femSigs[] = { FEMSigs ... }; + fwrite( femSigs , sizeof(unsigned int) , dim , fp ); + } + void write( FILE* fp ) const { fwrite( &_sz , sizeof(size_t) , 1 , fp ) ; fwrite( _data , sizeof(Data) , _sz , fp ); } + void read( FILE* fp ) + { + if( fread( &_sz , sizeof(size_t) , 1 , fp )!=1 ) ERROR_OUT( "Failed to read size" ); + _data = NewPointer< Data >( _sz ); + if( fread ( _data , sizeof(Data) , _sz , fp )!=_sz ) ERROR_OUT( "failed to read 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 old number of entries and map[i] should give the new index of the old i-th node + void _remapIndices( const node_index_type *newNodeIndices , 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]( sz ) ; else _data = NullPointer( Data ) ; _sz = sz; } + Pointer( Data ) _data; +}; +enum FEMTreeRealType +{ + FEM_TREE_REAL_FLOAT , + FEM_TREE_REAL_DOUBLE , + FEM_TREE_REAL_COUNT +}; +const char* FEMTreeRealNames[] = { "float" , "double" }; + +void ReadFEMTreeParameter( FILE* fp , 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" ); +} + +unsigned int* ReadDenseNodeDataSignatures( FILE* fp , unsigned int &dim ) +{ + if( fread( &dim , sizeof(unsigned int) , 1 , fp )!=1 ) 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" ); + return femSigs; +} + +// 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< typename T > struct TensorDerivatives{ }; +template< class Real , typename T > struct TensorDerivativeValues{ }; + +// 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; +}; +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 _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 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 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 > > { }; + + 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 > >{ }; + + 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; + }; + + 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; + + 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 > >{ }; + + 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; + }; + + 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; + }; +}; + +///////////////////////////////////////////////// +// 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); + + 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 ... TSignatures , unsigned int ... TDs > + 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 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 + { + 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 ); + } + }; + + 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 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< Dim >( node ); } + +template< unsigned int Dim , class Real , class Vertex > struct IsoSurfaceExtractor; + +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< Simplex< Real , Dim , Dim-1 > > >; + + +template< typename T > struct WindowLoopData{ }; + +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 ); } + ); + } + } +}; + +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; + std::vector< Allocator< FEMTreeNode > * > nodeAllocators; +protected: + template< unsigned int _Dim , class _Real , class Vertex > friend struct IsoSurfaceExtractor; + 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 ); +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 ) ); } + }; + 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 ) ); } + }; + + template< typename T , unsigned int PointD , typename ConstraintDual , typename SystemDual > + struct ApproximatePointInterpolationInfo : 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 ]; } + 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 ) { } + protected: + SparseNodeData< DualPointInfo< Dim , Real , T , PointD > , ZeroUIntPack< Dim > > _iData; + bool _constrainsDCTerm; + ConstraintDual _constraintDual; + SystemDual _systemDual; + + 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; + 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 ); } + + ApproximatePointInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _constraintDual( constraintDual ) , _systemDual( systemDual ) , _constrainsDCTerm( constrainsDCTerm ) { } + protected: + SparseNodeData< DualPointInfo< Dim , Real , T , PointD > , ZeroUIntPack< Dim > > _iData; + bool _constrainsDCTerm; + ConstraintDual _constraintDual; + SystemDual _systemDual; + + 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 ); + 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 ); } + + ApproximatePointAndDataInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _constraintDual( constraintDual ) , _systemDual( systemDual ) , _constrainsDCTerm( constrainsDCTerm ) { } + protected: + SparseNodeData< DualPointAndDataInfo< Dim , Real , Data , T , PointD > , ZeroUIntPack< Dim > > _iData; + bool _constrainsDCTerm; + ConstraintDual _constraintDual; + SystemDual _systemDual; + + 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 ); + 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 ); } + + ApproximatePointAndDataInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _constraintDual( constraintDual ) , _systemDual( systemDual ) , _constrainsDCTerm( constrainsDCTerm ) { } + protected: + SparseNodeData< DualPointAndDataInfo< Dim , Real , Data , T , PointD > , ZeroUIntPack< Dim > > _iData; + bool _constrainsDCTerm; + ConstraintDual _constraintDual; + SystemDual _systemDual; + + friend class FEMTree< Dim , Real >; + }; + + template< typename T , unsigned int PointD , typename ConstraintDual , typename SystemDual > + struct ApproximateChildPointInterpolationInfo : 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<& 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 ); } + + ApproximateChildPointInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _constraintDual( constraintDual ) , _systemDual( systemDual ) , _constrainsDCTerm( constrainsDCTerm ) { } + protected: + static const unsigned int _Mask = (1< , ZeroUIntPack< Dim > > _iData; + DualPointInfo< Dim , Real , T , PointD >& __iData( size_t pointIdx ){ return _iData[ pointIdx>>Dim ][ pointIdx & _Mask ]; } + const DualPointInfo< Dim , Real , T , PointD >& __iData( size_t pointIdx ) const { return _iData[ pointIdx>>Dim ][ pointIdx & _Mask ]; } + bool _constrainsDCTerm; + ConstraintDual _constraintDual; + SystemDual _systemDual; + + friend class FEMTree< Dim , Real >; + }; + template< unsigned int PointD , typename ConstraintDual , typename SystemDual > + struct ApproximateChildPointInterpolationInfo< double , 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 ); + if( idx<0 ) begin = end = 0; + else begin = (idx<& 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 ); } + + ApproximateChildPointInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _constraintDual( constraintDual ) , _systemDual( systemDual ) , _constrainsDCTerm( constrainsDCTerm ) { } + protected: + static const unsigned int _Mask = (1< , ZeroUIntPack< Dim > > _iData; + DualPointInfo< Dim , Real , T , PointD >& __iData( size_t pointIdx ){ return _iData[ pointIdx>>Dim ][ pointIdx & _Mask ]; } + const DualPointInfo< Dim , Real , T , PointD >& __iData( size_t pointIdx ) const { return _iData[ pointIdx>>Dim ][ pointIdx & _Mask ]; } + bool _constrainsDCTerm; + ConstraintDual _constraintDual; + SystemDual _systemDual; + + friend class FEMTree< Dim , Real >; + }; + template< typename T , typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > + struct ApproximateChildPointAndDataInterpolationInfo : 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<& 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(pointIdx).data , dValues ); } + + ApproximateChildPointAndDataInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _constraintDual( constraintDual ) , _systemDual( systemDual ) , _constrainsDCTerm( constrainsDCTerm ) { } + protected: + static const unsigned int _Mask = (1< , ZeroUIntPack< Dim > > _iData; + DualPointAndDataInfo< Dim , Real , Data , T , PointD >& __iData( size_t pointIdx ){ return _iData[ pointIdx>>Dim ][ pointIdx & _Mask ]; } + const DualPointAndDataInfo< Dim , Real , Data , T , PointD >& __iData( size_t pointIdx ) const { return _iData[ pointIdx>>Dim ][ pointIdx & _Mask ]; } + bool _constrainsDCTerm; + ConstraintDual _constraintDual; + SystemDual _systemDual; + + friend class FEMTree< Dim , Real >; + }; + template< typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > + struct ApproximateChildPointAndDataInterpolationInfo< 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 ); + if( idx==-1 ) begin = end = 0; + else begin = (idx<& 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 ); } + + ApproximateChildPointAndDataInterpolationInfo( ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm ) : _constraintDual( constraintDual ) , _systemDual( systemDual ) , _constrainsDCTerm( constrainsDCTerm ) { } + protected: + static const unsigned int _Mask = (1< , ZeroUIntPack< Dim > > _iData; + DualPointAndDataInfo< Dim , Real , Data , T , PointD >& __iData( size_t pointIdx ){ return _iData[ pointIdx>>Dim ][ pointIdx & _Mask ]; } + const DualPointAndDataInfo< Dim , Real , Data , T , PointD >& __iData( size_t pointIdx ) const { return _iData[ pointIdx>>Dim ][ pointIdx & _Mask ]; } + bool _constrainsDCTerm; + ConstraintDual _constraintDual; + SystemDual _systemDual; + + friend class FEMTree< Dim , Real >; + }; + 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 ); } + 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 ); } + + 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; + + friend class FEMTree< Dim , Real >; + }; + 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; + + 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; + + 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 , 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 ); + 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 ) + { + 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 ); + return a; + } + template< typename T , unsigned int PointD , typename ConstraintDual , typename SystemDual > + static ApproximateChildPointInterpolationInfo< T , PointD , ConstraintDual , SystemDual >* InitializeApproximateChildPointInterpolationInfo( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm , bool noRescale ) + { + ApproximateChildPointInterpolationInfo< T , PointD , ConstraintDual , SystemDual >* a = new ApproximateChildPointInterpolationInfo< T , PointD , ConstraintDual , SystemDual >( constraintDual , systemDual , constrainsDCTerm ); + a->_iData = tree._densifyChildInterpolationInfoAndSetDualConstraints< T , PointD >( samples , constraintDual , noRescale ); + return a; + } + template< typename T , typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > + static ApproximateChildPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >* InitializeApproximateChildPointAndDataInterpolationInfo( const class FEMTree< Dim , Real >& tree , const std::vector< PointSample >& samples , ConstPointer( Data ) sampleData , ConstraintDual constraintDual , SystemDual systemDual , bool constrainsDCTerm , bool noRescale ) + { + ApproximateChildPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >* a = new ApproximateChildPointAndDataInterpolationInfo< T , Data , PointD , ConstraintDual , SystemDual >( constraintDual , systemDual , constrainsDCTerm ); + a->_iData = tree._densifyChildInterpolationInfoAndSetDualConstraints< T , Data , PointD >( samples , sampleData , constraintDual , noRescale ); + 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 T , unsigned int PointD , unsigned int ... PointDs > + static bool ConstrainsDCTerm( const InterpolationInfo< T , PointD >* iInfo , const InterpolationInfo< T , PointDs >* ... iInfos ){ return ConstrainsDCTerm( iInfo ) || ConstrainsDCTerm( iInfos... ); } + template< typename T , unsigned int PointD > + static bool ConstrainsDCTerm( const InterpolationInfo< T , PointD >* iInfo ){ return iInfo && iInfo->constrainsDCTerm(); } + static bool ConstrainsDCTerm( void ){ return false; } + +#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 ) : _kernelDepth( kernelDepth ) , _coDimension( coDimension ){ ; } + int coDimension( void ) const { return _coDimension; } + int kernelDepth( void ) const { return _kernelDepth; } + protected: + 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 _isRefinableNode ( const FEMTreeNode* node ) const { return !GetGhostFlag< Dim >( node ) && ( node->nodeData.flags & FEMTreeNodeData::REFINABLE_FLAG ); } + + FEMTreeNode* _tree; + FEMTreeNode* _spaceRoot; + SortedTreeNodes< Dim > _sNodes; + LocalDepth _maxDepth; + int _depthOffset; + mutable unsigned int _femSigs1[ Dim ]; + mutable unsigned int _femSigs2[ Dim ]; + mutable unsigned int _refinableSigs[ Dim ]; + + static bool _InBounds( Point< Real , Dim > p ); + int _localToGlobal( LocalDepth 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 ); } + 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 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 + { + 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 ) + { + 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 ); + } + void _startAndWidth( const FEMTreeNode* node , Point< Real , Dim >& start , Real& width ) const + { + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + if( d>=0 ) width = Real( 1.0 / (1<< d ) ); + else width = Real( 1.0 * (1<<(-d)) ); + for( int dd=0 ; dd& center , Real& width ) const + { + int d , off[Dim]; + _localDepthAndOffset( node , d , off ); + width = Real( 1.0 / (1< p ) const + { + Point< Real , Dim > c ; Real w; + _centerAndWidth( node , c , w ); + int cIdx = 0; + for( int d=0 ; d=c[d] ) cIdx |= (1< 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; + +public: + template< unsigned int ... Degrees > LocalDepth getFullDepth( UIntPack< Degrees ... > ) 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 ); } + +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; + }; + template< unsigned int ... FEMSigs , typename T , unsigned int PointD , unsigned int ... PointDs > + typename std::enable_if< (sizeof...(PointDs)!=0) >::type _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 >* iInfo , const InterpolationInfo< T , PointDs >* ... iInfos ) const + { + _addPointValues( UIntPack< FEMSigs ... >() , pointValues , neighbors , bsData , iInfo ) , _addPointValues( UIntPack< FEMSigs ... >() , pointValues , neighbors , bsData , iInfos... ); + } + template< unsigned int ... FEMSigs > + 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 { } + 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 ... FEMSigs , typename T , unsigned int PointD , unsigned int ... PointDs > + typename std::enable_if< (sizeof...(PointDs)>1) >::type _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 InterpolationInfo< T , PointDs >* ... iInfos ) const + { + _addProlongedPointValues( UIntPack< FEMSigs ... >() , pointValues , neighbors , pNeighbors , bsData , iInfo ) , _addProlongedPointValues( UIntPack< FEMSigs ... >() , pointValues , neighbors , pNeighbors , bsData , iInfos... ); + } + template< unsigned int ... FEMSigs > 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 { } + 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 ... FEMSigs , typename T , unsigned int PointD , unsigned int ... PointDs > + typename std::enable_if< (sizeof...(PointDs)!=0) >::type _setPointValuesFromProlongedSolution( LocalDepth highDepth , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , ConstPointer( T ) prolongedSolution , InterpolationInfo< T , PointD >* iInfo , InterpolationInfo< T , PointDs >* ... iInfos ) const + { + _setPointValuesFromProlongedSolution( highDepth , bsData , prolongedSolution , iInfo ) , _setPointValuesFromProlongedSolution( highDepth , bsData , prolongedSolution , iInfos... ); + } + template< unsigned int ... FEMSigs , typename T > void _setPointValuesFromProlongedSolution( LocalDepth highDepth , const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , ConstPointer( T ) prolongedSolution ) const { } + 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 ... FEMSigs , typename T , unsigned int PointD , unsigned int ... PointDs > + typename std::enable_if< (sizeof...(PointDs)!=0) , T >::type _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 InterpolationInfo< T , PointDs >* ... iInfos ) const + { + return _getInterpolationConstraintFromProlongedSolution( neighbors , node , prolongedSolution , bsData , iInfo ) + _getInterpolationConstraintFromProlongedSolution( neighbors , node , prolongedSolution , bsData , iInfos... ); + } + template< unsigned int ... FEMSigs , typename T > 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 { return T(); } + 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 ... FEMSigs , typename T , unsigned int PointD , unsigned int ... PointDs > + typename std::enable_if< (sizeof...(PointDs)!=0) >::type _updateRestrictedInterpolationConstraints( const PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , LocalDepth highDepth , ConstPointer( T ) solution , Pointer( T ) cumulativeConstraints , const InterpolationInfo< T , PointD >* iInfo , const InterpolationInfo< T , PointDs >* ... iInfos ) const + { + _updateRestrictedInterpolationConstraints( bsData , highDepth , solution , cumulativeConstraints , iInfo ) , _updateRestrictedInterpolationConstraints( bsData , highDepth , solution , cumulativeConstraints , iInfos... ); + } + template< unsigned int ... FEMSigs , typename T > void _updateRestrictedInterpolationConstraints( PointEvaluator< UIntPack< FEMSigs ... > , UIntPack< FEMSignature< FEMSigs >::Degree ... > >& bsData , LocalDepth highDepth , ConstPointer( T ) solution , Pointer( T ) cumulativeConstraints ) const { ; } + 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 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 ) + { + int d , off[Dim] ; node->depthAndOffset( d , off ); + BaseFEMIntegrator::template 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 ); + } + + template< unsigned int ... FEMSigs > + int _getProlongedMatrixRowSize( const FEMTreeNode* node , const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& pNeighbors ) const; +#if defined( __GNUC__ ) && __GNUC__ < 5 + #warning "you've got me gcc version<5" + template< unsigned int ... FEMSigs > + int _getMatrixRowSize( UIntPack< FEMSigs ... > , const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& neighbors ) const; +#else // !__GNUC__ || __GNUC__ >=5 + template< unsigned int ... FEMSigs > + int _getMatrixRowSize( const typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >& neighbors ) const; +#endif // __GNUC__ || __GNUC__ < 4 + template< typename T , unsigned int ... PointDs , unsigned int ... FEMSigs > + 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 , SparseMatrix< Real , matrix_index_type , WindowSize< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >::Size > &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 , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) const; + template< typename T , unsigned int ... PointDs , unsigned int ... FEMSigs > + 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 , Pointer( MatrixEntry< Real , matrix_index_type > ) row , 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 , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) const; + template< typename T , unsigned int ... PointDs , unsigned int ... FEMSigs > + 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 , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) const; + + // Updates the constraints @(depth) based on the solution coefficients @(depth-1) + template< unsigned int ... FEMSigs , typename T , unsigned int ... PointDs > + 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 , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) const; + + template< unsigned int ... FEMSigs , typename T , typename TDotT , typename SORWeights , unsigned int ... PointDs > + 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 , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) const; + template< unsigned int ... FEMSigs , typename T , typename TDotT , typename SORWeights , unsigned int ... PointDs > + 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 , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) const; + template< unsigned int ... FEMSigs , typename T , typename TDotT , typename SORWeights , unsigned int ... PointDs > + 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 , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) const + { + if( sliced ) return _solveSlicedSystemGS( UIntPack< FEMSigs ... >() , F , bsData , depth , solution , prolongedSolution , constraints , Dot , iters , coarseToFine , sliceBlockSize , sorWeights , stats , computeNorms , interpolationInfo ... ); + else return _solveFullSystemGS ( UIntPack< FEMSigs ... >() , F , bsData , depth , solution , prolongedSolution , constraints , Dot , iters , coarseToFine , sorWeights , stats , computeNorms , interpolationInfo ... ); + } + template< unsigned int ... FEMSigs , typename T , typename TDotT , unsigned int ... PointDs > + 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 , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) const; + template< unsigned int ... FEMSigs , typename T , typename TDotT , unsigned int ... PointDs > + 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 , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) 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 , unsigned int ... PointDs > + int _getSliceMatrixAndProlongationConstraints( UIntPack< FEMSigs ... > , const BaseSystem< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , SparseMatrix< Real , matrix_index_type , WindowSize< UIntPack< BSplineOverlapSizes< FEMSignature< FEMSigs >::Degree >::OverlapSize ... > >::Size >& 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 , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) const; + + // Down samples constraints @(depth) to constraints @(depth-1) + template< class C , unsigned ... Degrees , unsigned int ... FEMSigs > void _downSample( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template RestrictionProlongation< UIntPack< Degrees ... > >& RP , LocalDepth highDepth , Pointer( C ) constraints ) const; + // Up samples coefficients @(depth-1) to coefficients @(depth) + template< class C , unsigned ... Degrees , unsigned int ... FEMSigs > void _upSample( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::template RestrictionProlongation< UIntPack< Degrees ... > >& RP , LocalDepth highDepth , Pointer( C ) coefficients ) 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; + + + // 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< bool ThreadSafe , 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 > Real _splatPointData( Allocator< FEMTreeNode > *nodeAllocator , const DensityEstimator< WeightDegree >& densityWeights , 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< 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 > V _evaluate( const Coefficients& coefficients , Point< Real , Dim > p , const PointEvaluator< UIntPack< DataSigs ... > , IsotropicUIntPack< Dim , D > >& pointEvaluator , const ConstPointSupportKey< UIntPack< FEMSignature< DataSigs >::Degree ... > >& dataKey ) 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 ) 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 + { + 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; + } + }; + 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 , 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< 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 ... FEMSigs > void _setRefinabilityFlags( UIntPack< FEMSigs ... > ) 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" ); + + 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; + + typedef std::tuple< typename BSplineEvaluationData< FEMSigs >::template Evaluator< PointD > ... > Evaluators; + typedef std::tuple< typename BSplineEvaluationData< FEMSigs >::template ChildEvaluator< PointD > ... > ChildEvaluators; + struct StencilData + { + 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; + }; + 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<>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 ); } + ); + + 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 ); + }; + + + static double _MaxMemoryUsage , _LocalMemoryUsage; + void _reorderDenseOrSparseNodeData( const node_index_type * , size_t ){ ; } + template< class Data , unsigned int ... FEMSigs , class ... DenseOrSparseNodeData > + void _reorderDenseOrSparseNodeData( const node_index_type *map , size_t sz , SparseNodeData< Data , UIntPack< FEMSigs ... > >* sData , DenseOrSparseNodeData* ... data ) + { + if( sData ) sData->_remapIndices( map , sz ); + _reorderDenseOrSparseNodeData( map , sz , data ... ); + } + template< class Data , unsigned int ... FEMSigs , class ... DenseOrSparseNodeData > + void _reorderDenseOrSparseNodeData( const node_index_type *map , size_t sz , DenseNodeData< Data , UIntPack< FEMSigs ... > >* dData , DenseOrSparseNodeData* ... data ) + { + if( dData ) dData->_remapIndices( map , sz ); + _reorderDenseOrSparseNodeData( map , sz , data ... ); + } +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( void ) + { + if( _tree ) for( int c=0 ; c<(1< xForm ) const; + static void WriteParameter( FILE* fp ) + { + 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 ); + int dim = Dim; + fwrite( &dim , sizeof(int) , 1 , fp ); + } + + template< unsigned int LeftRadius , unsigned int RightRadius , class ... DenseOrSparseNodeData > void thicken( FEMTreeNode** nodes , size_t nodeCount , DenseOrSparseNodeData* ... data ); + template< unsigned int LeftRadius , unsigned int RightRadius , class IsThickenNode , class ... DenseOrSparseNodeData > void thicken( IsThickenNode F , DenseOrSparseNodeData* ... data ); + template< unsigned int Radius , class ... DenseOrSparseNodeData > void thicken( FEMTreeNode** nodes , size_t nodeCount , DenseOrSparseNodeData* ... data ){ thicken< Radius , Radius >( nodes , nodeCount , data ... ); } + template< unsigned int Radius , class IsThickenNode , class ... DenseOrSparseNodeData > void thicken( IsThickenNode F , DenseOrSparseNodeData* ... data ){ thicken< Radius , Radius >( F , data ... ); } + template< unsigned int DensityDegree > + typename FEMTree::template DensityEstimator< DensityDegree >* setDensityEstimator( const std::vector< PointSample >& samples , LocalDepth splatDepth , Real samplesPerNode , int coDimension ); + template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > + SparseNodeData< OutData , UIntPack< DataSigs ... > > setDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , Real& pointWeightSum , std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction ); + template< unsigned int ... DataSigs , unsigned int DensityDegree , class InData , class OutData > +#if defined(_WIN32) || defined(_WIN64) + SparseNodeData< OutData , UIntPack< DataSigs ... > > setDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , Real& pointWeightSum , std::function< bool ( InData , OutData& ) > ConversionFunction , std::function< Real ( InData ) > BiasFunction = []( InData ){ return 0.f; } ); +#else // !_WIN32 && !_WIN64 + SparseNodeData< OutData , UIntPack< DataSigs ... > > setDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , Real& pointWeightSum , 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< Data , IsotropicUIntPack< Dim , DataSig > > setSingleDepthDataField( const std::vector< PointSample >& samples , const std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density ); + template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data > + SparseNodeData< ProjectiveData< Data , Real > , IsotropicUIntPack< Dim , DataSig > > setMultiDepthDataField( const std::vector< PointSample >& samples , std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density , bool nearest=false ); + template< unsigned int MaxDegree , class HasDataFunctor , class ... DenseOrSparseNodeData > void finalizeForMultigrid( LocalDepth fullDepth , const HasDataFunctor F , 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; + + // 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 ); + } + + template< typename T , unsigned int ... FEMSigs , unsigned int PointD , unsigned int ... PointDs > + typename std::enable_if< (sizeof...(PointDs)!=0) >::type addInterpolationConstraints( DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , LocalDepth maxDepth , const InterpolationInfo< T , PointD >& iInfo , const InterpolationInfo< T , PointDs >& ... iInfos ) const + { + addInterpolationConstraints< T , FEMSigs ... >( constraints , maxDepth , iInfo ); + addInterpolationConstraints< T , FEMSigs ... >( constraints , maxDepth , iInfos ... ); + } + template< typename T , unsigned int ... FEMSigs , unsigned int PointD > void addInterpolationConstraints( DenseNodeData< T , UIntPack< FEMSigs ... > >& constraints , LocalDepth maxDepth , const InterpolationInfo< T , PointD >& interpolationInfo ) const; + + // 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; } ); + } + + template< unsigned int ... FEMSigs1 , unsigned int ... FEMSigs2 , unsigned int ... PointDs > + double interpolationDot( const DenseNodeData< Real , UIntPack< FEMSigs1 ... > >& coefficients1 , const DenseNodeData< Real , UIntPack< FEMSigs2 ... > >& coefficients2 , const InterpolationInfo< Real , PointDs >* ... iInfos ) const + { + static_assert( sizeof...( FEMSigs1 )==Dim && sizeof...( FEMSigs2 )==Dim , "[ERROR] Dimensions don't match" ); + return _interpolationDot( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , coefficients1 , coefficients2 , []( Real v , Real w ){ return v*w; } , iInfos... ); + } + template< unsigned int ... FEMSigs , unsigned int ... PointDs > + double interpolationSquareNorm( const DenseNodeData< Real , UIntPack< FEMSigs ... > >& coefficients , const InterpolationInfo< Real , PointDs >* ... iInfos ) const + { + static_assert( sizeof...( FEMSigs )==Dim , "[ERROR] Dimensions don't match" ); + return _interpolationDot< Real >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , coefficients , coefficients , []( Real v , Real w ){ return v*w; } , iInfos... ); + } + // 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< typename T , typename TDotT , unsigned int ... FEMSigs1 , unsigned int ... FEMSigs2 , unsigned int ... PointDs > + double interpolationDot( TDotT Dot , const DenseNodeData< T , UIntPack< FEMSigs1 ... > >& coefficients1 , const DenseNodeData< T , UIntPack< FEMSigs2 ... > >& coefficients2 , const InterpolationInfo< T , PointDs >* ... iInfos ) const + { + static_assert( sizeof...( FEMSigs1 )==Dim && sizeof...( FEMSigs2 )==Dim , "[ERROR] Dimensions don't match" ); + return _interpolationDot< T >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , coefficients1 , coefficients2 , Dot , iInfos... ); + } + template< typename T , typename TDotT , unsigned int ... FEMSigs , unsigned int ... PointDs > + double interpolationSquareNorm( TDotT Dot , const DenseNodeData< T , UIntPack< FEMSigs ... > >& coefficients , const InterpolationInfo< T , PointDs >* ... iInfos ) const + { + static_assert( sizeof...( FEMSigs )==Dim , "[ERROR] Dimensions don't match" ); + return _interpolationDot< T >( UIntPack< FEMSigs ... >() , UIntPack< FEMSigs ... >() , coefficients , coefficients , Dot , iInfos... ); + } + + template< typename T , unsigned int ... PointDs , unsigned int ... FEMSigs > + SparseMatrix< Real , matrix_index_type > systemMatrix( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , LocalDepth depth , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) const; + template< typename T , unsigned int ... PointDs , unsigned int ... FEMSigs > + SparseMatrix< Real , matrix_index_type > prolongedSystemMatrix( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , LocalDepth highDepth , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) const; + template< unsigned int ... FEMSigs > + SparseMatrix< Real , matrix_index_type > downSampleMatrix( UIntPack< FEMSigs ... > , LocalDepth highDepth ) const; + template< typename T , unsigned int ... PointDs , unsigned int ... FEMSigs > + SparseMatrix< Real , matrix_index_type > fullSystemMatrix( UIntPack< FEMSigs ... > , typename BaseFEMIntegrator::System< UIntPack< FEMSignature< FEMSigs >::Degree ... > >& F , LocalDepth depth , bool nonRefinableOnly , const InterpolationInfo< T , PointDs >* ... interpolationInfo ) 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 + { + 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; + }; + 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; + int baseDepth , 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 ) , baseDepth(0) , baseVCycles(1) { } + }; + // Solve the linear system + template< unsigned int ... FEMSigs , typename T , typename TDotT , unsigned int ... PointDs > + 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 , InterpolationInfo< T , PointDs >* ... iData ) const; + template< unsigned int ... FEMSigs , typename T , typename TDotT , unsigned int ... PointDs > + 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 , InterpolationInfo< T , PointDs >* ... iData ) const; + template< unsigned int ... FEMSigs , unsigned int ... PointDs > + 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 , InterpolationInfo< Real , PointDs >* ... iData ) const + { + return solveSystem< FEMSigs ... , Real >( UIntPack< FEMSigs ... >() , F , constraints , solution , []( Real v , Real w ){ return v*w; } , maxSolveDepth , solverInfo , iData ... ); + } + template< unsigned int ... FEMSigs , unsigned int ... PointDs > + 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 , InterpolationInfo< Real , PointDs >* ... iData ) const + { + return solveSystem( UIntPack< FEMSigs ... >() , F , constraints , []( Real v , Real w ){ return v*w; } , maxSolveDepth , solverInfo , iData ... ); + } + + FEMTreeNode& spaceRoot( void ){ return *_spaceRoot; } + 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; } + 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; } + LocalDepth depth( void ) const { return _spaceRoot->maxDepth(); } + void resetNodeIndices( void ){ _nodeCount = 0 ; for( FEMTreeNode* node=_tree->nextNode() ; node ; node=_tree->nextNode( node ) ) _nodeInitializer( *node ) , node->nodeData.flags=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< typename T , typename TDotT , unsigned int ... FEMSigs1 , unsigned int ... FEMSigs2 , class Coefficients1 , class Coefficients2 , unsigned int PointD , unsigned int ... PointDs > + double _interpolationDot( UIntPack< FEMSigs1 ... > , UIntPack< FEMSigs2 ... > , const Coefficients1& coefficients1 , const Coefficients2& coefficients2 , TDotT Dot , const InterpolationInfo< T , PointD >* iInfo , const InterpolationInfo< T , PointDs >* ... iInfos ) const + { + return _interpolationDot< T >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , coefficients1 , coefficients2 , Dot , iInfo ) + _interpolationDot< T >( UIntPack< FEMSigs1 ... >() , UIntPack< FEMSigs2 ... >() , coefficients1 , coefficients2 , Dot , iInfos... ); + } + 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 IsoStats + { + std::string toString( void ) const { return std::string( "Iso-surface extraction not supported for dimension %d" , Dim ); } + }; + template< typename Data , typename SetVertexFunction , unsigned int ... FEMSigs , unsigned int WeightDegree , unsigned int DataSig > + static IsoStats 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 + CoredMeshData< Vertex , node_index_type >& mesh , // The mesh in which to store the output + const SetVertexFunction &SetVertex , // A function for setting the depth and data of a vertex + bool nonLinearFit , // Should a linear interpolant be used + bool addBarycenter , // Should we triangulate polygons by adding a mid-point + bool polygonMesh , // Should we output triangles or polygons + bool flipOrientation // Should we flip the orientation + ) + { + // The unspecialized implementation is not supported + WARN( "Iso-surface extraction not supported for dimension " , Dim ); + return IsoStats(); + } +}; + +template< unsigned int Dim , class Real > +struct FEMTreeInitializer +{ + typedef RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type > FEMTreeNode; + typedef NodeAndPointSample< Dim , Real > PointSample; + + 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; + }; + + // 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 + static size_t Initialize( FEMTreeNode& root , InputPointStream< Real , Dim >& pointStream , int maxDepth , std::vector< PointSample >& samplePoints , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); + template< class Data > static size_t Initialize( FEMTreeNode& root , InputPointStreamWithData< Real , Dim , Data >& pointStream , int maxDepth , std::vector< PointSample >& samplePoints , std::vector< Data >& sampleData , bool mergeNodeSamples , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer , std::function< Real ( const Point< Real , Dim >& , Data& ) > ProcessData = []( const Point< Real , Dim >& , Data& ){ 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 , int maxDepth , std::vector< NodeSimplices< Dim , Real > >& nodeSimplices , Allocator< FEMTreeNode >* nodeAllocator , std::function< void ( FEMTreeNode& ) > NodeInitializer ); + + 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 ); + +protected: + 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& root , 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 _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 ThreadSafe > + static size_t _AddSimplex( FEMTreeNode* node , 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< unsigned int Dim , class Real > +template< unsigned int ... SupportSizes > +const unsigned int FEMTree< Dim , Real >::CornerLoopData< SupportSizes ... >::supportSizes[] = { SupportSizes ... }; + +#include "Mesh/PoissonRecon/FEMTree.inl" +#include "Mesh/PoissonRecon/FEMTree.SortedTreeNodes.inl" +#include "Mesh/PoissonRecon/FEMTree.WeightedSamples.inl" +#include "Mesh/PoissonRecon/FEMTree.System.inl" +#include "Mesh/PoissonRecon/FEMTree.Evaluation.inl" +#include "Mesh/PoissonRecon/FEMTree.IsoSurface.specialized.inl" +#include "Mesh/PoissonRecon/FEMTree.Initialize.inl" +#endif // FEM_TREE_INCLUDED diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/FEMTree.inl b/modules/PoissonRecon/include/Mesh/PoissonRecon/FEMTree.inl new file mode 100644 index 00000000..c13539e1 --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/FEMTree.inl @@ -0,0 +1,1077 @@ +/* +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 "Mesh/PoissonRecon/MyMiscellany.h" + +///////////////////// +// FEMTreeNodeData // +///////////////////// +FEMTreeNodeData::FEMTreeNodeData( void ){ flags = 0; } +FEMTreeNodeData::~FEMTreeNodeData( void ) { } + + +///////////// +// FEMTree // +///////////// +template< unsigned int Dim , class Real > +double FEMTree< Dim , Real >::MemoryUsage( void ) +{ + double mem = double( MemoryInfo::Usage() ) / (1<<20); + _MaxMemoryUsage = std::max< double >( mem , _MaxMemoryUsage ); + _LocalMemoryUsage = std::max< double >( mem , _LocalMemoryUsage ); + return mem; +} + +template< unsigned int Dim , class Real > FEMTree< Dim , Real >::FEMTree( size_t blockSize ) : _nodeInitializer( *this ) +{ + if( blockSize ) + { + nodeAllocators.resize( std::thread::hardware_concurrency() ); + for( size_t i=0 ; i(); + nodeAllocators[i]->set( blockSize ); + } + } + _nodeCount = 0; + _tree = FEMTreeNode::NewBrood( nodeAllocators.size() ? nodeAllocators[0] : NULL , _nodeInitializer ); + _tree->template initChildren< false >( nodeAllocators.size() ? nodeAllocators[0] : NULL , _nodeInitializer ) , _spaceRoot = _tree->children; + int offset[Dim]; + for( int d=0 ; d::ResetDepthAndOffset( _spaceRoot , 0 , offset ); + _depthOffset = 0; + memset( _femSigs1 , -1 , sizeof( _femSigs1 ) ); + memset( _femSigs2 , -1 , sizeof( _femSigs2 ) ); + memset( _refinableSigs , -1 , sizeof( _refinableSigs ) ); +} +template< unsigned int Dim , class Real > +FEMTree< Dim , Real >::FEMTree( FILE* fp , XForm< Real , Dim+1 > &xForm , size_t blockSize ) : _nodeInitializer( *this ) +{ + if( blockSize ) + { + nodeAllocators.resize( std::thread::hardware_concurrency() ); + for( size_t i=0 ; i(); + 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; + + 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 > void FEMTree< Dim , Real >::write( FILE* fp , XForm< Real , Dim+1 > xForm ) const +{ + fwrite( xForm.coords , sizeof( Real ) , (Dim+1)*(Dim+1) , fp ); + fwrite( &_depthOffset , sizeof( int ) , 1 , fp ); + _tree->write( fp ); +} + +template< unsigned int Dim , class Real > +const RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* FEMTree< Dim , Real >::leaf( Point< Real , Dim > p ) const +{ + if( !_InBounds( p ) ) return NULL; + Point< Real , Dim > center; + for( int d=0 ; dchildren ) + { + int cIndex = FEMTreeNode::ChildIndex( center , p ); + node = node->children + cIndex; + 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 > +template< bool ThreadSafe > +RegularTreeNode< Dim , FEMTreeNodeData , depth_and_offset_type >* FEMTree< Dim , Real >::_leaf( Allocator< FEMTreeNode > *nodeAllocator , Point< Real , Dim > p , LocalDepth maxDepth ) +{ + if( !_InBounds( p ) ) return NULL; + Point< Real , Dim > center; + for( int d=0 ; dchildren ) || ( d>=0 && dchildren ) node->template initChildren< ThreadSafe >( nodeAllocator , _nodeInitializer ); + int cIndex = FEMTreeNode::ChildIndex( center , p ); + node = node->children + cIndex; + d++; + 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 > +bool FEMTree< Dim , Real >::isValidFEMNode( UIntPack< FEMSignatures ... > , const FEMTreeNode* node ) const +{ + if( GetGhostFlag< Dim >( node ) ) return false; + LocalDepth d ; LocalOffset off ; _localDepthAndOffset( node , d , off ); + if( d<0 ) return false; + return FEMIntegrator::IsValidFEMNode( UIntPack< FEMSignatures ... >() , d , off ); +} +template< unsigned int Dim , class Real > +bool FEMTree< Dim , Real >::isValidSpaceNode( const FEMTreeNode* node ) const +{ + if( !node ) return false; + LocalDepth d ; LocalOffset off ; _localDepthAndOffset( node , d , off ); + if( d<0 ) return false; + int res = 1<=res ) return false; + return true; +} + +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 ) +{ + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + bool refine = d::Signature ... >() , d , off ) ); + if( refine ) + { + if( !node->children ) node->template initChildren< ThreadSafe >( nodeAllocator , _nodeInitializer ); + 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 ); +} +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 +{ + LocalDepth d ; LocalOffset off; + _localDepthAndOffset( node , d , off ); + bool refine = d<0 || !FEMIntegrator::IsOutOfBounds( UIntPack< FEMDegreeAndBType< Degrees , BOUNDARY_FREE >::Signature ... >() , d , off ); + + if( refine ) + { + if( !node->children ) return d; + else + { + LocalDepth depth = INT_MAX; + for( int c=0 ; c<(1<() , 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; + LocalDepth depth = INT_MAX; + for( int c=0 ; c<(1<() , _tree->children+c ); + if( d +template< unsigned int LeftRadius , unsigned int RightRadius , class ... DenseOrSparseNodeData > +void FEMTree< Dim , Real >::thicken( FEMTreeNode **nodes , size_t nodeCount, DenseOrSparseNodeData* ... data ) +{ + Allocator< FEMTreeNode > *nodeAllocator = nodeAllocators.size() ? nodeAllocators[0] : NULL; + std::vector< node_index_type > map( _nodeCount ); + for( node_index_type i=0 ; i<_nodeCount ; i++ ) map[i] = i; + { + int d=0 , off[Dim]; + for( int d=0 ; d::template NeighborKey< IsotropicUIntPack< Dim , LeftRadius > , IsotropicUIntPack< Dim , RightRadius > > neighborKey; + neighborKey.set( _tree->maxDepth() ); + for( size_t i=0 ; i( nodes[i] , nodeAllocator , _nodeInitializer ); + { + int d=0 , off[Dim]; + for( int d=0 ; d +template< unsigned int LeftRadius , unsigned int RightRadius , class IsThickenNode , class ... DenseOrSparseNodeData > +void FEMTree< Dim , Real >::thicken( IsThickenNode F , DenseOrSparseNodeData* ... data ) +{ + std::vector< FEMTreeNode* > nodes; + for( FEMTreeNode* node=_tree->nextNode() ; node ; node=_tree->nextNode( node ) ) if( IsActiveNode( node ) && F( node ) ) nodes.push_back( node ); + thicken< LeftRadius , RightRadius >( &nodes[0] , nodes.size() , data ... ); +} + +template< unsigned int Dim , class Real > +template< unsigned int DensityDegree > +typename FEMTree< Dim , Real >::template DensityEstimator< DensityDegree >* FEMTree< Dim , Real >::setDensityEstimator( const std::vector< PointSample >& samples , LocalDepth splatDepth , Real samplesPerNode , int coDimension ) +{ + 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 , coDimension ); + DensityEstimator< DensityDegree >& density = *_density; + PointSupportKey< IsotropicUIntPack< Dim , DensityDegree > > densityKey; + densityKey.set( _localToGlobal( splatDepth ) ); + + std::vector< node_index_type > sampleMap( nodeCount() , -1 ); + 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 ); + 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; + Real w = s.weight / samplesPerNode; + _addWeightContribution< true >( nodeAllocator , density , node , p , densityKey , w ); + } + sample += s; + } + else if( idx<(node_index_type)sampleMap.size() && sampleMap[idx]!=-1 ) + { + sample = samples[ sampleMap[ idx ] ].sample; + if( d<=splatDepth && sample.weight>0 ) + { + Point< Real , Dim > p = sample.data / sample.weight; + Real w = sample.weight / samplesPerNode; + _addWeightContribution< true >( nodeAllocator , density , node , p , densityKey , w ); + } + } + return sample; + }; + SetDensity( _spaceRoot ); + + MemoryUsage(); + 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 >::setDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , Real& pointWeightSum , 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 setDataField( UIntPack< DataSigs ... >() , samples , data , density , pointWeightSum , 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 >::setDataField( UIntPack< DataSigs ... > , const std::vector< PointSample >& samples , const std::vector< InData >& data , const DensityEstimator< DensityDegree >* density , Real& pointWeightSum , std::function< bool ( InData , OutData & , Real & ) > ConversionAndBiasFunction ) +{ + LocalDepth maxDepth = _spaceRoot->maxDepth(); + 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 > dataField; + Real _pointWeightSum = 0; + 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 ) ) + { + AddAtomic( weightSum , sample.weight ); + out *= sample.weight; + Allocator< FEMTreeNode > *nodeAllocator = nodeAllocators.size() ? nodeAllocators[ thread ] : NULL; +#if defined( __GNUC__ ) && __GNUC__ < 5 + #warning "you've got me gcc version<5" + if( density ) AddAtomic( _pointWeightSum , _splatPointData< true , true , DensityDegree , OutData >( nodeAllocator , *density , p , out , dataField , densityKey , oneKey ? *( (DataKey*)&densityKey ) : dataKey , 0 , maxDepth , Dim , depthBias ) * sample.weight ); +#else // !__GNUC__ || __GNUC__ >=5 + if( density ) AddAtomic( _pointWeightSum , _splatPointData< true , true , DensityDegree , OutData , DataSigs ... >( nodeAllocator , *density , p , out , dataField , densityKey , oneKey ? *( (DataKey*)&densityKey ) : dataKey , 0 , maxDepth , Dim , depthBias ) * sample.weight ); +#endif // __GNUC__ || __GNUC__ < 4 + 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 + _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 ); + } + } + } + } + ); + pointWeightSum = _pointWeightSum / weightSum; + MemoryUsage(); + return dataField; +} +template< unsigned int Dim , class Real > +template< unsigned int DataSig , bool CreateNodes , unsigned int DensityDegree , class Data > +SparseNodeData< Data , IsotropicUIntPack< Dim , DataSig > > FEMTree< Dim , Real >::setSingleDepthDataField( const std::vector< PointSample >& samples , const std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density ) +{ + LocalDepth maxDepth = _spaceRoot->maxDepth(); + PointSupportKey< IsotropicUIntPack< Dim , DensityDegree > > densityKey; + PointSupportKey< IsotropicUIntPack< Dim , FEMSignature< DataSig >::Degree > > dataKey; + densityKey.set( _localToGlobal( maxDepth ) ) , dataKey.set( _localToGlobal( maxDepth ) ); + + SparseNodeData< Data , IsotropicUIntPack< Dim , DataSig > > dataField; + for( node_index_type i=0 ; i , Real >& sample = samples[i].sample; + const Data& data = sampleData[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( density ) _splatPointData< CreateNodes , false , DensityDegree , DataSig >( *density , p , data * sample.weight , dataField , densityKey , dataKey , 0 , maxDepth , Dim ); + else _splatPointData< CreateNodes , false , DataSig >( leaf( p , maxDepth ) , p , data * sample.weight , dataField , dataKey ); + } + MemoryUsage(); + return dataField; +} +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 >::setMultiDepthDataField( const std::vector< PointSample >& samples , std::vector< Data >& sampleData , const DensityEstimator< DensityDegree >* density , bool nearest ) +{ + 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 ) ); + + 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; + const Data& data = sampleData[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 ); + } + MemoryUsage(); + return dataField; +} +template< unsigned int Dim , class Real > +template< unsigned int MaxDegree , class HasDataFunctor , class ... DenseOrSparseNodeData > +void FEMTree< Dim , Real >::finalizeForMultigrid( LocalDepth fullDepth , const HasDataFunctor F , DenseOrSparseNodeData* ... data ) +{ + 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) ) + { + // +-+-+-+-+-+-+-+-+ + // | | | | | | | | | + // +-+-+-+-+-+-+-+-+ + // | | | | | | | | | + // +-+-+-+-+ +-+-+-+-+-+-+-+-+ + // | | | | | | | | | | | | | | + // +-+-+ +-+-+-+-+ +-+-+-+-+-+-+-+-+ + // |*| | | | | | | | | | | | | | | | + // +-o-+ -> +-+-o-+-+ -> +-+-+-+-o-+-+-+-+ + // | | | | | |*| | | | | | |*| | | | + // +-+-+ +-+-+-+-+ +-+-+-+-+-+-+-+-+ + // | | | | | | | | | | | | | | + // +-+-+-+-+ +-+-+-+-+-+-+-+-+ + // | | | | | | | | | + // +-+-+-+-+-+-+-+-+ + // | | | | | | | | | + // +-+-+-+-+-+-+-+-+ + + FEMTreeNode* newSpaceRootParent = FEMTreeNode::NewBrood( nodeAllocator , _nodeInitializer ); + FEMTreeNode* oldSpaceRootParent = _spaceRoot->parent; + int corner = _depthOffset<=1 ? (1<children = newSpaceRootParent; + for( int c=0 ; c<(1<maxDepth(); + // Make the low-resolution part of the tree be complete + fullDepth = std::max< LocalDepth >( 0 , std::min< LocalDepth >( _maxDepth , fullDepth ) ); + _setFullDepth< false >( IsotropicUIntPack< Dim , MaxDegree >() , nodeAllocator , fullDepth ); + // 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 = 0 , SetGhostFlag< Dim >( node , _localDepth( node )>fullDepth ); + + // Set the ghost nodes for the high-res part of the tree + _clipTree( F , fullDepth ); + + const int OverlapRadius = -BSplineOverlapSizes< MaxDegree , MaxDegree >::OverlapStart; + int maxDepth = _tree->maxDepth( ); + typedef typename FEMTreeNode::template NeighborKey< IsotropicUIntPack< Dim , OverlapRadius > , IsotropicUIntPack< Dim , OverlapRadius > > NeighborKey; + + std::vector< NeighborKey > neighborKeys( ThreadPool::NumThreads() ); + for( int i=0 ; i=0 ; d-- ) + { + 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< Dim >( node->children ) ) nodes.push_back( node ); + ThreadPool::Parallel_for( 0 , nodes.size() , [&]( unsigned int thread , size_t i ) + { + NeighborKey& neighborKey = neighborKeys[ thread ]; + FEMTreeNode* node = nodes[i]; + neighborKey.template getNeighbors< true , true >( node , nodeAllocators.size() ? nodeAllocators[ thread ] : NULL , _nodeInitializer ); + Pointer( FEMTreeNode* ) nodes = neighborKey.neighbors[ _localToGlobal(d) ].neighbors().data; + unsigned int size = neighborKey.neighbors[ _localToGlobal(d) ].neighbors.Size; + for( unsigned int i=0 ; i( nodes[i] , false ); + } + ); + } + std::vector< node_index_type > map; + _sNodes.set( *_tree , &map ); + _setSpaceValidityFlags(); + for( FEMTreeNode* node=_tree->nextNode() ; node ; node=_tree->nextNode( node ) ) if( !IsActiveNode< Dim >( node ) ) node->nodeData.nodeIndex = -1; + _reorderDenseOrSparseNodeData( &map[0] , _sNodes.size() , data ... ); + MemoryUsage(); +} + +template< unsigned int Dim , class Real > +void FEMTree< Dim , Real >::_setSpaceValidityFlags( void ) const +{ + 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; + } + ); +} +template< unsigned int Dim , class Real > +template< unsigned int ... FEMSigs1 > +void FEMTree< Dim , Real >::_setFEM1ValidityFlags( UIntPack< FEMSigs1 ... > ) const +{ + bool needToReset; + unsigned int femSigs1[] = { FEMSigs1 ... }; + { + static std::mutex m; + std::lock_guard< std::mutex > lock( m ); + needToReset = memcmp( femSigs1 , _femSigs1 , sizeof( _femSigs1 ) )!=0; + if( needToReset ) memcpy( _femSigs1 , femSigs1 , sizeof( _femSigs1 ) ); + } + if( needToReset ) + for( node_index_type i=0 ; i<(node_index_type)_sNodes.size() ; i++ ) + { + const unsigned char MASK = ~( FEMTreeNodeData::FEM_FLAG_1 ); + _sNodes.treeNodes[i]->nodeData.flags &= MASK; + if( isValidFEMNode( UIntPack< FEMSigs1 ... >() , _sNodes.treeNodes[i] ) ) _sNodes.treeNodes[i]->nodeData.flags |= FEMTreeNodeData::FEM_FLAG_1; + } + +} +template< unsigned int Dim , class Real > +template< unsigned int ... FEMSigs2 > +void FEMTree< Dim , Real >::_setFEM2ValidityFlags( UIntPack< FEMSigs2 ... > ) const +{ + bool needToReset; + unsigned int femSigs2[] = { FEMSigs2 ... }; + { + static std::mutex m; + std::lock_guard< std::mutex > lock(m); + needToReset = memcmp( femSigs2 , _femSigs2 , sizeof( _femSigs2 ) )!=0; + if( needToReset ) memcpy( _femSigs2 , femSigs2 , sizeof( _femSigs2 ) ); + } + if( needToReset ) + for( node_index_type i=0 ; i<(node_index_type)_sNodes.size() ; i++ ) + { + const unsigned char MASK = ~( FEMTreeNodeData::FEM_FLAG_2 ); + _sNodes.treeNodes[i]->nodeData.flags &= MASK; + if( isValidFEMNode( UIntPack< FEMSigs2 ... >() , _sNodes.treeNodes[i] ) ) _sNodes.treeNodes[i]->nodeData.flags |= FEMTreeNodeData::FEM_FLAG_2; + } +} +template< unsigned int Dim , class Real > +template< unsigned int ... FEMSigs > +void FEMTree< Dim , Real >::_setRefinabilityFlags( UIntPack< FEMSigs ... > ) const +{ + bool needToReset; + unsigned int refinableSigs[] = { FEMSigs ... }; + { + static std::mutex m; + std::lock_guard< std::mutex > lock(m); + needToReset = memcmp( refinableSigs , _refinableSigs , sizeof( _refinableSigs ) )!=0; + if( needToReset ) memcpy( _refinableSigs , refinableSigs , sizeof( _refinableSigs ) ); + } + if( needToReset ) + { + typedef typename FEMTreeNode::template ConstNeighborKey< UIntPack< ( - BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::UpSampleStart ) ... > , UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::UpSampleEnd ... > > UpSampleKey; + typedef typename FEMTreeNode::template ConstNeighbors< UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::UpSampleSize ... > > UpSampleNeighbors; + static const int UpSampleStart[] = { BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::UpSampleStart ... }; + std::vector< UpSampleKey > neighborKeys( ThreadPool::NumThreads() ); + for( size_t i=0 ; inodeData.flags &= MASK; + + LocalDepth d ; LocalOffset pOff; + _localDepthAndOffset( _sNodes.treeNodes[i] , d , pOff ); + + // Get the supporting child neighbors + neighborKey.getNeighbors( _sNodes.treeNodes[i] ); + UpSampleNeighbors neighbors; + neighborKey.getChildNeighbors( 0 , _localToGlobal( d ) , neighbors ); + + // Check if the child neighbors exist (i.e. that the children nodes are not ghost-nodes if they correspond to valid coefficients) + bool refinable = true; + LocalOffset cOff; + WindowLoop< Dim >::Run + ( + IsotropicUIntPack< Dim , 0 >() , UIntPack< BSplineSupportSizes< FEMSignature< FEMSigs >::Degree >::UpSampleSize ... >() , + [&]( int d , int i ){ cOff[d] = pOff[d]*2 + UpSampleStart[d] + i; } , + [&]( const FEMTreeNode* node ){ if( GetGhostFlag< Dim >( node ) && FEMIntegrator::IsValidFEMNode( UIntPack< FEMSigs ... >() , d+1 , cOff ) ) refinable = false; } , + neighbors.neighbors() + ); + if( refinable ) _sNodes.treeNodes[i]->nodeData.flags |= FEMTreeNodeData::REFINABLE_FLAG; + } + ); + } +} +template< unsigned int Dim , class Real > +template< class HasDataFunctor > +void FEMTree< Dim , Real >::_clipTree( const HasDataFunctor& f , LocalDepth fullDepth ) +{ + std::vector< FEMTreeNode * > nodes; + 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 ) nodes.push_back( temp ); + ThreadPool::Parallel_for( 0 , nodes.size() , [&]( unsigned int , size_t i ) + { + for( FEMTreeNode* node=nodes[i]->nextNode() ; node ; node=nodes[i]->nextNode(node) ) if( node->children ) + { + bool hasData = false; + for( int c=0 ; c<(1<children + c ); + for( int c=0 ; c<(1<( node->children+c , !hasData ); + } + } + ); +} + +template< unsigned int Dim , class Real > +template< typename T , typename Data , unsigned int PointD , typename ConstraintDual , typename SystemDual > +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 ); } ); + for( node_index_type i=0 ; i<(node_index_type)samples.size() ; i++ ) + { + const FEMTreeNode* leaf = samples[i].node; + while( leaf && !tree._isValidSpaceNode( leaf ) ) leaf = leaf->parent; + if( leaf && tree._isValidSpaceNode( leaf ) ) _sampleSpan[ leaf->nodeData.nodeIndex ].second++; + } + _iData.resize( samples.size() ); + + std::function< void ( FEMTreeNode* , node_index_type & ) > SetRange = [&] ( FEMTreeNode* node , node_index_type &start ) + { + std::pair< node_index_type , node_index_type >& span = _sampleSpan[ node->nodeData.nodeIndex ]; + if( tree._isValidSpaceNode( node->children ) ) + { + for( int c=0 ; c<(1<children + c , start ); + span.first = _sampleSpan[ node->children[0 ].nodeData.nodeIndex ].first; + span.second = _sampleSpan[ node->children[ (1<nextNode() ; node ; node=tree._spaceRoot->nextNode(node) ) + if( tree._isValidSpaceNode( node ) && !tree._isValidSpaceNode( node->children ) ) _sampleSpan[ node->nodeData.nodeIndex ].second = _sampleSpan[ node->nodeData.nodeIndex ].first; + + for( node_index_type i=0 ; i<(node_index_type)samples.size() ; i++ ) + { + const FEMTreeNode* leaf = samples[i].node; + while( leaf && !tree._isValidSpaceNode( leaf ) ) leaf = leaf->parent; + if( leaf && tree._isValidSpaceNode( leaf ) ) + { + const ProjectiveData< Point< Real , Dim > , Real >& pData = samples[i].sample; + DualPointAndDataInfo< Dim , Real , Data , T , PointD >& _pData = _iData[ _sampleSpan[ leaf->nodeData.nodeIndex ].second++ ]; + _pData.pointInfo.position = pData.data; + _pData.pointInfo.weight = pData.weight; + _pData.pointInfo.dualValues = _constraintDual( pData.data/pData.weight , sampleData[i]/pData.weight ) * pData.weight; + _pData.data = sampleData[i]; + } + } + + 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< +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() ); + 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++ ) + { + const FEMTreeNode* leaf = samples[i].node; + while( leaf && !tree._isValidSpaceNode( leaf ) ) leaf = leaf->parent; + if( leaf && tree._isValidSpaceNode( leaf ) ) _sampleSpan[ leaf->nodeData.nodeIndex ].second++; + } + _iData.resize( samples.size() ); + + std::function< void ( FEMTreeNode* , node_index_type & ) > SetRange = [&] ( FEMTreeNode* node , node_index_type &start ) + { + std::pair< node_index_type , node_index_type >& span = _sampleSpan[ node->nodeData.nodeIndex ]; + if( tree._isValidSpaceNode( node->children ) ) + { + for( int c=0 ; c<(1<children + c , start ); + span.first = _sampleSpan[ node->children[0 ].nodeData.nodeIndex ].first; + span.second = _sampleSpan[ node->children[ (1<nextNode() ; node ; node=tree._spaceRoot->nextNode(node) ) + if( tree._isValidSpaceNode( node ) && !tree._isValidSpaceNode( node->children ) ) _sampleSpan[ node->nodeData.nodeIndex ].second = _sampleSpan[ node->nodeData.nodeIndex ].first; + + for( node_index_type i=0 ; i<(node_index_type)samples.size() ; i++ ) + { + const FEMTreeNode* leaf = samples[i].node; + while( leaf && !tree._isValidSpaceNode( leaf ) ) leaf = leaf->parent; + if( leaf && tree._isValidSpaceNode( leaf ) ) + { + const ProjectiveData< Point< Real , Dim > , Real >& pData = samples[i].sample; + DualPointInfo< Dim , Real , T , PointD >& _pData = _iData[ _sampleSpan[ leaf->nodeData.nodeIndex ].second++ ]; + _pData.position = pData.data; + _pData.dualValues = _constraintDual( pData.data/pData.weight ) * pData.weight; + _pData.weight = pData.weight; + } + } + + 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; + if( leaf && tree._isValidSpaceNode( leaf ) ) _sampleSpan[ leaf->nodeData.nodeIndex ].second++; + } + _iData.resize( samples.size() ); + + std::function< void ( FEMTreeNode* , node_index_type & ) > SetRange = [&] ( FEMTreeNode *node , node_index_type &start ) + { + std::pair< node_index_type , node_index_type >& span = _sampleSpan[ node->nodeData.nodeIndex ]; + if( tree._isValidSpaceNode( node->children ) ) + { + for( int c=0 ; c<(1<children + c , start ); + span.first = _sampleSpan[ node->children[0 ].nodeData.nodeIndex ].first; + span.second = _sampleSpan[ node->children[ (1<nextNode() ; node ; node=tree._spaceRoot->nextNode(node) ) + if( tree._isValidSpaceNode( node ) && !tree._isValidSpaceNode( node->children ) ) _sampleSpan[ node->nodeData.nodeIndex ].second = _sampleSpan[ node->nodeData.nodeIndex ].first; + + for( node_index_type i=0 ; iparent; + if( leaf && tree._isValidSpaceNode( leaf ) ) + { + const ProjectiveData< Point< Real , Dim > , Real >& pData = samples[i].sample; + DualPointInfo< Dim , Real , T , PointD >& _pData = _iData[ _sampleSpan[ leaf->nodeData.nodeIndex ].second++ ]; + _pData.position = pData.data; + _pData.dualValues = _constraintDual( pData.data/pData.weight ) * pData.weight; + _pData.weight = pData.weight; + } + } + + 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 +{ + if( IsActiveNode< Dim >( node->children ) ) + { + bool hasChildData = false; + T t = {}; + for( int c=0 ; c<(1<children + c , interpolationInfo ) ) + { + t += interpolationInfo[ node->children + c ]; + hasChildData = true; + } + if( hasChildData && IsActiveNode< Dim >( node ) ) interpolationInfo[ node ] += t; + return hasChildData; + } + 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 +{ + 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; + const ProjectiveData< Point< Real , Dim > , Real >& pData = samples[i].sample; + while( !IsActiveNode< Dim >( node ) ) node = node->parent; + if( pData.weight ) + { + DualPointInfo< Dim , Real , T , PointD >& _pData = iInfo[node]; + _pData.position += pData.data; + _pData.weight += pData.weight; + _pData.dualValues += constraintDual( pData.data/pData.weight ) * pData.weight; + } + } + + // Set the interior values + _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(); + + // Set the average position and scale the weights + for( const FEMTreeNode* node=_tree->nextNode() ; node ; node=_tree->nextNode(node) ) if( IsActiveNode< Dim >( node ) ) + { + 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; +} +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 +{ + 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; + const ProjectiveData< Point< Real , Dim > , Real >& pData = samples[i].sample; + while( !IsActiveNode< Dim >( node ) ) node = node->parent; + if( pData.weight ) + { + DualPointAndDataInfo< Dim , Real , Data , T , PointD >& _pData = iInfo[node]; + _pData.pointInfo.position += pData.data; + _pData.pointInfo.dualValues += constraintDual( pData.data/pData.weight , sampleData[i]/pData.weight ) * pData.weight; + _pData.pointInfo.weight += pData.weight; + _pData.data += sampleData[i]; + } + } + + // Set the interior values + _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; + } + ); + 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 ) ) + { + 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; + } + } + 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 +{ + SparseNodeData< DualPointInfoBrood< Dim , Real , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > iInfo; + for( node_index_type i=0 ; i , Real >& pData = samples[i].sample; + while( !IsActiveNode< Dim >( node ) ) node = node->parent; + if( pData.weight ) + { + DualPointInfoBrood< Dim , Real , T , PointD >& _pData = iInfo[node]; + Point< Real , Dim > p = pData.data/pData.weight; + int cIdx = _childIndex( node , p ); + _pData[cIdx].position += pData.data; + _pData[cIdx].weight += pData.weight; + _pData[cIdx].dualValues += constraintDual( p ) * pData.weight; + } + } + + // Set the interior values + _setInterpolationInfoFromChildren( _spaceRoot , iInfo ); + + ThreadPool::Parallel_for( 0 , iInfo.size() , [&]( unsigned int , size_t i ) + { + iInfo[i].finalize(); + for( size_t c=0 ; c +template< typename T , typename Data , unsigned int PointD , typename ConstraintDual > +SparseNodeData< DualPointAndDataInfoBrood< Dim , Real , Data , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > FEMTree< Dim , Real >::_densifyChildInterpolationInfoAndSetDualConstraints( const std::vector< PointSample >& samples , ConstPointer( Data ) sampleData , ConstraintDual constraintDual , bool noRescale ) const +{ + SparseNodeData< DualPointAndDataInfoBrood< Dim , Real , Data , T , PointD > , IsotropicUIntPack< Dim , FEMTrivialSignature > > iInfo; + for( node_index_type i=0 ; i , Real >& pData = samples[i].sample; + while( !IsActiveNode< Dim >( node ) ) node = node->parent; + if( pData.weight ) + { + DualPointAndDataInfoBrood< Dim , Real , Data , T , PointD >& _pData = iInfo[node]; + Point< Real , Dim > p = pData.data/pData.weight; + int cIdx = _childIndex( node , p ); + _pData[cIdx].pointInfo.position += pData.data; + _pData[cIdx].pointInfo.dualValues += constraintDual( p , sampleData[i]/pData.weight ) * pData.weight; + _pData[cIdx].pointInfo.weight += pData.weight; + _pData[cIdx].data += sampleData[i]; + } + } + + // Set the interior values + _setInterpolationInfoFromChildren( _spaceRoot , iInfo ); + + ThreadPool::Parallel_for( 0 , iInfo.size() , [&]( unsigned int , size_t i ) + { + iInfo[i].finalize(); + for( size_t c=0 ; c +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 ); + + // 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 ); + + // 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 ); + map.resize( mapSize ); + } + + std::function< void ( FEMTreeNode* , FEMTreeNode* , std::vector< node_index_type > & , node_index_type & ) > MergeNodes = [&]( FEMTreeNode* node1 , FEMTreeNode* node2 , std::vector< node_index_type > &map , node_index_type &nextIndex ) + { + if( node1 && node2 ) + { + if( node2->nodeData.nodeIndex>=0 ) + { + if( node1->nodeData.nodeIndex<0 ) node1->nodeData.nodeIndex = nextIndex++; + map[ node2->nodeData.nodeIndex ] = node1->nodeData.nodeIndex; + } + if( node1->children && node2->children ) for( int c=0 ; c<(1<children+c , node2->children+c , map , nextIndex ); + else if( node2->children ) + { + for( int c=0 ; c<(1<children+c , map , nextIndex ); + node1->children = node2->children; + node2->children = NULL; + for( int c=0 ; c<(1<children[c].parent = node1; + } + } + else if( node2 ) + { + if( node2->nodeData.nodeIndex>=0 ){ map[ node2->nodeData.nodeIndex ] = nextIndex ; node2->nodeData.nodeIndex = nextIndex++; } + if( node2->children ) for( int c=0 ; c<(1<children+c , map , nextIndex ); + } + }; + + MergeNodes( _tree , tree->_tree , map , nextIndex ); + return map; +} + diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/Factor.h b/modules/PoissonRecon/include/Mesh/PoissonRecon/Factor.h new file mode 100644 index 00000000..3845e174 --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/Factor.h @@ -0,0 +1,154 @@ +/* +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 FACTOR_INCLUDED +#define FACTOR_INCLUDED + +#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 ) +{ + 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; + + 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; +} +// 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 ) + { + 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; +} +#endif // FACTOR_INCLUDED \ No newline at end of file diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/FunctionData.h b/modules/PoissonRecon/include/Mesh/PoissonRecon/FunctionData.h new file mode 100644 index 00000000..37a40c8d --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/FunctionData.h @@ -0,0 +1,142 @@ +/* +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 "Mesh/PoissonRecon/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 "Mesh/PoissonRecon/FunctionData.inl" +#endif // FUNCTION_DATA_INCLUDED \ No newline at end of file diff --git a/Src/FunctionData.inl b/modules/PoissonRecon/include/Mesh/PoissonRecon/FunctionData.inl similarity index 100% rename from Src/FunctionData.inl rename to modules/PoissonRecon/include/Mesh/PoissonRecon/FunctionData.inl diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/Geometry.h b/modules/PoissonRecon/include/Mesh/PoissonRecon/Geometry.h new file mode 100644 index 00000000..2a7e9378 --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/Geometry.h @@ -0,0 +1,629 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +#ifndef GEOMETRY_INCLUDED +#define GEOMETRY_INCLUDED + +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 +#include +#endif // _WIN32 + +template< class Real > Real Random( void ); + +template< class Real , unsigned int Dim > struct XForm; + +template< class Real , unsigned int Dim > +struct Point +{ + 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 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 _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 +struct XForm +{ + Real coords[Dim][Dim]; + XForm( void ) { memset( coords , 0 , sizeof(Real) * Dim * Dim ); } + 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 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 +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< class Real , unsigned int Dim > +struct Simplex< Real , Dim , 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< 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 ) + { + 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<=K ) _init( k+1 , values ... ); + } +}; +template< typename Index > using EdgeIndex = SimplexIndex< 1 , Index >; +template< typename Index > using TriangleIndex = SimplexIndex< 2 , Index >; + +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 > +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]; +}; + +template< typename Index > +struct CoredVertexIndex +{ + Index idx; + bool inCore; +}; + +template< class Vertex , typename Index > +class CoredCurveData +{ +public: + std::vector< Vertex > inCorePoints; + virtual void resetIterator( void ) = 0; + + virtual Index addOutOfCorePoint( const Vertex& p ) = 0; + virtual Index addOutOfCorePoint_s( unsigned int thread , const Vertex& p ) = 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 nextOutOfCorePoint( Vertex& p )=0; + virtual Index nextEdge( CoredVertexIndex< Index >& v1 , CoredVertexIndex< Index >& v2 ) = 0; + + virtual size_t outOfCorePointCount(void)=0; + virtual size_t edgeCount( void ) = 0; +}; + +template< class Vertex , typename Index > +class CoredMeshData +{ +public: + virtual ~CoredMeshData( void ){} + std::vector< Vertex > inCorePoints; + virtual void resetIterator( void ) = 0; + + virtual Index addOutOfCorePoint( const Vertex& p ) = 0; + virtual Index addOutOfCorePoint_s( unsigned int thread , const Vertex& p ) = 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 nextOutOfCorePoint( Vertex& p )=0; + virtual Index nextPolygon( std::vector< CoredVertexIndex< Index > >& vertices ) = 0; + + virtual size_t outOfCorePointCount( void )=0; + virtual size_t polygonCount( 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 addOutOfCorePoint( const Vertex& p ); + Index addOutOfCorePoint_s( unsigned int thread , const Vertex& p ); + void addEdge_s( unsigned int thread , CoredVertexIndex< Index > v1 , CoredVertexIndex< Index > v2 ); + void addEdge_s( unsigned int thread , Index v1 , Index v2 ); + + Index nextOutOfCorePoint( Vertex& p ); + Index nextEdge( CoredVertexIndex< Index > &v1 , CoredVertexIndex< Index > &v2 ); + + size_t outOfCorePointCount( 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 addOutOfCorePoint( const Vertex& p ); + Index addOutOfCorePoint_s( unsigned int thread , const Vertex& p ); + void addPolygon_s( unsigned int thread , const std::vector< CoredVertexIndex< Index > >& vertices ); + void addPolygon_s( unsigned int thread , const std::vector< Index >& vertices ); + + Index nextOutOfCorePoint( Vertex& p ); + Index nextPolygon( std::vector< CoredVertexIndex< Index > >& vertices ); + + size_t outOfCorePointCount( void ); + size_t polygonCount( 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 addOutOfCorePoint( const Vertex& p ); + Index addOutOfCorePoint_s( unsigned int thread , const Vertex& p ); + void addEdge_s( unsigned int thread , CoredVertexIndex< Index > v1 , CoredVertexIndex< Index > v2 ); + void addEdge_s( unsigned int thread , Index v1 , Index v2 ); + + Index nextOutOfCorePoint( Vertex& p ); + Index nextEdge( CoredVertexIndex< Index > &v1 , CoredVertexIndex< Index > &v2 ); + + size_t outOfCorePointCount( void ); + size_t edgeCount( void ); +}; + +template< class Vertex , typename Index > +class CoredFileMeshData : public CoredMeshData< Vertex , Index > +{ + BufferedReadWriteFile *oocPointFile; + Index oocPoints; + std::vector< Index > polygons; + std::vector< BufferedReadWriteFile* > polygonFiles; + unsigned int threadIndex; +public: + CoredFileMeshData( const char* fileHeader="" ); + ~CoredFileMeshData( void ); + + void resetIterator( void ); + + Index addOutOfCorePoint( const Vertex& p ); + Index addOutOfCorePoint_s( unsigned int thread , const Vertex& p ); + void addPolygon_s( unsigned int thread , const std::vector< CoredVertexIndex< Index > >& vertices ); + void addPolygon_s( unsigned int thread , const std::vector< Index >& vertices ); + + Index nextOutOfCorePoint( Vertex& p ); + Index nextPolygon( std::vector< CoredVertexIndex< Index > >& vertices ); + + size_t outOfCorePointCount( void ); + size_t polygonCount( void ); +}; +#include "Mesh/PoissonRecon/Geometry.inl" + +#endif // GEOMETRY_INCLUDED diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/Geometry.inl b/modules/PoissonRecon/include/Mesh/PoissonRecon/Geometry.inl new file mode 100644 index 00000000..ef61cc1e --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/Geometry.inl @@ -0,0 +1,299 @@ +/* +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 "Mesh/PoissonRecon/MyMiscellany.h" + +template< class Real > Real Random( void ){ return Real( rand() )/RAND_MAX; } + +template< class Real , int Dim > +Point< Real , Dim > RandomBallPoint( void ) +{ + Point< Real , Dim > p; + while(1) + { + for( int d=0 ; d() ); + double l=SquareLength(p); + if( SquareLength( p )<=1 ) return p; + } +} +template< class Real , int Dim > +Point< Real , Dim > RandomSpherePoint( void ) +{ + Point< Real , Dim > p = RandomBallPoint< Real , Dim >(); + return p / (Real)Length( p ); +} + +///////////////////////// +// 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 >::addOutOfCorePoint( const Vertex& p ) +{ + oocPoints.push_back(p); + return ( Index )oocPoints.size()-1; +} +template< class Vertex , typename Index > +Index CoredVectorMeshData< Vertex , Index >::addOutOfCorePoint_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 >::nextOutOfCorePoint( 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 >::outOfCorePointCount( void ){ return oocPoints.size(); } +template< class Vertex , typename Index > +size_t CoredVectorMeshData< Vertex , Index >::polygonCount( void ) +{ + size_t count = 0; + for( size_t i=0 ; i +CoredFileMeshData< Vertex , Index >::CoredFileMeshData( const char* fileHeader ) +{ + threadIndex = 0; + oocPoints = 0; + polygons.resize( std::thread::hardware_concurrency() ); + for( unsigned int i=0 ; i +CoredFileMeshData< Vertex , Index >::~CoredFileMeshData( void ) +{ + delete oocPointFile; + for( unsigned int i=0 ; i +void CoredFileMeshData< Vertex , Index >::resetIterator ( void ) +{ + oocPointFile->reset(); + threadIndex = 0; + for( unsigned int i=0 ; ireset(); +} +template< class Vertex , typename Index > +Index CoredFileMeshData< Vertex , Index >::addOutOfCorePoint( const Vertex& p ) +{ + oocPointFile->write( &p , sizeof( Vertex ) ); + oocPoints++; + return oocPoints-1; +} +template< class Vertex , typename Index > +Index CoredFileMeshData< Vertex , Index >::addOutOfCorePoint_s( unsigned int thread , const Vertex& p ) +{ + Index sz; + { + static std::mutex m; + std::lock_guard< std::mutex > lock(m); + sz = oocPoints; + oocPointFile->write( &p , sizeof( Vertex ) ); + oocPoints++; + } + return sz; +} +template< class Vertex , typename Index > +void CoredFileMeshData< Vertex , Index >::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 ); + polygons[thread]++; +} +template< class Vertex , typename Index > +void CoredFileMeshData< Vertex , Index >::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< class Vertex , typename Index > +Index CoredFileMeshData< Vertex , Index >::nextOutOfCorePoint( Vertex& p ) +{ + if( oocPointFile->read( &p , sizeof( Vertex ) ) ) return 1; + else return 0; +} +template< class Vertex , typename Index > +Index CoredFileMeshData< Vertex , Index >::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< class Vertex , typename Index > +size_t CoredFileMeshData< Vertex , Index >::outOfCorePointCount( void ){ return oocPoints; } +template< class Vertex , typename Index > +size_t CoredFileMeshData< Vertex , Index >::polygonCount( void ) +{ + size_t count = 0; + for( size_t i=0 ; i +void Simplex< Real , Dim , K >::split( Point< Real , Dim > pNormal , Real pOffset , std::vector< Simplex >& back , std::vector< Simplex >& front ) const +{ + Real values[K+1]; + bool frontSet = false , backSet = false; + + // Evaluate the hyper-plane's function at the vertices and mark if strictly front/back vertices have been found + for( unsigned int k=0 ; k<=K ; k++ ) + { + values[k] = Point< Real , Dim >::Dot( p[k] , pNormal ) - pOffset; + backSet |= ( values[k]<0 ) , frontSet |= ( values[k]>0 ); + } + + // If all the vertices are behind or on, or all the vertices are in front or on, we are done. + if( !frontSet ){ back.push_back( *this ) ; return; } + if( !backSet ){ front.push_back( *this ) ; return; } + + // Pick some intersection of the hyper-plane with a simplex edge + unsigned int v1 , v2; + Point< Real , Dim > midPoint; + { + for( unsigned int i=0 ; i f; // The face + Simplex< Real , Dim , K > s; // The sub-simplex + for( unsigned int j=0 , idx=0 ; j<=K ; j++ ) if( j!=i ) f[idx++] = p[j]; + std::vector< Simplex< Real , Dim , K-1 > > _back , _front; + f.split( pNormal , pOffset , _back , _front ); + s[i] = midPoint; + + for( unsigned int j=0 ; j<_back.size() ; j++ ) + { + for( unsigned int k=0 ; k +#include "Mesh/PoissonRecon/MyMiscellany.h" + +struct ImageReader +{ + 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 ) + { + 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; + } + + 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; +}; +#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 +{ +#if defined( _WIN32 ) || defined( _WIN64 ) + static const char Separator = (char)'\\'; +#else // !_WIN + 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; } + + if( front ) + { + 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 ); + } + } + return out; + } +}; + +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; +#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; +#endif // WIN32 + return false; +} + +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 ); +#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 ); +#endif // WIN32 + else + { + delete[] ext; + THROW( "failed to get image reader for: " , fileName ); + } + 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 ); +#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 ); +#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 ); +#endif // WIN32 + delete[] 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; +#ifdef SUPPORT_TILES + 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; +#ifdef SUPPORT_TILES + else if( !strcasecmp( ext , "iGrid" ) ) return true; +#endif // SUPPORT_TILES +#endif // WIN32 + 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 ); +#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 ); +#ifdef SUPPORT_TILES + 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 ); +#ifdef SUPPORT_TILES + else if( !strcasecmp( ext , "iGrid" ) ) writer = new TiledImageWriter( fileName , width , height , channels , params ); +#endif // SUPPORT_TILES +#endif // WIN32 + else + { + delete[] ext; + THROW( "failed to get image writer for: " , fileName ); + } + 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; } + { + 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[1024]; + 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 ); + { + 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 ]; + + _tileNames = new char*[ _tileColumns * _tileRows ]; + char tileName[1024]; + 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( _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 ); + } + _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 ) + { + 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 ]; + 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 ); + } + 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/modules/PoissonRecon/include/Mesh/PoissonRecon/JPEG.h b/modules/PoissonRecon/include/Mesh/PoissonRecon/JPEG.h new file mode 100644 index 00000000..300e9990 --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/JPEG.h @@ -0,0 +1,52 @@ +#ifndef JPEG_INCLUDED +#define JPEG_INCLUDED +#include "Mesh/PoissonRecon/Image.h" + +#include + +#ifdef _WIN32 +#include +#include "JPEG/jpeglib.h" +#include "JPEG/jerror.h" +#include "JPEG/jmorecfg.h" +#else // !_WIN32 +#include +#include +#include +#endif // _WIN32 + +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 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 "Mesh/PoissonRecon/JPEG.inl" +#endif //JPEG_INCLUDED diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/JPEG.inl b/modules/PoissonRecon/include/Mesh/PoissonRecon/JPEG.inl new file mode 100644 index 00000000..48b62440 --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/JPEG.inl @@ -0,0 +1,130 @@ +#include +#include + + +inline METHODDEF( void ) +my_error_exit (j_common_ptr cinfo) +{ + // cinfo->err really points to a my_error_mgr struct, so coerce pointer + my_error_ptr myerr = (my_error_ptr) cinfo->err; + + // Always display the message. + // We could postpone this until after returning, if we chose. + (*cinfo->err->output_message) (cinfo); + + // Return control to the setjmp point + longjmp(myerr->setjmp_buffer, 1); +} + +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 ); + + struct jpeg_decompress_struct cInfo; + struct my_error_mgr jErr; + + 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" ); + } + + jpeg_create_decompress( &cInfo ); + jpeg_stdio_src( &cInfo , fp ); + + (void) jpeg_read_header( &cInfo , TRUE ); + + channels = cInfo.num_components; + width = cInfo.image_width; + height = cInfo.image_height; + jpeg_destroy_decompress( &cInfo ); + + fclose( fp ); + return true; +} + +inline JPEGReader::JPEGReader( const char* fileName , unsigned int& width , unsigned int& height , unsigned int& channels ) +{ + _currentRow = 0; + _fp = fopen( fileName , "rb" ); + if( !_fp ) 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" ); + } + + jpeg_create_decompress( &_cInfo ); + jpeg_stdio_src( &_cInfo , _fp ); + + (void) jpeg_read_header( &_cInfo , TRUE ); + (void) jpeg_start_decompress( &_cInfo ); + + channels = _cInfo.output_components; + width = _cInfo.output_width; + height = _cInfo.output_height; +} +inline JPEGReader::~JPEGReader( void ) +{ + (void) jpeg_finish_decompress( &_cInfo ); + jpeg_destroy_decompress( &_cInfo ); + fclose( _fp ); +} +inline unsigned int JPEGReader::nextRow( unsigned char* row ) +{ + JSAMPROW row_pointers[1]; + row_pointers[0] = row; + jpeg_read_scanlines( &_cInfo , row_pointers, 1 ); + return _currentRow++; +} + +inline JPEGWriter::JPEGWriter( const char* fileName , unsigned int width , unsigned int height , unsigned int channels , unsigned int quality ) +{ + _currentRow = 0; + _fp = fopen( fileName , "wb" ); + if( !_fp ) ERROR_OUT( "Failed to open: " , fileName ); + + _cInfo.err = jpeg_std_error( &_jErr.pub ); + jpeg_create_compress( &_cInfo ); + + jpeg_stdio_dest( &_cInfo , _fp ); + + _cInfo.image_width = width; + _cInfo.image_height = height; + _cInfo.input_components = channels; + _cInfo.in_color_space = JCS_RGB; /* colorspace of input image */ + + jpeg_set_defaults( &_cInfo ); + jpeg_set_quality( &_cInfo , quality , TRUE ); + + jpeg_start_compress( &_cInfo , TRUE ); +} +inline JPEGWriter::~JPEGWriter( void ) +{ + jpeg_finish_compress( &_cInfo ); + jpeg_destroy_compress( &_cInfo ); + fclose( _fp ); +} +inline unsigned int JPEGWriter::nextRow( const unsigned char* row ) +{ + JSAMPROW row_pointer[1]; + row_pointer[0] = ( unsigned char* )row; + (void) jpeg_write_scanlines( &_cInfo , row_pointer , 1 ); + return _currentRow++; +} + +inline unsigned int JPEGWriter::nextRows( const unsigned char* rows , unsigned int rowNum ) +{ + JSAMPROW* row_pointers = new JSAMPROW[ rowNum ]; + for( unsigned int r=0 ; r +#if defined( WIN32 ) || defined( _WIN64 ) +#pragma message( "[WARNING] Need to explicitly exclude VCOMP.lib" ) +#pragma comment( lib , "CHOLMOD_FULL.lib" ) +#endif // WIN32 || _WIN64 +#ifdef DLONG +typedef long long SOLVER_LONG; +#define CHOLMOD( name ) cholmod_l_ ## name +#else // !DLONG +typedef int SOLVER_LONG; +#define CHOLMOD( name ) cholmod_ ## name +#endif // DLONG +#elif defined(EIGEN_USE_MKL_ALL) +#pragma comment( lib , "mkl_core.lib" ) +#pragma comment( lib , "mkl_intel_lp64.lib" ) +#pragma comment( lib , "mkl_intel_thread.lib" ) +#pragma comment( lib , "mkl_blas95_lp64.lib" ) +#pragma comment( lib , "libiomp5md.lib" ) +#endif // USE_CHOLMOD + +#include "SparseMatrixInterface.h" + +inline double SquareNorm( const double* values , int dim ){ double norm2 = 0 ; for( int i=0 ; i inline double SquareNorm( const Type* values , int dim ){ double norm2 = 0 ; for( int i=0 ; i inline double SquareDifference( const Type* values1 , const Type* values2 , int dim ){ double norm2 = 0 ; for( int i=0 ; i +struct CGScratch +{ + Real *r , *d , *q; + CGScratch( void ) : r(NULL) , d(NULL) , q(NULL) , _dim(0){ ; } + CGScratch( int dim ) : r(NULL) , d(NULL) , q(NULL){ resize(dim); } + ~CGScratch( void ){ resize(0); } + void resize( int dim ) + { + if( dim!=_dim ) + { + if( r ) delete[] r ; r = NULL; + if( d ) delete[] d ; d = NULL; + if( q ) delete[] q ; q = NULL; + if( dim ) r = new Real[dim] , d = new Real[dim] , q = new Real[dim]; + _dim = dim; + } + } +protected: + int _dim; +}; +template< class Real > +struct PreconditionedCGScratch : public CGScratch< Real > +{ + Real *s; + PreconditionedCGScratch( void ) : CGScratch< Real >() , s(NULL){ ; } + PreconditionedCGScratch( int dim ) : CGScratch< Real >() { resize(dim); } + ~PreconditionedCGScratch( void ){ resize(0); } + void resize( int dim ) + { + if( dim!=CGScratch< Real >::_dim ) + { + if( s ) delete[] s; s = NULL; + if( dim ) s = new Real[dim]; + } + CGScratch< Real >::resize( dim ); + } +}; +template< class Real > +struct DiagonalPreconditioner +{ + Real* iDiagonal; + DiagonalPreconditioner( void ) : iDiagonal(NULL) , _dim(0){ ; } + ~DiagonalPreconditioner( void ){ if( iDiagonal ) delete[] iDiagonal ; iDiagonal = NULL; } + template< class MatrixRowIterator > + void set( const SparseMatrixInterface< Real , MatrixRowIterator >& M ) + { + if( _dim!=M.rows() ) + { + _dim = (int)M.rows(); + if( iDiagonal ) delete[] iDiagonal , iDiagonal = NULL; + if( _dim>0 ) iDiagonal = new Real[_dim]; + } + memset( iDiagonal , 0 , sizeof(Real)*_dim ); +#pragma omp parallel for + for( int i=0 ; iN==i ) iDiagonal[i] += iter->Value; + iDiagonal[i] = (Real)1./iDiagonal[i]; + } + } + void operator()( const Real* in , Real* out ) const + { +#pragma omp parallel for + for( int i=0 ; i<_dim ; i++ ) out[i] = in[i] * iDiagonal[i]; + } +protected: + int _dim; +}; + +template< class Real , class SPDOperator > +int SolveCG( SPDOperator& L , int iters , int dim , const Real* b , Real* x , CGScratch< Real >* scratch=NULL , double eps=1e-8 , int threads=1 , bool verbose=false ) +{ + eps *= eps; + Real *r , *d , *q; + if( scratch ) r = scratch->r , d = scratch->d , q = scratch->q; + else r = new Real[dim] , d = new Real[dim] , q = new Real[dim]; + memset( r , 0 , sizeof(Real)*dim ) , memset( d , 0 , sizeof(Real)*dim ) , memset( q , 0 , sizeof(Real)*dim ); + double delta_new = 0 , delta_0; + + L( x , r ); +#pragma omp parallel for num_threads( threads ) reduction( + : delta_new ) + for( int i=0 ; ieps*delta_0 ; ii++ ) + { + L( d , q ); + double dDotQ = 0; +#pragma omp parallel for num_threads( threads ) reduction( + : dDotQ ) + for( int i=0 ; i %g\n" , ii , SquareNorm( b , dim ) , SquareNorm( r , dim ) ); + } + if( !scratch ) delete[] r , delete[] d , delete[] q; + return ii; +} +template< class Real , class SPDOperator , class SPDPreconditioner > +int SolvePreconditionedCG( SPDOperator& L , SPDPreconditioner& Pinverse , int iters , int dim , const Real* b , Real* x , PreconditionedCGScratch< Real >* scratch=NULL , double eps=1e-8 , int threads=1 , bool verbose=false ) +{ + eps *= eps; + Real *r , *d , *q , *s; + if( scratch ) r = scratch->r , d = scratch->d , q = scratch->q , s = scratch->s; + else r = new Real[dim] , d = new Real[dim] , q = new Real[dim] , s = new Real[dim]; + memset( r , 0 , sizeof(Real)*dim ) , memset( d , 0 , sizeof(Real)*dim ) , memset( q , 0 , sizeof(Real)*dim ) , memset( s , 0 , sizeof(Real)*dim ); + double delta_new = 0 , delta_0; + + L( x , r ); +#pragma omp parallel for num_threads( threads ) + for( int i=0 ; ieps*delta_0 ; ii++ ) + { + L( d , q ); + double dDotQ = 0; +#pragma omp parallel for num_threads( threads ) reduction( + : dDotQ ) + for( int i=0 ; i %g\n" , ii , SquareNorm( b , dim ) , SquareNorm( r , dim ) ); + } + if( !scratch ) delete[] r , delete[] d , delete[] q , delete[] s; + return ii; +} + + +#ifdef USE_EIGEN +#define STORE_EIGEN_MATRIX +#ifdef EIGEN_USE_MKL_ALL +#include +#else // !EIGEN_USE_MKL_ALL +#include +#endif // EIGEN_USE_MKL_ALL + +template< class Real , class MatrixRowIterator > +struct EigenSolver +{ + virtual void update( const SparseMatrixInterface< Real , MatrixRowIterator >& M ) = 0; + virtual void solve( ConstPointer( Real ) b , Pointer( Real ) x ) = 0; + virtual size_t dimension( void ) const = 0; +}; + +template< class Real , class MatrixRowIterator > +class EigenSolverCholeskyLLt : public EigenSolver< Real , MatrixRowIterator > +{ +#ifdef EIGEN_USE_MKL_ALL + typedef Eigen::PardisoLLT< Eigen::SparseMatrix< double > > Eigen_Solver; + typedef Eigen::VectorXd Eigen_Vector; +#else // !EIGEN_USE_MKL_ALL + typedef Eigen::SimplicialLLT< Eigen::SparseMatrix< double > > Eigen_Solver; + typedef Eigen::VectorXd Eigen_Vector; +#endif // EIGEN_USE_MKL_ALL + Eigen_Solver _solver; + Eigen_Vector _eigenB; +#ifdef STORE_EIGEN_MATRIX + Eigen::SparseMatrix< double > _eigenM; +#endif // STORE_EIGEN_MATRIX +public: + EigenSolverCholeskyLLt( const SparseMatrixInterface< Real , MatrixRowIterator >& M , bool analyzeOnly=false ) + { +#ifdef STORE_EIGEN_MATRIX + _eigenM.resize( int( M.rows() ) , int( M.rows() ) ); +#else // !STORE_EIGEN_MATRIX + Eigen::SparseMatrix< double > eigenM( int( M.rows() ) , int( M.rows() ) ); +#endif // STORE_EIGEN_MATRIX + std::vector< Eigen::Triplet< double > > triplets; + triplets.reserve( M.entries() ); + for( int i=0 ; i( i , iter->N , iter->Value ) ); +#ifdef STORE_EIGEN_MATRIX + _eigenM.setFromTriplets( triplets.begin() , triplets.end() ); + _solver.analyzePattern( _eigenM ); +#else // !STORE_EIGEN_MATRIX + eigenM.setFromTriplets( triplets.begin() , triplets.end() ); + _solver.analyzePattern( eigenM ); +#endif // STORE_EIGEN_MATRIX + if( !analyzeOnly ) + { +#ifdef STORE_EIGEN_MATRIX + _solver.factorize( _eigenM ); +#else // !STORE_EIGEN_MATRIX + _solver.factorize( eigenM ); +#endif // STORE_EIGEN_MATRIX + if( _solver.info()!=Eigen::Success ) fprintf( stderr , "[ERROR] EigenSolverCholeskyLLt::EigenSolverCholeskyLLt Failed to factorize matrix\n" ) , exit(0); + } + _eigenB.resize( M.rows() ); + } + void update( const SparseMatrixInterface< Real , MatrixRowIterator >& M ) + { +#ifdef STORE_EIGEN_MATRIX +#pragma omp parallel for + for( int i=0 ; iN ) = iter->Value; + _solver.factorize( _eigenM ); +#else // !STORE_EIGEN_MATRIX + Eigen::SparseMatrix< double > eigenM( int( M.rows() ) , int( M.rows() ) ); + std::vector< Eigen::Triplet< double > > triplets; + triplets.reserve( M.entries() ); + for( int i=0 ; i( i , iter->N , iter->Value ) ); + eigenM.setFromTriplets( triplets.begin() , triplets.end() ); + _solver.factorize( eigenM ); +#endif // STORE_EIGEN_MATRIX + switch( _solver.info() ) + { + case Eigen::Success: break; + case Eigen::NumericalIssue: fprintf( stderr , "[ERROR] EigenSolverCholeskyLLt::update Failed to factorize matrix (numerical issue)\n" ) , exit(0); + case Eigen::NoConvergence: fprintf( stderr , "[ERROR] EigenSolverCholeskyLLt::update Failed to factorize matrix (no convergence)\n" ) , exit(0); + case Eigen::InvalidInput: fprintf( stderr , "[ERROR] EigenSolverCholeskyLLt::update Failed to factorize matrix (invalid input)\n" ) , exit(0); + default: fprintf( stderr , "[ERROR] EigenSolverCholeskyLLt::update Failed to factorize matrix\n" ) , exit(0); + } + } + void solve( ConstPointer( Real ) b , Pointer( Real ) x ) + { +#pragma omp parallel for + for( int i=0 ; i<_eigenB.size() ; i++ ) _eigenB[i] = b[i]; + Eigen_Vector eigenX = _solver.solve( _eigenB ); +#pragma omp parallel for + for( int i=0 ; i& M , ConstPointer( Real ) b , Pointer( Real ) x ){ EigenSolverCholeskyLLt solver( M ) ; solver.solve( b , x ); } +}; +template< class Real , class MatrixRowIterator > +class EigenSolverCholeskyLDLt : public EigenSolver< Real , MatrixRowIterator > +{ +#ifdef EIGEN_USE_MKL_ALL + typedef Eigen::PardisoLDLT< Eigen::SparseMatrix< double > > Eigen_Solver; + typedef Eigen::VectorXd Eigen_Vector; +#else // !EIGEN_USE_MKL_ALL + typedef Eigen::SimplicialLDLT< Eigen::SparseMatrix< double > > Eigen_Solver; + typedef Eigen::VectorXd Eigen_Vector; +#endif // EIGEN_USE_MKL_ALL + Eigen_Solver _solver; + Eigen_Vector _eigenB; +public: + EigenSolverCholeskyLDLt( const SparseMatrixInterface< Real , MatrixRowIterator >& M , bool analyzeOnly=false ) + { + Eigen::SparseMatrix< double > eigenM( int( M.rows() ) , int( M.rows() ) ); + std::vector< Eigen::Triplet > triplets; + triplets.reserve( M.entries() ); + for( int i=0 ; i( i , iter->N , iter->Value ) ); + eigenM.setFromTriplets( triplets.begin() , triplets.end() ); + _solver.analyzePattern( eigenM ); + if( !analyzeOnly ) + { + _solver.factorize( eigenM ); + if( _solver.info()!=Eigen::Success ) fprintf( stderr , "[ERROR] EigenSolverCholeskyLDLt::EigenSolverCholeskyLDLt Failed to factorize matrix\n" ) , exit(0); + } + _eigenB.resize( M.rows() ); + } + void update( const SparseMatrixInterface< Real , MatrixRowIterator >& M ) + { + Eigen::SparseMatrix< double > eigenM( int( M.rows() ) , int( M.rows() ) ); + std::vector< Eigen::Triplet > triplets; + triplets.reserve( M.entries() ); + for( int i=0 ; i( i , iter->N , iter->Value ) ); + eigenM.setFromTriplets( triplets.begin() , triplets.end() ); + _solver.factorize( eigenM ); + if( _solver.info()!=Eigen::Success ) fprintf( stderr , "[ERROR] EigenSolverCholeskyLDLt::update Failed to factorize matrix\n" ) , exit(0); + } + void solve( ConstPointer( Real ) b , Pointer( Real ) x ) + { +#pragma omp parallel for + for( int i=0 ; i<_eigenB.size() ; i++ ) _eigenB[i] = b[i]; + Eigen_Vector eigenX = _solver.solve( _eigenB ); +#pragma omp parallel for + for( int i=0 ; i& M , ConstPointer( Real ) b , Pointer( Real ) x ){ EigenSolverCholeskyLDLt solver( M ) ; solver.solve( b , x ); } +}; +template< class Real , class MatrixRowIterator > +class EigenSolverCG : public EigenSolver< Real , MatrixRowIterator > +{ +#if 1 +// Eigen::ConjugateGradient< Eigen::SparseMatrix< double > , Eigen::Lower , Eigen::IncompleteLUT< double > > _solver; + Eigen::ConjugateGradient< Eigen::SparseMatrix< double > > _solver; +#else + Eigen::BiCGSTAB< Eigen::SparseMatrix< double > > _solver; +#endif + Eigen::VectorXd _eigenB , _eigenX; + Eigen::SparseMatrix< double > _eigenM; +public: + EigenSolverCG( const SparseMatrixInterface< Real , MatrixRowIterator >& M , int iters=20 , double tolerance=0. ) + { + _eigenM.resize( (int)M.rows() , (int)M.rows() ); + std::vector< Eigen::Triplet< double > > triplets; + triplets.reserve( M.entries() ); + for( int i=0 ; i( i , iter->N , iter->Value ) ); + _eigenM.setFromTriplets( triplets.begin() , triplets.end() ); + _solver.compute( _eigenM ); + _solver.analyzePattern( _eigenM ); + if( _solver.info()!=Eigen::Success ) fprintf( stderr , "[ERROR] EigenSolverCG::EigenSolverCG Failed to factorize matrix\n" ) , exit(0); + _eigenB.resize( M.rows() ) , _eigenX.resize( M.rows() ); + _solver.setMaxIterations( iters ); + _solver.setTolerance( tolerance ); + } + void update( const SparseMatrixInterface< Real , MatrixRowIterator >& M ) + { +#pragma omp parallel for + for( int i=0 ; iN ) = iter->Value; + _solver.compute( _eigenM ); + _solver.analyzePattern( _eigenM ); + if( _solver.info()!=Eigen::Success ) fprintf( stderr , "[ERROR] EigenSolverCG::update Failed to factorize matrix\n" ) , exit(0); + } + + void setIters( int iters ){ _solver.setMaxIterations( iters ); } + void solve( ConstPointer( Real ) b , Pointer( Real ) x ) + { +#pragma omp parallel for + for( int i=0 ; i<_eigenB.size() ; i++ ) _eigenB[i] = b[i] , _eigenX[i] = x[i]; + _eigenX = _solver.solveWithGuess( _eigenB , _eigenX ); +#pragma omp parallel for + for( int i=0 ; i<_eigenX.size() ; i++ ) x[i] = _eigenX[i]; + } + size_t dimension( void ) const { return _eigenB.size(); } + static void Solve( const SparseMatrixInterface< Real , MatrixRowIterator >& M , const Real* b , Real* x , int iters ){ EigenSolverCG solver( M , iters ) ; solver.solve( b , x ); } +}; + +#endif // USE_EIGEN + +#ifdef USE_CHOLMOD +class CholmodSolver +{ + const static bool LOWER_TRIANGULAR = true; + int dim; + cholmod_factor* cholmod_L; + cholmod_dense* cholmod_b; + cholmod_sparse* cholmod_M; + std::vector< bool > flaggedValues; + template< class Real , class MatrixRowIterator > void _init( const SparseMatrixInterface< Real , MatrixRowIterator >& M ); +public: + static cholmod_common cholmod_C; + static bool cholmod_C_set; + + template< class Real , class MatrixRowIterator > + CholmodSolver( const SparseMatrixInterface< Real , MatrixRowIterator >& M , bool analyzeOnly=false ); + ~CholmodSolver( void ); + + template< class Real > void solve( ConstPointer( Real ) b , Pointer( Real ) x ); + template< class Real , class MatrixRowIterator > bool update( const SparseMatrixInterface< Real , MatrixRowIterator >& M ); + int nonZeros( void ) const; + +}; +bool CholmodSolver::cholmod_C_set = false; +cholmod_common CholmodSolver::cholmod_C; + +template< class Real , class MatrixRowIterator > CholmodSolver::CholmodSolver( const SparseMatrixInterface< Real , MatrixRowIterator >& M , bool analyzeOnly ){ _init( M ) ; if( !analyzeOnly ) update( M ); } +template< class Real , class MatrixRowIterator > +void CholmodSolver::_init( const SparseMatrixInterface< Real , MatrixRowIterator >& M ) +{ + { + if( !cholmod_C_set ) CHOLMOD(start)( &cholmod_C ); + cholmod_C_set = true; + } + dim = (int)M.rows(); + + int maxEntries; + if( LOWER_TRIANGULAR ) + { + maxEntries = (int)( ( M.entries()-M.rows() ) / 2 + M.rows() ); + cholmod_M = CHOLMOD(allocate_sparse)( dim , dim , maxEntries , 0 , 1 , -1 , CHOLMOD_REAL , &cholmod_C ); + } + else + { + maxEntries = (int)M.entries(); + cholmod_M = CHOLMOD(allocate_sparse)( dim , dim , maxEntries , 0 , 1 , 0 , CHOLMOD_REAL , &cholmod_C ); + } + cholmod_M->i = malloc( sizeof( SOLVER_LONG ) * maxEntries ); + cholmod_M->x = malloc( sizeof( double ) * maxEntries ); + + SOLVER_LONG *_p = (SOLVER_LONG*)cholmod_M->p; + SOLVER_LONG *_i = (SOLVER_LONG*)cholmod_M->i; + + int off = 0; + dim = 0; + + for( int i=0 ; iN>=i ) _i[off++] = iter->N; + } + _p[dim] = off; + + cholmod_L = CHOLMOD(analyze)( cholmod_M , &cholmod_C ); + cholmod_b = CHOLMOD(allocate_dense)( dim , 1 , dim , cholmod_M->xtype , &cholmod_C ); +} +template< class Real , class MatrixRowIterator > +bool CholmodSolver::update( const SparseMatrixInterface< Real , MatrixRowIterator >& M ) +{ + double *_x = (double*)cholmod_M->x; + int off = 0; + + SOLVER_LONG *_p = (SOLVER_LONG*)cholmod_M->p; +#pragma omp parallel for + for( int i=0 ; iN>=i ) _x[off++] = double( iter->Value ); + } + + cholmod_C.print = 0; + CHOLMOD(factorize)( cholmod_M , cholmod_L , &cholmod_C ); + if( cholmod_C.status==CHOLMOD_NOT_POSDEF ) + { + fprintf( stderr , "[WARNING] CholmodSolver::update: Matrix not positive-definite\n" ); + return false; + } + else if( cholmod_C.status==CHOLMOD_OUT_OF_MEMORY ) + { + fprintf( stderr , "[WARNING] CholmodSolver::update: CHOLMOD ran out of memory\n" ); + return false; + } + else if( cholmod_C.status!=CHOLMOD_OK ) + { + fprintf( stderr , "[WARNING] CholmodSolver::update: CHOLMOD status not OK: %d\n" , cholmod_C.status ); + return false; + } + return true; +} +CholmodSolver::~CholmodSolver( void ) +{ + if( cholmod_L ) CHOLMOD(free_factor)( &cholmod_L , &cholmod_C ) , cholmod_L = NULL; + if( cholmod_b ) CHOLMOD(free_dense )( &cholmod_b , &cholmod_C ) , cholmod_b = NULL; + if( cholmod_M ) CHOLMOD(free_sparse)( &cholmod_M , &cholmod_C ) , cholmod_M = NULL; +} + +template< class Real > +void CholmodSolver::solve( ConstPointer( Real ) b , Pointer( Real ) x ) +{ + double* _b = (double*)cholmod_b->x; + for( int i=0 ; ix; + for( int i=0 ; ixtype != CHOLMOD_PATTERN && !(cholmod_L->is_super ) ) for( int i=0 ; in ; i++ ) nz += ((SOLVER_LONG*)cholmod_L->nz)[i]; + bool examine_super = false; + if( cholmod_L->xtype != CHOLMOD_PATTERN ) examine_super = true ; + else examine_super = ( ((int*)cholmod_L->s)[0] != (-1)); + if( examine_super ) + { + /* check and print each supernode */ + for (int s = 0 ; s < cholmod_L->nsuper ; s++) + { + int k1 = ((int*)cholmod_L->super) [s] ; + int k2 = ((int*)cholmod_L->super) [s+1] ; + int psi = ((int*)cholmod_L->pi)[s] ; + int psend = ((int*)cholmod_L->pi)[s+1] ; + int nsrow = psend - psi ; + int nscol = k2 - k1 ; + nz += nscol * nsrow - (nscol*nscol - nscol)/2 ; + } + } + return (int)nz; +} +#endif // USE_CHOLMOD +#endif // LINEAR_SOLVERS_INCLUDE \ No newline at end of file diff --git a/Src/MAT.h b/modules/PoissonRecon/include/Mesh/PoissonRecon/MAT.h similarity index 52% rename from Src/MAT.h rename to modules/PoissonRecon/include/Mesh/PoissonRecon/MAT.h index c090450d..d823f474 100644 --- a/Src/MAT.h +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/MAT.h @@ -27,22 +27,36 @@ DAMAGE. */ #ifndef MAT_INCLUDED #define MAT_INCLUDED -#include "Geometry.h" +#include "Mesh/PoissonRecon/Geometry.h" +#include "Mesh/PoissonRecon/Array.h" -template -class MinimalAreaTriangulation +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 { - Real* bestTriangulation; - int* midPoint; - Real GetArea(const size_t& i,const size_t& j,const std::vector >& vertices); - void GetTriangulation(const size_t& i,const size_t& j,const std::vector >& vertices,std::vector& triangles); -public: - MinimalAreaTriangulation(void); - ~MinimalAreaTriangulation(void); - Real GetArea(const std::vector >& vertices); - void GetTriangulation(const std::vector >& vertices,std::vector& triangles); -}; + 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; -#include "MAT.inl" + _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 "Mesh/PoissonRecon/MAT.inl" #endif // MAT_INCLUDED diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/MAT.inl b/modules/PoissonRecon/include/Mesh/PoissonRecon/MAT.inl new file mode 100644 index 00000000..83b49799 --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/MAT.inl @@ -0,0 +1,172 @@ +/* +Copyright (c) 2007, Michael Kazhdan +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +////////////////////////////// +// MinimalAreaTriangulation // +////////////////////////////// +template< typename Index , class Real , unsigned int Dim > +_MinimalAreaTriangulation< Index , Real , Dim >::_MinimalAreaTriangulation( ConstPointer( Point< Real , Dim > ) vertices , size_t vCount ) : _vertices( vertices ) , _vCount( vCount ) +{ + _bestTriangulation = NullPointer( Real ); + _midpoint = NullPointer( Index ); +} +template< typename Index , class Real , unsigned int Dim > +_MinimalAreaTriangulation< Index , Real , Dim >::~_MinimalAreaTriangulation( void ) +{ + FreePointer( _bestTriangulation ); + FreePointer( _midpoint ); +} +template< typename Index , class Real , unsigned int Dim > +std::vector< TriangleIndex< Index > > _MinimalAreaTriangulation< Index , Real , Dim >::getTriangulation( void ) +{ + std::vector< TriangleIndex< Index > > triangles; + if( _vCount==3 ) + { + triangles.resize(1); + triangles[0].idx[0] = 0; + triangles[0].idx[1] = 1; + triangles[0].idx[2] = 2; + return triangles; + } + else if( _vCount==4 ) + { + TriangleIndex< Index > tIndex[2][2]; + Real area[] = { 0 , 0 }; + + triangles.resize(2); + + tIndex[0][0].idx[0]=0; + tIndex[0][0].idx[1]=1; + tIndex[0][0].idx[2]=2; + tIndex[0][1].idx[0]=2; + tIndex[0][1].idx[1]=3; + tIndex[0][1].idx[2]=0; + + tIndex[1][0].idx[0]=0; + tIndex[1][0].idx[1]=1; + tIndex[1][0].idx[2]=3; + tIndex[1][1].idx[0]=3; + tIndex[1][1].idx[1]=1; + tIndex[1][1].idx[2]=2; + + Point< Real , Dim > p1 , p2; + for( int i=0 ; i<2 ; i++ ) for( int j=0 ; j<2 ; j++ ) area[i] = SquareArea( _vertices[ tIndex[i][j].idx[0] ] , _vertices[ tIndex[i][j].idx[1] ] , _vertices[ tIndex[i][j].idx[2] ] ); + if( area[0]>area[1] ) triangles[0] = tIndex[1][0] , triangles[1] = tIndex[1][1]; + else triangles[0] = tIndex[0][0] , triangles[1] = tIndex[0][1]; + return triangles; + } + _set(); + _addTriangles( 1 , 0 , triangles ); + return triangles; +} +template< typename Index , class Real , unsigned int Dim > +void _MinimalAreaTriangulation< Index , Real , Dim >::_set( void ) +{ + FreePointer( _bestTriangulation ); + FreePointer( _midpoint ); + _bestTriangulation = AllocPointer< Real >( _vCount * _vCount ); + _midpoint = AllocPointer< Index >( _vCount * _vCount ); + for( int i=0 ; i<_vCount*_vCount ; i++ ) _bestTriangulation[i] = -1 , _midpoint[i] = -1; + _subPolygonArea( 1 , 0 ); +} + +template< typename Index , class Real , unsigned int Dim > +Index _MinimalAreaTriangulation< Index , Real , Dim >::_subPolygonIndex( Index i , Index j ) const { return (Index)( i*_vCount+j ); } + +template< typename Index , class Real , unsigned int Dim > +void _MinimalAreaTriangulation< Index , Real , Dim >::_addTriangles( Index i , Index j , std::vector< TriangleIndex< Index > >& triangles ) const +{ + TriangleIndex< Index > tIndex; + if( j +Real _MinimalAreaTriangulation< Index , Real , Dim >::_subPolygonArea( Index i , Index j ) +{ + Index idx = _subPolygonIndex( i , j ); + if( _midpoint[idx]!=-1 ) return _bestTriangulation[idx]; + Real a = FLT_MAX , temp; + if( j=0 ) + { + temp += _bestTriangulation[idx1]; + // If the partial area is already too large, terminate + if( temp>a ) continue; // Terminate early + // Otherwise, compute the total area + temp += _subPolygonArea( r%_vCount , j%_vCount ); + } + else + { + // Otherwise, compute it now + temp += _subPolygonArea( r%_vCount , j%_vCount ); + // If the partial area is already too large, terminate + if( temp>a ) continue; + // Otherwise, compute the total area + temp += _subPolygonArea( i , r%_vCount ); + } + + if( temp +#include +#include "Mesh/PoissonRecon/Geometry.h" + +#include "Mesh/PoissonRecon/Window.h" + +namespace HyperCube +{ + enum Direction{ BACK , CROSS , FRONT }; + inline Direction Opposite( Direction dir ){ return dir==BACK ? FRONT : ( dir==FRONT ? BACK : CROSS ); } + + // 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 ); + + // 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 ); + + 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 >::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 , 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 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; + }; + + // 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 ); } + + 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< 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 ) + { + 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 ) + { + 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 ) + { + 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 _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 ) + { + 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 > + 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 >::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 > + 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 > 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 > +#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==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; } +#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; } +#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 ); } + + 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 ) + { + 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 > +#ifdef _MSC_VER + 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 >(); } +#endif // _MSC_VER + 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 ) +#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 ) +#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 > +#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 ) +#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 ) +#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 ); + } + + 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< 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< 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 > + 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; } +#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; } +#endif // _MSC_VER + 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 ) +#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 ) +#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 > +#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 ) +#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 ) +#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 ); + } + + + ///////////////////// + // 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 ) + { + for( int j=0 ; j<2 ; j++ ) isoIndices[i+j] = edges[mcIndex][i+j]; + nEdges++; + } + return nEdges; + } +} + +#endif //MARCHING_CUBES_INCLUDED diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/MyMiscellany.h b/modules/PoissonRecon/include/Mesh/PoissonRecon/MyMiscellany.h new file mode 100644 index 00000000..1f83d9a5 --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/MyMiscellany.h @@ -0,0 +1,930 @@ +/* +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_MISCELLANY_INCLUDED +#define MY_MISCELLANY_INCLUDED + +#include "Mesh/PoissonRecon/PreProcessor.h" + +////////////////// +// OpenMP Stuff // +////////////////// +#ifdef _OPENMP +#include +#endif // _OPENMP + +//////////////// +// Time Stuff // +//////////////// +#include +#include +#ifndef WIN32 +#include +#endif // WIN32 + +inline double Time( void ) +{ +#ifdef WIN32 + struct _timeb t; + _ftime( &t ); + return double( t.time ) + double( t.millitm ) / 1000.0; +#else // WIN32 + struct timeval t; + gettimeofday( &t , NULL ); + return t.tv_sec + double( t.tv_usec ) / 1000000; +#endif // WIN32 +} + +#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(); } +protected: + std::clock_t _startCPUClock; + std::chrono::time_point< std::chrono::system_clock > _startWallClock; +}; + +/////////////// +// I/O Stuff // +/////////////// +#if defined( _WIN32 ) || defined( _WIN64 ) +const char FileSeparator = '\\'; +#else // !_WIN +const char FileSeparator = '/'; +#endif // _WIN + +#ifndef SetTempDirectory +#if defined( _WIN32 ) || defined( _WIN64 ) +#define SetTempDirectory( tempDir , sz ) GetTempPath( (sz) , (tempDir) ) +#else // !_WIN32 && !_WIN64 +#define SetTempDirectory( tempDir , sz ) if( std::getenv( "TMPDIR" ) ) strcpy( tempDir , std::getenv( "TMPDIR" ) ); +#endif // _WIN32 || _WIN64 +#endif // !SetTempDirectory + +#include +#include +#include +struct MessageWriter +{ + 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 ) ); + } +}; + +///////////////////////////////////// +// 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 ) + { + 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( 0 ); + } +} +#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 + +#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); + + // 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 ); + + char ** messages = backtrace_symbols( trace , size ); + for( int i=1 ; i< size && messages!=NULL ; ++i ) + { + char *mangled_name=0 , *offset_begin=0 , *offset_end=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 ( *p=='(' ) mangled_name = p; + else if( *p=='+' ) offset_begin = p; + else if( *p==')' ) + { + offset_end = p; + break; + } + } + + // if the line could be processed, attempt to demangle the symbol + if( mangled_name && offset_begin && offset_end && mangled_name bool SetAtomic( volatile Value *value , Value newValue , Value oldValue ); +template< typename Data > void AddAtomic( Data& a , Data b ); + +//////////////////// +// 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 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 ) + { + 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; +}; + +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 = +{ +#ifdef _OPENMP + "open mp" , +#endif // _OPENMP + "thread pool" , + "async" , + "none" +}; +const std::vector< std::string >ThreadPool::ScheduleNames = { "static" , "dynamic" }; + +#include + +#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; +#else // !_WIN32 && !_WIN64 + uint32_t &_oldValue = *(uint32_t *)&oldValue; + uint32_t &_newValue = *(uint32_t *)&newValue; +// return __sync_bool_compare_and_swap( (uint32_t *)value , _oldValue , _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 &_oldValue = *(uint64_t *)&oldValue; + uint64_t &_newValue = *(uint64_t *)&newValue; +// return __sync_bool_compare_and_swap ( (uint64_t *)&value , _oldValue , _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( Number &a , Number b ) +{ +#if 0 + Number current = a; + Number sum = current+b; + while( !SetAtomic32( &a , sum , current ) ) current = a , sum = a+b; +#else +#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; +#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; +#endif // _WIN32 || _WIN64 +#endif +} + +template< typename Number > +void AddAtomic64( Number &a , Number b ) +{ +#if 1 + 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; +#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; +#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; + } +} + +///////////////////////// +// 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 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() ); + + 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 ); +} +#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 + +#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( ) +{ +#if defined(_WIN32) + /* 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) ) + { + close( fd ); + return (size_t)0L; /* Can't read? */ + } + close( fd ); + 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 ); +#if defined(__APPLE__) && defined(__MACH__) + return (size_t)rusage.ru_maxrss; +#else + return (size_t)(rusage.ru_maxrss * 1024L); +#endif + +#else + /* 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( ) +{ +#if defined(_WIN32) || defined( _WIN64 ) + /* 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; + +#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 ) + { + fclose( fp ); + return (size_t)0L; /* Can't read? */ + } + fclose( fp ); + return (size_t)rss * (size_t)sysconf( _SC_PAGESIZE); + +#else + /* AIX, BSD, Solaris, and Unknown OS ------------------------ */ + return (size_t)0L; /* Unsupported. */ +#endif +} +#endif // MY_MISCELLANY_INCLUDED diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/PNG.h b/modules/PoissonRecon/include/Mesh/PoissonRecon/PNG.h new file mode 100644 index 00000000..a816aa92 --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/PNG.h @@ -0,0 +1,35 @@ +#ifndef PNG_INCLUDED +#define PNG_INCLUDED + +#include "png.h" + +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 "Mesh/PoissonRecon/PNG.inl" +#endif //PNG_INCLUDED diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/PNG.inl b/modules/PoissonRecon/include/Mesh/PoissonRecon/PNG.inl new file mode 100644 index 00000000..e36f684a --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/PNG.inl @@ -0,0 +1,151 @@ +#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 ) +{ + _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" ); + _info_ptr = png_create_info_struct( _png_ptr ); + if( !_info_ptr ) 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" ); + + + _fp = fopen( fileName , "rb" ); + if( !_fp ) ERROR_OUT( "Failed to open file for reading: " , fileName ); + png_init_io( _png_ptr , _fp ); + + png_read_info( _png_ptr, _info_ptr ); + + width = png_get_image_width( _png_ptr , _info_ptr ); + height = png_get_image_height( _png_ptr, _info_ptr ); + channels = png_get_channels( _png_ptr , _info_ptr ); + int bit_depth=png_get_bit_depth( _png_ptr , _info_ptr ); + int color_type = png_get_color_type( _png_ptr , _info_ptr ); + if( bit_depth==16 ) + { + 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" ); + _scratchRow = NULL; + } + if( color_type==PNG_COLOR_TYPE_PALETTE ) png_set_expand( _png_ptr ) , printf( "Expanding PNG color pallette\n" ); + + { + long int a = 1; + int swap = (*((unsigned char *) &a) == 1); + if( swap ) png_set_swap( _png_ptr ); + } +} +inline unsigned int PNGReader::nextRow( unsigned char* row ) +{ + if( _scratchRow ) + { + int width = png_get_image_width( _png_ptr , _info_ptr ); + int channels = png_get_channels( _png_ptr , _info_ptr ); + + png_read_row( _png_ptr , (png_bytep)_scratchRow , NULL ); +#pragma omp parallel for + for( int i=0 ; i +#include "Mesh/PoissonRecon/Polynomial.h" + +#include "Mesh/PoissonRecon/Array.h" + +template +class StartingPolynomial +{ + public: + Polynomial p; + double start; + + template + StartingPolynomial operator*( + const StartingPolynomial& 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 +class PPolynomial +{ + public: + size_t polyCount; + Pointer(StartingPolynomial) polys; + + PPolynomial(void); + PPolynomial(const PPolynomial& p); + ~PPolynomial(void); + + PPolynomial& operator=(const PPolynomial& p); + + int size(void) const; + + void set(size_t size); + // Note: this method will sort the elements in sps + void set(Pointer(StartingPolynomial) sps, int count); + void reset(size_t newSize); + PPolynomial& compress(double delta = 0.); + + double operator()(double t) const; + double integral(double tMin, double tMax) const; + double Integral(void) const; + + template + PPolynomial& operator=(const PPolynomial& p); + + PPolynomial operator+(const PPolynomial& p) const; + PPolynomial operator-(const PPolynomial& p) const; + + template + PPolynomial operator*(const Polynomial& p) const; + template + PPolynomial operator*(const PPolynomial& p) const; + + PPolynomial& operator+=(double s); + PPolynomial& operator-=(double s); + PPolynomial& operator*=(double s); + PPolynomial& operator/=(double s); + PPolynomial operator+(double s) const; + PPolynomial operator-(double s) const; + PPolynomial operator*(double s) const; + PPolynomial operator/(double s) const; + + PPolynomial& addScaled(const PPolynomial& poly, double scale); + + PPolynomial scale(double s) const; + PPolynomial shift(double t) const; + PPolynomial reflect(double r = 0.) const; + + PPolynomial derivative(void) const; + PPolynomial integral(void) const; + + void getSolutions(double c, + std::vector& roots, + double EPS, + double min = -DBL_MAX, + double max = DBL_MAX) const; + + void printnl(void) const; + + PPolynomial MovingAverage(double radius) const; + static PPolynomial BSpline(double radius = 0.5); + + void write(FILE* fp, int samples, double min, double max) const; +}; +#include "Mesh/PoissonRecon/PPolynomial.inl" +#endif // P_POLYNOMIAL_INCLUDED diff --git a/Src/PPolynomial.inl b/modules/PoissonRecon/include/Mesh/PoissonRecon/PPolynomial.inl similarity index 99% rename from Src/PPolynomial.inl rename to modules/PoissonRecon/include/Mesh/PoissonRecon/PPolynomial.inl index a78ae580..d40f2d8c 100644 --- a/Src/PPolynomial.inl +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/PPolynomial.inl @@ -26,7 +26,7 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ -#include "Factor.h" +#include "Mesh/PoissonRecon/Factor.h" //////////////////////// // StartingPolynomial // @@ -172,7 +172,7 @@ template double PPolynomial::operator ()( double t ) const { double v=0; - for( int i=0 ; ipolys[i].start ; i++ ) v += polys[i].p(t); + for( int i=0 ; ipolys[i].start ; i++ ) v+=polys[i].p(t); return v; } diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/Ply.h b/modules/PoissonRecon/include/Mesh/PoissonRecon/Ply.h new file mode 100644 index 00000000..75532df3 --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/Ply.h @@ -0,0 +1,576 @@ +/* + +Header for PLY polygon files. + +- Greg Turk, March 1994 + +A PLY file contains a single polygonal _object_. + +An object is composed of lists of _elements_. Typical elements are +vertices, faces, edges and materials. + +Each type of element for a given object has one or more _properties_ +associated with the element type. For instance, a vertex element may +have as properties three floating-point values x,y,z and three unsigned +chars for red, green and blue. + +--------------------------------------------------------------- + +Copyright (c) 1994 The Board of Trustees of The Leland Stanford +Junior University. All rights reserved. + +Permission to use, copy, modify and distribute this software and its +documentation for any purpose is hereby granted without fee, provided +that the above copyright notice and this permission notice appear in +all copies of this software and that you do not sell the software. + +THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, +EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY +WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +*/ + +#ifndef PLY_INCLUDED +#define PLY_INCLUDED + +#include +#include +#include "Mesh/PoissonRecon/PlyFile.h" +#include "Mesh/PoissonRecon/Geometry.h" + +template< class Real > int PLYType( void ); +template<> inline int PLYType< int >( void ){ return PLY_INT ; } +template<> inline int PLYType< char >( void ){ return PLY_CHAR ; } +template<> inline int PLYType< unsigned char >( void ){ return PLY_UCHAR ; } +template<> inline int PLYType< float >( void ){ return PLY_FLOAT ; } +template<> inline int PLYType< double >( void ){ return PLY_DOUBLE; } +template< class Real > inline int PLYType( void ) +{ + ERROR_OUT( "Unrecognized type" ); + return -1; +} + +template< typename Integer > struct PLYTraits{ static const std::string name; }; +template<> const std::string PLYTraits< int >::name="int"; +template<> const std::string PLYTraits< unsigned int >::name="unsigned int"; +template<> const std::string PLYTraits< long >::name="long"; +template<> const std::string PLYTraits< unsigned long >::name="unsigned long"; +template<> const std::string PLYTraits< long long >::name="long long"; +template<> const std::string PLYTraits< unsigned long long >::name="unsigned long long"; + +template< typename Index > +struct PlyFace +{ + unsigned int nr_vertices; + Index *vertices; + int segment; + + static PlyProperty face_props[]; +}; +template<> +PlyProperty PlyFace< int >::face_props[] = { PlyProperty( "vertex_indices" , PLY_INT , PLY_INT , offsetof( PlyFace , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( PlyFace , nr_vertices ) ) }; +template<> +PlyProperty PlyFace< unsigned int >::face_props[] = { PlyProperty( "vertex_indices" , PLY_UINT , PLY_UINT , offsetof( PlyFace , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( PlyFace , nr_vertices ) ) }; +template<> +PlyProperty PlyFace< long long >::face_props[] = { PlyProperty( "vertex_indices" , PLY_LONGLONG , PLY_LONGLONG , offsetof( PlyFace , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( PlyFace , nr_vertices ) ) }; +template<> +PlyProperty PlyFace< unsigned long long >::face_props[] = { PlyProperty( "vertex_indices" , PLY_ULONGLONG , PLY_ULONGLONG , offsetof( PlyFace , vertices ) , 1 , PLY_INT , PLY_INT , offsetof( PlyFace , nr_vertices ) ) }; + +struct RGBColor +{ + unsigned char c[3]; + unsigned char& operator[]( int idx ) { return c[idx]; } + unsigned char operator[]( int idx ) const { return c[idx]; } + RGBColor( void ){ c[0] = c[1] = c[2] = 0; } + RGBColor( const RGBColor& rgb ){ memcpy( c , rgb.c , sizeof(unsigned char) * 3 ); } + RGBColor& operator = ( const RGBColor& rgb ){ memcpy( c , rgb.c , sizeof(unsigned char) * 3 ) ; return *this; } +}; + +/////////////// +// PlyVertex // +/////////////// +template< typename _Real , int Dim , typename _RealOnDisk=float > +class PlyVertex +{ +public: + typedef _Real Real; + + PlyVertex& operator += ( const PlyVertex& p ){ point += p.point ; return *this; } + PlyVertex& operator -= ( const PlyVertex& p ){ point -= p.point ; return *this; } + PlyVertex& operator *= ( Real s ) { point *= s ; return *this; } + PlyVertex& operator /= ( Real s ) { point /= s ; return *this; } + PlyVertex operator + ( const PlyVertex& p ) const { return PlyVertex( point + p.point ); } + PlyVertex operator - ( const PlyVertex& p ) const { return PlyVertex( point - p.point ); } + PlyVertex operator * ( Real s ) const { return PlyVertex( point * s ); } + PlyVertex operator / ( Real s ) const { return PlyVertex( point / s ); } + + const static int PlyReadNum = Dim; + const static int PlyWriteNum = Dim; + + static const PlyProperty* PlyReadProperties( void ){ return _PlyProperties; } + static const PlyProperty* PlyWriteProperties( void ){ return _PlyProperties; } + + Point< Real , Dim > point; + PlyVertex( void ) {} + PlyVertex( Point< Real , Dim > p ) : point(p) { } + + struct Transform + { + Transform( void ){} + Transform( const XForm< Real , Dim+1 >& xForm ) : _pointXForm(xForm) { } + PlyVertex operator() ( const PlyVertex& p ) const + { + PlyVertex _p; + _p.point = _pointXForm * p.point; + return _p; + } + protected: + XForm< Real , Dim+1 > _pointXForm; + }; + +protected: + static const PlyProperty _PlyProperties[]; +}; + +template<> +const PlyProperty PlyVertex< float , 2 , float >::_PlyProperties[] = +{ + PlyProperty( "x" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "y" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 ) , +}; +template<> +const PlyProperty PlyVertex< double , 2 , float >::_PlyProperties[] = +{ + PlyProperty( "x" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "y" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 ) , +}; +template<> +const PlyProperty PlyVertex< float , 2 , double >::_PlyProperties[] = +{ + PlyProperty( "x" , PLY_DOUBLE , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "y" , PLY_DOUBLE , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 ) , +}; +template<> +const PlyProperty PlyVertex< double , 2 , double >::_PlyProperties[] = +{ + PlyProperty( "x" , PLY_DOUBLE , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "y" , PLY_DOUBLE , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 ) , +}; + +template<> +const PlyProperty PlyVertex< float , 3 , float >::_PlyProperties[] = +{ + PlyProperty( "x" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "y" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "z" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 ) , +}; +template<> +const PlyProperty PlyVertex< double , 3 , float >::_PlyProperties[] = +{ + PlyProperty( "x" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "y" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "z" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 ) , +}; +template<> +const PlyProperty PlyVertex< float , 3 , double >::_PlyProperties[] = +{ + PlyProperty( "x" , PLY_DOUBLE , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "y" , PLY_DOUBLE , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "z" , PLY_DOUBLE , PLY_FLOAT , int( offsetof( PlyVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 ) , +}; +template<> +const PlyProperty PlyVertex< double , 3 , double >::_PlyProperties[] = +{ + PlyProperty( "x" , PLY_DOUBLE , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[0] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "y" , PLY_DOUBLE , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[1] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "z" , PLY_DOUBLE , PLY_DOUBLE , int( offsetof( PlyVertex , point.coords[2] ) ) , 0 , 0 , 0 , 0 ) , +}; + +/////////////////////// +// PlyVertexWithData // +/////////////////////// +template< typename _Real , int Dim , typename Data , typename _RealOnDisk=float > +class PlyVertexWithData +{ +public: + typedef _Real Real; + + PlyVertexWithData& operator += ( const PlyVertexWithData& p ){ point += p.point , data += p.data ; return *this; } + PlyVertexWithData& operator -= ( const PlyVertexWithData& p ){ point -= p.point , data -= p.data ; return *this; } + PlyVertexWithData& operator *= ( Real s ) { point *= s , data *= s ; return *this; } + PlyVertexWithData& operator /= ( Real s ) { point /= s , data /= s ; return *this; } + PlyVertexWithData operator + ( const PlyVertexWithData& p ) const { return PlyVertexWithData( point + p.point , data + p.data ); } + PlyVertexWithData operator - ( const PlyVertexWithData& p ) const { return PlyVertexWithData( point - p.point , data - p.data ); } + PlyVertexWithData operator * ( Real s ) const { return PlyVertexWithData( point * s , data * s ); } + PlyVertexWithData operator / ( Real s ) const { return PlyVertexWithData( point / s , data / s ); } + + const static int PlyReadNum = Data::PlyReadNum + Dim; + const static int PlyWriteNum = Data::PlyWriteNum + Dim; + + static const PlyProperty* PlyReadProperties( void ){ _SetReadProperties() ; return _PlyReadProperties; } + static const PlyProperty* PlyWriteProperties( void ){ _SetWriteProperties() ; return _PlyWriteProperties; } + + + Point< Real , Dim > point; + Data data; + PlyVertexWithData( void ) {} + PlyVertexWithData( Point< Real , Dim > p , Data d ) : point(p) , data(d) { } + + struct Transform + { + Transform( void ){} + Transform( const XForm< Real , Dim+1 >& xForm ) : _pointXForm(xForm) , _dataXForm(xForm) { } + PlyVertexWithData operator() ( const PlyVertexWithData& p ) const + { + PlyVertexWithData _p; + _p.point = _pointXForm * p.point; + _p.data = _dataXForm( p.data ); + return _p; + } + protected: + XForm< Real , Dim+1 > _pointXForm; + typename Data::Transform _dataXForm; + }; + +protected: + static void _SetReadProperties( void ); + static void _SetWriteProperties( void ); + static PlyProperty _PlyReadProperties[]; + static PlyProperty _PlyWriteProperties[]; +}; +template< typename Real , int Dim , typename Data , typename RealOnDisk > PlyProperty PlyVertexWithData< Real , Dim , Data , RealOnDisk >::_PlyReadProperties[ PlyReadNum ]; +template< typename Real , int Dim , typename Data , typename RealOnDisk > PlyProperty PlyVertexWithData< Real , Dim , Data , RealOnDisk >::_PlyWriteProperties[ PlyWriteNum ]; +template< typename Real , int Dim , typename Data , typename RealOnDisk > +void PlyVertexWithData< Real , Dim , Data , RealOnDisk >::_SetReadProperties( void ) +{ + { + const PlyProperty * ReadProps = PlyVertex< Real , Dim , RealOnDisk >::PlyReadProperties(); + for( int d=0 ; d::PlyReadNum ; d++ ) _PlyReadProperties[d] = ReadProps[d]; + } + { + const PlyProperty * ReadProps = Data::PlyReadProperties(); + for( int d=0 ; d::PlyReadNum ] = ReadProps[d]; + _PlyReadProperties[d+PlyVertex< Real , Dim , RealOnDisk >::PlyReadNum ].offset += (int)offsetof( PlyVertexWithData , data ); + } + } +} +template< typename Real , int Dim , typename Data , typename RealOnDisk > +void PlyVertexWithData< Real , Dim , Data , RealOnDisk >::_SetWriteProperties( void ) +{ + { + const PlyProperty * WriteProps = PlyVertex< Real , Dim , RealOnDisk >::PlyWriteProperties(); + for( int d=0 ; d::PlyWriteNum ; d++ ) _PlyWriteProperties[d] = WriteProps[d]; + } + { + const PlyProperty * WriteProps = Data::PlyWriteProperties(); + for( int d=0 ; d::PlyWriteNum ] = WriteProps[d]; + _PlyWriteProperties[d+PlyVertex< Real , Dim , RealOnDisk >::PlyWriteNum ].offset += (int)offsetof( PlyVertexWithData , data ); + } + } +} + +template< class Vertex , typename Index , class Real , int Dim , typename OutputIndex=int > +int PlyWritePolygons( const char* fileName , CoredMeshData< Vertex , Index >* mesh , int file_type , const Point< float , Dim >& translate , float scale , const std::vector< std::string >& comments , XForm< Real , Dim+1 > xForm=XForm< Real , Dim+1 >::Identity() ); + +template< class Vertex , typename Index , class Real , int Dim , typename OutputIndex=int > +int PlyWritePolygons( const char* fileName , CoredMeshData< Vertex , Index >* mesh , int file_type , const std::vector< std::string >& comments , XForm< Real , Dim+1 > xForm=XForm< Real , Dim+1 >::Identity() ); + +inline bool PlyReadHeader( char* fileName , const PlyProperty* properties , int propertyNum , bool* readFlags , int& file_type ) +{ + std::vector< std::string > elist; + float version; + + PlyFile *ply = PlyFile::Read( fileName , elist , file_type , version ); + if( !ply ) return false; + + for( int i=0 ; iget_property( elist[i].c_str() , &properties[j] )!=0; + + delete ply; + return true; +} +inline bool PlyReadHeader( char* fileName , const PlyProperty* properties , int propertyNum , bool* readFlags ) +{ + int file_type; + return PlyReadHeader( fileName , properties , propertyNum , readFlags , file_type ); +} + + +template< class Vertex , typename Index > +int PlyReadPolygons( const char* fileName, + std::vector< Vertex >& vertices , std::vector >& polygons , + const PlyProperty* properties , int propertyNum , + int& file_type , + std::vector< std::string > &comments , bool* readFlags=NULL ); + +template< class Vertex , typename Index > +int PlyWritePolygons( const char* fileName , + const std::vector< Vertex > &vertices , const std::vector< std::vector< Index > > &polygons , + const PlyProperty* properties , int propertyNum , + int file_type , + const std::vector< std::string > &comments ); + +template< class Vertex , typename Index > +int PlyWritePolygons( const char* fileName , + const std::vector< Vertex > &vertices , const std::vector< std::vector< Index > > &polygons , + const PlyProperty *properties , int propertyNum , + int file_type , + const std::vector< std::string > &comments ) +{ + size_t nr_vertices = vertices.size(); + size_t nr_faces = polygons.size(); + 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){return 0;} + + // + // describe vertex and face properties + // + ply->element_count( "vertex", nr_vertices ); + for( int i=0 ; idescribe_property( "vertex" , &properties[i] ); + ply->element_count( "face" , nr_faces ); + ply->describe_property( "face" , PlyFace< Index >::face_props ); + + // Write in the comments + for( int i=0 ; iput_comment( comments[i] ); + ply->header_complete(); + + // write vertices + ply->put_element_setup( elem_names[0] ); + for( size_t i=0 ; iput_element( (void *)&vertices[i] ); + + // write faces + PlyFace< Index > ply_face; + int maxFaceVerts=3; + ply_face.nr_vertices = 3; + ply_face.vertices = new Index[3]; + + ply->put_element_setup( elem_names[1] ); + for( size_t i=0 ; imaxFaceVerts ) + { + delete[] ply_face.vertices; + maxFaceVerts = (int)polygons[i].size(); + ply_face.vertices=new Index[ maxFaceVerts ]; + } + ply_face.nr_vertices = (int)polygons[i].size(); + for( size_t j=0 ; jput_element( (void *)&ply_face ); + } + + delete[] ply_face.vertices; + delete ply; + + return 1; +} + +template< class Vertex , typename Index > +int PlyReadPolygons +( + const char *fileName , + std::vector< Vertex > &vertices , + std::vector< std::vector< Index > > &polygons , + const PlyProperty *properties , + int propertyNum , + int &file_type , + std::vector< std::string > &comments , + bool *readFlags +) +{ + std::vector< std::string > elist = { std::string( "vertex" ) , std::string( "face" ) }; + float version; + + PlyFile *ply = PlyFile::Read( fileName , elist , file_type , version ); + if(!ply) return 0; + + 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() ) + { + delete ply; + return 0; + } + if( elem_name=="vertex" ) + { + for( int i=0 ; iget_property( elem_name , &properties[i] ); + if( readFlags ) readFlags[i] = (hasProperty!=0); + } + vertices.resize( num_elems ); + for( size_t j=0 ; jget_element( (void *)&vertices[j] ); + } + else if( elem_name=="face" ) + { + ply->get_property( elem_name , PlyFace< Index >::face_props ); + polygons.resize( num_elems ); + for( size_t j=0 ; j ply_face; + ply->get_element( (void *)&ply_face ); + polygons[j].resize( ply_face.nr_vertices ); + for( unsigned int k=0 ; kget_other_element( elem_name , num_elems ); + + for( int j=0 ; j +int PlyWritePolygons( const char* fileName , CoredMeshData< Vertex , Index >* mesh , int file_type , const Point< float , Dim >& translate , float scale , const std::vector< std::string > &comments , XForm< Real , Dim+1 > xForm ) +{ + if( mesh->outOfCorePointCount()+mesh->inCorePoints.size()>(size_t)std::numeric_limits::max() ) + { + if( std::is_same< Index , OutputIndex >::value ) ERROR_OUT( "more vertices than can be represented using " , PLYTraits< Index >::name ); + WARN( "more vertices than can be represented using " , PLYTraits< OutputIndex >::name , " using " , PLYTraits< Index >::name , " instead" ); + return PlyWritePolygons< Vertex , Index , Real , Dim , Index >( fileName , mesh , file_type , translate , scale , comments , xForm ); + } + size_t nr_vertices = mesh->outOfCorePointCount()+mesh->inCorePoints.size(); + size_t nr_faces = mesh->polygonCount(); + 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 ) return 0; + + mesh->resetIterator(); + + // + // describe vertex and face properties + // + ply->element_count( "vertex" , nr_vertices ); + for( int i=0 ; idescribe_property( "vertex" , &Vertex::Properties[i] ); + ply->element_count( "face" , nr_faces ); + ply->describe_property( "face" , PlyFace< OutputIndex >::face_props ); + + // Write in the comments + for( int i=0 ; iput_comment( comments[i] ); + ply->header_complete(); + + // write vertices + ply->put_element_setup( "vertex" ); + for( size_t i=0 ; iinCorePoints.size() ; i++ ) + { + Vertex vertex = xForm * ( mesh->inCorePoints[i] * scale + translate ); + ply->put_element( (void *)&vertex ); + } + for( size_t i=0; ioutOfCorePointCount() ; i++ ) + { + Vertex vertex; + mesh->nextOutOfCorePoint( vertex ); + vertex = xForm * ( vertex * scale + translate ); + ply->put_element( (void *)&vertex ); + } // for, write vertices + + // write faces + std::vector< CoredVertexIndex< Index > > polygon; + ply->put_element_setup( "face" ); + for( size_t i=0 ; i ply_face; + mesh->nextPolygon( polygon ); + ply_face.nr_vertices = int( polygon.size() ); + ply_face.vertices = new OutputIndex[ polygon.size() ]; + for( int j=0 ; jinCorePoints.size() ); + ply->put_element( (void *)&ply_face ); + delete[] ply_face.vertices; + } // for, write faces + + delete ply; + + return 1; +} + +template< class Vertex , typename Index , class Real , int Dim , typename OutputIndex > +int PlyWritePolygons( const char* fileName , CoredMeshData< Vertex , Index >* mesh , int file_type , const std::vector< std::string > &comments , XForm< Real , Dim+1 > xForm ) +{ + if( mesh->outOfCorePointCount()+mesh->inCorePoints.size()>(size_t)std::numeric_limits::max() ) + { + if( std::is_same< Index , OutputIndex >::value ) ERROR_OUT( "more vertices than can be represented using " , PLYTraits< Index >::name ); + WARN( "more vertices than can be represented using " , PLYTraits< OutputIndex >::name , " using " , PLYTraits< Index >::name , " instead" ); + return PlyWritePolygons< Vertex , Index , Real , Dim , Index >( fileName , mesh , file_type , comments , xForm ); + } + size_t nr_vertices = mesh->outOfCorePointCount()+mesh->inCorePoints.size(); + size_t nr_faces = mesh->polygonCount(); + 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 ) return 0; + + mesh->resetIterator(); + + // + // describe vertex and face properties + // + ply->element_count( "vertex" , nr_vertices ); + typename Vertex::Transform _xForm( xForm ); + const PlyProperty* PlyWriteProperties = Vertex::PlyWriteProperties(); + for( int i=0 ; idescribe_property( "vertex" , &PlyWriteProperties[i] ); + ply->element_count( "face" , nr_faces ); + ply->describe_property( "face" , PlyFace< OutputIndex >::face_props ); + + // Write in the comments + for( int i=0 ; iput_comment( comments[i] ); + ply->header_complete(); + // write vertices + ply->put_element_setup( "vertex" ); + for( size_t i=0 ; iinCorePoints.size() ; i++ ) + { + Vertex vertex = _xForm( mesh->inCorePoints[i] ); + ply->put_element( (void *)&vertex ); + } + for( size_t i=0; ioutOfCorePointCount() ; i++ ) + { + Vertex vertex; + mesh->nextOutOfCorePoint( vertex ); + vertex = _xForm( vertex ); + ply->put_element( (void *)&vertex ); + } // for, write vertices + + // write faces + std::vector< CoredVertexIndex< Index > > polygon; + ply->put_element_setup( "face" ); + for( size_t i=0 ; i ply_face; + mesh->nextPolygon( polygon ); + ply_face.nr_vertices = int( polygon.size() ); + ply_face.vertices = new OutputIndex[ polygon.size() ]; + for( int j=0 ; jinCorePoints.size() ); + ply->put_element( (void *)&ply_face ); + delete[] ply_face.vertices; + } // for, write faces + + delete ply; + + return 1; +} +inline int PlyDefaultFileType( void ){ return PLY_ASCII; } + +#endif // PLY_INCLUDED diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/PlyFile.h b/modules/PoissonRecon/include/Mesh/PoissonRecon/PlyFile.h new file mode 100644 index 00000000..16809bbe --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/PlyFile.h @@ -0,0 +1,201 @@ +/* + +Header for PLY polygon files. + +- Greg Turk, March 1994 + +A PLY file contains a single polygonal _object_. + +An object is composed of lists of _elements_. Typical elements are +vertices, faces, edges and materials. + +Each type of element for a given object has one or more _properties_ +associated with the element type. For instance, a vertex element may +have as properties three floating-point values x,y,z and three unsigned +chars for red, green and blue. + +--------------------------------------------------------------- + +Copyright (c) 1994 The Board of Trustees of The Leland Stanford +Junior University. All rights reserved. + +Permission to use, copy, modify and distribute this software and its +documentation for any purpose is hereby granted without fee, provided +that the above copyright notice and this permission notice appear in +all copies of this software and that you do not sell the software. + +THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, +EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY +WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. +*/ + +#ifndef PLY_FILE_INCLUDED +#define PLY_FILE_INCLUDED + +#include +#include + +#include +#include +#include +#include + +#define PLY_ASCII 1 /* ascii PLY file */ +#define PLY_BINARY_BE 2 /* binary PLY file, big endian */ +#define PLY_BINARY_LE 3 /* binary PLY file, little endian */ +#define PLY_BINARY_NATIVE 4 /* binary PLY file, same endianness as current architecture */ + +#define PLY_OKAY 0 /* ply routine worked okay */ +#define PLY_ERROR -1 /* error in ply routine */ + + /* scalar data types supported by PLY format */ + +#define PLY_START_TYPE 0 +#define PLY_CHAR 1 +#define PLY_SHORT 2 +#define PLY_INT 3 +#define PLY_LONGLONG 4 +#define PLY_UCHAR 5 +#define PLY_USHORT 6 +#define PLY_UINT 7 +#define PLY_ULONGLONG 8 +#define PLY_FLOAT 9 +#define PLY_DOUBLE 10 +#define PLY_INT_8 11 +#define PLY_UINT_8 12 +#define PLY_INT_16 13 +#define PLY_UINT_16 14 +#define PLY_INT_32 15 +#define PLY_UINT_32 16 +#define PLY_INT_64 17 +#define PLY_UINT_64 18 +#define PLY_FLOAT_32 19 +#define PLY_FLOAT_64 20 + +#define PLY_END_TYPE 21 + +#define PLY_SCALAR 0 +#define PLY_LIST 1 + +#define PLY_STRIP_COMMENT_HEADER 0 + +/* 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){ } +}; + +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 */ +}; + +/* 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 */ +}; + +/* "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 > & ); +}; + +#include "Mesh/PoissonRecon/PlyFile.inl" +#endif // PLY_FILE_INCLUDED diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/PlyFile.inl b/modules/PoissonRecon/include/Mesh/PoissonRecon/PlyFile.inl new file mode 100644 index 00000000..9af262ef --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/PlyFile.inl @@ -0,0 +1,1974 @@ +/* + +The interface routines for reading and writing PLY polygon files. + +Greg Turk, February 1994 + +--------------------------------------------------------------- + +A PLY file contains a single polygonal _object_. + +An object is composed of lists of _elements_. Typical elements are +vertices, faces, edges and materials. + +Each type of element for a given object has one or more _properties_ +associated with the element type. For instance, a vertex element may +have as properties the floating-point values x,y,z and the three unsigned +chars representing red, green and blue. + +--------------------------------------------------------------- + +Copyright (c) 1994 The Board of Trustees of The Leland Stanford +Junior University. All rights reserved. + +Permission to use, copy, modify and distribute this software and its +documentation for any purpose is hereby granted without fee, provided +that the above copyright notice and this permission notice appear in +all copies of this software and that you do not sell the software. + +THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, +EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY +WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. +*/ + +#include +#include +#include +#include +#include "Mesh/PoissonRecon/PlyFile.h" +#include "Mesh/PoissonRecon/MyMiscellany.h" + +const char *type_names[] = +{ + "invalid", + "char", + "short", + "int", + "longlong", + "uchar", + "ushort", + "uint", + "ulonglong", + "float", + "double", + + "int8", // character 1 + "uint8", // unsigned character 1 + "int16", // short integer 2 + "uint16", // unsigned short integer 2 + "int32", // integer 4 + "uint32", // unsigned integer 4 + "int64", // integer 8 + "uint64", // unsigned integer 8 + "float32", // single-precision float 4 + "float64", // double-precision float 8 +}; + +int ply_type_size[] = +{ + 0, + 1, + 2, + 4, + 8, + 1, + 2, + 4, + 8, + 4, + 8, + 1, + 1, + 2, + 2, + 4, + 4, + 8, + 8, + 4, + 8 +}; + +typedef union +{ + int int_value; + char byte_values[sizeof(int)]; +} endian_test_type; + + +static int native_binary_type = -1; +static int types_checked = 0; + +#define NO_OTHER_PROPS -1 + +#define DONT_STORE_PROP 0 +#define STORE_PROP 1 + +#define OTHER_PROP 0 +#define NAMED_PROP 1 + + +/* write to a file the word describing a PLY file data type */ +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 ** ); + +/* write to a file the word describing a PLY file data type */ +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 ); + +/* 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 ); + +/* return the value of a stored item */ +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 ); + +/* 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 & ); + +/* byte ordering */ +void get_native_binary_type(); +void swap_bytes( void * , int ); + +void check_types(); + +/*************/ +/* Writing */ +/*************/ + + +/****************************************************************************** +Given a file pointer, get ready to write PLY data to the file. + +Entry: +fp - the given file pointer +nelems - number of elements in object +elem_names - list of element names +file_type - file type, either ascii or binary + +Exit: +returns a pointer to a PlyFile, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *PlyFile::_Write( FILE *fp , const std::vector< std::string > &elem_names , int file_type ) +{ + /* check for NULL file pointer */ + if( fp==NULL ) return NULL; + + if( native_binary_type==-1 ) get_native_binary_type(); + if( !types_checked ) check_types(); + + /* create a record for this object */ + + PlyFile *plyfile = new PlyFile( fp ); + if( file_type==PLY_BINARY_NATIVE ) plyfile->file_type = native_binary_type; + else plyfile->file_type = file_type; + + /* tuck aside the names of the elements */ + plyfile->elems.resize( elem_names.size() ); + for( int i=0 ; ielems[i].name = elem_names[i]; + plyfile->elems[i].num = 0; + } + + /* return pointer to the file descriptor */ + return plyfile; +} + + +/****************************************************************************** +Open a polygon file for writing. + +Entry: +filename - name of file to read from +nelems - number of elements in object +elem_names - list of element names +file_type - file type, either ascii or binary + +Exit: +version - version number of PLY file +returns a file identifier, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *PlyFile::Write( const std::string &filename , const std::vector< std::string > &elem_names , int file_type , float &version ) +{ + /* tack on the extension .ply, if necessary */ + std::string name = filename; + if( name.length()<4 || name.substr( name.length()-4 )!=".ply" ) name += ".ply"; + + /* open the file for writing */ + FILE *fp = fopen( name.c_str() , "wb" ); + if( fp==NULL ) return NULL; + + /* create the actual PlyFile structure */ + PlyFile *plyfile = _Write( fp , elem_names , file_type ); + + /* say what PLY file version number we're writing */ + version = plyfile->version; + + /* return pointer to the file descriptor */ + return plyfile; +} + + +/****************************************************************************** +Describe an element, including its properties and how many will be written +to the file. + +Entry: +elem_name - name of element that information is being specified about +nelems - number of elements of this type to be written +nprops - number of properties contained in the element +prop_list - list of properties +******************************************************************************/ + +void PlyFile::describe_element( const std::string &elem_name , size_t nelems , int nprops , const PlyProperty *prop_list ) +{ + /* look for appropriate element */ + PlyElement *elem = find_element( elem_name ); + if( elem==NULL ) ERROR_OUT( "Can't find element '" , elem_name , "'" ); + + elem->num = nelems; + + /* copy the list of properties */ + elem->props.resize( nprops ); + for( int i=0 ; iprops[i] = PlyStoredProperty( prop_list[i] , NAMED_PROP ); +} + + +/****************************************************************************** +Describe a property of an element. + +Entry: +elem_name - name of element that information is being specified about +prop - the new property +******************************************************************************/ + +void PlyFile::describe_property( const std::string &elem_name , const PlyProperty *prop ) +{ + /* look for appropriate element */ + PlyElement *elem = find_element( elem_name ); + if( elem == NULL ) + { + WARN( "Can't find element '" , elem_name , "'" ); + return; + } + + elem->props.push_back( PlyStoredProperty( *prop , NAMED_PROP ) ); +} + + +/****************************************************************************** +Describe what the "other" properties are that are to be stored, and where +they are in an element. +******************************************************************************/ + +void PlyFile::describe_other_properties( const PlyOtherProp &other , int offset ) +{ + /* look for appropriate element */ + PlyElement *elem = find_element( other.name ); + if( elem==NULL ) + { + WARN( "Can't find element '" , other.name , "'" ); + return; + } + + elem->props.reserve( elem->props.size() + other.props.size() ); + for( int i=0 ; iprops.push_back( PlyStoredProperty( other.props[i] , OTHER_PROP ) ); + + /* save other info about other properties */ + elem->other_size = other.size; + elem->other_offset = offset; +} + + +/****************************************************************************** +State how many of a given element will be written. + +Entry: +elem_name - name of element that information is being specified about +nelems - number of elements of this type to be written +******************************************************************************/ +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 , "'" ); + + elem->num = nelems; +} + + +/****************************************************************************** +Signal that we've described everything a PLY file's header and that the +header should be written to the file. +******************************************************************************/ + +void PlyFile::header_complete( void ) +{ + fprintf( fp , "ply\n" ); + switch( file_type ) + { + 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 ); + } + + /* write out the comments */ + for( int i=0 ; iother_offset); + + /* write out either to an ascii or binary file */ + + if( file_type==PLY_ASCII ) /* write an ascii file */ + { + /* 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; + else elem_data = (char *)elem_ptr; + if( elem->props[j].prop.is_list ) + { + item = elem_data + elem->props[j].prop.count_offset; + get_stored_item( (void *)item , elem->props[j].prop.count_internal , int_val , uint_val , longlong_val , ulonglong_val , double_val ); + write_ascii_item( fp , int_val , uint_val , longlong_val , ulonglong_val , double_val , elem->props[j].prop.count_external ); + list_count = uint_val; + item_ptr = (char **)( elem_data + elem->props[j].prop.offset ); + item = item_ptr[0]; + item_size = ply_type_size[ elem->props[j].prop.internal_type ]; + for( int k=0 ; kprops[j].prop.internal_type , int_val , uint_val , longlong_val , ulonglong_val , double_val ); + write_ascii_item( fp , int_val , uint_val , longlong_val , ulonglong_val , double_val , elem->props[j].prop.external_type ); + item += item_size; + } + } + else + { + item = elem_data + elem->props[j].prop.offset; + get_stored_item( (void *)item , elem->props[j].prop.internal_type , int_val , uint_val , longlong_val , ulonglong_val , double_val ); + write_ascii_item( fp , int_val , uint_val , longlong_val , ulonglong_val , double_val , elem->props[j].prop.external_type ); + } + } + fprintf( fp , "\n" ); + } + else /* write a binary file */ + { + /* 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; + else elem_data = (char *)elem_ptr; + if( elem->props[j].prop.is_list ) + { + item = elem_data + elem->props[j].prop.count_offset; + item_size = ply_type_size[ elem->props[j].prop.count_internal ]; + get_stored_item( (void *)item , elem->props[j].prop.count_internal , int_val , uint_val , longlong_val , ulonglong_val , double_val ); + write_binary_item( fp , file_type , int_val , uint_val , longlong_val , ulonglong_val , double_val , elem->props[j].prop.count_external ); + list_count = uint_val; + item_ptr = (char **)( elem_data + elem->props[j].prop.offset ); + item = item_ptr[0]; + item_size = ply_type_size[ elem->props[j].prop.internal_type ]; + for( int k=0 ; kprops[j].prop.internal_type , int_val , uint_val , longlong_val , ulonglong_val , double_val ); + write_binary_item( fp , file_type , int_val , uint_val , longlong_val , ulonglong_val , double_val , elem->props[j].prop.external_type ); + item += item_size; + } + } + else + { + item = elem_data + elem->props[j].prop.offset; + item_size = ply_type_size[ elem->props[j].prop.internal_type ]; + get_stored_item( (void *)item , elem->props[j].prop.internal_type , int_val , uint_val , longlong_val , ulonglong_val , double_val ); + write_binary_item( fp , file_type , int_val , uint_val , longlong_val , ulonglong_val , double_val , elem->props[j].prop.external_type ); + } + } + } +} + + +/****************************************************************************** +Specify a comment that will be written in the header. + +Entry: +comment - the comment to be written +******************************************************************************/ + +void PlyFile::put_comment( const std::string &comment ){ comments.push_back( comment ); } + + +/****************************************************************************** +Specify a piece of object information (arbitrary text) that will be written +in the header. + +Entry: +obj_info - the text information to be written +******************************************************************************/ + +void PlyFile::put_obj_info( const std::string &obj_info ){ this->obj_info.push_back( obj_info ); } + + +/*************/ +/* Reading */ +/*************/ + + + +/****************************************************************************** +Given a file pointer, get ready to read PLY data from the file. + +Entry: +fp - the given file pointer + +Exit: +nelems - number of elements in object +elem_names - list of element names +returns a pointer to a PlyFile, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *PlyFile::_Read( FILE *fp , std::vector< std::string > &elem_names ) +{ + char *orig_line; + /* check for NULL file pointer */ + if( fp==NULL ) return NULL; + + if( native_binary_type==-1 ) get_native_binary_type(); + if( !types_checked ) check_types(); + + /* create record for this object */ + std::vector< std::string > words; + PlyFile *plyfile = new PlyFile( fp ); + + /* read and parse the file's header */ + words = get_words( plyfile->fp , &orig_line ); + if( !words.size() || words[0]!="ply" ) return NULL; + while( words.size() ) + { + /* parse words */ + if( words[0]=="format" ) + { + if( words.size()!=3 ) return NULL; + if ( words[1]=="ascii" ) plyfile->file_type = PLY_ASCII; + else if( words[1]=="binary_big_endian" ) plyfile->file_type = PLY_BINARY_BE; + else if( words[1]=="binary_little_endian" ) plyfile->file_type = PLY_BINARY_LE; + else return NULL; + plyfile->version = (float)atof( words[2].c_str() ); + } + else if( words[0]=="element" ) plyfile->add_element ( words ); + else if( words[0]=="property" ) plyfile->add_property( words ); + else if( words[0]=="comment" ) plyfile->add_comment ( orig_line ); + else if( words[0]=="obj_info" ) plyfile->add_obj_info( orig_line ); + else if( words[0]=="end_header" ) break; + + words = get_words( plyfile->fp , &orig_line ); + } + + /* create tags for each property of each element, to be used */ + /* 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 */ + } + + /* set return values about the elements */ + elem_names.resize( plyfile->elems.size() ); + for( int i=0 ; ielems[i].name; + + /* return a pointer to the file's information */ + return plyfile; +} + + +/****************************************************************************** +Open a polygon file for reading. + +Entry: +filename - name of file to read from + +Exit: +nelems - number of elements in object +elem_names - list of element names +file_type - file type, either ascii or binary +version - version number of PLY file +returns a file identifier, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *PlyFile::Read( const std::string &filename , std::vector< std::string > &elem_names , int &file_type , float &version ) +{ + /* tack on the extension .ply, if necessary */ + std::string name = filename; + if( name.length()<4 || name.substr( name.length()-4 )!=".ply" ) name += ".ply"; + + /* open the file for reading */ + FILE *fp = fopen( name.c_str() , "rb" ); + if( fp==NULL ) return NULL; + + /* create the PlyFile data structure */ + PlyFile *plyfile = _Read( fp , elem_names ); + + /* determine the file type and version */ + file_type = plyfile->file_type; + version = plyfile->version; + + /* return a pointer to the file's information */ + return plyfile; +} + + +/****************************************************************************** +Get information about a particular element. + +Entry: +elem_name - name of element to get information about + +Exit: +nelems - number of elements of this type in the file +nprops - number of properties +returns a list of properties, or NULL if the file doesn't contain that elem +******************************************************************************/ + +std::vector< PlyProperty * > PlyFile::get_element_description( const std::string &elem_name , size_t &nelems ) +{ + std::vector< PlyProperty * > prop_list; + + /* find information about the element */ + PlyElement *elem = find_element( elem_name ); + if( elem==NULL ) return prop_list; + nelems = elem->num; + + /* make a copy of the element's property list */ + prop_list.resize( elem->props.size() ); + for( int i=0 ; iprops.size() ; i++ ) prop_list[i] = new PlyProperty( elem->props[i].prop ); + + /* return this duplicate property list */ + return prop_list; +} + +/****************************************************************************** +Specify which properties of an element are to be returned. This should be +called before a call to the routine ply_get_element(). + +Entry: +elem_name - which element we're talking about +nprops - number of properties +prop_list - list of properties +******************************************************************************/ + +void PlyFile::get_element_setup( const std::string &elem_name , int nprops , PlyProperty *prop_list ) +{ + /* find information about the element */ + PlyElement *elem = find_element( elem_name ); + which_elem = elem; + + /* deposit the property information into the element's description */ + for( int i=0 ; ifind_property( prop_list[i].name , index ); + if( prop==NULL ) + { + WARN( "Can't find property '" , prop_list[i].name , "' in element '" , elem_name , "'" ); + continue; + } + + /* store its description */ + prop->internal_type = prop_list[i].internal_type; + prop->offset = prop_list[i].offset; + prop->count_internal = prop_list[i].count_internal; + prop->count_offset = prop_list[i].count_offset; + + /* specify that the user wants this property */ + elem->props[index].store = STORE_PROP; + } +} + + +/****************************************************************************** +Specify a property of an element that is to be returned. This should be +called (usually multiple times) before a call to the routine ply_get_element(). +This routine should be used in preference to the less flexible old routine +called ply_get_element_setup(). + +Entry: +elem_name - which element we're talking about +prop - property to add to those that will be returned +******************************************************************************/ + +int PlyFile::get_property( const std::string &elem_name , const PlyProperty *prop ) +{ + /* find information about the element */ + PlyElement *elem = find_element( elem_name ); + which_elem = elem; + + /* deposit the property information into the element's description */ + int index; + PlyProperty *prop_ptr = elem->find_property( prop->name , index ); + if( prop_ptr==NULL ) return 0; + prop_ptr->internal_type = prop->internal_type; + prop_ptr->offset = prop->offset; + prop_ptr->count_internal = prop->count_internal; + prop_ptr->count_offset = prop->count_offset; + + /* specify that the user wants this property */ + elem->props[index].store = STORE_PROP; + + return 1; +} + + +/****************************************************************************** +Read one element from the file. This routine assumes that we're reading +the type of element specified in the last call to the routine +ply_get_element_setup(). + +Entry: +elem_ptr - pointer to location where the element information should be put +******************************************************************************/ + +void PlyFile::get_element( void *elem_ptr ) +{ + if( file_type==PLY_ASCII ) _ascii_get_element( elem_ptr ); + else _binary_get_element( elem_ptr ); +} + +/****************************************************************************** +Extract the comments from the header information of a PLY file. + +Exit: +num_comments - number of comments returned +returns a pointer to a list of comments +******************************************************************************/ + +std::vector< std::string > &PlyFile::get_comments( void ){ return comments; } + +/****************************************************************************** +Extract the object information (arbitrary text) from the header information +of a PLY file. + +Exit: +num_obj_info - number of lines of text information returned +returns a pointer to a list of object info lines +******************************************************************************/ +std::vector< std::string > &PlyFile::get_obj_info( void ){ return obj_info; } + +/****************************************************************************** +Make ready for "other" properties of an element-- those properties that +the user has not explicitly asked for, but that are to be stashed away +in a special structure to be carried along with the element's other +information. + +Entry: +elem - element for which we want to save away other properties +******************************************************************************/ + +void setup_other_props( PlyElement *elem ) +{ + int size = 0; + + /* Examine each property in decreasing order of size. */ + /* We do this so that all data types will be aligned by */ + /* word, half-word, or whatever within the structure. */ + + for( int type_size=8 ; type_size>0 ; type_size/=2 ) + { + + /* add up the space taken by each property, and save this information */ + /* away in the property descriptor */ + for( int i=0 ; iprops.size() ; i++ ) + { + /* don't bother with properties we've been asked to store explicitly */ + if( elem->props[i].store ) continue; + PlyProperty &prop = elem->props[i].prop; + + /* internal types will be same as external */ + prop.internal_type = prop.external_type; + prop.count_internal = prop.count_external; + + /* check list case */ + if( prop.is_list ) + { + /* pointer to list */ + if( type_size==sizeof(void *) ) + { + prop.offset = size; + size += sizeof( void * ); /* always use size of a pointer here */ + } + + /* count of number of list elements */ + if( type_size==ply_type_size[ prop.count_external ] ) + { + prop.count_offset = size; + size += ply_type_size[ prop.count_external ]; + } + } + /* not list */ + else if( type_size==ply_type_size[ prop.external_type ] ) + { + prop.offset = size; + size += ply_type_size[ prop.external_type ]; + } + } + } + + /* save the size for the other_props structure */ + elem->other_size = size; +} + + +/****************************************************************************** +Specify that we want the "other" properties of an element to be tucked +away within the user's structure. The user needn't be concerned for how +these properties are stored. + +Entry: +elem_name - name of element that we want to store other_props in +offset - offset to where other_props will be stored inside user's structure + +Exit: +returns pointer to structure containing description of other_props +******************************************************************************/ + +bool PlyFile::set_other_properties( const std::string &elem_name , int offset , PlyOtherProp &other ) +{ + /* find information about the element */ + PlyElement *elem = find_element( elem_name ); + if( elem==NULL ) + { + WARN( "Can't find element '" , elem_name , "'" ); + return false; + } + + /* remember that this is the "current" element */ + which_elem = elem; + + /* save the offset to where to store the other_props */ + elem->other_offset = offset; + + /* place the appropriate pointers, etc. in the element's property list */ + setup_other_props( elem ); + + /* create structure for describing other_props */ + other.size = elem->other_size; + other.props.reserve( elem->props.size() ); + 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; + return true; +} + +/*************************/ +/* Other Element Stuff */ +/*************************/ + + + + +/****************************************************************************** +Grab all the data for an element that a user does not want to explicitly +read in. + +Entry: +elem_name - name of element whose data is to be read in +elem_count - number of instances of this element stored in the file + +Exit: +returns pointer to ALL the "other" element data for this PLY file +******************************************************************************/ + +PlyOtherElems *PlyFile::get_other_element( std::string &elem_name , size_t elem_count ) +{ + /* look for appropriate element */ + PlyElement *elem = find_element( elem_name ); + if( elem==NULL ) 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 ); + OtherElem *other = &other_elems->other_list.back(); + + /* save name of element */ + other->elem_name = elem_name; + + /* create a list to hold all the current elements */ + other->other_data.resize( elem_count ); + + /* set up for getting elements */ + set_other_properties( elem_name , offsetof( OtherData , other_props ) , other->other_props ); + + /* grab all these elements */ + for( int i=0 ; iother_data.size() ; i++ ) + { + /* grab and element from the file */ + get_element( (void *)&other->other_data[i] ); + } + + /* return pointer to the other elements data */ + return other_elems; +} + + +/****************************************************************************** +Pass along a pointer to "other" elements that we want to save in a given +PLY file. These other elements were presumably read from another PLY file. + +Entry: +other_elems - info about other elements that we want to store +******************************************************************************/ + +void PlyFile::describe_other_elements( PlyOtherElems *other_elems ) +{ + /* ignore this call if there is no other element */ + if( other_elems==NULL ) return; + + /* save pointer to this information */ + this->other_elems = other_elems; + + /* describe the other properties of this element */ + /* store them in the main element list as elements with + only other properties */ + + elems.reserve( elems.size() + other_elems->other_list.size() ); + for( int i=0 ; iother_list.size() ; i++ ) + { + PlyElement elem; + elem.name = other_elems->other_list[i].elem_name; + elem.num = other_elems->other_list[i].other_data.size(); + elem.props.resize(0); + describe_other_properties( other_elems->other_list[i].other_props , offsetof( OtherData , other_props ) ); + elems.push_back( elem ); + } +} + + +/****************************************************************************** +Write out the "other" elements specified for this PLY file. +******************************************************************************/ + +void PlyFile::put_other_elements( void ) +{ + OtherElem *other; + + /* make sure we have other elements to write */ + if( other_elems==NULL ) return; + + /* write out the data for each "other" element */ + for( int i=0 ; iother_list.size() ; i++ ) + { + other = &(other_elems->other_list[i]); + put_element_setup( other->elem_name ); + + /* write out each instance of the current element */ + for( int j=0 ; jother_data.size() ; j++ ) put_element( (void *)&other->other_data[j] ); + } +} + +/*******************/ +/* Miscellaneous */ +/*******************/ + +/****************************************************************************** +Get version number and file type of a PlyFile. + +Exit: +version - version of the file +file_type - PLY_ASCII, PLY_BINARY_BE, or PLY_BINARY_LE +******************************************************************************/ + +void PlyFile::get_info( float &version, int &file_type ){ version = this->version , file_type = this->file_type; } + +/****************************************************************************** +Find an element from the element list of a given PLY object. + +Entry: +element - name of element we're looking for + +Exit: +returns the element, or NULL if not found +******************************************************************************/ + +PlyElement *PlyFile::find_element( const std::string &element ) +{ + for( int i=0 ; i words; + PlyElement *elem; + int which_word; + void *elem_data , *item=NULL; + char *item_ptr; + int item_size; + int int_val; + unsigned int uint_val; + long long longlong_val; + unsigned long long ulonglong_val; + double double_val; + int list_count; + int store_it; + char **store_array; + char *orig_line; + char *other_data=NULL; + int other_flag; + + /* the kind of element we're reading currently */ + elem = which_elem; + + /* do we need to setup for other_props? */ + if( elem->other_offset!=NO_OTHER_PROPS ) + { + char **ptr; + other_flag = 1; + /* make room for other_props */ + other_data = (char *)malloc( elem->other_size ); + /* store pointer in user's structure to the other_props */ + ptr = (char **) ( (char*)elem_ptr + elem->other_offset); + *ptr = other_data; + } + else other_flag = 0; + + /* read in the element */ + words = get_words( fp , &orig_line ); + if( !words.size() ) ERROR_OUT( "Unexpected end of file" ); + + which_word = 0; + + for( int j=0 ; jprops.size() ; j++ ) + { + PlyProperty &prop = elem->props[j].prop; + store_it = (elem->props[j].store | other_flag); + + /* store either in the user's structure or in other_props */ + if( elem->props[j].store ) elem_data = elem_ptr; + else elem_data = other_data; + + if( prop.is_list ) /* a list */ + { + /* get and store the number of items in the list */ + get_ascii_item( words[which_word++] , prop.count_external , int_val , uint_val , longlong_val , ulonglong_val , double_val ); + if( store_it ) + { + item = (char *)elem_data + prop.count_offset; + store_item( item , prop.count_internal , int_val , uint_val , longlong_val , ulonglong_val , double_val ); + } + + /* allocate space for an array of items and store a ptr to the array */ + list_count = int_val; + item_size = ply_type_size[ prop.internal_type ]; + store_array = (char **)( (char *)elem_data + prop.offset ); + + if( list_count==0 ) + { + if( store_it ) *store_array = NULL; + } + else + { + if( store_it ) + { + item_ptr = (char *) malloc (sizeof (char) * item_size * list_count); + item = item_ptr; + *store_array = item_ptr; + } + + /* read items and store them into the array */ + for( int k=0 ; kother_offset!=NO_OTHER_PROPS ) + { + char **ptr; + other_flag = 1; + /* make room for other_props */ + other_data = (char *) malloc (elem->other_size); + /* store pointer in user's structure to the other_props */ + ptr = (char **) ((char *)elem_ptr + elem->other_offset); + *ptr = other_data; + } + else other_flag = 0; + + /* read in a number of elements */ + + for( int j=0 ; jprops.size() ; j++ ) + { + PlyProperty &prop = elem->props[j].prop; + store_it = ( elem->props[j].store | other_flag ); + + /* store either in the user's structure or in other_props */ + if( elem->props[j].store ) elem_data = elem_ptr; + else elem_data = other_data; + + if( prop.is_list ) /* a list */ + { + /* get and store the number of items in the list */ + get_binary_item( fp , file_type , prop.count_external , int_val, uint_val , longlong_val , ulonglong_val , double_val ); + if( store_it ) + { + item = (char *)elem_data + prop.count_offset; + store_item( item , prop.count_internal , int_val , uint_val , longlong_val , ulonglong_val , double_val ); + } + + /* allocate space for an array of items and store a ptr to the array */ + list_count = int_val; + item_size = ply_type_size[ prop.internal_type ]; + store_array = (char **) ((char *)elem_data + prop.offset); + if( list_count==0 ) + { + if( store_it ) *store_array = NULL; + } + else + { + if( store_it ) + { + item_ptr = (char *)malloc(sizeof (char) * item_size * list_count); + item = item_ptr; + *store_array = item_ptr; + } + + /* read items and store them into the array */ + for( int k=0 ; k=PLY_END_TYPE ) ERROR_OUT( "Bad data code: " , code ); + + /* write the code to a file */ + fprintf( fp , "%s" , type_names[code] ); +} + +/****************************************************************************** +Reverse the order in an array of bytes. This is the conversion from big +endian to little endian and vice versa + +Entry: +bytes - array of bytes to reverse (in place) +num_bytes - number of bytes in array +******************************************************************************/ + +void swap_bytes( void *bytes , int num_bytes ) +{ + char *chars = (char *)bytes; + + for( int i=0 ; i get_words( FILE *fp , char **orig_line ) +{ +#define BIG_STRING 4096 + static char str[BIG_STRING]; + static char str_copy[BIG_STRING]; + std::vector< std::string > words; + int max_words = 10; + int num_words = 0; + char *ptr , *ptr2; + char *result; + + /* read in a line */ + result = fgets( str , BIG_STRING , fp ); + if( result==NULL ) + { + *orig_line = NULL; + return words; + } + /* convert line-feed and tabs into spaces */ + /* (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'; + + for( ptr=str , ptr2=str_copy ; *ptr!='\0' ; ptr++ , ptr2++ ) + { + *ptr2 = *ptr; + // Added line here to manage carriage returns + if( *ptr == '\t' || *ptr == '\r' ) + { + *ptr = ' '; + *ptr2 = ' '; + } + else if( *ptr=='\n' ) + { + *ptr = ' '; + *ptr2 = '\0'; + break; + } + } + + /* find the words in the line */ + + ptr = str; + while( *ptr!='\0' ) + { + /* jump over leading spaces */ + while( *ptr==' ' ) ptr++; + + /* break if we reach the end */ + if( *ptr=='\0' ) break; + + char *_ptr = ptr; + + /* jump over non-spaces */ + while( *ptr!=' ' ) ptr++; + + /* place a null character here to mark the end of the word */ + *ptr++ = '\0'; + + /* save pointer to beginning of word */ + words.push_back( _ptr ); + } + + /* return the list of words */ + *orig_line = str_copy; + return words; +} + +/****************************************************************************** +Return the value of an item, given a pointer to it and its type. + +Entry: +item - pointer to item +type - data type that "item" points to + +Exit: +returns a double-precision float that contains the value of the item +******************************************************************************/ + +double get_item_value( const void *item , int type ) +{ + switch( type ) + { + case PLY_CHAR: + case PLY_INT_8: return (double)*(const char *)item; + case PLY_UCHAR: + case PLY_UINT_8: return (double)*(const unsigned char *)item; + case PLY_SHORT: + case PLY_INT_16: return (double)*(const short int *)item; + case PLY_USHORT: + case PLY_UINT_16: return (double)*(const unsigned short int *)item; + case PLY_INT: + case PLY_INT_32: return (double)*(const int *)item; + case PLY_LONGLONG: + case PLY_INT_64: return (double)*(const long long *)item; + case PLY_UINT: + case PLY_UINT_32: return (double)*(const unsigned int *)item; + case PLY_ULONGLONG: + case PLY_UINT_64: return (double)*(const unsigned long long *)item; + case PLY_FLOAT: + 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 ); + } + return 0; +} + + +/****************************************************************************** +Write out an item to a file as raw binary bytes. + +Entry: +fp - file to write to +int_val - integer version of item +uint_val - unsigned integer version of item +double_val - double-precision float version of item +type - data type to write out +******************************************************************************/ + +void write_binary_item( FILE *fp , int file_type , int int_val , unsigned int uint_val , long long longlong_val , unsigned long long ulonglong_val , double double_val , int type ) +{ + unsigned char uchar_val; + char char_val; + unsigned short ushort_val; + short short_val; + float float_val; + void *value; + + switch (type) { + case PLY_CHAR: + case PLY_INT_8: + char_val = char(int_val); + value = &char_val; + break; + case PLY_SHORT: + case PLY_INT_16: + short_val = short(int_val); + value = &short_val; + break; + case PLY_INT: + case PLY_INT_32: + value = &int_val; + break; + case PLY_LONGLONG: + case PLY_INT_64: + value = &longlong_val; + break; + case PLY_UCHAR: + case PLY_UINT_8: + uchar_val = (unsigned char)(uint_val); + value = &uchar_val; + break; + case PLY_USHORT: + case PLY_UINT_16: + ushort_val = (unsigned short)(uint_val); + value = &ushort_val; + break; + case PLY_UINT: + case PLY_UINT_32: + value = &uint_val; + break; + case PLY_ULONGLONG: + case PLY_UINT_64: + value = &ulonglong_val; + break; + case PLY_FLOAT: + case PLY_FLOAT_32: + float_val = (float)double_val; + value = &float_val; + break; + case PLY_DOUBLE: + case PLY_FLOAT_64: + value = &double_val; + break; + default: 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" ); +} + + +/****************************************************************************** +Write out an item to a file as ascii characters. + +Entry: +fp - file to write to +int_val - integer version of item +uint_val - unsigned integer version of item +double_val - double-precision float version of item +type - data type to write out +******************************************************************************/ + +void write_ascii_item( FILE *fp , int int_val , unsigned int uint_val , long long longlong_val , unsigned long long ulonglong_val , double double_val , int type ) +{ + switch (type) + { + case PLY_CHAR: + case PLY_INT_8: + case PLY_SHORT: + case PLY_INT_16: + case PLY_INT: + case PLY_INT_32: + if( fprintf( fp , "%d " , int_val )<=0 ) 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" ); + break; + case PLY_UCHAR: + case PLY_UINT_8: + case PLY_USHORT: + case PLY_UINT_16: + case PLY_UINT: + case PLY_UINT_32: + if( fprintf( fp , "%u " , uint_val )<=0 ) 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" ); + 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" ); + break; + default: ERROR_OUT( "Bad type: " , type ); + } +} + +/****************************************************************************** +Get the value of an item that is in memory, and place the result +into an integer, an unsigned integer and a double. + +Entry: +ptr - pointer to the item +type - data type supposedly in the item + +Exit: +int_val - integer value +uint_val - unsigned integer value +double_val - double-precision floating point value +******************************************************************************/ + +void get_stored_item( void *ptr , int type , int &int_val , unsigned int &uint_val , long long &longlong_val , unsigned long long &ulonglong_val , double &double_val ) +{ + switch( type ) + { + case PLY_CHAR: + case PLY_INT_8: + int_val = *((char *) ptr); + uint_val = int_val; + double_val = int_val; + longlong_val = (long long)int_val; + ulonglong_val = (unsigned long long)int_val; + break; + case PLY_UCHAR: + case PLY_UINT_8: + uint_val = *((unsigned char *) ptr); + int_val = uint_val; + double_val = uint_val; + longlong_val = (long long)uint_val; + ulonglong_val = (unsigned long long)uint_val; + break; + case PLY_SHORT: + case PLY_INT_16: + int_val = *((short int *) ptr); + uint_val = int_val; + double_val = int_val; + longlong_val = (long long)int_val; + ulonglong_val = (unsigned long long)int_val; + break; + case PLY_USHORT: + case PLY_UINT_16: + uint_val = *((unsigned short int *) ptr); + int_val = uint_val; + double_val = uint_val; + longlong_val = (long long)uint_val; + ulonglong_val = (unsigned long long)uint_val; + break; + case PLY_INT: + case PLY_INT_32: + int_val = *((int *) ptr); + uint_val = int_val; + double_val = int_val; + longlong_val = (long long)int_val; + ulonglong_val = (unsigned long long)int_val; + break; + case PLY_UINT: + case PLY_UINT_32: + uint_val = *((unsigned int *) ptr); + int_val = uint_val; + double_val = uint_val; + longlong_val = (long long)uint_val; + ulonglong_val = (unsigned long long)uint_val; + break; + case PLY_LONGLONG: + case PLY_INT_64: + longlong_val = *((long long *) ptr); + ulonglong_val = (unsigned long long)longlong_val; + int_val = (int)longlong_val; + uint_val = (unsigned int)longlong_val; + double_val = (double)longlong_val; + break; + case PLY_ULONGLONG: + case PLY_UINT_64: + ulonglong_val = *((unsigned long long *) ptr); + longlong_val = (long long)ulonglong_val; + int_val = (int)ulonglong_val; + uint_val = (unsigned int)ulonglong_val; + double_val = (double)ulonglong_val; + break; + case PLY_FLOAT: + case PLY_FLOAT_32: + double_val = *((float *) ptr); + int_val = (int)double_val; + uint_val = (unsigned int)double_val; + longlong_val = (long long)double_val; + ulonglong_val = (unsigned long long)double_val; + break; + case PLY_DOUBLE: + case PLY_FLOAT_64: + double_val = *((double *) ptr); + int_val = (int)double_val; + uint_val = (unsigned int)double_val; + longlong_val = (long long)double_val; + ulonglong_val = (unsigned long long)double_val; + break; + default: ERROR_OUT( "Bad type: " , type ); + } +} + +/****************************************************************************** +Get the value of an item from a binary file, and place the result +into an integer, an unsigned integer and a double. + +Entry: +fp - file to get item from +type - data type supposedly in the word + +Exit: +int_val - integer value +uint_val - unsigned integer value +double_val - double-precision floating point value +******************************************************************************/ + +void get_binary_item( FILE *fp , int file_type , int type , int &int_val , unsigned int &uint_val , long long &longlong_val , unsigned long long &ulonglong_val , double &double_val ) +{ + char c[8]; + void *ptr; + + ptr = ( void * )c; + + if( fread( ptr , ply_type_size[type] , 1 , fp )!=1 ) ERROR_OUT( "fread() failed -- aborting." ); + if( ( file_type!=native_binary_type ) && ( ply_type_size[type]>1 ) ) swap_bytes( (char *)ptr , ply_type_size[type] ); + + switch( type ) + { + case PLY_CHAR: + case PLY_INT_8: + int_val = *((char *) ptr); + uint_val = int_val; + longlong_val = int_val; + ulonglong_val = int_val; + double_val = int_val; + break; + case PLY_UCHAR: + case PLY_UINT_8: + uint_val = *((unsigned char *) ptr); + int_val = uint_val; + longlong_val = int_val; + ulonglong_val = int_val; + double_val = uint_val; + break; + case PLY_SHORT: + case PLY_INT_16: + int_val = *((short int *) ptr); + uint_val = int_val; + longlong_val = int_val; + ulonglong_val = int_val; + double_val = int_val; + break; + case PLY_USHORT: + case PLY_UINT_16: + uint_val = *((unsigned short int *) ptr); + int_val = uint_val; + longlong_val = int_val; + ulonglong_val = int_val; + double_val = uint_val; + break; + case PLY_INT: + case PLY_INT_32: + int_val = *((int *) ptr); + uint_val = int_val; + longlong_val = int_val; + ulonglong_val = int_val; + double_val = int_val; + break; + case PLY_UINT: + case PLY_UINT_32: + uint_val = *((unsigned int *) ptr); + int_val = uint_val; + longlong_val = int_val; + ulonglong_val = int_val; + double_val = uint_val; + break; + case PLY_LONGLONG: + case PLY_INT_64: + longlong_val = *((long long *) ptr); + ulonglong_val = (unsigned long long)longlong_val; + int_val = (int)longlong_val; + uint_val = (unsigned int)longlong_val; + double_val = (double)longlong_val; + break; + case PLY_ULONGLONG: + case PLY_UINT_64: + ulonglong_val = *((unsigned long long *) ptr); + longlong_val = (long long)ulonglong_val; + int_val = (int)ulonglong_val; + uint_val = (unsigned int)ulonglong_val; + double_val = (double)ulonglong_val; + break; + case PLY_FLOAT: + case PLY_FLOAT_32: + double_val = *((float *) ptr); + int_val = (int)double_val; + uint_val = (unsigned int)double_val; + longlong_val = (long long)double_val; + ulonglong_val = (unsigned long long)int_val; + break; + case PLY_DOUBLE: + case PLY_FLOAT_64: + double_val = *((double *) ptr); + int_val = (int)double_val; + uint_val = (unsigned int)double_val; + longlong_val = (long long)double_val; + ulonglong_val = (unsigned long long)int_val; + break; + default: ERROR_OUT( "Bad type: " , type ); + } +} + +/****************************************************************************** +Extract the value of an item from an ascii word, and place the result +into an integer, an unsigned integer and a double. + +Entry: +word - word to extract value from +type - data type supposedly in the word + +Exit: +int_val - integer value +uint_val - unsigned integer value +double_val - double-precision floating point value +******************************************************************************/ +void get_ascii_item( const std::string &word , int type , int &int_val , unsigned int &uint_val , long long &longlong_val , unsigned long long &ulonglong_val , double &double_val ) +{ + switch( type ) + { + case PLY_CHAR: + case PLY_INT_8: + case PLY_UCHAR: + case PLY_UINT_8: + case PLY_SHORT: + case PLY_INT_16: + case PLY_USHORT: + case PLY_UINT_16: + case PLY_INT: + case PLY_INT_32: + int_val = atoi( word.c_str() ); + uint_val = (unsigned int)int_val; + double_val = (double)int_val; + longlong_val = (long long)int_val; + ulonglong_val = (unsigned long long)int_val; + break; + + case PLY_UINT: + case PLY_UINT_32: + uint_val = strtol( word.c_str() , (char **)NULL , 10 ); + int_val = (int)uint_val; + double_val = (double)uint_val; + longlong_val = (long long)uint_val; + ulonglong_val = (unsigned long long)uint_val; + break; + case PLY_LONGLONG: + case PLY_INT_64: + longlong_val = std::stoll( word.c_str() ); + ulonglong_val = (unsigned long long)longlong_val; + int_val = (int)longlong_val; + uint_val = (unsigned int)longlong_val; + double_val = (double)longlong_val; + break; + case PLY_ULONGLONG: + case PLY_UINT_64: + ulonglong_val = std::stoull( word.c_str() ); + longlong_val = (long long)ulonglong_val; + int_val = (int)ulonglong_val; + uint_val = (unsigned int)ulonglong_val; + double_val = (double)ulonglong_val; + break; + case PLY_FLOAT: + case PLY_FLOAT_32: + case PLY_DOUBLE: + case PLY_FLOAT_64: + double_val = atof( word.c_str() ); + int_val = (int)double_val; + uint_val = (unsigned int)double_val; + longlong_val = (long long)double_val; + ulonglong_val = (unsigned long long)double_val; + break; + default: ERROR_OUT( "Bad type: " , type ); + } +} + +/****************************************************************************** +Store a value into a place being pointed to, guided by a data type. + +Entry: +item - place to store value +type - data type +int_val - integer version of value +uint_val - unsigned integer version of value +double_val - double version of value + +Exit: +item - pointer to stored value +******************************************************************************/ + +void store_item( void *item , int type , int int_val , unsigned int uint_val , long long longlong_val , unsigned long long ulonglong_val , double double_val ) +{ + switch( type ) + { + case PLY_CHAR: + case PLY_INT_8: *( char *)item = ( char) int_val ; break; + case PLY_UCHAR: + case PLY_UINT_8: *(unsigned char *)item = (unsigned char) uint_val ; break; + case PLY_SHORT: + case PLY_INT_16: *( short *)item = ( short) int_val ; break; + case PLY_USHORT: + case PLY_UINT_16: *(unsigned short *)item = (unsigned short) uint_val ; break; + case PLY_INT: + case PLY_INT_32: *( int *)item = ( int) int_val ; break; + case PLY_UINT: + case PLY_UINT_32: *(unsigned int *)item = (unsigned int) uint_val ; break; + case PLY_LONGLONG: + case PLY_INT_64: *( long long *)item = ( long long)longlong_val ; break; + case PLY_ULONGLONG: + case PLY_UINT_64: *(unsigned long long *)item = (unsigned long long)ulonglong_val ; break; + case PLY_FLOAT: + 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 ); + } +} + + +/****************************************************************************** +Add an element to a PLY file descriptor. + +Entry: +plyfile - PLY file descriptor +words - list of words describing the element +nwords - number of words in the list +******************************************************************************/ + +void PlyFile::add_element( const std::vector< std::string > &words ) +{ + PlyElement elem; + + /* set the new element */ + elem.name = words[1]; + elem.num = std::stoull( words[2] ); + elem.props.resize(0); + + /* add the new element to the object's list */ + elems.push_back( elem ); +} + +/****************************************************************************** +Return the type of a property, given the name of the property. + +Entry: +name - name of property type + +Exit: +returns integer code for property, or 0 if not found +******************************************************************************/ + +int get_prop_type( const std::string &type_name ) +{ + for( int i=PLY_START_TYPE+1 ; i &words ) +{ + PlyProperty prop; + if( words[1]=="list" ) /* is a list */ + { + prop.count_external = get_prop_type( words[2] ); + prop.external_type = get_prop_type( words[3]) ; + prop.name = words[4]; + prop.is_list = 1; + } + else /* not a list */ + { + prop.external_type = get_prop_type( words[1] ); + prop.name = words[2]; + prop.is_list = 0; + } + + /* add this property to the list of properties of the current element */ + elems.back().props.push_back( PlyStoredProperty( prop , DONT_STORE_PROP ) ); +} + + +/****************************************************************************** +Add a comment to a PLY file descriptor. + +Entry: +plyfile - PLY file descriptor +line - line containing comment +******************************************************************************/ + +void PlyFile::add_comment( const std::string &line ) +{ + /* skip over "comment" and leading spaces and tabs */ + int i = 7; + while( line[i]==' ' || line[i] =='\t' ) i++; + + put_comment( line.substr(i) ); +} + + +/****************************************************************************** +Add a some object information to a PLY file descriptor. + +Entry: +plyfile - PLY file descriptor +line - line containing text info +******************************************************************************/ + +void PlyFile::add_obj_info( const std::string &line ) +{ + /* skip over "obj_info" and leading spaces and tabs */ + int i = 8; + while( line[i]==' ' || line[i]=='\t' ) i++; + put_obj_info( line.substr(i) ); +} diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/PointStream.h b/modules/PoissonRecon/include/Mesh/PoissonRecon/PointStream.h new file mode 100644 index 00000000..c87eeb13 --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/PointStream.h @@ -0,0 +1,344 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior writften permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +#ifndef POINT_STREAM_INCLUDED +#define POINT_STREAM_INCLUDED + +#include +#include "Mesh/PoissonRecon/Ply.h" +#include "Mesh/PoissonRecon/Geometry.h" + + +template< class Real , unsigned int Dim > +class InputPointStream +{ +public: + virtual ~InputPointStream( void ){} + virtual void reset( void ) = 0; + virtual bool nextPoint( Point< Real , Dim >& p ) = 0; + virtual size_t nextPoints( Point< Real , Dim >* p , size_t count ) + { + size_t c=0; + for( size_t i=0 ; i& min , Point< Real , Dim >& max ) + { + bool first = true; + Point< Real , Dim > p; + while( nextPoint( p ) ) + { + for( unsigned int i=0 ; imax[i] ) max[i] = p[i]; + } + first = false; + } + reset(); + } +}; + +template< class Real , unsigned int Dim > +class OutputPointStream +{ +public: + virtual ~OutputPointStream( void ){} + virtual void nextPoint( const Point< Real , Dim >& p ) = 0; + virtual void nextPoints( const Point< Real , Dim >* p , size_t count ){ for( size_t i=0 ; i +class InputPointStreamWithData : public InputPointStream< Real , Dim > +{ +public: + virtual ~InputPointStreamWithData( void ){} + virtual void reset( void ) = 0; + virtual bool nextPoint( Point< Real , Dim >& p , Data& d ) = 0; + + virtual bool nextPoint( Point< Real , Dim >& p ){ Data d ; return nextPoint( p , d ); } + virtual size_t nextPoints( Point< Real , Dim >* p , Data* d , size_t count ) + { + size_t c=0; + for( size_t i=0 ; i* p , size_t count ){ return InputPointStream< Real , Dim >::nextPoints( p , count ); } +}; + +template< class Real , unsigned int Dim , class Data > +class OutputPointStreamWithData : public OutputPointStream< Real , Dim > +{ +public: + virtual ~OutputPointStreamWithData( void ){} + virtual void nextPoint( const Point< Real , Dim >& p , const Data& d ) = 0; + + virtual void nextPoint( const Point< Real , Dim >& p ){ Data d ; return nextPoint( p , d ); } + virtual void nextPoints( const Point< Real , Dim >* p , const Data* d , size_t count ){ for( size_t i=0 ; i* p , size_t count ){ OutputPointStream< Real , Dim >::nextPoints( p , count ); } +}; + +template< class Real , unsigned int Dim > +class TransformedInputPointStream : public InputPointStream< Real , Dim > +{ + std::function< void ( Point< Real , Dim >& ) > _xForm; + InputPointStream< Real , Dim >& _stream; +public: + TransformedInputPointStream( std::function< void ( Point< Real , Dim >& ) > xForm , InputPointStream< Real , Dim >& stream ) : _xForm(xForm) , _stream(stream) {;} + virtual void reset( void ){ _stream.reset(); } + virtual bool nextPoint( Point< Real , Dim >& p ) + { + bool ret = _stream.nextPoint( p ); + _xForm( p ); + return ret; + } +}; + +template< class Real , unsigned int Dim > +class TransformedOutputPointStream : public OutputPointStream< Real , Dim > +{ + std::function< void ( Point< Real , Dim >& ) > _xForm; + OutputPointStream< Real , Dim >& _stream; +public: + TransformedOutputPointStream( std::function< void ( Point< Real , Dim >& ) > xForm , OutputPointStream< Real , Dim >& stream ) : _xForm(xForm) , _stream(stream) {;} + virtual void reset( void ){ _stream.reset(); } + virtual bool nextPoint( const Point< Real , Dim >& p ) + { + Point< Real , Dim > _p = p; + _xForm( _p ); + return _stream.nextPoint( _p ); + } +}; + +template< class Real , unsigned int Dim , class Data > +class TransformedInputPointStreamWithData : public InputPointStreamWithData< Real , Dim , Data > +{ + std::function< void ( Point< Real , Dim >& , Data& ) > _xForm; + InputPointStreamWithData< Real , Dim , Data >& _stream; +public: + TransformedInputPointStreamWithData( std::function< void ( Point< Real , Dim >& , Data& ) > xForm , InputPointStreamWithData< Real , Dim , Data >& stream ) : _xForm(xForm) , _stream(stream) {;} + virtual void reset( void ){ _stream.reset(); } + virtual bool nextPoint( Point< Real , Dim >& p , Data& d ) + { + bool ret = _stream.nextPoint( p , d ); + _xForm( p , d ); + return ret; + } +}; + +template< class Real , unsigned int Dim , class Data > +class TransformedOutputPointStreamWithData : public OutputPointStreamWithData< Real , Dim , Data > +{ + std::function< void ( Point< Real , Dim >& , Data& ) > _xForm; + OutputPointStreamWithData< Real , Dim , Data >& _stream; +public: + TransformedOutputPointStreamWithData( std::function< void ( Point< Real , Dim >& , Data& ) > xForm , OutputPointStreamWithData< Real , Dim , Data >& stream ) : _xForm(xForm) , _stream(stream) {;} + virtual void nextPoint( const Point< Real , Dim >& p , const Data& d ) + { + Point< Real , Dim > _p = p; + Data _d = d; + _xForm( _p , _d ); + _stream.nextPoint( _p , _d ); + } +}; + +template< class Real , unsigned int Dim > +class MemoryInputPointStream : public InputPointStream< Real , Dim > +{ + const Point< Real , Dim >* _points; + size_t _pointCount; + size_t _current; +public: + MemoryInputPointStream( size_t pointCount , const Point< Real , Dim >* points ); + ~MemoryInputPointStream( void ); + void reset( void ); + bool nextPoint( Point< Real , Dim >& p ); +}; + +template< class Real , unsigned int Dim , class Data > +class MemoryInputPointStreamWithData : public InputPointStreamWithData< Real , Dim , Data > +{ + const std::pair< Point< Real , Dim > , Data >* _points; + size_t _pointCount; + size_t _current; +public: + MemoryInputPointStreamWithData( size_t pointCount , const std::pair< Point< Real , Dim > , Data >* points ); + ~MemoryInputPointStreamWithData( void ); + void reset( void ); + bool nextPoint( Point< Real , Dim >& p , Data& d ); +}; + +template< class Real , unsigned int Dim > +class ASCIIInputPointStream : public InputPointStream< Real , Dim > +{ + FILE* _fp; +public: + ASCIIInputPointStream( const char* fileName ); + ~ASCIIInputPointStream( void ); + void reset( void ); + bool nextPoint( Point< Real , Dim >& p ); +}; + +template< class Real , unsigned int Dim > +class ASCIIOutputPointStream : public OutputPointStream< Real , Dim > +{ + FILE* _fp; +public: + ASCIIOutputPointStream( const char* fileName ); + ~ASCIIOutputPointStream( void ); + void nextPoint( const Point< Real , Dim >& p ); +}; + +template< class Real , unsigned int Dim , class Data > +class ASCIIInputPointStreamWithData : public InputPointStreamWithData< Real , Dim , Data > +{ + FILE* _fp; + void (*_ReadData)( FILE* , Data& ); +public: + ASCIIInputPointStreamWithData( const char* fileName , void (*ReadData)( FILE* , Data& ) ); + ~ASCIIInputPointStreamWithData( void ); + void reset( void ); + bool nextPoint( Point< Real , Dim >& p , Data& d ); +}; + +template< class Real , unsigned int Dim , class Data > +class ASCIIOutputPointStreamWithData : public OutputPointStreamWithData< Real , Dim , Data > +{ + FILE* _fp; + void (*_WriteData)( FILE* , const Data& ); +public: + ASCIIOutputPointStreamWithData( const char* fileName , void (*WriteData)( FILE* , const Data& ) ); + ~ASCIIOutputPointStreamWithData( void ); + void nextPoint( const Point< Real , Dim >& p , const Data& d ); +}; + +template< class Real , unsigned int Dim > +class BinaryInputPointStream : public InputPointStream< Real , Dim > +{ + FILE* _fp; +public: + BinaryInputPointStream( const char* filename ); + ~BinaryInputPointStream( void ){ fclose( _fp ) , _fp=NULL; } + void reset( void ){ fseek( _fp , SEEK_SET , 0 ); } + bool nextPoint( Point< Real , Dim >& p ); +}; +template< class Real , unsigned int Dim > +class BinaryOutputPointStream : public OutputPointStream< Real , Dim > +{ + FILE* _fp; +public: + BinaryOutputPointStream( const char* filename ); + ~BinaryOutputPointStream( void ){ fclose( _fp ) , _fp=NULL; } + void reset( void ){ fseek( _fp , SEEK_SET , 0 ); } + void nextPoint( const Point< Real , Dim >& p ); +}; + +template< class Real , unsigned int Dim , class Data > +class BinaryInputPointStreamWithData : public InputPointStreamWithData< Real , Dim , Data > +{ + FILE* _fp; + void (*_ReadData)( FILE* , Data& ); +public: + BinaryInputPointStreamWithData( const char* filename , void (*ReadData)( FILE* , Data& ) ); + ~BinaryInputPointStreamWithData( void ){ fclose( _fp ) , _fp=NULL; } + void reset( void ){ fseek( _fp , SEEK_SET , 0 ); } + bool nextPoint( Point< Real , Dim >& p , Data& d ); +}; +template< class Real , unsigned int Dim , class Data > +class BinaryOutputPointStreamWithData : public OutputPointStreamWithData< Real , Dim , Data > +{ + FILE* _fp; + void (*_WriteData)( FILE* , const Data& ); +public: + BinaryOutputPointStreamWithData( const char* filename , void (*WriteData)( FILE* , const Data& ) ); + ~BinaryOutputPointStreamWithData( void ){ fclose( _fp ) , _fp=NULL; } + void reset( void ){ fseek( _fp , SEEK_SET , 0 ); } + void nextPoint( const Point< Real , Dim >& p , const Data& d ); +}; + +template< class Real , unsigned int Dim > +class PLYInputPointStream : public InputPointStream< Real , Dim > +{ + char* _fileName; + PlyFile* _ply; + std::vector< std::string > _elist; + + size_t _pCount , _pIdx; + void _free( void ); +public: + PLYInputPointStream( const char* fileName ); + ~PLYInputPointStream( void ); + void reset( void ); + bool nextPoint( Point< Real , Dim >& p ); +}; + +template< class Real , unsigned int Dim , class Data > +class PLYInputPointStreamWithData : public InputPointStreamWithData< Real , Dim , Data > +{ + struct _PlyVertexWithData : public PlyVertex< Real , Dim > { Data data; }; + char* _fileName; + PlyFile* _ply; + std::vector< std::string > _elist; + PlyProperty* _dataProperties; + int _dataPropertiesCount; + bool (*_validationFunction)( const bool* ); + + size_t _pCount , _pIdx; + void _free( void ); +public: + PLYInputPointStreamWithData( const char* fileName , const PlyProperty* dataProperties , int dataPropertiesCount , bool (*validationFunction)( const bool* )=NULL ); + ~PLYInputPointStreamWithData( void ); + void reset( void ); + bool nextPoint( Point< Real , Dim >& p , Data& d ); +}; + +template< class Real , unsigned int Dim > +class PLYOutputPointStream : public OutputPointStream< Real , Dim > +{ + PlyFile* _ply; + size_t _pCount , _pIdx; +public: + PLYOutputPointStream( const char* fileName , size_t count , int fileType ); + ~PLYOutputPointStream( void ); + void nextPoint( const Point< Real , Dim >& p ); +}; + +template< class Real , unsigned int Dim , class Data > +class PLYOutputPointStreamWithData : public OutputPointStreamWithData< Real , Dim , Data > +{ + struct _PlyVertexWithData : public PlyVertex< Real , Dim > { Data data; }; + PlyFile* _ply; + size_t _pCount , _pIdx; +public: + PLYOutputPointStreamWithData( const char* fileName , size_t count , int fileType , const PlyProperty* dataProperties , int dataPropertiesCount ); + ~PLYOutputPointStreamWithData( void ); + void nextPoint( const Point< Real , Dim >& p , const Data& d ); +}; + +#include "Mesh/PoissonRecon/PointStream.inl" +#endif // POINT_STREAM_INCLUDED diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/PointStream.inl b/modules/PoissonRecon/include/Mesh/PoissonRecon/PointStream.inl new file mode 100644 index 00000000..5cafe616 --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/PointStream.inl @@ -0,0 +1,452 @@ +/* +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. +*/ + +//////////////////////////// +// MemoryInputPointStream // +//////////////////////////// +template< class Real , unsigned int Dim > +MemoryInputPointStream< Real , Dim >::MemoryInputPointStream( size_t pointCount , const Point< Real , Dim >* points ){ _points = points , _pointCount = pointCount , _current = 0; } +template< class Real , unsigned int Dim > +MemoryInputPointStream< Real , Dim >::~MemoryInputPointStream( void ){ ; } +template< class Real , unsigned int Dim > +void MemoryInputPointStream< Real , Dim >::reset( void ) { _current=0; } +template< class Real , unsigned int Dim > +bool MemoryInputPointStream< Real , Dim >::nextPoint( Point< Real , Dim >& p ) +{ + if( _current>=_pointCount ) return false; + p = _points[_current]; + _current++; + return true; +} + +/////////////////////////// +// ASCIIInputPointStream // +/////////////////////////// +template< class Real , unsigned int Dim > +ASCIIInputPointStream< Real , Dim >::ASCIIInputPointStream( const char* fileName ) +{ + _fp = fopen( fileName , "r" ); + if( !_fp ) ERROR_OUT( "Failed to open file for reading: %s" , fileName ); +} +template< class Real , unsigned int Dim > +ASCIIInputPointStream< Real , Dim >::~ASCIIInputPointStream( void ) +{ + fclose( _fp ); + _fp = NULL; +} +template< class Real , unsigned int Dim > +void ASCIIInputPointStream< Real , Dim >::reset( void ) { fseek( _fp , SEEK_SET , 0 ); } +template< class Real , unsigned int Dim > +bool ASCIIInputPointStream< Real , Dim >::nextPoint( Point< Real , Dim >& p ) +{ + float c; + for( unsigned int d=0 ; d +ASCIIOutputPointStream< Real , Dim >::ASCIIOutputPointStream( const char* fileName ) +{ + _fp = fopen( fileName , "w" ); + if( !_fp ) ERROR_OUT( "Failed to open file for writing: %s" , fileName ); +} +template< class Real , unsigned int Dim > +ASCIIOutputPointStream< Real , Dim >::~ASCIIOutputPointStream( void ) +{ + fclose( _fp ); + _fp = NULL; +} +template< class Real , unsigned int Dim > +void ASCIIOutputPointStream< Real , Dim >::nextPoint( const Point< Real , Dim >& p ) +{ + for( unsigned int d=0 ; d +BinaryInputPointStream< Real , Dim >::BinaryInputPointStream( const char* fileName ) +{ + _fp = fopen( fileName , "rb" ); + if( !_fp ) ERROR_OUT( "Failed to open file for reading: %s" , fileName ); +} +template< class Real , unsigned int Dim > +bool BinaryInputPointStream< Real , Dim >::nextPoint( Point< Real , Dim >& p ){ return fread( &p , sizeof(Point< Real , Dim >) , 1 , _fp )==1; } + +///////////////////////////// +// BinaryOutputPointStream // +///////////////////////////// +template< class Real , unsigned int Dim > +BinaryOutputPointStream< Real , Dim >::BinaryOutputPointStream( const char* fileName ) +{ + _fp = fopen( fileName , "wb" ); + if( !_fp ) ERROR_OUT( "Failed to open file for writing: %s" , fileName ); +} +template< class Real , unsigned int Dim > +void BinaryOutputPointStream< Real , Dim >::nextPoint( const Point< Real , Dim >& p ){ fwrite( &p , sizeof(Point< Real , Dim >) , 1 , _fp )==1; } + +///////////////////////// +// PLYInputPointStream // +///////////////////////// +template< class Real , unsigned int Dim > +PLYInputPointStream< Real , Dim >::PLYInputPointStream( const char* fileName ) +{ + _fileName = new char[ strlen( fileName )+1 ]; + strcpy( _fileName , fileName ); + _ply = NULL; + reset(); +} +template< class Real , unsigned int Dim > +void PLYInputPointStream< Real , Dim >::reset( void ) +{ + int fileType; + float version; + std::vector< PlyProperty * > plist; + if( _ply ) _free(); + _ply = PlyFile::Read( _fileName, _elist, fileType, version ); + if( !_ply ) ERROR_OUT( "Failed to open ply file for reading: %s" , _fileName ); + + bool foundVertices = false; + for( int i=0 ; i<_elist.size() ; i++ ) + { + size_t num_elems; + std::string &elem_name = _elist[i]; + plist = _ply->get_element_description( elem_name , num_elems ); + if( !plist.size() ) ERROR_OUT( "Failed to get element description: %s" , elem_name ); + + if( elem_name=="vertex" ) + { + foundVertices = true; + _pCount = num_elems , _pIdx = 0; + for( int i=0 ; i::PlyReadNum ; i++ ) + if( !_ply->get_property( elem_name , &(PlyVertex< Real , Dim >::PlyReadProperties()[i]) ) ) ERROR_OUT( "Failed to find property in ply file: %s" , PlyVertex< Real , Dim >::PlyReadProperties()[i].name ); + } + for( int j=0 ; j +void PLYInputPointStream< Real , Dim >::_free( void ){ delete _ply; } + +template< class Real , unsigned int Dim > +PLYInputPointStream< Real , Dim >::~PLYInputPointStream( void ) +{ + _free(); + if( _fileName ) delete[] _fileName , _fileName = NULL; +} +template< class Real , unsigned int Dim > +bool PLYInputPointStream< Real , Dim >::nextPoint( Point< Real , Dim >& p ) +{ + if( _pIdx<_pCount ) + { + PlyVertex< Real , Dim > v; + _ply->get_element( (void *)&v ); + p = v.point; + _pIdx++; + return true; + } + else return false; +} + +//////////////////////////////////// +// MemoryInputPointStreamWithData // +//////////////////////////////////// +template< class Real , unsigned int Dim , class Data > +MemoryInputPointStreamWithData< Real , Dim , Data >::MemoryInputPointStreamWithData( size_t pointCount , const std::pair< Point< Real , Dim > , Data >* points ){ _points = points , _pointCount = pointCount , _current = 0; } +template< class Real , unsigned int Dim , class Data > +MemoryInputPointStreamWithData< Real , Dim , Data >::~MemoryInputPointStreamWithData( void ){ ; } +template< class Real , unsigned int Dim , class Data > +void MemoryInputPointStreamWithData< Real , Dim , Data >::reset( void ) { _current=0; } +template< class Real , unsigned int Dim , class Data > +bool MemoryInputPointStreamWithData< Real , Dim , Data >::nextPoint( Point< Real , Dim >& p , Data& d ) +{ + if( _current>=_pointCount ) return false; + p = _points[_current].first; + d = _points[_current].second; + _current++; + return true; +} + +/////////////////////////////////// +// ASCIIInputPointStreamWithData // +/////////////////////////////////// +template< class Real , unsigned int Dim , class Data > +ASCIIInputPointStreamWithData< Real , Dim , Data >::ASCIIInputPointStreamWithData( const char* fileName , void (*ReadData)( FILE* , Data& ) ) : _ReadData( ReadData ) +{ + _fp = fopen( fileName , "r" ); + if( !_fp ) ERROR_OUT( "Failed to open file for reading: " , fileName ); +} +template< class Real , unsigned int Dim , class Data > +ASCIIInputPointStreamWithData< Real , Dim , Data >::~ASCIIInputPointStreamWithData( void ) +{ + fclose( _fp ); + _fp = NULL; +} +template< class Real , unsigned int Dim , class Data > +void ASCIIInputPointStreamWithData< Real , Dim , Data >::reset( void ) { fseek( _fp , SEEK_SET , 0 ); } +template< class Real , unsigned int Dim , class Data > +bool ASCIIInputPointStreamWithData< Real , Dim , Data >::nextPoint( Point< Real , Dim >& p , Data& d ) +{ + float c; + for( unsigned int dd=0 ; dd +ASCIIOutputPointStreamWithData< Real , Dim , Data >::ASCIIOutputPointStreamWithData( const char* fileName , void (*WriteData)( FILE* , const Data& ) ) : _WriteData( WriteData ) +{ + _fp = fopen( fileName , "w" ); + if( !_fp ) ERROR_OUT( "Failed to open file for writing: %s" , fileName ); +} +template< class Real , unsigned int Dim , class Data > +ASCIIOutputPointStreamWithData< Real , Dim , Data >::~ASCIIOutputPointStreamWithData( void ) +{ + fclose( _fp ); + _fp = NULL; +} +template< class Real , unsigned int Dim , class Data > +void ASCIIOutputPointStreamWithData< Real , Dim , Data >::nextPoint( const Point< Real , Dim >& p , const Data& d ) +{ + for( unsigned int d=0 ; d +BinaryInputPointStreamWithData< Real , Dim , Data >::BinaryInputPointStreamWithData( const char* fileName , void (*ReadData)( FILE* , Data& ) ) : _ReadData(ReadData) +{ + _fp = fopen( fileName , "rb" ); + if( !_fp ) ERROR_OUT( "Failed to open file for reading: " , fileName ); +} +template< class Real , unsigned int Dim , class Data > +bool BinaryInputPointStreamWithData< Real , Dim , Data >::nextPoint( Point< Real , Dim >& p , Data& d ) +{ + if( fread( &p , sizeof(Point< Real , Dim >) , 1 , _fp )==1 ) + { + _ReadData( _fp , d ); + return true; + } + else return false; +} + +///////////////////////////////////// +// BinaryOutputPointStreamWithData // +///////////////////////////////////// +template< class Real , unsigned int Dim , class Data > +BinaryOutputPointStreamWithData< Real , Dim , Data >::BinaryOutputPointStreamWithData( const char* fileName , void (*WriteData)( FILE* , const Data& ) ) : _WriteData(WriteData) +{ + _fp = fopen( fileName , "wb" ); + if( !_fp ) ERROR_OUT( "Failed to open file for writing: " , fileName ); +} +template< class Real , unsigned int Dim , class Data > +void BinaryOutputPointStreamWithData< Real , Dim , Data >::nextPoint( const Point< Real , Dim >& p , const Data& d ) +{ + fwrite( &p , sizeof(Point< Real , Dim >) , 1 , _fp ); + _WriteData( _fp , d ); +} + +///////////////////////////////// +// PLYInputPointStreamWithData // +///////////////////////////////// +template< class Real , unsigned int Dim , class Data > +PLYInputPointStreamWithData< Real , Dim , Data >::PLYInputPointStreamWithData( const char* fileName , const PlyProperty* dataProperties , int dataPropertiesCount , bool (*validationFunction)( const bool* ) ) : _dataPropertiesCount( dataPropertiesCount ) , _validationFunction( validationFunction ) +{ + _dataProperties = new PlyProperty[ _dataPropertiesCount ]; + for( int i=0 ; i ); + _fileName = new char[ strlen( fileName )+1 ]; + strcpy( _fileName , fileName ); + _ply = NULL; + reset(); +} +template< class Real , unsigned int Dim , class Data > +void PLYInputPointStreamWithData< Real , Dim , Data >::reset( void ) +{ + int fileType; + float version; + std::vector< PlyProperty * > plist; + if( _ply ) _free(); + _ply = PlyFile::Read( _fileName , _elist , fileType , version ); + if( !_ply ) ERROR_OUT( "Failed to open ply file for reading: " , _fileName ); + + bool foundVertices = false; + for( int i=0 ; i<_elist.size() ; i++ ) + { + size_t num_elems; + std::string &elem_name = _elist[i]; + plist = _ply->get_element_description( elem_name , num_elems ); + if( !plist.size() ) ERROR_OUT( "Failed to get element description: " , elem_name ); + + if( elem_name=="vertex" ) + { + foundVertices = true; + _pCount = num_elems , _pIdx = 0; + const PlyProperty* PlyReadProperties = PlyVertex< Real , Dim >::PlyReadProperties(); + for( int i=0 ; i::PlyReadNum ; i++ ) + if( !_ply->get_property( elem_name , &(PlyReadProperties[i]) ) ) ERROR_OUT( "Failed to find property in ply file: " , PlyReadProperties[i].name ); + + if( _validationFunction ) + { + bool* properties = new bool[_dataPropertiesCount]; + for( int i=0 ; i<_dataPropertiesCount ; i++ ) + if( !_ply->get_property( elem_name , &(_dataProperties[i]) ) ) properties[i] = false; + else properties[i] = true; + bool valid = _validationFunction( properties ); + delete[] properties; + if( !valid ) ERROR_OUT( "Failed to validate properties in file" ); + } + else + { + for( int i=0 ; i<_dataPropertiesCount ; i++ ) + if( !_ply->get_property( elem_name , &(_dataProperties[i]) ) ) WARN( "Failed to find property in ply file: " , _dataProperties[i].name ); + } + } + for( int j=0 ; j +void PLYInputPointStreamWithData< Real , Dim , Data >::_free( void ){ delete _ply; } + +template< class Real , unsigned int Dim , class Data > +PLYInputPointStreamWithData< Real , Dim , Data >::~PLYInputPointStreamWithData( void ) +{ + _free(); + if( _fileName ) delete[] _fileName , _fileName = NULL; + if( _dataProperties ) delete[] _dataProperties , _dataProperties = NULL; +} +template< class Real , unsigned int Dim , class Data > +bool PLYInputPointStreamWithData< Real , Dim , Data >::nextPoint( Point< Real , Dim >& p , Data& d ) +{ + if( _pIdx<_pCount ) + { + _PlyVertexWithData v; + _ply->get_element( (void*) &v ); + p = v.point; + d = v.data; + _pIdx++; + return true; + } + else return false; +} + +////////////////////////// +// PLYOutputPointStream // +////////////////////////// +template< class Real , unsigned int Dim > +PLYOutputPointStream< Real , Dim >::PLYOutputPointStream( const char* fileName , size_t count , int fileType ) +{ + 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 ); + + _pIdx = 0; + _pCount = count; + _ply->element_count( "vertex" , _pCount ); + for( int i=0 ; i::WriteComponents ; i++ ) _ply->describe_property( "vertex" , &PlyVertex< Real , Dim >::WriteProperties()[i] ); + _ply->header_complete(); + _ply->put_element_setup( "vertex" ); +} +template< class Real , unsigned int Dim > +PLYOutputPointStream< Real , Dim >::~PLYOutputPointStream( void ) +{ + if( _pIdx!=_pCount ) ERROR_OUT( "Streamed points not equal to total count: " , _pIdx , " != " , _pCount ); + delete _ply; +} +template< class Real , unsigned int Dim > +void PLYOutputPointStream< Real , Dim >::nextPoint( const Point< Real , Dim >& p ) +{ + if( _pIdx==_pCount ) ERROR_OUT( "Trying to add more points than total: " , _pIdx , " < " , _pCount ); + PlyVertex< Real , Dim > op; + op.point = p; + _ply->put_element( (void *)&op ); + _pIdx++; +} + +////////////////////////////////// +// PLYOutputPointStreamWithData // +////////////////////////////////// +template< class Real , unsigned int Dim , class Data > +PLYOutputPointStreamWithData< Real , Dim , Data >::PLYOutputPointStreamWithData( const char* fileName , size_t count , int fileType , const PlyProperty* dataProperties , int dataPropertiesCount ) +{ + 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 ); + + _pIdx = 0; + _pCount = count; + _ply->element_count( "vertex" , _pCount ); + for( int i=0 ; i::PlyWriteNum ; i++ ) _ply->describe_property( "vertex" , &PlyVertex< Real , Dim >::PlyWriteProperties()[i] ); + for( int i=0 ; i ); + _ply->describe_property( "vertex" , &prop ); + } + + _ply->header_complete(); + _ply->put_element_setup( "vertex" ); +} +template< class Real , unsigned int Dim , class Data > +PLYOutputPointStreamWithData< Real , Dim , Data >::~PLYOutputPointStreamWithData( void ) +{ + if( _pIdx!=_pCount ) ERROR_OUT( "Streamed points not equal to total count: " , _pIdx , " != " , _pCount ); + delete _ply; +} +template< class Real , unsigned int Dim , class Data > +void PLYOutputPointStreamWithData< Real , Dim , Data >::nextPoint( const Point< Real , Dim >& p , const Data& d ) +{ + if( _pIdx==_pCount ) ERROR_OUT( "Trying to add more points than total: " , _pIdx , " < " , _pCount ); + _PlyVertexWithData op; + op.point = p; + op.data = d; + _ply->put_element( (void *)&op ); + _pIdx++; +} + diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/PointStreamData.h b/modules/PoissonRecon/include/Mesh/PoissonRecon/PointStreamData.h new file mode 100644 index 00000000..3a0cf9f7 --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/PointStreamData.h @@ -0,0 +1,513 @@ +/* +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 POINT_STREAM_DATA_INCLUDED +#define POINT_STREAM_DATA_INCLUDED + +#include +#include +#include "Mesh/PoissonRecon/Ply.h" + +template< class Real > using Color = Point< Real , 3 >; +template< class Real > void SetColorValues( const Color< Real >& color , unsigned char c[3] ){ for( int i=0 ; i<3 ; i++ ) c[i] = (unsigned char)std::max< int >( 0 , std::min< int >( 255 , (int)( color[i]+0.5 ) ) ); } +template< class Real > void SetColorValues( const Color< Real >& color , RGBColor& c ){ for( int i=0 ; i<3 ; i++ ) c[i] = (unsigned char)std::max< int >( 0 , std::min< int >( 255 , (int)( color[i]+0.5 ) ) ); } + +// Should have: +// -- binary operators for vectors +// -- static ReadASCII +// -- static WriteASCII +// -- static ReadBinary +// -- static WriteBinary +// -- static ValidPlyReadProperties( const bool* ) method +// -- static int PlyReadNum +// -- static int PlyWriteNum +// -- static const PlyProperty* PlyReadProperties() +// -- static const PlyProperty* PlyWriteProperties() +// -- a nested class Transform which gets initialized by something and acts on the data +template< typename Real , typename Data > +struct PointStreamData +{ + static const int PlyReadNum; + static const int PlyWriteNum; + static const PlyProperty* PlyReadProperties( void ); + static const PlyProperty* PlyWriteProperties( void ); + static bool ValidPlyReadProperties( const bool* flags ); + + typedef Data type; + Data psData; + + PointStreamData& operator += ( const PointStreamData& p ){ psData += p.psData ; return *this; } + PointStreamData& operator -= ( const PointStreamData& p ){ psData -= p.psData ; return *this; } + PointStreamData& operator *= ( Real s ) { psData *= s ; return *this; } + PointStreamData& operator /= ( Real s ) { psData /= s ; return *this; } + PointStreamData operator + ( const PointStreamData& p ) const { PointStreamData _p = *this ; _p += p ; return _p; } + PointStreamData operator - ( const PointStreamData& p ) const { PointStreamData _p = *this ; _p -= p ; return _p; } + PointStreamData operator * ( Real s ) const { PointStreamData _p = *this ; _p *= s ; return _p; } + PointStreamData operator / ( Real s ) const { PointStreamData _p = *this ; _p /= s ; return _p; } + + // Returns access to the data + Data &data( void ){ return psData; } + const Data &data( void ) const { return psData; } +}; +template< class Real , unsigned int Dim > +struct PointStreamPosition : public PointStreamData< Real , Point< Real , Dim > > +{ + struct Transform + { + Transform( void ){} + Transform( const XForm< Real , Dim+1 >& xForm ) : _xForm(xForm) { } + PointStreamPosition operator() ( const PointStreamPosition& p ) const + { + PointStreamPosition _p; + _p.psData = _xForm * p.psData; + return _p; + } + protected: + XForm< Real , Dim+1 > _xForm; + }; + static void ReadASCII( FILE* fp , PointStreamPosition& p ) + { + float f; + for( int i=0 ; i +const PlyProperty PointStreamPosition< float , 2 >::_PlyProperties[] = +{ + PlyProperty( "x" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamPosition , psData.coords[0] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "y" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamPosition , psData.coords[1] ) ) , 0 , 0 , 0 , 0 ) , +}; +template<> +const PlyProperty PointStreamPosition< double , 2 >::_PlyProperties[] = +{ + PlyProperty( "x" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamPosition , psData.coords[0] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "y" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamPosition , psData.coords[1] ) ) , 0 , 0 , 0 , 0 ) , +}; +template<> +const PlyProperty PointStreamPosition< float , 3 >::_PlyProperties[] = +{ + PlyProperty( "x" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamPosition , psData.coords[0] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "y" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamPosition , psData.coords[1] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "z" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamPosition , psData.coords[2] ) ) , 0 , 0 , 0 , 0 ) , +}; +template<> +const PlyProperty PointStreamPosition< double , 3 >::_PlyProperties[] = +{ + PlyProperty( "x" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamPosition , psData.coords[0] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "y" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamPosition , psData.coords[1] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "z" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamPosition , psData.coords[2] ) ) , 0 , 0 , 0 , 0 ) , +}; +template<> +const PlyProperty PointStreamPosition< float , 4 >::_PlyProperties[] = +{ + PlyProperty( "x" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamPosition , psData.coords[0] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "y" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamPosition , psData.coords[1] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "z" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamPosition , psData.coords[2] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "w" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamPosition , psData.coords[3] ) ) , 0 , 0 , 0 , 0 ) , +}; +template<> +const PlyProperty PointStreamPosition< double , 4 >::_PlyProperties[] = +{ + PlyProperty( "x" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamPosition , psData.coords[0] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "y" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamPosition , psData.coords[1] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "z" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamPosition , psData.coords[2] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "w" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamPosition , psData.coords[3] ) ) , 0 , 0 , 0 , 0 ) , +}; + +template< class Real , unsigned int Dim > +struct PointStreamNormal : public PointStreamData< Real , Point< Real , Dim > > +{ + struct Transform + { + Transform( void ){} + Transform( const XForm< Real , Dim+1 >& xForm ) + { + for( int i=0 ; i _xForm; + }; + static void ReadASCII( FILE* fp , PointStreamNormal& p ) + { + float f; + for( int i=0 ; i +const PlyProperty PointStreamNormal< float , 2 >::_PlyProperties[] = +{ + PlyProperty( "nx" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamNormal , psData.coords[0] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "ny" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamNormal , psData.coords[1] ) ) , 0 , 0 , 0 , 0 ) , +}; +template<> +const PlyProperty PointStreamNormal< double , 2 >::_PlyProperties[] = +{ + PlyProperty( "nx" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamNormal , psData.coords[0] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "ny" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamNormal , psData.coords[1] ) ) , 0 , 0 , 0 , 0 ) , +}; +template<> +const PlyProperty PointStreamNormal< float , 3 >::_PlyProperties[] = +{ + PlyProperty( "nx" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamNormal , psData.coords[0] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "ny" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamNormal , psData.coords[1] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "nz" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamNormal , psData.coords[2] ) ) , 0 , 0 , 0 , 0 ) , +}; +template<> +const PlyProperty PointStreamNormal< double , 3 >::_PlyProperties[] = +{ + PlyProperty( "nx" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamNormal , psData.coords[0] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "ny" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamNormal , psData.coords[1] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "nz" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamNormal , psData.coords[2] ) ) , 0 , 0 , 0 , 0 ) , +}; +template<> +const PlyProperty PointStreamNormal< float , 4 >::_PlyProperties[] = +{ + PlyProperty( "nx" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamNormal , psData.coords[0] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "ny" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamNormal , psData.coords[1] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "nz" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamNormal , psData.coords[2] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "nw" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamNormal , psData.coords[3] ) ) , 0 , 0 , 0 , 0 ) , +}; +template<> +const PlyProperty PointStreamNormal< double , 4 >::_PlyProperties[] = +{ + PlyProperty( "nx" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamNormal , psData.coords[0] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "ny" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamNormal , psData.coords[1] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "nz" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamNormal , psData.coords[2] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "nw" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamNormal , psData.coords[3] ) ) , 0 , 0 , 0 , 0 ) , +}; + +template< class Real > +struct PointStreamColor : public PointStreamData< Real , Color< Real > > +{ + struct Transform + { + Transform( void ){} + template< typename X > Transform( const X& ){} + PointStreamColor operator() ( const PointStreamColor& c ) const { return c; } + }; + static void ReadASCII( FILE* fp , PointStreamColor& p ) + { + unsigned int c[3]; + if( fscanf( fp , " %d %d %d " , &c[0] , &c[1] , &c[2] )!=3 ) ERROR_OUT( "Failed to read color" ); + p.psData[0] = (Real)c[0] , p.psData[1] = (Real)c[1] , p.psData[2] = (Real)c[2]; + }; + static void ReadBinary( FILE* fp , PointStreamColor& p ) + { + unsigned char c[3]; + if( fread( c , sizeof(unsigned char) , 3 , fp )!=3 ) ERROR_OUT( "Failed to read color" ); + p.psData[0] = (Real)c[0] , p.psData[1] = (Real)c[1] , p.psData[2] = (Real)c[2]; + } + static void WriteASCII( FILE* fp , const PointStreamColor& p ) + { + unsigned char c[3]; + SetColorValues( p.psData , c ); + fprintf( fp , " %d %d %d " , c[0] , c[1] , c[2] ); + }; + static void WriteBinary( FILE* fp , const PointStreamColor& p ) + { + unsigned char c[3]; + SetColorValues( p.psData , c ); + fwrite( c , sizeof(unsigned char) , 3 , fp ); + } + + static const int PlyReadNum = 6; + static const int PlyWriteNum = 3; + static const PlyProperty* PlyReadProperties( void ){ return _PlyProperties; } + static const PlyProperty* PlyWriteProperties( void ){ return _PlyProperties; } + static bool ValidPlyReadProperties( const bool* flags ){ for( int d=0 ; d<3 ; d++ ) if( !flags[d] && !flags[d+3] ) return false ; return true ; } +protected: + static const PlyProperty _PlyProperties[]; +}; +template<> +const PlyProperty PointStreamColor< float >::_PlyProperties[] = +{ + PlyProperty( "red" , PLY_UCHAR , PLY_FLOAT , int( offsetof( PointStreamColor , psData.coords[0] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "green" , PLY_UCHAR , PLY_FLOAT , int( offsetof( PointStreamColor , psData.coords[1] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "blue" , PLY_UCHAR , PLY_FLOAT , int( offsetof( PointStreamColor , psData.coords[2] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "r" , PLY_UCHAR , PLY_FLOAT , int( offsetof( PointStreamColor , psData.coords[0] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "g" , PLY_UCHAR , PLY_FLOAT , int( offsetof( PointStreamColor , psData.coords[1] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "b" , PLY_UCHAR , PLY_FLOAT , int( offsetof( PointStreamColor , psData.coords[2] ) ) , 0 , 0 , 0 , 0 ) , +}; +template<> +const PlyProperty PointStreamColor< double >::_PlyProperties[] = +{ + PlyProperty( "red" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( PointStreamColor , psData.coords[0] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "green" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( PointStreamColor , psData.coords[1] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "blue" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( PointStreamColor , psData.coords[2] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "r" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( PointStreamColor , psData.coords[0] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "g" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( PointStreamColor , psData.coords[1] ) ) , 0 , 0 , 0 , 0 ) , + PlyProperty( "b" , PLY_UCHAR , PLY_DOUBLE , int( offsetof( PointStreamColor , psData.coords[2] ) ) , 0 , 0 , 0 , 0 ) , +}; + +template< class Real > +struct PointStreamValue : public PointStreamData< Real , Real > +{ + struct Transform + { + Transform( void ){} + template< typename X > Transform( const X& ){} + PointStreamValue operator() ( const PointStreamValue& r ) const { return r; } + }; + static void ReadASCII ( FILE* fp , PointStreamValue& p ){ float f ; if( fscanf( fp , " %f " , &f )!=1 ) ERROR_OUT( "Failed to read color" ) ; p.psData = (Real)f; } + static void ReadBinary( FILE* fp , PointStreamValue& p ){ float f ; if( fread( &f , sizeof(float) , 1 , fp )!=1 ) ERROR_OUT( "Failed to read color" ) ; p.psData = (Real)f; } + static void WriteASCII ( FILE* fp , const PointStreamValue& p ){ float f = (float)p.psData ; fprintf( fp , " %f " , f ); } + static void WriteBinary( FILE* fp , const PointStreamValue& p ){ float f = (float)p.psData ; fwrite( &f , sizeof(Real) , 1 , fp ); } + static const int PlyReadNum = 1; + static const int PlyWriteNum = 1; + static const PlyProperty* PlyReadProperties( void ){ return _PlyProperties; } + static const PlyProperty* PlyWriteProperties( void ){ return _PlyProperties; } + static bool ValidPlyReadProperties( const bool* flags ){ if( !flags[0] ) return false ; return true ; } +public: + static const PlyProperty _PlyProperties[]; +}; +template<> +const PlyProperty PointStreamValue< float >::_PlyProperties[] = +{ + PlyProperty( "value" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamValue , psData ) ) , 0 , 0 , 0 , 0 ) , +}; +template<> +const PlyProperty PointStreamValue< double >::_PlyProperties[] = +{ + PlyProperty( "value" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamValue , psData ) ) , 0 , 0 , 0 , 0 ) , +}; + +template< class Real > +struct PointStreamRoughness : public PointStreamData< Real , Real > +{ + struct Transform + { + Transform( void ){} + template< typename X > Transform( const X& ){} + PointStreamRoughness operator() ( const PointStreamRoughness& r ) const { return r; } + }; + static void ReadASCII ( FILE* fp , PointStreamRoughness& p ){ float f ; if( fscanf( fp , " %f " , &f )!=1 ) ERROR_OUT( "Failed to read color" ) ; p.psData = (Real)f; } + static void ReadBinary( FILE* fp , PointStreamRoughness& p ){ float f ; if( fread( &f , sizeof(float) , 1 , fp )!=1 ) ERROR_OUT( "Failed to read color" ) ; p.psData = (Real)f; } + static void WriteASCII ( FILE* fp , const PointStreamRoughness& p ){ float f = (float)p.psData ; fprintf( fp , " %f " , f ); } + static void WriteBinary( FILE* fp , const PointStreamRoughness& p ){ float f = (float)p.psData ; fwrite( &f , sizeof(Real) , 1 , fp ); } + static const int PlyReadNum = 1; + static const int PlyWriteNum = 1; + static const PlyProperty* PlyReadProperties( void ){ return _PlyProperties; } + static const PlyProperty* PlyWriteProperties( void ){ return _PlyProperties; } + static bool ValidPlyReadProperties( const bool* flags ){ if( !flags[0] ) return false ; return true ; } +public: + static const PlyProperty _PlyProperties[]; +}; +template<> +const PlyProperty PointStreamRoughness< float >::_PlyProperties[] = +{ + PlyProperty( "rg" , PLY_FLOAT , PLY_FLOAT , int( offsetof( PointStreamRoughness , psData ) ) , 0 , 0 , 0 , 0 ) , +}; +template<> +const PlyProperty PointStreamRoughness< double >::_PlyProperties[] = +{ + PlyProperty( "rg" , PLY_FLOAT , PLY_DOUBLE , int( offsetof( PointStreamRoughness , psData ) ) , 0 , 0 , 0 , 0 ) , +}; + +template< typename Real , typename ... Data > +struct MultiPointStreamData : public PointStreamData< Real , std::tuple< Data ... > > +{ + typedef std::tuple< Data ... > MultiData; + using PointStreamData< Real , MultiData >::psData; + template< unsigned int I > using DataType = typename std::tuple_element< I , MultiData >::type; + + struct Transform + { + Transform( void ){} + template< typename X > + Transform( const X& x ){ _initTransforms<0>( x ); } + MultiPointStreamData operator() ( const MultiPointStreamData& d ) const + { + MultiPointStreamData _d; + _transform<0>( d , _d ); + return _d; + } + protected: + typedef std::tuple< typename Data::Transform ... > Transforms; + template< unsigned int I > using TransformType = typename std::tuple_element< I , Transforms >::type; + Transforms _xForms; + private: + template< unsigned int I , typename X > + typename std::enable_if< I!=sizeof...(Data) >::type _initTransforms( const X& x ){ std::get< I >( _xForms ) = TransformType< I >( x ) ; _initTransforms< I+1 >( x ); } + template< unsigned int I , typename X > + typename std::enable_if< I==sizeof...(Data) >::type _initTransforms( const X& x ){ } + template< unsigned int I > + typename std::enable_if< I!=sizeof...(Data) >::type _transform( const MultiPointStreamData& in , MultiPointStreamData& out ) const { std::get< I >( out.psData ) = std::get< I >( _xForms )( std::get< I >( in.psData ) ) ; _transform< I+1 >( in , out ); } + template< unsigned int I > + typename std::enable_if< I==sizeof...(Data) >::type _transform( const MultiPointStreamData& in , MultiPointStreamData& out ) const { } + }; + + static void ReadASCII ( FILE* fp , MultiPointStreamData& p ){ p._readASCII <0>( fp ); } + static void ReadBinary( FILE* fp , MultiPointStreamData& p ){ p._readBinary<0>( fp ); } + static void WriteASCII ( FILE* fp , const MultiPointStreamData& p ){ p._writeASCII <0>( fp ); } + static void WriteBinary( FILE* fp , const MultiPointStreamData& p ){ p._writeBinary<0>( fp ); } + + MultiPointStreamData& operator += ( const MultiPointStreamData& p ){ _add<0>( p ) ; return *this; } + MultiPointStreamData& operator -= ( const MultiPointStreamData& p ){ _sub<0>( p ) ; return *this; } + MultiPointStreamData& operator *= ( Real s ) { _mul<0>( s ) ; return *this; } + MultiPointStreamData& operator /= ( Real s ) { _div<0>( s ) ; return *this; } + MultiPointStreamData operator + ( const MultiPointStreamData& p ) const { MultiPointStreamData _p = *this ; _p += p ; return _p; } + MultiPointStreamData operator - ( const MultiPointStreamData& p ) const { MultiPointStreamData _p = *this ; _p -= p ; return _p; } + MultiPointStreamData operator * ( Real s ) const { MultiPointStreamData _p = *this ; _p *= s ; return _p; } + MultiPointStreamData operator / ( Real s ) const { MultiPointStreamData _p = *this ; _p /= s ; return _p; } + + template< unsigned int I > using _DataType = typename std::tuple_element< I , MultiData >::type::type; + + MultiData &data( void ){ return psData; } + const MultiData &data( void ) const { return psData; } + template< unsigned int I > _DataType< I > &data( void ) { return std::get< I >( psData ).psData; } + template< unsigned int I > const _DataType< I > &data( void ) const { return std::get< I >( psData ).psData; } +private: + template< unsigned int I > static constexpr typename std::enable_if< I!=sizeof...(Data) , int >::type _PlyTotalReadNum( void ){ return DataType< I >::PlyReadNum + _PlyTotalReadNum< I+1 >(); } + template< unsigned int I > static constexpr typename std::enable_if< I==sizeof...(Data) , int >::type _PlyTotalReadNum( void ){ return 0; } + template< unsigned int I > static constexpr typename std::enable_if< I!=sizeof...(Data) , int >::type _PlyTotalWriteNum( void ){ return DataType< I >::PlyWriteNum + _PlyTotalWriteNum< I+1 >(); } + template< unsigned int I > static constexpr typename std::enable_if< I==sizeof...(Data) , int >::type _PlyTotalWriteNum( void ){ return 0; } +public: + static const int PlyReadNum = _PlyTotalReadNum<0>(); + static const int PlyWriteNum = _PlyTotalWriteNum<0>(); + static PlyProperty* PlyReadProperties( void ){ _SetPlyReadProperties<0>( _PlyReadProperties ) ; return _PlyReadProperties; } + static PlyProperty* PlyWriteProperties( void ){ _SetPlyWriteProperties<0>( _PlyWriteProperties ) ; return _PlyWriteProperties; } + + static bool ValidPlyReadProperties( const bool* flags ){ return _ValidPlyReadProperties<0>( flags ) ; } + template< unsigned int I > static bool ValidPlyReadProperties( const bool* flags ){ return DataType< I >::ValidPlyReadProperties( flags + _PlyReadOffset< I >() ); } +protected: + static PlyProperty _PlyReadProperties[]; + static PlyProperty _PlyWriteProperties[]; +private: + // Gives the offset to the I-th element + template< unsigned int I > static typename std::enable_if< I==0 , unsigned int >::type _PlyReadOffset( void ){ return 0; } + template< unsigned int I > static typename std::enable_if< I!=0 , unsigned int >::type _PlyReadOffset( void ){ return DataType< I-1 >::PlyReadNum + _PlyReadOffset< I-1 >(); } + + template< unsigned int I > typename std::enable_if< I!=sizeof...(Data) >::type _readASCII ( FILE* fp ) { DataType< I >:: ReadASCII ( fp , std::get< I >( psData ) ) ; _readASCII < I+1 >( fp ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Data) >::type _readASCII ( FILE* fp ) { } + template< unsigned int I > typename std::enable_if< I!=sizeof...(Data) >::type _readBinary( FILE* fp ) { DataType< I >:: ReadBinary( fp , std::get< I >( psData ) ) ; _readBinary< I+1 >( fp ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Data) >::type _readBinary( FILE* fp ) { } + template< unsigned int I > typename std::enable_if< I!=sizeof...(Data) >::type _writeASCII ( FILE* fp ) const { DataType< I >::WriteASCII ( fp , std::get< I >( psData ) ) ; _writeASCII < I+1 >( fp ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Data) >::type _writeASCII ( FILE* fp ) const { } + template< unsigned int I > typename std::enable_if< I!=sizeof...(Data) >::type _writeBinary( FILE* fp ) const { DataType< I >::WriteBinary( fp , std::get< I >( psData ) ) ; _writeBinary< I+1 >( fp ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Data) >::type _writeBinary( FILE* fp ) const { } + + template< unsigned int I > typename std::enable_if< I!=sizeof...(Data) >::type _add( const MultiPointStreamData& p ){ std::get< I >( psData ) += std::get< I >( p.psData ) ; _add< I+1 >( p ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Data) >::type _add( const MultiPointStreamData& p ){ } + template< unsigned int I > typename std::enable_if< I!=sizeof...(Data) >::type _sub( const MultiPointStreamData& p ){ std::get< I >( psData ) -= std::get< I >( p.psData ) ; _sub< I+1 >( p ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Data) >::type _sub( const MultiPointStreamData& p ){ } + template< unsigned int I > typename std::enable_if< I!=sizeof...(Data) >::type _mul( Real s ){ std::get< I >( psData ) *= s ; _mul< I+1 >( s ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Data) >::type _mul( Real s ){ } + template< unsigned int I > typename std::enable_if< I!=sizeof...(Data) >::type _div( Real s ){ std::get< I >( psData ) /= s ; _div< I+1 >( s ); } + template< unsigned int I > typename std::enable_if< I==sizeof...(Data) >::type _div( Real s ){ } + + template< unsigned int I > static typename std::enable_if< I!=sizeof...(Data) >::type _SetPlyReadProperties( PlyProperty* PlyReadProperties ) + { + for( int d=0 ; d::PlyReadNum ; d++ ) + { + PlyReadProperties[d] = DataType< I >::PlyReadProperties()[d]; + MultiPointStreamData temp; + const typename std::tuple_element< I , MultiData >::type& temp_data = std::get< I >( temp.psData ); + PlyReadProperties[d].offset += (int)( (size_t)&temp_data - (size_t)&temp ); + } + _SetPlyReadProperties< I+1 >( PlyReadProperties + DataType< I >::PlyReadNum ); + } + template< unsigned int I > static typename std::enable_if< I==sizeof...(Data) >::type _SetPlyReadProperties( PlyProperty* PlyReadProperties ){ } + template< unsigned int I > static typename std::enable_if< I!=sizeof...(Data) >::type _SetPlyWriteProperties( PlyProperty* PlyWriteProperties ) + { + for( int d=0 ; d::PlyWriteNum ; d++ ) + { + PlyWriteProperties[d] = DataType< I >::PlyWriteProperties()[d]; + MultiPointStreamData temp; + const typename std::tuple_element< I , MultiData >::type& temp_data = std::get< I >( temp.psData ); + PlyWriteProperties[d].offset += (int)( (size_t)&temp_data - (size_t)&temp ); + } + _SetPlyWriteProperties< I+1 >( PlyWriteProperties + DataType< I >::PlyWriteNum ); + } + template< unsigned int I > static typename std::enable_if< I==sizeof...(Data) >::type _SetPlyWriteProperties( PlyProperty* PlyWriteProperties ){ } + + template< unsigned int I > static typename std::enable_if< I!=sizeof...(Data) , bool >::type _ValidPlyReadProperties( const bool* flags ){ return DataType< I >::ValidPlyReadProperties( flags ) && _ValidPlyReadProperties< I+1 >( flags + std::tuple_element< I , MultiData >::type::PlyReadNum ); } + template< unsigned int I > static typename std::enable_if< I==sizeof...(Data) , bool >::type _ValidPlyReadProperties( const bool* flags ){ return true; } +}; +template< typename Real , typename ... Data > PlyProperty MultiPointStreamData< Real , Data ... >::_PlyReadProperties[ MultiPointStreamData< Real , Data ... >::PlyReadNum==0 ? 1 : MultiPointStreamData< Real , Data ... >::PlyReadNum ]; +template< typename Real , typename ... Data > PlyProperty MultiPointStreamData< Real , Data ... >::_PlyWriteProperties[ MultiPointStreamData< Real , Data ... >::PlyWriteNum==0 ? 1 : MultiPointStreamData< Real , Data ... >::PlyWriteNum ]; + +#endif // POINT_STREAM_DATA_INCLUDED \ No newline at end of file diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/PoissonRecon.h b/modules/PoissonRecon/include/Mesh/PoissonRecon/PoissonRecon.h new file mode 100644 index 00000000..30cd8968 --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/PoissonRecon.h @@ -0,0 +1,873 @@ + +/* +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 POISSONRECON_INCLUDED +#define POISSONRECON_INCLUDED + +#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 DIMENSION 3 // The dimension of the system + +#include +#include +#include +#include +#include "Mesh/PoissonRecon/MyMiscellany.h" +#include "Mesh/PoissonRecon/CmdLineParser.h" +#include "Mesh/PoissonRecon/PPolynomial.h" +#include "Mesh/PoissonRecon/FEMTree.h" +#include "Mesh/PoissonRecon/Ply.h" +#include "Mesh/PoissonRecon/PointStreamData.h" +#include "Mesh/PoissonRecon/Image.h" + +class PoissonRecon +{ + public: +MessageWriter messageWriter; + +const float DefaultPointWeightMultiplier = 2.f; + +cmdLineParameter< char* > + In{ "in" } , + Out{ "out" } , + TempDir{ "tempDir" } , + Grid{ "grid" } , + Tree{ "tree" } , + Transform{ "xForm" }; + +cmdLineReadable + Performance{ "performance" } , + ShowResidual{ "showResidual" } , + NoComments{ "noComments" } , + PolygonMesh{ "polygonMesh" } , + NonManifold{ "nonManifold" } , + ASCII{ "ascii" } , + Density{ "density" } , + LinearFit{ "linearFit" } , + PrimalGrid{ "primalGrid" } , + ExactInterpolation{ "exact" } , + Normals{ "normals" } , + Colors{ "colors" } , + InCore{ "inCore" } , + Verbose{ "verbose" }; + +cmdLineParameter< int > +#ifndef FAST_COMPILE + Degree{ "degree" , DEFAULT_FEM_DEGREE } , +#endif // !FAST_COMPILE + Depth{ "depth" , 8 } , + KernelDepth{ "kernelDepth" } , + Iters{ "iters" , 8 } , + FullDepth{ "fullDepth" , 5 } , + BaseDepth{ "baseDepth" , 0 } , + BaseVCycles{ "baseVCycles" , 1 } , +#ifndef FAST_COMPILE + BType{ "bType" , DEFAULT_FEM_BOUNDARY+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 + ScheduleType{ "schedule" , (int)ThreadPool::DefaultSchedule } , + ThreadChunkSize{ "chunkSize" , (int)ThreadPool::DefaultChunkSize } , + Threads{ "threads" , (int)std::thread::hardware_concurrency() }; + +cmdLineParameter< float > + DataX{ "data" , 32.f } , + SamplesPerNode{ "samplesPerNode" , 1.5f } , + Scale{ "scale" , 1.1f } , + Width{ "width" , 0.f } , + Confidence{ "confidence" , 0.f } , + ConfidenceBias{ "confidenceBias" , 0.f } , + CGSolverAccuracy{ "cgAccuracy" , 1e-3f } , + PointWeight{ "pointWeight" }; + +cmdLineReadable* params[42] = +{ +#ifndef FAST_COMPILE + &Degree , &BType , +#endif // !FAST_COMPILE + &In , &Depth , &Out , &Transform , + &Width , + &Scale , &Verbose , &CGSolverAccuracy , &NoComments , + &KernelDepth , &SamplesPerNode , &Confidence , &NonManifold , &PolygonMesh , &ASCII , &ShowResidual , + &ConfidenceBias , + &BaseDepth , &BaseVCycles , + &PointWeight , + &Grid , &Threads , + &Tree , + &Density , + &FullDepth , + &Iters , + &DataX , + &Colors , + &Normals , + &LinearFit , + &PrimalGrid , + &TempDir , + &ExactInterpolation , + &Performance , + &MaxMemoryGB , + &InCore , + &ParallelType , + &ScheduleType , + &ThreadChunkSize , + 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" , Grid.name ); + printf( "\t[--%s ]\n" , Tree.name ); +#ifndef FAST_COMPILE + printf( "\t[--%s =%d]\n" , Degree.name , Degree.value ); + printf( "\t[--%s =%d]\n" , BType.name , BType.value ); + for( int i=0 ; i=%d]\n" , Depth.name , Depth.value ); + printf( "\t[--%s ]\n" , Width.name ); + printf( "\t[--%s =%d]\n" , FullDepth.name , FullDepth.value ); + printf( "\t[--%s =%d]\n" , BaseDepth.name , BaseDepth.value ); + 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 ); + 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]\n" , Normals.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 ); + 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]\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" , Performance.name ); + printf( "\t[--%s]\n" , Density.name ); + printf( "\t[--%s]\n" , LinearFit.name ); + printf( "\t[--%s]\n" , PrimalGrid.name ); + printf( "\t[--%s]\n" , ASCII.name ); + printf( "\t[--%s]\n" , NoComments.name ); + printf( "\t[--%s]\n" , TempDir.name ); + printf( "\t[--%s]\n" , InCore.name ); + printf( "\t[--%s]\n" , Verbose.name ); +} + +double Weight( double v , double start , double end ) +{ + v = ( v - start ) / ( end - start ); + if ( v<0 ) return 1.; + else if( v>1 ) return 0.; + else + { + // P(x) = a x^3 + b x^2 + c x + d + // P (0) = 1 , P (1) = 0 , P'(0) = 0 , P'(1) = 0 + // => d = 1 , a + b + c + d = 0 , c = 0 , 3a + 2b + c = 0 + // => c = 0 , d = 1 , a + b = -1 , 3a + 2b = 0 + // => a = 2 , b = -3 , c = 0 , d = 1 + // => P(x) = 2 x^3 - 3 x^2 + 1 + return 2. * v * v * v - 3. * v * v + 1.; + } +} + +template< unsigned int Dim , class Real > +struct FEMTreeProfiler +{ + FEMTree< Dim , Real >& tree; + double t; + PoissonRecon* poisson = new PoissonRecon(); + + 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) / %9.1f (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) / %9.1f (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 ) poisson->messageWriter( "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); + else poisson->messageWriter( "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (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 ) poisson->messageWriter( comments , "%s %9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (MB)\n" , header , Time()-t , FEMTree< Dim , Real >::LocalMemoryUsage() , FEMTree< Dim , Real >::MaxMemoryUsage() , MemoryInfo::PeakMemoryUsageMB() ); + else poisson->messageWriter( comments , "%9.1f (s), %9.1f (MB) / %9.1f (MB) / %9.1f (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 +XForm< Real , Dim+1 > GetPointXForm( InputPointStream< Real , Dim >& stream , Real width , Real scaleFactor , int& depth ) +{ + Point< Real , Dim > min , max; + stream.boundingBox( min , max ); + return GetBoundingBoxXForm( min , max , width , scaleFactor , depth ); +} +template< class Real , unsigned int Dim > +XForm< Real , Dim+1 > GetPointXForm( InputPointStream< Real , Dim >& stream , Real scaleFactor ) +{ + Point< Real , Dim > min , max; + stream.boundingBox( 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 Vertex , typename Real , typename SetVertexFunction , unsigned int ... FEMSigs , typename ... SampleData > +void ExtractMesh( UIntPack< FEMSigs ... > , std::tuple< SampleData ... > , FEMTree< sizeof ... ( FEMSigs ) , Real >& tree , const DenseNodeData< Real , UIntPack< FEMSigs ... > >& solution , Real isoValue , const std::vector< typename FEMTree< sizeof ... ( FEMSigs ) , Real >::PointSample >* samples , std::vector< MultiPointStreamData< Real , PointStreamNormal< Real , DIMENSION > , MultiPointStreamData< Real , SampleData ... > > >* sampleData , const typename FEMTree< sizeof ... ( FEMSigs ) , Real >::template DensityEstimator< WEIGHT_DEGREE >* density , const SetVertexFunction &SetVertex , std::vector< std::string > &comments , XForm< Real , sizeof...(FEMSigs)+1 > iXForm ) +{ + static const int Dim = sizeof ... ( FEMSigs ); + typedef UIntPack< FEMSigs ... > Sigs; + typedef PointStreamNormal< Real , Dim > NormalPointSampleData; + typedef MultiPointStreamData< Real , SampleData ... > AdditionalPointSampleData; + typedef MultiPointStreamData< Real , NormalPointSampleData , AdditionalPointSampleData > TotalPointSampleData; + static const unsigned int DataSig = FEMDegreeAndBType< DATA_DEGREE , BOUNDARY_FREE >::Signature; + typedef typename FEMTree< Dim , Real >::template DensityEstimator< WEIGHT_DEGREE > DensityEstimator; + + FEMTreeProfiler< Dim , Real > profiler( tree ); + + char tempHeader[1024]; + { + char tempPath[1024]; + tempPath[0] = 0; + if( TempDir.set ) strcpy( tempPath , TempDir.value ); + else SetTempDirectory( tempPath , sizeof(tempPath) ); + if( strlen(tempPath)==0 ) sprintf( tempPath , ".%c" , FileSeparator ); + if( tempPath[ strlen( tempPath )-1 ]==FileSeparator ) sprintf( tempHeader , "%sPR_" , tempPath ); + else sprintf( tempHeader , "%s%cPR_" , tempPath , FileSeparator ); + } + CoredMeshData< Vertex , node_index_type > *mesh; + if( InCore.set ) mesh = new CoredVectorMeshData< Vertex , node_index_type >(); + else mesh = new CoredFileMeshData< Vertex , node_index_type >( tempHeader ); + + profiler.start(); + typename IsoSurfaceExtractor< Dim , Real , Vertex >::IsoStats isoStats; + if( sampleData ) + { + SparseNodeData< ProjectiveData< TotalPointSampleData , Real > , IsotropicUIntPack< Dim , DataSig > > _sampleData = tree.template setMultiDepthDataField< 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 ) ) + { + ProjectiveData< TotalPointSampleData , Real >* clr = _sampleData( n ); + if( clr ) (*clr) *= (Real)pow( DataX.value , tree.depth( n ) ); + } + isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< TotalPointSampleData >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , &_sampleData , solution , isoValue , *mesh , SetVertex , !LinearFit.set , !NonManifold.set , PolygonMesh.set , false ); + } +#if defined( __GNUC__ ) && __GNUC__ < 5 +#warning "you've got me gcc version<5" + else isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< TotalPointSampleData >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , (SparseNodeData< ProjectiveData< TotalPointSampleData , Real > , IsotropicUIntPack< Dim , DataSig > > *)NULL , solution , isoValue , *mesh , SetVertex , !LinearFit.set , !NonManifold.set , PolygonMesh.set , false ); +#else // !__GNUC__ || __GNUC__ >=5 + else isoStats = IsoSurfaceExtractor< Dim , Real , Vertex >::template Extract< TotalPointSampleData >( Sigs() , UIntPack< WEIGHT_DEGREE >() , UIntPack< DataSig >() , tree , density , NULL , solution , isoValue , *mesh , SetVertex , !LinearFit.set , !NonManifold.set , PolygonMesh.set , false ); +#endif // __GNUC__ || __GNUC__ < 4 + messageWriter( "Vertices / Polygons: %llu / %llu\n" , (unsigned long long)( mesh->outOfCorePointCount()+mesh->inCorePoints.size() ) , (unsigned long long)mesh->polygonCount() ); + std::string isoStatsString = isoStats.toString() + std::string( "\n" ); + messageWriter( isoStatsString.c_str() ); + + if( Verbose.set ) + { + if( PolygonMesh.set ) profiler.dumpOutput2( comments , "# Got polygons:" ); + else profiler.dumpOutput2( comments , "# Got triangles:" ); + } + + std::vector< std::string > noComments; + if( !PlyWritePolygons< Vertex , node_index_type , Real , Dim >( Out.value , mesh , ASCII.set ? PLY_ASCII : PLY_BINARY_NATIVE , NoComments.set ? noComments : comments , iXForm ) ) + ERROR_OUT( "Could not write mesh to: " , Out.value ); + + delete mesh; +} + +template< typename Real , unsigned int Dim > +void WriteGrid( ConstPointer( Real ) values , int res , const char *fileName ) +{ + int resolution = 1; + for( int d=0 ; d avgs( ThreadPool::NumThreads() , 0 ); + ThreadPool::Parallel_for( 0 , resolution , [&]( unsigned int thread , size_t i ){ avgs[thread] += values[i]; } ); + for( unsigned int t=0 ; t stds( ThreadPool::NumThreads() , 0 ); + ThreadPool::Parallel_for( 0 , resolution , [&]( 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 ); + + unsigned char *pixels = new unsigned char[ resolution*3 ]; + ThreadPool::Parallel_for( 0 , resolution , [&]( 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 + { + + FILE *fp = fopen( fileName , "wb" ); + if( !fp ) ERROR_OUT( "Failed to open grid file for writing: " , fileName ); + else + { + fwrite( &res , sizeof(int) , 1 , fp ); + if( typeid(Real)==typeid(float) ) fwrite( values , sizeof(float) , resolution , fp ); + else + { + float *fValues = new float[resolution]; + for( int i=0 ; i +void Execute( int argc , char* argv[] , UIntPack< FEMSigs ... > ) +{ + 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; + typedef PointStreamNormal< Real , Dim > NormalPointSampleData; + typedef MultiPointStreamData< Real , SampleData ... > AdditionalPointSampleData; + typedef MultiPointStreamData< Real , NormalPointSampleData , AdditionalPointSampleData > TotalPointSampleData; + typedef InputPointStreamWithData< Real , Dim , TotalPointSampleData > InputPointStream; + typedef TransformedInputPointStreamWithData< Real , Dim , TotalPointSampleData > XInputPointStream; + std::vector< 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 ); + + + XForm< Real , Dim+1 > xForm , iXForm; + if( Transform.set ) + { + FILE* fp = fopen( Transform.value , "r" ); + if( !fp ) + { + WARN( "Could not read x-form from: " , Transform.value ); + xForm = XForm< Real , Dim+1 >::Identity(); + } + else + { + for( int i=0 ; i::Identity(); + + 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 ); + } + + double startTime = Time(); + Real isoValue = 0; + + FEMTree< Dim , Real > tree( MEMORY_ALLOCATOR_BLOCK_SIZE ); + FEMTreeProfiler< Dim , Real > profiler( tree ); + + if( Depth.set && Width.value>0 ) + { + WARN( "Both --" , Depth.name , " and --" , Width.name , " set, ignoring --" , Width.name ); + Width.value = 0; + } + + size_t pointCount; + + Real pointWeightSum; + std::vector< typename FEMTree< Dim , Real >::PointSample >* samples = new std::vector< typename FEMTree< Dim , Real >::PointSample >(); + std::vector< TotalPointSampleData >* sampleData = NULL; + DensityEstimator* density = NULL; + SparseNodeData< Point< Real , Dim > , NormalSigs >* normalInfo = NULL; + Real targetValue = (Real)0.5; + + // Read in the samples (and color data) + { + profiler.start(); + InputPointStream* pointStream; + char* ext = GetFileExtension( In.value ); + sampleData = new std::vector< TotalPointSampleData >(); + std::vector< std::pair< Point< Real , Dim > , TotalPointSampleData > > inCorePoints; + if( InCore.set ) + { + InputPointStream *_pointStream; + if ( !strcasecmp( ext , "bnpts" ) ) _pointStream = new BinaryInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::ReadBinary ); + else if( !strcasecmp( ext , "ply" ) ) _pointStream = new PLYInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::PlyReadProperties() , TotalPointSampleData::PlyReadNum , TotalPointSampleData::ValidPlyReadProperties ); + else _pointStream = new ASCIIInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::ReadASCII ); + Point< Real , Dim > p; + TotalPointSampleData d; + while( _pointStream->nextPoint( p , d ) ) inCorePoints.push_back( std::pair< Point< Real , Dim > , TotalPointSampleData >( p , d ) ); + delete _pointStream; + + pointStream = new MemoryInputPointStreamWithData< Real , Dim , TotalPointSampleData >( inCorePoints.size() , &inCorePoints[0] ); + } + else + { + if ( !strcasecmp( ext , "bnpts" ) ) pointStream = new BinaryInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::ReadBinary ); + else if( !strcasecmp( ext , "ply" ) ) pointStream = new PLYInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::PlyReadProperties() , TotalPointSampleData::PlyReadNum , TotalPointSampleData::ValidPlyReadProperties ); + else pointStream = new ASCIIInputPointStreamWithData< Real , Dim , TotalPointSampleData >( In.value , TotalPointSampleData::ReadASCII ); + } + delete[] ext; + typename TotalPointSampleData::Transform _xForm( xForm ); + XInputPointStream _pointStream( [&]( Point< Real , Dim >& p , TotalPointSampleData& d ){ p = xForm*p , d = _xForm(d); } , *pointStream ); + if( Width.value>0 ) xForm = GetPointXForm< Real , Dim >( _pointStream , Width.value , (Real)( Scale.value>0 ? Scale.value : 1. ) , Depth.value ) * xForm; + else xForm = Scale.value>0 ? GetPointXForm< Real , Dim >( _pointStream , (Real)Scale.value ) * xForm : xForm; + { + typename TotalPointSampleData::Transform _xForm( xForm ); + XInputPointStream _pointStream( [&]( Point< Real , Dim >& p , TotalPointSampleData& d ){ p = xForm*p , d = _xForm(d); } , *pointStream ); + auto ProcessDataWithConfidence = [&]( const Point< Real , Dim >& p , TotalPointSampleData& d ) + { + Real l = (Real)Length( d.template data<0>() ); + if( !l || l!=l ) return (Real)-1.; + return (Real)pow( l , Confidence.value ); + }; + auto ProcessData = []( const Point< Real , Dim >& p , TotalPointSampleData& d ) + { + Real l = (Real)Length( d.template data<0>() ); + if( !l || l!=l ) return (Real)-1.; + d.template data<0>() /= l; + return (Real)1.; + }; + if( Confidence.value>0 ) pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< TotalPointSampleData >( tree.spaceRoot() , _pointStream , Depth.value , *samples , *sampleData , true , tree.nodeAllocators[0] , tree.initializer() , ProcessDataWithConfidence ); + else pointCount = FEMTreeInitializer< Dim , Real >::template Initialize< TotalPointSampleData >( tree.spaceRoot() , _pointStream , Depth.value , *samples , *sampleData , true , tree.nodeAllocators[0] , tree.initializer() , ProcessData ); + } + iXForm = xForm.inverse(); + delete pointStream; + + messageWriter( "Input Points / Samples: %llu / %llu\n" , (unsigned long long)pointCount , (unsigned long long)samples->size() ); + if( Verbose.set ) profiler.dumpOutput2( comments , "# Read input into tree:" ); + } + 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; + { + DenseNodeData< Real , Sigs > constraints; + InterpolationInfo* iInfo = NULL; + int solveDepth = Depth.value; + + tree.resetNodeIndices(); + + // Get the kernel density estimator + { + profiler.start(); + density = tree.template setDensityEstimator< WEIGHT_DEGREE >( *samples , kernelDepth , SamplesPerNode.value , 1 ); + if( Verbose.set ) profiler.dumpOutput2( comments , "# Got kernel density:" ); + } + + // Transform the Hermite samples into a vector field + { + profiler.start(); + normalInfo = new SparseNodeData< Point< Real , Dim > , NormalSigs >(); + std::function< bool ( TotalPointSampleData , Point< Real , Dim >& ) > ConversionFunction = []( TotalPointSampleData in , Point< Real , Dim > &out ) + { + Point< Real , Dim > n = in.template data<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 ( TotalPointSampleData , Point< Real , Dim >& , Real & ) > ConversionAndBiasFunction = [this]( TotalPointSampleData in , Point< Real , Dim > &out , Real &bias ) + { + Point< Real , Dim > n = in.template data<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.setDataField( NormalSigs() , *samples , *sampleData , density , pointWeightSum , ConversionAndBiasFunction ); + else *normalInfo = tree.setDataField( NormalSigs() , *samples , *sampleData , density , pointWeightSum , ConversionFunction ); ThreadPool::Parallel_for( 0 , normalInfo->size() , [&]( unsigned int , size_t i ){ (*normalInfo)[i] *= (Real)-1.; } ); + if( Verbose.set ) profiler.dumpOutput2( comments , "# Got normal field:" ); + if( Verbose.set ) messageWriter( "Point weight / Estimated Area: %g / %g\n" , pointWeightSum , pointCount*pointWeightSum ); + } + + + if( !Density.set ) delete density , density = NULL; + if( DataX.value<=0 || ( !Colors.set && !Normals.set ) ) delete sampleData , sampleData = NULL; + + // Trim the tree and prepare for multigrid + { + profiler.start(); + constexpr int MAX_DEGREE = NORMAL_DEGREE > Degrees::Max() ? NORMAL_DEGREE : Degrees::Max(); + tree.template finalizeForMultigrid< MAX_DEGREE >( FullDepth.value , typename FEMTree< Dim , Real >::template HasNormalDataFunctor< NormalSigs >( *normalInfo ) , normalInfo , density ); + if( Verbose.set ) profiler.dumpOutput2( comments , "# Finalized tree:" ); + } + // Add the FEM constraints + { + profiler.start(); + 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 ) profiler.dumpOutput2( comments , "# Set FEM constraints:" ); + } + + // Free up the normal info + delete normalInfo , normalInfo = NULL; + + // 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 ); + tree.addInterpolationConstraints( constraints , solveDepth , *iInfo ); + if( Verbose.set ) profiler.dumpOutput2( comments , "#Set point constraints:" ); + } + + 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) ); + + // Solve the linear system + { + profiler.start(); + 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.baseDepth = BaseDepth.value , sInfo.baseVCycles = BaseVCycles.value; + typename FEMIntegrator::template System< Sigs , IsotropicUIntPack< Dim , 1 > > F( { 0. , 1. } ); + solution = tree.solveSystem( Sigs() , F , constraints , solveDepth , sInfo , iInfo ); + if( Verbose.set ) profiler.dumpOutput2( comments , "# Linear system solved:" ); + if( iInfo ) delete iInfo , iInfo = NULL; + } + } + + { + profiler.start(); + 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::WriteParameter( fp ); + DenseNodeData< Real , Sigs >::WriteSignatures( fp ); + tree.write( fp , xForm ); + solution.write( fp ); + fclose( fp ); + } + + if( Grid.set ) + { + int res = 0; + profiler.start(); + Pointer( Real ) values = tree.template regularGridEvaluate< true >( solution , res , -1 , PrimalGrid.set ); + size_t resolution = 1; + for( int d=0 ; d( values , res , Grid.value ); + DeletePointer( values ); + if( Verbose.set ) + { + printf( "Transform:\n" ); + for( int i=0 ; i , PointStreamValue< Real > , AdditionalPointSampleData > > Vertex; + auto SetVertex = []( Vertex& v , Point< Real , Dim > p , Real w , TotalPointSampleData d ){ v.point = p , v.data.template data<0>() = d.template data<0>() , v.data.template data<1>() = w , v.data.template data<2>() = d.template data<1>(); }; + ExtractMesh< Vertex >( UIntPack< FEMSigs ... >() , std::tuple< SampleData ... >() , tree , solution , isoValue , samples , sampleData , density , SetVertex , comments , iXForm ); + } + else + { + typedef PlyVertexWithData< Real , Dim , MultiPointStreamData< Real , PointStreamNormal< Real , Dim > , AdditionalPointSampleData > > Vertex; + auto SetVertex = []( Vertex& v , Point< Real , Dim > p , Real w , TotalPointSampleData d ){ v.point = p , v.data.template data<0>() = d.template data<0>() , v.data.template data<1>() = d.template data<1>(); }; + ExtractMesh< Vertex >( UIntPack< FEMSigs ... >() , std::tuple< SampleData ... >() , tree , solution , isoValue , samples , sampleData , density , SetVertex , comments , iXForm ); + } + } + else + { + if( Density.set ) + { + typedef PlyVertexWithData< Real , Dim , MultiPointStreamData< Real , PointStreamValue< Real > , AdditionalPointSampleData > > Vertex; + std::function< void ( Vertex& , Point< Real , Dim > , Real , TotalPointSampleData ) > SetVertex = []( Vertex& v , Point< Real , Dim > p , Real w , TotalPointSampleData d ){ v.point = p , v.data.template data<0>() = w , v.data.template data<1>() = d.template data<1>(); }; + ExtractMesh< Vertex >( UIntPack< FEMSigs ... >() , std::tuple< SampleData ... >() , tree , solution , isoValue , samples , sampleData , density , SetVertex , comments , iXForm ); + } + else + { + typedef PlyVertexWithData< Real , Dim , MultiPointStreamData< Real , AdditionalPointSampleData > > Vertex; + auto SetVertex = []( Vertex& v , Point< Real , Dim > p , Real w , TotalPointSampleData d ){ v.point = p , v.data.template data<0>() = d.template data<1>(); }; + ExtractMesh< Vertex >( UIntPack< FEMSigs ... >() , std::tuple< SampleData ... >() , tree , solution , isoValue , samples , sampleData , density , SetVertex , comments , iXForm ); + } + } + if( sampleData ){ delete sampleData ; sampleData = NULL; } + } + if( density ) delete density , density = NULL; + messageWriter( comments , "# Total Solve: %9.1f (s), %9.1f (MB)\n" , Time()-startTime , FEMTree< Dim , Real >::MaxMemoryUsage() ); +} + +#ifndef FAST_COMPILE +template< unsigned int Dim , class Real , typename ... SampleData > +void Execute( int argc , char* argv[] ) +{ + switch( BType.value ) + { + case BOUNDARY_FREE+1: + { + switch( Degree.value ) + { + case 1: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 1 , BOUNDARY_FREE >::Signature >() ); + case 2: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BOUNDARY_FREE >::Signature >() ); +// case 3: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BOUNDARY_FREE >::Signature >() ); +// case 4: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BOUNDARY_FREE >::Signature >() ); + default: ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); + } + } + case BOUNDARY_NEUMANN+1: + { + switch( Degree.value ) + { + case 1: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 1 , BOUNDARY_NEUMANN >::Signature >() ); + case 2: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BOUNDARY_NEUMANN >::Signature >() ); +// case 3: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BOUNDARY_NEUMANN >::Signature >() ); +// case 4: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BOUNDARY_NEUMANN >::Signature >() ); + default: ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); + } + } + case BOUNDARY_DIRICHLET+1: + { + switch( Degree.value ) + { + case 1: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 1 , BOUNDARY_DIRICHLET >::Signature >() ); + case 2: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 2 , BOUNDARY_DIRICHLET >::Signature >() ); +// case 3: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 3 , BOUNDARY_DIRICHLET >::Signature >() ); +// case 4: return Execute< Real , SampleData ... >( argc , argv , IsotropicUIntPack< Dim , FEMDegreeAndBType< 4 , BOUNDARY_DIRICHLET >::Signature >() ); + default: ERROR_OUT( "Only B-Splines of degree 1 - 2 are supported" ); + } + } + default: ERROR_OUT( "Not a valid boundary type: %d" , BType.value ); + } +} +#endif // !FAST_COMPILE + + int reconstruct(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 + 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 ); + + messageWriter.echoSTDOUT = Verbose.set; + if( !In.set ) + { + ShowUsage( argv[0] ); + return 0; + } + if( DataX.value<=0 ) Normals.set = Colors.set = false; + 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; + } + +#ifdef USE_DOUBLE + typedef double Real; +#else // !USE_DOUBLE + typedef float Real; +#endif // USE_DOUBLE + +#ifdef FAST_COMPILE + 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_" ); + if( !PointWeight.set ) PointWeight.value = DefaultPointWeightMultiplier*Degree; + if( Colors.set ) Execute< Real , PointStreamColor< Real > >( argc , argv , FEMSigs() ); + else Execute< Real >( argc , argv , FEMSigs() ); +#else // !FAST_COMPILE + if( !PointWeight.set ) PointWeight.value = DefaultPointWeightMultiplier*Degree.value; + if( Colors.set ) Execute< DIMENSION , Real , PointStreamColor< float > >( argc , argv ); + else Execute< DIMENSION , Real >( argc , argv ); +#endif // FAST_COMPILE + if( Performance.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; + } +}; + +#endif // POISSONRECON_INCLUDED diff --git a/Src/Polynomial.h b/modules/PoissonRecon/include/Mesh/PoissonRecon/Polynomial.h similarity index 85% rename from Src/Polynomial.h rename to modules/PoissonRecon/include/Mesh/PoissonRecon/Polynomial.h index 397b7bdb..670f5825 100644 --- a/Src/Polynomial.h +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/Polynomial.h @@ -29,19 +29,14 @@ DAMAGE. #ifndef POLYNOMIAL_INCLUDED #define POLYNOMIAL_INCLUDED -#define NEW_POLYNOMIAL_CODE 1 - -#include - template< int Degree > class Polynomial { public: double coefficients[Degree+1]; - Polynomial(void); - template - Polynomial(const Polynomial& P); + Polynomial( void ); + template< int Degree2 > Polynomial( const Polynomial< Degree2 >& P ); double operator()( double t ) const; double integral( double tMin , double tMax ) const; @@ -72,13 +67,20 @@ class Polynomial Polynomial scale( double s ) const; Polynomial shift( double t ) const; - Polynomial derivative(void) const; - Polynomial integral(void) 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; + 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); @@ -86,7 +88,6 @@ class Polynomial static void AddScaled(const Polynomial& p1,const Polynomial& p2,double w2,Polynomial& q); static void AddScaled(const Polynomial& p1,double w1,const Polynomial& p2,Polynomial& q); - void getSolutions(double c,std::vector& roots,double EPS) const; int getSolutions( double c , double* roots , double EPS ) const; // [NOTE] Both of these methods define the indexing according to DeBoor's algorithm, so that @@ -96,5 +97,5 @@ class Polynomial static void BinomialCoefficients( int bCoefficients[Degree+1] ); }; -#include "Polynomial.inl" +#include "Mesh/PoissonRecon/Polynomial.inl" #endif // POLYNOMIAL_INCLUDED diff --git a/Src/Polynomial.inl b/modules/PoissonRecon/include/Mesh/PoissonRecon/Polynomial.inl similarity index 88% rename from Src/Polynomial.inl rename to modules/PoissonRecon/include/Mesh/PoissonRecon/Polynomial.inl index ea7ae504..f28b93a6 100644 --- a/Src/Polynomial.inl +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/Polynomial.inl @@ -29,7 +29,7 @@ DAMAGE. #include #include #include -#include "Factor.h" +#include "Mesh/PoissonRecon/Factor.h" //////////////// // Polynomial // @@ -53,13 +53,6 @@ Polynomial& Polynomial::operator = (const Polynomial & return *this; } -template -Polynomial Polynomial::derivative(void) const{ - Polynomial p; - for(int i=0;i Polynomial Polynomial::integral(void) const{ Polynomial p; @@ -67,10 +60,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 +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< int Degree > double Polynomial::operator() ( double t ) const{ double v=coefficients[Degree]; for( int d=Degree-1 ; d>=0 ; d-- ) v = v*t + coefficients[d]; @@ -261,38 +254,10 @@ void Polynomial::printnl(void) const{ } printf("\n"); } -template -void Polynomial::getSolutions(double c,std::vector& roots,double EPS) const -{ - double r[4][2]; - int rCount=0; - roots.clear(); - switch(Degree){ - case 1: - rCount=Factor(coefficients[1],coefficients[0]-c,r,EPS); - break; - case 2: - rCount=Factor(coefficients[2],coefficients[1],coefficients[0]-c,r,EPS); - break; - case 3: - rCount=Factor(coefficients[3],coefficients[2],coefficients[1],coefficients[0]-c,r,EPS); - break; -// case 4: -// rCount=Factor(coefficients[4],coefficients[3],coefficients[2],coefficients[1],coefficients[0]-c,r,EPS); -// break; - default: - printf("Can't solve polynomial of degree: %d\n",Degree); - } - for(int i=0;i int Polynomial::getSolutions( double c , double* roots , double EPS ) const { - double _roots[4][2]; + std::complex< double > _roots[4]; int _rCount=0; switch( Degree ) { @@ -303,7 +268,7 @@ int Polynomial::getSolutions( double c , double* roots , double EPS ) co default: printf( "Can't solve polynomial of degree: %d\n" , Degree ); } int rCount = 0; - for( int i=0 ; i<_rCount ; i++ ) if( fabs(_roots[i][1])<=EPS ) roots[rCount++] = _roots[i][0]; + for( int i=0 ; i<_rCount ; i++ ) if( fabs( _roots[i].imag() )<=EPS ) roots[rCount++] = _roots[i].real(); return rCount; } // The 0-th order B-spline diff --git a/Src/Factor.h b/modules/PoissonRecon/include/Mesh/PoissonRecon/PreProcessor.h similarity index 53% rename from Src/Factor.h rename to modules/PoissonRecon/include/Mesh/PoissonRecon/PreProcessor.h index d6ee4b20..c07380dd 100644 --- a/Src/Factor.h +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/PreProcessor.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +Copyright (c) 2019, Michael Kazhdan and Matthew Bolitho All rights reserved. Redistribution and use in source and binary forms, with or without modification, @@ -26,25 +26,25 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S DAMAGE. */ -#ifndef FACTOR_INCLUDED -#define FACTOR_INCLUDED +#ifndef PRE_PROCESSOR_INCLUDED +#define PRE_PROCESSOR_INCLUDED -#define PI 3.1415926535897932384 -#define SQRT_3 1.7320508075688772935 +#undef BIG_DATA // Supports processing requiring more than 32-bit integers for indexing + // Note: enabling BIG_DATA can generate .ply files using "longlong" for vertex indices instead of "int". + // These are not standardly supported by .ply reading/writing applications. + // 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 +#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) -double ArcTan2(double y,double x); -double Angle(const double in[2]); -void Sqrt(const double in[2],double out[2]); -void Add(const double in1[2],const double in2[2],double out[2]); -void Subtract(const double in1[2],const double in2[2],double out[2]); -void Multiply(const double in1[2],const double in2[2],double out[2]); -void Divide(const double in1[2],const double in2[2],double out[2]); +#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 -int Factor(double a1,double a0,double roots[1][2],double EPS); -int Factor(double a2,double a1,double a0,double roots[2][2],double EPS); -int Factor(double a3,double a2,double a1,double a0,double roots[3][2],double EPS); -int Factor(double a4,double a3,double a2,double a1,double a0,double roots[4][2],double EPS); +#define VERSION "12.00" // The version of the code +#define MEMORY_ALLOCATOR_BLOCK_SIZE 1<<12 // The chunk size for memory allocation -int Solve(const double* eqns,const double* values,double* solutions, int dim); - -#endif // FACTOR_INCLUDED \ No newline at end of file +#endif // PRE_PROCESSOR_INCLUDED \ No newline at end of file diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/RegularTree.h b/modules/PoissonRecon/include/Mesh/PoissonRecon/RegularTree.h new file mode 100644 index 00000000..98bff23c --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/RegularTree.h @@ -0,0 +1,343 @@ +/* +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 REGULAR_TREE_NODE_INCLUDED +#define REGULAR_TREE_NODE_INCLUDED + +#include +#include "Mesh/PoissonRecon/Allocator.h" +#include "Mesh/PoissonRecon/BinaryNode.h" +#include "Mesh/PoissonRecon/Window.h" + +template< unsigned int Dim , class NodeData , class DepthAndOffsetType > +struct RegularTreeNode +{ +private: + DepthAndOffsetType _depth , _offset[Dim]; + template< typename Initializer > + 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 ); + + // 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; + 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; + + 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 ); + + 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 ); + + 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 ) + { + auto initializer = []( RegularTreeNode & ){}; + return read( fp , 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 ... > > + { + 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 ... > > + { + 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 ); + } + + }; + + 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 ); + }; + 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; + }; + + int width( int maxDepth ) const; +}; + +#include "Mesh/PoissonRecon/RegularTree.inl" + +#endif // REGULAR_TREE_NODE_INCLUDED diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/RegularTree.inl b/modules/PoissonRecon/include/Mesh/PoissonRecon/RegularTree.inl new file mode 100644 index 00000000..22db7aa8 --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/RegularTree.inl @@ -0,0 +1,837 @@ +/* +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 "Mesh/PoissonRecon/MyMiscellany.h" + +///////////////////// +// RegularTreeNode // +///////////////////// +template< unsigned int Dim , class NodeData , class DepthAndOffsetType > +RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::RegularTreeNode( void ) +{ + parent = children = NULL; + _depth = 0; + memset( _offset , 0 , sizeof(_offset ) ); +} +template< unsigned int Dim , class NodeData , class DepthAndOffsetType > +template< typename Initializer > +RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::RegularTreeNode( Initializer &initializer ) : RegularTreeNode() { initializer( *this ); } + +template< unsigned int Dim , class NodeData , class DepthAndOffsetType > +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::cleanChildren( bool deleteChildren ) +{ + if( children ) + { + for( int c=0 ; c<(1< +RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::~RegularTreeNode(void) +{ +#ifdef SHOW_WARNINGS +#pragma message( "[WARNING] Deallocation of children is your responsibility" ) +#endif // SHOW_WARNINGS + parent = children = NULL; +} +template< unsigned int Dim , class NodeData , class DepthAndOffsetType > +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<>d) & 1; + } + return brood; +} +template< unsigned int Dim , class NodeData , class DepthAndOffsetType > +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ResetDepthAndOffset( RegularTreeNode* root , int d , int off[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] ) + { + if( !current ) return root; + else if( current->children ) + { + ChildDepthAndOffset( d , off ); + return current->children; + } + 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]; + } +} + +template< unsigned int Dim , class NodeData , class DepthAndOffsetType > +template< typename Initializer > +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::setFullDepth( int maxDepth , Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ) +{ + if( maxDepth>0 ) + { + if( !children ) initChildren< false >( nodeAllocator , initializer ); + 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<>d) & 1 ); + } + return true; +} +template< unsigned int Dim , class NodeData , class DepthAndOffsetType > +template< typename Initializer > +bool RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::_initChildren_s( Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ) +{ + RegularTreeNode * volatile & children = this->children; + RegularTreeNode *_children; + + // Allocate the children + if( nodeAllocator ) _children = nodeAllocator->newElements( 1<>d) & 1 ); + // [WARNING] We are assuming that it's OK to initialize nodes that may not be used. + for( int idx=0 ; idx<(1< +template< class MergeFunctor > +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::merge( RegularTreeNode* node , MergeFunctor& f ) +{ + if( node ) + { + nodeData = f( nodeData , node->nodeData ); + if( children && node->children ) for( int c=0 ; c<(1<children[c] , f ); + else if( node->children ) + { + children = node->children; + for( int c=0 ; c<(1<children = NULL; + } + } +} + +template< unsigned int Dim , class NodeData , class DepthAndOffsetType > +inline void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::depthAndOffset( int& depth , int offset[Dim] ) const +{ + depth = _depth; + for( int d=0 ; d +inline void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::centerIndex( int index[Dim] ) const +{ + for( int i=0 ; i +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 +{ + width = Real( 1.0 / (1<<_depth) ); + for( int d=0 ; d +template< class Real > +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::startAndWidth( Point< Real , Dim >& start , Real& width ) const +{ + width = Real( 1.0 / (1<<_depth) ); + for( int d=0 ; d +template< class Real > +bool RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::isInside( Point< Real , Dim > p ) const +{ + Point< Real , Dim > c ; Real w; + centerAndWidth( c , w ) , w /= 2; + for( int d=0 ; d(c[d]+w) ) return false; + return true; +} + +template< unsigned int Dim , class NodeData , class DepthAndOffsetType > +int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::maxDepth(void) const +{ + if( !children ) return 0; + else + { + int c , d; + for( int i=0 ; i<(1<c ) c=d; + } + return c+1; + } +} +template< unsigned int Dim , class NodeData , class DepthAndOffsetType > +size_t RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::nodes( void ) const +{ + if( !children ) return 1; + else + { + size_t c=0; + for( int i=0 ; i<(1< +size_t RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::leaves( void ) const +{ + if( !children ) return 1; + else + { + size_t c=0; + for( int i=0 ; i<(1< +size_t RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::maxDepthLeaves( int maxDepth ) const +{ + if( depth()>maxDepth ) return 0; + if( !children ) return 1; + else + { + size_t c=0; + for( int i=0 ; i<(1< +const RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::root( void ) const +{ + const RegularTreeNode* temp = this; + 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 +{ + 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; +} +template< unsigned int Dim , class NodeData , class DepthAndOffsetType > +const RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::prevBranch( const RegularTreeNode* current ) const +{ + 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 > +RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::prevBranch( RegularTreeNode* current ) +{ + 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) + { + const RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* temp=this; + while( temp->children ) temp = temp->children; + return temp; + } + if( current->children ) return current->nextLeaf(); + const RegularTreeNode* temp=nextBranch( current ); + if( !temp ) return NULL; + else return temp->nextLeaf(); +} +template< unsigned int Dim , class NodeData , class DepthAndOffsetType > +RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::nextLeaf(RegularTreeNode* current){ + if( !current ) + { + RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* temp=this; + while( temp->children ) temp = temp->children; + return temp; + } + if( current->children ) return current->nextLeaf(); + RegularTreeNode* temp=nextBranch( current) ; + if( !temp ) return NULL; + else return temp->nextLeaf(); +} +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 +{ + if( !current ) return this; + else if( current->children && !ntl(current) ) return current->children; + else return nextBranch( current ); +} +template< unsigned int Dim , class NodeData , class DepthAndOffsetType > +template< typename NodeTerminationLambda > +RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::nextNode( NodeTerminationLambda &ntl , RegularTreeNode* current ) +{ + if( !current ) return this; + else if( current->children && !ntl(current) ) return current->children; + else return nextBranch( current ); +} + +template< unsigned int Dim , class NodeData , class DepthAndOffsetType > +const RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::nextNode( const RegularTreeNode* current ) const +{ + if( !current ) return this; + else if( current->children ) return current->children; + else return nextBranch( current ); +} +template< unsigned int Dim , class NodeData , class DepthAndOffsetType > +RegularTreeNode< Dim , NodeData , DepthAndOffsetType >* RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::nextNode( RegularTreeNode* current ) +{ + if( !current ) return this; + else if( current->children ) return current->children; + else return nextBranch( current ); +} + +template< unsigned int Dim , class NodeData , class DepthAndOffsetType > +void RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::printRange(void) const +{ + Point< float , Dim > center; + float width; + centerAndWidth( center , width ); + for( int d=0 ; d +template< class Real > +int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::ChildIndex( const Point< Real , Dim >& center , const Point< Real , Dim >& p ) +{ + int cIndex=0; + for( int d=0 ; dcenter[d] ) cIndex |= (1< +bool RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::write( const char* fileName ) const +{ + FILE* fp=fopen( fileName , "wb" ); + if( !fp ) return false; + bool ret = write(fp); + fclose(fp); + return ret; +} +template< unsigned int Dim , class NodeData , class DepthAndOffsetType > +bool RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::write( FILE* fp ) const +{ + fwrite( this , sizeof( RegularTreeNode< Dim , NodeData , DepthAndOffsetType > ) , 1 , fp ); + if( children ) for( int i=0 ; i<(1< +template< typename Initializer > +bool RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::read( const char* fileName , Allocator< RegularTreeNode >* nodeAllocator , Initializer &initializer ) +{ + FILE* fp = fopen( fileName , "rb" ); + if( !fp ) return false; + bool ret = read( fp , nodeAllocator , initializer ); + fclose( fp ); + return ret; +} +template< unsigned int Dim , class NodeData , class DepthAndOffsetType > +template< typename Initializer > +bool RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::read( FILE* fp , 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 ) + { + children = NULL; + initChildren< false >( nodeAllocator , initializer ); + for( int i=0 ; i<(1< +int RegularTreeNode< Dim , NodeData , DepthAndOffsetType >::width( int maxDepth ) const +{ + int d=depth(); + return 1<<(maxDepth-d); +} + +//////////////////////////////// +// RegularTreeNode::Neighbors // +//////////////////////////////// +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(); } +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; } + +///////////////////////////////////// +// 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(); } +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; } + +////////////////////////////////// +// 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; } +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 ) +{ + _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 ) ... > > ) ); +} +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 ) +{ + 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 ) +{ + if( neighbors ) delete[] neighbors; + neighbors = NULL; + _depth = d; + 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 ) +{ + 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 ); +} +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 ) +{ + return _NeighborsLoop< CreateNodes , ThreadSafe , NodeInitializer >( UIntPack< _PLeftRadii ... >() , UIntPack< _PRightRadii ... >() , UIntPack< _CLeftRadii ... >() , UIntPack< _CRightRadii ... >() , ( ConstWindowSlice< RegularTreeNode* , UIntPack< ( _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 ) +{ + 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 ); + } + return count; +} + + +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 ) +{ + static const int D = 1; + unsigned int count=0; + for( int i=-(int)_CLeftRadius ; i<=(int)_CRightRadius ; i++ ) + { + int _i = (i+c[Dim-1]) + ( _CLeftRadius<<1 ) , pi = ( _i>>1 ) - _CLeftRadius + _PLeftRadius , ci = i + _CLeftRadius; + if( CreateNodes ) + { + if( pNeighbors[pi] ) + { + if( !pNeighbors[pi]->children ) pNeighbors[pi]->template initChildren< ThreadSafe >( nodeAllocator , initializer ); + cNeighbors[ci] = pNeighbors[pi]->children + ( cornerIndex | ( ( _i&1)<<(Dim-1) ) ); + count++; + } + else cNeighbors[ci] = NULL; + } + else + { + if( pNeighbors[pi] && pNeighbors[pi]->children ) cNeighbors[ci] = pNeighbors[pi]->children + ( cornerIndex | ( ( _i&1)<<(Dim-1) ) ) , count++; + else cNeighbors[ci] = NULL; + } + } + return count; +} + +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 +{ + 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 ); +} + +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 +{ + NeighborType& pNeighbors = neighbors[d]; + // Check that we actually have a center node + if( !pNeighbors.neighbors.data[ CenterIndex ] ) return 0; + Point< Real , Dim > c; + Real w; + pNeighbors.neighbors.data[ CenterIndex ]->centerAndWidth( c , w ); + return getChildNeighbors< CreateNodes , ThreadSafe >( CornerIndex( c , p ) , d , cNeighbors , nodeAllocator , initializer ); +} + +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 ) +{ + 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; + if( reset ) neighbors.neighbors.data[ CenterIndex ] = NULL; + } + 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< 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 ); + } + return neighbors; +} + +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 ) +{ + static const unsigned int _CenterIndex = WindowIndex< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > , UIntPack< _LeftRadii ... > >::Index; + 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; + + // 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< CreateNodes , ThreadSafe >( node->parent , nodeAllocator , initializer ); + const Neighbors< 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; + 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 ); + } +} + +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 ) +{ + UIntPack< _LeftRadii ... > leftRadii; + UIntPack< _RightRadii ... > rightRadii; + if( !node->parent ) getNeighbors< CreateNodes , ThreadSafe >( leftRadii , rightRadii , node , neighbors , nodeAllocator , initializer ); + else + { + getNeighbors< CreateNodes , ThreadSafe >( leftRadii , rightRadii , node->parent , pNeighbors , nodeAllocator , initializer ); + _NeighborsLoop< CreateNodes , ThreadSafe >( leftRadii , rightRadii , leftRadii , rightRadii , pNeighbors.neighbors() , neighbors.neighbors() , (int)( node - node->parent->children ) , nodeAllocator , initializer ); + } +} + +/////////////////////////////////////// +// RegularTreeNode::ConstNeighborKey // +/////////////////////////////////////// +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; } +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 ) +{ + _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 ) ... > > ) ); +} +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 ) +{ + 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 ) +{ + set( key._depth ); + for( int d=0 ; d<=_depth ; d++ ) memcpy( &neighbors[d] , &key.neighbors[d] , sizeof( ConstNeighbors< 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 ) +{ + if( neighbors ) delete[] neighbors; + neighbors = NULL; + _depth = d; + 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< 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 ) +{ + 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 ); +} +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 ) +{ + return _NeighborsLoop( UIntPack< _PLeftRadii ... >() , UIntPack< _PRightRadii ... >() , UIntPack< _CLeftRadii ... >() , UIntPack< _CRightRadii ... >() , ( ConstWindowSlice< const RegularTreeNode* , UIntPack< ( _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 ) +{ + 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) ) ); + } + 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 ) +{ + static const int D = 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; + if( pNeighbors[pi] && pNeighbors[pi]->children ) cNeighbors[ci] = pNeighbors[pi]->children + ( cornerIndex | ( ( _i&1)<<(Dim-1) ) ) , count++; + else cNeighbors[ci] = NULL; + } + return count; +} + +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 +{ + const ConstNeighbors< 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 ); +} + +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 ) +{ + ConstNeighbors< 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 ) ); + } + 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 ) +{ + static const unsigned int _CenterIndex = WindowIndex< UIntPack< ( _LeftRadii + _RightRadii + 1 ) ... > , UIntPack< _LeftRadii ... > >::Index; + + 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; + // 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 ]; + _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; + 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 ) +{ + UIntPack< _LeftRadii ... > leftRadii; + UIntPack< _RightRadii ... > rightRadii; + if( !node->parent ) return getNeighbors( leftRadii , rightRadii , node , neighbors ); + else + { + getNeighbors( leftRadii , rightRadii , node->parent , pNeighbors ); + _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 +{ + ConstNeighbors< 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; + Real w; + pNeighbors.neighbors.data[ CenterIndex ]->centerAndWidth( c , w ); + int cIdx = 0; + for( int d=0 ; dc[d] ) cIdx |= (1< class SparseMatrix; + +template< class T , class IndexType > class SparseMatrix< T , IndexType , 0 > : public SparseMatrixInterface< T , ConstPointer( MatrixEntry< T , IndexType > ) > +{ + 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 > ) > +{ + 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 "Mesh/PoissonRecon/SparseMatrix.inl" +#endif // SPARSE_MATRIX_INCLUDED diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/SparseMatrix.inl b/modules/PoissonRecon/include/Mesh/PoissonRecon/SparseMatrix.inl new file mode 100644 index 00000000..58dff021 --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/SparseMatrix.inl @@ -0,0 +1,660 @@ +/* -*- C++ -*- +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +#include +#include +#include + +/////////////////////////////////////////////////////////////// +// SparseMatrix (unconstrained max row size specialization) // +/////////////////////////////////////////////////////////////// +template< class T , class IndexType > +SparseMatrix< T , IndexType , 0 >::SparseMatrix( void ) +{ + rowSizes = NullPointer( size_t ); + rowNum = 0; + _entries = NullPointer( Pointer( MatrixEntry< T , IndexType > ) ); +} + +template< class T , class IndexType > +SparseMatrix< T , IndexType , 0 >::SparseMatrix( size_t rowNum ) +{ + this->rowNum = 0; + rowSizes = NullPointer( size_t ); + _entries= NullPointer( Pointer( MatrixEntry< T , IndexType > ) ); + resize( rowNum ); +} +template< class T , class IndexType > +SparseMatrix< T , IndexType , 0 >::SparseMatrix( const SparseMatrix& M ) +{ + rowSizes = NullPointer( size_t ); + rowNum = 0; + _entries = NullPointer( Pointer( MatrixEntry< T , IndexType > ) ); + resize( M.rowNum ); + for( size_t i=0 ; i +SparseMatrix< T , IndexType , 0 >::SparseMatrix( SparseMatrix&& M ) +{ + rowSizes = NullPointer( size_t ); + rowNum = 0; + _entries = NullPointer( Pointer( MatrixEntry< T , IndexType > ) ); + + Swap( *this , M ); +} +template< class T , class IndexType > +template< class T2 , class IndexType2 > +SparseMatrix< T , IndexType , 0 >::SparseMatrix( const SparseMatrix< T2 , IndexType2 , 0 >& M ) +{ + rowSizes = NullPointer( size_t ); + rowNum = 0; + _entries = NULL; + resize( M.rowNum ); + for( size_t i=0 ; i( M._entries[i][j].N , T( M._entries[i][j].Value ) ); + } +} + +template< class T , class IndexType > +template< class T2 , class IndexType2 > +SparseMatrix< T , IndexType , 0 >& SparseMatrix< T , IndexType , 0 >::copy( const SparseMatrix< T2 , IndexType2 , 0 >& M ) +{ + resize( M.rowNum ); + for ( size_t i=0 ; i( (IndexType)idx , T( M[i][j].Value ) ); + } + } + return *this; +} +template< class T , class IndexType > +SparseMatrix< T , IndexType , 0 >& SparseMatrix< T , IndexType , 0 >::operator = ( SparseMatrix< T , IndexType , 0 >&& M ) +{ + Swap( *this , M ); + return *this; +} + +template< class T , class IndexType > +SparseMatrix< T , IndexType , 0 >& SparseMatrix< T , IndexType , 0 >::operator = ( const SparseMatrix< T , IndexType , 0 >& M ) +{ + resize( M.rowNum ); + for( size_t i=0 ; i +template< class T2 , class IndexType2 > +SparseMatrix< T , IndexType , 0 >& SparseMatrix< T , IndexType , 0 >::operator = (const SparseMatrix< T2 , IndexType2 , 0 >& M) +{ + resize( M.rowNum ); + for( size_t i=0 ; i( M._entries[i][j].N , T( M._entries[i][j].Value ) ); + } + return *this; +} + +template< class T , class IndexType > +template< class T2 > +void SparseMatrix< T , IndexType , 0 >::operator() ( const T2* in , T2* out ) const { Interface::multiply( in , out ); } + +template< class T , class IndexType > SparseMatrix< T , IndexType , 0 >::~SparseMatrix( void ) { resize( 0 ); } + +template< class T , class IndexType > +void SparseMatrix< T , IndexType , 0 >::resize( size_t r ) +{ + if( rowNum>0 ) + { + for( size_t i=0 ; i( r ) , memset( rowSizes , 0 , sizeof(size_t)*r ); + _entries = AllocPointer< Pointer( MatrixEntry< T , IndexType > ) >( r ); + for( size_t i=0 ; i ); + } +} + +template< class T , class IndexType > +void SparseMatrix< T , IndexType , 0 >::setRowSize( size_t row , size_t count ) +{ + if( row>=0 && row0 ) + { + _entries[ row ] = AllocPointer< MatrixEntry< T , IndexType > >( count ); + memset( _entries[ row ] , 0 , sizeof( MatrixEntry< T , IndexType > )*count ); + } + rowSizes[row] = count; + } + else 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 ) +{ + if( row>=0 && row >( _entries[row] , 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 ); +} + +template< class T , class IndexType > +SparseMatrix< T , IndexType , 0 > SparseMatrix< T , IndexType , 0 >::Identity( size_t dim ) +{ + SparseMatrix I; + I.resize( dim ); + for( size_t i=0 ; i( (IndexType)i , (T)1 ); + return I; +} +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 +SparseMatrix< T , IndexType , 0 >& SparseMatrix< T , IndexType , 0 >::operator /= ( T s ){ return (*this) * ( (T)1./s ); } +template< class T , class IndexType > +SparseMatrix< T , IndexType , 0 >& SparseMatrix< T , IndexType , 0 >::operator *= ( const SparseMatrix< T , IndexType , 0 >& B ) +{ + SparseMatrix foo = (*this) * B; + (*this) = foo; + return *this; +} +template< class T , class IndexType > +SparseMatrix< T , IndexType , 0 >& SparseMatrix< T , IndexType , 0 >::operator += ( const SparseMatrix< T , IndexType , 0 >& B ) +{ + SparseMatrix foo = (*this) + B; + (*this) = foo; + return *this; +} +template< class T , class IndexType > +SparseMatrix< T , IndexType , 0 >& SparseMatrix< T , IndexType , 0 >::operator -= ( const SparseMatrix< T , IndexType , 0 >& B ) +{ + SparseMatrix foo = (*this) - B; + (*this) = foo; + return *this; +} +template< class T , class IndexType > +SparseMatrix< T , IndexType , 0 > SparseMatrix< T , IndexType , 0 >::operator * ( T s ) const +{ + SparseMatrix out = (*this); + return out *= s; +} +template< class T , class IndexType > +SparseMatrix< T , IndexType , 0 > SparseMatrix< T , IndexType , 0 >::operator / ( T s ) const { return (*this) * ( (T)1. / s ); } +template< class T , class IndexType > +SparseMatrix< T , IndexType , 0 > SparseMatrix< T , IndexType , 0 >::operator * ( const SparseMatrix< T , IndexType , 0 >& B ) const +{ + SparseMatrix out; + const SparseMatrix& A = *this; + size_t aCols = 0 , aRows = A.rowNum; + size_t bCols = 0 , bRows = B.rowNum; + for( size_t i=0 ; i row; + for( size_t j=0 ; j::iterator iter = row.find(idx2); + if( iter==row.end() ) row[idx2] = AValue * BValue; + else iter->second += AValue * BValue; + } + } + out.setRowSize( i , row.size() ); + out.rowSizes[i] = 0; + for( typename std::unordered_map< IndexType , T >::iterator iter=row.begin() ; iter!=row.end() ; iter++ ) out[i][ out.rowSizes[i]++ ] = MatrixEntry< T , IndexType >( iter->first , iter->second ); + } + ); + return out; +} +template< class T , class IndexType > +SparseMatrix< T , IndexType , 0 > SparseMatrix< T , IndexType , 0 >::operator + ( const SparseMatrix< T , IndexType , 0 >& B ) const +{ + const SparseMatrix& A = *this; + size_t rowNum = std::max< size_t >( A.rowNum , B.rowNum ); + SparseMatrix out; + + out.resize( rowNum ); + ThreadPool::Parallel_for( 0 , rowNum , [&]( unsigned int , size_t i ) + { + std::unordered_map< IndexType , T > row; + if( i::iterator iter = row.find(idx); + if( iter==row.end() ) row[idx] = A[i][j].Value; + else iter->second += A[i][j].Value; + } + if( i::iterator iter = row.find(idx); + if( iter==row.end() ) row[idx] = B[i][j].Value; + else iter->second += B[i][j].Value; + } + out.setRowSize( i , row.size() ); + out.rowSizes[i] = 0; + for( typename std::unordered_map< IndexType , T >::iterator iter=row.begin() ; iter!=row.end() ; iter++ ) out[i][ out.rowSizes[i]++ ] = MatrixEntry< T , IndexType >( iter->first , iter->second ); + } + ); + return out; +} +template< class T , class IndexType > +SparseMatrix< T , IndexType , 0 > SparseMatrix< T , IndexType , 0 >::operator - ( const SparseMatrix< T , IndexType , 0 >& B ) const +{ + const SparseMatrix& A = *this; + size_t rowNum = std::max< size_t >( A.rowNum , B.rowNum ); + SparseMatrix out; + + out.resize( rowNum ); + ThreadPool::Parallel_for( 0 , rowNum , [&]( unsigned int , size_t i ) + { + std::unordered_map< IndexType , T > row; + if( i::iterator iter = row.find(idx); + if( iter==row.end() ) row[idx] = A[i][j].Value; + else iter->second += A[i][j].Value; + } + if( i::iterator iter = row.find(idx); + if( iter==row.end() ) row[idx] = -B[i][j].Value; + else iter->second -= B[i][j].Value; + } + out.setRowSize( i , row.size() ); + out.rowSizes[i] = 0; + for( typename std::unordered_map< IndexType , T >::iterator iter=row.begin() ; iter!=row.end() ; iter++ ) out[i][ out.rowSizes[i]++ ] = MatrixEntry< T , IndexType >( iter->first , iter->second ); + } + ); + return out; +} + +template< class T , class IndexType > +SparseMatrix< T , IndexType , 0 > SparseMatrix< T , IndexType , 0 >::transpose( T (*TransposeFunction)( const T& ) ) const +{ + SparseMatrix A; + const SparseMatrix& At = *this; + size_t aRows = 0 , aCols = At.rowNum; + for( size_t i=0 ; i( (IndexType)i , TransposeFunction( At[i][j].Value ) ); + } + else for( size_t i=0 ; i( (IndexType)i , At[i][j].Value ); + } + return A; +} +template< class T , class IndexType > +SparseMatrix< T , IndexType , 0 > SparseMatrix< T , IndexType , 0 >::transpose( size_t aRows , T (*TransposeFunction)( const T& ) ) const +{ + SparseMatrix A; + 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 ); + + A.resize( aRows ); + for( size_t i=0 ; i( (IndexType)i , TransposeFunction( At[i][j].Value ) ); + } + else + for( size_t i=0 ; i( (IndexType)i , At[i][j].Value ); + } + return A; +} + +template< class T , class IndexType > +template< class A_const_iterator , class B_const_iterator > +SparseMatrix< T , IndexType , 0 > SparseMatrix< T , IndexType , 0 >::Multiply( const SparseMatrixInterface< T , A_const_iterator >& A , const SparseMatrixInterface< T , B_const_iterator >& B ) +{ + SparseMatrix M; + size_t aCols = 0 , aRows = A.rows(); + 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 row; + for( A_const_iterator iterA=A.begin(i) ; iterA!=A.end(i) ; iterA++ ) + { + IndexType idx1 = iterA->N; + T AValue = iterA->Value; + for( B_const_iterator iterB=B.begin(idx1) ; iterB!=B.end(idx1) ; iterB++ ) + { + IndexType idx2 = iterB->N; + T BValue = iterB->Value; + T temp = BValue * AValue; // temp = A( i , idx1 ) * B( idx1 , idx2 ) + typename std::unordered_map< IndexType , T >::iterator iter = row.find(idx2); + if( iter==row.end() ) row[idx2] = temp; + else iter->second += temp; + } + } + M.setRowSize( i , row.size() ); + M.rowSizes[i] = 0; + for( typename std::unordered_map< IndexType , T >::iterator iter=row.begin() ; iter!=row.end() ; iter++ ) + M[i][ M.rowSizes[i]++ ] = MatrixEntry< T , IndexType >( iter->first , iter->second ); + } + ); + return M; +} +template< class T , class IndexType > +template< class const_iterator > +SparseMatrix< T , IndexType , 0 > SparseMatrix< T , IndexType , 0 >::Transpose( const SparseMatrixInterface< T , const_iterator >& At , T (*TransposeFunction)( const T& ) ) +{ + SparseMatrix< T , IndexType , 0 > A; + size_t aRows = 0 , aCols = At.rows(); + for( size_t i=0 ; iN ) aRows = iter->N+1; + + A.resize( aRows ); + for( size_t i=0 ; iN ]++; + for( size_t i=0 ; iN; + A[ii][ A.rowSizes[ii]++ ] = MatrixEntry< T , IndexType >( (IndexType)i , TransposeFunction( iter->Value ) ); + } + else + for( size_t i=0 ; iN; + A[ii][ A.rowSizes[ii]++ ] = MatrixEntry< T , IndexType >( (IndexType)i , iter->Value ); + } + return A; +} +template< class T , class IndexType > +template< class const_iterator > +SparseMatrix< T , IndexType , 0 > SparseMatrix< T , IndexType , 0 >::Transpose( const SparseMatrixInterface< T , const_iterator >& At , size_t outRows , T (*TransposeFunction)( const T& ) ) +{ + 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 ); + + A.resize( aRows ); + for( size_t i=0 ; iN ]++; + for( size_t i=0 ; iN; + A[ii][ A.rowSizes[ii]++ ] = MatrixEntry< T , IndexType >( (IndexType)i , TransposeFunction( iter->Value ) ); + } + else + for( size_t i=0 ; iN; + A[ii][ A.rowSizes[ii]++ ] = MatrixEntry< T , IndexType >( (IndexType)i , iter->Value ); + } + return true; +} + +/////////////////////////////////////////// +// SparseMatrix (bounded max row size ) // +/////////////////////////////////////////// + +template< class T , class IndexType , size_t MaxRowSize > +SparseMatrix< T , IndexType , MaxRowSize >::SparseMatrix( void ) +{ + _rowSizes = NullPointer( size_t ); + _rowNum = 0; + _entries = NullPointer( MatrixEntry< T , IndexType > ); + _maxRows = 0; +} + +template< class T , class IndexType , size_t MaxRowSize > +SparseMatrix< T , IndexType , MaxRowSize >::SparseMatrix( size_t rowNum ) : SparseMatrix() +{ + resize( rowNum ); +} +template< class T , class IndexType , size_t MaxRowSize > +SparseMatrix< T , IndexType , MaxRowSize >::SparseMatrix( const SparseMatrix& M ) : SparseMatrix() +{ + resize( M._rowNum ); + for( size_t i=0 ; i<_rowNum ; i++ ) + { + _rowSizes[i] = M._rowSizes[i]; + for( size_t j=0 ; j<_rowSizes[i] ; j++ ) _entries[ i + MaxRowSize*j ] = M._rowEntries[ i + MaxRowSize*j ]; + } +} +template< class T , class IndexType , size_t MaxRowSize > +SparseMatrix< T , IndexType , MaxRowSize >::SparseMatrix( SparseMatrix&& M ) : SparseMatrix() +{ + Swap( *this , M ); +} +template< class T , class IndexType , size_t MaxRowSize > +template< class T2 , class IndexType2 > +SparseMatrix< T , IndexType , MaxRowSize >::SparseMatrix( const SparseMatrix< T2 , IndexType2 , MaxRowSize >& M ) : SparseMatrix() +{ + resize( M._rowNum ); + for( size_t i=0 ; i<_rowNum ; i++ ) + { + _rowSizes[i] = M._rowSizes[i]; + for( size_t j=0 ; j<_rowSizes[i] ; j++ ) _entries[ i + MaxRowSize*j ] = MatrixEntry< T , IndexType >( M._rowEntries[i][j].N , T( M._entries[ i + MaxRowSize*j ].Value ) ); + } +} + +template< class T , class IndexType , size_t MaxRowSize > +SparseMatrix< T , IndexType , MaxRowSize >& SparseMatrix< T , IndexType , MaxRowSize >::operator = ( SparseMatrix< T , IndexType , MaxRowSize >&& M ) +{ + Swap( *this , M ); + return *this; +} + +template< class T , class IndexType , size_t MaxRowSize > +SparseMatrix< T , IndexType , MaxRowSize >& SparseMatrix< T , IndexType , MaxRowSize >::operator = ( const SparseMatrix< T , IndexType , MaxRowSize >& M ) +{ + resize( M._rowNum ); + for( size_t i=0 ; i<_rowNum ; i++ ) + { + _rowSizes[i] = M._rowSizes[i]; + for( size_t j=0 ; j<_rowSizes[i] ; j++ ) _entries[ i + MaxRowSize*j ] = M._entries[ i + MaxRowSize*j ]; + } + return *this; +} + +template< class T , class IndexType , size_t MaxRowSize > +template< class T2 , class IndexType2 > +SparseMatrix< T , IndexType , MaxRowSize >& SparseMatrix< T , IndexType , MaxRowSize >::operator = ( const SparseMatrix< T2 , IndexType2 , MaxRowSize >& M ) +{ + resize( M._rowNum ); + for( size_t i=0 ; i<_rowNum ; i++ ) + { + _rowSizes[i] = M._rowSizes[i]; + for( size_t j=0 ; j<_rowSizes[i] ; j++ ) _entries[ i + MaxRowSize*j ] = MatrixEntry< T , IndexType >( M._entries[ i + MaxRowSize*j ].N , T( M._entries[ i + MaxRowSize*j ].Value ) ); + } + return *this; +} + +template< class T , class IndexType , size_t MaxRowSize > +template< class T2 > +void SparseMatrix< T , IndexType , MaxRowSize >::operator() ( const T2* in , T2* out ) const { Interface::multiply( in , out ); } + +template< class T , class IndexType , size_t MaxRowSize > +SparseMatrix< T , IndexType , MaxRowSize >::~SparseMatrix( void ) +{ + FreePointer( _rowSizes ); + FreePointer( _entries ); +} + +template< class T , class IndexType , size_t MaxRowSize > +void SparseMatrix< T , IndexType , MaxRowSize >::resize( size_t rowNum ) +{ + _rowNum = rowNum; + if( rowNum>_maxRows ) + { + FreePointer( _rowSizes ); + FreePointer( _entries ); + + if( rowNum ) + { + _rowSizes = AllocPointer< size_t >( rowNum ) , memset( _rowSizes , 0 , sizeof(size_t)*rowNum ); + _entries = AllocPointer< MatrixEntry< T , IndexType > >( rowNum * MaxRowSize ); + _maxRows = 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 ); + 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 ); + else _rowSizes[row] = rowSize; +} + +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; } ); + return *this; +} + +template< class T , class IndexType , size_t MaxRowSize > +SparseMatrix< T , IndexType , MaxRowSize >& SparseMatrix< T , IndexType , MaxRowSize >::operator /= ( T s ){ return (*this) * ( (T)1./s ); } + +template< class T , class IndexType , size_t MaxRowSize > +SparseMatrix< T , IndexType , MaxRowSize > SparseMatrix< T , IndexType , MaxRowSize >::operator * ( T s ) const +{ + SparseMatrix out = (*this); + return out *= s; +} + +template< class T , class IndexType , size_t MaxRowSize > +SparseMatrix< T , IndexType , MaxRowSize > SparseMatrix< T , IndexType , MaxRowSize >::operator / ( T s ) const { return (*this) * ( (T)1. / s ); } diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/SparseMatrixInterface.h b/modules/PoissonRecon/include/Mesh/PoissonRecon/SparseMatrixInterface.h new file mode 100644 index 00000000..ad25269e --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/SparseMatrixInterface.h @@ -0,0 +1,94 @@ +/* +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 SPARSE_MATRIX_INTERFACE_INCLUDED +#define SPARSE_MATRIX_INTERFACE_INCLUDED + +#define FORCE_TWO_BYTE_ALIGNMENT 1 +#include "Mesh/PoissonRecon/MyMiscellany.h" +#include "Mesh/PoissonRecon/Array.h" + +#if 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 +#pragma pack(pop) +#endif // FORCE_TWO_BYTE_ALIGNMENT + +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 ); + +#include "Mesh/PoissonRecon/SparseMatrixInterface.inl" +#endif // SPARSE_MATRIX_INTERFACE_INCLUDED diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/SparseMatrixInterface.inl b/modules/PoissonRecon/include/Mesh/PoissonRecon/SparseMatrixInterface.inl new file mode 100644 index 00000000..b88f47bd --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/SparseMatrixInterface.inl @@ -0,0 +1,383 @@ +/* +Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +Neither the name of the Johns Hopkins University nor the names of its contributors +may be used to endorse or promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. +*/ + +template< class T , class const_iterator > size_t SparseMatrixInterface< T , const_iterator >::entries( void ) const +{ + size_t entries = 0; + for( size_t i=0 ; i double SparseMatrixInterface< T , const_iterator >::squareNorm( void ) const +{ + double n=0; + for( size_t i=0 ; iValue * iter->Value; + } + return n; + +} +template< class T , class const_iterator > double SparseMatrixInterface< T , const_iterator >::squareASymmetricNorm( void ) const +{ + double n=0; + for( size_t i=0 ; iN; + const_iterator e = end( j ); + double value = 0; + for( const_iterator iter2 = begin( j ) ; iter2!=e ; iter2++ ) + { + size_t k = iter2->N; + if( k==i ) value += iter2->Value; + } + n += (iter1->Value-value) * (iter1->Value-value); + } + } + return n; +} +template< class T , class const_iterator > double SparseMatrixInterface< T , const_iterator >::squareASymmetricNorm( size_t &idx1 , size_t &idx2 ) const +{ + double n=0; + double max=0; + for( size_t i=0 ; iN; + const_iterator e = end( j ); + double value = 0; + for( const_iterator iter2 = begin( j ) ; iter2!=e ; iter2++ ) + { + size_t k = iter2->N; + if( k==i ) value += iter2->Value; + } + double temp = (iter->Value-value) * (iter->Value-value); + n += temp; + if( temp>=max ) idx1 = i , idx2 = j , max=temp; + } + } + return n; +} +template< class T , class const_iterator > +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 ) + { + T2 temp; + memset( &temp , 0 , sizeof(T2) ); + ConstPointer( T2 ) _in = in; + const_iterator e = end( i ); + for( const_iterator iter = begin( i ) ; iter!=e ; iter++ ) temp += (T2)( _in[ iter->N ] * iter->Value ); + if( multiplyFlag & MULTIPLY_NEGATE ) temp = -temp; + if( multiplyFlag & MULTIPLY_ADD ) Out[i] += temp; + else Out[i] = temp; + } + ); +} +template< class T , class const_iterator > +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 ) + { + T2 temp; + memset( &temp , 0 , sizeof(T2) ); + ConstPointer( T2 ) _in = in; + const_iterator e = end( i ); + for( const_iterator iter = begin( i ) ; iter!=e ; iter++ ) temp += _in[ iter->N ] * iter->Value; + temp *= scale; + if( multiplyFlag & MULTIPLY_NEGATE ) temp = -temp; + if( multiplyFlag & MULTIPLY_ADD ) Out[i] += temp; + else Out[i] = temp; + } + ); +} + +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 ) + { + diagonal[i] = (T)0; + const_iterator e = end( i ); + for( const_iterator iter = begin( i ) ; iter!=e ; iter++ ) if( iter->N==i ) diagonal[i] += iter->Value; + } + ); +} + +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 ) + { + diagonal[i] = (T)0; + const_iterator e = end( i ); + for( const_iterator iter = begin( i ) ; iter!=e ; iter++ ) if( iter->N==i ) diagonal[i] += iter->Value; + if( diagonal[i] ) diagonal[i] = (T)( 1./diagonal[i] ); + } + ); +} + +template< class T , class const_iterator > +template< class T2 > +void SparseMatrixInterface< T , const_iterator >::jacobiIteration( ConstPointer( T ) diagonal , ConstPointer( T2 ) b , ConstPointer( T2 ) in , Pointer( T2 ) out , bool dReciprocal ) const +{ + 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]; } ); + else + ThreadPool::Parallel_for( 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 > +void SparseMatrixInterface< T , const_iterator >::gsIteration( ConstPointer( T ) diagonal , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward , bool dReciprocal ) const +{ + 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 + } + 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 + } +} +template< class T , class const_iterator > +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 ) + { + size_t jj = multiColorIndices[j]; + 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]; + } + ); + else + ThreadPool::Parallel_for( 0 , multiColorIndices.size() , [&]( unsigned int , size_t j ) + { + size_t jj = multiColorIndices[j]; + 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]; + } + ); +} + +template< class T , class const_iterator > +template< class T2 > +void SparseMatrixInterface< T , const_iterator >::gsIteration( const std::vector< std::vector< size_t > >& multiColorIndices , ConstPointer( T ) diagonal , ConstPointer( T2 ) b , Pointer( T2 ) x , bool forward , bool dReciprocal ) const +{ + 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 + } + 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 + } +} +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 ) +{ + std::vector< Real > scratch( ThreadPool::NumThreads() , 0 ); + eps *= eps; + Pointer( T ) r = AllocPointer< T >( dim ); + Pointer( T ) d = AllocPointer< T >( dim ); + Pointer( T ) q = AllocPointer< T >( dim ); + + 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] ); } ); + for( unsigned int t=0 ; teps*delta_0 ; ii++ ) + { + 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] ); } ); + for( unsigned int t=0 ; t 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 ) +{ + std::vector< Real > scratch( ThreadPool::NumThreads() , 0 ); + eps *= eps; + Pointer( T ) r = AllocPointer< T >( dim ); + Pointer( T ) d = AllocPointer< T >( dim ); + Pointer( T ) q = AllocPointer< T >( dim ); + Pointer( T ) Pb = AllocPointer< T >( dim ); + Pointer( T ) temp = AllocPointer< T >( dim ); + + auto PM = [&] ( ConstPointer(T) x , Pointer(T) y ) + { + M( x , temp ); + P( ( ConstPointer(T) )temp , y ); + }; + + Real delta_new = 0 , delta_0; + P( b , Pb ); + PM( ( ConstPointer( T ) )x , r ); + ThreadPool::Parallel_for( 0 , dim , [&]( unsigned int thread , size_t i ){ d[i] = r[i] = Pb[i] - r[i] , scratch[thread] += Dot( r[i] , r[i] ); } ); + for( unsigned int t=0 ; teps*delta_0 ; ii++ ) + { + PM( ( 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] ); } ); + for( unsigned int t=0 ; t +#include +#include +#include +#include "Mesh/PoissonRecon/FEMTree.h" +#include "Mesh/PoissonRecon/MyMiscellany.h" +#include "Mesh/PoissonRecon/CmdLineParser.h" +#include "Mesh/PoissonRecon/MAT.h" +#include "Mesh/PoissonRecon/Geometry.h" +#include "Mesh/PoissonRecon/Ply.h" +#include "Mesh/PoissonRecon/PointStreamData.h" + +class SurfaceTrimmer +{ + public: +MessageWriter messageWriter; + + +cmdLineParameter< char* > + In{ "in" } , + Out{ "out" }; +cmdLineParameter< int > + Smooth{ "smooth" , 5 }; +cmdLineParameter< float > + Trim{ "trim" } , + IslandAreaRatio{ "aRatio" , 0.001f }; +cmdLineReadable + PolygonMesh{ "polygonMesh" } , + Long{ "long" } , + Verbose{ "verbose" }; + + +cmdLineReadable* params[9] = +{ + &In , &Out , &Trim , &PolygonMesh , &Smooth , &IslandAreaRatio , &Verbose , &Long , + NULL +}; + +void ShowUsage( char* ex ) +{ + printf( "Usage: %s\n" , ex ); + printf( "\t --%s \n" , In.name ); + printf( "\t --%s \n" , Trim.name ); + printf( "\t[--%s ]\n" , Out.name ); + printf( "\t[--%s =%d]\n" , Smooth.name , Smooth.value ); + printf( "\t[--%s =%f]\n" , IslandAreaRatio.name , IslandAreaRatio.value ); + printf( "\t[--%s]\n" , PolygonMesh.name ); + printf( "\t[--%s]\n" , Long.name ); + printf( "\t[--%s]\n" , Verbose.name ); +} + +template< typename Index > +struct EdgeKey +{ + Index key1 , key2; + EdgeKey( Index k1=0 , Index k2=0 ) : key1(k1) , key2(k2) {} + 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 +}; + +template< typename Real , typename ... VertexData > +PlyVertexWithData< float , DIMENSION , MultiPointStreamData< float , PointStreamValue< float > , VertexData ... > > InterpolateVertices( const PlyVertexWithData< float , DIMENSION , MultiPointStreamData< float , PointStreamValue< float > , VertexData ... > >& v1 , const PlyVertexWithData< float , DIMENSION , MultiPointStreamData< float , PointStreamValue< float > , VertexData ... > >& v2 , Real value ) +{ + if( v1.data.template data<0>()==v2.data.template data<0>() ) return (v1+v2)/Real(2.); + Real dx = ( v1.data.template data<0>()-value ) / ( v1.data.template data<0>()-v2.data.template data<0>() ); + return v1*(1.f-dx) + v2*dx; +} + +template< typename Real , typename Index , typename ... VertexData > +void SmoothValues( std::vector< PlyVertexWithData< float , DIMENSION , MultiPointStreamData< float , PointStreamValue< float > , VertexData ... > > >& 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].data.template data<0>(); + } + } + for( size_t i=0 ; i() = ( sums[i] + vertices[i].data.template data<0>() ) / ( count[i] + 1 ); +} + +template< class Real , typename Index , typename ... VertexData > +void SplitPolygon +( + const std::vector< Index >& polygon , + std::vector< PlyVertexWithData< float , DIMENSION , MultiPointStreamData< float , PointStreamValue< float > , VertexData ... > > >& vertices , + std::vector< std::vector< Index > >* ltPolygons , std::vector< std::vector< Index > >* gtPolygons , + std::vector< bool >* ltFlags , std::vector< bool >* gtFlags , + std::unordered_map< EdgeKey< Index > , Index , typename EdgeKey< Index >::Hasher >& vertexTable, + Real trimValue +) +{ + int sz = int( polygon.size() ); + std::vector< bool > gt( sz ); + int gtCount = 0; + for( int j=0 ; j()>trimValue ); + if( gt[j] ) gtCount++; + } + if ( gtCount==sz ){ if( gtPolygons ) gtPolygons->push_back( polygon ) ; if( gtFlags ) gtFlags->push_back( false ); } + else if( gtCount==0 ){ if( ltPolygons ) ltPolygons->push_back( polygon ) ; if( ltFlags ) ltFlags->push_back( false ); } + else + { + int start; + for( start=0 ; start poly; + + // Add the initial vertex + { + int j1 = (start+int(sz)-1)%sz , j2 = start; + Index v1 = polygon[j1] , v2 = polygon[j2] , vIdx; + typename std::unordered_map< EdgeKey< Index > , Index , typename EdgeKey< Index >::Hasher >::iterator iter = vertexTable.find( EdgeKey< Index >(v1,v2) ); + if( iter==vertexTable.end() ) + { + vertexTable[ EdgeKey< Index >(v1,v2) ] = vIdx = (Index)vertices.size(); + vertices.push_back( InterpolateVertices( vertices[v1] , vertices[v2] , trimValue ) ); + } + else vIdx = iter->second; + poly.push_back( vIdx ); + } + + for( int _j=0 ; _j<=sz ; _j++ ) + { + int j1 = (_j+start+sz-1)%sz , j2 = (_j+start)%sz; + Index v1 = polygon[j1] , v2 = polygon[j2]; + if( gt[j2]==gtFlag ) poly.push_back( v2 ); + else + { + Index vIdx; + typename std::unordered_map< EdgeKey< Index > , Index , typename EdgeKey< Index >::Hasher >::iterator iter = vertexTable.find( EdgeKey< Index >(v1,v2) ); + if( iter==vertexTable.end() ) + { + vertexTable[ EdgeKey< Index >(v1,v2) ] = vIdx = (Index)vertices.size(); + vertices.push_back( InterpolateVertices( vertices[v1] , vertices[v2] , trimValue ) ); + } + else vIdx = iter->second; + poly.push_back( vIdx ); + if( gtFlag ){ if( gtPolygons ) gtPolygons->push_back( poly ) ; if( ltFlags ) ltFlags->push_back( true ); } + else { if( ltPolygons ) ltPolygons->push_back( poly ) ; if( gtFlags ) gtFlags->push_back( true ); } + poly.clear() , poly.push_back( vIdx ) , poly.push_back( v2 ); + gtFlag = !gtFlag; + } + } + } +} + +template< class Real , typename Index , class Vertex > +void Triangulate( const std::vector< Vertex >& vertices , const std::vector< std::vector< Index > >& polygons , std::vector< std::vector< Index > >& triangles ) +{ + triangles.clear(); + for( size_t i=0 ; i3 ) + { + std::vector< Point< Real , DIMENSION > > _vertices( polygons[i].size() ); + for( int j=0 ; j > _triangles = MinimalAreaTriangulation< Index , Real , DIMENSION >( ( ConstPointer( Point< Real , DIMENSION > ) )GetPointer( _vertices ) , _vertices.size() ); + + // Add the triangles to the mesh + size_t idx = triangles.size(); + triangles.resize( idx+_triangles.size() ); + for( int j=0 ; j +double PolygonArea( const std::vector< Vertex >& vertices , const std::vector< Index >& polygon ) +{ + if( polygon.size()<3 ) return 0.; + else if( polygon.size()==3 ) return Area( vertices[polygon[0]].point , vertices[polygon[1]].point , vertices[polygon[2]].point ); + else + { + Point< Real , DIMENSION > center; + for( size_t i=0 ; i +void RemoveHangingVertices( std::vector< Vertex >& vertices , std::vector< std::vector< Index > >& polygons ) +{ + std::unordered_map< Index, Index > vMap; + std::vector< bool > vertexFlags( vertices.size() , false ); + for( size_t i=0 ; i _vertices( vCount ); + for( Index i=0 ; i<(Index)vertices.size() ; i++ ) if( vertexFlags[i] ) _vertices[ vMap[i] ] = vertices[i]; + vertices = _vertices; +} + +template< typename Index > +void SetConnectedComponents( const std::vector< std::vector< Index > >& polygons , std::vector< std::vector< Index > >& components ) +{ + std::vector< Index > polygonRoots( polygons.size() ); + for( size_t i=0 ; i , Index , typename EdgeKey< Index >::Hasher > edgeTable; + for( size_t i=0 ; i eKey = EdgeKey< Index >(v1,v2); + typename std::unordered_map< EdgeKey< Index > , Index , typename EdgeKey< Index >::Hasher >::iterator iter = edgeTable.find(eKey); + if( iter==edgeTable.end() ) edgeTable[ eKey ] = (Index)i; + else + { + Index p = iter->second; + while( polygonRoots[p]!=p ) + { + Index temp = polygonRoots[p]; + polygonRoots[p] = (Index)i; + p = temp; + } + polygonRoots[p] = (Index)i; + } + } + } + for( size_t i=0 ; i vMap; + for( Index i=0 ; i<(Index)polygonRoots.size() ; i++ ) if( polygonRoots[i]==i ) vMap[i] = cCount++; + components.resize( cCount ); + for( Index i=0 ; i<(Index)polygonRoots.size() ; i++ ) components[ vMap[ polygonRoots[i] ] ].push_back(i); +} + +template< typename Index , typename ... VertexData > +int Execute( void ) +{ + typedef PlyVertexWithData< float , DIMENSION , MultiPointStreamData< float , PointStreamValue< float > , VertexData ... > > Vertex; + float min , max; + std::vector< Vertex > vertices; + std::vector< std::vector< Index > > polygons; + + int ft; + std::vector< std::string > comments; + PlyReadPolygons< Vertex >( In.value , vertices , polygons , Vertex::PlyReadProperties() , Vertex::PlyReadNum , ft , comments ); + + for( int i=0 ; i( vertices , polygons ); + min = max = vertices[0].data.template data<0>(); + for( size_t i=0 ; i( min , vertices[i].data.template data<0>() ) , max = std::max< float >( max , vertices[i].data.template data<0>() ); + + std::unordered_map< EdgeKey< Index > , Index , typename EdgeKey< Index >::Hasher > vertexTable; + 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" ); + 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 ) printf( "Value Range: [%f,%f]\n" , min , max ); + + double t=Time(); + for( size_t i=0 ; i0 ) + { + std::vector< std::vector< Index > > _ltPolygons , _gtPolygons; + std::vector< std::vector< Index > > ltComponents , gtComponents; + SetConnectedComponents( ltPolygons , ltComponents ); + SetConnectedComponents( gtPolygons , gtComponents ); + std::vector< double > ltAreas( ltComponents.size() , 0. ) , gtAreas( gtComponents.size() , 0. ); + std::vector< bool > ltComponentFlags( ltComponents.size() , false ) , gtComponentFlags( gtComponents.size() , false ); + double area = 0.; + for( size_t i=0 ; i( vertices , ltPolygons[ ltComponents[i][j] ] ); + ltComponentFlags[i] = ( ltComponentFlags[i] || ltFlags[ ltComponents[i][j] ] ); + } + area += ltAreas[i]; + } + for( size_t i=0 ; i( vertices , gtPolygons[ gtComponents[i][j] ] ); + gtComponentFlags[i] = ( gtComponentFlags[i] || gtFlags[ gtComponents[i][j] ] ); + } + area += gtAreas[i]; + } + for( size_t i=0 ; i > polys = ltPolygons; + Triangulate< float , Index , Vertex >( vertices , ltPolygons , polys ) , ltPolygons = polys; + } + { + std::vector< std::vector< Index > > polys = gtPolygons; + Triangulate< float , Index , Vertex >( vertices , gtPolygons , polys ) , gtPolygons = polys; + } + } + + RemoveHangingVertices( vertices , gtPolygons ); + char comment[1024]; + sprintf( comment , "#Trimmed In: %9.1f (s)" , Time()-t ); + comments.push_back( comment ); + if( Out.set ) + if( !PlyWritePolygons< Vertex >( Out.value , vertices , gtPolygons , Vertex::PlyWriteProperties() , Vertex::PlyWriteNum , ft , comments ) ) + ERROR_OUT( "Could not write mesh to: " , Out.value ); + + return EXIT_SUCCESS; +} + +int trim( int argc , char* argv[] ) +{ + cmdLineParse( argc-1 , &argv[1] , params ); + messageWriter.echoSTDOUT = Verbose.set; + + if( !In.set || !Trim.set ) + { + ShowUsage( argv[0] ); + return EXIT_FAILURE; + } + typedef MultiPointStreamData< float , PointStreamValue< float > , PointStreamNormal< float , DIMENSION > , PointStreamColor< float > > VertexData; + typedef PlyVertexWithData< float , DIMENSION , VertexData > Vertex; + bool readFlags[ Vertex::PlyReadNum ]; + if( !PlyReadHeader( In.value , Vertex::PlyReadProperties() , Vertex::PlyReadNum , readFlags ) ) ERROR_OUT( "Failed to read ply header: " , In.value ); + + bool hasValue = VertexData::ValidPlyReadProperties< 0 >( readFlags + DIMENSION ); + bool hasNormal = VertexData::ValidPlyReadProperties< 1 >( readFlags + DIMENSION ); + bool hasColor = VertexData::ValidPlyReadProperties< 2 >( readFlags + DIMENSION ); + + if( !hasValue ) ERROR_OUT( "Ply file does not contain values" ); + + if( Long.set ) + if( hasColor ) + if( hasNormal ) return Execute< long long , PointStreamNormal< float , DIMENSION > , PointStreamColor< float > >(); + else return Execute< long long , PointStreamColor< float > >(); + else + if( hasNormal ) return Execute< long long , PointStreamNormal< float , DIMENSION > >(); + else return Execute< long long >(); + else + if( hasColor ) + if( hasNormal ) return Execute< int , PointStreamNormal< float , DIMENSION > , PointStreamColor< float > >(); + else return Execute< int , PointStreamColor< float > >(); + else + if( hasNormal ) return Execute< int , PointStreamNormal< float , DIMENSION > >(); + else return Execute< int >(); +} +}; + +#endif // SURFACETRIMMER_INCLUDED diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/Window.h b/modules/PoissonRecon/include/Mesh/PoissonRecon/Window.h new file mode 100644 index 00000000..4934aa13 --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/Window.h @@ -0,0 +1,436 @@ +/* +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 WINDOW_INCLUDED +#define WINDOW_INCLUDED + +#include +#include "Mesh/PoissonRecon/MyMiscellany.h" +#include "Mesh/PoissonRecon/Allocator.h" +#include "Mesh/PoissonRecon/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 ... > +{ + 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(); } + + 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 ... >(); } +}; +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; } + + 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(); } + +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; } + + 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; } + + 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 > > +{ + 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; +#if defined( __GNUC__ ) && defined( DEBUG ) +#warning "you've got me gcc" + 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 ) +#warning "you've got me gcc" + 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< 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 ) + { + _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 "Mesh/PoissonRecon/Window.inl" + +#endif // WINDOW_INCLUDED diff --git a/modules/PoissonRecon/include/Mesh/PoissonRecon/Window.inl b/modules/PoissonRecon/include/Mesh/PoissonRecon/Window.inl new file mode 100644 index 00000000..675045fd --- /dev/null +++ b/modules/PoissonRecon/include/Mesh/PoissonRecon/Window.inl @@ -0,0 +1,361 @@ +/* +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. +*/ + +////////////////////////////////////////// +// IterationDimension < WindowDimension // +////////////////////////////////////////// +template< unsigned int WindowDimension , unsigned int IterationDimensions , unsigned int CurrentIteration > +struct _WindowLoop +{ +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::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] ... ); } ); + } + 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] ... ); } ); + } + 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] ... ); } ); + } + + 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] ... ); } + } + + 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] ... ); } ); + } + 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] ... ); } ); + } + 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] ... ); } ); + } + + 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 >; + + 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] ... ); } + } + + 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] ... ); } ); + } + 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] ... ); } ); + } + 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] ... ); } ); + } + + 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 ) + { + for( int i=UIntPack< Begin ... >::First ; i::First ; i++ ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , 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] ... ); } + } + + 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] ... ); } ); + } + 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] ... ); } ); + } + 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] ... ); } ); + } + + 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 ) + { + for( int i=UIntPack< Begin ... >::First ; i::First ; i++ ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , 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 ) + { + for( int i=UIntPack< Begin ... >::First ; i::First ; i++ ){ updateState( WindowDimension - CurrentDimension , i ) ; function( w[i] ... ); } + } + + 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] ... ); } ); + } + 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] ... ); } ); + } + 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] ... ); } ); + } + + 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 ) + { + for( int i=UIntPack< Begin ... >::First ; i::First ; i++ ){ updateState( thread , WindowDimension - CurrentDimension , i ) ; function( thread , 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" ); } +}; diff --git a/test.bat b/test.bat deleted file mode 100644 index 12ad4a6b..00000000 --- a/test.bat +++ /dev/null @@ -1,5 +0,0 @@ -\Research\PoissonRecon\PoissonRecon\Bin\x64\Release\PoissonRecon.exe --in \data\PointSets\eagle_cleaned.ply --color 16 --depth 10 --out eagle.d.ply --density --voxel eagel.d.iso --voxelDepth 8 --dirichlet -\Research\PoissonRecon\PoissonRecon\Bin\x64\Release\PoissonRecon.exe --in \data\PointSets\eagle_cleaned.ply --color 16 --depth 10 --out eagle.n.ply --density --voxel eagel.n.iso --voxelDepth 8 -\Research\PoissonRecon\PoissonRecon\Bin\x64\Release\SurfaceTrimmer.exe --in eagle.d.ply --out eagle.d.trim.ply --trim 6 -\Research\PoissonRecon\PoissonRecon\Bin\x64\Release\SurfaceTrimmer.exe --in eagle.n.ply --out eagle.n.trim.ply --trim 6 -