Code style cleanup in intern/dualcon.

This commit is contained in:
Nicholas Bishop
2012-05-08 22:11:05 +00:00
parent d9ce1cda94
commit 56342f222f
12 changed files with 3585 additions and 3925 deletions

View File

@@ -24,7 +24,7 @@
#define __DUALCON_H__
#ifdef __cplusplus
extern "C" {
extern "C" {
#endif
typedef float (*DualConCo)[3];
@@ -35,11 +35,11 @@ typedef struct DualConInput {
DualConCo co;
int co_stride;
int totco;
DualConFaces faces;
int face_stride;
int totface;
float min[3], max[3];
} DualConInput;
@@ -64,32 +64,32 @@ typedef enum {
} DualConMode;
/* Usage:
The three callback arguments are used for creating the output
mesh. The alloc_output callback takes the total number of vertices
and faces (quads) that will be in the output. It should allocate
and return a structure to hold the output mesh. The add_vert and
add_quad callbacks will then be called for each new vertex and
quad, and the callback should add the new mesh elements to the
structure.
*/
*
* The three callback arguments are used for creating the output
* mesh. The alloc_output callback takes the total number of vertices
* and faces (quads) that will be in the output. It should allocate
* and return a structure to hold the output mesh. The add_vert and
* add_quad callbacks will then be called for each new vertex and
* quad, and the callback should add the new mesh elements to the
* structure.
*/
void *dualcon(const DualConInput *input_mesh,
/* callbacks for output */
DualConAllocOutput alloc_output,
DualConAddVert add_vert,
DualConAddQuad add_quad,
/* callbacks for output */
DualConAllocOutput alloc_output,
DualConAddVert add_vert,
DualConAddQuad add_quad,
/* flags and settings to control the remeshing
algorithm */
DualConFlags flags,
DualConMode mode,
float threshold,
float hermite_num,
float scale,
int depth);
/* flags and settings to control the remeshing
* algorithm */
DualConFlags flags,
DualConMode mode,
float threshold,
float hermite_num,
float scale,
int depth);
#ifdef __cplusplus
}
}
#endif
#endif /* __DUALCON_H__ */

View File

@@ -36,31 +36,26 @@
// 3d point with integer coordinates
typedef struct
{
typedef struct {
int x, y, z;
} Point3i;
typedef struct
{
typedef struct {
Point3i begin;
Point3i end;
} BoundingBox;
// triangle that points to three vertices
typedef struct
{
float vt[3][3] ;
typedef struct {
float vt[3][3];
} Triangle;
// 3d point with float coordinates
typedef struct
{
typedef struct {
float x, y, z;
} Point3f;
typedef struct
{
typedef struct {
Point3f begin;
Point3f end;
} BoundingBoxf;

View File

@@ -43,19 +43,19 @@
class VirtualMemoryAllocator
{
public:
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;
};
/**
* Dynamic memory allocator - allows allocation/deallocation
*
*
* Note: there are 4 bytes overhead for each allocated yet unused object.
*/
template < int N >
@@ -63,157 +63,157 @@ 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 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);
// Update allocation stack
for (int i = 0; i < HEAP_UNIT; i++)
{
// 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 ;
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 * ) ) ;
}
/**
* 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 *) );
}
public:
/**
* Constructor
*/
MemoryAllocator( )
/**
* Constructor
*/
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;
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++)
{
HEAP_UNIT = 1 << HEAP_BASE ;
HEAP_MASK = ( 1 << HEAP_BASE ) - 1 ;
stack[0][i] = (data[0] + i * N);
}
}
data = ( UCHAR ** )malloc( sizeof( UCHAR * ) ) ;
data[ 0 ] = ( UCHAR * )malloc( HEAP_UNIT * N ) ;
datablocknum = 1 ;
/**
* 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);
}
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 ) ;
}
/**
* Allocation method
*/
void *allocate( )
{
if (available == 0)
{
allocateDataBlock( );
}
/**
* Destructor
*/
void destroy( )
// 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)
{
int i ;
for ( i = 0 ; i < datablocknum ; i ++ )
{
free( data[ i ] ) ;
}
for ( i = 0 ; i < stackblocknum ; i ++ )
{
free( stack[ i ] ) ;
}
free( data ) ;
free( stack ) ;
allocateStackBlock( );
}
/**
* Allocation method
*/
void * allocate ( )
{
if ( available == 0 )
{
allocateDataBlock ( ) ;
}
// 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("Allocating %d\n", header[ allocated ]) ;
available -- ;
return (void*)stack[ available >> HEAP_BASE ][ available & HEAP_MASK ] ;
}
/**
* Print information
*/
void printInfo( )
{
printf("Bytes: %d Used: %d Allocated: %d Maxfree: %d\n", getBytes(), getAllocated(), getAll(), stacksize);
}
/**
* De-allocation method
*/
void deallocate ( void * obj )
{
if ( available == stacksize )
{
allocateStackBlock ( ) ;
}
/**
* Query methods
*/
int getAllocated( )
{
return HEAP_UNIT * datablocknum - available;
};
// 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 ]) ;
}
int getAll( )
{
return HEAP_UNIT * datablocknum;
};
/**
* Print information
*/
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 getAll( )
{
return HEAP_UNIT * datablocknum ;
};
int getBytes( )
{
return N ;
};
int getBytes( )
{
return N;
};
};
#endif

View File

@@ -33,31 +33,32 @@
class ModelReader
{
public:
/// Constructor
ModelReader(){} ;
/// 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;
};

View File

