diff --git a/.gitignore b/.gitignore index de7f0f3..78c0dd4 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,5 @@ *.out *.app build/ + +test diff --git a/.travis.yml b/.travis.yml index 2974493..b52625d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,12 +12,13 @@ install: - | sudo apt-get install -y \ libocct-* \ + libhdf5-dev \ libboost-all-dev script: - mkdir build && cd build - | - cmake .. \ + cmake -DHDF5_INCLUDE_DIR=/usr/include/hdf5/serial -DHDF5_LIBRARIES="/usr/lib/x86_64-linux-gnu/hdf5/serial/libhdf5_cpp.a;/usr/lib/x86_64-linux-gnu/hdf5/serial/libhdf5.a;/usr/lib/x86_64-linux-gnu/libz.a;/usr/lib/x86_64-linux-gnu/libsz.a;/usr/lib/x86_64-linux-gnu/libaec.a;dl" .. \ -DIFC_SUPPORT=Off \ -DOCC_INCLUDE_DIR=/usr/include/opencascade \ -DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \ diff --git a/CMakeLists.txt b/CMakeLists.txt index 951e04e..585ab4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,17 +2,20 @@ cmake_minimum_required (VERSION 2.8.11) project (voxel) OPTION(IFC_SUPPORT "Build Volization Toolkit with IFC support (requires IfcOpenShell/master)." ON) -OPTION(USE_STATIC_MSVC_RUNTIME "Link to the static runtime on MSVC." ON) +OPTION(USE_STATIC_MSVC_RUNTIME "Link to the static runtime on MSVC." OFF) OPTION(ENABLE_TESTS "Enable tests." ON) include(CTest) set(CMAKE_BUILD_TYPE "RelWithDebInfo") +set(Boost_NO_BOOST_CMAKE On) if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(WIN_ARCH x64) + set(BITS 64) elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) set(WIN_ARCH Win32) + set(BITS 32) endif() set(OCC_LIBRARY_NAMES TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKOffset @@ -57,20 +60,36 @@ if(UNIX) add_definitions(-Wno-deprecated-declarations) else() if(IFC_SUPPORT) + # 1900 = VS 14.0 (v140 toolset) + # 1910-1919 = VS 15.0 (v141 toolset) + # 1920-1929 = VS 16.0 (v142 toolset) set(MSVC_YEAR 2017) if ("${MSVC_VERSION}" STREQUAL "1900") set(MSVC_YEAR 2015) + elseif(MSVC_VERSION GREATER 1919) + set(MSVC_YEAR 2019) endif() - + + file(READ "${IFCOPENSHELL_ROOT}/src/ifcparse/IfcParse.h" header) + string(REGEX MATCH "#define IFCOPENSHELL_VERSION \"[0-9a-zA-Z\\.\\-]+\"" ifcopenshell_version "${header}") + string(REGEX MATCH "[0-9]\\.[0-9]" ifcopenshell_major_version "${ifcopenshell_version}") file(TO_CMAKE_PATH "${IFCOPENSHELL_ROOT}" IFCOPENSHELL_ROOT) - if (EXISTS ${IFCOPENSHELL_ROOT}/deps-vs${MSVC_YEAR}-x86-installed/oce/${WIN_ARCH}/lib) - set(OCC_LIBRARY_DIR ${IFCOPENSHELL_ROOT}/deps-vs${MSVC_YEAR}-x86-installed/oce/${WIN_ARCH}/lib) + if (EXISTS ${IFCOPENSHELL_ROOT}/_deps-vs${MSVC_YEAR}-${WIN_ARCH}-installed/oce/${WIN_ARCH}/lib) + set(OCC_LIBRARY_DIR ${IFCOPENSHELL_ROOT}/_deps-vs${MSVC_YEAR}-${WIN_ARCH}-installed/oce/${WIN_ARCH}/lib) else() - set(OCC_LIBRARY_DIR ${IFCOPENSHELL_ROOT}/deps-vs${MSVC_YEAR}-x86-installed/opencascade-7.3.0p3/win32/lib) + if (${ifcopenshell_major_version} STREQUAL "0.7") + set(OCC_LIBRARY_DIR ${IFCOPENSHELL_ROOT}/_deps-vs${MSVC_YEAR}-${WIN_ARCH}-installed/opencascade-7.5.3/win${BITS}/lib) + else() + set(OCC_LIBRARY_DIR ${IFCOPENSHELL_ROOT}/_deps-vs${MSVC_YEAR}-${WIN_ARCH}-installed/opencascade-7.3.0p3/win${BITS}/lib) + endif() endif() - - set(OCC_INCLUDE_DIR ${IFCOPENSHELL_ROOT}/deps-vs${MSVC_YEAR}-x86-installed/oce/include/oce - ${IFCOPENSHELL_ROOT}/deps-vs${MSVC_YEAR}-x86-installed/opencascade-7.3.0p3/inc) + if (${ifcopenshell_major_version} STREQUAL "0.7") + set(OCC_INCLUDE_DIR ${IFCOPENSHELL_ROOT}/_deps-vs${MSVC_YEAR}-${WIN_ARCH}-installed/opencascade-7.5.3/inc) + else() + set(OCC_INCLUDE_DIR ${IFCOPENSHELL_ROOT}/_deps-vs${MSVC_YEAR}-${WIN_ARCH}-installed/oce/include/oce + ${IFCOPENSHELL_ROOT}/_deps-vs${MSVC_YEAR}-${WIN_ARCH}-installed/opencascade-7.3.0p3/inc) + endif() + else() file(TO_CMAKE_PATH "${OCC_LIBRARY_DIR}" OCC_LIBRARY_DIR) endif() @@ -103,6 +122,7 @@ endif() set(BOOST_COMPONENTS regex program_options iostreams system) + if (IFC_SUPPORT) # Find IfcOpenShell version, v0.6.0 does not have the IfcSchema namespace anymore file(READ "${IFCOPENSHELL_ROOT}/src/ifcparse/IfcParse.h" header) @@ -110,6 +130,11 @@ string(REGEX MATCH "#define IFCOPENSHELL_VERSION \"[0-9a-zA-Z\\.\\-]+\"" ifcopen string(REGEX MATCH "[0-9]\\.[0-9]" ifcopenshell_major_version "${ifcopenshell_version}") message(STATUS "IfcOpenShell version ${ifcopenshell_major_version}") +if (${ifcopenshell_major_version} STREQUAL "0.7") + add_definitions("-DIFCOPENSHELL_07") +endif() + + if (${ifcopenshell_major_version} STREQUAL "0.5") set(IFC_LIBRARY_NAMES IfcGeom IfcParse) add_definitions("-DIFCOPENSHELL_05") @@ -140,18 +165,30 @@ if(UNIX) string(REGEX REPLACE "([^;]+)" "${ICU_LIBRARY_DIR}/lib\\1.a" ICU_LIBRARIES "${ICU_LIBRARY_NAMES}") endif() else() - set(BOOST_ROOT ${IFCOPENSHELL_ROOT}/deps/boost_1_67_0) - set(BOOST_LIBRARYDIR ${IFCOPENSHELL_ROOT}/deps/boost_1_67_0/stage/vs${MSVC_YEAR}-${WIN_ARCH}/lib) + if (${ifcopenshell_major_version} STREQUAL "0.7") + SET(HDF5_INCLUDE_DIR ${IFCOPENSHELL_ROOT}/_deps-vs${MSVC_YEAR}-${WIN_ARCH}-installed/HDF5-1.8.22-win64/include) + SET(HDF5_LIBRARY_DIR ${IFCOPENSHELL_ROOT}/_deps-vs${MSVC_YEAR}-${WIN_ARCH}-installed/HDF5-1.8.22-win64/lib) + + SET(HDF5_LIBRARIES + "${HDF5_LIBRARY_DIR}/libhdf5_cpp.lib" + "${HDF5_LIBRARY_DIR}/libhdf5.lib" + "${HDF5_LIBRARY_DIR}/libzlib.lib" + "${HDF5_LIBRARY_DIR}/libsz.lib" + "${HDF5_LIBRARY_DIR}/libaec.lib") + endif() + + set(BOOST_ROOT ${IFCOPENSHELL_ROOT}/_deps/boost_1_74_0) + set(BOOST_LIBRARYDIR ${IFCOPENSHELL_ROOT}/_deps/boost_1_74_0/stage/vs${MSVC_YEAR}-${WIN_ARCH}/lib) set(IFC_INCLUDE_DIR ${IFCOPENSHELL_ROOT}/src) - set(IFC_LIBRARY_DIR ${IFCOPENSHELL_ROOT}/build-vs${MSVC_YEAR}-x86/${CMAKE_BUILD_TYPE}) + set(IFC_LIBRARY_DIR ${IFCOPENSHELL_ROOT}/_build-vs${MSVC_YEAR}-${WIN_ARCH}/${CMAKE_BUILD_TYPE}) string(REGEX REPLACE "([^;]+)" "${IFC_LIBRARY_DIR}/\\1.lib" IFC_LIBRARIES "${IFC_LIBRARY_NAMES}") if (${ifcopenshell_major_version} STREQUAL "0.5") set(ICU_LIBRARY_NAMES icuuc icudt) - set(ICU_LIBRARY_DIR ${IFCOPENSHELL_ROOT}/deps-vs${MSVC_YEAR}-x86-installed/icu/lib) - set(ICU_INCLUDE_DIR ${IFCOPENSHELL_ROOT}/deps-vs${MSVC_YEAR}-x86-installed/icu/include) + set(ICU_LIBRARY_DIR ${IFCOPENSHELL_ROOT}/_deps-vs${MSVC_YEAR}-${WIN_ARCH}-installed/icu/lib) + set(ICU_INCLUDE_DIR ${IFCOPENSHELL_ROOT}/_deps-vs${MSVC_YEAR}-${WIN_ARCH}-installed/icu/include) string(REGEX REPLACE "([^;]+)" "${ICU_LIBRARY_DIR}/\\1.lib" ICU_LIBRARIES "${ICU_LIBRARY_NAMES}") endif() endif() @@ -162,10 +199,11 @@ find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) message(STATUS "Boost include files found in ${Boost_INCLUDE_DIRS}") message(STATUS "Boost libraries found in ${Boost_LIBRARY_DIRS}") -include_directories(${IFC_INCLUDE_DIR} ${OCC_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/eigen) +include_directories(${IFC_INCLUDE_DIR} ${OCC_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ${HDF5_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/eigen) link_directories(${Boost_LIBRARY_DIRS}) -include_directories(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ${IFC_INCLUDE_DIR}) +include_directories(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ${HDF5_INCLUDE_DIR} ${IFC_INCLUDE_DIR}) +if (NOT MSVC) include(CheckCXXCompilerFlag) CHECK_CXX_COMPILER_FLAG("-std=c++14" COMPILER_SUPPORTS_CXX11) if(COMPILER_SUPPORTS_CXX11) @@ -173,6 +211,7 @@ if(COMPILER_SUPPORTS_CXX11) else() message(FATAL_ERROR "requires a compiler with C++11 support") endif() +endif() if (ENABLE_TESTS) @@ -211,7 +250,7 @@ ENDIF() set(LIBVOXELIZER_HEADER_FILES progress_writer.h dim3.h sweep.h shift.h collapse.h edge_detect.h fill_gaps.h offset.h polyfill.h resample.h storage.h writer.h factory.h processor.h volume.h voxelizer.h traversal.h util.h json_logger.h) set(LIBVOXELIZER_SOURCE_FILES tribox3.cpp polyfill.cpp progress_writer.cpp storage.cpp factory.cpp json_logger.cpp) add_library(libvoxel STATIC ${LIBVOXELIZER_HEADER_FILES} ${LIBVOXELIZER_SOURCE_FILES}) -target_link_libraries(libvoxel ${IFC_LIBRARIES} ${ICU_LIBRARIES} ${Boost_LIBRARIES} ${BCRYPT_LIBRARIES} ${OCC_LIBRARIES} ${LIB_RT} ${dl} ${CMAKE_THREAD_LIBS_INIT} ${WS2_LIBRARIES}) +target_link_libraries(libvoxel ${IFC_LIBRARIES} ${ICU_LIBRARIES} ${Boost_LIBRARIES} ${BCRYPT_LIBRARIES} ${OCC_LIBRARIES} ${LIB_RT} ${dl} ${CMAKE_THREAD_LIBS_INIT} ${WS2_LIBRARIES} ${HDF5_LIBRARIES}) set(LIBVOXEC_HEADER_FILES voxelfile.h voxec.h) set(LIBVOXEC_SOURCE_FILES voxec.cpp) diff --git a/json_logger.cpp b/json_logger.cpp index 3a81620..b968eab 100644 --- a/json_logger.cpp +++ b/json_logger.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace { struct ptree_writer { diff --git a/processor.h b/processor.h index d3d68ad..04d7cc5 100644 --- a/processor.h +++ b/processor.h @@ -19,9 +19,14 @@ #include // @todo < commit in IfcopenShell #include +#ifdef IFCOPENSHELL_07 +typedef IfcGeom::BRepElement elem_t; +#else typedef IfcGeom::BRepElement elem_t; #endif +#endif + typedef TopoDS_Shape geometry_t; typedef std::vector > geometry_collection_t; diff --git a/tests/test_hdf.cpp b/tests/test_hdf.cpp new file mode 100644 index 0000000..7e51745 --- /dev/null +++ b/tests/test_hdf.cpp @@ -0,0 +1,111 @@ +#include "../voxelizer.h" +#include "../writer.h" +#include "../processor.h" + +#include "H5Cpp.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef WITH_IFC +#include +#ifdef IFCOPENSHELL_05 +#include +using namespace Ifc2x3; +#else +#include +#endif +#endif + + +#ifdef WIN32 +#define DIRSEP "\\" +#else +#define DIRSEP "/" +#endif + + +TEST(HdfFileName, HDF) { + + + BRepPrimAPI_MakeBox mb(gp_Pnt(0, 0, 0), gp_Pnt(10, 10, 10)); + BRepPrimAPI_MakeSphere s(gp_Pnt(10, 10, 10), 7); + + auto x = s.Solid(); + + auto storage2 = new chunked_voxel_storage( 0, 0, 0, 1, 32, 32, 32, 32); + BRepTools breptools; + + breptools.Write(x, "sphere.brep"); + + BRepMesh_IncrementalMesh(x, 0.001); + auto vox = voxelizer(x, storage2); + vox.Convert(); + + auto storage = new chunked_voxel_storage(0., 0., 0., 0.1, 200, 150, 10, 32); + + { + BRepBuilderAPI_MakePolygon mp(gp_Pnt(1, 1, 2), gp_Pnt(16, 1, 2), gp_Pnt(16, 9.8, 2), gp_Pnt(1, 9.8, 2), true); + BRepBuilderAPI_MakeFace mf(mp.Wire()); + TopoDS_Face face = mf.Face(); + + auto vox = voxelizer(face, storage); + vox.Convert(); + } + + const double dim = 0.1; + auto storage3 = new chunked_voxel_storage(-dim, -dim, -dim, dim, 100, 100, 100, 16); + BRepPrimAPI_MakeBox make_box(8., 8., 8.); + auto vox3 = voxelizer(make_box.Solid(), storage3); + vox3.Convert(); + + hdf_writer writer; + writer.SetVoxels(storage3); + writer.Write("multi_dim_vox.h5"); + + //std::ofstream fs("voxobj.obj"); + //obj_export_helper oeh{ fs }; + //storage2->obj_export(oeh, false, false); + + // Write a 4D dataset + + const H5std_string FILE_NAME("multidim.h5"); + const H5std_string DATASET_NAME("continuous_chunks"); + const int NX = 32; // dataset dimensions + const int NY = 32; + const int NZ = 32; + const int NC = 3; + + const int RANK = 4; + H5::H5File file(FILE_NAME, H5F_ACC_TRUNC); + + hsize_t dimsf[4]; // dataset dimensions + dimsf[0] = NC; + dimsf[1] = NX; + dimsf[2] = NY; + dimsf[3] = NZ; + + H5::DataSpace dataspace(RANK, dimsf); + + H5::IntType datatype(H5::PredType::NATIVE_INT); + datatype.setOrder(H5T_ORDER_LE); + + H5::DataSet dataset = file.createDataSet(DATASET_NAME, datatype, dataspace); + + //std::vector data; + + //for (int i = 0; i < NX*NY*NZ*NC; i++) { + // data.push_back(0); + //} + + //dataset.write(data.data(), H5::PredType::NATIVE_INT); + +} diff --git a/tests/test_hdf_2.cpp b/tests/test_hdf_2.cpp new file mode 100644 index 0000000..34c53c8 --- /dev/null +++ b/tests/test_hdf_2.cpp @@ -0,0 +1,105 @@ +#include "../voxelizer.h" +#include "../writer.h" +#include "../processor.h" + +#ifdef WITH_IFC +#include +#ifdef IFCOPENSHELL_05 +#include +using namespace Ifc2x3; +#else +#include +#endif +#endif + +#include +#include +#include + +#include + +#ifdef WIN32 +#define DIRSEP "\\" +#else +#define DIRSEP "/" +#endif + + +#if defined(WITH_IFC) && !defined(IFCOPENSHELL_05) +TEST(Voxelization, IfcWallIds) { + const std::string input_filename = ".." DIRSEP "tests" DIRSEP "fixtures" DIRSEP "duplex.ifc"; + + IfcParse::IfcFile ifc_file(input_filename); + + const double d = 0.5; + + ASSERT_TRUE(ifc_file.good()); + + IfcGeom::IteratorSettings settings_surface; + settings_surface.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true); + settings_surface.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true); + + IfcGeom::entity_filter ef; + ef.include = true; + ef.entity_names = { "IfcWall" }; + ef.traverse = false; + + auto filters = std::vector({ ef }); + +#ifdef IFCOPENSHELL_07 + IfcGeom::Iterator it(settings_surface, &ifc_file, filters, 1); +#else + IfcGeom::Iterator it(settings_surface, &ifc_file, filters, 1); +#endif + ASSERT_TRUE(it.initialize()); + + geometry_collection_t geoms; + + while (true) { + TopoDS_Compound C = it.get_native()->geometry().as_compound(); + BRepMesh_IncrementalMesh(C, 0.001); + geoms.push_back({ it.get_native()->id(), C }); + if (!it.next()) { + break; + } + } + + Bnd_Box global_bounds; + for (auto& P : geoms) { + BRepBndLib::Add(P.second, global_bounds); + } + + double x1, y1, z1, x2, y2, z2; + global_bounds.Get(x1, y1, z1, x2, y2, z2); + int nx = (int)ceil((x2 - x1) / d) + 10; + int ny = (int)ceil((y2 - y1) / d) + 10; + int nz = (int)ceil((z2 - z1) / d) + 10; + + x1 -= d * 5; + y1 -= d * 5; + z1 -= d * 5; + + chunked_voxel_storage* storage = new chunked_voxel_storage(x1, y1, z1, d, nx, ny, nz, 64); + + { + progress_writer progress_1("test_wall_ids"); + processor pr(storage, progress_1); + pr.use_scanline() = false; + pr.process(geoms.begin(), geoms.end(), VOLUME_PRODUCT_ID(), output(MERGED(), "test_wall_ids.vox")); + } + + // PRINT WORLD BOUNDS OF STORAGE...e b + + //std::ofstream fs("boundaries.obj"); + //obj_export_helper oeh{ fs }; + //storage->obj_export(oeh, false, true); + + + hdf_writer writer; + writer.SetVoxels(storage); + writer.Write("test_walls.h5"); + +} +#else +TEST(Voxelization, DISABLED_IfcSpaceIds) {} +#endif \ No newline at end of file diff --git a/tests/test_space_ids.cpp b/tests/test_space_ids.cpp index 5dd6358..9f6d726 100644 --- a/tests/test_space_ids.cpp +++ b/tests/test_space_ids.cpp @@ -45,7 +45,11 @@ TEST(Voxelization, IfcSpaceIds) { auto filters = std::vector({ ef }); +#ifdef IFCOPENSHELL_07 + IfcGeom::Iterator it(settings_surface, &ifc_file, filters, 1); +#else IfcGeom::Iterator it(settings_surface, &ifc_file, filters, 1); +#endif ASSERT_TRUE(it.initialize()); diff --git a/voxec.h b/voxec.h index 509c516..59528a4 100644 --- a/voxec.h +++ b/voxec.h @@ -309,8 +309,11 @@ class op_create_geometry : public voxel_operation { settings_surface.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true); settings_surface.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true); // Only to determine whether building element parts decompositions of slabs should be processed as roofs +#ifdef IFCOPENSHELL_07 + settings_surface.set(IfcGeom::IteratorSettings::ELEMENT_HIERARCHY, true); +#else settings_surface.set(IfcGeom::IteratorSettings::SEARCH_FLOOR, true); - +#endif boost::optional include, roof_slabs; std::vector entities; @@ -376,10 +379,25 @@ class op_create_geometry : public voxel_operation { for (auto ifc_file : ifc_files.files) { - std::unique_ptr> iterator; +#ifdef IFCOPENSHELL_07 + std::unique_ptr iterator; +#else + std::unique_ptr> iterator; +#endif + #ifdef IFCOPENSHELL_05 iterator.reset(IfcGeom::Iterator(settings_surface, ifc_file, filters_surface)); + + +#elif IFCOPENSHELL_07 + + if (threads) { + iterator.reset(new IfcGeom::Iterator(settings_surface, ifc_file, filters_surface, *threads)); + } + else { + iterator.reset(new IfcGeom::Iterator(settings_surface, ifc_file, filters_surface)); + } #else if (threads) { iterator.reset(new IfcGeom::Iterator(settings_surface, ifc_file, filters_surface, *threads)); diff --git a/writer.h b/writer.h index 2ea3842..af67b39 100644 --- a/writer.h +++ b/writer.h @@ -2,13 +2,50 @@ #define WRITER_H #include "storage.h" +#include "H5Cpp.h" + +#include #include #include -class voxel_writer { -private: + +#define BEGIN_LOOP(i0, i1, j0, j1, k0, k1) {\ + vec_n<3, typename std::remove_reference::type> ijk;\ + for (ijk.get(0) = i0; ijk.get(0) < i1; ++ijk.get(0)) {\ + for (ijk.get(1) = j0; ijk.get(1) < j1; ++ijk.get(1)) {\ + for (ijk.get(2) = k0; ijk.get(2) < k1; ++ijk.get(2)) { + +#define BEGIN_LOOP_I(i0, i1, j0, j1, k0, k1) {\ + vec_n<3, typename std::remove_reference::type> ijk;\ + for (ijk.get(0) = i0; ijk.get(0) <= i1; ++ijk.get(0)) {\ + for (ijk.get(1) = j0; ijk.get(1) <= j1; ++ijk.get(1)) {\ + for (ijk.get(2) = k0; ijk.get(2) <= k1; ++ijk.get(2)) { + +#define BEGIN_LOOP2(v0, v1) BEGIN_LOOP(v0.template get<0>(), v1.template get<0>(), v0.template get<1>(), v1.template get<1>(), v0.template get<2>(), v1.template get<2>()) + +#define BEGIN_LOOP_I2(v0, v1) BEGIN_LOOP_I(v0.template get<0>(), v1.template get<0>(), v0.template get<1>(), v1.template get<1>(), v0.template get<2>(), v1.template get<2>()) + +#define BEGIN_LOOP_ZERO_2(v1) BEGIN_LOOP2(make_vec((decltype(v1)::element_type)0, (decltype(v1)::element_type)0, (decltype(v1)::element_type)0), v1) + +#define END_LOOP }}}} + + +class abstract_writer { + +public: abstract_voxel_storage* voxels_; + void SetVoxels(abstract_voxel_storage* voxels) { + voxels_ = voxels; + } + + virtual void Write(const std::string& fnc, std::string statement="default") = 0; + + +}; + +class voxel_writer :public abstract_writer { +private: std::ofstream& assert_good_(const std::string& fn, std::ofstream& fs) { if (!fs.good()) { @@ -18,11 +55,7 @@ class voxel_writer { } public: - void SetVoxels(abstract_voxel_storage* voxels) { - voxels_ = voxels; - } - - void Write(const std::string& fnc) { + void Write(const std::string& fnc, std::string statement = "default") { { std::string fn = fnc + std::string(".index"); std::ofstream fs(fn.c_str()); @@ -46,4 +79,323 @@ class voxel_writer { } }; + +class hdf_writer :public abstract_writer { + +public: + void Write(const std::string& fnc, std::string statement="default") { + + abstract_chunked_voxel_storage* storage = (abstract_chunked_voxel_storage*)voxels_; + + int continuous_count = 0; + int planar_count = 0; + int constant_count = 0; + + hsize_t nchunks_x = storage->num_chunks().get(0); + hsize_t nchunks_y = storage->num_chunks().get(1); + hsize_t nchunks_z = storage->num_chunks().get(2); + + BEGIN_LOOP(size_t(0), nchunks_x, 0U, nchunks_y, 0U, nchunks_z) + auto c = storage->get_chunk(ijk); + + if (c == nullptr) { + constant_count++; + + } + + else { + + if (c->is_explicit()) { + continuous_count++; + } + + else { + if (c->is_constant()) { + constant_count++; + } + + + else { + planar_count++; + + } + } + + + } + + END_LOOP; + + + + //TODO: Handle existing file (with group) case + const H5std_string FILE_NAME(fnc); + H5::H5File file(FILE_NAME, H5F_ACC_RDWR); + + H5::Group operation_group = H5::Group(file.createGroup(statement)); + + + // Continuous chunks dataset + const H5std_string CONTINUOUS_DATASET_NAME("continuous_chunks"); + + const hsize_t NC = continuous_count; + const hsize_t NX = storage->chunk_size(); + const hsize_t NY = storage->chunk_size(); + const hsize_t NZ = storage->chunk_size(); + + const int RANK = 4; + + hsize_t dimsf[4]; + dimsf[0] = NC; + dimsf[1] = NX; + dimsf[2] = NY; + dimsf[3] = NZ; + + H5::DataSpace dataspace(RANK, dimsf); + H5::IntType datatype(H5::PredType::NATIVE_INT); + datatype.setOrder(H5T_ORDER_LE); + H5::DataSet dataset = operation_group.createDataSet(CONTINUOUS_DATASET_NAME, datatype, dataspace); + + // Continuous dataset hyperslab preparation + hsize_t offset[4]; + offset[0] = -1; + offset[1] = 0; + offset[2] = 0; + offset[3] = 0; + + hsize_t slab_dimsf[4] = { 1, 1, 1, 1 }; + H5::DataSpace mspace2(RANK, slab_dimsf); + + + + //Planar chunks dataset + typedef struct s2_t { + int axis; + hvl_t offsets; + } s2_t; + + const H5std_string AXIS("axis"); + const H5std_string OFFSETS("offsets"); + + H5::VarLenType varlen_type(&H5::PredType::NATIVE_INT); + H5::CompType mtype2(sizeof(s2_t)); + mtype2.insertMember(AXIS, HOFFSET(s2_t, axis), H5::PredType::NATIVE_INT); + mtype2.insertMember(OFFSETS, HOFFSET(s2_t, offsets), varlen_type); + const H5std_string PLANAR_DATASET_NAME("planar_chunks"); + + const int PLANAR_RANK = 1; + hsize_t planar_dimsf[1]; + planar_dimsf[0] = planar_count; + H5::DataSpace planar_dataspace(PLANAR_RANK, planar_dimsf); + H5::DataSet planar_dataset = operation_group.createDataSet(PLANAR_DATASET_NAME, mtype2, planar_dataspace); + hsize_t planar_offset[1]; + planar_offset[0] = -1; + hsize_t planar_dims[1] = { 1 }; + H5::DataSpace planar_space(PLANAR_RANK, planar_dims); + + + + //Constant chunks dataset + const H5std_string CONSTANT_DATASET_NAME("constant_chunks"); + + const int CONSTANT_RANK = 1; + hsize_t constant_dimsf[1]; + constant_dimsf[0] = constant_count; + H5::DataSpace constant_dataspace(CONSTANT_RANK, constant_dimsf); + H5::DataSet constant_dataset = operation_group.createDataSet(CONSTANT_DATASET_NAME, H5::PredType::NATIVE_INT, constant_dataspace); + hsize_t constant_offset[1]; + constant_offset[0] = -1; + hsize_t constant_dims[1] = { 1 }; + H5::DataSpace constant_space(CONSTANT_RANK, constant_dims); + + + + // Regions dataset + const H5std_string REGIONS_DATASET_NAME("regions"); + + hsize_t regions_dimsf[1]; + regions_dimsf[0] = continuous_count + constant_count + planar_count; + + const int REGION_RANK = 1; + + H5::DataSpace regions_dataspace(REGION_RANK, regions_dimsf); + H5::PredType regions_datatype(H5::PredType::STD_REF_DSETREG); + regions_datatype.setOrder(H5T_ORDER_LE); + H5::DataSet regions_dataset = operation_group.createDataSet(REGIONS_DATASET_NAME, regions_datatype, regions_dataspace); + + // Regions dataset hyperslab preparation + hsize_t region_offset[1]; + region_offset[0] = -1; + hsize_t region_slab_dimsf[1] = { 1 }; + H5::DataSpace mspace3(REGION_RANK, region_slab_dimsf); + + // Continuous chunks region hyperslab preparation + hsize_t chunk_offset[4]; + const int CHUNK_RANK = 4; + chunk_offset[0] = -1; + chunk_offset[1] = 0; + chunk_offset[2] = 0; + chunk_offset[3] = 0; + hsize_t chunk_dimsf[4] = { 1, NX, NY, NZ }; + H5::DataSpace chunk_space(CHUNK_RANK, chunk_dimsf); + + // Planar chunks region hyperslab preparation + hsize_t planar_chunk_offset[1]; + const int PLANAR_CHUNK_RANK = 1; + planar_chunk_offset[0] = 1; + hsize_t planar_chunk_dimsf[1] = { 1 }; + H5::DataSpace planar_chunk_space(PLANAR_CHUNK_RANK, planar_chunk_dimsf); + + // Constant chunks region hyperslab preparation + hsize_t constant_chunk_offset[1]; + const int CONSTANT_CHUNK_RANK = 1; + constant_chunk_offset[0] = 1; + hsize_t constant_chunk_dimsf[1] = { 1 }; + H5::DataSpace constant_chunk_space(CONSTANT_CHUNK_RANK, constant_chunk_dimsf); + + + BEGIN_LOOP(size_t(0), nchunks_x, 0U, nchunks_y, 0U, nchunks_z) + auto c = storage->get_chunk(ijk); + + + + if (c == nullptr) { + + constant_offset[0]++; + constant_dataspace.selectHyperslab(H5S_SELECT_SET, constant_dims, constant_offset); + int constant_value[1] = { 0 }; + dataset.write(constant_value, H5::PredType::NATIVE_INT, constant_space, constant_dataspace); + + + region_offset[0]++; + regions_dataspace.selectHyperslab(H5S_SELECT_SET, region_slab_dimsf, region_offset); + + constant_chunk_offset[0]++; + + hobj_ref_t inter[1]; + file.reference(&inter[0], "/" + statement + "/constant_chunks", constant_dataspace, H5R_DATASET_REGION); + regions_dataset.write(inter, H5::PredType::STD_REF_DSETREG, mspace3, regions_dataspace); + } + + else { + + if (c->is_explicit()) { + + offset[0]++; + + size_t i0, j0, k0, i1, j1, k1; + i0 = 0; + j0 = 0; + k0 = 0; + c->extents().tie(i1, j1, k1); + + BEGIN_LOOP_ZERO_2(make_vec(i1, j1, k1)) + offset[1] = ijk.get(0); + offset[2] = ijk.get(1); + offset[3] = ijk.get(2); + dataspace.selectHyperslab(H5S_SELECT_SET, slab_dimsf, offset); + + if (c->value_bits() == 32) { + + uint32_t v; + std::vector hslab; + c->Get(ijk, &v); + hslab.push_back(v); + dataset.write(hslab.data(), H5::PredType::NATIVE_INT, mspace2, dataspace); + + } + + else { + std::vector hslab = { c->Get(ijk) }; + dataset.write(hslab.data(), H5::PredType::NATIVE_INT, mspace2, dataspace); + } + + + END_LOOP; + + region_offset[0]++; + regions_dataspace.selectHyperslab(H5S_SELECT_SET, region_slab_dimsf, region_offset); + + chunk_offset[0]++; + + dataspace.selectHyperslab(H5S_SELECT_SET, chunk_dimsf, chunk_offset); + + hobj_ref_t inter[1]; + file.reference(&inter[0], "/" + statement + "/continuous_chunks", dataspace, H5R_DATASET_REGION); + regions_dataset.write(inter, H5::PredType::STD_REF_DSETREG, mspace3, regions_dataspace); + + } + + else { + if (c->is_constant()) { + + constant_offset[0]++; + constant_dataspace.selectHyperslab(H5S_SELECT_SET, constant_dims, constant_offset); + int constant_value[1] = { 1 }; + dataset.write(constant_value, H5::PredType::NATIVE_INT, constant_space, constant_dataspace); + + + region_offset[0]++; + regions_dataspace.selectHyperslab(H5S_SELECT_SET, region_slab_dimsf, region_offset); + + constant_chunk_offset[0]++; + + + hobj_ref_t inter[1]; + file.reference(&inter[0], "/" + statement + "/constant_chunks", constant_dataspace, H5R_DATASET_REGION); + regions_dataset.write(inter, H5::PredType::STD_REF_DSETREG, mspace3, regions_dataspace); + + } + + + else { + + planar_voxel_storage* planvox = (planar_voxel_storage*)c; + + auto axis = planvox->axis(); + auto off = planvox->offsets(); + + std::vector offsets(off.begin(), off.end()); + + planar_offset[0]++; + + planar_dataspace.selectHyperslab(H5S_SELECT_SET, planar_dims, planar_offset); + std::vector input_vec; + hvl_t varlen_offsets; + + + varlen_offsets.len = offsets.size(); + + varlen_offsets.p = offsets.data(); + s2_t compound_data; + compound_data.axis = axis; + compound_data.offsets = varlen_offsets; + input_vec.push_back(compound_data); + planar_dataset.write(&compound_data, mtype2, planar_space, planar_dataspace); + + + region_offset[0]++; + regions_dataspace.selectHyperslab(H5S_SELECT_SET, region_slab_dimsf, region_offset); + + planar_chunk_offset[0]++; + + + hobj_ref_t inter[1]; + file.reference(&inter[0], "/" + statement + "/planar_chunks", planar_dataspace, H5R_DATASET_REGION); + regions_dataset.write(inter, H5::PredType::STD_REF_DSETREG, mspace3, regions_dataspace); + + } + } + + + } + END_LOOP + } +}; + + + + + + #endif