mirror of https://github.com/wpkong/Octree.git
30 changed files with 379 additions and 161 deletions
@ -1,52 +0,0 @@ |
|||
/**
|
|||
* ------------------------------------ |
|||
* @author: Weipeng Kong |
|||
* @date: 2021/11/22 |
|||
* @email: yjxkwp@foxmail.com |
|||
* @site: https://donot.fit
|
|||
* @description: |
|||
* ------------------------------------ |
|||
**/ |
|||
|
|||
#ifndef OCTREE_OCTREEIO_H |
|||
#define OCTREE_OCTREEIO_H |
|||
|
|||
#include <boost/filesystem.hpp> |
|||
|
|||
|
|||
namespace Octree { |
|||
|
|||
class BaseOctree; |
|||
class OctreeNode; |
|||
|
|||
class OctreeIO { |
|||
protected: |
|||
using fs_path = boost::filesystem::path; |
|||
}; |
|||
|
|||
class OctreeSaver : public OctreeIO { |
|||
private: |
|||
const BaseOctree &octree; |
|||
|
|||
public: |
|||
explicit OctreeSaver(const BaseOctree &octree); |
|||
|
|||
void save(const fs_path &path); |
|||
|
|||
private: |
|||
void save_recursively(const OctreeNode &node); |
|||
}; |
|||
|
|||
class OctreeLoader : public OctreeIO { |
|||
private: |
|||
BaseOctree &octree; |
|||
|
|||
public: |
|||
explicit OctreeLoader(BaseOctree &octree); |
|||
|
|||
void load(const fs_path &path); |
|||
}; |
|||
|
|||
} |
|||
|
|||
#endif //OCTREE_OCTREEIO_H
|
@ -1,29 +0,0 @@ |
|||
/**
|
|||
* ------------------------------------ |
|||
* @author: Weipeng Kong |
|||
* @date: 2021/11/22 |
|||
* @email: yjxkwp@foxmail.com |
|||
* @site: https://donot.fit
|
|||
* @description: |
|||
* ------------------------------------ |
|||
**/ |
|||
|
|||
#include "../include/Octree/OctreeIO.h" |
|||
#include "Octree/BaseOctree.h" |
|||
|
|||
namespace SerializationTool{ |
|||
|
|||
|
|||
} |
|||
|
|||
Octree::OctreeSaver::OctreeSaver(const Octree::BaseOctree &octree): octree(octree) { |
|||
|
|||
} |
|||
|
|||
void Octree::OctreeSaver::save(const Octree::OctreeIO::fs_path &path) { |
|||
|
|||
} |
|||
|
|||
void Octree::OctreeSaver::save_recursively(const Octree::OctreeNode &node) { |
|||
|
|||
} |
@ -0,0 +1 @@ |
|||
test-path.h |
@ -1,3 +1,6 @@ |
|||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/) |
|||
configure_file( |
|||
"${CMAKE_CURRENT_SOURCE_DIR}/test-path.h.in" |
|||
"${CMAKE_CURRENT_SOURCE_DIR}/test-path.h" |
|||
) |
|||
add_executable(octree_test main.cpp) |
|||
target_link_libraries(octree_test Octree pMesh) |
|||
|
@ -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
|
@ -0,0 +1 @@ |
|||
test-path.h |
@ -1,3 +1,6 @@ |
|||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/) |
|||
configure_file( |
|||
"${CMAKE_CURRENT_SOURCE_DIR}/test-path.h.in" |
|||
"${CMAKE_CURRENT_SOURCE_DIR}/test-path.h" |
|||
) |
|||
add_executable(sdf_test main.cpp) |
|||
target_link_libraries(sdf_test Octree pMesh) |
|||
|
@ -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
|
@ -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(udf_test main.cpp) |
|||
target_link_libraries(udf_test Octree pMesh) |
@ -0,0 +1,198 @@ |
|||
/**
|
|||
* ------------------------------------ |
|||
* @author: Weipeng Kong |
|||
* @date: 2021/11/17 |
|||
* @email: yjxkwp@foxmail.com |
|||
* @site: https://donot.fit
|
|||
* @description: |
|||
* ------------------------------------ |
|||
**/ |
|||
|
|||
#include <iostream> |
|||
#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/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 "Octree/udf/UDFOctree.h" |
|||
#include "Octree/OctreeBuilder.h" |
|||
#include "Octree/OctreeTraverser.h" |
|||
#include "Octree/udf/UDFTraversalSampler.h" |
|||
#include "test-path.h" |
|||
|
|||
|
|||
class VTKTraverser : public pMesh::io::BaseReader, public Octree::OctreeTraverser { |
|||
int node_cnt = 0; |
|||
public: |
|||
explicit VTKTraverser(const Octree::UDFOctree &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_mc_path = data_base_path / "stanford-bunny-mc.obj"; |
|||
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 = 2; |
|||
const double sample_step = 0.004; |
|||
|
|||
boost::timer t; |
|||
Octree::AABB aabb(mesh.aabb()); |
|||
|
|||
Octree::UDFOctree 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(); |
|||
|
|||
// origin points of model
|
|||
int opm = std::ceil(aabb_size.x() / sample_step) * |
|||
std::ceil(aabb_size.y() / sample_step) * |
|||
std::ceil(aabb_size.z() / sample_step); |
|||
|
|||
BOOST_LOG_TRIVIAL(debug) << "Origin Points of model = " << opm; |
|||
|
|||
// points per voxel
|
|||
int ppv = std::ceil(final_aabb_size.x() / sample_step) * |
|||
std::ceil(final_aabb_size.y() / sample_step) * |
|||
std::ceil(final_aabb_size.z() / sample_step); |
|||
|
|||
BOOST_LOG_TRIVIAL(debug) << "Points per voxel = " << ppv; |
|||
|
|||
pMesh::HexahedronMesh<> hexahedron_mesh; |
|||
VTKTraverser(octree) >> pMesh::io::DefaultVolumeReadAdapter<>(hexahedron_mesh)(); |
|||
|
|||
pMesh::io::VTKWriter(12, out_octree_path) |
|||
<< pMesh::io::DefaultVolumeWriteAdapter<>(hexahedron_mesh)(); |
|||
|
|||
BOOST_LOG_TRIVIAL(debug) << "Total Points = " << hexahedron_mesh.c_size() * ppv; |
|||
|
|||
BOOST_LOG_TRIVIAL(debug) << "Compression ratio = " << (double) hexahedron_mesh.c_size() * ppv / opm; |
|||
|
|||
BOOST_LOG_TRIVIAL(debug) << "Calculating UDF"; |
|||
Octree::UDFTraversalBuilder udf_builder(octree, mesh, sample_step); |
|||
udf_builder.build(); |
|||
BOOST_LOG_TRIVIAL(debug) << "End computing UDF"; |
|||
|
|||
if (1) { |
|||
Eigen::MatrixXd V = Eigen::MatrixXd(mesh.v_size(), 3); |
|||
Eigen::MatrixXi F = Eigen::MatrixXi(mesh.f_size(), 3); |
|||
|
|||
for (int i = 0; i < mesh.v_size(); ++i) { |
|||
V.row(i) = mesh.vertices[i].attr.coordinate; |
|||
} |
|||
|
|||
for (int i = 0; i < mesh.f_size(); ++i) { |
|||
const auto &face = mesh.faces[i].attr.vertices; |
|||
F.row(i) << face[0].id(), face[1].id(), face[2].id(); |
|||
} |
|||
|
|||
Eigen::MatrixXd GV; |
|||
Eigen::RowVector3i res; |
|||
const int s = 100; |
|||
igl::voxel_grid(V, 0, s, 1, GV, res); |
|||
|
|||
// compute values
|
|||
std::cout << "Computing distances..." << std::endl; |
|||
Eigen::VectorXd S = Eigen::VectorXd(GV.rows()), B; |
|||
|
|||
#if 0 |
|||
pMesh::Triangle3dMesh<> error_points; |
|||
#endif |
|||
|
|||
{ |
|||
for (int i = 0; i < GV.rows(); ++i) { |
|||
auto node = octree.map_node(GV.row(i)); |
|||
if (node == nullptr) { |
|||
S[i] = 1000; |
|||
} else { |
|||
S[i] = node->get_udf(GV.row(i)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
#if 0 |
|||
pMesh::io::VTKWriter(1, out_error_path) << pMesh::io::DefaultSurfaceWriteAdapter(error_points)(); |
|||
#endif |
|||
|
|||
std::cout << "Marching cubes..." << std::endl; |
|||
Eigen::MatrixXd SV, BV; |
|||
Eigen::MatrixXi SF, BF; |
|||
|
|||
igl::marching_cubes(S, GV, res(0), res(1), res(2), 0, SV, SF); |
|||
igl::writeOBJ(out_mc_path.string(), SV, SF); |
|||
} |
|||
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::UDFOctree &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