@@ -37,18 +37,15 @@ const int vertmap[8][3] = {
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}}
},
{{2, 2}, {2, 3}, {3, 3}}},
{{{0, 4}, {0, 5}, {1, 5}},
{{0, 6}, {0, 7}, {1, 7}},
{{2, 6}, {2, 7}, {3, 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}}
}
{{6, 6}, {6, 7}, {7, 7}}}
};
const int edgemap[12][2] = {

View File

@@ -54,20 +54,19 @@ extern const int facemap[6][4];
/**
* Structure for the projections inheritable from parent
*/
struct InheritableProjections
{
struct InheritableProjections {
/// Projections of triangle
LONG trigProj[13][2] ;
LONG trigProj[13][2];
/// Projections of triangle vertices on primary axes
LONG trigVertProj[13][3] ;
LONG trigVertProj[13][3];
/// Projections of triangle edges
LONG trigEdgeProj[13][3][2] ;
LONG trigEdgeProj[13][3][2];
/// Normal of the triangle
double norm[3] ;
double normA, normB ;
double norm[3];
double normA, normB;
/// End points along each axis
//int cubeEnds[13][2] ;
@@ -77,7 +76,7 @@ struct InheritableProjections
#ifdef CONTAINS_INDEX
/// Index of polygon
int index ;
int index;
#endif
};
@@ -88,758 +87,754 @@ struct InheritableProjections
class Projections
{
public:
/// Inheritable portion
InheritableProjections* inherit ;
/// Inheritable portion
InheritableProjections *inherit;
/// Projections of the cube vertices
LONG cubeProj[13][6] ;
/// Projections of the cube vertices
LONG cubeProj[13][6];
public:
Projections( )
{
}
Projections( )
{
}
/**
* Construction
* from a cube (axes aligned) and triangle
*/
Projections( LONG cube[2][3], LONG trig[3][3], LONG error, int triind )
{
int i, j ;
inherit = new InheritableProjections ;
/**
* Construction
* from a cube (axes aligned) and triangle
*/
Projections(LONG cube[2][3], LONG trig[3][3], LONG error, int triind)
{
int i, j;
inherit = new InheritableProjections;
#ifdef CONTAINS_INDEX
inherit->index = triind ;
inherit->index = triind;
#endif
/// Create axes
LONG axes[13][3] ;
/// Create axes
LONG axes[13][3];
// Cube faces
axes[0][0] = 1 ;
axes[0][1] = 0 ;
axes[0][2] = 0 ;
// Cube faces
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[1][0] = 0;
axes[1][1] = 1;
axes[1][2] = 0;
axes[2][0] = 0 ;
axes[2][1] = 0 ;
axes[2][2] = 1 ;
axes[2][0] = 0;
axes[2][1] = 0;
axes[2][2] = 1;
// Triangle face
LONG trigedge[3][3] ;
for ( i = 0 ; i < 3 ; i ++ )
// Triangle face
LONG trigedge[3][3];
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
for ( j = 0 ; j < 3 ; j ++ )
{
trigedge[i][j] = trig[(i+1)%3][j] - trig[i][j] ;
}
trigedge[i][j] = trig[(i + 1) % 3][j] - trig[i][j];
}
crossProduct( trigedge[0], trigedge[1], axes[3] ) ;
}
crossProduct(trigedge[0], trigedge[1], axes[3]);
/// Normalize face normal and store
double dedge1[] = { (double) trig[1][0] - (double) trig[0][0],
(double) trig[1][1] - (double) trig[0][1],
(double) trig[1][2] - (double) trig[0][2] } ;
double dedge2[] = { (double) trig[2][0] - (double) trig[1][0],
(double) trig[2][1] - (double) trig[1][1],
(double) trig[2][2] - (double) trig[1][2] } ;
crossProduct( dedge1, dedge2, inherit->norm ) ;
normalize( inherit->norm ) ;
/// Normalize face normal and store
double dedge1[] = { (double) trig[1][0] - (double) trig[0][0],
(double) trig[1][1] - (double) trig[0][1],
(double) trig[1][2] - (double) trig[0][2] };
double dedge2[] = { (double) trig[2][0] - (double) trig[1][0],
(double) trig[2][1] - (double) trig[1][1],
(double) trig[2][2] - (double) trig[1][2] };
crossProduct(dedge1, dedge2, inherit->norm);
normalize(inherit->norm);
// inherit->normA = norm[ 0 ] ;
// inherit->normB = norm[ 2 ] > 0 ? norm[ 1 ] : 2 + norm[ 1 ] ;
// Face edges and triangle edges
int ct = 4 ;
for ( i = 0 ; i < 3 ; i ++ )
for ( j = 0 ; j < 3 ; j ++ )
{
crossProduct( axes[j], trigedge[i], axes[ct] ) ;
ct ++ ;
}
/// Generate projections
LONG cubeedge[3][3] ;
for ( i = 0 ; i < 3 ; i ++ )
// Face edges and triangle edges
int ct = 4;
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++)
{
for ( j = 0 ; j < 3 ; j ++ )
{
cubeedge[i][j] = 0 ;
}
cubeedge[i][i] = cube[1][i] - cube[0][i] ;
crossProduct(axes[j], trigedge[i], axes[ct]);
ct++;
}
for ( j = 0 ; j < 13 ; j ++ )
/// Generate projections
LONG cubeedge[3][3];
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
// Origin
cubeProj[j][0] = dotProduct( axes[j], cube[0] ) ;
cubeedge[i][j] = 0;
}
cubeedge[i][i] = cube[1][i] - cube[0][i];
}
// 3 direction vectors
for ( i = 1 ; i < 4 ; i ++ )
{
cubeProj[j][i] = dotProduct( axes[j], cubeedge[i-1] ) ;
}
// Offsets of 2 ends of cube projection
LONG max = 0 ;
LONG min = 0 ;
for ( i = 1 ; i < 8 ; i ++ )
{
LONG proj = vertmap[i][0] * cubeProj[j][1] + vertmap[i][1] * cubeProj[j][2] + vertmap[i][2] * cubeProj[j][3] ;
if ( proj > max )
{
max = proj ;
}
if ( proj < min )
{
min = proj ;
}
}
cubeProj[j][4] = min ;
cubeProj[j][5] = max ;
for (j = 0; j < 13; j++)
{
// Origin
cubeProj[j][0] = dotProduct(axes[j], cube[0]);
// 3 direction vectors
for (i = 1; i < 4; i++)
{
cubeProj[j][i] = dotProduct(axes[j], cubeedge[i - 1]);
}
for ( j = 0 ; j < 13 ; j ++ )
// Offsets of 2 ends of cube projection
LONG max = 0;
LONG min = 0;
for (i = 1; i < 8; i++)
{
LONG vts[3] = { dotProduct( axes[j], trig[0] ),
dotProduct( axes[j], trig[1] ),
dotProduct( axes[j], trig[2] ) } ;
// Vertex
inherit->trigVertProj[j][0] = vts[0] ;
inherit->trigVertProj[j][1] = vts[1] ;
inherit->trigVertProj[j][2] = vts[2] ;
// Edge
for ( i = 0 ; i < 3 ; i ++ )
LONG proj = vertmap[i][0] * cubeProj[j][1] + vertmap[i][1] * cubeProj[j][2] + vertmap[i][2] * cubeProj[j][3];
if (proj > max)
{
if ( vts[i] < vts[(i+1) % 3] )
{
inherit->trigEdgeProj[j][i][0] = vts[i] ;
inherit->trigEdgeProj[j][i][1] = vts[(i+1) % 3] ;
}
else
{
inherit->trigEdgeProj[j][i][1] = vts[i] ;
inherit->trigEdgeProj[j][i][0] = vts[(i+1) % 3] ;
}
max = proj;
}
// Triangle
inherit->trigProj[j][0] = vts[0] ;
inherit->trigProj[j][1] = vts[0] ;
for ( i = 1 ; i < 3 ; i ++ )
if (proj < min)
{
if ( vts[i] < inherit->trigProj[j][0] )
{
inherit->trigProj[j][0] = vts[i] ;
}
if ( vts[i] > inherit->trigProj[j][1] )
{
inherit->trigProj[j][1] = vts[i] ;
}
min = proj;
}
}
cubeProj[j][4] = min;
cubeProj[j][5] = max;
}
/**
* Construction
* from a parent Projections object and the index of the children
*/
Projections ( Projections* parent )
for (j = 0; j < 13; j++)
{
// Copy inheritable projections
this->inherit = parent->inherit ;
LONG vts[3] = { dotProduct(axes[j], trig[0]),
dotProduct(axes[j], trig[1]),
dotProduct(axes[j], trig[2]) };
// Shrink cube projections
for ( int i = 0 ; i < 13 ; i ++ )
// Vertex
inherit->trigVertProj[j][0] = vts[0];
inherit->trigVertProj[j][1] = vts[1];
inherit->trigVertProj[j][2] = vts[2];
// Edge
for (i = 0; i < 3; i++)
{
cubeProj[i][0] = parent->cubeProj[i][0] ;
for ( int j = 1 ; j < 6 ; j ++ )
if (vts[i] < vts[(i + 1) % 3])
{
cubeProj[i][j] = parent->cubeProj[i][j] >> 1 ;
inherit->trigEdgeProj[j][i][0] = vts[i];
inherit->trigEdgeProj[j][i][1] = vts[(i + 1) % 3];
}
else {
inherit->trigEdgeProj[j][i][1] = vts[i];
inherit->trigEdgeProj[j][i][0] = vts[(i + 1) % 3];
}
}
};
Projections ( Projections* parent, int box[3], int depth )
{
int mask = ( 1 << depth ) - 1 ;
int nbox[3] = { box[0] & mask, box[1] & mask, box[2] & mask } ;
// Copy inheritable projections
this->inherit = parent->inherit ;
// Shrink cube projections
for ( int i = 0 ; i < 13 ; i ++ )
// Triangle
inherit->trigProj[j][0] = vts[0];
inherit->trigProj[j][1] = vts[0];
for (i = 1; i < 3; i++)
{
for ( int j = 1 ; j < 6 ; j ++ )
if (vts[i] < inherit->trigProj[j][0])
{
cubeProj[i][j] = parent->cubeProj[i][j] >> depth ;
inherit->trigProj[j][0] = vts[i];
}
cubeProj[i][0] = parent->cubeProj[i][0] + nbox[0] * cubeProj[i][1] + nbox[1] * cubeProj[i][2] + nbox[2] * cubeProj[i][3] ;
}
};
/**
* Testing intersection based on vertex/edge masks
*/
int getIntersectionMasks( UCHAR cedgemask, UCHAR& edgemask )
{
int i, j ;
edgemask = cedgemask ;
// Pre-processing
/*
if ( cvertmask & 1 )
{
edgemask |= 5 ;
}
if ( cvertmask & 2 )
{
edgemask |= 3 ;
}
if ( cvertmask & 4 )
{
edgemask |= 6 ;
}
*/
// Test axes for edge intersection
UCHAR bit = 1 ;
for ( j = 0 ; j < 3 ; j ++ )
{
if ( edgemask & bit )
if (vts[i] > inherit->trigProj[j][1])
{
for ( i = 0 ; i < 13 ; i ++ )
{
LONG proj0 = cubeProj[i][0] + cubeProj[i][4] ;
LONG proj1 = cubeProj[i][0] + cubeProj[i][5] ;
if ( proj0 > inherit->trigEdgeProj[i][j][1] ||
proj1 < inherit->trigEdgeProj[i][j][0] )
{
edgemask &= ( ~ bit ) ;
break ;
}
}
inherit->trigProj[j][1] = vts[i];
}
bit <<= 1 ;
}
/*
if ( edgemask != 0 )
{
printf("%d %d\n", cedgemask, edgemask) ;
}
*/
// Test axes for triangle intersection
if ( edgemask )
{
return 1 ;
}
for ( i = 3 ; i < 13 ; i ++ )
{
LONG proj0 = cubeProj[i][0] + cubeProj[i][4] ;
LONG proj1 = cubeProj[i][0] + cubeProj[i][5] ;
if ( proj0 > inherit->trigProj[i][1] ||
proj1 < inherit->trigProj[i][0] )
{
return 0 ;
}
}
return 1 ;
}
/**
* Retrieving children masks using PRIMARY AXES
*/
UCHAR getChildrenMasks( UCHAR cvertmask, UCHAR vertmask[8] )
{
int i, j, k ;
int bmask[3][2] = {{0,0},{0,0},{0,0}} ;
int vmask[3][3][2] = {{{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0}}} ;
UCHAR boxmask = 0 ;
LONG len = cubeProj[0][1] >> 1 ;
for ( i = 0 ; i < 3 ; i ++ )
{
LONG mid = cubeProj[i][0] + len ;
// Check bounding box
if ( mid >= inherit->trigProj[i][0] )
{
bmask[i][0] = 1 ;
}
if ( mid <= inherit->trigProj[i][1] )
{
bmask[i][1] = 1 ;
}
// Check vertex mask
if ( cvertmask )
{
for ( j = 0 ; j < 3 ; j ++ )
{
if ( cvertmask & ( 1 << j ) )
{
// Only check if it's contained this node
if ( mid >= inherit->trigVertProj[i][j] )
{
vmask[i][j][0] = 1 ;
}
if ( mid <= inherit->trigVertProj[i][j] )
{
vmask[i][j][1] = 1 ;
}
}
}
}
/*
// Check edge mask
if ( cedgemask )
{
for ( j = 0 ; j < 3 ; j ++ )
{
if ( cedgemask & ( 1 << j ) )
{
// Only check if it's contained this node
if ( mid >= inherit->trigEdgeProj[i][j][0] )
{
emask[i][j][0] = 1 ;
}
if ( mid <= inherit->trigEdgeProj[i][j][1] )
{
emask[i][j][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 ) ;
vertmask[ct] = (( vmask[0][0][i] & vmask[1][0][j] & vmask[2][0][k] ) |
(( vmask[0][1][i] & vmask[1][1][j] & vmask[2][1][k] ) << 1 ) |
(( vmask[0][2][i] & vmask[1][2][j] & vmask[2][2][k] ) << 2 ) ) ;
/*
edgemask[ct] = (( emask[0][0][i] & emask[1][0][j] & emask[2][0][k] ) |
(( emask[0][1][i] & emask[1][1][j] & emask[2][1][k] ) << 1 ) |
(( emask[0][2][i] & emask[1][2][j] & emask[2][2][k] ) << 2 ) ) ;
edgemask[ct] = cedgemask ;
*/
ct ++ ;
}
// Return bounding box masks
return boxmask ;
}
UCHAR getBoxMask( )
{
int i, j, k ;
int bmask[3][2] = {{0,0},{0,0},{0,0}} ;
UCHAR boxmask = 0 ;
LONG len = cubeProj[0][1] >> 1 ;
for ( i = 0 ; i < 3 ; i ++ )
{
LONG mid = cubeProj[i][0] + len ;
// Check bounding box
if ( mid >= inherit->trigProj[i][0] )
{
bmask[i][0] = 1 ;
}
if ( mid <= inherit->trigProj[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 ++ ;
}
// Return bounding box masks
return boxmask ;
}
/**
* Get projections for sub-cubes (simple axes)
*/
void getSubProjectionsSimple( Projections* p[8] )
{
// Process the axes cooresponding to the triangle's normal
int ind = 3 ;
LONG len = cubeProj[ 0 ][ 1 ] >> 1 ;
LONG trigproj[3] = { cubeProj[ ind ][ 1 ] >> 1, cubeProj[ ind ][ 2 ] >> 1, cubeProj[ ind ][ 3 ] >> 1 } ;
int ct = 0 ;
for ( int i = 0 ; i < 2 ; i ++ )
for ( int j = 0 ; j < 2 ; j ++ )
for ( int k = 0 ; k < 2 ; k ++ )
{
p[ct] = new Projections( ) ;
p[ct]->inherit = inherit ;
p[ct]->cubeProj[ 0 ][ 0 ] = cubeProj[ 0 ][ 0 ] + i * len ;
p[ct]->cubeProj[ 1 ][ 0 ] = cubeProj[ 1 ][ 0 ] + j * len ;
p[ct]->cubeProj[ 2 ][ 0 ] = cubeProj[ 2 ][ 0 ] + k * len ;
p[ct]->cubeProj[ 0 ][ 1 ] = len ;
for ( int m = 1 ; m < 4 ; m ++ )
{
p[ct]->cubeProj[ ind ][ m ] = trigproj[ m - 1 ] ;
}
p[ct]->cubeProj[ ind ][ 0 ] = cubeProj[ ind ][0] + i * trigproj[0] + j * trigproj[1] + k * trigproj[2] ;
ct ++ ;
}
}
/**
* Shifting a cube to a new origin
*/
void shift ( int off[3] )
{
for ( int i = 0 ; i < 13 ; i ++ )
{
cubeProj[i][0] += off[0] * cubeProj[i][1] + off[1] * cubeProj[i][2] + off[2] * cubeProj[i][3] ;
}
}
void shiftNoPrimary ( int off[3] )
}
/**
* Construction
* from a parent Projections object and the index of the children
*/
Projections (Projections *parent)
{
// Copy inheritable projections
this->inherit = parent->inherit;
// Shrink cube projections
for (int i = 0; i < 13; i++)
{
for ( int i = 3 ; i < 13 ; i ++ )
cubeProj[i][0] = parent->cubeProj[i][0];
for (int j = 1; j < 6; j++)
{
cubeProj[i][0] += off[0] * cubeProj[i][1] + off[1] * cubeProj[i][2] + off[2] * cubeProj[i][3] ;
cubeProj[i][j] = parent->cubeProj[i][j] >> 1;
}
}
};
Projections (Projections *parent, int box[3], int depth)
{
int mask = (1 << depth) - 1;
int nbox[3] = { box[0] & mask, box[1] & mask, box[2] & mask };
// Copy inheritable projections
this->inherit = parent->inherit;
// Shrink cube projections
for (int i = 0; i < 13; i++)
{
for (int j = 1; j < 6; j++)
{
cubeProj[i][j] = parent->cubeProj[i][j] >> depth;
}
cubeProj[i][0] = parent->cubeProj[i][0] + nbox[0] * cubeProj[i][1] + nbox[1] * cubeProj[i][2] + nbox[2] * cubeProj[i][3];
}
};
/**
* Testing intersection based on vertex/edge masks
*/
int getIntersectionMasks(UCHAR cedgemask, UCHAR& edgemask)
{
int i, j;
edgemask = cedgemask;
// Pre-processing
/*
if ( cvertmask & 1 )
{
edgemask |= 5 ;
}
if ( cvertmask & 2 )
{
edgemask |= 3 ;
}
if ( cvertmask & 4 )
{
edgemask |= 6 ;
}
*/
// Test axes for edge intersection
UCHAR bit = 1;
for (j = 0; j < 3; j++)
{
if (edgemask & bit)
{
for (i = 0; i < 13; i++)
{
LONG proj0 = cubeProj[i][0] + cubeProj[i][4];
LONG proj1 = cubeProj[i][0] + cubeProj[i][5];
if (proj0 > inherit->trigEdgeProj[i][j][1] ||
proj1 < inherit->trigEdgeProj[i][j][0])
{
edgemask &= (~bit);
break;
}
}
}
bit <<= 1;
}
/*
if ( edgemask != 0 )
{
printf("%d %d\n", cedgemask, edgemask) ;
}
*/
// Test axes for triangle intersection
if (edgemask)
{
return 1;
}
for (i = 3; i < 13; i++)
{
LONG proj0 = cubeProj[i][0] + cubeProj[i][4];
LONG proj1 = cubeProj[i][0] + cubeProj[i][5];
if (proj0 > inherit->trigProj[i][1] ||
proj1 < inherit->trigProj[i][0])
{
return 0;
}
}
/**
* Method to test intersection of the triangle and the cube
*/
int isIntersecting ( )
return 1;
}
/**
* Retrieving children masks using PRIMARY AXES
*/
UCHAR getChildrenMasks(UCHAR cvertmask, UCHAR vertmask[8])
{
int i, j, k;
int bmask[3][2] = {{0, 0}, {0, 0}, {0, 0}};
int vmask[3][3][2] = {{{0, 0}, {0, 0}, {0, 0}}, {{0, 0}, {0, 0}, {0, 0}}, {{0, 0}, {0, 0}, {0, 0}}};
UCHAR boxmask = 0;
LONG len = cubeProj[0][1] >> 1;
for (i = 0; i < 3; i++)
{
for ( int i = 0 ; i < 13 ; i ++ )
LONG mid = cubeProj[i][0] + len;
// Check bounding box
if (mid >= inherit->trigProj[i][0])
{
/*
LONG 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] ;
LONG 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] ;
*/
LONG proj0 = cubeProj[i][0] + cubeProj[i][4] ;
LONG proj1 = cubeProj[i][0] + cubeProj[i][5] ;
if ( proj0 > inherit->trigProj[i][1] ||
proj1 < inherit->trigProj[i][0] )
{
return 0 ;
}
bmask[i][0] = 1;
}
return 1 ;
};
int isIntersectingNoPrimary ( )
{
for ( int i = 3 ; i < 13 ; i ++ )
if (mid <= inherit->trigProj[i][1])
{
/*
LONG 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] ;
LONG 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] ;
*/
LONG proj0 = cubeProj[i][0] + cubeProj[i][4] ;
LONG proj1 = cubeProj[i][0] + cubeProj[i][5] ;
if ( proj0 > inherit->trigProj[i][1] ||
proj1 < inherit->trigProj[i][0] )
{
return 0 ;
}
bmask[i][1] = 1;
}
return 1 ;
};
/**
* Method to test intersection of the triangle and one edge
*/
int isIntersecting ( int edgeInd )
{
for ( int i = 0 ; i < 13 ; i ++ )
// Check vertex mask
if (cvertmask)
{
LONG proj0 = cubeProj[i][0] +
vertmap[edgemap[edgeInd][0]][0] * cubeProj[i][1] +
vertmap[edgemap[edgeInd][0]][1] * cubeProj[i][2] +
vertmap[edgemap[edgeInd][0]][2] * cubeProj[i][3] ;
LONG proj1 = cubeProj[i][0] +
vertmap[edgemap[edgeInd][1]][0] * cubeProj[i][1] +
vertmap[edgemap[edgeInd][1]][1] * cubeProj[i][2] +
vertmap[edgemap[edgeInd][1]][2] * cubeProj[i][3] ;
if ( proj0 < proj1 )
for (j = 0; j < 3; j++)
{
if ( proj0 > inherit->trigProj[i][1] ||
proj1 < inherit->trigProj[i][0] )
if (cvertmask & (1 << j) )
{
return 0 ;
}
}
else
{
if ( proj1 > inherit->trigProj[i][1] ||
proj0 < inherit->trigProj[i][0] )
{
return 0 ;
}
}
}
// printf( "Intersecting: %d %d\n", edgemap[edgeInd][0], edgemap[edgeInd][1] ) ;
return 1 ;
};
/**
* Method to test intersection of one triangle edge and one cube face
*/
int isIntersecting ( int edgeInd, int faceInd )
{
for ( int i = 0 ; i < 13 ; i ++ )
{
LONG trigproj0 = inherit->trigVertProj[i][edgeInd] ;
LONG trigproj1 = inherit->trigVertProj[i][(edgeInd+1)%3] ;
if ( trigproj0 < trigproj1 )
{
int t1 = 1 , t2 = 1 ;
for ( int j = 0 ; j < 4 ; j ++ )
{
LONG proj = cubeProj[i][0] +
vertmap[facemap[faceInd][j]][0] * cubeProj[i][1] +
vertmap[facemap[faceInd][j]][1] * cubeProj[i][2] +
vertmap[facemap[faceInd][j]][2] * cubeProj[i][3] ;
if ( proj >= trigproj0 )
// Only check if it's contained this node
if (mid >= inherit->trigVertProj[i][j])
{
t1 = 0 ;
vmask[i][j][0] = 1;
}
if ( proj <= trigproj1 )
if (mid <= inherit->trigVertProj[i][j])
{
t2 = 0 ;
vmask[i][j][1] = 1;
}
}
if ( t1 || t2 )
{
return 0 ;
}
}
else
{
int t1 = 1 , t2 = 1 ;
for ( int j = 0 ; j < 4 ; j ++ )
{
LONG proj = cubeProj[i][0] +
vertmap[facemap[faceInd][j]][0] * cubeProj[i][1] +
vertmap[facemap[faceInd][j]][1] * cubeProj[i][2] +
vertmap[facemap[faceInd][j]][2] * cubeProj[i][3] ;
if ( proj >= trigproj1 )
{
t1 = 0 ;
}
if ( proj <= trigproj0 )
{
t2 = 0 ;
}
}
if ( t1 || t2 )
{
return 0 ;
}
}
}
return 1 ;
};
int isIntersectingPrimary ( int edgeInd )
{
for ( int i = 0 ; i < 13 ; i ++ )
{
LONG proj0 = cubeProj[i][0] ;
LONG proj1 = cubeProj[i][0] + cubeProj[i][edgeInd + 1] ;
if ( proj0 < proj1 )
{
if ( proj0 > inherit->trigProj[i][1] ||
proj1 < inherit->trigProj[i][0] )
{
return 0 ;
}
}
else
{
if ( proj1 > inherit->trigProj[i][1] ||
proj0 < inherit->trigProj[i][0] )
{
return 0 ;
}
}
}
// printf( "Intersecting: %d %d\n", edgemap[edgeInd][0], edgemap[edgeInd][1] ) ;
return 1 ;
};
double getIntersection ( int edgeInd )
{
int i = 3 ;
LONG proj0 = cubeProj[i][0] +
vertmap[edgemap[edgeInd][0]][0] * cubeProj[i][1] +
vertmap[edgemap[edgeInd][0]][1] * cubeProj[i][2] +
vertmap[edgemap[edgeInd][0]][2] * cubeProj[i][3] ;
LONG proj1 = cubeProj[i][0] +
vertmap[edgemap[edgeInd][1]][0] * cubeProj[i][1] +
vertmap[edgemap[edgeInd][1]][1] * cubeProj[i][2] +
vertmap[edgemap[edgeInd][1]][2] * cubeProj[i][3] ;
LONG proj2 = inherit->trigProj[i][1] ;
/*
if ( proj0 < proj1 )
{
if ( proj2 < proj0 || proj2 > proj1 )
{
return -1 ;
}
}
else
{
if ( proj2 < proj1 || proj2 > proj0 )
{
return -1 ;
}
}
*/
// Check edge mask
if ( cedgemask )
{
for ( j = 0 ; j < 3 ; j ++ )
{
if ( cedgemask & ( 1 << j ) )
{
// Only check if it's contained this node
if ( mid >= inherit->trigEdgeProj[i][j][0] )
{
emask[i][j][0] = 1 ;
}
if ( mid <= inherit->trigEdgeProj[i][j][1] )
{
emask[i][j][1] = 1 ;
}
}
}
}
*/
double alpha = (double)( proj2 - proj0 ) / (double)( proj1 - proj0 ) ;
}
// 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);
vertmask[ct] = ((vmask[0][0][i] & vmask[1][0][j] & vmask[2][0][k]) |
((vmask[0][1][i] & vmask[1][1][j] & vmask[2][1][k]) << 1) |
((vmask[0][2][i] & vmask[1][2][j] & vmask[2][2][k]) << 2) );
/*
edgemask[ct] = (( emask[0][0][i] & emask[1][0][j] & emask[2][0][k] ) |
(( emask[0][1][i] & emask[1][1][j] & emask[2][1][k] ) << 1 ) |
(( emask[0][2][i] & emask[1][2][j] & emask[2][2][k] ) << 2 ) ) ;
edgemask[ct] = cedgemask ;
*/
ct++;
}
// Return bounding box masks
return boxmask;
}
UCHAR getBoxMask( )
{
int i, j, k;
int bmask[3][2] = {{0, 0}, {0, 0}, {0, 0}};
UCHAR boxmask = 0;
LONG len = cubeProj[0][1] >> 1;
for (i = 0; i < 3; i++)
{
LONG mid = cubeProj[i][0] + len;
// Check bounding box
if (mid >= inherit->trigProj[i][0])
{
bmask[i][0] = 1;
}
if (mid <= inherit->trigProj[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++;
}
// Return bounding box masks
return boxmask;
}
/**
* Get projections for sub-cubes (simple axes)
*/
void getSubProjectionsSimple(Projections *p[8])
{
// Process the axes cooresponding to the triangle's normal
int ind = 3;
LONG len = cubeProj[0][1] >> 1;
LONG trigproj[3] = { cubeProj[ind][1] >> 1, cubeProj[ind][2] >> 1, cubeProj[ind][3] >> 1 };
int ct = 0;
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
for (int k = 0; k < 2; k++)
{
p[ct] = new Projections( );
p[ct]->inherit = inherit;
p[ct]->cubeProj[0][0] = cubeProj[0][0] + i * len;
p[ct]->cubeProj[1][0] = cubeProj[1][0] + j * len;
p[ct]->cubeProj[2][0] = cubeProj[2][0] + k * len;
p[ct]->cubeProj[0][1] = len;
for (int m = 1; m < 4; m++)
{
p[ct]->cubeProj[ind][m] = trigproj[m - 1];
}
p[ct]->cubeProj[ind][0] = cubeProj[ind][0] + i * trigproj[0] + j * trigproj[1] + k * trigproj[2];
ct++;
}
}
/**
* Shifting a cube to a new origin
*/
void shift(int off[3])
{
for (int i = 0; i < 13; i++)
{
cubeProj[i][0] += off[0] * cubeProj[i][1] + off[1] * cubeProj[i][2] + off[2] * cubeProj[i][3];
}
}
void shiftNoPrimary(int off[3])
{
for (int i = 3; i < 13; i++)
{
cubeProj[i][0] += off[0] * cubeProj[i][1] + off[1] * cubeProj[i][2] + off[2] * cubeProj[i][3];
}
}
/**
* Method to test intersection of the triangle and the cube
*/
int isIntersecting( )
{
for (int i = 0; i < 13; i++)
{
/*
if ( alpha < 0 )
{
alpha = 0.5 ;
}
else if ( alpha > 1 )
{
alpha = 0.5 ;
}
*/
LONG 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] ;
LONG 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] ;
*/
return alpha ;
};
LONG proj0 = cubeProj[i][0] + cubeProj[i][4];
LONG proj1 = cubeProj[i][0] + cubeProj[i][5];
float getIntersectionPrimary ( int edgeInd )
if (proj0 > inherit->trigProj[i][1] ||
proj1 < inherit->trigProj[i][0])
{
return 0;
}
}
return 1;
};
int isIntersectingNoPrimary( )
{
for (int i = 3; i < 13; i++)
{
int i = 3 ;
/*
LONG 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] ;
LONG 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] ;
*/
LONG proj0 = cubeProj[i][0] ;
LONG proj1 = cubeProj[i][0] + cubeProj[i][edgeInd + 1] ;
LONG proj2 = inherit->trigProj[i][1] ;
LONG proj0 = cubeProj[i][0] + cubeProj[i][4];
LONG proj1 = cubeProj[i][0] + cubeProj[i][5];
// double alpha = (double)( ( proj2 - proj0 ) * cubeProj[edgeInd][edgeInd + 1] ) / (double)( proj1 - proj0 ) ;
double alpha = (double)( ( proj2 - proj0 ) ) / (double)( proj1 - proj0 ) ;
if ( alpha < 0 )
if (proj0 > inherit->trigProj[i][1] ||
proj1 < inherit->trigProj[i][0])
{
alpha = 0.5 ;
return 0;
}
else if ( alpha > 1 )
}
return 1;
};
/**
* Method to test intersection of the triangle and one edge
*/
int isIntersecting(int edgeInd)
{
for (int i = 0; i < 13; i++)
{
LONG proj0 = cubeProj[i][0] +
vertmap[edgemap[edgeInd][0]][0] * cubeProj[i][1] +
vertmap[edgemap[edgeInd][0]][1] * cubeProj[i][2] +
vertmap[edgemap[edgeInd][0]][2] * cubeProj[i][3];
LONG proj1 = cubeProj[i][0] +
vertmap[edgemap[edgeInd][1]][0] * cubeProj[i][1] +
vertmap[edgemap[edgeInd][1]][1] * cubeProj[i][2] +
vertmap[edgemap[edgeInd][1]][2] * cubeProj[i][3];
if (proj0 < proj1)
{
alpha = 0.5 ;
if (proj0 > inherit->trigProj[i][1] ||
proj1 < inherit->trigProj[i][0])
{
return 0;
}
}
else {
if (proj1 > inherit->trigProj[i][1] ||
proj0 < inherit->trigProj[i][0])
{
return 0;
}
}
}
return (float)alpha ;
};
// printf( "Intersecting: %d %d\n", edgemap[edgeInd][0], edgemap[edgeInd][1] ) ;
return 1;
};
/**
* Method to perform cross-product
/**
* Method to test intersection of one triangle edge and one cube face
*/
int isIntersecting(int edgeInd, int faceInd)
{
for (int i = 0; i < 13; i++)
{
LONG trigproj0 = inherit->trigVertProj[i][edgeInd];
LONG trigproj1 = inherit->trigVertProj[i][(edgeInd + 1) % 3];
if (trigproj0 < trigproj1)
{
int t1 = 1, t2 = 1;
for (int j = 0; j < 4; j++)
{
LONG proj = cubeProj[i][0] +
vertmap[facemap[faceInd][j]][0] * cubeProj[i][1] +
vertmap[facemap[faceInd][j]][1] * cubeProj[i][2] +
vertmap[facemap[faceInd][j]][2] * cubeProj[i][3];
if (proj >= trigproj0)
{
t1 = 0;
}
if (proj <= trigproj1)
{
t2 = 0;
}
}
if (t1 || t2)
{
return 0;
}
}
else {
int t1 = 1, t2 = 1;
for (int j = 0; j < 4; j++)
{
LONG proj = cubeProj[i][0] +
vertmap[facemap[faceInd][j]][0] * cubeProj[i][1] +
vertmap[facemap[faceInd][j]][1] * cubeProj[i][2] +
vertmap[facemap[faceInd][j]][2] * cubeProj[i][3];
if (proj >= trigproj1)
{
t1 = 0;
}
if (proj <= trigproj0)
{
t2 = 0;
}
}
if (t1 || t2)
{
return 0;
}
}
}
return 1;
};
int isIntersectingPrimary(int edgeInd)
{
for (int i = 0; i < 13; i++)
{
LONG proj0 = cubeProj[i][0];
LONG proj1 = cubeProj[i][0] + cubeProj[i][edgeInd + 1];
if (proj0 < proj1)
{
if (proj0 > inherit->trigProj[i][1] ||
proj1 < inherit->trigProj[i][0])
{
return 0;
}
}
else {
if (proj1 > inherit->trigProj[i][1] ||
proj0 < inherit->trigProj[i][0])
{
return 0;
}
}
}
// printf( "Intersecting: %d %d\n", edgemap[edgeInd][0], edgemap[edgeInd][1] ) ;
return 1;
};
double getIntersection(int edgeInd)
{
int i = 3;
LONG proj0 = cubeProj[i][0] +
vertmap[edgemap[edgeInd][0]][0] * cubeProj[i][1] +
vertmap[edgemap[edgeInd][0]][1] * cubeProj[i][2] +
vertmap[edgemap[edgeInd][0]][2] * cubeProj[i][3];
LONG proj1 = cubeProj[i][0] +
vertmap[edgemap[edgeInd][1]][0] * cubeProj[i][1] +
vertmap[edgemap[edgeInd][1]][1] * cubeProj[i][2] +
vertmap[edgemap[edgeInd][1]][2] * cubeProj[i][3];
LONG proj2 = inherit->trigProj[i][1];
/*
if ( proj0 < proj1 )
{
if ( proj2 < proj0 || proj2 > proj1 )
{
return -1 ;
}
}
else
{
if ( proj2 < proj1 || proj2 > proj0 )
{
return -1 ;
}
}
*/
void crossProduct ( LONG a[3], LONG b[3], LONG res[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] ;
}
void crossProduct ( double a[3], double b[3], double res[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] ;
}
/**
* Method to perform dot product
double alpha = (double)(proj2 - proj0) / (double)(proj1 - proj0);
/*
if ( alpha < 0 )
{
alpha = 0.5 ;
}
else if ( alpha > 1 )
{
alpha = 0.5 ;
}
*/
LONG dotProduct ( LONG a[3], LONG b[3] )
return alpha;
};
float getIntersectionPrimary(int edgeInd)
{
int i = 3;
LONG proj0 = cubeProj[i][0];
LONG proj1 = cubeProj[i][0] + cubeProj[i][edgeInd + 1];
LONG proj2 = inherit->trigProj[i][1];
// double alpha = (double)( ( proj2 - proj0 ) * cubeProj[edgeInd][edgeInd + 1] ) / (double)( proj1 - proj0 ) ;
double alpha = (double)( (proj2 - proj0) ) / (double)(proj1 - proj0);
if (alpha < 0)
{
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] ;
alpha = 0.5;
}
else if (alpha > 1)
{
alpha = 0.5;
}
void normalize( double a[3] )
return (float)alpha;
};
/**
* Method to perform cross-product
*/
void crossProduct(LONG a[3], LONG b[3], LONG res[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];
}
void crossProduct(double a[3], double b[3], double res[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];
}
/**
* Method to perform dot product
*/
LONG dotProduct(LONG a[3], LONG b[3])
{
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
void normalize(double a[3])
{
double mag = a[0] * a[0] + a[1] * a[1] + a[2] * a[2];
if (mag > 0)
{
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 ;
}
mag = sqrt(mag);
a[0] /= mag;
a[1] /= mag;
a[2] /= mag;
}
}
};

