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

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) {
}