/*
* This file is part of MoleculeViewer.
*
* MoleculeViewer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MoleculeViewer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MoleculeViewer. If not, see <http://www.gnu.org/licenses/>.
*/
package astex;
/* Copyright Astex Technology Ltd. 2003 */
/* Copyright David Hall, Boston University, 2011 */
/**
* A class for (hopefully) implementing marching
* cubes algorithm for isosurfaces.
*/
class March {
/** Number of edges per layer. */
private static int nLayerEdges = 0;
/** Indexing tags for edges of each layer. */
private static int layerEdges[] = null;
/** Layer dimensions. */
private static int iDim = 0;
private static int jDim = 0;
private static int kDim = 0;
private static int iDim1 = 0;
private static int jDim1 = 0;
private static int kDim1 = 0;
private static int iDim2 = 0;
private static int jDim2 = 0;
private static int kDim2 = 0;
private static int ijDim = 0;
/** Debugging? */
private static final boolean debug = false;
/** Empty edge identifier. */
private static final int emptyEdge = -1;
/** Effective zero. */
private static final float epsilon = 0.000001f;
/** tmesh object so that we can output triangles. */
private static Tmesh tmesh = null;
/** Looukp hoojami. */
private static int nedge01 = 0;
private static int ngrid01 = 0;
private static int count = 0;
public static boolean generateTriangles = true;
/** Vertex masks. */
private static final int V0 = 1;
private static final int V1 = 2;
private static final int V2 = 4;
private static final int V3 = 8;
private static final int V4 = 16;
private static final int V5 = 32;
private static final int V6 = 64;
private static final int V7 = 128;
/** Face masks. */
private static final int Face0123 = V0|V1|V2|V3;
private static final int Face0154 = V0|V1|V5|V4;
private static final int Face0374 = V0|V3|V7|V4;
/** Constructor. */
public static synchronized
Tmesh surface(float data[], int nx, int ny, int nz,
float threshold, boolean invert, Tmesh tm){
int i, j, k;
int off1;
//long then = System.currentTimeMillis();
tmesh = tm;
/* Sort out layer dimensions. */
iDim = nx;
jDim = ny;
kDim = nz;
iDim1 = iDim - 1;
jDim1 = jDim - 1;
kDim1 = kDim - 1;
iDim2 = iDim - 2;
jDim2 = jDim - 2;
kDim2 = kDim - 2;
ijDim = iDim * jDim;
/* Allocate enough space for the indexing tags
for the edges and set to empty. */
nLayerEdges = (iDim1) * (jDim1) * 12;
layerEdges = new int[nLayerEdges];
for(i = 0; i < nLayerEdges; i++){
layerEdges[i] = emptyEdge;
}
/* Sort out lookup varible. */
nedge01 = 12 * (iDim1);
ngrid01 = iDim * jDim;
if(debug){
System.out.println("Beginning marching cubes algorithm");
System.out.println("Dimensions: x " + iDim +
" y " + jDim + " z " + kDim);
}
marchLayer(data, 0, layerEdges, threshold);
/* Now do the remaining layers. */
for (k = 1; k < kDim1; k++) {
off1 = getEdgeOffset(0, 0, 0);
/* Percolate the last layer's top edges
to this layer's bottom edges. */
for (j = 0; j < jDim1; j++) {
for (i = 0; i < iDim1; i++) {
/* Copying edges. */
layerEdges[off1] = layerEdges[off1+2];
layerEdges[off1+4] = layerEdges[off1+6];
layerEdges[off1+8] = layerEdges[off1+11];
layerEdges[off1+9] = layerEdges[off1+10];
/* Reinitialize all of the remaining edges */
layerEdges[off1+1] = emptyEdge;
layerEdges[off1+2] = emptyEdge;
layerEdges[off1+3] = emptyEdge;
layerEdges[off1+5] = emptyEdge;
layerEdges[off1+6] = emptyEdge;
layerEdges[off1+7] = emptyEdge;
layerEdges[off1+10] = emptyEdge;
layerEdges[off1+11] = emptyEdge;
off1 += 12;
}
}
marchLayer(data, k, layerEdges, threshold);
}
if(debug){
System.out.println("Count " + count);
System.out.println("Finished marching cubes algorithm");
}
if(invert){
for(int iv = 0; iv < tmesh.np; iv++){
tmesh.nx[iv] = -tmesh.nx[iv];
tmesh.ny[iv] = -tmesh.ny[iv];
tmesh.nz[iv] = -tmesh.nz[iv];
}
}
return tmesh;
}
/* Grid values at each cell position. */
private static float cell[] = new float[8];
/* Reference to vertices at the 12 edges of a cell */
private static int cellVerts[] = new int[12];
/** This is the main marching cubes algorithm function. */
private static void marchLayer(float data[],
int layer, int layerEdges[],
float threshold){
int i, j, off, e;
float localData[] = data;
/* Cell index lookup. */
int cellIndex;
/* Initialise cellVerts. */
for(i = 0; i < 12; i++){
cellVerts[i] = emptyEdge;
}
/* Loop over each cube in the layer. */
int iijDim = iDim + ijDim;
for(j = 0; j < jDim1; j++) {
/** Do this simply first. */
int cell0 = getOffset(0, j, layer);
/* Initialise cell values in j. */
cell[0] = localData[cell0];
cell[1] = localData[cell0 + iDim];
cell[2] = localData[cell0 + iijDim];
cell[3] = localData[cell0 + ijDim];
cellIndex = 0;
if(cell[0] > threshold) cellIndex |= V0;
if(cell[1] > threshold) cellIndex |= V1;
if(cell[2] > threshold) cellIndex |= V2;
if(cell[3] > threshold) cellIndex |= V3;
for(i = 0; i < iDim1; i++) {
cell0++;
cell[4] = localData[cell0];
cell[5] = localData[cell0 + iDim];
cell[6] = localData[cell0 + iijDim];
cell[7] = localData[cell0 + ijDim];
/** Compute the index for the edge intersections for i. */
if(cell[4] > threshold) cellIndex |= V4;
if(cell[5] > threshold) cellIndex |= V5;
if(cell[6] > threshold) cellIndex |= V6;
if(cell[7] > threshold) cellIndex |= V7;
/* Skip loop if no edges */
if(cellIndex != 0 && cellIndex != 255){
count++;
/* Here find edge(s) that will contain a vertex. */
int lookup = 1;
for(e = 0; e < 12; e++){
if((edgeTable[cellIndex] & lookup) != 0){
addVertex(data, e, i, j, threshold,
cellVerts, layer);
}
lookup <<= 1;
}
/* Put the cellVerts references into
this cell's layerEdges table. */
off = getEdgeOffset(0, i, j);
for(e = 0; e < 12; e++){
if(cellVerts[e] != emptyEdge){
layerEdges[off] = cellVerts[e];
}
off++;
}
/* Propagate the vertex/normal references
to the adjacent cells to
the right and in front of this layer.
Propagate to the right */
if (i < iDim2) {
off = getEdgeOffset(0, i+1, j);
layerEdges[off] = cellVerts[4];
layerEdges[off+1] = cellVerts[5];
layerEdges[off+2] = cellVerts[6];
layerEdges[off+3] = cellVerts[7];
}
/* Propagate to the front. */
if (j < jDim2) {
off = getEdgeOffset( 3, i, j+1);
layerEdges[off] = cellVerts[1];
layerEdges[off+5] = cellVerts[9];
layerEdges[off+4] = cellVerts[5];
layerEdges[off+8] = cellVerts[10];
}
if(generateTriangles){
/* Add triangles. */
int ii = 0;
while (triTable[cellIndex][ii] != -1) {
tmesh.addTriangle(cellVerts[triTable[cellIndex][ii]],
cellVerts[triTable[cellIndex][ii+1]],
cellVerts[triTable[cellIndex][ii+2]]);
ii += 3;
}
}else{
// always contour these faces.
if((cellIndex & Face0123) != 0 && (cellIndex & Face0123) != Face0123){
contourFace(cellIndex, threshold, 0, 1, 2, 3, 0, 1, 2, 3);
}
if((cellIndex & Face0154) != 0 && (cellIndex & Face0154) != Face0154){
contourFace(cellIndex, threshold, 0, 1, 5, 4, 0, 9, 4, 8);
}
if((cellIndex & Face0374) != 0 && (cellIndex & Face0374) != Face0374){
contourFace(cellIndex, threshold, 0, 3, 7, 4, 3, 11, 7, 8);
}
// these are the end faces along each dimension.
// little point checking they need contouring before calling
if(i == iDim2){
contourFace(cellIndex, threshold, 4, 5, 6, 7, 4, 5, 6, 7);
}
if(j == jDim2){
contourFace(cellIndex, threshold, 1, 2, 6, 5, 1, 10, 5, 9);
}
if(layer == kDim2){
contourFace(cellIndex, threshold, 2, 3, 7, 6, 2, 11, 6, 10);
}
}
}
/* Copy over cell values in direction of i. */
cell[0] = cell[4];
cell[1] = cell[5];
cell[2] = cell[6];
cell[3] = cell[7];
/* sort out cellIndex. */
cellIndex = (cellIndex >>> 4);
}
}
}
/** Add edges for one face. */
private static void contourFace(int cellIndex, float level,
int v0, int v1, int v2, int v3,
int e0, int e1, int e2, int e3){
// build mask for this face.
int faceIndex = 0;
if((cellIndex & (1<<v0)) != 0) faceIndex |= 1;
if((cellIndex & (1<<v1)) != 0) faceIndex |= 2;
if((cellIndex & (1<<v2)) != 0) faceIndex |= 4;
if((cellIndex & (1<<v3)) != 0) faceIndex |= 8;
switch(faceIndex){
case 0: case 15: // nothing
break;
case 1: case 14:
tmesh.addLine(cellVerts[e3], cellVerts[e0], faceIndex);
break;
case 2: case 13:
tmesh.addLine(cellVerts[e0], cellVerts[e1], faceIndex);
break;
case 4: case 11:
tmesh.addLine(cellVerts[e1], cellVerts[e2], faceIndex);
break;
case 8: case 7:
tmesh.addLine(cellVerts[e2], cellVerts[e3], faceIndex);
break;
case 3: case 12:
tmesh.addLine(cellVerts[e1], cellVerts[e3], faceIndex);
break;
case 6: case 9:
tmesh.addLine(cellVerts[e0], cellVerts[e2], faceIndex);
break;
case 5: case 10:
// needs to take account of center value
double mean = 0.25 * (cell[v0] + cell[v1] + cell[v2] + cell[v3]);
// check which side the mean is on relative to one corner
if(mean > level == cell[v0] > level){
tmesh.addLine(cellVerts[e0], cellVerts[e1], faceIndex);
tmesh.addLine(cellVerts[e2], cellVerts[e3], faceIndex);
}else{
tmesh.addLine(cellVerts[e0], cellVerts[e3], faceIndex);
tmesh.addLine(cellVerts[e1], cellVerts[e2], faceIndex);
}
break;
default:
Log.error("unhandled faceIndex %d", faceIndex);
}
}
/** Retrieve offset as if a 3D array. */
private static int getOffset(int i, int j, int k){
return(i + iDim * j + ngrid01 * k);
}
/** Adds a vertex to the list. */
private static void addVertex(float data[], int edgeNum, int i, int j,
float threshold,
int cellVerts[], int layer){
/* Get the edge vertex. */
int edgeOffset = getEdgeOffset(edgeNum, i, j);
if(layerEdges[edgeOffset] == emptyEdge){
cellVerts[edgeNum] = makeVertex(data, edgeNum, i, j, layer, threshold);
} else {
cellVerts[edgeNum] = layerEdges[edgeOffset];
}
}
/** Returns the offset for edge lookup */
private static int getEdgeOffset(int edgeNum, int i, int j){
int off = edgeNum + (12 * i) + nedge01 * j;
return (off);
}
private static int from[] = new int[3];
private static int to[] = new int[3];
private static float normFrom[] = new float[3];
private static float normTo[] = new float[3];
private static float v[] = new float[3];
private static float n[] = new float[3];
/** Creates a vertex */
private static int makeVertex(float data[], int edgeNum,
int i, int j, int k, float threshold){
float d;
float len;
float localData[] = data;
switch(edgeNum){
case 0:
from[0] = i; from[1] = j; from[2] = k;
to[0] = i; to[1] = j+1; to[2] = k;
break;
case 1:
from[0] = i; from[1] = j+1; from[2] = k;
to[0] = i; to[1] = j+1; to[2] = k+1;
break;
case 2:
from[0] = i; from[1] = j+1; from[2] = k+1;
to[0] = i; to[1] = j; to[2] = k+1;
break;
case 3:
from[0] = i; from[1] = j; from[2] = k;
to[0] = i; to[1] = j; to[2] = k+1;
break;
case 4:
from[0] = i+1; from[1] = j; from[2] = k;
to[0] = i+1; to[1] = j+1; to[2] = k;
break;
case 5:
from[0] = i+1; from[1] = j+1; from[2] = k;
to[0] = i+1; to[1] = j+1; to[2] = k+1;
break;
case 6:
from[0] = i+1; from[1] = j+1; from[2] = k+1;
to[0] = i+1; to[1] = j; to[2] = k+1;
break;
case 7:
from[0] = i+1; from[1] = j; from[2] = k;
to[0] = i+1; to[1] = j; to[2] = k+1;
break;
case 8:
from[0] = i; from[1] = j; from[2] = k;
to[0] = i+1; to[1] = j; to[2] = k;
break;
case 9:
from[0] = i; from[1] = j+1; from[2] = k;
to[0] = i+1; to[1] = j+1; to[2] = k;
break;
case 10:
from[0] = i; from[1] = j+1; from[2] = k+1;
to[0] = i+1; to[1] = j+1; to[2] = k+1;
break;
case 11:
from[0] = i; from[1] = j; from[2] = k+1;
to[0] = i+1; to[1] = j; to[2] = k+1;
break;
default:
System.out.println("makeVertex: bad edge index " + edgeNum);
System.exit(2);
break;
}
int fromLookup = getOffset(from[0], from[1], from[2]);
int toLookup = getOffset(to[0], to[1], to[2]);
float fromValue = localData[fromLookup];
float toValue = localData[toLookup];
/* Calculate the relative distance from -> to. */
d = (fromValue - threshold) /
(fromValue - toValue);
if(d < epsilon){
d = 0.0f;
} else if(d > (1 - epsilon)){
d = 1.0f;
}
v[0] = from[0] + d * (to[0] - from[0]);
v[1] = from[1] + d * (to[1] - from[1]);
v[2] = from[2] + d * (to[2] - from[2]);
if(generateTriangles){
/* Determine the gradients at the endpoints of the edge
and interpolate the normal for the isosurface vertex. */
if(from[0] == 0){ /* On left edge. */
normFrom[0] = 0.5f * (-3.0f * localData[fromLookup] +
4.0f * localData[fromLookup + 1] -
localData[fromLookup + 2]);
}else if(from[0] == iDim1){ /* On right edge. */
normFrom[0] = 0.5f * (localData[fromLookup - 2] -
4.0f * localData[fromLookup - 1] +
3.0f * localData[fromLookup]);
}else{ /* In the interior. */
normFrom[0] = 0.5f * (localData[fromLookup + 1] -
localData[fromLookup - 1]);
}
if(from[1] == 0){ /* On front edge. */
normFrom[1] = 0.5f * (-3.0f * localData[fromLookup] +
4.0f * localData[fromLookup + iDim] -
localData[fromLookup + (2 * iDim)]);
}else if(from[1] == jDim1){ /* On back edge. */
normFrom[1] = 0.5f * (localData[fromLookup - (2 * iDim)] -
4.0f * localData[fromLookup - iDim] +
3.0f * localData[fromLookup]);
}else{ /* In the interior. */
normFrom[1] = 0.5f * (localData[fromLookup + iDim] -
localData[fromLookup - iDim]);
}
if(from[2] == 0){ /* On bottom edge. */
normFrom[2] = 0.5f * (-3.0f * localData[fromLookup] +
4.0f * localData[fromLookup + ijDim] -
localData[fromLookup + (2 * ijDim)]);
}else if(from[2] == kDim1){ /* On top edge. */
normFrom[2] = 0.5f * (localData[fromLookup - (2 * ijDim)] -
4.0f * localData[fromLookup - ijDim] +
3.0f * localData[fromLookup]);
}else{ /* In the interior. */
normFrom[2] = 0.5f * (localData[fromLookup + ijDim] -
localData[fromLookup - ijDim]);
}
/* Normal for to vertex. */
if(to[0] == 0){ /* On left edge. */
normTo[0] = 0.5f * (-3.0f * localData[toLookup] +
4.0f * localData[toLookup + 1] -
localData[toLookup + 2]);
}else if(to[0] == iDim1){ /* On right edge. */
normTo[0] = 0.5f * (localData[toLookup - 1] -
4.0f * localData[toLookup - 1] +
3.0f * localData[toLookup]);
}else{ /* In the interior. */
normTo[0] = 0.5f * (localData[toLookup + 1] -
localData[toLookup - 1]);
}
if(to[1] == 0){ /* On front edge. */
normTo[1] = 0.5f * ( -3.0f * localData[toLookup] +
4.0f * localData[toLookup + iDim] -
localData[toLookup + (2 * iDim)]);
}else if(to[1] == jDim1){ /* On back edge. */
normTo[1] = 0.5f * ( localData[toLookup - (2 * iDim)] -
4.0f * localData[toLookup - iDim] +
3.0f * localData[toLookup]);
}else{ /* In the interior. */
normTo[1] = 0.5f * ( localData[toLookup + iDim] -
localData[toLookup - iDim]);
}
if(to[2] == 0){ /* On bottom edge. */
normTo[2] = 0.5f * ( -3.0f * localData[toLookup] +
4.0f * localData[toLookup + ijDim] -
localData[toLookup + (2 * ijDim)]);
}else if(to[2] == kDim1){ /* On top edge. */
normTo[2] = 0.5f * ( localData[toLookup - (2 * ijDim)] -
4.0f * localData[toLookup - ijDim] +
3.0f * localData[toLookup]);
}else{ /* In the interior. */
normTo[2] = 0.5f * ( localData[toLookup + ijDim] -
localData[toLookup - ijDim]);
}
/* Now that we have the normals at the two endpoints, interpolate */
n[0] = normFrom[0] + d * (normTo[0] - normFrom[0]);
n[1] = normFrom[1] + d * (normTo[1] - normFrom[1]);
n[2] = normFrom[2] + d * (normTo[2] - normFrom[2]);
/* Normalize the normal at the isosurface vertex */
len = (float)Math.sqrt(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]);
if(len > epsilon){
n[0] /= len;
n[1] /= len;
n[2] /= len;
}else{ /* We have to fake this normal. */
n[0] = 1.0f;
n[1] = 0.0f;
n[2] = 0.0f;
}
}
/* Insert the vertex and the normal into the Tmesh object. */
tmesh.addPoint(v[0], v[1], v[2], -n[0], -n[1], -n[2], 0, 0);
/* Return the array reference of the vertex. */
return (tmesh.getnPoints() - 1);
}
/** Edge table lookup.
these tables for computing the Marching Cubes algorithm
are from http://www.mhri.edu.au/~pdb/modelling/polygonise/
by Paul Bourke, based on code by Cory Gene Bloyd.
The indexing of vertices and edges in a cube are defined
as:
_4____________4_____________5
/| /
/ | /|
/ | / |
7 | / |
/ | /5 |
/ | / |
/ 8 / 9
/ | / |
7/________|______6____________/6 |
| | | |
| | | |
| | | |
| |0____________0_____|_______|1
11 / | /
| / 10 /
| / | /
| /3 | /1
| / | /
| / | /
| / |/
|/3____________2_____________|2
For purposes of calculating vertices along the edges and the
triangulations created, there are 15 distinct cases, with
upper limits of
12 edge intersections
5 triangles created per cell
*/
// changed from int -> char
private static final char edgeTable[] = {
0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c,
0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac,
0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c,
0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc,
0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c,
0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc ,
0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460,
0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0,
0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230,
0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190,
0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0
};
// changed from int -> byte
private static final byte triTable[][] = {
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
{3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
{3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
{3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
{9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
{9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
{2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
{8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
{9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
{4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
{3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
{1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
{4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
{4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
{5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
{2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
{9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
{0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
{2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
{10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
{5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
{5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
{9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
{0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
{1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
{10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
{8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
{2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
{7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
{2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
{11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
{5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
{11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
{11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
{1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
{9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
{5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
{2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
{5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
{6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
{3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
{6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
{5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
{1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
{10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
{6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
{8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
{7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
{3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
{5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
{0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
{9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
{8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
{5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
{0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
{6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
{10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
{10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
{8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
{1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
{0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
{10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
{3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
{6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
{9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
{8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
{3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
{6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
{0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
{10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
{10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
{2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
{7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
{7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
{2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
{1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
{11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
{8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
{0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
{7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
{10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
{2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
{6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
{7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
{2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
{1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
{10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
{10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
{0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
{7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
{6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
{8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
{9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
{6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
{4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
{10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
{8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
{0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
{1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
{8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
{10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
{4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
{10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
{5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
{11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
{9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
{6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
{7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
{3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
{7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
{3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
{6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
{9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
{1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
{4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
{7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
{6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
{3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
{0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
{6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
{0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
{11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
{6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
{5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
{9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
{1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
{1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
{10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
{0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
{5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
{10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
{11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
{9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
{7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
{2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
{8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
{9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
{9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
{1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
{9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
{9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
{5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
{0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
{10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
{2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
{0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
{0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
{9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
{5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
{3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
{5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
{8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
{0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
{9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
{1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
{3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
{4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
{9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
{11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
{11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
{2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
{9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
{3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
{1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
{4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
{3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
{0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
{9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
{1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
};
}