mirror of https://github.com/wpkong/Octree.git
16 changed files with 715 additions and 212 deletions
@ -0,0 +1,21 @@ |
|||||
|
/**
|
||||
|
* ------------------------------------ |
||||
|
* @author: Weipeng Kong |
||||
|
* @date: 2022/2/23 |
||||
|
* @email: yjxkwp\@foxmail.com |
||||
|
* @description: |
||||
|
* ------------------------------------ |
||||
|
**/ |
||||
|
|
||||
|
#ifndef OCTREE_SRC_SOLIDVOXELBUILDER_H_ |
||||
|
#define OCTREE_SRC_SOLIDVOXELBUILDER_H_ |
||||
|
|
||||
|
#include "Octree/voxel/Voxel.h" |
||||
|
|
||||
|
namespace Octree { |
||||
|
class SolidVoxelBuilder { |
||||
|
|
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
#endif //OCTREE_SRC_SOLIDVOXELBUILDER_H_
|
@ -0,0 +1,35 @@ |
|||||
|
/**
|
||||
|
* ------------------------------------ |
||||
|
* @author: Weipeng Kong |
||||
|
* @date: 2022/2/23 |
||||
|
* @email: yjxkwp\@foxmail.com |
||||
|
* @description: |
||||
|
* ------------------------------------ |
||||
|
**/ |
||||
|
|
||||
|
#ifndef OCTREE_INCLUDE_OCTREE_VOXEL_SURFACEVOXELBUILDER_H_ |
||||
|
#define OCTREE_INCLUDE_OCTREE_VOXEL_SURFACEVOXELBUILDER_H_ |
||||
|
|
||||
|
|
||||
|
#include "Octree/BaseOctree.h" |
||||
|
#include "Octree/OctreeBuilder.h" |
||||
|
|
||||
|
namespace Octree { |
||||
|
class Voxel; |
||||
|
|
||||
|
class SurfaceVoxelBuilder { |
||||
|
private: |
||||
|
AABB aabb; |
||||
|
int _x, _y, _z; |
||||
|
double block_size; |
||||
|
BaseOctree &octree; |
||||
|
const pMesh::Triangle3dMesh<> &mesh; |
||||
|
|
||||
|
public: |
||||
|
explicit SurfaceVoxelBuilder(BaseOctree &octree, const pMesh::Triangle3dMesh<> &mesh, double block_size); |
||||
|
|
||||
|
void build(Voxel &voxel); |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
#endif //OCTREE_INCLUDE_OCTREE_VOXEL_SURFACEVOXELBUILDER_H_
|
@ -0,0 +1,42 @@ |
|||||
|
/**
|
||||
|
* ------------------------------------ |
||||
|
* @author: Weipeng Kong |
||||
|
* @date: 2022/2/23 |
||||
|
* @email: yjxkwp\@foxmail.com |
||||
|
* @description: |
||||
|
* ------------------------------------ |
||||
|
**/ |
||||
|
|
||||
|
#ifndef OCTREE_INCLUDE_OCTREE_VOXEL_VOXEL_H_ |
||||
|
#define OCTREE_INCLUDE_OCTREE_VOXEL_VOXEL_H_ |
||||
|
|
||||
|
#include <vector> |
||||
|
#include <Octree/AABB.h> |
||||
|
|
||||
|
namespace Octree { |
||||
|
class Voxel { |
||||
|
public: |
||||
|
AABB aabb; |
||||
|
int _x, _y, _z; |
||||
|
std::vector<bool> voxels; |
||||
|
|
||||
|
public: |
||||
|
Voxel() = default; |
||||
|
Voxel(int _x, int _y, int _z); |
||||
|
Voxel(const std::vector<bool> &value, int _x, int _y, int _z); |
||||
|
|
||||
|
public: |
||||
|
/**
|
||||
|
* Tool function: calc 1D index from 3D coordinate |
||||
|
* @param x |
||||
|
* @param y |
||||
|
* @param z |
||||
|
* @return |
||||
|
*/ |
||||
|
int id_at(int x, int y, int z) const; |
||||
|
|
||||
|
bool at(int x, int y, int z) const; |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
#endif //OCTREE_INCLUDE_OCTREE_VOXEL_VOXEL_H_
|
@ -0,0 +1,10 @@ |
|||||
|
/**
|
||||
|
* ------------------------------------ |
||||
|
* @author: Weipeng Kong |
||||
|
* @date: 2022/2/23 |
||||
|
* @email: yjxkwp\@foxmail.com |
||||
|
* @description: |
||||
|
* ------------------------------------ |
||||
|
**/ |
||||
|
|
||||
|
#include "Octree/voxel/SolidVoxelBuilder.h" |
@ -0,0 +1,60 @@ |
|||||
|
/**
|
||||
|
* ------------------------------------ |
||||
|
* @author: Weipeng Kong |
||||
|
* @date: 2022/2/23 |
||||
|
* @email: yjxkwp\@foxmail.com |
||||
|
* @description: |
||||
|
* ------------------------------------ |
||||
|
**/ |
||||
|
|
||||
|
#include "Octree/voxel/SurfaceVoxelBuilder.h" |
||||
|
#include "Octree/voxel/Voxel.h" |
||||
|
#include <queue> |
||||
|
|
||||
|
Octree::SurfaceVoxelBuilder::SurfaceVoxelBuilder(BaseOctree &octree, |
||||
|
const pMesh::Triangle3dMesh<> &mesh, |
||||
|
double block_size) : |
||||
|
block_size(block_size), octree(octree), mesh(mesh) { |
||||
|
aabb = AABB::ToIntegerSizeAABB(octree.aabb(), block_size, _x, _y, _z); |
||||
|
} |
||||
|
|
||||
|
void Octree::SurfaceVoxelBuilder::build(Octree::Voxel &voxel) { |
||||
|
voxel._x = _x; |
||||
|
voxel._y = _y; |
||||
|
voxel._z = _z; |
||||
|
voxel.aabb = aabb; |
||||
|
voxel.voxels.clear(); |
||||
|
voxel.voxels = std::vector<bool>(_x * _y * _z, false); |
||||
|
|
||||
|
BOOST_LOG_TRIVIAL(debug) << "Voxel size: " << _x << " " << _y << " " << _z; |
||||
|
|
||||
|
for (int i = 0; i < _x; ++i) { |
||||
|
double base_x = this->aabb.min().x() + i * block_size; |
||||
|
for (int j = 0; j < _y; ++j) { |
||||
|
double base_y = this->aabb.min().y() + j * block_size; |
||||
|
for (int k = 0; k < _z; ++k) { |
||||
|
double base_z = this->aabb.min().z() + k * block_size; |
||||
|
|
||||
|
AABB vox({base_x, base_y, base_z}, {base_x + block_size, base_y + block_size, base_z + block_size}); |
||||
|
auto candidates_vox = octree.map_voxel(vox); |
||||
|
bool exit_flag = false; |
||||
|
for (auto candidate : candidates_vox) { |
||||
|
for (uint32_t tid : candidate->tri_ids) { |
||||
|
const pMesh::Triangle3dMesh<>::Face &face = mesh.faces[tid].attr; |
||||
|
if (vox.intersect_triangle(mesh.vertices[face.vertices[0].id()].attr.coordinate, |
||||
|
mesh.vertices[face.vertices[1].id()].attr.coordinate, |
||||
|
mesh.vertices[face.vertices[2].id()].attr.coordinate)) { |
||||
|
voxel.voxels[voxel.id_at(i, j, k)] = true; |
||||
|
exit_flag = true; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
if(exit_flag) { |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
@ -0,0 +1,24 @@ |
|||||
|
/**
|
||||
|
* ------------------------------------ |
||||
|
* @author: Weipeng Kong |
||||
|
* @date: 2022/2/23 |
||||
|
* @email: yjxkwp\@foxmail.com |
||||
|
* @description: |
||||
|
* ------------------------------------ |
||||
|
**/ |
||||
|
|
||||
|
#include "Octree/voxel/Voxel.h" |
||||
|
|
||||
|
Octree::Voxel::Voxel(const std::vector<bool> &value, int _x, int _y, int _z): voxels(value), _x(_x), _y(_y), _z(_z) { |
||||
|
|
||||
|
} |
||||
|
|
||||
|
Octree::Voxel::Voxel(int _x, int _y, int _z): Voxel(std::vector<bool>(_x * _y * _z, false), _x, _y, _z) { |
||||
|
|
||||
|
} |
||||
|
int Octree::Voxel::id_at(int x, int y, int z) const { |
||||
|
return ((z * _y) + y) * _x + x; |
||||
|
} |
||||
|
bool Octree::Voxel::at(int x, int y, int z) const { |
||||
|
return voxels[id_at(x,y,z)]; |
||||
|
} |
@ -0,0 +1 @@ |
|||||
|
test-path.h |
@ -0,0 +1,6 @@ |
|||||
|
configure_file( |
||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/test-path.h.in" |
||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/test-path.h" |
||||
|
) |
||||
|
add_executable(solid_octree_test main.cpp) |
||||
|
target_link_libraries(solid_octree_test Octree pMesh) |
@ -0,0 +1,178 @@ |
|||||
|
/**
|
||||
|
* ------------------------------------ |
||||
|
* @author: Weipeng Kong |
||||
|
* @date: 2021/11/17 |
||||
|
* @email: yjxkwp@foxmail.com |
||||
|
* @site: https://donot.fit
|
||||
|
* @description: |
||||
|
* ------------------------------------ |
||||
|
**/ |
||||
|
|
||||
|
#include <iostream> |
||||
|
#include "Octree/sdf/SDFOctree.h" |
||||
|
#include "Octree/OctreeBuilder.h" |
||||
|
#include "Octree/OctreeTraverser.h" |
||||
|
#include "Octree/sdf/SDFTraversalSampler.h" |
||||
|
#include <igl/marching_cubes.h> |
||||
|
#include <igl/voxel_grid.h> |
||||
|
#include <igl/writeOBJ.h> |
||||
|
#include <pMesh/mesh/TriangleMesh.h> |
||||
|
#include <pMesh/mesh/HexahedronMesh.h> |
||||
|
#include <pMesh/io/reader/OBJReader.h> |
||||
|
#include <pMesh/io/reader/VTKReader.h> |
||||
|
#include <pMesh/io/writer/VTKWriter.h> |
||||
|
#include <pMesh/io/adapter/DefaultReadAdapter.h> |
||||
|
#include <pMesh/io/adapter/DefaultWriteAdapter.h> |
||||
|
#include <boost/timer.hpp> |
||||
|
#include <boost/log/trivial.hpp> |
||||
|
#include <pMesh/io/reader/BaseReader.h> |
||||
|
#include <pMesh/io/adapter/DefaultReadAdapter.h> |
||||
|
#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) { |
||||
|
} |
@ -0,0 +1,16 @@ |
|||||
|
/**
|
||||
|
* ------------------------------------ |
||||
|
* @author: Weipeng Kong |
||||
|
* @date: 2021/12/1 |
||||
|
* @email: yjxkwp@foxmail.com |
||||
|
* @site: https://donot.fit
|
||||
|
* @description: |
||||
|
* ------------------------------------ |
||||
|
**/ |
||||
|
|
||||
|
#ifndef OCTREE_SDF_TEST_PATH_H |
||||
|
#define OCTREE_SDF_TEST_PATH_H |
||||
|
|
||||
|
#define TEST_DATA_BASE_PATH "@TEST_DATA_BASE_PATH@" |
||||
|
|
||||
|
#endif //OCTREE_SDF_TEST_PATH_H
|
Loading…
Reference in new issue