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