
org.scijava.ops.image.geom.geom3d.DefaultMarchingCubes Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scijava-ops-image Show documentation
Show all versions of scijava-ops-image Show documentation
Image processing operations for SciJava Ops.
The newest version!
/*
* #%L
* Image processing operations for SciJava Ops.
* %%
* Copyright (C) 2014 - 2024 SciJava developers.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.ops.image.geom.geom3d;
import net.imglib2.Cursor;
import net.imglib2.FinalInterval;
import net.imglib2.RandomAccessibleInterval;
import net.imglib2.mesh.Mesh;
import net.imglib2.mesh.impl.naive.NaiveDoubleMesh;
import net.imglib2.type.BooleanType;
import net.imglib2.type.logic.BoolType;
import net.imglib2.view.ExtendedRandomAccessibleInterval;
import net.imglib2.view.Views;
import org.apache.commons.math3.util.MathArrays;
import org.scijava.function.Functions;
import org.scijava.ops.spi.Nullable;
/**
* This is a marching cubes implementation. It is inspired by Paul Bourke's
* (http://paulbourke.net/geometry/polygonise/) implementation. Especially the
* lookup tables are from his implementation.
*
* @author Tim-Oliver Buchholz (University of Konstanz)
* @param BooleanType
* @implNote op names='geom.marchingCubes'
*/
public class DefaultMarchingCubes> implements
Functions.Arity3, Double, VertexInterpolator, Mesh>
{
private double isolevel;
private VertexInterpolator interpolatorClass;
/**
* TODO
*
* @param input
* @param isolevel
* @param interpolatorClass
* @return the output
*/
@Override
@SuppressWarnings({ "unchecked" })
public Mesh apply(final RandomAccessibleInterval input,
@Nullable Double isolevel, @Nullable VertexInterpolator interpolatorClass)
{
// ensure validity of inputs
if (input.numDimensions() != 3) throw new IllegalArgumentException(
"Only three-dimensional inputs are supported!");
if (isolevel == null) this.isolevel = 1;
if (interpolatorClass == null) this.interpolatorClass =
new DefaultVertexInterpolator();
Mesh output = new NaiveDoubleMesh();
ExtendedRandomAccessibleInterval> extended =
Views.extendValue(input, (T) new BoolType(false));
Cursor c = Views.interval(extended, new FinalInterval(new long[] { input
.min(0) - 1, input.min(1) - 1, input.min(2) - 1 }, new long[] { input.max(
0) + 1, input.max(1) + 1, input.max(2) + 1 })).localizingCursor();
while (c.hasNext()) {
c.next();
int cursorX = c.getIntPosition(0);
int cursorY = c.getIntPosition(1);
int cursorZ = c.getIntPosition(2);
Cursor cu = getCube(extended, cursorX, cursorY, cursorZ);
int i = 0;
double[] vertex_values = new double[8];
while (cu.hasNext()) {
vertex_values[i++] = (cu.next().get()) ? 1 : 0;
}
// 6------7
// /| /|
// 2-----3 |
// | 4---|-5
// |/ |/
// 0-----1
vertex_values = mapFlatIterableToLookUpCube(vertex_values);
// 4------5
// /| /|
// 7-----6 |
// | 0---|-1
// |/ |/
// 3-----2
int cubeindex = getCubeIndex(vertex_values);
if (EDGE_TABLE[cubeindex] != 0) {
int[] p0 = new int[] { 0 + cursorX, 0 + cursorY, 1 + cursorZ };
int[] p1 = new int[] { 1 + cursorX, 0 + cursorY, 1 + cursorZ };
int[] p2 = new int[] { 1 + cursorX, 0 + cursorY, 0 + cursorZ };
int[] p3 = new int[] { 0 + cursorX, 0 + cursorY, 0 + cursorZ };
int[] p4 = new int[] { 0 + cursorX, 1 + cursorY, 1 + cursorZ };
int[] p5 = new int[] { 1 + cursorX, 1 + cursorY, 1 + cursorZ };
int[] p6 = new int[] { 1 + cursorX, 1 + cursorY, 0 + cursorZ };
int[] p7 = new int[] { 0 + cursorX, 1 + cursorY, 0 + cursorZ };
double[][] vertlist = new double[12][];
/* Find the vertices where the surface intersects the cube */
if (0 != (EDGE_TABLE[cubeindex] & 1)) {
vertlist[0] = interpolatePoint(p0, p1, vertex_values[0],
vertex_values[1]);
}
if (0 != (EDGE_TABLE[cubeindex] & 2)) {
vertlist[1] = interpolatePoint(p1, p2, vertex_values[1],
vertex_values[2]);
}
if (0 != (EDGE_TABLE[cubeindex] & 4)) {
vertlist[2] = interpolatePoint(p2, p3, vertex_values[2],
vertex_values[3]);
}
if (0 != (EDGE_TABLE[cubeindex] & 8)) {
vertlist[3] = interpolatePoint(p3, p0, vertex_values[3],
vertex_values[0]);
}
if (0 != (EDGE_TABLE[cubeindex] & 16)) {
vertlist[4] = interpolatePoint(p4, p5, vertex_values[4],
vertex_values[5]);
}
if (0 != (EDGE_TABLE[cubeindex] & 32)) {
vertlist[5] = interpolatePoint(p5, p6, vertex_values[5],
vertex_values[6]);
}
if (0 != (EDGE_TABLE[cubeindex] & 64)) {
vertlist[6] = interpolatePoint(p6, p7, vertex_values[6],
vertex_values[7]);
}
if (0 != (EDGE_TABLE[cubeindex] & 128)) {
vertlist[7] = interpolatePoint(p7, p4, vertex_values[7],
vertex_values[4]);
}
if (0 != (EDGE_TABLE[cubeindex] & 256)) {
vertlist[8] = interpolatePoint(p0, p4, vertex_values[0],
vertex_values[4]);
}
if (0 != (EDGE_TABLE[cubeindex] & 512)) {
vertlist[9] = interpolatePoint(p1, p5, vertex_values[1],
vertex_values[5]);
}
if (0 != (EDGE_TABLE[cubeindex] & 1024)) {
vertlist[10] = interpolatePoint(p2, p6, vertex_values[2],
vertex_values[6]);
}
if (0 != (EDGE_TABLE[cubeindex] & 2048)) {
vertlist[11] = interpolatePoint(p3, p7, vertex_values[3],
vertex_values[7]);
}
/* Create the triangle */
for (i = 0; TRIANGLE_TABLE[cubeindex][i] != -1; i += 3) {
final double v0x = vertlist[TRIANGLE_TABLE[cubeindex][i + 2]][0];
final double v0y = vertlist[TRIANGLE_TABLE[cubeindex][i + 2]][1];
final double v0z = vertlist[TRIANGLE_TABLE[cubeindex][i + 2]][2];
final double v1x = vertlist[TRIANGLE_TABLE[cubeindex][i + 1]][0];
final double v1y = vertlist[TRIANGLE_TABLE[cubeindex][i + 1]][1];
final double v1z = vertlist[TRIANGLE_TABLE[cubeindex][i + 1]][2];
final double v2x = vertlist[TRIANGLE_TABLE[cubeindex][i]][0];
final double v2y = vertlist[TRIANGLE_TABLE[cubeindex][i]][1];
final double v2z = vertlist[TRIANGLE_TABLE[cubeindex][i]][2];
if (positiveArea(v0x, v0y, v0z, v1x, v1y, v1z, v2x, v2y, v2z)) {
output.triangles().add(v0x, v0y, v0z, v1x, v1y, v1z, v2x, v2y, v2z);
}
}
}
}
return output;
}
private boolean positiveArea(double v0x, double v0y, double v0z, //
double v1x, double v1y, double v1z, //
double v2x, double v2y, double v2z)
{
final double p1x = v0x - v1x;
final double p1y = v0y - v1y;
final double p1z = v0z - v1z;
final double p2x = v2x - v0x;
final double p2y = v2y - v0y;
final double p2z = v2z - v0z;
// cross product
final double cpx = MathArrays.linearCombination(p1y, p2z, -p1z, p2y);
final double cpy = MathArrays.linearCombination(p1z, p2x, -p1x, p2z);
final double cpz = MathArrays.linearCombination(p1x, p2y, -p1y, p2x);
return cpx != 0 || cpy != 0 || cpz != 0;
}
private double[] interpolatePoint(int[] p0, int[] p1, double v0, double v1) {
this.interpolatorClass.setPoint1(p0);
this.interpolatorClass.setPoint2(p1);
this.interpolatorClass.setValue1(v0);
this.interpolatorClass.setValue2(v1);
this.interpolatorClass.setIsoLevel(this.isolevel);
this.interpolatorClass.run();
return this.interpolatorClass.getOutput();
}
private int getCubeIndex(final double[] vertex_values) {
int cubeindex = 0;
for (int i = 0; i < 8; i++) {
if (vertex_values[i] < this.isolevel) {
cubeindex |= (int) Math.pow(2, i);
}
}
return cubeindex;
}
private double[] mapFlatIterableToLookUpCube(final double[] vertex_values) {
double[] vv = new double[8];
vv[0] = vertex_values[4];
vv[1] = vertex_values[5];
vv[2] = vertex_values[1];
vv[3] = vertex_values[0];
vv[4] = vertex_values[6];
vv[5] = vertex_values[7];
vv[6] = vertex_values[3];
vv[7] = vertex_values[2];
return vv;
}
private Cursor getCube(
final ExtendedRandomAccessibleInterval> extended,
final int cursorX, final int cursorY, final int cursorZ)
{
return Views.flatIterable(Views.interval(extended, new FinalInterval(
new long[] { cursorX, cursorY, cursorZ }, new long[] { cursorX + 1,
cursorY + 1, cursorZ + 1 }))).cursor();
}
// For any edge, if one vertex is inside of the surface and the other is
// outside of the surface
// then the edge intersects the surface
// For each of the 8 vertices of the cube can be two possible states :
// either inside or outside of the surface
// For any cube the are 2^8=256 possible sets of vertex states
// This table lists the edges intersected by the surface for all 256
// possible vertex states
// There are 12 edges. For each entry in the table, if edge #n is
// intersected, then bit #n is set to 1
// This table is from Paul Bourke's
// (http://paulbourke.net/geometry/polygonise/)
// Marching Cubes implementation.
private static final int[] EDGE_TABLE = new int[] { 0x000, 0x109, 0x203,
0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03,
0xe09, 0xf00, 0x190, 0x099, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c,
0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, 0x230, 0x339, 0x033, 0x13a,
0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39,
0xd30, 0x3a0, 0x2a9, 0x1a3, 0x0aa, 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5,
0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, 0x460, 0x569, 0x663, 0x76a, 0x066,
0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0x0ff, 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff,
0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f,
0x055, 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, 0x7c0,
0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0x0cc, 0xfcc, 0xec5, 0xdcf, 0xcc6,
0xbca, 0xac3, 0x9c9, 0x8c0, 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5,
0xfcc, 0x0cc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, 0x950, 0x859,
0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x055, 0x35f, 0x256, 0x55a,
0x453, 0x759, 0x650, 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
0x2fc, 0x3f5, 0x0ff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, 0xb60, 0xa69, 0x963,
0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x066, 0x76a, 0x663,
0x569, 0x460, 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac,
0x5a5, 0x6af, 0x7a6, 0x0aa, 0x1a3, 0x2a9, 0x3a0, 0xd30, 0xc39, 0xf33, 0xe3a,
0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x033, 0x339,
0x230, 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795,
0x49f, 0x596, 0x29a, 0x393, 0x099, 0x190, 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06,
0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109,
0x000 };
// For each of the possible cube state there is a specific triangulation
// of the edge intersection points. This table lists all of
// them in the form of
// 0-5 edge triples with the list terminated by the invalid value -1.
// For example: TRIANGLE_TABLE[3] list the 2 triangles formed
// when corner[0]
// and corner[1] are inside of the surface, but the rest of the cube is not.
//
// This table is from Paul Bourke's
// (http://paulbourke.net/geometry/polygonise/)
// Marching Cubes implementation.
private static final int[][] TRIANGLE_TABLE = new int[][] { { -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 } };
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy