From ff1d39c93450ea8e460b9142ed6c4ffa4bf184f9 Mon Sep 17 00:00:00 2001 From: mattijs <mattijs> Date: Wed, 29 Feb 2012 14:41:22 +0000 Subject: [PATCH] ENH: cvMeshSurfaceSimplify: new cvMesh utility to output the surface --- .../utilities/mesh/generation/cvMesh/Allwmake | 1 + .../cvMesh/cvMeshSurfaceSimplify/Make/files | 6 + .../cvMesh/cvMeshSurfaceSimplify/Make/options | 17 + .../MarchingCubes/LookUpTable.h | 2322 ++++++++++++ .../MarchingCubes/MarchingCubes.cpp | 1302 +++++++ .../MarchingCubes/MarchingCubes.h | 343 ++ .../cvMeshSurfaceSimplify/MarchingCubes/ply.c | 3325 +++++++++++++++++ .../cvMeshSurfaceSimplify/MarchingCubes/ply.h | 233 ++ .../cvMeshSurfaceSimplify.C | 350 ++ .../marching_cubes_jgt.zip | Bin 0 -> 170157 bytes 10 files changed, 7899 insertions(+) create mode 100644 applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/Make/files create mode 100644 applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/Make/options create mode 100755 applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/LookUpTable.h create mode 100755 applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/MarchingCubes.cpp create mode 100755 applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/MarchingCubes.h create mode 100755 applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/ply.c create mode 100755 applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/ply.h create mode 100644 applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/cvMeshSurfaceSimplify.C create mode 100644 applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/marching_cubes_jgt.zip diff --git a/applications/utilities/mesh/generation/cvMesh/Allwmake b/applications/utilities/mesh/generation/cvMesh/Allwmake index 688b3be475c..f059754bab6 100755 --- a/applications/utilities/mesh/generation/cvMesh/Allwmake +++ b/applications/utilities/mesh/generation/cvMesh/Allwmake @@ -4,5 +4,6 @@ set -x wmake libso conformalVoronoiMesh wmake +wmake cvMeshSurfaceSimplify # ----------------------------------------------------------------- end-of-file diff --git a/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/Make/files b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/Make/files new file mode 100644 index 00000000000..a0fcd8f0bf8 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/Make/files @@ -0,0 +1,6 @@ +cvMeshSurfaceSimplify.C + +MarchingCubes/MarchingCubes.cpp +MarchingCubes/ply.c + +EXE = $(FOAM_APPBIN)/cvMeshSurfaceSimplify diff --git a/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/Make/options b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/Make/options new file mode 100644 index 00000000000..1711b9ba615 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/Make/options @@ -0,0 +1,17 @@ +include $(GENERAL_RULES)/CGAL + +EXE_INC = \ + -IMarchingCubes \ + -I../conformalVoronoiMesh/lnInclude \ + -I$(LIB_SRC)/edgeMesh/lnInclude \ + -I$(LIB_SRC)/triSurface/lnInclude \ + -I$(LIB_SRC)/meshTools/lnInclude + +EXE_LIBS = \ + $(CGAL_LIBS) \ + -lconformalVoronoiMesh \ + -ldecompositionMethods -L$(FOAM_LIBBIN)/dummy -lscotchDecomp \ + -ledgeMesh \ + -ltriSurface \ + -lmeshTools \ + -ldynamicMesh diff --git a/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/LookUpTable.h b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/LookUpTable.h new file mode 100755 index 00000000000..5529346954a --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/LookUpTable.h @@ -0,0 +1,2322 @@ +/** + * @file LookUpTable.h + * @author Thomas Lewiner <thomas.lewiner@polytechnique.org> + * @author Math Dept, PUC-Rio + * @version 0.2 + * @date 12/08/2002 + * + * @brief LookUpTable for the MarchingCubes 33 Algorithm + */ +//________________________________________________ + + + +#ifndef _LOOKUPTABLE_H_ +#define _LOOKUPTABLE_H_ + + + + + +//_____________________________________________________________________________ +/** + * \brief case mapping + * For each of the possible vertex states listed in this table there is a + * specific triangulation of the edge intersection points. The table lists + * all of them in the form of 0-5 edge triples with the list terminated by + * the invalid value -1. For example: case[3] list the 2 triangles + * formed when cube[0] and cube[1] are inside of the surface, but the rest of + * the cube is not. + * + * Cube description: + * 7 ________ 6 _____6__ ________ + * /| /| 7/| /| /| /| + * / | / | / | /5 | / 6 / | + * 4 /_______ / | /__4____ / 10 /_______3/ | + * | | |5 | | 11 | | | | | 2 | + * | 3|__|_____|2 | |__|__2__| | 4 |__|_____| + * | / | / 8 3/ 9 / | / | / + * | / | / | / | /1 | / 5 / + * |/_______|/ |/___0___|/ |/_1_____|/ + * 0 1 0 1 + */ +//----------------------------------------------------------------------------- +static const char cases[256][2] = { +/* 0: */ { 0, -1 }, +/* 1: 0, */ { 1, 0 }, +/* 2: 1, */ { 1, 1 }, +/* 3: 0, 1, */ { 2, 0 }, +/* 4: 2, */ { 1, 2 }, +/* 5: 0, 2, */ { 3, 0 }, +/* 6: 1, 2, */ { 2, 3 }, +/* 7: 0, 1, 2, */ { 5, 0 }, +/* 8: 3, */ { 1, 3 }, +/* 9: 0, 3, */ { 2, 1 }, +/* 10: 1, 3, */ { 3, 3 }, +/* 11: 0, 1, 3, */ { 5, 1 }, +/* 12: 2, 3, */ { 2, 5 }, +/* 13: 0, 2, 3, */ { 5, 4 }, +/* 14: 1, 2, 3, */ { 5, 9 }, +/* 15: 0, 1, 2, 3, */ { 8, 0 }, +/* 16: 4, */ { 1, 4 }, +/* 17: 0, 4, */ { 2, 2 }, +/* 18: 1, 4, */ { 3, 4 }, +/* 19: 0, 1, 4, */ { 5, 2 }, +/* 20: 2, 4, */ { 4, 2 }, +/* 21: 0, 2, 4, */ { 6, 2 }, +/* 22: 1, 2, 4, */ { 6, 9 }, +/* 23: 0, 1, 2, 4, */ { 11, 0 }, +/* 24: 3, 4, */ { 3, 8 }, +/* 25: 0, 3, 4, */ { 5, 5 }, +/* 26: 1, 3, 4, */ { 7, 3 }, +/* 27: 0, 1, 3, 4, */ { 9, 1 }, +/* 28: 2, 3, 4, */ { 6, 16 }, +/* 29: 0, 2, 3, 4, */ { 14, 3 }, +/* 30: 1, 2, 3, 4, */ { 12, 12 }, +/* 31: 0, 1, 2, 3, 4, */ { 5, 24 }, +/* 32: 5, */ { 1, 5 }, +/* 33: 0, 5, */ { 3, 1 }, +/* 34: 1, 5, */ { 2, 4 }, +/* 35: 0, 1, 5, */ { 5, 3 }, +/* 36: 2, 5, */ { 3, 6 }, +/* 37: 0, 2, 5, */ { 7, 0 }, +/* 38: 1, 2, 5, */ { 5, 10 }, +/* 39: 0, 1, 2, 5, */ { 9, 0 }, +/* 40: 3, 5, */ { 4, 3 }, +/* 41: 0, 3, 5, */ { 6, 4 }, +/* 42: 1, 3, 5, */ { 6, 11 }, +/* 43: 0, 1, 3, 5, */ { 14, 1 }, +/* 44: 2, 3, 5, */ { 6, 17 }, +/* 45: 0, 2, 3, 5, */ { 12, 4 }, +/* 46: 1, 2, 3, 5, */ { 11, 6 }, +/* 47: 0, 1, 2, 3, 5, */ { 5, 25 }, +/* 48: 4, 5, */ { 2, 8 }, +/* 49: 0, 4, 5, */ { 5, 7 }, +/* 50: 1, 4, 5, */ { 5, 12 }, +/* 51: 0, 1, 4, 5, */ { 8, 1 }, +/* 52: 2, 4, 5, */ { 6, 18 }, +/* 53: 0, 2, 4, 5, */ { 12, 5 }, +/* 54: 1, 2, 4, 5, */ { 14, 7 }, +/* 55: 0, 1, 2, 4, 5, */ { 5, 28 }, +/* 56: 3, 4, 5, */ { 6, 21 }, +/* 57: 0, 3, 4, 5, */ { 11, 4 }, +/* 58: 1, 3, 4, 5, */ { 12, 15 }, +/* 59: 0, 1, 3, 4, 5, */ { 5, 30 }, +/* 60: 2, 3, 4, 5, */ { 10, 5 }, +/* 61: 0, 2, 3, 4, 5, */ { 6, 32 }, +/* 62: 1, 2, 3, 4, 5, */ { 6, 39 }, +/* 63: 0, 1, 2, 3, 4, 5, */ { 2, 12 }, +/* 64: 6, */ { 1, 6 }, +/* 65: 0, 6, */ { 4, 0 }, +/* 66: 1, 6, */ { 3, 5 }, +/* 67: 0, 1, 6, */ { 6, 0 }, +/* 68: 2, 6, */ { 2, 6 }, +/* 69: 0, 2, 6, */ { 6, 3 }, +/* 70: 1, 2, 6, */ { 5, 11 }, +/* 71: 0, 1, 2, 6, */ { 14, 0 }, +/* 72: 3, 6, */ { 3, 9 }, +/* 73: 0, 3, 6, */ { 6, 5 }, +/* 74: 1, 3, 6, */ { 7, 4 }, +/* 75: 0, 1, 3, 6, */ { 12, 1 }, +/* 76: 2, 3, 6, */ { 5, 14 }, +/* 77: 0, 2, 3, 6, */ { 11, 3 }, +/* 78: 1, 2, 3, 6, */ { 9, 4 }, +/* 79: 0, 1, 2, 3, 6, */ { 5, 26 }, +/* 80: 4, 6, */ { 3, 10 }, +/* 81: 0, 4, 6, */ { 6, 6 }, +/* 82: 1, 4, 6, */ { 7, 5 }, +/* 83: 0, 1, 4, 6, */ { 12, 2 }, +/* 84: 2, 4, 6, */ { 6, 19 }, +/* 85: 0, 2, 4, 6, */ { 10, 1 }, +/* 86: 1, 2, 4, 6, */ { 12, 13 }, +/* 87: 0, 1, 2, 4, 6, */ { 6, 24 }, +/* 88: 3, 4, 6, */ { 7, 7 }, +/* 89: 0, 3, 4, 6, */ { 12, 9 }, +/* 90: 1, 3, 4, 6, */ { 13, 1 }, +/* 91: 0, 1, 3, 4, 6, */ { 7, 9 }, +/* 92: 2, 3, 4, 6, */ { 12, 20 }, +/* 93: 0, 2, 3, 4, 6, */ { 6, 33 }, +/* 94: 1, 2, 3, 4, 6, */ { 7, 13 }, +/* 95: 0, 1, 2, 3, 4, 6, */ { 3, 12 }, +/* 96: 5, 6, */ { 2, 10 }, +/* 97: 0, 5, 6, */ { 6, 7 }, +/* 98: 1, 5, 6, */ { 5, 13 }, +/* 99: 0, 1, 5, 6, */ { 11, 2 }, +/* 100: 2, 5, 6, */ { 5, 16 }, +/* 101: 0, 2, 5, 6, */ { 12, 7 }, +/* 102: 1, 2, 5, 6, */ { 8, 3 }, +/* 103: 0, 1, 2, 5, 6, */ { 5, 29 }, +/* 104: 3, 5, 6, */ { 6, 22 }, +/* 105: 0, 3, 5, 6, */ { 10, 2 }, +/* 106: 1, 3, 5, 6, */ { 12, 17 }, +/* 107: 0, 1, 3, 5, 6, */ { 6, 27 }, +/* 108: 2, 3, 5, 6, */ { 14, 9 }, +/* 109: 0, 2, 3, 5, 6, */ { 6, 34 }, +/* 110: 1, 2, 3, 5, 6, */ { 5, 39 }, +/* 111: 0, 1, 2, 3, 5, 6, */ { 2, 14 }, +/* 112: 4, 5, 6, */ { 5, 20 }, +/* 113: 0, 4, 5, 6, */ { 14, 5 }, +/* 114: 1, 4, 5, 6, */ { 9, 5 }, +/* 115: 0, 1, 4, 5, 6, */ { 5, 32 }, +/* 116: 2, 4, 5, 6, */ { 11, 10 }, +/* 117: 0, 2, 4, 5, 6, */ { 6, 35 }, +/* 118: 1, 2, 4, 5, 6, */ { 5, 41 }, +/* 119: 0, 1, 2, 4, 5, 6, */ { 2, 16 }, +/* 120: 3, 4, 5, 6, */ { 12, 23 }, +/* 121: 0, 3, 4, 5, 6, */ { 6, 37 }, +/* 122: 1, 3, 4, 5, 6, */ { 7, 14 }, +/* 123: 0, 1, 3, 4, 5, 6, */ { 3, 16 }, +/* 124: 2, 3, 4, 5, 6, */ { 6, 46 }, +/* 125: 0, 2, 3, 4, 5, 6, */ { 4, 6 }, +/* 126: 1, 2, 3, 4, 5, 6, */ { 3, 21 }, +/* 127: 0, 1, 2, 3, 4, 5, 6, */ { 1, 8 }, +/* 128: 7, */ { 1, 7 }, +/* 129: 0, 7, */ { 3, 2 }, +/* 130: 1, 7, */ { 4, 1 }, +/* 131: 0, 1, 7, */ { 6, 1 }, +/* 132: 2, 7, */ { 3, 7 }, +/* 133: 0, 2, 7, */ { 7, 1 }, +/* 134: 1, 2, 7, */ { 6, 10 }, +/* 135: 0, 1, 2, 7, */ { 12, 0 }, +/* 136: 3, 7, */ { 2, 7 }, +/* 137: 0, 3, 7, */ { 5, 6 }, +/* 138: 1, 3, 7, */ { 6, 12 }, +/* 139: 0, 1, 3, 7, */ { 11, 1 }, +/* 140: 2, 3, 7, */ { 5, 15 }, +/* 141: 0, 2, 3, 7, */ { 9, 2 }, +/* 142: 1, 2, 3, 7, */ { 14, 6 }, +/* 143: 0, 1, 2, 3, 7, */ { 5, 27 }, +/* 144: 4, 7, */ { 2, 9 }, +/* 145: 0, 4, 7, */ { 5, 8 }, +/* 146: 1, 4, 7, */ { 6, 13 }, +/* 147: 0, 1, 4, 7, */ { 14, 2 }, +/* 148: 2, 4, 7, */ { 6, 20 }, +/* 149: 0, 2, 4, 7, */ { 12, 6 }, +/* 150: 1, 2, 4, 7, */ { 10, 3 }, +/* 151: 0, 1, 2, 4, 7, */ { 6, 25 }, +/* 152: 3, 4, 7, */ { 5, 18 }, +/* 153: 0, 3, 4, 7, */ { 8, 2 }, +/* 154: 1, 3, 4, 7, */ { 12, 16 }, +/* 155: 0, 1, 3, 4, 7, */ { 5, 31 }, +/* 156: 2, 3, 4, 7, */ { 11, 9 }, +/* 157: 0, 2, 3, 4, 7, */ { 5, 34 }, +/* 158: 1, 2, 3, 4, 7, */ { 6, 40 }, +/* 159: 0, 1, 2, 3, 4, 7, */ { 2, 13 }, +/* 160: 5, 7, */ { 3, 11 }, +/* 161: 0, 5, 7, */ { 7, 2 }, +/* 162: 1, 5, 7, */ { 6, 14 }, +/* 163: 0, 1, 5, 7, */ { 12, 3 }, +/* 164: 2, 5, 7, */ { 7, 6 }, +/* 165: 0, 2, 5, 7, */ { 13, 0 }, +/* 166: 1, 2, 5, 7, */ { 12, 14 }, +/* 167: 0, 1, 2, 5, 7, */ { 7, 8 }, +/* 168: 3, 5, 7, */ { 6, 23 }, +/* 169: 0, 3, 5, 7, */ { 12, 10 }, +/* 170: 1, 3, 5, 7, */ { 10, 4 }, +/* 171: 0, 1, 3, 5, 7, */ { 6, 28 }, +/* 172: 2, 3, 5, 7, */ { 12, 21 }, +/* 173: 0, 2, 3, 5, 7, */ { 7, 10 }, +/* 174: 1, 2, 3, 5, 7, */ { 6, 41 }, +/* 175: 0, 1, 2, 3, 5, 7, */ { 3, 13 }, +/* 176: 4, 5, 7, */ { 5, 21 }, +/* 177: 0, 4, 5, 7, */ { 9, 3 }, +/* 178: 1, 4, 5, 7, */ { 11, 8 }, +/* 179: 0, 1, 4, 5, 7, */ { 5, 33 }, +/* 180: 2, 4, 5, 7, */ { 12, 22 }, +/* 181: 0, 2, 4, 5, 7, */ { 7, 11 }, +/* 182: 1, 2, 4, 5, 7, */ { 6, 42 }, +/* 183: 0, 1, 2, 4, 5, 7, */ { 3, 14 }, +/* 184: 3, 4, 5, 7, */ { 14, 11 }, +/* 185: 0, 3, 4, 5, 7, */ { 5, 36 }, +/* 186: 1, 3, 4, 5, 7, */ { 6, 44 }, +/* 187: 0, 1, 3, 4, 5, 7, */ { 2, 17 }, +/* 188: 2, 3, 4, 5, 7, */ { 6, 47 }, +/* 189: 0, 2, 3, 4, 5, 7, */ { 3, 18 }, +/* 190: 1, 2, 3, 4, 5, 7, */ { 4, 7 }, +/* 191: 0, 1, 2, 3, 4, 5, 7, */ { 1, 9 }, +/* 192: 6, 7, */ { 2, 11 }, +/* 193: 0, 6, 7, */ { 6, 8 }, +/* 194: 1, 6, 7, */ { 6, 15 }, +/* 195: 0, 1, 6, 7, */ { 10, 0 }, +/* 196: 2, 6, 7, */ { 5, 17 }, +/* 197: 0, 2, 6, 7, */ { 12, 8 }, +/* 198: 1, 2, 6, 7, */ { 11, 7 }, +/* 199: 0, 1, 2, 6, 7, */ { 6, 26 }, +/* 200: 3, 6, 7, */ { 5, 19 }, +/* 201: 0, 3, 6, 7, */ { 14, 4 }, +/* 202: 1, 3, 6, 7, */ { 12, 18 }, +/* 203: 0, 1, 3, 6, 7, */ { 6, 29 }, +/* 204: 2, 3, 6, 7, */ { 8, 4 }, +/* 205: 0, 2, 3, 6, 7, */ { 5, 35 }, +/* 206: 1, 2, 3, 6, 7, */ { 5, 40 }, +/* 207: 0, 1, 2, 3, 6, 7, */ { 2, 15 }, +/* 208: 4, 6, 7, */ { 5, 22 }, +/* 209: 0, 4, 6, 7, */ { 11, 5 }, +/* 210: 1, 4, 6, 7, */ { 12, 19 }, +/* 211: 0, 1, 4, 6, 7, */ { 6, 30 }, +/* 212: 2, 4, 6, 7, */ { 14, 10 }, +/* 213: 0, 2, 4, 6, 7, */ { 6, 36 }, +/* 214: 1, 2, 4, 6, 7, */ { 6, 43 }, +/* 215: 0, 1, 2, 4, 6, 7, */ { 4, 4 }, +/* 216: 3, 4, 6, 7, */ { 9, 7 }, +/* 217: 0, 3, 4, 6, 7, */ { 5, 37 }, +/* 218: 1, 3, 4, 6, 7, */ { 7, 15 }, +/* 219: 0, 1, 3, 4, 6, 7, */ { 3, 17 }, +/* 220: 2, 3, 4, 6, 7, */ { 5, 44 }, +/* 221: 0, 2, 3, 4, 6, 7, */ { 2, 19 }, +/* 222: 1, 2, 3, 4, 6, 7, */ { 3, 22 }, +/* 223: 0, 1, 2, 3, 4, 6, 7, */ { 1, 10 }, +/* 224: 5, 6, 7, */ { 5, 23 }, +/* 225: 0, 5, 6, 7, */ { 12, 11 }, +/* 226: 1, 5, 6, 7, */ { 14, 8 }, +/* 227: 0, 1, 5, 6, 7, */ { 6, 31 }, +/* 228: 2, 5, 6, 7, */ { 9, 6 }, +/* 229: 0, 2, 5, 6, 7, */ { 7, 12 }, +/* 230: 1, 2, 5, 6, 7, */ { 5, 42 }, +/* 231: 0, 1, 2, 5, 6, 7, */ { 3, 15 }, +/* 232: 3, 5, 6, 7, */ { 11, 11 }, +/* 233: 0, 3, 5, 6, 7, */ { 6, 38 }, +/* 234: 1, 3, 5, 6, 7, */ { 6, 45 }, +/* 235: 0, 1, 3, 5, 6, 7, */ { 4, 5 }, +/* 236: 2, 3, 5, 6, 7, */ { 5, 45 }, +/* 237: 0, 2, 3, 5, 6, 7, */ { 3, 19 }, +/* 238: 1, 2, 3, 5, 6, 7, */ { 2, 21 }, +/* 239: 0, 1, 2, 3, 5, 6, 7, */ { 1, 11 }, +/* 240: 4, 5, 6, 7, */ { 8, 5 }, +/* 241: 0, 4, 5, 6, 7, */ { 5, 38 }, +/* 242: 1, 4, 5, 6, 7, */ { 5, 43 }, +/* 243: 0, 1, 4, 5, 6, 7, */ { 2, 18 }, +/* 244: 2, 4, 5, 6, 7, */ { 5, 46 }, +/* 245: 0, 2, 4, 5, 6, 7, */ { 3, 20 }, +/* 246: 1, 2, 4, 5, 6, 7, */ { 2, 22 }, +/* 247: 0, 1, 2, 4, 5, 6, 7, */ { 1, 12 }, +/* 248: 3, 4, 5, 6, 7, */ { 5, 47 }, +/* 249: 0, 3, 4, 5, 6, 7, */ { 2, 20 }, +/* 250: 1, 3, 4, 5, 6, 7, */ { 3, 23 }, +/* 251: 0, 1, 3, 4, 5, 6, 7, */ { 1, 13 }, +/* 252: 2, 3, 4, 5, 6, 7, */ { 2, 23 }, +/* 253: 0, 2, 3, 4, 5, 6, 7, */ { 1, 14 }, +/* 254: 1, 2, 3, 4, 5, 6, 7, */ { 1, 15 }, +/* 255: 0, 1, 2, 3, 4, 5, 6, 7, */ { 0, -1 } +}; +//_____________________________________________________________________________ + + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 1 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling1[16][3] = { +/* 1: 0, */ { 0, 8, 3 }, +/* 2: 1, */ { 0, 1, 9 }, +/* 4: 2, */ { 1, 2, 10 }, +/* 8: 3, */ { 3, 11, 2 }, +/* 16: 4, */ { 4, 7, 8 }, +/* 32: 5, */ { 9, 5, 4 }, +/* 64: 6, */ { 10, 6, 5 }, +/* 128: 7, */ { 7, 6, 11 }, +/* 127: 0, 1, 2, 3, 4, 5, 6, */ { 7, 11, 6 }, +/* 191: 0, 1, 2, 3, 4, 5, 7, */ { 10, 5, 6 }, +/* 223: 0, 1, 2, 3, 4, 6, 7, */ { 9, 4, 5 }, +/* 239: 0, 1, 2, 3, 5, 6, 7, */ { 4, 8, 7 }, +/* 247: 0, 1, 2, 4, 5, 6, 7, */ { 3, 2, 11 }, +/* 251: 0, 1, 3, 4, 5, 6, 7, */ { 1, 10, 2 }, +/* 253: 0, 2, 3, 4, 5, 6, 7, */ { 0, 9, 1 }, +/* 254: 1, 2, 3, 4, 5, 6, 7, */ { 0, 3, 8 } +}; +//_____________________________________________________________________________ + + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 2 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling2[24][6] = { +/* 3: 0, 1, */ { 1, 8, 3, 9, 8, 1 }, +/* 9: 0, 3, */ { 0, 11, 2, 8, 11, 0 }, +/* 17: 0, 4, */ { 4, 3, 0, 7, 3, 4 }, +/* 6: 1, 2, */ { 9, 2, 10, 0, 2, 9 }, +/* 34: 1, 5, */ { 0, 5, 4, 1, 5, 0 }, +/* 12: 2, 3, */ { 3, 10, 1, 11, 10, 3 }, +/* 68: 2, 6, */ { 1, 6, 5, 2, 6, 1 }, +/* 136: 3, 7, */ { 7, 2, 3, 6, 2, 7 }, +/* 48: 4, 5, */ { 9, 7, 8, 5, 7, 9 }, +/* 144: 4, 7, */ { 6, 8, 4, 11, 8, 6 }, +/* 96: 5, 6, */ { 10, 4, 9, 6, 4, 10 }, +/* 192: 6, 7, */ { 11, 5, 10, 7, 5, 11 }, +/* 63: 0, 1, 2, 3, 4, 5, */ { 11, 10, 5, 7, 11, 5 }, +/* 159: 0, 1, 2, 3, 4, 7, */ { 10, 9, 4, 6, 10, 4 }, +/* 111: 0, 1, 2, 3, 5, 6, */ { 6, 4, 8, 11, 6, 8 }, +/* 207: 0, 1, 2, 3, 6, 7, */ { 9, 8, 7, 5, 9, 7 }, +/* 119: 0, 1, 2, 4, 5, 6, */ { 7, 3, 2, 6, 7, 2 }, +/* 187: 0, 1, 3, 4, 5, 7, */ { 1, 5, 6, 2, 1, 6 }, +/* 243: 0, 1, 4, 5, 6, 7, */ { 3, 1, 10, 11, 3, 10 }, +/* 221: 0, 2, 3, 4, 6, 7, */ { 0, 4, 5, 1, 0, 5 }, +/* 249: 0, 3, 4, 5, 6, 7, */ { 9, 10, 2, 0, 9, 2 }, +/* 238: 1, 2, 3, 5, 6, 7, */ { 4, 0, 3, 7, 4, 3 }, +/* 246: 1, 2, 4, 5, 6, 7, */ { 0, 2, 11, 8, 0, 11 }, +/* 252: 2, 3, 4, 5, 6, 7, */ { 1, 3, 8, 9, 1, 8 } +}; +//_____________________________________________________________________________ + +//_____________________________________________________________________________ +/** + * \brief test table for case 3 + * One face to test + * When the test on the specified face is positive : 4 first triangles + * When the test on the specified face is negative : 2 last triangles + * + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char test3[24] = { +/* 5: 0, 2, */ 5, +/* 33: 0, 5, */ 1, +/* 129: 0, 7, */ 4, +/* 10: 1, 3, */ 5, +/* 18: 1, 4, */ 1, +/* 66: 1, 6, */ 2, +/* 36: 2, 5, */ 2, +/* 132: 2, 7, */ 3, +/* 24: 3, 4, */ 4, +/* 72: 3, 6, */ 3, +/* 80: 4, 6, */ 6, +/* 160: 5, 7, */ 6, +/* 95: 0, 1, 2, 3, 4, 6, */ -6, +/* 175: 0, 1, 2, 3, 5, 7, */ -6, +/* 183: 0, 1, 2, 4, 5, 7, */ -3, +/* 231: 0, 1, 2, 5, 6, 7, */ -4, +/* 123: 0, 1, 3, 4, 5, 6, */ -3, +/* 219: 0, 1, 3, 4, 6, 7, */ -2, +/* 189: 0, 2, 3, 4, 5, 7, */ -2, +/* 237: 0, 2, 3, 5, 6, 7, */ -1, +/* 245: 0, 2, 4, 5, 6, 7, */ -5, +/* 126: 1, 2, 3, 4, 5, 6, */ -4, +/* 222: 1, 2, 3, 4, 6, 7, */ -1, +/* 250: 1, 3, 4, 5, 6, 7, */ -5 +}; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 3.1 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling3_1[24][6] = { +/* 5: 0, 2, */ { 0, 8, 3, 1, 2, 10 }, +/* 33: 0, 5, */ { 9, 5, 4, 0, 8, 3 }, +/* 129: 0, 7, */ { 3, 0, 8, 11, 7, 6 }, +/* 10: 1, 3, */ { 1, 9, 0, 2, 3, 11 }, +/* 18: 1, 4, */ { 0, 1, 9, 8, 4, 7 }, +/* 66: 1, 6, */ { 9, 0, 1, 5, 10, 6 }, +/* 36: 2, 5, */ { 1, 2, 10, 9, 5, 4 }, +/* 132: 2, 7, */ { 10, 1, 2, 6, 11, 7 }, +/* 24: 3, 4, */ { 8, 4, 7, 3, 11, 2 }, +/* 72: 3, 6, */ { 2, 3, 11, 10, 6, 5 }, +/* 80: 4, 6, */ { 5, 10, 6, 4, 7, 8 }, +/* 160: 5, 7, */ { 4, 9, 5, 7, 6, 11 }, +/* 95: 0, 1, 2, 3, 4, 6, */ { 5, 9, 4, 11, 6, 7 }, +/* 175: 0, 1, 2, 3, 5, 7, */ { 6, 10, 5, 8, 7, 4 }, +/* 183: 0, 1, 2, 4, 5, 7, */ { 11, 3, 2, 5, 6, 10 }, +/* 231: 0, 1, 2, 5, 6, 7, */ { 7, 4, 8, 2, 11, 3 }, +/* 123: 0, 1, 3, 4, 5, 6, */ { 2, 1, 10, 7, 11, 6 }, +/* 219: 0, 1, 3, 4, 6, 7, */ { 10, 2, 1, 4, 5, 9 }, +/* 189: 0, 2, 3, 4, 5, 7, */ { 1, 0, 9, 6, 10, 5 }, +/* 237: 0, 2, 3, 5, 6, 7, */ { 9, 1, 0, 7, 4, 8 }, +/* 245: 0, 2, 4, 5, 6, 7, */ { 0, 9, 1, 11, 3, 2 }, +/* 126: 1, 2, 3, 4, 5, 6, */ { 8, 0, 3, 6, 7, 11 }, +/* 222: 1, 2, 3, 4, 6, 7, */ { 4, 5, 9, 3, 8, 0 }, +/* 250: 1, 3, 4, 5, 6, 7, */ { 3, 8, 0, 10, 2, 1 } +}; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 3.2 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling3_2[24][12] = { +/* 5: 0, 2, */ { 10, 3, 2, 10, 8, 3, 10, 1, 0, 8, 10, 0 }, +/* 33: 0, 5, */ { 3, 4, 8, 3, 5, 4, 3, 0, 9, 5, 3, 9 }, +/* 129: 0, 7, */ { 6, 8, 7, 6, 0, 8, 6, 11, 3, 0, 6, 3 }, +/* 10: 1, 3, */ { 11, 0, 3, 11, 9, 0, 11, 2, 1, 9, 11, 1 }, +/* 18: 1, 4, */ { 7, 9, 4, 7, 1, 9, 7, 8, 0, 1, 7, 0 }, +/* 66: 1, 6, */ { 6, 1, 10, 6, 0, 1, 9, 0, 6, 9, 6, 5 }, +/* 36: 2, 5, */ { 4, 10, 5, 4, 2, 10, 4, 9, 1, 2, 4, 1 }, +/* 132: 2, 7, */ { 7, 2, 11, 7, 1, 2, 7, 6, 10, 1, 7, 10 }, +/* 24: 3, 4, */ { 2, 7, 11, 2, 4, 7, 2, 3, 8, 4, 2, 8 }, +/* 72: 3, 6, */ { 5, 11, 6, 5, 3, 11, 5, 10, 2, 3, 5, 2 }, +/* 80: 4, 6, */ { 8, 6, 7, 8, 10, 6, 8, 4, 5, 10, 8, 5 }, +/* 160: 5, 7, */ { 11, 5, 6, 11, 9, 5, 11, 7, 4, 9, 11, 4 }, +/* 95: 0, 1, 2, 3, 4, 6, */ { 6, 5, 11, 5, 9, 11, 4, 7, 11, 4, 11, 9 }, +/* 175: 0, 1, 2, 3, 5, 7, */ { 7, 6, 8, 6, 10, 8, 5, 4, 8, 5, 8, 10 }, +/* 183: 0, 1, 2, 4, 5, 7, */ { 6, 11, 5, 11, 3, 5, 2, 10, 5, 2, 5, 3 }, +/* 231: 0, 1, 2, 5, 6, 7, */ { 11, 7, 2, 7, 4, 2, 8, 3, 2, 8, 2, 4 }, +/* 123: 0, 1, 3, 4, 5, 6, */ { 11, 2, 7, 2, 1, 7, 10, 6, 7, 10, 7, 1 }, +/* 219: 0, 1, 3, 4, 6, 7, */ { 5, 10, 4, 10, 2, 4, 1, 9, 4, 1, 4, 2 }, +/* 189: 0, 2, 3, 4, 5, 7, */ { 10, 1, 6, 1, 0, 6, 6, 0, 9, 5, 6, 9 }, +/* 237: 0, 2, 3, 5, 6, 7, */ { 4, 9, 7, 9, 1, 7, 0, 8, 7, 0, 7, 1 }, +/* 245: 0, 2, 4, 5, 6, 7, */ { 3, 0, 11, 0, 9, 11, 1, 2, 11, 1, 11, 9 }, +/* 126: 1, 2, 3, 4, 5, 6, */ { 7, 8, 6, 8, 0, 6, 3, 11, 6, 3, 6, 0 }, +/* 222: 1, 2, 3, 4, 6, 7, */ { 8, 4, 3, 4, 5, 3, 9, 0, 3, 9, 3, 5 }, +/* 250: 1, 3, 4, 5, 6, 7, */ { 2, 3, 10, 3, 8, 10, 0, 1, 10, 0, 10, 8 } +}; +//_____________________________________________________________________________ + + + +//_____________________________________________________________________________ +/** + * \brief test table for case 4 + * Interior to test + * When the test on the interior is negative : 2 first triangles + * When the test on the interior is positive : 6 last triangles + * + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char test4[8] = { +/* 65: 0, 6, */ 7, +/* 130: 1, 7, */ 7, +/* 20: 2, 4, */ 7, +/* 40: 3, 5, */ 7, +/* 215: 0, 1, 2, 4, 6, 7, */ -7, +/* 235: 0, 1, 3, 5, 6, 7, */ -7, +/* 125: 0, 2, 3, 4, 5, 6, */ -7, +/* 190: 1, 2, 3, 4, 5, 7, */ -7 +}; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 4.1 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling4_1[8][6] = { +/* 65: 0, 6, */ { 0, 8, 3, 5, 10, 6 }, +/* 130: 1, 7, */ { 0, 1, 9, 11, 7, 6 }, +/* 20: 2, 4, */ { 1, 2, 10, 8, 4, 7 }, +/* 40: 3, 5, */ { 9, 5, 4, 2, 3, 11 }, +/* 215: 0, 1, 2, 4, 6, 7, */ { 4, 5, 9, 11, 3, 2 }, +/* 235: 0, 1, 3, 5, 6, 7, */ { 10, 2, 1, 7, 4, 8 }, +/* 125: 0, 2, 3, 4, 5, 6, */ { 9, 1, 0, 6, 7, 11 }, +/* 190: 1, 2, 3, 4, 5, 7, */ { 3, 8, 0, 6, 10, 5 } +}; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 4.2 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling4_2[8][18] = { +/* 65: 0, 6, */ { 8, 5, 0, 5, 8, 6, 3, 6, 8, 6, 3, 10, 0, 10, 3, 10, 0, 5 }, +/* 130: 1, 7, */ { 9, 6, 1, 6, 9, 7, 0, 7, 9, 7, 0, 11, 1, 11, 0, 11, 1, 6 }, +/* 20: 2, 4, */ { 10, 7, 2, 7, 10, 4, 1, 4, 10, 4, 1, 8, 2, 8, 1, 8, 2, 7 }, +/* 40: 3, 5, */ { 11, 4, 3, 4, 11, 5, 2, 5, 11, 5, 2, 9, 3, 9, 2, 9, 3, 4 }, +/* 215: 0, 1, 2, 4, 6, 7, */ { 3, 4, 11, 5, 11, 4, 11, 5, 2, 9, 2, 5, 2, 9, 3, 4, 3, 9 }, +/* 235: 0, 1, 3, 5, 6, 7, */ { 2, 7, 10, 4, 10, 7, 10, 4, 1, 8, 1, 4, 1, 8, 2, 7, 2, 8 }, +/* 125: 0, 2, 3, 4, 5, 6, */ { 1, 6, 9, 7, 9, 6, 9, 7, 0, 11, 0, 7, 0, 11, 1, 6, 1, 11 }, +/* 190: 1, 2, 3, 4, 5, 7, */ { 0, 5, 8, 6, 8, 5, 8, 6, 3, 10, 3, 6, 3, 10, 0, 5, 0, 10 } +}; +//_____________________________________________________________________________ + + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 5 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling5[48][9] = { +/* 7: 0, 1, 2, */ { 2, 8, 3, 2, 10, 8, 10, 9, 8 }, +/* 11: 0, 1, 3, */ { 1, 11, 2, 1, 9, 11, 9, 8, 11 }, +/* 19: 0, 1, 4, */ { 4, 1, 9, 4, 7, 1, 7, 3, 1 }, +/* 35: 0, 1, 5, */ { 8, 5, 4, 8, 3, 5, 3, 1, 5 }, +/* 13: 0, 2, 3, */ { 0, 10, 1, 0, 8, 10, 8, 11, 10 }, +/* 25: 0, 3, 4, */ { 11, 4, 7, 11, 2, 4, 2, 0, 4 }, +/* 137: 0, 3, 7, */ { 7, 0, 8, 7, 6, 0, 6, 2, 0 }, +/* 49: 0, 4, 5, */ { 9, 3, 0, 9, 5, 3, 5, 7, 3 }, +/* 145: 0, 4, 7, */ { 3, 6, 11, 3, 0, 6, 0, 4, 6 }, +/* 14: 1, 2, 3, */ { 3, 9, 0, 3, 11, 9, 11, 10, 9 }, +/* 38: 1, 2, 5, */ { 5, 2, 10, 5, 4, 2, 4, 0, 2 }, +/* 70: 1, 2, 6, */ { 9, 6, 5, 9, 0, 6, 0, 2, 6 }, +/* 50: 1, 4, 5, */ { 0, 7, 8, 0, 1, 7, 1, 5, 7 }, +/* 98: 1, 5, 6, */ { 10, 0, 1, 10, 6, 0, 6, 4, 0 }, +/* 76: 2, 3, 6, */ { 6, 3, 11, 6, 5, 3, 5, 1, 3 }, +/* 140: 2, 3, 7, */ { 10, 7, 6, 10, 1, 7, 1, 3, 7 }, +/* 100: 2, 5, 6, */ { 1, 4, 9, 1, 2, 4, 2, 6, 4 }, +/* 196: 2, 6, 7, */ { 11, 1, 2, 11, 7, 1, 7, 5, 1 }, +/* 152: 3, 4, 7, */ { 8, 2, 3, 8, 4, 2, 4, 6, 2 }, +/* 200: 3, 6, 7, */ { 2, 5, 10, 2, 3, 5, 3, 7, 5 }, +/* 112: 4, 5, 6, */ { 7, 10, 6, 7, 8, 10, 8, 9, 10 }, +/* 176: 4, 5, 7, */ { 6, 9, 5, 6, 11, 9, 11, 8, 9 }, +/* 208: 4, 6, 7, */ { 5, 8, 4, 5, 10, 8, 10, 11, 8 }, +/* 224: 5, 6, 7, */ { 4, 11, 7, 4, 9, 11, 9, 10, 11 }, +/* 31: 0, 1, 2, 3, 4, */ { 4, 7, 11, 4, 11, 9, 9, 11, 10 }, +/* 47: 0, 1, 2, 3, 5, */ { 5, 4, 8, 5, 8, 10, 10, 8, 11 }, +/* 79: 0, 1, 2, 3, 6, */ { 6, 5, 9, 6, 9, 11, 11, 9, 8 }, +/* 143: 0, 1, 2, 3, 7, */ { 7, 6, 10, 7, 10, 8, 8, 10, 9 }, +/* 55: 0, 1, 2, 4, 5, */ { 2, 10, 5, 2, 5, 3, 3, 5, 7 }, +/* 103: 0, 1, 2, 5, 6, */ { 8, 3, 2, 8, 2, 4, 4, 2, 6 }, +/* 59: 0, 1, 3, 4, 5, */ { 11, 2, 1, 11, 1, 7, 7, 1, 5 }, +/* 155: 0, 1, 3, 4, 7, */ { 1, 9, 4, 1, 4, 2, 2, 4, 6 }, +/* 115: 0, 1, 4, 5, 6, */ { 10, 6, 7, 10, 7, 1, 1, 7, 3 }, +/* 179: 0, 1, 4, 5, 7, */ { 6, 11, 3, 6, 3, 5, 5, 3, 1 }, +/* 157: 0, 2, 3, 4, 7, */ { 10, 1, 0, 10, 0, 6, 6, 0, 4 }, +/* 205: 0, 2, 3, 6, 7, */ { 0, 8, 7, 0, 7, 1, 1, 7, 5 }, +/* 185: 0, 3, 4, 5, 7, */ { 9, 5, 6, 9, 6, 0, 0, 6, 2 }, +/* 217: 0, 3, 4, 6, 7, */ { 5, 10, 2, 5, 2, 4, 4, 2, 0 }, +/* 241: 0, 4, 5, 6, 7, */ { 3, 0, 9, 3, 9, 11, 11, 9, 10 }, +/* 110: 1, 2, 3, 5, 6, */ { 3, 11, 6, 3, 6, 0, 0, 6, 4 }, +/* 206: 1, 2, 3, 6, 7, */ { 9, 0, 3, 9, 3, 5, 5, 3, 7 }, +/* 118: 1, 2, 4, 5, 6, */ { 7, 8, 0, 7, 0, 6, 6, 0, 2 }, +/* 230: 1, 2, 5, 6, 7, */ { 11, 7, 4, 11, 4, 2, 2, 4, 0 }, +/* 242: 1, 4, 5, 6, 7, */ { 0, 1, 10, 0, 10, 8, 8, 10, 11 }, +/* 220: 2, 3, 4, 6, 7, */ { 8, 4, 5, 8, 5, 3, 3, 5, 1 }, +/* 236: 2, 3, 5, 6, 7, */ { 4, 9, 1, 4, 1, 7, 7, 1, 3 }, +/* 244: 2, 4, 5, 6, 7, */ { 1, 2, 11, 1, 11, 9, 9, 11, 8 }, +/* 248: 3, 4, 5, 6, 7, */ { 2, 3, 8, 2, 8, 10, 10, 8, 9 } +}; +//_____________________________________________________________________________ + + +//_____________________________________________________________________________ +/** + * \brief test table for case 6 + * 1 face to test + eventually the interior + * When the test on the specified face is positive : 5 first triangles + * When the test on the specified face is negative : + * - if the test on the interior is negative : 3 middle triangles + * - if the test on the interior is positive : 8 last triangles + * The support edge for the interior test is marked as the 3rd column. + * + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char test6[48][3] = { +/* 67: 0, 1, 6, */ { 2, 7, 10 }, +/* 131: 0, 1, 7, */ { 4, 7, 11 }, +/* 21: 0, 2, 4, */ { 5, 7, 1 }, +/* 69: 0, 2, 6, */ { 5, 7, 3 }, +/* 41: 0, 3, 5, */ { 1, 7, 9 }, +/* 73: 0, 3, 6, */ { 3, 7, 10 }, +/* 81: 0, 4, 6, */ { 6, 7, 5 }, +/* 97: 0, 5, 6, */ { 1, 7, 8 }, +/* 193: 0, 6, 7, */ { 4, 7, 8 }, +/* 22: 1, 2, 4, */ { 1, 7, 8 }, +/* 134: 1, 2, 7, */ { 3, 7, 11 }, +/* 42: 1, 3, 5, */ { 5, 7, 2 }, +/* 138: 1, 3, 7, */ { 5, 7, 0 }, +/* 146: 1, 4, 7, */ { 1, 7, 9 }, +/* 162: 1, 5, 7, */ { 6, 7, 6 }, +/* 194: 1, 6, 7, */ { 2, 7, 9 }, +/* 28: 2, 3, 4, */ { 4, 7, 8 }, +/* 44: 2, 3, 5, */ { 2, 7, 9 }, +/* 52: 2, 4, 5, */ { 2, 7, 10 }, +/* 84: 2, 4, 6, */ { 6, 7, 7 }, +/* 148: 2, 4, 7, */ { 3, 7, 10 }, +/* 56: 3, 4, 5, */ { 4, 7, 11 }, +/* 104: 3, 5, 6, */ { 3, 7, 11 }, +/* 168: 3, 5, 7, */ { 6, 7, 4 }, +/* 87: 0, 1, 2, 4, 6, */ { -6, -7, 4 }, +/* 151: 0, 1, 2, 4, 7, */ { -3, -7, 11 }, +/* 199: 0, 1, 2, 6, 7, */ { -4, -7, 11 }, +/* 107: 0, 1, 3, 5, 6, */ { -3, -7, 10 }, +/* 171: 0, 1, 3, 5, 7, */ { -6, -7, 7 }, +/* 203: 0, 1, 3, 6, 7, */ { -2, -7, 10 }, +/* 211: 0, 1, 4, 6, 7, */ { -2, -7, 9 }, +/* 227: 0, 1, 5, 6, 7, */ { -4, -7, 8 }, +/* 61: 0, 2, 3, 4, 5, */ { -2, -7, 9 }, +/* 93: 0, 2, 3, 4, 6, */ { -6, -7, 6 }, +/* 109: 0, 2, 3, 5, 6, */ { -1, -7, 9 }, +/* 117: 0, 2, 4, 5, 6, */ { -5, -7, 0 }, +/* 213: 0, 2, 4, 6, 7, */ { -5, -7, 2 }, +/* 121: 0, 3, 4, 5, 6, */ { -3, -7, 11 }, +/* 233: 0, 3, 5, 6, 7, */ { -1, -7, 8 }, +/* 62: 1, 2, 3, 4, 5, */ { -4, -7, 8 }, +/* 158: 1, 2, 3, 4, 7, */ { -1, -7, 8 }, +/* 174: 1, 2, 3, 5, 7, */ { -6, -7, 5 }, +/* 182: 1, 2, 4, 5, 7, */ { -3, -7, 10 }, +/* 214: 1, 2, 4, 6, 7, */ { -1, -7, 9 }, +/* 186: 1, 3, 4, 5, 7, */ { -5, -7, 3 }, +/* 234: 1, 3, 5, 6, 7, */ { -5, -7, 1 }, +/* 124: 2, 3, 4, 5, 6, */ { -4, -7, 11 }, +/* 188: 2, 3, 4, 5, 7, */ { -2, -7, 10 } +}; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 6.1.1 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling6_1_1[48][9] = { +/* 67: 0, 1, 6, */ { 6, 5, 10, 3, 1, 8, 9, 8, 1 }, +/* 131: 0, 1, 7, */ { 11, 7, 6, 9, 3, 1, 3, 9, 8 }, +/* 21: 0, 2, 4, */ { 1, 2, 10, 7, 0, 4, 0, 7, 3 }, +/* 69: 0, 2, 6, */ { 3, 0, 8, 5, 2, 6, 2, 5, 1 }, +/* 41: 0, 3, 5, */ { 5, 4, 9, 2, 0, 11, 8, 11, 0 }, +/* 73: 0, 3, 6, */ { 10, 6, 5, 8, 2, 0, 2, 8, 11 }, +/* 81: 0, 4, 6, */ { 10, 6, 5, 0, 4, 3, 7, 3, 4 }, +/* 97: 0, 5, 6, */ { 3, 0, 8, 6, 4, 10, 9, 10, 4 }, +/* 193: 0, 6, 7, */ { 8, 3, 0, 10, 7, 5, 7, 10, 11 }, +/* 22: 1, 2, 4, */ { 8, 4, 7, 10, 0, 2, 0, 10, 9 }, +/* 134: 1, 2, 7, */ { 7, 6, 11, 0, 2, 9, 10, 9, 2 }, +/* 42: 1, 3, 5, */ { 2, 3, 11, 4, 1, 5, 1, 4, 0 }, +/* 138: 1, 3, 7, */ { 0, 1, 9, 6, 3, 7, 3, 6, 2 }, +/* 146: 1, 4, 7, */ { 9, 0, 1, 11, 4, 6, 4, 11, 8 }, +/* 162: 1, 5, 7, */ { 11, 7, 6, 1, 5, 0, 4, 0, 5 }, +/* 194: 1, 6, 7, */ { 0, 1, 9, 7, 5, 11, 10, 11, 5 }, +/* 28: 2, 3, 4, */ { 4, 7, 8, 1, 3, 10, 11, 10, 3 }, +/* 44: 2, 3, 5, */ { 9, 5, 4, 11, 1, 3, 1, 11, 10 }, +/* 52: 2, 4, 5, */ { 10, 1, 2, 8, 5, 7, 5, 8, 9 }, +/* 84: 2, 4, 6, */ { 8, 4, 7, 2, 6, 1, 5, 1, 6 }, +/* 148: 2, 4, 7, */ { 1, 2, 10, 4, 6, 8, 11, 8, 6 }, +/* 56: 3, 4, 5, */ { 2, 3, 11, 5, 7, 9, 8, 9, 7 }, +/* 104: 3, 5, 6, */ { 11, 2, 3, 9, 6, 4, 6, 9, 10 }, +/* 168: 3, 5, 7, */ { 9, 5, 4, 3, 7, 2, 6, 2, 7 }, +/* 87: 0, 1, 2, 4, 6, */ { 4, 5, 9, 2, 7, 3, 7, 2, 6 }, +/* 151: 0, 1, 2, 4, 7, */ { 3, 2, 11, 4, 6, 9, 10, 9, 6 }, +/* 199: 0, 1, 2, 6, 7, */ { 11, 3, 2, 9, 7, 5, 7, 9, 8 }, +/* 107: 0, 1, 3, 5, 6, */ { 10, 2, 1, 8, 6, 4, 6, 8, 11 }, +/* 171: 0, 1, 3, 5, 7, */ { 7, 4, 8, 1, 6, 2, 6, 1, 5 }, +/* 203: 0, 1, 3, 6, 7, */ { 2, 1, 10, 7, 5, 8, 9, 8, 5 }, +/* 211: 0, 1, 4, 6, 7, */ { 4, 5, 9, 3, 1, 11, 10, 11, 1 }, +/* 227: 0, 1, 5, 6, 7, */ { 8, 7, 4, 10, 3, 1, 3, 10, 11 }, +/* 61: 0, 2, 3, 4, 5, */ { 9, 1, 0, 11, 5, 7, 5, 11, 10 }, +/* 93: 0, 2, 3, 4, 6, */ { 6, 7, 11, 0, 5, 1, 5, 0, 4 }, +/* 109: 0, 2, 3, 5, 6, */ { 1, 0, 9, 6, 4, 11, 8, 11, 4 }, +/* 117: 0, 2, 4, 5, 6, */ { 9, 1, 0, 7, 3, 6, 2, 6, 3 }, +/* 213: 0, 2, 4, 6, 7, */ { 11, 3, 2, 5, 1, 4, 0, 4, 1 }, +/* 121: 0, 3, 4, 5, 6, */ { 11, 6, 7, 9, 2, 0, 2, 9, 10 }, +/* 233: 0, 3, 5, 6, 7, */ { 7, 4, 8, 2, 0, 10, 9, 10, 0 }, +/* 62: 1, 2, 3, 4, 5, */ { 0, 3, 8, 5, 7, 10, 11, 10, 7 }, +/* 158: 1, 2, 3, 4, 7, */ { 8, 0, 3, 10, 4, 6, 4, 10, 9 }, +/* 174: 1, 2, 3, 5, 7, */ { 5, 6, 10, 3, 4, 0, 4, 3, 7 }, +/* 182: 1, 2, 4, 5, 7, */ { 5, 6, 10, 0, 2, 8, 11, 8, 2 }, +/* 214: 1, 2, 4, 6, 7, */ { 9, 4, 5, 11, 0, 2, 0, 11, 8 }, +/* 186: 1, 3, 4, 5, 7, */ { 8, 0, 3, 6, 2, 5, 1, 5, 2 }, +/* 234: 1, 3, 5, 6, 7, */ { 10, 2, 1, 4, 0, 7, 3, 7, 0 }, +/* 124: 2, 3, 4, 5, 6, */ { 6, 7, 11, 1, 3, 9, 8, 9, 3 }, +/* 188: 2, 3, 4, 5, 7, */ { 10, 5, 6, 8, 1, 3, 1, 8, 9 } +}; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 6.1.2 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling6_1_2[48][27] = { + /* 67: 0, 1, 6, */ { 1, 12, 3, 12, 10, 3, 6, 3, 10, 3, 6, 8, 5, 8, 6, 8, 5, 12, 12, 9, 8, 1, 9, 12, 12, 5, 10 }, + /* 131: 0, 1, 7, */ { 1, 12, 3, 1, 11, 12, 11, 1, 6, 9, 6, 1, 6, 9, 7, 12, 7, 9, 9, 8, 12, 12, 8, 3, 11, 7, 12 }, + /* 21: 0, 2, 4, */ { 4, 12, 0, 4, 1, 12, 1, 4, 10, 7, 10, 4, 10, 7, 2, 12, 2, 7, 7, 3, 12, 12, 3, 0, 1, 2, 12 }, + /* 69: 0, 2, 6, */ { 6, 12, 2, 6, 3, 12, 3, 6, 8, 5, 8, 6, 8, 5, 0, 12, 0, 5, 5, 1, 12, 12, 1, 2, 3, 0, 12 }, + /* 41: 0, 3, 5, */ { 0, 12, 2, 12, 9, 2, 5, 2, 9, 2, 5, 11, 4, 11, 5, 11, 4, 12, 12, 8, 11, 0, 8, 12, 12, 4, 9 }, + /* 73: 0, 3, 6, */ { 0, 12, 2, 0, 10, 12, 10, 0, 5, 8, 5, 0, 5, 8, 6, 12, 6, 8, 8, 11, 12, 12, 11, 2, 10, 6, 12 }, + /* 81: 0, 4, 6, */ { 4, 12, 0, 12, 5, 0, 10, 0, 5, 0, 10, 3, 6, 3, 10, 3, 6, 12, 12, 7, 3, 4, 7, 12, 12, 6, 5 }, + /* 97: 0, 5, 6, */ { 4, 12, 6, 12, 8, 6, 3, 6, 8, 6, 3, 10, 0, 10, 3, 10, 0, 12, 12, 9, 10, 4, 9, 12, 12, 0, 8 }, + /* 193: 0, 6, 7, */ { 5, 12, 7, 5, 8, 12, 8, 5, 0, 10, 0, 5, 0, 10, 3, 12, 3, 10, 10, 11, 12, 12, 11, 7, 8, 3, 12 }, + /* 22: 1, 2, 4, */ { 2, 12, 0, 2, 8, 12, 8, 2, 7, 10, 7, 2, 7, 10, 4, 12, 4, 10, 10, 9, 12, 12, 9, 0, 8, 4, 12 }, + /* 134: 1, 2, 7, */ { 2, 12, 0, 12, 11, 0, 7, 0, 11, 0, 7, 9, 6, 9, 7, 9, 6, 12, 12, 10, 9, 2, 10, 12, 12, 6, 11 }, + /* 42: 1, 3, 5, */ { 5, 12, 1, 5, 2, 12, 2, 5, 11, 4, 11, 5, 11, 4, 3, 12, 3, 4, 4, 0, 12, 12, 0, 1, 2, 3, 12 }, + /* 138: 1, 3, 7, */ { 7, 12, 3, 7, 0, 12, 0, 7, 9, 6, 9, 7, 9, 6, 1, 12, 1, 6, 6, 2, 12, 12, 2, 3, 0, 1, 12 }, + /* 146: 1, 4, 7, */ { 6, 12, 4, 6, 9, 12, 9, 6, 1, 11, 1, 6, 1, 11, 0, 12, 0, 11, 11, 8, 12, 12, 8, 4, 9, 0, 12 }, + /* 162: 1, 5, 7, */ { 5, 12, 1, 12, 6, 1, 11, 1, 6, 1, 11, 0, 7, 0, 11, 0, 7, 12, 12, 4, 0, 5, 4, 12, 12, 7, 6 }, + /* 194: 1, 6, 7, */ { 5, 12, 7, 12, 9, 7, 0, 7, 9, 7, 0, 11, 1, 11, 0, 11, 1, 12, 12, 10, 11, 5, 10, 12, 12, 1, 9 }, + /* 28: 2, 3, 4, */ { 3, 12, 1, 12, 8, 1, 4, 1, 8, 1, 4, 10, 7, 10, 4, 10, 7, 12, 12, 11, 10, 3, 11, 12, 12, 7, 8 }, + /* 44: 2, 3, 5, */ { 3, 12, 1, 3, 9, 12, 9, 3, 4, 11, 4, 3, 4, 11, 5, 12, 5, 11, 11, 10, 12, 12, 10, 1, 9, 5, 12 }, + /* 52: 2, 4, 5, */ { 7, 12, 5, 7, 10, 12, 10, 7, 2, 8, 2, 7, 2, 8, 1, 12, 1, 8, 8, 9, 12, 12, 9, 5, 10, 1, 12 }, + /* 84: 2, 4, 6, */ { 6, 12, 2, 12, 7, 2, 8, 2, 7, 2, 8, 1, 4, 1, 8, 1, 4, 12, 12, 5, 1, 6, 5, 12, 12, 4, 7 }, + /* 148: 2, 4, 7, */ { 6, 12, 4, 12, 10, 4, 1, 4, 10, 4, 1, 8, 2, 8, 1, 8, 2, 12, 12, 11, 8, 6, 11, 12, 12, 2, 10 }, + /* 56: 3, 4, 5, */ { 7, 12, 5, 12, 11, 5, 2, 5, 11, 5, 2, 9, 3, 9, 2, 9, 3, 12, 12, 8, 9, 7, 8, 12, 12, 3, 11 }, + /* 104: 3, 5, 6, */ { 4, 12, 6, 4, 11, 12, 11, 4, 3, 9, 3, 4, 3, 9, 2, 12, 2, 9, 9, 10, 12, 12, 10, 6, 11, 2, 12 }, + /* 168: 3, 5, 7, */ { 7, 12, 3, 12, 4, 3, 9, 3, 4, 3, 9, 2, 5, 2, 9, 2, 5, 12, 12, 6, 2, 7, 6, 12, 12, 5, 4 }, + /* 87: 0, 1, 2, 4, 6, */ { 3, 12, 7, 3, 4, 12, 4, 3, 9, 2, 9, 3, 9, 2, 5, 12, 5, 2, 2, 6, 12, 12, 6, 7, 4, 5, 12 }, + /* 151: 0, 1, 2, 4, 7, */ { 6, 12, 4, 12, 11, 4, 3, 4, 11, 4, 3, 9, 2, 9, 3, 9, 2, 12, 12, 10, 9, 6, 10, 12, 12, 2, 11 }, + /* 199: 0, 1, 2, 6, 7, */ { 5, 12, 7, 5, 11, 12, 11, 5, 2, 9, 2, 5, 2, 9, 3, 12, 3, 9, 9, 8, 12, 12, 8, 7, 11, 3, 12 }, + /* 107: 0, 1, 3, 5, 6, */ { 4, 12, 6, 4, 10, 12, 10, 4, 1, 8, 1, 4, 1, 8, 2, 12, 2, 8, 8, 11, 12, 12, 11, 6, 10, 2, 12 }, + /* 171: 0, 1, 3, 5, 7, */ { 2, 12, 6, 2, 7, 12, 7, 2, 8, 1, 8, 2, 8, 1, 4, 12, 4, 1, 1, 5, 12, 12, 5, 6, 7, 4, 12 }, + /* 203: 0, 1, 3, 6, 7, */ { 5, 12, 7, 12, 10, 7, 2, 7, 10, 7, 2, 8, 1, 8, 2, 8, 1, 12, 12, 9, 8, 5, 9, 12, 12, 1, 10 }, + /* 211: 0, 1, 4, 6, 7, */ { 1, 12, 3, 12, 9, 3, 4, 3, 9, 3, 4, 11, 5, 11, 4, 11, 5, 12, 12, 10, 11, 1, 10, 12, 12, 5, 9 }, + /* 227: 0, 1, 5, 6, 7, */ { 1, 12, 3, 1, 8, 12, 8, 1, 4, 10, 4, 1, 4, 10, 7, 12, 7, 10, 10, 11, 12, 12, 11, 3, 8, 7, 12 }, + /* 61: 0, 2, 3, 4, 5, */ { 7, 12, 5, 7, 9, 12, 9, 7, 0, 11, 0, 7, 0, 11, 1, 12, 1, 11, 11, 10, 12, 12, 10, 5, 9, 1, 12 }, + /* 93: 0, 2, 3, 4, 6, */ { 1, 12, 5, 1, 6, 12, 6, 1, 11, 0, 11, 1, 11, 0, 7, 12, 7, 0, 0, 4, 12, 12, 4, 5, 6, 7, 12 }, + /* 109: 0, 2, 3, 5, 6, */ { 4, 12, 6, 12, 9, 6, 1, 6, 9, 6, 1, 11, 0, 11, 1, 11, 0, 12, 12, 8, 11, 4, 8, 12, 12, 0, 9 }, + /* 117: 0, 2, 4, 5, 6, */ { 3, 12, 7, 12, 0, 7, 9, 7, 0, 7, 9, 6, 1, 6, 9, 6, 1, 12, 12, 2, 6, 3, 2, 12, 12, 1, 0 }, + /* 213: 0, 2, 4, 6, 7, */ { 1, 12, 5, 12, 2, 5, 11, 5, 2, 5, 11, 4, 3, 4, 11, 4, 3, 12, 12, 0, 4, 1, 0, 12, 12, 3, 2 }, + /* 121: 0, 3, 4, 5, 6, */ { 0, 12, 2, 0, 11, 12, 11, 0, 7, 9, 7, 0, 7, 9, 6, 12, 6, 9, 9, 10, 12, 12, 10, 2, 11, 6, 12 }, + /* 233: 0, 3, 5, 6, 7, */ { 0, 12, 2, 12, 8, 2, 7, 2, 8, 2, 7, 10, 4, 10, 7, 10, 4, 12, 12, 9, 10, 0, 9, 12, 12, 4, 8 }, + /* 62: 1, 2, 3, 4, 5, */ { 7, 12, 5, 12, 8, 5, 0, 5, 8, 5, 0, 10, 3, 10, 0, 10, 3, 12, 12, 11, 10, 7, 11, 12, 12, 3, 8 }, + /* 158: 1, 2, 3, 4, 7, */ { 6, 12, 4, 6, 8, 12, 8, 6, 3, 10, 3, 6, 3, 10, 0, 12, 0, 10, 10, 9, 12, 12, 9, 4, 8, 0, 12 }, + /* 174: 1, 2, 3, 5, 7, */ { 0, 12, 4, 0, 5, 12, 5, 0, 10, 3, 10, 0, 10, 3, 6, 12, 6, 3, 3, 7, 12, 12, 7, 4, 5, 6, 12 }, + /* 182: 1, 2, 4, 5, 7, */ { 2, 12, 0, 12, 10, 0, 5, 0, 10, 0, 5, 8, 6, 8, 5, 8, 6, 12, 12, 11, 8, 2, 11, 12, 12, 6, 10 }, + /* 214: 1, 2, 4, 6, 7, */ { 2, 12, 0, 2, 9, 12, 9, 2, 5, 11, 5, 2, 5, 11, 4, 12, 4, 11, 11, 8, 12, 12, 8, 0, 9, 4, 12 }, + /* 186: 1, 3, 4, 5, 7, */ { 2, 12, 6, 12, 3, 6, 8, 6, 3, 6, 8, 5, 0, 5, 8, 5, 0, 12, 12, 1, 5, 2, 1, 12, 12, 0, 3 }, + /* 234: 1, 3, 5, 6, 7, */ { 0, 12, 4, 12, 1, 4, 10, 4, 1, 4, 10, 7, 2, 7, 10, 7, 2, 12, 12, 3, 7, 0, 3, 12, 12, 2, 1 }, + /* 124: 2, 3, 4, 5, 6, */ { 3, 12, 1, 12, 11, 1, 6, 1, 11, 1, 6, 9, 7, 9, 6, 9, 7, 12, 12, 8, 9, 3, 8, 12, 12, 7, 11 }, + /* 188: 2, 3, 4, 5, 7, */ { 3, 12, 1, 3, 10, 12, 10, 3, 6, 8, 6, 3, 6, 8, 5, 12, 5, 8, 8, 9, 12, 12, 9, 1, 10, 5, 12 }, +}; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 6.2 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling6_2[48][15] = { +/* 67: 0, 1, 6, */ { 1, 10, 3, 6, 3, 10, 3, 6, 8, 5, 8, 6, 8, 5, 9 }, +/* 131: 0, 1, 7, */ { 1, 11, 3, 11, 1, 6, 9, 6, 1, 6, 9, 7, 8, 7, 9 }, +/* 21: 0, 2, 4, */ { 4, 1, 0, 1, 4, 10, 7, 10, 4, 10, 7, 2, 3, 2, 7 }, +/* 69: 0, 2, 6, */ { 6, 3, 2, 3, 6, 8, 5, 8, 6, 8, 5, 0, 1, 0, 5 }, +/* 41: 0, 3, 5, */ { 0, 9, 2, 5, 2, 9, 2, 5, 11, 4, 11, 5, 11, 4, 8 }, +/* 73: 0, 3, 6, */ { 0, 10, 2, 10, 0, 5, 8, 5, 0, 5, 8, 6, 11, 6, 8 }, +/* 81: 0, 4, 6, */ { 4, 5, 0, 10, 0, 5, 0, 10, 3, 6, 3, 10, 3, 6, 7 }, +/* 97: 0, 5, 6, */ { 4, 8, 6, 3, 6, 8, 6, 3, 10, 0, 10, 3, 10, 0, 9 }, +/* 193: 0, 6, 7, */ { 5, 8, 7, 8, 5, 0, 10, 0, 5, 0, 10, 3, 11, 3, 10 }, +/* 22: 1, 2, 4, */ { 2, 8, 0, 8, 2, 7, 10, 7, 2, 7, 10, 4, 9, 4, 10 }, +/* 134: 1, 2, 7, */ { 2, 11, 0, 7, 0, 11, 0, 7, 9, 6, 9, 7, 9, 6, 10 }, +/* 42: 1, 3, 5, */ { 5, 2, 1, 2, 5, 11, 4, 11, 5, 11, 4, 3, 0, 3, 4 }, +/* 138: 1, 3, 7, */ { 7, 0, 3, 0, 7, 9, 6, 9, 7, 9, 6, 1, 2, 1, 6 }, +/* 146: 1, 4, 7, */ { 6, 9, 4, 9, 6, 1, 11, 1, 6, 1, 11, 0, 8, 0, 11 }, +/* 162: 1, 5, 7, */ { 5, 6, 1, 11, 1, 6, 1, 11, 0, 7, 0, 11, 0, 7, 4 }, +/* 194: 1, 6, 7, */ { 5, 9, 7, 0, 7, 9, 7, 0, 11, 1, 11, 0, 11, 1, 10 }, +/* 28: 2, 3, 4, */ { 3, 8, 1, 4, 1, 8, 1, 4, 10, 7, 10, 4, 10, 7, 11 }, +/* 44: 2, 3, 5, */ { 3, 9, 1, 9, 3, 4, 11, 4, 3, 4, 11, 5, 10, 5, 11 }, +/* 52: 2, 4, 5, */ { 7, 10, 5, 10, 7, 2, 8, 2, 7, 2, 8, 1, 9, 1, 8 }, +/* 84: 2, 4, 6, */ { 6, 7, 2, 8, 2, 7, 2, 8, 1, 4, 1, 8, 1, 4, 5 }, +/* 148: 2, 4, 7, */ { 6, 10, 4, 1, 4, 10, 4, 1, 8, 2, 8, 1, 8, 2, 11 }, +/* 56: 3, 4, 5, */ { 7, 11, 5, 2, 5, 11, 5, 2, 9, 3, 9, 2, 9, 3, 8 }, +/* 104: 3, 5, 6, */ { 4, 11, 6, 11, 4, 3, 9, 3, 4, 3, 9, 2, 10, 2, 9 }, +/* 168: 3, 5, 7, */ { 7, 4, 3, 9, 3, 4, 3, 9, 2, 5, 2, 9, 2, 5, 6 }, +/* 87: 0, 1, 2, 4, 6, */ { 3, 4, 7, 4, 3, 9, 2, 9, 3, 9, 2, 5, 6, 5, 2 }, +/* 151: 0, 1, 2, 4, 7, */ { 6, 11, 4, 3, 4, 11, 4, 3, 9, 2, 9, 3, 9, 2, 10 }, +/* 199: 0, 1, 2, 6, 7, */ { 5, 11, 7, 11, 5, 2, 9, 2, 5, 2, 9, 3, 8, 3, 9 }, +/* 107: 0, 1, 3, 5, 6, */ { 4, 10, 6, 10, 4, 1, 8, 1, 4, 1, 8, 2, 11, 2, 8 }, +/* 171: 0, 1, 3, 5, 7, */ { 2, 7, 6, 7, 2, 8, 1, 8, 2, 8, 1, 4, 5, 4, 1 }, +/* 203: 0, 1, 3, 6, 7, */ { 5, 10, 7, 2, 7, 10, 7, 2, 8, 1, 8, 2, 8, 1, 9 }, +/* 211: 0, 1, 4, 6, 7, */ { 1, 9, 3, 4, 3, 9, 3, 4, 11, 5, 11, 4, 11, 5, 10 }, +/* 227: 0, 1, 5, 6, 7, */ { 1, 8, 3, 8, 1, 4, 10, 4, 1, 4, 10, 7, 11, 7, 10 }, +/* 61: 0, 2, 3, 4, 5, */ { 7, 9, 5, 9, 7, 0, 11, 0, 7, 0, 11, 1, 10, 1, 11 }, +/* 93: 0, 2, 3, 4, 6, */ { 1, 6, 5, 6, 1, 11, 0, 11, 1, 11, 0, 7, 4, 7, 0 }, +/* 109: 0, 2, 3, 5, 6, */ { 4, 9, 6, 1, 6, 9, 6, 1, 11, 0, 11, 1, 11, 0, 8 }, +/* 117: 0, 2, 4, 5, 6, */ { 3, 0, 7, 9, 7, 0, 7, 9, 6, 1, 6, 9, 6, 1, 2 }, +/* 213: 0, 2, 4, 6, 7, */ { 1, 2, 5, 11, 5, 2, 5, 11, 4, 3, 4, 11, 4, 3, 0 }, +/* 121: 0, 3, 4, 5, 6, */ { 0, 11, 2, 11, 0, 7, 9, 7, 0, 7, 9, 6, 10, 6, 9 }, +/* 233: 0, 3, 5, 6, 7, */ { 0, 8, 2, 7, 2, 8, 2, 7, 10, 4, 10, 7, 10, 4, 9 }, +/* 62: 1, 2, 3, 4, 5, */ { 7, 8, 5, 0, 5, 8, 5, 0, 10, 3, 10, 0, 10, 3, 11 }, +/* 158: 1, 2, 3, 4, 7, */ { 6, 8, 4, 8, 6, 3, 10, 3, 6, 3, 10, 0, 9, 0, 10 }, +/* 174: 1, 2, 3, 5, 7, */ { 0, 5, 4, 5, 0, 10, 3, 10, 0, 10, 3, 6, 7, 6, 3 }, +/* 182: 1, 2, 4, 5, 7, */ { 2, 10, 0, 5, 0, 10, 0, 5, 8, 6, 8, 5, 8, 6, 11 }, +/* 214: 1, 2, 4, 6, 7, */ { 2, 9, 0, 9, 2, 5, 11, 5, 2, 5, 11, 4, 8, 4, 11 }, +/* 186: 1, 3, 4, 5, 7, */ { 2, 3, 6, 8, 6, 3, 6, 8, 5, 0, 5, 8, 5, 0, 1 }, +/* 234: 1, 3, 5, 6, 7, */ { 0, 1, 4, 10, 4, 1, 4, 10, 7, 2, 7, 10, 7, 2, 3 }, +/* 124: 2, 3, 4, 5, 6, */ { 3, 11, 1, 6, 1, 11, 1, 6, 9, 7, 9, 6, 9, 7, 8 }, +/* 188: 2, 3, 4, 5, 7, */ { 3, 10, 1, 10, 3, 6, 8, 6, 3, 6, 8, 5, 9, 5, 8 } +}; +//_____________________________________________________________________________ + + + +//_____________________________________________________________________________ +/** + * \brief test table for case 7 + * 3 faces to test + eventually the interior + * When the tests on the 3 specified faces are positive : + * - if the test on the interior is positive : 5 first triangles + * - if the test on the interior is negative : 9 next triangles + * When the tests on the first and the second specified faces are positive : 9 next triangles + * When the tests on the first and the third specified faces are positive : 9 next triangles + * When the tests on the second and the third specified faces are positive : 9 next triangles + * When the test on the first specified face is positive : 5 next triangles + * When the test on the second specified face is positive : 5 next triangles + * When the test on the third specified face is positive : 5 next triangles + * When the tests on the 3 specified faces are negative : 3 last triangles + * The support edge for the interior test is marked as the 5th column. + * + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char test7[16][5] = { +/* 37: 0, 2, 5, */ { 1, 2, 5, 7, 1 }, +/* 133: 0, 2, 7, */ { 3, 4, 5, 7, 3 }, +/* 161: 0, 5, 7, */ { 4, 1, 6, 7, 4 }, +/* 26: 1, 3, 4, */ { 4, 1, 5, 7, 0 }, +/* 74: 1, 3, 6, */ { 2, 3, 5, 7, 2 }, +/* 82: 1, 4, 6, */ { 1, 2, 6, 7, 5 }, +/* 164: 2, 5, 7, */ { 2, 3, 6, 7, 6 }, +/* 88: 3, 4, 6, */ { 3, 4, 6, 7, 7 }, +/* 167: 0, 1, 2, 5, 7, */ { -3, -4, -6, -7, 7 }, +/* 91: 0, 1, 3, 4, 6, */ { -2, -3, -6, -7, 6 }, +/* 173: 0, 2, 3, 5, 7, */ { -1, -2, -6, -7, 5 }, +/* 181: 0, 2, 4, 5, 7, */ { -2, -3, -5, -7, 2 }, +/* 229: 0, 2, 5, 6, 7, */ { -4, -1, -5, -7, 0 }, +/* 94: 1, 2, 3, 4, 6, */ { -4, -1, -6, -7, 4 }, +/* 122: 1, 3, 4, 5, 6, */ { -3, -4, -5, -7, 3 }, +/* 218: 1, 3, 4, 6, 7, */ { -1, -2, -5, -7, 1 } +}; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 7.1 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling7_1[16][9] = { +/* 37: 0, 2, 5, */ { 9, 5, 4, 10, 1, 2, 8, 3, 0 }, +/* 133: 0, 2, 7, */ { 11, 7, 6, 8, 3, 0, 10, 1, 2 }, +/* 161: 0, 5, 7, */ { 3, 0, 8, 5, 4, 9, 7, 6, 11 }, +/* 26: 1, 3, 4, */ { 8, 4, 7, 9, 0, 1, 11, 2, 3 }, +/* 74: 1, 3, 6, */ { 10, 6, 5, 11, 2, 3, 9, 0, 1 }, +/* 82: 1, 4, 6, */ { 0, 1, 9, 6, 5, 10, 4, 7, 8 }, +/* 164: 2, 5, 7, */ { 1, 2, 10, 7, 6, 11, 5, 4, 9 }, +/* 88: 3, 4, 6, */ { 2, 3, 11, 4, 7, 8, 6, 5, 10 }, +/* 167: 0, 1, 2, 5, 7, */ { 11, 3, 2, 8, 7, 4, 10, 5, 6 }, +/* 91: 0, 1, 3, 4, 6, */ { 10, 2, 1, 11, 6, 7, 9, 4, 5 }, +/* 173: 0, 2, 3, 5, 7, */ { 9, 1, 0, 10, 5, 6, 8, 7, 4 }, +/* 181: 0, 2, 4, 5, 7, */ { 5, 6, 10, 3, 2, 11, 1, 0, 9 }, +/* 229: 0, 2, 5, 6, 7, */ { 7, 4, 8, 1, 0, 9, 3, 2, 11 }, +/* 94: 1, 2, 3, 4, 6, */ { 8, 0, 3, 9, 4, 5, 11, 6, 7 }, +/* 122: 1, 3, 4, 5, 6, */ { 6, 7, 11, 0, 3, 8, 2, 1, 10 }, +/* 218: 1, 3, 4, 6, 7, */ { 4, 5, 9, 2, 1, 10, 0, 3, 8 } +}; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 7.2 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling7_2[16][3][15] = { +/* 37: 0, 2, 5, */ { + /* 1,0 */ { 1, 2, 10, 3, 4, 8, 4, 3, 5, 0, 5, 3, 5, 0, 9 }, + /* 0,1 */ { 3, 0, 8, 9, 1, 4, 2, 4, 1, 4, 2, 5, 10, 5, 2 }, + /* 1,1 */ { 9, 5, 4, 0, 10, 1, 10, 0, 8, 10, 8, 2, 3, 2, 8 } +}, +/* 133: 0, 2, 7, */ { + /* 1,0 */ { 3, 0, 8, 1, 6, 10, 6, 1, 7, 2, 7, 1, 7, 2, 11 }, + /* 0,1 */ { 1, 2, 10, 11, 3, 6, 0, 6, 3, 6, 0, 7, 8, 7, 0 }, + /* 1,1 */ { 11, 7, 6, 2, 8, 3, 8, 2, 10, 8, 10, 0, 1, 0, 10 } +}, +/* 161: 0, 5, 7, */ { + /* 1,0 */ { 9, 5, 4, 11, 3, 6, 0, 6, 3, 6, 0, 7, 8, 7, 0 }, + /* 0,1 */ { 11, 7, 6, 3, 4, 8, 4, 3, 5, 0, 5, 3, 5, 0, 9 }, + /* 1,1 */ { 3, 0, 8, 4, 9, 7, 11, 7, 9, 5, 11, 9, 11, 5, 6 } +}, +/* 26: 1, 3, 4, */ { + /* 1,0 */ { 0, 1, 9, 2, 7, 11, 7, 2, 4, 3, 4, 2, 4, 3, 8 }, + /* 0,1 */ { 2, 3, 11, 8, 0, 7, 1, 7, 0, 7, 1, 4, 9, 4, 1 }, + /* 1,1 */ { 8, 4, 7, 3, 9, 0, 9, 3, 11, 9, 11, 1, 2, 1, 11 } +}, +/* 74: 1, 3, 6, */ { + /* 1,0 */ { 2, 3, 11, 0, 5, 9, 5, 0, 6, 1, 6, 0, 6, 1, 10 }, + /* 0,1 */ { 0, 1, 9, 10, 2, 5, 3, 5, 2, 5, 3, 6, 11, 6, 3 }, + /* 1,1 */ { 6, 5, 10, 1, 11, 2, 11, 1, 9, 11, 9, 3, 0, 3, 9 } +}, +/* 82: 1, 4, 6, */ { + /* 1,0 */ { 6, 5, 10, 8, 0, 7, 1, 7, 0, 7, 1, 4, 9, 4, 1 }, + /* 0,1 */ { 8, 4, 7, 0, 5, 9, 5, 0, 6, 1, 6, 0, 6, 1, 10 }, + /* 1,1 */ { 0, 1, 9, 5, 10, 4, 8, 4, 10, 6, 8, 10, 8, 6, 7 } +}, +/* 164: 2, 5, 7, */ { + /* 1,0 */ { 11, 7, 6, 9, 1, 4, 2, 4, 1, 4, 2, 5, 10, 5, 2 }, + /* 0,1 */ { 9, 5, 4, 1, 6, 10, 6, 1, 7, 2, 7, 1, 7, 2, 11 }, + /* 1,1 */ { 1, 2, 10, 6, 11, 5, 9, 5, 11, 7, 9, 11, 9, 7, 4 } +}, +/* 88: 3, 4, 6, */ { + /* 1,0 */ { 8, 4, 7, 10, 2, 5, 3, 5, 2, 5, 3, 6, 11, 6, 3 }, + /* 0,1 */ { 6, 5, 10, 2, 7, 11, 7, 2, 4, 3, 4, 2, 4, 3, 8 }, + /* 1,1 */ { 2, 3, 11, 7, 8, 6, 10, 6, 8, 4, 10, 8, 10, 4, 5 } +}, +/* 167: 0, 1, 2, 5, 7, */ { + /* 1,0 */ { 7, 4, 8, 5, 2, 10, 2, 5, 3, 6, 3, 5, 3, 6, 11 }, + /* 0,1 */ { 10, 5, 6, 11, 7, 2, 4, 2, 7, 2, 4, 3, 8, 3, 4 }, + /* 1,1 */ { 11, 3, 2, 6, 8, 7, 8, 6, 10, 8, 10, 4, 5, 4, 10 } +}, +/* 91: 0, 1, 3, 4, 6, */ { + /* 1,0 */ { 6, 7, 11, 4, 1, 9, 1, 4, 2, 5, 2, 4, 2, 5, 10 }, + /* 0,1 */ { 4, 5, 9, 10, 6, 1, 7, 1, 6, 1, 7, 2, 11, 2, 7 }, + /* 1,1 */ { 10, 2, 1, 5, 11, 6, 11, 5, 9, 11, 9, 7, 4, 7, 9 } +}, +/* 173: 0, 2, 3, 5, 7, */ { + /* 1,0 */ { 10, 5, 6, 7, 0, 8, 0, 7, 1, 4, 1, 7, 1, 4, 9 }, + /* 0,1 */ { 7, 4, 8, 9, 5, 0, 6, 0, 5, 0, 6, 1, 10, 1, 6 }, + /* 1,1 */ { 9, 1, 0, 4, 10, 5, 10, 4, 8, 10, 8, 6, 7, 6, 8 } +}, +/* 181: 0, 2, 4, 5, 7, */ { + /* 1,0 */ { 11, 3, 2, 9, 5, 0, 6, 0, 5, 0, 6, 1, 10, 1, 6 }, + /* 0,1 */ { 9, 1, 0, 5, 2, 10, 2, 5, 3, 6, 3, 5, 3, 6, 11 }, + /* 1,1 */ { 10, 5, 6, 2, 11, 1, 9, 1, 11, 3, 9, 11, 9, 3, 0 } +}, +/* 229: 0, 2, 5, 6, 7, */ { + /* 1,0 */ { 9, 1, 0, 11, 7, 2, 4, 2, 7, 2, 4, 3, 8, 3, 4 }, + /* 0,1 */ { 11, 3, 2, 7, 0, 8, 0, 7, 1, 4, 1, 7, 1, 4, 9 }, + /* 1,1 */ { 7, 4, 8, 0, 9, 3, 11, 3, 9, 1, 11, 9, 11, 1, 2 } +}, +/* 94: 1, 2, 3, 4, 6, */ { + /* 1,0 */ { 4, 5, 9, 6, 3, 11, 3, 6, 0, 7, 0, 6, 0, 7, 8 }, + /* 0,1 */ { 6, 7, 11, 8, 4, 3, 5, 3, 4, 3, 5, 0, 9, 0, 5 }, + /* 1,1 */ { 8, 0, 3, 7, 9, 4, 9, 7, 11, 9, 11, 5, 6, 5, 11 } +}, +/* 122: 1, 3, 4, 5, 6, */ { + /* 1,0 */ { 8, 0, 3, 10, 6, 1, 7, 1, 6, 1, 7, 2, 11, 2, 7 }, + /* 0,1 */ { 10, 2, 1, 6, 3, 11, 3, 6, 0, 7, 0, 6, 0, 7, 8 }, + /* 1,1 */ { 6, 7, 11, 3, 8, 2, 10, 2, 8, 0, 10, 8, 10, 0, 1 } +}, +/* 218: 1, 3, 4, 6, 7, */ { + /* 1,0 */ { 10, 2, 1, 8, 4, 3, 5, 3, 4, 3, 5, 0, 9, 0, 5 }, + /* 0,1 */ { 8, 0, 3, 4, 1, 9, 1, 4, 2, 5, 2, 4, 2, 5, 10 }, + /* 1,1 */ { 4, 5, 9, 1, 10, 0, 8, 0, 10, 2, 8, 10, 8, 2, 3 } } +}; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 7.3 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling7_3[16][3][27] = { +/* 37: 0, 2, 5, */ { + /* 1,0 */ { 12, 2, 10, 12, 10, 5, 12, 5, 4, 12, 4, 8, 12, 8, 3, 12, 3, 0, 12, 0, 9, 12, 9, 1, 12, 1, 2 }, + /* 0,1 */ { 12, 5, 4, 12, 4, 8, 12, 8, 3, 12, 3, 2, 12, 2, 10, 12, 10, 1, 12, 1, 0, 12, 0, 9, 12, 9, 5 }, + /* 1,1 */ { 5, 4, 12, 10, 5, 12, 2, 10, 12, 3, 2, 12, 8, 3, 12, 0, 8, 12, 1, 0, 12, 9, 1, 12, 4, 9, 12 } +}, +/* 133: 0, 2, 7, */ { + /* 1,0 */ { 12, 0, 8, 12, 8, 7, 12, 7, 6, 12, 6, 10, 12, 10, 1, 12, 1, 2, 12, 2, 11, 12, 11, 3, 12, 3, 0 }, + /* 0,1 */ { 12, 7, 6, 12, 6, 10, 12, 10, 1, 12, 1, 0, 12, 0, 8, 12, 8, 3, 12, 3, 2, 12, 2, 11, 12, 11, 7 }, + /* 1,1 */ { 7, 6, 12, 8, 7, 12, 0, 8, 12, 1, 0, 12, 10, 1, 12, 2, 10, 12, 3, 2, 12, 11, 3, 12, 6, 11, 12 } +}, +/* 161: 0, 5, 7, */ { + /* 1,0 */ { 9, 5, 12, 0, 9, 12, 3, 0, 12, 11, 3, 12, 6, 11, 12, 7, 6, 12, 8, 7, 12, 4, 8, 12, 5, 4, 12 }, + /* 0,1 */ { 3, 0, 12, 11, 3, 12, 6, 11, 12, 5, 6, 12, 9, 5, 12, 4, 9, 12, 7, 4, 12, 8, 7, 12, 0, 8, 12 }, + /* 1,1 */ { 12, 3, 0, 12, 0, 9, 12, 9, 5, 12, 5, 6, 12, 6, 11, 12, 11, 7, 12, 7, 4, 12, 4, 8, 12, 8, 3 } +}, +/* 26: 1, 3, 4, */ { + /* 1,0 */ { 12, 1, 9, 12, 9, 4, 12, 4, 7, 12, 7, 11, 12, 11, 2, 12, 2, 3, 12, 3, 8, 12, 8, 0, 12, 0, 1 }, + /* 0,1 */ { 12, 4, 7, 12, 7, 11, 12, 11, 2, 12, 2, 1, 12, 1, 9, 12, 9, 0, 12, 0, 3, 12, 3, 8, 12, 8, 4 }, + /* 1,1 */ { 4, 7, 12, 9, 4, 12, 1, 9, 12, 2, 1, 12, 11, 2, 12, 3, 11, 12, 0, 3, 12, 8, 0, 12, 7, 8, 12 } +}, +/* 74: 1, 3, 6, */ { + /* 1,0 */ { 12, 3, 11, 12, 11, 6, 12, 6, 5, 12, 5, 9, 12, 9, 0, 12, 0, 1, 12, 1, 10, 12, 10, 2, 12, 2, 3 }, + /* 0,1 */ { 12, 6, 5, 12, 5, 9, 12, 9, 0, 12, 0, 3, 12, 3, 11, 12, 11, 2, 12, 2, 1, 12, 1, 10, 12, 10, 6 }, + /* 1,1 */ { 6, 5, 12, 11, 6, 12, 3, 11, 12, 0, 3, 12, 9, 0, 12, 1, 9, 12, 2, 1, 12, 10, 2, 12, 5, 10, 12 } +}, +/* 82: 1, 4, 6, */ { + /* 1,0 */ { 10, 6, 12, 1, 10, 12, 0, 1, 12, 8, 0, 12, 7, 8, 12, 4, 7, 12, 9, 4, 12, 5, 9, 12, 6, 5, 12 }, + /* 0,1 */ { 0, 1, 12, 8, 0, 12, 7, 8, 12, 6, 7, 12, 10, 6, 12, 5, 10, 12, 4, 5, 12, 9, 4, 12, 1, 9, 12 }, + /* 1,1 */ { 12, 0, 1, 12, 1, 10, 12, 10, 6, 12, 6, 7, 12, 7, 8, 12, 8, 4, 12, 4, 5, 12, 5, 9, 12, 9, 0 } +}, +/* 164: 2, 5, 7, */ { + /* 1,0 */ { 11, 7, 12, 2, 11, 12, 1, 2, 12, 9, 1, 12, 4, 9, 12, 5, 4, 12, 10, 5, 12, 6, 10, 12, 7, 6, 12 }, + /* 0,1 */ { 1, 2, 12, 9, 1, 12, 4, 9, 12, 7, 4, 12, 11, 7, 12, 6, 11, 12, 5, 6, 12, 10, 5, 12, 2, 10, 12 }, + /* 1,1 */ { 12, 1, 2, 12, 2, 11, 12, 11, 7, 12, 7, 4, 12, 4, 9, 12, 9, 5, 12, 5, 6, 12, 6, 10, 12, 10, 1 } +}, +/* 88: 3, 4, 6, */ { + /* 1,0 */ { 8, 4, 12, 3, 8, 12, 2, 3, 12, 10, 2, 12, 5, 10, 12, 6, 5, 12, 11, 6, 12, 7, 11, 12, 4, 7, 12 }, + /* 0,1 */ { 2, 3, 12, 10, 2, 12, 5, 10, 12, 4, 5, 12, 8, 4, 12, 7, 8, 12, 6, 7, 12, 11, 6, 12, 3, 11, 12 }, + /* 1,1 */ { 12, 2, 3, 12, 3, 8, 12, 8, 4, 12, 4, 5, 12, 5, 10, 12, 10, 6, 12, 6, 7, 12, 7, 11, 12, 11, 2 } +}, +/* 167: 0, 1, 2, 5, 7, */ { + /* 1,0 */ { 12, 4, 8, 12, 8, 3, 12, 3, 2, 12, 2, 10, 12, 10, 5, 12, 5, 6, 12, 6, 11, 12, 11, 7, 12, 7, 4 }, + /* 0,1 */ { 12, 3, 2, 12, 2, 10, 12, 10, 5, 12, 5, 4, 12, 4, 8, 12, 8, 7, 12, 7, 6, 12, 6, 11, 12, 11, 3 }, + /* 1,1 */ { 3, 2, 12, 8, 3, 12, 4, 8, 12, 5, 4, 12, 10, 5, 12, 6, 10, 12, 7, 6, 12, 11, 7, 12, 2, 11, 12 } +}, +/* 91: 0, 1, 3, 4, 6, */ { + /* 1,0 */ { 12, 7, 11, 12, 11, 2, 12, 2, 1, 12, 1, 9, 12, 9, 4, 12, 4, 5, 12, 5, 10, 12, 10, 6, 12, 6, 7 }, + /* 0,1 */ { 12, 2, 1, 12, 1, 9, 12, 9, 4, 12, 4, 7, 12, 7, 11, 12, 11, 6, 12, 6, 5, 12, 5, 10, 12, 10, 2 }, + /* 1,1 */ { 2, 1, 12, 11, 2, 12, 7, 11, 12, 4, 7, 12, 9, 4, 12, 5, 9, 12, 6, 5, 12, 10, 6, 12, 1, 10, 12 } +}, +/* 173: 0, 2, 3, 5, 7, */ { + /* 1,0 */ { 12, 6, 10, 12, 10, 1, 12, 1, 0, 12, 0, 8, 12, 8, 7, 12, 7, 4, 12, 4, 9, 12, 9, 5, 12, 5, 6 }, + /* 0,1 */ { 12, 1, 0, 12, 0, 8, 12, 8, 7, 12, 7, 6, 12, 6, 10, 12, 10, 5, 12, 5, 4, 12, 4, 9, 12, 9, 1 }, + /* 1,1 */ { 1, 0, 12, 10, 1, 12, 6, 10, 12, 7, 6, 12, 8, 7, 12, 4, 8, 12, 5, 4, 12, 9, 5, 12, 0, 9, 12 } +}, +/* 181: 0, 2, 4, 5, 7, */ { + /* 1,0 */ { 11, 3, 12, 6, 11, 12, 5, 6, 12, 9, 5, 12, 0, 9, 12, 1, 0, 12, 10, 1, 12, 2, 10, 12, 3, 2, 12 }, + /* 0,1 */ { 5, 6, 12, 9, 5, 12, 0, 9, 12, 3, 0, 12, 11, 3, 12, 2, 11, 12, 1, 2, 12, 10, 1, 12, 6, 10, 12 }, + /* 1,1 */ { 12, 5, 6, 12, 6, 11, 12, 11, 3, 12, 3, 0, 12, 0, 9, 12, 9, 1, 12, 1, 2, 12, 2, 10, 12, 10, 5 } +}, +/* 229: 0, 2, 5, 6, 7, */ { + /* 1,0 */ { 9, 1, 12, 4, 9, 12, 7, 4, 12, 11, 7, 12, 2, 11, 12, 3, 2, 12, 8, 3, 12, 0, 8, 12, 1, 0, 12 }, + /* 0,1 */ { 7, 4, 12, 11, 7, 12, 2, 11, 12, 1, 2, 12, 9, 1, 12, 0, 9, 12, 3, 0, 12, 8, 3, 12, 4, 8, 12 }, + /* 1,1 */ { 12, 7, 4, 12, 4, 9, 12, 9, 1, 12, 1, 2, 12, 2, 11, 12, 11, 3, 12, 3, 0, 12, 0, 8, 12, 8, 7 } +}, +/* 94: 1, 2, 3, 4, 6, */ { + /* 1,0 */ { 12, 5, 9, 12, 9, 0, 12, 0, 3, 12, 3, 11, 12, 11, 6, 12, 6, 7, 12, 7, 8, 12, 8, 4, 12, 4, 5 }, + /* 0,1 */ { 12, 0, 3, 12, 3, 11, 12, 11, 6, 12, 6, 5, 12, 5, 9, 12, 9, 4, 12, 4, 7, 12, 7, 8, 12, 8, 0 }, + /* 1,1 */ { 0, 3, 12, 9, 0, 12, 5, 9, 12, 6, 5, 12, 11, 6, 12, 7, 11, 12, 4, 7, 12, 8, 4, 12, 3, 8, 12 } +}, +/* 122: 1, 3, 4, 5, 6, */ { + /* 1,0 */ { 8, 0, 12, 7, 8, 12, 6, 7, 12, 10, 6, 12, 1, 10, 12, 2, 1, 12, 11, 2, 12, 3, 11, 12, 0, 3, 12 }, + /* 0,1 */ { 6, 7, 12, 10, 6, 12, 1, 10, 12, 0, 1, 12, 8, 0, 12, 3, 8, 12, 2, 3, 12, 11, 2, 12, 7, 11, 12 }, + /* 1,1 */ { 12, 6, 7, 12, 7, 8, 12, 8, 0, 12, 0, 1, 12, 1, 10, 12, 10, 2, 12, 2, 3, 12, 3, 11, 12, 11, 6 } +}, +/* 218: 1, 3, 4, 6, 7, */ { + /* 1,0 */ { 10, 2, 12, 5, 10, 12, 4, 5, 12, 8, 4, 12, 3, 8, 12, 0, 3, 12, 9, 0, 12, 1, 9, 12, 2, 1, 12 }, + /* 0,1 */ { 4, 5, 12, 8, 4, 12, 3, 8, 12, 2, 3, 12, 10, 2, 12, 1, 10, 12, 0, 1, 12, 9, 0, 12, 5, 9, 12 }, + /* 1,1 */ { 12, 4, 5, 12, 5, 10, 12, 10, 2, 12, 2, 3, 12, 3, 8, 12, 8, 0, 12, 0, 1, 12, 1, 9, 12, 9, 4 } } +}; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 7.4.1 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling7_4_1[16][15] = { +/* 37: 0, 2, 5, */ { 3, 4, 8, 4, 3, 10, 2, 10, 3, 4, 10, 5, 9, 1, 0 }, +/* 133: 0, 2, 7, */ { 1, 6, 10, 6, 1, 8, 0, 8, 1, 6, 8, 7, 11, 3, 2 }, +/* 161: 0, 5, 7, */ { 11, 3, 6, 9, 6, 3, 6, 9, 5, 0, 9, 3, 7, 4, 8 }, +/* 26: 1, 3, 4, */ { 2, 7, 11, 7, 2, 9, 1, 9, 2, 7, 9, 4, 8, 0, 3 }, +/* 74: 1, 3, 6, */ { 0, 5, 9, 5, 0, 11, 3, 11, 0, 5, 11, 6, 10, 2, 1 }, +/* 82: 1, 4, 6, */ { 8, 0, 7, 10, 7, 0, 7, 10, 6, 1, 10, 0, 4, 5, 9 }, +/* 164: 2, 5, 7, */ { 9, 1, 4, 11, 4, 1, 4, 11, 7, 2, 11, 1, 5, 6, 10 }, +/* 88: 3, 4, 6, */ { 10, 2, 5, 8, 5, 2, 5, 8, 4, 3, 8, 2, 6, 7, 11 }, +/* 167: 0, 1, 2, 5, 7, */ { 5, 2, 10, 2, 5, 8, 4, 8, 5, 2, 8, 3, 11, 7, 6 }, +/* 91: 0, 1, 3, 4, 6, */ { 4, 1, 9, 1, 4, 11, 7, 11, 4, 1, 11, 2, 10, 6, 5 }, +/* 173: 0, 2, 3, 5, 7, */ { 7, 0, 8, 0, 7, 10, 6, 10, 7, 0, 10, 1, 9, 5, 4 }, +/* 181: 0, 2, 4, 5, 7, */ { 9, 5, 0, 11, 0, 5, 0, 11, 3, 6, 11, 5, 1, 2, 10 }, +/* 229: 0, 2, 5, 6, 7, */ { 11, 7, 2, 9, 2, 7, 2, 9, 1, 4, 9, 7, 3, 0, 8 }, +/* 94: 1, 2, 3, 4, 6, */ { 6, 3, 11, 3, 6, 9, 5, 9, 6, 3, 9, 0, 8, 4, 7 }, +/* 122: 1, 3, 4, 5, 6, */ { 10, 6, 1, 8, 1, 6, 1, 8, 0, 7, 8, 6, 2, 3, 11 }, +/* 218: 1, 3, 4, 6, 7, */ { 8, 4, 3, 10, 3, 4, 3, 10, 2, 5, 10, 4, 0, 1, 9 } +}; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 7.4.2 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling7_4_2[16][27] = { +/* 37: 0, 2, 5, */ { 9, 4, 8, 4, 9, 5, 10, 5, 9, 1, 10, 9, 10, 1, 2, 0, 2, 1, 2, 0, 3, 8, 3, 0, 9, 8, 0 }, +/* 133: 0, 2, 7, */ { 11, 6, 10, 6, 11, 7, 8, 7, 11, 3, 8, 11, 8, 3, 0, 2, 0, 3, 0, 2, 1, 10, 1, 2, 11, 10, 2 }, +/* 161: 0, 5, 7, */ { 11, 3, 8, 0, 8, 3, 8, 0, 9, 8, 9, 4, 5, 4, 9, 4, 5, 7, 6, 7, 5, 7, 6, 11, 7, 11, 8 }, +/* 26: 1, 3, 4, */ { 8, 7, 11, 7, 8, 4, 9, 4, 8, 0, 9, 8, 9, 0, 1, 3, 1, 0, 1, 3, 2, 11, 2, 3, 8, 11, 3 }, +/* 74: 1, 3, 6, */ { 10, 5, 9, 5, 10, 6, 11, 6, 10, 2, 11, 10, 11, 2, 3, 1, 3, 2, 3, 1, 0, 9, 0, 1, 10, 9, 1 }, +/* 82: 1, 4, 6, */ { 8, 0, 9, 1, 9, 0, 9, 1, 10, 9, 10, 5, 6, 5, 10, 5, 6, 4, 7, 4, 6, 4, 7, 8, 4, 8, 9 }, +/* 164: 2, 5, 7, */ { 9, 1, 10, 2, 10, 1, 10, 2, 11, 10, 11, 6, 7, 6, 11, 6, 7, 5, 4, 5, 7, 5, 4, 9, 5, 9, 10 }, +/* 88: 3, 4, 6, */ { 10, 2, 11, 3, 11, 2, 11, 3, 8, 11, 8, 7, 4, 7, 8, 7, 4, 6, 5, 6, 4, 6, 5, 10, 6, 10, 11 }, +/* 167: 0, 1, 2, 5, 7, */ { 11, 2, 10, 2, 11, 3, 8, 3, 11, 7, 8, 11, 8, 7, 4, 6, 4, 7, 4, 6, 5, 10, 5, 6, 11, 10, 6 }, +/* 91: 0, 1, 3, 4, 6, */ { 10, 1, 9, 1, 10, 2, 11, 2, 10, 6, 11, 10, 11, 6, 7, 5, 7, 6, 7, 5, 4, 9, 4, 5, 10, 9, 5 }, +/* 173: 0, 2, 3, 5, 7, */ { 9, 0, 8, 0, 9, 1, 10, 1, 9, 5, 10, 9, 10, 5, 6, 4, 6, 5, 6, 4, 7, 8, 7, 4, 9, 8, 4 }, +/* 181: 0, 2, 4, 5, 7, */ { 9, 5, 10, 6, 10, 5, 10, 6, 11, 10, 11, 2, 3, 2, 11, 2, 3, 1, 0, 1, 3, 1, 0, 9, 1, 9, 10 }, +/* 229: 0, 2, 5, 6, 7, */ { 11, 7, 8, 4, 8, 7, 8, 4, 9, 8, 9, 0, 1, 0, 9, 0, 1, 3, 2, 3, 1, 3, 2, 11, 3, 11, 8 }, +/* 94: 1, 2, 3, 4, 6, */ { 8, 3, 11, 3, 8, 0, 9, 0, 8, 4, 9, 8, 9, 4, 5, 7, 5, 4, 5, 7, 6, 11, 6, 7, 8, 11, 7 }, +/* 122: 1, 3, 4, 5, 6, */ { 10, 6, 11, 7, 11, 6, 11, 7, 8, 11, 8, 3, 0, 3, 8, 3, 0, 2, 1, 2, 0, 2, 1, 10, 2, 10, 11 }, +/* 218: 1, 3, 4, 6, 7, */ { 8, 4, 9, 5, 9, 4, 9, 5, 10, 9, 10, 1, 2, 1, 10, 1, 2, 0, 3, 0, 2, 0, 3, 8, 0, 8, 9 } +}; +//_____________________________________________________________________________ + + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 8 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling8[6][6] = { +/* 15: 0, 1, 2, 3, */ { 9, 8, 10, 10, 8, 11 }, +/* 51: 0, 1, 4, 5, */ { 1, 5, 3, 3, 5, 7 }, +/* 153: 0, 3, 4, 7, */ { 0, 4, 2, 4, 6, 2 }, +/* 102: 1, 2, 5, 6, */ { 0, 2, 4, 4, 2, 6 }, +/* 204: 2, 3, 6, 7, */ { 1, 3, 5, 3, 7, 5 }, +/* 240: 4, 5, 6, 7, */ { 9, 10, 8, 10, 11, 8 } +}; +//_____________________________________________________________________________ + + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 9 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling9[8][12] = { +/* 39: 0, 1, 2, 5, */ { 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8 }, +/* 27: 0, 1, 3, 4, */ { 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1 }, +/* 141: 0, 2, 3, 7, */ { 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8 }, +/* 177: 0, 4, 5, 7, */ { 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5 }, +/* 78: 1, 2, 3, 6, */ { 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9 }, +/* 114: 1, 4, 5, 6, */ { 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0 }, +/* 228: 2, 5, 6, 7, */ { 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2 }, +/* 216: 3, 4, 6, 7, */ { 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4 } +}; +//_____________________________________________________________________________ + + + +//_____________________________________________________________________________ +/** + * \brief test table for case 10 + * 2 faces to test + eventually the interior + * When the tests on both specified faces are positive : 4 middle triangles (1) + * When the test on the first specified face is positive : 8 first triangles + * When the test on the second specified face is positive : 8 next triangles + * When the tests on both specified faces are negative : + * - if the test on the interior is negative : 4 middle triangles + * - if the test on the interior is positive : 8 last triangles + * + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char test10[6][3] = { +/* 195: 0, 1, 6, 7, */ { 2, 4, 7 }, +/* 85: 0, 2, 4, 6, */ { 5, 6, 7 }, +/* 105: 0, 3, 5, 6, */ { 1, 3, 7 }, +/* 150: 1, 2, 4, 7, */ { 1, 3, 7 }, +/* 170: 1, 3, 5, 7, */ { 5, 6, 7 }, +/* 60: 2, 3, 4, 5, */ { 2, 4, 7 } +}; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 10.1.1 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling10_1_1[6][12] = { +/* 195: 0, 1, 6, 7, */ { 5, 10, 7, 11, 7, 10, 8, 1, 9, 1, 8, 3 }, +/* 85: 0, 2, 4, 6, */ { 1, 2, 5, 6, 5, 2, 4, 3, 0, 3, 4, 7 }, +/* 105: 0, 3, 5, 6, */ { 11, 0, 8, 0, 11, 2, 4, 9, 6, 10, 6, 9 }, +/* 150: 1, 2, 4, 7, */ { 9, 0, 10, 2, 10, 0, 6, 8, 4, 8, 6, 11 }, +/* 170: 1, 3, 5, 7, */ { 7, 2, 3, 2, 7, 6, 0, 1, 4, 5, 4, 1 }, +/* 60: 2, 3, 4, 5, */ { 7, 9, 5, 9, 7, 8, 10, 1, 11, 3, 11, 1 } +}; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 10.1.1 inverted + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling10_1_1_[6][12] = { +/* 195: 0, 1, 6, 7, */ { 5, 9, 7, 8, 7, 9, 11, 1, 10, 1, 11, 3 }, +/* 85: 0, 2, 4, 6, */ { 3, 2, 7, 6, 7, 2, 4, 1, 0, 1, 4, 5 }, +/* 105: 0, 3, 5, 6, */ { 10, 0, 9, 0, 10, 2, 4, 8, 6, 11, 6, 8 }, +/* 150: 1, 2, 4, 7, */ { 8, 0, 11, 2, 11, 0, 6, 9, 4, 9, 6, 10 }, +/* 170: 1, 3, 5, 7, */ { 5, 2, 1, 2, 5, 6, 0, 3, 4, 7, 4, 3 }, +/* 60: 2, 3, 4, 5, */ { 7, 10, 5, 10, 7, 11, 9, 1, 8, 3, 8, 1 } +}; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 10.1.2 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling10_1_2[6][24] = { +/* 195: 0, 1, 6, 7, */ { 3, 11, 7, 3, 7, 8, 9, 8, 7, 5, 9, 7, 9, 5, 10, 9, 10, 1, 3, 1, 10, 11, 3, 10 }, +/* 85: 0, 2, 4, 6, */ { 7, 6, 5, 7, 5, 4, 0, 4, 5, 1, 0, 5, 0, 1, 2, 0, 2, 3, 7, 3, 2, 6, 7, 2 }, +/* 105: 0, 3, 5, 6, */ { 11, 2, 10, 6, 11, 10, 11, 6, 4, 11, 4, 8, 0, 8, 4, 9, 0, 4, 0, 9, 10, 0, 10, 2 }, +/* 150: 1, 2, 4, 7, */ { 11, 2, 10, 11, 10, 6, 4, 6, 10, 9, 4, 10, 4, 9, 0, 4, 0, 8, 11, 8, 0, 2, 11, 0 }, +/* 170: 1, 3, 5, 7, */ { 7, 6, 5, 4, 7, 5, 7, 4, 0, 7, 0, 3, 2, 3, 0, 1, 2, 0, 2, 1, 5, 2, 5, 6 }, +/* 60: 2, 3, 4, 5, */ { 7, 8, 3, 11, 7, 3, 7, 11, 10, 7, 10, 5, 9, 5, 10, 1, 9, 10, 9, 1, 3, 9, 3, 8 } +}; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 10.2 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling10_2[6][24] = { +/* 195: 0, 1, 6, 7, */ { 12, 5, 9, 12, 9, 8, 12, 8, 3, 12, 3, 1, 12, 1, 10, 12, 10, 11, 12, 11, 7, 12, 7, 5 }, +/* 85: 0, 2, 4, 6, */ { 12, 1, 0, 12, 0, 4, 12, 4, 7, 12, 7, 3, 12, 3, 2, 12, 2, 6, 12, 6, 5, 12, 5, 1 }, +/* 105: 0, 3, 5, 6, */ { 4, 8, 12, 6, 4, 12, 10, 6, 12, 9, 10, 12, 0, 9, 12, 2, 0, 12, 11, 2, 12, 8, 11, 12 }, +/* 150: 1, 2, 4, 7, */ { 12, 9, 4, 12, 4, 6, 12, 6, 11, 12, 11, 8, 12, 8, 0, 12, 0, 2, 12, 2, 10, 12, 10, 9 }, +/* 170: 1, 3, 5, 7, */ { 0, 3, 12, 4, 0, 12, 5, 4, 12, 1, 5, 12, 2, 1, 12, 6, 2, 12, 7, 6, 12, 3, 7, 12 }, +/* 60: 2, 3, 4, 5, */ { 10, 5, 12, 11, 10, 12, 3, 11, 12, 1, 3, 12, 9, 1, 12, 8, 9, 12, 7, 8, 12, 5, 7, 12 } +}; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 10.2 inverted + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling10_2_[6][24] = { +/* 195: 0, 1, 6, 7, */ { 8, 7, 12, 9, 8, 12, 1, 9, 12, 3, 1, 12, 11, 3, 12, 10, 11, 12, 5, 10, 12, 7, 5, 12 }, +/* 85: 0, 2, 4, 6, */ { 4, 5, 12, 0, 4, 12, 3, 0, 12, 7, 3, 12, 6, 7, 12, 2, 6, 12, 1, 2, 12, 5, 1, 12 }, +/* 105: 0, 3, 5, 6, */ { 12, 11, 6, 12, 6, 4, 12, 4, 9, 12, 9, 10, 12, 10, 2, 12, 2, 0, 12, 0, 8, 12, 8, 11 }, +/* 150: 1, 2, 4, 7, */ { 6, 10, 12, 4, 6, 12, 8, 4, 12, 11, 8, 12, 2, 11, 12, 0, 2, 12, 9, 0, 12, 10, 9, 12 }, +/* 170: 1, 3, 5, 7, */ { 12, 7, 4, 12, 4, 0, 12, 0, 1, 12, 1, 5, 12, 5, 6, 12, 6, 2, 12, 2, 3, 12, 3, 7 }, +/* 60: 2, 3, 4, 5, */ { 12, 7, 11, 12, 11, 10, 12, 10, 1, 12, 1, 3, 12, 3, 8, 12, 8, 9, 12, 9, 5, 12, 5, 7 } +}; +//_____________________________________________________________________________ + + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 11 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling11[12][12] = { +/* 23: 0, 1, 2, 4, */ { 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4 }, +/* 139: 0, 1, 3, 7, */ { 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6 }, +/* 99: 0, 1, 5, 6, */ { 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10 }, +/* 77: 0, 2, 3, 6, */ { 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6 }, +/* 57: 0, 3, 4, 5, */ { 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11 }, +/* 209: 0, 4, 6, 7, */ { 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0 }, +/* 46: 1, 2, 3, 5, */ { 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3 }, +/* 198: 1, 2, 6, 7, */ { 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7 }, +/* 178: 1, 4, 5, 7, */ { 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11 }, +/* 156: 2, 3, 4, 7, */ { 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1 }, +/* 116: 2, 4, 5, 6, */ { 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7 }, +/* 232: 3, 5, 6, 7, */ { 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9 } +}; +//_____________________________________________________________________________ + + +//_____________________________________________________________________________ +/** + * \brief test table for case 12 + * 2 faces to test + eventually the interior + * When the tests on both specified faces are positive : 4 middle triangles (1) + * When the test on the first specified face is positive : 8 first triangles + * When the test on the second specified face is positive : 8 next triangles + * When the tests on both specified faces are negative : + * - if the test on the interior is negative : 4 middle triangles + * - if the test on the interior is positive : 8 last triangles + * The support edge for the interior test is marked as the 4th column. + * + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char test12[24][4] = { +/* 135: 0, 1, 2, 7, */ { 4, 3, 7, 11 }, +/* 75: 0, 1, 3, 6, */ { 3, 2, 7, 10 }, +/* 83: 0, 1, 4, 6, */ { 2, 6, 7, 5 }, +/* 163: 0, 1, 5, 7, */ { 6, 4, 7, 7 }, +/* 45: 0, 2, 3, 5, */ { 2, 1, 7, 9 }, +/* 53: 0, 2, 4, 5, */ { 5, 2, 7, 1 }, +/* 149: 0, 2, 4, 7, */ { 5, 3, 7, 2 }, +/* 101: 0, 2, 5, 6, */ { 5, 1, 7, 0 }, +/* 197: 0, 2, 6, 7, */ { 5, 4, 7, 3 }, +/* 89: 0, 3, 4, 6, */ { 6, 3, 7, 6 }, +/* 169: 0, 3, 5, 7, */ { 1, 6, 7, 4 }, +/* 225: 0, 5, 6, 7, */ { 1, 4, 7, 8 }, +/* 30: 1, 2, 3, 4, */ { 4, 1, 7, 8 }, +/* 86: 1, 2, 4, 6, */ { 6, 1, 7, 4 }, +/* 166: 1, 2, 5, 7, */ { 3, 6, 7, 6 }, +/* 58: 1, 3, 4, 5, */ { 4, 5, 7, 3 }, +/* 154: 1, 3, 4, 7, */ { 1, 5, 7, 0 }, +/* 106: 1, 3, 5, 6, */ { 3, 5, 7, 2 }, +/* 202: 1, 3, 6, 7, */ { 2, 5, 7, 1 }, +/* 210: 1, 4, 6, 7, */ { 1, 2, 7, 9 }, +/* 92: 2, 3, 4, 6, */ { 4, 6, 7, 7 }, +/* 172: 2, 3, 5, 7, */ { 6, 2, 7, 5 }, +/* 180: 2, 4, 5, 7, */ { 2, 3, 7, 10 }, +/* 120: 3, 4, 5, 6, */ { 3, 4, 7, 11 } +}; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 12.1.1 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling12_1_1[24][12] = { +/* 135: 0, 1, 2, 7, */ { 7, 6, 11, 10, 3, 2, 3, 10, 8, 9, 8, 10 }, +/* 75: 0, 1, 3, 6, */ { 6, 5, 10, 9, 2, 1, 2, 9, 11, 8, 11, 9 }, +/* 83: 0, 1, 4, 6, */ { 10, 6, 5, 7, 9, 4, 9, 7, 1, 3, 1, 7 }, +/* 163: 0, 1, 5, 7, */ { 7, 6, 11, 4, 8, 5, 3, 5, 8, 5, 3, 1 }, +/* 45: 0, 2, 3, 5, */ { 5, 4, 9, 8, 1, 0, 1, 8, 10, 11, 10, 8 }, +/* 53: 0, 2, 4, 5, */ { 1, 2, 10, 0, 9, 3, 5, 3, 9, 3, 5, 7 }, +/* 149: 0, 2, 4, 7, */ { 10, 1, 2, 0, 11, 3, 11, 0, 6, 4, 6, 0 }, +/* 101: 0, 2, 5, 6, */ { 8, 3, 0, 2, 9, 1, 9, 2, 4, 6, 4, 2 }, +/* 197: 0, 2, 6, 7, */ { 3, 0, 8, 2, 11, 1, 7, 1, 11, 1, 7, 5 }, +/* 89: 0, 3, 4, 6, */ { 6, 5, 10, 7, 11, 4, 2, 4, 11, 4, 2, 0 }, +/* 169: 0, 3, 5, 7, */ { 9, 5, 4, 6, 8, 7, 8, 6, 0, 2, 0, 6 }, +/* 225: 0, 5, 6, 7, */ { 8, 3, 0, 7, 4, 11, 9, 11, 4, 11, 9, 10 }, +/* 30: 1, 2, 3, 4, */ { 4, 7, 8, 11, 0, 3, 0, 11, 9, 10, 9, 11 }, +/* 86: 1, 2, 4, 6, */ { 4, 7, 8, 5, 9, 6, 0, 6, 9, 6, 0, 2 }, +/* 166: 1, 2, 5, 7, */ { 11, 7, 6, 4, 10, 5, 10, 4, 2, 0, 2, 4 }, +/* 58: 1, 3, 4, 5, */ { 11, 2, 3, 1, 8, 0, 8, 1, 7, 5, 7, 1 }, +/* 154: 1, 3, 4, 7, */ { 0, 1, 9, 3, 8, 2, 4, 2, 8, 2, 4, 6 }, +/* 106: 1, 3, 5, 6, */ { 2, 3, 11, 1, 10, 0, 6, 0, 10, 0, 6, 4 }, +/* 202: 1, 3, 6, 7, */ { 9, 0, 1, 3, 10, 2, 10, 3, 5, 7, 5, 3 }, +/* 210: 1, 4, 6, 7, */ { 9, 0, 1, 4, 5, 8, 10, 8, 5, 8, 10, 11 }, +/* 92: 2, 3, 4, 6, */ { 8, 4, 7, 5, 11, 6, 11, 5, 3, 1, 3, 5 }, +/* 172: 2, 3, 5, 7, */ { 5, 4, 9, 6, 10, 7, 1, 7, 10, 7, 1, 3 }, +/* 180: 2, 4, 5, 7, */ { 10, 1, 2, 5, 6, 9, 11, 9, 6, 9, 11, 8 }, +/* 120: 3, 4, 5, 6, */ { 11, 2, 3, 6, 7, 10, 8, 10, 7, 10, 8, 9 } +}; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 12.1.1 inverted + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling12_1_1_[24][12] = { +/* 135: 0, 1, 2, 7, */ { 3, 2, 11, 10, 7, 6, 7, 10, 8, 9, 8, 10 }, +/* 75: 0, 1, 3, 6, */ { 2, 1, 10, 9, 6, 5, 6, 9, 11, 8, 11, 9 }, +/* 83: 0, 1, 4, 6, */ { 9, 4, 5, 7, 10, 6, 10, 7, 1, 3, 1, 7 }, +/* 163: 0, 1, 5, 7, */ { 7, 4, 8, 6, 11, 5, 3, 5, 11, 5, 3, 1 }, +/* 45: 0, 2, 3, 5, */ { 1, 0, 9, 8, 5, 4, 5, 8, 10, 11, 10, 8 }, +/* 53: 0, 2, 4, 5, */ { 1, 0, 9, 2, 10, 3, 5, 3, 10, 3, 5, 7 }, +/* 149: 0, 2, 4, 7, */ { 11, 3, 2, 0, 10, 1, 10, 0, 6, 4, 6, 0 }, +/* 101: 0, 2, 5, 6, */ { 9, 1, 0, 2, 8, 3, 8, 2, 4, 6, 4, 2 }, +/* 197: 0, 2, 6, 7, */ { 3, 2, 11, 0, 8, 1, 7, 1, 8, 1, 7, 5 }, +/* 89: 0, 3, 4, 6, */ { 6, 7, 11, 5, 10, 4, 2, 4, 10, 4, 2, 0 }, +/* 169: 0, 3, 5, 7, */ { 8, 7, 4, 6, 9, 5, 9, 6, 0, 2, 0, 6 }, +/* 225: 0, 5, 6, 7, */ { 8, 7, 4, 3, 0, 11, 9, 11, 0, 11, 9, 10 }, +/* 30: 1, 2, 3, 4, */ { 0, 3, 8, 11, 4, 7, 4, 11, 9, 10, 9, 11 }, +/* 86: 1, 2, 4, 6, */ { 4, 5, 9, 7, 8, 6, 0, 6, 8, 6, 0, 2 }, +/* 166: 1, 2, 5, 7, */ { 10, 5, 6, 4, 11, 7, 11, 4, 2, 0, 2, 4 }, +/* 58: 1, 3, 4, 5, */ { 8, 0, 3, 1, 11, 2, 11, 1, 7, 5, 7, 1 }, +/* 154: 1, 3, 4, 7, */ { 0, 3, 8, 1, 9, 2, 4, 2, 9, 2, 4, 6 }, +/* 106: 1, 3, 5, 6, */ { 2, 1, 10, 3, 11, 0, 6, 0, 11, 0, 6, 4 }, +/* 202: 1, 3, 6, 7, */ { 10, 2, 1, 3, 9, 0, 9, 3, 5, 7, 5, 3 }, +/* 210: 1, 4, 6, 7, */ { 9, 4, 5, 0, 1, 8, 10, 8, 1, 8, 10, 11 }, +/* 92: 2, 3, 4, 6, */ { 11, 6, 7, 5, 8, 4, 8, 5, 3, 1, 3, 5 }, +/* 172: 2, 3, 5, 7, */ { 5, 6, 10, 4, 9, 7, 1, 7, 9, 7, 1, 3 }, +/* 180: 2, 4, 5, 7, */ { 10, 5, 6, 1, 2, 9, 11, 9, 2, 9, 11, 8 }, +/* 120: 3, 4, 5, 6, */ { 11, 6, 7, 2, 3, 10, 8, 10, 3, 10, 8, 9 } +}; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 12.1.2 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling12_1_2[24][24] = { +/* 135: 0, 1, 2, 7, */ { 7, 3, 11, 3, 7, 8, 9, 8, 7, 6, 9, 7, 9, 6, 10, 2, 10, 6, 11, 2, 6, 2, 11, 3 }, +/* 75: 0, 1, 3, 6, */ { 6, 2, 10, 2, 6, 11, 8, 11, 6, 5, 8, 6, 8, 5, 9, 1, 9, 5, 10, 1, 5, 1, 10, 2 }, +/* 83: 0, 1, 4, 6, */ { 10, 9, 5, 9, 10, 1, 3, 1, 10, 6, 3, 10, 3, 6, 7, 4, 7, 6, 5, 4, 6, 4, 5, 9 }, +/* 163: 0, 1, 5, 7, */ { 7, 8, 11, 3, 11, 8, 11, 3, 1, 11, 1, 6, 5, 6, 1, 6, 5, 4, 6, 4, 7, 8, 7, 4 }, +/* 45: 0, 2, 3, 5, */ { 5, 1, 9, 1, 5, 10, 11, 10, 5, 4, 11, 5, 11, 4, 8, 0, 8, 4, 9, 0, 4, 0, 9, 1 }, +/* 53: 0, 2, 4, 5, */ { 1, 9, 10, 5, 10, 9, 10, 5, 7, 10, 7, 2, 3, 2, 7, 2, 3, 0, 2, 0, 1, 9, 1, 0 }, +/* 149: 0, 2, 4, 7, */ { 10, 11, 2, 11, 10, 6, 4, 6, 10, 1, 4, 10, 4, 1, 0, 3, 0, 1, 2, 3, 1, 3, 2, 11 }, +/* 101: 0, 2, 5, 6, */ { 8, 9, 0, 9, 8, 4, 6, 4, 8, 3, 6, 8, 6, 3, 2, 1, 2, 3, 0, 1, 3, 1, 0, 9 }, +/* 197: 0, 2, 6, 7, */ { 3, 11, 8, 7, 8, 11, 8, 7, 5, 8, 5, 0, 1, 0, 5, 0, 1, 2, 0, 2, 3, 11, 3, 2 }, +/* 89: 0, 3, 4, 6, */ { 6, 11, 10, 2, 10, 11, 10, 2, 0, 10, 0, 5, 4, 5, 0, 5, 4, 7, 5, 7, 6, 11, 6, 7 }, +/* 169: 0, 3, 5, 7, */ { 9, 8, 4, 8, 9, 0, 2, 0, 9, 5, 2, 9, 2, 5, 6, 7, 6, 5, 4, 7, 5, 7, 4, 8 }, +/* 225: 0, 5, 6, 7, */ { 8, 4, 0, 9, 0, 4, 0, 9, 10, 0, 10, 3, 11, 3, 10, 3, 11, 7, 3, 7, 8, 4, 8, 7 }, +/* 30: 1, 2, 3, 4, */ { 4, 0, 8, 0, 4, 9, 10, 9, 4, 7, 10, 4, 10, 7, 11, 3, 11, 7, 8, 3, 7, 3, 8, 0 }, +/* 86: 1, 2, 4, 6, */ { 4, 9, 8, 0, 8, 9, 8, 0, 2, 8, 2, 7, 6, 7, 2, 7, 6, 5, 7, 5, 4, 9, 4, 5 }, +/* 166: 1, 2, 5, 7, */ { 11, 10, 6, 10, 11, 2, 0, 2, 11, 7, 0, 11, 0, 7, 4, 5, 4, 7, 6, 5, 7, 5, 6, 10 }, +/* 58: 1, 3, 4, 5, */ { 11, 8, 3, 8, 11, 7, 5, 7, 11, 2, 5, 11, 5, 2, 1, 0, 1, 2, 3, 0, 2, 0, 3, 8 }, +/* 154: 1, 3, 4, 7, */ { 0, 8, 9, 4, 9, 8, 9, 4, 6, 9, 6, 1, 2, 1, 6, 1, 2, 3, 1, 3, 0, 8, 0, 3 }, +/* 106: 1, 3, 5, 6, */ { 2, 10, 11, 6, 11, 10, 11, 6, 4, 11, 4, 3, 0, 3, 4, 3, 0, 1, 3, 1, 2, 10, 2, 1 }, +/* 202: 1, 3, 6, 7, */ { 9, 10, 1, 10, 9, 5, 7, 5, 9, 0, 7, 9, 7, 0, 3, 2, 3, 0, 1, 2, 0, 2, 1, 10 }, +/* 210: 1, 4, 6, 7, */ { 9, 5, 1, 10, 1, 5, 1, 10, 11, 1, 11, 0, 8, 0, 11, 0, 8, 4, 0, 4, 9, 5, 9, 4 }, +/* 92: 2, 3, 4, 6, */ { 8, 11, 7, 11, 8, 3, 1, 3, 8, 4, 1, 8, 1, 4, 5, 6, 5, 4, 7, 6, 4, 6, 7, 11 }, +/* 172: 2, 3, 5, 7, */ { 5, 10, 9, 1, 9, 10, 9, 1, 3, 9, 3, 4, 7, 4, 3, 4, 7, 6, 4, 6, 5, 10, 5, 6 }, +/* 180: 2, 4, 5, 7, */ { 10, 6, 2, 11, 2, 6, 2, 11, 8, 2, 8, 1, 9, 1, 8, 1, 9, 5, 1, 5, 10, 6, 10, 5 }, +/* 120: 3, 4, 5, 6, */ { 11, 7, 3, 8, 3, 7, 3, 8, 9, 3, 9, 2, 10, 2, 9, 2, 10, 6, 2, 6, 11, 7, 11, 6 } +}; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 12.2 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling12_2[24][24] = { +/* 135: 0, 1, 2, 7, */ { 9, 8, 12, 10, 9, 12, 2, 10, 12, 3, 2, 12, 11, 3, 12, 6, 11, 12, 7, 6, 12, 8, 7, 12 }, +/* 75: 0, 1, 3, 6, */ { 8, 11, 12, 9, 8, 12, 1, 9, 12, 2, 1, 12, 10, 2, 12, 5, 10, 12, 6, 5, 12, 11, 6, 12 }, +/* 83: 0, 1, 4, 6, */ { 3, 1, 12, 7, 3, 12, 4, 7, 12, 9, 4, 12, 5, 9, 12, 6, 5, 12, 10, 6, 12, 1, 10, 12 }, +/* 163: 0, 1, 5, 7, */ { 12, 3, 1, 12, 1, 5, 12, 5, 6, 12, 6, 11, 12, 11, 7, 12, 7, 4, 12, 4, 8, 12, 8, 3 }, +/* 45: 0, 2, 3, 5, */ { 11, 10, 12, 8, 11, 12, 0, 8, 12, 1, 0, 12, 9, 1, 12, 4, 9, 12, 5, 4, 12, 10, 5, 12 }, +/* 53: 0, 2, 4, 5, */ { 12, 5, 7, 12, 7, 3, 12, 3, 2, 12, 2, 10, 12, 10, 1, 12, 1, 0, 12, 0, 9, 12, 9, 5 }, +/* 149: 0, 2, 4, 7, */ { 4, 6, 12, 0, 4, 12, 1, 0, 12, 10, 1, 12, 2, 10, 12, 3, 2, 12, 11, 3, 12, 6, 11, 12 }, +/* 101: 0, 2, 5, 6, */ { 6, 4, 12, 2, 6, 12, 3, 2, 12, 8, 3, 12, 0, 8, 12, 1, 0, 12, 9, 1, 12, 4, 9, 12 }, +/* 197: 0, 2, 6, 7, */ { 12, 7, 5, 12, 5, 1, 12, 1, 0, 12, 0, 8, 12, 8, 3, 12, 3, 2, 12, 2, 11, 12, 11, 7 }, +/* 89: 0, 3, 4, 6, */ { 12, 2, 0, 12, 0, 4, 12, 4, 5, 12, 5, 10, 12, 10, 6, 12, 6, 7, 12, 7, 11, 12, 11, 2 }, +/* 169: 0, 3, 5, 7, */ { 2, 0, 12, 6, 2, 12, 7, 6, 12, 8, 7, 12, 4, 8, 12, 5, 4, 12, 9, 5, 12, 0, 9, 12 }, +/* 225: 0, 5, 6, 7, */ { 12, 9, 10, 12, 10, 11, 12, 11, 7, 12, 7, 4, 12, 4, 8, 12, 8, 3, 12, 3, 0, 12, 0, 9 }, +/* 30: 1, 2, 3, 4, */ { 10, 9, 12, 11, 10, 12, 7, 11, 12, 4, 7, 12, 8, 4, 12, 3, 8, 12, 0, 3, 12, 9, 0, 12 }, +/* 86: 1, 2, 4, 6, */ { 12, 0, 2, 12, 2, 6, 12, 6, 7, 12, 7, 8, 12, 8, 4, 12, 4, 5, 12, 5, 9, 12, 9, 0 }, +/* 166: 1, 2, 5, 7, */ { 0, 2, 12, 4, 0, 12, 5, 4, 12, 10, 5, 12, 6, 10, 12, 7, 6, 12, 11, 7, 12, 2, 11, 12 }, +/* 58: 1, 3, 4, 5, */ { 5, 7, 12, 1, 5, 12, 0, 1, 12, 8, 0, 12, 3, 8, 12, 2, 3, 12, 11, 2, 12, 7, 11, 12 }, +/* 154: 1, 3, 4, 7, */ { 12, 4, 6, 12, 6, 2, 12, 2, 3, 12, 3, 8, 12, 8, 0, 12, 0, 1, 12, 1, 9, 12, 9, 4 }, +/* 106: 1, 3, 5, 6, */ { 12, 6, 4, 12, 4, 0, 12, 0, 1, 12, 1, 10, 12, 10, 2, 12, 2, 3, 12, 3, 11, 12, 11, 6 }, +/* 202: 1, 3, 6, 7, */ { 7, 5, 12, 3, 7, 12, 2, 3, 12, 10, 2, 12, 1, 10, 12, 0, 1, 12, 9, 0, 12, 5, 9, 12 }, +/* 210: 1, 4, 6, 7, */ { 12, 10, 11, 12, 11, 8, 12, 8, 0, 12, 0, 1, 12, 1, 9, 12, 9, 4, 12, 4, 5, 12, 5, 10 }, +/* 92: 2, 3, 4, 6, */ { 1, 3, 12, 5, 1, 12, 6, 5, 12, 11, 6, 12, 7, 11, 12, 4, 7, 12, 8, 4, 12, 3, 8, 12 }, +/* 172: 2, 3, 5, 7, */ { 12, 1, 3, 12, 3, 7, 12, 7, 4, 12, 4, 9, 12, 9, 5, 12, 5, 6, 12, 6, 10, 12, 10, 1 }, +/* 180: 2, 4, 5, 7, */ { 12, 11, 8, 12, 8, 9, 12, 9, 1, 12, 1, 2, 12, 2, 10, 12, 10, 5, 12, 5, 6, 12, 6, 11 }, +/* 120: 3, 4, 5, 6, */ { 12, 8, 9, 12, 9, 10, 12, 10, 2, 12, 2, 3, 12, 3, 11, 12, 11, 6, 12, 6, 7, 12, 7, 8 } +}; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 12.2 inverted + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling12_2_[24][24] = { +/* 135: 0, 1, 2, 7, */ { 12, 2, 11, 12, 11, 7, 12, 7, 6, 12, 6, 10, 12, 10, 9, 12, 9, 8, 12, 8, 3, 12, 3, 2 }, +/* 75: 0, 1, 3, 6, */ { 12, 1, 10, 12, 10, 6, 12, 6, 5, 12, 5, 9, 12, 9, 8, 12, 8, 11, 12, 11, 2, 12, 2, 1 }, +/* 83: 0, 1, 4, 6, */ { 12, 4, 5, 12, 5, 10, 12, 10, 6, 12, 6, 7, 12, 7, 3, 12, 3, 1, 12, 1, 9, 12, 9, 4 }, +/* 163: 0, 1, 5, 7, */ { 7, 6, 12, 8, 7, 12, 4, 8, 12, 5, 4, 12, 1, 5, 12, 3, 1, 12, 11, 3, 12, 6, 11, 12 }, +/* 45: 0, 2, 3, 5, */ { 12, 0, 9, 12, 9, 5, 12, 5, 4, 12, 4, 8, 12, 8, 11, 12, 11, 10, 12, 10, 1, 12, 1, 0 }, +/* 53: 0, 2, 4, 5, */ { 1, 2, 12, 9, 1, 12, 0, 9, 12, 3, 0, 12, 7, 3, 12, 5, 7, 12, 10, 5, 12, 2, 10, 12 }, +/* 149: 0, 2, 4, 7, */ { 12, 1, 2, 12, 2, 11, 12, 11, 3, 12, 3, 0, 12, 0, 4, 12, 4, 6, 12, 6, 10, 12, 10, 1 }, +/* 101: 0, 2, 5, 6, */ { 12, 3, 0, 12, 0, 9, 12, 9, 1, 12, 1, 2, 12, 2, 6, 12, 6, 4, 12, 4, 8, 12, 8, 3 }, +/* 197: 0, 2, 6, 7, */ { 3, 0, 12, 11, 3, 12, 2, 11, 12, 1, 2, 12, 5, 1, 12, 7, 5, 12, 8, 7, 12, 0, 8, 12 }, +/* 89: 0, 3, 4, 6, */ { 6, 5, 12, 11, 6, 12, 7, 11, 12, 4, 7, 12, 0, 4, 12, 2, 0, 12, 10, 2, 12, 5, 10, 12 }, +/* 169: 0, 3, 5, 7, */ { 12, 7, 4, 12, 4, 9, 12, 9, 5, 12, 5, 6, 12, 6, 2, 12, 2, 0, 12, 0, 8, 12, 8, 7 }, +/* 225: 0, 5, 6, 7, */ { 8, 7, 12, 0, 8, 12, 3, 0, 12, 11, 3, 12, 10, 11, 12, 9, 10, 12, 4, 9, 12, 7, 4, 12 }, +/* 30: 1, 2, 3, 4, */ { 12, 7, 8, 12, 8, 0, 12, 0, 3, 12, 3, 11, 12, 11, 10, 12, 10, 9, 12, 9, 4, 12, 4, 7 }, +/* 86: 1, 2, 4, 6, */ { 4, 7, 12, 9, 4, 12, 5, 9, 12, 6, 5, 12, 2, 6, 12, 0, 2, 12, 8, 0, 12, 7, 8, 12 }, +/* 166: 1, 2, 5, 7, */ { 12, 5, 6, 12, 6, 11, 12, 11, 7, 12, 7, 4, 12, 4, 0, 12, 0, 2, 12, 2, 10, 12, 10, 5 }, +/* 58: 1, 3, 4, 5, */ { 12, 0, 3, 12, 3, 11, 12, 11, 2, 12, 2, 1, 12, 1, 5, 12, 5, 7, 12, 7, 8, 12, 8, 0 }, +/* 154: 1, 3, 4, 7, */ { 0, 3, 12, 9, 0, 12, 1, 9, 12, 2, 1, 12, 6, 2, 12, 4, 6, 12, 8, 4, 12, 3, 8, 12 }, +/* 106: 1, 3, 5, 6, */ { 2, 1, 12, 11, 2, 12, 3, 11, 12, 0, 3, 12, 4, 0, 12, 6, 4, 12, 10, 6, 12, 1, 10, 12 }, +/* 202: 1, 3, 6, 7, */ { 12, 2, 1, 12, 1, 9, 12, 9, 0, 12, 0, 3, 12, 3, 7, 12, 7, 5, 12, 5, 10, 12, 10, 2 }, +/* 210: 1, 4, 6, 7, */ { 9, 0, 12, 5, 9, 12, 4, 5, 12, 8, 4, 12, 11, 8, 12, 10, 11, 12, 1, 10, 12, 0, 1, 12 }, +/* 92: 2, 3, 4, 6, */ { 12, 6, 7, 12, 7, 8, 12, 8, 4, 12, 4, 5, 12, 5, 1, 12, 1, 3, 12, 3, 11, 12, 11, 6 }, +/* 172: 2, 3, 5, 7, */ { 5, 4, 12, 10, 5, 12, 6, 10, 12, 7, 6, 12, 3, 7, 12, 1, 3, 12, 9, 1, 12, 4, 9, 12 }, +/* 180: 2, 4, 5, 7, */ { 10, 1, 12, 6, 10, 12, 5, 6, 12, 9, 5, 12, 8, 9, 12, 11, 8, 12, 2, 11, 12, 1, 2, 12 }, +/* 120: 3, 4, 5, 6, */ { 11, 2, 12, 7, 11, 12, 6, 7, 12, 10, 6, 12, 9, 10, 12, 8, 9, 12, 3, 8, 12, 2, 3, 12 } +}; +//_____________________________________________________________________________ + + + +//_____________________________________________________________________________ +/** + * \brief test table for case 13 + * All faces are to be tested + * + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +/* 13: face test */ +static const char test13[2][7] = { +/* 165: 0, 2, 5, 7, */ { 1,2,3,4,5,6,7 }, +/* 90: 1, 3, 4, 6, */ { 2,3,4,1,5,6,7 }, +}; + + + +//_____________________________________________________________________________ +/** + * \brief subconfiguration table for case 13 + * Hard-coded tests for the subconfiguration determination + * + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +/* 13: sub configs */ +static const char subconfig13[64] = { +/* 0: 0,0,0,0,0,0 */ 0, +/* 1: 1,0,0,0,0,0 */ 1, +/* 2: 0,1,0,0,0,0 */ 2, +/* 3: 1,1,0,0,0,0 */ 7, +/* 4: 0,0,1,0,0,0 */ 3, +/* 5: 1,0,1,0,0,0 */ -1, +/* 6: 0,1,1,0,0,0 */ 11, +/* 7: 1,1,1,0,0,0 */ -1, +/* 8: 0,0,0,1,0,0 */ 4, +/* 9: 1,0,0,1,0,0 */ 8, +/* 10: 0,1,0,1,0,0 */ -1, +/* 11: 1,1,0,1,0,0 */ -1, +/* 12: 0,0,1,1,0,0 */ 14, +/* 13: 1,0,1,1,0,0 */ -1, +/* 14: 0,1,1,1,0,0 */ -1, +/* 15: 1,1,1,1,0,0 */ -1, +/* 16: 0,0,0,0,1,0 */ 5, +/* 17: 1,0,0,0,1,0 */ 9, +/* 18: 0,1,0,0,1,0 */ 12, +/* 19: 1,1,0,0,1,0 */ 23, +/* 20: 0,0,1,0,1,0 */ 15, +/* 21: 1,0,1,0,1,0 */ -1, +/* 22: 0,1,1,0,1,0 */ 21, +/* 23: 1,1,1,0,1,0 */ 38, +/* 24: 0,0,0,1,1,0 */ 17, +/* 25: 1,0,0,1,1,0 */ 20, +/* 26: 0,1,0,1,1,0 */ -1, +/* 27: 1,1,0,1,1,0 */ 36, +/* 28: 0,0,1,1,1,0 */ 26, +/* 29: 1,0,1,1,1,0 */ 33, +/* 30: 0,1,1,1,1,0 */ 30, +/* 31: 1,1,1,1,1,0 */ 44, +/* 32: 0,0,0,0,0,1 */ 6, +/* 33: 1,0,0,0,0,1 */ 10, +/* 34: 0,1,0,0,0,1 */ 13, +/* 35: 1,1,0,0,0,1 */ 19, +/* 36: 0,0,1,0,0,1 */ 16, +/* 37: 1,0,1,0,0,1 */ -1, +/* 38: 0,1,1,0,0,1 */ 25, +/* 39: 1,1,1,0,0,1 */ 37, +/* 40: 0,0,0,1,0,1 */ 18, +/* 41: 1,0,0,1,0,1 */ 24, +/* 42: 0,1,0,1,0,1 */ -1, +/* 43: 1,1,0,1,0,1 */ 35, +/* 44: 0,0,1,1,0,1 */ 22, +/* 45: 1,0,1,1,0,1 */ 32, +/* 46: 0,1,1,1,0,1 */ 29, +/* 47: 1,1,1,1,0,1 */ 43, +/* 48: 0,0,0,0,1,1 */ -1, +/* 49: 1,0,0,0,1,1 */ -1, +/* 50: 0,1,0,0,1,1 */ -1, +/* 51: 1,1,0,0,1,1 */ 34, +/* 52: 0,0,1,0,1,1 */ -1, +/* 53: 1,0,1,0,1,1 */ -1, +/* 54: 0,1,1,0,1,1 */ 28, +/* 55: 1,1,1,0,1,1 */ 42, +/* 56: 0,0,0,1,1,1 */ -1, +/* 57: 1,0,0,1,1,1 */ 31, +/* 58: 0,1,0,1,1,1 */ -1, +/* 59: 1,1,0,1,1,1 */ 41, +/* 60: 0,0,1,1,1,1 */ 27, +/* 61: 1,0,1,1,1,1 */ 40, +/* 62: 0,1,1,1,1,1 */ 39, +/* 63: 1,1,1,1,1,1 */ 45, +}; + + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 13.1 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +/* 13.1 */ +static const char tiling13_1[2][12] = { +/* 165: 0, 2, 5, 7, */ { 11, 7, 6, 1, 2, 10, 8, 3, 0, 9, 5, 4 }, +/* 90: 1, 3, 4, 6, */ { 8, 4, 7, 2, 3, 11, 9, 0, 1, 10, 6, 5 } +}; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 13.1 inverted + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +/* 13.1 */ +static const char tiling13_1_[2][12] = { +/* 165: 0, 2, 5, 7, */ { 7, 4, 8, 11, 3, 2, 1, 0, 9, 5, 6, 10 }, +/* 90: 1, 3, 4, 6, */ { 6, 7, 11, 10, 2, 1, 0, 3, 8, 4, 5, 9 } +}; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 13.2 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +/* 13.2 */ +static const char tiling13_2[2][6][18] = { +/* 165: 0, 2, 5, 7, */ { + /* 1 */ { 1, 2, 10, 11, 7, 6, 3, 4, 8, 4, 3, 5, 0, 5, 3, 5, 0, 9 }, + /* 2 */ { 8, 3, 0, 11, 7, 6, 9, 1, 4, 2, 4, 1, 4, 2, 5, 10, 5, 2 }, + /* 3 */ { 9, 5, 4, 8, 3, 0, 1, 6, 10, 6, 1, 7, 2, 7, 1, 7, 2, 11 }, + /* 4 */ { 9, 5, 4, 1, 2, 10, 11, 3, 6, 0, 6, 3, 6, 0, 7, 8, 7, 0 }, + /* 5 */ { 9, 5, 4, 11, 7, 6, 0, 10, 1, 10, 0, 8, 10, 8, 2, 3, 2, 8 }, + /* 6 */ { 1, 2, 10, 3, 0, 8, 4, 9, 7, 11, 7, 9, 5, 11, 9, 11, 5, 6 } +}, +/* 90: 1, 3, 4, 6, */ { + /* 1 */ { 2, 3, 11, 8, 4, 7, 0, 5, 9, 5, 0, 6, 1, 6, 0, 6, 1, 10 }, + /* 2 */ { 9, 0, 1, 8, 4, 7, 10, 2, 5, 3, 5, 2, 5, 3, 6, 11, 6, 3 }, + /* 3 */ { 6, 5, 10, 9, 0, 1, 2, 7, 11, 7, 2, 4, 3, 4, 2, 4, 3, 8 }, + /* 4 */ { 6, 5, 10, 2, 3, 11, 8, 0, 7, 1, 7, 0, 7, 1, 4, 9, 4, 1 }, + /* 5 */ { 6, 5, 10, 8, 4, 7, 1, 11, 2, 11, 1, 9, 11, 9, 3, 0, 3, 9 }, + /* 6 */ { 2, 3, 11, 0, 1, 9, 5, 10, 4, 8, 4, 10, 6, 8, 10, 8, 6, 7 } +} }; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 13.2 inverted + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +/* 13.2 */ +static const char tiling13_2_[2][6][18] = { +/* 165: 0, 2, 5, 7, */ { + /* 1 */ { 10, 5, 6, 11, 3, 2, 7, 0, 8, 0, 7, 1, 4, 1, 7, 1, 4, 9 }, + /* 2 */ { 11, 3, 2, 7, 4, 8, 9, 5, 0, 6, 0, 5, 0, 6, 1, 10, 1, 6 }, + /* 3 */ { 1, 0, 9, 7, 4, 8, 5, 2, 10, 2, 5, 3, 6, 3, 5, 3, 6, 11 }, + /* 4 */ { 10, 5, 6, 1, 0, 9, 11, 7, 2, 4, 2, 7, 2, 4, 3, 8, 3, 4 }, + /* 5 */ { 10, 5, 6, 7, 4, 8, 2, 11, 1, 9, 1, 11, 3, 9, 11, 9, 3, 0 }, + /* 6 */ { 11, 3, 2, 9, 1, 0, 4, 10, 5, 10, 4, 8, 10, 8, 6, 7, 6, 8 } +}, +/* 90: 1, 3, 4, 6, */ { + /* 1 */ { 6, 7, 11, 8, 0, 3, 4, 1, 9, 1, 4, 2, 5, 2, 4, 2, 5, 10 }, + /* 2 */ { 8, 0, 3, 4, 5, 9, 10, 6, 1, 7, 1, 6, 1, 7, 2, 11, 2, 7 }, + /* 3 */ { 2, 1, 10, 4, 5, 9, 6, 3, 11, 3, 6, 0, 7, 0, 6, 0, 7, 8 }, + /* 4 */ { 6, 7, 11, 2, 1, 10, 8, 4, 3, 5, 3, 4, 3, 5, 0, 9, 0, 5 }, + /* 5 */ { 6, 7, 11, 4, 5, 9, 3, 8, 2, 10, 2, 8, 0, 10, 8, 10, 0, 1 }, + /* 6 */ { 8, 0, 3, 10, 2, 1, 5, 11, 6, 11, 5, 9, 11, 9, 7, 4, 7, 9 } +} }; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 13.3 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +/* 13.3 */ +static const char tiling13_3[2][12][30] = { +/* 165: 0, 2, 5, 7, */ { + /* 1,2 */ { 11, 7, 6, 12, 2, 10, 12, 10, 5, 12, 5, 4, 12, 4, 8, 12, 8, 3, 12, 3, 0, 12, 0, 9, 12, 9, 1, 12, 1, 2 }, + /* 1,4 */ { 1, 2, 10, 9, 5, 12, 0, 9, 12, 3, 0, 12, 11, 3, 12, 6, 11, 12, 7, 6, 12, 8, 7, 12, 4, 8, 12, 5, 4, 12 }, + /* 1,5 */ { 11, 7, 6, 12, 5, 4, 12, 4, 8, 12, 8, 3, 12, 3, 2, 12, 2, 10, 12, 10, 1, 12, 1, 0, 12, 0, 9, 12, 9, 5 }, + /* 1,6 */ { 1, 2, 10, 12, 3, 0, 12, 0, 9, 12, 9, 5, 12, 5, 6, 12, 6, 11, 12, 11, 7, 12, 7, 4, 12, 4, 8, 12, 8, 3 }, + /* 2,3 */ { 8, 3, 0, 11, 7, 12, 2, 11, 12, 1, 2, 12, 9, 1, 12, 4, 9, 12, 5, 4, 12, 10, 5, 12, 6, 10, 12, 7, 6, 12 }, + /* 2,5 */ { 11, 7, 6, 5, 4, 12, 10, 5, 12, 2, 10, 12, 3, 2, 12, 8, 3, 12, 0, 8, 12, 1, 0, 12, 9, 1, 12, 4, 9, 12 }, + /* 2,6 */ { 8, 3, 0, 1, 2, 12, 9, 1, 12, 4, 9, 12, 7, 4, 12, 11, 7, 12, 6, 11, 12, 5, 6, 12, 10, 5, 12, 2, 10, 12 }, + /* 3,4 */ { 9, 5, 4, 12, 0, 8, 12, 8, 7, 12, 7, 6, 12, 6, 10, 12, 10, 1, 12, 1, 2, 12, 2, 11, 12, 11, 3, 12, 3, 0 }, + /* 3,5 */ { 9, 5, 4, 12, 7, 6, 12, 6, 10, 12, 10, 1, 12, 1, 0, 12, 0, 8, 12, 8, 3, 12, 3, 2, 12, 2, 11, 12, 11, 7 }, + /* 3,6 */ { 8, 3, 0, 12, 1, 2, 12, 2, 11, 12, 11, 7, 12, 7, 4, 12, 4, 9, 12, 9, 5, 12, 5, 6, 12, 6, 10, 12, 10, 1 }, + /* 4,5 */ { 9, 5, 4, 7, 6, 12, 8, 7, 12, 0, 8, 12, 1, 0, 12, 10, 1, 12, 2, 10, 12, 3, 2, 12, 11, 3, 12, 6, 11, 12 }, + /* 4,6 */ { 1, 2, 10, 3, 0, 12, 11, 3, 12, 6, 11, 12, 5, 6, 12, 9, 5, 12, 4, 9, 12, 7, 4, 12, 8, 7, 12, 0, 8, 12 } +}, +/* 90: 1, 3, 4, 6, */ { + /* 1,2 */ { 8, 4, 7, 12, 3, 11, 12, 11, 6, 12, 6, 5, 12, 5, 9, 12, 9, 0, 12, 0, 1, 12, 1, 10, 12, 10, 2, 12, 2, 3 }, + /* 1,4 */ { 2, 3, 11, 10, 6, 12, 1, 10, 12, 0, 1, 12, 8, 0, 12, 7, 8, 12, 4, 7, 12, 9, 4, 12, 5, 9, 12, 6, 5, 12 }, + /* 1,5 */ { 8, 4, 7, 12, 6, 5, 12, 5, 9, 12, 9, 0, 12, 0, 3, 12, 3, 11, 12, 11, 2, 12, 2, 1, 12, 1, 10, 12, 10, 6 }, + /* 1,6 */ { 2, 3, 11, 12, 0, 1, 12, 1, 10, 12, 10, 6, 12, 6, 7, 12, 7, 8, 12, 8, 4, 12, 4, 5, 12, 5, 9, 12, 9, 0 }, + /* 2,3 */ { 0, 1, 9, 8, 4, 12, 3, 8, 12, 2, 3, 12, 10, 2, 12, 5, 10, 12, 6, 5, 12, 11, 6, 12, 7, 11, 12, 4, 7, 12 }, + /* 2,5 */ { 8, 4, 7, 6, 5, 12, 11, 6, 12, 3, 11, 12, 0, 3, 12, 9, 0, 12, 1, 9, 12, 2, 1, 12, 10, 2, 12, 5, 10, 12 }, + /* 2,6 */ { 9, 0, 1, 2, 3, 12, 10, 2, 12, 5, 10, 12, 4, 5, 12, 8, 4, 12, 7, 8, 12, 6, 7, 12, 11, 6, 12, 3, 11, 12 }, + /* 3,4 */ { 6, 5, 10, 12, 1, 9, 12, 9, 4, 12, 4, 7, 12, 7, 11, 12, 11, 2, 12, 2, 3, 12, 3, 8, 12, 8, 0, 12, 0, 1 }, + /* 3,5 */ { 6, 5, 10, 12, 4, 7, 12, 7, 11, 12, 11, 2, 12, 2, 1, 12, 1, 9, 12, 9, 0, 12, 0, 3, 12, 3, 8, 12, 8, 4 }, + /* 3,6 */ { 9, 0, 1, 12, 2, 3, 12, 3, 8, 12, 8, 4, 12, 4, 5, 12, 5, 10, 12, 10, 6, 12, 6, 7, 12, 7, 11, 12, 11, 2 }, + /* 4,5 */ { 6, 5, 10, 4, 7, 12, 9, 4, 12, 1, 9, 12, 2, 1, 12, 11, 2, 12, 3, 11, 12, 0, 3, 12, 8, 0, 12, 7, 8, 12 }, + /* 4,6 */ { 2, 3, 11, 0, 1, 12, 8, 0, 12, 7, 8, 12, 6, 7, 12, 10, 6, 12, 5, 10, 12, 4, 5, 12, 9, 4, 12, 1, 9, 12 } +} }; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 13.3, inverted + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +/* 13.3 */ +static const char tiling13_3_[2][12][30] = { +/* 165: 0, 2, 5, 7, */ { + /* 1,2 */ { 3, 2, 11, 8, 7, 12, 0, 8, 12, 1, 0, 12, 10, 1, 12, 6, 10, 12, 5, 6, 12, 9, 5, 12, 4, 9, 12, 7, 4, 12 }, + /* 1,4 */ { 5, 6, 10, 12, 2, 11, 12, 11, 7, 12, 7, 4, 12, 4, 9, 12, 9, 1, 12, 1, 0, 12, 0, 8, 12, 8, 3, 12, 3, 2 }, + /* 1,5 */ { 10, 5, 6, 12, 7, 4, 12, 4, 9, 12, 9, 1, 12, 1, 2, 12, 2, 11, 12, 11, 3, 12, 3, 0, 12, 0, 8, 12, 8, 7 }, + /* 1,6 */ { 11, 3, 2, 12, 1, 0, 12, 0, 8, 12, 8, 7, 12, 7, 6, 12, 6, 10, 12, 10, 5, 12, 5, 4, 12, 4, 9, 12, 9, 1 }, + /* 2,3 */ { 7, 4, 8, 11, 3, 12, 6, 11, 12, 5, 6, 12, 9, 5, 12, 0, 9, 12, 1, 0, 12, 10, 1, 12, 2, 10, 12, 3, 2, 12 }, + /* 2,5 */ { 7, 4, 8, 5, 6, 12, 9, 5, 12, 0, 9, 12, 3, 0, 12, 11, 3, 12, 2, 11, 12, 1, 2, 12, 10, 1, 12, 6, 10, 12 }, + /* 2,6 */ { 11, 3, 2, 1, 0, 12, 10, 1, 12, 6, 10, 12, 7, 6, 12, 8, 7, 12, 4, 8, 12, 5, 4, 12, 9, 5, 12, 0, 9, 12 }, + /* 3,4 */ { 1, 0, 9, 12, 4, 8, 12, 8, 3, 12, 3, 2, 12, 2, 10, 12, 10, 5, 12, 5, 6, 12, 6, 11, 12, 11, 7, 12, 7, 4 }, + /* 3,5 */ { 7, 4, 8, 12, 5, 6, 12, 6, 11, 12, 11, 3, 12, 3, 0, 12, 0, 9, 12, 9, 1, 12, 1, 2, 12, 2, 10, 12, 10, 5 }, + /* 3,6 */ { 1, 0, 9, 12, 3, 2, 12, 2, 10, 12, 10, 5, 12, 5, 4, 12, 4, 8, 12, 8, 7, 12, 7, 6, 12, 6, 11, 12, 11, 3 }, + /* 4,5 */ { 10, 5, 6, 7, 4, 12, 11, 7, 12, 2, 11, 12, 1, 2, 12, 9, 1, 12, 0, 9, 12, 3, 0, 12, 8, 3, 12, 4, 8, 12 }, + /* 4,6 */ { 9, 1, 0, 3, 2, 12, 8, 3, 12, 4, 8, 12, 5, 4, 12, 10, 5, 12, 6, 10, 12, 7, 6, 12, 11, 7, 12, 2, 11, 12 } +}, +/* 90: 1, 3, 4, 6, */ { + /* 1,2 */ { 0, 3, 8, 9, 4, 12, 1, 9, 12, 2, 1, 12, 11, 2, 12, 7, 11, 12, 6, 7, 12, 10, 6, 12, 5, 10, 12, 4, 5, 12 }, + /* 1,4 */ { 11, 6, 7, 12, 3, 8, 12, 8, 4, 12, 4, 5, 12, 5, 10, 12, 10, 2, 12, 2, 1, 12, 1, 9, 12, 9, 0, 12, 0, 3 }, + /* 1,5 */ { 6, 7, 11, 12, 4, 5, 12, 5, 10, 12, 10, 2, 12, 2, 3, 12, 3, 8, 12, 8, 0, 12, 0, 1, 12, 1, 9, 12, 9, 4 }, + /* 1,6 */ { 8, 0, 3, 12, 2, 1, 12, 1, 9, 12, 9, 4, 12, 4, 7, 12, 7, 11, 12, 11, 6, 12, 6, 5, 12, 5, 10, 12, 10, 2 }, + /* 2,3 */ { 4, 5, 9, 8, 0, 12, 7, 8, 12, 6, 7, 12, 10, 6, 12, 1, 10, 12, 2, 1, 12, 11, 2, 12, 3, 11, 12, 0, 3, 12 }, + /* 2,5 */ { 4, 5, 9, 6, 7, 12, 10, 6, 12, 1, 10, 12, 0, 1, 12, 8, 0, 12, 3, 8, 12, 2, 3, 12, 11, 2, 12, 7, 11, 12 }, + /* 2,6 */ { 8, 0, 3, 2, 1, 12, 11, 2, 12, 7, 11, 12, 4, 7, 12, 9, 4, 12, 5, 9, 12, 6, 5, 12, 10, 6, 12, 1, 10, 12 }, + /* 3,4 */ { 2, 1, 10, 12, 5, 9, 12, 9, 0, 12, 0, 3, 12, 3, 11, 12, 11, 6, 12, 6, 7, 12, 7, 8, 12, 8, 4, 12, 4, 5 }, + /* 3,5 */ { 4, 5, 9, 12, 6, 7, 12, 7, 8, 12, 8, 0, 12, 0, 1, 12, 1, 10, 12, 10, 2, 12, 2, 3, 12, 3, 11, 12, 11, 6 }, + /* 3,6 */ { 2, 1, 10, 12, 0, 3, 12, 3, 11, 12, 11, 6, 12, 6, 5, 12, 5, 9, 12, 9, 4, 12, 4, 7, 12, 7, 8, 12, 8, 0 }, + /* 4,5 */ { 6, 7, 11, 4, 5, 12, 8, 4, 12, 3, 8, 12, 2, 3, 12, 10, 2, 12, 1, 10, 12, 0, 1, 12, 9, 0, 12, 5, 9, 12 }, + /* 4,6 */ { 10, 2, 1, 0, 3, 12, 9, 0, 12, 5, 9, 12, 6, 5, 12, 11, 6, 12, 7, 11, 12, 4, 7, 12, 8, 4, 12, 3, 8, 12 } +} }; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 13.4 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +/* 13.4 */ +static const char tiling13_4[2][4][36] = { +/* 165: 0, 2, 5, 7, */ { +/* 1,2,6 */ { 12, 2, 10, 12, 10, 5, 12, 5, 6, 12, 6, 11, 12, 11, 7, 12, 7, 4, 12, 4, 8, 12, 8, 3, 12, 3, 0, 12, 0, 9, 12, 9, 1, 12, 1, 2 }, +/* 1,4,5 */ { 11, 3, 12, 6, 11, 12, 7, 6, 12, 8, 7, 12, 4, 8, 12, 5, 4, 12, 9, 5, 12, 0, 9, 12, 1, 0, 12, 10, 1, 12, 2, 10, 12, 3, 2, 12 }, +/* 2,3,5 */ { 9, 1, 12, 4, 9, 12, 5, 4, 12, 10, 5, 12, 6, 10, 12, 7, 6, 12, 11, 7, 12, 2, 11, 12, 3, 2, 12, 8, 3, 12, 0, 8, 12, 1, 0, 12 }, +/* 3,4,6 */ { 12, 0, 8, 12, 8, 7, 12, 7, 4, 12, 4, 9, 12, 9, 5, 12, 5, 6, 12, 6, 10, 12, 10, 1, 12, 1, 2, 12, 2, 11, 12, 11, 3, 12, 3, 0 } +}, +/* 90: 1, 3, 4, 6, */ { +/* 1,2,6 */ { 12, 3, 11, 12, 11, 6, 12, 6, 7, 12, 7, 8, 12, 8, 4, 12, 4, 5, 12, 5, 9, 12, 9, 0, 12, 0, 1, 12, 1, 10, 12, 10, 2, 12, 2, 3 }, +/* 1,4,5 */ { 8, 0, 12, 7, 8, 12, 4, 7, 12, 9, 4, 12, 5, 9, 12, 6, 5, 12, 10, 6, 12, 1, 10, 12, 2, 1, 12, 11, 2, 12, 3, 11, 12, 0, 3, 12 }, +/* 2,3,5 */ { 10, 2, 12, 5, 10, 12, 6, 5, 12, 11, 6, 12, 7, 11, 12, 4, 7, 12, 8, 4, 12, 3, 8, 12, 0, 3, 12, 9, 0, 12, 1, 9, 12, 2, 1, 12 }, +/* 3,4,6 */ { 12, 1, 9, 12, 9, 4, 12, 4, 5, 12, 5, 10, 12, 10, 6, 12, 6, 7, 12, 7, 11, 12, 11, 2, 12, 2, 3, 12, 3, 8, 12, 8, 0, 12, 0, 1 } +} }; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 13.5.1 + * The support edge for the interior test is marked as the 1st column. + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +/* 13.5.1 */ +static const char tiling13_5_1[2][4][18] = { +/* 165: 0, 2, 5, 7, */ { +/* 1,2,5 */ { 7, 6, 11, 1, 0, 9, 10, 3, 2, 3, 10, 5, 3, 5, 8, 4, 8, 5 }, +/* 1,4,6 */ { 1, 2, 10, 7, 4, 8, 3, 0, 11, 6, 11, 0, 9, 6, 0, 6, 9, 5 }, +/* 2,3,6 */ { 3, 0, 8, 5, 6, 10, 1, 2, 9, 4, 9, 2, 11, 4, 2, 4, 11, 7 }, +/* 3,4,5 */ { 5, 4, 9, 3, 2, 11, 8, 1, 0, 1, 8, 7, 1, 7, 10, 6, 10, 7 } +}, +/* 90: 1, 3, 4, 6, */ { +/* 1,2,5 */ { 4, 7, 8, 2, 1, 10, 11, 0, 3, 0, 11, 6, 0, 6, 9, 5, 9, 6 }, +/* 1,4,6 */ { 2, 3, 11, 4, 5, 9, 0, 1, 8, 7, 8, 1, 10, 7, 1, 7, 10, 6 }, +/* 2,3,6 */ { 0, 1, 9, 6, 7, 11, 2, 3, 10, 5, 10, 3, 8, 5, 3, 5, 8, 4 }, +/* 3,4,5 */ { 6, 5, 10, 0, 3, 8, 9, 2, 1, 2, 9, 4, 2, 4, 11, 7, 11, 4 } +} }; + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 13.5.2 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +/* 13.5.2 */ +static const char tiling13_5_2[2][4][30] = { +/* 165: 0, 2, 5, 7, */ { +/* 1,2,5 */ { 1, 0, 9, 7, 4, 8, 7, 8, 3, 7, 3, 11, 2, 11, 3, 11, 2, 10, 11, 10, 6, 5, 6, 10, 6, 5, 7, 4, 7, 5 }, +/* 1,4,6 */ { 7, 4, 8, 11, 3, 2, 6, 11, 2, 10, 6, 2, 6, 10, 5, 9, 5, 10, 1, 9, 10, 9, 1, 0, 2, 0, 1, 0, 2, 3 }, +/* 2,3,6 */ { 5, 6, 10, 9, 1, 0, 4, 9, 0, 8, 4, 0, 4, 8, 7, 11, 7, 8, 3, 11, 8, 11, 3, 2, 0, 2, 3, 2, 0, 1 }, +/* 3,4,5 */ { 3, 2, 11, 5, 6, 10, 5, 10, 1, 5, 1, 9, 0, 9, 1, 9, 0, 8, 9, 8, 4, 4, 8, 7, 4, 7, 5, 6, 5, 7 } +}, +/* 90: 1, 3, 4, 6, */ { +/* 1,2,5 */ { 2, 1, 10, 4, 5, 9, 4, 9, 0, 4, 0, 8, 3, 8, 0, 8, 3, 11, 8, 11, 7, 6, 7, 11, 7, 6, 4, 5, 4, 6 }, +/* 1,4,6 */ { 4, 5, 9, 8, 0, 3, 7, 8, 3, 11, 7, 3, 7, 11, 6, 10, 6, 11, 2, 10, 11, 10, 2, 1, 3, 1, 2, 1, 3, 0 }, +/* 2,3,6 */ { 6, 7, 11, 10, 2, 1, 5, 10, 1, 9, 5, 1, 5, 9, 4, 8, 4, 9, 0, 8, 9, 8, 0, 3, 1, 3, 0, 3, 1, 2 }, +/* 3,4,5 */ { 0, 3, 8, 6, 7, 11, 6, 11, 2, 6, 2, 10, 1, 10, 2, 10, 1, 9, 10, 9, 5, 5, 9, 4, 5, 4, 6, 7, 6, 4 } +} }; +//_____________________________________________________________________________ + + + +//_____________________________________________________________________________ +/** + * \brief tiling table for case 14 + * For each of the case above, the specific triangulation of the edge + * intersection points is given. + * When a case is ambiguous, there is an auxiliary table that contains + * the face number to test and the tiling table contains the specific + * triangulations depending on the results + * A minus sign means to invert the result of the test. + */ +//----------------------------------------------------------------------------- +static const char tiling14[12][12] = { +/* 71: 0, 1, 2, 6, */ { 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8 }, +/* 43: 0, 1, 3, 5, */ { 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5 }, +/* 147: 0, 1, 4, 7, */ { 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6 }, +/* 29: 0, 2, 3, 4, */ { 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4 }, +/* 201: 0, 3, 6, 7, */ { 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5 }, +/* 113: 0, 4, 5, 6, */ { 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10 }, +/* 142: 1, 2, 3, 7, */ { 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7 }, +/* 54: 1, 2, 4, 5, */ { 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2 }, +/* 226: 1, 5, 6, 7, */ { 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11 }, +/* 108: 2, 3, 5, 6, */ { 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3 }, +/* 212: 2, 4, 6, 7, */ { 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8 }, +/* 184: 3, 4, 5, 7, */ { 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2 } +}; +//_____________________________________________________________________________ + + + +//_____________________________________________________________________________ +/** + * \brief original Marching Cubes implementation + * For each of the possible vertex states listed in this table there is a + * specific triangulation of the edge intersection points. The table lists + * all of them in the form of 0-5 edge triples with the list terminated by + * the invalid value -1. For example: casesClassic[3] list the 2 triangles + * formed when cube[0] and cube[1] are inside of the surface, but the rest of + * the cube is not. + */ +//----------------------------------------------------------------------------- +static const char casesClassic[256][16] = { +/* 0: */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 1: 0, */ { 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 2: 1, */ { 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 3: 0, 1, */ { 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 4: 2, */ { 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 5: 0, 2, */ { 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 6: 1, 2, */ { 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 7: 0, 1, 2, */ { 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1 }, +/* 8: 3, */ { 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 9: 0, 3, */ { 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 10: 1, 3, */ { 1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 11: 0, 1, 3, */ { 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1 }, +/* 12: 2, 3, */ { 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 13: 0, 2, 3, */ { 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1 }, +/* 14: 1, 2, 3, */ { 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1 }, +/* 15: 0, 1, 2, 3, */ { 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 16: 4, */ { 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 17: 0, 4, */ { 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 18: 1, 4, */ { 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 19: 0, 1, 4, */ { 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1 }, +/* 20: 2, 4, */ { 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 21: 0, 2, 4, */ { 3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1 }, +/* 22: 1, 2, 4, */ { 9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 }, +/* 23: 0, 1, 2, 4, */ { 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1 }, +/* 24: 3, 4, */ { 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 25: 0, 3, 4, */ { 11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1 }, +/* 26: 1, 3, 4, */ { 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 }, +/* 27: 0, 1, 3, 4, */ { 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1 }, +/* 28: 2, 3, 4, */ { 3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1 }, +/* 29: 0, 2, 3, 4, */ { 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1 }, +/* 30: 1, 2, 3, 4, */ { 4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1 }, +/* 31: 0, 1, 2, 3, 4, */ { 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1 }, +/* 32: 5, */ { 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 33: 0, 5, */ { 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 34: 1, 5, */ { 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 35: 0, 1, 5, */ { 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1 }, +/* 36: 2, 5, */ { 1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 37: 0, 2, 5, */ { 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 }, +/* 38: 1, 2, 5, */ { 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1 }, +/* 39: 0, 1, 2, 5, */ { 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1 }, +/* 40: 3, 5, */ { 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 41: 0, 3, 5, */ { 0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 }, +/* 42: 1, 3, 5, */ { 0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 }, +/* 43: 0, 1, 3, 5, */ { 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1 }, +/* 44: 2, 3, 5, */ { 10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1 }, +/* 45: 0, 2, 3, 5, */ { 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1 }, +/* 46: 1, 2, 3, 5, */ { 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1 }, +/* 47: 0, 1, 2, 3, 5, */ { 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1 }, +/* 48: 4, 5, */ { 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 49: 0, 4, 5, */ { 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1 }, +/* 50: 1, 4, 5, */ { 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1 }, +/* 51: 0, 1, 4, 5, */ { 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 52: 2, 4, 5, */ { 9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1 }, +/* 53: 0, 2, 4, 5, */ { 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1 }, +/* 54: 1, 2, 4, 5, */ { 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1 }, +/* 55: 0, 1, 2, 4, 5, */ { 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1 }, +/* 56: 3, 4, 5, */ { 7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1 }, +/* 57: 0, 3, 4, 5, */ { 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1 }, +/* 58: 1, 3, 4, 5, */ { 2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1 }, +/* 59: 0, 1, 3, 4, 5, */ { 11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1 }, +/* 60: 2, 3, 4, 5, */ { 9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1 }, +/* 61: 0, 2, 3, 4, 5, */ { 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1 }, +/* 62: 1, 2, 3, 4, 5, */ { 11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1 }, +/* 63: 0, 1, 2, 3, 4, 5, */ { 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 64: 6, */ { 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 65: 0, 6, */ { 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 66: 1, 6, */ { 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 67: 0, 1, 6, */ { 1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 }, +/* 68: 2, 6, */ { 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 69: 0, 2, 6, */ { 1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1 }, +/* 70: 1, 2, 6, */ { 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1 }, +/* 71: 0, 1, 2, 6, */ { 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1 }, +/* 72: 3, 6, */ { 2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 73: 0, 3, 6, */ { 11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 }, +/* 74: 1, 3, 6, */ { 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 }, +/* 75: 0, 1, 3, 6, */ { 5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1 }, +/* 76: 2, 3, 6, */ { 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1 }, +/* 77: 0, 2, 3, 6, */ { 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1 }, +/* 78: 1, 2, 3, 6, */ { 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1 }, +/* 79: 0, 1, 2, 3, 6, */ { 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1 }, +/* 80: 4, 6, */ { 5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 81: 0, 4, 6, */ { 4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1 }, +/* 82: 1, 4, 6, */ { 1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 }, +/* 83: 0, 1, 4, 6, */ { 10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1 }, +/* 84: 2, 4, 6, */ { 6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1 }, +/* 85: 0, 2, 4, 6, */ { 1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1 }, +/* 86: 1, 2, 4, 6, */ { 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1 }, +/* 87: 0, 1, 2, 4, 6, */ { 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1 }, +/* 88: 3, 4, 6, */ { 3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 }, +/* 89: 0, 3, 4, 6, */ { 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1 }, +/* 90: 1, 3, 4, 6, */ { 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1 }, +/* 91: 0, 1, 3, 4, 6, */ { 9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1 }, +/* 92: 2, 3, 4, 6, */ { 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1 }, +/* 93: 0, 2, 3, 4, 6, */ { 5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1 }, +/* 94: 1, 2, 3, 4, 6, */ { 0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1 }, +/* 95: 0, 1, 2, 3, 4, 6, */ { 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1 }, +/* 96: 5, 6, */ { 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 97: 0, 5, 6, */ { 4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1 }, +/* 98: 1, 5, 6, */ { 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1 }, +/* 99: 0, 1, 5, 6, */ { 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1 }, +/* 100: 2, 5, 6, */ { 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1 }, +/* 101: 0, 2, 5, 6, */ { 3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1 }, +/* 102: 1, 2, 5, 6, */ { 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 103: 0, 1, 2, 5, 6, */ { 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1 }, +/* 104: 3, 5, 6, */ { 10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1 }, +/* 105: 0, 3, 5, 6, */ { 0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1 }, +/* 106: 1, 3, 5, 6, */ { 3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1 }, +/* 107: 0, 1, 3, 5, 6, */ { 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1 }, +/* 108: 2, 3, 5, 6, */ { 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1 }, +/* 109: 0, 2, 3, 5, 6, */ { 8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1 }, +/* 110: 1, 2, 3, 5, 6, */ { 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1 }, +/* 111: 0, 1, 2, 3, 5, 6, */ { 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 112: 4, 5, 6, */ { 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1 }, +/* 113: 0, 4, 5, 6, */ { 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1 }, +/* 114: 1, 4, 5, 6, */ { 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1 }, +/* 115: 0, 1, 4, 5, 6, */ { 10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1 }, +/* 116: 2, 4, 5, 6, */ { 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1 }, +/* 117: 0, 2, 4, 5, 6, */ { 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1 }, +/* 118: 1, 2, 4, 5, 6, */ { 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1 }, +/* 119: 0, 1, 2, 4, 5, 6, */ { 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 120: 3, 4, 5, 6, */ { 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1 }, +/* 121: 0, 3, 4, 5, 6, */ { 2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1 }, +/* 122: 1, 3, 4, 5, 6, */ { 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1 }, +/* 123: 0, 1, 3, 4, 5, 6, */ { 11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1 }, +/* 124: 2, 3, 4, 5, 6, */ { 8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1 }, +/* 125: 0, 2, 3, 4, 5, 6, */ { 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 126: 1, 2, 3, 4, 5, 6, */ { 7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1 }, +/* 127: 0, 1, 2, 3, 4, 5, 6, */ { 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 128: 7, */ { 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 129: 0, 7, */ { 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 130: 1, 7, */ { 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 131: 0, 1, 7, */ { 8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 }, +/* 132: 2, 7, */ { 10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 133: 0, 2, 7, */ { 1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 }, +/* 134: 1, 2, 7, */ { 2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 }, +/* 135: 0, 1, 2, 7, */ { 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1 }, +/* 136: 3, 7, */ { 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 137: 0, 3, 7, */ { 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1 }, +/* 138: 1, 3, 7, */ { 2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1 }, +/* 139: 0, 1, 3, 7, */ { 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1 }, +/* 140: 2, 3, 7, */ { 10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1 }, +/* 141: 0, 2, 3, 7, */ { 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1 }, +/* 142: 1, 2, 3, 7, */ { 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1 }, +/* 143: 0, 1, 2, 3, 7, */ { 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1 }, +/* 144: 4, 7, */ { 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 145: 0, 4, 7, */ { 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1 }, +/* 146: 1, 4, 7, */ { 8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1 }, +/* 147: 0, 1, 4, 7, */ { 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1 }, +/* 148: 2, 4, 7, */ { 6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1 }, +/* 149: 0, 2, 4, 7, */ { 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1 }, +/* 150: 1, 2, 4, 7, */ { 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1 }, +/* 151: 0, 1, 2, 4, 7, */ { 10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1 }, +/* 152: 3, 4, 7, */ { 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1 }, +/* 153: 0, 3, 4, 7, */ { 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 154: 1, 3, 4, 7, */ { 1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1 }, +/* 155: 0, 1, 3, 4, 7, */ { 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1 }, +/* 156: 2, 3, 4, 7, */ { 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1 }, +/* 157: 0, 2, 3, 4, 7, */ { 10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1 }, +/* 158: 1, 2, 3, 4, 7, */ { 4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1 }, +/* 159: 0, 1, 2, 3, 4, 7, */ { 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 160: 5, 7, */ { 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 161: 0, 5, 7, */ { 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 }, +/* 162: 1, 5, 7, */ { 5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 }, +/* 163: 0, 1, 5, 7, */ { 11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1 }, +/* 164: 2, 5, 7, */ { 9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 }, +/* 165: 0, 2, 5, 7, */ { 6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1 }, +/* 166: 1, 2, 5, 7, */ { 7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1 }, +/* 167: 0, 1, 2, 5, 7, */ { 3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1 }, +/* 168: 3, 5, 7, */ { 7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1 }, +/* 169: 0, 3, 5, 7, */ { 9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1 }, +/* 170: 1, 3, 5, 7, */ { 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1 }, +/* 171: 0, 1, 3, 5, 7, */ { 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1 }, +/* 172: 2, 3, 5, 7, */ { 9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1 }, +/* 173: 0, 2, 3, 5, 7, */ { 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1 }, +/* 174: 1, 2, 3, 5, 7, */ { 4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1 }, +/* 175: 0, 1, 2, 3, 5, 7, */ { 7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1 }, +/* 176: 4, 5, 7, */ { 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1 }, +/* 177: 0, 4, 5, 7, */ { 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1 }, +/* 178: 1, 4, 5, 7, */ { 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1 }, +/* 179: 0, 1, 4, 5, 7, */ { 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1 }, +/* 180: 2, 4, 5, 7, */ { 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1 }, +/* 181: 0, 2, 4, 5, 7, */ { 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1 }, +/* 182: 1, 2, 4, 5, 7, */ { 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1 }, +/* 183: 0, 1, 2, 4, 5, 7, */ { 6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1 }, +/* 184: 3, 4, 5, 7, */ { 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1 }, +/* 185: 0, 3, 4, 5, 7, */ { 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1 }, +/* 186: 1, 3, 4, 5, 7, */ { 1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1 }, +/* 187: 0, 1, 3, 4, 5, 7, */ { 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 188: 2, 3, 4, 5, 7, */ { 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1 }, +/* 189: 0, 2, 3, 4, 5, 7, */ { 10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1 }, +/* 190: 1, 2, 3, 4, 5, 7, */ { 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 191: 0, 1, 2, 3, 4, 5, 7, */ { 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 192: 6, 7, */ { 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 193: 0, 6, 7, */ { 11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1 }, +/* 194: 1, 6, 7, */ { 5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1 }, +/* 195: 0, 1, 6, 7, */ { 10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1 }, +/* 196: 2, 6, 7, */ { 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1 }, +/* 197: 0, 2, 6, 7, */ { 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1 }, +/* 198: 1, 2, 6, 7, */ { 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1 }, +/* 199: 0, 1, 2, 6, 7, */ { 7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1 }, +/* 200: 3, 6, 7, */ { 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1 }, +/* 201: 0, 3, 6, 7, */ { 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1 }, +/* 202: 1, 3, 6, 7, */ { 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1 }, +/* 203: 0, 1, 3, 6, 7, */ { 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1 }, +/* 204: 2, 3, 6, 7, */ { 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 205: 0, 2, 3, 6, 7, */ { 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1 }, +/* 206: 1, 2, 3, 6, 7, */ { 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1 }, +/* 207: 0, 1, 2, 3, 6, 7, */ { 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 208: 4, 6, 7, */ { 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1 }, +/* 209: 0, 4, 6, 7, */ { 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1 }, +/* 210: 1, 4, 6, 7, */ { 0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1 }, +/* 211: 0, 1, 4, 6, 7, */ { 10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1 }, +/* 212: 2, 4, 6, 7, */ { 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1 }, +/* 213: 0, 2, 4, 6, 7, */ { 0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1 }, +/* 214: 1, 2, 4, 6, 7, */ { 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1 }, +/* 215: 0, 1, 2, 4, 6, 7, */ { 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 216: 3, 4, 6, 7, */ { 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1 }, +/* 217: 0, 3, 4, 6, 7, */ { 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1 }, +/* 218: 1, 3, 4, 6, 7, */ { 3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1 }, +/* 219: 0, 1, 3, 4, 6, 7, */ { 5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1 }, +/* 220: 2, 3, 4, 6, 7, */ { 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1 }, +/* 221: 0, 2, 3, 4, 6, 7, */ { 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 222: 1, 2, 3, 4, 6, 7, */ { 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1 }, +/* 223: 0, 1, 2, 3, 4, 6, 7, */ { 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 224: 5, 6, 7, */ { 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1 }, +/* 225: 0, 5, 6, 7, */ { 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1 }, +/* 226: 1, 5, 6, 7, */ { 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1 }, +/* 227: 0, 1, 5, 6, 7, */ { 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1 }, +/* 228: 2, 5, 6, 7, */ { 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1 }, +/* 229: 0, 2, 5, 6, 7, */ { 9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1 }, +/* 230: 1, 2, 5, 6, 7, */ { 11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1 }, +/* 231: 0, 1, 2, 5, 6, 7, */ { 11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1 }, +/* 232: 3, 5, 6, 7, */ { 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1 }, +/* 233: 0, 3, 5, 6, 7, */ { 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1 }, +/* 234: 1, 3, 5, 6, 7, */ { 3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1 }, +/* 235: 0, 1, 3, 5, 6, 7, */ { 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 236: 2, 3, 5, 6, 7, */ { 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1 }, +/* 237: 0, 2, 3, 5, 6, 7, */ { 4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1 }, +/* 238: 1, 2, 3, 5, 6, 7, */ { 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 239: 0, 1, 2, 3, 5, 6, 7, */ { 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 240: 4, 5, 6, 7, */ { 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 241: 0, 4, 5, 6, 7, */ { 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1 }, +/* 242: 1, 4, 5, 6, 7, */ { 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1 }, +/* 243: 0, 1, 4, 5, 6, 7, */ { 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 244: 2, 4, 5, 6, 7, */ { 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1 }, +/* 245: 0, 2, 4, 5, 6, 7, */ { 3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1 }, +/* 246: 1, 2, 4, 5, 6, 7, */ { 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 247: 0, 1, 2, 4, 5, 6, 7, */ { 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 248: 3, 4, 5, 6, 7, */ { 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1 }, +/* 249: 0, 3, 4, 5, 6, 7, */ { 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 250: 1, 3, 4, 5, 6, 7, */ { 2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1 }, +/* 251: 0, 1, 3, 4, 5, 6, 7, */ { 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 252: 2, 3, 4, 5, 6, 7, */ { 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 253: 0, 2, 3, 4, 5, 6, 7, */ { 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 254: 1, 2, 3, 4, 5, 6, 7, */ { 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +/* 255: 0, 1, 2, 3, 4, 5, 6, 7, */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } +}; +//_____________________________________________________________________________ + + + +#endif // _LOOKUPTABLE_H_ diff --git a/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/MarchingCubes.cpp b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/MarchingCubes.cpp new file mode 100755 index 00000000000..d9012f0405a --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/MarchingCubes.cpp @@ -0,0 +1,1302 @@ +/** + * @file MarchingCubes.cpp + * @author Thomas Lewiner <thomas.lewiner@polytechnique.org> + * @author Math Dept, PUC-Rio + * @version 0.2 + * @date 12/08/2002 + * + * @brief MarchingCubes Algorithm + */ +//________________________________________________ + + +#if !defined(WIN32) || defined(__CYGWIN__) +#pragma implementation +#endif // WIN32 + +#include <math.h> +#include <time.h> +#include <memory.h> +#include <stdlib.h> +#include <float.h> +#include "MarchingCubes.h" +#include "ply.h" +#include "LookUpTable.h" + +// step size of the arrays of vertices and triangles +#define ALLOC_SIZE 65536 + +//_____________________________________________________________________________ +// print cube for debug +void MarchingCubes::print_cube() { printf( "\t%f %f %f %f %f %f %f %f\n", _cube[0], _cube[1], _cube[2], _cube[3], _cube[4], _cube[5], _cube[6], _cube[7]) ; } +//_____________________________________________________________________________ + + + +//_____________________________________________________________________________ +// Constructor +MarchingCubes::MarchingCubes( const int size_x /*= -1*/, const int size_y /*= -1*/, const int size_z /*= -1*/ ) : +//----------------------------------------------------------------------------- + _originalMC(false), + _ext_data (false), + _size_x (size_x), + _size_y (size_y), + _size_z (size_z), + _data ((real *)NULL), + _x_verts (( int *)NULL), + _y_verts (( int *)NULL), + _z_verts (( int *)NULL), + _nverts (0), + _ntrigs (0), + _Nverts (0), + _Ntrigs (0), + _vertices (( Vertex *)NULL), + _triangles ((Triangle*)NULL) +{} +//_____________________________________________________________________________ + + + +//_____________________________________________________________________________ +// Destructor +MarchingCubes::~MarchingCubes() +//----------------------------------------------------------------------------- +{ + clean_all() ; +} +//_____________________________________________________________________________ + + + +//_____________________________________________________________________________ +// main algorithm +void MarchingCubes::run( real iso ) +//----------------------------------------------------------------------------- +{ + clock_t time = clock() ; + + compute_intersection_points( iso ) ; + + for( _k = 0 ; _k < _size_z-1 ; _k++ ) + for( _j = 0 ; _j < _size_y-1 ; _j++ ) + for( _i = 0 ; _i < _size_x-1 ; _i++ ) + { + _lut_entry = 0 ; + for( int p = 0 ; p < 8 ; ++p ) + { + _cube[p] = get_data( _i+((p^(p>>1))&1), _j+((p>>1)&1), _k+((p>>2)&1) ) - iso ; + if( fabs( _cube[p] ) < FLT_EPSILON ) _cube[p] = FLT_EPSILON ; + if( _cube[p] > 0 ) _lut_entry += 1 << p ; + } +/* + if( ( _cube[0] = get_data( _i , _j , _k ) ) > 0 ) _lut_entry += 1 ; + if( ( _cube[1] = get_data(_i+1, _j , _k ) ) > 0 ) _lut_entry += 2 ; + if( ( _cube[2] = get_data(_i+1,_j+1, _k ) ) > 0 ) _lut_entry += 4 ; + if( ( _cube[3] = get_data( _i ,_j+1, _k ) ) > 0 ) _lut_entry += 8 ; + if( ( _cube[4] = get_data( _i , _j ,_k+1) ) > 0 ) _lut_entry += 16 ; + if( ( _cube[5] = get_data(_i+1, _j ,_k+1) ) > 0 ) _lut_entry += 32 ; + if( ( _cube[6] = get_data(_i+1,_j+1,_k+1) ) > 0 ) _lut_entry += 64 ; + if( ( _cube[7] = get_data( _i ,_j+1,_k+1) ) > 0 ) _lut_entry += 128 ; +*/ + process_cube( ) ; + } + + printf("Marching Cubes ran in %lf secs.\n", (double)(clock() - time)/CLOCKS_PER_SEC) ; +} +//_____________________________________________________________________________ + + + +//_____________________________________________________________________________ +// init temporary structures (must set sizes before call) +void MarchingCubes::init_temps() +//----------------------------------------------------------------------------- +{ + if( !_ext_data ) + _data = new real [_size_x * _size_y * _size_z] ; + _x_verts = new int [_size_x * _size_y * _size_z] ; + _y_verts = new int [_size_x * _size_y * _size_z] ; + _z_verts = new int [_size_x * _size_y * _size_z] ; + + memset( _x_verts, -1, _size_x * _size_y * _size_z * sizeof( int ) ) ; + memset( _y_verts, -1, _size_x * _size_y * _size_z * sizeof( int ) ) ; + memset( _z_verts, -1, _size_x * _size_y * _size_z * sizeof( int ) ) ; +} +//_____________________________________________________________________________ + + + +//_____________________________________________________________________________ +// init all structures (must set sizes before call) +void MarchingCubes::init_all () +//----------------------------------------------------------------------------- +{ + init_temps() ; + + _nverts = _ntrigs = 0 ; + _Nverts = _Ntrigs = ALLOC_SIZE ; + _vertices = new Vertex [_Nverts] ; + _triangles = new Triangle[_Ntrigs] ; +} +//_____________________________________________________________________________ + + + +//_____________________________________________________________________________ +// clean temporary structures +void MarchingCubes::clean_temps() +//----------------------------------------------------------------------------- +{ + if( !_ext_data ) + delete [] _data; + delete [] _x_verts; + delete [] _y_verts; + delete [] _z_verts; + + if( !_ext_data ) + _data = (real*)NULL ; + _x_verts = (int*)NULL ; + _y_verts = (int*)NULL ; + _z_verts = (int*)NULL ; +} +//_____________________________________________________________________________ + + + +//_____________________________________________________________________________ +// clean all structures +void MarchingCubes::clean_all() +//----------------------------------------------------------------------------- +{ + clean_temps() ; + delete [] _vertices ; + delete [] _triangles ; + _vertices = (Vertex *)NULL ; + _triangles = (Triangle *)NULL ; + _nverts = _ntrigs = 0 ; + _Nverts = _Ntrigs = 0 ; + + _size_x = _size_y = _size_z = -1 ; +} +//_____________________________________________________________________________ + + + +//_____________________________________________________________________________ +//_____________________________________________________________________________ + + +//_____________________________________________________________________________ +// Compute the intersection points +void MarchingCubes::compute_intersection_points( real iso ) +//----------------------------------------------------------------------------- +{ + for( _k = 0 ; _k < _size_z ; _k++ ) + for( _j = 0 ; _j < _size_y ; _j++ ) + for( _i = 0 ; _i < _size_x ; _i++ ) + { + _cube[0] = get_data( _i, _j, _k ) - iso ; + if( _i < _size_x - 1 ) _cube[1] = get_data(_i+1, _j , _k ) - iso ; + else _cube[1] = _cube[0] ; + + if( _j < _size_y - 1 ) _cube[3] = get_data( _i ,_j+1, _k ) - iso ; + else _cube[3] = _cube[0] ; + + if( _k < _size_z - 1 ) _cube[4] = get_data( _i , _j ,_k+1) - iso ; + else _cube[4] = _cube[0] ; + + if( fabs( _cube[0] ) < FLT_EPSILON ) _cube[0] = FLT_EPSILON ; + if( fabs( _cube[1] ) < FLT_EPSILON ) _cube[1] = FLT_EPSILON ; + if( fabs( _cube[3] ) < FLT_EPSILON ) _cube[3] = FLT_EPSILON ; + if( fabs( _cube[4] ) < FLT_EPSILON ) _cube[4] = FLT_EPSILON ; + + if( _cube[0] < 0 ) + { + if( _cube[1] > 0 ) set_x_vert( add_x_vertex( ), _i,_j,_k ) ; + if( _cube[3] > 0 ) set_y_vert( add_y_vertex( ), _i,_j,_k ) ; + if( _cube[4] > 0 ) set_z_vert( add_z_vertex( ), _i,_j,_k ) ; + } + else + { + if( _cube[1] < 0 ) set_x_vert( add_x_vertex( ), _i,_j,_k ) ; + if( _cube[3] < 0 ) set_y_vert( add_y_vertex( ), _i,_j,_k ) ; + if( _cube[4] < 0 ) set_z_vert( add_z_vertex( ), _i,_j,_k ) ; + } + } +} +//_____________________________________________________________________________ + + + + + +//_____________________________________________________________________________ +// Test a face +// if face>0 return true if the face contains a part of the surface +bool MarchingCubes::test_face( schar face ) +//----------------------------------------------------------------------------- +{ + real A,B,C,D ; + + switch( face ) + { + case -1 : case 1 : A = _cube[0] ; B = _cube[4] ; C = _cube[5] ; D = _cube[1] ; break ; + case -2 : case 2 : A = _cube[1] ; B = _cube[5] ; C = _cube[6] ; D = _cube[2] ; break ; + case -3 : case 3 : A = _cube[2] ; B = _cube[6] ; C = _cube[7] ; D = _cube[3] ; break ; + case -4 : case 4 : A = _cube[3] ; B = _cube[7] ; C = _cube[4] ; D = _cube[0] ; break ; + case -5 : case 5 : A = _cube[0] ; B = _cube[3] ; C = _cube[2] ; D = _cube[1] ; break ; + case -6 : case 6 : A = _cube[4] ; B = _cube[7] ; C = _cube[6] ; D = _cube[5] ; break ; + default : printf( "Invalid face code %d\n", face ) ; print_cube() ; A = B = C = D = 0 ; + }; + + if( fabs( A*C - B*D ) < FLT_EPSILON ) + return face >= 0 ; + return face * A * ( A*C - B*D ) >= 0 ; // face and A invert signs +} +//_____________________________________________________________________________ + + + + + +//_____________________________________________________________________________ +// Test the interior of a cube +// if s == 7, return true if the interior is empty +// if s ==-7, return false if the interior is empty +bool MarchingCubes::test_interior( schar s ) +//----------------------------------------------------------------------------- +{ + real t, At=0, Bt=0, Ct=0, Dt=0, a, b ; + char test = 0 ; + char edge = -1 ; // reference edge of the triangulation + + switch( _case ) + { + case 4 : + case 10 : + a = ( _cube[4] - _cube[0] ) * ( _cube[6] - _cube[2] ) - ( _cube[7] - _cube[3] ) * ( _cube[5] - _cube[1] ) ; + b = _cube[2] * ( _cube[4] - _cube[0] ) + _cube[0] * ( _cube[6] - _cube[2] ) + - _cube[1] * ( _cube[7] - _cube[3] ) - _cube[3] * ( _cube[5] - _cube[1] ) ; + t = - b / (2*a) ; + if( t<0 || t>1 ) return s>0 ; + + At = _cube[0] + ( _cube[4] - _cube[0] ) * t ; + Bt = _cube[3] + ( _cube[7] - _cube[3] ) * t ; + Ct = _cube[2] + ( _cube[6] - _cube[2] ) * t ; + Dt = _cube[1] + ( _cube[5] - _cube[1] ) * t ; + break ; + + case 6 : + case 7 : + case 12 : + case 13 : + switch( _case ) + { + case 6 : edge = test6 [_config][2] ; break ; + case 7 : edge = test7 [_config][4] ; break ; + case 12 : edge = test12[_config][3] ; break ; + case 13 : edge = tiling13_5_1[_config][_subconfig][0] ; break ; + } + switch( edge ) + { + case 0 : + t = _cube[0] / ( _cube[0] - _cube[1] ) ; + At = 0 ; + Bt = _cube[3] + ( _cube[2] - _cube[3] ) * t ; + Ct = _cube[7] + ( _cube[6] - _cube[7] ) * t ; + Dt = _cube[4] + ( _cube[5] - _cube[4] ) * t ; + break ; + case 1 : + t = _cube[1] / ( _cube[1] - _cube[2] ) ; + At = 0 ; + Bt = _cube[0] + ( _cube[3] - _cube[0] ) * t ; + Ct = _cube[4] + ( _cube[7] - _cube[4] ) * t ; + Dt = _cube[5] + ( _cube[6] - _cube[5] ) * t ; + break ; + case 2 : + t = _cube[2] / ( _cube[2] - _cube[3] ) ; + At = 0 ; + Bt = _cube[1] + ( _cube[0] - _cube[1] ) * t ; + Ct = _cube[5] + ( _cube[4] - _cube[5] ) * t ; + Dt = _cube[6] + ( _cube[7] - _cube[6] ) * t ; + break ; + case 3 : + t = _cube[3] / ( _cube[3] - _cube[0] ) ; + At = 0 ; + Bt = _cube[2] + ( _cube[1] - _cube[2] ) * t ; + Ct = _cube[6] + ( _cube[5] - _cube[6] ) * t ; + Dt = _cube[7] + ( _cube[4] - _cube[7] ) * t ; + break ; + case 4 : + t = _cube[4] / ( _cube[4] - _cube[5] ) ; + At = 0 ; + Bt = _cube[7] + ( _cube[6] - _cube[7] ) * t ; + Ct = _cube[3] + ( _cube[2] - _cube[3] ) * t ; + Dt = _cube[0] + ( _cube[1] - _cube[0] ) * t ; + break ; + case 5 : + t = _cube[5] / ( _cube[5] - _cube[6] ) ; + At = 0 ; + Bt = _cube[4] + ( _cube[7] - _cube[4] ) * t ; + Ct = _cube[0] + ( _cube[3] - _cube[0] ) * t ; + Dt = _cube[1] + ( _cube[2] - _cube[1] ) * t ; + break ; + case 6 : + t = _cube[6] / ( _cube[6] - _cube[7] ) ; + At = 0 ; + Bt = _cube[5] + ( _cube[4] - _cube[5] ) * t ; + Ct = _cube[1] + ( _cube[0] - _cube[1] ) * t ; + Dt = _cube[2] + ( _cube[3] - _cube[2] ) * t ; + break ; + case 7 : + t = _cube[7] / ( _cube[7] - _cube[4] ) ; + At = 0 ; + Bt = _cube[6] + ( _cube[5] - _cube[6] ) * t ; + Ct = _cube[2] + ( _cube[1] - _cube[2] ) * t ; + Dt = _cube[3] + ( _cube[0] - _cube[3] ) * t ; + break ; + case 8 : + t = _cube[0] / ( _cube[0] - _cube[4] ) ; + At = 0 ; + Bt = _cube[3] + ( _cube[7] - _cube[3] ) * t ; + Ct = _cube[2] + ( _cube[6] - _cube[2] ) * t ; + Dt = _cube[1] + ( _cube[5] - _cube[1] ) * t ; + break ; + case 9 : + t = _cube[1] / ( _cube[1] - _cube[5] ) ; + At = 0 ; + Bt = _cube[0] + ( _cube[4] - _cube[0] ) * t ; + Ct = _cube[3] + ( _cube[7] - _cube[3] ) * t ; + Dt = _cube[2] + ( _cube[6] - _cube[2] ) * t ; + break ; + case 10 : + t = _cube[2] / ( _cube[2] - _cube[6] ) ; + At = 0 ; + Bt = _cube[1] + ( _cube[5] - _cube[1] ) * t ; + Ct = _cube[0] + ( _cube[4] - _cube[0] ) * t ; + Dt = _cube[3] + ( _cube[7] - _cube[3] ) * t ; + break ; + case 11 : + t = _cube[3] / ( _cube[3] - _cube[7] ) ; + At = 0 ; + Bt = _cube[2] + ( _cube[6] - _cube[2] ) * t ; + Ct = _cube[1] + ( _cube[5] - _cube[1] ) * t ; + Dt = _cube[0] + ( _cube[4] - _cube[0] ) * t ; + break ; + default : printf( "Invalid edge %d\n", edge ) ; print_cube() ; break ; + } + break ; + + default : printf( "Invalid ambiguous case %d\n", _case ) ; print_cube() ; break ; + } + + if( At >= 0 ) test ++ ; + if( Bt >= 0 ) test += 2 ; + if( Ct >= 0 ) test += 4 ; + if( Dt >= 0 ) test += 8 ; + switch( test ) + { + case 0 : return s>0 ; + case 1 : return s>0 ; + case 2 : return s>0 ; + case 3 : return s>0 ; + case 4 : return s>0 ; + case 5 : if( At * Ct - Bt * Dt < FLT_EPSILON ) return s>0 ; break ; + case 6 : return s>0 ; + case 7 : return s<0 ; + case 8 : return s>0 ; + case 9 : return s>0 ; + case 10 : if( At * Ct - Bt * Dt >= FLT_EPSILON ) return s>0 ; break ; + case 11 : return s<0 ; + case 12 : return s>0 ; + case 13 : return s<0 ; + case 14 : return s<0 ; + case 15 : return s<0 ; + } + + return s<0 ; +} +//_____________________________________________________________________________ + + + + +//_____________________________________________________________________________ +// Process a unit cube +void MarchingCubes::process_cube( ) +//----------------------------------------------------------------------------- +{ + if( _originalMC ) + { + char nt = 0 ; + while( casesClassic[_lut_entry][3*nt] != -1 ) nt++ ; + add_triangle( casesClassic[_lut_entry], nt ) ; + return ; + } + + int v12 = -1 ; + _case = cases[_lut_entry][0] ; + _config = cases[_lut_entry][1] ; + _subconfig = 0 ; + + switch( _case ) + { + case 0 : + break ; + + case 1 : + add_triangle( tiling1[_config], 1 ) ; + break ; + + case 2 : + add_triangle( tiling2[_config], 2 ) ; + break ; + + case 3 : + if( test_face( test3[_config]) ) + add_triangle( tiling3_2[_config], 4 ) ; // 3.2 + else + add_triangle( tiling3_1[_config], 2 ) ; // 3.1 + break ; + + case 4 : + if( test_interior( test4[_config]) ) + add_triangle( tiling4_1[_config], 2 ) ; // 4.1.1 + else + add_triangle( tiling4_2[_config], 6 ) ; // 4.1.2 + break ; + + case 5 : + add_triangle( tiling5[_config], 3 ) ; + break ; + + case 6 : + if( test_face( test6[_config][0]) ) + add_triangle( tiling6_2[_config], 5 ) ; // 6.2 + else + { + if( test_interior( test6[_config][1]) ) + add_triangle( tiling6_1_1[_config], 3 ) ; // 6.1.1 + else + { + v12 = add_c_vertex() ; + add_triangle( tiling6_1_2[_config], 9 , v12) ; // 6.1.2 + } + } + break ; + + case 7 : + if( test_face( test7[_config][0] ) ) _subconfig += 1 ; + if( test_face( test7[_config][1] ) ) _subconfig += 2 ; + if( test_face( test7[_config][2] ) ) _subconfig += 4 ; + switch( _subconfig ) + { + case 0 : + add_triangle( tiling7_1[_config], 3 ) ; break ; + case 1 : + add_triangle( tiling7_2[_config][0], 5 ) ; break ; + case 2 : + add_triangle( tiling7_2[_config][1], 5 ) ; break ; + case 3 : + v12 = add_c_vertex() ; + add_triangle( tiling7_3[_config][0], 9, v12 ) ; break ; + case 4 : + add_triangle( tiling7_2[_config][2], 5 ) ; break ; + case 5 : + v12 = add_c_vertex() ; + add_triangle( tiling7_3[_config][1], 9, v12 ) ; break ; + case 6 : + v12 = add_c_vertex() ; + add_triangle( tiling7_3[_config][2], 9, v12 ) ; break ; + case 7 : + if( test_interior( test7[_config][3]) ) + add_triangle( tiling7_4_2[_config], 9 ) ; + else + add_triangle( tiling7_4_1[_config], 5 ) ; + break ; + }; + break ; + + case 8 : + add_triangle( tiling8[_config], 2 ) ; + break ; + + case 9 : + add_triangle( tiling9[_config], 4 ) ; + break ; + + case 10 : + if( test_face( test10[_config][0]) ) + { + if( test_face( test10[_config][1]) ) + add_triangle( tiling10_1_1_[_config], 4 ) ; // 10.1.1 + else + { + v12 = add_c_vertex() ; + add_triangle( tiling10_2[_config], 8, v12 ) ; // 10.2 + } + } + else + { + if( test_face( test10[_config][1]) ) + { + v12 = add_c_vertex() ; + add_triangle( tiling10_2_[_config], 8, v12 ) ; // 10.2 + } + else + { + if( test_interior( test10[_config][2]) ) + add_triangle( tiling10_1_1[_config], 4 ) ; // 10.1.1 + else + add_triangle( tiling10_1_2[_config], 8 ) ; // 10.1.2 + } + } + break ; + + case 11 : + add_triangle( tiling11[_config], 4 ) ; + break ; + + case 12 : + if( test_face( test12[_config][0]) ) + { + if( test_face( test12[_config][1]) ) + add_triangle( tiling12_1_1_[_config], 4 ) ; // 12.1.1 + else + { + v12 = add_c_vertex() ; + add_triangle( tiling12_2[_config], 8, v12 ) ; // 12.2 + } + } + else + { + if( test_face( test12[_config][1]) ) + { + v12 = add_c_vertex() ; + add_triangle( tiling12_2_[_config], 8, v12 ) ; // 12.2 + } + else + { + if( test_interior( test12[_config][2]) ) + add_triangle( tiling12_1_1[_config], 4 ) ; // 12.1.1 + else + add_triangle( tiling12_1_2[_config], 8 ) ; // 12.1.2 + } + } + break ; + + case 13 : + if( test_face( test13[_config][0] ) ) _subconfig += 1 ; + if( test_face( test13[_config][1] ) ) _subconfig += 2 ; + if( test_face( test13[_config][2] ) ) _subconfig += 4 ; + if( test_face( test13[_config][3] ) ) _subconfig += 8 ; + if( test_face( test13[_config][4] ) ) _subconfig += 16 ; + if( test_face( test13[_config][5] ) ) _subconfig += 32 ; + switch( subconfig13[_subconfig] ) + { + case 0 :/* 13.1 */ + add_triangle( tiling13_1[_config], 4 ) ; break ; + + case 1 :/* 13.2 */ + add_triangle( tiling13_2[_config][0], 6 ) ; break ; + case 2 :/* 13.2 */ + add_triangle( tiling13_2[_config][1], 6 ) ; break ; + case 3 :/* 13.2 */ + add_triangle( tiling13_2[_config][2], 6 ) ; break ; + case 4 :/* 13.2 */ + add_triangle( tiling13_2[_config][3], 6 ) ; break ; + case 5 :/* 13.2 */ + add_triangle( tiling13_2[_config][4], 6 ) ; break ; + case 6 :/* 13.2 */ + add_triangle( tiling13_2[_config][5], 6 ) ; break ; + + case 7 :/* 13.3 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_3[_config][0], 10, v12 ) ; break ; + case 8 :/* 13.3 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_3[_config][1], 10, v12 ) ; break ; + case 9 :/* 13.3 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_3[_config][2], 10, v12 ) ; break ; + case 10 :/* 13.3 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_3[_config][3], 10, v12 ) ; break ; + case 11 :/* 13.3 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_3[_config][4], 10, v12 ) ; break ; + case 12 :/* 13.3 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_3[_config][5], 10, v12 ) ; break ; + case 13 :/* 13.3 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_3[_config][6], 10, v12 ) ; break ; + case 14 :/* 13.3 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_3[_config][7], 10, v12 ) ; break ; + case 15 :/* 13.3 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_3[_config][8], 10, v12 ) ; break ; + case 16 :/* 13.3 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_3[_config][9], 10, v12 ) ; break ; + case 17 :/* 13.3 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_3[_config][10], 10, v12 ) ; break ; + case 18 :/* 13.3 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_3[_config][11], 10, v12 ) ; break ; + + case 19 :/* 13.4 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_4[_config][0], 12, v12 ) ; break ; + case 20 :/* 13.4 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_4[_config][1], 12, v12 ) ; break ; + case 21 :/* 13.4 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_4[_config][2], 12, v12 ) ; break ; + case 22 :/* 13.4 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_4[_config][3], 12, v12 ) ; break ; + + case 23 :/* 13.5 */ + _subconfig = 0 ; + if( test_interior( test13[_config][6] ) ) + add_triangle( tiling13_5_1[_config][0], 6 ) ; + else + add_triangle( tiling13_5_2[_config][0], 10 ) ; + break ; + case 24 :/* 13.5 */ + _subconfig = 1 ; + if( test_interior( test13[_config][6] ) ) + add_triangle( tiling13_5_1[_config][1], 6 ) ; + else + add_triangle( tiling13_5_2[_config][1], 10 ) ; + break ; + case 25 :/* 13.5 */ + _subconfig = 2 ; + if( test_interior( test13[_config][6] ) ) + add_triangle( tiling13_5_1[_config][2], 6 ) ; + else + add_triangle( tiling13_5_2[_config][2], 10 ) ; + break ; + case 26 :/* 13.5 */ + _subconfig = 3 ; + if( test_interior( test13[_config][6] ) ) + add_triangle( tiling13_5_1[_config][3], 6 ) ; + else + add_triangle( tiling13_5_2[_config][3], 10 ) ; + break ; + + case 27 :/* 13.3 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_3_[_config][0], 10, v12 ) ; break ; + case 28 :/* 13.3 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_3_[_config][1], 10, v12 ) ; break ; + case 29 :/* 13.3 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_3_[_config][2], 10, v12 ) ; break ; + case 30 :/* 13.3 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_3_[_config][3], 10, v12 ) ; break ; + case 31 :/* 13.3 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_3_[_config][4], 10, v12 ) ; break ; + case 32 :/* 13.3 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_3_[_config][5], 10, v12 ) ; break ; + case 33 :/* 13.3 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_3_[_config][6], 10, v12 ) ; break ; + case 34 :/* 13.3 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_3_[_config][7], 10, v12 ) ; break ; + case 35 :/* 13.3 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_3_[_config][8], 10, v12 ) ; break ; + case 36 :/* 13.3 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_3_[_config][9], 10, v12 ) ; break ; + case 37 :/* 13.3 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_3_[_config][10], 10, v12 ) ; break ; + case 38 :/* 13.3 */ + v12 = add_c_vertex() ; + add_triangle( tiling13_3_[_config][11], 10, v12 ) ; break ; + + case 39 :/* 13.2 */ + add_triangle( tiling13_2_[_config][0], 6 ) ; break ; + case 40 :/* 13.2 */ + add_triangle( tiling13_2_[_config][1], 6 ) ; break ; + case 41 :/* 13.2 */ + add_triangle( tiling13_2_[_config][2], 6 ) ; break ; + case 42 :/* 13.2 */ + add_triangle( tiling13_2_[_config][3], 6 ) ; break ; + case 43 :/* 13.2 */ + add_triangle( tiling13_2_[_config][4], 6 ) ; break ; + case 44 :/* 13.2 */ + add_triangle( tiling13_2_[_config][5], 6 ) ; break ; + + case 45 :/* 13.1 */ + add_triangle( tiling13_1_[_config], 4 ) ; break ; + + default : + printf("Marching Cubes: Impossible case 13?\n" ) ; print_cube() ; + } + break ; + + case 14 : + add_triangle( tiling14[_config], 4 ) ; + break ; + }; +} +//_____________________________________________________________________________ + + + +//_____________________________________________________________________________ +// Adding triangles +void MarchingCubes::add_triangle( const char* trig, char n, int v12 ) +//----------------------------------------------------------------------------- +{ + int tv[3] ; + + for( int t = 0 ; t < 3*n ; t++ ) + { + switch( trig[t] ) + { + case 0 : tv[ t % 3 ] = get_x_vert( _i , _j , _k ) ; break ; + case 1 : tv[ t % 3 ] = get_y_vert(_i+1, _j , _k ) ; break ; + case 2 : tv[ t % 3 ] = get_x_vert( _i ,_j+1, _k ) ; break ; + case 3 : tv[ t % 3 ] = get_y_vert( _i , _j , _k ) ; break ; + case 4 : tv[ t % 3 ] = get_x_vert( _i , _j ,_k+1) ; break ; + case 5 : tv[ t % 3 ] = get_y_vert(_i+1, _j ,_k+1) ; break ; + case 6 : tv[ t % 3 ] = get_x_vert( _i ,_j+1,_k+1) ; break ; + case 7 : tv[ t % 3 ] = get_y_vert( _i , _j ,_k+1) ; break ; + case 8 : tv[ t % 3 ] = get_z_vert( _i , _j , _k ) ; break ; + case 9 : tv[ t % 3 ] = get_z_vert(_i+1, _j , _k ) ; break ; + case 10 : tv[ t % 3 ] = get_z_vert(_i+1,_j+1, _k ) ; break ; + case 11 : tv[ t % 3 ] = get_z_vert( _i ,_j+1, _k ) ; break ; + case 12 : tv[ t % 3 ] = v12 ; break ; + default : break ; + } + + if( tv[t%3] == -1 ) + { + printf("Marching Cubes: invalid triangle %d\n", _ntrigs+1) ; + print_cube() ; + } + + if( t%3 == 2 ) + { + if( _ntrigs >= _Ntrigs ) + { + Triangle *temp = _triangles ; + _triangles = new Triangle[ 2*_Ntrigs ] ; + memcpy( _triangles, temp, _Ntrigs*sizeof(Triangle) ) ; + delete[] temp ; + printf("%d allocated triangles\n", _Ntrigs) ; + _Ntrigs *= 2 ; + } + + Triangle *T = _triangles + _ntrigs++ ; + T->v1 = tv[0] ; + T->v2 = tv[1] ; + T->v3 = tv[2] ; + } + } +} +//_____________________________________________________________________________ + + + +//_____________________________________________________________________________ +// Calculating gradient + +real MarchingCubes::get_x_grad( const int i, const int j, const int k ) const +//----------------------------------------------------------------------------- +{ + if( i > 0 ) + { + if ( i < _size_x - 1 ) + return ( get_data( i+1, j, k ) - get_data( i-1, j, k ) ) / 2 ; + else + return get_data( i, j, k ) - get_data( i-1, j, k ) ; + } + else + return get_data( i+1, j, k ) - get_data( i, j, k ) ; +} +//----------------------------------------------------------------------------- + +real MarchingCubes::get_y_grad( const int i, const int j, const int k ) const +//----------------------------------------------------------------------------- +{ + if( j > 0 ) + { + if ( j < _size_y - 1 ) + return ( get_data( i, j+1, k ) - get_data( i, j-1, k ) ) / 2 ; + else + return get_data( i, j, k ) - get_data( i, j-1, k ) ; + } + else + return get_data( i, j+1, k ) - get_data( i, j, k ) ; +} +//----------------------------------------------------------------------------- + +real MarchingCubes::get_z_grad( const int i, const int j, const int k ) const +//----------------------------------------------------------------------------- +{ + if( k > 0 ) + { + if ( k < _size_z - 1 ) + return ( get_data( i, j, k+1 ) - get_data( i, j, k-1 ) ) / 2 ; + else + return get_data( i, j, k ) - get_data( i, j, k-1 ) ; + } + else + return get_data( i, j, k+1 ) - get_data( i, j, k ) ; +} +//_____________________________________________________________________________ + + +//_____________________________________________________________________________ +// Adding vertices + +void MarchingCubes::test_vertex_addition() +{ + if( _nverts >= _Nverts ) + { + Vertex *temp = _vertices ; + _vertices = new Vertex[ _Nverts*2 ] ; + memcpy( _vertices, temp, _Nverts*sizeof(Vertex) ) ; + delete[] temp ; + printf("%d allocated vertices\n", _Nverts) ; + _Nverts *= 2 ; + } +} + + +int MarchingCubes::add_x_vertex( ) +//----------------------------------------------------------------------------- +{ + test_vertex_addition() ; + Vertex *vert = _vertices + _nverts++ ; + + real u = ( _cube[0] ) / ( _cube[0] - _cube[1] ) ; + + vert->x = (real)_i+u; + vert->y = (real) _j ; + vert->z = (real) _k ; + + vert->nx = (1-u)*get_x_grad(_i,_j,_k) + u*get_x_grad(_i+1,_j,_k) ; + vert->ny = (1-u)*get_y_grad(_i,_j,_k) + u*get_y_grad(_i+1,_j,_k) ; + vert->nz = (1-u)*get_z_grad(_i,_j,_k) + u*get_z_grad(_i+1,_j,_k) ; + + u = (real) sqrt( vert->nx * vert->nx + vert->ny * vert->ny +vert->nz * vert->nz ) ; + if( u > 0 ) + { + vert->nx /= u ; + vert->ny /= u ; + vert->nz /= u ; + } + + + return _nverts-1 ; +} +//----------------------------------------------------------------------------- + +int MarchingCubes::add_y_vertex( ) +//----------------------------------------------------------------------------- +{ + test_vertex_addition() ; + Vertex *vert = _vertices + _nverts++ ; + + real u = ( _cube[0] ) / ( _cube[0] - _cube[3] ) ; + + vert->x = (real) _i ; + vert->y = (real)_j+u; + vert->z = (real) _k ; + + vert->nx = (1-u)*get_x_grad(_i,_j,_k) + u*get_x_grad(_i,_j+1,_k) ; + vert->ny = (1-u)*get_y_grad(_i,_j,_k) + u*get_y_grad(_i,_j+1,_k) ; + vert->nz = (1-u)*get_z_grad(_i,_j,_k) + u*get_z_grad(_i,_j+1,_k) ; + + u = (real) sqrt( vert->nx * vert->nx + vert->ny * vert->ny +vert->nz * vert->nz ) ; + if( u > 0 ) + { + vert->nx /= u ; + vert->ny /= u ; + vert->nz /= u ; + } + + return _nverts-1 ; +} +//----------------------------------------------------------------------------- + +int MarchingCubes::add_z_vertex( ) +//----------------------------------------------------------------------------- +{ + test_vertex_addition() ; + Vertex *vert = _vertices + _nverts++ ; + + real u = ( _cube[0] ) / ( _cube[0] - _cube[4] ) ; + + vert->x = (real) _i ; + vert->y = (real) _j ; + vert->z = (real)_k+u; + + vert->nx = (1-u)*get_x_grad(_i,_j,_k) + u*get_x_grad(_i,_j,_k+1) ; + vert->ny = (1-u)*get_y_grad(_i,_j,_k) + u*get_y_grad(_i,_j,_k+1) ; + vert->nz = (1-u)*get_z_grad(_i,_j,_k) + u*get_z_grad(_i,_j,_k+1) ; + + u = (real) sqrt( vert->nx * vert->nx + vert->ny * vert->ny +vert->nz * vert->nz ) ; + if( u > 0 ) + { + vert->nx /= u ; + vert->ny /= u ; + vert->nz /= u ; + } + + return _nverts-1 ; +} + + +int MarchingCubes::add_c_vertex( ) +//----------------------------------------------------------------------------- +{ + test_vertex_addition() ; + Vertex *vert = _vertices + _nverts++ ; + + real u = 0 ; + int vid ; + + vert->x = vert->y = vert->z = vert->nx = vert->ny = vert->nz = 0 ; + + // Computes the average of the intersection points of the cube + vid = get_x_vert( _i , _j , _k ) ; + if( vid != -1 ) { ++u ; const Vertex &v = _vertices[vid] ; vert->x += v.x ; vert->y += v.y ; vert->z += v.z ; vert->nx += v.nx ; vert->ny += v.ny ; vert->nz += v.nz ; } + vid = get_y_vert(_i+1, _j , _k ) ; + if( vid != -1 ) { ++u ; const Vertex &v = _vertices[vid] ; vert->x += v.x ; vert->y += v.y ; vert->z += v.z ; vert->nx += v.nx ; vert->ny += v.ny ; vert->nz += v.nz ; } + vid = get_x_vert( _i ,_j+1, _k ) ; + if( vid != -1 ) { ++u ; const Vertex &v = _vertices[vid] ; vert->x += v.x ; vert->y += v.y ; vert->z += v.z ; vert->nx += v.nx ; vert->ny += v.ny ; vert->nz += v.nz ; } + vid = get_y_vert( _i , _j , _k ) ; + if( vid != -1 ) { ++u ; const Vertex &v = _vertices[vid] ; vert->x += v.x ; vert->y += v.y ; vert->z += v.z ; vert->nx += v.nx ; vert->ny += v.ny ; vert->nz += v.nz ; } + vid = get_x_vert( _i , _j ,_k+1) ; + if( vid != -1 ) { ++u ; const Vertex &v = _vertices[vid] ; vert->x += v.x ; vert->y += v.y ; vert->z += v.z ; vert->nx += v.nx ; vert->ny += v.ny ; vert->nz += v.nz ; } + vid = get_y_vert(_i+1, _j ,_k+1) ; + if( vid != -1 ) { ++u ; const Vertex &v = _vertices[vid] ; vert->x += v.x ; vert->y += v.y ; vert->z += v.z ; vert->nx += v.nx ; vert->ny += v.ny ; vert->nz += v.nz ; } + vid = get_x_vert( _i ,_j+1,_k+1) ; + if( vid != -1 ) { ++u ; const Vertex &v = _vertices[vid] ; vert->x += v.x ; vert->y += v.y ; vert->z += v.z ; vert->nx += v.nx ; vert->ny += v.ny ; vert->nz += v.nz ; } + vid = get_y_vert( _i , _j ,_k+1) ; + if( vid != -1 ) { ++u ; const Vertex &v = _vertices[vid] ; vert->x += v.x ; vert->y += v.y ; vert->z += v.z ; vert->nx += v.nx ; vert->ny += v.ny ; vert->nz += v.nz ; } + vid = get_z_vert( _i , _j , _k ) ; + if( vid != -1 ) { ++u ; const Vertex &v = _vertices[vid] ; vert->x += v.x ; vert->y += v.y ; vert->z += v.z ; vert->nx += v.nx ; vert->ny += v.ny ; vert->nz += v.nz ; } + vid = get_z_vert(_i+1, _j , _k ) ; + if( vid != -1 ) { ++u ; const Vertex &v = _vertices[vid] ; vert->x += v.x ; vert->y += v.y ; vert->z += v.z ; vert->nx += v.nx ; vert->ny += v.ny ; vert->nz += v.nz ; } + vid = get_z_vert(_i+1,_j+1, _k ) ; + if( vid != -1 ) { ++u ; const Vertex &v = _vertices[vid] ; vert->x += v.x ; vert->y += v.y ; vert->z += v.z ; vert->nx += v.nx ; vert->ny += v.ny ; vert->nz += v.nz ; } + vid = get_z_vert( _i ,_j+1, _k ) ; + if( vid != -1 ) { ++u ; const Vertex &v = _vertices[vid] ; vert->x += v.x ; vert->y += v.y ; vert->z += v.z ; vert->nx += v.nx ; vert->ny += v.ny ; vert->nz += v.nz ; } + + vert->x /= u ; + vert->y /= u ; + vert->z /= u ; + + u = (real) sqrt( vert->nx * vert->nx + vert->ny * vert->ny +vert->nz * vert->nz ) ; + if( u > 0 ) + { + vert->nx /= u ; + vert->ny /= u ; + vert->nz /= u ; + } + + return _nverts-1 ; +} +//_____________________________________________________________________________ + + + +//_____________________________________________________________________________ +//_____________________________________________________________________________ + + + + +//_____________________________________________________________________________ +// Grid exportation +void MarchingCubes::writeISO(const char *fn ) +//----------------------------------------------------------------------------- +{ + unsigned char buf[sizeof(float)] ; + + FILE *fp = fopen( fn, "wb" ) ; + + // header + * (int*) buf = _size_x ; + fwrite(buf, sizeof(float), 1, fp); + * (int*) buf = _size_y ; + fwrite(buf, sizeof(float), 1, fp); + * (int*) buf = _size_z ; + fwrite(buf, sizeof(float), 1, fp); + + * (float*) buf = -1.0f ; + fwrite(buf, sizeof(float), 1, fp); + * (float*) buf = 1.0f ; + fwrite(buf, sizeof(float), 1, fp); + * (float*) buf = -1.0f ; + fwrite(buf, sizeof(float), 1, fp); + * (float*) buf = 1.0f ; + fwrite(buf, sizeof(float), 1, fp); + * (float*) buf = -1.0f ; + fwrite(buf, sizeof(float), 1, fp); + * (float*) buf = 1.0f ; + fwrite(buf, sizeof(float), 1, fp); + + for( int i = 0 ; i < _size_x ; i++ ) + { + for( int j = 0 ; j < _size_y ; j++ ) + { + for( int k = 0 ; k < _size_z ; k++ ) + { + * (float*) buf = (float)get_data( i,j,k ) ; + fwrite(buf, sizeof(float), 1, fp); + } + } + } + + fclose(fp) ; +} +//_____________________________________________________________________________ + + + + + +//_____________________________________________________________________________ +// PLY exportation +void MarchingCubes::writePLY(const char *fn, bool bin ) +//----------------------------------------------------------------------------- +{ + + typedef struct PlyFace { + unsigned char nverts; /* number of Vertex indices in list */ + int *verts; /* Vertex index list */ + } PlyFace; + + + PlyProperty vert_props[] = { /* list of property information for a PlyVertex */ + {"x", Float32, Float32, offsetof( Vertex,x ), 0, 0, 0, 0}, + {"y", Float32, Float32, offsetof( Vertex,y ), 0, 0, 0, 0}, + {"z", Float32, Float32, offsetof( Vertex,z ), 0, 0, 0, 0}, + {"nx", Float32, Float32, offsetof( Vertex,nx ), 0, 0, 0, 0}, + {"ny", Float32, Float32, offsetof( Vertex,ny ), 0, 0, 0, 0}, + {"nz", Float32, Float32, offsetof( Vertex,nz ), 0, 0, 0, 0} + }; + + PlyProperty face_props[] = { /* list of property information for a PlyFace */ + {"vertex_indices", Int32, Int32, offsetof( PlyFace,verts ), + 1, Uint8, Uint8, offsetof( PlyFace,nverts )}, + }; + + + PlyFile *ply; + FILE *fp = fopen( fn, "w" ); + + int i ; + PlyFace face ; + int verts[3] ; + char *elem_names[] = { "vertex", "face" }; + printf("Marching Cubes::writePLY(%s)...", fn ) ; + ply = write_ply ( fp, 2, elem_names, bin? PLY_BINARY_LE : PLY_ASCII ); + + /* describe what properties go into the PlyVertex elements */ + describe_element_ply ( ply, "vertex", _nverts ); + describe_property_ply ( ply, &vert_props[0] ); + describe_property_ply ( ply, &vert_props[1] ); + describe_property_ply ( ply, &vert_props[2] ); + describe_property_ply ( ply, &vert_props[3] ); + describe_property_ply ( ply, &vert_props[4] ); + describe_property_ply ( ply, &vert_props[5] ); + + /* describe PlyFace properties (just list of PlyVertex indices) */ + describe_element_ply ( ply, "face", _ntrigs ); + describe_property_ply ( ply, &face_props[0] ); + + header_complete_ply ( ply ); + + /* set up and write the PlyVertex elements */ + put_element_setup_ply ( ply, "vertex" ); + for ( i = 0; i < _nverts; i++ ) + put_element_ply ( ply, ( void * ) &(_vertices[i]) ); + printf(" %d vertices written\n", _nverts ) ; + + /* set up and write the PlyFace elements */ + put_element_setup_ply ( ply, "face" ); + face.nverts = 3 ; + face.verts = verts ; + for ( i = 0; i < _ntrigs; i++ ) + { + face.verts[0] = _triangles[i].v1 ; + face.verts[1] = _triangles[i].v2 ; + face.verts[2] = _triangles[i].v3 ; + put_element_ply ( ply, ( void * ) &face ); + } + printf(" %d triangles written\n", _ntrigs ) ; + + close_ply ( ply ); + free_ply ( ply ); + fclose( fp ) ; +} +//_____________________________________________________________________________ + + + +//_____________________________________________________________________________ +// PLY importation +void MarchingCubes::readPLY(const char *fn ) +//----------------------------------------------------------------------------- +{ + typedef struct PlyFace { + unsigned char nverts; /* number of Vertex indices in list */ + int *verts; /* Vertex index list */ + } PlyFace; + + + PlyProperty vert_props[] = { /* list of property information for a PlyVertex */ + {"x", Float32, Float32, offsetof( Vertex,x ), 0, 0, 0, 0}, + {"y", Float32, Float32, offsetof( Vertex,y ), 0, 0, 0, 0}, + {"z", Float32, Float32, offsetof( Vertex,z ), 0, 0, 0, 0}, + {"nx", Float32, Float32, offsetof( Vertex,nx ), 0, 0, 0, 0}, + {"ny", Float32, Float32, offsetof( Vertex,ny ), 0, 0, 0, 0}, + {"nz", Float32, Float32, offsetof( Vertex,nz ), 0, 0, 0, 0} + }; + + PlyProperty face_props[] = { /* list of property information for a PlyFace */ + {"vertex_indices", Int32, Int32, offsetof( PlyFace,verts ), + 1, Uint8, Uint8, offsetof( PlyFace,nverts )}, + }; + + + FILE *fp = fopen( fn, "r" ); + if( !fp ) return ; + PlyFile *ply = read_ply ( fp ); + printf("Marching Cubes::readPLY(%s)...", fn ) ; + + //----------------------------------------------------------------------------- + + // gets the number of faces and vertices + for ( int i = 0; i < ply->num_elem_types; ++i ) + { + int elem_count ; + char *elem_name = setup_element_read_ply ( ply, i, &elem_count ); + if ( equal_strings ( "vertex", elem_name ) ) + _Nverts = _nverts = elem_count; + if ( equal_strings ( "face", elem_name ) ) + _Ntrigs = _ntrigs = elem_count; + } + delete [] _vertices ; + _vertices = new Vertex [_Nverts] ; + delete [] _triangles ; + _triangles = new Triangle[_Ntrigs] ; + + //----------------------------------------------------------------------------- + + /* examine each element type that is in the file (PlyVertex, PlyFace) */ + + for ( int i = 0; i < ply->num_elem_types; ++i ) + { + /* prepare to read the i'th list of elements */ + int elem_count ; + char *elem_name = setup_element_read_ply ( ply, i, &elem_count ); + + //----------------------------------------------------------------------------- + if ( equal_strings ( "vertex", elem_name ) ) + { + /* set up for getting PlyVertex elements */ + setup_property_ply ( ply, &vert_props[0] ); + setup_property_ply ( ply, &vert_props[1] ); + setup_property_ply ( ply, &vert_props[2] ); + setup_property_ply ( ply, &vert_props[3] ); + setup_property_ply ( ply, &vert_props[4] ); + setup_property_ply ( ply, &vert_props[5] ); + + for ( int j = 0; j < _nverts; ++j ) + { + get_element_ply ( ply, ( void * ) (_vertices + j) ); + } + printf(" %d vertices read\n", _nverts ) ; + } + + //----------------------------------------------------------------------------- + else if ( equal_strings ( "face", elem_name ) ) + { + /* set up for getting PlyFace elements */ + /* (all we need are PlyVertex indices) */ + + setup_property_ply ( ply, &face_props[0] ) ; + PlyFace face ; + for ( int j = 0; j < _ntrigs; ++j ) + { + get_element_ply ( ply, ( void * ) &face ); + if( face.nverts != 3 ) + { + printf( "not a triangulated surface: polygon %d has %d sides\n", j, face.nverts ) ; + return ; + } + + _triangles[j].v1 = face.verts[0] ; + _triangles[j].v2 = face.verts[1] ; + _triangles[j].v3 = face.verts[2] ; + + free( face.verts ) ; + } + printf(" %d triangles read\n", _ntrigs ) ; + } + //----------------------------------------------------------------------------- + + //----------------------------------------------------------------------------- + else /* all non-PlyVertex and non-PlyFace elements are grabbed here */ + get_other_element_ply ( ply ); + //----------------------------------------------------------------------------- + } + + close_ply ( ply ); + free_ply ( ply ); + +// fit_to_bbox() ; + fclose( fp ) ; +} +//_____________________________________________________________________________ + + + +//_____________________________________________________________________________ +// Open Inventor / VRML 1.0 ascii exportation +void MarchingCubes::writeIV(const char *fn ) +//----------------------------------------------------------------------------- +{ + FILE *fp = fopen( fn, "w" ) ; + int i ; + + printf("Marching Cubes::exportIV(%s)...", fn) ; + + fprintf( fp, "#Inventor V2.1 ascii \n\nSeparator { \n ShapeHints {\n vertexOrdering COUNTERCLOCKWISE\n shapeType UNKNOWN_SHAPE_TYPE\n creaseAngle 0.0\n }\n Coordinate3 { \n point [ \n" ) ; + for ( i = 0; i < _nverts; i++ ) + fprintf( fp, " %f %f %f,\n", _vertices[i].x, _vertices[i].y, _vertices[i].z ) ; + printf(" %d vertices written\n", _nverts ) ; + + fprintf( fp, "\n ] \n} \nNormal { \nvector [ \n" ) ; + for ( i = 0; i < _nverts; i++ ) + fprintf( fp, " %f %f %f,\n", _vertices[i].nx, _vertices[i].ny, _vertices[i].nz ) ; + + fprintf( fp, "\n ] \n} \nIndexedFaceSet { \ncoordIndex [ \n" ) ; + for ( i = 0; i < _ntrigs; i++ ) + fprintf( fp, "%d, %d, %d, -1,\n", _triangles[i].v1, _triangles[i].v2, _triangles[i].v3 ) ; + + fprintf( fp, " ] \n } \n } \n" ) ; + fclose( fp ) ; + printf(" %d triangles written\n", _ntrigs ) ; +} +//_____________________________________________________________________________ diff --git a/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/MarchingCubes.h b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/MarchingCubes.h new file mode 100755 index 00000000000..c589bffb7f5 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/MarchingCubes.h @@ -0,0 +1,343 @@ +/** + * @file MarchingCubes.h + * @author Thomas Lewiner <thomas.lewiner@polytechnique.org> + * @author Math Dept, PUC-Rio + * @version 0.2 + * @date 12/08/2002 + * + * @brief MarchingCubes Algorithm + */ +//________________________________________________ + + +#ifndef _MARCHINGCUBES_H_ +#define _MARCHINGCUBES_H_ + +#if !defined(WIN32) || defined(__CYGWIN__) +#pragma interface +#endif // WIN32 + + +//_____________________________________________________________________________ +// types +/** unsigned char alias */ +typedef unsigned char uchar ; +/** signed char alias */ +typedef signed char schar ; +/** isovalue alias */ +typedef float real ; + +//----------------------------------------------------------------------------- +// Vertex structure +/** \struct Vertex "MarchingCubes.h" MarchingCubes + * Position and normal of a vertex + * \brief vertex structure + * \param x X coordinate + * \param y Y coordinate + * \param z Z coordinate + * \param nx X component of the normal + * \param ny Y component of the normal + * \param nz Z component of the normal + */ +typedef struct +{ + real x, y, z ; /**< Vertex coordinates */ + real nx, ny, nz ; /**< Vertex normal */ +} Vertex ; + +//----------------------------------------------------------------------------- +// Triangle structure +/** \struct Triangle "MarchingCubes.h" MarchingCubes + * Indices of the oriented triange vertices + * \brief triangle structure + * \param v1 First vertex index + * \param v2 Second vertex index + * \param v3 Third vertex index + */ +typedef struct +{ + int v1,v2,v3 ; /**< Triangle vertices */ +} Triangle ; +//_____________________________________________________________________________ + + + +//_____________________________________________________________________________ +/** Marching Cubes algorithm wrapper */ +/** \class MarchingCubes + * \brief Marching Cubes algorithm. + */ +class MarchingCubes +//----------------------------------------------------------------------------- +{ +// Constructors +public : + /** + * Main and default constructor + * \brief constructor + * \param size_x width of the grid + * \param size_y depth of the grid + * \param size_z height of the grid + */ + MarchingCubes ( const int size_x = -1, const int size_y = -1, const int size_z = -1 ) ; + /** Destructor */ + ~MarchingCubes() ; + +//----------------------------------------------------------------------------- +// Accessors +public : + /** accesses the number of vertices of the generated mesh */ + inline const int nverts() const { return _nverts ; } + /** accesses the number of triangles of the generated mesh */ + inline const int ntrigs() const { return _ntrigs ; } + /** accesses a specific vertex of the generated mesh */ + inline Vertex * vert( const int i ) const { if( i < 0 || i >= _nverts ) return ( Vertex *)NULL ; return _vertices + i ; } + /** accesses a specific triangle of the generated mesh */ + inline Triangle * trig( const int i ) const { if( i < 0 || i >= _ntrigs ) return (Triangle*)NULL ; return _triangles + i ; } + + /** accesses the vertex buffer of the generated mesh */ + inline Vertex *vertices () { return _vertices ; } + /** accesses the triangle buffer of the generated mesh */ + inline Triangle *triangles() { return _triangles ; } + + /** accesses the width of the grid */ + inline const int size_x() const { return _size_x ; } + /** accesses the depth of the grid */ + inline const int size_y() const { return _size_y ; } + /** accesses the height of the grid */ + inline const int size_z() const { return _size_z ; } + + /** + * changes the size of the grid + * \param size_x width of the grid + * \param size_y depth of the grid + * \param size_z height of the grid + */ + inline void set_resolution( const int size_x, const int size_y, const int size_z ) { _size_x = size_x ; _size_y = size_y ; _size_z = size_z ; } + /** + * selects wether the algorithm will use the enhanced topologically controlled lookup table or the original MarchingCubes + * \param originalMC true for the original Marching Cubes + */ + inline void set_method ( const bool originalMC = false ) { _originalMC = originalMC ; } + /** + * selects to use data from another class + * \param data is the pointer to the external data, allocated as a size_x*size_y*size_z vector running in x first + */ + inline void set_ext_data ( real *data ) + { if( !_ext_data ) delete [] _data ; _ext_data = data != NULL ; if( _ext_data ) _data = data ; } + /** + * selects to allocate data + */ + inline void set_int_data () { _ext_data = false ; _data = NULL ; } + + // Data access + /** + * accesses a specific cube of the grid + * \param i abscisse of the cube + * \param j ordinate of the cube + * \param k height of the cube + */ + inline const real get_data ( const int i, const int j, const int k ) const { return _data[ i + j*_size_x + k*_size_x*_size_y] ; } + /** + * sets a specific cube of the grid + * \param val new value for the cube + * \param i abscisse of the cube + * \param j ordinate of the cube + * \param k height of the cube + */ + inline void set_data ( const real val, const int i, const int j, const int k ) { _data[ i + j*_size_x + k*_size_x*_size_y] = val ; } + + // Data initialization + /** inits temporary structures (must set sizes before call) : the grid and the vertex index per cube */ + void init_temps () ; + /** inits all structures (must set sizes before call) : the temporary structures and the mesh buffers */ + void init_all () ; + /** clears temporary structures : the grid and the main */ + void clean_temps() ; + /** clears all structures : the temporary structures and the mesh buffers */ + void clean_all () ; + + +//----------------------------------------------------------------------------- +// Exportation +public : + /** + * PLY exportation of the generated mesh + * \param fn name of the PLY file to create + * \param bin if true, the PLY will be written in binary mode + */ + void writePLY( const char *fn, bool bin = false ) ; + + /** + * PLY importation of a mesh + * \param fn name of the PLY file to read from + */ + void readPLY( const char *fn ) ; + + /** + * VRML / Open Inventor exportation of the generated mesh + * \param fn name of the IV file to create + */ + void writeIV ( const char *fn ) ; + + /** + * ISO exportation of the input grid + * \param fn name of the ISO file to create + */ + void writeISO( const char *fn ) ; + + +//----------------------------------------------------------------------------- +// Algorithm +public : + /** + * Main algorithm : must be called after init_all + * \param iso isovalue + */ + void run( real iso = (real)0.0 ) ; + +protected : + /** tesselates one cube */ + void process_cube () ; + /** tests if the components of the tesselation of the cube should be connected by the interior of an ambiguous face */ + bool test_face ( schar face ) ; + /** tests if the components of the tesselation of the cube should be connected through the interior of the cube */ + bool test_interior( schar s ) ; + + +//----------------------------------------------------------------------------- +// Operations +protected : + /** + * computes almost all the vertices of the mesh by interpolation along the cubes edges + * \param iso isovalue + */ + void compute_intersection_points( real iso ) ; + + /** + * routine to add a triangle to the mesh + * \param trig the code for the triangle as a sequence of edges index + * \param n the number of triangles to produce + * \param v12 the index of the interior vertex to use, if necessary + */ + void add_triangle ( const char* trig, char n, int v12 = -1 ) ; + + /** tests and eventually doubles the vertex buffer capacity for a new vertex insertion */ + void test_vertex_addition() ; + /** adds a vertex on the current horizontal edge */ + int add_x_vertex() ; + /** adds a vertex on the current longitudinal edge */ + int add_y_vertex() ; + /** adds a vertex on the current vertical edge */ + int add_z_vertex() ; + /** adds a vertex inside the current cube */ + int add_c_vertex() ; + + /** + * interpolates the horizontal gradient of the implicit function at the lower vertex of the specified cube + * \param i abscisse of the cube + * \param j ordinate of the cube + * \param k height of the cube + */ + real get_x_grad( const int i, const int j, const int k ) const ; + /** + * interpolates the longitudinal gradient of the implicit function at the lower vertex of the specified cube + * \param i abscisse of the cube + * \param j ordinate of the cube + * \param k height of the cube + */ + real get_y_grad( const int i, const int j, const int k ) const ; + /** + * interpolates the vertical gradient of the implicit function at the lower vertex of the specified cube + * \param i abscisse of the cube + * \param j ordinate of the cube + * \param k height of the cube + */ + real get_z_grad( const int i, const int j, const int k ) const ; + + /** + * accesses the pre-computed vertex index on the lower horizontal edge of a specific cube + * \param i abscisse of the cube + * \param j ordinate of the cube + * \param k height of the cube + */ + inline int get_x_vert( const int i, const int j, const int k ) const { return _x_verts[ i + j*_size_x + k*_size_x*_size_y] ; } + /** + * accesses the pre-computed vertex index on the lower longitudinal edge of a specific cube + * \param i abscisse of the cube + * \param j ordinate of the cube + * \param k height of the cube + */ + inline int get_y_vert( const int i, const int j, const int k ) const { return _y_verts[ i + j*_size_x + k*_size_x*_size_y] ; } + /** + * accesses the pre-computed vertex index on the lower vertical edge of a specific cube + * \param i abscisse of the cube + * \param j ordinate of the cube + * \param k height of the cube + */ + inline int get_z_vert( const int i, const int j, const int k ) const { return _z_verts[ i + j*_size_x + k*_size_x*_size_y] ; } + + /** + * sets the pre-computed vertex index on the lower horizontal edge of a specific cube + * \param val the index of the new vertex + * \param i abscisse of the cube + * \param j ordinate of the cube + * \param k height of the cube + */ + inline void set_x_vert( const int val, const int i, const int j, const int k ) { _x_verts[ i + j*_size_x + k*_size_x*_size_y] = val ; } + /** + * sets the pre-computed vertex index on the lower longitudinal edge of a specific cube + * \param val the index of the new vertex + * \param i abscisse of the cube + * \param j ordinate of the cube + * \param k height of the cube + */ + inline void set_y_vert( const int val, const int i, const int j, const int k ) { _y_verts[ i + j*_size_x + k*_size_x*_size_y] = val ; } + /** + * sets the pre-computed vertex index on the lower vertical edge of a specific cube + * \param val the index of the new vertex + * \param i abscisse of the cube + * \param j ordinate of the cube + * \param k height of the cube + */ + inline void set_z_vert( const int val, const int i, const int j, const int k ) { _z_verts[ i + j*_size_x + k*_size_x*_size_y] = val ; } + + /** prints cube for debug */ + void print_cube() ; + +//----------------------------------------------------------------------------- +// Elements +protected : + bool _originalMC ; /**< selects wether the algorithm will use the enhanced topologically controlled lookup table or the original MarchingCubes */ + bool _ext_data ; /**< selects wether to allocate data or use data from another class */ + + int _size_x ; /**< width of the grid */ + int _size_y ; /**< depth of the grid */ + int _size_z ; /**< height of the grid */ + real *_data ; /**< implicit function values sampled on the grid */ + + int *_x_verts ; /**< pre-computed vertex indices on the lower horizontal edge of each cube */ + int *_y_verts ; /**< pre-computed vertex indices on the lower longitudinal edge of each cube */ + int *_z_verts ; /**< pre-computed vertex indices on the lower vertical edge of each cube */ + + int _nverts ; /**< number of allocated vertices in the vertex buffer */ + int _ntrigs ; /**< number of allocated triangles in the triangle buffer */ + int _Nverts ; /**< size of the vertex buffer */ + int _Ntrigs ; /**< size of the triangle buffer */ + Vertex *_vertices ; /**< vertex buffer */ + Triangle *_triangles ; /**< triangle buffer */ + + int _i ; /**< abscisse of the active cube */ + int _j ; /**< height of the active cube */ + int _k ; /**< ordinate of the active cube */ + + real _cube[8] ; /**< values of the implicit function on the active cube */ + uchar _lut_entry ; /**< cube sign representation in [0..255] */ + uchar _case ; /**< case of the active cube in [0..15] */ + uchar _config ; /**< configuration of the active cube */ + uchar _subconfig ; /**< subconfiguration of the active cube */ +}; +//_____________________________________________________________________________ + + +#endif // _MARCHINGCUBES_H_ diff --git a/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/ply.c b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/ply.c new file mode 100755 index 00000000000..06c60f4dbb8 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/ply.c @@ -0,0 +1,3325 @@ +/* + +The interface routines for reading and writing PLY polygon files. + +Greg Turk + +--------------------------------------------------------------- + +A PLY file contains a single polygonal _object_. + +An object is composed of lists of _elements_. Typical elements are +vertices, faces, edges and materials. + +Each type of element for a given object has one or more _properties_ +associated with the element type. For instance, a vertex element may +have as properties the floating-point values x,y,z and the three unsigned +chars representing red, green and blue. + +----------------------------------------------------------------------- + +Copyright (c) 1998 Georgia Institute of Technology. All rights reserved. + +Permission to use, copy, modify and distribute this software and its +documentation for any purpose is hereby granted without fee, provided +that the above copyright notice and this permission notice appear in +all copies of this software and that you do not sell the software. + +THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, +EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY +WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <string.h> +#include "ply.h" + +char *type_names[] = { /* names of scalar types */ +"invalid", +"int8", "int16", "int32", "uint8", "uint16", "uint32", "float32", "float64", +}; + +char *old_type_names[] = { /* old names of types for backward compatability */ +"invalid", +"char", "short", "int", "uchar", "ushort", "uint", "float", "double", +}; + +int ply_type_size[] = { +0, 1, 2, 4, 1, 2, 4, 4, 8 +}; + +#define NO_OTHER_PROPS -1 + +#define DONT_STORE_PROP 0 +#define STORE_PROP 1 + +#define OTHER_PROP 0 +#define NAMED_PROP 1 + +/* returns 1 if strings are equal, 0 if not */ +int equal_strings( char * , char * ); + +/* find an element in a plyfile's list */ +PlyElement *find_element( PlyFile * , char * ); + +/* find a property in an element's list */ +PlyProperty *find_property( PlyElement * , char * , int * ); + +/* write to a file the word describing a PLY file data type */ +void write_scalar_type( FILE * , int ); + +/* read a line from a file and break it up into separate words */ +char* *get_words( FILE * , int * , char ** ); + +/* write an item to a file */ +void write_binary_item( FILE * , int, unsigned int, double, int ); +void write_ascii_item( FILE * , int, unsigned int, double, int ); + +/* add information to a PLY file descriptor */ +void add_element( PlyFile * , char ** , int ); +void add_property( PlyFile * , char ** , int ); +void add_comment( PlyFile * , char * ); +void add_obj_info( PlyFile * , char * ); + +/* copy a property */ +void copy_property( PlyProperty * , PlyProperty * ); + +/* store a value into where a pointer and a type specify */ +void store_item( char * , int, int, unsigned int, double ); + +/* return the value of a stored item */ +void get_stored_item( void * , int, int * , unsigned int * , double * ); + +/* return the value stored in an item, given ptr to it and its type */ +double get_item_value( char * , int ); + +/* get binary or ascii item and store it according to ptr and type */ +void get_ascii_item( char * , int, int * , unsigned int * , double * ); +void get_binary_item( FILE * , int, int * , unsigned int * , double * ); + +/* get a bunch of elements from a file */ +void ascii_get_element( PlyFile * , char * ); +void binary_get_element( PlyFile * , char * ); + +/* memory allocation */ +static char *my_alloc( int, int, char * ); + + +/*************/ +/* Writing */ +/*************/ + + +/****************************************************************************** +Given a file pointer, get ready to write PLY data to the file. + +Entry: +fp - the given file pointer +nelems - number of elements in object +elem_names - list of element names +file_type - file type, either ascii or binary + +Exit: +returns a pointer to a PlyFile, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *ply_write( FILE *fp, int nelems, char **elem_names, int file_type ) +{ + int i; + PlyFile *plyfile; + PlyElement *elem; + + /* check for NULL file pointer */ + if ( fp == NULL ) + return ( NULL ); + + /* create a record for this object */ + + plyfile = ( PlyFile * ) myalloc ( sizeof ( PlyFile ) ); + plyfile->file_type = file_type; + plyfile->num_comments = 0; + plyfile->num_obj_info = 0; + plyfile->num_elem_types = nelems; + plyfile->version = 1.0; + plyfile->fp = fp; + plyfile->other_elems = NULL; + + /* tuck aside the names of the elements */ + + plyfile->elems = ( PlyElement * * ) myalloc ( sizeof ( PlyElement * ) * nelems ); + for ( i = 0; i < nelems; i++ ) + { + elem = ( PlyElement * ) myalloc ( sizeof ( PlyElement ) ); + plyfile->elems[i] = elem; + elem->name = strdup ( elem_names[i] ); + elem->num = 0; + elem->nprops = 0; + } + + /* return pointer to the file descriptor */ + return ( plyfile ); +} + + +/****************************************************************************** +Open a polygon file for writing. + +Entry: +filename - name of file to read from +nelems - number of elements in object +elem_names - list of element names +file_type - file type, either ascii or binary + +Exit: +returns a file identifier, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *open_for_writing_ply( char *filename, int nelems, char **elem_names, int file_type ) +{ + PlyFile *plyfile; + char *name; + FILE *fp; + + /* tack on the extension .ply, if necessary */ + + name = ( char * ) myalloc ( sizeof ( char ) * ( strlen ( filename ) + 5 ) ); + strcpy ( name, filename ); + if ( strlen ( name ) < 4 || strcmp ( name + strlen ( name ) - 4, ".ply" ) != 0 ) + strcat ( name, ".ply" ); + + /* open the file for writing */ + + fp = fopen ( name, "w" ); + if ( fp == NULL ) + { + return ( NULL ); + } + + /* create the actual PlyFile structure */ + + plyfile = ply_write ( fp, nelems, elem_names, file_type ); + if ( plyfile == NULL ) + return ( NULL ); + + /* return pointer to the file descriptor */ + return ( plyfile ); +} + + +/****************************************************************************** +Describe an element, including its properties and how many will be written +to the file. + +Entry: +plyfile - file identifier +elem_name - name of element that information is being specified about +nelems - number of elements of this type to be written +nprops - number of properties contained in the element +prop_list - list of properties +******************************************************************************/ + +void element_layout_ply( PlyFile *plyfile, char *elem_name, int nelems, int nprops, PlyProperty *prop_list ) +{ + int i; + PlyElement *elem; + PlyProperty *prop; + + /* look for appropriate element */ + elem = find_element ( plyfile, elem_name ); + if ( elem == NULL ) + { + fprintf( stderr,"element_layout_ply: can't find element '%s'\n",elem_name ); + exit ( -1 ); + } + + elem->num = nelems; + + /* copy the list of properties */ + + elem->nprops = nprops; + elem->props = ( PlyProperty * * ) myalloc ( sizeof ( PlyProperty * ) * nprops ); + elem->store_prop = ( char * ) myalloc ( sizeof ( char ) * nprops ); + + for ( i = 0; i < nprops; i++ ) + { + prop = ( PlyProperty * ) myalloc ( sizeof ( PlyProperty ) ); + elem->props[i] = prop; + elem->store_prop[i] = NAMED_PROP; + copy_property ( prop, &prop_list[i] ); + } +} + + +/****************************************************************************** +Describe a property of an element. + +Entry: +plyfile - file identifier +elem_name - name of element that information is being specified about +prop - the new property +******************************************************************************/ + +void ply_describe_property( PlyFile *plyfile, char *elem_name, PlyProperty *prop ) +{ + PlyElement *elem; + PlyProperty *elem_prop; + + /* look for appropriate element */ + elem = find_element ( plyfile, elem_name ); + if ( elem == NULL ) + { + fprintf( stderr, "ply_describe_property: can't find element '%s'\n", + elem_name ); + return; + } + + /* create room for new property */ + + if ( elem->nprops == 0 ) + { + elem->props = ( PlyProperty * * ) myalloc ( sizeof ( PlyProperty * ) ); + elem->store_prop = ( char * ) myalloc ( sizeof ( char ) ); + elem->nprops = 1; + } + else + { + elem->nprops++; + elem->props = ( PlyProperty * * ) + realloc ( elem->props, sizeof ( PlyProperty * ) * elem->nprops ); + elem->store_prop = ( char * ) + realloc ( elem->store_prop, sizeof ( char ) * elem->nprops ); + } + + /* copy the new property */ + + elem_prop = ( PlyProperty * ) myalloc ( sizeof ( PlyProperty ) ); + elem->props[elem->nprops - 1] = elem_prop; + elem->store_prop[elem->nprops - 1] = NAMED_PROP; + copy_property ( elem_prop, prop ); +} + + +/****************************************************************************** +State how many of a given element will be written. + +Entry: +plyfile - file identifier +elem_name - name of element that information is being specified about +nelems - number of elements of this type to be written +******************************************************************************/ + +void element_count_ply( PlyFile *plyfile, char *elem_name, int nelems ) +{ + PlyElement *elem; + + /* look for appropriate element */ + elem = find_element ( plyfile, elem_name ); + if ( elem == NULL ) + { + fprintf( stderr,"element_count_ply: can't find element '%s'\n",elem_name ); + exit ( -1 ); + } + + elem->num = nelems; +} + + +/****************************************************************************** +Signal that we've described everything a PLY file's header and that the +header should be written to the file. + +Entry: +plyfile - file identifier +******************************************************************************/ + +void header_complete_ply( PlyFile *plyfile ) +{ + int i,j; + FILE *fp = plyfile->fp; + PlyElement *elem; + PlyProperty *prop; + + fprintf ( fp, "ply\n" ); + + switch ( plyfile->file_type ) + { + case PLY_ASCII: + fprintf ( fp, "format ascii 1.0\n" ); + break; + case PLY_BINARY_BE: + fprintf ( fp, "format binary_big_endian 1.0\n" ); + break; + case PLY_BINARY_LE: + fprintf ( fp, "format binary_little_endian 1.0\n" ); + break; + default: + fprintf ( stderr, "ply_header_complete: bad file type = %d\n", + plyfile->file_type ); + exit ( -1 ); + } + + /* write out the comments */ + + for ( i = 0; i < plyfile->num_comments; i++ ) + fprintf ( fp, "comment %s\n", plyfile->comments[i] ); + + /* write out object information */ + + for ( i = 0; i < plyfile->num_obj_info; i++ ) + fprintf ( fp, "obj_info %s\n", plyfile->obj_info[i] ); + + /* write out information about each element */ + + for ( i = 0; i < plyfile->num_elem_types; i++ ) + { + elem = plyfile->elems[i]; + fprintf ( fp, "element %s %d\n", elem->name, elem->num ); + + /* write out each property */ + for ( j = 0; j < elem->nprops; j++ ) + { + prop = elem->props[j]; + if ( prop->is_list == PLY_LIST ) + { + fprintf ( fp, "property list " ); + write_scalar_type ( fp, prop->count_external ); + fprintf ( fp, " " ); + write_scalar_type ( fp, prop->external_type ); + fprintf ( fp, " %s\n", prop->name ); + } + else if ( prop->is_list == PLY_STRING ) + { + fprintf ( fp, "property string" ); + fprintf ( fp, " %s\n", prop->name ); + } + else + { + fprintf ( fp, "property " ); + write_scalar_type ( fp, prop->external_type ); + fprintf ( fp, " %s\n", prop->name ); + } + } + } + + fprintf ( fp, "end_header\n" ); +} + + +/****************************************************************************** +Specify which elements are going to be written. This should be called +before a call to the routine ply_put_element(). + +Entry: +plyfile - file identifier +elem_name - name of element we're talking about +******************************************************************************/ + +void put_element_setup_ply( PlyFile *plyfile, char *elem_name ) +{ + PlyElement *elem; + + elem = find_element ( plyfile, elem_name ); + if ( elem == NULL ) + { + fprintf( stderr, "put_element_setup_ply: can't find element '%s'\n", elem_name ); + exit ( -1 ); + } + + plyfile->which_elem = elem; +} + + +/****************************************************************************** +Write an element to the file. This routine assumes that we're +writing the type of element specified in the last call to the routine +put_element_setup_ply(). + +Entry: +plyfile - file identifier +elem_ptr - pointer to the element +******************************************************************************/ + +void put_element_ply( PlyFile *plyfile, void *elem_ptr ) +{ + int j,k; + FILE *fp = plyfile->fp; + PlyElement *elem; + PlyProperty *prop; + char *item; + char *elem_data; + char* *item_ptr; + int list_count; + int item_size; + int int_val; + unsigned int uint_val; + double double_val; + char* *other_ptr; + + elem = plyfile->which_elem; + elem_data = ( char * ) elem_ptr; + other_ptr = ( char * * ) ( ( ( char * ) elem_ptr ) + elem->other_offset ); + + /* write out either to an ascii or binary file */ + + if ( plyfile->file_type == PLY_ASCII ) + { + /* write an ascii file */ + + /* write out each property of the element */ + for ( j = 0; j < elem->nprops; j++ ) + { + prop = elem->props[j]; + + if ( elem->store_prop[j] == OTHER_PROP ) + elem_data = *other_ptr; + else + elem_data = ( char * ) elem_ptr; + + if ( prop->is_list == PLY_LIST ) + { + /* list */ + item = elem_data + prop->count_offset; + get_stored_item ( ( void * ) item, prop->count_internal, + &int_val, &uint_val, &double_val ); + write_ascii_item ( fp, int_val, uint_val, double_val, + prop->count_external ); + list_count = uint_val; + item_ptr = ( char * * ) ( elem_data + prop->offset ); + item = item_ptr[0]; + item_size = ply_type_size[prop->internal_type]; + for ( k = 0; k < list_count; k++ ) + { + get_stored_item ( ( void * ) item, prop->internal_type, + &int_val, &uint_val, &double_val ); + write_ascii_item ( fp, int_val, uint_val, double_val, + prop->external_type ); + item += item_size; + } + } + else if ( prop->is_list == PLY_STRING ) + { + /* string */ + char* *str; + item = elem_data + prop->offset; + str = ( char * * ) item; + fprintf ( fp, "\"%s\"", *str ); + } + else + { + /* scalar */ + item = elem_data + prop->offset; + get_stored_item ( ( void * ) item, prop->internal_type, + &int_val, &uint_val, &double_val ); + write_ascii_item ( fp, int_val, uint_val, double_val, + prop->external_type ); + } + } + + fprintf ( fp, "\n" ); + } + else + { + /* write a binary file */ + + /* write out each property of the element */ + for ( j = 0; j < elem->nprops; j++ ) + { + prop = elem->props[j]; + if ( elem->store_prop[j] == OTHER_PROP ) + elem_data = *other_ptr; + else + elem_data = ( char * ) elem_ptr; + if ( prop->is_list == PLY_LIST ) + { + /* list */ + item = elem_data + prop->count_offset; + item_size = ply_type_size[prop->count_internal]; + get_stored_item ( ( void * ) item, prop->count_internal, + &int_val, &uint_val, &double_val ); + write_binary_item ( fp, int_val, uint_val, double_val, + prop->count_external ); + list_count = uint_val; + item_ptr = ( char * * ) ( elem_data + prop->offset ); + item = item_ptr[0]; + item_size = ply_type_size[prop->internal_type]; + for ( k = 0; k < list_count; k++ ) + { + get_stored_item ( ( void * ) item, prop->internal_type, + &int_val, &uint_val, &double_val ); + write_binary_item ( fp, int_val, uint_val, double_val, + prop->external_type ); + item += item_size; + } + } + else if ( prop->is_list == PLY_STRING ) + { + /* string */ + int len; + char* *str; + item = elem_data + prop->offset; + str = ( char * * ) item; + + /* write the length */ + len = strlen( *str ) + 1; + fwrite ( &len, sizeof( int ), 1, fp ); + + /* write the string, including the null character */ + fwrite ( *str, len, 1, fp ); + } + else + { + /* scalar */ + item = elem_data + prop->offset; + item_size = ply_type_size[prop->internal_type]; + get_stored_item ( ( void * ) item, prop->internal_type, + &int_val, &uint_val, &double_val ); + write_binary_item ( fp, int_val, uint_val, double_val, + prop->external_type ); + } + } + } +} + + + + + + +/*************/ +/* Reading */ +/*************/ + + + +/****************************************************************************** +Given a file pointer, get ready to read PLY data from the file. + +Entry: +fp - the given file pointer + +Exit: +nelems - number of elements in object +elem_names - list of element names +returns a pointer to a PlyFile, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *ply_read( FILE *fp, int *nelems, char ***elem_names ) +{ + int i,j; + PlyFile *plyfile; + int nwords; + char* *words; + int found_format = 0; + char* *elist; + PlyElement *elem; + char *orig_line; + + /* check for NULL file pointer */ + if ( fp == NULL ) + return ( NULL ); + + /* create record for this object */ + + plyfile = ( PlyFile * ) myalloc ( sizeof ( PlyFile ) ); + plyfile->num_elem_types = 0; + plyfile->comments = NULL; + plyfile->num_comments = 0; + plyfile->obj_info = NULL; + plyfile->num_obj_info = 0; + plyfile->fp = fp; + plyfile->other_elems = NULL; + plyfile->rule_list = NULL; + + /* read and parse the file's header */ + + words = get_words ( plyfile->fp, &nwords, &orig_line ); + if ( !words || !equal_strings ( words[0], "ply" ) ) + return ( NULL ); + + while ( words ) + { + /* parse words */ + + if ( equal_strings ( words[0], "format" ) ) + { + if ( nwords != 3 ) + return ( NULL ); + if ( equal_strings ( words[1], "ascii" ) ) + plyfile->file_type = PLY_ASCII; + else if ( equal_strings ( words[1], "binary_big_endian" ) ) + plyfile->file_type = PLY_BINARY_BE; + else if ( equal_strings ( words[1], "binary_little_endian" ) ) + plyfile->file_type = PLY_BINARY_LE; + else + return ( NULL ); + plyfile->version = ( float ) atof ( words[2] ); + found_format = 1; + } + else if ( equal_strings ( words[0], "element" ) ) + add_element ( plyfile, words, nwords ); + else if ( equal_strings ( words[0], "property" ) ) + add_property ( plyfile, words, nwords ); + else if ( equal_strings ( words[0], "comment" ) ) + add_comment ( plyfile, orig_line ); + else if ( equal_strings ( words[0], "obj_info" ) ) + add_obj_info ( plyfile, orig_line ); + else if ( equal_strings ( words[0], "end_header" ) ) + break; + + /* free up words space */ + free ( words ); + + words = get_words ( plyfile->fp, &nwords, &orig_line ); + } + + /* create tags for each property of each element, to be used */ + /* later to say whether or not to store each property for the user */ + + for ( i = 0; i < plyfile->num_elem_types; i++ ) + { + elem = plyfile->elems[i]; + elem->store_prop = ( char * ) myalloc ( sizeof ( char ) * elem->nprops ); + for ( j = 0; j < elem->nprops; j++ ) + elem->store_prop[j] = DONT_STORE_PROP; + elem->other_offset = NO_OTHER_PROPS; /* no "other" props by default */ + } + + /* set return values about the elements */ + + elist = ( char * * ) myalloc ( sizeof ( char * ) * plyfile->num_elem_types ); + for ( i = 0; i < plyfile->num_elem_types; i++ ) + elist[i] = strdup ( plyfile->elems[i]->name ); + + *elem_names = elist; + *nelems = plyfile->num_elem_types; + + /* return a pointer to the file's information */ + + return ( plyfile ); +} + + +/****************************************************************************** +Open a polygon file for reading. + +Entry: +filename - name of file to read from + +Exit: +nelems - number of elements in object +elem_names - list of element names +file_type - file type, either ascii or binary +version - version number of PLY file +returns a file identifier, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *ply_open_for_reading( char *filename, int *nelems, char ***elem_names, int *file_type, float *version ) +{ + FILE *fp; + PlyFile *plyfile; + char *name; + + /* tack on the extension .ply, if necessary */ + + name = ( char * ) myalloc ( sizeof ( char ) * ( strlen ( filename ) + 5 ) ); + strcpy ( name, filename ); + if ( strlen ( name ) < 4 || strcmp ( name + strlen ( name ) - 4, ".ply" ) != 0 ) + strcat ( name, ".ply" ); + + /* open the file for reading */ + + fp = fopen ( name, "r" ); + if ( fp == NULL ) + return ( NULL ); + + /* create the PlyFile data structure */ + + plyfile = ply_read ( fp, nelems, elem_names ); + + /* determine the file type and version */ + + *file_type = plyfile->file_type; + *version = plyfile->version; + + /* return a pointer to the file's information */ + + return ( plyfile ); +} + + +/****************************************************************************** +Get information about a particular element. + +Entry: +plyfile - file identifier +elem_name - name of element to get information about + +Exit: +nelems - number of elements of this type in the file +nprops - number of properties +returns a list of properties, or NULL if the file doesn't contain that elem +******************************************************************************/ + +PlyProperty **get_element_description_ply( PlyFile *plyfile, char *elem_name, int *nelems, int *nprops ) +{ + int i; + PlyElement *elem; + PlyProperty *prop; + PlyProperty* *prop_list; + + /* find information about the element */ + elem = find_element ( plyfile, elem_name ); + if ( elem == NULL ) + return ( NULL ); + + *nelems = elem->num; + *nprops = elem->nprops; + + /* make a copy of the element's property list */ + prop_list = ( PlyProperty * * ) myalloc ( sizeof ( PlyProperty * ) * elem->nprops ); + for ( i = 0; i < elem->nprops; i++ ) + { + prop = ( PlyProperty * ) myalloc ( sizeof ( PlyProperty ) ); + copy_property ( prop, elem->props[i] ); + prop_list[i] = prop; + } + + /* return this duplicate property list */ + return ( prop_list ); +} + + +/****************************************************************************** +Specify which properties of an element are to be returned. This should be +called before a call to the routine get_element_ply(). + +Entry: +plyfile - file identifier +elem_name - which element we're talking about +nprops - number of properties +prop_list - list of properties +******************************************************************************/ + +void get_element_setup_ply( PlyFile *plyfile, char *elem_name, int nprops, PlyProperty *prop_list ) +{ + int i; + PlyElement *elem; + PlyProperty *prop; + int index; + + /* find information about the element */ + elem = find_element ( plyfile, elem_name ); + plyfile->which_elem = elem; + + /* deposit the property information into the element's description */ + for ( i = 0; i < nprops; i++ ) + { + /* look for actual property */ + prop = find_property ( elem, prop_list[i].name, &index ); + if ( prop == NULL ) + { + fprintf ( stderr, "Warning: Can't find property '%s' in element '%s'\n", + prop_list[i].name, elem_name ); + continue; + } + + /* store its description */ + prop->internal_type = prop_list[i].internal_type; + prop->offset = prop_list[i].offset; + prop->count_internal = prop_list[i].count_internal; + prop->count_offset = prop_list[i].count_offset; + + /* specify that the user wants this property */ + elem->store_prop[index] = STORE_PROP; + } +} + + +/****************************************************************************** +Specify a property of an element that is to be returned. This should be +called (usually multiple times) before a call to the routine ply_get_element(). +This routine should be used in preference to the less flexible old routine +called ply_get_element_setup(). + +Entry: +plyfile - file identifier +elem_name - which element we're talking about +prop - property to add to those that will be returned +******************************************************************************/ + +void ply_get_property( PlyFile *plyfile, char *elem_name, PlyProperty *prop ) +{ + PlyElement *elem; + PlyProperty *prop_ptr; + int index; + + /* find information about the element */ + elem = find_element ( plyfile, elem_name ); + plyfile->which_elem = elem; + + /* deposit the property information into the element's description */ + + prop_ptr = find_property ( elem, prop->name, &index ); + if ( prop_ptr == NULL ) + { + fprintf ( stderr, "Warning: Can't find property '%s' in element '%s'\n", + prop->name, elem_name ); + return; + } + prop_ptr->internal_type = prop->internal_type; + prop_ptr->offset = prop->offset; + prop_ptr->count_internal = prop->count_internal; + prop_ptr->count_offset = prop->count_offset; + + /* specify that the user wants this property */ + elem->store_prop[index] = STORE_PROP; +} + + +/****************************************************************************** +Read one element from the file. This routine assumes that we're reading +the type of element specified in the last call to the routine +ply_get_element_setup(). + +Entry: +plyfile - file identifier +elem_ptr - pointer to location where the element information should be put +******************************************************************************/ + +void ply_get_element( PlyFile *plyfile, void *elem_ptr ) +{ + if ( plyfile->file_type == PLY_ASCII ) + ascii_get_element ( plyfile, ( char * ) elem_ptr ); + else + binary_get_element ( plyfile, ( char * ) elem_ptr ); +} + + +/****************************************************************************** +Extract the comments from the header information of a PLY file. + +Entry: +plyfile - file identifier + +Exit: +num_comments - number of comments returned +returns a pointer to a list of comments +******************************************************************************/ + +char **get_comments_ply( PlyFile *plyfile, int *num_comments ) +{ + *num_comments = plyfile->num_comments; + return ( plyfile->comments ); +} + + +/****************************************************************************** +Extract the object information (arbitrary text) from the header information +of a PLY file. + +Entry: +plyfile - file identifier + +Exit: +num_obj_info - number of lines of text information returned +returns a pointer to a list of object info lines +******************************************************************************/ + +char **get_obj_info_ply( PlyFile *plyfile, int *num_obj_info ) +{ + *num_obj_info = plyfile->num_obj_info; + return ( plyfile->obj_info ); +} + + +/****************************************************************************** +ake ready for "other" properties of an element-- those properties that +the user has not explicitly asked for, but that are to be stashed away +in a special structure to be carried along with the element's other +information. + +Entry: +plyfile - file identifier +elem - element for which we want to save away other properties +******************************************************************************/ + +void setup_other_props( PlyFile *plyfile, PlyElement *elem ) +{ + int i; + PlyProperty *prop; + int size = 0; + int type_size; + + /* Examine each property in decreasing order of size. */ + /* We do this so that all data types will be aligned by */ + /* word, half-word, or whatever within the structure. */ + + for ( type_size = 8; type_size > 0; type_size /= 2 ) + { + /* add up the space taken by each property, and save this information */ + /* away in the property descriptor */ + + for ( i = 0; i < elem->nprops; i++ ) + { + /* don't bother with properties we've been asked to store explicitly */ + if ( elem->store_prop[i] ) + continue; + + prop = elem->props[i]; + + /* internal types will be same as external */ + prop->internal_type = prop->external_type; + prop->count_internal = prop->count_external; + + /* list case */ + if ( prop->is_list == PLY_LIST ) + { + /* pointer to list */ + if ( type_size == sizeof ( void * ) ) + { + prop->offset = size; + size += sizeof ( void * ); /* always use size of a pointer here */ + } + + /* count of number of list elements */ + if ( type_size == ply_type_size[prop->count_external] ) + { + prop->count_offset = size; + size += ply_type_size[prop->count_external]; + } + } + /* string */ + else if ( prop->is_list == PLY_STRING ) + { + /* pointer to string */ + if ( type_size == sizeof ( char * ) ) + { + prop->offset = size; + size += sizeof ( char * ); + } + } + /* scalar */ + else if ( type_size == ply_type_size[prop->external_type] ) + { + prop->offset = size; + size += ply_type_size[prop->external_type]; + } + } + } + + /* save the size for the other_props structure */ + elem->other_size = size; +} + + +/****************************************************************************** +Specify that we want the "other" properties of an element to be tucked +away within the user's structure. + +Entry: +plyfile - file identifier +elem - the element that we want to store other_props in +offset - offset to where other_props will be stored inside user's structure + +Exit: +returns pointer to structure containing description of other_props +******************************************************************************/ + +static PlyOtherProp *get_other_properties( PlyFile *plyfile, PlyElement *elem, int offset ) +{ + int i; + PlyOtherProp *other; + PlyProperty *prop; + int nprops; + + /* remember that this is the "current" element */ + plyfile->which_elem = elem; + + /* save the offset to where to store the other_props */ + elem->other_offset = offset; + + /* place the appropriate pointers, etc. in the element's property list */ + setup_other_props ( plyfile, elem ); + + /* create structure for describing other_props */ + other = ( PlyOtherProp * ) myalloc ( sizeof ( PlyOtherProp ) ); + other->name = strdup ( elem->name ); +#if 0 +if (elem->other_offset == NO_OTHER_PROPS) { +other->size = 0; +other->props = NULL; +other->nprops = 0; +return (other); +} +#endif + other->size = elem->other_size; + other->props = ( PlyProperty * * ) myalloc ( sizeof( PlyProperty ) * elem->nprops ); + + /* save descriptions of each "other" property */ + nprops = 0; + for ( i = 0; i < elem->nprops; i++ ) + { + if ( elem->store_prop[i] ) + continue; + prop = ( PlyProperty * ) myalloc ( sizeof ( PlyProperty ) ); + copy_property ( prop, elem->props[i] ); + other->props[nprops] = prop; + nprops++; + } + other->nprops = nprops; + + /* set other_offset pointer appropriately if there are NO other properties */ + if ( other->nprops == 0 ) + { + elem->other_offset = NO_OTHER_PROPS; + } + + /* return structure */ + return ( other ); +} + + +/****************************************************************************** +Specify that we want the "other" properties of an element to be tucked +away within the user's structure. The user needn't be concerned for how +these properties are stored. + +Entry: +plyfile - file identifier +elem_name - name of element that we want to store other_props in +offset - offset to where other_props will be stored inside user's structure + +Exit: +returns pointer to structure containing description of other_props +******************************************************************************/ + +PlyOtherProp *ply_get_other_properties( PlyFile *plyfile, char *elem_name, int offset ) +{ + PlyElement *elem; + PlyOtherProp *other; + + /* find information about the element */ + elem = find_element ( plyfile, elem_name ); + if ( elem == NULL ) + { + fprintf ( stderr, "ply_get_other_properties: Can't find element '%s'\n", + elem_name ); + return ( NULL ); + } + + other = get_other_properties ( plyfile, elem, offset ); + return ( other ); +} + + + + +/*************************/ +/* Other Element Stuff */ +/*************************/ + + + + + +/****************************************************************************** +Grab all the data for the current element that a user does not want to +explicitly read in. Stores this in the PLY object's data structure. + +Entry: +plyfile - pointer to file + +Exit: +returns pointer to ALL the "other" element data for this PLY file +******************************************************************************/ + +PlyOtherElems *get_other_element_ply( PlyFile *plyfile ) +{ + int i; + PlyElement *elem; + char *elem_name; + int elem_count; + PlyOtherElems *other_elems; + OtherElem *other; + + elem = plyfile->which_elem; + elem_name = elem->name; + elem_count = elem->num; + + /* create room for the new "other" element, initializing the */ + /* other data structure if necessary */ + + if ( plyfile->other_elems == NULL ) + { + plyfile->other_elems = ( PlyOtherElems * ) myalloc ( sizeof ( PlyOtherElems ) ); + other_elems = plyfile->other_elems; + other_elems->other_list = ( OtherElem * ) myalloc ( sizeof ( OtherElem ) ); + other = &( other_elems->other_list[0] ); + other_elems->num_elems = 1; + } + else + { + other_elems = plyfile->other_elems; + other_elems->other_list = ( OtherElem * ) realloc ( other_elems->other_list, + sizeof ( OtherElem ) * other_elems->num_elems + 1 ); + other = &( other_elems->other_list[other_elems->num_elems] ); + other_elems->num_elems++; + } + + /* count of element instances in file */ + other->elem_count = elem_count; + + /* save name of element */ + other->elem_name = strdup ( elem_name ); + + /* create a list to hold all the current elements */ + other->other_data = ( OtherData * * ) + malloc ( sizeof ( OtherData * ) * other->elem_count ); + + /* set up for getting elements */ + other->other_props = ply_get_other_properties ( plyfile, elem_name, + offsetof( OtherData,other_props ) ); + + /* grab all these elements */ + for ( i = 0; i < other->elem_count; i++ ) + { + /* grab and element from the file */ + other->other_data[i] = ( OtherData * ) malloc ( sizeof ( OtherData ) ); + ply_get_element ( plyfile, ( void * ) other->other_data[i] ); + } + + /* return pointer to the other elements data */ + return ( other_elems ); +} + + +/****************************************************************************** +Write out the "other" elements specified for this PLY file. + +Entry: +plyfile - pointer to PLY file to write out other elements for +******************************************************************************/ + +void put_other_elements_ply( PlyFile *plyfile ) +{ + int i,j; + OtherElem *other; + + /* make sure we have other elements to write */ + if ( plyfile->other_elems == NULL ) + return; + + /* write out the data for each "other" element */ + + for ( i = 0; i < plyfile->other_elems->num_elems; i++ ) + { + other = &( plyfile->other_elems->other_list[i] ); + put_element_setup_ply ( plyfile, other->elem_name ); + + /* write out each instance of the current element */ + for ( j = 0; j < other->elem_count; j++ ) + put_element_ply ( plyfile, ( void * ) other->other_data[j] ); + } +} + + +/****************************************************************************** +Free up storage used by an "other" elements data structure. + +Entry: +other_elems - data structure to free up +******************************************************************************/ + +void free_other_elements_ply( PlyOtherElems *other_elems ) +{ +} + + + +/*******************/ +/* Miscellaneous */ +/*******************/ + + + +/****************************************************************************** +Close a PLY file. + +Entry: +plyfile - identifier of file to close +******************************************************************************/ + +void ply_close( PlyFile *plyfile ) +{ + fclose ( plyfile->fp ); + + /* free up memory associated with the PLY file */ + free ( plyfile ); +} + + +/****************************************************************************** +Get version number and file type of a PlyFile. + +Entry: +ply - pointer to PLY file + +Exit: +version - version of the file +file_type - PLY_ASCII, PLY_BINARY_BE, or PLY_BINARY_LE +******************************************************************************/ + +void get_info_ply( PlyFile *ply, float *version, int *file_type ) +{ + if ( ply == NULL ) + return; + + *version = ply->version; + *file_type = ply->file_type; +} + + +/****************************************************************************** +Compare two strings. Returns 1 if they are the same, 0 if not. +******************************************************************************/ + +int equal_strings( char *s1, char *s2 ) +{ + while ( *s1 && *s2 ) + if ( *s1++ != *s2++ ) + return ( 0 ); + + if ( *s1 != *s2 ) + return ( 0 ); + else + return ( 1 ); +} + + +/****************************************************************************** +Re-create the command line that was used to invoke this program. + +Entry: +argc - number of words in argv +argv - array of words in command line +******************************************************************************/ + +char *recreate_command_line( int argc, char *argv[] ) +{ + int i; + char *line; + int len = 0; + + /* count total number of characters needed, including separating spaces */ + for ( i = 0; i < argc; i++ ) + len += strlen( argv[i] ) + 1; + + /* create empty line */ + line = ( char * ) malloc ( sizeof( char ) * len ); + line[0] = '\0'; + + /* repeatedly append argv */ + for ( i = 0; i < argc; i++ ) + { + strcat ( line, argv[i] ); + if ( i != argc - 1 ) + strcat ( line, " " ); + } + + return ( line ); +} + + +/****************************************************************************** +Find an element from the element list of a given PLY object. + +Entry: +plyfile - file id for PLY file +element - name of element we're looking for + +Exit: +returns the element, or NULL if not found +******************************************************************************/ + +PlyElement *find_element( PlyFile *plyfile, char *element ) +{ + int i; + + for ( i = 0; i < plyfile->num_elem_types; i++ ) + if ( equal_strings ( element, plyfile->elems[i]->name ) ) + return ( plyfile->elems[i] ); + + return ( NULL ); +} + + +/****************************************************************************** +Find a property in the list of properties of a given element. + +Entry: +elem - pointer to element in which we want to find the property +prop_name - name of property to find + +Exit: +index - index to position in list +returns a pointer to the property, or NULL if not found +******************************************************************************/ + +PlyProperty *find_property( PlyElement *elem, char *prop_name, int *index ) +{ + int i; + + for ( i = 0; i < elem->nprops; i++ ) + if ( equal_strings ( prop_name, elem->props[i]->name ) ) + { + *index = i; + return ( elem->props[i] ); + } + + *index = -1; + return ( NULL ); +} + + +/****************************************************************************** +Read an element from an ascii file. + +Entry: +plyfile - file identifier +elem_ptr - pointer to element +******************************************************************************/ + +void ascii_get_element( PlyFile *plyfile, char *elem_ptr ) +{ + int j,k; + PlyElement *elem; + PlyProperty *prop; + char* *words; + int nwords; + int which_word; + char *elem_data,*item; + char *item_ptr; + int item_size; + int int_val; + unsigned int uint_val; + double double_val; + int list_count; + int store_it; + char* *store_array; + char *orig_line; + char *other_data; + int other_flag; + + item = (char*) NULL ; + other_data = (char*) NULL ; + + /* the kind of element we're reading currently */ + elem = plyfile->which_elem; + + /* do we need to setup for other_props? */ + + if ( elem->other_offset != NO_OTHER_PROPS ) + { + char* *ptr; + other_flag = 1; + /* make room for other_props */ + other_data = ( char * ) myalloc ( elem->other_size ); + /* store pointer in user's structure to the other_props */ + ptr = ( char * * ) ( elem_ptr + elem->other_offset ); + *ptr = other_data; + } + else + other_flag = 0; + + /* read in the element */ + + words = get_words ( plyfile->fp, &nwords, &orig_line ); + if ( words == NULL ) + { + fprintf ( stderr, "ply_get_element: unexpected end of file\n" ); + exit ( -1 ); + } + + which_word = 0; + + for ( j = 0; j < elem->nprops; j++ ) + { + prop = elem->props[j]; + store_it = ( elem->store_prop[j] | other_flag ); + + /* store either in the user's structure or in other_props */ + if ( elem->store_prop[j] ) + elem_data = elem_ptr; + else + elem_data = other_data; + + if ( prop->is_list == PLY_LIST ) + { + /* a list */ + + /* get and store the number of items in the list */ + get_ascii_item ( words[which_word++], prop->count_external, + &int_val, &uint_val, &double_val ); + if ( store_it ) + { + item = elem_data + prop->count_offset; + store_item( item, prop->count_internal, int_val, uint_val, double_val ); + } + + /* allocate space for an array of items and store a ptr to the array */ + list_count = int_val; + item_size = ply_type_size[prop->internal_type]; + store_array = ( char * * ) ( elem_data + prop->offset ); + + if ( list_count == 0 ) + { + if ( store_it ) + *store_array = NULL; + } + else + { + if ( store_it ) + { + item_ptr = ( char * ) myalloc ( sizeof ( char ) * item_size * list_count ); + item = item_ptr; + *store_array = item_ptr; + } + + /* read items and store them into the array */ + for ( k = 0; k < list_count; k++ ) + { + get_ascii_item ( words[which_word++], prop->external_type, + &int_val, &uint_val, &double_val ); + if ( store_it ) + { + store_item ( item, prop->internal_type, + int_val, uint_val, double_val ); + item += item_size; + } + } + } + } + else if ( prop->is_list == PLY_STRING ) + { + /* a string */ + if ( store_it ) + { + char *str; + char* *str_ptr; + str = strdup ( words[which_word++] ); + item = elem_data + prop->offset; + str_ptr = ( char * * ) item; + *str_ptr = str; + } + else + { + which_word++; + } + } + else + { + /* a scalar */ + get_ascii_item ( words[which_word++], prop->external_type, + &int_val, &uint_val, &double_val ); + if ( store_it ) + { + item = elem_data + prop->offset; + store_item ( item, prop->internal_type, int_val, uint_val, double_val ); + } + } + } + + free ( words ); +} + + +/****************************************************************************** +Read an element from a binary file. + +Entry: +plyfile - file identifier +elem_ptr - pointer to an element +******************************************************************************/ + +void binary_get_element( PlyFile *plyfile, char *elem_ptr ) +{ + int j,k; + PlyElement *elem; + PlyProperty *prop; + FILE *fp = plyfile->fp; + char *elem_data; + char *item; + char *item_ptr; + int item_size; + int int_val; + unsigned int uint_val; + double double_val; + int list_count; + int store_it; + char* *store_array; + char *other_data; + int other_flag; + + item = (char*) NULL ; + other_data = (char*) NULL ; + + /* the kind of element we're reading currently */ + elem = plyfile->which_elem; + + /* do we need to setup for other_props? */ + + if ( elem->other_offset != NO_OTHER_PROPS ) + { + char* *ptr; + other_flag = 1; + /* make room for other_props */ + other_data = ( char * ) myalloc ( elem->other_size ); + /* store pointer in user's structure to the other_props */ + ptr = ( char * * ) ( elem_ptr + elem->other_offset ); + *ptr = other_data; + } + else + other_flag = 0; + + /* read in a number of elements */ + + for ( j = 0; j < elem->nprops; j++ ) + { + prop = elem->props[j]; + store_it = ( elem->store_prop[j] | other_flag ); + + /* store either in the user's structure or in other_props */ + if ( elem->store_prop[j] ) + elem_data = elem_ptr; + else + elem_data = other_data; + + if ( prop->is_list == PLY_LIST ) + { + /* list */ + + /* get and store the number of items in the list */ + get_binary_item ( fp, prop->count_external, + &int_val, &uint_val, &double_val ); + if ( store_it ) + { + item = elem_data + prop->count_offset; + store_item( item, prop->count_internal, int_val, uint_val, double_val ); + } + + /* allocate space for an array of items and store a ptr to the array */ + list_count = int_val; + item_size = ply_type_size[prop->internal_type]; + store_array = ( char * * ) ( elem_data + prop->offset ); + if ( list_count == 0 ) + { + if ( store_it ) + *store_array = NULL; + } + else + { + if ( store_it ) + { + item_ptr = ( char * ) myalloc ( sizeof ( char ) * item_size * list_count ); + item = item_ptr; + *store_array = item_ptr; + } + + /* read items and store them into the array */ + for ( k = 0; k < list_count; k++ ) + { + get_binary_item ( fp, prop->external_type, + &int_val, &uint_val, &double_val ); + if ( store_it ) + { + store_item ( item, prop->internal_type, + int_val, uint_val, double_val ); + item += item_size; + } + } + } + } + else if ( prop->is_list == PLY_STRING ) + { + /* string */ + int len; + char *str; + fread ( &len, sizeof( int ), 1, fp ); + str = ( char * ) myalloc ( len ); + fread ( str, len, 1, fp ); + if ( store_it ) + { + char* *str_ptr; + item = elem_data + prop->offset; + str_ptr = ( char * * ) item; + *str_ptr = str; + } + } + else + { + /* scalar */ + get_binary_item ( fp, prop->external_type, + &int_val, &uint_val, &double_val ); + if ( store_it ) + { + item = elem_data + prop->offset; + store_item ( item, prop->internal_type, int_val, uint_val, double_val ); + } + } + } +} + + +/****************************************************************************** +Write to a file the word that represents a PLY data type. + +Entry: +fp - file pointer +code - code for type +******************************************************************************/ + +void write_scalar_type( FILE *fp, int code ) +{ + /* make sure this is a valid code */ + + if ( code <= StartType || code >= EndType ) + { + fprintf ( stderr, "write_scalar_type: bad data code = %d\n", code ); + exit ( -1 ); + } + + /* write the code to a file */ + + fprintf ( fp, "%s", type_names[code] ); +} + + +/****************************************************************************** +Get a text line from a file and break it up into words. + +IMPORTANT: The calling routine should call "free" on the returned pointer once +finished with it. + +Entry: +fp - file to read from + +Exit: +nwords - number of words returned +orig_line - the original line of characters +returns a list of words from the line, or NULL if end-of-file +******************************************************************************/ + +char **get_words( FILE *fp, int *nwords, char **orig_line ) +{ +#define BIG_STRING 4096 + static char str[BIG_STRING]; + static char str_copy[BIG_STRING]; + char* *words; + int max_words = 10; + int num_words = 0; + char *ptr,*ptr2; + char *result; + + words = ( char * * ) myalloc ( sizeof ( char * ) * max_words ); + + /* read in a line */ + result = fgets ( str, BIG_STRING, fp ); + if ( result == NULL ) + { + *nwords = 0; + *orig_line = NULL; + return ( NULL ); + } + + /* convert line-feed and tabs into spaces */ + /* (this guarentees that there will be a space before the */ + /* null character at the end of the string) */ + + str[BIG_STRING - 2] = ' '; + str[BIG_STRING - 1] = '\0'; + + for ( ptr = str, ptr2 = str_copy; *ptr != '\0'; ptr++, ptr2++ ) + { + *ptr2 = *ptr; + if ( *ptr == '\t' ) + { + *ptr = ' '; + *ptr2 = ' '; + } + else if ( *ptr == '\n' ) + { + *ptr = ' '; + *ptr2 = ' '; + break; + } + else if ( *ptr == '\r' ) + { + *ptr = ' '; + *ptr2 = '\0'; + } + } + + /* find the words in the line */ + + ptr = str; + while ( *ptr != '\0' ) + { + /* jump over leading spaces */ + while ( *ptr == ' ' ) + ptr++; + + /* break if we reach the end */ + if ( *ptr == '\0' ) + break; + + /* allocate more room for words if necessary */ + if ( num_words >= max_words ) + { + max_words += 10; + words = ( char * * ) realloc ( words, sizeof ( char * ) * max_words ); + } + + if ( *ptr == '\"' ) + { + /* a quote indidicates that we have a string */ + + /* skip over leading quote */ + ptr++; + + /* save pointer to beginning of word */ + words[num_words++] = ptr; + + /* find trailing quote or end of line */ + while ( *ptr != '\"' && *ptr != '\0' ) + ptr++; + + /* replace quote with a null character to mark the end of the word */ + /* if we are not already at the end of the line */ + if ( *ptr != '\0' ) + *ptr++ = '\0'; + } + else + { + /* non-string */ + + /* save pointer to beginning of word */ + words[num_words++] = ptr; + + /* jump over non-spaces */ + while ( *ptr != ' ' ) + ptr++; + + /* place a null character here to mark the end of the word */ + *ptr++ = '\0'; + } + } + + /* return the list of words */ + *nwords = num_words; + *orig_line = str_copy; + return ( words ); +} + + +/****************************************************************************** +Return the value of an item, given a pointer to it and its type. + +Entry: +item - pointer to item +type - data type that "item" points to + +Exit: +returns a double-precision float that contains the value of the item +******************************************************************************/ + +double get_item_value( char *item, int type ) +{ + unsigned char *puchar; + char *pchar; + short int *pshort; + unsigned short int *pushort; + int *pint; + unsigned int *puint; + float *pfloat; + double *pdouble; + int int_value; + unsigned int uint_value; + double double_value; + + switch ( type ) + { + case Int8: + pchar = ( char * ) item; + int_value = *pchar; + return ( ( double ) int_value ); + case Uint8: + puchar = ( unsigned char * ) item; + int_value = *puchar; + return ( ( double ) int_value ); + case Int16: + pshort = ( short int * ) item; + int_value = *pshort; + return ( ( double ) int_value ); + case Uint16: + pushort = ( unsigned short int * ) item; + int_value = *pushort; + return ( ( double ) int_value ); + case Int32: + pint = ( int * ) item; + int_value = *pint; + return ( ( double ) int_value ); + case Uint32: + puint = ( unsigned int * ) item; + uint_value = *puint; + return ( ( double ) uint_value ); + case Float32: + pfloat = ( float * ) item; + double_value = *pfloat; + return ( double_value ); + case Float64: + pdouble = ( double * ) item; + double_value = *pdouble; + return ( double_value ); + default: + fprintf ( stderr, "get_item_value: bad type = %d\n", type ); + exit ( -1 ); + } + + return ( 0.0 ); /* never actually gets here */ +} + + +/****************************************************************************** +Write out an item to a file as raw binary bytes. + +Entry: +fp - file to write to +int_val - integer version of item +uint_val - unsigned integer version of item +double_val - double-precision float version of item +type - data type to write out +******************************************************************************/ + +void write_binary_item( FILE *fp, int int_val, unsigned int uint_val, double double_val, int type ) +{ + unsigned char uchar_val; + char char_val; + unsigned short ushort_val; + short short_val; + float float_val; + + switch ( type ) + { + case Int8: + char_val = int_val; + fwrite ( &char_val, 1, 1, fp ); + break; + case Int16: + short_val = int_val; + fwrite ( &short_val, 2, 1, fp ); + break; + case Int32: + fwrite ( &int_val, 4, 1, fp ); + break; + case Uint8: + uchar_val = uint_val; + fwrite ( &uchar_val, 1, 1, fp ); + break; + case Uint16: + ushort_val = uint_val; + fwrite ( &ushort_val, 2, 1, fp ); + break; + case Uint32: + fwrite ( &uint_val, 4, 1, fp ); + break; + case Float32: + float_val = ( float ) double_val; + fwrite ( &float_val, 4, 1, fp ); + break; + case Float64: + fwrite ( &double_val, 8, 1, fp ); + break; + default: + fprintf ( stderr, "write_binary_item: bad type = %d\n", type ); + exit ( -1 ); + } +} + + +/****************************************************************************** +Write out an item to a file as ascii characters. + +Entry: +fp - file to write to +int_val - integer version of item +uint_val - unsigned integer version of item +double_val - double-precision float version of item +type - data type to write out +******************************************************************************/ + +void write_ascii_item( FILE *fp, int int_val, unsigned int uint_val, double double_val, int type ) +{ + switch ( type ) + { + case Int8: + case Int16: + case Int32: + fprintf ( fp, "%d ", int_val ); + break; + case Uint8: + case Uint16: + case Uint32: + fprintf ( fp, "%u ", uint_val ); + break; + case Float32: + case Float64: + fprintf ( fp, "%12f ", double_val ); + break; + default: + fprintf ( stderr, "write_ascii_item: bad type = %d\n", type ); + exit ( -1 ); + } +} + + +/****************************************************************************** +Get the value of an item that is in memory, and place the result +into an integer, an unsigned integer and a double. + +Entry: +ptr - pointer to the item +type - data type supposedly in the item + +Exit: +int_val - integer value +uint_val - unsigned integer value +double_val - double-precision floating point value +******************************************************************************/ + +void get_stored_item( void *ptr, int type, int *int_val, unsigned int *uint_val, double *double_val ) +{ + switch ( type ) + { + case Int8: + *int_val = *( ( char * ) ptr ); + *uint_val = *int_val; + *double_val = *int_val; + break; + case Uint8: + *uint_val = *( ( unsigned char * ) ptr ); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case Int16: + *int_val = *( ( short int * ) ptr ); + *uint_val = *int_val; + *double_val = *int_val; + break; + case Uint16: + *uint_val = *( ( unsigned short int * ) ptr ); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case Int32: + *int_val = *( ( int * ) ptr ); + *uint_val = *int_val; + *double_val = *int_val; + break; + case Uint32: + *uint_val = *( ( unsigned int * ) ptr ); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case Float32: + *double_val = *( ( float * ) ptr ); + *int_val = ( int ) *double_val; + *uint_val = ( unsigned int ) *double_val; + break; + case Float64: + *double_val = *( ( double * ) ptr ); + *int_val = ( int ) *double_val; + *uint_val = ( unsigned int ) *double_val; + break; + default: + fprintf ( stderr, "get_stored_item: bad type = %d\n", type ); + exit ( -1 ); + } +} + + +/****************************************************************************** +Get the value of an item from a binary file, and place the result +into an integer, an unsigned integer and a double. + +Entry: +fp - file to get item from +type - data type supposedly in the word + +Exit: +int_val - integer value +uint_val - unsigned integer value +double_val - double-precision floating point value +******************************************************************************/ + +void get_binary_item( FILE *fp, int type, int *int_val, unsigned int *uint_val, double *double_val ) +{ + char c[8]; + void *ptr; + + ptr = ( void * ) c; + + switch ( type ) + { + case Int8: + fread ( ptr, 1, 1, fp ); + *int_val = *( ( char * ) ptr ); + *uint_val = *int_val; + *double_val = *int_val; + break; + case Uint8: + fread ( ptr, 1, 1, fp ); + *uint_val = *( ( unsigned char * ) ptr ); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case Int16: + fread ( ptr, 2, 1, fp ); + *int_val = *( ( short int * ) ptr ); + *uint_val = *int_val; + *double_val = *int_val; + break; + case Uint16: + fread ( ptr, 2, 1, fp ); + *uint_val = *( ( unsigned short int * ) ptr ); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case Int32: + fread ( ptr, 4, 1, fp ); + *int_val = *( ( int * ) ptr ); + *uint_val = *int_val; + *double_val = *int_val; + break; + case Uint32: + fread ( ptr, 4, 1, fp ); + *uint_val = *( ( unsigned int * ) ptr ); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case Float32: + fread ( ptr, 4, 1, fp ); + *double_val = *( ( float * ) ptr ); + *int_val = ( int ) *double_val; + *uint_val = ( unsigned int ) *double_val; + break; + case Float64: + fread ( ptr, 8, 1, fp ); + *double_val = *( ( double * ) ptr ); + *int_val = ( int ) *double_val; + *uint_val = ( unsigned int ) *double_val; + break; + default: + fprintf ( stderr, "get_binary_item: bad type = %d\n", type ); + exit ( -1 ); + } +} + + +/****************************************************************************** +Extract the value of an item from an ascii word, and place the result +into an integer, an unsigned integer and a double. + +Entry: +word - word to extract value from +type - data type supposedly in the word + +Exit: +int_val - integer value +uint_val - unsigned integer value +double_val - double-precision floating point value +******************************************************************************/ + +void get_ascii_item( char *word, int type, int *int_val, unsigned int *uint_val, double *double_val ) +{ + switch ( type ) + { + case Int8: + case Uint8: + case Int16: + case Uint16: + case Int32: + *int_val = atoi ( word ); + *uint_val = *int_val; + *double_val = *int_val; + break; + + case Uint32: + *uint_val = strtoul ( word, ( char * * ) NULL, 10 ); + *int_val = *uint_val; + *double_val = *uint_val; + break; + + case Float32: + case Float64: + *double_val = atof ( word ); + *int_val = ( int ) *double_val; + *uint_val = ( unsigned int ) *double_val; + break; + + default: + fprintf ( stderr, "get_ascii_item: bad type = %d\n", type ); + exit ( -1 ); + } +} + + +/****************************************************************************** +Store a value into a place being pointed to, guided by a data type. + +Entry: +item - place to store value +type - data type +int_val - integer version of value +uint_val - unsigned integer version of value +double_val - double version of value + +Exit: +item - pointer to stored value +******************************************************************************/ + +void store_item( char *item, int type, int int_val, unsigned int uint_val, double double_val ) +{ + unsigned char *puchar; + short int *pshort; + unsigned short int *pushort; + int *pint; + unsigned int *puint; + float *pfloat; + double *pdouble; + + switch ( type ) + { + case Int8: + *item = int_val; + break; + case Uint8: + puchar = ( unsigned char * ) item; + *puchar = uint_val; + break; + case Int16: + pshort = ( short * ) item; + *pshort = int_val; + break; + case Uint16: + pushort = ( unsigned short * ) item; + *pushort = uint_val; + break; + case Int32: + pint = ( int * ) item; + *pint = int_val; + break; + case Uint32: + puint = ( unsigned int * ) item; + *puint = uint_val; + break; + case Float32: + pfloat = ( float * ) item; + *pfloat = ( float ) double_val; + break; + case Float64: + pdouble = ( double * ) item; + *pdouble = double_val; + break; + default: + fprintf ( stderr, "store_item: bad type = %d\n", type ); + exit ( -1 ); + } +} + + +/****************************************************************************** +Add an element to a PLY file descriptor. + +Entry: +plyfile - PLY file descriptor +words - list of words describing the element +nwords - number of words in the list +******************************************************************************/ + +void add_element( PlyFile *plyfile, char **words, int nwords ) +{ + PlyElement *elem; + + /* create the new element */ + elem = ( PlyElement * ) myalloc ( sizeof ( PlyElement ) ); + elem->name = strdup ( words[1] ); + elem->num = atoi ( words[2] ); + elem->nprops = 0; + + /* make room for new element in the object's list of elements */ + if ( plyfile->num_elem_types == 0 ) + plyfile->elems = ( PlyElement * * ) myalloc ( sizeof ( PlyElement * ) ); + else + plyfile->elems = ( PlyElement * * ) realloc ( plyfile->elems, + sizeof ( PlyElement * ) * ( plyfile->num_elem_types + 1 ) ); + + /* add the new element to the object's list */ + plyfile->elems[plyfile->num_elem_types] = elem; + plyfile->num_elem_types++; +} + + +/****************************************************************************** +Return the type of a property, given the name of the property. + +Entry: +name - name of property type + +Exit: +returns integer code for property, or 0 if not found +******************************************************************************/ + +int get_prop_type( char *type_name ) +{ + int i; + + /* try to match the type name */ + for ( i = StartType + 1; i < EndType; i++ ) + if ( equal_strings ( type_name, type_names[i] ) ) + return ( i ); + + /* see if we can match an old type name */ + for ( i = StartType + 1; i < EndType; i++ ) + if ( equal_strings ( type_name, old_type_names[i] ) ) + return ( i ); + + /* if we get here, we didn't find the type */ + return ( 0 ); +} + + +/****************************************************************************** +Add a property to a PLY file descriptor. + +Entry: +plyfile - PLY file descriptor +words - list of words describing the property +nwords - number of words in the list +******************************************************************************/ + +void add_property( PlyFile *plyfile, char **words, int nwords ) +{ + PlyProperty *prop; + PlyElement *elem; + + /* create the new property */ + + prop = ( PlyProperty * ) myalloc ( sizeof ( PlyProperty ) ); + + if ( equal_strings ( words[1], "list" ) ) + { + /* list */ + prop->count_external = get_prop_type ( words[2] ); + prop->external_type = get_prop_type ( words[3] ); + prop->name = strdup ( words[4] ); + prop->is_list = PLY_LIST; + } + else if ( equal_strings ( words[1], "string" ) ) + { + /* string */ + prop->count_external = Int8; + prop->external_type = Int8; + prop->name = strdup ( words[2] ); + prop->is_list = PLY_STRING; + } + else + { + /* scalar */ + prop->external_type = get_prop_type ( words[1] ); + prop->name = strdup ( words[2] ); + prop->is_list = PLY_SCALAR; + } + + /* add this property to the list of properties of the current element */ + + elem = plyfile->elems[plyfile->num_elem_types - 1]; + + if ( elem->nprops == 0 ) + elem->props = ( PlyProperty * * ) myalloc ( sizeof ( PlyProperty * ) ); + else + elem->props = ( PlyProperty * * ) realloc ( elem->props, + sizeof ( PlyProperty * ) * ( elem->nprops + 1 ) ); + + elem->props[elem->nprops] = prop; + elem->nprops++; +} + + +/****************************************************************************** +Add a comment to a PLY file descriptor. + +Entry: +plyfile - PLY file descriptor +line - line containing comment +******************************************************************************/ + +void add_comment( PlyFile *plyfile, char *line ) +{ + int i; + + /* skip over "comment" and leading spaces and tabs */ + i = 7; + while ( line[i] == ' ' || line[i] == '\t' ) + i++; + + append_comment_ply ( plyfile, &line[i] ); +} + + +/****************************************************************************** +Add a some object information to a PLY file descriptor. + +Entry: +plyfile - PLY file descriptor +line - line containing text info +******************************************************************************/ + +void add_obj_info( PlyFile *plyfile, char *line ) +{ + int i; + + /* skip over "obj_info" and leading spaces and tabs */ + i = 8; + while ( line[i] == ' ' || line[i] == '\t' ) + i++; + + append_obj_info_ply ( plyfile, &line[i] ); +} + + +/****************************************************************************** +Copy a property. +******************************************************************************/ + +void copy_property( PlyProperty *dest, PlyProperty *src ) +{ + dest->name = strdup ( src->name ); + dest->external_type = src->external_type; + dest->internal_type = src->internal_type; + dest->offset = src->offset; + + dest->is_list = src->is_list; + dest->count_external = src->count_external; + dest->count_internal = src->count_internal; + dest->count_offset = src->count_offset; +} + + +/****************************************************************************** +Allocate some memory. + +Entry: +size - amount of memory requested (in bytes) +lnum - line number from which memory was requested +fname - file name from which memory was requested +******************************************************************************/ + +static char *my_alloc( int size, int lnum, char *fname ) +{ + char *ptr; + + ptr = ( char * ) malloc ( size ); + + if ( ptr == 0 ) + { + fprintf( stderr, "Memory allocation bombed on line %d in %s\n", lnum, fname ); + } + + return ( ptr ); +} + + +/**** NEW STUFF ****/ +/**** NEW STUFF ****/ +/**** NEW STUFF ****/ +/**** NEW STUFF ****/ + + + +/****************************************************************************** +Given a file pointer, get ready to read PLY data from the file. + +Entry: +fp - the given file pointer + +Exit: +nelems - number of elements in object +elem_names - list of element names +returns a pointer to a PlyFile, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *read_ply( FILE *fp ) +{ + PlyFile *ply; + int num_elems; + char* *elem_names; + + ply = ply_read ( fp, &num_elems, &elem_names ); + + return ( ply ); +} + + +/****************************************************************************** +Given a file pointer, get ready to write PLY data to the file. + +Entry: +fp - the given file pointer +nelems - number of elements in object +elem_names - list of element names +file_type - file type, either ascii or binary + +Exit: +returns a pointer to a PlyFile, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *write_ply( FILE *fp, int nelems, char **elem_names, int file_type ) +{ + PlyFile *ply; + + ply = ply_write ( fp, nelems, elem_names, file_type ); + + return ( ply ); +} + + +/****************************************************************************** +Return a list of the names of the elements in a particular PLY file. + +Entry: +ply - PLY file whose element name list we want + +Exit: +num_elems - the number of element names in the list +returns the list of names +******************************************************************************/ + +char **get_element_list_ply( PlyFile *ply, int *num_elems ) +{ + int i; + char* *elist; + + /* create the list of element names */ + + elist = ( char * * ) myalloc ( sizeof ( char * ) * ply->num_elem_types ); + for ( i = 0; i < ply->num_elem_types; i++ ) + elist[i] = strdup ( ply->elems[i]->name ); + + /* return the number of elements and the list of element names */ + *num_elems = ply->num_elem_types; + return ( elist ); +} + + +/****************************************************************************** +Append a comment to a PLY file. + +Entry: +ply - file to append comment to +comment - the comment to append +******************************************************************************/ + +void append_comment_ply( PlyFile *ply, char *comment ) +{ + /* (re)allocate space for new comment */ + if ( ply->num_comments == 0 ) + ply->comments = ( char * * ) myalloc ( sizeof ( char * ) ); + else + ply->comments = ( char * * ) realloc ( ply->comments, + sizeof ( char * ) * ( ply->num_comments + 1 ) ); + + /* add comment to list */ + ply->comments[ply->num_comments] = strdup ( comment ); + ply->num_comments++; +} + + +/****************************************************************************** +Copy the comments from one PLY file to another. + +Entry: +out_ply - destination file to copy comments to +in_ply - the source of the comments +******************************************************************************/ + +void copy_comments_ply( PlyFile *out_ply, PlyFile *in_ply ) +{ + int i; + + for ( i = 0; i < in_ply->num_comments; i++ ) + append_comment_ply ( out_ply, in_ply->comments[i] ); +} + + +/****************************************************************************** +Append object information (arbitrary text) to a PLY file. + +Entry: +ply - file to append object info to +obj_info - the object info to append +******************************************************************************/ + +void append_obj_info_ply( PlyFile *ply, char *obj_info ) +{ + /* (re)allocate space for new info */ + if ( ply->num_obj_info == 0 ) + ply->obj_info = ( char * * ) myalloc ( sizeof ( char * ) ); + else + ply->obj_info = ( char * * ) realloc ( ply->obj_info, + sizeof ( char * ) * ( ply->num_obj_info + 1 ) ); + + /* add info to list */ + ply->obj_info[ply->num_obj_info] = strdup ( obj_info ); + ply->num_obj_info++; +} + + +/****************************************************************************** +Copy the object information from one PLY file to another. + +Entry: +out_ply - destination file to copy object information to +in_ply - the source of the object information +******************************************************************************/ + +void copy_obj_info_ply( PlyFile *out_ply, PlyFile *in_ply ) +{ + int i; + + for ( i = 0; i < in_ply->num_obj_info; i++ ) + append_obj_info_ply ( out_ply, in_ply->obj_info[i] ); +} + + +/****************************************************************************** +Close a PLY file. + +Entry: +plyfile - identifier of file to close +******************************************************************************/ + +void close_ply( PlyFile *plyfile ) +{ + fclose ( plyfile->fp ); +} + + +/****************************************************************************** +Free the memory used by a PLY file. + +Entry: +plyfile - identifier of file +******************************************************************************/ + +void free_ply( PlyFile *plyfile ) +{ + /* free up memory associated with the PLY file */ + free ( plyfile ); +} + + +/****************************************************************************** +Specify the index of the next element to be read in from a PLY file. + +Entry: +ply - file to read from +index - index of the element to be read + +Exit: +elem_count - the number of elements in the file +returns pointer to the name of this next element +******************************************************************************/ + +char *setup_element_read_ply( PlyFile *ply, int index, int *elem_count ) +{ + PlyElement *elem; + + if ( index < 0 || index > ply->num_elem_types ) + { + fprintf ( stderr, "Warning: No element with index %d\n", index ); + return ( 0 ); + } + + elem = ply->elems[index]; + + /* set this to be the current element */ + ply->which_elem = elem; + + /* return the number of such elements in the file and the element's name */ + *elem_count = elem->num; + return ( elem->name ); +} + + +/****************************************************************************** +Read one element from the file. This routine assumes that we're reading +the type of element specified in the last call to the routine +setup_element_read_ply(). + +Entry: +plyfile - file identifier +elem_ptr - pointer to location where the element information should be put +******************************************************************************/ + +void get_element_ply( PlyFile *plyfile, void *elem_ptr ) +{ + if ( plyfile->file_type == PLY_ASCII ) + ascii_get_element ( plyfile, ( char * ) elem_ptr ); + else + binary_get_element ( plyfile, ( char * ) elem_ptr ); +} + + +/****************************************************************************** +Specify one of several properties of the current element that is to be +read from a file. This should be called (usually multiple times) before a +call to the routine get_element_ply(). + +Entry: +plyfile - file identifier +prop - property to add to those that will be returned + +Exit: +0 if the property has not been found +1 if the property has been found +******************************************************************************/ + +int setup_property_ply( PlyFile *plyfile, PlyProperty *prop ) +{ + PlyElement *elem; + PlyProperty *prop_ptr; + int index; + + elem = plyfile->which_elem; + + /* deposit the property information into the element's description */ + + prop_ptr = find_property ( elem, prop->name, &index ); + if ( prop_ptr == NULL ) + { + fprintf ( stderr, "Warning: Can't find property '%s' in element '%s'\n", + prop->name, elem->name ); + return 0; + } + prop_ptr->internal_type = prop->internal_type; + prop_ptr->offset = prop->offset; + prop_ptr->count_internal = prop->count_internal; + prop_ptr->count_offset = prop->count_offset; + + /* specify that the user wants this property */ + elem->store_prop[index] = STORE_PROP; + return 1 ; +} + + +/****************************************************************************** +Specify that we want the "other" properties of the current element to be tucked +away within the user's structure. + +Entry: +plyfile - file identifier +offset - offset to where other_props will be stored inside user's structure + +Exit: +returns pointer to structure containing description of other_props +******************************************************************************/ + +PlyOtherProp *get_other_properties_ply( PlyFile *plyfile, int offset ) +{ + PlyOtherProp *other; + + other = get_other_properties ( plyfile, plyfile->which_elem, offset ); + return ( other ); +} + + +/****************************************************************************** +Describe which element is to be written next and state how many of them will +be written. + +Entry: +plyfile - file identifier +elem_name - name of element that information is being described +nelems - number of elements of this type to be written +******************************************************************************/ + +void describe_element_ply( PlyFile *plyfile, char *elem_name, int nelems ) +{ + PlyElement *elem; + + /* look for appropriate element */ + elem = find_element ( plyfile, elem_name ); + if ( elem == NULL ) + { + fprintf( stderr,"describe_element_ply: can't find element '%s'\n",elem_name ); + exit ( -1 ); + } + + elem->num = nelems; + + /* now this element is the current element */ + plyfile->which_elem = elem; +} + + +/****************************************************************************** +Describe a property of an element. + +Entry: +plyfile - file identifier +prop - the new property +******************************************************************************/ + +void describe_property_ply( PlyFile *plyfile, PlyProperty *prop ) +{ + PlyElement *elem; + PlyProperty *elem_prop; + + elem = plyfile->which_elem; + + /* create room for new property */ + + if ( elem->nprops == 0 ) + { + elem->props = ( PlyProperty * * ) myalloc ( sizeof ( PlyProperty * ) ); + elem->store_prop = ( char * ) myalloc ( sizeof ( char ) ); + elem->nprops = 1; + } + else + { + elem->nprops++; + elem->props = ( PlyProperty * * ) + realloc ( elem->props, sizeof ( PlyProperty * ) * elem->nprops ); + elem->store_prop = ( char * ) + realloc ( elem->store_prop, sizeof ( char ) * elem->nprops ); + } + + /* copy the new property */ + + elem_prop = ( PlyProperty * ) myalloc ( sizeof ( PlyProperty ) ); + elem->props[elem->nprops - 1] = elem_prop; + elem->store_prop[elem->nprops - 1] = NAMED_PROP; + copy_property ( elem_prop, prop ); +} + + +/****************************************************************************** +Describe what the "other" properties are that are to be stored, and where +they are in an element. +******************************************************************************/ + +void describe_other_properties_ply( PlyFile *plyfile, PlyOtherProp *other, int offset ) +{ + int i; + PlyElement *elem; + PlyProperty *prop; + + /* look for appropriate element */ + elem = find_element ( plyfile, other->name ); + if ( elem == NULL ) + { + fprintf( stderr, "describe_other_properties_ply: can't find element '%s'\n", + other->name ); + return; + } + + /* create room for other properties */ + + if ( elem->nprops == 0 ) + { + elem->props = ( PlyProperty * * ) + myalloc ( sizeof ( PlyProperty * ) * other->nprops ); + elem->store_prop = ( char * ) myalloc ( sizeof ( char ) * other->nprops ); + elem->nprops = 0; + } + else + { + int newsize; + newsize = elem->nprops + other->nprops; + elem->props = ( PlyProperty * * ) + realloc ( elem->props, sizeof ( PlyProperty * ) * newsize ); + elem->store_prop = ( char * ) + realloc ( elem->store_prop, sizeof ( char ) * newsize ); + } + + /* copy the other properties */ + + for ( i = 0; i < other->nprops; i++ ) + { + prop = ( PlyProperty * ) myalloc ( sizeof ( PlyProperty ) ); + copy_property ( prop, other->props[i] ); + elem->props[elem->nprops] = prop; + elem->store_prop[elem->nprops] = OTHER_PROP; + elem->nprops++; + } + + /* save other info about other properties */ + elem->other_size = other->size; + elem->other_offset = offset; +} + + +/****************************************************************************** +Pass along a pointer to "other" elements that we want to save in a given +PLY file. These other elements were presumably read from another PLY file. + +Entry: +plyfile - file pointer in which to store this other element info +other_elems - info about other elements that we want to store +******************************************************************************/ + +void describe_other_elements_ply( PlyFile *plyfile, PlyOtherElems *other_elems ) +{ + int i; + OtherElem *other; + + /* ignore this call if there is no other element */ + if ( other_elems == NULL ) + return; + + /* save pointer to this information */ + plyfile->other_elems = other_elems; + + /* describe the other properties of this element */ + + for ( i = 0; i < other_elems->num_elems; i++ ) + { + other = &( other_elems->other_list[i] ); + element_count_ply ( plyfile, other->elem_name, other->elem_count ); + describe_other_properties_ply ( plyfile, other->other_props, + offsetof( OtherData,other_props ) ); + } +} + + + +/**** Property Propagation Rules ****/ + + +typedef struct RuleName { +int code; +char *name; +} RuleName; + +RuleName rule_name_list[] = { +{AVERAGE_RULE, "avg"}, +{RANDOM_RULE, "rnd"}, +{MINIMUM_RULE, "max"}, +{MAXIMUM_RULE, "min"}, +{MAJORITY_RULE, "major"}, +{SAME_RULE, "same"}, +{-1, "end_marker"}, +}; + + + +/****************************************************************************** +Initialize the property propagation rules for an element. Default is to +use averaging (AVERAGE_RULE) for creating all new properties. + +Entry: +ply - PLY object that this is for +elem_name - name of the element that we're making the rules for + +Exit: +returns pointer to the default rules +******************************************************************************/ + +PlyPropRules *init_rule_ply( PlyFile *ply, char *elem_name ) +{ + int i,j; + PlyElement *elem; + PlyPropRules *rules; + PlyRuleList *list; + int found_prop; + + elem = find_element ( ply, elem_name ); + if ( elem == NULL ) + { + fprintf ( stderr, "init_rule_ply: Can't find element '%s'\n", elem_name ); + exit ( -1 ); + } + + rules = ( PlyPropRules * ) myalloc ( sizeof ( PlyPropRules ) ); + rules->elem = elem; + rules->rule_list = ( int * ) myalloc ( sizeof( int ) * elem->nprops ); + rules->max_props = 0; + rules->nprops = 0; + + /* default is to use averaging rule */ + for ( i = 0; i < elem->nprops; i++ ) + rules->rule_list[i] = AVERAGE_RULE; + + /* see if there are other rules we should use */ + + if ( ply->rule_list == NULL ) + return ( rules ); + + /* try to match the element, property and rule name */ + + for ( list = ply->rule_list; list != NULL; list = list->next ) + { + if ( !equal_strings ( list->element, elem->name ) ) + continue; + + found_prop = 0; + + for ( i = 0; i < elem->nprops; i++ ) + if ( equal_strings ( list->property, elem->props[i]->name ) ) + { + found_prop = 1; + + /* look for matching rule name */ + for ( j = 0; rule_name_list[j].code != -1; j++ ) + if ( equal_strings ( list->name, rule_name_list[j].name ) ) + { + rules->rule_list[i] = rule_name_list[j].code; + break; + } + } + + if ( !found_prop ) + { + fprintf ( stderr, "Can't find property '%s' for rule '%s'\n", + list->property, list->name ); + continue; + } + } + + return ( rules ); +} + + +/****************************************************************************** +odify a property propagation rule. + +Entry: +rules - rules for the element +prop_name - name of the property whose rule we're modifying +rule_type - type of rule (MAXIMUM_RULE, MINIMUM_RULE, MAJORITY_RULE, etc.) +******************************************************************************/ + +void modify_rule_ply( PlyPropRules *rules, char *prop_name, int rule_type ) +{ + int i; + PlyElement *elem = rules->elem; + + /* find the property and modify its rule type */ + + for ( i = 0; i < elem->nprops; i++ ) + if ( equal_strings ( elem->props[i]->name, prop_name ) ) + { + rules->rule_list[i] = rule_type; + return; + } + + /* we didn't find the property if we get here */ + fprintf ( stderr, "modify_rule_ply: Can't find property '%s'\n", prop_name ); + exit ( -1 ); +} + + +/****************************************************************************** +Begin to create a set of properties from a set of propagation rules. + +Entry: +ply - PLY object whose rules we're preparing to use +rules - rules for the element +******************************************************************************/ + +void start_props_ply( PlyFile *ply, PlyPropRules *rules ) +{ + /* PlyElement *elem = rules->elem; */ + + /* save pointer to the rules in the PLY object */ + ply->current_rules = rules; + + /* get ready for new sets of properties to combine */ + rules->nprops = 0; +} + + +/****************************************************************************** +Remember a set of properties and their weights for creating a new set of +properties. + +Entry: +weight - weights for this set of properties +other_props - the properties to use +******************************************************************************/ + +void weight_props_ply( PlyFile *ply, float weight, void *other_props ) +{ + PlyPropRules *rules = ply->current_rules; + + /* allocate space for properties and weights, if necessary */ + if ( rules->max_props == 0 ) + { + rules->max_props = 6; + rules->props = ( void * * ) myalloc ( sizeof ( void * ) * rules->max_props ); + rules->weights = ( float * ) myalloc ( sizeof ( float ) * rules->max_props ); + } + if ( rules->nprops == rules->max_props ) + { + rules->max_props *= 2; + rules->props = ( void * * ) realloc ( rules->props, + sizeof ( void * ) * rules->max_props ); + rules->weights = ( float * ) realloc ( rules->weights, + sizeof ( float ) * rules->max_props ); + } + + /* remember these new properties and their weights */ + + rules->props[rules->nprops] = other_props; + rules->weights[rules->nprops] = weight; + rules->nprops++; +} + + +/****************************************************************************** +Return a pointer to a new set of properties that have been created using +a specified set of property combination rules and a given collection of +"other" properties. + +Exit: +returns a pointer to the new properties +******************************************************************************/ + +void *get_new_props_ply( PlyFile *ply ) +{ + int i,j; + static double *vals; + static int max_vals = 0; + PlyPropRules *rules = ply->current_rules; + PlyElement *elem = rules->elem; + PlyProperty *prop; + char *data; + char *new_data; + void *ptr; + int offset; + int type; + double double_val; + int int_val; + unsigned int uint_val; + int random_pick; + + /* return NULL if we've got no "other" properties */ + if ( elem->other_size == 0 ) + { + return ( NULL ); + } + + /* create room for combined other properties */ + new_data = ( char * ) myalloc ( sizeof ( char ) * elem->other_size ); + + /* make sure there is enough room to store values we're to combine */ + + if ( max_vals == 0 ) + { + max_vals = rules->nprops; + vals = ( double * ) myalloc ( sizeof ( double ) * rules->nprops ); + } + if ( rules->nprops >= max_vals ) + { + max_vals = rules->nprops; + vals = ( double * ) realloc ( vals, sizeof ( double ) * rules->nprops ); + } + + /* in case we need a random choice */ + random_pick = ( int ) floor ( rules->nprops ); //* drand48()); + + /* calculate the combination for each "other" property of the element */ + + for ( i = 0; i < elem->nprops; i++ ) + { + /* don't bother with properties we've been asked to store explicitly */ + if ( elem->store_prop[i] ) + continue; + + prop = elem->props[i]; + offset = prop->offset; + type = prop->external_type; + + /* collect together all the values we're to combine */ + + for ( j = 0; j < rules->nprops; j++ ) + { + data = ( char * ) rules->props[j]; + ptr = ( void * ) ( data + offset ); + get_stored_item ( ( void * ) ptr, type, &int_val, &uint_val, &double_val ); + vals[j] = double_val; + } + + /* calculate the combined value */ + + switch ( rules->rule_list[i] ) + { + case AVERAGE_RULE: + { + double sum = 0; + double weight_sum = 0; + for ( j = 0; j < rules->nprops; j++ ) + { + sum += vals[j] * rules->weights[j]; + weight_sum += rules->weights[j]; + } + double_val = sum / weight_sum; + break; + } + case MINIMUM_RULE: + { + double_val = vals[0]; + for ( j = 1; j < rules->nprops; j++ ) + if ( double_val > vals[j] ) + double_val = vals[j]; + break; + } + case MAXIMUM_RULE: + { + double_val = vals[0]; + for ( j = 1; j < rules->nprops; j++ ) + if ( double_val < vals[j] ) + double_val = vals[j]; + break; + } + case RANDOM_RULE: + { + double_val = vals[random_pick]; + break; + } + case SAME_RULE: + { + double_val = vals[0]; + for ( j = 1; j < rules->nprops; j++ ) + if ( double_val != vals[j] ) + { + fprintf ( stderr, + "get_new_props_ply: Error combining properties that should be the same.\n" ); + exit ( -1 ); + } + break; + } + default: + fprintf ( stderr, "get_new_props_ply: Bad rule = %d\n", + rules->rule_list[i] ); + exit ( -1 ); + } + + /* store the combined value */ + + int_val = ( int ) double_val; + uint_val = ( unsigned int ) double_val; + ptr = ( void * ) ( new_data + offset ); + store_item ( ( char * ) ptr, type, int_val, uint_val, double_val ); + } + + return ( ( void * ) new_data ); +} + + +/****************************************************************************** +Set the list of user-specified property combination rules. +******************************************************************************/ + +void set_prop_rules_ply( PlyFile *ply, PlyRuleList *prop_rules ) +{ + ply->rule_list = prop_rules; +} + + +/****************************************************************************** +Append a property rule to a growing list of user-specified rules. + +Entry: +rule_list - current rule list +name - name of property combination rule +property - "element.property" says which property the rule affects + +Exit: +returns pointer to the new rule list +******************************************************************************/ + +PlyRuleList *append_prop_rule( PlyRuleList *rule_list, char *name, char *property ) +{ + PlyRuleList *rule; + PlyRuleList *rule_ptr; + char *str,*str2; + char *ptr; + + /* find . */ + str = strdup ( property ); + for ( ptr = str; *ptr != '\0' && *ptr != '.'; ptr++ ) + ; + + /* split string at . */ + if ( *ptr == '.' ) + { + *ptr = '\0'; + str2 = ptr + 1; + } + else + { + fprintf ( stderr, "Can't find property '%s' for rule '%s'\n", + property, name ); + return ( rule_list ); + } + + rule = ( PlyRuleList * ) malloc ( sizeof ( PlyRuleList ) ); + rule->name = name; + rule->element = str; + rule->property = str2; + rule->next = NULL; + + /* either start rule list or append to it */ + + if ( rule_list == NULL ) + rule_list = rule; + else + { + /* append new rule to current list */ + rule_ptr = rule_list; + while ( rule_ptr->next != NULL ) + rule_ptr = rule_ptr->next; + rule_ptr->next = rule; + } + + /* return pointer to list */ + + return ( rule_list ); +} + + +/****************************************************************************** +See if a name matches the name of any property combination rules. + +Entry: +name - name of rule we're trying to match + +Exit: +returns 1 if we find a match, 0 if not +******************************************************************************/ + +int matches_rule_name( char *name ) +{ + int i; + + for ( i = 0; rule_name_list[i].code != -1; i++ ) + if ( equal_strings ( rule_name_list[i].name, name ) ) + return ( 1 ); + + return ( 0 ); +} + diff --git a/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/ply.h b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/ply.h new file mode 100755 index 00000000000..1925d5e5843 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/ply.h @@ -0,0 +1,233 @@ +/* + +Header for PLY polygon files. + +- Greg Turk + +A PLY file contains a single polygonal _object_. + +An object is composed of lists of _elements_. Typical elements are +vertices, faces, edges and materials. + +Each type of element for a given object has one or more _properties_ +associated with the element type. For instance, a vertex element may +have as properties three floating-point values x,y,z and three unsigned +chars for red, green and blue. + +----------------------------------------------------------------------- + +Copyright (c) 1998 Georgia Institute of Technology. All rights reserved. + +Permission to use, copy, modify and distribute this software and its +documentation for any purpose is hereby granted without fee, provided +that the above copyright notice and this permission notice appear in +all copies of this software and that you do not sell the software. + +THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, +EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY +WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +*/ + +#ifndef __PLY_H__ +#define __PLY_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdio.h> +#include <stddef.h> + +#define PLY_ASCII 1 /* ascii PLY file */ +#define PLY_BINARY_BE 2 /* binary PLY file, big endian */ +#define PLY_BINARY_LE 3 /* binary PLY file, little endian */ + +#define PLY_OKAY 0 /* ply routine worked okay */ +#define PLY_ERROR -1 /* error in ply routine */ + +/* scalar data types supported by PLY format */ + +#define StartType 0 +#define Int8 1 +#define Int16 2 +#define Int32 3 +#define Uint8 4 +#define Uint16 5 +#define Uint32 6 +#define Float32 7 +#define Float64 8 +#define EndType 9 + +#define PLY_SCALAR 0 +#define PLY_LIST 1 +#define PLY_STRING 2 + + +typedef struct PlyProperty { /* description of a property */ + +char *name; /* property name */ +int external_type; /* file's data type */ +int internal_type; /* program's data type */ +int offset; /* offset bytes of prop in a struct */ + +int is_list; /* 0 = scalar, 1 = list, 2 = char string */ +int count_external; /* file's count type */ +int count_internal; /* program's count type */ +int count_offset; /* offset byte for list count */ + +} PlyProperty; + +typedef struct PlyElement { /* description of an element */ +char *name; /* element name */ +int num; /* number of elements in this object */ +int size; /* size of element (bytes) or -1 if variable */ +int nprops; /* number of properties for this element */ +PlyProperty **props; /* list of properties in the file */ +char *store_prop; /* flags: property wanted by user? */ +int other_offset; /* offset to un-asked-for props, or -1 if none*/ +int other_size; /* size of other_props structure */ +} PlyElement; + +typedef struct PlyOtherProp { /* describes other properties in an element */ +char *name; /* element name */ +int size; /* size of other_props */ +int nprops; /* number of properties in other_props */ +PlyProperty **props; /* list of properties in other_props */ +} PlyOtherProp; + +typedef struct OtherData { /* for storing other_props for an other element */ +void *other_props; +} OtherData; + +typedef struct OtherElem { /* data for one "other" element */ +char *elem_name; /* names of other elements */ +int elem_count; /* count of instances of each element */ +OtherData **other_data; /* actual property data for the elements */ +PlyOtherProp *other_props; /* description of the property data */ +} OtherElem; + +typedef struct PlyOtherElems { /* "other" elements, not interpreted by user */ +int num_elems; /* number of other elements */ +OtherElem *other_list; /* list of data for other elements */ +} PlyOtherElems; + +#define AVERAGE_RULE 1 +#define MAJORITY_RULE 2 +#define MINIMUM_RULE 3 +#define MAXIMUM_RULE 4 +#define SAME_RULE 5 +#define RANDOM_RULE 6 + +typedef struct PlyPropRules { /* rules for combining "other" properties */ +PlyElement *elem; /* element whose rules we are making */ +int *rule_list; /* types of rules (AVERAGE_PLY, MAJORITY_PLY, etc.) */ +int nprops; /* number of properties we're combining so far */ +int max_props; /* maximum number of properties we have room for now */ +void **props; /* list of properties we're combining */ +float *weights; /* list of weights of the properties */ +} PlyPropRules; + +typedef struct PlyRuleList { +char *name; /* name of the rule */ +char *element; /* name of element that rule applies to */ +char *property; /* name of property that rule applies to */ +struct PlyRuleList *next; /* pointer for linked list of rules */ +} PlyRuleList; + +typedef struct PlyFile { /* description of PLY file */ +FILE *fp; /* file pointer */ +int file_type; /* ascii or binary */ +float version; /* version number of file */ +int num_elem_types; /* number of element types of object */ +PlyElement **elems; /* list of elements */ +int num_comments; /* number of comments */ +char **comments; /* list of comments */ +int num_obj_info; /* number of items of object information */ +char **obj_info; /* list of object info items */ +PlyElement *which_elem; /* element we're currently reading or writing */ +PlyOtherElems *other_elems; /* "other" elements from a PLY file */ +PlyPropRules *current_rules; /* current propagation rules */ +PlyRuleList *rule_list; /* rule list from user */ +} PlyFile; + +/* memory allocation */ +/* +extern char *my_alloc(); +*/ +#define myalloc(mem_size) my_alloc((mem_size), __LINE__, __FILE__) + + +/* old routines */ + +#if 0 +extern PlyFile *ply_write(FILE *, int, char **, int); +extern PlyFile *ply_read(FILE *, int *, char ***); +extern PlyFile *ply_open_for_reading( char *, int *, char ***, int *, float *); +extern void ply_close(PlyFile *); +extern PlyOtherProp *ply_get_other_properties(PlyFile *, char *, int); +#endif + +extern void ply_describe_property( PlyFile * , char * , PlyProperty * ); +extern void ply_get_property( PlyFile * , char * , PlyProperty * ); +extern void ply_get_element( PlyFile * , void * ); + + +/*** delcaration of routines ***/ + +PlyOtherElems *get_other_element_ply( PlyFile * ); + +PlyFile *read_ply( FILE * ); +PlyFile *write_ply( FILE * , int, char ** , int ); +extern PlyFile *open_for_writing_ply( char * , int, char ** , int ); +void close_ply( PlyFile * ); +void free_ply( PlyFile * ); + +void get_info_ply( PlyFile * , float * , int * ); +void free_other_elements_ply( PlyOtherElems * ); + +void append_comment_ply( PlyFile * , char * ); +void append_obj_info_ply( PlyFile * , char * ); +void copy_comments_ply( PlyFile * , PlyFile * ); +void copy_obj_info_ply( PlyFile * , PlyFile * ); +char* *get_comments_ply( PlyFile * , int * ); +char* *get_obj_info_ply( PlyFile * , int * ); + +char* *get_element_list_ply( PlyFile * , int * ); +int setup_property_ply( PlyFile * , PlyProperty * ); +void get_element_ply( PlyFile * , void * ); +char *setup_element_read_ply( PlyFile * , int, int * ); +PlyOtherProp *get_other_properties_ply( PlyFile * , int ); + +void element_count_ply( PlyFile * , char * , int ); +void describe_element_ply( PlyFile * , char * , int ); +void describe_property_ply( PlyFile * , PlyProperty * ); +void describe_other_properties_ply( PlyFile * , PlyOtherProp * , int ); +void describe_other_elements_ply( PlyFile * , PlyOtherElems * ); +void get_element_setup_ply( PlyFile * , char * , int, PlyProperty * ); +PlyProperty* *get_element_description_ply( PlyFile * , char * , int * , int * ); +void element_layout_ply( PlyFile * , char * , int, int, PlyProperty * ); + +void header_complete_ply( PlyFile * ); +void put_element_setup_ply( PlyFile * , char * ); +void put_element_ply( PlyFile * , void * ); +void put_other_elements_ply( PlyFile * ); + +PlyPropRules *init_rule_ply( PlyFile * , char * ); +void modify_rule_ply( PlyPropRules * , char * , int ); +void start_props_ply( PlyFile * , PlyPropRules * ); +void weight_props_ply( PlyFile * , float, void * ); +void *get_new_props_ply( PlyFile * ); +void set_prop_rules_ply( PlyFile * , PlyRuleList * ); +PlyRuleList *append_prop_rule( PlyRuleList * , char * , char * ); +int matches_rule_name( char * ); + +int equal_strings( char * , char * ); +char *recreate_command_line( int, char *argv[] ); + + +#ifdef __cplusplus +} +#endif +#endif /* !__PLY_H__ */ + diff --git a/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/cvMeshSurfaceSimplify.C b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/cvMeshSurfaceSimplify.C new file mode 100644 index 00000000000..adc46f76237 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/cvMeshSurfaceSimplify.C @@ -0,0 +1,350 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM 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 General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Application + cvMeshSurfaceSimplify + +Description + Simplifies surfaces by resampling. + + Uses Thomas Lewiner's topology preserving MarchingCubes. + +\*---------------------------------------------------------------------------*/ + +#include "argList.H" +#include "Time.H" +#include "searchableSurfaces.H" +#include "conformationSurfaces.H" +#include "triSurfaceMesh.H" + +#include "MarchingCubes.h" + + +using namespace Foam; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +// Main program: + +int main(int argc, char *argv[]) +{ + argList::addNote + ( + "Re-sample surfaces used in cvMesh operation" + ); + //argList::validArgs.append("inputFile"); + argList::validArgs.append("(nx ny nz)"); + argList::validArgs.append("outputName"); + + #include "setRootCase.H" + #include "createTime.H" + runTime.functionObjects().off(); + + const Vector<label> n(IStringStream(args.args()[1])()); + const fileName exportName = args.args()[2]; + + Info<< "Reading surfaces as specified in the cvMeshDict and" + << " writing re-sampled " << n << " to " << exportName + << nl << endl; + + cpuTime timer; + + IOdictionary cvMeshDict + ( + IOobject + ( + "cvMeshDict", + runTime.system(), + runTime, + IOobject::MUST_READ_IF_MODIFIED, + IOobject::NO_WRITE + ) + ); + + // Define/load all geometry + searchableSurfaces allGeometry + ( + IOobject + ( + "cvSearchableSurfaces", + runTime.constant(), + "triSurface", + runTime, + IOobject::MUST_READ, + IOobject::NO_WRITE + ), + cvMeshDict.subDict("geometry") + ); + + Info<< "Geometry read in = " + << timer.cpuTimeIncrement() << " s." << nl << endl; + + + Random rndGen(64293*Pstream::myProcNo()); + + conformationSurfaces geometryToConformTo + ( + runTime, + rndGen, + allGeometry, + cvMeshDict.subDict("surfaceConformation") + ); + + Info<< "Set up geometry in = " + << timer.cpuTimeIncrement() << " s." << nl << endl; + + + + // Extend + treeBoundBox bb = geometryToConformTo.globalBounds(); + { + const vector smallVec = 0.1*bb.span(); + bb.min() -= smallVec; + bb.max() += smallVec; + } + + Info<< "Meshing to bounding box " << bb << nl << endl; + + const vector span(bb.span()); + const vector d + ( + span.x()/(n.x()-1), + span.y()/(n.y()-1), + span.z()/(n.z()-1) + ); + + MarchingCubes mc(span.x(), span.y(), span.z() ) ; + mc.set_resolution(n.x(), n.y(), n.z()); + mc.init_all() ; + + + // Generate points + pointField points(mc.size_x()*mc.size_y()*mc.size_z()); + label pointI = 0; + + point pt; + for( int k = 0 ; k < mc.size_z() ; k++ ) + { + pt.z() = bb.min().z() + k*d.z(); + for( int j = 0 ; j < mc.size_y() ; j++ ) + { + pt.y() = bb.min().y() + j*d.y(); + for( int i = 0 ; i < mc.size_x() ; i++ ) + { + pt.x() = bb.min().x() + i*d.x(); + points[pointI++] = pt; + } + } + } + + Info<< "Generated " << points.size() << " sampling points in = " + << timer.cpuTimeIncrement() << " s." << nl << endl; + + + // Compute data + const searchableSurfaces& geometry = geometryToConformTo.geometry(); + const labelList& surfaces = geometryToConformTo.surfaces(); + + scalarField signedDist; + labelList nearestSurfaces; + searchableSurfacesQueries::signedDistance + ( + geometry, + surfaces, + points, + scalarField(points.size(), sqr(GREAT)), + nearestSurfaces, + signedDist + ); + + // Fill elements + pointI = 0; + for( int k = 0 ; k < mc.size_z() ; k++ ) + { + for( int j = 0 ; j < mc.size_y() ; j++ ) + { + for( int i = 0 ; i < mc.size_x() ; i++ ) + { + mc.set_data(float(signedDist[pointI++]), i, j, k); + } + } + } + + Info<< "Determined signed distance in = " + << timer.cpuTimeIncrement() << " s." << nl << endl; + + + mc.run() ; + + Info<< "Constructed iso surface in = " + << timer.cpuTimeIncrement() << " s." << nl << endl; + + + mc.clean_temps() ; + + + + // Write output file + if (mc.ntrigs() > 0) + { + Triangle* triangles = mc.triangles(); + List<labelledTri> tris(mc.ntrigs()); + forAll(tris, triI) + { + tris[triI] = labelledTri + ( + triangles[triI].v1, + triangles[triI].v2, + triangles[triI].v3, + 0 // region + ); + } + + + Vertex* vertices = mc.vertices(); + pointField points(mc.nverts()); + forAll(points, pointI) + { + Vertex& v = vertices[pointI]; + points[pointI] = point + ( + bb.min().x() + v.x*span.x()/mc.size_x(), + bb.min().y() + v.y*span.y()/mc.size_y(), + bb.min().z() + v.z*span.z()/mc.size_z() + ); + } + + + // Find correspondence to original surfaces + labelList regionOffsets(surfaces.size()); + label nRegions = 0; + forAll(surfaces, i) + { + const wordList& regions = geometry[surfaces[i]].regions(); + regionOffsets[i] = nRegions; + nRegions += regions.size(); + } + + + geometricSurfacePatchList patches(nRegions); + nRegions = 0; + forAll(surfaces, i) + { + const wordList& regions = geometry[surfaces[i]].regions(); + + forAll(regions, regionI) + { + patches[nRegions] = geometricSurfacePatch + ( + "patch", + geometry[surfaces[i]].name() + "_" + regions[regionI], + nRegions + ); + nRegions++; + } + } + + triSurface s(tris, patches, points, true); + + Info<< "Extracted triSurface in = " + << timer.cpuTimeIncrement() << " s." << nl << endl; + + + // Find out region on local surface of nearest point + { + List<pointIndexHit> hitInfo; + labelList hitSurfaces; + geometryToConformTo.findSurfaceNearest + ( + s.faceCentres(), + scalarField(s.size(), sqr(GREAT)), + hitInfo, + hitSurfaces + ); + + // Get region + DynamicList<pointIndexHit> surfInfo(hitSurfaces.size()); + DynamicList<label> surfIndices(hitSurfaces.size()); + + forAll(surfaces, surfI) + { + // Extract info on this surface + surfInfo.clear(); + surfIndices.clear(); + forAll(hitSurfaces, triI) + { + if (hitSurfaces[triI] == surfI) + { + surfInfo.append(hitInfo[triI]); + surfIndices.append(triI); + } + } + + // Calculate sideness of these surface points + labelList region; + geometry[surfaces[surfI]].getRegion(surfInfo, region); + + forAll(region, i) + { + label triI = surfIndices[i]; + s[triI].region() = regionOffsets[surfI]+region[i]; + } + } + } + + Info<< "Re-patched surface in = " + << timer.cpuTimeIncrement() << " s." << nl << endl; + + triSurfaceMesh smesh + ( + IOobject + ( + exportName, + runTime.constant(), // instance + "triSurface", + runTime, // registry + IOobject::NO_READ, + IOobject::AUTO_WRITE, + false + ), + s + ); + + Info<< "writing surfMesh:\n " + << smesh.searchableSurface::objectPath() << nl << endl; + smesh.searchableSurface::write(); + + Info<< "Written surface in = " + << timer.cpuTimeIncrement() << " s." << nl << endl; + } + + mc.clean_all() ; + + + Info<< "End\n" << endl; + + return 0; +} + + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/marching_cubes_jgt.zip b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/marching_cubes_jgt.zip new file mode 100644 index 0000000000000000000000000000000000000000..bb15279b270eb84738e70467383317685d53e425 GIT binary patch literal 170157 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%0DaMCqo@)}?u!*aKJEEdy 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%0Du6XrzayQET^PSFJs_nWNu+= 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	NT@kYqKE(El4Q!p=;-qx$C$u@U4b{&~Nb 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 D4AmLS literal 0 HcmV?d00001 -- GitLab