ClangFormat: apply to source, most of intern

Apply clang format as proposed in T53211.

For details on usage and instructions for migrating branches
without conflicts, see:

https://wiki.blender.org/wiki/Tools/ClangFormat
This commit is contained in:
Campbell Barton
2019-04-17 06:17:24 +02:00
parent b3dabc200a
commit e12c08e8d1
4481 changed files with 1230080 additions and 1155401 deletions

View File

@@ -17,32 +17,32 @@
# ***** END GPL LICENSE BLOCK *****
set(INC
.
intern
.
intern
)
set(INC_SYS
${EIGEN3_INCLUDE_DIRS}
${EIGEN3_INCLUDE_DIRS}
)
set(SRC
intern/manifold_table.cpp
intern/marching_cubes_table.cpp
intern/octree.cpp
intern/Projections.cpp
intern/manifold_table.cpp
intern/marching_cubes_table.cpp
intern/octree.cpp
intern/Projections.cpp
intern/cubes.h
intern/GeoCommon.h
intern/manifold_table.h
intern/marching_cubes_table.h
intern/MemoryAllocator.h
intern/ModelReader.h
intern/octree.h
intern/Projections.h
intern/Queue.h
intern/cubes.h
intern/GeoCommon.h
intern/manifold_table.h
intern/marching_cubes_table.h
intern/MemoryAllocator.h
intern/ModelReader.h
intern/octree.h
intern/Projections.h
intern/Queue.h
intern/dualcon_c_api.cpp
dualcon.h
intern/dualcon_c_api.cpp
dualcon.h
)
set(LIB

View File

@@ -29,22 +29,22 @@ typedef float (*DualConCo)[3];
typedef unsigned int (*DualConTri)[3];
typedef unsigned int (*DualConLoop);
typedef unsigned int(*DualConLoop);
typedef struct DualConInput {
DualConLoop mloop;
DualConLoop mloop;
DualConCo co;
int co_stride;
int totco;
DualConCo co;
int co_stride;
int totco;
DualConTri looptri;
int tri_stride;
int tottri;
DualConTri looptri;
int tri_stride;
int tottri;
int loop_stride;
int loop_stride;
float min[3], max[3];
float min[3], max[3];
} DualConInput;
/* callback for allocating memory for output */
@@ -55,16 +55,16 @@ typedef void (*DualConAddVert)(void *output, const float co[3]);
typedef void (*DualConAddQuad)(void *output, const int vert_indices[4]);
typedef enum {
DUALCON_FLOOD_FILL = 1,
DUALCON_FLOOD_FILL = 1,
} DualConFlags;
typedef enum {
/* blocky */
DUALCON_CENTROID,
/* smooth */
DUALCON_MASS_POINT,
/* keeps sharp edges */
DUALCON_SHARP_FEATURES,
/* blocky */
DUALCON_CENTROID,
/* smooth */
DUALCON_MASS_POINT,
/* keeps sharp edges */
DUALCON_SHARP_FEATURES,
} DualConMode;
/* Usage:

View File

@@ -28,31 +28,29 @@
* @author Tao Ju
*/
// 3d point with integer coordinates
typedef struct {
int x, y, z;
int x, y, z;
} Point3i;
typedef struct {
Point3i begin;
Point3i end;
Point3i begin;
Point3i end;
} BoundingBox;
// triangle that points to three vertices
typedef struct {
float vt[3][3];
float vt[3][3];
} Triangle;
// 3d point with float coordinates
typedef struct {
float x, y, z;
float x, y, z;
} Point3f;
typedef struct {
Point3f begin;
Point3f end;
Point3f begin;
Point3f end;
} BoundingBoxf;
#endif /* __GEOCOMMON_H__ */
#endif /* __GEOCOMMON_H__ */

View File

@@ -29,29 +29,27 @@
* @author Tao Ju
*/
/**
* Base class of memory allocators
*/
class VirtualMemoryAllocator
{
public:
virtual ~VirtualMemoryAllocator() {}
class VirtualMemoryAllocator {
public:
virtual ~VirtualMemoryAllocator()
{
}
virtual void *allocate( ) = 0;
virtual void deallocate(void *obj) = 0;
virtual void destroy( ) = 0;
virtual void printInfo( ) = 0;
virtual void *allocate() = 0;
virtual void deallocate(void *obj) = 0;
virtual void destroy() = 0;
virtual void printInfo() = 0;
virtual int getAllocated( ) = 0;
virtual int getAll( ) = 0;
virtual int getBytes( ) = 0;
virtual int getAllocated() = 0;
virtual int getAll() = 0;
virtual int getBytes() = 0;
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("DUALCON:VirtualMemoryAllocator")
MEM_CXX_CLASS_ALLOC_FUNCS("DUALCON:VirtualMemoryAllocator")
#endif
};
/**
@@ -59,167 +57,160 @@ virtual int getBytes( ) = 0;
*
* Note: there are 4 bytes overhead for each allocated yet unused object.
*/
template < int N >
class MemoryAllocator : public VirtualMemoryAllocator
{
private:
template<int N> class MemoryAllocator : public VirtualMemoryAllocator {
private:
/// Constants
int HEAP_UNIT, HEAP_MASK;
/// Constants
int HEAP_UNIT, HEAP_MASK;
/// Data array
UCHAR **data;
/// Data array
UCHAR **data;
/// Allocation stack
UCHAR ***stack;
/// Allocation stack
UCHAR ***stack;
/// Number of data blocks
int datablocknum;
/// Number of data blocks
int datablocknum;
/// Number of stack blocks
int stackblocknum;
/// Number of stack blocks
int stackblocknum;
/// Size of stack
int stacksize;
/// Size of stack
int stacksize;
/// Number of available objects on stack
int available;
/// Number of available objects on stack
int available;
/**
/**
* Allocate a memory block
*/
void allocateDataBlock( )
{
// Allocate a data block
datablocknum += 1;
data = ( UCHAR ** )realloc(data, sizeof (UCHAR *) * datablocknum);
data[datablocknum - 1] = ( UCHAR * )malloc(HEAP_UNIT * N);
void allocateDataBlock()
{
// Allocate a data block
datablocknum += 1;
data = (UCHAR **)realloc(data, sizeof(UCHAR *) * datablocknum);
data[datablocknum - 1] = (UCHAR *)malloc(HEAP_UNIT * N);
// Update allocation stack
for (int i = 0; i < HEAP_UNIT; i++)
{
stack[0][i] = (data[datablocknum - 1] + i * N);
}
available = HEAP_UNIT;
}
// Update allocation stack
for (int i = 0; i < HEAP_UNIT; i++) {
stack[0][i] = (data[datablocknum - 1] + i * N);
}
available = HEAP_UNIT;
}
/**
/**
* Allocate a stack block, to store more deallocated objects
*/
void allocateStackBlock( )
{
// Allocate a stack block
stackblocknum += 1;
stacksize += HEAP_UNIT;
stack = ( UCHAR *** )realloc(stack, sizeof (UCHAR * *) * stackblocknum);
stack[stackblocknum - 1] = ( UCHAR ** )malloc(HEAP_UNIT * sizeof (UCHAR *) );
}
void allocateStackBlock()
{
// Allocate a stack block
stackblocknum += 1;
stacksize += HEAP_UNIT;
stack = (UCHAR ***)realloc(stack, sizeof(UCHAR **) * stackblocknum);
stack[stackblocknum - 1] = (UCHAR **)malloc(HEAP_UNIT * sizeof(UCHAR *));
}
public:
/**
public:
/**
* Constructor
*/
MemoryAllocator( )
{
HEAP_UNIT = 1 << HEAP_BASE;
HEAP_MASK = (1 << HEAP_BASE) - 1;
MemoryAllocator()
{
HEAP_UNIT = 1 << HEAP_BASE;
HEAP_MASK = (1 << HEAP_BASE) - 1;
data = ( UCHAR ** )malloc(sizeof(UCHAR *) );
data[0] = ( UCHAR * )malloc(HEAP_UNIT * N);
datablocknum = 1;
data = (UCHAR **)malloc(sizeof(UCHAR *));
data[0] = (UCHAR *)malloc(HEAP_UNIT * N);
datablocknum = 1;
stack = ( UCHAR *** )malloc(sizeof (UCHAR * *) );
stack[0] = ( UCHAR ** )malloc(HEAP_UNIT * sizeof (UCHAR *) );
stackblocknum = 1;
stacksize = HEAP_UNIT;
available = HEAP_UNIT;
stack = (UCHAR ***)malloc(sizeof(UCHAR **));
stack[0] = (UCHAR **)malloc(HEAP_UNIT * sizeof(UCHAR *));
stackblocknum = 1;
stacksize = HEAP_UNIT;
available = HEAP_UNIT;
for (int i = 0; i < HEAP_UNIT; i++)
{
stack[0][i] = (data[0] + i * N);
}
}
for (int i = 0; i < HEAP_UNIT; i++) {
stack[0][i] = (data[0] + i * N);
}
}
/**
/**
* Destructor
*/
void destroy( )
{
int i;
for (i = 0; i < datablocknum; i++)
{
free(data[i]);
}
for (i = 0; i < stackblocknum; i++)
{
free(stack[i]);
}
free(data);
free(stack);
}
void destroy()
{
int i;
for (i = 0; i < datablocknum; i++) {
free(data[i]);
}
for (i = 0; i < stackblocknum; i++) {
free(stack[i]);
}
free(data);
free(stack);
}
/**
/**
* Allocation method
*/
void *allocate( )
{
if (available == 0)
{
allocateDataBlock( );
}
void *allocate()
{
if (available == 0) {
allocateDataBlock();
}
// printf("Allocating %d\n", header[ allocated ]) ;
available--;
return (void *)stack[available >> HEAP_BASE][available & HEAP_MASK];
}
// printf("Allocating %d\n", header[ allocated ]) ;
available--;
return (void *)stack[available >> HEAP_BASE][available & HEAP_MASK];
}
/**
/**
* De-allocation method
*/
void deallocate(void *obj)
{
if (available == stacksize)
{
allocateStackBlock( );
}
void deallocate(void *obj)
{
if (available == stacksize) {
allocateStackBlock();
}
// printf("De-allocating %d\n", ( obj - data ) / N ) ;
stack[available >> HEAP_BASE][available & HEAP_MASK] = (UCHAR *)obj;
available++;
// printf("%d %d\n", allocated, header[ allocated ]) ;
}
// printf("De-allocating %d\n", ( obj - data ) / N ) ;
stack[available >> HEAP_BASE][available & HEAP_MASK] = (UCHAR *)obj;
available++;
// printf("%d %d\n", allocated, header[ allocated ]) ;
}
/**
/**
* Print information
*/
void printInfo( )
{
printf("Bytes: %d Used: %d Allocated: %d Maxfree: %d\n", getBytes(), getAllocated(), getAll(), stacksize);
}
void printInfo()
{
printf("Bytes: %d Used: %d Allocated: %d Maxfree: %d\n",
getBytes(),
getAllocated(),
getAll(),
stacksize);
}
/**
/**
* Query methods
*/
int getAllocated( )
{
return HEAP_UNIT * datablocknum - available;
};
int getAllocated()
{
return HEAP_UNIT * datablocknum - available;
};
int getAll( )
{
return HEAP_UNIT * datablocknum;
};
int getAll()
{
return HEAP_UNIT * datablocknum;
};
int getBytes( )
{
return N;
};
int getBytes()
{
return N;
};
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("DUALCON:MemoryAllocator")
MEM_CXX_CLASS_ALLOC_FUNCS("DUALCON:MemoryAllocator")
#endif
};
#endif /* __MEMORYALLOCATOR_H__ */
#endif /* __MEMORYALLOCATOR_H__ */

View File

@@ -24,40 +24,37 @@
*
* @author Tao Ju
*/
class ModelReader
{
public:
/// Constructor
ModelReader(){
};
class ModelReader {
public:
/// Constructor
ModelReader(){};
/// Get next triangle
virtual Triangle *getNextTriangle( ) = 0;
virtual int getNextTriangle(int t[3]) = 0;
/// Get next triangle
virtual Triangle *getNextTriangle() = 0;
virtual int getNextTriangle(int t[3]) = 0;
/// Get bounding box
virtual float getBoundingBox(float origin[3]) = 0;
/// Get bounding box
virtual float getBoundingBox(float origin[3]) = 0;
/// Get number of triangles
virtual int getNumTriangles( ) = 0;
/// Get number of triangles
virtual int getNumTriangles() = 0;
/// Get storage size
virtual int getMemory( ) = 0;
/// Get storage size
virtual int getMemory() = 0;
/// Reset file reading location
virtual void reset( ) = 0;
/// Reset file reading location
virtual void reset() = 0;
/// For explicit vertex models
virtual int getNumVertices( ) = 0;
/// For explicit vertex models
virtual int getNumVertices() = 0;
virtual void getNextVertex(float v[3]) = 0;
virtual void getNextVertex(float v[3]) = 0;
virtual void printInfo( ) = 0;
virtual void printInfo() = 0;
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("DUALCON:ModelReader")
MEM_CXX_CLASS_ALLOC_FUNCS("DUALCON:ModelReader")
#endif
};
#endif /* __MODELREADER_H__ */
#endif /* __MODELREADER_H__ */

View File

@@ -22,52 +22,45 @@
#include "Projections.h"
const int vertmap[8][3] = {
{0, 0, 0},
{0, 0, 1},
{0, 1, 0},
{0, 1, 1},
{1, 0, 0},
{1, 0, 1},
{1, 1, 0},
{1, 1, 1},
{0, 0, 0},
{0, 0, 1},
{0, 1, 0},
{0, 1, 1},
{1, 0, 0},
{1, 0, 1},
{1, 1, 0},
{1, 1, 1},
};
const int centmap[3][3][3][2] = {
{{{0, 0}, {0, 1}, {1, 1}},
{{0, 2}, {0, 3}, {1, 3}},
{{2, 2}, {2, 3}, {3, 3}}},
{{{0, 0}, {0, 1}, {1, 1}}, {{0, 2}, {0, 3}, {1, 3}}, {{2, 2}, {2, 3}, {3, 3}}},
{{{0, 4}, {0, 5}, {1, 5}},
{{0, 6}, {0, 7}, {1, 7}},
{{2, 6}, {2, 7}, {3, 7}}},
{{{0, 4}, {0, 5}, {1, 5}}, {{0, 6}, {0, 7}, {1, 7}}, {{2, 6}, {2, 7}, {3, 7}}},
{{{4, 4}, {4, 5}, {5, 5}},
{{4, 6}, {4, 7}, {5, 7}},
{{6, 6}, {6, 7}, {7, 7}}}
};
{{{4, 4}, {4, 5}, {5, 5}}, {{4, 6}, {4, 7}, {5, 7}}, {{6, 6}, {6, 7}, {7, 7}}}};
const int edgemap[12][2] = {
{0, 4},
{1, 5},
{2, 6},
{3, 7},
{0, 2},
{1, 3},
{4, 6},
{5, 7},
{0, 1},
{2, 3},
{4, 5},
{6, 7},
{0, 4},
{1, 5},
{2, 6},
{3, 7},
{0, 2},
{1, 3},
{4, 6},
{5, 7},
{0, 1},
{2, 3},
{4, 5},
{6, 7},
};
const int facemap[6][4] = {
{0, 1, 2, 3},
{4, 5, 6, 7},
{0, 1, 4, 5},
{2, 3, 6, 7},
{0, 2, 4, 6},
{1, 3, 5, 7},
{0, 1, 2, 3},
{4, 5, 6, 7},
{0, 1, 4, 5},
{2, 3, 6, 7},
{0, 2, 4, 6},
{1, 3, 5, 7},
};
/**
@@ -75,16 +68,16 @@ const int facemap[6][4] = {
*/
static void crossProduct(int64_t res[3], const int64_t a[3], const int64_t b[3])
{
res[0] = a[1] * b[2] - a[2] * b[1];
res[1] = a[2] * b[0] - a[0] * b[2];
res[2] = a[0] * b[1] - a[1] * b[0];
res[0] = a[1] * b[2] - a[2] * b[1];
res[1] = a[2] * b[0] - a[0] * b[2];
res[2] = a[0] * b[1] - a[1] * b[0];
}
static void crossProduct(double res[3], const double a[3], const double b[3])
{
res[0] = a[1] * b[2] - a[2] * b[1];
res[1] = a[2] * b[0] - a[0] * b[2];
res[2] = a[0] * b[1] - a[1] * b[0];
res[0] = a[1] * b[2] - a[2] * b[1];
res[1] = a[2] * b[0] - a[0] * b[2];
res[2] = a[0] * b[1] - a[1] * b[0];
}
/**
@@ -92,18 +85,18 @@ static void crossProduct(double res[3], const double a[3], const double b[3])
*/
static int64_t dotProduct(const int64_t a[3], const int64_t b[3])
{
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
static void normalize(double a[3])
{
double mag = a[0] * a[0] + a[1] * a[1] + a[2] * a[2];
if (mag > 0) {
mag = sqrt(mag);
a[0] /= mag;
a[1] /= mag;
a[2] /= mag;
}
double mag = a[0] * a[0] + a[1] * a[1] + a[2] * a[2];
if (mag > 0) {
mag = sqrt(mag);
a[0] /= mag;
a[1] /= mag;
a[2] /= mag;
}
}
/* Create projection axes for cube+triangle intersection testing.
@@ -118,114 +111,115 @@ static void normalize(double a[3])
*/
static void create_projection_axes(int64_t axes[NUM_AXES][3], const int64_t tri[3][3])
{
/* Cube face normals */
axes[0][0] = 1;
axes[0][1] = 0;
axes[0][2] = 0;
axes[1][0] = 0;
axes[1][1] = 1;
axes[1][2] = 0;
axes[2][0] = 0;
axes[2][1] = 0;
axes[2][2] = 1;
/* Cube face normals */
axes[0][0] = 1;
axes[0][1] = 0;
axes[0][2] = 0;
axes[1][0] = 0;
axes[1][1] = 1;
axes[1][2] = 0;
axes[2][0] = 0;
axes[2][1] = 0;
axes[2][2] = 1;
/* Get triangle edge vectors */
int64_t tri_edges[3][3];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++)
tri_edges[i][j] = tri[(i + 1) % 3][j] - tri[i][j];
}
/* Get triangle edge vectors */
int64_t tri_edges[3][3];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++)
tri_edges[i][j] = tri[(i + 1) % 3][j] - tri[i][j];
}
/* Triangle normal */
crossProduct(axes[3], tri_edges[0], tri_edges[1]);
/* Triangle normal */
crossProduct(axes[3], tri_edges[0], tri_edges[1]);
// Face edges and triangle edges
int ct = 4;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
crossProduct(axes[ct], axes[j], tri_edges[i]);
ct++;
}
}
// Face edges and triangle edges
int ct = 4;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
crossProduct(axes[ct], axes[j], tri_edges[i]);
ct++;
}
}
}
/**
* Construction from a cube (axes aligned) and triangle
*/
CubeTriangleIsect::CubeTriangleIsect(int64_t cube[2][3], int64_t tri[3][3], int64_t /*error*/, int triind)
CubeTriangleIsect::CubeTriangleIsect(int64_t cube[2][3],
int64_t tri[3][3],
int64_t /*error*/,
int triind)
{
int i;
inherit = new TriangleProjection;
inherit->index = triind;
int i;
inherit = new TriangleProjection;
inherit->index = triind;
int64_t axes[NUM_AXES][3];
create_projection_axes(axes, tri);
int64_t axes[NUM_AXES][3];
create_projection_axes(axes, tri);
/* Normalize face normal and store */
double dedge1[] = {(double)tri[1][0] - (double)tri[0][0],
(double)tri[1][1] - (double)tri[0][1],
(double)tri[1][2] - (double)tri[0][2]};
double dedge2[] = {(double)tri[2][0] - (double)tri[1][0],
(double)tri[2][1] - (double)tri[1][1],
(double)tri[2][2] - (double)tri[1][2]};
crossProduct(inherit->norm, dedge1, dedge2);
normalize(inherit->norm);
/* Normalize face normal and store */
double dedge1[] = {(double)tri[1][0] - (double)tri[0][0],
(double)tri[1][1] - (double)tri[0][1],
(double)tri[1][2] - (double)tri[0][2]};
double dedge2[] = {(double)tri[2][0] - (double)tri[1][0],
(double)tri[2][1] - (double)tri[1][1],
(double)tri[2][2] - (double)tri[1][2]};
crossProduct(inherit->norm, dedge1, dedge2);
normalize(inherit->norm);
int64_t cubeedge[3][3];
for (i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
cubeedge[i][j] = 0;
}
cubeedge[i][i] = cube[1][i] - cube[0][i];
}
int64_t cubeedge[3][3];
for (i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
cubeedge[i][j] = 0;
}
cubeedge[i][i] = cube[1][i] - cube[0][i];
}
/* Project the cube on to each axis */
for (int axis = 0; axis < NUM_AXES; axis++) {
CubeProjection &cube_proj = cubeProj[axis];
/* Project the cube on to each axis */
for (int axis = 0; axis < NUM_AXES; axis++) {
CubeProjection &cube_proj = cubeProj[axis];
/* Origin */
cube_proj.origin = dotProduct(axes[axis], cube[0]);
/* Origin */
cube_proj.origin = dotProduct(axes[axis], cube[0]);
/* 3 direction vectors */
for (i = 0; i < 3; i++)
cube_proj.edges[i] = dotProduct(axes[axis], cubeedge[i]);
/* 3 direction vectors */
for (i = 0; i < 3; i++)
cube_proj.edges[i] = dotProduct(axes[axis], cubeedge[i]);
/* Offsets of 2 ends of cube projection */
int64_t max = 0;
int64_t min = 0;
for (i = 1; i < 8; i++) {
int64_t proj = (vertmap[i][0] * cube_proj.edges[0] +
vertmap[i][1] * cube_proj.edges[1] +
vertmap[i][2] * cube_proj.edges[2]);
if (proj > max) {
max = proj;
}
if (proj < min) {
min = proj;
}
}
cube_proj.min = min;
cube_proj.max = max;
/* Offsets of 2 ends of cube projection */
int64_t max = 0;
int64_t min = 0;
for (i = 1; i < 8; i++) {
int64_t proj = (vertmap[i][0] * cube_proj.edges[0] + vertmap[i][1] * cube_proj.edges[1] +
vertmap[i][2] * cube_proj.edges[2]);
if (proj > max) {
max = proj;
}
if (proj < min) {
min = proj;
}
}
cube_proj.min = min;
cube_proj.max = max;
}
}
/* Project the triangle on to each axis */
for (int axis = 0; axis < NUM_AXES; axis++) {
const int64_t vts[3] = {dotProduct(axes[axis], tri[0]),
dotProduct(axes[axis], tri[1]),
dotProduct(axes[axis], tri[2])};
/* Project the triangle on to each axis */
for (int axis = 0; axis < NUM_AXES; axis++) {
const int64_t vts[3] = {dotProduct(axes[axis], tri[0]),
dotProduct(axes[axis], tri[1]),
dotProduct(axes[axis], tri[2])};
// Triangle
inherit->tri_proj[axis][0] = vts[0];
inherit->tri_proj[axis][1] = vts[0];
for (i = 1; i < 3; i++) {
if (vts[i] < inherit->tri_proj[axis][0])
inherit->tri_proj[axis][0] = vts[i];
// Triangle
inherit->tri_proj[axis][0] = vts[0];
inherit->tri_proj[axis][1] = vts[0];
for (i = 1; i < 3; i++) {
if (vts[i] < inherit->tri_proj[axis][0])
inherit->tri_proj[axis][0] = vts[i];
if (vts[i] > inherit->tri_proj[axis][1])
inherit->tri_proj[axis][1] = vts[i];
}
}
if (vts[i] > inherit->tri_proj[axis][1])
inherit->tri_proj[axis][1] = vts[i];
}
}
}
/**
@@ -234,67 +228,64 @@ CubeTriangleIsect::CubeTriangleIsect(int64_t cube[2][3], int64_t tri[3][3], int6
*/
CubeTriangleIsect::CubeTriangleIsect(CubeTriangleIsect *parent)
{
// Copy inheritable projections
this->inherit = parent->inherit;
// Copy inheritable projections
this->inherit = parent->inherit;
// Shrink cube projections
for (int i = 0; i < NUM_AXES; i++) {
cubeProj[i].origin = parent->cubeProj[i].origin;
// Shrink cube projections
for (int i = 0; i < NUM_AXES; i++) {
cubeProj[i].origin = parent->cubeProj[i].origin;
for (int j = 0; j < 3; j++)
cubeProj[i].edges[j] = parent->cubeProj[i].edges[j] >> 1;
for (int j = 0; j < 3; j++)
cubeProj[i].edges[j] = parent->cubeProj[i].edges[j] >> 1;
cubeProj[i].min = parent->cubeProj[i].min >> 1;
cubeProj[i].max = parent->cubeProj[i].max >> 1;
}
cubeProj[i].min = parent->cubeProj[i].min >> 1;
cubeProj[i].max = parent->cubeProj[i].max >> 1;
}
}
unsigned char CubeTriangleIsect::getBoxMask( )
unsigned char CubeTriangleIsect::getBoxMask()
{
int i, j, k;
int bmask[3][2] = {{0, 0}, {0, 0}, {0, 0}};
unsigned char boxmask = 0;
int64_t child_len = cubeProj[0].edges[0] >> 1;
int i, j, k;
int bmask[3][2] = {{0, 0}, {0, 0}, {0, 0}};
unsigned char boxmask = 0;
int64_t child_len = cubeProj[0].edges[0] >> 1;
for (i = 0; i < 3; i++) {
int64_t mid = cubeProj[i].origin + child_len;
for (i = 0; i < 3; i++) {
int64_t mid = cubeProj[i].origin + child_len;
// Check bounding box
if (mid >= inherit->tri_proj[i][0]) {
bmask[i][0] = 1;
}
if (mid < inherit->tri_proj[i][1]) {
bmask[i][1] = 1;
}
// Check bounding box
if (mid >= inherit->tri_proj[i][0]) {
bmask[i][0] = 1;
}
if (mid < inherit->tri_proj[i][1]) {
bmask[i][1] = 1;
}
}
}
// Fill in masks
int ct = 0;
for (i = 0; i < 2; i++) {
for (j = 0; j < 2; j++) {
for (k = 0; k < 2; k++) {
boxmask |= ((bmask[0][i] & bmask[1][j] & bmask[2][k]) << ct);
ct++;
}
}
}
// Fill in masks
int ct = 0;
for (i = 0; i < 2; i++) {
for (j = 0; j < 2; j++) {
for (k = 0; k < 2; k++) {
boxmask |= ( (bmask[0][i] & bmask[1][j] & bmask[2][k]) << ct);
ct++;
}
}
}
// Return bounding box masks
return boxmask;
// Return bounding box masks
return boxmask;
}
/**
* Shifting a cube to a new origin
*/
void CubeTriangleIsect::shift(int off[3])
{
for (int i = 0; i < NUM_AXES; i++) {
cubeProj[i].origin += (off[0] * cubeProj[i].edges[0] +
off[1] * cubeProj[i].edges[1] +
off[2] * cubeProj[i].edges[2]);
}
for (int i = 0; i < NUM_AXES; i++) {
cubeProj[i].origin += (off[0] * cubeProj[i].edges[0] + off[1] * cubeProj[i].edges[1] +
off[2] * cubeProj[i].edges[2]);
}
}
/**
@@ -302,75 +293,70 @@ void CubeTriangleIsect::shift(int off[3])
*/
int CubeTriangleIsect::isIntersecting() const
{
for (int i = 0; i < NUM_AXES; i++) {
/*
int64_t proj0 = cubeProj[i][0] +
vertmap[inherit->cubeEnds[i][0]][0] * cubeProj[i][1] +
vertmap[inherit->cubeEnds[i][0]][1] * cubeProj[i][2] +
vertmap[inherit->cubeEnds[i][0]][2] * cubeProj[i][3] ;
int64_t proj1 = cubeProj[i][0] +
vertmap[inherit->cubeEnds[i][1]][0] * cubeProj[i][1] +
vertmap[inherit->cubeEnds[i][1]][1] * cubeProj[i][2] +
vertmap[inherit->cubeEnds[i][1]][2] * cubeProj[i][3] ;
*/
for (int i = 0; i < NUM_AXES; i++) {
/*
int64_t proj0 = cubeProj[i][0] +
vertmap[inherit->cubeEnds[i][0]][0] * cubeProj[i][1] +
vertmap[inherit->cubeEnds[i][0]][1] * cubeProj[i][2] +
vertmap[inherit->cubeEnds[i][0]][2] * cubeProj[i][3] ;
int64_t proj1 = cubeProj[i][0] +
vertmap[inherit->cubeEnds[i][1]][0] * cubeProj[i][1] +
vertmap[inherit->cubeEnds[i][1]][1] * cubeProj[i][2] +
vertmap[inherit->cubeEnds[i][1]][2] * cubeProj[i][3] ;
*/
int64_t proj0 = cubeProj[i].origin + cubeProj[i].min;
int64_t proj1 = cubeProj[i].origin + cubeProj[i].max;
int64_t proj0 = cubeProj[i].origin + cubeProj[i].min;
int64_t proj1 = cubeProj[i].origin + cubeProj[i].max;
if (proj0 > inherit->tri_proj[i][1] ||
proj1 < inherit->tri_proj[i][0]) {
return 0;
}
}
if (proj0 > inherit->tri_proj[i][1] || proj1 < inherit->tri_proj[i][0]) {
return 0;
}
}
return 1;
return 1;
}
int CubeTriangleIsect::isIntersectingPrimary(int edgeInd) const
{
for (int i = 0; i < NUM_AXES; i++) {
for (int i = 0; i < NUM_AXES; i++) {
int64_t proj0 = cubeProj[i].origin;
int64_t proj1 = cubeProj[i].origin + cubeProj[i].edges[edgeInd];
int64_t proj0 = cubeProj[i].origin;
int64_t proj1 = cubeProj[i].origin + cubeProj[i].edges[edgeInd];
if (proj0 < proj1) {
if (proj0 > inherit->tri_proj[i][1] ||
proj1 < inherit->tri_proj[i][0]) {
return 0;
}
}
else {
if (proj1 > inherit->tri_proj[i][1] ||
proj0 < inherit->tri_proj[i][0]) {
return 0;
}
}
if (proj0 < proj1) {
if (proj0 > inherit->tri_proj[i][1] || proj1 < inherit->tri_proj[i][0]) {
return 0;
}
}
else {
if (proj1 > inherit->tri_proj[i][1] || proj0 < inherit->tri_proj[i][0]) {
return 0;
}
}
}
}
// printf( "Intersecting: %d %d\n", edgemap[edgeInd][0], edgemap[edgeInd][1] ) ;
return 1;
// printf( "Intersecting: %d %d\n", edgemap[edgeInd][0], edgemap[edgeInd][1] ) ;
return 1;
}
float CubeTriangleIsect::getIntersectionPrimary(int edgeInd) const
{
int i = 3;
int i = 3;
int64_t proj0 = cubeProj[i].origin;
int64_t proj1 = cubeProj[i].origin + cubeProj[i].edges[edgeInd];
int64_t proj2 = inherit->tri_proj[i][1];
int64_t d = proj1 - proj0;
double alpha;
int64_t proj0 = cubeProj[i].origin;
int64_t proj1 = cubeProj[i].origin + cubeProj[i].edges[edgeInd];
int64_t proj2 = inherit->tri_proj[i][1];
int64_t d = proj1 - proj0;
double alpha;
if (d == 0)
alpha = 0.5;
else {
alpha = (double)((proj2 - proj0)) / (double)d;
if (d == 0)
alpha = 0.5;
else {
alpha = (double)((proj2 - proj0)) / (double)d;
if (alpha < 0 || alpha > 1)
alpha = 0.5;
}
if (alpha < 0 || alpha > 1)
alpha = 0.5;
}
return (float)alpha;
return (float)alpha;
}

View File

@@ -24,11 +24,11 @@
#define GRID_DIMENSION 20
#if defined(_WIN32) && !(_MSC_VER >= 1900)
#define isnan(n) _isnan(n)
#define LONG __int64
#define int64_t __int64
# define isnan(n) _isnan(n)
# define LONG __int64
# define int64_t __int64
#else
#include <stdint.h>
# include <stdint.h>
#endif
/**
@@ -59,71 +59,70 @@ extern const int facemap[6][4];
* Structure for the projections inheritable from parent
*/
struct TriangleProjection {
/// Projections of triangle (min and max)
int64_t tri_proj[NUM_AXES][2];
/// Projections of triangle (min and max)
int64_t tri_proj[NUM_AXES][2];
/// Normal of the triangle
double norm[3];
/// Normal of the triangle
double norm[3];
/// Index of polygon
int index;
/// Index of polygon
int index;
};
/* This is a projection for the cube against a single projection
axis, see CubeTriangleIsect.cubeProj */
struct CubeProjection {
int64_t origin;
int64_t edges[3];
int64_t min, max;
int64_t origin;
int64_t edges[3];
int64_t min, max;
};
/**
* Class for projections of cube / triangle vertices on the separating axes
*/
class CubeTriangleIsect
{
public:
/// Inheritable portion
TriangleProjection *inherit;
class CubeTriangleIsect {
public:
/// Inheritable portion
TriangleProjection *inherit;
/// Projections of the cube vertices
CubeProjection cubeProj[NUM_AXES];
/// Projections of the cube vertices
CubeProjection cubeProj[NUM_AXES];
public:
CubeTriangleIsect() {}
public:
CubeTriangleIsect()
{
}
/**
* Construction from a cube (axes aligned) and triangle
*/
CubeTriangleIsect(int64_t cube[2][3], int64_t trig[3][3], int64_t error, int triind);
/**
* Construction from a parent CubeTriangleIsect object and the index of
* the children
*/
CubeTriangleIsect(CubeTriangleIsect *parent);
unsigned char getBoxMask( );
/**
* Construction from a cube (axes aligned) and triangle
*/
CubeTriangleIsect(int64_t cube[2][3], int64_t trig[3][3], int64_t error, int triind);
/**
* Shifting a cube to a new origin
*/
void shift(int off[3]);
/**
* Construction from a parent CubeTriangleIsect object and the index of
* the children
*/
CubeTriangleIsect(CubeTriangleIsect *parent);
/**
* Method to test intersection of the triangle and the cube
*/
int isIntersecting() const;
unsigned char getBoxMask();
int isIntersectingPrimary(int edgeInd) const;
/**
* Shifting a cube to a new origin
*/
void shift(int off[3]);
float getIntersectionPrimary(int edgeInd) const;
/**
* Method to test intersection of the triangle and the cube
*/
int isIntersecting() const;
int isIntersectingPrimary(int edgeInd) const;
float getIntersectionPrimary(int edgeInd) const;
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("DUALCON:CubeTriangleIsect")
MEM_CXX_CLASS_ALLOC_FUNCS("DUALCON:CubeTriangleIsect")
#endif
};
#endif /* __PROJECTIONS_H__ */
#endif /* __PROJECTIONS_H__ */

View File

@@ -18,85 +18,78 @@
#define __QUEUE_H__
struct gridQueueEle {
int x, y, z;
UCHAR dir;
gridQueueEle *next;
int x, y, z;
UCHAR dir;
gridQueueEle *next;
};
class GridQueue
{
gridQueueEle *head;
gridQueueEle *tail;
int numEles;
class GridQueue {
gridQueueEle *head;
gridQueueEle *tail;
int numEles;
public:
public:
GridQueue()
{
head = NULL;
tail = NULL;
numEles = 0;
}
GridQueue( )
{
head = NULL;
tail = NULL;
numEles = 0;
}
gridQueueEle *getHead()
{
return head;
}
gridQueueEle *getHead( )
{
return head;
}
int getNumElements()
{
return numEles;
}
int getNumElements( )
{
return numEles;
}
void pushQueue(int st[3], int dir)
{
gridQueueEle *ele = new gridQueueEle;
ele->x = st[0];
ele->y = st[1];
ele->z = st[2];
ele->dir = (UCHAR)dir;
ele->next = NULL;
if (head == NULL) {
head = ele;
}
else {
tail->next = ele;
}
tail = ele;
numEles++;
}
int popQueue(int st[3], int &dir)
{
if (head == NULL) {
return 0;
}
void pushQueue(int st[3], int dir)
{
gridQueueEle *ele = new gridQueueEle;
ele->x = st[0];
ele->y = st[1];
ele->z = st[2];
ele->dir = (UCHAR) dir;
ele->next = NULL;
if (head == NULL)
{
head = ele;
}
else {
tail->next = ele;
}
tail = ele;
numEles++;
}
st[0] = head->x;
st[1] = head->y;
st[2] = head->z;
dir = (int)(head->dir);
int popQueue(int st[3], int& dir)
{
if (head == NULL)
{
return 0;
}
gridQueueEle *temp = head;
head = head->next;
delete temp;
st[0] = head->x;
st[1] = head->y;
st[2] = head->z;
dir = (int) (head->dir);
if (head == NULL) {
tail = NULL;
}
numEles--;
gridQueueEle *temp = head;
head = head->next;
delete temp;
if (head == NULL)
{
tail = NULL;
}
numEles--;
return 1;
}
return 1;
}
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("DUALCON:GridQueue")
MEM_CXX_CLASS_ALLOC_FUNCS("DUALCON:GridQueue")
#endif
};
#endif /* __QUEUE_H__ */
#endif /* __QUEUE_H__ */

View File

@@ -20,26 +20,24 @@
#include "marching_cubes_table.h"
/* simple wrapper for auto-generated marching cubes data */
class Cubes
{
public:
/// Get number of triangles
int getNumTriangle(int mask)
{
return marching_cubes_numtri[mask];
}
class Cubes {
public:
/// Get number of triangles
int getNumTriangle(int mask)
{
return marching_cubes_numtri[mask];
}
/// Get a triangle
void getTriangle(int mask, int index, int indices[3])
{
for (int i = 0; i < 3; i++)
indices[i] = marching_cubes_tris[mask][index][i];
}
/// Get a triangle
void getTriangle(int mask, int index, int indices[3])
{
for (int i = 0; i < 3; i++)
indices[i] = marching_cubes_tris[mask][index][i];
}
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("DUALCON:Cubes")
MEM_CXX_CLASS_ALLOC_FUNCS("DUALCON:Cubes")
#endif
};
#endif /* __CUBES_H__ */
#endif /* __CUBES_H__ */

View File

@@ -23,141 +23,139 @@
#include <float.h>
#if defined(_WIN32)
#define isnan(n) _isnan(n)
# define isnan(n) _isnan(n)
#endif
static void veccopy(float dst[3], const float src[3])
{
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
}
#define GET_TRI(_mesh, _n) \
(*(DualConTri)(((char *)(_mesh)->looptri) + ((_n) * (_mesh)->tri_stride)))
(*(DualConTri)(((char *)(_mesh)->looptri) + ((_n) * (_mesh)->tri_stride)))
#define GET_CO(_mesh, _n) \
(*(DualConCo)(((char *)(_mesh)->co) + ((_n) * (_mesh)->co_stride)))
#define GET_CO(_mesh, _n) (*(DualConCo)(((char *)(_mesh)->co) + ((_n) * (_mesh)->co_stride)))
#define GET_LOOP(_mesh, _n) \
(*(DualConLoop)(((char *)(_mesh)->mloop) + ((_n) * (_mesh)->loop_stride)))
(*(DualConLoop)(((char *)(_mesh)->mloop) + ((_n) * (_mesh)->loop_stride)))
class DualConInputReader : public ModelReader
{
private:
const DualConInput *input_mesh;
int tottri, curtri;
float min[3], max[3], maxsize;
float scale;
public:
DualConInputReader(const DualConInput *mesh, float _scale)
: input_mesh(mesh), scale(_scale)
{
reset();
}
class DualConInputReader : public ModelReader {
private:
const DualConInput *input_mesh;
int tottri, curtri;
float min[3], max[3], maxsize;
float scale;
void reset()
{
curtri = 0;
maxsize = 0;
tottri = input_mesh->tottri;
public:
DualConInputReader(const DualConInput *mesh, float _scale) : input_mesh(mesh), scale(_scale)
{
reset();
}
veccopy(min, input_mesh->min);
veccopy(max, input_mesh->max);
void reset()
{
curtri = 0;
maxsize = 0;
tottri = input_mesh->tottri;
/* initialize maxsize */
for (int i = 0; i < 3; i++) {
float d = max[i] - min[i];
if (d > maxsize)
maxsize = d;
}
veccopy(min, input_mesh->min);
veccopy(max, input_mesh->max);
/* redo the bounds */
for (int i = 0; i < 3; i++)
{
min[i] = (max[i] + min[i]) / 2 - maxsize / 2;
max[i] = (max[i] + min[i]) / 2 + maxsize / 2;
}
/* initialize maxsize */
for (int i = 0; i < 3; i++) {
float d = max[i] - min[i];
if (d > maxsize)
maxsize = d;
}
for (int i = 0; i < 3; i++)
min[i] -= maxsize * (1 / scale - 1) / 2;
maxsize *= 1 / scale;
}
/* redo the bounds */
for (int i = 0; i < 3; i++) {
min[i] = (max[i] + min[i]) / 2 - maxsize / 2;
max[i] = (max[i] + min[i]) / 2 + maxsize / 2;
}
Triangle *getNextTriangle()
{
if (curtri == input_mesh->tottri)
return NULL;
for (int i = 0; i < 3; i++)
min[i] -= maxsize * (1 / scale - 1) / 2;
maxsize *= 1 / scale;
}
Triangle *t = new Triangle();
Triangle *getNextTriangle()
{
if (curtri == input_mesh->tottri)
return NULL;
unsigned int *tr = GET_TRI(input_mesh, curtri);
veccopy(t->vt[0], GET_CO(input_mesh, GET_LOOP(input_mesh, tr[0])));
veccopy(t->vt[1], GET_CO(input_mesh, GET_LOOP(input_mesh, tr[1])));
veccopy(t->vt[2], GET_CO(input_mesh, GET_LOOP(input_mesh, tr[2])));
Triangle *t = new Triangle();
curtri++;
unsigned int *tr = GET_TRI(input_mesh, curtri);
veccopy(t->vt[0], GET_CO(input_mesh, GET_LOOP(input_mesh, tr[0])));
veccopy(t->vt[1], GET_CO(input_mesh, GET_LOOP(input_mesh, tr[1])));
veccopy(t->vt[2], GET_CO(input_mesh, GET_LOOP(input_mesh, tr[2])));
/* remove triangle if it contains invalid coords */
for (int i = 0; i < 3; i++) {
const float *co = t->vt[i];
if (isnan(co[0]) || isnan(co[1]) || isnan(co[2])) {
delete t;
return getNextTriangle();
}
}
curtri++;
return t;
}
/* remove triangle if it contains invalid coords */
for (int i = 0; i < 3; i++) {
const float *co = t->vt[i];
if (isnan(co[0]) || isnan(co[1]) || isnan(co[2])) {
delete t;
return getNextTriangle();
}
}
int getNextTriangle(int t[3])
{
if (curtri == input_mesh->tottri)
return 0;
return t;
}
unsigned int *tr = GET_TRI(input_mesh, curtri);
t[0] = tr[0];
t[1] = tr[1];
t[2] = tr[2];
int getNextTriangle(int t[3])
{
if (curtri == input_mesh->tottri)
return 0;
curtri++;
unsigned int *tr = GET_TRI(input_mesh, curtri);
t[0] = tr[0];
t[1] = tr[1];
t[2] = tr[2];
return 1;
}
curtri++;
int getNumTriangles()
{
return tottri;
}
return 1;
}
int getNumVertices()
{
return input_mesh->totco;
}
int getNumTriangles()
{
return tottri;
}
float getBoundingBox(float origin[3])
{
veccopy(origin, min);
return maxsize;
}
int getNumVertices()
{
return input_mesh->totco;
}
/* output */
void getNextVertex(float /*v*/[3])
{
/* not used */
}
float getBoundingBox(float origin[3])
{
veccopy(origin, min);
return maxsize;
}
/* stubs */
void printInfo() {
}
int getMemory() {
return sizeof(DualConInputReader);
}
/* output */
void getNextVertex(float /*v*/[3])
{
/* not used */
}
/* stubs */
void printInfo()
{
}
int getMemory()
{
return sizeof(DualConInputReader);
}
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("DUALCON:DualConInputReader")
MEM_CXX_CLASS_ALLOC_FUNCS("DUALCON:DualConInputReader")
#endif
};
void *dualcon(const DualConInput *input_mesh,
@@ -173,9 +171,8 @@ void *dualcon(const DualConInput *input_mesh,
float scale,
int depth)
{
DualConInputReader r(input_mesh, scale);
Octree o(&r, alloc_output, add_vert, add_quad,
flags, mode, depth, threshold, hermite_num);
o.scanConvert();
return o.getOutputMesh();
DualConInputReader r(input_mesh, scale);
Octree o(&r, alloc_output, add_vert, add_quad, flags, mode, depth, threshold, hermite_num);
o.scanConvert();
return o.getOutputMesh();
}

View File

@@ -16,261 +16,3331 @@
#include "manifold_table.h"
const ManifoldIndices manifold_table[256] = {
{0, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}},
{1, {{1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}}},
{1, {{0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}}},
{1, {{1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}}},
{1, {{1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}}},
{2, {{0, 0}, {1, 1}, {2, 2}, {0, 0}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {0, 0}, {0, 0}}},
{1, {{1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}}},
{2, {{1, 1}, {0, 0}, {0, 0}, {2, 2}, {1, 1}, {2, 2}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {0, 0}, {0, 0}}},
{1, {{0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}}},
{1, {{1, 1}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}},
{1, {{1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}}},
{1, {{0, 0}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}}},
{1, {{1, 1}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}},
{1, {{1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}}},
{2, {{1, 1}, {2, 2}, {0, 0}, {0, 0}, {0, 0}, {2, 2}, {1, 1}, {0, 0}, {2, 2}, {0, 0}, {1, 1}, {0, 0}}},
{1, {{0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}}},
{2, {{1, 1}, {0, 0}, {2, 2}, {0, 0}, {2, 2}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {2, 2}, {1, 1}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {0, 0}}},
{3, {{1, 1}, {2, 2}, {3, 3}, {0, 0}, {3, 3}, {2, 2}, {1, 1}, {0, 0}, {2, 2}, {3, 3}, {1, 1}, {0, 0}}},
{1, {{0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}}},
{2, {{1, 1}, {0, 0}, {0, 0}, {2, 2}, {0, 0}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {2, 2}, {1, 1}, {0, 0}}},
{2, {{0, 0}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {1, 1}, {2, 2}, {0, 0}, {2, 2}, {1, 1}, {2, 2}, {0, 0}}},
{2, {{1, 1}, {2, 2}, {0, 0}, {2, 2}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {2, 2}, {2, 2}, {1, 1}, {0, 0}}},
{1, {{0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}}},
{2, {{1, 1}, {0, 0}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}}},
{2, {{1, 1}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {0, 0}, {1, 1}, {0, 0}, {2, 2}, {0, 0}, {1, 1}, {0, 0}}},
{1, {{0, 0}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}}},
{1, {{0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}}},
{2, {{1, 1}, {2, 2}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {2, 2}, {1, 1}, {0, 0}, {2, 2}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}}},
{1, {{1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}}},
{2, {{0, 0}, {1, 1}, {2, 2}, {0, 0}, {2, 2}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {2, 2}, {1, 1}, {0, 0}}},
{2, {{1, 1}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {2, 2}, {1, 1}, {1, 1}, {2, 2}, {0, 0}}},
{2, {{0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {2, 2}, {0, 0}, {2, 2}, {2, 2}, {1, 1}, {2, 2}, {0, 0}}},
{1, {{1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}}},
{2, {{0, 0}, {1, 1}, {0, 0}, {2, 2}, {0, 0}, {2, 2}, {0, 0}, {1, 1}, {0, 0}, {2, 2}, {1, 1}, {0, 0}}},
{3, {{1, 1}, {2, 2}, {0, 0}, {3, 3}, {1, 1}, {3, 3}, {0, 0}, {2, 2}, {1, 1}, {3, 3}, {2, 2}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {0, 0}}},
{1, {{1, 1}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}}},
{2, {{0, 0}, {1, 1}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}}},
{2, {{1, 1}, {2, 2}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {2, 2}, {1, 1}, {0, 0}, {2, 2}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}}},
{1, {{1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}}},
{1, {{1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}},
{1, {{0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}}},
{1, {{1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}},
{2, {{1, 1}, {1, 1}, {2, 2}, {0, 0}, {2, 2}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {2, 2}, {0, 0}, {0, 0}}},
{1, {{0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}}},
{2, {{1, 1}, {0, 0}, {2, 2}, {0, 0}, {2, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {2, 2}, {0, 0}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}}},
{2, {{1, 1}, {1, 1}, {0, 0}, {2, 2}, {0, 0}, {2, 2}, {1, 1}, {1, 1}, {0, 0}, {2, 2}, {0, 0}, {0, 0}}},
{2, {{0, 0}, {1, 1}, {0, 0}, {2, 2}, {1, 1}, {2, 2}, {1, 1}, {1, 1}, {1, 1}, {2, 2}, {0, 0}, {0, 0}}},
{1, {{1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}}},
{2, {{1, 1}, {1, 1}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}},
{2, {{0, 0}, {2, 2}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {1, 2}, {2, 2}, {2, 1}, {0, 0}, {0, 0}, {0, 0}}},
{2, {{1, 1}, {0, 0}, {2, 2}, {1, 2}, {2, 2}, {0, 0}, {1, 1}, {1, 1}, {2, 1}, {0, 0}, {0, 0}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}}},
{2, {{1, 1}, {0, 0}, {2, 2}, {0, 0}, {1, 1}, {0, 0}, {2, 2}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {2, 2}}},
{2, {{0, 0}, {1, 1}, {2, 2}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {2, 2}}},
{2, {{1, 1}, {1, 1}, {2, 2}, {0, 0}, {1, 1}, {1, 1}, {2, 2}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {2, 2}}},
{1, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}}},
{1, {{1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}}},
{2, {{0, 0}, {1, 1}, {0, 0}, {0, 0}, {2, 2}, {1, 1}, {2, 2}, {0, 0}, {1, 1}, {2, 2}, {0, 0}, {2, 2}}},
{1, {{1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}}},
{2, {{0, 0}, {0, 0}, {1, 1}, {2, 2}, {0, 0}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {2, 2}, {0, 0}, {1, 1}}},
{3, {{1, 1}, {0, 0}, {2, 2}, {3, 3}, {1, 1}, {3, 3}, {2, 2}, {0, 0}, {1, 1}, {3, 3}, {0, 0}, {2, 2}}},
{2, {{0, 0}, {1, 1}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {2, 2}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {2, 2}}},
{2, {{1, 1}, {1, 1}, {2, 2}, {1, 1}, {1, 1}, {0, 0}, {2, 2}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {2, 2}}},
{1, {{0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}}},
{1, {{1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}}},
{1, {{0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}}},
{1, {{1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}}},
{1, {{1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}}},
{1, {{0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}}},
{2, {{1, 1}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {2, 2}, {0, 0}, {0, 0}, {2, 2}, {0, 0}, {1, 1}, {1, 1}}},
{1, {{0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}}},
{1, {{1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}}},
{1, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}},
{2, {{1, 1}, {2, 2}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {0, 0}, {0, 0}, {2, 2}, {1, 1}, {1, 1}, {1, 1}}},
{1, {{0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}}},
{2, {{1, 1}, {0, 0}, {1, 1}, {2, 2}, {0, 0}, {2, 2}, {0, 0}, {0, 0}, {0, 0}, {2, 2}, {1, 1}, {1, 1}}},
{2, {{0, 0}, {0, 0}, {1, 1}, {2, 2}, {1, 1}, {2, 2}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {1, 1}, {1, 1}}},
{2, {{1, 1}, {2, 2}, {1, 1}, {2, 2}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {2, 2}, {2, 2}, {1, 1}, {1, 1}}},
{2, {{0, 0}, {1, 2}, {1, 1}, {2, 2}, {2, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {2, 2}, {1, 1}, {1, 1}}},
{1, {{1, 1}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}}},
{1, {{0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}}},
{2, {{2, 2}, {1, 1}, {0, 0}, {1, 1}, {2, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {2, 2}, {1, 2}}},
{1, {{0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}}},
{2, {{0, 0}, {1, 1}, {2, 2}, {0, 0}, {0, 0}, {0, 0}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {2, 2}}},
{3, {{1, 1}, {2, 2}, {3, 3}, {0, 0}, {1, 1}, {0, 0}, {3, 3}, {2, 2}, {1, 1}, {0, 0}, {2, 2}, {3, 3}}},
{2, {{0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {2, 2}, {1, 1}, {2, 2}, {2, 2}, {0, 0}, {2, 2}, {1, 1}}},
{2, {{1, 1}, {0, 0}, {2, 2}, {0, 0}, {1, 1}, {1, 1}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {2, 2}}},
{2, {{0, 0}, {1, 1}, {0, 0}, {0, 0}, {2, 2}, {0, 0}, {2, 2}, {1, 1}, {0, 0}, {2, 2}, {1, 1}, {2, 2}}},
{2, {{1, 1}, {2, 2}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {1, 1}, {1, 1}, {2, 2}, {1, 1}}},
{2, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {1, 1}, {2, 2}, {2, 2}, {1, 1}, {2, 2}, {1, 1}}},
{2, {{2, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {1, 1}, {0, 0}, {1, 2}, {1, 1}, {2, 2}}},
{3, {{0, 0}, {1, 1}, {2, 2}, {3, 3}, {0, 0}, {3, 3}, {2, 2}, {1, 1}, {0, 0}, {3, 3}, {1, 1}, {2, 2}}},
{4, {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 1}, {4, 4}, {3, 3}, {2, 2}, {1, 1}, {4, 4}, {2, 2}, {3, 3}}},
{2, {{0, 0}, {0, 0}, {1, 1}, {2, 2}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {1, 1}}},
{2, {{1, 1}, {0, 0}, {2, 2}, {1, 1}, {1, 1}, {0, 0}, {2, 2}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {2, 2}}},
{2, {{0, 0}, {1, 1}, {0, 0}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {2, 2}}},
{2, {{1, 1}, {2, 2}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {2, 2}, {1, 1}, {0, 0}, {2, 2}, {1, 1}}},
{2, {{0, 0}, {0, 0}, {0, 0}, {2, 1}, {1, 1}, {0, 0}, {1, 1}, {2, 2}, {1, 2}, {0, 0}, {2, 2}, {1, 1}}},
{2, {{1, 2}, {0, 0}, {0, 0}, {2, 1}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {0, 0}, {0, 0}, {2, 2}, {1, 1}}},
{1, {{1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}}},
{1, {{0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}}},
{1, {{1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}}},
{1, {{0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}}},
{1, {{1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {1, 1}}},
{1, {{0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {1, 1}}},
{2, {{2, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {0, 0}, {1, 2}, {2, 2}, {1, 1}, {0, 0}, {1, 1}}},
{1, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {1, 1}}},
{2, {{1, 1}, {1, 1}, {1, 1}, {2, 2}, {0, 0}, {2, 2}, {0, 0}, {1, 1}, {0, 0}, {2, 2}, {0, 0}, {1, 1}}},
{2, {{0, 0}, {1, 1}, {1, 1}, {2, 2}, {1, 1}, {2, 2}, {0, 0}, {1, 1}, {1, 1}, {2, 2}, {0, 0}, {1, 1}}},
{2, {{1, 2}, {0, 0}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {2, 1}, {1, 1}, {1, 1}, {0, 0}, {2, 2}}},
{2, {{0, 0}, {0, 0}, {2, 2}, {1, 1}, {1, 2}, {0, 0}, {0, 0}, {2, 1}, {0, 0}, {1, 1}, {0, 0}, {2, 2}}},
{2, {{1, 1}, {1, 1}, {0, 0}, {2, 2}, {1, 2}, {2, 2}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {2, 1}}},
{2, {{0, 0}, {1, 1}, {0, 0}, {2, 2}, {0, 0}, {2, 2}, {0, 0}, {1, 1}, {1, 2}, {0, 0}, {0, 0}, {2, 1}}},
{2, {{1, 1}, {0, 0}, {0, 0}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {2, 2}}},
{1, {{0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}}},
{1, {{0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}}},
{2, {{1, 1}, {0, 0}, {0, 0}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {2, 2}}},
{2, {{0, 0}, {1, 1}, {0, 0}, {2, 2}, {0, 0}, {1, 1}, {0, 0}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {2, 2}}},
{2, {{1, 1}, {1, 1}, {0, 0}, {2, 2}, {1, 1}, {1, 1}, {0, 0}, {2, 2}, {0, 0}, {0, 0}, {0, 0}, {2, 2}}},
{2, {{0, 0}, {0, 0}, {1, 1}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {2, 2}, {0, 0}, {1, 1}, {0, 0}, {2, 2}}},
{2, {{1, 1}, {0, 0}, {1, 1}, {2, 2}, {0, 0}, {0, 0}, {0, 0}, {2, 2}, {1, 1}, {1, 1}, {0, 0}, {2, 2}}},
{3, {{0, 0}, {1, 1}, {2, 2}, {3, 3}, {2, 2}, {1, 1}, {0, 0}, {3, 3}, {1, 1}, {2, 2}, {0, 0}, {3, 3}}},
{2, {{1, 1}, {1, 1}, {1, 1}, {2, 2}, {0, 0}, {1, 1}, {0, 0}, {2, 2}, {0, 0}, {1, 1}, {0, 0}, {2, 2}}},
{1, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {1, 1}}},
{2, {{1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {0, 0}, {2, 2}, {1, 1}, {2, 2}, {0, 0}, {2, 2}}},
{1, {{0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {1, 1}}},
{1, {{1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {1, 1}}},
{1, {{0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}}},
{1, {{1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}}},
{1, {{0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}}},
{1, {{1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}}},
{2, {{1, 1}, {0, 0}, {0, 0}, {2, 2}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {0, 0}, {0, 0}, {1, 1}, {2, 2}}},
{2, {{0, 0}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {0, 0}, {2, 2}, {1, 1}, {2, 2}, {0, 0}, {2, 2}, {1, 1}}},
{3, {{1, 1}, {2, 2}, {0, 0}, {3, 3}, {0, 0}, {2, 2}, {1, 1}, {3, 3}, {2, 2}, {0, 0}, {1, 1}, {3, 3}}},
{2, {{0, 0}, {1, 1}, {0, 0}, {2, 2}, {1, 1}, {1, 1}, {1, 1}, {2, 2}, {0, 0}, {0, 0}, {1, 1}, {2, 2}}},
{3, {{1, 1}, {0, 0}, {2, 2}, {3, 3}, {2, 2}, {0, 0}, {1, 1}, {3, 3}, {0, 0}, {2, 2}, {1, 1}, {3, 3}}},
{2, {{0, 0}, {0, 0}, {1, 1}, {2, 2}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {1, 1}, {1, 1}, {1, 1}, {2, 2}}},
{4, {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {3, 3}, {2, 2}, {1, 1}, {4, 4}, {2, 2}, {3, 3}, {1, 1}, {4, 4}}},
{2, {{0, 0}, {1, 1}, {1, 1}, {2, 2}, {0, 0}, {1, 1}, {1, 1}, {2, 2}, {0, 0}, {1, 1}, {1, 1}, {2, 2}}},
{2, {{1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {2, 2}, {1, 1}, {2, 2}, {0, 0}, {2, 2}, {1, 1}, {2, 2}}},
{2, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {1, 1}, {2, 2}, {1, 1}, {2, 2}, {1, 1}, {2, 2}}},
{2, {{1, 1}, {2, 2}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {2, 2}, {2, 2}, {1, 1}, {2, 2}}},
{2, {{0, 0}, {2, 1}, {0, 0}, {0, 0}, {1, 2}, {0, 0}, {2, 2}, {1, 1}, {0, 0}, {1, 1}, {2, 2}, {1, 1}}},
{2, {{1, 1}, {0, 0}, {2, 2}, {0, 0}, {2, 2}, {2, 2}, {1, 1}, {2, 2}, {0, 0}, {0, 0}, {1, 1}, {2, 2}}},
{2, {{0, 0}, {0, 0}, {2, 1}, {0, 0}, {0, 0}, {1, 2}, {1, 1}, {2, 2}, {1, 1}, {0, 0}, {1, 1}, {2, 2}}},
{2, {{1, 1}, {2, 2}, {2, 2}, {0, 0}, {2, 2}, {0, 0}, {1, 1}, {2, 2}, {2, 2}, {0, 0}, {1, 1}, {2, 2}}},
{2, {{0, 0}, {1, 2}, {2, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {0, 0}, {0, 0}, {1, 1}, {2, 2}}},
{1, {{0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}}},
{2, {{1, 1}, {2, 2}, {0, 0}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {2, 2}, {2, 2}}},
{1, {{0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}}},
{1, {{1, 1}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}}},
{2, {{0, 0}, {1, 1}, {2, 2}, {1, 1}, {2, 2}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {2, 2}, {1, 1}, {1, 1}}},
{2, {{1, 1}, {2, 2}, {1, 1}, {2, 2}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {2, 2}, {2, 2}}},
{2, {{0, 0}, {0, 0}, {1, 1}, {2, 2}, {1, 1}, {2, 2}, {0, 0}, {0, 0}, {2, 2}, {1, 1}, {2, 2}, {2, 2}}},
{2, {{1, 1}, {0, 0}, {1, 1}, {2, 2}, {0, 0}, {2, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 2}, {2, 2}}},
{1, {{0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}}},
{2, {{1, 1}, {2, 2}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {2, 2}, {2, 2}}},
{1, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}},
{1, {{1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}}},
{1, {{0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}}},
{2, {{2, 2}, {1, 1}, {1, 2}, {0, 0}, {0, 0}, {2, 1}, {0, 0}, {0, 0}, {2, 2}, {0, 0}, {1, 1}, {1, 1}}},
{1, {{0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}}},
{1, {{1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}}},
{1, {{1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}}},
{1, {{0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}}},
{1, {{1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}}},
{1, {{0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}}},
{2, {{1, 1}, {1, 1}, {2, 2}, {1, 1}, {2, 2}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {2, 2}, {0, 0}, {1, 1}}},
{2, {{0, 0}, {1, 1}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {2, 1}, {0, 0}, {1, 2}, {2, 2}, {0, 0}, {1, 1}}},
{2, {{1, 1}, {0, 0}, {2, 2}, {1, 1}, {2, 2}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {2, 2}, {0, 0}, {1, 1}}},
{2, {{0, 0}, {0, 0}, {2, 2}, {1, 1}, {0, 0}, {1, 2}, {2, 1}, {0, 0}, {0, 0}, {2, 2}, {0, 0}, {1, 1}}},
{1, {{1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}}},
{2, {{0, 0}, {2, 1}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {1, 1}, {0, 0}, {1, 1}, {2, 2}, {0, 0}, {1, 2}}},
{1, {{1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}}},
{1, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}}},
{2, {{2, 2}, {1, 2}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {2, 2}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {2, 1}}},
{2, {{0, 0}, {1, 1}, {2, 2}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {2, 2}}},
{2, {{2, 2}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {2, 2}, {0, 0}, {1, 2}, {0, 0}, {0, 0}, {2, 1}}},
{1, {{0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}}},
{1, {{0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}},
{2, {{1, 1}, {0, 0}, {2, 2}, {2, 2}, {1, 1}, {0, 0}, {2, 2}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {0, 0}}},
{2, {{0, 0}, {1, 1}, {2, 2}, {2, 2}, {0, 0}, {1, 1}, {2, 2}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {0, 0}}},
{2, {{1, 1}, {1, 1}, {2, 2}, {2, 2}, {1, 1}, {1, 1}, {2, 2}, {2, 2}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}}},
{1, {{1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}}},
{2, {{0, 0}, {1, 1}, {0, 0}, {2, 2}, {2, 2}, {1, 1}, {2, 2}, {2, 2}, {1, 1}, {2, 2}, {0, 0}, {0, 0}}},
{2, {{1, 2}, {2, 2}, {0, 0}, {1, 1}, {0, 0}, {2, 2}, {1, 1}, {1, 1}, {0, 0}, {2, 1}, {0, 0}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}}},
{2, {{1, 1}, {0, 0}, {2, 2}, {0, 0}, {1, 1}, {2, 2}, {2, 2}, {2, 2}, {1, 1}, {2, 2}, {0, 0}, {0, 0}}},
{1, {{0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}}},
{2, {{1, 1}, {1, 1}, {2, 2}, {0, 0}, {1, 1}, {0, 0}, {2, 2}, {1, 2}, {0, 0}, {2, 1}, {0, 0}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}},
{1, {{1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}}},
{1, {{0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}}},
{1, {{1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}},
{1, {{1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}}},
{2, {{1, 1}, {2, 2}, {1, 1}, {1, 1}, {0, 0}, {2, 2}, {0, 0}, {1, 1}, {2, 2}, {0, 0}, {1, 1}, {0, 0}}},
{2, {{0, 0}, {1, 1}, {1, 2}, {2, 2}, {1, 1}, {1, 1}, {0, 0}, {2, 2}, {0, 0}, {0, 0}, {2, 1}, {0, 0}}},
{1, {{1, 1}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {0, 0}}},
{2, {{1, 1}, {2, 2}, {0, 0}, {1, 1}, {1, 1}, {2, 2}, {0, 0}, {1, 1}, {2, 2}, {1, 1}, {1, 1}, {0, 0}}},
{2, {{0, 0}, {1, 1}, {0, 0}, {2, 2}, {0, 0}, {1, 1}, {0, 0}, {2, 2}, {0, 0}, {1, 2}, {2, 1}, {0, 0}}},
{1, {{1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}}},
{2, {{0, 0}, {0, 0}, {2, 1}, {0, 0}, {2, 2}, {1, 1}, {0, 0}, {1, 1}, {2, 2}, {1, 1}, {1, 2}, {0, 0}}},
{2, {{1, 1}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {2, 1}, {2, 2}, {1, 2}, {1, 1}, {0, 0}}},
{2, {{0, 0}, {1, 1}, {2, 2}, {0, 0}, {2, 2}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {2, 2}, {1, 1}, {0, 0}}},
{1, {{1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}}},
{2, {{1, 1}, {2, 2}, {0, 0}, {0, 0}, {1, 2}, {0, 0}, {0, 0}, {2, 1}, {2, 2}, {0, 0}, {1, 1}, {0, 0}}},
{1, {{0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}}},
{1, {{0, 0}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}}},
{2, {{1, 1}, {2, 2}, {2, 2}, {2, 2}, {1, 1}, {0, 0}, {2, 2}, {0, 0}, {1, 1}, {0, 0}, {2, 2}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}}},
{2, {{2, 2}, {0, 0}, {1, 1}, {1, 1}, {2, 2}, {1, 2}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {2, 1}, {0, 0}}},
{1, {{0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}}},
{2, {{1, 1}, {2, 2}, {0, 0}, {1, 2}, {0, 0}, {0, 0}, {2, 1}, {0, 0}, {1, 1}, {1, 1}, {2, 2}, {0, 0}}},
{2, {{0, 0}, {0, 0}, {0, 0}, {2, 1}, {2, 2}, {1, 1}, {1, 2}, {0, 0}, {1, 1}, {2, 2}, {1, 1}, {0, 0}}},
{2, {{1, 1}, {0, 0}, {0, 0}, {2, 2}, {0, 0}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {2, 2}, {1, 1}, {0, 0}}},
{1, {{0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}}},
{2, {{1, 1}, {2, 2}, {2, 2}, {0, 0}, {1, 1}, {2, 2}, {2, 2}, {0, 0}, {1, 1}, {2, 2}, {2, 2}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {0, 0}}},
{2, {{1, 1}, {0, 0}, {2, 2}, {0, 0}, {1, 1}, {0, 0}, {2, 2}, {0, 0}, {0, 0}, {2, 1}, {1, 2}, {0, 0}}},
{1, {{0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}}},
{2, {{1, 1}, {2, 2}, {0, 0}, {0, 0}, {0, 0}, {1, 2}, {2, 1}, {0, 0}, {1, 1}, {0, 0}, {2, 2}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}}},
{1, {{1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}}},
{1, {{1, 1}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}},
{1, {{0, 0}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}}},
{1, {{1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}},
{1, {{1, 1}, {1, 1}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}}},
{1, {{0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}}},
{2, {{1, 2}, {0, 0}, {0, 0}, {2, 1}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {0, 0}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}}},
{1, {{1, 1}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}}},
{2, {{0, 0}, {1, 2}, {2, 1}, {0, 0}, {2, 2}, {1, 1}, {0, 0}, {0, 0}, {2, 2}, {1, 1}, {0, 0}, {0, 0}}},
{1, {{1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}}},
{1, {{0, 0}, {0, 0}, {1, 1}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}}},
{1, {{1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}},
{1, {{0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}}},
{1, {{1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0, 0}, {0, 0}}},
{0, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}}
};
const ManifoldIndices manifold_table[256] = {{0,
{{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0}}},
{1,
{{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0}}},
{1,
{{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0}}},
{1,
{{1, 1},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0}}},
{1,
{{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0}}},
{2,
{{0, 0},
{1, 1},
{2, 2},
{0, 0},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{2, 2},
{0, 0},
{0, 0}}},
{1,
{{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0}}},
{2,
{{1, 1},
{0, 0},
{0, 0},
{2, 2},
{1, 1},
{2, 2},
{0, 0},
{0, 0},
{1, 1},
{2, 2},
{0, 0},
{0, 0}}},
{1,
{{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0}}},
{1,
{{1, 1},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0}}},
{1,
{{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0}}},
{1,
{{0, 0},
{1, 1},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0}}},
{1,
{{1, 1},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0}}},
{1,
{{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0}}},
{2,
{{1, 1},
{2, 2},
{0, 0},
{0, 0},
{0, 0},
{2, 2},
{1, 1},
{0, 0},
{2, 2},
{0, 0},
{1, 1},
{0, 0}}},
{1,
{{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0}}},
{2,
{{1, 1},
{0, 0},
{2, 2},
{0, 0},
{2, 2},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{2, 2},
{1, 1},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{0, 0}}},
{3,
{{1, 1},
{2, 2},
{3, 3},
{0, 0},
{3, 3},
{2, 2},
{1, 1},
{0, 0},
{2, 2},
{3, 3},
{1, 1},
{0, 0}}},
{1,
{{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0}}},
{2,
{{1, 1},
{0, 0},
{0, 0},
{2, 2},
{0, 0},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{2, 2},
{1, 1},
{0, 0}}},
{2,
{{0, 0},
{0, 0},
{0, 0},
{1, 1},
{2, 2},
{1, 1},
{2, 2},
{0, 0},
{2, 2},
{1, 1},
{2, 2},
{0, 0}}},
{2,
{{1, 1},
{2, 2},
{0, 0},
{2, 2},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{2, 2},
{2, 2},
{1, 1},
{0, 0}}},
{1,
{{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0}}},
{2,
{{1, 1},
{0, 0},
{2, 2},
{2, 2},
{2, 2},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0}}},
{2,
{{1, 1},
{2, 2},
{2, 2},
{2, 2},
{2, 2},
{0, 0},
{1, 1},
{0, 0},
{2, 2},
{0, 0},
{1, 1},
{0, 0}}},
{1,
{{0, 0},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0}}},
{1,
{{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0}}},
{2,
{{1, 1},
{2, 2},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{2, 2},
{1, 1},
{0, 0},
{2, 2},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0}}},
{1,
{{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0}}},
{2,
{{0, 0},
{1, 1},
{2, 2},
{0, 0},
{2, 2},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{2, 2},
{1, 1},
{0, 0}}},
{2,
{{1, 1},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{2, 2},
{1, 1},
{1, 1},
{2, 2},
{0, 0}}},
{2,
{{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{2, 2},
{0, 0},
{2, 2},
{2, 2},
{1, 1},
{2, 2},
{0, 0}}},
{1,
{{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0}}},
{2,
{{0, 0},
{1, 1},
{0, 0},
{2, 2},
{0, 0},
{2, 2},
{0, 0},
{1, 1},
{0, 0},
{2, 2},
{1, 1},
{0, 0}}},
{3,
{{1, 1},
{2, 2},
{0, 0},
{3, 3},
{1, 1},
{3, 3},
{0, 0},
{2, 2},
{1, 1},
{3, 3},
{2, 2},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{1, 1},
{0, 0}}},
{1,
{{1, 1},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0}}},
{2,
{{0, 0},
{1, 1},
{2, 2},
{2, 2},
{2, 2},
{2, 2},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0}}},
{2,
{{1, 1},
{2, 2},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{2, 2},
{1, 1},
{0, 0},
{2, 2},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0}}},
{1,
{{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0}}},
{1,
{{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0}}},
{1,
{{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0}}},
{1,
{{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0}}},
{2,
{{1, 1},
{1, 1},
{2, 2},
{0, 0},
{2, 2},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{2, 2},
{0, 0},
{0, 0}}},
{1,
{{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0}}},
{2,
{{1, 1},
{0, 0},
{2, 2},
{0, 0},
{2, 2},
{1, 1},
{1, 1},
{1, 1},
{1, 1},
{2, 2},
{0, 0},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0}}},
{2,
{{1, 1},
{1, 1},
{0, 0},
{2, 2},
{0, 0},
{2, 2},
{1, 1},
{1, 1},
{0, 0},
{2, 2},
{0, 0},
{0, 0}}},
{2,
{{0, 0},
{1, 1},
{0, 0},
{2, 2},
{1, 1},
{2, 2},
{1, 1},
{1, 1},
{1, 1},
{2, 2},
{0, 0},
{0, 0}}},
{1,
{{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0}}},
{2,
{{1, 1},
{1, 1},
{2, 2},
{2, 2},
{2, 2},
{2, 2},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0}}},
{2,
{{0, 0},
{2, 2},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{1, 2},
{2, 2},
{2, 1},
{0, 0},
{0, 0},
{0, 0}}},
{2,
{{1, 1},
{0, 0},
{2, 2},
{1, 2},
{2, 2},
{0, 0},
{1, 1},
{1, 1},
{2, 1},
{0, 0},
{0, 0},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1}}},
{2,
{{1, 1},
{0, 0},
{2, 2},
{0, 0},
{1, 1},
{0, 0},
{2, 2},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{2, 2}}},
{2,
{{0, 0},
{1, 1},
{2, 2},
{0, 0},
{0, 0},
{1, 1},
{2, 2},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{2, 2}}},
{2,
{{1, 1},
{1, 1},
{2, 2},
{0, 0},
{1, 1},
{1, 1},
{2, 2},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{2, 2}}},
{1,
{{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1}}},
{1,
{{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1}}},
{2,
{{0, 0},
{1, 1},
{0, 0},
{0, 0},
{2, 2},
{1, 1},
{2, 2},
{0, 0},
{1, 1},
{2, 2},
{0, 0},
{2, 2}}},
{1,
{{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1}}},
{2,
{{0, 0},
{0, 0},
{1, 1},
{2, 2},
{0, 0},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{2, 2},
{0, 0},
{1, 1}}},
{3,
{{1, 1},
{0, 0},
{2, 2},
{3, 3},
{1, 1},
{3, 3},
{2, 2},
{0, 0},
{1, 1},
{3, 3},
{0, 0},
{2, 2}}},
{2,
{{0, 0},
{1, 1},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{2, 2},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{2, 2}}},
{2,
{{1, 1},
{1, 1},
{2, 2},
{1, 1},
{1, 1},
{0, 0},
{2, 2},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{2, 2}}},
{1,
{{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1}}},
{1,
{{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1}}},
{1,
{{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1}}},
{1,
{{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1}}},
{1,
{{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1}}},
{1,
{{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1}}},
{2,
{{1, 1},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{2, 2},
{0, 0},
{0, 0},
{2, 2},
{0, 0},
{1, 1},
{1, 1}}},
{1,
{{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1}}},
{1,
{{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1}}},
{1,
{{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{1, 1}}},
{2,
{{1, 1},
{2, 2},
{0, 0},
{0, 0},
{1, 1},
{2, 2},
{0, 0},
{0, 0},
{2, 2},
{1, 1},
{1, 1},
{1, 1}}},
{1,
{{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1}}},
{2,
{{1, 1},
{0, 0},
{1, 1},
{2, 2},
{0, 0},
{2, 2},
{0, 0},
{0, 0},
{0, 0},
{2, 2},
{1, 1},
{1, 1}}},
{2,
{{0, 0},
{0, 0},
{1, 1},
{2, 2},
{1, 1},
{2, 2},
{0, 0},
{0, 0},
{1, 1},
{2, 2},
{1, 1},
{1, 1}}},
{2,
{{1, 1},
{2, 2},
{1, 1},
{2, 2},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{2, 2},
{2, 2},
{1, 1},
{1, 1}}},
{2,
{{0, 0},
{1, 2},
{1, 1},
{2, 2},
{2, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{2, 2},
{1, 1},
{1, 1}}},
{1,
{{1, 1},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1}}},
{1,
{{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1}}},
{2,
{{2, 2},
{1, 1},
{0, 0},
{1, 1},
{2, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{2, 2},
{1, 2}}},
{1,
{{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1}}},
{2,
{{0, 0},
{1, 1},
{2, 2},
{0, 0},
{0, 0},
{0, 0},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{2, 2}}},
{3,
{{1, 1},
{2, 2},
{3, 3},
{0, 0},
{1, 1},
{0, 0},
{3, 3},
{2, 2},
{1, 1},
{0, 0},
{2, 2},
{3, 3}}},
{2,
{{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{2, 2},
{1, 1},
{2, 2},
{2, 2},
{0, 0},
{2, 2},
{1, 1}}},
{2,
{{1, 1},
{0, 0},
{2, 2},
{0, 0},
{1, 1},
{1, 1},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{2, 2}}},
{2,
{{0, 0},
{1, 1},
{0, 0},
{0, 0},
{2, 2},
{0, 0},
{2, 2},
{1, 1},
{0, 0},
{2, 2},
{1, 1},
{2, 2}}},
{2,
{{1, 1},
{2, 2},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{2, 2},
{1, 1},
{1, 1},
{2, 2},
{1, 1}}},
{2,
{{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{2, 2},
{1, 1},
{2, 2},
{2, 2},
{1, 1},
{2, 2},
{1, 1}}},
{2,
{{2, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{2, 2},
{1, 1},
{0, 0},
{1, 2},
{1, 1},
{2, 2}}},
{3,
{{0, 0},
{1, 1},
{2, 2},
{3, 3},
{0, 0},
{3, 3},
{2, 2},
{1, 1},
{0, 0},
{3, 3},
{1, 1},
{2, 2}}},
{4,
{{1, 1},
{2, 2},
{3, 3},
{4, 4},
{1, 1},
{4, 4},
{3, 3},
{2, 2},
{1, 1},
{4, 4},
{2, 2},
{3, 3}}},
{2,
{{0, 0},
{0, 0},
{1, 1},
{2, 2},
{0, 0},
{0, 0},
{1, 1},
{2, 2},
{2, 2},
{2, 2},
{2, 2},
{1, 1}}},
{2,
{{1, 1},
{0, 0},
{2, 2},
{1, 1},
{1, 1},
{0, 0},
{2, 2},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{2, 2}}},
{2,
{{0, 0},
{1, 1},
{0, 0},
{2, 2},
{2, 2},
{2, 2},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{2, 2}}},
{2,
{{1, 1},
{2, 2},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{2, 2},
{1, 1},
{0, 0},
{2, 2},
{1, 1}}},
{2,
{{0, 0},
{0, 0},
{0, 0},
{2, 1},
{1, 1},
{0, 0},
{1, 1},
{2, 2},
{1, 2},
{0, 0},
{2, 2},
{1, 1}}},
{2,
{{1, 2},
{0, 0},
{0, 0},
{2, 1},
{0, 0},
{0, 0},
{1, 1},
{2, 2},
{0, 0},
{0, 0},
{2, 2},
{1, 1}}},
{1,
{{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1}}},
{1,
{{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{1, 1}}},
{1,
{{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{1, 1}}},
{1,
{{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1}}},
{1,
{{1, 1},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{1, 1}}},
{1,
{{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{1, 1}}},
{2,
{{2, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{2, 2},
{0, 0},
{1, 2},
{2, 2},
{1, 1},
{0, 0},
{1, 1}}},
{1,
{{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{1, 1}}},
{2,
{{1, 1},
{1, 1},
{1, 1},
{2, 2},
{0, 0},
{2, 2},
{0, 0},
{1, 1},
{0, 0},
{2, 2},
{0, 0},
{1, 1}}},
{2,
{{0, 0},
{1, 1},
{1, 1},
{2, 2},
{1, 1},
{2, 2},
{0, 0},
{1, 1},
{1, 1},
{2, 2},
{0, 0},
{1, 1}}},
{2,
{{1, 2},
{0, 0},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{2, 1},
{1, 1},
{1, 1},
{0, 0},
{2, 2}}},
{2,
{{0, 0},
{0, 0},
{2, 2},
{1, 1},
{1, 2},
{0, 0},
{0, 0},
{2, 1},
{0, 0},
{1, 1},
{0, 0},
{2, 2}}},
{2,
{{1, 1},
{1, 1},
{0, 0},
{2, 2},
{1, 2},
{2, 2},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{2, 1}}},
{2,
{{0, 0},
{1, 1},
{0, 0},
{2, 2},
{0, 0},
{2, 2},
{0, 0},
{1, 1},
{1, 2},
{0, 0},
{0, 0},
{2, 1}}},
{2,
{{1, 1},
{0, 0},
{0, 0},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{2, 2}}},
{1,
{{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1}}},
{1,
{{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1}}},
{2,
{{1, 1},
{0, 0},
{0, 0},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{2, 2}}},
{2,
{{0, 0},
{1, 1},
{0, 0},
{2, 2},
{0, 0},
{1, 1},
{0, 0},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{2, 2}}},
{2,
{{1, 1},
{1, 1},
{0, 0},
{2, 2},
{1, 1},
{1, 1},
{0, 0},
{2, 2},
{0, 0},
{0, 0},
{0, 0},
{2, 2}}},
{2,
{{0, 0},
{0, 0},
{1, 1},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{2, 2},
{0, 0},
{1, 1},
{0, 0},
{2, 2}}},
{2,
{{1, 1},
{0, 0},
{1, 1},
{2, 2},
{0, 0},
{0, 0},
{0, 0},
{2, 2},
{1, 1},
{1, 1},
{0, 0},
{2, 2}}},
{3,
{{0, 0},
{1, 1},
{2, 2},
{3, 3},
{2, 2},
{1, 1},
{0, 0},
{3, 3},
{1, 1},
{2, 2},
{0, 0},
{3, 3}}},
{2,
{{1, 1},
{1, 1},
{1, 1},
{2, 2},
{0, 0},
{1, 1},
{0, 0},
{2, 2},
{0, 0},
{1, 1},
{0, 0},
{2, 2}}},
{1,
{{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{1, 1}}},
{2,
{{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{2, 2},
{0, 0},
{2, 2},
{1, 1},
{2, 2},
{0, 0},
{2, 2}}},
{1,
{{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{1, 1}}},
{1,
{{1, 1},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{1, 1}}},
{1,
{{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1}}},
{1,
{{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{1, 1}}},
{1,
{{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{1, 1}}},
{1,
{{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1}}},
{2,
{{1, 1},
{0, 0},
{0, 0},
{2, 2},
{0, 0},
{0, 0},
{1, 1},
{2, 2},
{0, 0},
{0, 0},
{1, 1},
{2, 2}}},
{2,
{{0, 0},
{0, 0},
{0, 0},
{1, 1},
{2, 2},
{0, 0},
{2, 2},
{1, 1},
{2, 2},
{0, 0},
{2, 2},
{1, 1}}},
{3,
{{1, 1},
{2, 2},
{0, 0},
{3, 3},
{0, 0},
{2, 2},
{1, 1},
{3, 3},
{2, 2},
{0, 0},
{1, 1},
{3, 3}}},
{2,
{{0, 0},
{1, 1},
{0, 0},
{2, 2},
{1, 1},
{1, 1},
{1, 1},
{2, 2},
{0, 0},
{0, 0},
{1, 1},
{2, 2}}},
{3,
{{1, 1},
{0, 0},
{2, 2},
{3, 3},
{2, 2},
{0, 0},
{1, 1},
{3, 3},
{0, 0},
{2, 2},
{1, 1},
{3, 3}}},
{2,
{{0, 0},
{0, 0},
{1, 1},
{2, 2},
{0, 0},
{0, 0},
{1, 1},
{2, 2},
{1, 1},
{1, 1},
{1, 1},
{2, 2}}},
{4,
{{1, 1},
{2, 2},
{3, 3},
{4, 4},
{3, 3},
{2, 2},
{1, 1},
{4, 4},
{2, 2},
{3, 3},
{1, 1},
{4, 4}}},
{2,
{{0, 0},
{1, 1},
{1, 1},
{2, 2},
{0, 0},
{1, 1},
{1, 1},
{2, 2},
{0, 0},
{1, 1},
{1, 1},
{2, 2}}},
{2,
{{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{2, 2},
{1, 1},
{2, 2},
{0, 0},
{2, 2},
{1, 1},
{2, 2}}},
{2,
{{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{2, 2},
{1, 1},
{2, 2},
{1, 1},
{2, 2},
{1, 1},
{2, 2}}},
{2,
{{1, 1},
{2, 2},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{2, 2},
{2, 2},
{2, 2},
{1, 1},
{2, 2}}},
{2,
{{0, 0},
{2, 1},
{0, 0},
{0, 0},
{1, 2},
{0, 0},
{2, 2},
{1, 1},
{0, 0},
{1, 1},
{2, 2},
{1, 1}}},
{2,
{{1, 1},
{0, 0},
{2, 2},
{0, 0},
{2, 2},
{2, 2},
{1, 1},
{2, 2},
{0, 0},
{0, 0},
{1, 1},
{2, 2}}},
{2,
{{0, 0},
{0, 0},
{2, 1},
{0, 0},
{0, 0},
{1, 2},
{1, 1},
{2, 2},
{1, 1},
{0, 0},
{1, 1},
{2, 2}}},
{2,
{{1, 1},
{2, 2},
{2, 2},
{0, 0},
{2, 2},
{0, 0},
{1, 1},
{2, 2},
{2, 2},
{0, 0},
{1, 1},
{2, 2}}},
{2,
{{0, 0},
{1, 2},
{2, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{2, 2},
{0, 0},
{0, 0},
{1, 1},
{2, 2}}},
{1,
{{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1}}},
{2,
{{1, 1},
{2, 2},
{0, 0},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{2, 2},
{2, 2}}},
{1,
{{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1}}},
{1,
{{1, 1},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1}}},
{2,
{{0, 0},
{1, 1},
{2, 2},
{1, 1},
{2, 2},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{2, 2},
{1, 1},
{1, 1}}},
{2,
{{1, 1},
{2, 2},
{1, 1},
{2, 2},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{2, 2},
{2, 2}}},
{2,
{{0, 0},
{0, 0},
{1, 1},
{2, 2},
{1, 1},
{2, 2},
{0, 0},
{0, 0},
{2, 2},
{1, 1},
{2, 2},
{2, 2}}},
{2,
{{1, 1},
{0, 0},
{1, 1},
{2, 2},
{0, 0},
{2, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 2},
{2, 2}}},
{1,
{{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1}}},
{2,
{{1, 1},
{2, 2},
{0, 0},
{0, 0},
{1, 1},
{2, 2},
{0, 0},
{0, 0},
{1, 1},
{2, 2},
{2, 2},
{2, 2}}},
{1,
{{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{1, 1}}},
{1,
{{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1}}},
{1,
{{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1}}},
{2,
{{2, 2},
{1, 1},
{1, 2},
{0, 0},
{0, 0},
{2, 1},
{0, 0},
{0, 0},
{2, 2},
{0, 0},
{1, 1},
{1, 1}}},
{1,
{{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1}}},
{1,
{{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1}}},
{1,
{{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1}}},
{1,
{{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1}}},
{1,
{{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1}}},
{1,
{{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1}}},
{2,
{{1, 1},
{1, 1},
{2, 2},
{1, 1},
{2, 2},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{2, 2},
{0, 0},
{1, 1}}},
{2,
{{0, 0},
{1, 1},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{2, 1},
{0, 0},
{1, 2},
{2, 2},
{0, 0},
{1, 1}}},
{2,
{{1, 1},
{0, 0},
{2, 2},
{1, 1},
{2, 2},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{2, 2},
{0, 0},
{1, 1}}},
{2,
{{0, 0},
{0, 0},
{2, 2},
{1, 1},
{0, 0},
{1, 2},
{2, 1},
{0, 0},
{0, 0},
{2, 2},
{0, 0},
{1, 1}}},
{1,
{{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1}}},
{2,
{{0, 0},
{2, 1},
{0, 0},
{0, 0},
{1, 1},
{2, 2},
{1, 1},
{0, 0},
{1, 1},
{2, 2},
{0, 0},
{1, 2}}},
{1,
{{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1}}},
{1,
{{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1}}},
{2,
{{2, 2},
{1, 2},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{2, 2},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{2, 1}}},
{2,
{{0, 0},
{1, 1},
{2, 2},
{0, 0},
{0, 0},
{1, 1},
{2, 2},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{2, 2}}},
{2,
{{2, 2},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{2, 2},
{0, 0},
{1, 2},
{0, 0},
{0, 0},
{2, 1}}},
{1,
{{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1}}},
{1,
{{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0}}},
{2,
{{1, 1},
{0, 0},
{2, 2},
{2, 2},
{1, 1},
{0, 0},
{2, 2},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{0, 0}}},
{2,
{{0, 0},
{1, 1},
{2, 2},
{2, 2},
{0, 0},
{1, 1},
{2, 2},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{0, 0}}},
{2,
{{1, 1},
{1, 1},
{2, 2},
{2, 2},
{1, 1},
{1, 1},
{2, 2},
{2, 2},
{0, 0},
{0, 0},
{0, 0},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0}}},
{1,
{{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0}}},
{2,
{{0, 0},
{1, 1},
{0, 0},
{2, 2},
{2, 2},
{1, 1},
{2, 2},
{2, 2},
{1, 1},
{2, 2},
{0, 0},
{0, 0}}},
{2,
{{1, 2},
{2, 2},
{0, 0},
{1, 1},
{0, 0},
{2, 2},
{1, 1},
{1, 1},
{0, 0},
{2, 1},
{0, 0},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0}}},
{2,
{{1, 1},
{0, 0},
{2, 2},
{0, 0},
{1, 1},
{2, 2},
{2, 2},
{2, 2},
{1, 1},
{2, 2},
{0, 0},
{0, 0}}},
{1,
{{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0}}},
{2,
{{1, 1},
{1, 1},
{2, 2},
{0, 0},
{1, 1},
{0, 0},
{2, 2},
{1, 2},
{0, 0},
{2, 1},
{0, 0},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0}}},
{1,
{{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0}}},
{1,
{{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0}}},
{1,
{{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0}}},
{1,
{{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0}}},
{2,
{{1, 1},
{2, 2},
{1, 1},
{1, 1},
{0, 0},
{2, 2},
{0, 0},
{1, 1},
{2, 2},
{0, 0},
{1, 1},
{0, 0}}},
{2,
{{0, 0},
{1, 1},
{1, 2},
{2, 2},
{1, 1},
{1, 1},
{0, 0},
{2, 2},
{0, 0},
{0, 0},
{2, 1},
{0, 0}}},
{1,
{{1, 1},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{1, 1},
{0, 0}}},
{2,
{{1, 1},
{2, 2},
{0, 0},
{1, 1},
{1, 1},
{2, 2},
{0, 0},
{1, 1},
{2, 2},
{1, 1},
{1, 1},
{0, 0}}},
{2,
{{0, 0},
{1, 1},
{0, 0},
{2, 2},
{0, 0},
{1, 1},
{0, 0},
{2, 2},
{0, 0},
{1, 2},
{2, 1},
{0, 0}}},
{1,
{{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0}}},
{2,
{{0, 0},
{0, 0},
{2, 1},
{0, 0},
{2, 2},
{1, 1},
{0, 0},
{1, 1},
{2, 2},
{1, 1},
{1, 2},
{0, 0}}},
{2,
{{1, 1},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{2, 1},
{2, 2},
{1, 2},
{1, 1},
{0, 0}}},
{2,
{{0, 0},
{1, 1},
{2, 2},
{0, 0},
{2, 2},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{2, 2},
{1, 1},
{0, 0}}},
{1,
{{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0}}},
{2,
{{1, 1},
{2, 2},
{0, 0},
{0, 0},
{1, 2},
{0, 0},
{0, 0},
{2, 1},
{2, 2},
{0, 0},
{1, 1},
{0, 0}}},
{1,
{{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0}}},
{1,
{{0, 0},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0}}},
{2,
{{1, 1},
{2, 2},
{2, 2},
{2, 2},
{1, 1},
{0, 0},
{2, 2},
{0, 0},
{1, 1},
{0, 0},
{2, 2},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0}}},
{2,
{{2, 2},
{0, 0},
{1, 1},
{1, 1},
{2, 2},
{1, 2},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{2, 1},
{0, 0}}},
{1,
{{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0}}},
{2,
{{1, 1},
{2, 2},
{0, 0},
{1, 2},
{0, 0},
{0, 0},
{2, 1},
{0, 0},
{1, 1},
{1, 1},
{2, 2},
{0, 0}}},
{2,
{{0, 0},
{0, 0},
{0, 0},
{2, 1},
{2, 2},
{1, 1},
{1, 2},
{0, 0},
{1, 1},
{2, 2},
{1, 1},
{0, 0}}},
{2,
{{1, 1},
{0, 0},
{0, 0},
{2, 2},
{0, 0},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{2, 2},
{1, 1},
{0, 0}}},
{1,
{{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0}}},
{2,
{{1, 1},
{2, 2},
{2, 2},
{0, 0},
{1, 1},
{2, 2},
{2, 2},
{0, 0},
{1, 1},
{2, 2},
{2, 2},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{0, 0}}},
{2,
{{1, 1},
{0, 0},
{2, 2},
{0, 0},
{1, 1},
{0, 0},
{2, 2},
{0, 0},
{0, 0},
{2, 1},
{1, 2},
{0, 0}}},
{1,
{{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0}}},
{2,
{{1, 1},
{2, 2},
{0, 0},
{0, 0},
{0, 0},
{1, 2},
{2, 1},
{0, 0},
{1, 1},
{0, 0},
{2, 2},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0}}},
{1,
{{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0}}},
{1,
{{1, 1},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0}}},
{1,
{{0, 0},
{1, 1},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0}}},
{1,
{{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{1, 1},
{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0}}},
{1,
{{1, 1},
{1, 1},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0}}},
{1,
{{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0}}},
{2,
{{1, 2},
{0, 0},
{0, 0},
{2, 1},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{2, 2},
{0, 0},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0}}},
{1,
{{1, 1},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0}}},
{2,
{{0, 0},
{1, 2},
{2, 1},
{0, 0},
{2, 2},
{1, 1},
{0, 0},
{0, 0},
{2, 2},
{1, 1},
{0, 0},
{0, 0}}},
{1,
{{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0}}},
{1,
{{0, 0},
{0, 0},
{1, 1},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0}}},
{1,
{{1, 1},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0}}},
{1,
{{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0}}},
{1,
{{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0},
{1, 1},
{0, 0},
{0, 0},
{0, 0}}},
{0,
{{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0}}}};

View File

@@ -18,10 +18,10 @@
#define __MANIFOLD_TABLE_H__
typedef struct {
int comps;
int pairs[12][2];
int comps;
int pairs[12][2];
} ManifoldIndices;
extern const ManifoldIndices manifold_table[256];
#endif /* __MANIFOLD_TABLE_H__ */
#endif /* __MANIFOLD_TABLE_H__ */

View File

@@ -18,531 +18,2574 @@
/* number of triangles in each configuration */
const int marching_cubes_numtri[TOTCONF] = {
0, 1, 1, 2, 1, 2, 4, 3, 1, 4, 2, 3, 2, 3, 3, 2, 1, 2, 4, 3, 4, 3, 5, 4,
6, 5, 5, 4, 5, 4, 4, 3, 1, 4, 2, 3, 6, 5, 5, 4, 4, 5, 3, 4, 5, 4, 4, 3,
2, 3, 3, 2, 5, 4, 4, 3, 5, 4, 4, 3, 4, 3, 3, 2, 1, 4, 6, 5, 2, 3, 5, 4,
4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 2, 4, 3, 5, 4, 4, 3, 4, 3, 3, 2,
4, 5, 5, 4, 5, 4, 4, 3, 5, 4, 4, 3, 4, 3, 3, 2, 3, 4, 4, 3, 4, 3, 3, 2,
4, 3, 3, 2, 3, 2, 2, 1, 1, 6, 4, 5, 4, 5, 5, 4, 2, 5, 3, 4, 3, 4, 4, 3,
4, 5, 5, 4, 5, 4, 4, 3, 5, 4, 4, 3, 4, 3, 3, 2, 2, 5, 3, 4, 5, 4, 4, 3,
3, 4, 2, 3, 4, 3, 3, 2, 3, 4, 4, 3, 4, 3, 3, 2, 4, 3, 3, 2, 3, 2, 2, 1,
2, 5, 5, 4, 3, 4, 4, 3, 3, 4, 4, 3, 2, 3, 3, 2, 3, 4, 4, 3, 4, 3, 3, 2,
4, 3, 3, 2, 3, 2, 2, 1, 3, 4, 4, 3, 4, 3, 3, 2, 4, 3, 3, 2, 3, 2, 2, 1,
2, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0
};
0, 1, 1, 2, 1, 2, 4, 3, 1, 4, 2, 3, 2, 3, 3, 2, 1, 2, 4, 3, 4, 3, 5, 4, 6, 5, 5, 4, 5,
4, 4, 3, 1, 4, 2, 3, 6, 5, 5, 4, 4, 5, 3, 4, 5, 4, 4, 3, 2, 3, 3, 2, 5, 4, 4, 3, 5, 4,
4, 3, 4, 3, 3, 2, 1, 4, 6, 5, 2, 3, 5, 4, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 2, 4,
3, 5, 4, 4, 3, 4, 3, 3, 2, 4, 5, 5, 4, 5, 4, 4, 3, 5, 4, 4, 3, 4, 3, 3, 2, 3, 4, 4, 3,
4, 3, 3, 2, 4, 3, 3, 2, 3, 2, 2, 1, 1, 6, 4, 5, 4, 5, 5, 4, 2, 5, 3, 4, 3, 4, 4, 3, 4,
5, 5, 4, 5, 4, 4, 3, 5, 4, 4, 3, 4, 3, 3, 2, 2, 5, 3, 4, 5, 4, 4, 3, 3, 4, 2, 3, 4, 3,
3, 2, 3, 4, 4, 3, 4, 3, 3, 2, 4, 3, 3, 2, 3, 2, 2, 1, 2, 5, 5, 4, 3, 4, 4, 3, 3, 4, 4,
3, 2, 3, 3, 2, 3, 4, 4, 3, 4, 3, 3, 2, 4, 3, 3, 2, 3, 2, 2, 1, 3, 4, 4, 3, 4, 3, 3, 2,
4, 3, 3, 2, 3, 2, 2, 1, 2, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
/* table of triangles in each configuration */
const int marching_cubes_tris[TOTCONF][MAX_TRIS][3] = {
{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 0, 8}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 1, 5}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 0, 1}, {4, 1, 5}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 9, 2}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 8, 9}, {0, 9, 2}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{1, 5, 9}, {1, 9, 2}, {1, 2, 4}, {1, 4, 8}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 1, 5}, {0, 5, 9}, {0, 9, 2}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 3, 9}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 8, 5}, {0, 5, 3}, {0, 3, 9}, {0, 9, 4}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 1, 3}, {8, 3, 9}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 0, 1}, {4, 1, 3}, {4, 3, 9}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 5, 3}, {4, 3, 2}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 8, 5}, {0, 5, 3}, {0, 3, 2}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 1}, {4, 1, 3}, {4, 3, 2}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 1, 3}, {0, 3, 2}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 6, 10}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 4, 6}, {8, 6, 10}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 10, 1}, {6, 1, 5}, {6, 5, 8}, {6, 8, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 6, 10}, {4, 10, 1}, {4, 1, 5}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 0, 4}, {10, 4, 9}, {10, 9, 2}, {10, 2, 6}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 10, 8}, {6, 8, 9}, {6, 9, 2}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 0}, {6, 10, 1}, {6, 1, 5}, {6, 5, 9}, {6, 9, 2},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 10, 1}, {6, 1, 5}, {6, 5, 9}, {6, 9, 2}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 0, 5}, {0, 6, 9}, {9, 5, 0}, {6, 10, 3}, {5, 3, 10},
{3, 9, 6}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 8, 5}, {10, 5, 3}, {9, 4, 6}, {6, 10, 3}, {6, 3, 9},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 1, 3}, {9, 8, 0}, {9, 0, 6}, {6, 10, 3}, {6, 3, 9},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 6, 10}, {4, 10, 1}, {4, 1, 3}, {4, 3, 9}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 4, 5}, {3, 2, 6}, {3, 6, 10}, {10, 0, 5}, {10, 5, 3},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 10, 8}, {6, 8, 5}, {6, 5, 3}, {6, 3, 2}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 0}, {6, 10, 1}, {6, 1, 3}, {6, 3, 2}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 10, 1}, {6, 1, 3}, {6, 3, 2}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 7, 1}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 0, 10}, {4, 10, 7}, {4, 7, 1}, {4, 1, 8}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 10, 7}, {8, 7, 5}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 0, 10}, {4, 10, 7}, {4, 7, 5}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 2, 4}, {10, 4, 1}, {7, 2, 10}, {1, 9, 7}, {1, 4, 9},
{9, 2, 7}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{1, 8, 9}, {2, 0, 10}, {2, 10, 7}, {7, 1, 9}, {7, 9, 2},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 10}, {7, 5, 9}, {7, 9, 2}, {2, 4, 10}, {2, 10, 7},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 10, 7}, {0, 7, 5}, {0, 5, 9}, {0, 9, 2}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 7, 3}, {10, 3, 9}, {10, 9, 5}, {10, 5, 1}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 5, 1}, {4, 0, 10}, {4, 10, 7}, {4, 7, 3}, {4, 3, 9},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 10, 7}, {8, 7, 3}, {8, 3, 9}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 0, 10}, {4, 10, 7}, {4, 7, 3}, {4, 3, 9}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 5, 1}, {4, 1, 10}, {7, 3, 2}, {2, 4, 10}, {2, 10, 7},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 5, 1}, {0, 10, 7}, {0, 7, 3}, {0, 3, 2}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 10}, {4, 10, 7}, {4, 7, 3}, {4, 3, 2}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 10, 7}, {0, 7, 3}, {0, 3, 2}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 6, 7}, {0, 7, 1}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 4, 6}, {8, 6, 7}, {8, 7, 1}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 0, 6}, {8, 6, 7}, {8, 7, 5}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 6, 7}, {4, 7, 5}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{1, 0, 4}, {1, 4, 9}, {2, 6, 7}, {7, 1, 9}, {7, 9, 2},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 7, 1}, {6, 1, 8}, {6, 8, 9}, {6, 9, 2}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 0}, {6, 7, 5}, {6, 5, 9}, {6, 9, 2}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 7, 5}, {6, 5, 9}, {6, 9, 2}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 1, 0}, {6, 7, 3}, {6, 3, 9}, {9, 5, 0}, {9, 0, 6},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 5, 1}, {4, 6, 7}, {4, 7, 3}, {4, 3, 9}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 0, 6}, {8, 6, 7}, {8, 7, 3}, {8, 3, 9}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 6, 7}, {4, 7, 3}, {4, 3, 9}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 4, 5}, {0, 5, 1}, {6, 7, 3}, {6, 3, 2}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 5, 1}, {6, 7, 3}, {6, 3, 2}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 0}, {6, 7, 3}, {6, 3, 2}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 7, 3}, {6, 3, 2}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 2, 11}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 4, 2}, {8, 2, 11}, {8, 11, 6}, {8, 6, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 1, 6}, {6, 1, 11}, {11, 1, 5}, {2, 11, 5}, {2, 5, 8},
{6, 2, 8}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 0, 1}, {5, 4, 2}, {5, 2, 11}, {11, 6, 1}, {11, 1, 5},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 4, 9}, {6, 9, 11}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 0, 8}, {6, 8, 9}, {6, 9, 11}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 4, 8}, {6, 8, 1}, {5, 9, 11}, {11, 6, 1}, {11, 1, 5},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 0, 1}, {6, 1, 5}, {6, 5, 9}, {6, 9, 11}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 2, 9}, {6, 9, 5}, {6, 5, 3}, {6, 3, 11}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 2, 9}, {6, 0, 8}, {6, 8, 5}, {6, 5, 3}, {6, 3, 11},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{2, 9, 8}, {1, 3, 11}, {1, 11, 6}, {6, 2, 8}, {6, 8, 1},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 2, 9}, {6, 0, 1}, {6, 1, 3}, {6, 3, 11}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 4, 5}, {6, 5, 3}, {6, 3, 11}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 0, 8}, {6, 8, 5}, {6, 5, 3}, {6, 3, 11}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 4, 8}, {6, 8, 1}, {6, 1, 3}, {6, 3, 11}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 0, 1}, {6, 1, 3}, {6, 3, 11}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 0, 2}, {10, 2, 11}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 8, 4}, {10, 4, 2}, {10, 2, 11}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 0, 2}, {11, 10, 1}, {11, 1, 5}, {5, 8, 2}, {5, 2, 11},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 1, 5}, {10, 5, 4}, {10, 4, 2}, {10, 2, 11}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 0, 4}, {10, 4, 9}, {10, 9, 11}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 8, 9}, {10, 9, 11}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 0}, {10, 1, 5}, {10, 5, 9}, {10, 9, 11}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 1, 5}, {10, 5, 9}, {10, 9, 11}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 2, 9}, {0, 9, 5}, {3, 11, 10}, {10, 0, 5}, {10, 5, 3},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 2, 9}, {10, 8, 5}, {10, 5, 3}, {10, 3, 11}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 0, 2}, {8, 2, 9}, {10, 1, 3}, {10, 3, 11}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 2, 9}, {10, 1, 3}, {10, 3, 11}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 0, 4}, {10, 4, 5}, {10, 5, 3}, {10, 3, 11}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 8, 5}, {10, 5, 3}, {10, 3, 11}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 0}, {10, 1, 3}, {10, 3, 11}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 1, 3}, {10, 3, 11}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{1, 10, 6}, {1, 6, 2}, {1, 2, 11}, {1, 11, 7}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 10, 6}, {7, 1, 8}, {7, 8, 4}, {7, 4, 2}, {7, 2, 11},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 10, 6}, {8, 6, 2}, {11, 7, 5}, {5, 8, 2}, {5, 2, 11},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 10, 6}, {7, 5, 4}, {7, 4, 2}, {7, 2, 11}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 6, 4}, {9, 11, 7}, {9, 7, 1}, {1, 10, 4}, {1, 4, 9},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 10, 6}, {7, 1, 8}, {7, 8, 9}, {7, 9, 11}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 10}, {4, 10, 6}, {7, 5, 9}, {7, 9, 11}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 10, 6}, {7, 5, 9}, {7, 9, 11}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 1, 10}, {5, 10, 6}, {5, 6, 2}, {5, 2, 9}, {7, 3, 11},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 10, 6}, {8, 5, 1}, {4, 2, 9}, {7, 3, 11}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 10, 6}, {8, 6, 2}, {8, 2, 9}, {7, 3, 11}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 10, 6}, {4, 2, 9}, {7, 3, 11}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 6, 4}, {10, 4, 5}, {10, 5, 1}, {7, 3, 11}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 10, 6}, {8, 5, 1}, {7, 3, 11}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 10}, {4, 10, 6}, {7, 3, 11}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 10, 6}, {7, 3, 11}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{7, 1, 0}, {7, 0, 2}, {7, 2, 11}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{7, 1, 8}, {7, 8, 4}, {7, 4, 2}, {7, 2, 11}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{7, 5, 8}, {7, 8, 0}, {7, 0, 2}, {7, 2, 11}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{7, 5, 4}, {7, 4, 2}, {7, 2, 11}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{7, 1, 0}, {7, 0, 4}, {7, 4, 9}, {7, 9, 11}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{7, 1, 8}, {7, 8, 9}, {7, 9, 11}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 0}, {7, 5, 9}, {7, 9, 11}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{7, 5, 9}, {7, 9, 11}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 1, 0}, {5, 0, 2}, {5, 2, 9}, {7, 3, 11}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 5, 1}, {4, 2, 9}, {7, 3, 11}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 0, 2}, {8, 2, 9}, {7, 3, 11}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 2, 9}, {7, 3, 11}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 4, 5}, {0, 5, 1}, {7, 3, 11}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 5, 1}, {7, 3, 11}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 0}, {7, 3, 11}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{7, 3, 11}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{7, 11, 3}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{7, 11, 0}, {7, 0, 8}, {0, 11, 4}, {8, 3, 7}, {11, 3, 4},
{3, 8, 4}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 1, 7}, {8, 7, 11}, {8, 11, 3}, {8, 3, 5}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 1, 7}, {0, 7, 11}, {3, 5, 4}, {4, 0, 11}, {4, 11, 3},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 9, 3}, {4, 3, 7}, {4, 7, 11}, {4, 11, 2}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 9, 3}, {8, 3, 7}, {11, 2, 0}, {0, 8, 7}, {0, 7, 11},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 9, 3}, {4, 8, 1}, {4, 1, 7}, {4, 7, 11}, {4, 11, 2},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 9, 3}, {0, 1, 7}, {0, 7, 11}, {0, 11, 2}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 7, 11}, {5, 11, 9}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 5, 7}, {11, 9, 4}, {11, 4, 0}, {0, 8, 7}, {0, 7, 11},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 1, 7}, {8, 7, 11}, {8, 11, 9}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 0, 1}, {4, 1, 7}, {4, 7, 11}, {4, 11, 9}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 5, 7}, {4, 7, 11}, {4, 11, 2}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 8, 5}, {0, 5, 7}, {0, 7, 11}, {0, 11, 2}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 1}, {4, 1, 7}, {4, 7, 11}, {4, 11, 2}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 1, 7}, {0, 7, 11}, {0, 11, 2}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 6, 11}, {0, 11, 3}, {0, 3, 7}, {0, 7, 10}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{7, 10, 8}, {4, 6, 11}, {4, 11, 3}, {3, 7, 8}, {3, 8, 4},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 1, 7}, {5, 8, 0}, {5, 0, 6}, {5, 6, 11}, {5, 11, 3},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 1, 7}, {5, 4, 6}, {5, 6, 11}, {5, 11, 3}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{7, 10, 0}, {7, 0, 4}, {7, 4, 9}, {7, 9, 3}, {6, 11, 2},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{7, 10, 8}, {7, 8, 9}, {7, 9, 3}, {6, 11, 2}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 0}, {10, 1, 7}, {5, 9, 3}, {6, 11, 2}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 1, 7}, {5, 9, 3}, {6, 11, 2}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 7, 10}, {5, 10, 0}, {6, 11, 9}, {9, 5, 0}, {9, 0, 6},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 8, 5}, {10, 5, 7}, {4, 6, 11}, {4, 11, 9}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 1, 7}, {8, 0, 6}, {8, 6, 11}, {8, 11, 9}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 1, 7}, {4, 6, 11}, {4, 11, 9}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 0, 4}, {10, 4, 5}, {10, 5, 7}, {6, 11, 2}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 8, 5}, {10, 5, 7}, {6, 11, 2}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 0}, {10, 1, 7}, {6, 11, 2}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 1, 7}, {6, 11, 2}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{1, 10, 11}, {1, 11, 3}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 10, 11}, {3, 1, 8}, {3, 8, 4}, {4, 0, 11}, {4, 11, 3},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 8, 10}, {5, 10, 11}, {5, 11, 3}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 4, 0}, {5, 0, 10}, {5, 10, 11}, {5, 11, 3}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{9, 3, 1}, {10, 11, 2}, {10, 2, 4}, {4, 9, 1}, {4, 1, 10},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{1, 8, 9}, {1, 9, 3}, {0, 10, 11}, {0, 11, 2}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 9, 3}, {4, 8, 10}, {4, 10, 11}, {4, 11, 2}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 9, 3}, {0, 10, 11}, {0, 11, 2}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 1, 10}, {5, 10, 11}, {5, 11, 9}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 5, 1}, {4, 0, 10}, {4, 10, 11}, {4, 11, 9}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 10, 11}, {8, 11, 9}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 0, 10}, {4, 10, 11}, {4, 11, 9}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 5, 1}, {4, 1, 10}, {4, 10, 11}, {4, 11, 2}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 5, 1}, {0, 10, 11}, {0, 11, 2}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 10}, {4, 10, 11}, {4, 11, 2}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 10, 11}, {0, 11, 2}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{1, 0, 6}, {1, 6, 11}, {1, 11, 3}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{1, 8, 4}, {1, 4, 6}, {1, 6, 11}, {1, 11, 3}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 8, 0}, {5, 0, 6}, {5, 6, 11}, {5, 11, 3}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 4, 6}, {5, 6, 11}, {5, 11, 3}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{1, 0, 4}, {1, 4, 9}, {1, 9, 3}, {6, 11, 2}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{1, 8, 9}, {1, 9, 3}, {6, 11, 2}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 0}, {5, 9, 3}, {6, 11, 2}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 9, 3}, {6, 11, 2}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 1, 0}, {5, 0, 6}, {5, 6, 11}, {5, 11, 9}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 5, 1}, {4, 6, 11}, {4, 11, 9}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 0, 6}, {8, 6, 11}, {8, 11, 9}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 6, 11}, {4, 11, 9}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 4, 5}, {0, 5, 1}, {6, 11, 2}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 5, 1}, {6, 11, 2}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 0}, {6, 11, 2}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 11, 2}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{7, 6, 2}, {7, 2, 3}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{7, 6, 0}, {7, 0, 8}, {4, 2, 3}, {3, 7, 8}, {3, 8, 4},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{1, 7, 6}, {2, 3, 5}, {2, 5, 8}, {8, 1, 6}, {8, 6, 2},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 0, 1}, {6, 1, 7}, {5, 4, 2}, {5, 2, 3}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{7, 6, 4}, {7, 4, 9}, {7, 9, 3}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{7, 6, 0}, {7, 0, 8}, {7, 8, 9}, {7, 9, 3}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 4, 8}, {6, 8, 1}, {6, 1, 7}, {5, 9, 3}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 0, 1}, {6, 1, 7}, {5, 9, 3}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 7, 6}, {5, 6, 2}, {5, 2, 9}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 0, 8}, {6, 8, 5}, {6, 5, 7}, {4, 2, 9}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 1, 7}, {8, 7, 6}, {8, 6, 2}, {8, 2, 9}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 0, 1}, {6, 1, 7}, {4, 2, 9}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 4, 5}, {6, 5, 7}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 0, 8}, {6, 8, 5}, {6, 5, 7}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 4, 8}, {6, 8, 1}, {6, 1, 7}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{6, 0, 1}, {6, 1, 7}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{7, 10, 0}, {7, 0, 2}, {7, 2, 3}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{7, 10, 8}, {7, 8, 4}, {7, 4, 2}, {7, 2, 3}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 1, 7}, {5, 8, 0}, {5, 0, 2}, {5, 2, 3}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 1, 7}, {5, 4, 2}, {5, 2, 3}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{7, 10, 0}, {7, 0, 4}, {7, 4, 9}, {7, 9, 3}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{7, 10, 8}, {7, 8, 9}, {7, 9, 3}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 0}, {10, 1, 7}, {5, 9, 3}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 1, 7}, {5, 9, 3}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 7, 10}, {5, 10, 0}, {5, 0, 2}, {5, 2, 9}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 8, 5}, {10, 5, 7}, {4, 2, 9}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 1, 7}, {8, 0, 2}, {8, 2, 9}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 1, 7}, {4, 2, 9}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 0, 4}, {10, 4, 5}, {10, 5, 7}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 8, 5}, {10, 5, 7}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 0}, {10, 1, 7}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 1, 7}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{1, 10, 6}, {1, 6, 2}, {1, 2, 3}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 10, 6}, {1, 8, 4}, {1, 4, 2}, {1, 2, 3}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 8, 10}, {5, 10, 6}, {5, 6, 2}, {5, 2, 3}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 10, 6}, {5, 4, 2}, {5, 2, 3}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{1, 10, 6}, {1, 6, 4}, {1, 4, 9}, {1, 9, 3}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 10, 6}, {1, 8, 9}, {1, 9, 3}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 10}, {4, 10, 6}, {5, 9, 3}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 10, 6}, {5, 9, 3}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 1, 10}, {5, 10, 6}, {5, 6, 2}, {5, 2, 9}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 10, 6}, {8, 5, 1}, {4, 2, 9}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 10, 6}, {8, 6, 2}, {8, 2, 9}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 10, 6}, {4, 2, 9}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{10, 6, 4}, {10, 4, 5}, {10, 5, 1}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 10, 6}, {8, 5, 1}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 10}, {4, 10, 6}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 10, 6}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{1, 0, 2}, {1, 2, 3}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{1, 8, 4}, {1, 4, 2}, {1, 2, 3}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 8, 0}, {5, 0, 2}, {5, 2, 3}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 4, 2}, {5, 2, 3}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{1, 0, 4}, {1, 4, 9}, {1, 9, 3}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{1, 8, 9}, {1, 9, 3}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 0}, {5, 9, 3}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 9, 3}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{5, 1, 0}, {5, 0, 2}, {5, 2, 9}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 5, 1}, {4, 2, 9}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 0, 2}, {8, 2, 9}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 2, 9}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 4, 5}, {0, 5, 1}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{8, 5, 1}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{4, 8, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}},
{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}
};
const int marching_cubes_tris[TOTCONF][MAX_TRIS][3] = {{{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 0, 8},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 1, 5},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 0, 1},
{4, 1, 5},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 9, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 8, 9},
{0, 9, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{1, 5, 9},
{1, 9, 2},
{1, 2, 4},
{1, 4, 8},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 1, 5},
{0, 5, 9},
{0, 9, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 3, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 8, 5},
{0, 5, 3},
{0, 3, 9},
{0, 9, 4},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 1, 3},
{8, 3, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 0, 1},
{4, 1, 3},
{4, 3, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 5, 3},
{4, 3, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 8, 5},
{0, 5, 3},
{0, 3, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 1},
{4, 1, 3},
{4, 3, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 1, 3},
{0, 3, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 6, 10},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 4, 6},
{8, 6, 10},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 10, 1},
{6, 1, 5},
{6, 5, 8},
{6, 8, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 6, 10},
{4, 10, 1},
{4, 1, 5},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 0, 4},
{10, 4, 9},
{10, 9, 2},
{10, 2, 6},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 10, 8},
{6, 8, 9},
{6, 9, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 0},
{6, 10, 1},
{6, 1, 5},
{6, 5, 9},
{6, 9, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 10, 1},
{6, 1, 5},
{6, 5, 9},
{6, 9, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 0, 5},
{0, 6, 9},
{9, 5, 0},
{6, 10, 3},
{5, 3, 10},
{3, 9, 6},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 8, 5},
{10, 5, 3},
{9, 4, 6},
{6, 10, 3},
{6, 3, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 1, 3},
{9, 8, 0},
{9, 0, 6},
{6, 10, 3},
{6, 3, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 6, 10},
{4, 10, 1},
{4, 1, 3},
{4, 3, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 4, 5},
{3, 2, 6},
{3, 6, 10},
{10, 0, 5},
{10, 5, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 10, 8},
{6, 8, 5},
{6, 5, 3},
{6, 3, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 0},
{6, 10, 1},
{6, 1, 3},
{6, 3, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 10, 1},
{6, 1, 3},
{6, 3, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 7, 1},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 0, 10},
{4, 10, 7},
{4, 7, 1},
{4, 1, 8},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 10, 7},
{8, 7, 5},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 0, 10},
{4, 10, 7},
{4, 7, 5},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 2, 4},
{10, 4, 1},
{7, 2, 10},
{1, 9, 7},
{1, 4, 9},
{9, 2, 7},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{1, 8, 9},
{2, 0, 10},
{2, 10, 7},
{7, 1, 9},
{7, 9, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 10},
{7, 5, 9},
{7, 9, 2},
{2, 4, 10},
{2, 10, 7},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 10, 7},
{0, 7, 5},
{0, 5, 9},
{0, 9, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 7, 3},
{10, 3, 9},
{10, 9, 5},
{10, 5, 1},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 5, 1},
{4, 0, 10},
{4, 10, 7},
{4, 7, 3},
{4, 3, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 10, 7},
{8, 7, 3},
{8, 3, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 0, 10},
{4, 10, 7},
{4, 7, 3},
{4, 3, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 5, 1},
{4, 1, 10},
{7, 3, 2},
{2, 4, 10},
{2, 10, 7},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 5, 1},
{0, 10, 7},
{0, 7, 3},
{0, 3, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 10},
{4, 10, 7},
{4, 7, 3},
{4, 3, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 10, 7},
{0, 7, 3},
{0, 3, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 6, 7},
{0, 7, 1},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 4, 6},
{8, 6, 7},
{8, 7, 1},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 0, 6},
{8, 6, 7},
{8, 7, 5},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 6, 7},
{4, 7, 5},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{1, 0, 4},
{1, 4, 9},
{2, 6, 7},
{7, 1, 9},
{7, 9, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 7, 1},
{6, 1, 8},
{6, 8, 9},
{6, 9, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 0},
{6, 7, 5},
{6, 5, 9},
{6, 9, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 7, 5},
{6, 5, 9},
{6, 9, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 1, 0},
{6, 7, 3},
{6, 3, 9},
{9, 5, 0},
{9, 0, 6},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 5, 1},
{4, 6, 7},
{4, 7, 3},
{4, 3, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 0, 6},
{8, 6, 7},
{8, 7, 3},
{8, 3, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 6, 7},
{4, 7, 3},
{4, 3, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 4, 5},
{0, 5, 1},
{6, 7, 3},
{6, 3, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 5, 1},
{6, 7, 3},
{6, 3, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 0},
{6, 7, 3},
{6, 3, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 7, 3},
{6, 3, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 2, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 4, 2},
{8, 2, 11},
{8, 11, 6},
{8, 6, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 1, 6},
{6, 1, 11},
{11, 1, 5},
{2, 11, 5},
{2, 5, 8},
{6, 2, 8},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 0, 1},
{5, 4, 2},
{5, 2, 11},
{11, 6, 1},
{11, 1, 5},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 4, 9},
{6, 9, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 0, 8},
{6, 8, 9},
{6, 9, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 4, 8},
{6, 8, 1},
{5, 9, 11},
{11, 6, 1},
{11, 1, 5},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 0, 1},
{6, 1, 5},
{6, 5, 9},
{6, 9, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 2, 9},
{6, 9, 5},
{6, 5, 3},
{6, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 2, 9},
{6, 0, 8},
{6, 8, 5},
{6, 5, 3},
{6, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{2, 9, 8},
{1, 3, 11},
{1, 11, 6},
{6, 2, 8},
{6, 8, 1},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 2, 9},
{6, 0, 1},
{6, 1, 3},
{6, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 4, 5},
{6, 5, 3},
{6, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 0, 8},
{6, 8, 5},
{6, 5, 3},
{6, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 4, 8},
{6, 8, 1},
{6, 1, 3},
{6, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 0, 1},
{6, 1, 3},
{6, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 0, 2},
{10, 2, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 8, 4},
{10, 4, 2},
{10, 2, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 0, 2},
{11, 10, 1},
{11, 1, 5},
{5, 8, 2},
{5, 2, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 1, 5},
{10, 5, 4},
{10, 4, 2},
{10, 2, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 0, 4},
{10, 4, 9},
{10, 9, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 8, 9},
{10, 9, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 0},
{10, 1, 5},
{10, 5, 9},
{10, 9, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 1, 5},
{10, 5, 9},
{10, 9, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 2, 9},
{0, 9, 5},
{3, 11, 10},
{10, 0, 5},
{10, 5, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 2, 9},
{10, 8, 5},
{10, 5, 3},
{10, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 0, 2},
{8, 2, 9},
{10, 1, 3},
{10, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 2, 9},
{10, 1, 3},
{10, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 0, 4},
{10, 4, 5},
{10, 5, 3},
{10, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 8, 5},
{10, 5, 3},
{10, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 0},
{10, 1, 3},
{10, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 1, 3},
{10, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{1, 10, 6},
{1, 6, 2},
{1, 2, 11},
{1, 11, 7},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 10, 6},
{7, 1, 8},
{7, 8, 4},
{7, 4, 2},
{7, 2, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 10, 6},
{8, 6, 2},
{11, 7, 5},
{5, 8, 2},
{5, 2, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 10, 6},
{7, 5, 4},
{7, 4, 2},
{7, 2, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 6, 4},
{9, 11, 7},
{9, 7, 1},
{1, 10, 4},
{1, 4, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 10, 6},
{7, 1, 8},
{7, 8, 9},
{7, 9, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 10},
{4, 10, 6},
{7, 5, 9},
{7, 9, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 10, 6},
{7, 5, 9},
{7, 9, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 1, 10},
{5, 10, 6},
{5, 6, 2},
{5, 2, 9},
{7, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 10, 6},
{8, 5, 1},
{4, 2, 9},
{7, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 10, 6},
{8, 6, 2},
{8, 2, 9},
{7, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 10, 6},
{4, 2, 9},
{7, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 6, 4},
{10, 4, 5},
{10, 5, 1},
{7, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 10, 6},
{8, 5, 1},
{7, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 10},
{4, 10, 6},
{7, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 10, 6},
{7, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{7, 1, 0},
{7, 0, 2},
{7, 2, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{7, 1, 8},
{7, 8, 4},
{7, 4, 2},
{7, 2, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{7, 5, 8},
{7, 8, 0},
{7, 0, 2},
{7, 2, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{7, 5, 4},
{7, 4, 2},
{7, 2, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{7, 1, 0},
{7, 0, 4},
{7, 4, 9},
{7, 9, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{7, 1, 8},
{7, 8, 9},
{7, 9, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 0},
{7, 5, 9},
{7, 9, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{7, 5, 9},
{7, 9, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 1, 0},
{5, 0, 2},
{5, 2, 9},
{7, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 5, 1},
{4, 2, 9},
{7, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 0, 2},
{8, 2, 9},
{7, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 2, 9},
{7, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 4, 5},
{0, 5, 1},
{7, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 5, 1},
{7, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 0},
{7, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{7, 3, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{7, 11, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{7, 11, 0},
{7, 0, 8},
{0, 11, 4},
{8, 3, 7},
{11, 3, 4},
{3, 8, 4},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 1, 7},
{8, 7, 11},
{8, 11, 3},
{8, 3, 5},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 1, 7},
{0, 7, 11},
{3, 5, 4},
{4, 0, 11},
{4, 11, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 9, 3},
{4, 3, 7},
{4, 7, 11},
{4, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 9, 3},
{8, 3, 7},
{11, 2, 0},
{0, 8, 7},
{0, 7, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 9, 3},
{4, 8, 1},
{4, 1, 7},
{4, 7, 11},
{4, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 9, 3},
{0, 1, 7},
{0, 7, 11},
{0, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 7, 11},
{5, 11, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 5, 7},
{11, 9, 4},
{11, 4, 0},
{0, 8, 7},
{0, 7, 11},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 1, 7},
{8, 7, 11},
{8, 11, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 0, 1},
{4, 1, 7},
{4, 7, 11},
{4, 11, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 5, 7},
{4, 7, 11},
{4, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 8, 5},
{0, 5, 7},
{0, 7, 11},
{0, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 1},
{4, 1, 7},
{4, 7, 11},
{4, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 1, 7},
{0, 7, 11},
{0, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 6, 11},
{0, 11, 3},
{0, 3, 7},
{0, 7, 10},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{7, 10, 8},
{4, 6, 11},
{4, 11, 3},
{3, 7, 8},
{3, 8, 4},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 1, 7},
{5, 8, 0},
{5, 0, 6},
{5, 6, 11},
{5, 11, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 1, 7},
{5, 4, 6},
{5, 6, 11},
{5, 11, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{7, 10, 0},
{7, 0, 4},
{7, 4, 9},
{7, 9, 3},
{6, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{7, 10, 8},
{7, 8, 9},
{7, 9, 3},
{6, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 0},
{10, 1, 7},
{5, 9, 3},
{6, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 1, 7},
{5, 9, 3},
{6, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 7, 10},
{5, 10, 0},
{6, 11, 9},
{9, 5, 0},
{9, 0, 6},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 8, 5},
{10, 5, 7},
{4, 6, 11},
{4, 11, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 1, 7},
{8, 0, 6},
{8, 6, 11},
{8, 11, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 1, 7},
{4, 6, 11},
{4, 11, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 0, 4},
{10, 4, 5},
{10, 5, 7},
{6, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 8, 5},
{10, 5, 7},
{6, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 0},
{10, 1, 7},
{6, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 1, 7},
{6, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{1, 10, 11},
{1, 11, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 10, 11},
{3, 1, 8},
{3, 8, 4},
{4, 0, 11},
{4, 11, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 8, 10},
{5, 10, 11},
{5, 11, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 4, 0},
{5, 0, 10},
{5, 10, 11},
{5, 11, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{9, 3, 1},
{10, 11, 2},
{10, 2, 4},
{4, 9, 1},
{4, 1, 10},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{1, 8, 9},
{1, 9, 3},
{0, 10, 11},
{0, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 9, 3},
{4, 8, 10},
{4, 10, 11},
{4, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 9, 3},
{0, 10, 11},
{0, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 1, 10},
{5, 10, 11},
{5, 11, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 5, 1},
{4, 0, 10},
{4, 10, 11},
{4, 11, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 10, 11},
{8, 11, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 0, 10},
{4, 10, 11},
{4, 11, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 5, 1},
{4, 1, 10},
{4, 10, 11},
{4, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 5, 1},
{0, 10, 11},
{0, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 10},
{4, 10, 11},
{4, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 10, 11},
{0, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{1, 0, 6},
{1, 6, 11},
{1, 11, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{1, 8, 4},
{1, 4, 6},
{1, 6, 11},
{1, 11, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 8, 0},
{5, 0, 6},
{5, 6, 11},
{5, 11, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 4, 6},
{5, 6, 11},
{5, 11, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{1, 0, 4},
{1, 4, 9},
{1, 9, 3},
{6, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{1, 8, 9},
{1, 9, 3},
{6, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 0},
{5, 9, 3},
{6, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 9, 3},
{6, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 1, 0},
{5, 0, 6},
{5, 6, 11},
{5, 11, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 5, 1},
{4, 6, 11},
{4, 11, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 0, 6},
{8, 6, 11},
{8, 11, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 6, 11},
{4, 11, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 4, 5},
{0, 5, 1},
{6, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 5, 1},
{6, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 0},
{6, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 11, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{7, 6, 2},
{7, 2, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{7, 6, 0},
{7, 0, 8},
{4, 2, 3},
{3, 7, 8},
{3, 8, 4},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{1, 7, 6},
{2, 3, 5},
{2, 5, 8},
{8, 1, 6},
{8, 6, 2},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 0, 1},
{6, 1, 7},
{5, 4, 2},
{5, 2, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{7, 6, 4},
{7, 4, 9},
{7, 9, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{7, 6, 0},
{7, 0, 8},
{7, 8, 9},
{7, 9, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 4, 8},
{6, 8, 1},
{6, 1, 7},
{5, 9, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 0, 1},
{6, 1, 7},
{5, 9, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 7, 6},
{5, 6, 2},
{5, 2, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 0, 8},
{6, 8, 5},
{6, 5, 7},
{4, 2, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 1, 7},
{8, 7, 6},
{8, 6, 2},
{8, 2, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 0, 1},
{6, 1, 7},
{4, 2, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 4, 5},
{6, 5, 7},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 0, 8},
{6, 8, 5},
{6, 5, 7},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 4, 8},
{6, 8, 1},
{6, 1, 7},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{6, 0, 1},
{6, 1, 7},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{7, 10, 0},
{7, 0, 2},
{7, 2, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{7, 10, 8},
{7, 8, 4},
{7, 4, 2},
{7, 2, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 1, 7},
{5, 8, 0},
{5, 0, 2},
{5, 2, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 1, 7},
{5, 4, 2},
{5, 2, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{7, 10, 0},
{7, 0, 4},
{7, 4, 9},
{7, 9, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{7, 10, 8},
{7, 8, 9},
{7, 9, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 0},
{10, 1, 7},
{5, 9, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 1, 7},
{5, 9, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 7, 10},
{5, 10, 0},
{5, 0, 2},
{5, 2, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 8, 5},
{10, 5, 7},
{4, 2, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 1, 7},
{8, 0, 2},
{8, 2, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 1, 7},
{4, 2, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 0, 4},
{10, 4, 5},
{10, 5, 7},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 8, 5},
{10, 5, 7},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 0},
{10, 1, 7},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 1, 7},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{1, 10, 6},
{1, 6, 2},
{1, 2, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 10, 6},
{1, 8, 4},
{1, 4, 2},
{1, 2, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 8, 10},
{5, 10, 6},
{5, 6, 2},
{5, 2, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 10, 6},
{5, 4, 2},
{5, 2, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{1, 10, 6},
{1, 6, 4},
{1, 4, 9},
{1, 9, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 10, 6},
{1, 8, 9},
{1, 9, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 10},
{4, 10, 6},
{5, 9, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 10, 6},
{5, 9, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 1, 10},
{5, 10, 6},
{5, 6, 2},
{5, 2, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 10, 6},
{8, 5, 1},
{4, 2, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 10, 6},
{8, 6, 2},
{8, 2, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 10, 6},
{4, 2, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{10, 6, 4},
{10, 4, 5},
{10, 5, 1},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 10, 6},
{8, 5, 1},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 10},
{4, 10, 6},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 10, 6},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{1, 0, 2},
{1, 2, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{1, 8, 4},
{1, 4, 2},
{1, 2, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 8, 0},
{5, 0, 2},
{5, 2, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 4, 2},
{5, 2, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{1, 0, 4},
{1, 4, 9},
{1, 9, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{1, 8, 9},
{1, 9, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 0},
{5, 9, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 9, 3},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{5, 1, 0},
{5, 0, 2},
{5, 2, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 5, 1},
{4, 2, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 0, 2},
{8, 2, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 2, 9},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 4, 5},
{0, 5, 1},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{8, 5, 1},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{4, 8, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}},
{{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}}};

View File

@@ -34,2063 +34,2085 @@
#if DC_DEBUG
/* enable debug printfs */
#define dc_printf printf
# define dc_printf printf
#else
/* disable debug printfs */
#define dc_printf(...) do {} while (0)
# define dc_printf(...) \
do { \
} while (0)
#endif
Octree::Octree(ModelReader *mr,
DualConAllocOutput alloc_output_func,
DualConAddVert add_vert_func,
DualConAddQuad add_quad_func,
DualConFlags flags, DualConMode dualcon_mode, int depth,
float threshold, float sharpness)
: use_flood_fill(flags & DUALCON_FLOOD_FILL),
/* note on `use_manifold':
DualConFlags flags,
DualConMode dualcon_mode,
int depth,
float threshold,
float sharpness)
: use_flood_fill(flags & DUALCON_FLOOD_FILL),
/* note on `use_manifold':
After playing around with this option, the only case I could
find where this option gives different results is on
relatively thin corners. Sometimes along these corners two
vertices from separate sides will be placed in the same
position, so hole gets filled with a 5-sided face, where two
of those vertices are in the same 3D location. If
`use_manifold' is disabled, then the modifier doesn't
generate two separate vertices so the results end up as all
quads.
After playing around with this option, the only case I could
find where this option gives different results is on
relatively thin corners. Sometimes along these corners two
vertices from separate sides will be placed in the same
position, so hole gets filled with a 5-sided face, where two
of those vertices are in the same 3D location. If
`use_manifold' is disabled, then the modifier doesn't
generate two separate vertices so the results end up as all
quads.
Since the results are just as good with all quads, there
doesn't seem any reason to allow this to be toggled in
Blender. -nicholasbishop
*/
use_manifold(false),
hermite_num(sharpness),
mode(dualcon_mode),
alloc_output(alloc_output_func),
add_vert(add_vert_func),
add_quad(add_quad_func)
Since the results are just as good with all quads, there
doesn't seem any reason to allow this to be toggled in
Blender. -nicholasbishop
*/
use_manifold(false),
hermite_num(sharpness),
mode(dualcon_mode),
alloc_output(alloc_output_func),
add_vert(add_vert_func),
add_quad(add_quad_func)
{
thresh = threshold;
reader = mr;
dimen = 1 << GRID_DIMENSION;
range = reader->getBoundingBox(origin);
nodeCount = nodeSpace = 0;
maxDepth = depth;
mindimen = (dimen >> maxDepth);
minshift = (GRID_DIMENSION - maxDepth);
buildTable();
thresh = threshold;
reader = mr;
dimen = 1 << GRID_DIMENSION;
range = reader->getBoundingBox(origin);
nodeCount = nodeSpace = 0;
maxDepth = depth;
mindimen = (dimen >> maxDepth);
minshift = (GRID_DIMENSION - maxDepth);
buildTable();
maxTrianglePerCell = 0;
maxTrianglePerCell = 0;
// Initialize memory
// Initialize memory
#ifdef IN_VERBOSE_MODE
dc_printf("Range: %f origin: %f, %f,%f \n", range, origin[0], origin[1], origin[2]);
dc_printf("Initialize memory...\n");
dc_printf("Range: %f origin: %f, %f,%f \n", range, origin[0], origin[1], origin[2]);
dc_printf("Initialize memory...\n");
#endif
initMemory();
root = (Node *)createInternal(0);
initMemory();
root = (Node *)createInternal(0);
// Read MC table
// Read MC table
#ifdef IN_VERBOSE_MODE
dc_printf("Reading contour table...\n");
dc_printf("Reading contour table...\n");
#endif
cubes = new Cubes();
cubes = new Cubes();
}
Octree::~Octree()
{
delete cubes;
freeMemory();
delete cubes;
freeMemory();
}
void Octree::scanConvert()
{
// Scan triangles
// Scan triangles
#if DC_DEBUG
clock_t start, finish;
start = clock();
clock_t start, finish;
start = clock();
#endif
addAllTriangles();
resetMinimalEdges();
preparePrimalEdgesMask(&root->internal);
addAllTriangles();
resetMinimalEdges();
preparePrimalEdgesMask(&root->internal);
#if DC_DEBUG
finish = clock();
dc_printf("Time taken: %f seconds \n",
(double)(finish - start) / CLOCKS_PER_SEC);
finish = clock();
dc_printf("Time taken: %f seconds \n",
(double)(finish - start) / CLOCKS_PER_SEC);
#endif
// Generate signs
// Find holes
// Generate signs
// Find holes
#if DC_DEBUG
dc_printf("Patching...\n");
start = clock();
dc_printf("Patching...\n");
start = clock();
#endif
trace();
trace();
#if DC_DEBUG
finish = clock();
dc_printf("Time taken: %f seconds \n", (double)(finish - start) / CLOCKS_PER_SEC);
finish = clock();
dc_printf("Time taken: %f seconds \n", (double)(finish - start) / CLOCKS_PER_SEC);
# ifdef IN_VERBOSE_MODE
dc_printf("Holes: %d Average Length: %f Max Length: %d \n",
numRings,
(float)totRingLengths / (float)numRings,
maxRingLength);
# endif
#endif
// Check again
int tnumRings = numRings;
trace();
#ifdef IN_VERBOSE_MODE
dc_printf("Holes: %d Average Length: %f Max Length: %d \n", numRings, (float)totRingLengths / (float) numRings, maxRingLength);
dc_printf("Holes after patching: %d \n", numRings);
#endif
numRings = tnumRings;
#if DC_DEBUG
dc_printf("Building signs...\n");
start = clock();
#endif
buildSigns();
#if DC_DEBUG
finish = clock();
dc_printf("Time taken: %f seconds \n", (double)(finish - start) / CLOCKS_PER_SEC);
#endif
// Check again
int tnumRings = numRings;
trace();
if (use_flood_fill) {
/*
start = clock();
floodFill();
// Check again
tnumRings = numRings;
trace();
dc_printf("Holes after filling: %d \n", numRings);
numRings = tnumRings;
buildSigns();
finish = clock();
dc_printf("Time taken: %f seconds \n", (double)(finish - start) / CLOCKS_PER_SEC);
*/
#if DC_DEBUG
start = clock();
dc_printf("Removing components...\n");
#endif
floodFill();
buildSigns();
// dc_printf("Checking...\n");
// floodFill();
#if DC_DEBUG
finish = clock();
dc_printf("Time taken: %f seconds \n", (double)(finish - start) / CLOCKS_PER_SEC);
#endif
}
// Output
#if DC_DEBUG
start = clock();
#endif
writeOut();
#if DC_DEBUG
finish = clock();
#endif
// dc_printf("Time taken: %f seconds \n", (double)(finish - start) / CLOCKS_PER_SEC);
// Print info
#ifdef IN_VERBOSE_MODE
dc_printf("Holes after patching: %d \n", numRings);
#endif
numRings = tnumRings;
#if DC_DEBUG
dc_printf("Building signs...\n");
start = clock();
#endif
buildSigns();
#if DC_DEBUG
finish = clock();
dc_printf("Time taken: %f seconds \n", (double)(finish - start) / CLOCKS_PER_SEC);
#endif
if (use_flood_fill) {
/*
start = clock();
floodFill();
// Check again
tnumRings = numRings;
trace();
dc_printf("Holes after filling: %d \n", numRings);
numRings = tnumRings;
buildSigns();
finish = clock();
dc_printf("Time taken: %f seconds \n", (double)(finish - start) / CLOCKS_PER_SEC);
*/
#if DC_DEBUG
start = clock();
dc_printf("Removing components...\n");
#endif
floodFill();
buildSigns();
// dc_printf("Checking...\n");
// floodFill();
#if DC_DEBUG
finish = clock();
dc_printf("Time taken: %f seconds \n", (double)(finish - start) / CLOCKS_PER_SEC);
#endif
}
// Output
#if DC_DEBUG
start = clock();
#endif
writeOut();
#if DC_DEBUG
finish = clock();
#endif
// dc_printf("Time taken: %f seconds \n", (double)(finish - start) / CLOCKS_PER_SEC);
// Print info
#ifdef IN_VERBOSE_MODE
printMemUsage();
printMemUsage();
#endif
}
void Octree::initMemory()
{
leafalloc[0] = new MemoryAllocator<sizeof(LeafNode)>();
leafalloc[1] = new MemoryAllocator<sizeof(LeafNode) + sizeof(float) *EDGE_FLOATS>();
leafalloc[2] = new MemoryAllocator<sizeof(LeafNode) + sizeof(float) *EDGE_FLOATS * 2>();
leafalloc[3] = new MemoryAllocator<sizeof(LeafNode) + sizeof(float) *EDGE_FLOATS * 3>();
leafalloc[0] = new MemoryAllocator<sizeof(LeafNode)>();
leafalloc[1] = new MemoryAllocator<sizeof(LeafNode) + sizeof(float) * EDGE_FLOATS>();
leafalloc[2] = new MemoryAllocator<sizeof(LeafNode) + sizeof(float) * EDGE_FLOATS * 2>();
leafalloc[3] = new MemoryAllocator<sizeof(LeafNode) + sizeof(float) * EDGE_FLOATS * 3>();
alloc[0] = new MemoryAllocator<sizeof(InternalNode)>();
alloc[1] = new MemoryAllocator<sizeof(InternalNode) + sizeof(Node *)>();
alloc[2] = new MemoryAllocator<sizeof(InternalNode) + sizeof(Node *) * 2>();
alloc[3] = new MemoryAllocator<sizeof(InternalNode) + sizeof(Node *) * 3>();
alloc[4] = new MemoryAllocator<sizeof(InternalNode) + sizeof(Node *) * 4>();
alloc[5] = new MemoryAllocator<sizeof(InternalNode) + sizeof(Node *) * 5>();
alloc[6] = new MemoryAllocator<sizeof(InternalNode) + sizeof(Node *) * 6>();
alloc[7] = new MemoryAllocator<sizeof(InternalNode) + sizeof(Node *) * 7>();
alloc[8] = new MemoryAllocator<sizeof(InternalNode) + sizeof(Node *) * 8>();
alloc[0] = new MemoryAllocator<sizeof(InternalNode)>();
alloc[1] = new MemoryAllocator<sizeof(InternalNode) + sizeof(Node *)>();
alloc[2] = new MemoryAllocator<sizeof(InternalNode) + sizeof(Node *) * 2>();
alloc[3] = new MemoryAllocator<sizeof(InternalNode) + sizeof(Node *) * 3>();
alloc[4] = new MemoryAllocator<sizeof(InternalNode) + sizeof(Node *) * 4>();
alloc[5] = new MemoryAllocator<sizeof(InternalNode) + sizeof(Node *) * 5>();
alloc[6] = new MemoryAllocator<sizeof(InternalNode) + sizeof(Node *) * 6>();
alloc[7] = new MemoryAllocator<sizeof(InternalNode) + sizeof(Node *) * 7>();
alloc[8] = new MemoryAllocator<sizeof(InternalNode) + sizeof(Node *) * 8>();
}
void Octree::freeMemory()
{
for (int i = 0; i < 9; i++) {
alloc[i]->destroy();
delete alloc[i];
}
for (int i = 0; i < 9; i++) {
alloc[i]->destroy();
delete alloc[i];
}
for (int i = 0; i < 4; i++) {
leafalloc[i]->destroy();
delete leafalloc[i];
}
for (int i = 0; i < 4; i++) {
leafalloc[i]->destroy();
delete leafalloc[i];
}
}
void Octree::printMemUsage()
{
int totalbytes = 0;
dc_printf("********* Internal nodes: \n");
for (int i = 0; i < 9; i++) {
alloc[i]->printInfo();
int totalbytes = 0;
dc_printf("********* Internal nodes: \n");
for (int i = 0; i < 9; i++) {
alloc[i]->printInfo();
totalbytes += alloc[i]->getAll() * alloc[i]->getBytes();
}
dc_printf("********* Leaf nodes: \n");
int totalLeafs = 0;
for (int i = 0; i < 4; i++) {
leafalloc[i]->printInfo();
totalbytes += alloc[i]->getAll() * alloc[i]->getBytes();
}
dc_printf("********* Leaf nodes: \n");
int totalLeafs = 0;
for (int i = 0; i < 4; i++) {
leafalloc[i]->printInfo();
totalbytes += leafalloc[i]->getAll() * leafalloc[i]->getBytes();
totalLeafs += leafalloc[i]->getAllocated();
}
totalbytes += leafalloc[i]->getAll() * leafalloc[i]->getBytes();
totalLeafs += leafalloc[i]->getAllocated();
}
dc_printf("Total allocated bytes on disk: %d \n", totalbytes);
dc_printf("Total leaf nodes: %d\n", totalLeafs);
dc_printf("Total allocated bytes on disk: %d \n", totalbytes);
dc_printf("Total leaf nodes: %d\n", totalLeafs);
}
void Octree::resetMinimalEdges()
{
cellProcParity(root, 0, maxDepth);
cellProcParity(root, 0, maxDepth);
}
void Octree::addAllTriangles()
{
Triangle *trian;
int count = 0;
Triangle *trian;
int count = 0;
#if DC_DEBUG
int total = reader->getNumTriangles();
int unitcount = 1000;
dc_printf("\nScan converting to depth %d...\n", maxDepth);
int total = reader->getNumTriangles();
int unitcount = 1000;
dc_printf("\nScan converting to depth %d...\n", maxDepth);
#endif
srand(0);
srand(0);
while ((trian = reader->getNextTriangle()) != NULL) {
// Drop triangles
{
addTriangle(trian, count);
}
delete trian;
while ((trian = reader->getNextTriangle()) != NULL) {
// Drop triangles
{
addTriangle(trian, count);
}
delete trian;
count++;
count++;
#if DC_DEBUG
if (count % unitcount == 0) {
putchar(13);
if (count % unitcount == 0) {
putchar(13);
switch ((count / unitcount) % 4) {
case 0: dc_printf("-");
break;
case 1: dc_printf("/");
break;
case 2: dc_printf("|");
break;
case 3: dc_printf("\\");
break;
}
switch ((count / unitcount) % 4) {
case 0:
dc_printf("-");
break;
case 1:
dc_printf("/");
break;
case 2:
dc_printf("|");
break;
case 3:
dc_printf("\\");
break;
}
float percent = (float) count / total;
float percent = (float)count / total;
/*
int totbars = 50;
int bars =(int)(percent * totbars);
for(int i = 0; i < bars; i ++) {
putchar(219);
}
for(i = bars; i < totbars; i ++) {
putchar(176);
}
*/
/*
int totbars = 50;
int bars =(int)(percent * totbars);
for(int i = 0; i < bars; i ++) {
putchar(219);
}
for(i = bars; i < totbars; i ++) {
putchar(176);
}
*/
dc_printf(" %d triangles: ", count);
dc_printf(" %f%% complete.", 100 * percent);
}
dc_printf(" %d triangles: ", count);
dc_printf(" %f%% complete.", 100 * percent);
}
#endif
}
putchar(13);
}
putchar(13);
}
/* Prepare a triangle for insertion into the octree; call the other
addTriangle() to (recursively) build the octree */
void Octree::addTriangle(Triangle *trian, int triind)
{
int i, j;
int i, j;
/* Project the triangle's coordinates into the grid */
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++)
trian->vt[i][j] = dimen * (trian->vt[i][j] - origin[j]) / range;
}
/* Project the triangle's coordinates into the grid */
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++)
trian->vt[i][j] = dimen * (trian->vt[i][j] - origin[j]) / range;
}
/* Generate projections */
int64_t cube[2][3] = {{0, 0, 0}, {dimen, dimen, dimen}};
int64_t trig[3][3];
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++)
trig[i][j] = (int64_t)(trian->vt[i][j]);
}
/* Generate projections */
int64_t cube[2][3] = {{0, 0, 0}, {dimen, dimen, dimen}};
int64_t trig[3][3];
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++)
trig[i][j] = (int64_t)(trian->vt[i][j]);
}
/* Add triangle to the octree */
int64_t errorvec = (int64_t)(0);
CubeTriangleIsect *proj = new CubeTriangleIsect(cube, trig, errorvec, triind);
root = (Node *)addTriangle(&root->internal, proj, maxDepth);
/* Add triangle to the octree */
int64_t errorvec = (int64_t)(0);
CubeTriangleIsect *proj = new CubeTriangleIsect(cube, trig, errorvec, triind);
root = (Node *)addTriangle(&root->internal, proj, maxDepth);
delete proj->inherit;
delete proj;
delete proj->inherit;
delete proj;
}
#if 0
static void print_depth(int height, int maxDepth)
{
for (int i = 0; i < maxDepth - height; i++)
printf(" ");
for (int i = 0; i < maxDepth - height; i++)
printf(" ");
}
#endif
InternalNode *Octree::addTriangle(InternalNode *node, CubeTriangleIsect *p, int height)
{
int i;
const int vertdiff[8][3] = {
{0, 0, 0},
{0, 0, 1},
{0, 1, -1},
{0, 0, 1},
{1, -1, -1},
{0, 0, 1},
{0, 1, -1},
{0, 0, 1}};
unsigned char boxmask = p->getBoxMask();
CubeTriangleIsect *subp = new CubeTriangleIsect(p);
int i;
const int vertdiff[8][3] = {
{0, 0, 0}, {0, 0, 1}, {0, 1, -1}, {0, 0, 1}, {1, -1, -1}, {0, 0, 1}, {0, 1, -1}, {0, 0, 1}};
unsigned char boxmask = p->getBoxMask();
CubeTriangleIsect *subp = new CubeTriangleIsect(p);
int count = 0;
int tempdiff[3] = {0, 0, 0};
int count = 0;
int tempdiff[3] = {0, 0, 0};
/* Check triangle against each of the input node's children */
for (i = 0; i < 8; i++) {
tempdiff[0] += vertdiff[i][0];
tempdiff[1] += vertdiff[i][1];
tempdiff[2] += vertdiff[i][2];
/* Check triangle against each of the input node's children */
for (i = 0; i < 8; i++) {
tempdiff[0] += vertdiff[i][0];
tempdiff[1] += vertdiff[i][1];
tempdiff[2] += vertdiff[i][2];
/* Quick pruning using bounding box */
if (boxmask & (1 << i)) {
subp->shift(tempdiff);
tempdiff[0] = tempdiff[1] = tempdiff[2] = 0;
/* Quick pruning using bounding box */
if (boxmask & (1 << i)) {
subp->shift(tempdiff);
tempdiff[0] = tempdiff[1] = tempdiff[2] = 0;
/* Pruning using intersection test */
if (subp->isIntersecting()) {
if (!node->has_child(i)) {
if (height == 1)
node = addLeafChild(node, i, count, createLeaf(0));
else
node = addInternalChild(node, i, count, createInternal(0));
}
Node *chd = node->get_child(count);
/* Pruning using intersection test */
if (subp->isIntersecting()) {
if (!node->has_child(i)) {
if (height == 1)
node = addLeafChild(node, i, count, createLeaf(0));
else
node = addInternalChild(node, i, count, createInternal(0));
}
Node *chd = node->get_child(count);
if (node->is_child_leaf(i))
node->set_child(count, (Node *)updateCell(&chd->leaf, subp));
else
node->set_child(count, (Node *)addTriangle(&chd->internal, subp, height - 1));
}
}
if (node->is_child_leaf(i))
node->set_child(count, (Node *)updateCell(&chd->leaf, subp));
else
node->set_child(count, (Node *)addTriangle(&chd->internal, subp, height - 1));
}
}
if (node->has_child(i))
count++;
}
if (node->has_child(i))
count++;
}
delete subp;
delete subp;
return node;
return node;
}
LeafNode *Octree::updateCell(LeafNode *node, CubeTriangleIsect *p)
{
int i;
int i;
// Edge connectivity
int mask[3] = {0, 4, 8 };
int oldc = 0, newc = 0;
float offs[3];
float a[3], b[3], c[3];
// Edge connectivity
int mask[3] = {0, 4, 8};
int oldc = 0, newc = 0;
float offs[3];
float a[3], b[3], c[3];
for (i = 0; i < 3; i++) {
if (!getEdgeParity(node, mask[i])) {
if (p->isIntersectingPrimary(i)) {
// actualQuads ++;
setEdge(node, mask[i]);
offs[newc] = p->getIntersectionPrimary(i);
a[newc] = (float) p->inherit->norm[0];
b[newc] = (float) p->inherit->norm[1];
c[newc] = (float) p->inherit->norm[2];
newc++;
}
}
else {
offs[newc] = getEdgeOffsetNormal(node, oldc, a[newc], b[newc], c[newc]);
for (i = 0; i < 3; i++) {
if (!getEdgeParity(node, mask[i])) {
if (p->isIntersectingPrimary(i)) {
// actualQuads ++;
setEdge(node, mask[i]);
offs[newc] = p->getIntersectionPrimary(i);
a[newc] = (float)p->inherit->norm[0];
b[newc] = (float)p->inherit->norm[1];
c[newc] = (float)p->inherit->norm[2];
newc++;
}
}
else {
offs[newc] = getEdgeOffsetNormal(node, oldc, a[newc], b[newc], c[newc]);
oldc++;
newc++;
}
}
oldc++;
newc++;
}
}
if (newc > oldc) {
// New offsets added, update this node
node = updateEdgeOffsetsNormals(node, oldc, newc, offs, a, b, c);
}
if (newc > oldc) {
// New offsets added, update this node
node = updateEdgeOffsetsNormals(node, oldc, newc, offs, a, b, c);
}
return node;
return node;
}
void Octree::preparePrimalEdgesMask(InternalNode *node)
{
int count = 0;
for (int i = 0; i < 8; i++) {
if (node->has_child(i)) {
if (node->is_child_leaf(i))
createPrimalEdgesMask(&node->get_child(count)->leaf);
else
preparePrimalEdgesMask(&node->get_child(count)->internal);
int count = 0;
for (int i = 0; i < 8; i++) {
if (node->has_child(i)) {
if (node->is_child_leaf(i))
createPrimalEdgesMask(&node->get_child(count)->leaf);
else
preparePrimalEdgesMask(&node->get_child(count)->internal);
count++;
}
}
count++;
}
}
}
void Octree::trace()
{
int st[3] = {0, 0, 0, };
numRings = 0;
totRingLengths = 0;
maxRingLength = 0;
int st[3] = {
0,
0,
0,
};
numRings = 0;
totRingLengths = 0;
maxRingLength = 0;
PathList *chdpath = NULL;
root = trace(root, st, dimen, maxDepth, chdpath);
PathList *chdpath = NULL;
root = trace(root, st, dimen, maxDepth, chdpath);
if (chdpath != NULL) {
dc_printf("there are incomplete rings.\n");
printPaths(chdpath);
};
if (chdpath != NULL) {
dc_printf("there are incomplete rings.\n");
printPaths(chdpath);
};
}
Node *Octree::trace(Node *newnode, int *st, int len, int depth, PathList *& paths)
Node *Octree::trace(Node *newnode, int *st, int len, int depth, PathList *&paths)
{
len >>= 1;
PathList *chdpaths[8];
Node *chd[8];
int nst[8][3];
int i, j;
len >>= 1;
PathList *chdpaths[8];
Node *chd[8];
int nst[8][3];
int i, j;
// Get children paths
int chdleaf[8];
newnode->internal.fill_children(chd, chdleaf);
// Get children paths
int chdleaf[8];
newnode->internal.fill_children(chd, chdleaf);
// int count = 0;
for (i = 0; i < 8; i++) {
for (j = 0; j < 3; j++) {
nst[i][j] = st[j] + len * vertmap[i][j];
}
// int count = 0;
for (i = 0; i < 8; i++) {
for (j = 0; j < 3; j++) {
nst[i][j] = st[j] + len * vertmap[i][j];
}
if (chd[i] == NULL || newnode->internal.is_child_leaf(i)) {
chdpaths[i] = NULL;
}
else {
trace(chd[i], nst[i], len, depth - 1, chdpaths[i]);
}
}
if (chd[i] == NULL || newnode->internal.is_child_leaf(i)) {
chdpaths[i] = NULL;
}
else {
trace(chd[i], nst[i], len, depth - 1, chdpaths[i]);
}
}
// Get connectors on the faces
PathList *conn[12];
Node *nf[2];
int lf[2];
int df[2] = {depth - 1, depth - 1};
int *nstf[2];
// Get connectors on the faces
PathList *conn[12];
Node *nf[2];
int lf[2];
int df[2] = {depth - 1, depth - 1};
int *nstf[2];
newnode->internal.fill_children(chd, chdleaf);
newnode->internal.fill_children(chd, chdleaf);
for (i = 0; i < 12; i++) {
int c[2] = {cellProcFaceMask[i][0], cellProcFaceMask[i][1]};
for (i = 0; i < 12; i++) {
int c[2] = {cellProcFaceMask[i][0], cellProcFaceMask[i][1]};
for (int j = 0; j < 2; j++) {
lf[j] = chdleaf[c[j]];
nf[j] = chd[c[j]];
nstf[j] = nst[c[j]];
}
for (int j = 0; j < 2; j++) {
lf[j] = chdleaf[c[j]];
nf[j] = chd[c[j]];
nstf[j] = nst[c[j]];
}
conn[i] = NULL;
conn[i] = NULL;
findPaths((Node **)nf, lf, df, nstf, depth - 1, cellProcFaceMask[i][2], conn[i]);
findPaths((Node **)nf, lf, df, nstf, depth - 1, cellProcFaceMask[i][2], conn[i]);
//if(conn[i]) {
// printPath(conn[i]);
//}
}
//if(conn[i]) {
// printPath(conn[i]);
//}
}
// Connect paths
PathList *rings = NULL;
combinePaths(chdpaths[0], chdpaths[1], conn[8], rings);
combinePaths(chdpaths[2], chdpaths[3], conn[9], rings);
combinePaths(chdpaths[4], chdpaths[5], conn[10], rings);
combinePaths(chdpaths[6], chdpaths[7], conn[11], rings);
// Connect paths
PathList *rings = NULL;
combinePaths(chdpaths[0], chdpaths[1], conn[8], rings);
combinePaths(chdpaths[2], chdpaths[3], conn[9], rings);
combinePaths(chdpaths[4], chdpaths[5], conn[10], rings);
combinePaths(chdpaths[6], chdpaths[7], conn[11], rings);
combinePaths(chdpaths[0], chdpaths[2], conn[4], rings);
combinePaths(chdpaths[4], chdpaths[6], conn[5], rings);
combinePaths(chdpaths[0], NULL, conn[6], rings);
combinePaths(chdpaths[4], NULL, conn[7], rings);
combinePaths(chdpaths[0], chdpaths[2], conn[4], rings);
combinePaths(chdpaths[4], chdpaths[6], conn[5], rings);
combinePaths(chdpaths[0], NULL, conn[6], rings);
combinePaths(chdpaths[4], NULL, conn[7], rings);
combinePaths(chdpaths[0], chdpaths[4], conn[0], rings);
combinePaths(chdpaths[0], NULL, conn[1], rings);
combinePaths(chdpaths[0], NULL, conn[2], rings);
combinePaths(chdpaths[0], NULL, conn[3], rings);
combinePaths(chdpaths[0], chdpaths[4], conn[0], rings);
combinePaths(chdpaths[0], NULL, conn[1], rings);
combinePaths(chdpaths[0], NULL, conn[2], rings);
combinePaths(chdpaths[0], NULL, conn[3], rings);
// By now, only chdpaths[0] and rings have contents
// By now, only chdpaths[0] and rings have contents
// Process rings
if (rings) {
// printPath(rings);
// Process rings
if (rings) {
// printPath(rings);
/* Let's count first */
PathList *trings = rings;
while (trings) {
numRings++;
totRingLengths += trings->length;
if (trings->length > maxRingLength) {
maxRingLength = trings->length;
}
trings = trings->next;
}
/* Let's count first */
PathList *trings = rings;
while (trings) {
numRings++;
totRingLengths += trings->length;
if (trings->length > maxRingLength) {
maxRingLength = trings->length;
}
trings = trings->next;
}
// printPath(rings);
newnode = patch(newnode, st, (len << 1), rings);
}
// printPath(rings);
newnode = patch(newnode, st, (len << 1), rings);
}
// Return incomplete paths
paths = chdpaths[0];
return newnode;
// Return incomplete paths
paths = chdpaths[0];
return newnode;
}
void Octree::findPaths(Node *node[2], int leaf[2], int depth[2], int *st[2], int maxdep, int dir, PathList *& paths)
void Octree::findPaths(
Node *node[2], int leaf[2], int depth[2], int *st[2], int maxdep, int dir, PathList *&paths)
{
if (!(node[0] && node[1])) {
return;
}
if (!(node[0] && node[1])) {
return;
}
if (!(leaf[0] && leaf[1])) {
// Not at the bottom, recur
if (!(leaf[0] && leaf[1])) {
// Not at the bottom, recur
// Fill children nodes
int i, j;
Node *chd[2][8];
int chdleaf[2][8];
int nst[2][8][3];
// Fill children nodes
int i, j;
Node *chd[2][8];
int chdleaf[2][8];
int nst[2][8][3];
for (j = 0; j < 2; j++) {
if (!leaf[j]) {
node[j]->internal.fill_children(chd[j], chdleaf[j]);
for (j = 0; j < 2; j++) {
if (!leaf[j]) {
node[j]->internal.fill_children(chd[j], chdleaf[j]);
int len = (dimen >> (maxDepth - depth[j] + 1));
for (i = 0; i < 8; i++) {
for (int k = 0; k < 3; k++) {
nst[j][i][k] = st[j][k] + len * vertmap[i][k];
}
}
int len = (dimen >> (maxDepth - depth[j] + 1));
for (i = 0; i < 8; i++) {
for (int k = 0; k < 3; k++) {
nst[j][i][k] = st[j][k] + len * vertmap[i][k];
}
}
}
}
}
}
// 4 face calls
Node *nf[2];
int df[2];
int lf[2];
int *nstf[2];
for (i = 0; i < 4; i++) {
int c[2] = {faceProcFaceMask[dir][i][0], faceProcFaceMask[dir][i][1]};
for (int j = 0; j < 2; j++) {
if (leaf[j]) {
lf[j] = leaf[j];
nf[j] = node[j];
df[j] = depth[j];
nstf[j] = st[j];
}
else {
lf[j] = chdleaf[j][c[j]];
nf[j] = chd[j][c[j]];
df[j] = depth[j] - 1;
nstf[j] = nst[j][c[j]];
}
}
findPaths(nf, lf, df, nstf, maxdep - 1, faceProcFaceMask[dir][i][2], paths);
}
}
else {
// At the bottom, check this face
int ind = (depth[0] == maxdep ? 0 : 1);
int fcind = 2 * dir + (1 - ind);
if (getFaceParity((LeafNode *)node[ind], fcind)) {
// Add into path
PathElement *ele1 = new PathElement;
PathElement *ele2 = new PathElement;
// 4 face calls
Node *nf[2];
int df[2];
int lf[2];
int *nstf[2];
for (i = 0; i < 4; i++) {
int c[2] = {faceProcFaceMask[dir][i][0], faceProcFaceMask[dir][i][1]};
for (int j = 0; j < 2; j++) {
if (leaf[j]) {
lf[j] = leaf[j];
nf[j] = node[j];
df[j] = depth[j];
nstf[j] = st[j];
}
else {
lf[j] = chdleaf[j][c[j]];
nf[j] = chd[j][c[j]];
df[j] = depth[j] - 1;
nstf[j] = nst[j][c[j]];
}
}
findPaths(nf, lf, df, nstf, maxdep - 1, faceProcFaceMask[dir][i][2], paths);
}
ele1->pos[0] = st[0][0];
ele1->pos[1] = st[0][1];
ele1->pos[2] = st[0][2];
}
else {
// At the bottom, check this face
int ind = (depth[0] == maxdep ? 0 : 1);
int fcind = 2 * dir + (1 - ind);
if (getFaceParity((LeafNode *)node[ind], fcind)) {
// Add into path
PathElement *ele1 = new PathElement;
PathElement *ele2 = new PathElement;
ele2->pos[0] = st[1][0];
ele2->pos[1] = st[1][1];
ele2->pos[2] = st[1][2];
ele1->pos[0] = st[0][0];
ele1->pos[1] = st[0][1];
ele1->pos[2] = st[0][2];
ele1->next = ele2;
ele2->next = NULL;
ele2->pos[0] = st[1][0];
ele2->pos[1] = st[1][1];
ele2->pos[2] = st[1][2];
ele1->next = ele2;
ele2->next = NULL;
PathList *lst = new PathList;
lst->head = ele1;
lst->tail = ele2;
lst->length = 2;
lst->next = paths;
paths = lst;
// int l =(dimen >> maxDepth);
}
}
PathList *lst = new PathList;
lst->head = ele1;
lst->tail = ele2;
lst->length = 2;
lst->next = paths;
paths = lst;
// int l =(dimen >> maxDepth);
}
}
}
void Octree::combinePaths(PathList *& list1, PathList *list2, PathList *paths, PathList *& rings)
void Octree::combinePaths(PathList *&list1, PathList *list2, PathList *paths, PathList *&rings)
{
// Make new list of paths
PathList *nlist = NULL;
// Make new list of paths
PathList *nlist = NULL;
// Search for each connectors in paths
PathList *tpaths = paths;
PathList *tlist, *pre;
while (tpaths) {
PathList *singlist = tpaths;
PathList *templist;
tpaths = tpaths->next;
singlist->next = NULL;
// Search for each connectors in paths
PathList *tpaths = paths;
PathList *tlist, *pre;
while (tpaths) {
PathList *singlist = tpaths;
PathList *templist;
tpaths = tpaths->next;
singlist->next = NULL;
// Look for hookup in list1
tlist = list1;
pre = NULL;
while (tlist) {
if ((templist = combineSinglePath(list1, pre, tlist, singlist, NULL, singlist)) != NULL) {
singlist = templist;
continue;
}
pre = tlist;
tlist = tlist->next;
}
// Look for hookup in list1
tlist = list1;
pre = NULL;
while (tlist) {
if ((templist = combineSinglePath(list1, pre, tlist, singlist, NULL, singlist)) != NULL) {
singlist = templist;
continue;
}
pre = tlist;
tlist = tlist->next;
}
// Look for hookup in list2
tlist = list2;
pre = NULL;
while (tlist) {
if ((templist = combineSinglePath(list2, pre, tlist, singlist, NULL, singlist)) != NULL) {
singlist = templist;
continue;
}
pre = tlist;
tlist = tlist->next;
}
// Look for hookup in list2
tlist = list2;
pre = NULL;
while (tlist) {
if ((templist = combineSinglePath(list2, pre, tlist, singlist, NULL, singlist)) != NULL) {
singlist = templist;
continue;
}
pre = tlist;
tlist = tlist->next;
}
// Look for hookup in nlist
tlist = nlist;
pre = NULL;
while (tlist) {
if ((templist = combineSinglePath(nlist, pre, tlist, singlist, NULL, singlist)) != NULL) {
singlist = templist;
continue;
}
pre = tlist;
tlist = tlist->next;
}
// Look for hookup in nlist
tlist = nlist;
pre = NULL;
while (tlist) {
if ((templist = combineSinglePath(nlist, pre, tlist, singlist, NULL, singlist)) != NULL) {
singlist = templist;
continue;
}
pre = tlist;
tlist = tlist->next;
}
// Add to nlist or rings
if (isEqual(singlist->head, singlist->tail)) {
PathElement *temp = singlist->head;
singlist->head = temp->next;
delete temp;
singlist->length--;
singlist->tail->next = singlist->head;
// Add to nlist or rings
if (isEqual(singlist->head, singlist->tail)) {
PathElement *temp = singlist->head;
singlist->head = temp->next;
delete temp;
singlist->length--;
singlist->tail->next = singlist->head;
singlist->next = rings;
rings = singlist;
}
else {
singlist->next = nlist;
nlist = singlist;
}
singlist->next = rings;
rings = singlist;
}
else {
singlist->next = nlist;
nlist = singlist;
}
}
}
// Append list2 and nlist to the end of list1
tlist = list1;
if (tlist != NULL) {
while (tlist->next != NULL) {
tlist = tlist->next;
}
tlist->next = list2;
}
else {
tlist = list2;
list1 = list2;
}
if (tlist != NULL) {
while (tlist->next != NULL) {
tlist = tlist->next;
}
tlist->next = nlist;
}
else {
tlist = nlist;
list1 = nlist;
}
// Append list2 and nlist to the end of list1
tlist = list1;
if (tlist != NULL) {
while (tlist->next != NULL) {
tlist = tlist->next;
}
tlist->next = list2;
}
else {
tlist = list2;
list1 = list2;
}
if (tlist != NULL) {
while (tlist->next != NULL) {
tlist = tlist->next;
}
tlist->next = nlist;
}
else {
tlist = nlist;
list1 = nlist;
}
}
PathList *Octree::combineSinglePath(PathList *& head1, PathList *pre1, PathList *& list1, PathList *& head2, PathList *pre2, PathList *& list2)
PathList *Octree::combineSinglePath(PathList *&head1,
PathList *pre1,
PathList *&list1,
PathList *&head2,
PathList *pre2,
PathList *&list2)
{
if (isEqual(list1->head, list2->head) || isEqual(list1->tail, list2->tail)) {
// Reverse the list
if (list1->length < list2->length) {
// Reverse list1
PathElement *prev = list1->head;
PathElement *next = prev->next;
prev->next = NULL;
while (next != NULL) {
PathElement *tnext = next->next;
next->next = prev;
if (isEqual(list1->head, list2->head) || isEqual(list1->tail, list2->tail)) {
// Reverse the list
if (list1->length < list2->length) {
// Reverse list1
PathElement *prev = list1->head;
PathElement *next = prev->next;
prev->next = NULL;
while (next != NULL) {
PathElement *tnext = next->next;
next->next = prev;
prev = next;
next = tnext;
}
prev = next;
next = tnext;
}
list1->tail = list1->head;
list1->head = prev;
}
else {
// Reverse list2
PathElement *prev = list2->head;
PathElement *next = prev->next;
prev->next = NULL;
while (next != NULL) {
PathElement *tnext = next->next;
next->next = prev;
list1->tail = list1->head;
list1->head = prev;
}
else {
// Reverse list2
PathElement *prev = list2->head;
PathElement *next = prev->next;
prev->next = NULL;
while (next != NULL) {
PathElement *tnext = next->next;
next->next = prev;
prev = next;
next = tnext;
}
prev = next;
next = tnext;
}
list2->tail = list2->head;
list2->head = prev;
}
}
list2->tail = list2->head;
list2->head = prev;
}
}
if (isEqual(list1->head, list2->tail)) {
if (isEqual(list1->head, list2->tail)) {
// Easy case
PathElement *temp = list1->head->next;
delete list1->head;
list2->tail->next = temp;
// Easy case
PathElement *temp = list1->head->next;
delete list1->head;
list2->tail->next = temp;
PathList *nlist = new PathList;
nlist->length = list1->length + list2->length - 1;
nlist->head = list2->head;
nlist->tail = list1->tail;
nlist->next = NULL;
PathList *nlist = new PathList;
nlist->length = list1->length + list2->length - 1;
nlist->head = list2->head;
nlist->tail = list1->tail;
nlist->next = NULL;
deletePath(head1, pre1, list1);
deletePath(head2, pre2, list2);
deletePath(head1, pre1, list1);
deletePath(head2, pre2, list2);
return nlist;
}
else if (isEqual(list1->tail, list2->head)) {
// Easy case
PathElement *temp = list2->head->next;
delete list2->head;
list1->tail->next = temp;
return nlist;
}
else if (isEqual(list1->tail, list2->head)) {
// Easy case
PathElement *temp = list2->head->next;
delete list2->head;
list1->tail->next = temp;
PathList *nlist = new PathList;
nlist->length = list1->length + list2->length - 1;
nlist->head = list1->head;
nlist->tail = list2->tail;
nlist->next = NULL;
PathList *nlist = new PathList;
nlist->length = list1->length + list2->length - 1;
nlist->head = list1->head;
nlist->tail = list2->tail;
nlist->next = NULL;
deletePath(head1, pre1, list1);
deletePath(head2, pre2, list2);
deletePath(head1, pre1, list1);
deletePath(head2, pre2, list2);
return nlist;
}
return nlist;
}
return NULL;
return NULL;
}
void Octree::deletePath(PathList *& head, PathList *pre, PathList *& curr)
void Octree::deletePath(PathList *&head, PathList *pre, PathList *&curr)
{
PathList *temp = curr;
curr = temp->next;
delete temp;
PathList *temp = curr;
curr = temp->next;
delete temp;
if (pre == NULL) {
head = curr;
}
else {
pre->next = curr;
}
if (pre == NULL) {
head = curr;
}
else {
pre->next = curr;
}
}
void Octree::printElement(PathElement *ele)
{
if (ele != NULL) {
dc_printf("(%d %d %d)", ele->pos[0], ele->pos[1], ele->pos[2]);
}
if (ele != NULL) {
dc_printf("(%d %d %d)", ele->pos[0], ele->pos[1], ele->pos[2]);
}
}
void Octree::printPath(PathList *path)
{
PathElement *n = path->head;
int same = 0;
PathElement *n = path->head;
int same = 0;
#if DC_DEBUG
int len = (dimen >> maxDepth);
int len = (dimen >> maxDepth);
#endif
while (n && (same == 0 || n != path->head)) {
same++;
dc_printf("(%d %d %d)", n->pos[0] / len, n->pos[1] / len, n->pos[2] / len);
n = n->next;
}
while (n && (same == 0 || n != path->head)) {
same++;
dc_printf("(%d %d %d)", n->pos[0] / len, n->pos[1] / len, n->pos[2] / len);
n = n->next;
}
if (n == path->head) {
dc_printf(" Ring!\n");
}
else {
dc_printf(" %p end!\n", n);
}
if (n == path->head) {
dc_printf(" Ring!\n");
}
else {
dc_printf(" %p end!\n", n);
}
}
void Octree::printPath(PathElement *path)
{
PathElement *n = path;
int same = 0;
PathElement *n = path;
int same = 0;
#if DC_DEBUG
int len = (dimen >> maxDepth);
int len = (dimen >> maxDepth);
#endif
while (n && (same == 0 || n != path)) {
same++;
dc_printf("(%d %d %d)", n->pos[0] / len, n->pos[1] / len, n->pos[2] / len);
n = n->next;
}
if (n == path) {
dc_printf(" Ring!\n");
}
else {
dc_printf(" %p end!\n", n);
}
while (n && (same == 0 || n != path)) {
same++;
dc_printf("(%d %d %d)", n->pos[0] / len, n->pos[1] / len, n->pos[2] / len);
n = n->next;
}
if (n == path) {
dc_printf(" Ring!\n");
}
else {
dc_printf(" %p end!\n", n);
}
}
void Octree::printPaths(PathList *path)
{
PathList *iter = path;
int i = 0;
while (iter != NULL) {
dc_printf("Path %d:\n", i);
printPath(iter);
iter = iter->next;
i++;
}
PathList *iter = path;
int i = 0;
while (iter != NULL) {
dc_printf("Path %d:\n", i);
printPath(iter);
iter = iter->next;
i++;
}
}
Node *Octree::patch(Node *newnode, int st[3], int len, PathList *rings)
{
#ifdef IN_DEBUG_MODE
dc_printf("Call to PATCH with rings: \n");
printPaths(rings);
dc_printf("Call to PATCH with rings: \n");
printPaths(rings);
#endif
/* Do nothing but couting
PathList* tlist = rings;
PathList* ttlist;
PathElement* telem, * ttelem;
while(tlist!= NULL) {
// printPath(tlist);
numRings ++;
totRingLengths += tlist->length;
if(tlist->length > maxRingLength) {
maxRingLength = tlist->length;
}
ttlist = tlist;
tlist = tlist->next;
}
return node;
*/
/* Do nothing but couting
PathList* tlist = rings;
PathList* ttlist;
PathElement* telem, * ttelem;
while(tlist!= NULL) {
// printPath(tlist);
numRings ++;
totRingLengths += tlist->length;
if(tlist->length > maxRingLength) {
maxRingLength = tlist->length;
}
ttlist = tlist;
tlist = tlist->next;
}
return node;
*/
/* Pass onto separate calls in each direction */
if (len == mindimen) {
dc_printf("Error! should have no list by now.\n");
exit(0);
}
/* Pass onto separate calls in each direction */
if (len == mindimen) {
dc_printf("Error! should have no list by now.\n");
exit(0);
}
// YZ plane
PathList *xlists[2];
newnode = patchSplit(newnode, st, len, rings, 0, xlists[0], xlists[1]);
// YZ plane
PathList *xlists[2];
newnode = patchSplit(newnode, st, len, rings, 0, xlists[0], xlists[1]);
// XZ plane
PathList *ylists[4];
newnode = patchSplit(newnode, st, len, xlists[0], 1, ylists[0], ylists[1]);
newnode = patchSplit(newnode, st, len, xlists[1], 1, ylists[2], ylists[3]);
// XZ plane
PathList *ylists[4];
newnode = patchSplit(newnode, st, len, xlists[0], 1, ylists[0], ylists[1]);
newnode = patchSplit(newnode, st, len, xlists[1], 1, ylists[2], ylists[3]);
// XY plane
PathList *zlists[8];
newnode = patchSplit(newnode, st, len, ylists[0], 2, zlists[0], zlists[1]);
newnode = patchSplit(newnode, st, len, ylists[1], 2, zlists[2], zlists[3]);
newnode = patchSplit(newnode, st, len, ylists[2], 2, zlists[4], zlists[5]);
newnode = patchSplit(newnode, st, len, ylists[3], 2, zlists[6], zlists[7]);
// XY plane
PathList *zlists[8];
newnode = patchSplit(newnode, st, len, ylists[0], 2, zlists[0], zlists[1]);
newnode = patchSplit(newnode, st, len, ylists[1], 2, zlists[2], zlists[3]);
newnode = patchSplit(newnode, st, len, ylists[2], 2, zlists[4], zlists[5]);
newnode = patchSplit(newnode, st, len, ylists[3], 2, zlists[6], zlists[7]);
// Recur
len >>= 1;
int count = 0;
for (int i = 0; i < 8; i++) {
if (zlists[i] != NULL) {
int nori[3] = {
st[0] + len * vertmap[i][0], st[1] + len * vertmap[i][1], st[2] + len * vertmap[i][2]};
patch(newnode->internal.get_child(count), nori, len, zlists[i]);
}
// Recur
len >>= 1;
int count = 0;
for (int i = 0; i < 8; i++) {
if (zlists[i] != NULL) {
int nori[3] = {
st[0] + len * vertmap[i][0],
st[1] + len * vertmap[i][1],
st[2] + len * vertmap[i][2]
};
patch(newnode->internal.get_child(count), nori, len, zlists[i]);
}
if (newnode->internal.has_child(i)) {
count++;
}
}
if (newnode->internal.has_child(i)) {
count++;
}
}
#ifdef IN_DEBUG_MODE
dc_printf("Return from PATCH\n");
dc_printf("Return from PATCH\n");
#endif
return newnode;
return newnode;
}
Node *Octree::patchSplit(Node *newnode, int st[3], int len, PathList *rings,
int dir, PathList *& nrings1, PathList *& nrings2)
Node *Octree::patchSplit(Node *newnode,
int st[3],
int len,
PathList *rings,
int dir,
PathList *&nrings1,
PathList *&nrings2)
{
#ifdef IN_DEBUG_MODE
dc_printf("Call to PATCHSPLIT with direction %d and rings: \n", dir);
printPaths(rings);
dc_printf("Call to PATCHSPLIT with direction %d and rings: \n", dir);
printPaths(rings);
#endif
nrings1 = NULL;
nrings2 = NULL;
PathList *tmp;
while (rings != NULL) {
// Process this ring
newnode = patchSplitSingle(newnode, st, len, rings->head, dir, nrings1, nrings2);
nrings1 = NULL;
nrings2 = NULL;
PathList *tmp;
while (rings != NULL) {
// Process this ring
newnode = patchSplitSingle(newnode, st, len, rings->head, dir, nrings1, nrings2);
// Delete this ring from the group
tmp = rings;
rings = rings->next;
delete tmp;
}
// Delete this ring from the group
tmp = rings;
rings = rings->next;
delete tmp;
}
#ifdef IN_DEBUG_MODE
dc_printf("Return from PATCHSPLIT with \n");
dc_printf("Rings gourp 1:\n");
printPaths(nrings1);
dc_printf("Rings group 2:\n");
printPaths(nrings2);
dc_printf("Return from PATCHSPLIT with \n");
dc_printf("Rings gourp 1:\n");
printPaths(nrings1);
dc_printf("Rings group 2:\n");
printPaths(nrings2);
#endif
return newnode;
return newnode;
}
Node *Octree::patchSplitSingle(Node *newnode, int st[3], int len, PathElement *head, int dir, PathList *& nrings1, PathList *& nrings2)
Node *Octree::patchSplitSingle(Node *newnode,
int st[3],
int len,
PathElement *head,
int dir,
PathList *&nrings1,
PathList *&nrings2)
{
#ifdef IN_DEBUG_MODE
dc_printf("Call to PATCHSPLITSINGLE with direction %d and path: \n", dir);
printPath(head);
dc_printf("Call to PATCHSPLITSINGLE with direction %d and path: \n", dir);
printPath(head);
#endif
if (head == NULL) {
if (head == NULL) {
#ifdef IN_DEBUG_MODE
dc_printf("Return from PATCHSPLITSINGLE with head==NULL.\n");
dc_printf("Return from PATCHSPLITSINGLE with head==NULL.\n");
#endif
return newnode;
}
else {
// printPath(head);
}
return newnode;
}
else {
// printPath(head);
}
// Walk along the ring to find pair of intersections
PathElement *pre1 = NULL;
PathElement *pre2 = NULL;
int side = findPair(head, st[dir] + len / 2, dir, pre1, pre2);
// Walk along the ring to find pair of intersections
PathElement *pre1 = NULL;
PathElement *pre2 = NULL;
int side = findPair(head, st[dir] + len / 2, dir, pre1, pre2);
/*
if(pre1 == pre2) {
int edgelen =(dimen >> maxDepth);
dc_printf("Location: %d %d %d Direction: %d Reso: %d\n", st[0]/edgelen, st[1]/edgelen, st[2]/edgelen, dir, len/edgelen);
printPath(head);
exit(0);
}
*/
/*
if(pre1 == pre2) {
int edgelen =(dimen >> maxDepth);
dc_printf("Location: %d %d %d Direction: %d Reso: %d\n", st[0]/edgelen, st[1]/edgelen, st[2]/edgelen, dir, len/edgelen);
printPath(head);
exit(0);
}
*/
if (side) {
// Entirely on one side
PathList *nring = new PathList();
nring->head = head;
if (side) {
// Entirely on one side
PathList *nring = new PathList();
nring->head = head;
if (side == -1) {
nring->next = nrings1;
nrings1 = nring;
}
else {
nring->next = nrings2;
nrings2 = nring;
}
}
else {
// Break into two parts
PathElement *nxt1 = pre1->next;
PathElement *nxt2 = pre2->next;
pre1->next = nxt2;
pre2->next = nxt1;
if (side == -1) {
nring->next = nrings1;
nrings1 = nring;
}
else {
nring->next = nrings2;
nrings2 = nring;
}
}
else {
// Break into two parts
PathElement *nxt1 = pre1->next;
PathElement *nxt2 = pre2->next;
pre1->next = nxt2;
pre2->next = nxt1;
newnode = connectFace(newnode, st, len, dir, pre1, pre2);
newnode = connectFace(newnode, st, len, dir, pre1, pre2);
if (isEqual(pre1, pre1->next)) {
if (pre1 == pre1->next) {
delete pre1;
pre1 = NULL;
}
else {
PathElement *temp = pre1->next;
pre1->next = temp->next;
delete temp;
}
}
if (isEqual(pre2, pre2->next)) {
if (pre2 == pre2->next) {
delete pre2;
pre2 = NULL;
}
else {
PathElement *temp = pre2->next;
pre2->next = temp->next;
delete temp;
}
}
if (isEqual(pre1, pre1->next)) {
if (pre1 == pre1->next) {
delete pre1;
pre1 = NULL;
}
else {
PathElement *temp = pre1->next;
pre1->next = temp->next;
delete temp;
}
}
if (isEqual(pre2, pre2->next)) {
if (pre2 == pre2->next) {
delete pre2;
pre2 = NULL;
}
else {
PathElement *temp = pre2->next;
pre2->next = temp->next;
delete temp;
}
}
compressRing(pre1);
compressRing(pre2);
compressRing(pre1);
compressRing(pre2);
// Recur
newnode = patchSplitSingle(newnode, st, len, pre1, dir, nrings1, nrings2);
newnode = patchSplitSingle(newnode, st, len, pre2, dir, nrings1, nrings2);
}
// Recur
newnode = patchSplitSingle(newnode, st, len, pre1, dir, nrings1, nrings2);
newnode = patchSplitSingle(newnode, st, len, pre2, dir, nrings1, nrings2);
}
#ifdef IN_DEBUG_MODE
dc_printf("Return from PATCHSPLITSINGLE with \n");
dc_printf("Rings gourp 1:\n");
printPaths(nrings1);
dc_printf("Rings group 2:\n");
printPaths(nrings2);
dc_printf("Return from PATCHSPLITSINGLE with \n");
dc_printf("Rings gourp 1:\n");
printPaths(nrings1);
dc_printf("Rings group 2:\n");
printPaths(nrings2);
#endif
return newnode;
return newnode;
}
Node *Octree::connectFace(Node *newnode, int st[3], int len, int dir,
PathElement *f1, PathElement *f2)
Node *Octree::connectFace(
Node *newnode, int st[3], int len, int dir, PathElement *f1, PathElement *f2)
{
#ifdef IN_DEBUG_MODE
dc_printf("Call to CONNECTFACE with direction %d and length %d path: \n", dir, len);
dc_printf("Path(low side): \n");
printPath(f1);
// checkPath(f1);
dc_printf("Path(high side): \n");
printPath(f2);
// checkPath(f2);
dc_printf("Call to CONNECTFACE with direction %d and length %d path: \n", dir, len);
dc_printf("Path(low side): \n");
printPath(f1);
// checkPath(f1);
dc_printf("Path(high side): \n");
printPath(f2);
// checkPath(f2);
#endif
// Setup 2D
int pos = st[dir] + len / 2;
int xdir = (dir + 1) % 3;
int ydir = (dir + 2) % 3;
// Setup 2D
int pos = st[dir] + len / 2;
int xdir = (dir + 1) % 3;
int ydir = (dir + 2) % 3;
// Use existing intersections on f1 and f2
int x1, y1, x2, y2;
float p1, q1, p2, q2;
// Use existing intersections on f1 and f2
int x1, y1, x2, y2;
float p1, q1, p2, q2;
getFacePoint(f2->next, dir, x1, y1, p1, q1);
getFacePoint(f2, dir, x2, y2, p2, q2);
getFacePoint(f2->next, dir, x1, y1, p1, q1);
getFacePoint(f2, dir, x2, y2, p2, q2);
float dx = x2 + p2 - x1 - p1;
float dy = y2 + q2 - y1 - q1;
float dx = x2 + p2 - x1 - p1;
float dy = y2 + q2 - y1 - q1;
// Do adapted Bresenham line drawing
float rx = p1, ry = q1;
int incx = 1, incy = 1;
int lx = x1, ly = y1;
int hx = x2, hy = y2;
int choice;
if (x2 < x1) {
incx = -1;
rx = 1 - rx;
lx = x2;
hx = x1;
}
if (y2 < y1) {
incy = -1;
ry = 1 - ry;
ly = y2;
hy = y1;
}
// Do adapted Bresenham line drawing
float rx = p1, ry = q1;
int incx = 1, incy = 1;
int lx = x1, ly = y1;
int hx = x2, hy = y2;
int choice;
if (x2 < x1) {
incx = -1;
rx = 1 - rx;
lx = x2;
hx = x1;
}
if (y2 < y1) {
incy = -1;
ry = 1 - ry;
ly = y2;
hy = y1;
}
float sx = dx * incx;
float sy = dy * incy;
float sx = dx * incx;
float sy = dy * incy;
int ori[3];
ori[dir] = pos / mindimen;
ori[xdir] = x1;
ori[ydir] = y1;
int walkdir;
int inc;
float alpha;
int ori[3];
ori[dir] = pos / mindimen;
ori[xdir] = x1;
ori[ydir] = y1;
int walkdir;
int inc;
float alpha;
PathElement *curEleN = f1;
PathElement *curEleP = f2->next;
Node *nodeN = NULL, *nodeP = NULL;
LeafNode *curN = locateLeaf(&newnode->internal, len, f1->pos);
LeafNode *curP = locateLeaf(&newnode->internal, len, f2->next->pos);
if (curN == NULL || curP == NULL) {
exit(0);
}
int stN[3], stP[3];
int lenN, lenP;
PathElement *curEleN = f1;
PathElement *curEleP = f2->next;
Node *nodeN = NULL, *nodeP = NULL;
LeafNode *curN = locateLeaf(&newnode->internal, len, f1->pos);
LeafNode *curP = locateLeaf(&newnode->internal, len, f2->next->pos);
if (curN == NULL || curP == NULL) {
exit(0);
}
int stN[3], stP[3];
int lenN, lenP;
/* Unused code, leaving for posterity
/* Unused code, leaving for posterity
float stpt[3], edpt[3];
stpt[dir] = edpt[dir] =(float) pos;
stpt[xdir] =(x1 + p1) * mindimen;
stpt[ydir] =(y1 + q1) * mindimen;
edpt[xdir] =(x2 + p2) * mindimen;
edpt[ydir] =(y2 + q2) * mindimen;
*/
while (ori[xdir] != x2 || ori[ydir] != y2) {
int next;
if (sy * (1 - rx) > sx * (1 - ry)) {
choice = 1;
next = ori[ydir] + incy;
if (next < ly || next > hy) {
choice = 4;
next = ori[xdir] + incx;
}
}
else {
choice = 2;
next = ori[xdir] + incx;
if (next < lx || next > hx) {
choice = 3;
next = ori[ydir] + incy;
}
}
float stpt[3], edpt[3];
stpt[dir] = edpt[dir] =(float) pos;
stpt[xdir] =(x1 + p1) * mindimen;
stpt[ydir] =(y1 + q1) * mindimen;
edpt[xdir] =(x2 + p2) * mindimen;
edpt[ydir] =(y2 + q2) * mindimen;
*/
while (ori[xdir] != x2 || ori[ydir] != y2) {
int next;
if (sy * (1 - rx) > sx * (1 - ry)) {
choice = 1;
next = ori[ydir] + incy;
if (next < ly || next > hy) {
choice = 4;
next = ori[xdir] + incx;
}
}
else {
choice = 2;
next = ori[xdir] + incx;
if (next < lx || next > hx) {
choice = 3;
next = ori[ydir] + incy;
}
}
if (choice & 1) {
ori[ydir] = next;
if (choice == 1) {
rx += (sy == 0 ? 0 : (1 - ry) * sx / sy);
ry = 0;
}
if (choice & 1) {
ori[ydir] = next;
if (choice == 1) {
rx += (sy == 0 ? 0 : (1 - ry) * sx / sy);
ry = 0;
}
walkdir = 2;
inc = incy;
alpha = x2 < x1 ? 1 - rx : rx;
}
else {
ori[xdir] = next;
if (choice == 2) {
ry += (sx == 0 ? 0 : (1 - rx) * sy / sx);
rx = 0;
}
walkdir = 2;
inc = incy;
alpha = x2 < x1 ? 1 - rx : rx;
}
else {
ori[xdir] = next;
if (choice == 2) {
ry += (sx == 0 ? 0 : (1 - rx) * sy / sx);
rx = 0;
}
walkdir = 1;
inc = incx;
alpha = y2 < y1 ? 1 - ry : ry;
}
walkdir = 1;
inc = incx;
alpha = y2 < y1 ? 1 - ry : ry;
}
// Get the exact location of the marcher
int nori[3] = {ori[0] * mindimen, ori[1] * mindimen, ori[2] * mindimen};
float spt[3] = {(float)nori[0], (float)nori[1], (float)nori[2]};
spt[(dir + (3 - walkdir)) % 3] += alpha * mindimen;
if (inc < 0) {
spt[(dir + walkdir) % 3] += mindimen;
}
// dc_printf("new x,y: %d %d\n", ori[xdir] / edgelen, ori[ydir] / edgelen);
// dc_printf("nori: %d %d %d alpha: %f walkdir: %d\n", nori[0], nori[1], nori[2], alpha, walkdir);
// dc_printf("%f %f %f\n", spt[0], spt[1], spt[2]);
// Get the exact location of the marcher
int nori[3] = {ori[0] * mindimen, ori[1] * mindimen, ori[2] * mindimen};
float spt[3] = {(float) nori[0], (float) nori[1], (float) nori[2]};
spt[(dir + (3 - walkdir)) % 3] += alpha * mindimen;
if (inc < 0) {
spt[(dir + walkdir) % 3] += mindimen;
}
// Locate the current cells on both sides
newnode = locateCell(&newnode->internal, st, len, nori, dir, 1, nodeN, stN, lenN);
newnode = locateCell(&newnode->internal, st, len, nori, dir, 0, nodeP, stP, lenP);
// dc_printf("new x,y: %d %d\n", ori[xdir] / edgelen, ori[ydir] / edgelen);
// dc_printf("nori: %d %d %d alpha: %f walkdir: %d\n", nori[0], nori[1], nori[2], alpha, walkdir);
// dc_printf("%f %f %f\n", spt[0], spt[1], spt[2]);
updateParent(&newnode->internal, len, st);
// Locate the current cells on both sides
newnode = locateCell(&newnode->internal, st, len, nori, dir, 1, nodeN, stN, lenN);
newnode = locateCell(&newnode->internal, st, len, nori, dir, 0, nodeP, stP, lenP);
int flag = 0;
// Add the cells to the rings and fill in the patch
PathElement *newEleN;
if (curEleN->pos[0] != stN[0] || curEleN->pos[1] != stN[1] || curEleN->pos[2] != stN[2]) {
if (curEleN->next->pos[0] != stN[0] || curEleN->next->pos[1] != stN[1] ||
curEleN->next->pos[2] != stN[2]) {
newEleN = new PathElement;
newEleN->next = curEleN->next;
newEleN->pos[0] = stN[0];
newEleN->pos[1] = stN[1];
newEleN->pos[2] = stN[2];
updateParent(&newnode->internal, len, st);
curEleN->next = newEleN;
}
else {
newEleN = curEleN->next;
}
curN = patchAdjacent(&newnode->internal,
len,
curEleN->pos,
curN,
newEleN->pos,
(LeafNode *)nodeN,
walkdir,
inc,
dir,
1,
alpha);
int flag = 0;
// Add the cells to the rings and fill in the patch
PathElement *newEleN;
if (curEleN->pos[0] != stN[0] || curEleN->pos[1] != stN[1] || curEleN->pos[2] != stN[2]) {
if (curEleN->next->pos[0] != stN[0] || curEleN->next->pos[1] != stN[1] || curEleN->next->pos[2] != stN[2]) {
newEleN = new PathElement;
newEleN->next = curEleN->next;
newEleN->pos[0] = stN[0];
newEleN->pos[1] = stN[1];
newEleN->pos[2] = stN[2];
curEleN = newEleN;
flag++;
}
curEleN->next = newEleN;
}
else {
newEleN = curEleN->next;
}
curN = patchAdjacent(&newnode->internal, len, curEleN->pos, curN,
newEleN->pos, (LeafNode *)nodeN, walkdir,
inc, dir, 1, alpha);
PathElement *newEleP;
if (curEleP->pos[0] != stP[0] || curEleP->pos[1] != stP[1] || curEleP->pos[2] != stP[2]) {
if (f2->pos[0] != stP[0] || f2->pos[1] != stP[1] || f2->pos[2] != stP[2]) {
newEleP = new PathElement;
newEleP->next = curEleP;
newEleP->pos[0] = stP[0];
newEleP->pos[1] = stP[1];
newEleP->pos[2] = stP[2];
curEleN = newEleN;
flag++;
}
f2->next = newEleP;
}
else {
newEleP = f2;
}
curP = patchAdjacent(&newnode->internal,
len,
curEleP->pos,
curP,
newEleP->pos,
(LeafNode *)nodeP,
walkdir,
inc,
dir,
0,
alpha);
PathElement *newEleP;
if (curEleP->pos[0] != stP[0] || curEleP->pos[1] != stP[1] || curEleP->pos[2] != stP[2]) {
if (f2->pos[0] != stP[0] || f2->pos[1] != stP[1] || f2->pos[2] != stP[2]) {
newEleP = new PathElement;
newEleP->next = curEleP;
newEleP->pos[0] = stP[0];
newEleP->pos[1] = stP[1];
newEleP->pos[2] = stP[2];
curEleP = newEleP;
flag++;
}
f2->next = newEleP;
}
else {
newEleP = f2;
}
curP = patchAdjacent(&newnode->internal, len, curEleP->pos, curP,
newEleP->pos, (LeafNode *)nodeP, walkdir,
inc, dir, 0, alpha);
curEleP = newEleP;
flag++;
}
/*
if(flag == 0) {
dc_printf("error: non-synchronized patching! at \n");
}
*/
}
/*
if(flag == 0) {
dc_printf("error: non-synchronized patching! at \n");
}
*/
}
#ifdef IN_DEBUG_MODE
dc_printf("Return from CONNECTFACE with \n");
dc_printf("Path(low side):\n");
printPath(f1);
checkPath(f1);
dc_printf("Path(high side):\n");
printPath(f2);
checkPath(f2);
dc_printf("Return from CONNECTFACE with \n");
dc_printf("Path(low side):\n");
printPath(f1);
checkPath(f1);
dc_printf("Path(high side):\n");
printPath(f2);
checkPath(f2);
#endif
return newnode;
return newnode;
}
LeafNode *Octree::patchAdjacent(InternalNode *node, int len, int st1[3],
LeafNode *leaf1, int st2[3], LeafNode *leaf2,
int walkdir, int inc, int dir, int side,
LeafNode *Octree::patchAdjacent(InternalNode *node,
int len,
int st1[3],
LeafNode *leaf1,
int st2[3],
LeafNode *leaf2,
int walkdir,
int inc,
int dir,
int side,
float alpha)
{
#ifdef IN_DEBUG_MODE
dc_printf("Before patching.\n");
printInfo(st1);
printInfo(st2);
dc_printf("-----------------%d %d %d; %d %d %d\n", st1[0], st2[1], st1[2], st2[0], st2[1], st2[2]);
dc_printf("Before patching.\n");
printInfo(st1);
printInfo(st2);
dc_printf(
"-----------------%d %d %d; %d %d %d\n", st1[0], st2[1], st1[2], st2[0], st2[1], st2[2]);
#endif
// Get edge index on each leaf
int edgedir = (dir + (3 - walkdir)) % 3;
int incdir = (dir + walkdir) % 3;
int ind1 = (edgedir == 1 ? (dir + 3 - edgedir) % 3 - 1 : 2 - (dir + 3 - edgedir) % 3);
int ind2 = (edgedir == 1 ? (incdir + 3 - edgedir) % 3 - 1 : 2 - (incdir + 3 - edgedir) % 3);
// Get edge index on each leaf
int edgedir = (dir + (3 - walkdir)) % 3;
int incdir = (dir + walkdir) % 3;
int ind1 = (edgedir == 1 ? (dir + 3 - edgedir) % 3 - 1 : 2 - (dir + 3 - edgedir) % 3);
int ind2 = (edgedir == 1 ? (incdir + 3 - edgedir) % 3 - 1 : 2 - (incdir + 3 - edgedir) % 3);
int eind1 = ((edgedir << 2) | (side << ind1) | ((inc > 0 ? 1 : 0) << ind2));
int eind2 = ((edgedir << 2) | (side << ind1) | ((inc > 0 ? 0 : 1) << ind2));
int eind1 = ((edgedir << 2) | (side << ind1) | ((inc > 0 ? 1 : 0) << ind2));
int eind2 = ((edgedir << 2) | (side << ind1) | ((inc > 0 ? 0 : 1) << ind2));
#ifdef IN_DEBUG_MODE
dc_printf("Index 1: %d Alpha 1: %f Index 2: %d Alpha 2: %f\n", eind1, alpha, eind2, alpha);
/*
if(alpha < 0 || alpha > 1) {
dc_printf("Index 1: %d Alpha 1: %f Index 2: %d Alpha 2: %f\n", eind1, alpha, eind2, alpha);
printInfo(st1);
printInfo(st2);
}
*/
dc_printf("Index 1: %d Alpha 1: %f Index 2: %d Alpha 2: %f\n", eind1, alpha, eind2, alpha);
/*
if(alpha < 0 || alpha > 1) {
dc_printf("Index 1: %d Alpha 1: %f Index 2: %d Alpha 2: %f\n", eind1, alpha, eind2, alpha);
printInfo(st1);
printInfo(st2);
}
*/
#endif
// Flip edge parity
LeafNode *nleaf1 = flipEdge(leaf1, eind1, alpha);
LeafNode *nleaf2 = flipEdge(leaf2, eind2, alpha);
// Flip edge parity
LeafNode *nleaf1 = flipEdge(leaf1, eind1, alpha);
LeafNode *nleaf2 = flipEdge(leaf2, eind2, alpha);
// Update parent link
updateParent(node, len, st1, nleaf1);
updateParent(node, len, st2, nleaf2);
// updateParent(nleaf1, mindimen, st1);
// updateParent(nleaf2, mindimen, st2);
// Update parent link
updateParent(node, len, st1, nleaf1);
updateParent(node, len, st2, nleaf2);
// updateParent(nleaf1, mindimen, st1);
// updateParent(nleaf2, mindimen, st2);
/*
float m[3];
dc_printf("Adding new point: %f %f %f\n", spt[0], spt[1], spt[2]);
getMinimizer(leaf1, m);
dc_printf("Cell %d now has minimizer %f %f %f\n", leaf1, m[0], m[1], m[2]);
getMinimizer(leaf2, m);
dc_printf("Cell %d now has minimizer %f %f %f\n", leaf2, m[0], m[1], m[2]);
*/
/*
float m[3];
dc_printf("Adding new point: %f %f %f\n", spt[0], spt[1], spt[2]);
getMinimizer(leaf1, m);
dc_printf("Cell %d now has minimizer %f %f %f\n", leaf1, m[0], m[1], m[2]);
getMinimizer(leaf2, m);
dc_printf("Cell %d now has minimizer %f %f %f\n", leaf2, m[0], m[1], m[2]);
*/
#ifdef IN_DEBUG_MODE
dc_printf("After patching.\n");
printInfo(st1);
printInfo(st2);
dc_printf("After patching.\n");
printInfo(st1);
printInfo(st2);
#endif
return nleaf2;
return nleaf2;
}
Node *Octree::locateCell(InternalNode *node, int st[3], int len, int ori[3], int dir, int side, Node *& rleaf, int rst[3], int& rlen)
Node *Octree::locateCell(InternalNode *node,
int st[3],
int len,
int ori[3],
int dir,
int side,
Node *&rleaf,
int rst[3],
int &rlen)
{
#ifdef IN_DEBUG_MODE
// dc_printf("Call to LOCATECELL with node ");
// printNode(node);
// dc_printf("Call to LOCATECELL with node ");
// printNode(node);
#endif
int i;
len >>= 1;
int ind = 0;
for (i = 0; i < 3; i++) {
ind <<= 1;
if (i == dir && side == 1) {
ind |= (ori[i] <= (st[i] + len) ? 0 : 1);
}
else {
ind |= (ori[i] < (st[i] + len) ? 0 : 1);
}
}
int i;
len >>= 1;
int ind = 0;
for (i = 0; i < 3; i++) {
ind <<= 1;
if (i == dir && side == 1) {
ind |= (ori[i] <= (st[i] + len) ? 0 : 1);
}
else {
ind |= (ori[i] < (st[i] + len) ? 0 : 1);
}
}
#ifdef IN_DEBUG_MODE
// dc_printf("In LOCATECELL index of ori(%d %d %d) with dir %d side %d in st(%d %d %d, %d) is: %d\n",
// ori[0], ori[1], ori[2], dir, side, st[0], st[1], st[2], len, ind);
// dc_printf("In LOCATECELL index of ori(%d %d %d) with dir %d side %d in st(%d %d %d, %d) is: %d\n",
// ori[0], ori[1], ori[2], dir, side, st[0], st[1], st[2], len, ind);
#endif
rst[0] = st[0] + vertmap[ind][0] * len;
rst[1] = st[1] + vertmap[ind][1] * len;
rst[2] = st[2] + vertmap[ind][2] * len;
rst[0] = st[0] + vertmap[ind][0] * len;
rst[1] = st[1] + vertmap[ind][1] * len;
rst[2] = st[2] + vertmap[ind][2] * len;
if (node->has_child(ind)) {
int count = node->get_child_count(ind);
Node *chd = node->get_child(count);
if (node->is_child_leaf(ind)) {
rleaf = chd;
rlen = len;
}
else {
// Recur
node->set_child(count, locateCell(&chd->internal, rst, len, ori, dir, side, rleaf, rst, rlen));
}
}
else {
// Create a new child here
if (len == mindimen) {
LeafNode *chd = createLeaf(0);
node = addChild(node, ind, (Node *)chd, 1);
rleaf = (Node *)chd;
rlen = len;
}
else {
// Subdivide the empty cube
InternalNode *chd = createInternal(0);
node = addChild(node, ind,
locateCell(chd, rst, len, ori, dir, side, rleaf, rst, rlen), 0);
}
}
if (node->has_child(ind)) {
int count = node->get_child_count(ind);
Node *chd = node->get_child(count);
if (node->is_child_leaf(ind)) {
rleaf = chd;
rlen = len;
}
else {
// Recur
node->set_child(count,
locateCell(&chd->internal, rst, len, ori, dir, side, rleaf, rst, rlen));
}
}
else {
// Create a new child here
if (len == mindimen) {
LeafNode *chd = createLeaf(0);
node = addChild(node, ind, (Node *)chd, 1);
rleaf = (Node *)chd;
rlen = len;
}
else {
// Subdivide the empty cube
InternalNode *chd = createInternal(0);
node = addChild(node, ind, locateCell(chd, rst, len, ori, dir, side, rleaf, rst, rlen), 0);
}
}
#ifdef IN_DEBUG_MODE
// dc_printf("Return from LOCATECELL with node ");
// printNode(newnode);
// dc_printf("Return from LOCATECELL with node ");
// printNode(newnode);
#endif
return (Node *)node;
return (Node *)node;
}
void Octree::checkElement(PathElement * /*ele*/)
{
/*
if(ele != NULL && locateLeafCheck(ele->pos) != ele->node) {
dc_printf("Screwed! at pos: %d %d %d\n", ele->pos[0]>>minshift, ele->pos[1]>>minshift, ele->pos[2]>>minshift);
exit(0);
}
*/
/*
if(ele != NULL && locateLeafCheck(ele->pos) != ele->node) {
dc_printf("Screwed! at pos: %d %d %d\n", ele->pos[0]>>minshift, ele->pos[1]>>minshift, ele->pos[2]>>minshift);
exit(0);
}
*/
}
void Octree::checkPath(PathElement *path)
{
PathElement *n = path;
int same = 0;
while (n && (same == 0 || n != path)) {
same++;
checkElement(n);
n = n->next;
}
PathElement *n = path;
int same = 0;
while (n && (same == 0 || n != path)) {
same++;
checkElement(n);
n = n->next;
}
}
void Octree::testFacePoint(PathElement *e1, PathElement *e2)
{
int i;
PathElement *e = NULL;
for (i = 0; i < 3; i++) {
if (e1->pos[i] != e2->pos[i]) {
if (e1->pos[i] < e2->pos[i]) {
e = e2;
}
else {
e = e1;
}
break;
}
}
int i;
PathElement *e = NULL;
for (i = 0; i < 3; i++) {
if (e1->pos[i] != e2->pos[i]) {
if (e1->pos[i] < e2->pos[i]) {
e = e2;
}
else {
e = e1;
}
break;
}
}
int x, y;
float p, q;
dc_printf("Test.");
getFacePoint(e, i, x, y, p, q);
int x, y;
float p, q;
dc_printf("Test.");
getFacePoint(e, i, x, y, p, q);
}
void Octree::getFacePoint(PathElement *leaf, int dir, int& x, int& y, float& p, float& q)
void Octree::getFacePoint(PathElement *leaf, int dir, int &x, int &y, float &p, float &q)
{
// Find average intersections
float avg[3] = {0, 0, 0};
float off[3];
int num = 0, num2 = 0;
// Find average intersections
float avg[3] = {0, 0, 0};
float off[3];
int num = 0, num2 = 0;
LeafNode *leafnode = locateLeaf(leaf->pos);
for (int i = 0; i < 4; i++) {
int edgeind = faceMap[dir * 2][i];
int nst[3];
for (int j = 0; j < 3; j++) {
nst[j] = leaf->pos[j] + mindimen * vertmap[edgemap[edgeind][0]][j];
}
LeafNode *leafnode = locateLeaf(leaf->pos);
for (int i = 0; i < 4; i++) {
int edgeind = faceMap[dir * 2][i];
int nst[3];
for (int j = 0; j < 3; j++) {
nst[j] = leaf->pos[j] + mindimen * vertmap[edgemap[edgeind][0]][j];
}
if (getEdgeIntersectionByIndex(nst, edgeind / 4, off, 1)) {
avg[0] += off[0];
avg[1] += off[1];
avg[2] += off[2];
num++;
}
if (getEdgeParity(leafnode, edgeind)) {
num2++;
}
}
if (num == 0) {
dc_printf("Wrong! dir: %d pos: %d %d %d num: %d\n", dir, leaf->pos[0] >> minshift, leaf->pos[1] >> minshift, leaf->pos[2] >> minshift, num2);
avg[0] = (float) leaf->pos[0];
avg[1] = (float) leaf->pos[1];
avg[2] = (float) leaf->pos[2];
}
else {
if (getEdgeIntersectionByIndex(nst, edgeind / 4, off, 1)) {
avg[0] += off[0];
avg[1] += off[1];
avg[2] += off[2];
num++;
}
if (getEdgeParity(leafnode, edgeind)) {
num2++;
}
}
if (num == 0) {
dc_printf("Wrong! dir: %d pos: %d %d %d num: %d\n",
dir,
leaf->pos[0] >> minshift,
leaf->pos[1] >> minshift,
leaf->pos[2] >> minshift,
num2);
avg[0] = (float)leaf->pos[0];
avg[1] = (float)leaf->pos[1];
avg[2] = (float)leaf->pos[2];
}
else {
avg[0] /= num;
avg[1] /= num;
avg[2] /= num;
avg[0] /= num;
avg[1] /= num;
avg[2] /= num;
//avg[0] =(float) leaf->pos[0];
//avg[1] =(float) leaf->pos[1];
//avg[2] =(float) leaf->pos[2];
}
//avg[0] =(float) leaf->pos[0];
//avg[1] =(float) leaf->pos[1];
//avg[2] =(float) leaf->pos[2];
}
int xdir = (dir + 1) % 3;
int ydir = (dir + 2) % 3;
int xdir = (dir + 1) % 3;
int ydir = (dir + 2) % 3;
float xf = avg[xdir];
float yf = avg[ydir];
float xf = avg[xdir];
float yf = avg[ydir];
#ifdef IN_DEBUG_MODE
// Is it outside?
// PathElement* leaf = leaf1->len < leaf2->len ? leaf1 : leaf2;
/*
float* m =(leaf == leaf1 ? m1 : m2);
if(xf < leaf->pos[xdir] ||
yf < leaf->pos[ydir] ||
xf > leaf->pos[xdir] + leaf->len ||
yf > leaf->pos[ydir] + leaf->len) {
dc_printf("Outside cube(%d %d %d), %d : %d %d %f %f\n", leaf->pos[0], leaf->pos[1], leaf->pos[2], leaf->len,
pos, dir, xf, yf);
// Is it outside?
// PathElement* leaf = leaf1->len < leaf2->len ? leaf1 : leaf2;
/*
float* m =(leaf == leaf1 ? m1 : m2);
if(xf < leaf->pos[xdir] ||
yf < leaf->pos[ydir] ||
xf > leaf->pos[xdir] + leaf->len ||
yf > leaf->pos[ydir] + leaf->len) {
dc_printf("Outside cube(%d %d %d), %d : %d %d %f %f\n", leaf->pos[0], leaf->pos[1], leaf->pos[2], leaf->len,
pos, dir, xf, yf);
// For now, snap to cell
xf = m[xdir];
yf = m[ydir];
}
*/
// For now, snap to cell
xf = m[xdir];
yf = m[ydir];
}
*/
/*
if(alpha < 0 || alpha > 1 ||
xf < leaf->pos[xdir] || xf > leaf->pos[xdir] + leaf->len ||
yf < leaf->pos[ydir] || yf > leaf->pos[ydir] + leaf->len) {
dc_printf("Alpha: %f Address: %d and %d\n", alpha, leaf1->node, leaf2->node);
dc_printf("GETFACEPOINT result:(%d %d %d) %d min:(%f %f %f);(%d %d %d) %d min:(%f %f %f).\n",
leaf1->pos[0], leaf1->pos[1], leaf1->pos[2], leaf1->len, m1[0], m1[1], m1[2],
leaf2->pos[0], leaf2->pos[1], leaf2->pos[2], leaf2->len, m2[0], m2[1], m2[2]);
dc_printf("Face point at dir %d pos %d: %f %f\n", dir, pos, xf, yf);
}
*/
/*
if(alpha < 0 || alpha > 1 ||
xf < leaf->pos[xdir] || xf > leaf->pos[xdir] + leaf->len ||
yf < leaf->pos[ydir] || yf > leaf->pos[ydir] + leaf->len) {
dc_printf("Alpha: %f Address: %d and %d\n", alpha, leaf1->node, leaf2->node);
dc_printf("GETFACEPOINT result:(%d %d %d) %d min:(%f %f %f);(%d %d %d) %d min:(%f %f %f).\n",
leaf1->pos[0], leaf1->pos[1], leaf1->pos[2], leaf1->len, m1[0], m1[1], m1[2],
leaf2->pos[0], leaf2->pos[1], leaf2->pos[2], leaf2->len, m2[0], m2[1], m2[2]);
dc_printf("Face point at dir %d pos %d: %f %f\n", dir, pos, xf, yf);
}
*/
#endif
// Get the integer and float part
x = ((leaf->pos[xdir]) >> minshift);
y = ((leaf->pos[ydir]) >> minshift);
// Get the integer and float part
x = ((leaf->pos[xdir]) >> minshift);
y = ((leaf->pos[ydir]) >> minshift);
p = (xf - leaf->pos[xdir]) / mindimen;
q = (yf - leaf->pos[ydir]) / mindimen;
p = (xf - leaf->pos[xdir]) / mindimen;
q = (yf - leaf->pos[ydir]) / mindimen;
#ifdef IN_DEBUG_MODE
dc_printf("Face point at dir %d : %f %f\n", dir, xf, yf);
dc_printf("Face point at dir %d : %f %f\n", dir, xf, yf);
#endif
}
int Octree::findPair(PathElement *head, int pos, int dir, PathElement *& pre1, PathElement *& pre2)
int Octree::findPair(PathElement *head, int pos, int dir, PathElement *&pre1, PathElement *&pre2)
{
int side = getSide(head, pos, dir);
PathElement *cur = head;
PathElement *anchor;
PathElement *ppre1, *ppre2;
int side = getSide(head, pos, dir);
PathElement *cur = head;
PathElement *anchor;
PathElement *ppre1, *ppre2;
// Start from this face, find a pair
anchor = cur;
ppre1 = cur;
cur = cur->next;
while (cur != anchor && (getSide(cur, pos, dir) == side)) {
ppre1 = cur;
cur = cur->next;
}
if (cur == anchor) {
// No pair found
return side;
}
// Start from this face, find a pair
anchor = cur;
ppre1 = cur;
cur = cur->next;
while (cur != anchor && (getSide(cur, pos, dir) == side)) {
ppre1 = cur;
cur = cur->next;
}
if (cur == anchor) {
// No pair found
return side;
}
side = getSide(cur, pos, dir);
ppre2 = cur;
cur = cur->next;
while (getSide(cur, pos, dir) == side) {
ppre2 = cur;
cur = cur->next;
}
side = getSide(cur, pos, dir);
ppre2 = cur;
cur = cur->next;
while (getSide(cur, pos, dir) == side) {
ppre2 = cur;
cur = cur->next;
}
// Switch pre1 and pre2 if we start from the higher side
if (side == -1) {
cur = ppre1;
ppre1 = ppre2;
ppre2 = cur;
}
// Switch pre1 and pre2 if we start from the higher side
if (side == -1) {
cur = ppre1;
ppre1 = ppre2;
ppre2 = cur;
}
pre1 = ppre1;
pre2 = ppre2;
pre1 = ppre1;
pre2 = ppre2;
return 0;
return 0;
}
int Octree::getSide(PathElement *e, int pos, int dir)
{
return (e->pos[dir] < pos ? -1 : 1);
return (e->pos[dir] < pos ? -1 : 1);
}
int Octree::isEqual(PathElement *e1, PathElement *e2)
{
return (e1->pos[0] == e2->pos[0] && e1->pos[1] == e2->pos[1] && e1->pos[2] == e2->pos[2]);
return (e1->pos[0] == e2->pos[0] && e1->pos[1] == e2->pos[1] && e1->pos[2] == e2->pos[2]);
}
void Octree::compressRing(PathElement *& ring)
void Octree::compressRing(PathElement *&ring)
{
if (ring == NULL) {
return;
}
if (ring == NULL) {
return;
}
#ifdef IN_DEBUG_MODE
dc_printf("Call to COMPRESSRING with path: \n");
printPath(ring);
dc_printf("Call to COMPRESSRING with path: \n");
printPath(ring);
#endif
PathElement *cur = ring->next->next;
PathElement *pre = ring->next;
PathElement *prepre = ring;
PathElement *anchor = prepre;
PathElement *cur = ring->next->next;
PathElement *pre = ring->next;
PathElement *prepre = ring;
PathElement *anchor = prepre;
do {
while (isEqual(cur, prepre)) {
// Delete
if (cur == prepre) {
// The ring has shrinked to a point
delete pre;
delete cur;
anchor = NULL;
break;
}
else {
prepre->next = cur->next;
delete pre;
delete cur;
pre = prepre->next;
cur = pre->next;
anchor = prepre;
}
}
do {
while (isEqual(cur, prepre)) {
// Delete
if (cur == prepre) {
// The ring has shrinked to a point
delete pre;
delete cur;
anchor = NULL;
break;
}
else {
prepre->next = cur->next;
delete pre;
delete cur;
pre = prepre->next;
cur = pre->next;
anchor = prepre;
}
}
if (anchor == NULL) {
break;
}
if (anchor == NULL) {
break;
}
prepre = pre;
pre = cur;
cur = cur->next;
} while (prepre != anchor);
prepre = pre;
pre = cur;
cur = cur->next;
} while (prepre != anchor);
ring = anchor;
ring = anchor;
#ifdef IN_DEBUG_MODE
dc_printf("Return from COMPRESSRING with path: \n");
printPath(ring);
dc_printf("Return from COMPRESSRING with path: \n");
printPath(ring);
#endif
}
void Octree::buildSigns()
{
// First build a lookup table
// dc_printf("Building up look up table...\n");
int size = 1 << 12;
unsigned char table[1 << 12];
for (int i = 0; i < size; i++) {
table[i] = 0;
}
for (int i = 0; i < 256; i++) {
int ind = 0;
for (int j = 11; j >= 0; j--) {
ind <<= 1;
if (((i >> edgemap[j][0]) & 1) ^ ((i >> edgemap[j][1]) & 1)) {
ind |= 1;
}
}
// First build a lookup table
// dc_printf("Building up look up table...\n");
int size = 1 << 12;
unsigned char table[1 << 12];
for (int i = 0; i < size; i++) {
table[i] = 0;
}
for (int i = 0; i < 256; i++) {
int ind = 0;
for (int j = 11; j >= 0; j--) {
ind <<= 1;
if (((i >> edgemap[j][0]) & 1) ^ ((i >> edgemap[j][1]) & 1)) {
ind |= 1;
}
}
table[ind] = i;
}
table[ind] = i;
}
// Next, traverse the grid
int sg = 1;
int cube[8];
buildSigns(table, root, 0, sg, cube);
// Next, traverse the grid
int sg = 1;
int cube[8];
buildSigns(table, root, 0, sg, cube);
}
void Octree::buildSigns(unsigned char table[], Node *node, int isLeaf, int sg, int rvalue[8])
{
if (node == NULL) {
for (int i = 0; i < 8; i++) {
rvalue[i] = sg;
}
return;
}
if (node == NULL) {
for (int i = 0; i < 8; i++) {
rvalue[i] = sg;
}
return;
}
if (isLeaf == 0) {
// Internal node
Node *chd[8];
int leaf[8];
node->internal.fill_children(chd, leaf);
if (isLeaf == 0) {
// Internal node
Node *chd[8];
int leaf[8];
node->internal.fill_children(chd, leaf);
// Get the signs at the corners of the first cube
rvalue[0] = sg;
int oris[8];
buildSigns(table, chd[0], leaf[0], sg, oris);
// Get the signs at the corners of the first cube
rvalue[0] = sg;
int oris[8];
buildSigns(table, chd[0], leaf[0], sg, oris);
// Get the rest
int cube[8];
for (int i = 1; i < 8; i++) {
buildSigns(table, chd[i], leaf[i], oris[i], cube);
rvalue[i] = cube[i];
}
// Get the rest
int cube[8];
for (int i = 1; i < 8; i++) {
buildSigns(table, chd[i], leaf[i], oris[i], cube);
rvalue[i] = cube[i];
}
}
else {
// Leaf node
generateSigns(&node->leaf, table, sg);
}
else {
// Leaf node
generateSigns(&node->leaf, table, sg);
for (int i = 0; i < 8; i++) {
rvalue[i] = getSign(&node->leaf, i);
}
}
for (int i = 0; i < 8; i++) {
rvalue[i] = getSign(&node->leaf, i);
}
}
}
void Octree::floodFill()
{
// int threshold =(int)((dimen/mindimen) *(dimen/mindimen) * 0.5f);
int st[3] = {0, 0, 0};
// int threshold =(int)((dimen/mindimen) *(dimen/mindimen) * 0.5f);
int st[3] = {0, 0, 0};
// First, check for largest component
// size stored in -threshold
clearProcessBits(root, maxDepth);
int threshold = floodFill(root, st, dimen, maxDepth, 0);
// First, check for largest component
// size stored in -threshold
clearProcessBits(root, maxDepth);
int threshold = floodFill(root, st, dimen, maxDepth, 0);
// Next remove
dc_printf("Largest component: %d\n", threshold);
threshold *= thresh;
dc_printf("Removing all components smaller than %d\n", threshold);
int st2[3] = {0, 0, 0};
clearProcessBits(root, maxDepth);
floodFill(root, st2, dimen, maxDepth, threshold);
// Next remove
dc_printf("Largest component: %d\n", threshold);
threshold *= thresh;
dc_printf("Removing all components smaller than %d\n", threshold);
int st2[3] = {0, 0, 0};
clearProcessBits(root, maxDepth);
floodFill(root, st2, dimen, maxDepth, threshold);
}
void Octree::clearProcessBits(Node *node, int height)
{
int i;
int i;
if (height == 0) {
// Leaf cell,
for (i = 0; i < 12; i++) {
setOutProcess(&node->leaf, i);
}
}
else {
// Internal cell, recur
int count = 0;
for (i = 0; i < 8; i++) {
if (node->internal.has_child(i)) {
clearProcessBits(node->internal.get_child(count), height - 1);
count++;
}
}
}
if (height == 0) {
// Leaf cell,
for (i = 0; i < 12; i++) {
setOutProcess(&node->leaf, i);
}
}
else {
// Internal cell, recur
int count = 0;
for (i = 0; i < 8; i++) {
if (node->internal.has_child(i)) {
clearProcessBits(node->internal.get_child(count), height - 1);
count++;
}
}
}
}
int Octree::floodFill(LeafNode *leaf, int st[3], int len, int /*height*/, int threshold)
{
int i, j;
int maxtotal = 0;
int i, j;
int maxtotal = 0;
// Leaf cell,
int par, inp;
// Leaf cell,
int par, inp;
// Test if the leaf has intersection edges
for (i = 0; i < 12; i++) {
par = getEdgeParity(leaf, i);
inp = isInProcess(leaf, i);
// Test if the leaf has intersection edges
for (i = 0; i < 12; i++) {
par = getEdgeParity(leaf, i);
inp = isInProcess(leaf, i);
if (par == 1 && inp == 0) {
// Intersection edge, hasn't been processed
// Let's start filling
GridQueue *queue = new GridQueue();
int total = 1;
if (par == 1 && inp == 0) {
// Intersection edge, hasn't been processed
// Let's start filling
GridQueue *queue = new GridQueue();
int total = 1;
// Set to in process
int mst[3];
mst[0] = st[0] + vertmap[edgemap[i][0]][0] * len;
mst[1] = st[1] + vertmap[edgemap[i][0]][1] * len;
mst[2] = st[2] + vertmap[edgemap[i][0]][2] * len;
int mdir = i / 4;
setInProcessAll(mst, mdir);
// Set to in process
int mst[3];
mst[0] = st[0] + vertmap[edgemap[i][0]][0] * len;
mst[1] = st[1] + vertmap[edgemap[i][0]][1] * len;
mst[2] = st[2] + vertmap[edgemap[i][0]][2] * len;
int mdir = i / 4;
setInProcessAll(mst, mdir);
// Put this edge into queue
queue->pushQueue(mst, mdir);
// Put this edge into queue
queue->pushQueue(mst, mdir);
// Queue processing
int nst[3], dir;
while (queue->popQueue(nst, dir) == 1) {
// dc_printf("nst: %d %d %d, dir: %d\n", nst[0]/mindimen, nst[1]/mindimen, nst[2]/mindimen, dir);
// locations
int stMask[3][3] = {
{0, 0 - len, 0 - len},
{0 - len, 0, 0 - len},
{0 - len, 0 - len, 0}
};
int cst[2][3];
for (j = 0; j < 3; j++) {
cst[0][j] = nst[j];
cst[1][j] = nst[j] + stMask[dir][j];
}
// Queue processing
int nst[3], dir;
while (queue->popQueue(nst, dir) == 1) {
// dc_printf("nst: %d %d %d, dir: %d\n", nst[0]/mindimen, nst[1]/mindimen, nst[2]/mindimen, dir);
// locations
int stMask[3][3] = {{0, 0 - len, 0 - len}, {0 - len, 0, 0 - len}, {0 - len, 0 - len, 0}};
int cst[2][3];
for (j = 0; j < 3; j++) {
cst[0][j] = nst[j];
cst[1][j] = nst[j] + stMask[dir][j];
}
// cells
LeafNode *cs[2];
for (j = 0; j < 2; j++) {
cs[j] = locateLeaf(cst[j]);
}
// cells
LeafNode *cs[2];
for (j = 0; j < 2; j++) {
cs[j] = locateLeaf(cst[j]);
}
// Middle sign
int s = getSign(cs[0], 0);
// Middle sign
int s = getSign(cs[0], 0);
// Masks
int fcCells[4] = {1, 0, 1, 0};
int fcEdges[3][4][3] = {
{{9, 2, 11}, {8, 1, 10}, {5, 1, 7}, {4, 2, 6}},
{{10, 6, 11}, {8, 5, 9}, {1, 5, 3}, {0, 6, 2}},
{{6, 10, 7}, {4, 9, 5}, {2, 9, 3}, {0, 10, 1}}
};
// Masks
int fcCells[4] = {1, 0, 1, 0};
int fcEdges[3][4][3] = {{{9, 2, 11}, {8, 1, 10}, {5, 1, 7}, {4, 2, 6}},
{{10, 6, 11}, {8, 5, 9}, {1, 5, 3}, {0, 6, 2}},
{{6, 10, 7}, {4, 9, 5}, {2, 9, 3}, {0, 10, 1}}};
// Search for neighboring connected intersection edges
for (int find = 0; find < 4; find++) {
int cind = fcCells[find];
int eind, edge;
if (s == 0) {
// Original order
for (eind = 0; eind < 3; eind++) {
edge = fcEdges[dir][find][eind];
if (getEdgeParity(cs[cind], edge) == 1) {
break;
}
}
}
else {
// Inverse order
for (eind = 2; eind >= 0; eind--) {
edge = fcEdges[dir][find][eind];
if (getEdgeParity(cs[cind], edge) == 1) {
break;
}
}
}
// Search for neighboring connected intersection edges
for (int find = 0; find < 4; find++) {
int cind = fcCells[find];
int eind, edge;
if (s == 0) {
// Original order
for (eind = 0; eind < 3; eind++) {
edge = fcEdges[dir][find][eind];
if (getEdgeParity(cs[cind], edge) == 1) {
break;
}
}
}
else {
// Inverse order
for (eind = 2; eind >= 0; eind--) {
edge = fcEdges[dir][find][eind];
if (getEdgeParity(cs[cind], edge) == 1) {
break;
}
}
}
if (eind == 3 || eind == -1) {
dc_printf("Wrong! this is not a consistent sign. %d\n", eind);
}
else {
int est[3];
est[0] = cst[cind][0] + vertmap[edgemap[edge][0]][0] * len;
est[1] = cst[cind][1] + vertmap[edgemap[edge][0]][1] * len;
est[2] = cst[cind][2] + vertmap[edgemap[edge][0]][2] * len;
int edir = edge / 4;
if (eind == 3 || eind == -1) {
dc_printf("Wrong! this is not a consistent sign. %d\n", eind);
}
else {
int est[3];
est[0] = cst[cind][0] + vertmap[edgemap[edge][0]][0] * len;
est[1] = cst[cind][1] + vertmap[edgemap[edge][0]][1] * len;
est[2] = cst[cind][2] + vertmap[edgemap[edge][0]][2] * len;
int edir = edge / 4;
if (isInProcess(cs[cind], edge) == 0) {
setInProcessAll(est, edir);
queue->pushQueue(est, edir);
// dc_printf("Pushed: est: %d %d %d, edir: %d\n", est[0]/len, est[1]/len, est[2]/len, edir);
total++;
}
}
}
}
if (isInProcess(cs[cind], edge) == 0) {
setInProcessAll(est, edir);
queue->pushQueue(est, edir);
// dc_printf("Pushed: est: %d %d %d, edir: %d\n", est[0]/len, est[1]/len, est[2]/len, edir);
total++;
}
}
}
}
dc_printf("Size of component: %d ", total);
dc_printf("Size of component: %d ", total);
if (threshold == 0) {
// Measuring stage
if (total > maxtotal) {
maxtotal = total;
}
dc_printf(".\n");
delete queue;
continue;
}
if (threshold == 0) {
// Measuring stage
if (total > maxtotal) {
maxtotal = total;
}
dc_printf(".\n");
delete queue;
continue;
}
if (total >= threshold) {
dc_printf("Maintained.\n");
delete queue;
continue;
}
dc_printf("Less then %d, removing...\n", threshold);
if (total >= threshold) {
dc_printf("Maintained.\n");
delete queue;
continue;
}
dc_printf("Less then %d, removing...\n", threshold);
// We have to remove this noise
// We have to remove this noise
// Flip parity
// setOutProcessAll(mst, mdir);
flipParityAll(mst, mdir);
// Flip parity
// setOutProcessAll(mst, mdir);
flipParityAll(mst, mdir);
// Put this edge into queue
queue->pushQueue(mst, mdir);
// Put this edge into queue
queue->pushQueue(mst, mdir);
// Queue processing
while (queue->popQueue(nst, dir) == 1) {
// dc_printf("nst: %d %d %d, dir: %d\n", nst[0]/mindimen, nst[1]/mindimen, nst[2]/mindimen, dir);
// locations
int stMask[3][3] = {
{0, 0 - len, 0 - len},
{0 - len, 0, 0 - len},
{0 - len, 0 - len, 0}
};
int cst[2][3];
for (j = 0; j < 3; j++) {
cst[0][j] = nst[j];
cst[1][j] = nst[j] + stMask[dir][j];
}
// Queue processing
while (queue->popQueue(nst, dir) == 1) {
// dc_printf("nst: %d %d %d, dir: %d\n", nst[0]/mindimen, nst[1]/mindimen, nst[2]/mindimen, dir);
// locations
int stMask[3][3] = {{0, 0 - len, 0 - len}, {0 - len, 0, 0 - len}, {0 - len, 0 - len, 0}};
int cst[2][3];
for (j = 0; j < 3; j++) {
cst[0][j] = nst[j];
cst[1][j] = nst[j] + stMask[dir][j];
}
// cells
LeafNode *cs[2];
for (j = 0; j < 2; j++)
cs[j] = locateLeaf(cst[j]);
// cells
LeafNode *cs[2];
for (j = 0; j < 2; j++)
cs[j] = locateLeaf(cst[j]);
// Middle sign
int s = getSign(cs[0], 0);
// Middle sign
int s = getSign(cs[0], 0);
// Masks
int fcCells[4] = {1, 0, 1, 0};
int fcEdges[3][4][3] = {
{{9, 2, 11}, {8, 1, 10}, {5, 1, 7}, {4, 2, 6}},
{{10, 6, 11}, {8, 5, 9}, {1, 5, 3}, {0, 6, 2}},
{{6, 10, 7}, {4, 9, 5}, {2, 9, 3}, {0, 10, 1}}
};
// Masks
int fcCells[4] = {1, 0, 1, 0};
int fcEdges[3][4][3] = {{{9, 2, 11}, {8, 1, 10}, {5, 1, 7}, {4, 2, 6}},
{{10, 6, 11}, {8, 5, 9}, {1, 5, 3}, {0, 6, 2}},
{{6, 10, 7}, {4, 9, 5}, {2, 9, 3}, {0, 10, 1}}};
// Search for neighboring connected intersection edges
for (int find = 0; find < 4; find++) {
int cind = fcCells[find];
int eind, edge;
if (s == 0) {
// Original order
for (eind = 0; eind < 3; eind++) {
edge = fcEdges[dir][find][eind];
if (isInProcess(cs[cind], edge) == 1) {
break;
}
}
}
else {
// Inverse order
for (eind = 2; eind >= 0; eind--) {
edge = fcEdges[dir][find][eind];
if (isInProcess(cs[cind], edge) == 1) {
break;
}
}
}
// Search for neighboring connected intersection edges
for (int find = 0; find < 4; find++) {
int cind = fcCells[find];
int eind, edge;
if (s == 0) {
// Original order
for (eind = 0; eind < 3; eind++) {
edge = fcEdges[dir][find][eind];
if (isInProcess(cs[cind], edge) == 1) {
break;
}
}
}
else {
// Inverse order
for (eind = 2; eind >= 0; eind--) {
edge = fcEdges[dir][find][eind];
if (isInProcess(cs[cind], edge) == 1) {
break;
}
}
}
if (eind == 3 || eind == -1) {
dc_printf("Wrong! this is not a consistent sign. %d\n", eind);
}
else {
int est[3];
est[0] = cst[cind][0] + vertmap[edgemap[edge][0]][0] * len;
est[1] = cst[cind][1] + vertmap[edgemap[edge][0]][1] * len;
est[2] = cst[cind][2] + vertmap[edgemap[edge][0]][2] * len;
int edir = edge / 4;
if (eind == 3 || eind == -1) {
dc_printf("Wrong! this is not a consistent sign. %d\n", eind);
}
else {
int est[3];
est[0] = cst[cind][0] + vertmap[edgemap[edge][0]][0] * len;
est[1] = cst[cind][1] + vertmap[edgemap[edge][0]][1] * len;
est[2] = cst[cind][2] + vertmap[edgemap[edge][0]][2] * len;
int edir = edge / 4;
if (getEdgeParity(cs[cind], edge) == 1) {
flipParityAll(est, edir);
queue->pushQueue(est, edir);
// dc_printf("Pushed: est: %d %d %d, edir: %d\n", est[0]/len, est[1]/len, est[2]/len, edir);
total++;
}
}
}
}
if (getEdgeParity(cs[cind], edge) == 1) {
flipParityAll(est, edir);
queue->pushQueue(est, edir);
// dc_printf("Pushed: est: %d %d %d, edir: %d\n", est[0]/len, est[1]/len, est[2]/len, edir);
total++;
}
}
}
}
delete queue;
}
}
delete queue;
}
}
return maxtotal;
return maxtotal;
}
int Octree::floodFill(Node *node, int st[3], int len, int height, int threshold)
{
int i;
int maxtotal = 0;
int i;
int maxtotal = 0;
if (height == 0) {
maxtotal = floodFill(&node->leaf, st, len, height, threshold);
}
else {
// Internal cell, recur
int count = 0;
len >>= 1;
for (i = 0; i < 8; i++) {
if (node->internal.has_child(i)) {
int nst[3];
nst[0] = st[0] + vertmap[i][0] * len;
nst[1] = st[1] + vertmap[i][1] * len;
nst[2] = st[2] + vertmap[i][2] * len;
if (height == 0) {
maxtotal = floodFill(&node->leaf, st, len, height, threshold);
}
else {
// Internal cell, recur
int count = 0;
len >>= 1;
for (i = 0; i < 8; i++) {
if (node->internal.has_child(i)) {
int nst[3];
nst[0] = st[0] + vertmap[i][0] * len;
nst[1] = st[1] + vertmap[i][1] * len;
nst[2] = st[2] + vertmap[i][2] * len;
int d = floodFill(node->internal.get_child(count), nst, len, height - 1, threshold);
if (d > maxtotal) {
maxtotal = d;
}
count++;
}
}
}
return maxtotal;
int d = floodFill(node->internal.get_child(count), nst, len, height - 1, threshold);
if (d > maxtotal) {
maxtotal = d;
}
count++;
}
}
}
return maxtotal;
}
void Octree::writeOut()
{
int numQuads = 0;
int numVertices = 0;
int numEdges = 0;
int numQuads = 0;
int numVertices = 0;
int numEdges = 0;
countIntersection(root, maxDepth, numQuads, numVertices, numEdges);
countIntersection(root, maxDepth, numQuads, numVertices, numEdges);
dc_printf("Vertices counted: %d Polys counted: %d \n", numVertices, numQuads);
output_mesh = alloc_output(numVertices, numQuads);
int offset = 0;
int st[3] = {0, 0, 0};
dc_printf("Vertices counted: %d Polys counted: %d \n", numVertices, numQuads);
output_mesh = alloc_output(numVertices, numQuads);
int offset = 0;
int st[3] = {0, 0, 0};
// First, output vertices
offset = 0;
actualVerts = 0;
actualQuads = 0;
// First, output vertices
offset = 0;
actualVerts = 0;
actualQuads = 0;
generateMinimizer(root, st, dimen, maxDepth, offset);
cellProcContour(root, 0, maxDepth);
dc_printf("Vertices written: %d Quads written: %d \n", offset, actualQuads);
generateMinimizer(root, st, dimen, maxDepth, offset);
cellProcContour(root, 0, maxDepth);
dc_printf("Vertices written: %d Quads written: %d \n", offset, actualQuads);
}
void Octree::countIntersection(Node *node, int height, int& nedge, int& ncell, int& nface)
void Octree::countIntersection(Node *node, int height, int &nedge, int &ncell, int &nface)
{
if (height > 0) {
int total = node->internal.get_num_children();
for (int i = 0; i < total; i++) {
countIntersection(node->internal.get_child(i), height - 1, nedge, ncell, nface);
}
}
else {
nedge += getNumEdges2(&node->leaf);
if (height > 0) {
int total = node->internal.get_num_children();
for (int i = 0; i < total; i++) {
countIntersection(node->internal.get_child(i), height - 1, nedge, ncell, nface);
}
}
else {
nedge += getNumEdges2(&node->leaf);
int smask = getSignMask(&node->leaf);
int smask = getSignMask(&node->leaf);
if (use_manifold) {
int comps = manifold_table[smask].comps;
ncell += comps;
}
else {
if (smask > 0 && smask < 255) {
ncell++;
}
}
if (use_manifold) {
int comps = manifold_table[smask].comps;
ncell += comps;
}
else {
if (smask > 0 && smask < 255) {
ncell++;
}
}
for (int i = 0; i < 3; i++) {
if (getFaceEdgeNum(&node->leaf, i * 2)) {
nface++;
}
}
}
for (int i = 0; i < 3; i++) {
if (getFaceEdgeNum(&node->leaf, i * 2)) {
nface++;
}
}
}
}
/* from http://eigen.tuxfamily.org/bz/show_bug.cgi?id=257 */
@@ -2099,751 +2121,713 @@ void pseudoInverse(const _Matrix_Type_ &a,
_Matrix_Type_ &result,
double epsilon = std::numeric_limits<typename _Matrix_Type_::Scalar>::epsilon())
{
Eigen::JacobiSVD< _Matrix_Type_ > svd = a.jacobiSvd(Eigen::ComputeFullU |
Eigen::ComputeFullV);
Eigen::JacobiSVD<_Matrix_Type_> svd = a.jacobiSvd(Eigen::ComputeFullU | Eigen::ComputeFullV);
typename _Matrix_Type_::Scalar tolerance = epsilon * std::max(a.cols(),
a.rows()) *
svd.singularValues().array().abs().maxCoeff();
typename _Matrix_Type_::Scalar tolerance = epsilon * std::max(a.cols(), a.rows()) *
svd.singularValues().array().abs().maxCoeff();
result = svd.matrixV() *
_Matrix_Type_((svd.singularValues().array().abs() >
tolerance).select(svd.singularValues().
array().inverse(), 0)).asDiagonal() *
svd.matrixU().adjoint();
result = svd.matrixV() *
_Matrix_Type_((svd.singularValues().array().abs() > tolerance)
.select(svd.singularValues().array().inverse(), 0))
.asDiagonal() *
svd.matrixU().adjoint();
}
static void solve_least_squares(const float halfA[], const float b[],
const float midpoint[], float rvalue[])
static void solve_least_squares(const float halfA[],
const float b[],
const float midpoint[],
float rvalue[])
{
/* calculate pseudo-inverse */
Eigen::MatrixXf A(3, 3), pinv(3, 3);
A << halfA[0], halfA[1], halfA[2],
halfA[1], halfA[3], halfA[4],
halfA[2], halfA[4], halfA[5];
pseudoInverse(A, pinv);
/* calculate pseudo-inverse */
Eigen::MatrixXf A(3, 3), pinv(3, 3);
A << halfA[0], halfA[1], halfA[2], halfA[1], halfA[3], halfA[4], halfA[2], halfA[4], halfA[5];
pseudoInverse(A, pinv);
Eigen::Vector3f b2(b), mp(midpoint), result;
b2 = b2 + A * -mp;
result = pinv * b2 + mp;
Eigen::Vector3f b2(b), mp(midpoint), result;
b2 = b2 + A * -mp;
result = pinv * b2 + mp;
for (int i = 0; i < 3; i++)
rvalue[i] = result(i);
for (int i = 0; i < 3; i++)
rvalue[i] = result(i);
}
static void mass_point(float mp[3], const float pts[12][3], const int parity[12])
{
int ec = 0;
int ec = 0;
for (int i = 0; i < 12; i++) {
if (parity[i]) {
const float *p = pts[i];
for (int i = 0; i < 12; i++) {
if (parity[i]) {
const float *p = pts[i];
mp[0] += p[0];
mp[1] += p[1];
mp[2] += p[2];
mp[0] += p[0];
mp[1] += p[1];
mp[2] += p[2];
ec++;
}
}
ec++;
}
}
if (ec == 0) {
return;
}
mp[0] /= ec;
mp[1] /= ec;
mp[2] /= ec;
if (ec == 0) {
return;
}
mp[0] /= ec;
mp[1] /= ec;
mp[2] /= ec;
}
static void minimize(float rvalue[3], float mp[3], const float pts[12][3],
const float norms[12][3], const int parity[12])
static void minimize(float rvalue[3],
float mp[3],
const float pts[12][3],
const float norms[12][3],
const int parity[12])
{
float ata[6] = {0, 0, 0, 0, 0, 0};
float atb[3] = {0, 0, 0};
int ec = 0;
float ata[6] = {0, 0, 0, 0, 0, 0};
float atb[3] = {0, 0, 0};
int ec = 0;
for (int i = 0; i < 12; i++) {
// if(getEdgeParity(leaf, i))
if (parity[i]) {
const float *norm = norms[i];
const float *p = pts[i];
for (int i = 0; i < 12; i++) {
// if(getEdgeParity(leaf, i))
if (parity[i]) {
const float *norm = norms[i];
const float *p = pts[i];
// QEF
ata[0] += (float)(norm[0] * norm[0]);
ata[1] += (float)(norm[0] * norm[1]);
ata[2] += (float)(norm[0] * norm[2]);
ata[3] += (float)(norm[1] * norm[1]);
ata[4] += (float)(norm[1] * norm[2]);
ata[5] += (float)(norm[2] * norm[2]);
// QEF
ata[0] += (float)(norm[0] * norm[0]);
ata[1] += (float)(norm[0] * norm[1]);
ata[2] += (float)(norm[0] * norm[2]);
ata[3] += (float)(norm[1] * norm[1]);
ata[4] += (float)(norm[1] * norm[2]);
ata[5] += (float)(norm[2] * norm[2]);
const float pn = p[0] * norm[0] + p[1] * norm[1] + p[2] * norm[2];
const float pn = p[0] * norm[0] + p[1] * norm[1] + p[2] * norm[2];
atb[0] += (float)(norm[0] * pn);
atb[1] += (float)(norm[1] * pn);
atb[2] += (float)(norm[2] * pn);
atb[0] += (float)(norm[0] * pn);
atb[1] += (float)(norm[1] * pn);
atb[2] += (float)(norm[2] * pn);
// Minimizer
mp[0] += p[0];
mp[1] += p[1];
mp[2] += p[2];
// Minimizer
mp[0] += p[0];
mp[1] += p[1];
mp[2] += p[2];
ec++;
}
}
ec++;
}
}
if (ec == 0) {
return;
}
mp[0] /= ec;
mp[1] /= ec;
mp[2] /= ec;
if (ec == 0) {
return;
}
mp[0] /= ec;
mp[1] /= ec;
mp[2] /= ec;
// Solve least squares
solve_least_squares(ata, atb, mp, rvalue);
// Solve least squares
solve_least_squares(ata, atb, mp, rvalue);
}
void Octree::computeMinimizer(const LeafNode *leaf, int st[3], int len,
float rvalue[3]) const
void Octree::computeMinimizer(const LeafNode *leaf, int st[3], int len, float rvalue[3]) const
{
// First, gather all edge intersections
float pts[12][3], norms[12][3];
int parity[12];
fillEdgeIntersections(leaf, st, len, pts, norms, parity);
// First, gather all edge intersections
float pts[12][3], norms[12][3];
int parity[12];
fillEdgeIntersections(leaf, st, len, pts, norms, parity);
switch (mode) {
case DUALCON_CENTROID:
rvalue[0] = (float) st[0] + len / 2;
rvalue[1] = (float) st[1] + len / 2;
rvalue[2] = (float) st[2] + len / 2;
break;
switch (mode) {
case DUALCON_CENTROID:
rvalue[0] = (float)st[0] + len / 2;
rvalue[1] = (float)st[1] + len / 2;
rvalue[2] = (float)st[2] + len / 2;
break;
case DUALCON_MASS_POINT:
rvalue[0] = rvalue[1] = rvalue[2] = 0;
mass_point(rvalue, pts, parity);
break;
case DUALCON_MASS_POINT:
rvalue[0] = rvalue[1] = rvalue[2] = 0;
mass_point(rvalue, pts, parity);
break;
default: {
// Sharp features */
default: {
// Sharp features */
// construct QEF and minimizer
float mp[3] = {0, 0, 0};
minimize(rvalue, mp, pts, norms, parity);
// construct QEF and minimizer
float mp[3] = {0, 0, 0};
minimize(rvalue, mp, pts, norms, parity);
/* Restraining the location of the minimizer */
float nh1 = hermite_num * len;
float nh2 = (1 + hermite_num) * len;
/* Restraining the location of the minimizer */
float nh1 = hermite_num * len;
float nh2 = (1 + hermite_num) * len;
if (rvalue[0] < st[0] - nh1 ||
rvalue[1] < st[1] - nh1 ||
rvalue[2] < st[2] - nh1 ||
if (rvalue[0] < st[0] - nh1 || rvalue[1] < st[1] - nh1 || rvalue[2] < st[2] - nh1 ||
rvalue[0] > st[0] + nh2 ||
rvalue[1] > st[1] + nh2 ||
rvalue[2] > st[2] + nh2)
{
// Use mass point instead
rvalue[0] = mp[0];
rvalue[1] = mp[1];
rvalue[2] = mp[2];
}
break;
}
}
rvalue[0] > st[0] + nh2 || rvalue[1] > st[1] + nh2 || rvalue[2] > st[2] + nh2) {
// Use mass point instead
rvalue[0] = mp[0];
rvalue[1] = mp[1];
rvalue[2] = mp[2];
}
break;
}
}
}
void Octree::generateMinimizer(Node *node, int st[3], int len, int height, int& offset)
void Octree::generateMinimizer(Node *node, int st[3], int len, int height, int &offset)
{
int i, j;
int i, j;
if (height == 0) {
// Leaf cell, generate
if (height == 0) {
// Leaf cell, generate
// First, find minimizer
float rvalue[3];
rvalue[0] = (float) st[0] + len / 2;
rvalue[1] = (float) st[1] + len / 2;
rvalue[2] = (float) st[2] + len / 2;
computeMinimizer(&node->leaf, st, len, rvalue);
// First, find minimizer
float rvalue[3];
rvalue[0] = (float)st[0] + len / 2;
rvalue[1] = (float)st[1] + len / 2;
rvalue[2] = (float)st[2] + len / 2;
computeMinimizer(&node->leaf, st, len, rvalue);
// Update
//float fnst[3];
for (j = 0; j < 3; j++) {
rvalue[j] = rvalue[j] * range / dimen + origin[j];
//fnst[j] = st[j] * range / dimen + origin[j];
}
// Update
//float fnst[3];
for (j = 0; j < 3; j++) {
rvalue[j] = rvalue[j] * range / dimen + origin[j];
//fnst[j] = st[j] * range / dimen + origin[j];
}
int mult = 0, smask = getSignMask(&node->leaf);
int mult = 0, smask = getSignMask(&node->leaf);
if (use_manifold) {
mult = manifold_table[smask].comps;
}
else {
if (smask > 0 && smask < 255) {
mult = 1;
}
}
if (use_manifold) {
mult = manifold_table[smask].comps;
}
else {
if (smask > 0 && smask < 255) {
mult = 1;
}
}
for (j = 0; j < mult; j++) {
add_vert(output_mesh, rvalue);
}
for (j = 0; j < mult; j++) {
add_vert(output_mesh, rvalue);
}
// Store the index
setMinimizerIndex(&node->leaf, offset);
// Store the index
setMinimizerIndex(&node->leaf, offset);
offset += mult;
}
else {
// Internal cell, recur
int count = 0;
len >>= 1;
for (i = 0; i < 8; i++) {
if (node->internal.has_child(i)) {
int nst[3];
nst[0] = st[0] + vertmap[i][0] * len;
nst[1] = st[1] + vertmap[i][1] * len;
nst[2] = st[2] + vertmap[i][2] * len;
offset += mult;
}
else {
// Internal cell, recur
int count = 0;
len >>= 1;
for (i = 0; i < 8; i++) {
if (node->internal.has_child(i)) {
int nst[3];
nst[0] = st[0] + vertmap[i][0] * len;
nst[1] = st[1] + vertmap[i][1] * len;
nst[2] = st[2] + vertmap[i][2] * len;
generateMinimizer(node->internal.get_child(count),
nst, len, height - 1, offset);
count++;
}
}
}
generateMinimizer(node->internal.get_child(count), nst, len, height - 1, offset);
count++;
}
}
}
}
void Octree::processEdgeWrite(Node *node[4], int /*depth*/[4], int /*maxdep*/, int dir)
{
//int color = 0;
//int color = 0;
int i = 3;
{
if (getEdgeParity((LeafNode *)(node[i]), processEdgeMask[dir][i])) {
int flip = 0;
int edgeind = processEdgeMask[dir][i];
if (getSign((LeafNode *)node[i], edgemap[edgeind][1]) > 0) {
flip = 1;
}
int i = 3;
{
if (getEdgeParity((LeafNode *)(node[i]), processEdgeMask[dir][i])) {
int flip = 0;
int edgeind = processEdgeMask[dir][i];
if (getSign((LeafNode *)node[i], edgemap[edgeind][1]) > 0) {
flip = 1;
}
int num = 0;
{
int ind[8];
if (use_manifold) {
int vind[2];
int seq[4] = {0, 1, 3, 2};
for (int k = 0; k < 4; k++) {
getMinimizerIndices((LeafNode *)(node[seq[k]]), processEdgeMask[dir][seq[k]], vind);
ind[num] = vind[0];
num++;
int num = 0;
{
int ind[8];
if (use_manifold) {
int vind[2];
int seq[4] = {0, 1, 3, 2};
for (int k = 0; k < 4; k++) {
getMinimizerIndices((LeafNode *)(node[seq[k]]), processEdgeMask[dir][seq[k]], vind);
ind[num] = vind[0];
num++;
if (vind[1] != -1) {
ind[num] = vind[1];
num++;
if (flip == 0) {
ind[num - 1] = vind[0];
ind[num - 2] = vind[1];
}
}
}
if (vind[1] != -1) {
ind[num] = vind[1];
num++;
if (flip == 0) {
ind[num - 1] = vind[0];
ind[num - 2] = vind[1];
}
}
}
/* we don't use the manifold option, but if it is
ever enabled again note that it can output
non-quads */
}
else {
if (flip) {
ind[0] = getMinimizerIndex((LeafNode *)(node[2]));
ind[1] = getMinimizerIndex((LeafNode *)(node[3]));
ind[2] = getMinimizerIndex((LeafNode *)(node[1]));
ind[3] = getMinimizerIndex((LeafNode *)(node[0]));
}
else {
ind[0] = getMinimizerIndex((LeafNode *)(node[0]));
ind[1] = getMinimizerIndex((LeafNode *)(node[1]));
ind[2] = getMinimizerIndex((LeafNode *)(node[3]));
ind[3] = getMinimizerIndex((LeafNode *)(node[2]));
}
/* we don't use the manifold option, but if it is
ever enabled again note that it can output
non-quads */
}
else {
if (flip) {
ind[0] = getMinimizerIndex((LeafNode *)(node[2]));
ind[1] = getMinimizerIndex((LeafNode *)(node[3]));
ind[2] = getMinimizerIndex((LeafNode *)(node[1]));
ind[3] = getMinimizerIndex((LeafNode *)(node[0]));
}
else {
ind[0] = getMinimizerIndex((LeafNode *)(node[0]));
ind[1] = getMinimizerIndex((LeafNode *)(node[1]));
ind[2] = getMinimizerIndex((LeafNode *)(node[3]));
ind[3] = getMinimizerIndex((LeafNode *)(node[2]));
}
add_quad(output_mesh, ind);
}
}
return;
}
else {
return;
}
}
add_quad(output_mesh, ind);
}
}
return;
}
else {
return;
}
}
}
void Octree::edgeProcContour(Node *node[4], int leaf[4], int depth[4], int maxdep, int dir)
{
if (!(node[0] && node[1] && node[2] && node[3])) {
return;
}
if (leaf[0] && leaf[1] && leaf[2] && leaf[3]) {
processEdgeWrite(node, depth, maxdep, dir);
}
else {
int i, j;
Node *chd[4][8];
for (j = 0; j < 4; j++) {
for (i = 0; i < 8; i++) {
chd[j][i] = ((!leaf[j]) && node[j]->internal.has_child(i)) ?
node[j]->internal.get_child(
node[j]->internal.get_child_count(i)) : NULL;
}
}
if (!(node[0] && node[1] && node[2] && node[3])) {
return;
}
if (leaf[0] && leaf[1] && leaf[2] && leaf[3]) {
processEdgeWrite(node, depth, maxdep, dir);
}
else {
int i, j;
Node *chd[4][8];
for (j = 0; j < 4; j++) {
for (i = 0; i < 8; i++) {
chd[j][i] = ((!leaf[j]) && node[j]->internal.has_child(i)) ?
node[j]->internal.get_child(node[j]->internal.get_child_count(i)) :
NULL;
}
}
// 2 edge calls
Node *ne[4];
int le[4];
int de[4];
for (i = 0; i < 2; i++) {
int c[4] = {edgeProcEdgeMask[dir][i][0],
edgeProcEdgeMask[dir][i][1],
edgeProcEdgeMask[dir][i][2],
edgeProcEdgeMask[dir][i][3]};
// 2 edge calls
Node *ne[4];
int le[4];
int de[4];
for (i = 0; i < 2; i++) {
int c[4] = {edgeProcEdgeMask[dir][i][0],
edgeProcEdgeMask[dir][i][1],
edgeProcEdgeMask[dir][i][2],
edgeProcEdgeMask[dir][i][3]};
for (int j = 0; j < 4; j++) {
if (leaf[j]) {
le[j] = leaf[j];
ne[j] = node[j];
de[j] = depth[j];
}
else {
le[j] = node[j]->internal.is_child_leaf(c[j]);
ne[j] = chd[j][c[j]];
de[j] = depth[j] - 1;
}
}
for (int j = 0; j < 4; j++) {
if (leaf[j]) {
le[j] = leaf[j];
ne[j] = node[j];
de[j] = depth[j];
}
else {
le[j] = node[j]->internal.is_child_leaf(c[j]);
ne[j] = chd[j][c[j]];
de[j] = depth[j] - 1;
}
}
edgeProcContour(ne, le, de, maxdep - 1, edgeProcEdgeMask[dir][i][4]);
}
}
edgeProcContour(ne, le, de, maxdep - 1, edgeProcEdgeMask[dir][i][4]);
}
}
}
void Octree::faceProcContour(Node *node[2], int leaf[2], int depth[2], int maxdep, int dir)
{
if (!(node[0] && node[1])) {
return;
}
if (!(node[0] && node[1])) {
return;
}
if (!(leaf[0] && leaf[1])) {
int i, j;
// Fill children nodes
Node *chd[2][8];
for (j = 0; j < 2; j++) {
for (i = 0; i < 8; i++) {
chd[j][i] = ((!leaf[j]) && node[j]->internal.has_child(i)) ?
node[j]->internal.get_child(
node[j]->internal.get_child_count(i)) : NULL;
}
}
if (!(leaf[0] && leaf[1])) {
int i, j;
// Fill children nodes
Node *chd[2][8];
for (j = 0; j < 2; j++) {
for (i = 0; i < 8; i++) {
chd[j][i] = ((!leaf[j]) && node[j]->internal.has_child(i)) ?
node[j]->internal.get_child(node[j]->internal.get_child_count(i)) :
NULL;
}
}
// 4 face calls
Node *nf[2];
int df[2];
int lf[2];
for (i = 0; i < 4; i++) {
int c[2] = {faceProcFaceMask[dir][i][0], faceProcFaceMask[dir][i][1]};
for (int j = 0; j < 2; j++) {
if (leaf[j]) {
lf[j] = leaf[j];
nf[j] = node[j];
df[j] = depth[j];
}
else {
lf[j] = node[j]->internal.is_child_leaf(c[j]);
nf[j] = chd[j][c[j]];
df[j] = depth[j] - 1;
}
}
faceProcContour(nf, lf, df, maxdep - 1, faceProcFaceMask[dir][i][2]);
}
// 4 face calls
Node *nf[2];
int df[2];
int lf[2];
for (i = 0; i < 4; i++) {
int c[2] = {faceProcFaceMask[dir][i][0], faceProcFaceMask[dir][i][1]};
for (int j = 0; j < 2; j++) {
if (leaf[j]) {
lf[j] = leaf[j];
nf[j] = node[j];
df[j] = depth[j];
}
else {
lf[j] = node[j]->internal.is_child_leaf(c[j]);
nf[j] = chd[j][c[j]];
df[j] = depth[j] - 1;
}
}
faceProcContour(nf, lf, df, maxdep - 1, faceProcFaceMask[dir][i][2]);
}
// 4 edge calls
int orders[2][4] = {{0, 0, 1, 1}, {0, 1, 0, 1}};
Node *ne[4];
int le[4];
int de[4];
// 4 edge calls
int orders[2][4] = {{0, 0, 1, 1}, {0, 1, 0, 1}};
Node *ne[4];
int le[4];
int de[4];
for (i = 0; i < 4; i++) {
int c[4] = {faceProcEdgeMask[dir][i][1], faceProcEdgeMask[dir][i][2],
faceProcEdgeMask[dir][i][3], faceProcEdgeMask[dir][i][4]};
int *order = orders[faceProcEdgeMask[dir][i][0]];
for (i = 0; i < 4; i++) {
int c[4] = {faceProcEdgeMask[dir][i][1],
faceProcEdgeMask[dir][i][2],
faceProcEdgeMask[dir][i][3],
faceProcEdgeMask[dir][i][4]};
int *order = orders[faceProcEdgeMask[dir][i][0]];
for (int j = 0; j < 4; j++) {
if (leaf[order[j]]) {
le[j] = leaf[order[j]];
ne[j] = node[order[j]];
de[j] = depth[order[j]];
}
else {
le[j] = node[order[j]]->internal.is_child_leaf(c[j]);
ne[j] = chd[order[j]][c[j]];
de[j] = depth[order[j]] - 1;
}
}
for (int j = 0; j < 4; j++) {
if (leaf[order[j]]) {
le[j] = leaf[order[j]];
ne[j] = node[order[j]];
de[j] = depth[order[j]];
}
else {
le[j] = node[order[j]]->internal.is_child_leaf(c[j]);
ne[j] = chd[order[j]][c[j]];
de[j] = depth[order[j]] - 1;
}
}
edgeProcContour(ne, le, de, maxdep - 1, faceProcEdgeMask[dir][i][5]);
}
}
edgeProcContour(ne, le, de, maxdep - 1, faceProcEdgeMask[dir][i][5]);
}
}
}
void Octree::cellProcContour(Node *node, int leaf, int depth)
{
if (node == NULL) {
return;
}
if (node == NULL) {
return;
}
if (!leaf) {
int i;
if (!leaf) {
int i;
// Fill children nodes
Node *chd[8];
for (i = 0; i < 8; i++) {
chd[i] = ((!leaf) && node->internal.has_child(i)) ?
node->internal.get_child(node->internal.get_child_count(i)) : NULL;
}
// Fill children nodes
Node *chd[8];
for (i = 0; i < 8; i++) {
chd[i] = ((!leaf) && node->internal.has_child(i)) ?
node->internal.get_child(node->internal.get_child_count(i)) :
NULL;
}
// 8 Cell calls
for (i = 0; i < 8; i++) {
cellProcContour(chd[i], node->internal.is_child_leaf(i), depth - 1);
}
// 8 Cell calls
for (i = 0; i < 8; i++) {
cellProcContour(chd[i], node->internal.is_child_leaf(i), depth - 1);
}
// 12 face calls
Node *nf[2];
int lf[2];
int df[2] = {depth - 1, depth - 1};
for (i = 0; i < 12; i++) {
int c[2] = {cellProcFaceMask[i][0], cellProcFaceMask[i][1]};
// 12 face calls
Node *nf[2];
int lf[2];
int df[2] = {depth - 1, depth - 1};
for (i = 0; i < 12; i++) {
int c[2] = {cellProcFaceMask[i][0], cellProcFaceMask[i][1]};
lf[0] = node->internal.is_child_leaf(c[0]);
lf[1] = node->internal.is_child_leaf(c[1]);
lf[0] = node->internal.is_child_leaf(c[0]);
lf[1] = node->internal.is_child_leaf(c[1]);
nf[0] = chd[c[0]];
nf[1] = chd[c[1]];
nf[0] = chd[c[0]];
nf[1] = chd[c[1]];
faceProcContour(nf, lf, df, depth - 1, cellProcFaceMask[i][2]);
}
faceProcContour(nf, lf, df, depth - 1, cellProcFaceMask[i][2]);
}
// 6 edge calls
Node *ne[4];
int le[4];
int de[4] = {depth - 1, depth - 1, depth - 1, depth - 1};
for (i = 0; i < 6; i++) {
int c[4] = {cellProcEdgeMask[i][0], cellProcEdgeMask[i][1], cellProcEdgeMask[i][2], cellProcEdgeMask[i][3]};
// 6 edge calls
Node *ne[4];
int le[4];
int de[4] = {depth - 1, depth - 1, depth - 1, depth - 1};
for (i = 0; i < 6; i++) {
int c[4] = {cellProcEdgeMask[i][0],
cellProcEdgeMask[i][1],
cellProcEdgeMask[i][2],
cellProcEdgeMask[i][3]};
for (int j = 0; j < 4; j++) {
le[j] = node->internal.is_child_leaf(c[j]);
ne[j] = chd[c[j]];
}
edgeProcContour(ne, le, de, depth - 1, cellProcEdgeMask[i][4]);
}
}
for (int j = 0; j < 4; j++) {
le[j] = node->internal.is_child_leaf(c[j]);
ne[j] = chd[c[j]];
}
edgeProcContour(ne, le, de, depth - 1, cellProcEdgeMask[i][4]);
}
}
}
void Octree::processEdgeParity(LeafNode *node[4], int /*depth*/[4], int /*maxdep*/, int dir)
{
int con = 0;
for (int i = 0; i < 4; i++) {
// Minimal cell
// if(op == 0)
{
if (getEdgeParity(node[i], processEdgeMask[dir][i])) {
con = 1;
break;
}
}
}
if (con == 1) {
for (int i = 0; i < 4; i++) {
setEdge(node[i], processEdgeMask[dir][i]);
}
}
int con = 0;
for (int i = 0; i < 4; i++) {
// Minimal cell
// if(op == 0)
{
if (getEdgeParity(node[i], processEdgeMask[dir][i])) {
con = 1;
break;
}
}
}
if (con == 1) {
for (int i = 0; i < 4; i++) {
setEdge(node[i], processEdgeMask[dir][i]);
}
}
}
void Octree::edgeProcParity(Node *node[4], int leaf[4], int depth[4], int maxdep, int dir)
{
if (!(node[0] && node[1] && node[2] && node[3])) {
return;
}
if (leaf[0] && leaf[1] && leaf[2] && leaf[3]) {
processEdgeParity((LeafNode **)node, depth, maxdep, dir);
}
else {
int i, j;
Node *chd[4][8];
for (j = 0; j < 4; j++) {
for (i = 0; i < 8; i++) {
chd[j][i] = ((!leaf[j]) && node[j]->internal.has_child(i)) ?
node[j]->internal.get_child( node[j]->internal.get_child_count(i)) : NULL;
}
}
if (!(node[0] && node[1] && node[2] && node[3])) {
return;
}
if (leaf[0] && leaf[1] && leaf[2] && leaf[3]) {
processEdgeParity((LeafNode **)node, depth, maxdep, dir);
}
else {
int i, j;
Node *chd[4][8];
for (j = 0; j < 4; j++) {
for (i = 0; i < 8; i++) {
chd[j][i] = ((!leaf[j]) && node[j]->internal.has_child(i)) ?
node[j]->internal.get_child(node[j]->internal.get_child_count(i)) :
NULL;
}
}
// 2 edge calls
Node *ne[4];
int le[4];
int de[4];
for (i = 0; i < 2; i++) {
int c[4] = {edgeProcEdgeMask[dir][i][0],
edgeProcEdgeMask[dir][i][1],
edgeProcEdgeMask[dir][i][2],
edgeProcEdgeMask[dir][i][3]};
// 2 edge calls
Node *ne[4];
int le[4];
int de[4];
for (i = 0; i < 2; i++) {
int c[4] = {edgeProcEdgeMask[dir][i][0],
edgeProcEdgeMask[dir][i][1],
edgeProcEdgeMask[dir][i][2],
edgeProcEdgeMask[dir][i][3]};
// int allleaf = 1;
for (int j = 0; j < 4; j++) {
// int allleaf = 1;
for (int j = 0; j < 4; j++) {
if (leaf[j]) {
le[j] = leaf[j];
ne[j] = node[j];
de[j] = depth[j];
}
else {
le[j] = node[j]->internal.is_child_leaf(c[j]);
ne[j] = chd[j][c[j]];
de[j] = depth[j] - 1;
if (leaf[j]) {
le[j] = leaf[j];
ne[j] = node[j];
de[j] = depth[j];
}
else {
le[j] = node[j]->internal.is_child_leaf(c[j]);
ne[j] = chd[j][c[j]];
de[j] = depth[j] - 1;
}
}
}
}
edgeProcParity(ne, le, de, maxdep - 1, edgeProcEdgeMask[dir][i][4]);
}
}
edgeProcParity(ne, le, de, maxdep - 1, edgeProcEdgeMask[dir][i][4]);
}
}
}
void Octree::faceProcParity(Node *node[2], int leaf[2], int depth[2], int maxdep, int dir)
{
if (!(node[0] && node[1])) {
return;
}
if (!(node[0] && node[1])) {
return;
}
if (!(leaf[0] && leaf[1])) {
int i, j;
// Fill children nodes
Node *chd[2][8];
for (j = 0; j < 2; j++) {
for (i = 0; i < 8; i++) {
chd[j][i] = ((!leaf[j]) && node[j]->internal.has_child(i)) ?
node[j]->internal.get_child(
node[j]->internal.get_child_count(i)) : NULL;
}
}
if (!(leaf[0] && leaf[1])) {
int i, j;
// Fill children nodes
Node *chd[2][8];
for (j = 0; j < 2; j++) {
for (i = 0; i < 8; i++) {
chd[j][i] = ((!leaf[j]) && node[j]->internal.has_child(i)) ?
node[j]->internal.get_child(node[j]->internal.get_child_count(i)) :
NULL;
}
}
// 4 face calls
Node *nf[2];
int df[2];
int lf[2];
for (i = 0; i < 4; i++) {
int c[2] = {faceProcFaceMask[dir][i][0], faceProcFaceMask[dir][i][1]};
for (int j = 0; j < 2; j++) {
if (leaf[j]) {
lf[j] = leaf[j];
nf[j] = node[j];
df[j] = depth[j];
}
else {
lf[j] = node[j]->internal.is_child_leaf(c[j]);
nf[j] = chd[j][c[j]];
df[j] = depth[j] - 1;
}
}
faceProcParity(nf, lf, df, maxdep - 1, faceProcFaceMask[dir][i][2]);
}
// 4 face calls
Node *nf[2];
int df[2];
int lf[2];
for (i = 0; i < 4; i++) {
int c[2] = {faceProcFaceMask[dir][i][0], faceProcFaceMask[dir][i][1]};
for (int j = 0; j < 2; j++) {
if (leaf[j]) {
lf[j] = leaf[j];
nf[j] = node[j];
df[j] = depth[j];
}
else {
lf[j] = node[j]->internal.is_child_leaf(c[j]);
nf[j] = chd[j][c[j]];
df[j] = depth[j] - 1;
}
}
faceProcParity(nf, lf, df, maxdep - 1, faceProcFaceMask[dir][i][2]);
}
// 4 edge calls
int orders[2][4] = {{0, 0, 1, 1}, {0, 1, 0, 1}};
Node *ne[4];
int le[4];
int de[4];
// 4 edge calls
int orders[2][4] = {{0, 0, 1, 1}, {0, 1, 0, 1}};
Node *ne[4];
int le[4];
int de[4];
for (i = 0; i < 4; i++) {
int c[4] = {faceProcEdgeMask[dir][i][1], faceProcEdgeMask[dir][i][2],
faceProcEdgeMask[dir][i][3], faceProcEdgeMask[dir][i][4]};
int *order = orders[faceProcEdgeMask[dir][i][0]];
for (i = 0; i < 4; i++) {
int c[4] = {faceProcEdgeMask[dir][i][1],
faceProcEdgeMask[dir][i][2],
faceProcEdgeMask[dir][i][3],
faceProcEdgeMask[dir][i][4]};
int *order = orders[faceProcEdgeMask[dir][i][0]];
for (int j = 0; j < 4; j++) {
if (leaf[order[j]]) {
le[j] = leaf[order[j]];
ne[j] = node[order[j]];
de[j] = depth[order[j]];
}
else {
le[j] = node[order[j]]->internal.is_child_leaf(c[j]);
ne[j] = chd[order[j]][c[j]];
de[j] = depth[order[j]] - 1;
}
}
for (int j = 0; j < 4; j++) {
if (leaf[order[j]]) {
le[j] = leaf[order[j]];
ne[j] = node[order[j]];
de[j] = depth[order[j]];
}
else {
le[j] = node[order[j]]->internal.is_child_leaf(c[j]);
ne[j] = chd[order[j]][c[j]];
de[j] = depth[order[j]] - 1;
}
}
edgeProcParity(ne, le, de, maxdep - 1, faceProcEdgeMask[dir][i][5]);
}
}
edgeProcParity(ne, le, de, maxdep - 1, faceProcEdgeMask[dir][i][5]);
}
}
}
void Octree::cellProcParity(Node *node, int leaf, int depth)
{
if (node == NULL) {
return;
}
if (node == NULL) {
return;
}
if (!leaf) {
int i;
if (!leaf) {
int i;
// Fill children nodes
Node *chd[8];
for (i = 0; i < 8; i++) {
chd[i] = ((!leaf) && node->internal.has_child(i)) ?
node->internal.get_child(node->internal.get_child_count(i)) : NULL;
}
// Fill children nodes
Node *chd[8];
for (i = 0; i < 8; i++) {
chd[i] = ((!leaf) && node->internal.has_child(i)) ?
node->internal.get_child(node->internal.get_child_count(i)) :
NULL;
}
// 8 Cell calls
for (i = 0; i < 8; i++) {
cellProcParity(chd[i], node->internal.is_child_leaf(i), depth - 1);
}
// 8 Cell calls
for (i = 0; i < 8; i++) {
cellProcParity(chd[i], node->internal.is_child_leaf(i), depth - 1);
}
// 12 face calls
Node *nf[2];
int lf[2];
int df[2] = {depth - 1, depth - 1};
for (i = 0; i < 12; i++) {
int c[2] = {cellProcFaceMask[i][0], cellProcFaceMask[i][1]};
// 12 face calls
Node *nf[2];
int lf[2];
int df[2] = {depth - 1, depth - 1};
for (i = 0; i < 12; i++) {
int c[2] = {cellProcFaceMask[i][0], cellProcFaceMask[i][1]};
lf[0] = node->internal.is_child_leaf(c[0]);
lf[1] = node->internal.is_child_leaf(c[1]);
lf[0] = node->internal.is_child_leaf(c[0]);
lf[1] = node->internal.is_child_leaf(c[1]);
nf[0] = chd[c[0]];
nf[1] = chd[c[1]];
nf[0] = chd[c[0]];
nf[1] = chd[c[1]];
faceProcParity(nf, lf, df, depth - 1, cellProcFaceMask[i][2]);
}
faceProcParity(nf, lf, df, depth - 1, cellProcFaceMask[i][2]);
}
// 6 edge calls
Node *ne[4];
int le[4];
int de[4] = {depth - 1, depth - 1, depth - 1, depth - 1};
for (i = 0; i < 6; i++) {
int c[4] = {cellProcEdgeMask[i][0], cellProcEdgeMask[i][1], cellProcEdgeMask[i][2], cellProcEdgeMask[i][3]};
// 6 edge calls
Node *ne[4];
int le[4];
int de[4] = {depth - 1, depth - 1, depth - 1, depth - 1};
for (i = 0; i < 6; i++) {
int c[4] = {cellProcEdgeMask[i][0],
cellProcEdgeMask[i][1],
cellProcEdgeMask[i][2],
cellProcEdgeMask[i][3]};
for (int j = 0; j < 4; j++) {
le[j] = node->internal.is_child_leaf(c[j]);
ne[j] = chd[c[j]];
}
edgeProcParity(ne, le, de, depth - 1, cellProcEdgeMask[i][4]);
}
}
for (int j = 0; j < 4; j++) {
le[j] = node->internal.is_child_leaf(c[j]);
ne[j] = chd[c[j]];
}
edgeProcParity(ne, le, de, depth - 1, cellProcEdgeMask[i][4]);
}
}
}
/* definitions for global arrays */
const int edgemask[3] = {5, 3, 6};
const int faceMap[6][4] = {
{4, 8, 5, 9},
{6, 10, 7, 11},
{0, 8, 1, 10},
{2, 9, 3, 11},
{0, 4, 2, 6},
{1, 5, 3, 7},
{4, 8, 5, 9},
{6, 10, 7, 11},
{0, 8, 1, 10},
{2, 9, 3, 11},
{0, 4, 2, 6},
{1, 5, 3, 7},
};
const int cellProcFaceMask[12][3] = {
{0, 4, 0},
{1, 5, 0},
{2, 6, 0},
{3, 7, 0},
{0, 2, 1},
{4, 6, 1},
{1, 3, 1},
{5, 7, 1},
{0, 1, 2},
{2, 3, 2},
{4, 5, 2},
{6, 7, 2},
{0, 4, 0},
{1, 5, 0},
{2, 6, 0},
{3, 7, 0},
{0, 2, 1},
{4, 6, 1},
{1, 3, 1},
{5, 7, 1},
{0, 1, 2},
{2, 3, 2},
{4, 5, 2},
{6, 7, 2},
};
const int cellProcEdgeMask[6][5] = {
{0, 1, 2, 3, 0},
{4, 5, 6, 7, 0},
{0, 4, 1, 5, 1},
{2, 6, 3, 7, 1},
{0, 2, 4, 6, 2},
{1, 3, 5, 7, 2},
{0, 1, 2, 3, 0},
{4, 5, 6, 7, 0},
{0, 4, 1, 5, 1},
{2, 6, 3, 7, 1},
{0, 2, 4, 6, 2},
{1, 3, 5, 7, 2},
};
const int faceProcFaceMask[3][4][3] = {
{{4, 0, 0},
{5, 1, 0},
{6, 2, 0},
{7, 3, 0}},
{{2, 0, 1},
{6, 4, 1},
{3, 1, 1},
{7, 5, 1}},
{{1, 0, 2},
{3, 2, 2},
{5, 4, 2},
{7, 6, 2}}
};
const int faceProcFaceMask[3][4][3] = {{{4, 0, 0}, {5, 1, 0}, {6, 2, 0}, {7, 3, 0}},
{{2, 0, 1}, {6, 4, 1}, {3, 1, 1}, {7, 5, 1}},
{{1, 0, 2}, {3, 2, 2}, {5, 4, 2}, {7, 6, 2}}};
const int faceProcEdgeMask[3][4][6] = {
{{1, 4, 0, 5, 1, 1},
{1, 6, 2, 7, 3, 1},
{0, 4, 6, 0, 2, 2},
{0, 5, 7, 1, 3, 2}},
{{0, 2, 3, 0, 1, 0},
{0, 6, 7, 4, 5, 0},
{1, 2, 0, 6, 4, 2},
{1, 3, 1, 7, 5, 2}},
{{1, 1, 0, 3, 2, 0},
{1, 5, 4, 7, 6, 0},
{0, 1, 5, 0, 4, 1},
{0, 3, 7, 2, 6, 1}}
};
{{1, 4, 0, 5, 1, 1}, {1, 6, 2, 7, 3, 1}, {0, 4, 6, 0, 2, 2}, {0, 5, 7, 1, 3, 2}},
{{0, 2, 3, 0, 1, 0}, {0, 6, 7, 4, 5, 0}, {1, 2, 0, 6, 4, 2}, {1, 3, 1, 7, 5, 2}},
{{1, 1, 0, 3, 2, 0}, {1, 5, 4, 7, 6, 0}, {0, 1, 5, 0, 4, 1}, {0, 3, 7, 2, 6, 1}}};
const int edgeProcEdgeMask[3][2][5] = {
{{3, 2, 1, 0, 0},
{7, 6, 5, 4, 0}},
{{5, 1, 4, 0, 1},
{7, 3, 6, 2, 1}},
{{6, 4, 2, 0, 2},
{7, 5, 3, 1, 2}},
{{3, 2, 1, 0, 0}, {7, 6, 5, 4, 0}},
{{5, 1, 4, 0, 1}, {7, 3, 6, 2, 1}},
{{6, 4, 2, 0, 2}, {7, 5, 3, 1, 2}},
};
const int processEdgeMask[3][4] = {
{3, 2, 1, 0},
{7, 5, 6, 4},
{11, 10, 9, 8},
{3, 2, 1, 0},
{7, 5, 6, 4},
{11, 10, 9, 8},
};
const int dirCell[3][4][3] = {
{{0, -1, -1},
{0, -1, 0},
{0, 0, -1},
{0, 0, 0}},
{{-1, 0, -1},
{-1, 0, 0},
{0, 0, -1},
{0, 0, 0}},
{{-1, -1, 0},
{-1, 0, 0},
{0, -1, 0},
{0, 0, 0}}
};
const int dirCell[3][4][3] = {{{0, -1, -1}, {0, -1, 0}, {0, 0, -1}, {0, 0, 0}},
{{-1, 0, -1}, {-1, 0, 0}, {0, 0, -1}, {0, 0, 0}},
{{-1, -1, 0}, {-1, 0, 0}, {0, -1, 0}, {0, 0, 0}}};
const int dirEdge[3][4] = {
{3, 2, 1, 0},
{7, 6, 5, 4},
{11, 10, 9, 8},
{3, 2, 1, 0},
{7, 6, 5, 4},
{11, 10, 9, 8},
};
int InternalNode::numChildrenTable[256];

View File

@@ -37,7 +37,6 @@
* @author Tao Ju
*/
/* Global defines */
// Uncomment to see debug information
// #define IN_DEBUG_MODE
@@ -53,98 +52,97 @@ union Node;
struct LeafNode;
struct InternalNode {
/* Initialized in Octree::BuildTable */
static int numChildrenTable[256];
static int childrenCountTable[256][8];
static int childrenIndexTable[256][8];
/* Initialized in Octree::BuildTable */
static int numChildrenTable[256];
static int childrenCountTable[256][8];
static int childrenIndexTable[256][8];
/* Bit N indicates whether child N exists or not */
unsigned char has_child_bitfield;
/* Bit N indicates whether child N is a leaf or not */
unsigned char child_is_leaf_bitfield;
/* Bit N indicates whether child N exists or not */
unsigned char has_child_bitfield;
/* Bit N indicates whether child N is a leaf or not */
unsigned char child_is_leaf_bitfield;
/* Can have up to eight children */
Node *children[0];
/* Can have up to eight children */
Node *children[0];
/// Test if child is leaf
int is_child_leaf(int index) const
{
return (child_is_leaf_bitfield >> index) & 1;
}
/// Test if child is leaf
int is_child_leaf(int index) const
{
return (child_is_leaf_bitfield >> index) & 1;
}
/// If child index exists
int has_child(int index) const
{
return (has_child_bitfield >> index) & 1;
}
/// If child index exists
int has_child(int index) const
{
return (has_child_bitfield >> index) & 1;
}
/// Get the pointer to child index
Node *get_child(int count)
{
return children[count];
}
/// Get the pointer to child index
Node *get_child(int count)
{
return children[count];
}
const Node *get_child(int count) const
{
return children[count];
}
const Node *get_child(int count) const
{
return children[count];
}
/// Get total number of children
int get_num_children() const
{
return numChildrenTable[has_child_bitfield];
}
/// Get total number of children
int get_num_children() const
{
return numChildrenTable[has_child_bitfield];
}
/// Get the count of children
int get_child_count(int index) const
{
return childrenCountTable[has_child_bitfield][index];
}
int get_child_index(int count)
{
return childrenIndexTable[has_child_bitfield][count];
}
const int *get_child_counts() const
{
return childrenCountTable[has_child_bitfield];
}
/// Get the count of children
int get_child_count(int index) const
{
return childrenCountTable[has_child_bitfield][index];
}
int get_child_index(int count)
{
return childrenIndexTable[has_child_bitfield][count];
}
const int *get_child_counts() const
{
return childrenCountTable[has_child_bitfield];
}
/// Get all children
void fill_children(Node *children[8], int leaf[8])
{
int count = 0;
for (int i = 0; i < 8; i++) {
leaf[i] = is_child_leaf(i);
if (has_child(i)) {
children[i] = get_child(count);
count++;
}
else {
children[i] = NULL;
leaf[i] = 0;
}
}
}
/// Get all children
void fill_children(Node *children[8], int leaf[8])
{
int count = 0;
for (int i = 0; i < 8; i++) {
leaf[i] = is_child_leaf(i);
if (has_child(i)) {
children[i] = get_child(count);
count++;
}
else {
children[i] = NULL;
leaf[i] = 0;
}
}
}
/// Sets the child pointer
void set_child(int count, Node *chd)
{
children[count] = chd;
}
void set_internal_child(int index, int count, InternalNode *chd)
{
set_child(count, (Node *)chd);
has_child_bitfield |= (1 << index);
}
void set_leaf_child(int index, int count, LeafNode *chd)
{
set_child(count, (Node *)chd);
has_child_bitfield |= (1 << index);
child_is_leaf_bitfield |= (1 << index);
}
/// Sets the child pointer
void set_child(int count, Node *chd)
{
children[count] = chd;
}
void set_internal_child(int index, int count, InternalNode *chd)
{
set_child(count, (Node *)chd);
has_child_bitfield |= (1 << index);
}
void set_leaf_child(int index, int count, LeafNode *chd)
{
set_child(count, (Node *)chd);
has_child_bitfield |= (1 << index);
child_is_leaf_bitfield |= (1 << index);
}
};
/**
* Bits order
*
@@ -157,27 +155,27 @@ struct InternalNode {
* Byte 5: edge intersections(4 bytes per inter, or 12 bytes if USE_HERMIT)
*/
struct LeafNode /* TODO: remove this attribute once everything is fixed */ {
unsigned short edge_parity : 12;
unsigned short primary_edge_intersections : 3;
unsigned short edge_parity : 12;
unsigned short primary_edge_intersections : 3;
/* XXX: maybe actually unused? */
unsigned short in_process : 1;
/* XXX: maybe actually unused? */
unsigned short in_process : 1;
/* bitfield */
char signs;
/* bitfield */
char signs;
int minimizer_index;
int minimizer_index;
unsigned short flood_fill;
unsigned short flood_fill;
float edge_intersections[0];
float edge_intersections[0];
};
/* Doesn't get directly allocated anywhere, just used for passing
pointers to nodes that could be internal or leaf. */
union Node {
InternalNode internal;
LeafNode leaf;
InternalNode internal;
LeafNode leaf;
};
/* Global variables */
@@ -197,1195 +195,1209 @@ extern const int dirEdge[3][4];
*/
struct PathElement {
// Origin
int pos[3];
// Origin
int pos[3];
// link
PathElement *next;
// link
PathElement *next;
};
struct PathList {
// Head
PathElement *head;
PathElement *tail;
// Head
PathElement *head;
PathElement *tail;
// Length of the list
int length;
// Length of the list
int length;
// Next list
PathList *next;
// Next list
PathList *next;
};
/**
* Class for building and processing an octree
*/
class Octree
{
class Octree {
public:
/* Public members */
/* Public members */
/// Memory allocators
VirtualMemoryAllocator *alloc[9];
VirtualMemoryAllocator *leafalloc[4];
/// Memory allocators
VirtualMemoryAllocator *alloc[9];
VirtualMemoryAllocator *leafalloc[4];
/// Root node
Node *root;
/// Root node
Node *root;
/// Model reader
ModelReader *reader;
/// Model reader
ModelReader *reader;
/// Marching cubes table
Cubes *cubes;
/// Marching cubes table
Cubes *cubes;
/// Length of grid
int dimen;
int mindimen, minshift;
/// Length of grid
int dimen;
int mindimen, minshift;
/// Maximum depth
int maxDepth;
/// Maximum depth
int maxDepth;
/// The lower corner of the bounding box and the size
float origin[3];
float range;
/// The lower corner of the bounding box and the size
float origin[3];
float range;
/// Counting information
int nodeCount;
int nodeSpace;
int nodeCounts[9];
/// Counting information
int nodeCount;
int nodeSpace;
int nodeCounts[9];
int actualQuads, actualVerts;
int actualQuads, actualVerts;
PathList *ringList;
PathList *ringList;
int maxTrianglePerCell;
int outType; // 0 for OFF, 1 for PLY, 2 for VOL
int maxTrianglePerCell;
int outType; // 0 for OFF, 1 for PLY, 2 for VOL
// For flood filling
int use_flood_fill;
float thresh;
// For flood filling
int use_flood_fill;
float thresh;
int use_manifold;
int use_manifold;
float hermite_num;
float hermite_num;
DualConMode mode;
DualConMode mode;
public:
/**
* Construtor
*/
Octree(ModelReader *mr,
DualConAllocOutput alloc_output_func,
DualConAddVert add_vert_func,
DualConAddQuad add_quad_func,
DualConFlags flags, DualConMode mode, int depth,
float threshold, float hermite_num);
/**
* Construtor
*/
Octree(ModelReader *mr,
DualConAllocOutput alloc_output_func,
DualConAddVert add_vert_func,
DualConAddQuad add_quad_func,
DualConFlags flags,
DualConMode mode,
int depth,
float threshold,
float hermite_num);
/**
* Destructor
*/
~Octree();
/**
* Destructor
*/
~Octree();
/**
* Scan convert
*/
void scanConvert();
/**
* Scan convert
*/
void scanConvert();
void *getOutputMesh() {
return output_mesh;
}
void *getOutputMesh()
{
return output_mesh;
}
private:
/* Helper functions */
/* Helper functions */
/**
* Initialize memory allocators
*/
void initMemory();
/**
* Initialize memory allocators
*/
void initMemory();
/**
* Release memory
*/
void freeMemory();
/**
* Release memory
*/
void freeMemory();
/**
* Print memory usage
*/
void printMemUsage();
/**
* Print memory usage
*/
void printMemUsage();
/**
* Methods to set / restore minimum edges
*/
void resetMinimalEdges();
/**
* Methods to set / restore minimum edges
*/
void resetMinimalEdges();
void cellProcParity(Node *node, int leaf, int depth);
void faceProcParity(Node *node[2], int leaf[2], int depth[2], int maxdep, int dir);
void edgeProcParity(Node *node[4], int leaf[4], int depth[4], int maxdep, int dir);
void cellProcParity(Node *node, int leaf, int depth);
void faceProcParity(Node * node[2], int leaf[2], int depth[2], int maxdep, int dir);
void edgeProcParity(Node * node[4], int leaf[4], int depth[4], int maxdep, int dir);
void processEdgeParity(LeafNode *node[4], int depths[4], int maxdep, int dir);
void processEdgeParity(LeafNode * node[4], int depths[4], int maxdep, int dir);
/**
* Add triangles to the tree
*/
void addAllTriangles();
void addTriangle(Triangle *trian, int triind);
InternalNode *addTriangle(InternalNode *node, CubeTriangleIsect *p, int height);
/**
* Add triangles to the tree
*/
void addAllTriangles();
void addTriangle(Triangle *trian, int triind);
InternalNode *addTriangle(InternalNode *node, CubeTriangleIsect *p, int height);
/**
* Method to update minimizer in a cell: update edge intersections instead
*/
LeafNode *updateCell(LeafNode *node, CubeTriangleIsect *p);
/**
* Method to update minimizer in a cell: update edge intersections instead
*/
LeafNode *updateCell(LeafNode *node, CubeTriangleIsect *p);
/* Routines to detect and patch holes */
int numRings;
int totRingLengths;
int maxRingLength;
/* Routines to detect and patch holes */
int numRings;
int totRingLengths;
int maxRingLength;
/**
* Entry routine.
*/
void trace();
/**
* Trace the given node, find patches and fill them in
*/
Node *trace(Node *node, int *st, int len, int depth, PathList *&paths);
/**
* Look for path on the face and add to paths
*/
void findPaths(
Node *node[2], int leaf[2], int depth[2], int *st[2], int maxdep, int dir, PathList *&paths);
/**
* Combine two list1 and list2 into list1 using connecting paths list3,
* while closed paths are appended to rings
*/
void combinePaths(PathList *&list1, PathList *list2, PathList *paths, PathList *&rings);
/**
* Helper function: combine current paths in list1 and list2 to a single path and append to list3
*/
PathList *combineSinglePath(PathList *&head1,
PathList *pre1,
PathList *&list1,
PathList *&head2,
PathList *pre2,
PathList *&list2);
/**
* Entry routine.
*/
void trace();
/**
* Trace the given node, find patches and fill them in
*/
Node *trace(Node *node, int *st, int len, int depth, PathList *& paths);
/**
* Look for path on the face and add to paths
*/
void findPaths(Node * node[2], int leaf[2], int depth[2], int *st[2], int maxdep, int dir, PathList * &paths);
/**
* Combine two list1 and list2 into list1 using connecting paths list3,
* while closed paths are appended to rings
*/
void combinePaths(PathList *& list1, PathList *list2, PathList *paths, PathList *& rings);
/**
* Helper function: combine current paths in list1 and list2 to a single path and append to list3
*/
PathList *combineSinglePath(PathList *& head1, PathList *pre1, PathList *& list1, PathList *& head2, PathList *pre2, PathList *& list2);
/**
* Functions to patch rings in a node
*/
Node *patch(Node *node, int st[3], int len, PathList *rings);
Node *patchSplit(Node *node,
int st[3],
int len,
PathList *rings,
int dir,
PathList *&nrings1,
PathList *&nrings2);
Node *patchSplitSingle(Node *node,
int st[3],
int len,
PathElement *head,
int dir,
PathList *&nrings1,
PathList *&nrings2);
Node *connectFace(Node *node, int st[3], int len, int dir, PathElement *f1, PathElement *f2);
Node *locateCell(InternalNode *node,
int st[3],
int len,
int ori[3],
int dir,
int side,
Node *&rleaf,
int rst[3],
int &rlen);
void compressRing(PathElement *&ring);
void getFacePoint(PathElement *leaf, int dir, int &x, int &y, float &p, float &q);
LeafNode *patchAdjacent(InternalNode *node,
int len,
int st1[3],
LeafNode *leaf1,
int st2[3],
LeafNode *leaf2,
int walkdir,
int inc,
int dir,
int side,
float alpha);
int findPair(PathElement *head, int pos, int dir, PathElement *&pre1, PathElement *&pre2);
int getSide(PathElement *e, int pos, int dir);
int isEqual(PathElement *e1, PathElement *e2);
void preparePrimalEdgesMask(InternalNode *node);
void testFacePoint(PathElement *e1, PathElement *e2);
/**
* Functions to patch rings in a node
*/
Node *patch(Node *node, int st[3], int len, PathList * rings);
Node *patchSplit(Node *node, int st[3], int len, PathList * rings, int dir, PathList * &nrings1, PathList * &nrings2);
Node *patchSplitSingle(Node *node, int st[3], int len, PathElement *head, int dir, PathList * &nrings1, PathList * &nrings2);
Node *connectFace(Node *node, int st[3], int len, int dir, PathElement * f1, PathElement * f2);
Node *locateCell(InternalNode *node, int st[3], int len, int ori[3], int dir, int side, Node * &rleaf, int rst[3], int& rlen);
void compressRing(PathElement *& ring);
void getFacePoint(PathElement *leaf, int dir, int& x, int& y, float& p, float& q);
LeafNode *patchAdjacent(InternalNode *node, int len, int st1[3], LeafNode * leaf1, int st2[3], LeafNode * leaf2, int walkdir, int inc, int dir, int side, float alpha);
int findPair(PathElement *head, int pos, int dir, PathElement *& pre1, PathElement *& pre2);
int getSide(PathElement *e, int pos, int dir);
int isEqual(PathElement *e1, PathElement *e2);
void preparePrimalEdgesMask(InternalNode *node);
void testFacePoint(PathElement *e1, PathElement *e2);
/**
* Path-related functions
*/
void deletePath(PathList *&head, PathList *pre, PathList *&curr);
void printPath(PathList *path);
void printPath(PathElement *path);
void printElement(PathElement *ele);
void printPaths(PathList *path);
void checkElement(PathElement *ele);
void checkPath(PathElement *path);
/**
* Path-related functions
*/
void deletePath(PathList *& head, PathList *pre, PathList *& curr);
void printPath(PathList *path);
void printPath(PathElement *path);
void printElement(PathElement *ele);
void printPaths(PathList *path);
void checkElement(PathElement *ele);
void checkPath(PathElement *path);
/**
* Routines to build signs to create a partitioned volume
*(after patching rings)
*/
void buildSigns();
void buildSigns(unsigned char table[], Node *node, int isLeaf, int sg, int rvalue[8]);
/************************************************************************/
/* To remove disconnected components */
/************************************************************************/
void floodFill();
void clearProcessBits(Node *node, int height);
int floodFill(LeafNode *leaf, int st[3], int len, int height, int threshold);
int floodFill(Node *node, int st[3], int len, int height, int threshold);
/**
* Routines to build signs to create a partitioned volume
*(after patching rings)
*/
void buildSigns();
void buildSigns(unsigned char table[], Node * node, int isLeaf, int sg, int rvalue[8]);
/**
* Write out polygon file
*/
void writeOut();
/************************************************************************/
/* To remove disconnected components */
/************************************************************************/
void floodFill();
void clearProcessBits(Node *node, int height);
int floodFill(LeafNode *leaf, int st[3], int len, int height, int threshold);
int floodFill(Node *node, int st[3], int len, int height, int threshold);
void countIntersection(Node *node, int height, int &nedge, int &ncell, int &nface);
void generateMinimizer(Node *node, int st[3], int len, int height, int &offset);
void computeMinimizer(const LeafNode *leaf, int st[3], int len, float rvalue[3]) const;
/**
* Traversal functions to generate polygon model
* op: 0 for counting, 1 for writing OBJ, 2 for writing OFF, 3 for writing PLY
*/
void cellProcContour(Node *node, int leaf, int depth);
void faceProcContour(Node *node[2], int leaf[2], int depth[2], int maxdep, int dir);
void edgeProcContour(Node *node[4], int leaf[4], int depth[4], int maxdep, int dir);
void processEdgeWrite(Node *node[4], int depths[4], int maxdep, int dir);
/**
* Write out polygon file
*/
void writeOut();
void countIntersection(Node *node, int height, int& nedge, int& ncell, int& nface);
void generateMinimizer(Node *node, int st[3], int len, int height, int& offset);
void computeMinimizer(const LeafNode * leaf, int st[3], int len,
float rvalue[3]) const;
/**
* Traversal functions to generate polygon model
* op: 0 for counting, 1 for writing OBJ, 2 for writing OFF, 3 for writing PLY
*/
void cellProcContour(Node *node, int leaf, int depth);
void faceProcContour(Node * node[2], int leaf[2], int depth[2], int maxdep, int dir);
void edgeProcContour(Node * node[4], int leaf[4], int depth[4], int maxdep, int dir);
void processEdgeWrite(Node * node[4], int depths[4], int maxdep, int dir);
/* output callbacks/data */
DualConAllocOutput alloc_output;
DualConAddVert add_vert;
DualConAddQuad add_quad;
void *output_mesh;
/* output callbacks/data */
DualConAllocOutput alloc_output;
DualConAddVert add_vert;
DualConAddQuad add_quad;
void *output_mesh;
private:
/************ Operators for all nodes ************/
/// Lookup table
int numEdgeTable[8];
int edgeCountTable[8][3];
/// Build up lookup table
void buildTable()
{
for (int i = 0; i < 256; i++) {
InternalNode::numChildrenTable[i] = 0;
int count = 0;
for (int j = 0; j < 8; j++) {
InternalNode::numChildrenTable[i] += ((i >> j) & 1);
InternalNode::childrenCountTable[i][j] = count;
InternalNode::childrenIndexTable[i][count] = j;
count += ((i >> j) & 1);
}
}
for (int i = 0; i < 8; i++) {
numEdgeTable[i] = 0;
int count = 0;
for (int j = 0; j < 3; j++) {
numEdgeTable[i] += ((i >> j) & 1);
edgeCountTable[i][j] = count;
count += ((i >> j) & 1);
}
}
}
int getSign(Node *node, int height, int index)
{
if (height == 0) {
return getSign(&node->leaf, index);
}
else {
if (node->internal.has_child(index)) {
return getSign(node->internal.get_child(node->internal.get_child_count(index)),
height - 1,
index);
}
else {
return getSign(node->internal.get_child(0),
height - 1,
7 - node->internal.get_child_index(0));
}
}
}
/************ Operators for leaf nodes ************/
void printInfo(int st[3])
{
printf("INFO AT: %d %d %d\n", st[0] >> minshift, st[1] >> minshift, st[2] >> minshift);
LeafNode *leaf = (LeafNode *)locateLeafCheck(st);
if (leaf)
printInfo(leaf);
else
printf("Leaf not exists!\n");
}
void printInfo(const LeafNode *leaf)
{
/*
printf("Edge mask: ");
for(int i = 0; i < 12; i ++)
{
printf("%d ", getEdgeParity(leaf, i));
}
printf("\n");
printf("Stored edge mask: ");
for(i = 0; i < 3; i ++)
{
printf("%d ", getStoredEdgesParity(leaf, i));
}
printf("\n");
*/
printf("Sign mask: ");
for (int i = 0; i < 8; i++) {
printf("%d ", getSign(leaf, i));
}
printf("\n");
}
/// Retrieve signs
int getSign(const LeafNode *leaf, int index)
{
return ((leaf->signs >> index) & 1);
}
/// Set sign
void setSign(LeafNode *leaf, int index)
{
leaf->signs |= (1 << index);
}
void setSign(LeafNode *leaf, int index, int sign)
{
leaf->signs &= (~(1 << index));
leaf->signs |= ((sign & 1) << index);
}
int getSignMask(const LeafNode *leaf) const
{
return leaf->signs;
}
void setInProcessAll(int st[3], int dir)
{
int nst[3], eind;
for (int i = 0; i < 4; i++) {
nst[0] = st[0] + dirCell[dir][i][0] * mindimen;
nst[1] = st[1] + dirCell[dir][i][1] * mindimen;
nst[2] = st[2] + dirCell[dir][i][2] * mindimen;
eind = dirEdge[dir][i];
LeafNode *cell = locateLeafCheck(nst);
assert(cell);
setInProcess(cell, eind);
}
}
void flipParityAll(int st[3], int dir)
{
int nst[3], eind;
for (int i = 0; i < 4; i++) {
nst[0] = st[0] + dirCell[dir][i][0] * mindimen;
nst[1] = st[1] + dirCell[dir][i][1] * mindimen;
nst[2] = st[2] + dirCell[dir][i][2] * mindimen;
eind = dirEdge[dir][i];
LeafNode *cell = locateLeaf(nst);
flipEdge(cell, eind);
}
}
void setInProcess(LeafNode *leaf, int eind)
{
assert(eind >= 0 && eind <= 11);
leaf->flood_fill |= (1 << eind);
}
void setOutProcess(LeafNode *leaf, int eind)
{
assert(eind >= 0 && eind <= 11);
leaf->flood_fill &= ~(1 << eind);
}
int isInProcess(LeafNode *leaf, int eind)
{
assert(eind >= 0 && eind <= 11);
return (leaf->flood_fill >> eind) & 1;
}
/// Generate signs at the corners from the edge parity
void generateSigns(LeafNode *leaf, unsigned char table[], int start)
{
leaf->signs = table[leaf->edge_parity];
if ((start ^ leaf->signs) & 1) {
leaf->signs = ~(leaf->signs);
}
}
/// Get edge parity
int getEdgeParity(const LeafNode *leaf, int index) const
{
assert(index >= 0 && index <= 11);
return (leaf->edge_parity >> index) & 1;
}
/// Get edge parity on a face
int getFaceParity(LeafNode *leaf, int index)
{
int a = getEdgeParity(leaf, faceMap[index][0]) +
getEdgeParity(leaf, faceMap[index][1]) +
getEdgeParity(leaf, faceMap[index][2]) +
getEdgeParity(leaf, faceMap[index][3]);
return (a & 1);
}
int getFaceEdgeNum(LeafNode *leaf, int index)
{
int a = getEdgeParity(leaf, faceMap[index][0]) +
getEdgeParity(leaf, faceMap[index][1]) +
getEdgeParity(leaf, faceMap[index][2]) +
getEdgeParity(leaf, faceMap[index][3]);
return a;
}
/// Set edge parity
void flipEdge(LeafNode *leaf, int index)
{
assert(index >= 0 && index <= 11);
leaf->edge_parity ^= (1 << index);
}
/// Set 1
void setEdge(LeafNode *leaf, int index)
{
assert(index >= 0 && index <= 11);
leaf->edge_parity |= (1 << index);
}
/// Set 0
void resetEdge(LeafNode *leaf, int index)
{
assert(index >= 0 && index <= 11);
leaf->edge_parity &= ~(1 << index);
}
/// Flipping with a new intersection offset
void createPrimalEdgesMask(LeafNode *leaf)
{
leaf->primary_edge_intersections = getPrimalEdgesMask2(leaf);
}
void setStoredEdgesParity(LeafNode *leaf, int pindex)
{
assert(pindex <= 2 && pindex >= 0);
leaf->primary_edge_intersections |= (1 << pindex);
}
int getStoredEdgesParity(const LeafNode *leaf, int pindex) const
{
assert(pindex <= 2 && pindex >= 0);
return (leaf->primary_edge_intersections >> pindex) & 1;
}
LeafNode *flipEdge(LeafNode *leaf, int index, float alpha)
{
flipEdge(leaf, index);
if ((index & 3) == 0) {
int ind = index / 4;
if (getEdgeParity(leaf, index) && !getStoredEdgesParity(leaf, ind)) {
// Create a new node
int num = getNumEdges(leaf) + 1;
setStoredEdgesParity(leaf, ind);
int count = getEdgeCount(leaf, ind);
LeafNode *nleaf = createLeaf(num);
*nleaf = *leaf;
setEdgeOffset(nleaf, alpha, count);
if (num > 1) {
float *pts = leaf->edge_intersections;
float *npts = nleaf->edge_intersections;
for (int i = 0; i < count; i++) {
for (int j = 0; j < EDGE_FLOATS; j++) {
npts[i * EDGE_FLOATS + j] = pts[i * EDGE_FLOATS + j];
}
}
for (int i = count + 1; i < num; i++) {
for (int j = 0; j < EDGE_FLOATS; j++) {
npts[i * EDGE_FLOATS + j] = pts[(i - 1) * EDGE_FLOATS + j];
}
}
}
removeLeaf(num - 1, (LeafNode *)leaf);
leaf = nleaf;
}
}
return leaf;
}
/// Update parent link
void updateParent(InternalNode *node, int len, int st[3], LeafNode *leaf)
{
// First, locate the parent
int count;
InternalNode *parent = locateParent(node, len, st, count);
// Update
parent->set_child(count, (Node *)leaf);
}
void updateParent(InternalNode *node, int len, int st[3])
{
if (len == dimen) {
root = (Node *)node;
return;
}
// First, locate the parent
int count;
InternalNode *parent = locateParent(len, st, count);
// UPdate
parent->set_child(count, (Node *)node);
}
/// Find edge intersection on a given edge
int getEdgeIntersectionByIndex(int st[3], int index, float pt[3], int check) const
{
// First, locat the leaf
const LeafNode *leaf;
if (check) {
leaf = locateLeafCheck(st);
}
else {
leaf = locateLeaf(st);
}
if (leaf && getStoredEdgesParity(leaf, index)) {
float off = getEdgeOffset(leaf, getEdgeCount(leaf, index));
pt[0] = (float) st[0];
pt[1] = (float) st[1];
pt[2] = (float) st[2];
pt[index] += off * mindimen;
return 1;
}
else {
return 0;
}
}
/// Retrieve number of edges intersected
int getPrimalEdgesMask(const LeafNode *leaf) const
{
return leaf->primary_edge_intersections;
}
int getPrimalEdgesMask2(LeafNode *leaf)
{
return (((leaf->edge_parity & 0x1) >> 0) |
((leaf->edge_parity & 0x10) >> 3) |
((leaf->edge_parity & 0x100) >> 6));
}
/// Get the count for a primary edge
int getEdgeCount(const LeafNode *leaf, int index) const
{
return edgeCountTable[getPrimalEdgesMask(leaf)][index];
}
int getNumEdges(LeafNode *leaf)
{
return numEdgeTable[getPrimalEdgesMask(leaf)];
}
int getNumEdges2(LeafNode *leaf)
{
return numEdgeTable[getPrimalEdgesMask2(leaf)];
}
/// Set edge intersection
void setEdgeOffset(LeafNode *leaf, float pt, int count)
{
float *pts = leaf->edge_intersections;
pts[EDGE_FLOATS * count] = pt;
pts[EDGE_FLOATS * count + 1] = 0;
pts[EDGE_FLOATS * count + 2] = 0;
pts[EDGE_FLOATS * count + 3] = 0;
}
/// Set multiple edge intersections
void setEdgeOffsets(LeafNode *leaf, float pt[3], int len)
{
float *pts = leaf->edge_intersections;
for (int i = 0; i < len; i++) {
pts[i] = pt[i];
}
}
/// Retrieve edge intersection
float getEdgeOffset(const LeafNode *leaf, int count) const
{
return leaf->edge_intersections[4 * count];
}
/// Update method
LeafNode *updateEdgeOffsets(LeafNode *leaf, int oldlen, int newlen, float offs[3])
{
// First, create a new leaf node
LeafNode *nleaf = createLeaf(newlen);
*nleaf = *leaf;
// Next, fill in the offsets
setEdgeOffsets(nleaf, offs, newlen);
// Finally, delete the old leaf
removeLeaf(oldlen, leaf);
return nleaf;
}
/// Set minimizer index
void setMinimizerIndex(LeafNode *leaf, int index)
{
leaf->minimizer_index = index;
}
/// Get minimizer index
int getMinimizerIndex(LeafNode *leaf)
{
return leaf->minimizer_index;
}
int getMinimizerIndex(LeafNode *leaf, int eind)
{
int add = manifold_table[getSignMask(leaf)].pairs[eind][0] - 1;
assert(add >= 0);
return leaf->minimizer_index + add;
}
void getMinimizerIndices(LeafNode *leaf, int eind, int inds[2])
{
const int *add = manifold_table[getSignMask(leaf)].pairs[eind];
inds[0] = leaf->minimizer_index + add[0] - 1;
if (add[0] == add[1]) {
inds[1] = -1;
}
else {
inds[1] = leaf->minimizer_index + add[1] - 1;
}
}
/// Set edge intersection
void setEdgeOffsetNormal(LeafNode *leaf, float pt, float a, float b, float c, int count)
{
float *pts = leaf->edge_intersections;
pts[4 * count] = pt;
pts[4 * count + 1] = a;
pts[4 * count + 2] = b;
pts[4 * count + 3] = c;
}
float getEdgeOffsetNormal(LeafNode *leaf, int count, float& a, float& b, float& c)
{
float *pts = leaf->edge_intersections;
a = pts[4 * count + 1];
b = pts[4 * count + 2];
c = pts[4 * count + 3];
return pts[4 * count];
}
/// Set multiple edge intersections
void setEdgeOffsetsNormals(LeafNode *leaf, const float pt[],
const float a[], const float b[],
const float c[], int len)
{
float *pts = leaf->edge_intersections;
for (int i = 0; i < len; i++) {
if (pt[i] > 1 || pt[i] < 0) {
printf("\noffset: %f\n", pt[i]);
}
pts[i * 4] = pt[i];
pts[i * 4 + 1] = a[i];
pts[i * 4 + 2] = b[i];
pts[i * 4 + 3] = c[i];
}
}
/// Retrieve complete edge intersection
void getEdgeIntersectionByIndex(const LeafNode *leaf, int index, int st[3],
int len, float pt[3], float nm[3]) const
{
int count = getEdgeCount(leaf, index);
const float *pts = leaf->edge_intersections;
float off = pts[4 * count];
pt[0] = (float) st[0];
pt[1] = (float) st[1];
pt[2] = (float) st[2];
pt[index] += (off * len);
nm[0] = pts[4 * count + 1];
nm[1] = pts[4 * count + 2];
nm[2] = pts[4 * count + 3];
}
float getEdgeOffsetNormalByIndex(LeafNode *leaf, int index, float nm[3])
{
int count = getEdgeCount(leaf, index);
float *pts = leaf->edge_intersections;
float off = pts[4 * count];
nm[0] = pts[4 * count + 1];
nm[1] = pts[4 * count + 2];
nm[2] = pts[4 * count + 3];
return off;
}
void fillEdgeIntersections(const LeafNode *leaf, int st[3], int len,
float pts[12][3], float norms[12][3]) const
{
int i;
// int stt[3] = {0, 0, 0};
// The three primal edges are easy
int pmask[3] = {0, 4, 8};
for (i = 0; i < 3; i++) {
if (getEdgeParity(leaf, pmask[i])) {
// getEdgeIntersectionByIndex(leaf, i, stt, 1, pts[pmask[i]], norms[pmask[i]]);
getEdgeIntersectionByIndex(leaf, i, st, len, pts[pmask[i]], norms[pmask[i]]);
}
}
// 3 face adjacent cubes
int fmask[3][2] = {{6, 10}, {2, 9}, {1, 5}};
int femask[3][2] = {{1, 2}, {0, 2}, {0, 1}};
for (i = 0; i < 3; i++) {
int e1 = getEdgeParity(leaf, fmask[i][0]);
int e2 = getEdgeParity(leaf, fmask[i][1]);
if (e1 || e2) {
int nst[3] = {st[0], st[1], st[2]};
nst[i] += len;
// int nstt[3] = {0, 0, 0};
// nstt[i] += 1;
const LeafNode *node = locateLeaf(nst);
if (e1) {
// getEdgeIntersectionByIndex(node, femask[i][0], nstt, 1, pts[fmask[i][0]], norms[fmask[i][0]]);
getEdgeIntersectionByIndex(node, femask[i][0], nst, len, pts[fmask[i][0]], norms[fmask[i][0]]);
}
if (e2) {
// getEdgeIntersectionByIndex(node, femask[i][1], nstt, 1, pts[fmask[i][1]], norms[fmask[i][1]]);
getEdgeIntersectionByIndex(node, femask[i][1], nst, len, pts[fmask[i][1]], norms[fmask[i][1]]);
}
}
}
// 3 edge adjacent cubes
int emask[3] = {3, 7, 11};
int eemask[3] = {0, 1, 2};
for (i = 0; i < 3; i++) {
if (getEdgeParity(leaf, emask[i])) {
int nst[3] = {st[0] + len, st[1] + len, st[2] + len};
nst[i] -= len;
// int nstt[3] = {1, 1, 1};
// nstt[i] -= 1;
const LeafNode *node = locateLeaf(nst);
// getEdgeIntersectionByIndex(node, eemask[i], nstt, 1, pts[emask[i]], norms[emask[i]]);
getEdgeIntersectionByIndex(node, eemask[i], nst, len, pts[emask[i]], norms[emask[i]]);
}
}
}
void fillEdgeIntersections(const LeafNode *leaf, int st[3], int len,
float pts[12][3], float norms[12][3],
int parity[12]) const
{
int i;
for (i = 0; i < 12; i++) {
parity[i] = 0;
}
// int stt[3] = {0, 0, 0};
// The three primal edges are easy
int pmask[3] = {0, 4, 8};
for (i = 0; i < 3; i++) {
if (getStoredEdgesParity(leaf, i)) {
// getEdgeIntersectionByIndex(leaf, i, stt, 1, pts[pmask[i]], norms[pmask[i]]);
getEdgeIntersectionByIndex(leaf, i, st, len, pts[pmask[i]], norms[pmask[i]]);
parity[pmask[i]] = 1;
}
}
// 3 face adjacent cubes
int fmask[3][2] = {{6, 10}, {2, 9}, {1, 5}};
int femask[3][2] = {{1, 2}, {0, 2}, {0, 1}};
for (i = 0; i < 3; i++) {
{
int nst[3] = {st[0], st[1], st[2]};
nst[i] += len;
// int nstt[3] = {0, 0, 0};
// nstt[i] += 1;
const LeafNode *node = locateLeafCheck(nst);
if (node == NULL) {
continue;
}
int e1 = getStoredEdgesParity(node, femask[i][0]);
int e2 = getStoredEdgesParity(node, femask[i][1]);
if (e1) {
// getEdgeIntersectionByIndex(node, femask[i][0], nstt, 1, pts[fmask[i][0]], norms[fmask[i][0]]);
getEdgeIntersectionByIndex(node, femask[i][0], nst, len, pts[fmask[i][0]], norms[fmask[i][0]]);
parity[fmask[i][0]] = 1;
}
if (e2) {
// getEdgeIntersectionByIndex(node, femask[i][1], nstt, 1, pts[fmask[i][1]], norms[fmask[i][1]]);
getEdgeIntersectionByIndex(node, femask[i][1], nst, len, pts[fmask[i][1]], norms[fmask[i][1]]);
parity[fmask[i][1]] = 1;
}
}
}
// 3 edge adjacent cubes
int emask[3] = {3, 7, 11};
int eemask[3] = {0, 1, 2};
for (i = 0; i < 3; i++) {
// if(getEdgeParity(leaf, emask[i]))
{
int nst[3] = {st[0] + len, st[1] + len, st[2] + len};
nst[i] -= len;
// int nstt[3] = {1, 1, 1};
// nstt[i] -= 1;
const LeafNode *node = locateLeafCheck(nst);
if (node == NULL) {
continue;
}
if (getStoredEdgesParity(node, eemask[i])) {
// getEdgeIntersectionByIndex(node, eemask[i], nstt, 1, pts[emask[i]], norms[emask[i]]);
getEdgeIntersectionByIndex(node, eemask[i], nst, len, pts[emask[i]], norms[emask[i]]);
parity[emask[i]] = 1;
}
}
}
}
void fillEdgeOffsetsNormals(LeafNode *leaf, int st[3], int len, float pts[12], float norms[12][3], int parity[12])
{
int i;
for (i = 0; i < 12; i++) {
parity[i] = 0;
}
// int stt[3] = {0, 0, 0};
// The three primal edges are easy
int pmask[3] = {0, 4, 8};
for (i = 0; i < 3; i++) {
if (getStoredEdgesParity(leaf, i)) {
pts[pmask[i]] = getEdgeOffsetNormalByIndex(leaf, i, norms[pmask[i]]);
parity[pmask[i]] = 1;
}
}
// 3 face adjacent cubes
int fmask[3][2] = {{6, 10}, {2, 9}, {1, 5}};
int femask[3][2] = {{1, 2}, {0, 2}, {0, 1}};
for (i = 0; i < 3; i++) {
{
int nst[3] = {st[0], st[1], st[2]};
nst[i] += len;
// int nstt[3] = {0, 0, 0};
// nstt[i] += 1;
LeafNode *node = locateLeafCheck(nst);
if (node == NULL) {
continue;
}
int e1 = getStoredEdgesParity(node, femask[i][0]);
int e2 = getStoredEdgesParity(node, femask[i][1]);
if (e1) {
pts[fmask[i][0]] = getEdgeOffsetNormalByIndex(node, femask[i][0], norms[fmask[i][0]]);
parity[fmask[i][0]] = 1;
}
if (e2) {
pts[fmask[i][1]] = getEdgeOffsetNormalByIndex(node, femask[i][1], norms[fmask[i][1]]);
parity[fmask[i][1]] = 1;
}
}
}
// 3 edge adjacent cubes
int emask[3] = {3, 7, 11};
int eemask[3] = {0, 1, 2};
for (i = 0; i < 3; i++) {
// if(getEdgeParity(leaf, emask[i]))
{
int nst[3] = {st[0] + len, st[1] + len, st[2] + len};
nst[i] -= len;
// int nstt[3] = {1, 1, 1};
// nstt[i] -= 1;
LeafNode *node = locateLeafCheck(nst);
if (node == NULL) {
continue;
}
if (getStoredEdgesParity(node, eemask[i])) {
pts[emask[i]] = getEdgeOffsetNormalByIndex(node, eemask[i], norms[emask[i]]);
parity[emask[i]] = 1;
}
}
}
}
/// Update method
LeafNode *updateEdgeOffsetsNormals(LeafNode *leaf, int oldlen, int newlen, float offs[3], float a[3], float b[3], float c[3])
{
// First, create a new leaf node
LeafNode *nleaf = createLeaf(newlen);
*nleaf = *leaf;
// Next, fill in the offsets
setEdgeOffsetsNormals(nleaf, offs, a, b, c, newlen);
// Finally, delete the old leaf
removeLeaf(oldlen, leaf);
return nleaf;
}
/// Locate a leaf
/// WARNING: assuming this leaf already exists!
LeafNode *locateLeaf(int st[3])
{
Node *node = (Node *)root;
for (int i = GRID_DIMENSION - 1; i > GRID_DIMENSION - maxDepth - 1; i--) {
int index = (((st[0] >> i) & 1) << 2) |
(((st[1] >> i) & 1) << 1) |
(((st[2] >> i) & 1));
node = node->internal.get_child(node->internal.get_child_count(index));
}
return &node->leaf;
}
const LeafNode *locateLeaf(int st[3]) const
{
const Node *node = root;
for (int i = GRID_DIMENSION - 1; i > GRID_DIMENSION - maxDepth - 1; i--) {
int index = (((st[0] >> i) & 1) << 2) |
(((st[1] >> i) & 1) << 1) |
(((st[2] >> i) & 1));
node = node->internal.get_child(node->internal.get_child_count(index));
}
return &node->leaf;
}
LeafNode *locateLeaf(InternalNode *parent, int len, int st[3])
{
Node *node = (Node *)parent;
int index;
for (int i = len / 2; i >= mindimen; i >>= 1) {
index = (((st[0] & i) ? 4 : 0) |
((st[1] & i) ? 2 : 0) |
((st[2] & i) ? 1 : 0));
node = node->internal.get_child(node->internal.get_child_count(index));
}
return &node->leaf;
}
LeafNode *locateLeafCheck(int st[3])
{
Node *node = (Node *)root;
for (int i = GRID_DIMENSION - 1; i > GRID_DIMENSION - maxDepth - 1; i--) {
int index = (((st[0] >> i) & 1) << 2) |
(((st[1] >> i) & 1) << 1) |
(((st[2] >> i) & 1));
if (!node->internal.has_child(index)) {
return NULL;
}
node = node->internal.get_child(node->internal.get_child_count(index));
}
return &node->leaf;
}
const LeafNode *locateLeafCheck(int st[3]) const
{
const Node *node = root;
for (int i = GRID_DIMENSION - 1; i > GRID_DIMENSION - maxDepth - 1; i--) {
int index = (((st[0] >> i) & 1) << 2) |
(((st[1] >> i) & 1) << 1) |
(((st[2] >> i) & 1));
if (!node->internal.has_child(index)) {
return NULL;
}
node = node->internal.get_child(node->internal.get_child_count(index));
}
return &node->leaf;
}
InternalNode *locateParent(int len, int st[3], int& count)
{
InternalNode *node = (InternalNode *)root;
InternalNode *pre = NULL;
int index = 0;
for (int i = dimen / 2; i >= len; i >>= 1) {
index = (((st[0] & i) ? 4 : 0) |
((st[1] & i) ? 2 : 0) |
((st[2] & i) ? 1 : 0));
pre = node;
node = &node->get_child(node->get_child_count(index))->internal;
}
count = pre->get_child_count(index);
return pre;
}
InternalNode *locateParent(InternalNode *parent, int len, int st[3], int& count)
{
InternalNode *node = parent;
InternalNode *pre = NULL;
int index = 0;
for (int i = len / 2; i >= mindimen; i >>= 1) {
index = (((st[0] & i) ? 4 : 0) |
((st[1] & i) ? 2 : 0) |
((st[2] & i) ? 1 : 0));
pre = node;
node = &node->get_child(node->get_child_count(index))->internal;
}
count = pre->get_child_count(index);
return pre;
}
/************ Operators for internal nodes ************/
/// Add a kid to an existing internal node
InternalNode *addChild(InternalNode *node, int index, Node *child, int aLeaf)
{
// Create new internal node
int num = node->get_num_children();
InternalNode *rnode = createInternal(num + 1);
// Establish children
int i;
int count1 = 0, count2 = 0;
for (i = 0; i < 8; i++) {
if (i == index) {
if (aLeaf) {
rnode->set_leaf_child(i, count2, &child->leaf);
}
else {
rnode->set_internal_child(i, count2, &child->internal);
}
count2++;
}
else if (node->has_child(i)) {
if (node->is_child_leaf(i)) {
rnode->set_leaf_child(i, count2, &node->get_child(count1)->leaf);
}
else {
rnode->set_internal_child(i, count2, &node->get_child(count1)->internal);
}
count1++;
count2++;
}
}
removeInternal(num, node);
return rnode;
}
/// Allocate a node
InternalNode *createInternal(int length)
{
InternalNode *inode = (InternalNode *)alloc[length]->allocate();
inode->has_child_bitfield = 0;
inode->child_is_leaf_bitfield = 0;
return inode;
}
LeafNode *createLeaf(int length)
{
assert(length <= 3);
LeafNode *lnode = (LeafNode *)leafalloc[length]->allocate();
lnode->edge_parity = 0;
lnode->primary_edge_intersections = 0;
lnode->signs = 0;
return lnode;
}
void removeInternal(int num, InternalNode *node)
{
alloc[num]->deallocate(node);
}
void removeLeaf(int num, LeafNode *leaf)
{
assert(num >= 0 && num <= 3);
leafalloc[num]->deallocate(leaf);
}
/// Add a leaf (by creating a new par node with the leaf added)
InternalNode *addLeafChild(InternalNode *par, int index, int count,
LeafNode *leaf)
{
int num = par->get_num_children() + 1;
InternalNode *npar = createInternal(num);
*npar = *par;
if (num == 1) {
npar->set_leaf_child(index, 0, leaf);
}
else {
int i;
for (i = 0; i < count; i++) {
npar->set_child(i, par->get_child(i));
}
npar->set_leaf_child(index, count, leaf);
for (i = count + 1; i < num; i++) {
npar->set_child(i, par->get_child(i - 1));
}
}
removeInternal(num - 1, par);
return npar;
}
InternalNode *addInternalChild(InternalNode *par, int index, int count,
InternalNode *node)
{
int num = par->get_num_children() + 1;
InternalNode *npar = createInternal(num);
*npar = *par;
if (num == 1) {
npar->set_internal_child(index, 0, node);
}
else {
int i;
for (i = 0; i < count; i++) {
npar->set_child(i, par->get_child(i));
}
npar->set_internal_child(index, count, node);
for (i = count + 1; i < num; i++) {
npar->set_child(i, par->get_child(i - 1));
}
}
removeInternal(num - 1, par);
return npar;
}
/************ Operators for all nodes ************/
/// Lookup table
int numEdgeTable[8];
int edgeCountTable[8][3];
/// Build up lookup table
void buildTable()
{
for (int i = 0; i < 256; i++) {
InternalNode::numChildrenTable[i] = 0;
int count = 0;
for (int j = 0; j < 8; j++) {
InternalNode::numChildrenTable[i] += ((i >> j) & 1);
InternalNode::childrenCountTable[i][j] = count;
InternalNode::childrenIndexTable[i][count] = j;
count += ((i >> j) & 1);
}
}
for (int i = 0; i < 8; i++) {
numEdgeTable[i] = 0;
int count = 0;
for (int j = 0; j < 3; j++) {
numEdgeTable[i] += ((i >> j) & 1);
edgeCountTable[i][j] = count;
count += ((i >> j) & 1);
}
}
}
int getSign(Node *node, int height, int index)
{
if (height == 0) {
return getSign(&node->leaf, index);
}
else {
if (node->internal.has_child(index)) {
return getSign(
node->internal.get_child(node->internal.get_child_count(index)), height - 1, index);
}
else {
return getSign(
node->internal.get_child(0), height - 1, 7 - node->internal.get_child_index(0));
}
}
}
/************ Operators for leaf nodes ************/
void printInfo(int st[3])
{
printf("INFO AT: %d %d %d\n", st[0] >> minshift, st[1] >> minshift, st[2] >> minshift);
LeafNode *leaf = (LeafNode *)locateLeafCheck(st);
if (leaf)
printInfo(leaf);
else
printf("Leaf not exists!\n");
}
void printInfo(const LeafNode *leaf)
{
/*
printf("Edge mask: ");
for(int i = 0; i < 12; i ++)
{
printf("%d ", getEdgeParity(leaf, i));
}
printf("\n");
printf("Stored edge mask: ");
for(i = 0; i < 3; i ++)
{
printf("%d ", getStoredEdgesParity(leaf, i));
}
printf("\n");
*/
printf("Sign mask: ");
for (int i = 0; i < 8; i++) {
printf("%d ", getSign(leaf, i));
}
printf("\n");
}
/// Retrieve signs
int getSign(const LeafNode *leaf, int index)
{
return ((leaf->signs >> index) & 1);
}
/// Set sign
void setSign(LeafNode *leaf, int index)
{
leaf->signs |= (1 << index);
}
void setSign(LeafNode *leaf, int index, int sign)
{
leaf->signs &= (~(1 << index));
leaf->signs |= ((sign & 1) << index);
}
int getSignMask(const LeafNode *leaf) const
{
return leaf->signs;
}
void setInProcessAll(int st[3], int dir)
{
int nst[3], eind;
for (int i = 0; i < 4; i++) {
nst[0] = st[0] + dirCell[dir][i][0] * mindimen;
nst[1] = st[1] + dirCell[dir][i][1] * mindimen;
nst[2] = st[2] + dirCell[dir][i][2] * mindimen;
eind = dirEdge[dir][i];
LeafNode *cell = locateLeafCheck(nst);
assert(cell);
setInProcess(cell, eind);
}
}
void flipParityAll(int st[3], int dir)
{
int nst[3], eind;
for (int i = 0; i < 4; i++) {
nst[0] = st[0] + dirCell[dir][i][0] * mindimen;
nst[1] = st[1] + dirCell[dir][i][1] * mindimen;
nst[2] = st[2] + dirCell[dir][i][2] * mindimen;
eind = dirEdge[dir][i];
LeafNode *cell = locateLeaf(nst);
flipEdge(cell, eind);
}
}
void setInProcess(LeafNode *leaf, int eind)
{
assert(eind >= 0 && eind <= 11);
leaf->flood_fill |= (1 << eind);
}
void setOutProcess(LeafNode *leaf, int eind)
{
assert(eind >= 0 && eind <= 11);
leaf->flood_fill &= ~(1 << eind);
}
int isInProcess(LeafNode *leaf, int eind)
{
assert(eind >= 0 && eind <= 11);
return (leaf->flood_fill >> eind) & 1;
}
/// Generate signs at the corners from the edge parity
void generateSigns(LeafNode *leaf, unsigned char table[], int start)
{
leaf->signs = table[leaf->edge_parity];
if ((start ^ leaf->signs) & 1) {
leaf->signs = ~(leaf->signs);
}
}
/// Get edge parity
int getEdgeParity(const LeafNode *leaf, int index) const
{
assert(index >= 0 && index <= 11);
return (leaf->edge_parity >> index) & 1;
}
/// Get edge parity on a face
int getFaceParity(LeafNode *leaf, int index)
{
int a = getEdgeParity(leaf, faceMap[index][0]) + getEdgeParity(leaf, faceMap[index][1]) +
getEdgeParity(leaf, faceMap[index][2]) + getEdgeParity(leaf, faceMap[index][3]);
return (a & 1);
}
int getFaceEdgeNum(LeafNode *leaf, int index)
{
int a = getEdgeParity(leaf, faceMap[index][0]) + getEdgeParity(leaf, faceMap[index][1]) +
getEdgeParity(leaf, faceMap[index][2]) + getEdgeParity(leaf, faceMap[index][3]);
return a;
}
/// Set edge parity
void flipEdge(LeafNode *leaf, int index)
{
assert(index >= 0 && index <= 11);
leaf->edge_parity ^= (1 << index);
}
/// Set 1
void setEdge(LeafNode *leaf, int index)
{
assert(index >= 0 && index <= 11);
leaf->edge_parity |= (1 << index);
}
/// Set 0
void resetEdge(LeafNode *leaf, int index)
{
assert(index >= 0 && index <= 11);
leaf->edge_parity &= ~(1 << index);
}
/// Flipping with a new intersection offset
void createPrimalEdgesMask(LeafNode *leaf)
{
leaf->primary_edge_intersections = getPrimalEdgesMask2(leaf);
}
void setStoredEdgesParity(LeafNode *leaf, int pindex)
{
assert(pindex <= 2 && pindex >= 0);
leaf->primary_edge_intersections |= (1 << pindex);
}
int getStoredEdgesParity(const LeafNode *leaf, int pindex) const
{
assert(pindex <= 2 && pindex >= 0);
return (leaf->primary_edge_intersections >> pindex) & 1;
}
LeafNode *flipEdge(LeafNode *leaf, int index, float alpha)
{
flipEdge(leaf, index);
if ((index & 3) == 0) {
int ind = index / 4;
if (getEdgeParity(leaf, index) && !getStoredEdgesParity(leaf, ind)) {
// Create a new node
int num = getNumEdges(leaf) + 1;
setStoredEdgesParity(leaf, ind);
int count = getEdgeCount(leaf, ind);
LeafNode *nleaf = createLeaf(num);
*nleaf = *leaf;
setEdgeOffset(nleaf, alpha, count);
if (num > 1) {
float *pts = leaf->edge_intersections;
float *npts = nleaf->edge_intersections;
for (int i = 0; i < count; i++) {
for (int j = 0; j < EDGE_FLOATS; j++) {
npts[i * EDGE_FLOATS + j] = pts[i * EDGE_FLOATS + j];
}
}
for (int i = count + 1; i < num; i++) {
for (int j = 0; j < EDGE_FLOATS; j++) {
npts[i * EDGE_FLOATS + j] = pts[(i - 1) * EDGE_FLOATS + j];
}
}
}
removeLeaf(num - 1, (LeafNode *)leaf);
leaf = nleaf;
}
}
return leaf;
}
/// Update parent link
void updateParent(InternalNode *node, int len, int st[3], LeafNode *leaf)
{
// First, locate the parent
int count;
InternalNode *parent = locateParent(node, len, st, count);
// Update
parent->set_child(count, (Node *)leaf);
}
void updateParent(InternalNode *node, int len, int st[3])
{
if (len == dimen) {
root = (Node *)node;
return;
}
// First, locate the parent
int count;
InternalNode *parent = locateParent(len, st, count);
// UPdate
parent->set_child(count, (Node *)node);
}
/// Find edge intersection on a given edge
int getEdgeIntersectionByIndex(int st[3], int index, float pt[3], int check) const
{
// First, locat the leaf
const LeafNode *leaf;
if (check) {
leaf = locateLeafCheck(st);
}
else {
leaf = locateLeaf(st);
}
if (leaf && getStoredEdgesParity(leaf, index)) {
float off = getEdgeOffset(leaf, getEdgeCount(leaf, index));
pt[0] = (float)st[0];
pt[1] = (float)st[1];
pt[2] = (float)st[2];
pt[index] += off * mindimen;
return 1;
}
else {
return 0;
}
}
/// Retrieve number of edges intersected
int getPrimalEdgesMask(const LeafNode *leaf) const
{
return leaf->primary_edge_intersections;
}
int getPrimalEdgesMask2(LeafNode *leaf)
{
return (((leaf->edge_parity & 0x1) >> 0) | ((leaf->edge_parity & 0x10) >> 3) |
((leaf->edge_parity & 0x100) >> 6));
}
/// Get the count for a primary edge
int getEdgeCount(const LeafNode *leaf, int index) const
{
return edgeCountTable[getPrimalEdgesMask(leaf)][index];
}
int getNumEdges(LeafNode *leaf)
{
return numEdgeTable[getPrimalEdgesMask(leaf)];
}
int getNumEdges2(LeafNode *leaf)
{
return numEdgeTable[getPrimalEdgesMask2(leaf)];
}
/// Set edge intersection
void setEdgeOffset(LeafNode *leaf, float pt, int count)
{
float *pts = leaf->edge_intersections;
pts[EDGE_FLOATS * count] = pt;
pts[EDGE_FLOATS * count + 1] = 0;
pts[EDGE_FLOATS * count + 2] = 0;
pts[EDGE_FLOATS * count + 3] = 0;
}
/// Set multiple edge intersections
void setEdgeOffsets(LeafNode *leaf, float pt[3], int len)
{
float *pts = leaf->edge_intersections;
for (int i = 0; i < len; i++) {
pts[i] = pt[i];
}
}
/// Retrieve edge intersection
float getEdgeOffset(const LeafNode *leaf, int count) const
{
return leaf->edge_intersections[4 * count];
}
/// Update method
LeafNode *updateEdgeOffsets(LeafNode *leaf, int oldlen, int newlen, float offs[3])
{
// First, create a new leaf node
LeafNode *nleaf = createLeaf(newlen);
*nleaf = *leaf;
// Next, fill in the offsets
setEdgeOffsets(nleaf, offs, newlen);
// Finally, delete the old leaf
removeLeaf(oldlen, leaf);
return nleaf;
}
/// Set minimizer index
void setMinimizerIndex(LeafNode *leaf, int index)
{
leaf->minimizer_index = index;
}
/// Get minimizer index
int getMinimizerIndex(LeafNode *leaf)
{
return leaf->minimizer_index;
}
int getMinimizerIndex(LeafNode *leaf, int eind)
{
int add = manifold_table[getSignMask(leaf)].pairs[eind][0] - 1;
assert(add >= 0);
return leaf->minimizer_index + add;
}
void getMinimizerIndices(LeafNode *leaf, int eind, int inds[2])
{
const int *add = manifold_table[getSignMask(leaf)].pairs[eind];
inds[0] = leaf->minimizer_index + add[0] - 1;
if (add[0] == add[1]) {
inds[1] = -1;
}
else {
inds[1] = leaf->minimizer_index + add[1] - 1;
}
}
/// Set edge intersection
void setEdgeOffsetNormal(LeafNode *leaf, float pt, float a, float b, float c, int count)
{
float *pts = leaf->edge_intersections;
pts[4 * count] = pt;
pts[4 * count + 1] = a;
pts[4 * count + 2] = b;
pts[4 * count + 3] = c;
}
float getEdgeOffsetNormal(LeafNode *leaf, int count, float &a, float &b, float &c)
{
float *pts = leaf->edge_intersections;
a = pts[4 * count + 1];
b = pts[4 * count + 2];
c = pts[4 * count + 3];
return pts[4 * count];
}
/// Set multiple edge intersections
void setEdgeOffsetsNormals(
LeafNode *leaf, const float pt[], const float a[], const float b[], const float c[], int len)
{
float *pts = leaf->edge_intersections;
for (int i = 0; i < len; i++) {
if (pt[i] > 1 || pt[i] < 0) {
printf("\noffset: %f\n", pt[i]);
}
pts[i * 4] = pt[i];
pts[i * 4 + 1] = a[i];
pts[i * 4 + 2] = b[i];
pts[i * 4 + 3] = c[i];
}
}
/// Retrieve complete edge intersection
void getEdgeIntersectionByIndex(
const LeafNode *leaf, int index, int st[3], int len, float pt[3], float nm[3]) const
{
int count = getEdgeCount(leaf, index);
const float *pts = leaf->edge_intersections;
float off = pts[4 * count];
pt[0] = (float)st[0];
pt[1] = (float)st[1];
pt[2] = (float)st[2];
pt[index] += (off * len);
nm[0] = pts[4 * count + 1];
nm[1] = pts[4 * count + 2];
nm[2] = pts[4 * count + 3];
}
float getEdgeOffsetNormalByIndex(LeafNode *leaf, int index, float nm[3])
{
int count = getEdgeCount(leaf, index);
float *pts = leaf->edge_intersections;
float off = pts[4 * count];
nm[0] = pts[4 * count + 1];
nm[1] = pts[4 * count + 2];
nm[2] = pts[4 * count + 3];
return off;
}
void fillEdgeIntersections(
const LeafNode *leaf, int st[3], int len, float pts[12][3], float norms[12][3]) const
{
int i;
// int stt[3] = {0, 0, 0};
// The three primal edges are easy
int pmask[3] = {0, 4, 8};
for (i = 0; i < 3; i++) {
if (getEdgeParity(leaf, pmask[i])) {
// getEdgeIntersectionByIndex(leaf, i, stt, 1, pts[pmask[i]], norms[pmask[i]]);
getEdgeIntersectionByIndex(leaf, i, st, len, pts[pmask[i]], norms[pmask[i]]);
}
}
// 3 face adjacent cubes
int fmask[3][2] = {{6, 10}, {2, 9}, {1, 5}};
int femask[3][2] = {{1, 2}, {0, 2}, {0, 1}};
for (i = 0; i < 3; i++) {
int e1 = getEdgeParity(leaf, fmask[i][0]);
int e2 = getEdgeParity(leaf, fmask[i][1]);
if (e1 || e2) {
int nst[3] = {st[0], st[1], st[2]};
nst[i] += len;
// int nstt[3] = {0, 0, 0};
// nstt[i] += 1;
const LeafNode *node = locateLeaf(nst);
if (e1) {
// getEdgeIntersectionByIndex(node, femask[i][0], nstt, 1, pts[fmask[i][0]], norms[fmask[i][0]]);
getEdgeIntersectionByIndex(
node, femask[i][0], nst, len, pts[fmask[i][0]], norms[fmask[i][0]]);
}
if (e2) {
// getEdgeIntersectionByIndex(node, femask[i][1], nstt, 1, pts[fmask[i][1]], norms[fmask[i][1]]);
getEdgeIntersectionByIndex(
node, femask[i][1], nst, len, pts[fmask[i][1]], norms[fmask[i][1]]);
}
}
}
// 3 edge adjacent cubes
int emask[3] = {3, 7, 11};
int eemask[3] = {0, 1, 2};
for (i = 0; i < 3; i++) {
if (getEdgeParity(leaf, emask[i])) {
int nst[3] = {st[0] + len, st[1] + len, st[2] + len};
nst[i] -= len;
// int nstt[3] = {1, 1, 1};
// nstt[i] -= 1;
const LeafNode *node = locateLeaf(nst);
// getEdgeIntersectionByIndex(node, eemask[i], nstt, 1, pts[emask[i]], norms[emask[i]]);
getEdgeIntersectionByIndex(node, eemask[i], nst, len, pts[emask[i]], norms[emask[i]]);
}
}
}
void fillEdgeIntersections(const LeafNode *leaf,
int st[3],
int len,
float pts[12][3],
float norms[12][3],
int parity[12]) const
{
int i;
for (i = 0; i < 12; i++) {
parity[i] = 0;
}
// int stt[3] = {0, 0, 0};
// The three primal edges are easy
int pmask[3] = {0, 4, 8};
for (i = 0; i < 3; i++) {
if (getStoredEdgesParity(leaf, i)) {
// getEdgeIntersectionByIndex(leaf, i, stt, 1, pts[pmask[i]], norms[pmask[i]]);
getEdgeIntersectionByIndex(leaf, i, st, len, pts[pmask[i]], norms[pmask[i]]);
parity[pmask[i]] = 1;
}
}
// 3 face adjacent cubes
int fmask[3][2] = {{6, 10}, {2, 9}, {1, 5}};
int femask[3][2] = {{1, 2}, {0, 2}, {0, 1}};
for (i = 0; i < 3; i++) {
{
int nst[3] = {st[0], st[1], st[2]};
nst[i] += len;
// int nstt[3] = {0, 0, 0};
// nstt[i] += 1;
const LeafNode *node = locateLeafCheck(nst);
if (node == NULL) {
continue;
}
int e1 = getStoredEdgesParity(node, femask[i][0]);
int e2 = getStoredEdgesParity(node, femask[i][1]);
if (e1) {
// getEdgeIntersectionByIndex(node, femask[i][0], nstt, 1, pts[fmask[i][0]], norms[fmask[i][0]]);
getEdgeIntersectionByIndex(
node, femask[i][0], nst, len, pts[fmask[i][0]], norms[fmask[i][0]]);
parity[fmask[i][0]] = 1;
}
if (e2) {
// getEdgeIntersectionByIndex(node, femask[i][1], nstt, 1, pts[fmask[i][1]], norms[fmask[i][1]]);
getEdgeIntersectionByIndex(
node, femask[i][1], nst, len, pts[fmask[i][1]], norms[fmask[i][1]]);
parity[fmask[i][1]] = 1;
}
}
}
// 3 edge adjacent cubes
int emask[3] = {3, 7, 11};
int eemask[3] = {0, 1, 2};
for (i = 0; i < 3; i++) {
// if(getEdgeParity(leaf, emask[i]))
{
int nst[3] = {st[0] + len, st[1] + len, st[2] + len};
nst[i] -= len;
// int nstt[3] = {1, 1, 1};
// nstt[i] -= 1;
const LeafNode *node = locateLeafCheck(nst);
if (node == NULL) {
continue;
}
if (getStoredEdgesParity(node, eemask[i])) {
// getEdgeIntersectionByIndex(node, eemask[i], nstt, 1, pts[emask[i]], norms[emask[i]]);
getEdgeIntersectionByIndex(node, eemask[i], nst, len, pts[emask[i]], norms[emask[i]]);
parity[emask[i]] = 1;
}
}
}
}
void fillEdgeOffsetsNormals(
LeafNode *leaf, int st[3], int len, float pts[12], float norms[12][3], int parity[12])
{
int i;
for (i = 0; i < 12; i++) {
parity[i] = 0;
}
// int stt[3] = {0, 0, 0};
// The three primal edges are easy
int pmask[3] = {0, 4, 8};
for (i = 0; i < 3; i++) {
if (getStoredEdgesParity(leaf, i)) {
pts[pmask[i]] = getEdgeOffsetNormalByIndex(leaf, i, norms[pmask[i]]);
parity[pmask[i]] = 1;
}
}
// 3 face adjacent cubes
int fmask[3][2] = {{6, 10}, {2, 9}, {1, 5}};
int femask[3][2] = {{1, 2}, {0, 2}, {0, 1}};
for (i = 0; i < 3; i++) {
{
int nst[3] = {st[0], st[1], st[2]};
nst[i] += len;
// int nstt[3] = {0, 0, 0};
// nstt[i] += 1;
LeafNode *node = locateLeafCheck(nst);
if (node == NULL) {
continue;
}
int e1 = getStoredEdgesParity(node, femask[i][0]);
int e2 = getStoredEdgesParity(node, femask[i][1]);
if (e1) {
pts[fmask[i][0]] = getEdgeOffsetNormalByIndex(node, femask[i][0], norms[fmask[i][0]]);
parity[fmask[i][0]] = 1;
}
if (e2) {
pts[fmask[i][1]] = getEdgeOffsetNormalByIndex(node, femask[i][1], norms[fmask[i][1]]);
parity[fmask[i][1]] = 1;
}
}
}
// 3 edge adjacent cubes
int emask[3] = {3, 7, 11};
int eemask[3] = {0, 1, 2};
for (i = 0; i < 3; i++) {
// if(getEdgeParity(leaf, emask[i]))
{
int nst[3] = {st[0] + len, st[1] + len, st[2] + len};
nst[i] -= len;
// int nstt[3] = {1, 1, 1};
// nstt[i] -= 1;
LeafNode *node = locateLeafCheck(nst);
if (node == NULL) {
continue;
}
if (getStoredEdgesParity(node, eemask[i])) {
pts[emask[i]] = getEdgeOffsetNormalByIndex(node, eemask[i], norms[emask[i]]);
parity[emask[i]] = 1;
}
}
}
}
/// Update method
LeafNode *updateEdgeOffsetsNormals(
LeafNode *leaf, int oldlen, int newlen, float offs[3], float a[3], float b[3], float c[3])
{
// First, create a new leaf node
LeafNode *nleaf = createLeaf(newlen);
*nleaf = *leaf;
// Next, fill in the offsets
setEdgeOffsetsNormals(nleaf, offs, a, b, c, newlen);
// Finally, delete the old leaf
removeLeaf(oldlen, leaf);
return nleaf;
}
/// Locate a leaf
/// WARNING: assuming this leaf already exists!
LeafNode *locateLeaf(int st[3])
{
Node *node = (Node *)root;
for (int i = GRID_DIMENSION - 1; i > GRID_DIMENSION - maxDepth - 1; i--) {
int index = (((st[0] >> i) & 1) << 2) | (((st[1] >> i) & 1) << 1) | (((st[2] >> i) & 1));
node = node->internal.get_child(node->internal.get_child_count(index));
}
return &node->leaf;
}
const LeafNode *locateLeaf(int st[3]) const
{
const Node *node = root;
for (int i = GRID_DIMENSION - 1; i > GRID_DIMENSION - maxDepth - 1; i--) {
int index = (((st[0] >> i) & 1) << 2) | (((st[1] >> i) & 1) << 1) | (((st[2] >> i) & 1));
node = node->internal.get_child(node->internal.get_child_count(index));
}
return &node->leaf;
}
LeafNode *locateLeaf(InternalNode *parent, int len, int st[3])
{
Node *node = (Node *)parent;
int index;
for (int i = len / 2; i >= mindimen; i >>= 1) {
index = (((st[0] & i) ? 4 : 0) | ((st[1] & i) ? 2 : 0) | ((st[2] & i) ? 1 : 0));
node = node->internal.get_child(node->internal.get_child_count(index));
}
return &node->leaf;
}
LeafNode *locateLeafCheck(int st[3])
{
Node *node = (Node *)root;
for (int i = GRID_DIMENSION - 1; i > GRID_DIMENSION - maxDepth - 1; i--) {
int index = (((st[0] >> i) & 1) << 2) | (((st[1] >> i) & 1) << 1) | (((st[2] >> i) & 1));
if (!node->internal.has_child(index)) {
return NULL;
}
node = node->internal.get_child(node->internal.get_child_count(index));
}
return &node->leaf;
}
const LeafNode *locateLeafCheck(int st[3]) const
{
const Node *node = root;
for (int i = GRID_DIMENSION - 1; i > GRID_DIMENSION - maxDepth - 1; i--) {
int index = (((st[0] >> i) & 1) << 2) | (((st[1] >> i) & 1) << 1) | (((st[2] >> i) & 1));
if (!node->internal.has_child(index)) {
return NULL;
}
node = node->internal.get_child(node->internal.get_child_count(index));
}
return &node->leaf;
}
InternalNode *locateParent(int len, int st[3], int &count)
{
InternalNode *node = (InternalNode *)root;
InternalNode *pre = NULL;
int index = 0;
for (int i = dimen / 2; i >= len; i >>= 1) {
index = (((st[0] & i) ? 4 : 0) | ((st[1] & i) ? 2 : 0) | ((st[2] & i) ? 1 : 0));
pre = node;
node = &node->get_child(node->get_child_count(index))->internal;
}
count = pre->get_child_count(index);
return pre;
}
InternalNode *locateParent(InternalNode *parent, int len, int st[3], int &count)
{
InternalNode *node = parent;
InternalNode *pre = NULL;
int index = 0;
for (int i = len / 2; i >= mindimen; i >>= 1) {
index = (((st[0] & i) ? 4 : 0) | ((st[1] & i) ? 2 : 0) | ((st[2] & i) ? 1 : 0));
pre = node;
node = &node->get_child(node->get_child_count(index))->internal;
}
count = pre->get_child_count(index);
return pre;
}
/************ Operators for internal nodes ************/
/// Add a kid to an existing internal node
InternalNode *addChild(InternalNode *node, int index, Node *child, int aLeaf)
{
// Create new internal node
int num = node->get_num_children();
InternalNode *rnode = createInternal(num + 1);
// Establish children
int i;
int count1 = 0, count2 = 0;
for (i = 0; i < 8; i++) {
if (i == index) {
if (aLeaf) {
rnode->set_leaf_child(i, count2, &child->leaf);
}
else {
rnode->set_internal_child(i, count2, &child->internal);
}
count2++;
}
else if (node->has_child(i)) {
if (node->is_child_leaf(i)) {
rnode->set_leaf_child(i, count2, &node->get_child(count1)->leaf);
}
else {
rnode->set_internal_child(i, count2, &node->get_child(count1)->internal);
}
count1++;
count2++;
}
}
removeInternal(num, node);
return rnode;
}
/// Allocate a node
InternalNode *createInternal(int length)
{
InternalNode *inode = (InternalNode *)alloc[length]->allocate();
inode->has_child_bitfield = 0;
inode->child_is_leaf_bitfield = 0;
return inode;
}
LeafNode *createLeaf(int length)
{
assert(length <= 3);
LeafNode *lnode = (LeafNode *)leafalloc[length]->allocate();
lnode->edge_parity = 0;
lnode->primary_edge_intersections = 0;
lnode->signs = 0;
return lnode;
}
void removeInternal(int num, InternalNode *node)
{
alloc[num]->deallocate(node);
}
void removeLeaf(int num, LeafNode *leaf)
{
assert(num >= 0 && num <= 3);
leafalloc[num]->deallocate(leaf);
}
/// Add a leaf (by creating a new par node with the leaf added)
InternalNode *addLeafChild(InternalNode *par, int index, int count, LeafNode *leaf)
{
int num = par->get_num_children() + 1;
InternalNode *npar = createInternal(num);
*npar = *par;
if (num == 1) {
npar->set_leaf_child(index, 0, leaf);
}
else {
int i;
for (i = 0; i < count; i++) {
npar->set_child(i, par->get_child(i));
}
npar->set_leaf_child(index, count, leaf);
for (i = count + 1; i < num; i++) {
npar->set_child(i, par->get_child(i - 1));
}
}
removeInternal(num - 1, par);
return npar;
}
InternalNode *addInternalChild(InternalNode *par, int index, int count, InternalNode *node)
{
int num = par->get_num_children() + 1;
InternalNode *npar = createInternal(num);
*npar = *par;
if (num == 1) {
npar->set_internal_child(index, 0, node);
}
else {
int i;
for (i = 0; i < count; i++) {
npar->set_child(i, par->get_child(i));
}
npar->set_internal_child(index, count, node);
for (i = count + 1; i < num; i++) {
npar->set_child(i, par->get_child(i - 1));
}
}
removeInternal(num - 1, par);
return npar;
}
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("DUALCON:Octree")
MEM_CXX_CLASS_ALLOC_FUNCS("DUALCON:Octree")
#endif
};
#endif /* __OCTREE_H__ */
#endif /* __OCTREE_H__ */