From e2ebc0d68f63c142ff121320dc7f705233087b27 Mon Sep 17 00:00:00 2001 From: almar Date: Tue, 19 Apr 2016 13:41:01 +0200 Subject: [PATCH 01/25] add marching cubes lewiner algorithm (from visvis) --- skimage/measure/__init__.py | 2 + skimage/measure/_marching_cubes_lewiner.py | 173 ++ .../measure/_marching_cubes_lewiner_cy.pyx | 1416 +++++++++++++++++ .../measure/_marching_cubes_lewiner_luts.py | 529 ++++++ skimage/measure/setup.py | 4 + 5 files changed, 2124 insertions(+) create mode 100644 skimage/measure/_marching_cubes_lewiner.py create mode 100644 skimage/measure/_marching_cubes_lewiner_cy.pyx create mode 100644 skimage/measure/_marching_cubes_lewiner_luts.py diff --git a/skimage/measure/__init__.py b/skimage/measure/__init__.py index 264cf162..c03587d4 100755 --- a/skimage/measure/__init__.py +++ b/skimage/measure/__init__.py @@ -1,6 +1,7 @@ from ._find_contours import find_contours from ._marching_cubes import (marching_cubes, mesh_surface_area, correct_mesh_orientation) +from ._marching_cubes_lewiner import marching_cubes_lewiner from ._regionprops import regionprops, perimeter from .simple_metrics import compare_mse, compare_nrmse, compare_psnr from ._structural_similarity import compare_ssim, structural_similarity @@ -29,6 +30,7 @@ __all__ = ['find_contours', 'moments_normalized', 'moments_hu', 'marching_cubes', + 'marching_cubes_lewiner', 'mesh_surface_area', 'correct_mesh_orientation', 'profile_line', diff --git a/skimage/measure/_marching_cubes_lewiner.py b/skimage/measure/_marching_cubes_lewiner.py new file mode 100644 index 00000000..12cb5100 --- /dev/null +++ b/skimage/measure/_marching_cubes_lewiner.py @@ -0,0 +1,173 @@ +import sys +import base64 + +import numpy as np + +if sys.version_info[0] == 3: + base64decode = base64.decodebytes +else: + base64decode = base64.decodestring + +from . import _marching_cubes_lewiner_luts as mcluts +from . import _marching_cubes_lewiner_cy + + + +def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), + step_size=1, use_classic=False): + """ + Lewiner marching cubes algorithm to find surfaces in 3d volumetric data + + In contrast to ``marching_cubes()``, this algorithm resolves + ambiguities and guarantees topologically correct results. + + Parameters + ---------- + volume : (M, N, P) array (the data is internally converted to + float32 if necessary) + level : float + Contour value to search for isosurfaces in `volume`. If not + given or None, the average of the min and max of vol is used. + spacing : length-3 tuple of floats + Voxel spacing in spatial dimensions corresponding to numpy array + indexing dimensions (M, N, P) as in `volume`. + step_size : int + Step size in voxels. Default 1. Larger steps yield faster but + coarser results. The result will always be topologically correct + though. + use_classic : bool + If given and True, the classic marching cubes by Lorensen (1987) + is used. This option is included for reference purposes. Note + that this algorithm has ambiguities and is not guaranteed to + produce a topologically correct result. + + Returns + ------- + verts : (V, 3) array + Spatial coordinates for V unique mesh vertices. Coordinate order + matches input `volume` (M, N, P). + faces : (F, 3) array + Define triangular faces via referencing vertex indices from ``verts``. + This algorithm specifically outputs triangles, so each face has + exactly three indices. + normals : (V, 3) array + The normal direction at each vertex, as calculated from the + data. + values : (V, ) array + Gives a measure for the maximum value of the data in the local region + near each vertex. This can be used by visualization tools to apply + a colormap to the mesh. + + Notes about the algorithm + ------------------------- + + This is an implementation of: + + Efficient implementation of Marching Cubes' cases with + topological guarantees. Thomas Lewiner, Helio Lopes, Antonio + Wilson Vieira and Geovan Tavares. Journal of Graphics Tools + 8(2): pp. 1-15 (december 2003) + + The algorithm is an improved version of Chernyaev's Marching Cubes 33 + algorithm, originally written in C++. It is an efficient algorithm + that relies on heavy use of lookup tables to handle the many different + cases. This keeps the algorithm relatively easy. The current algorithm + is a port of Lewiner's algorithm and written in Cython. + """ + + # Check volume and ensure its in the format that the alg needs + if not isinstance(volume, np.ndarray) or (volume.ndim != 3): + raise ValueError('Input volume should be a 3D numpy array.') + if volume.shape[0] < 2 or volume.shape[1] < 2 or volume.shape[2] < 2: + raise ValueError("Input array must be at least 2x2x2.") + volume = np.array(volume, dtype=np.float32, order="C", copy=False) + + # Check/convert other inputs: + # level + if level is None: + level = 0.5 * (volume.min() + volume.max()) + else: + level = float(level) + if level < volume.min() or level > volume.max(): + raise ValueError("Surface level must be within volume data range.") + # spacing + if len(spacing) != 3: + raise ValueError("`spacing` must consist of three floats.") + # step_size + step_size = int(step_size) + if step_size < 1: + raise ValueError('step_size must be at least one.') + # use_classic + use_classic = bool(use_classic) + + # Get LutProvider class (reuse if possible) + L = _getMCLuts() + + # Apply algorithm + func = _marching_cubes_lewiner_cy.marching_cubes + vertices, faces , normals, values = func(volume, level, L, step_size, use_classic) + + if not len(vertices): + raise RuntimeError('No surface found at the given iso value.') + + # Output in z-y-x order, as is common in skimage + vertices = np.fliplr(vertices) + normals = np.fliplr(normals) + + # Finishing touches to output + faces.shape = -1, 3 + if spacing != (1, 1, 1): + vertices = vertices * np.r_[spacing] + + return vertices, faces, normals, values + + +def _toArray(args): + shape, text = args + byts = base64decode(text.encode('utf-8')) + ar = np.frombuffer(byts, dtype='int8') + ar.shape = shape + return ar + + +# Map an edge-index to two relative pixel positions. The ege index +# represents a point that lies somewhere in between these pixels. +# Linear interpolation should be used to determine where it is exactly. +# 0 +# 3 1 -> 0x +# 2 xx +EDGETORELATIVEPOSX = np.array([ [0,1],[1,1],[1,0],[0,0], [0,1],[1,1],[1,0],[0,0], [0,0],[1,1],[1,1],[0,0] ], 'int8') +EDGETORELATIVEPOSY = np.array([ [0,0],[0,1],[1,1],[1,0], [0,0],[0,1],[1,1],[1,0], [0,0],[0,0],[1,1],[1,1] ], 'int8') +EDGETORELATIVEPOSZ = np.array([ [0,0],[0,0],[0,0],[0,0], [1,1],[1,1],[1,1],[1,1], [0,1],[0,1],[0,1],[0,1] ], 'int8') + + +def _getMCLuts(): + """ Kind of lazy obtaining of the luts. + """ + if not hasattr(mcluts, 'THE_LUTS'): + + mcluts.THE_LUTS = _marching_cubes_lewiner_cy.LutProvider( + EDGETORELATIVEPOSX, EDGETORELATIVEPOSY, EDGETORELATIVEPOSZ, + + _toArray(mcluts.CASESCLASSIC), _toArray(mcluts.CASES), + + _toArray(mcluts.TILING1), _toArray(mcluts.TILING2), _toArray(mcluts.TILING3_1), _toArray(mcluts.TILING3_2), + _toArray(mcluts.TILING4_1), _toArray(mcluts.TILING4_2), _toArray(mcluts.TILING5), _toArray(mcluts.TILING6_1_1), + _toArray(mcluts.TILING6_1_2), _toArray(mcluts.TILING6_2), _toArray(mcluts.TILING7_1), + _toArray(mcluts.TILING7_2), _toArray(mcluts.TILING7_3), _toArray(mcluts.TILING7_4_1), + _toArray(mcluts.TILING7_4_2), _toArray(mcluts.TILING8), _toArray(mcluts.TILING9), + _toArray(mcluts.TILING10_1_1), _toArray(mcluts.TILING10_1_1_), _toArray(mcluts.TILING10_1_2), + _toArray(mcluts.TILING10_2), _toArray(mcluts.TILING10_2_), _toArray(mcluts.TILING11), + _toArray(mcluts.TILING12_1_1), _toArray(mcluts.TILING12_1_1_), _toArray(mcluts.TILING12_1_2), + _toArray(mcluts.TILING12_2), _toArray(mcluts.TILING12_2_), _toArray(mcluts.TILING13_1), + _toArray(mcluts.TILING13_1_), _toArray(mcluts.TILING13_2), _toArray(mcluts.TILING13_2_), + _toArray(mcluts.TILING13_3), _toArray(mcluts.TILING13_3_), _toArray(mcluts.TILING13_4), + _toArray(mcluts.TILING13_5_1), _toArray(mcluts.TILING13_5_2), _toArray(mcluts.TILING14), + + _toArray(mcluts.TEST3), _toArray(mcluts.TEST4), _toArray(mcluts.TEST6), + _toArray(mcluts.TEST7), _toArray(mcluts.TEST10), _toArray(mcluts.TEST12), + _toArray(mcluts.TEST13), _toArray(mcluts.SUBCONFIG13), + ) + + return mcluts.THE_LUTS + diff --git a/skimage/measure/_marching_cubes_lewiner_cy.pyx b/skimage/measure/_marching_cubes_lewiner_cy.pyx new file mode 100644 index 00000000..04fe49f2 --- /dev/null +++ b/skimage/measure/_marching_cubes_lewiner_cy.pyx @@ -0,0 +1,1416 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2012, Almar Klein +# Copyright (C) 2002, Thomas Lewiner + +""" +This is an implementation of the marching cubes algorithm proposed in: + +Efficient implementation of Marching Cubes' cases with topological guarantees. +Thomas Lewiner, Helio Lopes, Antonio Wilson Vieira and Geovan Tavares. +Journal of Graphics Tools 8(2): pp. 1-15 (december 2003) + +I selected this algorithm because it provides topologically correct results, +and because the algorithms implementation is relatively simple. Most of +the magic is in the lookup tables, which are provided as open source. + +This code is distributed under the terms of the (new) BSD License. + +""" + +# Cython specific imports +import numpy as np +cimport numpy as np +import cython + +# Enable low level memory management +# from libc.stdlib cimport malloc, free +cdef extern from "stdlib.h": # The cimport does not work on my Linux Laptop + void free(void* ptr) + void* malloc(size_t size) + +# Type defs, we support float32 and float64 +ctypedef np.float32_t FLOAT32_T +ctypedef np.float64_t FLOAT64_T +ctypedef np.int32_t INT32_T +FLOAT32 = np.float32 +FLOAT64 = np.float64 +INT32 = np.float32 + + +# Define tiny winy number +cdef double FLT_EPSILON = np.spacing(1.0) #0.0000001 + + +# Define abs function for doubles +cdef inline double dabs(double a): return a if a>=0 else -a + + +# todo: allow dynamic isovalue? +# todo: can we disable Cython from checking for zero division? Sometimes we know that it never happens! + + +cdef class Cell: + """ Class to keep track of some stuff during the whole cube marching + procedure. + + This "struct" keeps track of the current cell location, and the values + of corners of the cube. Gradients for the cube corners are calculated + when needed. + + Additionally, it keeps track of the array of vertices, faces and normals. + + Notes on vertices + ----------------- + The vertices are stored in a C-array that is increased in size with + factors of two if needed. The same applies to the faces and normals. + + Notes on faces + -------------- + To keep track of the vertices already defined, this class maintains + two faceLayer arrays. faceLayer1 is of the current layer (z-value) + and faceLayer2 is of the next. Both face layers have 4 elements per + cell in that layer, 1 for each unique edge per cell (see + get_index_in_facelayer). These are initialized as -1, and set to the + index in the vertex array when a new vertex is created. + In summary, this allows us to keep track of the already created + vertices without keeping a very big array. + + Notes on normals + ---------------- + The normal is simply defined as the gradient. Each time that a face is + created, we also add the gradient of that vertex position to the + normals array. The gradients are all calculated from the differences between + the 8 corners of the current cube, but because the final value of a normal + was contributed from multiple cells, the normals are quite accurate. + + """ + + # Reference to LUTS object + cdef LutProvider luts + + # Location of cube + cdef int x + cdef int y + cdef int z + + # Stepsize + cdef int step + + # Values of cube corners (isovalue subtracted) + cdef double v0 + cdef double v1 + cdef double v2 + cdef double v3 + cdef double v4 + cdef double v5 + cdef double v6 + cdef double v7 + + # Small arrays to store the above values in (allowing indexing) + # and also the gradient at these points + cdef double *vv + cdef double *vg + + # Max value of the eight corners + cdef double vmax + + # Vertex position of center of cube (only calculated if needed) + cdef double v12_x + cdef double v12_y + cdef double v12_z + # And corresponding gradient + cdef double v12_xg + cdef double v12_yg + cdef double v12_zg + cdef int v12_calculated # a boolean + + # The index value, our magic 256 bit word + cdef int index + + # Dimensions of the total volume + cdef int nx + cdef int ny + cdef int nz + + # Arrays with face information + cdef int *faceLayer # The current facelayer (reference-copy of one of the below) + cdef int *faceLayer1 # The actual first face layer + cdef int *faceLayer2 # The actual second face layer + + # Stuff to store the output vertices + cdef float *_vertices + cdef float *_normals + cdef float *_values + cdef int _vertexCount + cdef int _vertexMaxCount + + # Stuff to store the output faces + cdef int *_faces + cdef int _faceCount + cdef int _faceMaxCount + + + def __init__(self, LutProvider luts, int nx, int ny, int nz): + self.luts = luts + self.nx, self.ny, self.nz = nx, ny, nz + + # Allocate face layers + self.faceLayer1 = malloc(self.nx*self.ny*4 * sizeof(int)) + self.faceLayer2 = malloc(self.nx*self.ny*4 * sizeof(int)) + cdef int i + for i in range(self.nx*self.ny*4): + self.faceLayer1[i] = -1 + self.faceLayer2[i] = -1 + self.faceLayer = self.faceLayer1 + + + def __cinit__(self): + + # Init tiny arrays for vertices and gradients at the vertices + self.vv = malloc(8 * sizeof(double)) + self.vg = malloc(8*3 * sizeof(double)) + + # Init face layers + self.faceLayer1 = NULL + self.faceLayer2 = NULL + + # Init vertices + self._vertexCount = 0 + self._vertexMaxCount = 8 + self._vertices = malloc(self._vertexMaxCount*3 * sizeof(float)) + self._normals = malloc(self._vertexMaxCount*3 * sizeof(float)) + self._values = malloc(self._vertexMaxCount * sizeof(float)) + # Clear normals and values + cdef int i, j + for i in range(self._vertexMaxCount): + self._values[i] = 0.0 + for j in range(3): + self._normals[i*3+j] = 0.0 + + # Init faces + self._faceCount = 0 + self._faceMaxCount = 8 + self._faces = malloc(self._faceMaxCount * sizeof(int)) + + + def __dealloc__(self): + if self.vv is not NULL: + free(self.vv) + if self.vg is not NULL: + free(self.vg) + if self.faceLayer1 is not NULL: + free(self.faceLayer1) + if self.faceLayer2 is not NULL: + free(self.faceLayer2) + if self._vertices is not NULL: + free(self._vertices) + if self._normals is not NULL: + free(self._normals) + if self._values is not NULL: + free(self._values) + if self._faces is not NULL: + free(self._faces) + + + cdef void _increase_size_vertices(self): + """ Increase the size of the vertices array by a factor two. + """ + # Allocate new array + cdef int newMaxCount = self._vertexMaxCount * 2 + cdef float *newVertices = malloc(newMaxCount*3 * sizeof(float)) + cdef float *newNormals = malloc(newMaxCount*3 * sizeof(float)) + cdef float *newValues = malloc(newMaxCount * sizeof(float)) + # Clear + cdef int i, j + for i in range(self._vertexCount, newMaxCount): + newValues[i] = 0.0 + for j in range(3): + newNormals[i*3+j] = 0.0 + # Copy + for i in range(self._vertexCount): + newValues[i] = self._values[i] + for j in range(3): + newVertices[i*3+j] = self._vertices[i*3+j] + newNormals[i*3+j] = self._normals[i*3+j] + # Apply + free(self._vertices); self._vertices = newVertices + free(self._normals); self._normals = newNormals + free(self._values); self._values = newValues + self._vertexMaxCount = newMaxCount + + + cdef void _increase_size_faces(self): + """ Increase the size of the faces array by a factor two. + """ + # Allocate new array + cdef int newMaxCount = self._faceMaxCount * 2 + cdef int *newFaces = malloc(newMaxCount * sizeof(int)) + # Copy + cdef int i + for i in range(self._faceCount): + newFaces[i] = self._faces[i] + # Apply + free(self._faces) + self._faces = newFaces + self._faceMaxCount = newMaxCount + + + ## Adding results + + cdef int add_vertex(self, float x, float y, float z): + """ Add a vertex to the result. Return index in vertex array. + """ + # Check if array is large enough + if self._vertexCount >= self._vertexMaxCount: + self._increase_size_vertices() + # Add vertex + self._vertices[self._vertexCount*3+0] = x + self._vertices[self._vertexCount*3+1] = y + self._vertices[self._vertexCount*3+2] = z + self._vertexCount += 1 + return self._vertexCount -1 + + + cdef void add_gradient(self, int vertexIndex, float gx, float gy, float gz): + """ Add a gradient value to the vertex corresponding to the given index. + """ + self._normals[vertexIndex*3+0] += gx + self._normals[vertexIndex*3+1] += gy + self._normals[vertexIndex*3+2] += gz + + + cdef void add_gradient_from_index(self, int vertexIndex, int i, float strength): + """ Add a gradient value to the vertex corresponding to the given index. + vertexIndex is the index in the large array of vertices that is returned. + i is the index of the array of vertices 0-7 for the current cell. + """ + self.add_gradient(vertexIndex, self.vg[i*3+0] * strength, self.vg[i*3+1] * strength, self.vg[i*3+2] * strength) + + + cdef add_face(self, int index): + """ Add a face to the result. Also updates the value. + """ + # Check if array is large enough + if self._faceCount >= self._faceMaxCount: + self._increase_size_faces() + # Add face + self._faces[self._faceCount] = index + self._faceCount += 1 + # Also update value + if self.vmax > self._values[index]: + self._values[index] = self.vmax + + + ## Getting results + + def get_vertices(self): + """ Get the final vertex array. + """ + vertices = np.empty((self._vertexCount,3),'float32') + cdef np.ndarray[FLOAT32_T, ndim=2] vertices_ = vertices + cdef int i, j + for i in range(self._vertexCount): + for j in range(3): + vertices_[i,j] = self._vertices[i*3+j] + return vertices + + def get_normals(self): + """ Get the final normals array. + The normals are normalized to unit length. + """ + normals = np.empty((self._vertexCount,3),'float32') + cdef np.ndarray[FLOAT32_T, ndim=2] normals_ = normals + + cdef int i, j + cdef double length, dtmp + for i in range(self._vertexCount): + length = 0.0 + for j in range(3): + dtmp = self._normals[i*3+j] # Make it double before taking **2! + length += dtmp*dtmp + if length > 0.0: + length = 1.0 / length**0.5 + for j in range(3): + normals_[i,j] = self._normals[i*3+j] * length + return normals + + def get_faces(self): + faces = np.empty((self._faceCount,),'int32') + cdef np.ndarray[INT32_T, ndim=1] faces_ = faces + cdef int i, j + for i in range(self._faceCount): + faces_[i] = self._faces[i] + return faces + + def get_values(self): + values = np.empty((self._vertexCount,),'float32') + cdef np.ndarray[FLOAT32_T, ndim=1] values_ = values + cdef int i, j + for i in range(self._vertexCount): + values_[i] = self._values[i] + return values + + + ## Called from marching cube function + + cdef void new_z_value(self): + """ This method should be called each time a new z layer is entered. + We will swap the layers with face information and empty the second. + """ + # Swap layers + self.faceLayer1, self.faceLayer2 = self.faceLayer2, self.faceLayer1 + # Empty last + cdef int i + for i in range(self.nx*self.ny*4): + self.faceLayer2[i] = -1 + + + cdef void set_cube(self, double isovalue, int x, int y, int z, int step, + double v0, double v1, double v2, double v3, + double v4, double v5, double v6, double v7): + """ Set the cube to the new location. + + Set the values of the cube corners. The isovalue is subtracted + from them, such that in further calculations the isovalue can be + taken as zero. + + This method also calculated the magic 256 word to identify the + cases (i.e. cell.index). + """ + + # Set location and step + self.x = x + self.y = y + self.z = z + self.step = step + + # Set values + self.v0 = v0 - isovalue + self.v1 = v1 - isovalue + self.v2 = v2 - isovalue + self.v3 = v3 - isovalue + self.v4 = v4 - isovalue + self.v5 = v5 - isovalue + self.v6 = v6 - isovalue + self.v7 = v7 - isovalue + + # Calculate index + cdef int index = 0 + if self.v0 > 0.0: index += 1 + if self.v1 > 0.0: index += 2 + if self.v2 > 0.0: index += 4 + if self.v3 > 0.0: index += 8 + if self.v4 > 0.0: index += 16 + if self.v5 > 0.0: index += 32 + if self.v6 > 0.0: index += 64 + if self.v7 > 0.0: index += 128 + self.index = index + + # Reset c12 + self.v12_calculated = 0 + + + cdef void add_triangles(self, Lut lut, int lutIndex, int nt): + """ Add triangles. + + The vertices for the triangles are specified in the given + Lut at the specified index. There are nt triangles. + + The reason that nt should be given is because it is often known + beforehand. + + """ + + cdef int i, j + cdef int vi + + self.prepare_for_adding_triangles() + + for i in range(nt): + for j in range(3): + # Get two sides for each element in this vertex + vi = lut.get2(lutIndex, i*3+j) + self._add_face_from_edge_index(vi) + + + cdef void add_triangles2(self, Lut lut, int lutIndex, int lutIndex2, int nt): + """ Same as add_triangles, except that now the geometry is in a LUT + with 3 dimensions, and an extra index is provided. + + """ + cdef int i, j + cdef int vi + + self.prepare_for_adding_triangles() + + for i in range(nt): + for j in range(3): + # Get two sides for each element in this vertex + vi = lut.get3(lutIndex, lutIndex2, i*3+j) + self._add_face_from_edge_index(vi) + + + ## Used internally + + cdef void _add_face_from_edge_index(self, int vi): + """ Add one face from an edge index. Only adds a face if the + vertex already exists. Otherwise also adds a vertex and applies + interpolation. + """ + + # typedefs + cdef int indexInVertexArray, indexInFaceLayer + cdef int dx1, dy1, dz1 + cdef int dx2, dy2, dz2 + cdef int index1, index2 + cdef double tmpf1, tmpf2 + cdef double fx, fy, fz, ff + cdef double stp = self.step + + # Get index in the face layer and corresponding vertex number + indexInFaceLayer = self.get_index_in_facelayer(vi) + indexInVertexArray = self.faceLayer[indexInFaceLayer] + + # If we have the center vertex, we have things pre-calculated, + # otherwise we need to interpolate. + # In both cases we distinguish between having this vertex already + # or not. + + if vi == 12: # center vertex + if self.v12_calculated == 0: + self.calculate_center_vertex() + if indexInVertexArray >= 0: + # Vertex already calculated, only need to add face and gradient + self.add_face(indexInVertexArray) + self.add_gradient(indexInVertexArray, self.v12_xg, self.v12_yg, self.v12_zg) + else: + # Add precalculated center vertex position (is interpolated) + indexInVertexArray = self.add_vertex( self.v12_x, self.v12_y, self.v12_z) + # Update face layer + self.faceLayer[indexInFaceLayer] = indexInVertexArray + # Add face and gradient + self.add_face(indexInVertexArray) + self.add_gradient(indexInVertexArray, self.v12_xg, self.v12_yg, self.v12_zg) + + else: + + # Get relative edge indices for x, y and z + dx1, dx2 = self.luts.EDGESRELX.get2(vi,0), self.luts.EDGESRELX.get2(vi,1) + dy1, dy2 = self.luts.EDGESRELY.get2(vi,0), self.luts.EDGESRELY.get2(vi,1) + dz1, dz2 = self.luts.EDGESRELZ.get2(vi,0), self.luts.EDGESRELZ.get2(vi,1) + # Make two vertex indices + index1 = dz1*4 + dy1*2 + dx1 + index2 = dz2*4 + dy2*2 + dx2 + # Define strength of both corners + tmpf1 = 1.0 / (FLT_EPSILON + dabs(self.vv[index1])) + tmpf2 = 1.0 / (FLT_EPSILON + dabs(self.vv[index2])) + + if indexInVertexArray >= 0: + # Vertex already calculated, only need to add face and gradient + self.add_face(indexInVertexArray) + self.add_gradient_from_index(indexInVertexArray, index1, tmpf1) + self.add_gradient_from_index(indexInVertexArray, index2, tmpf2) + + else: + # Interpolate by applying a kind of center-of-mass method + fx, fy, fz, ff = 0.0, 0.0, 0.0, 0.0 + fx += dx1 * tmpf1; fy += dy1 * tmpf1; fz += dz1 * tmpf1; ff += tmpf1 + fx += dx2 * tmpf2; fy += dy2 * tmpf2; fz += dz2 * tmpf2; ff += tmpf2 + # Add vertex + indexInVertexArray = self.add_vertex( + self.x + stp*fx/ff, + self.y + stp*fy/ff, + self.z + stp*fz/ff ) + # Update face layer + self.faceLayer[indexInFaceLayer] = indexInVertexArray + # Add face and gradient + self.add_face(indexInVertexArray) + self.add_gradient_from_index(indexInVertexArray, index1, tmpf1) + self.add_gradient_from_index(indexInVertexArray, index2, tmpf2) + + +# # Create vertex non-interpolated +# self.add_vertex( self.x + 0.5* dx1 + 0.5 * dx2, +# self.y + 0.5* dy1 + 0.5 * dy2, +# self.z + 0.5* dz1 + 0.5 * dz2 ) + + + + cdef int get_index_in_facelayer(self, int vi): + """ + Get the index of a vertex position, given the edge on which it lies. + We keep a list of faces so we can reuse vertices. This improves + speed because we need less interpolation, and the result is more + compact and can be visualized better because normals can be + interpolated. + + For each cell, we store 4 vertex indices; all other edges can be + represented as the edge of another cell. The fourth is the center vertex. + + This method returns -1 if no vertex has been defined yet. + + + vertices edes edge-indices per cell + * 7 ________ 6 _____6__ ________ + * /| /| 7/| /| /| /| + * / | / | / | /5 | / | / | + * 4 /_______ / | /__4____ / 10 /_______ / | + * | | |5 | | 11 | | | | | | + * | 3|__|_____|2 | |__|__2__| | |__|_____| + * | / | / 8 3/ 9 / 2 / | / + * | / | / | / | /1 | 1 | / + * |/_______|/ |/___0___|/ |/___0___|/ + * 0 1 0 1 + */ + """ + + # Init indices, both are corrected below + cdef int i = self.nx * self.y + self.x # Index of cube to get vertex at + cdef int j = 0 # Vertex number for that cell + cdef int vi_ = vi + + cdef int *faceLayer + + # Select either upper or lower half + if vi < 8: + # 8 horizontal edges + if vi < 4: + faceLayer = self.faceLayer1 + else: + vi -= 4 + faceLayer = self.faceLayer2 + + # Calculate actual index based on edge + #if vi == 0: pass # no step + if vi == 1: # step in x + i += self.step + j = 1 + elif vi == 2: # step in y + i += self.nx * self.step + elif vi == 3: # no step + j = 1 + + elif vi<12: + # four vertical edges + faceLayer = self.faceLayer1 + j = 2 + + #if vi == 8: pass # no step + if vi == 9: # step in x + i += self.step + elif vi == 10: # step in x and y + i += self.nx * self.step + self.step + elif vi == 11: # step in y + i += self.nx * self.step + + else: + # center vertex + faceLayer = self.faceLayer1 + j = 3 + + # Store facelayer and return index + self.faceLayer = faceLayer # Dirty way of returning a value + return 4*i + j + + + cdef void prepare_for_adding_triangles(self): + """ Calculates some things to help adding the triangles: + array with corner values, max corner value, gradient at each corner. + """ + + cdef int i + + # Copy values in array so we can index them. Note the misalignment + # because the numbering does not correspond with bitwise OR of xyz. + self.vv[0] = self.v0 + self.vv[1] = self.v1 + self.vv[2] = self.v3# + self.vv[3] = self.v2# + self.vv[4] = self.v4 + self.vv[5] = self.v5 + self.vv[6] = self.v7# + self.vv[7] = self.v6# + + # Calculate max + cdef double vmin, vmax + vmin, vmax = 0.0, 0.0 + for i in range(8): + if self.vv[i] > vmax: + vmax = self.vv[i] + if self.vv[i] < vmin: + vmin = self.vv[i] + self.vmax = vmax-vmin + + # Calculate gradients + # Derivatives, selected to always point in same direction. + # Note that many corners have the same components as other points, + # by interpolating and averaging the normals this is solved. + # todo: we can potentially reuse these similar to how we store vertex indices in face layers + self.vg[0*3+0], self.vg[0*3+1], self.vg[0*3+2] = self.v0-self.v1, self.v0-self.v3, self.v0-self.v4 + self.vg[1*3+0], self.vg[1*3+1], self.vg[1*3+2] = self.v0-self.v1, self.v1-self.v2, self.v1-self.v5 + self.vg[2*3+0], self.vg[2*3+1], self.vg[2*3+2] = self.v3-self.v2, self.v1-self.v2, self.v2-self.v6 + self.vg[3*3+0], self.vg[3*3+1], self.vg[3*3+2] = self.v3-self.v2, self.v0-self.v3, self.v3-self.v7 + self.vg[4*3+0], self.vg[4*3+1], self.vg[4*3+2] = self.v4-self.v5, self.v4-self.v7, self.v0-self.v4 + self.vg[5*3+0], self.vg[5*3+1], self.vg[5*3+2] = self.v4-self.v5, self.v5-self.v6, self.v1-self.v5 + self.vg[6*3+0], self.vg[6*3+1], self.vg[6*3+2] = self.v7-self.v6, self.v5-self.v6, self.v2-self.v6 + self.vg[7*3+0], self.vg[7*3+1], self.vg[7*3+2] = self.v7-self.v6, self.v4-self.v7, self.v3-self.v7 + + + cdef void calculate_center_vertex(self): + """ Calculate interpolated center vertex and its gradient. + """ + cdef double v0, v1, v2, v3, v4, v5, v6, v7 + cdef double fx, fy, fz, ff + fx, fy, fz, ff = 0.0, 0.0, 0.0, 0.0 + + # Define "strength" of each corner of the cube that we need + v0 = 1.0 / (FLT_EPSILON + dabs(self.v0)) + v1 = 1.0 / (FLT_EPSILON + dabs(self.v1)) + v2 = 1.0 / (FLT_EPSILON + dabs(self.v2)) + v3 = 1.0 / (FLT_EPSILON + dabs(self.v3)) + v4 = 1.0 / (FLT_EPSILON + dabs(self.v4)) + v5 = 1.0 / (FLT_EPSILON + dabs(self.v5)) + v6 = 1.0 / (FLT_EPSILON + dabs(self.v6)) + v7 = 1.0 / (FLT_EPSILON + dabs(self.v7)) + + # Apply a kind of center-of-mass method + fx += 0.0*v0; fy += 0.0*v0; fz += 0.0*v0; ff += v0 + fx += 1.0*v1; fy += 0.0*v1; fz += 0.0*v1; ff += v1 + fx += 1.0*v2; fy += 1.0*v2; fz += 0.0*v2; ff += v2 + fx += 0.0*v3; fy += 1.0*v3; fz += 0.0*v3; ff += v3 + fx += 0.0*v4; fy += 0.0*v4; fz += 1.0*v4; ff += v4 + fx += 1.0*v5; fy += 0.0*v5; fz += 1.0*v5; ff += v5 + fx += 1.0*v6; fy += 1.0*v6; fz += 1.0*v6; ff += v6 + fx += 0.0*v7; fy += 1.0*v7; fz += 1.0*v7; ff += v7 + + # Store + cdef double stp = self.step + self.v12_x = self.x + stp * fx / ff + self.v12_y = self.y + stp * fy / ff + self.v12_z = self.z + stp * fz / ff + + # Also pre-calculate gradient of center + # note that prepare_for_adding_triangles() must have been called for + # the gradient data to exist. + self.v12_xg = ( v0*self.vg[0*3+0] + v1*self.vg[1*3+0] + v2*self.vg[2*3+0] + v3*self.vg[3*3+0] + + v4*self.vg[4*3+0] + v5*self.vg[5*3+0] + v6*self.vg[6*3+0] + v7*self.vg[7*3+0] ) + self.v12_yg = ( v0*self.vg[0*3+1] + v1*self.vg[1*3+1] + v2*self.vg[2*3+1] + v3*self.vg[3*3+1] + + v4*self.vg[4*3+1] + v5*self.vg[5*3+1] + v6*self.vg[6*3+1] + v7*self.vg[7*3+1] ) + self.v12_xg = ( v0*self.vg[0*3+2] + v1*self.vg[1*3+2] + v2*self.vg[2*3+2] + v3*self.vg[3*3+2] + + v4*self.vg[4*3+2] + v5*self.vg[5*3+2] + v6*self.vg[6*3+2] + v7*self.vg[7*3+2] ) + + # Set flag that this stuff is calculated + self.v12_calculated = 1 + + + +cdef class Lut: + """ Representation of a lookup table. + The tables are initially defined as numpy arrays. On initialization, + this class converts them to a C array for fast access. + This class defines functions to look up values using 1, 2 or 3 indices. + """ + + cdef char* VALUES + cdef int L0 # Length + cdef int L1 # size of tuple + cdef int L2 # size of tuple in tuple (if any) + + def __init__(self, array): + + # Get the shape of the LUT + self.L1 = 1 + self.L2 = 1 + # + self.L0 = array.shape[0] + if array.ndim > 1: + self.L1 = array.shape[1] + if array.ndim > 2: + self.L2 = array.shape[2] + + # Copy the contents + array = array.ravel() + cdef int n, N + N = self.L0 * self.L1 * self.L2 + self.VALUES = malloc(N * sizeof(char)) + for n in range(N): + self.VALUES[n] = array[n] + + def __cinit__(self): + self.VALUES = NULL + + def __dealloc__(self): + if self.VALUES is not NULL: + free(self.VALUES) + + cdef int get1(self, int i0): + return self.VALUES[i0] + + cdef int get2(self, int i0, int i1): + return self.VALUES[i0*self.L1 + i1] + + cdef int get3(self, int i0, int i1, int i2): + return self.VALUES[i0*self.L1*self.L2 + i1*self.L2 + i2] + + + +cdef class LutProvider: + """ Class that provides a common interface to the many lookup tables + used by the algorithm. + All the lists of lut names are autogenerated to prevent human error. + """ + + cdef Lut EDGESRELX # Edges relative X + cdef Lut EDGESRELY + cdef Lut EDGESRELZ + + cdef Lut CASESCLASSIC + cdef Lut CASES + + cdef Lut TILING1 + cdef Lut TILING2 + cdef Lut TILING3_1 + cdef Lut TILING3_2 + cdef Lut TILING4_1 + cdef Lut TILING4_2 + cdef Lut TILING5 + cdef Lut TILING6_1_1 + cdef Lut TILING6_1_2 + cdef Lut TILING6_2 + cdef Lut TILING7_1 + cdef Lut TILING7_2 + cdef Lut TILING7_3 + cdef Lut TILING7_4_1 + cdef Lut TILING7_4_2 + cdef Lut TILING8 + cdef Lut TILING9 + cdef Lut TILING10_1_1 + cdef Lut TILING10_1_1_ + cdef Lut TILING10_1_2 + cdef Lut TILING10_2 + cdef Lut TILING10_2_ + cdef Lut TILING11 + cdef Lut TILING12_1_1 + cdef Lut TILING12_1_1_ + cdef Lut TILING12_1_2 + cdef Lut TILING12_2 + cdef Lut TILING12_2_ + cdef Lut TILING13_1 + cdef Lut TILING13_1_ + cdef Lut TILING13_2 + cdef Lut TILING13_2_ + cdef Lut TILING13_3 + cdef Lut TILING13_3_ + cdef Lut TILING13_4 + cdef Lut TILING13_5_1 + cdef Lut TILING13_5_2 + cdef Lut TILING14 + + cdef Lut TEST3 + cdef Lut TEST4 + cdef Lut TEST6 + cdef Lut TEST7 + cdef Lut TEST10 + cdef Lut TEST12 + cdef Lut TEST13 + + cdef Lut SUBCONFIG13 + + + def __init__(self, EDGESRELX, EDGESRELY, EDGESRELZ, CASESCLASSIC, CASES, + + TILING1, TILING2, TILING3_1, TILING3_2, TILING4_1, TILING4_2, + TILING5, TILING6_1_1, TILING6_1_2, TILING6_2, TILING7_1, TILING7_2, + TILING7_3, TILING7_4_1, TILING7_4_2, TILING8, TILING9, + TILING10_1_1, TILING10_1_1_, TILING10_1_2, TILING10_2, TILING10_2_, + TILING11, TILING12_1_1, TILING12_1_1_, TILING12_1_2, TILING12_2, + TILING12_2_, TILING13_1, TILING13_1_, TILING13_2, TILING13_2_, + TILING13_3, TILING13_3_, TILING13_4, TILING13_5_1, TILING13_5_2, + TILING14, + + TEST3, TEST4, TEST6, TEST7, TEST10, TEST12, TEST13, + SUBCONFIG13, + ): + + self.EDGESRELX = Lut(EDGESRELX) + self.EDGESRELY = Lut(EDGESRELY) + self.EDGESRELZ = Lut(EDGESRELZ) + + self.CASESCLASSIC = Lut(CASESCLASSIC) + self.CASES = Lut(CASES) + + self.TILING1 = Lut(TILING1) + self.TILING2 = Lut(TILING2) + self.TILING3_1 = Lut(TILING3_1) + self.TILING3_2 = Lut(TILING3_2) + self.TILING4_1 = Lut(TILING4_1) + self.TILING4_2 = Lut(TILING4_2) + self.TILING5 = Lut(TILING5) + self.TILING6_1_1 = Lut(TILING6_1_1) + self.TILING6_1_2 = Lut(TILING6_1_2) + self.TILING6_2 = Lut(TILING6_2) + self.TILING7_1 = Lut(TILING7_1) + self.TILING7_2 = Lut(TILING7_2) + self.TILING7_3 = Lut(TILING7_3) + self.TILING7_4_1 = Lut(TILING7_4_1) + self.TILING7_4_2 = Lut(TILING7_4_2) + self.TILING8 = Lut(TILING8) + self.TILING9 = Lut(TILING9) + self.TILING10_1_1 = Lut(TILING10_1_1) + self.TILING10_1_1_ = Lut(TILING10_1_1_) + self.TILING10_1_2 = Lut(TILING10_1_2) + self.TILING10_2 = Lut(TILING10_2) + self.TILING10_2_ = Lut(TILING10_2_) + self.TILING11 = Lut(TILING11) + self.TILING12_1_1 = Lut(TILING12_1_1) + self.TILING12_1_1_ = Lut(TILING12_1_1_) + self.TILING12_1_2 = Lut(TILING12_1_2) + self.TILING12_2 = Lut(TILING12_2) + self.TILING12_2_ = Lut(TILING12_2_) + self.TILING13_1 = Lut(TILING13_1) + self.TILING13_1_ = Lut(TILING13_1_) + self.TILING13_2 = Lut(TILING13_2) + self.TILING13_2_ = Lut(TILING13_2_) + self.TILING13_3 = Lut(TILING13_3) + self.TILING13_3_ = Lut(TILING13_3_) + self.TILING13_4 = Lut(TILING13_4) + self.TILING13_5_1 = Lut(TILING13_5_1) + self.TILING13_5_2 = Lut(TILING13_5_2) + self.TILING14 = Lut(TILING14) + + self.TEST3 = Lut(TEST3) + self.TEST4 = Lut(TEST4) + self.TEST6 = Lut(TEST6) + self.TEST7 = Lut(TEST7) + self.TEST10 = Lut(TEST10) + self.TEST12 = Lut(TEST12) + self.TEST13 = Lut(TEST13) + + self.SUBCONFIG13 = Lut(SUBCONFIG13) + + + +@cython.boundscheck(False) +@cython.wraparound(False) +def marching_cubes(im, double isovalue, LutProvider luts, int st=1, int classic=0): + """ marching_cubes(im, double isovalue, LutProvider luts, int st=1, int classic=0) + This is the main entry to apply marching cubes. + Returns (vertices, faces, normals, values) + """ + + # Typdedef image + cdef np.ndarray[FLOAT32_T, ndim=3] im_ = im + + # Get dimemsnions + cdef int Nx, Ny, Nz + Nx, Ny, Nz = im.shape[2], im.shape[1], im.shape[0] + + # Create cell to use throughout + cdef Cell cell = Cell(luts, Nx, Ny, Nz) + + # Typedef variables + cdef int x, y, z + cdef int nt + cdef int case, config, subconfig + + # Unfortunately, using a step in the for loops degregades performance. + # Quick and dirty trick below ... + + if st == 1: + + for z in range(0,Nz-1): + cell.new_z_value() # Indicate that we enter a new layer + for y in range(0,Ny-1): + for x in range(0,Nx-1): + + # Initialize cell + cell.set_cube(isovalue, x, y, z, st, + im_[z ,y, x], im_[z ,y, x+st], im_[z ,y+st, x+st], im_[z ,y+st, x], + im_[z+st,y, x], im_[z+st,y, x+st], im_[z+st,y+st, x+st], im_[z+st,y+st, x] ) + + # Do classic! + if classic: + # Determine number of vertices + nt = 0 + while luts.CASESCLASSIC.get2(cell.index, 3*nt) != -1: + nt += 1 + # Add triangles + if nt > 0: + cell.add_triangles(luts.CASESCLASSIC, cell.index, nt) + else: + # Get case, if non-nul, enter the big switch + case = luts.CASES.get2(cell.index, 0) + if case > 0: + config = luts.CASES.get2(cell.index, 1) + the_big_switch(luts, cell, case, config) + + else: + + for z in range(0,Nz-st,st): + cell.new_z_value() # Indicate that we enter a new layer + for y in range(0,Ny-st,st): + for x in range(0,Nx-st,st): + + # Initialize cell + cell.set_cube(isovalue, x, y, z, st, + im_[z ,y, x], im_[z ,y, x+st], im_[z ,y+st, x+st], im_[z ,y+st, x], + im_[z+st,y, x], im_[z+st,y, x+st], im_[z+st,y+st, x+st], im_[z+st,y+st, x] ) + + # Do classic! + if classic: + # Determine number of vertices + nt = 0 + while luts.CASESCLASSIC.get2(cell.index, 3*nt) != -1: + nt += 1 + # Add triangles + if nt > 0: + cell.add_triangles(luts.CASESCLASSIC, cell.index, nt) + else: + # Get case, if non-nul, enter the big switch + case = luts.CASES.get2(cell.index, 0) + if case > 0: + config = luts.CASES.get2(cell.index, 1) + the_big_switch(luts, cell, case, config) + + + # Done + return cell.get_vertices(), cell.get_faces(), cell.get_normals(), cell.get_values() + + + +cdef void the_big_switch(LutProvider luts, Cell cell, int case, int config): + """ The big switch (i.e. if-statement) that I meticulously ported from + the source code provided by Lewiner et. al. + + Together with all the look-up tables, this is where the magic is ... + """ + + cdef int subconfig = 0 + + # Sinatures for tests + #test_face(cell, luts.TESTX.get1(config)): + #test_internal(cell, luts, case, config, subconfig, luts.TESTX.get1(config)): + #cell.add_triangles(luts.TILINGX, config, N) + + if case == 1: + cell.add_triangles(luts.TILING1, config, 1) + + elif case == 2: + cell.add_triangles(luts.TILING2, config, 2) + + elif case == 3: + if test_face(cell, luts.TEST3.get1(config)): + cell.add_triangles(luts.TILING3_2, config, 4) + else: + cell.add_triangles(luts.TILING3_1, config, 2) + + elif case == 4 : + if test_internal(cell, luts, case, config, subconfig, luts.TEST4.get1(config)): + cell.add_triangles(luts.TILING4_1, config, 2) + else: + cell.add_triangles(luts.TILING4_2, config, 6) + + elif case == 5 : + cell.add_triangles(luts.TILING5, config, 3) + + elif case == 6 : + if test_face(cell, luts.TEST6.get2(config,0)): + cell.add_triangles(luts.TILING6_2, config, 5) + else: + if test_internal(cell, luts, case, config, subconfig, luts.TEST6.get2(config,1)): + cell.add_triangles(luts.TILING6_1_1, config, 3) + else: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles(luts.TILING6_1_2, config, 9) + + elif case == 7 : + # Get subconfig + if test_face(cell, luts.TEST7.get2(config,0)): subconfig += 1 + if test_face(cell, luts.TEST7.get2(config,1)): subconfig += 2 + if test_face(cell, luts.TEST7.get2(config,2)): subconfig += 4 + # Behavior depends on subconfig + if subconfig == 0: cell.add_triangles(luts.TILING7_1, config, 3) + elif subconfig == 1: cell.add_triangles2(luts.TILING7_2, config, 0, 5) + elif subconfig == 2: cell.add_triangles2(luts.TILING7_2, config, 1, 5) + elif subconfig == 3: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING7_3, config, 0, 9) + elif subconfig == 4: cell.add_triangles2(luts.TILING7_2, config, 2, 5) + elif subconfig == 5: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING7_3, config, 1, 9) + elif subconfig == 6: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING7_3, config, 2, 9) + elif subconfig == 7: + if test_internal(cell, luts, case, config, subconfig, luts.TEST7.get2(config,3)): + cell.add_triangles(luts.TILING7_4_2, config, 9) + else: + cell.add_triangles(luts.TILING7_4_1, config, 5) + + elif case == 8 : + cell.add_triangles(luts.TILING8, config, 2) + + elif case == 9 : + cell.add_triangles(luts.TILING9, config, 4) + + elif case == 10 : + if test_face(cell, luts.TEST10.get2(config,0)): + if test_face(cell, luts.TEST10.get2(config,1)): + cell.add_triangles(luts.TILING10_1_1_, config, 4) + else: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles(luts.TILING10_2, config, 8) + else: + if test_face(cell, luts.TEST10.get2(config,1)): + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles(luts.TILING10_2_, config, 8) + else: + if test_internal(cell, luts, case, config, subconfig, luts.TEST10.get2(config,2)): + cell.add_triangles(luts.TILING10_1_1, config, 4) + else: + cell.add_triangles(luts.TILING10_1_2, config, 8) + + elif case == 11 : + cell.add_triangles(luts.TILING11, config, 4) + + elif case == 12 : + if test_face(cell, luts.TEST12.get2(config,0)): + if test_face(cell, luts.TEST12.get2(config,1)): + cell.add_triangles(luts.TILING12_1_1_, config, 4) + else: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles(luts.TILING12_2, config, 8) + else: + if test_face(cell, luts.TEST12.get2(config,1)): + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles(luts.TILING12_2_, config, 8) + else: + if test_internal(cell, luts, case, config, subconfig, luts.TEST12.get2(config,2)): + cell.add_triangles(luts.TILING12_1_1, config, 4) + else: + cell.add_triangles(luts.TILING12_1_2, config, 8) + + elif case == 13 : + # Calculate subconfig + if test_face(cell, luts.TEST13.get2(config,0)): subconfig += 1 + if test_face(cell, luts.TEST13.get2(config,1)): subconfig += 2 + if test_face(cell, luts.TEST13.get2(config,2)): subconfig += 4 + if test_face(cell, luts.TEST13.get2(config,3)): subconfig += 8 + if test_face(cell, luts.TEST13.get2(config,4)): subconfig += 16 + if test_face(cell, luts.TEST13.get2(config,5)): subconfig += 32 + + # Map via LUT + subconfig = luts.SUBCONFIG13.get1(subconfig) + + # Behavior depends on subconfig + if subconfig==0: cell.add_triangles(luts.TILING13_1, config, 4) + elif subconfig==1: cell.add_triangles2(luts.TILING13_2, config, 0, 6) + elif subconfig==2: cell.add_triangles2(luts.TILING13_2, config, 1, 6) + elif subconfig==3: cell.add_triangles2(luts.TILING13_2, config, 2, 6) + elif subconfig==4: cell.add_triangles2(luts.TILING13_2, config, 3, 6) + elif subconfig==5: cell.add_triangles2(luts.TILING13_2, config, 4, 6) + elif subconfig==6: cell.add_triangles2(luts.TILING13_2, config, 5, 6) + # + elif subconfig==7: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_3, config, 0, 10) + elif subconfig==8: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_3, config, 1, 10) + elif subconfig==9: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_3, config, 2, 10) + elif subconfig==10: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_3, config, 3, 10) + elif subconfig==11: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_3, config, 4, 10) + elif subconfig==12: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_3, config, 5, 10) + elif subconfig==13: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_3, config, 6, 10) + elif subconfig==14: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_3, config, 7, 10) + elif subconfig==15: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_3, config, 8, 10) + elif subconfig==16: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_3, config, 9, 10) + elif subconfig==17: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_3, config, 10, 10) + elif subconfig==18: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_3, config, 11, 10) + # + elif subconfig==19: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_4, config, 0, 12) + elif subconfig==20: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_4, config, 1, 12) + elif subconfig==21: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_4, config, 2, 12) + elif subconfig==22: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_4, config, 3, 12) + # + elif subconfig==23: + subconfig = 0 # Note: the original source code sets the subconfig, without apparent reason + if test_internal(cell, luts, case, config, subconfig, luts.TEST13.get2(config,6)): + cell.add_triangles2(luts.TILING13_5_1, config, 0, 6) + else: + cell.add_triangles2(luts.TILING13_5_2, config, 0, 10) + elif subconfig==24: + subconfig = 1 + if test_internal(cell, luts, case, config, subconfig, luts.TEST13.get2(config,6)): + cell.add_triangles2(luts.TILING13_5_1, config, 1, 6) + else: + cell.add_triangles2(luts.TILING13_5_2, config, 1, 10) + elif subconfig==25: + subconfig = 2 ; + if test_internal(cell, luts, case, config, subconfig, luts.TEST13.get2(config,6)): + cell.add_triangles2(luts.TILING13_5_1, config, 2, 6) + else: + cell.add_triangles2(luts.TILING13_5_2, config, 2, 10) + elif subconfig==26: + subconfig = 3 ; + if test_internal(cell, luts, case, config, subconfig, luts.TEST13.get2(config,6)): + cell.add_triangles2(luts.TILING13_5_1, config, 3, 6) + else: + cell.add_triangles2(luts.TILING13_5_2, config, 3, 10) + # + elif subconfig==27: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_3_, config, 0, 10) + elif subconfig==28: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_3_, config, 1, 10) + elif subconfig==29: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_3_, config, 2, 10) + elif subconfig==30: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_3_, config, 3, 10) + elif subconfig==31: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_3_, config, 4, 10) + elif subconfig==32: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_3_, config, 5, 10) + elif subconfig==33: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_3_, config,6, 10) + elif subconfig==34: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_3_, config, 7, 10) + elif subconfig==35: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_3_, config, 8, 10) + elif subconfig==36: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_3_, config, 9, 10) + elif subconfig==37: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_3_, config, 10, 10) + elif subconfig==38: + #cell.calculate_center_vertex() # v12 needed + cell.add_triangles2(luts.TILING13_3_, config, 11, 10) + # + elif subconfig==39: + cell.add_triangles2(luts.TILING13_2_, config, 0, 6) + elif subconfig==40: + cell.add_triangles2(luts.TILING13_2_, config, 1, 6) + elif subconfig==41: + cell.add_triangles2(luts.TILING13_2_, config, 2, 6) + elif subconfig==42: + cell.add_triangles2(luts.TILING13_2_, config, 3, 6) + elif subconfig==43: + cell.add_triangles2(luts.TILING13_2_, config, 4, 6) + elif subconfig==44: + cell.add_triangles2(luts.TILING13_2_, config, 5, 6) + # + elif subconfig==45: + cell.add_triangles(luts.TILING13_1_, config, 4) + # + else: + print("Marching Cubes: Impossible case 13?" ) + + elif case == 14 : + cell.add_triangles(luts.TILING14, config, 4) + + +cdef int test_face(Cell cell, int face): + """ Return True of the face contains part of the surface. + """ + + # Get face absolute value + cdef int absFace = face + if face < 0: + absFace *= -1 + + # Get values of corners A B C D + cdef double A, B, C, D + if absFace == 1: + A, B, C, D = cell.v0, cell.v4, cell.v5, cell.v1 + elif absFace == 2: + A, B, C, D = cell.v1, cell.v5, cell.v6, cell.v2 + elif absFace == 3: + A, B, C, D = cell.v2, cell.v6, cell.v7, cell.v3 + elif absFace == 4: + A, B, C, D = cell.v3, cell.v7, cell.v4, cell.v0 + elif absFace == 5: + A, B, C, D = cell.v0, cell.v3, cell.v2, cell.v1 + elif absFace == 6: + A, B, C, D = cell.v4, cell.v7, cell.v6, cell.v5 + + # Return sign + cdef double AC_BD = A*C - B*D + if AC_BD > - FLT_EPSILON and AC_BD < FLT_EPSILON: + return face >= 0 + else: + return face * A * AC_BD >= 0; # face and A invert signs + + +cdef int test_internal(Cell cell, LutProvider luts, int case, int config, int subconfig, int s): + """ Return True of the face contains part of the surface. + """ + + # Typedefs + cdef double t, At, Bt, Ct, Dt, a, b + cdef int test = 0 + cdef int edge = -1 # reference edge of the triangulation + + + # Calculate At Bt Ct Dt a b + # Select case 4, 10, 7, 12, 13 + At, Bt, Ct, Dt = 0.0, 0.0, 0.0, 0.0 + + if case==4 or case==10: + a = ( cell.v4 - cell.v0 ) * ( cell.v6 - cell.v2 ) - ( cell.v7 - cell.v3 ) * ( cell.v5 - cell.v1 ) + b = cell.v2 * ( cell.v4 - cell.v0 ) + cell.v0 * ( cell.v6 - cell.v2 ) - cell.v1 * ( cell.v7 - cell.v3 ) - cell.v3 * ( cell.v5 - cell.v1 ) + t = - b / (2*a + FLT_EPSILON) + if t<0 or t>1: return s>0 ; + + At = cell.v0 + ( cell.v4 - cell.v0 ) * t + Bt = cell.v3 + ( cell.v7 - cell.v3 ) * t + Ct = cell.v2 + ( cell.v6 - cell.v2 ) * t + Dt = cell.v1 + ( cell.v5 - cell.v1 ) * t + + elif case==6 or case==7 or case==12 or case==13: + # Define edge + if case == 6: edge = luts.TEST6.get2(config, 2) + elif case == 7: edge = luts.TEST7.get2(config, 4) + elif case == 12: edge = luts.TEST12.get2(config, 3) + elif case == 13: edge = luts.TILING13_5_1.get3(config, subconfig, 0) + + if edge==0: + t = cell.v0 / ( cell.v0 - cell.v1 + FLT_EPSILON ) + At = 0 + Bt = cell.v3 + ( cell.v2 - cell.v3 ) * t + Ct = cell.v7 + ( cell.v6 - cell.v7 ) * t + Dt = cell.v4 + ( cell.v5 - cell.v4 ) * t + elif edge==1: + t = cell.v1 / ( cell.v1 - cell.v2 + FLT_EPSILON ) + At = 0 + Bt = cell.v0 + ( cell.v3 - cell.v0 ) * t + Ct = cell.v4 + ( cell.v7 - cell.v4 ) * t + Dt = cell.v5 + ( cell.v6 - cell.v5 ) * t + elif edge==2: + t = cell.v2 / ( cell.v2 - cell.v3 + FLT_EPSILON ) + At = 0 + Bt = cell.v1 + ( cell.v0 - cell.v1 ) * t + Ct = cell.v5 + ( cell.v4 - cell.v5 ) * t + Dt = cell.v6 + ( cell.v7 - cell.v6 ) * t + elif edge==3: + t = cell.v3 / ( cell.v3 - cell.v0 + FLT_EPSILON ) + At = 0 + Bt = cell.v2 + ( cell.v1 - cell.v2 ) * t + Ct = cell.v6 + ( cell.v5 - cell.v6 ) * t + Dt = cell.v7 + ( cell.v4 - cell.v7 ) * t + elif edge==4: + t = cell.v4 / ( cell.v4 - cell.v5 + FLT_EPSILON ) + At = 0 + Bt = cell.v7 + ( cell.v6 - cell.v7 ) * t + Ct = cell.v3 + ( cell.v2 - cell.v3 ) * t + Dt = cell.v0 + ( cell.v1 - cell.v0 ) * t + elif edge==5: + t = cell.v5 / ( cell.v5 - cell.v6 + FLT_EPSILON ) + At = 0 + Bt = cell.v4 + ( cell.v7 - cell.v4 ) * t + Ct = cell.v0 + ( cell.v3 - cell.v0 ) * t + Dt = cell.v1 + ( cell.v2 - cell.v1 ) * t + elif edge==6: + t = cell.v6 / ( cell.v6 - cell.v7 + FLT_EPSILON ) + At = 0 + Bt = cell.v5 + ( cell.v4 - cell.v5 ) * t + Ct = cell.v1 + ( cell.v0 - cell.v1 ) * t + Dt = cell.v2 + ( cell.v3 - cell.v2 ) * t + elif edge==7: + t = cell.v7 / ( cell.v7 - cell.v4 + FLT_EPSILON ) + At = 0 + Bt = cell.v6 + ( cell.v5 - cell.v6 ) * t + Ct = cell.v2 + ( cell.v1 - cell.v2 ) * t + Dt = cell.v3 + ( cell.v0 - cell.v3 ) * t + elif edge==8: + t = cell.v0 / ( cell.v0 - cell.v4 + FLT_EPSILON ) + At = 0 + Bt = cell.v3 + ( cell.v7 - cell.v3 ) * t + Ct = cell.v2 + ( cell.v6 - cell.v2 ) * t + Dt = cell.v1 + ( cell.v5 - cell.v1 ) * t + elif edge==9: + t = cell.v1 / ( cell.v1 - cell.v5 + FLT_EPSILON ) + At = 0 + Bt = cell.v0 + ( cell.v4 - cell.v0 ) * t + Ct = cell.v3 + ( cell.v7 - cell.v3 ) * t + Dt = cell.v2 + ( cell.v6 - cell.v2 ) * t + elif edge==10: + t = cell.v2 / ( cell.v2 - cell.v6 + FLT_EPSILON ) + At = 0 + Bt = cell.v1 + ( cell.v5 - cell.v1 ) * t + Ct = cell.v0 + ( cell.v4 - cell.v0 ) * t + Dt = cell.v3 + ( cell.v7 - cell.v3 ) * t + elif edge==11: + t = cell.v3 / ( cell.v3 - cell.v7 + FLT_EPSILON ) + At = 0 + Bt = cell.v2 + ( cell.v6 - cell.v2 ) * t + Ct = cell.v1 + ( cell.v5 - cell.v1 ) * t + Dt = cell.v0 + ( cell.v4 - cell.v0 ) * t + else: + print( "Invalid edge %i." % edge ) + else: + print( "Invalid ambiguous case %i." % case ) + + # Process results + if At >= 0: test += 1 + if Bt >= 0: test += 2 + if Ct >= 0: test += 4 + if Dt >= 0: test += 8 + + # Determine what to return + if test==0: return s>0 + elif test==1: return s>0 + elif test==2: return s>0 + elif test==3: return s>0 + elif test==4: return s>0 + elif test==5: + if At * Ct - Bt * Dt < FLT_EPSILON: return s>0 + elif test==6: return s>0 + elif test==7: return s<0 + elif test==8: return s>0 + elif test==9: return s>0 + elif test==10: + if At * Ct - Bt * Dt >= FLT_EPSILON: return s>0 + elif test==11: return s<0 + elif test==12: return s>0 + elif test==13: return s<0 + elif test==14: return s<0 + elif test==15: return s<0 + else: return s<0 diff --git a/skimage/measure/_marching_cubes_lewiner_luts.py b/skimage/measure/_marching_cubes_lewiner_luts.py new file mode 100644 index 00000000..59243662 --- /dev/null +++ b/skimage/measure/_marching_cubes_lewiner_luts.py @@ -0,0 +1,529 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2012, Almar Klein +# Copyright (C) 2002, Thomas Lewiner + +# This file was auto-generated from LookUpTable.h by createluts.py. + +#static const char casesClassic[256][16] +CASESCLASSIC = (256, 16), """ +/////////////////////wAIA/////////////////8AAQn/////////////////AQgDCQgB//// +/////////wECCv////////////////8ACAMBAgr/////////////CQIKAAIJ/////////////wII +AwIKCAoJCP////////8DCwL/////////////////AAsCCAsA/////////////wEJAAIDC/////// +//////8BCwIBCQsJCAv/////////AwoBCwoD/////////////wAKAQAICggLCv////////8DCQAD +CwkLCgn/////////CQgKCggL/////////////wQHCP////////////////8EAwAHAwT///////// +////AAEJCAQH/////////////wQBCQQHAQcDAf////////8BAgoIBAf/////////////AwQHAwAE +AQIK/////////wkCCgkAAggEB/////////8CCgkCCQcCBwMHCQT/////CAQHAwsC//////////// +/wsEBwsCBAIABP////////8JAAEIBAcCAwv/////////BAcLCQQLCQsCCQIB/////wMKAQMLCgcI +BP////////8BCwoBBAsBAAQHCwT/////BAcICQALCQsKCwAD/////wQHCwQLCQkLCv////////8J +BQT/////////////////CQUEAAgD/////////////wAFBAEFAP////////////8IBQQIAwUDAQX/ +////////AQIKCQUE/////////////wMACAECCgQJBf////////8FAgoFBAIEAAL/////////AgoF +AwIFAwUEAwQI/////wkFBAIDC/////////////8ACwIACAsECQX/////////AAUEAAEFAgML//// +/////wIBBQIFCAIICwQIBf////8KAwsKAQMJBQT/////////BAkFAAgBCAoBCAsK/////wUEAAUA +CwULCgsAA/////8FBAgFCAoKCAv/////////CQcIBQcJ/////////////wkDAAkFAwUHA/////// +//8ABwgAAQcBBQf/////////AQUDAwUH/////////////wkHCAkFBwoBAv////////8KAQIJBQAF +AwAFBwP/////CAACCAIFCAUHCgUC/////wIKBQIFAwMFB/////////8HCQUHCAkDCwL///////// +CQUHCQcCCQIAAgcL/////wIDCwABCAEHCAEFB/////8LAgELAQcHAQX/////////CQUICAUHCgED +CgML/////wUHAAUACQcLAAEACgsKAP8LCgALAAMKBQAIAAcFBwD/CwoFBwsF/////////////woG +Bf////////////////8ACAMFCgb/////////////CQABBQoG/////////////wEIAwEJCAUKBv// +//////8BBgUCBgH/////////////AQYFAQIGAwAI/////////wkGBQkABgACBv////////8FCQgF +CAIFAgYDAgj/////AgMLCgYF/////////////wsACAsCAAoGBf////////8AAQkCAwsFCgb///// +////BQoGAQkCCQsCCQgL/////wYDCwYFAwUBA/////////8ACAsACwUABQEFCwb/////AwsGAAMG +AAYFAAUJ/////wYFCQYJCwsJCP////////8FCgYEBwj/////////////BAMABAcDBgUK//////// +/wEJAAUKBggEB/////////8KBgUBCQcBBwMHCQT/////BgECBgUBBAcI/////////wECBQUCBgMA +BAMEB/////8IBAcJAAUABgUAAgb/////BwMJBwkEAwIJBQkGAgYJ/wMLAgcIBAoGBf////////8F +CgYEBwIEAgACBwv/////AAEJBAcIAgMLBQoG/////wkCAQkLAgkECwcLBAUKBv8IBAcDCwUDBQEF +Cwb/////BQELBQsGAQALBwsEAAQL/wAFCQAGBQADBgsGAwgEB/8GBQkGCQsEBwkHCwn/////CgQJ +BgQK/////////////wQKBgQJCgAIA/////////8KAAEKBgAGBAD/////////CAMBCAEGCAYEBgEK +/////wEECQECBAIGBP////////8DAAgBAgkCBAkCBgT/////AAIEBAIG/////////////wgDAggC +BAQCBv////////8KBAkKBgQLAgP/////////AAgCAggLBAkKBAoG/////wMLAgABBgAGBAYBCv// +//8GBAEGAQoECAECAQsICwH/CQYECQMGCQEDCwYD/////wgLAQgBAAsGAQkBBAYEAf8DCwYDBgAA +BgT/////////BgQICwYI/////////////wcKBgcICggJCv////////8ABwMACgcACQoGBwr///// +CgYHAQoHAQcIAQgA/////woGBwoHAQEHA/////////8BAgYBBggBCAkIBgf/////AgYJAgkBBgcJ +AAkDBwMJ/wcIAAcABgYAAv////////8HAwIGBwL/////////////AgMLCgYICggJCAYH/////wIA +BwIHCwAJBwYHCgkKB/8BCAABBwgBCgcGBwoCAwv/CwIBCwEHCgYBBgcB/////wgJBggGBwkBBgsG +AwEDBv8ACQELBgf/////////////BwgABwAGAwsACwYA/////wcLBv////////////////8HBgv/ +////////////////AwAICwcG/////////////wABCQsHBv////////////8IAQkIAwELBwb///// +////CgECBgsH/////////////wECCgMACAYLB/////////8CCQACCgkGCwf/////////BgsHAgoD +CggDCgkI/////wcCAwYCB/////////////8HAAgHBgAGAgD/////////AgcGAgMHAAEJ//////// +/wEGAgEIBgEJCAgHBv////8KBwYKAQcBAwf/////////CgcGAQcKAQgHAQAI/////wADBwAHCgAK +CQYKB/////8HBgoHCggICgn/////////BggECwgG/////////////wMGCwMABgAEBv////////8I +BgsIBAYJAAH/////////CQQGCQYDCQMBCwMG/////wYIBAYLCAIKAf////////8BAgoDAAsABgsA +BAb/////BAsIBAYLAAIJAgoJ/////woJAwoDAgkEAwsDBgQGA/8IAgMIBAIEBgL/////////AAQC +BAYC/////////////wEJAAIDBAIEBgQDCP////8BCQQBBAICBAb/////////CAEDCAYBCAQGBgoB +/////woBAAoABgYABP////////8EBgMEAwgGCgMAAwkKCQP/CgkEBgoE/////////////wQJBQcG +C/////////////8ACAMECQULBwb/////////BQABBQQABwYL/////////wsHBggDBAMFBAMBBf// +//8JBQQKAQIHBgv/////////BgsHAQIKAAgDBAkF/////wcGCwUECgQCCgQAAv////8DBAgDBQQD +AgUKBQILBwb/BwIDBwYCBQQJ/////////wkFBAAIBgAGAgYIB/////8DBgIDBwYBBQAFBAD///// +BgIIBggHAgEIBAgFAQUI/wkFBAoBBgEHBgEDB/////8BBgoBBwYBAAcIBwAJBQT/BAAKBAoFAAMK +BgoHAwcK/wcGCgcKCAUECgQICv////8GCQUGCwkLCAn/////////AwYLAAYDAAUGAAkF/////wAL +CAAFCwABBQUGC/////8GCwMGAwUFAwH/////////AQIKCQULCQsICwUG/////wALAwAGCwAJBgUG +CQECCv8LCAULBQYIAAUKBQIAAgX/BgsDBgMFAgoDCgUD/////wUICQUCCAUGAgMIAv////8JBQYJ +BgAABgL/////////AQUIAQgABQYIAwgCBgII/wEFBgIBBv////////////8BAwYBBgoDCAYFBgkI +CQb/CgEACgAGCQUABQYA/////wADCAUGCv////////////8KBQb/////////////////CwUKBwUL +/////////////wsFCgsHBQgDAP////////8FCwcFCgsBCQD/////////CgcFCgsHCQgBCAMB//// +/wsBAgsHAQcFAf////////8ACAMBAgcBBwUHAgv/////CQcFCQIHCQACAgsH/////wcFAgcCCwUJ +AgMCCAkIAv8CBQoCAwUDBwX/////////CAIACAUCCAcFCgIF/////wkAAQUKAwUDBwMKAv////8J +CAIJAgEIBwIKAgUHBQL/AQMFAwcF/////////////wAIBwAHAQEHBf////////8JAAMJAwUFAwf/ +////////CQgHBQkH/////////////wUIBAUKCAoLCP////////8FAAQFCwAFCgsLAwD/////AAEJ +CAQKCAoLCgQF/////woLBAoEBQsDBAkEAQMBBP8CBQECCAUCCwgEBQj/////AAQLAAsDBAULAgsB +BQEL/wACBQAFCQILBQQFCAsIBf8JBAUCCwP/////////////AgUKAwUCAwQFAwgE/////wUKAgUC +BAQCAP////////8DCgIDBQoDCAUEBQgAAQn/BQoCBQIEAQkCCQQC/////wgEBQgFAwMFAf////// +//8ABAUBAAX/////////////CAQFCAUDCQAFAAMF/////wkEBf////////////////8ECwcECQsJ +Cgv/////////AAgDBAkHCQsHCQoL/////wEKCwELBAEEAAcEC/////8DAQQDBAgBCgQHBAsKCwT/ +BAsHCQsECQILCQEC/////wkHBAkLBwkBCwILAQAIA/8LBwQLBAICBAD/////////CwcECwQCCAME +AwIE/////wIJCgIHCQIDBwcECf////8JCgcJBwQKAgcIBwACAAf/AwcKAwoCBwQKAQoABAAK/wEK +AggHBP////////////8ECQEEAQcHAQP/////////BAkBBAEHAAgBCAcB/////wQAAwcEA/////// +//////8ECAf/////////////////CQoICgsI/////////////wMACQMJCwsJCv////////8AAQoA +CggICgv/////////AwEKCwMK/////////////wECCwELCQkLCP////////8DAAkDCQsBAgkCCwn/ +////AAILCAAL/////////////wMCC/////////////////8CAwgCCAoKCAn/////////CQoCAAkC +/////////////wIDCAIICgABCAEKCP////8BCgL/////////////////AQMICQEI//////////// +/wAJAf////////////////8AAwj//////////////////////////////////////w== +""" + +#static const char cases[256][2] +CASES = (256, 2), """ +AP8BAAEBAgABAgMAAgMFAAEDAgEDAwUBAgUFBAUJCAABBAICAwQFAgQCBgIGCQsAAwgFBQcDCQEG +EA4DDAwFGAEFAwECBAUDAwYHAAUKCQAEAwYEBgsOAQYRDAQLBgUZAggFBwUMCAEGEgwFDgcFHAYV +CwQMDwUeCgUGIAYnAgwBBgQAAwUGAAIGBgMFCw4AAwkGBQcEDAEFDgsDCQQFGgMKBgYHBQwCBhMK +AQwNBhgHBwwJDQEHCQwUBiEHDQMMAgoGBwUNCwIFEAwHCAMFHQYWCgIMEQYbDgkGIgUnAg4FFA4F +CQUFIAsKBiMFKQIQDBcGJQcOAxAGLgQGAxUBCAEHAwIEAQYBAwcHAQYKDAACBwUGBgwLAQUPCQIO +BgUbAgkFCAYNDgIGFAwGCgMGGQUSCAIMEAUfCwkFIgYoAg0DCwcCBg4MAwcGDQAMDgcIBhcMCgoE +BhwMFQcKBikDDQUVCQMLCAUhDBYHCwYqAw4OCwUkBiwCEQYvAxIEBwEJAgsGCAYPCgAFEQwICwcG +GgUTDgQMEgYdCAQFIwUoAg8FFgsFDBMGHg4KBiQGKwQECQcFJQcPAxEFLAITAxYBCgUXDAsOCAYf +CQYHDAUqAw8LCwYmBi0EBQUtAxMCFQELCAUFJgUrAhIFLgMUAhYBDAUvAhQDFwENAhcBDgEPAP8= +""" + +#static const char tiling1[16][3] +TILING1 = (16, 3), """ +AAgDAAEJAQIKAwsCBAcICQUECgYFBwYLBwsGCgUGCQQFBAgHAwILAQoCAAkBAAMI +""" + +#static const char tiling2[24][6] +TILING2 = (24, 6), """ +AQgDCQgBAAsCCAsABAMABwMECQIKAAIJAAUEAQUAAwoBCwoDAQYFAgYBBwIDBgIHCQcIBQcJBggE +CwgGCgQJBgQKCwUKBwULCwoFBwsFCgkEBgoEBgQICwYICQgHBQkHBwMCBgcCAQUGAgEGAwEKCwMK +AAQFAQAFCQoCAAkCBAADBwQDAAILCAALAQMICQEI +""" + +#static const char tiling3_1[24][6] +TILING3_1 = (24, 6), """ +AAgDAQIKCQUEAAgDAwAICwcGAQkAAgMLAAEJCAQHCQABBQoGAQIKCQUECgECBgsHCAQHAwsCAgML +CgYFBQoGBAcIBAkFBwYLBQkECwYHBgoFCAcECwMCBQYKBwQIAgsDAgEKBwsGCgIBBAUJAQAJBgoF +CQEABwQIAAkBCwMCCAADBgcLBAUJAwgAAwgACgIB +""" + +#static const char tiling3_2[24][12] +TILING3_2 = (24, 12), """ +CgMCCggDCgEACAoAAwQIAwUEAwAJBQMJBggHBgAIBgsDAAYDCwADCwkACwIBCQsBBwkEBwEJBwgA +AQcABgEKBgABCQAGCQYFBAoFBAIKBAkBAgQBBwILBwECBwYKAQcKAgcLAgQHAgMIBAIIBQsGBQML +BQoCAwUCCAYHCAoGCAQFCggFCwUGCwkFCwcECQsEBgULBQkLBAcLBAsJBwYIBgoIBQQIBQgKBgsF +CwMFAgoFAgUDCwcCBwQCCAMCCAIECwIHAgEHCgYHCgcBBQoECgIEAQkEAQQCCgEGAQAGBgAJBQYJ +BAkHCQEHAAgHAAcBAwALAAkLAQILAQsJBwgGCAAGAwsGAwYACAQDBAUDCQADCQMFAgMKAwgKAAEK +AAoI +""" + +#static const char tiling4_1[8][6] +TILING4_1 = (8, 6), """ +AAgDBQoGAAEJCwcGAQIKCAQHCQUEAgMLBAUJCwMCCgIBBwQICQEABgcLAwgABgoF +""" + +#static const char tiling4_2[8][18] +TILING4_2 = (8, 18), """ +CAUABQgGAwYIBgMKAAoDCgAFCQYBBgkHAAcJBwALAQsACwEGCgcCBwoEAQQKBAEIAggBCAIHCwQD +BAsFAgULBQIJAwkCCQMEAwQLBQsECwUCCQIFAgkDBAMJAgcKBAoHCgQBCAEEAQgCBwIIAQYJBwkG +CQcACwAHAAsBBgELAAUIBggFCAYDCgMGAwoABQAK +""" + +#static const char tiling5[48][9] +TILING5 = (48, 9), """ +AggDAgoICgkIAQsCAQkLCQgLBAEJBAcBBwMBCAUECAMFAwEFAAoBAAgKCAsKCwQHCwIEAgAEBwAI +BwYABgIACQMACQUDBQcDAwYLAwAGAAQGAwkAAwsJCwoJBQIKBQQCBAACCQYFCQAGAAIGAAcIAAEH +AQUHCgABCgYABgQABgMLBgUDBQEDCgcGCgEHAQMHAQQJAQIEAgYECwECCwcBBwUBCAIDCAQCBAYC +AgUKAgMFAwcFBwoGBwgKCAkKBgkFBgsJCwgJBQgEBQoICgsIBAsHBAkLCQoLBAcLBAsJCQsKBQQI +BQgKCggLBgUJBgkLCwkIBwYKBwoICAoJAgoFAgUDAwUHCAMCCAIEBAIGCwIBCwEHBwEFAQkEAQQC +AgQGCgYHCgcBAQcDBgsDBgMFBQMBCgEACgAGBgAEAAgHAAcBAQcFCQUGCQYAAAYCBQoCBQIEBAIA +AwAJAwkLCwkKAwsGAwYAAAYECQADCQMFBQMHBwgABwAGBgACCwcECwQCAgQAAAEKAAoICAoLCAQF +CAUDAwUBBAkBBAEHBwEDAQILAQsJCQsIAgMIAggKCggJ +""" + +#static const char tiling6_1_1[48][9] +TILING6_1_1 = (48, 9), """ +BgUKAwEICQgBCwcGCQMBAwkIAQIKBwAEAAcDAwAIBQIGAgUBBQQJAgALCAsACgYFCAIAAggLCgYF +AAQDBwMEAwAIBgQKCQoECAMACgcFBwoLCAQHCgACAAoJBwYLAAIJCgkCAgMLBAEFAQQAAAEJBgMH +AwYCCQABCwQGBAsICwcGAQUABAAFAAEJBwULCgsFBAcIAQMKCwoDCQUECwEDAQsKCgECCAUHBQgJ +CAQHAgYBBQEGAQIKBAYICwgGAgMLBQcJCAkHCwIDCQYEBgkKCQUEAwcCBgIHBAUJAgcDBwIGAwIL +BAYJCgkGCwMCCQcFBwkICgIBCAYEBggLBwQIAQYCBgEFAgEKBwUICQgFBAUJAwELCgsBCAcECgMB +AwoLCQEACwUHBQsKBgcLAAUBBQAEAQAJBgQLCAsECQEABwMGAgYDCwMCBQEEAAQBCwYHCQIAAgkK +BwQIAgAKCQoAAAMIBQcKCwoHCAADCgQGBAoJBQYKAwQABAMHBQYKAAIICwgCCQQFCwACAAsICAAD +BgIFAQUCCgIBBAAHAwcABgcLAQMJCAkDCgUGCAEDAQgJ +""" + +#static const char tiling6_1_2[48][27] +TILING6_1_2 = (48, 27), """ +AQwDDAoDBgMKAwYIBQgGCAUMDAkIAQkMDAUKAQwDAQsMCwEGCQYBBgkHDAcJCQgMDAgDCwcMBAwA +BAEMAQQKBwoECgcCDAIHBwMMDAMAAQIMBgwCBgMMAwYIBQgGCAUADAAFBQEMDAECAwAMAAwCDAkC +BQIJAgULBAsFCwQMDAgLAAgMDAQJAAwCAAoMCgAFCAUABQgGDAYICAsMDAsCCgYMBAwADAUACgAF +AAoDBgMKAwYMDAcDBAcMDAYFBAwGDAgGAwYIBgMKAAoDCgAMDAkKBAkMDAAIBQwHBQgMCAUACgAF +AAoDDAMKCgsMDAsHCAMMAgwAAggMCAIHCgcCBwoEDAQKCgkMDAkACAQMAgwADAsABwALAAcJBgkH +CQYMDAoJAgoMDAYLBQwBBQIMAgULBAsFCwQDDAMEBAAMDAABAgMMBwwDBwAMAAcJBgkHCQYBDAEG +BgIMDAIDAAEMBgwEBgkMCQYBCwEGAQsADAALCwgMDAgECQAMBQwBDAYBCwEGAQsABwALAAcMDAQA +BQQMDAcGBQwHDAkHAAcJBwALAQsACwEMDAoLBQoMDAEJAwwBDAgBBAEIAQQKBwoECgcMDAsKAwsM +DAcIAwwBAwkMCQMECwQDBAsFDAULCwoMDAoBCQUMBwwFBwoMCgcCCAIHAggBDAEICAkMDAkFCgEM +BgwCDAcCCAIHAggBBAEIAQQMDAUBBgUMDAQHBgwEDAoEAQQKBAEIAggBCAIMDAsIBgsMDAIKBwwF +DAsFAgULBQIJAwkCCQMMDAgJBwgMDAMLBAwGBAsMCwQDCQMEAwkCDAIJCQoMDAoGCwIMBwwDDAQD +CQMEAwkCBQIJAgUMDAYCBwYMDAUEAwwHAwQMBAMJAgkDCQIFDAUCAgYMDAYHBAUMBgwEDAsEAwQL +BAMJAgkDCQIMDAoJBgoMDAILBQwHBQsMCwUCCQIFAgkDDAMJCQgMDAgHCwMMBAwGBAoMCgQBCAEE +AQgCDAIICAsMDAsGCgIMAgwGAgcMBwIIAQgCCAEEDAQBAQUMDAUGBwQMBQwHDAoHAgcKBwIIAQgC +CAEMDAkIBQkMDAEKAQwDDAkDBAMJAwQLBQsECwUMDAoLAQoMDAUJAQwDAQgMCAEECgQBBAoHDAcK +CgsMDAsDCAcMBwwFBwkMCQcACwAHAAsBDAELCwoMDAoFCQEMAQwFAQYMBgELAAsBCwAHDAcAAAQM +DAQFBgcMBAwGDAkGAQYJBgELAAsBCwAMDAgLBAgMDAAJAwwHDAAHCQcABwkGAQYJBgEMDAIGAwIM +DAEAAQwFDAIFCwUCBQsEAwQLBAMMDAAEAQAMDAMCAAwCAAsMCwAHCQcABwkGDAYJCQoMDAoCCwYM +AAwCDAgCBwIIAgcKBAoHCgQMDAkKAAkMDAQIBwwFDAgFAAUIBQAKAwoACgMMDAsKBwsMDAMIBgwE +BggMCAYDCgMGAwoADAAKCgkMDAkECAAMAAwEAAUMBQAKAwoACgMGDAYDAwcMDAcEBQYMAgwADAoA +BQAKAAUIBggFCAYMDAsIAgsMDAYKAgwAAgkMCQIFCwUCBQsEDAQLCwgMDAgACQQMAgwGDAMGCAYD +BggFAAUIBQAMDAEFAgEMDAADAAwEDAEECgQBBAoHAgcKBwIMDAMHAAMMDAIBAwwBDAsBBgELAQYJ +BwkGCQcMDAgJAwgMDAcLAwwBAwoMCgMGCAYDBggFDAUICAkMDAkBCgUM +""" + +#static const char tiling6_2[48][15] +TILING6_2 = (48, 15), """ +AQoDBgMKAwYIBQgGCAUJAQsDCwEGCQYBBgkHCAcJBAEAAQQKBwoECgcCAwIHBgMCAwYIBQgGCAUA +AQAFAAkCBQIJAgULBAsFCwQIAAoCCgAFCAUABQgGCwYIBAUACgAFAAoDBgMKAwYHBAgGAwYIBgMK +AAoDCgAJBQgHCAUACgAFAAoDCwMKAggACAIHCgcCBwoECQQKAgsABwALAAcJBgkHCQYKBQIBAgUL +BAsFCwQDAAMEBwADAAcJBgkHCQYBAgEGBgkECQYBCwEGAQsACAALBQYBCwEGAQsABwALAAcEBQkH +AAcJBwALAQsACwEKAwgBBAEIAQQKBwoECgcLAwkBCQMECwQDBAsFCgULBwoFCgcCCAIHAggBCQEI +BgcCCAIHAggBBAEIAQQFBgoEAQQKBAEIAggBCAILBwsFAgULBQIJAwkCCQMIBAsGCwQDCQMEAwkC +CgIJBwQDCQMEAwkCBQIJAgUGAwQHBAMJAgkDCQIFBgUCBgsEAwQLBAMJAgkDCQIKBQsHCwUCCQIF +AgkDCAMJBAoGCgQBCAEEAQgCCwIIAgcGBwIIAQgCCAEEBQQBBQoHAgcKBwIIAQgCCAEJAQkDBAMJ +AwQLBQsECwUKAQgDCAEECgQBBAoHCwcKBwkFCQcACwAHAAsBCgELAQYFBgELAAsBCwAHBAcABAkG +AQYJBgELAAsBCwAIAwAHCQcABwkGAQYJBgECAQIFCwUCBQsEAwQLBAMAAAsCCwAHCQcABwkGCgYJ +AAgCBwIIAgcKBAoHCgQJBwgFAAUIBQAKAwoACgMLBggECAYDCgMGAwoACQAKAAUEBQAKAwoACgMG +BwYDAgoABQAKAAUIBggFCAYLAgkACQIFCwUCBQsECAQLAgMGCAYDBggFAAUIBQABAAEECgQBBAoH +AgcKBwIDAwsBBgELAQYJBwkGCQcIAwoBCgMGCAYDBggFCQUI +""" + +#static const char tiling7_1[16][9] +TILING7_1 = (16, 9), """ +CQUECgECCAMACwcGCAMACgECAwAIBQQJBwYLCAQHCQABCwIDCgYFCwIDCQABAAEJBgUKBAcIAQIK +BwYLBQQJAgMLBAcIBgUKCwMCCAcECgUGCgIBCwYHCQQFCQEACgUGCAcEBQYKAwILAQAJBwQIAQAJ +AwILCAADCQQFCwYHBgcLAAMIAgEKBAUJAgEKAAMI +""" + +#static const char tiling7_2[16][3][15] +TILING7_2 = (16, 3, 15), """ +AQIKAwQIBAMFAAUDBQAJAwAICQEEAgQBBAIFCgUCCQUEAAoBCgAICggCAwIIAwAIAQYKBgEHAgcB +BwILAQIKCwMGAAYDBgAHCAcACwcGAggDCAIKCAoAAQAKCQUECwMGAAYDBgAHCAcACwcGAwQIBAMF +AAUDBQAJAwAIBAkHCwcJBQsJCwUGAAEJAgcLBwIEAwQCBAMIAgMLCAAHAQcABwEECQQBCAQHAwkA +CQMLCQsBAgELAgMLAAUJBQAGAQYABgEKAAEJCgIFAwUCBQMGCwYDBgUKAQsCCwEJCwkDAAMJBgUK +CAAHAQcABwEECQQBCAQHAAUJBQAGAQYABgEKAAEJBQoECAQKBggKCAYHCwcGCQEEAgQBBAIFCgUC +CQUEAQYKBgEHAgcBBwILAQIKBgsFCQULBwkLCQcECAQHCgIFAwUCBQMGCwYDBgUKAgcLBwIEAwQC +BAMIAgMLBwgGCgYIBAoICgQFBwQIBQIKAgUDBgMFAwYLCgUGCwcCBAIHAgQDCAMECwMCBggHCAYK +CAoEBQQKBgcLBAEJAQQCBQIEAgUKBAUJCgYBBwEGAQcCCwIHCgIBBQsGCwUJCwkHBAcJCgUGBwAI +AAcBBAEHAQQJBwQICQUABgAFAAYBCgEGCQEABAoFCgQICggGBwYICwMCCQUABgAFAAYBCgEGCQEA +BQIKAgUDBgMFAwYLCgUGAgsBCQELAwkLCQMACQEACwcCBAIHAgQDCAMECwMCBwAIAAcBBAEHAQQJ +BwQIAAkDCwMJAQsJCwECBAUJBgMLAwYABwAGAAcIBgcLCAQDBQMEAwUACQAFCAADBwkECQcLCQsF +BgULCAADCgYBBwEGAQcCCwIHCgIBBgMLAwYABwAGAAcIBgcLAwgCCgIIAAoICgABCgIBCAQDBQME +AwUACQAFCAADBAEJAQQCBQIEAgUKBAUJAQoACAAKAggKCAID +""" + +#static const char tiling7_3[16][3][27] +TILING7_3 = (16, 3, 27), """ +DAIKDAoFDAUEDAQIDAgDDAMADAAJDAkBDAECDAUEDAQIDAgDDAMCDAIKDAoBDAEADAAJDAkFBQQM +CgUMAgoMAwIMCAMMAAgMAQAMCQEMBAkMDAAIDAgHDAcGDAYKDAoBDAECDAILDAsDDAMADAcGDAYK +DAoBDAEADAAIDAgDDAMCDAILDAsHBwYMCAcMAAgMAQAMCgEMAgoMAwIMCwMMBgsMCQUMAAkMAwAM +CwMMBgsMBwYMCAcMBAgMBQQMAwAMCwMMBgsMBQYMCQUMBAkMBwQMCAcMAAgMDAMADAAJDAkFDAUG +DAYLDAsHDAcEDAQIDAgDDAEJDAkEDAQHDAcLDAsCDAIDDAMIDAgADAABDAQHDAcLDAsCDAIBDAEJ +DAkADAADDAMIDAgEBAcMCQQMAQkMAgEMCwIMAwsMAAMMCAAMBwgMDAMLDAsGDAYFDAUJDAkADAAB +DAEKDAoCDAIDDAYFDAUJDAkADAADDAMLDAsCDAIBDAEKDAoGBgUMCwYMAwsMAAMMCQAMAQkMAgEM +CgIMBQoMCgYMAQoMAAEMCAAMBwgMBAcMCQQMBQkMBgUMAAEMCAAMBwgMBgcMCgYMBQoMBAUMCQQM +AQkMDAABDAEKDAoGDAYHDAcIDAgEDAQFDAUJDAkACwcMAgsMAQIMCQEMBAkMBQQMCgUMBgoMBwYM +AQIMCQEMBAkMBwQMCwcMBgsMBQYMCgUMAgoMDAECDAILDAsHDAcEDAQJDAkFDAUGDAYKDAoBCAQM +AwgMAgMMCgIMBQoMBgUMCwYMBwsMBAcMAgMMCgIMBQoMBAUMCAQMBwgMBgcMCwYMAwsMDAIDDAMI +DAgEDAQFDAUKDAoGDAYHDAcLDAsCDAQIDAgDDAMCDAIKDAoFDAUGDAYLDAsHDAcEDAMCDAIKDAoF +DAUEDAQIDAgHDAcGDAYLDAsDAwIMCAMMBAgMBQQMCgUMBgoMBwYMCwcMAgsMDAcLDAsCDAIBDAEJ +DAkEDAQFDAUKDAoGDAYHDAIBDAEJDAkEDAQHDAcLDAsGDAYFDAUKDAoCAgEMCwIMBwsMBAcMCQQM +BQkMBgUMCgYMAQoMDAYKDAoBDAEADAAIDAgHDAcEDAQJDAkFDAUGDAEADAAIDAgHDAcGDAYKDAoF +DAUEDAQJDAkBAQAMCgEMBgoMBwYMCAcMBAgMBQQMCQUMAAkMCwMMBgsMBQYMCQUMAAkMAQAMCgEM +AgoMAwIMBQYMCQUMAAkMAwAMCwMMAgsMAQIMCgEMBgoMDAUGDAYLDAsDDAMADAAJDAkBDAECDAIK +DAoFCQEMBAkMBwQMCwcMAgsMAwIMCAMMAAgMAQAMBwQMCwcMAgsMAQIMCQEMAAkMAwAMCAMMBAgM +DAcEDAQJDAkBDAECDAILDAsDDAMADAAIDAgHDAUJDAkADAADDAMLDAsGDAYHDAcIDAgEDAQFDAAD +DAMLDAsGDAYFDAUJDAkEDAQHDAcIDAgAAAMMCQAMBQkMBgUMCwYMBwsMBAcMCAQMAwgMCAAMBwgM +BgcMCgYMAQoMAgEMCwIMAwsMAAMMBgcMCgYMAQoMAAEMCAAMAwgMAgMMCwIMBwsMDAYHDAcIDAgA +DAABDAEKDAoCDAIDDAMLDAsGCgIMBQoMBAUMCAQMAwgMAAMMCQAMAQkMAgEMBAUMCAQMAwgMAgMM +CgIMAQoMAAEMCQAMBQkMDAQFDAUKDAoCDAIDDAMIDAgADAABDAEJDAkE +""" + +#static const char tiling7_4_1[16][15] +TILING7_4_1 = (16, 15), """ +AwQIBAMKAgoDBAoFCQEAAQYKBgEIAAgBBggHCwMCCwMGCQYDBgkFAAkDBwQIAgcLBwIJAQkCBwkE +CAADAAUJBQALAwsABQsGCgIBCAAHCgcABwoGAQoABAUJCQEECwQBBAsHAgsBBQYKCgIFCAUCBQgE +AwgCBgcLBQIKAgUIBAgFAggDCwcGBAEJAQQLBwsEAQsCCgYFBwAIAAcKBgoHAAoBCQUECQUACwAF +AAsDBgsFAQIKCwcCCQIHAgkBBAkHAwAIBgMLAwYJBQkGAwkACAQHCgYBCAEGAQgABwgGAgMLCAQD +CgMEAwoCBQoEAAEJ +""" + +#static const char tiling7_4_2[16][27] +TILING7_4_2 = (16, 27), """ +CQQIBAkFCgUJAQoJCgECAAIBAgADCAMACQgACwYKBgsHCAcLAwgLCAMAAgADAAIBCgECCwoCCwMI +AAgDCAAJCAkEBQQJBAUHBgcFBwYLBwsICAcLBwgECQQIAAkICQABAwEAAQMCCwIDCAsDCgUJBQoG +CwYKAgsKCwIDAQMCAwEACQABCgkBCAAJAQkACQEKCQoFBgUKBQYEBwQGBAcIBAgJCQEKAgoBCgIL +CgsGBwYLBgcFBAUHBQQJBQkKCgILAwsCCwMICwgHBAcIBwQGBQYEBgUKBgoLCwIKAgsDCAMLBwgL +CAcEBgQHBAYFCgUGCwoGCgEJAQoCCwIKBgsKCwYHBQcGBwUECQQFCgkFCQAIAAkBCgEJBQoJCgUG +BAYFBgQHCAcECQgECQUKBgoFCgYLCgsCAwILAgMBAAEDAQAJAQkKCwcIBAgHCAQJCAkAAQAJAAED +AgMBAwILAwsICAMLAwgACQAIBAkICQQFBwUEBQcGCwYHCAsHCgYLBwsGCwcICwgDAAMIAwACAQIA +AgEKAgoLCAQJBQkECQUKCQoBAgEKAQIAAwACAAMIAAgJ +""" + +#static const char tiling8[6][6] +TILING8 = (6, 6), """ +CQgKCggLAQUDAwUHAAQCBAYCAAIEBAIGAQMFAwcFCQoICgsI +""" + +#static const char tiling9[8][12] +TILING9 = (8, 12), """ +AgoFAwIFAwUEAwQIBAcLCQQLCQsCCQIBCgcGAQcKAQgHAQAIAwYLAAYDAAUGAAkFAwsGAAMGAAYF +AAUJCgYHAQoHAQcIAQgABAsHCQsECQILCQECAgUKAwUCAwQFAwgE +""" + +#static const char tiling10_1_1[6][12] +TILING10_1_1 = (6, 12), """ +BQoHCwcKCAEJAQgDAQIFBgUCBAMAAwQHCwAIAAsCBAkGCgYJCQAKAgoABggECAYLBwIDAgcGAAEE +BQQBBwkFCQcICgELAwsB +""" + +#static const char tiling10_1_1_[6][12] +TILING10_1_1_ = (6, 12), """ +BQkHCAcJCwEKAQsDAwIHBgcCBAEAAQQFCgAJAAoCBAgGCwYICAALAgsABgkECQYKBQIBAgUGAAME +BwQDBwoFCgcLCQEIAwgB +""" + +#static const char tiling10_1_2[6][24] +TILING10_1_2 = (6, 24), """ +AwsHAwcICQgHBQkHCQUKCQoBAwEKCwMKBwYFBwUEAAQFAQAFAAECAAIDBwMCBgcCCwIKBgsKCwYE +CwQIAAgECQAEAAkKAAoCCwIKCwoGBAYKCQQKBAkABAAICwgAAgsABwYFBAcFBwQABwADAgMAAQIA +AgEFAgUGBwgDCwcDBwsKBwoFCQUKAQkKCQEDCQMI +""" + +#static const char tiling10_2[6][24] +TILING10_2 = (6, 24), """ +DAUJDAkIDAgDDAMBDAEKDAoLDAsHDAcFDAEADAAEDAQHDAcDDAMCDAIGDAYFDAUBBAgMBgQMCgYM +CQoMAAkMAgAMCwIMCAsMDAkEDAQGDAYLDAsIDAgADAACDAIKDAoJAAMMBAAMBQQMAQUMAgEMBgIM +BwYMAwcMCgUMCwoMAwsMAQMMCQEMCAkMBwgMBQcM +""" + +#static const char tiling10_2_[6][24] +TILING10_2_ = (6, 24), """ +CAcMCQgMAQkMAwEMCwMMCgsMBQoMBwUMBAUMAAQMAwAMBwMMBgcMAgYMAQIMBQEMDAsGDAYEDAQJ +DAkKDAoCDAIADAAIDAgLBgoMBAYMCAQMCwgMAgsMAAIMCQAMCgkMDAcEDAQADAABDAEFDAUGDAYC +DAIDDAMHDAcLDAsKDAoBDAEDDAMIDAgJDAkFDAUH +""" + +#static const char tiling11[12][12] +TILING11 = (12, 12), """ +AgoJAgkHAgcDBwkEAQYCAQgGAQkICAcGCAMBCAEGCAYEBgEKAAgLAAsFAAUBBQsGCQUHCQcCCQIA +AgcLBQAEBQsABQoLCwMABQQABQALBQsKCwADCQcFCQIHCQACAgsHAAsIAAULAAEFBQYLCAEDCAYB +CAQGBgoBAQIGAQYIAQgJCAYHAgkKAgcJAgMHBwQJ +""" + +#static const char tiling12_1_1[24][12] +TILING12_1_1 = (24, 12), """ +BwYLCgMCAwoICQgKBgUKCQIBAgkLCAsJCgYFBwkECQcBAwEHBwYLBAgFAwUIBQMBBQQJCAEAAQgK +CwoIAQIKAAkDBQMJAwUHCgECAAsDCwAGBAYACAMAAgkBCQIEBgQCAwAIAgsBBwELAQcFBgUKBwsE +AgQLBAIACQUEBggHCAYAAgAGCAMABwQLCQsECwkKBAcICwADAAsJCgkLBAcIBQkGAAYJBgACCwcG +BAoFCgQCAAIECwIDAQgACAEHBQcBAAEJAwgCBAIIAgQGAgMLAQoABgAKAAYECQABAwoCCgMFBwUD +CQABBAUICggFCAoLCAQHBQsGCwUDAQMFBQQJBgoHAQcKBwEDCgECBQYJCwkGCQsICwIDBgcKCAoH +CggJ +""" + +#static const char tiling12_1_1_[24][12] +TILING12_1_1_ = (24, 12), """ +AwILCgcGBwoICQgKAgEKCQYFBgkLCAsJCQQFBwoGCgcBAwEHBwQIBgsFAwULBQMBAQAJCAUEBQgK +CwoIAQAJAgoDBQMKAwUHCwMCAAoBCgAGBAYACQEAAggDCAIEBgQCAwILAAgBBwEIAQcFBgcLBQoE +AgQKBAIACAcEBgkFCQYAAgAGCAcEAwALCQsACwkKAAMICwQHBAsJCgkLBAUJBwgGAAYIBgACCgUG +BAsHCwQCAAIECAADAQsCCwEHBQcBAAMIAQkCBAIJAgQGAgEKAwsABgALAAYECgIBAwkACQMFBwUD +CQQFAAEICggBCAoLCwYHBQgECAUDAQMFBQYKBAkHAQcJBwEDCgUGAQIJCwkCCQsICwYHAgMKCAoD +CggJ +""" + +#static const char tiling12_1_2[24][24] +TILING12_1_2 = (24, 24), """ +BwMLAwcICQgHBgkHCQYKAgoGCwIGAgsDBgIKAgYLCAsGBQgGCAUJAQkFCgEFAQoCCgkFCQoBAwEK +BgMKAwYHBAcGBQQGBAUJBwgLAwsICwMBCwEGBQYBBgUEBgQHCAcEBQEJAQUKCwoFBAsFCwQIAAgE +CQAEAAkBAQkKBQoJCgUHCgcCAwIHAgMAAgABCQEACgsCCwoGBAYKAQQKBAEAAwABAgMBAwILCAkA +CQgEBgQIAwYIBgMCAQIDAAEDAQAJAwsIBwgLCAcFCAUAAQAFAAECAAIDCwMCBgsKAgoLCgIACgAF +BAUABQQHBQcGCwYHCQgECAkAAgAJBQIJAgUGBwYFBAcFBwQICAQACQAEAAkKAAoDCwMKAwsHAwcI +BAgHBAAIAAQJCgkEBwoECgcLAwsHCAMHAwgABAkIAAgJCAACCAIHBgcCBwYFBwUECQQFCwoGCgsC +AAILBwALAAcEBQQHBgUHBQYKCwgDCAsHBQcLAgULBQIBAAECAwACAAMIAAgJBAkICQQGCQYBAgEG +AQIDAQMACAADAgoLBgsKCwYECwQDAAMEAwABAwECCgIBCQoBCgkFBwUJAAcJBwADAgMAAQIAAgEK +CQUBCgEFAQoLAQsACAALAAgEAAQJBQkECAsHCwgDAQMIBAEIAQQFBgUEBwYEBgcLBQoJAQkKCQED +CQMEBwQDBAcGBAYFCgUGCgYCCwIGAgsIAggBCQEIAQkFAQUKBgoFCwcDCAMHAwgJAwkCCgIJAgoG +AgYLBwsG +""" + +#static const char tiling12_2[24][24] +TILING12_2 = (24, 24), """ +CQgMCgkMAgoMAwIMCwMMBgsMBwYMCAcMCAsMCQgMAQkMAgEMCgIMBQoMBgUMCwYMAwEMBwMMBAcM +CQQMBQkMBgUMCgYMAQoMDAMBDAEFDAUGDAYLDAsHDAcEDAQIDAgDCwoMCAsMAAgMAQAMCQEMBAkM +BQQMCgUMDAUHDAcDDAMCDAIKDAoBDAEADAAJDAkFBAYMAAQMAQAMCgEMAgoMAwIMCwMMBgsMBgQM +AgYMAwIMCAMMAAgMAQAMCQEMBAkMDAcFDAUBDAEADAAIDAgDDAMCDAILDAsHDAIADAAEDAQFDAUK +DAoGDAYHDAcLDAsCAgAMBgIMBwYMCAcMBAgMBQQMCQUMAAkMDAkKDAoLDAsHDAcEDAQIDAgDDAMA +DAAJCgkMCwoMBwsMBAcMCAQMAwgMAAMMCQAMDAACDAIGDAYHDAcIDAgEDAQFDAUJDAkAAAIMBAAM +BQQMCgUMBgoMBwYMCwcMAgsMBQcMAQUMAAEMCAAMAwgMAgMMCwIMBwsMDAQGDAYCDAIDDAMIDAgA +DAABDAEJDAkEDAYEDAQADAABDAEKDAoCDAIDDAMLDAsGBwUMAwcMAgMMCgIMAQoMAAEMCQAMBQkM +DAoLDAsIDAgADAABDAEJDAkEDAQFDAUKAQMMBQEMBgUMCwYMBwsMBAcMCAQMAwgMDAEDDAMHDAcE +DAQJDAkFDAUGDAYKDAoBDAsIDAgJDAkBDAECDAIKDAoFDAUGDAYLDAgJDAkKDAoCDAIDDAMLDAsG +DAYHDAcI +""" + +#static const char tiling12_2_[24][24] +TILING12_2_ = (24, 24), """ +DAILDAsHDAcGDAYKDAoJDAkIDAgDDAMCDAEKDAoGDAYFDAUJDAkIDAgLDAsCDAIBDAQFDAUKDAoG +DAYHDAcDDAMBDAEJDAkEBwYMCAcMBAgMBQQMAQUMAwEMCwMMBgsMDAAJDAkFDAUEDAQIDAgLDAsK +DAoBDAEAAQIMCQEMAAkMAwAMBwMMBQcMCgUMAgoMDAECDAILDAsDDAMADAAEDAQGDAYKDAoBDAMA +DAAJDAkBDAECDAIGDAYEDAQIDAgDAwAMCwMMAgsMAQIMBQEMBwUMCAcMAAgMBgUMCwYMBwsMBAcM +AAQMAgAMCgIMBQoMDAcEDAQJDAkFDAUGDAYCDAIADAAIDAgHCAcMAAgMAwAMCwMMCgsMCQoMBAkM +BwQMDAcIDAgADAADDAMLDAsKDAoJDAkEDAQHBAcMCQQMBQkMBgUMAgYMAAIMCAAMBwgMDAUGDAYL +DAsHDAcEDAQADAACDAIKDAoFDAADDAMLDAsCDAIBDAEFDAUHDAcIDAgAAAMMCQAMAQkMAgEMBgIM +BAYMCAQMAwgMAgEMCwIMAwsMAAMMBAAMBgQMCgYMAQoMDAIBDAEJDAkADAADDAMHDAcFDAUKDAoC +CQAMBQkMBAUMCAQMCwgMCgsMAQoMAAEMDAYHDAcIDAgEDAQFDAUBDAEDDAMLDAsGBQQMCgUMBgoM +BwYMAwcMAQMMCQEMBAkMCgEMBgoMBQYMCQUMCAkMCwgMAgsMAQIMCwIMBwsMBgcMCgYMCQoMCAkM +AwgMAgMM +""" + +#static const char tiling13_1[2][12] +TILING13_1 = (2, 12), """ +CwcGAQIKCAMACQUECAQHAgMLCQABCgYF +""" + +#static const char tiling13_1_[2][12] +TILING13_1_ = (2, 12), """ +BwQICwMCAQAJBQYKBgcLCgIBAAMIBAUJ +""" + +#static const char tiling13_2[2][6][18] +TILING13_2 = (2, 6, 18), """ +AQIKCwcGAwQIBAMFAAUDBQAJCAMACwcGCQEEAgQBBAIFCgUCCQUECAMAAQYKBgEHAgcBBwILCQUE +AQIKCwMGAAYDBgAHCAcACQUECwcGAAoBCgAICggCAwIIAQIKAwAIBAkHCwcJBQsJCwUGAgMLCAQH +AAUJBQAGAQYABgEKCQABCAQHCgIFAwUCBQMGCwYDBgUKCQABAgcLBwIEAwQCBAMIBgUKAgMLCAAH +AQcABwEECQQBBgUKCAQHAQsCCwEJCwkDAAMJAgMLAAEJBQoECAQKBggKCAYH +""" + +#static const char tiling13_2_[2][6][18] +TILING13_2_ = (2, 6, 18), """ +CgUGCwMCBwAIAAcBBAEHAQQJCwMCBwQICQUABgAFAAYBCgEGAQAJBwQIBQIKAgUDBgMFAwYLCgUG +AQAJCwcCBAIHAgQDCAMECgUGBwQIAgsBCQELAwkLCQMACwMCCQEABAoFCgQICggGBwYIBgcLCAAD +BAEJAQQCBQIEAgUKCAADBAUJCgYBBwEGAQcCCwIHAgEKBAUJBgMLAwYABwAGAAcIBgcLAgEKCAQD +BQMEAwUACQAFBgcLBAUJAwgCCgIIAAoICgABCAADCgIBBQsGCwUJCwkHBAcJ +""" + +#static const char tiling13_3[2][12][30] +TILING13_3 = (2, 12, 30), """ +CwcGDAIKDAoFDAUEDAQIDAgDDAMADAAJDAkBDAECAQIKCQUMAAkMAwAMCwMMBgsMBwYMCAcMBAgM +BQQMCwcGDAUEDAQIDAgDDAMCDAIKDAoBDAEADAAJDAkFAQIKDAMADAAJDAkFDAUGDAYLDAsHDAcE +DAQIDAgDCAMACwcMAgsMAQIMCQEMBAkMBQQMCgUMBgoMBwYMCwcGBQQMCgUMAgoMAwIMCAMMAAgM +AQAMCQEMBAkMCAMAAQIMCQEMBAkMBwQMCwcMBgsMBQYMCgUMAgoMCQUEDAAIDAgHDAcGDAYKDAoB +DAECDAILDAsDDAMACQUEDAcGDAYKDAoBDAEADAAIDAgDDAMCDAILDAsHCAMADAECDAILDAsHDAcE +DAQJDAkFDAUGDAYKDAoBCQUEBwYMCAcMAAgMAQAMCgEMAgoMAwIMCwMMBgsMAQIKAwAMCwMMBgsM +BQYMCQUMBAkMBwQMCAcMAAgMCAQHDAMLDAsGDAYFDAUJDAkADAABDAEKDAoCDAIDAgMLCgYMAQoM +AAEMCAAMBwgMBAcMCQQMBQkMBgUMCAQHDAYFDAUJDAkADAADDAMLDAsCDAIBDAEKDAoGAgMLDAAB +DAEKDAoGDAYHDAcIDAgEDAQFDAUJDAkAAAEJCAQMAwgMAgMMCgIMBQoMBgUMCwYMBwsMBAcMCAQH +BgUMCwYMAwsMAAMMCQAMAQkMAgEMCgIMBQoMCQABAgMMCgIMBQoMBAUMCAQMBwgMBgcMCwYMAwsM +BgUKDAEJDAkEDAQHDAcLDAsCDAIDDAMIDAgADAABBgUKDAQHDAcLDAsCDAIBDAEJDAkADAADDAMI +DAgECQABDAIDDAMIDAgEDAQFDAUKDAoGDAYHDAcLDAsCBgUKBAcMCQQMAQkMAgEMCwIMAwsMAAMM +CAAMBwgMAgMLAAEMCAAMBwgMBgcMCgYMBQoMBAUMCQQMAQkM +""" + +#static const char tiling13_3_[2][12][30] +TILING13_3_ = (2, 12, 30), """ +AwILCAcMAAgMAQAMCgEMBgoMBQYMCQUMBAkMBwQMBQYKDAILDAsHDAcEDAQJDAkBDAEADAAIDAgD +DAMCCgUGDAcEDAQJDAkBDAECDAILDAsDDAMADAAIDAgHCwMCDAEADAAIDAgHDAcGDAYKDAoFDAUE +DAQJDAkBBwQICwMMBgsMBQYMCQUMAAkMAQAMCgEMAgoMAwIMBwQIBQYMCQUMAAkMAwAMCwMMAgsM +AQIMCgEMBgoMCwMCAQAMCgEMBgoMBwYMCAcMBAgMBQQMCQUMAAkMAQAJDAQIDAgDDAMCDAIKDAoF +DAUGDAYLDAsHDAcEBwQIDAUGDAYLDAsDDAMADAAJDAkBDAECDAIKDAoFAQAJDAMCDAIKDAoFDAUE +DAQIDAgHDAcGDAYLDAsDCgUGBwQMCwcMAgsMAQIMCQEMAAkMAwAMCAMMBAgMCQEAAwIMCAMMBAgM +BQQMCgUMBgoMBwYMCwcMAgsMAAMICQQMAQkMAgEMCwIMBwsMBgcMCgYMBQoMBAUMCwYHDAMIDAgE +DAQFDAUKDAoCDAIBDAEJDAkADAADBgcLDAQFDAUKDAoCDAIDDAMIDAgADAABDAEJDAkECAADDAIB +DAEJDAkEDAQHDAcLDAsGDAYFDAUKDAoCBAUJCAAMBwgMBgcMCgYMAQoMAgEMCwIMAwsMAAMMBAUJ +BgcMCgYMAQoMAAEMCAAMAwgMAgMMCwIMBwsMCAADAgEMCwIMBwsMBAcMCQQMBQkMBgUMCgYMAQoM +AgEKDAUJDAkADAADDAMLDAsGDAYHDAcIDAgEDAQFBAUJDAYHDAcIDAgADAABDAEKDAoCDAIDDAML +DAsGAgEKDAADDAMLDAsGDAYFDAUJDAkEDAQHDAcIDAgABgcLBAUMCAQMAwgMAgMMCgIMAQoMAAEM +CQAMBQkMCgIBAAMMCQAMBQkMBgUMCwYMBwsMBAcMCAQMAwgM +""" + +#static const char tiling13_4[2][4][36] +TILING13_4 = (2, 4, 36), """ +DAIKDAoFDAUGDAYLDAsHDAcEDAQIDAgDDAMADAAJDAkBDAECCwMMBgsMBwYMCAcMBAgMBQQMCQUM +AAkMAQAMCgEMAgoMAwIMCQEMBAkMBQQMCgUMBgoMBwYMCwcMAgsMAwIMCAMMAAgMAQAMDAAIDAgH +DAcEDAQJDAkFDAUGDAYKDAoBDAECDAILDAsDDAMADAMLDAsGDAYHDAcIDAgEDAQFDAUJDAkADAAB +DAEKDAoCDAIDCAAMBwgMBAcMCQQMBQkMBgUMCgYMAQoMAgEMCwIMAwsMAAMMCgIMBQoMBgUMCwYM +BwsMBAcMCAQMAwgMAAMMCQAMAQkMAgEMDAEJDAkEDAQFDAUKDAoGDAYHDAcLDAsCDAIDDAMIDAgA +DAAB +""" + +#static const char tiling13_5_1[2][4][18] +TILING13_5_1 = (2, 4, 18), """ +BwYLAQAJCgMCAwoFAwUIBAgFAQIKBwQIAwALBgsACQYABgkFAwAIBQYKAQIJBAkCCwQCBAsHBQQJ +AwILCAEAAQgHAQcKBgoHBAcIAgEKCwADAAsGAAYJBQkGAgMLBAUJAAEIBwgBCgcBBwoGAAEJBgcL +AgMKBQoDCAUDBQgEBgUKAAMICQIBAgkEAgQLBwsE +""" + +#static const char tiling13_5_2[2][4][30] +TILING13_5_2 = (2, 4, 30), """ +AQAJBwQIBwgDBwMLAgsDCwIKCwoGBQYKBgUHBAcFBwQICwMCBgsCCgYCBgoFCQUKAQkKCQEAAgAB +AAIDBQYKCQEABAkACAQABAgHCwcIAwsICwMCAAIDAgABAwILBQYKBQoBBQEJAAkBCQAICQgEBAgH +BAcFBgUHAgEKBAUJBAkABAAIAwgACAMLCAsHBgcLBwYEBQQGBAUJCAADBwgDCwcDBwsGCgYLAgoL +CgIBAwECAQMABgcLCgIBBQoBCQUBBQkECAQJAAgJCAADAQMAAwECAAMIBgcLBgsCBgIKAQoCCgEJ +CgkFBQkEBQQGBwYE +""" + +#static const char tiling14[12][12] +TILING14 = (12, 12), """ +BQkIBQgCBQIGAwIIAgEFAgUIAggLBAgFCQQGCQYDCQMBCwMGAQsKAQQLAQAEBwsECAIACAUCCAcF +CgIFAAcDAAoHAAkKBgcKAAMHAAcKAAoJBgoHCAACCAIFCAUHCgUCAQoLAQsEAQQABwQLCQYECQMG +CQEDCwYDAgUBAggFAgsIBAUIBQgJBQIIBQYCAwgC +""" + +#static const char test3[24] +TEST3 = (24,), """ +BQEEBQECAgMEAwYG+vr9/P3+/v/7/P/7 +""" + +#static const char test4[8] +TEST4 = (8,), """ +BwcHB/n5+fk= +""" + +#static const char test6[48][3] +TEST6 = (48, 3), """ +AgcKBAcLBQcBBQcDAQcJAwcKBgcFAQcIBAcIAQcIAwcLBQcCBQcAAQcJBgcGAgcJBAcIAgcJAgcK +BgcHAwcKBAcLAwcLBgcE+vkE/fkL/PkL/fkK+vkH/vkK/vkJ/PkI/vkJ+vkG//kJ+/kA+/kC/fkL +//kI/PkI//kI+vkF/fkK//kJ+/kD+/kB/PkL/vkK +""" + +#static const char test7[16][5] +TEST7 = (16, 5), """ +AQIFBwEDBAUHAwQBBgcEBAEFBwACAwUHAgECBgcFAgMGBwYDBAYHB/38+vkH/v36+Qb//vr5Bf79 ++/kC/P/7+QD8//r5BP38+/kD//77+QE= +""" + +#static const char test10[6][3] +TEST10 = (6, 3), """ +AgQHBQYHAQMHAQMHBQYHAgQH +""" + +#static const char test12[24][4] +TEST12 = (24, 4), """ +BAMHCwMCBwoCBgcFBgQHBwIBBwkFAgcBBQMHAgUBBwAFBAcDBgMHBgEGBwQBBAcIBAEHCAYBBwQD +BgcGBAUHAwEFBwADBQcCAgUHAQECBwkEBgcHBgIHBQIDBwoDBAcL +""" + +#static const char test13[2][7] +TEST13 = (2, 7), """ +AQIDBAUGBwIDBAEFBgc= +""" + +#static const char subconfig13[64] +SUBCONFIG13 = (64,), """ +AAECBwP/C/8ECP//Dv///wUJDBcP/xUmERT/JBohHiwGCg0TEP8ZJRIY/yMWIB0r////Iv//HCr/ +H/8pGygnLQ== +""" diff --git a/skimage/measure/setup.py b/skimage/measure/setup.py index ef92450a..cea657c5 100644 --- a/skimage/measure/setup.py +++ b/skimage/measure/setup.py @@ -16,6 +16,7 @@ def configuration(parent_package='', top_path=None): cython(['_find_contours_cy.pyx'], working_path=base_path) cython(['_moments_cy.pyx'], working_path=base_path) cython(['_marching_cubes_cy.pyx'], working_path=base_path) + cython(['_marching_cubes_lewiner_cy.pyx'], working_path=base_path) cython(['_pnpoly.pyx'], working_path=base_path) config.add_extension('_ccomp', sources=['_ccomp.c'], @@ -27,6 +28,9 @@ def configuration(parent_package='', top_path=None): config.add_extension('_marching_cubes_cy', sources=['_marching_cubes_cy.c'], include_dirs=[get_numpy_include_dirs()]) + config.add_extension('_marching_cubes_lewiner_cy', + sources=['_marching_cubes_lewiner_cy.c'], + include_dirs=[get_numpy_include_dirs()]) config.add_extension('_pnpoly', sources=['_pnpoly.c'], include_dirs=[get_numpy_include_dirs(), '../_shared']) From 8d9ad26488112a8cb794d54088ab98b93e529185 Mon Sep 17 00:00:00 2001 From: almar Date: Wed, 20 Apr 2016 02:24:24 +0200 Subject: [PATCH 02/25] mc deal with degenerate triangles --- skimage/measure/_marching_cubes_lewiner.py | 14 +++- .../measure/_marching_cubes_lewiner_cy.pyx | 66 ++++++++++++++++--- 2 files changed, 68 insertions(+), 12 deletions(-) diff --git a/skimage/measure/_marching_cubes_lewiner.py b/skimage/measure/_marching_cubes_lewiner.py index 12cb5100..537395f2 100644 --- a/skimage/measure/_marching_cubes_lewiner.py +++ b/skimage/measure/_marching_cubes_lewiner.py @@ -14,7 +14,7 @@ from . import _marching_cubes_lewiner_cy def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), - step_size=1, use_classic=False): + step_size=1, allow_degenerate=True, use_classic=False): """ Lewiner marching cubes algorithm to find surfaces in 3d volumetric data @@ -35,6 +35,10 @@ def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), Step size in voxels. Default 1. Larger steps yield faster but coarser results. The result will always be topologically correct though. + allow_degenerate : bool + Whether to allow degenerate triangles in the end-result. Default True. + If False, degenerate triangles are removed, making the algorithm + about twice as slow. use_classic : bool If given and True, the classic marching cubes by Lorensen (1987) is used. This option is included for reference purposes. Note @@ -80,7 +84,7 @@ def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), raise ValueError('Input volume should be a 3D numpy array.') if volume.shape[0] < 2 or volume.shape[1] < 2 or volume.shape[2] < 2: raise ValueError("Input array must be at least 2x2x2.") - volume = np.array(volume, dtype=np.float32, order="C", copy=False) + volume = np.ascontiguousarray(volume, np.float32) # no copy if not necessary # Check/convert other inputs: # level @@ -119,7 +123,11 @@ def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), if spacing != (1, 1, 1): vertices = vertices * np.r_[spacing] - return vertices, faces, normals, values + if allow_degenerate: + return vertices, faces, normals, values + else: + fun = _marching_cubes_lewiner_cy.remove_degenerate_faces + return fun(vertices, faces, normals, values) def _toArray(args): diff --git a/skimage/measure/_marching_cubes_lewiner_cy.pyx b/skimage/measure/_marching_cubes_lewiner_cy.pyx index 04fe49f2..d1aa2280 100644 --- a/skimage/measure/_marching_cubes_lewiner_cy.pyx +++ b/skimage/measure/_marching_cubes_lewiner_cy.pyx @@ -1,6 +1,11 @@ # -*- coding: utf-8 -*- # Copyright (C) 2012, Almar Klein # Copyright (C) 2002, Thomas Lewiner +# +#cython: cdivision=True +#cython: boundscheck=False +#cython: nonecheck=False +#cython: wraparound=False """ This is an implementation of the marching cubes algorithm proposed in: @@ -43,11 +48,55 @@ cdef double FLT_EPSILON = np.spacing(1.0) #0.0000001 # Define abs function for doubles cdef inline double dabs(double a): return a if a>=0 else -a - +cdef inline int imin(int a, int b): return a if a0]]] + vertices2 = vertices[vertices_ok] + arrays2 = [arr[vertices_ok] for arr in arrays] + + return (vertices2, faces2) + tuple(arrays2) + cdef class Cell: """ Class to keep track of some stuff during the whole cube marching @@ -449,7 +498,6 @@ cdef class Cell: vi = lut.get3(lutIndex, lutIndex2, i*3+j) self._add_face_from_edge_index(vi) - ## Used internally cdef void _add_face_from_edge_index(self, int vi): @@ -505,6 +553,8 @@ cdef class Cell: tmpf1 = 1.0 / (FLT_EPSILON + dabs(self.vv[index1])) tmpf2 = 1.0 / (FLT_EPSILON + dabs(self.vv[index2])) + # print('indexInVertexArray', self.x, self.y, self.z, '-', vi, indexInVertexArray, indexInFaceLayer) + if indexInVertexArray >= 0: # Vertex already calculated, only need to add face and gradient self.add_face(indexInVertexArray) @@ -516,6 +566,7 @@ cdef class Cell: fx, fy, fz, ff = 0.0, 0.0, 0.0, 0.0 fx += dx1 * tmpf1; fy += dy1 * tmpf1; fz += dz1 * tmpf1; ff += tmpf1 fx += dx2 * tmpf2; fy += dy2 * tmpf2; fz += dz2 * tmpf2; ff += tmpf2 + # Add vertex indexInVertexArray = self.add_vertex( self.x + stp*fx/ff, @@ -550,7 +601,7 @@ cdef class Cell: This method returns -1 if no vertex has been defined yet. - vertices edes edge-indices per cell + vertices edges edge-indices per cell * 7 ________ 6 _____6__ ________ * /| /| 7/| /| /| /| * / | / | / | /5 | / | / | @@ -560,7 +611,7 @@ cdef class Cell: * | / | / 8 3/ 9 / 2 / | / * | / | / | / | /1 | 1 | / * |/_______|/ |/___0___|/ |/___0___|/ - * 0 1 0 1 + * 0 1 */ """ @@ -590,8 +641,8 @@ cdef class Cell: elif vi == 3: # no step j = 1 - elif vi<12: - # four vertical edges + elif vi < 12: + # 4 vertical edges faceLayer = self.faceLayer1 j = 2 @@ -889,9 +940,6 @@ cdef class LutProvider: self.SUBCONFIG13 = Lut(SUBCONFIG13) - -@cython.boundscheck(False) -@cython.wraparound(False) def marching_cubes(im, double isovalue, LutProvider luts, int st=1, int classic=0): """ marching_cubes(im, double isovalue, LutProvider luts, int st=1, int classic=0) This is the main entry to apply marching cubes. From 9f843fa6195f0efe60e46cc404e1cb79d13075ac Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Wed, 20 Apr 2016 02:26:04 +0200 Subject: [PATCH 03/25] marching cubes tests --- skimage/measure/tests/test_marching_cubes.py | 84 +++++++++++++++++++- 1 file changed, 80 insertions(+), 4 deletions(-) diff --git a/skimage/measure/tests/test_marching_cubes.py b/skimage/measure/tests/test_marching_cubes.py index 0e3d77ec..491fedfc 100644 --- a/skimage/measure/tests/test_marching_cubes.py +++ b/skimage/measure/tests/test_marching_cubes.py @@ -2,16 +2,23 @@ import numpy as np from numpy.testing import assert_raises from skimage.draw import ellipsoid, ellipsoid_stats -from skimage.measure import (marching_cubes, mesh_surface_area, - correct_mesh_orientation) +from skimage.measure import (marching_cubes, marching_cubes_lewiner, + mesh_surface_area, correct_mesh_orientation) def test_marching_cubes_isotropic(): ellipsoid_isotropic = ellipsoid(6, 10, 16, levelset=True) _, surf = ellipsoid_stats(6, 10, 16) + + # Classic verts, faces = marching_cubes(ellipsoid_isotropic, 0.) surf_calc = mesh_surface_area(verts, faces) - + # Test within 1% tolerance for isotropic. Will always underestimate. + assert surf > surf_calc and surf_calc > surf * 0.99 + + # Lewiner + verts, faces, *_ = marching_cubes_lewiner(ellipsoid_isotropic, 0.) + surf_calc = mesh_surface_area(verts, faces) # Test within 1% tolerance for isotropic. Will always underestimate. assert surf > surf_calc and surf_calc > surf * 0.99 @@ -21,20 +28,36 @@ def test_marching_cubes_anisotropic(): ellipsoid_anisotropic = ellipsoid(6, 10, 16, spacing=spacing, levelset=True) _, surf = ellipsoid_stats(6, 10, 16) + + # Classic verts, faces = marching_cubes(ellipsoid_anisotropic, 0., spacing=spacing) surf_calc = mesh_surface_area(verts, faces) - + # Test within 1.5% tolerance for anisotropic. Will always underestimate. + assert surf > surf_calc and surf_calc > surf * 0.985 + + # Lewiner + verts, faces, *_ = marching_cubes_lewiner(ellipsoid_anisotropic, 0., + spacing=spacing) + surf_calc = mesh_surface_area(verts, faces) # Test within 1.5% tolerance for anisotropic. Will always underestimate. assert surf > surf_calc and surf_calc > surf * 0.985 def test_invalid_input(): + # Classic assert_raises(ValueError, marching_cubes, np.zeros((2, 2, 1)), 0) assert_raises(ValueError, marching_cubes, np.zeros((2, 2, 1)), 1) assert_raises(ValueError, marching_cubes, np.ones((3, 3, 3)), 1, spacing=(1, 2)) assert_raises(ValueError, marching_cubes, np.zeros((20, 20)), 0) + + # Lewiner + assert_raises(ValueError, marching_cubes_lewiner, np.zeros((2, 2, 1)), 0) + assert_raises(ValueError, marching_cubes_lewiner, np.zeros((2, 2, 1)), 1) + assert_raises(ValueError, marching_cubes_lewiner, np.ones((3, 3, 3)), 1, + spacing=(1, 2)) + assert_raises(ValueError, marching_cubes_lewiner, np.zeros((20, 20)), 0) def test_correct_mesh_orientation(): @@ -74,5 +97,58 @@ def test_correct_mesh_orientation(): np.testing.assert_array_equal(expected, corrected_faces1) +def test_both_algs_same_result_ellipse(): + # Performing this test on data that does not have ambiguities + + sphere_small = ellipsoid(1, 1, 1, levelset=True) + + vertices1, faces1, *_ = marching_cubes(sphere_small, 0) + vertices2, faces2, *_ = marching_cubes_lewiner(sphere_small, 0, allow_degenerate=False) + vertices3, faces3, *_ = marching_cubes_lewiner(sphere_small, 0, allow_degenerate=False, use_classic=True) + + # Order id different, best we can do is test equal shape and same vertices present + assert _same_mesh(vertices1, faces1, vertices2, faces2) + assert _same_mesh(vertices1, faces1, vertices3, faces3) + + +def _same_mesh(vertices1, faces1, vertices2, faces2): + faces1 = [sorted(f) for f in faces1] + faces2 = [sorted(f) for f in faces2] + triangles1 = vertices1[np.array(faces1)] + triangles2 = vertices2[np.array(faces2)] + triang1 = set([tuple(t.flat) for t in triangles1]) + triang2 = set([tuple(t.flat) for t in triangles2]) + return triang1 == triang2 + + +def test_both_algs_same_result_donut(): + # Performing this test on data that does not have ambiguities + + n = 48 + a, b = 2.5/n, -1.25 + isovalue = 0.0 + # + vol = np.empty((n,n,n), 'float32') + for iz in range(vol.shape[0]): + for iy in range(vol.shape[1]): + for ix in range(vol.shape[2]): + z, y, x = float(iz)*a+b, float(iy)*a+b, float(ix)*a+b + vol[iz,iy,ix] = ( ( + (8*x)**2 + (8*y-2)**2 + (8*z)**2 + 16 - 1.85*1.85 ) * ( (8*x)**2 + + (8*y-2)**2 + (8*z)**2 + 16 - 1.85*1.85 ) - 64 * ( (8*x)**2 + (8*y-2)**2 ) + ) * ( ( (8*x)**2 + ((8*y-2)+4)*((8*y-2)+4) + (8*z)**2 + 16 - 1.85*1.85 ) + * ( (8*x)**2 + ((8*y-2)+4)*((8*y-2)+4) + (8*z)**2 + 16 - 1.85*1.85 ) - + 64 * ( ((8*y-2)+4)*((8*y-2)+4) + (8*z)**2 + ) ) + 1025 + + vertices1, faces1, *_ = marching_cubes(vol, 0) + vertices2, faces2, *_ = marching_cubes_lewiner(vol, 0) + vertices3, faces3, *_ = marching_cubes_lewiner(vol, 0, use_classic=True) + + assert not _same_mesh(vertices1, faces1, vertices2, faces2) + #assert _same_mesh(vertices1, faces1, vertices3, faces3) # would have been nice + assert not _same_mesh(vertices2, faces2, vertices3, faces3) + + if __name__ == '__main__': np.testing.run_module_suite() From f4c4822f8cd10ad1c11ee1b01e039bebff3dd1d5 Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Wed, 20 Apr 2016 02:27:29 +0200 Subject: [PATCH 04/25] remove unnecessary line WTF --- skimage/measure/_marching_cubes.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/skimage/measure/_marching_cubes.py b/skimage/measure/_marching_cubes.py index 46d50c7c..0bf2f46a 100644 --- a/skimage/measure/_marching_cubes.py +++ b/skimage/measure/_marching_cubes.py @@ -130,9 +130,6 @@ def marching_cubes(volume, level, spacing=(1., 1., 1.), verts = np.asarray(verts) faces = np.asarray(faces) - # Calculate gradient of `volume`, then interpolate to vertices in `verts` - grad_x, grad_y, grad_z = np.gradient(volume) - # Fancy indexing to define two vector arrays from triangle vertices faces = _correct_mesh_orientation(volume, verts[faces], faces, spacing, gradient_direction) From dc784a619de51b2843f93340092e198e83b66000 Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Wed, 20 Apr 2016 02:30:33 +0200 Subject: [PATCH 05/25] tweaks to original mc function (docs and level) --- skimage/measure/_marching_cubes.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/skimage/measure/_marching_cubes.py b/skimage/measure/_marching_cubes.py index 0bf2f46a..a761ece4 100644 --- a/skimage/measure/_marching_cubes.py +++ b/skimage/measure/_marching_cubes.py @@ -4,17 +4,18 @@ from .._shared.utils import warn from . import _marching_cubes_cy -def marching_cubes(volume, level, spacing=(1., 1., 1.), +def marching_cubes(volume, level=None, spacing=(1., 1., 1.), gradient_direction='descent'): """ - Marching cubes algorithm to find iso-valued surfaces in 3d volumetric data + Classic marching cubes algorithm to find surfaces in 3d volumetric data Parameters ---------- volume : (M, N, P) array of doubles Input data volume to find isosurfaces. Will be cast to `np.float64`. level : float - Contour value to search for isosurfaces in `volume`. + Contour value to search for isosurfaces in `volume`. If not + given or None, the average of the min and max of vol is used. spacing : length-3 tuple of floats Voxel spacing in spatial dimensions corresponding to numpy array indexing dimensions (M, N, P) as in `volume`. @@ -108,8 +109,12 @@ def marching_cubes(volume, level, spacing=(1., 1., 1.), # Check inputs and ensure `volume` is C-contiguous for memoryviews if volume.ndim != 3: raise ValueError("Input volume must have 3 dimensions.") - if level < volume.min() or level > volume.max(): - raise ValueError("Contour level must be within volume data range.") + if level is None: + level = 0.5 * (volume.min() + volume.max()) + else: + level = float(level) + if level < volume.min() or level > volume.max(): + raise ValueError("Surface level must be within volume data range.") if len(spacing) != 3: raise ValueError("`spacing` must consist of three floats.") From 19740b0ff9ed40ffc87fa399d602cb922071cd11 Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Wed, 20 Apr 2016 02:37:14 +0200 Subject: [PATCH 06/25] add not how to show mc surface in visvis --- skimage/measure/_marching_cubes.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/skimage/measure/_marching_cubes.py b/skimage/measure/_marching_cubes.py index a761ece4..09332d1c 100644 --- a/skimage/measure/_marching_cubes.py +++ b/skimage/measure/_marching_cubes.py @@ -83,17 +83,24 @@ def marching_cubes(volume, level=None, spacing=(1., 1., 1.), To quantify the area of an isosurface generated by this algorithm, pass outputs directly into `skimage.measure.mesh_surface_area`. - Regarding visualization of algorithm output, the ``mayavi`` package - is recommended. To contour a volume named `myvolume` about the level 0.0:: + Regarding visualization of algorithm output, to contour a volume + named `myvolume` about the level 0.0, using the ``mayavi`` package:: >>> from mayavi import mlab # doctest: +SKIP - >>> verts, faces = marching_cubes(myvolume, 0.0, (1., 1., 2.)) # doctest: +SKIP + >>> verts, faces = marching_cubes(myvolume, 0.0) # doctest: +SKIP >>> mlab.triangular_mesh([vert[0] for vert in verts], ... [vert[1] for vert in verts], ... [vert[2] for vert in verts], ... faces) # doctest: +SKIP >>> mlab.show() # doctest: +SKIP - + + Similarly using the ``visvis`` package:: + + >>> import visvis as vv # doctest: +SKIP + >>> verts, faces = marching_cubes(myvolume, 0.0) # doctest: +SKIP + >>> vv.mesh(np.fliplr(verts), faces) # doctest: +SKIP + >>> vv.use().Run() # doctest: +SKIP + References ---------- .. [1] Lorensen, William and Harvey E. Cline. Marching Cubes: A High From b954ba5024717aea8a1be6d0657d576e3d7ccb33 Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Wed, 20 Apr 2016 02:41:09 +0200 Subject: [PATCH 07/25] add extra materials related to lewiner mc algorithm --- skimage/measure/mc_meta/LookUpTable.h | 2322 +++++++++++++++++++++ skimage/measure/mc_meta/MarchingCubes.cpp | 1302 ++++++++++++ skimage/measure/mc_meta/createluts.py | 175 ++ skimage/measure/mc_meta/visual_test.py | 64 + 4 files changed, 3863 insertions(+) create mode 100644 skimage/measure/mc_meta/LookUpTable.h create mode 100644 skimage/measure/mc_meta/MarchingCubes.cpp create mode 100644 skimage/measure/mc_meta/createluts.py create mode 100644 skimage/measure/mc_meta/visual_test.py diff --git a/skimage/measure/mc_meta/LookUpTable.h b/skimage/measure/mc_meta/LookUpTable.h new file mode 100644 index 00000000..55293469 --- /dev/null +++ b/skimage/measure/mc_meta/LookUpTable.h @@ -0,0 +1,2322 @@ +/** + * @file LookUpTable.h + * @author Thomas Lewiner + * @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/skimage/measure/mc_meta/MarchingCubes.cpp b/skimage/measure/mc_meta/MarchingCubes.cpp new file mode 100644 index 00000000..d9012f04 --- /dev/null +++ b/skimage/measure/mc_meta/MarchingCubes.cpp @@ -0,0 +1,1302 @@ +/** + * @file MarchingCubes.cpp + * @author Thomas Lewiner + * @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 +#include +#include +#include +#include +#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/skimage/measure/mc_meta/createluts.py b/skimage/measure/mc_meta/createluts.py new file mode 100644 index 00000000..c6be213c --- /dev/null +++ b/skimage/measure/mc_meta/createluts.py @@ -0,0 +1,175 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2012, Almar Klein + +""" Create lookup tables for the marching cubes algorithm, by parsing +the file "LookUpTable.h". This prints a text to the stdout wich +can then be copied to luts.py. + +The luts are tuples of shape and base64 encoded bytes. + +""" + +import numpy as np +import sys +import base64 + +# Get base64 encode/decode functions +PY3 = sys.version_info[0] == 3 +if PY3: + base64encode = base64.encodebytes + base64decode = base64.decodebytes +else: + base64encode = base64.encodestring + base64decode = base64.decodestring + +def create_luts(fname): + + # Get the lines in the C header file + text = open(fname,'rb').read().decode('utf-8') + lines1 = [line.rstrip() for line in text.splitlines()] + + # Init lines for Python + lines2 = [] + + # Get classic table + more_lines, ii = get_table(lines1, 'static const char casesClassic', 0) + lines2.extend(more_lines) + + # Get cases table + more_lines, ii = get_table(lines1, 'static const char cases', 0) + lines2.extend(more_lines) + + # Get tiling tables + ii = 0 + for casenr in range(99): + # Get table + more_lines, ii = get_table(lines1, 'static const char tiling', ii+1) + if ii < 0: + break + else: + lines2.extend(more_lines) + + # Get test tables + ii = 0 + for casenr in range(99): + # Get table + more_lines, ii = get_table(lines1, 'static const char test', ii+1) + if ii < 0: + break + else: + lines2.extend(more_lines) + + # Get subconfig tables + ii = 0 + for casenr in range(99): + # Get table + more_lines, ii = get_table(lines1, 'static const char subconfig', ii+1) + if ii < 0: + break + else: + lines2.extend(more_lines) + + return '\n'.join(lines2) + + +def get_table(lines1, needle, i): + + # Try to find the start + ii = search_line(lines1, needle, i) + if ii < 0: + return [], -1 + + # Init result + lines2 = [] + + # Get size and name + front, dummu, back = lines1[ii].partition('[') + name = front.split(' ')[-1].upper() + size = int(back.split(']',1)[0]) + cdes = lines1[ii].rstrip(' {=') + + # Write name + lines2.append('%s = np.array([' % name) + + # Get elements + for i in range(ii+1, ii+1+9999999): + line1 = lines1[i] + front, dummy, back = line1.partition('*/') + if not back: + front, back = back, front + line2 = ' ' + line2 += back.strip().replace('{', '[').replace('}',']').replace(';','') + line2 += front.replace('/*',' #').rstrip() + lines2.append(line2) + if line1.endswith('};'): + break + + # Close and return + lines2.append(" , 'int8')") + lines2.append('') + #return lines2, ii+size + + # Execute code and get array as base64 text + code = '\n'.join(lines2) + code = code.split('=',1)[1] + array = eval(code) + array64 = base64encode(array.tostring()).decode('utf-8') + # Reverse: bytes = base64decode(text.encode('utf-8')) + text = '%s = %s, """\n%s"""' % (name, str(array.shape), array64) + + # Build actual lines + lines2 = [] + #lines2.append( '# %s -> %s %s' % (cdes, str(array.dtype), str(array.shape)) ) + lines2.append( '#' + cdes) + lines2.append(text) + lines2.append('') + return lines2, ii+size + + +def search_line(lines, refline, start=0): + for i, line in enumerate(lines[start:]): + if line.startswith(refline): + return i + start + return -1 + + + +def getLutNames(prefix): + aa = [] + for a in dir(luts): + if a.startswith(prefix): aa.append(a) + + def sortkey(x): + fullnr = x.split(prefix)[1] + nr, us, subnr = fullnr.partition('_') + if len(nr) == 1: + nr = '0'+nr + return nr + us + subnr + + return [a for a in sorted(aa, key=sortkey)] + + + +if __name__ == '__main__': + import os + fname = os.path.join(os.getcwd(), 'LookUpTable.h') + + if True: + with open(os.path.join(os.getcwd(), 'mcluts.py'), 'w') as f: + f.write('# -*- coding: utf-8 -*-\n') + f.write('# Copyright (C) 2012, Almar Klein\n# Copyright (C) 2002, Thomas Lewiner\n\n') + f.write('# This file was auto-generated from LookUpTable.h by createluts.py.\n\n') + f.write(create_luts(fname)) + + else: + for prefix in ['TILING', 'TEST']: + tmp = ['luts.'+a for a in getLutNames(prefix)] + print(', '.join(tmp)) + print('') + for name in getLutNames(prefix): + print('self.%s = Lut(%s)' % (name, name)) + print('') + for name in getLutNames(prefix): + print('cdef Lut %s' % name) + print('') + print('') diff --git a/skimage/measure/mc_meta/visual_test.py b/skimage/measure/mc_meta/visual_test.py new file mode 100644 index 00000000..ae8c0bfb --- /dev/null +++ b/skimage/measure/mc_meta/visual_test.py @@ -0,0 +1,64 @@ +""" +Script to show the results of the two marching cubes algorithms on different +data. +""" + +import time + +import numpy as np +import visvis as vv + +from skimage.measure import marching_cubes, marching_cubes_lewiner + + +# Create test volume +SELECT = 1 + +if SELECT == 1: + # Medical data + vol = vv.volread('stent') + isovalue = 800 + +elif SELECT == 2: + # Blocky data + vol = vv.aVolume(20, 128) # Different every time + isovalue = 0.2 + +elif SELECT == 3: + # Generate two donuts + n = 48 + a, b = 2.5/n, -1.25 + isovalue = 0.0 + # + vol = np.empty((n,n,n), 'float32') + for iz in range(vol.shape[0]): + for iy in range(vol.shape[1]): + for ix in range(vol.shape[2]): + z, y, x = float(iz)*a+b, float(iy)*a+b, float(ix)*a+b + vol[iz,iy,ix] = ( ( + (8*x)**2 + (8*y-2)**2 + (8*z)**2 + 16 - 1.85*1.85 ) * ( (8*x)**2 + + (8*y-2)**2 + (8*z)**2 + 16 - 1.85*1.85 ) - 64 * ( (8*x)**2 + (8*y-2)**2 ) + ) * ( ( (8*x)**2 + ((8*y-2)+4)*((8*y-2)+4) + (8*z)**2 + 16 - 1.85*1.85 ) + * ( (8*x)**2 + ((8*y-2)+4)*((8*y-2)+4) + (8*z)**2 + 16 - 1.85*1.85 ) - + 64 * ( ((8*y-2)+4)*((8*y-2)+4) + (8*z)**2 + ) ) + 1025 + # Uncommenting the line below will yield different results for classic MC + #vol = -vol + +# Get surface meshes +t0 = time.time() +vertices1, faces1, *_ = marching_cubes_lewiner(vol, isovalue, use_classic=False) +print('finding surface lewiner took %1.0f ms' % (1000*(time.time()-t0)) ) + +t0 = time.time() +vertices2, faces2, *_ = marching_cubes(vol, isovalue) +print('finding surface classic took %1.0f ms' % (1000*(time.time()-t0)) ) + +# Show +vv.figure(1); vv.clf() +a1 = vv.subplot(121); vv.mesh(np.fliplr(vertices1), faces1) +a2 = vv.subplot(122); vv.mesh(np.fliplr(vertices2), faces2) +a1.camera = a2.camera + + +vv.use().Run() From 8275ac07c20d2fa6a4bc5b8ed530876767640206 Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Fri, 20 May 2016 09:11:38 +0200 Subject: [PATCH 08/25] add mc lewiner to bento.info --- bento.info | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bento.info b/bento.info index 0dad510e..5597045c 100644 --- a/bento.info +++ b/bento.info @@ -53,6 +53,9 @@ Library: Extension: skimage.measure._marching_cubes_cy Sources: skimage/measure/_marching_cubes_cy.pyx + Extension: skimage.measure._marching_cubes_lewiner_cy + Sources: + skimage/measure/_marching_cubes_lewiner_cy.pyx Extension: skimage.graph._mcp Sources: skimage/graph/_mcp.pyx From f4f05107e7f13bcbe5749f7531fd31580c571ed1 Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Fri, 20 May 2016 10:16:42 +0200 Subject: [PATCH 09/25] add gradient_direction arg to lewiner mc algorithm --- skimage/measure/_marching_cubes_lewiner.py | 22 ++++++++++++++++---- skimage/measure/mc_meta/visual_test.py | 18 +++++++++++----- skimage/measure/tests/test_marching_cubes.py | 12 +++++------ 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/skimage/measure/_marching_cubes_lewiner.py b/skimage/measure/_marching_cubes_lewiner.py index 537395f2..f105b4b3 100644 --- a/skimage/measure/_marching_cubes_lewiner.py +++ b/skimage/measure/_marching_cubes_lewiner.py @@ -14,7 +14,8 @@ from . import _marching_cubes_lewiner_cy def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), - step_size=1, allow_degenerate=True, use_classic=False): + gradient_direction='descent', step_size=1, + allow_degenerate=True, use_classic=False): """ Lewiner marching cubes algorithm to find surfaces in 3d volumetric data @@ -31,14 +32,21 @@ def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), spacing : length-3 tuple of floats Voxel spacing in spatial dimensions corresponding to numpy array indexing dimensions (M, N, P) as in `volume`. + gradient_direction : string + Controls if the mesh was generated from an isosurface with gradient + descent toward objects of interest (the default), or the opposite, + considering the *left-hand* rule. + The two options are: + * descent : Object was greater than exterior + * ascent : Exterior was greater than object step_size : int Step size in voxels. Default 1. Larger steps yield faster but coarser results. The result will always be topologically correct though. allow_degenerate : bool - Whether to allow degenerate triangles in the end-result. Default True. - If False, degenerate triangles are removed, making the algorithm - about twice as slow. + Whether to allow degenerate (i.e. zero-area) triangles in the + end-result. Default True. If False, degenerate triangles are + removed, at the cost of making the algorithm slower. use_classic : bool If given and True, the classic marching cubes by Lorensen (1987) is used. This option is included for reference purposes. Note @@ -120,6 +128,12 @@ def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), # Finishing touches to output faces.shape = -1, 3 + if gradient_direction == 'descent': + # MC implementation is right-handed, but gradient_direction is left-handed + faces = np.fliplr(faces) + elif not gradient_direction == 'ascent': + raise ValueError("Incorrect input %s in `gradient_direction`, see " + "docstring." % (gradient_direction)) if spacing != (1, 1, 1): vertices = vertices * np.r_[spacing] diff --git a/skimage/measure/mc_meta/visual_test.py b/skimage/measure/mc_meta/visual_test.py index ae8c0bfb..7a8ea699 100644 --- a/skimage/measure/mc_meta/visual_test.py +++ b/skimage/measure/mc_meta/visual_test.py @@ -9,10 +9,12 @@ import numpy as np import visvis as vv from skimage.measure import marching_cubes, marching_cubes_lewiner +from skimage.draw import ellipsoid # Create test volume -SELECT = 1 +SELECT = 4 +gradient_dir = 'descent' # ascent or descent if SELECT == 1: # Medical data @@ -45,20 +47,26 @@ elif SELECT == 3: # Uncommenting the line below will yield different results for classic MC #vol = -vol +elif SELECT == 4: + vol = ellipsoid(4, 3, 2, levelset=True) + isovalue = 0 + # Get surface meshes t0 = time.time() -vertices1, faces1, *_ = marching_cubes_lewiner(vol, isovalue, use_classic=False) +vertices1, faces1, *_ = marching_cubes_lewiner(vol, isovalue, gradient_direction=gradient_dir, use_classic=False) print('finding surface lewiner took %1.0f ms' % (1000*(time.time()-t0)) ) t0 = time.time() -vertices2, faces2, *_ = marching_cubes(vol, isovalue) +vertices2, faces2, *_ = marching_cubes(vol, isovalue, gradient_direction=gradient_dir) print('finding surface classic took %1.0f ms' % (1000*(time.time()-t0)) ) # Show vv.figure(1); vv.clf() -a1 = vv.subplot(121); vv.mesh(np.fliplr(vertices1), faces1) -a2 = vv.subplot(122); vv.mesh(np.fliplr(vertices2), faces2) +a1 = vv.subplot(121); m1 = vv.mesh(np.fliplr(vertices1), faces1) +a2 = vv.subplot(122); m2 = vv.mesh(np.fliplr(vertices2), faces2) a1.camera = a2.camera +# visvis uses right-hand rule, gradient_direction param uses left-hand rule +m1.cullFaces = m2.cullFaces = 'front' # None, front or back vv.use().Run() diff --git a/skimage/measure/tests/test_marching_cubes.py b/skimage/measure/tests/test_marching_cubes.py index 491fedfc..4d62abe0 100644 --- a/skimage/measure/tests/test_marching_cubes.py +++ b/skimage/measure/tests/test_marching_cubes.py @@ -106,21 +106,21 @@ def test_both_algs_same_result_ellipse(): vertices2, faces2, *_ = marching_cubes_lewiner(sphere_small, 0, allow_degenerate=False) vertices3, faces3, *_ = marching_cubes_lewiner(sphere_small, 0, allow_degenerate=False, use_classic=True) - # Order id different, best we can do is test equal shape and same vertices present + # Order is different, best we can do is test equal shape and same vertices present assert _same_mesh(vertices1, faces1, vertices2, faces2) assert _same_mesh(vertices1, faces1, vertices3, faces3) def _same_mesh(vertices1, faces1, vertices2, faces2): - faces1 = [sorted(f) for f in faces1] - faces2 = [sorted(f) for f in faces2] + rounder = lambda x: int(x*1000)/1000 # to take into account small variations triangles1 = vertices1[np.array(faces1)] triangles2 = vertices2[np.array(faces2)] - triang1 = set([tuple(t.flat) for t in triangles1]) - triang2 = set([tuple(t.flat) for t in triangles2]) + triang1 = [np.concatenate(sorted(t, key=lambda x:tuple(x))) for t in triangles1] + triang1 = set([tuple([rounder(i) for i in t]) for t in triang1]) + triang2 = [np.concatenate(sorted(t, key=lambda x:tuple(x))) for t in triangles2] + triang2 = set([tuple([rounder(i) for i in t]) for t in triang2]) return triang1 == triang2 - def test_both_algs_same_result_donut(): # Performing this test on data that does not have ambiguities From f44e55b36dd9b1ba47094881a15ca29d987cdba7 Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Fri, 20 May 2016 10:17:06 +0200 Subject: [PATCH 10/25] add readme to mc_mata dir --- skimage/measure/mc_meta/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 skimage/measure/mc_meta/README.md diff --git a/skimage/measure/mc_meta/README.md b/skimage/measure/mc_meta/README.md new file mode 100644 index 00000000..b6b8978e --- /dev/null +++ b/skimage/measure/mc_meta/README.md @@ -0,0 +1,8 @@ +This directory contains meta-files related to the Lewiner marching cubes +algorithm. These are not used by the algorithm, but can be convenient +for development/maintenance: + +* MarchingCubes.cpp - the original algorithm, this is ported to Cython +* LookupTable.h - the original LUTs, these are ported to Python +* createluts.py - scrip to generate Python luts from the .h file +* visual_test.py - script to compare visual results of marchingcubes algorithms From 41857a073632f1e9a7dcb1ca7a8df324006a3b9c Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Fri, 20 May 2016 13:45:12 +0200 Subject: [PATCH 11/25] address Stefans comments --- CONTRIBUTORS.txt | 3 +- skimage/measure/_marching_cubes.py | 4 +- skimage/measure/_marching_cubes_lewiner.py | 65 ++++++++++--------- .../measure/_marching_cubes_lewiner_cy.pyx | 11 ++-- .../measure/_marching_cubes_lewiner_luts.py | 3 +- skimage/measure/mc_meta/createluts.py | 1 - skimage/measure/mc_meta/visual_test.py | 2 +- skimage/measure/tests/test_marching_cubes.py | 21 ++++-- 8 files changed, 62 insertions(+), 48 deletions(-) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 44214d85..e4c852e6 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -35,7 +35,8 @@ and more. - Almar Klein - Binary heap class for graph algorithms + Binary heap class and other improvements for graph algorithms + Lewiner variant of marching cubes algorithm - Lee Kamentsky and Thouis Jones of the CellProfiler team, Broad Institute, MIT Constant time per pixel median filter, edge detectors, and more. diff --git a/skimage/measure/_marching_cubes.py b/skimage/measure/_marching_cubes.py index 09332d1c..476f4e39 100644 --- a/skimage/measure/_marching_cubes.py +++ b/skimage/measure/_marching_cubes.py @@ -109,9 +109,9 @@ def marching_cubes(volume, level=None, spacing=(1., 1., 1.), See Also -------- - skimage.measure.correct_mesh_orientation + skimage.measure.marching_cubes_lewiner skimage.measure.mesh_surface_area - + """ # Check inputs and ensure `volume` is C-contiguous for memoryviews if volume.ndim != 3: diff --git a/skimage/measure/_marching_cubes_lewiner.py b/skimage/measure/_marching_cubes_lewiner.py index f105b4b3..7f8339e5 100644 --- a/skimage/measure/_marching_cubes_lewiner.py +++ b/skimage/measure/_marching_cubes_lewiner.py @@ -24,8 +24,9 @@ def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), Parameters ---------- - volume : (M, N, P) array (the data is internally converted to - float32 if necessary) + volume : (M, N, P) array + Input data volume to find isosurfaces. Will internally be + converted to float32 if necessary. level : float Contour value to search for isosurfaces in `volume`. If not given or None, the average of the min and max of vol is used. @@ -73,18 +74,24 @@ def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), Notes about the algorithm ------------------------- - This is an implementation of: - - Efficient implementation of Marching Cubes' cases with - topological guarantees. Thomas Lewiner, Helio Lopes, Antonio - Wilson Vieira and Geovan Tavares. Journal of Graphics Tools - 8(2): pp. 1-15 (december 2003) - - The algorithm is an improved version of Chernyaev's Marching Cubes 33 + The algorithm [1] is an improved version of Chernyaev's Marching Cubes 33 algorithm, originally written in C++. It is an efficient algorithm that relies on heavy use of lookup tables to handle the many different cases. This keeps the algorithm relatively easy. The current algorithm is a port of Lewiner's algorithm and written in Cython. + + References + ---------- + .. [1] Thomas Lewiner, Helio Lopes, Antonio Wilson Vieira and Geovan + Tavares. Efficient implementation of Marching Cubes' cases with + topological guarantees. Journal of Graphics Tools 8(2) + pp. 1-15 (december 2003). + + See Also + -------- + skimage.measure.marching_cubes + skimage.measure.mesh_surface_area + """ # Check volume and ensure its in the format that the alg needs @@ -113,7 +120,7 @@ def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), use_classic = bool(use_classic) # Get LutProvider class (reuse if possible) - L = _getMCLuts() + L = _get_mc_luts() # Apply algorithm func = _marching_cubes_lewiner_cy.marching_cubes @@ -144,7 +151,7 @@ def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), return fun(vertices, faces, normals, values) -def _toArray(args): +def _to_array(args): shape, text = args byts = base64decode(text.encode('utf-8')) ar = np.frombuffer(byts, dtype='int8') @@ -163,7 +170,7 @@ EDGETORELATIVEPOSY = np.array([ [0,0],[0,1],[1,1],[1,0], [0,0],[0,1],[1,1],[1,0] EDGETORELATIVEPOSZ = np.array([ [0,0],[0,0],[0,0],[0,0], [1,1],[1,1],[1,1],[1,1], [0,1],[0,1],[0,1],[0,1] ], 'int8') -def _getMCLuts(): +def _get_mc_luts(): """ Kind of lazy obtaining of the luts. """ if not hasattr(mcluts, 'THE_LUTS'): @@ -171,24 +178,24 @@ def _getMCLuts(): mcluts.THE_LUTS = _marching_cubes_lewiner_cy.LutProvider( EDGETORELATIVEPOSX, EDGETORELATIVEPOSY, EDGETORELATIVEPOSZ, - _toArray(mcluts.CASESCLASSIC), _toArray(mcluts.CASES), + _to_array(mcluts.CASESCLASSIC), _to_array(mcluts.CASES), - _toArray(mcluts.TILING1), _toArray(mcluts.TILING2), _toArray(mcluts.TILING3_1), _toArray(mcluts.TILING3_2), - _toArray(mcluts.TILING4_1), _toArray(mcluts.TILING4_2), _toArray(mcluts.TILING5), _toArray(mcluts.TILING6_1_1), - _toArray(mcluts.TILING6_1_2), _toArray(mcluts.TILING6_2), _toArray(mcluts.TILING7_1), - _toArray(mcluts.TILING7_2), _toArray(mcluts.TILING7_3), _toArray(mcluts.TILING7_4_1), - _toArray(mcluts.TILING7_4_2), _toArray(mcluts.TILING8), _toArray(mcluts.TILING9), - _toArray(mcluts.TILING10_1_1), _toArray(mcluts.TILING10_1_1_), _toArray(mcluts.TILING10_1_2), - _toArray(mcluts.TILING10_2), _toArray(mcluts.TILING10_2_), _toArray(mcluts.TILING11), - _toArray(mcluts.TILING12_1_1), _toArray(mcluts.TILING12_1_1_), _toArray(mcluts.TILING12_1_2), - _toArray(mcluts.TILING12_2), _toArray(mcluts.TILING12_2_), _toArray(mcluts.TILING13_1), - _toArray(mcluts.TILING13_1_), _toArray(mcluts.TILING13_2), _toArray(mcluts.TILING13_2_), - _toArray(mcluts.TILING13_3), _toArray(mcluts.TILING13_3_), _toArray(mcluts.TILING13_4), - _toArray(mcluts.TILING13_5_1), _toArray(mcluts.TILING13_5_2), _toArray(mcluts.TILING14), + _to_array(mcluts.TILING1), _to_array(mcluts.TILING2), _to_array(mcluts.TILING3_1), _to_array(mcluts.TILING3_2), + _to_array(mcluts.TILING4_1), _to_array(mcluts.TILING4_2), _to_array(mcluts.TILING5), _to_array(mcluts.TILING6_1_1), + _to_array(mcluts.TILING6_1_2), _to_array(mcluts.TILING6_2), _to_array(mcluts.TILING7_1), + _to_array(mcluts.TILING7_2), _to_array(mcluts.TILING7_3), _to_array(mcluts.TILING7_4_1), + _to_array(mcluts.TILING7_4_2), _to_array(mcluts.TILING8), _to_array(mcluts.TILING9), + _to_array(mcluts.TILING10_1_1), _to_array(mcluts.TILING10_1_1_), _to_array(mcluts.TILING10_1_2), + _to_array(mcluts.TILING10_2), _to_array(mcluts.TILING10_2_), _to_array(mcluts.TILING11), + _to_array(mcluts.TILING12_1_1), _to_array(mcluts.TILING12_1_1_), _to_array(mcluts.TILING12_1_2), + _to_array(mcluts.TILING12_2), _to_array(mcluts.TILING12_2_), _to_array(mcluts.TILING13_1), + _to_array(mcluts.TILING13_1_), _to_array(mcluts.TILING13_2), _to_array(mcluts.TILING13_2_), + _to_array(mcluts.TILING13_3), _to_array(mcluts.TILING13_3_), _to_array(mcluts.TILING13_4), + _to_array(mcluts.TILING13_5_1), _to_array(mcluts.TILING13_5_2), _to_array(mcluts.TILING14), - _toArray(mcluts.TEST3), _toArray(mcluts.TEST4), _toArray(mcluts.TEST6), - _toArray(mcluts.TEST7), _toArray(mcluts.TEST10), _toArray(mcluts.TEST12), - _toArray(mcluts.TEST13), _toArray(mcluts.SUBCONFIG13), + _to_array(mcluts.TEST3), _to_array(mcluts.TEST4), _to_array(mcluts.TEST6), + _to_array(mcluts.TEST7), _to_array(mcluts.TEST10), _to_array(mcluts.TEST12), + _to_array(mcluts.TEST13), _to_array(mcluts.SUBCONFIG13), ) return mcluts.THE_LUTS diff --git a/skimage/measure/_marching_cubes_lewiner_cy.pyx b/skimage/measure/_marching_cubes_lewiner_cy.pyx index d1aa2280..b37fb718 100644 --- a/skimage/measure/_marching_cubes_lewiner_cy.pyx +++ b/skimage/measure/_marching_cubes_lewiner_cy.pyx @@ -1,6 +1,4 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012, Almar Klein -# Copyright (C) 2002, Thomas Lewiner # #cython: cdivision=True #cython: boundscheck=False @@ -14,11 +12,12 @@ Efficient implementation of Marching Cubes' cases with topological guarantees. Thomas Lewiner, Helio Lopes, Antonio Wilson Vieira and Geovan Tavares. Journal of Graphics Tools 8(2): pp. 1-15 (december 2003) -I selected this algorithm because it provides topologically correct results, -and because the algorithms implementation is relatively simple. Most of -the magic is in the lookup tables, which are provided as open source. +This algorithm has the advantage that it provides topologically correct +results, and the algorithms implementation is relatively simple. Most +of the magic is in the lookup tables, which are provided as open source. -This code is distributed under the terms of the (new) BSD License. +Originally implemented in C++ by Thomas Lewiner in 2002, ported to Cython +by Almar Klein in 2012. Adapted for scikit-image in 2016. """ diff --git a/skimage/measure/_marching_cubes_lewiner_luts.py b/skimage/measure/_marching_cubes_lewiner_luts.py index 59243662..07fb5728 100644 --- a/skimage/measure/_marching_cubes_lewiner_luts.py +++ b/skimage/measure/_marching_cubes_lewiner_luts.py @@ -1,8 +1,7 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012, Almar Klein -# Copyright (C) 2002, Thomas Lewiner # This file was auto-generated from LookUpTable.h by createluts.py. +# The luts are Copyright (C) 2002 by Thomas Lewiner #static const char casesClassic[256][16] CASESCLASSIC = (256, 16), """ diff --git a/skimage/measure/mc_meta/createluts.py b/skimage/measure/mc_meta/createluts.py index c6be213c..670a27c8 100644 --- a/skimage/measure/mc_meta/createluts.py +++ b/skimage/measure/mc_meta/createluts.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012, Almar Klein """ Create lookup tables for the marching cubes algorithm, by parsing the file "LookUpTable.h". This prints a text to the stdout wich diff --git a/skimage/measure/mc_meta/visual_test.py b/skimage/measure/mc_meta/visual_test.py index 7a8ea699..e8b7e717 100644 --- a/skimage/measure/mc_meta/visual_test.py +++ b/skimage/measure/mc_meta/visual_test.py @@ -13,7 +13,7 @@ from skimage.draw import ellipsoid # Create test volume -SELECT = 4 +SELECT = 3 gradient_dir = 'descent' # ascent or descent if SELECT == 1: diff --git a/skimage/measure/tests/test_marching_cubes.py b/skimage/measure/tests/test_marching_cubes.py index 4d62abe0..25262682 100644 --- a/skimage/measure/tests/test_marching_cubes.py +++ b/skimage/measure/tests/test_marching_cubes.py @@ -111,15 +111,21 @@ def test_both_algs_same_result_ellipse(): assert _same_mesh(vertices1, faces1, vertices3, faces3) -def _same_mesh(vertices1, faces1, vertices2, faces2): - rounder = lambda x: int(x*1000)/1000 # to take into account small variations +def _same_mesh(vertices1, faces1, vertices2, faces2, tol=1e-10): + """ Compare two meshes, using a certain tolerance and invariant to + the order of the faces. + """ + # Unwind vertices triangles1 = vertices1[np.array(faces1)] triangles2 = vertices2[np.array(faces2)] + # Sort vertices within each triangle triang1 = [np.concatenate(sorted(t, key=lambda x:tuple(x))) for t in triangles1] - triang1 = set([tuple([rounder(i) for i in t]) for t in triang1]) triang2 = [np.concatenate(sorted(t, key=lambda x:tuple(x))) for t in triangles2] - triang2 = set([tuple([rounder(i) for i in t]) for t in triang2]) - return triang1 == triang2 + # Sort the resulting 9-element "tuples" + triang1 = np.array(sorted([tuple(x) for x in triang1])) + triang2 = np.array(sorted([tuple(x) for x in triang2])) + return triang1.shape == triang2.shape and np.allclose(triang1, triang2, 0, tol) + def test_both_algs_same_result_donut(): # Performing this test on data that does not have ambiguities @@ -145,9 +151,12 @@ def test_both_algs_same_result_donut(): vertices2, faces2, *_ = marching_cubes_lewiner(vol, 0) vertices3, faces3, *_ = marching_cubes_lewiner(vol, 0, use_classic=True) + # Old and new alg are different assert not _same_mesh(vertices1, faces1, vertices2, faces2) - #assert _same_mesh(vertices1, faces1, vertices3, faces3) # would have been nice + # New classic and new Lewiner are different assert not _same_mesh(vertices2, faces2, vertices3, faces3) + # Would have been nice if old and new classic would have been the same + # assert _same_mesh(vertices1, faces1, vertices3, faces3, 5) if __name__ == '__main__': From ededdfaf56d6f7d07ae171310dc701601adec45f Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Wed, 25 May 2016 10:53:06 +0200 Subject: [PATCH 12/25] improve docs and acks related to new MC alg --- CONTRIBUTORS.txt | 3 +++ skimage/measure/_marching_cubes_lewiner.py | 14 ++++++++------ skimage/measure/mc_meta/visual_test.py | 4 ++-- skimage/measure/tests/test_marching_cubes.py | 1 + 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index e4c852e6..921a2b1b 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -230,6 +230,9 @@ - Alex Izvorski Color spaces for YUV and related spaces +- Thomas Lewiner + Design and original implementation of the Lewiner marching cubes algorithm + - Jeff Hemmelgarn Minimum threshold diff --git a/skimage/measure/_marching_cubes_lewiner.py b/skimage/measure/_marching_cubes_lewiner.py index 7f8339e5..ab5976af 100644 --- a/skimage/measure/_marching_cubes_lewiner.py +++ b/skimage/measure/_marching_cubes_lewiner.py @@ -52,7 +52,9 @@ def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), If given and True, the classic marching cubes by Lorensen (1987) is used. This option is included for reference purposes. Note that this algorithm has ambiguities and is not guaranteed to - produce a topologically correct result. + produce a topologically correct result. The results with using + this option are *not* generally the same as the ``marching_cubes()`` + function. Returns ------- @@ -74,11 +76,11 @@ def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), Notes about the algorithm ------------------------- - The algorithm [1] is an improved version of Chernyaev's Marching Cubes 33 - algorithm, originally written in C++. It is an efficient algorithm - that relies on heavy use of lookup tables to handle the many different - cases. This keeps the algorithm relatively easy. The current algorithm - is a port of Lewiner's algorithm and written in Cython. + The algorithm [1] is an improved version of Chernyaev's Marching + Cubes 33 algorithm. It is an efficient algorithm that relies on + heavy use of lookup tables to handle the many different cases, + keeping the algorithm relatively easy. This implementation is + written in Cython, ported from Lewiner's C++ implementation. References ---------- diff --git a/skimage/measure/mc_meta/visual_test.py b/skimage/measure/mc_meta/visual_test.py index e8b7e717..f04ade92 100644 --- a/skimage/measure/mc_meta/visual_test.py +++ b/skimage/measure/mc_meta/visual_test.py @@ -27,7 +27,7 @@ elif SELECT == 2: isovalue = 0.2 elif SELECT == 3: - # Generate two donuts + # Generate two donuts using a formula by Thomas Lewiner n = 48 a, b = 2.5/n, -1.25 isovalue = 0.0 @@ -53,7 +53,7 @@ elif SELECT == 4: # Get surface meshes t0 = time.time() -vertices1, faces1, *_ = marching_cubes_lewiner(vol, isovalue, gradient_direction=gradient_dir, use_classic=False) +vertices1, faces1, *_ = marching_cubes_lewiner(vol, isovalue, gradient_direction=gradient_dir, use_classic=True) print('finding surface lewiner took %1.0f ms' % (1000*(time.time()-t0)) ) t0 = time.time() diff --git a/skimage/measure/tests/test_marching_cubes.py b/skimage/measure/tests/test_marching_cubes.py index 25262682..e46a4207 100644 --- a/skimage/measure/tests/test_marching_cubes.py +++ b/skimage/measure/tests/test_marching_cubes.py @@ -138,6 +138,7 @@ def test_both_algs_same_result_donut(): for iz in range(vol.shape[0]): for iy in range(vol.shape[1]): for ix in range(vol.shape[2]): + # Double-torii formula by Thomas Lewiner z, y, x = float(iz)*a+b, float(iy)*a+b, float(ix)*a+b vol[iz,iy,ix] = ( ( (8*x)**2 + (8*y-2)**2 + (8*z)**2 + 16 - 1.85*1.85 ) * ( (8*x)**2 + From 72ba10d896241ed3b7294747d1286e0b8d76283f Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Wed, 25 May 2016 10:56:40 +0200 Subject: [PATCH 13/25] fix for legacy py --- skimage/measure/tests/test_marching_cubes.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/skimage/measure/tests/test_marching_cubes.py b/skimage/measure/tests/test_marching_cubes.py index e46a4207..c15d7d94 100644 --- a/skimage/measure/tests/test_marching_cubes.py +++ b/skimage/measure/tests/test_marching_cubes.py @@ -17,7 +17,7 @@ def test_marching_cubes_isotropic(): assert surf > surf_calc and surf_calc > surf * 0.99 # Lewiner - verts, faces, *_ = marching_cubes_lewiner(ellipsoid_isotropic, 0.) + verts, faces = marching_cubes_lewiner(ellipsoid_isotropic, 0.)[:2] surf_calc = mesh_surface_area(verts, faces) # Test within 1% tolerance for isotropic. Will always underestimate. assert surf > surf_calc and surf_calc > surf * 0.99 @@ -37,8 +37,7 @@ def test_marching_cubes_anisotropic(): assert surf > surf_calc and surf_calc > surf * 0.985 # Lewiner - verts, faces, *_ = marching_cubes_lewiner(ellipsoid_anisotropic, 0., - spacing=spacing) + verts, faces = marching_cubes_lewiner(ellipsoid_anisotropic, 0., spacing=spacing)[:2] surf_calc = mesh_surface_area(verts, faces) # Test within 1.5% tolerance for anisotropic. Will always underestimate. assert surf > surf_calc and surf_calc > surf * 0.985 @@ -102,9 +101,9 @@ def test_both_algs_same_result_ellipse(): sphere_small = ellipsoid(1, 1, 1, levelset=True) - vertices1, faces1, *_ = marching_cubes(sphere_small, 0) - vertices2, faces2, *_ = marching_cubes_lewiner(sphere_small, 0, allow_degenerate=False) - vertices3, faces3, *_ = marching_cubes_lewiner(sphere_small, 0, allow_degenerate=False, use_classic=True) + vertices1, faces1 = marching_cubes(sphere_small, 0)[:2] + vertices2, faces2 = marching_cubes_lewiner(sphere_small, 0, allow_degenerate=False)[:2] + vertices3, faces3 = marching_cubes_lewiner(sphere_small, 0, allow_degenerate=False, use_classic=True)[:2] # Order is different, best we can do is test equal shape and same vertices present assert _same_mesh(vertices1, faces1, vertices2, faces2) @@ -148,9 +147,9 @@ def test_both_algs_same_result_donut(): 64 * ( ((8*y-2)+4)*((8*y-2)+4) + (8*z)**2 ) ) + 1025 - vertices1, faces1, *_ = marching_cubes(vol, 0) - vertices2, faces2, *_ = marching_cubes_lewiner(vol, 0) - vertices3, faces3, *_ = marching_cubes_lewiner(vol, 0, use_classic=True) + vertices1, faces1 = marching_cubes(vol, 0)[:2] + vertices2, faces2 = marching_cubes_lewiner(vol, 0)[:2] + vertices3, faces3 = marching_cubes_lewiner(vol, 0, use_classic=True)[:2] # Old and new alg are different assert not _same_mesh(vertices1, faces1, vertices2, faces2) From 41ca298eb6eb1ff9003855b28ec7fced2f2f3ef7 Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Thu, 21 Jul 2016 15:12:33 +0200 Subject: [PATCH 14/25] MC: doc tweaks --- skimage/measure/_marching_cubes.py | 1 - skimage/measure/_marching_cubes_lewiner.py | 11 +++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/skimage/measure/_marching_cubes.py b/skimage/measure/_marching_cubes.py index 476f4e39..1a381c3c 100644 --- a/skimage/measure/_marching_cubes.py +++ b/skimage/measure/_marching_cubes.py @@ -111,7 +111,6 @@ def marching_cubes(volume, level=None, spacing=(1., 1., 1.), -------- skimage.measure.marching_cubes_lewiner skimage.measure.mesh_surface_area - """ # Check inputs and ensure `volume` is C-contiguous for memoryviews if volume.ndim != 3: diff --git a/skimage/measure/_marching_cubes_lewiner.py b/skimage/measure/_marching_cubes_lewiner.py index ab5976af..9df5134c 100644 --- a/skimage/measure/_marching_cubes_lewiner.py +++ b/skimage/measure/_marching_cubes_lewiner.py @@ -12,7 +12,6 @@ from . import _marching_cubes_lewiner_luts as mcluts from . import _marching_cubes_lewiner_cy - def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), gradient_direction='descent', step_size=1, allow_degenerate=True, use_classic=False): @@ -20,7 +19,9 @@ def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), Lewiner marching cubes algorithm to find surfaces in 3d volumetric data In contrast to ``marching_cubes()``, this algorithm resolves - ambiguities and guarantees topologically correct results. + ambiguities and guarantees topologically correct results. Therefore, + this algorithm generally a better choice, unless there is a specific + need for the classic algorithm. Parameters ---------- @@ -73,9 +74,8 @@ def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), near each vertex. This can be used by visualization tools to apply a colormap to the mesh. - Notes about the algorithm - ------------------------- - + Notes + ----- The algorithm [1] is an improved version of Chernyaev's Marching Cubes 33 algorithm. It is an efficient algorithm that relies on heavy use of lookup tables to handle the many different cases, @@ -93,7 +93,6 @@ def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), -------- skimage.measure.marching_cubes skimage.measure.mesh_surface_area - """ # Check volume and ensure its in the format that the alg needs From fb695be664285ce2162f15fde161c48ff215a1bb Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Thu, 21 Jul 2016 16:42:05 +0200 Subject: [PATCH 15/25] Fixes and improvements to MC lewiner alg --- .../measure/_marching_cubes_lewiner_cy.pyx | 108 ++++++++---------- 1 file changed, 47 insertions(+), 61 deletions(-) diff --git a/skimage/measure/_marching_cubes_lewiner_cy.pyx b/skimage/measure/_marching_cubes_lewiner_cy.pyx index b37fb718..f4f0194d 100644 --- a/skimage/measure/_marching_cubes_lewiner_cy.pyx +++ b/skimage/measure/_marching_cubes_lewiner_cy.pyx @@ -72,11 +72,10 @@ def remove_degenerate_faces(vertices, faces, *arrays): # Iterate over all faces. When we encounter a degenerate triangle, # we update the vertex map, i.e. we merge the corresponding vertices. for j in range(faces_.shape[0]): - face_ = faces_[j] - i1, i2, i3 = face_[0], face_[1], face_[2] - v1, v2, v3 = vertices_[face_[0]], vertices_[face_[1]], vertices_[face_[2]] + i1, i2, i3 = faces_[j][0], faces_[j][1], faces_[j][2] + v1, v2, v3 = vertices_[i1], vertices_[i2], vertices_[i3] if v1[0] == v2[0] and v1[1] == v2[1] and v1[2] == v2[2]: - vertices_map1_[i1] = vertices_map1_[i1] = imin(vertices_map1_[i1], vertices_map1_[i2]) + vertices_map1_[i1] = vertices_map1_[i2] = imin(vertices_map1_[i1], vertices_map1_[i2]) faces_ok_[j] = 0 if v1[0] == v3[0] and v1[1] == v3[1] and v1[2] == v3[2]: vertices_map1_[i1] = vertices_map1_[i3] = imin(vertices_map1_[i1], vertices_map1_[i3]) @@ -956,69 +955,56 @@ def marching_cubes(im, double isovalue, LutProvider luts, int st=1, int classic= cdef Cell cell = Cell(luts, Nx, Ny, Nz) # Typedef variables - cdef int x, y, z + cdef int x, y, z, x_st, y_st, z_st cdef int nt cdef int case, config, subconfig - # Unfortunately, using a step in the for loops degregades performance. - # Quick and dirty trick below ... + # Unfortunately specifying a step in range() siginificantly degrades + # performance. Therefore we use a while loop. + # we have: max_x = Nx_bound + st + st - 1 + # -> Nx_bound = max_allowable_x + 1 - 2 * st + # -> Nx_bound = Nx - 2 * st + assert st > 0 + cdef int Nx_bound, Ny_bound, Nz_bound + Nx_bound, Ny_bound, Nz_bound = Nx - 2 * st, Ny - 2 * st, Nz - 2 * st # precalculated index range - if st == 1: + z = -st + while z < Nz_bound: + z += st + z_st = z + st - for z in range(0,Nz-1): - cell.new_z_value() # Indicate that we enter a new layer - for y in range(0,Ny-1): - for x in range(0,Nx-1): - - # Initialize cell - cell.set_cube(isovalue, x, y, z, st, - im_[z ,y, x], im_[z ,y, x+st], im_[z ,y+st, x+st], im_[z ,y+st, x], - im_[z+st,y, x], im_[z+st,y, x+st], im_[z+st,y+st, x+st], im_[z+st,y+st, x] ) - - # Do classic! - if classic: - # Determine number of vertices - nt = 0 - while luts.CASESCLASSIC.get2(cell.index, 3*nt) != -1: - nt += 1 - # Add triangles - if nt > 0: - cell.add_triangles(luts.CASESCLASSIC, cell.index, nt) - else: - # Get case, if non-nul, enter the big switch - case = luts.CASES.get2(cell.index, 0) - if case > 0: - config = luts.CASES.get2(cell.index, 1) - the_big_switch(luts, cell, case, config) - - else: - - for z in range(0,Nz-st,st): - cell.new_z_value() # Indicate that we enter a new layer - for y in range(0,Ny-st,st): - for x in range(0,Nx-st,st): - - # Initialize cell - cell.set_cube(isovalue, x, y, z, st, - im_[z ,y, x], im_[z ,y, x+st], im_[z ,y+st, x+st], im_[z ,y+st, x], - im_[z+st,y, x], im_[z+st,y, x+st], im_[z+st,y+st, x+st], im_[z+st,y+st, x] ) - - # Do classic! - if classic: - # Determine number of vertices - nt = 0 - while luts.CASESCLASSIC.get2(cell.index, 3*nt) != -1: - nt += 1 - # Add triangles - if nt > 0: - cell.add_triangles(luts.CASESCLASSIC, cell.index, nt) - else: - # Get case, if non-nul, enter the big switch - case = luts.CASES.get2(cell.index, 0) - if case > 0: - config = luts.CASES.get2(cell.index, 1) - the_big_switch(luts, cell, case, config) + cell.new_z_value() # Indicate that we enter a new layer + y = -st + while y < Ny_bound: + y += st + y_st = y + st + + x = -st + while x < Nx_bound: + x += st + x_st = x + st + + # Initialize cell + cell.set_cube(isovalue, x, y, z, st, + im_[z ,y, x], im_[z ,y, x_st], im_[z ,y_st, x_st], im_[z ,y_st, x], + im_[z_st,y, x], im_[z_st,y, x_st], im_[z_st,y_st, x_st], im_[z_st,y_st, x] ) + + # Do classic! + if classic: + # Determine number of vertices + nt = 0 + while luts.CASESCLASSIC.get2(cell.index, 3*nt) != -1: + nt += 1 + # Add triangles + if nt > 0: + cell.add_triangles(luts.CASESCLASSIC, cell.index, nt) + else: + # Get case, if non-nul, enter the big switch + case = luts.CASES.get2(cell.index, 0) + if case > 0: + config = luts.CASES.get2(cell.index, 1) + the_big_switch(luts, cell, case, config) # Done return cell.get_vertices(), cell.get_faces(), cell.get_normals(), cell.get_values() From 9909cea01cb224f7194a13ae2e429b952a92710f Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Fri, 22 Jul 2016 00:29:14 +0200 Subject: [PATCH 16/25] MC: Use memoryviews --- .../measure/_marching_cubes_lewiner_cy.pyx | 42 +++++++------------ skimage/measure/mc_meta/visual_test.py | 2 +- 2 files changed, 16 insertions(+), 28 deletions(-) diff --git a/skimage/measure/_marching_cubes_lewiner_cy.pyx b/skimage/measure/_marching_cubes_lewiner_cy.pyx index f4f0194d..0fa0bdb3 100644 --- a/skimage/measure/_marching_cubes_lewiner_cy.pyx +++ b/skimage/measure/_marching_cubes_lewiner_cy.pyx @@ -32,19 +32,9 @@ cdef extern from "stdlib.h": # The cimport does not work on my Linux Laptop void free(void* ptr) void* malloc(size_t size) -# Type defs, we support float32 and float64 -ctypedef np.float32_t FLOAT32_T -ctypedef np.float64_t FLOAT64_T -ctypedef np.int32_t INT32_T -FLOAT32 = np.float32 -FLOAT64 = np.float64 -INT32 = np.float32 - - # Define tiny winy number cdef double FLT_EPSILON = np.spacing(1.0) #0.0000001 - # Define abs function for doubles cdef inline double dabs(double a): return a if a>=0 else -a cdef inline int imin(int a, int b): return a if a Date: Fri, 22 Jul 2016 00:46:37 +0200 Subject: [PATCH 17/25] MC: typed input arg --- skimage/measure/_marching_cubes_lewiner_cy.pyx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/skimage/measure/_marching_cubes_lewiner_cy.pyx b/skimage/measure/_marching_cubes_lewiner_cy.pyx index 0fa0bdb3..502d29a0 100644 --- a/skimage/measure/_marching_cubes_lewiner_cy.pyx +++ b/skimage/measure/_marching_cubes_lewiner_cy.pyx @@ -926,15 +926,12 @@ cdef class LutProvider: self.SUBCONFIG13 = Lut(SUBCONFIG13) -def marching_cubes(im, double isovalue, LutProvider luts, int st=1, int classic=0): +def marching_cubes(float [:, :, :] im not None, double isovalue, LutProvider luts, int st=1, int classic=0): """ marching_cubes(im, double isovalue, LutProvider luts, int st=1, int classic=0) This is the main entry to apply marching cubes. Returns (vertices, faces, normals, values) """ - # Typdedef image - cdef float [:, :, :] im_ = im - # Get dimemsnions cdef int Nx, Ny, Nz Nx, Ny, Nz = im.shape[2], im.shape[1], im.shape[0] @@ -975,8 +972,8 @@ def marching_cubes(im, double isovalue, LutProvider luts, int st=1, int classic= # Initialize cell cell.set_cube(isovalue, x, y, z, st, - im_[z ,y, x], im_[z ,y, x_st], im_[z ,y_st, x_st], im_[z ,y_st, x], - im_[z_st,y, x], im_[z_st,y, x_st], im_[z_st,y_st, x_st], im_[z_st,y_st, x] ) + im[z ,y, x], im[z ,y, x_st], im[z ,y_st, x_st], im[z ,y_st, x], + im[z_st,y, x], im[z_st,y, x_st], im[z_st,y_st, x_st], im[z_st,y_st, x] ) # Do classic! if classic: From e47392af97f8765cb330028cf172b8c275c7eacb Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Fri, 22 Jul 2016 00:53:20 +0200 Subject: [PATCH 18/25] MC: docs --- skimage/measure/_marching_cubes_lewiner.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/skimage/measure/_marching_cubes_lewiner.py b/skimage/measure/_marching_cubes_lewiner.py index 9df5134c..fb2aaed1 100644 --- a/skimage/measure/_marching_cubes_lewiner.py +++ b/skimage/measure/_marching_cubes_lewiner.py @@ -18,10 +18,10 @@ def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), """ Lewiner marching cubes algorithm to find surfaces in 3d volumetric data - In contrast to ``marching_cubes()``, this algorithm resolves - ambiguities and guarantees topologically correct results. Therefore, - this algorithm generally a better choice, unless there is a specific - need for the classic algorithm. + In contrast to ``marching_cubes()``, this algorithm is faster, + resolves ambiguities, and guarantees topologically correct results. + Therefore, this algorithm generally a better choice, unless there + is a specific need for the classic algorithm. Parameters ---------- From 49237ff473108d3689d16e745a4aa007c4f0728d Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Sun, 24 Jul 2016 12:47:11 +0200 Subject: [PATCH 19/25] better testing for python 3+ --- skimage/measure/_marching_cubes_lewiner.py | 2 +- skimage/measure/mc_meta/createluts.py | 3 +-- skimage/measure/tests/test_marching_cubes.py | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/skimage/measure/_marching_cubes_lewiner.py b/skimage/measure/_marching_cubes_lewiner.py index fb2aaed1..5f1db597 100644 --- a/skimage/measure/_marching_cubes_lewiner.py +++ b/skimage/measure/_marching_cubes_lewiner.py @@ -3,7 +3,7 @@ import base64 import numpy as np -if sys.version_info[0] == 3: +if sys.version_info >= (3, ): base64decode = base64.decodebytes else: base64decode = base64.decodestring diff --git a/skimage/measure/mc_meta/createluts.py b/skimage/measure/mc_meta/createluts.py index 670a27c8..94b6fe62 100644 --- a/skimage/measure/mc_meta/createluts.py +++ b/skimage/measure/mc_meta/createluts.py @@ -13,8 +13,7 @@ import sys import base64 # Get base64 encode/decode functions -PY3 = sys.version_info[0] == 3 -if PY3: +if sys.version_info >= (3, ): base64encode = base64.encodebytes base64decode = base64.decodebytes else: diff --git a/skimage/measure/tests/test_marching_cubes.py b/skimage/measure/tests/test_marching_cubes.py index c15d7d94..2d0c766d 100644 --- a/skimage/measure/tests/test_marching_cubes.py +++ b/skimage/measure/tests/test_marching_cubes.py @@ -132,7 +132,7 @@ def test_both_algs_same_result_donut(): n = 48 a, b = 2.5/n, -1.25 isovalue = 0.0 - # + vol = np.empty((n,n,n), 'float32') for iz in range(vol.shape[0]): for iy in range(vol.shape[1]): From dd6adf7b7c4a29f4ef3e6ca201fd8d37ff561cf4 Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Sun, 24 Jul 2016 12:56:02 +0200 Subject: [PATCH 20/25] MC:docs --- skimage/measure/_marching_cubes.py | 8 ++++++-- skimage/measure/_marching_cubes_lewiner.py | 11 ++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/skimage/measure/_marching_cubes.py b/skimage/measure/_marching_cubes.py index 1a381c3c..fa91de07 100644 --- a/skimage/measure/_marching_cubes.py +++ b/skimage/measure/_marching_cubes.py @@ -7,8 +7,11 @@ from . import _marching_cubes_cy def marching_cubes(volume, level=None, spacing=(1., 1., 1.), gradient_direction='descent'): """ - Classic marching cubes algorithm to find surfaces in 3d volumetric data + Classic marching cubes algorithm to find surfaces in 3d volumetric data. + Note that the ``marching_cubes_lewiner()`` algorithm is recommended over + this algorithm, because it's faster and produces better results. + Parameters ---------- volume : (M, N, P) array of doubles @@ -106,7 +109,8 @@ def marching_cubes(volume, level=None, spacing=(1., 1., 1.), .. [1] Lorensen, William and Harvey E. Cline. Marching Cubes: A High Resolution 3D Surface Construction Algorithm. Computer Graphics (SIGGRAPH 87 Proceedings) 21(4) July 1987, p. 163-170). - + DOI: 10.1145/37401.37422 + See Also -------- skimage.measure.marching_cubes_lewiner diff --git a/skimage/measure/_marching_cubes_lewiner.py b/skimage/measure/_marching_cubes_lewiner.py index 5f1db597..2c6f1fd6 100644 --- a/skimage/measure/_marching_cubes_lewiner.py +++ b/skimage/measure/_marching_cubes_lewiner.py @@ -16,7 +16,7 @@ def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), gradient_direction='descent', step_size=1, allow_degenerate=True, use_classic=False): """ - Lewiner marching cubes algorithm to find surfaces in 3d volumetric data + Lewiner marching cubes algorithm to find surfaces in 3d volumetric data. In contrast to ``marching_cubes()``, this algorithm is faster, resolves ambiguities, and guarantees topologically correct results. @@ -84,10 +84,11 @@ def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), References ---------- - .. [1] Thomas Lewiner, Helio Lopes, Antonio Wilson Vieira and Geovan - Tavares. Efficient implementation of Marching Cubes' cases with - topological guarantees. Journal of Graphics Tools 8(2) - pp. 1-15 (december 2003). + .. [1] Thomas Lewiner, Helio Lopes, Antonio Wilson Vieira and Geovan + Tavares. Efficient implementation of Marching Cubes' cases with + topological guarantees. Journal of Graphics Tools 8(2) + pp. 1-15 (december 2003). + DOI: 10.1080/10867651.2003.10487582 See Also -------- From a90f875d15333230ad3bfbd7f526af9a889513d5 Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Mon, 25 Jul 2016 12:25:57 +0200 Subject: [PATCH 21/25] Rename MC algs to make lewiner the default --- bento.info | 4 +- skimage/measure/__init__.py | 8 ++- ...ng_cubes.py => _marching_cubes_classic.py} | 40 +++++------ ..._cy.pyx => _marching_cubes_classic_cy.pyx} | 0 skimage/measure/_marching_cubes_lewiner.py | 67 +++++++++++++++++-- skimage/measure/mc_meta/visual_test.py | 4 +- skimage/measure/setup.py | 6 +- skimage/measure/tests/test_marching_cubes.py | 49 +++++++++++--- 8 files changed, 132 insertions(+), 46 deletions(-) rename skimage/measure/{_marching_cubes.py => _marching_cubes_classic.py} (91%) rename skimage/measure/{_marching_cubes_cy.pyx => _marching_cubes_classic_cy.pyx} (100%) diff --git a/bento.info b/bento.info index 5597045c..53ef3e08 100644 --- a/bento.info +++ b/bento.info @@ -50,9 +50,9 @@ Library: Extension: skimage.measure._moments_cy Sources: skimage/measure/_moments_cy.pyx - Extension: skimage.measure._marching_cubes_cy + Extension: skimage.measure._marching_cubes_classic_cy Sources: - skimage/measure/_marching_cubes_cy.pyx + skimage/measure/_marching_cubes_classic_cy.pyx Extension: skimage.measure._marching_cubes_lewiner_cy Sources: skimage/measure/_marching_cubes_lewiner_cy.pyx diff --git a/skimage/measure/__init__.py b/skimage/measure/__init__.py index c03587d4..015f67d5 100755 --- a/skimage/measure/__init__.py +++ b/skimage/measure/__init__.py @@ -1,7 +1,8 @@ from ._find_contours import find_contours -from ._marching_cubes import (marching_cubes, mesh_surface_area, - correct_mesh_orientation) -from ._marching_cubes_lewiner import marching_cubes_lewiner +from ._marching_cubes_lewiner import marching_cubes, marching_cubes_lewiner +from ._marching_cubes_classic import (marching_cubes_classic, + mesh_surface_area, + correct_mesh_orientation) from ._regionprops import regionprops, perimeter from .simple_metrics import compare_mse, compare_nrmse, compare_psnr from ._structural_similarity import compare_ssim, structural_similarity @@ -31,6 +32,7 @@ __all__ = ['find_contours', 'moments_hu', 'marching_cubes', 'marching_cubes_lewiner', + 'marching_cubes_classic', 'mesh_surface_area', 'correct_mesh_orientation', 'profile_line', diff --git a/skimage/measure/_marching_cubes.py b/skimage/measure/_marching_cubes_classic.py similarity index 91% rename from skimage/measure/_marching_cubes.py rename to skimage/measure/_marching_cubes_classic.py index fa91de07..b6e77c5d 100644 --- a/skimage/measure/_marching_cubes.py +++ b/skimage/measure/_marching_cubes_classic.py @@ -1,15 +1,15 @@ import numpy as np import scipy.ndimage as ndi from .._shared.utils import warn -from . import _marching_cubes_cy +from . import _marching_cubes_classic_cy -def marching_cubes(volume, level=None, spacing=(1., 1., 1.), - gradient_direction='descent'): +def marching_cubes_classic(volume, level=None, spacing=(1., 1., 1.), + gradient_direction='descent'): """ Classic marching cubes algorithm to find surfaces in 3d volumetric data. - Note that the ``marching_cubes_lewiner()`` algorithm is recommended over + Note that the ``marching_cubes()`` algorithm is recommended over this algorithm, because it's faster and produces better results. Parameters @@ -90,7 +90,7 @@ def marching_cubes(volume, level=None, spacing=(1., 1., 1.), named `myvolume` about the level 0.0, using the ``mayavi`` package:: >>> from mayavi import mlab # doctest: +SKIP - >>> verts, faces = marching_cubes(myvolume, 0.0) # doctest: +SKIP + >>> verts, faces = marching_cubes_classic(myvolume, 0.0) # doctest: +SKIP >>> mlab.triangular_mesh([vert[0] for vert in verts], ... [vert[1] for vert in verts], ... [vert[2] for vert in verts], @@ -100,7 +100,7 @@ def marching_cubes(volume, level=None, spacing=(1., 1., 1.), Similarly using the ``visvis`` package:: >>> import visvis as vv # doctest: +SKIP - >>> verts, faces = marching_cubes(myvolume, 0.0) # doctest: +SKIP + >>> verts, faces = marching_cubes_classic(myvolume, 0.0) # doctest: +SKIP >>> vv.mesh(np.fliplr(verts), faces) # doctest: +SKIP >>> vv.use().Run() # doctest: +SKIP @@ -113,7 +113,7 @@ def marching_cubes(volume, level=None, spacing=(1., 1., 1.), See Also -------- - skimage.measure.marching_cubes_lewiner + skimage.measure.marching_cubes skimage.measure.mesh_surface_area """ # Check inputs and ensure `volume` is C-contiguous for memoryviews @@ -136,11 +136,12 @@ def marching_cubes(volume, level=None, spacing=(1., 1., 1.), # Note: this algorithm is fast, but returns degenerate "triangles" which # have repeated vertices - and equivalent vertices are redundantly # placed in every triangle they connect with. - raw_faces = _marching_cubes_cy.iterate_and_store_3d(volume, float(level)) + raw_faces = _marching_cubes_classic_cy.iterate_and_store_3d(volume, + float(level)) # Find and collect unique vertices, storing triangle verts as indices. # Returns a true mesh with no degenerate faces. - verts, faces = _marching_cubes_cy.unpack_unique_verts(raw_faces) + verts, faces = _marching_cubes_classic_cy.unpack_unique_verts(raw_faces) verts = np.asarray(verts) faces = np.asarray(faces) @@ -172,7 +173,7 @@ def mesh_surface_area(verts, faces): Notes ----- - The arguments expected by this function are the exact outputs from + The arguments expected by this function are the first two outputs from `skimage.measure.marching_cubes`. For unit correct output, ensure correct `spacing` was passed to `skimage.measure.marching_cubes`. @@ -182,6 +183,7 @@ def mesh_surface_area(verts, faces): See Also -------- skimage.measure.marching_cubes + skimage.measure.marching_cubes_classic skimage.measure.correct_mesh_orientation """ @@ -229,7 +231,7 @@ def correct_mesh_orientation(volume, verts, faces, spacing=(1., 1., 1.), Certain applications and mesh processing algorithms require all faces to be oriented in a consistent way. Generally, this means a normal vector points "out" of the meshed shapes. This algorithm corrects the output from - `skimage.measure.marching_cubes` by flipping the orientation of + `skimage.measure.marching_cubes_classic` by flipping the orientation of mis-oriented faces. Because marching cubes could be used to find isosurfaces either on @@ -240,21 +242,21 @@ def correct_mesh_orientation(volume, verts, faces, spacing=(1., 1., 1.), completely incorrectly, try changing this option. The arguments expected by this function are the exact outputs from - `skimage.measure.marching_cubes`. Only `faces` is corrected and returned, - as the vertices do not change; only the order in which they are + `skimage.measure.marching_cubes_classic`. Only `faces` is corrected and + returned, as the vertices do not change; only the order in which they are referenced. This algorithm assumes ``faces`` provided are all triangles. See Also -------- - skimage.measure.marching_cubes + skimage.measure.marching_cubes_classic skimage.measure.mesh_surface_area """ warn(DeprecationWarning("`correct_mesh_orientation` is deprecated for " - "removal as `marching_cubes` now guarantess " - "correct mesh orientation.")) + "removal as `marching_cubes`_classic now " + "guarantees correct mesh orientation.")) verts = verts.copy() verts[:, 0] /= spacing[0] @@ -303,7 +305,7 @@ def _correct_mesh_orientation(volume, actual_verts, faces, Certain applications and mesh processing algorithms require all faces to be oriented in a consistent way. Generally, this means a normal vector points "out" of the meshed shapes. This algorithm corrects the output from - `skimage.measure.marching_cubes` by flipping the orientation of + `skimage.measure.marching_cubes_classic` by flipping the orientation of mis-oriented faces. Because marching cubes could be used to find isosurfaces either on @@ -314,7 +316,7 @@ def _correct_mesh_orientation(volume, actual_verts, faces, completely incorrectly, try changing this option. The arguments expected by this function are the exact outputs from - `skimage.measure.marching_cubes` except `actual_verts`, which is an + `skimage.measure.marching_cubes_classic` except `actual_verts`, which is an uncorrected version of the fancy indexing operation `verts[faces]`. Only `faces` is corrected and returned as the vertices do not change, only the order in which they are referenced. @@ -323,7 +325,7 @@ def _correct_mesh_orientation(volume, actual_verts, faces, See Also -------- - skimage.measure.marching_cubes + skimage.measure.marching_cubes_classic skimage.measure.mesh_surface_area """ diff --git a/skimage/measure/_marching_cubes_cy.pyx b/skimage/measure/_marching_cubes_classic_cy.pyx similarity index 100% rename from skimage/measure/_marching_cubes_cy.pyx rename to skimage/measure/_marching_cubes_classic_cy.pyx diff --git a/skimage/measure/_marching_cubes_lewiner.py b/skimage/measure/_marching_cubes_lewiner.py index 2c6f1fd6..067396db 100644 --- a/skimage/measure/_marching_cubes_lewiner.py +++ b/skimage/measure/_marching_cubes_lewiner.py @@ -1,24 +1,55 @@ import sys import base64 +import dis +import inspect import numpy as np if sys.version_info >= (3, ): base64decode = base64.decodebytes + ordornot = lambda x:x else: base64decode = base64.decodestring + ordornot = ord from . import _marching_cubes_lewiner_luts as mcluts from . import _marching_cubes_lewiner_cy +from .._shared.utils import skimage_deprecation, warn -def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), - gradient_direction='descent', step_size=1, - allow_degenerate=True, use_classic=False): +def expected_output_args(): + """ Get number of expected output args. + + Please don't use this to influence the algorithmic bahaviour of a function. + For ``a, b, rest*, c = ...`` syntax, returns n + 0.1 (3.1 in this example). + """ + f = inspect.currentframe().f_back.f_back + i = f.f_lasti + 3 + bytecode = f.f_code.co_code + instruction = ordornot(bytecode[i]) + while True: + if instruction == dis.opmap['DUP_TOP']: + if ordornot(bytecode[i + 1]) == dis.opmap['UNPACK_SEQUENCE']: + return ordornot(bytecode[i + 2]) + i += 4 + instruction = ordornot(bytecode[i]) + continue + if instruction == dis.opmap['STORE_NAME']: + return 1 + if instruction == dis.opmap['UNPACK_SEQUENCE']: + return ordornot(bytecode[i + 1]) + if instruction == dis.opmap.get('UNPACK_EX', -1): # py3k + return ordornot(bytecode[i + 1]) + ordornot(bytecode[i + 2]) + 0.1 + return 0 + + +def marching_cubes(volume, level=None, spacing=(1., 1., 1.), + gradient_direction='descent', step_size=1, + allow_degenerate=True, use_classic=False): """ Lewiner marching cubes algorithm to find surfaces in 3d volumetric data. - In contrast to ``marching_cubes()``, this algorithm is faster, + In contrast to ``marching_cubes_classic()``, this algorithm is faster, resolves ambiguities, and guarantees topologically correct results. Therefore, this algorithm generally a better choice, unless there is a specific need for the classic algorithm. @@ -54,8 +85,8 @@ def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), is used. This option is included for reference purposes. Note that this algorithm has ambiguities and is not guaranteed to produce a topologically correct result. The results with using - this option are *not* generally the same as the ``marching_cubes()`` - function. + this option are *not* generally the same as the + ``marching_cubes_classic()`` function. Returns ------- @@ -92,10 +123,32 @@ def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), See Also -------- - skimage.measure.marching_cubes + skimage.measure.marching_cubes_classic skimage.measure.mesh_surface_area """ + # This signature (output args) of this func changed after 0.12 + try: + nout = expected_output_args() + except Exception: + nout = 0 + if nout <= 2: + warn(skimage_deprecation('`marching_cubes` now uses a better and ' + 'faster algorithm, and returns four instead ' + 'of two outputs (see docstring for details). ' + 'Backwards compatibility with 0.12 and prior ' + 'is available with `marching_cubes_classic`.')) + + return marching_cubes_lewiner(volume, level, spacing, gradient_direction, + step_size, allow_degenerate, use_classic) + + +def marching_cubes_lewiner(volume, level=None, spacing=(1., 1., 1.), + gradient_direction='descent', step_size=1, + allow_degenerate=True, use_classic=False): + """ Alias for ``marching_cubes()``. + """ + # Check volume and ensure its in the format that the alg needs if not isinstance(volume, np.ndarray) or (volume.ndim != 3): raise ValueError('Input volume should be a 3D numpy array.') diff --git a/skimage/measure/mc_meta/visual_test.py b/skimage/measure/mc_meta/visual_test.py index bc95758a..64504fd9 100644 --- a/skimage/measure/mc_meta/visual_test.py +++ b/skimage/measure/mc_meta/visual_test.py @@ -8,7 +8,7 @@ import time import numpy as np import visvis as vv -from skimage.measure import marching_cubes, marching_cubes_lewiner +from skimage.measure import marching_cubes_classic, marching_cubes_lewiner from skimage.draw import ellipsoid @@ -57,7 +57,7 @@ vertices1, faces1, *_ = marching_cubes_lewiner(vol, isovalue, gradient_direction print('finding surface lewiner took %1.0f ms' % (1000*(time.time()-t0)) ) t0 = time.time() -vertices2, faces2, *_ = marching_cubes(vol, isovalue, gradient_direction=gradient_dir) +vertices2, faces2, *_ = marching_cubes_classic(vol, isovalue, gradient_direction=gradient_dir) print('finding surface classic took %1.0f ms' % (1000*(time.time()-t0)) ) # Show diff --git a/skimage/measure/setup.py b/skimage/measure/setup.py index cea657c5..df69ff5d 100644 --- a/skimage/measure/setup.py +++ b/skimage/measure/setup.py @@ -15,7 +15,7 @@ def configuration(parent_package='', top_path=None): cython(['_ccomp.pyx'], working_path=base_path) cython(['_find_contours_cy.pyx'], working_path=base_path) cython(['_moments_cy.pyx'], working_path=base_path) - cython(['_marching_cubes_cy.pyx'], working_path=base_path) + cython(['_marching_cubes_classic_cy.pyx'], working_path=base_path) cython(['_marching_cubes_lewiner_cy.pyx'], working_path=base_path) cython(['_pnpoly.pyx'], working_path=base_path) @@ -25,8 +25,8 @@ def configuration(parent_package='', top_path=None): include_dirs=[get_numpy_include_dirs()]) config.add_extension('_moments_cy', sources=['_moments_cy.c'], include_dirs=[get_numpy_include_dirs()]) - config.add_extension('_marching_cubes_cy', - sources=['_marching_cubes_cy.c'], + config.add_extension('_marching_cubes_classic_cy', + sources=['_marching_cubes_classic_cy.c'], include_dirs=[get_numpy_include_dirs()]) config.add_extension('_marching_cubes_lewiner_cy', sources=['_marching_cubes_lewiner_cy.c'], diff --git a/skimage/measure/tests/test_marching_cubes.py b/skimage/measure/tests/test_marching_cubes.py index 2d0c766d..3fa85da3 100644 --- a/skimage/measure/tests/test_marching_cubes.py +++ b/skimage/measure/tests/test_marching_cubes.py @@ -1,9 +1,38 @@ +import sys import numpy as np from numpy.testing import assert_raises from skimage.draw import ellipsoid, ellipsoid_stats -from skimage.measure import (marching_cubes, marching_cubes_lewiner, +from skimage.measure import (marching_cubes, + marching_cubes_classic, marching_cubes_lewiner, mesh_surface_area, correct_mesh_orientation) +from skimage.measure._marching_cubes_lewiner import expected_output_args + + +def test_expected_output_args(): + + res = [] + + def foo(): + nout = expected_output_args() + print(nout) + res.append(nout) + return [nout] * int(nout) + + foo() + a = foo() + a, b = foo() + a, b, c = foo() + assert res == [0, 1, 2, 3] or res == [0, 0, 2, 3] + # ``a = foo()`` somehow yields 0 in test, which is ok for us; + # we only want to distinguish between > 2 args or not + + if sys.version_info >= (3, 3): + res = [] + exec('*a, b, c = foo()') + exec('a, b, c, *d = foo()') + exec('a, b, *c, d, e = foo()') + assert res == [2.1, 3.1, 4.1] def test_marching_cubes_isotropic(): @@ -11,7 +40,7 @@ def test_marching_cubes_isotropic(): _, surf = ellipsoid_stats(6, 10, 16) # Classic - verts, faces = marching_cubes(ellipsoid_isotropic, 0.) + verts, faces = marching_cubes_classic(ellipsoid_isotropic, 0.) surf_calc = mesh_surface_area(verts, faces) # Test within 1% tolerance for isotropic. Will always underestimate. assert surf > surf_calc and surf_calc > surf * 0.99 @@ -30,8 +59,8 @@ def test_marching_cubes_anisotropic(): _, surf = ellipsoid_stats(6, 10, 16) # Classic - verts, faces = marching_cubes(ellipsoid_anisotropic, 0., - spacing=spacing) + verts, faces = marching_cubes_classic(ellipsoid_anisotropic, 0., + spacing=spacing) surf_calc = mesh_surface_area(verts, faces) # Test within 1.5% tolerance for anisotropic. Will always underestimate. assert surf > surf_calc and surf_calc > surf * 0.985 @@ -45,11 +74,11 @@ def test_marching_cubes_anisotropic(): def test_invalid_input(): # Classic - assert_raises(ValueError, marching_cubes, np.zeros((2, 2, 1)), 0) - assert_raises(ValueError, marching_cubes, np.zeros((2, 2, 1)), 1) - assert_raises(ValueError, marching_cubes, np.ones((3, 3, 3)), 1, + assert_raises(ValueError, marching_cubes_classic, np.zeros((2, 2, 1)), 0) + assert_raises(ValueError, marching_cubes_classic, np.zeros((2, 2, 1)), 1) + assert_raises(ValueError, marching_cubes_classic, np.ones((3, 3, 3)), 1, spacing=(1, 2)) - assert_raises(ValueError, marching_cubes, np.zeros((20, 20)), 0) + assert_raises(ValueError, marching_cubes_classic, np.zeros((20, 20)), 0) # Lewiner assert_raises(ValueError, marching_cubes_lewiner, np.zeros((2, 2, 1)), 0) @@ -101,7 +130,7 @@ def test_both_algs_same_result_ellipse(): sphere_small = ellipsoid(1, 1, 1, levelset=True) - vertices1, faces1 = marching_cubes(sphere_small, 0)[:2] + vertices1, faces1 = marching_cubes_classic(sphere_small, 0)[:2] vertices2, faces2 = marching_cubes_lewiner(sphere_small, 0, allow_degenerate=False)[:2] vertices3, faces3 = marching_cubes_lewiner(sphere_small, 0, allow_degenerate=False, use_classic=True)[:2] @@ -147,7 +176,7 @@ def test_both_algs_same_result_donut(): 64 * ( ((8*y-2)+4)*((8*y-2)+4) + (8*z)**2 ) ) + 1025 - vertices1, faces1 = marching_cubes(vol, 0)[:2] + vertices1, faces1 = marching_cubes_classic(vol, 0)[:2] vertices2, faces2 = marching_cubes_lewiner(vol, 0)[:2] vertices3, faces3 = marching_cubes_lewiner(vol, 0, use_classic=True)[:2] From 01a1e5e4b733b30633dc543cfa5f9785d9306560 Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Tue, 26 Jul 2016 11:31:48 +0200 Subject: [PATCH 22/25] MC: small tweaks from reviewer comments --- skimage/measure/_marching_cubes_classic.py | 2 +- skimage/measure/_marching_cubes_lewiner.py | 4 ++-- skimage/measure/tests/test_marching_cubes.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/skimage/measure/_marching_cubes_classic.py b/skimage/measure/_marching_cubes_classic.py index b6e77c5d..2cd936a2 100644 --- a/skimage/measure/_marching_cubes_classic.py +++ b/skimage/measure/_marching_cubes_classic.py @@ -255,7 +255,7 @@ def correct_mesh_orientation(volume, verts, faces, spacing=(1., 1., 1.), """ warn(DeprecationWarning("`correct_mesh_orientation` is deprecated for " - "removal as `marching_cubes`_classic now " + "removal as `marching_cubes_classic` now " "guarantees correct mesh orientation.")) verts = verts.copy() diff --git a/skimage/measure/_marching_cubes_lewiner.py b/skimage/measure/_marching_cubes_lewiner.py index 067396db..66764ebc 100644 --- a/skimage/measure/_marching_cubes_lewiner.py +++ b/skimage/measure/_marching_cubes_lewiner.py @@ -17,7 +17,7 @@ from . import _marching_cubes_lewiner_cy from .._shared.utils import skimage_deprecation, warn -def expected_output_args(): +def _expected_output_args(): """ Get number of expected output args. Please don't use this to influence the algorithmic bahaviour of a function. @@ -129,7 +129,7 @@ def marching_cubes(volume, level=None, spacing=(1., 1., 1.), # This signature (output args) of this func changed after 0.12 try: - nout = expected_output_args() + nout = _expected_output_args() except Exception: nout = 0 if nout <= 2: diff --git a/skimage/measure/tests/test_marching_cubes.py b/skimage/measure/tests/test_marching_cubes.py index 3fa85da3..a9d59a21 100644 --- a/skimage/measure/tests/test_marching_cubes.py +++ b/skimage/measure/tests/test_marching_cubes.py @@ -6,7 +6,7 @@ from skimage.draw import ellipsoid, ellipsoid_stats from skimage.measure import (marching_cubes, marching_cubes_classic, marching_cubes_lewiner, mesh_surface_area, correct_mesh_orientation) -from skimage.measure._marching_cubes_lewiner import expected_output_args +from skimage.measure._marching_cubes_lewiner import _expected_output_args def test_expected_output_args(): @@ -14,7 +14,7 @@ def test_expected_output_args(): res = [] def foo(): - nout = expected_output_args() + nout = _expected_output_args() print(nout) res.append(nout) return [nout] * int(nout) From 6d0d655121c38e661431c4d0bcb024be09a0f32a Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Tue, 26 Jul 2016 11:41:26 +0200 Subject: [PATCH 23/25] MC: docs and example fixes --- doc/examples/edges/plot_marching_cubes.py | 4 ++-- skimage/measure/_marching_cubes_classic.py | 18 ------------------ skimage/measure/_marching_cubes_lewiner.py | 21 +++++++++++++++++++++ 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/doc/examples/edges/plot_marching_cubes.py b/doc/examples/edges/plot_marching_cubes.py index 5dad1680..919601b0 100644 --- a/doc/examples/edges/plot_marching_cubes.py +++ b/doc/examples/edges/plot_marching_cubes.py @@ -33,10 +33,10 @@ ellip_double = np.concatenate((ellip_base[:-1, ...], ellip_base[2:, ...]), axis=0) # Use marching cubes to obtain the surface mesh of these ellipsoids -verts, faces = measure.marching_cubes(ellip_double, 0) +verts, faces, normals, values = measure.marching_cubes(ellip_double, 0) # Display resulting triangular mesh using Matplotlib. This can also be done -# with mayavi (see skimage.measure.marching_cubes docstring). +# with mayavi or visvis (see skimage.measure.marching_cubes docstring). fig = plt.figure(figsize=(10, 12)) ax = fig.add_subplot(111, projection='3d') diff --git a/skimage/measure/_marching_cubes_classic.py b/skimage/measure/_marching_cubes_classic.py index 2cd936a2..da688204 100644 --- a/skimage/measure/_marching_cubes_classic.py +++ b/skimage/measure/_marching_cubes_classic.py @@ -86,24 +86,6 @@ def marching_cubes_classic(volume, level=None, spacing=(1., 1., 1.), To quantify the area of an isosurface generated by this algorithm, pass outputs directly into `skimage.measure.mesh_surface_area`. - Regarding visualization of algorithm output, to contour a volume - named `myvolume` about the level 0.0, using the ``mayavi`` package:: - - >>> from mayavi import mlab # doctest: +SKIP - >>> verts, faces = marching_cubes_classic(myvolume, 0.0) # doctest: +SKIP - >>> mlab.triangular_mesh([vert[0] for vert in verts], - ... [vert[1] for vert in verts], - ... [vert[2] for vert in verts], - ... faces) # doctest: +SKIP - >>> mlab.show() # doctest: +SKIP - - Similarly using the ``visvis`` package:: - - >>> import visvis as vv # doctest: +SKIP - >>> verts, faces = marching_cubes_classic(myvolume, 0.0) # doctest: +SKIP - >>> vv.mesh(np.fliplr(verts), faces) # doctest: +SKIP - >>> vv.use().Run() # doctest: +SKIP - References ---------- .. [1] Lorensen, William and Harvey E. Cline. Marching Cubes: A High diff --git a/skimage/measure/_marching_cubes_lewiner.py b/skimage/measure/_marching_cubes_lewiner.py index 66764ebc..d2ba4aa5 100644 --- a/skimage/measure/_marching_cubes_lewiner.py +++ b/skimage/measure/_marching_cubes_lewiner.py @@ -113,6 +113,27 @@ def marching_cubes(volume, level=None, spacing=(1., 1., 1.), keeping the algorithm relatively easy. This implementation is written in Cython, ported from Lewiner's C++ implementation. + To quantify the area of an isosurface generated by this algorithm, pass + verts and faces to `skimage.measure.mesh_surface_area`. + + Regarding visualization of algorithm output, to contour a volume + named `myvolume` about the level 0.0, using the ``mayavi`` package:: + + >>> from mayavi import mlab # doctest: +SKIP + >>> verts, faces, normals, values = marching_cubes(myvolume, 0.0) # doctest: +SKIP + >>> mlab.triangular_mesh([vert[0] for vert in verts], + ... [vert[1] for vert in verts], + ... [vert[2] for vert in verts], + ... faces) # doctest: +SKIP + >>> mlab.show() # doctest: +SKIP + + Similarly using the ``visvis`` package:: + + >>> import visvis as vv # doctest: +SKIP + >>> verts, faces, normals, values = marching_cubes_classic(myvolume, 0.0) # doctest: +SKIP + >>> vv.mesh(np.fliplr(verts), faces, normals, values) # doctest: +SKIP + >>> vv.use().Run() # doctest: +SKIP + References ---------- .. [1] Thomas Lewiner, Helio Lopes, Antonio Wilson Vieira and Geovan From 76861051293995cf108fe060440db32e267eaa41 Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Tue, 26 Jul 2016 13:19:23 +0200 Subject: [PATCH 24/25] MC: python2 compat --- skimage/measure/tests/test_marching_cubes.py | 30 +++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/skimage/measure/tests/test_marching_cubes.py b/skimage/measure/tests/test_marching_cubes.py index a9d59a21..5cce3ea8 100644 --- a/skimage/measure/tests/test_marching_cubes.py +++ b/skimage/measure/tests/test_marching_cubes.py @@ -8,30 +8,32 @@ from skimage.measure import (marching_cubes, mesh_surface_area, correct_mesh_orientation) from skimage.measure._marching_cubes_lewiner import _expected_output_args +def func_that_knows_about_its_outputs(r): + # Must be defined in global scope to avoid syntax error on Python 2 *sigh* + nout = _expected_output_args() + print(nout) + r.append(nout) + return [nout] * int(nout) + def test_expected_output_args(): + foo = func_that_knows_about_its_outputs + res = [] - - def foo(): - nout = _expected_output_args() - print(nout) - res.append(nout) - return [nout] * int(nout) - - foo() - a = foo() - a, b = foo() - a, b, c = foo() + foo(res) + a = foo(res) + a, b = foo(res) + a, b, c = foo(res) assert res == [0, 1, 2, 3] or res == [0, 0, 2, 3] # ``a = foo()`` somehow yields 0 in test, which is ok for us; # we only want to distinguish between > 2 args or not if sys.version_info >= (3, 3): res = [] - exec('*a, b, c = foo()') - exec('a, b, c, *d = foo()') - exec('a, b, *c, d, e = foo()') + exec('*a, b, c = foo(res)') + exec('a, b, c, *d = foo(res)') + exec('a, b, *c, d, e = foo(res)') assert res == [2.1, 3.1, 4.1] From 7e71a8e0423ff8c72dfbac6a4e4d854685472bbe Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Tue, 26 Jul 2016 22:22:35 +0200 Subject: [PATCH 25/25] MC: add comment about except --- skimage/measure/_marching_cubes_lewiner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skimage/measure/_marching_cubes_lewiner.py b/skimage/measure/_marching_cubes_lewiner.py index d2ba4aa5..60f37feb 100644 --- a/skimage/measure/_marching_cubes_lewiner.py +++ b/skimage/measure/_marching_cubes_lewiner.py @@ -152,7 +152,7 @@ def marching_cubes(volume, level=None, spacing=(1., 1., 1.), try: nout = _expected_output_args() except Exception: - nout = 0 + nout = 0 # always warn if, for whaterver reason, the black magic in above call fails if nout <= 2: warn(skimage_deprecation('`marching_cubes` now uses a better and ' 'faster algorithm, and returns four instead '