View File

@@ -23,83 +23,81 @@
#ifndef QUEUE_H
#define QUEUE_H
struct gridQueueEle
{
struct gridQueueEle {
int x, y, z;
UCHAR dir ;
gridQueueEle* next ;
UCHAR dir;
gridQueueEle *next;
};
class GridQueue
{
gridQueueEle* head ;
gridQueueEle* tail ;
int numEles ;
gridQueueEle *head;
gridQueueEle *tail;
int numEles;
public:
GridQueue( )
GridQueue( )
{
head = NULL;
tail = NULL;
numEles = 0;
}
gridQueueEle *getHead( )
{
return head;
}
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 = NULL ;
tail = NULL ;
numEles = 0 ;
head = ele;
}
else {
tail->next = ele;
}
tail = ele;
numEles++;
}
int popQueue(int st[3], int& dir)
{
if (head == NULL)
{
return 0;
}
gridQueueEle* getHead( )
st[0] = head->x;
st[1] = head->y;
st[2] = head->z;
dir = (int) (head->dir);
gridQueueEle *temp = head;
head = head->next;
delete temp;
if (head == NULL)
{
return head ;
tail = NULL;
}
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 ;
}
st[0] = head->x ;
st[1] = head->y ;
st[2] = head->z ;
dir = (int) (head->dir) ;
gridQueueEle* temp = head ;
head = head->next ;
delete temp ;
if ( head == NULL )
{
tail = NULL ;
}
numEles -- ;
return 1 ;
}
return 1;
}
};

View File

@@ -29,18 +29,18 @@
class Cubes
{
public:
/// Get number of triangles
int getNumTriangle(int mask)
{
return marching_cubes_numtri[mask];
}
/// 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];
}
};
#endif

View File

@@ -40,166 +40,169 @@ void veccopy(float dst[3], const float src[3])
}
#define GET_FACE(_mesh, _n) \
(*(DualConFaces)(((char*)(_mesh)->faces) + ((_n) * (_mesh)->face_stride)))
(*(DualConFaces)(((char *)(_mesh)->faces) + ((_n) * (_mesh)->face_stride)))
#define GET_CO(_mesh, _n) \
(*(DualConCo)(((char*)(_mesh)->co) + ((_n) * (_mesh)->co_stride)))
(*(DualConCo)(((char *)(_mesh)->co) + ((_n) * (_mesh)->co_stride)))
class DualConInputReader : public ModelReader
{
private:
const DualConInput *input_mesh;
int tottri, curface, offset;
float min[3], max[3], maxsize;
float scale;
const DualConInput *input_mesh;
int tottri, curface, offset;
float min[3], max[3], maxsize;
float scale;
public:
DualConInputReader(const DualConInput *mesh, float _scale)
DualConInputReader(const DualConInput *mesh, float _scale)
: input_mesh(mesh), scale(_scale)
{
reset();
{
reset();
}
void reset()
{
tottri = 0;
curface = 0;
offset = 0;
maxsize = 0;
/* initialize tottri */
for (int i = 0; i < input_mesh->totface; i++)
tottri += GET_FACE(input_mesh, i)[3] ? 2 : 1;
veccopy(min, input_mesh->min);
veccopy(max, input_mesh->max);
/* initialize maxsize */
for (int i = 0; i < 3; i++) {
float d = max[i] - min[i];
if (d > maxsize)
maxsize = d;
}
void reset()
/* redo the bounds */
for (int i = 0; i < 3; i++)
{
tottri = 0;
curface = 0;
min[i] = (max[i] + min[i]) / 2 - maxsize / 2;
max[i] = (max[i] + min[i]) / 2 + maxsize / 2;
}
for (int i = 0; i < 3; i++)
min[i] -= maxsize * (1 / scale - 1) / 2;
maxsize *= 1 / scale;
}
Triangle *getNextTriangle()
{
if (curface == input_mesh->totface)
return 0;
Triangle *t = new Triangle();
unsigned int *f = GET_FACE(input_mesh, curface);
if (offset == 0) {
veccopy(t->vt[0], GET_CO(input_mesh, f[0]));
veccopy(t->vt[1], GET_CO(input_mesh, f[1]));
veccopy(t->vt[2], GET_CO(input_mesh, f[2]));
}
else {
veccopy(t->vt[0], GET_CO(input_mesh, f[2]));
veccopy(t->vt[1], GET_CO(input_mesh, f[3]));
veccopy(t->vt[2], GET_CO(input_mesh, f[0]));
}
if (offset == 0 && f[3])
offset++;
else {
offset = 0;
maxsize = 0;
/* initialize tottri */
for(int i = 0; i < input_mesh->totface; i++)
tottri += GET_FACE(input_mesh, i)[3] ? 2 : 1;
veccopy(min, input_mesh->min);
veccopy(max, input_mesh->max);
/* initialize maxsize */
for(int i = 0; i < 3; i++) {
float d = max[i] - min[i];
if(d > maxsize)
maxsize = d;
}
/* 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;
}
for(int i = 0; i < 3; i++)
min[i] -= maxsize * (1 / scale - 1) / 2;
maxsize *= 1 / scale;
curface++;
}
Triangle* getNextTriangle()
{
if(curface == input_mesh->totface)
return 0;
Triangle* t = new Triangle();
unsigned int *f = GET_FACE(input_mesh, curface);
if(offset == 0) {
veccopy(t->vt[0], GET_CO(input_mesh, f[0]));
veccopy(t->vt[1], GET_CO(input_mesh, f[1]));
veccopy(t->vt[2], GET_CO(input_mesh, f[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();
}
else {
veccopy(t->vt[0], GET_CO(input_mesh, f[2]));
veccopy(t->vt[1], GET_CO(input_mesh, f[3]));
veccopy(t->vt[2], GET_CO(input_mesh, f[0]));
}
if(offset == 0 && f[3])
offset++;
else {
offset = 0;
curface++;
}
/* 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();
}
}
return t;
}
int getNextTriangle(int t[3])
{
if(curface == input_mesh->totface)
return 0;
unsigned int *f = GET_FACE(input_mesh, curface);
if(offset == 0) {
t[0] = f[0];
t[1] = f[1];
t[2] = f[2];
}
else {
t[0] = f[2];
t[1] = f[3];
t[2] = f[0];
}
return t;
}
if(offset == 0 && f[3])
offset++;
else {
offset = 0;
curface++;
}
int getNextTriangle(int t[3])
{
if (curface == input_mesh->totface)
return 0;
return 1;
unsigned int *f = GET_FACE(input_mesh, curface);
if (offset == 0) {
t[0] = f[0];
t[1] = f[1];
t[2] = f[2];
}
else {
t[0] = f[2];
t[1] = f[3];
t[2] = f[0];
}
int getNumTriangles()
{
return tottri;
if (offset == 0 && f[3])
offset++;
else {
offset = 0;
curface++;
}
int getNumVertices()
{
return input_mesh->totco;
}
return 1;
}
float getBoundingBox(float origin[3])
{
veccopy(origin, min);
return maxsize ;
}
int getNumTriangles()
{
return tottri;
}
/* output */
void getNextVertex(float v[3])
{
/* not used */
}
int getNumVertices()
{
return input_mesh->totco;
}
/* stubs */
void printInfo() {}
int getMemory() { return sizeof(DualConInputReader); }
float getBoundingBox(float origin[3])
{
veccopy(origin, min);
return maxsize;
}
/* output */
void getNextVertex(float v[3])
{
/* not used */
}
/* stubs */
void printInfo() {
}
int getMemory() {
return sizeof(DualConInputReader);
}
};
void *dualcon(const DualConInput *input_mesh,
/* callbacks for output */
DualConAllocOutput alloc_output,
DualConAddVert add_vert,
DualConAddQuad add_quad,
DualConFlags flags,
DualConMode mode,
float threshold,
float hermite_num,
float scale,
int depth)
/* callbacks for output */
DualConAllocOutput alloc_output,
DualConAddVert add_vert,
DualConAddQuad add_quad,
DualConFlags flags,
DualConMode mode,
float threshold,
float hermite_num,
float scale,
int depth)
{
DualConInputReader r(input_mesh, scale);
Octree o(&r, alloc_output, add_vert, add_quad,
flags, mode, depth, threshold, hermite_num);
flags, mode, depth, threshold, hermite_num);
o.scanConvert();
return o.getOutputMesh();
}

View File

@@ -39,516 +39,516 @@ const int marching_cubes_numtri[TOTCONF] = {
/* 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}}
{{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

@@ -39,38 +39,38 @@
#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)
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':
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 seperate 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.
/* note on `use_manifold':
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)
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 seperate 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)
{
thresh = threshold;
reader = mr;
@@ -78,8 +78,8 @@ Octree::Octree(ModelReader* mr,
range = reader->getBoundingBox(origin);
nodeCount = nodeSpace = 0;
maxDepth = depth;
mindimen =(dimen >> maxDepth);
minshift =(GRID_DIMENSION - maxDepth);
mindimen = (dimen >> maxDepth);
minshift = (GRID_DIMENSION - maxDepth);
buildTable();
maxTrianglePerCell = 0;
@@ -90,7 +90,7 @@ Octree::Octree(ModelReader* mr,
dc_printf("Initialize memory...\n");
#endif
initMemory();
root = (Node*)createInternal(0);
root = (Node *)createInternal(0);
// Read MC table
#ifdef IN_VERBOSE_MODE
@@ -112,15 +112,15 @@ void Octree::scanConvert()
clock_t start, finish;
start = clock();
#endif
addTrian();
resetMinimalEdges();
preparePrimalEdgesMask(&root->internal);
#if DC_DEBUG
finish = clock();
dc_printf("Time taken: %f seconds \n",
(double)(finish - start) / CLOCKS_PER_SEC);
dc_printf("Time taken: %f seconds \n",
(double)(finish - start) / CLOCKS_PER_SEC);
#endif
// Generate signs
@@ -132,18 +132,18 @@ void Octree::scanConvert()
trace();
#if DC_DEBUG
finish = clock();
dc_printf("Time taken: %f seconds \n", (double)(finish - start) / CLOCKS_PER_SEC);
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);
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 after patching: %d \n", numRings);
#endif
#endif
numRings = tnumRings;
#if DC_DEBUG
@@ -153,22 +153,22 @@ void Octree::scanConvert()
buildSigns();
#if DC_DEBUG
finish = clock();
dc_printf("Time taken: %f seconds \n", (double)(finish - start) / CLOCKS_PER_SEC);
dc_printf("Time taken: %f seconds \n", (double)(finish - start) / CLOCKS_PER_SEC);
#endif
if(use_flood_fill) {
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);
*/
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");
@@ -179,7 +179,7 @@ void Octree::scanConvert()
// floodFill();
#if DC_DEBUG
finish = clock();
dc_printf("Time taken: %f seconds \n",(double)(finish - start) / CLOCKS_PER_SEC);
dc_printf("Time taken: %f seconds \n", (double)(finish - start) / CLOCKS_PER_SEC);
#endif
}
@@ -202,31 +202,29 @@ void Octree::scanConvert()
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[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[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 ++)
{
for (int i = 0; i < 9; i++) {
alloc[i]->destroy();
delete alloc[i];
}
for(int i = 0; i < 4; i ++)
{
for (int i = 0; i < 4; i++) {
leafalloc[i]->destroy();
delete leafalloc[i];
}
@@ -236,22 +234,20 @@ void Octree::printMemUsage()
{
int totalbytes = 0;
dc_printf("********* Internal nodes: \n");
for(int i = 0; i < 9; i ++)
{
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 ++)
{
for (int i = 0; i < 4; i++) {
leafalloc[i]->printInfo();
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);
}
@@ -263,9 +259,9 @@ void Octree::resetMinimalEdges()
void Octree::addTrian()
{
Triangle* trian;
Triangle *trian;
int count = 0;
#if DC_DEBUG
int total = reader->getNumTriangles();
int unitcount = 1000;
@@ -274,196 +270,175 @@ void Octree::addTrian()
srand(0);
while((trian = reader->getNextTriangle()) != NULL)
{
while ((trian = reader->getNextTriangle()) != NULL) {
// Drop triangles
{
addTrian(trian, count);
}
delete trian;
count ++;
count++;
#if DC_DEBUG
if(count % unitcount == 0)
{
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);
}
#endif
}
putchar(13);
}
void Octree::addTrian(Triangle* trian, int triind)
void Octree::addTrian(Triangle *trian, int triind)
{
int i, j;
// Blowing up the triangle to the grid
float mid[3] = {0, 0, 0};
for(i = 0; i < 3; i ++)
for(j = 0; j < 3; j ++)
{
trian->vt[i][j] = dimen *(trian->vt[i][j] - origin[j]) / range;
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++) {
trian->vt[i][j] = dimen * (trian->vt[i][j] - origin[j]) / range;
mid[j] += trian->vt[i][j] / 3;
}
// Generate projections
LONG cube[2][3] = {{0, 0, 0}, {dimen, dimen, dimen}};
LONG trig[3][3];
for(i = 0; i < 3; i ++)
for( j = 0; j < 3; j ++)
{
trig[i][j] =(LONG)(trian->vt[i][j]);
// Perturb end points, if set so
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++) {
trig[i][j] = (LONG)(trian->vt[i][j]);
// Perturb end points, if set so
}
// Add to the octree
// int start[3] = {0, 0, 0};
LONG errorvec =(LONG)(0);
Projections* proj = new Projections(cube, trig, errorvec, triind);
root = (Node*)addTrian(&root->internal, proj, maxDepth);
LONG errorvec = (LONG)(0);
Projections *proj = new Projections(cube, trig, errorvec, triind);
root = (Node *)addTrian(&root->internal, proj, maxDepth);
delete proj->inherit;
delete proj;
}
InternalNode* Octree::addTrian(InternalNode* node, Projections* p, int height)
InternalNode *Octree::addTrian(InternalNode *node, Projections *p, int height)
{
int i;
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}};
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}};
UCHAR boxmask = p->getBoxMask();
Projections* subp = new Projections(p);
Projections *subp = new Projections(p);
int count = 0;
int tempdiff[3] = {0,0,0};
for(i = 0; i < 8; i ++)
{
int tempdiff[3] = {0, 0, 0};
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))
{
if (boxmask & (1 << i)) {
subp->shift(tempdiff);
tempdiff[0] = tempdiff[1] = tempdiff[2] = 0;
/* Pruning using intersection test */
if(subp->isIntersecting())
if (subp->isIntersecting()) {
// if(subp->getIntersectionMasks(cedgemask, edgemask))
{
if(! hasChild(node, i))
{
if(height == 1)
{
if (!hasChild(node, i)) {
if (height == 1) {
node = addLeafChild(node, i, count, createLeaf(0));
}
else
{
else {
node = addInternalChild(node, i, count, createInternal(0));
}
}
Node* chd = getChild(node, count);
if(! isLeaf(node, i))
{
Node *chd = getChild(node, count);
if (!isLeaf(node, i)) {
// setChild(node, count, addTrian(chd, subp, height - 1, vertmask[i], edgemask));
setChild(node, count, (Node*)addTrian(&chd->internal, subp, height - 1));
setChild(node, count, (Node *)addTrian(&chd->internal, subp, height - 1));
}
else
{
setChild(node, count, (Node*)updateCell(&chd->leaf, subp));
else {
setChild(node, count, (Node *)updateCell(&chd->leaf, subp));
}
}
}
if(hasChild(node, i))
{
count ++;
if (hasChild(node, i)) {
count++;
}
}
delete subp;
return node;
}
LeafNode* Octree::updateCell(LeafNode* node, Projections* p)
LeafNode *Octree::updateCell(LeafNode *node, Projections *p)
{
int i;
// Edge connectivity
int mask[3] = {0, 4, 8 };
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))
{
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 ++;
a[newc] = (float) p->inherit->norm[0];
b[newc] = (float) p->inherit->norm[1];
c[newc] = (float) p->inherit->norm[2];
newc++;
}
}
else
{
else {
offs[newc] = getEdgeOffsetNormal(node, oldc, a[newc], b[newc], c[newc]);
// if(p->isIntersectingPrimary(i))
{
// dc_printf("Multiple intersections!\n");
// setPatchEdge(node, i);
}
oldc ++;
newc ++;
oldc++;
newc++;
}
}
if(newc > oldc)
{
if (newc > oldc) {
// New offsets added, update this node
node = updateEdgeOffsetsNormals(node, oldc, newc, offs, a, b, c);
}
@@ -471,45 +446,42 @@ LeafNode* Octree::updateCell(LeafNode* node, Projections* p)
return node;
}
void Octree::preparePrimalEdgesMask(InternalNode* node)
void Octree::preparePrimalEdgesMask(InternalNode *node)
{
int count = 0;
for(int i = 0; i < 8; i ++)
{
if(hasChild(node, i))
{
if(isLeaf(node, i))
for (int i = 0; i < 8; i++) {
if (hasChild(node, i)) {
if (isLeaf(node, i))
createPrimalEdgesMask(&getChild(node, count)->leaf);
else
preparePrimalEdgesMask(&getChild(node, count)->internal);
count ++;
count++;
}
}
}
void Octree::trace()
{
int st[3] = {0, 0, 0,};
int st[3] = {0, 0, 0, };
numRings = 0;
totRingLengths = 0;
maxRingLength = 0;
PathList* chdpath = NULL;
PathList *chdpath = NULL;
root = trace(root, st, dimen, maxDepth, chdpath);
if(chdpath != NULL)
{
dc_printf("there are incomplete rings.\n");
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];
PathList *chdpaths[8];
Node *chd[8];
int nst[8][3];
int i, j;
@@ -518,55 +490,48 @@ Node* Octree::trace(Node* newnode, int* st, int len, int depth, PathList*& paths
fillChildren(&newnode->internal, chd, chdleaf);
// int count = 0;
for(i = 0; i < 8; i ++)
{
for(j = 0; j < 3; j ++)
{
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 || isLeaf(&newnode->internal, i))
{
if (chd[i] == NULL || isLeaf(&newnode->internal, i)) {
chdpaths[i] = NULL;
}
else
{
else {
trace(chd[i], nst[i], len, depth - 1, chdpaths[i]);
}
}
// Get connectors on the faces
PathList* conn[12];
Node* nf[2];
PathList *conn[12];
Node *nf[2];
int lf[2];
int df[2] = {depth - 1, depth - 1};
int* nstf[2];
int *nstf[2];
fillChildren(&newnode->internal, chd, chdleaf);
for(i = 0; i < 12; i ++)
{
for (i = 0; i < 12; i++) {
int c[2] = {cellProcFaceMask[i][0], cellProcFaceMask[i][1]};
for(int j = 0; j < 2; 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;
findPaths((Node**)nf, lf, df, nstf, depth - 1, cellProcFaceMask[i][2], conn[i]);
//if(conn[i])
//{
findPaths((Node **)nf, lf, df, nstf, depth - 1, cellProcFaceMask[i][2], conn[i]);
//if(conn[i]) {
// printPath(conn[i]);
//}
}
// Connect paths
PathList* rings = NULL;
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);
@@ -585,25 +550,22 @@ Node* Octree::trace(Node* newnode, int* st, int len, int depth, PathList*& paths
// By now, only chdpaths[0] and rings have contents
// Process rings
if(rings)
{
if (rings) {
// printPath(rings);
/* Let's count first */
PathList* trings = rings;
while(trings)
{
numRings ++;
PathList *trings = rings;
while (trings) {
numRings++;
totRingLengths += trings->length;
if(trings->length > maxRingLength)
{
if (trings->length > maxRingLength) {
maxRingLength = trings->length;
}
trings = trings->next;
}
// printPath(rings);
newnode = patch(newnode, st,(len << 1), rings);
newnode = patch(newnode, st, (len << 1), rings);
}
// Return incomplete paths
@@ -611,34 +573,28 @@ Node* Octree::trace(Node* newnode, int* st, int len, int depth, PathList*& paths
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]))
{
if (!(node[0] && node[1])) {
return;
}
if(!(leaf[0] && leaf[1]))
{
if (!(leaf[0] && leaf[1])) {
// Not at the bottom, recur
// Fill children nodes
int i, j;
Node* chd[2][8];
Node *chd[2][8];
int chdleaf[2][8];
int nst[2][8][3];
for(j = 0; j < 2; j ++)
{
if(! leaf[j])
{
for (j = 0; j < 2; j++) {
if (!leaf[j]) {
fillChildren(&node[j]->internal, chd[j], chdleaf[j]);
int len =(dimen >>(maxDepth - depth[j] + 1));
for(i = 0; i < 8; i ++)
{
for(int k = 0; k < 3; 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];
}
}
@@ -647,24 +603,20 @@ void Octree::findPaths(Node* node[2], int leaf[2], int depth[2], int* st[2], int
}
// 4 face calls
Node* nf[2];
Node *nf[2];
int df[2];
int lf[2];
int* nstf[2];
for(i = 0; i < 4; i ++)
{
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])
{
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
{
else {
lf[j] = chdleaf[j][c[j]];
nf[j] = chd[j][c[j]];
df[j] = depth[j] - 1;
@@ -675,16 +627,14 @@ void Octree::findPaths(Node* node[2], int leaf[2], int depth[2], int* st[2], int
}
}
else
{
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))
{
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;
PathElement *ele1 = new PathElement;
PathElement *ele2 = new PathElement;
ele1->pos[0] = st[0][0];
ele1->pos[1] = st[0][1];
@@ -697,7 +647,7 @@ void Octree::findPaths(Node* node[2], int leaf[2], int depth[2], int* st[2], int
ele1->next = ele2;
ele2->next = NULL;
PathList* lst = new PathList;
PathList *lst = new PathList;
lst->head = ele1;
lst->tail = ele2;
lst->length = 2;
@@ -710,28 +660,25 @@ void Octree::findPaths(Node* node[2], int leaf[2], int depth[2], int* st[2], int
}
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;
PathList *nlist = NULL;
// Search for each connectors in paths
PathList* tpaths = paths;
PathList* tlist, * pre;
while(tpaths)
{
PathList* singlist = tpaths;
PathList* templist;
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)
{
while (tlist) {
if ((templist = combineSinglePath(list1, pre, tlist, singlist, NULL, singlist)) != NULL) {
singlist = templist;
continue;
}
@@ -742,10 +689,8 @@ void Octree::combinePaths(PathList*& list1, PathList* list2, PathList* paths, Pa
// Look for hookup in list2
tlist = list2;
pre = NULL;
while(tlist)
{
if((templist = combineSinglePath(list2, pre, tlist, singlist, NULL, singlist)) != NULL)
{
while (tlist) {
if ((templist = combineSinglePath(list2, pre, tlist, singlist, NULL, singlist)) != NULL) {
singlist = templist;
continue;
}
@@ -756,10 +701,8 @@ void Octree::combinePaths(PathList*& list1, PathList* list2, PathList* paths, Pa
// Look for hookup in nlist
tlist = nlist;
pre = NULL;
while(tlist)
{
if((templist = combineSinglePath(nlist, pre, tlist, singlist, NULL, singlist)) != NULL)
{
while (tlist) {
if ((templist = combineSinglePath(nlist, pre, tlist, singlist, NULL, singlist)) != NULL) {
singlist = templist;
continue;
}
@@ -768,71 +711,60 @@ void Octree::combinePaths(PathList*& list1, PathList* list2, PathList* paths, Pa
}
// Add to nlist or rings
if(isEqual(singlist->head, singlist->tail))
{
PathElement* temp = singlist->head;
if (isEqual(singlist->head, singlist->tail)) {
PathElement *temp = singlist->head;
singlist->head = temp->next;
delete temp;
singlist->length --;
singlist->length--;
singlist->tail->next = singlist->head;
singlist->next = rings;
rings = singlist;
}
else
{
else {
singlist->next = nlist;
nlist = singlist;
}
}
// Append list2 and nlist to the end of list1
// Append list2 and nlist to the end of list1
tlist = list1;
if(tlist != NULL)
{
while(tlist->next != NULL)
{
if (tlist != NULL) {
while (tlist->next != NULL) {
tlist = tlist->next;
}
tlist->next = list2;
}
else
{
else {
tlist = list2;
list1 = list2;
}
if(tlist != NULL)
{
while(tlist->next != NULL)
{
if (tlist != NULL) {
while (tlist->next != NULL) {
tlist = tlist->next;
}
tlist->next = nlist;
}
else
{
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))
{
if (isEqual(list1->head, list2->head) || isEqual(list1->tail, list2->tail)) {
// Reverse the list
if(list1->length < list2->length)
{
if (list1->length < list2->length) {
// Reverse list1
PathElement* prev = list1->head;
PathElement* next = prev->next;
PathElement *prev = list1->head;
PathElement *next = prev->next;
prev->next = NULL;
while(next != NULL)
{
PathElement* tnext = next->next;
while (next != NULL) {
PathElement *tnext = next->next;
next->next = prev;
prev = next;
@@ -842,15 +774,13 @@ PathList* Octree::combineSinglePath(PathList*& head1, PathList* pre1, PathList*&
list1->tail = list1->head;
list1->head = prev;
}
else
{
else {
// Reverse list2
PathElement* prev = list2->head;
PathElement* next = prev->next;
PathElement *prev = list2->head;
PathElement *next = prev->next;
prev->next = NULL;
while(next != NULL)
{
PathElement* tnext = next->next;
while (next != NULL) {
PathElement *tnext = next->next;
next->next = prev;
prev = next;
@@ -860,17 +790,16 @@ PathList* Octree::combineSinglePath(PathList*& head1, PathList* pre1, PathList*&
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;
PathElement *temp = list1->head->next;
delete list1->head;
list2->tail->next = temp;
PathList* nlist = new PathList;
PathList *nlist = new PathList;
nlist->length = list1->length + list2->length - 1;
nlist->head = list2->head;
nlist->tail = list1->tail;
@@ -880,15 +809,14 @@ PathList* Octree::combineSinglePath(PathList*& head1, PathList* pre1, PathList*&
deletePath(head2, pre2, list2);
return nlist;
}
else if(isEqual(list1->tail, list2->head))
{
}
else if (isEqual(list1->tail, list2->head)) {
// Easy case
PathElement* temp = list2->head->next;
PathElement *temp = list2->head->next;
delete list2->head;
list1->tail->next = temp;
PathList* nlist = new PathList;
PathList *nlist = new PathList;
nlist->length = list1->length + list2->length - 1;
nlist->head = list1->head;
nlist->tail = list2->tail;
@@ -903,173 +831,158 @@ PathList* Octree::combineSinglePath(PathList*& head1, PathList* pre1, PathList*&
return NULL;
}
void Octree::deletePath(PathList*& head, PathList* pre, PathList*& curr)
void Octree::deletePath(PathList *& head, PathList *pre, PathList *& curr)
{
PathList* temp = curr;
PathList *temp = curr;
curr = temp->next;
delete temp;
if(pre == NULL)
{
if (pre == NULL) {
head = curr;
}
else
{
else {
pre->next = curr;
}
}
void Octree::printElement(PathElement* ele)
void Octree::printElement(PathElement *ele)
{
if(ele != NULL)
{
if (ele != NULL) {
dc_printf("(%d %d %d)", ele->pos[0], ele->pos[1], ele->pos[2]);
}
}
void Octree::printPath(PathList* path)
void Octree::printPath(PathList *path)
{
PathElement* n = path->head;
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 ++;
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)
{
if (n == path->head) {
dc_printf(" Ring!\n");
}
else
{
else {
dc_printf(" %p end!\n", n);
}
}
void Octree::printPath(PathElement* path)
void Octree::printPath(PathElement *path)
{
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 ++;
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)
{
if (n == path) {
dc_printf(" Ring!\n");
}
else
{
else {
dc_printf(" %p end!\n", n);
}
}
void Octree::printPaths(PathList* path)
void Octree::printPaths(PathList *path)
{
PathList* iter = path;
PathList *iter = path;
int i = 0;
while(iter != NULL)
{
while (iter != NULL) {
dc_printf("Path %d:\n", i);
printPath(iter);
iter = iter->next;
i ++;
i++;
}
}
Node* Octree::patch(Node* newnode, int st[3], int len, PathList* rings)
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);
#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)
{
if (len == mindimen) {
dc_printf("Error! should have no list by now.\n");
exit(0);
}
// YZ plane
PathList* xlists[2];
PathList *xlists[2];
newnode = patchSplit(newnode, st, len, rings, 0, xlists[0], xlists[1]);
// XZ plane
PathList* ylists[4];
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];
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)
{
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(getChild(&newnode->internal , count), nori, len, zlists[i]);
st[0] + len * vertmap[i][0],
st[1] + len * vertmap[i][1],
st[2] + len * vertmap[i][2]
};
patch(getChild(&newnode->internal, count), nori, len, zlists[i]);
}
if(hasChild(&newnode->internal, i))
{
count ++;
if (hasChild(&newnode->internal, i)) {
count++;
}
}
#ifdef IN_DEBUG_MODE
dc_printf("Return from PATCH\n");
#endif
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);
@@ -1078,12 +991,11 @@ Node* Octree::patchSplit(Node* newnode, int st[3], int len, PathList* rings,
nrings1 = NULL;
nrings2 = NULL;
PathList* tmp;
while(rings != 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;
@@ -1101,91 +1013,78 @@ Node* Octree::patchSplit(Node* newnode, int st[3], int len, PathList* rings,
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);
#endif
if(head == NULL)
{
if (head == NULL) {
#ifdef IN_DEBUG_MODE
dc_printf("Return from PATCHSPLITSINGLE with head==NULL.\n");
#endif
return newnode;
}
else
{
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);
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(side)
{
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();
PathList *nring = new PathList();
nring->head = head;
if(side == -1)
{
if (side == -1) {
nring->next = nrings1;
nrings1 = nring;
}
else
{
else {
nring->next = nrings2;
nrings2 = nring;
}
}
else
{
else {
// Break into two parts
PathElement* nxt1 = pre1->next;
PathElement* nxt2 = pre2->next;
PathElement *nxt1 = pre1->next;
PathElement *nxt2 = pre2->next;
pre1->next = nxt2;
pre2->next = nxt1;
newnode = connectFace(newnode, st, len, dir, pre1, pre2);
if(isEqual(pre1, pre1->next))
{
if(pre1 == pre1->next)
{
if (isEqual(pre1, pre1->next)) {
if (pre1 == pre1->next) {
delete pre1;
pre1 = NULL;
}
else
{
PathElement* temp = pre1->next;
else {
PathElement *temp = pre1->next;
pre1->next = temp->next;
delete temp;
}
}
if(isEqual(pre2, pre2->next))
{
if(pre2 == pre2->next)
{
if (isEqual(pre2, pre2->next)) {
if (pre2 == pre2->next) {
delete pre2;
pre2 = NULL;
}
else
{
PathElement* temp = pre2->next;
else {
PathElement *temp = pre2->next;
pre2->next = temp->next;
delete temp;
}
@@ -1193,11 +1092,11 @@ Node* Octree::patchSplitSingle(Node* newnode, int st[3], int len, PathElement* h
compressRing(pre1);
compressRing(pre2);
// Recur
newnode = patchSplitSingle(newnode, st, len, pre1, dir, nrings1, nrings2);
newnode = patchSplitSingle(newnode, st, len, pre2, dir, nrings1, nrings2);
}
#ifdef IN_DEBUG_MODE
@@ -1211,8 +1110,8 @@ Node* Octree::patchSplitSingle(Node* newnode, int st[3], int len, PathElement* h
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);
@@ -1224,45 +1123,43 @@ Node* Octree::connectFace(Node* newnode, int st[3], int len, int dir,
// checkPath(f2);
#endif
// Setup 2D
// Setup 2D
int pos = st[dir] + len / 2;
int xdir =(dir + 1) % 3;
int ydir =(dir + 2) % 3;
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;
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;
// Do adapted Bresenham line drawing
float rx = p1, ry = q1;
int incx = 1, incy = 1;
int incx = 1, incy = 1;
int lx = x1, ly = y1;
int hx = x2, hy = y2;
int choice;
if(x2 < x1)
{
if (x2 < x1) {
incx = -1;
rx = 1 - rx;
lx = x2;
hx = x1;
}
if(y2 < y1)
{
if (y2 < y1) {
incy = -1;
ry = 1 - ry;
ly = y2;
hy = y1;
}
float sx = dx * incx;
float sy = dy * incy;
int ori[3];
ori[dir] = pos / mindimen;
ori[xdir] = x1;
@@ -1271,89 +1168,78 @@ Node* Octree::connectFace(Node* newnode, int st[3], int len, int dir,
int inc;
float alpha;
PathElement* curEleN = f1;
PathElement* curEleP = f2->next;
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)
{
if (curN == NULL || curP == NULL) {
exit(0);
}
int stN[3], stP[3];
int lenN, lenP;
/* 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)
{
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;
if (sy * (1 - rx) > sx * (1 - ry)) {
choice = 1;
next = ori[ydir] + incy;
if(next < ly || next > hy)
{
if (next < ly || next > hy) {
choice = 4;
next = ori[xdir] + incx;
}
}
else
{
else {
choice = 2;
next = ori[xdir] + incx;
if(next < lx || next > hx)
{
if (next < lx || next > hx) {
choice = 3;
next = ori[ydir] + incy;
}
}
if(choice & 1)
{
if (choice & 1) {
ori[ydir] = next;
if(choice == 1)
{
rx +=(sy == 0 ? 0 :(1 - ry) * sx / sy );
if (choice == 1) {
rx += (sy == 0 ? 0 : (1 - ry) * sx / sy);
ry = 0;
}
walkdir = 2;
inc = incy;
alpha = x2 < x1 ? 1 - rx : rx;
}
else
{
else {
ori[xdir] = next;
if(choice == 2)
{
ry +=(sx == 0 ? 0 :(1 - rx) * sy / sx);
rx = 0;
if (choice == 2) {
ry += (sx == 0 ? 0 : (1 - rx) * sy / sx);
rx = 0;
}
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)
{
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]);
@@ -1366,11 +1252,9 @@ Node* Octree::connectFace(Node* newnode, int st[3], int len, int dir,
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])
{
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];
@@ -1379,23 +1263,20 @@ Node* Octree::connectFace(Node* newnode, int st[3], int len, int dir,
curEleN->next = newEleN;
}
else
{
else {
newEleN = curEleN->next;
}
curN = patchAdjacent(&newnode->internal, len, curEleN->pos, curN,
newEleN->pos, (LeafNode*)nodeN, walkdir,
inc, dir, 1, alpha);
newEleN->pos, (LeafNode *)nodeN, walkdir,
inc, dir, 1, alpha);
curEleN = newEleN;
flag ++;
flag++;
}
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])
{
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];
@@ -1404,27 +1285,25 @@ Node* Octree::connectFace(Node* newnode, int st[3], int len, int dir,
f2->next = newEleP;
}
else
{
else {
newEleP = f2;
}
curP = patchAdjacent(&newnode->internal, len, curEleP->pos, curP,
newEleP->pos, (LeafNode*)nodeP, walkdir,
inc, dir, 0, alpha);
newEleP->pos, (LeafNode *)nodeP, walkdir,
inc, dir, 0, alpha);
curEleP = newEleP;
flag ++;
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
@@ -1441,10 +1320,10 @@ Node* Octree::connectFace(Node* newnode, int st[3], int len, int dir,
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,
float alpha)
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");
@@ -1454,29 +1333,28 @@ LeafNode* Octree::patchAdjacent(InternalNode* node, int len, int st1[3],
#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);
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);
}
*/
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);
LeafNode *nleaf1 = flipEdge(leaf1, eind1, alpha);
LeafNode *nleaf2 = flipEdge(leaf2, eind2, alpha);
// Update parent link
updateParent(node, len, st1, nleaf1);
@@ -1485,13 +1363,13 @@ LeafNode* Octree::patchAdjacent(InternalNode* node, int len, int st1[3],
// 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");
@@ -1501,7 +1379,7 @@ LeafNode* Octree::patchAdjacent(InternalNode* node, int len, int st1[3],
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 ");
@@ -1511,16 +1389,13 @@ Node* Octree::locateCell(InternalNode* node, int st[3], int len, int ori[3], int
int i;
len >>= 1;
int ind = 0;
for(i = 0; i < 3; i ++)
{
for (i = 0; i < 3; i++) {
ind <<= 1;
if(i == dir && side == 1)
{
ind |=(ori[i] <=(st[i] + len) ? 0 : 1);
if (i == dir && side == 1) {
ind |= (ori[i] <= (st[i] + len) ? 0 : 1);
}
else
{
ind |=(ori[i] <(st[i] + len) ? 0 : 1);
else {
ind |= (ori[i] < (st[i] + len) ? 0 : 1);
}
}
@@ -1532,86 +1407,74 @@ Node* Octree::locateCell(InternalNode* node, int st[3], int len, int ori[3], int
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(hasChild(node, ind))
{
if (hasChild(node, ind)) {
int count = getChildCount(node, ind);
Node* chd = getChild(node, count);
if(isLeaf(node, ind))
{
Node *chd = getChild(node, count);
if (isLeaf(node, ind)) {
rleaf = chd;
rlen = len;
}
else
{
else {
// Recur
setChild(node, count, locateCell(&chd->internal, rst, len, ori, dir, side, rleaf, rst, rlen));
}
}
else
{
else {
// Create a new child here
if(len == mindimen)
{
LeafNode* chd = createLeaf(0);
node = addChild(node, ind, (Node*)chd, 1);
rleaf = (Node*)chd;
if (len == mindimen) {
LeafNode *chd = createLeaf(0);
node = addChild(node, ind, (Node *)chd, 1);
rleaf = (Node *)chd;
rlen = len;
}
else
{
else {
// Subdivide the empty cube
InternalNode* chd = createInternal(0);
InternalNode *chd = createInternal(0);
node = addChild(node, ind,
locateCell(chd, rst, len, ori, dir, side, rleaf, rst, rlen), 0);
locateCell(chd, rst, len, ori, dir, side, rleaf, rst, rlen), 0);
}
}
#ifdef IN_DEBUG_MODE
// dc_printf("Return from LOCATECELL with node ");
// printNode(newnode);
#endif
return (Node*)node;
return (Node *)node;
}
void Octree::checkElement(PathElement* ele)
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)
void Octree::checkPath(PathElement *path)
{
PathElement *n = path;
int same = 0;
while(n &&(same == 0 || n != path))
{
same ++;
while (n && (same == 0 || n != path)) {
same++;
checkElement(n);
n = n->next;
}
}
void Octree::testFacePoint(PathElement* e1, PathElement* e2)
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])
{
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
{
else {
e = e1;
}
break;
@@ -1624,56 +1487,50 @@ void Octree::testFacePoint(PathElement* e1, PathElement* e2)
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;
LeafNode* leafnode = locateLeaf(leaf->pos);
for(int i = 0; i < 4; i ++)
{
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 ++)
{
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))
{
if (getEdgeIntersectionByIndex(nst, edgeind / 4, off, 1)) {
avg[0] += off[0];
avg[1] += off[1];
avg[2] += off[2];
num ++;
num++;
}
if(getEdgeParity(leafnode, edgeind))
{
num2 ++;
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];
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
{
else {
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];
}
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];
@@ -1682,42 +1539,40 @@ void Octree::getFacePoint(PathElement* leaf, int dir, int& x, int& y, float& p,
// 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);
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);
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
@@ -1725,41 +1580,37 @@ void Octree::getFacePoint(PathElement* leaf, int dir, int& x, int& y, float& p,
#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;
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))
{
while (cur != anchor && (getSide(cur, pos, dir) == side)) {
ppre1 = cur;
cur = cur->next;
}
if(cur == anchor)
{
if (cur == anchor) {
// No pair found
return side;
}
side = getSide(cur, pos, dir);
ppre2 = cur;
cur = cur->next;
while(getSide(cur, pos, dir) == side)
{
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)
{
if (side == -1) {
cur = ppre1;
ppre1 = ppre2;
ppre2 = cur;
@@ -1767,24 +1618,23 @@ int Octree::findPair(PathElement* head, int pos, int dir, PathElement*& pre1, Pa
pre1 = ppre1;
pre2 = ppre2;
return 0;
}
int Octree::getSide(PathElement* e, int pos, int dir)
int Octree::getSide(PathElement *e, int pos, int dir)
{
return (e->pos[dir] < pos ? -1 : 1);
}
int Octree::isEqual(PathElement* e1, PathElement* e2)
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]);
}
void Octree::compressRing(PathElement*& ring)
void Octree::compressRing(PathElement *& ring)
{
if(ring == NULL)
{
if (ring == NULL) {
return;
}
#ifdef IN_DEBUG_MODE
@@ -1792,26 +1642,22 @@ void Octree::compressRing(PathElement*& ring)
printPath(ring);
#endif
PathElement* cur = ring->next->next;
PathElement* pre = ring->next;
PathElement* prepre = ring;
PathElement* anchor = prepre;
do
{
while(isEqual(cur, 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)
{
if (cur == prepre) {
// The ring has shrinked to a point
delete pre;
delete cur;
anchor = NULL;
break;
}
else
{
else {
prepre->next = cur->next;
delete pre;
delete cur;
@@ -1820,17 +1666,16 @@ void Octree::compressRing(PathElement*& ring)
anchor = prepre;
}
}
if(anchor == NULL)
{
if (anchor == NULL) {
break;
}
prepre = pre;
pre = cur;
cur = cur->next;
} while(prepre != anchor);
} while (prepre != anchor);
ring = anchor;
#ifdef IN_DEBUG_MODE
@@ -1845,18 +1690,14 @@ void Octree::buildSigns()
// dc_printf("Building up look up table...\n");
int size = 1 << 12;
unsigned char table[1 << 12];
for(int i = 0; i < size; i ++)
{
for (int i = 0; i < size; i++) {
table[i] = 0;
}
for(int i = 0; i < 256; i ++)
{
for (int i = 0; i < 256; i++) {
int ind = 0;
for(int j = 11; j >= 0; j --)
{
for (int j = 11; j >= 0; j--) {
ind <<= 1;
if(((i >> edgemap[j][0]) & 1) ^((i >> edgemap[j][1]) & 1))
{
if (((i >> edgemap[j][0]) & 1) ^ ((i >> edgemap[j][1]) & 1)) {
ind |= 1;
}
}
@@ -1870,21 +1711,18 @@ void Octree::buildSigns()
buildSigns(table, root, 0, sg, cube);
}
void Octree::buildSigns(unsigned char table[], Node* node, int isLeaf, int sg, int rvalue[8])
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 ++)
{
if (node == NULL) {
for (int i = 0; i < 8; i++) {
rvalue[i] = sg;
}
return;
}
if(isLeaf == 0)
{
if (isLeaf == 0) {
// Internal node
Node* chd[8];
Node *chd[8];
int leaf[8];
fillChildren(&node->internal, chd, leaf);
@@ -1895,20 +1733,17 @@ void Octree::buildSigns(unsigned char table[], Node* node, int isLeaf, int sg, i
// Get the rest
int cube[8];
for(int i = 1; i < 8; i ++)
{
for (int i = 1; i < 8; i++) {
buildSigns(table, chd[i], leaf[i], oris[i], cube);
rvalue[i] = cube[i];
}
}
else
{
else {
// Leaf node
generateSigns(&node->leaf, table, sg);
for(int i = 0; i < 8; i ++)
{
for (int i = 0; i < 8; i++) {
rvalue[i] = getSign(&node->leaf, i);
}
}
@@ -1935,50 +1770,45 @@ void Octree::floodFill()
}
void Octree::clearProcessBits(Node* node, int height)
void Octree::clearProcessBits(Node *node, int height)
{
int i;
if(height == 0)
{
// Leaf cell,
for(i = 0; i < 12; i ++)
{
if (height == 0) {
// Leaf cell,
for (i = 0; i < 12; i++) {
setOutProcess(&node->leaf, i);
}
}
else
{
else {
// Internal cell, recur
int count = 0;
for(i = 0; i < 8; i ++)
{
if(hasChild(&node->internal, i))
{
for (i = 0; i < 8; i++) {
if (hasChild(&node->internal, i)) {
clearProcessBits(getChild(&node->internal, count), height - 1);
count ++;
count++;
}
}
}
}
}
int Octree::floodFill(LeafNode* leaf, int st[3], int len, int height, int threshold)
int Octree::floodFill(LeafNode *leaf, int st[3], int len, int height, int threshold)
{
int i, j;
int maxtotal = 0;
// Leaf cell,
// Leaf cell,
int par, inp;
// Test if the leaf has intersection edges
for(i = 0; i < 12; i ++) {
for (i = 0; i < 12; i++) {
par = getEdgeParity(leaf, i);
inp = isInProcess(leaf, i);
if(par == 1 && inp == 0) {
if (par == 1 && inp == 0) {
// Intersection edge, hasn't been processed
// Let's start filling
GridQueue* queue = new GridQueue();
GridQueue *queue = new GridQueue();
int total = 1;
// Set to in process
@@ -1994,7 +1824,7 @@ int Octree::floodFill(LeafNode* leaf, int st[3], int len, int height, int thresh
// Queue processing
int nst[3], dir;
while(queue->popQueue(nst, dir) == 1) {
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] = {
@@ -2003,14 +1833,14 @@ int Octree::floodFill(LeafNode* leaf, int st[3], int len, int height, int thresh
{0 - len, 0 - len, 0}
};
int cst[2][3];
for(j = 0; j < 3; j ++) {
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 ++) {
// cells
LeafNode *cs[2];
for (j = 0; j < 2; j++) {
cs[j] = locateLeaf(cst[j]);
}
@@ -2018,37 +1848,37 @@ int Octree::floodFill(LeafNode* leaf, int st[3], int len, int height, int thresh
int s = getSign(cs[0], 0);
// Masks
int fcCells[4] = {1,0,1,0};
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}}
{{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 ++) {
for (int find = 0; find < 4; find++) {
int cind = fcCells[find];
int eind, edge;
if(s == 0) {
if (s == 0) {
// Original order
for(eind = 0; eind < 3; eind ++) {
for (eind = 0; eind < 3; eind++) {
edge = fcEdges[dir][find][eind];
if(getEdgeParity(cs[cind], edge) == 1) {
if (getEdgeParity(cs[cind], edge) == 1) {
break;
}
}
}
else {
// Inverse order
for(eind = 2; eind >= 0; eind --) {
for (eind = 2; eind >= 0; eind--) {
edge = fcEdges[dir][find][eind];
if(getEdgeParity(cs[cind], edge) == 1) {
if (getEdgeParity(cs[cind], edge) == 1) {
break;
}
}
}
if(eind == 3 || eind == -1) {
if (eind == 3 || eind == -1) {
dc_printf("Wrong! this is not a consistent sign. %d\n", eind);
}
else {
@@ -2057,12 +1887,12 @@ int Octree::floodFill(LeafNode* leaf, int st[3], int len, int height, int thresh
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) {
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 ++;
total++;
}
}
}
@@ -2070,16 +1900,16 @@ int Octree::floodFill(LeafNode* leaf, int st[3], int len, int height, int thresh
dc_printf("Size of component: %d ", total);
if(threshold == 0) {
if (threshold == 0) {
// Measuring stage
if(total > maxtotal) {
if (total > maxtotal) {
maxtotal = total;
}
dc_printf(".\n");
continue;
}
if(total >= threshold) {
if (total >= threshold) {
dc_printf("Maintained.\n");
continue;
}
@@ -2095,7 +1925,7 @@ int Octree::floodFill(LeafNode* leaf, int st[3], int len, int height, int thresh
queue->pushQueue(mst, mdir);
// Queue processing
while(queue->popQueue(nst, dir) == 1) {
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] = {
@@ -2104,51 +1934,51 @@ int Octree::floodFill(LeafNode* leaf, int st[3], int len, int height, int thresh
{0 - len, 0 - len, 0}
};
int cst[2][3];
for(j = 0; j < 3; j ++) {
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 ++)
// cells
LeafNode *cs[2];
for (j = 0; j < 2; j++)
cs[j] = locateLeaf(cst[j]);
// Middle sign
int s = getSign(cs[0], 0);
// Masks
int fcCells[4] = {1,0,1,0};
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}}
{{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 ++) {
for (int find = 0; find < 4; find++) {
int cind = fcCells[find];
int eind, edge;
if(s == 0) {
if (s == 0) {
// Original order
for(eind = 0; eind < 3; eind ++) {
for (eind = 0; eind < 3; eind++) {
edge = fcEdges[dir][find][eind];
if(isInProcess(cs[cind], edge) == 1) {
if (isInProcess(cs[cind], edge) == 1) {
break;
}
}
}
else {
// Inverse order
for(eind = 2; eind >= 0; eind --) {
for (eind = 2; eind >= 0; eind--) {
edge = fcEdges[dir][find][eind];
if(isInProcess(cs[cind], edge) == 1) {
if (isInProcess(cs[cind], edge) == 1) {
break;
}
}
}
if(eind == 3 || eind == -1) {
if (eind == 3 || eind == -1) {
dc_printf("Wrong! this is not a consistent sign. %d\n", eind);
}
else {
@@ -2157,12 +1987,12 @@ int Octree::floodFill(LeafNode* leaf, int st[3], int len, int height, int thresh
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) {
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 ++;
total++;
}
}
}
@@ -2173,35 +2003,30 @@ int Octree::floodFill(LeafNode* leaf, int st[3], int len, int height, int thresh
return maxtotal;
}
int Octree::floodFill(Node* node, int st[3], int len, int height, int threshold)
int Octree::floodFill(Node *node, int st[3], int len, int height, int threshold)
{
int i;
int maxtotal = 0;
if(height == 0)
{
if (height == 0) {
maxtotal = floodFill(&node->leaf, st, len, height, threshold);
}
else
{
else {
// Internal cell, recur
int count = 0;
len >>= 1;
for(i = 0; i < 8; i ++)
{
if(hasChild((InternalNode*)node, i))
{
for (i = 0; i < 8; i++) {
if (hasChild((InternalNode *)node, 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(getChild((InternalNode*)node, count), nst, len, height - 1, threshold);
if(d > maxtotal)
{
int d = floodFill(getChild((InternalNode *)node, count), nst, len, height - 1, threshold);
if (d > maxtotal) {
maxtotal = d;
}
count ++;
count++;
}
}
}
@@ -2220,7 +2045,7 @@ void Octree::writeOut()
countIntersection(root, maxDepth, numQuads, numVertices, numEdges);
dc_printf("Vertices counted: %d Polys counted: %d \n", numVertices, numQuads);
output_mesh = alloc_output(numVertices, numQuads);
output_mesh = alloc_output(numVertices, numQuads);
int offset = 0;
int st[3] = {0, 0, 0};
@@ -2234,39 +2059,32 @@ void Octree::writeOut()
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)
{
if (height > 0) {
int total = getNumChildren(&node->internal);
for(int i = 0; i < total; i ++)
{
for (int i = 0; i < total; i++) {
countIntersection(getChild(&node->internal, i), height - 1, nedge, ncell, nface);
}
}
else
{
else {
nedge += getNumEdges2(&node->leaf);
int smask = getSignMask(&node->leaf);
if(use_manifold)
{
if (use_manifold) {
int comps = manifold_table[smask].comps;
ncell += comps;
}
else {
if(smask > 0 && smask < 255)
{
ncell ++;
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++;
}
}
}
@@ -2275,92 +2093,89 @@ void Octree::countIntersection(Node* node, int height, int& nedge, int& ncell, i
/* from http://eigen.tuxfamily.org/bz/show_bug.cgi?id=257 */
template<typename _Matrix_Type_>
void pseudoInverse(const _Matrix_Type_ &a,
_Matrix_Type_ &result,
double epsilon = std::numeric_limits<typename _Matrix_Type_::Scalar>::epsilon())
_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::ComputeFullV);
typename _Matrix_Type_::Scalar tolerance = epsilon * std::max(a.cols(),
a.rows()) *
svd.singularValues().array().abs().maxCoeff();
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();
_Matrix_Type_((svd.singularValues().array().abs() >
tolerance).select(svd.singularValues().
array().inverse(), 0)).asDiagonal() *
svd.matrixU().adjoint();
}
void solve_least_squares(const float halfA[], const float b[],
const float midpoint[], float rvalue[])
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];
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;
for(int i = 0; i < 3; i++)
for (int i = 0; i < 3; i++)
rvalue[i] = result(i);
}
void minimize(float rvalue[3], float mp[3], const float pts[12][3],
const float norms[12][3], const int parity[12])
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;
for(int i = 0; i < 12; 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];
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]);
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]);
double 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];
ec ++;
ec++;
}
}
if(ec == 0)
{
if (ec == 0) {
return;
}
mp[0] /= ec;
mp[1] /= ec;
mp[2] /= ec;
// Solve least squares
solve_least_squares(ata, atb, mp, rvalue);
}
void Octree::computeMinimizer(LeafNode* leaf, int st[3], int len, float rvalue[3])
void Octree::computeMinimizer(LeafNode *leaf, int st[3], int len, float rvalue[3])
{
// First, gather all edge intersections
float pts[12][3], norms[12][3];
@@ -2370,19 +2185,18 @@ void Octree::computeMinimizer(LeafNode* leaf, int st[3], int len, float rvalue[3
// Next, 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;
if((mode == DUALCON_MASS_POINT || mode == DUALCON_CENTROID) ||
(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))
{
if(mode == DUALCON_CENTROID) {
float nh2 = (1 + hermite_num) * len;
if ((mode == DUALCON_MASS_POINT || mode == DUALCON_CENTROID) ||
(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)) {
if (mode == DUALCON_CENTROID) {
// Use centroids
rvalue[0] =(float) st[0] + len / 2;
rvalue[1] =(float) st[1] + len / 2;
rvalue[2] =(float) st[2] + len / 2;
rvalue[0] = (float) st[0] + len / 2;
rvalue[1] = (float) st[1] + len / 2;
rvalue[2] = (float) st[2] + len / 2;
}
else {
// Use mass point instead
@@ -2393,120 +2207,96 @@ void Octree::computeMinimizer(LeafNode* leaf, int st[3], int len, float rvalue[3
}
}
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;
if(height == 0)
{
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;
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 ++)
{
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);
if(use_manifold)
{
if (use_manifold) {
mult = manifold_table[smask].comps;
}
else
{
if(smask > 0 && smask < 255)
{
else {
if (smask > 0 && smask < 255) {
mult = 1;
}
}
for(j = 0; j < mult; j ++)
{
for (j = 0; j < mult; j++) {
add_vert(output_mesh, rvalue);
}
// Store the index
setMinimizerIndex(&node->leaf, offset);
offset += mult;
}
else
{
else {
// Internal cell, recur
int count = 0;
len >>= 1;
for(i = 0; i < 8; i ++)
{
if(hasChild(&node->internal, i))
{
for (i = 0; i < 8; i++) {
if (hasChild(&node->internal, 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(getChild(&node->internal, count),
nst, len, height - 1, offset);
count ++;
nst, len, height - 1, offset);
count++;
}
}
}
}
void Octree::processEdgeWrite(Node* node[4], int depth[4], int maxdep, int dir)
void Octree::processEdgeWrite(Node *node[4], int depth[4], int maxdep, int dir)
{
//int color = 0;
int i = 3;
{
if(getEdgeParity((LeafNode*)(node[i]), processEdgeMask[dir][i]))
{
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)
{
if (getSign((LeafNode *)node[i], edgemap[edgeind][1]) > 0) {
flip = 1;
}
int num = 0;
{
int ind[8];
if(use_manifold)
{
/* Deprecated
int ind[4] = {
getMinimizerIndex(node[0], processEdgeMask[dir][0]),
getMinimizerIndex(node[1], processEdgeMask[dir][1]),
getMinimizerIndex(node[3], processEdgeMask[dir][3]),
getMinimizerIndex(node[2], processEdgeMask[dir][2])
};
num = 4;
*/
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];
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];
}
}
}
@@ -2516,125 +2306,67 @@ void Octree::processEdgeWrite(Node* node[4], int depth[4], int maxdep, int dir)
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]));
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]));
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);
}
/*
if(outType == 0)
{
// OFF
num =(color ? -num : num);
fprintf(fout, "%d ", num);
if(flip)
{
for(int k = num - 1; k >= 0; k --)
{
fprintf(fout, "%d ", ind[k]);
}
}
else
{
for(int k = 0; k < num; k ++)
{
fprintf(fout, "%d ", ind[k]);
}
}
fprintf(fout, "\n");
actualQuads ++;
}
else if(outType == 1)
{
// PLY
if(flip)
{
int tind[8];
for(int k = num - 1; k >= 0; k --)
{
tind[k] = ind[num-1-k];
}
// PLYWriter::writeFace(fout, num, tind);
}
else
{
// PLYWriter::writeFace(fout, num, ind);
}
actualQuads ++;
}*/
}
return;
}
else
{
else {
return;
}
}
}
void Octree::edgeProcContour(Node* node[4], int leaf[4], int depth[4], int maxdep, int dir)
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]))
{
if (!(node[0] && node[1] && node[2] && node[3])) {
return;
}
if(leaf[0] && leaf[1] && leaf[2] && leaf[3])
{
if (leaf[0] && leaf[1] && leaf[2] && leaf[3]) {
processEdgeWrite(node, depth, maxdep, dir);
}
else
{
else {
int i, j;
Node* chd[4][8];
for(j = 0; j < 4; j ++)
{
for(i = 0; i < 8; i ++)
{
Node *chd[4][8];
for (j = 0; j < 4; j++) {
for (i = 0; i < 8; i++) {
chd[j][i] = ((!leaf[j]) && hasChild(&node[j]->internal, i)) ?
getChild(&node[j]->internal,
getChildCount(&node[j]->internal, i)) : NULL;
getChild(&node[j]->internal,
getChildCount(&node[j]->internal, i)) : NULL;
}
}
// 2 edge calls
Node* ne[4];
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 (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])
{
for (int j = 0; j < 4; j++) {
if (leaf[j]) {
le[j] = leaf[j];
ne[j] = node[j];
de[j] = depth[j];
}
else
{
else {
le[j] = isLeaf(&node[j]->internal, c[j]);
ne[j] = chd[j][c[j]];
de[j] = depth[j] - 1;
@@ -2647,45 +2379,37 @@ void Octree::edgeProcContour(Node* node[4], int leaf[4], int depth[4], int maxde
}
}
void Octree::faceProcContour(Node* node[2], int leaf[2], int depth[2], int maxdep, int dir)
void Octree::faceProcContour(Node *node[2], int leaf[2], int depth[2], int maxdep, int dir)
{
if(!(node[0] && node[1]))
{
if (!(node[0] && node[1])) {
return;
}
if(!(leaf[0] && leaf[1]))
{
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]) && hasChild(&node[j]->internal, i)) ?
getChild(&node[j]->internal,
getChildCount(&node[j]->internal, i)) : NULL;
Node *chd[2][8];
for (j = 0; j < 2; j++) {
for (i = 0; i < 8; i++) {
chd[j][i] = ((!leaf[j]) && hasChild(&node[j]->internal, i)) ?
getChild(&node[j]->internal,
getChildCount(&node[j]->internal, i)) : NULL;
}
}
// 4 face calls
Node* nf[2];
Node *nf[2];
int df[2];
int lf[2];
for(i = 0; i < 4; i ++)
{
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])
{
for (int j = 0; j < 2; j++) {
if (leaf[j]) {
lf[j] = leaf[j];
nf[j] = node[j];
df[j] = depth[j];
}
else
{
else {
lf[j] = isLeaf(&node[j]->internal, c[j]);
nf[j] = chd[j][c[j]];
df[j] = depth[j] - 1;
@@ -2696,26 +2420,22 @@ void Octree::faceProcContour(Node* node[2], int leaf[2], int depth[2], int maxde
// 4 edge calls
int orders[2][4] = {{0, 0, 1, 1}, {0, 1, 0, 1}};
Node* ne[4];
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(int j = 0; j < 4; j ++)
{
if(leaf[order[j]])
{
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
{
else {
le[j] = isLeaf(&node[order[j]]->internal, c[j]);
ne[j] = chd[order[j]][c[j]];
de[j] = depth[order[j]] - 1;
@@ -2728,38 +2448,33 @@ void Octree::faceProcContour(Node* node[2], int leaf[2], int depth[2], int maxde
}
void Octree::cellProcContour(Node* node, int leaf, int depth)
void Octree::cellProcContour(Node *node, int leaf, int depth)
{
if(node == NULL)
{
if (node == NULL) {
return;
}
if(! leaf)
{
if (!leaf) {
int i;
// Fill children nodes
Node* chd[8];
for(i = 0; i < 8; i ++)
{
chd[i] =((!leaf) && hasChild(&node->internal, i)) ?
getChild(&node->internal,
getChildCount(&node->internal, i)) : NULL;
Node *chd[8];
for (i = 0; i < 8; i++) {
chd[i] = ((!leaf) && hasChild(&node->internal, i)) ?
getChild(&node->internal,
getChildCount(&node->internal, i)) : NULL;
}
// 8 Cell calls
for(i = 0; i < 8; i ++)
{
for (i = 0; i < 8; i++) {
cellProcContour(chd[i], isLeaf(&node->internal, i), depth - 1);
}
// 12 face calls
Node* nf[2];
Node *nf[2];
int lf[2];
int df[2] = {depth - 1, depth - 1};
for(i = 0; i < 12; i ++)
{
for (i = 0; i < 12; i++) {
int c[2] = {cellProcFaceMask[i][0], cellProcFaceMask[i][1]};
lf[0] = isLeaf(&node->internal, c[0]);
@@ -2772,15 +2487,13 @@ void Octree::cellProcContour(Node* node, int leaf, int depth)
}
// 6 edge calls
Node* ne[4];
Node *ne[4];
int le[4];
int de[4] = {depth - 1, depth - 1, depth - 1, depth - 1};
for(i = 0; i < 6; i ++)
{
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 ++)
{
for (int j = 0; j < 4; j++) {
le[j] = isLeaf(&node->internal, c[j]);
ne[j] = chd[c[j]];
}
@@ -2788,81 +2501,68 @@ void Octree::cellProcContour(Node* node, int leaf, int depth)
edgeProcContour(ne, le, de, depth - 1, cellProcEdgeMask[i][4]);
}
}
}
void Octree::processEdgeParity(LeafNode* node[4], int depth[4], int maxdep, int dir)
void Octree::processEdgeParity(LeafNode *node[4], int depth[4], int maxdep, int dir)
{
int con = 0;
for(int i = 0; i < 4; i ++)
{
for (int i = 0; i < 4; i++) {
// Minimal cell
// if(op == 0)
{
if(getEdgeParity(node[i], processEdgeMask[dir][i]))
{
if (getEdgeParity(node[i], processEdgeMask[dir][i])) {
con = 1;
break;
}
}
}
if(con == 1)
{
for(int i = 0; i < 4; i ++)
{
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)
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]))
{
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);
if (leaf[0] && leaf[1] && leaf[2] && leaf[3]) {
processEdgeParity((LeafNode **)node, depth, maxdep, dir);
}
else
{
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]) && hasChild(&node[j]->internal, i)) ?
getChild(&node[j]->internal, getChildCount(&node[j]->internal, i)) : NULL;
Node *chd[4][8];
for (j = 0; j < 4; j++) {
for (i = 0; i < 8; i++) {
chd[j][i] = ((!leaf[j]) && hasChild(&node[j]->internal, i)) ?
getChild(&node[j]->internal, getChildCount(&node[j]->internal, i)) : NULL;
}
}
// 2 edge calls
Node* ne[4];
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 (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 ++)
{
for (int j = 0; j < 4; j++) {
if(leaf[j])
{
if (leaf[j]) {
le[j] = leaf[j];
ne[j] = node[j];
de[j] = depth[j];
}
else
{
else {
le[j] = isLeaf(&node[j]->internal, c[j]);
ne[j] = chd[j][c[j]];
de[j] = depth[j] - 1;
@@ -2877,45 +2577,37 @@ void Octree::edgeProcParity(Node* node[4], int leaf[4], int depth[4], int maxdep
}
}
void Octree::faceProcParity(Node* node[2], int leaf[2], int depth[2], int maxdep, int dir)
void Octree::faceProcParity(Node *node[2], int leaf[2], int depth[2], int maxdep, int dir)
{
if(!(node[0] && node[1]))
{
if (!(node[0] && node[1])) {
return;
}
if(!(leaf[0] && leaf[1]))
{
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]) && hasChild(&node[j]->internal, i)) ?
getChild(&node[j]->internal,
getChildCount(&node[j]->internal, i)) : NULL;
Node *chd[2][8];
for (j = 0; j < 2; j++) {
for (i = 0; i < 8; i++) {
chd[j][i] = ((!leaf[j]) && hasChild(&node[j]->internal, i)) ?
getChild(&node[j]->internal,
getChildCount(&node[j]->internal, i)) : NULL;
}
}
// 4 face calls
Node* nf[2];
Node *nf[2];
int df[2];
int lf[2];
for(i = 0; i < 4; i ++)
{
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])
{
for (int j = 0; j < 2; j++) {
if (leaf[j]) {
lf[j] = leaf[j];
nf[j] = node[j];
df[j] = depth[j];
}
else
{
else {
lf[j] = isLeaf(&node[j]->internal, c[j]);
nf[j] = chd[j][c[j]];
df[j] = depth[j] - 1;
@@ -2926,27 +2618,23 @@ void Octree::faceProcParity(Node* node[2], int leaf[2], int depth[2], int maxdep
// 4 edge calls
int orders[2][4] = {{0, 0, 1, 1}, {0, 1, 0, 1}};
Node* ne[4];
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(int j = 0; j < 4; j ++)
{
if(leaf[order[j]])
{
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] = isLeaf((InternalNode*)(node[order[j]]), c[j]);
else {
le[j] = isLeaf((InternalNode *)(node[order[j]]), c[j]);
ne[j] = chd[order[j]][c[j]];
de[j] = depth[order[j]] - 1;
}
@@ -2958,42 +2646,37 @@ void Octree::faceProcParity(Node* node[2], int leaf[2], int depth[2], int maxdep
}
void Octree::cellProcParity(Node* node, int leaf, int depth)
void Octree::cellProcParity(Node *node, int leaf, int depth)
{
if(node == NULL)
{
if (node == NULL) {
return;
}
if(! leaf)
{
if (!leaf) {
int i;
// Fill children nodes
Node* chd[8];
for(i = 0; i < 8; i ++)
{
chd[i] =((!leaf) && hasChild((InternalNode*)node, i)) ?
getChild((InternalNode*)node,
getChildCount((InternalNode*)node, i)) : NULL;
Node *chd[8];
for (i = 0; i < 8; i++) {
chd[i] = ((!leaf) && hasChild((InternalNode *)node, i)) ?
getChild((InternalNode *)node,
getChildCount((InternalNode *)node, i)) : NULL;
}
// 8 Cell calls
for(i = 0; i < 8; i ++)
{
cellProcParity(chd[i], isLeaf((InternalNode*)node, i), depth - 1);
for (i = 0; i < 8; i++) {
cellProcParity(chd[i], isLeaf((InternalNode *)node, i), depth - 1);
}
// 12 face calls
Node* nf[2];
Node *nf[2];
int lf[2];
int df[2] = {depth - 1, depth - 1};
for(i = 0; i < 12; i ++)
{
for (i = 0; i < 12; i++) {
int c[2] = {cellProcFaceMask[i][0], cellProcFaceMask[i][1]};
lf[0] = isLeaf((InternalNode*)node, c[0]);
lf[1] = isLeaf((InternalNode*)node, c[1]);
lf[0] = isLeaf((InternalNode *)node, c[0]);
lf[1] = isLeaf((InternalNode *)node, c[1]);
nf[0] = chd[c[0]];
nf[1] = chd[c[1]];
@@ -3002,23 +2685,21 @@ void Octree::cellProcParity(Node* node, int leaf, int depth)
}
// 6 edge calls
Node* ne[4];
Node *ne[4];
int le[4];
int de[4] = {depth - 1, depth - 1, depth - 1, depth - 1};
for(i = 0; i < 6; i ++)
{
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] = isLeaf((InternalNode*)node, c[j]);
for (int j = 0; j < 4; j++) {
le[j] = isLeaf((InternalNode *)node, c[j]);
ne[j] = chd[c[j]];
}
edgeProcParity(ne, le, de, depth - 1, cellProcEdgeMask[i][4]);
}
}
}
/* definitions for global arrays */

View File

@@ -37,7 +37,7 @@
#include "dualcon.h"
/**
* Main class and structures for scan-convertion, sign-generation,
* Main class and structures for scan-convertion, sign-generation,
* and surface reconstruction.
*
* @author Tao Ju
@@ -90,7 +90,7 @@ struct LeafNode /* TODO: remove this attribute once everything is fixed */ {
char signs;
int minimizer_index;
unsigned short flood_fill;
float edge_intersections[0];
@@ -112,33 +112,31 @@ extern const int faceProcFaceMask[3][4][3];
extern const int edgeProcEdgeMask[3][2][5];
extern const int faceProcEdgeMask[3][4][6];
extern const int processEdgeMask[3][4];
extern const int dirCell[3][4][3];
extern const int dirCell[3][4][3];
extern const int dirEdge[3][4];
/**
* Structures for detecting/patching open cycles on the dual surface
*/
struct PathElement
{
struct PathElement {
// Origin
int pos[3];
// link
PathElement* next;
PathElement *next;
};
struct PathList
{
struct PathList {
// Head
PathElement* head;
PathElement* tail;
PathElement *head;
PathElement *tail;
// Length of the list
int length;
// Next list
PathList* next;
PathList *next;
};
@@ -148,1284 +146,1276 @@ struct PathList
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;
/// The lower corner of the bounding box and the size
float origin[3];
float range;
/// Maximum depth
int maxDepth;
/// Counting information
int nodeCount;
int nodeSpace;
int nodeCounts[9];
/// The lower corner of the bounding box and the size
float origin[3];
float range;
int actualQuads, actualVerts;
/// Counting information
int nodeCount;
int nodeSpace;
int nodeCounts[9];
PathList* ringList;
int actualQuads, actualVerts;
int maxTrianglePerCell;
int outType; // 0 for OFF, 1 for PLY, 2 for VOL
PathList *ringList;
// For flood filling
int use_flood_fill;
float thresh;
int maxTrianglePerCell;
int outType; // 0 for OFF, 1 for PLY, 2 for VOL
int use_manifold;
// For flood filling
int use_flood_fill;
float thresh;
float hermite_num;
int use_manifold;
DualConMode mode;
float hermite_num;
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 */
/**
* Initialize memory allocators
*/
void initMemory();
/* Helper functions */
/**
* Release memory
*/
void freeMemory();
/**
* Initialize memory allocators
*/
void initMemory();
/**
* Print memory usage
*/
void printMemUsage();
/**
* Release memory
*/
void freeMemory();
/**
* 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 addTrian();
void addTrian(Triangle* trian, int triind);
InternalNode* addTrian(InternalNode* node, Projections* p, int height);
/**
* Add triangles to the tree
*/
void addTrian();
void addTrian(Triangle *trian, int triind);
InternalNode *addTrian(InternalNode *node, Projections *p, int height);
/**
* Method to update minimizer in a cell: update edge intersections instead
*/
LeafNode* updateCell(LeafNode* node, Projections* p);
/**
* Method to update minimizer in a cell: update edge intersections instead
*/
LeafNode *updateCell(LeafNode *node, Projections *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);
/**
* 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);
/**
* 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);
/**
* 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]);
/**
* 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);
/************************************************************************/
/* 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);
/**
* 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(LeafNode* leaf, int st[3], int len, float rvalue[3]);
/**
* 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(LeafNode * leaf, int st[3], int len, float rvalue[3]);
/**
* 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 ************/
/************ Operators for all nodes ************/
/// Lookup table
int numChildrenTable[256];
int childrenCountTable[256][8];
int childrenIndexTable[256][8];
int numEdgeTable[8];
int edgeCountTable[8][3];
/// Lookup table
int numChildrenTable[256];
int childrenCountTable[256][8];
int childrenIndexTable[256][8];
int numEdgeTable[8];
int edgeCountTable[8][3];
/// Build up lookup table
void buildTable()
/// Build up lookup table
void buildTable()
{
for (int i = 0; i < 256; i++)
{
for(int i = 0; i < 256; i ++)
numChildrenTable[i] = 0;
int count = 0;
for (int j = 0; j < 8; j++)
{
numChildrenTable[i] = 0;
int count = 0;
for(int j = 0; j < 8; j ++)
numChildrenTable[i] += ((i >> j) & 1);
childrenCountTable[i][j] = count;
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 (hasChild(&node->internal, index))
{
return getSign(getChild(&node->internal, getChildCount(&node->internal, index)),
height - 1,
index);
}
else {
return getSign(getChild(&node->internal, 0),
height - 1,
7 - getChildIndex(&node->internal, 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)
{
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(LeafNode *leaf, int index)
{
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(LeafNode *leaf, int pindex)
{
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)
{
numChildrenTable[i] +=((i >> j) & 1);
childrenCountTable[i][j] = count;
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(hasChild(&node->internal, index))
{
return getSign(getChild(&node->internal, getChildCount(&node->internal, index)),
height - 1,
index);
}
else
{
return getSign(getChild(&node->internal, 0),
height - 1,
7 - getChildIndex(&node->internal, 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)
{
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(LeafNode* leaf, int index)
{
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(LeafNode* leaf, int pindex)
{
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++)
{
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++)
{
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];
}
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
setChild(parent, 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
setChild(parent, count, (Node*)node);
}
/// Find edge intersection on a given edge
int getEdgeIntersectionByIndex(int st[3], int index, float pt[3], int check)
{
// First, locat the leaf
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;
removeLeaf(num - 1, (LeafNode *)leaf);
leaf = nleaf;
}
}
/// Retrieve number of edges intersected
int getPrimalEdgesMask(LeafNode* leaf)
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
setChild(parent, count, (Node *)leaf);
}
void updateParent(InternalNode *node, int len, int st[3])
{
if (len == dimen)
{
return leaf->primary_edge_intersections;
root = (Node *)node;
return;
}
int getPrimalEdgesMask2(LeafNode* leaf)
// First, locate the parent
int count;
InternalNode *parent = locateParent(len, st, count);
// UPdate
setChild(parent, count, (Node *)node);
}
/// Find edge intersection on a given edge
int getEdgeIntersectionByIndex(int st[3], int index, float pt[3], int check)
{
// First, locat the leaf
LeafNode *leaf;
if (check)
{
return (((leaf->edge_parity & 0x1) >> 0) |
((leaf->edge_parity & 0x10) >> 3) |
((leaf->edge_parity & 0x100) >> 6));
leaf = locateLeafCheck(st);
}
else {
leaf = locateLeaf(st);
}
/// Get the count for a primary edge
int getEdgeCount(LeafNode* leaf, int index)
if (leaf && getStoredEdgesParity(leaf, index))
{
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(LeafNode* leaf, int count)
{
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, float pt[], float a[], float b[], 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(LeafNode* leaf, int index, int st[3], int len, float pt[3], float nm[3])
{
int count = getEdgeCount(leaf, index);
float *pts = leaf->edge_intersections;
float off = pts[4 * count];
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 * len);
pt[index] += off * mindimen;
nm[0] = pts[4 * count + 1];
nm[1] = pts[4 * count + 2];
nm[2] = pts[4 * count + 3];
return 1;
}
else {
return 0;
}
}
/// Retrieve number of edges intersected
int getPrimalEdgesMask(LeafNode *leaf)
{
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(LeafNode *leaf, int index)
{
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(LeafNode *leaf, int count)
{
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, float pt[], float a[], float b[], 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(LeafNode *leaf, int index, int st[3], int len, float pt[3], float nm[3])
{
int count = getEdgeCount(leaf, index);
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(LeafNode *leaf, int st[3], int len, float pts[12][3], float norms[12][3])
{
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]]);
}
}
float getEdgeOffsetNormalByIndex(LeafNode* leaf, int index, float nm[3])
// 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 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];
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;
LeafNode *node = locateLeaf(nst);
return off;
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]]);
}
}
}
void fillEdgeIntersections(LeafNode* leaf, int st[3], int len, float pts[12][3], float norms[12][3])
// 3 edge adjacent cubes
int emask[3] = {3, 7, 11};
int eemask[3] = {0, 1, 2};
for (i = 0; i < 3; i++)
{
int i;
// int stt[3] = {0, 0, 0};
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 = locateLeaf(nst);
// The three primal edges are easy
int pmask[3] = {0, 4, 8};
for(i = 0; i < 3; 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]]);
}
}
}
void fillEdgeIntersections(LeafNode *leaf, int st[3], int len, float pts[12][3], 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))
{
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]]);
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)
{
// getEdgeIntersectionByIndex(leaf, i, stt, 1, pts[pmask[i]], norms[pmask[i]]);
getEdgeIntersectionByIndex(leaf, i, st, len, pts[pmask[i]], norms[pmask[i]]);
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 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 ++)
}
// 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 e1 = getEdgeParity(leaf, fmask[i][0]);
int e2 = getEdgeParity(leaf, fmask[i][1]);
if(e1 || e2)
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)
{
int nst[3] = {st[0], st[1], st[2]};
nst[i] += len;
// int nstt[3] = {0, 0, 0};
// nstt[i] += 1;
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]]);
}
continue;
}
}
// 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]))
if (getStoredEdgesParity(node, eemask[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 = 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]]);
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;
}
}
}
void fillEdgeIntersections(LeafNode* leaf, int st[3], int len, float pts[12][3], float norms[12][3], int parity[12])
// 3 edge adjacent cubes
int emask[3] = {3, 7, 11};
int eemask[3] = {0, 1, 2};
for (i = 0; i < 3; i++)
{
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;
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;
LeafNode *node = locateLeafCheck(nst);
if (node == NULL)
{
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]))
{
// 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;
}
continue;
}
if (getStoredEdgesParity(node, eemask[i]))
{
pts[emask[i]] = getEdgeOffsetNormalByIndex(node, eemask[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])
/// 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 = getChild(&node->internal, getChildCount(&node->internal, 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 = getChild(&node->internal,
getChildCount(&node->internal, 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 (!hasChild(&node->internal, index))
{
return NULL;
}
node = getChild(&node->internal, getChildCount(&node->internal, 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 = &getChild(node, getChildCount(node, index))->internal;
}
count = getChildCount(pre, 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 = (InternalNode *)getChild(node, getChildCount(node, index));
}
count = getChildCount(pre, index);
return pre;
}
/************ Operators for internal nodes ************/
/// If child index exists
int hasChild(InternalNode *node, int index)
{
return (node->has_child >> index) & 1;
}
/// Test if child is leaf
int isLeaf(InternalNode *node, int index)
{
return (node->child_is_leaf >> index) & 1;
}
/// Get the pointer to child index
Node *getChild(InternalNode *node, int count)
{
return node->children[count];
};
/// Get total number of children
int getNumChildren(InternalNode *node)
{
return numChildrenTable[node->has_child];
}
/// Get the count of children
int getChildCount(InternalNode *node, int index)
{
return childrenCountTable[node->has_child][index];
}
int getChildIndex(InternalNode *node, int count)
{
return childrenIndexTable[node->has_child][count];
}
int *getChildCounts(InternalNode *node)
{
return childrenCountTable[node->has_child];
}
/// Get all children
void fillChildren(InternalNode *node, Node *children[8], int leaf[8])
{
int count = 0;
for (int i = 0; i < 8; i++)
{
leaf[i] = isLeaf(node, i);
if (hasChild(node, i))
{
children[i] = getChild(node, count);
count++;
}
else {
children[i] = NULL;
leaf[i] = 0;
}
}
}
/// Sets the child pointer
void setChild(InternalNode *node, int count, Node *chd)
{
node->children[count] = chd;
}
void setInternalChild(InternalNode *node, int index, int count, InternalNode *chd)
{
setChild(node, count, (Node *)chd);
node->has_child |= (1 << index);
}
void setLeafChild(InternalNode *node, int index, int count, LeafNode *chd)
{
setChild(node, count, (Node *)chd);
node->has_child |= (1 << index);
node->child_is_leaf |= (1 << index);
}
/// Add a kid to an existing internal node
/// Fix me: can we do this without wasting memory ?
/// Fixed: using variable memory
InternalNode *addChild(InternalNode *node, int index, Node *child, int aLeaf)
{
// Create new internal node
int num = getNumChildren(node);
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)
{
setLeafChild(rnode, i, count2, &child->leaf);
}
else {
setInternalChild(rnode, i, count2, &child->internal);
}
count2++;
}
else if (hasChild(node, i))
{
if (isLeaf(node, i))
{
setLeafChild(rnode, i, count2, &getChild(node, count1)->leaf);
}
else {
setInternalChild(rnode, i, count2, &getChild(node, 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 = 0;
inode->child_is_leaf = 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 = getNumChildren(par) + 1;
InternalNode *npar = createInternal(num);
*npar = *par;
if (num == 1)
{
setLeafChild(npar, index, 0, leaf);
}
else {
int i;
for(i = 0; i < 12; i ++)
for (i = 0; i < count; i++)
{
parity[i] = 0;
setChild(npar, i, getChild(par, 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 ++)
setLeafChild(npar, index, count, leaf);
for (i = count + 1; i < num; 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;
}
}
setChild(npar, i, getChild(par, i - 1));
}
}
removeInternal(num - 1, par);
return npar;
}
/// Update method
LeafNode* updateEdgeOffsetsNormals(LeafNode* leaf, int oldlen, int newlen, float offs[3], float a[3], float b[3], float c[3])
InternalNode *addInternalChild(InternalNode *par, int index, int count,
InternalNode *node)
{
int num = getNumChildren(par) + 1;
InternalNode *npar = createInternal(num);
*npar = *par;
if (num == 1)
{
// 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;
setInternalChild(npar, index, 0, node);
}
/// 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 = getChild(&node->internal, getChildCount(&node->internal, 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 = getChild(&node->internal,
getChildCount(&node->internal, 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(!hasChild(&node->internal, index))
{
return NULL;
}
node = getChild(&node->internal, getChildCount(&node->internal, 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 = &getChild(node, getChildCount(node, index))->internal;
}
count = getChildCount(pre, 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 = (InternalNode*)getChild(node, getChildCount(node, index));
}
count = getChildCount(pre, index);
return pre;
}
/************ Operators for internal nodes ************/
/// If child index exists
int hasChild(InternalNode* node, int index)
{
return (node->has_child >> index) & 1;
}
/// Test if child is leaf
int isLeaf(InternalNode* node, int index)
{
return (node->child_is_leaf >> index) & 1;
}
/// Get the pointer to child index
Node* getChild(InternalNode* node, int count)
{
return node->children[count];
};
/// Get total number of children
int getNumChildren(InternalNode* node)
{
return numChildrenTable[node->has_child];
}
/// Get the count of children
int getChildCount(InternalNode* node, int index)
{
return childrenCountTable[node->has_child][index];
}
int getChildIndex(InternalNode* node, int count)
{
return childrenIndexTable[node->has_child][count];
}
int* getChildCounts(InternalNode* node)
{
return childrenCountTable[node->has_child];
}
/// Get all children
void fillChildren(InternalNode* node, Node* children[8], int leaf[8])
{
int count = 0;
for(int i = 0; i < 8; i ++)
{
leaf[i] = isLeaf(node, i);
if(hasChild(node, i))
{
children[i] = getChild(node, count);
count ++;
}
else
{
children[i] = NULL;
leaf[i] = 0;
}
}
}
/// Sets the child pointer
void setChild(InternalNode* node, int count, Node* chd)
{
node->children[count] = chd;
}
void setInternalChild(InternalNode* node, int index, int count, InternalNode* chd)
{
setChild(node, count, (Node*)chd);
node->has_child |= (1 << index);
}
void setLeafChild(InternalNode* node, int index, int count, LeafNode* chd)
{
setChild(node, count, (Node*)chd);
node->has_child |=(1 << index);
node->child_is_leaf |= (1 << index);
}
/// Add a kid to an existing internal node
/// Fix me: can we do this without wasting memory ?
/// Fixed: using variable memory
InternalNode* addChild(InternalNode* node, int index, Node* child, int aLeaf)
{
// Create new internal node
int num = getNumChildren(node);
InternalNode* rnode = createInternal(num + 1);
// Establish children
else {
int i;
int count1 = 0, count2 = 0;
for(i = 0; i < 8; i ++)
for (i = 0; i < count; i++)
{
if(i == index)
{
if(aLeaf)
{
setLeafChild(rnode, i, count2, &child->leaf);
}
else
{
setInternalChild(rnode, i, count2, &child->internal);
}
count2 ++;
}
else if(hasChild(node, i))
{
if(isLeaf(node, i))
{
setLeafChild(rnode, i, count2, &getChild(node, count1)->leaf);
}
else
{
setInternalChild(rnode, i, count2, &getChild(node, count1)->internal);
}
count1 ++;
count2 ++;
}
setChild(npar, i, getChild(par, i));
}
removeInternal(num, node);
return rnode;
}
/// Allocate a node
InternalNode* createInternal(int length)
{
InternalNode* inode = (InternalNode*)alloc[length]->allocate();
inode->has_child = 0;
inode->child_is_leaf = 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 = getNumChildren(par) + 1;
InternalNode* npar = createInternal(num);
*npar = *par;
if(num == 1)
setInternalChild(npar, index, count, node);
for (i = count + 1; i < num; i++)
{
setLeafChild(npar, index, 0, leaf);
setChild(npar, i, getChild(par, i - 1));
}
else
{
int i;
for(i = 0; i < count; i ++)
{
setChild(npar, i, getChild(par, i));
}
setLeafChild(npar, index, count, leaf);
for(i = count + 1; i < num; i ++)
{
setChild(npar, i, getChild(par, i - 1));
}
}
removeInternal(num-1, par);
return npar;
}
InternalNode* addInternalChild(InternalNode* par, int index, int count,
InternalNode* node)
{
int num = getNumChildren(par) + 1;
InternalNode* npar = createInternal(num);
*npar = *par;
if(num == 1)
{
setInternalChild(npar, index, 0, node);
}
else
{
int i;
for(i = 0; i < count; i ++)
{
setChild(npar, i, getChild(par, i));
}
setInternalChild(npar, index, count, node);
for(i = count + 1; i < num; i ++)
{
setChild(npar, i, getChild(par, i - 1));
}
}
removeInternal(num-1, par);
return npar;
}
removeInternal(num - 1, par);
return npar;
}
};
#endif