/** * ------------------------------------ * @author: Weipeng Kong * @date: 2021/11/17 * @email: yjxkwp@foxmail.com * @site: https://donot.fit * @description: * ------------------------------------ **/ #include #include "Octree/sdf/SDFOctree.h" #include "Octree/OctreeBuilder.h" #include "Octree/OctreeTraverser.h" #include "Octree/sdf/SDFTraversalSampler.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "test-path.h" #include "Octree/voxel/SurfaceVoxelBuilder.h" #include "Octree/voxel/Voxel.h" class VTKTraverser : public pMesh::io::BaseReader, public Octree::OctreeTraverser { int node_cnt = 0; public: explicit VTKTraverser(const Octree::BaseOctree &octree, const TraverseStrategy strategy = DFS); void visit_node(Octree::OctreeNode &node) override; pMesh::io::ReadAdapter *reader_adapter; bool operator>>(pMesh::io::ReadAdapter &adapter) override; }; int main() { pMesh::io::fs_path data_base_path = TEST_DATA_BASE_PATH; BOOST_LOG_TRIVIAL(debug) << "base data path is " << boost::filesystem::absolute(data_base_path); auto mesh_path = data_base_path / "stanford-bunny.obj"; auto out_octree_path = data_base_path / "stanford-bunny-octree.vtk"; auto out_voxel_path = data_base_path / "stanford-bunny-voxel.vtk"; auto out_error_path = data_base_path / "stanford-bunny-error_points.vtk"; pMesh::Triangle3dMesh<> mesh; pMesh::io::OBJReader(mesh_path) >> pMesh::io::DefaultSurfaceReadAdapter<>(mesh, false)(); BOOST_LOG_TRIVIAL(info) << "Load Face #" << mesh.f_size(); const int level = 4; const double block_size = 0.005; boost::timer t; Octree::AABB aabb(mesh.aabb()); Octree::BaseOctree octree(level, aabb); Octree::OctreeBuilder builder(mesh, octree); builder.build(); BOOST_LOG_TRIVIAL(debug) << "time elapse " << t.elapsed(); auto aabb_size = octree.aabb().size(); BOOST_LOG_TRIVIAL(debug) << "Global AABB " << aabb_size.transpose(); auto final_aabb_size = aabb_size / pow(2, level); BOOST_LOG_TRIVIAL(debug) << "Local AABB " << final_aabb_size.transpose(); pMesh::HexahedronMesh<> hexahedron_mesh; VTKTraverser(octree) >> pMesh::io::DefaultVolumeReadAdapter<>(hexahedron_mesh)(); pMesh::io::VTKWriter(12, out_octree_path) << pMesh::io::DefaultVolumeWriteAdapter<>(hexahedron_mesh)(); t.restart(); Octree::Voxel voxel; Octree::SurfaceVoxelBuilder voxel_builder(octree, mesh, block_size); voxel_builder.build(voxel); BOOST_LOG_TRIVIAL(debug) << "SurfaceVoxelBuilder time elapse " << t.elapsed(); // output voxel pMesh::HexahedronMesh<> voxelMesh; { auto aabb = voxel.aabb; int _x = voxel._x; int _y = voxel._y; int _z = voxel._z; for (int i = 0; i < _x; ++i) { double base_x = aabb.min().x() + i * block_size; for (int j = 0; j < _y; ++j) { double base_y = aabb.min().y() + j * block_size; for (int k = 0; k < _z; ++k) { double base_z = aabb.min().z() + k * block_size; if(voxel.voxels[voxel.id_at(i, j, k)]){ Octree::AABB v({base_x, base_y, base_z}, {base_x + block_size, base_y + block_size, base_z + block_size}); voxelMesh.vertices.emplace_back(pMesh::Volume::Vertex(0, {v.min().x(),v.min().y(),v.min().z()})); voxelMesh.vertices.emplace_back(pMesh::Volume::Vertex(1, {v.max().x(),v.min().y(),v.min().z()})); voxelMesh.vertices.emplace_back(pMesh::Volume::Vertex(2, {v.max().x(),v.max().y(),v.min().z()})); voxelMesh.vertices.emplace_back(pMesh::Volume::Vertex(3, {v.min().x(),v.max().y(),v.min().z()})); voxelMesh.vertices.emplace_back(pMesh::Volume::Vertex(4, {v.min().x(),v.min().y(),v.max().z()})); voxelMesh.vertices.emplace_back(pMesh::Volume::Vertex(5, {v.max().x(),v.min().y(),v.max().z()})); voxelMesh.vertices.emplace_back(pMesh::Volume::Vertex(6, {v.max().x(),v.max().y(),v.max().z()})); voxelMesh.vertices.emplace_back(pMesh::Volume::Vertex(7, {v.min().x(),v.max().y(),v.max().z()})); int base_id = voxelMesh.v_size(); pMesh::Volume::Cell cell; using PPP = pMesh::Volume::VertexHandle; cell.vertices = { PPP(base_id + 0), PPP(base_id + 1), PPP(base_id + 2), PPP(base_id + 3), PPP(base_id + 4), PPP(base_id + 5), PPP(base_id + 6), PPP(base_id + 7) }; voxelMesh.cells.emplace_back(cell); } } } } } pMesh::io::VTKWriter(12, out_voxel_path) << pMesh::io::DefaultVolumeWriteAdapter<>(voxelMesh)(); return 0; } void VTKTraverser::visit_node(Octree::OctreeNode &node) { if (node.get_level() != octree.get_max_level()) { // assert(!node.is_leaf()); assert(node.tri_ids.empty()); return; } auto min = node.get_aabb().min(); auto max = node.get_aabb().max(); reader_adapter->feed_vertex({min.x(), min.y(), min.z()}); reader_adapter->feed_vertex({max.x(), min.y(), min.z()}); reader_adapter->feed_vertex({max.x(), max.y(), min.z()}); reader_adapter->feed_vertex({min.x(), max.y(), min.z()}); reader_adapter->feed_vertex({min.x(), min.y(), max.z()}); reader_adapter->feed_vertex({max.x(), min.y(), max.z()}); reader_adapter->feed_vertex({max.x(), max.y(), max.z()}); reader_adapter->feed_vertex({min.x(), max.y(), max.z()}); reader_adapter->feed_collection( { 0 + node_cnt, 1 + node_cnt, 2 + node_cnt, 3 + node_cnt, 4 + node_cnt, 5 + node_cnt, 6 + node_cnt, 7 + node_cnt }); node_cnt += 8; } bool VTKTraverser::operator>>(pMesh::io::ReadAdapter &adapter) { reader_adapter = &adapter; node_cnt = 0; adapter.start(); this->traverse(); adapter.end(); return true; } VTKTraverser::VTKTraverser(const Octree::BaseOctree &octree, const OctreeTraverser::TraverseStrategy strategy) : OctreeTraverser( octree, strategy) { }