Browse Source

add solid voxel

master
lab pc 3 years ago
parent
commit
a002f7d18b
  1. 106917
      data/stanford-bunny.obj
  2. 3
      include/Octree/voxel/SolidVoxelBuilder.h
  3. 7
      include/Octree/voxel/Voxel.h
  4. 39
      src/voxel/SolidVoxelBuilder.cpp
  5. 23
      src/voxel/Voxel.cpp
  6. 115
      tests/solid_octree_test/main.cpp

106917
data/stanford-bunny.obj

File diff suppressed because it is too large

3
include/Octree/voxel/SolidVoxelBuilder.h

@ -14,6 +14,9 @@
namespace Octree {
class SolidVoxelBuilder {
private:
const Octree::Voxel &surfVoxel;
public:
explicit SolidVoxelBuilder(const Voxel& surfVoxel);

7
include/Octree/voxel/Voxel.h

@ -35,11 +35,14 @@ public:
* @param x
* @param y
* @param z
* @param expand Consider the expand of the voxel
* @return
*/
int id_at(int x, int y, int z) const;
int id_at(int x, int y, int z, bool in_exp=false) const;
bool at(int x, int y, int z) const;
bool at(int x, int y, int z, bool in_exp=false) const;
bool is_in_bound(int x, int y, int z, bool in_exp=false) const;
};
}

39
src/voxel/SolidVoxelBuilder.cpp

@ -8,10 +8,47 @@
**/
#include "Octree/voxel/SolidVoxelBuilder.h"
Octree::SolidVoxelBuilder::SolidVoxelBuilder(const Octree::Voxel &voxel) {
#include <queue>
#include <boost/log/trivial.hpp>
Octree::SolidVoxelBuilder::SolidVoxelBuilder(const Octree::Voxel &surfVoxel): surfVoxel(surfVoxel) {
}
void Octree::SolidVoxelBuilder::build(Octree::Voxel &solidVoxel) {
solidVoxel = surfVoxel;
// BFS
static Eigen::Vector3i Directions[6] = {
{1,0,0}, {-1,0,0}, {0,1,0}, {0,-1,0}, {0,0,1}, {0,0,-1}
};
using coord_t = Eigen::Vector3i;
std::queue<coord_t> queue;
queue.push(coord_t(0,0,0));
while (!queue.empty()) {
// BOOST_LOG_TRIVIAL(debug) << "queue size: " << queue.size();
coord_t current_coord = queue.front();
queue.pop();
int current_idx = solidVoxel.id_at(current_coord.x(), current_coord.y(), current_coord.z(), true);
// BOOST_LOG_TRIVIAL(debug) << "current_coord: " << current_coord.transpose() << " id: " << current_idx;
if(solidVoxel.voxels[current_idx]) continue; // if visited
solidVoxel.voxels[current_idx] = true;
for (int i = 0; i < 6; ++i) {
coord_t neighbor_coord = current_coord + Directions[i];
if (solidVoxel.is_in_bound(neighbor_coord.x(), neighbor_coord.y(), neighbor_coord.z(), true)) {
int neighbor_idx = solidVoxel.id_at(neighbor_coord.x(), neighbor_coord.y(), neighbor_coord.z(), true);
// BOOST_LOG_TRIVIAL(debug) << "neighbor_coord: " << neighbor_coord.transpose();
if(solidVoxel.voxels[neighbor_idx]) continue; // if visited
queue.push(neighbor_coord);
}
}
}
// negate and merge boundary
for (int i = 0; i < solidVoxel.voxels.size(); ++i) {
solidVoxel.voxels[i] = !solidVoxel.voxels[i] + surfVoxel.voxels[i];
}
}

23
src/voxel/Voxel.cpp

@ -20,16 +20,17 @@ Octree::Voxel::Voxel(int _x, int _y, int _z, int expand) :
}
int Octree::Voxel::id_at(int x, int y, int z) const {
x += expand;
y += expand;
z += expand;
int Octree::Voxel::id_at(int x, int y, int z, bool in_exp) const {
if(not in_exp){
x += expand;
y += expand;
z += expand;
}
return ((z * _y_exp) + y) * _x_exp + x;
// return ((z * _y) + y) * _x + x;
}
bool Octree::Voxel::at(int x, int y, int z) const {
return voxels[id_at(x, y, z)];
bool Octree::Voxel::at(int x, int y, int z, bool in_exp) const {
return voxels[id_at(x, y, z, in_exp)];
}
void Octree::Voxel::create_voxels(int _x, int _y, int _z, int expand) {
@ -42,3 +43,11 @@ void Octree::Voxel::create_voxels(int _x, int _y, int _z, int expand) {
this->expand = expand;
voxels = std::vector<bool>(_x_exp * _y_exp * _z_exp, false);
}
bool Octree::Voxel::is_in_bound(int x, int y, int z, bool in_exp) const {
if(in_exp){
return x >= 0 and x < _x_exp and y >= 0 and y < _y_exp and z >= 0 and z < _z_exp;
}else{
return x >= 0 and x < _x and y >= 0 and y < _y and z >= 0 and z < _z;
}
}

115
tests/solid_octree_test/main.cpp

@ -21,6 +21,7 @@
#include <pMesh/io/reader/OBJReader.h>
#include <pMesh/io/reader/VTKReader.h>
#include <pMesh/io/writer/VTKWriter.h>
#include <pMesh/io/writer/OBJWriter.h>
#include <pMesh/io/adapter/DefaultReadAdapter.h>
#include <pMesh/io/adapter/DefaultWriteAdapter.h>
#include <boost/timer.hpp>
@ -30,6 +31,7 @@
#include "test-path.h"
#include "Octree/voxel/SurfaceVoxelBuilder.h"
#include "Octree/voxel/SolidVoxelBuilder.h"
#include "Octree/voxel/Voxel.h"
class VTKTraverser : public pMesh::io::BaseReader, public Octree::OctreeTraverser {
@ -44,14 +46,15 @@ public:
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 mesh_path = data_base_path / "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_voxel_surf_path = data_base_path / "stanford-bunny-voxel-surf.obj";
auto out_voxel_line_path = data_base_path / "stanford-bunny-voxel-line.obj";
auto out_error_path = data_base_path / "stanford-bunny-error_points.vtk";
pMesh::Triangle3dMesh<> mesh;
@ -61,7 +64,7 @@ int main() {
BOOST_LOG_TRIVIAL(info) << "Load Face #" << mesh.f_size();
const int level = 4;
const double block_size = 0.005;
const double block_size = 0.03;
boost::timer t;
Octree::AABB aabb(mesh.aabb());
@ -84,14 +87,21 @@ int main() {
<< pMesh::io::DefaultVolumeWriteAdapter<>(hexahedron_mesh)();
t.restart();
Octree::Voxel voxel;
Octree::SurfaceVoxelBuilder voxel_builder(octree, mesh, block_size);
voxel_builder.build(voxel);
Octree::Voxel surfVoxel, solidVoxel;
Octree::SurfaceVoxelBuilder(octree, mesh, block_size).build(surfVoxel);
BOOST_LOG_TRIVIAL(debug) << "SurfaceVoxelBuilder time elapse " << t.elapsed();
t.restart();
Octree::SolidVoxelBuilder(surfVoxel).build(solidVoxel);
BOOST_LOG_TRIVIAL(debug) << "SolidVoxelBuilder time elapse " << t.elapsed();
// output voxel
pMesh::HexahedronMesh<> voxelMesh;
pMesh::SurfaceMesh<> faceMesh;
pMesh::SurfaceMesh<> lineMesh;
{
Octree::Voxel &voxel = solidVoxel;
auto aabb = voxel.aabb;
int _x = voxel._x;
int _y = voxel._y;
@ -104,34 +114,97 @@ int main() {
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()}));
if (voxel.voxels[voxel.id_at(i, j, k)]) {
int base_id = voxelMesh.v_size();
Octree::AABB v
({base_x, base_y, base_z}, {base_x + block_size, base_y + block_size, base_z + block_size});
std::vector<pMesh::Point3d> vertices = {
{v.min().x(), v.min().y(), v.min().z()},
{v.max().x(), v.min().y(), v.min().z()},
{v.max().x(), v.max().y(), v.min().z()},
{v.min().x(), v.max().y(), v.min().z()},
{v.min().x(), v.min().y(), v.max().z()},
{v.max().x(), v.min().y(), v.max().z()},
{v.max().x(), v.max().y(), v.max().z()},
{v.min().x(), v.max().y(), v.max().z()}
};
static std::vector<std::vector<int>> line_cell = {
{0, 1}, {1, 2}, {2, 3}, {3, 0},
{4, 5}, {5, 6}, {6, 7}, {7, 4},
{0, 4}, {1, 5}, {2, 6}, {3, 7}
};
static std::vector<std::vector<int>> faces = {
{0, 1, 2, 3}, {4, 5, 6, 7}, {0, 1, 5, 4}, {2, 3, 7, 6}, {0, 3, 7, 4}, {1, 2, 6, 5}
};
for (const auto &v : vertices) {
voxelMesh.vertices.emplace_back(pMesh::Volume::Vertex(0, v));
faceMesh.vertices.emplace_back(pMesh::Surface::Vertex(0, v));
lineMesh.vertices.emplace_back(pMesh::Surface::Vertex(0, v));
}
pMesh::Volume::Cell cell;
using PPP = pMesh::Volume::VertexHandle;
using PVP = pMesh::Volume::VertexHandle;
using PSP = pMesh::Surface::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)
PVP(base_id + 0), PVP(base_id + 1), PVP(base_id + 2), PVP(base_id + 3),
PVP(base_id + 4), PVP(base_id + 5), PVP(base_id + 6), PVP(base_id + 7)
};
voxelMesh.cells.emplace_back(cell);
for (const auto &face : faces) {
pMesh::Surface::Face f;
f.vertices = {
PSP(base_id + face[0]), PSP(base_id + face[1]), PSP(base_id + face[2]), PSP(base_id + face[3])
};
faceMesh.faces.emplace_back(f);
}
for (const auto &line : line_cell) {
pMesh::Surface::Face l;
l.vertices = {
PSP(base_id + line[0]), PSP(base_id + line[1])
};
lineMesh.faces.emplace_back(l);
}
}
}
}
}
}
pMesh::io::VTKWriter(12, out_voxel_path)
<< pMesh::io::DefaultVolumeWriteAdapter<>(voxelMesh)();
{
Eigen::MatrixXd vFaceMatrix(faceMesh.v_size(), 3);
Eigen::MatrixXi fFaceMatrix(faceMesh.f_size(), 4);
for (int i = 0; i < faceMesh.v_size(); ++i) {
vFaceMatrix.row(i) = faceMesh.vertices[i].attr.coordinate.transpose();
}
for (int i = 0; i < faceMesh.f_size(); ++i) {
auto ff = faceMesh.faces[i].attr.vertices;
fFaceMatrix.row(i) <<ff[0].id(),ff[1].id(),ff[2].id(),ff[3].id();
}
igl::writeOBJ(out_voxel_surf_path.string(), vFaceMatrix, fFaceMatrix);
}
{
Eigen::MatrixXd vFaceMatrix(lineMesh.v_size(), 3);
Eigen::MatrixXi fFaceMatrix(lineMesh.f_size(), 2);
for (int i = 0; i < lineMesh.v_size(); ++i) {
vFaceMatrix.row(i) = lineMesh.vertices[i].attr.coordinate.transpose();
}
for (int i = 0; i < lineMesh.f_size(); ++i) {
auto ff = lineMesh.faces[i].attr.vertices;
fFaceMatrix.row(i) <<ff[0].id(),ff[1].id();
}
igl::writeOBJ(out_voxel_line_path.string(), vFaceMatrix, fFaceMatrix);
std::cout << "Write lines" << std::endl;
}
return 0;
}

Loading…
Cancel
Save