add MeshReconstruction dep and some test meshes

This commit is contained in:
papush! 2021-11-25 15:00:20 +01:00
parent 068dede832
commit 1659341370
24 changed files with 172763 additions and 2 deletions

View File

@ -6,6 +6,10 @@ find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets)
add_subdirectory(external/OpenMesh) add_subdirectory(external/OpenMesh)
add_subdirectory(external/Eigen) add_subdirectory(external/Eigen)
add_subdirectory(external/MeshReconstruction)
target_include_directories(MeshReconstruction INTERFACE
external/MeshReconstruction/lib)
add_executable(${PROJECT_NAME}) add_executable(${PROJECT_NAME})
target_sources(${PROJECT_NAME} PRIVATE target_sources(${PROJECT_NAME} PRIVATE
resources.qrc resources.qrc
@ -28,11 +32,14 @@ target_sources(${PROJECT_NAME} PRIVATE
src/quad_patch.cpp src/quad_patch.cpp
src/quad_patch.h src/quad_patch.h
src/quad_patch_tesselator.cpp src/quad_patch_tesselator.cpp
src/quad_patch_tesselator.h) src/quad_patch_tesselator.h
src/hole_filling.h
src/hole_filling.cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE target_link_libraries(${PROJECT_NAME} PRIVATE
Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Core Qt5::Gui Qt5::Widgets
OpenMeshCore OpenMeshCore
eigen) eigen
MeshReconstruction)
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17) target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17)
set_target_properties(${PROJECT_NAME} PROPERTIES set_target_properties(${PROJECT_NAME} PROPERTIES
AUTOMOC ON AUTOMOC ON

68474
data/face_scaled.obj Normal file

File diff suppressed because it is too large Load Diff

103420
data/gargoyle_trou.obj Normal file

File diff suppressed because it is too large Load Diff

BIN
external/MeshReconstruction/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,3 @@
bin
html/
latex/

View File

@ -0,0 +1,16 @@
cmake_minimum_required (VERSION 3.0)
project (MeshReconstruction)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Parallel compilation.
if(WIN32)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4250")
endif()
set(CMAKE_DEBUG_POSTFIX "d")
add_subdirectory(lib)
add_subdirectory(demo)

13
external/MeshReconstruction/Readme.md vendored Normal file
View File

@ -0,0 +1,13 @@
# MeshReconstruction
This is a small library that can reconstruct a triangle mesh from a <a href="http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm">signed distance function</a> using the <a href="https://en.wikipedia.org/wiki/Marching_cubes">Marching Cubes algorithm</a> and export it to a file in the <a href="https://de.wikipedia.org/wiki/Wavefront_OBJ">obj format</a>.
The library is self-contained and has no dependencies. The library is fast due to precomputed lookup tables and a narrow-band approach which excludes a lot of marching cubes that are far away from the surface.
The library requires C++14 and has been tested under Visual Studio 2017 and Windows 10 but should port to other systems without major problems.
The library can be used under the terms of the MIT License.
<p align="center">
<img src="overview.png" width="400" alt="Overview">
</p>

View File

@ -0,0 +1,3 @@
include_directories("." ${PROJECT_SOURCE_DIR}/lib)
add_executable(Demo main.cpp)
target_link_libraries (Demo MeshReconstruction)

View File

@ -0,0 +1,22 @@
#include <MeshReconstruction.h>
#include <IO.h>
using namespace MeshReconstruction;
int main()
{
auto sphereSdf = [](Vec3 const& pos)
{
auto const Radius = 1.0;
return pos.Norm() - Radius;
};
Rect3 domain;
domain.min = { -1.1, -1.1, -1.1 };
domain.size = {2.2, 2.2, 2.2};
Vec3 cubeSize{ 0.05, 0.05, 0.05 };
auto mesh = MarchCube(sphereSdf, domain, cubeSize);
WriteObjFile(mesh, "sphere.obj");
}

View File

@ -0,0 +1,12 @@
add_library(MeshReconstruction MeshReconstruction.h MeshReconstruction.cpp Cube.h Cube.cpp DataStructs.h IO.h IO.cpp Triangulation.h Triangulation.cpp)
target_link_libraries(MeshReconstruction m)
install(TARGETS MeshReconstruction
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
install(DIRECTORY .
DESTINATION .
FILES_MATCHING PATTERN "*.h")

149
external/MeshReconstruction/lib/Cube.cpp vendored Normal file
View File

@ -0,0 +1,149 @@
#include "Cube.h"
#include <cmath>
using namespace MeshReconstruction;
namespace
{
// Cube has 8 vertices. Each vertex can have positive or negative sign.
// 2^8 = 256 possible configurations mapped to intersected edges in each case.
// The 12 edges are numbered as 1, 2, 4, ..., 2048 and are stored as a 12-bit bitstring for each configuration.
const int signConfigToIntersectedEdges[256] = {
0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c,
0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac,
0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c,
0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc,
0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c,
0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc ,
0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460,
0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0,
0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230,
0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190,
0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 };
struct Edge
{
int edgeFlag : 12; // flag: 1, 2, 4, ... 2048
int vert0; // 0-7
int vert1; // 0-7
};
const Edge edges[12] =
{
{ 1, 0, 1 }, // edge 0
{ 2, 1, 2 }, // edge 1
{ 4, 2, 3 }, // ...
{ 8, 3, 0 },
{ 16, 4, 5 },
{ 32, 5, 6 },
{ 64, 6, 7 },
{ 128, 7, 4 },
{ 256, 0, 4 },
{ 512, 1, 5 },
{ 1024, 2, 6 },
{ 2048, 3, 7 } // edge 11
};
}
Vec3 Cube::LerpVertex(double isoLevel, int i1, int i2) const
{
auto const Eps = 1e-5;
auto const v1 = sdf[i1];
auto const v2 = sdf[i2];
auto const& p1 = pos[i1];
auto const& p2 = pos[i2];
if (abs(isoLevel - v1) < Eps) return p1;
if (abs(isoLevel - v2) < Eps) return p2;
if (abs(v1 - v2) < Eps) return p1;
auto mu = (isoLevel - v1) / (v2 - v1);
return p1 + (p2 - p1)*mu;
}
Cube::Cube(Rect3 const& space, Fun3s const& sdf)
{
auto mx = space.min.x;
auto my = space.min.y;
auto mz = space.min.z;
auto sx = space.size.x;
auto sy = space.size.y;
auto sz = space.size.z;
pos[0] = space.min;
pos[1] = { mx + sx, my, mz };
pos[2] = { mx + sx, my, mz + sz };
pos[3] = { mx, my, mz + sz };
pos[4] = { mx, my + sy, mz };
pos[5] = { mx + sx, my + sy, mz };
pos[6] = { mx + sx, my + sy, mz + sz };
pos[7] = { mx, my + sy, mz + sz };
for (auto i = 0; i < 8; ++i)
{
auto sd = sdf(pos[i]);
if (sd == 0) sd += 1e-6;
this->sdf[i] = sd;
}
}
int Cube::SignConfig(double isoLevel) const
{
auto edgeIndex = 0;
for (auto i = 0; i < 8; ++i)
{
if (sdf[i] < isoLevel)
{
edgeIndex |= 1 << i;
}
}
return edgeIndex;
}
IntersectInfo Cube::Intersect(double iso) const
{
// idea:
// from signs at 8 corners of cube a sign configuration (256 possible ones) is computed
// this configuration can be used to index into a table that tells which of the 12 edges are intersected
// find vertices adjacent to edges and interpolate cut vertex and store it in IntersectionInfo object
IntersectInfo intersect;
intersect.signConfig = SignConfig(iso);
for (auto e = 0; e<12; ++e)
{
if (signConfigToIntersectedEdges[intersect.signConfig] & edges[e].edgeFlag)
{
auto v0 = edges[e].vert0;
auto v1 = edges[e].vert1;
auto vert = LerpVertex(iso, v0, v1);
intersect.edgeVertIndices[e] = vert;
}
}
return intersect;
}

30
external/MeshReconstruction/lib/Cube.h vendored Normal file
View File

@ -0,0 +1,30 @@
#pragma once
#include "DataStructs.h"
namespace MeshReconstruction
{
struct IntersectInfo
{
// 0 - 255
int signConfig;
// If it exists, vertex on edge i is stored at position i.
// For edge numbering and location see numberings.png.
std::array<Vec3, 12> edgeVertIndices;
};
class Cube
{
Vec3 pos[8];
double sdf[8];
Vec3 LerpVertex(double isoLevel, int i1, int i2) const;
int SignConfig(double isoLevel) const;
public:
Cube(Rect3 const& space, Fun3s const& sdf);
// Find the vertices where the surface intersects the cube.
IntersectInfo Intersect(double isoLevel = 0) const;
};
}

View File

@ -0,0 +1,57 @@
#pragma once
#include <vector>
#include <array>
#include <functional>
#include <cmath>
namespace MeshReconstruction
{
struct Vec3
{
double x, y, z;
Vec3 operator+(Vec3 const& o) const
{
return { x + o.x, y + o.y, z + o.z };
}
Vec3 operator-(Vec3 const& o) const
{
return { x - o.x, y - o.y, z - o.z };
}
Vec3 operator*(double c) const
{
return { c*x, c*y, c*z };
}
double Norm() const
{
return sqrt(x*x + y*y + z*z);
}
Vec3 Normalized() const
{
auto n = Norm();
return { x / n, y / n, z / n };
}
};
struct Rect3
{
Vec3 min;
Vec3 size;
};
using Triangle = std::array<int, 3>;
struct Mesh
{
std::vector<Vec3> vertices;
std::vector<Triangle> triangles;
std::vector<Vec3> vertexNormals;
};
using Fun3s = std::function<double(Vec3 const&)>;
using Fun3v = std::function<Vec3(Vec3 const&)>;
}

53
external/MeshReconstruction/lib/IO.cpp vendored Normal file
View File

@ -0,0 +1,53 @@
#include "IO.h"
#include <stdexcept>
using namespace std;
void MeshReconstruction::WriteObjFile(Mesh const& mesh, string const& fileName)
{
// FILE faster than streams.
FILE* file;
//auto status = fopen_s(&file, fileName.c_str(), "w");
//if (status != 0)
//{
// throw runtime_error("Could not write obj file.");
//}
file = fopen(fileName.c_str(), "w");
if (file == NULL)
{
throw runtime_error("Could not write obj file.");
}
// write stats
fprintf(file, "# %d vertices, %d triangles\n\n",
static_cast<int>(mesh.vertices.size()),
static_cast<int>(mesh.triangles.size()));
// vertices
for (auto vi = 0; vi < mesh.vertices.size(); ++vi)
{
auto const& v = mesh.vertices.at(vi);
fprintf(file, "v %f %f %f\n", v.x, v.y, v.z);
}
// vertex normals
fprintf(file, "\n");
for (auto ni = 0; ni < mesh.vertices.size(); ++ni)
{
auto const& vn = mesh.vertexNormals.at(ni);
fprintf(file, "vn %f %f %f\n", vn.x, vn.y, vn.z);
}
// triangles (1-based)
fprintf(file, "\n");
for (auto ti = 0; ti < mesh.triangles.size(); ++ti)
{
auto const& t = mesh.triangles.at(ti);
fprintf(file, "f %d//%d %d//%d %d//%d\n",
t[0] + 1, t[0] + 1,
t[1] + 1, t[1] + 1,
t[2] + 1, t[2] + 1);
}
fclose(file);
}

9
external/MeshReconstruction/lib/IO.h vendored Normal file
View File

@ -0,0 +1,9 @@
#pragma once
#include <string>
#include "DataStructs.h"
namespace MeshReconstruction
{
/// Writes a mesh to a file in <a href="https://de.wikipedia.org/wiki/Wavefront_OBJ">obj format</a>.
void WriteObjFile(Mesh const& mesh, std::string const& file);
}

View File

@ -0,0 +1,78 @@
#include "MeshReconstruction.h"
#include "Cube.h"
#include "Triangulation.h"
using namespace MeshReconstruction;
using namespace std;
// Adapted from here: http://paulbourke.net/geometry/polygonise/
namespace
{
Vec3 NumGrad(Fun3s const& f, Vec3 const& p)
{
auto const Eps = 1e-6;
Vec3 epsX{ Eps, 0, 0 }, epsY{ 0, Eps, 0 }, epsZ{ 0, 0, Eps };
auto gx = (f(p + epsX) - f(p - epsX)) / 2;
auto gy = (f(p + epsY) - f(p - epsY)) / 2;
auto gz = (f(p + epsZ) - f(p - epsZ)) / 2;
return { gx, gy, gz };
}
}
Mesh MeshReconstruction::MarchCube(Fun3s const& sdf, Rect3 const& domain)
{
auto const NumCubes = 50;
auto cubeSize = domain.size * (1.0 / NumCubes);
return MarchCube(sdf, domain, cubeSize);
}
Mesh MeshReconstruction::MarchCube(
Fun3s const& sdf,
Rect3 const& domain,
Vec3 const& cubeSize,
double isoLevel,
Fun3v sdfGrad)
{
// Default value.
sdfGrad = sdfGrad == nullptr
? [&sdf](Vec3 const& p) { return NumGrad(sdf, p); }
: sdfGrad;
auto const NumX = static_cast<int>(ceil(domain.size.x / cubeSize.x));
auto const NumY = static_cast<int>(ceil(domain.size.y / cubeSize.y));
auto const NumZ = static_cast<int>(ceil(domain.size.z / cubeSize.z));
auto const HalfCubeDiag = cubeSize.Norm() / 2.0;
auto const HalfCubeSize = cubeSize * 0.5;
Mesh mesh;
for (auto ix = 0; ix < NumX; ++ix)
{
auto x = domain.min.x + ix * cubeSize.x;
for (auto iy = 0; iy < NumY; ++iy)
{
auto y = domain.min.y + iy * cubeSize.y;
for (auto iz = 0; iz < NumZ; ++iz)
{
auto z = domain.min.z + iz * cubeSize.z;
Vec3 min{ x, y, z };
// Process only if cube lies within narrow band around surface.
auto cubeCenter = min + HalfCubeSize;
auto dist = abs(sdf(cubeCenter) - isoLevel);
if (dist > HalfCubeDiag) continue;
Cube cube({ min, cubeSize }, sdf);
auto intersect = cube.Intersect(isoLevel);
Triangulate(intersect, sdfGrad, mesh);
}
}
}
return mesh;
}

View File

@ -0,0 +1,27 @@
#pragma once
#include "DataStructs.h"
namespace MeshReconstruction
{
/// Reconstructs a triangle mesh from a given signed distance function using <a href="https://en.wikipedia.org/wiki/Marching_cubes">Marching Cubes</a>.
/// @param sdf The <a href="http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm">Signed Distance Function</a>.
/// @param domain Domain of reconstruction.
/// @returns The reconstructed mesh.
Mesh MarchCube(
Fun3s const& sdf,
Rect3 const& domain);
/// Reconstructs a triangle mesh from a given signed distance function using <a href="https://en.wikipedia.org/wiki/Marching_cubes">Marching Cubes</a>.
/// @param sdf The <a href="http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm">Signed Distance Function</a>.
/// @param domain Domain of reconstruction.
/// @param cubeSize Size of marching cubes. Smaller cubes yields meshes of higher resolution.
/// @param isoLevel Level set of the SDF for which triangulation should be done. Changing this value moves the reconstructed surface.
/// @param sdfGrad Gradient of the SDF which yields the vertex normals of the reconstructed mesh. If none is provided a numerical approximation is used.
/// @returns The reconstructed mesh.
Mesh MarchCube(
Fun3s const& sdf,
Rect3 const& domain,
Vec3 const& cubeSize,
double isoLevel = 0,
Fun3v sdfGrad = nullptr);
}

View File

@ -0,0 +1,301 @@
#include "Triangulation.h"
namespace
{
// Indices into vertex buffer (0 - 11).
// Three successive entries make up one triangle.
// -1 means unused.
const int signConfigToTriangles[256][16] =
{ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 },
{ 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1 },
{ 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1 },
{ 3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1 },
{ 4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1 },
{ 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 },
{ 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1 },
{ 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1 },
{ 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 },
{ 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1 },
{ 10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1 },
{ 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1 },
{ 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1 },
{ 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1 },
{ 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1 },
{ 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1 },
{ 7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1 },
{ 2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1 },
{ 11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1 },
{ 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1 },
{ 11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1 },
{ 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1 },
{ 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1 },
{ 2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 },
{ 5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1 },
{ 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1 },
{ 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1 },
{ 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1 },
{ 5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 },
{ 10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1 },
{ 6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1 },
{ 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1 },
{ 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1 },
{ 3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 },
{ 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1 },
{ 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1 },
{ 9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1 },
{ 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1 },
{ 5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1 },
{ 0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1 },
{ 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1 },
{ 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1 },
{ 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1 },
{ 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1 },
{ 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1 },
{ 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1 },
{ 10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1 },
{ 3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1 },
{ 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1 },
{ 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1 },
{ 8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1 },
{ 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1 },
{ 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1 },
{ 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1 },
{ 10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1 },
{ 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1 },
{ 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1 },
{ 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1 },
{ 2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1 },
{ 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1 },
{ 11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1 },
{ 8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1 },
{ 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1 },
{ 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 },
{ 10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 },
{ 2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 },
{ 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1 },
{ 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1 },
{ 2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1 },
{ 10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1 },
{ 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1 },
{ 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1 },
{ 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1 },
{ 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1 },
{ 8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1 },
{ 6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1 },
{ 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1 },
{ 10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1 },
{ 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1 },
{ 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1 },
{ 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1 },
{ 10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1 },
{ 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 },
{ 5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 },
{ 11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1 },
{ 9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 },
{ 6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1 },
{ 7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1 },
{ 3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1 },
{ 7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1 },
{ 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1 },
{ 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1 },
{ 9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1 },
{ 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1 },
{ 4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1 },
{ 7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1 },
{ 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1 },
{ 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1 },
{ 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1 },
{ 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1 },
{ 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1 },
{ 6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1 },
{ 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1 },
{ 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1 },
{ 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1 },
{ 10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1 },
{ 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1 },
{ 5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1 },
{ 10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1 },
{ 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1 },
{ 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1 },
{ 7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1 },
{ 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1 },
{ 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1 },
{ 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1 },
{ 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1 },
{ 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1 },
{ 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1 },
{ 0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1 },
{ 10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1 },
{ 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1 },
{ 0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1 },
{ 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1 },
{ 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1 },
{ 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1 },
{ 5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1 },
{ 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1 },
{ 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1 },
{ 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1 },
{ 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1 },
{ 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1 },
{ 9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1 },
{ 11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1 },
{ 11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1 },
{ 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1 },
{ 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1 },
{ 3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1 },
{ 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1 },
{ 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1 },
{ 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1 },
{ 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } };
}
/// Given a grid cube and an isolevel the triangles (5 max)
/// required to represent the isosurface in the cube are computed.
void MeshReconstruction::Triangulate(
IntersectInfo const& intersect,
Fun3v const& grad,
Mesh& mesh)
{
// Cube is entirely in/out of the surface. Generate no triangles.
if (intersect.signConfig == 0 || intersect.signConfig == 255) return;
auto const& tri = signConfigToTriangles[intersect.signConfig];
for (auto i = 0; tri[i] != -1; i += 3)
{
auto const& v0 = intersect.edgeVertIndices[tri[i]];
auto const& v1 = intersect.edgeVertIndices[tri[i + 1]];
auto const& v2 = intersect.edgeVertIndices[tri[i + 2]];
mesh.vertices.push_back(v0);
mesh.vertices.push_back(v1);
mesh.vertices.push_back(v2);
auto normal0 = grad(v0).Normalized();
auto normal1 = grad(v1).Normalized();
auto normal2 = grad(v2).Normalized();
mesh.vertexNormals.push_back(normal0);
mesh.vertexNormals.push_back(normal1);
mesh.vertexNormals.push_back(normal2);
auto last = static_cast<int>(mesh.vertices.size() - 1);
mesh.triangles.push_back({ last - 2, last - 1, last });
}
}

View File

@ -0,0 +1,11 @@
#pragma once
#include "Cube.h"
#include "DataStructs.h"
namespace MeshReconstruction
{
void Triangulate(
IntersectInfo const& intersect,
Fun3v const& grad,
Mesh& mesh);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
external/MeshReconstruction/overview.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

View File

@ -0,0 +1,5 @@
Notes du TP de réparation de maillage par surface implicite de Mme Bac
Fonction implicite f(x) = Σ(1,n)[αi φ(||X-Xi||) + …]
φ(r) = r²ln(r) : fonction radiale, une par point, =0 au point

58
src/hole_filling.cpp Normal file
View File

@ -0,0 +1,58 @@
#include "hole_filling.h"
#include "util.h"
#include <MeshReconstruction.h>
static std::vector<std::vector<HalfedgeHandle>> findHoles(MyMesh &mesh) {
std::vector<std::vector<HalfedgeHandle>> holes;
std::set<HalfedgeHandle> ignore;
for (HalfedgeHandle it : mesh.halfedges()) {
if (mesh.is_boundary(it)
&& ignore.find(it) == ignore.end()) {
holes.emplace_back();
holes.back().push_back(it);
ignore.insert(it);
for (HalfedgeHandle it2 : HalfedgeLoopRange<MyMesh>(mesh, it)) {
holes.back().push_back(it2);
ignore.insert(it2);
}
}
}
return holes;
}
void fillHoleDumb(MyMesh &mesh, std::vector<HalfedgeHandle> &hole) {
mesh.request_vertex_status();
mesh.request_edge_status();
mesh.request_face_status();
Point center(0, 0, 0);
size_t length = 0;
for (HalfedgeHandle it : hole) {
VertexHandle vert = mesh.to_vertex_handle(it);
center += mesh.point(vert);
length++;
}
center /= length;
VertexHandle center_handle = mesh.new_vertex_dirty(center);
mesh.set_color(center_handle, mesh.default_color);
for (HalfedgeHandle it : hole) {
mesh.add_face(mesh.from_vertex_handle(it),
mesh.to_vertex_handle(it),
center_handle);
}
}
void fillHolesDumb(MyMesh &mesh) {
mesh.holes = findHoles(mesh);
for (auto hole : mesh.holes) {
fillHoleDumb(mesh, hole);
}
}
void fillHolesImplicit(MyMesh &mesh) {
}

13
src/hole_filling.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef HOLE_FILLING_H
#define HOLE_FILLING_H
#include "my_mesh.h"
#include <vector>
void fillHoleDumb(MyMesh &mesh, std::vector<HalfedgeHandle> &hole);
void fillHolesDumb(MyMesh &mesh);
void fillHolesImplicit(MyMesh &mesh);
#endif