mirror of https://github.com/wpkong/Octree.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
179 lines
6.6 KiB
179 lines
6.6 KiB
3 years ago
|
/**
|
||
|
* ------------------------------------
|
||
|
* @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) {
|
||
|
}
|